@thomasfosterau/effect-richtext 0.0.0-stage → 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 +118 -2
  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 +206 -3
@@ -0,0 +1,618 @@
1
+ import { attempt } from "../internal/attempt.js";
2
+ import { SchemaDefinitionError, isModelError } from "./errors.js";
3
+ import { Fragment } from "./fragment.js";
4
+ import { Mark } from "./mark.js";
5
+ import { Slice } from "./replace.js";
6
+ import * as Arr from "effect/Array";
7
+ import * as Option from "effect/Option";
8
+ // src/model/from_dom.ts
9
+ /**
10
+ * DOM parsing, ported from ProseMirror's `DOMParser`.
11
+ *
12
+ * @since 0.1.0
13
+ */
14
+ function isTagRule(rule) {
15
+ return rule.tag != null;
16
+ }
17
+ function isStyleRule(rule) {
18
+ return rule.style != null;
19
+ }
20
+ const ruleOrigin = /* @__PURE__ */ new WeakMap();
21
+ const originOf = (rule) => ruleOrigin.get(rule) ?? rule;
22
+ function withAttrs(rule, attrs) {
23
+ const result = {
24
+ ...rule,
25
+ attrs: attrs || void 0
26
+ };
27
+ ruleOrigin.set(result, originOf(rule));
28
+ return result;
29
+ }
30
+ /**
31
+ * A DOM parser represents a strategy for parsing DOM content into a
32
+ * document conforming to a given schema. Its behavior is defined by an
33
+ * array of [rules](#ParseRule).
34
+ *
35
+ * @since 0.1.0
36
+ * @category models
37
+ */
38
+ var DOMParser = class DOMParser {
39
+ /**
40
+ * Create a parser that targets the given schema, using the given
41
+ * parsing rules.
42
+ */
43
+ constructor(schema, rules) {
44
+ this.schema = schema;
45
+ this.rules = rules;
46
+ this.tags = [];
47
+ this.styles = [];
48
+ const matchedStyles = [];
49
+ const tags = [], styles = [];
50
+ rules.forEach((rule) => {
51
+ if (isTagRule(rule)) tags.push(rule);
52
+ else if (isStyleRule(rule)) {
53
+ const prop = /[^=]*/.exec(rule.style)[0];
54
+ if (matchedStyles.indexOf(prop) < 0) matchedStyles.push(prop);
55
+ styles.push(rule);
56
+ }
57
+ });
58
+ this.tags = tags;
59
+ this.styles = styles;
60
+ this.matchedStyles = matchedStyles;
61
+ this.normalizeLists = !tags.some((r) => {
62
+ if (!/^(ul|ol)\b/.test(r.tag) || !r.node) return false;
63
+ const node = schema.nodes[r.node];
64
+ return !!node && !!node.contentMatch.matchTypeOrNull(node);
65
+ });
66
+ }
67
+ /** Parse a document from the content of a DOM node. */
68
+ parse(dom, options = {}) {
69
+ return attempt(() => this.parseUnsafe(dom, options), isModelError);
70
+ }
71
+ /** Like `parse`, but throws a `ModelError` on failure. */
72
+ parseUnsafe(dom, options = {}) {
73
+ const context = new ParseContext(this, options, false);
74
+ context.addAll(dom, Mark.none, options.from, options.to);
75
+ return context.finish();
76
+ }
77
+ /**
78
+ * Parses the content of the given DOM node, like
79
+ * [`parse`](#DOMParser.parse), and takes the same set of options.
80
+ * But unlike that method, which produces a whole node, this one
81
+ * returns a slice that is open at the sides, meaning that the schema
82
+ * constraints aren't applied to the start of nodes to the left of
83
+ * the input and the end of nodes at the end.
84
+ */
85
+ parseSlice(dom, options = {}) {
86
+ return attempt(() => this.parseSliceUnsafe(dom, options), isModelError);
87
+ }
88
+ /** Like `parseSlice`, but throws a `ModelError` on failure. */
89
+ parseSliceUnsafe(dom, options = {}) {
90
+ const context = new ParseContext(this, options, true);
91
+ context.addAll(dom, Mark.none, options.from, options.to);
92
+ return Slice.maxOpen(context.finish());
93
+ }
94
+ /**
95
+ * Find the first tag rule (after `after`, when given) that matches
96
+ * the given DOM node in the given context. When the rule has a
97
+ * `getAttrs` function, the returned rule is a copy whose `attrs` hold
98
+ * the computed attributes.
99
+ */
100
+ matchTag(dom, context, after) {
101
+ return Option.fromNullishOr(this.matchTagOrNull(dom, context ?? new ParseContext(this, {}, false), after));
102
+ }
103
+ /** @internal */
104
+ matchTagOrNull(dom, context, after) {
105
+ for (let i = after ? this.tags.indexOf(originOf(after)) + 1 : 0; i < this.tags.length; i++) {
106
+ const rule = this.tags[i];
107
+ if (matches(dom, rule.tag) && (rule.namespace === void 0 || dom.namespaceURI == rule.namespace) && (!rule.context || context.matchesContext(rule.context))) {
108
+ if (rule.getAttrs) {
109
+ const result = rule.getAttrs(dom);
110
+ if (result === false) continue;
111
+ return withAttrs(rule, result);
112
+ }
113
+ return rule;
114
+ }
115
+ }
116
+ return null;
117
+ }
118
+ /**
119
+ * Find the first style rule (after `after`, when given) that matches
120
+ * the given style property and value in the given context.
121
+ */
122
+ matchStyle(prop, value, context, after) {
123
+ return Option.fromNullishOr(this.matchStyleOrNull(prop, value, context ?? new ParseContext(this, {}, false), after));
124
+ }
125
+ /** @internal */
126
+ matchStyleOrNull(prop, value, context, after) {
127
+ for (let i = after ? this.styles.indexOf(originOf(after)) + 1 : 0; i < this.styles.length; i++) {
128
+ const rule = this.styles[i], style = rule.style;
129
+ if (style.indexOf(prop) != 0 || rule.context && !context.matchesContext(rule.context) || style.length > prop.length && (style.charCodeAt(prop.length) != 61 || style.slice(prop.length + 1) != value)) continue;
130
+ if (rule.getAttrs) {
131
+ const result = rule.getAttrs(value);
132
+ if (result === false) continue;
133
+ return withAttrs(rule, result);
134
+ }
135
+ return rule;
136
+ }
137
+ return null;
138
+ }
139
+ /**
140
+ * Gather the parse rules from a schema's node and mark specs,
141
+ * ordered by priority (and schema order for equal priorities). Rules
142
+ * without a `node`/`mark` get the name of the type they were defined
143
+ * on.
144
+ */
145
+ static schemaRules(schema) {
146
+ const result = [];
147
+ function insert(rule) {
148
+ const priority = rule.priority == null ? 50 : rule.priority;
149
+ let i = 0;
150
+ for (; i < result.length; i++) {
151
+ const next = result[i];
152
+ if ((next.priority == null ? 50 : next.priority) < priority) break;
153
+ }
154
+ result.splice(i, 0, rule);
155
+ }
156
+ for (const name in schema.marks) {
157
+ const rules = schema.marks[name].spec.parseDOM;
158
+ if (rules) rules.forEach((r) => {
159
+ const rule = { ...r };
160
+ if (!(rule.mark || rule.ignore || rule.clearMark)) rule.mark = name;
161
+ insert(rule);
162
+ });
163
+ }
164
+ for (const name in schema.nodes) {
165
+ const rules = schema.nodes[name].spec.parseDOM;
166
+ if (rules) rules.forEach((r) => {
167
+ const rule = { ...r };
168
+ if (!(rule.node || rule.ignore || rule.mark)) rule.node = name;
169
+ insert(rule);
170
+ });
171
+ }
172
+ return result;
173
+ }
174
+ /**
175
+ * Construct a DOM parser using the parsing rules listed in a schema's
176
+ * node specs, reordered by priority. The parser is cached on the
177
+ * schema.
178
+ */
179
+ static fromSchema(schema) {
180
+ return schema.cached.domParser || (schema.cached.domParser = new DOMParser(schema, DOMParser.schemaRules(schema)));
181
+ }
182
+ };
183
+ const blockTags = {
184
+ address: true,
185
+ article: true,
186
+ aside: true,
187
+ blockquote: true,
188
+ body: true,
189
+ canvas: true,
190
+ dd: true,
191
+ div: true,
192
+ dl: true,
193
+ fieldset: true,
194
+ figcaption: true,
195
+ figure: true,
196
+ footer: true,
197
+ form: true,
198
+ h1: true,
199
+ h2: true,
200
+ h3: true,
201
+ h4: true,
202
+ h5: true,
203
+ h6: true,
204
+ header: true,
205
+ hgroup: true,
206
+ hr: true,
207
+ li: true,
208
+ noscript: true,
209
+ ol: true,
210
+ output: true,
211
+ p: true,
212
+ pre: true,
213
+ section: true,
214
+ table: true,
215
+ tfoot: true,
216
+ ul: true
217
+ };
218
+ const ignoreTags = {
219
+ head: true,
220
+ noscript: true,
221
+ object: true,
222
+ script: true,
223
+ style: true,
224
+ title: true
225
+ };
226
+ const listTags = {
227
+ ol: true,
228
+ ul: true
229
+ };
230
+ const hasOwn = (table, key) => Object.prototype.hasOwnProperty.call(table, key);
231
+ const OPT_PRESERVE_WS = 1;
232
+ const OPT_PRESERVE_WS_FULL = 2;
233
+ const OPT_OPEN_LEFT = 4;
234
+ function wsOptionsFor(type, preserveWhitespace, base) {
235
+ if (preserveWhitespace != null) return (preserveWhitespace ? OPT_PRESERVE_WS : 0) | (preserveWhitespace === "full" ? OPT_PRESERVE_WS_FULL : 0);
236
+ return type && type.whitespace == "pre" ? 3 : base & -5;
237
+ }
238
+ var NodeContext = class {
239
+ constructor(type, attrs, marks, solid, match, options) {
240
+ this.type = type;
241
+ this.attrs = attrs;
242
+ this.marks = marks;
243
+ this.solid = solid;
244
+ this.options = options;
245
+ this.content = [];
246
+ this.activeMarks = Mark.none;
247
+ this.match = match || (options & OPT_OPEN_LEFT ? null : type.contentMatch);
248
+ }
249
+ findWrapping(node) {
250
+ if (!this.match) {
251
+ if (!this.type) return [];
252
+ const fill = this.type.contentMatch.fillBeforeOrNull(Fragment.from(node));
253
+ if (fill) this.match = this.type.contentMatch.matchFragmentOrNull(fill);
254
+ else {
255
+ const start = this.type.contentMatch;
256
+ const wrap = start.findWrappingOrNull(node.type);
257
+ if (wrap) {
258
+ this.match = start;
259
+ return wrap;
260
+ } else return null;
261
+ }
262
+ }
263
+ return this.match.findWrappingOrNull(node.type);
264
+ }
265
+ finish(openEnd) {
266
+ if (!(this.options & OPT_PRESERVE_WS)) {
267
+ const last = this.content[this.content.length - 1];
268
+ let m;
269
+ if (last && last.isText && (m = /[ \t\r\n\f]+$/.exec(last.text))) {
270
+ const text = last;
271
+ if (text.text.length == m[0].length) this.content.pop();
272
+ else this.content[this.content.length - 1] = text.withText(text.text.slice(0, text.text.length - m[0].length));
273
+ }
274
+ }
275
+ let content = Fragment.from(this.content);
276
+ if (!openEnd && this.match) content = content.append(this.match.fillBeforeOrNull(Fragment.empty, true));
277
+ return this.type ? this.type.createUnsafe(this.attrs, content, this.marks) : content;
278
+ }
279
+ inlineContext(node) {
280
+ if (this.type) return this.type.inlineContent;
281
+ if (this.content.length) return this.content[0].isInline;
282
+ return !!node.parentNode && !hasOwn(blockTags, node.parentNode.nodeName.toLowerCase());
283
+ }
284
+ };
285
+ /** @internal */
286
+ var ParseContext = class {
287
+ constructor(parser, options, isOpen) {
288
+ this.parser = parser;
289
+ this.options = options;
290
+ this.isOpen = isOpen;
291
+ this.open = 0;
292
+ this.localPreserveWS = false;
293
+ const topNode = options.topNode;
294
+ let topContext;
295
+ const topOptions = wsOptionsFor(null, options.preserveWhitespace, 0) | (isOpen ? OPT_OPEN_LEFT : 0);
296
+ if (topNode) topContext = new NodeContext(topNode.type, topNode.attrs, Mark.none, true, options.topMatch || topNode.type.contentMatch, topOptions);
297
+ else if (isOpen) topContext = new NodeContext(null, null, Mark.none, true, null, topOptions);
298
+ else topContext = new NodeContext(parser.schema.topNodeType, null, Mark.none, true, null, topOptions);
299
+ this.nodes = [topContext];
300
+ this.find = options.findPositions;
301
+ this.needsBlock = false;
302
+ }
303
+ get top() {
304
+ return this.nodes[this.open];
305
+ }
306
+ addDOM(dom, marks) {
307
+ if (dom.nodeType == 3) this.addTextNode(dom, marks);
308
+ else if (dom.nodeType == 1) this.addElement(dom, marks);
309
+ }
310
+ addTextNode(dom, marks) {
311
+ let value = dom.nodeValue;
312
+ const top = this.top;
313
+ const preserveWS = top.options & OPT_PRESERVE_WS_FULL ? "full" : this.localPreserveWS || (top.options & OPT_PRESERVE_WS) > 0;
314
+ const schema = this.parser.schema;
315
+ const linebreak = Option.getOrNull(schema.linebreakReplacement);
316
+ if (preserveWS === "full" || top.inlineContext(dom) || /[^ \t\r\n\f]/.test(value)) {
317
+ if (!preserveWS) {
318
+ value = value.replace(/[ \t\r\n\f]+/g, " ");
319
+ if (/^[ \t\r\n\f]/.test(value) && this.open == this.nodes.length - 1) {
320
+ const nodeBefore = top.content[top.content.length - 1];
321
+ const domNodeBefore = dom.previousSibling;
322
+ if (!nodeBefore || domNodeBefore && domNodeBefore.nodeName == "BR" || nodeBefore.isText && /[ \t\r\n\f]$/.test(nodeBefore.text)) value = value.slice(1);
323
+ }
324
+ } else if (preserveWS === "full") value = value.replace(/\r\n?/g, "\n");
325
+ else if (linebreak && /[\r\n]/.test(value) && this.top.findWrapping(linebreak.createUnsafe())) {
326
+ const lines = value.split(/\r?\n|\r/);
327
+ for (let i = 0; i < lines.length; i++) {
328
+ if (i) this.insertNode(linebreak.createUnsafe(), marks, true);
329
+ if (lines[i]) this.insertNode(schema.textUnsafe(lines[i]), marks, !/\S/.test(lines[i]));
330
+ }
331
+ value = "";
332
+ } else value = value.replace(/\r?\n|\r/g, " ");
333
+ if (value) this.insertNode(schema.textUnsafe(value), marks, !/\S/.test(value));
334
+ this.findInText(dom);
335
+ } else this.findInside(dom);
336
+ }
337
+ addElement(dom, marks, matchAfter) {
338
+ const outerWS = this.localPreserveWS;
339
+ let top = this.top;
340
+ if (dom.tagName == "PRE" || /pre/.test(dom.style && dom.style.whiteSpace)) this.localPreserveWS = true;
341
+ const name = dom.nodeName.toLowerCase();
342
+ let ruleID;
343
+ if (hasOwn(listTags, name) && this.parser.normalizeLists) normalizeList(dom);
344
+ const rule = this.options.ruleFromNode && this.options.ruleFromNode(dom) || (ruleID = this.parser.matchTagOrNull(dom, this, matchAfter));
345
+ out: if (rule ? rule.ignore : hasOwn(ignoreTags, name)) {
346
+ this.findInside(dom);
347
+ this.ignoreFallback(dom, marks);
348
+ } else if (!rule || rule.skip || rule.closeParent) {
349
+ if (rule && rule.closeParent) this.open = Math.max(0, this.open - 1);
350
+ else if (rule && rule.skip.nodeType) dom = rule.skip;
351
+ let sync = false;
352
+ const oldNeedsBlock = this.needsBlock;
353
+ if (hasOwn(blockTags, name)) {
354
+ if (top.content.length && top.content[0].isInline && this.open) {
355
+ this.open--;
356
+ top = this.top;
357
+ }
358
+ sync = true;
359
+ if (!top.type) this.needsBlock = true;
360
+ } else if (!dom.firstChild) {
361
+ this.leafFallback(dom, marks);
362
+ break out;
363
+ }
364
+ const innerMarks = rule && rule.skip ? marks : this.readStyles(dom, marks);
365
+ if (innerMarks) this.addAll(dom, innerMarks);
366
+ if (sync) this.sync(top);
367
+ this.needsBlock = oldNeedsBlock;
368
+ } else {
369
+ const innerMarks = this.readStyles(dom, marks);
370
+ if (innerMarks) this.addElementByRule(dom, rule, innerMarks, rule.consuming === false ? ruleID ?? void 0 : void 0);
371
+ }
372
+ this.localPreserveWS = outerWS;
373
+ }
374
+ leafFallback(dom, marks) {
375
+ if (dom.nodeName == "BR" && this.top.type && this.top.type.inlineContent) this.addTextNode(dom.ownerDocument.createTextNode("\n"), marks);
376
+ }
377
+ ignoreFallback(dom, marks) {
378
+ if (dom.nodeName == "BR" && (!this.top.type || !this.top.type.inlineContent)) this.findPlace(this.parser.schema.textUnsafe("-"), marks, true);
379
+ }
380
+ readStyles(dom, marks) {
381
+ const styles = dom.style;
382
+ if (styles && styles.length) for (let i = 0; i < this.parser.matchedStyles.length; i++) {
383
+ const name = this.parser.matchedStyles[i], value = styles.getPropertyValue(name);
384
+ if (value) for (let after = void 0;;) {
385
+ const rule = this.parser.matchStyleOrNull(name, value, this, after);
386
+ if (!rule) break;
387
+ if (rule.ignore) return null;
388
+ if (rule.clearMark) marks = marks.filter((m) => !rule.clearMark(m));
389
+ else marks = marks.concat(markType(this.parser.schema, rule.mark).createUnsafe(rule.attrs));
390
+ if (rule.consuming === false) after = rule;
391
+ else break;
392
+ }
393
+ }
394
+ return marks;
395
+ }
396
+ addElementByRule(dom, rule, marks, continueAfter) {
397
+ let sync = false, nodeType;
398
+ if (rule.node) {
399
+ nodeType = this.parser.schema.nodeType(rule.node);
400
+ if (!nodeType.isLeaf) {
401
+ const inner = this.enter(nodeType, rule.attrs || null, marks, rule.preserveWhitespace);
402
+ if (inner) {
403
+ sync = true;
404
+ marks = inner;
405
+ }
406
+ } else if (!this.insertNode(nodeType.createUnsafe(rule.attrs), marks, dom.nodeName == "BR")) this.leafFallback(dom, marks);
407
+ } else marks = marks.concat(markType(this.parser.schema, rule.mark).createUnsafe(rule.attrs));
408
+ const startIn = this.top;
409
+ if (nodeType && nodeType.isLeaf) this.findInside(dom);
410
+ else if (continueAfter) this.addElement(dom, marks, continueAfter);
411
+ else if (rule.getContent) {
412
+ this.findInside(dom);
413
+ rule.getContent(dom, this.parser.schema).forEach((node) => this.insertNode(node, marks, false));
414
+ } else {
415
+ let contentDOM = dom;
416
+ if (typeof rule.contentElement == "string") contentDOM = dom.querySelector(rule.contentElement);
417
+ else if (typeof rule.contentElement == "function") contentDOM = rule.contentElement(dom);
418
+ else if (rule.contentElement) contentDOM = rule.contentElement;
419
+ this.findAround(dom, contentDOM, true);
420
+ this.addAll(contentDOM, marks);
421
+ this.findAround(dom, contentDOM, false);
422
+ }
423
+ if (sync && this.sync(startIn)) this.open--;
424
+ }
425
+ addAll(parent, marks, startIndex, endIndex) {
426
+ let index = startIndex || 0;
427
+ for (let dom = startIndex ? parent.childNodes[startIndex] : parent.firstChild, end = endIndex == null ? null : parent.childNodes[endIndex]; dom != end; dom = dom.nextSibling, ++index) {
428
+ this.findAtPoint(parent, index);
429
+ this.addDOM(dom, marks);
430
+ }
431
+ this.findAtPoint(parent, index);
432
+ }
433
+ findPlace(node, marks, cautious) {
434
+ let route, sync;
435
+ for (let depth = this.open, penalty = 0; depth >= 0; depth--) {
436
+ const cx = this.nodes[depth];
437
+ const found = cx.findWrapping(node);
438
+ if (found && (!route || route.length > found.length + penalty)) {
439
+ route = found;
440
+ sync = cx;
441
+ if (!found.length) break;
442
+ }
443
+ if (cx.solid) {
444
+ if (cautious) break;
445
+ penalty += 2;
446
+ }
447
+ }
448
+ if (!route) return null;
449
+ this.sync(sync);
450
+ for (let i = 0; i < route.length; i++) marks = this.enterInner(route[i], null, marks, false);
451
+ return marks;
452
+ }
453
+ insertNode(node, marks, cautious) {
454
+ if (node.isInline && this.needsBlock && !this.top.type) {
455
+ const block = this.textblockFromContext();
456
+ if (block) marks = this.enterInner(block, null, marks);
457
+ }
458
+ const innerMarks = this.findPlace(node, marks, cautious);
459
+ if (innerMarks) {
460
+ this.closeExtra();
461
+ const top = this.top;
462
+ if (top.match) top.match = top.match.matchTypeOrNull(node.type);
463
+ let nodeMarks = Mark.none;
464
+ for (const m of innerMarks.concat(node.marks)) if (top.type ? top.type.allowsMarkType(m.type) : markMayApply(m.type, node.type)) nodeMarks = m.addToSet(nodeMarks);
465
+ top.content.push(node.mark(nodeMarks));
466
+ return true;
467
+ }
468
+ return false;
469
+ }
470
+ enter(type, attrs, marks, preserveWS) {
471
+ let innerMarks = this.findPlace(type.createUnsafe(attrs), marks, false);
472
+ if (innerMarks) innerMarks = this.enterInner(type, attrs, marks, true, preserveWS);
473
+ return innerMarks;
474
+ }
475
+ enterInner(type, attrs, marks, solid = false, preserveWS) {
476
+ this.closeExtra();
477
+ const top = this.top;
478
+ top.match = top.match && top.match.matchTypeOrNull(type);
479
+ let options = wsOptionsFor(type, preserveWS, top.options);
480
+ if (top.options & OPT_OPEN_LEFT && Arr.isReadonlyArrayEmpty(top.content)) options |= OPT_OPEN_LEFT;
481
+ let applyMarks = Mark.none;
482
+ marks = marks.filter((m) => {
483
+ if (top.type ? top.type.allowsMarkType(m.type) : markMayApply(m.type, type)) {
484
+ applyMarks = m.addToSet(applyMarks);
485
+ return false;
486
+ }
487
+ return true;
488
+ });
489
+ this.nodes.push(new NodeContext(type, attrs, applyMarks, solid, null, options));
490
+ this.open++;
491
+ return marks;
492
+ }
493
+ closeExtra(openEnd = false) {
494
+ let i = this.nodes.length - 1;
495
+ if (i > this.open) {
496
+ for (; i > this.open; i--) this.nodes[i - 1].content.push(this.nodes[i].finish(openEnd));
497
+ this.nodes.length = this.open + 1;
498
+ }
499
+ }
500
+ finish() {
501
+ this.open = 0;
502
+ this.closeExtra(this.isOpen);
503
+ return this.nodes[0].finish(!!(this.isOpen || this.options.topOpen));
504
+ }
505
+ sync(to) {
506
+ for (let i = this.open; i >= 0; i--) if (this.nodes[i] == to) {
507
+ this.open = i;
508
+ return true;
509
+ } else if (this.localPreserveWS) this.nodes[i].options |= OPT_PRESERVE_WS;
510
+ return false;
511
+ }
512
+ get currentPos() {
513
+ this.closeExtra();
514
+ let pos = 0;
515
+ for (let i = this.open; i >= 0; i--) {
516
+ const content = this.nodes[i].content;
517
+ for (let j = content.length - 1; j >= 0; j--) pos += content[j].nodeSize;
518
+ if (i) pos++;
519
+ }
520
+ return pos;
521
+ }
522
+ findAtPoint(parent, offset) {
523
+ if (this.find) {
524
+ for (let i = 0; i < this.find.length; i++) if (this.find[i].node == parent && this.find[i].offset == offset) this.find[i].pos = this.currentPos;
525
+ }
526
+ }
527
+ findInside(parent) {
528
+ if (this.find) {
529
+ for (let i = 0; i < this.find.length; i++) if (this.find[i].pos == null && parent.nodeType == 1 && parent.contains(this.find[i].node)) this.find[i].pos = this.currentPos;
530
+ }
531
+ }
532
+ findAround(parent, content, before) {
533
+ if (parent != content && this.find) {
534
+ for (let i = 0; i < this.find.length; i++) if (this.find[i].pos == null && parent.nodeType == 1 && parent.contains(this.find[i].node)) {
535
+ if (content.compareDocumentPosition(this.find[i].node) & (before ? 2 : 4)) this.find[i].pos = this.currentPos;
536
+ }
537
+ }
538
+ }
539
+ findInText(textNode) {
540
+ if (this.find) {
541
+ for (let i = 0; i < this.find.length; i++) if (this.find[i].node == textNode) this.find[i].pos = this.currentPos - (textNode.nodeValue.length - this.find[i].offset);
542
+ }
543
+ }
544
+ matchesContext(context) {
545
+ if (context.indexOf("|") > -1) return context.split(/\s*\|\s*/).some(this.matchesContext, this);
546
+ const parts = context.split("/");
547
+ const option = this.options.context;
548
+ const useRoot = !this.isOpen && (!option || option.parent.type == this.nodes[0].type);
549
+ const minDepth = -(option ? option.depth + 1 : 0) + (useRoot ? 0 : 1);
550
+ const match = (i, depth) => {
551
+ for (; i >= 0; i--) {
552
+ const part = parts[i];
553
+ if (part == "") {
554
+ if (i == parts.length - 1 || i == 0) continue;
555
+ for (; depth >= minDepth; depth--) if (match(i - 1, depth)) return true;
556
+ return false;
557
+ } else {
558
+ const next = depth > 0 || depth == 0 && useRoot ? this.nodes[depth].type : option && depth >= minDepth ? option.node(depth - minDepth).type : null;
559
+ if (!next || next.name != part && !next.isInGroup(part)) return false;
560
+ depth--;
561
+ }
562
+ }
563
+ return true;
564
+ };
565
+ return match(parts.length - 1, this.open);
566
+ }
567
+ textblockFromContext() {
568
+ const $context = this.options.context;
569
+ if ($context) for (let d = $context.depth; d >= 0; d--) {
570
+ const deflt = $context.node(d).contentMatchAtUnsafe($context.indexAfter(d)).defaultTypeOrNull;
571
+ if (deflt && deflt.isTextblock && deflt.defaultAttrs) return deflt;
572
+ }
573
+ const nodes = this.parser.schema.nodes;
574
+ for (const name in nodes) {
575
+ const type = nodes[name];
576
+ if (type.isTextblock && type.defaultAttrs) return type;
577
+ }
578
+ }
579
+ };
580
+ function markType(schema, name) {
581
+ const type = name === void 0 ? void 0 : schema.marks[name];
582
+ if (!type) throw new SchemaDefinitionError({ message: `Parse rule refers to unknown mark type ${String(name)}` });
583
+ return type;
584
+ }
585
+ function normalizeList(dom) {
586
+ for (let child = dom.firstChild, prevItem = null; child; child = child.nextSibling) {
587
+ const name = child.nodeType == 1 ? child.nodeName.toLowerCase() : null;
588
+ if (name && hasOwn(listTags, name) && prevItem) {
589
+ prevItem.appendChild(child);
590
+ child = prevItem;
591
+ } else if (name == "li") prevItem = child;
592
+ else if (name) prevItem = null;
593
+ }
594
+ }
595
+ function matches(dom, selector) {
596
+ const f = dom.matches || dom.msMatchesSelector || dom.webkitMatchesSelector || dom.mozMatchesSelector;
597
+ return !!f && f.call(dom, selector);
598
+ }
599
+ function markMayApply(markType, nodeType) {
600
+ const nodes = nodeType.schema.nodes;
601
+ for (const name in nodes) {
602
+ const parent = nodes[name];
603
+ if (!parent.allowsMarkType(markType)) continue;
604
+ const seen = [];
605
+ const scan = (match) => {
606
+ seen.push(match);
607
+ for (let i = 0; i < match.next.length; i++) {
608
+ const { next, type } = match.next[i];
609
+ if (type == nodeType) return true;
610
+ if (seen.indexOf(next) < 0 && scan(next)) return true;
611
+ }
612
+ return false;
613
+ };
614
+ if (scan(parent.contentMatch)) return true;
615
+ }
616
+ return false;
617
+ }
618
+ export { DOMParser };
@@ -0,0 +1,37 @@
1
+ import { Fragment } from "./fragment.js";
2
+ import { Mark } from "./mark.js";
3
+ import { Node, NodeJSON } from "./node.js";
4
+ import { Slice } from "./replace.js";
5
+ import { AnySchema } from "./schema.js";
6
+ import * as S from "effect/Schema";
7
+ /** @internal */
8
+ export declare function markFromJSON<Sc extends AnySchema>(schema: Sc, json: any): Mark<Sc>;
9
+ /** @internal */
10
+ export declare function nodeFromJSON<Sc extends AnySchema>(schema: Sc, json: any): Node<Sc>;
11
+ /** @internal */
12
+ export declare function fragmentFromJSON<Sc extends AnySchema>(schema: Sc, value: any): Fragment<Sc>;
13
+ /** @internal */
14
+ export declare function sliceFromJSON<Sc extends AnySchema>(schema: Sc, value: any): Slice<Sc>;
15
+ /**
16
+ * An Effect `Schema` that decodes the JSON representation of a node
17
+ * into a `Node` of the given document schema (validating structure,
18
+ * content, and attributes), and encodes nodes back to JSON.
19
+ *
20
+ * ```ts skip-type-checking
21
+ * import { Schema } from "effect"
22
+ * const doc = yield* Schema.decodeUnknownEffect(NodeFromJSON(mySchema))(json)
23
+ * ```
24
+ *
25
+ * @since 0.1.0
26
+ * @category schemas
27
+ */
28
+ export declare const NodeFromJSON: <Sc extends AnySchema>(schema: Sc) => S.Codec<Node<Sc>, NodeJSON>;
29
+ /**
30
+ * An Effect `Schema` for the top-level document of a schema: like
31
+ * `NodeFromJSON`, but also requires the decoded node to be of the
32
+ * schema's top node type.
33
+ *
34
+ * @since 0.1.0
35
+ * @category schemas
36
+ */
37
+ export declare const DocFromJSON: <Sc extends AnySchema>(schema: Sc) => S.Codec<Node<Sc>, NodeJSON>;