printDiffs.js
  1  'use strict';
  2  
  3  Object.defineProperty(exports, '__esModule', {
  4    value: true
  5  });
  6  exports.diffStringsRaw = exports.diffStringsUnified = exports.createPatchMark = exports.printDiffLines = exports.printAnnotation = exports.countChanges = exports.hasCommonDiff = exports.printCommonLine = exports.printInsertLine = exports.printDeleteLine = void 0;
  7  
  8  var _cleanupSemantic = require('./cleanupSemantic');
  9  
 10  var _diffLines = require('./diffLines');
 11  
 12  var _diffStrings = _interopRequireDefault(require('./diffStrings'));
 13  
 14  var _getAlignedDiffs = _interopRequireDefault(require('./getAlignedDiffs'));
 15  
 16  var _joinAlignedDiffs = require('./joinAlignedDiffs');
 17  
 18  var _normalizeDiffOptions = require('./normalizeDiffOptions');
 19  
 20  function _interopRequireDefault(obj) {
 21    return obj && obj.__esModule ? obj : {default: obj};
 22  }
 23  
 24  /**
 25   * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
 26   *
 27   * This source code is licensed under the MIT license found in the
 28   * LICENSE file in the root directory of this source tree.
 29   */
 30  const formatTrailingSpaces = (line, trailingSpaceFormatter) =>
 31    line.replace(/\s+$/, match => trailingSpaceFormatter(match));
 32  
 33  const printDiffLine = (
 34    line,
 35    isFirstOrLast,
 36    color,
 37    indicator,
 38    trailingSpaceFormatter,
 39    emptyFirstOrLastLinePlaceholder
 40  ) =>
 41    line.length !== 0
 42      ? color(
 43          indicator + ' ' + formatTrailingSpaces(line, trailingSpaceFormatter)
 44        )
 45      : indicator !== ' '
 46      ? color(indicator)
 47      : isFirstOrLast && emptyFirstOrLastLinePlaceholder.length !== 0
 48      ? color(indicator + ' ' + emptyFirstOrLastLinePlaceholder)
 49      : '';
 50  
 51  const printDeleteLine = (
 52    line,
 53    isFirstOrLast,
 54    {
 55      aColor,
 56      aIndicator,
 57      changeLineTrailingSpaceColor,
 58      emptyFirstOrLastLinePlaceholder
 59    }
 60  ) =>
 61    printDiffLine(
 62      line,
 63      isFirstOrLast,
 64      aColor,
 65      aIndicator,
 66      changeLineTrailingSpaceColor,
 67      emptyFirstOrLastLinePlaceholder
 68    );
 69  
 70  exports.printDeleteLine = printDeleteLine;
 71  
 72  const printInsertLine = (
 73    line,
 74    isFirstOrLast,
 75    {
 76      bColor,
 77      bIndicator,
 78      changeLineTrailingSpaceColor,
 79      emptyFirstOrLastLinePlaceholder
 80    }
 81  ) =>
 82    printDiffLine(
 83      line,
 84      isFirstOrLast,
 85      bColor,
 86      bIndicator,
 87      changeLineTrailingSpaceColor,
 88      emptyFirstOrLastLinePlaceholder
 89    );
 90  
 91  exports.printInsertLine = printInsertLine;
 92  
 93  const printCommonLine = (
 94    line,
 95    isFirstOrLast,
 96    {
 97      commonColor,
 98      commonIndicator,
 99      commonLineTrailingSpaceColor,
100      emptyFirstOrLastLinePlaceholder
101    }
102  ) =>
103    printDiffLine(
104      line,
105      isFirstOrLast,
106      commonColor,
107      commonIndicator,
108      commonLineTrailingSpaceColor,
109      emptyFirstOrLastLinePlaceholder
110    );
111  
112  exports.printCommonLine = printCommonLine;
113  
114  const hasCommonDiff = (diffs, isMultiline) => {
115    if (isMultiline) {
116      // Important: Ignore common newline that was appended to multiline strings!
117      const iLast = diffs.length - 1;
118      return diffs.some(
119        (diff, i) =>
120          diff[0] === _cleanupSemantic.DIFF_EQUAL &&
121          (i !== iLast || diff[1] !== '\n')
122      );
123    }
124  
125    return diffs.some(diff => diff[0] === _cleanupSemantic.DIFF_EQUAL);
126  };
127  
128  exports.hasCommonDiff = hasCommonDiff;
129  
130  const countChanges = diffs => {
131    let a = 0;
132    let b = 0;
133    diffs.forEach(diff => {
134      switch (diff[0]) {
135        case _cleanupSemantic.DIFF_DELETE:
136          a += 1;
137          break;
138  
139        case _cleanupSemantic.DIFF_INSERT:
140          b += 1;
141          break;
142      }
143    });
144    return {
145      a,
146      b
147    };
148  };
149  
150  exports.countChanges = countChanges;
151  
152  const printAnnotation = (
153    {
154      aAnnotation,
155      aColor,
156      aIndicator,
157      bAnnotation,
158      bColor,
159      bIndicator,
160      includeChangeCounts,
161      omitAnnotationLines
162    },
163    changeCounts
164  ) => {
165    if (omitAnnotationLines) {
166      return '';
167    }
168  
169    let aRest = '';
170    let bRest = '';
171  
172    if (includeChangeCounts) {
173      const aCount = String(changeCounts.a);
174      const bCount = String(changeCounts.b); // Padding right aligns the ends of the annotations.
175  
176      const baAnnotationLengthDiff = bAnnotation.length - aAnnotation.length;
177      const aAnnotationPadding = ' '.repeat(Math.max(0, baAnnotationLengthDiff));
178      const bAnnotationPadding = ' '.repeat(Math.max(0, -baAnnotationLengthDiff)); // Padding left aligns the ends of the counts.
179  
180      const baCountLengthDiff = bCount.length - aCount.length;
181      const aCountPadding = ' '.repeat(Math.max(0, baCountLengthDiff));
182      const bCountPadding = ' '.repeat(Math.max(0, -baCountLengthDiff));
183      aRest =
184        aAnnotationPadding + '  ' + aIndicator + ' ' + aCountPadding + aCount;
185      bRest =
186        bAnnotationPadding + '  ' + bIndicator + ' ' + bCountPadding + bCount;
187    }
188  
189    return (
190      aColor(aIndicator + ' ' + aAnnotation + aRest) +
191      '\n' +
192      bColor(bIndicator + ' ' + bAnnotation + bRest) +
193      '\n\n'
194    );
195  };
196  
197  exports.printAnnotation = printAnnotation;
198  
199  const printDiffLines = (diffs, options) =>
200    printAnnotation(options, countChanges(diffs)) +
201    (options.expand
202      ? (0, _joinAlignedDiffs.joinAlignedDiffsExpand)(diffs, options)
203      : (0, _joinAlignedDiffs.joinAlignedDiffsNoExpand)(diffs, options)); // In GNU diff format, indexes are one-based instead of zero-based.
204  
205  exports.printDiffLines = printDiffLines;
206  
207  const createPatchMark = (aStart, aEnd, bStart, bEnd, {patchColor}) =>
208    patchColor(
209      `@@ -${aStart + 1},${aEnd - aStart} +${bStart + 1},${bEnd - bStart} @@`
210    ); // Compare two strings character-by-character.
211  // Format as comparison lines in which changed substrings have inverse colors.
212  
213  exports.createPatchMark = createPatchMark;
214  
215  const diffStringsUnified = (a, b, options) => {
216    if (a !== b && a.length !== 0 && b.length !== 0) {
217      const isMultiline = a.includes('\n') || b.includes('\n'); // getAlignedDiffs assumes that a newline was appended to the strings.
218  
219      const diffs = diffStringsRaw(
220        isMultiline ? a + '\n' : a,
221        isMultiline ? b + '\n' : b,
222        true // cleanupSemantic
223      );
224  
225      if (hasCommonDiff(diffs, isMultiline)) {
226        const optionsNormalized = (0, _normalizeDiffOptions.normalizeDiffOptions)(
227          options
228        );
229        const lines = (0, _getAlignedDiffs.default)(
230          diffs,
231          optionsNormalized.changeColor
232        );
233        return printDiffLines(lines, optionsNormalized);
234      }
235    } // Fall back to line-by-line diff.
236  
237    return (0, _diffLines.diffLinesUnified)(
238      a.split('\n'),
239      b.split('\n'),
240      options
241    );
242  }; // Compare two strings character-by-character.
243  // Optionally clean up small common substrings, also known as chaff.
244  
245  exports.diffStringsUnified = diffStringsUnified;
246  
247  const diffStringsRaw = (a, b, cleanup) => {
248    const diffs = (0, _diffStrings.default)(a, b);
249  
250    if (cleanup) {
251      (0, _cleanupSemantic.cleanupSemantic)(diffs); // impure function
252    }
253  
254    return diffs;
255  };
256  
257  exports.diffStringsRaw = diffStringsRaw;