| 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; |
| 3 | |
| 4 | import * as Y from "yjs"; |
| 5 | |
| 6 | import { KINDS, kindModel } from "../index.ts"; |
| 7 | import { doc, docTarget, docTargets, linkedFolioIds, previewLines } from "./index.ts"; |
| 8 | |
| 9 | const origin = { key: "user:ana", kind: "edit" as const, note: null }; |
| 10 | |
| 11 | test("the registry has the doc kind and nothing not built yet", () => { |
| 12 | assert.equal(kindModel("doc"), doc); |
| 13 | assert.equal(kindModel("slides"), null); |
| 14 | assert.equal(kindModel("nope"), null); |
| 15 | assert.deepEqual(Object.keys(KINDS), ["doc"]); |
| 16 | }); |
| 17 | |
| 18 | test("a doc seeds from Markdown and renders it back, with its card", () => { |
| 19 | const d = new Y.Doc(); |
| 20 | assert.equal(doc.isEmpty(d), true); |
| 21 | doc.seed(d, { text: "# Plan\n\nShip it on Tuesday.\n\n- one\n- two\n" }); |
| 22 | assert.equal(doc.isEmpty(d), false); |
| 23 | const r = doc.render(d); |
| 24 | assert.match(r.text, /^# Plan/); |
| 25 | assert.match(r.text, /Ship it on Tuesday\./); |
| 26 | assert.deepEqual(r.preview, { kind: "doc", lines: ["Plan", "Ship it on Tuesday.", "one", "two"] }); |
| 27 | const read = doc.read(d); |
| 28 | assert.equal(read.content, r.text); |
| 29 | assert.ok((read.blocks ?? []).length >= 3); |
| 30 | assert.ok(doc.chunks(r.text, "Plan").length >= 1); |
| 31 | assert.equal(doc.validate(d), null); |
| 32 | }); |
| 33 | |
| 34 | test("an agent's edit applies to its target, and a missing one doesn't", () => { |
| 35 | const d = new Y.Doc(); |
| 36 | doc.seed(d, { text: "# Notes\n\nFirst.\n\n## Risks\n\nNone yet.\n" }); |
| 37 | const appended = doc.applyAgentEdit(d, { kind: "doc", target: { kind: "append" }, markdown: "Added by an agent." }, origin); |
| 38 | assert.deepEqual(appended, { applied: true, summary: "Added to the end" }); |
| 39 | assert.match(doc.render(d).text, /Added by an agent\./); |
| 40 | const section = doc.applyAgentEdit(d, { kind: "doc", target: { kind: "section", heading: "Risks" }, markdown: "## Risks\n\nThe date." }, origin); |
| 41 | assert.equal(section.applied, true); |
| 42 | assert.match(doc.render(d).text, /The date\./); |
| 43 | assert.doesNotMatch(doc.render(d).text, /None yet\./); |
| 44 | const gone = doc.applyAgentEdit(d, { kind: "doc", target: { kind: "section", heading: "Nowhere" }, markdown: "x" }, origin); |
| 45 | assert.equal(gone.applied, false); |
| 46 | assert.ok(docTarget(d, { kind: "section", heading: "Risks" })); |
| 47 | assert.equal(docTarget(d, { kind: "section", heading: "Nowhere" }), null); |
| 48 | assert.deepEqual(docTargets(d, [{ kind: "section", heading: "Nowhere" }]), [null]); |
| 49 | // Another kind's edit is never applied to a doc. |
| 50 | assert.equal(doc.applyAgentEdit(d, { kind: "slides", ops: [] } as never, origin).applied, false); |
| 51 | }); |
| 52 | |
| 53 | test("a doc restores from an old state and from old text", () => { |
| 54 | const d = new Y.Doc(); |
| 55 | doc.seed(d, { text: "Version one.\n" }); |
| 56 | const old = new Y.Doc(); |
| 57 | Y.applyUpdate(old, Y.encodeStateAsUpdate(d)); |
| 58 | doc.applyAgentEdit(d, { kind: "doc", target: { kind: "document" }, markdown: "Version two." }, origin); |
| 59 | assert.match(doc.render(d).text, /Version two/); |
| 60 | doc.restore(d, old, { ...origin, kind: "restore" }); |
| 61 | assert.match(doc.render(d).text, /Version one/); |
| 62 | doc.restoreText(d, "Version three.\n", { ...origin, kind: "restore" }); |
| 63 | assert.match(doc.render(d).text, /Version three/); |
| 64 | }); |
| 65 | |
| 66 | test("links to other folios and preview lines", () => { |
| 67 | const a = "fol_01jb2k7x9hfq0b3zj0f5s2m8ra"; |
| 68 | assert.deepEqual(linkedFolioIds(`see /acme/-/artifacts/plan-${a} and ${a}`), [a]); |
| 69 | assert.deepEqual(previewLines("# A\n\n**B** text\n\n```\ncode\n```\n", 2), ["A", "B text"]); |
| 70 | }); |