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" }}
paths:
- ./node_modules
- run: yarn run test
- run: yarn run lint
- run: yarn run coverage
- run: yarn run codacy
- persist_to_workspace:
root: ~/diff2html
paths:
- docs
- dist
- build
build-node_4:
<<: *common-build
@ -80,11 +80,6 @@ jobs:
steps:
- attach_workspace:
at: .
- run:
name: Prepare website sources
command: |
rm -f docs/assets
mv dist docs/assets
- run:
name: Deploy
working_directory: ~/diff2html/docs

View file

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

View file

@ -1,10 +1,12 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 6,
"ecmaVersion": 2018,
"sourceType": "module",
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
"jsx": true
},
"sourceType": "module"
}
},
"env": {
"es6": true,
@ -19,325 +21,17 @@
"worker": true,
"qunit": true
},
"plugins": [
"standard",
"promise"
],
"plugins": ["standard", "node", "import", "promise", "@typescript-eslint", "jest"],
"globals": {
"document": false,
"navigator": false,
"window": false
},
"rules": {
"accessor-pairs": 2,
"arrow-spacing": [
2,
{
"before": true,
"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"
]
}
"extends": [
"plugin:@typescript-eslint/recommended",
"plugin:jest/recommended",
"plugin:promise/recommended",
"standard",
"plugin:prettier/recommended"
]
}

5
.gitignore vendored
View file

@ -28,3 +28,8 @@ bower_components/
# 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": {
"node": ">=4"
},
"preferGlobal": true,
"scripts": {
"release": "./scripts/release.sh",
"release-website": "./scripts/release-website.sh",
"templates": "./scripts/hulk.js --wrapper node --variable 'browserTemplates' ./src/templates/*.mustache > ./src/templates/diff2html-templates.js",
"build": "tsc",
"lint": "eslint '*/**/*.{js,jsx,ts,tsx}'",
"style": "yarn run lint",
"lint": "eslint .",
"coverage": "istanbul cover _mocha -- -u exports -R spec ./test/**/*",
"check-coverage": "istanbul check-coverage --statements 90 --functions 90 --branches 85 --lines 90 ./coverage/coverage.json",
"test": "yarn run coverage && yarn run check-coverage",
"test": "jest",
"coverage": "jest --collectCoverage",
"coverage-html": "yarn run coverage && open ./coverage/index.html",
"codacy": "cat ./coverage/lcov.info | codacy-coverage",
"preversion": "yarn run release && yarn run release-website && yarn run lint && yarn test",
"version": "git add -A src dist docs package.json",
"release": "yarn run release-css && yarn run release-templates && yarn run release-ts && yarn run release-browser-bundle && yarn run release-website",
"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"
},
"main": "./src/diff2html.js",
"main": "./build/commonjs-node/diff2html.js",
"browser": {
"fs": false
},
@ -60,28 +63,38 @@
"whatwg-fetch": "^3.0.0"
},
"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",
"browserify": "^16.2.3",
"browserify": "^16.5.0",
"clean-css-cli": "^4.3.0",
"codacy-coverage": "^3.4.0",
"eslint": "^5.16.0",
"eslint-plugin-promise": "^4.1.1",
"eslint-plugin-standard": "^4.0.0",
"eslint": "6.2.2",
"eslint-config-prettier": "6.1.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",
"istanbul": "^0.4.5",
"jest": "24.9.0",
"mkdirp": "^0.5.1",
"mocha": "5.2.0",
"nopt": "^4.0.1",
"postcss-cli": "^6.1.2",
"uglify-js": "^3.6.0"
"postcss-cli": "^6.1.3",
"prettier": "1.18.2",
"ts-jest": "24.0.2",
"typescript": "^3.6.3",
"terser": "^4.3.8"
},
"resolutions": {
"lodash": "4.17.14"
"lodash": "4.17.15"
},
"license": "MIT",
"files": [
"src",
"dist",
"typescript"
"build"
]
}

View file

@ -16,61 +16,66 @@
*/
// dependencies
var hogan = require('hogan.js');
var path = require('path');
var nopt = require('nopt');
var mkderp = require('mkdirp');
var fs = require('fs');
const path = require("path");
const fs = require("fs");
const hogan = require("hogan.js");
const nopt = require("nopt");
const mkderp = require("mkdirp");
// locals
var specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'];
var specialsRegExp = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
var options = {
'namespace': String,
'outputdir': path,
'variable': String,
'wrapper': String,
'version': true,
'help': true
const specials = ["/", ".", "*", "+", "?", "|", "(", ")", "[", "]", "{", "}", "\\"];
const specialsRegExp = new RegExp("(\\" + specials.join("|\\") + ")", "g");
let options = {
namespace: String,
outputdir: path,
variable: String,
wrapper: String,
version: true,
help: true
};
var shortHand = {
'n': ['--namespace'],
'o': ['--outputdir'],
'vn': ['--variable'],
'w': ['--wrapper'],
'h': ['--help'],
'v': ['--version']
const shortHand = {
n: ["--namespace"],
o: ["--outputdir"],
vn: ["--variable"],
w: ["--wrapper"],
h: ["--help"],
v: ["--version"]
};
var templates;
let templates;
// options
options = nopt(options, shortHand);
// escape special regexp characters
function esc(text) {
return text.replace(specialsRegExp, '\\$1');
return text.replace(specialsRegExp, "\\$1");
}
// cyan function for rob
function cyan(text) {
return '\x1B[36m' + text + '\x1B[39m';
return "\x1B[36m" + text + "\x1B[39m";
}
// check for dirs and correct ext (<3 for windows)
function extractFiles(args) {
var usage = '\n' +
cyan('USAGE:') + ' hulk [--wrapper wrapper] [--outputdir outputdir] ' +
'[--namespace namespace] [--variable variable] FILES\n\n' +
cyan('OPTIONS:') + ' [-w, --wrapper] :: wraps the template (i.e. amd)\n' +
' [-o, --outputdir] :: outputs the templates as individual files to a directory\n\n' +
' [-n, --namespace] :: prepend string to template names\n\n' +
' [-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';
var files = [];
const usage =
"\n" +
cyan("USAGE:") +
" hulk [--wrapper wrapper] [--outputdir outputdir] " +
"[--namespace namespace] [--variable variable] FILES\n\n" +
cyan("OPTIONS:") +
" [-w, --wrapper] :: wraps the template (i.e. amd)\n" +
" [-o, --outputdir] :: outputs the templates as individual files to a directory\n\n" +
" [-n, --namespace] :: prepend string to template names\n\n" +
" [-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) {
console.log(require('../package.json').version);
console.log(require("../package.json").version);
process.exit(0);
}
@ -81,12 +86,13 @@ function extractFiles(args) {
args.forEach(function(arg) {
if (/\*/.test(arg)) {
arg = arg.split('*');
arg = arg.split("*");
files = files.concat(
fs.readdirSync(arg[0] || '.')
fs
.readdirSync(arg[0] || ".")
.map(function(f) {
var file = path.join(arg[0], f);
return new RegExp(esc(arg[1]) + '$').test(f) && fs.statSync(file).isFile() && file;
const file = path.join(arg[0], f);
return new RegExp(esc(arg[1]) + "$").test(f) && fs.statSync(file).isFile() && file;
})
.filter(function(f) {
return f;
@ -112,51 +118,65 @@ function removeByteOrderMark(text) {
// wrap templates
function wrap(file, name, openedFile) {
switch (options.wrapper) {
case 'amd':
return 'define(' + (!options.outputdir ? '"' + path.join(path.dirname(file), name) + '", ' : '') +
case "amd":
return (
"define(" +
(!options.outputdir ? '"' + path.join(path.dirname(file), name) + '", ' : "") +
'[ "hogan.js" ], function(Hogan){ return new Hogan.Template(' +
hogan.compile(openedFile, {asString: 1}) +
');});';
case 'node':
var globalObj = 'global.' + (options.variable || 'templates') + '["' + name + '"]';
var globalStmt = globalObj + ' = new Hogan.Template(' + hogan.compile(openedFile, {asString: 1}) + ');';
hogan.compile(openedFile, { asString: 1 }) +
");});"
);
case "node":
var globalObj = "global." + (options.variable || "templates") + '["' + name + '"]';
var globalStmt = globalObj + " = new Hogan.Template(" + hogan.compile(openedFile, { asString: 1 }) + ");";
var nodeOutput = globalStmt;
// if we have a template per file the export will expose the template directly
if (options.outputdir) {
nodeOutput = nodeOutput + '\n' + 'module.exports = ' + globalObj + ';';
nodeOutput = nodeOutput + "\n" + "module.exports = " + globalObj + ";";
}
return nodeOutput;
default:
return (options.variable || 'templates') +
'["' + name + '"] = new Hogan.Template(' +
hogan.compile(openedFile, {asString: 1}) +
');';
return (
(options.variable || "templates") +
'["' +
name +
'"] = new Hogan.Template(' +
hogan.compile(openedFile, { asString: 1 }) +
");"
);
}
}
function prepareOutput(content) {
var variableName = options.variable || 'templates';
const variableName = options.variable || "templates";
switch (options.wrapper) {
case 'amd':
case "amd":
return content;
case 'node':
var nodeExport = '';
case "node":
var nodeExport = "";
// if we have aggregated templates the export will expose the template map
if (!options.outputdir) {
nodeExport = 'module.exports = global.' + variableName + ';\n';
nodeExport = "module.exports = global." + variableName + ";\n";
}
return '(function() {\n' +
'if (!!!global.' + variableName + ') global.' + variableName + ' = {};\n' +
return (
"(function() {\n" +
"if (!!!global." +
variableName +
") global." +
variableName +
" = {};\n" +
'var Hogan = require("hogan.js");' +
content + '\n' +
content +
"\n" +
nodeExport +
'})();';
"})();"
);
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
function namespace(name) {
return (options.namespace || '') + name;
return (options.namespace || "") + name;
}
// write a template foreach file that matches template extension
templates = extractFiles(options.argv.remain)
.map(function(file) {
var openedFile = fs.readFileSync(file, 'utf-8').trim();
var name;
let openedFile = fs.readFileSync(file, "utf-8").trim();
let name;
if (!openedFile) return;
name = namespace(path.basename(file).replace(/\..*$/, ''));
name = namespace(path.basename(file).replace(/\..*$/, ""));
openedFile = removeByteOrderMark(openedFile);
openedFile = wrap(file, name, openedFile);
if (!options.outputdir) return openedFile;
fs.writeFileSync(path.join(options.outputdir, name + '.js')
, prepareOutput(openedFile));
fs.writeFileSync(path.join(options.outputdir, name + ".js"), prepareOutput(openedFile));
})
.filter(function(t) {
return t;
@ -190,4 +209,4 @@ templates = extractFiles(options.argv.remain)
// output templates
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';
var pagesRoot = root + '/pages';
const hogan = require("hogan.js");
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 = {
'all': {
'demoUrl': 'demo.html?diff=https://github.com/rtfpessoa/diff2html/pull/106'
const template = hogan.compile(readFile(root + "/template.mustache"));
const options = {
all: {
demoUrl: "demo.html?diff=https://github.com/rtfpessoa/diff2html/pull/106"
},
'demo': {
'extraClass': 'template-index-min'
demo: {
extraClass: "template-index-min"
}
};
websitePages.map(function(page) {
var pagePartialTemplate = hogan.compile(readFile(pagesRoot + '/' + page + '/' + page + '.partial.mustache'));
var pageAssetsTemplate = hogan.compile(readFile(pagesRoot + '/' + page + '/' + page + '-assets.partial.mustache'));
var pageScriptsTemplate = hogan.compile(readFile(pagesRoot + '/' + page + '/' + page + '-scripts.partial.mustache'));
const pagePartialTemplate = hogan.compile(readFile(pagesRoot + "/" + page + "/" + page + ".partial.mustache"));
const pageAssetsTemplate = hogan.compile(readFile(pagesRoot + "/" + page + "/" + page + "-assets.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
var genericOptions = options['all'] || {};
const genericOptions = options.all || {};
for (key in genericOptions) {
if (genericOptions.hasOwnProperty(key)) {
templateOptions[key] = genericOptions[key];
@ -36,32 +40,31 @@ websitePages.map(function(page) {
}
// Allow each page to have custom options
var pageOptions = options[page] || {};
const pageOptions = options[page] || {};
for (key in pageOptions) {
if (pageOptions.hasOwnProperty(key)) {
templateOptions[key] = pageOptions[key];
}
}
var pagePartial = pagePartialTemplate.render(templateOptions);
var pageAssets = pageAssetsTemplate.render(templateOptions);
var pageScripts = pageScriptsTemplate.render(templateOptions);
const pagePartial = pagePartialTemplate.render(templateOptions);
const pageAssets = pageAssetsTemplate.render(templateOptions);
const pageScripts = pageScriptsTemplate.render(templateOptions);
templateOptions.assets = pageAssets;
templateOptions.scripts = pageScripts;
templateOptions.content = pagePartial;
var pageHtml = template.render(templateOptions);
writeFile('docs/' + page + '.html', pageHtml);
const pageHtml = template.render(templateOptions);
writeFile("docs/" + page + ".html", pageHtml);
});
function readFile(filePath) {
try {
return fs.readFileSync(filePath, 'utf8');
} catch (_ignore) {
}
return fs.readFileSync(filePath, "utf8");
} catch (_ignore) {}
return '';
return "";
}
function writeFile(filePath, content) {

View file

@ -1,17 +1,14 @@
#!/bin/bash
#
# diff2html website release script
# by rtfpessoa
#
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_CSS_FILE=${INPUT_DIR}/main.css
OUTPUT_DIR=docs
OUTPUT_DIR=${SCRIPT_DIRECTORY}/../docs
OUTPUT_DEMO_JS=${OUTPUT_DIR}/demo.js
OUTPUT_DEMO_MIN_JS=${OUTPUT_DIR}/demo.min.js
OUTPUT_CSS_FILE=${OUTPUT_DIR}/main.css
@ -21,7 +18,7 @@ echo "Creating diff2html website release ..."
echo "Cleaning previous versions ..."
rm -rf ${OUTPUT_DIR}
mkdir -p ${OUTPUT_DIR}
mkdir -p ${OUTPUT_DIR}/assets
echo "Minifying ${OUTPUT_CSS_FILE} to ${OUTPUT_MIN_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}
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 ..."
node ./scripts/release-website.js
node ${SCRIPT_DIRECTORY}/release-website.js
echo "Copying static files ..."
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}/sitemap.xml ${OUTPUT_DIR}/
echo "Creating diff2html assets symlink ..."
ln -s ../dist docs/assets
echo "Copying diff2html resources ..."
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!"

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 =
'diff --git a/sample b/sample\n' +
'index 0000001..0ddf2ba\n' +
'--- a/sample\n' +
'+++ b/sample\n' +
'@@ -1 +1 @@\n' +
'-test\n' +
'+test1\n';
const jsonExample1 = [
{
blocks: [
{
lines: [
{
content: "-test",
type: "d2h-del",
oldNumber: 1,
newNumber: null
},
{
content: "+test1",
type: "d2h-ins",
oldNumber: null,
newNumber: 1
}
],
oldStartLine: "1",
oldStartLine2: null,
newStartLine: "1",
header: "@@ -1 +1 @@"
}
],
deletedLines: 1,
addedLines: 1,
checksumBefore: "0000001",
checksumAfter: "0ddf2ba",
oldName: "sample",
language: undefined,
newName: "sample",
isCombined: false
}
];
var jsonExample1 =
[
{
blocks: [
{
lines: [
{
content: '-test',
type: 'd2h-del',
oldNumber: 1,
newNumber: null
},
{
content: '+test1',
type: 'd2h-ins',
oldNumber: null,
newNumber: 1
}
],
oldStartLine: '1',
oldStartLine2: null,
newStartLine: '1',
header: '@@ -1 +1 @@'
}
],
deletedLines: 1,
addedLines: 1,
checksumBefore: '0000001',
checksumAfter: '0ddf2ba',
oldName: 'sample',
language: undefined,
newName: 'sample',
isCombined: false
}
];
var filesExample1 =
const filesExample1 =
'<div class="d2h-file-list-wrapper">\n' +
' <div class="d2h-file-list-header">\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-show">show</a>\n' +
' </div>\n' +
" </div>\n" +
' <ol class="d2h-file-list">\n' +
' <li class="d2h-file-list-line">\n' +
' <span class="d2h-file-name-wrapper">\n' +
@ -64,13 +61,13 @@ var filesExample1 =
' <span class="d2h-file-stats">\n' +
' <span class="d2h-lines-added">+1</span>\n' +
' <span class="d2h-lines-deleted">-1</span>\n' +
' </span>\n' +
' </span>\n' +
'</li>\n' +
' </ol>\n' +
'</div>';
" </span>\n" +
" </span>\n" +
"</li>\n" +
" </ol>\n" +
"</div>";
var htmlLineExample1 =
const htmlLineExample1 =
'<div class="d2h-wrapper">\n' +
' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="">\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' +
' </svg> <span class="d2h-file-name">sample</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-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' +
" <tr>\n" +
' <td class="d2h-code-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">@@ -1 +1 @@</div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-del">\n' +
' <div class="line-num1">1</div>\n' +
'<div class="line-num2"></div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-del">\n' +
' <div class="d2h-code-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn"><del>test</del></span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' +
'<div class="line-num2">1</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn"><ins>test1</ins></span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>\n' +
' </tbody>\n' +
' </table>\n' +
' </div>\n' +
' </div>\n' +
'</div>\n' +
'</div>';
" </div>\n" +
" </td>\n" +
"</tr>\n" +
" </tbody>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
"</div>\n" +
"</div>";
var htmlLineExample1WithFilesSummary = filesExample1 + htmlLineExample1;
const htmlLineExample1WithFilesSummary = filesExample1 + htmlLineExample1;
var htmlSideExample1 =
const htmlSideExample1 =
'<div class="d2h-wrapper">\n' +
' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="">\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' +
' </svg> <span class="d2h-file-name">sample</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-file-side-diff">\n' +
' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' +
" <tr>\n" +
' <td class="d2h-code-side-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info">@@ -1 +1 @@</div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-del">\n' +
' 1\n' +
' </td>\n' +
" 1\n" +
" </td>\n" +
' <td class="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-ctn"><del>test</del></span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>\n' +
' </tbody>\n' +
' </table>\n' +
' </div>\n' +
' </div>\n' +
" </div>\n" +
" </td>\n" +
"</tr>\n" +
" </tbody>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
' <div class="d2h-file-side-diff">\n' +
' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' +
" <tr>\n" +
' <td class="d2h-code-side-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info"></div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-ins">\n' +
' 1\n' +
' </td>\n' +
" 1\n" +
" </td>\n" +
' <td class="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-ctn"><ins>test1</ins></span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>\n' +
' </tbody>\n' +
' </table>\n' +
' </div>\n' +
' </div>\n' +
' </div>\n' +
'</div>\n' +
'</div>';
" </div>\n" +
" </td>\n" +
"</tr>\n" +
" </tbody>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
"</div>\n" +
"</div>";
var htmlSideExample1WithFilesSummary = filesExample1 + htmlSideExample1;
const htmlSideExample1WithFilesSummary = filesExample1 + htmlSideExample1;
describe('Diff2Html', function() {
describe('getJsonFromDiff', function() {
it('should parse simple diff to json', 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' +
'+test1\n';
var result = Diff2Html.getJsonFromDiff(diff);
describe("Diff2Html", function() {
describe("getJsonFromDiff", function() {
it("should parse simple diff to json", 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" +
"+test1\n";
const result = Diff2Html.getJsonFromDiff(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);
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);
});
// Test case for issue #49
it('should parse diff with added EOF', function() {
var diff =
'diff --git a/sample.scala b/sample.scala\n' +
'index b583263..8b2fc3e 100644\n' +
'--- a/b583263..8b2fc3e\n' +
'+++ b/8b2fc3e\n' +
'@@ -50,5 +50,7 @@ case class Response[+A](value: Option[A],\n' +
' object ResponseErrorCode extends JsonEnumeration {\n' +
' val NoError, ServiceError, JsonError,\n' +
' InvalidPermissions, MissingPermissions, GenericError,\n' +
'- TokenRevoked, MissingToken = Value\n' +
'-}\n' +
'\\ No newline at end of file\n' +
'+ TokenRevoked, MissingToken,\n' +
'+ IndexLock, RepositoryError, NotValidRepo, PullRequestNotMergeable, BranchError,\n' +
'+ PluginError, CodeParserError, EngineError = Value\n' +
'+}\n';
var result = Diff2Html.getJsonFromDiff(diff);
it("should parse diff with added EOF", function() {
const diff =
"diff --git a/sample.scala b/sample.scala\n" +
"index b583263..8b2fc3e 100644\n" +
"--- a/b583263..8b2fc3e\n" +
"+++ b/8b2fc3e\n" +
"@@ -50,5 +50,7 @@ case class Response[+A](value: Option[A],\n" +
" object ResponseErrorCode extends JsonEnumeration {\n" +
" val NoError, ServiceError, JsonError,\n" +
" InvalidPermissions, MissingPermissions, GenericError,\n" +
"- TokenRevoked, MissingToken = Value\n" +
"-}\n" +
"\\ No newline at end of file\n" +
"+ TokenRevoked, MissingToken,\n" +
"+ IndexLock, RepositoryError, NotValidRepo, PullRequestNotMergeable, BranchError,\n" +
"+ PluginError, CodeParserError, EngineError = Value\n" +
"+}\n";
const result = Diff2Html.getJsonFromDiff(diff);
assert.equal(50, 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].oldNumber);
expect(50).toEqual(result[0].blocks[0].lines[0].newNumber);
assert.equal(51, 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].oldNumber);
expect(51).toEqual(result[0].blocks[0].lines[1].newNumber);
assert.equal(52, 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].oldNumber);
expect(52).toEqual(result[0].blocks[0].lines[2].newNumber);
assert.equal(53, result[0].blocks[0].lines[3].oldNumber);
assert.equal(null, result[0].blocks[0].lines[3].newNumber);
expect(53).toEqual(result[0].blocks[0].lines[3].oldNumber);
expect(null).toEqual(result[0].blocks[0].lines[3].newNumber);
assert.equal(54, result[0].blocks[0].lines[4].oldNumber);
assert.equal(null, result[0].blocks[0].lines[4].newNumber);
expect(54).toEqual(result[0].blocks[0].lines[4].oldNumber);
expect(null).toEqual(result[0].blocks[0].lines[4].newNumber);
assert.equal(null, result[0].blocks[0].lines[5].oldNumber);
assert.equal(53, result[0].blocks[0].lines[5].newNumber);
expect(null).toEqual(result[0].blocks[0].lines[5].oldNumber);
expect(53).toEqual(result[0].blocks[0].lines[5].newNumber);
assert.equal(null, result[0].blocks[0].lines[6].oldNumber);
assert.equal(54, result[0].blocks[0].lines[6].newNumber);
expect(null).toEqual(result[0].blocks[0].lines[6].oldNumber);
expect(54).toEqual(result[0].blocks[0].lines[6].newNumber);
assert.equal(null, result[0].blocks[0].lines[7].oldNumber);
assert.equal(55, result[0].blocks[0].lines[7].newNumber);
expect(null).toEqual(result[0].blocks[0].lines[7].oldNumber);
expect(55).toEqual(result[0].blocks[0].lines[7].newNumber);
assert.equal(null, result[0].blocks[0].lines[8].oldNumber);
assert.equal(56, result[0].blocks[0].lines[8].newNumber);
expect(null).toEqual(result[0].blocks[0].lines[8].oldNumber);
expect(56).toEqual(result[0].blocks[0].lines[8].newNumber);
});
it('should generate pretty line by line html from diff', function() {
var result = Diff2Html.getPrettyHtmlFromDiff(diffExample1);
assert.equal(htmlLineExample1, result);
it("should generate pretty line by line html from diff", function() {
const result = Diff2Html.getPrettyHtmlFromDiff(diffExample1);
expect(htmlLineExample1).toEqual(result);
});
it('should generate pretty line by line html from json', function() {
var result = Diff2Html.getPrettyHtmlFromJson(jsonExample1);
assert.equal(htmlLineExample1, result);
it("should generate pretty line by line html from json", function() {
const result = Diff2Html.getPrettyHtmlFromJson(jsonExample1);
expect(htmlLineExample1).toEqual(result);
});
it('should generate pretty diff with files summary', function() {
var result = Diff2Html.getPrettyHtmlFromDiff(diffExample1, {showFiles: true});
assert.equal(htmlLineExample1WithFilesSummary, result);
it("should generate pretty diff with files summary", function() {
const result = Diff2Html.getPrettyHtmlFromDiff(diffExample1, { showFiles: true });
expect(htmlLineExample1WithFilesSummary).toEqual(result);
});
it('should generate pretty side by side html from diff', function() {
var result = Diff2Html.getPrettySideBySideHtmlFromDiff(diffExample1);
assert.equal(htmlSideExample1, result);
it("should generate pretty side by side html from diff", function() {
const result = Diff2Html.getPrettySideBySideHtmlFromDiff(diffExample1);
expect(htmlSideExample1).toEqual(result);
});
it('should generate pretty side by side html from json', function() {
var result = Diff2Html.getPrettySideBySideHtmlFromJson(jsonExample1);
assert.equal(htmlSideExample1, result);
it("should generate pretty side by side html from json", function() {
const result = Diff2Html.getPrettySideBySideHtmlFromJson(jsonExample1);
expect(htmlSideExample1).toEqual(result);
});
it('should generate pretty side by side html from diff', function() {
var result = Diff2Html.getPrettySideBySideHtmlFromDiff(diffExample1, {showFiles: true});
assert.equal(htmlSideExample1WithFilesSummary, result);
it("should generate pretty side by side html from diff 2", function() {
const result = Diff2Html.getPrettySideBySideHtmlFromDiff(diffExample1, { showFiles: true });
expect(htmlSideExample1WithFilesSummary).toEqual(result);
});
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' +
'index fc3e3f4..b486d10 100644\n' +
'--- a/CHANGELOG.md\n' +
'+++ b/CHANGELOG.md\n' +
'@@ -1,7 +1,6 @@\n' +
' # Change Log\n' +
' All notable changes to this project will be documented in this file.\n' +
' This project adheres to [Semantic Versioning](http://semver.org/).\n' +
it("should generate pretty side by side html from diff with html on headers", function() {
const diffExample2 =
"diff --git a/CHANGELOG.md b/CHANGELOG.md\n" +
"index fc3e3f4..b486d10 100644\n" +
"--- a/CHANGELOG.md\n" +
"+++ b/CHANGELOG.md\n" +
"@@ -1,7 +1,6 @@\n" +
" # Change Log\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>\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" +
' - 1.1.7:\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 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.7:\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 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.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' +
' \n';
" - 1.1.4: [patch] Promise refactoring\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 class="d2h-file-header">\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' +
' </svg> <span class="d2h-file-name">CHANGELOG.md</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-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' +
" <tr>\n" +
' <td class="d2h-code-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">@@ -1,7 +1,6 @@</div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">1</div>\n' +
'<div class="line-num2">1</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="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-ctn"># Change Log</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">2</div>\n' +
'<div class="line-num2">2</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="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-ctn">All notable changes to this project will be documented in this file.</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">3</div>\n' +
'<div class="line-num2">3</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="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-ctn">This project adheres to [Semantic Versioning](http:&#x2F;&#x2F;semver.org&#x2F;).</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-del">\n' +
' <div class="line-num1">4</div>\n' +
'<div class="line-num2"></div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-del">\n' +
' <div class="d2h-code-line d2h-del">\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' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">5</div>\n' +
'<div class="line-num2">4</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="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-ctn">$a=&quot;&lt;table&gt;&lt;tr&gt;&lt;td&gt;</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">6</div>\n' +
'<div class="line-num2">5</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="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-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' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">7</div>\n' +
'<div class="line-num2">6</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="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-ctn">- 1.1.8:</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>\n' +
'<tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr>\n" +
"<tr>\n" +
' <td class="d2h-code-linenumber d2h-info"></td>\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' +
' </td>\n' +
'</tr><tr>\n' +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">11</div>\n' +
'<div class="line-num2">10</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="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-ctn">- 1.1.7:</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">12</div>\n' +
'<div class="line-num2">11</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="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-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' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">13</div>\n' +
'<div class="line-num2">12</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="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-ctn"> - Fix credential dialog issue [#864](https:&#x2F;&#x2F;github.com&#x2F;FredrikNoren&#x2F;ungit&#x2F;pull&#x2F;864)</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-del">\n' +
' <div class="line-num1">14</div>\n' +
'<div class="line-num2"></div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-del">\n' +
' <div class="d2h-code-line d2h-del">\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' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' +
'<div class="line-num2">13</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\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' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">15</div>\n' +
'<div class="line-num2">14</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="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-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' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">16</div>\n' +
'<div class="line-num2">15</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="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-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' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">17</div>\n' +
'<div class="line-num2">16</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="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-ctn">- 1.1.4: [patch] Promise refactoring</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">18</div>\n' +
'<div class="line-num2">17</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-cntx">\n' +
' <div class="d2h-code-line d2h-cntx">\n' +
' <span class="d2h-code-line-prefix">&nbsp;</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>\n' +
' </tbody>\n' +
' </table>\n' +
' </div>\n' +
' </div>\n' +
'</div>\n' +
'</div>';
" </div>\n" +
" </td>\n" +
"</tr>\n" +
" </tbody>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
"</div>\n" +
"</div>";
var result = Diff2Html.getPrettyHtmlFromDiff(diffExample2);
assert.equal(result, htmlExample2);
const result = Diff2Html.getPrettyHtmlFromDiff(diffExample2);
expect(result).toEqual(htmlExample2);
});
});
});

View file

@ -1,92 +1,102 @@
var assert = require('assert');
var FileListPrinter = require('../src/file-list-printer.js').FileListPrinter;
const FileListPrinter = require("../file-list-printer.js").FileListPrinter;
describe('FileListPrinter', function() {
describe('generateFileList', function() {
it('should expose old and new files to templates', function() {
var files = [{
addedlines: 12,
deletedlines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js'
}, {
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name1.js',
newName: 'my/file/name2.js'
}, {
addedLines: 12,
deletedLines: 0,
language: 'js',
oldName: 'dev/null',
newName: 'my/file/name.js',
isNew: true
}, {
addedLines: 0,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'dev/null',
isDeleted: true
}];
describe("FileListPrinter", function() {
describe("generateFileList", function() {
it("should expose old and new files to templates", function() {
const files = [
{
addedlines: 12,
deletedlines: 41,
language: "js",
oldName: "my/file/name.js",
newName: "my/file/name.js"
},
{
addedLines: 12,
deletedLines: 41,
language: "js",
oldName: "my/file/name1.js",
newName: "my/file/name2.js"
},
{
addedLines: 12,
deletedLines: 0,
language: "js",
oldName: "dev/null",
newName: "my/file/name.js",
isNew: true
},
{
addedLines: 0,
deletedLines: 41,
language: "js",
oldName: "my/file/name.js",
newName: "dev/null",
isDeleted: true
}
];
var fileListPrinter = new FileListPrinter({
const fileListPrinter = new FileListPrinter({
rawTemplates: {
'file-summary-wrapper': '{{{files}}}',
'file-summary-line': '{{oldName}}, {{newName}}, {{fileName}}'
"file-summary-wrapper": "{{{files}}}",
"file-summary-line": "{{oldName}}, {{newName}}, {{fileName}}"
}
});
var fileHtml = fileListPrinter.generateFileList(files);
var expected = 'my/file/name.js, my/file/name.js, my/file/name.js\n' +
'my/file/name1.js, my/file/name2.js, my/file/{name1.js → name2.js}\n' +
'dev/null, my/file/name.js, my/file/name.js\n' +
'my/file/name.js, dev/null, my/file/name.js';
const fileHtml = fileListPrinter.generateFileList(files);
const expected =
"my/file/name.js, my/file/name.js, my/file/name.js\n" +
"my/file/name1.js, my/file/name2.js, my/file/{name1.js → name2.js}\n" +
"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() {
var files = [{
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js'
}, {
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name1.js',
newName: 'my/file/name2.js'
}, {
addedLines: 12,
deletedLines: 0,
language: 'js',
oldName: 'dev/null',
newName: 'my/file/name.js',
isNew: true
}, {
addedLines: 0,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'dev/null',
isDeleted: true
}];
it("should work for all kinds of files", function() {
const files = [
{
addedLines: 12,
deletedLines: 41,
language: "js",
oldName: "my/file/name.js",
newName: "my/file/name.js"
},
{
addedLines: 12,
deletedLines: 41,
language: "js",
oldName: "my/file/name1.js",
newName: "my/file/name2.js"
},
{
addedLines: 12,
deletedLines: 0,
language: "js",
oldName: "dev/null",
newName: "my/file/name.js",
isNew: true
},
{
addedLines: 0,
deletedLines: 41,
language: "js",
oldName: "my/file/name.js",
newName: "dev/null",
isDeleted: true
}
];
var fileListPrinter = new FileListPrinter();
var fileHtml = fileListPrinter.generateFileList(files);
const fileListPrinter = new FileListPrinter();
const fileHtml = fileListPrinter.generateFileList(files);
var expected =
const expected =
'<div class="d2h-file-list-wrapper">\n' +
' <div class="d2h-file-list-header">\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-show">show</a>\n' +
' </div>\n' +
" </div>\n" +
' <ol class="d2h-file-list">\n' +
' <li class="d2h-file-list-line">\n' +
' <span class="d2h-file-name-wrapper">\n' +
@ -97,9 +107,9 @@ describe('FileListPrinter', function() {
' <span class="d2h-file-stats">\n' +
' <span class="d2h-lines-added">+12</span>\n' +
' <span class="d2h-lines-deleted">-41</span>\n' +
' </span>\n' +
' </span>\n' +
'</li>\n' +
" </span>\n" +
" </span>\n" +
"</li>\n" +
'<li class="d2h-file-list-line">\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' +
@ -109,9 +119,9 @@ describe('FileListPrinter', function() {
' <span class="d2h-file-stats">\n' +
' <span class="d2h-lines-added">+12</span>\n' +
' <span class="d2h-lines-deleted">-41</span>\n' +
' </span>\n' +
' </span>\n' +
'</li>\n' +
" </span>\n" +
" </span>\n" +
"</li>\n" +
'<li class="d2h-file-list-line">\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' +
@ -121,9 +131,9 @@ describe('FileListPrinter', function() {
' <span class="d2h-file-stats">\n' +
' <span class="d2h-lines-added">+12</span>\n' +
' <span class="d2h-lines-deleted">-0</span>\n' +
' </span>\n' +
' </span>\n' +
'</li>\n' +
" </span>\n" +
" </span>\n" +
"</li>\n" +
'<li class="d2h-file-list-line">\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' +
@ -133,13 +143,13 @@ describe('FileListPrinter', function() {
' <span class="d2h-file-stats">\n' +
' <span class="d2h-lines-added">+0</span>\n' +
' <span class="d2h-lines-deleted">-41</span>\n' +
' </span>\n' +
' </span>\n' +
'</li>\n' +
' </ol>\n' +
'</div>';
" </span>\n" +
" </span>\n" +
"</li>\n" +
" </ol>\n" +
"</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() {
it('should return an empty diff', function() {
var lineByLinePrinter = new LineByLinePrinter({});
var fileHtml = lineByLinePrinter._generateEmptyDiff();
var expected = '<tr>\n' +
describe("LineByLinePrinter", function() {
describe("_generateEmptyDiff", function() {
it("should return an empty diff", function() {
const lineByLinePrinter = new LineByLinePrinter({});
const fileHtml = lineByLinePrinter._generateEmptyDiff();
const expected =
"<tr>\n" +
' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">\n' +
' File without changes\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" File without changes\n" +
" </div>\n" +
" </td>\n" +
"</tr>";
assert.equal(expected, fileHtml);
expect(expected).toEqual(fileHtml);
});
});
describe('makeLineHtml', function() {
it('should work for insertions', function() {
var diffParser = require('../src/diff-parser.js').DiffParser;
var lineByLinePrinter = new LineByLinePrinter({});
var fileHtml = lineByLinePrinter.makeLineHtml(false,
diffParser.LINE_TYPE.INSERTS, '', 30, 'test', '+');
fileHtml = fileHtml.replace(/\n\n+/g, '\n');
var expected = '<tr>\n' +
describe("makeLineHtml", function() {
it("should work for insertions", function() {
const diffParser = require("../diff-parser.js").DiffParser;
const lineByLinePrinter = new LineByLinePrinter({});
let fileHtml = lineByLinePrinter.makeLineHtml(false, diffParser.LINE_TYPE.INSERTS, "", 30, "test", "+");
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
const expected =
"<tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' +
'<div class="line-num2">30</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn">test</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" </div>\n" +
" </td>\n" +
"</tr>";
assert.equal(expected, fileHtml);
expect(expected).toEqual(fileHtml);
});
it('should work for deletions', function() {
var diffParser = require('../src/diff-parser.js').DiffParser;
var lineByLinePrinter = new LineByLinePrinter({});
var fileHtml = lineByLinePrinter.makeLineHtml(false,
diffParser.LINE_TYPE.DELETES, 30, '', 'test', '-');
fileHtml = fileHtml.replace(/\n\n+/g, '\n');
var expected = '<tr>\n' +
it("should work for deletions", function() {
const diffParser = require("../diff-parser.js").DiffParser;
const lineByLinePrinter = new LineByLinePrinter({});
let fileHtml = lineByLinePrinter.makeLineHtml(false, diffParser.LINE_TYPE.DELETES, 30, "", "test", "-");
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
const expected =
"<tr>\n" +
' <td class="d2h-code-linenumber d2h-del">\n' +
' <div class="line-num1">30</div>\n' +
'<div class="line-num2"></div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-del">\n' +
' <div class="d2h-code-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn">test</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" </div>\n" +
" </td>\n" +
"</tr>";
assert.equal(expected, fileHtml);
expect(expected).toEqual(fileHtml);
});
it('should convert indents into non breakin spaces (2 white spaces)', function() {
var diffParser = require('../src/diff-parser.js').DiffParser;
var lineByLinePrinter = new LineByLinePrinter({});
var fileHtml = lineByLinePrinter.makeLineHtml(false,
diffParser.LINE_TYPE.INSERTS, '', 30, ' test', '+');
fileHtml = fileHtml.replace(/\n\n+/g, '\n');
var expected = '<tr>\n' +
it("should convert indents into non breakin spaces (2 white spaces)", function() {
const diffParser = require("../diff-parser.js").DiffParser;
const lineByLinePrinter = new LineByLinePrinter({});
let fileHtml = lineByLinePrinter.makeLineHtml(false, diffParser.LINE_TYPE.INSERTS, "", 30, " test", "+");
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
const expected =
"<tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' +
'<div class="line-num2">30</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn"> test</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" </div>\n" +
" </td>\n" +
"</tr>";
assert.equal(expected, fileHtml);
expect(expected).toEqual(fileHtml);
});
it('should convert indents into non breakin spaces (4 white spaces)', function() {
var diffParser = require('../src/diff-parser.js').DiffParser;
var lineByLinePrinter = new LineByLinePrinter({});
var fileHtml = lineByLinePrinter.makeLineHtml(false,
diffParser.LINE_TYPE.INSERTS, '', 30, ' test', '+');
fileHtml = fileHtml.replace(/\n\n+/g, '\n');
var expected = '<tr>\n' +
it("should convert indents into non breakin spaces (4 white spaces)", function() {
const diffParser = require("../diff-parser.js").DiffParser;
const lineByLinePrinter = new LineByLinePrinter({});
let fileHtml = lineByLinePrinter.makeLineHtml(false, diffParser.LINE_TYPE.INSERTS, "", 30, " test", "+");
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
const expected =
"<tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' +
'<div class="line-num2">30</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn"> test</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" </div>\n" +
" </td>\n" +
"</tr>";
assert.equal(expected, fileHtml);
expect(expected).toEqual(fileHtml);
});
it('should preserve tabs', function() {
var diffParser = require('../src/diff-parser.js').DiffParser;
var lineByLinePrinter = new LineByLinePrinter({});
var fileHtml = lineByLinePrinter.makeLineHtml(false,
diffParser.LINE_TYPE.INSERTS, '', 30, '\ttest', '+');
fileHtml = fileHtml.replace(/\n\n+/g, '\n');
var expected = '<tr>\n' +
it("should preserve tabs", function() {
const diffParser = require("../diff-parser.js").DiffParser;
const lineByLinePrinter = new LineByLinePrinter({});
let fileHtml = lineByLinePrinter.makeLineHtml(false, diffParser.LINE_TYPE.INSERTS, "", 30, "\ttest", "+");
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
const expected =
"<tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' +
'' +
"" +
'<div class="line-num2">30</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn">\ttest</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" </div>\n" +
" </td>\n" +
"</tr>";
assert.equal(expected, fileHtml);
expect(expected).toEqual(fileHtml);
});
});
describe('makeFileDiffHtml', function() {
it('should work for simple file', function() {
var lineByLinePrinter = new LineByLinePrinter({});
describe("makeFileDiffHtml", function() {
it("should work for simple file", function() {
const lineByLinePrinter = new LineByLinePrinter({});
var file = {
const file = {
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js'
language: "js",
oldName: "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 class="d2h-file-header">\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' +
' </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' +
' </div>\n' +
" </div>\n" +
' <div class="d2h-file-diff">\n' +
' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' +
' <span>Random Html</span>\n' +
' </tbody>\n' +
' </table>\n' +
' </div>\n' +
' </div>\n' +
'</div>';
" <span>Random Html</span>\n" +
" </tbody>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
"</div>";
assert.equal(expected, fileHtml);
expect(expected).toEqual(fileHtml);
});
it('should work for simple added file', function() {
var lineByLinePrinter = new LineByLinePrinter({});
it("should work for simple added file", function() {
const lineByLinePrinter = new LineByLinePrinter({});
var file = {
const file = {
addedLines: 12,
deletedLines: 0,
language: 'js',
oldName: 'dev/null',
newName: 'my/file/name.js',
language: "js",
oldName: "dev/null",
newName: "my/file/name.js",
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 class="d2h-file-header">\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' +
' </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' +
' </div>\n' +
" </div>\n" +
' <div class="d2h-file-diff">\n' +
' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' +
' <span>Random Html</span>\n' +
' </tbody>\n' +
' </table>\n' +
' </div>\n' +
' </div>\n' +
'</div>';
" <span>Random Html</span>\n" +
" </tbody>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
"</div>";
assert.equal(expected, fileHtml);
expect(expected).toEqual(fileHtml);
});
it('should work for simple deleted file', function() {
var lineByLinePrinter = new LineByLinePrinter({});
it("should work for simple deleted file", function() {
const lineByLinePrinter = new LineByLinePrinter({});
var file = {
const file = {
addedLines: 0,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'dev/null',
language: "js",
oldName: "my/file/name.js",
newName: "dev/null",
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 class="d2h-file-header">\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' +
' </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' +
' </div>\n' +
" </div>\n" +
' <div class="d2h-file-diff">\n' +
' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' +
' <span>Random Html</span>\n' +
' </tbody>\n' +
' </table>\n' +
' </div>\n' +
' </div>\n' +
'</div>';
" <span>Random Html</span>\n" +
" </tbody>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
"</div>";
assert.equal(expected, fileHtml);
expect(expected).toEqual(fileHtml);
});
it('should work for simple renamed file', function() {
var lineByLinePrinter = new LineByLinePrinter({});
it("should work for simple renamed file", function() {
const lineByLinePrinter = new LineByLinePrinter({});
var file = {
const file = {
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name1.js',
newName: 'my/file/name2.js',
language: "js",
oldName: "my/file/name1.js",
newName: "my/file/name2.js",
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 class="d2h-file-header">\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' +
' </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' +
' </div>\n' +
" </div>\n" +
' <div class="d2h-file-diff">\n' +
' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' +
' <span>Random Html</span>\n' +
' </tbody>\n' +
' </table>\n' +
' </div>\n' +
' </div>\n' +
'</div>';
" <span>Random Html</span>\n" +
" </tbody>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
"</div>";
assert.equal(expected, fileHtml);
expect(expected).toEqual(fileHtml);
});
it('should return empty when option renderNothingWhenEmpty is true and file blocks not present', function() {
var lineByLinePrinter = new LineByLinePrinter({
it("should return empty when option renderNothingWhenEmpty is true and file blocks not present", function() {
const lineByLinePrinter = new LineByLinePrinter({
renderNothingWhenEmpty: true
});
var file = {
const file = {
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() {
it('should work for simple content', function() {
var lineByLinePrinter = new LineByLinePrinter({});
var fileHtml = lineByLinePrinter.makeLineByLineHtmlWrapper('<span>Random Html</span>');
describe("makeLineByLineHtmlWrapper", function() {
it("should work for simple content", function() {
const lineByLinePrinter = new LineByLinePrinter({});
const fileHtml = lineByLinePrinter.makeLineByLineHtmlWrapper("<span>Random Html</span>");
var expected =
'<div class="d2h-wrapper">\n' +
' <span>Random Html</span>\n' +
'</div>';
const expected = '<div class="d2h-wrapper">\n' + " <span>Random Html</span>\n" + "</div>";
assert.equal(expected, fileHtml);
expect(expected).toEqual(fileHtml);
});
});
describe('generateLineByLineJsonHtml', function() {
it('should work for list of files', function() {
var exampleJson = [
describe("generateLineByLineJsonHtml", function() {
it("should work for list of files", function() {
const exampleJson = [
{
blocks: [
{
lines: [
{
content: '-test',
type: 'd2h-del',
content: "-test",
type: "d2h-del",
oldNumber: 1,
newNumber: null
},
{
content: '+test1r',
type: 'd2h-ins',
content: "+test1r",
type: "d2h-ins",
oldNumber: null,
newNumber: 1
}
],
oldStartLine: '1',
oldStartLine: "1",
oldStartLine2: null,
newStartLine: '1',
header: '@@ -1 +1 @@'
newStartLine: "1",
header: "@@ -1 +1 @@"
}
],
deletedLines: 1,
addedLines: 1,
checksumBefore: '0000001',
checksumAfter: '0ddf2ba',
oldName: 'sample',
checksumBefore: "0000001",
checksumAfter: "0ddf2ba",
oldName: "sample",
language: undefined,
newName: 'sample',
newName: "sample",
isCombined: false
}
];
var lineByLinePrinter = new LineByLinePrinter({matching: 'lines'});
var html = lineByLinePrinter.generateLineByLineJsonHtml(exampleJson);
var expected =
const lineByLinePrinter = new LineByLinePrinter({ matching: "lines" });
const html = lineByLinePrinter.generateLineByLineJsonHtml(exampleJson);
const expected =
'<div class="d2h-wrapper">\n' +
' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="">\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' +
' </svg> <span class="d2h-file-name">sample</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-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' +
" <tr>\n" +
' <td class="d2h-code-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">@@ -1 +1 @@</div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-del">\n' +
' <div class="line-num1">1</div>\n' +
'<div class="line-num2"></div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-del">\n' +
' <div class="d2h-code-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn"><del>test</del></span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' +
'<div class="line-num2">1</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn"><ins>test1r</ins></span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>\n' +
' </tbody>\n' +
' </table>\n' +
' </div>\n' +
' </div>\n' +
'</div>\n' +
'</div>';
" </div>\n" +
" </td>\n" +
"</tr>\n" +
" </tbody>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
"</div>\n" +
"</div>";
assert.equal(expected, html);
expect(expected).toEqual(html);
});
it('should work for empty blocks', function() {
var exampleJson = [{
blocks: [],
deletedLines: 0,
addedLines: 0,
oldName: 'sample',
language: 'js',
newName: 'sample',
isCombined: false
}];
it("should work for empty blocks", function() {
const exampleJson = [
{
blocks: [],
deletedLines: 0,
addedLines: 0,
oldName: "sample",
language: "js",
newName: "sample",
isCombined: false
}
];
var lineByLinePrinter = new LineByLinePrinter({ renderNothingWhenEmpty: false });
var html = lineByLinePrinter.generateLineByLineJsonHtml(exampleJson);
var expected =
const lineByLinePrinter = new LineByLinePrinter({ renderNothingWhenEmpty: false });
const html = lineByLinePrinter.generateLineByLineJsonHtml(exampleJson);
const expected =
'<div class="d2h-wrapper">\n' +
' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">\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' +
' </svg> <span class="d2h-file-name">sample</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-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' +
" <tr>\n" +
' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">\n' +
' File without changes\n' +
' </div>\n' +
' </td>\n' +
'</tr>\n' +
' </tbody>\n' +
' </table>\n' +
' </div>\n' +
' </div>\n' +
'</div>\n' +
'</div>';
" File without changes\n" +
" </div>\n" +
" </td>\n" +
"</tr>\n" +
" </tbody>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
"</div>\n" +
"</div>";
assert.equal(expected, html);
expect(expected).toEqual(html);
});
});
describe('_processLines', function() {
it('should work for simple block header', function() {
var lineByLinePrinter = new LineByLinePrinter({});
var oldLines = [{
content: '-test',
type: 'd2h-del',
oldNumber: 1,
newNumber: null
}];
var newLines = [{
content: '+test1r',
type: 'd2h-ins',
oldNumber: null,
newNumber: 1
}];
describe("_processLines", function() {
it("should work for simple block header", function() {
const lineByLinePrinter = new LineByLinePrinter({});
const oldLines = [
{
content: "-test",
type: "d2h-del",
oldNumber: 1,
newNumber: null
}
];
const newLines = [
{
content: "+test1r",
type: "d2h-ins",
oldNumber: null,
newNumber: 1
}
];
var html = lineByLinePrinter._processLines(false, oldLines, newLines);
const html = lineByLinePrinter._processLines(false, oldLines, newLines);
var expected =
'<tr>\n' +
const expected =
"<tr>\n" +
' <td class="d2h-code-linenumber d2h-del">\n' +
' <div class="line-num1">1</div>\n' +
'<div class="line-num2"></div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-del">\n' +
' <div class="d2h-code-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn">test</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' +
'<div class="line-num2">1</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn">test1r</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" </div>\n" +
" </td>\n" +
"</tr>";
assert.equal(expected, html);
expect(expected).toEqual(html);
});
});
describe('_generateFileHtml', function() {
it('should work for simple file', function() {
var lineByLinePrinter = new LineByLinePrinter({});
var file = {
describe("_generateFileHtml", function() {
it("should work for simple file", function() {
const lineByLinePrinter = new LineByLinePrinter({});
const file = {
blocks: [
{
lines: [
{
content: ' one context line',
type: 'd2h-cntx',
content: " one context line",
type: "d2h-cntx",
oldNumber: 1,
newNumber: 1
},
{
content: '-test',
type: 'd2h-del',
content: "-test",
type: "d2h-del",
oldNumber: 2,
newNumber: null
},
{
content: '+test1r',
type: 'd2h-ins',
content: "+test1r",
type: "d2h-ins",
oldNumber: null,
newNumber: 2
},
{
content: '+test2r',
type: 'd2h-ins',
content: "+test2r",
type: "d2h-ins",
oldNumber: null,
newNumber: 3
}
],
oldStartLine: '1',
oldStartLine: "1",
oldStartLine2: null,
newStartLine: '1',
header: '@@ -1 +1 @@'
newStartLine: "1",
header: "@@ -1 +1 @@"
}
],
deletedLines: 1,
addedLines: 1,
checksumBefore: '0000001',
checksumAfter: '0ddf2ba',
oldName: 'sample',
checksumBefore: "0000001",
checksumAfter: "0ddf2ba",
oldName: "sample",
language: undefined,
newName: 'sample',
newName: "sample",
isCombined: false
};
var html = lineByLinePrinter._generateFileHtml(file);
const html = lineByLinePrinter._generateFileHtml(file);
var expected =
'<tr>\n' +
const expected =
"<tr>\n" +
' <td class="d2h-code-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' +
' <div class="d2h-code-line d2h-info">@@ -1 +1 @@</div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-cntx">\n' +
' <div class="line-num1">1</div>\n' +
'<div class="line-num2">1</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="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-ctn">one context line</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-del">\n' +
' <div class="line-num1">2</div>\n' +
'<div class="line-num2"></div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-del">\n' +
' <div class="d2h-code-line d2h-del">\n' +
' <span class="d2h-code-line-prefix">-</span>\n' +
' <span class="d2h-code-line-ctn"><del>test</del></span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' +
'<div class="line-num2">2</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn"><ins>test1r</ins></span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-linenumber d2h-ins">\n' +
' <div class="line-num1"></div>\n' +
'<div class="line-num2">3</div>\n' +
' </td>\n' +
" </td>\n" +
' <td class="d2h-ins">\n' +
' <div class="d2h-code-line d2h-ins">\n' +
' <span class="d2h-code-line-prefix">+</span>\n' +
' <span class="d2h-code-line-ctn">test2r</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" </div>\n" +
" </td>\n" +
"</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() {
it('should return an empty diff', function() {
var sideBySidePrinter = new SideBySidePrinter({});
var fileHtml = sideBySidePrinter.generateEmptyDiff();
var expectedRight = '';
var expectedLeft = '<tr>\n' +
describe("SideBySidePrinter", function() {
describe("generateEmptyDiff", function() {
it("should return an empty diff", function() {
const sideBySidePrinter = new SideBySidePrinter({});
const fileHtml = sideBySidePrinter.generateEmptyDiff();
const expectedRight = "";
const expectedLeft =
"<tr>\n" +
' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info">\n' +
' File without changes\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" File without changes\n" +
" </div>\n" +
" </td>\n" +
"</tr>";
assert.equal(expectedRight, fileHtml.right);
assert.equal(expectedLeft, fileHtml.left);
expect(expectedRight).toEqual(fileHtml.right);
expect(expectedLeft).toEqual(fileHtml.left);
});
});
describe('generateSideBySideFileHtml', function() {
it('should generate lines with the right prefixes', function() {
var sideBySidePrinter = new SideBySidePrinter({});
describe("generateSideBySideFileHtml", function() {
it("should generate lines with the right prefixes", function() {
const sideBySidePrinter = new SideBySidePrinter({});
var file = {
'blocks': [
const file = {
blocks: [
{
'lines': [
lines: [
{
'content': ' context',
'type': 'd2h-cntx',
'oldNumber': 19,
'newNumber': 19
content: " context",
type: "d2h-cntx",
oldNumber: 19,
newNumber: 19
},
{
'content': '-removed',
'type': 'd2h-del',
'oldNumber': 20,
'newNumber': null
content: "-removed",
type: "d2h-del",
oldNumber: 20,
newNumber: null
},
{
'content': '+added',
'type': 'd2h-ins',
'oldNumber': null,
'newNumber': 20
content: "+added",
type: "d2h-ins",
oldNumber: null,
newNumber: 20
},
{
'content': '+another added',
'type': 'd2h-ins',
'oldNumber': null,
'newNumber': 21
content: "+another added",
type: "d2h-ins",
oldNumber: null,
newNumber: 21
}
],
'oldStartLine': '19',
'newStartLine': '19',
'header': '@@ -19,7 +19,7 @@'
oldStartLine: "19",
newStartLine: "19",
header: "@@ -19,7 +19,7 @@"
}
],
'deletedLines': 1,
'addedLines': 1,
'checksumBefore': 'fc56817',
'checksumAfter': 'e8e7e49',
'mode': '100644',
'oldName': 'coverage.init',
'language': 'init',
'newName': 'coverage.init',
'isCombined': false
deletedLines: 1,
addedLines: 1,
checksumBefore: "fc56817",
checksumAfter: "e8e7e49",
mode: "100644",
oldName: "coverage.init",
language: "init",
newName: "coverage.init",
isCombined: false
};
var fileHtml = sideBySidePrinter.generateSideBySideFileHtml(file);
const fileHtml = sideBySidePrinter.generateSideBySideFileHtml(file);
var expectedLeft =
'<tr>\n' +
const expectedLeft =
"<tr>\n" +
' <td class="d2h-code-side-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info">@@ -19,7 +19,7 @@</div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-cntx">\n' +
' 19\n' +
' </td>\n' +
" 19\n" +
" </td>\n" +
' <td class="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-ctn">context</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-del">\n' +
' 20\n' +
' </td>\n' +
" 20\n" +
" </td>\n" +
' <td class="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-ctn"><del>removed</del></span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">\n' +
' ' +
'\n' +
' </td>\n' +
" " +
"\n" +
" </td>\n" +
' <td class="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-ctn">&nbsp;</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" </div>\n" +
" </td>\n" +
"</tr>";
var expectedRight =
'<tr>\n' +
const expectedRight =
"<tr>\n" +
' <td class="d2h-code-side-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info"></div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-cntx">\n' +
' 19\n' +
' </td>\n' +
" 19\n" +
" </td>\n" +
' <td class="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-ctn">context</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-ins">\n' +
' 20\n' +
' </td>\n' +
" 20\n" +
" </td>\n" +
' <td class="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-ctn"><ins>added</ins></span>\n' +
' </div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </div>\n" +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-ins">\n' +
' 21\n' +
' </td>\n' +
" 21\n" +
" </td>\n" +
' <td class="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-ctn">another added</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" </div>\n" +
" </td>\n" +
"</tr>";
assert.equal(expectedLeft, fileHtml.left);
assert.equal(expectedRight, fileHtml.right);
expect(expectedLeft).toEqual(fileHtml.left);
expect(expectedRight).toEqual(fileHtml.right);
});
});
describe('generateSingleLineHtml', function() {
it('should work for insertions', function() {
var diffParser = require('../src/diff-parser.js').DiffParser;
var sideBySidePrinter = new SideBySidePrinter({});
var fileHtml = sideBySidePrinter.generateSingleLineHtml(false,
diffParser.LINE_TYPE.INSERTS, 30, 'test', '+');
var expected = '<tr>\n' +
describe("generateSingleLineHtml", function() {
it("should work for insertions", function() {
const diffParser = require("../diff-parser.js").DiffParser;
const sideBySidePrinter = new SideBySidePrinter({});
const fileHtml = sideBySidePrinter.generateSingleLineHtml(false, diffParser.LINE_TYPE.INSERTS, 30, "test", "+");
const expected =
"<tr>\n" +
' <td class="d2h-code-side-linenumber d2h-ins">\n' +
' 30\n' +
' </td>\n' +
" 30\n" +
" </td>\n" +
' <td class="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-ctn">test</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" </div>\n" +
" </td>\n" +
"</tr>";
assert.equal(expected, fileHtml);
expect(expected).toEqual(fileHtml);
});
it('should work for deletions', function() {
var diffParser = require('../src/diff-parser.js').DiffParser;
var sideBySidePrinter = new SideBySidePrinter({});
var fileHtml = sideBySidePrinter.generateSingleLineHtml(false,
diffParser.LINE_TYPE.DELETES, 30, 'test', '-');
var expected = '<tr>\n' +
it("should work for deletions", function() {
const diffParser = require("../diff-parser.js").DiffParser;
const sideBySidePrinter = new SideBySidePrinter({});
const fileHtml = sideBySidePrinter.generateSingleLineHtml(false, diffParser.LINE_TYPE.DELETES, 30, "test", "-");
const expected =
"<tr>\n" +
' <td class="d2h-code-side-linenumber d2h-del">\n' +
' 30\n' +
' </td>\n' +
" 30\n" +
" </td>\n" +
' <td class="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-ctn">test</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" </div>\n" +
" </td>\n" +
"</tr>";
assert.equal(expected, fileHtml);
expect(expected).toEqual(fileHtml);
});
});
describe('generateSideBySideJsonHtml', function() {
it('should work for list of files', function() {
var exampleJson = [
describe("generateSideBySideJsonHtml", function() {
it("should work for list of files", function() {
const exampleJson = [
{
blocks: [
{
lines: [
{
content: '-test',
type: 'd2h-del',
content: "-test",
type: "d2h-del",
oldNumber: 1,
newNumber: null
},
{
content: '+test1r',
type: 'd2h-ins',
content: "+test1r",
type: "d2h-ins",
oldNumber: null,
newNumber: 1
}
],
oldStartLine: '1',
oldStartLine: "1",
oldStartLine2: null,
newStartLine: '1',
header: '@@ -1 +1 @@'
newStartLine: "1",
header: "@@ -1 +1 @@"
}
],
deletedLines: 1,
addedLines: 1,
checksumBefore: '0000001',
checksumAfter: '0ddf2ba',
oldName: 'sample',
checksumBefore: "0000001",
checksumAfter: "0ddf2ba",
oldName: "sample",
language: undefined,
newName: 'sample',
newName: "sample",
isCombined: false
}
];
var sideBySidePrinter = new SideBySidePrinter({matching: 'lines'});
var html = sideBySidePrinter.generateSideBySideJsonHtml(exampleJson);
var expected =
const sideBySidePrinter = new SideBySidePrinter({ matching: "lines" });
const html = sideBySidePrinter.generateSideBySideJsonHtml(exampleJson);
const expected =
'<div class="d2h-wrapper">\n' +
' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="">\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' +
' </svg> <span class="d2h-file-name">sample</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-file-side-diff">\n' +
' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' +
" <tr>\n" +
' <td class="d2h-code-side-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info">@@ -1 +1 @@</div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-del">\n' +
' 1\n' +
' </td>\n' +
" 1\n" +
" </td>\n" +
' <td class="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-ctn"><del>test</del></span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>\n' +
' </tbody>\n' +
' </table>\n' +
' </div>\n' +
' </div>\n' +
" </div>\n" +
" </td>\n" +
"</tr>\n" +
" </tbody>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
' <div class="d2h-file-side-diff">\n' +
' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' +
" <tr>\n" +
' <td class="d2h-code-side-linenumber d2h-info"></td>\n' +
' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info"></div>\n' +
' </td>\n' +
'</tr><tr>\n' +
" </td>\n" +
"</tr><tr>\n" +
' <td class="d2h-code-side-linenumber d2h-ins">\n' +
' 1\n' +
' </td>\n' +
" 1\n" +
" </td>\n" +
' <td class="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-ctn"><ins>test1r</ins></span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>\n' +
' </tbody>\n' +
' </table>\n' +
' </div>\n' +
' </div>\n' +
' </div>\n' +
'</div>\n' +
'</div>';
" </div>\n" +
" </td>\n" +
"</tr>\n" +
" </tbody>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
"</div>\n" +
"</div>";
assert.equal(expected, html);
expect(expected).toEqual(html);
});
it('should work for files without blocks', function() {
var exampleJson = [{
blocks: [],
oldName: 'sample',
language: 'js',
newName: 'sample',
isCombined: false
}];
it("should work for files without blocks", function() {
const exampleJson = [
{
blocks: [],
oldName: "sample",
language: "js",
newName: "sample",
isCombined: false
}
];
var sideBySidePrinter = new SideBySidePrinter();
var html = sideBySidePrinter.generateSideBySideJsonHtml(exampleJson);
var expected =
const sideBySidePrinter = new SideBySidePrinter();
const html = sideBySidePrinter.generateSideBySideJsonHtml(exampleJson);
const expected =
'<div class="d2h-wrapper">\n' +
' <div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">\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' +
' </svg> <span class="d2h-file-name">sample</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-file-side-diff">\n' +
' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' +
' <tr>\n' +
" <tr>\n" +
' <td class="d2h-info">\n' +
' <div class="d2h-code-side-line d2h-info">\n' +
' File without changes\n' +
' </div>\n' +
' </td>\n' +
'</tr>\n' +
' </tbody>\n' +
' </table>\n' +
' </div>\n' +
' </div>\n' +
" File without changes\n" +
" </div>\n" +
" </td>\n" +
"</tr>\n" +
" </tbody>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
' <div class="d2h-file-side-diff">\n' +
' <div class="d2h-code-wrapper">\n' +
' <table class="d2h-diff-table">\n' +
' <tbody class="d2h-diff-tbody">\n' +
' \n' +
' </tbody>\n' +
' </table>\n' +
' </div>\n' +
' </div>\n' +
' </div>\n' +
'</div>\n' +
'</div>';
" \n" +
" </tbody>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
"</div>\n" +
"</div>";
assert.equal(expected, html);
expect(expected).toEqual(html);
});
});
describe('processLines', function() {
it('should process file lines', function() {
var oldLines = [{
content: '-test',
type: 'd2h-del',
oldNumber: 1,
newNumber: null
}];
describe("processLines", function() {
it("should process file lines", function() {
const oldLines = [
{
content: "-test",
type: "d2h-del",
oldNumber: 1,
newNumber: null
}
];
var newLines = [{
content: '+test1r',
type: 'd2h-ins',
oldNumber: null,
newNumber: 1
}];
const newLines = [
{
content: "+test1r",
type: "d2h-ins",
oldNumber: null,
newNumber: 1
}
];
var sideBySidePrinter = new SideBySidePrinter({matching: 'lines'});
var html = sideBySidePrinter.processLines(false, oldLines, newLines);
var expectedLeft =
'<tr>\n' +
const sideBySidePrinter = new SideBySidePrinter({ matching: "lines" });
const html = sideBySidePrinter.processLines(false, oldLines, newLines);
const expectedLeft =
"<tr>\n" +
' <td class="d2h-code-side-linenumber d2h-del">\n' +
' 1\n' +
' </td>\n' +
" 1\n" +
" </td>\n" +
' <td class="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-ctn">test</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" </div>\n" +
" </td>\n" +
"</tr>";
var expectedRight =
'<tr>\n' +
const expectedRight =
"<tr>\n" +
' <td class="d2h-code-side-linenumber d2h-ins">\n' +
' 1\n' +
' </td>\n' +
" 1\n" +
" </td>\n" +
' <td class="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-ctn">test1r</span>\n' +
' </div>\n' +
' </td>\n' +
'</tr>';
" </div>\n" +
" </td>\n" +
"</tr>";
assert.equal(expectedLeft, html.left);
assert.equal(expectedRight, html.right);
expect(expectedLeft).toEqual(html.left);
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() {
var utils = require('./utils.js').Utils;
const utils = require("./utils.js").Utils;
var LINE_TYPE = {
INSERTS: 'd2h-ins',
DELETES: 'd2h-del',
INSERT_CHANGES: 'd2h-ins d2h-change',
DELETE_CHANGES: 'd2h-del d2h-change',
CONTEXT: 'd2h-cntx',
INFO: 'd2h-info'
const LINE_TYPE = {
INSERTS: "d2h-ins",
DELETES: "d2h-del",
INSERT_CHANGES: "d2h-ins d2h-change",
DELETE_CHANGES: "d2h-del d2h-change",
CONTEXT: "d2h-cntx",
INFO: "d2h-info"
};
function DiffParser() {
}
function DiffParser() {}
DiffParser.prototype.LINE_TYPE = LINE_TYPE;
DiffParser.prototype.generateDiffJson = function(diffInput, configuration) {
var config = configuration || {};
const config = configuration || {};
var files = [];
var currentFile = null;
var currentBlock = null;
var oldLine = null;
var oldLine2 = null; // Used for combined diff
var newLine = null;
const files = [];
let currentFile = null;
let currentBlock = null;
let oldLine = null;
let oldLine2 = null; // Used for combined diff
let newLine = null;
var possibleOldName;
var possibleNewName;
let possibleOldName;
let possibleNewName;
/* Diff Header */
var oldFileNameHeader = '--- ';
var newFileNameHeader = '+++ ';
var hunkHeaderPrefix = '@@';
const oldFileNameHeader = "--- ";
const newFileNameHeader = "+++ ";
const hunkHeaderPrefix = "@@";
/* Add previous block(if exists) before start a new file */
function saveBlock() {
@ -86,7 +85,7 @@
function startBlock(line) {
saveBlock();
var values;
let values;
/**
* From Range:
@ -113,7 +112,7 @@
newLine = values[3];
} else {
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;
@ -131,11 +130,11 @@
}
function createLine(line) {
var currentLine = {};
const currentLine = {};
currentLine.content = line;
var newLinePrefixes = !currentFile.isCombined ? ['+'] : ['+', ' +'];
var delLinePrefixes = !currentFile.isCombined ? ['-'] : ['-', ' -'];
const newLinePrefixes = !currentFile.isCombined ? ["+"] : ["+", " +"];
const delLinePrefixes = !currentFile.isCombined ? ["-"] : ["-", " -"];
/* Fill the line data */
if (utils.startsWith(line, newLinePrefixes)) {
@ -169,10 +168,10 @@
* Hunk header is a group of three lines started by ( `--- ` , `+++ ` , `@@` )
*/
function existHunkHeader(line, lineIdx) {
var idx = lineIdx;
let idx = lineIdx;
while (idx < diffLines.length - 3) {
if (utils.startsWith(line, 'diff')) {
if (utils.startsWith(line, "diff")) {
return false;
}
@ -190,56 +189,56 @@
return false;
}
var diffLines =
diffInput.replace(/\\ No newline at end of file/g, '')
.replace(/\r\n?/g, '\n')
.split('\n');
var diffLines = diffInput
.replace(/\\ No newline at end of file/g, "")
.replace(/\r\n?/g, "\n")
.split("\n");
/* Diff */
var oldMode = /^old mode (\d{6})/;
var newMode = /^new mode (\d{6})/;
var deletedFileMode = /^deleted file mode (\d{6})/;
var newFileMode = /^new file mode (\d{6})/;
const oldMode = /^old mode (\d{6})/;
const newMode = /^new mode (\d{6})/;
const deletedFileMode = /^deleted file mode (\d{6})/;
const newFileMode = /^new file mode (\d{6})/;
var copyFrom = /^copy from "?(.+)"?/;
var copyTo = /^copy to "?(.+)"?/;
const copyFrom = /^copy from "?(.+)"?/;
const copyTo = /^copy to "?(.+)"?/;
var renameFrom = /^rename from "?(.+)"?/;
var renameTo = /^rename to "?(.+)"?/;
const renameFrom = /^rename from "?(.+)"?/;
const renameTo = /^rename to "?(.+)"?/;
var similarityIndex = /^similarity index (\d+)%/;
var dissimilarityIndex = /^dissimilarity index (\d+)%/;
var index = /^index ([0-9a-z]+)\.\.([0-9a-z]+)\s*(\d{6})?/;
const similarityIndex = /^similarity index (\d+)%/;
const dissimilarityIndex = /^dissimilarity index (\d+)%/;
const index = /^index ([0-9a-z]+)\.\.([0-9a-z]+)\s*(\d{6})?/;
var binaryFiles = /^Binary files (.*) and (.*) differ/;
var binaryDiff = /^GIT binary patch/;
const binaryFiles = /^Binary files (.*) and (.*) differ/;
const binaryDiff = /^GIT binary patch/;
/* Combined Diff */
var combinedIndex = /^index ([0-9a-z]+),([0-9a-z]+)\.\.([0-9a-z]+)/;
var combinedMode = /^mode (\d{6}),(\d{6})\.\.(\d{6})/;
var combinedNewFile = /^new file mode (\d{6})/;
var combinedDeletedFile = /^deleted file mode (\d{6}),(\d{6})/;
const combinedIndex = /^index ([0-9a-z]+),([0-9a-z]+)\.\.([0-9a-z]+)/;
const combinedMode = /^mode (\d{6}),(\d{6})\.\.(\d{6})/;
const combinedNewFile = /^new file mode (\d{6})/;
const combinedDeletedFile = /^deleted file mode (\d{6}),(\d{6})/;
diffLines.forEach(function(line, lineIndex) {
// Unmerged paths, and possibly other non-diffable files
// https://github.com/scottgonzalez/pretty-diff/issues/11
// Also, remove some useless lines
if (!line || utils.startsWith(line, '*')) {
if (!line || utils.startsWith(line, "*")) {
return;
}
// Used to store regex capture groups
var values;
let values;
var prevLine = diffLines[lineIndex - 1];
var nxtLine = diffLines[lineIndex + 1];
var afterNxtLine = diffLines[lineIndex + 2];
const prevLine = diffLines[lineIndex - 1];
const nxtLine = diffLines[lineIndex + 1];
const afterNxtLine = diffLines[lineIndex + 2];
if (utils.startsWith(line, 'diff')) {
if (utils.startsWith(line, "diff")) {
startFile();
// 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))) {
possibleOldName = _getFilename(null, values[1], config.dstPrefix);
possibleNewName = _getFilename(null, values[2], config.srcPrefix);
@ -249,15 +248,14 @@
return;
}
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
(
utils.startsWith(line, oldFileNameHeader) && // If we get to an old file path header line
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
(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
utils.startsWith(nxtLine, newFileNameHeader) && utils.startsWith(afterNxtLine, hunkHeaderPrefix)
)
)
utils.startsWith(nxtLine, newFileNameHeader) &&
utils.startsWith(afterNxtLine, hunkHeaderPrefix)))
) {
startFile();
}
@ -268,18 +266,19 @@
* - https://github.com/rtfpessoa/diff2html/issues/87
*/
if (
(utils.startsWith(line, oldFileNameHeader) &&
utils.startsWith(nxtLine, newFileNameHeader)) ||
(utils.startsWith(line, newFileNameHeader) &&
utils.startsWith(prevLine, oldFileNameHeader))
(utils.startsWith(line, oldFileNameHeader) && utils.startsWith(nxtLine, newFileNameHeader)) ||
(utils.startsWith(line, newFileNameHeader) && utils.startsWith(prevLine, oldFileNameHeader))
) {
/*
* --- Date Timestamp[FractionalSeconds] TimeZone
* --- 2002-02-21 23:30:39.942229878 -0800
*/
if (currentFile && !currentFile.oldName &&
utils.startsWith(line, '--- ') && (values = getSrcFilename(line, config))) {
if (
currentFile &&
!currentFile.oldName &&
utils.startsWith(line, "--- ") &&
(values = getSrcFilename(line, config))
) {
currentFile.oldName = values;
currentFile.language = getExtension(currentFile.oldName, currentFile.language);
return;
@ -289,8 +288,12 @@
* +++ Date Timestamp[FractionalSeconds] TimeZone
* +++ 2002-02-21 23:30:39.942229878 -0800
*/
if (currentFile && !currentFile.newName &&
utils.startsWith(line, '+++ ') && (values = getDstFilename(line, config))) {
if (
currentFile &&
!currentFile.newName &&
utils.startsWith(line, "+++ ") &&
(values = getDstFilename(line, config))
) {
currentFile.newName = values;
currentFile.language = getExtension(currentFile.newName, currentFile.language);
return;
@ -311,12 +314,12 @@
* 2. Old line starts with: -
* 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);
return;
}
var doesNotExistHunkHeader = !existHunkHeader(line, lineIndex);
const doesNotExistHunkHeader = !existHunkHeader(line, lineIndex);
/*
* Git diffs provide more information regarding files modes, renames, copies,
@ -356,7 +359,7 @@
currentFile.isBinary = true;
currentFile.oldName = _getFilename(null, values[1], config.srcPrefix);
currentFile.newName = _getFilename(null, values[2], config.dstPrefix);
startBlock('Binary file');
startBlock("Binary file");
} else if ((values = binaryDiff.exec(line))) {
currentFile.isBinary = true;
startBlock(line);
@ -390,7 +393,7 @@
};
function getExtension(filename, language) {
var nameSplit = filename.split('.');
const nameSplit = filename.split(".");
if (nameSplit.length > 1) {
return nameSplit[nameSplit.length - 1];
}
@ -399,31 +402,31 @@
}
function getSrcFilename(line, cfg) {
return _getFilename('---', line, cfg.srcPrefix);
return _getFilename("---", line, cfg.srcPrefix);
}
function getDstFilename(line, cfg) {
return _getFilename('\\+\\+\\+', line, cfg.dstPrefix);
return _getFilename("\\+\\+\\+", line, cfg.dstPrefix);
}
function _getFilename(linePrefix, line, extraPrefix) {
var prefixes = ['a/', 'b/', 'i/', 'w/', 'c/', 'o/'];
const prefixes = ["a/", "b/", "i/", "w/", "c/", "o/"];
if (extraPrefix) {
prefixes.push(extraPrefix);
}
var FilenameRegExp;
let FilenameRegExp;
if (linePrefix) {
FilenameRegExp = new RegExp('^' + linePrefix + ' "?(.+?)"?$');
FilenameRegExp = new RegExp("^" + linePrefix + ' "?(.+?)"?$');
} else {
FilenameRegExp = new RegExp('^"?(.+?)"?$');
}
var filename;
var values = FilenameRegExp.exec(line);
let filename;
const values = FilenameRegExp.exec(line);
if (values && values[1]) {
filename = values[1];
var matchingPrefixes = prefixes.filter(function(p) {
const matchingPrefixes = prefixes.filter(function(p) {
return filename.indexOf(p) === 0;
});
@ -435,7 +438,7 @@
// Cleanup timestamps generated by the unified diff (diff command) as specified in
// https://www.gnu.org/software/diffutils/manual/html_node/Detailed-Unified.html
// 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;

11
src/diff2html.d.ts vendored
View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

@ -8,17 +8,17 @@
*
*/
/*global $, hljs, Diff2Html*/
/* global $, hljs, Diff2Html */
(function() {
var highlightJS = require('./highlight.js-internals.js').HighlightJS;
const highlightJS = require("./highlight.js-internals.js").HighlightJS;
var diffJson = null;
var defaultTarget = 'body';
var currentSelectionColumnId = -1;
let diffJson = null;
const defaultTarget = "body";
let currentSelectionColumnId = -1;
function Diff2HtmlUI(config) {
var cfg = config || {};
const cfg = config || {};
if (cfg.diff) {
diffJson = Diff2Html.getJsonFromDiff(cfg.diff);
@ -30,9 +30,9 @@
}
Diff2HtmlUI.prototype.draw = function(targetId, config) {
var cfg = config || {};
cfg.inputFormat = 'json';
var $target = this._getTarget(targetId);
const cfg = config || {};
cfg.inputFormat = "json";
const $target = this._getTarget(targetId);
$target.html(Diff2Html.getPrettyHtml(diffJson, cfg));
if (cfg.synchronisedScroll) {
@ -41,25 +41,27 @@
};
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')
const $target = this._getTarget(targetId);
$target.find(".d2h-file-side-diff").scroll(function() {
const $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);
const $target = this._getTarget(targetId);
var hashTag = this._getHashTag();
const hashTag = this._getHashTag();
var $showBtn = $target.find('.d2h-show');
var $hideBtn = $target.find('.d2h-hide');
var $fileList = $target.find('.d2h-file-list');
const $showBtn = $target.find(".d2h-show");
const $hideBtn = $target.find(".d2h-hide");
const $fileList = $target.find(".d2h-file-list");
if (hashTag === 'files-summary-show') show();
else if (hashTag === 'files-summary-hide') hide();
if (hashTag === "files-summary-show") show();
else if (hashTag === "files-summary-hide") hide();
else if (startVisible) show();
else hide();
@ -80,51 +82,53 @@
};
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
var $files = $target.find('.d2h-file-wrapper');
const $files = $target.find(".d2h-file-wrapper");
$files.map(function(_i, file) {
var oldLinesState;
var newLinesState;
var $file = $(file);
var language = $file.data('lang');
let oldLinesState;
let newLinesState;
const $file = $(file);
const language = $file.data("lang");
// 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) {
var $line = $(line);
var text = line.textContent;
var lineParent = line.parentNode;
const $line = $(line);
const text = line.textContent;
const lineParent = line.parentNode;
var lineState;
if (lineParent.className.indexOf('d2h-del') !== -1) {
let 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);
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;
} else if (lineParent.className.indexOf('d2h-ins') !== -1) {
} else if (lineParent.className.indexOf("d2h-ins") !== -1) {
newLinesState = result.top;
} else {
oldLinesState = result.top;
newLinesState = result.top;
}
var originalStream = highlightJS.nodeStream(line);
const originalStream = highlightJS.nodeStream(line);
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;
result.value = highlightJS.mergeStreams(originalStream, highlightJS.nodeStream(resultNode), text);
}
$line.addClass('hljs');
$line.addClass("hljs");
$line.addClass(result.language);
$line.html(result.value);
});
@ -132,15 +136,15 @@
};
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;
} else if (typeof targetId === 'string') {
} 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.');
console.log("Please provide a jQuery object or a valid DOM query string.");
$target = $(defaultTarget);
}
@ -148,10 +152,10 @@
};
Diff2HtmlUI.prototype._getHashTag = function() {
var docUrl = document.URL;
var hashTagIndex = docUrl.indexOf('#');
const docUrl = document.URL;
const hashTagIndex = docUrl.indexOf("#");
var hashTag = null;
let hashTag = null;
if (hashTagIndex !== -1) {
hashTag = docUrl.substr(hashTagIndex + 1);
}
@ -166,46 +170,46 @@
};
Diff2HtmlUI.prototype._initSelection = function() {
var body = $('body');
var that = this;
const body = $("body");
const that = this;
body.on('mousedown', '.d2h-diff-table', function(event) {
var target = $(event.target);
var table = target.closest('.d2h-diff-table');
body.on("mousedown", ".d2h-diff-table", function(event) {
const target = $(event.target);
const 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');
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');
} 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);
body.on("copy", ".d2h-diff-table", function(event) {
const clipboardData = event.originalEvent.clipboardData;
const 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;
const sel = window.getSelection();
const range = sel.getRangeAt(0);
const doc = range.cloneContents();
const nodes = doc.querySelectorAll("tr");
let text = "";
const 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, '');
const td = tr.cells[tr.cells.length === 1 ? 0 : idx];
text += (i ? "\n" : "") + td.textContent.replace(/(?:\r\n|\r|\n)/g, "");
});
}

View file

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

View file

@ -6,24 +6,24 @@
*/
(function() {
var merge = require('merge');
const merge = require("merge");
function Utils() {
}
function Utils() {}
Utils.prototype.escape = function(str) {
return str.slice(0)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#x27;')
.replace(/\//g, '&#x2F;');
return str
.slice(0)
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#x27;")
.replace(/\//g, "&#x2F;");
};
Utils.prototype.startsWith = function(str, start) {
if (typeof start === 'object') {
var result = false;
if (typeof start === "object") {
let result = false;
start.forEach(function(s) {
if (str.indexOf(s) === 0) {
result = true;
@ -37,7 +37,7 @@
};
Utils.prototype.valueOrEmpty = function(value) {
return value || '';
return value || "";
};
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() {
// Improves browser compatibility
require('whatwg-fetch');
require("whatwg-fetch");
var searchParam = 'diff';
const 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');
const $container = $(".container");
const $url = $("#url");
const $outputFormat = $("#diff-url-options-output-format");
const $showFiles = $("#diff-url-options-show-files");
const $matching = $("#diff-url-options-matching");
const $wordsThreshold = $("#diff-url-options-match-words-threshold");
const $matchingMaxComparisons = $("#diff-url-options-matching-max-comparisons");
if (window.location.search) {
var url = getUrlFromSearch(window.location.search);
const url = getUrlFromSearch(window.location.search);
$url.val(url);
smartDraw(url);
}
@ -41,99 +41,99 @@ $(document).ready(function() {
.add($wordsThreshold)
.add($matchingMaxComparisons)
.change(function(e) {
console.log('');
console.log("");
console.log(e);
console.log('');
console.log("");
smartDraw(null, true);
});
function getUrlFromSearch(search) {
try {
return search
.split('?')[1]
.split(searchParam + '=')[1]
.split('&')[0];
} catch (_ignore) {
}
.split("?")[1]
.split(searchParam + "=")[1]
.split("&")[0];
} catch (_ignore) {}
return null;
}
function getParamsFromSearch(search) {
var map = {};
const map = {};
try {
search
.split('?')[1]
.split('&')
.split("?")[1]
.split("&")
.map(function(e) {
var values = e.split('=');
const values = e.split("=");
map[values[0]] = values[1];
});
} catch (_ignore) {
}
} catch (_ignore) {}
return map;
}
function bind() {
$('#url-btn').click(function(e) {
$("#url-btn").click(function(e) {
e.preventDefault();
var url = $url.val();
const url = $url.val();
smartDraw(url);
});
$url.on('paste', function(e) {
var url = e.originalEvent.clipboardData.getData('Text');
$url.on("paste", function(e) {
const url = e.originalEvent.clipboardData.getData("Text");
smartDraw(url);
});
}
function prepareUrl(url) {
var fetchUrl;
var headers = new Headers();
let fetchUrl;
const headers = new Headers();
var githubCommitUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
var githubPrUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/pull\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
const githubCommitUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
const 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)?(?:\/.*)?$/;
const gitlabCommitUrl = /^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
const 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\/(.*?)(?:\/.*)?$/;
const bitbucketCommitUrl = /^https?:\/\/(?:www\.)?bitbucket\.org\/(.*?)\/(.*?)\/commits\/(.*?)(?:\/raw)?(?:\/.*)?$/;
const 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';
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;
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';
const baseUrl = "https://bitbucket.org/api/2.0/repositories/";
if (type === "pullrequests") {
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))) {
fetchUrl = gitHubUrlGen(values[1], values[2], 'commits', values[3]);
fetchUrl = gitHubUrlGen(values[1], values[2], "commits", values[3]);
} 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))) {
fetchUrl = gitLabUrlGen(values[1], values[2], 'commit', values[3]);
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]);
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]);
fetchUrl = bitbucketUrlGen(values[1], values[2], "commit", values[3]);
} 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 {
console.info('Could not parse url, using the provided url.');
fetchUrl = 'https://crossorigin.me/' + url;
console.info("Could not parse url, using the provided url.");
fetchUrl = "https://crossorigin.me/" + url;
}
return {
@ -144,90 +144,96 @@ $(document).ready(function() {
}
function smartDraw(urlOpt, forced) {
var url = urlOpt || $url.val();
var req = prepareUrl(url);
const url = urlOpt || $url.val();
const req = prepareUrl(url);
draw(req, forced);
}
function draw(req, forced) {
if (!validateUrl(req.url)) {
console.error('Invalid url provided!');
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();
const outputFormat = $outputFormat.val();
const showFiles = $showFiles.is(":checked");
const matching = $matching.val();
const wordsThreshold = $wordsThreshold.val();
const matchingMaxComparisons = $matchingMaxComparisons.val();
fetch(req.url, {
method: 'GET',
method: "GET",
headers: req.headers,
mode: 'cors',
cache: 'default'
mode: "cors",
cache: "default"
})
.then(function(res) {
return res.text();
})
.then(function(data) {
var container = '#url-diff-container';
var diff2htmlUi = new Diff2HtmlUI({diff: data});
const container = "#url-diff-container";
const diff2htmlUi = new Diff2HtmlUI({ diff: data });
if (outputFormat === 'side-by-side') {
$container.css({'width': '100%'});
if (outputFormat === "side-by-side") {
$container.css({ width: "100%" });
} else {
$container.css({'width': ''});
$container.css({ width: "" });
}
var params = getParamsFromSearch(window.location.search);
const 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;
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;
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']);
$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;
params.synchronisedScroll = params.synchronisedScroll || true;
diff2htmlUi.draw(container, params);
diff2htmlUi.fileListCloseable(container, params['fileListCloseable'] || false);
if (params['highlight'] === undefined || params['highlight']) {
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);
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);
const 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('&');
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