@localix-ai/flowdown 0.0.0-stage → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +101 -2
  3. package/dist/browser/file-actions.js +80 -0
  4. package/dist/browser/file-actions.js.map +1 -0
  5. package/dist/core/block-facts.js +72 -0
  6. package/dist/core/block-facts.js.map +1 -0
  7. package/dist/core/blocks.d.ts +25 -0
  8. package/dist/core/blocks.js +463 -0
  9. package/dist/core/blocks.js.map +1 -0
  10. package/dist/core/bounded-cache.js +42 -0
  11. package/dist/core/bounded-cache.js.map +1 -0
  12. package/dist/core/dollars.d.ts +12 -0
  13. package/dist/core/dollars.js +88 -0
  14. package/dist/core/dollars.js.map +1 -0
  15. package/dist/core/fence-scan.js +53 -0
  16. package/dist/core/fence-scan.js.map +1 -0
  17. package/dist/core/file-tree-parse.d.ts +26 -0
  18. package/dist/core/file-tree-parse.js +51 -0
  19. package/dist/core/file-tree-parse.js.map +1 -0
  20. package/dist/core/forms-html.js +63 -0
  21. package/dist/core/forms-html.js.map +1 -0
  22. package/dist/core/forms.d.ts +28 -0
  23. package/dist/core/forms.js +23 -0
  24. package/dist/core/forms.js.map +1 -0
  25. package/dist/core/headings.d.ts +11 -0
  26. package/dist/core/headings.js +74 -0
  27. package/dist/core/headings.js.map +1 -0
  28. package/dist/core/heal.d.ts +11 -0
  29. package/dist/core/heal.js +220 -0
  30. package/dist/core/heal.js.map +1 -0
  31. package/dist/core/load-once.js +23 -0
  32. package/dist/core/load-once.js.map +1 -0
  33. package/dist/core/math-delimiters.js +33 -0
  34. package/dist/core/math-delimiters.js.map +1 -0
  35. package/dist/core/math-syntax.js +56 -0
  36. package/dist/core/math-syntax.js.map +1 -0
  37. package/dist/core/prose.d.ts +10 -0
  38. package/dist/core/prose.js +77 -0
  39. package/dist/core/prose.js.map +1 -0
  40. package/dist/core/remark-answer-blocks.d.ts +5 -0
  41. package/dist/core/remark-answer-blocks.js +172 -0
  42. package/dist/core/remark-answer-blocks.js.map +1 -0
  43. package/dist/core/remark-answer-containers.js +299 -0
  44. package/dist/core/remark-answer-containers.js.map +1 -0
  45. package/dist/core/sanitize-schema.d.ts +18 -0
  46. package/dist/core/sanitize-schema.js +62 -0
  47. package/dist/core/sanitize-schema.js.map +1 -0
  48. package/dist/core/syntax.d.ts +8 -0
  49. package/dist/core/syntax.js +32 -0
  50. package/dist/core/syntax.js.map +1 -0
  51. package/dist/dialect.d.ts +92 -0
  52. package/dist/dialect.js +176 -0
  53. package/dist/dialect.js.map +1 -0
  54. package/dist/document/fence.d.ts +25 -0
  55. package/dist/document/fence.js +101 -0
  56. package/dist/document/fence.js.map +1 -0
  57. package/dist/document/index.d.ts +46 -0
  58. package/dist/document/index.js +66 -0
  59. package/dist/document/index.js.map +1 -0
  60. package/dist/document/table.d.ts +11 -0
  61. package/dist/document/table.js +35 -0
  62. package/dist/document/table.js.map +1 -0
  63. package/dist/dom/index.d.ts +21 -0
  64. package/dist/dom/index.js +123 -0
  65. package/dist/dom/index.js.map +1 -0
  66. package/dist/dom/patch.js +104 -0
  67. package/dist/dom/patch.js.map +1 -0
  68. package/dist/element/index.d.ts +29 -0
  69. package/dist/element/index.js +64 -0
  70. package/dist/element/index.js.map +1 -0
  71. package/dist/engine/blocks.js +774 -0
  72. package/dist/engine/blocks.js.map +1 -0
  73. package/dist/engine/entities.js +83 -0
  74. package/dist/engine/entities.js.map +1 -0
  75. package/dist/engine/entity-core.js +9 -0
  76. package/dist/engine/entity-core.js.map +1 -0
  77. package/dist/engine/entity-table.js +9 -0
  78. package/dist/engine/entity-table.js.map +1 -0
  79. package/dist/engine/html.d.ts +7 -0
  80. package/dist/engine/html.js +207 -0
  81. package/dist/engine/html.js.map +1 -0
  82. package/dist/engine/index.d.ts +7 -0
  83. package/dist/engine/index.js +74 -0
  84. package/dist/engine/index.js.map +1 -0
  85. package/dist/engine/inlines.js +852 -0
  86. package/dist/engine/inlines.js.map +1 -0
  87. package/dist/engine/types.d.ts +109 -0
  88. package/dist/engine/url.d.ts +11 -0
  89. package/dist/engine/url.js +16 -0
  90. package/dist/engine/url.js.map +1 -0
  91. package/dist/engine/visit.d.ts +10 -0
  92. package/dist/engine/visit.js +29 -0
  93. package/dist/engine/visit.js.map +1 -0
  94. package/dist/highlight/highlight.d.ts +4 -0
  95. package/dist/highlight/highlight.js +144 -0
  96. package/dist/highlight/highlight.js.map +1 -0
  97. package/dist/highlight/index.d.ts +4 -0
  98. package/dist/highlight/index.js +18 -0
  99. package/dist/highlight/index.js.map +1 -0
  100. package/dist/html/index.d.ts +4 -0
  101. package/dist/html/index.js +544 -0
  102. package/dist/html/index.js.map +1 -0
  103. package/dist/index.d.ts +27 -0
  104. package/dist/index.js +13 -0
  105. package/dist/math/index.d.ts +17 -0
  106. package/dist/math/index.js +20 -0
  107. package/dist/math/index.js.map +1 -0
  108. package/dist/math/typeset.d.ts +12 -0
  109. package/dist/math/typeset.js +74 -0
  110. package/dist/math/typeset.js.map +1 -0
  111. package/dist/mermaid/diagram.d.ts +8 -0
  112. package/dist/mermaid/diagram.js +114 -0
  113. package/dist/mermaid/diagram.js.map +1 -0
  114. package/dist/mermaid/drawing.js +139 -0
  115. package/dist/mermaid/drawing.js.map +1 -0
  116. package/dist/mermaid/icons.js +16 -0
  117. package/dist/mermaid/icons.js.map +1 -0
  118. package/dist/mermaid/index.d.ts +13 -0
  119. package/dist/mermaid/index.js +3 -0
  120. package/dist/mermaid/loader.d.ts +5 -0
  121. package/dist/mermaid/loader.js +18 -0
  122. package/dist/mermaid/loader.js.map +1 -0
  123. package/dist/mermaid/look.d.ts +16 -0
  124. package/dist/mermaid/look.js +167 -0
  125. package/dist/mermaid/look.js.map +1 -0
  126. package/dist/mermaid/normalize-svg.js +44 -0
  127. package/dist/mermaid/normalize-svg.js.map +1 -0
  128. package/dist/mermaid/renderer.d.ts +22 -0
  129. package/dist/mermaid/renderer.js +132 -0
  130. package/dist/mermaid/renderer.js.map +1 -0
  131. package/dist/mermaid/viewer.js +309 -0
  132. package/dist/mermaid/viewer.js.map +1 -0
  133. package/dist/prompt/index.d.ts +19 -0
  134. package/dist/prompt/index.js +54 -0
  135. package/dist/prompt/index.js.map +1 -0
  136. package/dist/react/callout.d.ts +9 -0
  137. package/dist/react/callout.js +12 -0
  138. package/dist/react/callout.js.map +1 -0
  139. package/dist/react/code-block.d.ts +18 -0
  140. package/dist/react/code-block.js +81 -0
  141. package/dist/react/code-block.js.map +1 -0
  142. package/dist/react/context.d.ts +18 -0
  143. package/dist/react/context.js +17 -0
  144. package/dist/react/context.js.map +1 -0
  145. package/dist/react/draw.d.ts +2 -0
  146. package/dist/react/draw.js +16 -0
  147. package/dist/react/draw.js.map +1 -0
  148. package/dist/react/file-tree.d.ts +16 -0
  149. package/dist/react/file-tree.js +69 -0
  150. package/dist/react/file-tree.js.map +1 -0
  151. package/dist/react/growing-code.js +36 -0
  152. package/dist/react/growing-code.js.map +1 -0
  153. package/dist/react/helpers.d.ts +6 -0
  154. package/dist/react/helpers.js +17 -0
  155. package/dist/react/helpers.js.map +1 -0
  156. package/dist/react/icons.js +23 -0
  157. package/dist/react/icons.js.map +1 -0
  158. package/dist/react/labels.js +9 -0
  159. package/dist/react/labels.js.map +1 -0
  160. package/dist/react/markdown.d.ts +78 -0
  161. package/dist/react/markdown.js +204 -0
  162. package/dist/react/markdown.js.map +1 -0
  163. package/dist/react/render.d.ts +8 -0
  164. package/dist/react/render.js +41 -0
  165. package/dist/react/render.js.map +1 -0
  166. package/dist/react/table-rows.js +66 -0
  167. package/dist/react/table-rows.js.map +1 -0
  168. package/dist/react/table.js +36 -0
  169. package/dist/react/table.js.map +1 -0
  170. package/dist/react/tabs.d.ts +25 -0
  171. package/dist/react/tabs.js +58 -0
  172. package/dist/react/tabs.js.map +1 -0
  173. package/dist/react/use-smooth-text.d.ts +6 -0
  174. package/dist/react/use-smooth-text.js +156 -0
  175. package/dist/react/use-smooth-text.js.map +1 -0
  176. package/dist/react/use-stage.d.ts +9 -0
  177. package/dist/react/use-stage.js +57 -0
  178. package/dist/react/use-stage.js.map +1 -0
  179. package/dist/remark.d.ts +20 -0
  180. package/dist/remark.js +10 -0
  181. package/dist/render/factory.d.ts +15 -0
  182. package/dist/render/labels.d.ts +41 -0
  183. package/dist/render/labels.js +43 -0
  184. package/dist/render/labels.js.map +1 -0
  185. package/dist/render/tree.js +312 -0
  186. package/dist/render/tree.js.map +1 -0
  187. package/dist/render/view.d.ts +55 -0
  188. package/dist/render/view.js +302 -0
  189. package/dist/render/view.js.map +1 -0
  190. package/dist/render/views.d.ts +16 -0
  191. package/dist/render/views.js +261 -0
  192. package/dist/render/views.js.map +1 -0
  193. package/dist/render/vnode.d.ts +21 -0
  194. package/dist/render/vnode.js +194 -0
  195. package/dist/render/vnode.js.map +1 -0
  196. package/dist/static/index.d.ts +28 -0
  197. package/dist/static/index.js +27 -0
  198. package/dist/static/index.js.map +1 -0
  199. package/dist/stream.d.ts +12 -0
  200. package/dist/stream.js +3 -0
  201. package/dist/styles.css +1351 -0
  202. package/dist/tui/code.d.ts +5 -0
  203. package/dist/tui/code.js +240 -0
  204. package/dist/tui/code.js.map +1 -0
  205. package/dist/tui/index.d.ts +54 -0
  206. package/dist/tui/index.js +99 -0
  207. package/dist/tui/index.js.map +1 -0
  208. package/dist/tui/math.js +242 -0
  209. package/dist/tui/math.js.map +1 -0
  210. package/dist/tui/printable.d.ts +12 -0
  211. package/dist/tui/printable.js +31 -0
  212. package/dist/tui/printable.js.map +1 -0
  213. package/dist/tui/render.d.ts +12 -0
  214. package/dist/tui/render.js +524 -0
  215. package/dist/tui/render.js.map +1 -0
  216. package/dist/tui/style.d.ts +35 -0
  217. package/dist/tui/style.js +77 -0
  218. package/dist/tui/style.js.map +1 -0
  219. package/dist/tui/table.js +73 -0
  220. package/dist/tui/table.js.map +1 -0
  221. package/dist/tui/width.d.ts +2 -0
  222. package/dist/tui/width.js +133 -0
  223. package/dist/tui/width.js.map +1 -0
  224. package/dist/tui/wrap.d.ts +8 -0
  225. package/dist/tui/wrap.js +190 -0
  226. package/dist/tui/wrap.js.map +1 -0
  227. package/package.json +127 -4
@@ -0,0 +1,312 @@
1
+ import "../dialect.js";
2
+ import { normalizeUri } from "../engine/entities.js";
3
+ // src/render/tree.ts
4
+ /**
5
+ * A Markdown tree as elements, for any target that has elements: the one place that says which
6
+ * tag a node becomes, what a task list or a footnote is made of, and which URL is let through.
7
+ */
8
+ /** The prefix on every id content makes, so it cannot stand in for one of the page's own. */
9
+ const ID_PREFIX = "user-content-";
10
+ const URL_PROPS = [
11
+ "href",
12
+ "src",
13
+ "cite",
14
+ "longDesc"
15
+ ];
16
+ /** `dataCalloutTitle` as the attribute React writes: `data-callout-title`. */
17
+ const attribute = (name) => name.length > 4 && name.startsWith("data") && name.charCodeAt(4) >= 65 && name.charCodeAt(4) <= 90 ? `data-${name.slice(4).replace(/[A-Z]/g, (letter, at) => (at > 0 ? "-" : "") + letter.toLowerCase())}` : name;
18
+ /** A node's own element name and properties (`data.hName`, `data.hProperties`) over the default. */
19
+ const own = (node, tag, props) => {
20
+ const data = node.data;
21
+ if (data === void 0) return [tag, props];
22
+ const name = typeof data.hName === "string" ? data.hName : tag;
23
+ const extra = data.hProperties;
24
+ if (extra === void 0) return [name, props];
25
+ const merged = props === null ? {} : { ...props };
26
+ for (const key in extra) {
27
+ const value = extra[key];
28
+ if (value === void 0 || value === null || value === false) continue;
29
+ if (key === "className") merged.className = Array.isArray(value) ? value.join(" ") : value;
30
+ else merged[attribute(key)] = value;
31
+ }
32
+ return [name, merged];
33
+ };
34
+ /**
35
+ * The function that draws a tree with `factory`'s elements. Every call of it gives new elements;
36
+ * the caller remembers them by the tree's text.
37
+ */
38
+ const createRenderer = ({ element: h, text, fragment }) => (root, options) => {
39
+ const { components, urlTransform } = options;
40
+ const NEWLINE = text("\n");
41
+ const SPACE = text(" ");
42
+ /**
43
+ * The URL the page's check lets through, or undefined when it refuses one: emptied, or no
44
+ * answer. An empty URL as written (`[a]()`) stays empty, the link CommonMark writes.
45
+ */
46
+ const allowed = (url, key, node) => {
47
+ const checked = urlTransform(url, key, node);
48
+ return checked || (url === "" && checked === "" ? "" : void 0);
49
+ };
50
+ /** The page's component for an element the renderer writes itself, or the element. */
51
+ const pageTag = (name) => components[name] ?? name;
52
+ const element = (node, tag, props, children) => {
53
+ const [name, merged] = own(node, tag, props);
54
+ if (merged !== null && node.data?.hProperties !== void 0) {
55
+ for (const key of URL_PROPS) {
56
+ if (typeof merged[key] !== "string") continue;
57
+ const url = allowed(merged[key], key, node);
58
+ if (url === void 0) delete merged[key];
59
+ else merged[key] = url;
60
+ }
61
+ if (merged.innerHTML !== void 0) children = [];
62
+ }
63
+ const Page = components[name];
64
+ if (Page === void 0) return h(name, merged, children);
65
+ return h(Page, merged === null ? { node } : {
66
+ ...merged,
67
+ node
68
+ }, children);
69
+ };
70
+ /** A run of text-level nodes. */
71
+ const inline = (nodes) => {
72
+ const out = [];
73
+ if (nodes !== void 0) for (const node of nodes) one(node, out, false);
74
+ return out;
75
+ };
76
+ /** A run of blocks, a line break between each: before the first and after the last as well when `around`. */
77
+ const blocks = (nodes, around) => {
78
+ const out = [];
79
+ if (nodes === void 0) return out;
80
+ if (around) out.push(NEWLINE);
81
+ for (let index = 0; index < nodes.length; index++) {
82
+ const node = nodes[index];
83
+ if (index > 0 && node.type !== "text" && nodes[index - 1].type !== "text") out.push(NEWLINE);
84
+ one(node, out, false);
85
+ }
86
+ if (around && nodes.length > 0) out.push(NEWLINE);
87
+ return out;
88
+ };
89
+ const item = (node, loose) => {
90
+ const children = node.children ?? [];
91
+ const out = [];
92
+ const task = typeof node.checked === "boolean";
93
+ const box = task ? h(pageTag("input"), {
94
+ type: "checkbox",
95
+ disabled: true,
96
+ "data-task-key": options.offset + (node.position?.start.offset ?? 0),
97
+ ...node.checked ? { checked: true } : null
98
+ }, []) : null;
99
+ const first = children[0];
100
+ if (box !== null && (first === void 0 || first.type !== "paragraph" || first.data?.hName !== void 0)) {
101
+ if (loose) out.push(NEWLINE, h(pageTag("p"), null, [box]));
102
+ else out.push(box);
103
+ }
104
+ for (let index = 0; index < children.length; index++) {
105
+ const child = children[index];
106
+ const paragraph = child.type === "paragraph" && child.data?.hName === void 0;
107
+ if (loose || index !== 0 || !paragraph) out.push(NEWLINE);
108
+ if (paragraph) {
109
+ const words = inline(child.children);
110
+ if (box !== null && index === 0) {
111
+ if (words.length > 0) words.unshift(SPACE);
112
+ words.unshift(box);
113
+ }
114
+ if (loose) out.push(element(child, "p", null, words));
115
+ else out.push(...words);
116
+ } else one(child, out, false);
117
+ }
118
+ const last = children[children.length - 1];
119
+ if (last !== void 0 && (loose || last.type !== "paragraph" || last.data?.hName !== void 0)) out.push(NEWLINE);
120
+ return element(node, "li", task ? { className: "task-list-item" } : null, out);
121
+ };
122
+ const footnotes = (node) => {
123
+ const items = [NEWLINE];
124
+ const definitions = node.children ?? [];
125
+ for (let at = 0; at < definitions.length; at++) {
126
+ const definition = definitions[at];
127
+ const id = normalizeUri(definition.identifier ?? "");
128
+ const back = [];
129
+ for (let nth = 1; nth <= (definition.count ?? 1); nth++) {
130
+ const suffix = nth > 1 ? `-${nth}` : "";
131
+ if (nth > 1) back.push(SPACE);
132
+ back.push(h(pageTag("a"), {
133
+ href: `#${ID_PREFIX}fnref-${id}${suffix}`,
134
+ "data-footnote-backref": "",
135
+ "aria-label": `Back to reference ${definition.index}${suffix}`,
136
+ className: "data-footnote-backref"
137
+ }, nth > 1 ? [text("↩"), h(pageTag("sup"), null, [text(String(nth))])] : [text("↩")]));
138
+ }
139
+ const content = definition.children ?? [];
140
+ const body = [NEWLINE];
141
+ const tail = content[content.length - 1];
142
+ for (let index = 0; index < content.length; index++) {
143
+ const child = content[index];
144
+ if (index > 0) body.push(NEWLINE);
145
+ if (child === tail && child.type === "paragraph" && child.data?.hName === void 0) body.push(h(pageTag("p"), null, [
146
+ ...inline(child.children),
147
+ SPACE,
148
+ ...back
149
+ ]));
150
+ else one(child, body, false);
151
+ }
152
+ if (tail === void 0 || tail.type !== "paragraph" || tail.data?.hName !== void 0) body.push(NEWLINE, ...back);
153
+ body.push(NEWLINE);
154
+ if (at > 0) items.push(NEWLINE);
155
+ items.push(h(pageTag("li"), { id: `${ID_PREFIX}fn-${id}` }, body));
156
+ }
157
+ items.push(NEWLINE);
158
+ return h(pageTag("section"), {
159
+ "data-footnotes": "",
160
+ className: "footnotes"
161
+ }, [
162
+ h(pageTag("h2"), {
163
+ className: "sr-only",
164
+ id: `${ID_PREFIX}footnote-label`
165
+ }, [text("Footnotes")]),
166
+ NEWLINE,
167
+ h(pageTag("ol"), null, items),
168
+ NEWLINE
169
+ ]);
170
+ };
171
+ const one = (node, out, _tight) => {
172
+ switch (node.type) {
173
+ case "text":
174
+ out.push(text(node.value ?? ""));
175
+ return;
176
+ case "paragraph":
177
+ out.push(element(node, "p", null, inline(node.children)));
178
+ return;
179
+ case "heading": {
180
+ const id = options.headingIds?.get(options.offset + (node.position?.start.offset ?? 0));
181
+ out.push(element(node, `h${node.depth}`, id === void 0 ? null : { id }, inline(node.children)));
182
+ return;
183
+ }
184
+ case "emphasis":
185
+ out.push(element(node, "em", null, inline(node.children)));
186
+ return;
187
+ case "strong":
188
+ out.push(element(node, "strong", null, inline(node.children)));
189
+ return;
190
+ case "delete":
191
+ out.push(element(node, "del", null, inline(node.children)));
192
+ return;
193
+ case "inlineCode":
194
+ out.push(element(node, "code", null, [text((node.value ?? "").replace(/\r?\n|\r/g, " "))]));
195
+ return;
196
+ case "break":
197
+ out.push(element(node, "br", null, []), NEWLINE);
198
+ return;
199
+ case "link": {
200
+ const url = node.url ?? "";
201
+ const href = allowed(url, "href", node);
202
+ if (href === void 0 && node.children?.length === 1 && node.children[0]?.value === url) {
203
+ out.push(text(url));
204
+ return;
205
+ }
206
+ const props = href === void 0 ? {} : { href };
207
+ if (node.title) props.title = node.title;
208
+ out.push(element(node, "a", props, inline(node.children)));
209
+ return;
210
+ }
211
+ case "image": {
212
+ const src = allowed(node.url ?? "", "src", node);
213
+ const props = src ? {
214
+ src,
215
+ alt: node.alt ?? ""
216
+ } : { alt: node.alt ?? "" };
217
+ if (node.title) props.title = node.title;
218
+ out.push(element(node, "img", props, []));
219
+ return;
220
+ }
221
+ case "thematicBreak":
222
+ out.push(element(node, "hr", null, []));
223
+ return;
224
+ case "blockquote":
225
+ out.push(element(node, "blockquote", null, blocks(node.children, true)));
226
+ return;
227
+ case "code": {
228
+ const language = node.lang;
229
+ if (language === "mermaid" || language === "tree") {
230
+ const drawn = options.special(language, (node.value ?? "").replace(/\n$/, ""));
231
+ if (drawn !== void 0) {
232
+ out.push(drawn);
233
+ return;
234
+ }
235
+ }
236
+ const code = element(node, "code", language ? { className: `language-${language}` } : null, [text(node.value ?? "")]);
237
+ const Pre = components.pre;
238
+ out.push(Pre === void 0 ? h("pre", null, [code]) : h(Pre, { node }, [code]));
239
+ return;
240
+ }
241
+ case "list": {
242
+ const children = node.children ?? [];
243
+ let loose = node.spread === true;
244
+ let tasks = false;
245
+ for (const child of children) {
246
+ if (child.spread === true) loose = true;
247
+ if (typeof child.checked === "boolean") tasks = true;
248
+ }
249
+ const props = {};
250
+ if (node.ordered && typeof node.start === "number" && node.start !== 1) props.start = node.start;
251
+ if (tasks) props.className = "contains-task-list";
252
+ const rows = [NEWLINE];
253
+ for (let index = 0; index < children.length; index++) {
254
+ if (index > 0) rows.push(NEWLINE);
255
+ rows.push(item(children[index], loose));
256
+ }
257
+ if (children.length > 0) rows.push(NEWLINE);
258
+ out.push(element(node, node.ordered ? "ol" : "ul", props, rows));
259
+ return;
260
+ }
261
+ case "listItem":
262
+ out.push(item(node, node.spread === true));
263
+ return;
264
+ case "table": {
265
+ const rows = node.children ?? [];
266
+ const align = node.align ?? [];
267
+ const row = (from, header) => element(from, "tr", null, (from.children ?? []).map((cell, index) => element(cell, header ? "th" : "td", align[index] ? { style: { textAlign: align[index] } } : null, inline(cell.children))));
268
+ const parts = [];
269
+ const head = rows[0];
270
+ if (head !== void 0) parts.push(h(pageTag("thead"), null, [row(head, true)]));
271
+ if (rows.length > 1) parts.push(h(pageTag("tbody"), null, rows.slice(1).map((from) => row(from, false))));
272
+ out.push(element(node, "table", null, parts));
273
+ return;
274
+ }
275
+ case "footnoteReference": {
276
+ const id = normalizeUri(node.identifier ?? "");
277
+ const nth = (node.occurrence ?? 1) > 1 ? `-${node.occurrence}` : "";
278
+ out.push(h(pageTag("sup"), null, [h(pageTag("a"), {
279
+ href: `#${ID_PREFIX}fn-${id}`,
280
+ id: `${ID_PREFIX}fnref-${id}${nth}`,
281
+ "data-footnote-ref": "",
282
+ "aria-describedby": `${ID_PREFIX}footnote-label`
283
+ }, [text(String(node.index))])]));
284
+ return;
285
+ }
286
+ case "footnotes":
287
+ out.push(footnotes(node));
288
+ return;
289
+ case "html": return;
290
+ case "root":
291
+ out.push(...blocks(node.children, false));
292
+ return;
293
+ default: {
294
+ const children = node.children === void 0 ? node.value === void 0 ? [] : [text(node.value)] : mixed(node.children);
295
+ if (typeof node.data?.hName === "string") out.push(element(node, "div", null, children));
296
+ else out.push(...children);
297
+ }
298
+ }
299
+ };
300
+ /** The children of an element the tree does not know: blocks or text, as they come. */
301
+ const mixed = (nodes) => {
302
+ const out = [];
303
+ for (const node of nodes) one(node, out, false);
304
+ return out;
305
+ };
306
+ const out = [];
307
+ one(root, out, false);
308
+ return fragment(out);
309
+ };
310
+ export { ID_PREFIX, createRenderer };
311
+
312
+ //# sourceMappingURL=tree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.js","names":[],"sources":["../../src/render/tree.ts"],"sourcesContent":["/**\n * A Markdown tree as elements, for any target that has elements: the one place that says which\n * tag a node becomes, what a task list or a footnote is made of, and which URL is let through.\n */\nimport { DIAGRAM_FENCE_LANGUAGE, TREE_FENCE_LANGUAGE } from '../dialect'\nimport { normalizeUri } from '../engine/entities'\nimport type { Node } from '../engine/types'\nimport type { UrlTransform } from '../engine/url'\nimport type { Factory, Props } from './factory'\n\n/** A page's own element for a tag: it gets the tag's properties, and the node it draws as `node`. */\nexport type Components<C> = Record<string, C | undefined>\n\nexport interface RenderOptions<E, C> {\n components: Components<C>\n urlTransform: UrlTransform\n /** Where the tree's text starts in the document: task boxes and headings are keyed by it. */\n offset: number\n /** Ids for the headings, by where each starts in the document. */\n headingIds: ReadonlyMap<number, string> | null\n /** A ```mermaid or ```tree fence, drawn by the page that asked for one. */\n special: (language: string, source: string) => E | undefined\n}\n\n/** The prefix on every id content makes, so it cannot stand in for one of the page's own. */\nexport const ID_PREFIX = 'user-content-'\n\nconst URL_PROPS = ['href', 'src', 'cite', 'longDesc'] as const\n\n/** `dataCalloutTitle` as the attribute React writes: `data-callout-title`. */\nconst attribute = (name: string): string =>\n name.length > 4 && name.startsWith('data') && name.charCodeAt(4) >= 65 && name.charCodeAt(4) <= 90\n ? `data-${name.slice(4).replace(/[A-Z]/g, (letter, at: number) => (at > 0 ? '-' : '') + letter.toLowerCase())}`\n : name\n\n/** A node's own element name and properties (`data.hName`, `data.hProperties`) over the default. */\nconst own = (node: Node, tag: string, props: Props | null): [string, Props | null] => {\n const data = node.data\n if (data === undefined) return [tag, props]\n const name = typeof data.hName === 'string' ? data.hName : tag\n const extra = data.hProperties as Props | undefined\n if (extra === undefined) return [name, props]\n const merged: Props = props === null ? {} : { ...props }\n for (const key in extra) {\n const value = extra[key]\n if (value === undefined || value === null || value === false) continue\n if (key === 'className') merged.className = Array.isArray(value) ? value.join(' ') : value\n else merged[attribute(key)] = value\n }\n return [name, merged]\n}\n\n/**\n * The function that draws a tree with `factory`'s elements. Every call of it gives new elements;\n * the caller remembers them by the tree's text.\n */\nexport const createRenderer =\n <E, C>({ element: h, text, fragment }: Factory<E, C>) =>\n (root: Node, options: RenderOptions<E, C>): E => {\n const { components, urlTransform } = options\n const NEWLINE = text('\\n')\n const SPACE = text(' ')\n /**\n * The URL the page's check lets through, or undefined when it refuses one: emptied, or no\n * answer. An empty URL as written (`[a]()`) stays empty, the link CommonMark writes.\n */\n const allowed = (url: string, key: string, node: Node): string | undefined => {\n const checked = urlTransform(url, key, node)\n return checked || (url === '' && checked === '' ? '' : undefined)\n }\n /** The page's component for an element the renderer writes itself, or the element. */\n const pageTag = (name: string): string | C => components[name] ?? name\n\n const element = (node: Node, tag: string, props: Props | null, children: E[]): E => {\n const [name, merged] = own(node, tag, props)\n if (merged !== null && node.data?.hProperties !== undefined) {\n // An element an extension made: its URLs pass the page's check like a link's or an image's,\n // and one refused is dropped, not left as an empty attribute.\n for (const key of URL_PROPS) {\n if (typeof merged[key] !== 'string') continue\n const url = allowed(merged[key] as string, key, node)\n if (url === undefined) delete merged[key]\n else merged[key] = url\n }\n // An element given its HTML has no children of its own.\n if (merged.innerHTML !== undefined) children = []\n }\n const Page = components[name]\n if (Page === undefined) return h(name, merged, children)\n return h(Page, merged === null ? { node } : { ...merged, node }, children)\n }\n\n /** A run of text-level nodes. */\n const inline = (nodes: Node[] | undefined): E[] => {\n const out: E[] = []\n if (nodes !== undefined) for (const node of nodes) one(node, out, false)\n return out\n }\n\n /** A run of blocks, a line break between each: before the first and after the last as well when `around`. */\n const blocks = (nodes: Node[] | undefined, around: boolean): E[] => {\n const out: E[] = []\n if (nodes === undefined) return out\n if (around) out.push(NEWLINE)\n for (let index = 0; index < nodes.length; index++) {\n const node = nodes[index] as Node\n // Text among blocks is what raw HTML left there, with its own line breaks.\n if (index > 0 && node.type !== 'text' && (nodes[index - 1] as Node).type !== 'text')\n out.push(NEWLINE)\n one(node, out, false)\n }\n if (around && nodes.length > 0) out.push(NEWLINE)\n return out\n }\n\n const item = (node: Node, loose: boolean): E => {\n const children = node.children ?? []\n const out: E[] = []\n const task = typeof node.checked === 'boolean'\n const box = task\n ? h(\n pageTag('input'),\n {\n type: 'checkbox',\n disabled: true,\n 'data-task-key': options.offset + (node.position?.start.offset ?? 0),\n ...(node.checked ? { checked: true } : null),\n },\n [],\n )\n : null\n const first = children[0]\n // A task's box opens the item's first paragraph, or stands as one when there is none.\n if (\n box !== null &&\n (first === undefined || first.type !== 'paragraph' || first.data?.hName !== undefined)\n ) {\n if (loose) out.push(NEWLINE, h(pageTag('p'), null, [box]))\n else out.push(box)\n }\n for (let index = 0; index < children.length; index++) {\n const child = children[index] as Node\n const paragraph = child.type === 'paragraph' && child.data?.hName === undefined\n if (loose || index !== 0 || !paragraph) out.push(NEWLINE)\n if (paragraph) {\n const words = inline(child.children)\n if (box !== null && index === 0) {\n if (words.length > 0) words.unshift(SPACE)\n words.unshift(box)\n }\n if (loose) out.push(element(child, 'p', null, words))\n else out.push(...words)\n } else one(child, out, false)\n }\n const last = children[children.length - 1]\n if (\n last !== undefined &&\n (loose || last.type !== 'paragraph' || last.data?.hName !== undefined)\n )\n out.push(NEWLINE)\n return element(node, 'li', task ? { className: 'task-list-item' } : null, out)\n }\n\n const footnotes = (node: Node): E => {\n const items: E[] = [NEWLINE]\n const definitions = node.children ?? []\n for (let at = 0; at < definitions.length; at++) {\n const definition = definitions[at] as Node\n const id = normalizeUri(definition.identifier ?? '')\n const back: E[] = []\n for (let nth = 1; nth <= (definition.count ?? 1); nth++) {\n const suffix = nth > 1 ? `-${nth}` : ''\n if (nth > 1) back.push(SPACE)\n back.push(\n h(\n pageTag('a'),\n {\n href: `#${ID_PREFIX}fnref-${id}${suffix}`,\n 'data-footnote-backref': '',\n 'aria-label': `Back to reference ${definition.index}${suffix}`,\n className: 'data-footnote-backref',\n },\n nth > 1 ? [text('↩'), h(pageTag('sup'), null, [text(String(nth))])] : [text('↩')],\n ),\n )\n }\n const content = definition.children ?? []\n const body: E[] = [NEWLINE]\n const tail = content[content.length - 1]\n for (let index = 0; index < content.length; index++) {\n const child = content[index] as Node\n if (index > 0) body.push(NEWLINE)\n if (child === tail && child.type === 'paragraph' && child.data?.hName === undefined)\n body.push(h(pageTag('p'), null, [...inline(child.children), SPACE, ...back]))\n else one(child, body, false)\n }\n if (tail === undefined || tail.type !== 'paragraph' || tail.data?.hName !== undefined)\n body.push(NEWLINE, ...back)\n body.push(NEWLINE)\n if (at > 0) items.push(NEWLINE)\n items.push(h(pageTag('li'), { id: `${ID_PREFIX}fn-${id}` }, body))\n }\n items.push(NEWLINE)\n return h(pageTag('section'), { 'data-footnotes': '', className: 'footnotes' }, [\n h(pageTag('h2'), { className: 'sr-only', id: `${ID_PREFIX}footnote-label` }, [\n text('Footnotes'),\n ]),\n NEWLINE,\n h(pageTag('ol'), null, items),\n NEWLINE,\n ])\n }\n\n const one = (node: Node, out: E[], _tight: boolean): void => {\n switch (node.type) {\n case 'text':\n out.push(text(node.value ?? ''))\n return\n case 'paragraph':\n out.push(element(node, 'p', null, inline(node.children)))\n return\n case 'heading': {\n const id = options.headingIds?.get(options.offset + (node.position?.start.offset ?? 0))\n out.push(\n element(\n node,\n `h${node.depth}`,\n id === undefined ? null : { id },\n inline(node.children),\n ),\n )\n return\n }\n case 'emphasis':\n out.push(element(node, 'em', null, inline(node.children)))\n return\n case 'strong':\n out.push(element(node, 'strong', null, inline(node.children)))\n return\n case 'delete':\n out.push(element(node, 'del', null, inline(node.children)))\n return\n case 'inlineCode':\n out.push(\n element(node, 'code', null, [text((node.value ?? '').replace(/\\r?\\n|\\r/g, ' '))]),\n )\n return\n case 'break':\n out.push(element(node, 'br', null, []), NEWLINE)\n return\n case 'link': {\n const url = node.url ?? ''\n const href = allowed(url, 'href', node)\n // A bare address the page refuses to link (`ftp://…`) stays the text it was written as.\n if (\n href === undefined &&\n node.children?.length === 1 &&\n node.children[0]?.value === url\n ) {\n out.push(text(url))\n return\n }\n // A refused URL leaves the link without an `href`: an empty one would link to the page.\n const props: Props = href === undefined ? {} : { href }\n if (node.title) props.title = node.title\n out.push(element(node, 'a', props, inline(node.children)))\n return\n }\n case 'image': {\n // A refused or empty source is left off: `src=\"\"` makes a browser fetch the page again.\n const src = allowed(node.url ?? '', 'src', node)\n const props: Props = src ? { src, alt: node.alt ?? '' } : { alt: node.alt ?? '' }\n if (node.title) props.title = node.title\n out.push(element(node, 'img', props, []))\n return\n }\n case 'thematicBreak':\n out.push(element(node, 'hr', null, []))\n return\n case 'blockquote':\n out.push(element(node, 'blockquote', null, blocks(node.children, true)))\n return\n case 'code': {\n const language = node.lang\n if (language === DIAGRAM_FENCE_LANGUAGE || language === TREE_FENCE_LANGUAGE) {\n const drawn = options.special(language, (node.value ?? '').replace(/\\n$/, ''))\n if (drawn !== undefined) {\n out.push(drawn)\n return\n }\n }\n const code = element(\n node,\n 'code',\n language ? { className: `language-${language}` } : null,\n [text(node.value ?? '')],\n )\n const Pre = components.pre\n out.push(Pre === undefined ? h('pre', null, [code]) : h(Pre, { node }, [code]))\n return\n }\n case 'list': {\n const children = node.children ?? []\n let loose = node.spread === true\n let tasks = false\n for (const child of children) {\n if (child.spread === true) loose = true\n if (typeof child.checked === 'boolean') tasks = true\n }\n const props: Props = {}\n if (node.ordered && typeof node.start === 'number' && node.start !== 1)\n props.start = node.start\n if (tasks) props.className = 'contains-task-list'\n const rows: E[] = [NEWLINE]\n for (let index = 0; index < children.length; index++) {\n if (index > 0) rows.push(NEWLINE)\n rows.push(item(children[index] as Node, loose))\n }\n if (children.length > 0) rows.push(NEWLINE)\n out.push(element(node, node.ordered ? 'ol' : 'ul', props, rows))\n return\n }\n case 'listItem':\n out.push(item(node, node.spread === true))\n return\n case 'table': {\n const rows = node.children ?? []\n const align = node.align ?? []\n const row = (from: Node, header: boolean): E =>\n element(\n from,\n 'tr',\n null,\n (from.children ?? []).map((cell, index) =>\n element(\n cell,\n header ? 'th' : 'td',\n align[index] ? { style: { textAlign: align[index] } } : null,\n inline(cell.children),\n ),\n ),\n )\n const parts: E[] = []\n const head = rows[0]\n if (head !== undefined) parts.push(h(pageTag('thead'), null, [row(head, true)]))\n if (rows.length > 1)\n parts.push(\n h(\n pageTag('tbody'),\n null,\n rows.slice(1).map((from) => row(from, false)),\n ),\n )\n out.push(element(node, 'table', null, parts))\n return\n }\n case 'footnoteReference': {\n const id = normalizeUri(node.identifier ?? '')\n const nth = (node.occurrence ?? 1) > 1 ? `-${node.occurrence}` : ''\n out.push(\n h(pageTag('sup'), null, [\n h(\n pageTag('a'),\n {\n href: `#${ID_PREFIX}fn-${id}`,\n id: `${ID_PREFIX}fnref-${id}${nth}`,\n 'data-footnote-ref': '',\n 'aria-describedby': `${ID_PREFIX}footnote-label`,\n },\n [text(String(node.index))],\n ),\n ]),\n )\n return\n }\n case 'footnotes':\n out.push(footnotes(node))\n return\n case 'html':\n // Raw HTML is drawn only once the HTML stage has made elements of it.\n return\n case 'root':\n out.push(...blocks(node.children, false))\n return\n default: {\n // An extension's node: drawn by the element it names for itself, or as its children.\n const children =\n node.children === undefined\n ? node.value === undefined\n ? []\n : [text(node.value)]\n : mixed(node.children)\n if (typeof node.data?.hName === 'string') out.push(element(node, 'div', null, children))\n else out.push(...children)\n }\n }\n }\n\n /** The children of an element the tree does not know: blocks or text, as they come. */\n const mixed = (nodes: Node[]): E[] => {\n const out: E[] = []\n for (const node of nodes) one(node, out, false)\n return out\n }\n\n const out: E[] = []\n one(root, out, false)\n return fragment(out)\n }\n"],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { Extension } from "../engine/types.js";
2
+ import { UrlTransform } from "../engine/url.js";
3
+ import { LabelOverrides } from "./labels.js";
4
+ import { Highlighter } from "./views.js";
5
+ import { VComponent, VNode } from "./vnode.js";
6
+ /** Your own elements for any tag (`a`, `img`, `pre`, `table`, …) or the dialect's. */
7
+ export type ViewComponents = Record<string, VComponent | undefined>;
8
+ export interface ViewOptions {
9
+ components?: ViewComponents;
10
+ /** Your own drawing of a ```mermaid fence; `growing` while the fence is still being written. */
11
+ diagram?: (source: string, growing: boolean) => VNode;
12
+ /** Your own drawing of a ```tree fence. */
13
+ tree?: (source: string) => VNode;
14
+ /** Your own syntax, after the dialect's (`Extension`). */
15
+ extensions?: Extension[];
16
+ /** Give headings ids (`setup`, `setup-1`) to link to. */
17
+ headingIds?: boolean;
18
+ /** Raw HTML in the text, parsed and sanitized: `@localix-ai/flowdown/html`. Without it the tags are left out. */
19
+ html?: Extension | null;
20
+ /** Typeset `$…$`: `@localix-ai/flowdown/math`. */
21
+ math?: Extension | null;
22
+ /** Highlight fenced code: `@localix-ai/flowdown/highlight`, or your own. */
23
+ highlight?: Highlighter | null;
24
+ /** The words the renderer adds (callout names, button labels), for a page in another language. */
25
+ labels?: LabelOverrides;
26
+ /** Rewrite or refuse a link or image URL; by default only safe protocols are kept. */
27
+ urlTransform?: UrlTransform | null;
28
+ className?: string;
29
+ /** Leaves the `flowdown` class off the root element, so the package's stylesheet does not apply. */
30
+ unstyled?: boolean;
31
+ /** The caret after streaming text; on by default while streaming. */
32
+ caret?: boolean;
33
+ /**
34
+ * What the ids of a `[!TABS]` form's tabs and panels start with. Two documents on one page need
35
+ * two prefixes; `@localix-ai/flowdown/dom` gives each of its own.
36
+ */
37
+ idPrefix?: string;
38
+ /** The page the view is drawn on: with one, its tabs, trees and buttons answer the reader. */
39
+ host?: ViewHost;
40
+ }
41
+ /**
42
+ * What makes a view alive. A view drawn as HTML text has none, and its tabs, file trees and code
43
+ * buttons are drawn and nothing more; given one, they carry listeners (`onClick`, `onKeyDown`)
44
+ * that change what the view shows and ask the host to draw it again.
45
+ */
46
+ export interface ViewHost {
47
+ /** Something the reader did changed what the document shows: draw it again, now. */
48
+ redraw(): void;
49
+ /** Put `text` on the clipboard; resolves whether it got there. */
50
+ copy(text: string): Promise<boolean>;
51
+ /** Save `text` as a file named after its fence's title, or its language. */
52
+ download(text: string, title: string | undefined, language: string | undefined): void;
53
+ /** The box of a table, each time it is drawn: a host that can measure makes a wide one scroll. */
54
+ table?(box: unknown): void;
55
+ }