UNPKG

devghost

Version:

👻 Find dead code, dead imports, and dead dependencies before they haunt your project

213 lines • 8.42 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.analyzeUnusedTypes = analyzeUnusedTypes; const fs = __importStar(require("node:fs")); const ts = __importStar(require("typescript")); const tsparser_1 = require("../utils/tsparser"); /** * Analyze TypeScript files for unused types, interfaces, type aliases, and enums */ function analyzeUnusedTypes(files) { const unusedTypes = []; const allTypeDeclarations = new Map(); const typeReferences = new Set(); // First pass: collect all type declarations for (const file of files) { if (!fs.existsSync(file)) continue; const content = fs.readFileSync(file, 'utf-8'); if ((0, tsparser_1.shouldIgnoreFile)(content)) continue; const sourceFile = (0, tsparser_1.createSourceFile)(file, content); collectTypeDeclarations(sourceFile, file, allTypeDeclarations); } // Second pass: find type references for (const file of files) { if (!fs.existsSync(file)) continue; const content = fs.readFileSync(file, 'utf-8'); const sourceFile = (0, tsparser_1.createSourceFile)(file, content); collectTypeReferences(sourceFile, typeReferences); } // Find unused types for (const [_typeId, typeDecl] of allTypeDeclarations) { if (!typeReferences.has(typeDecl.name)) { unusedTypes.push({ file: typeDecl.file, line: typeDecl.line, column: typeDecl.column, typeName: typeDecl.name, typeKind: typeDecl.kind, isExported: typeDecl.isExported, entireLine: typeDecl.entireLine, }); } } return unusedTypes; } function collectTypeDeclarations(sourceFile, filePath, declarations) { function visit(node) { // Interface declarations if (ts.isInterfaceDeclaration(node) && node.name) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); const text = node.getText(sourceFile); const firstLine = text.split('\n')[0]; declarations.set(`${filePath}:${node.name.text}`, { file: filePath, name: node.name.text, kind: 'interface', line: line + 1, column: character, isExported: hasExportModifier(node), entireLine: firstLine, }); } // Type alias declarations if (ts.isTypeAliasDeclaration(node) && node.name) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); const text = node.getText(sourceFile); const firstLine = text.split('\n')[0]; declarations.set(`${filePath}:${node.name.text}`, { file: filePath, name: node.name.text, kind: 'type', line: line + 1, column: character, isExported: hasExportModifier(node), entireLine: firstLine, }); } // Enum declarations if (ts.isEnumDeclaration(node) && node.name) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); const text = node.getText(sourceFile); const firstLine = text.split('\n')[0]; declarations.set(`${filePath}:${node.name.text}`, { file: filePath, name: node.name.text, kind: 'enum', line: line + 1, column: character, isExported: hasExportModifier(node), entireLine: firstLine, }); } // Class declarations (as types) if (ts.isClassDeclaration(node) && node.name) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); const text = node.getText(sourceFile); const firstLine = text.split('\n')[0]; declarations.set(`${filePath}:${node.name.text}`, { file: filePath, name: node.name.text, kind: 'class', line: line + 1, column: character, isExported: hasExportModifier(node), entireLine: firstLine, }); } ts.forEachChild(node, visit); } visit(sourceFile); } function collectTypeReferences(sourceFile, references) { function visit(node) { // Type references if (ts.isTypeReferenceNode(node)) { const typeName = node.typeName.getText(sourceFile); references.add(typeName); } // Heritage clauses (extends, implements) if (ts.isHeritageClause(node)) { for (const type of node.types) { const typeName = type.expression.getText(sourceFile); references.add(typeName); } } // Variable declarations with type annotations if (ts.isVariableDeclaration(node) && node.type) { extractTypeNamesFromTypeNode(node.type, sourceFile, references); } // Function parameters and return types if (ts.isFunctionLike(node)) { // Parameters for (const param of node.parameters) { if (param.type) { extractTypeNamesFromTypeNode(param.type, sourceFile, references); } } // Return type if (node.type) { extractTypeNamesFromTypeNode(node.type, sourceFile, references); } } // Type assertions (as expressions) if (ts.isAsExpression(node)) { extractTypeNamesFromTypeNode(node.type, sourceFile, references); } ts.forEachChild(node, visit); } visit(sourceFile); } function extractTypeNamesFromTypeNode(typeNode, sourceFile, references) { if (ts.isTypeReferenceNode(typeNode)) { const typeName = typeNode.typeName.getText(sourceFile); references.add(typeName); } if (ts.isUnionTypeNode(typeNode) || ts.isIntersectionTypeNode(typeNode)) { for (const type of typeNode.types) { extractTypeNamesFromTypeNode(type, sourceFile, references); } } if (ts.isArrayTypeNode(typeNode)) { extractTypeNamesFromTypeNode(typeNode.elementType, sourceFile, references); } if (ts.isTypeLiteralNode(typeNode)) { for (const member of typeNode.members) { if (ts.isPropertySignature(member) && member.type) { extractTypeNamesFromTypeNode(member.type, sourceFile, references); } } } } function hasExportModifier(node) { const modifiersNode = node; if (!modifiersNode.modifiers) return false; return modifiersNode.modifiers.some((mod) => mod.kind === ts.SyntaxKind.ExportKeyword); } //# sourceMappingURL=unusedTypes.js.map