unified

Project: syntax-tree/unist-diff

Package: unist-diff@2.0.0

  1. Diff two unist trees
  1. unist 132
  2. tree 44
  3. node 24
  4. diff 2

unist-diff

Build Coverage Downloads Size Sponsors Backers Chat

unist utility to diff two trees.

Based on the vtree diffing algorithm in virtual-dom, but for Unist.

‼️ Work in progress / unstable / broken / experimental

See preliminary docs

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!

Install

npm:

npm install unist-diff

Use

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: Node // Reference to the tree at `left`.
}

API

diff(left, right)

Diff two trees.

Parameters
  • left (Node) — Left tree
  • right (Node) — Right tree
Returns

Object.<Patch|Patches> — Object mapping indices of nodes to one or more patches.

Patch

Patches represent changes. They come with three properties:

  • type (string) — Type of change (either 'remove', 'insert', 'replace', 'props', 'text', or 'order')
  • 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

  • type ('node')
  • left (Node) — Left node
  • right (Node) — Right node

props

text

  • type ('text')
  • left (Node) — Left node
  • right (Node) — Right node

order

  • type ('order')
  • left (Node) — Parent node
  • right (MoveDiff) — Reorder

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 in removes) or to (when in inserts)

Contribute

See contributing.md in syntax-tree/.github for ways to get started. See support.md for ways to get help.

This project has a code of conduct. By interacting with this repository, organization, or community you agree to abide by its terms.

License

MIT © Titus Wormer