Files
yamadashy--repomix/tests/core/file/fileProcess.inclusionLevel.test.ts
wehub-resource-sync 719032b19f
Update Schema / Update configuration json schema (push) Has been cancelled
Memory Benchmark / Memory Test (Full Analysis) (push) Has been cancelled
CI Quality / Lint GitHub Actions (actionlint) (push) Has been cancelled
CI Quality / Lint GitHub Actions (zizmor) (push) Has been cancelled
CI Quality / Check typos (push) Has been cancelled
CI / Test coverage (push) Has been cancelled
CI / Test (22.x, windows-latest) (push) Has been cancelled
CI / Test (24.x, macos-latest) (push) Has been cancelled
CI / Test (24.x, ubuntu-latest) (push) Has been cancelled
CI / Test (24.x, windows-latest) (push) Has been cancelled
CI / Test (26.x, macos-latest) (push) Has been cancelled
CI / Test (26.x, ubuntu-latest) (push) Has been cancelled
CI / Test (26.x, windows-latest) (push) Has been cancelled
CI / Test with Bun (latest, macos-latest) (push) Has been cancelled
CI / Test with Bun (latest, ubuntu-latest) (push) Has been cancelled
CI / Test with Bun (latest, windows-latest) (push) Has been cancelled
CI / Build and run (22.x, macos-latest) (push) Has been cancelled
CI / Build and run (22.x, ubuntu-latest) (push) Has been cancelled
CI / Build and run (22.x, windows-latest) (push) Has been cancelled
autofix.ci / autofix (push) Has been cancelled
CI Browser Extension / Lint Browser Extension (push) Has been cancelled
CI Browser Extension / Test Browser Extension (push) Has been cancelled
Memory Benchmark / Memory Test (push) Has been cancelled
CI Website / Lint Website Client (push) Has been cancelled
CI Website / Lint Website Server (push) Has been cancelled
CI Website / Test Website Server (push) Has been cancelled
CI Website / Bundle Website Server (push) Has been cancelled
CI / Lint Biome (push) Has been cancelled
CI / Lint oxlint (push) Has been cancelled
CI / Lint TypeScript (push) Has been cancelled
CI / Lint Secretlint (push) Has been cancelled
CI / Test (22.x, macos-latest) (push) Has been cancelled
CI / Test (22.x, ubuntu-latest) (push) Has been cancelled
CI / Build and run (24.x, macos-latest) (push) Has been cancelled
CI / Build and run (24.x, ubuntu-latest) (push) Has been cancelled
CI / Build and run (24.x, windows-latest) (push) Has been cancelled
CI / Build and run (26.x, macos-latest) (push) Has been cancelled
CI / Build and run (26.x, ubuntu-latest) (push) Has been cancelled
CI / Build and run (26.x, windows-latest) (push) Has been cancelled
CI / Build and run with Bun (latest, macos-latest) (push) Has been cancelled
CI / Build and run with Bun (latest, ubuntu-latest) (push) Has been cancelled
CI / Build and run with Bun (latest, windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Docker / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Docker / build (linux/arm/v7, ubuntu-24.04-arm) (push) Has been cancelled
Docker / build (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker / merge (push) Has been cancelled
Pack repository with Repomix / pack-repo (push) Has been cancelled
Performance Benchmark History / Benchmark (macos-latest) (push) Has been cancelled
Performance Benchmark History / Benchmark (ubuntu-latest) (push) Has been cancelled
Performance Benchmark History / Benchmark (windows-latest) (push) Has been cancelled
Performance Benchmark History / Store Results (push) Has been cancelled
Test Repomix Action / Test Node.js 22 (push) Has been cancelled
Test Repomix Action / Test Node.js 24 (push) Has been cancelled
Test Repomix Action / Test Node.js 26 (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:37 +08:00

231 lines
9.6 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
import type { FileInclusionLevel } from '../../../src/core/file/fileLevelResolve.js';
import type { FileManipulator } from '../../../src/core/file/fileManipulate.js';
import { applyLightweightTransforms, processFiles } from '../../../src/core/file/fileProcess.js';
import type { ProcessedFile, RawFile } from '../../../src/core/file/fileTypes.js';
import type { FileProcessTask } from '../../../src/core/file/workers/fileProcessWorker.js';
import fileProcessWorker from '../../../src/core/file/workers/fileProcessWorker.js';
import { parseFile } from '../../../src/core/treeSitter/parseFile.js';
import type { WorkerOptions } from '../../../src/shared/processConcurrency.js';
import { createMockConfig } from '../../testing/testUtils.js';
// parseFile is the Tree-sitter compression entry point. Mock it so these tests
// assert routing/decisions (which files get compressed) without depending on
// the exact compressed output of the real parser.
vi.mock('../../../src/core/treeSitter/parseFile.js');
vi.mock('../../../src/shared/logger.js');
const mockGetFileManipulator = (_filePath: string): FileManipulator | null => null;
const mockInitTaskRunner = <T, R>(_options: WorkerOptions) => {
return {
run: async (task: T) => {
return (await fileProcessWorker(task as FileProcessTask)) as R;
},
cleanup: async () => {
// no-op for tests
},
};
};
const byPath = (files: ProcessedFile[]): Record<string, string> =>
Object.fromEntries(files.map((f) => [f.path, f.content]));
describe('fileProcess inclusion levels (output.patterns)', () => {
beforeEach(() => {
vi.mocked(parseFile).mockResolvedValue('<<compressed>>');
});
describe('processFiles', () => {
it('excludes directory-only files from the content output while keeping other files', async () => {
const rawFiles: RawFile[] = [
{ path: 'src/index.ts', content: 'const a = 1;' },
{ path: 'website/index.html', content: '<html></html>' },
];
const config = createMockConfig({
output: { patterns: [{ pattern: 'website/**/*', directoryStructureOnly: true }] },
});
const result = await processFiles(rawFiles, config, () => {}, {
initTaskRunner: mockInitTaskRunner,
getFileManipulator: mockGetFileManipulator,
});
expect(result.map((f) => f.path)).toEqual(['src/index.ts']);
});
it('compresses files matched by a compress pattern even when global compress is off', async () => {
const rawFiles: RawFile[] = [
{ path: 'docs/guide.md', content: 'real docs content' },
{ path: 'src/index.ts', content: 'const a = 1;' },
];
const config = createMockConfig({
output: { compress: false, patterns: [{ pattern: 'docs/**/*', compress: true }] },
});
const result = await processFiles(rawFiles, config, () => {}, {
initTaskRunner: mockInitTaskRunner,
getFileManipulator: mockGetFileManipulator,
});
const content = byPath(result);
expect(content['docs/guide.md']).toBe('<<compressed>>');
expect(content['src/index.ts']).toBe('const a = 1;');
});
it('keeps full content for a pattern that overrides a global compress, while still compressing others', async () => {
const rawFiles: RawFile[] = [
{ path: 'src/index.ts', content: 'const a = 1;' },
{ path: 'lib/util.ts', content: 'const b = 2;' },
];
const config = createMockConfig({
output: { compress: true, patterns: [{ pattern: 'src/**/*', compress: false }] },
});
const result = await processFiles(rawFiles, config, () => {}, {
initTaskRunner: mockInitTaskRunner,
getFileManipulator: mockGetFileManipulator,
});
const content = byPath(result);
expect(content['src/index.ts']).toBe('const a = 1;');
expect(content['lib/util.ts']).toBe('<<compressed>>');
});
it('handles compress and directory-only patterns together (compress, exclude, keep full)', async () => {
const rawFiles: RawFile[] = [
{ path: 'src/index.ts', content: 'const a = 1;' },
{ path: 'docs/guide.md', content: 'real docs content' },
{ path: 'website/index.html', content: '<html></html>' },
];
const config = createMockConfig({
output: {
compress: false,
patterns: [
{ pattern: 'docs/**/*', compress: true },
{ pattern: 'website/**/*', directoryStructureOnly: true },
],
},
});
const result = await processFiles(rawFiles, config, () => {}, {
initTaskRunner: mockInitTaskRunner,
getFileManipulator: mockGetFileManipulator,
});
const content = byPath(result);
expect(Object.keys(content).sort()).toEqual(['docs/guide.md', 'src/index.ts']);
expect(content['docs/guide.md']).toBe('<<compressed>>');
expect(content['src/index.ts']).toBe('const a = 1;');
});
it('does not compress when global compress is off and no pattern matches', async () => {
const rawFiles: RawFile[] = [{ path: 'src/index.ts', content: 'const a = 1;' }];
const config = createMockConfig({
output: { compress: false, patterns: [{ pattern: 'docs/**/*', compress: true }] },
});
const result = await processFiles(rawFiles, config, () => {}, {
initTaskRunner: mockInitTaskRunner,
getFileManipulator: mockGetFileManipulator,
});
expect(byPath(result)['src/index.ts']).toBe('const a = 1;');
});
// The packager resolves the inclusion level against each file's
// per-root-relative path (the basis include/ignore use) and threads it on
// rawFile.level before rewriting path to its display form. processFiles must
// honor that threaded level rather than re-deriving it from the display path,
// which is what makes output.patterns match per-root for multiple roots and
// for output.filePathStyle: 'cwd-relative'.
it('honors a precomputed directory-only level threaded on rawFile.level over the path-derived level', async () => {
// No output.patterns are configured, so resolving from the (display) path
// alone would yield 'full'. The threaded 'directory-only' level must win and
// drop the file from the content output.
const rawFiles: RawFile[] = [
{ path: 'app/src/index.ts', content: 'const a = 1;', level: 'directory-only' },
{ path: 'app/README.md', content: '# app', level: 'full' },
];
const config = createMockConfig({ output: {} });
const result = await processFiles(rawFiles, config, () => {}, {
initTaskRunner: mockInitTaskRunner,
getFileManipulator: mockGetFileManipulator,
});
expect(result.map((f) => f.path)).toEqual(['app/README.md']);
});
it('honors a precomputed compress level threaded on rawFile.level over the path-derived level', async () => {
// Global compress is off and no pattern matches, so the path-derived level
// would be 'full'. The threaded 'compress' level must route the file through
// the compression pipeline (worker path).
const rawFiles: RawFile[] = [{ path: 'app/src/index.ts', content: 'const a = 1;', level: 'compress' }];
const config = createMockConfig({ output: { compress: false } });
const result = await processFiles(rawFiles, config, () => {}, {
initTaskRunner: mockInitTaskRunner,
getFileManipulator: mockGetFileManipulator,
});
expect(byPath(result)['app/src/index.ts']).toBe('<<compressed>>');
});
});
describe('applyLightweightTransforms', () => {
it('does not add line numbers to a file compressed via an output pattern', () => {
const files: ProcessedFile[] = [{ path: 'docs/guide.md', content: 'Line 1\nLine 2' }];
const config = createMockConfig({
output: {
showLineNumbers: true,
compress: false,
patterns: [{ pattern: 'docs/**/*', compress: true }],
},
});
const result = applyLightweightTransforms(files, config, () => {}, {
getFileManipulator: mockGetFileManipulator,
});
expect(result).toEqual([{ path: 'docs/guide.md', content: 'Line 1\nLine 2' }]);
});
it('still adds line numbers to files not matched by a compress pattern', () => {
const files: ProcessedFile[] = [{ path: 'src/index.ts', content: 'Line 1\nLine 2' }];
const config = createMockConfig({
output: {
showLineNumbers: true,
compress: false,
patterns: [{ pattern: 'docs/**/*', compress: true }],
},
});
const result = applyLightweightTransforms(files, config, () => {}, {
getFileManipulator: mockGetFileManipulator,
});
expect(result).toEqual([{ path: 'src/index.ts', content: '1: Line 1\n2: Line 2' }]);
});
it('consults a provided fileLevels map instead of recomputing the level', () => {
// The file resolves to 'full' on its own (no patterns), but the precomputed
// map marks it 'compress', so line numbers must be suppressed. This proves the
// map is consulted rather than resolveFileLevel being called again.
const files: ProcessedFile[] = [{ path: 'src/index.ts', content: 'Line 1\nLine 2' }];
const config = createMockConfig({ output: { showLineNumbers: true } });
const fileLevels = new Map<string, FileInclusionLevel>([['src/index.ts', 'compress']]);
const result = applyLightweightTransforms(
files,
config,
() => {},
{ getFileManipulator: mockGetFileManipulator },
fileLevels,
);
expect(result).toEqual([{ path: 'src/index.ts', content: 'Line 1\nLine 2' }]);
});
});
});