UNPKG

rxcc

Version:

A tool to pack repository contents to single file for AI consumption

160 lines 7.99 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import fs from 'node:fs/promises'; import path from 'node:path'; import { XMLBuilder } from 'fast-xml-parser'; import Handlebars from 'handlebars'; import { RepomixError } from '../../shared/errorHandle.js'; import { searchFiles } from '../file/fileSearch.js'; import { generateTreeString } from '../file/fileTreeGenerate.js'; import { sortOutputFiles } from './outputSort.js'; import { generateHeader, generateSummaryFileFormat, generateSummaryNotes, generateSummaryPurpose, generateSummaryUsageGuidelines, } from './outputStyleDecorate.js'; import { getMarkdownTemplate } from './outputStyles/markdownStyle.js'; import { getPlainTemplate } from './outputStyles/plainStyle.js'; import { getXmlTemplate } from './outputStyles/xmlStyle.js'; const calculateMarkdownDelimiter = (files) => { const maxBackticks = files .flatMap((file) => { var _a; return (_a = file.content.match(/`+/g)) !== null && _a !== void 0 ? _a : []; }) .reduce((max, match) => Math.max(max, match.length), 0); return '`'.repeat(Math.max(3, maxBackticks + 1)); }; const createRenderContext = (outputGeneratorContext) => { return { generationHeader: generateHeader(outputGeneratorContext.config, outputGeneratorContext.generationDate), // configを追加 summaryPurpose: generateSummaryPurpose(), summaryFileFormat: generateSummaryFileFormat(), summaryUsageGuidelines: generateSummaryUsageGuidelines(outputGeneratorContext.config, outputGeneratorContext.instruction), summaryNotes: generateSummaryNotes(outputGeneratorContext.config), headerText: outputGeneratorContext.config.output.headerText, instruction: outputGeneratorContext.instruction, treeString: outputGeneratorContext.treeString, processedFiles: outputGeneratorContext.processedFiles, fileSummaryEnabled: outputGeneratorContext.config.output.fileSummary, directoryStructureEnabled: outputGeneratorContext.config.output.directoryStructure, escapeFileContent: outputGeneratorContext.config.output.parsableStyle, markdownCodeBlockDelimiter: calculateMarkdownDelimiter(outputGeneratorContext.processedFiles), }; }; const generateParsableXmlOutput = (renderContext) => __awaiter(void 0, void 0, void 0, function* () { const xmlBuilder = new XMLBuilder({ ignoreAttributes: false }); const xmlDocument = { repomix: { '#text': renderContext.generationHeader, file_summary: renderContext.fileSummaryEnabled ? { '#text': 'This section contains a summary of this file.', purpose: renderContext.summaryPurpose, file_format: `${renderContext.summaryFileFormat} 4. Repository files, each consisting of: - File path as an attribute - Full contents of the file`, usage_guidelines: renderContext.summaryUsageGuidelines, notes: renderContext.summaryNotes, additional_info: { user_provided_header: renderContext.headerText, }, } : undefined, directory_structure: renderContext.directoryStructureEnabled ? renderContext.treeString : undefined, files: { '#text': "This section contains the contents of the repository's files.", file: renderContext.processedFiles.map((file) => ({ '#text': file.content, '@_path': file.path, })), }, instruction: renderContext.instruction ? renderContext.instruction : undefined, }, }; try { return xmlBuilder.build(xmlDocument); } catch (error) { throw new RepomixError(`Failed to generate XML output: ${error instanceof Error ? error.message : 'Unknown error'}`); } }); const generateHandlebarOutput = (config, renderContext) => __awaiter(void 0, void 0, void 0, function* () { let template; switch (config.output.style) { case 'xml': template = getXmlTemplate(); break; case 'markdown': template = getMarkdownTemplate(); break; case 'plain': template = getPlainTemplate(); break; default: throw new RepomixError(`Unknown output style: ${config.output.style}`); } try { const compiledTemplate = Handlebars.compile(template); return `${compiledTemplate(renderContext).trim()}\n`; } catch (error) { throw new RepomixError(`Failed to compile template: ${error instanceof Error ? error.message : 'Unknown error'}`); } }); export const generateOutput = (rootDirs_1, config_1, processedFiles_1, allFilePaths_1, ...args_1) => __awaiter(void 0, [rootDirs_1, config_1, processedFiles_1, allFilePaths_1, ...args_1], void 0, function* (rootDirs, config, processedFiles, allFilePaths, deps = { buildOutputGeneratorContext, generateHandlebarOutput, generateParsableXmlOutput, sortOutputFiles, }) { // Sort processed files by git change count if enabled const sortedProcessedFiles = yield deps.sortOutputFiles(processedFiles, config); const outputGeneratorContext = yield deps.buildOutputGeneratorContext(rootDirs, config, allFilePaths, sortedProcessedFiles); const renderContext = createRenderContext(outputGeneratorContext); if (!config.output.parsableStyle) return deps.generateHandlebarOutput(config, renderContext); switch (config.output.style) { case 'xml': return deps.generateParsableXmlOutput(renderContext); case 'markdown': return deps.generateHandlebarOutput(config, renderContext); default: return deps.generateHandlebarOutput(config, renderContext); } }); export const buildOutputGeneratorContext = (rootDirs, config, allFilePaths, processedFiles) => __awaiter(void 0, void 0, void 0, function* () { let repositoryInstruction = ''; if (config.output.instructionFilePath) { const instructionPath = path.resolve(config.cwd, config.output.instructionFilePath); try { repositoryInstruction = yield fs.readFile(instructionPath, 'utf-8'); } catch (_a) { throw new RepomixError(`Instruction file not found at ${instructionPath}`); } } let emptyDirPaths = []; if (config.output.includeEmptyDirectories) { try { emptyDirPaths = (yield Promise.all(rootDirs.map((rootDir) => searchFiles(rootDir, config)))).reduce((acc, curr) => ({ filePaths: [...acc.filePaths, ...curr.filePaths], emptyDirPaths: [...acc.emptyDirPaths, ...curr.emptyDirPaths], }), { filePaths: [], emptyDirPaths: [] }).emptyDirPaths; } catch (error) { if (error instanceof Error) { throw new RepomixError(`Failed to search for empty directories: ${error.message}`); } } } return { generationDate: new Date().toISOString(), treeString: generateTreeString(allFilePaths, emptyDirPaths), processedFiles, config, instruction: repositoryInstruction, }; }); //# sourceMappingURL=outputGenerate.js.map