UNPKG

@rayburst/sharity

Version:

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

182 lines 6.72 kB
"use strict"; /** * Utilities for scanning workspaces and finding packages */ 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; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.findPackages = findPackages; exports.findSourceFiles = findSourceFiles; exports.findPackageJson = findPackageJson; exports.getPackageName = getPackageName; exports.resolveImportPath = resolveImportPath; const fs = __importStar(require("fs")); const path = __importStar(require("path")); const fast_glob_1 = __importDefault(require("fast-glob")); const typescript_parser_1 = require("./typescript-parser"); /** * Find all packages matching glob patterns */ async function findPackages(globs, cwd = process.cwd()) { const packages = []; for (const glob of globs) { const packageJsonPaths = await (0, fast_glob_1.default)(`${glob}/package.json`, { cwd, absolute: true, ignore: ['**/node_modules/**'], }); for (const packageJsonPath of packageJsonPaths) { const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); const packagePath = path.dirname(packageJsonPath); packages.push({ name: packageJson.name || path.basename(packagePath), path: packagePath, packageJsonPath, }); } } return packages; } /** * Find all source files in a package */ async function findSourceFiles(packagePath, excludePatterns = [], includeTests = false) { const patterns = [ '**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', ]; const defaultExcludes = [ '**/node_modules/**', '**/dist/**', '**/build/**', '**/*.d.ts', ]; if (!includeTests) { defaultExcludes.push('**/*.test.*', '**/*.spec.*', '**/__tests__/**', '**/__mocks__/**'); } const files = await (0, fast_glob_1.default)(patterns, { cwd: packagePath, absolute: true, ignore: [...defaultExcludes, ...excludePatterns], }); return files.filter((file) => { if (!(0, typescript_parser_1.shouldAnalyzeFile)(file)) return false; if (!includeTests && (0, typescript_parser_1.isTestFile)(file)) return false; return true; }); } /** * Find the package.json for a given directory */ function findPackageJson(startPath) { let currentPath = startPath; while (currentPath !== path.parse(currentPath).root) { const packageJsonPath = path.join(currentPath, 'package.json'); if (fs.existsSync(packageJsonPath)) { return packageJsonPath; } currentPath = path.dirname(currentPath); } return null; } /** * Get package name from package.json */ function getPackageName(packagePath) { const packageJsonPath = path.join(packagePath, 'package.json'); if (fs.existsSync(packageJsonPath)) { const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); return packageJson.name || path.basename(packagePath); } return path.basename(packagePath); } /** * Resolve import path to actual file path * Handles: * - Package imports: "@exaring/ui" -> /path/to/packages/ui * - Relative imports: "./Button" -> /path/to/Button.tsx */ function resolveImportPath(importSource, fromFile, workspaceRoot) { // Relative import if (importSource.startsWith('.')) { const fromDir = path.dirname(fromFile); const resolved = path.resolve(fromDir, importSource); // Try with extensions for (const ext of ['.ts', '.tsx', '.js', '.jsx', '/index.ts', '/index.tsx', '/index.js', '/index.jsx']) { const withExt = resolved + ext; if (fs.existsSync(withExt)) { return withExt; } } return resolved; } // Package import (e.g., "@exaring/ui" or "shared-package") // Try to find in workspace const parts = importSource.split('/'); const packageName = importSource.startsWith('@') ? `${parts[0]}/${parts[1]}` : parts[0]; // Look for package in common locations const possiblePaths = [ path.join(workspaceRoot, 'packages', packageName.replace(/^@[^/]+\//, '')), path.join(workspaceRoot, 'apps', packageName.replace(/^@[^/]+\//, '')), path.join(workspaceRoot, 'node_modules', packageName), ]; for (const possiblePath of possiblePaths) { if (fs.existsSync(possiblePath)) { // Check if there's a subpath in the import const subPath = parts.slice(packageName.startsWith('@') ? 2 : 1).join('/'); if (subPath) { return path.join(possiblePath, subPath); } // Try to resolve to main file const packageJsonPath = path.join(possiblePath, 'package.json'); if (fs.existsSync(packageJsonPath)) { const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); const main = packageJson.main || 'index.js'; return path.join(possiblePath, main); } return possiblePath; } } return null; } //# sourceMappingURL=workspace-scanner.js.map