Skip to content

Commit 4256476

Browse files
Fix ParentNode insertBefore links
1 parent 4873d1b commit 4256476

3 files changed

Lines changed: 69 additions & 0 deletions

File tree

.changeset/young-owls-kick.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@remote-dom/polyfill': patch
3+
---
4+
5+
Fix linked-list corruption when inserting a child before a non-head sibling.

packages/polyfill/source/ParentNode.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ export class ParentNode extends ChildNode {
124124
child[NEXT] = before;
125125
child[PREV] = before[PREV];
126126
if (before[PREV] === null) this[CHILD] = child;
127+
else before[PREV][NEXT] = child;
127128
before[PREV] = child;
128129
} else {
129130
child[NEXT] = null;
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import {Window} from '../index.ts';
2+
3+
import {describe, it, expect, beforeEach} from 'vitest';
4+
5+
describe('ParentNode', () => {
6+
beforeEach(() => {
7+
const window = new Window();
8+
Window.setGlobalThis(window);
9+
});
10+
11+
it('updates sibling links when inserting before a non-head child', () => {
12+
const parent = document.createElement('div');
13+
const first = document.createElement('first');
14+
const second = document.createElement('second');
15+
const third = document.createElement('third');
16+
const inserted = document.createElement('inserted');
17+
18+
parent.append(first, second, third);
19+
parent.insertBefore(inserted, second);
20+
21+
expect([...parent.childNodes]).toStrictEqual([
22+
first,
23+
inserted,
24+
second,
25+
third,
26+
]);
27+
expect(nodesFromSiblingLinks(parent)).toStrictEqual([...parent.childNodes]);
28+
expect(first.nextSibling).toBe(inserted);
29+
expect(inserted.previousSibling).toBe(first);
30+
expect(inserted.nextSibling).toBe(second);
31+
expect(second.previousSibling).toBe(inserted);
32+
});
33+
34+
it('updates sibling links when moving a child before a non-head child', () => {
35+
const parent = document.createElement('div');
36+
const first = document.createElement('first');
37+
const second = document.createElement('second');
38+
const third = document.createElement('third');
39+
const moved = document.createElement('moved');
40+
41+
parent.append(first, second, third, moved);
42+
parent.insertBefore(moved, second);
43+
44+
expect([...parent.childNodes]).toStrictEqual([first, moved, second, third]);
45+
expect(nodesFromSiblingLinks(parent)).toStrictEqual([...parent.childNodes]);
46+
expect(first.nextSibling).toBe(moved);
47+
expect(moved.previousSibling).toBe(first);
48+
expect(moved.nextSibling).toBe(second);
49+
expect(second.previousSibling).toBe(moved);
50+
});
51+
});
52+
53+
function nodesFromSiblingLinks(parent: Node) {
54+
const nodes: Node[] = [];
55+
let node = parent.firstChild;
56+
57+
while (node) {
58+
nodes.push(node);
59+
node = node.nextSibling;
60+
}
61+
62+
return nodes;
63+
}

0 commit comments

Comments
 (0)