@webpieces/dev-config 0.2.72 → 0.2.74

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.
@@ -11,8 +11,9 @@
11
11
  *
12
12
  * Modes:
13
13
  * - OFF: Skip validation entirely
14
- * - MODIFIED_NEW: Only validate new methods (detected via git diff)
15
- * - MODIFIED: Validate all methods in modified files
14
+ * - NEW_METHODS: Only validate new methods (detected via git diff)
15
+ * - MODIFIED_AND_NEW_METHODS: Validate new methods + methods with changes in their line range
16
+ * - MODIFIED_FILES: Validate all methods in modified files
16
17
  * - ALL: Validate all methods in all TypeScript files
17
18
  *
18
19
  * Escape hatch: Add webpieces-disable require-return-type comment with justification
@@ -176,31 +177,39 @@ function findMethodsInFile(filePath, workspaceRoot) {
176
177
  function visit(node) {
177
178
  let methodName;
178
179
  let startLine;
180
+ let endLine;
179
181
  let hasReturnType = false;
180
182
  if (ts.isMethodDeclaration(node) && node.name) {
181
183
  methodName = node.name.getText(sourceFile);
182
184
  const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
185
+ const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
183
186
  startLine = start.line + 1;
187
+ endLine = end.line + 1;
184
188
  hasReturnType = hasExplicitReturnType(node);
185
189
  }
186
190
  else if (ts.isFunctionDeclaration(node) && node.name) {
187
191
  methodName = node.name.getText(sourceFile);
188
192
  const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
193
+ const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
189
194
  startLine = start.line + 1;
195
+ endLine = end.line + 1;
190
196
  hasReturnType = hasExplicitReturnType(node);
191
197
  }
192
198
  else if (ts.isArrowFunction(node)) {
193
199
  if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
194
200
  methodName = node.parent.name.getText(sourceFile);
195
201
  const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
202
+ const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
196
203
  startLine = start.line + 1;
204
+ endLine = end.line + 1;
197
205
  hasReturnType = hasExplicitReturnType(node);
198
206
  }
199
207
  }
200
- if (methodName && startLine !== undefined) {
208
+ if (methodName && startLine !== undefined && endLine !== undefined) {
201
209
  methods.push({
202
210
  name: methodName,
203
211
  line: startLine,
212
+ endLine,
204
213
  hasReturnType,
205
214
  hasDisableComment: hasDisableComment(fileLines, startLine),
206
215
  });
@@ -211,10 +220,47 @@ function findMethodsInFile(filePath, workspaceRoot) {
211
220
  return methods;
212
221
  }
213
222
  /**
214
- * Find methods without explicit return types based on mode.
223
+ * Parse diff to extract changed line numbers (both additions and modifications).
224
+ */
225
+ function getChangedLineNumbers(diffContent) {
226
+ const changedLines = new Set();
227
+ const lines = diffContent.split('\n');
228
+ let currentLine = 0;
229
+ for (const line of lines) {
230
+ const hunkMatch = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
231
+ if (hunkMatch) {
232
+ currentLine = parseInt(hunkMatch[1], 10);
233
+ continue;
234
+ }
235
+ if (line.startsWith('+') && !line.startsWith('+++')) {
236
+ changedLines.add(currentLine);
237
+ currentLine++;
238
+ }
239
+ else if (line.startsWith('-') && !line.startsWith('---')) {
240
+ // Deletions don't increment line number
241
+ }
242
+ else {
243
+ currentLine++;
244
+ }
245
+ }
246
+ return changedLines;
247
+ }
248
+ /**
249
+ * Check if a method has any changed lines within its range.
250
+ */
251
+ function methodHasChanges(method, changedLines) {
252
+ for (let line = method.line; line <= method.endLine; line++) {
253
+ if (changedLines.has(line)) {
254
+ return true;
255
+ }
256
+ }
257
+ return false;
258
+ }
259
+ /**
260
+ * Find NEW methods without explicit return types (NEW_METHODS mode).
215
261
  */
216
262
  // webpieces-disable max-lines-new-methods -- File iteration with diff parsing and method matching
217
- function findViolationsForModifiedNew(workspaceRoot, changedFiles, base, head) {
263
+ function findViolationsForNewMethods(workspaceRoot, changedFiles, base, head) {
218
264
  const violations = [];
219
265
  for (const file of changedFiles) {
220
266
  const diff = getFileDiff(workspaceRoot, file, base, head);
@@ -239,9 +285,38 @@ function findViolationsForModifiedNew(workspaceRoot, changedFiles, base, head) {
239
285
  return violations;
240
286
  }
241
287
  /**
242
- * Find all methods without explicit return types in modified files.
288
+ * Find NEW methods AND methods with changes (MODIFIED_AND_NEW_METHODS mode).
289
+ */
290
+ // webpieces-disable max-lines-new-methods -- Combines new method detection with change detection
291
+ function findViolationsForModifiedAndNewMethods(workspaceRoot, changedFiles, base, head) {
292
+ const violations = [];
293
+ for (const file of changedFiles) {
294
+ const diff = getFileDiff(workspaceRoot, file, base, head);
295
+ const newMethodNames = findNewMethodSignaturesInDiff(diff);
296
+ const changedLines = getChangedLineNumbers(diff);
297
+ const methods = findMethodsInFile(file, workspaceRoot);
298
+ for (const method of methods) {
299
+ if (method.hasReturnType)
300
+ continue;
301
+ if (method.hasDisableComment)
302
+ continue;
303
+ const isNewMethod = newMethodNames.has(method.name);
304
+ const isModifiedMethod = methodHasChanges(method, changedLines);
305
+ if (!isNewMethod && !isModifiedMethod)
306
+ continue;
307
+ violations.push({
308
+ file,
309
+ methodName: method.name,
310
+ line: method.line,
311
+ });
312
+ }
313
+ }
314
+ return violations;
315
+ }
316
+ /**
317
+ * Find all methods without explicit return types in modified files (MODIFIED_FILES mode).
243
318
  */
244
- function findViolationsForModified(workspaceRoot, changedFiles) {
319
+ function findViolationsForModifiedFiles(workspaceRoot, changedFiles) {
245
320
  const violations = [];
246
321
  for (const file of changedFiles) {
247
322
  const methods = findMethodsInFile(file, workspaceRoot);
@@ -260,11 +335,11 @@ function findViolationsForModified(workspaceRoot, changedFiles) {
260
335
  return violations;
261
336
  }
262
337
  /**
263
- * Find all methods without explicit return types in all files.
338
+ * Find all methods without explicit return types in all files (ALL mode).
264
339
  */
265
340
  function findViolationsForAll(workspaceRoot) {
266
341
  const allFiles = getAllTypeScriptFiles(workspaceRoot);
267
- return findViolationsForModified(workspaceRoot, allFiles);
342
+ return findViolationsForModifiedFiles(workspaceRoot, allFiles);
268
343
  }
269
344
  /**
270
345
  * Auto-detect the base branch by finding the merge-base with origin/main.
@@ -325,7 +400,7 @@ function reportViolations(violations, mode) {
325
400
  }
326
401
  async function runExecutor(options, context) {
327
402
  const workspaceRoot = context.root;
328
- const mode = options.mode ?? 'MODIFIED_NEW';
403
+ const mode = options.mode ?? 'NEW_METHODS';
329
404
  if (mode === 'OFF') {
330
405
  console.log('\n⏭️ Skipping return type validation (mode: OFF)');
331
406
  console.log('');
@@ -359,11 +434,14 @@ async function runExecutor(options, context) {
359
434
  return { success: true };
360
435
  }
361
436
  console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);
362
- if (mode === 'MODIFIED_NEW') {
363
- violations = findViolationsForModifiedNew(workspaceRoot, changedFiles, base, head);
437
+ if (mode === 'NEW_METHODS') {
438
+ violations = findViolationsForNewMethods(workspaceRoot, changedFiles, base, head);
439
+ }
440
+ else if (mode === 'MODIFIED_AND_NEW_METHODS') {
441
+ violations = findViolationsForModifiedAndNewMethods(workspaceRoot, changedFiles, base, head);
364
442
  }
365
- else if (mode === 'MODIFIED') {
366
- violations = findViolationsForModified(workspaceRoot, changedFiles);
443
+ else if (mode === 'MODIFIED_FILES') {
444
+ violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles);
367
445
  }
368
446
  }
369
447
  if (violations.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/dev-config/architecture/executors/validate-return-types/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Return Types Executor\n *\n * Validates that methods have explicit return type annotations for better code readability.\n * Instead of relying on TypeScript's type inference, explicit return types make code clearer:\n *\n * BAD: method() { return new MyClass(); }\n * GOOD: method(): MyClass { return new MyClass(); }\n * GOOD: async method(): Promise<MyType> { ... }\n *\n * Modes:\n * - OFF: Skip validation entirely\n * - MODIFIED_NEW: Only validate new methods (detected via git diff)\n * - MODIFIED: Validate all methods in modified files\n * - ALL: Validate all methods in all TypeScript files\n *\n * Escape hatch: Add webpieces-disable require-return-type comment with justification\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\n\nexport type ReturnTypeMode = 'OFF' | 'MODIFIED_NEW' | 'MODIFIED' | 'ALL';\n\nexport interface ValidateReturnTypesOptions {\n mode?: ReturnTypeMode;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\ninterface MethodViolation {\n file: string;\n methodName: string;\n line: number;\n}\n\n/**\n * Get changed TypeScript files between base and head (or working tree if head not specified).\n */\n// webpieces-disable max-lines-new-methods -- Git command handling with untracked files requires multiple code paths\nfunction getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: string): string[] {\n try {\n const diffTarget = head ? `${base} ${head}` : base;\n const output = execSync(`git diff --name-only ${diffTarget} -- '*.ts' '*.tsx'`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const changedFiles = output\n .trim()\n .split('\\n')\n .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));\n\n if (!head) {\n try {\n const untrackedOutput = execSync(`git ls-files --others --exclude-standard '*.ts' '*.tsx'`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const untrackedFiles = untrackedOutput\n .trim()\n .split('\\n')\n .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));\n const allFiles = new Set([...changedFiles, ...untrackedFiles]);\n return Array.from(allFiles);\n } catch {\n return changedFiles;\n }\n }\n\n return changedFiles;\n } catch {\n return [];\n }\n}\n\n/**\n * Get all TypeScript files in the workspace using git ls-files (excluding tests).\n */\nfunction getAllTypeScriptFiles(workspaceRoot: string): string[] {\n try {\n const output = execSync(`git ls-files '*.ts' '*.tsx'`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n return output\n .trim()\n .split('\\n')\n .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));\n } catch {\n return [];\n }\n}\n\n/**\n * Get the diff content for a specific file.\n */\nfunction getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string {\n try {\n const diffTarget = head ? `${base} ${head}` : base;\n const diff = execSync(`git diff ${diffTarget} -- \"${file}\"`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n\n if (!diff && !head) {\n const fullPath = path.join(workspaceRoot, file);\n if (fs.existsSync(fullPath)) {\n const isUntracked = execSync(`git ls-files --others --exclude-standard \"${file}\"`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n }).trim();\n\n if (isUntracked) {\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lines = content.split('\\n');\n return lines.map((line) => `+${line}`).join('\\n');\n }\n }\n }\n\n return diff;\n } catch {\n return '';\n }\n}\n\n/**\n * Parse diff to find newly added method signatures.\n */\nfunction findNewMethodSignaturesInDiff(diffContent: string): Set<string> {\n const newMethods = new Set<string>();\n const lines = diffContent.split('\\n');\n\n const patterns = [\n /^\\+\\s*(?:export\\s+)?(?:async\\s+)?function\\s+(\\w+)\\s*\\(/,\n /^\\+\\s*(?:export\\s+)?(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s*)?\\(/,\n /^\\+\\s*(?:export\\s+)?(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?function/,\n /^\\+\\s*(?:(?:public|private|protected)\\s+)?(?:static\\s+)?(?:async\\s+)?(\\w+)\\s*\\(/,\n ];\n\n for (const line of lines) {\n if (line.startsWith('+') && !line.startsWith('+++')) {\n for (const pattern of patterns) {\n const match = line.match(pattern);\n if (match) {\n const methodName = match[1];\n if (methodName && !['if', 'for', 'while', 'switch', 'catch', 'constructor'].includes(methodName)) {\n newMethods.add(methodName);\n }\n break;\n }\n }\n }\n }\n\n return newMethods;\n}\n\n/**\n * Check if a line contains a webpieces-disable comment for return type.\n */\nfunction hasDisableComment(lines: string[], lineNumber: number): boolean {\n const startCheck = Math.max(0, lineNumber - 5);\n for (let i = lineNumber - 2; i >= startCheck; i--) {\n const line = lines[i]?.trim() ?? '';\n if (line.startsWith('function ') || line.startsWith('class ') || line.endsWith('}')) {\n break;\n }\n if (line.includes('webpieces-disable') && line.includes('require-return-type')) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Check if a method has an explicit return type annotation.\n */\nfunction hasExplicitReturnType(node: ts.MethodDeclaration | ts.FunctionDeclaration | ts.ArrowFunction): boolean {\n return node.type !== undefined;\n}\n\ninterface MethodInfo {\n name: string;\n line: number;\n hasReturnType: boolean;\n hasDisableComment: boolean;\n}\n\n/**\n * Parse a TypeScript file and find methods with their return type status.\n */\n// webpieces-disable max-lines-new-methods -- AST traversal requires inline visitor function\nfunction findMethodsInFile(filePath: string, workspaceRoot: string): MethodInfo[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const fileLines = content.split('\\n');\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n\n const methods: MethodInfo[] = [];\n\n // webpieces-disable max-lines-new-methods -- AST visitor pattern requires handling multiple node types\n function visit(node: ts.Node): void {\n let methodName: string | undefined;\n let startLine: number | undefined;\n let hasReturnType = false;\n\n if (ts.isMethodDeclaration(node) && node.name) {\n methodName = node.name.getText(sourceFile);\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n startLine = start.line + 1;\n hasReturnType = hasExplicitReturnType(node);\n } else if (ts.isFunctionDeclaration(node) && node.name) {\n methodName = node.name.getText(sourceFile);\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n startLine = start.line + 1;\n hasReturnType = hasExplicitReturnType(node);\n } else if (ts.isArrowFunction(node)) {\n if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {\n methodName = node.parent.name.getText(sourceFile);\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n startLine = start.line + 1;\n hasReturnType = hasExplicitReturnType(node);\n }\n }\n\n if (methodName && startLine !== undefined) {\n methods.push({\n name: methodName,\n line: startLine,\n hasReturnType,\n hasDisableComment: hasDisableComment(fileLines, startLine),\n });\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return methods;\n}\n\n/**\n * Find methods without explicit return types based on mode.\n */\n// webpieces-disable max-lines-new-methods -- File iteration with diff parsing and method matching\nfunction findViolationsForModifiedNew(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head?: string\n): MethodViolation[] {\n const violations: MethodViolation[] = [];\n\n for (const file of changedFiles) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const newMethodNames = findNewMethodSignaturesInDiff(diff);\n\n if (newMethodNames.size === 0) continue;\n\n const methods = findMethodsInFile(file, workspaceRoot);\n\n for (const method of methods) {\n if (!newMethodNames.has(method.name)) continue;\n if (method.hasReturnType) continue;\n if (method.hasDisableComment) continue;\n\n violations.push({\n file,\n methodName: method.name,\n line: method.line,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Find all methods without explicit return types in modified files.\n */\nfunction findViolationsForModified(workspaceRoot: string, changedFiles: string[]): MethodViolation[] {\n const violations: MethodViolation[] = [];\n\n for (const file of changedFiles) {\n const methods = findMethodsInFile(file, workspaceRoot);\n\n for (const method of methods) {\n if (method.hasReturnType) continue;\n if (method.hasDisableComment) continue;\n\n violations.push({\n file,\n methodName: method.name,\n line: method.line,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Find all methods without explicit return types in all files.\n */\nfunction findViolationsForAll(workspaceRoot: string): MethodViolation[] {\n const allFiles = getAllTypeScriptFiles(workspaceRoot);\n return findViolationsForModified(workspaceRoot, allFiles);\n}\n\n/**\n * Auto-detect the base branch by finding the merge-base with origin/main.\n */\nfunction detectBase(workspaceRoot: string): string | null {\n try {\n const mergeBase = execSync('git merge-base HEAD origin/main', {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n if (mergeBase) {\n return mergeBase;\n }\n } catch {\n try {\n const mergeBase = execSync('git merge-base HEAD main', {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n if (mergeBase) {\n return mergeBase;\n }\n } catch {\n // Ignore\n }\n }\n return null;\n}\n\n/**\n * Report violations to console.\n */\nfunction reportViolations(violations: MethodViolation[], mode: ReturnTypeMode): void {\n console.error('');\n console.error('❌ Methods missing explicit return types!');\n console.error('');\n console.error('📚 Explicit return types improve code readability:');\n console.error('');\n console.error(' BAD: method() { return new MyClass(); }');\n console.error(' GOOD: method(): MyClass { return new MyClass(); }');\n console.error(' GOOD: async method(): Promise<MyType> { ... }');\n console.error('');\n\n for (const v of violations) {\n console.error(` ❌ ${v.file}:${v.line}`);\n console.error(` Method: ${v.methodName} - missing return type annotation`);\n }\n console.error('');\n\n console.error(' To fix: Add explicit return type after the parameter list');\n console.error('');\n console.error(' Escape hatch (use sparingly):');\n console.error(' // webpieces-disable require-return-type -- [your reason]');\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n}\n\nexport default async function runExecutor(\n options: ValidateReturnTypesOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n const workspaceRoot = context.root;\n const mode: ReturnTypeMode = options.mode ?? 'MODIFIED_NEW';\n\n if (mode === 'OFF') {\n console.log('\\n⏭️ Skipping return type validation (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n📏 Validating Return Types\\n');\n console.log(` Mode: ${mode}`);\n\n let violations: MethodViolation[] = [];\n\n if (mode === 'ALL') {\n console.log(' Scope: All tracked TypeScript files');\n console.log('');\n violations = findViolationsForAll(workspaceRoot);\n } else {\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n\n if (!base) {\n console.log('\\n⏭️ Skipping return type validation (could not detect base branch)');\n console.log('');\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);\n\n if (changedFiles.length === 0) {\n console.log('✅ No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);\n\n if (mode === 'MODIFIED_NEW') {\n violations = findViolationsForModifiedNew(workspaceRoot, changedFiles, base, head);\n } else if (mode === 'MODIFIED') {\n violations = findViolationsForModified(workspaceRoot, changedFiles);\n }\n }\n\n if (violations.length === 0) {\n console.log('✅ All methods have explicit return types');\n return { success: true };\n }\n\n reportViolations(violations, mode);\n\n return { success: false };\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/dev-config/architecture/executors/validate-return-types/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Return Types Executor\n *\n * Validates that methods have explicit return type annotations for better code readability.\n * Instead of relying on TypeScript's type inference, explicit return types make code clearer:\n *\n * BAD: method() { return new MyClass(); }\n * GOOD: method(): MyClass { return new MyClass(); }\n * GOOD: async method(): Promise<MyType> { ... }\n *\n * Modes:\n * - OFF: Skip validation entirely\n * - NEW_METHODS: Only validate new methods (detected via git diff)\n * - MODIFIED_AND_NEW_METHODS: Validate new methods + methods with changes in their line range\n * - MODIFIED_FILES: Validate all methods in modified files\n * - ALL: Validate all methods in all TypeScript files\n *\n * Escape hatch: Add webpieces-disable require-return-type comment with justification\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\n\nexport type ReturnTypeMode = 'OFF' | 'NEW_METHODS' | 'MODIFIED_AND_NEW_METHODS' | 'MODIFIED_FILES' | 'ALL';\n\nexport interface ValidateReturnTypesOptions {\n mode?: ReturnTypeMode;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\ninterface MethodViolation {\n file: string;\n methodName: string;\n line: number;\n}\n\n/**\n * Get changed TypeScript files between base and head (or working tree if head not specified).\n */\n// webpieces-disable max-lines-new-methods -- Git command handling with untracked files requires multiple code paths\nfunction getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: string): string[] {\n try {\n const diffTarget = head ? `${base} ${head}` : base;\n const output = execSync(`git diff --name-only ${diffTarget} -- '*.ts' '*.tsx'`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const changedFiles = output\n .trim()\n .split('\\n')\n .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));\n\n if (!head) {\n try {\n const untrackedOutput = execSync(`git ls-files --others --exclude-standard '*.ts' '*.tsx'`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const untrackedFiles = untrackedOutput\n .trim()\n .split('\\n')\n .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));\n const allFiles = new Set([...changedFiles, ...untrackedFiles]);\n return Array.from(allFiles);\n } catch {\n return changedFiles;\n }\n }\n\n return changedFiles;\n } catch {\n return [];\n }\n}\n\n/**\n * Get all TypeScript files in the workspace using git ls-files (excluding tests).\n */\nfunction getAllTypeScriptFiles(workspaceRoot: string): string[] {\n try {\n const output = execSync(`git ls-files '*.ts' '*.tsx'`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n return output\n .trim()\n .split('\\n')\n .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));\n } catch {\n return [];\n }\n}\n\n/**\n * Get the diff content for a specific file.\n */\nfunction getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string {\n try {\n const diffTarget = head ? `${base} ${head}` : base;\n const diff = execSync(`git diff ${diffTarget} -- \"${file}\"`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n\n if (!diff && !head) {\n const fullPath = path.join(workspaceRoot, file);\n if (fs.existsSync(fullPath)) {\n const isUntracked = execSync(`git ls-files --others --exclude-standard \"${file}\"`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n }).trim();\n\n if (isUntracked) {\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lines = content.split('\\n');\n return lines.map((line) => `+${line}`).join('\\n');\n }\n }\n }\n\n return diff;\n } catch {\n return '';\n }\n}\n\n/**\n * Parse diff to find newly added method signatures.\n */\nfunction findNewMethodSignaturesInDiff(diffContent: string): Set<string> {\n const newMethods = new Set<string>();\n const lines = diffContent.split('\\n');\n\n const patterns = [\n /^\\+\\s*(?:export\\s+)?(?:async\\s+)?function\\s+(\\w+)\\s*\\(/,\n /^\\+\\s*(?:export\\s+)?(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s*)?\\(/,\n /^\\+\\s*(?:export\\s+)?(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?function/,\n /^\\+\\s*(?:(?:public|private|protected)\\s+)?(?:static\\s+)?(?:async\\s+)?(\\w+)\\s*\\(/,\n ];\n\n for (const line of lines) {\n if (line.startsWith('+') && !line.startsWith('+++')) {\n for (const pattern of patterns) {\n const match = line.match(pattern);\n if (match) {\n const methodName = match[1];\n if (methodName && !['if', 'for', 'while', 'switch', 'catch', 'constructor'].includes(methodName)) {\n newMethods.add(methodName);\n }\n break;\n }\n }\n }\n }\n\n return newMethods;\n}\n\n/**\n * Check if a line contains a webpieces-disable comment for return type.\n */\nfunction hasDisableComment(lines: string[], lineNumber: number): boolean {\n const startCheck = Math.max(0, lineNumber - 5);\n for (let i = lineNumber - 2; i >= startCheck; i--) {\n const line = lines[i]?.trim() ?? '';\n if (line.startsWith('function ') || line.startsWith('class ') || line.endsWith('}')) {\n break;\n }\n if (line.includes('webpieces-disable') && line.includes('require-return-type')) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Check if a method has an explicit return type annotation.\n */\nfunction hasExplicitReturnType(node: ts.MethodDeclaration | ts.FunctionDeclaration | ts.ArrowFunction): boolean {\n return node.type !== undefined;\n}\n\ninterface MethodInfo {\n name: string;\n line: number;\n endLine: number;\n hasReturnType: boolean;\n hasDisableComment: boolean;\n}\n\n/**\n * Parse a TypeScript file and find methods with their return type status.\n */\n// webpieces-disable max-lines-new-methods -- AST traversal requires inline visitor function\nfunction findMethodsInFile(filePath: string, workspaceRoot: string): MethodInfo[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const fileLines = content.split('\\n');\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n\n const methods: MethodInfo[] = [];\n\n // webpieces-disable max-lines-new-methods -- AST visitor pattern requires handling multiple node types\n function visit(node: ts.Node): void {\n let methodName: string | undefined;\n let startLine: number | undefined;\n let endLine: number | undefined;\n let hasReturnType = false;\n\n if (ts.isMethodDeclaration(node) && node.name) {\n methodName = node.name.getText(sourceFile);\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());\n startLine = start.line + 1;\n endLine = end.line + 1;\n hasReturnType = hasExplicitReturnType(node);\n } else if (ts.isFunctionDeclaration(node) && node.name) {\n methodName = node.name.getText(sourceFile);\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());\n startLine = start.line + 1;\n endLine = end.line + 1;\n hasReturnType = hasExplicitReturnType(node);\n } else if (ts.isArrowFunction(node)) {\n if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {\n methodName = node.parent.name.getText(sourceFile);\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());\n startLine = start.line + 1;\n endLine = end.line + 1;\n hasReturnType = hasExplicitReturnType(node);\n }\n }\n\n if (methodName && startLine !== undefined && endLine !== undefined) {\n methods.push({\n name: methodName,\n line: startLine,\n endLine,\n hasReturnType,\n hasDisableComment: hasDisableComment(fileLines, startLine),\n });\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return methods;\n}\n\n/**\n * Parse diff to extract changed line numbers (both additions and modifications).\n */\nfunction getChangedLineNumbers(diffContent: string): Set<number> {\n const changedLines = new Set<number>();\n const lines = diffContent.split('\\n');\n let currentLine = 0;\n\n for (const line of lines) {\n const hunkMatch = line.match(/^@@ -\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/);\n if (hunkMatch) {\n currentLine = parseInt(hunkMatch[1], 10);\n continue;\n }\n\n if (line.startsWith('+') && !line.startsWith('+++')) {\n changedLines.add(currentLine);\n currentLine++;\n } else if (line.startsWith('-') && !line.startsWith('---')) {\n // Deletions don't increment line number\n } else {\n currentLine++;\n }\n }\n\n return changedLines;\n}\n\n/**\n * Check if a method has any changed lines within its range.\n */\nfunction methodHasChanges(method: MethodInfo, changedLines: Set<number>): boolean {\n for (let line = method.line; line <= method.endLine; line++) {\n if (changedLines.has(line)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Find NEW methods without explicit return types (NEW_METHODS mode).\n */\n// webpieces-disable max-lines-new-methods -- File iteration with diff parsing and method matching\nfunction findViolationsForNewMethods(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head?: string\n): MethodViolation[] {\n const violations: MethodViolation[] = [];\n\n for (const file of changedFiles) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const newMethodNames = findNewMethodSignaturesInDiff(diff);\n\n if (newMethodNames.size === 0) continue;\n\n const methods = findMethodsInFile(file, workspaceRoot);\n\n for (const method of methods) {\n if (!newMethodNames.has(method.name)) continue;\n if (method.hasReturnType) continue;\n if (method.hasDisableComment) continue;\n\n violations.push({\n file,\n methodName: method.name,\n line: method.line,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Find NEW methods AND methods with changes (MODIFIED_AND_NEW_METHODS mode).\n */\n// webpieces-disable max-lines-new-methods -- Combines new method detection with change detection\nfunction findViolationsForModifiedAndNewMethods(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head?: string\n): MethodViolation[] {\n const violations: MethodViolation[] = [];\n\n for (const file of changedFiles) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const newMethodNames = findNewMethodSignaturesInDiff(diff);\n const changedLines = getChangedLineNumbers(diff);\n\n const methods = findMethodsInFile(file, workspaceRoot);\n\n for (const method of methods) {\n if (method.hasReturnType) continue;\n if (method.hasDisableComment) continue;\n\n const isNewMethod = newMethodNames.has(method.name);\n const isModifiedMethod = methodHasChanges(method, changedLines);\n\n if (!isNewMethod && !isModifiedMethod) continue;\n\n violations.push({\n file,\n methodName: method.name,\n line: method.line,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Find all methods without explicit return types in modified files (MODIFIED_FILES mode).\n */\nfunction findViolationsForModifiedFiles(workspaceRoot: string, changedFiles: string[]): MethodViolation[] {\n const violations: MethodViolation[] = [];\n\n for (const file of changedFiles) {\n const methods = findMethodsInFile(file, workspaceRoot);\n\n for (const method of methods) {\n if (method.hasReturnType) continue;\n if (method.hasDisableComment) continue;\n\n violations.push({\n file,\n methodName: method.name,\n line: method.line,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Find all methods without explicit return types in all files (ALL mode).\n */\nfunction findViolationsForAll(workspaceRoot: string): MethodViolation[] {\n const allFiles = getAllTypeScriptFiles(workspaceRoot);\n return findViolationsForModifiedFiles(workspaceRoot, allFiles);\n}\n\n/**\n * Auto-detect the base branch by finding the merge-base with origin/main.\n */\nfunction detectBase(workspaceRoot: string): string | null {\n try {\n const mergeBase = execSync('git merge-base HEAD origin/main', {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n if (mergeBase) {\n return mergeBase;\n }\n } catch {\n try {\n const mergeBase = execSync('git merge-base HEAD main', {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n if (mergeBase) {\n return mergeBase;\n }\n } catch {\n // Ignore\n }\n }\n return null;\n}\n\n/**\n * Report violations to console.\n */\nfunction reportViolations(violations: MethodViolation[], mode: ReturnTypeMode): void {\n console.error('');\n console.error('❌ Methods missing explicit return types!');\n console.error('');\n console.error('📚 Explicit return types improve code readability:');\n console.error('');\n console.error(' BAD: method() { return new MyClass(); }');\n console.error(' GOOD: method(): MyClass { return new MyClass(); }');\n console.error(' GOOD: async method(): Promise<MyType> { ... }');\n console.error('');\n\n for (const v of violations) {\n console.error(` ❌ ${v.file}:${v.line}`);\n console.error(` Method: ${v.methodName} - missing return type annotation`);\n }\n console.error('');\n\n console.error(' To fix: Add explicit return type after the parameter list');\n console.error('');\n console.error(' Escape hatch (use sparingly):');\n console.error(' // webpieces-disable require-return-type -- [your reason]');\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n}\n\nexport default async function runExecutor(\n options: ValidateReturnTypesOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n const workspaceRoot = context.root;\n const mode: ReturnTypeMode = options.mode ?? 'NEW_METHODS';\n\n if (mode === 'OFF') {\n console.log('\\n⏭️ Skipping return type validation (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n📏 Validating Return Types\\n');\n console.log(` Mode: ${mode}`);\n\n let violations: MethodViolation[] = [];\n\n if (mode === 'ALL') {\n console.log(' Scope: All tracked TypeScript files');\n console.log('');\n violations = findViolationsForAll(workspaceRoot);\n } else {\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n\n if (!base) {\n console.log('\\n⏭️ Skipping return type validation (could not detect base branch)');\n console.log('');\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);\n\n if (changedFiles.length === 0) {\n console.log('✅ No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);\n\n if (mode === 'NEW_METHODS') {\n violations = findViolationsForNewMethods(workspaceRoot, changedFiles, base, head);\n } else if (mode === 'MODIFIED_AND_NEW_METHODS') {\n violations = findViolationsForModifiedAndNewMethods(workspaceRoot, changedFiles, base, head);\n } else if (mode === 'MODIFIED_FILES') {\n violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles);\n }\n }\n\n if (violations.length === 0) {\n console.log('✅ All methods have explicit return types');\n return { success: true };\n }\n\n reportViolations(violations, mode);\n\n return { success: false };\n}\n"]}
@@ -10,8 +10,9 @@
10
10
  *
11
11
  * Modes:
12
12
  * - OFF: Skip validation entirely
13
- * - MODIFIED_NEW: Only validate new methods (detected via git diff)
14
- * - MODIFIED: Validate all methods in modified files
13
+ * - NEW_METHODS: Only validate new methods (detected via git diff)
14
+ * - MODIFIED_AND_NEW_METHODS: Validate new methods + methods with changes in their line range
15
+ * - MODIFIED_FILES: Validate all methods in modified files
15
16
  * - ALL: Validate all methods in all TypeScript files
16
17
  *
17
18
  * Escape hatch: Add webpieces-disable require-return-type comment with justification
@@ -23,7 +24,7 @@ import * as fs from 'fs';
23
24
  import * as path from 'path';
24
25
  import * as ts from 'typescript';
25
26
 
26
- export type ReturnTypeMode = 'OFF' | 'MODIFIED_NEW' | 'MODIFIED' | 'ALL';
27
+ export type ReturnTypeMode = 'OFF' | 'NEW_METHODS' | 'MODIFIED_AND_NEW_METHODS' | 'MODIFIED_FILES' | 'ALL';
27
28
 
28
29
  export interface ValidateReturnTypesOptions {
29
30
  mode?: ReturnTypeMode;
@@ -188,6 +189,7 @@ function hasExplicitReturnType(node: ts.MethodDeclaration | ts.FunctionDeclarati
188
189
  interface MethodInfo {
189
190
  name: string;
190
191
  line: number;
192
+ endLine: number;
191
193
  hasReturnType: boolean;
192
194
  hasDisableComment: boolean;
193
195
  }
@@ -210,31 +212,39 @@ function findMethodsInFile(filePath: string, workspaceRoot: string): MethodInfo[
210
212
  function visit(node: ts.Node): void {
211
213
  let methodName: string | undefined;
212
214
  let startLine: number | undefined;
215
+ let endLine: number | undefined;
213
216
  let hasReturnType = false;
214
217
 
215
218
  if (ts.isMethodDeclaration(node) && node.name) {
216
219
  methodName = node.name.getText(sourceFile);
217
220
  const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
221
+ const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
218
222
  startLine = start.line + 1;
223
+ endLine = end.line + 1;
219
224
  hasReturnType = hasExplicitReturnType(node);
220
225
  } else if (ts.isFunctionDeclaration(node) && node.name) {
221
226
  methodName = node.name.getText(sourceFile);
222
227
  const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
228
+ const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
223
229
  startLine = start.line + 1;
230
+ endLine = end.line + 1;
224
231
  hasReturnType = hasExplicitReturnType(node);
225
232
  } else if (ts.isArrowFunction(node)) {
226
233
  if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
227
234
  methodName = node.parent.name.getText(sourceFile);
228
235
  const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
236
+ const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
229
237
  startLine = start.line + 1;
238
+ endLine = end.line + 1;
230
239
  hasReturnType = hasExplicitReturnType(node);
231
240
  }
232
241
  }
233
242
 
234
- if (methodName && startLine !== undefined) {
243
+ if (methodName && startLine !== undefined && endLine !== undefined) {
235
244
  methods.push({
236
245
  name: methodName,
237
246
  line: startLine,
247
+ endLine,
238
248
  hasReturnType,
239
249
  hasDisableComment: hasDisableComment(fileLines, startLine),
240
250
  });
@@ -248,10 +258,50 @@ function findMethodsInFile(filePath: string, workspaceRoot: string): MethodInfo[
248
258
  }
249
259
 
250
260
  /**
251
- * Find methods without explicit return types based on mode.
261
+ * Parse diff to extract changed line numbers (both additions and modifications).
262
+ */
263
+ function getChangedLineNumbers(diffContent: string): Set<number> {
264
+ const changedLines = new Set<number>();
265
+ const lines = diffContent.split('\n');
266
+ let currentLine = 0;
267
+
268
+ for (const line of lines) {
269
+ const hunkMatch = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
270
+ if (hunkMatch) {
271
+ currentLine = parseInt(hunkMatch[1], 10);
272
+ continue;
273
+ }
274
+
275
+ if (line.startsWith('+') && !line.startsWith('+++')) {
276
+ changedLines.add(currentLine);
277
+ currentLine++;
278
+ } else if (line.startsWith('-') && !line.startsWith('---')) {
279
+ // Deletions don't increment line number
280
+ } else {
281
+ currentLine++;
282
+ }
283
+ }
284
+
285
+ return changedLines;
286
+ }
287
+
288
+ /**
289
+ * Check if a method has any changed lines within its range.
290
+ */
291
+ function methodHasChanges(method: MethodInfo, changedLines: Set<number>): boolean {
292
+ for (let line = method.line; line <= method.endLine; line++) {
293
+ if (changedLines.has(line)) {
294
+ return true;
295
+ }
296
+ }
297
+ return false;
298
+ }
299
+
300
+ /**
301
+ * Find NEW methods without explicit return types (NEW_METHODS mode).
252
302
  */
253
303
  // webpieces-disable max-lines-new-methods -- File iteration with diff parsing and method matching
254
- function findViolationsForModifiedNew(
304
+ function findViolationsForNewMethods(
255
305
  workspaceRoot: string,
256
306
  changedFiles: string[],
257
307
  base: string,
@@ -284,9 +334,48 @@ function findViolationsForModifiedNew(
284
334
  }
285
335
 
286
336
  /**
287
- * Find all methods without explicit return types in modified files.
337
+ * Find NEW methods AND methods with changes (MODIFIED_AND_NEW_METHODS mode).
338
+ */
339
+ // webpieces-disable max-lines-new-methods -- Combines new method detection with change detection
340
+ function findViolationsForModifiedAndNewMethods(
341
+ workspaceRoot: string,
342
+ changedFiles: string[],
343
+ base: string,
344
+ head?: string
345
+ ): MethodViolation[] {
346
+ const violations: MethodViolation[] = [];
347
+
348
+ for (const file of changedFiles) {
349
+ const diff = getFileDiff(workspaceRoot, file, base, head);
350
+ const newMethodNames = findNewMethodSignaturesInDiff(diff);
351
+ const changedLines = getChangedLineNumbers(diff);
352
+
353
+ const methods = findMethodsInFile(file, workspaceRoot);
354
+
355
+ for (const method of methods) {
356
+ if (method.hasReturnType) continue;
357
+ if (method.hasDisableComment) continue;
358
+
359
+ const isNewMethod = newMethodNames.has(method.name);
360
+ const isModifiedMethod = methodHasChanges(method, changedLines);
361
+
362
+ if (!isNewMethod && !isModifiedMethod) continue;
363
+
364
+ violations.push({
365
+ file,
366
+ methodName: method.name,
367
+ line: method.line,
368
+ });
369
+ }
370
+ }
371
+
372
+ return violations;
373
+ }
374
+
375
+ /**
376
+ * Find all methods without explicit return types in modified files (MODIFIED_FILES mode).
288
377
  */
289
- function findViolationsForModified(workspaceRoot: string, changedFiles: string[]): MethodViolation[] {
378
+ function findViolationsForModifiedFiles(workspaceRoot: string, changedFiles: string[]): MethodViolation[] {
290
379
  const violations: MethodViolation[] = [];
291
380
 
292
381
  for (const file of changedFiles) {
@@ -308,11 +397,11 @@ function findViolationsForModified(workspaceRoot: string, changedFiles: string[]
308
397
  }
309
398
 
310
399
  /**
311
- * Find all methods without explicit return types in all files.
400
+ * Find all methods without explicit return types in all files (ALL mode).
312
401
  */
313
402
  function findViolationsForAll(workspaceRoot: string): MethodViolation[] {
314
403
  const allFiles = getAllTypeScriptFiles(workspaceRoot);
315
- return findViolationsForModified(workspaceRoot, allFiles);
404
+ return findViolationsForModifiedFiles(workspaceRoot, allFiles);
316
405
  }
317
406
 
318
407
  /**
@@ -381,7 +470,7 @@ export default async function runExecutor(
381
470
  context: ExecutorContext
382
471
  ): Promise<ExecutorResult> {
383
472
  const workspaceRoot = context.root;
384
- const mode: ReturnTypeMode = options.mode ?? 'MODIFIED_NEW';
473
+ const mode: ReturnTypeMode = options.mode ?? 'NEW_METHODS';
385
474
 
386
475
  if (mode === 'OFF') {
387
476
  console.log('\n⏭️ Skipping return type validation (mode: OFF)');
@@ -425,10 +514,12 @@ export default async function runExecutor(
425
514
 
426
515
  console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);
427
516
 
428
- if (mode === 'MODIFIED_NEW') {
429
- violations = findViolationsForModifiedNew(workspaceRoot, changedFiles, base, head);
430
- } else if (mode === 'MODIFIED') {
431
- violations = findViolationsForModified(workspaceRoot, changedFiles);
517
+ if (mode === 'NEW_METHODS') {
518
+ violations = findViolationsForNewMethods(workspaceRoot, changedFiles, base, head);
519
+ } else if (mode === 'MODIFIED_AND_NEW_METHODS') {
520
+ violations = findViolationsForModifiedAndNewMethods(workspaceRoot, changedFiles, base, head);
521
+ } else if (mode === 'MODIFIED_FILES') {
522
+ violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles);
432
523
  }
433
524
  }
434
525
 
@@ -6,9 +6,9 @@
6
6
  "properties": {
7
7
  "mode": {
8
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"
9
+ "enum": ["OFF", "NEW_METHODS", "MODIFIED_AND_NEW_METHODS", "MODIFIED_FILES", "ALL"],
10
+ "description": "OFF: skip validation. NEW_METHODS: only new methods in diff. MODIFIED_AND_NEW_METHODS: new methods + methods with changes. MODIFIED_FILES: all methods in modified files. ALL: all methods everywhere.",
11
+ "default": "NEW_METHODS"
12
12
  }
13
13
  },
14
14
  "required": []
package/executors.json CHANGED
@@ -69,6 +69,11 @@
69
69
  "implementation": "./architecture/executors/validate-return-types/executor",
70
70
  "schema": "./architecture/executors/validate-return-types/schema.json",
71
71
  "description": "Validate methods have explicit return type annotations"
72
+ },
73
+ "validate-no-inline-types": {
74
+ "implementation": "./architecture/executors/validate-no-inline-types/executor",
75
+ "schema": "./architecture/executors/validate-no-inline-types/schema.json",
76
+ "description": "Validate no inline type literals are used - prefer named types"
72
77
  }
73
78
  }
74
79
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/dev-config",
3
- "version": "0.2.72",
3
+ "version": "0.2.74",
4
4
  "description": "Development configuration, scripts, and patterns for WebPieces projects",
5
5
  "type": "commonjs",
6
6
  "bin": {