Merge branch 'master' into lint-bin-files

This commit is contained in:
Thibault Duplessis
2026-02-20 18:42:25 +01:00
committed by GitHub
24 changed files with 74 additions and 116 deletions
+2 -2
View File
@@ -2,9 +2,9 @@
"name": "bin",
"type": "module",
"dependencies": {
"@types/node": "24.0.1",
"@types/node": "24.10.13",
"cheerio": "^1.1.2",
"fast-xml-parser": "^5.3.4",
"fast-xml-parser": "^5.3.6",
"mongodb": "6.16.0"
},
"license": "ISC"
+1 -1
View File
@@ -18,7 +18,7 @@
"@lichess-org/chessground": "^10.0.2",
"@lichess-org/pgn-viewer": "^2.5.9",
"@types/lichess": "workspace:*",
"@types/node": "^24.10.0",
"@types/node": "^24.10.13",
"ab": "github:lichess-org/ab-stub",
"chessops": "^0.15",
"jsdom": "^27.1.0",
+18 -30
View File
@@ -23,8 +23,8 @@ importers:
specifier: workspace:*
version: link:ui/@types/lichess
'@types/node':
specifier: ^24.10.0
version: 24.10.0
specifier: ^24.10.13
version: 24.10.13
ab:
specifier: github:lichess-org/ab-stub
version: https://codeload.github.com/lichess-org/ab-stub/tar.gz/94236bf34dbc9c05daf50f4c9842d859b9142be0
@@ -68,14 +68,14 @@ importers:
bin:
dependencies:
'@types/node':
specifier: 24.0.1
version: 24.0.1
specifier: 24.10.13
version: 24.10.13
cheerio:
specifier: ^1.1.2
version: 1.1.2
fast-xml-parser:
specifier: ^5.3.4
version: 5.3.4
specifier: ^5.3.6
version: 5.3.6
mongodb:
specifier: 6.16.0
version: 6.16.0
@@ -501,8 +501,8 @@ importers:
specifier: workspace:*
version: link:../lib
swiper:
specifier: ^12.0.3
version: 12.0.3
specifier: ^12.1.2
version: 12.1.2
ui/round:
dependencies:
@@ -1085,11 +1085,8 @@ packages:
'@types/node@22.17.0':
resolution: {integrity: sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ==}
'@types/node@24.0.1':
resolution: {integrity: sha512-MX4Zioh39chHlDJbKmEgydJDS3tspMP/lnQC67G3SWsTnb9NeYVWOjkxpOSy4oMfPs4StcWHwBrvUb4ybfnuaw==}
'@types/node@24.10.0':
resolution: {integrity: sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==}
'@types/node@24.10.13':
resolution: {integrity: sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==}
'@types/qrcode@1.5.6':
resolution: {integrity: sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==}
@@ -1409,8 +1406,8 @@ packages:
fast-uri@3.1.0:
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
fast-xml-parser@5.3.4:
resolution: {integrity: sha512-EFd6afGmXlCx8H8WTZHhAoDaWaGyuIBoZJ2mknrNxug+aZKjkp0a0dlars9Izl+jF+7Gu1/5f/2h68cQpe0IiA==}
fast-xml-parser@5.3.6:
resolution: {integrity: sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==}
hasBin: true
fastest-levenshtein@1.0.16:
@@ -2102,8 +2099,8 @@ packages:
resolution: {integrity: sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==}
engines: {node: '>= 0.8.0'}
swiper@12.0.3:
resolution: {integrity: sha512-BHd6U1VPEIksrXlyXjMmRWO0onmdNPaTAFduzqR3pgjvi7KfmUCAm/0cj49u2D7B0zNjMw02TSeXfinC1hDCXg==}
swiper@12.1.2:
resolution: {integrity: sha512-4gILrI3vXZqoZh71I1PALqukCFgk+gpOwe1tOvz5uE9kHtl2gTDzmYflYCwWvR4LOvCrJi6UEEU+gnuW5BtkgQ==}
engines: {node: '>= 4.7.0'}
symbol-tree@3.2.4:
@@ -2166,9 +2163,6 @@ packages:
undici-types@7.16.0:
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
undici-types@7.8.0:
resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==}
undici@7.16.0:
resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==}
engines: {node: '>=20.18.1'}
@@ -2638,17 +2632,13 @@ snapshots:
dependencies:
undici-types: 6.21.0
'@types/node@24.0.1':
dependencies:
undici-types: 7.8.0
'@types/node@24.10.0':
'@types/node@24.10.13':
dependencies:
undici-types: 7.16.0
'@types/qrcode@1.5.6':
dependencies:
'@types/node': 24.10.0
'@types/node': 24.10.13
'@types/react@19.1.9':
dependencies:
@@ -2973,7 +2963,7 @@ snapshots:
fast-uri@3.1.0: {}
fast-xml-parser@5.3.4:
fast-xml-parser@5.3.6:
dependencies:
strnum: 2.1.2
@@ -3677,7 +3667,7 @@ snapshots:
dependencies:
svg.js: 2.7.1
swiper@12.0.3: {}
swiper@12.1.2: {}
symbol-tree@3.2.4: {}
@@ -3732,8 +3722,6 @@ snapshots:
undici-types@7.16.0: {}
undici-types@7.8.0: {}
undici@7.16.0: {}
unicorn-magic@0.4.0: {}
+1 -1
View File
@@ -22,7 +22,7 @@ object Dependencies {
val maxmind = "com.maxmind.geoip2" % "geoip2" % "4.0.1"
val caffeine = "com.github.ben-manes.caffeine" % "caffeine" % "3.2.3" % "compile"
val scaffeine = "com.github.blemale" %% "scaffeine" % "5.3.0" % "compile"
val googleOAuth = "com.google.auth" % "google-auth-library-oauth2-http" % "1.42.1"
val googleOAuth = "com.google.auth" % "google-auth-library-oauth2-http" % "1.43.0"
val galimatias = "io.mola.galimatias" % "galimatias" % "0.2.2-NF"
val scalatags = "com.lihaoyi" %% "scalatags" % "0.13.1"
val lettuce = "io.lettuce" % "lettuce-core" % "7.4.0.RELEASE"
+1 -1
View File
@@ -11,7 +11,7 @@
},
"dependencies": {
"@types/micromatch": "4.0.10",
"@types/node": "24.8.1",
"@types/node": "24.10.13",
"@types/tinycolor2": "1.4.6",
"esbuild": "0.27.3",
"fast-glob": "3.3.3",
+9 -9
View File
@@ -12,8 +12,8 @@ importers:
specifier: 4.0.10
version: 4.0.10
'@types/node':
specifier: 24.8.1
version: 24.8.1
specifier: 24.10.13
version: 24.10.13
'@types/tinycolor2':
specifier: 1.4.6
version: 1.4.6
@@ -114,8 +114,8 @@ packages:
'@types/micromatch@4.0.10':
resolution: {integrity: sha512-5jOhFDElqr4DKTrTEbnW8DZ4Hz5LRUEmyrGpCMrD/NphYv3nUnaF08xmSLx1rGGnyEs/kFnhiw6dCgcDqMr5PQ==}
'@types/node@24.8.1':
resolution: {integrity: sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q==}
'@types/node@24.10.13':
resolution: {integrity: sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==}
'@types/tinycolor2@1.4.6':
resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==}
@@ -236,8 +236,8 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
undici-types@7.14.0:
resolution: {integrity: sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==}
undici-types@7.16.0:
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
ignoredOptionalDependencies:
- '@esbuild/*-arm'
@@ -293,9 +293,9 @@ snapshots:
dependencies:
'@types/braces': 3.0.5
'@types/node@24.8.1':
'@types/node@24.10.13':
dependencies:
undici-types: 7.14.0
undici-types: 7.16.0
'@types/tinycolor2@1.4.6': {}
@@ -391,4 +391,4 @@ snapshots:
typescript@5.9.3: {}
undici-types@7.14.0: {}
undici-types@7.16.0: {}
+3 -3
View File
@@ -1,6 +1,6 @@
import { Api } from '../../../node_modules/@lichess-org/chessground/dist/api';
import { Config } from '../../../node_modules/@lichess-org/chessground/dist/config';
import * as cg from '../../../node_modules/@lichess-org/chessground/dist/types';
import { Api } from '@lichess-org/chessground/api';
import { Config } from '@lichess-org/chessground/config';
import * as cg from '@lichess-org/chessground/types';
declare global {
type CgApi = Api;
+2 -3
View File
@@ -1,10 +1,9 @@
import { drag } from './crazyCtrl';
import { h } from 'snabbdom';
import type { MouchEvent } from '@lichess-org/chessground/types';
import { onInsert } from 'lib/view';
import type AnalyseCtrl from '../ctrl';
const eventNames = ['mousedown', 'touchstart'];
const eventNames = ['mousedown', 'touchstart'] as const;
const oKeys = ['pawn', 'knight', 'bishop', 'rook', 'queen'] as const;
type Position = 'top' | 'bottom';
@@ -23,7 +22,7 @@ export default function (ctrl: AnalyseCtrl, color: Color, position: Position) {
class: { usable },
hook: onInsert(el => {
eventNames.forEach(name => {
el.addEventListener(name, e => drag(ctrl, color, e as MouchEvent));
el.addEventListener(name, e => drag(ctrl, color, e));
});
}),
},
+1 -6
View File
@@ -67,12 +67,7 @@ export class ExplorerConfigCtrl {
const prevData = previous?.data;
this.data = {
open: prevData?.open || prop(false),
db: storedProp<ExplorerDb>(
'explorer.db2.' + variant,
this.allDbs[0],
str => str as ExplorerDb,
v => v,
),
db: storedProp<ExplorerDb>('explorer.db2.' + variant, this.allDbs[0], str => str as ExplorerDb),
rating: storedJsonProp('analyse.explorer.rating', () => allRatings.slice(1)),
speed: storedJsonProp<ExplorerSpeed[]>('explorer.speed', () => allSpeeds.slice(1)),
mode: storedJsonProp<ExplorerMode[]>('explorer.mode', () => allModes),
+1 -6
View File
@@ -42,12 +42,7 @@ export class StudyChapterNewForm {
if (!val) this.dialog?.close();
});
initial = toggle(false);
tab = storedProp<ChapterTab>(
'analyse.study.form.tab',
'init',
str => str as ChapterTab,
v => v,
);
tab = storedProp<ChapterTab>('analyse.study.form.tab', 'init', str => str as ChapterTab);
editor: LichessEditor | null = null;
editorFen: Prop<FEN | null> = prop(null);
isDefaultName = toggle(true);
+1 -1
View File
@@ -66,7 +66,7 @@ export const formView = (ctrl: TopicsCtrl, userId?: string): VNode =>
],
onInsert: dlg => {
dlg.show();
(dlg.view.querySelector('.tagify__input') as HTMLElement)?.focus();
dlg.view.querySelector<HTMLElement>('.tagify__input')?.focus();
},
});
+5 -8
View File
@@ -13,14 +13,11 @@ import type { TreePath } from 'lib/tree/types';
export class TreeView {
constructor(readonly ctrl: AnalyseCtrl) {}
private autoScrollRequest: 'instant' | 'smooth' | false = false;
private autoScrollRequest: ScrollBehavior | false = false;
hidden = true;
modePreference = storedProp<'column' | 'inline'>(
'treeView',
'column',
str => (str === 'column' ? 'column' : 'inline'),
v => v,
modePreference = storedProp<'column' | 'inline'>('treeView', 'column', str =>
str === 'column' ? 'column' : 'inline',
);
mode: 'column' | 'inline';
@@ -33,7 +30,7 @@ export class TreeView {
return this.mode === 'column' ? renderColumnView(this.ctrl, concealOf) : renderInlineView(this.ctrl);
}
requestAutoScroll(request: 'instant' | 'smooth' | false) {
requestAutoScroll(request: ScrollBehavior | false) {
this.autoScrollRequest = request;
}
@@ -82,7 +79,7 @@ function eventPath(e: MouseEvent): TreePath | null {
);
}
const autoScroll = throttle(200, (behavior: 'instant' | 'smooth' = 'instant') => {
const autoScroll = throttle(200, (behavior: ScrollBehavior = 'instant') => {
const scrollView = document.querySelector<HTMLElement>('.analyse__moves')!;
const moveEl = scrollView.querySelector<HTMLElement>('.active');
if (!moveEl) return scrollView.scrollTo({ top: 0, behavior });
+7 -6
View File
@@ -166,11 +166,12 @@ export function renderNvui(ctx: AnalyseNvuiContext): VNode {
});
});
root.find('.copy-fen').on('click', function (this: HTMLElement) {
const inputFen = document.querySelector('.analyse__underboard__fen input') as HTMLInputElement;
const fen = inputFen.value;
navigator.clipboard.writeText(fen).then(() => {
notify.set(i18n.nvui.copiedToClipboard('FEN'));
});
const fen = document.querySelector<HTMLInputElement>('.analyse__underboard__fen input')?.value;
if (fen) {
navigator.clipboard.writeText(fen).then(() => {
notify.set(i18n.nvui.copiedToClipboard('FEN'));
});
}
});
},
},
@@ -346,7 +347,7 @@ function onSubmit(ctx: AnalyseNvuiContext, $input: Cash) {
if (command && !command.invalid?.(ctrl)) command.cb(ctx, input);
else {
const move = inputToMove(input, ctrl.node.fen, ctrl.chessground);
const isDrop = (u: undefined | string | DropMove) => !!(u && typeof u !== 'string');
const isDrop = (u?: string | DropMove) => !!(u && typeof u !== 'string');
const isInvalidDrop = (d: DropMove) =>
!ctrl.crazyValid(d.role, d.key) || ctrl.chessground.state.pieces.has(d.key);
const isInvalidCrazy = isDrop(move) && isInvalidDrop(move);
+1 -1
View File
@@ -91,7 +91,7 @@ site.load.then(() => {
$editor.find('div.status').removeClass('saved');
});
const submit = debounce(() => {
const form = document.querySelector('form.async') as HTMLFormElement;
const form = document.querySelector<HTMLFormElement>('form.async');
if (!form) return;
xhr.formToXhr(form).then(() => {
$editor.find('div.status').addClass('saved');
+2 -1
View File
@@ -15,7 +15,8 @@ export function initModule(
fireworks: true,
},
): void {
const canvas = document.querySelector('canvas#confetti') as HTMLCanvasElement;
const canvas = document.querySelector<HTMLCanvasElement>('canvas#confetti');
if (!canvas) return;
const party = confetti.create(canvas, {
disableForReducedMotion: true,
+3 -3
View File
@@ -1,7 +1,7 @@
import { pubsub } from 'lib/pubsub';
site.load.then(() => {
const form = document.querySelector('.search__form') as HTMLFormElement,
const form = document.querySelector<HTMLFormElement>('.search__form'),
$form = $(form),
$usernames = $form.find('.usernames input'),
$userRows = $form.find('.user-row'),
@@ -65,8 +65,8 @@ site.load.then(() => {
function serialize() {
const params = new URLSearchParams();
for (const [k, v] of new FormData(form).entries()) {
if (v != '') params.set(k, v as string);
for (const [k, v] of new FormData(form ?? undefined).entries()) {
if (v != '') params.set(k, v.toString());
}
return params.toString();
}
+1 -1
View File
@@ -63,7 +63,7 @@ function appeal() {
}
function autoForm({ selector, ops }: { selector: string; ops: string }) {
const el = document.querySelector(selector) as HTMLElement;
const el = document.querySelector<HTMLElement>(selector);
const oplist = ops.split(' ');
if (!el || oplist.length === 0) return;
if (oplist.includes('focus')) el.focus();
+1 -1
View File
@@ -10,7 +10,7 @@ export const autoScroll = throttle(100, (movesEl: HTMLElement, ctrl: PlayCtrl) =
if (ctrl.board.onPly < 3) st = 0;
else if (ctrl.isOnLastPly()) st = scrollMax;
else {
const plyEl = movesEl.querySelector('.current') as HTMLElement | undefined;
const plyEl = movesEl.querySelector<HTMLElement>('.current');
if (plyEl)
st =
displayColumns() === 1
+1 -9
View File
@@ -92,12 +92,7 @@ export default class CoordinateTrainerCtrl {
}
colorChoice: Prop<ColorChoice> = withEffect<ColorChoice>(
storedProp<ColorChoice>(
'coordinateTrainer.colorChoice',
'random',
str => str as ColorChoice,
v => v,
),
storedProp<ColorChoice>('coordinateTrainer.colorChoice', 'random', str => str as ColorChoice),
() => this.setOrientationFromColorChoice(),
);
@@ -114,7 +109,6 @@ export default class CoordinateTrainerCtrl {
'coordinateTrainer.mode',
window.location.hash === '#name' ? 'nameSquare' : 'findSquare',
str => str as Mode,
v => v,
),
() => this.onModeChange(),
);
@@ -148,7 +142,6 @@ export default class CoordinateTrainerCtrl {
'coordinateTrainer.timeControl',
document.body.classList.contains('kid') ? 'untimed' : 'thirtySeconds',
str => str as TimeControl,
v => v,
),
this.redraw,
);
@@ -192,7 +185,6 @@ export default class CoordinateTrainerCtrl {
'coordinateTrainer.coordinateInputMethod',
window.innerWidth >= 980 ? 'text' : 'buttons',
str => str as InputMethod,
v => v,
),
this.redraw,
);
+9 -19
View File
@@ -13,7 +13,12 @@ export function storedProp<V>(
key: string,
defaultValue: V,
fromStr: (str: string) => V,
toStr: (v: V) => string,
toStr: (v: V) => string = (v: V) => {
if (v && typeof v.toString === 'function') {
return v.toString();
}
throw new Error(`storedProp: value ${typeof v} has no toString method, provide a custom stringifier`);
},
): StoredProp<V> {
const compatKey = 'analyse.' + key;
let cached: V;
@@ -35,20 +40,10 @@ export function storedProp<V>(
}
export const storedStringProp = (k: string, defaultValue: string): StoredProp<string> =>
storedProp<string>(
k,
defaultValue,
str => str,
v => v,
);
storedProp<string>(k, defaultValue, str => str);
export const storedBooleanProp = (k: string, defaultValue: boolean): StoredProp<boolean> =>
storedProp<boolean>(
k,
defaultValue,
str => str === 'true',
v => v.toString(),
);
storedProp<boolean>(k, defaultValue, str => str === 'true');
export const storedStringPropWithEffect = (
k: string,
@@ -63,12 +58,7 @@ export const storedBooleanPropWithEffect = (
): Prop<boolean> => withEffect(storedBooleanProp(k, defaultValue), effect);
export const storedIntProp = (k: string, defaultValue: number): StoredProp<number> =>
storedProp<number>(
k,
defaultValue,
str => Number(str),
v => v + '',
);
storedProp<number>(k, defaultValue, str => Number(str));
export const storedIntPropWithEffect = (
k: string,
+1 -1
View File
@@ -23,7 +23,7 @@ export const expandCheckboxZone = (table: HTMLTableElement, tdSelector: string,
$(table).on('click', tdSelector, (e: MouseEvent) => {
if ((e.target as HTMLElement).tagName === 'INPUT') onSelect(e.target as HTMLInputElement, e.shiftKey);
else {
const input = (e.target as HTMLTableElement).querySelector('input') as HTMLInputElement | undefined;
const input = (e.target as HTMLTableElement).querySelector<HTMLInputElement>('input');
if (input && !input.disabled) {
input.checked = !input.checked;
onSelect(input, e.shiftKey);
+1 -1
View File
@@ -1,7 +1,7 @@
import { initMiniBoardWith } from 'lib/view';
site.load.then(() => {
const rootEl = document.querySelector('.puzzle-openings') as HTMLElement | undefined;
const rootEl = document.querySelector<HTMLElement>('.puzzle-openings');
if (rootEl && !('ontouchstart' in window)) loadBoardTips(rootEl);
});
+1 -1
View File
@@ -4,7 +4,7 @@
"type": "module",
"dependencies": {
"lib": "workspace:*",
"swiper": "^12.0.3"
"swiper": "^12.1.2"
},
"build": {
"bundle": "src/recap.ts"
+1 -1
View File
@@ -34,7 +34,7 @@ const autoScroll = throttle(100, (movesEl: HTMLElement, ctrl: RoundController) =
if (ctrl.ply < 3) st = 0;
else if (ctrl.ply === util.lastPly(ctrl.data)) st = scrollMax;
else {
const plyEl = movesEl.querySelector('.a1t') as HTMLElement | undefined;
const plyEl = movesEl.querySelector<HTMLElement>('.a1t');
if (plyEl)
st =
displayColumns() === 1