88 lines
2.8 KiB
TypeScript
88 lines
2.8 KiB
TypeScript
import * as fs from 'fs/promises';
|
|
import * as os from 'os';
|
|
import * as path from 'path';
|
|
|
|
const DEFAULT_PROJECT_ROOT_TOKEN = '__PROJECT_ROOT__';
|
|
const FIXTURE_ROOT = path.join(process.cwd(), 'test', 'fixtures', 'team', 'task-change-ledger');
|
|
|
|
export type TaskChangeLedgerFixtureManifest = {
|
|
schemaVersion: number;
|
|
name: string;
|
|
taskId: string;
|
|
description: string;
|
|
projectRootToken?: string;
|
|
expected?: {
|
|
totalFiles?: number;
|
|
warnings?: string[];
|
|
relativePaths?: string[];
|
|
relationKinds?: Array<'rename' | 'copy'>;
|
|
};
|
|
};
|
|
|
|
export type MaterializedTaskChangeLedgerFixture = {
|
|
rootDir: string;
|
|
projectDir: string;
|
|
manifest: TaskChangeLedgerFixtureManifest;
|
|
cleanup: () => Promise<void>;
|
|
};
|
|
|
|
function replaceTokenInValue<T>(value: T, token: string, replacement: string): T {
|
|
if (typeof value === 'string') {
|
|
return value.split(token).join(replacement) as T;
|
|
}
|
|
if (Array.isArray(value)) {
|
|
return value.map((item) => replaceTokenInValue(item, token, replacement)) as T;
|
|
}
|
|
if (value && typeof value === 'object') {
|
|
return Object.fromEntries(
|
|
Object.entries(value as Record<string, unknown>).map(([key, item]) => [
|
|
key,
|
|
replaceTokenInValue(item, token, replacement),
|
|
])
|
|
) as T;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
async function rewriteProjectRootTokens(rootDir: string, token: string, projectDir: string): Promise<void> {
|
|
const jsonStringReplacement = JSON.stringify(projectDir).slice(1, -1);
|
|
const entries = await fs.readdir(rootDir, { withFileTypes: true });
|
|
for (const entry of entries) {
|
|
const entryPath = path.join(rootDir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
await rewriteProjectRootTokens(entryPath, token, projectDir);
|
|
continue;
|
|
}
|
|
if (!['.json', '.jsonl'].includes(path.extname(entry.name))) {
|
|
continue;
|
|
}
|
|
const raw = await fs.readFile(entryPath, 'utf8');
|
|
await fs.writeFile(entryPath, raw.split(token).join(jsonStringReplacement), 'utf8');
|
|
}
|
|
}
|
|
|
|
export async function materializeTaskChangeLedgerFixture(
|
|
fixtureName: string
|
|
): Promise<MaterializedTaskChangeLedgerFixture> {
|
|
const sourceDir = path.join(FIXTURE_ROOT, fixtureName);
|
|
const rootDir = await fs.mkdtemp(path.join(os.tmpdir(), `task-change-ledger-${fixtureName}-`));
|
|
await fs.cp(sourceDir, rootDir, { recursive: true });
|
|
|
|
const manifestPath = path.join(rootDir, 'manifest.json');
|
|
const manifest = JSON.parse(
|
|
await fs.readFile(manifestPath, 'utf8')
|
|
) as TaskChangeLedgerFixtureManifest;
|
|
const projectDir = path.join(rootDir, 'project');
|
|
const token = manifest.projectRootToken ?? DEFAULT_PROJECT_ROOT_TOKEN;
|
|
|
|
await rewriteProjectRootTokens(rootDir, token, projectDir);
|
|
|
|
return {
|
|
rootDir,
|
|
projectDir,
|
|
manifest: replaceTokenInValue(manifest, token, projectDir),
|
|
cleanup: async () => {
|
|
await fs.rm(rootDir, { recursive: true, force: true });
|
|
},
|
|
};
|
|
}
|