mirror of https://github.com/zulip/zulip.git
parent
695affd44e
commit
fc2298ec54
|
@ -23,6 +23,8 @@
|
|||
const jsdom = require('jsdom');
|
||||
const _ = require('underscore');
|
||||
|
||||
const mdiff = require('./mdiff.js');
|
||||
|
||||
// Module-level global instance of MarkdownComparer, initialized when needed
|
||||
let _markdownComparerInstance = null;
|
||||
|
||||
|
@ -155,25 +157,28 @@ class MarkdownComparer {
|
|||
}
|
||||
}
|
||||
|
||||
function returnComparer() {
|
||||
if (!_markdownComparerInstance) {
|
||||
_markdownComparerInstance = new MarkdownComparer((actual, expected) => {
|
||||
return [
|
||||
"Actual and expected output do not match. Showing diff",
|
||||
mdiff.diff_strings(actual, expected),
|
||||
].join('\n');
|
||||
});
|
||||
}
|
||||
return _markdownComparerInstance;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
equal(expected, actual, message) {
|
||||
if (!_markdownComparerInstance) {
|
||||
_markdownComparerInstance = new MarkdownComparer();
|
||||
}
|
||||
_markdownComparerInstance.assertEqual(actual, expected, message);
|
||||
returnComparer().assertEqual(actual, expected, message);
|
||||
},
|
||||
|
||||
notEqual(expected, actual, message) {
|
||||
if (!_markdownComparerInstance) {
|
||||
_markdownComparerInstance = new MarkdownComparer();
|
||||
}
|
||||
_markdownComparerInstance.assertNotEqual(actual, expected, message);
|
||||
returnComparer().assertNotEqual(actual, expected, message);
|
||||
},
|
||||
|
||||
setFormatter(output_formatter) {
|
||||
if (!_markdownComparerInstance) {
|
||||
_markdownComparerInstance = new MarkdownComparer();
|
||||
}
|
||||
_markdownComparerInstance.setFormatter(output_formatter);
|
||||
returnComparer().setFormatter(output_formatter);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/**
|
||||
* mdiff.js
|
||||
*
|
||||
* Used to produce colorful and informative diffs for comparison of generated
|
||||
* Markdown. Unlike the built-in diffs used in python or node.js assert libraries,
|
||||
* is actually designed to be effective for long, single-line comparisons.
|
||||
*
|
||||
* Based on diffing library difflib, a js port of the python library.
|
||||
*
|
||||
* The sole exported function diff_strings(string_0, string_1) returns a pretty-printed
|
||||
* unicode string containing their diff.
|
||||
*/
|
||||
|
||||
const _ = require('underscore');
|
||||
const difflib = require('difflib');
|
||||
|
||||
function apply_color(input_string, changes) {
|
||||
let previous_index = 0;
|
||||
let processed_string = input_string.slice(0,2);
|
||||
input_string = input_string.slice(2);
|
||||
|
||||
const formatter = {
|
||||
delete : (string) => { return "\u001b[31m" + string + "\u001b[0m"; },
|
||||
insert : (string) => { return "\u001b[32m" + string + "\u001b[0m"; },
|
||||
replace : (string) => { return "\u001b[33m" + string + "\u001b[0m"; },
|
||||
};
|
||||
changes.forEach((change) => {
|
||||
if (formatter.hasOwnProperty(change.tag)) {
|
||||
processed_string += input_string.slice(previous_index, change.beginning_index);
|
||||
processed_string += formatter[change.tag](
|
||||
input_string.slice(change.beginning_index, change.ending_index)
|
||||
);
|
||||
previous_index = change.ending_index;
|
||||
}
|
||||
});
|
||||
|
||||
processed_string += input_string.slice(previous_index);
|
||||
return processed_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The library difflib produces diffs that look as follows:
|
||||
*
|
||||
* - <p>upgrade! yes</p>
|
||||
* ? ^^ -
|
||||
* + <p>downgrade yes.</p>
|
||||
* ? ^^^^ +
|
||||
*
|
||||
* The purpose of this function is to facilitate converting these diffs into
|
||||
* colored versions, where the question-mark lines are removed, replaced with
|
||||
* directions to add appropriate color to the lines that they annotate.
|
||||
*/
|
||||
function parse_questionmark_line(questionmark_line) {
|
||||
let current_sequence = ""; // Either "^", "-", "+", or ""
|
||||
let beginning_index = 0;
|
||||
let index = 0;
|
||||
|
||||
const changes_list = [];
|
||||
const aliases = {
|
||||
"^" : "replace",
|
||||
"+" : "insert",
|
||||
"-" : "delete",
|
||||
};
|
||||
const add_change = () => {
|
||||
if (current_sequence) {
|
||||
changes_list.push({
|
||||
tag : aliases[current_sequence],
|
||||
beginning_index,
|
||||
ending_index : index,
|
||||
});
|
||||
current_sequence = "";
|
||||
}
|
||||
};
|
||||
|
||||
questionmark_line = questionmark_line.slice(2).trimRight("\n");
|
||||
|
||||
for (const character of questionmark_line) {
|
||||
if (aliases.hasOwnProperty(character)) {
|
||||
if (current_sequence !== character) {
|
||||
add_change();
|
||||
current_sequence = character;
|
||||
beginning_index = index;
|
||||
}
|
||||
} else {
|
||||
add_change();
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
|
||||
// In case we have a "change" involving the last character on a line
|
||||
// e.g. a string such as "? ^^ -- ++++"
|
||||
add_change();
|
||||
|
||||
return changes_list;
|
||||
}
|
||||
|
||||
function diff_strings(string_0, string_1) {
|
||||
let output_lines = [];
|
||||
let ndiff_output = "";
|
||||
let changes_list = [];
|
||||
|
||||
ndiff_output = difflib.ndiff(string_0.split("\n"), string_1.split("\n"));
|
||||
|
||||
ndiff_output.forEach((line) => {
|
||||
if (line.startsWith("+")) {
|
||||
output_lines.push(line);
|
||||
} else if (line.startsWith("-")) {
|
||||
output_lines.push(line);
|
||||
} else if (line.startsWith("?")) {
|
||||
changes_list = parse_questionmark_line(line);
|
||||
output_lines[output_lines.length - 1] = apply_color(
|
||||
output_lines[output_lines.length -1], changes_list);
|
||||
} else {
|
||||
output_lines.push(line);
|
||||
}
|
||||
});
|
||||
|
||||
const emphasize_codes = (string) => {
|
||||
return "\u001b[34m" + string.slice(0,1) + "\u001b[0m" + string.slice(1);
|
||||
};
|
||||
output_lines = _.map(output_lines, emphasize_codes);
|
||||
|
||||
return output_lines.join("\n");
|
||||
}
|
||||
|
||||
module.exports = { diff_strings };
|
||||
|
||||
// Simple CLI for this module
|
||||
// Only run this code if called as a command-line utility
|
||||
if (require.main === module) {
|
||||
// First two args are just "node" and "mdiff.js"
|
||||
const argv = require('minimist')(process.argv.slice(2));
|
||||
|
||||
if (_.has(argv, "help")) {
|
||||
console.log(process.argv[0] + " " + process.argv[1] +
|
||||
" [ --help ]" +
|
||||
" string_0" +
|
||||
" string_1" +
|
||||
"\n" +
|
||||
"Where string_0 and string_1 are the strings to be diffed"
|
||||
);
|
||||
}
|
||||
|
||||
const output = diff_strings(argv._[0], argv._[1]);
|
||||
console.log(output);
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
"@types/webpack": "3.0.13",
|
||||
"blueimp-md5": "2.10.0",
|
||||
"clipboard": "1.5.16",
|
||||
"difflib": "0.2.4",
|
||||
"emoji-datasource": "3.0.0",
|
||||
"emoji-datasource-apple": "3.0.0",
|
||||
"emoji-datasource-emojione": "3.0.0",
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
ZULIP_VERSION = "1.7.1+git"
|
||||
|
||||
PROVISION_VERSION = '14.1'
|
||||
PROVISION_VERSION = '14.2'
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -1207,6 +1207,12 @@ diffie-hellman@^5.0.0:
|
|||
miller-rabin "^4.0.0"
|
||||
randombytes "^2.0.0"
|
||||
|
||||
difflib@^0.2.4:
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/difflib/-/difflib-0.2.4.tgz#b5e30361a6db023176d562892db85940a718f47e"
|
||||
dependencies:
|
||||
heap ">= 0.2.0"
|
||||
|
||||
doctrine@^1.2.2:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
|
||||
|
@ -2631,6 +2637,10 @@ hawk@~3.1.3:
|
|||
hoek "2.x.x"
|
||||
sntp "1.x.x"
|
||||
|
||||
"heap@>= 0.2.0":
|
||||
version "0.2.6"
|
||||
resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac"
|
||||
|
||||
hmac-drbg@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
|
||||
|
|
Loading…
Reference in New Issue