structure-maker
Version:
Generate a folder structure with tech-specific icons
138 lines (113 loc) • 4.1 kB
JavaScript
import fs from 'fs';
import path from 'path';
import chalk from 'chalk';
import minimist from 'minimist';
const FILE_TYPE_ICONS = {
'.js': '💻',
'.ts': '💻',
'.py': '💻',
'.java': '💻',
'.md': '📜',
'.txt': '📜',
'.json': '📊',
'.jpg': '🖼️',
'.png': '🖼️',
'.gif': '🖼️',
'.mp4': '🎥',
'.avi': '🎥',
'.mp3': '🎵',
'.wav': '🎵',
'.pdf': '📚',
'.docx': '📚',
};
function getFileIcon(fileName) {
const ext = path.extname(fileName).toLowerCase();
return FILE_TYPE_ICONS[ext] || '📄';
}
function generateTree(dir, prefix = "", colorize = false, depth = Infinity, currentDepth = 0, ignorePatterns = []) {
if (currentDepth > depth) return { tree: '', fileCount: 0, folderCount: 0, fileTypes: {} };
const entries = fs
.readdirSync(dir, { withFileTypes: true })
.filter(
(e) => !['node_modules', '.git', '.expo', '.next', '.DS_Store', ...ignorePatterns].includes(e.name)
)
.sort((a, b) => (a.isDirectory() ? -1 : 1));
let tree = '';
let fileCount = 0;
let folderCount = 0;
let fileTypes = {};
entries.forEach((entry, index) => {
const isLast = index === entries.length - 1;
const connector = isLast ? '└─' : '├─';
const fullPath = path.join(dir, entry.name);
const icon = entry.isDirectory() ? '📁' : getFileIcon(entry.name);
let displayName = colorize
? entry.isDirectory()
? `${chalk.blue(icon)} ${chalk.blue.bold(entry.name)}`
: `${chalk.green(icon)} ${chalk.green(entry.name)}`
: `${icon} ${entry.name}`;
if (entry.isFile()) {
const stats = fs.statSync(fullPath);
const size = (stats.size / 1024).toFixed(1);
displayName += ` (${size} KB)`;
fileCount++;
const ext = path.extname(entry.name).toLowerCase() || 'other';
fileTypes[ext] = (fileTypes[ext] || 0) + 1;
} else {
folderCount++;
}
tree += `${prefix}${connector} ${displayName}\n`;
if (entry.isDirectory()) {
const nextPrefix = prefix + (isLast ? ' ' : '│ ');
const subtree = generateTree(fullPath, nextPrefix, colorize, depth, currentDepth + 1, ignorePatterns);
tree += subtree.tree || '';
fileCount += subtree.fileCount || 0;
folderCount += subtree.folderCount || 0;
for (const [ext, count] of Object.entries(subtree.fileTypes || {})) {
fileTypes[ext] = (fileTypes[ext] || 0) + count;
}
}
});
return { tree, fileCount, folderCount, fileTypes };
}
function main() {
try {
const args = minimist(process.argv.slice(2), {
string: ['ignore', 'depth'],
default: { ignore: '', depth: Infinity },
});
const ignorePatterns = args.ignore ? args.ignore.split(',').map((s) => s.trim()) : [];
const depth = parseInt(args.depth) || Infinity;
const currentDir = process.cwd();
const outputFile = 'folder-structure.md';
const rootName = path.basename(currentDir);
const { tree, fileCount, folderCount, fileTypes } = generateTree(currentDir, '', false, depth, 0, ignorePatterns);
const fileTypesSummary = Object.entries(fileTypes)
.map(([ext, count]) => `- **${ext || 'other'}**: ${count}`)
.join('\n');
const markdownContent = `
# Folder Structure
## Summary
- **Total Folders**: ${folderCount}
- **Total Files**: ${fileCount}
- **Root Directory**: ${rootName}
### File Types
${fileTypesSummary}
## Table of Contents
- [Directory Structure](#directory-structure)
## Directory Structure
\`\`\`
${rootName}/
${tree}
\`\`\`
`;
fs.writeFileSync(outputFile, markdownContent);
console.log(chalk.cyan(`✔ Folder structure saved to ${outputFile}`));
console.log(chalk.cyan(`Summary: ${folderCount} folders, ${fileCount} files`));
console.log(`${rootName}/\n${generateTree(currentDir, '', true, depth, 0, ignorePatterns).tree}`);
} catch (err) {
console.error(chalk.red('Error:', err.message));
}
}
main();