eleven / ocho Public

Clone
git clone https://amadan.net/eleven/ocho

Plain git — no account needed to clone.

Download

Download this file

1// 🤖 The composer serialization contract (issue #890): the vectors in
2// test/event-vectors/composer-serialize.json pin the wire bytes the WEB
3// serializer (composer-md.js, the authority) emits for each composer doc
4// shape, so the native twin (ComposerSerialize.swift, run by
5// ComposerSerializeTests over the byte-identical fixture) can never drift.
6// node test/composer-vectors.test.mjs
7import assert from "node:assert/strict";
8import { readFileSync } from "node:fs";
9import { dirname, join } from "node:path";
10import { fileURLToPath } from "node:url";
11import { composerSchema as schema, serializeDoc } from "../web/static/composer-md.js";
12import { parseMessage } from "../web/static/markdown.js";
13
14const __dirname = dirname(fileURLToPath(import.meta.url));
15
16let failures = 0;
17async function test(name, fn) {
18 try {
19 await fn();
20 console.log("PASS " + name);
21 } catch (e) {
22 console.log("FAIL " + name + " — " + (e && e.message));
23 failures++;
24 }
25}
26
27// The tree vocabulary (test/event-vectors/markdown.json's) → a ProseMirror
28// doc over the composer schema. Inline nesting becomes mark arrays; a br
29// inside a styled wrapper carries the wrapper's marks (the marked-break case).
30function inlineNodes(children, marks = []) {
31 const out = [];
32 for (const n of children) {
33 if (n.t === "text") out.push(schema.text(n.text, marks));
34 else if (n.t === "br") out.push(schema.nodes.hard_break.create(null, null, marks));
35 else if (n.t === "code") out.push(schema.text(n.text, [...marks, schema.marks.code.create()]));
36 else if (n.t === "strong" || n.t === "em") out.push(...inlineNodes(n.children, [...marks, schema.marks[n.t].create()]));
37 else if (n.t === "strike") out.push(...inlineNodes(n.children, [...marks, schema.marks.strike.create()]));
38 else if (n.t === "link") out.push(...inlineNodes(n.children, [...marks, schema.marks.link.create({ href: n.href })]));
39 else throw new Error("unknown inline " + n.t);
40 }
41 return out;
42}
43function blockNode(b) {
44 if (b.t === "p") return schema.nodes.paragraph.create(null, inlineNodes(b.children));
45 if (b.t === "quote") return schema.nodes.blockquote.create(null, b.children.map(blockNode));
46 if (b.t === "ul") return schema.nodes.bullet_list.create(null, b.items.map((item) => schema.nodes.list_item.create(null, item.map(blockNode))));
47 if (b.t === "ol") return schema.nodes.ordered_list.create({ order: b.start }, b.items.map((item) => schema.nodes.list_item.create(null, item.map(blockNode))));
48 if (b.t === "codeblock") return schema.nodes.code_block.create({ params: b.lang }, b.text ? [schema.text(b.text)] : []);
49 throw new Error("unknown block " + b.t);
50}
51export function docFromTree(tree) {
52 return schema.nodes.doc.create(null, tree.map(blockNode));
53}
54
55const canonical = readFileSync(join(__dirname, "event-vectors", "composer-serialize.json"), "utf8");
56const { vectors } = JSON.parse(canonical);
57
58await test("vector file has substantial coverage", () => {
59 assert.ok(vectors.length >= 40, `only ${vectors.length} vectors`);
60});
61
62for (const v of vectors) {
63 await test(`serialize: ${v.name}`, () => {
64 assert.equal(serializeDoc(docFromTree(v.tree)), v.md, v.note || "");
65 });
66 await test(`reparse: ${v.name}`, () => {
67 assert.deepEqual(parseMessage(v.md), v.reparse ?? v.tree);
68 });
69}
70
71await test("ios fixture copy is byte-identical to canonical", () => {
72 const bundled = readFileSync(
73 join(__dirname, "..", "ios", "LChatCore", "Tests", "LChatCoreTests", "Fixtures", "composer-serialize-vector.json"),
74 "utf8"
75 );
76 assert.strictEqual(
77 bundled,
78 canonical,
79 "run cp test/event-vectors/composer-serialize.json ios/LChatCore/Tests/LChatCoreTests/Fixtures/composer-serialize-vector.json"
80 );
81});
82
83if (failures) {
84 console.error(`\ncomposer-vectors: ${failures} test(s) failed`);
85 process.exit(1);
86}
87console.log("\ncomposer-vectors: all tests passed");
88