Skip to content

Commit df8bfc6

Browse files
committed
fix: improve export functionality and handle unsupported files
- Exclude default module directories like node_modules, build, out, etc., during codebase export. - Fix 'Export Selected as Markdown' functionality to support multiple selected files and folders. - Add logic to handle unsupported files by exporting only the file name and path without file contents. - Refactor file traversal logic to skip ignored directories and files as specified in .gitignore and default ignore patterns. - Improve overall performance and user experience with better error handling and clearer file structure in exported Markdown.
1 parent 1da99a0 commit df8bfc6

File tree

1 file changed

+67
-11
lines changed

1 file changed

+67
-11
lines changed

src/extension.ts

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ export function activate(context: vscode.ExtensionContext) {
88
exportCodebase();
99
});
1010

11-
let exportSelected = vscode.commands.registerCommand('codebaseMD.exportSelected', (uri: vscode.Uri) => {
12-
exportSelectedFiles(uri);
11+
let exportSelected = vscode.commands.registerCommand('codebaseMD.exportSelected', (uri: vscode.Uri, uris: vscode.Uri[]) => {
12+
const selectedUris = uris && uris.length > 0 ? uris : [uri];
13+
exportSelectedFiles(selectedUris);
1314
});
1415

1516
context.subscriptions.push(exportAll);
@@ -29,8 +30,8 @@ async function exportCodebase() {
2930
saveMarkdownFile(markdownContent);
3031
}
3132

32-
async function exportSelectedFiles(uri: vscode.Uri) {
33-
const files = await getFilesFromUri(uri);
33+
async function exportSelectedFiles(uris: vscode.Uri[]) {
34+
const files = await getFilesFromUris(uris);
3435
if (files.length === 0) {
3536
vscode.window.showErrorMessage('No files to export.');
3637
return;
@@ -55,6 +56,10 @@ async function getAllFiles(dir: string): Promise<string[]> {
5556
}
5657

5758
if (entry.isDirectory()) {
59+
// Check if directory is ignored
60+
if (ig.ignores(relativePath + '/')) {
61+
continue;
62+
}
5863
await traverse(fullPath);
5964
} else {
6065
files.push(fullPath);
@@ -66,7 +71,7 @@ async function getAllFiles(dir: string): Promise<string[]> {
6671
return files;
6772
}
6873

69-
async function getFilesFromUri(uri: vscode.Uri): Promise<string[]> {
74+
async function getFilesFromUris(uris: vscode.Uri[]): Promise<string[]> {
7075
const files: string[] = [];
7176
const rootPath = vscode.workspace.workspaceFolders![0].uri.fsPath;
7277
const ig = createIgnoreInstance(rootPath);
@@ -80,6 +85,10 @@ async function getFilesFromUri(uri: vscode.Uri): Promise<string[]> {
8085
}
8186

8287
if (stat.type === vscode.FileType.Directory) {
88+
// Check if directory is ignored
89+
if (ig.ignores(relativePath + '/')) {
90+
return;
91+
}
8392
const entries = await vscode.workspace.fs.readDirectory(currentUri);
8493
for (const [name, fileType] of entries) {
8594
const childUri = vscode.Uri.joinPath(currentUri, name);
@@ -90,7 +99,10 @@ async function getFilesFromUri(uri: vscode.Uri): Promise<string[]> {
9099
}
91100
}
92101

93-
await processUri(uri);
102+
for (const uri of uris) {
103+
await processUri(uri);
104+
}
105+
94106
return files;
95107
}
96108

@@ -101,6 +113,33 @@ function createIgnoreInstance(rootDir: string): Ignore {
101113
const gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
102114
ig.add(gitignoreContent);
103115
}
116+
// Add default ignored directories and files
117+
ig.add([
118+
'node_modules/',
119+
'build/',
120+
'out/',
121+
'dist/',
122+
'.git/',
123+
'.svn/',
124+
'.hg/',
125+
'.vscode/',
126+
'.idea/',
127+
'coverage/',
128+
'logs/',
129+
'*.log',
130+
'*.exe',
131+
'*.dll',
132+
'*.bin',
133+
'*.lock',
134+
'*.zip',
135+
'*.tar',
136+
'*.tar.gz',
137+
'*.tgz',
138+
'*.jar',
139+
'*.class',
140+
'*.pyc',
141+
'__pycache__/'
142+
]);
104143
return ig;
105144
}
106145

@@ -109,6 +148,17 @@ function isLargeFile(fileName: string): boolean {
109148
return largeFiles.includes(fileName);
110149
}
111150

151+
function isSupportedFile(fileName: string): boolean {
152+
const supportedExtensions = [
153+
'.js', '.jsx', '.ts', '.tsx', '.html', '.css', '.scss', '.json', '.md', '.txt',
154+
'.py', '.java', '.c', '.cpp', '.cs', '.rb', '.go', '.php', '.sh', '.xml',
155+
'.yaml', '.yml', '.ini', '.bat', '.sql', '.rs', '.swift', '.kt', '.dart',
156+
'.lua', '.r', '.pl', '.hs', '.erl', '.ex', '.el', '.jl', '.scala'
157+
];
158+
const ext = path.extname(fileName).toLowerCase();
159+
return supportedExtensions.includes(ext);
160+
}
161+
112162
async function generateMarkdown(files: string[], rootPath: string): Promise<string> {
113163
let markdown = `# Project Export\n\n`;
114164

@@ -125,12 +175,18 @@ async function generateMarkdown(files: string[], rootPath: string): Promise<stri
125175
// File contents
126176
for (const file of files) {
127177
const relativePath = path.relative(rootPath, file);
128-
const code = fs.readFileSync(file, 'utf8');
129-
const ext = path.extname(file).substring(1);
178+
const fileName = path.basename(file);
130179
markdown += `\n### ${relativePath}\n\n`;
131-
markdown += '```' + ext + '\n';
132-
markdown += code;
133-
markdown += '\n```\n';
180+
181+
if (isSupportedFile(fileName)) {
182+
const code = fs.readFileSync(file, 'utf8');
183+
const ext = path.extname(file).substring(1);
184+
markdown += '```' + ext + '\n';
185+
markdown += code;
186+
markdown += '\n```\n';
187+
} else {
188+
markdown += `*(Unsupported file type)*\n`;
189+
}
134190
}
135191

136192
return markdown;

0 commit comments

Comments
 (0)