UNPKG

@rayburst/sharity

Version:

Analyze shared package usage across monorepos - calculate symbol sharing percentages, track exclusive imports, and identify unused exports

255 lines 9.03 kB
"use strict"; /** * TypeScript parser utilities using TypeScript Compiler API */ 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.parseFile = parseFile; exports.countLinesInFile = countLinesInFile; exports.shouldAnalyzeFile = shouldAnalyzeFile; exports.isTestFile = isTestFile; const ts = __importStar(require("typescript")); const fs = __importStar(require("fs")); const path = __importStar(require("path")); /** * Parse a TypeScript/JavaScript file and extract exports and imports */ function parseFile(filePath) { const sourceCode = fs.readFileSync(filePath, 'utf-8'); const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true); const exports = extractExports(sourceFile, filePath); const imports = extractImports(sourceFile, filePath); return { filePath, exports, imports, }; } /** * Extract all exported symbols from a source file */ function extractExports(sourceFile, filePath) { const exports = []; function visit(node) { // Named exports: export const/function/class/interface/type/enum if (ts.isVariableStatement(node) && node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) { node.declarationList.declarations.forEach((decl) => { if (ts.isIdentifier(decl.name)) { exports.push(createExportedSymbol(decl.name.text, node, filePath)); } }); } // export function/class if ((ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node)) && node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) && node.name) { exports.push(createExportedSymbol(node.name.text, node, filePath)); } // export interface/type/enum if ((ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isEnumDeclaration(node)) && node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) { exports.push(createExportedSymbol(node.name.text, node, filePath)); } // export { name1, name2 } if (ts.isExportDeclaration(node) && node.exportClause) { if (ts.isNamedExports(node.exportClause)) { node.exportClause.elements.forEach((element) => { const name = element.name.text; exports.push(createExportedSymbol(name, node, filePath)); }); } } ts.forEachChild(node, visit); } visit(sourceFile); return exports; } /** * Extract all import statements from a source file */ function extractImports(sourceFile, filePath) { const imports = []; function visit(node) { if (ts.isImportDeclaration(node)) { const moduleSpecifier = node.moduleSpecifier; if (ts.isStringLiteral(moduleSpecifier)) { const source = moduleSpecifier.text; const specifiers = []; if (node.importClause) { // Default import: import Foo from 'bar' if (node.importClause.name) { specifiers.push(node.importClause.name.text); } // Named imports: import { Foo, Bar } from 'baz' if (node.importClause.namedBindings) { if (ts.isNamedImports(node.importClause.namedBindings)) { node.importClause.namedBindings.elements.forEach((element) => { specifiers.push(element.name.text); }); } // Namespace import: import * as Foo from 'bar' else if (ts.isNamespaceImport(node.importClause.namedBindings)) { specifiers.push(node.importClause.namedBindings.name.text); } } } imports.push({ source, specifiers, filePath, }); } } ts.forEachChild(node, visit); } visit(sourceFile); return imports; } /** * Create an ExportedSymbol from a node */ function createExportedSymbol(name, node, filePath) { const sourceFile = node.getSourceFile(); const { line: startLine } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); const { line: endLine } = sourceFile.getLineAndCharacterOfPosition(node.getEnd()); const lineCount = endLine - startLine + 1; return { name, exportPath: getExportPath(filePath), filePath, lineCount, startLine: startLine + 1, // 1-indexed endLine: endLine + 1, // 1-indexed kind: inferSymbolKind(node), }; } /** * Infer the kind of symbol from the AST node */ function inferSymbolKind(node) { if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) { return 'function'; } if (ts.isClassDeclaration(node)) { return 'class'; } if (ts.isInterfaceDeclaration(node)) { return 'interface'; } if (ts.isTypeAliasDeclaration(node)) { return 'type'; } if (ts.isEnumDeclaration(node)) { return 'enum'; } if (ts.isVariableStatement(node)) { // Check if it looks like a component (starts with uppercase) const decl = node.declarationList.declarations[0]; if (decl && ts.isIdentifier(decl.name) && /^[A-Z]/.test(decl.name.text)) { return 'component'; } return 'const'; } return 'unknown'; } /** * Get a relative export path from an absolute file path */ function getExportPath(filePath) { // Remove file extension let exportPath = filePath.replace(/\.(ts|tsx|js|jsx)$/, ''); // Try to make it relative to common base paths const commonPaths = ['/packages/', '/src/', '/apps/']; for (const commonPath of commonPaths) { const index = exportPath.indexOf(commonPath); if (index !== -1) { exportPath = exportPath.substring(index + commonPath.length); break; } } return exportPath; } /** * Count total lines in a file (excluding empty lines and comments) */ function countLinesInFile(filePath) { const content = fs.readFileSync(filePath, 'utf-8'); const lines = content.split('\n'); let count = 0; let inMultiLineComment = false; for (const line of lines) { const trimmed = line.trim(); // Skip empty lines if (trimmed.length === 0) continue; // Handle multi-line comments if (trimmed.startsWith('/*')) { inMultiLineComment = true; } if (inMultiLineComment) { if (trimmed.endsWith('*/')) { inMultiLineComment = false; } continue; } // Skip single-line comments if (trimmed.startsWith('//')) continue; count++; } return count; } /** * Check if a file should be analyzed (based on extension) */ function shouldAnalyzeFile(filePath) { const ext = path.extname(filePath); return ['.ts', '.tsx', '.js', '.jsx'].includes(ext); } /** * Check if a file is a test file */ function isTestFile(filePath) { const fileName = path.basename(filePath); return (fileName.includes('.test.') || fileName.includes('.spec.') || fileName.includes('__tests__')); } //# sourceMappingURL=typescript-parser.js.map