@webpieces/dev-config 0.2.95 → 0.2.97

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 (181) hide show
  1. package/config/eslint/base.mjs +1 -1
  2. package/executors.json +6 -91
  3. package/package.json +6 -19
  4. package/{executors → src/executors}/help/executor.d.ts +4 -2
  5. package/src/executors/help/executor.js.map +1 -0
  6. package/src/executors/validate-eslint-sync/executor.js.map +1 -0
  7. package/{executors → src/executors}/validate-versions-locked/executor.js +2 -1
  8. package/src/executors/validate-versions-locked/executor.js.map +1 -0
  9. package/src/index.d.ts +1 -1
  10. package/src/index.js +1 -1
  11. package/src/index.js.map +1 -1
  12. package/src/plugin.d.ts +86 -0
  13. package/{plugin.js → src/plugin.js} +31 -15
  14. package/src/plugin.js.map +1 -0
  15. package/src/toError.d.ts +5 -0
  16. package/src/toError.js +37 -0
  17. package/src/toError.js.map +1 -0
  18. package/templates/eslint.webpieces.config.mjs +1 -1
  19. package/architecture/executors/diff-utils.d.ts +0 -24
  20. package/architecture/executors/diff-utils.js +0 -119
  21. package/architecture/executors/diff-utils.js.map +0 -1
  22. package/architecture/executors/diff-utils.ts +0 -127
  23. package/architecture/executors/generate/executor.d.ts +0 -16
  24. package/architecture/executors/generate/executor.js +0 -44
  25. package/architecture/executors/generate/executor.js.map +0 -1
  26. package/architecture/executors/generate/executor.ts +0 -59
  27. package/architecture/executors/generate/schema.json +0 -14
  28. package/architecture/executors/validate-architecture-unchanged/executor.d.ts +0 -17
  29. package/architecture/executors/validate-architecture-unchanged/executor.js +0 -229
  30. package/architecture/executors/validate-architecture-unchanged/executor.js.map +0 -1
  31. package/architecture/executors/validate-architecture-unchanged/executor.ts +0 -251
  32. package/architecture/executors/validate-architecture-unchanged/schema.json +0 -14
  33. package/architecture/executors/validate-code/executor.d.ts +0 -78
  34. package/architecture/executors/validate-code/executor.js +0 -243
  35. package/architecture/executors/validate-code/executor.js.map +0 -1
  36. package/architecture/executors/validate-code/executor.ts +0 -406
  37. package/architecture/executors/validate-code/schema.json +0 -227
  38. package/architecture/executors/validate-dtos/executor.d.ts +0 -42
  39. package/architecture/executors/validate-dtos/executor.js +0 -561
  40. package/architecture/executors/validate-dtos/executor.js.map +0 -1
  41. package/architecture/executors/validate-dtos/executor.ts +0 -689
  42. package/architecture/executors/validate-dtos/schema.json +0 -33
  43. package/architecture/executors/validate-modified-files/executor.d.ts +0 -25
  44. package/architecture/executors/validate-modified-files/executor.js +0 -501
  45. package/architecture/executors/validate-modified-files/executor.js.map +0 -1
  46. package/architecture/executors/validate-modified-files/executor.ts +0 -571
  47. package/architecture/executors/validate-modified-files/schema.json +0 -25
  48. package/architecture/executors/validate-modified-methods/executor.d.ts +0 -31
  49. package/architecture/executors/validate-modified-methods/executor.js +0 -694
  50. package/architecture/executors/validate-modified-methods/executor.js.map +0 -1
  51. package/architecture/executors/validate-modified-methods/executor.ts +0 -797
  52. package/architecture/executors/validate-modified-methods/schema.json +0 -25
  53. package/architecture/executors/validate-new-methods/executor.d.ts +0 -28
  54. package/architecture/executors/validate-new-methods/executor.js +0 -513
  55. package/architecture/executors/validate-new-methods/executor.js.map +0 -1
  56. package/architecture/executors/validate-new-methods/executor.ts +0 -584
  57. package/architecture/executors/validate-new-methods/schema.json +0 -25
  58. package/architecture/executors/validate-no-any-unknown/executor.d.ts +0 -42
  59. package/architecture/executors/validate-no-any-unknown/executor.js +0 -462
  60. package/architecture/executors/validate-no-any-unknown/executor.js.map +0 -1
  61. package/architecture/executors/validate-no-any-unknown/executor.ts +0 -540
  62. package/architecture/executors/validate-no-any-unknown/schema.json +0 -24
  63. package/architecture/executors/validate-no-architecture-cycles/executor.d.ts +0 -16
  64. package/architecture/executors/validate-no-architecture-cycles/executor.js +0 -48
  65. package/architecture/executors/validate-no-architecture-cycles/executor.js.map +0 -1
  66. package/architecture/executors/validate-no-architecture-cycles/executor.ts +0 -60
  67. package/architecture/executors/validate-no-architecture-cycles/schema.json +0 -8
  68. package/architecture/executors/validate-no-destructure/executor.d.ts +0 -52
  69. package/architecture/executors/validate-no-destructure/executor.js +0 -491
  70. package/architecture/executors/validate-no-destructure/executor.js.map +0 -1
  71. package/architecture/executors/validate-no-destructure/executor.ts +0 -578
  72. package/architecture/executors/validate-no-destructure/schema.json +0 -24
  73. package/architecture/executors/validate-no-direct-api-resolver/executor.d.ts +0 -47
  74. package/architecture/executors/validate-no-direct-api-resolver/executor.js +0 -566
  75. package/architecture/executors/validate-no-direct-api-resolver/executor.js.map +0 -1
  76. package/architecture/executors/validate-no-direct-api-resolver/executor.ts +0 -666
  77. package/architecture/executors/validate-no-direct-api-resolver/schema.json +0 -29
  78. package/architecture/executors/validate-no-inline-types/executor.d.ts +0 -91
  79. package/architecture/executors/validate-no-inline-types/executor.js +0 -669
  80. package/architecture/executors/validate-no-inline-types/executor.js.map +0 -1
  81. package/architecture/executors/validate-no-inline-types/executor.ts +0 -775
  82. package/architecture/executors/validate-no-inline-types/schema.json +0 -24
  83. package/architecture/executors/validate-no-skiplevel-deps/executor.d.ts +0 -19
  84. package/architecture/executors/validate-no-skiplevel-deps/executor.js +0 -227
  85. package/architecture/executors/validate-no-skiplevel-deps/executor.js.map +0 -1
  86. package/architecture/executors/validate-no-skiplevel-deps/executor.ts +0 -267
  87. package/architecture/executors/validate-no-skiplevel-deps/schema.json +0 -8
  88. package/architecture/executors/validate-packagejson/executor.d.ts +0 -16
  89. package/architecture/executors/validate-packagejson/executor.js +0 -57
  90. package/architecture/executors/validate-packagejson/executor.js.map +0 -1
  91. package/architecture/executors/validate-packagejson/executor.ts +0 -74
  92. package/architecture/executors/validate-packagejson/schema.json +0 -8
  93. package/architecture/executors/validate-prisma-converters/executor.d.ts +0 -60
  94. package/architecture/executors/validate-prisma-converters/executor.js +0 -634
  95. package/architecture/executors/validate-prisma-converters/executor.js.map +0 -1
  96. package/architecture/executors/validate-prisma-converters/executor.ts +0 -822
  97. package/architecture/executors/validate-prisma-converters/schema.json +0 -38
  98. package/architecture/executors/validate-return-types/executor.d.ts +0 -29
  99. package/architecture/executors/validate-return-types/executor.js +0 -439
  100. package/architecture/executors/validate-return-types/executor.js.map +0 -1
  101. package/architecture/executors/validate-return-types/executor.ts +0 -524
  102. package/architecture/executors/validate-return-types/schema.json +0 -24
  103. package/architecture/executors/visualize/executor.d.ts +0 -17
  104. package/architecture/executors/visualize/executor.js +0 -49
  105. package/architecture/executors/visualize/executor.js.map +0 -1
  106. package/architecture/executors/visualize/executor.ts +0 -63
  107. package/architecture/executors/visualize/schema.json +0 -14
  108. package/architecture/index.d.ts +0 -19
  109. package/architecture/index.js +0 -23
  110. package/architecture/index.js.map +0 -1
  111. package/architecture/index.ts +0 -20
  112. package/architecture/lib/graph-comparator.d.ts +0 -39
  113. package/architecture/lib/graph-comparator.js +0 -100
  114. package/architecture/lib/graph-comparator.js.map +0 -1
  115. package/architecture/lib/graph-comparator.ts +0 -141
  116. package/architecture/lib/graph-generator.d.ts +0 -19
  117. package/architecture/lib/graph-generator.js +0 -84
  118. package/architecture/lib/graph-generator.js.map +0 -1
  119. package/architecture/lib/graph-generator.ts +0 -97
  120. package/architecture/lib/graph-loader.d.ts +0 -31
  121. package/architecture/lib/graph-loader.js +0 -98
  122. package/architecture/lib/graph-loader.js.map +0 -1
  123. package/architecture/lib/graph-loader.ts +0 -116
  124. package/architecture/lib/graph-sorter.d.ts +0 -37
  125. package/architecture/lib/graph-sorter.js +0 -110
  126. package/architecture/lib/graph-sorter.js.map +0 -1
  127. package/architecture/lib/graph-sorter.ts +0 -137
  128. package/architecture/lib/graph-visualizer.d.ts +0 -29
  129. package/architecture/lib/graph-visualizer.js +0 -217
  130. package/architecture/lib/graph-visualizer.js.map +0 -1
  131. package/architecture/lib/graph-visualizer.ts +0 -231
  132. package/architecture/lib/package-validator.d.ts +0 -38
  133. package/architecture/lib/package-validator.js +0 -126
  134. package/architecture/lib/package-validator.js.map +0 -1
  135. package/architecture/lib/package-validator.ts +0 -170
  136. package/eslint-plugin/__tests__/catch-error-pattern.test.ts +0 -374
  137. package/eslint-plugin/__tests__/max-file-lines.test.ts +0 -207
  138. package/eslint-plugin/__tests__/max-method-lines.test.ts +0 -258
  139. package/eslint-plugin/__tests__/no-unmanaged-exceptions.test.ts +0 -359
  140. package/eslint-plugin/index.d.ts +0 -23
  141. package/eslint-plugin/index.js +0 -30
  142. package/eslint-plugin/index.js.map +0 -1
  143. package/eslint-plugin/index.ts +0 -29
  144. package/eslint-plugin/rules/catch-error-pattern.d.ts +0 -11
  145. package/eslint-plugin/rules/catch-error-pattern.js +0 -143
  146. package/eslint-plugin/rules/catch-error-pattern.js.map +0 -1
  147. package/eslint-plugin/rules/catch-error-pattern.ts +0 -246
  148. package/eslint-plugin/rules/enforce-architecture.d.ts +0 -15
  149. package/eslint-plugin/rules/enforce-architecture.js +0 -476
  150. package/eslint-plugin/rules/enforce-architecture.js.map +0 -1
  151. package/eslint-plugin/rules/enforce-architecture.ts +0 -543
  152. package/eslint-plugin/rules/max-file-lines.d.ts +0 -12
  153. package/eslint-plugin/rules/max-file-lines.js +0 -257
  154. package/eslint-plugin/rules/max-file-lines.js.map +0 -1
  155. package/eslint-plugin/rules/max-file-lines.ts +0 -272
  156. package/eslint-plugin/rules/max-method-lines.d.ts +0 -12
  157. package/eslint-plugin/rules/max-method-lines.js +0 -240
  158. package/eslint-plugin/rules/max-method-lines.js.map +0 -1
  159. package/eslint-plugin/rules/max-method-lines.ts +0 -287
  160. package/eslint-plugin/rules/no-unmanaged-exceptions.d.ts +0 -22
  161. package/eslint-plugin/rules/no-unmanaged-exceptions.js +0 -160
  162. package/eslint-plugin/rules/no-unmanaged-exceptions.js.map +0 -1
  163. package/eslint-plugin/rules/no-unmanaged-exceptions.ts +0 -179
  164. package/executors/help/executor.js.map +0 -1
  165. package/executors/help/executor.ts +0 -61
  166. package/executors/validate-eslint-sync/executor.js.map +0 -1
  167. package/executors/validate-eslint-sync/executor.ts +0 -87
  168. package/executors/validate-versions-locked/executor.js.map +0 -1
  169. package/executors/validate-versions-locked/executor.ts +0 -368
  170. package/plugin/README.md +0 -243
  171. package/plugin/index.d.ts +0 -4
  172. package/plugin/index.js +0 -8
  173. package/plugin/index.js.map +0 -1
  174. package/plugin/index.ts +0 -4
  175. /package/{executors → src/executors}/help/executor.js +0 -0
  176. /package/{executors → src/executors}/help/schema.json +0 -0
  177. /package/{executors → src/executors}/validate-eslint-sync/executor.d.ts +0 -0
  178. /package/{executors → src/executors}/validate-eslint-sync/executor.js +0 -0
  179. /package/{executors → src/executors}/validate-eslint-sync/schema.json +0 -0
  180. /package/{executors → src/executors}/validate-versions-locked/executor.d.ts +0 -0
  181. /package/{executors → src/executors}/validate-versions-locked/schema.json +0 -0
@@ -1,257 +0,0 @@
1
- "use strict";
2
- /**
3
- * ESLint rule to enforce maximum file length
4
- *
5
- * Enforces a configurable maximum line count for files.
6
- * Default: 700 lines
7
- *
8
- * Configuration:
9
- * '@webpieces/max-file-lines': ['error', { max: 700 }]
10
- */
11
- const tslib_1 = require("tslib");
12
- const fs = tslib_1.__importStar(require("fs"));
13
- const path = tslib_1.__importStar(require("path"));
14
- const toError_1 = require("../../toError");
15
- const FILE_DOC_CONTENT = `# AI Agent Instructions: File Too Long
16
-
17
- **READ THIS FILE to fix files that are too long**
18
-
19
- ## Core Principle
20
- Files should contain a SINGLE COHESIVE UNIT.
21
- - One class per file (Java convention)
22
- - If class is too large, extract child responsibilities
23
- - Use dependency injection to compose functionality
24
-
25
- ## Command: Reduce File Size
26
-
27
- ### Step 1: Check for Multiple Classes
28
- If the file contains multiple classes, **SEPARATE each class into its own file**.
29
-
30
- \`\`\`typescript
31
- // BAD: UserController.ts (multiple classes)
32
- export class UserController { /* ... */ }
33
- export class UserValidator { /* ... */ }
34
- export class UserNotifier { /* ... */ }
35
-
36
- // GOOD: Three separate files
37
- // UserController.ts
38
- export class UserController { /* ... */ }
39
-
40
- // UserValidator.ts
41
- export class UserValidator { /* ... */ }
42
-
43
- // UserNotifier.ts
44
- export class UserNotifier { /* ... */ }
45
- \`\`\`
46
-
47
- ### Step 2: Extract Child Responsibilities (if single class is too large)
48
-
49
- #### Pattern: Create New Service Class with Dependency Injection
50
-
51
- \`\`\`typescript
52
- // BAD: UserController.ts (800 lines, single class)
53
- @provideSingleton()
54
- @Controller()
55
- export class UserController {
56
- // 200 lines: CRUD operations
57
- // 300 lines: validation logic
58
- // 200 lines: notification logic
59
- // 100 lines: analytics logic
60
- }
61
-
62
- // GOOD: Extract validation service
63
- // 1. Create UserValidationService.ts
64
- @provideSingleton()
65
- export class UserValidationService {
66
- validateUserData(data: UserData): ValidationResult {
67
- // 300 lines of validation logic moved here
68
- }
69
-
70
- validateEmail(email: string): boolean { /* ... */ }
71
- validatePassword(password: string): boolean { /* ... */ }
72
- }
73
-
74
- // 2. Inject into UserController.ts
75
- @provideSingleton()
76
- @Controller()
77
- export class UserController {
78
- constructor(
79
- @inject(TYPES.UserValidationService)
80
- private validator: UserValidationService
81
- ) {}
82
-
83
- async createUser(data: UserData): Promise<User> {
84
- const validation = this.validator.validateUserData(data);
85
- if (!validation.isValid) {
86
- throw new ValidationError(validation.errors);
87
- }
88
- // ... rest of logic
89
- }
90
- }
91
- \`\`\`
92
-
93
- ## AI Agent Action Steps
94
-
95
- 1. **ANALYZE** the file structure:
96
- - Count classes (if >1, separate immediately)
97
- - Identify logical responsibilities within single class
98
-
99
- 2. **IDENTIFY** "child code" to extract:
100
- - Validation logic -> ValidationService
101
- - Notification logic -> NotificationService
102
- - Data transformation -> TransformerService
103
- - External API calls -> ApiService
104
- - Business rules -> RulesEngine
105
-
106
- 3. **CREATE** new service file(s):
107
- - Start with temporary name: \`XXXX.ts\` or \`ChildService.ts\`
108
- - Add \`@provideSingleton()\` decorator
109
- - Move child methods to new class
110
-
111
- 4. **UPDATE** dependency injection:
112
- - Add to \`TYPES\` constants (if using symbol-based DI)
113
- - Inject new service into original class constructor
114
- - Replace direct method calls with \`this.serviceName.method()\`
115
-
116
- 5. **RENAME** extracted file:
117
- - Read the extracted code to understand its purpose
118
- - Rename \`XXXX.ts\` to logical name (e.g., \`UserValidationService.ts\`)
119
-
120
- 6. **VERIFY** file sizes:
121
- - Original file should now be <700 lines
122
- - Each extracted file should be <700 lines
123
- - If still too large, extract more services
124
-
125
- ## Examples of Child Responsibilities to Extract
126
-
127
- | If File Contains | Extract To | Pattern |
128
- |-----------------|------------|---------|
129
- | Validation logic (200+ lines) | \`XValidator.ts\` or \`XValidationService.ts\` | Singleton service |
130
- | Notification logic (150+ lines) | \`XNotifier.ts\` or \`XNotificationService.ts\` | Singleton service |
131
- | Data transformation (200+ lines) | \`XTransformer.ts\` | Singleton service |
132
- | External API calls (200+ lines) | \`XApiClient.ts\` | Singleton service |
133
- | Complex business rules (300+ lines) | \`XRulesEngine.ts\` | Singleton service |
134
- | Database queries (200+ lines) | \`XRepository.ts\` | Singleton service |
135
-
136
- ## WebPieces Dependency Injection Pattern
137
-
138
- \`\`\`typescript
139
- // 1. Define service with @provideSingleton
140
- import { provideSingleton } from '@webpieces/http-routing';
141
-
142
- @provideSingleton()
143
- export class MyService {
144
- doSomething(): void { /* ... */ }
145
- }
146
-
147
- // 2. Inject into consumer
148
- import { inject } from 'inversify';
149
- import { TYPES } from './types';
150
-
151
- @provideSingleton()
152
- @Controller()
153
- export class MyController {
154
- constructor(
155
- @inject(TYPES.MyService) private service: MyService
156
- ) {}
157
- }
158
- \`\`\`
159
-
160
- Remember: Find the "child code" and pull it down into a new class. Once moved, the code's purpose becomes clear, making it easy to rename to a logical name.
161
- `;
162
- // Module-level flag to prevent redundant file creation
163
- let fileDocCreated = false;
164
- function getWorkspaceRoot(context) {
165
- const filename = context.filename || context.getFilename();
166
- let dir = path.dirname(filename);
167
- // Walk up directory tree to find workspace root
168
- while (dir !== path.dirname(dir)) {
169
- const pkgPath = path.join(dir, 'package.json');
170
- if (fs.existsSync(pkgPath)) {
171
- try {
172
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
173
- if (pkg.workspaces || pkg.name === 'webpieces-ts') {
174
- return dir;
175
- }
176
- }
177
- catch (err) {
178
- //const error = toError(err);
179
- void err; // Continue searching if JSON parse fails
180
- }
181
- }
182
- dir = path.dirname(dir);
183
- }
184
- return process.cwd(); // Fallback
185
- }
186
- function ensureDocFile(docPath, content) {
187
- try {
188
- fs.mkdirSync(path.dirname(docPath), { recursive: true });
189
- fs.writeFileSync(docPath, content, 'utf-8');
190
- return true;
191
- }
192
- catch (err) {
193
- const error = (0, toError_1.toError)(err);
194
- console.warn(`[webpieces] Could not create doc file: ${docPath}`, error);
195
- return false;
196
- }
197
- }
198
- function ensureFileDoc(context) {
199
- if (fileDocCreated)
200
- return; // Performance: only create once per lint run
201
- const workspaceRoot = getWorkspaceRoot(context);
202
- const docPath = path.join(workspaceRoot, 'tmp', 'webpieces', 'webpieces.filesize.md');
203
- if (ensureDocFile(docPath, FILE_DOC_CONTENT)) {
204
- fileDocCreated = true;
205
- }
206
- }
207
- const rule = {
208
- meta: {
209
- type: 'suggestion',
210
- docs: {
211
- description: 'Enforce maximum file length',
212
- category: 'Best Practices',
213
- recommended: false,
214
- url: 'https://github.com/deanhiller/webpieces-ts',
215
- },
216
- messages: {
217
- tooLong: 'AI Agent: READ tmp/webpieces/webpieces.filesize.md for fix instructions. File has {{actual}} lines (max: {{max}})',
218
- },
219
- fixable: undefined,
220
- schema: [
221
- {
222
- type: 'object',
223
- properties: {
224
- max: {
225
- type: 'integer',
226
- minimum: 1,
227
- },
228
- },
229
- additionalProperties: false,
230
- },
231
- ],
232
- },
233
- create(context) {
234
- const options = context.options[0];
235
- const maxLines = options?.max ?? 700;
236
- return {
237
- Program(node) {
238
- ensureFileDoc(context);
239
- const sourceCode = context.sourceCode || context.getSourceCode();
240
- const lines = sourceCode.lines;
241
- const lineCount = lines.length;
242
- if (lineCount > maxLines) {
243
- context.report({
244
- node,
245
- messageId: 'tooLong',
246
- data: {
247
- actual: String(lineCount),
248
- max: String(maxLines),
249
- },
250
- });
251
- }
252
- },
253
- };
254
- },
255
- };
256
- module.exports = rule;
257
- //# sourceMappingURL=max-file-lines.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"max-file-lines.js","sourceRoot":"","sources":["../../../../../../packages/tooling/dev-config/eslint-plugin/rules/max-file-lines.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ESLint rule to enforce maximum file length\n *\n * Enforces a configurable maximum line count for files.\n * Default: 700 lines\n *\n * Configuration:\n * '@webpieces/max-file-lines': ['error', { max: 700 }]\n */\n\nimport type { Rule } from 'eslint';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { toError } from '../../toError';\n\ninterface FileLinesOptions {\n max: number;\n}\n\nconst FILE_DOC_CONTENT = `# AI Agent Instructions: File Too Long\n\n**READ THIS FILE to fix files that are too long**\n\n## Core Principle\nFiles should contain a SINGLE COHESIVE UNIT.\n- One class per file (Java convention)\n- If class is too large, extract child responsibilities\n- Use dependency injection to compose functionality\n\n## Command: Reduce File Size\n\n### Step 1: Check for Multiple Classes\nIf the file contains multiple classes, **SEPARATE each class into its own file**.\n\n\\`\\`\\`typescript\n// BAD: UserController.ts (multiple classes)\nexport class UserController { /* ... */ }\nexport class UserValidator { /* ... */ }\nexport class UserNotifier { /* ... */ }\n\n// GOOD: Three separate files\n// UserController.ts\nexport class UserController { /* ... */ }\n\n// UserValidator.ts\nexport class UserValidator { /* ... */ }\n\n// UserNotifier.ts\nexport class UserNotifier { /* ... */ }\n\\`\\`\\`\n\n### Step 2: Extract Child Responsibilities (if single class is too large)\n\n#### Pattern: Create New Service Class with Dependency Injection\n\n\\`\\`\\`typescript\n// BAD: UserController.ts (800 lines, single class)\n@provideSingleton()\n@Controller()\nexport class UserController {\n // 200 lines: CRUD operations\n // 300 lines: validation logic\n // 200 lines: notification logic\n // 100 lines: analytics logic\n}\n\n// GOOD: Extract validation service\n// 1. Create UserValidationService.ts\n@provideSingleton()\nexport class UserValidationService {\n validateUserData(data: UserData): ValidationResult {\n // 300 lines of validation logic moved here\n }\n\n validateEmail(email: string): boolean { /* ... */ }\n validatePassword(password: string): boolean { /* ... */ }\n}\n\n// 2. Inject into UserController.ts\n@provideSingleton()\n@Controller()\nexport class UserController {\n constructor(\n @inject(TYPES.UserValidationService)\n private validator: UserValidationService\n ) {}\n\n async createUser(data: UserData): Promise<User> {\n const validation = this.validator.validateUserData(data);\n if (!validation.isValid) {\n throw new ValidationError(validation.errors);\n }\n // ... rest of logic\n }\n}\n\\`\\`\\`\n\n## AI Agent Action Steps\n\n1. **ANALYZE** the file structure:\n - Count classes (if >1, separate immediately)\n - Identify logical responsibilities within single class\n\n2. **IDENTIFY** \"child code\" to extract:\n - Validation logic -> ValidationService\n - Notification logic -> NotificationService\n - Data transformation -> TransformerService\n - External API calls -> ApiService\n - Business rules -> RulesEngine\n\n3. **CREATE** new service file(s):\n - Start with temporary name: \\`XXXX.ts\\` or \\`ChildService.ts\\`\n - Add \\`@provideSingleton()\\` decorator\n - Move child methods to new class\n\n4. **UPDATE** dependency injection:\n - Add to \\`TYPES\\` constants (if using symbol-based DI)\n - Inject new service into original class constructor\n - Replace direct method calls with \\`this.serviceName.method()\\`\n\n5. **RENAME** extracted file:\n - Read the extracted code to understand its purpose\n - Rename \\`XXXX.ts\\` to logical name (e.g., \\`UserValidationService.ts\\`)\n\n6. **VERIFY** file sizes:\n - Original file should now be <700 lines\n - Each extracted file should be <700 lines\n - If still too large, extract more services\n\n## Examples of Child Responsibilities to Extract\n\n| If File Contains | Extract To | Pattern |\n|-----------------|------------|---------|\n| Validation logic (200+ lines) | \\`XValidator.ts\\` or \\`XValidationService.ts\\` | Singleton service |\n| Notification logic (150+ lines) | \\`XNotifier.ts\\` or \\`XNotificationService.ts\\` | Singleton service |\n| Data transformation (200+ lines) | \\`XTransformer.ts\\` | Singleton service |\n| External API calls (200+ lines) | \\`XApiClient.ts\\` | Singleton service |\n| Complex business rules (300+ lines) | \\`XRulesEngine.ts\\` | Singleton service |\n| Database queries (200+ lines) | \\`XRepository.ts\\` | Singleton service |\n\n## WebPieces Dependency Injection Pattern\n\n\\`\\`\\`typescript\n// 1. Define service with @provideSingleton\nimport { provideSingleton } from '@webpieces/http-routing';\n\n@provideSingleton()\nexport class MyService {\n doSomething(): void { /* ... */ }\n}\n\n// 2. Inject into consumer\nimport { inject } from 'inversify';\nimport { TYPES } from './types';\n\n@provideSingleton()\n@Controller()\nexport class MyController {\n constructor(\n @inject(TYPES.MyService) private service: MyService\n ) {}\n}\n\\`\\`\\`\n\nRemember: Find the \"child code\" and pull it down into a new class. Once moved, the code's purpose becomes clear, making it easy to rename to a logical name.\n`;\n\n// Module-level flag to prevent redundant file creation\nlet fileDocCreated = false;\n\nfunction getWorkspaceRoot(context: Rule.RuleContext): string {\n const filename = context.filename || context.getFilename();\n let dir = path.dirname(filename);\n\n // Walk up directory tree to find workspace root\n while (dir !== path.dirname(dir)) {\n const pkgPath = path.join(dir, 'package.json');\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\n if (pkg.workspaces || pkg.name === 'webpieces-ts') {\n return dir;\n }\n } catch (err: unknown) {\n //const error = toError(err);\n void err; // Continue searching if JSON parse fails\n }\n }\n dir = path.dirname(dir);\n }\n return process.cwd(); // Fallback\n}\n\nfunction ensureDocFile(docPath: string, content: string): boolean {\n try {\n fs.mkdirSync(path.dirname(docPath), { recursive: true });\n fs.writeFileSync(docPath, content, 'utf-8');\n return true;\n } catch (err: unknown) {\n const error = toError(err);\n console.warn(`[webpieces] Could not create doc file: ${docPath}`, error);\n return false;\n }\n}\n\nfunction ensureFileDoc(context: Rule.RuleContext): void {\n if (fileDocCreated) return; // Performance: only create once per lint run\n\n const workspaceRoot = getWorkspaceRoot(context);\n const docPath = path.join(workspaceRoot, 'tmp', 'webpieces', 'webpieces.filesize.md');\n\n if (ensureDocFile(docPath, FILE_DOC_CONTENT)) {\n fileDocCreated = true;\n }\n}\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Enforce maximum file length',\n category: 'Best Practices',\n recommended: false,\n url: 'https://github.com/deanhiller/webpieces-ts',\n },\n messages: {\n tooLong:\n 'AI Agent: READ tmp/webpieces/webpieces.filesize.md for fix instructions. File has {{actual}} lines (max: {{max}})',\n },\n fixable: undefined,\n schema: [\n {\n type: 'object',\n properties: {\n max: {\n type: 'integer',\n minimum: 1,\n },\n },\n additionalProperties: false,\n },\n ],\n },\n\n create(context: Rule.RuleContext): Rule.RuleListener {\n const options = context.options[0] as FileLinesOptions | undefined;\n const maxLines = options?.max ?? 700;\n\n return {\n Program(node: any): void {\n ensureFileDoc(context);\n\n const sourceCode = context.sourceCode || context.getSourceCode();\n const lines = sourceCode.lines;\n const lineCount = lines.length;\n\n if (lineCount > maxLines) {\n context.report({\n node,\n messageId: 'tooLong',\n data: {\n actual: String(lineCount),\n max: String(maxLines),\n },\n });\n }\n },\n };\n },\n};\n\nexport = rule;\n"]}
@@ -1,272 +0,0 @@
1
- /**
2
- * ESLint rule to enforce maximum file length
3
- *
4
- * Enforces a configurable maximum line count for files.
5
- * Default: 700 lines
6
- *
7
- * Configuration:
8
- * '@webpieces/max-file-lines': ['error', { max: 700 }]
9
- */
10
-
11
- import type { Rule } from 'eslint';
12
- import * as fs from 'fs';
13
- import * as path from 'path';
14
- import { toError } from '../../toError';
15
-
16
- interface FileLinesOptions {
17
- max: number;
18
- }
19
-
20
- const FILE_DOC_CONTENT = `# AI Agent Instructions: File Too Long
21
-
22
- **READ THIS FILE to fix files that are too long**
23
-
24
- ## Core Principle
25
- Files should contain a SINGLE COHESIVE UNIT.
26
- - One class per file (Java convention)
27
- - If class is too large, extract child responsibilities
28
- - Use dependency injection to compose functionality
29
-
30
- ## Command: Reduce File Size
31
-
32
- ### Step 1: Check for Multiple Classes
33
- If the file contains multiple classes, **SEPARATE each class into its own file**.
34
-
35
- \`\`\`typescript
36
- // BAD: UserController.ts (multiple classes)
37
- export class UserController { /* ... */ }
38
- export class UserValidator { /* ... */ }
39
- export class UserNotifier { /* ... */ }
40
-
41
- // GOOD: Three separate files
42
- // UserController.ts
43
- export class UserController { /* ... */ }
44
-
45
- // UserValidator.ts
46
- export class UserValidator { /* ... */ }
47
-
48
- // UserNotifier.ts
49
- export class UserNotifier { /* ... */ }
50
- \`\`\`
51
-
52
- ### Step 2: Extract Child Responsibilities (if single class is too large)
53
-
54
- #### Pattern: Create New Service Class with Dependency Injection
55
-
56
- \`\`\`typescript
57
- // BAD: UserController.ts (800 lines, single class)
58
- @provideSingleton()
59
- @Controller()
60
- export class UserController {
61
- // 200 lines: CRUD operations
62
- // 300 lines: validation logic
63
- // 200 lines: notification logic
64
- // 100 lines: analytics logic
65
- }
66
-
67
- // GOOD: Extract validation service
68
- // 1. Create UserValidationService.ts
69
- @provideSingleton()
70
- export class UserValidationService {
71
- validateUserData(data: UserData): ValidationResult {
72
- // 300 lines of validation logic moved here
73
- }
74
-
75
- validateEmail(email: string): boolean { /* ... */ }
76
- validatePassword(password: string): boolean { /* ... */ }
77
- }
78
-
79
- // 2. Inject into UserController.ts
80
- @provideSingleton()
81
- @Controller()
82
- export class UserController {
83
- constructor(
84
- @inject(TYPES.UserValidationService)
85
- private validator: UserValidationService
86
- ) {}
87
-
88
- async createUser(data: UserData): Promise<User> {
89
- const validation = this.validator.validateUserData(data);
90
- if (!validation.isValid) {
91
- throw new ValidationError(validation.errors);
92
- }
93
- // ... rest of logic
94
- }
95
- }
96
- \`\`\`
97
-
98
- ## AI Agent Action Steps
99
-
100
- 1. **ANALYZE** the file structure:
101
- - Count classes (if >1, separate immediately)
102
- - Identify logical responsibilities within single class
103
-
104
- 2. **IDENTIFY** "child code" to extract:
105
- - Validation logic -> ValidationService
106
- - Notification logic -> NotificationService
107
- - Data transformation -> TransformerService
108
- - External API calls -> ApiService
109
- - Business rules -> RulesEngine
110
-
111
- 3. **CREATE** new service file(s):
112
- - Start with temporary name: \`XXXX.ts\` or \`ChildService.ts\`
113
- - Add \`@provideSingleton()\` decorator
114
- - Move child methods to new class
115
-
116
- 4. **UPDATE** dependency injection:
117
- - Add to \`TYPES\` constants (if using symbol-based DI)
118
- - Inject new service into original class constructor
119
- - Replace direct method calls with \`this.serviceName.method()\`
120
-
121
- 5. **RENAME** extracted file:
122
- - Read the extracted code to understand its purpose
123
- - Rename \`XXXX.ts\` to logical name (e.g., \`UserValidationService.ts\`)
124
-
125
- 6. **VERIFY** file sizes:
126
- - Original file should now be <700 lines
127
- - Each extracted file should be <700 lines
128
- - If still too large, extract more services
129
-
130
- ## Examples of Child Responsibilities to Extract
131
-
132
- | If File Contains | Extract To | Pattern |
133
- |-----------------|------------|---------|
134
- | Validation logic (200+ lines) | \`XValidator.ts\` or \`XValidationService.ts\` | Singleton service |
135
- | Notification logic (150+ lines) | \`XNotifier.ts\` or \`XNotificationService.ts\` | Singleton service |
136
- | Data transformation (200+ lines) | \`XTransformer.ts\` | Singleton service |
137
- | External API calls (200+ lines) | \`XApiClient.ts\` | Singleton service |
138
- | Complex business rules (300+ lines) | \`XRulesEngine.ts\` | Singleton service |
139
- | Database queries (200+ lines) | \`XRepository.ts\` | Singleton service |
140
-
141
- ## WebPieces Dependency Injection Pattern
142
-
143
- \`\`\`typescript
144
- // 1. Define service with @provideSingleton
145
- import { provideSingleton } from '@webpieces/http-routing';
146
-
147
- @provideSingleton()
148
- export class MyService {
149
- doSomething(): void { /* ... */ }
150
- }
151
-
152
- // 2. Inject into consumer
153
- import { inject } from 'inversify';
154
- import { TYPES } from './types';
155
-
156
- @provideSingleton()
157
- @Controller()
158
- export class MyController {
159
- constructor(
160
- @inject(TYPES.MyService) private service: MyService
161
- ) {}
162
- }
163
- \`\`\`
164
-
165
- Remember: Find the "child code" and pull it down into a new class. Once moved, the code's purpose becomes clear, making it easy to rename to a logical name.
166
- `;
167
-
168
- // Module-level flag to prevent redundant file creation
169
- let fileDocCreated = false;
170
-
171
- function getWorkspaceRoot(context: Rule.RuleContext): string {
172
- const filename = context.filename || context.getFilename();
173
- let dir = path.dirname(filename);
174
-
175
- // Walk up directory tree to find workspace root
176
- while (dir !== path.dirname(dir)) {
177
- const pkgPath = path.join(dir, 'package.json');
178
- if (fs.existsSync(pkgPath)) {
179
- try {
180
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
181
- if (pkg.workspaces || pkg.name === 'webpieces-ts') {
182
- return dir;
183
- }
184
- } catch (err: unknown) {
185
- //const error = toError(err);
186
- void err; // Continue searching if JSON parse fails
187
- }
188
- }
189
- dir = path.dirname(dir);
190
- }
191
- return process.cwd(); // Fallback
192
- }
193
-
194
- function ensureDocFile(docPath: string, content: string): boolean {
195
- try {
196
- fs.mkdirSync(path.dirname(docPath), { recursive: true });
197
- fs.writeFileSync(docPath, content, 'utf-8');
198
- return true;
199
- } catch (err: unknown) {
200
- const error = toError(err);
201
- console.warn(`[webpieces] Could not create doc file: ${docPath}`, error);
202
- return false;
203
- }
204
- }
205
-
206
- function ensureFileDoc(context: Rule.RuleContext): void {
207
- if (fileDocCreated) return; // Performance: only create once per lint run
208
-
209
- const workspaceRoot = getWorkspaceRoot(context);
210
- const docPath = path.join(workspaceRoot, 'tmp', 'webpieces', 'webpieces.filesize.md');
211
-
212
- if (ensureDocFile(docPath, FILE_DOC_CONTENT)) {
213
- fileDocCreated = true;
214
- }
215
- }
216
-
217
- const rule: Rule.RuleModule = {
218
- meta: {
219
- type: 'suggestion',
220
- docs: {
221
- description: 'Enforce maximum file length',
222
- category: 'Best Practices',
223
- recommended: false,
224
- url: 'https://github.com/deanhiller/webpieces-ts',
225
- },
226
- messages: {
227
- tooLong:
228
- 'AI Agent: READ tmp/webpieces/webpieces.filesize.md for fix instructions. File has {{actual}} lines (max: {{max}})',
229
- },
230
- fixable: undefined,
231
- schema: [
232
- {
233
- type: 'object',
234
- properties: {
235
- max: {
236
- type: 'integer',
237
- minimum: 1,
238
- },
239
- },
240
- additionalProperties: false,
241
- },
242
- ],
243
- },
244
-
245
- create(context: Rule.RuleContext): Rule.RuleListener {
246
- const options = context.options[0] as FileLinesOptions | undefined;
247
- const maxLines = options?.max ?? 700;
248
-
249
- return {
250
- Program(node: any): void {
251
- ensureFileDoc(context);
252
-
253
- const sourceCode = context.sourceCode || context.getSourceCode();
254
- const lines = sourceCode.lines;
255
- const lineCount = lines.length;
256
-
257
- if (lineCount > maxLines) {
258
- context.report({
259
- node,
260
- messageId: 'tooLong',
261
- data: {
262
- actual: String(lineCount),
263
- max: String(maxLines),
264
- },
265
- });
266
- }
267
- },
268
- };
269
- },
270
- };
271
-
272
- export = rule;
@@ -1,12 +0,0 @@
1
- /**
2
- * ESLint rule to enforce maximum method length
3
- *
4
- * Enforces a configurable maximum line count for methods, functions, and arrow functions.
5
- * Default: 70 lines
6
- *
7
- * Configuration:
8
- * '@webpieces/max-method-lines': ['error', { max: 70 }]
9
- */
10
- import type { Rule } from 'eslint';
11
- declare const rule: Rule.RuleModule;
12
- export = rule;