@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,54 @@
|
|
|
1
|
+
import { next as automerge } from '@automerge/automerge';
|
|
2
|
+
import { EditorState } from 'prosemirror-state';
|
|
3
|
+
import { pmToAm } from './pmToAm.js';
|
|
4
|
+
function removeMarksRecursively(schema, node) {
|
|
5
|
+
if (node.isText) {
|
|
6
|
+
return schema.text(node.text);
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
const newChildren = [];
|
|
10
|
+
node.content.forEach((child) => {
|
|
11
|
+
newChildren.push(removeMarksRecursively(schema, child));
|
|
12
|
+
});
|
|
13
|
+
return node.copy(node.type.create(null, newChildren).content);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function replaceDocWithoutMarks(oldState, newDoc) {
|
|
17
|
+
const { tr } = oldState;
|
|
18
|
+
const cleanDoc = removeMarksRecursively(oldState.schema, newDoc);
|
|
19
|
+
tr.replaceWith(0, oldState.doc.content.size, cleanDoc.content);
|
|
20
|
+
return tr;
|
|
21
|
+
}
|
|
22
|
+
function addMarksToTransaction(doc, tr) {
|
|
23
|
+
doc.descendants((node, pos) => {
|
|
24
|
+
if (node.isText) {
|
|
25
|
+
for (const mark of node.marks) {
|
|
26
|
+
tr.addMark(pos, pos + node.nodeSize, mark);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export function createEmptyDocFromExisting(doc) {
|
|
32
|
+
return doc.type.createAndFill();
|
|
33
|
+
}
|
|
34
|
+
export function pmDocToAm(basicSchemaAdapter, amDoc, docToLoad, pathToTextField = ['text']) {
|
|
35
|
+
const spans = automerge.spans(amDoc, pathToTextField);
|
|
36
|
+
const emptyDoc = createEmptyDocFromExisting(docToLoad);
|
|
37
|
+
const state = EditorState.create({ doc: emptyDoc });
|
|
38
|
+
const tr = replaceDocWithoutMarks(state, docToLoad);
|
|
39
|
+
addMarksToTransaction(docToLoad, tr);
|
|
40
|
+
return automerge.change(amDoc, (d) => {
|
|
41
|
+
pmToAm(basicSchemaAdapter, spans, tr.steps, d, tr.docs[0], pathToTextField);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
export function pmDocToAmHandle(basicSchemaAdapter, handle, docToLoad, pathToTextField = ['text']) {
|
|
45
|
+
const amDoc = handle.docSync();
|
|
46
|
+
const spans = automerge.spans(amDoc, pathToTextField);
|
|
47
|
+
const emptyDoc = createEmptyDocFromExisting(docToLoad);
|
|
48
|
+
const state = EditorState.create({ doc: emptyDoc });
|
|
49
|
+
const tr = replaceDocWithoutMarks(state, docToLoad);
|
|
50
|
+
addMarksToTransaction(docToLoad, tr);
|
|
51
|
+
handle.change((d) => {
|
|
52
|
+
pmToAm(basicSchemaAdapter, spans, tr.steps, d, tr.docs[0], pathToTextField);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { next as automerge } from '@automerge/automerge/slim';
|
|
2
|
+
export declare function patchSpans(atPath: automerge.Prop[], spans: automerge.Span[], patch: automerge.Patch): void;
|
|
3
|
+
export declare function applyBlockPatch(parentPath: automerge.Prop[], patch: automerge.Patch, block: {
|
|
4
|
+
[key: string]: automerge.MaterializeValue;
|
|
5
|
+
}): void;
|
|
6
|
+
export declare function findBlockAtCharIdx(spans: automerge.Span[], charIdx: number): {
|
|
7
|
+
[key: string]: automerge.MaterializeValue;
|
|
8
|
+
} | null;
|
|
9
|
+
//# sourceMappingURL=maintainSpans.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maintainSpans.d.ts","sourceRoot":"","sources":["../../../src/extension-automerge/src/maintainSpans.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG9D,wBAAgB,UAAU,CACxB,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,EACxB,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,EACvB,KAAK,EAAE,SAAS,CAAC,KAAK,QA+BvB;AA+TD,wBAAgB,eAAe,CAC7B,UAAU,EAAE,SAAS,CAAC,IAAI,EAAE,EAC5B,KAAK,EAAE,SAAS,CAAC,KAAK,EACtB,KAAK,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,gBAAgB,CAAA;CAAE,QAqCrD;AAqFD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,EACvB,OAAO,EAAE,MAAM,GACd;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,gBAAgB,CAAA;CAAE,GAAG,IAAI,CAatD"}
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
import { next as automerge } from '@automerge/automerge/slim';
|
|
2
|
+
import { isArrayEqual, isPrefixOfArray } from './utils.js';
|
|
3
|
+
export function patchSpans(atPath, spans, patch) {
|
|
4
|
+
if (isArrayEqual(atPath, patch.path)) {
|
|
5
|
+
if (patch.action === 'mark') {
|
|
6
|
+
for (const mark of patch.marks) {
|
|
7
|
+
markSpans(spans, mark);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
else if (isPrefixOfArray(atPath, patch.path)) {
|
|
12
|
+
if (patch.path.length === atPath.length + 1) {
|
|
13
|
+
// This is either an insert or delete of a block
|
|
14
|
+
if (patch.action === 'insert') {
|
|
15
|
+
insertBlock(spans, patch);
|
|
16
|
+
}
|
|
17
|
+
else if (patch.action === 'del') {
|
|
18
|
+
deleteSpans(spans, patch);
|
|
19
|
+
}
|
|
20
|
+
else if (patch.action === 'splice') {
|
|
21
|
+
spliceSpans(spans, patch);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
const index = patch.path[atPath.length];
|
|
26
|
+
if (typeof index !== 'number') {
|
|
27
|
+
console.error(`Invalid path: ${patch.path}`);
|
|
28
|
+
throw new Error('Invalid path: expected number when patching spans');
|
|
29
|
+
}
|
|
30
|
+
const block = findBlockAtCharIdx(spans, index);
|
|
31
|
+
if (block == null) {
|
|
32
|
+
throw new Error('Invalid path: unable to find block at index');
|
|
33
|
+
}
|
|
34
|
+
applyBlockPatch(atPath, patch, block);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function spliceSpans(spans, patch) {
|
|
39
|
+
let idx = 0;
|
|
40
|
+
const patchIndex = patch.path[patch.path.length - 1];
|
|
41
|
+
if (typeof patchIndex !== 'number') {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
let spanIdx = 0;
|
|
45
|
+
while (spanIdx < spans.length) {
|
|
46
|
+
const span = spans[spanIdx];
|
|
47
|
+
// Scenarios
|
|
48
|
+
// 1. We are inserting into the range of an existing text span
|
|
49
|
+
// * With the same marks
|
|
50
|
+
// * With different marks
|
|
51
|
+
// 3. We are inserting at the end of an existing text span
|
|
52
|
+
// * With the same marks
|
|
53
|
+
// * With different marks
|
|
54
|
+
// 4. We are inserting into the range of a block
|
|
55
|
+
// 5. We are inserting at the end of a block
|
|
56
|
+
if (span.type === 'text') {
|
|
57
|
+
if (idx <= patchIndex && idx + span.value.length > patchIndex) {
|
|
58
|
+
const offset = patchIndex - idx;
|
|
59
|
+
const before = span.value.slice(0, offset);
|
|
60
|
+
const after = span.value.slice(offset);
|
|
61
|
+
if (marksEqual(span.marks, patch.marks)) {
|
|
62
|
+
span.value = before + patch.value + after;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
const newSpans = [];
|
|
66
|
+
const prevSpan = spans[spanIdx - 1];
|
|
67
|
+
if (before.length === 0 &&
|
|
68
|
+
prevSpan &&
|
|
69
|
+
prevSpan.type === 'text' &&
|
|
70
|
+
marksEqual(prevSpan.marks, patch.marks)) {
|
|
71
|
+
prevSpan.value += patch.value;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
if (before.length > 0) {
|
|
75
|
+
newSpans.push(makeTextSpan({
|
|
76
|
+
value: before,
|
|
77
|
+
marks: span.marks,
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
newSpans.push(makeTextSpan({
|
|
81
|
+
value: patch.value,
|
|
82
|
+
marks: patch.marks,
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
if (after.length > 0) {
|
|
86
|
+
newSpans.push(makeTextSpan({
|
|
87
|
+
value: after,
|
|
88
|
+
marks: span.marks,
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
spans.splice(spanIdx, 1, ...newSpans);
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
idx += span.value.length;
|
|
97
|
+
spanIdx += 1;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
if (idx === patchIndex) {
|
|
102
|
+
const prevSpan = spans[spanIdx - 1];
|
|
103
|
+
if (prevSpan != null &&
|
|
104
|
+
prevSpan.type === 'text' &&
|
|
105
|
+
marksEqual(prevSpan.marks, patch.marks)) {
|
|
106
|
+
// if the block marker is after a text span with the same marks,
|
|
107
|
+
// add this text to that span
|
|
108
|
+
prevSpan.value += patch.value;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
// otherwise insert a text span before the block
|
|
112
|
+
const newSpan = {
|
|
113
|
+
type: 'text',
|
|
114
|
+
value: patch.value,
|
|
115
|
+
};
|
|
116
|
+
if (patch.marks != null) {
|
|
117
|
+
newSpan.marks = patch.marks;
|
|
118
|
+
}
|
|
119
|
+
spans.splice(spanIdx, 0, newSpan);
|
|
120
|
+
}
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
idx += 1;
|
|
124
|
+
spanIdx += 1;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (idx === patchIndex) {
|
|
128
|
+
//we're inserting at the end
|
|
129
|
+
const lastSpan = spans[spans.length - 1];
|
|
130
|
+
if (lastSpan &&
|
|
131
|
+
lastSpan.type === 'text' &&
|
|
132
|
+
marksEqual(lastSpan.marks || {}, patch.marks || {})) {
|
|
133
|
+
lastSpan.value += patch.value;
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
const newSpan = {
|
|
137
|
+
type: 'text',
|
|
138
|
+
value: patch.value,
|
|
139
|
+
};
|
|
140
|
+
if (patch.marks != null) {
|
|
141
|
+
newSpan.marks = patch.marks;
|
|
142
|
+
}
|
|
143
|
+
spans.push(newSpan);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function markSpans(spans, patch) {
|
|
148
|
+
let textPos = 0;
|
|
149
|
+
let i = 0;
|
|
150
|
+
while (i < spans.length) {
|
|
151
|
+
const span = spans[i];
|
|
152
|
+
if (span.type === 'text') {
|
|
153
|
+
const spanStart = textPos;
|
|
154
|
+
const spanEnd = textPos + span.value.length;
|
|
155
|
+
if (spanStart < patch.end && spanEnd > patch.start) {
|
|
156
|
+
const startOffset = Math.max(0, patch.start - spanStart);
|
|
157
|
+
const endOffset = Math.min(span.value.length, patch.end - spanStart);
|
|
158
|
+
if (startOffset > 0) {
|
|
159
|
+
spans.splice(i, 1, makeTextSpan({
|
|
160
|
+
value: span.value.slice(0, startOffset),
|
|
161
|
+
marks: span.marks,
|
|
162
|
+
}), makeTextSpan({
|
|
163
|
+
value: span.value.slice(startOffset, endOffset),
|
|
164
|
+
marks: {
|
|
165
|
+
...span.marks,
|
|
166
|
+
[patch.name]: patch.value,
|
|
167
|
+
},
|
|
168
|
+
}));
|
|
169
|
+
i++;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
spans[i] = makeTextSpan({
|
|
173
|
+
value: span.value.slice(0, endOffset),
|
|
174
|
+
marks: {
|
|
175
|
+
...span.marks,
|
|
176
|
+
[patch.name]: patch.value,
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (endOffset < span.value.length) {
|
|
181
|
+
spans.splice(i + 1, 0, makeTextSpan({
|
|
182
|
+
value: span.value.slice(endOffset),
|
|
183
|
+
marks: span.marks,
|
|
184
|
+
}));
|
|
185
|
+
}
|
|
186
|
+
// Merge with previous span if marks are the same
|
|
187
|
+
const prevSpan = spans[i - 1];
|
|
188
|
+
let thisSpan = spans[i];
|
|
189
|
+
if (i > 0 &&
|
|
190
|
+
prevSpan.type === 'text' &&
|
|
191
|
+
thisSpan.type === 'text' &&
|
|
192
|
+
marksEqual(prevSpan.marks, thisSpan.marks)) {
|
|
193
|
+
prevSpan.value += thisSpan.value;
|
|
194
|
+
spans.splice(i, 1);
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
i++;
|
|
198
|
+
}
|
|
199
|
+
// Merge with next span if marks are the same
|
|
200
|
+
const nextSpan = spans[i + 1];
|
|
201
|
+
thisSpan = spans[i];
|
|
202
|
+
if (i < spans.length - 1 &&
|
|
203
|
+
nextSpan.type === 'text' &&
|
|
204
|
+
thisSpan.type === 'text' &&
|
|
205
|
+
marksEqual(nextSpan.marks, thisSpan.marks)) {
|
|
206
|
+
thisSpan.value += nextSpan.value;
|
|
207
|
+
spans.splice(i + 1, 1);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
i++;
|
|
212
|
+
}
|
|
213
|
+
textPos += span.value.length;
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
i++;
|
|
217
|
+
textPos += 1;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function deleteSpans(spans, patch) {
|
|
222
|
+
const start = patch.path[patch.path.length - 1];
|
|
223
|
+
if (typeof start !== 'number') {
|
|
224
|
+
throw new Error('Invalid path: expected number when deleting spans');
|
|
225
|
+
}
|
|
226
|
+
const end = start + (patch.length || 1);
|
|
227
|
+
let deleteCount = 0;
|
|
228
|
+
// This is always the offset of the start of spans[i] in the _current_ spans
|
|
229
|
+
// (i.e. not the original spans)
|
|
230
|
+
let textPos = 0;
|
|
231
|
+
let i = 0;
|
|
232
|
+
// Returns the amount to rewind `textPos` by
|
|
233
|
+
function mergeSpans(index) {
|
|
234
|
+
const prevSpan = spans[index - 1];
|
|
235
|
+
const thisSpan = spans[index];
|
|
236
|
+
if (prevSpan &&
|
|
237
|
+
prevSpan.type === 'text' &&
|
|
238
|
+
thisSpan &&
|
|
239
|
+
thisSpan.type === 'text' &&
|
|
240
|
+
marksEqual(prevSpan.marks, thisSpan.marks)) {
|
|
241
|
+
const rewind = prevSpan.value.length;
|
|
242
|
+
prevSpan.value += thisSpan.value;
|
|
243
|
+
spans.splice(index, 1);
|
|
244
|
+
return rewind;
|
|
245
|
+
}
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
while (i < spans.length && deleteCount < end - start) {
|
|
249
|
+
const span = spans[i];
|
|
250
|
+
const adjustedEnd = end - deleteCount;
|
|
251
|
+
if (span.type === 'text') {
|
|
252
|
+
const spanStart = textPos;
|
|
253
|
+
const spanEnd = textPos + span.value.length;
|
|
254
|
+
if (spanStart >= start && spanEnd <= adjustedEnd) {
|
|
255
|
+
// Span is fully within the deletion range, remove it
|
|
256
|
+
spans.splice(i, 1);
|
|
257
|
+
deleteCount += span.value.length;
|
|
258
|
+
mergeSpans(i);
|
|
259
|
+
}
|
|
260
|
+
else if (spanStart < adjustedEnd && spanEnd > start) {
|
|
261
|
+
// Span partially overlaps with the deletion range
|
|
262
|
+
const startOffset = Math.max(0, start - spanStart);
|
|
263
|
+
const endOffset = Math.min(span.value.length, adjustedEnd - spanStart);
|
|
264
|
+
if (startOffset > 0 && endOffset < span.value.length) {
|
|
265
|
+
// Split the span into two parts
|
|
266
|
+
spans.splice(i, 1, makeTextSpan({
|
|
267
|
+
value: span.value.slice(0, startOffset),
|
|
268
|
+
marks: span.marks,
|
|
269
|
+
}), makeTextSpan({
|
|
270
|
+
value: span.value.slice(endOffset),
|
|
271
|
+
marks: span.marks,
|
|
272
|
+
}));
|
|
273
|
+
i++;
|
|
274
|
+
(textPos += startOffset), (deleteCount += endOffset - startOffset);
|
|
275
|
+
}
|
|
276
|
+
else if (startOffset > 0) {
|
|
277
|
+
deleteCount += span.value.length - startOffset;
|
|
278
|
+
// Truncate the end of the span
|
|
279
|
+
span.value = span.value.slice(0, startOffset);
|
|
280
|
+
}
|
|
281
|
+
else if (endOffset < span.value.length) {
|
|
282
|
+
deleteCount += endOffset;
|
|
283
|
+
// Truncate the start of the span
|
|
284
|
+
span.value = span.value.slice(endOffset);
|
|
285
|
+
}
|
|
286
|
+
const rewind = mergeSpans(i);
|
|
287
|
+
if (rewind) {
|
|
288
|
+
textPos -= rewind;
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
i++;
|
|
292
|
+
textPos += span.value.length;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
textPos += span.value.length;
|
|
297
|
+
i++;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else if (span.type === 'block') {
|
|
301
|
+
if (textPos >= start && textPos < adjustedEnd) {
|
|
302
|
+
// Block is within the deletion range, remove it
|
|
303
|
+
spans.splice(i, 1);
|
|
304
|
+
deleteCount += 1;
|
|
305
|
+
const rewind = mergeSpans(i);
|
|
306
|
+
if (rewind) {
|
|
307
|
+
i--;
|
|
308
|
+
textPos -= rewind;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
textPos++;
|
|
313
|
+
i++;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
export function applyBlockPatch(parentPath, patch, block) {
|
|
319
|
+
const pathInBlock = patch.path.slice(parentPath.length + 1);
|
|
320
|
+
if (patch.action === 'put') {
|
|
321
|
+
const target = resolveTarget(block, pathInBlock.slice(0, -1));
|
|
322
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
323
|
+
// deno-lint-ignore no-cond-assign
|
|
324
|
+
const key = patch.path[patch.path.length - 1];
|
|
325
|
+
target[key] = copyValue(patch.value);
|
|
326
|
+
}
|
|
327
|
+
else if (patch.action === 'insert') {
|
|
328
|
+
const target = resolveTarget(block, pathInBlock.slice(0, -2));
|
|
329
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
330
|
+
const insertAt = pathInBlock.pop();
|
|
331
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
332
|
+
const prop = pathInBlock.pop();
|
|
333
|
+
const arr = target[prop];
|
|
334
|
+
if (!Array.isArray(arr)) {
|
|
335
|
+
throw new Error('Invalid path: expected array when inserting');
|
|
336
|
+
}
|
|
337
|
+
arr.splice(insertAt, 0, ...copyValues(patch.values));
|
|
338
|
+
}
|
|
339
|
+
else if (patch.action === 'splice') {
|
|
340
|
+
const target = resolveTarget(block, pathInBlock.slice(0, -2));
|
|
341
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
342
|
+
const insertAt = pathInBlock.pop();
|
|
343
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
344
|
+
const prop = pathInBlock.pop();
|
|
345
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
346
|
+
const before = target[prop];
|
|
347
|
+
const after = before.slice(0, insertAt) + patch.value +
|
|
348
|
+
before.slice(insertAt);
|
|
349
|
+
target[prop] = after;
|
|
350
|
+
}
|
|
351
|
+
else if (patch.action === 'del') {
|
|
352
|
+
const target = resolveTarget(block, pathInBlock.slice(0, -1));
|
|
353
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
354
|
+
const key = patch.path[patch.path.length - 1];
|
|
355
|
+
delete target[key];
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
function copyValues(vals) {
|
|
359
|
+
// Copy RawString by value because otherwise instanceof fails
|
|
360
|
+
return vals.map((val) => copyValue(val));
|
|
361
|
+
}
|
|
362
|
+
function copyValue(val) {
|
|
363
|
+
// Copy RawString by value because otherwise instanceof fails
|
|
364
|
+
if (val instanceof automerge.RawString) {
|
|
365
|
+
return new automerge.RawString(val.toString());
|
|
366
|
+
}
|
|
367
|
+
return structuredClone(val);
|
|
368
|
+
}
|
|
369
|
+
function resolveTarget(block, path) {
|
|
370
|
+
let target = block;
|
|
371
|
+
for (const pathElem of path) {
|
|
372
|
+
if (typeof target !== 'object') {
|
|
373
|
+
throw new Error('Invalid path: expected object when resolving target');
|
|
374
|
+
}
|
|
375
|
+
target = target[pathElem];
|
|
376
|
+
}
|
|
377
|
+
return target;
|
|
378
|
+
}
|
|
379
|
+
function insertBlock(spans, patch) {
|
|
380
|
+
let idx = 0;
|
|
381
|
+
let spanIdx = 0;
|
|
382
|
+
const patchIndex = patch.path[patch.path.length - 1];
|
|
383
|
+
if (typeof patchIndex !== 'number') {
|
|
384
|
+
throw new Error(`Invalid patch path, expected a number got ", ${patch.path[patch.path.length - 1]}`);
|
|
385
|
+
}
|
|
386
|
+
const newBlocks = [];
|
|
387
|
+
for (const val of patch.values) {
|
|
388
|
+
if (!val || typeof val !== 'object') {
|
|
389
|
+
throw new Error('Invalid patch: expected object when inserting');
|
|
390
|
+
}
|
|
391
|
+
if (!(Object.keys(val).length === 0)) {
|
|
392
|
+
throw new Error('Invalid patch: unexpected nonempty object when inserting');
|
|
393
|
+
}
|
|
394
|
+
newBlocks.push({
|
|
395
|
+
type: 'block',
|
|
396
|
+
value: {},
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
while (idx < patchIndex && spanIdx < spans.length) {
|
|
400
|
+
const span = spans[spanIdx];
|
|
401
|
+
if (span.type == 'text') {
|
|
402
|
+
if (span.value.length + idx > patchIndex) {
|
|
403
|
+
const offset = patchIndex - idx;
|
|
404
|
+
const left = span.value.slice(0, offset);
|
|
405
|
+
const right = span.value.slice(offset);
|
|
406
|
+
span.value = left;
|
|
407
|
+
spans.splice(spanIdx + 1, 0, ...newBlocks);
|
|
408
|
+
spans.splice(spanIdx + newBlocks.length + 1, 0, {
|
|
409
|
+
type: 'text',
|
|
410
|
+
value: right,
|
|
411
|
+
});
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
idx += span.value.length;
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
idx += 1;
|
|
418
|
+
}
|
|
419
|
+
spanIdx += 1;
|
|
420
|
+
}
|
|
421
|
+
spans.splice(spanIdx, 0, ...newBlocks);
|
|
422
|
+
}
|
|
423
|
+
export function findBlockAtCharIdx(spans, charIdx) {
|
|
424
|
+
let idx = 0;
|
|
425
|
+
for (const span of spans) {
|
|
426
|
+
if (span.type === 'block') {
|
|
427
|
+
if (idx === charIdx) {
|
|
428
|
+
return span.value;
|
|
429
|
+
}
|
|
430
|
+
idx += 1;
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
idx += span.value.length;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
function marksEqual(
|
|
439
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
440
|
+
marks1,
|
|
441
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
442
|
+
marks2) {
|
|
443
|
+
if (marks1 === marks2) {
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
if (!marks1 ||
|
|
447
|
+
!marks2 ||
|
|
448
|
+
Object.keys(marks1).length !== Object.keys(marks2).length) {
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
for (const key in marks1) {
|
|
452
|
+
if (marks1[key] !== marks2[key]) {
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return true;
|
|
457
|
+
}
|
|
458
|
+
function makeTextSpan({ value, marks, }) {
|
|
459
|
+
const result = { type: 'text', value };
|
|
460
|
+
if (marks != null) {
|
|
461
|
+
result.marks = marks;
|
|
462
|
+
}
|
|
463
|
+
return result;
|
|
464
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Step } from 'prosemirror-transform';
|
|
2
|
+
import { Node } from 'prosemirror-model';
|
|
3
|
+
import { next as automerge, Prop } from '@automerge/automerge/slim';
|
|
4
|
+
import { SchemaAdapter } from './SchemaAdapter.js';
|
|
5
|
+
export declare function pmToAm(adapter: SchemaAdapter, spans: automerge.Span[], steps: Step[], doc: any, pmDoc: Node, path: Prop[]): void;
|
|
6
|
+
//# sourceMappingURL=pmToAm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pmToAm.d.ts","sourceRoot":"","sources":["../../../src/extension-automerge/src/pmToAm.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,IAAI,EACL,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAkB,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAEpE,OAAO,EAAsB,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEvE,wBAAgB,MAAM,CACpB,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,EACvB,KAAK,EAAE,IAAI,EAAE,EAEb,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,IAAI,EACX,IAAI,EAAE,IAAI,EAAE,QA4Bb"}
|