@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,90 @@
1
+ import * as Schema from "effect/Schema";
2
+ declare const PositionError_base: Schema.Class<PositionError, Schema.TaggedStruct<"PositionError", {
3
+ readonly message: Schema.String;
4
+ }>, import("effect/Cause").YieldableError>;
5
+ /**
6
+ * A position or index was outside of the valid range of a node or
7
+ * fragment.
8
+ *
9
+ * @since 0.1.0
10
+ * @category errors
11
+ */
12
+ export declare class PositionError extends PositionError_base {}
13
+ declare const ReplaceError_base: Schema.Class<ReplaceError, Schema.TaggedStruct<"ReplaceError", {
14
+ readonly message: Schema.String;
15
+ }>, import("effect/Cause").YieldableError>;
16
+ /**
17
+ * Raised when a [`Slice`](#Slice) cannot be fitted into a document,
18
+ * typically by `Node.replace`.
19
+ *
20
+ * @since 0.1.0
21
+ * @category errors
22
+ */
23
+ export declare class ReplaceError extends ReplaceError_base {}
24
+ declare const ContentError_base: Schema.Class<ContentError, Schema.TaggedStruct<"ContentError", {
25
+ readonly message: Schema.String;
26
+ }>, import("effect/Cause").YieldableError>;
27
+ /**
28
+ * Content that does not satisfy a node type's content expression or
29
+ * mark restrictions.
30
+ *
31
+ * @since 0.1.0
32
+ * @category errors
33
+ */
34
+ export declare class ContentError extends ContentError_base {}
35
+ declare const AttributeError_base: Schema.Class<AttributeError, Schema.TaggedStruct<"AttributeError", {
36
+ readonly message: Schema.String;
37
+ }>, import("effect/Cause").YieldableError>;
38
+ /**
39
+ * Missing, unknown, or invalid node or mark attributes.
40
+ *
41
+ * @since 0.1.0
42
+ * @category errors
43
+ */
44
+ export declare class AttributeError extends AttributeError_base {}
45
+ declare const SchemaDefinitionError_base: Schema.Class<SchemaDefinitionError, Schema.TaggedStruct<"SchemaDefinitionError", {
46
+ readonly message: Schema.String;
47
+ }>, import("effect/Cause").YieldableError>;
48
+ /**
49
+ * A schema definition (or a content expression in it) is invalid.
50
+ *
51
+ * @since 0.1.0
52
+ * @category errors
53
+ */
54
+ export declare class SchemaDefinitionError extends SchemaDefinitionError_base {}
55
+ declare const JSONError_base: Schema.Class<JSONError, Schema.TaggedStruct<"JSONError", {
56
+ readonly message: Schema.String;
57
+ }>, import("effect/Cause").YieldableError>;
58
+ /**
59
+ * Raised when deserializing JSON that does not describe a valid
60
+ * document structure for the schema.
61
+ *
62
+ * @since 0.1.0
63
+ * @category errors
64
+ */
65
+ export declare class JSONError extends JSONError_base {}
66
+ declare const DOMSpecError_base: Schema.Class<DOMSpecError, Schema.TaggedStruct<"DOMSpecError", {
67
+ readonly message: Schema.String;
68
+ }>, import("effect/Cause").YieldableError>;
69
+ /**
70
+ * An invalid [`DOMOutputSpec`](#DOMOutputSpec) was passed to the DOM
71
+ * serializer (for example a misplaced content hole, or an array taken
72
+ * from an attribute value).
73
+ *
74
+ * @since 0.1.0
75
+ * @category errors
76
+ */
77
+ export declare class DOMSpecError extends DOMSpecError_base {}
78
+ /**
79
+ * Union of all errors produced by the model.
80
+ *
81
+ * @since 0.1.0
82
+ * @category errors
83
+ */
84
+ export type ModelError = PositionError | ReplaceError | ContentError | AttributeError | SchemaDefinitionError | JSONError | DOMSpecError;
85
+ /**
86
+ * @since 0.1.0
87
+ * @category guards
88
+ */
89
+ export declare const isModelError: (u: unknown) => u is ModelError;
90
+ export {};
@@ -0,0 +1,76 @@
1
+ import * as Predicate from "effect/Predicate";
2
+ import * as HashSet from "effect/HashSet";
3
+ import * as Schema from "effect/Schema";
4
+ // src/model/errors.ts
5
+ /**
6
+ * Tagged errors raised by the document model.
7
+ *
8
+ * Every fallible operation in `@thomasfosterau/effect-richtext/model` reports failure
9
+ * through the Effect error channel using one of these errors. The
10
+ * `*Unsafe` variants of those operations throw the same error values
11
+ * instead, which makes them usable from synchronous code.
12
+ *
13
+ * @since 0.1.0
14
+ */
15
+ /**
16
+ * A position or index was outside of the valid range of a node or
17
+ * fragment.
18
+ *
19
+ * @since 0.1.0
20
+ * @category errors
21
+ */
22
+ var PositionError = class extends Schema.TaggedError()("PositionError", { message: Schema.String }) {};
23
+ /**
24
+ * Raised when a [`Slice`](#Slice) cannot be fitted into a document,
25
+ * typically by `Node.replace`.
26
+ *
27
+ * @since 0.1.0
28
+ * @category errors
29
+ */
30
+ var ReplaceError = class extends Schema.TaggedError()("ReplaceError", { message: Schema.String }) {};
31
+ /**
32
+ * Content that does not satisfy a node type's content expression or
33
+ * mark restrictions.
34
+ *
35
+ * @since 0.1.0
36
+ * @category errors
37
+ */
38
+ var ContentError = class extends Schema.TaggedError()("ContentError", { message: Schema.String }) {};
39
+ /**
40
+ * Missing, unknown, or invalid node or mark attributes.
41
+ *
42
+ * @since 0.1.0
43
+ * @category errors
44
+ */
45
+ var AttributeError = class extends Schema.TaggedError()("AttributeError", { message: Schema.String }) {};
46
+ /**
47
+ * A schema definition (or a content expression in it) is invalid.
48
+ *
49
+ * @since 0.1.0
50
+ * @category errors
51
+ */
52
+ var SchemaDefinitionError = class extends Schema.TaggedError()("SchemaDefinitionError", { message: Schema.String }) {};
53
+ /**
54
+ * Raised when deserializing JSON that does not describe a valid
55
+ * document structure for the schema.
56
+ *
57
+ * @since 0.1.0
58
+ * @category errors
59
+ */
60
+ var JSONError = class extends Schema.TaggedError()("JSONError", { message: Schema.String }) {};
61
+ /**
62
+ * An invalid [`DOMOutputSpec`](#DOMOutputSpec) was passed to the DOM
63
+ * serializer (for example a misplaced content hole, or an array taken
64
+ * from an attribute value).
65
+ *
66
+ * @since 0.1.0
67
+ * @category errors
68
+ */
69
+ var DOMSpecError = class extends Schema.TaggedError()("DOMSpecError", { message: Schema.String }) {};
70
+ const modelErrorTags = HashSet.make("PositionError", "ReplaceError", "ContentError", "AttributeError", "SchemaDefinitionError", "JSONError", "DOMSpecError");
71
+ /**
72
+ * @since 0.1.0
73
+ * @category guards
74
+ */
75
+ const isModelError = (u) => Predicate.isObjectOrArray(u) && HashSet.has(modelErrorTags, u._tag);
76
+ export { AttributeError, ContentError, DOMSpecError, JSONError, PositionError, ReplaceError, SchemaDefinitionError, isModelError };
@@ -0,0 +1,131 @@
1
+ import { PositionError } from "./errors.js";
2
+ import { Node, NodeJSON } from "./node.js";
3
+ import { AnySchema, NodeNames } from "./schema.js";
4
+ import * as Effect from "effect/Effect";
5
+ import * as Option from "effect/Option";
6
+ import * as Equal from "effect/Equal";
7
+ import * as Hash from "effect/Hash";
8
+ /**
9
+ * Callback used by `nodesBetween` and `descendants`. Return `false` to
10
+ * prevent descending into a node.
11
+ *
12
+ * @since 0.1.0
13
+ * @category models
14
+ */
15
+ export type NodeVisitor<Sc extends AnySchema = AnySchema> = (node: Node<Sc>, pos: number, parent: Option.Option<Node<Sc>>, index: number) => boolean | void;
16
+ /**
17
+ * A fragment represents a node's collection of child nodes.
18
+ *
19
+ * Like nodes, fragments are persistent data structures, and you should
20
+ * not mutate them or their content. Rather, you create new instances
21
+ * whenever needed.
22
+ *
23
+ * Fragments implement `Equal` (structural equality) and are iterable.
24
+ *
25
+ * @since 0.1.0
26
+ * @category models
27
+ */
28
+ export declare class Fragment<Sc extends AnySchema = AnySchema, out N extends NodeNames<Sc> = NodeNames<Sc>> implements Equal.Equal, Iterable<Node<Sc, N>> {
29
+ /** The child nodes in this fragment. */
30
+ readonly content: ReadonlyArray<Node<Sc, N>>;
31
+ /** The size of the fragment, which is the total of the size of its content nodes. */
32
+ readonly size: number;
33
+ /** @internal */
34
+ constructor(
35
+ /** The child nodes in this fragment. */
36
+ content: ReadonlyArray<Node<Sc, N>>, size?: number);
37
+ [Symbol.iterator](): Iterator<Node<Sc, N>>;
38
+ /**
39
+ * Invoke a callback for all descendant nodes between the given two
40
+ * positions (relative to start of this fragment). Doesn't descend
41
+ * into a node when the callback returns `false`.
42
+ */
43
+ nodesBetween(from: number, to: number, f: NodeVisitor<Sc>, nodeStart?: number, parent?: Node<Sc>): void;
44
+ /**
45
+ * Call the given callback for every descendant node. `pos` will be
46
+ * relative to the start of the fragment. The callback may return
47
+ * `false` to prevent traversal of a given node's children.
48
+ */
49
+ descendants(f: NodeVisitor<Sc>): void;
50
+ /** Extract the text between `from` and `to`. See `Node.textBetween`. */
51
+ textBetween(from: number, to: number, blockSeparator?: string | null, leafText?: string | null | ((leafNode: Node<Sc>) => string)): string;
52
+ /** Create a new fragment containing the combined content of this fragment and the other. */
53
+ append<N2 extends NodeNames<Sc>>(other: Fragment<Sc, N2>): Fragment<Sc, N | N2>;
54
+ /** Cut out the sub-fragment between the two given positions. */
55
+ cut(from: number, to?: number): Fragment<Sc, N>;
56
+ /** @internal */
57
+ cutByIndex(from: number, to: number): Fragment<Sc, N>;
58
+ /** Create a new fragment in which the node at the given index is replaced by the given node. */
59
+ replaceChild<N2 extends NodeNames<Sc>>(index: number, node: Node<Sc, N2>): Fragment<Sc, N | N2>;
60
+ /** Create a new fragment by prepending the given node to this fragment. */
61
+ addToStart<N2 extends NodeNames<Sc>>(node: Node<Sc, N2>): Fragment<Sc, N | N2>;
62
+ /** Create a new fragment by appending the given node to this fragment. */
63
+ addToEnd<N2 extends NodeNames<Sc>>(node: Node<Sc, N2>): Fragment<Sc, N | N2>;
64
+ /** Compare this fragment to another one. */
65
+ eq(other: Fragment<any, any>): boolean;
66
+ /** @internal */
67
+ [Equal.symbol](that: Equal.Equal): boolean;
68
+ /** @internal */
69
+ [Hash.symbol](): number;
70
+ /** The first child of the fragment, if any. */
71
+ get firstChild(): Option.Option<Node<Sc, N>>;
72
+ /** The last child of the fragment, if any. */
73
+ get lastChild(): Option.Option<Node<Sc, N>>;
74
+ /** The number of child nodes in this fragment. */
75
+ get childCount(): number;
76
+ /** Get the child node at the given index. Fails with a `PositionError` when the index is out of range. */
77
+ child(index: number): Effect.Effect<Node<Sc, N>, PositionError>;
78
+ /** Like `child`, but throws a `PositionError` when the index is out of range. */
79
+ childUnsafe(index: number): Node<Sc, N>;
80
+ /** Get the child node at the given index, if it exists. */
81
+ maybeChild(index: number): Option.Option<Node<Sc, N>>;
82
+ /** Call `f` for every child node, passing the node, its offset into this parent node, and its index. */
83
+ forEach(f: (node: Node<Sc, N>, offset: number, index: number) => void): void;
84
+ /** Find the first position at which this fragment and another fragment differ, if any. */
85
+ findDiffStart(other: Fragment<any, any>, pos?: number): Option.Option<number>;
86
+ /**
87
+ * Find the first position, searching from the end, at which this
88
+ * fragment and the given fragment differ, if any. Since this
89
+ * position will not be the same in both nodes, an object with two
90
+ * separate positions is returned.
91
+ */
92
+ findDiffEnd(other: Fragment<any, any>, pos?: number, otherPos?: number): Option.Option<{
93
+ readonly a: number;
94
+ readonly b: number;
95
+ }>;
96
+ /**
97
+ * Find the index and inner offset corresponding to a given relative
98
+ * position in this fragment. The result object will be reused
99
+ * (overwritten) the next time the function is called.
100
+ *
101
+ * @internal
102
+ */
103
+ findIndex(pos: number): {
104
+ index: number;
105
+ offset: number;
106
+ };
107
+ /** Return a debugging string that describes this fragment. */
108
+ toString(): string;
109
+ /** @internal */
110
+ toStringInner(): string;
111
+ /** Create a JSON-serializable representation of this fragment. */
112
+ toJSON(): ReadonlyArray<NodeJSON> | null;
113
+ /**
114
+ * Build a fragment from an array of nodes. Ensures that adjacent text
115
+ * nodes with the same marks are joined together.
116
+ */
117
+ static fromArray<Sc extends AnySchema, N extends NodeNames<Sc>>(array: ReadonlyArray<Node<Sc, N>>): Fragment<Sc, N>;
118
+ /**
119
+ * Create a fragment from something that can be interpreted as a set
120
+ * of nodes. For `null`/`undefined`, it returns the empty fragment.
121
+ * For a fragment, the fragment itself. For a node or array of nodes,
122
+ * a fragment containing those nodes.
123
+ */
124
+ static from<Sc extends AnySchema, N extends NodeNames<Sc>>(nodes?: Fragment<Sc, N> | Node<Sc, N> | ReadonlyArray<Node<Sc, N>> | null): Fragment<Sc, N>;
125
+ /**
126
+ * An empty fragment. Intended to be reused whenever a node doesn't
127
+ * contain anything (rather than allocating a new empty fragment for
128
+ * each leaf node).
129
+ */
130
+ static readonly empty: Fragment<any, any>;
131
+ }
@@ -0,0 +1,262 @@
1
+ import { attempt } from "../internal/attempt.js";
2
+ import { findDiffEnd, findDiffStart } from "./diff.js";
3
+ import { PositionError } from "./errors.js";
4
+ import * as Option from "effect/Option";
5
+ import * as Equal from "effect/Equal";
6
+ import * as Hash from "effect/Hash";
7
+ // src/model/fragment.ts
8
+ const isPositionError = (u) => u instanceof PositionError;
9
+ /**
10
+ * A fragment represents a node's collection of child nodes.
11
+ *
12
+ * Like nodes, fragments are persistent data structures, and you should
13
+ * not mutate them or their content. Rather, you create new instances
14
+ * whenever needed.
15
+ *
16
+ * Fragments implement `Equal` (structural equality) and are iterable.
17
+ *
18
+ * @since 0.1.0
19
+ * @category models
20
+ */
21
+ var Fragment = class Fragment {
22
+ /** @internal */
23
+ constructor(content, size) {
24
+ this.content = content;
25
+ this.size = size || 0;
26
+ if (size == null) for (let i = 0; i < content.length; i++) this.size += content[i].nodeSize;
27
+ }
28
+ [Symbol.iterator]() {
29
+ return this.content[Symbol.iterator]();
30
+ }
31
+ /**
32
+ * Invoke a callback for all descendant nodes between the given two
33
+ * positions (relative to start of this fragment). Doesn't descend
34
+ * into a node when the callback returns `false`.
35
+ */
36
+ nodesBetween(from, to, f, nodeStart = 0, parent) {
37
+ const parentOption = parent ? Option.some(parent) : Option.none();
38
+ for (let i = 0, pos = 0; pos < to; i++) {
39
+ const child = this.content[i], end = pos + child.nodeSize;
40
+ if (end > from && f(child, nodeStart + pos, parentOption, i) !== false && child.content.size) {
41
+ const start = pos + 1;
42
+ child.nodesBetween(Math.max(0, from - start), Math.min(child.content.size, to - start), f, nodeStart + start);
43
+ }
44
+ pos = end;
45
+ }
46
+ }
47
+ /**
48
+ * Call the given callback for every descendant node. `pos` will be
49
+ * relative to the start of the fragment. The callback may return
50
+ * `false` to prevent traversal of a given node's children.
51
+ */
52
+ descendants(f) {
53
+ this.nodesBetween(0, this.size, f);
54
+ }
55
+ /** Extract the text between `from` and `to`. See `Node.textBetween`. */
56
+ textBetween(from, to, blockSeparator, leafText) {
57
+ let text = "", first = true;
58
+ this.nodesBetween(from, to, (node, pos) => {
59
+ const nodeText = node.isText ? node.text.slice(Math.max(from, pos) - pos, to - pos) : !node.isLeaf ? "" : leafText ? typeof leafText === "function" ? leafText(node) : leafText : node.type.spec.leafText ? node.type.spec.leafText(node) : "";
60
+ if (node.isBlock && (node.isLeaf && nodeText || node.isTextblock) && blockSeparator) {
61
+ if (first) first = false;
62
+ else text += blockSeparator;
63
+ }
64
+ text += nodeText;
65
+ }, 0);
66
+ return text;
67
+ }
68
+ /** Create a new fragment containing the combined content of this fragment and the other. */
69
+ append(other) {
70
+ if (!other.size) return this;
71
+ if (!this.size) return other;
72
+ const last = this.content[this.content.length - 1], first = other.content[0];
73
+ const content = this.content.slice();
74
+ let i = 0;
75
+ if (last.isText && last.sameMarkup(first)) {
76
+ content[content.length - 1] = last.withText(last.text + first.text);
77
+ i = 1;
78
+ }
79
+ for (; i < other.content.length; i++) content.push(other.content[i]);
80
+ return new Fragment(content, this.size + other.size);
81
+ }
82
+ /** Cut out the sub-fragment between the two given positions. */
83
+ cut(from, to = this.size) {
84
+ if (from === 0 && to === this.size) return this;
85
+ const result = [];
86
+ let size = 0;
87
+ if (to > from) for (let i = 0, pos = 0; pos < to; i++) {
88
+ let child = this.content[i];
89
+ const end = pos + child.nodeSize;
90
+ if (end > from) {
91
+ if (pos < from || end > to) {
92
+ if (child.isText) child = child.cut(Math.max(0, from - pos), Math.min(child.text.length, to - pos));
93
+ else child = child.cut(Math.max(0, from - pos - 1), Math.min(child.content.size, to - pos - 1));
94
+ }
95
+ result.push(child);
96
+ size += child.nodeSize;
97
+ }
98
+ pos = end;
99
+ }
100
+ return new Fragment(result, size);
101
+ }
102
+ /** @internal */
103
+ cutByIndex(from, to) {
104
+ if (from === to) return Fragment.empty;
105
+ if (from === 0 && to === this.content.length) return this;
106
+ return new Fragment(this.content.slice(from, to));
107
+ }
108
+ /** Create a new fragment in which the node at the given index is replaced by the given node. */
109
+ replaceChild(index, node) {
110
+ const current = this.content[index];
111
+ if (current === node) return this;
112
+ const copy = this.content.slice();
113
+ const size = this.size + node.nodeSize - current.nodeSize;
114
+ copy[index] = node;
115
+ return new Fragment(copy, size);
116
+ }
117
+ /** Create a new fragment by prepending the given node to this fragment. */
118
+ addToStart(node) {
119
+ return new Fragment([node].concat(this.content), this.size + node.nodeSize);
120
+ }
121
+ /** Create a new fragment by appending the given node to this fragment. */
122
+ addToEnd(node) {
123
+ return new Fragment(this.content.concat(node), this.size + node.nodeSize);
124
+ }
125
+ /** Compare this fragment to another one. */
126
+ eq(other) {
127
+ if (this.content.length !== other.content.length) return false;
128
+ for (let i = 0; i < this.content.length; i++) if (!this.content[i].eq(other.content[i])) return false;
129
+ return true;
130
+ }
131
+ /** @internal */
132
+ [Equal.symbol](that) {
133
+ return that instanceof Fragment && this.eq(that);
134
+ }
135
+ /** @internal */
136
+ [Hash.symbol]() {
137
+ return Hash.array(this.content);
138
+ }
139
+ /** The first child of the fragment, if any. */
140
+ get firstChild() {
141
+ return Option.fromUndefinedOr(this.content[0]);
142
+ }
143
+ /** The last child of the fragment, if any. */
144
+ get lastChild() {
145
+ return Option.fromUndefinedOr(this.content[this.content.length - 1]);
146
+ }
147
+ /** The number of child nodes in this fragment. */
148
+ get childCount() {
149
+ return this.content.length;
150
+ }
151
+ /** Get the child node at the given index. Fails with a `PositionError` when the index is out of range. */
152
+ child(index) {
153
+ return attempt(() => this.childUnsafe(index), isPositionError);
154
+ }
155
+ /** Like `child`, but throws a `PositionError` when the index is out of range. */
156
+ childUnsafe(index) {
157
+ const found = this.content[index];
158
+ if (!found) throw new PositionError({ message: "Index " + index + " out of range for " + this });
159
+ return found;
160
+ }
161
+ /** Get the child node at the given index, if it exists. */
162
+ maybeChild(index) {
163
+ return Option.fromUndefinedOr(this.content[index]);
164
+ }
165
+ /** Call `f` for every child node, passing the node, its offset into this parent node, and its index. */
166
+ forEach(f) {
167
+ for (let i = 0, p = 0; i < this.content.length; i++) {
168
+ const child = this.content[i];
169
+ f(child, p, i);
170
+ p += child.nodeSize;
171
+ }
172
+ }
173
+ /** Find the first position at which this fragment and another fragment differ, if any. */
174
+ findDiffStart(other, pos = 0) {
175
+ return Option.fromNullishOr(findDiffStart(this, other, pos));
176
+ }
177
+ /**
178
+ * Find the first position, searching from the end, at which this
179
+ * fragment and the given fragment differ, if any. Since this
180
+ * position will not be the same in both nodes, an object with two
181
+ * separate positions is returned.
182
+ */
183
+ findDiffEnd(other, pos = this.size, otherPos = other.size) {
184
+ return Option.fromNullishOr(findDiffEnd(this, other, pos, otherPos));
185
+ }
186
+ /**
187
+ * Find the index and inner offset corresponding to a given relative
188
+ * position in this fragment. The result object will be reused
189
+ * (overwritten) the next time the function is called.
190
+ *
191
+ * @internal
192
+ */
193
+ findIndex(pos) {
194
+ if (pos === 0) return retIndex(0, pos);
195
+ if (pos === this.size) return retIndex(this.content.length, pos);
196
+ if (pos > this.size || pos < 0) throw new PositionError({ message: `Position ${pos} outside of fragment (${this.toString()})` });
197
+ for (let i = 0, curPos = 0;; i++) {
198
+ const cur = this.content[i], end = curPos + cur.nodeSize;
199
+ if (end >= pos) {
200
+ if (end === pos) return retIndex(i + 1, end);
201
+ return retIndex(i, curPos);
202
+ }
203
+ curPos = end;
204
+ }
205
+ }
206
+ /** Return a debugging string that describes this fragment. */
207
+ toString() {
208
+ return "<" + this.toStringInner() + ">";
209
+ }
210
+ /** @internal */
211
+ toStringInner() {
212
+ return this.content.join(", ");
213
+ }
214
+ /** Create a JSON-serializable representation of this fragment. */
215
+ toJSON() {
216
+ return this.content.length ? this.content.map((n) => n.toJSON()) : null;
217
+ }
218
+ /**
219
+ * Build a fragment from an array of nodes. Ensures that adjacent text
220
+ * nodes with the same marks are joined together.
221
+ */
222
+ static fromArray(array) {
223
+ if (!array.length) return Fragment.empty;
224
+ let joined;
225
+ let size = 0;
226
+ for (let i = 0; i < array.length; i++) {
227
+ const node = array[i];
228
+ size += node.nodeSize;
229
+ if (i && node.isText && array[i - 1].sameMarkup(node)) {
230
+ if (!joined) joined = array.slice(0, i);
231
+ joined[joined.length - 1] = node.withText(joined[joined.length - 1].text + node.text);
232
+ } else if (joined) joined.push(node);
233
+ }
234
+ return new Fragment(joined || array, size);
235
+ }
236
+ /**
237
+ * Create a fragment from something that can be interpreted as a set
238
+ * of nodes. For `null`/`undefined`, it returns the empty fragment.
239
+ * For a fragment, the fragment itself. For a node or array of nodes,
240
+ * a fragment containing those nodes.
241
+ */
242
+ static from(nodes) {
243
+ if (!nodes) return Fragment.empty;
244
+ if (nodes instanceof Fragment) return nodes;
245
+ if (Array.isArray(nodes)) return this.fromArray(nodes);
246
+ if (nodes.attrs) return new Fragment([nodes], nodes.nodeSize);
247
+ throw new PositionError({ message: "Can not convert " + nodes + " to a Fragment" });
248
+ }
249
+ static {
250
+ this.empty = new Fragment([], 0);
251
+ }
252
+ };
253
+ const found = {
254
+ index: 0,
255
+ offset: 0
256
+ };
257
+ function retIndex(index, offset) {
258
+ found.index = index;
259
+ found.offset = offset;
260
+ return found;
261
+ }
262
+ export { Fragment };