From 306a2357db30fe6c4f0765f2d502e2d6c1f7b038 Mon Sep 17 00:00:00 2001 From: Kazuki Yamada Date: Mon, 12 Aug 2024 00:21:23 +0900 Subject: [PATCH] feat(config): Add support for project instruction file --- README.md | 59 ++++++++- package-lock.json | 65 ++++++++++ package.json | 1 + repopack-instruction.md | 9 ++ repopack.config.json | 1 + src/config/configTypes.ts | 2 + src/core/output/outputGenerator.ts | 35 ++++-- src/core/output/outputGeneratorTypes.ts | 1 + src/core/output/outputStyleCommonDecorator.ts | 56 +++++++++ src/core/output/plainStyleGenerator.ts | 119 ++++++++++-------- src/core/output/xmlStyleGenerator.ts | 106 +++++++++------- src/core/packager.ts | 2 +- tests/core/output/outputGenerator.test.ts | 5 +- tests/core/output/plainStyleGenerator.test.ts | 9 +- tests/core/output/xmlStyleGenerator.test.ts | 9 +- tests/core/packager.test.ts | 30 +++++ .../outputs/simple-project-output.txt | 32 ++--- .../outputs/simple-project-output.xml | 34 ++--- tests/integration-tests/packager.test.ts | 4 +- tsconfig.json | 4 +- 20 files changed, 429 insertions(+), 154 deletions(-) create mode 100644 repopack-instruction.md create mode 100644 src/core/output/outputStyleCommonDecorator.ts diff --git a/README.md b/README.md index 105ef20..2da4453 100644 --- a/README.md +++ b/README.md @@ -137,8 +137,10 @@ To enhance AI comprehension, the output file begins with an AI-oriented explanat #### Plain Text Format (default) ```text +This file is a merged representation of the entire codebase, combining all repository files into a single document. + ================================================================ -REPOPACK OUTPUT FILE +File Summary ================================================================ (Metadata and usage AI instructions) @@ -169,6 +171,11 @@ File: src/utils.js // File contents here (...remaining files) + +================================================================ +Instruction +================================================================ +(Custom instructions from `output.instructionFilePath`) ``` #### XML Format @@ -181,9 +188,11 @@ repopack --style xml The XML format structures the content in a hierarchical manner: ```xml - +This file is a merged representation of the entire codebase, combining all repository files into a single document. + + (Metadata and usage AI instructions) - + src/ @@ -201,6 +210,10 @@ src/ (...remaining files) + + +(Custom instructions from `output.instructionFilePath`) + ``` For those interested in the potential of XML tags in AI contexts: @@ -279,6 +292,7 @@ Here's an explanation of the configuration options: |`output.filePath`| The name of the output file | `"repopack-output.txt"` | |`output.style`| The style of the output (`plain`, `xml`) |`"plain"`| |`output.headerText`| Custom text to include in the file header |`null`| +|`output.instructionFilePath`| Path to a file containing detailed custom instructions |`null`| |`output.removeComments`| Whether to remove comments from supported file types | `false` | |`output.removeEmptyLines`| Whether to remove empty lines from the output | `false` | |`output.showLineNumbers`| Whether to add line numbers to each line in the output |`false`| @@ -349,6 +363,45 @@ This approach allows for flexible file exclusion configuration based on your pro Note: Binary files are not included in the packed output by default, but their paths are listed in the "Repository Structure" section of the output file. This provides a complete overview of the repository structure while keeping the packed file efficient and text-based. +### Custom Instruction + +The `output.instructionFilePath` option allows you to specify a separate file containing detailed instructions or context about your project. This allows AI systems to understand the specific context and requirements of your project, potentially leading to more relevant and tailored analysis or suggestions. + +Here's an example of how you might use this feature: + +1. Create a file named `repopack-instruction.md` in your project root: + +```markdown +# Coding Guidelines +- Follow the Airbnb JavaScript Style Guide +- Suggest splitting files into smaller, focused units when appropriate +- Add comments for non-obvious logic. Keep all text in English +- All new features should have corresponding unit tests + +# Generate Comprehensive Output +- Include all content without abbreviation, unless specified otherwise +- Optimize for handling large codebases while maintaining output quality +``` + +2. In your `repopack.config.json`, add the `instructionFilePath` option: + +```json5 +{ + "output": { + "instructionFilePath": "repopack-instruction.md", + // other options... + } +} +``` + +When Repopack generates the output, it will include the contents of `repopack-instruction.md` in a dedicated section. + +Note: The instruction content is appended at the end of the output file. This placement can be particularly effective for AI systems. For those interested in understanding why this might be beneficial, Anthropic provides some insights in their documentation: +https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/long-context-tips + +> Put longform data at the top: Place your long documents and inputs (~20K+ tokens) near the top of your prompt, above your query, instructions, and examples. This can significantly improve Claude's performance across all models. +> Queries at the end can improve response quality by up to 30% in tests, especially with complex, multi-document inputs. + ### Comment Removal When `output.removeComments` is set to `true`, Repopack will attempt to remove comments from supported file types. This feature can help reduce the size of the output file and focus on the essential code content. diff --git a/package-lock.json b/package-lock.json index 740797b..e92c595 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "cli-spinners": "^2.9.2", "commander": "^11.1.0", "globby": "^14.0.2", + "handlebars": "^4.7.8", "iconv-lite": "^0.6.3", "istextorbinary": "^9.5.0", "jschardet": "^3.1.3", @@ -2192,6 +2193,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2649,6 +2671,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", @@ -2681,6 +2712,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, "node_modules/normalize-package-data": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", @@ -3317,6 +3354,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", @@ -3804,6 +3850,19 @@ "node": ">=14.17" } }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", @@ -4026,6 +4085,12 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", diff --git a/package.json b/package.json index 87cf704..723b53a 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "cli-spinners": "^2.9.2", "commander": "^11.1.0", "globby": "^14.0.2", + "handlebars": "^4.7.8", "iconv-lite": "^0.6.3", "istextorbinary": "^9.5.0", "jschardet": "^3.1.3", diff --git a/repopack-instruction.md b/repopack-instruction.md new file mode 100644 index 0000000..90e1a33 --- /dev/null +++ b/repopack-instruction.md @@ -0,0 +1,9 @@ +# Coding Guidelines +- Follow the Airbnb JavaScript Style Guide +- Suggest splitting files into smaller, focused units when appropriate +- Add comments for non-obvious logic. Keep all text in English +- All new features should have corresponding unit tests + +# Generate Comprehensive Output +- Include all content without abbreviation, unless specified otherwise +- Optimize for handling large codebases while maintaining output quality diff --git a/repopack.config.json b/repopack.config.json index 6d39987..fdaaef5 100644 --- a/repopack.config.json +++ b/repopack.config.json @@ -3,6 +3,7 @@ "filePath": "repopack-output.xml", "style": "xml", "headerText": "This repository contains the source code for the Repopack tool.\nRepopack is designed to pack repository contents into a single file,\nmaking it easier for AI systems to analyze and process the codebase.\n\nKey Features:\n- Configurable ignore patterns\n- Custom header text support\n- Efficient file processing and packing\n\nPlease refer to the README.md file for more detailed information on usage and configuration.\n", + "instructionFilePath": "repopack-instruction.md", "removeComments": false, "removeEmptyLines": false, "topFilesLength": 5, diff --git a/src/config/configTypes.ts b/src/config/configTypes.ts index 3c0f173..a920d5d 100644 --- a/src/config/configTypes.ts +++ b/src/config/configTypes.ts @@ -5,6 +5,7 @@ interface RepopackConfigBase { filePath?: string; style?: RepopackOutputStyle; headerText?: string; + instructionFilePath?: string; removeComments?: boolean; removeEmptyLines?: boolean; topFilesLength?: number; @@ -23,6 +24,7 @@ export type RepopackConfigDefault = RepopackConfigBase & { filePath: string; style: RepopackOutputStyle; headerText?: string; + instructionFilePath?: string; removeComments: boolean; removeEmptyLines: boolean; topFilesLength: number; diff --git a/src/core/output/outputGenerator.ts b/src/core/output/outputGenerator.ts index b2f31ed..9654ffe 100644 --- a/src/core/output/outputGenerator.ts +++ b/src/core/output/outputGenerator.ts @@ -1,4 +1,7 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; import type { RepopackConfigMerged } from '../../config/configTypes.js'; +import { RepopackError } from '../../shared/errorHandler.js'; import { generateTreeString } from '../file/fileTreeGenerator.js'; import type { ProcessedFile } from '../file/fileTypes.js'; import type { OutputGeneratorContext } from './outputGeneratorTypes.js'; @@ -6,11 +9,12 @@ import { generatePlainStyle } from './plainStyleGenerator.js'; import { generateXmlStyle } from './xmlStyleGenerator.js'; export const generateOutput = async ( + rootDir: string, config: RepopackConfigMerged, processedFiles: ProcessedFile[], allFilePaths: string[], ): Promise => { - const outputGeneratorContext = buildOutputGeneratorContext(config, allFilePaths, processedFiles); + const outputGeneratorContext = await buildOutputGeneratorContext(rootDir, config, allFilePaths, processedFiles); let output: string; switch (config.output.style) { @@ -24,13 +28,28 @@ export const generateOutput = async ( return output; }; -export const buildOutputGeneratorContext = ( +export const buildOutputGeneratorContext = async ( + rootDir: string, config: RepopackConfigMerged, allFilePaths: string[], processedFiles: ProcessedFile[], -): OutputGeneratorContext => ({ - generationDate: new Date().toISOString(), - treeString: generateTreeString(allFilePaths), - processedFiles, - config, -}); +): Promise => { + let repositoryInstruction = ''; + + if (config.output.instructionFilePath) { + const instructionPath = path.resolve(rootDir, config.output.instructionFilePath); + try { + repositoryInstruction = await fs.readFile(instructionPath, 'utf-8'); + } catch { + throw new RepopackError(`Instruction file not found at ${instructionPath}`); + } + } + + return { + generationDate: new Date().toISOString(), + treeString: generateTreeString(allFilePaths), + processedFiles, + config, + instruction: repositoryInstruction, + }; +}; diff --git a/src/core/output/outputGeneratorTypes.ts b/src/core/output/outputGeneratorTypes.ts index dc9847b..bef9275 100644 --- a/src/core/output/outputGeneratorTypes.ts +++ b/src/core/output/outputGeneratorTypes.ts @@ -6,4 +6,5 @@ export interface OutputGeneratorContext { treeString: string; processedFiles: ProcessedFile[]; config: RepopackConfigMerged; + instruction: string; } diff --git a/src/core/output/outputStyleCommonDecorator.ts b/src/core/output/outputStyleCommonDecorator.ts new file mode 100644 index 0000000..64a9ffb --- /dev/null +++ b/src/core/output/outputStyleCommonDecorator.ts @@ -0,0 +1,56 @@ +import type { RepopackConfigMerged } from '../../config/configTypes.js'; + +export const generateHeader = (generationDate: string): string => { + return ` +This file is a merged representation of the entire codebase, combining all repository files into a single document. +Generated by Repopack on: ${generationDate} +`.trim(); +}; + +export const generateSummaryPurpose = (): string => { + return ` +This file contains a packed representation of the entire repository's contents. +It is designed to be easily consumable by AI systems for analysis, code review, +or other automated processes. +`.trim(); +}; + +export const generateSummaryFileFormat = (): string => { + return ` +The content is organized as follows: +1. This summary section +2. Repository information +3. Repository structure +`.trim(); +}; + +export const generateSummaryUsageGuidelines = (config: RepopackConfigMerged, repositoryInstruction: string): string => { + return ` +- This file should be treated as read-only. Any changes should be made to the + original repository files, not this packed version. +- When processing this file, use the file path to distinguish + between different files in the repository. +- Be aware that this file may contain sensitive information. Handle it with + the same level of security as you would the original repository. +${config.output.headerText ? '- Pay special attention to the Repository Description. These contain important context and guidelines specific to this project.' : ''} +${repositoryInstruction ? '- Pay special attention to the Repository Instruction. These contain important context and guidelines specific to this project.' : ''} +`.trim(); +}; + +export const generateSummaryNotes = (config: RepopackConfigMerged): string => { + return ` +- Some files may have been excluded based on .gitignore rules and Repopack's + configuration. +- Binary files are not included in this packed representation. Please refer to + the Repository Structure section for a complete list of file paths, including + binary files. +${config.output.removeComments ? '- Code comments have been removed.\n' : ''} +${config.output.showLineNumbers ? '- Line numbers have been added to the beginning of each line.\n' : ''} +`.trim(); +}; + +export const generateSummaryAdditionalInfo = (): string => { + return ` +For more information about Repopack, visit: https://github.com/yamadashy/repopack +`.trim(); +}; diff --git a/src/core/output/plainStyleGenerator.ts b/src/core/output/plainStyleGenerator.ts index ef2cb0d..7b8ec40 100644 --- a/src/core/output/plainStyleGenerator.ts +++ b/src/core/output/plainStyleGenerator.ts @@ -1,29 +1,56 @@ +import Handlebars from 'handlebars'; import type { OutputGeneratorContext } from './outputGeneratorTypes.js'; +import { + generateHeader, + generateSummaryAdditionalInfo, + generateSummaryFileFormat, + generateSummaryNotes, + generateSummaryPurpose, + generateSummaryUsageGuidelines, +} from './outputStyleCommonDecorator.js'; const PLAIN_SEPARATOR = '='.repeat(16); const PLAIN_LONG_SEPARATOR = '='.repeat(64); -export const generatePlainStyle = (data: OutputGeneratorContext): string => { - const { generationDate, treeString, processedFiles, config } = data; +export const generatePlainStyle = (outputGeneratorContext: OutputGeneratorContext) => { + const template = Handlebars.compile(plainTemplate); + + const renderContext = { + generationHeader: generateHeader(outputGeneratorContext.generationDate), + plainSeparator: PLAIN_SEPARATOR, + plainLongSeparator: PLAIN_LONG_SEPARATOR, + summaryPurpose: generateSummaryPurpose(), + summaryFileFormat: generateSummaryFileFormat(), + summaryUsageGuidelines: generateSummaryUsageGuidelines( + outputGeneratorContext.config, + outputGeneratorContext.instruction, + ), + summaryNotes: generateSummaryNotes(outputGeneratorContext.config), + summaryAdditionalInfo: generateSummaryAdditionalInfo(), + headerText: outputGeneratorContext.config.output.headerText, + instruction: outputGeneratorContext.instruction, + treeString: outputGeneratorContext.treeString, + processedFiles: outputGeneratorContext.processedFiles, + }; + + return `${template(renderContext).trim()}\n`; +}; - let output = `${PLAIN_LONG_SEPARATOR} -Repopack Output File -${PLAIN_LONG_SEPARATOR} +const plainTemplate = ` +{{{generationHeader}}} -This file was generated by Repopack on: ${generationDate} +{{{plainLongSeparator}}} +File Summary +{{{plainLongSeparator}}} Purpose: -------- -This file contains a packed representation of the entire repository's contents. -It is designed to be easily consumable by AI systems for analysis, code review, -or other automated processes. +{{{summaryPurpose}}} File Format: ------------ -The content is organized as follows: -1. This header section -2. Repository structure -3. Multiple file entries, each consisting of: +{{{summaryFileFormat}}} +4. Multiple file entries, each consisting of: a. A separator line (================) b. The file path (File: path/to/file) c. Another separator line @@ -32,54 +59,44 @@ The content is organized as follows: Usage Guidelines: ----------------- -1. This file should be treated as read-only. Any changes should be made to the - original repository files, not this packed version. -2. When processing this file, use the separators and "File:" markers to - distinguish between different files in the repository. -3. Be aware that this file may contain sensitive information. Handle it with - the same level of security as you would the original repository. +{{{summaryUsageGuidelines}}} Notes: ------ -- Some files may have been excluded based on .gitignore rules and Repopack's - configuration. -- Binary files are not included in this packed representation. Please refer to - the Repository Structure section for a complete list of file paths, including - binary files. -${config.output.removeComments ? '- Code comments have been removed.\n' : ''} -${config.output.showLineNumbers ? '- Line numbers have been added to the beginning of each line.\n' : ''} - -For more information about Repopack, visit: https://github.com/yamadashy/repopack +{{{summaryNotes}}} -`; +Additional Info: +---------------- +{{#if headerText}} +User Provided Header: +----------------------- +{{{headerText}}} +{{/if}} - if (config.output.headerText) { - output += `Additional User-Provided Header: --------------------------------- -${config.output.headerText} - -`; - } +{{{summaryAdditionalInfo}}} - output += `${PLAIN_LONG_SEPARATOR} +{{{plainLongSeparator}}} Repository Structure -${PLAIN_LONG_SEPARATOR} -${treeString} +{{{plainLongSeparator}}} +{{{treeString}}} -${PLAIN_LONG_SEPARATOR} +{{{plainLongSeparator}}} Repository Files -${PLAIN_LONG_SEPARATOR} +{{{plainLongSeparator}}} -`; +{{#each processedFiles}} +{{{../plainSeparator}}} +File: {{{this.path}}} +{{{../plainSeparator}}} +{{{this.content}}} - for (const file of processedFiles) { - output += `${PLAIN_SEPARATOR} -File: ${file.path} -${PLAIN_SEPARATOR} -${file.content} +{{/each}} -`; - } +{{#if instruction}} +{{{plainLongSeparator}}} +Instruction +{{{plainLongSeparator}}} +{{{instruction}}} +{{/if}} - return `${output.trim()}\n`; -}; +`; diff --git a/src/core/output/xmlStyleGenerator.ts b/src/core/output/xmlStyleGenerator.ts index a8dfe63..f8eb360 100644 --- a/src/core/output/xmlStyleGenerator.ts +++ b/src/core/output/xmlStyleGenerator.ts @@ -1,81 +1,91 @@ +import Handlebars from 'handlebars'; import type { OutputGeneratorContext } from './outputGeneratorTypes.js'; +import { + generateHeader, + generateSummaryAdditionalInfo, + generateSummaryFileFormat, + generateSummaryNotes, + generateSummaryPurpose, + generateSummaryUsageGuidelines, +} from './outputStyleCommonDecorator.js'; -export const generateXmlStyle = (data: OutputGeneratorContext): string => { - const { generationDate, treeString, processedFiles, config } = data; +export const generateXmlStyle = (outputGeneratorContext: OutputGeneratorContext) => { + const template = Handlebars.compile(xmlTemplate); - let xml = ` + const renderContext = { + generationHeader: generateHeader(outputGeneratorContext.generationDate), + summaryPurpose: generateSummaryPurpose(), + summaryFileFormat: generateSummaryFileFormat(), + summaryUsageGuidelines: generateSummaryUsageGuidelines( + outputGeneratorContext.config, + outputGeneratorContext.instruction, + ), + summaryNotes: generateSummaryNotes(outputGeneratorContext.config), + summaryAdditionalInfo: generateSummaryAdditionalInfo(), + headerText: outputGeneratorContext.config.output.headerText, + instruction: outputGeneratorContext.instruction, + treeString: outputGeneratorContext.treeString, + processedFiles: outputGeneratorContext.processedFiles, + }; -
-Repopack Output File -This file was generated by Repopack on: ${generationDate} -
+ return `${template(renderContext).trim()}\n`; +}; + +const xmlTemplate = ` +{{{generationHeader}}} + + +This section contains a summary of this file. -This file contains a packed representation of the entire repository's contents. -It is designed to be easily consumable by AI systems for analysis, code review, -or other automated processes. +{{{summaryPurpose}}} -The content is organized as follows: -1. This summary section -2. Repository structure -3. Repository files, each consisting of: +{{{summaryFileFormat}}} +4. Repository files, each consisting of: - File path as an attribute - Full contents of the file -1. This file should be treated as read-only. Any changes should be made to the - original repository files, not this packed version. -2. When processing this file, use the file path attributes to distinguish - between different files in the repository. -3. Be aware that this file may contain sensitive information. Handle it with - the same level of security as you would the original repository. +{{{summaryUsageGuidelines}}} -- Some files may have been excluded based on .gitignore rules and Repopack's - configuration. -- Binary files are not included in this packed representation. -${config.output.removeComments ? '- Code comments have been removed.\n' : ''} -${config.output.showLineNumbers ? '- Line numbers have been added to the beginning of each line.\n' : ''} +{{{summaryNotes}}} -For more information about Repopack, visit: https://github.com/yamadashy/repopack - -`; - - if (config.output.headerText) { - xml += ` +{{#if headerText}} -${config.output.headerText} +{{{headerText}}} -`; - } +{{/if}} - xml += ` -
+{{{summaryAdditionalInfo}}} + + + -${treeString} +{{{treeString}}} -`; +This section contains the contents of the repository's files. - for (const file of processedFiles) { - xml += ` - -${file.content} +{{#each processedFiles}} + +{{{this.content}}} -`; - } - xml += ` +{{/each}} -`; - return `${xml.trim()}\n`; -}; +{{#if instruction}} + +{{{instruction}}} + +{{/if}} +`; diff --git a/src/core/packager.ts b/src/core/packager.ts index 8665ea5..d55f1b8 100644 --- a/src/core/packager.ts +++ b/src/core/packager.ts @@ -68,7 +68,7 @@ export const pack = async ( // Generate output progressCallback('Generating output...'); - const output = await deps.generateOutput(config, processedFiles, safeFilePaths); + const output = await deps.generateOutput(rootDir, config, processedFiles, safeFilePaths); // Write output to file. path is relative to the cwd progressCallback('Writing output file...'); diff --git a/tests/core/output/outputGenerator.test.ts b/tests/core/output/outputGenerator.test.ts index e12d545..bdc0eb6 100644 --- a/tests/core/output/outputGenerator.test.ts +++ b/tests/core/output/outputGenerator.test.ts @@ -1,3 +1,4 @@ +import process from 'node:process'; import { describe, expect, test } from 'vitest'; import type { ProcessedFile } from '../../../src/core/file/fileTypes.js'; import { generateOutput } from '../../../src/core/output/outputGenerator.js'; @@ -20,9 +21,9 @@ describe('outputGenerator', () => { { path: 'dir/file2.txt', content: 'content2' }, ]; - const output = await generateOutput(mockConfig, mockProcessedFiles, []); + const output = await generateOutput(process.cwd(), mockConfig, mockProcessedFiles, []); - expect(output).toContain('Repopack Output File'); + expect(output).toContain('File Summary'); expect(output).toContain('File: file1.txt'); expect(output).toContain('content1'); expect(output).toContain('File: dir/file2.txt'); diff --git a/tests/core/output/plainStyleGenerator.test.ts b/tests/core/output/plainStyleGenerator.test.ts index ef8fccc..523b341 100644 --- a/tests/core/output/plainStyleGenerator.test.ts +++ b/tests/core/output/plainStyleGenerator.test.ts @@ -1,3 +1,4 @@ +import process from 'node:process'; import { beforeEach, describe, expect, test, vi } from 'vitest'; import { buildOutputGeneratorContext } from '../../../src/core/output/outputGenerator.js'; import { generatePlainStyle } from '../../../src/core/output/plainStyleGenerator.js'; @@ -23,10 +24,12 @@ describe('outputGenerator', () => { }, }); - const commonData = buildOutputGeneratorContext(mockConfig, [], []); - const output = await generatePlainStyle(commonData); + const context = await buildOutputGeneratorContext(process.cwd(), mockConfig, [], []); + const output = await generatePlainStyle(context); - expect(output).toContain('Repopack Output File'); + expect(output).toContain('File Summary'); + expect(output).toContain('Repository Structure'); expect(output).toContain('Custom header text'); + expect(output).toContain('Repository Files'); }); }); diff --git a/tests/core/output/xmlStyleGenerator.test.ts b/tests/core/output/xmlStyleGenerator.test.ts index ae1a5ad..cd87d3d 100644 --- a/tests/core/output/xmlStyleGenerator.test.ts +++ b/tests/core/output/xmlStyleGenerator.test.ts @@ -1,3 +1,4 @@ +import process from 'node:process'; import { beforeEach, describe, expect, test, vi } from 'vitest'; import { buildOutputGeneratorContext } from '../../../src/core/output/outputGenerator.js'; import { generateXmlStyle } from '../../../src/core/output/xmlStyleGenerator.js'; @@ -23,10 +24,12 @@ describe('outputGenerator', () => { }, }); - const commonData = buildOutputGeneratorContext(mockConfig, [], []); - const output = await generateXmlStyle(commonData); + const context = await buildOutputGeneratorContext(process.cwd(), mockConfig, [], []); + const output = await generateXmlStyle(context); - expect(output).toContain('Repopack Output File'); + expect(output).toContain('file_summary'); + expect(output).toContain('repository_structure'); expect(output).toContain('Custom header text'); + expect(output).toContain('repository_files'); }); }); diff --git a/tests/core/packager.test.ts b/tests/core/packager.test.ts index bdbef66..8d28321 100644 --- a/tests/core/packager.test.ts +++ b/tests/core/packager.test.ts @@ -47,6 +47,36 @@ describe('packager', () => { expect(mockDeps.generateOutput).toHaveBeenCalled(); expect(fs.writeFile).toHaveBeenCalled(); + expect(mockDeps.processFiles).toHaveBeenCalledWith( + [ + expect.objectContaining({ + content: 'raw content 1', + path: 'file1.txt', + }), + expect.objectContaining({ + content: 'raw content 2', + path: file2Path, + }), + ], + mockConfig, + ); + expect(mockDeps.generateOutput).toHaveBeenCalledWith( + 'root', + mockConfig, + [ + expect.objectContaining({ + content: 'processed content 1', + path: 'file1.txt', + }), + expect.objectContaining({ + content: 'processed content 2', + path: file2Path, + }), + ], + ['file1.txt', file2Path], + ); + + // Check the result of pack function expect(result.totalFiles).toBe(2); expect(result.totalCharacters).toBe(38); expect(result.totalTokens).toBe(20); diff --git a/tests/integration-tests/fixtures/packager/outputs/simple-project-output.txt b/tests/integration-tests/fixtures/packager/outputs/simple-project-output.txt index cc0596f..fd02861 100644 --- a/tests/integration-tests/fixtures/packager/outputs/simple-project-output.txt +++ b/tests/integration-tests/fixtures/packager/outputs/simple-project-output.txt @@ -1,9 +1,9 @@ +This file is a merged representation of the entire codebase, combining all repository files into a single document. + ================================================================ -Repopack Output File +File Summary ================================================================ -This file was generated by Repopack on: 2024-08-05T14:48:13.214Z - Purpose: -------- This file contains a packed representation of the entire repository's contents. @@ -13,9 +13,10 @@ or other automated processes. File Format: ------------ The content is organized as follows: -1. This header section -2. Repository structure -3. Multiple file entries, each consisting of: +1. This summary section +2. Repository information +3. Repository structure +4. Multiple file entries, each consisting of: a. A separator line (================) b. The file path (File: path/to/file) c. Another separator line @@ -24,12 +25,13 @@ The content is organized as follows: Usage Guidelines: ----------------- -1. This file should be treated as read-only. Any changes should be made to the +- This file should be treated as read-only. Any changes should be made to the original repository files, not this packed version. -2. When processing this file, use the separators and "File:" markers to - distinguish between different files in the repository. -3. Be aware that this file may contain sensitive information. Handle it with +- When processing this file, use the file path to distinguish + between different files in the repository. +- Be aware that this file may contain sensitive information. Handle it with the same level of security as you would the original repository. +- Pay special attention to the Repository Description. These contain important context and guidelines specific to this project. Notes: ------ @@ -39,14 +41,14 @@ Notes: the Repository Structure section for a complete list of file paths, including binary files. - +Additional Info: +---------------- +User Provided Header: +----------------------- +This repository is simple-project For more information about Repopack, visit: https://github.com/yamadashy/repopack -Additional User-Provided Header: --------------------------------- -This repository is simple-project - ================================================================ Repository Structure ================================================================ diff --git a/tests/integration-tests/fixtures/packager/outputs/simple-project-output.xml b/tests/integration-tests/fixtures/packager/outputs/simple-project-output.xml index 6bf245e..166ed18 100644 --- a/tests/integration-tests/fixtures/packager/outputs/simple-project-output.xml +++ b/tests/integration-tests/fixtures/packager/outputs/simple-project-output.xml @@ -1,8 +1,7 @@ - +This file is a merged representation of the entire codebase, combining all repository files into a single document. -
-Repopack Output File -
+ +This section contains a summary of this file. This file contains a packed representation of the entire repository's contents. @@ -13,38 +12,40 @@ or other automated processes. The content is organized as follows: 1. This summary section -2. Repository structure -3. Repository files, each consisting of: +2. Repository information +3. Repository structure +4. Repository files, each consisting of: - File path as an attribute - Full contents of the file -1. This file should be treated as read-only. Any changes should be made to the +- This file should be treated as read-only. Any changes should be made to the original repository files, not this packed version. -2. When processing this file, use the file path attributes to distinguish +- When processing this file, use the file path to distinguish between different files in the repository. -3. Be aware that this file may contain sensitive information. Handle it with +- Be aware that this file may contain sensitive information. Handle it with the same level of security as you would the original repository. +- Pay special attention to the Repository Description. These contain important context and guidelines specific to this project. - Some files may have been excluded based on .gitignore rules and Repopack's configuration. -- Binary files are not included in this packed representation. - - +- Binary files are not included in this packed representation. Please refer to + the Repository Structure section for a complete list of file paths, including + binary files. -For more information about Repopack, visit: https://github.com/yamadashy/repopack - - This repository is simple-project -
+For more information about Repopack, visit: https://github.com/yamadashy/repopack + + + resources/ @@ -60,6 +61,7 @@ repopack.config.json +This section contains the contents of the repository's files. ignored-data.txt diff --git a/tests/integration-tests/packager.test.ts b/tests/integration-tests/packager.test.ts index 3e91ecf..4e04e44 100644 --- a/tests/integration-tests/packager.test.ts +++ b/tests/integration-tests/packager.test.ts @@ -56,8 +56,8 @@ describe.runIf(!isWindows)('packager integration', () => { let actualOutput = await fs.readFile(actualOutputPath, 'utf-8'); let expectedOutput = await fs.readFile(expectedOutputPath, 'utf-8'); - actualOutput = actualOutput.replace(/^This file was generated by Repopack on:.*\n/gm, ''); - expectedOutput = expectedOutput.replace(/^This file was generated by Repopack on:.*\n/gm, ''); + actualOutput = actualOutput.replace(/^Generated by Repopack on:.*\n/gm, ''); + expectedOutput = expectedOutput.replace(/^Generated by Repopack on:.*\n/gm, ''); // Compare the outputs expect(actualOutput).toBe(expectedOutput); diff --git a/tsconfig.json b/tsconfig.json index 4b04a60..2b8f07d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,6 @@ "resolveJsonModule": true, "types": ["node", "picocolors"] }, - "include": ["src/**/*", "tests/**/*"], - "exclude": ["tests/integration-tests/fixtures"] + "include": ["src/**/*", "tests/**/*"] + // "exclude": ["tests/integration-tests/fixtures"] }