filetree-pro
Version:
A powerful file tree generator for VS Code and Cursor. Generate beautiful file trees in multiple formats with smart exclusions and custom configurations.
287 lines (263 loc) • 7.73 kB
text/typescript
import { filesize } from 'filesize';
import moment from 'moment';
import * as path from 'path';
import { FileTypeInfo } from '../types';
export function getFileTypeInfo(filename: string): FileTypeInfo {
const ext = path.extname(filename).toLowerCase();
const name = path.basename(filename).toLowerCase();
// Code files
if (['.js', '.ts', '.jsx', '.tsx', '.vue', '.svelte'].includes(ext)) {
return {
type: 'code',
icon: '📄',
color: '#f7df1e',
extensions: ['.js', '.ts', '.jsx', '.tsx'],
};
}
if (['.py', '.pyc', '.pyo'].includes(ext)) {
return { type: 'code', icon: '🐍', color: '#3776ab', extensions: ['.py', '.pyc', '.pyo'] };
}
if (['.java', '.class'].includes(ext)) {
return { type: 'code', icon: '☕', color: '#007396', extensions: ['.java', '.class'] };
}
if (['.cpp', '.cc', '.cxx', '.c++', '.hpp', '.h'].includes(ext)) {
return {
type: 'code',
icon: '⚡',
color: '#00599c',
extensions: ['.cpp', '.cc', '.cxx', '.hpp', '.h'],
};
}
if (['.go'].includes(ext)) {
return { type: 'code', icon: '🐹', color: '#00add8', extensions: ['.go'] };
}
if (['.rs'].includes(ext)) {
return { type: 'code', icon: '🦀', color: '#ce422b', extensions: ['.rs'] };
}
if (['.php'].includes(ext)) {
return { type: 'code', icon: '🐘', color: '#777bb4', extensions: ['.php'] };
}
if (['.rb'].includes(ext)) {
return { type: 'code', icon: '💎', color: '#cc342d', extensions: ['.rb'] };
}
if (['.swift'].includes(ext)) {
return { type: 'code', icon: '🍎', color: '#ff6b35', extensions: ['.swift'] };
}
if (['.kt'].includes(ext)) {
return { type: 'code', icon: '☕', color: '#f18e33', extensions: ['.kt'] };
}
if (['.scala'].includes(ext)) {
return { type: 'code', icon: '☕', color: '#dc322f', extensions: ['.scala'] };
}
// Web files
if (['.html', '.htm'].includes(ext)) {
return { type: 'code', icon: '🌐', color: '#e34c26', extensions: ['.html', '.htm'] };
}
if (['.css', '.scss', '.sass', '.less'].includes(ext)) {
return {
type: 'code',
icon: '🎨',
color: '#1572b6',
extensions: ['.css', '.scss', '.sass', '.less'],
};
}
if (['.json', '.xml', '.yaml', '.yml', '.toml'].includes(ext)) {
return {
type: 'config',
icon: '⚙️',
color: '#f7df1e',
extensions: ['.json', '.xml', '.yaml', '.yml', '.toml'],
};
}
// Config files
if (['.env', '.config', '.conf', '.ini'].includes(ext) || name.startsWith('.')) {
return {
type: 'config',
icon: '⚙️',
color: '#6c757d',
extensions: ['.env', '.config', '.conf', '.ini'],
};
}
if (['.gitignore', '.gitattributes', '.gitmodules'].includes(name)) {
return {
type: 'config',
icon: '📁',
color: '#f05032',
extensions: ['.gitignore', '.gitattributes'],
};
}
if (['package.json', 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml'].includes(name)) {
return {
type: 'config',
icon: '📦',
color: '#cb3837',
extensions: ['package.json', 'yarn.lock'],
};
}
if (['dockerfile', '.dockerignore', 'Dockerfile'].includes(name)) {
return {
type: 'config',
icon: '🐳',
color: '#2496ed',
extensions: ['dockerfile', '.dockerignore', 'Dockerfile'],
};
}
// Document files
if (['.md', '.markdown'].includes(ext)) {
return { type: 'document', icon: '📝', color: '#000000', extensions: ['.md', '.markdown'] };
}
if (['.txt', '.rtf'].includes(ext)) {
return { type: 'document', icon: '📄', color: '#6c757d', extensions: ['.txt', '.rtf'] };
}
if (['.pdf'].includes(ext)) {
return { type: 'document', icon: '📕', color: '#ff0000', extensions: ['.pdf'] };
}
if (['.doc', '.docx'].includes(ext)) {
return { type: 'document', icon: '📘', color: '#2b579a', extensions: ['.doc', '.docx'] };
}
// Image files
if (['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg', '.webp'].includes(ext)) {
return {
type: 'image',
icon: '🖼️',
color: '#ff6b6b',
extensions: ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg', '.webp'],
};
}
// Video files
if (['.mp4', '.avi', '.mov', '.wmv', '.flv', '.webm'].includes(ext)) {
return {
type: 'video',
icon: '🎬',
color: '#ff6b6b',
extensions: ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.webm'],
};
}
// Audio files
if (['.mp3', '.wav', '.flac', '.aac', '.ogg'].includes(ext)) {
return {
type: 'audio',
icon: '🎵',
color: '#ff6b6b',
extensions: ['.mp3', '.wav', '.flac', '.aac', '.ogg'],
};
}
// Archive files
if (['.zip', '.rar', '.7z', '.tar', '.gz', '.bz2'].includes(ext)) {
return {
type: 'archive',
icon: '📦',
color: '#ffa500',
extensions: ['.zip', '.rar', '.7z', '.tar', '.gz', '.bz2'],
};
}
// Binary files
if (['.exe', '.dll', '.so', '.dylib', '.bin'].includes(ext)) {
return {
type: 'binary',
icon: '⚙️',
color: '#6c757d',
extensions: ['.exe', '.dll', '.so', '.dylib', '.bin'],
};
}
// Default for unknown files
return { type: 'unknown', icon: '📄', color: '#6c757d', extensions: [] };
}
export function formatFileSize(bytes: number): string {
return filesize(bytes, { base: 2 });
}
export function formatDate(date: Date): string {
return moment(date).format('MMM DD, YYYY HH:mm');
}
export function formatRelativeDate(date: Date): string {
return moment(date).fromNow();
}
export function getFileExtension(filename: string): string {
const ext = path.extname(filename).toLowerCase();
// Handle hidden files that start with a dot
if (filename.startsWith('.') && !ext) {
return filename;
}
return ext;
}
export function isTextFile(filename: string): boolean {
const textExtensions = [
'.txt',
'.md',
'.markdown',
'.json',
'.xml',
'.yaml',
'.yml',
'.toml',
'.ini',
'.cfg',
'.conf',
'.js',
'.ts',
'.jsx',
'.tsx',
'.vue',
'.svelte',
'.py',
'.java',
'.cpp',
'.cc',
'.cxx',
'.hpp',
'.h',
'.go',
'.rs',
'.php',
'.rb',
'.swift',
'.kt',
'.scala',
'.html',
'.htm',
'.css',
'.scss',
'.sass',
'.less',
'.sql',
'.sh',
'.bash',
'.zsh',
'.fish',
'.ps1',
'.bat',
'.cmd',
'.env',
'.gitignore',
'.gitattributes',
'.dockerignore',
'dockerfile',
];
const ext = getFileExtension(filename).toLowerCase();
return textExtensions.includes(ext);
}
export function getFileIcon(filename: string): string {
const fileTypeInfo = getFileTypeInfo(filename);
return fileTypeInfo.icon;
}
export function getFileColor(filename: string): string {
const fileTypeInfo = getFileTypeInfo(filename);
return fileTypeInfo.color || '#6c757d';
}
export function sanitizeFileName(filename: string): string {
return filename.replace(/[<>:"/\\|?*]/g, '_');
}
export function isHiddenFile(filename: string): boolean {
return filename.startsWith('.') || filename.includes('~');
}
export function getDisplayName(filename: string): string {
// Handle special files - return plain text for tests (case-insensitive)
const lowerFilename = filename.toLowerCase();
if (lowerFilename === 'package.json') return 'package.json';
if (lowerFilename === 'readme.md') return 'README.md';
if (lowerFilename === '.gitignore') return '.gitignore';
if (lowerFilename === 'dockerfile') return 'Dockerfile';
if (lowerFilename === '.env') return '.env';
// Return just the filename without path
return path.basename(filename);
}