| 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; |
| 3 | |
| 4 | import { |
| 5 | buildTree, |
| 6 | canDo, |
| 7 | citationHref, |
| 8 | coverStyle, |
| 9 | cursorColour, |
| 10 | dayGroups, |
| 11 | dayKey, |
| 12 | flatten, |
| 13 | linkedArtifacts, |
| 14 | pathTo, |
| 15 | readingTime, |
| 16 | repoFilePath, |
| 17 | repoFolders, |
| 18 | snippetParts, |
| 19 | spacePath, |
| 20 | } from "./folios.ts"; |
| 21 | |
| 22 | const node = (id: string, parent_id: string | null, position: number) => ({ |
| 23 | id, |
| 24 | kind: "doc" as const, |
| 25 | parent_id, |
| 26 | position, |
| 27 | title: id.toUpperCase(), |
| 28 | icon: null, |
| 29 | slug: id, |
| 30 | restricted: false, |
| 31 | }); |
| 32 | |
| 33 | const nodes = [node("b", null, 2), node("a", null, 1), node("c", "a", 1), node("orphan", "gone", 3)]; |
| 34 | |
| 35 | test("the tree orders each level and lifts folios whose parent isn't there", () => { |
| 36 | const tree = buildTree(nodes); |
| 37 | assert.deepEqual( |
| 38 | tree.map((n) => n.id), |
| 39 | ["a", "b", "orphan"], |
| 40 | ); |
| 41 | assert.equal(tree[0]!.children[0]!.id, "c"); |
| 42 | assert.equal(tree[0]!.children[0]!.depth, 1); |
| 43 | assert.deepEqual( |
| 44 | flatten(tree).map((n) => n.id), |
| 45 | ["a", "c", "b", "orphan"], |
| 46 | ); |
| 47 | assert.deepEqual(pathTo(nodes, "c"), ["a"]); |
| 48 | }); |
| 49 | |
| 50 | test("the home list groups by the viewer's day: Today, Yesterday, then dates", () => { |
| 51 | const now = new Date("2026-10-09T15:00:00Z"); |
| 52 | const items = ["2026-10-09T14:00:00Z", "2026-10-09T01:00:00Z", "2026-10-08T20:00:00Z", "2026-10-07T12:00:00Z", "2025-12-31T12:00:00Z"]; |
| 53 | const utc = dayGroups(items, (i) => i, "UTC", now); |
| 54 | assert.deepEqual( |
| 55 | utc.map((g) => [g.label, g.items.length]), |
| 56 | [ |
| 57 | ["Today", 2], |
| 58 | ["Yesterday", 1], |
| 59 | ["Oct 7", 1], |
| 60 | ["Dec 31, 2025", 1], |
| 61 | ], |
| 62 | ); |
| 63 | // At 01:00 UTC it is still the 8th in Chicago: that one is yesterday's there. |
| 64 | const chicago = dayGroups(items, (i) => i, "America/Chicago", now); |
| 65 | assert.deepEqual( |
| 66 | chicago.map((g) => [g.label, g.items.length]), |
| 67 | [ |
| 68 | ["Today", 1], |
| 69 | ["Yesterday", 2], |
| 70 | ["Oct 7", 1], |
| 71 | ["Dec 31, 2025", 1], |
| 72 | ], |
| 73 | ); |
| 74 | assert.equal(dayKey("2026-10-09T01:00:00Z", "America/Chicago"), "2026-10-08"); |
| 75 | }); |
| 76 | |
| 77 | test("chat messages name the artifacts they link to, in this workspace only", () => { |
| 78 | const id = "fol_01jb2k7x9hfq0b3zj0f5s2m8ra"; |
| 79 | const other = "fol_01jb2k7x9hfq0b3zj0f5s2m8rb"; |
| 80 | assert.deepEqual( |
| 81 | linkedArtifacts(`See https://g1t.sh/acme/-/artifacts/q4-plan-${id} and /acme/-/artifacts/${other}, and again /Acme/-/artifacts/${id}`, "acme"), |
| 82 | [id, other], |
| 83 | ); |
| 84 | assert.deepEqual(linkedArtifacts(`/other/-/artifacts/x-${id}`, "acme"), []); |
| 85 | assert.deepEqual(linkedArtifacts(`/acme/-/artifacts/spaces/general`, "acme"), []); |
| 86 | }); |
| 87 | |
| 88 | test("snippets mark their matches", () => { |
| 89 | assert.deepEqual(snippetParts("a [[b]] c"), [ |
| 90 | { text: "a ", match: false }, |
| 91 | { text: "b", match: true }, |
| 92 | { text: " c", match: false }, |
| 93 | ]); |
| 94 | }); |
| 95 | |
| 96 | test("covers, colours, roles, reading time", () => { |
| 97 | assert.match(coverStyle("gradient:1")!, /^linear-gradient/); |
| 98 | assert.match(coverStyle("https://g1tusercontent.com/docs-files/x")!, /url\("https:/); |
| 99 | assert.equal(coverStyle("javascript:alert(1)"), null); |
| 100 | assert.equal(cursorColour("ana"), cursorColour("ana")); |
| 101 | assert.equal(canDo("edit", "comment"), true); |
| 102 | assert.equal(canDo("comment", "edit"), false); |
| 103 | assert.deepEqual(readingTime("one two three"), { words: 3, minutes: 1 }); |
| 104 | }); |
| 105 | |
| 106 | test("a citation links to its code, a glob to the folder it starts from", () => { |
| 107 | assert.equal(citationHref({ repo: "acme/web", path: "src/export.ts", ref: "abc1234" }), "/acme/web/blob/abc1234/src/export.ts"); |
| 108 | assert.equal(citationHref({ repo: "acme/web", path: "src/jobs", ref: null }), "/acme/web/tree/HEAD/src/jobs"); |
| 109 | assert.equal(citationHref({ repo: "acme/web", path: "src/**/*.sql", ref: "abc" }), "/acme/web/tree/abc/src"); |
| 110 | }); |
| 111 | |
| 112 | test("a project's docs become folders, and spaces and files have addresses under Artifacts", () => { |
| 113 | const root = repoFolders([ |
| 114 | { path: "README.md", title: "Acme" }, |
| 115 | { path: "docs/setup.md", title: "Setup" }, |
| 116 | { path: "docs/guides/deploy.md", title: "Deploy" }, |
| 117 | ]); |
| 118 | assert.deepEqual( |
| 119 | root.files.map((f) => f.path), |
| 120 | ["README.md", "docs/setup.md"], |
| 121 | ); |
| 122 | assert.equal(root.folders[0]!.name, "guides"); |
| 123 | assert.deepEqual( |
| 124 | root.folders[0]!.files.map((f) => f.title), |
| 125 | ["Deploy"], |
| 126 | ); |
| 127 | assert.equal(repoFilePath("acme", "acme/web", "docs/a b.md"), "/acme/-/artifacts/repo/acme/web/docs/a%20b.md"); |
| 128 | assert.equal(spacePath("acme", "general"), "/acme/-/artifacts/spaces/general"); |
| 129 | }); |