@webpieces/code-rules 0.0.1 → 0.2.113
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -3
- package/src/cli.d.ts +1 -0
- package/src/cli.js +19 -0
- package/src/cli.js.map +1 -0
- package/src/diff-utils.d.ts +24 -0
- package/src/{diff-utils.ts → diff-utils.js} +30 -38
- package/src/diff-utils.js.map +1 -0
- package/src/from-shared-config.d.ts +28 -0
- package/src/from-shared-config.js +119 -0
- package/src/from-shared-config.js.map +1 -0
- package/src/index.js +33 -0
- package/src/index.js.map +1 -0
- package/src/validate-catch-error-pattern.d.ts +47 -0
- package/src/{validate-catch-error-pattern.ts → validate-catch-error-pattern.js} +74 -195
- package/src/validate-catch-error-pattern.js.map +1 -0
- package/src/validate-code.d.ts +98 -0
- package/src/{validate-code.ts → validate-code.js} +65 -259
- package/src/validate-code.js.map +1 -0
- package/src/validate-dtos.d.ts +41 -0
- package/src/{validate-dtos.ts → validate-dtos.js} +88 -215
- package/src/validate-dtos.js.map +1 -0
- package/src/validate-modified-files.d.ts +24 -0
- package/src/{validate-modified-files.ts → validate-modified-files.js} +46 -115
- package/src/validate-modified-files.js.map +1 -0
- package/src/validate-modified-methods.d.ts +30 -0
- package/src/{validate-modified-methods.ts → validate-modified-methods.js} +94 -196
- package/src/validate-modified-methods.js.map +1 -0
- package/src/validate-new-methods.d.ts +27 -0
- package/src/{validate-new-methods.ts → validate-new-methods.js} +63 -133
- package/src/validate-new-methods.js.map +1 -0
- package/src/validate-no-any-unknown.d.ts +41 -0
- package/src/{validate-no-any-unknown.ts → validate-no-any-unknown.js} +69 -146
- package/src/validate-no-any-unknown.js.map +1 -0
- package/src/validate-no-destructure.d.ts +51 -0
- package/src/{validate-no-destructure.ts → validate-no-destructure.js} +80 -166
- package/src/validate-no-destructure.js.map +1 -0
- package/src/validate-no-direct-api-resolver.d.ts +46 -0
- package/src/{validate-no-direct-api-resolver.ts → validate-no-direct-api-resolver.js} +112 -211
- package/src/validate-no-direct-api-resolver.js.map +1 -0
- package/src/validate-no-implicit-any.d.ts +36 -0
- package/src/{validate-no-implicit-any.ts → validate-no-implicit-any.js} +94 -141
- package/src/validate-no-implicit-any.js.map +1 -0
- package/src/validate-no-inline-types.d.ts +90 -0
- package/src/{validate-no-inline-types.ts → validate-no-inline-types.js} +93 -198
- package/src/validate-no-inline-types.js.map +1 -0
- package/src/validate-no-unmanaged-exceptions.d.ts +43 -0
- package/src/{validate-no-unmanaged-exceptions.ts → validate-no-unmanaged-exceptions.js} +71 -140
- package/src/validate-no-unmanaged-exceptions.js.map +1 -0
- package/src/validate-prisma-converters.d.ts +59 -0
- package/src/{validate-prisma-converters.ts → validate-prisma-converters.js} +120 -307
- package/src/validate-prisma-converters.js.map +1 -0
- package/src/validate-return-types.d.ts +28 -0
- package/src/{validate-return-types.ts → validate-return-types.js} +84 -168
- package/src/validate-return-types.js.map +1 -0
- package/LICENSE +0 -373
- package/jest.config.ts +0 -20
- package/project.json +0 -22
- package/src/cli.ts +0 -17
- package/src/from-shared-config.ts +0 -118
- package/tsconfig.json +0 -22
- package/tsconfig.lib.json +0 -10
- package/tsconfig.spec.json +0 -14
- /package/src/{index.ts → index.d.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-new-methods.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-new-methods.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate New Methods Executor\n *\n * Validates that newly added methods don't exceed a maximum line count.\n * Runs in affected mode when:\n * 1. NX_BASE environment variable is set (via nx affected), OR\n * 2. Auto-detects base by finding merge-base with origin/main\n *\n * This validator encourages writing methods that read like a \"table of contents\"\n * where each method call describes a larger piece of work.\n *\n * Usage:\n * nx affected --target=validate-new-methods --base=origin/main\n * OR: runs automatically via build's architecture:validate-complete dependency\n *\n * Escape hatch: Add webpieces-disable max-lines-new-methods comment with justification\n */\n\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 ValidateNewMethodsOptions {\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 isNew: boolean;\n limit: number;\n}\n\ninterface MethodInfo {\n name: string;\n line: number;\n lines: number;\n hasDisableComment: boolean;\n}\n\nconst TMP_DIR = '.webpieces/instruct-ai';\nconst TMP_MD_FILE = 'webpieces.methodsize.md';\n\nconst METHODSIZE_DOC_CONTENT = `# Instructions: New 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.\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 New Methods?\n\nMethods under the limit 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\nExtracting logical units into well-named methods makes code more readable for both\nAI and humans.\n\n## How to Refactor\n\nInstead of:\n\\`\\`\\`typescript\nasync processOrder(order: Order): Promise<Result> {\n // 50 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 justification:\n\n\\`\\`\\`typescript\n// webpieces-disable max-lines-new-methods -- Complex state machine, splitting reduces clarity\nasync complexStateMachine(): Promise<void> {\n // ... longer method with justification\n}\n\\`\\`\\`\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-new-methods 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 // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\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 // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\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 (err: unknown) {\n //const error = toError(err);\n // If ls-files fails, just return the changed files\n return changedFiles;\n }\n }\n\n return changedFiles;\n } catch (err: unknown) {\n //const error = toError(err);\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 // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\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 (err: unknown) {\n //const error = toError(err);\n return '';\n }\n}\n\n/**\n * Parse diff to find newly added method signatures\n */\nfunction findNewMethodSignaturesInDiff(diffContent: string): Set<string> {\n const newMethods = new Set<string>();\n const lines = diffContent.split('\\n');\n\n // Patterns to match method definitions\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 * Check if a line contains a webpieces-disable comment that exempts from new method validation.\n * Both max-lines-new-methods AND max-lines-modified are accepted here.\n */\nfunction hasDisableComment(lines: string[], lineNumber: number): boolean {\n // Check the line before the method (lineNumber is 1-indexed, array is 0-indexed)\n // We need to check a few lines before in case there's JSDoc or decorators\n const startCheck = Math.max(0, lineNumber - 5);\n for (let i = lineNumber - 2; i >= startCheck; i--) {\n const line = lines[i]?.trim() ?? '';\n // Stop if we hit another function/class/etc\n if (line.startsWith('function ') || line.startsWith('class ') || line.endsWith('}')) {\n break;\n }\n if (line.includes('webpieces-disable')) {\n // Either escape hatch exempts from the lowLimit new method check\n if (line.includes('max-lines-new-methods') || line.includes('max-lines-modified')) {\n return true;\n }\n }\n }\n return false;\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 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 // Check if it's assigned to a variable\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 lines: endLine - startLine + 1,\n hasDisableComment: hasDisableComment(fileLines, startLine),\n });\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return methods;\n}\n\n/**\n * Find new methods that exceed the line limit\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 // Get the diff to find which methods are NEW (not just modified)\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const newMethodNames = findNewMethodSignaturesInDiff(diff);\n\n if (newMethodNames.size === 0) continue;\n\n // Parse the current file to get method line counts\n const methods = findMethodsInFile(file, workspaceRoot);\n\n for (const method of methods) {\n if (!newMethodNames.has(method.name)) continue;\n\n if (method.lines > limit) {\n if (!disableAllowed) {\n // No escape possible\n violations.push({\n file,\n methodName: method.name,\n line: method.line,\n lines: method.lines,\n isNew: true,\n limit,\n });\n } else if (!method.hasDisableComment) {\n // Escape allowed but not present\n violations.push({\n file,\n methodName: method.name,\n line: method.line,\n lines: method.lines,\n isNew: true,\n limit,\n });\n }\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 * This allows the executor to run even when NX_BASE isn't set (e.g., via dependsOn).\n */\nfunction detectBase(workspaceRoot: string): string | null {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // First, try to get merge-base with origin/main\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 (err: unknown) {\n //const error = toError(err);\n // origin/main might not exist, try main\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\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 (err2: unknown) {\n //const error2 = toError(err2);\n // Ignore - will return null\n }\n }\n return null;\n}\n\n/**\n * Report violations to the user with helpful instructions\n */\nfunction reportViolations(violations: MethodViolation[], limit: number, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c New methods exceed ' + limit + ' line limit!');\n console.error('');\n console.error('\\ud83d\\udcda Methods should read like a \"table of contents\" - each method call');\n console.error(' describes a larger piece of work.');\n console.error('');\n console.error('\\u26a0\\ufe0f *** READ .webpieces/instruct-ai/webpieces.methodsize.md for detailed guidance on how to fix this easily *** \\u26a0\\ufe0f');\n console.error('');\n\n if (disableAllowed) {\n console.error('\\u26a0\\ufe0f VIOLATIONS (can use escape hatch):');\n } else {\n console.error('\\ud83d\\udeab VIOLATIONS (cannot be bypassed with disable comment):');\n }\n console.error('');\n for (const v of violations) {\n console.error(` \\u274c ${v.file}:${v.line}`);\n console.error(` Method: ${v.methodName} (${v.lines} lines, limit: ${limit})`);\n }\n console.error('');\n if (disableAllowed) {\n console.error(' Use escape: // webpieces-disable max-lines-new-methods -- [your reason]');\n } else {\n console.error(' These methods MUST be refactored - no escape hatch available (disableAllowed=false).');\n }\n console.error('');\n}\n\nexport default async function runValidator(\n options: ValidateNewMethodsOptions,\n workspaceRoot: string\n): Promise<ExecutorResult> {\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 new method validation (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n // Check if running in affected mode via NX_BASE, or auto-detect\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 // Try to auto-detect base from git merge-base\n base = detectBase(workspaceRoot) ?? undefined;\n\n if (!base) {\n console.log('\\n\\u23ed\\ufe0f Skipping new method validation (could not detect base branch)');\n console.log(' To run explicitly: nx affected --target=validate-new-methods --base=origin/main');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating New Method Sizes (auto-detected base)\\n');\n } else {\n console.log('\\n\\ud83d\\udccf Validating New 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 new methods: ${limit} lines (${disableAllowed ? 'can escape' : 'NO escape possible'})`);\n console.log('');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Get changed TypeScript files (base to head, or working tree if head not set)\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 // Find violations\n const violations = findViolations(workspaceRoot, changedFiles, base, limit, disableAllowed, head);\n\n if (violations.length === 0) {\n console.log('\\u2705 All new methods are within ' + limit + ' lines');\n return { success: true };\n }\n\n // Write instructions file and report violations\n writeTmpInstructions(workspaceRoot);\n reportViolations(violations, limit, disableAllowed);\n\n return { success: false };\n } catch (err: unknown) {\n //const error = toError(err);\n const error = err instanceof Error ? err : new Error(String(err));\n console.error('\\u274c New method validation failed:', error.message);\n return { success: false };\n }\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate No Any Unknown Executor
|
|
3
|
+
*
|
|
4
|
+
* Validates that `any` and `unknown` TypeScript keywords are not used.
|
|
5
|
+
* Uses LINE-BASED detection (not method-based) for git diff filtering.
|
|
6
|
+
*
|
|
7
|
+
* ============================================================================
|
|
8
|
+
* VIOLATIONS (BAD) - These patterns are flagged:
|
|
9
|
+
* ============================================================================
|
|
10
|
+
*
|
|
11
|
+
* - const x: any = ...
|
|
12
|
+
* - function foo(arg: any): any { }
|
|
13
|
+
* - const data = response as any;
|
|
14
|
+
* - type T = any;
|
|
15
|
+
* - const x: unknown = ...
|
|
16
|
+
* - function foo(arg: unknown): unknown { }
|
|
17
|
+
*
|
|
18
|
+
* ============================================================================
|
|
19
|
+
* MODES (LINE-BASED)
|
|
20
|
+
* ============================================================================
|
|
21
|
+
* - OFF: Skip validation entirely
|
|
22
|
+
* - MODIFIED_CODE: Flag any/unknown on changed lines (lines in diff hunks)
|
|
23
|
+
* - MODIFIED_FILES: Flag ALL any/unknown in files that were modified
|
|
24
|
+
*
|
|
25
|
+
* ============================================================================
|
|
26
|
+
* ESCAPE HATCH
|
|
27
|
+
* ============================================================================
|
|
28
|
+
* Add comment above the violation:
|
|
29
|
+
* // webpieces-disable no-any-unknown -- [your justification]
|
|
30
|
+
* const x: any = ...;
|
|
31
|
+
*/
|
|
32
|
+
export type NoAnyUnknownMode = 'OFF' | 'MODIFIED_CODE' | 'MODIFIED_FILES';
|
|
33
|
+
export interface ValidateNoAnyUnknownOptions {
|
|
34
|
+
mode?: NoAnyUnknownMode;
|
|
35
|
+
disableAllowed?: boolean;
|
|
36
|
+
ignoreModifiedUntilEpoch?: number;
|
|
37
|
+
}
|
|
38
|
+
export interface ExecutorResult {
|
|
39
|
+
success: boolean;
|
|
40
|
+
}
|
|
41
|
+
export default function runValidator(options: ValidateNoAnyUnknownOptions, workspaceRoot: string): Promise<ExecutorResult>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Validate No Any Unknown Executor
|
|
3
4
|
*
|
|
@@ -29,41 +30,22 @@
|
|
|
29
30
|
* // webpieces-disable no-any-unknown -- [your justification]
|
|
30
31
|
* const x: any = ...;
|
|
31
32
|
*/
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
export interface ValidateNoAnyUnknownOptions {
|
|
41
|
-
mode?: NoAnyUnknownMode;
|
|
42
|
-
disableAllowed?: boolean;
|
|
43
|
-
ignoreModifiedUntilEpoch?: number;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface ExecutorResult {
|
|
47
|
-
success: boolean;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
interface AnyUnknownViolation {
|
|
51
|
-
file: string;
|
|
52
|
-
line: number;
|
|
53
|
-
column: number;
|
|
54
|
-
keyword: 'any' | 'unknown';
|
|
55
|
-
context: string;
|
|
56
|
-
}
|
|
57
|
-
|
|
33
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
+
exports.default = runValidator;
|
|
35
|
+
const tslib_1 = require("tslib");
|
|
36
|
+
const child_process_1 = require("child_process");
|
|
37
|
+
const fs = tslib_1.__importStar(require("fs"));
|
|
38
|
+
const path = tslib_1.__importStar(require("path"));
|
|
39
|
+
const ts = tslib_1.__importStar(require("typescript"));
|
|
58
40
|
/**
|
|
59
41
|
* Get changed TypeScript files between base and head (or working tree if head not specified).
|
|
60
42
|
*/
|
|
61
43
|
// webpieces-disable max-lines-new-methods -- Git command handling with untracked files requires multiple code paths
|
|
62
|
-
function getChangedTypeScriptFiles(workspaceRoot
|
|
44
|
+
function getChangedTypeScriptFiles(workspaceRoot, base, head) {
|
|
63
45
|
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
64
46
|
try {
|
|
65
47
|
const diffTarget = head ? `${base} ${head}` : base;
|
|
66
|
-
const output = execSync(`git diff --name-only ${diffTarget} -- '*.ts' '*.tsx'`, {
|
|
48
|
+
const output = (0, child_process_1.execSync)(`git diff --name-only ${diffTarget} -- '*.ts' '*.tsx'`, {
|
|
67
49
|
cwd: workspaceRoot,
|
|
68
50
|
encoding: 'utf-8',
|
|
69
51
|
});
|
|
@@ -71,11 +53,10 @@ function getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: s
|
|
|
71
53
|
.trim()
|
|
72
54
|
.split('\n')
|
|
73
55
|
.filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));
|
|
74
|
-
|
|
75
56
|
if (!head) {
|
|
76
57
|
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
77
58
|
try {
|
|
78
|
-
const untrackedOutput = execSync(`git ls-files --others --exclude-standard '*.ts' '*.tsx'`, {
|
|
59
|
+
const untrackedOutput = (0, child_process_1.execSync)(`git ls-files --others --exclude-standard '*.ts' '*.tsx'`, {
|
|
79
60
|
cwd: workspaceRoot,
|
|
80
61
|
encoding: 'utf-8',
|
|
81
62
|
});
|
|
@@ -85,39 +66,37 @@ function getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: s
|
|
|
85
66
|
.filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));
|
|
86
67
|
const allFiles = new Set([...changedFiles, ...untrackedFiles]);
|
|
87
68
|
return Array.from(allFiles);
|
|
88
|
-
}
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
89
71
|
//const error = toError(err);
|
|
90
72
|
return changedFiles;
|
|
91
73
|
}
|
|
92
74
|
}
|
|
93
|
-
|
|
94
75
|
return changedFiles;
|
|
95
|
-
}
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
96
78
|
//const error = toError(err);
|
|
97
79
|
return [];
|
|
98
80
|
}
|
|
99
81
|
}
|
|
100
|
-
|
|
101
82
|
/**
|
|
102
83
|
* Get the diff content for a specific file.
|
|
103
84
|
*/
|
|
104
|
-
function getFileDiff(workspaceRoot
|
|
85
|
+
function getFileDiff(workspaceRoot, file, base, head) {
|
|
105
86
|
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
106
87
|
try {
|
|
107
88
|
const diffTarget = head ? `${base} ${head}` : base;
|
|
108
|
-
const diff = execSync(`git diff ${diffTarget} -- "${file}"`, {
|
|
89
|
+
const diff = (0, child_process_1.execSync)(`git diff ${diffTarget} -- "${file}"`, {
|
|
109
90
|
cwd: workspaceRoot,
|
|
110
91
|
encoding: 'utf-8',
|
|
111
92
|
});
|
|
112
|
-
|
|
113
93
|
if (!diff && !head) {
|
|
114
94
|
const fullPath = path.join(workspaceRoot, file);
|
|
115
95
|
if (fs.existsSync(fullPath)) {
|
|
116
|
-
const isUntracked = execSync(`git ls-files --others --exclude-standard "${file}"`, {
|
|
96
|
+
const isUntracked = (0, child_process_1.execSync)(`git ls-files --others --exclude-standard "${file}"`, {
|
|
117
97
|
cwd: workspaceRoot,
|
|
118
98
|
encoding: 'utf-8',
|
|
119
99
|
}).trim();
|
|
120
|
-
|
|
121
100
|
if (isUntracked) {
|
|
122
101
|
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
123
102
|
const lines = content.split('\n');
|
|
@@ -125,46 +104,43 @@ function getFileDiff(workspaceRoot: string, file: string, base: string, head?: s
|
|
|
125
104
|
}
|
|
126
105
|
}
|
|
127
106
|
}
|
|
128
|
-
|
|
129
107
|
return diff;
|
|
130
|
-
}
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
131
110
|
//const error = toError(err);
|
|
132
111
|
return '';
|
|
133
112
|
}
|
|
134
113
|
}
|
|
135
|
-
|
|
136
114
|
/**
|
|
137
115
|
* Parse diff to extract changed line numbers (additions only - lines starting with +).
|
|
138
116
|
*/
|
|
139
|
-
function getChangedLineNumbers(diffContent
|
|
140
|
-
const changedLines = new Set
|
|
117
|
+
function getChangedLineNumbers(diffContent) {
|
|
118
|
+
const changedLines = new Set();
|
|
141
119
|
const lines = diffContent.split('\n');
|
|
142
120
|
let currentLine = 0;
|
|
143
|
-
|
|
144
121
|
for (const line of lines) {
|
|
145
122
|
const hunkMatch = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
|
|
146
123
|
if (hunkMatch) {
|
|
147
124
|
currentLine = parseInt(hunkMatch[1], 10);
|
|
148
125
|
continue;
|
|
149
126
|
}
|
|
150
|
-
|
|
151
127
|
if (line.startsWith('+') && !line.startsWith('+++')) {
|
|
152
128
|
changedLines.add(currentLine);
|
|
153
129
|
currentLine++;
|
|
154
|
-
}
|
|
130
|
+
}
|
|
131
|
+
else if (line.startsWith('-') && !line.startsWith('---')) {
|
|
155
132
|
// Deletions don't increment line number
|
|
156
|
-
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
157
135
|
currentLine++;
|
|
158
136
|
}
|
|
159
137
|
}
|
|
160
|
-
|
|
161
138
|
return changedLines;
|
|
162
139
|
}
|
|
163
|
-
|
|
164
140
|
/**
|
|
165
141
|
* Check if a line contains a webpieces-disable comment for no-any-unknown.
|
|
166
142
|
*/
|
|
167
|
-
function hasDisableComment(lines
|
|
143
|
+
function hasDisableComment(lines, lineNumber) {
|
|
168
144
|
const startCheck = Math.max(0, lineNumber - 5);
|
|
169
145
|
for (let i = lineNumber - 2; i >= startCheck; i--) {
|
|
170
146
|
const line = lines[i]?.trim() ?? '';
|
|
@@ -177,15 +153,14 @@ function hasDisableComment(lines: string[], lineNumber: number): boolean {
|
|
|
177
153
|
}
|
|
178
154
|
return false;
|
|
179
155
|
}
|
|
180
|
-
|
|
181
156
|
/**
|
|
182
157
|
* Get a description of the context where the any/unknown keyword appears.
|
|
183
158
|
*/
|
|
184
159
|
// webpieces-disable max-lines-new-methods -- Context detection requires checking many AST node types
|
|
185
|
-
function getViolationContext(node
|
|
160
|
+
function getViolationContext(node, sourceFile) {
|
|
186
161
|
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
187
162
|
try {
|
|
188
|
-
let current
|
|
163
|
+
let current = node;
|
|
189
164
|
while (current.parent) {
|
|
190
165
|
const parent = current.parent;
|
|
191
166
|
if (ts.isParameter(parent)) {
|
|
@@ -220,33 +195,25 @@ function getViolationContext(node: ts.Node, sourceFile: ts.SourceFile): string {
|
|
|
220
195
|
current = parent;
|
|
221
196
|
}
|
|
222
197
|
return 'type position';
|
|
223
|
-
}
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
224
200
|
//const error = toError(err);
|
|
225
201
|
return 'type position';
|
|
226
202
|
}
|
|
227
203
|
}
|
|
228
|
-
|
|
229
|
-
interface AnyUnknownInfo {
|
|
230
|
-
line: number;
|
|
231
|
-
column: number;
|
|
232
|
-
keyword: 'any' | 'unknown';
|
|
233
|
-
context: string;
|
|
234
|
-
hasDisableComment: boolean;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
204
|
/**
|
|
238
205
|
* Check if a node is in a catch clause variable declaration.
|
|
239
206
|
* This allows `catch (err: unknown)` and `catch (err: unknown)` patterns.
|
|
240
207
|
*/
|
|
241
|
-
function isInCatchClause(node
|
|
242
|
-
let current
|
|
208
|
+
function isInCatchClause(node) {
|
|
209
|
+
let current = node.parent;
|
|
243
210
|
while (current) {
|
|
244
211
|
if (ts.isCatchClause(current)) {
|
|
245
212
|
// We're somewhere in a catch clause - check if we're in the variable declaration
|
|
246
|
-
const catchClause = current
|
|
213
|
+
const catchClause = current;
|
|
247
214
|
if (catchClause.variableDeclaration) {
|
|
248
215
|
// Walk back up from the original node to see if we're part of the variable declaration
|
|
249
|
-
let checkNode
|
|
216
|
+
let checkNode = node.parent;
|
|
250
217
|
while (checkNode && checkNode !== current) {
|
|
251
218
|
if (checkNode === catchClause.variableDeclaration) {
|
|
252
219
|
return true;
|
|
@@ -259,23 +226,20 @@ function isInCatchClause(node: ts.Node): boolean {
|
|
|
259
226
|
}
|
|
260
227
|
return false;
|
|
261
228
|
}
|
|
262
|
-
|
|
263
229
|
/**
|
|
264
230
|
* Find all `any` and `unknown` keywords in a file using AST.
|
|
265
231
|
*/
|
|
266
232
|
// webpieces-disable max-lines-new-methods -- AST traversal with nested visitor function for keyword detection
|
|
267
|
-
function findAnyUnknownInFile(filePath
|
|
233
|
+
function findAnyUnknownInFile(filePath, workspaceRoot) {
|
|
268
234
|
const fullPath = path.join(workspaceRoot, filePath);
|
|
269
|
-
if (!fs.existsSync(fullPath))
|
|
270
|
-
|
|
235
|
+
if (!fs.existsSync(fullPath))
|
|
236
|
+
return [];
|
|
271
237
|
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
272
238
|
const fileLines = content.split('\n');
|
|
273
239
|
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
|
|
274
|
-
|
|
275
|
-
const violations: AnyUnknownInfo[] = [];
|
|
276
|
-
|
|
240
|
+
const violations = [];
|
|
277
241
|
// webpieces-disable max-lines-new-methods -- AST visitor needs to handle both any and unknown keywords with full context detection
|
|
278
|
-
function visit(node
|
|
242
|
+
function visit(node) {
|
|
279
243
|
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
280
244
|
try {
|
|
281
245
|
// Detect `any` keyword
|
|
@@ -285,7 +249,6 @@ function findAnyUnknownInFile(filePath: string, workspaceRoot: string): AnyUnkno
|
|
|
285
249
|
ts.forEachChild(node, visit);
|
|
286
250
|
return;
|
|
287
251
|
}
|
|
288
|
-
|
|
289
252
|
const startPos = node.getStart(sourceFile);
|
|
290
253
|
if (startPos >= 0) {
|
|
291
254
|
const pos = sourceFile.getLineAndCharacterOfPosition(startPos);
|
|
@@ -293,7 +256,6 @@ function findAnyUnknownInFile(filePath: string, workspaceRoot: string): AnyUnkno
|
|
|
293
256
|
const column = pos.character + 1;
|
|
294
257
|
const context = getViolationContext(node, sourceFile);
|
|
295
258
|
const disabled = hasDisableComment(fileLines, line);
|
|
296
|
-
|
|
297
259
|
violations.push({
|
|
298
260
|
line,
|
|
299
261
|
column,
|
|
@@ -303,7 +265,6 @@ function findAnyUnknownInFile(filePath: string, workspaceRoot: string): AnyUnkno
|
|
|
303
265
|
});
|
|
304
266
|
}
|
|
305
267
|
}
|
|
306
|
-
|
|
307
268
|
// Detect `unknown` keyword
|
|
308
269
|
if (node.kind === ts.SyntaxKind.UnknownKeyword) {
|
|
309
270
|
// Skip catch clause variable types: catch (err: unknown) is allowed
|
|
@@ -311,7 +272,6 @@ function findAnyUnknownInFile(filePath: string, workspaceRoot: string): AnyUnkno
|
|
|
311
272
|
ts.forEachChild(node, visit);
|
|
312
273
|
return;
|
|
313
274
|
}
|
|
314
|
-
|
|
315
275
|
const startPos = node.getStart(sourceFile);
|
|
316
276
|
if (startPos >= 0) {
|
|
317
277
|
const pos = sourceFile.getLineAndCharacterOfPosition(startPos);
|
|
@@ -319,7 +279,6 @@ function findAnyUnknownInFile(filePath: string, workspaceRoot: string): AnyUnkno
|
|
|
319
279
|
const column = pos.character + 1;
|
|
320
280
|
const context = getViolationContext(node, sourceFile);
|
|
321
281
|
const disabled = hasDisableComment(fileLines, line);
|
|
322
|
-
|
|
323
282
|
violations.push({
|
|
324
283
|
line,
|
|
325
284
|
column,
|
|
@@ -329,45 +288,35 @@ function findAnyUnknownInFile(filePath: string, workspaceRoot: string): AnyUnkno
|
|
|
329
288
|
});
|
|
330
289
|
}
|
|
331
290
|
}
|
|
332
|
-
}
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
333
293
|
//const error = toError(err);
|
|
334
294
|
// Skip nodes that cause errors during analysis
|
|
335
295
|
}
|
|
336
|
-
|
|
337
296
|
ts.forEachChild(node, visit);
|
|
338
297
|
}
|
|
339
|
-
|
|
340
298
|
visit(sourceFile);
|
|
341
299
|
return violations;
|
|
342
300
|
}
|
|
343
|
-
|
|
344
301
|
/**
|
|
345
302
|
* MODIFIED_CODE mode: Flag violations on changed lines in diff hunks.
|
|
346
303
|
* This is LINE-BASED detection.
|
|
347
304
|
*/
|
|
348
305
|
// webpieces-disable max-lines-new-methods -- File iteration with diff parsing and line filtering
|
|
349
|
-
function findViolationsForModifiedCode(
|
|
350
|
-
|
|
351
|
-
changedFiles: string[],
|
|
352
|
-
base: string,
|
|
353
|
-
head: string | undefined,
|
|
354
|
-
disableAllowed: boolean
|
|
355
|
-
): AnyUnknownViolation[] {
|
|
356
|
-
const violations: AnyUnknownViolation[] = [];
|
|
357
|
-
|
|
306
|
+
function findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed) {
|
|
307
|
+
const violations = [];
|
|
358
308
|
for (const file of changedFiles) {
|
|
359
309
|
const diff = getFileDiff(workspaceRoot, file, base, head);
|
|
360
310
|
const changedLines = getChangedLineNumbers(diff);
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
311
|
+
if (changedLines.size === 0)
|
|
312
|
+
continue;
|
|
364
313
|
const allViolations = findAnyUnknownInFile(file, workspaceRoot);
|
|
365
|
-
|
|
366
314
|
for (const v of allViolations) {
|
|
367
|
-
if (disableAllowed && v.hasDisableComment)
|
|
315
|
+
if (disableAllowed && v.hasDisableComment)
|
|
316
|
+
continue;
|
|
368
317
|
// LINE-BASED: Only include if the violation is on a changed line
|
|
369
|
-
if (!changedLines.has(v.line))
|
|
370
|
-
|
|
318
|
+
if (!changedLines.has(v.line))
|
|
319
|
+
continue;
|
|
371
320
|
violations.push({
|
|
372
321
|
file,
|
|
373
322
|
line: v.line,
|
|
@@ -377,22 +326,18 @@ function findViolationsForModifiedCode(
|
|
|
377
326
|
});
|
|
378
327
|
}
|
|
379
328
|
}
|
|
380
|
-
|
|
381
329
|
return violations;
|
|
382
330
|
}
|
|
383
|
-
|
|
384
331
|
/**
|
|
385
332
|
* MODIFIED_FILES mode: Flag ALL violations in files that were modified.
|
|
386
333
|
*/
|
|
387
|
-
function findViolationsForModifiedFiles(workspaceRoot
|
|
388
|
-
const violations
|
|
389
|
-
|
|
334
|
+
function findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed) {
|
|
335
|
+
const violations = [];
|
|
390
336
|
for (const file of changedFiles) {
|
|
391
337
|
const allViolations = findAnyUnknownInFile(file, workspaceRoot);
|
|
392
|
-
|
|
393
338
|
for (const v of allViolations) {
|
|
394
|
-
if (disableAllowed && v.hasDisableComment)
|
|
395
|
-
|
|
339
|
+
if (disableAllowed && v.hasDisableComment)
|
|
340
|
+
continue;
|
|
396
341
|
violations.push({
|
|
397
342
|
file,
|
|
398
343
|
line: v.line,
|
|
@@ -402,50 +347,47 @@ function findViolationsForModifiedFiles(workspaceRoot: string, changedFiles: str
|
|
|
402
347
|
});
|
|
403
348
|
}
|
|
404
349
|
}
|
|
405
|
-
|
|
406
350
|
return violations;
|
|
407
351
|
}
|
|
408
|
-
|
|
409
352
|
/**
|
|
410
353
|
* Auto-detect the base branch by finding the merge-base with origin/main.
|
|
411
354
|
*/
|
|
412
|
-
function detectBase(workspaceRoot
|
|
355
|
+
function detectBase(workspaceRoot) {
|
|
413
356
|
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
414
357
|
try {
|
|
415
|
-
const mergeBase = execSync('git merge-base HEAD origin/main', {
|
|
358
|
+
const mergeBase = (0, child_process_1.execSync)('git merge-base HEAD origin/main', {
|
|
416
359
|
cwd: workspaceRoot,
|
|
417
360
|
encoding: 'utf-8',
|
|
418
361
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
419
362
|
}).trim();
|
|
420
|
-
|
|
421
363
|
if (mergeBase) {
|
|
422
364
|
return mergeBase;
|
|
423
365
|
}
|
|
424
|
-
}
|
|
366
|
+
}
|
|
367
|
+
catch (err) {
|
|
425
368
|
//const error = toError(err);
|
|
426
369
|
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
427
370
|
try {
|
|
428
|
-
const mergeBase = execSync('git merge-base HEAD main', {
|
|
371
|
+
const mergeBase = (0, child_process_1.execSync)('git merge-base HEAD main', {
|
|
429
372
|
cwd: workspaceRoot,
|
|
430
373
|
encoding: 'utf-8',
|
|
431
374
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
432
375
|
}).trim();
|
|
433
|
-
|
|
434
376
|
if (mergeBase) {
|
|
435
377
|
return mergeBase;
|
|
436
378
|
}
|
|
437
|
-
}
|
|
379
|
+
}
|
|
380
|
+
catch (err2) {
|
|
438
381
|
//const error2 = toError(err2);
|
|
439
382
|
// Ignore
|
|
440
383
|
}
|
|
441
384
|
}
|
|
442
385
|
return null;
|
|
443
386
|
}
|
|
444
|
-
|
|
445
387
|
/**
|
|
446
388
|
* Report violations to console.
|
|
447
389
|
*/
|
|
448
|
-
function reportViolations(violations
|
|
390
|
+
function reportViolations(violations, mode) {
|
|
449
391
|
console.error('');
|
|
450
392
|
console.error('❌ `any` and `unknown` keywords found! Use specific types instead.');
|
|
451
393
|
console.error('');
|
|
@@ -457,13 +399,11 @@ function reportViolations(violations: AnyUnknownViolation[], mode: NoAnyUnknownM
|
|
|
457
399
|
console.error(' BAD: function process(input: unknown): unknown { }');
|
|
458
400
|
console.error(' GOOD: function process(input: ValidInput): ValidOutput { }');
|
|
459
401
|
console.error('');
|
|
460
|
-
|
|
461
402
|
for (const v of violations) {
|
|
462
403
|
console.error(` ❌ ${v.file}:${v.line}:${v.column}`);
|
|
463
404
|
console.error(` \`${v.keyword}\` keyword in ${v.context}`);
|
|
464
405
|
}
|
|
465
406
|
console.error('');
|
|
466
|
-
|
|
467
407
|
console.error(' To fix: Replace with specific types or interfaces');
|
|
468
408
|
console.error('');
|
|
469
409
|
console.error(' Escape hatch (use sparingly):');
|
|
@@ -472,12 +412,11 @@ function reportViolations(violations: AnyUnknownViolation[], mode: NoAnyUnknownM
|
|
|
472
412
|
console.error(` Current mode: ${mode}`);
|
|
473
413
|
console.error('');
|
|
474
414
|
}
|
|
475
|
-
|
|
476
415
|
/**
|
|
477
416
|
* Resolve mode considering ignoreModifiedUntilEpoch override.
|
|
478
417
|
* When active, downgrades to OFF. When expired, logs a warning.
|
|
479
418
|
*/
|
|
480
|
-
function resolveMode(normalMode
|
|
419
|
+
function resolveMode(normalMode, epoch) {
|
|
481
420
|
if (epoch === undefined || normalMode === 'OFF') {
|
|
482
421
|
return normalMode;
|
|
483
422
|
}
|
|
@@ -490,63 +429,47 @@ function resolveMode(normalMode: NoAnyUnknownMode, epoch: number | undefined): N
|
|
|
490
429
|
}
|
|
491
430
|
return normalMode;
|
|
492
431
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
options: ValidateNoAnyUnknownOptions,
|
|
496
|
-
workspaceRoot: string
|
|
497
|
-
): Promise<ExecutorResult> {
|
|
498
|
-
const mode: NoAnyUnknownMode = resolveMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch);
|
|
432
|
+
async function runValidator(options, workspaceRoot) {
|
|
433
|
+
const mode = resolveMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch);
|
|
499
434
|
const disableAllowed = options.disableAllowed ?? true;
|
|
500
|
-
|
|
501
435
|
if (mode === 'OFF') {
|
|
502
436
|
console.log('\n⏭️ Skipping no-any-unknown validation (mode: OFF)');
|
|
503
437
|
console.log('');
|
|
504
438
|
return { success: true };
|
|
505
439
|
}
|
|
506
|
-
|
|
507
440
|
console.log('\n📏 Validating No Any/Unknown\n');
|
|
508
441
|
console.log(` Mode: ${mode}`);
|
|
509
|
-
|
|
510
442
|
let base = process.env['NX_BASE'];
|
|
511
443
|
const head = process.env['NX_HEAD'];
|
|
512
|
-
|
|
513
444
|
if (!base) {
|
|
514
445
|
base = detectBase(workspaceRoot) ?? undefined;
|
|
515
|
-
|
|
516
446
|
if (!base) {
|
|
517
447
|
console.log('\n⏭️ Skipping no-any-unknown validation (could not detect base branch)');
|
|
518
448
|
console.log('');
|
|
519
449
|
return { success: true };
|
|
520
450
|
}
|
|
521
451
|
}
|
|
522
|
-
|
|
523
452
|
console.log(` Base: ${base}`);
|
|
524
453
|
console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);
|
|
525
454
|
console.log('');
|
|
526
|
-
|
|
527
455
|
const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);
|
|
528
|
-
|
|
529
456
|
if (changedFiles.length === 0) {
|
|
530
457
|
console.log('✅ No TypeScript files changed');
|
|
531
458
|
return { success: true };
|
|
532
459
|
}
|
|
533
|
-
|
|
534
460
|
console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);
|
|
535
|
-
|
|
536
|
-
let violations: AnyUnknownViolation[] = [];
|
|
537
|
-
|
|
461
|
+
let violations = [];
|
|
538
462
|
if (mode === 'MODIFIED_CODE') {
|
|
539
463
|
violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed);
|
|
540
|
-
}
|
|
464
|
+
}
|
|
465
|
+
else if (mode === 'MODIFIED_FILES') {
|
|
541
466
|
violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed);
|
|
542
467
|
}
|
|
543
|
-
|
|
544
468
|
if (violations.length === 0) {
|
|
545
469
|
console.log('✅ No any/unknown keywords found');
|
|
546
470
|
return { success: true };
|
|
547
471
|
}
|
|
548
|
-
|
|
549
472
|
reportViolations(violations, mode);
|
|
550
|
-
|
|
551
473
|
return { success: false };
|
|
552
474
|
}
|
|
475
|
+
//# sourceMappingURL=validate-no-any-unknown.js.map
|