refactor: Initial migration to typescript

This commit is contained in:
Rodrigo Fernandes 2019-10-06 21:04:33 +01:00
parent 5fe55be6f3
commit a8b9b2b49a
No known key found for this signature in database
GPG key ID: 67157D2E3D4258B4
63 changed files with 5197 additions and 11130 deletions

View file

@ -29,14 +29,14 @@ jobs:
key: dependency-cache-{{ checksum "yarn.lock" }} key: dependency-cache-{{ checksum "yarn.lock" }}
paths: paths:
- ./node_modules - ./node_modules
- run: yarn run test
- run: yarn run lint - run: yarn run lint
- run: yarn run coverage
- run: yarn run codacy - run: yarn run codacy
- persist_to_workspace: - persist_to_workspace:
root: ~/diff2html root: ~/diff2html
paths: paths:
- docs - docs
- dist - build
build-node_4: build-node_4:
<<: *common-build <<: *common-build
@ -80,11 +80,6 @@ jobs:
steps: steps:
- attach_workspace: - attach_workspace:
at: . at: .
- run:
name: Prepare website sources
command: |
rm -f docs/assets
mv dist docs/assets
- run: - run:
name: Deploy name: Deploy
working_directory: ~/diff2html/docs working_directory: ~/diff2html/docs

View file

@ -1,11 +1,6 @@
# Skip coverage and build folders # Skip build results
coverage/** coverage/**
dist/** build/**
# Ignore symlink to build folder
docs/** docs/**
node_modules/**
# Ignore HTML templates generated code src/diff2html-templates.js
src/**
!src/*.js
!src/ui/js/*.js

View file

@ -1,10 +1,12 @@
{ {
"parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {
"ecmaVersion": 6, "ecmaVersion": 2018,
"sourceType": "module",
"ecmaFeatures": { "ecmaFeatures": {
"experimentalObjectRestSpread": true,
"jsx": true "jsx": true
}, }
"sourceType": "module"
}, },
"env": { "env": {
"es6": true, "es6": true,
@ -19,325 +21,17 @@
"worker": true, "worker": true,
"qunit": true "qunit": true
}, },
"plugins": [ "plugins": ["standard", "node", "import", "promise", "@typescript-eslint", "jest"],
"standard",
"promise"
],
"globals": { "globals": {
"document": false, "document": false,
"navigator": false, "navigator": false,
"window": false "window": false
}, },
"rules": { "extends": [
"accessor-pairs": 2, "plugin:@typescript-eslint/recommended",
"arrow-spacing": [ "plugin:jest/recommended",
2, "plugin:promise/recommended",
{ "standard",
"before": true, "plugin:prettier/recommended"
"after": true
}
],
"block-spacing": [
2,
"always"
],
"brace-style": [
2,
"1tbs",
{
"allowSingleLine": true
}
],
"camelcase": [
2,
{
"properties": "never"
}
],
"comma-dangle": [
2,
"never"
],
"comma-spacing": [
2,
{
"before": false,
"after": true
}
],
"comma-style": [
2,
"last"
],
"constructor-super": 2,
"curly": [
2,
"multi-line"
],
"dot-location": [
2,
"property"
],
"eol-last": 2,
"eqeqeq": [
2,
"allow-null"
],
"generator-star-spacing": [
2,
{
"before": true,
"after": true
}
],
"handle-callback-err": [
2,
"^(err|error)$"
],
"indent": [
2,
2,
{
"SwitchCase": 1
}
],
"jsx-quotes": [
2,
"prefer-single"
],
"key-spacing": [
2,
{
"beforeColon": false,
"afterColon": true
}
],
"keyword-spacing": [
2,
{
"before": true,
"after": true
}
],
"new-cap": [
2,
{
"newIsCap": true,
"capIsNew": false
}
],
"new-parens": 2,
"no-array-constructor": 2,
"no-caller": 2,
"no-class-assign": 2,
"no-cond-assign": 2,
"no-const-assign": 2,
"no-control-regex": 2,
"no-debugger": 2,
"no-delete-var": 2,
"no-dupe-args": 2,
"no-dupe-class-members": 2,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
"no-duplicate-imports": 2,
"no-empty-character-class": 2,
"no-empty-pattern": 2,
"no-eval": 2,
"no-ex-assign": 2,
"no-extend-native": 2,
"no-extra-bind": 2,
"no-extra-boolean-cast": 2,
"no-extra-parens": [
2,
"functions"
],
"no-fallthrough": 2,
"no-floating-decimal": 2,
"no-func-assign": 2,
"no-implied-eval": 2,
"no-inner-declarations": [
2,
"functions"
],
"no-invalid-regexp": 2,
"no-irregular-whitespace": 2,
"no-iterator": 2,
"no-label-var": 2,
"no-labels": [
2,
{
"allowLoop": false,
"allowSwitch": false
}
],
"no-lone-blocks": 2,
"no-mixed-spaces-and-tabs": 2,
"no-multi-spaces": 2,
"no-multi-str": 2,
"no-multiple-empty-lines": [
2,
{
"max": 1
}
],
"no-native-reassign": 2,
"no-negated-in-lhs": 2,
"no-new": 2,
"no-new-func": 2,
"no-new-object": 2,
"no-new-require": 2,
"no-new-symbol": 2,
"no-new-wrappers": 2,
"no-obj-calls": 2,
"no-octal": 2,
"no-octal-escape": 2,
"no-path-concat": 2,
"no-proto": 2,
"no-redeclare": 2,
"no-regex-spaces": 2,
"no-return-assign": [
2,
"except-parens"
],
"no-self-assign": 2,
"no-self-compare": 2,
"no-sequences": 2,
"no-shadow-restricted-names": 2,
"no-spaced-func": 2,
"no-sparse-arrays": 2,
"no-this-before-super": 2,
"no-throw-literal": 2,
"no-trailing-spaces": 2,
"no-undef": 2,
"no-undef-init": 2,
"no-unexpected-multiline": 2,
"no-unmodified-loop-condition": 2,
"no-unneeded-ternary": [
2,
{
"defaultAssignment": false
}
],
"no-unreachable": 2,
"no-unsafe-finally": 2,
"no-unused-vars": [
2,
{
"vars": "all",
"args": "none"
}
],
"no-useless-call": 2,
"no-useless-computed-key": 2,
"no-useless-constructor": 2,
"no-useless-escape": 2,
"no-whitespace-before-property": 2,
"no-with": 2,
"one-var": [
2,
{
"initialized": "never"
}
],
"operator-linebreak": [
2,
"after",
{
"overrides": {
"?": "before",
":": "before"
}
}
],
"padded-blocks": [
2,
"never"
],
"quotes": [
2,
"single",
"avoid-escape"
],
"semi": [
2,
"always"
],
"semi-spacing": [
2,
{
"before": false,
"after": true
}
],
"space-before-blocks": [
2,
"always"
],
"space-before-function-paren": [
2,
"never"
],
"space-in-parens": [
2,
"never"
],
"space-infix-ops": 2,
"space-unary-ops": [
2,
{
"words": true,
"nonwords": false
}
],
"spaced-comment": [
2,
"always",
{
"markers": [
"global",
"globals",
"eslint",
"eslint-disable",
"*package",
"!",
","
] ]
} }
],
"template-curly-spacing": [
2,
"never"
],
"use-isnan": 2,
"valid-typeof": 2,
"wrap-iife": [
2,
"any"
],
"yield-star-spacing": [
2,
"both"
],
"yoda": [
2,
"never"
],
"standard/object-curly-even-spacing": [
2,
"either"
],
"standard/array-bracket-even-spacing": [
2,
"either"
],
"standard/computed-property-even-spacing": [
2,
"even"
],
"promise/param-names": 2,
"linebreak-style": [
2,
"unix"
]
}
}

5
.gitignore vendored
View file

@ -28,3 +28,8 @@ bower_components/
# Terraform # Terraform
/terraform/.terraform /terraform/.terraform
/docs/
/dist/
/build/
/src/diff2html-templates.js

366
dist/diff2html-ui.js vendored
View file

@ -1,366 +0,0 @@
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
(function (global){
/*
*
* Diff to HTML (diff2html-ui.js)
* Author: rtfpessoa
*
* Depends on: [ jQuery ]
* Optional dependencies on: [ highlight.js ]
*
*/
/*global $, hljs, Diff2Html*/
(function() {
var highlightJS = require('./highlight.js-internals.js').HighlightJS;
var diffJson = null;
var defaultTarget = 'body';
var currentSelectionColumnId = -1;
function Diff2HtmlUI(config) {
var cfg = config || {};
if (cfg.diff) {
diffJson = Diff2Html.getJsonFromDiff(cfg.diff);
} else if (cfg.json) {
diffJson = cfg.json;
}
this._initSelection();
}
Diff2HtmlUI.prototype.draw = function(targetId, config) {
var cfg = config || {};
cfg.inputFormat = 'json';
var $target = this._getTarget(targetId);
$target.html(Diff2Html.getPrettyHtml(diffJson, cfg));
if (cfg.synchronisedScroll) {
this.synchronisedScroll($target, cfg);
}
};
Diff2HtmlUI.prototype.synchronisedScroll = function(targetId) {
var $target = this._getTarget(targetId);
$target.find('.d2h-file-side-diff').scroll(function() {
var $this = $(this);
$this.closest('.d2h-file-wrapper').find('.d2h-file-side-diff')
.scrollLeft($this.scrollLeft());
});
};
Diff2HtmlUI.prototype.fileListCloseable = function(targetId, startVisible) {
var $target = this._getTarget(targetId);
var hashTag = this._getHashTag();
var $showBtn = $target.find('.d2h-show');
var $hideBtn = $target.find('.d2h-hide');
var $fileList = $target.find('.d2h-file-list');
if (hashTag === 'files-summary-show') show();
else if (hashTag === 'files-summary-hide') hide();
else if (startVisible) show();
else hide();
$showBtn.click(show);
$hideBtn.click(hide);
function show() {
$showBtn.hide();
$hideBtn.show();
$fileList.show();
}
function hide() {
$hideBtn.hide();
$showBtn.show();
$fileList.hide();
}
};
Diff2HtmlUI.prototype.highlightCode = function(targetId) {
var that = this;
var $target = that._getTarget(targetId);
// collect all the diff files and execute the highlight on their lines
var $files = $target.find('.d2h-file-wrapper');
$files.map(function(_i, file) {
var oldLinesState;
var newLinesState;
var $file = $(file);
var language = $file.data('lang');
// collect all the code lines and execute the highlight on them
var $codeLines = $file.find('.d2h-code-line-ctn');
$codeLines.map(function(_j, line) {
var $line = $(line);
var text = line.textContent;
var lineParent = line.parentNode;
var lineState;
if (lineParent.className.indexOf('d2h-del') !== -1) {
lineState = oldLinesState;
} else {
lineState = newLinesState;
}
var result = hljs.getLanguage(language) ? hljs.highlight(language, text, true, lineState) : hljs.highlightAuto(text);
if (lineParent.className.indexOf('d2h-del') !== -1) {
oldLinesState = result.top;
} else if (lineParent.className.indexOf('d2h-ins') !== -1) {
newLinesState = result.top;
} else {
oldLinesState = result.top;
newLinesState = result.top;
}
var originalStream = highlightJS.nodeStream(line);
if (originalStream.length) {
var resultNode = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
resultNode.innerHTML = result.value;
result.value = highlightJS.mergeStreams(originalStream, highlightJS.nodeStream(resultNode), text);
}
$line.addClass('hljs');
$line.addClass(result.language);
$line.html(result.value);
});
});
};
Diff2HtmlUI.prototype._getTarget = function(targetId) {
var $target;
if (typeof targetId === 'object' && targetId instanceof jQuery) {
$target = targetId;
} else if (typeof targetId === 'string') {
$target = $(targetId);
} else {
console.error("Wrong target provided! Falling back to default value 'body'.");
console.log('Please provide a jQuery object or a valid DOM query string.');
$target = $(defaultTarget);
}
return $target;
};
Diff2HtmlUI.prototype._getHashTag = function() {
var docUrl = document.URL;
var hashTagIndex = docUrl.indexOf('#');
var hashTag = null;
if (hashTagIndex !== -1) {
hashTag = docUrl.substr(hashTagIndex + 1);
}
return hashTag;
};
Diff2HtmlUI.prototype._distinct = function(collection) {
return collection.filter(function(v, i) {
return collection.indexOf(v) === i;
});
};
Diff2HtmlUI.prototype._initSelection = function() {
var body = $('body');
var that = this;
body.on('mousedown', '.d2h-diff-table', function(event) {
var target = $(event.target);
var table = target.closest('.d2h-diff-table');
if (target.closest('.d2h-code-line,.d2h-code-side-line').length) {
table.removeClass('selecting-left');
table.addClass('selecting-right');
currentSelectionColumnId = 1;
} else if (target.closest('.d2h-code-linenumber,.d2h-code-side-linenumber').length) {
table.removeClass('selecting-right');
table.addClass('selecting-left');
currentSelectionColumnId = 0;
}
});
body.on('copy', '.d2h-diff-table', function(event) {
var clipboardData = event.originalEvent.clipboardData;
var text = that._getSelectedText();
clipboardData.setData('text', text);
event.preventDefault();
});
};
Diff2HtmlUI.prototype._getSelectedText = function() {
var sel = window.getSelection();
var range = sel.getRangeAt(0);
var doc = range.cloneContents();
var nodes = doc.querySelectorAll('tr');
var text = '';
var idx = currentSelectionColumnId;
if (nodes.length === 0) {
text = doc.textContent;
} else {
[].forEach.call(nodes, function(tr, i) {
var td = tr.cells[tr.cells.length === 1 ? 0 : idx];
text += (i ? '\n' : '') + td.textContent.replace(/(?:\r\n|\r|\n)/g, '');
});
}
return text;
};
module.exports.Diff2HtmlUI = Diff2HtmlUI;
// Expose diff2html in the browser
global.Diff2HtmlUI = Diff2HtmlUI;
})();
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./highlight.js-internals.js":2}],2:[function(require,module,exports){
/*
*
* highlight.js
* Author: isagalaev
*
*/
(function() {
function HighlightJS() {
}
/*
* Copied from Highlight.js Private API
* Will be removed when this part of the API is exposed
*/
/* Utility vars */
var ArrayProto = [];
/* Utility functions */
function escape(value) {
return value.replace(/&/gm, '&amp;').replace(/</gm, '&lt;').replace(/>/gm, '&gt;');
}
function tag(node) {
return node.nodeName.toLowerCase();
}
/* Stream merging */
HighlightJS.prototype.nodeStream = function(node) {
var result = [];
(function _nodeStream(node, offset) {
for (var child = node.firstChild; child; child = child.nextSibling) {
if (child.nodeType === 3) {
offset += child.nodeValue.length;
} else if (child.nodeType === 1) {
result.push({
event: 'start',
offset: offset,
node: child
});
offset = _nodeStream(child, offset);
// Prevent void elements from having an end tag that would actually
// double them in the output. There are more void elements in HTML
// but we list only those realistically expected in code display.
if (!tag(child).match(/br|hr|img|input/)) {
result.push({
event: 'stop',
offset: offset,
node: child
});
}
}
}
return offset;
})(node, 0);
return result;
};
HighlightJS.prototype.mergeStreams = function(original, highlighted, value) {
var processed = 0;
var result = '';
var nodeStack = [];
function selectStream() {
if (!original.length || !highlighted.length) {
return original.length ? original : highlighted;
}
if (original[0].offset !== highlighted[0].offset) {
return (original[0].offset < highlighted[0].offset) ? original : highlighted;
}
/*
To avoid starting the stream just before it should stop the order is
ensured that original always starts first and closes last:
if (event1 == 'start' && event2 == 'start')
return original;
if (event1 == 'start' && event2 == 'stop')
return highlighted;
if (event1 == 'stop' && event2 == 'start')
return original;
if (event1 == 'stop' && event2 == 'stop')
return highlighted;
... which is collapsed to:
*/
return highlighted[0].event === 'start' ? original : highlighted;
}
function open(node) {
function attr_str(a) {
return ' ' + a.nodeName + '="' + escape(a.value) + '"';
}
result += '<' + tag(node) + ArrayProto.map.call(node.attributes, attr_str).join('') + '>';
}
function close(node) {
result += '</' + tag(node) + '>';
}
function render(event) {
(event.event === 'start' ? open : close)(event.node);
}
while (original.length || highlighted.length) {
var stream = selectStream();
result += escape(value.substring(processed, stream[0].offset));
processed = stream[0].offset;
if (stream === original) {
/*
On any opening or closing tag of the original markup we first close
the entire highlighted node stack, then render the original tag along
with all the following original tags at the same offset and then
reopen all the tags on the highlighted stack.
*/
nodeStack.reverse().forEach(close);
do {
render(stream.splice(0, 1)[0]);
stream = selectStream();
} while (stream === original && stream.length && stream[0].offset === processed);
nodeStack.reverse().forEach(open);
} else {
if (stream[0].event === 'start') {
nodeStack.push(stream[0].node);
} else {
nodeStack.pop();
}
render(stream.splice(0, 1)[0]);
}
}
return result + escape(value.substr(processed));
};
/* **** Highlight.js Private API **** */
module.exports.HighlightJS = new HighlightJS();
})();
},{}]},{},[1]);

File diff suppressed because one or more lines are too long

367
dist/diff2html.css vendored

File diff suppressed because one or more lines are too long

71
dist/diff2html.d.ts vendored
View file

@ -1,71 +0,0 @@
// Type definitions for diff2html
// Project: https://github.com/rtfpessoa/diff2html
// Definitions by: rtfpessoa <https://github.com/rtfpessoa/>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
declare namespace Diff2Html {
export interface Options {
inputFormat?: 'diff' | 'json';
outputFormat?: 'line-by-line' | 'side-by-side';
showFiles?: boolean;
diffStyle?: 'word' | 'char';
matching?: 'lines' | 'words' | 'none';
matchWordsThreshold?: number;
matchingMaxComparisons?: number;
maxLineSizeInBlockForComparison?: number;
maxLineLengthHighlight?: number;
templates?: object;
rawTemplates?: object;
renderNothingWhenEmpty?: boolean;
}
export interface Line {
content: string;
type: string;
oldNumber: number;
newNumber: number;
}
export interface Block {
oldStartLine: number;
oldStartLine2?: number;
newStartLine: number;
header: string;
lines: Line[];
}
export interface Result {
addedLines: number;
deletedLines: number;
isCombined: boolean;
isGitDiff: boolean;
oldName: string;
newName: string;
language: string;
blocks: Block[];
oldMode?: string;
newMode?: string;
deletedFileMode?: string;
newFileMode?: string;
isDeleted?: boolean;
isNew?: boolean;
isCopy?: boolean;
isRename?: boolean;
unchangedPercentage?: number;
changedPercentage?: number;
checksumBefore?: string;
checksumAfter?: string;
mode?: string;
}
export interface Diff2Html {
getJsonFromDiff(input: string, configuration?: Options): Result[];
getPrettyHtml(input: any, configuration?: Options): string;
}
}
declare module "diff2html" {
var d2h: { "Diff2Html": Diff2Html.Diff2Html };
export = d2h;
}

4782
dist/diff2html.js vendored

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
diff2html.xyz

View file

@ -1 +0,0 @@
../dist

View file

@ -1,255 +0,0 @@
<!DOCTYPE html>
<html lang="en" class="js">
<head>
<meta charset="utf-8">
<!--[if IE]>
<meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'/>
<![endif]-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Diff parser and pretty html generator">
<meta name="keywords" content="diff2html,git,diff,unified,pretty,html,css,javaccript">
<meta name="author" content="Rodrigo Fernandes (rtfpessoa)">
<title>diff2html</title>
<!-- search engine -->
<link rel="canonical" href="https://diff2html.xyz">
<!-- open graph -->
<meta property="og:title" content="diff2html">
<meta property="og:type" content="website">
<meta property="og:description"
content="Diff parser and pretty html generator.">
<meta property="og:url" content="https://diff2html.xyz">
<meta property="og:site_name" content="diff2html">
<!-- Bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<!-- Custom styles for this template -->
<link href="main.min.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/github.min.css">
<!-- diff2html -->
<link rel="stylesheet" type="text/css" href="assets/diff2html.min.css">
<!-- -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-78351861-2', 'auto');
ga('send', 'pageview');
</script>
</head>
<body class="template-index template-index-min">
<div class="swag-line">
<div class="container">
<nav class="navbar navbar-default navbar-tall navbar-full" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#global-nav">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.html">diff2html</a>
</div>
<div class="collapse navbar-collapse" id="global-nav">
<div class="navbar-right">
<ul class="nav navbar-nav">
<li>
<a href="index.html#install">Getting Started</a>
</li>
<li>
<a href="index.html#cli">CLI</a>
</li>
<li>
<a href="demo.html?diff=https://github.com/rtfpessoa/diff2html/pull/106">Demo</a>
</li>
<li>
<a href="https://github.com/rtfpessoa/diff2html#how-to-use" target="_blank">Docs</a>
</li>
<li>
<a href="https://github.com/rtfpessoa/diff2html/issues/new" target="_blank">Support</a>
</li>
</ul>
</div>
</div>
</nav>
<h1>Diff Prettifier <a href="#help">
<svg height="32" class="octicon octicon-unverified" viewBox="0 0 16 16" version="1.1" width="64" aria-hidden="true">
<path
d="M15.67 7.06l-1.08-1.34c-.17-.22-.28-.48-.31-.77l-.19-1.7a1.51 1.51 0 0 0-1.33-1.33l-1.7-.19c-.3-.03-.56-.16-.78-.33L8.94.32c-.55-.44-1.33-.44-1.88 0L5.72 1.4c-.22.17-.48.28-.77.31l-1.7.19c-.7.08-1.25.63-1.33 1.33l-.19 1.7c-.03.3-.16.56-.33.78L.32 7.05c-.44.55-.44 1.33 0 1.88l1.08 1.34c.17.22.28.48.31.77l.19 1.7c.08.7.63 1.25 1.33 1.33l1.7.19c.3.03.56.16.78.33l1.34 1.08c.55.44 1.33.44 1.88 0l1.34-1.08c.22-.17.48-.28.77-.31l1.7-.19c.7-.08 1.25-.63 1.33-1.33l.19-1.7c.03-.3.16-.56.33-.78l1.08-1.34c.44-.55.44-1.33 0-1.88zM9 11.5c0 .28-.22.5-.5.5h-1c-.27 0-.5-.22-.5-.5v-1c0-.28.23-.5.5-.5h1c.28 0 .5.22.5.5v1zm1.56-4.89c-.06.17-.17.33-.3.47-.13.16-.14.19-.33.38-.16.17-.31.3-.52.45-.11.09-.2.19-.28.27-.08.08-.14.17-.19.27-.05.1-.08.19-.11.3-.03.11-.03.13-.03.25H7.13c0-.22 0-.31.03-.48.03-.19.08-.36.14-.52.06-.14.14-.28.25-.42.11-.13.23-.25.41-.38.27-.19.36-.3.48-.52.12-.22.2-.38.2-.59 0-.27-.06-.45-.2-.58-.13-.13-.31-.19-.58-.19-.09 0-.19.02-.3.05-.11.03-.17.09-.25.16-.08.07-.14.11-.2.2a.41.41 0 0 0-.09.28h-2c0-.38.13-.56.27-.83.16-.27.36-.5.61-.67.25-.17.55-.3.88-.38.33-.08.7-.13 1.09-.13.44 0 .83.05 1.17.13.34.09.63.22.88.39.23.17.41.38.55.63.13.25.19.55.19.88 0 .22 0 .42-.08.59l-.02-.01z"></path>
</svg>
</a>
</h1>
<p>GitHub, Bitbucket and GitLab commit and pull request compatible</p>
<p>Just paste the GitHub, Bitbucket or GitLab commit, pull request or merge request url
or any other git or unified compatible diff and we will render a pretty html representation of it
with code syntax highlight and line similarity matching for better code reviews.
</p>
<h2>Options:</h2>
<div class="row">
<div class="col-md-2 col-xs-12 col-15">
<label title="Output format of the HTML, either line by line or side by side">Output Format
<select class="options-label-value" id="diff-url-options-output-format" name="outputFormat">
<option value="line-by-line" selected>Line by Line</option>
<option value="side-by-side">Side by Side</option>
</select>
</label>
</div>
<div class=" col-md-2 col-xs-12 col-15">
<label title="Show the file list summary before the diff">File Summary
<input class="options-label-value" id="diff-url-options-show-files" type="checkbox" name="showFiles" checked/>
</label>
</div>
<div class=" col-md-2 col-xs-12 col-15">
<label title="Level of matching for the comparison algorithm">Matching Type
<select class="options-label-value" id="diff-url-options-matching" name="matching">
<option value="lines">Lines</option>
<option value="words" selected>Words</option>
<option value="none">None</option>
</select>
</label>
</div>
<div class=" col-md-2 col-xs-12 col-15">
<label title="Similarity threshold for the matching algorithm">Words Threshold
<input class="options-label-value" id="diff-url-options-match-words-threshold" type="number"
name="matchWordsThreshold" value="0.25" step="0.05"
min="0" max="1"/>
</label>
</div>
<div class=" col-md-2 col-xs-12 col-15">
<label title="Maximum number of comparison performed by the matching algorithm in a block of changes">Max
Comparisons
<input class="options-label-value" id="diff-url-options-matching-max-comparisons" type="number"
name="matchingMaxComparisons" value="2500"
step="100" min="0"/>
</label>
</div>
</div>
<br>
<div class="diff-url-wrapper">
<input id="url" class="diff-url-input" type="text" name="url" placeholder="URL"/>
<a id="url-btn" class="diff-url-btn btn btn-sm" href="#">Load</a>
</div>
<br>
<div id="url-diff-container" style="margin: 0 auto;">
</div>
<br>
<h3 id="help">Help:</h3>
<ul>
<li>
<b>Why should I use this instead of GitHub, Bitbucket or GitLab?</b>
<p>Code Syntax Highlight</p>
<p>Line similarity match (similar lines are together)</p>
<p>Line by Line and Side by Side diffs</p>
<p>Supports any git and unified compatible diffs</p>
<p>Easy code selection</p>
</li>
<li>
<b>What urls are supported?</b>
<p>Any GitHub, Bitbucket or GitLab Commit, Pull Request or Merge Request urls.</p>
<p>Any Git or Unified Raw Diff or Patch urls.</p>
</li>
<li>
<b>Can I send a custom url for a friend, colleague or co-worker?</b>
<p>Just add a url parameter called diff to current url using as value your Commit, Pull Request, Merge Request, Diff
or Patch url.</p>
<p>ex: <a href="demo.html?diff=https://github.com/rtfpessoa/diff2html/pull/106">https://diff2html.xyz/demo.html?diff=https://github.com/rtfpessoa/diff2html/pull/106</a>
</p>
</li>
<li>
<b>Why can't I paste a diff?</b>
<p><a href="https://diffy.org/">diffy.org</a> is an amazing tool created by <a
href="https://github.com/pbu88">pbu88</a>
to share your diffs and uses diff2html under the hood.</p>
<p>Also, diff2html cli can directly publish diffs to <a href="https://diffy.org/">diffy.org</a></p>
</li>
</ul>
<br>
<h3>Thank you</h3>
<p>I want to thank <a href="https://github.com/kevinsimper">kevinsimper</a> for this great idea,
providing better diff support for existing online services.
</p>
</div>
<footer class="footer clearfix">
<p class="col-xs-10 col-xs-offset-1">
Website originally designed and built by
<a href="https://twitter.com/mdo" target="_blank">@mdo</a>,
<a href="https://twitter.com/fat" target="_blank">@fat</a>, and
<a href="https://twitter.com/dhg" target="_blank">@dhg</a>,
adapted with <span class="hero-red"></span> by
<a href="https://twitter.com/rtfpessoa" target="_blank">@rtfpessoa</a>.
</p>
<ul class="footer-list col-xs-10 col-xs-offset-1">
<li class="footer-list-item">
<a class="footer-list-link" href="https://github.com/rtfpessoa/diff2html#how-to-use"
target="_blank">FAQ</a>
</li>
<li class="footer-list-item">
<a class="footer-list-link" href="https://diff2html.xyz">diff2html</a>
</li>
</ul>
</footer>
</div>
<!-- General JavaScript -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"
integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS"
crossorigin="anonymous"></script>
<script type="application/ld+json">
{
"@context": "http://schema.org/",
"@type": "SoftwareSourceCode",
"name": "diff2html",
"author": "Rodrigo Fernandes",
"image": "https://diff2html.xyz/img/snapshot-3.png",
"description": "Diff parser and pretty html generator.",
"codeRepository": "https://github.com/rtfpessoa/diff2html",
"programmingLanguage": "JavaScript",
"runtimePlatform": "Node >= 0.12",
"mainEntityOfPage": "https://diff2html.xyz/"
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/languages/scala.min.js"></script>
<!-- diff2html -->
<script type="text/javascript" src="assets/diff2html.min.js"></script>
<script type="text/javascript" src="assets/diff2html-ui.min.js"></script>
<!-- -->
<script type="text/javascript" src="demo.min.js"></script>
</body>
</html>

View file

@ -1,769 +0,0 @@
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.WHATWGFetch = {})));
}(this, (function (exports) { 'use strict';
var support = {
searchParams: 'URLSearchParams' in self,
iterable: 'Symbol' in self && 'iterator' in Symbol,
blob:
'FileReader' in self &&
'Blob' in self &&
(function() {
try {
new Blob();
return true
} catch (e) {
return false
}
})(),
formData: 'FormData' in self,
arrayBuffer: 'ArrayBuffer' in self
};
function isDataView(obj) {
return obj && DataView.prototype.isPrototypeOf(obj)
}
if (support.arrayBuffer) {
var viewClasses = [
'[object Int8Array]',
'[object Uint8Array]',
'[object Uint8ClampedArray]',
'[object Int16Array]',
'[object Uint16Array]',
'[object Int32Array]',
'[object Uint32Array]',
'[object Float32Array]',
'[object Float64Array]'
];
var isArrayBufferView =
ArrayBuffer.isView ||
function(obj) {
return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
};
}
function normalizeName(name) {
if (typeof name !== 'string') {
name = String(name);
}
if (/[^a-z0-9\-#$%&'*+.^_`|~]/i.test(name)) {
throw new TypeError('Invalid character in header field name')
}
return name.toLowerCase()
}
function normalizeValue(value) {
if (typeof value !== 'string') {
value = String(value);
}
return value
}
// Build a destructive iterator for the value list
function iteratorFor(items) {
var iterator = {
next: function() {
var value = items.shift();
return {done: value === undefined, value: value}
}
};
if (support.iterable) {
iterator[Symbol.iterator] = function() {
return iterator
};
}
return iterator
}
function Headers(headers) {
this.map = {};
if (headers instanceof Headers) {
headers.forEach(function(value, name) {
this.append(name, value);
}, this);
} else if (Array.isArray(headers)) {
headers.forEach(function(header) {
this.append(header[0], header[1]);
}, this);
} else if (headers) {
Object.getOwnPropertyNames(headers).forEach(function(name) {
this.append(name, headers[name]);
}, this);
}
}
Headers.prototype.append = function(name, value) {
name = normalizeName(name);
value = normalizeValue(value);
var oldValue = this.map[name];
this.map[name] = oldValue ? oldValue + ', ' + value : value;
};
Headers.prototype['delete'] = function(name) {
delete this.map[normalizeName(name)];
};
Headers.prototype.get = function(name) {
name = normalizeName(name);
return this.has(name) ? this.map[name] : null
};
Headers.prototype.has = function(name) {
return this.map.hasOwnProperty(normalizeName(name))
};
Headers.prototype.set = function(name, value) {
this.map[normalizeName(name)] = normalizeValue(value);
};
Headers.prototype.forEach = function(callback, thisArg) {
for (var name in this.map) {
if (this.map.hasOwnProperty(name)) {
callback.call(thisArg, this.map[name], name, this);
}
}
};
Headers.prototype.keys = function() {
var items = [];
this.forEach(function(value, name) {
items.push(name);
});
return iteratorFor(items)
};
Headers.prototype.values = function() {
var items = [];
this.forEach(function(value) {
items.push(value);
});
return iteratorFor(items)
};
Headers.prototype.entries = function() {
var items = [];
this.forEach(function(value, name) {
items.push([name, value]);
});
return iteratorFor(items)
};
if (support.iterable) {
Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
}
function consumed(body) {
if (body.bodyUsed) {
return Promise.reject(new TypeError('Already read'))
}
body.bodyUsed = true;
}
function fileReaderReady(reader) {
return new Promise(function(resolve, reject) {
reader.onload = function() {
resolve(reader.result);
};
reader.onerror = function() {
reject(reader.error);
};
})
}
function readBlobAsArrayBuffer(blob) {
var reader = new FileReader();
var promise = fileReaderReady(reader);
reader.readAsArrayBuffer(blob);
return promise
}
function readBlobAsText(blob) {
var reader = new FileReader();
var promise = fileReaderReady(reader);
reader.readAsText(blob);
return promise
}
function readArrayBufferAsText(buf) {
var view = new Uint8Array(buf);
var chars = new Array(view.length);
for (var i = 0; i < view.length; i++) {
chars[i] = String.fromCharCode(view[i]);
}
return chars.join('')
}
function bufferClone(buf) {
if (buf.slice) {
return buf.slice(0)
} else {
var view = new Uint8Array(buf.byteLength);
view.set(new Uint8Array(buf));
return view.buffer
}
}
function Body() {
this.bodyUsed = false;
this._initBody = function(body) {
this._bodyInit = body;
if (!body) {
this._bodyText = '';
} else if (typeof body === 'string') {
this._bodyText = body;
} else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
this._bodyBlob = body;
} else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
this._bodyFormData = body;
} else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
this._bodyText = body.toString();
} else if (support.arrayBuffer && support.blob && isDataView(body)) {
this._bodyArrayBuffer = bufferClone(body.buffer);
// IE 10-11 can't handle a DataView body.
this._bodyInit = new Blob([this._bodyArrayBuffer]);
} else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
this._bodyArrayBuffer = bufferClone(body);
} else {
this._bodyText = body = Object.prototype.toString.call(body);
}
if (!this.headers.get('content-type')) {
if (typeof body === 'string') {
this.headers.set('content-type', 'text/plain;charset=UTF-8');
} else if (this._bodyBlob && this._bodyBlob.type) {
this.headers.set('content-type', this._bodyBlob.type);
} else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
}
}
};
if (support.blob) {
this.blob = function() {
var rejected = consumed(this);
if (rejected) {
return rejected
}
if (this._bodyBlob) {
return Promise.resolve(this._bodyBlob)
} else if (this._bodyArrayBuffer) {
return Promise.resolve(new Blob([this._bodyArrayBuffer]))
} else if (this._bodyFormData) {
throw new Error('could not read FormData body as blob')
} else {
return Promise.resolve(new Blob([this._bodyText]))
}
};
this.arrayBuffer = function() {
if (this._bodyArrayBuffer) {
return consumed(this) || Promise.resolve(this._bodyArrayBuffer)
} else {
return this.blob().then(readBlobAsArrayBuffer)
}
};
}
this.text = function() {
var rejected = consumed(this);
if (rejected) {
return rejected
}
if (this._bodyBlob) {
return readBlobAsText(this._bodyBlob)
} else if (this._bodyArrayBuffer) {
return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))
} else if (this._bodyFormData) {
throw new Error('could not read FormData body as text')
} else {
return Promise.resolve(this._bodyText)
}
};
if (support.formData) {
this.formData = function() {
return this.text().then(decode)
};
}
this.json = function() {
return this.text().then(JSON.parse)
};
return this
}
// HTTP methods whose capitalization should be normalized
var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];
function normalizeMethod(method) {
var upcased = method.toUpperCase();
return methods.indexOf(upcased) > -1 ? upcased : method
}
function Request(input, options) {
options = options || {};
var body = options.body;
if (input instanceof Request) {
if (input.bodyUsed) {
throw new TypeError('Already read')
}
this.url = input.url;
this.credentials = input.credentials;
if (!options.headers) {
this.headers = new Headers(input.headers);
}
this.method = input.method;
this.mode = input.mode;
this.signal = input.signal;
if (!body && input._bodyInit != null) {
body = input._bodyInit;
input.bodyUsed = true;
}
} else {
this.url = String(input);
}
this.credentials = options.credentials || this.credentials || 'same-origin';
if (options.headers || !this.headers) {
this.headers = new Headers(options.headers);
}
this.method = normalizeMethod(options.method || this.method || 'GET');
this.mode = options.mode || this.mode || null;
this.signal = options.signal || this.signal;
this.referrer = null;
if ((this.method === 'GET' || this.method === 'HEAD') && body) {
throw new TypeError('Body not allowed for GET or HEAD requests')
}
this._initBody(body);
}
Request.prototype.clone = function() {
return new Request(this, {body: this._bodyInit})
};
function decode(body) {
var form = new FormData();
body
.trim()
.split('&')
.forEach(function(bytes) {
if (bytes) {
var split = bytes.split('=');
var name = split.shift().replace(/\+/g, ' ');
var value = split.join('=').replace(/\+/g, ' ');
form.append(decodeURIComponent(name), decodeURIComponent(value));
}
});
return form
}
function parseHeaders(rawHeaders) {
var headers = new Headers();
// Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
// https://tools.ietf.org/html/rfc7230#section-3.2
var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ');
preProcessedHeaders.split(/\r?\n/).forEach(function(line) {
var parts = line.split(':');
var key = parts.shift().trim();
if (key) {
var value = parts.join(':').trim();
headers.append(key, value);
}
});
return headers
}
Body.call(Request.prototype);
function Response(bodyInit, options) {
if (!options) {
options = {};
}
this.type = 'default';
this.status = options.status === undefined ? 200 : options.status;
this.ok = this.status >= 200 && this.status < 300;
this.statusText = 'statusText' in options ? options.statusText : 'OK';
this.headers = new Headers(options.headers);
this.url = options.url || '';
this._initBody(bodyInit);
}
Body.call(Response.prototype);
Response.prototype.clone = function() {
return new Response(this._bodyInit, {
status: this.status,
statusText: this.statusText,
headers: new Headers(this.headers),
url: this.url
})
};
Response.error = function() {
var response = new Response(null, {status: 0, statusText: ''});
response.type = 'error';
return response
};
var redirectStatuses = [301, 302, 303, 307, 308];
Response.redirect = function(url, status) {
if (redirectStatuses.indexOf(status) === -1) {
throw new RangeError('Invalid status code')
}
return new Response(null, {status: status, headers: {location: url}})
};
exports.DOMException = self.DOMException;
try {
new exports.DOMException();
} catch (err) {
exports.DOMException = function(message, name) {
this.message = message;
this.name = name;
var error = Error(message);
this.stack = error.stack;
};
exports.DOMException.prototype = Object.create(Error.prototype);
exports.DOMException.prototype.constructor = exports.DOMException;
}
function fetch(input, init) {
return new Promise(function(resolve, reject) {
var request = new Request(input, init);
if (request.signal && request.signal.aborted) {
return reject(new exports.DOMException('Aborted', 'AbortError'))
}
var xhr = new XMLHttpRequest();
function abortXhr() {
xhr.abort();
}
xhr.onload = function() {
var options = {
status: xhr.status,
statusText: xhr.statusText,
headers: parseHeaders(xhr.getAllResponseHeaders() || '')
};
options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
var body = 'response' in xhr ? xhr.response : xhr.responseText;
resolve(new Response(body, options));
};
xhr.onerror = function() {
reject(new TypeError('Network request failed'));
};
xhr.ontimeout = function() {
reject(new TypeError('Network request failed'));
};
xhr.onabort = function() {
reject(new exports.DOMException('Aborted', 'AbortError'));
};
xhr.open(request.method, request.url, true);
if (request.credentials === 'include') {
xhr.withCredentials = true;
} else if (request.credentials === 'omit') {
xhr.withCredentials = false;
}
if ('responseType' in xhr && support.blob) {
xhr.responseType = 'blob';
}
request.headers.forEach(function(value, name) {
xhr.setRequestHeader(name, value);
});
if (request.signal) {
request.signal.addEventListener('abort', abortXhr);
xhr.onreadystatechange = function() {
// DONE (success or failure)
if (xhr.readyState === 4) {
request.signal.removeEventListener('abort', abortXhr);
}
};
}
xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
})
}
fetch.polyfill = true;
if (!self.fetch) {
self.fetch = fetch;
self.Headers = Headers;
self.Request = Request;
self.Response = Response;
}
exports.Headers = Headers;
exports.Request = Request;
exports.Response = Response;
exports.fetch = fetch;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{}],2:[function(require,module,exports){
/* global Diff2HtmlUI */
/*
* Example URLs:
*
* https://github.com/rtfpessoa/diff2html/commit/7d02e67f3b3386ac5d804f974d025cd7a1165839
* https://github.com/rtfpessoa/diff2html/pull/106
*
* https://gitlab.com/gitlab-org/gitlab-ce/commit/4e963fed42ad518caa7353d361a38a1250c99c41
* https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/6763
*
* https://bitbucket.org/atlassian/amps/commits/52c38116f12475f75af4a147b7a7685478b83eca
* https://bitbucket.org/atlassian/amps/pull-requests/236
*/
$(document).ready(function() {
// Improves browser compatibility
require('whatwg-fetch');
var searchParam = 'diff';
var $container = $('.container');
var $url = $('#url');
var $outputFormat = $('#diff-url-options-output-format');
var $showFiles = $('#diff-url-options-show-files');
var $matching = $('#diff-url-options-matching');
var $wordsThreshold = $('#diff-url-options-match-words-threshold');
var $matchingMaxComparisons = $('#diff-url-options-matching-max-comparisons');
if (window.location.search) {
var url = getUrlFromSearch(window.location.search);
$url.val(url);
smartDraw(url);
}
bind();
$outputFormat
.add($showFiles)
.add($matching)
.add($wordsThreshold)
.add($matchingMaxComparisons)
.change(function(e) {
console.log('');
console.log(e);
console.log('');
smartDraw(null, true);
});
function getUrlFromSearch(search) {
try {
return search
.split('?')[1]
.split(searchParam + '=')[1]
.split('&')[0];
} catch (_ignore) {
}
return null;
}
function getParamsFromSearch(search) {
var map = {};
try {
search
.split('?')[1]
.split('&')
.map(function(e) {
var values = e.split('=');
map[values[0]] = values[1];
});
} catch (_ignore) {
}
return map;
}
function bind() {
$('#url-btn').click(function(e) {
e.preventDefault();
var url = $url.val();
smartDraw(url);
});
$url.on('paste', function(e) {
var url = e.originalEvent.clipboardData.getData('Text');
smartDraw(url);
});
}
function prepareUrl(url) {
var fetchUrl;
var headers = new Headers();
var githubCommitUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
var githubPrUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/pull\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
var gitlabCommitUrl = /^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
var gitlabPrUrl = /^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/merge_requests\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
var bitbucketCommitUrl = /^https?:\/\/(?:www\.)?bitbucket\.org\/(.*?)\/(.*?)\/commits\/(.*?)(?:\/raw)?(?:\/.*)?$/;
var bitbucketPrUrl = /^https?:\/\/(?:www\.)?bitbucket\.org\/(.*?)\/(.*?)\/pull-requests\/(.*?)(?:\/.*)?$/;
function gitLabUrlGen(userName, projectName, type, value) {
return 'https://crossorigin.me/https://gitlab.com/' + userName + '/' + projectName + '/' + type + '/' + value + '.diff';
}
function gitHubUrlGen(userName, projectName, type, value) {
headers.append('Accept', 'application/vnd.github.v3.diff');
return 'https://api.github.com/repos/' + userName + '/' + projectName + '/' + type + '/' + value;
}
function bitbucketUrlGen(userName, projectName, type, value) {
var baseUrl = 'https://bitbucket.org/api/2.0/repositories/';
if (type === 'pullrequests') {
return baseUrl + userName + '/' + projectName + '/pullrequests/' + value + '/diff';
}
return baseUrl + userName + '/' + projectName + '/diff/' + value;
}
var values;
if ((values = githubCommitUrl.exec(url))) {
fetchUrl = gitHubUrlGen(values[1], values[2], 'commits', values[3]);
} else if ((values = githubPrUrl.exec(url))) {
fetchUrl = gitHubUrlGen(values[1], values[2], 'pulls', values[3]);
} else if ((values = gitlabCommitUrl.exec(url))) {
fetchUrl = gitLabUrlGen(values[1], values[2], 'commit', values[3]);
} else if ((values = gitlabPrUrl.exec(url))) {
fetchUrl = gitLabUrlGen(values[1], values[2], 'merge_requests', values[3]);
} else if ((values = bitbucketCommitUrl.exec(url))) {
fetchUrl = bitbucketUrlGen(values[1], values[2], 'commit', values[3]);
} else if ((values = bitbucketPrUrl.exec(url))) {
fetchUrl = bitbucketUrlGen(values[1], values[2], 'pullrequests', values[3]);
} else {
console.info('Could not parse url, using the provided url.');
fetchUrl = 'https://crossorigin.me/' + url;
}
return {
originalUrl: url,
url: fetchUrl,
headers: headers
};
}
function smartDraw(urlOpt, forced) {
var url = urlOpt || $url.val();
var req = prepareUrl(url);
draw(req, forced);
}
function draw(req, forced) {
if (!validateUrl(req.url)) {
console.error('Invalid url provided!');
return;
}
if (validateUrl(req.originalUrl)) updateUrl(req.originalUrl);
var outputFormat = $outputFormat.val();
var showFiles = $showFiles.is(':checked');
var matching = $matching.val();
var wordsThreshold = $wordsThreshold.val();
var matchingMaxComparisons = $matchingMaxComparisons.val();
fetch(req.url, {
method: 'GET',
headers: req.headers,
mode: 'cors',
cache: 'default'
})
.then(function(res) {
return res.text();
})
.then(function(data) {
var container = '#url-diff-container';
var diff2htmlUi = new Diff2HtmlUI({diff: data});
if (outputFormat === 'side-by-side') {
$container.css({'width': '100%'});
} else {
$container.css({'width': ''});
}
var params = getParamsFromSearch(window.location.search);
delete params[searchParam];
if (forced) {
params['outputFormat'] = outputFormat;
params['showFiles'] = showFiles;
params['matching'] = matching;
params['wordsThreshold'] = wordsThreshold;
params['matchingMaxComparisons'] = matchingMaxComparisons;
} else {
params['outputFormat'] = params['outputFormat'] || outputFormat;
params['showFiles'] = String(params['showFiles']) !== 'false' || (params['showFiles'] === null && showFiles);
params['matching'] = params['matching'] || matching;
params['wordsThreshold'] = params['wordsThreshold'] || wordsThreshold;
params['matchingMaxComparisons'] = params['matchingMaxComparisons'] || matchingMaxComparisons;
$outputFormat.val(params['outputFormat']);
$showFiles.prop('checked', params['showFiles']);
$matching.val(params['matching']);
$wordsThreshold.val(params['wordsThreshold']);
$matchingMaxComparisons.val(params['matchingMaxComparisons']);
}
params['synchronisedScroll'] = params['synchronisedScroll'] || true;
diff2htmlUi.draw(container, params);
diff2htmlUi.fileListCloseable(container, params['fileListCloseable'] || false);
if (params['highlight'] === undefined || params['highlight']) {
diff2htmlUi.highlightCode(container);
}
});
}
function validateUrl(url) {
return /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(url);
}
function updateUrl(url) {
var params = getParamsFromSearch(window.location.search);
if (params[searchParam] === url) return;
params[searchParam] = url;
var paramString = Object.keys(params).map(function(k) { return k + '=' + params[k]; }).join('&');
window.location = 'demo.html?' + paramString;
}
});
},{"whatwg-fetch":1}]},{},[2]);

1
docs/demo.min.js vendored

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

View file

@ -1,433 +0,0 @@
<!DOCTYPE html>
<html lang="en" class="js">
<head>
<meta charset="utf-8">
<!--[if IE]>
<meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'/>
<![endif]-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Diff parser and pretty html generator">
<meta name="keywords" content="diff2html,git,diff,unified,pretty,html,css,javaccript">
<meta name="author" content="Rodrigo Fernandes (rtfpessoa)">
<title>diff2html</title>
<!-- search engine -->
<link rel="canonical" href="https://diff2html.xyz">
<!-- open graph -->
<meta property="og:title" content="diff2html">
<meta property="og:type" content="website">
<meta property="og:description"
content="Diff parser and pretty html generator.">
<meta property="og:url" content="https://diff2html.xyz">
<meta property="og:site_name" content="diff2html">
<!-- Bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<!-- Custom styles for this template -->
<link href="main.min.css" rel="stylesheet">
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-78351861-2', 'auto');
ga('send', 'pageview');
</script>
</head>
<body class="template-index ">
<div class="swag-line">
<div class="container">
<nav class="navbar navbar-default navbar-tall navbar-full" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#global-nav">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.html">diff2html</a>
</div>
<div class="collapse navbar-collapse" id="global-nav">
<div class="navbar-right">
<ul class="nav navbar-nav">
<li>
<a href="index.html#install">Getting Started</a>
</li>
<li>
<a href="index.html#cli">CLI</a>
</li>
<li>
<a href="demo.html?diff=https://github.com/rtfpessoa/diff2html/pull/106">Demo</a>
</li>
<li>
<a href="https://github.com/rtfpessoa/diff2html#how-to-use" target="_blank">Docs</a>
</li>
<li>
<a href="https://github.com/rtfpessoa/diff2html/issues/new" target="_blank">Support</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="hero hero-homepage">
<span class="hero-booticon">
<span class="hero-green">diff</span><span class="hero-black">2</span><span
class="hero-red">html</span>
</span>
<h1 class="hero-header">Diff parser and pretty html generator</h1>
<h4 class="text-muted">Better diffs, unmatched reviews.</h4>
<h2><a class="btn btn-lg" href="demo.html?diff=https://github.com/rtfpessoa/diff2html/pull/106">Demo</a></h2>
<div class="screenshots screenshots-fan clearfix">
<img class="screenshot hidden-xs" src="img/snapshot-2.png">
<a class="screenshot" href="demo.html?diff=https://github.com/rtfpessoa/diff2html/pull/106">
<img src="img/snapshot-3.png">
</a>
<a class="screenshot hidden-xs" href="demo.html?diff=https://github.com/rtfpessoa/diff2html/pull/106">
<img src="img/snapshot-1.png">
</a>
</div>
</div>
<div>
<div class="row row-padded-small row-bordered">
<div class="col-sm-8 col-sm-offset-2 text-center">
<h2 class="m-b-md">Each diff provides a comprehensive visualization of the code changes,
helping developers identify problems and better understand the changes.</h2>
</div>
</div>
<div class="row row-padded-small homepage-grid row-bordered p-t text-center">
<div class="col-sm-4">
<span class="svg-icon-large">
<svg aria-hidden="true" class="octicon octicon-diff" height="16" version="1.1"
viewBox="0 0 14 16" width="14"><path
d="M6 7h2v1H6v2h-1V8H3v-1h2V5h1v2zM3 13h5v-1H3v1z m4.5-11l3.5 3.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V3c0-0.55 0.45-1 1-1h6.5z m2.5 4L7 3H1v12h9V6zM8.5 0S3 0 3 0v1h5l4 4v8h1V4.5L8.5 0z"></path></svg>
</span>
<h5><strong>Line by Line and Side by Side changes</strong></h5>
<p class="text-muted">Each diff features a line by line and side by side preview of your
changes.</p>
</div>
<div class="col-sm-4">
<span class="svg-icon-large">
<svg aria-hidden="true" class="octicon octicon-tasklist" height="16" version="1.1"
viewBox="0 0 16 16" width="16"><path
d="M15.41 9H7.59c-0.59 0-0.59-0.41-0.59-1s0-1 0.59-1h7.81c0.59 0 0.59 0.41 0.59 1s0 1-0.59 1zM9.59 4c-0.59 0-0.59-0.41-0.59-1s0-1 0.59-1h5.81c0.59 0 0.59 0.41 0.59 1s0 1-0.59 1H9.59zM0 3.91l1.41-1.3 1.59 1.59L7.09 0l1.41 1.41-5.5 5.5L0 3.91z m7.59 8.09h7.81c0.59 0 0.59 0.41 0.59 1s0 1-0.59 1H7.59c-0.59 0-0.59-0.41-0.59-1s0-1 0.59-1z"></path></svg>
</span>
<h5><strong>Code syntax highlight</strong></h5>
<p class="text-muted">All the code changes are syntax highlighted using <a
href="https://highlightjs.org/">highlight.js</a>,
providing more readability.</p>
</div>
<div class="col-sm-4">
<span class="svg-icon-large">
<svg aria-hidden="true" class="octicon octicon-clippy" height="16" version="1.1"
viewBox="0 0 14 16"
width="14">
<path d="M2 12h4v1H2v-1z m5-6H2v1h5v-1z m2 3V7L6 10l3 3V11h5V9H9z m-4.5-1H2v1h2.5v-1zM2 11h2.5v-1H2v1z m9 1h1v2c-0.02 0.28-0.11 0.52-0.3 0.7s-0.42 0.28-0.7 0.3H1c-0.55 0-1-0.45-1-1V3c0-0.55 0.45-1 1-1h3C4 0.89 4.89 0 6 0s2 0.89 2 2h3c0.55 0 1 0.45 1 1v5h-1V5H1v9h10V12zM2 4h8c0-0.55-0.45-1-1-1h-1c-0.55 0-1-0.45-1-1s-0.45-1-1-1-1 0.45-1 1-0.45 1-1 1h-1c-0.55 0-1 0.45-1 1z"></path>
</svg>
</span>
<h5><strong>Line similarity matching</strong></h5>
<p class="text-muted">Similar lines are paired, allowing for easier change tracking.</p>
</div>
</div>
<div id="install" class="row-padded-small row-centered row-bordered">
<div class="col-md-12">
<div class="row">
<div class="col-md-12">
<h3><strong>Install with Bower</strong></h3>
<p>You can install and manage diff2html's CSS and JS using Bower:</p>
<div class="homepage-code-example">
<p><span class="unselectable">&gt; $ </span><span class="text-muted">bower install diff2html</span></p>
<span class="btn-clipboard" data-clipboard-text="bower install diff2html" title="Copy">Copy</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h3><strong>Install with npm</strong></h3>
<p>You can also install diff2html using npm:</p>
<div class="homepage-code-example">
<p><span class="unselectable">&gt; $ </span><span class="text-muted">npm install diff2html</span></p>
<span class="btn-clipboard" data-clipboard-text="npm install diff2html" title="Copy">Copy</span>
</div>
</div>
</div>
<div class="row row-padded-small">
<div class="col-md-12">
<a href="https://github.com/rtfpessoa/diff2html#how-to-use" target="_blank">
Find usage examples in the Docs
</a>
</div>
</div>
</div>
</div>
<div id="cli" class="row row-padded-small row-centered row-bordered">
<div class="col-xs-10 col-xs-offset-1 col-md-6 col-md-offset-0">
<h3><strong>With command line integration</strong></h3>
<h4 class="m-b-md">We work hard to make sure you can have your diffs in a simple and flexible
way. Go <a href="https://github.com/rtfpessoa/diff2html-cli" target="_blank">here full
documentation</a>.</h4>
</div>
<div class="col-xs-10 col-xs-offset-1 col-md-6 col-md-offset-0">
<div class="homepage-terminal-example">
<p class="m-b-md">
<span class="unselectable">&gt; $ </span><span class="text-muted">npm install -g diff2html-cli</span><br>
<span class="unselectable">diff2html cli installed!</span>
</p>
<p class="m-b-md">
<span class="unselectable">&gt; $ </span><span class="text-muted">diff2html</span><br>
<span class="unselectable">Previous commit changes on your browser</span>
</p>
<p>
<span class="unselectable">&gt; $ <span class="text-muted">is that it?</span><br>
Yup, it's that simple.</span>
</p>
</div>
</div>
</div>
<div id="users" class="row row-padded-small row-centered row-bordered">
<div class="col-md-12">
<div class="row">
<div class="col-md-12">
<h3><strong>Projects using diff2html</strong></h3>
</div>
</div>
<div class="row row-eq-height">
<div class="col-xs-12 col-sm-6 col-md-3 m-b-lg">
<div class="panel panel-default panel-profile m-b-0">
<div class="panel-body text-center">
<h5 class="panel-title">diff2html-cli</h5>
<p class="m-b">diff2html from your terminal to the browser.</p>
<a href="https://github.com/rtfpessoa/diff2html-cli" target="_blank"
class="btn btn-primary-outline btn-sm m-b">
<span class="icon icon-add-user"></span> View GitHub
</a>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3 m-b-lg">
<div class="panel panel-default panel-profile m-b-0">
<div class="panel-body text-center">
<h5 class="panel-title">Codacy</h5>
<p class="m-b">Check code style, security, duplication, complexity and coverage on every change.</p>
<a href="https://www.codacy.com" target="_blank"
class="btn btn-primary-outline btn-sm m-b">
<span class="icon icon-add-user"></span> Website
</a>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3 m-b-lg">
<div class="panel panel-default panel-profile m-b-0">
<div class="panel-body text-center">
<h5 class="panel-title">Ungit</h5>
<p class="m-b">The easiest way to use git. On any platform. Anywhere.</p>
<a href="https://github.com/FredrikNoren/ungit" target="_blank"
class="btn btn-primary-outline btn-sm m-b">
<span class="icon icon-add-user"></span> View GitHub
</a>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3 m-b-lg">
<div class="panel panel-default panel-profile m-b-0">
<div class="panel-body text-center">
<h5 class="panel-title">Diffy</h5>
<p class="m-b">Share your diffs and explain your ideas without committing.</p>
<a href="https://diffy.org/" target="_blank"
class="btn btn-primary-outline btn-sm m-b">
<span class="icon icon-add-user"></span> Website
</a>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3 m-b-lg">
<div class="panel panel-default panel-profile m-b-0">
<div class="panel-body text-center">
<h5 class="panel-title">diff-pane</h5>
<p class="m-b">Atom - Diff two panes.</p>
<a href="https://github.com/t-ari/diff-pane" target="_blank"
class="btn btn-primary-outline btn-sm m-b">
<span class="icon icon-add-user"></span> View GitHub
</a>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3 m-b-lg">
<div class="panel panel-default panel-profile m-b-0">
<div class="panel-body text-center">
<h5 class="panel-title">node-giff</h5>
<p class="m-b">Display git diff on browser.</p>
<a href="https://github.com/do7be/node-giff" target="_blank"
class="btn btn-primary-outline btn-sm m-b">
<span class="icon icon-add-user"></span> View GitHub
</a>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3 m-b-lg">
<div class="panel panel-default panel-profile m-b-0">
<div class="panel-body text-center">
<h5 class="panel-title">edgar-monitor</h5>
<p class="m-b">A module that processes new Edgar filings and sends out
notifications.</p>
<a href="https://github.com/buzzfeed-openlab/edgar-monitor" target="_blank"
class="btn btn-primary-outline btn-sm m-b">
<span class="icon icon-add-user"></span> View GitHub
</a>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3 m-b-lg">
<div class="panel panel-default panel-profile m-b-0">
<div class="panel-body text-center">
<h5 class="panel-title">node-git</h5>
<p class="m-b">Execute Git Command by Node.js.</p>
<a href="https://github.com/liangshuai/node-git" target="_blank"
class="btn btn-primary-outline btn-sm m-b">
<span class="icon icon-add-user"></span> View GitHub
</a>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3 m-b-lg">
<div class="panel panel-default panel-profile m-b-0">
<div class="panel-body text-center">
<h5 class="panel-title">Jenkins</h5>
<p class="m-b">Show diffs between builds</p>
<a href="https://wiki.jenkins-ci.org/display/JENKINS/Last+Changes+Plugin" target="_blank"
class="btn btn-primary-outline btn-sm m-b">
<span class="icon icon-add-user"></span> Website
</a>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3 m-b-lg">
<div class="panel panel-default panel-profile m-b-0">
<div class="panel-body text-center">
<h5 class="panel-title">Light Review</h5>
<p class="m-b">Code Reviews with maximum control for the leading developers</p>
<a href="http://light-review.com/" target="_blank"
class="btn btn-primary-outline btn-sm m-b">
<span class="icon icon-add-user"></span> Website
</a>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3 m-b-lg">
<div class="panel panel-default panel-profile m-b-0">
<div class="panel-body text-center">
<h5 class="panel-title">Simple Git</h5>
<p class="m-b">A simple package to be able to drive GIT</p>
<a href="https://github.com/mauricioszabo/simple-git" target="_blank"
class="btn btn-primary-outline btn-sm m-b">
<span class="icon icon-add-user"></span> View GitHub
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row row-padded-small text-center">
<div class="col-sm-8 col-sm-offset-2 text-center">
<h3><strong>Open Source</strong></h3>
<h4 class="m-b-md">diff2html is open source.
If you'd like to be part of the diff2html community or help us improve,
find us on <a href="https://github.com/rtfpessoa/diff2html" target="_blank">GitHub</a> and
<a href="https://gitter.im/rtfpessoa/diff2html" target="_blank">Gitter</a>. Need any help?
</h4>
<a class="btn btn-md" href="https://github.com/rtfpessoa/diff2html#how-to-use" target="_blank">
Read more in the Docs
</a>
</div>
</div>
</div>
</div>
<footer class="footer clearfix">
<p class="col-xs-10 col-xs-offset-1">
Website originally designed and built by
<a href="https://twitter.com/mdo" target="_blank">@mdo</a>,
<a href="https://twitter.com/fat" target="_blank">@fat</a>, and
<a href="https://twitter.com/dhg" target="_blank">@dhg</a>,
adapted with <span class="hero-red"></span> by
<a href="https://twitter.com/rtfpessoa" target="_blank">@rtfpessoa</a>.
</p>
<ul class="footer-list col-xs-10 col-xs-offset-1">
<li class="footer-list-item">
<a class="footer-list-link" href="https://github.com/rtfpessoa/diff2html#how-to-use"
target="_blank">FAQ</a>
</li>
<li class="footer-list-item">
<a class="footer-list-link" href="https://diff2html.xyz">diff2html</a>
</li>
</ul>
</footer>
</div>
<!-- General JavaScript -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"
integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS"
crossorigin="anonymous"></script>
<script type="application/ld+json">
{
"@context": "http://schema.org/",
"@type": "SoftwareSourceCode",
"name": "diff2html",
"author": "Rodrigo Fernandes",
"image": "https://diff2html.xyz/img/snapshot-3.png",
"description": "Diff parser and pretty html generator.",
"codeRepository": "https://github.com/rtfpessoa/diff2html",
"programmingLanguage": "JavaScript",
"runtimePlatform": "Node >= 0.12",
"mainEntityOfPage": "https://diff2html.xyz/"
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.5.10/clipboard.min.js"></script>
<script>
new Clipboard(document.getElementsByClassName("btn-clipboard"));
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

4
docs/main.min.css vendored

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
User-agent: *

View file

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<url>
<loc>https://diff2html.xyz/</loc>
</url>
<url>
<loc>https://diff2html.xyz/index.html</loc>
</url>
<url>
<loc>https://diff2html.xyz/demo.html</loc>
</url>
</urlset>

15
jest.config.js Normal file
View file

@ -0,0 +1,15 @@
module.exports = {
verbose: true,
preset: "ts-jest",
testEnvironment: "node",
coverageDirectory: "./coverage",
coverageReporters: ["lcov", "text", "html"],
coverageThreshold: {
global: {
statements: 90,
branches: 85,
functions: 90,
lines: 90
}
}
};

View file

@ -34,22 +34,25 @@
"engines": { "engines": {
"node": ">=4" "node": ">=4"
}, },
"preferGlobal": true,
"scripts": { "scripts": {
"release": "./scripts/release.sh", "build": "tsc",
"release-website": "./scripts/release-website.sh", "lint": "eslint '*/**/*.{js,jsx,ts,tsx}'",
"templates": "./scripts/hulk.js --wrapper node --variable 'browserTemplates' ./src/templates/*.mustache > ./src/templates/diff2html-templates.js",
"style": "yarn run lint", "style": "yarn run lint",
"lint": "eslint .", "test": "jest",
"coverage": "istanbul cover _mocha -- -u exports -R spec ./test/**/*", "coverage": "jest --collectCoverage",
"check-coverage": "istanbul check-coverage --statements 90 --functions 90 --branches 85 --lines 90 ./coverage/coverage.json", "coverage-html": "yarn run coverage && open ./coverage/index.html",
"test": "yarn run coverage && yarn run check-coverage",
"codacy": "cat ./coverage/lcov.info | codacy-coverage", "codacy": "cat ./coverage/lcov.info | codacy-coverage",
"preversion": "yarn run release && yarn run release-website && yarn run lint && yarn test", "release": "yarn run release-css && yarn run release-templates && yarn run release-ts && yarn run release-browser-bundle && yarn run release-website",
"version": "git add -A src dist docs package.json", "release-css": "./scripts/release-css.sh",
"release-templates": "./scripts/release-templates.sh",
"release-ts": "yarn run build",
"release-browser-bundle": "./scripts/release-browser-bundle.sh",
"release-website": "./scripts/release-website.sh",
"preversion": "yarn run release && yarn run lint && yarn test",
"version": "git add -A package.json",
"postversion": "git push && git push --tags" "postversion": "git push && git push --tags"
}, },
"main": "./src/diff2html.js", "main": "./build/commonjs-node/diff2html.js",
"browser": { "browser": {
"fs": false "fs": false
}, },
@ -60,28 +63,38 @@
"whatwg-fetch": "^3.0.0" "whatwg-fetch": "^3.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "24.0.18",
"@types/node": "^12.7.2",
"@typescript-eslint/eslint-plugin": "2.0.0",
"@typescript-eslint/parser": "2.0.0",
"autoprefixer": "^9.6.0", "autoprefixer": "^9.6.0",
"browserify": "^16.2.3", "browserify": "^16.5.0",
"clean-css-cli": "^4.3.0", "clean-css-cli": "^4.3.0",
"codacy-coverage": "^3.4.0", "codacy-coverage": "^3.4.0",
"eslint": "^5.16.0", "eslint": "6.2.2",
"eslint-plugin-promise": "^4.1.1", "eslint-config-prettier": "6.1.0",
"eslint-plugin-standard": "^4.0.0", "eslint-config-standard": "14.0.1",
"eslint-plugin-import": "2.18.2",
"eslint-plugin-jest": "22.15.2",
"eslint-plugin-node": "9.1.0",
"eslint-plugin-prettier": "3.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"fast-html-parser": "^1.0.1", "fast-html-parser": "^1.0.1",
"istanbul": "^0.4.5", "jest": "24.9.0",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"mocha": "5.2.0",
"nopt": "^4.0.1", "nopt": "^4.0.1",
"postcss-cli": "^6.1.2", "postcss-cli": "^6.1.3",
"uglify-js": "^3.6.0" "prettier": "1.18.2",
"ts-jest": "24.0.2",
"typescript": "^3.6.3",
"terser": "^4.3.8"
}, },
"resolutions": { "resolutions": {
"lodash": "4.17.14" "lodash": "4.17.15"
}, },
"license": "MIT", "license": "MIT",
"files": [ "files": [
"src", "build"
"dist",
"typescript"
] ]
} }

View file

@ -16,61 +16,66 @@
*/ */
// dependencies // dependencies
var hogan = require('hogan.js'); const path = require("path");
var path = require('path'); const fs = require("fs");
var nopt = require('nopt'); const hogan = require("hogan.js");
var mkderp = require('mkdirp'); const nopt = require("nopt");
var fs = require('fs'); const mkderp = require("mkdirp");
// locals // locals
var specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\']; const specials = ["/", ".", "*", "+", "?", "|", "(", ")", "[", "]", "{", "}", "\\"];
var specialsRegExp = new RegExp('(\\' + specials.join('|\\') + ')', 'g'); const specialsRegExp = new RegExp("(\\" + specials.join("|\\") + ")", "g");
var options = { let options = {
'namespace': String, namespace: String,
'outputdir': path, outputdir: path,
'variable': String, variable: String,
'wrapper': String, wrapper: String,
'version': true, version: true,
'help': true help: true
}; };
var shortHand = { const shortHand = {
'n': ['--namespace'], n: ["--namespace"],
'o': ['--outputdir'], o: ["--outputdir"],
'vn': ['--variable'], vn: ["--variable"],
'w': ['--wrapper'], w: ["--wrapper"],
'h': ['--help'], h: ["--help"],
'v': ['--version'] v: ["--version"]
}; };
var templates; let templates;
// options // options
options = nopt(options, shortHand); options = nopt(options, shortHand);
// escape special regexp characters // escape special regexp characters
function esc(text) { function esc(text) {
return text.replace(specialsRegExp, '\\$1'); return text.replace(specialsRegExp, "\\$1");
} }
// cyan function for rob // cyan function for rob
function cyan(text) { function cyan(text) {
return '\x1B[36m' + text + '\x1B[39m'; return "\x1B[36m" + text + "\x1B[39m";
} }
// check for dirs and correct ext (<3 for windows) // check for dirs and correct ext (<3 for windows)
function extractFiles(args) { function extractFiles(args) {
var usage = '\n' + const usage =
cyan('USAGE:') + ' hulk [--wrapper wrapper] [--outputdir outputdir] ' + "\n" +
'[--namespace namespace] [--variable variable] FILES\n\n' + cyan("USAGE:") +
cyan('OPTIONS:') + ' [-w, --wrapper] :: wraps the template (i.e. amd)\n' + " hulk [--wrapper wrapper] [--outputdir outputdir] " +
' [-o, --outputdir] :: outputs the templates as individual files to a directory\n\n' + "[--namespace namespace] [--variable variable] FILES\n\n" +
' [-n, --namespace] :: prepend string to template names\n\n' + cyan("OPTIONS:") +
' [-vn, --variable] :: variable name for non-amd wrapper\n\n' + " [-w, --wrapper] :: wraps the template (i.e. amd)\n" +
cyan('EXAMPLE:') + ' hulk --wrapper amd ./templates/*.mustache\n\n' + " [-o, --outputdir] :: outputs the templates as individual files to a directory\n\n" +
cyan('NOTE:') + ' hulk supports the "*" wildcard and allows you to target specific extensions too\n'; " [-n, --namespace] :: prepend string to template names\n\n" +
var files = []; " [-vn, --variable] :: variable name for non-amd wrapper\n\n" +
cyan("EXAMPLE:") +
" hulk --wrapper amd ./templates/*.mustache\n\n" +
cyan("NOTE:") +
' hulk supports the "*" wildcard and allows you to target specific extensions too\n';
let files = [];
if (options.version) { if (options.version) {
console.log(require('../package.json').version); console.log(require("../package.json").version);
process.exit(0); process.exit(0);
} }
@ -81,12 +86,13 @@ function extractFiles(args) {
args.forEach(function(arg) { args.forEach(function(arg) {
if (/\*/.test(arg)) { if (/\*/.test(arg)) {
arg = arg.split('*'); arg = arg.split("*");
files = files.concat( files = files.concat(
fs.readdirSync(arg[0] || '.') fs
.readdirSync(arg[0] || ".")
.map(function(f) { .map(function(f) {
var file = path.join(arg[0], f); const file = path.join(arg[0], f);
return new RegExp(esc(arg[1]) + '$').test(f) && fs.statSync(file).isFile() && file; return new RegExp(esc(arg[1]) + "$").test(f) && fs.statSync(file).isFile() && file;
}) })
.filter(function(f) { .filter(function(f) {
return f; return f;
@ -112,51 +118,65 @@ function removeByteOrderMark(text) {
// wrap templates // wrap templates
function wrap(file, name, openedFile) { function wrap(file, name, openedFile) {
switch (options.wrapper) { switch (options.wrapper) {
case 'amd': case "amd":
return 'define(' + (!options.outputdir ? '"' + path.join(path.dirname(file), name) + '", ' : '') + return (
"define(" +
(!options.outputdir ? '"' + path.join(path.dirname(file), name) + '", ' : "") +
'[ "hogan.js" ], function(Hogan){ return new Hogan.Template(' + '[ "hogan.js" ], function(Hogan){ return new Hogan.Template(' +
hogan.compile(openedFile, { asString: 1 }) + hogan.compile(openedFile, { asString: 1 }) +
');});'; ");});"
case 'node': );
var globalObj = 'global.' + (options.variable || 'templates') + '["' + name + '"]'; case "node":
var globalStmt = globalObj + ' = new Hogan.Template(' + hogan.compile(openedFile, {asString: 1}) + ');'; var globalObj = "global." + (options.variable || "templates") + '["' + name + '"]';
var globalStmt = globalObj + " = new Hogan.Template(" + hogan.compile(openedFile, { asString: 1 }) + ");";
var nodeOutput = globalStmt; var nodeOutput = globalStmt;
// if we have a template per file the export will expose the template directly // if we have a template per file the export will expose the template directly
if (options.outputdir) { if (options.outputdir) {
nodeOutput = nodeOutput + '\n' + 'module.exports = ' + globalObj + ';'; nodeOutput = nodeOutput + "\n" + "module.exports = " + globalObj + ";";
} }
return nodeOutput; return nodeOutput;
default: default:
return (options.variable || 'templates') + return (
'["' + name + '"] = new Hogan.Template(' + (options.variable || "templates") +
'["' +
name +
'"] = new Hogan.Template(' +
hogan.compile(openedFile, { asString: 1 }) + hogan.compile(openedFile, { asString: 1 }) +
');'; ");"
);
} }
} }
function prepareOutput(content) { function prepareOutput(content) {
var variableName = options.variable || 'templates'; const variableName = options.variable || "templates";
switch (options.wrapper) { switch (options.wrapper) {
case 'amd': case "amd":
return content; return content;
case 'node': case "node":
var nodeExport = ''; var nodeExport = "";
// if we have aggregated templates the export will expose the template map // if we have aggregated templates the export will expose the template map
if (!options.outputdir) { if (!options.outputdir) {
nodeExport = 'module.exports = global.' + variableName + ';\n'; nodeExport = "module.exports = global." + variableName + ";\n";
} }
return '(function() {\n' + return (
'if (!!!global.' + variableName + ') global.' + variableName + ' = {};\n' + "(function() {\n" +
"if (!!!global." +
variableName +
") global." +
variableName +
" = {};\n" +
'var Hogan = require("hogan.js");' + 'var Hogan = require("hogan.js");' +
content + '\n' + content +
"\n" +
nodeExport + nodeExport +
'})();'; "})();"
);
default: default:
return 'if (!!!' + variableName + ') var ' + variableName + ' = {};\n' + content; return "if (!!!" + variableName + ") var " + variableName + " = {};\n" + content;
} }
} }
@ -167,21 +187,20 @@ if (options.outputdir) {
// Prepend namespace to template name // Prepend namespace to template name
function namespace(name) { function namespace(name) {
return (options.namespace || '') + name; return (options.namespace || "") + name;
} }
// write a template foreach file that matches template extension // write a template foreach file that matches template extension
templates = extractFiles(options.argv.remain) templates = extractFiles(options.argv.remain)
.map(function(file) { .map(function(file) {
var openedFile = fs.readFileSync(file, 'utf-8').trim(); let openedFile = fs.readFileSync(file, "utf-8").trim();
var name; let name;
if (!openedFile) return; if (!openedFile) return;
name = namespace(path.basename(file).replace(/\..*$/, '')); name = namespace(path.basename(file).replace(/\..*$/, ""));
openedFile = removeByteOrderMark(openedFile); openedFile = removeByteOrderMark(openedFile);
openedFile = wrap(file, name, openedFile); openedFile = wrap(file, name, openedFile);
if (!options.outputdir) return openedFile; if (!options.outputdir) return openedFile;
fs.writeFileSync(path.join(options.outputdir, name + '.js') fs.writeFileSync(path.join(options.outputdir, name + ".js"), prepareOutput(openedFile));
, prepareOutput(openedFile));
}) })
.filter(function(t) { .filter(function(t) {
return t; return t;
@ -190,4 +209,4 @@ templates = extractFiles(options.argv.remain)
// output templates // output templates
if (!templates.length || options.outputdir) process.exit(0); if (!templates.length || options.outputdir) process.exit(0);
console.log(prepareOutput(templates.join('\n'))); console.log(prepareOutput(templates.join("\n")));

View file

@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIRECTORY="$( cd "$( dirname "$0" )" && pwd )"
INPUT_DIR=${SCRIPT_DIRECTORY}/../build/commonjs-node
INPUT_UI_DIR=${INPUT_DIR}/ui
INPUT_JS_FILE=${INPUT_DIR}/diff2html.js
INPUT_JS_UI_FILE=${INPUT_UI_DIR}/js/diff2html-ui.js
OUTPUT_DIR=${SCRIPT_DIRECTORY}/../build/browser
OUTPUT_JS_FILE=${OUTPUT_DIR}/diff2html.js
OUTPUT_MIN_JS_FILE=${OUTPUT_DIR}/diff2html.min.js
OUTPUT_JS_UI_FILE=${OUTPUT_DIR}/diff2html-ui.js
OUTPUT_MIN_JS_UI_FILE=${OUTPUT_DIR}/diff2html-ui.min.js
echo "Creating diff2html browser bundle ..."
echo "Cleaning previous versions ..."
rm -rf ${OUTPUT_DIR}
mkdir -p ${OUTPUT_DIR}
echo "Generating js aggregation file in ${OUTPUT_JS_FILE}"
browserify -e ${INPUT_JS_FILE} -o ${OUTPUT_JS_FILE}
echo "Minifying ${OUTPUT_JS_FILE} to ${OUTPUT_MIN_JS_FILE}"
terser ${OUTPUT_JS_FILE} -c -o ${OUTPUT_MIN_JS_FILE}
echo "Generating js ui aggregation file in ${OUTPUT_JS_UI_FILE}"
browserify -e ${INPUT_JS_UI_FILE} -o ${OUTPUT_JS_UI_FILE}
echo "Minifying ${OUTPUT_JS_UI_FILE} to ${OUTPUT_MIN_JS_UI_FILE}"
terser ${OUTPUT_JS_UI_FILE} -c -o ${OUTPUT_MIN_JS_UI_FILE}
echo "diff2html browser bundle created successfully!"

25
scripts/release-css.sh Executable file
View file

@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIRECTORY="$( cd "$( dirname "$0" )" && pwd )"
INPUT_DIR=${SCRIPT_DIRECTORY}/../src
INPUT_UI_DIR=${INPUT_DIR}/ui
INPUT_CSS_FILE=${INPUT_UI_DIR}/css/diff2html.css
OUTPUT_DIR=${SCRIPT_DIRECTORY}/../build/css
OUTPUT_CSS_FILE=${OUTPUT_DIR}/diff2html.css
OUTPUT_MIN_CSS_FILE=${OUTPUT_DIR}/diff2html.min.css
echo "Creating diff2html css ..."
echo "Cleaning previous versions ..."
rm -rf ${OUTPUT_DIR}
mkdir -p ${OUTPUT_DIR}
echo "Minifying ${OUTPUT_CSS_FILE} to ${OUTPUT_MIN_CSS_FILE}"
postcss --use autoprefixer -o ${OUTPUT_CSS_FILE} ${INPUT_CSS_FILE}
cleancss --advanced --compatibility=ie8 -o ${OUTPUT_MIN_CSS_FILE} ${OUTPUT_CSS_FILE}
echo "diff2html css created successfully!"

10
scripts/release-templates.sh Executable file
View file

@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIRECTORY="$( cd "$( dirname "$0" )" && pwd )"
node ${SCRIPT_DIRECTORY}/hulk.js \
--wrapper node \
--variable 'browserTemplates' \
${SCRIPT_DIRECTORY}/../src/templates/*.mustache > ${SCRIPT_DIRECTORY}/../src/diff2html-templates.js

View file

@ -1,34 +1,38 @@
var fs = require('fs'); #!/usr/bin/env node
var hogan = require('hogan.js'); const fs = require("fs");
var root = 'website/templates'; const hogan = require("hogan.js");
var pagesRoot = root + '/pages';
var websitePages = fs.readdirSync(root + '/pages'); const root = "website/templates";
const pagesRoot = root + "/pages";
var template = hogan.compile(readFile(root + '/template.mustache')); const websitePages = fs.readdirSync(root + "/pages");
var options = { const template = hogan.compile(readFile(root + "/template.mustache"));
'all': {
'demoUrl': 'demo.html?diff=https://github.com/rtfpessoa/diff2html/pull/106' const options = {
all: {
demoUrl: "demo.html?diff=https://github.com/rtfpessoa/diff2html/pull/106"
}, },
'demo': { demo: {
'extraClass': 'template-index-min' extraClass: "template-index-min"
} }
}; };
websitePages.map(function(page) { websitePages.map(function(page) {
var pagePartialTemplate = hogan.compile(readFile(pagesRoot + '/' + page + '/' + page + '.partial.mustache')); const pagePartialTemplate = hogan.compile(readFile(pagesRoot + "/" + page + "/" + page + ".partial.mustache"));
var pageAssetsTemplate = hogan.compile(readFile(pagesRoot + '/' + page + '/' + page + '-assets.partial.mustache')); const pageAssetsTemplate = hogan.compile(readFile(pagesRoot + "/" + page + "/" + page + "-assets.partial.mustache"));
var pageScriptsTemplate = hogan.compile(readFile(pagesRoot + '/' + page + '/' + page + '-scripts.partial.mustache')); const pageScriptsTemplate = hogan.compile(
readFile(pagesRoot + "/" + page + "/" + page + "-scripts.partial.mustache")
);
var templateOptions = {}; const templateOptions = {};
var key; let key;
// Allow the pages to share common options // Allow the pages to share common options
var genericOptions = options['all'] || {}; const genericOptions = options.all || {};
for (key in genericOptions) { for (key in genericOptions) {
if (genericOptions.hasOwnProperty(key)) { if (genericOptions.hasOwnProperty(key)) {
templateOptions[key] = genericOptions[key]; templateOptions[key] = genericOptions[key];
@ -36,32 +40,31 @@ websitePages.map(function(page) {
} }
// Allow each page to have custom options // Allow each page to have custom options
var pageOptions = options[page] || {}; const pageOptions = options[page] || {};
for (key in pageOptions) { for (key in pageOptions) {
if (pageOptions.hasOwnProperty(key)) { if (pageOptions.hasOwnProperty(key)) {
templateOptions[key] = pageOptions[key]; templateOptions[key] = pageOptions[key];
} }
} }
var pagePartial = pagePartialTemplate.render(templateOptions); const pagePartial = pagePartialTemplate.render(templateOptions);
var pageAssets = pageAssetsTemplate.render(templateOptions); const pageAssets = pageAssetsTemplate.render(templateOptions);
var pageScripts = pageScriptsTemplate.render(templateOptions); const pageScripts = pageScriptsTemplate.render(templateOptions);
templateOptions.assets = pageAssets; templateOptions.assets = pageAssets;
templateOptions.scripts = pageScripts; templateOptions.scripts = pageScripts;
templateOptions.content = pagePartial; templateOptions.content = pagePartial;
var pageHtml = template.render(templateOptions); const pageHtml = template.render(templateOptions);
writeFile('docs/' + page + '.html', pageHtml); writeFile("docs/" + page + ".html", pageHtml);
}); });
function readFile(filePath) { function readFile(filePath) {
try { try {
return fs.readFileSync(filePath, 'utf8'); return fs.readFileSync(filePath, "utf8");
} catch (_ignore) { } catch (_ignore) {}
}
return ''; return "";
} }
function writeFile(filePath, content) { function writeFile(filePath, content) {

View file

@ -1,17 +1,14 @@
#!/bin/bash #!/bin/bash
#
# diff2html website release script
# by rtfpessoa
#
set -e set -e
INPUT_DIR=website SCRIPT_DIRECTORY="$( cd "$( dirname "$0" )" && pwd )"
INPUT_DIR=${SCRIPT_DIRECTORY}/../website
INPUT_DEMO_JS=${INPUT_DIR}/templates/pages/demo/demo.js INPUT_DEMO_JS=${INPUT_DIR}/templates/pages/demo/demo.js
INPUT_CSS_FILE=${INPUT_DIR}/main.css INPUT_CSS_FILE=${INPUT_DIR}/main.css
OUTPUT_DIR=docs OUTPUT_DIR=${SCRIPT_DIRECTORY}/../docs
OUTPUT_DEMO_JS=${OUTPUT_DIR}/demo.js OUTPUT_DEMO_JS=${OUTPUT_DIR}/demo.js
OUTPUT_DEMO_MIN_JS=${OUTPUT_DIR}/demo.min.js OUTPUT_DEMO_MIN_JS=${OUTPUT_DIR}/demo.min.js
OUTPUT_CSS_FILE=${OUTPUT_DIR}/main.css OUTPUT_CSS_FILE=${OUTPUT_DIR}/main.css
@ -21,7 +18,7 @@ echo "Creating diff2html website release ..."
echo "Cleaning previous versions ..." echo "Cleaning previous versions ..."
rm -rf ${OUTPUT_DIR} rm -rf ${OUTPUT_DIR}
mkdir -p ${OUTPUT_DIR} mkdir -p ${OUTPUT_DIR}/assets
echo "Minifying ${OUTPUT_CSS_FILE} to ${OUTPUT_MIN_CSS_FILE}" echo "Minifying ${OUTPUT_CSS_FILE} to ${OUTPUT_MIN_CSS_FILE}"
postcss --use autoprefixer -o ${OUTPUT_CSS_FILE} ${INPUT_CSS_FILE} postcss --use autoprefixer -o ${OUTPUT_CSS_FILE} ${INPUT_CSS_FILE}
@ -31,10 +28,10 @@ echo "Generating website js aggregation file in ${OUTPUT_DEMO_JS}"
browserify -e ${INPUT_DEMO_JS} -o ${OUTPUT_DEMO_JS} browserify -e ${INPUT_DEMO_JS} -o ${OUTPUT_DEMO_JS}
echo "Minifying ${OUTPUT_DEMO_JS} to ${OUTPUT_DEMO_MIN_JS}" echo "Minifying ${OUTPUT_DEMO_JS} to ${OUTPUT_DEMO_MIN_JS}"
uglifyjs ${OUTPUT_DEMO_JS} -c -o ${OUTPUT_DEMO_MIN_JS} terser ${OUTPUT_DEMO_JS} -c -o ${OUTPUT_DEMO_MIN_JS}
echo "Generating HTMLs from templates ..." echo "Generating HTMLs from templates ..."
node ./scripts/release-website.js node ${SCRIPT_DIRECTORY}/release-website.js
echo "Copying static files ..." echo "Copying static files ..."
cp -rf ${INPUT_DIR}/img ${OUTPUT_DIR}/ cp -rf ${INPUT_DIR}/img ${OUTPUT_DIR}/
@ -43,7 +40,9 @@ cp -f ${INPUT_DIR}/favicon.ico ${OUTPUT_DIR}/
cp -f ${INPUT_DIR}/robots.txt ${OUTPUT_DIR}/ cp -f ${INPUT_DIR}/robots.txt ${OUTPUT_DIR}/
cp -f ${INPUT_DIR}/sitemap.xml ${OUTPUT_DIR}/ cp -f ${INPUT_DIR}/sitemap.xml ${OUTPUT_DIR}/
echo "Creating diff2html assets symlink ..." echo "Copying diff2html resources ..."
ln -s ../dist docs/assets cp ${SCRIPT_DIRECTORY}/../build/browser/diff2html.min.js ${SCRIPT_DIRECTORY}/../docs/assets/
cp ${SCRIPT_DIRECTORY}/../build/browser/diff2html-ui.min.js ${SCRIPT_DIRECTORY}/../docs/assets/
cp ${SCRIPT_DIRECTORY}/../build/css/diff2html.min.css ${SCRIPT_DIRECTORY}/../docs/assets/
echo "diff2html website release created successfully!" echo "diff2html website release created successfully!"

View file

@ -1,57 +0,0 @@
#!/bin/bash
#
# diff2html release script
# by rtfpessoa
#
set -e
INPUT_DIR=src
INTPUT_TEMPLATES_DIR=${INPUT_DIR}/templates
INPUT_UI_DIR=${INPUT_DIR}/ui
INPUT_JS_FILE=${INPUT_DIR}/diff2html.js
INPUT_JS_UI_FILE=${INPUT_UI_DIR}/js/diff2html-ui.js
INPUT_CSS_FILE=${INPUT_UI_DIR}/css/diff2html.css
INPUT_TYPINGS_D_TS_FILE=${INPUT_DIR}/diff2html.d.ts
GENERATED_TEMPLATES_FILE=${INTPUT_TEMPLATES_DIR}/diff2html-templates.js
OUTPUT_DIR=dist
OUTPUT_JS_FILE=${OUTPUT_DIR}/diff2html.js
OUTPUT_MIN_JS_FILE=${OUTPUT_DIR}/diff2html.min.js
OUTPUT_JS_UI_FILE=${OUTPUT_DIR}/diff2html-ui.js
OUTPUT_MIN_JS_UI_FILE=${OUTPUT_DIR}/diff2html-ui.min.js
OUTPUT_CSS_FILE=${OUTPUT_DIR}/diff2html.css
OUTPUT_MIN_CSS_FILE=${OUTPUT_DIR}/diff2html.min.css
OUTPUT_TYPINGS_D_TS_FILE=${OUTPUT_DIR}/diff2html.d.ts
echo "Creating diff2html release ..."
echo "Cleaning previous versions ..."
rm -rf ${OUTPUT_DIR}
mkdir -p ${OUTPUT_DIR}
echo "Minifying ${OUTPUT_CSS_FILE} to ${OUTPUT_MIN_CSS_FILE}"
postcss --use autoprefixer -o ${OUTPUT_CSS_FILE} ${INPUT_CSS_FILE}
cleancss --advanced --compatibility=ie8 -o ${OUTPUT_MIN_CSS_FILE} ${OUTPUT_CSS_FILE}
echo "Pre-compile hogan.js templates"
yarn run templates
echo "Generating js aggregation file in ${OUTPUT_JS_FILE}"
browserify -e ${INPUT_JS_FILE} -o ${OUTPUT_JS_FILE}
echo "Minifying ${OUTPUT_JS_FILE} to ${OUTPUT_MIN_JS_FILE}"
uglifyjs ${OUTPUT_JS_FILE} -c -o ${OUTPUT_MIN_JS_FILE}
echo "Generating js ui aggregation file in ${OUTPUT_JS_UI_FILE}"
browserify -e ${INPUT_JS_UI_FILE} -o ${OUTPUT_JS_UI_FILE}
echo "Minifying ${OUTPUT_JS_UI_FILE} to ${OUTPUT_MIN_JS_UI_FILE}"
uglifyjs ${OUTPUT_JS_UI_FILE} -c -o ${OUTPUT_MIN_JS_UI_FILE}
echo "Copying types ${INPUT_TYPINGS_D_TS_FILE} to ${OUTPUT_TYPINGS_D_TS_FILE}"
cp -f ${INPUT_TYPINGS_D_TS_FILE} ${OUTPUT_TYPINGS_D_TS_FILE}
echo "diff2html release created successfully!"

View file

@ -0,0 +1,728 @@
const DiffParser = require("../diff-parser.js").DiffParser;
function checkDiffSample(diff) {
const result = DiffParser.generateDiffJson(diff);
const file1 = result[0];
expect(1).toEqual(result.length);
expect(1).toEqual(file1.addedLines);
expect(1).toEqual(file1.deletedLines);
expect("sample").toEqual(file1.oldName);
expect("sample").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
}
describe("DiffParser", function() {
describe("generateDiffJson", function() {
it("should parse unix with \n diff", function() {
const diff =
"diff --git a/sample b/sample\n" +
"index 0000001..0ddf2ba\n" +
"--- a/sample\n" +
"+++ b/sample\n" +
"@@ -1 +1 @@\n" +
"-test\n" +
"+test1r\n";
checkDiffSample(diff);
});
it("should parse windows with \r\n diff", function() {
const diff =
"diff --git a/sample b/sample\r\n" +
"index 0000001..0ddf2ba\r\n" +
"--- a/sample\r\n" +
"+++ b/sample\r\n" +
"@@ -1 +1 @@\r\n" +
"-test\r\n" +
"+test1r\r\n";
checkDiffSample(diff);
});
it("should parse old os x with \r diff", function() {
const diff =
"diff --git a/sample b/sample\r" +
"index 0000001..0ddf2ba\r" +
"--- a/sample\r" +
"+++ b/sample\r" +
"@@ -1 +1 @@\r" +
"-test\r" +
"+test1r\r";
checkDiffSample(diff);
});
it("should parse mixed eols diff", function() {
const diff =
"diff --git a/sample b/sample\n" +
"index 0000001..0ddf2ba\r\n" +
"--- a/sample\r" +
"+++ b/sample\r\n" +
"@@ -1 +1 @@\n" +
"-test\r" +
"+test1r\n";
checkDiffSample(diff);
});
it("should parse diff with special characters", function() {
const diff =
'diff --git "a/bla with \ttab.scala" "b/bla with \ttab.scala"\n' +
"index 4c679d7..e9bd385 100644\n" +
'--- "a/bla with \ttab.scala"\n' +
'+++ "b/bla with \ttab.scala"\n' +
"@@ -1 +1,2 @@\n" +
"-cenas\n" +
"+cenas com ananas\n" +
"+bananas";
const result = DiffParser.generateDiffJson(diff);
const file1 = result[0];
expect(1).toEqual(result.length);
expect(2).toEqual(file1.addedLines);
expect(1).toEqual(file1.deletedLines);
expect("bla with \ttab.scala").toEqual(file1.oldName);
expect("bla with \ttab.scala").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
});
it("should parse diff with prefix", function() {
const diff =
'diff --git "\tbla with \ttab.scala" "\tbla with \ttab.scala"\n' +
"index 4c679d7..e9bd385 100644\n" +
'--- "\tbla with \ttab.scala"\n' +
'+++ "\tbla with \ttab.scala"\n' +
"@@ -1 +1,2 @@\n" +
"-cenas\n" +
"+cenas com ananas\n" +
"+bananas";
const result = DiffParser.generateDiffJson(diff, { srcPrefix: "\t", dstPrefix: "\t" });
const file1 = result[0];
expect(1).toEqual(result.length);
expect(2).toEqual(file1.addedLines);
expect(1).toEqual(file1.deletedLines);
expect("bla with \ttab.scala").toEqual(file1.oldName);
expect("bla with \ttab.scala").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
});
it("should parse diff with deleted file", function() {
const diff =
"diff --git a/src/var/strundefined.js b/src/var/strundefined.js\n" +
"deleted file mode 100644\n" +
"index 04e16b0..0000000\n" +
"--- a/src/var/strundefined.js\n" +
"+++ /dev/null\n" +
"@@ -1,3 +0,0 @@\n" +
"-define(function() {\n" +
"- return typeof undefined;\n" +
"-});\n";
const result = DiffParser.generateDiffJson(diff);
expect(1).toEqual(result.length);
const file1 = result[0];
expect(false).toEqual(file1.isCombined);
expect(0).toEqual(file1.addedLines);
expect(3).toEqual(file1.deletedLines);
expect("src/var/strundefined.js").toEqual(file1.oldName);
expect("/dev/null").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
expect(true).toEqual(file1.isDeleted);
expect("04e16b0").toEqual(file1.checksumBefore);
expect("0000000").toEqual(file1.checksumAfter);
});
it("should parse diff with new file", function() {
const diff =
"diff --git a/test.js b/test.js\n" +
"new file mode 100644\n" +
"index 0000000..e1e22ec\n" +
"--- /dev/null\n" +
"+++ b/test.js\n" +
"@@ -0,0 +1,5 @@\n" +
"+var parser = require('./source/git-parser');\n" +
"+\n" +
"+var patchLineList = [ false, false, false, false ];\n" +
"+\n" +
"+console.log(parser.parsePatchDiffResult(text, patchLineList));\n";
const result = DiffParser.generateDiffJson(diff);
expect(1).toEqual(result.length);
const file1 = result[0];
expect(false).toEqual(file1.isCombined);
expect(5).toEqual(file1.addedLines);
expect(0).toEqual(file1.deletedLines);
expect("/dev/null").toEqual(file1.oldName);
expect("test.js").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
expect(true).toEqual(file1.isNew);
expect("100644").toEqual(file1.newFileMode);
expect("0000000").toEqual(file1.checksumBefore);
expect("e1e22ec").toEqual(file1.checksumAfter);
});
it("should parse diff with nested diff", function() {
const diff =
"diff --git a/src/offset.js b/src/offset.js\n" +
"index cc6ffb4..fa51f18 100644\n" +
"--- a/src/offset.js\n" +
"+++ b/src/offset.js\n" +
"@@ -1,6 +1,5 @@\n" +
"+var parser = require('./source/git-parser');\n" +
"+\n" +
"+var text = 'diff --git a/components/app/app.html b/components/app/app.html\\nindex ecb7a95..027bd9b 100644\\n--- a/components/app/app.html\\n+++ b/components/app/app.html\\n@@ -52,0 +53,3 @@\\n+\\n+\\n+\\n@@ -56,0 +60,3 @@\\n+\\n+\\n+\\n'\n" +
"+var patchLineList = [ false, false, false, false ];\n" +
"+\n" +
"+console.log(parser.parsePatchDiffResult(text, patchLineList));\n";
const result = DiffParser.generateDiffJson(diff);
expect(1).toEqual(result.length);
const file1 = result[0];
expect(false).toEqual(file1.isCombined);
expect(6).toEqual(file1.addedLines);
expect(0).toEqual(file1.deletedLines);
expect("src/offset.js").toEqual(file1.oldName);
expect("src/offset.js").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
expect(6).toEqual(file1.blocks[0].lines.length);
expect("cc6ffb4").toEqual(file1.checksumBefore);
expect("fa51f18").toEqual(file1.checksumAfter);
});
it("should parse diff with multiple blocks", function() {
const diff =
"diff --git a/src/attributes/classes.js b/src/attributes/classes.js\n" +
"index c617824..c8d1393 100644\n" +
"--- a/src/attributes/classes.js\n" +
"+++ b/src/attributes/classes.js\n" +
"@@ -1,10 +1,9 @@\n" +
" define([\n" +
' "../core",\n' +
' "../var/rnotwhite",\n' +
'- "../var/strundefined",\n' +
' "../data/var/dataPriv",\n' +
' "../core/init"\n' +
"-], function( jQuery, rnotwhite, strundefined, dataPriv ) {\n" +
"+], function( jQuery, rnotwhite, dataPriv ) {\n" +
" \n" +
" var rclass = /[\\t\\r\\n\\f]/g;\n" +
" \n" +
"@@ -128,7 +127,7 @@ jQuery.fn.extend({\n" +
" }\n" +
" \n" +
" // Toggle whole class name\n" +
'- } else if ( type === strundefined || type === "boolean" ) {\n' +
'+ } else if ( value === undefined || type === "boolean" ) {\n' +
" if ( this.className ) {\n" +
" // store className if set\n" +
' dataPriv.set( this, "__className__", this.className );\n';
const result = DiffParser.generateDiffJson(diff);
expect(1).toEqual(result.length);
const file1 = result[0];
expect(false).toEqual(file1.isCombined);
expect(2).toEqual(file1.addedLines);
expect(3).toEqual(file1.deletedLines);
expect("src/attributes/classes.js").toEqual(file1.oldName);
expect("src/attributes/classes.js").toEqual(file1.newName);
expect(2).toEqual(file1.blocks.length);
expect(11).toEqual(file1.blocks[0].lines.length);
expect(8).toEqual(file1.blocks[1].lines.length);
expect("c617824").toEqual(file1.checksumBefore);
expect("c8d1393").toEqual(file1.checksumAfter);
});
it("should parse diff with multiple files", function() {
const diff =
"diff --git a/src/core/init.js b/src/core/init.js\n" +
"index e49196a..50f310c 100644\n" +
"--- a/src/core/init.js\n" +
"+++ b/src/core/init.js\n" +
"@@ -101,7 +101,7 @@ var rootjQuery,\n" +
" // HANDLE: $(function)\n" +
" // Shortcut for document ready\n" +
" } else if ( jQuery.isFunction( selector ) ) {\n" +
'- return typeof rootjQuery.ready !== "undefined" ?\n' +
"+ return rootjQuery.ready !== undefined ?\n" +
" rootjQuery.ready( selector ) :\n" +
" // Execute immediately if ready is not present\n" +
" selector( jQuery );\n" +
"diff --git a/src/event.js b/src/event.js\n" +
"index 7336f4d..6183f70 100644\n" +
"--- a/src/event.js\n" +
"+++ b/src/event.js\n" +
"@@ -1,6 +1,5 @@\n" +
" define([\n" +
' "./core",\n' +
'- "./var/strundefined",\n' +
' "./var/rnotwhite",\n' +
' "./var/hasOwn",\n' +
' "./var/slice",\n';
const result = DiffParser.generateDiffJson(diff);
expect(2).toEqual(result.length);
const file1 = result[0];
expect(false).toEqual(file1.isCombined);
expect(1).toEqual(file1.addedLines);
expect(1).toEqual(file1.deletedLines);
expect("src/core/init.js").toEqual(file1.oldName);
expect("src/core/init.js").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
expect(8).toEqual(file1.blocks[0].lines.length);
expect("e49196a").toEqual(file1.checksumBefore);
expect("50f310c").toEqual(file1.checksumAfter);
const file2 = result[1];
expect(false).toEqual(file2.isCombined);
expect(0).toEqual(file2.addedLines);
expect(1).toEqual(file2.deletedLines);
expect("src/event.js").toEqual(file2.oldName);
expect("src/event.js").toEqual(file2.newName);
expect(1).toEqual(file2.blocks.length);
expect(6).toEqual(file2.blocks[0].lines.length);
expect("7336f4d").toEqual(file2.checksumBefore);
expect("6183f70").toEqual(file2.checksumAfter);
});
it("should parse combined diff", function() {
const diff =
"diff --combined describe.c\n" +
"index fabadb8,cc95eb0..4866510\n" +
"--- a/describe.c\n" +
"+++ b/describe.c\n" +
"@@@ -98,20 -98,12 +98,20 @@@\n" +
" return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;\n" +
" }\n" +
" \n" +
"- static void describe(char *arg)\n" +
" -static void describe(struct commit *cmit, int last_one)\n" +
"++static void describe(char *arg, int last_one)\n" +
" {\n" +
" + unsigned char sha1[20];\n" +
" + struct commit *cmit;\n" +
" struct commit_list *list;\n" +
" static int initialized = 0;\n" +
" struct commit_name *n;\n" +
" \n" +
" + if (get_sha1(arg, sha1) < 0)\n" +
" + usage(describe_usage);\n" +
" + cmit = lookup_commit_reference(sha1);\n" +
" + if (!cmit)\n" +
" + usage(describe_usage);\n" +
" +\n" +
" if (!initialized) {\n" +
" initialized = 1;\n" +
" for_each_ref(get_name);\n";
const result = DiffParser.generateDiffJson(diff);
expect(1).toEqual(result.length);
const file1 = result[0];
expect(true).toEqual(file1.isCombined);
expect(9).toEqual(file1.addedLines);
expect(2).toEqual(file1.deletedLines);
expect("describe.c").toEqual(file1.oldName);
expect("describe.c").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
expect(22).toEqual(file1.blocks[0].lines.length);
expect(["4866510", "cc95eb0"].sort()).toEqual(file1.checksumBefore.sort());
expect("fabadb8").toEqual(file1.checksumAfter);
});
it("should parse diffs with copied files", function() {
const diff =
"diff --git a/index.js b/more-index.js\n" +
"dissimilarity index 5%\n" +
"copy from index.js\n" +
"copy to more-index.js\n";
const result = DiffParser.generateDiffJson(diff);
expect(1).toEqual(result.length);
const file1 = result[0];
expect(0).toEqual(file1.addedLines);
expect(0).toEqual(file1.deletedLines);
expect("index.js").toEqual(file1.oldName);
expect("more-index.js").toEqual(file1.newName);
expect(0).toEqual(file1.blocks.length);
expect(true).toEqual(file1.isCopy);
expect("5").toEqual(file1.changedPercentage);
});
it("should parse diffs with moved files", function() {
const diff =
"diff --git a/more-index.js b/other-index.js\n" +
"similarity index 86%\n" +
"rename from more-index.js\n" +
"rename to other-index.js\n";
const result = DiffParser.generateDiffJson(diff);
expect(1).toEqual(result.length);
const file1 = result[0];
expect(0).toEqual(file1.addedLines);
expect(0).toEqual(file1.deletedLines);
expect("more-index.js").toEqual(file1.oldName);
expect("other-index.js").toEqual(file1.newName);
expect(0).toEqual(file1.blocks.length);
expect(true).toEqual(file1.isRename);
expect("86").toEqual(file1.unchangedPercentage);
});
it("should parse diffs correct line numbers", function() {
const diff =
"diff --git a/sample b/sample\n" +
"index 0000001..0ddf2ba\n" +
"--- a/sample\n" +
"+++ b/sample\n" +
"@@ -1 +1,2 @@\n" +
"-test\n" +
"+test1r\n";
const result = DiffParser.generateDiffJson(diff);
expect(1).toEqual(result.length);
const file1 = result[0];
expect(1).toEqual(file1.addedLines);
expect(1).toEqual(file1.deletedLines);
expect("sample").toEqual(file1.oldName);
expect("sample").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
expect(2).toEqual(file1.blocks[0].lines.length);
expect(1).toEqual(file1.blocks[0].lines[0].oldNumber);
expect(null).toEqual(file1.blocks[0].lines[0].newNumber);
expect(null).toEqual(file1.blocks[0].lines[1].oldNumber);
expect(1).toEqual(file1.blocks[0].lines[1].newNumber);
});
it("should parse unified non git diff and strip timestamps off the headers", function() {
const diffs = [
// 2 hours ahead of GMT
"--- a/sample.js 2016-10-25 11:37:14.000000000 +0200\n" +
"+++ b/sample.js 2016-10-25 11:37:14.000000000 +0200\n" +
"@@ -1 +1,2 @@\n" +
"-test\n" +
"+test1r\n" +
"+test2r\n",
// 2 hours behind GMT
"--- a/sample.js 2016-10-25 11:37:14.000000000 -0200\n" +
"+++ b/sample.js 2016-10-25 11:37:14.000000000 -0200\n" +
"@@ -1 +1,2 @@\n" +
"-test\n" +
"+test1r\n" +
"+test2r\n"
];
diffs.forEach(function(diff) {
const result = DiffParser.generateDiffJson(diff);
const file1 = result[0];
expect(1).toEqual(result.length);
expect(2).toEqual(file1.addedLines);
expect(1).toEqual(file1.deletedLines);
expect("sample.js").toEqual(file1.oldName);
expect("sample.js").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
const linesContent = file1.blocks[0].lines.map(function(line) {
return line.content;
});
expect(linesContent).toEqual(["-test", "+test1r", "+test2r"]);
});
});
it("should parse unified non git diff", function() {
const diff =
"--- a/sample.js\n" + "+++ b/sample.js\n" + "@@ -1 +1,2 @@\n" + "-test\n" + "+test1r\n" + "+test2r\n";
const result = DiffParser.generateDiffJson(diff);
const file1 = result[0];
expect(1).toEqual(result.length);
expect(2).toEqual(file1.addedLines);
expect(1).toEqual(file1.deletedLines);
expect("sample.js").toEqual(file1.oldName);
expect("sample.js").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
const linesContent = file1.blocks[0].lines.map(function(line) {
return line.content;
});
expect(linesContent).toEqual(["-test", "+test1r", "+test2r"]);
});
it("should parse unified diff with multiple hunks and files", function() {
const diff =
"--- sample.js\n" +
"+++ sample.js\n" +
"@@ -1 +1,2 @@\n" +
"-test\n" +
"@@ -10 +20,2 @@\n" +
"+test\n" +
"--- sample1.js\n" +
"+++ sample1.js\n" +
"@@ -1 +1,2 @@\n" +
"+test1";
const result = DiffParser.generateDiffJson(diff);
expect(2).toEqual(result.length);
const file1 = result[0];
expect(1).toEqual(file1.addedLines);
expect(1).toEqual(file1.deletedLines);
expect("sample.js").toEqual(file1.oldName);
expect("sample.js").toEqual(file1.newName);
expect(2).toEqual(file1.blocks.length);
const linesContent1 = file1.blocks[0].lines.map(function(line) {
return line.content;
});
expect(linesContent1).toEqual(["-test"]);
const linesContent2 = file1.blocks[1].lines.map(function(line) {
return line.content;
});
expect(linesContent2).toEqual(["+test"]);
const file2 = result[1];
expect(1).toEqual(file2.addedLines);
expect(0).toEqual(file2.deletedLines);
expect("sample1.js").toEqual(file2.oldName);
expect("sample1.js").toEqual(file2.newName);
expect(1).toEqual(file2.blocks.length);
const linesContent = file2.blocks[0].lines.map(function(line) {
return line.content;
});
expect(linesContent).toEqual(["+test1"]);
});
it("should parse diff with --- and +++ in the context lines", function() {
const diff =
"--- sample.js\n" +
"+++ sample.js\n" +
"@@ -1,8 +1,8 @@\n" +
" test\n" +
" \n" +
"-- 1\n" +
"--- 1\n" +
"---- 1\n" +
" \n" +
"++ 2\n" +
"+++ 2\n" +
"++++ 2";
const result = DiffParser.generateDiffJson(diff);
const file1 = result[0];
expect(1).toEqual(result.length);
expect(3).toEqual(file1.addedLines);
expect(3).toEqual(file1.deletedLines);
expect("sample.js").toEqual(file1.oldName);
expect("sample.js").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
const linesContent = file1.blocks[0].lines.map(function(line) {
return line.content;
});
expect(linesContent).toEqual([" test", " ", "-- 1", "--- 1", "---- 1", " ", "++ 2", "+++ 2", "++++ 2"]);
});
it("should parse diff without proper hunk headers", function() {
const diff = "--- sample.js\n" + "+++ sample.js\n" + "@@ @@\n" + " test";
const result = DiffParser.generateDiffJson(diff);
const file1 = result[0];
expect(1).toEqual(result.length);
expect(0).toEqual(file1.addedLines);
expect(0).toEqual(file1.deletedLines);
expect("sample.js").toEqual(file1.oldName);
expect("sample.js").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
const linesContent = file1.blocks[0].lines.map(function(line) {
return line.content;
});
expect(linesContent).toEqual([" test"]);
});
it("should parse binary file diff", function() {
const diff =
"diff --git a/last-changes-config.png b/last-changes-config.png\n" +
"index 322248b..56fc1f2 100644\n" +
"--- a/last-changes-config.png\n" +
"+++ b/last-changes-config.png\n" +
"Binary files differ";
const result = DiffParser.generateDiffJson(diff);
const file1 = result[0];
expect(1).toEqual(result.length);
expect(0).toEqual(file1.addedLines);
expect(0).toEqual(file1.deletedLines);
expect("last-changes-config.png").toEqual(file1.oldName);
expect("last-changes-config.png").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
expect(0).toEqual(file1.blocks[0].lines.length);
expect("Binary files differ").toEqual(file1.blocks[0].header);
});
it("should parse diff with --find-renames", function() {
const diff =
"diff --git a/src/test-bar.js b/src/test-baz.js\n" +
"similarity index 98%\n" +
"rename from src/test-bar.js\n" +
"rename to src/test-baz.js\n" +
"index e01513b..f14a870 100644\n" +
"--- a/src/test-bar.js\n" +
"+++ b/src/test-baz.js\n" +
"@@ -1,4 +1,32 @@\n" +
" function foo() {\n" +
'-var bar = "Whoops!";\n' +
'+var baz = "Whoops!";\n' +
" }\n" +
" ";
const result = DiffParser.generateDiffJson(diff);
const file1 = result[0];
expect(1).toEqual(result.length);
expect(1).toEqual(file1.addedLines);
expect(1).toEqual(file1.deletedLines);
expect("src/test-bar.js").toEqual(file1.oldName);
expect("src/test-baz.js").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
expect(5).toEqual(file1.blocks[0].lines.length);
const linesContent = file1.blocks[0].lines.map(function(line) {
return line.content;
});
expect(linesContent).toEqual([" function foo() {", '-var bar = "Whoops!";', '+var baz = "Whoops!";', " }", " "]);
});
it("should parse diff with prefix 2", function() {
const diff =
'diff --git "\tTest.scala" "\tScalaTest.scala"\n' +
"similarity index 88%\n" +
"rename from Test.scala\n" +
"rename to ScalaTest.scala\n" +
"index 7d1f9bf..8b13271 100644\n" +
'--- "\tTest.scala"\n' +
'+++ "\tScalaTest.scala"\n' +
"@@ -1,6 +1,8 @@\n" +
" class Test {\n" +
" \n" +
" def method1 = ???\n" +
"+\n" +
"+ def method2 = ???\n" +
" \n" +
" def myMethod = ???\n" +
" \n" +
"@@ -10,7 +12,6 @@ class Test {\n" +
" \n" +
" def + = ???\n" +
" \n" +
"- def |> = ???\n" +
" \n" +
" }\n" +
" \n" +
'diff --git "\ttardis.png" "\ttardis.png"\n' +
"new file mode 100644\n" +
"index 0000000..d503a29\n" +
'Binary files /dev/null and "\ttardis.png" differ\n' +
"diff --git a/src/test-bar.js b/src/test-baz.js\n" +
"similarity index 98%\n" +
"rename from src/test-bar.js\n" +
"rename to src/test-baz.js\n" +
"index e01513b..f14a870 100644\n" +
"--- a/src/test-bar.js\n" +
"+++ b/src/test-baz.js\n" +
"@@ -1,4 +1,32 @@\n" +
" function foo() {\n" +
'-var bar = "Whoops!";\n' +
'+var baz = "Whoops!";\n' +
" }\n" +
" ";
const result = DiffParser.generateDiffJson(diff, { srcPrefix: "\t", dstPrefix: "\t" });
expect(3).toEqual(result.length);
const file1 = result[0];
expect(2).toEqual(file1.addedLines);
expect(1).toEqual(file1.deletedLines);
expect("Test.scala").toEqual(file1.oldName);
expect("ScalaTest.scala").toEqual(file1.newName);
expect(2).toEqual(file1.blocks.length);
expect(8).toEqual(file1.blocks[0].lines.length);
expect(7).toEqual(file1.blocks[1].lines.length);
const file2 = result[1];
expect("/dev/null").toEqual(file2.oldName);
expect("tardis.png").toEqual(file2.newName);
const file3 = result[2];
expect(1).toEqual(file3.addedLines);
expect(1).toEqual(file3.deletedLines);
expect("src/test-bar.js").toEqual(file3.oldName);
expect("src/test-baz.js").toEqual(file3.newName);
expect(1).toEqual(file3.blocks.length);
expect(5).toEqual(file3.blocks[0].lines.length);
const linesContent = file3.blocks[0].lines.map(function(line) {
return line.content;
});
expect(linesContent).toEqual([" function foo() {", '-var bar = "Whoops!";', '+var baz = "Whoops!";', " }", " "]);
});
it("should parse binary with content", function() {
const diff =
"diff --git a/favicon.png b/favicon.png\n" +
"deleted file mode 100644\n" +
"index 2a9d516a5647205d7be510dd0dff93a3663eff6f..0000000000000000000000000000000000000000\n" +
"GIT binary patch\n" +
"literal 0\n" +
"HcmV?d00001\n" +
"\n" +
"literal 471\n" +
"zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf<Z~8yL>4nJ\n" +
"za0`Jj<E6WGe}IBwC9V-A&PAz-C7Jno3L%-fsSJk3`UaNzMkcGzh!g=;$beJ?=ckpF\n" +
"zCl;kLIHu$$r7E~(7NwTw7iAYKI0u`(*t4mJfq_xq)5S5wqIc=!hrWj$cv|<b{x!c(\n" +
"z;3r#y;31Y&=1q>qPVOAS4ANVKzqmCp=Cty@U^(7zk!jHsvT~YI{F^=Ex6g|gox78w\n" +
"z+Sn2Du3GS9U7qU`1*NYYlJi3u-!<?H-eky}wyIIL;8VU@wCDrb0``&v(jQ*DWSR4K\n" +
"zPq(3;isEyho{emNa=%%!jDPE`l3u;5d=q=<+v8kO-=C`*G#t-*AiE-D>-_B#8k9H0\n" +
"zGl{FnZs<2$wz5^=Q2h-1XI^s{LQL1#T4epqNPC%Orl(tD_@!*EY++~^Lt2<2&!&%=\n" +
"z`m>(TYj6uS7jDdt=eH>iOyQg(QMR<-Fw8)Dk^ZG)XQTuzEgl{`GpS?Cfq9818R9~=\n" +
"z{&h9@9n8F^?|qusoPy{k#%tVHzu7H$t26CR`BJZk*Ixf&u36WuS=?6m2^ho-p00i_\n" +
"I>zopr0Nz-&lmGw#\n" +
"diff --git a/src/test-bar.js b/src/test-baz.js\n" +
"similarity index 98%\n" +
"rename from src/test-bar.js\n" +
"rename to src/test-baz.js\n" +
"index e01513b..f14a870 100644\n" +
"--- a/src/test-bar.js\n" +
"+++ b/src/test-baz.js\n" +
"@@ -1,4 +1,32 @@\n" +
" function foo() {\n" +
'-var bar = "Whoops!";\n' +
'+var baz = "Whoops!";\n' +
" }\n" +
" ";
const result = DiffParser.generateDiffJson(diff);
expect(2).toEqual(result.length);
const file1 = result[0];
expect("favicon.png").toEqual(file1.oldName);
expect("favicon.png").toEqual(file1.newName);
expect(1).toEqual(file1.blocks.length);
expect(0).toEqual(file1.blocks[0].lines.length);
const file2 = result[1];
expect(1).toEqual(file2.addedLines);
expect(1).toEqual(file2.deletedLines);
expect("src/test-bar.js").toEqual(file2.oldName);
expect("src/test-baz.js").toEqual(file2.newName);
expect(1).toEqual(file2.blocks.length);
expect(5).toEqual(file2.blocks[0].lines.length);
const linesContent = file2.blocks[0].lines.map(function(line) {
return line.content;
});
expect(linesContent).toEqual([" function foo() {", '-var bar = "Whoops!";', '+var baz = "Whoops!";', " }", " "]);
});
});
});

View file

@ -1,59 +1,56 @@
var assert = require('assert'); const Diff2Html = require("../diff2html.js").Diff2Html;
var Diff2Html = require('../src/diff2html.js').Diff2Html; const diffExample1 =
"diff --git a/sample b/sample\n" +
"index 0000001..0ddf2ba\n" +
"--- a/sample\n" +
"+++ b/sample\n" +
"@@ -1 +1 @@\n" +
"-test\n" +
"+test1\n";
var diffExample1 = const jsonExample1 = [
'diff --git a/sample b/sample\n' +
'index 0000001..0ddf2ba\n' +
'--- a/sample\n' +
'+++ b/sample\n' +
'@@ -1 +1 @@\n' +
'-test\n' +
'+test1\n';
var jsonExample1 =
[
{ {
blocks: [ blocks: [
{ {
lines: [ lines: [
{ {
content: '-test', content: "-test",
type: 'd2h-del', type: "d2h-del",
oldNumber: 1, oldNumber: 1,
newNumber: null newNumber: null
}, },
{ {
content: '+test1', content: "+test1",
type: 'd2h-ins', type: "d2h-ins",
oldNumber: null, oldNumber: null,
newNumber: 1 newNumber: 1
} }
], ],
oldStartLine: '1', oldStartLine: "1",
oldStartLine2: null, oldStartLine2: null,
newStartLine: '1', newStartLine: "1",
header: '@@ -1 +1 @@' header: "@@ -1 +1 @@"
} }
], ],
deletedLines: 1, deletedLines: 1,
addedLines: 1, addedLines: 1,
checksumBefore: '0000001', checksumBefore: "0000001",
checksumAfter: '0ddf2ba', checksumAfter: "0ddf2ba",
oldName: 'sample', oldName: "sample",
language: undefined, language: undefined,
newName: 'sample', newName: "sample",
isCombined: false isCombined: false
} }
]; ];
var filesExample1 = const filesExample1 =
'<div class="d2h-file-list-wrapper">\n' + '<div class="d2h-file-list-wrapper">\n' +
' <div class="d2h-file-list-header">\n' + ' <div class="d2h-file-list-header">\n' +
' <span class="d2h-file-list-title">Files changed (1)</span>\n' + ' <span class="d2h-file-list-title">Files changed (1)</span>\n' +
' <a class="d2h-file-switch d2h-hide">hide</a>\n' + ' <a class="d2h-file-switch d2h-hide">hide</a>\n' +
' <a class="d2h-file-switch d2h-show">show</a>\n' + ' <a class="d2h-file-switch d2h-show">show</a>\n' +
' </div>\n' + " </div>\n" +
' <ol class="d2h-file-list">\n' + ' <ol class="d2h-file-list">\n' +
' <li class="d2h-file-list-line">\n' + ' <li class="d2h-file-list-line">\n' +
' <span class="d2h-file-name-wrapper">\n' + ' <span class="d2h-file-name-wrapper">\n' +
@ -64,13 +61,13 @@ var filesExample1 =
' <span class="d2h-file-stats">\n' + ' <span class="d2h-file-stats">\n' +
' <span class="d2h-lines-added">+1</span>\n' + ' <span class="d2h-lines-added">+1</span>\n' +
' <span class="d2h-lines-deleted">-1</span>\n' + ' <span class="d2h-lines-deleted">-1</span>\n' +
' </span>\n' + " </span>\n" +
' </span>\n' + " </span>\n" +
'</li>\n' + "</li>\n" +
' </ol>\n' + " </ol>\n" +
'</div>'; "</div>";
var htmlLineExample1 = const htmlLineExample1 =
'<div class="d2h-wrapper">\n' + '<div class="d2h-wrapper">\n' +
' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="">\n' + ' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="">\n' +
' <div class="d2h-file-header">\n' + ' <div class="d2h-file-header">\n' +
@ -79,49 +76,49 @@ var htmlLineExample1 =
' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' + ' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' +
' </svg> <span class="d2h-file-name">sample</span>\n' + ' </svg> <span class="d2h-file-name">sample</span>\n' +
' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' + ' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' +
' </div>\n' + " </div>\n" +
' <div class="d2h-file-diff">\n' + ' <div class="d2h-file-diff">\n' +
' <div class="d2h-code-wrapper">\n' + ' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' + ' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' + ' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' + " <tr>\n" +
' <td class="d2h-code-linenumber d2h-info"></td>\n' + ' <td class="d2h-code-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">@@ -1 +1 @@</div>\n' + ' <div class="d2h-code-line d2h-info">@@ -1 +1 @@</div>\n' +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-del">\n' + ' <td class="d2h-code-linenumber d2h-del">\n' +
' <div class="line-num1">1</div>\n' + ' <div class="line-num1">1</div>\n' +
'<div class="line-num2"></div>\n' + '<div class="line-num2"></div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-del">\n' + ' <td class="d2h-del">\n' +
' <div class="d2h-code-line d2h-del">\n' + ' <div class="d2h-code-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' + ' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn"><del>test</del></span>\n' + ' <span class="d2h-code-line-ctn"><del>test</del></span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' + ' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' + ' <div class="line-num1"></div>\n' +
'<div class="line-num2">1</div>\n' + '<div class="line-num2">1</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' + ' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn"><ins>test1</ins></span>\n' + ' <span class="d2h-code-line-ctn"><ins>test1</ins></span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>\n' + "</tr>\n" +
' </tbody>\n' + " </tbody>\n" +
' </table>\n' + " </table>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
'</div>\n' + "</div>\n" +
'</div>'; "</div>";
var htmlLineExample1WithFilesSummary = filesExample1 + htmlLineExample1; const htmlLineExample1WithFilesSummary = filesExample1 + htmlLineExample1;
var htmlSideExample1 = const htmlSideExample1 =
'<div class="d2h-wrapper">\n' + '<div class="d2h-wrapper">\n' +
' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="">\n' + ' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="">\n' +
' <div class="d2h-file-header">\n' + ' <div class="d2h-file-header">\n' +
@ -130,187 +127,189 @@ var htmlSideExample1 =
' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' + ' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' +
' </svg> <span class="d2h-file-name">sample</span>\n' + ' </svg> <span class="d2h-file-name">sample</span>\n' +
' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' + ' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' +
' </div>\n' + " </div>\n" +
' <div class="d2h-files-diff">\n' + ' <div class="d2h-files-diff">\n' +
' <div class="d2h-file-side-diff">\n' + ' <div class="d2h-file-side-diff">\n' +
' <div class="d2h-code-wrapper">\n' + ' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' + ' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' + ' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' + " <tr>\n" +
' <td class="d2h-code-side-linenumber d2h-info"></td>\n' + ' <td class="d2h-code-side-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info">@@ -1 +1 @@</div>\n' + ' <div class="d2h-code-side-line d2h-info">@@ -1 +1 @@</div>\n' +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-del">\n' + ' <td class="d2h-code-side-linenumber d2h-del">\n' +
' 1\n' + " 1\n" +
' </td>\n' + " </td>\n" +
' <td class="d2h-del">\n' + ' <td class="d2h-del">\n' +
' <div class="d2h-code-side-line d2h-del">\n' + ' <div class="d2h-code-side-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' + ' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn"><del>test</del></span>\n' + ' <span class="d2h-code-line-ctn"><del>test</del></span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>\n' + "</tr>\n" +
' </tbody>\n' + " </tbody>\n" +
' </table>\n' + " </table>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
' <div class="d2h-file-side-diff">\n' + ' <div class="d2h-file-side-diff">\n' +
' <div class="d2h-code-wrapper">\n' + ' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' + ' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' + ' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' + " <tr>\n" +
' <td class="d2h-code-side-linenumber d2h-info"></td>\n' + ' <td class="d2h-code-side-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info"></div>\n' + ' <div class="d2h-code-side-line d2h-info"></div>\n' +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-ins">\n' + ' <td class="d2h-code-side-linenumber d2h-ins">\n' +
' 1\n' + " 1\n" +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-side-line d2h-ins">\n' + ' <div class="d2h-code-side-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn"><ins>test1</ins></span>\n' + ' <span class="d2h-code-line-ctn"><ins>test1</ins></span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>\n' + "</tr>\n" +
' </tbody>\n' + " </tbody>\n" +
' </table>\n' + " </table>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
'</div>\n' + "</div>\n" +
'</div>'; "</div>";
var htmlSideExample1WithFilesSummary = filesExample1 + htmlSideExample1; const htmlSideExample1WithFilesSummary = filesExample1 + htmlSideExample1;
describe('Diff2Html', function() { describe("Diff2Html", function() {
describe('getJsonFromDiff', function() { describe("getJsonFromDiff", function() {
it('should parse simple diff to json', function() { it("should parse simple diff to json", function() {
var diff = const diff =
'diff --git a/sample b/sample\n' + "diff --git a/sample b/sample\n" +
'index 0000001..0ddf2ba\n' + "index 0000001..0ddf2ba\n" +
'--- a/sample\n' + "--- a/sample\n" +
'+++ b/sample\n' + "+++ b/sample\n" +
'@@ -1 +1 @@\n' + "@@ -1 +1 @@\n" +
'-test\n' + "-test\n" +
'+test1\n'; "+test1\n";
var result = Diff2Html.getJsonFromDiff(diff); const result = Diff2Html.getJsonFromDiff(diff);
var file1 = result[0]; const file1 = result[0];
assert.equal(1, result.length); expect(1).toEqual(result.length);
assert.equal(1, file1.addedLines); expect(1).toEqual(file1.addedLines);
assert.equal(1, file1.deletedLines); expect(1).toEqual(file1.deletedLines);
assert.equal('sample', file1.oldName); expect("sample").toEqual(file1.oldName);
assert.equal('sample', file1.newName); expect("sample").toEqual(file1.newName);
assert.equal(1, file1.blocks.length); expect(1).toEqual(file1.blocks.length);
}); });
// Test case for issue #49 // Test case for issue #49
it('should parse diff with added EOF', function() { it("should parse diff with added EOF", function() {
var diff = const diff =
'diff --git a/sample.scala b/sample.scala\n' + "diff --git a/sample.scala b/sample.scala\n" +
'index b583263..8b2fc3e 100644\n' + "index b583263..8b2fc3e 100644\n" +
'--- a/b583263..8b2fc3e\n' + "--- a/b583263..8b2fc3e\n" +
'+++ b/8b2fc3e\n' + "+++ b/8b2fc3e\n" +
'@@ -50,5 +50,7 @@ case class Response[+A](value: Option[A],\n' + "@@ -50,5 +50,7 @@ case class Response[+A](value: Option[A],\n" +
' object ResponseErrorCode extends JsonEnumeration {\n' + " object ResponseErrorCode extends JsonEnumeration {\n" +
' val NoError, ServiceError, JsonError,\n' + " val NoError, ServiceError, JsonError,\n" +
' InvalidPermissions, MissingPermissions, GenericError,\n' + " InvalidPermissions, MissingPermissions, GenericError,\n" +
'- TokenRevoked, MissingToken = Value\n' + "- TokenRevoked, MissingToken = Value\n" +
'-}\n' + "-}\n" +
'\\ No newline at end of file\n' + "\\ No newline at end of file\n" +
'+ TokenRevoked, MissingToken,\n' + "+ TokenRevoked, MissingToken,\n" +
'+ IndexLock, RepositoryError, NotValidRepo, PullRequestNotMergeable, BranchError,\n' + "+ IndexLock, RepositoryError, NotValidRepo, PullRequestNotMergeable, BranchError,\n" +
'+ PluginError, CodeParserError, EngineError = Value\n' + "+ PluginError, CodeParserError, EngineError = Value\n" +
'+}\n'; "+}\n";
var result = Diff2Html.getJsonFromDiff(diff); const result = Diff2Html.getJsonFromDiff(diff);
assert.equal(50, result[0].blocks[0].lines[0].oldNumber); expect(50).toEqual(result[0].blocks[0].lines[0].oldNumber);
assert.equal(50, result[0].blocks[0].lines[0].newNumber); expect(50).toEqual(result[0].blocks[0].lines[0].newNumber);
assert.equal(51, result[0].blocks[0].lines[1].oldNumber); expect(51).toEqual(result[0].blocks[0].lines[1].oldNumber);
assert.equal(51, result[0].blocks[0].lines[1].newNumber); expect(51).toEqual(result[0].blocks[0].lines[1].newNumber);
assert.equal(52, result[0].blocks[0].lines[2].oldNumber); expect(52).toEqual(result[0].blocks[0].lines[2].oldNumber);
assert.equal(52, result[0].blocks[0].lines[2].newNumber); expect(52).toEqual(result[0].blocks[0].lines[2].newNumber);
assert.equal(53, result[0].blocks[0].lines[3].oldNumber); expect(53).toEqual(result[0].blocks[0].lines[3].oldNumber);
assert.equal(null, result[0].blocks[0].lines[3].newNumber); expect(null).toEqual(result[0].blocks[0].lines[3].newNumber);
assert.equal(54, result[0].blocks[0].lines[4].oldNumber); expect(54).toEqual(result[0].blocks[0].lines[4].oldNumber);
assert.equal(null, result[0].blocks[0].lines[4].newNumber); expect(null).toEqual(result[0].blocks[0].lines[4].newNumber);
assert.equal(null, result[0].blocks[0].lines[5].oldNumber); expect(null).toEqual(result[0].blocks[0].lines[5].oldNumber);
assert.equal(53, result[0].blocks[0].lines[5].newNumber); expect(53).toEqual(result[0].blocks[0].lines[5].newNumber);
assert.equal(null, result[0].blocks[0].lines[6].oldNumber); expect(null).toEqual(result[0].blocks[0].lines[6].oldNumber);
assert.equal(54, result[0].blocks[0].lines[6].newNumber); expect(54).toEqual(result[0].blocks[0].lines[6].newNumber);
assert.equal(null, result[0].blocks[0].lines[7].oldNumber); expect(null).toEqual(result[0].blocks[0].lines[7].oldNumber);
assert.equal(55, result[0].blocks[0].lines[7].newNumber); expect(55).toEqual(result[0].blocks[0].lines[7].newNumber);
assert.equal(null, result[0].blocks[0].lines[8].oldNumber); expect(null).toEqual(result[0].blocks[0].lines[8].oldNumber);
assert.equal(56, result[0].blocks[0].lines[8].newNumber); expect(56).toEqual(result[0].blocks[0].lines[8].newNumber);
}); });
it('should generate pretty line by line html from diff', function() { it("should generate pretty line by line html from diff", function() {
var result = Diff2Html.getPrettyHtmlFromDiff(diffExample1); const result = Diff2Html.getPrettyHtmlFromDiff(diffExample1);
assert.equal(htmlLineExample1, result); expect(htmlLineExample1).toEqual(result);
}); });
it('should generate pretty line by line html from json', function() { it("should generate pretty line by line html from json", function() {
var result = Diff2Html.getPrettyHtmlFromJson(jsonExample1); const result = Diff2Html.getPrettyHtmlFromJson(jsonExample1);
assert.equal(htmlLineExample1, result); expect(htmlLineExample1).toEqual(result);
}); });
it('should generate pretty diff with files summary', function() { it("should generate pretty diff with files summary", function() {
var result = Diff2Html.getPrettyHtmlFromDiff(diffExample1, {showFiles: true}); const result = Diff2Html.getPrettyHtmlFromDiff(diffExample1, { showFiles: true });
assert.equal(htmlLineExample1WithFilesSummary, result); expect(htmlLineExample1WithFilesSummary).toEqual(result);
}); });
it('should generate pretty side by side html from diff', function() { it("should generate pretty side by side html from diff", function() {
var result = Diff2Html.getPrettySideBySideHtmlFromDiff(diffExample1); const result = Diff2Html.getPrettySideBySideHtmlFromDiff(diffExample1);
assert.equal(htmlSideExample1, result); expect(htmlSideExample1).toEqual(result);
}); });
it('should generate pretty side by side html from json', function() { it("should generate pretty side by side html from json", function() {
var result = Diff2Html.getPrettySideBySideHtmlFromJson(jsonExample1); const result = Diff2Html.getPrettySideBySideHtmlFromJson(jsonExample1);
assert.equal(htmlSideExample1, result); expect(htmlSideExample1).toEqual(result);
}); });
it('should generate pretty side by side html from diff', function() { it("should generate pretty side by side html from diff 2", function() {
var result = Diff2Html.getPrettySideBySideHtmlFromDiff(diffExample1, {showFiles: true}); const result = Diff2Html.getPrettySideBySideHtmlFromDiff(diffExample1, { showFiles: true });
assert.equal(htmlSideExample1WithFilesSummary, result); expect(htmlSideExample1WithFilesSummary).toEqual(result);
}); });
it('should generate pretty side by side html from diff with html on headers', function() { it("should generate pretty side by side html from diff with html on headers", function() {
var diffExample2 = 'diff --git a/CHANGELOG.md b/CHANGELOG.md\n' + const diffExample2 =
'index fc3e3f4..b486d10 100644\n' + "diff --git a/CHANGELOG.md b/CHANGELOG.md\n" +
'--- a/CHANGELOG.md\n' + "index fc3e3f4..b486d10 100644\n" +
'+++ b/CHANGELOG.md\n' + "--- a/CHANGELOG.md\n" +
'@@ -1,7 +1,6 @@\n' + "+++ b/CHANGELOG.md\n" +
' # Change Log\n' + "@@ -1,7 +1,6 @@\n" +
' All notable changes to this project will be documented in this file.\n' + " # Change Log\n" +
' This project adheres to [Semantic Versioning](http://semver.org/).\n' + " All notable changes to this project will be documented in this file.\n" +
" This project adheres to [Semantic Versioning](http://semver.org/).\n" +
'-$a="<table><tr><td>Use the following format for additions: ` - VERSION: [feature/patch (if applicable)] Short description of change. Links to relevant issues/PRs.`\n' + '-$a="<table><tr><td>Use the following format for additions: ` - VERSION: [feature/patch (if applicable)] Short description of change. Links to relevant issues/PRs.`\n' +
' $a="<table><tr><td>\n' + ' $a="<table><tr><td>\n' +
" $a=\"<table><tr><td>- 1.1.9: Fix around ubuntu's inability to cache promises. [#877](https://github.com/FredrikNoren/ungit/pull/878)\n" + " $a=\"<table><tr><td>- 1.1.9: Fix around ubuntu's inability to cache promises. [#877](https://github.com/FredrikNoren/ungit/pull/878)\n" +
' - 1.1.8:\n' + " - 1.1.8:\n" +
"@@ -11,7 +10,7 @@ $a=\"<table><tr><td>- 1.1.9: Fix around ubuntu's inability to cache promises. [#8\n" + "@@ -11,7 +10,7 @@ $a=\"<table><tr><td>- 1.1.9: Fix around ubuntu's inability to cache promises. [#8\n" +
' - 1.1.7:\n' + " - 1.1.7:\n" +
' - Fix diff flickering issue and optimization [#865](https://github.com/FredrikNoren/ungit/pull/865)\n' + " - Fix diff flickering issue and optimization [#865](https://github.com/FredrikNoren/ungit/pull/865)\n" +
' - Fix credential dialog issue [#864](https://github.com/FredrikNoren/ungit/pull/864)\n' + " - Fix credential dialog issue [#864](https://github.com/FredrikNoren/ungit/pull/864)\n" +
'- - Fix HEAD branch order when redraw [#858](https://github.com/FredrikNoren/ungit/issues/858)\n' + "- - Fix HEAD branch order when redraw [#858](https://github.com/FredrikNoren/ungit/issues/858)\n" +
'+4 - Fix HEAD branch order when redraw [#858](https://github.com/FredrikNoren/ungit/issues/858)\n' + "+4 - Fix HEAD branch order when redraw [#858](https://github.com/FredrikNoren/ungit/issues/858)\n" +
' - 1.1.6: Fix path auto complete [#861](https://github.com/FredrikNoren/ungit/issues/861)\n' + " - 1.1.6: Fix path auto complete [#861](https://github.com/FredrikNoren/ungit/issues/861)\n" +
' - 1.1.5: Update "Toggle all" button after commit or changing selected files [#859](https://github.com/FredrikNoren/ungit/issues/859)\n' + ' - 1.1.5: Update "Toggle all" button after commit or changing selected files [#859](https://github.com/FredrikNoren/ungit/issues/859)\n' +
' - 1.1.4: [patch] Promise refactoring\n' + " - 1.1.4: [patch] Promise refactoring\n" +
' \n'; " \n";
var htmlExample2 = '<div class="d2h-wrapper">\n' + const htmlExample2 =
'<div class="d2h-wrapper">\n' +
' <div id="d2h-211439" class="d2h-file-wrapper" data-lang="md">\n' + ' <div id="d2h-211439" class="d2h-file-wrapper" data-lang="md">\n' +
' <div class="d2h-file-header">\n' + ' <div class="d2h-file-header">\n' +
' <span class="d2h-file-name-wrapper">\n' + ' <span class="d2h-file-name-wrapper">\n' +
@ -318,207 +317,207 @@ describe('Diff2Html', function() {
' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' + ' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' +
' </svg> <span class="d2h-file-name">CHANGELOG.md</span>\n' + ' </svg> <span class="d2h-file-name">CHANGELOG.md</span>\n' +
' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' + ' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' +
' </div>\n' + " </div>\n" +
' <div class="d2h-file-diff">\n' + ' <div class="d2h-file-diff">\n' +
' <div class="d2h-code-wrapper">\n' + ' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' + ' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' + ' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' + " <tr>\n" +
' <td class="d2h-code-linenumber d2h-info"></td>\n' + ' <td class="d2h-code-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">@@ -1,7 +1,6 @@</div>\n' + ' <div class="d2h-code-line d2h-info">@@ -1,7 +1,6 @@</div>\n' +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' + ' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">1</div>\n' + ' <div class="line-num1">1</div>\n' +
'<div class="line-num2">1</div>\n' + '<div class="line-num2">1</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' + ' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn"># Change Log</span>\n' + ' <span class="d2h-code-line-ctn"># Change Log</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' + ' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">2</div>\n' + ' <div class="line-num1">2</div>\n' +
'<div class="line-num2">2</div>\n' + '<div class="line-num2">2</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' + ' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn">All notable changes to this project will be documented in this file.</span>\n' + ' <span class="d2h-code-line-ctn">All notable changes to this project will be documented in this file.</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' + ' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">3</div>\n' + ' <div class="line-num1">3</div>\n' +
'<div class="line-num2">3</div>\n' + '<div class="line-num2">3</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' + ' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn">This project adheres to [Semantic Versioning](http:&#x2F;&#x2F;semver.org&#x2F;).</span>\n' + ' <span class="d2h-code-line-ctn">This project adheres to [Semantic Versioning](http:&#x2F;&#x2F;semver.org&#x2F;).</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-del">\n' + ' <td class="d2h-code-linenumber d2h-del">\n' +
' <div class="line-num1">4</div>\n' + ' <div class="line-num1">4</div>\n' +
'<div class="line-num2"></div>\n' + '<div class="line-num2"></div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-del">\n' + ' <td class="d2h-del">\n' +
' <div class="d2h-code-line d2h-del">\n' + ' <div class="d2h-code-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' + ' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn">$a=&quot;&lt;table&gt;&lt;tr&gt;&lt;td&gt;Use the following format for additions: ` - VERSION: [feature&#x2F;patch (if applicable)] Short description of change. Links to relevant issues&#x2F;PRs.`</span>\n' + ' <span class="d2h-code-line-ctn">$a=&quot;&lt;table&gt;&lt;tr&gt;&lt;td&gt;Use the following format for additions: ` - VERSION: [feature&#x2F;patch (if applicable)] Short description of change. Links to relevant issues&#x2F;PRs.`</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' + ' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">5</div>\n' + ' <div class="line-num1">5</div>\n' +
'<div class="line-num2">4</div>\n' + '<div class="line-num2">4</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' + ' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn">$a=&quot;&lt;table&gt;&lt;tr&gt;&lt;td&gt;</span>\n' + ' <span class="d2h-code-line-ctn">$a=&quot;&lt;table&gt;&lt;tr&gt;&lt;td&gt;</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' + ' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">6</div>\n' + ' <div class="line-num1">6</div>\n' +
'<div class="line-num2">5</div>\n' + '<div class="line-num2">5</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' + ' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn">$a=&quot;&lt;table&gt;&lt;tr&gt;&lt;td&gt;- 1.1.9: Fix around ubuntu&#x27;s inability to cache promises. [#877](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;pull&#x2F;878)</span>\n' + ' <span class="d2h-code-line-ctn">$a=&quot;&lt;table&gt;&lt;tr&gt;&lt;td&gt;- 1.1.9: Fix around ubuntu&#x27;s inability to cache promises. [#877](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;pull&#x2F;878)</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' + ' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">7</div>\n' + ' <div class="line-num1">7</div>\n' +
'<div class="line-num2">6</div>\n' + '<div class="line-num2">6</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' + ' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn">- 1.1.8:</span>\n' + ' <span class="d2h-code-line-ctn">- 1.1.8:</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>\n' + "</tr>\n" +
'<tr>\n' + "<tr>\n" +
' <td class="d2h-code-linenumber d2h-info"></td>\n' + ' <td class="d2h-code-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">@@ -11,7 +10,7 @@ $a=&quot;&lt;table&gt;&lt;tr&gt;&lt;td&gt;- 1.1.9: Fix around ubuntu&#x27;s inability to cache promises. [#8</div>\n' + ' <div class="d2h-code-line d2h-info">@@ -11,7 +10,7 @@ $a=&quot;&lt;table&gt;&lt;tr&gt;&lt;td&gt;- 1.1.9: Fix around ubuntu&#x27;s inability to cache promises. [#8</div>\n' +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' + ' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">11</div>\n' + ' <div class="line-num1">11</div>\n' +
'<div class="line-num2">10</div>\n' + '<div class="line-num2">10</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' + ' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn">- 1.1.7:</span>\n' + ' <span class="d2h-code-line-ctn">- 1.1.7:</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' + ' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">12</div>\n' + ' <div class="line-num1">12</div>\n' +
'<div class="line-num2">11</div>\n' + '<div class="line-num2">11</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' + ' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn"> - Fix diff flickering issue and optimization [#865](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;pull&#x2F;865)</span>\n' + ' <span class="d2h-code-line-ctn"> - Fix diff flickering issue and optimization [#865](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;pull&#x2F;865)</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' + ' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">13</div>\n' + ' <div class="line-num1">13</div>\n' +
'<div class="line-num2">12</div>\n' + '<div class="line-num2">12</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' + ' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn"> - Fix credential dialog issue [#864](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;pull&#x2F;864)</span>\n' + ' <span class="d2h-code-line-ctn"> - Fix credential dialog issue [#864](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;pull&#x2F;864)</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-del">\n' + ' <td class="d2h-code-linenumber d2h-del">\n' +
' <div class="line-num1">14</div>\n' + ' <div class="line-num1">14</div>\n' +
'<div class="line-num2"></div>\n' + '<div class="line-num2"></div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-del">\n' + ' <td class="d2h-del">\n' +
' <div class="d2h-code-line d2h-del">\n' + ' <div class="d2h-code-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' + ' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn"> - Fix HEAD branch order when redraw [#858](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;issues&#x2F;858)</span>\n' + ' <span class="d2h-code-line-ctn"> - Fix HEAD branch order when redraw [#858](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;issues&#x2F;858)</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' + ' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' + ' <div class="line-num1"></div>\n' +
'<div class="line-num2">13</div>\n' + '<div class="line-num2">13</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' + ' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn"><ins>4</ins> - Fix HEAD branch order when redraw [#858](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;issues&#x2F;858)</span>\n' + ' <span class="d2h-code-line-ctn"><ins>4</ins> - Fix HEAD branch order when redraw [#858](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;issues&#x2F;858)</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' + ' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">15</div>\n' + ' <div class="line-num1">15</div>\n' +
'<div class="line-num2">14</div>\n' + '<div class="line-num2">14</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' + ' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn">- 1.1.6: Fix path auto complete [#861](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;issues&#x2F;861)</span>\n' + ' <span class="d2h-code-line-ctn">- 1.1.6: Fix path auto complete [#861](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;issues&#x2F;861)</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' + ' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">16</div>\n' + ' <div class="line-num1">16</div>\n' +
'<div class="line-num2">15</div>\n' + '<div class="line-num2">15</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' + ' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn">- 1.1.5: Update &quot;Toggle all&quot; button after commit or changing selected files [#859](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;issues&#x2F;859)</span>\n' + ' <span class="d2h-code-line-ctn">- 1.1.5: Update &quot;Toggle all&quot; button after commit or changing selected files [#859](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;issues&#x2F;859)</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' + ' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">17</div>\n' + ' <div class="line-num1">17</div>\n' +
'<div class="line-num2">16</div>\n' + '<div class="line-num2">16</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' + ' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn">- 1.1.4: [patch] Promise refactoring</span>\n' + ' <span class="d2h-code-line-ctn">- 1.1.4: [patch] Promise refactoring</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' + ' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">18</div>\n' + ' <div class="line-num1">18</div>\n' +
'<div class="line-num2">17</div>\n' + '<div class="line-num2">17</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' + ' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>\n' + "</tr>\n" +
' </tbody>\n' + " </tbody>\n" +
' </table>\n' + " </table>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
'</div>\n' + "</div>\n" +
'</div>'; "</div>";
var result = Diff2Html.getPrettyHtmlFromDiff(diffExample2); const result = Diff2Html.getPrettyHtmlFromDiff(diffExample2);
assert.equal(result, htmlExample2); expect(result).toEqual(htmlExample2);
}); });
}); });
}); });

View file

@ -1,92 +1,102 @@
var assert = require('assert'); const FileListPrinter = require("../file-list-printer.js").FileListPrinter;
var FileListPrinter = require('../src/file-list-printer.js').FileListPrinter;
describe('FileListPrinter', function() { describe("FileListPrinter", function() {
describe('generateFileList', function() { describe("generateFileList", function() {
it('should expose old and new files to templates', function() { it("should expose old and new files to templates", function() {
var files = [{ const files = [
{
addedlines: 12, addedlines: 12,
deletedlines: 41, deletedlines: 41,
language: 'js', language: "js",
oldName: 'my/file/name.js', oldName: "my/file/name.js",
newName: 'my/file/name.js' newName: "my/file/name.js"
}, { },
{
addedLines: 12, addedLines: 12,
deletedLines: 41, deletedLines: 41,
language: 'js', language: "js",
oldName: 'my/file/name1.js', oldName: "my/file/name1.js",
newName: 'my/file/name2.js' newName: "my/file/name2.js"
}, { },
{
addedLines: 12, addedLines: 12,
deletedLines: 0, deletedLines: 0,
language: 'js', language: "js",
oldName: 'dev/null', oldName: "dev/null",
newName: 'my/file/name.js', newName: "my/file/name.js",
isNew: true isNew: true
}, { },
{
addedLines: 0, addedLines: 0,
deletedLines: 41, deletedLines: 41,
language: 'js', language: "js",
oldName: 'my/file/name.js', oldName: "my/file/name.js",
newName: 'dev/null', newName: "dev/null",
isDeleted: true isDeleted: true
}]; }
];
var fileListPrinter = new FileListPrinter({ const fileListPrinter = new FileListPrinter({
rawTemplates: { rawTemplates: {
'file-summary-wrapper': '{{{files}}}', "file-summary-wrapper": "{{{files}}}",
'file-summary-line': '{{oldName}}, {{newName}}, {{fileName}}' "file-summary-line": "{{oldName}}, {{newName}}, {{fileName}}"
} }
}); });
var fileHtml = fileListPrinter.generateFileList(files); const fileHtml = fileListPrinter.generateFileList(files);
var expected = 'my/file/name.js, my/file/name.js, my/file/name.js\n' + const expected =
'my/file/name1.js, my/file/name2.js, my/file/{name1.js → name2.js}\n' + "my/file/name.js, my/file/name.js, my/file/name.js\n" +
'dev/null, my/file/name.js, my/file/name.js\n' + "my/file/name1.js, my/file/name2.js, my/file/{name1.js → name2.js}\n" +
'my/file/name.js, dev/null, my/file/name.js'; "dev/null, my/file/name.js, my/file/name.js\n" +
"my/file/name.js, dev/null, my/file/name.js";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
it('should work for all kinds of files', function() { it("should work for all kinds of files", function() {
var files = [{ const files = [
{
addedLines: 12, addedLines: 12,
deletedLines: 41, deletedLines: 41,
language: 'js', language: "js",
oldName: 'my/file/name.js', oldName: "my/file/name.js",
newName: 'my/file/name.js' newName: "my/file/name.js"
}, { },
{
addedLines: 12, addedLines: 12,
deletedLines: 41, deletedLines: 41,
language: 'js', language: "js",
oldName: 'my/file/name1.js', oldName: "my/file/name1.js",
newName: 'my/file/name2.js' newName: "my/file/name2.js"
}, { },
{
addedLines: 12, addedLines: 12,
deletedLines: 0, deletedLines: 0,
language: 'js', language: "js",
oldName: 'dev/null', oldName: "dev/null",
newName: 'my/file/name.js', newName: "my/file/name.js",
isNew: true isNew: true
}, { },
{
addedLines: 0, addedLines: 0,
deletedLines: 41, deletedLines: 41,
language: 'js', language: "js",
oldName: 'my/file/name.js', oldName: "my/file/name.js",
newName: 'dev/null', newName: "dev/null",
isDeleted: true isDeleted: true
}]; }
];
var fileListPrinter = new FileListPrinter(); const fileListPrinter = new FileListPrinter();
var fileHtml = fileListPrinter.generateFileList(files); const fileHtml = fileListPrinter.generateFileList(files);
var expected = const expected =
'<div class="d2h-file-list-wrapper">\n' + '<div class="d2h-file-list-wrapper">\n' +
' <div class="d2h-file-list-header">\n' + ' <div class="d2h-file-list-header">\n' +
' <span class="d2h-file-list-title">Files changed (4)</span>\n' + ' <span class="d2h-file-list-title">Files changed (4)</span>\n' +
' <a class="d2h-file-switch d2h-hide">hide</a>\n' + ' <a class="d2h-file-switch d2h-hide">hide</a>\n' +
' <a class="d2h-file-switch d2h-show">show</a>\n' + ' <a class="d2h-file-switch d2h-show">show</a>\n' +
' </div>\n' + " </div>\n" +
' <ol class="d2h-file-list">\n' + ' <ol class="d2h-file-list">\n' +
' <li class="d2h-file-list-line">\n' + ' <li class="d2h-file-list-line">\n' +
' <span class="d2h-file-name-wrapper">\n' + ' <span class="d2h-file-name-wrapper">\n' +
@ -97,9 +107,9 @@ describe('FileListPrinter', function() {
' <span class="d2h-file-stats">\n' + ' <span class="d2h-file-stats">\n' +
' <span class="d2h-lines-added">+12</span>\n' + ' <span class="d2h-lines-added">+12</span>\n' +
' <span class="d2h-lines-deleted">-41</span>\n' + ' <span class="d2h-lines-deleted">-41</span>\n' +
' </span>\n' + " </span>\n" +
' </span>\n' + " </span>\n" +
'</li>\n' + "</li>\n" +
'<li class="d2h-file-list-line">\n' + '<li class="d2h-file-list-line">\n' +
' <span class="d2h-file-name-wrapper">\n' + ' <span class="d2h-file-name-wrapper">\n' +
' <svg aria-hidden="true" class="d2h-icon d2h-moved" height="16" title="renamed" version="1.1"\n' + ' <svg aria-hidden="true" class="d2h-icon d2h-moved" height="16" title="renamed" version="1.1"\n' +
@ -109,9 +119,9 @@ describe('FileListPrinter', function() {
' <span class="d2h-file-stats">\n' + ' <span class="d2h-file-stats">\n' +
' <span class="d2h-lines-added">+12</span>\n' + ' <span class="d2h-lines-added">+12</span>\n' +
' <span class="d2h-lines-deleted">-41</span>\n' + ' <span class="d2h-lines-deleted">-41</span>\n' +
' </span>\n' + " </span>\n" +
' </span>\n' + " </span>\n" +
'</li>\n' + "</li>\n" +
'<li class="d2h-file-list-line">\n' + '<li class="d2h-file-list-line">\n' +
' <span class="d2h-file-name-wrapper">\n' + ' <span class="d2h-file-name-wrapper">\n' +
' <svg aria-hidden="true" class="d2h-icon d2h-added" height="16" title="added" version="1.1" viewBox="0 0 14 16"\n' + ' <svg aria-hidden="true" class="d2h-icon d2h-added" height="16" title="added" version="1.1" viewBox="0 0 14 16"\n' +
@ -121,9 +131,9 @@ describe('FileListPrinter', function() {
' <span class="d2h-file-stats">\n' + ' <span class="d2h-file-stats">\n' +
' <span class="d2h-lines-added">+12</span>\n' + ' <span class="d2h-lines-added">+12</span>\n' +
' <span class="d2h-lines-deleted">-0</span>\n' + ' <span class="d2h-lines-deleted">-0</span>\n' +
' </span>\n' + " </span>\n" +
' </span>\n' + " </span>\n" +
'</li>\n' + "</li>\n" +
'<li class="d2h-file-list-line">\n' + '<li class="d2h-file-list-line">\n' +
' <span class="d2h-file-name-wrapper">\n' + ' <span class="d2h-file-name-wrapper">\n' +
' <svg aria-hidden="true" class="d2h-icon d2h-deleted" height="16" title="removed" version="1.1"\n' + ' <svg aria-hidden="true" class="d2h-icon d2h-deleted" height="16" title="removed" version="1.1"\n' +
@ -133,13 +143,13 @@ describe('FileListPrinter', function() {
' <span class="d2h-file-stats">\n' + ' <span class="d2h-file-stats">\n' +
' <span class="d2h-lines-added">+0</span>\n' + ' <span class="d2h-lines-added">+0</span>\n' +
' <span class="d2h-lines-deleted">-41</span>\n' + ' <span class="d2h-lines-deleted">-41</span>\n' +
' </span>\n' + " </span>\n" +
' </span>\n' + " </span>\n" +
'</li>\n' + "</li>\n" +
' </ol>\n' + " </ol>\n" +
'</div>'; "</div>";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
}); });
}); });

View file

@ -0,0 +1,73 @@
const HoganJsUtils = new (require("../hoganjs-utils.js")).HoganJsUtils();
const diffParser = require("../diff-parser.js").DiffParser;
describe("HoganJsUtils", function() {
describe("render", function() {
const emptyDiffHtml =
"<tr>\n" +
' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">\n' +
" File without changes\n" +
" </div>\n" +
" </td>\n" +
"</tr>";
it("should render view", function() {
const result = HoganJsUtils.render("generic", "empty-diff", {
contentClass: "d2h-code-line",
diffParser: diffParser
});
expect(emptyDiffHtml).toEqual(result);
});
it("should render view without cache", function() {
const result = HoganJsUtils.render(
"generic",
"empty-diff",
{
contentClass: "d2h-code-line",
diffParser: diffParser
},
{ noCache: true }
);
expect(emptyDiffHtml).toEqual(result);
});
it("should return null if template is missing", function() {
const hoganUtils = new (require("../hoganjs-utils.js")).HoganJsUtils({ noCache: true });
const result = hoganUtils.render("generic", "missing-template", {});
expect(null).toEqual(result);
});
it("should allow templates to be overridden with compiled templates", function() {
const emptyDiffTemplate = HoganJsUtils.compile("<p>{{myName}}</p>");
const config = { templates: { "generic-empty-diff": emptyDiffTemplate } };
const hoganUtils = new (require("../hoganjs-utils.js")).HoganJsUtils(config);
const result = hoganUtils.render("generic", "empty-diff", { myName: "Rodrigo Fernandes" });
expect("<p>Rodrigo Fernandes</p>").toEqual(result);
});
it("should allow templates to be overridden with uncompiled templates", function() {
const emptyDiffTemplate = "<p>{{myName}}</p>";
const config = { rawTemplates: { "generic-empty-diff": emptyDiffTemplate } };
const hoganUtils = new (require("../hoganjs-utils.js")).HoganJsUtils(config);
const result = hoganUtils.render("generic", "empty-diff", { myName: "Rodrigo Fernandes" });
expect("<p>Rodrigo Fernandes</p>").toEqual(result);
});
it("should allow templates to be overridden giving priority to compiled templates", function() {
const emptyDiffTemplate = HoganJsUtils.compile("<p>{{myName}}</p>");
const emptyDiffTemplateUncompiled = "<p>Not used!</p>";
const config = {
templates: { "generic-empty-diff": emptyDiffTemplate },
rawTemplates: { "generic-empty-diff": emptyDiffTemplateUncompiled }
};
const hoganUtils = new (require("../hoganjs-utils.js")).HoganJsUtils(config);
const result = hoganUtils.render("generic", "empty-diff", { myName: "Rodrigo Fernandes" });
expect("<p>Rodrigo Fernandes</p>").toEqual(result);
});
});
});

View file

@ -1,153 +1,152 @@
var assert = require('assert'); const LineByLinePrinter = require("../line-by-line-printer.js").LineByLinePrinter;
var LineByLinePrinter = require('../src/line-by-line-printer.js').LineByLinePrinter; describe("LineByLinePrinter", function() {
describe("_generateEmptyDiff", function() {
describe('LineByLinePrinter', function() { it("should return an empty diff", function() {
describe('_generateEmptyDiff', function() { const lineByLinePrinter = new LineByLinePrinter({});
it('should return an empty diff', function() { const fileHtml = lineByLinePrinter._generateEmptyDiff();
var lineByLinePrinter = new LineByLinePrinter({}); const expected =
var fileHtml = lineByLinePrinter._generateEmptyDiff(); "<tr>\n" +
var expected = '<tr>\n' +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">\n' + ' <div class="d2h-code-line d2h-info">\n' +
' File without changes\n' + " File without changes\n" +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
}); });
describe('makeLineHtml', function() { describe("makeLineHtml", function() {
it('should work for insertions', function() { it("should work for insertions", function() {
var diffParser = require('../src/diff-parser.js').DiffParser; const diffParser = require("../diff-parser.js").DiffParser;
var lineByLinePrinter = new LineByLinePrinter({}); const lineByLinePrinter = new LineByLinePrinter({});
var fileHtml = lineByLinePrinter.makeLineHtml(false, let fileHtml = lineByLinePrinter.makeLineHtml(false, diffParser.LINE_TYPE.INSERTS, "", 30, "test", "+");
diffParser.LINE_TYPE.INSERTS, '', 30, 'test', '+'); fileHtml = fileHtml.replace(/\n\n+/g, "\n");
fileHtml = fileHtml.replace(/\n\n+/g, '\n'); const expected =
var expected = '<tr>\n' + "<tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' + ' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' + ' <div class="line-num1"></div>\n' +
'<div class="line-num2">30</div>\n' + '<div class="line-num2">30</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' + ' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn">test</span>\n' + ' <span class="d2h-code-line-ctn">test</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
it('should work for deletions', function() { it("should work for deletions", function() {
var diffParser = require('../src/diff-parser.js').DiffParser; const diffParser = require("../diff-parser.js").DiffParser;
var lineByLinePrinter = new LineByLinePrinter({}); const lineByLinePrinter = new LineByLinePrinter({});
var fileHtml = lineByLinePrinter.makeLineHtml(false, let fileHtml = lineByLinePrinter.makeLineHtml(false, diffParser.LINE_TYPE.DELETES, 30, "", "test", "-");
diffParser.LINE_TYPE.DELETES, 30, '', 'test', '-'); fileHtml = fileHtml.replace(/\n\n+/g, "\n");
fileHtml = fileHtml.replace(/\n\n+/g, '\n'); const expected =
var expected = '<tr>\n' + "<tr>\n" +
' <td class="d2h-code-linenumber d2h-del">\n' + ' <td class="d2h-code-linenumber d2h-del">\n' +
' <div class="line-num1">30</div>\n' + ' <div class="line-num1">30</div>\n' +
'<div class="line-num2"></div>\n' + '<div class="line-num2"></div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-del">\n' + ' <td class="d2h-del">\n' +
' <div class="d2h-code-line d2h-del">\n' + ' <div class="d2h-code-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' + ' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn">test</span>\n' + ' <span class="d2h-code-line-ctn">test</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
it('should convert indents into non breakin spaces (2 white spaces)', function() { it("should convert indents into non breakin spaces (2 white spaces)", function() {
var diffParser = require('../src/diff-parser.js').DiffParser; const diffParser = require("../diff-parser.js").DiffParser;
var lineByLinePrinter = new LineByLinePrinter({}); const lineByLinePrinter = new LineByLinePrinter({});
var fileHtml = lineByLinePrinter.makeLineHtml(false, let fileHtml = lineByLinePrinter.makeLineHtml(false, diffParser.LINE_TYPE.INSERTS, "", 30, " test", "+");
diffParser.LINE_TYPE.INSERTS, '', 30, ' test', '+'); fileHtml = fileHtml.replace(/\n\n+/g, "\n");
fileHtml = fileHtml.replace(/\n\n+/g, '\n'); const expected =
var expected = '<tr>\n' + "<tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' + ' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' + ' <div class="line-num1"></div>\n' +
'<div class="line-num2">30</div>\n' + '<div class="line-num2">30</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' + ' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn"> test</span>\n' + ' <span class="d2h-code-line-ctn"> test</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
it('should convert indents into non breakin spaces (4 white spaces)', function() { it("should convert indents into non breakin spaces (4 white spaces)", function() {
var diffParser = require('../src/diff-parser.js').DiffParser; const diffParser = require("../diff-parser.js").DiffParser;
var lineByLinePrinter = new LineByLinePrinter({}); const lineByLinePrinter = new LineByLinePrinter({});
var fileHtml = lineByLinePrinter.makeLineHtml(false, let fileHtml = lineByLinePrinter.makeLineHtml(false, diffParser.LINE_TYPE.INSERTS, "", 30, " test", "+");
diffParser.LINE_TYPE.INSERTS, '', 30, ' test', '+'); fileHtml = fileHtml.replace(/\n\n+/g, "\n");
fileHtml = fileHtml.replace(/\n\n+/g, '\n'); const expected =
var expected = '<tr>\n' + "<tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' + ' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' + ' <div class="line-num1"></div>\n' +
'<div class="line-num2">30</div>\n' + '<div class="line-num2">30</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' + ' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn"> test</span>\n' + ' <span class="d2h-code-line-ctn"> test</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
it('should preserve tabs', function() { it("should preserve tabs", function() {
var diffParser = require('../src/diff-parser.js').DiffParser; const diffParser = require("../diff-parser.js").DiffParser;
var lineByLinePrinter = new LineByLinePrinter({}); const lineByLinePrinter = new LineByLinePrinter({});
var fileHtml = lineByLinePrinter.makeLineHtml(false, let fileHtml = lineByLinePrinter.makeLineHtml(false, diffParser.LINE_TYPE.INSERTS, "", 30, "\ttest", "+");
diffParser.LINE_TYPE.INSERTS, '', 30, '\ttest', '+'); fileHtml = fileHtml.replace(/\n\n+/g, "\n");
fileHtml = fileHtml.replace(/\n\n+/g, '\n'); const expected =
var expected = '<tr>\n' + "<tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' + ' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' + ' <div class="line-num1"></div>\n' +
'' + "" +
'<div class="line-num2">30</div>\n' + '<div class="line-num2">30</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' + ' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn">\ttest</span>\n' + ' <span class="d2h-code-line-ctn">\ttest</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
}); });
describe('makeFileDiffHtml', function() { describe("makeFileDiffHtml", function() {
it('should work for simple file', function() { it("should work for simple file", function() {
var lineByLinePrinter = new LineByLinePrinter({}); const lineByLinePrinter = new LineByLinePrinter({});
var file = { const file = {
addedLines: 12, addedLines: 12,
deletedLines: 41, deletedLines: 41,
language: 'js', language: "js",
oldName: 'my/file/name.js', oldName: "my/file/name.js",
newName: 'my/file/name.js' newName: "my/file/name.js"
}; };
var diffs = '<span>Random Html</span>'; const diffs = "<span>Random Html</span>";
var fileHtml = lineByLinePrinter.makeFileDiffHtml(file, diffs); const fileHtml = lineByLinePrinter.makeFileDiffHtml(file, diffs);
var expected = const expected =
'<div id="d2h-781444" class="d2h-file-wrapper" data-lang="js">\n' + '<div id="d2h-781444" class="d2h-file-wrapper" data-lang="js">\n' +
' <div class="d2h-file-header">\n' + ' <div class="d2h-file-header">\n' +
' <span class="d2h-file-name-wrapper">\n' + ' <span class="d2h-file-name-wrapper">\n' +
@ -155,36 +154,36 @@ describe('LineByLinePrinter', function() {
' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' + ' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' +
' </svg> <span class="d2h-file-name">my/file/name.js</span>\n' + ' </svg> <span class="d2h-file-name">my/file/name.js</span>\n' +
' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' + ' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' +
' </div>\n' + " </div>\n" +
' <div class="d2h-file-diff">\n' + ' <div class="d2h-file-diff">\n' +
' <div class="d2h-code-wrapper">\n' + ' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' + ' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' + ' <tbody class="d2h-diff-tbody">\n' +
' <span>Random Html</span>\n' + " <span>Random Html</span>\n" +
' </tbody>\n' + " </tbody>\n" +
' </table>\n' + " </table>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
'</div>'; "</div>";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
it('should work for simple added file', function() { it("should work for simple added file", function() {
var lineByLinePrinter = new LineByLinePrinter({}); const lineByLinePrinter = new LineByLinePrinter({});
var file = { const file = {
addedLines: 12, addedLines: 12,
deletedLines: 0, deletedLines: 0,
language: 'js', language: "js",
oldName: 'dev/null', oldName: "dev/null",
newName: 'my/file/name.js', newName: "my/file/name.js",
isNew: true isNew: true
}; };
var diffs = '<span>Random Html</span>'; const diffs = "<span>Random Html</span>";
var fileHtml = lineByLinePrinter.makeFileDiffHtml(file, diffs); const fileHtml = lineByLinePrinter.makeFileDiffHtml(file, diffs);
var expected = const expected =
'<div id="d2h-781444" class="d2h-file-wrapper" data-lang="js">\n' + '<div id="d2h-781444" class="d2h-file-wrapper" data-lang="js">\n' +
' <div class="d2h-file-header">\n' + ' <div class="d2h-file-header">\n' +
' <span class="d2h-file-name-wrapper">\n' + ' <span class="d2h-file-name-wrapper">\n' +
@ -192,36 +191,36 @@ describe('LineByLinePrinter', function() {
' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' + ' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' +
' </svg> <span class="d2h-file-name">my/file/name.js</span>\n' + ' </svg> <span class="d2h-file-name">my/file/name.js</span>\n' +
' <span class="d2h-tag d2h-added d2h-added-tag">ADDED</span></span>\n' + ' <span class="d2h-tag d2h-added d2h-added-tag">ADDED</span></span>\n' +
' </div>\n' + " </div>\n" +
' <div class="d2h-file-diff">\n' + ' <div class="d2h-file-diff">\n' +
' <div class="d2h-code-wrapper">\n' + ' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' + ' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' + ' <tbody class="d2h-diff-tbody">\n' +
' <span>Random Html</span>\n' + " <span>Random Html</span>\n" +
' </tbody>\n' + " </tbody>\n" +
' </table>\n' + " </table>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
'</div>'; "</div>";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
it('should work for simple deleted file', function() { it("should work for simple deleted file", function() {
var lineByLinePrinter = new LineByLinePrinter({}); const lineByLinePrinter = new LineByLinePrinter({});
var file = { const file = {
addedLines: 0, addedLines: 0,
deletedLines: 41, deletedLines: 41,
language: 'js', language: "js",
oldName: 'my/file/name.js', oldName: "my/file/name.js",
newName: 'dev/null', newName: "dev/null",
isDeleted: true isDeleted: true
}; };
var diffs = '<span>Random Html</span>'; const diffs = "<span>Random Html</span>";
var fileHtml = lineByLinePrinter.makeFileDiffHtml(file, diffs); const fileHtml = lineByLinePrinter.makeFileDiffHtml(file, diffs);
var expected = const expected =
'<div id="d2h-781444" class="d2h-file-wrapper" data-lang="js">\n' + '<div id="d2h-781444" class="d2h-file-wrapper" data-lang="js">\n' +
' <div class="d2h-file-header">\n' + ' <div class="d2h-file-header">\n' +
' <span class="d2h-file-name-wrapper">\n' + ' <span class="d2h-file-name-wrapper">\n' +
@ -229,36 +228,36 @@ describe('LineByLinePrinter', function() {
' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' + ' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' +
' </svg> <span class="d2h-file-name">my/file/name.js</span>\n' + ' </svg> <span class="d2h-file-name">my/file/name.js</span>\n' +
' <span class="d2h-tag d2h-deleted d2h-deleted-tag">DELETED</span></span>\n' + ' <span class="d2h-tag d2h-deleted d2h-deleted-tag">DELETED</span></span>\n' +
' </div>\n' + " </div>\n" +
' <div class="d2h-file-diff">\n' + ' <div class="d2h-file-diff">\n' +
' <div class="d2h-code-wrapper">\n' + ' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' + ' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' + ' <tbody class="d2h-diff-tbody">\n' +
' <span>Random Html</span>\n' + " <span>Random Html</span>\n" +
' </tbody>\n' + " </tbody>\n" +
' </table>\n' + " </table>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
'</div>'; "</div>";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
it('should work for simple renamed file', function() { it("should work for simple renamed file", function() {
var lineByLinePrinter = new LineByLinePrinter({}); const lineByLinePrinter = new LineByLinePrinter({});
var file = { const file = {
addedLines: 12, addedLines: 12,
deletedLines: 41, deletedLines: 41,
language: 'js', language: "js",
oldName: 'my/file/name1.js', oldName: "my/file/name1.js",
newName: 'my/file/name2.js', newName: "my/file/name2.js",
isRename: true isRename: true
}; };
var diffs = '<span>Random Html</span>'; const diffs = "<span>Random Html</span>";
var fileHtml = lineByLinePrinter.makeFileDiffHtml(file, diffs); const fileHtml = lineByLinePrinter.makeFileDiffHtml(file, diffs);
var expected = const expected =
'<div id="d2h-662683" class="d2h-file-wrapper" data-lang="js">\n' + '<div id="d2h-662683" class="d2h-file-wrapper" data-lang="js">\n' +
' <div class="d2h-file-header">\n' + ' <div class="d2h-file-header">\n' +
' <span class="d2h-file-name-wrapper">\n' + ' <span class="d2h-file-name-wrapper">\n' +
@ -266,93 +265,90 @@ describe('LineByLinePrinter', function() {
' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' + ' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' +
' </svg> <span class="d2h-file-name">my/file/{name1.js → name2.js}</span>\n' + ' </svg> <span class="d2h-file-name">my/file/{name1.js → name2.js}</span>\n' +
' <span class="d2h-tag d2h-moved d2h-moved-tag">RENAMED</span></span>\n' + ' <span class="d2h-tag d2h-moved d2h-moved-tag">RENAMED</span></span>\n' +
' </div>\n' + " </div>\n" +
' <div class="d2h-file-diff">\n' + ' <div class="d2h-file-diff">\n' +
' <div class="d2h-code-wrapper">\n' + ' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' + ' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' + ' <tbody class="d2h-diff-tbody">\n' +
' <span>Random Html</span>\n' + " <span>Random Html</span>\n" +
' </tbody>\n' + " </tbody>\n" +
' </table>\n' + " </table>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
'</div>'; "</div>";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
it('should return empty when option renderNothingWhenEmpty is true and file blocks not present', function() { it("should return empty when option renderNothingWhenEmpty is true and file blocks not present", function() {
var lineByLinePrinter = new LineByLinePrinter({ const lineByLinePrinter = new LineByLinePrinter({
renderNothingWhenEmpty: true renderNothingWhenEmpty: true
}); });
var file = { const file = {
blocks: [] blocks: []
}; };
var diffs = '<span>Random Html</span>'; const diffs = "<span>Random Html</span>";
var fileHtml = lineByLinePrinter.makeFileDiffHtml(file, diffs); const fileHtml = lineByLinePrinter.makeFileDiffHtml(file, diffs);
var expected = ''; const expected = "";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
}); });
describe('makeLineByLineHtmlWrapper', function() { describe("makeLineByLineHtmlWrapper", function() {
it('should work for simple content', function() { it("should work for simple content", function() {
var lineByLinePrinter = new LineByLinePrinter({}); const lineByLinePrinter = new LineByLinePrinter({});
var fileHtml = lineByLinePrinter.makeLineByLineHtmlWrapper('<span>Random Html</span>'); const fileHtml = lineByLinePrinter.makeLineByLineHtmlWrapper("<span>Random Html</span>");
var expected = const expected = '<div class="d2h-wrapper">\n' + " <span>Random Html</span>\n" + "</div>";
'<div class="d2h-wrapper">\n' +
' <span>Random Html</span>\n' +
'</div>';
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
}); });
describe('generateLineByLineJsonHtml', function() { describe("generateLineByLineJsonHtml", function() {
it('should work for list of files', function() { it("should work for list of files", function() {
var exampleJson = [ const exampleJson = [
{ {
blocks: [ blocks: [
{ {
lines: [ lines: [
{ {
content: '-test', content: "-test",
type: 'd2h-del', type: "d2h-del",
oldNumber: 1, oldNumber: 1,
newNumber: null newNumber: null
}, },
{ {
content: '+test1r', content: "+test1r",
type: 'd2h-ins', type: "d2h-ins",
oldNumber: null, oldNumber: null,
newNumber: 1 newNumber: 1
} }
], ],
oldStartLine: '1', oldStartLine: "1",
oldStartLine2: null, oldStartLine2: null,
newStartLine: '1', newStartLine: "1",
header: '@@ -1 +1 @@' header: "@@ -1 +1 @@"
} }
], ],
deletedLines: 1, deletedLines: 1,
addedLines: 1, addedLines: 1,
checksumBefore: '0000001', checksumBefore: "0000001",
checksumAfter: '0ddf2ba', checksumAfter: "0ddf2ba",
oldName: 'sample', oldName: "sample",
language: undefined, language: undefined,
newName: 'sample', newName: "sample",
isCombined: false isCombined: false
} }
]; ];
var lineByLinePrinter = new LineByLinePrinter({matching: 'lines'}); const lineByLinePrinter = new LineByLinePrinter({ matching: "lines" });
var html = lineByLinePrinter.generateLineByLineJsonHtml(exampleJson); const html = lineByLinePrinter.generateLineByLineJsonHtml(exampleJson);
var expected = const expected =
'<div class="d2h-wrapper">\n' + '<div class="d2h-wrapper">\n' +
' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="">\n' + ' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="">\n' +
' <div class="d2h-file-header">\n' + ' <div class="d2h-file-header">\n' +
@ -361,63 +357,65 @@ describe('LineByLinePrinter', function() {
' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' + ' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' +
' </svg> <span class="d2h-file-name">sample</span>\n' + ' </svg> <span class="d2h-file-name">sample</span>\n' +
' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' + ' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' +
' </div>\n' + " </div>\n" +
' <div class="d2h-file-diff">\n' + ' <div class="d2h-file-diff">\n' +
' <div class="d2h-code-wrapper">\n' + ' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' + ' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' + ' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' + " <tr>\n" +
' <td class="d2h-code-linenumber d2h-info"></td>\n' + ' <td class="d2h-code-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">@@ -1 +1 @@</div>\n' + ' <div class="d2h-code-line d2h-info">@@ -1 +1 @@</div>\n' +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-del">\n' + ' <td class="d2h-code-linenumber d2h-del">\n' +
' <div class="line-num1">1</div>\n' + ' <div class="line-num1">1</div>\n' +
'<div class="line-num2"></div>\n' + '<div class="line-num2"></div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-del">\n' + ' <td class="d2h-del">\n' +
' <div class="d2h-code-line d2h-del">\n' + ' <div class="d2h-code-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' + ' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn"><del>test</del></span>\n' + ' <span class="d2h-code-line-ctn"><del>test</del></span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' + ' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' + ' <div class="line-num1"></div>\n' +
'<div class="line-num2">1</div>\n' + '<div class="line-num2">1</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' + ' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn"><ins>test1r</ins></span>\n' + ' <span class="d2h-code-line-ctn"><ins>test1r</ins></span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>\n' + "</tr>\n" +
' </tbody>\n' + " </tbody>\n" +
' </table>\n' + " </table>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
'</div>\n' + "</div>\n" +
'</div>'; "</div>";
assert.equal(expected, html); expect(expected).toEqual(html);
}); });
it('should work for empty blocks', function() { it("should work for empty blocks", function() {
var exampleJson = [{ const exampleJson = [
{
blocks: [], blocks: [],
deletedLines: 0, deletedLines: 0,
addedLines: 0, addedLines: 0,
oldName: 'sample', oldName: "sample",
language: 'js', language: "js",
newName: 'sample', newName: "sample",
isCombined: false isCombined: false
}]; }
];
var lineByLinePrinter = new LineByLinePrinter({ renderNothingWhenEmpty: false }); const lineByLinePrinter = new LineByLinePrinter({ renderNothingWhenEmpty: false });
var html = lineByLinePrinter.generateLineByLineJsonHtml(exampleJson); const html = lineByLinePrinter.generateLineByLineJsonHtml(exampleJson);
var expected = const expected =
'<div class="d2h-wrapper">\n' + '<div class="d2h-wrapper">\n' +
' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">\n' + ' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">\n' +
' <div class="d2h-file-header">\n' + ' <div class="d2h-file-header">\n' +
@ -426,179 +424,183 @@ describe('LineByLinePrinter', function() {
' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' + ' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' +
' </svg> <span class="d2h-file-name">sample</span>\n' + ' </svg> <span class="d2h-file-name">sample</span>\n' +
' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' + ' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' +
' </div>\n' + " </div>\n" +
' <div class="d2h-file-diff">\n' + ' <div class="d2h-file-diff">\n' +
' <div class="d2h-code-wrapper">\n' + ' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' + ' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' + ' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' + " <tr>\n" +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">\n' + ' <div class="d2h-code-line d2h-info">\n' +
' File without changes\n' + " File without changes\n" +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>\n' + "</tr>\n" +
' </tbody>\n' + " </tbody>\n" +
' </table>\n' + " </table>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
'</div>\n' + "</div>\n" +
'</div>'; "</div>";
assert.equal(expected, html); expect(expected).toEqual(html);
}); });
}); });
describe('_processLines', function() { describe("_processLines", function() {
it('should work for simple block header', function() { it("should work for simple block header", function() {
var lineByLinePrinter = new LineByLinePrinter({}); const lineByLinePrinter = new LineByLinePrinter({});
var oldLines = [{ const oldLines = [
content: '-test', {
type: 'd2h-del', content: "-test",
type: "d2h-del",
oldNumber: 1, oldNumber: 1,
newNumber: null newNumber: null
}]; }
var newLines = [{ ];
content: '+test1r', const newLines = [
type: 'd2h-ins', {
content: "+test1r",
type: "d2h-ins",
oldNumber: null, oldNumber: null,
newNumber: 1 newNumber: 1
}]; }
];
var html = lineByLinePrinter._processLines(false, oldLines, newLines); const html = lineByLinePrinter._processLines(false, oldLines, newLines);
var expected = const expected =
'<tr>\n' + "<tr>\n" +
' <td class="d2h-code-linenumber d2h-del">\n' + ' <td class="d2h-code-linenumber d2h-del">\n' +
' <div class="line-num1">1</div>\n' + ' <div class="line-num1">1</div>\n' +
'<div class="line-num2"></div>\n' + '<div class="line-num2"></div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-del">\n' + ' <td class="d2h-del">\n' +
' <div class="d2h-code-line d2h-del">\n' + ' <div class="d2h-code-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' + ' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn">test</span>\n' + ' <span class="d2h-code-line-ctn">test</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' + ' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' + ' <div class="line-num1"></div>\n' +
'<div class="line-num2">1</div>\n' + '<div class="line-num2">1</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' + ' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn">test1r</span>\n' + ' <span class="d2h-code-line-ctn">test1r</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
assert.equal(expected, html); expect(expected).toEqual(html);
}); });
}); });
describe('_generateFileHtml', function() { describe("_generateFileHtml", function() {
it('should work for simple file', function() { it("should work for simple file", function() {
var lineByLinePrinter = new LineByLinePrinter({}); const lineByLinePrinter = new LineByLinePrinter({});
var file = { const file = {
blocks: [ blocks: [
{ {
lines: [ lines: [
{ {
content: ' one context line', content: " one context line",
type: 'd2h-cntx', type: "d2h-cntx",
oldNumber: 1, oldNumber: 1,
newNumber: 1 newNumber: 1
}, },
{ {
content: '-test', content: "-test",
type: 'd2h-del', type: "d2h-del",
oldNumber: 2, oldNumber: 2,
newNumber: null newNumber: null
}, },
{ {
content: '+test1r', content: "+test1r",
type: 'd2h-ins', type: "d2h-ins",
oldNumber: null, oldNumber: null,
newNumber: 2 newNumber: 2
}, },
{ {
content: '+test2r', content: "+test2r",
type: 'd2h-ins', type: "d2h-ins",
oldNumber: null, oldNumber: null,
newNumber: 3 newNumber: 3
} }
], ],
oldStartLine: '1', oldStartLine: "1",
oldStartLine2: null, oldStartLine2: null,
newStartLine: '1', newStartLine: "1",
header: '@@ -1 +1 @@' header: "@@ -1 +1 @@"
} }
], ],
deletedLines: 1, deletedLines: 1,
addedLines: 1, addedLines: 1,
checksumBefore: '0000001', checksumBefore: "0000001",
checksumAfter: '0ddf2ba', checksumAfter: "0ddf2ba",
oldName: 'sample', oldName: "sample",
language: undefined, language: undefined,
newName: 'sample', newName: "sample",
isCombined: false isCombined: false
}; };
var html = lineByLinePrinter._generateFileHtml(file); const html = lineByLinePrinter._generateFileHtml(file);
var expected = const expected =
'<tr>\n' + "<tr>\n" +
' <td class="d2h-code-linenumber d2h-info"></td>\n' + ' <td class="d2h-code-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">@@ -1 +1 @@</div>\n' + ' <div class="d2h-code-line d2h-info">@@ -1 +1 @@</div>\n' +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' + ' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">1</div>\n' + ' <div class="line-num1">1</div>\n' +
'<div class="line-num2">1</div>\n' + '<div class="line-num2">1</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' + ' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn">one context line</span>\n' + ' <span class="d2h-code-line-ctn">one context line</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-del">\n' + ' <td class="d2h-code-linenumber d2h-del">\n' +
' <div class="line-num1">2</div>\n' + ' <div class="line-num1">2</div>\n' +
'<div class="line-num2"></div>\n' + '<div class="line-num2"></div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-del">\n' + ' <td class="d2h-del">\n' +
' <div class="d2h-code-line d2h-del">\n' + ' <div class="d2h-code-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' + ' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn"><del>test</del></span>\n' + ' <span class="d2h-code-line-ctn"><del>test</del></span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' + ' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' + ' <div class="line-num1"></div>\n' +
'<div class="line-num2">2</div>\n' + '<div class="line-num2">2</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' + ' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn"><ins>test1r</ins></span>\n' + ' <span class="d2h-code-line-ctn"><ins>test1r</ins></span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' + ' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' + ' <div class="line-num1"></div>\n' +
'<div class="line-num2">3</div>\n' + '<div class="line-num2">3</div>\n' +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' + ' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn">test2r</span>\n' + ' <span class="d2h-code-line-ctn">test2r</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
assert.equal(expected, html); expect(expected).toEqual(html);
}); });
}); });
}); });

View file

@ -0,0 +1,126 @@
const PrinterUtils = require("../printer-utils.js").PrinterUtils;
describe("Utils", function() {
describe("getHtmlId", function() {
it("should generate file unique id", function() {
const result = PrinterUtils.getHtmlId({
oldName: "sample.js",
newName: "sample.js"
});
expect("d2h-960013").toEqual(result);
});
it("should generate file unique id for empty hashes", function() {
const result = PrinterUtils.getHtmlId({
oldName: "sample.js",
newName: "sample.js"
});
expect("d2h-960013").toEqual(result);
});
});
describe("getDiffName", function() {
it("should generate the file name for a changed file", function() {
const result = PrinterUtils.getDiffName({
oldName: "sample.js",
newName: "sample.js"
});
expect("sample.js").toEqual(result);
});
it("should generate the file name for a changed file and full rename", function() {
const result = PrinterUtils.getDiffName({
oldName: "sample1.js",
newName: "sample2.js"
});
expect("sample1.js → sample2.js").toEqual(result);
});
it("should generate the file name for a changed file and prefix rename", function() {
const result = PrinterUtils.getDiffName({
oldName: "src/path/sample.js",
newName: "source/path/sample.js"
});
expect("{src → source}/path/sample.js").toEqual(result);
});
it("should generate the file name for a changed file and suffix rename", function() {
const result = PrinterUtils.getDiffName({
oldName: "src/path/sample1.js",
newName: "src/path/sample2.js"
});
expect("src/path/{sample1.js → sample2.js}").toEqual(result);
});
it("should generate the file name for a changed file and middle rename", function() {
const result = PrinterUtils.getDiffName({
oldName: "src/really/big/path/sample.js",
newName: "src/small/path/sample.js"
});
expect("src/{really/big → small}/path/sample.js").toEqual(result);
});
it("should generate the file name for a deleted file", function() {
const result = PrinterUtils.getDiffName({
oldName: "src/my/file.js",
newName: "/dev/null"
});
expect("src/my/file.js").toEqual(result);
});
it("should generate the file name for a new file", function() {
const result = PrinterUtils.getDiffName({
oldName: "/dev/null",
newName: "src/my/file.js"
});
expect("src/my/file.js").toEqual(result);
});
it("should generate handle undefined filename", function() {
const result = PrinterUtils.getDiffName({});
expect("unknown/file/path").toEqual(result);
});
});
describe("diffHighlight", function() {
it("should highlight two lines", function() {
const result = PrinterUtils.diffHighlight("-var myVar = 2;", "+var myVariable = 3;", { matching: "words" });
expect({
first: {
prefix: "-",
line: "var <del>myVar</del> = <del>2</del>;"
},
second: {
prefix: "+",
line: "var <ins>myVariable</ins> = <ins>3</ins>;"
}
}).toEqual(result);
});
it("should highlight two lines char by char", function() {
const result = PrinterUtils.diffHighlight("-var myVar = 2;", "+var myVariable = 3;", { diffStyle: "char" });
expect({
first: {
prefix: "-",
line: "var myVar = <del>2</del>;"
},
second: {
prefix: "+",
line: "var myVar<ins>iable</ins> = <ins>3</ins>;"
}
}).toEqual(result);
});
it("should highlight combined diff lines", function() {
const result = PrinterUtils.diffHighlight(" -var myVar = 2;", " +var myVariable = 3;", {
diffStyle: "word",
isCombined: true,
matching: "words",
matchWordsThreshold: 1.0
});
expect({
first: {
prefix: " -",
line: 'var <del class="d2h-change">myVar</del> = <del class="d2h-change">2</del>;'
},
second: {
prefix: " +",
line: 'var <ins class="d2h-change">myVariable</ins> = <ins class="d2h-change">3</ins>;'
}
}).toEqual(result);
});
});
});

View file

@ -1,240 +1,239 @@
var assert = require('assert'); const SideBySidePrinter = require("../side-by-side-printer.js").SideBySidePrinter;
var SideBySidePrinter = require('../src/side-by-side-printer.js').SideBySidePrinter; describe("SideBySidePrinter", function() {
describe("generateEmptyDiff", function() {
describe('SideBySidePrinter', function() { it("should return an empty diff", function() {
describe('generateEmptyDiff', function() { const sideBySidePrinter = new SideBySidePrinter({});
it('should return an empty diff', function() { const fileHtml = sideBySidePrinter.generateEmptyDiff();
var sideBySidePrinter = new SideBySidePrinter({}); const expectedRight = "";
var fileHtml = sideBySidePrinter.generateEmptyDiff(); const expectedLeft =
var expectedRight = ''; "<tr>\n" +
var expectedLeft = '<tr>\n' +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info">\n' + ' <div class="d2h-code-side-line d2h-info">\n' +
' File without changes\n' + " File without changes\n" +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
assert.equal(expectedRight, fileHtml.right); expect(expectedRight).toEqual(fileHtml.right);
assert.equal(expectedLeft, fileHtml.left); expect(expectedLeft).toEqual(fileHtml.left);
}); });
}); });
describe('generateSideBySideFileHtml', function() { describe("generateSideBySideFileHtml", function() {
it('should generate lines with the right prefixes', function() { it("should generate lines with the right prefixes", function() {
var sideBySidePrinter = new SideBySidePrinter({}); const sideBySidePrinter = new SideBySidePrinter({});
var file = { const file = {
'blocks': [ blocks: [
{ {
'lines': [ lines: [
{ {
'content': ' context', content: " context",
'type': 'd2h-cntx', type: "d2h-cntx",
'oldNumber': 19, oldNumber: 19,
'newNumber': 19 newNumber: 19
}, },
{ {
'content': '-removed', content: "-removed",
'type': 'd2h-del', type: "d2h-del",
'oldNumber': 20, oldNumber: 20,
'newNumber': null newNumber: null
}, },
{ {
'content': '+added', content: "+added",
'type': 'd2h-ins', type: "d2h-ins",
'oldNumber': null, oldNumber: null,
'newNumber': 20 newNumber: 20
}, },
{ {
'content': '+another added', content: "+another added",
'type': 'd2h-ins', type: "d2h-ins",
'oldNumber': null, oldNumber: null,
'newNumber': 21 newNumber: 21
} }
], ],
'oldStartLine': '19', oldStartLine: "19",
'newStartLine': '19', newStartLine: "19",
'header': '@@ -19,7 +19,7 @@' header: "@@ -19,7 +19,7 @@"
} }
], ],
'deletedLines': 1, deletedLines: 1,
'addedLines': 1, addedLines: 1,
'checksumBefore': 'fc56817', checksumBefore: "fc56817",
'checksumAfter': 'e8e7e49', checksumAfter: "e8e7e49",
'mode': '100644', mode: "100644",
'oldName': 'coverage.init', oldName: "coverage.init",
'language': 'init', language: "init",
'newName': 'coverage.init', newName: "coverage.init",
'isCombined': false isCombined: false
}; };
var fileHtml = sideBySidePrinter.generateSideBySideFileHtml(file); const fileHtml = sideBySidePrinter.generateSideBySideFileHtml(file);
var expectedLeft = const expectedLeft =
'<tr>\n' + "<tr>\n" +
' <td class="d2h-code-side-linenumber d2h-info"></td>\n' + ' <td class="d2h-code-side-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info">@@ -19,7 +19,7 @@</div>\n' + ' <div class="d2h-code-side-line d2h-info">@@ -19,7 +19,7 @@</div>\n' +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-cntx">\n' + ' <td class="d2h-code-side-linenumber d2h-cntx">\n' +
' 19\n' + " 19\n" +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-side-line d2h-cntx">\n' + ' <div class="d2h-code-side-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn">context</span>\n' + ' <span class="d2h-code-line-ctn">context</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-del">\n' + ' <td class="d2h-code-side-linenumber d2h-del">\n' +
' 20\n' + " 20\n" +
' </td>\n' + " </td>\n" +
' <td class="d2h-del">\n' + ' <td class="d2h-del">\n' +
' <div class="d2h-code-side-line d2h-del">\n' + ' <div class="d2h-code-side-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' + ' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn"><del>removed</del></span>\n' + ' <span class="d2h-code-line-ctn"><del>removed</del></span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">\n' + ' <td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">\n' +
' ' + " " +
'\n' + "\n" +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx d2h-emptyplaceholder">\n' + ' <td class="d2h-cntx d2h-emptyplaceholder">\n' +
' <div class="d2h-code-side-line d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">\n' + ' <div class="d2h-code-side-line d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn">&nbsp;</span>\n' + ' <span class="d2h-code-line-ctn">&nbsp;</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
var expectedRight = const expectedRight =
'<tr>\n' + "<tr>\n" +
' <td class="d2h-code-side-linenumber d2h-info"></td>\n' + ' <td class="d2h-code-side-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info"></div>\n' + ' <div class="d2h-code-side-line d2h-info"></div>\n' +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-cntx">\n' + ' <td class="d2h-code-side-linenumber d2h-cntx">\n' +
' 19\n' + " 19\n" +
' </td>\n' + " </td>\n" +
' <td class="d2h-cntx">\n' + ' <td class="d2h-cntx">\n' +
' <div class="d2h-code-side-line d2h-cntx">\n' + ' <div class="d2h-code-side-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' + ' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' <span class="d2h-code-line-ctn">context</span>\n' + ' <span class="d2h-code-line-ctn">context</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-ins">\n' + ' <td class="d2h-code-side-linenumber d2h-ins">\n' +
' 20\n' + " 20\n" +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-side-line d2h-ins">\n' + ' <div class="d2h-code-side-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn"><ins>added</ins></span>\n' + ' <span class="d2h-code-line-ctn"><ins>added</ins></span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-ins">\n' + ' <td class="d2h-code-side-linenumber d2h-ins">\n' +
' 21\n' + " 21\n" +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-side-line d2h-ins">\n' + ' <div class="d2h-code-side-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn">another added</span>\n' + ' <span class="d2h-code-line-ctn">another added</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
assert.equal(expectedLeft, fileHtml.left); expect(expectedLeft).toEqual(fileHtml.left);
assert.equal(expectedRight, fileHtml.right); expect(expectedRight).toEqual(fileHtml.right);
}); });
}); });
describe('generateSingleLineHtml', function() { describe("generateSingleLineHtml", function() {
it('should work for insertions', function() { it("should work for insertions", function() {
var diffParser = require('../src/diff-parser.js').DiffParser; const diffParser = require("../diff-parser.js").DiffParser;
var sideBySidePrinter = new SideBySidePrinter({}); const sideBySidePrinter = new SideBySidePrinter({});
var fileHtml = sideBySidePrinter.generateSingleLineHtml(false, const fileHtml = sideBySidePrinter.generateSingleLineHtml(false, diffParser.LINE_TYPE.INSERTS, 30, "test", "+");
diffParser.LINE_TYPE.INSERTS, 30, 'test', '+'); const expected =
var expected = '<tr>\n' + "<tr>\n" +
' <td class="d2h-code-side-linenumber d2h-ins">\n' + ' <td class="d2h-code-side-linenumber d2h-ins">\n' +
' 30\n' + " 30\n" +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-side-line d2h-ins">\n' + ' <div class="d2h-code-side-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn">test</span>\n' + ' <span class="d2h-code-line-ctn">test</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
it('should work for deletions', function() { it("should work for deletions", function() {
var diffParser = require('../src/diff-parser.js').DiffParser; const diffParser = require("../diff-parser.js").DiffParser;
var sideBySidePrinter = new SideBySidePrinter({}); const sideBySidePrinter = new SideBySidePrinter({});
var fileHtml = sideBySidePrinter.generateSingleLineHtml(false, const fileHtml = sideBySidePrinter.generateSingleLineHtml(false, diffParser.LINE_TYPE.DELETES, 30, "test", "-");
diffParser.LINE_TYPE.DELETES, 30, 'test', '-'); const expected =
var expected = '<tr>\n' + "<tr>\n" +
' <td class="d2h-code-side-linenumber d2h-del">\n' + ' <td class="d2h-code-side-linenumber d2h-del">\n' +
' 30\n' + " 30\n" +
' </td>\n' + " </td>\n" +
' <td class="d2h-del">\n' + ' <td class="d2h-del">\n' +
' <div class="d2h-code-side-line d2h-del">\n' + ' <div class="d2h-code-side-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' + ' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn">test</span>\n' + ' <span class="d2h-code-line-ctn">test</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
assert.equal(expected, fileHtml); expect(expected).toEqual(fileHtml);
}); });
}); });
describe('generateSideBySideJsonHtml', function() { describe("generateSideBySideJsonHtml", function() {
it('should work for list of files', function() { it("should work for list of files", function() {
var exampleJson = [ const exampleJson = [
{ {
blocks: [ blocks: [
{ {
lines: [ lines: [
{ {
content: '-test', content: "-test",
type: 'd2h-del', type: "d2h-del",
oldNumber: 1, oldNumber: 1,
newNumber: null newNumber: null
}, },
{ {
content: '+test1r', content: "+test1r",
type: 'd2h-ins', type: "d2h-ins",
oldNumber: null, oldNumber: null,
newNumber: 1 newNumber: 1
} }
], ],
oldStartLine: '1', oldStartLine: "1",
oldStartLine2: null, oldStartLine2: null,
newStartLine: '1', newStartLine: "1",
header: '@@ -1 +1 @@' header: "@@ -1 +1 @@"
} }
], ],
deletedLines: 1, deletedLines: 1,
addedLines: 1, addedLines: 1,
checksumBefore: '0000001', checksumBefore: "0000001",
checksumAfter: '0ddf2ba', checksumAfter: "0ddf2ba",
oldName: 'sample', oldName: "sample",
language: undefined, language: undefined,
newName: 'sample', newName: "sample",
isCombined: false isCombined: false
} }
]; ];
var sideBySidePrinter = new SideBySidePrinter({matching: 'lines'}); const sideBySidePrinter = new SideBySidePrinter({ matching: "lines" });
var html = sideBySidePrinter.generateSideBySideJsonHtml(exampleJson); const html = sideBySidePrinter.generateSideBySideJsonHtml(exampleJson);
var expected = const expected =
'<div class="d2h-wrapper">\n' + '<div class="d2h-wrapper">\n' +
' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="">\n' + ' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="">\n' +
' <div class="d2h-file-header">\n' + ' <div class="d2h-file-header">\n' +
@ -243,74 +242,76 @@ describe('SideBySidePrinter', function() {
' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' + ' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' +
' </svg> <span class="d2h-file-name">sample</span>\n' + ' </svg> <span class="d2h-file-name">sample</span>\n' +
' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' + ' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' +
' </div>\n' + " </div>\n" +
' <div class="d2h-files-diff">\n' + ' <div class="d2h-files-diff">\n' +
' <div class="d2h-file-side-diff">\n' + ' <div class="d2h-file-side-diff">\n' +
' <div class="d2h-code-wrapper">\n' + ' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' + ' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' + ' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' + " <tr>\n" +
' <td class="d2h-code-side-linenumber d2h-info"></td>\n' + ' <td class="d2h-code-side-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info">@@ -1 +1 @@</div>\n' + ' <div class="d2h-code-side-line d2h-info">@@ -1 +1 @@</div>\n' +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-del">\n' + ' <td class="d2h-code-side-linenumber d2h-del">\n' +
' 1\n' + " 1\n" +
' </td>\n' + " </td>\n" +
' <td class="d2h-del">\n' + ' <td class="d2h-del">\n' +
' <div class="d2h-code-side-line d2h-del">\n' + ' <div class="d2h-code-side-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' + ' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn"><del>test</del></span>\n' + ' <span class="d2h-code-line-ctn"><del>test</del></span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>\n' + "</tr>\n" +
' </tbody>\n' + " </tbody>\n" +
' </table>\n' + " </table>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
' <div class="d2h-file-side-diff">\n' + ' <div class="d2h-file-side-diff">\n' +
' <div class="d2h-code-wrapper">\n' + ' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' + ' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' + ' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' + " <tr>\n" +
' <td class="d2h-code-side-linenumber d2h-info"></td>\n' + ' <td class="d2h-code-side-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info"></div>\n' + ' <div class="d2h-code-side-line d2h-info"></div>\n' +
' </td>\n' + " </td>\n" +
'</tr><tr>\n' + "</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-ins">\n' + ' <td class="d2h-code-side-linenumber d2h-ins">\n' +
' 1\n' + " 1\n" +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-side-line d2h-ins">\n' + ' <div class="d2h-code-side-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn"><ins>test1r</ins></span>\n' + ' <span class="d2h-code-line-ctn"><ins>test1r</ins></span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>\n' + "</tr>\n" +
' </tbody>\n' + " </tbody>\n" +
' </table>\n' + " </table>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
'</div>\n' + "</div>\n" +
'</div>'; "</div>";
assert.equal(expected, html); expect(expected).toEqual(html);
}); });
it('should work for files without blocks', function() { it("should work for files without blocks", function() {
var exampleJson = [{ const exampleJson = [
{
blocks: [], blocks: [],
oldName: 'sample', oldName: "sample",
language: 'js', language: "js",
newName: 'sample', newName: "sample",
isCombined: false isCombined: false
}]; }
];
var sideBySidePrinter = new SideBySidePrinter(); const sideBySidePrinter = new SideBySidePrinter();
var html = sideBySidePrinter.generateSideBySideJsonHtml(exampleJson); const html = sideBySidePrinter.generateSideBySideJsonHtml(exampleJson);
var expected = const expected =
'<div class="d2h-wrapper">\n' + '<div class="d2h-wrapper">\n' +
' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">\n' + ' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">\n' +
' <div class="d2h-file-header">\n' + ' <div class="d2h-file-header">\n' +
@ -319,86 +320,90 @@ describe('SideBySidePrinter', function() {
' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' + ' <path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>\n' +
' </svg> <span class="d2h-file-name">sample</span>\n' + ' </svg> <span class="d2h-file-name">sample</span>\n' +
' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' + ' <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>\n' +
' </div>\n' + " </div>\n" +
' <div class="d2h-files-diff">\n' + ' <div class="d2h-files-diff">\n' +
' <div class="d2h-file-side-diff">\n' + ' <div class="d2h-file-side-diff">\n' +
' <div class="d2h-code-wrapper">\n' + ' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' + ' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' + ' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' + " <tr>\n" +
' <td class="d2h-info">\n' + ' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info">\n' + ' <div class="d2h-code-side-line d2h-info">\n' +
' File without changes\n' + " File without changes\n" +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>\n' + "</tr>\n" +
' </tbody>\n' + " </tbody>\n" +
' </table>\n' + " </table>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
' <div class="d2h-file-side-diff">\n' + ' <div class="d2h-file-side-diff">\n' +
' <div class="d2h-code-wrapper">\n' + ' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' + ' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' + ' <tbody class="d2h-diff-tbody">\n' +
' \n' + " \n" +
' </tbody>\n' + " </tbody>\n" +
' </table>\n' + " </table>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
' </div>\n' + " </div>\n" +
'</div>\n' + "</div>\n" +
'</div>'; "</div>";
assert.equal(expected, html); expect(expected).toEqual(html);
}); });
}); });
describe('processLines', function() { describe("processLines", function() {
it('should process file lines', function() { it("should process file lines", function() {
var oldLines = [{ const oldLines = [
content: '-test', {
type: 'd2h-del', content: "-test",
type: "d2h-del",
oldNumber: 1, oldNumber: 1,
newNumber: null newNumber: null
}]; }
];
var newLines = [{ const newLines = [
content: '+test1r', {
type: 'd2h-ins', content: "+test1r",
type: "d2h-ins",
oldNumber: null, oldNumber: null,
newNumber: 1 newNumber: 1
}]; }
];
var sideBySidePrinter = new SideBySidePrinter({matching: 'lines'}); const sideBySidePrinter = new SideBySidePrinter({ matching: "lines" });
var html = sideBySidePrinter.processLines(false, oldLines, newLines); const html = sideBySidePrinter.processLines(false, oldLines, newLines);
var expectedLeft = const expectedLeft =
'<tr>\n' + "<tr>\n" +
' <td class="d2h-code-side-linenumber d2h-del">\n' + ' <td class="d2h-code-side-linenumber d2h-del">\n' +
' 1\n' + " 1\n" +
' </td>\n' + " </td>\n" +
' <td class="d2h-del">\n' + ' <td class="d2h-del">\n' +
' <div class="d2h-code-side-line d2h-del">\n' + ' <div class="d2h-code-side-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' + ' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn">test</span>\n' + ' <span class="d2h-code-line-ctn">test</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
var expectedRight = const expectedRight =
'<tr>\n' + "<tr>\n" +
' <td class="d2h-code-side-linenumber d2h-ins">\n' + ' <td class="d2h-code-side-linenumber d2h-ins">\n' +
' 1\n' + " 1\n" +
' </td>\n' + " </td>\n" +
' <td class="d2h-ins">\n' + ' <td class="d2h-ins">\n' +
' <div class="d2h-code-side-line d2h-ins">\n' + ' <div class="d2h-code-side-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' + ' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn">test1r</span>\n' + ' <span class="d2h-code-line-ctn">test1r</span>\n' +
' </div>\n' + " </div>\n" +
' </td>\n' + " </td>\n" +
'</tr>'; "</tr>";
assert.equal(expectedLeft, html.left); expect(expectedLeft).toEqual(html.left);
assert.equal(expectedRight, html.right); expect(expectedRight).toEqual(html.right);
}); });
}); });
}); });

View file

@ -0,0 +1,23 @@
const Utils = require("../utils.js").Utils;
describe("Utils", function() {
describe("escape", function() {
it("should escape & with &amp;", function() {
const result = Utils.escape("&");
expect("&amp;").toEqual(result);
});
it("should escape < with &lt;", function() {
const result = Utils.escape("<");
expect("&lt;").toEqual(result);
});
it("should escape > with &gt;", function() {
const result = Utils.escape(">");
expect("&gt;").toEqual(result);
});
it("should escape a string with multiple problematic characters", function() {
const result = Utils.escape('<a href="#">\tlink text</a>');
const expected = "&lt;a href=&quot;#&quot;&gt;\tlink text&lt;&#x2F;a&gt;";
expect(expected).toEqual(result);
});
});
});

View file

@ -6,39 +6,38 @@
*/ */
(function() { (function() {
var utils = require('./utils.js').Utils; const utils = require("./utils.js").Utils;
var LINE_TYPE = { const LINE_TYPE = {
INSERTS: 'd2h-ins', INSERTS: "d2h-ins",
DELETES: 'd2h-del', DELETES: "d2h-del",
INSERT_CHANGES: 'd2h-ins d2h-change', INSERT_CHANGES: "d2h-ins d2h-change",
DELETE_CHANGES: 'd2h-del d2h-change', DELETE_CHANGES: "d2h-del d2h-change",
CONTEXT: 'd2h-cntx', CONTEXT: "d2h-cntx",
INFO: 'd2h-info' INFO: "d2h-info"
}; };
function DiffParser() { function DiffParser() {}
}
DiffParser.prototype.LINE_TYPE = LINE_TYPE; DiffParser.prototype.LINE_TYPE = LINE_TYPE;
DiffParser.prototype.generateDiffJson = function(diffInput, configuration) { DiffParser.prototype.generateDiffJson = function(diffInput, configuration) {
var config = configuration || {}; const config = configuration || {};
var files = []; const files = [];
var currentFile = null; let currentFile = null;
var currentBlock = null; let currentBlock = null;
var oldLine = null; let oldLine = null;
var oldLine2 = null; // Used for combined diff let oldLine2 = null; // Used for combined diff
var newLine = null; let newLine = null;
var possibleOldName; let possibleOldName;
var possibleNewName; let possibleNewName;
/* Diff Header */ /* Diff Header */
var oldFileNameHeader = '--- '; const oldFileNameHeader = "--- ";
var newFileNameHeader = '+++ '; const newFileNameHeader = "+++ ";
var hunkHeaderPrefix = '@@'; const hunkHeaderPrefix = "@@";
/* Add previous block(if exists) before start a new file */ /* Add previous block(if exists) before start a new file */
function saveBlock() { function saveBlock() {
@ -86,7 +85,7 @@
function startBlock(line) { function startBlock(line) {
saveBlock(); saveBlock();
var values; let values;
/** /**
* From Range: * From Range:
@ -113,7 +112,7 @@
newLine = values[3]; newLine = values[3];
} else { } else {
if (utils.startsWith(line, hunkHeaderPrefix)) { if (utils.startsWith(line, hunkHeaderPrefix)) {
console.error('Failed to parse lines, starting in 0!'); console.error("Failed to parse lines, starting in 0!");
} }
oldLine = 0; oldLine = 0;
@ -131,11 +130,11 @@
} }
function createLine(line) { function createLine(line) {
var currentLine = {}; const currentLine = {};
currentLine.content = line; currentLine.content = line;
var newLinePrefixes = !currentFile.isCombined ? ['+'] : ['+', ' +']; const newLinePrefixes = !currentFile.isCombined ? ["+"] : ["+", " +"];
var delLinePrefixes = !currentFile.isCombined ? ['-'] : ['-', ' -']; const delLinePrefixes = !currentFile.isCombined ? ["-"] : ["-", " -"];
/* Fill the line data */ /* Fill the line data */
if (utils.startsWith(line, newLinePrefixes)) { if (utils.startsWith(line, newLinePrefixes)) {
@ -169,10 +168,10 @@
* Hunk header is a group of three lines started by ( `--- ` , `+++ ` , `@@` ) * Hunk header is a group of three lines started by ( `--- ` , `+++ ` , `@@` )
*/ */
function existHunkHeader(line, lineIdx) { function existHunkHeader(line, lineIdx) {
var idx = lineIdx; let idx = lineIdx;
while (idx < diffLines.length - 3) { while (idx < diffLines.length - 3) {
if (utils.startsWith(line, 'diff')) { if (utils.startsWith(line, "diff")) {
return false; return false;
} }
@ -190,56 +189,56 @@
return false; return false;
} }
var diffLines = var diffLines = diffInput
diffInput.replace(/\\ No newline at end of file/g, '') .replace(/\\ No newline at end of file/g, "")
.replace(/\r\n?/g, '\n') .replace(/\r\n?/g, "\n")
.split('\n'); .split("\n");
/* Diff */ /* Diff */
var oldMode = /^old mode (\d{6})/; const oldMode = /^old mode (\d{6})/;
var newMode = /^new mode (\d{6})/; const newMode = /^new mode (\d{6})/;
var deletedFileMode = /^deleted file mode (\d{6})/; const deletedFileMode = /^deleted file mode (\d{6})/;
var newFileMode = /^new file mode (\d{6})/; const newFileMode = /^new file mode (\d{6})/;
var copyFrom = /^copy from "?(.+)"?/; const copyFrom = /^copy from "?(.+)"?/;
var copyTo = /^copy to "?(.+)"?/; const copyTo = /^copy to "?(.+)"?/;
var renameFrom = /^rename from "?(.+)"?/; const renameFrom = /^rename from "?(.+)"?/;
var renameTo = /^rename to "?(.+)"?/; const renameTo = /^rename to "?(.+)"?/;
var similarityIndex = /^similarity index (\d+)%/; const similarityIndex = /^similarity index (\d+)%/;
var dissimilarityIndex = /^dissimilarity index (\d+)%/; const dissimilarityIndex = /^dissimilarity index (\d+)%/;
var index = /^index ([0-9a-z]+)\.\.([0-9a-z]+)\s*(\d{6})?/; const index = /^index ([0-9a-z]+)\.\.([0-9a-z]+)\s*(\d{6})?/;
var binaryFiles = /^Binary files (.*) and (.*) differ/; const binaryFiles = /^Binary files (.*) and (.*) differ/;
var binaryDiff = /^GIT binary patch/; const binaryDiff = /^GIT binary patch/;
/* Combined Diff */ /* Combined Diff */
var combinedIndex = /^index ([0-9a-z]+),([0-9a-z]+)\.\.([0-9a-z]+)/; const combinedIndex = /^index ([0-9a-z]+),([0-9a-z]+)\.\.([0-9a-z]+)/;
var combinedMode = /^mode (\d{6}),(\d{6})\.\.(\d{6})/; const combinedMode = /^mode (\d{6}),(\d{6})\.\.(\d{6})/;
var combinedNewFile = /^new file mode (\d{6})/; const combinedNewFile = /^new file mode (\d{6})/;
var combinedDeletedFile = /^deleted file mode (\d{6}),(\d{6})/; const combinedDeletedFile = /^deleted file mode (\d{6}),(\d{6})/;
diffLines.forEach(function(line, lineIndex) { diffLines.forEach(function(line, lineIndex) {
// Unmerged paths, and possibly other non-diffable files // Unmerged paths, and possibly other non-diffable files
// https://github.com/scottgonzalez/pretty-diff/issues/11 // https://github.com/scottgonzalez/pretty-diff/issues/11
// Also, remove some useless lines // Also, remove some useless lines
if (!line || utils.startsWith(line, '*')) { if (!line || utils.startsWith(line, "*")) {
return; return;
} }
// Used to store regex capture groups // Used to store regex capture groups
var values; let values;
var prevLine = diffLines[lineIndex - 1]; const prevLine = diffLines[lineIndex - 1];
var nxtLine = diffLines[lineIndex + 1]; const nxtLine = diffLines[lineIndex + 1];
var afterNxtLine = diffLines[lineIndex + 2]; const afterNxtLine = diffLines[lineIndex + 2];
if (utils.startsWith(line, 'diff')) { if (utils.startsWith(line, "diff")) {
startFile(); startFile();
// diff --git a/blocked_delta_results.png b/blocked_delta_results.png // diff --git a/blocked_delta_results.png b/blocked_delta_results.png
var gitDiffStart = /^diff --git "?(.+)"? "?(.+)"?/; const gitDiffStart = /^diff --git "?(.+)"? "?(.+)"?/;
if ((values = gitDiffStart.exec(line))) { if ((values = gitDiffStart.exec(line))) {
possibleOldName = _getFilename(null, values[1], config.dstPrefix); possibleOldName = _getFilename(null, values[1], config.dstPrefix);
possibleNewName = _getFilename(null, values[2], config.srcPrefix); possibleNewName = _getFilename(null, values[2], config.srcPrefix);
@ -249,15 +248,14 @@
return; return;
} }
if (!currentFile || // If we do not have a file yet, we should crete one if (
( !currentFile || // If we do not have a file yet, we should crete one
!currentFile.isGitDiff && currentFile && // If we already have some file in progress and (!currentFile.isGitDiff &&
( currentFile && // If we already have some file in progress and
utils.startsWith(line, oldFileNameHeader) && // If we get to an old file path header line (utils.startsWith(line, oldFileNameHeader) && // If we get to an old file path header line
// And is followed by the new file path header line and the hunk header line // And is followed by the new file path header line and the hunk header line
utils.startsWith(nxtLine, newFileNameHeader) && utils.startsWith(afterNxtLine, hunkHeaderPrefix) utils.startsWith(nxtLine, newFileNameHeader) &&
) utils.startsWith(afterNxtLine, hunkHeaderPrefix)))
)
) { ) {
startFile(); startFile();
} }
@ -268,18 +266,19 @@
* - https://github.com/rtfpessoa/diff2html/issues/87 * - https://github.com/rtfpessoa/diff2html/issues/87
*/ */
if ( if (
(utils.startsWith(line, oldFileNameHeader) && (utils.startsWith(line, oldFileNameHeader) && utils.startsWith(nxtLine, newFileNameHeader)) ||
utils.startsWith(nxtLine, newFileNameHeader)) || (utils.startsWith(line, newFileNameHeader) && utils.startsWith(prevLine, oldFileNameHeader))
(utils.startsWith(line, newFileNameHeader) &&
utils.startsWith(prevLine, oldFileNameHeader))
) { ) {
/* /*
* --- Date Timestamp[FractionalSeconds] TimeZone * --- Date Timestamp[FractionalSeconds] TimeZone
* --- 2002-02-21 23:30:39.942229878 -0800 * --- 2002-02-21 23:30:39.942229878 -0800
*/ */
if (currentFile && !currentFile.oldName && if (
utils.startsWith(line, '--- ') && (values = getSrcFilename(line, config))) { currentFile &&
!currentFile.oldName &&
utils.startsWith(line, "--- ") &&
(values = getSrcFilename(line, config))
) {
currentFile.oldName = values; currentFile.oldName = values;
currentFile.language = getExtension(currentFile.oldName, currentFile.language); currentFile.language = getExtension(currentFile.oldName, currentFile.language);
return; return;
@ -289,8 +288,12 @@
* +++ Date Timestamp[FractionalSeconds] TimeZone * +++ Date Timestamp[FractionalSeconds] TimeZone
* +++ 2002-02-21 23:30:39.942229878 -0800 * +++ 2002-02-21 23:30:39.942229878 -0800
*/ */
if (currentFile && !currentFile.newName && if (
utils.startsWith(line, '+++ ') && (values = getDstFilename(line, config))) { currentFile &&
!currentFile.newName &&
utils.startsWith(line, "+++ ") &&
(values = getDstFilename(line, config))
) {
currentFile.newName = values; currentFile.newName = values;
currentFile.language = getExtension(currentFile.newName, currentFile.language); currentFile.language = getExtension(currentFile.newName, currentFile.language);
return; return;
@ -311,12 +314,12 @@
* 2. Old line starts with: - * 2. Old line starts with: -
* 3. Context line starts with: <SPACE> * 3. Context line starts with: <SPACE>
*/ */
if (currentBlock && (utils.startsWith(line, '+') || utils.startsWith(line, '-') || utils.startsWith(line, ' '))) { if (currentBlock && (utils.startsWith(line, "+") || utils.startsWith(line, "-") || utils.startsWith(line, " "))) {
createLine(line); createLine(line);
return; return;
} }
var doesNotExistHunkHeader = !existHunkHeader(line, lineIndex); const doesNotExistHunkHeader = !existHunkHeader(line, lineIndex);
/* /*
* Git diffs provide more information regarding files modes, renames, copies, * Git diffs provide more information regarding files modes, renames, copies,
@ -356,7 +359,7 @@
currentFile.isBinary = true; currentFile.isBinary = true;
currentFile.oldName = _getFilename(null, values[1], config.srcPrefix); currentFile.oldName = _getFilename(null, values[1], config.srcPrefix);
currentFile.newName = _getFilename(null, values[2], config.dstPrefix); currentFile.newName = _getFilename(null, values[2], config.dstPrefix);
startBlock('Binary file'); startBlock("Binary file");
} else if ((values = binaryDiff.exec(line))) { } else if ((values = binaryDiff.exec(line))) {
currentFile.isBinary = true; currentFile.isBinary = true;
startBlock(line); startBlock(line);
@ -390,7 +393,7 @@
}; };
function getExtension(filename, language) { function getExtension(filename, language) {
var nameSplit = filename.split('.'); const nameSplit = filename.split(".");
if (nameSplit.length > 1) { if (nameSplit.length > 1) {
return nameSplit[nameSplit.length - 1]; return nameSplit[nameSplit.length - 1];
} }
@ -399,31 +402,31 @@
} }
function getSrcFilename(line, cfg) { function getSrcFilename(line, cfg) {
return _getFilename('---', line, cfg.srcPrefix); return _getFilename("---", line, cfg.srcPrefix);
} }
function getDstFilename(line, cfg) { function getDstFilename(line, cfg) {
return _getFilename('\\+\\+\\+', line, cfg.dstPrefix); return _getFilename("\\+\\+\\+", line, cfg.dstPrefix);
} }
function _getFilename(linePrefix, line, extraPrefix) { function _getFilename(linePrefix, line, extraPrefix) {
var prefixes = ['a/', 'b/', 'i/', 'w/', 'c/', 'o/']; const prefixes = ["a/", "b/", "i/", "w/", "c/", "o/"];
if (extraPrefix) { if (extraPrefix) {
prefixes.push(extraPrefix); prefixes.push(extraPrefix);
} }
var FilenameRegExp; let FilenameRegExp;
if (linePrefix) { if (linePrefix) {
FilenameRegExp = new RegExp('^' + linePrefix + ' "?(.+?)"?$'); FilenameRegExp = new RegExp("^" + linePrefix + ' "?(.+?)"?$');
} else { } else {
FilenameRegExp = new RegExp('^"?(.+?)"?$'); FilenameRegExp = new RegExp('^"?(.+?)"?$');
} }
var filename; let filename;
var values = FilenameRegExp.exec(line); const values = FilenameRegExp.exec(line);
if (values && values[1]) { if (values && values[1]) {
filename = values[1]; filename = values[1];
var matchingPrefixes = prefixes.filter(function(p) { const matchingPrefixes = prefixes.filter(function(p) {
return filename.indexOf(p) === 0; return filename.indexOf(p) === 0;
}); });
@ -435,7 +438,7 @@
// Cleanup timestamps generated by the unified diff (diff command) as specified in // Cleanup timestamps generated by the unified diff (diff command) as specified in
// https://www.gnu.org/software/diffutils/manual/html_node/Detailed-Unified.html // https://www.gnu.org/software/diffutils/manual/html_node/Detailed-Unified.html
// Ie: 2016-10-25 11:37:14.000000000 +0200 // Ie: 2016-10-25 11:37:14.000000000 +0200
filename = filename.replace(/\s+\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d+)? [-+]\d{4}.*$/, ''); filename = filename.replace(/\s+\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d+)? [-+]\d{4}.*$/, "");
} }
return filename; return filename;

11
src/diff2html.d.ts vendored
View file

@ -4,13 +4,12 @@
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
declare namespace Diff2Html { declare namespace Diff2Html {
export interface Options { export interface Options {
inputFormat?: 'diff' | 'json'; inputFormat?: "diff" | "json";
outputFormat?: 'line-by-line' | 'side-by-side'; outputFormat?: "line-by-line" | "side-by-side";
showFiles?: boolean; showFiles?: boolean;
diffStyle?: 'word' | 'char'; diffStyle?: "word" | "char";
matching?: 'lines' | 'words' | 'none'; matching?: "lines" | "words" | "none";
matchWordsThreshold?: number; matchWordsThreshold?: number;
matchingMaxComparisons?: number; matchingMaxComparisons?: number;
maxLineSizeInBlockForComparison?: number; maxLineSizeInBlockForComparison?: number;
@ -66,6 +65,6 @@ declare namespace Diff2Html {
} }
declare module "diff2html" { declare module "diff2html" {
var d2h: { "Diff2Html": Diff2Html.Diff2Html }; var d2h: { Diff2Html: Diff2Html.Diff2Html };
export = d2h; export = d2h;
} }

View file

@ -6,19 +6,18 @@
*/ */
(function() { (function() {
var diffParser = require('./diff-parser.js').DiffParser; const diffParser = require("./diff-parser.js").DiffParser;
var htmlPrinter = require('./html-printer.js').HtmlPrinter; const htmlPrinter = require("./html-printer.js").HtmlPrinter;
var utils = require('./utils.js').Utils; const utils = require("./utils.js").Utils;
function Diff2Html() { function Diff2Html() {}
}
var defaultConfig = { const defaultConfig = {
inputFormat: 'diff', inputFormat: "diff",
outputFormat: 'line-by-line', outputFormat: "line-by-line",
showFiles: false, showFiles: false,
diffStyle: 'word', diffStyle: "word",
matching: 'none', matching: "none",
matchWordsThreshold: 0.25, matchWordsThreshold: 0.25,
matchingMaxComparisons: 2500, matchingMaxComparisons: 2500,
maxLineSizeInBlockForComparison: 200, maxLineSizeInBlockForComparison: 200,
@ -32,7 +31,7 @@
* Generates json object from string diff input * Generates json object from string diff input
*/ */
Diff2Html.prototype.getJsonFromDiff = function(diffInput, config) { Diff2Html.prototype.getJsonFromDiff = function(diffInput, config) {
var cfg = utils.safeConfig(config, defaultConfig); const cfg = utils.safeConfig(config, defaultConfig);
return diffParser.generateDiffJson(diffInput, cfg); return diffParser.generateDiffJson(diffInput, cfg);
}; };
@ -40,20 +39,20 @@
* Generates the html diff. The config parameter configures the output/input formats and other options * Generates the html diff. The config parameter configures the output/input formats and other options
*/ */
Diff2Html.prototype.getPrettyHtml = function(diffInput, config) { Diff2Html.prototype.getPrettyHtml = function(diffInput, config) {
var cfg = utils.safeConfig(config, defaultConfig); const cfg = utils.safeConfig(config, defaultConfig);
var diffJson = diffInput; let diffJson = diffInput;
if (!cfg.inputFormat || cfg.inputFormat === 'diff') { if (!cfg.inputFormat || cfg.inputFormat === "diff") {
diffJson = diffParser.generateDiffJson(diffInput, cfg); diffJson = diffParser.generateDiffJson(diffInput, cfg);
} }
var fileList = ''; let fileList = "";
if (cfg.showFiles === true) { if (cfg.showFiles === true) {
fileList = htmlPrinter.generateFileListSummary(diffJson, cfg); fileList = htmlPrinter.generateFileListSummary(diffJson, cfg);
} }
var diffOutput = ''; let diffOutput = "";
if (cfg.outputFormat === 'side-by-side') { if (cfg.outputFormat === "side-by-side") {
diffOutput = htmlPrinter.generateSideBySideJsonHtml(diffJson, cfg); diffOutput = htmlPrinter.generateSideBySideJsonHtml(diffJson, cfg);
} else { } else {
diffOutput = htmlPrinter.generateLineByLineJsonHtml(diffJson, cfg); diffOutput = htmlPrinter.generateLineByLineJsonHtml(diffJson, cfg);
@ -70,9 +69,9 @@
* Generates pretty html from string diff input * Generates pretty html from string diff input
*/ */
Diff2Html.prototype.getPrettyHtmlFromDiff = function(diffInput, config) { Diff2Html.prototype.getPrettyHtmlFromDiff = function(diffInput, config) {
var cfg = utils.safeConfig(config, defaultConfig); const cfg = utils.safeConfig(config, defaultConfig);
cfg.inputFormat = 'diff'; cfg.inputFormat = "diff";
cfg.outputFormat = 'line-by-line'; cfg.outputFormat = "line-by-line";
return this.getPrettyHtml(diffInput, cfg); return this.getPrettyHtml(diffInput, cfg);
}; };
@ -80,9 +79,9 @@
* Generates pretty html from a json object * Generates pretty html from a json object
*/ */
Diff2Html.prototype.getPrettyHtmlFromJson = function(diffJson, config) { Diff2Html.prototype.getPrettyHtmlFromJson = function(diffJson, config) {
var cfg = utils.safeConfig(config, defaultConfig); const cfg = utils.safeConfig(config, defaultConfig);
cfg.inputFormat = 'json'; cfg.inputFormat = "json";
cfg.outputFormat = 'line-by-line'; cfg.outputFormat = "line-by-line";
return this.getPrettyHtml(diffJson, cfg); return this.getPrettyHtml(diffJson, cfg);
}; };
@ -90,9 +89,9 @@
* Generates pretty side by side html from string diff input * Generates pretty side by side html from string diff input
*/ */
Diff2Html.prototype.getPrettySideBySideHtmlFromDiff = function(diffInput, config) { Diff2Html.prototype.getPrettySideBySideHtmlFromDiff = function(diffInput, config) {
var cfg = utils.safeConfig(config, defaultConfig); const cfg = utils.safeConfig(config, defaultConfig);
cfg.inputFormat = 'diff'; cfg.inputFormat = "diff";
cfg.outputFormat = 'side-by-side'; cfg.outputFormat = "side-by-side";
return this.getPrettyHtml(diffInput, cfg); return this.getPrettyHtml(diffInput, cfg);
}; };
@ -100,13 +99,13 @@
* Generates pretty side by side html from a json object * Generates pretty side by side html from a json object
*/ */
Diff2Html.prototype.getPrettySideBySideHtmlFromJson = function(diffJson, config) { Diff2Html.prototype.getPrettySideBySideHtmlFromJson = function(diffJson, config) {
var cfg = utils.safeConfig(config, defaultConfig); const cfg = utils.safeConfig(config, defaultConfig);
cfg.inputFormat = 'json'; cfg.inputFormat = "json";
cfg.outputFormat = 'side-by-side'; cfg.outputFormat = "side-by-side";
return this.getPrettyHtml(diffJson, cfg); return this.getPrettyHtml(diffJson, cfg);
}; };
var diffObject = new Diff2Html(); const diffObject = new Diff2Html();
module.exports.Diff2Html = diffObject; module.exports.Diff2Html = diffObject;
// Expose diff2html in the browser // Expose diff2html in the browser

View file

@ -6,40 +6,45 @@
*/ */
(function() { (function() {
var printerUtils = require('./printer-utils.js').PrinterUtils; const printerUtils = require("./printer-utils.js").PrinterUtils;
var hoganUtils; let hoganUtils;
var baseTemplatesPath = 'file-summary'; const baseTemplatesPath = "file-summary";
var iconsBaseTemplatesPath = 'icon'; const iconsBaseTemplatesPath = "icon";
function FileListPrinter(config) { function FileListPrinter(config) {
this.config = config; this.config = config;
var HoganJsUtils = require('./hoganjs-utils.js').HoganJsUtils; const HoganJsUtils = require("./hoganjs-utils.js").HoganJsUtils;
hoganUtils = new HoganJsUtils(config); hoganUtils = new HoganJsUtils(config);
} }
FileListPrinter.prototype.generateFileList = function(diffFiles) { FileListPrinter.prototype.generateFileList = function(diffFiles) {
var lineTemplate = hoganUtils.template(baseTemplatesPath, 'line'); const lineTemplate = hoganUtils.template(baseTemplatesPath, "line");
var files = diffFiles.map(function(file) { const files = diffFiles
var fileTypeName = printerUtils.getFileTypeIcon(file); .map(function(file) {
var iconTemplate = hoganUtils.template(iconsBaseTemplatesPath, fileTypeName); const fileTypeName = printerUtils.getFileTypeIcon(file);
const iconTemplate = hoganUtils.template(iconsBaseTemplatesPath, fileTypeName);
return lineTemplate.render({ return lineTemplate.render(
{
fileHtmlId: printerUtils.getHtmlId(file), fileHtmlId: printerUtils.getHtmlId(file),
oldName: file.oldName, oldName: file.oldName,
newName: file.newName, newName: file.newName,
fileName: printerUtils.getDiffName(file), fileName: printerUtils.getDiffName(file),
deletedLines: '-' + file.deletedLines, deletedLines: "-" + file.deletedLines,
addedLines: '+' + file.addedLines addedLines: "+" + file.addedLines
}, { },
{
fileIcon: iconTemplate fileIcon: iconTemplate
}); }
}).join('\n'); );
})
.join("\n");
return hoganUtils.render(baseTemplatesPath, 'wrapper', { return hoganUtils.render(baseTemplatesPath, "wrapper", {
filesNumber: diffFiles.length, filesNumber: diffFiles.length,
files: files files: files
}); });

View file

@ -6,20 +6,20 @@
*/ */
(function() { (function() {
var fs = require('fs'); const fs = require("fs");
var path = require('path'); const path = require("path");
var hogan = require('hogan.js'); const hogan = require("hogan.js");
var hoganTemplates = require('./templates/diff2html-templates.js'); const hoganTemplates = require("./diff2html-templates.js");
var extraTemplates; let extraTemplates;
function HoganJsUtils(configuration) { function HoganJsUtils(configuration) {
this.config = configuration || {}; this.config = configuration || {};
extraTemplates = this.config.templates || {}; extraTemplates = this.config.templates || {};
var rawTemplates = this.config.rawTemplates || {}; const rawTemplates = this.config.rawTemplates || {};
for (var templateName in rawTemplates) { for (const templateName in rawTemplates) {
if (rawTemplates.hasOwnProperty(templateName)) { if (rawTemplates.hasOwnProperty(templateName)) {
if (!extraTemplates[templateName]) extraTemplates[templateName] = this.compile(rawTemplates[templateName]); if (!extraTemplates[templateName]) extraTemplates[templateName] = this.compile(rawTemplates[templateName]);
} }
@ -27,7 +27,7 @@
} }
HoganJsUtils.prototype.render = function(namespace, view, params) { HoganJsUtils.prototype.render = function(namespace, view, params) {
var template = this.template(namespace, view); const template = this.template(namespace, view);
if (template) { if (template) {
return template.render(params); return template.render(params);
} }
@ -36,13 +36,13 @@
}; };
HoganJsUtils.prototype.template = function(namespace, view) { HoganJsUtils.prototype.template = function(namespace, view) {
var templateKey = this._templateKey(namespace, view); const templateKey = this._templateKey(namespace, view);
return this._getTemplate(templateKey); return this._getTemplate(templateKey);
}; };
HoganJsUtils.prototype._getTemplate = function(templateKey) { HoganJsUtils.prototype._getTemplate = function(templateKey) {
var template; let template;
if (!this.config.noCache) { if (!this.config.noCache) {
template = this._readFromCache(templateKey); template = this._readFromCache(templateKey);
@ -56,18 +56,18 @@
}; };
HoganJsUtils.prototype._loadTemplate = function(templateKey) { HoganJsUtils.prototype._loadTemplate = function(templateKey) {
var template; let template;
try { try {
if (fs.readFileSync) { if (fs.readFileSync) {
var templatesPath = path.resolve(__dirname, 'templates'); const templatesPath = path.resolve(__dirname, "templates");
var templatePath = path.join(templatesPath, templateKey); const templatePath = path.join(templatesPath, templateKey);
var templateContent = fs.readFileSync(templatePath + '.mustache', 'utf8'); const templateContent = fs.readFileSync(templatePath + ".mustache", "utf8");
template = hogan.compile(templateContent); template = hogan.compile(templateContent);
hoganTemplates[templateKey] = template; hoganTemplates[templateKey] = template;
} }
} catch (e) { } catch (e) {
console.error('Failed to read (template: ' + templateKey + ') from fs: ' + e.message); console.error("Failed to read (template: " + templateKey + ") from fs: " + e.message);
} }
return template; return template;
@ -78,7 +78,7 @@
}; };
HoganJsUtils.prototype._templateKey = function(namespace, view) { HoganJsUtils.prototype._templateKey = function(namespace, view) {
return namespace + '-' + view; return namespace + "-" + view;
}; };
HoganJsUtils.prototype.compile = function(templateStr) { HoganJsUtils.prototype.compile = function(templateStr) {

View file

@ -6,25 +6,24 @@
*/ */
(function() { (function() {
var LineByLinePrinter = require('./line-by-line-printer.js').LineByLinePrinter; const LineByLinePrinter = require("./line-by-line-printer.js").LineByLinePrinter;
var SideBySidePrinter = require('./side-by-side-printer.js').SideBySidePrinter; const SideBySidePrinter = require("./side-by-side-printer.js").SideBySidePrinter;
var FileListPrinter = require('./file-list-printer.js').FileListPrinter; const FileListPrinter = require("./file-list-printer.js").FileListPrinter;
function HtmlPrinter() { function HtmlPrinter() {}
}
HtmlPrinter.prototype.generateLineByLineJsonHtml = function(diffFiles, config) { HtmlPrinter.prototype.generateLineByLineJsonHtml = function(diffFiles, config) {
var lineByLinePrinter = new LineByLinePrinter(config); const lineByLinePrinter = new LineByLinePrinter(config);
return lineByLinePrinter.generateLineByLineJsonHtml(diffFiles); return lineByLinePrinter.generateLineByLineJsonHtml(diffFiles);
}; };
HtmlPrinter.prototype.generateSideBySideJsonHtml = function(diffFiles, config) { HtmlPrinter.prototype.generateSideBySideJsonHtml = function(diffFiles, config) {
var sideBySidePrinter = new SideBySidePrinter(config); const sideBySidePrinter = new SideBySidePrinter(config);
return sideBySidePrinter.generateSideBySideJsonHtml(diffFiles); return sideBySidePrinter.generateSideBySideJsonHtml(diffFiles);
}; };
HtmlPrinter.prototype.generateFileListSummary = function(diffJson, config) { HtmlPrinter.prototype.generateFileListSummary = function(diffJson, config) {
var fileListPrinter = new FileListPrinter(config); const fileListPrinter = new FileListPrinter(config);
return fileListPrinter.generateFileList(diffJson); return fileListPrinter.generateFileList(diffJson);
}; };

View file

@ -6,54 +6,57 @@
*/ */
(function() { (function() {
var diffParser = require('./diff-parser.js').DiffParser; const diffParser = require("./diff-parser.js").DiffParser;
var printerUtils = require('./printer-utils.js').PrinterUtils; const printerUtils = require("./printer-utils.js").PrinterUtils;
var utils = require('./utils.js').Utils; const utils = require("./utils.js").Utils;
var Rematch = require('./rematch.js').Rematch; const Rematch = require("./rematch.js").Rematch;
var hoganUtils; let hoganUtils;
var genericTemplatesPath = 'generic'; const genericTemplatesPath = "generic";
var baseTemplatesPath = 'line-by-line'; const baseTemplatesPath = "line-by-line";
var iconsBaseTemplatesPath = 'icon'; const iconsBaseTemplatesPath = "icon";
var tagsBaseTemplatesPath = 'tag'; const tagsBaseTemplatesPath = "tag";
function LineByLinePrinter(config) { function LineByLinePrinter(config) {
this.config = config; this.config = config;
var HoganJsUtils = require('./hoganjs-utils.js').HoganJsUtils; const HoganJsUtils = require("./hoganjs-utils.js").HoganJsUtils;
hoganUtils = new HoganJsUtils(config); hoganUtils = new HoganJsUtils(config);
} }
LineByLinePrinter.prototype.makeFileDiffHtml = function(file, diffs) { LineByLinePrinter.prototype.makeFileDiffHtml = function(file, diffs) {
if (this.config.renderNothingWhenEmpty && file.blocks && !file.blocks.length) return ''; if (this.config.renderNothingWhenEmpty && file.blocks && !file.blocks.length) return "";
var fileDiffTemplate = hoganUtils.template(baseTemplatesPath, 'file-diff'); const fileDiffTemplate = hoganUtils.template(baseTemplatesPath, "file-diff");
var filePathTemplate = hoganUtils.template(genericTemplatesPath, 'file-path'); const filePathTemplate = hoganUtils.template(genericTemplatesPath, "file-path");
var fileIconTemplate = hoganUtils.template(iconsBaseTemplatesPath, 'file'); const fileIconTemplate = hoganUtils.template(iconsBaseTemplatesPath, "file");
var fileTagTemplate = hoganUtils.template(tagsBaseTemplatesPath, printerUtils.getFileTypeIcon(file)); const fileTagTemplate = hoganUtils.template(tagsBaseTemplatesPath, printerUtils.getFileTypeIcon(file));
return fileDiffTemplate.render({ return fileDiffTemplate.render({
file: file, file: file,
fileHtmlId: printerUtils.getHtmlId(file), fileHtmlId: printerUtils.getHtmlId(file),
diffs: diffs, diffs: diffs,
filePath: filePathTemplate.render({ filePath: filePathTemplate.render(
{
fileDiffName: printerUtils.getDiffName(file) fileDiffName: printerUtils.getDiffName(file)
}, { },
{
fileIcon: fileIconTemplate, fileIcon: fileIconTemplate,
fileTag: fileTagTemplate fileTag: fileTagTemplate
}) }
)
}); });
}; };
LineByLinePrinter.prototype.makeLineByLineHtmlWrapper = function(content) { LineByLinePrinter.prototype.makeLineByLineHtmlWrapper = function(content) {
return hoganUtils.render(genericTemplatesPath, 'wrapper', {'content': content}); return hoganUtils.render(genericTemplatesPath, "wrapper", { content: content });
}; };
LineByLinePrinter.prototype.generateLineByLineJsonHtml = function(diffFiles) { LineByLinePrinter.prototype.generateLineByLineJsonHtml = function(diffFiles) {
var that = this; const that = this;
var htmlDiffs = diffFiles.map(function(file) { const htmlDiffs = diffFiles.map(function(file) {
var diffs; let diffs;
if (file.blocks.length) { if (file.blocks.length) {
diffs = that._generateFileHtml(file); diffs = that._generateFileHtml(file);
} else { } else {
@ -62,49 +65,53 @@
return that.makeFileDiffHtml(file, diffs); return that.makeFileDiffHtml(file, diffs);
}); });
return this.makeLineByLineHtmlWrapper(htmlDiffs.join('\n')); return this.makeLineByLineHtmlWrapper(htmlDiffs.join("\n"));
}; };
var matcher = Rematch.rematch(function(a, b) { const matcher = Rematch.rematch(function(a, b) {
var amod = a.content.substr(1); const amod = a.content.substr(1);
var bmod = b.content.substr(1); const bmod = b.content.substr(1);
return Rematch.distance(amod, bmod); return Rematch.distance(amod, bmod);
}); });
LineByLinePrinter.prototype.makeColumnLineNumberHtml = function(block) { LineByLinePrinter.prototype.makeColumnLineNumberHtml = function(block) {
return hoganUtils.render(genericTemplatesPath, 'column-line-number', { return hoganUtils.render(genericTemplatesPath, "column-line-number", {
diffParser: diffParser, diffParser: diffParser,
blockHeader: utils.escape(block.header), blockHeader: utils.escape(block.header),
lineClass: 'd2h-code-linenumber', lineClass: "d2h-code-linenumber",
contentClass: 'd2h-code-line' contentClass: "d2h-code-line"
}); });
}; };
LineByLinePrinter.prototype._generateFileHtml = function(file) { LineByLinePrinter.prototype._generateFileHtml = function(file) {
var that = this; const that = this;
return file.blocks.map(function(block) { return file.blocks
var lines = that.makeColumnLineNumberHtml(block); .map(function(block) {
var oldLines = []; let lines = that.makeColumnLineNumberHtml(block);
var newLines = []; let oldLines = [];
let newLines = [];
function processChangeBlock() { function processChangeBlock() {
var matches; let matches;
var insertType; let insertType;
var deleteType; let deleteType;
var comparisons = oldLines.length * newLines.length; const comparisons = oldLines.length * newLines.length;
var maxLineSizeInBlock = Math.max.apply(null, const maxLineSizeInBlock = Math.max.apply(
[0].concat((oldLines.concat(newLines)).map( null,
function(elem) { [0].concat(
oldLines.concat(newLines).map(function(elem) {
return elem.content.length; return elem.content.length;
} })
))); )
);
var doMatching = comparisons < that.config.matchingMaxComparisons && const doMatching =
comparisons < that.config.matchingMaxComparisons &&
maxLineSizeInBlock < that.config.maxLineSizeInBlockForComparison && maxLineSizeInBlock < that.config.maxLineSizeInBlockForComparison &&
(that.config.matching === 'lines' || that.config.matching === 'words'); (that.config.matching === "lines" || that.config.matching === "words");
if (doMatching) { if (doMatching) {
matches = matcher(oldLines, newLines); matches = matcher(oldLines, newLines);
@ -120,25 +127,35 @@
oldLines = match[0]; oldLines = match[0];
newLines = match[1]; newLines = match[1];
var processedOldLines = []; let processedOldLines = [];
var processedNewLines = []; let processedNewLines = [];
var common = Math.min(oldLines.length, newLines.length); const common = Math.min(oldLines.length, newLines.length);
var oldLine, newLine; let oldLine, newLine;
for (var j = 0; j < common; j++) { for (let j = 0; j < common; j++) {
oldLine = oldLines[j]; oldLine = oldLines[j];
newLine = newLines[j]; newLine = newLines[j];
that.config.isCombined = file.isCombined; that.config.isCombined = file.isCombined;
var diff = printerUtils.diffHighlight(oldLine.content, newLine.content, that.config); const diff = printerUtils.diffHighlight(oldLine.content, newLine.content, that.config);
processedOldLines += processedOldLines += that.makeLineHtml(
that.makeLineHtml(file.isCombined, deleteType, oldLine.oldNumber, oldLine.newNumber, file.isCombined,
diff.first.line, diff.first.prefix); deleteType,
processedNewLines += oldLine.oldNumber,
that.makeLineHtml(file.isCombined, insertType, newLine.oldNumber, newLine.newNumber, oldLine.newNumber,
diff.second.line, diff.second.prefix); diff.first.line,
diff.first.prefix
);
processedNewLines += that.makeLineHtml(
file.isCombined,
insertType,
newLine.oldNumber,
newLine.newNumber,
diff.second.line,
diff.second.prefix
);
} }
lines += processedOldLines + processedNewLines; lines += processedOldLines + processedNewLines;
@ -149,12 +166,14 @@
newLines = []; newLines = [];
} }
for (var i = 0; i < block.lines.length; i++) { for (let i = 0; i < block.lines.length; i++) {
var line = block.lines[i]; const line = block.lines[i];
var escapedLine = utils.escape(line.content); const escapedLine = utils.escape(line.content);
if (line.type !== diffParser.LINE_TYPE.INSERTS && if (
(newLines.length > 0 || (line.type !== diffParser.LINE_TYPE.DELETES && oldLines.length > 0))) { line.type !== diffParser.LINE_TYPE.INSERTS &&
(newLines.length > 0 || (line.type !== diffParser.LINE_TYPE.DELETES && oldLines.length > 0))
) {
processChangeBlock(); processChangeBlock();
} }
@ -167,7 +186,7 @@
} else if (line.type === diffParser.LINE_TYPE.INSERTS && Boolean(oldLines.length)) { } else if (line.type === diffParser.LINE_TYPE.INSERTS && Boolean(oldLines.length)) {
newLines.push(line); newLines.push(line);
} else { } else {
console.error('Unknown state in html line-by-line generator'); console.error("Unknown state in html line-by-line generator");
processChangeBlock(); processChangeBlock();
} }
} }
@ -175,21 +194,22 @@
processChangeBlock(); processChangeBlock();
return lines; return lines;
}).join('\n'); })
.join("\n");
}; };
LineByLinePrinter.prototype._processLines = function(isCombined, oldLines, newLines) { LineByLinePrinter.prototype._processLines = function(isCombined, oldLines, newLines) {
var lines = ''; let lines = "";
for (var i = 0; i < oldLines.length; i++) { for (let i = 0; i < oldLines.length; i++) {
var oldLine = oldLines[i]; const oldLine = oldLines[i];
var oldEscapedLine = utils.escape(oldLine.content); const oldEscapedLine = utils.escape(oldLine.content);
lines += this.makeLineHtml(isCombined, oldLine.type, oldLine.oldNumber, oldLine.newNumber, oldEscapedLine); lines += this.makeLineHtml(isCombined, oldLine.type, oldLine.oldNumber, oldLine.newNumber, oldEscapedLine);
} }
for (var j = 0; j < newLines.length; j++) { for (let j = 0; j < newLines.length; j++) {
var newLine = newLines[j]; const newLine = newLines[j];
var newEscapedLine = utils.escape(newLine.content); const newEscapedLine = utils.escape(newLine.content);
lines += this.makeLineHtml(isCombined, newLine.type, newLine.oldNumber, newLine.newNumber, newEscapedLine); lines += this.makeLineHtml(isCombined, newLine.type, newLine.oldNumber, newLine.newNumber, newEscapedLine);
} }
@ -197,29 +217,28 @@
}; };
LineByLinePrinter.prototype.makeLineHtml = function(isCombined, type, oldNumber, newNumber, content, possiblePrefix) { LineByLinePrinter.prototype.makeLineHtml = function(isCombined, type, oldNumber, newNumber, content, possiblePrefix) {
var lineNumberTemplate = hoganUtils.render(baseTemplatesPath, 'numbers', { const lineNumberTemplate = hoganUtils.render(baseTemplatesPath, "numbers", {
oldNumber: utils.valueOrEmpty(oldNumber), oldNumber: utils.valueOrEmpty(oldNumber),
newNumber: utils.valueOrEmpty(newNumber) newNumber: utils.valueOrEmpty(newNumber)
}); });
var lineWithoutPrefix = content; let lineWithoutPrefix = content;
var prefix = possiblePrefix; let prefix = possiblePrefix;
if (!prefix) { if (!prefix) {
var lineWithPrefix = printerUtils.separatePrefix(isCombined, content); const lineWithPrefix = printerUtils.separatePrefix(isCombined, content);
prefix = lineWithPrefix.prefix; prefix = lineWithPrefix.prefix;
lineWithoutPrefix = lineWithPrefix.line; lineWithoutPrefix = lineWithPrefix.line;
} }
if (prefix === ' ') { if (prefix === " ") {
prefix = '&nbsp;'; prefix = "&nbsp;";
} }
return hoganUtils.render(genericTemplatesPath, 'line', return hoganUtils.render(genericTemplatesPath, "line", {
{
type: type, type: type,
lineClass: 'd2h-code-linenumber', lineClass: "d2h-code-linenumber",
contentClass: 'd2h-code-line', contentClass: "d2h-code-line",
prefix: prefix, prefix: prefix,
content: lineWithoutPrefix, content: lineWithoutPrefix,
lineNumber: lineNumberTemplate lineNumber: lineNumberTemplate
@ -227,8 +246,8 @@
}; };
LineByLinePrinter.prototype._generateEmptyDiff = function() { LineByLinePrinter.prototype._generateEmptyDiff = function() {
return hoganUtils.render(genericTemplatesPath, 'empty-diff', { return hoganUtils.render(genericTemplatesPath, "empty-diff", {
contentClass: 'd2h-code-line', contentClass: "d2h-code-line",
diffParser: diffParser diffParser: diffParser
}); });
}; };

View file

@ -6,18 +6,17 @@
*/ */
(function() { (function() {
var jsDiff = require('diff'); const jsDiff = require("diff");
var utils = require('./utils.js').Utils; const utils = require("./utils.js").Utils;
var Rematch = require('./rematch.js').Rematch; const Rematch = require("./rematch.js").Rematch;
var separator = '/'; const separator = "/";
function PrinterUtils() { function PrinterUtils() {}
}
PrinterUtils.prototype.separatePrefix = function(isCombined, line) { PrinterUtils.prototype.separatePrefix = function(isCombined, line) {
var prefix; let prefix;
var lineWithoutPrefix; let lineWithoutPrefix;
if (isCombined) { if (isCombined) {
prefix = line.substring(0, 2); prefix = line.substring(0, 2);
@ -28,45 +27,56 @@
} }
return { return {
'prefix': prefix, prefix: prefix,
'line': lineWithoutPrefix line: lineWithoutPrefix
}; };
}; };
PrinterUtils.prototype.getHtmlId = function(file) { PrinterUtils.prototype.getHtmlId = function(file) {
var hashCode = function(text) { const hashCode = function(text) {
var i, chr, len; let i, chr, len;
var hash = 0; let hash = 0;
for (i = 0, len = text.length; i < len; i++) { for (i = 0, len = text.length; i < len; i++) {
chr = text.charCodeAt(i); chr = text.charCodeAt(i);
hash = ((hash << 5) - hash) + chr; hash = (hash << 5) - hash + chr;
hash |= 0; // Convert to 32bit integer hash |= 0; // Convert to 32bit integer
} }
return hash; return hash;
}; };
return 'd2h-' + hashCode(this.getDiffName(file)).toString().slice(-6); return (
"d2h-" +
hashCode(this.getDiffName(file))
.toString()
.slice(-6)
);
}; };
PrinterUtils.prototype.getDiffName = function(file) { PrinterUtils.prototype.getDiffName = function(file) {
var oldFilename = unifyPath(file.oldName); const oldFilename = unifyPath(file.oldName);
var newFilename = unifyPath(file.newName); const newFilename = unifyPath(file.newName);
if (oldFilename && newFilename && oldFilename !== newFilename && !isDevNullName(oldFilename) && !isDevNullName(newFilename)) { if (
var prefixPaths = []; oldFilename &&
var suffixPaths = []; newFilename &&
oldFilename !== newFilename &&
!isDevNullName(oldFilename) &&
!isDevNullName(newFilename)
) {
const prefixPaths = [];
const suffixPaths = [];
var oldFilenameParts = oldFilename.split(separator); const oldFilenameParts = oldFilename.split(separator);
var newFilenameParts = newFilename.split(separator); const newFilenameParts = newFilename.split(separator);
var oldFilenamePartsSize = oldFilenameParts.length; const oldFilenamePartsSize = oldFilenameParts.length;
var newFilenamePartsSize = newFilenameParts.length; const newFilenamePartsSize = newFilenameParts.length;
var i = 0; let i = 0;
var j = oldFilenamePartsSize - 1; let j = oldFilenamePartsSize - 1;
var k = newFilenamePartsSize - 1; let k = newFilenamePartsSize - 1;
while (i < j && i < k) { while (i < j && i < k) {
if (oldFilenameParts[i] === newFilenameParts[i]) { if (oldFilenameParts[i] === newFilenameParts[i]) {
@ -87,53 +97,55 @@
} }
} }
var finalPrefix = prefixPaths.join(separator); const finalPrefix = prefixPaths.join(separator);
var finalSuffix = suffixPaths.join(separator); const finalSuffix = suffixPaths.join(separator);
var oldRemainingPath = oldFilenameParts.slice(i, j + 1).join(separator); const oldRemainingPath = oldFilenameParts.slice(i, j + 1).join(separator);
var newRemainingPath = newFilenameParts.slice(i, k + 1).join(separator); const newRemainingPath = newFilenameParts.slice(i, k + 1).join(separator);
if (finalPrefix.length && finalSuffix.length) { if (finalPrefix.length && finalSuffix.length) {
return finalPrefix + separator + '{' + oldRemainingPath + ' → ' + newRemainingPath + '}' + separator + finalSuffix; return (
finalPrefix + separator + "{" + oldRemainingPath + " → " + newRemainingPath + "}" + separator + finalSuffix
);
} else if (finalPrefix.length) { } else if (finalPrefix.length) {
return finalPrefix + separator + '{' + oldRemainingPath + ' → ' + newRemainingPath + '}'; return finalPrefix + separator + "{" + oldRemainingPath + " → " + newRemainingPath + "}";
} else if (finalSuffix.length) { } else if (finalSuffix.length) {
return '{' + oldRemainingPath + ' → ' + newRemainingPath + '}' + separator + finalSuffix; return "{" + oldRemainingPath + " → " + newRemainingPath + "}" + separator + finalSuffix;
} }
return oldFilename + ' → ' + newFilename; return oldFilename + " → " + newFilename;
} else if (newFilename && !isDevNullName(newFilename)) { } else if (newFilename && !isDevNullName(newFilename)) {
return newFilename; return newFilename;
} else if (oldFilename) { } else if (oldFilename) {
return oldFilename; return oldFilename;
} }
return 'unknown/file/path'; return "unknown/file/path";
}; };
PrinterUtils.prototype.getFileTypeIcon = function(file) { PrinterUtils.prototype.getFileTypeIcon = function(file) {
var templateName = 'file-changed'; let templateName = "file-changed";
if (file.isRename) { if (file.isRename) {
templateName = 'file-renamed'; templateName = "file-renamed";
} else if (file.isCopy) { } else if (file.isCopy) {
templateName = 'file-renamed'; templateName = "file-renamed";
} else if (file.isNew) { } else if (file.isNew) {
templateName = 'file-added'; templateName = "file-added";
} else if (file.isDeleted) { } else if (file.isDeleted) {
templateName = 'file-deleted'; templateName = "file-deleted";
} else if (file.newName !== file.oldName) { } else if (file.newName !== file.oldName) {
// If file is not Added, not Deleted and the names changed it must be a rename :) // If file is not Added, not Deleted and the names changed it must be a rename :)
templateName = 'file-renamed'; templateName = "file-renamed";
} }
return templateName; return templateName;
}; };
PrinterUtils.prototype.diffHighlight = function(diffLine1, diffLine2, config) { PrinterUtils.prototype.diffHighlight = function(diffLine1, diffLine2, config) {
var linePrefix1, linePrefix2, unprefixedLine1, unprefixedLine2; let linePrefix1, linePrefix2, unprefixedLine1, unprefixedLine2;
var prefixSize = 1; let prefixSize = 1;
if (config.isCombined) { if (config.isCombined) {
prefixSize = 2; prefixSize = 2;
@ -144,8 +156,10 @@
unprefixedLine1 = diffLine1.substr(prefixSize); unprefixedLine1 = diffLine1.substr(prefixSize);
unprefixedLine2 = diffLine2.substr(prefixSize); unprefixedLine2 = diffLine2.substr(prefixSize);
if (unprefixedLine1.length > config.maxLineLengthHighlight || if (
unprefixedLine2.length > config.maxLineLengthHighlight) { unprefixedLine1.length > config.maxLineLengthHighlight ||
unprefixedLine2.length > config.maxLineLengthHighlight
) {
return { return {
first: { first: {
prefix: linePrefix1, prefix: linePrefix1,
@ -158,42 +172,42 @@
}; };
} }
var diff; let diff;
if (config.diffStyle === 'char') { if (config.diffStyle === "char") {
diff = jsDiff.diffChars(unprefixedLine1, unprefixedLine2); diff = jsDiff.diffChars(unprefixedLine1, unprefixedLine2);
} else { } else {
diff = jsDiff.diffWordsWithSpace(unprefixedLine1, unprefixedLine2); diff = jsDiff.diffWordsWithSpace(unprefixedLine1, unprefixedLine2);
} }
var highlightedLine = ''; let highlightedLine = "";
var changedWords = []; const changedWords = [];
if (config.diffStyle === 'word' && config.matching === 'words') { if (config.diffStyle === "word" && config.matching === "words") {
var treshold = 0.25; let treshold = 0.25;
if (typeof (config.matchWordsThreshold) !== 'undefined') { if (typeof config.matchWordsThreshold !== "undefined") {
treshold = config.matchWordsThreshold; treshold = config.matchWordsThreshold;
} }
var matcher = Rematch.rematch(function(a, b) { const matcher = Rematch.rematch(function(a, b) {
var amod = a.value; const amod = a.value;
var bmod = b.value; const bmod = b.value;
return Rematch.distance(amod, bmod); return Rematch.distance(amod, bmod);
}); });
var removed = diff.filter(function isRemoved(element) { const removed = diff.filter(function isRemoved(element) {
return element.removed; return element.removed;
}); });
var added = diff.filter(function isAdded(element) { const added = diff.filter(function isAdded(element) {
return element.added; return element.added;
}); });
var chunks = matcher(added, removed); const chunks = matcher(added, removed);
chunks.forEach(function(chunk) { chunks.forEach(function(chunk) {
if (chunk[0].length === 1 && chunk[1].length === 1) { if (chunk[0].length === 1 && chunk[1].length === 1) {
var dist = Rematch.distance(chunk[0][0].value, chunk[1][0].value); const dist = Rematch.distance(chunk[0][0].value, chunk[1][0].value);
if (dist < treshold) { if (dist < treshold) {
changedWords.push(chunk[0][0]); changedWords.push(chunk[0][0]);
changedWords.push(chunk[1][0]); changedWords.push(chunk[1][0]);
@ -203,12 +217,12 @@
} }
diff.forEach(function(part) { diff.forEach(function(part) {
var addClass = changedWords.indexOf(part) > -1 ? ' class="d2h-change"' : ''; const addClass = changedWords.indexOf(part) > -1 ? ' class="d2h-change"' : "";
var elemType = part.added ? 'ins' : part.removed ? 'del' : null; const elemType = part.added ? "ins" : part.removed ? "del" : null;
var escapedValue = utils.escape(part.value); const escapedValue = utils.escape(part.value);
if (elemType !== null) { if (elemType !== null) {
highlightedLine += '<' + elemType + addClass + '>' + escapedValue + '</' + elemType + '>'; highlightedLine += "<" + elemType + addClass + ">" + escapedValue + "</" + elemType + ">";
} else { } else {
highlightedLine += escapedValue; highlightedLine += escapedValue;
} }
@ -228,22 +242,22 @@
function unifyPath(path) { function unifyPath(path) {
if (path) { if (path) {
return path.replace('\\', '/'); return path.replace("\\", "/");
} }
return path; return path;
} }
function isDevNullName(name) { function isDevNullName(name) {
return name.indexOf('dev/null') !== -1; return name.indexOf("dev/null") !== -1;
} }
function removeIns(line) { function removeIns(line) {
return line.replace(/(<ins[^>]*>((.|\n)*?)<\/ins>)/g, ''); return line.replace(/(<ins[^>]*>((.|\n)*?)<\/ins>)/g, "");
} }
function removeDel(line) { function removeDel(line) {
return line.replace(/(<del[^>]*>((.|\n)*?)<\/del>)/g, ''); return line.replace(/(<del[^>]*>((.|\n)*?)<\/del>)/g, "");
} }
module.exports.PrinterUtils = new PrinterUtils(); module.exports.PrinterUtils = new PrinterUtils();

View file

@ -7,7 +7,7 @@
*/ */
(function() { (function() {
var Rematch = {}; const Rematch = {};
/* /*
Copyright (c) 2011 Andrei Mackenzie Copyright (c) 2011 Andrei Mackenzie
@ -29,16 +29,16 @@
return a.length; return a.length;
} }
var matrix = []; const matrix = [];
// Increment along the first column of each row // Increment along the first column of each row
var i; let i;
for (i = 0; i <= b.length; i++) { for (i = 0; i <= b.length; i++) {
matrix[i] = [i]; matrix[i] = [i];
} }
// Increment each column in the first row // Increment each column in the first row
var j; let j;
for (j = 0; j <= a.length; j++) { for (j = 0; j <= a.length; j++) {
matrix[0][j] = j; matrix[0][j] = j;
} }
@ -49,9 +49,13 @@
if (b.charAt(i - 1) === a.charAt(j - 1)) { if (b.charAt(i - 1) === a.charAt(j - 1)) {
matrix[i][j] = matrix[i - 1][j - 1]; matrix[i][j] = matrix[i - 1][j - 1];
} else { } else {
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // Substitution matrix[i][j] = Math.min(
Math.min(matrix[i][j - 1] + 1, // Insertion matrix[i - 1][j - 1] + 1, // Substitution
matrix[i - 1][j] + 1)); // Deletion Math.min(
matrix[i][j - 1] + 1, // Insertion
matrix[i - 1][j] + 1
)
); // Deletion
} }
} }
} }
@ -64,19 +68,19 @@
Rematch.distance = function distance(x, y) { Rematch.distance = function distance(x, y) {
x = x.trim(); x = x.trim();
y = y.trim(); y = y.trim();
var lev = levenshtein(x, y); const lev = levenshtein(x, y);
var score = lev / (x.length + y.length); const score = lev / (x.length + y.length);
return score; return score;
}; };
Rematch.rematch = function rematch(distanceFunction) { Rematch.rematch = function rematch(distanceFunction) {
function findBestMatch(a, b, cache) { function findBestMatch(a, b, cache) {
var bestMatchDist = Infinity; let bestMatchDist = Infinity;
var bestMatch; let bestMatch;
for (var i = 0; i < a.length; ++i) { for (let i = 0; i < a.length; ++i) {
for (var j = 0; j < b.length; ++j) { for (let j = 0; j < b.length; ++j) {
var cacheKey = JSON.stringify([a[i], b[j]]); const cacheKey = JSON.stringify([a[i], b[j]]);
var md; var md;
if (cache.hasOwnProperty(cacheKey)) { if (cache.hasOwnProperty(cacheKey)) {
md = cache[cacheKey]; md = cache[cacheKey];
@ -95,33 +99,33 @@
} }
function group(a, b, level, cache) { function group(a, b, level, cache) {
if (typeof (cache) === 'undefined') { if (typeof cache === "undefined") {
cache = {}; cache = {};
} }
var bm = findBestMatch(a, b, cache); const bm = findBestMatch(a, b, cache);
if (!level) { if (!level) {
level = 0; level = 0;
} }
if (!bm || (a.length + b.length < 3)) { if (!bm || a.length + b.length < 3) {
return [[a, b]]; return [[a, b]];
} }
var a1 = a.slice(0, bm.indexA); const a1 = a.slice(0, bm.indexA);
var b1 = b.slice(0, bm.indexB); const b1 = b.slice(0, bm.indexB);
var aMatch = [a[bm.indexA]]; const aMatch = [a[bm.indexA]];
var bMatch = [b[bm.indexB]]; const bMatch = [b[bm.indexB]];
var tailA = bm.indexA + 1; const tailA = bm.indexA + 1;
var tailB = bm.indexB + 1; const tailB = bm.indexB + 1;
var a2 = a.slice(tailA); const a2 = a.slice(tailA);
var b2 = b.slice(tailB); const b2 = b.slice(tailB);
var group1 = group(a1, b1, level + 1, cache); const group1 = group(a1, b1, level + 1, cache);
var groupMatch = group(aMatch, bMatch, level + 1, cache); const groupMatch = group(aMatch, bMatch, level + 1, cache);
var group2 = group(a2, b2, level + 1, cache); const group2 = group(a2, b2, level + 1, cache);
var result = groupMatch; let result = groupMatch;
if (bm.indexA > 0 || bm.indexB > 0) { if (bm.indexA > 0 || bm.indexB > 0) {
result = group1.concat(result); result = group1.concat(result);

View file

@ -6,21 +6,21 @@
*/ */
(function() { (function() {
var diffParser = require('./diff-parser.js').DiffParser; const diffParser = require("./diff-parser.js").DiffParser;
var printerUtils = require('./printer-utils.js').PrinterUtils; const printerUtils = require("./printer-utils.js").PrinterUtils;
var utils = require('./utils.js').Utils; const utils = require("./utils.js").Utils;
var Rematch = require('./rematch.js').Rematch; const Rematch = require("./rematch.js").Rematch;
var hoganUtils; let hoganUtils;
var genericTemplatesPath = 'generic'; const genericTemplatesPath = "generic";
var baseTemplatesPath = 'side-by-side'; const baseTemplatesPath = "side-by-side";
var iconsBaseTemplatesPath = 'icon'; const iconsBaseTemplatesPath = "icon";
var tagsBaseTemplatesPath = 'tag'; const tagsBaseTemplatesPath = "tag";
var matcher = Rematch.rematch(function(a, b) { const matcher = Rematch.rematch(function(a, b) {
var amod = a.content.substr(1); const amod = a.content.substr(1);
var bmod = b.content.substr(1); const bmod = b.content.substr(1);
return Rematch.distance(amod, bmod); return Rematch.distance(amod, bmod);
}); });
@ -28,34 +28,38 @@
function SideBySidePrinter(config) { function SideBySidePrinter(config) {
this.config = config; this.config = config;
var HoganJsUtils = require('./hoganjs-utils.js').HoganJsUtils; const HoganJsUtils = require("./hoganjs-utils.js").HoganJsUtils;
hoganUtils = new HoganJsUtils(config); hoganUtils = new HoganJsUtils(config);
} }
SideBySidePrinter.prototype.makeDiffHtml = function(file, diffs) { SideBySidePrinter.prototype.makeDiffHtml = function(file, diffs) {
var fileDiffTemplate = hoganUtils.template(baseTemplatesPath, 'file-diff'); const fileDiffTemplate = hoganUtils.template(baseTemplatesPath, "file-diff");
var filePathTemplate = hoganUtils.template(genericTemplatesPath, 'file-path'); const filePathTemplate = hoganUtils.template(genericTemplatesPath, "file-path");
var fileIconTemplate = hoganUtils.template(iconsBaseTemplatesPath, 'file'); const fileIconTemplate = hoganUtils.template(iconsBaseTemplatesPath, "file");
var fileTagTemplate = hoganUtils.template(tagsBaseTemplatesPath, printerUtils.getFileTypeIcon(file)); const fileTagTemplate = hoganUtils.template(tagsBaseTemplatesPath, printerUtils.getFileTypeIcon(file));
return fileDiffTemplate.render({ return fileDiffTemplate.render({
file: file, file: file,
fileHtmlId: printerUtils.getHtmlId(file), fileHtmlId: printerUtils.getHtmlId(file),
diffs: diffs, diffs: diffs,
filePath: filePathTemplate.render({ filePath: filePathTemplate.render(
{
fileDiffName: printerUtils.getDiffName(file) fileDiffName: printerUtils.getDiffName(file)
}, { },
{
fileIcon: fileIconTemplate, fileIcon: fileIconTemplate,
fileTag: fileTagTemplate fileTag: fileTagTemplate
}) }
)
}); });
}; };
SideBySidePrinter.prototype.generateSideBySideJsonHtml = function(diffFiles) { SideBySidePrinter.prototype.generateSideBySideJsonHtml = function(diffFiles) {
var that = this; const that = this;
var content = diffFiles.map(function(file) { const content = diffFiles
var diffs; .map(function(file) {
let diffs;
if (file.blocks.length) { if (file.blocks.length) {
diffs = that.generateSideBySideFileHtml(file); diffs = that.generateSideBySideFileHtml(file);
} else { } else {
@ -63,47 +67,52 @@
} }
return that.makeDiffHtml(file, diffs); return that.makeDiffHtml(file, diffs);
}).join('\n'); })
.join("\n");
return hoganUtils.render(genericTemplatesPath, 'wrapper', {'content': content}); return hoganUtils.render(genericTemplatesPath, "wrapper", { content: content });
}; };
SideBySidePrinter.prototype.makeSideHtml = function(blockHeader) { SideBySidePrinter.prototype.makeSideHtml = function(blockHeader) {
return hoganUtils.render(genericTemplatesPath, 'column-line-number', { return hoganUtils.render(genericTemplatesPath, "column-line-number", {
diffParser: diffParser, diffParser: diffParser,
blockHeader: utils.escape(blockHeader), blockHeader: utils.escape(blockHeader),
lineClass: 'd2h-code-side-linenumber', lineClass: "d2h-code-side-linenumber",
contentClass: 'd2h-code-side-line' contentClass: "d2h-code-side-line"
}); });
}; };
SideBySidePrinter.prototype.generateSideBySideFileHtml = function(file) { SideBySidePrinter.prototype.generateSideBySideFileHtml = function(file) {
var that = this; const that = this;
var fileHtml = {}; const fileHtml = {};
fileHtml.left = ''; fileHtml.left = "";
fileHtml.right = ''; fileHtml.right = "";
file.blocks.forEach(function(block) { file.blocks.forEach(function(block) {
fileHtml.left += that.makeSideHtml(block.header); fileHtml.left += that.makeSideHtml(block.header);
fileHtml.right += that.makeSideHtml(''); fileHtml.right += that.makeSideHtml("");
var oldLines = []; let oldLines = [];
var newLines = []; let newLines = [];
function processChangeBlock() { function processChangeBlock() {
var matches; let matches;
var insertType; let insertType;
var deleteType; let deleteType;
var comparisons = oldLines.length * newLines.length; const comparisons = oldLines.length * newLines.length;
var maxLineSizeInBlock = Math.max.apply(null, (oldLines.concat(newLines)).map(function(elem) { const maxLineSizeInBlock = Math.max.apply(
null,
oldLines.concat(newLines).map(function(elem) {
return elem.length; return elem.length;
})); })
);
var doMatching = comparisons < that.config.matchingMaxComparisons && const doMatching =
comparisons < that.config.matchingMaxComparisons &&
maxLineSizeInBlock < that.config.maxLineSizeInBlockForComparison && maxLineSizeInBlock < that.config.maxLineSizeInBlockForComparison &&
(that.config.matching === 'lines' || that.config.matching === 'words'); (that.config.matching === "lines" || that.config.matching === "words");
if (doMatching) { if (doMatching) {
matches = matcher(oldLines, newLines); matches = matcher(oldLines, newLines);
@ -119,30 +128,38 @@
oldLines = match[0]; oldLines = match[0];
newLines = match[1]; newLines = match[1];
var common = Math.min(oldLines.length, newLines.length); const common = Math.min(oldLines.length, newLines.length);
var max = Math.max(oldLines.length, newLines.length); const max = Math.max(oldLines.length, newLines.length);
for (var j = 0; j < common; j++) { for (let j = 0; j < common; j++) {
var oldLine = oldLines[j]; const oldLine = oldLines[j];
var newLine = newLines[j]; const newLine = newLines[j];
that.config.isCombined = file.isCombined; that.config.isCombined = file.isCombined;
var diff = printerUtils.diffHighlight(oldLine.content, newLine.content, that.config); const diff = printerUtils.diffHighlight(oldLine.content, newLine.content, that.config);
fileHtml.left += fileHtml.left += that.generateSingleLineHtml(
that.generateSingleLineHtml(file.isCombined, deleteType, oldLine.oldNumber, file.isCombined,
diff.first.line, diff.first.prefix); deleteType,
fileHtml.right += oldLine.oldNumber,
that.generateSingleLineHtml(file.isCombined, insertType, newLine.newNumber, diff.first.line,
diff.second.line, diff.second.prefix); diff.first.prefix
);
fileHtml.right += that.generateSingleLineHtml(
file.isCombined,
insertType,
newLine.newNumber,
diff.second.line,
diff.second.prefix
);
} }
if (max > common) { if (max > common) {
var oldSlice = oldLines.slice(common); const oldSlice = oldLines.slice(common);
var newSlice = newLines.slice(common); const newSlice = newLines.slice(common);
var tmpHtml = that.processLines(file.isCombined, oldSlice, newSlice); const tmpHtml = that.processLines(file.isCombined, oldSlice, newSlice);
fileHtml.left += tmpHtml.left; fileHtml.left += tmpHtml.left;
fileHtml.right += tmpHtml.right; fileHtml.right += tmpHtml.right;
} }
@ -152,28 +169,42 @@
newLines = []; newLines = [];
} }
for (var i = 0; i < block.lines.length; i++) { for (let i = 0; i < block.lines.length; i++) {
var line = block.lines[i]; const line = block.lines[i];
var prefix = line.content[0]; const prefix = line.content[0];
var escapedLine = utils.escape(line.content.substr(1)); const escapedLine = utils.escape(line.content.substr(1));
if (line.type !== diffParser.LINE_TYPE.INSERTS && if (
(newLines.length > 0 || (line.type !== diffParser.LINE_TYPE.DELETES && oldLines.length > 0))) { line.type !== diffParser.LINE_TYPE.INSERTS &&
(newLines.length > 0 || (line.type !== diffParser.LINE_TYPE.DELETES && oldLines.length > 0))
) {
processChangeBlock(); processChangeBlock();
} }
if (line.type === diffParser.LINE_TYPE.CONTEXT) { if (line.type === diffParser.LINE_TYPE.CONTEXT) {
fileHtml.left += that.generateSingleLineHtml(file.isCombined, line.type, line.oldNumber, escapedLine, prefix); fileHtml.left += that.generateSingleLineHtml(file.isCombined, line.type, line.oldNumber, escapedLine, prefix);
fileHtml.right += that.generateSingleLineHtml(file.isCombined, line.type, line.newNumber, escapedLine, prefix); fileHtml.right += that.generateSingleLineHtml(
file.isCombined,
line.type,
line.newNumber,
escapedLine,
prefix
);
} else if (line.type === diffParser.LINE_TYPE.INSERTS && !oldLines.length) { } else if (line.type === diffParser.LINE_TYPE.INSERTS && !oldLines.length) {
fileHtml.left += that.generateSingleLineHtml(file.isCombined, diffParser.LINE_TYPE.CONTEXT, '', '', ''); fileHtml.left += that.generateSingleLineHtml(file.isCombined, diffParser.LINE_TYPE.CONTEXT, "", "", "");
fileHtml.right += that.generateSingleLineHtml(file.isCombined, line.type, line.newNumber, escapedLine, prefix); fileHtml.right += that.generateSingleLineHtml(
file.isCombined,
line.type,
line.newNumber,
escapedLine,
prefix
);
} else if (line.type === diffParser.LINE_TYPE.DELETES) { } else if (line.type === diffParser.LINE_TYPE.DELETES) {
oldLines.push(line); oldLines.push(line);
} else if (line.type === diffParser.LINE_TYPE.INSERTS && Boolean(oldLines.length)) { } else if (line.type === diffParser.LINE_TYPE.INSERTS && Boolean(oldLines.length)) {
newLines.push(line); newLines.push(line);
} else { } else {
console.error('unknown state in html side-by-side generator'); console.error("unknown state in html side-by-side generator");
processChangeBlock(); processChangeBlock();
} }
} }
@ -185,15 +216,15 @@
}; };
SideBySidePrinter.prototype.processLines = function(isCombined, oldLines, newLines) { SideBySidePrinter.prototype.processLines = function(isCombined, oldLines, newLines) {
var that = this; const that = this;
var fileHtml = {}; const fileHtml = {};
fileHtml.left = ''; fileHtml.left = "";
fileHtml.right = ''; fileHtml.right = "";
var maxLinesNumber = Math.max(oldLines.length, newLines.length); const maxLinesNumber = Math.max(oldLines.length, newLines.length);
for (var i = 0; i < maxLinesNumber; i++) { for (let i = 0; i < maxLinesNumber; i++) {
var oldLine = oldLines[i]; const oldLine = oldLines[i];
var newLine = newLines[i]; const newLine = newLines[i];
var oldContent; var oldContent;
var newContent; var newContent;
var oldPrefix; var oldPrefix;
@ -210,16 +241,40 @@
} }
if (oldLine && newLine) { if (oldLine && newLine) {
fileHtml.left += that.generateSingleLineHtml(isCombined, oldLine.type, oldLine.oldNumber, oldContent, oldPrefix); fileHtml.left += that.generateSingleLineHtml(
fileHtml.right += that.generateSingleLineHtml(isCombined, newLine.type, newLine.newNumber, newContent, newPrefix); isCombined,
oldLine.type,
oldLine.oldNumber,
oldContent,
oldPrefix
);
fileHtml.right += that.generateSingleLineHtml(
isCombined,
newLine.type,
newLine.newNumber,
newContent,
newPrefix
);
} else if (oldLine) { } else if (oldLine) {
fileHtml.left += that.generateSingleLineHtml(isCombined, oldLine.type, oldLine.oldNumber, oldContent, oldPrefix); fileHtml.left += that.generateSingleLineHtml(
fileHtml.right += that.generateSingleLineHtml(isCombined, diffParser.LINE_TYPE.CONTEXT, '', '', ''); isCombined,
oldLine.type,
oldLine.oldNumber,
oldContent,
oldPrefix
);
fileHtml.right += that.generateSingleLineHtml(isCombined, diffParser.LINE_TYPE.CONTEXT, "", "", "");
} else if (newLine) { } else if (newLine) {
fileHtml.left += that.generateSingleLineHtml(isCombined, diffParser.LINE_TYPE.CONTEXT, '', '', ''); fileHtml.left += that.generateSingleLineHtml(isCombined, diffParser.LINE_TYPE.CONTEXT, "", "", "");
fileHtml.right += that.generateSingleLineHtml(isCombined, newLine.type, newLine.newNumber, newContent, newPrefix); fileHtml.right += that.generateSingleLineHtml(
isCombined,
newLine.type,
newLine.newNumber,
newContent,
newPrefix
);
} else { } else {
console.error('How did it get here?'); console.error("How did it get here?");
} }
} }
@ -227,29 +282,28 @@
}; };
SideBySidePrinter.prototype.generateSingleLineHtml = function(isCombined, type, number, content, possiblePrefix) { SideBySidePrinter.prototype.generateSingleLineHtml = function(isCombined, type, number, content, possiblePrefix) {
var lineWithoutPrefix = content; let lineWithoutPrefix = content;
var prefix = possiblePrefix; let prefix = possiblePrefix;
var lineClass = 'd2h-code-side-linenumber'; let lineClass = "d2h-code-side-linenumber";
var contentClass = 'd2h-code-side-line'; let contentClass = "d2h-code-side-line";
if (!number && !content) { if (!number && !content) {
lineClass += ' d2h-code-side-emptyplaceholder'; lineClass += " d2h-code-side-emptyplaceholder";
contentClass += ' d2h-code-side-emptyplaceholder'; contentClass += " d2h-code-side-emptyplaceholder";
type += ' d2h-emptyplaceholder'; type += " d2h-emptyplaceholder";
prefix = '&nbsp;'; prefix = "&nbsp;";
lineWithoutPrefix = '&nbsp;'; lineWithoutPrefix = "&nbsp;";
} else if (!prefix) { } else if (!prefix) {
var lineWithPrefix = printerUtils.separatePrefix(isCombined, content); const lineWithPrefix = printerUtils.separatePrefix(isCombined, content);
prefix = lineWithPrefix.prefix; prefix = lineWithPrefix.prefix;
lineWithoutPrefix = lineWithPrefix.line; lineWithoutPrefix = lineWithPrefix.line;
} }
if (prefix === ' ') { if (prefix === " ") {
prefix = '&nbsp;'; prefix = "&nbsp;";
} }
return hoganUtils.render(genericTemplatesPath, 'line', return hoganUtils.render(genericTemplatesPath, "line", {
{
type: type, type: type,
lineClass: lineClass, lineClass: lineClass,
contentClass: contentClass, contentClass: contentClass,
@ -260,11 +314,11 @@
}; };
SideBySidePrinter.prototype.generateEmptyDiff = function() { SideBySidePrinter.prototype.generateEmptyDiff = function() {
var fileHtml = {}; const fileHtml = {};
fileHtml.right = ''; fileHtml.right = "";
fileHtml.left = hoganUtils.render(genericTemplatesPath, 'empty-diff', { fileHtml.left = hoganUtils.render(genericTemplatesPath, "empty-diff", {
contentClass: 'd2h-code-side-line', contentClass: "d2h-code-side-line",
diffParser: diffParser diffParser: diffParser
}); });

View file

@ -1,23 +0,0 @@
(function() {
if (!!!global.browserTemplates) global.browserTemplates = {};
var Hogan = require("hogan.js");global.browserTemplates["file-summary-line"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<li class=\"d2h-file-list-line\">");t.b("\n" + i);t.b(" <span class=\"d2h-file-name-wrapper\">");t.b("\n" + i);t.b(t.rp("<fileIcon0",c,p," "));t.b(" <a href=\"#");t.b(t.v(t.f("fileHtmlId",c,p,0)));t.b("\" class=\"d2h-file-name\">");t.b(t.v(t.f("fileName",c,p,0)));t.b("</a>");t.b("\n" + i);t.b(" <span class=\"d2h-file-stats\">");t.b("\n" + i);t.b(" <span class=\"d2h-lines-added\">");t.b(t.v(t.f("addedLines",c,p,0)));t.b("</span>");t.b("\n" + i);t.b(" <span class=\"d2h-lines-deleted\">");t.b(t.v(t.f("deletedLines",c,p,0)));t.b("</span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b("</li>");return t.fl(); },partials: {"<fileIcon0":{name:"fileIcon", partials: {}, subs: { }}}, subs: { }});
global.browserTemplates["file-summary-wrapper"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<div class=\"d2h-file-list-wrapper\">");t.b("\n" + i);t.b(" <div class=\"d2h-file-list-header\">");t.b("\n" + i);t.b(" <span class=\"d2h-file-list-title\">Files changed (");t.b(t.v(t.f("filesNumber",c,p,0)));t.b(")</span>");t.b("\n" + i);t.b(" <a class=\"d2h-file-switch d2h-hide\">hide</a>");t.b("\n" + i);t.b(" <a class=\"d2h-file-switch d2h-show\">show</a>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" <ol class=\"d2h-file-list\">");t.b("\n" + i);t.b(" ");t.b(t.t(t.f("files",c,p,0)));t.b("\n" + i);t.b(" </ol>");t.b("\n" + i);t.b("</div>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["generic-column-line-number"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<tr>");t.b("\n" + i);t.b(" <td class=\"");t.b(t.v(t.f("lineClass",c,p,0)));t.b(" ");t.b(t.v(t.d("diffParser.LINE_TYPE.INFO",c,p,0)));t.b("\"></td>");t.b("\n" + i);t.b(" <td class=\"");t.b(t.v(t.d("diffParser.LINE_TYPE.INFO",c,p,0)));t.b("\">");t.b("\n" + i);t.b(" <div class=\"");t.b(t.v(t.f("contentClass",c,p,0)));t.b(" ");t.b(t.v(t.d("diffParser.LINE_TYPE.INFO",c,p,0)));t.b("\">");t.b(t.t(t.f("blockHeader",c,p,0)));t.b("</div>");t.b("\n" + i);t.b(" </td>");t.b("\n" + i);t.b("</tr>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["generic-empty-diff"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<tr>");t.b("\n" + i);t.b(" <td class=\"");t.b(t.v(t.d("diffParser.LINE_TYPE.INFO",c,p,0)));t.b("\">");t.b("\n" + i);t.b(" <div class=\"");t.b(t.v(t.f("contentClass",c,p,0)));t.b(" ");t.b(t.v(t.d("diffParser.LINE_TYPE.INFO",c,p,0)));t.b("\">");t.b("\n" + i);t.b(" File without changes");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" </td>");t.b("\n" + i);t.b("</tr>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["generic-file-path"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<span class=\"d2h-file-name-wrapper\">");t.b("\n" + i);t.b(t.rp("<fileIcon0",c,p," "));t.b(" <span class=\"d2h-file-name\">");t.b(t.v(t.f("fileDiffName",c,p,0)));t.b("</span>");t.b("\n" + i);t.b(t.rp("<fileTag1",c,p," "));t.b("</span>");return t.fl(); },partials: {"<fileIcon0":{name:"fileIcon", partials: {}, subs: { }},"<fileTag1":{name:"fileTag", partials: {}, subs: { }}}, subs: { }});
global.browserTemplates["generic-line"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<tr>");t.b("\n" + i);t.b(" <td class=\"");t.b(t.v(t.f("lineClass",c,p,0)));t.b(" ");t.b(t.v(t.f("type",c,p,0)));t.b("\">");t.b("\n" + i);t.b(" ");t.b(t.t(t.f("lineNumber",c,p,0)));t.b("\n" + i);t.b(" </td>");t.b("\n" + i);t.b(" <td class=\"");t.b(t.v(t.f("type",c,p,0)));t.b("\">");t.b("\n" + i);t.b(" <div class=\"");t.b(t.v(t.f("contentClass",c,p,0)));t.b(" ");t.b(t.v(t.f("type",c,p,0)));t.b("\">");t.b("\n" + i);if(t.s(t.f("prefix",c,p,1),c,p,0,171,247,"{{ }}")){t.rs(c,p,function(c,p,t){t.b(" <span class=\"d2h-code-line-prefix\">");t.b(t.t(t.f("prefix",c,p,0)));t.b("</span>");t.b("\n" + i);});c.pop();}if(t.s(t.f("content",c,p,1),c,p,0,279,353,"{{ }}")){t.rs(c,p,function(c,p,t){t.b(" <span class=\"d2h-code-line-ctn\">");t.b(t.t(t.f("content",c,p,0)));t.b("</span>");t.b("\n" + i);});c.pop();}t.b(" </div>");t.b("\n" + i);t.b(" </td>");t.b("\n" + i);t.b("</tr>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["generic-wrapper"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<div class=\"d2h-wrapper\">");t.b("\n" + i);t.b(" ");t.b(t.t(t.f("content",c,p,0)));t.b("\n" + i);t.b("</div>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["icon-file-added"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<svg aria-hidden=\"true\" class=\"d2h-icon d2h-added\" height=\"16\" title=\"added\" version=\"1.1\" viewBox=\"0 0 14 16\"");t.b("\n" + i);t.b(" width=\"14\">");t.b("\n" + i);t.b(" <path d=\"M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM6 9H3V7h3V4h2v3h3v2H8v3H6V9z\"></path>");t.b("\n" + i);t.b("</svg>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["icon-file-changed"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<svg aria-hidden=\"true\" class=\"d2h-icon d2h-changed\" height=\"16\" title=\"modified\" version=\"1.1\"");t.b("\n" + i);t.b(" viewBox=\"0 0 14 16\" width=\"14\">");t.b("\n" + i);t.b(" <path d=\"M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM4 8c0-1.66 1.34-3 3-3s3 1.34 3 3-1.34 3-3 3-3-1.34-3-3z\"></path>");t.b("\n" + i);t.b("</svg>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["icon-file-deleted"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<svg aria-hidden=\"true\" class=\"d2h-icon d2h-deleted\" height=\"16\" title=\"removed\" version=\"1.1\"");t.b("\n" + i);t.b(" viewBox=\"0 0 14 16\" width=\"14\">");t.b("\n" + i);t.b(" <path d=\"M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM11 9H3V7h8v2z\"></path>");t.b("\n" + i);t.b("</svg>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["icon-file-renamed"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<svg aria-hidden=\"true\" class=\"d2h-icon d2h-moved\" height=\"16\" title=\"renamed\" version=\"1.1\"");t.b("\n" + i);t.b(" viewBox=\"0 0 14 16\" width=\"14\">");t.b("\n" + i);t.b(" <path d=\"M6 9H3V7h3V4l5 4-5 4V9z m8-7v12c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h12c0.55 0 1 0.45 1 1z m-1 0H1v12h12V2z\"></path>");t.b("\n" + i);t.b("</svg>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["icon-file"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<svg aria-hidden=\"true\" class=\"d2h-icon\" height=\"16\" version=\"1.1\" viewBox=\"0 0 12 16\" width=\"12\">");t.b("\n" + i);t.b(" <path d=\"M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z\"></path>");t.b("\n" + i);t.b("</svg>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["line-by-line-file-diff"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<div id=\"");t.b(t.v(t.f("fileHtmlId",c,p,0)));t.b("\" class=\"d2h-file-wrapper\" data-lang=\"");t.b(t.v(t.d("file.language",c,p,0)));t.b("\">");t.b("\n" + i);t.b(" <div class=\"d2h-file-header\">");t.b("\n" + i);t.b(" ");t.b(t.t(t.f("filePath",c,p,0)));t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" <div class=\"d2h-file-diff\">");t.b("\n" + i);t.b(" <div class=\"d2h-code-wrapper\">");t.b("\n" + i);t.b(" <table class=\"d2h-diff-table\">");t.b("\n" + i);t.b(" <tbody class=\"d2h-diff-tbody\">");t.b("\n" + i);t.b(" ");t.b(t.t(t.f("diffs",c,p,0)));t.b("\n" + i);t.b(" </tbody>");t.b("\n" + i);t.b(" </table>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b("</div>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["line-by-line-numbers"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<div class=\"line-num1\">");t.b(t.v(t.f("oldNumber",c,p,0)));t.b("</div>");t.b("\n" + i);t.b("<div class=\"line-num2\">");t.b(t.v(t.f("newNumber",c,p,0)));t.b("</div>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["side-by-side-file-diff"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<div id=\"");t.b(t.v(t.f("fileHtmlId",c,p,0)));t.b("\" class=\"d2h-file-wrapper\" data-lang=\"");t.b(t.v(t.d("file.language",c,p,0)));t.b("\">");t.b("\n" + i);t.b(" <div class=\"d2h-file-header\">");t.b("\n" + i);t.b(" ");t.b(t.t(t.f("filePath",c,p,0)));t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" <div class=\"d2h-files-diff\">");t.b("\n" + i);t.b(" <div class=\"d2h-file-side-diff\">");t.b("\n" + i);t.b(" <div class=\"d2h-code-wrapper\">");t.b("\n" + i);t.b(" <table class=\"d2h-diff-table\">");t.b("\n" + i);t.b(" <tbody class=\"d2h-diff-tbody\">");t.b("\n" + i);t.b(" ");t.b(t.t(t.d("diffs.left",c,p,0)));t.b("\n" + i);t.b(" </tbody>");t.b("\n" + i);t.b(" </table>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" <div class=\"d2h-file-side-diff\">");t.b("\n" + i);t.b(" <div class=\"d2h-code-wrapper\">");t.b("\n" + i);t.b(" <table class=\"d2h-diff-table\">");t.b("\n" + i);t.b(" <tbody class=\"d2h-diff-tbody\">");t.b("\n" + i);t.b(" ");t.b(t.t(t.d("diffs.right",c,p,0)));t.b("\n" + i);t.b(" </tbody>");t.b("\n" + i);t.b(" </table>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b("</div>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["tag-file-added"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<span class=\"d2h-tag d2h-added d2h-added-tag\">ADDED</span>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["tag-file-changed"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<span class=\"d2h-tag d2h-changed d2h-changed-tag\">CHANGED</span>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["tag-file-deleted"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<span class=\"d2h-tag d2h-deleted d2h-deleted-tag\">DELETED</span>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["tag-file-renamed"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<span class=\"d2h-tag d2h-moved d2h-moved-tag\">RENAMED</span>");return t.fl(); },partials: {}, subs: { }});
module.exports = global.browserTemplates;
})();

View file

@ -11,14 +11,14 @@
/* global $, hljs, Diff2Html */ /* global $, hljs, Diff2Html */
(function() { (function() {
var highlightJS = require('./highlight.js-internals.js').HighlightJS; const highlightJS = require("./highlight.js-internals.js").HighlightJS;
var diffJson = null; let diffJson = null;
var defaultTarget = 'body'; const defaultTarget = "body";
var currentSelectionColumnId = -1; let currentSelectionColumnId = -1;
function Diff2HtmlUI(config) { function Diff2HtmlUI(config) {
var cfg = config || {}; const cfg = config || {};
if (cfg.diff) { if (cfg.diff) {
diffJson = Diff2Html.getJsonFromDiff(cfg.diff); diffJson = Diff2Html.getJsonFromDiff(cfg.diff);
@ -30,9 +30,9 @@
} }
Diff2HtmlUI.prototype.draw = function(targetId, config) { Diff2HtmlUI.prototype.draw = function(targetId, config) {
var cfg = config || {}; const cfg = config || {};
cfg.inputFormat = 'json'; cfg.inputFormat = "json";
var $target = this._getTarget(targetId); const $target = this._getTarget(targetId);
$target.html(Diff2Html.getPrettyHtml(diffJson, cfg)); $target.html(Diff2Html.getPrettyHtml(diffJson, cfg));
if (cfg.synchronisedScroll) { if (cfg.synchronisedScroll) {
@ -41,25 +41,27 @@
}; };
Diff2HtmlUI.prototype.synchronisedScroll = function(targetId) { Diff2HtmlUI.prototype.synchronisedScroll = function(targetId) {
var $target = this._getTarget(targetId); const $target = this._getTarget(targetId);
$target.find('.d2h-file-side-diff').scroll(function() { $target.find(".d2h-file-side-diff").scroll(function() {
var $this = $(this); const $this = $(this);
$this.closest('.d2h-file-wrapper').find('.d2h-file-side-diff') $this
.closest(".d2h-file-wrapper")
.find(".d2h-file-side-diff")
.scrollLeft($this.scrollLeft()); .scrollLeft($this.scrollLeft());
}); });
}; };
Diff2HtmlUI.prototype.fileListCloseable = function(targetId, startVisible) { Diff2HtmlUI.prototype.fileListCloseable = function(targetId, startVisible) {
var $target = this._getTarget(targetId); const $target = this._getTarget(targetId);
var hashTag = this._getHashTag(); const hashTag = this._getHashTag();
var $showBtn = $target.find('.d2h-show'); const $showBtn = $target.find(".d2h-show");
var $hideBtn = $target.find('.d2h-hide'); const $hideBtn = $target.find(".d2h-hide");
var $fileList = $target.find('.d2h-file-list'); const $fileList = $target.find(".d2h-file-list");
if (hashTag === 'files-summary-show') show(); if (hashTag === "files-summary-show") show();
else if (hashTag === 'files-summary-hide') hide(); else if (hashTag === "files-summary-hide") hide();
else if (startVisible) show(); else if (startVisible) show();
else hide(); else hide();
@ -80,51 +82,53 @@
}; };
Diff2HtmlUI.prototype.highlightCode = function(targetId) { Diff2HtmlUI.prototype.highlightCode = function(targetId) {
var that = this; const that = this;
var $target = that._getTarget(targetId); const $target = that._getTarget(targetId);
// collect all the diff files and execute the highlight on their lines // collect all the diff files and execute the highlight on their lines
var $files = $target.find('.d2h-file-wrapper'); const $files = $target.find(".d2h-file-wrapper");
$files.map(function(_i, file) { $files.map(function(_i, file) {
var oldLinesState; let oldLinesState;
var newLinesState; let newLinesState;
var $file = $(file); const $file = $(file);
var language = $file.data('lang'); const language = $file.data("lang");
// collect all the code lines and execute the highlight on them // collect all the code lines and execute the highlight on them
var $codeLines = $file.find('.d2h-code-line-ctn'); const $codeLines = $file.find(".d2h-code-line-ctn");
$codeLines.map(function(_j, line) { $codeLines.map(function(_j, line) {
var $line = $(line); const $line = $(line);
var text = line.textContent; const text = line.textContent;
var lineParent = line.parentNode; const lineParent = line.parentNode;
var lineState; let lineState;
if (lineParent.className.indexOf('d2h-del') !== -1) { if (lineParent.className.indexOf("d2h-del") !== -1) {
lineState = oldLinesState; lineState = oldLinesState;
} else { } else {
lineState = newLinesState; lineState = newLinesState;
} }
var result = hljs.getLanguage(language) ? hljs.highlight(language, text, true, lineState) : hljs.highlightAuto(text); const result = hljs.getLanguage(language)
? hljs.highlight(language, text, true, lineState)
: hljs.highlightAuto(text);
if (lineParent.className.indexOf('d2h-del') !== -1) { if (lineParent.className.indexOf("d2h-del") !== -1) {
oldLinesState = result.top; oldLinesState = result.top;
} else if (lineParent.className.indexOf('d2h-ins') !== -1) { } else if (lineParent.className.indexOf("d2h-ins") !== -1) {
newLinesState = result.top; newLinesState = result.top;
} else { } else {
oldLinesState = result.top; oldLinesState = result.top;
newLinesState = result.top; newLinesState = result.top;
} }
var originalStream = highlightJS.nodeStream(line); const originalStream = highlightJS.nodeStream(line);
if (originalStream.length) { if (originalStream.length) {
var resultNode = document.createElementNS('http://www.w3.org/1999/xhtml', 'div'); const resultNode = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
resultNode.innerHTML = result.value; resultNode.innerHTML = result.value;
result.value = highlightJS.mergeStreams(originalStream, highlightJS.nodeStream(resultNode), text); result.value = highlightJS.mergeStreams(originalStream, highlightJS.nodeStream(resultNode), text);
} }
$line.addClass('hljs'); $line.addClass("hljs");
$line.addClass(result.language); $line.addClass(result.language);
$line.html(result.value); $line.html(result.value);
}); });
@ -132,15 +136,15 @@
}; };
Diff2HtmlUI.prototype._getTarget = function(targetId) { Diff2HtmlUI.prototype._getTarget = function(targetId) {
var $target; let $target;
if (typeof targetId === 'object' && targetId instanceof jQuery) { if (typeof targetId === "object" && targetId instanceof jQuery) {
$target = targetId; $target = targetId;
} else if (typeof targetId === 'string') { } else if (typeof targetId === "string") {
$target = $(targetId); $target = $(targetId);
} else { } else {
console.error("Wrong target provided! Falling back to default value 'body'."); console.error("Wrong target provided! Falling back to default value 'body'.");
console.log('Please provide a jQuery object or a valid DOM query string.'); console.log("Please provide a jQuery object or a valid DOM query string.");
$target = $(defaultTarget); $target = $(defaultTarget);
} }
@ -148,10 +152,10 @@
}; };
Diff2HtmlUI.prototype._getHashTag = function() { Diff2HtmlUI.prototype._getHashTag = function() {
var docUrl = document.URL; const docUrl = document.URL;
var hashTagIndex = docUrl.indexOf('#'); const hashTagIndex = docUrl.indexOf("#");
var hashTag = null; let hashTag = null;
if (hashTagIndex !== -1) { if (hashTagIndex !== -1) {
hashTag = docUrl.substr(hashTagIndex + 1); hashTag = docUrl.substr(hashTagIndex + 1);
} }
@ -166,46 +170,46 @@
}; };
Diff2HtmlUI.prototype._initSelection = function() { Diff2HtmlUI.prototype._initSelection = function() {
var body = $('body'); const body = $("body");
var that = this; const that = this;
body.on('mousedown', '.d2h-diff-table', function(event) { body.on("mousedown", ".d2h-diff-table", function(event) {
var target = $(event.target); const target = $(event.target);
var table = target.closest('.d2h-diff-table'); const table = target.closest(".d2h-diff-table");
if (target.closest('.d2h-code-line,.d2h-code-side-line').length) { if (target.closest(".d2h-code-line,.d2h-code-side-line").length) {
table.removeClass('selecting-left'); table.removeClass("selecting-left");
table.addClass('selecting-right'); table.addClass("selecting-right");
currentSelectionColumnId = 1; currentSelectionColumnId = 1;
} else if (target.closest('.d2h-code-linenumber,.d2h-code-side-linenumber').length) { } else if (target.closest(".d2h-code-linenumber,.d2h-code-side-linenumber").length) {
table.removeClass('selecting-right'); table.removeClass("selecting-right");
table.addClass('selecting-left'); table.addClass("selecting-left");
currentSelectionColumnId = 0; currentSelectionColumnId = 0;
} }
}); });
body.on('copy', '.d2h-diff-table', function(event) { body.on("copy", ".d2h-diff-table", function(event) {
var clipboardData = event.originalEvent.clipboardData; const clipboardData = event.originalEvent.clipboardData;
var text = that._getSelectedText(); const text = that._getSelectedText();
clipboardData.setData('text', text); clipboardData.setData("text", text);
event.preventDefault(); event.preventDefault();
}); });
}; };
Diff2HtmlUI.prototype._getSelectedText = function() { Diff2HtmlUI.prototype._getSelectedText = function() {
var sel = window.getSelection(); const sel = window.getSelection();
var range = sel.getRangeAt(0); const range = sel.getRangeAt(0);
var doc = range.cloneContents(); const doc = range.cloneContents();
var nodes = doc.querySelectorAll('tr'); const nodes = doc.querySelectorAll("tr");
var text = ''; let text = "";
var idx = currentSelectionColumnId; const idx = currentSelectionColumnId;
if (nodes.length === 0) { if (nodes.length === 0) {
text = doc.textContent; text = doc.textContent;
} else { } else {
[].forEach.call(nodes, function(tr, i) { [].forEach.call(nodes, function(tr, i) {
var td = tr.cells[tr.cells.length === 1 ? 0 : idx]; const td = tr.cells[tr.cells.length === 1 ? 0 : idx];
text += (i ? '\n' : '') + td.textContent.replace(/(?:\r\n|\r|\n)/g, ''); text += (i ? "\n" : "") + td.textContent.replace(/(?:\r\n|\r|\n)/g, "");
}); });
} }

View file

@ -6,8 +6,7 @@
*/ */
(function() { (function() {
function HighlightJS() { function HighlightJS() {}
}
/* /*
* Copied from Highlight.js Private API * Copied from Highlight.js Private API
@ -16,12 +15,15 @@
/* Utility vars */ /* Utility vars */
var ArrayProto = []; const ArrayProto = [];
/* Utility functions */ /* Utility functions */
function escape(value) { function escape(value) {
return value.replace(/&/gm, '&amp;').replace(/</gm, '&lt;').replace(/>/gm, '&gt;'); return value
.replace(/&/gm, "&amp;")
.replace(/</gm, "&lt;")
.replace(/>/gm, "&gt;");
} }
function tag(node) { function tag(node) {
@ -31,14 +33,14 @@
/* Stream merging */ /* Stream merging */
HighlightJS.prototype.nodeStream = function(node) { HighlightJS.prototype.nodeStream = function(node) {
var result = []; const result = [];
(function _nodeStream(node, offset) { (function _nodeStream(node, offset) {
for (var child = node.firstChild; child; child = child.nextSibling) { for (let child = node.firstChild; child; child = child.nextSibling) {
if (child.nodeType === 3) { if (child.nodeType === 3) {
offset += child.nodeValue.length; offset += child.nodeValue.length;
} else if (child.nodeType === 1) { } else if (child.nodeType === 1) {
result.push({ result.push({
event: 'start', event: "start",
offset: offset, offset: offset,
node: child node: child
}); });
@ -48,7 +50,7 @@
// but we list only those realistically expected in code display. // but we list only those realistically expected in code display.
if (!tag(child).match(/br|hr|img|input/)) { if (!tag(child).match(/br|hr|img|input/)) {
result.push({ result.push({
event: 'stop', event: "stop",
offset: offset, offset: offset,
node: child node: child
}); });
@ -61,16 +63,16 @@
}; };
HighlightJS.prototype.mergeStreams = function(original, highlighted, value) { HighlightJS.prototype.mergeStreams = function(original, highlighted, value) {
var processed = 0; let processed = 0;
var result = ''; let result = "";
var nodeStack = []; const nodeStack = [];
function selectStream() { function selectStream() {
if (!original.length || !highlighted.length) { if (!original.length || !highlighted.length) {
return original.length ? original : highlighted; return original.length ? original : highlighted;
} }
if (original[0].offset !== highlighted[0].offset) { if (original[0].offset !== highlighted[0].offset) {
return (original[0].offset < highlighted[0].offset) ? original : highlighted; return original[0].offset < highlighted[0].offset ? original : highlighted;
} }
/* /*
@ -86,27 +88,27 @@
return highlighted; return highlighted;
... which is collapsed to: ... which is collapsed to:
*/ */
return highlighted[0].event === 'start' ? original : highlighted; return highlighted[0].event === "start" ? original : highlighted;
} }
function open(node) { function open(node) {
function attr_str(a) { function attr_str(a) {
return ' ' + a.nodeName + '="' + escape(a.value) + '"'; return " " + a.nodeName + '="' + escape(a.value) + '"';
} }
result += '<' + tag(node) + ArrayProto.map.call(node.attributes, attr_str).join('') + '>'; result += "<" + tag(node) + ArrayProto.map.call(node.attributes, attr_str).join("") + ">";
} }
function close(node) { function close(node) {
result += '</' + tag(node) + '>'; result += "</" + tag(node) + ">";
} }
function render(event) { function render(event) {
(event.event === 'start' ? open : close)(event.node); (event.event === "start" ? open : close)(event.node);
} }
while (original.length || highlighted.length) { while (original.length || highlighted.length) {
var stream = selectStream(); let stream = selectStream();
result += escape(value.substring(processed, stream[0].offset)); result += escape(value.substring(processed, stream[0].offset));
processed = stream[0].offset; processed = stream[0].offset;
if (stream === original) { if (stream === original) {
@ -123,7 +125,7 @@
} while (stream === original && stream.length && stream[0].offset === processed); } while (stream === original && stream.length && stream[0].offset === processed);
nodeStack.reverse().forEach(open); nodeStack.reverse().forEach(open);
} else { } else {
if (stream[0].event === 'start') { if (stream[0].event === "start") {
nodeStack.push(stream[0].node); nodeStack.push(stream[0].node);
} else { } else {
nodeStack.pop(); nodeStack.pop();

View file

@ -6,24 +6,24 @@
*/ */
(function() { (function() {
var merge = require('merge'); const merge = require("merge");
function Utils() { function Utils() {}
}
Utils.prototype.escape = function(str) { Utils.prototype.escape = function(str) {
return str.slice(0) return str
.replace(/&/g, '&amp;') .slice(0)
.replace(/</g, '&lt;') .replace(/&/g, "&amp;")
.replace(/>/g, '&gt;') .replace(/</g, "&lt;")
.replace(/"/g, '&quot;') .replace(/>/g, "&gt;")
.replace(/'/g, '&#x27;') .replace(/"/g, "&quot;")
.replace(/\//g, '&#x2F;'); .replace(/'/g, "&#x27;")
.replace(/\//g, "&#x2F;");
}; };
Utils.prototype.startsWith = function(str, start) { Utils.prototype.startsWith = function(str, start) {
if (typeof start === 'object') { if (typeof start === "object") {
var result = false; let result = false;
start.forEach(function(s) { start.forEach(function(s) {
if (str.indexOf(s) === 0) { if (str.indexOf(s) === 0) {
result = true; result = true;
@ -37,7 +37,7 @@
}; };
Utils.prototype.valueOrEmpty = function(value) { Utils.prototype.valueOrEmpty = function(value) {
return value || ''; return value || "";
}; };
Utils.prototype.safeConfig = function(cfg, defaultConfig) { Utils.prototype.safeConfig = function(cfg, defaultConfig) {

View file

@ -1,743 +0,0 @@
var assert = require('assert');
var DiffParser = require('../src/diff-parser.js').DiffParser;
describe('DiffParser', function() {
describe('generateDiffJson', function() {
it('should parse unix with \n diff', function() {
var diff =
'diff --git a/sample b/sample\n' +
'index 0000001..0ddf2ba\n' +
'--- a/sample\n' +
'+++ b/sample\n' +
'@@ -1 +1 @@\n' +
'-test\n' +
'+test1r\n';
checkDiffSample(diff);
});
it('should parse windows with \r\n diff', function() {
var diff =
'diff --git a/sample b/sample\r\n' +
'index 0000001..0ddf2ba\r\n' +
'--- a/sample\r\n' +
'+++ b/sample\r\n' +
'@@ -1 +1 @@\r\n' +
'-test\r\n' +
'+test1r\r\n';
checkDiffSample(diff);
});
it('should parse old os x with \r diff', function() {
var diff =
'diff --git a/sample b/sample\r' +
'index 0000001..0ddf2ba\r' +
'--- a/sample\r' +
'+++ b/sample\r' +
'@@ -1 +1 @@\r' +
'-test\r' +
'+test1r\r';
checkDiffSample(diff);
});
it('should parse mixed eols diff', function() {
var diff =
'diff --git a/sample b/sample\n' +
'index 0000001..0ddf2ba\r\n' +
'--- a/sample\r' +
'+++ b/sample\r\n' +
'@@ -1 +1 @@\n' +
'-test\r' +
'+test1r\n';
checkDiffSample(diff);
});
function checkDiffSample(diff) {
var result = DiffParser.generateDiffJson(diff);
var file1 = result[0];
assert.equal(1, result.length);
assert.equal(1, file1.addedLines);
assert.equal(1, file1.deletedLines);
assert.equal('sample', file1.oldName);
assert.equal('sample', file1.newName);
assert.equal(1, file1.blocks.length);
}
it('should parse diff with special characters', function() {
var diff =
'diff --git "a/bla with \ttab.scala" "b/bla with \ttab.scala"\n' +
'index 4c679d7..e9bd385 100644\n' +
'--- "a/bla with \ttab.scala"\n' +
'+++ "b/bla with \ttab.scala"\n' +
'@@ -1 +1,2 @@\n' +
'-cenas\n' +
'+cenas com ananas\n' +
'+bananas';
var result = DiffParser.generateDiffJson(diff);
var file1 = result[0];
assert.equal(1, result.length);
assert.equal(2, file1.addedLines);
assert.equal(1, file1.deletedLines);
assert.equal('bla with \ttab.scala', file1.oldName);
assert.equal('bla with \ttab.scala', file1.newName);
assert.equal(1, file1.blocks.length);
});
it('should parse diff with prefix', function() {
var diff =
'diff --git "\tbla with \ttab.scala" "\tbla with \ttab.scala"\n' +
'index 4c679d7..e9bd385 100644\n' +
'--- "\tbla with \ttab.scala"\n' +
'+++ "\tbla with \ttab.scala"\n' +
'@@ -1 +1,2 @@\n' +
'-cenas\n' +
'+cenas com ananas\n' +
'+bananas';
var result = DiffParser.generateDiffJson(diff, {'srcPrefix': '\t', 'dstPrefix': '\t'});
var file1 = result[0];
assert.equal(1, result.length);
assert.equal(2, file1.addedLines);
assert.equal(1, file1.deletedLines);
assert.equal('bla with \ttab.scala', file1.oldName);
assert.equal('bla with \ttab.scala', file1.newName);
assert.equal(1, file1.blocks.length);
});
it('should parse diff with deleted file', function() {
var diff =
'diff --git a/src/var/strundefined.js b/src/var/strundefined.js\n' +
'deleted file mode 100644\n' +
'index 04e16b0..0000000\n' +
'--- a/src/var/strundefined.js\n' +
'+++ /dev/null\n' +
'@@ -1,3 +0,0 @@\n' +
'-define(function() {\n' +
'- return typeof undefined;\n' +
'-});\n';
var result = DiffParser.generateDiffJson(diff);
assert.equal(1, result.length);
var file1 = result[0];
assert.equal(false, file1.isCombined);
assert.equal(0, file1.addedLines);
assert.equal(3, file1.deletedLines);
assert.equal('src/var/strundefined.js', file1.oldName);
assert.equal('/dev/null', file1.newName);
assert.equal(1, file1.blocks.length);
assert.equal(true, file1.isDeleted);
assert.equal('04e16b0', file1.checksumBefore);
assert.equal('0000000', file1.checksumAfter);
});
it('should parse diff with new file', function() {
var diff =
'diff --git a/test.js b/test.js\n' +
'new file mode 100644\n' +
'index 0000000..e1e22ec\n' +
'--- /dev/null\n' +
'+++ b/test.js\n' +
'@@ -0,0 +1,5 @@\n' +
"+var parser = require('./source/git-parser');\n" +
'+\n' +
'+var patchLineList = [ false, false, false, false ];\n' +
'+\n' +
'+console.log(parser.parsePatchDiffResult(text, patchLineList));\n';
var result = DiffParser.generateDiffJson(diff);
assert.equal(1, result.length);
var file1 = result[0];
assert.equal(false, file1.isCombined);
assert.equal(5, file1.addedLines);
assert.equal(0, file1.deletedLines);
assert.equal('/dev/null', file1.oldName);
assert.equal('test.js', file1.newName);
assert.equal(1, file1.blocks.length);
assert.equal(true, file1.isNew);
assert.equal(100644, file1.newFileMode);
assert.equal('0000000', file1.checksumBefore);
assert.equal('e1e22ec', file1.checksumAfter);
});
it('should parse diff with nested diff', function() {
var diff =
'diff --git a/src/offset.js b/src/offset.js\n' +
'index cc6ffb4..fa51f18 100644\n' +
'--- a/src/offset.js\n' +
'+++ b/src/offset.js\n' +
'@@ -1,6 +1,5 @@\n' +
"+var parser = require('./source/git-parser');\n" +
'+\n' +
"+var text = 'diff --git a/components/app/app.html b/components/app/app.html\\nindex ecb7a95..027bd9b 100644\\n--- a/components/app/app.html\\n+++ b/components/app/app.html\\n@@ -52,0 +53,3 @@\\n+\\n+\\n+\\n@@ -56,0 +60,3 @@\\n+\\n+\\n+\\n'\n" +
'+var patchLineList = [ false, false, false, false ];\n' +
'+\n' +
'+console.log(parser.parsePatchDiffResult(text, patchLineList));\n';
var result = DiffParser.generateDiffJson(diff);
assert.equal(1, result.length);
var file1 = result[0];
assert.equal(false, file1.isCombined);
assert.equal(6, file1.addedLines);
assert.equal(0, file1.deletedLines);
assert.equal('src/offset.js', file1.oldName);
assert.equal('src/offset.js', file1.newName);
assert.equal(1, file1.blocks.length);
assert.equal(6, file1.blocks[0].lines.length);
assert.equal('cc6ffb4', file1.checksumBefore);
assert.equal('fa51f18', file1.checksumAfter);
});
it('should parse diff with multiple blocks', function() {
var diff =
'diff --git a/src/attributes/classes.js b/src/attributes/classes.js\n' +
'index c617824..c8d1393 100644\n' +
'--- a/src/attributes/classes.js\n' +
'+++ b/src/attributes/classes.js\n' +
'@@ -1,10 +1,9 @@\n' +
' define([\n' +
' "../core",\n' +
' "../var/rnotwhite",\n' +
'- "../var/strundefined",\n' +
' "../data/var/dataPriv",\n' +
' "../core/init"\n' +
'-], function( jQuery, rnotwhite, strundefined, dataPriv ) {\n' +
'+], function( jQuery, rnotwhite, dataPriv ) {\n' +
' \n' +
' var rclass = /[\\t\\r\\n\\f]/g;\n' +
' \n' +
'@@ -128,7 +127,7 @@ jQuery.fn.extend({\n' +
' }\n' +
' \n' +
' // Toggle whole class name\n' +
'- } else if ( type === strundefined || type === "boolean" ) {\n' +
'+ } else if ( value === undefined || type === "boolean" ) {\n' +
' if ( this.className ) {\n' +
' // store className if set\n' +
' dataPriv.set( this, "__className__", this.className );\n';
var result = DiffParser.generateDiffJson(diff);
assert.equal(1, result.length);
var file1 = result[0];
assert.equal(false, file1.isCombined);
assert.equal(2, file1.addedLines);
assert.equal(3, file1.deletedLines);
assert.equal('src/attributes/classes.js', file1.oldName);
assert.equal('src/attributes/classes.js', file1.newName);
assert.equal(2, file1.blocks.length);
assert.equal(11, file1.blocks[0].lines.length);
assert.equal(8, file1.blocks[1].lines.length);
assert.equal('c617824', file1.checksumBefore);
assert.equal('c8d1393', file1.checksumAfter);
});
it('should parse diff with multiple files', function() {
var diff =
'diff --git a/src/core/init.js b/src/core/init.js\n' +
'index e49196a..50f310c 100644\n' +
'--- a/src/core/init.js\n' +
'+++ b/src/core/init.js\n' +
'@@ -101,7 +101,7 @@ var rootjQuery,\n' +
' // HANDLE: $(function)\n' +
' // Shortcut for document ready\n' +
' } else if ( jQuery.isFunction( selector ) ) {\n' +
'- return typeof rootjQuery.ready !== "undefined" ?\n' +
'+ return rootjQuery.ready !== undefined ?\n' +
' rootjQuery.ready( selector ) :\n' +
' // Execute immediately if ready is not present\n' +
' selector( jQuery );\n' +
'diff --git a/src/event.js b/src/event.js\n' +
'index 7336f4d..6183f70 100644\n' +
'--- a/src/event.js\n' +
'+++ b/src/event.js\n' +
'@@ -1,6 +1,5 @@\n' +
' define([\n' +
' "./core",\n' +
'- "./var/strundefined",\n' +
' "./var/rnotwhite",\n' +
' "./var/hasOwn",\n' +
' "./var/slice",\n';
var result = DiffParser.generateDiffJson(diff);
assert.equal(2, result.length);
var file1 = result[0];
assert.equal(false, file1.isCombined);
assert.equal(1, file1.addedLines);
assert.equal(1, file1.deletedLines);
assert.equal('src/core/init.js', file1.oldName);
assert.equal('src/core/init.js', file1.newName);
assert.equal(1, file1.blocks.length);
assert.equal(8, file1.blocks[0].lines.length);
assert.equal('e49196a', file1.checksumBefore);
assert.equal('50f310c', file1.checksumAfter);
var file2 = result[1];
assert.equal(false, file2.isCombined);
assert.equal(0, file2.addedLines);
assert.equal(1, file2.deletedLines);
assert.equal('src/event.js', file2.oldName);
assert.equal('src/event.js', file2.newName);
assert.equal(1, file2.blocks.length);
assert.equal(6, file2.blocks[0].lines.length);
assert.equal('7336f4d', file2.checksumBefore);
assert.equal('6183f70', file2.checksumAfter);
});
it('should parse combined diff', function() {
var diff =
'diff --combined describe.c\n' +
'index fabadb8,cc95eb0..4866510\n' +
'--- a/describe.c\n' +
'+++ b/describe.c\n' +
'@@@ -98,20 -98,12 +98,20 @@@\n' +
' return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;\n' +
' }\n' +
' \n' +
'- static void describe(char *arg)\n' +
' -static void describe(struct commit *cmit, int last_one)\n' +
'++static void describe(char *arg, int last_one)\n' +
' {\n' +
' + unsigned char sha1[20];\n' +
' + struct commit *cmit;\n' +
' struct commit_list *list;\n' +
' static int initialized = 0;\n' +
' struct commit_name *n;\n' +
' \n' +
' + if (get_sha1(arg, sha1) < 0)\n' +
' + usage(describe_usage);\n' +
' + cmit = lookup_commit_reference(sha1);\n' +
' + if (!cmit)\n' +
' + usage(describe_usage);\n' +
' +\n' +
' if (!initialized) {\n' +
' initialized = 1;\n' +
' for_each_ref(get_name);\n';
var result = DiffParser.generateDiffJson(diff);
assert.equal(1, result.length);
var file1 = result[0];
assert.equal(true, file1.isCombined);
assert.equal(9, file1.addedLines);
assert.equal(2, file1.deletedLines);
assert.equal('describe.c', file1.oldName);
assert.equal('describe.c', file1.newName);
assert.equal(1, file1.blocks.length);
assert.equal(22, file1.blocks[0].lines.length);
assert.deepEqual(['4866510', 'cc95eb0'].sort(), file1.checksumBefore.sort());
assert.equal('fabadb8', file1.checksumAfter);
});
it('should parse diffs with copied files', function() {
var diff =
'diff --git a/index.js b/more-index.js\n' +
'dissimilarity index 5%\n' +
'copy from index.js\n' +
'copy to more-index.js\n';
var result = DiffParser.generateDiffJson(diff);
assert.equal(1, result.length);
var file1 = result[0];
assert.equal(0, file1.addedLines);
assert.equal(0, file1.deletedLines);
assert.equal('index.js', file1.oldName);
assert.equal('more-index.js', file1.newName);
assert.equal(0, file1.blocks.length);
assert.equal(true, file1.isCopy);
assert.equal(5, file1.changedPercentage);
});
it('should parse diffs with moved files', function() {
var diff =
'diff --git a/more-index.js b/other-index.js\n' +
'similarity index 86%\n' +
'rename from more-index.js\n' +
'rename to other-index.js\n';
var result = DiffParser.generateDiffJson(diff);
assert.equal(1, result.length);
var file1 = result[0];
assert.equal(0, file1.addedLines);
assert.equal(0, file1.deletedLines);
assert.equal('more-index.js', file1.oldName);
assert.equal('other-index.js', file1.newName);
assert.equal(0, file1.blocks.length);
assert.equal(true, file1.isRename);
assert.equal(86, file1.unchangedPercentage);
});
it('should parse diffs correct line numbers', function() {
var diff =
'diff --git a/sample b/sample\n' +
'index 0000001..0ddf2ba\n' +
'--- a/sample\n' +
'+++ b/sample\n' +
'@@ -1 +1,2 @@\n' +
'-test\n' +
'+test1r\n';
var result = DiffParser.generateDiffJson(diff);
assert.equal(1, result.length);
var file1 = result[0];
assert.equal(1, file1.addedLines);
assert.equal(1, file1.deletedLines);
assert.equal('sample', file1.oldName);
assert.equal('sample', file1.newName);
assert.equal(1, file1.blocks.length);
assert.equal(2, file1.blocks[0].lines.length);
assert.equal(1, file1.blocks[0].lines[0].oldNumber);
assert.equal(null, file1.blocks[0].lines[0].newNumber);
assert.equal(null, file1.blocks[0].lines[1].oldNumber);
assert.equal(1, file1.blocks[0].lines[1].newNumber);
});
it('should parse unified non git diff and strip timestamps off the headers', function() {
var diffs = [
// 2 hours ahead of GMT
'--- a/sample.js 2016-10-25 11:37:14.000000000 +0200\n' +
'+++ b/sample.js 2016-10-25 11:37:14.000000000 +0200\n' +
'@@ -1 +1,2 @@\n' +
'-test\n' +
'+test1r\n' +
'+test2r\n',
// 2 hours behind GMT
'--- a/sample.js 2016-10-25 11:37:14.000000000 -0200\n' +
'+++ b/sample.js 2016-10-25 11:37:14.000000000 -0200\n' +
'@@ -1 +1,2 @@\n' +
'-test\n' +
'+test1r\n' +
'+test2r\n'
];
diffs.forEach(function(diff) {
var result = DiffParser.generateDiffJson(diff);
var file1 = result[0];
assert.equal(1, result.length);
assert.equal(2, file1.addedLines);
assert.equal(1, file1.deletedLines);
assert.equal('sample.js', file1.oldName);
assert.equal('sample.js', file1.newName);
assert.equal(1, file1.blocks.length);
var linesContent = file1.blocks[0].lines.map(function(line) {
return line.content;
});
assert.deepEqual(linesContent, ['-test', '+test1r', '+test2r']);
});
});
it('should parse unified non git diff', function() {
var diff =
'--- a/sample.js\n' +
'+++ b/sample.js\n' +
'@@ -1 +1,2 @@\n' +
'-test\n' +
'+test1r\n' +
'+test2r\n';
var result = DiffParser.generateDiffJson(diff);
var file1 = result[0];
assert.equal(1, result.length);
assert.equal(2, file1.addedLines);
assert.equal(1, file1.deletedLines);
assert.equal('sample.js', file1.oldName);
assert.equal('sample.js', file1.newName);
assert.equal(1, file1.blocks.length);
var linesContent = file1.blocks[0].lines.map(function(line) {
return line.content;
});
assert.deepEqual(linesContent, ['-test', '+test1r', '+test2r']);
});
it('should parse unified diff with multiple hunks and files', function() {
var diff =
'--- sample.js\n' +
'+++ sample.js\n' +
'@@ -1 +1,2 @@\n' +
'-test\n' +
'@@ -10 +20,2 @@\n' +
'+test\n' +
'--- sample1.js\n' +
'+++ sample1.js\n' +
'@@ -1 +1,2 @@\n' +
'+test1';
var result = DiffParser.generateDiffJson(diff);
assert.equal(2, result.length);
var file1 = result[0];
assert.equal(1, file1.addedLines);
assert.equal(1, file1.deletedLines);
assert.equal('sample.js', file1.oldName);
assert.equal('sample.js', file1.newName);
assert.equal(2, file1.blocks.length);
var linesContent1 = file1.blocks[0].lines.map(function(line) {
return line.content;
});
assert.deepEqual(linesContent1, ['-test']);
var linesContent2 = file1.blocks[1].lines.map(function(line) {
return line.content;
});
assert.deepEqual(linesContent2, ['+test']);
var file2 = result[1];
assert.equal(1, file2.addedLines);
assert.equal(0, file2.deletedLines);
assert.equal('sample1.js', file2.oldName);
assert.equal('sample1.js', file2.newName);
assert.equal(1, file2.blocks.length);
var linesContent = file2.blocks[0].lines.map(function(line) {
return line.content;
});
assert.deepEqual(linesContent, ['+test1']);
});
it('should parse diff with --- and +++ in the context lines', function() {
var diff =
'--- sample.js\n' +
'+++ sample.js\n' +
'@@ -1,8 +1,8 @@\n' +
' test\n' +
' \n' +
'-- 1\n' +
'--- 1\n' +
'---- 1\n' +
' \n' +
'++ 2\n' +
'+++ 2\n' +
'++++ 2';
var result = DiffParser.generateDiffJson(diff);
var file1 = result[0];
assert.equal(1, result.length);
assert.equal(3, file1.addedLines);
assert.equal(3, file1.deletedLines);
assert.equal('sample.js', file1.oldName);
assert.equal('sample.js', file1.newName);
assert.equal(1, file1.blocks.length);
var linesContent = file1.blocks[0].lines.map(function(line) {
return line.content;
});
assert.deepEqual(linesContent,
[' test', ' ', '-- 1', '--- 1', '---- 1', ' ', '++ 2', '+++ 2', '++++ 2']);
});
it('should parse diff without proper hunk headers', function() {
var diff =
'--- sample.js\n' +
'+++ sample.js\n' +
'@@ @@\n' +
' test';
var result = DiffParser.generateDiffJson(diff);
var file1 = result[0];
assert.equal(1, result.length);
assert.equal(0, file1.addedLines);
assert.equal(0, file1.deletedLines);
assert.equal('sample.js', file1.oldName);
assert.equal('sample.js', file1.newName);
assert.equal(1, file1.blocks.length);
var linesContent = file1.blocks[0].lines.map(function(line) {
return line.content;
});
assert.deepEqual(linesContent, [' test']);
});
it('should parse binary file diff', function() {
var diff =
'diff --git a/last-changes-config.png b/last-changes-config.png\n' +
'index 322248b..56fc1f2 100644\n' +
'--- a/last-changes-config.png\n' +
'+++ b/last-changes-config.png\n' +
'Binary files differ';
var result = DiffParser.generateDiffJson(diff);
var file1 = result[0];
assert.equal(1, result.length);
assert.equal(0, file1.addedLines);
assert.equal(0, file1.deletedLines);
assert.equal('last-changes-config.png', file1.oldName);
assert.equal('last-changes-config.png', file1.newName);
assert.equal(1, file1.blocks.length);
assert.equal(0, file1.blocks[0].lines.length);
assert.equal('Binary files differ', file1.blocks[0].header);
});
it('should parse diff with --find-renames', function() {
var diff =
'diff --git a/src/test-bar.js b/src/test-baz.js\n' +
'similarity index 98%\n' +
'rename from src/test-bar.js\n' +
'rename to src/test-baz.js\n' +
'index e01513b..f14a870 100644\n' +
'--- a/src/test-bar.js\n' +
'+++ b/src/test-baz.js\n' +
'@@ -1,4 +1,32 @@\n' +
' function foo() {\n' +
'-var bar = "Whoops!";\n' +
'+var baz = "Whoops!";\n' +
' }\n' +
' ';
var result = DiffParser.generateDiffJson(diff);
var file1 = result[0];
assert.equal(1, result.length);
assert.equal(1, file1.addedLines);
assert.equal(1, file1.deletedLines);
assert.equal('src/test-bar.js', file1.oldName);
assert.equal('src/test-baz.js', file1.newName);
assert.equal(1, file1.blocks.length);
assert.equal(5, file1.blocks[0].lines.length);
var linesContent = file1.blocks[0].lines.map(function(line) {
return line.content;
});
assert.deepEqual(linesContent,
[' function foo() {', '-var bar = "Whoops!";', '+var baz = "Whoops!";', ' }', ' ']);
});
it('should parse diff with prefix', function() {
var diff =
'diff --git "\tTest.scala" "\tScalaTest.scala"\n' +
'similarity index 88%\n' +
'rename from Test.scala\n' +
'rename to ScalaTest.scala\n' +
'index 7d1f9bf..8b13271 100644\n' +
'--- "\tTest.scala"\n' +
'+++ "\tScalaTest.scala"\n' +
'@@ -1,6 +1,8 @@\n' +
' class Test {\n' +
' \n' +
' def method1 = ???\n' +
'+\n' +
'+ def method2 = ???\n' +
' \n' +
' def myMethod = ???\n' +
' \n' +
'@@ -10,7 +12,6 @@ class Test {\n' +
' \n' +
' def + = ???\n' +
' \n' +
'- def |> = ???\n' +
' \n' +
' }\n' +
' \n' +
'diff --git "\ttardis.png" "\ttardis.png"\n' +
'new file mode 100644\n' +
'index 0000000..d503a29\n' +
'Binary files /dev/null and "\ttardis.png" differ\n' +
'diff --git a/src/test-bar.js b/src/test-baz.js\n' +
'similarity index 98%\n' +
'rename from src/test-bar.js\n' +
'rename to src/test-baz.js\n' +
'index e01513b..f14a870 100644\n' +
'--- a/src/test-bar.js\n' +
'+++ b/src/test-baz.js\n' +
'@@ -1,4 +1,32 @@\n' +
' function foo() {\n' +
'-var bar = "Whoops!";\n' +
'+var baz = "Whoops!";\n' +
' }\n' +
' ';
var result = DiffParser.generateDiffJson(diff, {'srcPrefix': '\t', 'dstPrefix': '\t'});
assert.equal(3, result.length);
var file1 = result[0];
assert.equal(2, file1.addedLines);
assert.equal(1, file1.deletedLines);
assert.equal('Test.scala', file1.oldName);
assert.equal('ScalaTest.scala', file1.newName);
assert.equal(2, file1.blocks.length);
assert.equal(8, file1.blocks[0].lines.length);
assert.equal(7, file1.blocks[1].lines.length);
var file2 = result[1];
assert.equal('/dev/null', file2.oldName);
assert.equal('tardis.png', file2.newName);
var file3 = result[2];
assert.equal(1, file3.addedLines);
assert.equal(1, file3.deletedLines);
assert.equal('src/test-bar.js', file3.oldName);
assert.equal('src/test-baz.js', file3.newName);
assert.equal(1, file3.blocks.length);
assert.equal(5, file3.blocks[0].lines.length);
var linesContent = file3.blocks[0].lines.map(function(line) {
return line.content;
});
assert.deepEqual(linesContent,
[' function foo() {', '-var bar = "Whoops!";', '+var baz = "Whoops!";', ' }', ' ']);
});
it('should parse binary with content', function() {
var diff =
'diff --git a/favicon.png b/favicon.png\n' +
'deleted file mode 100644\n' +
'index 2a9d516a5647205d7be510dd0dff93a3663eff6f..0000000000000000000000000000000000000000\n' +
'GIT binary patch\n' +
'literal 0\n' +
'HcmV?d00001\n' +
'\n' +
'literal 471\n' +
'zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf<Z~8yL>4nJ\n' +
'za0`Jj<E6WGe}IBwC9V-A&PAz-C7Jno3L%-fsSJk3`UaNzMkcGzh!g=;$beJ?=ckpF\n' +
'zCl;kLIHu$$r7E~(7NwTw7iAYKI0u`(*t4mJfq_xq)5S5wqIc=!hrWj$cv|<b{x!c(\n' +
'z;3r#y;31Y&=1q>qPVOAS4ANVKzqmCp=Cty@U^(7zk!jHsvT~YI{F^=Ex6g|gox78w\n' +
'z+Sn2Du3GS9U7qU`1*NYYlJi3u-!<?H-eky}wyIIL;8VU@wCDrb0``&v(jQ*DWSR4K\n' +
'zPq(3;isEyho{emNa=%%!jDPE`l3u;5d=q=<+v8kO-=C`*G#t-*AiE-D>-_B#8k9H0\n' +
'zGl{FnZs<2$wz5^=Q2h-1XI^s{LQL1#T4epqNPC%Orl(tD_@!*EY++~^Lt2<2&!&%=\n' +
'z`m>(TYj6uS7jDdt=eH>iOyQg(QMR<-Fw8)Dk^ZG)XQTuzEgl{`GpS?Cfq9818R9~=\n' +
'z{&h9@9n8F^?|qusoPy{k#%tVHzu7H$t26CR`BJZk*Ixf&u36WuS=?6m2^ho-p00i_\n' +
'I>zopr0Nz-&lmGw#\n' +
'diff --git a/src/test-bar.js b/src/test-baz.js\n' +
'similarity index 98%\n' +
'rename from src/test-bar.js\n' +
'rename to src/test-baz.js\n' +
'index e01513b..f14a870 100644\n' +
'--- a/src/test-bar.js\n' +
'+++ b/src/test-baz.js\n' +
'@@ -1,4 +1,32 @@\n' +
' function foo() {\n' +
'-var bar = "Whoops!";\n' +
'+var baz = "Whoops!";\n' +
' }\n' +
' ';
var result = DiffParser.generateDiffJson(diff);
assert.equal(2, result.length);
var file1 = result[0];
assert.equal('favicon.png', file1.oldName);
assert.equal('favicon.png', file1.newName);
assert.equal(1, file1.blocks.length);
assert.equal(0, file1.blocks[0].lines.length);
var file2 = result[1];
assert.equal(1, file2.addedLines);
assert.equal(1, file2.deletedLines);
assert.equal('src/test-bar.js', file2.oldName);
assert.equal('src/test-baz.js', file2.newName);
assert.equal(1, file2.blocks.length);
assert.equal(5, file2.blocks[0].lines.length);
var linesContent = file2.blocks[0].lines.map(function(line) {
return line.content;
});
assert.deepEqual(linesContent,
[' function foo() {', '-var bar = "Whoops!";', '+var baz = "Whoops!";', ' }', ' ']);
});
});
});

View file

@ -1,70 +0,0 @@
var assert = require('assert');
var HoganJsUtils = new (require('../src/hoganjs-utils.js').HoganJsUtils)();
var diffParser = require('../src/diff-parser.js').DiffParser;
describe('HoganJsUtils', function() {
describe('render', function() {
var emptyDiffHtml =
'<tr>\n' +
' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">\n' +
' File without changes\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
it('should render view', function() {
var result = HoganJsUtils.render('generic', 'empty-diff', {
contentClass: 'd2h-code-line',
diffParser: diffParser
});
assert.equal(emptyDiffHtml, result);
});
it('should render view without cache', function() {
var result = HoganJsUtils.render('generic', 'empty-diff', {
contentClass: 'd2h-code-line',
diffParser: diffParser
}, {noCache: true});
assert.equal(emptyDiffHtml, result);
});
it('should return null if template is missing', function() {
var hoganUtils = new (require('../src/hoganjs-utils.js').HoganJsUtils)({noCache: true});
var result = hoganUtils.render('generic', 'missing-template', {});
assert.equal(null, result);
});
it('should allow templates to be overridden with compiled templates', function() {
var emptyDiffTemplate = HoganJsUtils.compile('<p>{{myName}}</p>');
var config = {templates: {'generic-empty-diff': emptyDiffTemplate}};
var hoganUtils = new (require('../src/hoganjs-utils.js').HoganJsUtils)(config);
var result = hoganUtils.render('generic', 'empty-diff', {myName: 'Rodrigo Fernandes'});
assert.equal('<p>Rodrigo Fernandes</p>', result);
});
it('should allow templates to be overridden with uncompiled templates', function() {
var emptyDiffTemplate = '<p>{{myName}}</p>';
var config = {rawTemplates: {'generic-empty-diff': emptyDiffTemplate}};
var hoganUtils = new (require('../src/hoganjs-utils.js').HoganJsUtils)(config);
var result = hoganUtils.render('generic', 'empty-diff', {myName: 'Rodrigo Fernandes'});
assert.equal('<p>Rodrigo Fernandes</p>', result);
});
it('should allow templates to be overridden giving priority to compiled templates', function() {
var emptyDiffTemplate = HoganJsUtils.compile('<p>{{myName}}</p>');
var emptyDiffTemplateUncompiled = '<p>Not used!</p>';
var config = {
templates: {'generic-empty-diff': emptyDiffTemplate},
rawTemplates: {'generic-empty-diff': emptyDiffTemplateUncompiled}
};
var hoganUtils = new (require('../src/hoganjs-utils.js').HoganJsUtils)(config);
var result = hoganUtils.render('generic', 'empty-diff', {myName: 'Rodrigo Fernandes'});
assert.equal('<p>Rodrigo Fernandes</p>', result);
});
});
});

View file

@ -1,140 +0,0 @@
var assert = require('assert');
var PrinterUtils = require('../src/printer-utils.js').PrinterUtils;
describe('Utils', function() {
describe('getHtmlId', function() {
it('should generate file unique id', function() {
var result = PrinterUtils.getHtmlId({
oldName: 'sample.js',
newName: 'sample.js'
});
assert.equal('d2h-960013', result);
});
it('should generate file unique id for empty hashes', function() {
var result = PrinterUtils.getHtmlId({
oldName: 'sample.js',
newName: 'sample.js'
});
assert.equal('d2h-960013', result);
});
});
describe('getDiffName', function() {
it('should generate the file name for a changed file', function() {
var result = PrinterUtils.getDiffName({
oldName: 'sample.js',
newName: 'sample.js'
});
assert.equal('sample.js', result);
});
it('should generate the file name for a changed file and full rename', function() {
var result = PrinterUtils.getDiffName({
oldName: 'sample1.js',
newName: 'sample2.js'
});
assert.equal('sample1.js → sample2.js', result);
});
it('should generate the file name for a changed file and prefix rename', function() {
var result = PrinterUtils.getDiffName({
oldName: 'src/path/sample.js',
newName: 'source/path/sample.js'
});
assert.equal('{src → source}/path/sample.js', result);
});
it('should generate the file name for a changed file and suffix rename', function() {
var result = PrinterUtils.getDiffName({
oldName: 'src/path/sample1.js',
newName: 'src/path/sample2.js'
});
assert.equal('src/path/{sample1.js → sample2.js}', result);
});
it('should generate the file name for a changed file and middle rename', function() {
var result = PrinterUtils.getDiffName({
oldName: 'src/really/big/path/sample.js',
newName: 'src/small/path/sample.js'
});
assert.equal('src/{really/big → small}/path/sample.js', result);
});
it('should generate the file name for a deleted file', function() {
var result = PrinterUtils.getDiffName({
oldName: 'src/my/file.js',
newName: '/dev/null'
});
assert.equal('src/my/file.js', result);
});
it('should generate the file name for a new file', function() {
var result = PrinterUtils.getDiffName({
oldName: '/dev/null',
newName: 'src/my/file.js'
});
assert.equal('src/my/file.js', result);
});
it('should generate handle undefined filename', function() {
var result = PrinterUtils.getDiffName({});
assert.equal('unknown/file/path', result);
});
});
describe('diffHighlight', function() {
it('should highlight two lines', function() {
var result = PrinterUtils.diffHighlight(
'-var myVar = 2;',
'+var myVariable = 3;',
{matching: 'words'}
);
assert.deepEqual({
first: {
prefix: '-',
line: 'var <del>myVar</del> = <del>2</del>;'
},
second: {
prefix: '+',
line: 'var <ins>myVariable</ins> = <ins>3</ins>;'
}
}, result);
});
it('should highlight two lines char by char', function() {
var result = PrinterUtils.diffHighlight(
'-var myVar = 2;',
'+var myVariable = 3;',
{ diffStyle: 'char' }
);
assert.deepEqual({
first: {
prefix: '-',
line: 'var myVar = <del>2</del>;'
},
second: {
prefix: '+',
line: 'var myVar<ins>iable</ins> = <ins>3</ins>;'
}
}, result);
});
it('should highlight combined diff lines', function() {
var result = PrinterUtils.diffHighlight(
' -var myVar = 2;',
' +var myVariable = 3;',
{
diffStyle: 'word',
isCombined: true,
matching: 'words',
matchWordsThreshold: 1.00
}
);
assert.deepEqual({
first: {
prefix: ' -',
line: 'var <del class="d2h-change">myVar</del> = <del class="d2h-change">2</del>;'
},
second: {
prefix: ' +',
line: 'var <ins class="d2h-change">myVariable</ins> = <ins class="d2h-change">3</ins>;'
}
}, result);
});
});
});

View file

@ -1,25 +0,0 @@
var assert = require('assert');
var Utils = require('../src/utils.js').Utils;
describe('Utils', function() {
describe('escape', function() {
it('should escape & with &amp;', function() {
var result = Utils.escape('&');
assert.equal('&amp;', result);
});
it('should escape < with &lt;', function() {
var result = Utils.escape('<');
assert.equal('&lt;', result);
});
it('should escape > with &gt;', function() {
var result = Utils.escape('>');
assert.equal('&gt;', result);
});
it('should escape a string with multiple problematic characters', function() {
var result = Utils.escape('<a href="#">\tlink text</a>');
var expected = '&lt;a href=&quot;#&quot;&gt;\tlink text&lt;&#x2F;a&gt;';
assert.equal(expected, result);
});
});
});

28
tsconfig.json Normal file
View file

@ -0,0 +1,28 @@
{
"compilerOptions": {
"outDir": "./build/commonjs-node",
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
// TODO: Change to true after migration to TS is complete
"allowJs": true,
"declaration": false,
"declarationMap": false,
/////////////////////////////////////////////////////////
"strictNullChecks": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"alwaysStrict": true,
"strict": true,
"noImplicitAny": true,
"noImplicitThis": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true
},
"include": ["./src/**/*"],
"exclude": ["node_modules", "./src/__tests__/*"]
}

View file

@ -15,20 +15,20 @@
$(document).ready(function() { $(document).ready(function() {
// Improves browser compatibility // Improves browser compatibility
require('whatwg-fetch'); require("whatwg-fetch");
var searchParam = 'diff'; const searchParam = "diff";
var $container = $('.container'); const $container = $(".container");
var $url = $('#url'); const $url = $("#url");
var $outputFormat = $('#diff-url-options-output-format'); const $outputFormat = $("#diff-url-options-output-format");
var $showFiles = $('#diff-url-options-show-files'); const $showFiles = $("#diff-url-options-show-files");
var $matching = $('#diff-url-options-matching'); const $matching = $("#diff-url-options-matching");
var $wordsThreshold = $('#diff-url-options-match-words-threshold'); const $wordsThreshold = $("#diff-url-options-match-words-threshold");
var $matchingMaxComparisons = $('#diff-url-options-matching-max-comparisons'); const $matchingMaxComparisons = $("#diff-url-options-matching-max-comparisons");
if (window.location.search) { if (window.location.search) {
var url = getUrlFromSearch(window.location.search); const url = getUrlFromSearch(window.location.search);
$url.val(url); $url.val(url);
smartDraw(url); smartDraw(url);
} }
@ -41,99 +41,99 @@ $(document).ready(function() {
.add($wordsThreshold) .add($wordsThreshold)
.add($matchingMaxComparisons) .add($matchingMaxComparisons)
.change(function(e) { .change(function(e) {
console.log(''); console.log("");
console.log(e); console.log(e);
console.log(''); console.log("");
smartDraw(null, true); smartDraw(null, true);
}); });
function getUrlFromSearch(search) { function getUrlFromSearch(search) {
try { try {
return search return search
.split('?')[1] .split("?")[1]
.split(searchParam + '=')[1] .split(searchParam + "=")[1]
.split('&')[0]; .split("&")[0];
} catch (_ignore) { } catch (_ignore) {}
}
return null; return null;
} }
function getParamsFromSearch(search) { function getParamsFromSearch(search) {
var map = {}; const map = {};
try { try {
search search
.split('?')[1] .split("?")[1]
.split('&') .split("&")
.map(function(e) { .map(function(e) {
var values = e.split('='); const values = e.split("=");
map[values[0]] = values[1]; map[values[0]] = values[1];
}); });
} catch (_ignore) { } catch (_ignore) {}
}
return map; return map;
} }
function bind() { function bind() {
$('#url-btn').click(function(e) { $("#url-btn").click(function(e) {
e.preventDefault(); e.preventDefault();
var url = $url.val(); const url = $url.val();
smartDraw(url); smartDraw(url);
}); });
$url.on('paste', function(e) { $url.on("paste", function(e) {
var url = e.originalEvent.clipboardData.getData('Text'); const url = e.originalEvent.clipboardData.getData("Text");
smartDraw(url); smartDraw(url);
}); });
} }
function prepareUrl(url) { function prepareUrl(url) {
var fetchUrl; let fetchUrl;
var headers = new Headers(); const headers = new Headers();
var githubCommitUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/; const githubCommitUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
var githubPrUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/pull\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/; const githubPrUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/pull\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
var gitlabCommitUrl = /^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/; const gitlabCommitUrl = /^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
var gitlabPrUrl = /^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/merge_requests\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/; const gitlabPrUrl = /^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/merge_requests\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
var bitbucketCommitUrl = /^https?:\/\/(?:www\.)?bitbucket\.org\/(.*?)\/(.*?)\/commits\/(.*?)(?:\/raw)?(?:\/.*)?$/; const bitbucketCommitUrl = /^https?:\/\/(?:www\.)?bitbucket\.org\/(.*?)\/(.*?)\/commits\/(.*?)(?:\/raw)?(?:\/.*)?$/;
var bitbucketPrUrl = /^https?:\/\/(?:www\.)?bitbucket\.org\/(.*?)\/(.*?)\/pull-requests\/(.*?)(?:\/.*)?$/; const bitbucketPrUrl = /^https?:\/\/(?:www\.)?bitbucket\.org\/(.*?)\/(.*?)\/pull-requests\/(.*?)(?:\/.*)?$/;
function gitLabUrlGen(userName, projectName, type, value) { function gitLabUrlGen(userName, projectName, type, value) {
return 'https://crossorigin.me/https://gitlab.com/' + userName + '/' + projectName + '/' + type + '/' + value + '.diff'; return (
"https://crossorigin.me/https://gitlab.com/" + userName + "/" + projectName + "/" + type + "/" + value + ".diff"
);
} }
function gitHubUrlGen(userName, projectName, type, value) { function gitHubUrlGen(userName, projectName, type, value) {
headers.append('Accept', 'application/vnd.github.v3.diff'); headers.append("Accept", "application/vnd.github.v3.diff");
return 'https://api.github.com/repos/' + userName + '/' + projectName + '/' + type + '/' + value; return "https://api.github.com/repos/" + userName + "/" + projectName + "/" + type + "/" + value;
} }
function bitbucketUrlGen(userName, projectName, type, value) { function bitbucketUrlGen(userName, projectName, type, value) {
var baseUrl = 'https://bitbucket.org/api/2.0/repositories/'; const baseUrl = "https://bitbucket.org/api/2.0/repositories/";
if (type === 'pullrequests') { if (type === "pullrequests") {
return baseUrl + userName + '/' + projectName + '/pullrequests/' + value + '/diff'; return baseUrl + userName + "/" + projectName + "/pullrequests/" + value + "/diff";
} }
return baseUrl + userName + '/' + projectName + '/diff/' + value; return baseUrl + userName + "/" + projectName + "/diff/" + value;
} }
var values; let values;
if ((values = githubCommitUrl.exec(url))) { if ((values = githubCommitUrl.exec(url))) {
fetchUrl = gitHubUrlGen(values[1], values[2], 'commits', values[3]); fetchUrl = gitHubUrlGen(values[1], values[2], "commits", values[3]);
} else if ((values = githubPrUrl.exec(url))) { } else if ((values = githubPrUrl.exec(url))) {
fetchUrl = gitHubUrlGen(values[1], values[2], 'pulls', values[3]); fetchUrl = gitHubUrlGen(values[1], values[2], "pulls", values[3]);
} else if ((values = gitlabCommitUrl.exec(url))) { } else if ((values = gitlabCommitUrl.exec(url))) {
fetchUrl = gitLabUrlGen(values[1], values[2], 'commit', values[3]); fetchUrl = gitLabUrlGen(values[1], values[2], "commit", values[3]);
} else if ((values = gitlabPrUrl.exec(url))) { } else if ((values = gitlabPrUrl.exec(url))) {
fetchUrl = gitLabUrlGen(values[1], values[2], 'merge_requests', values[3]); fetchUrl = gitLabUrlGen(values[1], values[2], "merge_requests", values[3]);
} else if ((values = bitbucketCommitUrl.exec(url))) { } else if ((values = bitbucketCommitUrl.exec(url))) {
fetchUrl = bitbucketUrlGen(values[1], values[2], 'commit', values[3]); fetchUrl = bitbucketUrlGen(values[1], values[2], "commit", values[3]);
} else if ((values = bitbucketPrUrl.exec(url))) { } else if ((values = bitbucketPrUrl.exec(url))) {
fetchUrl = bitbucketUrlGen(values[1], values[2], 'pullrequests', values[3]); fetchUrl = bitbucketUrlGen(values[1], values[2], "pullrequests", values[3]);
} else { } else {
console.info('Could not parse url, using the provided url.'); console.info("Could not parse url, using the provided url.");
fetchUrl = 'https://crossorigin.me/' + url; fetchUrl = "https://crossorigin.me/" + url;
} }
return { return {
@ -144,90 +144,96 @@ $(document).ready(function() {
} }
function smartDraw(urlOpt, forced) { function smartDraw(urlOpt, forced) {
var url = urlOpt || $url.val(); const url = urlOpt || $url.val();
var req = prepareUrl(url); const req = prepareUrl(url);
draw(req, forced); draw(req, forced);
} }
function draw(req, forced) { function draw(req, forced) {
if (!validateUrl(req.url)) { if (!validateUrl(req.url)) {
console.error('Invalid url provided!'); console.error("Invalid url provided!");
return; return;
} }
if (validateUrl(req.originalUrl)) updateUrl(req.originalUrl); if (validateUrl(req.originalUrl)) updateUrl(req.originalUrl);
var outputFormat = $outputFormat.val(); const outputFormat = $outputFormat.val();
var showFiles = $showFiles.is(':checked'); const showFiles = $showFiles.is(":checked");
var matching = $matching.val(); const matching = $matching.val();
var wordsThreshold = $wordsThreshold.val(); const wordsThreshold = $wordsThreshold.val();
var matchingMaxComparisons = $matchingMaxComparisons.val(); const matchingMaxComparisons = $matchingMaxComparisons.val();
fetch(req.url, { fetch(req.url, {
method: 'GET', method: "GET",
headers: req.headers, headers: req.headers,
mode: 'cors', mode: "cors",
cache: 'default' cache: "default"
}) })
.then(function(res) { .then(function(res) {
return res.text(); return res.text();
}) })
.then(function(data) { .then(function(data) {
var container = '#url-diff-container'; const container = "#url-diff-container";
var diff2htmlUi = new Diff2HtmlUI({diff: data}); const diff2htmlUi = new Diff2HtmlUI({ diff: data });
if (outputFormat === 'side-by-side') { if (outputFormat === "side-by-side") {
$container.css({'width': '100%'}); $container.css({ width: "100%" });
} else { } else {
$container.css({'width': ''}); $container.css({ width: "" });
} }
var params = getParamsFromSearch(window.location.search); const params = getParamsFromSearch(window.location.search);
delete params[searchParam]; delete params[searchParam];
if (forced) { if (forced) {
params['outputFormat'] = outputFormat; params.outputFormat = outputFormat;
params['showFiles'] = showFiles; params.showFiles = showFiles;
params['matching'] = matching; params.matching = matching;
params['wordsThreshold'] = wordsThreshold; params.wordsThreshold = wordsThreshold;
params['matchingMaxComparisons'] = matchingMaxComparisons; params.matchingMaxComparisons = matchingMaxComparisons;
} else { } else {
params['outputFormat'] = params['outputFormat'] || outputFormat; params.outputFormat = params.outputFormat || outputFormat;
params['showFiles'] = String(params['showFiles']) !== 'false' || (params['showFiles'] === null && showFiles); params.showFiles = String(params.showFiles) !== "false" || (params.showFiles === null && showFiles);
params['matching'] = params['matching'] || matching; params.matching = params.matching || matching;
params['wordsThreshold'] = params['wordsThreshold'] || wordsThreshold; params.wordsThreshold = params.wordsThreshold || wordsThreshold;
params['matchingMaxComparisons'] = params['matchingMaxComparisons'] || matchingMaxComparisons; params.matchingMaxComparisons = params.matchingMaxComparisons || matchingMaxComparisons;
$outputFormat.val(params['outputFormat']); $outputFormat.val(params.outputFormat);
$showFiles.prop('checked', params['showFiles']); $showFiles.prop("checked", params.showFiles);
$matching.val(params['matching']); $matching.val(params.matching);
$wordsThreshold.val(params['wordsThreshold']); $wordsThreshold.val(params.wordsThreshold);
$matchingMaxComparisons.val(params['matchingMaxComparisons']); $matchingMaxComparisons.val(params.matchingMaxComparisons);
} }
params['synchronisedScroll'] = params['synchronisedScroll'] || true; params.synchronisedScroll = params.synchronisedScroll || true;
diff2htmlUi.draw(container, params); diff2htmlUi.draw(container, params);
diff2htmlUi.fileListCloseable(container, params['fileListCloseable'] || false); diff2htmlUi.fileListCloseable(container, params.fileListCloseable || false);
if (params['highlight'] === undefined || params['highlight']) { if (params.highlight === undefined || params.highlight) {
diff2htmlUi.highlightCode(container); diff2htmlUi.highlightCode(container);
} }
}); });
} }
function validateUrl(url) { function validateUrl(url) {
return /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(url); return /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(
url
);
} }
function updateUrl(url) { function updateUrl(url) {
var params = getParamsFromSearch(window.location.search); const params = getParamsFromSearch(window.location.search);
if (params[searchParam] === url) return; if (params[searchParam] === url) return;
params[searchParam] = url; params[searchParam] = url;
var paramString = Object.keys(params).map(function(k) { return k + '=' + params[k]; }).join('&'); const paramString = Object.keys(params)
.map(function(k) {
return k + "=" + params[k];
})
.join("&");
window.location = 'demo.html?' + paramString; window.location = "demo.html?" + paramString;
} }
}); });

2618
yarn.lock

File diff suppressed because it is too large Load diff