refactor: Move types and use enums
This commit is contained in:
parent
f72ee2ea46
commit
4200bd7a3b
16 changed files with 236 additions and 265 deletions
|
|
@ -63,6 +63,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/diff": "4.0.2",
|
"@types/diff": "4.0.2",
|
||||||
"@types/highlight.js": "9.12.3",
|
"@types/highlight.js": "9.12.3",
|
||||||
|
"@types/hogan.js": "^3.0.0",
|
||||||
"@types/jest": "24.0.18",
|
"@types/jest": "24.0.18",
|
||||||
"@types/mkdirp": "0.5.2",
|
"@types/mkdirp": "0.5.2",
|
||||||
"@types/node": "12.7.2",
|
"@types/node": "12.7.2",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { parse, html } from "../diff2html";
|
import { parse, html } from "../diff2html";
|
||||||
import { DiffFile, LineType } from "../render-utils";
|
import { DiffFile, LineType, OutputFormatType } from "../types";
|
||||||
|
|
||||||
const diffExample1 =
|
const diffExample1 =
|
||||||
"diff --git a/sample b/sample\n" +
|
"diff --git a/sample b/sample\n" +
|
||||||
|
|
@ -271,17 +271,17 @@ describe("Diff2Html", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should generate pretty side by side html from diff", () => {
|
it("should generate pretty side by side html from diff", () => {
|
||||||
const result = html(diffExample1, { outputFormat: "side-by-side", drawFileList: false });
|
const result = html(diffExample1, { outputFormat: OutputFormatType.SIDE_BY_SIDE, drawFileList: false });
|
||||||
expect(result).toEqual(htmlSideExample1);
|
expect(result).toEqual(htmlSideExample1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should generate pretty side by side html from json", () => {
|
it("should generate pretty side by side html from json", () => {
|
||||||
const result = html(jsonExample1, { outputFormat: "side-by-side", drawFileList: false });
|
const result = html(jsonExample1, { outputFormat: OutputFormatType.SIDE_BY_SIDE, drawFileList: false });
|
||||||
expect(result).toEqual(htmlSideExample1);
|
expect(result).toEqual(htmlSideExample1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should generate pretty side by side html from diff 2", () => {
|
it("should generate pretty side by side html from diff 2", () => {
|
||||||
const result = html(diffExample1, { outputFormat: "side-by-side", drawFileList: true });
|
const result = html(diffExample1, { outputFormat: OutputFormatType.SIDE_BY_SIDE, drawFileList: true });
|
||||||
expect(result).toEqual(htmlSideExample1WithFilesSummary);
|
expect(result).toEqual(htmlSideExample1WithFilesSummary);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import LineByLineRenderer from "../line-by-line-renderer";
|
import LineByLineRenderer from "../line-by-line-renderer";
|
||||||
import HoganJsUtils from "../hoganjs-utils";
|
import HoganJsUtils from "../hoganjs-utils";
|
||||||
import { LineType, CSSLineClass, DiffLine, DiffFile } from "../render-utils";
|
import { LineType, DiffLine, DiffFile, LineMatchingType } from "../types";
|
||||||
|
import { CSSLineClass } from "../render-utils";
|
||||||
|
|
||||||
describe("LineByLineRenderer", () => {
|
describe("LineByLineRenderer", () => {
|
||||||
describe("_generateEmptyDiff", () => {
|
describe("_generateEmptyDiff", () => {
|
||||||
|
|
@ -378,7 +379,7 @@ describe("LineByLineRenderer", () => {
|
||||||
|
|
||||||
const hoganUtils = new HoganJsUtils({});
|
const hoganUtils = new HoganJsUtils({});
|
||||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {
|
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {
|
||||||
matching: "lines"
|
matching: LineMatchingType.LINES
|
||||||
});
|
});
|
||||||
const html = lineByLineRenderer.render(exampleJson);
|
const html = lineByLineRenderer.render(exampleJson);
|
||||||
const expected =
|
const expected =
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import * as renderUtils from "../render-utils";
|
import * as renderUtils from "../render-utils";
|
||||||
|
import { DiffStyleType, LineMatchingType } from "../types";
|
||||||
|
|
||||||
describe("Utils", function() {
|
describe("Utils", function() {
|
||||||
describe("getHtmlId", function() {
|
describe("getHtmlId", function() {
|
||||||
|
|
@ -73,7 +74,7 @@ describe("Utils", function() {
|
||||||
describe("diffHighlight", function() {
|
describe("diffHighlight", function() {
|
||||||
it("should highlight two lines", function() {
|
it("should highlight two lines", function() {
|
||||||
const result = renderUtils.diffHighlight("-var myVar = 2;", "+var myVariable = 3;", false, {
|
const result = renderUtils.diffHighlight("-var myVar = 2;", "+var myVariable = 3;", false, {
|
||||||
matching: "words"
|
matching: LineMatchingType.WORDS
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
|
|
@ -88,7 +89,9 @@ describe("Utils", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("should highlight two lines char by char", function() {
|
it("should highlight two lines char by char", function() {
|
||||||
const result = renderUtils.diffHighlight("-var myVar = 2;", "+var myVariable = 3;", false, { diffStyle: "char" });
|
const result = renderUtils.diffHighlight("-var myVar = 2;", "+var myVariable = 3;", false, {
|
||||||
|
diffStyle: DiffStyleType.CHAR
|
||||||
|
});
|
||||||
|
|
||||||
expect({
|
expect({
|
||||||
oldLine: {
|
oldLine: {
|
||||||
|
|
@ -103,8 +106,8 @@ describe("Utils", function() {
|
||||||
});
|
});
|
||||||
it("should highlight combined diff lines", function() {
|
it("should highlight combined diff lines", function() {
|
||||||
const result = renderUtils.diffHighlight(" -var myVar = 2;", " +var myVariable = 3;", true, {
|
const result = renderUtils.diffHighlight(" -var myVar = 2;", " +var myVariable = 3;", true, {
|
||||||
diffStyle: "word",
|
diffStyle: DiffStyleType.WORD,
|
||||||
matching: "words",
|
matching: LineMatchingType.WORDS,
|
||||||
matchWordsThreshold: 1.0
|
matchWordsThreshold: 1.0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import SideBySideRenderer from "../side-by-side-renderer";
|
import SideBySideRenderer from "../side-by-side-renderer";
|
||||||
import HoganJsUtils from "../hoganjs-utils";
|
import HoganJsUtils from "../hoganjs-utils";
|
||||||
import { LineType, CSSLineClass, DiffLine, DiffFile } from "../render-utils";
|
import { LineType, DiffLine, DiffFile, LineMatchingType } from "../types";
|
||||||
|
import { CSSLineClass } from "../render-utils";
|
||||||
|
|
||||||
describe("SideBySideRenderer", () => {
|
describe("SideBySideRenderer", () => {
|
||||||
describe("generateEmptyDiff", () => {
|
describe("generateEmptyDiff", () => {
|
||||||
|
|
@ -238,7 +239,7 @@ describe("SideBySideRenderer", () => {
|
||||||
];
|
];
|
||||||
|
|
||||||
const hoganUtils = new HoganJsUtils({});
|
const hoganUtils = new HoganJsUtils({});
|
||||||
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, { matching: "lines" });
|
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, { matching: LineMatchingType.LINES });
|
||||||
const html = sideBySideRenderer.render(exampleJson);
|
const html = sideBySideRenderer.render(exampleJson);
|
||||||
const expected =
|
const expected =
|
||||||
'<div class="d2h-wrapper">\n' +
|
'<div class="d2h-wrapper">\n' +
|
||||||
|
|
@ -386,7 +387,7 @@ describe("SideBySideRenderer", () => {
|
||||||
];
|
];
|
||||||
|
|
||||||
const hoganUtils = new HoganJsUtils({});
|
const hoganUtils = new HoganJsUtils({});
|
||||||
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, { matching: "lines" });
|
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, { matching: LineMatchingType.LINES });
|
||||||
const html = sideBySideRenderer.processLines(false, oldLines, newLines);
|
const html = sideBySideRenderer.processLines(false, oldLines, newLines);
|
||||||
const expectedLeft =
|
const expectedLeft =
|
||||||
"<tr>\n" +
|
"<tr>\n" +
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,64 @@
|
||||||
import { escapeForHtml } from "../utils";
|
import { escapeForRegExp, escapeForHtml, unifyPath, hashCode } from "../utils";
|
||||||
|
|
||||||
describe("Utils", function() {
|
describe("Utils", () => {
|
||||||
describe("escape", function() {
|
describe("escapeForRegExp", () => {
|
||||||
it("should escape & with &", function() {
|
it("should escape markdown link text", () => {
|
||||||
|
const result = escapeForRegExp("[Link](https://diff2html.xyz)");
|
||||||
|
expect(result).toEqual("\\[Link\\]\\(https:\\/\\/diff2html\\.xyz\\)");
|
||||||
|
});
|
||||||
|
it("should escape all dangerous characters", () => {
|
||||||
|
const result = escapeForRegExp("-[]/{}()*+?.\\^$|");
|
||||||
|
expect(result).toEqual("\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("escapeForHtml", () => {
|
||||||
|
it("should escape & with &", () => {
|
||||||
const result = escapeForHtml("&");
|
const result = escapeForHtml("&");
|
||||||
expect("&").toEqual(result);
|
expect(result).toEqual("&");
|
||||||
});
|
});
|
||||||
it("should escape < with <", function() {
|
it("should escape < with <", () => {
|
||||||
const result = escapeForHtml("<");
|
const result = escapeForHtml("<");
|
||||||
expect("<").toEqual(result);
|
expect(result).toEqual("<");
|
||||||
});
|
});
|
||||||
it("should escape > with >", function() {
|
it("should escape > with >", () => {
|
||||||
const result = escapeForHtml(">");
|
const result = escapeForHtml(">");
|
||||||
expect(">").toEqual(result);
|
expect(result).toEqual(">");
|
||||||
});
|
});
|
||||||
it("should escape a string with multiple problematic characters", function() {
|
it('should escape " with "', () => {
|
||||||
const result = escapeForHtml('<a href="#">\tlink text</a>');
|
const result = escapeForHtml('"');
|
||||||
const expected = "<a href="#">\tlink text</a>";
|
expect(result).toEqual(""");
|
||||||
expect(expected).toEqual(result);
|
});
|
||||||
|
it("should escape ' with '", () => {
|
||||||
|
const result = escapeForHtml("'");
|
||||||
|
expect(result).toEqual("'");
|
||||||
|
});
|
||||||
|
it("should escape / with /", () => {
|
||||||
|
const result = escapeForHtml("/");
|
||||||
|
expect(result).toEqual("/");
|
||||||
|
});
|
||||||
|
it("should escape a string containing HTML code", () => {
|
||||||
|
const result = escapeForHtml(`<a href="/search?q=diff2html">Search 'Diff2Html'</a>`);
|
||||||
|
expect(result).toEqual(
|
||||||
|
"<a href="/search?q=diff2html">Search 'Diff2Html'</a>"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("unifyPath", () => {
|
||||||
|
it("should unify windows style path", () => {
|
||||||
|
const result = unifyPath("\\Users\\Downloads\\diff.html");
|
||||||
|
expect(result).toEqual("/Users/Downloads/diff.html");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("hashCode", () => {
|
||||||
|
it("should create consistent hash for a text piece", () => {
|
||||||
|
const string = "/home/diff2html/diff.html";
|
||||||
|
expect(hashCode(string)).toEqual(hashCode(string));
|
||||||
|
});
|
||||||
|
it("should create different hash for different text pieces", () => {
|
||||||
|
expect(hashCode("/home/diff2html/diff1.html")).not.toEqual(hashCode("/home/diff2html/diff2.html"));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { DiffFile, DiffBlock, DiffLine, LineType } from "./render-utils";
|
import { DiffFile, DiffBlock, DiffLine, LineType } from "./types";
|
||||||
import { escapeForRegExp } from "./utils";
|
import { escapeForRegExp } from "./utils";
|
||||||
|
|
||||||
export interface DiffParserConfig {
|
export interface DiffParserConfig {
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,9 @@ import * as DiffParser from "./diff-parser";
|
||||||
import * as fileListPrinter from "./file-list-renderer";
|
import * as fileListPrinter from "./file-list-renderer";
|
||||||
import LineByLineRenderer, { LineByLineRendererConfig, defaultLineByLineRendererConfig } from "./line-by-line-renderer";
|
import LineByLineRenderer, { LineByLineRendererConfig, defaultLineByLineRendererConfig } from "./line-by-line-renderer";
|
||||||
import SideBySideRenderer, { SideBySideRendererConfig, defaultSideBySideRendererConfig } from "./side-by-side-renderer";
|
import SideBySideRenderer, { SideBySideRendererConfig, defaultSideBySideRendererConfig } from "./side-by-side-renderer";
|
||||||
import { DiffFile } from "./render-utils";
|
import { DiffFile, OutputFormatType } from "./types";
|
||||||
import HoganJsUtils, { HoganJsUtilsConfig } from "./hoganjs-utils";
|
import HoganJsUtils, { HoganJsUtilsConfig } from "./hoganjs-utils";
|
||||||
|
|
||||||
type OutputFormatType = "line-by-line" | "side-by-side";
|
|
||||||
|
|
||||||
export interface Diff2HtmlConfig
|
export interface Diff2HtmlConfig
|
||||||
extends DiffParser.DiffParserConfig,
|
extends DiffParser.DiffParserConfig,
|
||||||
LineByLineRendererConfig,
|
LineByLineRendererConfig,
|
||||||
|
|
@ -19,7 +17,7 @@ export interface Diff2HtmlConfig
|
||||||
export const defaultDiff2HtmlConfig = {
|
export const defaultDiff2HtmlConfig = {
|
||||||
...defaultLineByLineRendererConfig,
|
...defaultLineByLineRendererConfig,
|
||||||
...defaultSideBySideRendererConfig,
|
...defaultSideBySideRendererConfig,
|
||||||
outputFormat: "line-by-line" as OutputFormatType,
|
outputFormat: OutputFormatType.LINE_BY_LINE,
|
||||||
drawFileList: true
|
drawFileList: true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import * as renderUtils from "./render-utils";
|
import * as renderUtils from "./render-utils";
|
||||||
import HoganJsUtils from "./hoganjs-utils";
|
import HoganJsUtils from "./hoganjs-utils";
|
||||||
|
import { DiffFile } from "./types";
|
||||||
|
|
||||||
const baseTemplatesPath = "file-summary";
|
const baseTemplatesPath = "file-summary";
|
||||||
const iconsBaseTemplatesPath = "icon";
|
const iconsBaseTemplatesPath = "icon";
|
||||||
|
|
||||||
export function render(diffFiles: renderUtils.DiffFile[], hoganUtils: HoganJsUtils): string {
|
export function render(diffFiles: DiffFile[], hoganUtils: HoganJsUtils): string {
|
||||||
const files = diffFiles
|
const files = diffFiles
|
||||||
.map(file =>
|
.map(file =>
|
||||||
hoganUtils.render(
|
hoganUtils.render(
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import * as utils from "./utils";
|
||||||
import HoganJsUtils from "./hoganjs-utils";
|
import HoganJsUtils from "./hoganjs-utils";
|
||||||
import * as Rematch from "./rematch";
|
import * as Rematch from "./rematch";
|
||||||
import * as renderUtils from "./render-utils";
|
import * as renderUtils from "./render-utils";
|
||||||
|
import { DiffFile, DiffBlock, DiffLine, LineType } from "./types";
|
||||||
|
|
||||||
export interface LineByLineRendererConfig extends renderUtils.RenderConfig {
|
export interface LineByLineRendererConfig extends renderUtils.RenderConfig {
|
||||||
renderNothingWhenEmpty?: boolean;
|
renderNothingWhenEmpty?: boolean;
|
||||||
|
|
@ -25,12 +26,12 @@ export default class LineByLineRenderer {
|
||||||
private readonly hoganUtils: HoganJsUtils;
|
private readonly hoganUtils: HoganJsUtils;
|
||||||
private readonly config: typeof defaultLineByLineRendererConfig;
|
private readonly config: typeof defaultLineByLineRendererConfig;
|
||||||
|
|
||||||
constructor(hoganUtils: HoganJsUtils, config: LineByLineRendererConfig) {
|
constructor(hoganUtils: HoganJsUtils, config: LineByLineRendererConfig = {}) {
|
||||||
this.hoganUtils = hoganUtils;
|
this.hoganUtils = hoganUtils;
|
||||||
this.config = { ...defaultLineByLineRendererConfig, ...config };
|
this.config = { ...defaultLineByLineRendererConfig, ...config };
|
||||||
}
|
}
|
||||||
|
|
||||||
render(diffFiles: renderUtils.DiffFile[]): string | undefined {
|
render(diffFiles: DiffFile[]): string | undefined {
|
||||||
const htmlDiffs = diffFiles.map(file => {
|
const htmlDiffs = diffFiles.map(file => {
|
||||||
let diffs;
|
let diffs;
|
||||||
if (file.blocks.length) {
|
if (file.blocks.length) {
|
||||||
|
|
@ -45,7 +46,7 @@ export default class LineByLineRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this private after improving tests
|
// TODO: Make this private after improving tests
|
||||||
makeFileDiffHtml(file: renderUtils.DiffFile, diffs: string): string {
|
makeFileDiffHtml(file: DiffFile, diffs: string): string {
|
||||||
if (this.config.renderNothingWhenEmpty && Array.isArray(file.blocks) && file.blocks.length === 0) return "";
|
if (this.config.renderNothingWhenEmpty && Array.isArray(file.blocks) && file.blocks.length === 0) return "";
|
||||||
|
|
||||||
const fileDiffTemplate = this.hoganUtils.template(baseTemplatesPath, "file-diff");
|
const fileDiffTemplate = this.hoganUtils.template(baseTemplatesPath, "file-diff");
|
||||||
|
|
@ -75,7 +76,7 @@ export default class LineByLineRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this private after improving tests
|
// TODO: Make this private after improving tests
|
||||||
makeColumnLineNumberHtml(block: renderUtils.DiffBlock): string {
|
makeColumnLineNumberHtml(block: DiffBlock): string {
|
||||||
return this.hoganUtils.render(genericTemplatesPath, "column-line-number", {
|
return this.hoganUtils.render(genericTemplatesPath, "column-line-number", {
|
||||||
CSSLineClass: renderUtils.CSSLineClass,
|
CSSLineClass: renderUtils.CSSLineClass,
|
||||||
blockHeader: utils.escapeForHtml(block.header),
|
blockHeader: utils.escapeForHtml(block.header),
|
||||||
|
|
@ -104,7 +105,7 @@ export default class LineByLineRenderer {
|
||||||
if (!prefix) {
|
if (!prefix) {
|
||||||
const lineWithPrefix = renderUtils.deconstructLine(content, isCombined);
|
const lineWithPrefix = renderUtils.deconstructLine(content, isCombined);
|
||||||
prefix = lineWithPrefix.prefix;
|
prefix = lineWithPrefix.prefix;
|
||||||
lineWithoutPrefix = lineWithPrefix.line;
|
lineWithoutPrefix = lineWithPrefix.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefix === " ") {
|
if (prefix === " ") {
|
||||||
|
|
@ -130,7 +131,7 @@ export default class LineByLineRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this private after improving tests
|
// TODO: Make this private after improving tests
|
||||||
processLines(isCombined: boolean, oldLines: renderUtils.DiffLine[], newLines: renderUtils.DiffLine[]): string {
|
processLines(isCombined: boolean, oldLines: DiffLine[], newLines: DiffLine[]): string {
|
||||||
let lines = "";
|
let lines = "";
|
||||||
|
|
||||||
for (let i = 0; i < oldLines.length; i++) {
|
for (let i = 0; i < oldLines.length; i++) {
|
||||||
|
|
@ -161,16 +162,17 @@ export default class LineByLineRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this private after improving tests
|
// TODO: Make this private after improving tests
|
||||||
generateFileHtml(file: renderUtils.DiffFile): string {
|
generateFileHtml(file: DiffFile): string {
|
||||||
const prefixSize = renderUtils.prefixLength(file.isCombined);
|
const distance = Rematch.newDistanceFn(
|
||||||
const distance = Rematch.newDistanceFn((e: renderUtils.DiffLine) => e.content.substring(prefixSize));
|
(e: DiffLine) => renderUtils.deconstructLine(e.content, file.isCombined).content
|
||||||
|
);
|
||||||
const matcher = Rematch.newMatcherFn(distance);
|
const matcher = Rematch.newMatcherFn(distance);
|
||||||
|
|
||||||
return file.blocks
|
return file.blocks
|
||||||
.map(block => {
|
.map(block => {
|
||||||
let lines = this.makeColumnLineNumberHtml(block);
|
let lines = this.makeColumnLineNumberHtml(block);
|
||||||
let oldLines: renderUtils.DiffLine[] = [];
|
let oldLines: DiffLine[] = [];
|
||||||
let newLines: renderUtils.DiffLine[] = [];
|
let newLines: DiffLine[] = [];
|
||||||
|
|
||||||
const processChangeBlock = (): void => {
|
const processChangeBlock = (): void => {
|
||||||
let matches;
|
let matches;
|
||||||
|
|
@ -243,17 +245,17 @@ export default class LineByLineRenderer {
|
||||||
|
|
||||||
for (let i = 0; i < block.lines.length; i++) {
|
for (let i = 0; i < block.lines.length; i++) {
|
||||||
const diffLine = block.lines[i];
|
const diffLine = block.lines[i];
|
||||||
const { prefix, line } = renderUtils.deconstructLine(diffLine.content, file.isCombined);
|
const { prefix, content: line } = renderUtils.deconstructLine(diffLine.content, file.isCombined);
|
||||||
const escapedLine = utils.escapeForHtml(line);
|
const escapedLine = utils.escapeForHtml(line);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
diffLine.type !== renderUtils.LineType.INSERT &&
|
diffLine.type !== LineType.INSERT &&
|
||||||
(newLines.length > 0 || (diffLine.type !== renderUtils.LineType.DELETE && oldLines.length > 0))
|
(newLines.length > 0 || (diffLine.type !== LineType.DELETE && oldLines.length > 0))
|
||||||
) {
|
) {
|
||||||
processChangeBlock();
|
processChangeBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (diffLine.type === renderUtils.LineType.CONTEXT) {
|
if (diffLine.type === LineType.CONTEXT) {
|
||||||
lines += this.makeLineHtml(
|
lines += this.makeLineHtml(
|
||||||
file.isCombined,
|
file.isCombined,
|
||||||
renderUtils.toCSSClass(diffLine.type),
|
renderUtils.toCSSClass(diffLine.type),
|
||||||
|
|
@ -262,7 +264,7 @@ export default class LineByLineRenderer {
|
||||||
diffLine.newNumber,
|
diffLine.newNumber,
|
||||||
prefix
|
prefix
|
||||||
);
|
);
|
||||||
} else if (diffLine.type === renderUtils.LineType.INSERT && !oldLines.length) {
|
} else if (diffLine.type === LineType.INSERT && !oldLines.length) {
|
||||||
lines += this.makeLineHtml(
|
lines += this.makeLineHtml(
|
||||||
file.isCombined,
|
file.isCombined,
|
||||||
renderUtils.toCSSClass(diffLine.type),
|
renderUtils.toCSSClass(diffLine.type),
|
||||||
|
|
@ -271,9 +273,9 @@ export default class LineByLineRenderer {
|
||||||
diffLine.newNumber,
|
diffLine.newNumber,
|
||||||
prefix
|
prefix
|
||||||
);
|
);
|
||||||
} else if (diffLine.type === renderUtils.LineType.DELETE) {
|
} else if (diffLine.type === LineType.DELETE) {
|
||||||
oldLines.push(diffLine);
|
oldLines.push(diffLine);
|
||||||
} else if (diffLine.type === renderUtils.LineType.INSERT && Boolean(oldLines.length)) {
|
} else if (diffLine.type === LineType.INSERT && Boolean(oldLines.length)) {
|
||||||
newLines.push(diffLine);
|
newLines.push(diffLine);
|
||||||
} else {
|
} else {
|
||||||
console.error("Unknown state in html line-by-line generator");
|
console.error("Unknown state in html line-by-line generator");
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,7 @@ import * as jsDiff from "diff";
|
||||||
|
|
||||||
import { unifyPath, escapeForHtml, hashCode } from "./utils";
|
import { unifyPath, escapeForHtml, hashCode } from "./utils";
|
||||||
import * as rematch from "./rematch";
|
import * as rematch from "./rematch";
|
||||||
|
import { LineMatchingType, DiffStyleType, LineType, DiffLineParts, DiffFile, DiffFileName } from "./types";
|
||||||
export type DiffLineParts = {
|
|
||||||
prefix: string;
|
|
||||||
line: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export enum CSSLineClass {
|
export enum CSSLineClass {
|
||||||
INSERTS = "d2h-ins",
|
INSERTS = "d2h-ins",
|
||||||
|
|
@ -17,73 +13,17 @@ export enum CSSLineClass {
|
||||||
DELETE_CHANGES = "d2h-del d2h-change"
|
DELETE_CHANGES = "d2h-del d2h-change"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum LineType {
|
export type HighlightedLines = {
|
||||||
INSERT = "insert",
|
oldLine: {
|
||||||
DELETE = "delete",
|
prefix: string;
|
||||||
CONTEXT = "context"
|
content: string;
|
||||||
}
|
};
|
||||||
|
newLine: {
|
||||||
interface DiffLineDeleted {
|
prefix: string;
|
||||||
type: LineType.DELETE;
|
content: string;
|
||||||
oldNumber: number;
|
};
|
||||||
newNumber: undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DiffLineInserted {
|
|
||||||
type: LineType.INSERT;
|
|
||||||
oldNumber: undefined;
|
|
||||||
newNumber: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DiffLineContext {
|
|
||||||
type: LineType.CONTEXT;
|
|
||||||
oldNumber: number;
|
|
||||||
newNumber: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type DiffLine = (DiffLineDeleted | DiffLineInserted | DiffLineContext) & {
|
|
||||||
content: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface DiffBlock {
|
|
||||||
oldStartLine: number;
|
|
||||||
oldStartLine2?: number;
|
|
||||||
newStartLine: number;
|
|
||||||
header: string;
|
|
||||||
lines: DiffLine[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DiffFileName {
|
|
||||||
oldName: string;
|
|
||||||
newName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DiffFile extends DiffFileName {
|
|
||||||
addedLines: number;
|
|
||||||
deletedLines: number;
|
|
||||||
isCombined: boolean;
|
|
||||||
isGitDiff: boolean;
|
|
||||||
language: string;
|
|
||||||
blocks: DiffBlock[];
|
|
||||||
oldMode?: string | string[];
|
|
||||||
newMode?: string;
|
|
||||||
deletedFileMode?: string;
|
|
||||||
newFileMode?: string;
|
|
||||||
isDeleted?: boolean;
|
|
||||||
isNew?: boolean;
|
|
||||||
isCopy?: boolean;
|
|
||||||
isRename?: boolean;
|
|
||||||
isBinary?: boolean;
|
|
||||||
unchangedPercentage?: number;
|
|
||||||
changedPercentage?: number;
|
|
||||||
checksumBefore?: string | string[];
|
|
||||||
checksumAfter?: string;
|
|
||||||
mode?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LineMatchingType = "lines" | "words" | "none";
|
|
||||||
export type DiffStyleType = "word" | "char";
|
|
||||||
|
|
||||||
export interface RenderConfig {
|
export interface RenderConfig {
|
||||||
matching?: LineMatchingType;
|
matching?: LineMatchingType;
|
||||||
matchWordsThreshold?: number;
|
matchWordsThreshold?: number;
|
||||||
|
|
@ -92,21 +32,10 @@ export interface RenderConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultRenderConfig = {
|
export const defaultRenderConfig = {
|
||||||
matching: "none" as LineMatchingType,
|
matching: LineMatchingType.NONE,
|
||||||
matchWordsThreshold: 0.25,
|
matchWordsThreshold: 0.25,
|
||||||
maxLineLengthHighlight: 10000,
|
maxLineLengthHighlight: 10000,
|
||||||
diffStyle: "word" as DiffStyleType
|
diffStyle: DiffStyleType.WORD
|
||||||
};
|
|
||||||
|
|
||||||
type HighlightedLines = {
|
|
||||||
oldLine: {
|
|
||||||
prefix: string;
|
|
||||||
content: string;
|
|
||||||
};
|
|
||||||
newLine: {
|
|
||||||
prefix: string;
|
|
||||||
content: string;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const separator = "/";
|
const separator = "/";
|
||||||
|
|
@ -142,7 +71,7 @@ export function toCSSClass(lineType: LineType): CSSLineClass {
|
||||||
/**
|
/**
|
||||||
* Prefix length of the hunk lines in the diff
|
* Prefix length of the hunk lines in the diff
|
||||||
*/
|
*/
|
||||||
export function prefixLength(isCombined: boolean): number {
|
function prefixLength(isCombined: boolean): number {
|
||||||
return isCombined ? 2 : 1;
|
return isCombined ? 2 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,7 +82,7 @@ export function deconstructLine(line: string, isCombined: boolean): DiffLinePart
|
||||||
const indexToSplit = prefixLength(isCombined);
|
const indexToSplit = prefixLength(isCombined);
|
||||||
return {
|
return {
|
||||||
prefix: line.substring(0, indexToSplit),
|
prefix: line.substring(0, indexToSplit),
|
||||||
line: line.substring(indexToSplit)
|
content: line.substring(indexToSplit)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -263,40 +192,36 @@ export function getFileIcon(file: DiffFile): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a unique string numerical identifier based on the names of the file diff
|
* Highlight differences between @diffLine1 and @diffLine2 using <ins> and <del> tags
|
||||||
*/
|
*/
|
||||||
export function diffHighlight(
|
export function diffHighlight(
|
||||||
diffLine1: string,
|
diffLine1: string,
|
||||||
diffLine2: string,
|
diffLine2: string,
|
||||||
isCombined: boolean,
|
isCombined: boolean,
|
||||||
config: RenderConfig
|
config: RenderConfig = {}
|
||||||
): HighlightedLines {
|
): HighlightedLines {
|
||||||
const { matching, maxLineLengthHighlight, matchWordsThreshold, diffStyle } = { ...defaultRenderConfig, ...config };
|
const { matching, maxLineLengthHighlight, matchWordsThreshold, diffStyle } = { ...defaultRenderConfig, ...config };
|
||||||
const prefixLengthVal = prefixLength(isCombined);
|
|
||||||
|
|
||||||
const linePrefix1 = diffLine1.substr(0, prefixLengthVal);
|
const line1 = deconstructLine(diffLine1, isCombined);
|
||||||
const unprefixedLine1 = diffLine1.substr(prefixLengthVal);
|
const line2 = deconstructLine(diffLine2, isCombined);
|
||||||
|
|
||||||
const linePrefix2 = diffLine2.substr(0, prefixLengthVal);
|
if (line1.content.length > maxLineLengthHighlight || line2.content.length > maxLineLengthHighlight) {
|
||||||
const unprefixedLine2 = diffLine2.substr(prefixLengthVal);
|
|
||||||
|
|
||||||
if (unprefixedLine1.length > maxLineLengthHighlight || unprefixedLine2.length > maxLineLengthHighlight) {
|
|
||||||
return {
|
return {
|
||||||
oldLine: {
|
oldLine: {
|
||||||
prefix: linePrefix1,
|
prefix: line1.prefix,
|
||||||
content: escapeForHtml(unprefixedLine1)
|
content: escapeForHtml(line1.content)
|
||||||
},
|
},
|
||||||
newLine: {
|
newLine: {
|
||||||
prefix: linePrefix2,
|
prefix: line2.prefix,
|
||||||
content: escapeForHtml(unprefixedLine2)
|
content: escapeForHtml(line2.content)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const diff =
|
const diff =
|
||||||
diffStyle === "char"
|
diffStyle === "char"
|
||||||
? jsDiff.diffChars(unprefixedLine1, unprefixedLine2)
|
? jsDiff.diffChars(line1.content, line2.content)
|
||||||
: jsDiff.diffWordsWithSpace(unprefixedLine1, unprefixedLine2);
|
: jsDiff.diffWordsWithSpace(line1.content, line2.content);
|
||||||
|
|
||||||
const changedWords: jsDiff.Change[] = [];
|
const changedWords: jsDiff.Change[] = [];
|
||||||
if (diffStyle === "word" && matching === "words") {
|
if (diffStyle === "word" && matching === "words") {
|
||||||
|
|
@ -332,11 +257,11 @@ export function diffHighlight(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
oldLine: {
|
oldLine: {
|
||||||
prefix: linePrefix1,
|
prefix: line1.prefix,
|
||||||
content: removeInsElements(highlightedLine)
|
content: removeInsElements(highlightedLine)
|
||||||
},
|
},
|
||||||
newLine: {
|
newLine: {
|
||||||
prefix: linePrefix2,
|
prefix: line2.prefix,
|
||||||
content: removeDelElements(highlightedLine)
|
content: removeDelElements(highlightedLine)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import * as utils from "./utils";
|
||||||
import HoganJsUtils from "./hoganjs-utils";
|
import HoganJsUtils from "./hoganjs-utils";
|
||||||
import * as Rematch from "./rematch";
|
import * as Rematch from "./rematch";
|
||||||
import * as renderUtils from "./render-utils";
|
import * as renderUtils from "./render-utils";
|
||||||
|
import { DiffLine, LineType, DiffFile } from "./types";
|
||||||
|
|
||||||
export interface SideBySideRendererConfig extends renderUtils.RenderConfig {
|
export interface SideBySideRendererConfig extends renderUtils.RenderConfig {
|
||||||
renderNothingWhenEmpty?: boolean;
|
renderNothingWhenEmpty?: boolean;
|
||||||
|
|
@ -30,12 +31,12 @@ export default class SideBySideRenderer {
|
||||||
private readonly hoganUtils: HoganJsUtils;
|
private readonly hoganUtils: HoganJsUtils;
|
||||||
private readonly config: typeof defaultSideBySideRendererConfig;
|
private readonly config: typeof defaultSideBySideRendererConfig;
|
||||||
|
|
||||||
constructor(hoganUtils: HoganJsUtils, config: SideBySideRendererConfig) {
|
constructor(hoganUtils: HoganJsUtils, config: SideBySideRendererConfig = {}) {
|
||||||
this.hoganUtils = hoganUtils;
|
this.hoganUtils = hoganUtils;
|
||||||
this.config = { ...defaultSideBySideRendererConfig, ...config };
|
this.config = { ...defaultSideBySideRendererConfig, ...config };
|
||||||
}
|
}
|
||||||
|
|
||||||
render(diffFiles: renderUtils.DiffFile[]): string | undefined {
|
render(diffFiles: DiffFile[]): string | undefined {
|
||||||
const content = diffFiles
|
const content = diffFiles
|
||||||
.map(file => {
|
.map(file => {
|
||||||
let diffs;
|
let diffs;
|
||||||
|
|
@ -65,7 +66,7 @@ export default class SideBySideRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this private after improving tests
|
// TODO: Make this private after improving tests
|
||||||
makeDiffHtml(file: renderUtils.DiffFile, diffs: FileHtml): string {
|
makeDiffHtml(file: DiffFile, diffs: FileHtml): string {
|
||||||
const fileDiffTemplate = this.hoganUtils.template(baseTemplatesPath, "file-diff");
|
const fileDiffTemplate = this.hoganUtils.template(baseTemplatesPath, "file-diff");
|
||||||
const filePathTemplate = this.hoganUtils.template(genericTemplatesPath, "file-path");
|
const filePathTemplate = this.hoganUtils.template(genericTemplatesPath, "file-path");
|
||||||
const fileIconTemplate = this.hoganUtils.template(iconsBaseTemplatesPath, "file");
|
const fileIconTemplate = this.hoganUtils.template(iconsBaseTemplatesPath, "file");
|
||||||
|
|
@ -98,9 +99,10 @@ export default class SideBySideRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this private after improving tests
|
// TODO: Make this private after improving tests
|
||||||
generateSideBySideFileHtml(file: renderUtils.DiffFile): FileHtml {
|
generateSideBySideFileHtml(file: DiffFile): FileHtml {
|
||||||
const prefixSize = renderUtils.prefixLength(file.isCombined);
|
const distance = Rematch.newDistanceFn(
|
||||||
const distance = Rematch.newDistanceFn((e: renderUtils.DiffLine) => e.content.substring(prefixSize));
|
(e: DiffLine) => renderUtils.deconstructLine(e.content, file.isCombined).content
|
||||||
|
);
|
||||||
const matcher = Rematch.newMatcherFn(distance);
|
const matcher = Rematch.newMatcherFn(distance);
|
||||||
|
|
||||||
const fileHtml = {
|
const fileHtml = {
|
||||||
|
|
@ -112,8 +114,8 @@ export default class SideBySideRenderer {
|
||||||
fileHtml.left += this.makeSideHtml(block.header);
|
fileHtml.left += this.makeSideHtml(block.header);
|
||||||
fileHtml.right += this.makeSideHtml("");
|
fileHtml.right += this.makeSideHtml("");
|
||||||
|
|
||||||
let oldLines: renderUtils.DiffLine[] = [];
|
let oldLines: DiffLine[] = [];
|
||||||
let newLines: renderUtils.DiffLine[] = [];
|
let newLines: DiffLine[] = [];
|
||||||
|
|
||||||
const processChangeBlock = (): void => {
|
const processChangeBlock = (): void => {
|
||||||
let matches;
|
let matches;
|
||||||
|
|
@ -184,17 +186,17 @@ export default class SideBySideRenderer {
|
||||||
|
|
||||||
for (let i = 0; i < block.lines.length; i++) {
|
for (let i = 0; i < block.lines.length; i++) {
|
||||||
const diffLine = block.lines[i];
|
const diffLine = block.lines[i];
|
||||||
const { prefix, line } = renderUtils.deconstructLine(diffLine.content, file.isCombined);
|
const { prefix, content: line } = renderUtils.deconstructLine(diffLine.content, file.isCombined);
|
||||||
const escapedLine = utils.escapeForHtml(line);
|
const escapedLine = utils.escapeForHtml(line);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
diffLine.type !== renderUtils.LineType.INSERT &&
|
diffLine.type !== LineType.INSERT &&
|
||||||
(newLines.length > 0 || (diffLine.type !== renderUtils.LineType.DELETE && oldLines.length > 0))
|
(newLines.length > 0 || (diffLine.type !== LineType.DELETE && oldLines.length > 0))
|
||||||
) {
|
) {
|
||||||
processChangeBlock();
|
processChangeBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (diffLine.type === renderUtils.LineType.CONTEXT) {
|
if (diffLine.type === LineType.CONTEXT) {
|
||||||
fileHtml.left += this.generateSingleLineHtml(
|
fileHtml.left += this.generateSingleLineHtml(
|
||||||
file.isCombined,
|
file.isCombined,
|
||||||
renderUtils.toCSSClass(diffLine.type),
|
renderUtils.toCSSClass(diffLine.type),
|
||||||
|
|
@ -209,7 +211,7 @@ export default class SideBySideRenderer {
|
||||||
diffLine.newNumber,
|
diffLine.newNumber,
|
||||||
prefix
|
prefix
|
||||||
);
|
);
|
||||||
} else if (diffLine.type === renderUtils.LineType.INSERT && !oldLines.length) {
|
} else if (diffLine.type === LineType.INSERT && !oldLines.length) {
|
||||||
fileHtml.left += this.generateSingleLineHtml(file.isCombined, renderUtils.CSSLineClass.CONTEXT, "");
|
fileHtml.left += this.generateSingleLineHtml(file.isCombined, renderUtils.CSSLineClass.CONTEXT, "");
|
||||||
fileHtml.right += this.generateSingleLineHtml(
|
fileHtml.right += this.generateSingleLineHtml(
|
||||||
file.isCombined,
|
file.isCombined,
|
||||||
|
|
@ -218,9 +220,9 @@ export default class SideBySideRenderer {
|
||||||
diffLine.newNumber,
|
diffLine.newNumber,
|
||||||
prefix
|
prefix
|
||||||
);
|
);
|
||||||
} else if (diffLine.type === renderUtils.LineType.DELETE) {
|
} else if (diffLine.type === LineType.DELETE) {
|
||||||
oldLines.push(diffLine);
|
oldLines.push(diffLine);
|
||||||
} else if (diffLine.type === renderUtils.LineType.INSERT && Boolean(oldLines.length)) {
|
} else if (diffLine.type === LineType.INSERT && Boolean(oldLines.length)) {
|
||||||
newLines.push(diffLine);
|
newLines.push(diffLine);
|
||||||
} else {
|
} else {
|
||||||
console.error("unknown state in html side-by-side generator");
|
console.error("unknown state in html side-by-side generator");
|
||||||
|
|
@ -235,7 +237,7 @@ export default class SideBySideRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this private after improving tests
|
// TODO: Make this private after improving tests
|
||||||
processLines(isCombined: boolean, oldLines: renderUtils.DiffLine[], newLines: renderUtils.DiffLine[]): FileHtml {
|
processLines(isCombined: boolean, oldLines: DiffLine[], newLines: DiffLine[]): FileHtml {
|
||||||
const fileHtml = {
|
const fileHtml = {
|
||||||
right: "",
|
right: "",
|
||||||
left: ""
|
left: ""
|
||||||
|
|
@ -252,7 +254,7 @@ export default class SideBySideRenderer {
|
||||||
let newPrefix;
|
let newPrefix;
|
||||||
|
|
||||||
if (oldLine) {
|
if (oldLine) {
|
||||||
const { prefix, line } = renderUtils.deconstructLine(oldLine.content, isCombined);
|
const { prefix, content: line } = renderUtils.deconstructLine(oldLine.content, isCombined);
|
||||||
oldContent = utils.escapeForHtml(line);
|
oldContent = utils.escapeForHtml(line);
|
||||||
oldPrefix = prefix;
|
oldPrefix = prefix;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -261,7 +263,7 @@ export default class SideBySideRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newLine) {
|
if (newLine) {
|
||||||
const { prefix, line } = renderUtils.deconstructLine(newLine.content, isCombined);
|
const { prefix, content: line } = renderUtils.deconstructLine(newLine.content, isCombined);
|
||||||
newContent = utils.escapeForHtml(line);
|
newContent = utils.escapeForHtml(line);
|
||||||
newPrefix = prefix;
|
newPrefix = prefix;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -333,7 +335,7 @@ export default class SideBySideRenderer {
|
||||||
} else if (!prefix) {
|
} else if (!prefix) {
|
||||||
const lineWithPrefix = renderUtils.deconstructLine(content, isCombined);
|
const lineWithPrefix = renderUtils.deconstructLine(content, isCombined);
|
||||||
prefix = lineWithPrefix.prefix;
|
prefix = lineWithPrefix.prefix;
|
||||||
lineWithoutPrefix = lineWithPrefix.line;
|
lineWithoutPrefix = lineWithPrefix.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefix === " ") {
|
if (prefix === " ") {
|
||||||
|
|
|
||||||
84
src/types.ts
Normal file
84
src/types.ts
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
export type DiffLineParts = {
|
||||||
|
prefix: string;
|
||||||
|
content: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export enum LineType {
|
||||||
|
INSERT = "insert",
|
||||||
|
DELETE = "delete",
|
||||||
|
CONTEXT = "context"
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiffLineDeleted {
|
||||||
|
type: LineType.DELETE;
|
||||||
|
oldNumber: number;
|
||||||
|
newNumber: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiffLineInserted {
|
||||||
|
type: LineType.INSERT;
|
||||||
|
oldNumber: undefined;
|
||||||
|
newNumber: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiffLineContext {
|
||||||
|
type: LineType.CONTEXT;
|
||||||
|
oldNumber: number;
|
||||||
|
newNumber: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DiffLine = (DiffLineDeleted | DiffLineInserted | DiffLineContext) & {
|
||||||
|
content: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface DiffBlock {
|
||||||
|
oldStartLine: number;
|
||||||
|
oldStartLine2?: number;
|
||||||
|
newStartLine: number;
|
||||||
|
header: string;
|
||||||
|
lines: DiffLine[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiffFileName {
|
||||||
|
oldName: string;
|
||||||
|
newName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiffFile extends DiffFileName {
|
||||||
|
addedLines: number;
|
||||||
|
deletedLines: number;
|
||||||
|
isCombined: boolean;
|
||||||
|
isGitDiff: boolean;
|
||||||
|
language: string;
|
||||||
|
blocks: DiffBlock[];
|
||||||
|
oldMode?: string | string[];
|
||||||
|
newMode?: string;
|
||||||
|
deletedFileMode?: string;
|
||||||
|
newFileMode?: string;
|
||||||
|
isDeleted?: boolean;
|
||||||
|
isNew?: boolean;
|
||||||
|
isCopy?: boolean;
|
||||||
|
isRename?: boolean;
|
||||||
|
isBinary?: boolean;
|
||||||
|
unchangedPercentage?: number;
|
||||||
|
changedPercentage?: number;
|
||||||
|
checksumBefore?: string | string[];
|
||||||
|
checksumAfter?: string;
|
||||||
|
mode?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum OutputFormatType {
|
||||||
|
LINE_BY_LINE = "line-by-line",
|
||||||
|
SIDE_BY_SIDE = "side-by-side"
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum LineMatchingType {
|
||||||
|
LINES = "lines",
|
||||||
|
WORDS = "words",
|
||||||
|
NONE = "none"
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum DiffStyleType {
|
||||||
|
WORD = "word",
|
||||||
|
CHAR = "char"
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import HighlightJS from "highlight.js";
|
import HighlightJS from "highlight.js";
|
||||||
import * as HighlightJSInternals from "./highlight.js-internals";
|
import * as HighlightJSInternals from "./highlight.js-internals";
|
||||||
import { html, Diff2HtmlConfig, defaultDiff2HtmlConfig } from "../../diff2html";
|
import { html, Diff2HtmlConfig, defaultDiff2HtmlConfig } from "../../diff2html";
|
||||||
import { DiffFile } from "../../render-utils";
|
import { DiffFile } from "../../types";
|
||||||
|
|
||||||
export interface Diff2HtmlUIConfig extends Diff2HtmlConfig {
|
export interface Diff2HtmlUIConfig extends Diff2HtmlConfig {
|
||||||
synchronisedScroll?: boolean;
|
synchronisedScroll?: boolean;
|
||||||
|
|
|
||||||
93
typings/hoganjs.d.ts
vendored
93
typings/hoganjs.d.ts
vendored
|
|
@ -1,93 +0,0 @@
|
||||||
// Type definitions for hogan.js 3.0
|
|
||||||
// Project: http://twitter.github.com/hogan.js/
|
|
||||||
// Definitions by: Andrew Leedham <https://github.com/AndrewLeedham>
|
|
||||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
||||||
// TypeScript Version: 2.2
|
|
||||||
|
|
||||||
declare module "hogan.js" {
|
|
||||||
export interface Context {
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SectionTags {
|
|
||||||
o: string;
|
|
||||||
c: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HoganOptions {
|
|
||||||
asString?: boolean;
|
|
||||||
sectionTags?: ReadonlyArray<SectionTags>;
|
|
||||||
delimiters?: string;
|
|
||||||
disableLambda?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Token {
|
|
||||||
tag: string;
|
|
||||||
otag?: string;
|
|
||||||
ctag?: string;
|
|
||||||
i?: number;
|
|
||||||
n?: string;
|
|
||||||
text?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Leaf extends Token {
|
|
||||||
end: number;
|
|
||||||
nodes: Token[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Tree = Leaf[];
|
|
||||||
|
|
||||||
export interface Partials {
|
|
||||||
[symbol: string]: HoganTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HoganConstructor {
|
|
||||||
code: (context: any, partials: object, indent: string) => string;
|
|
||||||
partials: object;
|
|
||||||
subs: object;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HoganTemplate {
|
|
||||||
constructor(codeObject: HoganConstructor);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the template to a string.
|
|
||||||
*
|
|
||||||
* @param context - The data to render the template with.
|
|
||||||
* @param partials - The partials to render the template with.
|
|
||||||
* @param indent - The string to indent when rendering the template.
|
|
||||||
* @returns A rendered template.
|
|
||||||
*/
|
|
||||||
render(context: Context, partials?: Partials, indent?: string): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export { HoganTemplate as Template, HoganTemplate as template };
|
|
||||||
|
|
||||||
export function compile(text: string, options?: HoganOptions & { asString: false }): HoganTemplate;
|
|
||||||
export function compile(text: string, options?: HoganOptions & { asString: true }): string;
|
|
||||||
/**
|
|
||||||
* Compiles templates to HoganTemplate objects, which have a render method.
|
|
||||||
*
|
|
||||||
* @param text - Raw mustache string to compile.
|
|
||||||
* @param options - Options to use when compiling. See https://github.com/twitter/hogan.js#compilation-options.
|
|
||||||
* @returns A HoganTemplate.
|
|
||||||
*/
|
|
||||||
export function compile(text: string, options?: HoganOptions): HoganTemplate | string;
|
|
||||||
/**
|
|
||||||
* Scans templates returning an array of found tokens.
|
|
||||||
*
|
|
||||||
* @param text - Raw mustache string to scan.
|
|
||||||
* @param delimiters - A string that overrides the default delimiters. Example: "<% %>".
|
|
||||||
* @returns Found tokens.
|
|
||||||
*/
|
|
||||||
export function scan(text: string, delimiters?: string): Token[];
|
|
||||||
/**
|
|
||||||
* Structures tokens into a tree.
|
|
||||||
*
|
|
||||||
* @param tokens - An array of scanned tokens.
|
|
||||||
* @param text - Unused pass undefined.
|
|
||||||
* @param options - Options to use when parsing. See https://github.com/twitter/hogan.js#compilation-options.
|
|
||||||
* @returns The tree structure of the given tokens.
|
|
||||||
*/
|
|
||||||
export function parse(tokens: ReadonlyArray<Token>, text?: undefined, options?: HoganOptions): Tree;
|
|
||||||
}
|
|
||||||
|
|
@ -361,6 +361,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/highlight.js/-/highlight.js-9.12.3.tgz#b672cfaac25cbbc634a0fd92c515f66faa18dbca"
|
resolved "https://registry.yarnpkg.com/@types/highlight.js/-/highlight.js-9.12.3.tgz#b672cfaac25cbbc634a0fd92c515f66faa18dbca"
|
||||||
integrity sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ==
|
integrity sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ==
|
||||||
|
|
||||||
|
"@types/hogan.js@^3.0.0":
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/hogan.js/-/hogan.js-3.0.0.tgz#bf26560f39a38224ab6d0491b06f72c8fbe0953d"
|
||||||
|
integrity sha512-djkvb/AN43c3lIGCojNQ1FBS9VqqKhcTns5RQnHw4xBT/csy0jAssAsOiJ8NfaaioZaeKYE7XkVRxE5NeSZcaA==
|
||||||
|
|
||||||
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
|
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
|
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue