text: 'use strict';
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.default = diffStrings;
  
  var _chalk = require('chalk');
  
  var _chalk2 = _interopRequireDefault(_chalk);
  
  var _diff = require('diff');
  
  var _constants = require('./constants.js');
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  const DIFF_CONTEXT_DEFAULT = 5; // removed | added | equal
  
  // Given diff digit, return array which consists of:
  // if compared line is removed or added: corresponding original line
  // if compared line is equal: original received and expected lines
  /**
   * Copyright (c) 2014-present, Facebook, Inc. 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.
   *
   * 
   */
  
  // Given chunk, return diff character.
  const getDiffChar = chunk => chunk.removed ? '-' : chunk.added ? '+' : ' ';
  
  // Given diff character in line of hunk or computed from properties of chunk.
  const getDiffDigit = char => char === '-' ? -1 : char === '+' ? 1 : 0;
  
  // Color for text of line.
  const getColor = (digit, onlyIndentationChanged) => {
    if (digit === -1) {
      return _chalk2.default.green; // removed
    }
    if (digit === 1) {
      return _chalk2.default.red; // added
    }
    return onlyIndentationChanged ? _chalk2.default.cyan : _chalk2.default.dim;
  };
  
  // Do NOT color leading or trailing spaces if original lines are equal:
  
  // Background color for leading or trailing spaces.
  const getBgColor = (digit, onlyIndentationChanged) => digit === 0 && !onlyIndentationChanged ? _chalk2.default.bgYellow : _chalk2.default.inverse;
  
  // 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 getAnnotation = options => _chalk2.default.green('- ' + (options && options.aAnnotation || 'Expected')) + '\n' + _chalk2.default.red('+ ' + (options && options.bAnnotation || 'Received')) + '\n\n';
  
  // Given string, return array of its lines.
  const splitIntoLines = string => {
    const lines = string.split('\n');
  
    if (lines.length !== 0 && lines[lines.length - 1] === '') {
      lines.pop();
    }
  
    return lines;
  };
  
  // Given diff character and compared line, return original line with colors.
  const formatLine = (char, lineCompared, getOriginal) => {
    const digit = getDiffDigit(char);
  
    if (getOriginal) {
      // Compared without indentation if expected value is data structure.
      const lineArray = getOriginal(digit);
      const lineOriginal = lineArray[0];
      const onlyIndentationChanged = digit === 0 && lineOriginal.length !== lineArray[1].length;
  
      return getColor(digit, onlyIndentationChanged)(char + ' ' +
      // Prepend indentation spaces from original to compared line.
      lineOriginal.slice(0, lineOriginal.length - lineCompared.length) + highlightLeadingTrailingSpaces(lineCompared, getBgColor(digit, onlyIndentationChanged)));
    }
  
    // Format compared line when expected is snapshot or multiline string.
    return getColor(digit)(char + ' ' + highlightTrailingSpaces(lineCompared, getBgColor(digit)));
  };
  
  // Given original lines, return callback function
  // which given diff digit, returns array.
  const getterForChunks = original => {
    const linesExpected = splitIntoLines(original.a);
    const linesReceived = splitIntoLines(original.b);
  
    let iExpected = 0;
    let iReceived = 0;
  
    return digit => {
      if (digit === -1) {
        return [linesExpected[iExpected++]];
      }
      if (digit === 1) {
        return [linesReceived[iReceived++]];
      }
      // Because compared line is equal: original received and expected lines.
      return [linesReceived[iReceived++], linesExpected[iExpected++]];
    };
  };
  
  // jest --expand
  const formatChunks = (a, b, original) => {
    const chunks = (0, _diff.diffLines)(a, b);
    if (chunks.every(chunk => !chunk.removed && !chunk.added)) {
      return null;
    }
  
    const getOriginal = original && getterForChunks(original);
    return chunks.reduce((lines, chunk) => {
      const char = getDiffChar(chunk);
  
      splitIntoLines(chunk.value).forEach(line => {
        lines.push(formatLine(char, line, getOriginal));
      });
  
      return lines;
    }, []).join('\n');
  };
  
  // Only show patch marks ("@@ ... @@") if the diff is big.
  // To determine this, we need to compare either the original string (a) to
  // `hunk.oldLines` or a new string to `hunk.newLines`.
  // If the `oldLinesCount` is greater than `hunk.oldLines`
  // we can be sure that at least 1 line has been "hidden".
  const shouldShowPatchMarks = (hunk, oldLinesCount) => oldLinesCount > hunk.oldLines;
  
  const createPatchMark = hunk => {
    const markOld = `-${hunk.oldStart},${hunk.oldLines}`;
    const markNew = `+${hunk.newStart},${hunk.newLines}`;
    return _chalk2.default.yellow(`@@ ${markOld} ${markNew} @@`);
  };
  
  // Given original lines, return callback function which given indexes for hunk,
  // returns another callback function which given diff digit, returns array.
  const getterForHunks = original => {
    const linesExpected = splitIntoLines(original.a);
    const linesReceived = splitIntoLines(original.b);
  
    return (iExpected, iReceived) => digit => {
      if (digit === -1) {
        return [linesExpected[iExpected++]];
      }
      if (digit === 1) {
        return [linesReceived[iReceived++]];
      }
      // Because compared line is equal: original received and expected lines.
      return [linesReceived[iReceived++], linesExpected[iExpected++]];
    };
  };
  
  // jest --no-expand
  const formatHunks = (a, b, contextLines, original) => {
    const options = {
      context: typeof contextLines === 'number' && contextLines >= 0 ? contextLines : DIFF_CONTEXT_DEFAULT
    };
  
    var _structuredPatch = (0, _diff.structuredPatch)('', '', a, b, '', '', options);
  
    const hunks = _structuredPatch.hunks;
  
    if (hunks.length === 0) {
      return null;
    }
  
    const getter = original && getterForHunks(original);
    const oldLinesCount = (a.match(/\n/g) || []).length;
    return hunks.reduce((lines, hunk) => {
      if (shouldShowPatchMarks(hunk, oldLinesCount)) {
        lines.push(createPatchMark(hunk));
      }
  
      // Hunk properties are one-based but index args are zero-based.
      const getOriginal = getter && getter(hunk.oldStart - 1, hunk.newStart - 1);
      hunk.lines.forEach(line => {
        lines.push(formatLine(line[0], line.slice(1), getOriginal));
      });
  
      return lines;
    }, []).join('\n');
  };
  
  function diffStrings(a, b, options, original) {
    // Because `formatHunks` and `formatChunks` ignore one trailing newline,
    // always append newline to strings:
    a += '\n';
    b += '\n';
  
    // `diff` uses the Myers LCS diff algorithm which runs in O(n+d^2) time
    // (where "d" is the edit distance) and can get very slow for large edit
    // distances. Mitigate the cost by switching to a lower-resolution diff
    // whenever linebreaks are involved.
    const result = options && options.expand === false ? formatHunks(a, b, options && options.contextLines, original) : formatChunks(a, b, original);
  
    return result === null ? _constants.NO_DIFF_MESSAGE : getAnnotation(options) + result;
  }