PageSourceSearch

https://www.msgc.ca/shout/web/v6.51.1.R20260831/node_modules/diff/dist/diff.js

js msgc.ca collected 2026-09-29 07:25:52 UTC 50,124 bytes, 1,627 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.