138 lines
4.4 KiB
TypeScript
138 lines
4.4 KiB
TypeScript
import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { describe, expect, it } from "@suaveplan/testing/runner";
|
|
import {
|
|
build,
|
|
buildRegistryIndex,
|
|
buildRegistryItem,
|
|
parseArgs,
|
|
serialize,
|
|
validateIndex,
|
|
validateItem,
|
|
} from "./build-registry.js";
|
|
|
|
describe("build-registry", () => {
|
|
it(
|
|
"buildRegistryItem produces a shadcn-compatible item",
|
|
{ timeout: 5000 },
|
|
() => {
|
|
const item = buildRegistryItem("button");
|
|
expect(item.name).toBe("@suaveplan/button");
|
|
expect(item.type).toBe("registry:ui");
|
|
expect(item.files).toEqual([
|
|
{ path: "button.tsx", type: "registry:ui" },
|
|
]);
|
|
expect(validateItem(item)).toBe(true);
|
|
}
|
|
);
|
|
|
|
it(
|
|
"buildRegistryIndex includes every supplied name",
|
|
{ timeout: 5000 },
|
|
() => {
|
|
const idx = buildRegistryIndex(["button", "card"]);
|
|
expect(idx.items).toHaveLength(2);
|
|
expect(idx.items[0]?.name).toBe("@suaveplan/button");
|
|
expect(validateIndex(idx)).toBe(true);
|
|
}
|
|
);
|
|
|
|
it(
|
|
"parseArgs picks up --out and --components flags",
|
|
{ timeout: 5000 },
|
|
() => {
|
|
const parsed = parseArgs([
|
|
"--out",
|
|
"/tmp/out",
|
|
"--components",
|
|
"/tmp/src/components",
|
|
]);
|
|
expect(parsed.outDir).toBe("/tmp/out");
|
|
expect(parsed.componentsDir).toBe("/tmp/src/components");
|
|
}
|
|
);
|
|
|
|
it(
|
|
"serialize emits canonical JSON with trailing newline",
|
|
{ timeout: 5000 },
|
|
() => {
|
|
const out = serialize({ a: 1 });
|
|
expect(out).toBe('{\n "a": 1\n}\n');
|
|
}
|
|
);
|
|
|
|
it(
|
|
"build emits an empty index when components dir does not exist",
|
|
{ timeout: 10000 },
|
|
async () => {
|
|
const dir = await mkdtemp(join(tmpdir(), "registry-empty-"));
|
|
const componentsDir = join(dir, "src", "components");
|
|
const outDir = join(dir, "registry", "r");
|
|
const result = await build({ componentsDir, outDir });
|
|
expect(result.items).toEqual([]);
|
|
const idx = JSON.parse(await readFile(result.indexPath, "utf8"));
|
|
expect(idx.items).toEqual([]);
|
|
}
|
|
);
|
|
|
|
it(
|
|
"build emits one manifest per component when present",
|
|
{ timeout: 10000 },
|
|
async () => {
|
|
const dir = await mkdtemp(join(tmpdir(), "registry-some-"));
|
|
const componentsDir = join(dir, "src", "components");
|
|
const outDir = join(dir, "registry", "r");
|
|
await mkdir(join(componentsDir, "button"), { recursive: true });
|
|
await writeFile(
|
|
join(componentsDir, "button", "button.tsx"),
|
|
"export const Button = () => null;"
|
|
);
|
|
await mkdir(join(componentsDir, "card"), { recursive: true });
|
|
await writeFile(
|
|
join(componentsDir, "card", "index.ts"),
|
|
"export {};"
|
|
);
|
|
const result = await build({ componentsDir, outDir });
|
|
expect(result.items.sort()).toEqual(["button", "card"]);
|
|
const buttonItem = JSON.parse(
|
|
await readFile(join(outDir, "button.json"), "utf8")
|
|
);
|
|
expect(buttonItem.name).toBe("@suaveplan/button");
|
|
const idx = JSON.parse(await readFile(result.indexPath, "utf8"));
|
|
expect(idx.items).toHaveLength(2);
|
|
}
|
|
);
|
|
|
|
it(
|
|
"validateItem rejects malformed items",
|
|
{ timeout: 5000 },
|
|
() => {
|
|
expect(
|
|
validateItem({
|
|
$schema: "wrong",
|
|
name: "x",
|
|
type: "registry:ui",
|
|
dependencies: [],
|
|
registryDependencies: [],
|
|
files: [],
|
|
} as never)
|
|
).toBe(false);
|
|
}
|
|
);
|
|
|
|
it(
|
|
"validateIndex rejects malformed indexes",
|
|
{ timeout: 5000 },
|
|
() => {
|
|
expect(
|
|
validateIndex({
|
|
$schema: "wrong",
|
|
name: "x",
|
|
items: [],
|
|
} as never)
|
|
).toBe(false);
|
|
}
|
|
);
|
|
});
|