mirror of
https://github.com/yamadashy/repomix.git
synced 2026-02-11 20:28:51 +01:00
- Remove unused imports across 67 files (RepomixConfigMerged, QueryCapture, etc.) - Fix unused parameters by prefixing with underscore (_context, _index, etc.) - Remove unused catch parameters using modern JavaScript syntax - Fix require-yield warnings in generator functions - Remove unused variables and interface declarations - Add oxlint configuration to ignore integration test fixtures Resolves 144 linting warnings while preserving all functionality. All 743 tests continue to pass. Code quality significantly improved.
424 lines
12 KiB
TypeScript
424 lines
12 KiB
TypeScript
import { program } from 'commander';
|
|
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
|
|
import * as defaultAction from '../../src/cli/actions/defaultAction.js';
|
|
import * as initAction from '../../src/cli/actions/initAction.js';
|
|
import * as remoteAction from '../../src/cli/actions/remoteAction.js';
|
|
import * as versionAction from '../../src/cli/actions/versionAction.js';
|
|
import { run, runCli } from '../../src/cli/cliRun.js';
|
|
import type { CliOptions } from '../../src/cli/types.js';
|
|
import type { PackResult } from '../../src/core/packager.js';
|
|
import { type RepomixLogLevel, logger, repomixLogLevels } from '../../src/shared/logger.js';
|
|
import { createMockConfig } from '../testing/testUtils.js';
|
|
|
|
let logLevel: RepomixLogLevel;
|
|
|
|
vi.mock('../../src/shared/logger', () => ({
|
|
repomixLogLevels: {
|
|
SILENT: -1,
|
|
ERROR: 0,
|
|
WARN: 1,
|
|
INFO: 2,
|
|
DEBUG: 3,
|
|
},
|
|
logger: {
|
|
log: vi.fn(),
|
|
trace: vi.fn(),
|
|
debug: vi.fn(),
|
|
info: vi.fn(),
|
|
warn: vi.fn(),
|
|
error: vi.fn(),
|
|
success: vi.fn(),
|
|
note: vi.fn(),
|
|
setLogLevel: vi.fn((level: RepomixLogLevel) => {
|
|
logLevel = level;
|
|
}),
|
|
getLogLevel: vi.fn(() => logLevel),
|
|
},
|
|
setLogLevelByWorkerData: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('../../src/cli/actions/defaultAction');
|
|
vi.mock('../../src/cli/actions/initAction');
|
|
vi.mock('../../src/cli/actions/remoteAction');
|
|
vi.mock('../../src/cli/actions/versionAction');
|
|
|
|
describe('cliRun', () => {
|
|
beforeEach(() => {
|
|
vi.resetAllMocks();
|
|
|
|
vi.mocked(defaultAction.runDefaultAction).mockResolvedValue({
|
|
config: createMockConfig({
|
|
cwd: process.cwd(),
|
|
input: {
|
|
maxFileSize: 50 * 1024 * 1024,
|
|
},
|
|
output: {
|
|
filePath: 'repomix-output.txt',
|
|
style: 'plain',
|
|
stdout: false,
|
|
parsableStyle: false,
|
|
fileSummary: true,
|
|
directoryStructure: true,
|
|
topFilesLength: 5,
|
|
showLineNumbers: false,
|
|
removeComments: false,
|
|
removeEmptyLines: false,
|
|
compress: false,
|
|
copyToClipboard: false,
|
|
files: true,
|
|
git: {
|
|
sortByChanges: true,
|
|
sortByChangesMaxCommits: 100,
|
|
includeDiffs: false,
|
|
},
|
|
},
|
|
include: [],
|
|
ignore: {
|
|
useGitignore: true,
|
|
useDefaultPatterns: true,
|
|
customPatterns: [],
|
|
},
|
|
security: {
|
|
enableSecurityCheck: true,
|
|
},
|
|
tokenCount: {
|
|
encoding: 'o200k_base',
|
|
},
|
|
}),
|
|
packResult: {
|
|
totalFiles: 0,
|
|
totalCharacters: 0,
|
|
totalTokens: 0,
|
|
fileCharCounts: {},
|
|
fileTokenCounts: {},
|
|
suspiciousFilesResults: [],
|
|
gitDiffTokenCount: 0,
|
|
gitLogTokenCount: 0,
|
|
suspiciousGitDiffResults: [],
|
|
suspiciousGitLogResults: [],
|
|
processedFiles: [],
|
|
safeFilePaths: [],
|
|
skippedFiles: [],
|
|
} satisfies PackResult,
|
|
});
|
|
vi.mocked(initAction.runInitAction).mockResolvedValue();
|
|
vi.mocked(remoteAction.runRemoteAction).mockResolvedValue({
|
|
config: createMockConfig({
|
|
cwd: process.cwd(),
|
|
input: {
|
|
maxFileSize: 50 * 1024 * 1024,
|
|
},
|
|
output: {
|
|
filePath: 'repomix-output.txt',
|
|
stdout: false,
|
|
style: 'plain',
|
|
parsableStyle: false,
|
|
fileSummary: true,
|
|
directoryStructure: true,
|
|
topFilesLength: 5,
|
|
showLineNumbers: false,
|
|
removeComments: false,
|
|
removeEmptyLines: false,
|
|
compress: false,
|
|
copyToClipboard: false,
|
|
files: true,
|
|
git: {
|
|
sortByChanges: true,
|
|
sortByChangesMaxCommits: 100,
|
|
includeDiffs: false,
|
|
},
|
|
},
|
|
include: [],
|
|
ignore: {
|
|
useGitignore: true,
|
|
useDefaultPatterns: true,
|
|
customPatterns: [],
|
|
},
|
|
security: {
|
|
enableSecurityCheck: true,
|
|
},
|
|
tokenCount: {
|
|
encoding: 'o200k_base',
|
|
},
|
|
}),
|
|
packResult: {
|
|
totalFiles: 0,
|
|
totalCharacters: 0,
|
|
totalTokens: 0,
|
|
fileCharCounts: {},
|
|
fileTokenCounts: {},
|
|
suspiciousFilesResults: [],
|
|
gitDiffTokenCount: 0,
|
|
gitLogTokenCount: 0,
|
|
suspiciousGitDiffResults: [],
|
|
suspiciousGitLogResults: [],
|
|
processedFiles: [],
|
|
safeFilePaths: [],
|
|
skippedFiles: [],
|
|
} satisfies PackResult,
|
|
});
|
|
vi.mocked(versionAction.runVersionAction).mockResolvedValue();
|
|
});
|
|
|
|
test('should call process.exit(1) on error', async () => {
|
|
const exitSpy = vi.spyOn(process, 'exit').mockImplementationOnce(() => undefined as never);
|
|
const parseSpy = vi.spyOn(program, 'description').mockImplementationOnce(() => {
|
|
throw Error();
|
|
});
|
|
const handleErrorSpy = vi.spyOn(logger, 'error');
|
|
await expect(run()).resolves.not.toThrow();
|
|
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
expect(handleErrorSpy).toHaveBeenCalled();
|
|
exitSpy.mockReset();
|
|
parseSpy.mockReset();
|
|
handleErrorSpy.mockReset();
|
|
});
|
|
|
|
describe('executeAction', () => {
|
|
test('should execute default action when no special options provided', async () => {
|
|
await runCli(['.'], process.cwd(), {});
|
|
|
|
expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(['.'], process.cwd(), expect.any(Object));
|
|
});
|
|
|
|
test('should enable verbose logging when verbose option is true', async () => {
|
|
await runCli(['.'], process.cwd(), { verbose: true });
|
|
|
|
expect(logger.setLogLevel).toHaveBeenCalledWith(repomixLogLevels.DEBUG);
|
|
});
|
|
|
|
test('should execute version action when version option is true', async () => {
|
|
await runCli(['.'], process.cwd(), { version: true });
|
|
|
|
expect(versionAction.runVersionAction).toHaveBeenCalled();
|
|
expect(defaultAction.runDefaultAction).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('should execute init action when init option is true', async () => {
|
|
await runCli(['.'], process.cwd(), { init: true });
|
|
|
|
expect(initAction.runInitAction).toHaveBeenCalledWith(process.cwd(), false);
|
|
expect(defaultAction.runDefaultAction).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('should execute remote action when remote option is provided', async () => {
|
|
await runCli(['.'], process.cwd(), {
|
|
remote: 'yamadashy/repomix',
|
|
});
|
|
|
|
expect(remoteAction.runRemoteAction).toHaveBeenCalledWith('yamadashy/repomix', expect.any(Object));
|
|
expect(defaultAction.runDefaultAction).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('parsable style flag', () => {
|
|
test('should disable parsable style by default', async () => {
|
|
await runCli(['.'], process.cwd(), {});
|
|
|
|
expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
|
|
['.'],
|
|
process.cwd(),
|
|
expect.not.objectContaining({
|
|
parsableStyle: false,
|
|
}),
|
|
);
|
|
});
|
|
|
|
test('should handle --parsable-style flag', async () => {
|
|
await runCli(['.'], process.cwd(), { parsableStyle: true });
|
|
|
|
expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
|
|
['.'],
|
|
process.cwd(),
|
|
expect.objectContaining({
|
|
parsableStyle: true,
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('security check flag', () => {
|
|
test('should enable security check by default', async () => {
|
|
await runCli(['.'], process.cwd(), {});
|
|
|
|
expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
|
|
['.'],
|
|
process.cwd(),
|
|
expect.not.objectContaining({
|
|
securityCheck: false,
|
|
}),
|
|
);
|
|
});
|
|
|
|
test('should handle --no-security-check flag', async () => {
|
|
await runCli(['.'], process.cwd(), { securityCheck: false });
|
|
|
|
expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
|
|
['.'],
|
|
process.cwd(),
|
|
expect.objectContaining({
|
|
securityCheck: false,
|
|
}),
|
|
);
|
|
});
|
|
|
|
test('should handle explicit --security-check flag', async () => {
|
|
await runCli(['.'], process.cwd(), { securityCheck: true });
|
|
|
|
expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
|
|
['.'],
|
|
process.cwd(),
|
|
expect.objectContaining({
|
|
securityCheck: true,
|
|
}),
|
|
);
|
|
});
|
|
|
|
test('should handle explicit --no-gitignore flag', async () => {
|
|
await runCli(['.'], process.cwd(), { gitignore: false });
|
|
|
|
expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
|
|
['.'],
|
|
process.cwd(),
|
|
expect.objectContaining({
|
|
gitignore: false,
|
|
}),
|
|
);
|
|
});
|
|
|
|
test('should handle explicit --no-default-patterns flag', async () => {
|
|
await runCli(['.'], process.cwd(), { defaultPatterns: false });
|
|
|
|
expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
|
|
['.'],
|
|
process.cwd(),
|
|
expect.objectContaining({
|
|
defaultPatterns: false,
|
|
}),
|
|
);
|
|
});
|
|
|
|
test('should handle explicit --header-text flag', async () => {
|
|
await runCli(['.'], process.cwd(), {
|
|
headerText: 'I am a good header text',
|
|
});
|
|
|
|
expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
|
|
['.'],
|
|
process.cwd(),
|
|
expect.objectContaining({
|
|
headerText: 'I am a good header text',
|
|
}),
|
|
);
|
|
});
|
|
|
|
test('should handle --instruction-file-path flag', async () => {
|
|
await runCli(['.'], process.cwd(), {
|
|
instructionFilePath: 'path/to/instruction.txt',
|
|
});
|
|
|
|
expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
|
|
['.'],
|
|
process.cwd(),
|
|
expect.objectContaining({
|
|
instructionFilePath: 'path/to/instruction.txt',
|
|
}),
|
|
);
|
|
});
|
|
|
|
test('should handle --include-empty-directories flag', async () => {
|
|
await runCli(['.'], process.cwd(), {
|
|
includeEmptyDirectories: true,
|
|
});
|
|
|
|
expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
|
|
['.'],
|
|
process.cwd(),
|
|
expect.objectContaining({
|
|
includeEmptyDirectories: true,
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('quiet mode', () => {
|
|
test('should set log level to SILENT when quiet option is true', async () => {
|
|
const options: CliOptions = {
|
|
quiet: true,
|
|
};
|
|
|
|
await runCli(['.'], process.cwd(), options);
|
|
|
|
expect(logger.getLogLevel()).toBe(repomixLogLevels.SILENT);
|
|
});
|
|
|
|
test('should set log level to DEBUG when verbose option is true', async () => {
|
|
const options: CliOptions = {
|
|
verbose: true,
|
|
};
|
|
|
|
await runCli(['.'], process.cwd(), options);
|
|
|
|
expect(logger.getLogLevel()).toBe(repomixLogLevels.DEBUG);
|
|
});
|
|
|
|
test('should set log level to INFO by default', async () => {
|
|
const options: CliOptions = {};
|
|
|
|
await runCli(['.'], process.cwd(), options);
|
|
|
|
expect(logger.getLogLevel()).toBe(repomixLogLevels.INFO);
|
|
});
|
|
});
|
|
|
|
describe('stdout mode', () => {
|
|
const originalIsTTY = process.stdout.isTTY;
|
|
|
|
afterEach(() => {
|
|
process.stdout.isTTY = originalIsTTY;
|
|
});
|
|
|
|
test('should handle --stdout flag', async () => {
|
|
const options: CliOptions = {
|
|
stdout: true,
|
|
};
|
|
|
|
await runCli(['.'], process.cwd(), options);
|
|
|
|
expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
|
|
['.'],
|
|
process.cwd(),
|
|
expect.objectContaining({
|
|
stdout: true,
|
|
}),
|
|
);
|
|
});
|
|
|
|
test('should not enable stdout mode when explicitly setting output', async () => {
|
|
// Mock pipe detection
|
|
process.stdout.isTTY = false;
|
|
const options: CliOptions = {
|
|
output: 'custom-output.txt',
|
|
};
|
|
|
|
await runCli(['.'], process.cwd(), options);
|
|
|
|
// stdout should not be set
|
|
expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
|
|
['.'],
|
|
process.cwd(),
|
|
expect.objectContaining({
|
|
output: 'custom-output.txt',
|
|
}),
|
|
);
|
|
expect(defaultAction.runDefaultAction).not.toHaveBeenCalledWith(
|
|
['.'],
|
|
process.cwd(),
|
|
expect.objectContaining({
|
|
stdout: true,
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
});
|