Skip to content

Commit 076e144

Browse files
committed
clean: Remove as type casts and use runtime typechecks with fallback when possible
1 parent fe8365b commit 076e144

3 files changed

Lines changed: 74 additions & 35 deletions

File tree

src/ui/js/diff2html-ui-base.ts

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,13 @@ export class Diff2HtmlUI {
5252

5353
synchronisedScroll(): void {
5454
this.targetElement.querySelectorAll('.d2h-file-wrapper').forEach(wrapper => {
55-
const [left, right] = [].slice.call(wrapper.querySelectorAll('.d2h-file-side-diff')) as HTMLElement[];
55+
const [left, right] = Array<Element>().slice.call(wrapper.querySelectorAll('.d2h-file-side-diff'));
56+
5657
if (left === undefined || right === undefined) return;
58+
5759
const onScroll = (event: Event): void => {
5860
if (event === null || event.target === null) return;
61+
5962
if (event.target === left) {
6063
right.scrollTop = left.scrollTop;
6164
right.scrollLeft = left.scrollLeft;
@@ -70,29 +73,28 @@ export class Diff2HtmlUI {
7073
}
7174

7275
fileListToggle(startVisible: boolean): void {
73-
const hashTag = this.getHashTag();
74-
75-
const showBtn = this.targetElement.querySelector('.d2h-show') as HTMLElement;
76-
const hideBtn = this.targetElement.querySelector('.d2h-hide') as HTMLElement;
77-
const fileList = this.targetElement.querySelector('.d2h-file-list') as HTMLElement;
76+
const showBtn: HTMLElement | null = this.targetElement.querySelector('d2h-show');
77+
const hideBtn: HTMLElement | null = this.targetElement.querySelector('.d2h-hide');
78+
const fileList: HTMLElement | null = this.targetElement.querySelector('.d2h-file-list');
7879

7980
if (showBtn === null || hideBtn === null || fileList === null) return;
8081

81-
function show(): void {
82+
const show: () => void = () => {
8283
showBtn.style.display = 'none';
8384
hideBtn.style.display = 'inline';
8485
fileList.style.display = 'block';
85-
}
86+
};
8687

87-
function hide(): void {
88+
const hide: () => void = () => {
8889
showBtn.style.display = 'inline';
8990
hideBtn.style.display = 'none';
9091
fileList.style.display = 'none';
91-
}
92+
};
9293

9394
showBtn.addEventListener('click', () => show());
9495
hideBtn.addEventListener('click', () => hide());
9596

97+
const hashTag = this.getHashTag();
9698
if (hashTag === 'files-summary-show') show();
9799
else if (hashTag === 'files-summary-hide') hide();
98100
else if (startVisible) show();
@@ -117,11 +119,11 @@ export class Diff2HtmlUI {
117119
if (this.hljs === null) return;
118120

119121
const text = line.textContent;
120-
const lineParent = line.parentNode as HTMLElement;
122+
const lineParent = line.parentNode;
121123

122-
if (lineParent === null || text === null) return;
124+
if (text === null || lineParent === null || !this.isElement(lineParent)) return;
123125

124-
const lineState = lineParent.className.indexOf('d2h-del') !== -1 ? oldLinesState : newLinesState;
126+
const lineState = lineParent.classList.contains('d2h-del') ? oldLinesState : newLinesState;
125127

126128
const language = file.getAttribute('data-lang');
127129
const result =
@@ -130,9 +132,9 @@ export class Diff2HtmlUI {
130132
: this.hljs.highlightAuto(text);
131133

132134
if (this.instanceOfIHighlightResult(result)) {
133-
if (lineParent.className.indexOf('d2h-del') !== -1) {
135+
if (lineParent.classList.contains('d2h-del')) {
134136
oldLinesState = result.top;
135-
} else if (lineParent.className.indexOf('d2h-ins') !== -1) {
137+
} else if (lineParent.classList.contains('d2h-ins')) {
136138
newLinesState = result.top;
137139
} else {
138140
oldLinesState = result.top;
@@ -159,18 +161,15 @@ export class Diff2HtmlUI {
159161
const diffTable = body.getElementsByClassName('d2h-diff-table')[0];
160162

161163
diffTable.addEventListener('mousedown', event => {
162-
if (event === null || event.target === null) return;
163-
164-
const mouseEvent = event as MouseEvent;
165-
const target = mouseEvent.target as HTMLElement;
166-
const table = target.closest('.d2h-diff-table');
164+
if (event === null || !this.isElement(event.target)) return;
167165

166+
const table = event.target.closest('.d2h-diff-table');
168167
if (table !== null) {
169-
if (target.closest('.d2h-code-line,.d2h-code-side-line') !== null) {
168+
if (event.target.closest('.d2h-code-line,.d2h-code-side-line') !== null) {
170169
table.classList.remove('selecting-left');
171170
table.classList.add('selecting-right');
172171
this.currentSelectionColumnId = 1;
173-
} else if (target.closest('.d2h-code-linenumber,.d2h-code-side-linenumber') !== null) {
172+
} else if (event.target.closest('.d2h-code-linenumber,.d2h-code-side-linenumber') !== null) {
174173
table.classList.remove('selecting-right');
175174
table.classList.add('selecting-left');
176175
this.currentSelectionColumnId = 0;
@@ -179,8 +178,9 @@ export class Diff2HtmlUI {
179178
});
180179

181180
diffTable.addEventListener('copy', event => {
182-
const clipboardEvent = event as ClipboardEvent;
183-
const clipboardData = clipboardEvent.clipboardData;
181+
if (!this.isClipboardEvent(event)) return;
182+
183+
const clipboardData = event.clipboardData;
184184
const text = this.getSelectedText();
185185

186186
if (clipboardData === null || text === undefined) return;
@@ -231,4 +231,12 @@ export class Diff2HtmlUI {
231231

232232
return text;
233233
}
234+
235+
private isElement(arg?: unknown): arg is Element {
236+
return arg !== null && (arg as Element)?.classList !== undefined;
237+
}
238+
239+
private isClipboardEvent(arg?: unknown): arg is ClipboardEvent {
240+
return arg !== null && (arg as ClipboardEvent)?.clipboardData !== undefined;
241+
}
234242
}

src/ui/js/highlight.js-helpers.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ export function mergeStreams(original: NodeEvent[], highlighted: NodeEvent[], va
6363
let result = '';
6464
const nodeStack = [];
6565

66+
function isElement(arg?: unknown): arg is Element {
67+
return arg !== null && (arg as Element)?.attributes !== undefined;
68+
}
69+
6670
function selectStream(): NodeEvent[] {
6771
if (!original.length || !highlighted.length) {
6872
return original.length ? original : highlighted;
@@ -88,9 +92,12 @@ export function mergeStreams(original: NodeEvent[], highlighted: NodeEvent[], va
8892
}
8993

9094
function open(node: Node): void {
91-
const htmlNode = node as HTMLElement;
92-
result += `<${tag(node)} ${[].map
93-
.call(htmlNode.attributes, (attr: Attr) => `${attr.nodeName}="${escape(attr.value)}"`)
95+
if (!isElement(node)) {
96+
throw new Error('Node is not an Element');
97+
}
98+
99+
result += `<${tag(node)} ${Array<Attr>()
100+
.map.call(node.attributes, attr => `${attr.nodeName}="${escape(attr.value)}"`)
94101
.join(' ')}>`;
95102
}
96103

website/templates/pages/demo/demo.ts

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,30 @@ type Elements = {
208208
};
209209
};
210210

211+
function isHTMLInputElement(arg?: unknown): arg is HTMLInputElement {
212+
return arg !== null && (arg as HTMLInputElement)?.value !== undefined;
213+
}
214+
215+
function getHTMLInputElementById(id: string): HTMLInputElement {
216+
const element = document.getElementById(id);
217+
218+
if (!isHTMLInputElement(element)) {
219+
throw new Error(`Could not find html input element with id '${id}'`);
220+
}
221+
222+
return element;
223+
}
224+
225+
function getHTMLElementById(id: string): HTMLElement {
226+
const element = document.getElementById(id);
227+
228+
if (element === null) {
229+
throw new Error(`Could not find html element with id '${id}'`);
230+
}
231+
232+
return element;
233+
}
234+
211235
document.addEventListener('DOMContentLoaded', async () => {
212236
// Improves browser compatibility
213237
require('whatwg-fetch');
@@ -226,20 +250,20 @@ document.addEventListener('DOMContentLoaded', async () => {
226250

227251
const elements: Elements = {
228252
structure: {
229-
diffTarget: document.getElementById('url-diff-container') as HTMLElement,
253+
diffTarget: getHTMLElementById('url-diff-container'),
230254
},
231255
url: {
232-
input: document.getElementById('url') as HTMLInputElement,
233-
button: document.getElementById('url-btn') as HTMLElement,
256+
input: getHTMLInputElementById('url'),
257+
button: getHTMLElementById('url-btn'),
234258
},
235259
options: {
236-
outputFormat: document.getElementById('diff-url-options-output-format') as HTMLInputElement,
237-
matching: document.getElementById('diff-url-options-matching') as HTMLInputElement,
238-
wordsThreshold: document.getElementById('diff-url-options-match-words-threshold') as HTMLInputElement,
239-
matchingMaxComparisons: document.getElementById('diff-url-options-matching-max-comparisons') as HTMLInputElement,
260+
outputFormat: getHTMLInputElementById('diff-url-options-output-format'),
261+
matching: getHTMLInputElementById('diff-url-options-matching'),
262+
wordsThreshold: getHTMLInputElementById('diff-url-options-match-words-threshold'),
263+
matchingMaxComparisons: getHTMLInputElementById('diff-url-options-matching-max-comparisons'),
240264
},
241265
checkboxes: {
242-
drawFileList: document.getElementById('diff-url-options-show-files') as HTMLInputElement,
266+
drawFileList: getHTMLInputElementById('diff-url-options-show-files'),
243267
},
244268
};
245269

0 commit comments

Comments
 (0)