printDiffs.js 6.6 KB

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