Skip to content

Commit 286a336

Browse files
committed
feat: Add ability to diff whole nodes as opposed to just descendant trees.
implements #112
1 parent 85f90b4 commit 286a336

File tree

2 files changed

+43
-27
lines changed

2 files changed

+43
-27
lines changed

src/diff.js

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,42 @@ import realNodeMap from './util/real-node-map';
55

66
const { Node } = window;
77

8+
function diffNode (source, destination) {
9+
let nodeInstructions = compareNode(source, destination);
10+
11+
// If there are instructions (even an empty array) it means the node can be
12+
// diffed and doesn't have to be replaced. If the instructions are falsy
13+
// it means that the nodes are not similar (cannot be changed) and must be
14+
// replaced instead.
15+
if (nodeInstructions) {
16+
return nodeInstructions.concat(diff({ source, destination }));
17+
}
18+
19+
return [{
20+
destination,
21+
source,
22+
type: types.REPLACE_CHILD
23+
}];
24+
}
25+
826
export default function diff (opts = {}) {
9-
let src = opts.source;
10-
let dst = opts.destination;
11-
let instructions = [];
27+
const src = opts.source;
28+
const dst = opts.destination;
1229

1330
if (!src || !dst) {
1431
return [];
1532
}
1633

17-
let srcChs = src.childNodes;
18-
let dstChs = dst.childNodes;
19-
let srcChsLen = srcChs ? srcChs.length : 0;
20-
let dstChsLen = dstChs ? dstChs.length : 0;
34+
let instructions = opts.root ? diffNode(src, dst) : [];
35+
36+
const srcChs = src.childNodes;
37+
const dstChs = dst.childNodes;
38+
const srcChsLen = srcChs ? srcChs.length : 0;
39+
const dstChsLen = dstChs ? dstChs.length : 0;
2140

2241
for (let a = 0; a < dstChsLen; a++) {
23-
let curSrc = srcChs[a];
24-
let curDst = dstChs[a];
42+
const curSrc = srcChs[a];
43+
const curDst = dstChs[a];
2544

2645
// If there is no matching destination node it means we need to remove the
2746
// current source node from the source.
@@ -41,24 +60,7 @@ export default function diff (opts = {}) {
4160
}
4261
}
4362

44-
let nodeInstructions = compareNode(curSrc, curDst);
45-
46-
// If there are instructions (even an empty array) it means the node can be
47-
// diffed and doesn't have to be replaced. If the instructions are falsy
48-
// it means that the nodes are not similar (cannot be changed) and must be
49-
// replaced instead.
50-
if (nodeInstructions) {
51-
const newOpts = opts;
52-
newOpts.destination = curDst;
53-
newOpts.source = curSrc;
54-
instructions = instructions.concat(nodeInstructions, diff(newOpts));
55-
} else {
56-
instructions.push({
57-
destination: curDst,
58-
source: curSrc,
59-
type: types.REPLACE_CHILD
60-
});
61-
}
63+
instructions = instructions.concat(diffNode(curSrc, curDst));
6264
}
6365

6466
if (dstChsLen < srcChsLen) {

test/unit.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,20 @@ describe('jsx', function () {
157157
assert.equal(instructions[0].source.tagName, 'SPAN', 'source tagName');
158158
assert.equal(instructions[0].type, types.REPLACE_CHILD, 'type');
159159
});
160+
161+
it('diffing root nodes (as opposed to only decendant trees)', () => {
162+
const root = true;
163+
const source = createElement('div');
164+
const destination = element('div', { test: 'test' });
165+
const instructions = sd.diff({ destination, root, source });
166+
167+
assert.equal(instructions.length, 1, 'should have instructions');
168+
assert.equal(instructions[0].data.name, 'test');
169+
assert.equal(instructions[0].data.value, 'test');
170+
assert.equal(instructions[0].destination, destination);
171+
assert.equal(instructions[0].source, source);
172+
assert.equal(instructions[0].type, types.SET_ATTRIBUTE);
173+
});
160174
});
161175

162176
_describe('patch', function () {

0 commit comments

Comments
 (0)