clean: Remove as type casts and use runtime typechecks with fallback when possible

This commit is contained in:
Rodrigo Fernandes 2020-01-25 23:49:53 +00:00
parent fe8365bcc1
commit 076e14400b
No known key found for this signature in database
GPG key ID: 67157D2E3D4258B4
3 changed files with 74 additions and 35 deletions

View file

@ -52,10 +52,13 @@ export class Diff2HtmlUI {
synchronisedScroll(): void {
this.targetElement.querySelectorAll('.d2h-file-wrapper').forEach(wrapper => {
const [left, right] = [].slice.call(wrapper.querySelectorAll('.d2h-file-side-diff')) as HTMLElement[];
const [left, right] = Array<Element>().slice.call(wrapper.querySelectorAll('.d2h-file-side-diff'));
if (left === undefined || right === undefined) return;
const onScroll = (event: Event): void => {
if (event === null || event.target === null) return;
if (event.target === left) {
right.scrollTop = left.scrollTop;
right.scrollLeft = left.scrollLeft;
@ -70,29 +73,28 @@ export class Diff2HtmlUI {
}
fileListToggle(startVisible: boolean): void {
const hashTag = this.getHashTag();
const showBtn = this.targetElement.querySelector('.d2h-show') as HTMLElement;
const hideBtn = this.targetElement.querySelector('.d2h-hide') as HTMLElement;
const fileList = this.targetElement.querySelector('.d2h-file-list') as HTMLElement;
const showBtn: HTMLElement | null = this.targetElement.querySelector('d2h-show');
const hideBtn: HTMLElement | null = this.targetElement.querySelector('.d2h-hide');
const fileList: HTMLElement | null = this.targetElement.querySelector('.d2h-file-list');
if (showBtn === null || hideBtn === null || fileList === null) return;
function show(): void {
const show: () => void = () => {
showBtn.style.display = 'none';
hideBtn.style.display = 'inline';
fileList.style.display = 'block';
}
};
function hide(): void {
const hide: () => void = () => {
showBtn.style.display = 'inline';
hideBtn.style.display = 'none';
fileList.style.display = 'none';
}
};
showBtn.addEventListener('click', () => show());
hideBtn.addEventListener('click', () => hide());
const hashTag = this.getHashTag();
if (hashTag === 'files-summary-show') show();
else if (hashTag === 'files-summary-hide') hide();
else if (startVisible) show();
@ -117,11 +119,11 @@ export class Diff2HtmlUI {
if (this.hljs === null) return;
const text = line.textContent;
const lineParent = line.parentNode as HTMLElement;
const lineParent = line.parentNode;
if (lineParent === null || text === null) return;
if (text === null || lineParent === null || !this.isElement(lineParent)) return;
const lineState = lineParent.className.indexOf('d2h-del') !== -1 ? oldLinesState : newLinesState;
const lineState = lineParent.classList.contains('d2h-del') ? oldLinesState : newLinesState;
const language = file.getAttribute('data-lang');
const result =
@ -130,9 +132,9 @@ export class Diff2HtmlUI {
: this.hljs.highlightAuto(text);
if (this.instanceOfIHighlightResult(result)) {
if (lineParent.className.indexOf('d2h-del') !== -1) {
if (lineParent.classList.contains('d2h-del')) {
oldLinesState = result.top;
} else if (lineParent.className.indexOf('d2h-ins') !== -1) {
} else if (lineParent.classList.contains('d2h-ins')) {
newLinesState = result.top;
} else {
oldLinesState = result.top;
@ -159,18 +161,15 @@ export class Diff2HtmlUI {
const diffTable = body.getElementsByClassName('d2h-diff-table')[0];
diffTable.addEventListener('mousedown', event => {
if (event === null || event.target === null) return;
const mouseEvent = event as MouseEvent;
const target = mouseEvent.target as HTMLElement;
const table = target.closest('.d2h-diff-table');
if (event === null || !this.isElement(event.target)) return;
const table = event.target.closest('.d2h-diff-table');
if (table !== null) {
if (target.closest('.d2h-code-line,.d2h-code-side-line') !== null) {
if (event.target.closest('.d2h-code-line,.d2h-code-side-line') !== null) {
table.classList.remove('selecting-left');
table.classList.add('selecting-right');
this.currentSelectionColumnId = 1;
} else if (target.closest('.d2h-code-linenumber,.d2h-code-side-linenumber') !== null) {
} else if (event.target.closest('.d2h-code-linenumber,.d2h-code-side-linenumber') !== null) {
table.classList.remove('selecting-right');
table.classList.add('selecting-left');
this.currentSelectionColumnId = 0;
@ -179,8 +178,9 @@ export class Diff2HtmlUI {
});
diffTable.addEventListener('copy', event => {
const clipboardEvent = event as ClipboardEvent;
const clipboardData = clipboardEvent.clipboardData;
if (!this.isClipboardEvent(event)) return;
const clipboardData = event.clipboardData;
const text = this.getSelectedText();
if (clipboardData === null || text === undefined) return;
@ -231,4 +231,12 @@ export class Diff2HtmlUI {
return text;
}
private isElement(arg?: unknown): arg is Element {
return arg !== null && (arg as Element)?.classList !== undefined;
}
private isClipboardEvent(arg?: unknown): arg is ClipboardEvent {
return arg !== null && (arg as ClipboardEvent)?.clipboardData !== undefined;
}
}

View file

@ -63,6 +63,10 @@ export function mergeStreams(original: NodeEvent[], highlighted: NodeEvent[], va
let result = '';
const nodeStack = [];
function isElement(arg?: unknown): arg is Element {
return arg !== null && (arg as Element)?.attributes !== undefined;
}
function selectStream(): NodeEvent[] {
if (!original.length || !highlighted.length) {
return original.length ? original : highlighted;
@ -88,9 +92,12 @@ export function mergeStreams(original: NodeEvent[], highlighted: NodeEvent[], va
}
function open(node: Node): void {
const htmlNode = node as HTMLElement;
result += `<${tag(node)} ${[].map
.call(htmlNode.attributes, (attr: Attr) => `${attr.nodeName}="${escape(attr.value)}"`)
if (!isElement(node)) {
throw new Error('Node is not an Element');
}
result += `<${tag(node)} ${Array<Attr>()
.map.call(node.attributes, attr => `${attr.nodeName}="${escape(attr.value)}"`)
.join(' ')}>`;
}

View file

@ -208,6 +208,30 @@ type Elements = {
};
};
function isHTMLInputElement(arg?: unknown): arg is HTMLInputElement {
return arg !== null && (arg as HTMLInputElement)?.value !== undefined;
}
function getHTMLInputElementById(id: string): HTMLInputElement {
const element = document.getElementById(id);
if (!isHTMLInputElement(element)) {
throw new Error(`Could not find html input element with id '${id}'`);
}
return element;
}
function getHTMLElementById(id: string): HTMLElement {
const element = document.getElementById(id);
if (element === null) {
throw new Error(`Could not find html element with id '${id}'`);
}
return element;
}
document.addEventListener('DOMContentLoaded', async () => {
// Improves browser compatibility
require('whatwg-fetch');
@ -226,20 +250,20 @@ document.addEventListener('DOMContentLoaded', async () => {
const elements: Elements = {
structure: {
diffTarget: document.getElementById('url-diff-container') as HTMLElement,
diffTarget: getHTMLElementById('url-diff-container'),
},
url: {
input: document.getElementById('url') as HTMLInputElement,
button: document.getElementById('url-btn') as HTMLElement,
input: getHTMLInputElementById('url'),
button: getHTMLElementById('url-btn'),
},
options: {
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,
outputFormat: getHTMLInputElementById('diff-url-options-output-format'),
matching: getHTMLInputElementById('diff-url-options-matching'),
wordsThreshold: getHTMLInputElementById('diff-url-options-match-words-threshold'),
matchingMaxComparisons: getHTMLInputElementById('diff-url-options-matching-max-comparisons'),
},
checkboxes: {
drawFileList: document.getElementById('diff-url-options-show-files') as HTMLInputElement,
drawFileList: getHTMLInputElementById('diff-url-options-show-files'),
},
};