import type { PageMeta } from "@silverbulletmd/silverbullet/type/index"; import { expect, test } from "vitest"; import { buildPageTree, collectPlainleafTags, plainleafPageLabel, plainleafTaskReference, visiblePlainleafPages, } from "./plainleaf_workspace.tsx"; function page(name: string, extra: Partial = {}): PageMeta { return { ref: name, tag: "page", name, created: "2026-08-12T00:00:00Z", lastModified: "2026-08-12T00:00:00Z", perm: "rw", ...extra, }; } test("builds nested folders from slash-separated page names", () => { const tree = buildPageTree([ page("Inbox"), page("Projects/Plainleaf/Plan"), page("Projects/Plainleaf/Research"), page("Projects/Website"), ]); expect(tree.map((node) => [node.kind, node.name])).toEqual([ ["folder", "Projects"], ["page", "Inbox"], ]); expect(tree[0]).toMatchObject({ kind: "folder", name: "Projects", children: [ { kind: "folder", name: "Plainleaf", children: [ { kind: "page", name: "Projects/Plainleaf/Plan", label: "Plan" }, { kind: "page", name: "Projects/Plainleaf/Research", label: "Research", }, ], }, { kind: "page", name: "Projects/Website", label: "Website" }, ], }); }); test("keeps a page and a same-named folder as separate nodes", () => { const tree = buildPageTree([page("Projects"), page("Projects/Plan")]); expect(tree).toMatchObject([ { kind: "folder", name: "Projects", children: [{ kind: "page", name: "Projects/Plan" }], }, { kind: "page", name: "Projects" }, ]); }); test("omits aspiring and decorated hidden pages", () => { const tree = buildPageTree([ page("Visible"), page("Aspiring", { _isAspiring: true }), page("Hidden", { pageDecoration: { hide: true } }), ]); expect(tree).toMatchObject([{ kind: "page", name: "Visible" }]); }); test("hides SilverBullet system roots and meta-tagged pages", () => { const pages = [ page("Notes/Visible"), page("Library/Std"), page("Repositories/Std"), page("CONFIG"), page("Internal", { tags: ["meta/library"] }), ]; expect(visiblePlainleafPages(pages).map((item) => item.name)).toEqual([ "Notes/Visible", ]); expect(visiblePlainleafPages(pages, true).map((item) => item.name)).toEqual([ "Notes/Visible", "Library/Std", "Repositories/Std", "CONFIG", "Internal", ]); }); test("uses a friendly home label without changing the stored page name", () => { expect(plainleafPageLabel("index", "index")).toBe("首页"); expect(plainleafPageLabel("项目/计划", "index")).toBe("计划"); expect(plainleafPageLabel("Library/Std", "index")).toBe("内置"); expect(plainleafPageLabel("CONFIG", "index")).toBe("系统配置"); const tree = buildPageTree([page("index")], "index"); expect(tree).toMatchObject([{ kind: "page", name: "index", label: "首页" }]); }); test("counts user tags and excludes internal tags", () => { const tags = collectPlainleafTags([ page("A", { tags: ["产品"] }), page("B", { tags: ["产品", "灵感"] }), page("C", { tags: ["template"] }), page("D", { tags: ["产品", "meta/library"] }), ]); expect(tags).toEqual([ { name: "产品", count: 2 }, { name: "灵感", count: 1 }, ]); expect( collectPlainleafTags( [page("Library/Test", { tags: ["meta/library"] })], true, ), ).toEqual([{ name: "meta/library", count: 1 }]); }); test("qualifies anchor-backed task refs with their source page", () => { expect( plainleafTaskReference({ ref: "follow-up", page: "项目/计划", name: "跟进", state: " ", done: false, }), ).toBe("项目/计划$follow-up"); expect( plainleafTaskReference({ ref: "项目/计划@42", page: "项目/计划", name: "跟进", state: " ", done: false, }), ).toBe("项目/计划@42"); });