Diff two Unist trees.
Based on the vtree
diffing algorithm in virtual-dom
,
but for Unist.
One caveat is that “Unist” does not support keys. Keys are what allow
performant reordering of children. To deal with that, unist-diff
uses
“synthetic” keys based on the properties on nodes (excluding their value
or their children). This is not ideal but it’s better than nothing.
Let’s see how it goes!
Installation
npm:
npm install unist-diff
Usage
var h = require('hastscript');
var diff = require('unist-diff');
var left = h('div', [
h('p', [
'Some ',
h('b', 'importance'),
' and ',
h('i', 'emphasis'),
'.'
]),
h('pre', h('code', 'foo()'))
]);
var right = h('div', [
h('p', [
'Some ',
h('strong', 'importance'),
' and ',
h('em', 'emphasis'),
'.'
]),
h('pre', h('code', 'bar()'))
]);
console.dir(diff(left, right), {depth: null});
Yields:
{ '1':
[ { type: 'insert',
left: null,
right:
{ type: 'element',
tagName: 'strong',
properties: {},
children: [ { type: 'text', value: 'importance' } ] } },
{ type: 'insert',
left: null,
right:
{ type: 'element',
tagName: 'em',
properties: {},
children: [ { type: 'text', value: 'emphasis' } ] } } ],
'3':
{ type: 'remove',
left:
{ type: 'element',
tagName: 'b',
properties: {},
children: [ { type: 'text', value: 'importance' } ] },
right: null },
'6':
{ type: 'remove',
left:
{ type: 'element',
tagName: 'i',
properties: {},
children: [ { type: 'text', value: 'emphasis' } ] },
right: null },
'11':
{ type: 'text',
left: { type: 'text', value: 'foo()' },
right: { type: 'text', value: 'bar()' } },
left:
{ type: 'element',
tagName: 'div',
properties: {},
children:
[ { type: 'element',
tagName: 'p',
properties: {},
children:
[ { type: 'text', value: 'Some ' },
{ type: 'element',
tagName: 'b',
properties: {},
children: [ { type: 'text', value: 'importance' } ] },
{ type: 'text', value: ' and ' },
{ type: 'element',
tagName: 'i',
properties: {},
children: [ { type: 'text', value: 'emphasis' } ] },
{ type: 'text', value: '.' } ] },
{ type: 'element',
tagName: 'pre',
properties: {},
children:
[ { type: 'element',
tagName: 'code',
properties: {},
children: [ { type: 'text', value: 'foo()' } ] } ] } ] } }
API
diff(left, right)
Parameters
Returns
Array.<Patch>
— List of one or patch
es.
Patch
Patches represent changes. They come with three properties:
-
type
(string
) — Type of change -
left
(Node
, optional) — Left node -
right
(Node
,PropsDiff
,MoveDiff
, optional) — New thing
remove
-
type
('remove'
) -
left
(Node
) — Left node -
right
(null
)
insert
-
type
('insert'
) -
left
(null
) -
right
(Node
) — Right node
replace
props
text
order
PropsDiff
PropsDiff
is an object mapping keys to new values.
In the diff:
- If a key is removed, the key’s value is set to
undefined
. - If the new value and the old value are both plain objects, the key’s
value is set to a
PropsDiff
of both values. - In all other cases, the key’s value is set to the new value.
MoveDiff
MoveDiff
is an object with two arrays: removes
and inserts
.
They always have equal lengths, and are never both empty. Objects in
inserts
and removes
have the following properties:
-
left
(Node
) — The moved node; -
right
(number
) — The index this node moved from (when inremoves
) or to (when ininserts
).