Skip to content

Commit

Permalink
Allow for passing in multiple directories
Browse files Browse the repository at this point in the history
  • Loading branch information
rchatrath7 committed Feb 6, 2025
1 parent 836abcd commit e6834d9
Show file tree
Hide file tree
Showing 12 changed files with 160 additions and 90 deletions.
61 changes: 47 additions & 14 deletions src/cli/actions/defaultAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface DefaultActionRunnerResult {
}

export const runDefaultAction = async (
directory: string,
directories: string[],
cwd: string,
options: CliOptions,
): Promise<DefaultActionRunnerResult> => {
Expand All @@ -43,15 +43,15 @@ export const runDefaultAction = async (

logger.trace('Merged config:', config);

const targetPath = path.resolve(directory);
const targetPaths = directories.map((directory) => path.resolve(directory));

const spinner = new Spinner('Packing files...');
spinner.start();

let packResult: PackResult;

try {
packResult = await pack(targetPath, config, (message) => {
packResult = await pack(targetPaths, config, (message) => {
spinner.update(message);
});
} catch (error) {
Expand Down Expand Up @@ -104,37 +104,64 @@ const buildCliConfig = (options: CliOptions): RepomixConfigCli => {
cliConfig.ignore = { ...cliConfig.ignore, useGitignore: options.gitignore };
}
if (options.defaultPatterns !== undefined) {
cliConfig.ignore = { ...cliConfig.ignore, useDefaultPatterns: options.defaultPatterns };
cliConfig.ignore = {
...cliConfig.ignore,
useDefaultPatterns: options.defaultPatterns,
};
}
if (options.topFilesLen !== undefined) {
cliConfig.output = { ...cliConfig.output, topFilesLength: options.topFilesLen };
cliConfig.output = {
...cliConfig.output,
topFilesLength: options.topFilesLen,
};

Check warning on line 116 in src/cli/actions/defaultAction.ts

View check run for this annotation

Codecov / codecov/patch

src/cli/actions/defaultAction.ts#L113-L116

Added lines #L113 - L116 were not covered by tests
}
if (options.outputShowLineNumbers !== undefined) {
cliConfig.output = { ...cliConfig.output, showLineNumbers: options.outputShowLineNumbers };
cliConfig.output = {
...cliConfig.output,
showLineNumbers: options.outputShowLineNumbers,
};

Check warning on line 122 in src/cli/actions/defaultAction.ts

View check run for this annotation

Codecov / codecov/patch

src/cli/actions/defaultAction.ts#L119-L122

Added lines #L119 - L122 were not covered by tests
}
if (options.copy) {
cliConfig.output = { ...cliConfig.output, copyToClipboard: options.copy };
}
if (options.style) {
cliConfig.output = { ...cliConfig.output, style: options.style.toLowerCase() as RepomixOutputStyle };
cliConfig.output = {
...cliConfig.output,
style: options.style.toLowerCase() as RepomixOutputStyle,
};
}
if (options.parsableStyle !== undefined) {
cliConfig.output = { ...cliConfig.output, parsableStyle: options.parsableStyle };
cliConfig.output = {
...cliConfig.output,
parsableStyle: options.parsableStyle,
};
}
if (options.securityCheck !== undefined) {
cliConfig.security = { enableSecurityCheck: options.securityCheck };
}
if (options.fileSummary !== undefined) {
cliConfig.output = { ...cliConfig.output, fileSummary: options.fileSummary };
cliConfig.output = {
...cliConfig.output,
fileSummary: options.fileSummary,
};
}
if (options.directoryStructure !== undefined) {
cliConfig.output = { ...cliConfig.output, directoryStructure: options.directoryStructure };
cliConfig.output = {
...cliConfig.output,
directoryStructure: options.directoryStructure,
};
}
if (options.removeComments !== undefined) {
cliConfig.output = { ...cliConfig.output, removeComments: options.removeComments };
cliConfig.output = {
...cliConfig.output,
removeComments: options.removeComments,
};
}
if (options.removeEmptyLines !== undefined) {
cliConfig.output = { ...cliConfig.output, removeEmptyLines: options.removeEmptyLines };
cliConfig.output = {
...cliConfig.output,
removeEmptyLines: options.removeEmptyLines,
};
}
if (options.headerText !== undefined) {
cliConfig.output = { ...cliConfig.output, headerText: options.headerText };
Expand All @@ -143,10 +170,16 @@ const buildCliConfig = (options: CliOptions): RepomixConfigCli => {
cliConfig.tokenCount = { encoding: options.tokenCountEncoding };
}
if (options.instructionFilePath) {
cliConfig.output = { ...cliConfig.output, instructionFilePath: options.instructionFilePath };
cliConfig.output = {
...cliConfig.output,
instructionFilePath: options.instructionFilePath,
};
}
if (options.includeEmptyDirectories) {
cliConfig.output = { ...cliConfig.output, includeEmptyDirectories: options.includeEmptyDirectories };
cliConfig.output = {
...cliConfig.output,
includeEmptyDirectories: options.includeEmptyDirectories,
};
}

try {
Expand Down
2 changes: 1 addition & 1 deletion src/cli/actions/remoteAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const runRemoteAction = async (
logger.log('');

// Run the default action on the cloned repository
result = await deps.runDefaultAction(tempDirPath, tempDirPath, options);
result = await deps.runDefaultAction([tempDirPath], tempDirPath, options);
await copyOutputToCurrentDirectory(tempDirPath, process.cwd(), result.config.output.filePath);
} catch (error) {
spinner.fail('Error during repository cloning. cleanup...');
Expand Down
8 changes: 4 additions & 4 deletions src/cli/cliRun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const run = async () => {
try {
program
.description('Repomix - Pack your repository into a single AI-friendly file')
.arguments('[directory]')
.arguments('[directories...]')
.option('-v, --version', 'show version information')
.option('-o, --output <file>', 'specify the output file name')
.option('--include <patterns>', 'list of include patterns (comma-separated)')
Expand Down Expand Up @@ -73,15 +73,15 @@ export const run = async () => {
.option('--no-security-check', 'disable security check')
.option('--instruction-file-path <path>', 'path to a file containing detailed custom instructions')
.option('--include-empty-directories', 'include empty directories in the output')
.action((directory = '.', options: CliOptions = {}) => executeAction(directory, process.cwd(), options));
.action((directories = ['.'], options: CliOptions = {}) => executeAction(directories, process.cwd(), options));

await program.parseAsync(process.argv);
} catch (error) {
handleError(error);
}
};

export const executeAction = async (directory: string, cwd: string, options: CliOptions) => {
export const executeAction = async (directories: string[], cwd: string, options: CliOptions) => {
logger.setVerbose(options.verbose || false);

if (options.version) {
Expand All @@ -102,5 +102,5 @@ export const executeAction = async (directory: string, cwd: string, options: Cli
return;
}

await runDefaultAction(directory, cwd, options);
await runDefaultAction(directories, cwd, options);
};
18 changes: 12 additions & 6 deletions src/core/output/outputGenerate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { XMLBuilder } from 'fast-xml-parser';
import Handlebars from 'handlebars';
import type { RepomixConfigMerged } from '../../config/configSchema.js';
import { RepomixError } from '../../shared/errorHandle.js';
import { searchFiles } from '../file/fileSearch.js';
import { type FileSearchResult, searchFiles } from '../file/fileSearch.js';
import { generateTreeString } from '../file/fileTreeGenerate.js';
import type { ProcessedFile } from '../file/fileTypes.js';
import type { OutputGeneratorContext, RenderContext } from './outputGeneratorTypes.js';
Expand Down Expand Up @@ -112,12 +112,12 @@ const generateHandlebarOutput = async (config: RepomixConfigMerged, renderContex
};

export const generateOutput = async (
rootDir: string,
rootDirs: string[],
config: RepomixConfigMerged,
processedFiles: ProcessedFile[],
allFilePaths: string[],
): Promise<string> => {
const outputGeneratorContext = await buildOutputGeneratorContext(rootDir, config, allFilePaths, processedFiles);
const outputGeneratorContext = await buildOutputGeneratorContext(rootDirs, config, allFilePaths, processedFiles);
const renderContext = createRenderContext(outputGeneratorContext);

if (!config.output.parsableStyle) return generateHandlebarOutput(config, renderContext);
Expand All @@ -132,7 +132,7 @@ export const generateOutput = async (
};

export const buildOutputGeneratorContext = async (
rootDir: string,
rootDirs: string[],
config: RepomixConfigMerged,
allFilePaths: string[],
processedFiles: ProcessedFile[],
Expand All @@ -151,8 +151,14 @@ export const buildOutputGeneratorContext = async (
let emptyDirPaths: string[] = [];
if (config.output.includeEmptyDirectories) {
try {
const searchResult = await searchFiles(rootDir, config);
emptyDirPaths = searchResult.emptyDirPaths;
emptyDirPaths = (await Promise.all(rootDirs.map((rootDir) => searchFiles(rootDir, config)))).reduce(
(acc: FileSearchResult, curr: FileSearchResult) =>
({
filePaths: [...acc.filePaths, ...curr.filePaths],
emptyDirPaths: [...acc.emptyDirPaths, ...curr.emptyDirPaths],
}) as FileSearchResult,
{ filePaths: [], emptyDirPaths: [] },
).emptyDirPaths;

Check warning on line 161 in src/core/output/outputGenerate.ts

View check run for this annotation

Codecov / codecov/patch

src/core/output/outputGenerate.ts#L154-L161

Added lines #L154 - L161 were not covered by tests
} catch (error) {
if (error instanceof Error) {
throw new RepomixError(`Failed to search for empty directories: ${error.message}`);
Expand Down
20 changes: 15 additions & 5 deletions src/core/packager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import type { RepomixConfigMerged } from '../config/configSchema.js';
import type { RepomixProgressCallback } from '../shared/types.js';
import { collectFiles } from './file/fileCollect.js';
import { processFiles } from './file/fileProcess.js';
import { searchFiles } from './file/fileSearch.js';
import { FileSearchResult, searchFiles } from './file/fileSearch.js';
import type { RawFile } from './file/fileTypes.js';
import { calculateMetrics } from './metrics/calculateMetrics.js';
import { generateOutput } from './output/outputGenerate.js';
import { copyToClipboardIfEnabled } from './packager/copyToClipboardIfEnabled.js';
Expand All @@ -20,7 +21,7 @@ export interface PackResult {
}

export const pack = async (
rootDir: string,
rootDirs: string[],
config: RepomixConfigMerged,
progressCallback: RepomixProgressCallback = () => {},
deps = {
Expand All @@ -35,10 +36,19 @@ export const pack = async (
},
): Promise<PackResult> => {
progressCallback('Searching for files...');
const { filePaths } = await deps.searchFiles(rootDir, config);
const filePathsByDir = await Promise.all(
rootDirs.map(async (rootDir) => ({
rootDir,
filePaths: (await deps.searchFiles(rootDir, config)).filePaths,
})),
);

progressCallback('Collecting files...');
const rawFiles = await deps.collectFiles(filePaths, rootDir, progressCallback);
const rawFiles = (
await Promise.all(
filePathsByDir.map(({ rootDir, filePaths }) => deps.collectFiles(filePaths, rootDir, progressCallback)),
)
).reduce((acc: RawFile[], curr: RawFile[]) => acc.concat(...curr), []);

const { safeFilePaths, safeRawFiles, suspiciousFilesResults } = await deps.validateFileSafety(
rawFiles,
Expand All @@ -51,7 +61,7 @@ export const pack = async (
const processedFiles = await deps.processFiles(safeRawFiles, config, progressCallback);

progressCallback('Generating output...');
const output = await deps.generateOutput(rootDir, config, processedFiles, safeFilePaths);
const output = await deps.generateOutput(rootDirs, config, processedFiles, safeFilePaths);

progressCallback('Writing output file...');
await deps.writeOutputToDisk(output, config);
Expand Down
Loading

0 comments on commit e6834d9

Please sign in to comment.