Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Merge main into Artifacts Phase 2 | 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; | |
| 3 | ||
| 4 | import { type DocNode, docToMarkdown, escapeText, markdownToDoc } from "./chat-compose.ts"; | |
| 5 | ||
| 6 | const text = (value: string, ...marks: (string | { type: string; attrs?: Record<string, unknown> })[]): DocNode => ({ | |
| 7 | type: "text", | |
| 8 | text: value, | |
| 9 | ...(marks.length ? { marks: marks.map((mark) => (typeof mark === "string" ? { type: mark } : mark)) } : {}), | |
| 10 | }); | |
| 11 | const p = (...content: DocNode[]): DocNode => (content.length ? { type: "paragraph", content } : { type: "paragraph" }); | |
| 12 | const doc = (...content: DocNode[]): DocNode => ({ type: "doc", content }); | |
| 13 | ||
| 14 | test("formatting is written as Markdown", () => { | |
| 15 | assert.equal( | |
| 16 | docToMarkdown(doc(p(text("bold", "bold"), text(" "), text("it", "italic"), text(" "), text("gone", "strike"), text(" "), text("a*b", "code")))), | |
| 17 | "**bold** _it_ ~~gone~~ `a*b`", | |
| 18 | ); | |
| 19 | // Marks that overlap open and close once. | |
| 20 | assert.equal(docToMarkdown(doc(p(text("a", "bold"), text("b", "bold", "italic"), text("c", "bold")))), "**a_b_c**"); | |
| 21 | // Spaces at a mark's edges sit outside it. | |
| 22 | assert.equal(docToMarkdown(doc(p(text("say "), text(" hi ", "bold"), text("there")))), "say **hi** there"); | |
| 23 | assert.equal(docToMarkdown(doc(p(text("tick ` in", "code")))), "`` tick ` in ``"); | |
| 24 | }); | |
| 25 | ||
| 26 | test("links: with their text, or bare when the text is the address", () => { | |
| 27 | const link = (href: string) => ({ type: "link", attrs: { href } }); | |
| 28 | assert.equal(docToMarkdown(doc(p(text("the docs", link("https://g1t.sh/docs"))))), "[the docs](https://g1t.sh/docs)"); | |
| 29 | assert.equal(docToMarkdown(doc(p(text("https://g1t.sh", link("https://g1t.sh"))))), "https://g1t.sh"); | |
| 30 | assert.equal(docToMarkdown(doc(p(text("x", link("https://a.example/a b"))))), "[x](<https://a.example/a%20b>)"); | |
| 31 | }); | |
| 32 | ||
| 33 | test("each paragraph is a line; an empty one is a blank line", () => { | |
| 34 | assert.equal(docToMarkdown(doc(p(text("one")), p(text("two")), p(), p(text("three")))), "one\ntwo\n\nthree"); | |
| 35 | assert.equal(docToMarkdown(doc(p(), p(text("x")), p())), "x"); | |
| 36 | }); | |
| 37 | ||
| 38 | test("text that only looks like Markdown is escaped, and mentions stay mentions", () => { | |
| 39 | assert.equal(escapeText("2*3 and snake_case and _edge_ and [x] and `t` and ~5"), "2\\*3 and snake_case and \\_edge\\_ and \\[x\\] and \\`t\\` and \\~5"); | |
| 40 | assert.equal(docToMarkdown(doc(p(text("- not a list")), p(text("1. not either")), p(text("# nor this")), p(text("> or this")))), "\\- not a list\n1\\. not either\n\\# nor this\n\\> or this"); | |
| 41 | assert.equal(docToMarkdown(doc(p(text("ask @ana in #web about #12")))), "ask @ana in #web about #12"); | |
| 42 | }); | |
| 43 | ||
| 44 | test("lists, quotes and code blocks", () => { | |
| 45 | const item = (...content: DocNode[]): DocNode => ({ type: "listItem", content }); | |
| 46 | assert.equal( | |
| 47 | docToMarkdown( | |
| 48 | doc( | |
| 49 | p(text("Plan:")), | |
| 50 | { type: "bulletList", content: [item(p(text("one"))), item(p(text("two")), { type: "orderedList", attrs: { start: 1 }, content: [item(p(text("deep")))] })] }, | |
| 51 | p(text("after")), | |
| 52 | ), | |
| 53 | ), | |
| 54 | "Plan:\n\n- one\n- two\n 1. deep\n\nafter", | |
| 55 | ); | |
| 56 | assert.equal(docToMarkdown(doc({ type: "orderedList", attrs: { start: 3 }, content: [item(p(text("c"))), item(p(text("d")))] })), "3. c\n4. d"); | |
| 57 | assert.equal(docToMarkdown(doc({ type: "blockquote", content: [p(text("quoted")), p(), p(text("more"))] })), "> quoted\n>\n> more"); | |
| 58 | assert.equal(docToMarkdown(doc({ type: "codeBlock", attrs: { language: "ts" }, content: [{ type: "text", text: "const a = 1;\n\n\nconst b = `x`;" }] })), "```ts\nconst a = 1;\n\n\nconst b = `x`;\n```"); | |
| 59 | assert.equal(docToMarkdown(doc({ type: "codeBlock", attrs: { language: null }, content: [{ type: "text", text: "```\nfence\n```" }] })), "````\n```\nfence\n```\n````"); | |
| 60 | }); | |
| 61 | ||
| 62 | test("Markdown comes back into the composer as it was written", () => { | |
| 63 | const samples = [ | |
| 64 | "**bold** _it_ ~~gone~~ `code`", | |
| 65 | "one\ntwo\n\nthree", | |
| 66 | "Plan:\n\n- one\n- two\n 1. deep\n\nafter", | |
| 67 | "3. c\n4. d", | |
| 68 | "> quoted\n>\n> more", | |
| 69 | "```ts\nconst a = 1;\n\nconst b = 2;\n```", | |
| 70 | "[the docs](https://g1t.sh/docs) and https://g1t.sh", | |
| 71 | "ask @ana in #web about g1t#12", | |
| 72 | "\\- not a list and 2\\*3 and snake_case", | |
| 73 | "**a _b_ c**", | |
| 74 | ]; | |
| 75 | for (const sample of samples) assert.equal(docToMarkdown(markdownToDoc(sample)), sample, sample); | |
| 76 | }); | |
| 77 | ||
| 78 | test("Markdown the composer cannot write still comes in", () => { | |
| 79 | // A heading is a bold line; a rule is left out; an image is a link. | |
| 80 | assert.equal(docToMarkdown(markdownToDoc("## Notes\n---\ntext")), "**Notes**\ntext"); | |
| 81 | assert.equal(docToMarkdown(markdownToDoc("*star em* and __strong__ and ~one~")), "_star em_ and **strong** and ~~one~~"); | |
| 82 | assert.deepEqual(markdownToDoc(""), { type: "doc", content: [{ type: "paragraph" }] }); | |
| 83 | }); |
This file's history is long; its oldest lines are credited to the oldest commit read.