Moving an existing child can leave its prev and next links pointing to itself even though the serialized HTML looks unchanged. Reproduced on main at 0ab9a8e943bb86704ceb962770bc46647404ea45:
import { load } from 'cheerio';
const $ = load('<main><span id="a"></span><span id="b"></span></main>');
$('main').append($('#b'));
console.log($('#b').prev().attr('id')); // 'b', expected 'a'
console.log($('#b').next().length); // 1, expected 0
console.log($('#a').next().length); // 0, expected 1
The same problem occurs when prepending the first child, inserting an already-adjacent sibling, or wrapping a node with an existing sibling. Moving several children can also produce the wrong order, and empty insertions can break adjacent links.
uniqueSplice chooses neighbors before removing the incoming nodes from their current parents. The proposed fix detaches those nodes first, adjusts the insertion index as each is removed, then reconnects the surrounding nodes, including when the incoming list is empty.
This also reproduces without the changes in #5563. A fix and regression tests are prepared.
Moving an existing child can leave its
prevandnextlinks pointing to itself even though the serialized HTML looks unchanged. Reproduced on main at0ab9a8e943bb86704ceb962770bc46647404ea45:The same problem occurs when prepending the first child, inserting an already-adjacent sibling, or wrapping a node with an existing sibling. Moving several children can also produce the wrong order, and empty insertions can break adjacent links.
uniqueSplicechooses neighbors before removing the incoming nodes from their current parents. The proposed fix detaches those nodes first, adjusts the insertion index as each is removed, then reconnects the surrounding nodes, including when the incoming list is empty.This also reproduces without the changes in #5563. A fix and regression tests are prepared.