2019-11-24 22:44:26 +00:00
|
|
|
import { Diff2HtmlUI, defaultDiff2HtmlUIConfig, Diff2HtmlUIConfig } from "../../../../src/ui/js/diff2html-ui";
|
|
|
|
|
|
|
|
|
|
import "../../../main.ts";
|
|
|
|
|
import "../../../main.css";
|
|
|
|
|
import "./demo.css";
|
|
|
|
|
import "../../../../src/ui/css/diff2html.css";
|
2016-10-12 22:55:31 +00:00
|
|
|
|
2016-10-12 21:52:59 +00:00
|
|
|
/*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
|
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
type URLParams = {
|
|
|
|
|
diff?: string;
|
|
|
|
|
[key: string]: string | boolean | number | undefined;
|
|
|
|
|
};
|
|
|
|
|
|
2019-10-12 21:45:49 +00:00
|
|
|
const searchParam = "diff";
|
|
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
function getParamsFromSearch(search: string): URLParams {
|
2019-10-12 21:45:49 +00:00
|
|
|
try {
|
2019-11-24 22:44:26 +00:00
|
|
|
return search
|
2019-10-12 21:45:49 +00:00
|
|
|
.split("?")[1]
|
|
|
|
|
.split("&")
|
2019-11-24 22:44:26 +00:00
|
|
|
.reduce((urlParams, e) => {
|
2019-10-12 21:45:49 +00:00
|
|
|
const values = e.split("=");
|
2019-11-24 22:44:26 +00:00
|
|
|
return {
|
|
|
|
|
...urlParams,
|
|
|
|
|
[values[0]]: values[1]
|
|
|
|
|
};
|
|
|
|
|
}, {});
|
|
|
|
|
} catch (_ignore) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
2019-10-12 21:45:49 +00:00
|
|
|
}
|
2016-10-16 16:40:36 +00:00
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
function validateUrl(url: string): boolean {
|
2019-10-13 18:21:19 +00:00
|
|
|
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
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
type Request = {
|
|
|
|
|
url: string;
|
|
|
|
|
headers: Headers;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function prepareRequest(url: string): Request {
|
2019-10-13 18:21:19 +00:00
|
|
|
if (!validateUrl(url)) {
|
2019-11-24 22:44:26 +00:00
|
|
|
const errorMsg = "Invalid url provided!";
|
|
|
|
|
console.error(errorMsg);
|
|
|
|
|
throw new Error(errorMsg);
|
2019-10-13 18:21:19 +00:00
|
|
|
}
|
|
|
|
|
|
2019-10-12 21:45:49 +00:00
|
|
|
let fetchUrl;
|
|
|
|
|
const headers = new Headers();
|
2016-10-12 21:52:59 +00:00
|
|
|
|
2019-10-12 21:45:49 +00:00
|
|
|
const githubCommitUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
|
|
|
|
|
const githubPrUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/pull\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
|
2016-10-12 21:52:59 +00:00
|
|
|
|
2019-10-12 21:45:49 +00:00
|
|
|
const gitlabCommitUrl = /^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
|
|
|
|
|
const gitlabPrUrl = /^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/merge_requests\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
|
2016-10-12 21:52:59 +00:00
|
|
|
|
2019-10-12 21:45:49 +00:00
|
|
|
const bitbucketCommitUrl = /^https?:\/\/(?:www\.)?bitbucket\.org\/(.*?)\/(.*?)\/commits\/(.*?)(?:\/raw)?(?:\/.*)?$/;
|
|
|
|
|
const bitbucketPrUrl = /^https?:\/\/(?:www\.)?bitbucket\.org\/(.*?)\/(.*?)\/pull-requests\/(.*?)(?:\/.*)?$/;
|
2016-10-16 16:40:36 +00:00
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
function gitLabUrlGen(userName: string, projectName: string, type: string, value: string): string {
|
2019-10-12 21:45:49 +00:00
|
|
|
return (
|
|
|
|
|
"https://crossorigin.me/https://gitlab.com/" + userName + "/" + projectName + "/" + type + "/" + value + ".diff"
|
|
|
|
|
);
|
2017-10-16 21:00:03 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
function gitHubUrlGen(userName: string, projectName: string, type: string, value: string): string {
|
2019-10-12 21:45:49 +00:00
|
|
|
headers.append("Accept", "application/vnd.github.v3.diff");
|
|
|
|
|
return "https://api.github.com/repos/" + userName + "/" + projectName + "/" + type + "/" + value;
|
2016-10-12 21:52:59 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
function bitbucketUrlGen(userName: string, projectName: string, type: string, value: string): string {
|
2019-10-12 21:45:49 +00:00
|
|
|
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;
|
|
|
|
|
}
|
2016-10-15 11:13:09 +00:00
|
|
|
|
2019-10-12 21:45:49 +00:00
|
|
|
let 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;
|
|
|
|
|
}
|
2016-10-12 21:52:59 +00:00
|
|
|
|
2019-10-12 21:45:49 +00:00
|
|
|
return {
|
|
|
|
|
url: fetchUrl,
|
|
|
|
|
headers: headers
|
|
|
|
|
};
|
|
|
|
|
}
|
2016-10-12 21:52:59 +00:00
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
function getConfiguration(urlParams: URLParams): Diff2HtmlUIConfig {
|
2019-10-13 18:21:19 +00:00
|
|
|
// Removing `diff` form `urlParams` to avoid being inserted
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
|
|
|
const { diff, ...urlParamsRest } = urlParams;
|
2019-11-24 22:44:26 +00:00
|
|
|
const config: URLParams = {
|
|
|
|
|
...defaultDiff2HtmlUIConfig,
|
2019-10-13 18:21:19 +00:00
|
|
|
...urlParamsRest
|
|
|
|
|
};
|
2016-10-12 21:52:59 +00:00
|
|
|
|
2019-10-13 18:21:19 +00:00
|
|
|
return Object.entries(config).reduce((object, [k, v]) => {
|
|
|
|
|
const newObject = !Number.isNaN(Number(v))
|
|
|
|
|
? { [k]: Number(v) }
|
2019-11-24 22:44:26 +00:00
|
|
|
: v === "true" || v === "false"
|
2019-10-13 18:21:19 +00:00
|
|
|
? { [k]: Boolean(v) }
|
|
|
|
|
: { [k]: v };
|
|
|
|
|
return { ...object, ...newObject };
|
|
|
|
|
}, {});
|
2019-10-12 21:45:49 +00:00
|
|
|
}
|
2016-10-12 21:52:59 +00:00
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
async function getDiff(request: Request): Promise<string> {
|
|
|
|
|
try {
|
|
|
|
|
const result = await fetch(request.url, {
|
|
|
|
|
method: "GET",
|
|
|
|
|
headers: request.headers,
|
|
|
|
|
mode: "cors",
|
|
|
|
|
cache: "default"
|
|
|
|
|
});
|
|
|
|
|
return result.text();
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Failed to retrieve diff", error);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
2019-10-12 21:45:49 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
function draw(diffString: string, config: Diff2HtmlUIConfig, elements: Elements): void {
|
|
|
|
|
const diff2htmlUi = new Diff2HtmlUI(diffString, elements.structure.diffTarget, config);
|
2019-10-13 18:21:19 +00:00
|
|
|
|
|
|
|
|
if (config.outputFormat === "side-by-side") {
|
|
|
|
|
elements.structure.container.style.width = "100%";
|
|
|
|
|
} else {
|
|
|
|
|
elements.structure.container.style.width = "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diff2htmlUi.draw();
|
2019-10-12 21:45:49 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
async function prepareInitialState(elements: Elements): Promise<[Diff2HtmlUIConfig, string]> {
|
2019-10-13 18:21:19 +00:00
|
|
|
const urlParams = getParamsFromSearch(window.location.search);
|
|
|
|
|
const currentUrl = (urlParams && urlParams[searchParam]) || "https://github.com/rtfpessoa/diff2html/pull/106";
|
2019-10-12 21:45:49 +00:00
|
|
|
|
2019-10-13 18:21:19 +00:00
|
|
|
if (currentUrl !== elements.url.input.value) elements.url.input.value = currentUrl;
|
|
|
|
|
|
|
|
|
|
const request = prepareRequest(currentUrl);
|
|
|
|
|
|
|
|
|
|
const initialConfiguration = getConfiguration(urlParams);
|
|
|
|
|
const initialDiff = await getDiff(request);
|
|
|
|
|
|
|
|
|
|
return [initialConfiguration, initialDiff];
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
function updateBrowserUrl(config: Diff2HtmlUIConfig, newDiffUrl: string): void {
|
2019-10-13 18:21:19 +00:00
|
|
|
if (history.pushState) {
|
|
|
|
|
const paramString = Object.entries(config)
|
|
|
|
|
.map(([k, v]) => k + "=" + v)
|
|
|
|
|
.join("&");
|
|
|
|
|
const newPageUrl =
|
|
|
|
|
window.location.protocol +
|
|
|
|
|
"//" +
|
|
|
|
|
window.location.host +
|
|
|
|
|
window.location.pathname +
|
|
|
|
|
"?" +
|
|
|
|
|
paramString +
|
|
|
|
|
"&" +
|
|
|
|
|
searchParam +
|
|
|
|
|
"=" +
|
|
|
|
|
newDiffUrl;
|
|
|
|
|
window.history.pushState({ path: newPageUrl }, "", newPageUrl);
|
|
|
|
|
}
|
2019-10-12 21:45:49 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
type Elements = {
|
|
|
|
|
structure: {
|
|
|
|
|
container: HTMLElement;
|
|
|
|
|
diffTarget: HTMLElement;
|
|
|
|
|
};
|
|
|
|
|
url: {
|
|
|
|
|
input: HTMLInputElement;
|
|
|
|
|
button: HTMLElement;
|
|
|
|
|
};
|
|
|
|
|
options: {
|
|
|
|
|
outputFormat: HTMLInputElement;
|
|
|
|
|
matching: HTMLInputElement;
|
|
|
|
|
wordsThreshold: HTMLInputElement;
|
|
|
|
|
matchingMaxComparisons: HTMLInputElement;
|
|
|
|
|
};
|
|
|
|
|
checkboxes: {
|
|
|
|
|
drawFileList: HTMLInputElement;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2019-10-13 18:21:19 +00:00
|
|
|
document.addEventListener("DOMContentLoaded", async () => {
|
2019-10-12 21:45:49 +00:00
|
|
|
// Improves browser compatibility
|
|
|
|
|
require("whatwg-fetch");
|
2017-10-16 21:00:03 +00:00
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
const drawAndUpdateUrl = async (
|
|
|
|
|
diffUrl: string,
|
|
|
|
|
diffString: string,
|
|
|
|
|
config: Diff2HtmlUIConfig,
|
|
|
|
|
elements: Elements
|
|
|
|
|
): Promise<void> => {
|
2019-10-13 18:21:19 +00:00
|
|
|
updateBrowserUrl(config, diffUrl);
|
|
|
|
|
const newRequest = prepareRequest(diffUrl);
|
|
|
|
|
diffString = await getDiff(newRequest);
|
|
|
|
|
draw(diffString, config, elements);
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-24 22:44:26 +00:00
|
|
|
const elements: Elements = {
|
2019-10-13 18:21:19 +00:00
|
|
|
structure: {
|
2019-11-24 22:44:26 +00:00
|
|
|
container: document.getElementsByClassName("container")[0] as HTMLElement,
|
|
|
|
|
diffTarget: document.getElementById("url-diff-container") as HTMLElement
|
2019-10-13 18:21:19 +00:00
|
|
|
},
|
|
|
|
|
url: {
|
2019-11-24 22:44:26 +00:00
|
|
|
input: document.getElementById("url") as HTMLInputElement,
|
|
|
|
|
button: document.getElementById("url-btn") as HTMLElement
|
2019-10-13 18:21:19 +00:00
|
|
|
},
|
|
|
|
|
options: {
|
2019-11-24 22:44:26 +00:00
|
|
|
outputFormat: document.getElementById("diff-url-options-output-format") as HTMLInputElement,
|
|
|
|
|
matching: document.getElementById("diff-url-options-matching") as HTMLInputElement,
|
|
|
|
|
wordsThreshold: document.getElementById("diff-url-options-match-words-threshold") as HTMLInputElement,
|
|
|
|
|
matchingMaxComparisons: document.getElementById("diff-url-options-matching-max-comparisons") as HTMLInputElement
|
2019-10-13 18:21:19 +00:00
|
|
|
},
|
|
|
|
|
checkboxes: {
|
2019-11-24 22:44:26 +00:00
|
|
|
drawFileList: document.getElementById("diff-url-options-show-files") as HTMLInputElement
|
2019-10-13 18:21:19 +00:00
|
|
|
}
|
2019-10-12 21:45:49 +00:00
|
|
|
};
|
2017-10-16 21:00:03 +00:00
|
|
|
|
2019-10-13 18:21:19 +00:00
|
|
|
let [config, diffString] = await prepareInitialState(elements);
|
2016-10-16 16:40:36 +00:00
|
|
|
|
2019-10-13 18:21:19 +00:00
|
|
|
// Update HTML inputs from any changes in URL
|
2019-11-24 22:44:26 +00:00
|
|
|
config.outputFormat && (elements.options.outputFormat.value = config.outputFormat);
|
|
|
|
|
config.drawFileList && (elements.checkboxes.drawFileList.checked = config.drawFileList);
|
|
|
|
|
config.matching && (elements.options.matching.value = config.matching);
|
|
|
|
|
config.matchWordsThreshold && (elements.options.wordsThreshold.value = config.matchWordsThreshold.toString());
|
|
|
|
|
config.matchingMaxComparisons &&
|
|
|
|
|
(elements.options.matchingMaxComparisons.value = config.matchingMaxComparisons.toString());
|
2019-10-13 18:21:19 +00:00
|
|
|
|
|
|
|
|
Object.entries(elements.options).forEach(([option, element]) =>
|
|
|
|
|
element.addEventListener("change", () => {
|
2019-11-24 22:44:26 +00:00
|
|
|
config = { ...config, [option]: element.value };
|
2019-10-13 18:21:19 +00:00
|
|
|
drawAndUpdateUrl(elements.url.input.value, diffString, config, elements);
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Object.entries(elements.checkboxes).forEach(([option, checkbox]) =>
|
|
|
|
|
checkbox.addEventListener("change", () => {
|
2019-11-24 22:44:26 +00:00
|
|
|
config = { ...config, [option]: checkbox.checked };
|
2019-10-13 18:21:19 +00:00
|
|
|
drawAndUpdateUrl(elements.url.input.value, diffString, config, elements);
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
elements.url.button.addEventListener("click", async e => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
const newDiffUrl = elements.url.input.value;
|
|
|
|
|
const newRequest = prepareRequest(newDiffUrl);
|
|
|
|
|
diffString = await getDiff(newRequest);
|
|
|
|
|
drawAndUpdateUrl(newDiffUrl, diffString, config, elements);
|
|
|
|
|
});
|
2016-10-16 16:40:36 +00:00
|
|
|
|
2019-10-13 18:21:19 +00:00
|
|
|
return drawAndUpdateUrl(elements.url.input.value, diffString, config, elements);
|
2016-10-12 21:52:59 +00:00
|
|
|
});
|