mirror of
https://github.com/morluto/rea
synced 2026-10-26 06:16:17 -04:00
244 lines
8.2 KiB
TypeScript
244 lines
8.2 KiB
TypeScript
import fs from "node:fs";
|
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
|
|
import { add, commit, init } from "isomorphic-git";
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
|
|
import {
|
|
importReferenceSource,
|
|
normalizeHistoricalSourceParseFailures,
|
|
} from "../../../src/application/ReferenceSourceImport.js";
|
|
import { projectReferenceSourceEntryFailure } from "../../../src/application/ReferenceSourceImportEntries.js";
|
|
import {
|
|
projectReferenceSourceImportError,
|
|
type ReferenceSourceImportError,
|
|
} from "../../../src/application/ReferenceSourceImportTypes.js";
|
|
import { createHistoricalSourceManifest } from "../../../src/domain/referenceSourceGraph.js";
|
|
|
|
const fixture = async (parent: string, name: string): Promise<string> => {
|
|
const root = join(parent, name);
|
|
await mkdir(join(root, "src"), { recursive: true });
|
|
await Promise.all([
|
|
writeFile(join(root, "src", "main.ts"), 'import "./dep";\n'),
|
|
writeFile(join(root, "src", "dep.ts"), "export const value = 1;\n"),
|
|
writeFile(join(root, "src", "broken.ts"), "const = ;\n"),
|
|
writeFile(join(root, ".env"), "SECRET_SENTINEL=do-not-record\n"),
|
|
writeFile(join(root, "package.json"), '{"name":"fixture"}\n'),
|
|
]);
|
|
return root;
|
|
};
|
|
|
|
const importTree = (root: string, signal?: AbortSignal) =>
|
|
importReferenceSource({
|
|
root,
|
|
caller: "reference-import-test",
|
|
policy: {
|
|
secretPatterns: [".env", ".env.*"],
|
|
},
|
|
...(signal === undefined ? {} : { signal }),
|
|
});
|
|
|
|
describe("reference source import error projection", () => {
|
|
it("deduplicates exact parse failures without collapsing distinct reasons", () => {
|
|
const malformed = {
|
|
path: "src/main.ts",
|
|
parser: "babel",
|
|
reason: "Malformed input",
|
|
};
|
|
const unexpected = {
|
|
path: "src/main.ts",
|
|
parser: "babel",
|
|
reason: "Unexpected token",
|
|
};
|
|
|
|
expect(
|
|
normalizeHistoricalSourceParseFailures([
|
|
unexpected,
|
|
malformed,
|
|
unexpected,
|
|
]),
|
|
).toEqual([malformed, unexpected]);
|
|
});
|
|
|
|
it("projects entry failures without low-level reader diagnostics", () => {
|
|
for (const [kind, code] of [
|
|
["directory", "io"],
|
|
["symlink", "io"],
|
|
["file", "io"],
|
|
["file", "cancelled"],
|
|
["unknown", "unsupported"],
|
|
] as const) {
|
|
const message = projectReferenceSourceEntryFailure({
|
|
status: "failed",
|
|
path: "safe/path",
|
|
kind,
|
|
code,
|
|
message: "SECRET internal diagnostic /private/path",
|
|
});
|
|
expect(message).not.toContain("SECRET");
|
|
expect(message).not.toContain("/private/path");
|
|
expect(message).toMatch(/Check|try again|when ready|smaller|supported/u);
|
|
}
|
|
});
|
|
|
|
it("projects every import failure without raw parser or policy text", () => {
|
|
const expectedCategories = {
|
|
cancelled: "cancelled",
|
|
"invalid-root": "invalid_input",
|
|
io: "execution_failure",
|
|
parse: "execution_failure",
|
|
} as const;
|
|
for (const [code, category] of Object.entries(expectedCategories)) {
|
|
const projected = projectReferenceSourceImportError({
|
|
tag: "reference-source-import",
|
|
code: code as ReferenceSourceImportError["code"],
|
|
message: "SECRET parser stack and /private/path",
|
|
});
|
|
expect(projected.category).toBe(category);
|
|
expect(projected.message).not.toContain("SECRET");
|
|
expect(projected.message).not.toContain("/private/path");
|
|
expect(projected.message).toMatch(/try again|when ready|Check that/u);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("reference source import behavior", () => {
|
|
it("imports a source file larger than the former 16 MiB ceiling", async () => {
|
|
const root = await createTestTempDirectory("rea-reference-large-");
|
|
const size = 16 * 1024 * 1024 + 1;
|
|
await writeFile(join(root, "large.bin"), Buffer.alloc(size, 0x61));
|
|
|
|
const result = await importReferenceSource({
|
|
root,
|
|
caller: "reference-import-test",
|
|
policy: { secretPatterns: [] },
|
|
});
|
|
|
|
expect(result.ok).toBe(true);
|
|
if (!result.ok) return;
|
|
expect(result.value.entries).toContainEqual(
|
|
expect.objectContaining({
|
|
path: "large.bin",
|
|
kind: "file",
|
|
size,
|
|
content_state: "hashed",
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("imports more than ten thousand source entries", async () => {
|
|
const root = await createTestTempDirectory("rea-reference-many-");
|
|
await Promise.all(
|
|
Array.from({ length: 10_001 }, (_, index) =>
|
|
writeFile(join(root, `entry-${String(index).padStart(5, "0")}`), ""),
|
|
),
|
|
);
|
|
|
|
const result = await importReferenceSource({
|
|
root,
|
|
caller: "reference-import-test",
|
|
policy: { secretPatterns: [] },
|
|
});
|
|
|
|
expect(result.ok).toBe(true);
|
|
if (!result.ok) return;
|
|
expect(result.value.entries).toHaveLength(10_001);
|
|
});
|
|
|
|
it("imports BMP and supplementary filenames in Unicode code point order", async () => {
|
|
const root = await createTestTempDirectory("reference-unicode-");
|
|
try {
|
|
const paths = ["\uE000.ts", "\u{10000}.ts"];
|
|
await Promise.all(
|
|
paths.map((path) =>
|
|
writeFile(join(root, path), "export const value = 1;\n"),
|
|
),
|
|
);
|
|
const result = await importTree(root);
|
|
expect(result.ok).toBe(true);
|
|
if (!result.ok) return;
|
|
expect(result.value.entries.map(({ path }) => path)).toEqual(paths);
|
|
const repeated = await importTree(root);
|
|
expect(repeated).toEqual(result);
|
|
} finally {
|
|
await rm(root, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
it("is relocation-stable, resolves imports, and excludes secrets before capture", async () => {
|
|
const parent = await createTestTempDirectory("rea-reference-import-");
|
|
try {
|
|
const leftRoot = await fixture(parent, "left");
|
|
const rightRoot = await fixture(parent, "right");
|
|
const [left, right] = await Promise.all([
|
|
importTree(leftRoot),
|
|
importTree(rightRoot),
|
|
]);
|
|
expect(left.ok).toBe(true);
|
|
expect(right.ok).toBe(true);
|
|
if (!left.ok || !right.ok) throw new Error("expected imports to pass");
|
|
expect(createHistoricalSourceManifest(left.value)).toEqual(
|
|
createHistoricalSourceManifest(right.value),
|
|
);
|
|
expect(left.value.relationships).toContainEqual(
|
|
expect.objectContaining({
|
|
from_path: "src/main.ts",
|
|
to: "src/dep.ts",
|
|
resolution: "internal",
|
|
}),
|
|
);
|
|
expect(left.value.parse_failures).toHaveLength(1);
|
|
expect(left.value.exclusions).toContainEqual({
|
|
path: ".env",
|
|
reason: "configured-secret",
|
|
});
|
|
expect(JSON.stringify(left.value)).not.toContain("SECRET_SENTINEL");
|
|
expect(JSON.stringify(left.value)).not.toContain(leftRoot);
|
|
} finally {
|
|
await rm(parent, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
it("imports the caller-selected directory and honors cancellation", async () => {
|
|
const outside = await createTestTempDirectory("rea-reference-outside-");
|
|
try {
|
|
const root = await fixture(outside, "tree");
|
|
expect(await importTree(root)).toMatchObject({ ok: true });
|
|
const controller = new AbortController();
|
|
controller.abort();
|
|
const cancelled = await importTree(root, controller.signal);
|
|
expect(cancelled).toMatchObject({
|
|
ok: false,
|
|
error: { code: "cancelled" },
|
|
});
|
|
} finally {
|
|
await rm(outside, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
it("records bounded local Git state without invoking Git", async () => {
|
|
const parent = await createTestTempDirectory("rea-reference-git-");
|
|
try {
|
|
const root = await fixture(parent, "repo");
|
|
await init({ fs, dir: root, defaultBranch: "main" });
|
|
for (const filepath of ["package.json", "src/main.ts", "src/dep.ts"])
|
|
await add({ fs, dir: root, filepath });
|
|
const oid = await commit({
|
|
fs,
|
|
dir: root,
|
|
author: { name: "REA Test", email: "rea@example.invalid" },
|
|
message: "fixture",
|
|
});
|
|
const result = await importTree(root);
|
|
expect(result.ok).toBe(true);
|
|
if (!result.ok) throw result.error;
|
|
expect(result.value.vcs).toEqual({ kind: "git", head: oid, dirty: null });
|
|
} finally {
|
|
await rm(parent, { recursive: true, force: true });
|
|
}
|
|
});
|
|
});
|