@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.
- package/LICENSE +48 -0
- package/README.md +117 -1
- package/dist/_virtual/_rolldown/runtime.js +12 -0
- package/dist/commands/commands.d.ts +323 -0
- package/dist/commands/commands.js +722 -0
- package/dist/commands/internal.js +43 -0
- package/dist/commands/keymaps.d.ts +46 -0
- package/dist/commands/keymaps.js +64 -0
- package/dist/commands.d.ts +3 -0
- package/dist/commands.js +3 -0
- package/dist/compat/commands.d.ts +250 -0
- package/dist/compat/commands.js +275 -0
- package/dist/compat/internal/core.d.ts +20 -0
- package/dist/compat/internal/core.js +148 -0
- package/dist/compat/internal/props.js +82 -0
- package/dist/compat/keymap.d.ts +21 -0
- package/dist/compat/keymap.js +38 -0
- package/dist/compat/model.d.ts +893 -0
- package/dist/compat/model.js +1212 -0
- package/dist/compat/orderedmap.d.ts +74 -0
- package/dist/compat/orderedmap.js +124 -0
- package/dist/compat/schema-basic.d.ts +38 -0
- package/dist/compat/schema-basic.js +238 -0
- package/dist/compat/schema-list.d.ts +81 -0
- package/dist/compat/schema-list.js +156 -0
- package/dist/compat/state.d.ts +415 -0
- package/dist/compat/state.js +689 -0
- package/dist/compat/test-builder.d.ts +98 -0
- package/dist/compat/test-builder.js +197 -0
- package/dist/compat/transform.d.ts +458 -0
- package/dist/compat/transform.js +803 -0
- package/dist/compat/view.d.ts +411 -0
- package/dist/compat/view.js +409 -0
- package/dist/dropcursor.d.ts +46 -0
- package/dist/dropcursor.js +176 -0
- package/dist/extensions/defaults.d.ts +716 -0
- package/dist/extensions/defaults.js +209 -0
- package/dist/extensions/editor.d.ts +246 -0
- package/dist/extensions/editor.js +271 -0
- package/dist/extensions/extension.d.ts +375 -0
- package/dist/extensions/extension.js +233 -0
- package/dist/extensions.d.ts +4 -0
- package/dist/extensions.js +4 -0
- package/dist/gapcursor.d.ts +66 -0
- package/dist/gapcursor.js +273 -0
- package/dist/history.d.ts +178 -0
- package/dist/history.js +412 -0
- package/dist/html.d.ts +158 -0
- package/dist/html.js +164 -0
- package/dist/inputrules.d.ts +271 -0
- package/dist/inputrules.js +321 -0
- package/dist/internal/attempt.js +15 -0
- package/dist/internal/json.js +29 -0
- package/dist/keymap/keymap.d.ts +130 -0
- package/dist/keymap/keymap.js +159 -0
- package/dist/keymap.d.ts +2 -0
- package/dist/keymap.js +1 -0
- package/dist/markdown/errors.d.ts +23 -0
- package/dist/markdown/errors.js +26 -0
- package/dist/markdown/from_markdown.d.ts +185 -0
- package/dist/markdown/from_markdown.js +266 -0
- package/dist/markdown/schema.d.ts +522 -0
- package/dist/markdown/schema.js +292 -0
- package/dist/markdown/to_markdown.d.ts +251 -0
- package/dist/markdown/to_markdown.js +413 -0
- package/dist/markdown.d.ts +5 -0
- package/dist/markdown.js +5 -0
- package/dist/model/attrsCodec.js +48 -0
- package/dist/model/comparedeep.js +17 -0
- package/dist/model/content.d.ts +232 -0
- package/dist/model/content.js +630 -0
- package/dist/model/diff.js +66 -0
- package/dist/model/dom.d.ts +3 -0
- package/dist/model/errors.d.ts +90 -0
- package/dist/model/errors.js +76 -0
- package/dist/model/fragment.d.ts +131 -0
- package/dist/model/fragment.js +262 -0
- package/dist/model/from_dom.d.ts +299 -0
- package/dist/model/from_dom.js +618 -0
- package/dist/model/json.d.ts +37 -0
- package/dist/model/json.js +126 -0
- package/dist/model/mark.d.ts +73 -0
- package/dist/model/mark.js +121 -0
- package/dist/model/node.d.ts +267 -0
- package/dist/model/node.js +434 -0
- package/dist/model/replace.d.ts +78 -0
- package/dist/model/replace.js +207 -0
- package/dist/model/resolvedpos.d.ts +196 -0
- package/dist/model/resolvedpos.js +305 -0
- package/dist/model/schema.d.ts +740 -0
- package/dist/model/schema.js +451 -0
- package/dist/model/to_dom.d.ts +169 -0
- package/dist/model/to_dom.js +238 -0
- package/dist/model.d.ts +12 -0
- package/dist/model.js +12 -0
- package/dist/placeholder.d.ts +53 -0
- package/dist/placeholder.js +79 -0
- package/dist/reactive/observer.d.ts +54 -0
- package/dist/reactive/observer.js +61 -0
- package/dist/reactive/selectors.d.ts +22 -0
- package/dist/reactive/selectors.js +61 -0
- package/dist/reactive/stateref.d.ts +72 -0
- package/dist/reactive/stateref.js +71 -0
- package/dist/reactive/streams.d.ts +83 -0
- package/dist/reactive/streams.js +85 -0
- package/dist/reactive.d.ts +16 -0
- package/dist/reactive.js +26 -0
- package/dist/schema-basic.d.ts +448 -0
- package/dist/schema-basic.js +269 -0
- package/dist/schema-list/commands.d.ts +66 -0
- package/dist/schema-list/commands.js +203 -0
- package/dist/schema-list.d.ts +92 -0
- package/dist/schema-list.js +100 -0
- package/dist/state/errors.d.ts +39 -0
- package/dist/state/errors.js +32 -0
- package/dist/state/plugin.d.ts +232 -0
- package/dist/state/plugin.js +82 -0
- package/dist/state/selection.d.ts +297 -0
- package/dist/state/selection.js +486 -0
- package/dist/state/state.d.ts +212 -0
- package/dist/state/state.js +489 -0
- package/dist/state/transaction.d.ts +145 -0
- package/dist/state/transaction.js +195 -0
- package/dist/state.d.ts +6 -0
- package/dist/state.js +6 -0
- package/dist/test-builder.d.ts +3582 -0
- package/dist/test-builder.js +239 -0
- package/dist/transform/attr_step.d.ts +60 -0
- package/dist/transform/attr_step.js +105 -0
- package/dist/transform/errors.d.ts +50 -0
- package/dist/transform/errors.js +35 -0
- package/dist/transform/map.d.ts +182 -0
- package/dist/transform/map.js +280 -0
- package/dist/transform/mark.js +98 -0
- package/dist/transform/mark_set_step.js +69 -0
- package/dist/transform/mark_step.d.ts +113 -0
- package/dist/transform/mark_step.js +225 -0
- package/dist/transform/replace.d.ts +18 -0
- package/dist/transform/replace.js +381 -0
- package/dist/transform/replace_step.d.ts +109 -0
- package/dist/transform/replace_step.js +175 -0
- package/dist/transform/step.d.ts +157 -0
- package/dist/transform/step.js +168 -0
- package/dist/transform/structure.d.ts +89 -0
- package/dist/transform/structure.js +350 -0
- package/dist/transform/transform.d.ts +248 -0
- package/dist/transform/transform.js +373 -0
- package/dist/transform.d.ts +10 -0
- package/dist/transform.js +10 -0
- package/dist/view/browser.js +39 -0
- package/dist/view/capturekeys.js +282 -0
- package/dist/view/clipboard.d.ts +8 -0
- package/dist/view/clipboard.js +245 -0
- package/dist/view/decoration.d.ts +339 -0
- package/dist/view/decoration.js +566 -0
- package/dist/view/dom.d.ts +18 -0
- package/dist/view/dom.js +140 -0
- package/dist/view/domchange.js +295 -0
- package/dist/view/domcoords.d.ts +22 -0
- package/dist/view/domcoords.js +448 -0
- package/dist/view/domobserver.d.ts +47 -0
- package/dist/view/domobserver.js +328 -0
- package/dist/view/errors.d.ts +18 -0
- package/dist/view/errors.js +21 -0
- package/dist/view/input.d.ts +58 -0
- package/dist/view/input.js +704 -0
- package/dist/view/selection.js +198 -0
- package/dist/view/view.d.ts +699 -0
- package/dist/view/view.js +623 -0
- package/dist/view/viewdesc.d.ts +236 -0
- package/dist/view/viewdesc.js +1205 -0
- package/dist/view-css.d.ts +43 -0
- package/dist/view-css.js +124 -0
- package/dist/view.d.ts +6 -0
- package/dist/view.js +4 -0
- package/package.json +200 -4
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { seq, zeroOrMore } from "./model/content.js";
|
|
2
|
+
import { DocSchema } from "./model/schema.js";
|
|
3
|
+
import { Node } from "./model/node.js";
|
|
4
|
+
import { marks, nodes } from "./schema-basic.js";
|
|
5
|
+
import { addListNodes } from "./schema-list.js";
|
|
6
|
+
// src/test-builder.ts
|
|
7
|
+
/**
|
|
8
|
+
* Helpers for concisely building documents in tests, ported from
|
|
9
|
+
* `prosemirror-test-builder`.
|
|
10
|
+
*
|
|
11
|
+
* Builders are functions that take an optional attributes object and
|
|
12
|
+
* any number of children (nodes, strings, or the output of mark
|
|
13
|
+
* builders). Strings may contain `<name>` tags, which are removed from
|
|
14
|
+
* the text and recorded (as document positions) in the resulting
|
|
15
|
+
* node's `tag` object.
|
|
16
|
+
*
|
|
17
|
+
* ```ts skip-type-checking
|
|
18
|
+
* const d = doc(p("hello <a>world"))
|
|
19
|
+
* d.tag.a // => 7
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @since 0.1.0
|
|
23
|
+
*/
|
|
24
|
+
const noTag = Object.create(null);
|
|
25
|
+
const tags = /* @__PURE__ */ new WeakMap();
|
|
26
|
+
/**
|
|
27
|
+
* Get the tags recorded for a node built with a builder (empty when
|
|
28
|
+
* none were recorded).
|
|
29
|
+
*
|
|
30
|
+
* @since 0.1.0
|
|
31
|
+
* @category utils
|
|
32
|
+
*/
|
|
33
|
+
const tagsOf = (node) => tags.get(node) ?? noTag;
|
|
34
|
+
const withTag = (node, tag) => {
|
|
35
|
+
if (tag !== noTag) tags.set(node, tag);
|
|
36
|
+
return node;
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(Node.prototype, "tag", {
|
|
39
|
+
get() {
|
|
40
|
+
return tagsOf(this);
|
|
41
|
+
},
|
|
42
|
+
configurable: true
|
|
43
|
+
});
|
|
44
|
+
const isFlat = (u) => (typeof u === "object" || typeof u === "function") && u !== null && Array.isArray(u.flat);
|
|
45
|
+
function flatten(schema, children, f) {
|
|
46
|
+
const result = [];
|
|
47
|
+
let pos = 0;
|
|
48
|
+
let tag = noTag;
|
|
49
|
+
for (let i = 0; i < children.length; i++) {
|
|
50
|
+
const child = children[i];
|
|
51
|
+
if (typeof child === "string") {
|
|
52
|
+
const re = /<(\w+)>/g;
|
|
53
|
+
let m;
|
|
54
|
+
let at = 0, out = "";
|
|
55
|
+
while (m = re.exec(child)) {
|
|
56
|
+
out += child.slice(at, m.index);
|
|
57
|
+
pos += m.index - at;
|
|
58
|
+
at = m.index + m[0].length;
|
|
59
|
+
if (tag === noTag) tag = Object.create(null);
|
|
60
|
+
tag[m[1]] = pos;
|
|
61
|
+
}
|
|
62
|
+
out += child.slice(at);
|
|
63
|
+
pos += child.length - at;
|
|
64
|
+
if (out) result.push(f(schema.textUnsafe(out)));
|
|
65
|
+
} else if (isFlat(child)) {
|
|
66
|
+
const childTag = child.tag ?? noTag;
|
|
67
|
+
if (childTag !== noTag) {
|
|
68
|
+
if (tag === noTag) tag = Object.create(null);
|
|
69
|
+
for (const id in childTag) tag[id] = childTag[id] + pos;
|
|
70
|
+
}
|
|
71
|
+
for (let j = 0; j < child.flat.length; j++) {
|
|
72
|
+
const node = f(child.flat[j]);
|
|
73
|
+
pos += node.nodeSize;
|
|
74
|
+
result.push(node);
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
const node0 = child;
|
|
78
|
+
const childTag = tagsOf(node0);
|
|
79
|
+
if (childTag !== noTag) {
|
|
80
|
+
if (tag === noTag) tag = Object.create(null);
|
|
81
|
+
for (const id in childTag) tag[id] = childTag[id] + (node0.isText ? 0 : 1) + pos;
|
|
82
|
+
}
|
|
83
|
+
const node = f(node0);
|
|
84
|
+
pos += node.nodeSize;
|
|
85
|
+
result.push(node);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
nodes: result,
|
|
90
|
+
tag
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function takeAttrs(attrs, args) {
|
|
94
|
+
const a0 = args[0];
|
|
95
|
+
if (!args.length || a0 && (typeof a0 === "string" || a0 instanceof Node || isFlat(a0))) return attrs;
|
|
96
|
+
args.shift();
|
|
97
|
+
if (!attrs) return a0;
|
|
98
|
+
if (!a0) return attrs;
|
|
99
|
+
return {
|
|
100
|
+
...attrs,
|
|
101
|
+
...a0
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function block(type, attrs = null) {
|
|
105
|
+
const result = function(...args) {
|
|
106
|
+
const myAttrs = takeAttrs(attrs, args);
|
|
107
|
+
const { nodes, tag } = flatten(type.schema, args, (n) => n);
|
|
108
|
+
return withTag(type.createUnsafe(myAttrs, nodes), tag);
|
|
109
|
+
};
|
|
110
|
+
if (type.isLeaf) try {
|
|
111
|
+
result.flat = [type.createUnsafe(attrs)];
|
|
112
|
+
} catch {}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
function mark(type, attrs) {
|
|
116
|
+
return function(...args) {
|
|
117
|
+
const m = type.createUnsafe(takeAttrs(attrs, args));
|
|
118
|
+
const { nodes, tag } = flatten(type.schema, args, (n) => {
|
|
119
|
+
const newMarks = m.addToSet(n.marks);
|
|
120
|
+
return newMarks.length > n.marks.length ? n.mark(newMarks) : n;
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
flat: nodes,
|
|
124
|
+
tag
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Create builders for the given schema. `names` can be used to define
|
|
130
|
+
* additional builders with preset attributes, using `nodeType` or
|
|
131
|
+
* `markType` to specify the underlying type:
|
|
132
|
+
*
|
|
133
|
+
* ```ts skip-type-checking
|
|
134
|
+
* builders(schema, { h1: { nodeType: "heading", level: 1 } })
|
|
135
|
+
* ```
|
|
136
|
+
*
|
|
137
|
+
* @since 0.1.0
|
|
138
|
+
* @category constructors
|
|
139
|
+
*/
|
|
140
|
+
function builders(schema, names) {
|
|
141
|
+
const result = { schema };
|
|
142
|
+
for (const name in schema.nodes) result[name] = block(schema.nodes[name], {});
|
|
143
|
+
for (const name in schema.marks) result[name] = mark(schema.marks[name], {});
|
|
144
|
+
if (names) for (const name in names) {
|
|
145
|
+
const value = { ...names[name] };
|
|
146
|
+
const typeName = value.nodeType || value.markType || name;
|
|
147
|
+
delete value.nodeType;
|
|
148
|
+
delete value.markType;
|
|
149
|
+
const nodeType = schema.nodes[typeName], markType = schema.marks[typeName];
|
|
150
|
+
if (nodeType) result[name] = block(nodeType, value);
|
|
151
|
+
else if (markType) result[name] = mark(markType, value);
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* The test schema: the basic schema with list nodes added.
|
|
157
|
+
*
|
|
158
|
+
* @since 0.1.0
|
|
159
|
+
* @category schemas
|
|
160
|
+
*/
|
|
161
|
+
const schema = DocSchema.makeUnsafe({
|
|
162
|
+
nodes: addListNodes(nodes, seq("paragraph", zeroOrMore("block")), "block"),
|
|
163
|
+
marks
|
|
164
|
+
});
|
|
165
|
+
const b = builders(schema, {
|
|
166
|
+
p: { nodeType: "paragraph" },
|
|
167
|
+
pre: { nodeType: "code_block" },
|
|
168
|
+
h1: {
|
|
169
|
+
nodeType: "heading",
|
|
170
|
+
level: 1
|
|
171
|
+
},
|
|
172
|
+
h2: {
|
|
173
|
+
nodeType: "heading",
|
|
174
|
+
level: 2
|
|
175
|
+
},
|
|
176
|
+
h3: {
|
|
177
|
+
nodeType: "heading",
|
|
178
|
+
level: 3
|
|
179
|
+
},
|
|
180
|
+
li: { nodeType: "list_item" },
|
|
181
|
+
ul: { nodeType: "bullet_list" },
|
|
182
|
+
ol: { nodeType: "ordered_list" },
|
|
183
|
+
br: { nodeType: "hard_break" },
|
|
184
|
+
img: {
|
|
185
|
+
nodeType: "image",
|
|
186
|
+
src: "img.png"
|
|
187
|
+
},
|
|
188
|
+
hr: { nodeType: "horizontal_rule" },
|
|
189
|
+
a: {
|
|
190
|
+
markType: "link",
|
|
191
|
+
href: "foo"
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
/**
|
|
195
|
+
* Structural equality helper.
|
|
196
|
+
*
|
|
197
|
+
* @since 0.1.0
|
|
198
|
+
* @category utils
|
|
199
|
+
*/
|
|
200
|
+
function eq(a, b) {
|
|
201
|
+
return a.eq(b);
|
|
202
|
+
}
|
|
203
|
+
/** @since 0.1.0 */
|
|
204
|
+
const doc = b.doc;
|
|
205
|
+
/** @since 0.1.0 */
|
|
206
|
+
const p = b.p;
|
|
207
|
+
/** @since 0.1.0 */
|
|
208
|
+
const code_block = b.code_block;
|
|
209
|
+
/** @since 0.1.0 */
|
|
210
|
+
const pre = b.pre;
|
|
211
|
+
/** @since 0.1.0 */
|
|
212
|
+
const h1 = b.h1;
|
|
213
|
+
/** @since 0.1.0 */
|
|
214
|
+
const h2 = b.h2;
|
|
215
|
+
/** @since 0.1.0 */
|
|
216
|
+
const h3 = b.h3;
|
|
217
|
+
/** @since 0.1.0 */
|
|
218
|
+
const li = b.li;
|
|
219
|
+
/** @since 0.1.0 */
|
|
220
|
+
const ul = b.ul;
|
|
221
|
+
/** @since 0.1.0 */
|
|
222
|
+
const ol = b.ol;
|
|
223
|
+
/** @since 0.1.0 */
|
|
224
|
+
const img = b.img;
|
|
225
|
+
/** @since 0.1.0 */
|
|
226
|
+
const hr = b.hr;
|
|
227
|
+
/** @since 0.1.0 */
|
|
228
|
+
const br = b.br;
|
|
229
|
+
/** @since 0.1.0 */
|
|
230
|
+
const blockquote = b.blockquote;
|
|
231
|
+
/** @since 0.1.0 */
|
|
232
|
+
const a = b.a;
|
|
233
|
+
/** @since 0.1.0 */
|
|
234
|
+
const em = b.em;
|
|
235
|
+
/** @since 0.1.0 */
|
|
236
|
+
const strong = b.strong;
|
|
237
|
+
/** @since 0.1.0 */
|
|
238
|
+
const code = b.code;
|
|
239
|
+
export { a, blockquote, br, builders, code, code_block, doc, em, eq, h1, h2, h3, hr, img, li, ol, p, pre, schema, strong, tagsOf, ul };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { AnySchema } from "../model/schema.js";
|
|
2
|
+
import { Node } from "../model/node.js";
|
|
3
|
+
import "../model.js";
|
|
4
|
+
import { Mappable, StepMap } from "./map.js";
|
|
5
|
+
import { Step, StepJSON, StepResult } from "./step.js";
|
|
6
|
+
import * as Option from "effect/Option";
|
|
7
|
+
/**
|
|
8
|
+
* Update an attribute in a specific node.
|
|
9
|
+
*
|
|
10
|
+
* @since 0.1.0
|
|
11
|
+
* @category steps
|
|
12
|
+
*/
|
|
13
|
+
export declare class AttrStep<Sc extends AnySchema = AnySchema> extends Step<Sc> {
|
|
14
|
+
/** The position of the target node. */
|
|
15
|
+
readonly pos: number;
|
|
16
|
+
/** The attribute to set. */
|
|
17
|
+
readonly attr: string;
|
|
18
|
+
/** The attribute's new value. */
|
|
19
|
+
readonly value: unknown;
|
|
20
|
+
/** Construct an attribute step. */
|
|
21
|
+
constructor(
|
|
22
|
+
/** The position of the target node. */
|
|
23
|
+
pos: number,
|
|
24
|
+
/** The attribute to set. */
|
|
25
|
+
attr: string,
|
|
26
|
+
/** The attribute's new value. */
|
|
27
|
+
value: unknown);
|
|
28
|
+
apply(doc: Node<Sc>): StepResult<Sc>;
|
|
29
|
+
getMap(): StepMap;
|
|
30
|
+
invert(doc: Node<Sc>): Step<Sc>;
|
|
31
|
+
map(mapping: Mappable): Option.Option<Step<Sc>>;
|
|
32
|
+
toJSON(): StepJSON;
|
|
33
|
+
/** @internal */
|
|
34
|
+
static fromJSONUnsafe<Sc extends AnySchema>(_schema: Sc, json: any): AttrStep<Sc>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Update an attribute in the doc node.
|
|
38
|
+
*
|
|
39
|
+
* @since 0.1.0
|
|
40
|
+
* @category steps
|
|
41
|
+
*/
|
|
42
|
+
export declare class DocAttrStep<Sc extends AnySchema = AnySchema> extends Step<Sc> {
|
|
43
|
+
/** The attribute to set. */
|
|
44
|
+
readonly attr: string;
|
|
45
|
+
/** The attribute's new value. */
|
|
46
|
+
readonly value: unknown;
|
|
47
|
+
/** Construct an attribute step. */
|
|
48
|
+
constructor(
|
|
49
|
+
/** The attribute to set. */
|
|
50
|
+
attr: string,
|
|
51
|
+
/** The attribute's new value. */
|
|
52
|
+
value: unknown);
|
|
53
|
+
apply(doc: Node<Sc>): StepResult<Sc>;
|
|
54
|
+
getMap(): StepMap;
|
|
55
|
+
invert(doc: Node<Sc>): Step<Sc>;
|
|
56
|
+
map(_mapping: Mappable): Option.Option<Step<Sc>>;
|
|
57
|
+
toJSON(): StepJSON;
|
|
58
|
+
/** @internal */
|
|
59
|
+
static fromJSONUnsafe<Sc extends AnySchema>(_schema: Sc, json: any): DocAttrStep<Sc>;
|
|
60
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Fragment } from "../model/fragment.js";
|
|
2
|
+
import { JSONError } from "../model/errors.js";
|
|
3
|
+
import { Slice } from "../model/replace.js";
|
|
4
|
+
import { StepMap } from "./map.js";
|
|
5
|
+
import { Step, StepResult } from "./step.js";
|
|
6
|
+
import * as Option from "effect/Option";
|
|
7
|
+
import * as Predicate from "effect/Predicate";
|
|
8
|
+
// src/transform/attr_step.ts
|
|
9
|
+
/**
|
|
10
|
+
* Attribute steps.
|
|
11
|
+
*
|
|
12
|
+
* @since 0.1.0
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Update an attribute in a specific node.
|
|
16
|
+
*
|
|
17
|
+
* @since 0.1.0
|
|
18
|
+
* @category steps
|
|
19
|
+
*/
|
|
20
|
+
var AttrStep = class AttrStep extends Step {
|
|
21
|
+
/** Construct an attribute step. */
|
|
22
|
+
constructor(pos, attr, value) {
|
|
23
|
+
super();
|
|
24
|
+
this.pos = pos;
|
|
25
|
+
this.attr = attr;
|
|
26
|
+
this.value = value;
|
|
27
|
+
}
|
|
28
|
+
apply(doc) {
|
|
29
|
+
const node = doc.nodeAtOrNull(this.pos);
|
|
30
|
+
if (!node) return StepResult.fail("No node at attribute step's position");
|
|
31
|
+
const attrs = Object.create(null);
|
|
32
|
+
for (const name in node.attrs) attrs[name] = node.attrs[name];
|
|
33
|
+
attrs[this.attr] = this.value;
|
|
34
|
+
const updated = node.type.createUnsafe(attrs, null, node.marks);
|
|
35
|
+
return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment.from(updated), 0, node.isLeaf ? 0 : 1));
|
|
36
|
+
}
|
|
37
|
+
getMap() {
|
|
38
|
+
return StepMap.empty;
|
|
39
|
+
}
|
|
40
|
+
invert(doc) {
|
|
41
|
+
return new AttrStep(this.pos, this.attr, doc.nodeAtOrNull(this.pos).attrs[this.attr]);
|
|
42
|
+
}
|
|
43
|
+
map(mapping) {
|
|
44
|
+
const pos = mapping.mapResult(this.pos, 1);
|
|
45
|
+
return pos.deletedAfter ? Option.none() : Option.some(new AttrStep(pos.pos, this.attr, this.value));
|
|
46
|
+
}
|
|
47
|
+
toJSON() {
|
|
48
|
+
return {
|
|
49
|
+
stepType: "attr",
|
|
50
|
+
pos: this.pos,
|
|
51
|
+
attr: this.attr,
|
|
52
|
+
value: this.value
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** @internal */
|
|
56
|
+
static fromJSONUnsafe(_schema, json) {
|
|
57
|
+
if (!Predicate.isNumber(json.pos) || !Predicate.isString(json.attr)) throw new JSONError({ message: "Invalid input for AttrStep.fromJSON" });
|
|
58
|
+
return new AttrStep(json.pos, json.attr, json.value);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
Step.jsonID("attr", AttrStep);
|
|
62
|
+
/**
|
|
63
|
+
* Update an attribute in the doc node.
|
|
64
|
+
*
|
|
65
|
+
* @since 0.1.0
|
|
66
|
+
* @category steps
|
|
67
|
+
*/
|
|
68
|
+
var DocAttrStep = class DocAttrStep extends Step {
|
|
69
|
+
/** Construct an attribute step. */
|
|
70
|
+
constructor(attr, value) {
|
|
71
|
+
super();
|
|
72
|
+
this.attr = attr;
|
|
73
|
+
this.value = value;
|
|
74
|
+
}
|
|
75
|
+
apply(doc) {
|
|
76
|
+
const attrs = Object.create(null);
|
|
77
|
+
for (const name in doc.attrs) attrs[name] = doc.attrs[name];
|
|
78
|
+
attrs[this.attr] = this.value;
|
|
79
|
+
const updated = doc.type.createUnsafe(attrs, doc.content, doc.marks);
|
|
80
|
+
return StepResult.ok(updated);
|
|
81
|
+
}
|
|
82
|
+
getMap() {
|
|
83
|
+
return StepMap.empty;
|
|
84
|
+
}
|
|
85
|
+
invert(doc) {
|
|
86
|
+
return new DocAttrStep(this.attr, doc.attrs[this.attr]);
|
|
87
|
+
}
|
|
88
|
+
map(_mapping) {
|
|
89
|
+
return Option.some(this);
|
|
90
|
+
}
|
|
91
|
+
toJSON() {
|
|
92
|
+
return {
|
|
93
|
+
stepType: "docAttr",
|
|
94
|
+
attr: this.attr,
|
|
95
|
+
value: this.value
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/** @internal */
|
|
99
|
+
static fromJSONUnsafe(_schema, json) {
|
|
100
|
+
if (!Predicate.isString(json.attr)) throw new JSONError({ message: "Invalid input for DocAttrStep.fromJSON" });
|
|
101
|
+
return new DocAttrStep(json.attr, json.value);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
Step.jsonID("docAttr", DocAttrStep);
|
|
105
|
+
export { AttrStep, DocAttrStep };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ModelError } from "../model/errors.js";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
declare const TransformError_base: Schema.Class<TransformError, Schema.TaggedStruct<"TransformError", {
|
|
4
|
+
readonly message: Schema.String;
|
|
5
|
+
}>, import("effect/Cause").YieldableError>;
|
|
6
|
+
/**
|
|
7
|
+
* An invalid transform operation, such as wrapping content in node
|
|
8
|
+
* types that can not contain it, splitting where splitting is not
|
|
9
|
+
* allowed, or addressing a position that holds no node. Corresponds to
|
|
10
|
+
* the `TransformError`/`RangeError`s thrown by ProseMirror's transform
|
|
11
|
+
* methods.
|
|
12
|
+
*
|
|
13
|
+
* @since 0.1.0
|
|
14
|
+
* @category errors
|
|
15
|
+
*/
|
|
16
|
+
export declare class TransformError extends TransformError_base {}
|
|
17
|
+
declare const StepError_base: Schema.Class<StepError, Schema.TaggedStruct<"StepError", {
|
|
18
|
+
readonly message: Schema.String;
|
|
19
|
+
}>, import("effect/Cause").YieldableError>;
|
|
20
|
+
/**
|
|
21
|
+
* A step could not be applied to a document. The `message` is the
|
|
22
|
+
* step's failure message (see `StepResult.failed`).
|
|
23
|
+
*
|
|
24
|
+
* @since 0.1.0
|
|
25
|
+
* @category errors
|
|
26
|
+
*/
|
|
27
|
+
export declare class StepError extends StepError_base {}
|
|
28
|
+
/**
|
|
29
|
+
* Union of the errors defined by the transform layer.
|
|
30
|
+
*
|
|
31
|
+
* @since 0.1.0
|
|
32
|
+
* @category errors
|
|
33
|
+
*/
|
|
34
|
+
export type TransformFailure = TransformError | StepError;
|
|
35
|
+
/**
|
|
36
|
+
* @since 0.1.0
|
|
37
|
+
* @category guards
|
|
38
|
+
*/
|
|
39
|
+
export declare const isTransformFailure: (u: unknown) => u is TransformFailure;
|
|
40
|
+
/**
|
|
41
|
+
* Errors that can be produced by transform operations: the transform
|
|
42
|
+
* layer's own errors plus model errors.
|
|
43
|
+
*
|
|
44
|
+
* @since 0.1.0
|
|
45
|
+
* @category errors
|
|
46
|
+
*/
|
|
47
|
+
export type TransformOrModelError = TransformFailure | ModelError;
|
|
48
|
+
/** @internal */
|
|
49
|
+
export declare const isTransformOrModelError: (u: unknown) => u is TransformOrModelError;
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { isModelError } from "../model/errors.js";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
// src/transform/errors.ts
|
|
4
|
+
/**
|
|
5
|
+
* Tagged errors raised by the transform layer.
|
|
6
|
+
*
|
|
7
|
+
* @since 0.1.0
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* An invalid transform operation, such as wrapping content in node
|
|
11
|
+
* types that can not contain it, splitting where splitting is not
|
|
12
|
+
* allowed, or addressing a position that holds no node. Corresponds to
|
|
13
|
+
* the `TransformError`/`RangeError`s thrown by ProseMirror's transform
|
|
14
|
+
* methods.
|
|
15
|
+
*
|
|
16
|
+
* @since 0.1.0
|
|
17
|
+
* @category errors
|
|
18
|
+
*/
|
|
19
|
+
var TransformError = class extends Schema.TaggedError()("TransformError", { message: Schema.String }) {};
|
|
20
|
+
/**
|
|
21
|
+
* A step could not be applied to a document. The `message` is the
|
|
22
|
+
* step's failure message (see `StepResult.failed`).
|
|
23
|
+
*
|
|
24
|
+
* @since 0.1.0
|
|
25
|
+
* @category errors
|
|
26
|
+
*/
|
|
27
|
+
var StepError = class extends Schema.TaggedError()("StepError", { message: Schema.String }) {};
|
|
28
|
+
/**
|
|
29
|
+
* @since 0.1.0
|
|
30
|
+
* @category guards
|
|
31
|
+
*/
|
|
32
|
+
const isTransformFailure = (u) => u instanceof TransformError || u instanceof StepError;
|
|
33
|
+
/** @internal */
|
|
34
|
+
const isTransformOrModelError = (u) => isTransformFailure(u) || isModelError(u);
|
|
35
|
+
export { StepError, TransformError, isTransformFailure, isTransformOrModelError };
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import * as Option from "effect/Option";
|
|
2
|
+
/**
|
|
3
|
+
* There are several things that positions can be mapped through.
|
|
4
|
+
* Such objects conform to this interface.
|
|
5
|
+
*
|
|
6
|
+
* @since 0.1.0
|
|
7
|
+
* @category models
|
|
8
|
+
*/
|
|
9
|
+
export interface Mappable {
|
|
10
|
+
/**
|
|
11
|
+
* Map a position through this object. When given, `assoc` (should be
|
|
12
|
+
* -1 or 1, defaults to 1) determines with which side the position is
|
|
13
|
+
* associated, which determines in which direction to move when a
|
|
14
|
+
* chunk of content is inserted at the mapped position.
|
|
15
|
+
*/
|
|
16
|
+
readonly map: (pos: number, assoc?: number) => number;
|
|
17
|
+
/**
|
|
18
|
+
* Map a position, and return an object containing additional
|
|
19
|
+
* information about the mapping. The result's `deleted` field tells
|
|
20
|
+
* you whether the position was deleted (completely enclosed in a
|
|
21
|
+
* replaced range) during the mapping. When content on only one side
|
|
22
|
+
* is deleted, the position itself is only considered deleted when
|
|
23
|
+
* `assoc` points in the direction of the deleted content.
|
|
24
|
+
*/
|
|
25
|
+
readonly mapResult: (pos: number, assoc?: number) => MapResult;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* An object representing a mapped position with extra information.
|
|
29
|
+
*
|
|
30
|
+
* @since 0.1.0
|
|
31
|
+
* @category models
|
|
32
|
+
*/
|
|
33
|
+
export declare class MapResult {
|
|
34
|
+
/** The mapped version of the position. */
|
|
35
|
+
readonly pos: number;
|
|
36
|
+
/** @internal */
|
|
37
|
+
readonly delInfo: number;
|
|
38
|
+
/** @internal */
|
|
39
|
+
readonly recover: number | null;
|
|
40
|
+
/** @internal */
|
|
41
|
+
constructor(
|
|
42
|
+
/** The mapped version of the position. */
|
|
43
|
+
pos: number,
|
|
44
|
+
/** @internal */
|
|
45
|
+
delInfo: number,
|
|
46
|
+
/** @internal */
|
|
47
|
+
recover: number | null);
|
|
48
|
+
/**
|
|
49
|
+
* Tells you whether the position was deleted, that is, whether the
|
|
50
|
+
* step removed the token on the side queried (via the `assoc`)
|
|
51
|
+
* argument from the document.
|
|
52
|
+
*/
|
|
53
|
+
get deleted(): boolean;
|
|
54
|
+
/** Tells you whether the token before the mapped position was deleted. */
|
|
55
|
+
get deletedBefore(): boolean;
|
|
56
|
+
/** True when the token after the mapped position was deleted. */
|
|
57
|
+
get deletedAfter(): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Tells whether any of the steps mapped through deletes across the
|
|
60
|
+
* position (including both the token before and after the position).
|
|
61
|
+
*/
|
|
62
|
+
get deletedAcross(): boolean;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* A map describing the deletions and insertions made by a step, which
|
|
66
|
+
* can be used to find the correspondence between positions in the
|
|
67
|
+
* pre-step version of a document and the same position in the
|
|
68
|
+
* post-step version.
|
|
69
|
+
*
|
|
70
|
+
* @since 0.1.0
|
|
71
|
+
* @category models
|
|
72
|
+
*/
|
|
73
|
+
export declare class StepMap implements Mappable {
|
|
74
|
+
/** @internal */
|
|
75
|
+
readonly ranges: ReadonlyArray<number>;
|
|
76
|
+
/** @internal */
|
|
77
|
+
readonly inverted: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Create a position map. The modifications to the document are
|
|
80
|
+
* represented as an array of numbers, in which each group of three
|
|
81
|
+
* represents a modified chunk as `[start, oldSize, newSize]`.
|
|
82
|
+
*/
|
|
83
|
+
constructor(
|
|
84
|
+
/** @internal */
|
|
85
|
+
ranges: ReadonlyArray<number>,
|
|
86
|
+
/** @internal */
|
|
87
|
+
inverted?: boolean);
|
|
88
|
+
/** @internal */
|
|
89
|
+
recover(value: number): number;
|
|
90
|
+
mapResult(pos: number, assoc?: number): MapResult;
|
|
91
|
+
map(pos: number, assoc?: number): number;
|
|
92
|
+
/** @internal */
|
|
93
|
+
_map(pos: number, assoc: number, simple: boolean): number | MapResult;
|
|
94
|
+
/** @internal */
|
|
95
|
+
touches(pos: number, recover: number): boolean;
|
|
96
|
+
/** Calls the given function on each of the changed ranges included in this map. */
|
|
97
|
+
forEach(f: (oldStart: number, oldEnd: number, newStart: number, newEnd: number) => void): void;
|
|
98
|
+
/**
|
|
99
|
+
* Create an inverted version of this map. The result can be used to
|
|
100
|
+
* map positions in the post-step document to the pre-step document.
|
|
101
|
+
*/
|
|
102
|
+
invert(): StepMap;
|
|
103
|
+
/** @internal */
|
|
104
|
+
toString(): string;
|
|
105
|
+
/**
|
|
106
|
+
* Create a map that moves all positions by offset `n` (which may be
|
|
107
|
+
* negative). This can be useful when applying steps meant for a
|
|
108
|
+
* sub-document to a larger document, or vice-versa.
|
|
109
|
+
*/
|
|
110
|
+
static offset(n: number): StepMap;
|
|
111
|
+
/** A StepMap that contains no changed ranges. */
|
|
112
|
+
static readonly empty: StepMap;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* A mapping represents a pipeline of zero or more step maps. It has
|
|
116
|
+
* special provisions for losslessly handling mapping positions through
|
|
117
|
+
* a series of steps in which some steps are inverted versions of
|
|
118
|
+
* earlier steps. (This comes up when ‘rebasing’ steps for collaboration
|
|
119
|
+
* or history management.)
|
|
120
|
+
*
|
|
121
|
+
* Mappings are mutable: `appendMap` and friends modify the mapping in
|
|
122
|
+
* place.
|
|
123
|
+
*
|
|
124
|
+
* @since 0.1.0
|
|
125
|
+
* @category models
|
|
126
|
+
*/
|
|
127
|
+
export declare class Mapping implements Mappable {
|
|
128
|
+
/** @internal */
|
|
129
|
+
mirror?: Array<number> | undefined;
|
|
130
|
+
/**
|
|
131
|
+
* The starting position in the `maps` array, used when `map` or
|
|
132
|
+
* `mapResult` is called.
|
|
133
|
+
*/
|
|
134
|
+
from: number;
|
|
135
|
+
/** The end position in the `maps` array. */
|
|
136
|
+
to: number;
|
|
137
|
+
private _maps;
|
|
138
|
+
private ownData;
|
|
139
|
+
/** Create a new mapping with the given position maps. */
|
|
140
|
+
constructor(maps?: ReadonlyArray<StepMap>,
|
|
141
|
+
/** @internal */
|
|
142
|
+
mirror?: Array<number> | undefined,
|
|
143
|
+
/**
|
|
144
|
+
* The starting position in the `maps` array, used when `map` or
|
|
145
|
+
* `mapResult` is called.
|
|
146
|
+
*/
|
|
147
|
+
from?: number,
|
|
148
|
+
/** The end position in the `maps` array. */
|
|
149
|
+
to?: number);
|
|
150
|
+
/** The step maps in this mapping. */
|
|
151
|
+
get maps(): ReadonlyArray<StepMap>;
|
|
152
|
+
/** Create a mapping that maps only through a part of this one. */
|
|
153
|
+
slice(from?: number, to?: number): Mapping;
|
|
154
|
+
/**
|
|
155
|
+
* Add a step map to the end of this mapping. If `mirrors` is given,
|
|
156
|
+
* it should be the index of the step map that is the mirror image of
|
|
157
|
+
* this one.
|
|
158
|
+
*/
|
|
159
|
+
appendMap(map: StepMap, mirrors?: number): void;
|
|
160
|
+
/** Add all the step maps in a given mapping to this one (preserving mirroring information). */
|
|
161
|
+
appendMapping(mapping: Mapping): void;
|
|
162
|
+
/**
|
|
163
|
+
* Finds the offset of the step map that mirrors the map at the given
|
|
164
|
+
* offset, in this mapping (as per the second argument to
|
|
165
|
+
* `appendMap`).
|
|
166
|
+
*/
|
|
167
|
+
getMirror(n: number): Option.Option<number>;
|
|
168
|
+
/** @internal */
|
|
169
|
+
getMirrorOrUndefined(n: number): number | undefined;
|
|
170
|
+
/** Record that the maps at offsets `n` and `m` mirror each other. */
|
|
171
|
+
setMirror(n: number, m: number): void;
|
|
172
|
+
/** Append the inverse of the given mapping to this one. */
|
|
173
|
+
appendMappingInverted(mapping: Mapping): void;
|
|
174
|
+
/** Create an inverted version of this mapping. */
|
|
175
|
+
invert(): Mapping;
|
|
176
|
+
/** Map a position through this mapping. */
|
|
177
|
+
map(pos: number, assoc?: number): number;
|
|
178
|
+
/** Map a position through this mapping, returning a mapping result. */
|
|
179
|
+
mapResult(pos: number, assoc?: number): MapResult;
|
|
180
|
+
/** @internal */
|
|
181
|
+
_map(pos: number, assoc: number, simple: boolean): number | MapResult;
|
|
182
|
+
}
|