@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,630 @@
1
+ import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
+ import { SchemaDefinitionError } from "./errors.js";
3
+ import { Fragment } from "./fragment.js";
4
+ import * as Arr from "effect/Array";
5
+ import * as Option from "effect/Option";
6
+ import * as Predicate from "effect/Predicate";
7
+ import * as Match from "effect/Match";
8
+ import * as Order from "effect/Order";
9
+ // src/model/content.ts
10
+ /**
11
+ * Content expressions describe which children a node type allows.
12
+ *
13
+ * Unlike ProseMirror, which uses a string mini-language
14
+ * (`"paragraph+"`, `"heading block*"`), content is described with
15
+ * typed combinators. The node and group names a combinator refers to
16
+ * are tracked at the type level, so the schema knows which node types
17
+ * may appear inside each node:
18
+ *
19
+ * ```ts skip-type-checking
20
+ * import { Content } from "@thomasfosterau/effect-richtext/model"
21
+ *
22
+ * Content.seq("heading", Content.zeroOrMore("block"))
23
+ * // ContentExpr<"heading" | "block">
24
+ * ```
25
+ *
26
+ * `Content.parse` accepts the ProseMirror string syntax for
27
+ * compatibility, at the cost of losing the type-level information.
28
+ *
29
+ * @since 0.1.0
30
+ */
31
+ var content_exports = /* @__PURE__ */ __exportAll({
32
+ ContentMatch: () => ContentMatch,
33
+ choice: () => choice,
34
+ format: () => format,
35
+ isContentExpr: () => isContentExpr,
36
+ oneOrMore: () => oneOrMore,
37
+ optional: () => optional,
38
+ parse: () => parse,
39
+ ref: () => ref,
40
+ repeat: () => repeat,
41
+ seq: () => seq,
42
+ zeroOrMore: () => zeroOrMore
43
+ });
44
+ const TypeId = "~effect-richtext/model/ContentExpr";
45
+ const variance = { _Refs: (_) => _ };
46
+ const make = (ast) => ({
47
+ [TypeId]: variance,
48
+ ast
49
+ });
50
+ const toAST = (input) => Predicate.isString(input) ? {
51
+ _tag: "Name",
52
+ name: input
53
+ } : input.ast;
54
+ /**
55
+ * @since 0.1.0
56
+ * @category guards
57
+ */
58
+ const isContentExpr = (u) => Predicate.isObjectOrArray(u) && TypeId in u;
59
+ /**
60
+ * Reference a single node type or group by name.
61
+ *
62
+ * @since 0.1.0
63
+ * @category constructors
64
+ */
65
+ const ref = (name) => make({
66
+ _tag: "Name",
67
+ name
68
+ });
69
+ /**
70
+ * A sequence of expressions that must appear in order.
71
+ *
72
+ * @since 0.1.0
73
+ * @category combinators
74
+ */
75
+ const seq = (...items) => items.length === 1 ? make(toAST(items[0])) : make({
76
+ _tag: "Seq",
77
+ exprs: items.map(toAST)
78
+ });
79
+ /**
80
+ * Any one of the given expressions.
81
+ *
82
+ * @since 0.1.0
83
+ * @category combinators
84
+ */
85
+ const choice = (...items) => items.length === 1 ? make(toAST(items[0])) : make({
86
+ _tag: "Choice",
87
+ exprs: items.map(toAST)
88
+ });
89
+ /**
90
+ * Zero or more repetitions (`expr*`).
91
+ *
92
+ * @since 0.1.0
93
+ * @category combinators
94
+ */
95
+ const zeroOrMore = (item) => make({
96
+ _tag: "Star",
97
+ expr: toAST(item)
98
+ });
99
+ /**
100
+ * One or more repetitions (`expr+`).
101
+ *
102
+ * @since 0.1.0
103
+ * @category combinators
104
+ */
105
+ const oneOrMore = (item) => make({
106
+ _tag: "Plus",
107
+ expr: toAST(item)
108
+ });
109
+ /**
110
+ * Zero or one occurrence (`expr?`).
111
+ *
112
+ * @since 0.1.0
113
+ * @category combinators
114
+ */
115
+ const optional = (item) => make({
116
+ _tag: "Opt",
117
+ expr: toAST(item)
118
+ });
119
+ /**
120
+ * Between `min` and `max` repetitions (`expr{min,max}`). When `max` is
121
+ * omitted it defaults to `min`; pass `Infinity` for no upper bound.
122
+ *
123
+ * @since 0.1.0
124
+ * @category combinators
125
+ */
126
+ const repeat = (item, min, max = min) => make({
127
+ _tag: "Range",
128
+ min,
129
+ max: max === Infinity ? -1 : max,
130
+ expr: toAST(item)
131
+ });
132
+ /**
133
+ * Parse a ProseMirror-style content expression string, such as
134
+ * `"paragraph block*"`. The referenced names are not tracked at the
135
+ * type level.
136
+ *
137
+ * Syntax errors throw a `SchemaDefinitionError` immediately; unknown names
138
+ * and other semantic errors are reported when the schema is compiled.
139
+ *
140
+ * @since 0.1.0
141
+ * @category constructors
142
+ */
143
+ const parse = (source) => {
144
+ const stream = new TokenStream(source);
145
+ if (stream.next === void 0) return make({
146
+ _tag: "Seq",
147
+ exprs: []
148
+ });
149
+ const expr = parseExpr(stream);
150
+ if (stream.next !== void 0) stream.err("Unexpected trailing text");
151
+ return make(expr);
152
+ };
153
+ /**
154
+ * Render a content expression in ProseMirror's string syntax.
155
+ *
156
+ * @since 0.1.0
157
+ * @category utils
158
+ */
159
+ const format = (expr) => formatAST(toAST(expr), 0);
160
+ const formatAST = (ast, prec) => Match.valueTags(ast, {
161
+ Name: (ast) => ast.name,
162
+ Choice: (ast) => {
163
+ const s = ast.exprs.map((e) => formatAST(e, 1)).join(" | ");
164
+ return prec > 0 ? `(${s})` : s;
165
+ },
166
+ Seq: (ast) => {
167
+ const s = ast.exprs.map((e) => formatAST(e, 2)).join(" ");
168
+ return prec > 1 ? `(${s})` : s;
169
+ },
170
+ Plus: (ast) => formatAST(ast.expr, 3) + "+",
171
+ Star: (ast) => formatAST(ast.expr, 3) + "*",
172
+ Opt: (ast) => formatAST(ast.expr, 3) + "?",
173
+ Range: (ast) => formatAST(ast.expr, 3) + "{" + ast.min + (ast.max === ast.min ? "" : "," + (ast.max < 0 ? "" : ast.max)) + "}"
174
+ });
175
+ const isEmptyAST = (ast) => Predicate.isTagged(ast, "Seq") && Arr.isReadonlyArrayEmpty(ast.exprs);
176
+ var TokenStream = class {
177
+ constructor(source) {
178
+ this.source = source;
179
+ this.pos = 0;
180
+ this.tokens = source.split(/\s*(?=\b|\W|$)/);
181
+ if (this.tokens[this.tokens.length - 1] === "") this.tokens.pop();
182
+ if (this.tokens[0] === "") this.tokens.shift();
183
+ }
184
+ get next() {
185
+ return this.tokens[this.pos];
186
+ }
187
+ eat(tok) {
188
+ if (this.next === tok) {
189
+ this.pos++;
190
+ return true;
191
+ }
192
+ return false;
193
+ }
194
+ err(str) {
195
+ throw new SchemaDefinitionError({ message: str + " (in content expression '" + this.source + "')" });
196
+ }
197
+ };
198
+ function parseExpr(stream) {
199
+ const exprs = [];
200
+ do
201
+ exprs.push(parseExprSeq(stream));
202
+ while (stream.eat("|"));
203
+ return exprs.length === 1 ? exprs[0] : {
204
+ _tag: "Choice",
205
+ exprs
206
+ };
207
+ }
208
+ function parseExprSeq(stream) {
209
+ const exprs = [];
210
+ do
211
+ exprs.push(parseExprSubscript(stream));
212
+ while (stream.next !== void 0 && stream.next !== ")" && stream.next !== "|");
213
+ return exprs.length === 1 ? exprs[0] : {
214
+ _tag: "Seq",
215
+ exprs
216
+ };
217
+ }
218
+ function parseExprSubscript(stream) {
219
+ let expr = parseExprAtom(stream);
220
+ for (;;) if (stream.eat("+")) expr = {
221
+ _tag: "Plus",
222
+ expr
223
+ };
224
+ else if (stream.eat("*")) expr = {
225
+ _tag: "Star",
226
+ expr
227
+ };
228
+ else if (stream.eat("?")) expr = {
229
+ _tag: "Opt",
230
+ expr
231
+ };
232
+ else if (stream.eat("{")) expr = parseExprRange(stream, expr);
233
+ else break;
234
+ return expr;
235
+ }
236
+ function parseNum(stream) {
237
+ const next = stream.next;
238
+ if (next === void 0 || /\D/.test(next)) stream.err("Expected number, got '" + next + "'");
239
+ stream.pos++;
240
+ return Number(next);
241
+ }
242
+ function parseExprRange(stream, expr) {
243
+ const min = parseNum(stream);
244
+ let max = min;
245
+ if (stream.eat(",")) {
246
+ if (stream.next !== "}") max = parseNum(stream);
247
+ else max = -1;
248
+ }
249
+ if (!stream.eat("}")) stream.err("Unclosed braced range");
250
+ return {
251
+ _tag: "Range",
252
+ min,
253
+ max,
254
+ expr
255
+ };
256
+ }
257
+ function parseExprAtom(stream) {
258
+ if (stream.eat("(")) {
259
+ const expr = parseExpr(stream);
260
+ if (!stream.eat(")")) stream.err("Missing closing paren");
261
+ return expr;
262
+ }
263
+ const next = stream.next;
264
+ if (next !== void 0 && !/\W/.test(next)) {
265
+ stream.pos++;
266
+ return {
267
+ _tag: "Name",
268
+ name: next
269
+ };
270
+ }
271
+ return stream.err("Unexpected token '" + next + "'");
272
+ }
273
+ /**
274
+ * Instances of this class represent a match state of a node type's
275
+ * content expression, and can be used to find out whether further
276
+ * content matches here, and whether a given position is a valid end of
277
+ * the node.
278
+ *
279
+ * @since 0.1.0
280
+ * @category models
281
+ */
282
+ var ContentMatch = class ContentMatch {
283
+ /** @internal */
284
+ constructor(validEnd) {
285
+ this.validEnd = validEnd;
286
+ this.next = [];
287
+ this.wrapCache = [];
288
+ }
289
+ /** @internal */
290
+ static compile(content, nodeTypes, typeName) {
291
+ if (content === void 0) return ContentMatch.empty;
292
+ const ast = Predicate.isString(content) ? parse(content).ast : content.ast;
293
+ if (isEmptyAST(ast)) return ContentMatch.empty;
294
+ const source = formatAST(ast, 0);
295
+ const match = dfa(nfa(resolve(ast, {
296
+ inline: null,
297
+ nodeTypes,
298
+ source,
299
+ typeName
300
+ })));
301
+ checkForDeadEnds(match, source);
302
+ return match;
303
+ }
304
+ /**
305
+ * Match a node type, returning a match after that node if
306
+ * successful.
307
+ */
308
+ matchType(type) {
309
+ return Option.fromNullishOr(this.matchTypeOrNull(type));
310
+ }
311
+ /** @internal */
312
+ matchTypeOrNull(type) {
313
+ for (let i = 0; i < this.next.length; i++) if (this.next[i].type === type) return this.next[i].next;
314
+ return null;
315
+ }
316
+ /** Try to match a fragment. Returns the resulting match when successful. */
317
+ matchFragment(frag, start = 0, end = frag.childCount) {
318
+ return Option.fromNullishOr(this.matchFragmentOrNull(frag, start, end));
319
+ }
320
+ /** @internal */
321
+ matchFragmentOrNull(frag, start = 0, end = frag.childCount) {
322
+ if (start >= end) return this;
323
+ let cur = this.matchTypeOrNull(frag.content[start].type);
324
+ for (let i = start + 1; cur && i < end; i++) cur = cur.matchTypeOrNull(frag.content[i].type);
325
+ return cur;
326
+ }
327
+ /** @internal */
328
+ get inlineContent() {
329
+ return Arr.isReadonlyArrayNonEmpty(this.next) && this.next[0].type.isInline;
330
+ }
331
+ /** Get the first matching node type at this match position that can be generated. */
332
+ get defaultType() {
333
+ return Option.fromNullishOr(this.defaultTypeOrNull);
334
+ }
335
+ /** @internal */
336
+ get defaultTypeOrNull() {
337
+ for (let i = 0; i < this.next.length; i++) {
338
+ const { type } = this.next[i];
339
+ if (!(type.isText || type.hasRequiredAttrs())) return type;
340
+ }
341
+ return null;
342
+ }
343
+ /** @internal */
344
+ compatible(other) {
345
+ for (let i = 0; i < this.next.length; i++) for (let j = 0; j < other.next.length; j++) if (this.next[i].type === other.next[j].type) return true;
346
+ return false;
347
+ }
348
+ /**
349
+ * Try to match the given fragment, and if that fails, see if it can
350
+ * be made to match by inserting nodes in front of it. When
351
+ * successful, return a fragment of inserted nodes (which may be
352
+ * empty if nothing had to be inserted). When `toEnd` is true, only
353
+ * return a fragment if the resulting match goes to the end of the
354
+ * content expression.
355
+ */
356
+ fillBefore(after, toEnd = false, startIndex = 0) {
357
+ return Option.fromNullishOr(this.fillBeforeOrNull(after, toEnd, startIndex));
358
+ }
359
+ /** @internal */
360
+ fillBeforeOrNull(after, toEnd = false, startIndex = 0) {
361
+ const seen = [this];
362
+ function search(match, types) {
363
+ const finished = match.matchFragmentOrNull(after, startIndex);
364
+ if (finished && (!toEnd || finished.validEnd)) return Fragment.fromArray(types.map((tp) => tp.createAndFillOrNull()));
365
+ for (let i = 0; i < match.next.length; i++) {
366
+ const { next, type } = match.next[i];
367
+ if (!(type.isText || type.hasRequiredAttrs()) && seen.indexOf(next) === -1) {
368
+ seen.push(next);
369
+ const found = search(next, types.concat(type));
370
+ if (found) return found;
371
+ }
372
+ }
373
+ return null;
374
+ }
375
+ return search(this, []);
376
+ }
377
+ /**
378
+ * Find a set of wrapping node types that would allow a node of the
379
+ * given type to appear at this position. The result may be empty
380
+ * (when it fits directly) and will be `None` when no such wrapping
381
+ * exists.
382
+ */
383
+ findWrapping(target) {
384
+ return Option.fromNullishOr(this.findWrappingOrNull(target));
385
+ }
386
+ /** @internal */
387
+ findWrappingOrNull(target) {
388
+ for (let i = 0; i < this.wrapCache.length; i += 2) if (this.wrapCache[i] === target) return this.wrapCache[i + 1];
389
+ const computed = this.computeWrapping(target);
390
+ this.wrapCache.push(target, computed);
391
+ return computed;
392
+ }
393
+ /** @internal */
394
+ computeWrapping(target) {
395
+ const seen = Object.create(null);
396
+ const active = [{
397
+ match: this,
398
+ type: null,
399
+ via: null
400
+ }];
401
+ while (active.length) {
402
+ const current = active.shift();
403
+ const match = current.match;
404
+ if (match.matchTypeOrNull(target)) {
405
+ const result = [];
406
+ for (let obj = current; obj.type; obj = obj.via) result.push(obj.type);
407
+ return result.reverse();
408
+ }
409
+ for (let i = 0; i < match.next.length; i++) {
410
+ const { next, type } = match.next[i];
411
+ if (!type.isLeaf && !type.hasRequiredAttrs() && !(type.name in seen) && (!current.type || next.validEnd)) {
412
+ active.push({
413
+ match: type.contentMatch,
414
+ type,
415
+ via: current
416
+ });
417
+ seen[type.name] = true;
418
+ }
419
+ }
420
+ }
421
+ return null;
422
+ }
423
+ /** The number of outgoing edges this node has in the content automaton. */
424
+ get edgeCount() {
425
+ return this.next.length;
426
+ }
427
+ /** Get the _n_th outgoing edge from this node in the content automaton. */
428
+ edge(n) {
429
+ return Option.fromNullishOr(this.next[n]);
430
+ }
431
+ /** @internal */
432
+ toString() {
433
+ const seen = [];
434
+ function scan(m) {
435
+ seen.push(m);
436
+ for (let i = 0; i < m.next.length; i++) if (seen.indexOf(m.next[i].next) === -1) scan(m.next[i].next);
437
+ }
438
+ scan(this);
439
+ return seen.map((m, i) => {
440
+ let out = i + (m.validEnd ? "*" : " ") + " ";
441
+ for (let i = 0; i < m.next.length; i++) out += (i ? ", " : "") + m.next[i].type.name + "->" + seen.indexOf(m.next[i].next);
442
+ return out;
443
+ }).join("\n");
444
+ }
445
+ static {
446
+ this.empty = new ContentMatch(true);
447
+ }
448
+ };
449
+ const fail = (ctx, message) => {
450
+ throw new SchemaDefinitionError({ message: `${message} (in content expression '${ctx.source}' of node type '${ctx.typeName}')` });
451
+ };
452
+ function resolveName(ctx, name) {
453
+ const types = ctx.nodeTypes;
454
+ const type = types[name];
455
+ if (type) return [type];
456
+ const result = [];
457
+ for (const typeName in types) {
458
+ const type = types[typeName];
459
+ if (type.isInGroup(name)) result.push(type);
460
+ }
461
+ if (Arr.isArrayEmpty(result)) fail(ctx, "No node type or group '" + name + "' found");
462
+ return result;
463
+ }
464
+ function resolve(ast, ctx) {
465
+ return Match.valueTags(ast, {
466
+ Name: (ast) => {
467
+ const exprs = resolveName(ctx, ast.name).map((type) => {
468
+ if (ctx.inline === null) ctx.inline = type.isInline;
469
+ else if (ctx.inline !== type.isInline) fail(ctx, "Mixing inline and block content");
470
+ return {
471
+ type: "name",
472
+ value: type
473
+ };
474
+ });
475
+ return exprs.length === 1 ? exprs[0] : {
476
+ type: "choice",
477
+ exprs
478
+ };
479
+ },
480
+ Choice: (ast) => ({
481
+ type: "choice",
482
+ exprs: ast.exprs.map((e) => resolve(e, ctx))
483
+ }),
484
+ Seq: (ast) => ({
485
+ type: "seq",
486
+ exprs: ast.exprs.map((e) => resolve(e, ctx))
487
+ }),
488
+ Plus: (ast) => ({
489
+ type: "plus",
490
+ expr: resolve(ast.expr, ctx)
491
+ }),
492
+ Star: (ast) => ({
493
+ type: "star",
494
+ expr: resolve(ast.expr, ctx)
495
+ }),
496
+ Opt: (ast) => ({
497
+ type: "opt",
498
+ expr: resolve(ast.expr, ctx)
499
+ }),
500
+ Range: (ast) => {
501
+ if (ast.min < 0 || ast.max >= 0 && ast.max < ast.min || !Number.isInteger(ast.min)) fail(ctx, `Invalid repetition range {${ast.min},${ast.max}}`);
502
+ return {
503
+ type: "range",
504
+ min: ast.min,
505
+ max: ast.max,
506
+ expr: resolve(ast.expr, ctx)
507
+ };
508
+ }
509
+ });
510
+ }
511
+ function nfa(expr) {
512
+ const nfa = [[]];
513
+ connect(compile(expr, 0), node());
514
+ return nfa;
515
+ function node() {
516
+ return nfa.push([]) - 1;
517
+ }
518
+ function edge(from, to, term) {
519
+ const edge = {
520
+ term,
521
+ to
522
+ };
523
+ nfa[from].push(edge);
524
+ return edge;
525
+ }
526
+ function connect(edges, to) {
527
+ edges.forEach((edge) => edge.to = to);
528
+ }
529
+ function compile(expr, from) {
530
+ return Match.value(expr).pipe(Match.discriminatorsExhaustive("type")({
531
+ choice: (expr) => expr.exprs.reduce((out, expr) => out.concat(compile(expr, from)), []),
532
+ seq: (expr) => {
533
+ if (Arr.isReadonlyArrayEmpty(expr.exprs)) return [edge(from)];
534
+ let cur = from;
535
+ for (let i = 0;; i++) {
536
+ const next = compile(expr.exprs[i], cur);
537
+ if (i === expr.exprs.length - 1) return next;
538
+ connect(next, cur = node());
539
+ }
540
+ },
541
+ star: (expr) => {
542
+ const loop = node();
543
+ edge(from, loop);
544
+ connect(compile(expr.expr, loop), loop);
545
+ return [edge(loop)];
546
+ },
547
+ plus: (expr) => {
548
+ const loop = node();
549
+ connect(compile(expr.expr, from), loop);
550
+ connect(compile(expr.expr, loop), loop);
551
+ return [edge(loop)];
552
+ },
553
+ opt: (expr) => [edge(from)].concat(compile(expr.expr, from)),
554
+ range: (expr) => {
555
+ let cur = from;
556
+ for (let i = 0; i < expr.min; i++) {
557
+ const next = node();
558
+ connect(compile(expr.expr, cur), next);
559
+ cur = next;
560
+ }
561
+ if (expr.max === -1) connect(compile(expr.expr, cur), cur);
562
+ else for (let i = expr.min; i < expr.max; i++) {
563
+ const next = node();
564
+ edge(cur, next);
565
+ connect(compile(expr.expr, cur), next);
566
+ cur = next;
567
+ }
568
+ return [edge(cur)];
569
+ },
570
+ name: (expr) => [edge(from, void 0, expr.value)]
571
+ }));
572
+ }
573
+ }
574
+ const descending = Order.flip(Order.Number);
575
+ function nullFrom(nfa, node) {
576
+ const result = [];
577
+ scan(node);
578
+ return Arr.sort(result, descending);
579
+ function scan(node) {
580
+ const edges = nfa[node];
581
+ if (edges.length === 1 && !edges[0].term) return scan(edges[0].to);
582
+ result.push(node);
583
+ for (let i = 0; i < edges.length; i++) {
584
+ const { term, to } = edges[i];
585
+ if (!term && result.indexOf(to) === -1) scan(to);
586
+ }
587
+ }
588
+ }
589
+ function dfa(nfa) {
590
+ const labeled = Object.create(null);
591
+ return explore(nullFrom(nfa, 0));
592
+ function explore(states) {
593
+ const out = [];
594
+ states.forEach((node) => {
595
+ nfa[node].forEach(({ term, to }) => {
596
+ if (!term) return;
597
+ let set;
598
+ for (let i = 0; i < out.length; i++) if (out[i][0] === term) set = out[i][1];
599
+ nullFrom(nfa, to).forEach((node) => {
600
+ if (!set) out.push([term, set = []]);
601
+ if (set.indexOf(node) === -1) set.push(node);
602
+ });
603
+ });
604
+ });
605
+ const state = labeled[states.join(",")] = new ContentMatch(states.indexOf(nfa.length - 1) > -1);
606
+ for (let i = 0; i < out.length; i++) {
607
+ const states = Arr.sort(out[i][1], descending);
608
+ state.next.push({
609
+ type: out[i][0],
610
+ next: labeled[states.join(",")] || explore(states)
611
+ });
612
+ }
613
+ return state;
614
+ }
615
+ }
616
+ function checkForDeadEnds(match, source) {
617
+ for (let i = 0, work = [match]; i < work.length; i++) {
618
+ const state = work[i];
619
+ let dead = !state.validEnd;
620
+ const nodes = [];
621
+ for (let j = 0; j < state.next.length; j++) {
622
+ const { next, type } = state.next[j];
623
+ nodes.push(type.name);
624
+ if (dead && !(type.isText || type.hasRequiredAttrs())) dead = false;
625
+ if (work.indexOf(next) === -1) work.push(next);
626
+ }
627
+ if (dead) throw new SchemaDefinitionError({ message: "Only non-generatable nodes (" + nodes.join(", ") + ") in a required position (see https://prosemirror.net/docs/guide/#generatable) (in content expression '" + source + "')" });
628
+ }
629
+ }
630
+ export { ContentMatch, choice, content_exports, format, isContentExpr, oneOrMore, optional, parse, ref, repeat, seq, zeroOrMore };
@@ -0,0 +1,66 @@
1
+ // src/model/diff.ts
2
+ /** @internal */
3
+ function findDiffStart(a, b, pos) {
4
+ for (let i = 0;; i++) {
5
+ if (i === a.childCount || i === b.childCount) return a.childCount === b.childCount ? null : pos;
6
+ const childA = a.content[i], childB = b.content[i];
7
+ if (childA === childB) {
8
+ pos += childA.nodeSize;
9
+ continue;
10
+ }
11
+ if (!childA.sameMarkup(childB)) return pos;
12
+ if (childA.isText && childA.text !== childB.text) return pos + sameTextStart(childA.text, childB.text);
13
+ if (childA.content.size || childB.content.size) {
14
+ const inner = findDiffStart(childA.content, childB.content, pos + 1);
15
+ if (inner != null) return inner;
16
+ }
17
+ pos += childA.nodeSize;
18
+ }
19
+ }
20
+ /** @internal */
21
+ function findDiffEnd(a, b, posA, posB) {
22
+ for (let iA = a.childCount, iB = b.childCount;;) {
23
+ if (iA === 0 || iB === 0) return iA === iB ? null : {
24
+ a: posA,
25
+ b: posB
26
+ };
27
+ const childA = a.content[--iA], childB = b.content[--iB], size = childA.nodeSize;
28
+ if (childA === childB) {
29
+ posA -= size;
30
+ posB -= size;
31
+ continue;
32
+ }
33
+ if (!childA.sameMarkup(childB)) return {
34
+ a: posA,
35
+ b: posB
36
+ };
37
+ if (childA.isText && childA.text !== childB.text) {
38
+ const same = sameTextEnd(childA.text, childB.text);
39
+ return {
40
+ a: posA - same,
41
+ b: posB - same
42
+ };
43
+ }
44
+ if (childA.content.size || childB.content.size) {
45
+ const inner = findDiffEnd(childA.content, childB.content, posA - 1, posB - 1);
46
+ if (inner) return inner;
47
+ }
48
+ posA -= size;
49
+ posB -= size;
50
+ }
51
+ }
52
+ function sameTextStart(ta, tb) {
53
+ let j = 0;
54
+ while (ta[j] === tb[j]) j++;
55
+ return j && j < ta.length && j < tb.length && splitsPair(ta, j) ? j - 1 : j;
56
+ }
57
+ function sameTextEnd(ta, tb) {
58
+ let same = 0;
59
+ while (same < ta.length && same < tb.length && ta[ta.length - same - 1] === tb[tb.length - same - 1]) same++;
60
+ const end = ta.length - same;
61
+ return end && same && same < tb.length && splitsPair(ta, end) ? same - 1 : same;
62
+ }
63
+ const splitsPair = (text, i) => surrogateHigh(text.charCodeAt(i - 1)) && surrogateLow(text.charCodeAt(i));
64
+ const surrogateLow = (ch) => ch >= 56320 && ch < 57344;
65
+ const surrogateHigh = (ch) => ch >= 55296 && ch < 56320;
66
+ export { findDiffEnd, findDiffStart };
@@ -0,0 +1,3 @@
1
+ import { ParseRule, TagParseRule } from "./from_dom.js";
2
+ import { DOMOutputSpec } from "./to_dom.js";
3
+ export type { DOMOutputSpec, ParseRule, TagParseRule };