Skip to content

Instantly share code, notes, and snippets.

@davidcostadev
Created November 27, 2025 22:24
Show Gist options
  • Select an option

  • Save davidcostadev/df331fc4865f75e2347e8a2bf4d391e2 to your computer and use it in GitHub Desktop.

Select an option

Save davidcostadev/df331fc4865f75e2347e8a2bf4d391e2 to your computer and use it in GitHub Desktop.
find-isolated-files.js
#!/usr/bin/env node
/**
* Script to find isolated files in src directory
* A file is considered isolated if it exports something but those exports are never imported
*/
const fs = require('fs');
const path = require('path');
const SRC_DIR = path.join(__dirname, '..', 'src');
// Get all TypeScript files in src
function getAllTsFiles(dir, fileList = []) {
const files = fs.readdirSync(dir);
files.forEach((file) => {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
getAllTsFiles(filePath, fileList);
} else if (file.endsWith('.ts') && !file.endsWith('.spec.ts') && !file.endsWith('.test.ts')) {
fileList.push(filePath);
}
});
return fileList;
}
// Extract exports from a file
function extractExports(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
const exports = new Set();
// Match export statements
const exportPatterns = [
// export class X
/export\s+(?:default\s+)?class\s+(\w+)/g,
// export interface X
/export\s+(?:default\s+)?interface\s+(\w+)/g,
// export type X
/export\s+(?:default\s+)?type\s+(\w+)/g,
// export enum X
/export\s+(?:default\s+)?enum\s+(\w+)/g,
// export const X
/export\s+(?:default\s+)?const\s+(\w+)/g,
// export function X
/export\s+(?:default\s+)?function\s+(\w+)/g,
// export { X, Y, Z }
/export\s*\{[^}]*\b(\w+)\b[^}]*\}/g,
// export { X as Y }
/export\s*\{[^}]*\b(\w+)\s+as\s+\w+\b[^}]*\}/g,
];
exportPatterns.forEach((pattern) => {
let match;
while ((match = pattern.exec(content)) !== null) {
if (match[1]) {
exports.add(match[1]);
}
}
});
// Check for default exports
if (/export\s+default/.test(content)) {
exports.add('default');
}
return Array.from(exports);
}
// Get possible import paths for a file
function getPossibleImportPaths(filePath) {
const relativePath = path.relative(SRC_DIR, filePath);
const paths = new Set();
// Remove .ts extension
const basePath = relativePath.replace(/\.ts$/, '');
// Add various possible import formats
paths.add(basePath.replace(/\\/g, '/'));
paths.add(`src/${basePath.replace(/\\/g, '/')}`);
paths.add(`./${basePath.replace(/\\/g, '/')}`);
paths.add(`../${basePath.replace(/\\/g, '/')}`);
// Add path without src prefix
const withoutSrc = basePath.replace(/^src[\/\\]/, '').replace(/\\/g, '/');
paths.add(withoutSrc);
paths.add(`./${withoutSrc}`);
// Add just the filename
const fileName = path.basename(filePath, '.ts');
paths.add(fileName);
// Add directory/filename
const dirName = path.basename(path.dirname(filePath));
paths.add(`${dirName}/${fileName}`);
return Array.from(paths);
}
// Read all file contents for searching
function getAllFileContents() {
const files = getAllTsFiles(SRC_DIR);
const contents = new Map();
files.forEach((filePath) => {
try {
contents.set(filePath, fs.readFileSync(filePath, 'utf-8'));
} catch (error) {
// Skip files that can't be read
}
});
return contents;
}
// Check if exports are used anywhere
function isExportedUsed(filePath, exports, allContents) {
if (exports.length === 0) {
return false; // No exports, not isolated
}
const possibleImportPaths = getPossibleImportPaths(filePath);
const fileName = path.basename(filePath, '.ts');
// Search through all files for imports
for (const [otherFilePath, content] of allContents.entries()) {
// Skip the file itself
if (otherFilePath === filePath) {
continue;
}
// Check for imports from this file using various path formats
for (const importPath of possibleImportPaths) {
// Escape special regex characters
const escapedPath = importPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
// Match: from 'path' or from "path"
const importPattern = new RegExp(`from\\s+['"]${escapedPath}['"]`, 'g');
if (importPattern.test(content)) {
return true;
}
// Match: require('path')
const requirePattern = new RegExp(`require\\(['"]${escapedPath}['"]\\)`, 'g');
if (requirePattern.test(content)) {
return true;
}
}
// Check for specific export names being imported
for (const exportName of exports) {
if (exportName === 'default') {
// Check for default imports
const defaultImportPattern = new RegExp(
`import\\s+\\w+\\s+from\\s+['"][^'"]*${fileName}['"]|import\\s+\\{[^}]*\\}\\s+from\\s+['"][^'"]*${fileName}['"]`,
'g',
);
if (defaultImportPattern.test(content)) {
return true;
}
} else {
// Check for named imports
const namedImportPattern = new RegExp(
`import\\s+.*\\b${exportName}\\b.*from|import\\s+\\{[^}]*\\b${exportName}\\b[^}]*\\}`,
'g',
);
if (namedImportPattern.test(content)) {
// Verify it's actually importing from this file
const lines = content.split('\n');
for (let i = 0; i < lines.length; i++) {
if (lines[i].includes(exportName)) {
// Check if this line or nearby lines reference our file
const checkRange = lines.slice(Math.max(0, i - 2), Math.min(lines.length, i + 3)).join('\n');
for (const importPath of possibleImportPaths) {
const escapedPath = importPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
if (new RegExp(escapedPath).test(checkRange)) {
return true;
}
}
}
}
}
}
}
}
return false;
}
// Main function
function findIsolatedFiles() {
console.log('πŸ” Scanning for isolated files in src...\n');
const allFiles = getAllTsFiles(SRC_DIR);
const allContents = getAllFileContents();
const isolatedFiles = [];
console.log(`πŸ“ Found ${allFiles.length} TypeScript files to analyze...\n`);
for (const filePath of allFiles) {
const exports = extractExports(filePath);
const isUsed = isExportedUsed(filePath, exports, allContents);
if (exports.length > 0 && !isUsed) {
const relativePath = path.relative(SRC_DIR, filePath);
isolatedFiles.push({
path: relativePath,
exports: exports,
});
}
}
if (isolatedFiles.length === 0) {
console.log('βœ… No isolated files found! All exported files are being used.\n');
return;
}
console.log(`⚠️ Found ${isolatedFiles.length} isolated file(s):\n`);
isolatedFiles.forEach((file) => {
console.log(`πŸ“„ ${file.path}`);
console.log(` Exports: ${file.exports.join(', ') || 'default'}\n`);
});
console.log('\nπŸ’‘ Tip: These files export something but are never imported.');
console.log(' Review them to see if they should be removed or if they need to be used.\n');
}
// Run the script
findIsolatedFiles();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment