@webpieces/dev-config 0.2.69 ā 0.2.71
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/validate-code/executor.d.ts +2 -0
- package/architecture/executors/validate-code/executor.js +8 -1
- package/architecture/executors/validate-code/executor.js.map +1 -1
- package/architecture/executors/validate-code/executor.ts +12 -1
- package/architecture/executors/validate-code/schema.json +6 -0
- package/architecture/executors/validate-modified-methods/executor.js +2 -2
- package/architecture/executors/validate-modified-methods/executor.js.map +1 -1
- package/architecture/executors/validate-modified-methods/executor.ts +2 -2
- package/architecture/executors/validate-new-methods/executor.js +2 -2
- package/architecture/executors/validate-new-methods/executor.js.map +1 -1
- package/architecture/executors/validate-new-methods/executor.ts +2 -2
- package/architecture/executors/validate-return-types/executor.d.ts +27 -0
- package/architecture/executors/validate-return-types/executor.js +376 -0
- package/architecture/executors/validate-return-types/executor.js.map +1 -0
- package/architecture/executors/validate-return-types/executor.ts +446 -0
- package/architecture/executors/validate-return-types/schema.json +15 -0
- package/executors.json +5 -0
- package/package.json +1 -1
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate Return Types Executor
|
|
3
|
+
*
|
|
4
|
+
* Validates that methods have explicit return type annotations for better code readability.
|
|
5
|
+
* Instead of relying on TypeScript's type inference, explicit return types make code clearer:
|
|
6
|
+
*
|
|
7
|
+
* BAD: method() { return new MyClass(); }
|
|
8
|
+
* GOOD: method(): MyClass { return new MyClass(); }
|
|
9
|
+
* GOOD: async method(): Promise<MyType> { ... }
|
|
10
|
+
*
|
|
11
|
+
* Modes:
|
|
12
|
+
* - OFF: Skip validation entirely
|
|
13
|
+
* - MODIFIED_NEW: Only validate new methods (detected via git diff)
|
|
14
|
+
* - MODIFIED: Validate all methods in modified files
|
|
15
|
+
* - ALL: Validate all methods in all TypeScript files
|
|
16
|
+
*
|
|
17
|
+
* Escape hatch: Add webpieces-disable require-return-type comment with justification
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { ExecutorContext } from '@nx/devkit';
|
|
21
|
+
import { execSync } from 'child_process';
|
|
22
|
+
import * as fs from 'fs';
|
|
23
|
+
import * as path from 'path';
|
|
24
|
+
import * as ts from 'typescript';
|
|
25
|
+
|
|
26
|
+
export type ReturnTypeMode = 'OFF' | 'MODIFIED_NEW' | 'MODIFIED' | 'ALL';
|
|
27
|
+
|
|
28
|
+
export interface ValidateReturnTypesOptions {
|
|
29
|
+
mode?: ReturnTypeMode;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface ExecutorResult {
|
|
33
|
+
success: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface MethodViolation {
|
|
37
|
+
file: string;
|
|
38
|
+
methodName: string;
|
|
39
|
+
line: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get changed TypeScript files between base and head (or working tree if head not specified).
|
|
44
|
+
*/
|
|
45
|
+
// webpieces-disable max-lines-new-methods -- Git command handling with untracked files requires multiple code paths
|
|
46
|
+
function getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: string): string[] {
|
|
47
|
+
try {
|
|
48
|
+
const diffTarget = head ? `${base} ${head}` : base;
|
|
49
|
+
const output = execSync(`git diff --name-only ${diffTarget} -- '*.ts' '*.tsx'`, {
|
|
50
|
+
cwd: workspaceRoot,
|
|
51
|
+
encoding: 'utf-8',
|
|
52
|
+
});
|
|
53
|
+
const changedFiles = output
|
|
54
|
+
.trim()
|
|
55
|
+
.split('\n')
|
|
56
|
+
.filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));
|
|
57
|
+
|
|
58
|
+
if (!head) {
|
|
59
|
+
try {
|
|
60
|
+
const untrackedOutput = execSync(`git ls-files --others --exclude-standard '*.ts' '*.tsx'`, {
|
|
61
|
+
cwd: workspaceRoot,
|
|
62
|
+
encoding: 'utf-8',
|
|
63
|
+
});
|
|
64
|
+
const untrackedFiles = untrackedOutput
|
|
65
|
+
.trim()
|
|
66
|
+
.split('\n')
|
|
67
|
+
.filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));
|
|
68
|
+
const allFiles = new Set([...changedFiles, ...untrackedFiles]);
|
|
69
|
+
return Array.from(allFiles);
|
|
70
|
+
} catch {
|
|
71
|
+
return changedFiles;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return changedFiles;
|
|
76
|
+
} catch {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get all TypeScript files in the workspace (excluding node_modules, dist, tests).
|
|
83
|
+
*/
|
|
84
|
+
function getAllTypeScriptFiles(workspaceRoot: string): string[] {
|
|
85
|
+
try {
|
|
86
|
+
const output = execSync(
|
|
87
|
+
`find packages apps -type f \\( -name "*.ts" -o -name "*.tsx" \\) | grep -v node_modules | grep -v dist | grep -v ".spec.ts" | grep -v ".test.ts"`,
|
|
88
|
+
{
|
|
89
|
+
cwd: workspaceRoot,
|
|
90
|
+
encoding: 'utf-8',
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
return output
|
|
94
|
+
.trim()
|
|
95
|
+
.split('\n')
|
|
96
|
+
.filter((f) => f);
|
|
97
|
+
} catch {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get the diff content for a specific file.
|
|
104
|
+
*/
|
|
105
|
+
function getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string {
|
|
106
|
+
try {
|
|
107
|
+
const diffTarget = head ? `${base} ${head}` : base;
|
|
108
|
+
const diff = execSync(`git diff ${diffTarget} -- "${file}"`, {
|
|
109
|
+
cwd: workspaceRoot,
|
|
110
|
+
encoding: 'utf-8',
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
if (!diff && !head) {
|
|
114
|
+
const fullPath = path.join(workspaceRoot, file);
|
|
115
|
+
if (fs.existsSync(fullPath)) {
|
|
116
|
+
const isUntracked = execSync(`git ls-files --others --exclude-standard "${file}"`, {
|
|
117
|
+
cwd: workspaceRoot,
|
|
118
|
+
encoding: 'utf-8',
|
|
119
|
+
}).trim();
|
|
120
|
+
|
|
121
|
+
if (isUntracked) {
|
|
122
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
123
|
+
const lines = content.split('\n');
|
|
124
|
+
return lines.map((line) => `+${line}`).join('\n');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return diff;
|
|
130
|
+
} catch {
|
|
131
|
+
return '';
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Parse diff to find newly added method signatures.
|
|
137
|
+
*/
|
|
138
|
+
function findNewMethodSignaturesInDiff(diffContent: string): Set<string> {
|
|
139
|
+
const newMethods = new Set<string>();
|
|
140
|
+
const lines = diffContent.split('\n');
|
|
141
|
+
|
|
142
|
+
const patterns = [
|
|
143
|
+
/^\+\s*(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(/,
|
|
144
|
+
/^\+\s*(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*(?:async\s*)?\(/,
|
|
145
|
+
/^\+\s*(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*(?:async\s+)?function/,
|
|
146
|
+
/^\+\s*(?:(?:public|private|protected)\s+)?(?:static\s+)?(?:async\s+)?(\w+)\s*\(/,
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
for (const line of lines) {
|
|
150
|
+
if (line.startsWith('+') && !line.startsWith('+++')) {
|
|
151
|
+
for (const pattern of patterns) {
|
|
152
|
+
const match = line.match(pattern);
|
|
153
|
+
if (match) {
|
|
154
|
+
const methodName = match[1];
|
|
155
|
+
if (methodName && !['if', 'for', 'while', 'switch', 'catch', 'constructor'].includes(methodName)) {
|
|
156
|
+
newMethods.add(methodName);
|
|
157
|
+
}
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return newMethods;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Check if a line contains a webpieces-disable comment for return type.
|
|
169
|
+
*/
|
|
170
|
+
function hasDisableComment(lines: string[], lineNumber: number): boolean {
|
|
171
|
+
const startCheck = Math.max(0, lineNumber - 5);
|
|
172
|
+
for (let i = lineNumber - 2; i >= startCheck; i--) {
|
|
173
|
+
const line = lines[i]?.trim() ?? '';
|
|
174
|
+
if (line.startsWith('function ') || line.startsWith('class ') || line.endsWith('}')) {
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
if (line.includes('webpieces-disable') && line.includes('require-return-type')) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Check if a method has an explicit return type annotation.
|
|
186
|
+
*/
|
|
187
|
+
function hasExplicitReturnType(node: ts.MethodDeclaration | ts.FunctionDeclaration | ts.ArrowFunction): boolean {
|
|
188
|
+
return node.type !== undefined;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
interface MethodInfo {
|
|
192
|
+
name: string;
|
|
193
|
+
line: number;
|
|
194
|
+
hasReturnType: boolean;
|
|
195
|
+
hasDisableComment: boolean;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Parse a TypeScript file and find methods with their return type status.
|
|
200
|
+
*/
|
|
201
|
+
// webpieces-disable max-lines-new-methods -- AST traversal requires inline visitor function
|
|
202
|
+
function findMethodsInFile(filePath: string, workspaceRoot: string): MethodInfo[] {
|
|
203
|
+
const fullPath = path.join(workspaceRoot, filePath);
|
|
204
|
+
if (!fs.existsSync(fullPath)) return [];
|
|
205
|
+
|
|
206
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
207
|
+
const fileLines = content.split('\n');
|
|
208
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
|
|
209
|
+
|
|
210
|
+
const methods: MethodInfo[] = [];
|
|
211
|
+
|
|
212
|
+
// webpieces-disable max-lines-new-methods -- AST visitor pattern requires handling multiple node types
|
|
213
|
+
function visit(node: ts.Node): void {
|
|
214
|
+
let methodName: string | undefined;
|
|
215
|
+
let startLine: number | undefined;
|
|
216
|
+
let hasReturnType = false;
|
|
217
|
+
|
|
218
|
+
if (ts.isMethodDeclaration(node) && node.name) {
|
|
219
|
+
methodName = node.name.getText(sourceFile);
|
|
220
|
+
const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
221
|
+
startLine = start.line + 1;
|
|
222
|
+
hasReturnType = hasExplicitReturnType(node);
|
|
223
|
+
} else if (ts.isFunctionDeclaration(node) && node.name) {
|
|
224
|
+
methodName = node.name.getText(sourceFile);
|
|
225
|
+
const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
226
|
+
startLine = start.line + 1;
|
|
227
|
+
hasReturnType = hasExplicitReturnType(node);
|
|
228
|
+
} else if (ts.isArrowFunction(node)) {
|
|
229
|
+
if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
|
|
230
|
+
methodName = node.parent.name.getText(sourceFile);
|
|
231
|
+
const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
232
|
+
startLine = start.line + 1;
|
|
233
|
+
hasReturnType = hasExplicitReturnType(node);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (methodName && startLine !== undefined) {
|
|
238
|
+
methods.push({
|
|
239
|
+
name: methodName,
|
|
240
|
+
line: startLine,
|
|
241
|
+
hasReturnType,
|
|
242
|
+
hasDisableComment: hasDisableComment(fileLines, startLine),
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
ts.forEachChild(node, visit);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
visit(sourceFile);
|
|
250
|
+
return methods;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Find methods without explicit return types based on mode.
|
|
255
|
+
*/
|
|
256
|
+
// webpieces-disable max-lines-new-methods -- File iteration with diff parsing and method matching
|
|
257
|
+
function findViolationsForModifiedNew(
|
|
258
|
+
workspaceRoot: string,
|
|
259
|
+
changedFiles: string[],
|
|
260
|
+
base: string,
|
|
261
|
+
head?: string
|
|
262
|
+
): MethodViolation[] {
|
|
263
|
+
const violations: MethodViolation[] = [];
|
|
264
|
+
|
|
265
|
+
for (const file of changedFiles) {
|
|
266
|
+
const diff = getFileDiff(workspaceRoot, file, base, head);
|
|
267
|
+
const newMethodNames = findNewMethodSignaturesInDiff(diff);
|
|
268
|
+
|
|
269
|
+
if (newMethodNames.size === 0) continue;
|
|
270
|
+
|
|
271
|
+
const methods = findMethodsInFile(file, workspaceRoot);
|
|
272
|
+
|
|
273
|
+
for (const method of methods) {
|
|
274
|
+
if (!newMethodNames.has(method.name)) continue;
|
|
275
|
+
if (method.hasReturnType) continue;
|
|
276
|
+
if (method.hasDisableComment) continue;
|
|
277
|
+
|
|
278
|
+
violations.push({
|
|
279
|
+
file,
|
|
280
|
+
methodName: method.name,
|
|
281
|
+
line: method.line,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return violations;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Find all methods without explicit return types in modified files.
|
|
291
|
+
*/
|
|
292
|
+
function findViolationsForModified(workspaceRoot: string, changedFiles: string[]): MethodViolation[] {
|
|
293
|
+
const violations: MethodViolation[] = [];
|
|
294
|
+
|
|
295
|
+
for (const file of changedFiles) {
|
|
296
|
+
const methods = findMethodsInFile(file, workspaceRoot);
|
|
297
|
+
|
|
298
|
+
for (const method of methods) {
|
|
299
|
+
if (method.hasReturnType) continue;
|
|
300
|
+
if (method.hasDisableComment) continue;
|
|
301
|
+
|
|
302
|
+
violations.push({
|
|
303
|
+
file,
|
|
304
|
+
methodName: method.name,
|
|
305
|
+
line: method.line,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return violations;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Find all methods without explicit return types in all files.
|
|
315
|
+
*/
|
|
316
|
+
function findViolationsForAll(workspaceRoot: string): MethodViolation[] {
|
|
317
|
+
const allFiles = getAllTypeScriptFiles(workspaceRoot);
|
|
318
|
+
return findViolationsForModified(workspaceRoot, allFiles);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Auto-detect the base branch by finding the merge-base with origin/main.
|
|
323
|
+
*/
|
|
324
|
+
function detectBase(workspaceRoot: string): string | null {
|
|
325
|
+
try {
|
|
326
|
+
const mergeBase = execSync('git merge-base HEAD origin/main', {
|
|
327
|
+
cwd: workspaceRoot,
|
|
328
|
+
encoding: 'utf-8',
|
|
329
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
330
|
+
}).trim();
|
|
331
|
+
|
|
332
|
+
if (mergeBase) {
|
|
333
|
+
return mergeBase;
|
|
334
|
+
}
|
|
335
|
+
} catch {
|
|
336
|
+
try {
|
|
337
|
+
const mergeBase = execSync('git merge-base HEAD main', {
|
|
338
|
+
cwd: workspaceRoot,
|
|
339
|
+
encoding: 'utf-8',
|
|
340
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
341
|
+
}).trim();
|
|
342
|
+
|
|
343
|
+
if (mergeBase) {
|
|
344
|
+
return mergeBase;
|
|
345
|
+
}
|
|
346
|
+
} catch {
|
|
347
|
+
// Ignore
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Report violations to console.
|
|
355
|
+
*/
|
|
356
|
+
function reportViolations(violations: MethodViolation[], mode: ReturnTypeMode): void {
|
|
357
|
+
console.error('');
|
|
358
|
+
console.error('ā Methods missing explicit return types!');
|
|
359
|
+
console.error('');
|
|
360
|
+
console.error('š Explicit return types improve code readability:');
|
|
361
|
+
console.error('');
|
|
362
|
+
console.error(' BAD: method() { return new MyClass(); }');
|
|
363
|
+
console.error(' GOOD: method(): MyClass { return new MyClass(); }');
|
|
364
|
+
console.error(' GOOD: async method(): Promise<MyType> { ... }');
|
|
365
|
+
console.error('');
|
|
366
|
+
|
|
367
|
+
for (const v of violations) {
|
|
368
|
+
console.error(` ā ${v.file}:${v.line}`);
|
|
369
|
+
console.error(` Method: ${v.methodName} - missing return type annotation`);
|
|
370
|
+
}
|
|
371
|
+
console.error('');
|
|
372
|
+
|
|
373
|
+
console.error(' To fix: Add explicit return type after the parameter list');
|
|
374
|
+
console.error('');
|
|
375
|
+
console.error(' Escape hatch (use sparingly):');
|
|
376
|
+
console.error(' // webpieces-disable require-return-type -- [your reason]');
|
|
377
|
+
console.error('');
|
|
378
|
+
console.error(` Current mode: ${mode}`);
|
|
379
|
+
console.error('');
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
export default async function runExecutor(
|
|
383
|
+
options: ValidateReturnTypesOptions,
|
|
384
|
+
context: ExecutorContext
|
|
385
|
+
): Promise<ExecutorResult> {
|
|
386
|
+
const workspaceRoot = context.root;
|
|
387
|
+
const mode: ReturnTypeMode = options.mode ?? 'MODIFIED_NEW';
|
|
388
|
+
|
|
389
|
+
if (mode === 'OFF') {
|
|
390
|
+
console.log('\nāļø Skipping return type validation (mode: OFF)');
|
|
391
|
+
console.log('');
|
|
392
|
+
return { success: true };
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
console.log('\nš Validating Return Types\n');
|
|
396
|
+
console.log(` Mode: ${mode}`);
|
|
397
|
+
|
|
398
|
+
let violations: MethodViolation[] = [];
|
|
399
|
+
|
|
400
|
+
if (mode === 'ALL') {
|
|
401
|
+
console.log(' Scope: All TypeScript files');
|
|
402
|
+
console.log('');
|
|
403
|
+
violations = findViolationsForAll(workspaceRoot);
|
|
404
|
+
} else {
|
|
405
|
+
let base = process.env['NX_BASE'];
|
|
406
|
+
const head = process.env['NX_HEAD'];
|
|
407
|
+
|
|
408
|
+
if (!base) {
|
|
409
|
+
base = detectBase(workspaceRoot) ?? undefined;
|
|
410
|
+
|
|
411
|
+
if (!base) {
|
|
412
|
+
console.log('\nāļø Skipping return type validation (could not detect base branch)');
|
|
413
|
+
console.log('');
|
|
414
|
+
return { success: true };
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
console.log(` Base: ${base}`);
|
|
419
|
+
console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);
|
|
420
|
+
console.log('');
|
|
421
|
+
|
|
422
|
+
const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);
|
|
423
|
+
|
|
424
|
+
if (changedFiles.length === 0) {
|
|
425
|
+
console.log('ā
No TypeScript files changed');
|
|
426
|
+
return { success: true };
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
console.log(`š Checking ${changedFiles.length} changed file(s)...`);
|
|
430
|
+
|
|
431
|
+
if (mode === 'MODIFIED_NEW') {
|
|
432
|
+
violations = findViolationsForModifiedNew(workspaceRoot, changedFiles, base, head);
|
|
433
|
+
} else if (mode === 'MODIFIED') {
|
|
434
|
+
violations = findViolationsForModified(workspaceRoot, changedFiles);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (violations.length === 0) {
|
|
439
|
+
console.log('ā
All methods have explicit return types');
|
|
440
|
+
return { success: true };
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
reportViolations(violations, mode);
|
|
444
|
+
|
|
445
|
+
return { success: false };
|
|
446
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/schema",
|
|
3
|
+
"title": "Validate Return Types Executor",
|
|
4
|
+
"description": "Validates that methods have explicit return type annotations for better code readability.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"mode": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"enum": ["OFF", "MODIFIED_NEW", "MODIFIED", "ALL"],
|
|
10
|
+
"description": "OFF: skip validation. MODIFIED_NEW: only validate new methods. MODIFIED: validate all methods in modified files. ALL: validate all methods in all files.",
|
|
11
|
+
"default": "MODIFIED_NEW"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"required": []
|
|
15
|
+
}
|
package/executors.json
CHANGED
|
@@ -64,6 +64,11 @@
|
|
|
64
64
|
"implementation": "./architecture/executors/validate-code/executor",
|
|
65
65
|
"schema": "./architecture/executors/validate-code/schema.json",
|
|
66
66
|
"description": "Combined validation for new methods, modified methods, and file sizes"
|
|
67
|
+
},
|
|
68
|
+
"validate-return-types": {
|
|
69
|
+
"implementation": "./architecture/executors/validate-return-types/executor",
|
|
70
|
+
"schema": "./architecture/executors/validate-return-types/schema.json",
|
|
71
|
+
"description": "Validate methods have explicit return type annotations"
|
|
67
72
|
}
|
|
68
73
|
}
|
|
69
74
|
}
|