@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-no-direct-api-resolver.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-no-direct-api-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate No Direct API in Resolver Executor\n *\n * Validates two Angular anti-patterns using LINE-BASED detection:\n *\n * ============================================================================\n * VIOLATIONS (BAD) - These patterns are flagged:\n * ============================================================================\n *\n * 1. In *.routes.ts files: inject(XxxApi) — resolvers should inject services, not APIs directly\n * 2. In *.component.ts files: this.<field>.snapshot.data — components should subscribe to\n * service BehaviorSubjects, not read route snapshot data\n *\n * ============================================================================\n * CORRECT PATTERNS (GOOD)\n * ============================================================================\n *\n * 1. In resolvers: inject(XxxService) which calls the API internally\n * 2. In components: this.myService.someObservable$ (subscribe to service BehaviorSubjects)\n *\n * ============================================================================\n * MODES (LINE-BASED)\n * ============================================================================\n * - OFF: Skip validation entirely\n * - MODIFIED_CODE: Flag violations on changed lines (lines in diff hunks)\n * - NEW_AND_MODIFIED_METHODS: Flag violations in new/modified method/route scopes\n * - MODIFIED_FILES: Flag ALL violations in files that were modified\n *\n * ============================================================================\n * ESCAPE HATCH\n * ============================================================================\n * Add comment above the violation:\n * // webpieces-disable no-direct-api-resolver -- [your justification]\n * const myApi = inject(MyApi);\n */\n\nimport { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\nimport { getFileDiff, getChangedLineNumbers, findNewMethodSignaturesInDiff } from './diff-utils';\n\nexport type NoDirectApiResolverMode = 'OFF' | 'MODIFIED_CODE' | 'NEW_AND_MODIFIED_METHODS' | 'MODIFIED_FILES';\n\nexport interface ValidateNoDirectApiResolverOptions {\n mode?: NoDirectApiResolverMode;\n disableAllowed?: boolean;\n ignoreModifiedUntilEpoch?: number;\n enforcePaths?: string[];\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\ninterface Violation {\n file: string;\n line: number;\n column: number;\n context: string;\n}\n\ninterface ViolationInfo {\n line: number;\n column: number;\n context: string;\n hasDisableComment: boolean;\n}\n\n/**\n * Get changed TypeScript files between base and head (or working tree if head not specified).\n */\n// webpieces-disable max-lines-new-methods -- Git command handling with untracked files requires multiple code paths\nfunction getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: string): string[] {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const diffTarget = head ? `${base} ${head}` : base;\n const output = execSync(`git diff --name-only ${diffTarget} -- '*.ts' '*.tsx'`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const changedFiles = output\n .trim()\n .split('\\n')\n .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));\n\n if (!head) {\n // 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 const allFiles = new Set([...changedFiles, ...untrackedFiles]);\n return Array.from(allFiles);\n } catch (err: unknown) {\n //const error = toError(err);\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 * Check if a line contains a webpieces-disable comment for no-direct-api-resolver.\n */\nfunction hasDisableComment(lines: string[], lineNumber: number): boolean {\n const startCheck = Math.max(0, lineNumber - 5);\n for (let i = lineNumber - 2; i >= startCheck; i--) {\n const line = lines[i]?.trim() ?? '';\n if (line.startsWith('function ') || line.startsWith('class ') || line.endsWith('}')) {\n break;\n }\n if (line.includes('webpieces-disable') && line.includes('no-direct-api-resolver')) {\n return true;\n }\n }\n return false;\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 // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\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 (err: unknown) {\n //const error = toError(err);\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\n }\n }\n return null;\n}\n\n/**\n * Find inject(XxxApi) calls in *.routes.ts files.\n * Flags any CallExpression where callee is `inject` and the first argument is an identifier ending with `Api`.\n */\nfunction findDirectApiInjections(filePath: string, workspaceRoot: string, disableAllowed: boolean): ViolationInfo[] {\n if (!filePath.endsWith('.routes.ts')) return [];\n\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 violations: ViolationInfo[] = [];\n\n function visit(node: ts.Node): void {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n if (ts.isCallExpression(node)) {\n const callee = node.expression;\n if (ts.isIdentifier(callee) && callee.text === 'inject') {\n const firstArg = node.arguments[0];\n if (firstArg && ts.isIdentifier(firstArg) && firstArg.text.endsWith('Api')) {\n const startPos = node.getStart(sourceFile);\n if (startPos >= 0) {\n const pos = sourceFile.getLineAndCharacterOfPosition(startPos);\n const line = pos.line + 1;\n const column = pos.character + 1;\n const disabled = hasDisableComment(fileLines, line);\n\n if (!disableAllowed && disabled) {\n violations.push({ line, column, context: `inject(${firstArg.text}) in route resolver`, hasDisableComment: false });\n } else {\n violations.push({ line, column, context: `inject(${firstArg.text}) in route resolver`, hasDisableComment: disabled });\n }\n }\n }\n }\n }\n } catch (err: unknown) {\n //const error = toError(err);\n // Skip nodes that cause errors during analysis\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return violations;\n}\n\n/**\n * Find this.<field>.snapshot.data access patterns in *.component.ts files.\n * Flags PropertyAccessExpression chains: this.<anything>.snapshot.data\n */\nfunction findSnapshotDataAccess(filePath: string, workspaceRoot: string, disableAllowed: boolean): ViolationInfo[] {\n if (!filePath.endsWith('.component.ts')) return [];\n\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 violations: ViolationInfo[] = [];\n\n function visit(node: ts.Node): void {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Looking for: this.<field>.snapshot.data\n // AST shape: PropertyAccessExpression(.data) -> PropertyAccessExpression(.snapshot) -> PropertyAccessExpression(.<field>) -> this\n if (ts.isPropertyAccessExpression(node) && node.name.text === 'data') {\n const snapshotAccess = node.expression;\n if (ts.isPropertyAccessExpression(snapshotAccess) && snapshotAccess.name.text === 'snapshot') {\n const fieldAccess = snapshotAccess.expression;\n if (ts.isPropertyAccessExpression(fieldAccess)) {\n const receiver = fieldAccess.expression;\n if (receiver.kind === ts.SyntaxKind.ThisKeyword) {\n const fieldName = fieldAccess.name.text;\n const startPos = node.getStart(sourceFile);\n if (startPos >= 0) {\n const pos = sourceFile.getLineAndCharacterOfPosition(startPos);\n const line = pos.line + 1;\n const column = pos.character + 1;\n const disabled = hasDisableComment(fileLines, line);\n\n if (!disableAllowed && disabled) {\n violations.push({ line, column, context: `this.${fieldName}.snapshot.data in component`, hasDisableComment: false });\n } else {\n violations.push({ line, column, context: `this.${fieldName}.snapshot.data in component`, hasDisableComment: disabled });\n }\n }\n }\n }\n }\n }\n } catch (err: unknown) {\n //const error = toError(err);\n // Skip nodes that cause errors during analysis\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return violations;\n}\n\n/**\n * Find all violations in a file (both inject(Api) and snapshot.data patterns).\n */\nfunction findViolationsInFile(filePath: string, workspaceRoot: string, disableAllowed: boolean): ViolationInfo[] {\n const apiViolations = findDirectApiInjections(filePath, workspaceRoot, disableAllowed);\n const snapshotViolations = findSnapshotDataAccess(filePath, workspaceRoot, disableAllowed);\n return [...apiViolations, ...snapshotViolations];\n}\n\n/**\n * MODIFIED_CODE mode: Flag violations on changed lines in diff hunks.\n */\n// webpieces-disable max-lines-new-methods -- File iteration with diff parsing and line filtering\nfunction findViolationsForModifiedCode(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head: string | undefined,\n disableAllowed: boolean\n): Violation[] {\n const violations: Violation[] = [];\n\n for (const file of changedFiles) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const changedLines = getChangedLineNumbers(diff);\n\n if (changedLines.size === 0) continue;\n\n const allViolations = findViolationsInFile(file, workspaceRoot, disableAllowed);\n\n for (const v of allViolations) {\n if (disableAllowed && v.hasDisableComment) continue;\n // LINE-BASED: Only include if the violation is on a changed line\n if (!changedLines.has(v.line)) continue;\n\n violations.push({\n file,\n line: v.line,\n column: v.column,\n context: v.context,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * MODIFIED_FILES mode: Flag ALL violations in files that were modified.\n */\nfunction findViolationsForModifiedFiles(workspaceRoot: string, changedFiles: string[], disableAllowed: boolean): Violation[] {\n const violations: Violation[] = [];\n\n for (const file of changedFiles) {\n const allViolations = findViolationsInFile(file, workspaceRoot, disableAllowed);\n\n for (const v of allViolations) {\n if (disableAllowed && v.hasDisableComment) continue;\n\n violations.push({\n file,\n line: v.line,\n column: v.column,\n context: v.context,\n });\n }\n }\n\n return violations;\n}\n\ninterface RangeInfo {\n name: string;\n startLine: number;\n endLine: number;\n}\n\n/**\n * Find route object ranges in *.routes.ts files.\n * A route object is an ObjectLiteralExpression that contains (directly or in descendants)\n * a `resolve` property. Returns the line range of each such top-level route object.\n */\nfunction findRouteObjectRanges(filePath: string, workspaceRoot: string): RangeInfo[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n\n const ranges: RangeInfo[] = [];\n\n function hasResolveProperty(node: ts.Node): boolean {\n if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) && node.name.text === 'resolve') {\n return true;\n }\n let found = false;\n ts.forEachChild(node, (child) => {\n if (hasResolveProperty(child)) {\n found = true;\n }\n });\n return found;\n }\n\n function visitTopLevel(node: ts.Node): void {\n if (ts.isObjectLiteralExpression(node) && hasResolveProperty(node)) {\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());\n ranges.push({\n name: `route@${start.line + 1}`,\n startLine: start.line + 1,\n endLine: end.line + 1,\n });\n return;\n }\n ts.forEachChild(node, visitTopLevel);\n }\n\n visitTopLevel(sourceFile);\n return ranges;\n}\n\n/**\n * Find method/function ranges in *.component.ts files.\n * Returns ranges for class methods, function declarations, and arrow functions in variable declarations.\n */\nfunction findMethodRanges(filePath: string, workspaceRoot: string): RangeInfo[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n\n const ranges: RangeInfo[] = [];\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 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 ranges.push({ name: methodName, startLine, endLine });\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return ranges;\n}\n\n/**\n * NEW_AND_MODIFIED_METHODS mode: Flag violations in new/modified method/route scopes.\n * - For *.routes.ts: If any line in a route object is changed, flag all inject(XxxApi) violations in that route\n * - For *.component.ts: If a method is new/modified, flag all snapshot.data violations in that method\n */\n// webpieces-disable max-lines-new-methods -- Method-scoped validation with route objects and component methods\nfunction findViolationsForModifiedMethods(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head: string | undefined,\n disableAllowed: boolean\n): Violation[] {\n const violations: Violation[] = [];\n\n for (const file of changedFiles) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const changedLines = getChangedLineNumbers(diff);\n const newMethodNames = findNewMethodSignaturesInDiff(diff);\n\n if (changedLines.size === 0 && newMethodNames.size === 0) continue;\n\n if (file.endsWith('.routes.ts')) {\n const routeRanges = findRouteObjectRanges(file, workspaceRoot);\n const allViolations = findDirectApiInjections(file, workspaceRoot, disableAllowed);\n\n for (const range of routeRanges) {\n let rangeHasChanges = false;\n for (let line = range.startLine; line <= range.endLine; line++) {\n if (changedLines.has(line)) {\n rangeHasChanges = true;\n break;\n }\n }\n if (!rangeHasChanges) continue;\n\n for (const v of allViolations) {\n if (disableAllowed && v.hasDisableComment) continue;\n if (v.line >= range.startLine && v.line <= range.endLine) {\n violations.push({\n file,\n line: v.line,\n column: v.column,\n context: v.context,\n });\n }\n }\n }\n } else if (file.endsWith('.component.ts')) {\n const methodRanges = findMethodRanges(file, workspaceRoot);\n const allViolations = findSnapshotDataAccess(file, workspaceRoot, disableAllowed);\n\n for (const range of methodRanges) {\n const isNewMethod = newMethodNames.has(range.name);\n let rangeHasChanges = false;\n if (!isNewMethod) {\n for (let line = range.startLine; line <= range.endLine; line++) {\n if (changedLines.has(line)) {\n rangeHasChanges = true;\n break;\n }\n }\n }\n if (!isNewMethod && !rangeHasChanges) continue;\n\n for (const v of allViolations) {\n if (disableAllowed && v.hasDisableComment) continue;\n if (v.line >= range.startLine && v.line <= range.endLine) {\n violations.push({\n file,\n line: v.line,\n column: v.column,\n context: v.context,\n });\n }\n }\n }\n }\n }\n\n return violations;\n}\n\n/**\n * Report violations to console.\n */\n// webpieces-disable max-lines-new-methods -- Console output with examples and escape hatch information\nfunction reportViolations(violations: Violation[], mode: NoDirectApiResolverMode, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c Direct API usage in resolvers or snapshot.data in components found!');\n console.error('');\n console.error('\\ud83d\\udcda Resolvers should use services, and components should subscribe to service observables:');\n console.error('');\n console.error(' BAD (in *.routes.ts resolver):');\n console.error(' const myApi = inject(MyApi);');\n console.error(' resolve: () => inject(MyApi).fetchData()');\n console.error('');\n console.error(' GOOD (in *.routes.ts resolver):');\n console.error(' const myService = inject(MyService);');\n console.error(' resolve: () => inject(MyService).loadData()');\n console.error('');\n console.error(' BAD (in *.component.ts):');\n console.error(' const data = this.route.snapshot.data;');\n console.error('');\n console.error(' GOOD (in *.component.ts):');\n console.error(' this.myService.data$.subscribe(data => ...)');\n console.error('');\n\n for (const v of violations) {\n console.error(` \\u274c ${v.file}:${v.line}:${v.column}`);\n console.error(` ${v.context}`);\n }\n console.error('');\n\n if (disableAllowed) {\n console.error(' Escape hatch (use sparingly):');\n console.error(' // webpieces-disable no-direct-api-resolver -- [your reason]');\n } else {\n console.error(' Escape hatch: DISABLED (disableAllowed: false)');\n console.error(' Disable comments are ignored. Fix the pattern directly.');\n }\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n}\n\n/**\n * Resolve mode considering ignoreModifiedUntilEpoch override.\n * When active, downgrades to OFF. When expired, logs a warning.\n */\nfunction resolveMode(normalMode: NoDirectApiResolverMode, epoch: number | undefined): NoDirectApiResolverMode {\n if (epoch === undefined || normalMode === 'OFF') {\n return normalMode;\n }\n const nowSeconds = Date.now() / 1000;\n if (nowSeconds < epoch) {\n const expiresDate = new Date(epoch * 1000).toISOString().split('T')[0];\n console.log(`\\n\\u23ed\\ufe0f Skipping no-direct-api-resolver validation (ignoreModifiedUntilEpoch active, expires: ${expiresDate})`);\n console.log('');\n return 'OFF';\n }\n return normalMode;\n}\n\n/**\n * Filter changed files to only those under enforcePaths (if configured).\n */\nfunction filterByEnforcePaths(changedFiles: string[], enforcePaths: string[] | undefined): string[] {\n if (!enforcePaths || enforcePaths.length === 0) {\n return changedFiles;\n }\n return changedFiles.filter((file) =>\n enforcePaths.some((prefix) => file.startsWith(prefix))\n );\n}\n\n/**\n * Filter to only relevant Angular files (*.routes.ts and *.component.ts).\n */\nfunction filterRelevantFiles(changedFiles: string[]): string[] {\n return changedFiles.filter((file) =>\n file.endsWith('.routes.ts') || file.endsWith('.component.ts')\n );\n}\n\nexport default async function runValidator(\n options: ValidateNoDirectApiResolverOptions,\n workspaceRoot: string\n): Promise<ExecutorResult> {\n const mode: NoDirectApiResolverMode = resolveMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch);\n const disableAllowed = options.disableAllowed ?? true;\n\n if (mode === 'OFF') {\n console.log('\\n\\u23ed\\ufe0f Skipping no-direct-api-resolver validation (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating No Direct API in Resolver\\n');\n console.log(` Mode: ${mode}`);\n\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 no-direct-api-resolver validation (could not detect base branch)');\n console.log('');\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const allChangedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);\n const scopedFiles = filterByEnforcePaths(allChangedFiles, options.enforcePaths);\n const changedFiles = filterRelevantFiles(scopedFiles);\n\n if (changedFiles.length === 0) {\n console.log('\\u2705 No relevant Angular files changed (*.routes.ts, *.component.ts)');\n return { success: true };\n }\n\n console.log(`\\ud83d\\udcc2 Checking ${changedFiles.length} changed file(s)...`);\n\n let violations: Violation[] = [];\n\n if (mode === 'MODIFIED_CODE') {\n violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed);\n } else if (mode === 'NEW_AND_MODIFIED_METHODS') {\n violations = findViolationsForModifiedMethods(workspaceRoot, changedFiles, base, head, disableAllowed);\n } else if (mode === 'MODIFIED_FILES') {\n violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed);\n }\n\n if (violations.length === 0) {\n console.log('\\u2705 No direct API resolver patterns found');\n return { success: true };\n }\n\n reportViolations(violations, mode, disableAllowed);\n\n return { success: false };\n}\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate No Implicit Any Executor
|
|
3
|
+
*
|
|
4
|
+
* Flags function parameters, variables, and object-literal properties whose
|
|
5
|
+
* types collapse to the implicit `any` produced by TypeScript inference when
|
|
6
|
+
* an annotation is missing. Pairs with validate-no-any-unknown (which bans
|
|
7
|
+
* the literal keyword) so together they force developers to write real types.
|
|
8
|
+
*
|
|
9
|
+
* Detection leverages the TypeScript compiler directly: we build a ts.Program
|
|
10
|
+
* from the project's tsconfig.json with `noImplicitAny: true` overridden, then
|
|
11
|
+
* filter pre-emit diagnostics to the set of codes that describe implicit-any
|
|
12
|
+
* inferences (TS7006, TS7005, TS7018, etc.) and map them back to changed lines.
|
|
13
|
+
*
|
|
14
|
+
* ============================================================================
|
|
15
|
+
* MODES (LINE-BASED)
|
|
16
|
+
* ============================================================================
|
|
17
|
+
* - OFF: Skip validation entirely.
|
|
18
|
+
* - MODIFIED_CODE: Flag implicit-any on changed lines (lines in diff hunks).
|
|
19
|
+
* - MODIFIED_FILES: Flag ALL implicit-any in files that were modified.
|
|
20
|
+
*
|
|
21
|
+
* ============================================================================
|
|
22
|
+
* ESCAPE HATCH
|
|
23
|
+
* ============================================================================
|
|
24
|
+
* // webpieces-disable no-implicit-any -- [your justification]
|
|
25
|
+
* function handler(x) { ... }
|
|
26
|
+
*/
|
|
27
|
+
export type NoImplicitAnyMode = 'OFF' | 'MODIFIED_CODE' | 'MODIFIED_FILES';
|
|
28
|
+
export interface ValidateNoImplicitAnyOptions {
|
|
29
|
+
mode?: NoImplicitAnyMode;
|
|
30
|
+
disableAllowed?: boolean;
|
|
31
|
+
ignoreModifiedUntilEpoch?: number;
|
|
32
|
+
}
|
|
33
|
+
export interface ExecutorResult {
|
|
34
|
+
success: boolean;
|
|
35
|
+
}
|
|
36
|
+
export default function runValidator(options: ValidateNoImplicitAnyOptions, workspaceRoot: string): Promise<ExecutorResult>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Validate No Implicit Any Executor
|
|
3
4
|
*
|
|
@@ -24,111 +25,90 @@
|
|
|
24
25
|
* // webpieces-disable no-implicit-any -- [your justification]
|
|
25
26
|
* function handler(x) { ... }
|
|
26
27
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
export interface ValidateNoImplicitAnyOptions {
|
|
36
|
-
mode?: NoImplicitAnyMode;
|
|
37
|
-
disableAllowed?: boolean;
|
|
38
|
-
ignoreModifiedUntilEpoch?: number;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface ExecutorResult {
|
|
42
|
-
success: boolean;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
interface ImplicitAnyViolation {
|
|
46
|
-
file: string;
|
|
47
|
-
line: number;
|
|
48
|
-
column: number;
|
|
49
|
-
code: number;
|
|
50
|
-
message: string;
|
|
51
|
-
hasDisableComment: boolean;
|
|
52
|
-
}
|
|
53
|
-
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.default = runValidator;
|
|
30
|
+
const tslib_1 = require("tslib");
|
|
31
|
+
const child_process_1 = require("child_process");
|
|
32
|
+
const fs = tslib_1.__importStar(require("fs"));
|
|
33
|
+
const path = tslib_1.__importStar(require("path"));
|
|
34
|
+
const ts = tslib_1.__importStar(require("typescript"));
|
|
54
35
|
// TS diagnostic codes that describe an implicit-any inference. TS7010 (missing
|
|
55
36
|
// return-type annotation) is intentionally omitted because it is already
|
|
56
37
|
// covered by the sibling `require-return-type` validator.
|
|
57
|
-
const IMPLICIT_ANY_CODES
|
|
38
|
+
const IMPLICIT_ANY_CODES = new Set([
|
|
58
39
|
7005, 7006, 7008, 7015, 7018, 7019, 7031, 7034, 7053,
|
|
59
40
|
]);
|
|
60
|
-
|
|
61
|
-
function listUntrackedOrEmpty(workspaceRoot: string): string[] {
|
|
41
|
+
function listUntrackedOrEmpty(workspaceRoot) {
|
|
62
42
|
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
63
43
|
try {
|
|
64
|
-
const output = execSync(`git ls-files --others --exclude-standard '*.ts' '*.tsx'`, {
|
|
44
|
+
const output = (0, child_process_1.execSync)(`git ls-files --others --exclude-standard '*.ts' '*.tsx'`, {
|
|
65
45
|
cwd: workspaceRoot,
|
|
66
46
|
encoding: 'utf-8',
|
|
67
47
|
});
|
|
68
|
-
return output.trim().split('\n').filter((f
|
|
69
|
-
}
|
|
48
|
+
return output.trim().split('\n').filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
70
51
|
//const error = toError(err);
|
|
71
52
|
return [];
|
|
72
53
|
}
|
|
73
54
|
}
|
|
74
|
-
|
|
75
|
-
function getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: string): string[] {
|
|
55
|
+
function getChangedTypeScriptFiles(workspaceRoot, base, head) {
|
|
76
56
|
const diffTarget = head ? `${base} ${head}` : base;
|
|
77
|
-
const output = execSync(`git diff --name-only ${diffTarget} -- '*.ts' '*.tsx'`, {
|
|
57
|
+
const output = (0, child_process_1.execSync)(`git diff --name-only ${diffTarget} -- '*.ts' '*.tsx'`, {
|
|
78
58
|
cwd: workspaceRoot,
|
|
79
59
|
encoding: 'utf-8',
|
|
80
60
|
});
|
|
81
|
-
const changed = output.trim().split('\n').filter((f
|
|
82
|
-
if (head)
|
|
61
|
+
const changed = output.trim().split('\n').filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));
|
|
62
|
+
if (head)
|
|
63
|
+
return changed;
|
|
83
64
|
return Array.from(new Set([...changed, ...listUntrackedOrEmpty(workspaceRoot)]));
|
|
84
65
|
}
|
|
85
|
-
|
|
86
|
-
function getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string {
|
|
66
|
+
function getFileDiff(workspaceRoot, file, base, head) {
|
|
87
67
|
const diffTarget = head ? `${base} ${head}` : base;
|
|
88
|
-
const diff = execSync(`git diff ${diffTarget} -- "${file}"`, {
|
|
68
|
+
const diff = (0, child_process_1.execSync)(`git diff ${diffTarget} -- "${file}"`, {
|
|
89
69
|
cwd: workspaceRoot,
|
|
90
70
|
encoding: 'utf-8',
|
|
91
71
|
});
|
|
92
|
-
if (diff || head)
|
|
72
|
+
if (diff || head)
|
|
73
|
+
return diff;
|
|
93
74
|
const fullPath = path.join(workspaceRoot, file);
|
|
94
|
-
if (!fs.existsSync(fullPath))
|
|
95
|
-
|
|
75
|
+
if (!fs.existsSync(fullPath))
|
|
76
|
+
return '';
|
|
77
|
+
const isUntracked = (0, child_process_1.execSync)(`git ls-files --others --exclude-standard "${file}"`, {
|
|
96
78
|
cwd: workspaceRoot,
|
|
97
79
|
encoding: 'utf-8',
|
|
98
80
|
}).trim();
|
|
99
|
-
if (!isUntracked)
|
|
81
|
+
if (!isUntracked)
|
|
82
|
+
return '';
|
|
100
83
|
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
101
84
|
const lines = content.split('\n');
|
|
102
85
|
const hunk = `@@ -0,0 +1,${String(lines.length)} @@`;
|
|
103
|
-
return hunk + '\n' + lines.map((line
|
|
86
|
+
return hunk + '\n' + lines.map((line) => `+${line}`).join('\n');
|
|
104
87
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const changedLines = new Set<number>();
|
|
88
|
+
function getChangedLineNumbers(diffContent) {
|
|
89
|
+
const changedLines = new Set();
|
|
108
90
|
const lines = diffContent.split('\n');
|
|
109
91
|
let currentLine = 0;
|
|
110
|
-
|
|
111
92
|
for (const line of lines) {
|
|
112
93
|
const hunkMatch = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
|
|
113
94
|
if (hunkMatch) {
|
|
114
95
|
currentLine = parseInt(hunkMatch[1], 10);
|
|
115
96
|
continue;
|
|
116
97
|
}
|
|
117
|
-
|
|
118
98
|
if (line.startsWith('+') && !line.startsWith('+++')) {
|
|
119
99
|
changedLines.add(currentLine);
|
|
120
100
|
currentLine++;
|
|
121
|
-
}
|
|
101
|
+
}
|
|
102
|
+
else if (line.startsWith('-') && !line.startsWith('---')) {
|
|
122
103
|
// Deletions don't increment line number
|
|
123
|
-
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
124
106
|
currentLine++;
|
|
125
107
|
}
|
|
126
108
|
}
|
|
127
|
-
|
|
128
109
|
return changedLines;
|
|
129
110
|
}
|
|
130
|
-
|
|
131
|
-
function hasDisableComment(lines: string[], lineNumber: number): boolean {
|
|
111
|
+
function hasDisableComment(lines, lineNumber) {
|
|
132
112
|
const startCheck = Math.max(0, lineNumber - 5);
|
|
133
113
|
for (let i = lineNumber - 2; i >= startCheck; i--) {
|
|
134
114
|
const line = lines[i]?.trim() ?? '';
|
|
@@ -141,36 +121,37 @@ function hasDisableComment(lines: string[], lineNumber: number): boolean {
|
|
|
141
121
|
}
|
|
142
122
|
return false;
|
|
143
123
|
}
|
|
144
|
-
|
|
145
124
|
// Cache one ts.Program per tsconfig.json so multiple changed files in the
|
|
146
125
|
// same project share parse/binding cost.
|
|
147
|
-
const programCache = new Map
|
|
148
|
-
|
|
149
|
-
function findTsConfigForFile(absoluteFilePath: string, workspaceRoot: string): string | null {
|
|
126
|
+
const programCache = new Map();
|
|
127
|
+
function findTsConfigForFile(absoluteFilePath, workspaceRoot) {
|
|
150
128
|
const root = path.resolve(workspaceRoot);
|
|
151
129
|
let dir = path.dirname(absoluteFilePath);
|
|
152
130
|
while (dir.startsWith(root)) {
|
|
153
131
|
const candidate = path.join(dir, 'tsconfig.json');
|
|
154
|
-
if (fs.existsSync(candidate))
|
|
132
|
+
if (fs.existsSync(candidate))
|
|
133
|
+
return candidate;
|
|
155
134
|
const parent = path.dirname(dir);
|
|
156
|
-
if (parent === dir)
|
|
135
|
+
if (parent === dir)
|
|
136
|
+
break;
|
|
157
137
|
dir = parent;
|
|
158
138
|
}
|
|
159
139
|
return null;
|
|
160
140
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
141
|
+
function buildProgram(tsconfigPath) {
|
|
142
|
+
const configFile = ts.readConfigFile(tsconfigPath, (p) => ts.sys.readFile(p));
|
|
143
|
+
if (configFile.error)
|
|
144
|
+
return null;
|
|
165
145
|
const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.dirname(tsconfigPath));
|
|
166
|
-
if (parsed.errors.length > 0 || parsed.fileNames.length === 0)
|
|
167
|
-
|
|
146
|
+
if (parsed.errors.length > 0 || parsed.fileNames.length === 0)
|
|
147
|
+
return null;
|
|
148
|
+
const options = { ...parsed.options, noImplicitAny: true, noEmit: true, skipLibCheck: true };
|
|
168
149
|
return ts.createProgram({ rootNames: parsed.fileNames, options });
|
|
169
150
|
}
|
|
170
|
-
|
|
171
|
-
function getProgramForFile(absoluteFilePath: string, workspaceRoot: string): ts.Program | null {
|
|
151
|
+
function getProgramForFile(absoluteFilePath, workspaceRoot) {
|
|
172
152
|
const tsconfigPath = findTsConfigForFile(absoluteFilePath, workspaceRoot);
|
|
173
|
-
if (!tsconfigPath)
|
|
153
|
+
if (!tsconfigPath)
|
|
154
|
+
return null;
|
|
174
155
|
if (programCache.has(tsconfigPath)) {
|
|
175
156
|
return programCache.get(tsconfigPath) ?? null;
|
|
176
157
|
}
|
|
@@ -178,28 +159,27 @@ function getProgramForFile(absoluteFilePath: string, workspaceRoot: string): ts.
|
|
|
178
159
|
programCache.set(tsconfigPath, program);
|
|
179
160
|
return program;
|
|
180
161
|
}
|
|
181
|
-
|
|
182
|
-
function flattenMessage(message: string | ts.DiagnosticMessageChain): string {
|
|
162
|
+
function flattenMessage(message) {
|
|
183
163
|
return ts.flattenDiagnosticMessageText(message, ' ');
|
|
184
164
|
}
|
|
185
|
-
|
|
186
|
-
function findImplicitAnyInFile(filePath: string, workspaceRoot: string): ImplicitAnyViolation[] {
|
|
165
|
+
function findImplicitAnyInFile(filePath, workspaceRoot) {
|
|
187
166
|
const absolute = path.resolve(workspaceRoot, filePath);
|
|
188
|
-
if (!fs.existsSync(absolute))
|
|
189
|
-
|
|
167
|
+
if (!fs.existsSync(absolute))
|
|
168
|
+
return [];
|
|
190
169
|
const program = getProgramForFile(absolute, workspaceRoot);
|
|
191
|
-
if (!program)
|
|
192
|
-
|
|
170
|
+
if (!program)
|
|
171
|
+
return [];
|
|
193
172
|
const sourceFile = program.getSourceFile(absolute);
|
|
194
|
-
if (!sourceFile)
|
|
195
|
-
|
|
173
|
+
if (!sourceFile)
|
|
174
|
+
return [];
|
|
196
175
|
const fileLines = fs.readFileSync(absolute, 'utf-8').split('\n');
|
|
197
176
|
const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile);
|
|
198
|
-
const violations
|
|
199
|
-
|
|
177
|
+
const violations = [];
|
|
200
178
|
for (const diag of diagnostics) {
|
|
201
|
-
if (!IMPLICIT_ANY_CODES.has(diag.code))
|
|
202
|
-
|
|
179
|
+
if (!IMPLICIT_ANY_CODES.has(diag.code))
|
|
180
|
+
continue;
|
|
181
|
+
if (!diag.file || diag.start === undefined)
|
|
182
|
+
continue;
|
|
203
183
|
const pos = diag.file.getLineAndCharacterOfPosition(diag.start);
|
|
204
184
|
const line = pos.line + 1;
|
|
205
185
|
const column = pos.character + 1;
|
|
@@ -212,66 +192,56 @@ function findImplicitAnyInFile(filePath: string, workspaceRoot: string): Implici
|
|
|
212
192
|
hasDisableComment: hasDisableComment(fileLines, line),
|
|
213
193
|
});
|
|
214
194
|
}
|
|
215
|
-
|
|
216
195
|
return violations;
|
|
217
196
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
workspaceRoot: string,
|
|
221
|
-
changedFiles: string[],
|
|
222
|
-
base: string,
|
|
223
|
-
head: string | undefined,
|
|
224
|
-
disableAllowed: boolean,
|
|
225
|
-
): ImplicitAnyViolation[] {
|
|
226
|
-
const results: ImplicitAnyViolation[] = [];
|
|
197
|
+
function findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed) {
|
|
198
|
+
const results = [];
|
|
227
199
|
for (const file of changedFiles) {
|
|
228
200
|
const diff = getFileDiff(workspaceRoot, file, base, head);
|
|
229
201
|
const changedLines = getChangedLineNumbers(diff);
|
|
230
|
-
if (changedLines.size === 0)
|
|
231
|
-
|
|
202
|
+
if (changedLines.size === 0)
|
|
203
|
+
continue;
|
|
232
204
|
const all = findImplicitAnyInFile(file, workspaceRoot);
|
|
233
205
|
for (const v of all) {
|
|
234
|
-
if (disableAllowed && v.hasDisableComment)
|
|
235
|
-
|
|
206
|
+
if (disableAllowed && v.hasDisableComment)
|
|
207
|
+
continue;
|
|
208
|
+
if (!changedLines.has(v.line))
|
|
209
|
+
continue;
|
|
236
210
|
results.push(v);
|
|
237
211
|
}
|
|
238
212
|
}
|
|
239
213
|
return results;
|
|
240
214
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
workspaceRoot: string,
|
|
244
|
-
changedFiles: string[],
|
|
245
|
-
disableAllowed: boolean,
|
|
246
|
-
): ImplicitAnyViolation[] {
|
|
247
|
-
const results: ImplicitAnyViolation[] = [];
|
|
215
|
+
function findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed) {
|
|
216
|
+
const results = [];
|
|
248
217
|
for (const file of changedFiles) {
|
|
249
218
|
const all = findImplicitAnyInFile(file, workspaceRoot);
|
|
250
219
|
for (const v of all) {
|
|
251
|
-
if (disableAllowed && v.hasDisableComment)
|
|
220
|
+
if (disableAllowed && v.hasDisableComment)
|
|
221
|
+
continue;
|
|
252
222
|
results.push(v);
|
|
253
223
|
}
|
|
254
224
|
}
|
|
255
225
|
return results;
|
|
256
226
|
}
|
|
257
|
-
|
|
258
|
-
function detectBase(workspaceRoot: string): string | null {
|
|
227
|
+
function detectBase(workspaceRoot) {
|
|
259
228
|
for (const ref of ['origin/main', 'main']) {
|
|
260
229
|
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
261
230
|
try {
|
|
262
|
-
const merged = execSync(`git merge-base HEAD ${ref}`, {
|
|
231
|
+
const merged = (0, child_process_1.execSync)(`git merge-base HEAD ${ref}`, {
|
|
263
232
|
cwd: workspaceRoot, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'],
|
|
264
233
|
}).trim();
|
|
265
|
-
if (merged)
|
|
266
|
-
|
|
234
|
+
if (merged)
|
|
235
|
+
return merged;
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
267
238
|
//const error = toError(err);
|
|
268
239
|
// try next ref
|
|
269
240
|
}
|
|
270
241
|
}
|
|
271
242
|
return null;
|
|
272
243
|
}
|
|
273
|
-
|
|
274
|
-
function reportViolations(violations: ImplicitAnyViolation[], mode: NoImplicitAnyMode): void {
|
|
244
|
+
function reportViolations(violations, mode) {
|
|
275
245
|
console.error('');
|
|
276
246
|
console.error('\u274c Implicit-any inferences found! Add explicit type annotations.');
|
|
277
247
|
console.error('');
|
|
@@ -280,7 +250,6 @@ function reportViolations(violations: ImplicitAnyViolation[], mode: NoImplicitAn
|
|
|
280
250
|
console.error(' BAD: function process(input) { return input.length; }');
|
|
281
251
|
console.error(' GOOD: function process(input: string): number { return input.length; }');
|
|
282
252
|
console.error('');
|
|
283
|
-
|
|
284
253
|
for (const v of violations) {
|
|
285
254
|
console.error(` \u274c ${v.file}:${v.line}:${v.column}`);
|
|
286
255
|
console.error(` TS${v.code}: ${v.message}`);
|
|
@@ -292,8 +261,7 @@ function reportViolations(violations: ImplicitAnyViolation[], mode: NoImplicitAn
|
|
|
292
261
|
console.error(` Current mode: ${mode}`);
|
|
293
262
|
console.error('');
|
|
294
263
|
}
|
|
295
|
-
|
|
296
|
-
function resolveMode(normalMode: NoImplicitAnyMode, epoch: number | undefined): NoImplicitAnyMode {
|
|
264
|
+
function resolveMode(normalMode, epoch) {
|
|
297
265
|
if (epoch === undefined || normalMode === 'OFF') {
|
|
298
266
|
return normalMode;
|
|
299
267
|
}
|
|
@@ -306,26 +274,18 @@ function resolveMode(normalMode: NoImplicitAnyMode, epoch: number | undefined):
|
|
|
306
274
|
}
|
|
307
275
|
return normalMode;
|
|
308
276
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
options: ValidateNoImplicitAnyOptions,
|
|
312
|
-
workspaceRoot: string,
|
|
313
|
-
): Promise<ExecutorResult> {
|
|
314
|
-
const mode: NoImplicitAnyMode = resolveMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch);
|
|
277
|
+
async function runInternal(options, workspaceRoot) {
|
|
278
|
+
const mode = resolveMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch);
|
|
315
279
|
const disableAllowed = options.disableAllowed ?? true;
|
|
316
|
-
|
|
317
280
|
if (mode === 'OFF') {
|
|
318
281
|
console.log('\n\u23ed\ufe0f Skipping no-implicit-any validation (mode: OFF)');
|
|
319
282
|
console.log('');
|
|
320
283
|
return { success: true };
|
|
321
284
|
}
|
|
322
|
-
|
|
323
285
|
console.log('\n\ud83d\udccf Validating No Implicit Any\n');
|
|
324
286
|
console.log(` Mode: ${mode}`);
|
|
325
|
-
|
|
326
287
|
let base = process.env['NX_BASE'];
|
|
327
288
|
const head = process.env['NX_HEAD'];
|
|
328
|
-
|
|
329
289
|
if (!base) {
|
|
330
290
|
base = detectBase(workspaceRoot) ?? undefined;
|
|
331
291
|
if (!base) {
|
|
@@ -334,45 +294,38 @@ async function runInternal(
|
|
|
334
294
|
return { success: true };
|
|
335
295
|
}
|
|
336
296
|
}
|
|
337
|
-
|
|
338
297
|
console.log(` Base: ${base}`);
|
|
339
298
|
console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);
|
|
340
299
|
console.log('');
|
|
341
|
-
|
|
342
300
|
const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);
|
|
343
301
|
if (changedFiles.length === 0) {
|
|
344
302
|
console.log('\u2705 No TypeScript files changed');
|
|
345
303
|
return { success: true };
|
|
346
304
|
}
|
|
347
|
-
|
|
348
305
|
console.log(`\ud83d\udcc2 Checking ${changedFiles.length} changed file(s)...`);
|
|
349
|
-
|
|
350
|
-
let violations: ImplicitAnyViolation[] = [];
|
|
306
|
+
let violations = [];
|
|
351
307
|
if (mode === 'MODIFIED_CODE') {
|
|
352
308
|
violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed);
|
|
353
|
-
}
|
|
309
|
+
}
|
|
310
|
+
else if (mode === 'MODIFIED_FILES') {
|
|
354
311
|
violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed);
|
|
355
312
|
}
|
|
356
|
-
|
|
357
313
|
if (violations.length === 0) {
|
|
358
314
|
console.log('\u2705 No implicit-any inferences found');
|
|
359
315
|
return { success: true };
|
|
360
316
|
}
|
|
361
|
-
|
|
362
317
|
reportViolations(violations, mode);
|
|
363
318
|
return { success: false };
|
|
364
319
|
}
|
|
365
|
-
|
|
366
|
-
export default async function runValidator(
|
|
367
|
-
options: ValidateNoImplicitAnyOptions,
|
|
368
|
-
workspaceRoot: string
|
|
369
|
-
): Promise<ExecutorResult> {
|
|
320
|
+
async function runValidator(options, workspaceRoot) {
|
|
370
321
|
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
371
322
|
try {
|
|
372
323
|
return await runInternal(options, workspaceRoot);
|
|
373
|
-
}
|
|
324
|
+
}
|
|
325
|
+
catch (err) {
|
|
374
326
|
//const error = toError(err);
|
|
375
327
|
console.warn('\n\u23ed\ufe0f Skipping no-implicit-any validation due to unexpected error\n');
|
|
376
328
|
return { success: true };
|
|
377
329
|
}
|
|
378
330
|
}
|
|
331
|
+
//# sourceMappingURL=validate-no-implicit-any.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-no-implicit-any.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-no-implicit-any.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate No Implicit Any Executor\n *\n * Flags function parameters, variables, and object-literal properties whose\n * types collapse to the implicit `any` produced by TypeScript inference when\n * an annotation is missing. Pairs with validate-no-any-unknown (which bans\n * the literal keyword) so together they force developers to write real types.\n *\n * Detection leverages the TypeScript compiler directly: we build a ts.Program\n * from the project's tsconfig.json with `noImplicitAny: true` overridden, then\n * filter pre-emit diagnostics to the set of codes that describe implicit-any\n * inferences (TS7006, TS7005, TS7018, etc.) and map them back to changed lines.\n *\n * ============================================================================\n * MODES (LINE-BASED)\n * ============================================================================\n * - OFF: Skip validation entirely.\n * - MODIFIED_CODE: Flag implicit-any on changed lines (lines in diff hunks).\n * - MODIFIED_FILES: Flag ALL implicit-any in files that were modified.\n *\n * ============================================================================\n * ESCAPE HATCH\n * ============================================================================\n * // webpieces-disable no-implicit-any -- [your justification]\n * function handler(x) { ... }\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 NoImplicitAnyMode = 'OFF' | 'MODIFIED_CODE' | 'MODIFIED_FILES';\n\nexport interface ValidateNoImplicitAnyOptions {\n mode?: NoImplicitAnyMode;\n disableAllowed?: boolean;\n ignoreModifiedUntilEpoch?: number;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\ninterface ImplicitAnyViolation {\n file: string;\n line: number;\n column: number;\n code: number;\n message: string;\n hasDisableComment: boolean;\n}\n\n// TS diagnostic codes that describe an implicit-any inference. TS7010 (missing\n// return-type annotation) is intentionally omitted because it is already\n// covered by the sibling `require-return-type` validator.\nconst IMPLICIT_ANY_CODES: ReadonlySet<number> = new Set<number>([\n 7005, 7006, 7008, 7015, 7018, 7019, 7031, 7034, 7053,\n]);\n\nfunction listUntrackedOrEmpty(workspaceRoot: string): string[] {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const output = execSync(`git ls-files --others --exclude-standard '*.ts' '*.tsx'`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n return output.trim().split('\\n').filter((f: string) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));\n } catch (err: unknown) {\n //const error = toError(err);\n return [];\n }\n}\n\nfunction getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: string): string[] {\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 changed = output.trim().split('\\n').filter((f: string) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));\n if (head) return changed;\n return Array.from(new Set([...changed, ...listUntrackedOrEmpty(workspaceRoot)]));\n}\n\nfunction getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string {\n const diffTarget = head ? `${base} ${head}` : base;\n const diff = execSync(`git diff ${diffTarget} -- \"${file}\"`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n if (diff || head) return diff;\n const fullPath = path.join(workspaceRoot, file);\n if (!fs.existsSync(fullPath)) return '';\n const isUntracked = execSync(`git ls-files --others --exclude-standard \"${file}\"`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n }).trim();\n if (!isUntracked) return '';\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lines = content.split('\\n');\n const hunk = `@@ -0,0 +1,${String(lines.length)} @@`;\n return hunk + '\\n' + lines.map((line: string) => `+${line}`).join('\\n');\n}\n\nfunction getChangedLineNumbers(diffContent: string): Set<number> {\n const changedLines = new Set<number>();\n const lines = diffContent.split('\\n');\n let currentLine = 0;\n\n for (const line of lines) {\n const hunkMatch = line.match(/^@@ -\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/);\n if (hunkMatch) {\n currentLine = parseInt(hunkMatch[1], 10);\n continue;\n }\n\n if (line.startsWith('+') && !line.startsWith('+++')) {\n changedLines.add(currentLine);\n currentLine++;\n } else if (line.startsWith('-') && !line.startsWith('---')) {\n // Deletions don't increment line number\n } else {\n currentLine++;\n }\n }\n\n return changedLines;\n}\n\nfunction hasDisableComment(lines: string[], lineNumber: number): boolean {\n const startCheck = Math.max(0, lineNumber - 5);\n for (let i = lineNumber - 2; i >= startCheck; i--) {\n const line = lines[i]?.trim() ?? '';\n if (line.startsWith('function ') || line.startsWith('class ') || line.endsWith('}')) {\n break;\n }\n if (line.includes('webpieces-disable') && line.includes('no-implicit-any')) {\n return true;\n }\n }\n return false;\n}\n\n// Cache one ts.Program per tsconfig.json so multiple changed files in the\n// same project share parse/binding cost.\nconst programCache = new Map<string, ts.Program | null>();\n\nfunction findTsConfigForFile(absoluteFilePath: string, workspaceRoot: string): string | null {\n const root = path.resolve(workspaceRoot);\n let dir = path.dirname(absoluteFilePath);\n while (dir.startsWith(root)) {\n const candidate = path.join(dir, 'tsconfig.json');\n if (fs.existsSync(candidate)) return candidate;\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\nfunction buildProgram(tsconfigPath: string): ts.Program | null {\n const configFile = ts.readConfigFile(tsconfigPath, (p: string) => ts.sys.readFile(p));\n if (configFile.error) return null;\n const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.dirname(tsconfigPath));\n if (parsed.errors.length > 0 || parsed.fileNames.length === 0) return null;\n const options: ts.CompilerOptions = { ...parsed.options, noImplicitAny: true, noEmit: true, skipLibCheck: true };\n return ts.createProgram({ rootNames: parsed.fileNames, options });\n}\n\nfunction getProgramForFile(absoluteFilePath: string, workspaceRoot: string): ts.Program | null {\n const tsconfigPath = findTsConfigForFile(absoluteFilePath, workspaceRoot);\n if (!tsconfigPath) return null;\n if (programCache.has(tsconfigPath)) {\n return programCache.get(tsconfigPath) ?? null;\n }\n const program = buildProgram(tsconfigPath);\n programCache.set(tsconfigPath, program);\n return program;\n}\n\nfunction flattenMessage(message: string | ts.DiagnosticMessageChain): string {\n return ts.flattenDiagnosticMessageText(message, ' ');\n}\n\nfunction findImplicitAnyInFile(filePath: string, workspaceRoot: string): ImplicitAnyViolation[] {\n const absolute = path.resolve(workspaceRoot, filePath);\n if (!fs.existsSync(absolute)) return [];\n\n const program = getProgramForFile(absolute, workspaceRoot);\n if (!program) return [];\n\n const sourceFile = program.getSourceFile(absolute);\n if (!sourceFile) return [];\n\n const fileLines = fs.readFileSync(absolute, 'utf-8').split('\\n');\n const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile);\n const violations: ImplicitAnyViolation[] = [];\n\n for (const diag of diagnostics) {\n if (!IMPLICIT_ANY_CODES.has(diag.code)) continue;\n if (!diag.file || diag.start === undefined) continue;\n const pos = diag.file.getLineAndCharacterOfPosition(diag.start);\n const line = pos.line + 1;\n const column = pos.character + 1;\n violations.push({\n file: filePath,\n line,\n column,\n code: diag.code,\n message: flattenMessage(diag.messageText),\n hasDisableComment: hasDisableComment(fileLines, line),\n });\n }\n\n return violations;\n}\n\nfunction findViolationsForModifiedCode(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head: string | undefined,\n disableAllowed: boolean,\n): ImplicitAnyViolation[] {\n const results: ImplicitAnyViolation[] = [];\n for (const file of changedFiles) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const changedLines = getChangedLineNumbers(diff);\n if (changedLines.size === 0) continue;\n\n const all = findImplicitAnyInFile(file, workspaceRoot);\n for (const v of all) {\n if (disableAllowed && v.hasDisableComment) continue;\n if (!changedLines.has(v.line)) continue;\n results.push(v);\n }\n }\n return results;\n}\n\nfunction findViolationsForModifiedFiles(\n workspaceRoot: string,\n changedFiles: string[],\n disableAllowed: boolean,\n): ImplicitAnyViolation[] {\n const results: ImplicitAnyViolation[] = [];\n for (const file of changedFiles) {\n const all = findImplicitAnyInFile(file, workspaceRoot);\n for (const v of all) {\n if (disableAllowed && v.hasDisableComment) continue;\n results.push(v);\n }\n }\n return results;\n}\n\nfunction detectBase(workspaceRoot: string): string | null {\n for (const ref of ['origin/main', 'main']) {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const merged = execSync(`git merge-base HEAD ${ref}`, {\n cwd: workspaceRoot, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n if (merged) return merged;\n } catch (err: unknown) {\n //const error = toError(err);\n // try next ref\n }\n }\n return null;\n}\n\nfunction reportViolations(violations: ImplicitAnyViolation[], mode: NoImplicitAnyMode): void {\n console.error('');\n console.error('\\u274c Implicit-any inferences found! Add explicit type annotations.');\n console.error('');\n console.error('\\ud83d\\udcda Why: an untyped parameter or variable erases type safety silently.');\n console.error('');\n console.error(' BAD: function process(input) { return input.length; }');\n console.error(' GOOD: function process(input: string): number { return input.length; }');\n console.error('');\n\n for (const v of violations) {\n console.error(` \\u274c ${v.file}:${v.line}:${v.column}`);\n console.error(` TS${v.code}: ${v.message}`);\n }\n console.error('');\n console.error(' Escape hatch (use sparingly):');\n console.error(' // webpieces-disable no-implicit-any -- [your reason]');\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n}\n\nfunction resolveMode(normalMode: NoImplicitAnyMode, epoch: number | undefined): NoImplicitAnyMode {\n if (epoch === undefined || normalMode === 'OFF') {\n return normalMode;\n }\n const nowSeconds = Date.now() / 1000;\n if (nowSeconds < epoch) {\n const expiresDate = new Date(epoch * 1000).toISOString().split('T')[0];\n console.log(`\\n\\u23ed\\ufe0f Skipping no-implicit-any validation (ignoreModifiedUntilEpoch active, expires: ${expiresDate})`);\n console.log('');\n return 'OFF';\n }\n return normalMode;\n}\n\nasync function runInternal(\n options: ValidateNoImplicitAnyOptions,\n workspaceRoot: string,\n): Promise<ExecutorResult> {\n const mode: NoImplicitAnyMode = resolveMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch);\n const disableAllowed = options.disableAllowed ?? true;\n\n if (mode === 'OFF') {\n console.log('\\n\\u23ed\\ufe0f Skipping no-implicit-any validation (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating No Implicit Any\\n');\n console.log(` Mode: ${mode}`);\n\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n if (!base) {\n console.log('\\n\\u23ed\\ufe0f Skipping no-implicit-any validation (could not detect base branch)');\n console.log('');\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);\n 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 let violations: ImplicitAnyViolation[] = [];\n if (mode === 'MODIFIED_CODE') {\n violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed);\n } else if (mode === 'MODIFIED_FILES') {\n violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed);\n }\n\n if (violations.length === 0) {\n console.log('\\u2705 No implicit-any inferences found');\n return { success: true };\n }\n\n reportViolations(violations, mode);\n return { success: false };\n}\n\nexport default async function runValidator(\n options: ValidateNoImplicitAnyOptions,\n workspaceRoot: string\n): Promise<ExecutorResult> {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return await runInternal(options, workspaceRoot);\n } catch (err: unknown) {\n //const error = toError(err);\n console.warn('\\n\\u23ed\\ufe0f Skipping no-implicit-any validation due to unexpected error\\n');\n return { success: true };\n }\n}\n"]}
|