mirror of
https://github.com/Patiun/com.gregkilmer.www.git
synced 2026-11-08 04:08:24 +00:00
a2f723ca2d
Phase 1 of the functional design plan. - Move the old site into legacy/, unchanged, for reference. It still builds from there until cutover. - Add packages/schema: the one definition of all 20 note types, with field titles and descriptions, note and vault checks, and JSON Schema export so later editing tools and the MCP server share it. - Add vault-kit: Obsidian templates generated from the schema, and the Site guide for 24.01_PersonalWebsite. - Add tools/migrate: turns the legacy JSON, collections, store data and page text into 545 Site folder notes and 84 images, and checks the result with the schema. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012aSbo2D1qP8cMFQCykf7kx
63 lines
2.7 KiB
TypeScript
63 lines
2.7 KiB
TypeScript
import { basename, join, resolve } from "node:path";
|
|
import { beforeAll, describe, expect, it } from "vitest";
|
|
import { checkNote, checkVault } from "@gk/schema";
|
|
import { build, loadProducts, type BuildResult } from "../src/build.ts";
|
|
|
|
const legacy = resolve(import.meta.dirname, "../../../legacy");
|
|
let result: BuildResult;
|
|
|
|
beforeAll(async () => {
|
|
await loadProducts(legacy);
|
|
result = build(legacy);
|
|
});
|
|
|
|
const find = (type: string, title: string) => result.notes.find((n) => n.data.type === type && n.data.title === title);
|
|
|
|
describe("migration", () => {
|
|
it("produces only valid notes and a consistent vault", () => {
|
|
const vault = result.notes.map((n) => {
|
|
const r = checkNote(n.text);
|
|
expect(r.ok, n.path).toBe(true);
|
|
return { path: n.path, type: String(n.data.type), data: n.data, body: n.body };
|
|
});
|
|
expect(checkVault(vault, result.attachments.map((a) => basename(a.to)))).toEqual([]);
|
|
});
|
|
|
|
it("carries every legacy list item over", () => {
|
|
const count = (t: string) => result.notes.filter((n) => n.data.type === t).length;
|
|
expect(count("board-game")).toBe(50);
|
|
// 24 reading + 108 anime + 103 TV + 152 movies + 11 hall of fame + 5 now playing
|
|
expect(count("library-item")).toBe(403);
|
|
expect(count("experience")).toBe(3);
|
|
});
|
|
|
|
it("merges a favorite listed twice into one note", () => {
|
|
const demonSlayer = result.notes.filter((n) => n.data.title === "Demon Slayer");
|
|
expect(demonSlayer).toHaveLength(1);
|
|
expect(demonSlayer[0]!.data).toMatchObject({ favorite: true, group: "Major Modern Hits", state: "finished" });
|
|
});
|
|
|
|
it("splits author from series", () => {
|
|
expect(find("library-item", "Cosmere")?.data).toMatchObject({ creator: "Brandon Sanderson", medium: "book" });
|
|
});
|
|
|
|
it("keeps the store's real prices and slots", () => {
|
|
const proxies = find("product-line", "Proxy MTG Cards")!.data as any;
|
|
expect(proxies.slots).toEqual({ open: 1, total: 3 });
|
|
expect(proxies.priceTiers).toContainEqual({ band: "100 card deck", price: "$40.00", note: "per set of cards" });
|
|
});
|
|
|
|
it("logs status for everything in progress", () => {
|
|
const kinds = result.notes.filter((n) => n.data.type === "status").map((n) => `${n.data.kind}: ${n.data.title}`);
|
|
expect(kinds).toContain("Playing: Slay the Spire 2");
|
|
expect(kinds).toContain("Watching: House of the Dragon");
|
|
expect(kinds).toContain("Listening: The Lord of the Rings");
|
|
});
|
|
|
|
it("never publishes anything still waiting on Greg", () => {
|
|
for (const title of ["D&D campaign", "Daggerheart campaign", "Carrier Connect", "Book-bound journals"]) {
|
|
expect(result.notes.find((n) => n.data.title === title)?.data.publish, title).toBe(false);
|
|
}
|
|
});
|
|
});
|