@kerebron/extension-basic-editor 0.0.6 → 0.0.8
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/esm/editor/src/CoreEditor.d.ts +28 -0
- package/esm/editor/src/CoreEditor.d.ts.map +1 -0
- package/esm/editor/src/CoreEditor.js +170 -0
- package/esm/editor/src/Extension.d.ts +26 -0
- package/esm/editor/src/Extension.d.ts.map +1 -0
- package/esm/editor/src/Extension.js +33 -0
- package/esm/editor/src/ExtensionManager.d.ts +32 -0
- package/esm/editor/src/ExtensionManager.d.ts.map +1 -0
- package/esm/editor/src/ExtensionManager.js +253 -0
- package/esm/editor/src/Mark.d.ts +18 -0
- package/esm/editor/src/Mark.d.ts.map +1 -0
- package/esm/editor/src/Mark.js +34 -0
- package/esm/editor/src/Node.d.ts +27 -0
- package/esm/editor/src/Node.d.ts.map +1 -0
- package/esm/editor/src/Node.js +43 -0
- package/esm/editor/src/commands/CommandManager.d.ts +20 -0
- package/esm/editor/src/commands/CommandManager.d.ts.map +1 -0
- package/esm/editor/src/commands/CommandManager.js +60 -0
- package/esm/editor/src/commands/createChainableState.d.ts +3 -0
- package/esm/editor/src/commands/createChainableState.d.ts.map +1 -0
- package/esm/editor/src/commands/createChainableState.js +29 -0
- package/esm/editor/src/commands/mod.d.ts +49 -0
- package/esm/editor/src/commands/mod.d.ts.map +1 -0
- package/esm/editor/src/commands/mod.js +928 -0
- package/esm/editor/src/mod.d.ts +5 -0
- package/esm/editor/src/mod.d.ts.map +1 -0
- package/esm/editor/src/mod.js +4 -0
- package/esm/editor/src/plugins/input-rules/InputRulesPlugin.d.ts +23 -0
- package/esm/editor/src/plugins/input-rules/InputRulesPlugin.d.ts.map +1 -0
- package/esm/editor/src/plugins/input-rules/InputRulesPlugin.js +163 -0
- package/esm/editor/src/plugins/input-rules/mod.d.ts +3 -0
- package/esm/editor/src/plugins/input-rules/mod.d.ts.map +1 -0
- package/esm/editor/src/plugins/input-rules/mod.js +2 -0
- package/esm/editor/src/plugins/input-rules/rulebuilders.d.ts +5 -0
- package/esm/editor/src/plugins/input-rules/rulebuilders.d.ts.map +1 -0
- package/esm/editor/src/plugins/input-rules/rulebuilders.js +50 -0
- package/esm/editor/src/types.d.ts +29 -0
- package/esm/editor/src/types.d.ts.map +1 -0
- package/esm/editor/src/types.js +1 -0
- package/esm/editor/src/utilities/createNodeFromContent.d.ts +12 -0
- package/esm/editor/src/utilities/createNodeFromContent.d.ts.map +1 -0
- package/esm/editor/src/utilities/createNodeFromContent.js +118 -0
- package/esm/editor/src/utilities/getHtmlAttributes.d.ts +4 -0
- package/esm/editor/src/utilities/getHtmlAttributes.d.ts.map +1 -0
- package/esm/editor/src/utilities/getHtmlAttributes.js +47 -0
- package/esm/editor/src/utilities/mod.d.ts +3 -0
- package/esm/editor/src/utilities/mod.d.ts.map +1 -0
- package/esm/editor/src/utilities/mod.js +2 -0
- package/esm/extension-automerge/src/CursorPlugin.d.ts +16 -0
- package/esm/extension-automerge/src/CursorPlugin.d.ts.map +1 -0
- package/esm/extension-automerge/src/CursorPlugin.js +114 -0
- package/esm/extension-automerge/src/ExtensionAutomerge.d.ts +26 -0
- package/esm/extension-automerge/src/ExtensionAutomerge.d.ts.map +1 -0
- package/esm/extension-automerge/src/ExtensionAutomerge.js +136 -0
- package/esm/extension-automerge/src/MarkUnknown.d.ts +8 -0
- package/esm/extension-automerge/src/MarkUnknown.d.ts.map +1 -0
- package/esm/extension-automerge/src/MarkUnknown.js +26 -0
- package/esm/extension-automerge/src/NodeUnknown.d.ts +8 -0
- package/esm/extension-automerge/src/NodeUnknown.d.ts.map +1 -0
- package/esm/extension-automerge/src/NodeUnknown.js +28 -0
- package/esm/extension-automerge/src/NodeUnknownBlock.d.ts +11 -0
- package/esm/extension-automerge/src/NodeUnknownBlock.d.ts.map +1 -0
- package/esm/extension-automerge/src/NodeUnknownBlock.js +36 -0
- package/esm/extension-automerge/src/SchemaAdapter.d.ts +70 -0
- package/esm/extension-automerge/src/SchemaAdapter.d.ts.map +1 -0
- package/esm/extension-automerge/src/SchemaAdapter.js +188 -0
- package/esm/extension-automerge/src/SyncPlugin.d.ts +16 -0
- package/esm/extension-automerge/src/SyncPlugin.d.ts.map +1 -0
- package/esm/extension-automerge/src/SyncPlugin.js +147 -0
- package/esm/extension-automerge/src/amToPm.d.ts +9 -0
- package/esm/extension-automerge/src/amToPm.d.ts.map +1 -0
- package/esm/extension-automerge/src/amToPm.js +245 -0
- package/esm/extension-automerge/src/amTraversal.d.ts +62 -0
- package/esm/extension-automerge/src/amTraversal.d.ts.map +1 -0
- package/esm/extension-automerge/src/amTraversal.js +688 -0
- package/esm/extension-automerge/src/loader.d.ts +8 -0
- package/esm/extension-automerge/src/loader.d.ts.map +1 -0
- package/esm/extension-automerge/src/loader.js +54 -0
- package/esm/extension-automerge/src/maintainSpans.d.ts +9 -0
- package/esm/extension-automerge/src/maintainSpans.d.ts.map +1 -0
- package/esm/extension-automerge/src/maintainSpans.js +464 -0
- package/esm/extension-automerge/src/pmToAm.d.ts +6 -0
- package/esm/extension-automerge/src/pmToAm.d.ts.map +1 -0
- package/esm/extension-automerge/src/pmToAm.js +183 -0
- package/esm/extension-automerge/src/pmTraversal.d.ts +26 -0
- package/esm/extension-automerge/src/pmTraversal.d.ts.map +1 -0
- package/esm/extension-automerge/src/pmTraversal.js +102 -0
- package/esm/extension-automerge/src/types.d.ts +42 -0
- package/esm/extension-automerge/src/types.d.ts.map +1 -0
- package/esm/extension-automerge/src/types.js +94 -0
- package/esm/extension-automerge/src/utils.d.ts +3 -0
- package/esm/extension-automerge/src/utils.d.ts.map +1 -0
- package/esm/extension-automerge/src/utils.js +18 -0
- package/esm/extension-basic-editor/src/ExtensionBaseKeymap.d.ts +8 -0
- package/esm/extension-basic-editor/src/ExtensionBaseKeymap.d.ts.map +1 -0
- package/esm/{ExtensionBaseKeymap.js → extension-basic-editor/src/ExtensionBaseKeymap.js} +2 -2
- package/esm/{ExtensionBasicEditor.d.ts → extension-basic-editor/src/ExtensionBasicEditor.d.ts} +1 -1
- package/esm/extension-basic-editor/src/ExtensionBasicEditor.d.ts.map +1 -0
- package/esm/{ExtensionBasicEditor.js → extension-basic-editor/src/ExtensionBasicEditor.js} +1 -1
- package/esm/{ExtensionDropcursor.d.ts → extension-basic-editor/src/ExtensionDropcursor.d.ts} +1 -1
- package/esm/extension-basic-editor/src/ExtensionDropcursor.d.ts.map +1 -0
- package/esm/{ExtensionDropcursor.js → extension-basic-editor/src/ExtensionDropcursor.js} +1 -1
- package/esm/{ExtensionGapcursor.d.ts → extension-basic-editor/src/ExtensionGapcursor.d.ts} +1 -1
- package/esm/extension-basic-editor/src/ExtensionGapcursor.d.ts.map +1 -0
- package/esm/{ExtensionGapcursor.js → extension-basic-editor/src/ExtensionGapcursor.js} +1 -1
- package/esm/{ExtensionHistory.d.ts → extension-basic-editor/src/ExtensionHistory.d.ts} +2 -2
- package/esm/extension-basic-editor/src/ExtensionHistory.d.ts.map +1 -0
- package/esm/{ExtensionHistory.js → extension-basic-editor/src/ExtensionHistory.js} +1 -1
- package/esm/{MarkCode.d.ts → extension-basic-editor/src/MarkCode.d.ts} +2 -2
- package/esm/extension-basic-editor/src/MarkCode.d.ts.map +1 -0
- package/esm/{MarkCode.js → extension-basic-editor/src/MarkCode.js} +2 -2
- package/esm/{MarkItalic.d.ts → extension-basic-editor/src/MarkItalic.d.ts} +2 -2
- package/esm/extension-basic-editor/src/MarkItalic.d.ts.map +1 -0
- package/esm/{MarkItalic.js → extension-basic-editor/src/MarkItalic.js} +2 -2
- package/esm/{MarkLink.d.ts → extension-basic-editor/src/MarkLink.d.ts} +1 -1
- package/esm/extension-basic-editor/src/MarkLink.d.ts.map +1 -0
- package/esm/{MarkLink.js → extension-basic-editor/src/MarkLink.js} +1 -1
- package/esm/{MarkStrong.d.ts → extension-basic-editor/src/MarkStrong.d.ts} +2 -2
- package/esm/extension-basic-editor/src/MarkStrong.d.ts.map +1 -0
- package/esm/{MarkStrong.js → extension-basic-editor/src/MarkStrong.js} +2 -2
- package/esm/{MarkUnderline.d.ts → extension-basic-editor/src/MarkUnderline.d.ts} +2 -2
- package/esm/extension-basic-editor/src/MarkUnderline.d.ts.map +1 -0
- package/esm/{MarkUnderline.js → extension-basic-editor/src/MarkUnderline.js} +2 -2
- package/esm/{NodeAside.d.ts → extension-basic-editor/src/NodeAside.d.ts} +1 -1
- package/esm/extension-basic-editor/src/NodeAside.d.ts.map +1 -0
- package/esm/{NodeAside.js → extension-basic-editor/src/NodeAside.js} +1 -1
- package/esm/{NodeBlockquote.d.ts → extension-basic-editor/src/NodeBlockquote.d.ts} +3 -3
- package/esm/extension-basic-editor/src/NodeBlockquote.d.ts.map +1 -0
- package/esm/{NodeBlockquote.js → extension-basic-editor/src/NodeBlockquote.js} +3 -3
- package/esm/{NodeBulletList.d.ts → extension-basic-editor/src/NodeBulletList.d.ts} +3 -3
- package/esm/extension-basic-editor/src/NodeBulletList.d.ts.map +1 -0
- package/esm/{NodeBulletList.js → extension-basic-editor/src/NodeBulletList.js} +3 -3
- package/esm/{NodeDocument.d.ts → extension-basic-editor/src/NodeDocument.d.ts} +1 -1
- package/esm/extension-basic-editor/src/NodeDocument.d.ts.map +1 -0
- package/esm/{NodeDocument.js → extension-basic-editor/src/NodeDocument.js} +1 -1
- package/esm/{NodeHardBreak.d.ts → extension-basic-editor/src/NodeHardBreak.d.ts} +2 -2
- package/esm/extension-basic-editor/src/NodeHardBreak.d.ts.map +1 -0
- package/esm/{NodeHardBreak.js → extension-basic-editor/src/NodeHardBreak.js} +2 -2
- package/esm/{NodeHeading.d.ts → extension-basic-editor/src/NodeHeading.d.ts} +3 -3
- package/esm/extension-basic-editor/src/NodeHeading.d.ts.map +1 -0
- package/esm/{NodeHeading.js → extension-basic-editor/src/NodeHeading.js} +3 -3
- package/esm/{NodeHorizontalRule.d.ts → extension-basic-editor/src/NodeHorizontalRule.d.ts} +2 -2
- package/esm/extension-basic-editor/src/NodeHorizontalRule.d.ts.map +1 -0
- package/esm/{NodeHorizontalRule.js → extension-basic-editor/src/NodeHorizontalRule.js} +1 -1
- package/esm/{NodeImage.d.ts → extension-basic-editor/src/NodeImage.d.ts} +2 -2
- package/esm/extension-basic-editor/src/NodeImage.d.ts.map +1 -0
- package/esm/{NodeImage.js → extension-basic-editor/src/NodeImage.js} +1 -1
- package/esm/{NodeListItem.d.ts → extension-basic-editor/src/NodeListItem.d.ts} +2 -2
- package/esm/extension-basic-editor/src/NodeListItem.d.ts.map +1 -0
- package/esm/{NodeListItem.js → extension-basic-editor/src/NodeListItem.js} +1 -1
- package/esm/{NodeOrderedList.d.ts → extension-basic-editor/src/NodeOrderedList.d.ts} +3 -3
- package/esm/extension-basic-editor/src/NodeOrderedList.d.ts.map +1 -0
- package/esm/{NodeOrderedList.js → extension-basic-editor/src/NodeOrderedList.js} +5 -5
- package/esm/{NodeParagraph.d.ts → extension-basic-editor/src/NodeParagraph.d.ts} +2 -2
- package/esm/extension-basic-editor/src/NodeParagraph.d.ts.map +1 -0
- package/esm/{NodeParagraph.js → extension-basic-editor/src/NodeParagraph.js} +2 -2
- package/esm/{NodeText.d.ts → extension-basic-editor/src/NodeText.d.ts} +1 -1
- package/esm/extension-basic-editor/src/NodeText.d.ts.map +1 -0
- package/esm/{NodeText.js → extension-basic-editor/src/NodeText.js} +1 -1
- package/package.json +31 -25
- package/esm/ExtensionBaseKeymap.d.ts +0 -8
- package/esm/ExtensionBaseKeymap.d.ts.map +0 -1
- package/esm/ExtensionBasicEditor.d.ts.map +0 -1
- package/esm/ExtensionDropcursor.d.ts.map +0 -1
- package/esm/ExtensionGapcursor.d.ts.map +0 -1
- package/esm/ExtensionHistory.d.ts.map +0 -1
- package/esm/MarkCode.d.ts.map +0 -1
- package/esm/MarkItalic.d.ts.map +0 -1
- package/esm/MarkLink.d.ts.map +0 -1
- package/esm/MarkStrong.d.ts.map +0 -1
- package/esm/MarkUnderline.d.ts.map +0 -1
- package/esm/NodeAside.d.ts.map +0 -1
- package/esm/NodeBlockquote.d.ts.map +0 -1
- package/esm/NodeBulletList.d.ts.map +0 -1
- package/esm/NodeDocument.d.ts.map +0 -1
- package/esm/NodeHardBreak.d.ts.map +0 -1
- package/esm/NodeHeading.d.ts.map +0 -1
- package/esm/NodeHorizontalRule.d.ts.map +0 -1
- package/esm/NodeImage.d.ts.map +0 -1
- package/esm/NodeListItem.d.ts.map +0 -1
- package/esm/NodeOrderedList.d.ts.map +0 -1
- package/esm/NodeParagraph.d.ts.map +0 -1
- package/esm/NodeText.d.ts.map +0 -1
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
export class SchemaAdapter {
|
|
2
|
+
constructor(schema) {
|
|
3
|
+
Object.defineProperty(this, "nodeMappings", {
|
|
4
|
+
enumerable: true,
|
|
5
|
+
configurable: true,
|
|
6
|
+
writable: true,
|
|
7
|
+
value: void 0
|
|
8
|
+
});
|
|
9
|
+
Object.defineProperty(this, "markMappings", {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
configurable: true,
|
|
12
|
+
writable: true,
|
|
13
|
+
value: void 0
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(this, "unknownBlock", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
configurable: true,
|
|
18
|
+
writable: true,
|
|
19
|
+
value: void 0
|
|
20
|
+
});
|
|
21
|
+
Object.defineProperty(this, "unknownLeaf", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true,
|
|
25
|
+
value: void 0
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(this, "unknownMark", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
configurable: true,
|
|
30
|
+
writable: true,
|
|
31
|
+
value: void 0
|
|
32
|
+
});
|
|
33
|
+
Object.defineProperty(this, "schema", {
|
|
34
|
+
enumerable: true,
|
|
35
|
+
configurable: true,
|
|
36
|
+
writable: true,
|
|
37
|
+
value: void 0
|
|
38
|
+
});
|
|
39
|
+
const nodeMappings = [];
|
|
40
|
+
const markMappings = [];
|
|
41
|
+
let unknownBlock = null;
|
|
42
|
+
for (const [nodeName, nodeSpec] of Object.entries(schema.nodes)) {
|
|
43
|
+
const adaptSpec = nodeSpec.spec.automerge;
|
|
44
|
+
if (adaptSpec == null) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (adaptSpec.unknownBlock) {
|
|
48
|
+
if (unknownBlock != null) {
|
|
49
|
+
throw new Error('only one node can be marked as unknownBlock');
|
|
50
|
+
}
|
|
51
|
+
unknownBlock = schema.nodes[nodeName];
|
|
52
|
+
}
|
|
53
|
+
if (adaptSpec.block != null) {
|
|
54
|
+
const nodeMapping = {
|
|
55
|
+
blockName: adaptSpec.block,
|
|
56
|
+
content: schema.nodes[nodeName],
|
|
57
|
+
isEmbed: adaptSpec.isEmbed || false,
|
|
58
|
+
};
|
|
59
|
+
if (adaptSpec.attrParsers != null) {
|
|
60
|
+
nodeMapping.attrParsers = adaptSpec.attrParsers;
|
|
61
|
+
}
|
|
62
|
+
nodeMappings.push(nodeMapping);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const [markName, markSpec] of Object.entries(schema.marks || {})) {
|
|
66
|
+
const adaptSpec = markSpec.spec.automerge;
|
|
67
|
+
if (adaptSpec == null) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (adaptSpec.markName != null) {
|
|
71
|
+
let parsers;
|
|
72
|
+
if (adaptSpec.parsers != null) {
|
|
73
|
+
parsers = adaptSpec.parsers;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
parsers = {
|
|
77
|
+
fromAutomerge: () => ({}),
|
|
78
|
+
fromProsemirror: () => true,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
markMappings.push({
|
|
82
|
+
automergeMarkName: adaptSpec.markName,
|
|
83
|
+
prosemirrorMark: schema.marks[markName],
|
|
84
|
+
parsers,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (unknownBlock == null) {
|
|
89
|
+
throw new Error(`no unknown block specified: one node must be marked as the unknownblock
|
|
90
|
+
by setting the automerge.unknownBlock property to true`);
|
|
91
|
+
}
|
|
92
|
+
this.unknownMark = schema.marks.unknownMark;
|
|
93
|
+
this.nodeMappings = nodeMappings;
|
|
94
|
+
this.markMappings = markMappings;
|
|
95
|
+
this.unknownLeaf = schema.nodes.unknownLeaf;
|
|
96
|
+
this.unknownBlock = unknownBlock;
|
|
97
|
+
this.schema = schema;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function shallowClone(spec) {
|
|
101
|
+
const nodes = {};
|
|
102
|
+
for (const [nodeName, node] of Object.entries(spec.nodes)) {
|
|
103
|
+
const shallowCopy = Object.assign({}, node);
|
|
104
|
+
if (node.attrs != null) {
|
|
105
|
+
shallowCopy.attrs = Object.assign({}, node.attrs);
|
|
106
|
+
}
|
|
107
|
+
nodes[nodeName] = shallowCopy;
|
|
108
|
+
}
|
|
109
|
+
const marks = {};
|
|
110
|
+
if (spec.marks != null) {
|
|
111
|
+
for (const [markName, mark] of Object.entries(spec.marks)) {
|
|
112
|
+
const shallowCopy = Object.assign({}, mark);
|
|
113
|
+
if (mark.attrs != null) {
|
|
114
|
+
shallowCopy.attrs = Object.assign({}, mark.attrs);
|
|
115
|
+
}
|
|
116
|
+
marks[markName] = shallowCopy;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return { nodes, marks };
|
|
120
|
+
}
|
|
121
|
+
export function addAmgNodeStateAttrs(nodes) {
|
|
122
|
+
for (const [name, nodeSpec] of Object.entries(nodes)) {
|
|
123
|
+
if (name !== 'text') {
|
|
124
|
+
if (nodeSpec.attrs == null) {
|
|
125
|
+
nodeSpec.attrs = {
|
|
126
|
+
isAmgBlock: { default: false },
|
|
127
|
+
unknownAttrs: { default: null },
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
nodeSpec.attrs.isAmgBlock = { default: false };
|
|
132
|
+
nodeSpec.attrs.unknownAttrs = { default: null };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (nodeSpec.automerge?.unknownBlock) {
|
|
136
|
+
if (nodeSpec.attrs == null) {
|
|
137
|
+
nodeSpec.attrs = {
|
|
138
|
+
unknownParentBlock: { default: null },
|
|
139
|
+
unknownBlock: { default: null },
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
nodeSpec.attrs.unknownParentBlock = { default: null };
|
|
144
|
+
nodeSpec.attrs.unknownBlock = { default: null };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return nodes;
|
|
149
|
+
}
|
|
150
|
+
export function amMarksFromPmMarks(adapter, marks) {
|
|
151
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
152
|
+
const result = {};
|
|
153
|
+
marks.forEach((mark) => {
|
|
154
|
+
const markMapping = adapter.markMappings.find((m) => m.prosemirrorMark === mark.type);
|
|
155
|
+
if (markMapping != null) {
|
|
156
|
+
result[markMapping.automergeMarkName] = markMapping.parsers
|
|
157
|
+
.fromProsemirror(mark);
|
|
158
|
+
}
|
|
159
|
+
else if (mark.type === adapter.unknownMark) {
|
|
160
|
+
for (const [key, value] of Object.entries(mark.attrs.unknownMarks)) {
|
|
161
|
+
result[key] = value;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
export function pmMarksFromAmMarks(adapter, amMarks) {
|
|
168
|
+
const unknownMarks = {};
|
|
169
|
+
let hasUnknownMark = false;
|
|
170
|
+
const pmMarks = [];
|
|
171
|
+
for (const [markName, markValue] of Object.entries(amMarks)) {
|
|
172
|
+
// Filter tombstoned marks (https://github.com/automerge/automerge/issues/715).
|
|
173
|
+
if (markValue == null)
|
|
174
|
+
continue;
|
|
175
|
+
const mapping = adapter.markMappings.find((m) => m.automergeMarkName === markName);
|
|
176
|
+
if (mapping == null) {
|
|
177
|
+
unknownMarks[markName] = markValue;
|
|
178
|
+
hasUnknownMark = true;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
pmMarks.push(mapping.prosemirrorMark.create(mapping.parsers.fromAutomerge(markValue)));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (hasUnknownMark) {
|
|
185
|
+
pmMarks.push(adapter.unknownMark.create({ unknownMarks }));
|
|
186
|
+
}
|
|
187
|
+
return pmMarks;
|
|
188
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Plugin, PluginKey } from 'prosemirror-state';
|
|
2
|
+
import { next as automerge } from '@automerge/automerge/slim';
|
|
3
|
+
import { SchemaAdapter } from './SchemaAdapter.js';
|
|
4
|
+
import { DocHandle, DocHandleChangePayload } from './types.js';
|
|
5
|
+
export declare const syncPluginKey: PluginKey<any>;
|
|
6
|
+
export declare class SyncPlugin<T> extends Plugin {
|
|
7
|
+
private adapter;
|
|
8
|
+
private path;
|
|
9
|
+
ignoreTr: boolean;
|
|
10
|
+
onAutoMergeChange: (args: DocHandleChangePayload<unknown>) => void;
|
|
11
|
+
private handle;
|
|
12
|
+
private view;
|
|
13
|
+
constructor(adapter: SchemaAdapter, path: automerge.Prop[], handle: DocHandle<T>);
|
|
14
|
+
changeHandle(handle: DocHandle<any>): void;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=SyncPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SyncPlugin.d.ts","sourceRoot":"","sources":["../../../src/extension-automerge/src/SyncPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAa,MAAM,mBAAmB,CAAC;AAGjE,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI9D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAG/D,eAAO,MAAM,aAAa,gBAAkC,CAAC;AAE7D,qBAAa,UAAU,CAAC,CAAC,CAAE,SAAQ,MAAM;IAQrC,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,IAAI;IARd,QAAQ,UAAS;IACjB,iBAAiB,EAAG,CAAC,IAAI,EAAE,sBAAsB,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IAEpE,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,IAAI,CAAc;gBAGhB,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,EAC9B,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAiGtB,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC;CAwCpC"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { Plugin, PluginKey, Selection } from 'prosemirror-state';
|
|
2
|
+
import { ChangeSet } from 'prosemirror-changeset';
|
|
3
|
+
import { next as automerge } from '@automerge/automerge/slim';
|
|
4
|
+
import { pmToAm } from './pmToAm.js';
|
|
5
|
+
import { amToPm } from './amToPm.js';
|
|
6
|
+
import { amSpansToDoc } from './amTraversal.js';
|
|
7
|
+
import { isArrayEqual } from './utils.js';
|
|
8
|
+
export const syncPluginKey = new PluginKey('automerge-sync');
|
|
9
|
+
export class SyncPlugin extends Plugin {
|
|
10
|
+
constructor(adapter, path, handle) {
|
|
11
|
+
super({
|
|
12
|
+
key: syncPluginKey,
|
|
13
|
+
view: (view) => {
|
|
14
|
+
this.view = view;
|
|
15
|
+
this.changeHandle(handle);
|
|
16
|
+
return {
|
|
17
|
+
destroy: () => {
|
|
18
|
+
if (this.handle) {
|
|
19
|
+
this.handle.off('change', this.onAutoMergeChange);
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
appendTransaction(transactions, oldState, state) {
|
|
25
|
+
if (this.ignoreTr)
|
|
26
|
+
return;
|
|
27
|
+
transactions = transactions.filter((tx) => tx.docChanged);
|
|
28
|
+
if (transactions.length === 0)
|
|
29
|
+
return undefined;
|
|
30
|
+
//eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
31
|
+
const docBefore = this.handle.docSync();
|
|
32
|
+
const headsBefore = automerge.getHeads(docBefore);
|
|
33
|
+
const spansBefore = automerge.spans(docBefore, path);
|
|
34
|
+
// Apply transactions to the automerge doc
|
|
35
|
+
this.ignoreTr = true;
|
|
36
|
+
this.handle.change((doc) => {
|
|
37
|
+
for (const tx of transactions) {
|
|
38
|
+
const spans = automerge.spans(doc, path);
|
|
39
|
+
pmToAm(adapter, spans, tx.steps, doc, tx.docs[0], path);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
this.ignoreTr = false;
|
|
43
|
+
//eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
44
|
+
const docAfter = this.handle.docSync();
|
|
45
|
+
const headsAfter = automerge.getHeads(docAfter);
|
|
46
|
+
const spansAfter = automerge.spans(docAfter, path);
|
|
47
|
+
// Ignore if nothing changed.
|
|
48
|
+
if (isArrayEqual(headsBefore, headsAfter))
|
|
49
|
+
return undefined;
|
|
50
|
+
// Check if ProseMirror doc matches the AutoMerge doc
|
|
51
|
+
// by comparing changesets between the two transactions.
|
|
52
|
+
const patches = automerge.diff(docAfter, headsBefore, headsAfter);
|
|
53
|
+
const tx = amToPm(adapter, spansBefore, patches, path, oldState.tr);
|
|
54
|
+
let amChangeSet = ChangeSet.create(oldState.doc);
|
|
55
|
+
amChangeSet = amChangeSet.addSteps(oldState.doc, tx.mapping.maps, undefined);
|
|
56
|
+
let pmChangeSet = ChangeSet.create(oldState.doc);
|
|
57
|
+
for (const tr of transactions) {
|
|
58
|
+
pmChangeSet = pmChangeSet.addSteps(tr.docs[0], tr.mapping.maps, undefined);
|
|
59
|
+
}
|
|
60
|
+
const diff = pmChangeSet.changedRange(amChangeSet);
|
|
61
|
+
if (!diff || diff.from === diff.to)
|
|
62
|
+
return undefined;
|
|
63
|
+
console.warn("Warning: ProseMirror doc doesn't match AutoMerge spans.\n\n" +
|
|
64
|
+
'State will be automatically fixed with a tr. File an issue at https://github.com/automerge/automerge-repo.\n', {
|
|
65
|
+
spansBefore,
|
|
66
|
+
steps: transactions.map((tr) => tr.steps.map((s) => s.toJSON())),
|
|
67
|
+
});
|
|
68
|
+
// Replace the diff range in ProseMirror doc from the AutoMerge doc.
|
|
69
|
+
const doc = amSpansToDoc(adapter, spansAfter);
|
|
70
|
+
const slice = doc.slice(diff.from, diff.to);
|
|
71
|
+
const tr = state.tr;
|
|
72
|
+
tr.replace(diff.from, diff.to, slice);
|
|
73
|
+
try {
|
|
74
|
+
tr.setSelection(Selection.fromJSON(tr.doc, state.selection.toJSON()));
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
if (e instanceof RangeError) {
|
|
78
|
+
// Sometimes the selection can't be mapped for some reason, so we just give up and hope for the best
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
throw e;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
tr.setStoredMarks(state.storedMarks);
|
|
85
|
+
return tr;
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
Object.defineProperty(this, "adapter", {
|
|
89
|
+
enumerable: true,
|
|
90
|
+
configurable: true,
|
|
91
|
+
writable: true,
|
|
92
|
+
value: adapter
|
|
93
|
+
});
|
|
94
|
+
Object.defineProperty(this, "path", {
|
|
95
|
+
enumerable: true,
|
|
96
|
+
configurable: true,
|
|
97
|
+
writable: true,
|
|
98
|
+
value: path
|
|
99
|
+
});
|
|
100
|
+
Object.defineProperty(this, "ignoreTr", {
|
|
101
|
+
enumerable: true,
|
|
102
|
+
configurable: true,
|
|
103
|
+
writable: true,
|
|
104
|
+
value: false
|
|
105
|
+
});
|
|
106
|
+
Object.defineProperty(this, "onAutoMergeChange", {
|
|
107
|
+
enumerable: true,
|
|
108
|
+
configurable: true,
|
|
109
|
+
writable: true,
|
|
110
|
+
value: void 0
|
|
111
|
+
});
|
|
112
|
+
Object.defineProperty(this, "handle", {
|
|
113
|
+
enumerable: true,
|
|
114
|
+
configurable: true,
|
|
115
|
+
writable: true,
|
|
116
|
+
value: void 0
|
|
117
|
+
});
|
|
118
|
+
Object.defineProperty(this, "view", {
|
|
119
|
+
enumerable: true,
|
|
120
|
+
configurable: true,
|
|
121
|
+
writable: true,
|
|
122
|
+
value: void 0
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
changeHandle(handle) {
|
|
126
|
+
if (!this.view) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (this.handle) {
|
|
130
|
+
this.handle.off('change', this.onAutoMergeChange);
|
|
131
|
+
}
|
|
132
|
+
const onAutoMergeChange = ({ doc, patches, patchInfo, }) => {
|
|
133
|
+
if (this.ignoreTr)
|
|
134
|
+
return;
|
|
135
|
+
const headsBefore = automerge.getHeads(patchInfo.before);
|
|
136
|
+
const spans = automerge.spans(automerge.view(doc, headsBefore), this.path);
|
|
137
|
+
const tr = amToPm(this.adapter, spans, patches, this.path, this.view.state.tr);
|
|
138
|
+
tr.setMeta('addToHistory', false); // remote changes should not be added to local stack
|
|
139
|
+
this.ignoreTr = true;
|
|
140
|
+
this.view.dispatch(tr);
|
|
141
|
+
this.ignoreTr = false;
|
|
142
|
+
};
|
|
143
|
+
this.onAutoMergeChange = onAutoMergeChange;
|
|
144
|
+
handle.on('change', this.onAutoMergeChange);
|
|
145
|
+
this.handle = handle;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { next as automerge, Patch, type Prop } from '@automerge/automerge/slim';
|
|
2
|
+
import { Transaction } from 'prosemirror-state';
|
|
3
|
+
import { SchemaAdapter } from './SchemaAdapter.js';
|
|
4
|
+
type SpliceTextPatch = automerge.SpliceTextPatch;
|
|
5
|
+
export declare function amToPm(adapter: SchemaAdapter, spansAtStart: automerge.Span[], patches: Array<Patch>, path: Prop[], tx: Transaction): Transaction;
|
|
6
|
+
export declare function handleSplice(adapter: SchemaAdapter, spans: automerge.Span[], patch: SpliceTextPatch, path: Prop[], tx: Transaction): Transaction;
|
|
7
|
+
export declare function handleBlockChange(adapter: SchemaAdapter, atPath: automerge.Prop[], spans: automerge.Span[], _blockIdx: number, patches: automerge.Patch[], tx: Transaction): Transaction;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=amToPm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amToPm.d.ts","sourceRoot":"","sources":["../../../src/extension-automerge/src/amToPm.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,IAAI,IAAI,SAAS,EACjB,KAAK,EACL,KAAK,IAAI,EACV,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAMhD,OAAO,EAAsB,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEvE,KAAK,eAAe,GAAG,SAAS,CAAC,eAAe,CAAC;AAQjD,wBAAgB,MAAM,CACpB,OAAO,EAAE,aAAa,EACtB,YAAY,EAAE,SAAS,CAAC,IAAI,EAAE,EAC9B,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,EACrB,IAAI,EAAE,IAAI,EAAE,EACZ,EAAE,EAAE,WAAW,GACd,WAAW,CA0Cb;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,EACvB,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,IAAI,EAAE,EACZ,EAAE,EAAE,WAAW,GACd,WAAW,CAQb;AAkDD,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,EACxB,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,EACvB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,SAAS,CAAC,KAAK,EAAE,EAC1B,EAAE,EAAE,WAAW,GACd,WAAW,CA0Cb"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { Fragment, Slice } from 'prosemirror-model';
|
|
2
|
+
import { ReplaceStep } from 'prosemirror-transform';
|
|
3
|
+
import { amSpansToDoc, amSpliceIdxToPmIdx } from './amTraversal.js';
|
|
4
|
+
import { findBlockAtCharIdx, patchSpans } from './maintainSpans.js';
|
|
5
|
+
import { isArrayEqual, isPrefixOfArray } from './utils.js';
|
|
6
|
+
import { pmMarksFromAmMarks } from './SchemaAdapter.js';
|
|
7
|
+
export function amToPm(adapter, spansAtStart, patches, path, tx) {
|
|
8
|
+
const gathered = gatherPatches(path, patches);
|
|
9
|
+
for (const patchGroup of gathered) {
|
|
10
|
+
if (patchGroup.type === 'text') {
|
|
11
|
+
for (const patch of patchGroup.patches) {
|
|
12
|
+
if (patch.action === 'splice') {
|
|
13
|
+
tx = handleSplice(adapter, spansAtStart, patch, path, tx);
|
|
14
|
+
patchSpans(path, spansAtStart, patch);
|
|
15
|
+
}
|
|
16
|
+
else if (patch.action === 'del') {
|
|
17
|
+
const patchIndex = patch.path[patch.path.length - 1];
|
|
18
|
+
const block = findBlockAtCharIdx(spansAtStart, patchIndex);
|
|
19
|
+
if (block != null) {
|
|
20
|
+
tx = handleBlockChange(adapter, path, spansAtStart, patchIndex, [patch], tx);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
tx = handleDelete(adapter, spansAtStart, patch, path, tx);
|
|
24
|
+
}
|
|
25
|
+
patchSpans(path, spansAtStart, patch);
|
|
26
|
+
}
|
|
27
|
+
else if (patch.action === 'mark') {
|
|
28
|
+
tx = handleMark(adapter, spansAtStart, patch, path, tx);
|
|
29
|
+
patchSpans(path, spansAtStart, patch);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
tx = handleBlockChange(adapter, path, spansAtStart, patchGroup.index, patchGroup.patches, tx);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return tx;
|
|
38
|
+
}
|
|
39
|
+
export function handleSplice(adapter, spans, patch, path, tx) {
|
|
40
|
+
const index = charPath(path, patch.path);
|
|
41
|
+
if (index === null)
|
|
42
|
+
return tx;
|
|
43
|
+
const pmIdx = amSpliceIdxToPmIdx(adapter, spans, index);
|
|
44
|
+
if (pmIdx == null)
|
|
45
|
+
throw new Error('Invalid index');
|
|
46
|
+
const content = patchContentToFragment(adapter, patch.value, patch.marks);
|
|
47
|
+
tx = tx.step(new ReplaceStep(pmIdx, pmIdx, new Slice(content, 0, 0)));
|
|
48
|
+
return tx;
|
|
49
|
+
}
|
|
50
|
+
function handleDelete(adapter, spans, patch, path, tx) {
|
|
51
|
+
const index = charPath(path, patch.path);
|
|
52
|
+
if (index === null)
|
|
53
|
+
return tx;
|
|
54
|
+
const start = amSpliceIdxToPmIdx(adapter, spans, index);
|
|
55
|
+
if (start == null)
|
|
56
|
+
throw new Error('Invalid index');
|
|
57
|
+
const end = start + (patch.length || 1);
|
|
58
|
+
return tx.delete(start, end);
|
|
59
|
+
}
|
|
60
|
+
function handleMark(adapter, spans, patch, path, tx) {
|
|
61
|
+
if (isArrayEqual(patch.path, path)) {
|
|
62
|
+
for (const mark of patch.marks) {
|
|
63
|
+
const pmStart = amSpliceIdxToPmIdx(adapter, spans, mark.start);
|
|
64
|
+
const pmEnd = amSpliceIdxToPmIdx(adapter, spans, mark.end);
|
|
65
|
+
if (pmStart == null || pmEnd == null)
|
|
66
|
+
throw new Error('Invalid index');
|
|
67
|
+
if (mark.value == null) {
|
|
68
|
+
const markMapping = adapter.markMappings.find((m) => m.automergeMarkName === mark.name);
|
|
69
|
+
const markType = markMapping
|
|
70
|
+
? markMapping.prosemirrorMark
|
|
71
|
+
: adapter.unknownMark;
|
|
72
|
+
tx = tx.removeMark(pmStart, pmEnd, markType);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
const pmMarks = pmMarksFromAmMarks(adapter, {
|
|
76
|
+
[mark.name]: mark.value,
|
|
77
|
+
});
|
|
78
|
+
for (const pmMark of pmMarks) {
|
|
79
|
+
tx = tx.addMark(pmStart, pmEnd, pmMark);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return tx;
|
|
85
|
+
}
|
|
86
|
+
export function handleBlockChange(adapter, atPath, spans, _blockIdx, patches, tx) {
|
|
87
|
+
for (const patch of patches) {
|
|
88
|
+
patchSpans(atPath, spans, patch);
|
|
89
|
+
}
|
|
90
|
+
const docAfter = amSpansToDoc(adapter, spans);
|
|
91
|
+
const change = findDiff(tx.doc.content, docAfter.content);
|
|
92
|
+
if (change == null)
|
|
93
|
+
return tx;
|
|
94
|
+
const $from = docAfter.resolve(change.start);
|
|
95
|
+
const $to = docAfter.resolve(change.endB);
|
|
96
|
+
const $fromA = tx.doc.resolve(change.start);
|
|
97
|
+
const inlineChange = $from.sameParent($to) &&
|
|
98
|
+
$from.parent.inlineContent &&
|
|
99
|
+
$fromA.end() >= change.endA;
|
|
100
|
+
const chFrom = change.start;
|
|
101
|
+
const chTo = change.endA;
|
|
102
|
+
let handledByInline = false;
|
|
103
|
+
if (inlineChange) {
|
|
104
|
+
if ($from.pos == $to.pos) {
|
|
105
|
+
// Deletion
|
|
106
|
+
handledByInline = true;
|
|
107
|
+
tx = tx.delete(chFrom, chTo);
|
|
108
|
+
}
|
|
109
|
+
else if ($from.parent.child($from.index()).isText &&
|
|
110
|
+
$from.index() == $to.index() - ($to.textOffset ? 0 : 1)) {
|
|
111
|
+
handledByInline = true;
|
|
112
|
+
// Both positions in the same text node -- simply insert text
|
|
113
|
+
const text = $from.parent.textBetween($from.parentOffset, $to.parentOffset);
|
|
114
|
+
tx = tx.insertText(text, chFrom, chTo);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (!handledByInline) {
|
|
118
|
+
tx = tx.replace(chFrom, chTo, docAfter.slice(change.start, change.endB));
|
|
119
|
+
}
|
|
120
|
+
return tx;
|
|
121
|
+
}
|
|
122
|
+
function findDiff(a, b) {
|
|
123
|
+
let start = a.findDiffStart(b);
|
|
124
|
+
if (start == null)
|
|
125
|
+
return null;
|
|
126
|
+
//eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
127
|
+
let { a: endA, b: endB } = a.findDiffEnd(b);
|
|
128
|
+
if (endA < start && a.size < b.size) {
|
|
129
|
+
if (start &&
|
|
130
|
+
start < b.size &&
|
|
131
|
+
isSurrogatePair(b.textBetween(start - 1, start + 1))) {
|
|
132
|
+
start -= 1;
|
|
133
|
+
}
|
|
134
|
+
endB = start + (endB - endA);
|
|
135
|
+
endA = start;
|
|
136
|
+
}
|
|
137
|
+
else if (endB < start) {
|
|
138
|
+
if (start &&
|
|
139
|
+
start < a.size &&
|
|
140
|
+
isSurrogatePair(a.textBetween(start - 1, start + 1))) {
|
|
141
|
+
start -= 1;
|
|
142
|
+
}
|
|
143
|
+
endA = start + (endA - endB);
|
|
144
|
+
endB = start;
|
|
145
|
+
}
|
|
146
|
+
return { start, endA, endB };
|
|
147
|
+
}
|
|
148
|
+
function isSurrogatePair(str) {
|
|
149
|
+
if (str.length != 2)
|
|
150
|
+
return false;
|
|
151
|
+
const a = str.charCodeAt(0), b = str.charCodeAt(1);
|
|
152
|
+
return a >= 0xdc00 && a <= 0xdfff && b >= 0xd800 && b <= 0xdbff;
|
|
153
|
+
}
|
|
154
|
+
// If the path of the patch is of the form [path, <index>] then we know this is
|
|
155
|
+
// a path to a character within the sequence given by path
|
|
156
|
+
function charPath(textPath, candidatePath) {
|
|
157
|
+
if (candidatePath.length !== textPath.length + 1)
|
|
158
|
+
return null;
|
|
159
|
+
for (let i = 0; i < textPath.length; i++) {
|
|
160
|
+
if (textPath[i] !== candidatePath[i])
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
const index = candidatePath[candidatePath.length - 1];
|
|
164
|
+
if (typeof index === 'number')
|
|
165
|
+
return index;
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
function patchContentToFragment(adapter, patchContent, marks) {
|
|
169
|
+
let pmMarks = undefined;
|
|
170
|
+
if (marks != null) {
|
|
171
|
+
pmMarks = pmMarksFromAmMarks(adapter, marks);
|
|
172
|
+
}
|
|
173
|
+
// Splice is only ever called once a block has already been created so we're
|
|
174
|
+
// only inserting text. This means we don't have to think about openStart
|
|
175
|
+
// and openEnd
|
|
176
|
+
return Fragment.from(adapter.schema.text(patchContent, pmMarks));
|
|
177
|
+
}
|
|
178
|
+
function gatherPatches(textPath, diff) {
|
|
179
|
+
const result = [];
|
|
180
|
+
let state = { type: 'gatheringText', gathered: [] };
|
|
181
|
+
function flush() {
|
|
182
|
+
if (state.type === 'gatheringBlock') {
|
|
183
|
+
result.push({
|
|
184
|
+
type: 'block',
|
|
185
|
+
index: state.index,
|
|
186
|
+
patches: state.gathered,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
else if (state.type === 'gatheringText') {
|
|
190
|
+
result.push({ type: 'text', patches: state.gathered });
|
|
191
|
+
}
|
|
192
|
+
state = { type: 'transitioning' };
|
|
193
|
+
}
|
|
194
|
+
for (const patch of diff) {
|
|
195
|
+
if (!isPrefixOfArray(textPath, patch.path)) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (isArrayEqual(textPath, patch.path) && patch.action === 'mark') {
|
|
199
|
+
if (state.type === 'gatheringText') {
|
|
200
|
+
state.gathered.push(patch);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
flush();
|
|
204
|
+
state = { type: 'gatheringText', gathered: [patch] };
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else if (patch.path.length === textPath.length + 1) {
|
|
208
|
+
const lastElem = patch.path[patch.path.length - 1];
|
|
209
|
+
if (typeof lastElem === 'number') {
|
|
210
|
+
if (patch.action === 'splice' || patch.action === 'del') {
|
|
211
|
+
if (state.type === 'gatheringText') {
|
|
212
|
+
state.gathered.push(patch);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
flush();
|
|
216
|
+
state = { type: 'gatheringText', gathered: [patch] };
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else if (patch.action === 'insert') {
|
|
220
|
+
flush();
|
|
221
|
+
state = {
|
|
222
|
+
type: 'gatheringBlock',
|
|
223
|
+
index: lastElem,
|
|
224
|
+
gathered: [patch],
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
const index = patch.path[textPath.length];
|
|
231
|
+
if (typeof index !== 'number') {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (state.type === 'gatheringBlock' && state.index === index) {
|
|
235
|
+
state.gathered.push(patch);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
flush();
|
|
239
|
+
state = { type: 'gatheringBlock', index: index, gathered: [patch] };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
flush();
|
|
244
|
+
return result;
|
|
245
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { next as automerge } from '@automerge/automerge/slim';
|
|
2
|
+
import { Node } from 'prosemirror-model';
|
|
3
|
+
import { BlockMarker } from './types.js';
|
|
4
|
+
import { SchemaAdapter } from './SchemaAdapter.js';
|
|
5
|
+
type RenderRole = 'explicit' | 'render-only';
|
|
6
|
+
export type TraversalEvent = {
|
|
7
|
+
type: 'openTag';
|
|
8
|
+
tag: string;
|
|
9
|
+
role: RenderRole;
|
|
10
|
+
attrs?: {
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
};
|
|
13
|
+
} | {
|
|
14
|
+
type: 'closeTag';
|
|
15
|
+
tag: string;
|
|
16
|
+
role: RenderRole;
|
|
17
|
+
} | {
|
|
18
|
+
type: 'leafNode';
|
|
19
|
+
tag: string;
|
|
20
|
+
role: RenderRole;
|
|
21
|
+
} | {
|
|
22
|
+
type: 'text';
|
|
23
|
+
text: string;
|
|
24
|
+
marks: automerge.MarkSet;
|
|
25
|
+
} | {
|
|
26
|
+
type: 'block';
|
|
27
|
+
isUnknown?: boolean;
|
|
28
|
+
block: {
|
|
29
|
+
type: string;
|
|
30
|
+
parents: string[];
|
|
31
|
+
attrs: {
|
|
32
|
+
[key: string]: automerge.MaterializeValue;
|
|
33
|
+
};
|
|
34
|
+
isEmbed: boolean;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Convert an array of AutoMerge spans into a ProseMirror doc.
|
|
39
|
+
* @param adapter
|
|
40
|
+
* @param spans
|
|
41
|
+
* @returns
|
|
42
|
+
*/
|
|
43
|
+
export declare function amSpansToDoc(adapter: SchemaAdapter, spans: automerge.Span[]): Node;
|
|
44
|
+
export declare function amSpliceIdxToPmIdx(adapter: SchemaAdapter, spans: automerge.Span[], target: number): number | null;
|
|
45
|
+
export declare function amIdxToPmBlockIdx(adapter: SchemaAdapter, spans: automerge.Span[], target: number): number | null;
|
|
46
|
+
type Indexes = {
|
|
47
|
+
amIdx: number;
|
|
48
|
+
pmIdx: number;
|
|
49
|
+
};
|
|
50
|
+
export declare function eventsWithIndexChanges(events: IterableIterator<TraversalEvent>): IterableIterator<{
|
|
51
|
+
event: TraversalEvent;
|
|
52
|
+
before: Indexes;
|
|
53
|
+
after: Indexes;
|
|
54
|
+
}>;
|
|
55
|
+
export declare function traverseNode(adapter: SchemaAdapter, node: Node): IterableIterator<TraversalEvent>;
|
|
56
|
+
export declare function traverseSpans(adapter: SchemaAdapter, amSpans: automerge.Span[]): IterableIterator<TraversalEvent>;
|
|
57
|
+
export declare function blockAtIdx(spans: automerge.Span[], target: number): {
|
|
58
|
+
index: number;
|
|
59
|
+
block: BlockMarker;
|
|
60
|
+
} | null;
|
|
61
|
+
export {};
|
|
62
|
+
//# sourceMappingURL=amTraversal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amTraversal.d.ts","sourceRoot":"","sources":["../../../src/extension-automerge/src/amTraversal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAGL,IAAI,EAGL,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAgB,WAAW,EAAiB,MAAM,YAAY,CAAC;AACtE,OAAO,EAIL,aAAa,EACd,MAAM,oBAAoB,CAAC;AAE5B,KAAK,UAAU,GAAG,UAAU,GAAG,aAAa,CAAC;AAO7C,MAAM,MAAM,cAAc,GACtB;IACA,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;IAEjB,KAAK,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;CAChC,GACC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC,OAAO,CAAA;CAAE,GACxD;IACA,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,gBAAgB,CAAA;SAAE,CAAC;QACrD,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;CACH,CAAC;AAEJ;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,GACtB,IAAI,CAyDN;AAqCD,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,EACvB,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,IAAI,CAyBf;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,EACvB,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,IAAI,CA4Bf;AAED,KAAK,OAAO,GAAG;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAiB,sBAAsB,CACrC,MAAM,EAAE,gBAAgB,CAAC,cAAc,CAAC,GACvC,gBAAgB,CAAC;IAClB,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC,CA2BD;AAED,wBAAiB,YAAY,CAC3B,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,IAAI,GACT,gBAAgB,CAAC,cAAc,CAAC,CA4ElC;AAwPD,wBAAiB,aAAa,CAC5B,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,SAAS,CAAC,IAAI,EAAE,GACxB,gBAAgB,CAAC,cAAc,CAAC,CAkBlC;AAmOD,wBAAgB,UAAU,CACxB,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,EACvB,MAAM,EAAE,MAAM,GACb;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GAAG,IAAI,CAoB9C"}
|