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;