repo2txt / js /local.js
multimodalart's picture
Upload 12 files
69fac21 verified
raw
history blame
8.78 kB
import { displayDirectoryStructure, sortContents, getSelectedFiles, formatRepoContents } from './utils.js';
import { extractZipContents } from './zip-utils.js';
// Add at the top of the file with other imports
let pathZipMap = {};
// Event listener for directory selection
document.getElementById('directoryPicker').addEventListener('change', handleDirectorySelection);
// Event listener for zip file selection
document.getElementById('zipPicker').addEventListener('change', handleZipSelection);
async function handleDirectorySelection(event) {
const files = event.target.files;
if (files.length === 0) return;
const gitignoreContent = ['.git/**']
const tree = [];
for (let file of files) {
const filePath = file.webkitRelativePath.startsWith('/') ? file.webkitRelativePath.slice(1) : file.webkitRelativePath;
tree.push({
path: filePath,
type: 'blob',
urlType: 'directory',
url: URL.createObjectURL(file)
});
if (file.webkitRelativePath.endsWith('.gitignore')) {
const gitignoreReader = new FileReader();
gitignoreReader.onload = function(e) {
const content = e.target.result;
const lines = content.split('\n');
const gitignorePath = file.webkitRelativePath.split('/').slice(0, -1).join('/');
lines.forEach(line => {
line = line.trim();
if (line && !line.startsWith('#')) {
if (gitignorePath) {
gitignoreContent.push(`${gitignorePath}/${line}`);
} else {
gitignoreContent.push(line);
}
}
});
filterAndDisplayTree(tree, gitignoreContent);
};
gitignoreReader.readAsText(file);
}
}
filterAndDisplayTree(tree, gitignoreContent);
}
// Handle zip file selection
async function handleZipSelection(event) {
const file = event.target.files[0];
if (!file) return;
try {
// Clear the directory picker
document.getElementById('directoryPicker').value = '';
// Extract zip contents and update the global pathZipMap
const { tree, gitignoreContent, pathZipMap: extractedPathZipMap } = await extractZipContents(file);
pathZipMap = extractedPathZipMap; // Update the global variable
// Filter and display the tree
filterAndDisplayTree(tree, gitignoreContent);
} catch (error) {
const outputText = document.getElementById('outputText');
outputText.value = `Error processing zip file: ${error.message}\n\n` +
"Please ensure:\n" +
"1. The zip file is not corrupted.\n" +
"2. The zip file contains text files that can be read.\n" +
"3. The zip file format is supported (.zip, .rar, .7z).\n";
}
}
function filterAndDisplayTree(tree, gitignoreContent) {
// Filter tree based on gitignore rules
const filteredTree = tree.filter(file => !isIgnored(file.path, gitignoreContent));
// Sort the tree
filteredTree.sort(sortContents);
// Display the directory structure
displayDirectoryStructure(filteredTree);
// Show the generate text button
document.getElementById('generateTextButton').style.display = 'flex';
}
// Event listener for generating text file
document.getElementById('generateTextButton').addEventListener('click', async function () {
const outputText = document.getElementById('outputText');
outputText.value = '';
try {
const selectedFiles = getSelectedFiles();
if (selectedFiles.length === 0) {
throw new Error('No files selected');
}
const fileContents = await fetchFileContents(selectedFiles);
const formattedText = formatRepoContents(fileContents);
outputText.value = formattedText;
document.getElementById('copyButton').style.display = 'flex';
document.getElementById('downloadButton').style.display = 'flex';
} catch (error) {
outputText.value = `Error generating text file: ${error.message}\n\n` +
"Please ensure:\n" +
"1. You have selected at least one file from the directory structure.\n" +
"2. The selected files are accessible and readable.\n" +
"3. You have sufficient permissions to read the selected files.";
}
});
// Modify fetchFileContents to handle both URL and text content
async function fetchFileContents(files) {
const contents = await Promise.all(files.map(async file => {
if (file.urlType === 'zip') {
const relativePath = file.path.startsWith('/') ? file.path.slice(1) : file.path;
const text = await pathZipMap[relativePath].async('text');
return { url: file.url, path: relativePath, text };
} else {
// Fetch content from URL (from directory)
const response = await fetch(file.url);
if (!response.ok) {
throw new Error(`Failed to fetch file: ${file.path}`);
}
const text = await response.text();
return { url: file.url, path: file.path, text };
}
}));
return contents;
}
// Initialize Lucide icons
document.addEventListener('DOMContentLoaded', function() {
lucide.createIcons();
});
function isIgnored(filePath, gitignoreRules) {
return gitignoreRules.some(rule => {
try {
// Convert gitignore rule to regex
let pattern = rule.replace(/\./g, '\\.') // Escape dots
.replace(/\*/g, '.*') // Convert * to .*
.replace(/\?/g, '.') // Convert ? to .
.replace(/\/$/, '(/.*)?$') // Handle directory matches
.replace(/^\//, '^'); // Handle root-level matches
// If the rule doesn't start with ^, it can match anywhere in the path
if (!pattern.startsWith('^')) {
pattern = `(^|/)${pattern}`;
}
const regex = new RegExp(pattern);
return regex.test(filePath);
} catch (error) {
console.log('Skipping ignore check for', filePath, 'with rule', rule);
console.log(error);
return false;
}
});
}
// Function to copy text to clipboard with fallback
function copyToClipboard(text) {
// Try using the modern Clipboard API first
if (navigator.clipboard && window.isSecureContext) {
return navigator.clipboard.writeText(text)
.then(() => console.log('Text copied to clipboard'))
.catch(err => {
console.error('Failed to copy text: ', err);
return false;
});
} else {
// Fallback to older execCommand method
try {
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
textArea.style.top = '-999999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
const success = document.execCommand('copy');
textArea.remove();
if (success) {
console.log('Text copied to clipboard');
return Promise.resolve();
} else {
console.error('Failed to copy text');
return Promise.reject(new Error('execCommand returned false'));
}
} catch (err) {
console.error('Failed to copy text: ', err);
return Promise.reject(err);
}
}
}
// Event listener for copying text to clipboard
document.getElementById('copyButton').addEventListener('click', function () {
const outputText = document.getElementById('outputText');
outputText.select();
copyToClipboard(outputText.value)
.catch(err => console.error('Failed to copy text: ', err));
});
// Event listener for downloading text file
document.getElementById('downloadButton').addEventListener('click', function () {
const outputText = document.getElementById('outputText').value;
if (!outputText.trim()) {
document.getElementById('outputText').value = 'Error: No content to download. Please generate the text file first.';
return;
}
const blob = new Blob([outputText], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'prompt.txt';
a.click();
URL.revokeObjectURL(url);
});