# domdiff

> A fast and simple way to diff childNodes

Latest version **2.2.2** (published 2020-03-15) · ISC license · 0 weekly downloads

## Install

```sh
npm install domdiff
pnpm add domdiff
yarn add domdiff
bun add domdiff
```

## Health

**Score 30/100 (F)** — status: abandoned.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 2.2.2 |
| Published | 2020-03-15 |
| First published | 2017-12-01 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 1 |
| Unpacked size | 48.4 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 229 |
| Author | Andrea Giammarchi |
| Maintainers | webreflection |
| Keywords | dom, diff |

## Links

- npm: https://www.npmjs.com/package/domdiff
- Repository: https://github.com/WebReflection/domdiff
- Homepage: https://github.com/WebReflection/domdiff#readme
- Issues: https://github.com/WebReflection/domdiff/issues
- npm.io page: https://npm.io/package/domdiff

## Dependencies (1)

- [uarray](https://npm.io/package/uarray.md) ^1.0.0

## Alternatives

- [babylon](https://npm.io/package/babylon.md) — 5.1M weekly downloads
- [csscolorparser](https://npm.io/package/csscolorparser.md) — 3.7M weekly downloads
- [expr-eval-fork](https://npm.io/package/expr-eval-fork.md) — 1.5M weekly downloads
- [@leeoniya/ufuzzy](https://npm.io/package/@leeoniya/ufuzzy.md) — 247.7K weekly downloads
- [xml-parser](https://npm.io/package/xml-parser.md) — 78.4K weekly downloads

## Recent versions

- 2.2.2 (latest) — 2020-03-15
- 2.2.1 — 2019-12-08
- 2.2.0 — 2019-11-27
- 2.1.1 — 2019-11-15
- 2.1.0 — 2019-09-17
- 2.0.7 — 2019-08-23
- 2.0.6 — 2019-07-24
- 2.0.5 — 2019-07-03
- 2.0.4 — 2019-07-03
- 2.0.3 — 2019-01-17
- 2.0.2 — 2018-11-23
- 2.0.1 — 2018-11-22
- 1.0.3 — 2018-11-22
- 1.0.2 — 2018-11-22
- 2.0.0 — 2018-09-13
- … 20 more at https://npm.io/package/domdiff/versions

## README

# domdiff

[![donate](https://img.shields.io/badge/$-donate-ff69b4.svg?maxAge=2592000&style=flat)](https://github.com/WebReflection/donate) [![Coverage Status](https://coveralls.io/repos/github/WebReflection/domdiff/badge.svg?branch=master)](https://coveralls.io/github/WebReflection/domdiff?branch=master) [![Build Status](https://travis-ci.org/WebReflection/domdiff.svg?branch=master)](https://travis-ci.org/WebReflection/domdiff) [![License: ISC](https://img.shields.io/badge/License-ISC-yellow.svg)](https://opensource.org/licenses/ISC)


A vDOM-less implementation of the [petit-dom](https://github.com/yelouafi/petit-dom) diffing logic, at the core of [hyperHTML](https://github.com/WebReflection/hyperHTML).


### V2 breaking change

  * the good old snabdom diff logic has been 100% replaced
  * lists with `null` or `undefined` nodes are not allowed anymore

<sup><sub>... but I guess having null nodes in the equation was quite possibly a bad idea in the first place ...</sub></sup>

#### V2 Diffing Strategies:

  * common prefixes
  * common suffixes
  * skip same lists
  * add boundaries
  * remove boundaries
  * simple sub-sequences insertions and removals
  * one to many and many to one replacements
  * fast inverted list swap
  * O(ND) algo with a limit of 50 attempts
  * last fallback with a simplified Hunt Szymanski algorithm

The current goal is to have in about 1K the best DOM diffing library out there.

#### V1 breaking change

The signature has moved from `parent, current[], future[], getNode(), beforeNode` to `parent, current[], future[], {before, compare(), node()}`.


### Signature

```js
futureNodes = domdiff(
  parentNode,     // where changes happen
  currentNodes,   // Array of current items/nodes
  futureNodes,    // Array of future items/nodes (returned)
  options         // optional object with one of the following properties
                  //  before: domNode
                  //  compare(generic, generic) => true if same generic
                  //  node(generic) => Node
);
```


### How to import it:

  * via **CDN**, as global variable: `https://unpkg.com/domdiff`
  * via **ESM**, as external module: `https://unpkg.com/domdiff/esm/index.js`
  * via **CJS**: `const EventTarget = require('domdiff').default;` <sup><sub>( or `require('domdiff/cjs').default` )</sub></sup>
  * via bundlers/transpilers: `import domdiff from 'domdiff';` <sup><sub>( or `from 'domdiff/esm'` )</sub></sup>


### Example

```js
var nodes = {
  a: document.createTextNode('a'),
  b: document.createTextNode('b'),
  c: document.createTextNode('c')
};

var parentNode = document.createElement('p');
var childNodes = [nodes.a, nodes.c];
parentNode.append(...childNodes);
parentNode.textContent;
// "ac"

childNodes = domdiff(
  parentNode,
  childNodes,
  [nodes.a, nodes.b, nodes.c]
);

parentNode.textContent;
// "abc"
```


### Compatibility:

Every. JavaScript. Engine.


### A `{node: (generic, info) => node}` callback for complex data

The optional `{node: (generic, info) => node}` is invoked per each operation on the DOM.

This can be useful to represent node through wrappers, whenever that is needed.

The passed `info` value can be:

  * `1` when the item/node is being appended
  * `0` when the item/node is being used as insert _before_ reference
  * `-0` when the item/node is being used as insert _after_ reference
  * `-1` when the item/node is being removed

[Example](https://codepen.io/WebReflection/pen/bYJVPd?editors=0010)

```js
function node(item, i) {
  // case removal or case after
  if ((1 / i) < 0) {
    // case removal
    if (i) {
      // if the item has more than a node
      // remove all other nodes at once
      if (item.length > 1) {
        const range = document.createRange();
        range.setStartBefore(item[1]);
        range.setEndAfter(item[item.length - 1]);
        range.deleteContents();
      }
      // return the first node to be removed
      return item[0];
    }
    // case after
    else {
      return item[item.length - 1];
    }
  }
  // case insert
  else if (i) {
    const fragment = document.createDocumentFragment();
    fragment.append(...item);
    return fragment;
  }
  // case before
  else {
    return item[0];
  }
}

const and = [document.createTextNode(' & ')];

const Bob = [
  document.createTextNode('B'),
  document.createTextNode('o'),
  document.createTextNode('b')
];

const Lucy = [
  document.createTextNode('L'),
  document.createTextNode('u'),
  document.createTextNode('c'),
  document.createTextNode('y')
];

// clean the body for demo purpose
document.body.textContent = '';
let content = domdiff(
  document.body,
  [],
  [Bob, and, Lucy],
  {node}
);

// ... later on ...
content = domdiff(
  document.body,
  content,
  [Lucy, and, Bob],
  {node}
);

// clean up
domdiff(
  document.body,
  content,
  [],
  {node}
);

```

---
_Source: https://npm.io/package/domdiff · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
