mirror of
https://github.com/morluto/rea
synced 2026-10-27 14:42:18 -04:00
135 lines
4.4 KiB
TypeScript
135 lines
4.4 KiB
TypeScript
import {
|
|
mkdir,
|
|
readFile,
|
|
readlink,
|
|
symlink,
|
|
unlink,
|
|
writeFile,
|
|
} from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { expect } from "vitest";
|
|
|
|
import { historicalSourceGraphSchema } from "../../../src/domain/referenceSourceGraph.js";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { cliTest } from "../../support/cli/cliFixture.js";
|
|
|
|
cliTest.skipIf(process.platform === "win32")(
|
|
"resolves source symlink targets through native traversal across retargeting and missing files",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-reference-native-links-");
|
|
const config = await createTestTempDirectory("rea-reference-link-config-");
|
|
const outside = await createTestTempDirectory(
|
|
"rea-reference-link-outside-",
|
|
);
|
|
for (const directory of [
|
|
join(root, "first"),
|
|
join(root, "second"),
|
|
outside,
|
|
]) {
|
|
await mkdir(join(directory, "deep"), { recursive: true });
|
|
await writeFile(
|
|
join(directory, "source.js"),
|
|
"export const selected = true;\n",
|
|
);
|
|
}
|
|
await writeFile(join(root, "source.js"), "export const decoy = true;\n");
|
|
const alias = join(root, "alias");
|
|
await symlink(join(root, "first/deep"), alias);
|
|
await symlink("alias/../source.js", join(root, "selected.js"));
|
|
await symlink("alias/../../source.js", join(root, "parent.js"));
|
|
await symlink("absent/../source.js", join(root, "missing-parent.js"));
|
|
await symlink("source.js/", join(root, "directory-required.js"));
|
|
await symlink("source.js/..", join(root, "file-parent.js"));
|
|
await symlink("source.js/../source.js", join(root, "file-parent-child.js"));
|
|
const run = async () => {
|
|
const result = await cli.run({
|
|
arguments: ["import-reference-source", root, "--json"],
|
|
environment: {
|
|
HOME: config,
|
|
XDG_CONFIG_HOME: config,
|
|
XDG_CACHE_HOME: config,
|
|
},
|
|
});
|
|
expect(result.exitCode, result.stderr + JSON.stringify(result.json)).toBe(
|
|
0,
|
|
);
|
|
return historicalSourceGraphSchema.parse(result.json);
|
|
};
|
|
const first = await run();
|
|
expect(first.entries).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
path: "selected.js",
|
|
target: "first/source.js",
|
|
target_state: "internal",
|
|
}),
|
|
expect.objectContaining({
|
|
path: "parent.js",
|
|
target: "source.js",
|
|
target_state: "internal",
|
|
}),
|
|
expect.objectContaining({
|
|
path: "missing-parent.js",
|
|
target: `${root}/absent/../source.js`,
|
|
target_state: "missing",
|
|
}),
|
|
expect.objectContaining({
|
|
path: "directory-required.js",
|
|
target: `${root}/source.js/`,
|
|
target_state: "missing",
|
|
}),
|
|
expect.objectContaining({
|
|
path: "file-parent.js",
|
|
target: `${root}/source.js/..`,
|
|
target_state: "missing",
|
|
}),
|
|
expect.objectContaining({
|
|
path: "file-parent-child.js",
|
|
target: `${root}/source.js/../source.js`,
|
|
target_state: "missing",
|
|
}),
|
|
]),
|
|
);
|
|
await unlink(alias);
|
|
await symlink(join(root, "second/deep"), alias);
|
|
const second = await run();
|
|
expect(second.entries).toContainEqual(
|
|
expect.objectContaining({
|
|
path: "selected.js",
|
|
target: "second/source.js",
|
|
target_state: "internal",
|
|
}),
|
|
);
|
|
await unlink(join(root, "second/source.js"));
|
|
const missing = await run();
|
|
expect(missing.entries).toContainEqual(
|
|
expect.objectContaining({
|
|
path: "selected.js",
|
|
target: "second/source.js",
|
|
target_state: "missing",
|
|
}),
|
|
);
|
|
await unlink(alias);
|
|
await symlink(join(outside, "deep"), alias);
|
|
const external = await run();
|
|
expect(external.entries).toContainEqual(
|
|
expect.objectContaining({
|
|
path: "selected.js",
|
|
target: join(outside, "source.js"),
|
|
target_state: "external",
|
|
}),
|
|
);
|
|
expect(
|
|
external.entries
|
|
.filter((entry) => entry.kind === "file")
|
|
.map((entry) => entry.path),
|
|
).toEqual(["first/source.js", "source.js"]);
|
|
expect(await readlink(join(root, "selected.js"))).toBe(
|
|
"alias/../source.js",
|
|
);
|
|
expect(await readFile(join(root, "source.js"), "utf8")).toBe(
|
|
"export const decoy = true;\n",
|
|
);
|
|
},
|
|
);
|