@thomasfosterau/effect-richtext 0.0.0 → 0.1.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 (176) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +117 -1
  3. package/dist/_virtual/_rolldown/runtime.js +12 -0
  4. package/dist/commands/commands.d.ts +323 -0
  5. package/dist/commands/commands.js +722 -0
  6. package/dist/commands/internal.js +43 -0
  7. package/dist/commands/keymaps.d.ts +46 -0
  8. package/dist/commands/keymaps.js +64 -0
  9. package/dist/commands.d.ts +3 -0
  10. package/dist/commands.js +3 -0
  11. package/dist/compat/commands.d.ts +250 -0
  12. package/dist/compat/commands.js +275 -0
  13. package/dist/compat/internal/core.d.ts +20 -0
  14. package/dist/compat/internal/core.js +148 -0
  15. package/dist/compat/internal/props.js +82 -0
  16. package/dist/compat/keymap.d.ts +21 -0
  17. package/dist/compat/keymap.js +38 -0
  18. package/dist/compat/model.d.ts +893 -0
  19. package/dist/compat/model.js +1212 -0
  20. package/dist/compat/orderedmap.d.ts +74 -0
  21. package/dist/compat/orderedmap.js +124 -0
  22. package/dist/compat/schema-basic.d.ts +38 -0
  23. package/dist/compat/schema-basic.js +238 -0
  24. package/dist/compat/schema-list.d.ts +81 -0
  25. package/dist/compat/schema-list.js +156 -0
  26. package/dist/compat/state.d.ts +415 -0
  27. package/dist/compat/state.js +689 -0
  28. package/dist/compat/test-builder.d.ts +98 -0
  29. package/dist/compat/test-builder.js +197 -0
  30. package/dist/compat/transform.d.ts +458 -0
  31. package/dist/compat/transform.js +803 -0
  32. package/dist/compat/view.d.ts +411 -0
  33. package/dist/compat/view.js +409 -0
  34. package/dist/dropcursor.d.ts +46 -0
  35. package/dist/dropcursor.js +176 -0
  36. package/dist/extensions/defaults.d.ts +716 -0
  37. package/dist/extensions/defaults.js +209 -0
  38. package/dist/extensions/editor.d.ts +246 -0
  39. package/dist/extensions/editor.js +271 -0
  40. package/dist/extensions/extension.d.ts +375 -0
  41. package/dist/extensions/extension.js +233 -0
  42. package/dist/extensions.d.ts +4 -0
  43. package/dist/extensions.js +4 -0
  44. package/dist/gapcursor.d.ts +66 -0
  45. package/dist/gapcursor.js +273 -0
  46. package/dist/history.d.ts +178 -0
  47. package/dist/history.js +412 -0
  48. package/dist/html.d.ts +158 -0
  49. package/dist/html.js +164 -0
  50. package/dist/inputrules.d.ts +271 -0
  51. package/dist/inputrules.js +321 -0
  52. package/dist/internal/attempt.js +15 -0
  53. package/dist/internal/json.js +29 -0
  54. package/dist/keymap/keymap.d.ts +130 -0
  55. package/dist/keymap/keymap.js +159 -0
  56. package/dist/keymap.d.ts +2 -0
  57. package/dist/keymap.js +1 -0
  58. package/dist/markdown/errors.d.ts +23 -0
  59. package/dist/markdown/errors.js +26 -0
  60. package/dist/markdown/from_markdown.d.ts +185 -0
  61. package/dist/markdown/from_markdown.js +266 -0
  62. package/dist/markdown/schema.d.ts +522 -0
  63. package/dist/markdown/schema.js +292 -0
  64. package/dist/markdown/to_markdown.d.ts +251 -0
  65. package/dist/markdown/to_markdown.js +413 -0
  66. package/dist/markdown.d.ts +5 -0
  67. package/dist/markdown.js +5 -0
  68. package/dist/model/attrsCodec.js +48 -0
  69. package/dist/model/comparedeep.js +17 -0
  70. package/dist/model/content.d.ts +232 -0
  71. package/dist/model/content.js +630 -0
  72. package/dist/model/diff.js +66 -0
  73. package/dist/model/dom.d.ts +3 -0
  74. package/dist/model/errors.d.ts +90 -0
  75. package/dist/model/errors.js +76 -0
  76. package/dist/model/fragment.d.ts +131 -0
  77. package/dist/model/fragment.js +262 -0
  78. package/dist/model/from_dom.d.ts +299 -0
  79. package/dist/model/from_dom.js +618 -0
  80. package/dist/model/json.d.ts +37 -0
  81. package/dist/model/json.js +126 -0
  82. package/dist/model/mark.d.ts +73 -0
  83. package/dist/model/mark.js +121 -0
  84. package/dist/model/node.d.ts +267 -0
  85. package/dist/model/node.js +434 -0
  86. package/dist/model/replace.d.ts +78 -0
  87. package/dist/model/replace.js +207 -0
  88. package/dist/model/resolvedpos.d.ts +196 -0
  89. package/dist/model/resolvedpos.js +305 -0
  90. package/dist/model/schema.d.ts +740 -0
  91. package/dist/model/schema.js +451 -0
  92. package/dist/model/to_dom.d.ts +169 -0
  93. package/dist/model/to_dom.js +238 -0
  94. package/dist/model.d.ts +12 -0
  95. package/dist/model.js +12 -0
  96. package/dist/placeholder.d.ts +53 -0
  97. package/dist/placeholder.js +79 -0
  98. package/dist/reactive/observer.d.ts +54 -0
  99. package/dist/reactive/observer.js +61 -0
  100. package/dist/reactive/selectors.d.ts +22 -0
  101. package/dist/reactive/selectors.js +61 -0
  102. package/dist/reactive/stateref.d.ts +72 -0
  103. package/dist/reactive/stateref.js +71 -0
  104. package/dist/reactive/streams.d.ts +83 -0
  105. package/dist/reactive/streams.js +85 -0
  106. package/dist/reactive.d.ts +16 -0
  107. package/dist/reactive.js +26 -0
  108. package/dist/schema-basic.d.ts +448 -0
  109. package/dist/schema-basic.js +269 -0
  110. package/dist/schema-list/commands.d.ts +66 -0
  111. package/dist/schema-list/commands.js +203 -0
  112. package/dist/schema-list.d.ts +92 -0
  113. package/dist/schema-list.js +100 -0
  114. package/dist/state/errors.d.ts +39 -0
  115. package/dist/state/errors.js +32 -0
  116. package/dist/state/plugin.d.ts +232 -0
  117. package/dist/state/plugin.js +82 -0
  118. package/dist/state/selection.d.ts +297 -0
  119. package/dist/state/selection.js +486 -0
  120. package/dist/state/state.d.ts +212 -0
  121. package/dist/state/state.js +489 -0
  122. package/dist/state/transaction.d.ts +145 -0
  123. package/dist/state/transaction.js +195 -0
  124. package/dist/state.d.ts +6 -0
  125. package/dist/state.js +6 -0
  126. package/dist/test-builder.d.ts +3582 -0
  127. package/dist/test-builder.js +239 -0
  128. package/dist/transform/attr_step.d.ts +60 -0
  129. package/dist/transform/attr_step.js +105 -0
  130. package/dist/transform/errors.d.ts +50 -0
  131. package/dist/transform/errors.js +35 -0
  132. package/dist/transform/map.d.ts +182 -0
  133. package/dist/transform/map.js +280 -0
  134. package/dist/transform/mark.js +98 -0
  135. package/dist/transform/mark_set_step.js +69 -0
  136. package/dist/transform/mark_step.d.ts +113 -0
  137. package/dist/transform/mark_step.js +225 -0
  138. package/dist/transform/replace.d.ts +18 -0
  139. package/dist/transform/replace.js +381 -0
  140. package/dist/transform/replace_step.d.ts +109 -0
  141. package/dist/transform/replace_step.js +175 -0
  142. package/dist/transform/step.d.ts +157 -0
  143. package/dist/transform/step.js +168 -0
  144. package/dist/transform/structure.d.ts +89 -0
  145. package/dist/transform/structure.js +350 -0
  146. package/dist/transform/transform.d.ts +248 -0
  147. package/dist/transform/transform.js +373 -0
  148. package/dist/transform.d.ts +10 -0
  149. package/dist/transform.js +10 -0
  150. package/dist/view/browser.js +39 -0
  151. package/dist/view/capturekeys.js +282 -0
  152. package/dist/view/clipboard.d.ts +8 -0
  153. package/dist/view/clipboard.js +245 -0
  154. package/dist/view/decoration.d.ts +339 -0
  155. package/dist/view/decoration.js +566 -0
  156. package/dist/view/dom.d.ts +18 -0
  157. package/dist/view/dom.js +140 -0
  158. package/dist/view/domchange.js +295 -0
  159. package/dist/view/domcoords.d.ts +22 -0
  160. package/dist/view/domcoords.js +448 -0
  161. package/dist/view/domobserver.d.ts +47 -0
  162. package/dist/view/domobserver.js +328 -0
  163. package/dist/view/errors.d.ts +18 -0
  164. package/dist/view/errors.js +21 -0
  165. package/dist/view/input.d.ts +58 -0
  166. package/dist/view/input.js +704 -0
  167. package/dist/view/selection.js +198 -0
  168. package/dist/view/view.d.ts +699 -0
  169. package/dist/view/view.js +623 -0
  170. package/dist/view/viewdesc.d.ts +236 -0
  171. package/dist/view/viewdesc.js +1205 -0
  172. package/dist/view-css.d.ts +43 -0
  173. package/dist/view-css.js +124 -0
  174. package/dist/view.d.ts +6 -0
  175. package/dist/view.js +4 -0
  176. package/package.json +200 -4
@@ -0,0 +1,413 @@
1
+ import { Mark } from "../model/mark.js";
2
+ import { MarkdownError } from "./errors.js";
3
+ import * as Arr from "effect/Array";
4
+ import * as Order from "effect/Order";
5
+ // src/markdown/to_markdown.ts
6
+ /**
7
+ * Serializing documents to Markdown.
8
+ *
9
+ * @since 0.1.0
10
+ */
11
+ const blankMark = {
12
+ open: "",
13
+ close: "",
14
+ mixable: true
15
+ };
16
+ /**
17
+ * A specification for serializing a document as Markdown/CommonMark
18
+ * text.
19
+ *
20
+ * @since 0.1.0
21
+ * @category models
22
+ */
23
+ var MarkdownSerializer = class {
24
+ /**
25
+ * Construct a serializer with the given configuration. The `nodes`
26
+ * object should map node names in a given schema to function that
27
+ * take a serializer state and such a node, and serialize the node.
28
+ */
29
+ constructor(nodes, marks, options = {}) {
30
+ this.nodes = nodes;
31
+ this.marks = marks;
32
+ this.options = options;
33
+ }
34
+ /**
35
+ * Serialize the content of the given node to
36
+ * [CommonMark](http://commonmark.org/).
37
+ *
38
+ * Serialization can't fail for nodes that the serializer knows; in
39
+ * strict mode (the default) an unknown node or mark type is a
40
+ * programming error and throws a `MarkdownError`.
41
+ */
42
+ serialize(content, options = {}) {
43
+ const state = new MarkdownSerializerState(this.nodes, this.marks, {
44
+ ...this.options,
45
+ ...options
46
+ });
47
+ state.renderContent(content);
48
+ return state.out;
49
+ }
50
+ };
51
+ function backticksFor(node, side) {
52
+ const ticks = /`+/g;
53
+ let m, len = 0;
54
+ if (node.isText) while (m = ticks.exec(node.text)) len = Math.max(len, m[0].length);
55
+ let result = len > 0 && side > 0 ? " `" : "`";
56
+ for (let i = 0; i < len; i++) result += "`";
57
+ if (len > 0 && side < 0) result += " ";
58
+ return result;
59
+ }
60
+ function isPlainURL(link, parent, index) {
61
+ if (link.attrs.title || !/^\w+:/.test(link.attrs.href)) return false;
62
+ const content = parent.childUnsafe(index);
63
+ if (!content.isText || content.text != link.attrs.href || content.marks[content.marks.length - 1] != link) return false;
64
+ return index == parent.childCount - 1 || !link.isInSet(parent.childUnsafe(index + 1).marks);
65
+ }
66
+ /**
67
+ * A serializer for the Markdown schema (or any schema using the same
68
+ * node and mark names).
69
+ *
70
+ * @since 0.1.0
71
+ * @category serializers
72
+ */
73
+ const defaultMarkdownSerializer = new MarkdownSerializer({
74
+ blockquote(state, node) {
75
+ state.wrapBlock("> ", null, node, () => state.renderContent(node));
76
+ },
77
+ code_block(state, node) {
78
+ const backticks = node.textContent.match(/`{3,}/gm);
79
+ const fence = backticks ? Arr.sort(backticks, Order.String).slice(-1)[0] + "`" : "```";
80
+ state.write(fence + (node.attrs.params || "") + "\n");
81
+ state.text(node.textContent, false);
82
+ state.write("\n");
83
+ state.write(fence);
84
+ state.closeBlock(node);
85
+ },
86
+ heading(state, node) {
87
+ state.write(state.repeat("#", node.attrs.level) + " ");
88
+ state.renderInline(node, false);
89
+ state.closeBlock(node);
90
+ },
91
+ horizontal_rule(state, node) {
92
+ state.write(node.attrs.markup || "---");
93
+ state.closeBlock(node);
94
+ },
95
+ bullet_list(state, node) {
96
+ state.renderList(node, " ", () => (node.attrs.bullet || "*") + " ");
97
+ },
98
+ ordered_list(state, node) {
99
+ const start = node.attrs.order ?? 1;
100
+ const maxW = String(start + node.childCount - 1).length;
101
+ const space = state.repeat(" ", maxW + 2);
102
+ state.renderList(node, space, (i) => {
103
+ const nStr = String(start + i);
104
+ return state.repeat(" ", maxW - nStr.length) + nStr + ". ";
105
+ });
106
+ },
107
+ list_item(state, node) {
108
+ state.renderContent(node);
109
+ },
110
+ paragraph(state, node) {
111
+ state.renderInline(node);
112
+ state.closeBlock(node);
113
+ },
114
+ image(state, node) {
115
+ state.write("![" + state.esc(node.attrs.alt || "") + "](" + node.attrs.src.replace(/[()]/g, "\\$&") + (node.attrs.title ? " \"" + node.attrs.title.replace(/"/g, "\\\"") + "\"" : "") + ")");
116
+ },
117
+ hard_break(state, node, parent, index) {
118
+ for (let i = index + 1; i < parent.childCount; i++) if (parent.childUnsafe(i).type != node.type) {
119
+ state.write("\\\n");
120
+ return;
121
+ }
122
+ },
123
+ text(state, node) {
124
+ state.text(node.text, !state.inAutolink);
125
+ }
126
+ }, {
127
+ em: {
128
+ open: "*",
129
+ close: "*",
130
+ mixable: true,
131
+ expelEnclosingWhitespace: true
132
+ },
133
+ strong: {
134
+ open: "**",
135
+ close: "**",
136
+ mixable: true,
137
+ expelEnclosingWhitespace: true
138
+ },
139
+ link: {
140
+ open(state, mark, parent, index) {
141
+ state.inAutolink = isPlainURL(mark, parent, index);
142
+ return state.inAutolink ? "<" : "[";
143
+ },
144
+ close(state, mark) {
145
+ const { inAutolink } = state;
146
+ state.inAutolink = void 0;
147
+ return inAutolink ? ">" : "](" + mark.attrs.href.replace(/[()"]/g, "\\$&") + (mark.attrs.title ? ` "${mark.attrs.title.replace(/"/g, "\\\"")}"` : "") + ")";
148
+ },
149
+ mixable: true
150
+ },
151
+ code: {
152
+ open(_state, _mark, parent, index) {
153
+ return backticksFor(parent.childUnsafe(index), -1);
154
+ },
155
+ close(_state, _mark, parent, index) {
156
+ return backticksFor(parent.childUnsafe(index - 1), 1);
157
+ },
158
+ escape: false
159
+ }
160
+ });
161
+ /**
162
+ * This is an object used to track state and expose methods related to
163
+ * markdown serialization. Instances are passed to node and mark
164
+ * serialization methods.
165
+ *
166
+ * @since 0.1.0
167
+ * @category models
168
+ */
169
+ var MarkdownSerializerState = class {
170
+ /** @internal */
171
+ constructor(nodes, marks, options) {
172
+ this.nodes = nodes;
173
+ this.marks = marks;
174
+ this.delim = "";
175
+ this.out = "";
176
+ this.closed = null;
177
+ this.inAutolink = void 0;
178
+ this.atBlockStart = false;
179
+ this.inTightList = false;
180
+ this.options = {
181
+ ...options,
182
+ tightLists: options.tightLists ?? false,
183
+ hardBreakNodeName: options.hardBreakNodeName ?? "hard_break"
184
+ };
185
+ }
186
+ /** @internal */
187
+ flushClose(size = 2) {
188
+ if (this.closed) {
189
+ if (!this.atBlank()) this.out += "\n";
190
+ if (size > 1) {
191
+ let delimMin = this.delim;
192
+ const trim = /\s+$/.exec(delimMin);
193
+ if (trim) delimMin = delimMin.slice(0, delimMin.length - trim[0].length);
194
+ for (let i = 1; i < size; i++) this.out += delimMin + "\n";
195
+ }
196
+ this.closed = null;
197
+ }
198
+ }
199
+ /** @internal */
200
+ getMark(name) {
201
+ let info = this.marks[name];
202
+ if (!info) {
203
+ if (this.options.strict !== false) throw new MarkdownError({ message: `Mark type \`${name}\` not supported by Markdown renderer` });
204
+ info = blankMark;
205
+ }
206
+ return info;
207
+ }
208
+ /**
209
+ * Render a block, prefixing each line with `delim`, and the first line
210
+ * in `firstDelim`. `node` should be the node that is closed at the end
211
+ * of the block, and `f` is a function that renders the content of the
212
+ * block.
213
+ */
214
+ wrapBlock(delim, firstDelim, node, f) {
215
+ const old = this.delim;
216
+ this.write(firstDelim != null ? firstDelim : delim);
217
+ this.delim += delim;
218
+ f();
219
+ this.delim = old;
220
+ this.closeBlock(node);
221
+ }
222
+ /** @internal */
223
+ atBlank() {
224
+ return !this.out || this.out[this.out.length - 1] == "\n";
225
+ }
226
+ /** Ensure the current content ends with a newline. */
227
+ ensureNewLine() {
228
+ if (!this.atBlank()) this.out += "\n";
229
+ }
230
+ /**
231
+ * Prepare the state for writing output (closing closed paragraphs,
232
+ * adding delimiters, and so on), and then optionally add content
233
+ * (unescaped) to the output.
234
+ */
235
+ write(content) {
236
+ this.flushClose();
237
+ if (this.delim && this.atBlank()) this.out += this.delim;
238
+ if (content) this.out += content;
239
+ }
240
+ /** Close the block for the given node. */
241
+ closeBlock(node) {
242
+ this.closed = node;
243
+ }
244
+ /** Add the given text to the document. When escape is not `false`, it will be escaped. */
245
+ text(text, escape = true) {
246
+ const lines = text.split("\n");
247
+ for (let i = 0; i < lines.length; i++) {
248
+ this.write();
249
+ if (!escape && lines[i][0] == "[" && /(^|[^\\])!$/.test(this.out.slice(-2))) this.out = this.out.slice(0, this.out.length - 1) + "\\!";
250
+ this.out += escape ? this.esc(lines[i], this.atBlockStart) : lines[i];
251
+ if (i != lines.length - 1) this.out += "\n";
252
+ }
253
+ }
254
+ /**
255
+ * Render the given node as a block. In strict mode, throws a
256
+ * `MarkdownError` for node types without a serializer.
257
+ */
258
+ render(node, parent, index) {
259
+ const serializer = this.nodes[node.type.name];
260
+ if (serializer) serializer(this, node, parent, index);
261
+ else if (this.options.strict !== false) throw new MarkdownError({ message: "Token type `" + node.type.name + "` not supported by Markdown renderer" });
262
+ else if (!node.type.isLeaf) {
263
+ if (node.type.inlineContent) this.renderInline(node);
264
+ else this.renderContent(node);
265
+ if (node.isBlock) this.closeBlock(node);
266
+ }
267
+ }
268
+ /** Render the contents of `parent` as block nodes. */
269
+ renderContent(parent) {
270
+ parent.forEach((node, _, i) => this.render(node, parent, i));
271
+ }
272
+ /** Render the contents of `parent` as inline content. */
273
+ renderInline(parent, fromBlockStart = true) {
274
+ this.atBlockStart = fromBlockStart;
275
+ const active = [];
276
+ let trailing = "";
277
+ const progress = (node, _offset, index) => {
278
+ let marks = node ? node.marks : [];
279
+ if (node && node.type.name === this.options.hardBreakNodeName) marks = marks.filter((m) => {
280
+ if (index + 1 == parent.childCount) return false;
281
+ const next = parent.childUnsafe(index + 1);
282
+ return m.isInSet(next.marks) && (!next.isText || /\S/.test(next.text));
283
+ });
284
+ const inner = marks.length ? marks[marks.length - 1] : null;
285
+ const noEsc = inner && this.getMark(inner.type.name).escape === false;
286
+ const len = marks.length - (noEsc ? 1 : 0);
287
+ outer: for (let i = 0; i < len; i++) {
288
+ const mark = marks[i];
289
+ if (!this.getMark(mark.type.name).mixable) break;
290
+ for (let j = 0; j < active.length; j++) {
291
+ const other = active[j];
292
+ if (!this.getMark(other.type.name).mixable) break;
293
+ if (mark.eq(other)) {
294
+ if (i > j) marks = marks.slice(0, j).concat(mark).concat(marks.slice(j, i)).concat(marks.slice(i + 1, len));
295
+ else if (j > i) marks = marks.slice(0, i).concat(marks.slice(i + 1, j)).concat(mark).concat(marks.slice(j, len));
296
+ continue outer;
297
+ }
298
+ }
299
+ }
300
+ let keep = 0;
301
+ while (keep < Math.min(active.length, len) && marks[keep].eq(active[keep])) ++keep;
302
+ let leading = trailing;
303
+ trailing = "";
304
+ if (node && node.isText && marks.some((mark) => {
305
+ const info = this.getMark(mark.type.name);
306
+ return info && info.expelEnclosingWhitespace && !active.some((m, i) => i < keep && m.eq(mark));
307
+ })) {
308
+ const [_, lead, rest] = /^(\s*)(.*)$/m.exec(node.text);
309
+ if (lead) {
310
+ leading += lead;
311
+ node = rest ? node.withText(rest) : null;
312
+ if (!node) marks = active;
313
+ }
314
+ }
315
+ if (node && node.isText && marks.some((mark, i) => {
316
+ const info = this.getMark(mark.type.name);
317
+ return info && info.expelEnclosingWhitespace && !this.isMarkAhead(parent, index + 1, marks.slice(0, i + 1));
318
+ })) {
319
+ const [_, rest, trail] = /^(.*?)(\s*)$/m.exec(node.text);
320
+ if (trail) {
321
+ trailing = trail;
322
+ node = rest ? node.withText(rest) : null;
323
+ if (!node) marks = active;
324
+ }
325
+ }
326
+ if (node || index == parent.childCount) while (keep < active.length) this.text(this.markString(active.pop(), false, parent, index), false);
327
+ if (leading) this.text(leading);
328
+ if (node) {
329
+ while (active.length < len) {
330
+ const add = marks[active.length];
331
+ active.push(add);
332
+ this.text(this.markString(add, true, parent, index), false);
333
+ this.atBlockStart = false;
334
+ }
335
+ if (noEsc && node.isText) this.text(this.markString(inner, true, parent, index) + node.text + this.markString(inner, false, parent, index + 1), false);
336
+ else this.render(node, parent, index);
337
+ this.atBlockStart = false;
338
+ if (node.isText && node.nodeSize > 0) this.atBlockStart = false;
339
+ }
340
+ };
341
+ parent.forEach(progress);
342
+ progress(null, 0, parent.childCount);
343
+ this.atBlockStart = false;
344
+ }
345
+ /**
346
+ * Render a node's content as a list. `delim` should be the extra
347
+ * indentation added to all lines except the first in an item,
348
+ * `firstDelim` is a function going from an item index to a delimiter
349
+ * for the first line of the item.
350
+ */
351
+ renderList(node, delim, firstDelim) {
352
+ if (this.closed && this.closed.type == node.type) this.flushClose(3);
353
+ else if (this.inTightList) this.flushClose(1);
354
+ const attrs = node.attrs;
355
+ const isTight = typeof attrs.tight != "undefined" ? attrs.tight : this.options.tightLists;
356
+ const prevTight = this.inTightList;
357
+ this.inTightList = isTight;
358
+ node.forEach((child, _, i) => {
359
+ if (i && isTight) this.flushClose(1);
360
+ this.wrapBlock(delim, firstDelim(i), node, () => this.render(child, node, i));
361
+ });
362
+ this.inTightList = prevTight;
363
+ }
364
+ /**
365
+ * Escape the given string so that it can safely appear in Markdown
366
+ * content. If `startOfLine` is true, also escape characters that have
367
+ * special meaning only at the start of the line.
368
+ */
369
+ esc(str, startOfLine = false) {
370
+ str = str.replace(/[`*\\~[\]_]/g, (m, i) => m == "_" && i > 0 && i + 1 < str.length && str[i - 1].match(/\w/) && str[i + 1].match(/\w/) ? m : "\\" + m);
371
+ if (startOfLine) str = str.replace(/^(\+[ ]|[-*>])/, "\\$&").replace(/^(\s*)(#{1,6})(\s|$)/, "$1\\$2$3").replace(/^(\s*\d+)\.\s/, "$1\\. ");
372
+ if (this.options.escapeExtraCharacters) str = str.replace(this.options.escapeExtraCharacters, "\\$&");
373
+ return str;
374
+ }
375
+ /** @internal */
376
+ quote(str) {
377
+ const wrap = str.indexOf("\"") == -1 ? "\"\"" : str.indexOf("'") == -1 ? "''" : "()";
378
+ return wrap[0] + str + wrap[1];
379
+ }
380
+ /** Repeat the given string `n` times. */
381
+ repeat(str, n) {
382
+ let out = "";
383
+ for (let i = 0; i < n; i++) out += str;
384
+ return out;
385
+ }
386
+ /** Get the markdown string for a given opening or closing mark. */
387
+ markString(mark, open, parent, index) {
388
+ const info = this.getMark(mark.type.name);
389
+ const value = open ? info.open : info.close;
390
+ return typeof value == "string" ? value : value(this, mark, parent, index);
391
+ }
392
+ /**
393
+ * Get leading and trailing whitespace from a string. Values of leading
394
+ * or trailing property of the return object will be undefined if there
395
+ * is no match.
396
+ */
397
+ getEnclosingWhitespace(text) {
398
+ return {
399
+ leading: (text.match(/^(\s+)/) || [void 0])[0],
400
+ trailing: (text.match(/(\s+)$/) || [void 0])[0]
401
+ };
402
+ }
403
+ /** @internal */
404
+ isMarkAhead(parent, index, marks) {
405
+ for (;; index++) {
406
+ if (index >= parent.childCount) return false;
407
+ const next = parent.childUnsafe(index);
408
+ if (next.type.name != this.options.hardBreakNodeName) return next.marks.length >= marks.length && Mark.sameSet(next.marks.slice(0, marks.length), marks);
409
+ index++;
410
+ }
411
+ }
412
+ };
413
+ export { MarkdownSerializer, MarkdownSerializerState, defaultMarkdownSerializer };
@@ -0,0 +1,5 @@
1
+ import { MarkdownError, isMarkdownError } from "./markdown/errors.js";
2
+ import { MarkdownParseState, MarkdownParser, ParseSpec, TokenHandler, defaultMarkdownParser } from "./markdown/from_markdown.js";
3
+ import { MarkdownSchema, marks, nodes, schema } from "./markdown/schema.js";
4
+ import { MarkSerializerSpec, MarkdownSerializeOptions, MarkdownSerializer, MarkdownSerializerOptions, MarkdownSerializerState, MarkdownSerializerStateOptions, NodeSerializer, defaultMarkdownSerializer } from "./markdown/to_markdown.js";
5
+ export { MarkSerializerSpec, MarkdownError, MarkdownParseState, MarkdownParser, MarkdownSchema, MarkdownSerializeOptions, MarkdownSerializer, MarkdownSerializerOptions, MarkdownSerializerState, MarkdownSerializerStateOptions, NodeSerializer, ParseSpec, TokenHandler, defaultMarkdownParser, defaultMarkdownSerializer, isMarkdownError, marks, nodes, schema };
@@ -0,0 +1,5 @@
1
+ import { MarkdownError, isMarkdownError } from "./markdown/errors.js";
2
+ import { MarkdownParseState, MarkdownParser, defaultMarkdownParser } from "./markdown/from_markdown.js";
3
+ import { marks, nodes, schema } from "./markdown/schema.js";
4
+ import { MarkdownSerializer, MarkdownSerializerState, defaultMarkdownSerializer } from "./markdown/to_markdown.js";
5
+ export { MarkdownError, MarkdownParseState, MarkdownParser, MarkdownSerializer, MarkdownSerializerState, defaultMarkdownParser, defaultMarkdownSerializer, isMarkdownError, marks, nodes, schema };
@@ -0,0 +1,48 @@
1
+ import * as S from "effect/Schema";
2
+ // src/model/attrsCodec.ts
3
+ const encoderCache = /* @__PURE__ */ new WeakMap();
4
+ const decoderCache = /* @__PURE__ */ new WeakMap();
5
+ const encoder = (schema) => {
6
+ let enc = encoderCache.get(schema);
7
+ if (!enc) {
8
+ enc = S.encodeUnknownSync(schema);
9
+ encoderCache.set(schema, enc);
10
+ }
11
+ return enc;
12
+ };
13
+ const decoder = (schema) => {
14
+ let dec = decoderCache.get(schema);
15
+ if (!dec) {
16
+ dec = S.decodeUnknownSync(schema);
17
+ decoderCache.set(schema, dec);
18
+ }
19
+ return dec;
20
+ };
21
+ const mapAttrs = (defs, attrs, decode) => {
22
+ let out;
23
+ for (const name in attrs) {
24
+ const def = defs[name];
25
+ if (!def?.schema || def.identityCodec && (!decode || def.is !== void 0 && def.is(attrs[name]))) continue;
26
+ const value = (decode ? decoder : encoder)(def.schema)(attrs[name]);
27
+ if (value !== attrs[name]) {
28
+ if (!out) out = { ...attrs };
29
+ out[name] = value;
30
+ }
31
+ }
32
+ return out ?? attrs;
33
+ };
34
+ /**
35
+ * Encode attribute values with their schemas, for JSON output. Returns
36
+ * the input object when nothing changed.
37
+ *
38
+ * @internal
39
+ */
40
+ const encodeAttrs = (defs, attrs) => mapAttrs(defs, attrs, false);
41
+ /**
42
+ * Decode attribute values from JSON with their schemas. Throws the
43
+ * schema error on failure.
44
+ *
45
+ * @internal
46
+ */
47
+ const decodeAttrs = (defs, attrs) => mapAttrs(defs, attrs, true);
48
+ export { decodeAttrs, encodeAttrs };
@@ -0,0 +1,17 @@
1
+ import * as Predicate from "effect/Predicate";
2
+ // src/model/comparedeep.ts
3
+ /** @internal */
4
+ function compareDeep(a, b) {
5
+ if (a === b) return true;
6
+ if (!Predicate.isObjectOrArray(a) || !Predicate.isObjectOrArray(b)) return false;
7
+ if (Array.isArray(a)) {
8
+ if (!Array.isArray(b) || a.length !== b.length) return false;
9
+ for (let i = 0; i < a.length; i++) if (!compareDeep(a[i], b[i])) return false;
10
+ } else {
11
+ if (Array.isArray(b)) return false;
12
+ for (const p in a) if (!(p in b) || !compareDeep(a[p], b[p])) return false;
13
+ for (const p in b) if (!(p in a)) return false;
14
+ }
15
+ return true;
16
+ }
17
+ export { compareDeep };