@webpieces/dev-config 0.2.84 → 0.2.86
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.
- package/architecture/executors/diff-utils.d.ts +24 -0
- package/architecture/executors/diff-utils.js +119 -0
- package/architecture/executors/diff-utils.js.map +1 -0
- package/architecture/executors/diff-utils.ts +127 -0
- package/architecture/executors/validate-code/executor.d.ts +7 -0
- package/architecture/executors/validate-code/executor.js +57 -2
- package/architecture/executors/validate-code/executor.js.map +1 -1
- package/architecture/executors/validate-code/executor.ts +72 -2
- package/architecture/executors/validate-code/schema.json +21 -8
- package/architecture/executors/validate-no-destructure/executor.d.ts +52 -0
- package/architecture/executors/validate-no-destructure/executor.js +493 -0
- package/architecture/executors/validate-no-destructure/executor.js.map +1 -0
- package/architecture/executors/validate-no-destructure/executor.ts +580 -0
- package/architecture/executors/validate-no-destructure/schema.json +24 -0
- package/architecture/executors/validate-no-inline-types/executor.d.ts +2 -2
- package/architecture/executors/validate-no-inline-types/executor.js +3 -3
- package/architecture/executors/validate-no-inline-types/executor.js.map +1 -1
- package/architecture/executors/validate-no-inline-types/executor.ts +4 -4
- package/architecture/executors/validate-no-inline-types/schema.json +2 -2
- package/architecture/executors/validate-prisma-converters/executor.d.ts +4 -3
- package/architecture/executors/validate-prisma-converters/executor.js +122 -3
- package/architecture/executors/validate-prisma-converters/executor.js.map +1 -1
- package/architecture/executors/validate-prisma-converters/executor.ts +170 -4
- package/architecture/executors/validate-prisma-converters/schema.json +2 -2
- package/architecture/executors/validate-return-types/executor.d.ts +2 -2
- package/architecture/executors/validate-return-types/executor.js +3 -3
- package/architecture/executors/validate-return-types/executor.js.map +1 -1
- package/architecture/executors/validate-return-types/executor.ts +4 -4
- package/architecture/executors/validate-return-types/schema.json +2 -2
- package/executors.json +5 -0
- package/package.json +1 -1
|
@@ -7,6 +7,7 @@ import runNoInlineTypesExecutor, { NoInlineTypesMode } from '../validate-no-inli
|
|
|
7
7
|
import runNoAnyUnknownExecutor, { NoAnyUnknownMode } from '../validate-no-any-unknown/executor';
|
|
8
8
|
import runValidateDtosExecutor, { ValidateDtosMode } from '../validate-dtos/executor';
|
|
9
9
|
import runPrismaConvertersExecutor, { PrismaConverterMode } from '../validate-prisma-converters/executor';
|
|
10
|
+
import runNoDestructureExecutor, { NoDestructureMode } from '../validate-no-destructure/executor';
|
|
10
11
|
|
|
11
12
|
export type MethodMaxLimitMode = 'OFF' | 'NEW_METHODS' | 'NEW_AND_MODIFIED_METHODS' | 'MODIFIED_FILES';
|
|
12
13
|
export type FileMaxLimitMode = 'OFF' | 'MODIFIED_FILES';
|
|
@@ -59,6 +60,12 @@ export interface PrismaConverterConfig {
|
|
|
59
60
|
ignoreModifiedUntilEpoch?: number;
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
export interface NoDestructureConfig {
|
|
64
|
+
mode?: NoDestructureMode;
|
|
65
|
+
disableAllowed?: boolean;
|
|
66
|
+
ignoreModifiedUntilEpoch?: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
62
69
|
export interface ValidateCodeOptions {
|
|
63
70
|
methodMaxLimit?: MethodMaxLimitConfig;
|
|
64
71
|
fileMaxLimit?: FileMaxLimitConfig;
|
|
@@ -67,6 +74,7 @@ export interface ValidateCodeOptions {
|
|
|
67
74
|
noAnyUnknown?: NoAnyUnknownConfig;
|
|
68
75
|
validateDtos?: ValidateDtosConfig;
|
|
69
76
|
prismaConverter?: PrismaConverterConfig;
|
|
77
|
+
noDestructure?: NoDestructureConfig;
|
|
70
78
|
}
|
|
71
79
|
|
|
72
80
|
export interface ExecutorResult {
|
|
@@ -107,6 +115,9 @@ interface ParsedConfig {
|
|
|
107
115
|
prismaConverterSchemaPath: string | undefined;
|
|
108
116
|
prismaConverterConvertersPaths: string[];
|
|
109
117
|
prismaConverterIgnoreEpoch: number | undefined;
|
|
118
|
+
noDestructureMode: NoDestructureMode;
|
|
119
|
+
noDestructureDisableAllowed: boolean;
|
|
120
|
+
noDestructureIgnoreEpoch: number | undefined;
|
|
110
121
|
}
|
|
111
122
|
|
|
112
123
|
interface ResolvedMethodMode {
|
|
@@ -119,6 +130,45 @@ interface ResolvedFileMode {
|
|
|
119
130
|
override: OverrideInfo | undefined;
|
|
120
131
|
}
|
|
121
132
|
|
|
133
|
+
const VALID_MODES: Record<string, string[]> = {
|
|
134
|
+
methodMaxLimit: ['OFF', 'NEW_METHODS', 'NEW_AND_MODIFIED_METHODS', 'MODIFIED_FILES'],
|
|
135
|
+
fileMaxLimit: ['OFF', 'MODIFIED_FILES'],
|
|
136
|
+
requireReturnType: ['OFF', 'NEW_METHODS', 'NEW_AND_MODIFIED_METHODS', 'MODIFIED_FILES'],
|
|
137
|
+
noInlineTypeLiterals: ['OFF', 'NEW_METHODS', 'NEW_AND_MODIFIED_METHODS', 'MODIFIED_FILES'],
|
|
138
|
+
noAnyUnknown: ['OFF', 'MODIFIED_CODE', 'MODIFIED_FILES'],
|
|
139
|
+
validateDtos: ['OFF', 'MODIFIED_CLASS', 'MODIFIED_FILES'],
|
|
140
|
+
prismaConverter: ['OFF', 'MODIFIED_METHOD_AND_CODE', 'MODIFIED_FILES'],
|
|
141
|
+
noDestructure: ['OFF', 'MODIFIED_CODE', 'MODIFIED_FILES'],
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Validate that all configured modes are valid. Produces clear error messages naming the rule.
|
|
146
|
+
*/
|
|
147
|
+
function validateModes(options: ValidateCodeOptions): string[] {
|
|
148
|
+
const errors: string[] = [];
|
|
149
|
+
|
|
150
|
+
const modeEntries: [string, string | undefined][] = [
|
|
151
|
+
['methodMaxLimit', options.methodMaxLimit?.mode],
|
|
152
|
+
['fileMaxLimit', options.fileMaxLimit?.mode],
|
|
153
|
+
['requireReturnType', options.requireReturnType?.mode],
|
|
154
|
+
['noInlineTypeLiterals', options.noInlineTypeLiterals?.mode],
|
|
155
|
+
['noAnyUnknown', options.noAnyUnknown?.mode],
|
|
156
|
+
['validateDtos', options.validateDtos?.mode],
|
|
157
|
+
['prismaConverter', options.prismaConverter?.mode],
|
|
158
|
+
['noDestructure', options.noDestructure?.mode],
|
|
159
|
+
];
|
|
160
|
+
|
|
161
|
+
for (const [ruleName, modeValue] of modeEntries) {
|
|
162
|
+
if (modeValue === undefined) continue;
|
|
163
|
+
const validModes = VALID_MODES[ruleName];
|
|
164
|
+
if (!validModes.includes(modeValue)) {
|
|
165
|
+
errors.push(`${ruleName}.mode = '${modeValue}' is invalid. Valid modes: ${validModes.join(', ')}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return errors;
|
|
170
|
+
}
|
|
171
|
+
|
|
122
172
|
function formatEpochDate(epoch: number): string {
|
|
123
173
|
return new Date(epoch * 1000).toISOString().split('T')[0];
|
|
124
174
|
}
|
|
@@ -201,6 +251,9 @@ function parseConfig(options: ValidateCodeOptions): ParsedConfig {
|
|
|
201
251
|
prismaConverterSchemaPath: options.prismaConverter?.schemaPath,
|
|
202
252
|
prismaConverterConvertersPaths: options.prismaConverter?.convertersPaths ?? [],
|
|
203
253
|
prismaConverterIgnoreEpoch: options.prismaConverter?.ignoreModifiedUntilEpoch,
|
|
254
|
+
noDestructureMode: options.noDestructure?.mode ?? 'OFF',
|
|
255
|
+
noDestructureDisableAllowed: options.noDestructure?.disableAllowed ?? true,
|
|
256
|
+
noDestructureIgnoreEpoch: options.noDestructure?.ignoreModifiedUntilEpoch,
|
|
204
257
|
};
|
|
205
258
|
}
|
|
206
259
|
|
|
@@ -220,6 +273,7 @@ function logConfig(config: ParsedConfig): void {
|
|
|
220
273
|
console.log(` No any/unknown: mode=${config.noAnyUnknownMode}, disableAllowed=${config.noAnyUnknownDisableAllowed}`);
|
|
221
274
|
console.log(` Validate DTOs: mode=${config.validateDtosMode}, disableAllowed=${config.validateDtosDisableAllowed}`);
|
|
222
275
|
console.log(` Prisma converters: mode=${config.prismaConverterMode}, disableAllowed=${config.prismaConverterDisableAllowed}`);
|
|
276
|
+
console.log(` No destructure: mode=${config.noDestructureMode}, disableAllowed=${config.noDestructureDisableAllowed}`);
|
|
223
277
|
console.log('');
|
|
224
278
|
}
|
|
225
279
|
|
|
@@ -227,7 +281,7 @@ function isAllOff(config: ParsedConfig): boolean {
|
|
|
227
281
|
return config.methodMode === 'OFF' && config.fileMode === 'OFF' &&
|
|
228
282
|
config.returnTypeMode === 'OFF' && config.noInlineTypesMode === 'OFF' &&
|
|
229
283
|
config.noAnyUnknownMode === 'OFF' && config.validateDtosMode === 'OFF' &&
|
|
230
|
-
config.prismaConverterMode === 'OFF';
|
|
284
|
+
config.prismaConverterMode === 'OFF' && config.noDestructureMode === 'OFF';
|
|
231
285
|
}
|
|
232
286
|
|
|
233
287
|
async function runMethodValidators(config: ParsedConfig, context: ExecutorContext): Promise<ExecutorResult[]> {
|
|
@@ -253,6 +307,16 @@ export default async function runExecutor(
|
|
|
253
307
|
options: ValidateCodeOptions,
|
|
254
308
|
context: ExecutorContext
|
|
255
309
|
): Promise<ExecutorResult> {
|
|
310
|
+
const modeErrors = validateModes(options);
|
|
311
|
+
if (modeErrors.length > 0) {
|
|
312
|
+
console.error('');
|
|
313
|
+
for (const err of modeErrors) {
|
|
314
|
+
console.error(`❌ ${err}`);
|
|
315
|
+
}
|
|
316
|
+
console.error('');
|
|
317
|
+
return { success: false };
|
|
318
|
+
}
|
|
319
|
+
|
|
256
320
|
const config = parseConfig(options);
|
|
257
321
|
|
|
258
322
|
if (isAllOff(config)) {
|
|
@@ -295,11 +359,17 @@ export default async function runExecutor(
|
|
|
295
359
|
convertersPaths: config.prismaConverterConvertersPaths,
|
|
296
360
|
ignoreModifiedUntilEpoch: config.prismaConverterIgnoreEpoch,
|
|
297
361
|
}, context);
|
|
362
|
+
const noDestructureResult = await runNoDestructureExecutor({
|
|
363
|
+
mode: config.noDestructureMode,
|
|
364
|
+
disableAllowed: config.noDestructureDisableAllowed,
|
|
365
|
+
ignoreModifiedUntilEpoch: config.noDestructureIgnoreEpoch,
|
|
366
|
+
}, context);
|
|
298
367
|
|
|
299
368
|
const allSuccess = methodResults.every((r) => r.success) &&
|
|
300
369
|
fileResult.success && returnTypesResult.success &&
|
|
301
370
|
noInlineTypesResult.success && noAnyUnknownResult.success &&
|
|
302
|
-
validateDtosResult.success && prismaConverterResult.success
|
|
371
|
+
validateDtosResult.success && prismaConverterResult.success &&
|
|
372
|
+
noDestructureResult.success;
|
|
303
373
|
|
|
304
374
|
console.log(allSuccess ? '\n\u2705 All code validations passed\n' : '\n\u274c Some code validations failed\n');
|
|
305
375
|
return { success: allSuccess };
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
},
|
|
16
16
|
"mode": {
|
|
17
17
|
"type": "string",
|
|
18
|
-
"enum": ["OFF", "NEW_METHODS", "NEW_AND_MODIFIED_METHODS", "MODIFIED_FILES"],
|
|
19
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.",
|
|
20
19
|
"default": "NEW_AND_MODIFIED_METHODS"
|
|
21
20
|
},
|
|
@@ -41,7 +40,6 @@
|
|
|
41
40
|
},
|
|
42
41
|
"mode": {
|
|
43
42
|
"type": "string",
|
|
44
|
-
"enum": ["OFF", "MODIFIED_FILES"],
|
|
45
43
|
"description": "OFF: skip validation. MODIFIED_FILES: all code in modified files.",
|
|
46
44
|
"default": "MODIFIED_FILES"
|
|
47
45
|
},
|
|
@@ -62,7 +60,6 @@
|
|
|
62
60
|
"properties": {
|
|
63
61
|
"mode": {
|
|
64
62
|
"type": "string",
|
|
65
|
-
"enum": ["OFF", "NEW_METHODS", "NEW_AND_MODIFIED_METHODS", "MODIFIED_FILES"],
|
|
66
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.",
|
|
67
64
|
"default": "OFF"
|
|
68
65
|
},
|
|
@@ -83,7 +80,6 @@
|
|
|
83
80
|
"properties": {
|
|
84
81
|
"mode": {
|
|
85
82
|
"type": "string",
|
|
86
|
-
"enum": ["OFF", "NEW_METHODS", "NEW_AND_MODIFIED_METHODS", "MODIFIED_FILES"],
|
|
87
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.",
|
|
88
84
|
"default": "OFF"
|
|
89
85
|
},
|
|
@@ -104,7 +100,6 @@
|
|
|
104
100
|
"properties": {
|
|
105
101
|
"mode": {
|
|
106
102
|
"type": "string",
|
|
107
|
-
"enum": ["OFF", "MODIFIED_CODE", "MODIFIED_FILES"],
|
|
108
103
|
"description": "OFF: skip validation. MODIFIED_CODE: only changed lines in diff. MODIFIED_FILES: all in modified files. Disallows `any` and `unknown` TypeScript keywords.",
|
|
109
104
|
"default": "OFF"
|
|
110
105
|
},
|
|
@@ -125,7 +120,6 @@
|
|
|
125
120
|
"properties": {
|
|
126
121
|
"mode": {
|
|
127
122
|
"type": "string",
|
|
128
|
-
"enum": ["OFF", "MODIFIED_CLASS", "MODIFIED_FILES"],
|
|
129
123
|
"description": "OFF: skip validation. MODIFIED_CLASS: only validate Dto classes with changed lines. MODIFIED_FILES: validate all Dtos in modified files.",
|
|
130
124
|
"default": "OFF"
|
|
131
125
|
},
|
|
@@ -155,8 +149,7 @@
|
|
|
155
149
|
"properties": {
|
|
156
150
|
"mode": {
|
|
157
151
|
"type": "string",
|
|
158
|
-
"
|
|
159
|
-
"description": "OFF: skip validation. MODIFIED_FILES: validate converter and non-converter files modified in the diff.",
|
|
152
|
+
"description": "OFF: skip validation. MODIFIED_METHOD_AND_CODE: validate new/modified methods in converters + changed lines in non-converters. MODIFIED_FILES: validate all methods in modified files.",
|
|
160
153
|
"default": "OFF"
|
|
161
154
|
},
|
|
162
155
|
"disableAllowed": {
|
|
@@ -178,6 +171,26 @@
|
|
|
178
171
|
"description": "Epoch seconds. Until this time, skip prisma-converter validation entirely. When expired, normal mode resumes. Omit when not needed."
|
|
179
172
|
}
|
|
180
173
|
}
|
|
174
|
+
},
|
|
175
|
+
"noDestructure": {
|
|
176
|
+
"type": "object",
|
|
177
|
+
"description": "Validate no destructuring patterns are used. Destructuring hurts code traceability.",
|
|
178
|
+
"properties": {
|
|
179
|
+
"mode": {
|
|
180
|
+
"type": "string",
|
|
181
|
+
"description": "OFF: skip validation. MODIFIED_CODE: only changed lines in diff. MODIFIED_FILES: all in modified files. Disallows destructuring patterns.",
|
|
182
|
+
"default": "OFF"
|
|
183
|
+
},
|
|
184
|
+
"disableAllowed": {
|
|
185
|
+
"type": "boolean",
|
|
186
|
+
"description": "Whether disable comments work. When false, no escape hatch.",
|
|
187
|
+
"default": true
|
|
188
|
+
},
|
|
189
|
+
"ignoreModifiedUntilEpoch": {
|
|
190
|
+
"type": "number",
|
|
191
|
+
"description": "Epoch seconds. Until this time, skip validation entirely. When expired, normal mode resumes. Omit when not needed."
|
|
192
|
+
}
|
|
193
|
+
}
|
|
181
194
|
}
|
|
182
195
|
},
|
|
183
196
|
"required": []
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate No Destructure Executor
|
|
3
|
+
*
|
|
4
|
+
* Validates that destructuring patterns are not used in TypeScript code.
|
|
5
|
+
* Uses LINE-BASED detection (not method-based) for git diff filtering.
|
|
6
|
+
*
|
|
7
|
+
* ============================================================================
|
|
8
|
+
* VIOLATIONS (BAD) - These patterns are flagged:
|
|
9
|
+
* ============================================================================
|
|
10
|
+
*
|
|
11
|
+
* - const { x, y } = obj — object destructuring in variable declarations
|
|
12
|
+
* - const [a, b] = fn() — array destructuring (except Promise.all)
|
|
13
|
+
* - for (const { email } of items) — object destructuring in for-of loops
|
|
14
|
+
* - for (const [a, b] of items) — array destructuring in for-of (except Object.entries)
|
|
15
|
+
* - const { page = 0 } = opts — destructuring with defaults
|
|
16
|
+
* - const { done: streamDone } = obj — destructuring with renaming
|
|
17
|
+
* - function foo({ x, y }: Type) — function parameter destructuring
|
|
18
|
+
*
|
|
19
|
+
* ============================================================================
|
|
20
|
+
* ALLOWED (skip — NOT violations)
|
|
21
|
+
* ============================================================================
|
|
22
|
+
*
|
|
23
|
+
* - const [a, b] = await Promise.all([...]) — Promise.all array destructuring
|
|
24
|
+
* - for (const [key, value] of Object.entries(obj)) — Object.entries in for-of
|
|
25
|
+
* - const { extracted, ...rest } = obj — rest operator separation
|
|
26
|
+
* - Lines with // webpieces-disable no-destructure -- [reason] (only when disableAllowed: true)
|
|
27
|
+
*
|
|
28
|
+
* ============================================================================
|
|
29
|
+
* MODES (LINE-BASED)
|
|
30
|
+
* ============================================================================
|
|
31
|
+
* - OFF: Skip validation entirely
|
|
32
|
+
* - MODIFIED_CODE: Flag destructuring on changed lines (lines in diff hunks)
|
|
33
|
+
* - MODIFIED_FILES: Flag ALL destructuring in files that were modified
|
|
34
|
+
*
|
|
35
|
+
* ============================================================================
|
|
36
|
+
* ESCAPE HATCH
|
|
37
|
+
* ============================================================================
|
|
38
|
+
* Add comment above the violation:
|
|
39
|
+
* // webpieces-disable no-destructure -- [your justification]
|
|
40
|
+
* const { x, y } = obj;
|
|
41
|
+
*/
|
|
42
|
+
import type { ExecutorContext } from '@nx/devkit';
|
|
43
|
+
export type NoDestructureMode = 'OFF' | 'MODIFIED_CODE' | 'MODIFIED_FILES';
|
|
44
|
+
export interface ValidateNoDestructureOptions {
|
|
45
|
+
mode?: NoDestructureMode;
|
|
46
|
+
disableAllowed?: boolean;
|
|
47
|
+
ignoreModifiedUntilEpoch?: number;
|
|
48
|
+
}
|
|
49
|
+
export interface ExecutorResult {
|
|
50
|
+
success: boolean;
|
|
51
|
+
}
|
|
52
|
+
export default function runExecutor(options: ValidateNoDestructureOptions, context: ExecutorContext): Promise<ExecutorResult>;
|