Skip to content

Commit c7bf836

Browse files
authored
Fix in-place reverse messing up position rebasing (#16)
1 parent 3b9d823 commit c7bf836

4 files changed

Lines changed: 83 additions & 0 deletions

File tree

.yarn/versions/3b133141.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
releases:
2+
"@handlewithcare/prosemirror-suggest-changes": patch

src/__tests__/withSuggestChanges.test.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,85 @@ describe("withSuggestChanges", () => {
7575
);
7676
const newState = editorState.apply(suggestedTr);
7777

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+
78157
// Should pass without error - document should be modified
79158
expect(newState.doc.toJSON()).not.toEqual(doc.toJSON());
80159
});

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: 1 addition & 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,

0 commit comments

Comments
 (0)