You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							290 lines
						
					
					
						
							9.6 KiB
						
					
					
				
			
		
		
	
	
							290 lines
						
					
					
						
							9.6 KiB
						
					
					
				'use strict'; | 
						|
 | 
						|
Object.defineProperty(exports, '__esModule', { | 
						|
  value: true | 
						|
}); | 
						|
exports.default = void 0; | 
						|
 | 
						|
var _chalk = _interopRequireDefault(require('chalk')); | 
						|
 | 
						|
var _diffSequences = _interopRequireDefault(require('diff-sequences')); | 
						|
 | 
						|
var _constants = require('./constants'); | 
						|
 | 
						|
var _printDiffs = require('./printDiffs'); | 
						|
 | 
						|
function _interopRequireDefault(obj) { | 
						|
  return obj && obj.__esModule ? obj : {default: obj}; | 
						|
} | 
						|
 | 
						|
/** | 
						|
 * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | 
						|
 * | 
						|
 * This source code is licensed under the MIT license found in the | 
						|
 * LICENSE file in the root directory of this source tree. | 
						|
 */ | 
						|
const DIFF_CONTEXT_DEFAULT = 5; | 
						|
const fgDelete = _chalk.default.green; | 
						|
const fgInsert = _chalk.default.red; | 
						|
const fgCommon = _chalk.default.dim; // common lines (even indentation same) | 
						|
 | 
						|
const fgIndent = _chalk.default.cyan; // common lines (only indentation different) | 
						|
 | 
						|
const bgCommon = _chalk.default.bgYellow; // edge spaces in common line (even indentation same) | 
						|
 | 
						|
const bgInverse = _chalk.default.inverse; // edge spaces in any other lines | 
						|
// ONLY trailing if expected value is snapshot or multiline string. | 
						|
 | 
						|
const highlightTrailingSpaces = (line, bgColor) => | 
						|
  line.replace(/\s+$/, bgColor('$&')); // BOTH leading AND trailing if expected value is data structure. | 
						|
 | 
						|
const highlightLeadingTrailingSpaces = ( | 
						|
  line, | 
						|
  bgColor // If line consists of ALL spaces: highlight all of them. | 
						|
) => | 
						|
  highlightTrailingSpaces(line, bgColor).replace( | 
						|
    // If line has an ODD length of leading spaces: highlight only the LAST. | 
						|
    /^(\s\s)*(\s)(?=[^\s])/, | 
						|
    '$1' + bgColor('$2') | 
						|
  ); | 
						|
 | 
						|
const getHighlightSpaces = bothEdges => | 
						|
  bothEdges ? highlightLeadingTrailingSpaces : highlightTrailingSpaces; | 
						|
 | 
						|
// Given index interval in expected lines, put formatted delete lines. | 
						|
const formatDelete = (aStart, aEnd, aLinesUn, aLinesIn, put) => { | 
						|
  const highlightSpaces = getHighlightSpaces(aLinesUn !== aLinesIn); | 
						|
 | 
						|
  for (let aIndex = aStart; aIndex !== aEnd; aIndex += 1) { | 
						|
    const aLineUn = aLinesUn[aIndex]; | 
						|
    const aLineIn = aLinesIn[aIndex]; | 
						|
    const indentation = aLineIn.slice(0, aLineIn.length - aLineUn.length); | 
						|
    put(fgDelete('- ' + indentation + highlightSpaces(aLineUn, bgInverse))); | 
						|
  } | 
						|
}; // Given index interval in received lines, put formatted insert lines. | 
						|
 | 
						|
const formatInsert = (bStart, bEnd, bLinesUn, bLinesIn, put) => { | 
						|
  const highlightSpaces = getHighlightSpaces(bLinesUn !== bLinesIn); | 
						|
 | 
						|
  for (let bIndex = bStart; bIndex !== bEnd; bIndex += 1) { | 
						|
    const bLineUn = bLinesUn[bIndex]; | 
						|
    const bLineIn = bLinesIn[bIndex]; | 
						|
    const indentation = bLineIn.slice(0, bLineIn.length - bLineUn.length); | 
						|
    put(fgInsert('+ ' + indentation + highlightSpaces(bLineUn, bgInverse))); | 
						|
  } | 
						|
}; // Given the number of items and starting indexes of a common subsequence, | 
						|
// put formatted common lines. | 
						|
 | 
						|
const formatCommon = ( | 
						|
  nCommon, | 
						|
  aCommon, | 
						|
  bCommon, | 
						|
  aLinesIn, | 
						|
  bLinesUn, | 
						|
  bLinesIn, | 
						|
  put | 
						|
) => { | 
						|
  const highlightSpaces = getHighlightSpaces(bLinesUn !== bLinesIn); | 
						|
 | 
						|
  for (; nCommon !== 0; nCommon -= 1, aCommon += 1, bCommon += 1) { | 
						|
    const bLineUn = bLinesUn[bCommon]; | 
						|
    const bLineIn = bLinesIn[bCommon]; | 
						|
    const bLineInLength = bLineIn.length; // For common lines, received indentation seems more intuitive. | 
						|
 | 
						|
    const indentation = bLineIn.slice(0, bLineInLength - bLineUn.length); // Color shows whether expected and received line has same indentation. | 
						|
 | 
						|
    const hasSameIndentation = aLinesIn[aCommon].length === bLineInLength; | 
						|
    const fg = hasSameIndentation ? fgCommon : fgIndent; | 
						|
    const bg = hasSameIndentation ? bgCommon : bgInverse; | 
						|
    put(fg('  ' + indentation + highlightSpaces(bLineUn, bg))); | 
						|
  } | 
						|
}; // jest --expand | 
						|
// Return formatted diff as joined string of all lines. | 
						|
 | 
						|
const diffExpand = (aLinesUn, bLinesUn, aLinesIn, bLinesIn) => { | 
						|
  const isCommon = (aIndex, bIndex) => aLinesUn[aIndex] === bLinesUn[bIndex]; | 
						|
 | 
						|
  const array = []; | 
						|
 | 
						|
  const put = line => { | 
						|
    array.push(line); | 
						|
  }; | 
						|
 | 
						|
  let aStart = 0; | 
						|
  let bStart = 0; | 
						|
 | 
						|
  const foundSubsequence = (nCommon, aCommon, bCommon) => { | 
						|
    formatDelete(aStart, aCommon, aLinesUn, aLinesIn, put); | 
						|
    formatInsert(bStart, bCommon, bLinesUn, bLinesIn, put); | 
						|
    formatCommon(nCommon, aCommon, bCommon, aLinesIn, bLinesUn, bLinesIn, put); | 
						|
    aStart = aCommon + nCommon; | 
						|
    bStart = bCommon + nCommon; | 
						|
  }; | 
						|
 | 
						|
  const aLength = aLinesUn.length; | 
						|
  const bLength = bLinesUn.length; | 
						|
  (0, _diffSequences.default)(aLength, bLength, isCommon, foundSubsequence); // After the last common subsequence, format remaining change lines. | 
						|
 | 
						|
  formatDelete(aStart, aLength, aLinesUn, aLinesIn, put); | 
						|
  formatInsert(bStart, bLength, bLinesUn, bLinesIn, put); | 
						|
  return array.join('\n'); | 
						|
}; | 
						|
 | 
						|
const getContextLines = options => | 
						|
  options && | 
						|
  typeof options.contextLines === 'number' && | 
						|
  options.contextLines >= 0 | 
						|
    ? options.contextLines | 
						|
    : DIFF_CONTEXT_DEFAULT; // jest --no-expand | 
						|
// Return joined string of formatted diff for all change lines, | 
						|
// but if some common lines are omitted because there are more than the context, | 
						|
// then a “patch mark” precedes each set of adjacent changed and common lines. | 
						|
 | 
						|
const diffNoExpand = ( | 
						|
  aLinesUn, | 
						|
  bLinesUn, | 
						|
  aLinesIn, | 
						|
  bLinesIn, | 
						|
  nContextLines | 
						|
) => { | 
						|
  const isCommon = (aIndex, bIndex) => aLinesUn[aIndex] === bLinesUn[bIndex]; | 
						|
 | 
						|
  let iPatchMark = 0; // index of placeholder line for patch mark | 
						|
 | 
						|
  const array = ['']; | 
						|
 | 
						|
  const put = line => { | 
						|
    array.push(line); | 
						|
  }; | 
						|
 | 
						|
  let isAtEnd = false; | 
						|
  const aLength = aLinesUn.length; | 
						|
  const bLength = bLinesUn.length; | 
						|
  const nContextLines2 = nContextLines + nContextLines; // Initialize the first patch for changes at the start, | 
						|
  // especially for edge case in which there is no common subsequence. | 
						|
 | 
						|
  let aStart = 0; | 
						|
  let aEnd = 0; | 
						|
  let bStart = 0; | 
						|
  let bEnd = 0; // Given the number of items and starting indexes of each common subsequence, | 
						|
  // format any preceding change lines, and then common context lines. | 
						|
 | 
						|
  const foundSubsequence = (nCommon, aStartCommon, bStartCommon) => { | 
						|
    const aEndCommon = aStartCommon + nCommon; | 
						|
    const bEndCommon = bStartCommon + nCommon; | 
						|
    isAtEnd = aEndCommon === aLength && bEndCommon === bLength; // If common subsequence is at start, re-initialize the first patch. | 
						|
 | 
						|
    if (aStartCommon === 0 && bStartCommon === 0) { | 
						|
      const nLines = nContextLines < nCommon ? nContextLines : nCommon; | 
						|
      aStart = aEndCommon - nLines; | 
						|
      bStart = bEndCommon - nLines; | 
						|
      formatCommon(nLines, aStart, bStart, aLinesIn, bLinesUn, bLinesIn, put); | 
						|
      aEnd = aEndCommon; | 
						|
      bEnd = bEndCommon; | 
						|
      return; | 
						|
    } // Format preceding change lines. | 
						|
 | 
						|
    formatDelete(aEnd, aStartCommon, aLinesUn, aLinesIn, put); | 
						|
    formatInsert(bEnd, bStartCommon, bLinesUn, bLinesIn, put); | 
						|
    aEnd = aStartCommon; | 
						|
    bEnd = bStartCommon; // If common subsequence is at end, then context follows preceding changes; | 
						|
    // else context follows preceding changes AND precedes following changes. | 
						|
 | 
						|
    const maxContextLines = isAtEnd ? nContextLines : nContextLines2; | 
						|
 | 
						|
    if (nCommon <= maxContextLines) { | 
						|
      // The patch includes all lines in the common subsequence. | 
						|
      formatCommon(nCommon, aEnd, bEnd, aLinesIn, bLinesUn, bLinesIn, put); | 
						|
      aEnd += nCommon; | 
						|
      bEnd += nCommon; | 
						|
      return; | 
						|
    } // The patch ends because context is less than number of common lines. | 
						|
 | 
						|
    formatCommon(nContextLines, aEnd, bEnd, aLinesIn, bLinesUn, bLinesIn, put); | 
						|
    aEnd += nContextLines; | 
						|
    bEnd += nContextLines; | 
						|
    array[iPatchMark] = (0, _printDiffs.createPatchMark)( | 
						|
      aStart, | 
						|
      aEnd, | 
						|
      bStart, | 
						|
      bEnd | 
						|
    ); // If common subsequence is not at end, another patch follows it. | 
						|
 | 
						|
    if (!isAtEnd) { | 
						|
      iPatchMark = array.length; // index of placeholder line | 
						|
 | 
						|
      array[iPatchMark] = ''; | 
						|
      const nLines = nContextLines < nCommon ? nContextLines : nCommon; | 
						|
      aStart = aEndCommon - nLines; | 
						|
      bStart = bEndCommon - nLines; | 
						|
      formatCommon(nLines, aStart, bStart, aLinesIn, bLinesUn, bLinesIn, put); | 
						|
      aEnd = aEndCommon; | 
						|
      bEnd = bEndCommon; | 
						|
    } | 
						|
  }; | 
						|
 | 
						|
  (0, _diffSequences.default)(aLength, bLength, isCommon, foundSubsequence); // If no common subsequence or last was not at end, format remaining change lines. | 
						|
 | 
						|
  if (!isAtEnd) { | 
						|
    formatDelete(aEnd, aLength, aLinesUn, aLinesIn, put); | 
						|
    formatInsert(bEnd, bLength, bLinesUn, bLinesIn, put); | 
						|
    aEnd = aLength; | 
						|
    bEnd = bLength; | 
						|
  } | 
						|
 | 
						|
  if (aStart === 0 && aEnd === aLength && bStart === 0 && bEnd === bLength) { | 
						|
    array.splice(0, 1); // delete placeholder line for patch mark | 
						|
  } else { | 
						|
    array[iPatchMark] = (0, _printDiffs.createPatchMark)( | 
						|
      aStart, | 
						|
      aEnd, | 
						|
      bStart, | 
						|
      bEnd | 
						|
    ); | 
						|
  } | 
						|
 | 
						|
  return array.join('\n'); | 
						|
}; | 
						|
 | 
						|
var _default = (a, b, options, original) => { | 
						|
  if (a === b) { | 
						|
    return _constants.NO_DIFF_MESSAGE; | 
						|
  } | 
						|
 | 
						|
  let aLinesUn = a.split('\n'); | 
						|
  let bLinesUn = b.split('\n'); // Indentation is unknown if expected value is snapshot or multiline string. | 
						|
 | 
						|
  let aLinesIn = aLinesUn; | 
						|
  let bLinesIn = bLinesUn; | 
						|
 | 
						|
  if (original) { | 
						|
    // Indentation is known if expected value is data structure: | 
						|
    // Compare lines without indentation and format lines with indentation. | 
						|
    aLinesIn = original.a.split('\n'); | 
						|
    bLinesIn = original.b.split('\n'); | 
						|
 | 
						|
    if ( | 
						|
      aLinesUn.length !== aLinesIn.length || | 
						|
      bLinesUn.length !== bLinesIn.length | 
						|
    ) { | 
						|
      // Fall back if unindented and indented lines are inconsistent. | 
						|
      aLinesUn = aLinesIn; | 
						|
      bLinesUn = bLinesIn; | 
						|
    } | 
						|
  } | 
						|
 | 
						|
  return ( | 
						|
    (0, _printDiffs.printAnnotation)(options) + | 
						|
    (options && options.expand === false | 
						|
      ? diffNoExpand( | 
						|
          aLinesUn, | 
						|
          bLinesUn, | 
						|
          aLinesIn, | 
						|
          bLinesIn, | 
						|
          getContextLines(options) | 
						|
        ) | 
						|
      : diffExpand(aLinesUn, bLinesUn, aLinesIn, bLinesIn)) | 
						|
  ); | 
						|
}; | 
						|
 | 
						|
exports.default = _default;
 | 
						|
 |