@magic-marker/prosemirror-suggest-changes 0.3.2 → 0.3.3-wrap-unwrap.1
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/dist/__tests__/playwrightPage.d.ts +8 -1
- package/dist/commands.js +132 -41
- package/dist/ensureSelectionPlugin.js +3 -2
- package/dist/features/wrapUnwrap/__tests__/listStructure.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/addIdAttr.d.ts +2 -0
- package/dist/features/wrapUnwrap/addIdAttr.js +62 -0
- package/dist/features/wrapUnwrap/buildMaterializedPaths.d.ts +3 -0
- package/dist/features/wrapUnwrap/buildMaterializedPaths.js +71 -0
- package/dist/features/wrapUnwrap/constants.d.ts +3 -0
- package/dist/features/wrapUnwrap/constants.js +7 -0
- package/dist/features/wrapUnwrap/generateNodeId.d.ts +2 -0
- package/dist/features/wrapUnwrap/generateNodeId.js +6 -0
- package/dist/features/wrapUnwrap/getNodeId.d.ts +2 -0
- package/dist/features/wrapUnwrap/getNodeId.js +5 -0
- package/dist/features/wrapUnwrap/revertStructureSuggestions.d.ts +9 -0
- package/dist/features/wrapUnwrap/revertStructureSuggestions.js +433 -0
- package/dist/features/wrapUnwrap/sameParentChain.d.ts +2 -0
- package/dist/features/wrapUnwrap/sameParentChain.js +4 -0
- package/dist/features/wrapUnwrap/stableNodeIdsPlugin.d.ts +12 -0
- package/dist/features/wrapUnwrap/stableNodeIdsPlugin.js +95 -0
- package/dist/features/wrapUnwrap/structureChangesPlugin.d.ts +7 -0
- package/dist/features/wrapUnwrap/structureChangesPlugin.js +174 -0
- package/dist/features/wrapUnwrap/types.d.ts +45 -0
- package/dist/features/wrapUnwrap/types.js +13 -0
- package/dist/generateId.js +2 -2
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/rebaseStep.d.ts +9 -0
- package/dist/rebaseStep.js +11 -0
- package/dist/replaceStep.d.ts +1 -1
- package/dist/schema.d.ts +2 -1
- package/dist/schema.js +37 -1
- package/dist/testing/e2eTestSchema.d.ts +2 -0
- package/dist/testing/testBuilders.d.ts +1 -2
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +6 -2
- package/dist/withSuggestChanges.d.ts +5 -1
- package/dist/withSuggestChanges.js +39 -2
- package/package.json +2 -2
- package/src/features/wrapUnwrap/README.md +127 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type Locator, type Page } from "@playwright/test";
|
|
2
2
|
export declare class EditorPage {
|
|
3
3
|
readonly page: Page;
|
|
4
|
+
readonly deletionMarksVisibility: "hidden" | "visible";
|
|
4
5
|
private readonly selectors;
|
|
5
|
-
constructor(page: Page);
|
|
6
|
+
constructor(page: Page, deletionMarksVisibility?: "hidden" | "visible");
|
|
6
7
|
get editor(): Locator;
|
|
7
8
|
getParagraphText(index: number): Promise<string>;
|
|
8
9
|
getParagraphCount(): Promise<number>;
|
|
@@ -12,4 +13,10 @@ export declare class EditorPage {
|
|
|
12
13
|
head: number;
|
|
13
14
|
}>;
|
|
14
15
|
getDOMTextContentOfChildAtIndex(index: number): Promise<string>;
|
|
16
|
+
getDocJSON(): Promise<object>;
|
|
17
|
+
getCurrentAndExpectedDoc(expectedDocJSON: object): Promise<{
|
|
18
|
+
currentDoc: import("prosemirror-model").Node;
|
|
19
|
+
expectedDoc: import("prosemirror-model").Node;
|
|
20
|
+
}>;
|
|
21
|
+
revertAll(): Promise<void>;
|
|
15
22
|
}
|
package/dist/commands.js
CHANGED
|
@@ -5,6 +5,7 @@ import { suggestChangesKey } from "./plugin.js";
|
|
|
5
5
|
import { getSuggestionMarks } from "./utils.js";
|
|
6
6
|
import { ZWSP } from "./constants.js";
|
|
7
7
|
import { maybeRevertJoinMark } from "./features/joinOnDelete/index.js";
|
|
8
|
+
import { applyAllStructureSuggestions, applyAllStructureSuggestionsOnNode, applyOneStructureSuggestion, revertAllStructureSuggestions, revertAllStructureSuggestionsOnNode, revertOneStructureSuggestion } from "./features/wrapUnwrap/revertStructureSuggestions.js";
|
|
8
9
|
/**
|
|
9
10
|
* Given a node and a transform, add a set of steps to the
|
|
10
11
|
* transform that applies all marks of type markTypeToApply
|
|
@@ -134,20 +135,34 @@ function applyModificationsToTransform(node, tr, dir, suggestionId, from, to) {
|
|
|
134
135
|
}
|
|
135
136
|
export function applySuggestionsToNode(node) {
|
|
136
137
|
const { deletion, insertion } = getSuggestionMarks(node.type.schema);
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
// first, create a structure transform that applies all structure changes on the given node
|
|
139
|
+
const structureTransform = applyAllStructureSuggestionsOnNode(node);
|
|
140
|
+
// then start a clear transform from the document where the structure changes are applied
|
|
141
|
+
const suggestionsTransform = new Transform(structureTransform.doc);
|
|
142
|
+
applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, insertion, deletion);
|
|
143
|
+
applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, 1);
|
|
144
|
+
// replay suggestion transform on top of the structure transform
|
|
145
|
+
suggestionsTransform.steps.forEach((step)=>{
|
|
146
|
+
structureTransform.step(step);
|
|
147
|
+
});
|
|
148
|
+
return structureTransform.doc;
|
|
141
149
|
}
|
|
142
150
|
export function applySuggestionsToRange(doc, from, to) {
|
|
151
|
+
const { deletion, insertion } = getSuggestionMarks(doc.type.schema);
|
|
143
152
|
// blockRange can only return null if a predicate is provided
|
|
144
153
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
145
154
|
const nodeRange = doc.resolve(from).blockRange(doc.resolve(to));
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
155
|
+
// create a structure transform that applies all structure changes on the given node range
|
|
156
|
+
const structureTransform = applyAllStructureSuggestionsOnNode(doc, nodeRange.start, nodeRange.end);
|
|
157
|
+
// then start a clear transform from the document where the structure changes are applied
|
|
158
|
+
const suggestionsTransform = new Transform(structureTransform.doc);
|
|
159
|
+
applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, insertion, deletion, undefined, nodeRange.start, nodeRange.end);
|
|
160
|
+
applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, 1, undefined, nodeRange.start, nodeRange.end);
|
|
161
|
+
// replay suggestion transform on top of the structure transform
|
|
162
|
+
suggestionsTransform.steps.forEach((step)=>{
|
|
163
|
+
structureTransform.step(step);
|
|
164
|
+
});
|
|
165
|
+
return structureTransform.doc.slice(structureTransform.mapping.map(from), structureTransform.mapping.map(to));
|
|
151
166
|
}
|
|
152
167
|
/**
|
|
153
168
|
* Command that applies all tracked changes in a document.
|
|
@@ -157,13 +172,26 @@ export function applySuggestionsToRange(doc, from, to) {
|
|
|
157
172
|
* contents left in the doc.
|
|
158
173
|
*/ export function applySuggestions(state, dispatch) {
|
|
159
174
|
const { deletion, insertion } = getSuggestionMarks(state.schema);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
175
|
+
// create a structure transform that applies all structure changes on the given document
|
|
176
|
+
const structureTransform = applyAllStructureSuggestions(state.doc);
|
|
177
|
+
// then start a clear transform from the document where the structure changes are applied
|
|
178
|
+
const suggestionsTransform = new Transform(structureTransform.doc);
|
|
179
|
+
applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, insertion, deletion);
|
|
180
|
+
applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, 1);
|
|
181
|
+
// replay suggestion transform on top of the structure transform
|
|
182
|
+
suggestionsTransform.steps.forEach((step)=>{
|
|
183
|
+
structureTransform.step(step);
|
|
184
|
+
});
|
|
185
|
+
// apply the structure transform to the transaction
|
|
186
|
+
const transaction = state.tr;
|
|
187
|
+
structureTransform.steps.forEach((step)=>{
|
|
188
|
+
transaction.step(step);
|
|
189
|
+
});
|
|
190
|
+
if (!transaction.steps.length) return false;
|
|
191
|
+
transaction.setMeta(suggestChangesKey, {
|
|
164
192
|
skip: true
|
|
165
193
|
});
|
|
166
|
-
dispatch?.(
|
|
194
|
+
dispatch?.(transaction);
|
|
167
195
|
return true;
|
|
168
196
|
}
|
|
169
197
|
/**
|
|
@@ -175,13 +203,26 @@ export function applySuggestionsToRange(doc, from, to) {
|
|
|
175
203
|
*/ export function applySuggestionsInRange(from, to) {
|
|
176
204
|
return (state, dispatch)=>{
|
|
177
205
|
const { deletion, insertion } = getSuggestionMarks(state.schema);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
206
|
+
// create a structure transform that applies all structure changes on the given node range
|
|
207
|
+
const structureTransform = applyAllStructureSuggestionsOnNode(state.doc, from, to);
|
|
208
|
+
// then start a clear transform from the document where the structure changes are applied
|
|
209
|
+
const suggestionsTransform = new Transform(structureTransform.doc);
|
|
210
|
+
applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, insertion, deletion, undefined, from, to);
|
|
211
|
+
applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, 1, undefined, from, to);
|
|
212
|
+
// replay suggestion transform on top of the structure transform
|
|
213
|
+
suggestionsTransform.steps.forEach((step)=>{
|
|
214
|
+
structureTransform.step(step);
|
|
215
|
+
});
|
|
216
|
+
// apply the structure transform to the transaction
|
|
217
|
+
const transaction = state.tr;
|
|
218
|
+
structureTransform.steps.forEach((step)=>{
|
|
219
|
+
transaction.step(step);
|
|
220
|
+
});
|
|
221
|
+
if (!transaction.steps.length) return false;
|
|
222
|
+
transaction.setMeta(suggestChangesKey, {
|
|
182
223
|
skip: true
|
|
183
224
|
});
|
|
184
|
-
dispatch?.(
|
|
225
|
+
dispatch?.(transaction);
|
|
185
226
|
return true;
|
|
186
227
|
};
|
|
187
228
|
}
|
|
@@ -194,14 +235,26 @@ export function applySuggestionsToRange(doc, from, to) {
|
|
|
194
235
|
*/ export function applySuggestion(suggestionId, from, to) {
|
|
195
236
|
return (state, dispatch)=>{
|
|
196
237
|
const { deletion, insertion } = getSuggestionMarks(state.schema);
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
238
|
+
// create a structure transform that applies the given structure change on the given node
|
|
239
|
+
const structureTransform = applyOneStructureSuggestion(state.doc, suggestionId);
|
|
240
|
+
// then start a clear transform from the document where the structure changes are applied
|
|
241
|
+
const suggestionsTransform = new Transform(structureTransform.doc);
|
|
242
|
+
applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, insertion, deletion, suggestionId, from, to);
|
|
243
|
+
applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, 1, undefined, from, to);
|
|
244
|
+
// replay suggestion transform on top of the structure transform
|
|
245
|
+
suggestionsTransform.steps.forEach((step)=>{
|
|
246
|
+
structureTransform.step(step);
|
|
247
|
+
});
|
|
248
|
+
// apply the structure transform to the transaction
|
|
249
|
+
const transaction = state.tr;
|
|
250
|
+
structureTransform.steps.forEach((step)=>{
|
|
251
|
+
transaction.step(step);
|
|
252
|
+
});
|
|
253
|
+
if (!transaction.steps.length) return false;
|
|
254
|
+
transaction.setMeta(suggestChangesKey, {
|
|
202
255
|
skip: true
|
|
203
256
|
});
|
|
204
|
-
dispatch?.(
|
|
257
|
+
dispatch?.(transaction);
|
|
205
258
|
return true;
|
|
206
259
|
};
|
|
207
260
|
}
|
|
@@ -213,13 +266,26 @@ export function applySuggestionsToRange(doc, from, to) {
|
|
|
213
266
|
* Modifications tracked in modification marks will be reverted.
|
|
214
267
|
*/ export function revertSuggestions(state, dispatch) {
|
|
215
268
|
const { deletion, insertion } = getSuggestionMarks(state.schema);
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
269
|
+
// create a structure transform that reverts all structure changes on the given document
|
|
270
|
+
const structureTransform = revertAllStructureSuggestions(state.doc);
|
|
271
|
+
// then start a clear transform from the document where the structure changes are reverted
|
|
272
|
+
const suggestionsTransform = new Transform(structureTransform.doc);
|
|
273
|
+
applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, deletion, insertion);
|
|
274
|
+
applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, -1);
|
|
275
|
+
// replay suggestion transform on top of the structure transform
|
|
276
|
+
suggestionsTransform.steps.forEach((step)=>{
|
|
277
|
+
structureTransform.step(step);
|
|
278
|
+
});
|
|
279
|
+
// apply the structure transform to the transaction
|
|
280
|
+
const transaction = state.tr;
|
|
281
|
+
structureTransform.steps.forEach((step)=>{
|
|
282
|
+
transaction.step(step);
|
|
283
|
+
});
|
|
284
|
+
if (!transaction.steps.length) return false;
|
|
285
|
+
transaction.setMeta(suggestChangesKey, {
|
|
220
286
|
skip: true
|
|
221
287
|
});
|
|
222
|
-
dispatch?.(
|
|
288
|
+
dispatch?.(transaction);
|
|
223
289
|
return true;
|
|
224
290
|
}
|
|
225
291
|
/**
|
|
@@ -231,13 +297,26 @@ export function applySuggestionsToRange(doc, from, to) {
|
|
|
231
297
|
*/ export function revertSuggestionsInRange(from, to) {
|
|
232
298
|
return (state, dispatch)=>{
|
|
233
299
|
const { deletion, insertion } = getSuggestionMarks(state.schema);
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
300
|
+
// create a structure transform that reverts all structure changes on the given node range
|
|
301
|
+
const structureTransform = revertAllStructureSuggestionsOnNode(state.doc, from, to);
|
|
302
|
+
// then start a clear transform from the document where the structure changes are reverted
|
|
303
|
+
const suggestionsTransform = new Transform(structureTransform.doc);
|
|
304
|
+
applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, deletion, insertion, undefined, from, to);
|
|
305
|
+
applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, -1, undefined, from, to);
|
|
306
|
+
// replay suggestion transform on top of the structure transform
|
|
307
|
+
suggestionsTransform.steps.forEach((step)=>{
|
|
308
|
+
structureTransform.step(step);
|
|
309
|
+
});
|
|
310
|
+
// apply the structure transform to the transaction
|
|
311
|
+
const transaction = state.tr;
|
|
312
|
+
structureTransform.steps.forEach((step)=>{
|
|
313
|
+
transaction.step(step);
|
|
314
|
+
});
|
|
315
|
+
if (!transaction.steps.length) return false;
|
|
316
|
+
transaction.setMeta(suggestChangesKey, {
|
|
238
317
|
skip: true
|
|
239
318
|
});
|
|
240
|
-
dispatch?.(
|
|
319
|
+
dispatch?.(transaction);
|
|
241
320
|
return true;
|
|
242
321
|
};
|
|
243
322
|
}
|
|
@@ -250,14 +329,26 @@ export function applySuggestionsToRange(doc, from, to) {
|
|
|
250
329
|
*/ export function revertSuggestion(suggestionId, from, to) {
|
|
251
330
|
return (state, dispatch)=>{
|
|
252
331
|
const { deletion, insertion } = getSuggestionMarks(state.schema);
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
332
|
+
// create a structure transform that reverts the given structure change on the given node
|
|
333
|
+
const structureTransform = revertOneStructureSuggestion(state.doc, suggestionId);
|
|
334
|
+
// then start a clear transform from the document where the structure changes are reverted
|
|
335
|
+
const suggestionsTransform = new Transform(structureTransform.doc);
|
|
336
|
+
applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, deletion, insertion, suggestionId, from, to);
|
|
337
|
+
applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, -1, undefined, from, to);
|
|
338
|
+
// replay suggestion transform on top of the structure transform
|
|
339
|
+
suggestionsTransform.steps.forEach((step)=>{
|
|
340
|
+
structureTransform.step(step);
|
|
341
|
+
});
|
|
342
|
+
// apply the structure transform to the transaction
|
|
343
|
+
const transaction = state.tr;
|
|
344
|
+
structureTransform.steps.forEach((step)=>{
|
|
345
|
+
transaction.step(step);
|
|
346
|
+
});
|
|
347
|
+
if (!transaction.steps.length) return false;
|
|
348
|
+
transaction.setMeta(suggestChangesKey, {
|
|
257
349
|
skip: true
|
|
258
350
|
});
|
|
259
|
-
|
|
260
|
-
dispatch?.(tr);
|
|
351
|
+
dispatch?.(transaction);
|
|
261
352
|
return true;
|
|
262
353
|
};
|
|
263
354
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Plugin, PluginKey, TextSelection } from "prosemirror-state";
|
|
2
2
|
import { getSuggestionMarks } from "./utils.js";
|
|
3
3
|
import { ZWSP } from "./constants.js";
|
|
4
|
-
const TRACE_ENABLED =
|
|
4
|
+
const TRACE_ENABLED = true;
|
|
5
5
|
function trace(...args) {
|
|
6
6
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
7
7
|
if (!TRACE_ENABLED) return;
|
|
@@ -48,6 +48,7 @@ export function ensureSelection() {
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
appendTransaction (_transactions, oldState, newState) {
|
|
51
|
+
console.log("ensureSelectionPlugin.appendTransaction", newState.selection.toJSON());
|
|
51
52
|
const pluginState = ensureSelectionKey.getState(newState);
|
|
52
53
|
if (!(newState.selection instanceof TextSelection)) {
|
|
53
54
|
return null;
|
|
@@ -63,7 +64,7 @@ export function ensureSelection() {
|
|
|
63
64
|
$newAnchor
|
|
64
65
|
});
|
|
65
66
|
trace("appendTransaction", "search for new valid $head...");
|
|
66
|
-
let $newHead = getNewValidPos(newState.selection.$head, getDirection(oldState.selection.$head, newState.selection.$head, pluginState));
|
|
67
|
+
let $newHead = newState.selection.empty ? $newAnchor : getNewValidPos(newState.selection.$head, getDirection(oldState.selection.$head, newState.selection.$head, pluginState));
|
|
67
68
|
trace("appendTransaction", "new valid $head", $newHead?.pos, {
|
|
68
69
|
$newHead
|
|
69
70
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export const addIdAttr = (nodeSpec, key)=>{
|
|
2
|
+
const { toDOM, parseDOM } = nodeSpec;
|
|
3
|
+
if (!toDOM || !parseDOM) {
|
|
4
|
+
console.warn("addIdAttr", "ignored node", key, "with nodeSpec", nodeSpec);
|
|
5
|
+
return nodeSpec;
|
|
6
|
+
}
|
|
7
|
+
const newNodeSpec = {
|
|
8
|
+
...nodeSpec,
|
|
9
|
+
attrs: {
|
|
10
|
+
...nodeSpec.attrs ?? {},
|
|
11
|
+
id: {
|
|
12
|
+
default: null
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
toDOM (node) {
|
|
16
|
+
const domOutputSpec = toDOM(node);
|
|
17
|
+
if (!Array.isArray(domOutputSpec)) {
|
|
18
|
+
console.warn("addIdAttr", "domOutputSpec is not an array, id is not added", domOutputSpec);
|
|
19
|
+
return domOutputSpec;
|
|
20
|
+
}
|
|
21
|
+
const id = typeof node.attrs["id"] === "string" ? node.attrs["id"] : null;
|
|
22
|
+
const attrs = domOutputSpec[1];
|
|
23
|
+
if (!Array.isArray(attrs) && typeof attrs === "object" && attrs !== null) {
|
|
24
|
+
const theRest = domOutputSpec.slice(2);
|
|
25
|
+
const result = [
|
|
26
|
+
domOutputSpec[0],
|
|
27
|
+
id ? {
|
|
28
|
+
...attrs,
|
|
29
|
+
"data-id": id
|
|
30
|
+
} : attrs,
|
|
31
|
+
...theRest
|
|
32
|
+
];
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
const theRest = domOutputSpec.slice(1);
|
|
36
|
+
const result = [
|
|
37
|
+
domOutputSpec[0],
|
|
38
|
+
id ? {
|
|
39
|
+
"data-id": id
|
|
40
|
+
} : {},
|
|
41
|
+
...theRest
|
|
42
|
+
];
|
|
43
|
+
return result;
|
|
44
|
+
},
|
|
45
|
+
parseDOM: [
|
|
46
|
+
...parseDOM.map((tagParseRule)=>({
|
|
47
|
+
...tagParseRule,
|
|
48
|
+
getAttrs (dom) {
|
|
49
|
+
const id = dom.getAttribute("data-id");
|
|
50
|
+
return tagParseRule.getAttrs ? {
|
|
51
|
+
...tagParseRule.getAttrs(dom),
|
|
52
|
+
id
|
|
53
|
+
} : {
|
|
54
|
+
id
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}))
|
|
58
|
+
]
|
|
59
|
+
};
|
|
60
|
+
console.info("addIdAttr", "adding id to node", key, "with nodeSpec", nodeSpec, "new nodeSpec", newNodeSpec);
|
|
61
|
+
return newNodeSpec;
|
|
62
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { getNodeId } from "./getNodeId.js";
|
|
2
|
+
export function buildMaterializedPaths(doc) {
|
|
3
|
+
const paths = new Map();
|
|
4
|
+
// add direct doc children first since they have a specific parent signature due to doc not having an ID
|
|
5
|
+
doc.children.forEach((node, index, children)=>{
|
|
6
|
+
const nodeId = getNodeId(node);
|
|
7
|
+
if (nodeId == null) return;
|
|
8
|
+
const leftSibling = children[index - 1];
|
|
9
|
+
const leftSiblingId = leftSibling ? getNodeId(leftSibling) : null;
|
|
10
|
+
const rightSibling = children[index + 1];
|
|
11
|
+
const rightSiblingId = rightSibling ? getNodeId(rightSibling) : null;
|
|
12
|
+
const parent = {
|
|
13
|
+
nodeId: "__doc__",
|
|
14
|
+
nodeType: "__doc__",
|
|
15
|
+
nodeAttrs: {},
|
|
16
|
+
nodeMarks: [],
|
|
17
|
+
childSiblingIds: [
|
|
18
|
+
leftSiblingId,
|
|
19
|
+
rightSiblingId
|
|
20
|
+
],
|
|
21
|
+
childIndex: index
|
|
22
|
+
};
|
|
23
|
+
paths.set(nodeId, {
|
|
24
|
+
nodeType: node.type.name,
|
|
25
|
+
chain: [
|
|
26
|
+
parent
|
|
27
|
+
]
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
// now add the rest of the nodes
|
|
31
|
+
doc.descendants((node, _pos, parent, childIndex)=>{
|
|
32
|
+
if (node.isText) return false;
|
|
33
|
+
const nodeId = getNodeId(node);
|
|
34
|
+
if (nodeId == null) return true;
|
|
35
|
+
// this is to avoid processing direct doc children twice
|
|
36
|
+
if (paths.has(nodeId)) return true;
|
|
37
|
+
if (parent == null) return true;
|
|
38
|
+
const parentId = getNodeId(parent);
|
|
39
|
+
if (parentId == null) return true;
|
|
40
|
+
// by definition, for any node it's parent chain should already exist
|
|
41
|
+
// because we go downwards
|
|
42
|
+
const parentChain = paths.get(parentId);
|
|
43
|
+
if (parentChain == null) return true;
|
|
44
|
+
const leftSibling = parent.children[childIndex - 1];
|
|
45
|
+
const leftSiblingId = leftSibling ? getNodeId(leftSibling) : null;
|
|
46
|
+
const rightSibling = parent.children[childIndex + 1];
|
|
47
|
+
const rightSiblingId = rightSibling ? getNodeId(rightSibling) : null;
|
|
48
|
+
// (this node parent chain) is (parent chain of the parent node) + (the parent node itself)
|
|
49
|
+
const parentDesc = {
|
|
50
|
+
nodeId: parentId,
|
|
51
|
+
nodeType: parent.type.name,
|
|
52
|
+
nodeAttrs: parent.attrs,
|
|
53
|
+
nodeMarks: parent.marks.map((mark)=>mark.toJSON()),
|
|
54
|
+
childSiblingIds: [
|
|
55
|
+
leftSiblingId,
|
|
56
|
+
rightSiblingId
|
|
57
|
+
],
|
|
58
|
+
childIndex: childIndex
|
|
59
|
+
};
|
|
60
|
+
const chain = [
|
|
61
|
+
parentDesc,
|
|
62
|
+
...parentChain.chain
|
|
63
|
+
];
|
|
64
|
+
paths.set(nodeId, {
|
|
65
|
+
nodeType: node.type.name,
|
|
66
|
+
chain
|
|
67
|
+
});
|
|
68
|
+
return true;
|
|
69
|
+
});
|
|
70
|
+
return paths;
|
|
71
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */ export function generateNodeId(_node, _pos, _parent, _index) {
|
|
2
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
3
|
+
return crypto.randomUUID();
|
|
4
|
+
}
|
|
5
|
+
return `node-${Math.random().toString(36).slice(2)}`;
|
|
6
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Node } from "prosemirror-model";
|
|
2
|
+
import { Transform } from "prosemirror-transform";
|
|
3
|
+
import { type SuggestionId } from "../../generateId.js";
|
|
4
|
+
export declare function applyAllStructureSuggestions(node: Node): Transform;
|
|
5
|
+
export declare function revertAllStructureSuggestions(node: Node): Transform;
|
|
6
|
+
export declare function applyOneStructureSuggestion(node: Node, suggestionId: SuggestionId): Transform;
|
|
7
|
+
export declare function revertOneStructureSuggestion(node: Node, suggestionId: SuggestionId): Transform;
|
|
8
|
+
export declare function applyAllStructureSuggestionsOnNode(node: Node, from?: number, to?: number): Transform;
|
|
9
|
+
export declare function revertAllStructureSuggestionsOnNode(node: Node, from?: number, to?: number): Transform;
|