@webpieces/dev-config 0.2.95 → 0.2.98

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,669 +0,0 @@
1
- "use strict";
2
- /**
3
- * Validate No Inline Types Executor
4
- *
5
- * Validates that inline type literals AND tuple types are not used in type positions.
6
- * Prefer named types/interfaces/classes for clarity and reusability.
7
- *
8
- * ============================================================================
9
- * VIOLATIONS (BAD) - These patterns are flagged:
10
- * ============================================================================
11
- *
12
- * 1. INLINE TYPE LITERALS { }
13
- * -------------------------
14
- * - Inline parameter type: function foo(arg: { x: number }) { }
15
- * - Inline return type: function foo(): { x: number } { }
16
- * - Inline variable type: const config: { timeout: number } = { timeout: 5 };
17
- * - Inline property type: class C { data: { id: number }; }
18
- * - Inline in union: type T = { x: number } | null;
19
- * - Inline in intersection: type T = { x: number } & { y: number };
20
- * - Inline in generic: Promise<{ data: string }>
21
- * - Inline in array: function foo(): { id: string }[] { }
22
- * - Nested inline in alias: type T = { data: { nested: number } }; // inner { } flagged
23
- * - Inline in tuple: type T = [{ x: number }, string];
24
- *
25
- * 2. TUPLE TYPES [ ]
26
- * ----------------
27
- * - Tuple return type: function foo(): [Items[], number] { }
28
- * - Tuple parameter type: function foo(arg: [string, number]) { }
29
- * - Tuple variable type: const result: [Data[], number] = getData();
30
- * - Tuple in generic: Promise<[Items[], number]>
31
- * - Tuple in union: type T = [A, B] | null;
32
- * - Nested tuple: type T = { data: [A, B] };
33
- *
34
- * ============================================================================
35
- * ALLOWED (GOOD) - These patterns pass validation:
36
- * ============================================================================
37
- *
38
- * 1. TYPE ALIAS DEFINITIONS (direct body only)
39
- * -----------------------------------------
40
- * - Type alias with literal: type MyConfig = { timeout: number };
41
- * - Type alias with tuple: type MyResult = [Items[], number];
42
- * - Interface definition: interface MyData { id: number }
43
- * - Class definition: class UserData { id: number; name: string; }
44
- *
45
- * 2. USING NAMED TYPES
46
- * ------------------
47
- * - Named param type: function foo(arg: MyConfig) { }
48
- * - Named return type: function foo(): MyConfig { }
49
- * - Named with null: function foo(): MyConfig | null { }
50
- * - Named with undefined: function foo(): MyConfig | undefined { }
51
- * - Union of named types: type Either = TypeA | TypeB;
52
- * - Named in generic: Promise<MyResult>
53
- * - Named tuple alias: function foo(): MyTupleResult { }
54
- *
55
- * 3. PRIMITIVES AND BUILT-INS
56
- * -------------------------
57
- * - Primitive types: function foo(): string { }
58
- * - Primitive arrays: function foo(): string[] { }
59
- * - Built-in generics: function foo(): Promise<string> { }
60
- * - Void return: function foo(): void { }
61
- *
62
- * ============================================================================
63
- * MODES
64
- * ============================================================================
65
- * - OFF: Skip validation entirely
66
- * - NEW_METHODS: Only validate in new methods (detected via git diff)
67
- * - NEW_AND_MODIFIED_METHODS: Validate in new methods + methods with changes
68
- * - MODIFIED_FILES: Validate all violations in modified files
69
- *
70
- * ============================================================================
71
- * ESCAPE HATCH
72
- * ============================================================================
73
- * Add comment above the violation:
74
- * // webpieces-disable no-inline-types -- [your justification]
75
- * function foo(arg: { x: number }) { }
76
- *
77
- * Use sparingly! Common valid reasons:
78
- * - Prisma payload types that require inline generics
79
- * - Third-party library APIs that expect inline types
80
- * - Legacy code being incrementally migrated
81
- */
82
- Object.defineProperty(exports, "__esModule", { value: true });
83
- exports.default = runExecutor;
84
- const tslib_1 = require("tslib");
85
- const child_process_1 = require("child_process");
86
- const fs = tslib_1.__importStar(require("fs"));
87
- const path = tslib_1.__importStar(require("path"));
88
- const ts = tslib_1.__importStar(require("typescript"));
89
- /**
90
- * Get changed TypeScript files between base and head (or working tree if head not specified).
91
- */
92
- // webpieces-disable max-lines-new-methods -- Git command handling with untracked files requires multiple code paths
93
- function getChangedTypeScriptFiles(workspaceRoot, base, head) {
94
- try {
95
- const diffTarget = head ? `${base} ${head}` : base;
96
- const output = (0, child_process_1.execSync)(`git diff --name-only ${diffTarget} -- '*.ts' '*.tsx'`, {
97
- cwd: workspaceRoot,
98
- encoding: 'utf-8',
99
- });
100
- const changedFiles = output
101
- .trim()
102
- .split('\n')
103
- .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));
104
- if (!head) {
105
- try {
106
- const untrackedOutput = (0, child_process_1.execSync)(`git ls-files --others --exclude-standard '*.ts' '*.tsx'`, {
107
- cwd: workspaceRoot,
108
- encoding: 'utf-8',
109
- });
110
- const untrackedFiles = untrackedOutput
111
- .trim()
112
- .split('\n')
113
- .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));
114
- const allFiles = new Set([...changedFiles, ...untrackedFiles]);
115
- return Array.from(allFiles);
116
- }
117
- catch {
118
- return changedFiles;
119
- }
120
- }
121
- return changedFiles;
122
- }
123
- catch {
124
- return [];
125
- }
126
- }
127
- /**
128
- * Get the diff content for a specific file.
129
- */
130
- function getFileDiff(workspaceRoot, file, base, head) {
131
- try {
132
- const diffTarget = head ? `${base} ${head}` : base;
133
- const diff = (0, child_process_1.execSync)(`git diff ${diffTarget} -- "${file}"`, {
134
- cwd: workspaceRoot,
135
- encoding: 'utf-8',
136
- });
137
- if (!diff && !head) {
138
- const fullPath = path.join(workspaceRoot, file);
139
- if (fs.existsSync(fullPath)) {
140
- const isUntracked = (0, child_process_1.execSync)(`git ls-files --others --exclude-standard "${file}"`, {
141
- cwd: workspaceRoot,
142
- encoding: 'utf-8',
143
- }).trim();
144
- if (isUntracked) {
145
- const content = fs.readFileSync(fullPath, 'utf-8');
146
- const lines = content.split('\n');
147
- return lines.map((line) => `+${line}`).join('\n');
148
- }
149
- }
150
- }
151
- return diff;
152
- }
153
- catch {
154
- return '';
155
- }
156
- }
157
- /**
158
- * Parse diff to extract changed line numbers (both additions and modifications).
159
- */
160
- function getChangedLineNumbers(diffContent) {
161
- const changedLines = new Set();
162
- const lines = diffContent.split('\n');
163
- let currentLine = 0;
164
- for (const line of lines) {
165
- const hunkMatch = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
166
- if (hunkMatch) {
167
- currentLine = parseInt(hunkMatch[1], 10);
168
- continue;
169
- }
170
- if (line.startsWith('+') && !line.startsWith('+++')) {
171
- changedLines.add(currentLine);
172
- currentLine++;
173
- }
174
- else if (line.startsWith('-') && !line.startsWith('---')) {
175
- // Deletions don't increment line number
176
- }
177
- else {
178
- currentLine++;
179
- }
180
- }
181
- return changedLines;
182
- }
183
- /**
184
- * Check if a line contains a webpieces-disable comment for no-inline-types.
185
- */
186
- function hasDisableComment(lines, lineNumber) {
187
- const startCheck = Math.max(0, lineNumber - 5);
188
- for (let i = lineNumber - 2; i >= startCheck; i--) {
189
- const line = lines[i]?.trim() ?? '';
190
- if (line.startsWith('function ') || line.startsWith('class ') || line.endsWith('}')) {
191
- break;
192
- }
193
- if (line.includes('webpieces-disable') && line.includes('no-inline-types')) {
194
- return true;
195
- }
196
- }
197
- return false;
198
- }
199
- /**
200
- * Check if a TypeLiteral or TupleType node is in an allowed context.
201
- * Only allowed if the DIRECT parent is a TypeAliasDeclaration.
202
- *
203
- * ALLOWED:
204
- * type MyConfig = { x: number }; // TypeLiteral direct child of TypeAliasDeclaration
205
- * type MyTuple = [A, B]; // TupleType direct child of TypeAliasDeclaration
206
- *
207
- * NOT ALLOWED (flagged):
208
- * type T = { x: number } | null; // Parent is UnionType, not TypeAliasDeclaration
209
- * type T = { data: { nested: number } }; // Inner TypeLiteral's parent is PropertySignature
210
- * function foo(): [A, B] { } // TupleType's parent is FunctionDeclaration
211
- * type T = Prisma.GetPayload<{ include: {...} }>; // TypeLiteral in generic argument
212
- *
213
- * NOTE: Prisma types require inline type literals in generic arguments. Use the escape hatch:
214
- * // webpieces-disable no-inline-types -- Prisma API requires inline type argument
215
- * type T = Prisma.GetPayload<{ include: {...} }>;
216
- */
217
- function isInAllowedContext(node) {
218
- const parent = node.parent;
219
- if (!parent)
220
- return false;
221
- // Only allowed if it's the DIRECT body of a type alias
222
- if (ts.isTypeAliasDeclaration(parent)) {
223
- return true;
224
- }
225
- return false;
226
- }
227
- /**
228
- * Get a description of the context where the inline type or tuple appears.
229
- *
230
- * Returns human-readable context like:
231
- * - "inline parameter type"
232
- * - "tuple return type"
233
- * - "inline type in generic argument"
234
- */
235
- // webpieces-disable max-lines-new-methods -- Context detection requires checking many AST node types
236
- function getViolationContext(node, sourceFile) {
237
- try {
238
- const isTuple = ts.isTupleTypeNode(node);
239
- const prefix = isTuple ? 'tuple' : 'inline';
240
- let current = node;
241
- while (current.parent) {
242
- const parent = current.parent;
243
- if (ts.isParameter(parent)) {
244
- return `${prefix} parameter type`;
245
- }
246
- if (ts.isFunctionDeclaration(parent) || ts.isMethodDeclaration(parent) || ts.isArrowFunction(parent)) {
247
- if (parent.type === current) {
248
- return `${prefix} return type`;
249
- }
250
- }
251
- if (ts.isVariableDeclaration(parent)) {
252
- return `${prefix} variable type`;
253
- }
254
- if (ts.isPropertyDeclaration(parent) || ts.isPropertySignature(parent)) {
255
- if (parent.type === current) {
256
- return `${prefix} property type`;
257
- }
258
- // Check if it's nested inside another type literal
259
- let ancestor = parent.parent;
260
- while (ancestor) {
261
- if (ts.isTypeLiteralNode(ancestor)) {
262
- return `nested ${prefix} type`;
263
- }
264
- if (ts.isTypeAliasDeclaration(ancestor)) {
265
- return `nested ${prefix} type in type alias`;
266
- }
267
- ancestor = ancestor.parent;
268
- }
269
- }
270
- if (ts.isUnionTypeNode(parent) || ts.isIntersectionTypeNode(parent)) {
271
- return `${prefix} type in union/intersection`;
272
- }
273
- // Safely check parent.parent before accessing it
274
- if (parent.parent && ts.isTypeReferenceNode(parent.parent) && ts.isTypeNode(parent)) {
275
- return `${prefix} type in generic argument`;
276
- }
277
- // Direct parent is TypeReferenceNode (e.g., Prisma.GetPayload<{...}>)
278
- if (ts.isTypeReferenceNode(parent)) {
279
- return `${prefix} type in generic argument`;
280
- }
281
- if (ts.isArrayTypeNode(parent)) {
282
- return `${prefix} type in array`;
283
- }
284
- if (ts.isTupleTypeNode(parent) && !isTuple) {
285
- return `inline type in tuple`;
286
- }
287
- current = parent;
288
- }
289
- return isTuple ? 'tuple type' : 'inline type literal';
290
- }
291
- catch (error) {
292
- // Defensive: return generic context if AST traversal fails
293
- return ts.isTupleTypeNode(node) ? 'tuple type' : 'inline type literal';
294
- }
295
- }
296
- /**
297
- * Find all methods/functions in a file with their line ranges.
298
- */
299
- // webpieces-disable max-lines-new-methods -- AST traversal requires inline visitor function
300
- function findMethodsInFile(filePath, workspaceRoot) {
301
- const fullPath = path.join(workspaceRoot, filePath);
302
- if (!fs.existsSync(fullPath))
303
- return [];
304
- const content = fs.readFileSync(fullPath, 'utf-8');
305
- const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
306
- const methods = [];
307
- // webpieces-disable max-lines-new-methods -- AST visitor pattern requires handling multiple node types
308
- function visit(node) {
309
- let methodName;
310
- let startLine;
311
- let endLine;
312
- if (ts.isMethodDeclaration(node) && node.name) {
313
- methodName = node.name.getText(sourceFile);
314
- const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
315
- const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
316
- startLine = start.line + 1;
317
- endLine = end.line + 1;
318
- }
319
- else if (ts.isFunctionDeclaration(node) && node.name) {
320
- methodName = node.name.getText(sourceFile);
321
- const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
322
- const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
323
- startLine = start.line + 1;
324
- endLine = end.line + 1;
325
- }
326
- else if (ts.isArrowFunction(node)) {
327
- if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
328
- methodName = node.parent.name.getText(sourceFile);
329
- const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
330
- const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
331
- startLine = start.line + 1;
332
- endLine = end.line + 1;
333
- }
334
- }
335
- if (methodName && startLine !== undefined && endLine !== undefined) {
336
- methods.push({ name: methodName, startLine, endLine });
337
- }
338
- ts.forEachChild(node, visit);
339
- }
340
- visit(sourceFile);
341
- return methods;
342
- }
343
- /**
344
- * Check if a line is within any method's range and if that method has changes.
345
- */
346
- function isLineInChangedMethod(line, methods, changedLines, newMethodNames) {
347
- for (const method of methods) {
348
- if (line >= method.startLine && line <= method.endLine) {
349
- // Check if this method is new or has changes
350
- if (newMethodNames.has(method.name)) {
351
- return true;
352
- }
353
- // Check if any line in the method range has changes
354
- for (let l = method.startLine; l <= method.endLine; l++) {
355
- if (changedLines.has(l)) {
356
- return true;
357
- }
358
- }
359
- }
360
- }
361
- return false;
362
- }
363
- /**
364
- * Check if a line is within a new method.
365
- */
366
- function isLineInNewMethod(line, methods, newMethodNames) {
367
- for (const method of methods) {
368
- if (line >= method.startLine && line <= method.endLine && newMethodNames.has(method.name)) {
369
- return true;
370
- }
371
- }
372
- return false;
373
- }
374
- /**
375
- * Parse diff to find newly added method signatures.
376
- */
377
- function findNewMethodSignaturesInDiff(diffContent) {
378
- const newMethods = new Set();
379
- const lines = diffContent.split('\n');
380
- const patterns = [
381
- /^\+\s*(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(/,
382
- /^\+\s*(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*(?:async\s*)?\(/,
383
- /^\+\s*(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*(?:async\s+)?function/,
384
- /^\+\s*(?:(?:public|private|protected)\s+)?(?:static\s+)?(?:async\s+)?(\w+)\s*\(/,
385
- ];
386
- for (const line of lines) {
387
- if (line.startsWith('+') && !line.startsWith('+++')) {
388
- for (const pattern of patterns) {
389
- const match = line.match(pattern);
390
- if (match) {
391
- const methodName = match[1];
392
- if (methodName && !['if', 'for', 'while', 'switch', 'catch', 'constructor'].includes(methodName)) {
393
- newMethods.add(methodName);
394
- }
395
- break;
396
- }
397
- }
398
- }
399
- }
400
- return newMethods;
401
- }
402
- /**
403
- * Find all inline type literals AND tuple types in a file.
404
- *
405
- * Detects:
406
- * - TypeLiteral nodes: { x: number }
407
- * - TupleType nodes: [A, B]
408
- *
409
- * Both are flagged unless they are the DIRECT body of a type alias.
410
- */
411
- // webpieces-disable max-lines-new-methods -- AST traversal with visitor pattern
412
- function findInlineTypesInFile(filePath, workspaceRoot) {
413
- const fullPath = path.join(workspaceRoot, filePath);
414
- if (!fs.existsSync(fullPath))
415
- return [];
416
- const content = fs.readFileSync(fullPath, 'utf-8');
417
- const fileLines = content.split('\n');
418
- const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
419
- const inlineTypes = [];
420
- function visit(node) {
421
- try {
422
- // Check for inline type literals: { x: number }
423
- if (ts.isTypeLiteralNode(node)) {
424
- if (!isInAllowedContext(node)) {
425
- const startPos = node.getStart(sourceFile);
426
- if (startPos >= 0) {
427
- const pos = sourceFile.getLineAndCharacterOfPosition(startPos);
428
- const line = pos.line + 1;
429
- const column = pos.character + 1;
430
- const context = getViolationContext(node, sourceFile);
431
- const disabled = hasDisableComment(fileLines, line);
432
- inlineTypes.push({
433
- line,
434
- column,
435
- context,
436
- hasDisableComment: disabled,
437
- });
438
- }
439
- }
440
- }
441
- // Check for tuple types: [A, B]
442
- if (ts.isTupleTypeNode(node)) {
443
- if (!isInAllowedContext(node)) {
444
- const startPos = node.getStart(sourceFile);
445
- if (startPos >= 0) {
446
- const pos = sourceFile.getLineAndCharacterOfPosition(startPos);
447
- const line = pos.line + 1;
448
- const column = pos.character + 1;
449
- const context = getViolationContext(node, sourceFile);
450
- const disabled = hasDisableComment(fileLines, line);
451
- inlineTypes.push({
452
- line,
453
- column,
454
- context,
455
- hasDisableComment: disabled,
456
- });
457
- }
458
- }
459
- }
460
- }
461
- catch (error) {
462
- // Skip nodes that cause errors during analysis
463
- }
464
- ts.forEachChild(node, visit);
465
- }
466
- visit(sourceFile);
467
- return inlineTypes;
468
- }
469
- /**
470
- * Find violations in new methods only (NEW_METHODS mode).
471
- */
472
- // webpieces-disable max-lines-new-methods -- File iteration with diff parsing and method matching
473
- function findViolationsForNewMethods(workspaceRoot, changedFiles, base, head, disableAllowed) {
474
- const violations = [];
475
- for (const file of changedFiles) {
476
- const diff = getFileDiff(workspaceRoot, file, base, head);
477
- const newMethodNames = findNewMethodSignaturesInDiff(diff);
478
- if (newMethodNames.size === 0)
479
- continue;
480
- const methods = findMethodsInFile(file, workspaceRoot);
481
- const inlineTypes = findInlineTypesInFile(file, workspaceRoot);
482
- for (const inlineType of inlineTypes) {
483
- if (disableAllowed && inlineType.hasDisableComment)
484
- continue;
485
- if (!isLineInNewMethod(inlineType.line, methods, newMethodNames))
486
- continue;
487
- violations.push({
488
- file,
489
- line: inlineType.line,
490
- column: inlineType.column,
491
- context: inlineType.context,
492
- });
493
- }
494
- }
495
- return violations;
496
- }
497
- /**
498
- * Find violations in new and modified methods (NEW_AND_MODIFIED_METHODS mode).
499
- */
500
- // webpieces-disable max-lines-new-methods -- Combines new method detection with change detection
501
- function findViolationsForModifiedAndNewMethods(workspaceRoot, changedFiles, base, head, disableAllowed) {
502
- const violations = [];
503
- for (const file of changedFiles) {
504
- const diff = getFileDiff(workspaceRoot, file, base, head);
505
- const newMethodNames = findNewMethodSignaturesInDiff(diff);
506
- const changedLines = getChangedLineNumbers(diff);
507
- const methods = findMethodsInFile(file, workspaceRoot);
508
- const inlineTypes = findInlineTypesInFile(file, workspaceRoot);
509
- for (const inlineType of inlineTypes) {
510
- if (disableAllowed && inlineType.hasDisableComment)
511
- continue;
512
- if (!isLineInChangedMethod(inlineType.line, methods, changedLines, newMethodNames))
513
- continue;
514
- violations.push({
515
- file,
516
- line: inlineType.line,
517
- column: inlineType.column,
518
- context: inlineType.context,
519
- });
520
- }
521
- }
522
- return violations;
523
- }
524
- /**
525
- * Find all violations in modified files (MODIFIED_FILES mode).
526
- */
527
- function findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed) {
528
- const violations = [];
529
- for (const file of changedFiles) {
530
- const inlineTypes = findInlineTypesInFile(file, workspaceRoot);
531
- for (const inlineType of inlineTypes) {
532
- if (disableAllowed && inlineType.hasDisableComment)
533
- continue;
534
- violations.push({
535
- file,
536
- line: inlineType.line,
537
- column: inlineType.column,
538
- context: inlineType.context,
539
- });
540
- }
541
- }
542
- return violations;
543
- }
544
- /**
545
- * Auto-detect the base branch by finding the merge-base with origin/main.
546
- */
547
- function detectBase(workspaceRoot) {
548
- try {
549
- const mergeBase = (0, child_process_1.execSync)('git merge-base HEAD origin/main', {
550
- cwd: workspaceRoot,
551
- encoding: 'utf-8',
552
- stdio: ['pipe', 'pipe', 'pipe'],
553
- }).trim();
554
- if (mergeBase) {
555
- return mergeBase;
556
- }
557
- }
558
- catch {
559
- try {
560
- const mergeBase = (0, child_process_1.execSync)('git merge-base HEAD main', {
561
- cwd: workspaceRoot,
562
- encoding: 'utf-8',
563
- stdio: ['pipe', 'pipe', 'pipe'],
564
- }).trim();
565
- if (mergeBase) {
566
- return mergeBase;
567
- }
568
- }
569
- catch {
570
- // Ignore
571
- }
572
- }
573
- return null;
574
- }
575
- /**
576
- * Report violations to console.
577
- */
578
- function reportViolations(violations, mode) {
579
- console.error('');
580
- console.error('❌ Inline type literals found! Use named types instead.');
581
- console.error('');
582
- console.error('📚 Named types improve code clarity and reusability:');
583
- console.error('');
584
- console.error(' BAD: function foo(arg: { x: number }) { }');
585
- console.error(' GOOD: type MyConfig = { x: number };');
586
- console.error(' function foo(arg: MyConfig) { }');
587
- console.error('');
588
- console.error(' BAD: type Nullable = { x: number } | null;');
589
- console.error(' GOOD: type MyData = { x: number };');
590
- console.error(' type Nullable = MyData | null;');
591
- console.error('');
592
- for (const v of violations) {
593
- console.error(` ❌ ${v.file}:${v.line}:${v.column}`);
594
- console.error(` ${v.context}`);
595
- }
596
- console.error('');
597
- console.error(' To fix: Extract inline types to named type aliases or interfaces');
598
- console.error('');
599
- console.error(' Escape hatch (use sparingly):');
600
- console.error(' // webpieces-disable no-inline-types -- [your reason]');
601
- console.error('');
602
- console.error(` Current mode: ${mode}`);
603
- console.error('');
604
- }
605
- /**
606
- * Resolve mode considering ignoreModifiedUntilEpoch override.
607
- * When active, downgrades to OFF. When expired, logs a warning.
608
- */
609
- function resolveMode(normalMode, epoch) {
610
- if (epoch === undefined || normalMode === 'OFF') {
611
- return normalMode;
612
- }
613
- const nowSeconds = Date.now() / 1000;
614
- if (nowSeconds < epoch) {
615
- const expiresDate = new Date(epoch * 1000).toISOString().split('T')[0];
616
- console.log(`\n⏭️ Skipping no-inline-types validation (ignoreModifiedUntilEpoch active, expires: ${expiresDate})`);
617
- console.log('');
618
- return 'OFF';
619
- }
620
- return normalMode;
621
- }
622
- async function runExecutor(options, context) {
623
- const workspaceRoot = context.root;
624
- const mode = resolveMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch);
625
- const disableAllowed = options.disableAllowed ?? true;
626
- if (mode === 'OFF') {
627
- console.log('\n⏭️ Skipping no-inline-types validation (mode: OFF)');
628
- console.log('');
629
- return { success: true };
630
- }
631
- console.log('\n📏 Validating No Inline Types\n');
632
- console.log(` Mode: ${mode}`);
633
- let base = process.env['NX_BASE'];
634
- const head = process.env['NX_HEAD'];
635
- if (!base) {
636
- base = detectBase(workspaceRoot) ?? undefined;
637
- if (!base) {
638
- console.log('\n⏭️ Skipping no-inline-types validation (could not detect base branch)');
639
- console.log('');
640
- return { success: true };
641
- }
642
- }
643
- console.log(` Base: ${base}`);
644
- console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);
645
- console.log('');
646
- const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);
647
- if (changedFiles.length === 0) {
648
- console.log('✅ No TypeScript files changed');
649
- return { success: true };
650
- }
651
- console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);
652
- let violations = [];
653
- if (mode === 'NEW_METHODS') {
654
- violations = findViolationsForNewMethods(workspaceRoot, changedFiles, base, head, disableAllowed);
655
- }
656
- else if (mode === 'NEW_AND_MODIFIED_METHODS') {
657
- violations = findViolationsForModifiedAndNewMethods(workspaceRoot, changedFiles, base, head, disableAllowed);
658
- }
659
- else if (mode === 'MODIFIED_FILES') {
660
- violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed);
661
- }
662
- if (violations.length === 0) {
663
- console.log('✅ No inline type literals found');
664
- return { success: true };
665
- }
666
- reportViolations(violations, mode);
667
- return { success: false };
668
- }
669
- //# sourceMappingURL=executor.js.map