aboutsummaryrefslogtreecommitdiff
path: root/node_modules/jest-diff/build/diffStrings.js
blob: 6961ff801037248b6d35b5118228f292eabafd91 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
 * Copyright (c) 2014, Facebook, Inc. All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * 
 */

'use strict';

const chalk = require('chalk');
const diff = require('diff');var _require =

require('./constants.js');const NO_DIFF_MESSAGE = _require.NO_DIFF_MESSAGE;
const DIFF_CONTEXT = 5;

















const getColor = (added, removed) =>
added ?
chalk.red :
removed ? chalk.green : chalk.dim;

const getBgColor = (added, removed) =>
added ?
chalk.bgRed :
removed ? chalk.bgGreen : chalk.dim;

const highlightTrailingWhitespace = (line, bgColor) =>
line.replace(/\s+$/, bgColor('$&'));

const getAnnotation = options =>
chalk.green('- ' + (options && options.aAnnotation || 'Expected')) + '\n' +
chalk.red('+ ' + (options && options.bAnnotation || 'Received')) + '\n\n';

const diffLines = (a, b) => {
  let isDifferent = false;
  return {
    diff: diff.diffLines(a, b).map(part => {const
      added = part.added,removed = part.removed;
      if (part.added || part.removed) {
        isDifferent = true;
      }

      const lines = part.value.split('\n');
      const color = getColor(added, removed);
      const bgColor = getBgColor(added, removed);

      if (lines[lines.length - 1] === '') {
        lines.pop();
      }

      return lines.map(line => {
        const highlightedLine = highlightTrailingWhitespace(line, bgColor);
        const mark = color(part.added ? '+' : part.removed ? '-' : ' ');
        return mark + ' ' + color(highlightedLine) + '\n';
      }).join('');
    }).join('').trim(),
    isDifferent };

};

// 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 chalk.yellow(`@@ ${markOld} ${markNew} @@\n`);
};

const structuredPatch = (a, b) => {
  const options = { context: DIFF_CONTEXT };
  let isDifferent = false;
  // Make sure the strings end with a newline.
  if (!a.endsWith('\n')) {
    a += '\n';
  }
  if (!b.endsWith('\n')) {
    b += '\n';
  }

  const oldLinesCount = (a.match(/\n/g) || []).length;

  return {
    diff: diff.structuredPatch('', '', a, b, '', '', options).
    hunks.map(hunk => {
      const lines = hunk.lines.map(line => {
        const added = line[0] === '+';
        const removed = line[0] === '-';

        const color = getColor(added, removed);
        const bgColor = getBgColor(added, removed);

        const highlightedLine = highlightTrailingWhitespace(line, bgColor);
        return color(highlightedLine) + '\n';
      }).join('');

      isDifferent = true;
      return shouldShowPatchMarks(hunk, oldLinesCount) ?
      createPatchMark(hunk) + lines :
      lines;
    }).join('').trim(),
    isDifferent };

};

function diffStrings(a, b, options) {
  // `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 ?
  structuredPatch(a, b) :
  diffLines(a, b);

  if (result.isDifferent) {
    return getAnnotation(options) + result.diff;
  } else {
    return NO_DIFF_MESSAGE;
  }
}

module.exports = diffStrings;