1function Diff() {}
2Diff.prototype = {
3  diff: function diff(oldString, newString) {
4    var _options$timeout;
5
6    var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
7    var callback = options.callback;
8
9    if (typeof options === 'function') {
10      callback = options;
11      options = {};
12    }
13
14    this.options = options;
15    var self = this;
16
17    function done(value) {
18      if (callback) {
19        setTimeout(function () {
20          callback(undefined, value);
21        }, 0);
22        return true;
23      } else {
24        return value;
25      }
26    } // Allow subclasses to massage the input prior to running
27
28
29    oldString = this.castInput(oldString);
30    newString = this.castInput(newString);
31    oldString = this.removeEmpty(this.tokenize(oldString));
32    newString = this.removeEmpty(this.tokenize(newString));
33    var newLen = newString.length,
34        oldLen = oldString.length;
35    var editLength = 1;
36    var maxEditLength = newLen + oldLen;
37
38    if (options.maxEditLength) {
39      maxEditLength = Math.min(maxEditLength, options.maxEditLength);
40    }
41
42    var maxExecutionTime = (_options$timeout = options.timeout) !== null && _options$timeout !== void 0 ? _options$timeout : Infinity;
43    var abortAfterTimestamp = Date.now() + maxExecutionTime;
44    var bestPath = [{
45      oldPos: -1,
46      lastComponent: undefined
47    }]; // Seed editLength = 0, i.e. the content starts with the same values
48
49    var newPos = this.extractCommon(bestPath[0], newString, oldString, 0);
50
51    if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
52      // Identity per the equality and tokenizer
53      return done([{
54        value: this.join(newString),
55        count: newString.length
56      }]);
57    } // Once we hit the right edge of the edit graph on some diagonal k, we can
58    // definitely reach the end of the edit graph in no more than k edits, so
59    // there's no point in considering any moves to diagonal k+1 any more (from
60    // which we're guaranteed to need at least k+1 more edits).
61    // Similarly, once we've reached the bottom of the edit graph, there's no
62    // point considering moves to lower diagonals.
63    // We record this fact by setting minDiagonalToConsider and
64    // maxDiagonalToConsider to some finite value once we've hit the edge of
65    // the edit graph.
66    // This optimization is not faithful to the original algorithm presented in
67    // Myers's paper, which instead pointlessly extends D-paths off the end of
68    // the edit graph - see page 7 of Myers's paper which notes this point
69    // explicitly and illustrates it with a diagram. This has major performance
70    // implications for some common scenarios. For instance, to compute a diff
71    // where the new text simply appends d characters on the end of the
72    // original text of length n, the true Myers algorithm will take O(n+d^2)
73    // time while this optimization needs only O(n+d) time.
74
75
76    var minDiagonalToConsider = -Infinity,
77        maxDiagonalToConsider = Infinity; // Main worker method. checks all permutations of a given edit length for acceptance.
78
79    function execEditLength() {
80      for (var diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
81        var basePath = void 0;
82        var removePath = bestPath[diagonalPath - 1],
83            addPath = bestPath[diagonalPath + 1];
84
85        if (removePath) {
86          // No one else is going to attempt to use this value, clear it
87          bestPath[diagonalPath - 1] = undefined;
88        }
89
90        var canAdd = false;
91
92        if (addPath) {
93          // what newPos will be after we do an insertion:
94          var addPathNewPos = addPath.oldPos - diagonalPath;
95          canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
96        }
97
98        var canRemove = removePath && removePath.oldPos + 1 < oldLen;
99
100        if (!canAdd && !canRemove) {
101          // If this path is a terminal then prune
102          bestPath[diagonalPath] = undefined;
103          continue;
104        } // Select the diagonal that we want to branch from. We select the prior
105        // path whose position in the old string is the farthest from the origin
106        // and does not pass the bounds of the diff graph
107        // TODO: Remove the `+ 1` here to make behavior match Myers algorithm
108        //       and prefer to order removals before insertions.
109
110
111        if (!canRemove || canAdd && removePath.oldPos + 1 < addPath.oldPos) {
112          basePath = self.addToPath(addPath, true, undefined, 0);
113        } else {
114          basePath = self.addToPath(removePath, undefined, true, 1);
115        }
116
117        newPos = self.extractCommon(basePath, newString, oldString, diagonalPath);
118
119        if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
120          // If we have hit the end of both strings, then we are done
121          return done(buildValues(self, basePath.lastComponent, newString, oldString, self.useLongestToken));
122        } else {
123          bestPath[diagonalPath] = basePath;
124
125          if (basePath.oldPos + 1 >= oldLen) {
126            maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
127          }
128
129          if (newPos + 1 >= newLen) {
130            minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
131          }
132        }
133      }
134
135      editLength++;
136    } // Performs the length of edit iteration. Is a bit fugly as this has to support the
137    // sync and async mode which is never fun. Loops over execEditLength until a value
138    // is produced, or until the edit length exceeds options.maxEditLength (if given),
139    // in which case it will return undefined.
140
141
142    if (callback) {
143      (function exec() {
144        setTimeout(function () {
145          if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
146            return callback();
147          }
148
149          if (!execEditLength()) {
150            exec();
151          }
152        }, 0);
153      })();
154    } else {
155      while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
156        var ret = execEditLength();
157
158        if (ret) {
159          return ret;
160        }
161      }
162    }
163  },
164  addToPath: function addToPath(path, added, removed, oldPosInc) {
165    var last = path.lastComponent;
166
167    if (last && last.added === added && last.removed === removed) {
168      return {
169        oldPos: path.oldPos + oldPosInc,
170        lastComponent: {
171          count: last.count + 1,
172          added: added,
173          removed: removed,
174          previousComponent: last.previousComponent
175        }
176      };
177    } else {
178      return {
179        oldPos: path.oldPos + oldPosInc,
180        lastComponent: {
181          count: 1,
182          added: added,
183          removed: removed,
184          previousComponent: last
185        }
186      };
187    }
188  },
189  extractCommon: function extractCommon(basePath, newString, oldString, diagonalPath) {
190    var newLen = newString.length,
191        oldLen = oldString.length,
192        oldPos = basePath.oldPos,
193        newPos = oldPos - diagonalPath,
194        commonCount = 0;
195
196    while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newString[newPos + 1], oldString[oldPos + 1])) {
197      newPos++;
198      oldPos++;
199      commonCount++;
200    }
201
202    if (commonCount) {
203      basePath.lastComponent = {
204        count: commonCount,
205        previousComponent: basePath.lastComponent
206      };
207    }
208
209    basePath.oldPos = oldPos;
210    return newPos;
211  },
212  equals: function equals(left, right) {
213    if (this.options.comparator) {
214      return this.options.comparator(left, right);
215    } else {
216      return left === right || this.options.ignoreCase && left.toLowerCase() === right.toLowerCase();
217    }
218  },
219  removeEmpty: function removeEmpty(array) {
220    var ret = [];
221
222    for (var i = 0; i < array.length; i++) {
223      if (array[i]) {
224        ret.push(array[i]);
225      }
226    }
227
228    return ret;
229  },
230  castInput: function castInput(value) {
231    return value;
232  },
233  tokenize: function tokenize(value) {
234    return value.split('');
235  },
236  join: function join(chars) {
237    return chars.join('');
238  }
239};
240
241function buildValues(diff, lastComponent, newString, oldString, useLongestToken) {
242  // First we convert our linked list of components in reverse order to an
243  // array in the right order:
244  var components = [];
245  var nextComponent;
246
247  while (lastComponent) {
248    components.push(lastComponent);
249    nextComponent = lastComponent.previousComponent;
250    delete lastComponent.previousComponent;
251    lastComponent = nextComponent;
252  }
253
254  components.reverse();
255  var componentPos = 0,
256      componentLen = components.length,
257      newPos = 0,
258      oldPos = 0;
259
260  for (; componentPos < componentLen; componentPos++) {
261    var component = components[componentPos];
262
263    if (!component.removed) {
264      if (!component.added && useLongestToken) {
265        var value = newString.slice(newPos, newPos + component.count);
266        value = value.map(function (value, i) {
267          var oldValue = oldString[oldPos + i];
268          return oldValue.length > value.length ? oldValue : value;
269        });
270        component.value = diff.join(value);
271      } else {
272        component.value = diff.join(newString.slice(newPos, newPos + component.count));
273      }
274
275      newPos += component.count; // Common case
276
277      if (!component.added) {
278        oldPos += component.count;
279      }
280    } else {
281      component.value = diff.join(oldString.slice(oldPos, oldPos + component.count));
282      oldPos += component.count; // Reverse add and remove so removes are output first to match common convention
283      // The diffing algorithm is tied to add then remove output and this is the simplest
284      // route to get the desired output with minimal overhead.
285
286      if (componentPos && components[componentPos - 1].added) {
287        var tmp = components[componentPos - 1];
288        components[componentPos - 1] = components[componentPos];
289        components[componentPos] = tmp;
290      }
291    }
292  } // Special case handle for when one terminal is ignored (i.e. whitespace).
293  // For this case we merge the terminal into the prior string and drop the change.
294  // This is only available for string mode.
295
296
297  var finalComponent = components[componentLen - 1];
298
299  if (componentLen > 1 && typeof finalComponent.value === 'string' && (finalComponent.added || finalComponent.removed) && diff.equals('', finalComponent.value)) {
300    components[componentLen - 2].value += finalComponent.value;
301    components.pop();
302  }
303
304  return components;
305}
306
307var characterDiff = new Diff();
308function diffChars(oldStr, newStr, options) {
309  return characterDiff.diff(oldStr, newStr, options);
310}
311
312function generateOptions(options, defaults) {
313  if (typeof options === 'function') {
314    defaults.callback = options;
315  } else if (options) {
316    for (var name in options) {
317      /* istanbul ignore else */
318      if (options.hasOwnProperty(name)) {
319        defaults[name] = options[name];
320      }
321    }
322  }
323
324  return defaults;
325}
326
327//
328// Ranges and exceptions:
329// Latin-1 Supplement, 0080–00FF
330//  - U+00D7  × Multiplication sign
331//  - U+00F7  ÷ Division sign
332// Latin Extended-A, 0100–017F
333// Latin Extended-B, 0180–024F
334// IPA Extensions, 0250–02AF
335// Spacing Modifier Letters, 02B0–02FF
336//  - U+02C7  ˇ &#711;  Caron
337//  - U+02D8  ˘ &#728;  Breve
338//  - U+02D9  ˙ &#729;  Dot Above
339//  - U+02DA  ˚ &#730;  Ring Above
340//  - U+02DB  ˛ &#731;  Ogonek
341//  - U+02DC  ˜ &#732;  Small Tilde
342//  - U+02DD  ˝ &#733;  Double Acute Accent
343// Latin Extended Additional, 1E00–1EFF
344
345var extendedWordChars = /^[A-Za-z\xC0-\u02C6\u02C8-\u02D7\u02DE-\u02FF\u1E00-\u1EFF]+$/;
346var reWhitespace = /\S/;
347var wordDiff = new Diff();
348
349wordDiff.equals = function (left, right) {
350  if (this.options.ignoreCase) {
351    left = left.toLowerCase();
352    right = right.toLowerCase();
353  }
354
355  return left === right || this.options.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right);
356};
357
358wordDiff.tokenize = function (value) {
359  // All whitespace symbols except newline group into one token, each newline - in separate token
360  var tokens = value.split(/([^\S\r\n]+|[()[\]{}'"\r\n]|\b)/); // Join the boundary splits that we do not consider to be boundaries. This is primarily the extended Latin character set.
361
362  for (var i = 0; i < tokens.length - 1; i++) {
363    // If we have an empty string in the next field and we have only word chars before and after, merge
364    if (!tokens[i + 1] && tokens[i + 2] && extendedWordChars.test(tokens[i]) && extendedWordChars.test(tokens[i + 2])) {
365      tokens[i] += tokens[i + 2];
366      tokens.splice(i + 1, 2);
367      i--;
368    }
369  }
370
371  return tokens;
372};
373
374function diffWords(oldStr, newStr, options) {
375  options = generateOptions(options, {
376    ignoreWhitespace: true
377  });
378  return wordDiff.diff(oldStr, newStr, options);
379}
380function diffWordsWithSpace(oldStr, newStr, options) {
381  return wordDiff.diff(oldStr, newStr, options);
382}
383
384var lineDiff = new Diff();
385
386lineDiff.tokenize = function (value) {
387  if (this.options.stripTrailingCr) {
388    // remove one \r before \n to match GNU diff's --strip-trailing-cr behavior
389    value = value.replace(/\r\n/g, '\n');
390  }
391
392  var retLines = [],
393      linesAndNewlines = value.split(/(\n|\r\n)/); // Ignore the final empty token that occurs if the string ends with a new line
394
395  if (!linesAndNewlines[linesAndNewlines.length - 1]) {
396    linesAndNewlines.pop();
397  } // Merge the content and line separators into single tokens
398
399
400  for (var i = 0; i < linesAndNewlines.length; i++) {
401    var line = linesAndNewlines[i];
402
403    if (i % 2 && !this.options.newlineIsToken) {
404      retLines[retLines.length - 1] += line;
405    } else {
406      if (this.options.ignoreWhitespace) {
407        line = line.trim();
408      }
409
410      retLines.push(line);
411    }
412  }
413
414  return retLines;
415};
416
417function diffLines(oldStr, newStr, callback) {
418  return lineDiff.diff(oldStr, newStr, callback);
419}
420function diffTrimmedLines(oldStr, newStr, callback) {
421  var options = generateOptions(callback, {
422    ignoreWhitespace: true
423  });
424  return lineDiff.diff(oldStr, newStr, options);
425}
426
427var sentenceDiff = new Diff();
428
429sentenceDiff.tokenize = function (value) {
430  return value.split(/(\S.+?[.!?])(?=\s+|$)/);
431};
432
433function diffSentences(oldStr, newStr, callback) {
434  return sentenceDiff.diff(oldStr, newStr, callback);
435}
436
437var cssDiff = new Diff();
438
439cssDiff.tokenize = function (value) {
440  return value.split(/([{}:;,]|\s+)/);
441};
442
443function diffCss(oldStr, newStr, callback) {
444  return cssDiff.diff(oldStr, newStr, callback);
445}
446
447function _typeof(obj) {
448  "@babel/helpers - typeof";
449
450  if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
451    _typeof = function (obj) {
452      return typeof obj;
453    };
454  } else {
455    _typeof = function (obj) {
456      return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
457    };
458  }
459
460  return _typeof(obj);
461}
462
463function _defineProperty(obj, key, value) {
464  if (key in obj) {
465    Object.defineProperty(obj, key, {
466      value: value,
467      enumerable: true,
468      configurable: true,
469      writable: true
470    });
471  } else {
472    obj[key] = value;
473  }
474
475  return obj;
476}
477
478function ownKeys(object, enumerableOnly) {
479  var keys = Object.keys(object);
480
481  if (Object.getOwnPropertySymbols) {
482    var symbols = Object.getOwnPropertySymbols(object);
483    if (enumerableOnly) symbols = symbols.filter(function (sym) {
484      return Object.getOwnPropertyDescriptor(object, sym).enumerable;
485    });
486    keys.push.apply(keys, symbols);
487  }
488
489  return keys;
490}
491
492function _objectSpread2(target) {
493  for (var i = 1; i < arguments.length; i++) {
494    var source = arguments[i] != null ? arguments[i] : {};
495
496    if (i % 2) {
497      ownKeys(Object(source), true).forEach(function (key) {
498        _defineProperty(target, key, source[key]);
499      });
500    } else if (Object.getOwnPropertyDescriptors) {
501      Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
502    } else {
503      ownKeys(Object(source)).forEach(function (key) {
504        Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
505      });
506    }
507  }
508
509  return target;
510}
511
512function _toConsumableArray(arr) {
513  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
514}
515
516function _arrayWithoutHoles(arr) {
517  if (Array.isArray(arr)) return _arrayLikeToArray(arr);
518}
519
520function _iterableToArray(iter) {
521  if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
522}
523
524function _unsupportedIterableToArray(o, minLen) {
525  if (!o) return;
526  if (typeof o === "string") return _arrayLikeToArray(o, minLen);
527  var n = Object.prototype.toString.call(o).slice(8, -1);
528  if (n === "Object" && o.constructor) n = o.constructor.name;
529  if (n === "Map" || n === "Set") return Array.from(o);
530  if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
531}
532
533function _arrayLikeToArray(arr, len) {
534  if (len == null || len > arr.length) len = arr.length;
535
536  for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
537
538  return arr2;
539}
540
541function _nonIterableSpread() {
542  throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
543}
544
545var objectPrototypeToString = Object.prototype.toString;
546var jsonDiff = new Diff(); // Discriminate between two lines of pretty-printed, serialized JSON where one of them has a
547// dangling comma and the other doesn't. Turns out including the dangling comma yields the nicest output:
548
549jsonDiff.useLongestToken = true;
550jsonDiff.tokenize = lineDiff.tokenize;
551
552jsonDiff.castInput = function (value) {
553  var _this$options = this.options,
554      undefinedReplacement = _this$options.undefinedReplacement,
555      _this$options$stringi = _this$options.stringifyReplacer,
556      stringifyReplacer = _this$options$stringi === void 0 ? function (k, v) {
557    return typeof v === 'undefined' ? undefinedReplacement : v;
558  } : _this$options$stringi;
559  return typeof value === 'string' ? value : JSON.stringify(canonicalize(value, null, null, stringifyReplacer), stringifyReplacer, '  ');
560};
561
562jsonDiff.equals = function (left, right) {
563  return Diff.prototype.equals.call(jsonDiff, left.replace(/,([\r\n])/g, '$1'), right.replace(/,([\r\n])/g, '$1'));
564};
565
566function diffJson(oldObj, newObj, options) {
567  return jsonDiff.diff(oldObj, newObj, options);
568} // This function handles the presence of circular references by bailing out when encountering an
569// object that is already on the "stack" of items being processed. Accepts an optional replacer
570
571function canonicalize(obj, stack, replacementStack, replacer, key) {
572  stack = stack || [];
573  replacementStack = replacementStack || [];
574
575  if (replacer) {
576    obj = replacer(key, obj);
577  }
578
579  var i;
580
581  for (i = 0; i < stack.length; i += 1) {
582    if (stack[i] === obj) {
583      return replacementStack[i];
584    }
585  }
586
587  var canonicalizedObj;
588
589  if ('[object Array]' === objectPrototypeToString.call(obj)) {
590    stack.push(obj);
591    canonicalizedObj = new Array(obj.length);
592    replacementStack.push(canonicalizedObj);
593
594    for (i = 0; i < obj.length; i += 1) {
595      canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack, replacer, key);
596    }
597
598    stack.pop();
599    replacementStack.pop();
600    return canonicalizedObj;
601  }
602
603  if (obj && obj.toJSON) {
604    obj = obj.toJSON();
605  }
606
607  if (_typeof(obj) === 'object' && obj !== null) {
608    stack.push(obj);
609    canonicalizedObj = {};
610    replacementStack.push(canonicalizedObj);
611
612    var sortedKeys = [],
613        _key;
614
615    for (_key in obj) {
616      /* istanbul ignore else */
617      if (obj.hasOwnProperty(_key)) {
618        sortedKeys.push(_key);
619      }
620    }
621
622    sortedKeys.sort();
623
624    for (i = 0; i < sortedKeys.length; i += 1) {
625      _key = sortedKeys[i];
626      canonicalizedObj[_key] = canonicalize(obj[_key], stack, replacementStack, replacer, _key);
627    }
628
629    stack.pop();
630    replacementStack.pop();
631  } else {
632    canonicalizedObj = obj;
633  }
634
635  return canonicalizedObj;
636}
637
638var arrayDiff = new Diff();
639
640arrayDiff.tokenize = function (value) {
641  return value.slice();
642};
643
644arrayDiff.join = arrayDiff.removeEmpty = function (value) {
645  return value;
646};
647
648function diffArrays(oldArr, newArr, callback) {
649  return arrayDiff.diff(oldArr, newArr, callback);
650}
651
652function parsePatch(uniDiff) {
653  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
654  var diffstr = uniDiff.split(/\r\n|[\n\v\f\r\x85]/),
655      delimiters = uniDiff.match(/\r\n|[\n\v\f\r\x85]/g) || [],
656      list = [],
657      i = 0;
658
659  function parseIndex() {
660    var index = {};
661    list.push(index); // Parse diff metadata
662
663    while (i < diffstr.length) {
664      var line = diffstr[i]; // File header found, end parsing diff metadata
665
666      if (/^(\-\-\-|\+\+\+|@@)\s/.test(line)) {
667        break;
668      } // Diff index
669
670
671      var header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line);
672
673      if (header) {
674        index.index = header[1];
675      }
676
677      i++;
678    } // Parse file headers if they are defined. Unified diff requires them, but
679    // there's no technical issues to have an isolated hunk without file header
680
681
682    parseFileHeader(index);
683    parseFileHeader(index); // Parse hunks
684
685    index.hunks = [];
686
687    while (i < diffstr.length) {
688      var _line = diffstr[i];
689
690      if (/^(Index:|diff|\-\-\-|\+\+\+)\s/.test(_line)) {
691        break;
692      } else if (/^@@/.test(_line)) {
693        index.hunks.push(parseHunk());
694      } else if (_line && options.strict) {
695        // Ignore unexpected content unless in strict mode
696        throw new Error('Unknown line ' + (i + 1) + ' ' + JSON.stringify(_line));
697      } else {
698        i++;
699      }
700    }
701  } // Parses the --- and +++ headers, if none are found, no lines
702  // are consumed.
703
704
705  function parseFileHeader(index) {
706    var fileHeader = /^(---|\+\+\+)\s+(.*)$/.exec(diffstr[i]);
707
708    if (fileHeader) {
709      var keyPrefix = fileHeader[1] === '---' ? 'old' : 'new';
710      var data = fileHeader[2].split('\t', 2);
711      var fileName = data[0].replace(/\\\\/g, '\\');
712
713      if (/^".*"$/.test(fileName)) {
714        fileName = fileName.substr(1, fileName.length - 2);
715      }
716
717      index[keyPrefix + 'FileName'] = fileName;
718      index[keyPrefix + 'Header'] = (data[1] || '').trim();
719      i++;
720    }
721  } // Parses a hunk
722  // This assumes that we are at the start of a hunk.
723
724
725  function parseHunk() {
726    var chunkHeaderIndex = i,
727        chunkHeaderLine = diffstr[i++],
728        chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
729    var hunk = {
730      oldStart: +chunkHeader[1],
731      oldLines: typeof chunkHeader[2] === 'undefined' ? 1 : +chunkHeader[2],
732      newStart: +chunkHeader[3],
733      newLines: typeof chunkHeader[4] === 'undefined' ? 1 : +chunkHeader[4],
734      lines: [],
735      linedelimiters: []
736    }; // Unified Diff Format quirk: If the chunk size is 0,
737    // the first number is one lower than one would expect.
738    // https://www.artima.com/weblogs/viewpost.jsp?thread=164293
739
740    if (hunk.oldLines === 0) {
741      hunk.oldStart += 1;
742    }
743
744    if (hunk.newLines === 0) {
745      hunk.newStart += 1;
746    }
747
748    var addCount = 0,
749        removeCount = 0;
750
751    for (; i < diffstr.length; i++) {
752      // Lines starting with '---' could be mistaken for the "remove line" operation
753      // But they could be the header for the next file. Therefore prune such cases out.
754      if (diffstr[i].indexOf('--- ') === 0 && i + 2 < diffstr.length && diffstr[i + 1].indexOf('+++ ') === 0 && diffstr[i + 2].indexOf('@@') === 0) {
755        break;
756      }
757
758      var operation = diffstr[i].length == 0 && i != diffstr.length - 1 ? ' ' : diffstr[i][0];
759
760      if (operation === '+' || operation === '-' || operation === ' ' || operation === '\\') {
761        hunk.lines.push(diffstr[i]);
762        hunk.linedelimiters.push(delimiters[i] || '\n');
763
764        if (operation === '+') {
765          addCount++;
766        } else if (operation === '-') {
767          removeCount++;
768        } else if (operation === ' ') {
769          addCount++;
770          removeCount++;
771        }
772      } else {
773        break;
774      }
775    } // Handle the empty block count case
776
777
778    if (!addCount && hunk.newLines === 1) {
779      hunk.newLines = 0;
780    }
781
782    if (!removeCount && hunk.oldLines === 1) {
783      hunk.oldLines = 0;
784    } // Perform optional sanity checking
785
786
787    if (options.strict) {
788      if (addCount !== hunk.newLines) {
789        throw new Error('Added line count did not match for hunk at line ' + (chunkHeaderIndex + 1));
790      }
791
792      if (removeCount !== hunk.oldLines) {
793        throw new Error('Removed line count did not match for hunk at line ' + (chunkHeaderIndex + 1));
794      }
795    }
796
797    return hunk;
798  }
799
800  while (i < diffstr.length) {
801    parseIndex();
802  }
803
804  return list;
805}
806
807// Iterator that traverses in the range of [min, max], stepping
808// by distance from a given start position. I.e. for [0, 4], with
809// start of 2, this will iterate 2, 3, 1, 4, 0.
810function distanceIterator (start, minLine, maxLine) {
811  var wantForward = true,
812      backwardExhausted = false,
813      forwardExhausted = false,
814      localOffset = 1;
815  return function iterator() {
816    if (wantForward && !forwardExhausted) {
817      if (backwardExhausted) {
818        localOffset++;
819      } else {
820        wantForward = false;
821      } // Check if trying to fit beyond text length, and if not, check it fits
822      // after offset location (or desired location on first iteration)
823
824
825      if (start + localOffset <= maxLine) {
826        return localOffset;
827      }
828
829      forwardExhausted = true;
830    }
831
832    if (!backwardExhausted) {
833      if (!forwardExhausted) {
834        wantForward = true;
835      } // Check if trying to fit before text beginning, and if not, check it fits
836      // before offset location
837
838
839      if (minLine <= start - localOffset) {
840        return -localOffset++;
841      }
842
843      backwardExhausted = true;
844      return iterator();
845    } // We tried to fit hunk before text beginning and beyond text length, then
846    // hunk can't fit on the text. Return undefined
847
848  };
849}
850
851function applyPatch(source, uniDiff) {
852  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
853
854  if (typeof uniDiff === 'string') {
855    uniDiff = parsePatch(uniDiff);
856  }
857
858  if (Array.isArray(uniDiff)) {
859    if (uniDiff.length > 1) {
860      throw new Error('applyPatch only works with a single input.');
861    }
862
863    uniDiff = uniDiff[0];
864  } // Apply the diff to the input
865
866
867  var lines = source.split(/\r\n|[\n\v\f\r\x85]/),
868      delimiters = source.match(/\r\n|[\n\v\f\r\x85]/g) || [],
869      hunks = uniDiff.hunks,
870      compareLine = options.compareLine || function (lineNumber, line, operation, patchContent) {
871    return line === patchContent;
872  },
873      errorCount = 0,
874      fuzzFactor = options.fuzzFactor || 0,
875      minLine = 0,
876      offset = 0,
877      removeEOFNL,
878      addEOFNL;
879  /**
880   * Checks if the hunk exactly fits on the provided location
881   */
882
883
884  function hunkFits(hunk, toPos) {
885    for (var j = 0; j < hunk.lines.length; j++) {
886      var line = hunk.lines[j],
887          operation = line.length > 0 ? line[0] : ' ',
888          content = line.length > 0 ? line.substr(1) : line;
889
890      if (operation === ' ' || operation === '-') {
891        // Context sanity check
892        if (!compareLine(toPos + 1, lines[toPos], operation, content)) {
893          errorCount++;
894
895          if (errorCount > fuzzFactor) {
896            return false;
897          }
898        }
899
900        toPos++;
901      }
902    }
903
904    return true;
905  } // Search best fit offsets for each hunk based on the previous ones
906
907
908  for (var i = 0; i < hunks.length; i++) {
909    var hunk = hunks[i],
910        maxLine = lines.length - hunk.oldLines,
911        localOffset = 0,
912        toPos = offset + hunk.oldStart - 1;
913    var iterator = distanceIterator(toPos, minLine, maxLine);
914
915    for (; localOffset !== undefined; localOffset = iterator()) {
916      if (hunkFits(hunk, toPos + localOffset)) {
917        hunk.offset = offset += localOffset;
918        break;
919      }
920    }
921
922    if (localOffset === undefined) {
923      return false;
924    } // Set lower text limit to end of the current hunk, so next ones don't try
925    // to fit over already patched text
926
927
928    minLine = hunk.offset + hunk.oldStart + hunk.oldLines;
929  } // Apply patch hunks
930
931
932  var diffOffset = 0;
933
934  for (var _i = 0; _i < hunks.length; _i++) {
935    var _hunk = hunks[_i],
936        _toPos = _hunk.oldStart + _hunk.offset + diffOffset - 1;
937
938    diffOffset += _hunk.newLines - _hunk.oldLines;
939
940    for (var j = 0; j < _hunk.lines.length; j++) {
941      var line = _hunk.lines[j],
942          operation = line.length > 0 ? line[0] : ' ',
943          content = line.length > 0 ? line.substr(1) : line,
944          delimiter = _hunk.linedelimiters && _hunk.linedelimiters[j] || '\n';
945
946      if (operation === ' ') {
947        _toPos++;
948      } else if (operation === '-') {
949        lines.splice(_toPos, 1);
950        delimiters.splice(_toPos, 1);
951        /* istanbul ignore else */
952      } else if (operation === '+') {
953        lines.splice(_toPos, 0, content);
954        delimiters.splice(_toPos, 0, delimiter);
955        _toPos++;
956      } else if (operation === '\\') {
957        var previousOperation = _hunk.lines[j - 1] ? _hunk.lines[j - 1][0] : null;
958
959        if (previousOperation === '+') {
960          removeEOFNL = true;
961        } else if (previousOperation === '-') {
962          addEOFNL = true;
963        }
964      }
965    }
966  } // Handle EOFNL insertion/removal
967
968
969  if (removeEOFNL) {
970    while (!lines[lines.length - 1]) {
971      lines.pop();
972      delimiters.pop();
973    }
974  } else if (addEOFNL) {
975    lines.push('');
976    delimiters.push('\n');
977  }
978
979  for (var _k = 0; _k < lines.length - 1; _k++) {
980    lines[_k] = lines[_k] + delimiters[_k];
981  }
982
983  return lines.join('');
984} // Wrapper that supports multiple file patches via callbacks.
985
986function applyPatches(uniDiff, options) {
987  if (typeof uniDiff === 'string') {
988    uniDiff = parsePatch(uniDiff);
989  }
990
991  var currentIndex = 0;
992
993  function processIndex() {
994    var index = uniDiff[currentIndex++];
995
996    if (!index) {
997      return options.complete();
998    }
999
1000    options.loadFile(index, function (err, data) {
1001      if (err) {
1002        return options.complete(err);
1003      }
1004
1005      var updatedContent = applyPatch(data, index, options);
1006      options.patched(index, updatedContent, function (err) {
1007        if (err) {
1008          return options.complete(err);
1009        }
1010
1011        processIndex();
1012      });
1013    });
1014  }
1015
1016  processIndex();
1017}
1018
1019function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
1020  if (!options) {
1021    options = {};
1022  }
1023
1024  if (typeof options.context === 'undefined') {
1025    options.context = 4;
1026  }
1027
1028  var diff = diffLines(oldStr, newStr, options);
1029
1030  if (!diff) {
1031    return;
1032  }
1033
1034  diff.push({
1035    value: '',
1036    lines: []
1037  }); // Append an empty value to make cleanup easier
1038
1039  function contextLines(lines) {
1040    return lines.map(function (entry) {
1041      return ' ' + entry;
1042    });
1043  }
1044
1045  var hunks = [];
1046  var oldRangeStart = 0,
1047      newRangeStart = 0,
1048      curRange = [],
1049      oldLine = 1,
1050      newLine = 1;
1051
1052  var _loop = function _loop(i) {
1053    var current = diff[i],
1054        lines = current.lines || current.value.replace(/\n$/, '').split('\n');
1055    current.lines = lines;
1056
1057    if (current.added || current.removed) {
1058      var _curRange;
1059
1060      // If we have previous context, start with that
1061      if (!oldRangeStart) {
1062        var prev = diff[i - 1];
1063        oldRangeStart = oldLine;
1064        newRangeStart = newLine;
1065
1066        if (prev) {
1067          curRange = options.context > 0 ? contextLines(prev.lines.slice(-options.context)) : [];
1068          oldRangeStart -= curRange.length;
1069          newRangeStart -= curRange.length;
1070        }
1071      } // Output our changes
1072
1073
1074      (_curRange = curRange).push.apply(_curRange, _toConsumableArray(lines.map(function (entry) {
1075        return (current.added ? '+' : '-') + entry;
1076      }))); // Track the updated file position
1077
1078
1079      if (current.added) {
1080        newLine += lines.length;
1081      } else {
1082        oldLine += lines.length;
1083      }
1084    } else {
1085      // Identical context lines. Track line changes
1086      if (oldRangeStart) {
1087        // Close out any changes that have been output (or join overlapping)
1088        if (lines.length <= options.context * 2 && i < diff.length - 2) {
1089          var _curRange2;
1090
1091          // Overlapping
1092          (_curRange2 = curRange).push.apply(_curRange2, _toConsumableArray(contextLines(lines)));
1093        } else {
1094          var _curRange3;
1095
1096          // end the range and output
1097          var contextSize = Math.min(lines.length, options.context);
1098
1099          (_curRange3 = curRange).push.apply(_curRange3, _toConsumableArray(contextLines(lines.slice(0, contextSize))));
1100
1101          var hunk = {
1102            oldStart: oldRangeStart,
1103            oldLines: oldLine - oldRangeStart + contextSize,
1104            newStart: newRangeStart,
1105            newLines: newLine - newRangeStart + contextSize,
1106            lines: curRange
1107          };
1108
1109          if (i >= diff.length - 2 && lines.length <= options.context) {
1110            // EOF is inside this hunk
1111            var oldEOFNewline = /\n$/.test(oldStr);
1112            var newEOFNewline = /\n$/.test(newStr);
1113            var noNlBeforeAdds = lines.length == 0 && curRange.length > hunk.oldLines;
1114
1115            if (!oldEOFNewline && noNlBeforeAdds && oldStr.length > 0) {
1116              // special case: old has no eol and no trailing context; no-nl can end up before adds
1117              // however, if the old file is empty, do not output the no-nl line
1118              curRange.splice(hunk.oldLines, 0, '\\ No newline at end of file');
1119            }
1120
1121            if (!oldEOFNewline && !noNlBeforeAdds || !newEOFNewline) {
1122              curRange.push('\\ No newline at end of file');
1123            }
1124          }
1125
1126          hunks.push(hunk);
1127          oldRangeStart = 0;
1128          newRangeStart = 0;
1129          curRange = [];
1130        }
1131      }
1132
1133      oldLine += lines.length;
1134      newLine += lines.length;
1135    }
1136  };
1137
1138  for (var i = 0; i < diff.length; i++) {
1139    _loop(i);
1140  }
1141
1142  return {
1143    oldFileName: oldFileName,
1144    newFileName: newFileName,
1145    oldHeader: oldHeader,
1146    newHeader: newHeader,
1147    hunks: hunks
1148  };
1149}
1150function formatPatch(diff) {
1151  if (Array.isArray(diff)) {
1152    return diff.map(formatPatch).join('\n');
1153  }
1154
1155  var ret = [];
1156
1157  if (diff.oldFileName == diff.newFileName) {
1158    ret.push('Index: ' + diff.oldFileName);
1159  }
1160
1161  ret.push('===================================================================');
1162  ret.push('--- ' + diff.oldFileName + (typeof diff.oldHeader === 'undefined' ? '' : '\t' + diff.oldHeader));
1163  ret.push('+++ ' + diff.newFileName + (typeof diff.newHeader === 'undefined' ? '' : '\t' + diff.newHeader));
1164
1165  for (var i = 0; i < diff.hunks.length; i++) {
1166    var hunk = diff.hunks[i]; // Unified Diff Format quirk: If the chunk size is 0,
1167    // the first number is one lower than one would expect.
1168    // https://www.artima.com/weblogs/viewpost.jsp?thread=164293
1169
1170    if (hunk.oldLines === 0) {
1171      hunk.oldStart -= 1;
1172    }
1173
1174    if (hunk.newLines === 0) {
1175      hunk.newStart -= 1;
1176    }
1177
1178    ret.push('@@ -' + hunk.oldStart + ',' + hunk.oldLines + ' +' + hunk.newStart + ',' + hunk.newLines + ' @@');
1179    ret.push.apply(ret, hunk.lines);
1180  }
1181
1182  return ret.join('\n') + '\n';
1183}
1184function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
1185  return formatPatch(structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options));
1186}
1187function createPatch(fileName, oldStr, newStr, oldHeader, newHeader, options) {
1188  return createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader, options);
1189}
1190
1191function arrayEqual(a, b) {
1192  if (a.length !== b.length) {
1193    return false;
1194  }
1195
1196  return arrayStartsWith(a, b);
1197}
1198function arrayStartsWith(array, start) {
1199  if (start.length > array.length) {
1200    return false;
1201  }
1202
1203  for (var i = 0; i < start.length; i++) {
1204    if (start[i] !== array[i]) {
1205      return false;
1206    }
1207  }
1208
1209  return true;
1210}
1211
1212function calcLineCount(hunk) {
1213  var _calcOldNewLineCount = calcOldNewLineCount(hunk.lines),
1214      oldLines = _calcOldNewLineCount.oldLines,
1215      newLines = _calcOldNewLineCount.newLines;
1216
1217  if (oldLines !== undefined) {
1218    hunk.oldLines = oldLines;
1219  } else {
1220    delete hunk.oldLines;
1221  }
1222
1223  if (newLines !== undefined) {
1224    hunk.newLines = newLines;
1225  } else {
1226    delete hunk.newLines;
1227  }
1228}
1229function merge(mine, theirs, base) {
1230  mine = loadPatch(mine, base);
1231  theirs = loadPatch(theirs, base);
1232  var ret = {}; // For index we just let it pass through as it doesn't have any necessary meaning.
1233  // Leaving sanity checks on this to the API consumer that may know more about the
1234  // meaning in their own context.
1235
1236  if (mine.index || theirs.index) {
1237    ret.index = mine.index || theirs.index;
1238  }
1239
1240  if (mine.newFileName || theirs.newFileName) {
1241    if (!fileNameChanged(mine)) {
1242      // No header or no change in ours, use theirs (and ours if theirs does not exist)
1243      ret.oldFileName = theirs.oldFileName || mine.oldFileName;
1244      ret.newFileName = theirs.newFileName || mine.newFileName;
1245      ret.oldHeader = theirs.oldHeader || mine.oldHeader;
1246      ret.newHeader = theirs.newHeader || mine.newHeader;
1247    } else if (!fileNameChanged(theirs)) {
1248      // No header or no change in theirs, use ours
1249      ret.oldFileName = mine.oldFileName;
1250      ret.newFileName = mine.newFileName;
1251      ret.oldHeader = mine.oldHeader;
1252      ret.newHeader = mine.newHeader;
1253    } else {
1254      // Both changed... figure it out
1255      ret.oldFileName = selectField(ret, mine.oldFileName, theirs.oldFileName);
1256      ret.newFileName = selectField(ret, mine.newFileName, theirs.newFileName);
1257      ret.oldHeader = selectField(ret, mine.oldHeader, theirs.oldHeader);
1258      ret.newHeader = selectField(ret, mine.newHeader, theirs.newHeader);
1259    }
1260  }
1261
1262  ret.hunks = [];
1263  var mineIndex = 0,
1264      theirsIndex = 0,
1265      mineOffset = 0,
1266      theirsOffset = 0;
1267
1268  while (mineIndex < mine.hunks.length || theirsIndex < theirs.hunks.length) {
1269    var mineCurrent = mine.hunks[mineIndex] || {
1270      oldStart: Infinity
1271    },
1272        theirsCurrent = theirs.hunks[theirsIndex] || {
1273      oldStart: Infinity
1274    };
1275
1276    if (hunkBefore(mineCurrent, theirsCurrent)) {
1277      // This patch does not overlap with any of the others, yay.
1278      ret.hunks.push(cloneHunk(mineCurrent, mineOffset));
1279      mineIndex++;
1280      theirsOffset += mineCurrent.newLines - mineCurrent.oldLines;
1281    } else if (hunkBefore(theirsCurrent, mineCurrent)) {
1282      // This patch does not overlap with any of the others, yay.
1283      ret.hunks.push(cloneHunk(theirsCurrent, theirsOffset));
1284      theirsIndex++;
1285      mineOffset += theirsCurrent.newLines - theirsCurrent.oldLines;
1286    } else {
1287      // Overlap, merge as best we can
1288      var mergedHunk = {
1289        oldStart: Math.min(mineCurrent.oldStart, theirsCurrent.oldStart),
1290        oldLines: 0,
1291        newStart: Math.min(mineCurrent.newStart + mineOffset, theirsCurrent.oldStart + theirsOffset),
1292        newLines: 0,
1293        lines: []
1294      };
1295      mergeLines(mergedHunk, mineCurrent.oldStart, mineCurrent.lines, theirsCurrent.oldStart, theirsCurrent.lines);
1296      theirsIndex++;
1297      mineIndex++;
1298      ret.hunks.push(mergedHunk);
1299    }
1300  }
1301
1302  return ret;
1303}
1304
1305function loadPatch(param, base) {
1306  if (typeof param === 'string') {
1307    if (/^@@/m.test(param) || /^Index:/m.test(param)) {
1308      return parsePatch(param)[0];
1309    }
1310
1311    if (!base) {
1312      throw new Error('Must provide a base reference or pass in a patch');
1313    }
1314
1315    return structuredPatch(undefined, undefined, base, param);
1316  }
1317
1318  return param;
1319}
1320
1321function fileNameChanged(patch) {
1322  return patch.newFileName && patch.newFileName !== patch.oldFileName;
1323}
1324
1325function selectField(index, mine, theirs) {
1326  if (mine === theirs) {
1327    return mine;
1328  } else {
1329    index.conflict = true;
1330    return {
1331      mine: mine,
1332      theirs: theirs
1333    };
1334  }
1335}
1336
1337function hunkBefore(test, check) {
1338  return test.oldStart < check.oldStart && test.oldStart + test.oldLines < check.oldStart;
1339}
1340
1341function cloneHunk(hunk, offset) {
1342  return {
1343    oldStart: hunk.oldStart,
1344    oldLines: hunk.oldLines,
1345    newStart: hunk.newStart + offset,
1346    newLines: hunk.newLines,
1347    lines: hunk.lines
1348  };
1349}
1350
1351function mergeLines(hunk, mineOffset, mineLines, theirOffset, theirLines) {
1352  // This will generally result in a conflicted hunk, but there are cases where the context
1353  // is the only overlap where we can successfully merge the content here.
1354  var mine = {
1355    offset: mineOffset,
1356    lines: mineLines,
1357    index: 0
1358  },
1359      their = {
1360    offset: theirOffset,
1361    lines: theirLines,
1362    index: 0
1363  }; // Handle any leading content
1364
1365  insertLeading(hunk, mine, their);
1366  insertLeading(hunk, their, mine); // Now in the overlap content. Scan through and select the best changes from each.
1367
1368  while (mine.index < mine.lines.length && their.index < their.lines.length) {
1369    var mineCurrent = mine.lines[mine.index],
1370        theirCurrent = their.lines[their.index];
1371
1372    if ((mineCurrent[0] === '-' || mineCurrent[0] === '+') && (theirCurrent[0] === '-' || theirCurrent[0] === '+')) {
1373      // Both modified ...
1374      mutualChange(hunk, mine, their);
1375    } else if (mineCurrent[0] === '+' && theirCurrent[0] === ' ') {
1376      var _hunk$lines;
1377
1378      // Mine inserted
1379      (_hunk$lines = hunk.lines).push.apply(_hunk$lines, _toConsumableArray(collectChange(mine)));
1380    } else if (theirCurrent[0] === '+' && mineCurrent[0] === ' ') {
1381      var _hunk$lines2;
1382
1383      // Theirs inserted
1384      (_hunk$lines2 = hunk.lines).push.apply(_hunk$lines2, _toConsumableArray(collectChange(their)));
1385    } else if (mineCurrent[0] === '-' && theirCurrent[0] === ' ') {
1386      // Mine removed or edited
1387      removal(hunk, mine, their);
1388    } else if (theirCurrent[0] === '-' && mineCurrent[0] === ' ') {
1389      // Their removed or edited
1390      removal(hunk, their, mine, true);
1391    } else if (mineCurrent === theirCurrent) {
1392      // Context identity
1393      hunk.lines.push(mineCurrent);
1394      mine.index++;
1395      their.index++;
1396    } else {
1397      // Context mismatch
1398      conflict(hunk, collectChange(mine), collectChange(their));
1399    }
1400  } // Now push anything that may be remaining
1401
1402
1403  insertTrailing(hunk, mine);
1404  insertTrailing(hunk, their);
1405  calcLineCount(hunk);
1406}
1407
1408function mutualChange(hunk, mine, their) {
1409  var myChanges = collectChange(mine),
1410      theirChanges = collectChange(their);
1411
1412  if (allRemoves(myChanges) && allRemoves(theirChanges)) {
1413    // Special case for remove changes that are supersets of one another
1414    if (arrayStartsWith(myChanges, theirChanges) && skipRemoveSuperset(their, myChanges, myChanges.length - theirChanges.length)) {
1415      var _hunk$lines3;
1416
1417      (_hunk$lines3 = hunk.lines).push.apply(_hunk$lines3, _toConsumableArray(myChanges));
1418
1419      return;
1420    } else if (arrayStartsWith(theirChanges, myChanges) && skipRemoveSuperset(mine, theirChanges, theirChanges.length - myChanges.length)) {
1421      var _hunk$lines4;
1422
1423      (_hunk$lines4 = hunk.lines).push.apply(_hunk$lines4, _toConsumableArray(theirChanges));
1424
1425      return;
1426    }
1427  } else if (arrayEqual(myChanges, theirChanges)) {
1428    var _hunk$lines5;
1429
1430    (_hunk$lines5 = hunk.lines).push.apply(_hunk$lines5, _toConsumableArray(myChanges));
1431
1432    return;
1433  }
1434
1435  conflict(hunk, myChanges, theirChanges);
1436}
1437
1438function removal(hunk, mine, their, swap) {
1439  var myChanges = collectChange(mine),
1440      theirChanges = collectContext(their, myChanges);
1441
1442  if (theirChanges.merged) {
1443    var _hunk$lines6;
1444
1445    (_hunk$lines6 = hunk.lines).push.apply(_hunk$lines6, _toConsumableArray(theirChanges.merged));
1446  } else {
1447    conflict(hunk, swap ? theirChanges : myChanges, swap ? myChanges : theirChanges);
1448  }
1449}
1450
1451function conflict(hunk, mine, their) {
1452  hunk.conflict = true;
1453  hunk.lines.push({
1454    conflict: true,
1455    mine: mine,
1456    theirs: their
1457  });
1458}
1459
1460function insertLeading(hunk, insert, their) {
1461  while (insert.offset < their.offset && insert.index < insert.lines.length) {
1462    var line = insert.lines[insert.index++];
1463    hunk.lines.push(line);
1464    insert.offset++;
1465  }
1466}
1467
1468function insertTrailing(hunk, insert) {
1469  while (insert.index < insert.lines.length) {
1470    var line = insert.lines[insert.index++];
1471    hunk.lines.push(line);
1472  }
1473}
1474
1475function collectChange(state) {
1476  var ret = [],
1477      operation = state.lines[state.index][0];
1478
1479  while (state.index < state.lines.length) {
1480    var line = state.lines[state.index]; // Group additions that are immediately after subtractions and treat them as one "atomic" modify change.
1481
1482    if (operation === '-' && line[0] === '+') {
1483      operation = '+';
1484    }
1485
1486    if (operation === line[0]) {
1487      ret.push(line);
1488      state.index++;
1489    } else {
1490      break;
1491    }
1492  }
1493
1494  return ret;
1495}
1496
1497function collectContext(state, matchChanges) {
1498  var changes = [],
1499      merged = [],
1500      matchIndex = 0,
1501      contextChanges = false,
1502      conflicted = false;
1503
1504  while (matchIndex < matchChanges.length && state.index < state.lines.length) {
1505    var change = state.lines[state.index],
1506        match = matchChanges[matchIndex]; // Once we've hit our add, then we are done
1507
1508    if (match[0] === '+') {
1509      break;
1510    }
1511
1512    contextChanges = contextChanges || change[0] !== ' ';
1513    merged.push(match);
1514    matchIndex++; // Consume any additions in the other block as a conflict to attempt
1515    // to pull in the remaining context after this
1516
1517    if (change[0] === '+') {
1518      conflicted = true;
1519
1520      while (change[0] === '+') {
1521        changes.push(change);
1522        change = state.lines[++state.index];
1523      }
1524    }
1525
1526    if (match.substr(1) === change.substr(1)) {
1527      changes.push(change);
1528      state.index++;
1529    } else {
1530      conflicted = true;
1531    }
1532  }
1533
1534  if ((matchChanges[matchIndex] || '')[0] === '+' && contextChanges) {
1535    conflicted = true;
1536  }
1537
1538  if (conflicted) {
1539    return changes;
1540  }
1541
1542  while (matchIndex < matchChanges.length) {
1543    merged.push(matchChanges[matchIndex++]);
1544  }
1545
1546  return {
1547    merged: merged,
1548    changes: changes
1549  };
1550}
1551
1552function allRemoves(changes) {
1553  return changes.reduce(function (prev, change) {
1554    return prev && change[0] === '-';
1555  }, true);
1556}
1557
1558function skipRemoveSuperset(state, removeChanges, delta) {
1559  for (var i = 0; i < delta; i++) {
1560    var changeContent = removeChanges[removeChanges.length - delta + i].substr(1);
1561
1562    if (state.lines[state.index + i] !== ' ' + changeContent) {
1563      return false;
1564    }
1565  }
1566
1567  state.index += delta;
1568  return true;
1569}
1570
1571function calcOldNewLineCount(lines) {
1572  var oldLines = 0;
1573  var newLines = 0;
1574  lines.forEach(function (line) {
1575    if (typeof line !== 'string') {
1576      var myCount = calcOldNewLineCount(line.mine);
1577      var theirCount = calcOldNewLineCount(line.theirs);
1578
1579      if (oldLines !== undefined) {
1580        if (myCount.oldLines === theirCount.oldLines) {
1581          oldLines += myCount.oldLines;
1582        } else {
1583          oldLines = undefined;
1584        }
1585      }
1586
1587      if (newLines !== undefined) {
1588        if (myCount.newLines === theirCount.newLines) {
1589          newLines += myCount.newLines;
1590        } else {
1591          newLines = undefined;
1592        }
1593      }
1594    } else {
1595      if (newLines !== undefined && (line[0] === '+' || line[0] === ' ')) {
1596        newLines++;
1597      }
1598
1599      if (oldLines !== undefined && (line[0] === '-' || line[0] === ' ')) {
1600        oldLines++;
1601      }
1602    }
1603  });
1604  return {
1605    oldLines: oldLines,
1606    newLines: newLines
1607  };
1608}
1609
1610function reversePatch(structuredPatch) {
1611  if (Array.isArray(structuredPatch)) {
1612    return structuredPatch.map(reversePatch).reverse();
1613  }
1614
1615  return _objectSpread2(_objectSpread2({}, structuredPatch), {}, {
1616    oldFileName: structuredPatch.newFileName,
1617    oldHeader: structuredPatch.newHeader,
1618    newFileName: structuredPatch.oldFileName,
1619    newHeader: structuredPatch.oldHeader,
1620    hunks: structuredPatch.hunks.map(function (hunk) {
1621      return {
1622        oldLines: hunk.newLines,
1623        oldStart: hunk.newStart,
1624        newLines: hunk.oldLines,
1625        newStart: hunk.oldStart,
1626        linedelimiters: hunk.linedelimiters,
1627        lines: hunk.lines.map(function (l) {
1628          if (l.startsWith('-')) {
1629            return "+".concat(l.slice(1));
1630          }
1631
1632          if (l.startsWith('+')) {
1633            return "-".concat(l.slice(1));
1634          }
1635
1636          return l;
1637        })
1638      };
1639    })
1640  });
1641}
1642
1643// See: http://code.google.com/p/google-diff-match-patch/wiki/API
1644function convertChangesToDMP(changes) {
1645  var ret = [],
1646      change,
1647      operation;
1648
1649  for (var i = 0; i < changes.length; i++) {
1650    change = changes[i];
1651
1652    if (change.added) {
1653      operation = 1;
1654    } else if (change.removed) {
1655      operation = -1;
1656    } else {
1657      operation = 0;
1658    }
1659
1660    ret.push([operation, change.value]);
1661  }
1662
1663  return ret;
1664}
1665
1666function convertChangesToXML(changes) {
1667  var ret = [];
1668
1669  for (var i = 0; i < changes.length; i++) {
1670    var change = changes[i];
1671
1672    if (change.added) {
1673      ret.push('<ins>');
1674    } else if (change.removed) {
1675      ret.push('<del>');
1676    }
1677
1678    ret.push(escapeHTML(change.value));
1679
1680    if (change.added) {
1681      ret.push('</ins>');
1682    } else if (change.removed) {
1683      ret.push('</del>');
1684    }
1685  }
1686
1687  return ret.join('');
1688}
1689
1690function escapeHTML(s) {
1691  var n = s;
1692  n = n.replace(/&/g, '&amp;');
1693  n = n.replace(/</g, '&lt;');
1694  n = n.replace(/>/g, '&gt;');
1695  n = n.replace(/"/g, '&quot;');
1696  return n;
1697}
1698
1699export { Diff, applyPatch, applyPatches, canonicalize, convertChangesToDMP, convertChangesToXML, createPatch, createTwoFilesPatch, diffArrays, diffChars, diffCss, diffJson, diffLines, diffSentences, diffTrimmedLines, diffWords, diffWordsWithSpace, formatPatch, merge, parsePatch, reversePatch, structuredPatch };
1700