Skip to content

Commit 83ef720

Browse files
committed
Fixed node size error for multi-step transaction.
1 parent 39f0eae commit 83ef720

3 files changed

Lines changed: 92 additions & 7 deletions

File tree

src/__tests__/withSuggestChanges.test.ts

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
/* eslint-disable @typescript-eslint/no-non-null-assertion */
32
import { EditorState } from "prosemirror-state";
43
import { Fragment, Slice } from "prosemirror-model";
@@ -38,26 +37,30 @@ describe("withSuggestChanges", () => {
3837
originalTransaction.step(step1);
3938

4039
// Step 2: Replace first "test" with "WORK" in second paragraph
41-
// Use the updated document from the transaction
40+
// Create step with original positions, then map it
4241
const step2 = replaceStep(
43-
originalTransaction.doc,
42+
doc,
4443
doc.tag["c"]!,
4544
doc.tag["d"],
4645
new Slice(Fragment.from(testBuilders.schema.text("WORK")), 0, 0),
4746
) as ReplaceStep | null;
4847
assert(step2, "Could not create step2");
49-
originalTransaction.step(step2);
48+
const mappedStep2 = step2.map(originalTransaction.mapping);
49+
assert(mappedStep2, "Could not map step2");
50+
originalTransaction.step(mappedStep2);
5051

5152
// Step 3: Replace second "test" with "WORK" in second paragraph
52-
// Use the updated document from the transaction
53+
// Create step with original positions, then map it
5354
const step3 = replaceStep(
54-
originalTransaction.doc,
55+
doc,
5556
doc.tag["e"]!,
5657
doc.tag["f"],
5758
new Slice(Fragment.from(testBuilders.schema.text("WORK")), 0, 0),
5859
) as ReplaceStep | null;
5960
assert(step3, "Could not create step3");
60-
originalTransaction.step(step3);
61+
const mappedStep3 = step3.map(originalTransaction.mapping);
62+
assert(mappedStep3, "Could not map step3");
63+
originalTransaction.step(mappedStep3);
6164

6265
// Verify the transaction produces expected result
6366
const originalTrState = editorState.apply(originalTransaction);
@@ -72,6 +75,85 @@ describe("withSuggestChanges", () => {
7275
);
7376
const newState = editorState.apply(suggestedTr);
7477

78+
// Should pass without error - document should be modified
79+
expect(newState.doc.toJSON()).not.toEqual(doc.toJSON());
80+
});
81+
it("shouldn't throw nodeSize errors on multiline edits", () => {
82+
// Create document with all tags for the replacements
83+
const doc = testBuilders.doc(
84+
testBuilders.paragraph({ id: null }, "<a>test<b> <c>test<d>"),
85+
testBuilders.paragraph({ id: null }, "<e>test<f> <g>test<h>"),
86+
) as TaggedNode;
87+
88+
const editorState = EditorState.create({
89+
doc,
90+
plugins: [suggestChanges()],
91+
});
92+
93+
const originalTransaction = editorState.tr;
94+
95+
// Step 1: Replace first "test" with "WORKKKKKKK"
96+
const step1 = replaceStep(
97+
doc,
98+
doc.tag["a"]!,
99+
doc.tag["b"],
100+
new Slice(Fragment.from(testBuilders.schema.text("WORKKKKKKK")), 0, 0),
101+
) as ReplaceStep | null;
102+
assert(step1, "Could not create step1");
103+
originalTransaction.step(step1);
104+
105+
// Step 2: Replace second "test" with "WORKKKKKKK"
106+
// Create step with original positions, then map it
107+
const step2 = replaceStep(
108+
doc,
109+
doc.tag["c"]!,
110+
doc.tag["d"],
111+
new Slice(Fragment.from(testBuilders.schema.text("WORKKKKKKK")), 0, 0),
112+
) as ReplaceStep | null;
113+
assert(step2, "Could not create step2");
114+
const mappedStep2 = step2.map(originalTransaction.mapping);
115+
assert(mappedStep2, "Could not map step2");
116+
originalTransaction.step(mappedStep2);
117+
118+
// Step 3: Replace third "test" with "WORKKKKKKK"
119+
// Create step with original positions, then map it
120+
const step3 = replaceStep(
121+
doc,
122+
doc.tag["e"]!,
123+
doc.tag["f"],
124+
new Slice(Fragment.from(testBuilders.schema.text("WORKKKKKKK")), 0, 0),
125+
) as ReplaceStep | null;
126+
assert(step3, "Could not create step3");
127+
const mappedStep3 = step3.map(originalTransaction.mapping);
128+
assert(mappedStep3, "Could not map step3");
129+
originalTransaction.step(mappedStep3);
130+
131+
// Step 4: Replace fourth "test" with "WORKKKKKKK"
132+
// Create step with original positions, then map it
133+
const step4 = replaceStep(
134+
doc,
135+
doc.tag["g"]!,
136+
doc.tag["h"],
137+
new Slice(Fragment.from(testBuilders.schema.text("WORKKKKKKK")), 0, 0),
138+
) as ReplaceStep | null;
139+
assert(step4, "Could not create step4");
140+
const mappedStep4 = step4.map(originalTransaction.mapping);
141+
assert(mappedStep4, "Could not map step4");
142+
originalTransaction.step(mappedStep4);
143+
144+
// Verify the transaction produces expected result
145+
const originalTrState = editorState.apply(originalTransaction);
146+
expect(originalTrState.doc.textContent).toEqual(
147+
"WORKKKKKKK WORKKKKKKKWORKKKKKKK WORKKKKKKK",
148+
);
149+
150+
// Transform to suggestion transaction
151+
const suggestedTr = transformToSuggestionTransaction(
152+
originalTransaction,
153+
editorState,
154+
);
155+
const newState = editorState.apply(suggestedTr);
156+
75157
// Should pass without error - document should be modified
76158
expect(newState.doc.toJSON()).not.toEqual(doc.toJSON());
77159
});

src/rebasePos.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { type Step } from "prosemirror-transform";
99
*/
1010
export function rebasePos(pos: number, back: Step[], forth: Step[]) {
1111
const reset = back
12+
.slice()
1213
.reverse()
1314
.reduce((acc, step) => step.getMap().invert().map(acc), pos);
1415
return forth.reduce((acc, step) => step.getMap().map(acc), reset);

src/withSuggestChanges.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ function getStepHandler<S extends Step>(step: S): StepHandler<S> {
6666
prevSteps: Step[],
6767
) => {
6868
const reset = prevSteps
69+
.slice()
6970
.reverse()
7071
.reduce<Step | null>(
7172
(acc, step) => acc?.map(step.getMap().invert()) ?? null,
@@ -224,6 +225,7 @@ export function withSuggestChanges(
224225
isSuggestChangesEnabled(this.state) &&
225226
!tr.getMeta("history$") &&
226227
!tr.getMeta("collab$") &&
228+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
227229
!ySyncMeta.isUndoRedoOperation &&
228230
!ySyncMeta.isChangeOrigin &&
229231
!("skip" in (tr.getMeta(suggestChangesKey) ?? {}))

0 commit comments

Comments
 (0)