lookatni-file-markers
Version:
Advanced file organization system with unique markers for code sharing and project management. Extract files from marked content, generate markers, and validate project integrity.
195 lines (194 loc) • 7.82 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.MarkerGenerator = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
class MarkerGenerator {
constructor(logger) {
this.logger = logger;
this.FS_CHAR = String.fromCharCode(28);
}
async generateMarkers(sourceFolder, outputFile, options, progressCallback) {
const results = {
sourceFolder,
totalFiles: 0,
totalBytes: 0,
skippedFiles: [],
fileTypes: {}
};
const allFiles = this.getAllFiles(sourceFolder, options.excludePatterns);
this.logger.info(`Found ${allFiles.length} files to process`);
const filesToProcess = allFiles.filter(filePath => {
try {
const stats = fs.statSync(filePath);
const sizeKB = stats.size / 1024;
if (options.maxFileSize !== -1 && sizeKB > options.maxFileSize) {
results.skippedFiles.push({
path: path.relative(sourceFolder, filePath),
reason: `File too large (${sizeKB.toFixed(1)} KB > ${options.maxFileSize} KB)`
});
return false;
}
if (this.isBinaryFile(filePath)) {
results.skippedFiles.push({
path: path.relative(sourceFolder, filePath),
reason: 'Binary file'
});
return false;
}
return true;
}
catch (error) {
results.skippedFiles.push({
path: path.relative(sourceFolder, filePath),
reason: `Error reading file: ${error}`
});
return false;
}
});
this.logger.info(`Processing ${filesToProcess.length} files after filtering`);
let output = `//${this.FS_CHAR}/ PROJECT_INFO /${this.FS_CHAR}//\n`;
output += `Project: ${path.basename(sourceFolder)}\n`;
output += `Generated: ${new Date().toISOString()}\n`;
output += `Total Files: ${filesToProcess.length}\n`;
output += `Source: ${sourceFolder}\n\n`;
for (let i = 0; i < filesToProcess.length; i++) {
const filePath = filesToProcess[i];
const relativePath = path.relative(sourceFolder, filePath);
if (progressCallback) {
progressCallback(i + 1, filesToProcess.length);
}
try {
const content = fs.readFileSync(filePath, 'utf-8');
const stats = fs.statSync(filePath);
results.totalFiles++;
results.totalBytes += stats.size;
const ext = path.extname(filePath).toLowerCase() || 'no-extension';
results.fileTypes[ext] = (results.fileTypes[ext] || 0) + 1;
output += `//${this.FS_CHAR}/ ${relativePath} /${this.FS_CHAR}//\n`;
output += content;
if (!content.endsWith('\n')) {
output += '\n';
}
output += '\n';
this.logger.debug(`Processed: ${relativePath} (${stats.size} bytes)`);
}
catch (error) {
this.logger.error(`Error processing ${relativePath}:`, error);
results.skippedFiles.push({
path: relativePath,
reason: `Read error: ${error}`
});
}
}
fs.writeFileSync(outputFile, output, 'utf-8');
this.logger.info(`Generated markers file: ${outputFile}`);
return results;
}
getAllFiles(dir, excludePatterns) {
const files = [];
const traverse = (currentDir) => {
try {
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(currentDir, entry.name);
const relativePath = path.relative(dir, fullPath);
if (this.shouldExclude(entry.name, relativePath, excludePatterns)) {
continue;
}
if (entry.isDirectory()) {
traverse(fullPath);
}
else if (entry.isFile()) {
files.push(fullPath);
}
}
}
catch (error) {
this.logger.warn(`Cannot read directory ${currentDir}:`, error);
}
};
traverse(dir);
return files;
}
shouldExclude(name, relativePath, patterns) {
for (const pattern of patterns) {
if (pattern.includes('*')) {
const regex = new RegExp(pattern.replace(/\*/g, '.*'));
if (regex.test(name) || regex.test(relativePath)) {
return true;
}
}
else if (name === pattern || relativePath.includes(pattern)) {
return true;
}
}
return false;
}
isBinaryFile(filePath) {
const binaryExtensions = [
'.exe', '.dll', '.so', '.dylib', '.bin', '.obj',
'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.ico', '.webp',
'.mp3', '.mp4', '.avi', '.mov', '.wav', '.ogg',
'.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx',
'.zip', '.rar', '.7z', '.tar', '.gz', '.bz2',
'.class', '.jar', '.war', '.ear',
'.pyc', '.pyo', '.pyd',
'.woff', '.woff2', '.ttf', '.otf', '.eot'
];
const ext = path.extname(filePath).toLowerCase();
if (binaryExtensions.includes(ext)) {
return true;
}
try {
const buffer = fs.readFileSync(filePath, { encoding: null, flag: 'r' });
if (buffer.length === 0) {
return false;
}
const sampleSize = Math.min(1024, buffer.length);
for (let i = 0; i < sampleSize; i++) {
if (buffer[i] === 0) {
return true;
}
}
return false;
}
catch {
return true;
}
}
}
exports.MarkerGenerator = MarkerGenerator;