Skip to content

Commit

Permalink
Merge pull request #15700 from brollin/implement-isolated-declarations
Browse files Browse the repository at this point in the history
ui/common: enable isolatedDeclarations
  • Loading branch information
ornicar committed Jul 12, 2024
2 parents b5d43b6 + baa32fa commit d608f0c
Show file tree
Hide file tree
Showing 26 changed files with 77 additions and 72 deletions.
6 changes: 3 additions & 3 deletions ui/common/src/clock.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
export const formatMs = (msTime: number) => {
export const formatMs = (msTime: number): string => {
const date = new Date(Math.max(0, msTime + 500)),
hours = date.getUTCHours(),
minutes = date.getUTCMinutes(),
seconds = date.getUTCSeconds();
return hours > 0 ? hours + ':' + pad(minutes) + ':' + pad(seconds) : minutes + ':' + pad(seconds);
};

export const otbClockIsRunning = (fen: string) => !fen.includes('PPPPPPPP/RNBQKBNR');
export const otbClockIsRunning = (fen: string): boolean => !fen.includes('PPPPPPPP/RNBQKBNR');

export const lichessClockIsRunning = (fen: string, color: Color) =>
export const lichessClockIsRunning = (fen: string, color: Color): boolean =>
color == 'white' ? !fen.includes('PPPPPPPP/RNBQKBNR') : !fen.startsWith('rnbqkbnr/pppppppp');

const pad = (x: number) => (x < 10 ? '0' : '') + x;
44 changes: 23 additions & 21 deletions ui/common/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,30 +74,32 @@ export const memoize = <A>(compute: () => A): (() => A) => {
};
};

export const scrollToInnerSelector = (el: HTMLElement, selector: string, horiz: boolean = false) =>
export const scrollToInnerSelector = (el: HTMLElement, selector: string, horiz: boolean = false): void =>
scrollTo(el, el.querySelector(selector), horiz);

export const scrollTo = (el: HTMLElement, target: HTMLElement | null, horiz: boolean = false) => {
export const scrollTo = (el: HTMLElement, target: HTMLElement | null, horiz: boolean = false): void => {
if (target)
horiz
? (el.scrollLeft = target.offsetLeft - el.offsetWidth / 2 + target.offsetWidth / 2)
: (el.scrollTop = target.offsetTop - el.offsetHeight / 2 + target.offsetHeight / 2);
};

export const onClickAway = (f: () => void) => (el: HTMLElement) => {
const listen: () => void = () =>
$(document).one('click', e => {
if (!document.contains(el)) {
return;
}
if (el.contains(e.target)) {
listen();
} else {
f();
}
});
setTimeout(listen, 300);
};
export const onClickAway =
(f: () => void) =>
(el: HTMLElement): void => {
const listen: () => void = () =>
$(document).one('click', e => {
if (!document.contains(el)) {
return;
}
if (el.contains(e.target)) {
listen();
} else {
f();
}
});
setTimeout(listen, 300);
};

export type SparseSet<T> = Set<T> | T;
export type SparseMap<V> = Map<string, SparseSet<V>>;
Expand All @@ -114,13 +116,13 @@ export function getSpread<T>(m: SparseMap<T>, key: string): T[] {
return spread(m.get(key));
}

export function remove<T>(m: SparseMap<T>, key: string, val: T) {
export function remove<T>(m: SparseMap<T>, key: string, val: T): void {
const v = m.get(key);
if (v === val) m.delete(key);
else if (v instanceof Set) v.delete(val);
}

export function pushMap<T>(m: SparseMap<T>, key: string, val: T) {
export function pushMap<T>(m: SparseMap<T>, key: string, val: T): void {
const v = m.get(key);
if (!v) m.set(key, val);
else {
Expand All @@ -129,16 +131,16 @@ export function pushMap<T>(m: SparseMap<T>, key: string, val: T) {
}
}

export function hyphenToCamel(str: string) {
export function hyphenToCamel(str: string): string {
return str.replace(/-([a-z])/g, g => g[1].toUpperCase());
}

export const requestIdleCallback = (f: () => void, timeout?: number) => {
export const requestIdleCallback = (f: () => void, timeout?: number): void => {
if (window.requestIdleCallback) window.requestIdleCallback(f, timeout ? { timeout } : undefined);
else requestAnimationFrame(f);
};

export const escapeHtml = (str: string) =>
export const escapeHtml = (str: string): string =>
/[&<>"']/.test(str)
? str
.replace(/&/g, '&amp;')
Expand Down
2 changes: 1 addition & 1 deletion ui/common/src/complete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface Opts<Result> {
regex?: RegExp;
}

export default function <Result>(opts: Opts<Result>) {
export default function <Result>(opts: Opts<Result>): void {
const minLength = opts.minLength || 3,
empty = opts.empty || (() => '<div class="complete-list__empty">No results.</div>'),
cache = new Map<string, Result[]>(),
Expand Down
6 changes: 3 additions & 3 deletions ui/common/src/controls.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { h, Hooks, VNode } from 'snabbdom';
import { bind } from './snabbdom';
import { toggle as baseToggle } from './common';
import { toggle as baseToggle, Toggle } from './common';
import * as xhr from './xhr';

export interface ToggleSettings {
Expand All @@ -13,7 +13,7 @@ export interface ToggleSettings {
change(v: boolean): void;
}

export function toggle(t: ToggleSettings, trans: Trans, redraw: () => void) {
export function toggle(t: ToggleSettings, trans: Trans, redraw: () => void): VNode {
const fullId = 'abset-' + t.id;
return h(
'div.setting.' + fullId + (t.cls ? '.' + t.cls : ''),
Expand Down Expand Up @@ -45,7 +45,7 @@ export function rangeConfig(read: () => number, write: (value: number) => void):
};
}

export const boolPrefXhrToggle = (prefKey: string, val: boolean, effect: () => void = site.reload) =>
export const boolPrefXhrToggle = (prefKey: string, val: boolean, effect: () => void = site.reload): Toggle =>
baseToggle(val, async v => {
await xhr.text(`/pref/${prefKey}`, { method: 'post', body: xhr.form({ [prefKey]: v ? '1' : '0' }) });
effect();
Expand Down
13 changes: 7 additions & 6 deletions ui/common/src/device.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Hooks } from 'snabbdom';
import { memoize } from './common';
import { bind } from './snabbdom';

const longPressDuration = 610;

export function bindMobileTapHold(el: HTMLElement, f: (e: Event) => unknown, redraw?: () => void) {
export function bindMobileTapHold(el: HTMLElement, f: (e: Event) => unknown, redraw?: () => void): void {
let longPressCountdown: number;

el.addEventListener('touchstart', e => {
Expand Down Expand Up @@ -36,7 +37,7 @@ export const bindMobileMousedown =
}
};

export const hookMobileMousedown = (f: (e: Event) => any) =>
export const hookMobileMousedown = (f: (e: Event) => any): Hooks =>
bind('ontouchstart' in window ? 'click' : 'mousedown', f);

export const isMobile = (): boolean => isAndroid() || isIOS();
Expand All @@ -45,7 +46,7 @@ export const isAndroid = (): boolean => /Android/.test(navigator.userAgent);

export const isSafari = (): boolean => /^((?!chrome|android).)*safari/i.test(navigator.userAgent);

export const isIOS = (constraint?: { below?: number; atLeast?: number }) => {
export const isIOS = (constraint?: { below?: number; atLeast?: number }): boolean => {
let answer = ios();
if (!constraint || !answer) return answer;
const version = parseFloat(navigator.userAgent.slice(navigator.userAgent.indexOf('Version/') + 8));
Expand All @@ -65,16 +66,16 @@ export const getFirefoxMajorVersion = (): number | undefined => {

export const isIOSChrome = (): boolean => /CriOS/.test(navigator.userAgent);

export const isTouchDevice = () => !hasMouse();
export const isTouchDevice = (): boolean => !hasMouse();

export const isIPad = (): boolean =>
navigator?.maxTouchPoints > 2 && /iPad|Macintosh/.test(navigator.userAgent);

export type Feature = 'wasm' | 'sharedMem' | 'simd';

export const hasFeature = (feat?: string) => !feat || features().includes(feat as Feature);
export const hasFeature = (feat?: string): boolean => !feat || features().includes(feat as Feature);

export const features = memoize<readonly Feature[]>(() => {
export const features: () => readonly Feature[] = memoize<readonly Feature[]>(() => {
const features: Feature[] = [];
if (
typeof WebAssembly === 'object' &&
Expand Down
2 changes: 1 addition & 1 deletion ui/common/src/dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export type Action =
| { selector: string; event?: string | string[]; listener: ActionListener }
| { selector: string; event?: string | string[]; result: string };

export const ready = site.load.then(async () => {
export const ready: Promise<boolean> = site.load.then(async () => {
window.addEventListener('resize', onResize);
if (window.HTMLDialogElement) return true;
dialogPolyfill = (await import(site.asset.url('npm/dialog-polyfill.esm.js')).catch(() => undefined))
Expand Down
2 changes: 1 addition & 1 deletion ui/common/src/flairPicker.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export default function flairPickerLoader(element: HTMLElement) {
export default function flairPickerLoader(element: HTMLElement): void {
const parent = $(element).parent();
const close = () => element.removeAttribute('open');
const onEmojiSelect = (i?: { id: string; src: string }) => {
Expand Down
2 changes: 1 addition & 1 deletion ui/common/src/linkPopup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { domDialog } from './dialog';

export const makeLinkPopups = (dom: HTMLElement | Cash, trans: Trans, selector = 'a[href^="http"]') => {
export const makeLinkPopups = (dom: HTMLElement | Cash, trans: Trans, selector = 'a[href^="http"]'): void => {
const $el = $(dom);
if (!$el.hasClass('link-popup-ready'))
$el.addClass('link-popup-ready').on('click', selector, function (this: HTMLLinkElement) {
Expand Down
2 changes: 1 addition & 1 deletion ui/common/src/menuHover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type State = {
event?: string;
};

export default function () {
export default function (): void {
if ('ontouchstart' in window) return;

const interval = 200,
Expand Down
8 changes: 4 additions & 4 deletions ui/common/src/miniBoard.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { h } from 'snabbdom';
import { h, VNode } from 'snabbdom';
import * as domData from './data';
import { uciToMove } from 'chessground/util';

Expand All @@ -25,15 +25,15 @@ export const initWith = (node: HTMLElement, fen: string, orientation: Color, lm?
);
};

export const initAll = (parent?: HTMLElement) =>
export const initAll = (parent?: HTMLElement): void =>
Array.from((parent || document).getElementsByClassName('mini-board--init')).forEach((el: HTMLElement) => {
el.classList.remove('mini-board--init');
init(el);
});

export const fenColor = (fen: string) => (fen.includes(' w') ? 'white' : 'black');
export const fenColor = (fen: string): Color => (fen.includes(' w') ? 'white' : 'black');

export const renderClock = (color: Color, time: number) =>
export const renderClock = (color: Color, time: number): VNode =>
h(`span.mini-game__clock.mini-game__clock--${color}`, {
attrs: { 'data-time': time, 'data-managed': 1 },
});
2 changes: 1 addition & 1 deletion ui/common/src/notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function notify(msg: string | (() => string)) {
listenToFocus();
}

export default function (msg: string | (() => string)) {
export default function (msg: string | (() => string)): void {
if (document.hasFocus() || !('Notification' in window)) return;
if (Notification.permission === 'granted') {
// increase chances that the first tab can put a local storage lock
Expand Down
4 changes: 2 additions & 2 deletions ui/common/src/number.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
let numberFormatter: false | Intl.NumberFormat | null = false;

export const numberFormat = (n: number) => {
export const numberFormat = (n: number): string => {
if (numberFormatter === false)
numberFormatter = window.Intl && Intl.NumberFormat ? new Intl.NumberFormat() : null;
if (numberFormatter === null) return '' + n;
Expand All @@ -17,7 +17,7 @@ export const numberSpread = (el: HTMLElement, nbSteps: number, duration: number,
}
};
let timeouts: Timeout[] = [];
return (nb: number, overrideNbSteps?: number) => {
return (nb: number, overrideNbSteps?: number): void => {
if (!el || (!nb && nb !== 0)) return;
if (overrideNbSteps) nbSteps = Math.abs(overrideNbSteps);
timeouts.forEach(clearTimeout);
Expand Down
2 changes: 1 addition & 1 deletion ui/common/src/password.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const addPasswordVisibilityToggleListener = () => {
export const addPasswordVisibilityToggleListener = (): void => {
$('.password-wrapper').each(function (this: HTMLElement) {
const $wrapper = $(this);
const $button = $wrapper.find('.password-reveal');
Expand Down
2 changes: 1 addition & 1 deletion ui/common/src/perfIcons.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as licon from './licon';

const perfIcons = {
const perfIcons: Record<Exclude<Perf, 'fromPosition'>, string> = {
ultraBullet: licon.UltraBullet,
bullet: licon.Bullet,
blitz: licon.FlameBlitz,
Expand Down
2 changes: 1 addition & 1 deletion ui/common/src/random.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const randomToken = () => {
export const randomToken = (): string => {
try {
const data = window.crypto.getRandomValues(new Uint8Array(9));
return btoa(String.fromCharCode(...data)).replace(/[/+]/g, '_');
Expand Down
2 changes: 1 addition & 1 deletion ui/common/src/resize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default function resizeHandle(
pref: Prefs.ShowResizeHandle,
ply: number,
visible?: Visible,
) {
): void {
if (pref === Prefs.ShowResizeHandle.Never) return;

const el = document.createElement('cg-resize');
Expand Down
16 changes: 8 additions & 8 deletions ui/common/src/richText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { VNode, Hooks } from 'snabbdom';
import { escapeHtml } from './common';

// from https://github.com/bryanwoods/autolink-js/blob/master/autolink.js
export const linkRegex =
export const linkRegex: RegExp =
/(^|[\s\n]|<[A-Za-z]*\/?>)((?:(?:https?|ftp):\/\/|lichess\.org)[\-A-Z0-9+\u0026\u2019@#\/%?=()~_|!:,.;]*[\-A-Z0-9+\u0026@#\/%=~()_|])/gi;
export const newLineRegex = /\n/g;
export const userPattern = /(^|[^\w@#/])@([a-z0-9_-]{2,30})/gi;
export const newLineRegex: RegExp = /\n/g;
export const userPattern: RegExp = /(^|[^\w@#/])@([a-z0-9_-]{2,30})/gi;

// looks like it has a @mention or #gameid or a url.tld
export const isMoreThanText = (str: string) => /(\n|(@|#|\.)\w{2,}|(board|game) \d)/i.test(str);
export const isMoreThanText = (str: string): boolean => /(\n|(@|#|\.)\w{2,}|(board|game) \d)/i.test(str);

export function toLink(url: string): string {
if (!url.match(/^[A-Za-z]+:\/\//)) url = 'https://' + url;
Expand All @@ -36,17 +36,17 @@ export const innerHTML = <A>(a: A, toHtml: (a: A) => string): Hooks => ({
},
});

export function linkReplace(href: string, body?: string, cls?: string) {
export function linkReplace(href: string, body?: string, cls?: string): string {
if (href.includes('&quot;')) return href;
return `<a target="_blank" rel="noopener nofollow noreferrer" href="${
href.startsWith('/') || href.includes('://') ? href : '//' + href
}"${cls ? ` class="${cls}"` : ''}>${body ? body : href}</a>`;
}

export const userLinkReplace = (_: string, prefix: string, user: string) =>
export const userLinkReplace = (_: string, prefix: string, user: string): string =>
prefix + linkReplace('/@/' + user, '@' + user);

export const expandMentions = (html: string) => html.replace(userPattern, userLinkReplace);
export const expandMentions = (html: string): string => html.replace(userPattern, userLinkReplace);

export function enrichText(text: string, allowNewlines = true): string {
let html = autolink(escapeHtml(text), toLink);
Expand All @@ -60,7 +60,7 @@ export function richHTML(text: string, newLines = true): Hooks {

const linkPattern = /\b\b(?:https?:\/\/)?(lichess\.org\/[-–—\w+&'@#\/%?=()~|!:,.;]+[\w+&@#\/%=~|])/gi;
const pawnDropPattern = /^[a-h][2-7]$/;
export const movePattern =
export const movePattern: RegExp =
/\b(\d+)\s*(\.+)\s*(?:[o0-]+[o0]|[NBRQKP\u2654\u2655\u2656\u2657\u2658\u2659]?[a-h]?[1-8]?[x@]?[a-h][1-8](?:=[NBRQK\u2654\u2655\u2656\u2657\u2658\u2659])?)\+?#?[!\?=]{0,5}/gi;
const boardPattern = /\b(?:board|game)\s(\d{1,2})/gi;

Expand Down
10 changes: 5 additions & 5 deletions ui/common/src/selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface Selectable<C = any> {
}

export class Selector<T extends Selectable, C = any> {
group = new Map<string, T>();
group: Map<string, T> = new Map<string, T>();
context?: C;
key: string | false = false;

Expand All @@ -22,7 +22,7 @@ export class Selector<T extends Selectable, C = any> {
return this.key ? this.group.get(this.key) : undefined;
}

select(key: string | false) {
select(key: string | false): void {
if (this.key) {
if (this.key === key) return;
this.selected?.deselect?.(this.context);
Expand All @@ -35,14 +35,14 @@ export class Selector<T extends Selectable, C = any> {
return this.group.get(key);
}

set(key: string, val: T) {
set(key: string, val: T): void {
const reselect = this.key === key;
this.close(key);
this.group.set(key, val);
if (reselect) this.select(key);
}

close(key?: string) {
close(key?: string): void {
if (key === undefined) {
for (const k of this.group.keys()) this.close(k);
return;
Expand All @@ -54,7 +54,7 @@ export class Selector<T extends Selectable, C = any> {
this.group.get(key)?.close?.(this.context);
}

delete(key?: string) {
delete(key?: string): void {
this.close(key);
key ? this.group.delete(key) : this.group.clear();
}
Expand Down
Loading

0 comments on commit d608f0c

Please sign in to comment.