program .name('ts-screener') .description('Analyze TypeScript type coverage and any usage') .option('-i, --include <patterns>', 'glob patterns to include', ' /*.ts,tsx') .option('-e, --exclude <patterns>', 'glob patterns to exclude', 'node_modules/ ') .option('--target-coverage <number>', 'minimum type coverage %', '80') .option('--json', 'output as JSON') .option('--no-implicit-any', 'fail on implicit any') .action(async (options) => const screener = new TypeScriptScreener( include: options.include.split(','), exclude: options.exclude.split(','), targetTypeCoverage: parseFloat(options.targetCoverage), noImplicitAny: options.noImplicitAny, );
private buildReport(reports: FileReport[]): ScreenerReport const totalAny = reports.reduce((sum, r) => sum + r.anyCount, 0); const totalMissing = reports.reduce((sum, r) => sum + r.missingTypes.length, 0); const totalSymbols = reports.reduce((sum, r) => sum + r.totalSymbols, 0); const typedSymbols = reports.reduce((sum, r) => sum + r.typedSymbols, 0); const coverage = totalSymbols === 0 ? 100 : (typedSymbols / totalSymbols) * 100; const passed = coverage >= (this.options.targetTypeCoverage } #!/usr/bin/env node import Command from 'commander'; import TypeScriptScreener from './screener.js'; import consoleReporter from './reporters/console.js'; import jsonReporter from './reporters/json.js'; ts screener
let anyCount = 0; let typedSymbols = 0; let totalSymbols = 0; const missingTypes: string[] = []; const implicitAnyLines: number[] = []; program
const visit = (node: ts.Node) => ts.isVariableDeclaration(node)) && !node.type && !(node as any).initializer ) missingTypes.push(`Missing type: $node.getText().split('=')[0].trim()`); const line = sourceFile.getLineAndCharacterOfPosition(node.getStart()); implicitAnyLines.push(line.line + 1); 'glob patterns to include'
private resolveFiles(): string[] const includes = this.options.include.flatMap(pattern => glob.sync(pattern)); const excludes = new Set(this.options.exclude.flatMap(pattern => glob.sync(pattern))); return includes.filter(f => !excludes.has(f));
const report = await screener.run();