UNPKG

substance

Version:

Substance is a JavaScript library for web-based content editing. It provides building blocks for realizing custom text editors and web-based publishing system. It is developed to power our online editing platform [Substance](http://substance.io).

108 lines (101 loc) 2.42 kB
import isString from './isString' import levenshtein from './levenshtein' /* Determines a list of changes to transform String a into String b. @param {String} a @param {String} b */ function diff (a, b, offset) { if (!isString(a) || !isString(b)) { throw new Error('Illegal arguments.') } offset = offset || 0 let changes = [] if (a || b) { if (!a && b) { changes.push({ type: 'insert', start: offset, text: b }) } else if (a && !b) { changes.push({ type: 'delete', start: offset, end: offset + a.length }) } else { const m = levenshtein(a, b) changes = _diff(a, b, m, offset) } } return changes } function _diff (a, b, m, offset) { let i = b.length let j = a.length const changes = [] let current while (i > 0 && j > 0) { _next() } _commit() return changes function _next () { const d = m[i][j] const ib = i - 1 const jb = j - 1 // substitute if (m[ib][jb] < d) { if (current && current.type === 'replace') { current.start-- current.text.unshift(b.charAt(ib)) } else { _commit() current = { type: 'replace', start: jb, end: j, text: [b.charAt(ib)] } } i-- j-- // insert } else if (m[ib][j] < d) { if (current && current.type === 'insert') { current.start-- current.text.unshift(b.charAt(ib)) } else { _commit() current = { type: 'insert', start: jb, text: [b.charAt(ib)] } } i-- // delete char } else if (m[i][jb] < d) { if (current && current.type === 'delete') { current.start-- } else { _commit() current = { type: 'delete', start: jb, end: j } } j-- // preserve } else { _commit() i-- j-- } } function _commit () { if (current) { switch (current.type) { case 'insert': current.start += offset current.text = current.text.join('') break case 'delete': current.start += offset current.end += offset break case 'replace': current.start += offset current.end += offset current.text = current.text.join('') break default: throw new Error('Invalid state') } changes.push(current) current = null } } } export default diff