@webpieces/dev-config 0.2.78 → 0.2.79

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.
@@ -432,8 +432,15 @@ function reportViolations(violations, limit, disableAllowed) {
432
432
  }
433
433
  else {
434
434
  console.error(' \u26a0\ufe0f disableAllowed is false - disable comments are NOT allowed.');
435
+ console.error(' This rule must be met and cannot be disabled since nx.json disableAllowed is set to false.');
435
436
  console.error(' You MUST refactor to reduce file size.');
436
437
  console.error('');
438
+ console.error(' For a major refactor, a human can add "ignoreModifiedUntilEpoch" to nx.json validate-code options.');
439
+ console.error(' This is an expiry timestamp (epoch ms) for when we start forcing everyone to meet size rules again.');
440
+ console.error(' Sometimes for speed, we allow files to expand during a refactor and over time,');
441
+ console.error(' each PR reduces files as they get touched.');
442
+ console.error(' AI agents should NOT add ignoreModifiedUntilEpoch - ask a human to do it.');
443
+ console.error('');
437
444
  }
438
445
  }
439
446
  async function runExecutor(options, context) {
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/dev-config/architecture/executors/validate-modified-files/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Modified Files Executor\n *\n * Validates that modified files don't exceed a maximum line count (default 900).\n * This encourages keeping files small and focused - when you touch a file,\n * you must bring it under the limit.\n *\n * Usage:\n * nx affected --target=validate-modified-files --base=origin/main\n *\n * Escape hatch: Add webpieces-disable max-lines-modified-files comment with date and justification\n * Format: // webpieces-disable max-lines-modified-files 2025/01/15 -- [reason]\n * The disable expires after 1 month from the date specified.\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nexport type FileMaxLimitMode = 'OFF' | 'MODIFIED_FILES';\n\nexport interface ValidateModifiedFilesOptions {\n limit?: number;\n mode?: FileMaxLimitMode;\n disableAllowed?: boolean;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\ninterface FileViolation {\n file: string;\n lines: number;\n expiredDisable?: boolean;\n expiredDate?: string;\n}\n\nconst TMP_DIR = 'tmp/webpieces';\nconst TMP_MD_FILE = 'webpieces.filesize.md';\n\nconst FILESIZE_DOC_CONTENT = `# AI Agent Instructions: File Too Long\n\n**READ THIS FILE to fix files that are too long**\n\n## Core Principle\n\nWith **stateless systems + dependency injection, refactor is trivial**.\nPick a method or a few and move to new class XXXXX, then inject XXXXX\ninto all users of those methods via the constructor.\nDelete those methods from original class.\n\n**99% of files can be less than the configured max lines of code.**\n\nFiles should contain a SINGLE COHESIVE UNIT.\n- One class per file (Java convention)\n- If class is too large, extract child responsibilities\n- Use dependency injection to compose functionality\n\n## Command: Reduce File Size\n\n### Step 1: Check for Multiple Classes\nIf the file contains multiple classes, **SEPARATE each class into its own file**.\n\n\\`\\`\\`typescript\n// BAD: UserController.ts (multiple classes)\nexport class UserController { /* ... */ }\nexport class UserValidator { /* ... */ }\nexport class UserNotifier { /* ... */ }\n\n// GOOD: Three separate files\n// UserController.ts\nexport class UserController { /* ... */ }\n\n// UserValidator.ts\nexport class UserValidator { /* ... */ }\n\n// UserNotifier.ts\nexport class UserNotifier { /* ... */ }\n\\`\\`\\`\n\n### Step 2: Extract Child Responsibilities (if single class is too large)\n\n#### Pattern: Create New Service Class with Dependency Injection\n\n\\`\\`\\`typescript\n// BAD: UserController.ts (800 lines, single class)\n@provideSingleton()\n@Controller()\nexport class UserController {\n // 200 lines: CRUD operations\n // 300 lines: validation logic\n // 200 lines: notification logic\n // 100 lines: analytics logic\n}\n\n// GOOD: Extract validation service\n// 1. Create UserValidationService.ts\n@provideSingleton()\nexport class UserValidationService {\n validateUserData(data: UserData): ValidationResult {\n // 300 lines of validation logic moved here\n }\n\n validateEmail(email: string): boolean { /* ... */ }\n validatePassword(password: string): boolean { /* ... */ }\n}\n\n// 2. Inject into UserController.ts\n@provideSingleton()\n@Controller()\nexport class UserController {\n constructor(\n @inject(TYPES.UserValidationService)\n private validator: UserValidationService\n ) {}\n\n async createUser(data: UserData): Promise<User> {\n const validation = this.validator.validateUserData(data);\n if (!validation.isValid) {\n throw new ValidationError(validation.errors);\n }\n // ... rest of logic\n }\n}\n\\`\\`\\`\n\n## AI Agent Action Steps\n\n1. **ANALYZE** the file structure:\n - Count classes (if >1, separate immediately)\n - Identify logical responsibilities within single class\n\n2. **IDENTIFY** \"child code\" to extract:\n - Validation logic -> ValidationService\n - Notification logic -> NotificationService\n - Data transformation -> TransformerService\n - External API calls -> ApiService\n - Business rules -> RulesEngine\n\n3. **CREATE** new service file(s):\n - Start with temporary name: \\`XXXX.ts\\` or \\`ChildService.ts\\`\n - Add \\`@provideSingleton()\\` decorator\n - Move child methods to new class\n\n4. **UPDATE** dependency injection:\n - Add to \\`TYPES\\` constants (if using symbol-based DI)\n - Inject new service into original class constructor\n - Replace direct method calls with \\`this.serviceName.method()\\`\n\n5. **RENAME** extracted file:\n - Read the extracted code to understand its purpose\n - Rename \\`XXXX.ts\\` to logical name (e.g., \\`UserValidationService.ts\\`)\n\n6. **VERIFY** file sizes:\n - Original file should now be under the limit\n - Each extracted file should be under the limit\n - If still too large, extract more services\n\n## Examples of Child Responsibilities to Extract\n\n| If File Contains | Extract To | Pattern |\n|-----------------|------------|---------|\n| Validation logic (200+ lines) | \\`XValidator.ts\\` or \\`XValidationService.ts\\` | Singleton service |\n| Notification logic (150+ lines) | \\`XNotifier.ts\\` or \\`XNotificationService.ts\\` | Singleton service |\n| Data transformation (200+ lines) | \\`XTransformer.ts\\` | Singleton service |\n| External API calls (200+ lines) | \\`XApiClient.ts\\` | Singleton service |\n| Complex business rules (300+ lines) | \\`XRulesEngine.ts\\` | Singleton service |\n| Database queries (200+ lines) | \\`XRepository.ts\\` | Singleton service |\n\n## WebPieces Dependency Injection Pattern\n\n\\`\\`\\`typescript\n// 1. Define service with @provideSingleton\nimport { provideSingleton } from '@webpieces/http-routing';\n\n@provideSingleton()\nexport class MyService {\n doSomething(): void { /* ... */ }\n}\n\n// 2. Inject into consumer\nimport { inject } from 'inversify';\nimport { TYPES } from './types';\n\n@provideSingleton()\n@Controller()\nexport class MyController {\n constructor(\n @inject(TYPES.MyService) private service: MyService\n ) {}\n}\n\\`\\`\\`\n\n## Escape Hatch\n\nIf refactoring is genuinely not feasible (generated files, complex algorithms, etc.),\nadd a disable comment at the TOP of the file (within first 5 lines) with a DATE:\n\n\\`\\`\\`typescript\n// webpieces-disable max-lines-modified-files 2025/01/15 -- Complex generated file, refactoring would break generation\n\\`\\`\\`\n\n**IMPORTANT**: The date format is yyyy/mm/dd. The disable will EXPIRE after 1 month from this date.\nAfter expiration, you must either fix the file or update the date to get another month.\nThis ensures that disable comments are reviewed periodically.\n\nRemember: Find the \"child code\" and pull it down into a new class. Once moved, the code's purpose becomes clear, making it easy to rename to a logical name.\n`;\n\n/**\n * Write the instructions documentation to tmp directory\n */\nfunction writeTmpInstructions(workspaceRoot: string): string {\n const tmpDir = path.join(workspaceRoot, TMP_DIR);\n const mdPath = path.join(tmpDir, TMP_MD_FILE);\n\n fs.mkdirSync(tmpDir, { recursive: true });\n fs.writeFileSync(mdPath, FILESIZE_DOC_CONTENT);\n\n return mdPath;\n}\n\n/**\n * Get changed TypeScript files between base and head (or working tree if head not specified).\n * Uses `git diff base [head]` to match what `nx affected` does.\n * When head is NOT specified, also includes untracked files (matching nx affected behavior).\n */\nfunction getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: string): string[] {\n try {\n // If head is specified, diff base to head; otherwise diff base to working tree\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 // When comparing to working tree (no head specified), also include untracked files\n // This matches what nx affected does: \"All modified files not yet committed or tracked will also be added\"\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 // Merge and dedupe\n const allFiles = new Set([...changedFiles, ...untrackedFiles]);\n return Array.from(allFiles);\n } catch {\n // If ls-files fails, just return the changed files\n return changedFiles;\n }\n }\n\n return changedFiles;\n } catch {\n return [];\n }\n}\n\n/**\n * Parse a date string in yyyy/mm/dd format and return a Date object.\n * Returns null if the format is invalid.\n */\nfunction parseDisableDate(dateStr: string): Date | null {\n // Match yyyy/mm/dd format\n const match = dateStr.match(/^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/);\n if (!match) return null;\n\n const year = parseInt(match[1], 10);\n const month = parseInt(match[2], 10) - 1; // JS months are 0-indexed\n const day = parseInt(match[3], 10);\n\n const date = new Date(year, month, day);\n\n // Validate the date is valid (e.g., not Feb 30)\n if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {\n return null;\n }\n\n return date;\n}\n\n/**\n * Check if a date is within the last month (not expired).\n */\nfunction isDateWithinMonth(date: Date): boolean {\n const now = new Date();\n const oneMonthAgo = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate());\n return date >= oneMonthAgo;\n}\n\ninterface DisableStatus {\n hasDisable: boolean;\n isValid: boolean;\n isExpired: boolean;\n date?: string;\n}\n\n/**\n * Check if a file has a valid, non-expired disable comment at the top (within first 5 lines).\n * Returns status object with details about the disable comment.\n */\n// webpieces-disable max-lines-new-methods -- Date validation logic requires checking multiple conditions\nfunction checkDisableComment(content: string): DisableStatus {\n const lines = content.split('\\n').slice(0, 5);\n\n for (const line of lines) {\n if (line.includes('webpieces-disable') && line.includes('max-lines-modified-files')) {\n // Found disable comment, now check for date\n // Format: // webpieces-disable max-lines-modified-files yyyy/mm/dd -- reason\n const dateMatch = line.match(/max-lines-modified-files\\s+(\\d{4}\\/\\d{2}\\/\\d{2}|XXXX\\/XX\\/XX)/);\n\n if (!dateMatch) {\n // No date found - invalid disable comment\n return { hasDisable: true, isValid: false, isExpired: false };\n }\n\n const dateStr = dateMatch[1];\n\n // Secret permanent disable\n if (dateStr === 'XXXX/XX/XX') {\n return { hasDisable: true, isValid: true, isExpired: false, date: dateStr };\n }\n\n const date = parseDisableDate(dateStr);\n if (!date) {\n // Invalid date format\n return { hasDisable: true, isValid: false, isExpired: false, date: dateStr };\n }\n\n if (!isDateWithinMonth(date)) {\n // Date is expired (older than 1 month)\n return { hasDisable: true, isValid: true, isExpired: true, date: dateStr };\n }\n\n // Valid and not expired\n return { hasDisable: true, isValid: true, isExpired: false, date: dateStr };\n }\n }\n\n return { hasDisable: false, isValid: false, isExpired: false };\n}\n\n/**\n * Count lines in a file and check for violations\n */\n// webpieces-disable max-lines-new-methods -- File iteration with disable checking logic\nfunction findViolations(workspaceRoot: string, changedFiles: string[], limit: number, disableAllowed: boolean): FileViolation[] {\n const violations: FileViolation[] = [];\n\n for (const file of changedFiles) {\n const fullPath = path.join(workspaceRoot, file);\n\n if (!fs.existsSync(fullPath)) continue;\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lineCount = content.split('\\n').length;\n\n // Skip files under the limit\n if (lineCount <= limit) continue;\n\n // When disableAllowed is false, ignore all disable comments\n if (!disableAllowed) {\n violations.push({ file, lines: lineCount });\n continue;\n }\n\n // Check for disable comment\n const disableStatus = checkDisableComment(content);\n\n if (disableStatus.hasDisable) {\n if (disableStatus.isValid && !disableStatus.isExpired) {\n // Valid, non-expired disable - skip this file\n continue;\n }\n\n if (disableStatus.isExpired) {\n // Expired disable - report as violation with expired info\n violations.push({\n file,\n lines: lineCount,\n expiredDisable: true,\n expiredDate: disableStatus.date,\n });\n continue;\n }\n\n // Invalid disable (missing/bad date) - fall through to report as violation\n }\n\n violations.push({\n file,\n lines: lineCount,\n });\n }\n\n return violations;\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 * Get today's date in yyyy/mm/dd format for error messages\n */\nfunction getTodayDateString(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n return `${year}/${month}/${day}`;\n}\n\n/**\n * Report violations to console\n */\n// webpieces-disable max-lines-new-methods -- Error output formatting with multiple message sections\nfunction reportViolations(violations: FileViolation[], limit: number, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c YOU MUST FIX THIS AND NOT be more than ' + limit + ' lines of code per file');\n console.error(' as it slows down IDEs AND is VERY VERY EASY to refactor.');\n console.error('');\n console.error('\\ud83d\\udcda With stateless systems + dependency injection, refactor is trivial:');\n console.error(' Pick a method or a few and move to new class XXXXX, then inject XXXXX');\n console.error(' into all users of those methods via the constructor.');\n console.error(' Delete those methods from original class.');\n console.error(' 99% of files can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error('\\u26a0\\ufe0f *** READ tmp/webpieces/webpieces.filesize.md for detailed guidance on how to fix this easily *** \\u26a0\\ufe0f');\n console.error('');\n\n for (const v of violations) {\n if (v.expiredDisable) {\n console.error(` \\u274c ${v.file} (${v.lines} lines, max: ${limit})`);\n console.error(` \\u23f0 EXPIRED DISABLE: Your disable comment dated ${v.expiredDate} has expired (>1 month old).`);\n console.error(` You must either FIX the file or UPDATE the date to get another month.`);\n } else {\n console.error(` \\u274c ${v.file} (${v.lines} lines, max: ${limit})`);\n }\n }\n console.error('');\n\n // Only show escape hatch instructions when disableAllowed is true\n if (disableAllowed) {\n console.error(' You can disable this error, but you will be forced to fix again in 1 month');\n console.error(' since 99% of files can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error(' Use escape with DATE (expires in 1 month):');\n console.error(` // webpieces-disable max-lines-modified-files ${getTodayDateString()} -- [your reason]`);\n console.error('');\n } else {\n console.error(' \\u26a0\\ufe0f disableAllowed is false - disable comments are NOT allowed.');\n console.error(' You MUST refactor to reduce file size.');\n console.error('');\n }\n}\n\nexport default async function runExecutor(\n options: ValidateModifiedFilesOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n const workspaceRoot = context.root;\n const limit = options.limit ?? 900;\n const mode: FileMaxLimitMode = options.mode ?? 'MODIFIED_FILES';\n const disableAllowed = options.disableAllowed ?? true;\n\n // Skip validation entirely if mode is OFF\n if (mode === 'OFF') {\n console.log('\\n\\u23ed\\ufe0f Skipping modified files validation (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n // If NX_HEAD is set (via nx affected --head=X), use it; otherwise compare to working tree\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\\u23ed\\ufe0f Skipping modified files validation (could not detect base branch)');\n console.log(' To run explicitly: nx affected --target=validate-modified-files --base=origin/main');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating Modified File Sizes (auto-detected base)\\n');\n } else {\n console.log('\\n\\ud83d\\udccf Validating Modified File Sizes\\n');\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log(` Mode: ${mode}`);\n console.log(` Max lines for modified files: ${limit}`);\n console.log(` Disable allowed: ${disableAllowed}${!disableAllowed ? ' (no escape hatch)' : ''}`);\n console.log('');\n\n try {\n const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);\n\n if (changedFiles.length === 0) {\n console.log('\\u2705 No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`\\ud83d\\udcc2 Checking ${changedFiles.length} changed file(s)...`);\n\n const violations = findViolations(workspaceRoot, changedFiles, limit, disableAllowed);\n\n if (violations.length === 0) {\n console.log('\\u2705 All modified files are under ' + limit + ' lines');\n return { success: true };\n }\n\n writeTmpInstructions(workspaceRoot);\n reportViolations(violations, limit, disableAllowed);\n return { success: false };\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n console.error('\\u274c Modified files validation failed:', error.message);\n return { success: false };\n }\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/dev-config/architecture/executors/validate-modified-files/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Modified Files Executor\n *\n * Validates that modified files don't exceed a maximum line count (default 900).\n * This encourages keeping files small and focused - when you touch a file,\n * you must bring it under the limit.\n *\n * Usage:\n * nx affected --target=validate-modified-files --base=origin/main\n *\n * Escape hatch: Add webpieces-disable max-lines-modified-files comment with date and justification\n * Format: // webpieces-disable max-lines-modified-files 2025/01/15 -- [reason]\n * The disable expires after 1 month from the date specified.\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nexport type FileMaxLimitMode = 'OFF' | 'MODIFIED_FILES';\n\nexport interface ValidateModifiedFilesOptions {\n limit?: number;\n mode?: FileMaxLimitMode;\n disableAllowed?: boolean;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\ninterface FileViolation {\n file: string;\n lines: number;\n expiredDisable?: boolean;\n expiredDate?: string;\n}\n\nconst TMP_DIR = 'tmp/webpieces';\nconst TMP_MD_FILE = 'webpieces.filesize.md';\n\nconst FILESIZE_DOC_CONTENT = `# AI Agent Instructions: File Too Long\n\n**READ THIS FILE to fix files that are too long**\n\n## Core Principle\n\nWith **stateless systems + dependency injection, refactor is trivial**.\nPick a method or a few and move to new class XXXXX, then inject XXXXX\ninto all users of those methods via the constructor.\nDelete those methods from original class.\n\n**99% of files can be less than the configured max lines of code.**\n\nFiles should contain a SINGLE COHESIVE UNIT.\n- One class per file (Java convention)\n- If class is too large, extract child responsibilities\n- Use dependency injection to compose functionality\n\n## Command: Reduce File Size\n\n### Step 1: Check for Multiple Classes\nIf the file contains multiple classes, **SEPARATE each class into its own file**.\n\n\\`\\`\\`typescript\n// BAD: UserController.ts (multiple classes)\nexport class UserController { /* ... */ }\nexport class UserValidator { /* ... */ }\nexport class UserNotifier { /* ... */ }\n\n// GOOD: Three separate files\n// UserController.ts\nexport class UserController { /* ... */ }\n\n// UserValidator.ts\nexport class UserValidator { /* ... */ }\n\n// UserNotifier.ts\nexport class UserNotifier { /* ... */ }\n\\`\\`\\`\n\n### Step 2: Extract Child Responsibilities (if single class is too large)\n\n#### Pattern: Create New Service Class with Dependency Injection\n\n\\`\\`\\`typescript\n// BAD: UserController.ts (800 lines, single class)\n@provideSingleton()\n@Controller()\nexport class UserController {\n // 200 lines: CRUD operations\n // 300 lines: validation logic\n // 200 lines: notification logic\n // 100 lines: analytics logic\n}\n\n// GOOD: Extract validation service\n// 1. Create UserValidationService.ts\n@provideSingleton()\nexport class UserValidationService {\n validateUserData(data: UserData): ValidationResult {\n // 300 lines of validation logic moved here\n }\n\n validateEmail(email: string): boolean { /* ... */ }\n validatePassword(password: string): boolean { /* ... */ }\n}\n\n// 2. Inject into UserController.ts\n@provideSingleton()\n@Controller()\nexport class UserController {\n constructor(\n @inject(TYPES.UserValidationService)\n private validator: UserValidationService\n ) {}\n\n async createUser(data: UserData): Promise<User> {\n const validation = this.validator.validateUserData(data);\n if (!validation.isValid) {\n throw new ValidationError(validation.errors);\n }\n // ... rest of logic\n }\n}\n\\`\\`\\`\n\n## AI Agent Action Steps\n\n1. **ANALYZE** the file structure:\n - Count classes (if >1, separate immediately)\n - Identify logical responsibilities within single class\n\n2. **IDENTIFY** \"child code\" to extract:\n - Validation logic -> ValidationService\n - Notification logic -> NotificationService\n - Data transformation -> TransformerService\n - External API calls -> ApiService\n - Business rules -> RulesEngine\n\n3. **CREATE** new service file(s):\n - Start with temporary name: \\`XXXX.ts\\` or \\`ChildService.ts\\`\n - Add \\`@provideSingleton()\\` decorator\n - Move child methods to new class\n\n4. **UPDATE** dependency injection:\n - Add to \\`TYPES\\` constants (if using symbol-based DI)\n - Inject new service into original class constructor\n - Replace direct method calls with \\`this.serviceName.method()\\`\n\n5. **RENAME** extracted file:\n - Read the extracted code to understand its purpose\n - Rename \\`XXXX.ts\\` to logical name (e.g., \\`UserValidationService.ts\\`)\n\n6. **VERIFY** file sizes:\n - Original file should now be under the limit\n - Each extracted file should be under the limit\n - If still too large, extract more services\n\n## Examples of Child Responsibilities to Extract\n\n| If File Contains | Extract To | Pattern |\n|-----------------|------------|---------|\n| Validation logic (200+ lines) | \\`XValidator.ts\\` or \\`XValidationService.ts\\` | Singleton service |\n| Notification logic (150+ lines) | \\`XNotifier.ts\\` or \\`XNotificationService.ts\\` | Singleton service |\n| Data transformation (200+ lines) | \\`XTransformer.ts\\` | Singleton service |\n| External API calls (200+ lines) | \\`XApiClient.ts\\` | Singleton service |\n| Complex business rules (300+ lines) | \\`XRulesEngine.ts\\` | Singleton service |\n| Database queries (200+ lines) | \\`XRepository.ts\\` | Singleton service |\n\n## WebPieces Dependency Injection Pattern\n\n\\`\\`\\`typescript\n// 1. Define service with @provideSingleton\nimport { provideSingleton } from '@webpieces/http-routing';\n\n@provideSingleton()\nexport class MyService {\n doSomething(): void { /* ... */ }\n}\n\n// 2. Inject into consumer\nimport { inject } from 'inversify';\nimport { TYPES } from './types';\n\n@provideSingleton()\n@Controller()\nexport class MyController {\n constructor(\n @inject(TYPES.MyService) private service: MyService\n ) {}\n}\n\\`\\`\\`\n\n## Escape Hatch\n\nIf refactoring is genuinely not feasible (generated files, complex algorithms, etc.),\nadd a disable comment at the TOP of the file (within first 5 lines) with a DATE:\n\n\\`\\`\\`typescript\n// webpieces-disable max-lines-modified-files 2025/01/15 -- Complex generated file, refactoring would break generation\n\\`\\`\\`\n\n**IMPORTANT**: The date format is yyyy/mm/dd. The disable will EXPIRE after 1 month from this date.\nAfter expiration, you must either fix the file or update the date to get another month.\nThis ensures that disable comments are reviewed periodically.\n\nRemember: Find the \"child code\" and pull it down into a new class. Once moved, the code's purpose becomes clear, making it easy to rename to a logical name.\n`;\n\n/**\n * Write the instructions documentation to tmp directory\n */\nfunction writeTmpInstructions(workspaceRoot: string): string {\n const tmpDir = path.join(workspaceRoot, TMP_DIR);\n const mdPath = path.join(tmpDir, TMP_MD_FILE);\n\n fs.mkdirSync(tmpDir, { recursive: true });\n fs.writeFileSync(mdPath, FILESIZE_DOC_CONTENT);\n\n return mdPath;\n}\n\n/**\n * Get changed TypeScript files between base and head (or working tree if head not specified).\n * Uses `git diff base [head]` to match what `nx affected` does.\n * When head is NOT specified, also includes untracked files (matching nx affected behavior).\n */\nfunction getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: string): string[] {\n try {\n // If head is specified, diff base to head; otherwise diff base to working tree\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 // When comparing to working tree (no head specified), also include untracked files\n // This matches what nx affected does: \"All modified files not yet committed or tracked will also be added\"\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 // Merge and dedupe\n const allFiles = new Set([...changedFiles, ...untrackedFiles]);\n return Array.from(allFiles);\n } catch {\n // If ls-files fails, just return the changed files\n return changedFiles;\n }\n }\n\n return changedFiles;\n } catch {\n return [];\n }\n}\n\n/**\n * Parse a date string in yyyy/mm/dd format and return a Date object.\n * Returns null if the format is invalid.\n */\nfunction parseDisableDate(dateStr: string): Date | null {\n // Match yyyy/mm/dd format\n const match = dateStr.match(/^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/);\n if (!match) return null;\n\n const year = parseInt(match[1], 10);\n const month = parseInt(match[2], 10) - 1; // JS months are 0-indexed\n const day = parseInt(match[3], 10);\n\n const date = new Date(year, month, day);\n\n // Validate the date is valid (e.g., not Feb 30)\n if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {\n return null;\n }\n\n return date;\n}\n\n/**\n * Check if a date is within the last month (not expired).\n */\nfunction isDateWithinMonth(date: Date): boolean {\n const now = new Date();\n const oneMonthAgo = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate());\n return date >= oneMonthAgo;\n}\n\ninterface DisableStatus {\n hasDisable: boolean;\n isValid: boolean;\n isExpired: boolean;\n date?: string;\n}\n\n/**\n * Check if a file has a valid, non-expired disable comment at the top (within first 5 lines).\n * Returns status object with details about the disable comment.\n */\n// webpieces-disable max-lines-new-methods -- Date validation logic requires checking multiple conditions\nfunction checkDisableComment(content: string): DisableStatus {\n const lines = content.split('\\n').slice(0, 5);\n\n for (const line of lines) {\n if (line.includes('webpieces-disable') && line.includes('max-lines-modified-files')) {\n // Found disable comment, now check for date\n // Format: // webpieces-disable max-lines-modified-files yyyy/mm/dd -- reason\n const dateMatch = line.match(/max-lines-modified-files\\s+(\\d{4}\\/\\d{2}\\/\\d{2}|XXXX\\/XX\\/XX)/);\n\n if (!dateMatch) {\n // No date found - invalid disable comment\n return { hasDisable: true, isValid: false, isExpired: false };\n }\n\n const dateStr = dateMatch[1];\n\n // Secret permanent disable\n if (dateStr === 'XXXX/XX/XX') {\n return { hasDisable: true, isValid: true, isExpired: false, date: dateStr };\n }\n\n const date = parseDisableDate(dateStr);\n if (!date) {\n // Invalid date format\n return { hasDisable: true, isValid: false, isExpired: false, date: dateStr };\n }\n\n if (!isDateWithinMonth(date)) {\n // Date is expired (older than 1 month)\n return { hasDisable: true, isValid: true, isExpired: true, date: dateStr };\n }\n\n // Valid and not expired\n return { hasDisable: true, isValid: true, isExpired: false, date: dateStr };\n }\n }\n\n return { hasDisable: false, isValid: false, isExpired: false };\n}\n\n/**\n * Count lines in a file and check for violations\n */\n// webpieces-disable max-lines-new-methods -- File iteration with disable checking logic\nfunction findViolations(workspaceRoot: string, changedFiles: string[], limit: number, disableAllowed: boolean): FileViolation[] {\n const violations: FileViolation[] = [];\n\n for (const file of changedFiles) {\n const fullPath = path.join(workspaceRoot, file);\n\n if (!fs.existsSync(fullPath)) continue;\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lineCount = content.split('\\n').length;\n\n // Skip files under the limit\n if (lineCount <= limit) continue;\n\n // When disableAllowed is false, ignore all disable comments\n if (!disableAllowed) {\n violations.push({ file, lines: lineCount });\n continue;\n }\n\n // Check for disable comment\n const disableStatus = checkDisableComment(content);\n\n if (disableStatus.hasDisable) {\n if (disableStatus.isValid && !disableStatus.isExpired) {\n // Valid, non-expired disable - skip this file\n continue;\n }\n\n if (disableStatus.isExpired) {\n // Expired disable - report as violation with expired info\n violations.push({\n file,\n lines: lineCount,\n expiredDisable: true,\n expiredDate: disableStatus.date,\n });\n continue;\n }\n\n // Invalid disable (missing/bad date) - fall through to report as violation\n }\n\n violations.push({\n file,\n lines: lineCount,\n });\n }\n\n return violations;\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 * Get today's date in yyyy/mm/dd format for error messages\n */\nfunction getTodayDateString(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n return `${year}/${month}/${day}`;\n}\n\n/**\n * Report violations to console\n */\n// webpieces-disable max-lines-new-methods -- Error output formatting with multiple message sections\nfunction reportViolations(violations: FileViolation[], limit: number, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c YOU MUST FIX THIS AND NOT be more than ' + limit + ' lines of code per file');\n console.error(' as it slows down IDEs AND is VERY VERY EASY to refactor.');\n console.error('');\n console.error('\\ud83d\\udcda With stateless systems + dependency injection, refactor is trivial:');\n console.error(' Pick a method or a few and move to new class XXXXX, then inject XXXXX');\n console.error(' into all users of those methods via the constructor.');\n console.error(' Delete those methods from original class.');\n console.error(' 99% of files can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error('\\u26a0\\ufe0f *** READ tmp/webpieces/webpieces.filesize.md for detailed guidance on how to fix this easily *** \\u26a0\\ufe0f');\n console.error('');\n\n for (const v of violations) {\n if (v.expiredDisable) {\n console.error(` \\u274c ${v.file} (${v.lines} lines, max: ${limit})`);\n console.error(` \\u23f0 EXPIRED DISABLE: Your disable comment dated ${v.expiredDate} has expired (>1 month old).`);\n console.error(` You must either FIX the file or UPDATE the date to get another month.`);\n } else {\n console.error(` \\u274c ${v.file} (${v.lines} lines, max: ${limit})`);\n }\n }\n console.error('');\n\n // Only show escape hatch instructions when disableAllowed is true\n if (disableAllowed) {\n console.error(' You can disable this error, but you will be forced to fix again in 1 month');\n console.error(' since 99% of files can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error(' Use escape with DATE (expires in 1 month):');\n console.error(` // webpieces-disable max-lines-modified-files ${getTodayDateString()} -- [your reason]`);\n console.error('');\n } else {\n console.error(' \\u26a0\\ufe0f disableAllowed is false - disable comments are NOT allowed.');\n console.error(' This rule must be met and cannot be disabled since nx.json disableAllowed is set to false.');\n console.error(' You MUST refactor to reduce file size.');\n console.error('');\n console.error(' For a major refactor, a human can add \"ignoreModifiedUntilEpoch\" to nx.json validate-code options.');\n console.error(' This is an expiry timestamp (epoch ms) for when we start forcing everyone to meet size rules again.');\n console.error(' Sometimes for speed, we allow files to expand during a refactor and over time,');\n console.error(' each PR reduces files as they get touched.');\n console.error(' AI agents should NOT add ignoreModifiedUntilEpoch - ask a human to do it.');\n console.error('');\n }\n}\n\nexport default async function runExecutor(\n options: ValidateModifiedFilesOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n const workspaceRoot = context.root;\n const limit = options.limit ?? 900;\n const mode: FileMaxLimitMode = options.mode ?? 'MODIFIED_FILES';\n const disableAllowed = options.disableAllowed ?? true;\n\n // Skip validation entirely if mode is OFF\n if (mode === 'OFF') {\n console.log('\\n\\u23ed\\ufe0f Skipping modified files validation (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n // If NX_HEAD is set (via nx affected --head=X), use it; otherwise compare to working tree\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\\u23ed\\ufe0f Skipping modified files validation (could not detect base branch)');\n console.log(' To run explicitly: nx affected --target=validate-modified-files --base=origin/main');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating Modified File Sizes (auto-detected base)\\n');\n } else {\n console.log('\\n\\ud83d\\udccf Validating Modified File Sizes\\n');\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log(` Mode: ${mode}`);\n console.log(` Max lines for modified files: ${limit}`);\n console.log(` Disable allowed: ${disableAllowed}${!disableAllowed ? ' (no escape hatch)' : ''}`);\n console.log('');\n\n try {\n const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);\n\n if (changedFiles.length === 0) {\n console.log('\\u2705 No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`\\ud83d\\udcc2 Checking ${changedFiles.length} changed file(s)...`);\n\n const violations = findViolations(workspaceRoot, changedFiles, limit, disableAllowed);\n\n if (violations.length === 0) {\n console.log('\\u2705 All modified files are under ' + limit + ' lines');\n return { success: true };\n }\n\n writeTmpInstructions(workspaceRoot);\n reportViolations(violations, limit, disableAllowed);\n return { success: false };\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n console.error('\\u274c Modified files validation failed:', error.message);\n return { success: false };\n }\n}\n"]}
@@ -489,8 +489,15 @@ function reportViolations(violations: FileViolation[], limit: number, disableAll
489
489
  console.error('');
490
490
  } else {
491
491
  console.error(' \u26a0\ufe0f disableAllowed is false - disable comments are NOT allowed.');
492
+ console.error(' This rule must be met and cannot be disabled since nx.json disableAllowed is set to false.');
492
493
  console.error(' You MUST refactor to reduce file size.');
493
494
  console.error('');
495
+ console.error(' For a major refactor, a human can add "ignoreModifiedUntilEpoch" to nx.json validate-code options.');
496
+ console.error(' This is an expiry timestamp (epoch ms) for when we start forcing everyone to meet size rules again.');
497
+ console.error(' Sometimes for speed, we allow files to expand during a refactor and over time,');
498
+ console.error(' each PR reduces files as they get touched.');
499
+ console.error(' AI agents should NOT add ignoreModifiedUntilEpoch - ask a human to do it.');
500
+ console.error('');
494
501
  }
495
502
  }
496
503
 
@@ -625,8 +625,15 @@ function reportViolations(violations, limit, disableAllowed) {
625
625
  }
626
626
  else {
627
627
  console.error(' \u26a0\ufe0f disableAllowed is false - disable comments are NOT allowed.');
628
+ console.error(' This rule must be met and cannot be disabled since nx.json disableAllowed is set to false.');
628
629
  console.error(' You MUST refactor to reduce method size.');
629
630
  console.error('');
631
+ console.error(' For a major refactor, a human can add "ignoreModifiedUntilEpoch" to nx.json validate-code options.');
632
+ console.error(' This is an expiry timestamp (epoch ms) for when we start forcing everyone to meet size rules again.');
633
+ console.error(' Sometimes for speed, we allow methods to expand during a refactor and over time,');
634
+ console.error(' each PR reduces methods as they get touched.');
635
+ console.error(' AI agents should NOT add ignoreModifiedUntilEpoch - ask a human to do it.');
636
+ console.error('');
630
637
  }
631
638
  }
632
639
  async function runExecutor(options, context) {
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/dev-config/architecture/executors/validate-modified-methods/executor.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;AA+rBH,8BAmEC;;AA/vBD,iDAAyC;AACzC,+CAAyB;AACzB,mDAA6B;AAC7B,uDAAiC;AAuBjC,MAAM,OAAO,GAAG,eAAe,CAAC;AAChC,MAAM,WAAW,GAAG,yBAAyB,CAAC;AAE9C,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2H9B,CAAC;AAEF;;GAEG;AACH,SAAS,oBAAoB,CAAC,aAAqB;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAE9C,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IAEjD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,SAAS,yBAAyB,CAAC,aAAqB,EAAE,IAAY,EAAE,IAAa;IACjF,IAAI,CAAC;QACD,+EAA+E;QAC/E,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACnD,MAAM,MAAM,GAAG,IAAA,wBAAQ,EAAC,wBAAwB,UAAU,oBAAoB,EAAE;YAC5E,GAAG,EAAE,aAAa;YAClB,QAAQ,EAAE,OAAO;SACpB,CAAC,CAAC;QACH,MAAM,YAAY,GAAG,MAAM;aACtB,IAAI,EAAE;aACN,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;QAE5E,mFAAmF;QACnF,2GAA2G;QAC3G,IAAI,CAAC,IAAI,EAAE,CAAC;YACR,IAAI,CAAC;gBACD,MAAM,eAAe,GAAG,IAAA,wBAAQ,EAAC,yDAAyD,EAAE;oBACxF,GAAG,EAAE,aAAa;oBAClB,QAAQ,EAAE,OAAO;iBACpB,CAAC,CAAC;gBACH,MAAM,cAAc,GAAG,eAAe;qBACjC,IAAI,EAAE;qBACN,KAAK,CAAC,IAAI,CAAC;qBACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;gBAC5E,mBAAmB;gBACnB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,YAAY,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC;gBAC/D,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACL,mDAAmD;gBACnD,OAAO,YAAY,CAAC;YACxB,CAAC;QACL,CAAC;QAED,OAAO,YAAY,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,EAAE,CAAC;IACd,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAAC,aAAqB,EAAE,IAAY,EAAE,IAAY,EAAE,IAAa;IACjF,IAAI,CAAC;QACD,+EAA+E;QAC/E,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACnD,MAAM,IAAI,GAAG,IAAA,wBAAQ,EAAC,YAAY,UAAU,QAAQ,IAAI,GAAG,EAAE;YACzD,GAAG,EAAE,aAAa;YAClB,QAAQ,EAAE,OAAO;SACpB,CAAC,CAAC;QAEH,wFAAwF;QACxF,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;YAChD,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1B,6BAA6B;gBAC7B,MAAM,WAAW,GAAG,IAAA,wBAAQ,EAAC,6CAA6C,IAAI,GAAG,EAAE;oBAC/E,GAAG,EAAE,aAAa;oBAClB,QAAQ,EAAE,OAAO;iBACpB,CAAC,CAAC,IAAI,EAAE,CAAC;gBAEV,IAAI,WAAW,EAAE,CAAC;oBACd,yDAAyD;oBACzD,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;oBACnD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAClC,qDAAqD;oBACrD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACtD,CAAC;YACL,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,EAAE,CAAC;IACd,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,yFAAyF;AACzF,SAAS,6BAA6B,CAAC,WAAmB;IACtD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEtC,sEAAsE;IACtE,MAAM,QAAQ,GAAG;QACb,qEAAqE;QACrE,wDAAwD;QACxD,4CAA4C;QAC5C,iEAAiE;QACjE,mDAAmD;QACnD,uEAAuE;QACvE,oHAAoH;QACpH,iFAAiF;KACpF,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAClD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBAClC,IAAI,KAAK,EAAE,CAAC;oBACR,sDAAsD;oBACtD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;oBAC5B,IAAI,UAAU,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;wBAC/F,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;oBAC/B,CAAC;oBACD,MAAM;gBACV,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,UAAU,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAAC,WAAmB;IAC9C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IACvC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEtC,IAAI,cAAc,GAAG,CAAC,CAAC;IAEvB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,iEAAiE;QACjE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACtE,IAAI,SAAS,EAAE,CAAC;YACZ,cAAc,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC5C,SAAS;QACb,CAAC;QAED,IAAI,cAAc,KAAK,CAAC;YAAE,SAAS;QAEnC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAClD,aAAa;YACb,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YACjC,cAAc,EAAE,CAAC;QACrB,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YACzD,oDAAoD;QACxD,CAAC;aAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,2BAA2B;YAC3B,cAAc,EAAE,CAAC;QACrB,CAAC;IACL,CAAC;IAED,OAAO,YAAY,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,OAAe;IACrC,0BAA0B;IAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAC3D,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,0BAA0B;IACpE,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEnC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAExC,gDAAgD;IAChD,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,GAAG,EAAE,CAAC;QACrF,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,IAAU;IACjC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACnF,OAAO,IAAI,IAAI,WAAW,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB;IACvB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC1D,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACnD,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;AACrC,CAAC;AAQD;;;;;;GAMG;AACH,uGAAuG;AACvG,SAAS,cAAc,CAAC,KAAe,EAAE,UAAkB;IACvD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;IAC/C,KAAK,IAAI,CAAC,GAAG,UAAU,GAAG,CAAC,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QAChD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAClF,MAAM;QACV,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACrC,IAAI,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC;gBACtC,0DAA0D;gBAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;gBAExF,IAAI,CAAC,SAAS,EAAE,CAAC;oBACb,6CAA6C;oBAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;gBAC9D,CAAC;gBAED,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;gBAE7B,2BAA2B;gBAC3B,IAAI,OAAO,KAAK,YAAY,EAAE,CAAC;oBAC3B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;gBAC7D,CAAC;gBAED,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBACvC,IAAI,CAAC,IAAI,EAAE,CAAC;oBACR,yCAAyC;oBACzC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;gBAC5D,CAAC;gBAED,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC3B,uCAAuC;oBACvC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;gBAC5D,CAAC;gBAED,wBAAwB;gBACxB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;YAC7D,CAAC;YACD,IAAI,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;gBACzC,6DAA6D;gBAC7D,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,4DAA4D,CAAC,CAAC;gBAE3F,IAAI,CAAC,SAAS,EAAE,CAAC;oBACb,6CAA6C;oBAC7C,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;gBAClE,CAAC;gBAED,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;gBAE7B,2BAA2B;gBAC3B,IAAI,OAAO,KAAK,YAAY,EAAE,CAAC;oBAC3B,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;gBACjE,CAAC;gBAED,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBACvC,IAAI,CAAC,IAAI,EAAE,CAAC;oBACR,yCAAyC;oBACzC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;gBAChE,CAAC;gBAED,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC3B,uCAAuC;oBACvC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;gBAChE,CAAC;gBAED,wBAAwB;gBACxB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;YACjE,CAAC;QACL,CAAC;IACL,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAC9C,CAAC;AAUD;;GAEG;AACH,4FAA4F;AAC5F,SAAS,iBAAiB,CAAC,QAAgB,EAAE,aAAqB;IAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IACpD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IAExC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,UAAU,GAAG,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAExF,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,uGAAuG;IACvG,SAAS,KAAK,CAAC,IAAa;QACxB,IAAI,UAA8B,CAAC;QACnC,IAAI,SAA6B,CAAC;QAClC,IAAI,OAA2B,CAAC;QAEhC,IAAI,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5C,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAC3C,MAAM,KAAK,GAAG,UAAU,CAAC,6BAA6B,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxE,MAAM,GAAG,GAAG,UAAU,CAAC,6BAA6B,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YACpE,SAAS,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;YAC3B,OAAO,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACrD,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAC3C,MAAM,KAAK,GAAG,UAAU,CAAC,6BAA6B,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxE,MAAM,GAAG,GAAG,UAAU,CAAC,6BAA6B,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YACpE,SAAS,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;YAC3B,OAAO,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,IAAI,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7E,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;gBAClD,MAAM,KAAK,GAAG,UAAU,CAAC,6BAA6B,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACxE,MAAM,GAAG,GAAG,UAAU,CAAC,6BAA6B,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;gBACpE,SAAS,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;gBAC3B,OAAO,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;YAC3B,CAAC;QACL,CAAC;QAED,IAAI,UAAU,IAAI,SAAS,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YACjE,OAAO,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,OAAO;gBAChB,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,CAAC;gBAC9B,WAAW,EAAE,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC;aACpD,CAAC,CAAC;QACP,CAAC;QAED,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,CAAC;IAClB,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,MAAkB,EAAE,kBAA+B;IACzE,KAAK,IAAI,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;QAC1D,IAAI,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IAClD,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,uBAAuB,CAAC,IAAY,EAAE,MAAkB,EAAE,cAAuB;IACtF,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC;IAE/E,IAAI,CAAC,cAAc,EAAE,CAAC;QAClB,kGAAkG;QAClG,IAAI,WAAW,KAAK,MAAM;YAAE,OAAO,IAAI,CAAC;QACxC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;IACrF,CAAC;IAED,IAAI,WAAW,KAAK,MAAM,IAAI,SAAS,EAAE,CAAC;QACtC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;IACrI,CAAC;IACD,IAAI,WAAW,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IAE5C,IAAI,SAAS,EAAE,CAAC;QACZ,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;IACrI,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;AACrF,CAAC;AAED;;GAEG;AACH,SAAS,4BAA4B,CAAC,IAAY,EAAE,MAAkB,EAAE,cAAuB;IAC3F,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC;IAE/E,IAAI,CAAC,cAAc,EAAE,CAAC;QAClB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;IACrF,CAAC;IACD,IAAI,WAAW,KAAK,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACvC,6BAA6B;QAC7B,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,IAAI,WAAW,KAAK,MAAM,IAAI,SAAS,EAAE,CAAC;QACtC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;IACrI,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;AACrF,CAAC;AAED;;;GAGG;AACH,SAAS,cAAc,CACnB,aAAqB,EACrB,YAAsB,EACtB,IAAY,EACZ,KAAa,EACb,cAAuB,EACvB,IAAa;IAEb,MAAM,UAAU,GAAsB,EAAE,CAAC;IAEzC,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,WAAW,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI;YAAE,SAAS;QAEpB,MAAM,cAAc,GAAG,6BAA6B,CAAC,IAAI,CAAC,CAAC;QAC3D,MAAM,kBAAkB,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QACvD,IAAI,kBAAkB,CAAC,IAAI,KAAK,CAAC;YAAE,SAAS;QAE5C,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QAEvD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC3B,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC;YAE5D,oFAAoF;YACpF,IAAI,cAAc,IAAI,WAAW,KAAK,MAAM,IAAI,CAAC,SAAS;gBAAE,SAAS;YACrE,IAAI,MAAM,CAAC,KAAK,IAAI,KAAK;gBAAE,SAAS;YAEpC,MAAM,WAAW,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAEpD,IAAI,WAAW,EAAE,CAAC;gBACd,MAAM,SAAS,GAAG,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;gBACxE,IAAI,SAAS;oBAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC9C,CAAC;iBAAM,IAAI,gBAAgB,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAAE,CAAC;gBACtD,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;gBAC7E,IAAI,SAAS;oBAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC9C,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,UAAU,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,aAAqB;IACrC,IAAI,CAAC;QACD,MAAM,SAAS,GAAG,IAAA,wBAAQ,EAAC,iCAAiC,EAAE;YAC1D,GAAG,EAAE,aAAa;YAClB,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAClC,CAAC,CAAC,IAAI,EAAE,CAAC;QAEV,IAAI,SAAS,EAAE,CAAC;YACZ,OAAO,SAAS,CAAC;QACrB,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACL,IAAI,CAAC;YACD,MAAM,SAAS,GAAG,IAAA,wBAAQ,EAAC,0BAA0B,EAAE;gBACnD,GAAG,EAAE,aAAa;gBAClB,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;aAClC,CAAC,CAAC,IAAI,EAAE,CAAC;YAEV,IAAI,SAAS,EAAE,CAAC;gBACZ,OAAO,SAAS,CAAC;YACrB,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACL,SAAS;QACb,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,oGAAoG;AACpG,SAAS,gBAAgB,CAAC,UAA6B,EAAE,KAAa,EAAE,cAAuB;IAC3F,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,iCAAiC,GAAG,KAAK,GAAG,SAAS,CAAC,CAAC;IACrE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,iEAAiE,GAAG,KAAK,GAAG,SAAS,CAAC,CAAC;IACrG,OAAO,CAAC,KAAK,CAAC,8EAA8E,CAAC,CAAC;IAC9F,OAAO,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;IAC7E,OAAO,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAC;IAClF,OAAO,CAAC,KAAK,CAAC,qGAAqG,CAAC,CAAC;IACrH,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CACT,+HAA+H,CAClI,CAAC;IACF,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAElB,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAC9C,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,KAAK,gBAAgB,KAAK,GAAG,CAAC,CAAC;YAChF,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC,WAAW,IAAI,SAAS,8BAA8B,CAAC,CAAC;YACnI,OAAO,CAAC,KAAK,CAAC,iFAAiF,CAAC,CAAC;QACrG,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAC9C,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,KAAK,gBAAgB,KAAK,GAAG,CAAC,CAAC;QACpF,CAAC;IACL,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAElB,kEAAkE;IAClE,IAAI,cAAc,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,+EAA+E,CAAC,CAAC;QAC/F,OAAO,CAAC,KAAK,CAAC,2CAA2C,GAAG,KAAK,GAAG,iBAAiB,CAAC,CAAC;QACvF,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;QAC/D,OAAO,CAAC,KAAK,CAAC,8CAA8C,kBAAkB,EAAE,mBAAmB,CAAC,CAAC;QACrG,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACtB,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,KAAK,CAAC,8EAA8E,CAAC,CAAC;QAC9F,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAC7D,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACtB,CAAC;AACL,CAAC;AAEc,KAAK,UAAU,WAAW,CACrC,OAAuC,EACvC,OAAwB;IAExB,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IACnC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;IAClC,MAAM,IAAI,GAAuB,OAAO,CAAC,IAAI,IAAI,0BAA0B,CAAC;IAC5E,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC;IAEtD,0CAA0C;IAC1C,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAC;QAC/E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC7B,CAAC;IAED,0FAA0F;IAC1F,IAAI,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAEpC,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,IAAI,GAAG,UAAU,CAAC,aAAa,CAAC,IAAI,SAAS,CAAC;QAE9C,IAAI,CAAC,IAAI,EAAE,CAAC;YACR,OAAO,CAAC,GAAG,CAAC,oFAAoF,CAAC,CAAC;YAClG,OAAO,CAAC,GAAG,CAAC,yFAAyF,CAAC,CAAC;YACvG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC7B,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,wEAAwE,CAAC,CAAC;IAC1F,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI,6CAA6C,EAAE,CAAC,CAAC;IACjF,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,kCAAkC,KAAK,EAAE,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,uBAAuB,cAAc,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACnG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,IAAI,CAAC;QACD,MAAM,YAAY,GAAG,yBAAyB,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAE1E,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;YAClD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC7B,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,yBAAyB,YAAY,CAAC,MAAM,qBAAqB,CAAC,CAAC;QAE/E,MAAM,UAAU,GAAG,cAAc,CAAC,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC;QAElG,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,wCAAwC,GAAG,KAAK,GAAG,QAAQ,CAAC,CAAC;YACzE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC7B,CAAC;QAED,oBAAoB,CAAC,aAAa,CAAC,CAAC;QACpC,gBAAgB,CAAC,UAAU,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;QACpD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAClE,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;AACL,CAAC","sourcesContent":["/**\n * Validate Modified Methods Executor\n *\n * Validates that modified methods don't exceed a maximum line count (default 80).\n * This encourages gradual cleanup of legacy long methods - when you touch a method,\n * you must bring it under the limit.\n *\n * Combined with validate-new-methods, this creates a gradual\n * transition to cleaner code:\n * - New methods: must be under limit\n * - Modified methods: must be under limit (cleanup when touched)\n * - Untouched methods: no limit (legacy allowed)\n *\n * Usage:\n * nx affected --target=validate-modified-methods --base=origin/main\n *\n * Escape hatch: Add webpieces-disable max-lines-modified comment with date and justification\n * Format: // webpieces-disable max-lines-modified 2025/01/15 -- [reason]\n * The disable expires after 1 month from the date specified.\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 MethodMaxLimitMode = 'OFF' | 'NEW_METHODS' | 'NEW_AND_MODIFIED_METHODS' | 'MODIFIED_FILES';\n\nexport interface ValidateModifiedMethodsOptions {\n limit?: number;\n mode?: MethodMaxLimitMode;\n disableAllowed?: boolean;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\ninterface MethodViolation {\n file: string;\n methodName: string;\n line: number;\n lines: number;\n expiredDisable?: boolean;\n expiredDate?: string;\n}\n\nconst TMP_DIR = 'tmp/webpieces';\nconst TMP_MD_FILE = 'webpieces.methodsize.md';\n\nconst METHODSIZE_DOC_CONTENT = `# Instructions: Method Too Long\n\n## Requirement\n\n**~99% of the time**, you can stay under the \\`limit\\` from nx.json\nby extracting logical units into well-named methods.\nNearly all software can be written with methods under this size.\nTake the extra time to refactor - it's worth it for long-term maintainability.\n\n## The \"Table of Contents\" Principle\n\nGood code reads like a book's table of contents:\n- Chapter titles (method names) tell you WHAT happens\n- Reading chapter titles gives you the full story\n- You can dive into chapters (implementations) for details\n\n## Why Limit Method Sizes?\n\nMethods under reasonable limits are:\n- Easy to review in a single screen\n- Simple to understand without scrolling\n- Quick for AI to analyze and suggest improvements\n- More testable in isolation\n- Self-documenting through well-named extracted methods\n\n## Gradual Cleanup Strategy\n\nThis codebase uses a gradual cleanup approach:\n- **New methods**: Must be under \\`limit\\` from nx.json\n- **Modified methods**: Must be under \\`limit\\` from nx.json\n- **Untouched methods**: No limit (legacy code is allowed until touched)\n\n## How to Refactor\n\nInstead of:\n\\`\\`\\`typescript\nasync processOrder(order: Order): Promise<Result> {\n // 100 lines of validation, transformation, saving, notifications...\n}\n\\`\\`\\`\n\nWrite:\n\\`\\`\\`typescript\nasync processOrder(order: Order): Promise<Result> {\n const validated = this.validateOrder(order);\n const transformed = this.applyBusinessRules(validated);\n const saved = await this.saveToDatabase(transformed);\n await this.notifyStakeholders(saved);\n return this.buildResult(saved);\n}\n\\`\\`\\`\n\nNow the main method is a \"table of contents\" - each line tells part of the story!\n\n## Patterns for Extraction\n\n### Pattern 1: Extract Loop Bodies\n\\`\\`\\`typescript\n// BEFORE\nfor (const item of items) {\n // 20 lines of processing\n}\n\n// AFTER\nfor (const item of items) {\n this.processItem(item);\n}\n\\`\\`\\`\n\n### Pattern 2: Extract Conditional Blocks\n\\`\\`\\`typescript\n// BEFORE\nif (isAdmin(user)) {\n // 15 lines of admin logic\n}\n\n// AFTER\nif (isAdmin(user)) {\n this.handleAdminUser(user);\n}\n\\`\\`\\`\n\n### Pattern 3: Extract Data Transformations\n\\`\\`\\`typescript\n// BEFORE\nconst result = {\n // 10+ lines of object construction\n};\n\n// AFTER\nconst result = this.buildResultObject(data);\n\\`\\`\\`\n\n## If Refactoring Is Not Feasible\n\nSometimes methods genuinely need to be longer (complex algorithms, state machines, etc.).\n\n**Escape hatch**: Add a webpieces-disable comment with DATE and justification:\n\n\\`\\`\\`typescript\n// webpieces-disable max-lines-modified 2025/01/15 -- Complex state machine, splitting reduces clarity\nasync complexStateMachine(): Promise<void> {\n // ... longer method with justification\n}\n\\`\\`\\`\n\n**IMPORTANT**: The date format is yyyy/mm/dd. The disable will EXPIRE after 1 month from this date.\nAfter expiration, you must either fix the method or update the date to get another month.\nThis ensures that disable comments are reviewed periodically.\n\n## AI Agent Action Steps\n\n1. **READ** the method to understand its logical sections\n2. **IDENTIFY** logical units that can be extracted\n3. **EXTRACT** into well-named private methods\n4. **VERIFY** the main method now reads like a table of contents\n5. **IF NOT FEASIBLE**: Add webpieces-disable max-lines-modified comment with clear justification\n\n## Remember\n\n- Every method you write today will be read many times tomorrow\n- The best code explains itself through structure\n- When in doubt, extract and name it\n`;\n\n/**\n * Write the instructions documentation to tmp directory\n */\nfunction writeTmpInstructions(workspaceRoot: string): string {\n const tmpDir = path.join(workspaceRoot, TMP_DIR);\n const mdPath = path.join(tmpDir, TMP_MD_FILE);\n\n fs.mkdirSync(tmpDir, { recursive: true });\n fs.writeFileSync(mdPath, METHODSIZE_DOC_CONTENT);\n\n return mdPath;\n}\n\n/**\n * Get changed TypeScript files between base and head (or working tree if head not specified).\n * Uses `git diff base [head]` to match what `nx affected` does.\n * When head is NOT specified, also includes untracked files (matching nx affected behavior).\n */\nfunction getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: string): string[] {\n try {\n // If head is specified, diff base to head; otherwise diff base to working tree\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 // When comparing to working tree (no head specified), also include untracked files\n // This matches what nx affected does: \"All modified files not yet committed or tracked will also be added\"\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 // Merge and dedupe\n const allFiles = new Set([...changedFiles, ...untrackedFiles]);\n return Array.from(allFiles);\n } catch {\n // If ls-files fails, just return the changed files\n return changedFiles;\n }\n }\n\n return changedFiles;\n } catch {\n return [];\n }\n}\n\n/**\n * Get the diff content for a specific file between base and head (or working tree if head not specified).\n * Uses `git diff base [head]` to match what `nx affected` does.\n * For untracked files, returns the entire file content as additions.\n */\nfunction getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string {\n try {\n // If head is specified, diff base to head; otherwise diff base to working tree\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 is empty and we're comparing to working tree, check if it's an untracked file\n if (!diff && !head) {\n const fullPath = path.join(workspaceRoot, file);\n if (fs.existsSync(fullPath)) {\n // Check if file is untracked\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 // For untracked files, treat entire content as additions\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lines = content.split('\\n');\n // Create a pseudo-diff where all lines are additions\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 NEW method signatures.\n * Must handle: export function, async function, const/let arrow functions, class methods\n */\n// webpieces-disable max-lines-new-methods -- Regex patterns require inline documentation\nfunction findNewMethodSignaturesInDiff(diffContent: string): Set<string> {\n const newMethods = new Set<string>();\n const lines = diffContent.split('\\n');\n\n // Patterns to match method definitions (same as validate-new-methods)\n const patterns = [\n // [export] [async] function methodName( - most explicit, check first\n /^\\+\\s*(?:export\\s+)?(?:async\\s+)?function\\s+(\\w+)\\s*\\(/,\n // [export] const/let methodName = [async] (\n /^\\+\\s*(?:export\\s+)?(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s*)?\\(/,\n // [export] const/let methodName = [async] function\n /^\\+\\s*(?:export\\s+)?(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?function/,\n // class method: [public/private/protected] [static] [async] methodName( - but NOT constructor, if, for, while, etc.\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 // Extract method name - now always in capture group 1\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 * Parse diff to find line numbers that have changes in the new file\n */\nfunction getChangedLineNumbers(diffContent: string): Set<number> {\n const changedLines = new Set<number>();\n const lines = diffContent.split('\\n');\n\n let currentNewLine = 0;\n\n for (const line of lines) {\n // Parse hunk header: @@ -oldStart,oldCount +newStart,newCount @@\n const hunkMatch = line.match(/^@@ -\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/);\n if (hunkMatch) {\n currentNewLine = parseInt(hunkMatch[1], 10);\n continue;\n }\n\n if (currentNewLine === 0) continue;\n\n if (line.startsWith('+') && !line.startsWith('+++')) {\n // Added line\n changedLines.add(currentNewLine);\n currentNewLine++;\n } else if (line.startsWith('-') && !line.startsWith('---')) {\n // Removed line - doesn't increment new line counter\n } else if (!line.startsWith('\\\\')) {\n // Context line (unchanged)\n currentNewLine++;\n }\n }\n\n return changedLines;\n}\n\n/**\n * Parse a date string in yyyy/mm/dd format and return a Date object.\n * Returns null if the format is invalid.\n */\nfunction parseDisableDate(dateStr: string): Date | null {\n // Match yyyy/mm/dd format\n const match = dateStr.match(/^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/);\n if (!match) return null;\n\n const year = parseInt(match[1], 10);\n const month = parseInt(match[2], 10) - 1; // JS months are 0-indexed\n const day = parseInt(match[3], 10);\n\n const date = new Date(year, month, day);\n\n // Validate the date is valid (e.g., not Feb 30)\n if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {\n return null;\n }\n\n return date;\n}\n\n/**\n * Check if a date is within the last month (not expired).\n */\nfunction isDateWithinMonth(date: Date): boolean {\n const now = new Date();\n const oneMonthAgo = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate());\n return date >= oneMonthAgo;\n}\n\n/**\n * Get today's date in yyyy/mm/dd format for error messages\n */\nfunction getTodayDateString(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n return `${year}/${month}/${day}`;\n}\n\ninterface DisableInfo {\n type: 'full' | 'new-only' | 'none';\n isExpired: boolean;\n date?: string;\n}\n\n/**\n * Check what kind of webpieces-disable comment is present for a method.\n * Returns: DisableInfo with type, expiration status, and date\n * - 'full': max-lines-modified (ultimate escape, skips both validators)\n * - 'new-only': max-lines-new-methods (escaped 30-line check, still needs 80-line check)\n * - 'none': no escape hatch\n */\n// webpieces-disable max-lines-new-methods -- Complex validation logic with multiple escape hatch types\nfunction getDisableInfo(lines: string[], lineNumber: number): DisableInfo {\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')) {\n if (line.includes('max-lines-modified')) {\n // Check for date in format: max-lines-modified yyyy/mm/dd\n const dateMatch = line.match(/max-lines-modified\\s+(\\d{4}\\/\\d{2}\\/\\d{2}|XXXX\\/XX\\/XX)/);\n\n if (!dateMatch) {\n // No date found - treat as expired (invalid)\n return { type: 'full', isExpired: true, date: undefined };\n }\n\n const dateStr = dateMatch[1];\n\n // Secret permanent disable\n if (dateStr === 'XXXX/XX/XX') {\n return { type: 'full', isExpired: false, date: dateStr };\n }\n\n const date = parseDisableDate(dateStr);\n if (!date) {\n // Invalid date format - treat as expired\n return { type: 'full', isExpired: true, date: dateStr };\n }\n\n if (!isDateWithinMonth(date)) {\n // Date is expired (older than 1 month)\n return { type: 'full', isExpired: true, date: dateStr };\n }\n\n // Valid and not expired\n return { type: 'full', isExpired: false, date: dateStr };\n }\n if (line.includes('max-lines-new-methods')) {\n // Check for date in format: max-lines-new-methods yyyy/mm/dd\n const dateMatch = line.match(/max-lines-new-methods\\s+(\\d{4}\\/\\d{2}\\/\\d{2}|XXXX\\/XX\\/XX)/);\n\n if (!dateMatch) {\n // No date found - treat as expired (invalid)\n return { type: 'new-only', isExpired: true, date: undefined };\n }\n\n const dateStr = dateMatch[1];\n\n // Secret permanent disable\n if (dateStr === 'XXXX/XX/XX') {\n return { type: 'new-only', isExpired: false, date: dateStr };\n }\n\n const date = parseDisableDate(dateStr);\n if (!date) {\n // Invalid date format - treat as expired\n return { type: 'new-only', isExpired: true, date: dateStr };\n }\n\n if (!isDateWithinMonth(date)) {\n // Date is expired (older than 1 month)\n return { type: 'new-only', isExpired: true, date: dateStr };\n }\n\n // Valid and not expired\n return { type: 'new-only', isExpired: false, date: dateStr };\n }\n }\n }\n return { type: 'none', isExpired: false };\n}\n\ninterface MethodInfo {\n name: string;\n line: number;\n endLine: number;\n lines: number;\n disableInfo: DisableInfo;\n}\n\n/**\n * Parse a TypeScript file and find methods with their line counts\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\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 } 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 } 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 }\n }\n\n if (methodName && startLine !== undefined && endLine !== undefined) {\n methods.push({\n name: methodName,\n line: startLine,\n endLine: endLine,\n lines: endLine - startLine + 1,\n disableInfo: getDisableInfo(fileLines, startLine),\n });\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return methods;\n}\n\n/**\n * Check if a method has any changes within its line range\n */\nfunction methodHasChanges(method: MethodInfo, changedLineNumbers: Set<number>): boolean {\n for (let line = method.line; line <= method.endLine; line++) {\n if (changedLineNumbers.has(line)) return true;\n }\n return false;\n}\n\n/**\n * Check a NEW method and return violation if applicable\n */\nfunction checkNewMethodViolation(file: string, method: MethodInfo, disableAllowed: boolean): MethodViolation | null {\n const { type: disableType, isExpired, date: disableDate } = method.disableInfo;\n\n if (!disableAllowed) {\n // When disableAllowed is false, skip NEW methods without escape (let validate-new-methods handle)\n if (disableType === 'none') return null;\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n }\n\n if (disableType === 'full' && isExpired) {\n return { file, methodName: method.name, line: method.line, lines: method.lines, expiredDisable: true, expiredDate: disableDate };\n }\n if (disableType !== 'new-only') return null;\n\n if (isExpired) {\n return { file, methodName: method.name, line: method.line, lines: method.lines, expiredDisable: true, expiredDate: disableDate };\n }\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n}\n\n/**\n * Check a MODIFIED method and return violation if applicable\n */\nfunction checkModifiedMethodViolation(file: string, method: MethodInfo, disableAllowed: boolean): MethodViolation | null {\n const { type: disableType, isExpired, date: disableDate } = method.disableInfo;\n\n if (!disableAllowed) {\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n }\n if (disableType === 'full' && !isExpired) {\n // Valid escape, no violation\n return null;\n }\n if (disableType === 'full' && isExpired) {\n return { file, methodName: method.name, line: method.line, lines: method.lines, expiredDisable: true, expiredDate: disableDate };\n }\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n}\n\n/**\n * Find methods that exceed the limit.\n * Checks NEW methods with escape hatches and MODIFIED methods.\n */\nfunction findViolations(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n limit: number,\n disableAllowed: boolean,\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 if (!diff) continue;\n\n const newMethodNames = findNewMethodSignaturesInDiff(diff);\n const changedLineNumbers = getChangedLineNumbers(diff);\n if (changedLineNumbers.size === 0) continue;\n\n const methods = findMethodsInFile(file, workspaceRoot);\n\n for (const method of methods) {\n const { type: disableType, isExpired } = method.disableInfo;\n\n // Skip methods with valid, non-expired full escape - unless disableAllowed is false\n if (disableAllowed && disableType === 'full' && !isExpired) continue;\n if (method.lines <= limit) continue;\n\n const isNewMethod = newMethodNames.has(method.name);\n\n if (isNewMethod) {\n const violation = checkNewMethodViolation(file, method, disableAllowed);\n if (violation) violations.push(violation);\n } else if (methodHasChanges(method, changedLineNumbers)) {\n const violation = checkModifiedMethodViolation(file, method, disableAllowed);\n if (violation) violations.push(violation);\n }\n }\n }\n\n return violations;\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 */\n// webpieces-disable max-lines-new-methods -- Error output formatting with multiple message sections\nfunction reportViolations(violations: MethodViolation[], limit: number, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c Modified methods exceed ' + limit + ' lines!');\n console.error('');\n console.error('\\ud83d\\udcda When you modify a method, you must bring it under ' + limit + ' lines.');\n console.error(' This rule encourages GRADUAL cleanup so even though you did not cause it,');\n console.error(' you touched it, so you should fix now as part of your PR');\n console.error(' (this is for vibe coding and AI to fix as it touches things).');\n console.error(' You can refactor to stay under the limit 50% of the time. If not feasible, use the escape hatch.');\n console.error('');\n console.error(\n '\\u26a0\\ufe0f *** READ tmp/webpieces/webpieces.methodsize.md for detailed guidance on how to fix this easily *** \\u26a0\\ufe0f'\n );\n console.error('');\n\n for (const v of violations) {\n if (v.expiredDisable) {\n console.error(` \\u274c ${v.file}:${v.line}`);\n console.error(` Method: ${v.methodName} (${v.lines} lines, max: ${limit})`);\n console.error(` \\u23f0 EXPIRED DISABLE: Your disable comment dated ${v.expiredDate ?? 'unknown'} has expired (>1 month old).`);\n console.error(` You must either FIX the method or UPDATE the date to get another month.`);\n } else {\n console.error(` \\u274c ${v.file}:${v.line}`);\n console.error(` Method: ${v.methodName} (${v.lines} lines, max: ${limit})`);\n }\n }\n console.error('');\n\n // Only show escape hatch instructions when disableAllowed is true\n if (disableAllowed) {\n console.error(' You can disable this error, but you will be forced to fix again in 1 month');\n console.error(' since 99% of methods can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error(' Use escape with DATE (expires in 1 month):');\n console.error(` // webpieces-disable max-lines-modified ${getTodayDateString()} -- [your reason]`);\n console.error('');\n } else {\n console.error(' \\u26a0\\ufe0f disableAllowed is false - disable comments are NOT allowed.');\n console.error(' You MUST refactor to reduce method size.');\n console.error('');\n }\n}\n\nexport default async function runExecutor(\n options: ValidateModifiedMethodsOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n const workspaceRoot = context.root;\n const limit = options.limit ?? 80;\n const mode: MethodMaxLimitMode = options.mode ?? 'NEW_AND_MODIFIED_METHODS';\n const disableAllowed = options.disableAllowed ?? true;\n\n // Skip validation entirely if mode is OFF\n if (mode === 'OFF') {\n console.log('\\n\\u23ed\\ufe0f Skipping modified method validation (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n // If NX_HEAD is set (via nx affected --head=X), use it; otherwise compare to working tree\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\\u23ed\\ufe0f Skipping modified method validation (could not detect base branch)');\n console.log(' To run explicitly: nx affected --target=validate-modified-methods --base=origin/main');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating Modified Method Sizes (auto-detected base)\\n');\n } else {\n console.log('\\n\\ud83d\\udccf Validating Modified Method Sizes\\n');\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log(` Mode: ${mode}`);\n console.log(` Limit for modified methods: ${limit}`);\n console.log(` Disable allowed: ${disableAllowed}${!disableAllowed ? ' (no escape hatch)' : ''}`);\n console.log('');\n\n try {\n const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);\n\n if (changedFiles.length === 0) {\n console.log('\\u2705 No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`\\ud83d\\udcc2 Checking ${changedFiles.length} changed file(s)...`);\n\n const violations = findViolations(workspaceRoot, changedFiles, base, limit, disableAllowed, head);\n\n if (violations.length === 0) {\n console.log('\\u2705 All modified methods are under ' + limit + ' lines');\n return { success: true };\n }\n\n writeTmpInstructions(workspaceRoot);\n reportViolations(violations, limit, disableAllowed);\n return { success: false };\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n console.error('\\u274c Modified method validation failed:', error.message);\n return { success: false };\n }\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/dev-config/architecture/executors/validate-modified-methods/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Modified Methods Executor\n *\n * Validates that modified methods don't exceed a maximum line count (default 80).\n * This encourages gradual cleanup of legacy long methods - when you touch a method,\n * you must bring it under the limit.\n *\n * Combined with validate-new-methods, this creates a gradual\n * transition to cleaner code:\n * - New methods: must be under limit\n * - Modified methods: must be under limit (cleanup when touched)\n * - Untouched methods: no limit (legacy allowed)\n *\n * Usage:\n * nx affected --target=validate-modified-methods --base=origin/main\n *\n * Escape hatch: Add webpieces-disable max-lines-modified comment with date and justification\n * Format: // webpieces-disable max-lines-modified 2025/01/15 -- [reason]\n * The disable expires after 1 month from the date specified.\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 MethodMaxLimitMode = 'OFF' | 'NEW_METHODS' | 'NEW_AND_MODIFIED_METHODS' | 'MODIFIED_FILES';\n\nexport interface ValidateModifiedMethodsOptions {\n limit?: number;\n mode?: MethodMaxLimitMode;\n disableAllowed?: boolean;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\ninterface MethodViolation {\n file: string;\n methodName: string;\n line: number;\n lines: number;\n expiredDisable?: boolean;\n expiredDate?: string;\n}\n\nconst TMP_DIR = 'tmp/webpieces';\nconst TMP_MD_FILE = 'webpieces.methodsize.md';\n\nconst METHODSIZE_DOC_CONTENT = `# Instructions: Method Too Long\n\n## Requirement\n\n**~99% of the time**, you can stay under the \\`limit\\` from nx.json\nby extracting logical units into well-named methods.\nNearly all software can be written with methods under this size.\nTake the extra time to refactor - it's worth it for long-term maintainability.\n\n## The \"Table of Contents\" Principle\n\nGood code reads like a book's table of contents:\n- Chapter titles (method names) tell you WHAT happens\n- Reading chapter titles gives you the full story\n- You can dive into chapters (implementations) for details\n\n## Why Limit Method Sizes?\n\nMethods under reasonable limits are:\n- Easy to review in a single screen\n- Simple to understand without scrolling\n- Quick for AI to analyze and suggest improvements\n- More testable in isolation\n- Self-documenting through well-named extracted methods\n\n## Gradual Cleanup Strategy\n\nThis codebase uses a gradual cleanup approach:\n- **New methods**: Must be under \\`limit\\` from nx.json\n- **Modified methods**: Must be under \\`limit\\` from nx.json\n- **Untouched methods**: No limit (legacy code is allowed until touched)\n\n## How to Refactor\n\nInstead of:\n\\`\\`\\`typescript\nasync processOrder(order: Order): Promise<Result> {\n // 100 lines of validation, transformation, saving, notifications...\n}\n\\`\\`\\`\n\nWrite:\n\\`\\`\\`typescript\nasync processOrder(order: Order): Promise<Result> {\n const validated = this.validateOrder(order);\n const transformed = this.applyBusinessRules(validated);\n const saved = await this.saveToDatabase(transformed);\n await this.notifyStakeholders(saved);\n return this.buildResult(saved);\n}\n\\`\\`\\`\n\nNow the main method is a \"table of contents\" - each line tells part of the story!\n\n## Patterns for Extraction\n\n### Pattern 1: Extract Loop Bodies\n\\`\\`\\`typescript\n// BEFORE\nfor (const item of items) {\n // 20 lines of processing\n}\n\n// AFTER\nfor (const item of items) {\n this.processItem(item);\n}\n\\`\\`\\`\n\n### Pattern 2: Extract Conditional Blocks\n\\`\\`\\`typescript\n// BEFORE\nif (isAdmin(user)) {\n // 15 lines of admin logic\n}\n\n// AFTER\nif (isAdmin(user)) {\n this.handleAdminUser(user);\n}\n\\`\\`\\`\n\n### Pattern 3: Extract Data Transformations\n\\`\\`\\`typescript\n// BEFORE\nconst result = {\n // 10+ lines of object construction\n};\n\n// AFTER\nconst result = this.buildResultObject(data);\n\\`\\`\\`\n\n## If Refactoring Is Not Feasible\n\nSometimes methods genuinely need to be longer (complex algorithms, state machines, etc.).\n\n**Escape hatch**: Add a webpieces-disable comment with DATE and justification:\n\n\\`\\`\\`typescript\n// webpieces-disable max-lines-modified 2025/01/15 -- Complex state machine, splitting reduces clarity\nasync complexStateMachine(): Promise<void> {\n // ... longer method with justification\n}\n\\`\\`\\`\n\n**IMPORTANT**: The date format is yyyy/mm/dd. The disable will EXPIRE after 1 month from this date.\nAfter expiration, you must either fix the method or update the date to get another month.\nThis ensures that disable comments are reviewed periodically.\n\n## AI Agent Action Steps\n\n1. **READ** the method to understand its logical sections\n2. **IDENTIFY** logical units that can be extracted\n3. **EXTRACT** into well-named private methods\n4. **VERIFY** the main method now reads like a table of contents\n5. **IF NOT FEASIBLE**: Add webpieces-disable max-lines-modified comment with clear justification\n\n## Remember\n\n- Every method you write today will be read many times tomorrow\n- The best code explains itself through structure\n- When in doubt, extract and name it\n`;\n\n/**\n * Write the instructions documentation to tmp directory\n */\nfunction writeTmpInstructions(workspaceRoot: string): string {\n const tmpDir = path.join(workspaceRoot, TMP_DIR);\n const mdPath = path.join(tmpDir, TMP_MD_FILE);\n\n fs.mkdirSync(tmpDir, { recursive: true });\n fs.writeFileSync(mdPath, METHODSIZE_DOC_CONTENT);\n\n return mdPath;\n}\n\n/**\n * Get changed TypeScript files between base and head (or working tree if head not specified).\n * Uses `git diff base [head]` to match what `nx affected` does.\n * When head is NOT specified, also includes untracked files (matching nx affected behavior).\n */\nfunction getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: string): string[] {\n try {\n // If head is specified, diff base to head; otherwise diff base to working tree\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 // When comparing to working tree (no head specified), also include untracked files\n // This matches what nx affected does: \"All modified files not yet committed or tracked will also be added\"\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 // Merge and dedupe\n const allFiles = new Set([...changedFiles, ...untrackedFiles]);\n return Array.from(allFiles);\n } catch {\n // If ls-files fails, just return the changed files\n return changedFiles;\n }\n }\n\n return changedFiles;\n } catch {\n return [];\n }\n}\n\n/**\n * Get the diff content for a specific file between base and head (or working tree if head not specified).\n * Uses `git diff base [head]` to match what `nx affected` does.\n * For untracked files, returns the entire file content as additions.\n */\nfunction getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string {\n try {\n // If head is specified, diff base to head; otherwise diff base to working tree\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 is empty and we're comparing to working tree, check if it's an untracked file\n if (!diff && !head) {\n const fullPath = path.join(workspaceRoot, file);\n if (fs.existsSync(fullPath)) {\n // Check if file is untracked\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 // For untracked files, treat entire content as additions\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lines = content.split('\\n');\n // Create a pseudo-diff where all lines are additions\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 NEW method signatures.\n * Must handle: export function, async function, const/let arrow functions, class methods\n */\n// webpieces-disable max-lines-new-methods -- Regex patterns require inline documentation\nfunction findNewMethodSignaturesInDiff(diffContent: string): Set<string> {\n const newMethods = new Set<string>();\n const lines = diffContent.split('\\n');\n\n // Patterns to match method definitions (same as validate-new-methods)\n const patterns = [\n // [export] [async] function methodName( - most explicit, check first\n /^\\+\\s*(?:export\\s+)?(?:async\\s+)?function\\s+(\\w+)\\s*\\(/,\n // [export] const/let methodName = [async] (\n /^\\+\\s*(?:export\\s+)?(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s*)?\\(/,\n // [export] const/let methodName = [async] function\n /^\\+\\s*(?:export\\s+)?(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?function/,\n // class method: [public/private/protected] [static] [async] methodName( - but NOT constructor, if, for, while, etc.\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 // Extract method name - now always in capture group 1\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 * Parse diff to find line numbers that have changes in the new file\n */\nfunction getChangedLineNumbers(diffContent: string): Set<number> {\n const changedLines = new Set<number>();\n const lines = diffContent.split('\\n');\n\n let currentNewLine = 0;\n\n for (const line of lines) {\n // Parse hunk header: @@ -oldStart,oldCount +newStart,newCount @@\n const hunkMatch = line.match(/^@@ -\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/);\n if (hunkMatch) {\n currentNewLine = parseInt(hunkMatch[1], 10);\n continue;\n }\n\n if (currentNewLine === 0) continue;\n\n if (line.startsWith('+') && !line.startsWith('+++')) {\n // Added line\n changedLines.add(currentNewLine);\n currentNewLine++;\n } else if (line.startsWith('-') && !line.startsWith('---')) {\n // Removed line - doesn't increment new line counter\n } else if (!line.startsWith('\\\\')) {\n // Context line (unchanged)\n currentNewLine++;\n }\n }\n\n return changedLines;\n}\n\n/**\n * Parse a date string in yyyy/mm/dd format and return a Date object.\n * Returns null if the format is invalid.\n */\nfunction parseDisableDate(dateStr: string): Date | null {\n // Match yyyy/mm/dd format\n const match = dateStr.match(/^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/);\n if (!match) return null;\n\n const year = parseInt(match[1], 10);\n const month = parseInt(match[2], 10) - 1; // JS months are 0-indexed\n const day = parseInt(match[3], 10);\n\n const date = new Date(year, month, day);\n\n // Validate the date is valid (e.g., not Feb 30)\n if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {\n return null;\n }\n\n return date;\n}\n\n/**\n * Check if a date is within the last month (not expired).\n */\nfunction isDateWithinMonth(date: Date): boolean {\n const now = new Date();\n const oneMonthAgo = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate());\n return date >= oneMonthAgo;\n}\n\n/**\n * Get today's date in yyyy/mm/dd format for error messages\n */\nfunction getTodayDateString(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n return `${year}/${month}/${day}`;\n}\n\ninterface DisableInfo {\n type: 'full' | 'new-only' | 'none';\n isExpired: boolean;\n date?: string;\n}\n\n/**\n * Check what kind of webpieces-disable comment is present for a method.\n * Returns: DisableInfo with type, expiration status, and date\n * - 'full': max-lines-modified (ultimate escape, skips both validators)\n * - 'new-only': max-lines-new-methods (escaped 30-line check, still needs 80-line check)\n * - 'none': no escape hatch\n */\n// webpieces-disable max-lines-new-methods -- Complex validation logic with multiple escape hatch types\nfunction getDisableInfo(lines: string[], lineNumber: number): DisableInfo {\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')) {\n if (line.includes('max-lines-modified')) {\n // Check for date in format: max-lines-modified yyyy/mm/dd\n const dateMatch = line.match(/max-lines-modified\\s+(\\d{4}\\/\\d{2}\\/\\d{2}|XXXX\\/XX\\/XX)/);\n\n if (!dateMatch) {\n // No date found - treat as expired (invalid)\n return { type: 'full', isExpired: true, date: undefined };\n }\n\n const dateStr = dateMatch[1];\n\n // Secret permanent disable\n if (dateStr === 'XXXX/XX/XX') {\n return { type: 'full', isExpired: false, date: dateStr };\n }\n\n const date = parseDisableDate(dateStr);\n if (!date) {\n // Invalid date format - treat as expired\n return { type: 'full', isExpired: true, date: dateStr };\n }\n\n if (!isDateWithinMonth(date)) {\n // Date is expired (older than 1 month)\n return { type: 'full', isExpired: true, date: dateStr };\n }\n\n // Valid and not expired\n return { type: 'full', isExpired: false, date: dateStr };\n }\n if (line.includes('max-lines-new-methods')) {\n // Check for date in format: max-lines-new-methods yyyy/mm/dd\n const dateMatch = line.match(/max-lines-new-methods\\s+(\\d{4}\\/\\d{2}\\/\\d{2}|XXXX\\/XX\\/XX)/);\n\n if (!dateMatch) {\n // No date found - treat as expired (invalid)\n return { type: 'new-only', isExpired: true, date: undefined };\n }\n\n const dateStr = dateMatch[1];\n\n // Secret permanent disable\n if (dateStr === 'XXXX/XX/XX') {\n return { type: 'new-only', isExpired: false, date: dateStr };\n }\n\n const date = parseDisableDate(dateStr);\n if (!date) {\n // Invalid date format - treat as expired\n return { type: 'new-only', isExpired: true, date: dateStr };\n }\n\n if (!isDateWithinMonth(date)) {\n // Date is expired (older than 1 month)\n return { type: 'new-only', isExpired: true, date: dateStr };\n }\n\n // Valid and not expired\n return { type: 'new-only', isExpired: false, date: dateStr };\n }\n }\n }\n return { type: 'none', isExpired: false };\n}\n\ninterface MethodInfo {\n name: string;\n line: number;\n endLine: number;\n lines: number;\n disableInfo: DisableInfo;\n}\n\n/**\n * Parse a TypeScript file and find methods with their line counts\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\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 } 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 } 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 }\n }\n\n if (methodName && startLine !== undefined && endLine !== undefined) {\n methods.push({\n name: methodName,\n line: startLine,\n endLine: endLine,\n lines: endLine - startLine + 1,\n disableInfo: getDisableInfo(fileLines, startLine),\n });\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return methods;\n}\n\n/**\n * Check if a method has any changes within its line range\n */\nfunction methodHasChanges(method: MethodInfo, changedLineNumbers: Set<number>): boolean {\n for (let line = method.line; line <= method.endLine; line++) {\n if (changedLineNumbers.has(line)) return true;\n }\n return false;\n}\n\n/**\n * Check a NEW method and return violation if applicable\n */\nfunction checkNewMethodViolation(file: string, method: MethodInfo, disableAllowed: boolean): MethodViolation | null {\n const { type: disableType, isExpired, date: disableDate } = method.disableInfo;\n\n if (!disableAllowed) {\n // When disableAllowed is false, skip NEW methods without escape (let validate-new-methods handle)\n if (disableType === 'none') return null;\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n }\n\n if (disableType === 'full' && isExpired) {\n return { file, methodName: method.name, line: method.line, lines: method.lines, expiredDisable: true, expiredDate: disableDate };\n }\n if (disableType !== 'new-only') return null;\n\n if (isExpired) {\n return { file, methodName: method.name, line: method.line, lines: method.lines, expiredDisable: true, expiredDate: disableDate };\n }\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n}\n\n/**\n * Check a MODIFIED method and return violation if applicable\n */\nfunction checkModifiedMethodViolation(file: string, method: MethodInfo, disableAllowed: boolean): MethodViolation | null {\n const { type: disableType, isExpired, date: disableDate } = method.disableInfo;\n\n if (!disableAllowed) {\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n }\n if (disableType === 'full' && !isExpired) {\n // Valid escape, no violation\n return null;\n }\n if (disableType === 'full' && isExpired) {\n return { file, methodName: method.name, line: method.line, lines: method.lines, expiredDisable: true, expiredDate: disableDate };\n }\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n}\n\n/**\n * Find methods that exceed the limit.\n * Checks NEW methods with escape hatches and MODIFIED methods.\n */\nfunction findViolations(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n limit: number,\n disableAllowed: boolean,\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 if (!diff) continue;\n\n const newMethodNames = findNewMethodSignaturesInDiff(diff);\n const changedLineNumbers = getChangedLineNumbers(diff);\n if (changedLineNumbers.size === 0) continue;\n\n const methods = findMethodsInFile(file, workspaceRoot);\n\n for (const method of methods) {\n const { type: disableType, isExpired } = method.disableInfo;\n\n // Skip methods with valid, non-expired full escape - unless disableAllowed is false\n if (disableAllowed && disableType === 'full' && !isExpired) continue;\n if (method.lines <= limit) continue;\n\n const isNewMethod = newMethodNames.has(method.name);\n\n if (isNewMethod) {\n const violation = checkNewMethodViolation(file, method, disableAllowed);\n if (violation) violations.push(violation);\n } else if (methodHasChanges(method, changedLineNumbers)) {\n const violation = checkModifiedMethodViolation(file, method, disableAllowed);\n if (violation) violations.push(violation);\n }\n }\n }\n\n return violations;\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 */\n// webpieces-disable max-lines-new-methods -- Error output formatting with multiple message sections\nfunction reportViolations(violations: MethodViolation[], limit: number, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c Modified methods exceed ' + limit + ' lines!');\n console.error('');\n console.error('\\ud83d\\udcda When you modify a method, you must bring it under ' + limit + ' lines.');\n console.error(' This rule encourages GRADUAL cleanup so even though you did not cause it,');\n console.error(' you touched it, so you should fix now as part of your PR');\n console.error(' (this is for vibe coding and AI to fix as it touches things).');\n console.error(' You can refactor to stay under the limit 50% of the time. If not feasible, use the escape hatch.');\n console.error('');\n console.error(\n '\\u26a0\\ufe0f *** READ tmp/webpieces/webpieces.methodsize.md for detailed guidance on how to fix this easily *** \\u26a0\\ufe0f'\n );\n console.error('');\n\n for (const v of violations) {\n if (v.expiredDisable) {\n console.error(` \\u274c ${v.file}:${v.line}`);\n console.error(` Method: ${v.methodName} (${v.lines} lines, max: ${limit})`);\n console.error(` \\u23f0 EXPIRED DISABLE: Your disable comment dated ${v.expiredDate ?? 'unknown'} has expired (>1 month old).`);\n console.error(` You must either FIX the method or UPDATE the date to get another month.`);\n } else {\n console.error(` \\u274c ${v.file}:${v.line}`);\n console.error(` Method: ${v.methodName} (${v.lines} lines, max: ${limit})`);\n }\n }\n console.error('');\n\n // Only show escape hatch instructions when disableAllowed is true\n if (disableAllowed) {\n console.error(' You can disable this error, but you will be forced to fix again in 1 month');\n console.error(' since 99% of methods can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error(' Use escape with DATE (expires in 1 month):');\n console.error(` // webpieces-disable max-lines-modified ${getTodayDateString()} -- [your reason]`);\n console.error('');\n } else {\n console.error(' \\u26a0\\ufe0f disableAllowed is false - disable comments are NOT allowed.');\n console.error(' This rule must be met and cannot be disabled since nx.json disableAllowed is set to false.');\n console.error(' You MUST refactor to reduce method size.');\n console.error('');\n console.error(' For a major refactor, a human can add \"ignoreModifiedUntilEpoch\" to nx.json validate-code options.');\n console.error(' This is an expiry timestamp (epoch ms) for when we start forcing everyone to meet size rules again.');\n console.error(' Sometimes for speed, we allow methods to expand during a refactor and over time,');\n console.error(' each PR reduces methods as they get touched.');\n console.error(' AI agents should NOT add ignoreModifiedUntilEpoch - ask a human to do it.');\n console.error('');\n }\n}\n\nexport default async function runExecutor(\n options: ValidateModifiedMethodsOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n const workspaceRoot = context.root;\n const limit = options.limit ?? 80;\n const mode: MethodMaxLimitMode = options.mode ?? 'NEW_AND_MODIFIED_METHODS';\n const disableAllowed = options.disableAllowed ?? true;\n\n // Skip validation entirely if mode is OFF\n if (mode === 'OFF') {\n console.log('\\n\\u23ed\\ufe0f Skipping modified method validation (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n // If NX_HEAD is set (via nx affected --head=X), use it; otherwise compare to working tree\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\\u23ed\\ufe0f Skipping modified method validation (could not detect base branch)');\n console.log(' To run explicitly: nx affected --target=validate-modified-methods --base=origin/main');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating Modified Method Sizes (auto-detected base)\\n');\n } else {\n console.log('\\n\\ud83d\\udccf Validating Modified Method Sizes\\n');\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log(` Mode: ${mode}`);\n console.log(` Limit for modified methods: ${limit}`);\n console.log(` Disable allowed: ${disableAllowed}${!disableAllowed ? ' (no escape hatch)' : ''}`);\n console.log('');\n\n try {\n const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);\n\n if (changedFiles.length === 0) {\n console.log('\\u2705 No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`\\ud83d\\udcc2 Checking ${changedFiles.length} changed file(s)...`);\n\n const violations = findViolations(workspaceRoot, changedFiles, base, limit, disableAllowed, head);\n\n if (violations.length === 0) {\n console.log('\\u2705 All modified methods are under ' + limit + ' lines');\n return { success: true };\n }\n\n writeTmpInstructions(workspaceRoot);\n reportViolations(violations, limit, disableAllowed);\n return { success: false };\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n console.error('\\u274c Modified method validation failed:', error.message);\n return { success: false };\n }\n}\n"]}
@@ -715,8 +715,15 @@ function reportViolations(violations: MethodViolation[], limit: number, disableA
715
715
  console.error('');
716
716
  } else {
717
717
  console.error(' \u26a0\ufe0f disableAllowed is false - disable comments are NOT allowed.');
718
+ console.error(' This rule must be met and cannot be disabled since nx.json disableAllowed is set to false.');
718
719
  console.error(' You MUST refactor to reduce method size.');
719
720
  console.error('');
721
+ console.error(' For a major refactor, a human can add "ignoreModifiedUntilEpoch" to nx.json validate-code options.');
722
+ console.error(' This is an expiry timestamp (epoch ms) for when we start forcing everyone to meet size rules again.');
723
+ console.error(' Sometimes for speed, we allow methods to expand during a refactor and over time,');
724
+ console.error(' each PR reduces methods as they get touched.');
725
+ console.error(' AI agents should NOT add ignoreModifiedUntilEpoch - ask a human to do it.');
726
+ console.error('');
720
727
  }
721
728
  }
722
729
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/dev-config",
3
- "version": "0.2.78",
3
+ "version": "0.2.79",
4
4
  "description": "Development configuration, scripts, and patterns for WebPieces projects",
5
5
  "type": "commonjs",
6
6
  "bin": {