-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
183 lines (149 loc) · 5.9 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
const fs = require('fs').promises;
const path = require('path');
const { program } = require('commander');
const { shouldSkipTraversal, shouldSkipContent } = require('./ignore');
program
.argument('<folderPath>', 'Path to the target folder')
.argument('[outputName]', 'Output file name (optional)')
.option('-f, --filter <patterns>', 'Additional patterns to filter (separated by commas)')
.parse();
const [folderPath] = program.args;
const options = program.opts();
const additionalFilters = options.filter ? options.filter.split(',').map(p => p.trim()) : [];
const originalSkipTraversal = shouldSkipTraversal;
const shouldSkipTraversalWithFilters = (filepath) => {
if (originalSkipTraversal(filepath)) {
return true;
}
const normalizedPath = filepath.replace(/\\/g, '/');
return additionalFilters.some(pattern => {
const regexPattern = pattern.includes('/')
? pattern.replace(/\//g, '[/\\\\]')
: `(^|[/\\\\])${pattern}($|[/\\\\])`;
return new RegExp(regexPattern).test(normalizedPath);
});
};
let totalFiles = 0;
let totalSize = 0;
let fileTypes = {};
let technologies = new Set();
function formatSize(bytes) {
if (bytes < 1024) return bytes + ' B';
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
}
async function generateTree(dir, prefix = '', includedFiles = new Set()) {
let result = '';
const items = await fs.readdir(dir);
for (let i = 0; i < items.length; i++) {
const item = items[i];
const itemPath = path.join(dir, item);
const stats = await fs.stat(itemPath);
if (shouldSkipTraversalWithFilters(itemPath)) continue;
const isLast = i === items.length - 1;
const connector = isLast ? '└── ' : '├── ';
const newPrefix = isLast ? ' ' : '│ ';
if (stats.isFile()) {
const size = formatSize(stats.size);
const isIncluded = !shouldSkipContent(itemPath);
const indicator = isIncluded ? ' ✓' : ' ✗';
result += `${prefix}${connector}${item} (${size})${indicator}\n`;
} else {
result += `${prefix}${connector}${item}/\n`;
result += await generateTree(itemPath, prefix + newPrefix, includedFiles);
}
}
return result;
}
async function getAllFiles(dir) {
const fileList = [];
const items = await fs.readdir(dir);
for (const item of items) {
const fullPath = path.join(dir, item);
if (shouldSkipTraversalWithFilters(fullPath)) continue;
const stats = await fs.stat(fullPath);
if (stats.isDirectory()) {
const subFiles = await getAllFiles(fullPath);
fileList.push(...subFiles);
} else {
// Track all files in stats, regardless of content inclusion
const ext = path.extname(fullPath).toLowerCase();
fileTypes[ext] = (fileTypes[ext] || 0) + 1;
if (['.ts', '.tsx'].includes(ext)) technologies.add('TypeScript');
if (['.jsx', '.tsx'].includes(ext)) technologies.add('React');
if (ext === '.vue') technologies.add('Vue.js');
if (ext === '.py') technologies.add('Python');
totalFiles++;
totalSize += stats.size;
if (!shouldSkipContent(fullPath)) {
fileList.push({
path: fullPath,
size: stats.size,
extension: ext
});
}
}
}
return fileList;
}
async function main() {
try {
console.log('Starting to process directory:', folderPath);
const stats = await fs.stat(folderPath);
if (!stats.isDirectory()) {
throw new Error('Provided path is not a directory');
}
const date = new Date();
const dateStr = `${(date.getMonth() + 1).toString().padStart(2, '0')}${date.getDate().toString().padStart(2, '0')}${date.getFullYear()}`;
const timestamp = Math.floor(date.getTime() / 1000);
const folderName = path.basename(folderPath);
const outputFileName = program.args[1] || `${folderName}_${dateStr}_${timestamp}.txt`;
console.log('Collecting files...');
const files = await getAllFiles(folderPath);
const includedFiles = new Set(files.map(f => f.path));
console.log('Generating tree structure...');
const treeStructure = await generateTree(folderPath, '', includedFiles);
console.log(`Found ${files.length} files`);
let output = 'Project Overview\n===============\n\n';
output += `Project Statistics:\n`;
output += `Total Files: ${totalFiles}\n`;
output += `Total Size: ${formatSize(totalSize)}\n\n`;
output += `File Types:\n`;
Object.entries(fileTypes)
.sort(([, a], [, b]) => b - a)
.forEach(([ext, count]) => {
output += ` ${ext || 'no extension'}: ${count} files\n`;
});
output += `\nDetected Technologies:\n`;
Array.from(technologies).sort().forEach(tech => {
output += ` - ${tech}\n`;
});
output += '\nFolder Structure (Tree)\n=====================\n';
output += 'Legend: ✓ = Included in output, ✗ = Excluded from output\n\n';
output += treeStructure;
output += '\n==============\n';
console.log('Processing individual files...');
for (const file of files) {
try {
const content = await fs.readFile(file.path, 'utf8');
const relPath = path.relative(folderPath, file.path);
output += `\nFile Name: ${relPath}\n`;
output += `Size: ${formatSize(file.size)}\n`;
output += 'Code:\n';
output += content;
output += '\n-------- [ Separator ] ------\n';
} catch (error) {
console.error(`Error reading file ${file.path}:`, error.message);
}
}
console.log('Writing output file...');
await fs.writeFile(outputFileName, output);
console.log(`Output written to ${outputFileName}`);
console.log(`Total files processed: ${files.length}`);
console.log(`Total size: ${formatSize(totalSize)}`);
} catch (error) {
console.error('Error:', error.message);
process.exit(1);
}
}
main();