From fc6d96391280cdace9283483f89eaa84d92d044d Mon Sep 17 00:00:00 2001 From: Guangcong Luo Date: Mon, 19 May 2025 13:27:19 -0700 Subject: [PATCH] Strongly type Config (Also remove a bunch of global types) --- config/config-example.js | 1 + .../src/battle-animations-moves.ts | 1 + play.pokemonshowdown.com/src/battle-dex.ts | 19 +++++---- play.pokemonshowdown.com/src/battle-log.ts | 5 ++- .../src/battle-searchresults.tsx | 1 + play.pokemonshowdown.com/src/battle-sound.ts | 4 +- .../src/client-connection.ts | 6 +-- play.pokemonshowdown.com/src/client-core.ts | 2 +- play.pokemonshowdown.com/src/client-main.ts | 32 ++++++++++++++ play.pokemonshowdown.com/src/globals.d.ts | 42 +++++-------------- play.pokemonshowdown.com/src/panel-battle.tsx | 2 +- play.pokemonshowdown.com/src/panel-ladder.tsx | 2 +- .../src/panel-mainmenu.tsx | 2 +- play.pokemonshowdown.com/src/panel-popups.tsx | 4 +- play.pokemonshowdown.com/src/panel-topbar.tsx | 2 +- teams.pokemonshowdown.com/src/teams-index.tsx | 1 + .../src/teams-search.tsx | 1 + teams.pokemonshowdown.com/src/teams-view.tsx | 1 + 18 files changed, 75 insertions(+), 53 deletions(-) diff --git a/config/config-example.js b/config/config-example.js index df8551b4d..af0dcb250 100644 --- a/config/config-example.js +++ b/config/config-example.js @@ -1,3 +1,4 @@ +/** @type {import('../play.pokemonshowdown.com/src/client-main').PSConfig} */ var Config = Config || {}; /* version */ Config.version = "0"; diff --git a/play.pokemonshowdown.com/src/battle-animations-moves.ts b/play.pokemonshowdown.com/src/battle-animations-moves.ts index 566f6208b..a57c7fba6 100644 --- a/play.pokemonshowdown.com/src/battle-animations-moves.ts +++ b/play.pokemonshowdown.com/src/battle-animations-moves.ts @@ -10,6 +10,7 @@ */ import { type AnimTable, BattleOtherAnims } from './battle-animations'; +import { Config } from './client-main'; export const BattleMoveAnims: AnimTable = { taunt: { diff --git a/play.pokemonshowdown.com/src/battle-dex.ts b/play.pokemonshowdown.com/src/battle-dex.ts index f3e431985..5b9ba9936 100644 --- a/play.pokemonshowdown.com/src/battle-dex.ts +++ b/play.pokemonshowdown.com/src/battle-dex.ts @@ -25,6 +25,7 @@ import { } from "./battle-dex-data"; import type * as DexData from "./battle-dex-data"; import type { Teams } from "./battle-teams"; +import { Config } from "./client-main"; export declare namespace Dex { /* eslint-disable @typescript-eslint/no-shadow */ @@ -290,9 +291,9 @@ export const Dex = new class implements ModdedDex { } if (avatar.includes('.') && window.Config?.server?.registered) { // custom avatar served by the server - let protocol = (Config.server.port === 443) ? 'https' : 'http'; - return protocol + '://' + Config.server.host + ':' + Config.server.port + - '/avatars/' + encodeURIComponent(avatar).replace(/%3F/g, '?'); + const protocol = (Config.server.port === 443) ? 'https' : 'http'; + const server = `${protocol}://${Config.server.host}:${Config.server.port}`; + return `${server}/avatars/${encodeURIComponent(avatar).replace(/%3F/g, '?')}`; } return Dex.resourcePrefix + 'sprites/trainers/' + Dex.sanitizeName(avatar || 'unknown') + '.png'; } @@ -888,7 +889,7 @@ export const Dex = new class implements ModdedDex { getItemIcon(item: any) { let num = 0; - if (typeof item === 'string' && exports.BattleItems) item = exports.BattleItems[toID(item)]; + if (typeof item === 'string' && window.BattleItems) item = window.BattleItems[toID(item)]; if (item?.spritenum) num = item.spritenum; let top = Math.floor(num / 16) * 24; @@ -922,8 +923,8 @@ export const Dex = new class implements ModdedDex { getPokeballs() { if (this.pokeballs) return this.pokeballs; this.pokeballs = []; - if (!window.BattleItems) window.BattleItems = {}; - for (const data of Object.values(window.BattleItems)) { + window.BattleItems ||= {}; + for (const data of Object.values(BattleItems)) { if (!data.isPokeball) continue; this.pokeballs.push(data.name); } @@ -944,7 +945,7 @@ export class ModdedDex { pokeballs: string[] | null = null; constructor(modid: ID) { this.modid = modid; - const gen = parseInt(modid.substr(3, 1), 10); + const gen = parseInt(modid.charAt(3), 10); if (!modid.startsWith('gen') || !gen) throw new Error("Unsupported modid"); this.gen = gen; } @@ -1132,8 +1133,8 @@ export class ModdedDex { getPokeballs() { if (this.pokeballs) return this.pokeballs; this.pokeballs = []; - if (!window.BattleItems) window.BattleItems = {}; - for (const data of Object.values(window.BattleItems)) { + window.BattleItems ||= {}; + for (const data of Object.values(BattleItems)) { if (data.gen && data.gen > this.gen) continue; if (!data.isPokeball) continue; this.pokeballs.push(data.name); diff --git a/play.pokemonshowdown.com/src/battle-log.ts b/play.pokemonshowdown.com/src/battle-log.ts index 6d4a1eda2..0d8815675 100644 --- a/play.pokemonshowdown.com/src/battle-log.ts +++ b/play.pokemonshowdown.com/src/battle-log.ts @@ -19,6 +19,7 @@ import { Dex, toID, toRoomid, toUserid, type ID } from './battle-dex'; import { Teams } from './battle-teams'; import { BattleTextParser, type Args, type KWArgs } from './battle-text-parser'; import { Net } from './client-connection'; // optional +import { Config } from './client-main'; // Caja declare const html4: any; @@ -298,7 +299,7 @@ export class BattleLog { const body = args[2]; const roomid = this.scene?.battle.roomid; if (!roomid) break; - app.rooms[roomid].notifyOnce(title, body, 'highlight'); + window.app?.rooms[roomid].notifyOnce(title, body, 'highlight'); break; case 'showteam': { @@ -1344,7 +1345,7 @@ export class BattleLog { } static interstice = (() => { - const whitelist: string[] = Config.whitelist; + const whitelist = Config.whitelist || []; const patterns = whitelist.map(entry => new RegExp( `^(https?:)?//([A-Za-z0-9-]*\\.)?${entry.replace(/\./g, '\\.')}(/.*)?`, 'i' )); diff --git a/play.pokemonshowdown.com/src/battle-searchresults.tsx b/play.pokemonshowdown.com/src/battle-searchresults.tsx index 058f9f0cd..9b58cefb0 100644 --- a/play.pokemonshowdown.com/src/battle-searchresults.tsx +++ b/play.pokemonshowdown.com/src/battle-searchresults.tsx @@ -10,6 +10,7 @@ import preact from "../js/lib/preact"; import { Dex, toID, type ID } from "./battle-dex"; import type { DexSearch, SearchRow, SearchType } from "./battle-dex-search"; +import { Config } from "./client-main"; export class PSSearchResults extends preact.Component<{ search: DexSearch, windowing?: number | null, hideFilters?: boolean, firstRow?: SearchRow, diff --git a/play.pokemonshowdown.com/src/battle-sound.ts b/play.pokemonshowdown.com/src/battle-sound.ts index b070fc243..f71043796 100644 --- a/play.pokemonshowdown.com/src/battle-sound.ts +++ b/play.pokemonshowdown.com/src/battle-sound.ts @@ -1,4 +1,4 @@ -import { PS } from "./client-main"; +import { Config, PS } from "./client-main"; export class BattleBGM { /** @@ -116,7 +116,7 @@ export const BattleSound = new class { if (this.soundCache[url]) return this.soundCache[url]; try { const sound = document.createElement('audio'); - sound.src = 'https://' + Config.routes.client + '/' + url; + sound.src = `https://${Config.routes.client}/${url}`; sound.volume = this.effectVolume / 100; this.soundCache[url] = sound; return sound; diff --git a/play.pokemonshowdown.com/src/client-connection.ts b/play.pokemonshowdown.com/src/client-connection.ts index 3a02f46f3..1e67c510b 100644 --- a/play.pokemonshowdown.com/src/client-connection.ts +++ b/play.pokemonshowdown.com/src/client-connection.ts @@ -5,7 +5,7 @@ * @license MIT */ -import { PS } from "./client-main"; +import { Config, PS } from "./client-main"; declare const SockJS: any; declare const POKEMON_SHOWDOWN_TESTCLIENT_KEY: string | undefined; @@ -26,8 +26,8 @@ export class PSConnection { } connect() { const server = PS.server; - const port = server.protocol === 'https' ? ':' + server.port : ':' + server.httpport; - const url = server.protocol + '://' + server.host + port + server.prefix; + const port = server.protocol === 'https' ? `:${server.port}` : `:${server.httpport || server.port}`; + const url = `${server.protocol}://${server.host}${port}${server.prefix}`; try { this.socket = new SockJS(url, [], { timeout: 5 * 60 * 1000 }); } catch { diff --git a/play.pokemonshowdown.com/src/client-core.ts b/play.pokemonshowdown.com/src/client-core.ts index ca8a5551c..818408f4e 100644 --- a/play.pokemonshowdown.com/src/client-core.ts +++ b/play.pokemonshowdown.com/src/client-core.ts @@ -13,7 +13,7 @@ * @license AGPLv3 */ -import { PS } from "./client-main"; +import { Config, PS } from "./client-main"; declare const ColorThief: any; /********************************************************************** diff --git a/play.pokemonshowdown.com/src/client-main.ts b/play.pokemonshowdown.com/src/client-main.ts index 4e0a2a958..b8391d44d 100644 --- a/play.pokemonshowdown.com/src/client-main.ts +++ b/play.pokemonshowdown.com/src/client-main.ts @@ -22,6 +22,38 @@ import { Teams } from './battle-teams'; declare const BattleTextAFD: any; declare const BattleTextNotAFD: any; +/********************************************************************** + * Config + *********************************************************************/ + +export interface ServerInfo { + id: ID; + protocol: string; + host: string; + port: number; + httpport?: number; + altport?: number; + prefix: string; + afd?: boolean; + registered?: boolean; +} +export interface PSConfig { + server: ServerInfo; + defaultserver: ServerInfo; + routes: { + root: string, + client: string, + dex: string, + replays: string, + users: string, + teams: string, + }; + customcolors: Record; + whitelist?: string[]; + testclient?: boolean; +} +export declare const Config: PSConfig; + /********************************************************************** * Prefs *********************************************************************/ diff --git a/play.pokemonshowdown.com/src/globals.d.ts b/play.pokemonshowdown.com/src/globals.d.ts index c7e5aa588..04ec3c619 100644 --- a/play.pokemonshowdown.com/src/globals.d.ts +++ b/play.pokemonshowdown.com/src/globals.d.ts @@ -3,42 +3,22 @@ // dex data /////////// +type AnyObject = { [k: string]: any }; declare const BattleText: { [id: string]: { [templateName: string]: string } }; declare const BattleFormats: { [id: string]: import('./panel-teamdropdown').FormatData }; -declare const BattlePokedex: any; -declare const BattleMovedex: any; -declare const BattleAbilities: any; -declare const BattleItems: any; -declare const BattleAliases: any; -declare const BattleStatuses: any; -declare const BattlePokemonSprites: any; -declare const BattlePokemonSpritesBW: any; +declare const BattlePokedex: { [id: string]: AnyObject }; +declare const BattleMovedex: { [id: string]: AnyObject }; +declare const BattleAbilities: { [id: string]: AnyObject }; +declare const BattleItems: { [id: string]: AnyObject }; +declare const BattleAliases: { [id: string]: string }; +declare const BattleStatuses: { [id: string]: AnyObject }; +declare const BattlePokemonSprites: { [id: string]: AnyObject }; +declare const BattlePokemonSpritesBW: { [id: string]: AnyObject }; declare const NonBattleGames: { [id: string]: string }; -// PS globals -///////////// - -declare const Config: any; -declare const Replays: any; -declare const exports: any; -type AnyObject = { [k: string]: any }; -declare const app: { user: AnyObject, rooms: AnyObject, ignore?: AnyObject }; +// Window +///////// interface Window { [k: string]: any; } - -// Temporary globals (exported from modules, used by non-module files) - -// When creating new module files, these should all be commented out -// to make sure they're not being used globally in modules. - -// declare var Battle: typeof import('./battle').Battle; -// type Battle = import('./battle').Battle; -// declare var BattleScene: typeof import('./battle-animations').BattleScene; -// type BattleScene = import('./battle-animations').BattleScene; -// declare var Pokemon: typeof import('./battle').Pokemon; -// type Pokemon = import('./battle').Pokemon; -// type ServerPokemon = import('./battle').ServerPokemon; -// declare var BattleLog: typeof import('./battle-log').BattleLog; -// type BattleLog = import('./battle-log').BattleLog; diff --git a/play.pokemonshowdown.com/src/panel-battle.tsx b/play.pokemonshowdown.com/src/panel-battle.tsx index f1b08a54b..2be9bad6d 100644 --- a/play.pokemonshowdown.com/src/panel-battle.tsx +++ b/play.pokemonshowdown.com/src/panel-battle.tsx @@ -6,7 +6,7 @@ */ import preact from "../js/lib/preact"; -import { PS, PSRoom, type RoomOptions, type RoomID } from "./client-main"; +import { PS, PSRoom, type RoomOptions, type RoomID, Config } from "./client-main"; import { PSIcon, PSPanelWrapper, PSRoomPanel } from "./panels"; import { ChatLog, ChatRoom, ChatTextEntry, ChatUserList } from "./panel-chat"; import { FormatDropdown } from "./panel-mainmenu"; diff --git a/play.pokemonshowdown.com/src/panel-ladder.tsx b/play.pokemonshowdown.com/src/panel-ladder.tsx index 8ee2eb375..8e207b560 100644 --- a/play.pokemonshowdown.com/src/panel-ladder.tsx +++ b/play.pokemonshowdown.com/src/panel-ladder.tsx @@ -7,7 +7,7 @@ * @license MIT */ -import { PS, PSRoom } from "./client-main"; +import { Config, PS, PSRoom } from "./client-main"; import { Net } from "./client-connection"; import { PSPanelWrapper, PSRoomPanel } from "./panels"; import { BattleLog } from "./battle-log"; diff --git a/play.pokemonshowdown.com/src/panel-mainmenu.tsx b/play.pokemonshowdown.com/src/panel-mainmenu.tsx index 3498769da..e06a94cc4 100644 --- a/play.pokemonshowdown.com/src/panel-mainmenu.tsx +++ b/play.pokemonshowdown.com/src/panel-mainmenu.tsx @@ -7,7 +7,7 @@ import preact from "../js/lib/preact"; import { PSLoginServer } from "./client-connection"; -import { PS, PSRoom, type RoomID, type RoomOptions, type Team } from "./client-main"; +import { Config, PS, PSRoom, type RoomID, type RoomOptions, type Team } from "./client-main"; import { PSIcon, PSPanelWrapper, PSRoomPanel } from "./panels"; import type { BattlesRoom } from "./panel-battle"; import type { ChatRoom } from "./panel-chat"; diff --git a/play.pokemonshowdown.com/src/panel-popups.tsx b/play.pokemonshowdown.com/src/panel-popups.tsx index f742967de..1ac21d6b1 100644 --- a/play.pokemonshowdown.com/src/panel-popups.tsx +++ b/play.pokemonshowdown.com/src/panel-popups.tsx @@ -4,7 +4,9 @@ import type { ID } from "./battle-dex-data"; import { BattleLog } from "./battle-log"; import { PSLoginServer } from "./client-connection"; import { PSBackground } from "./client-core"; -import { PSRoom, type RoomOptions, PS, type PSLoginState, type RoomID, type TimestampOptions } from "./client-main"; +import { + PS, PSRoom, Config, type RoomOptions, type PSLoginState, type RoomID, type TimestampOptions, +} from "./client-main"; import { type BattleRoom } from "./panel-battle"; import { ChatUserList, type ChatRoom } from "./panel-chat"; import { PSRoomPanel, PSPanelWrapper, PSView } from "./panels"; diff --git a/play.pokemonshowdown.com/src/panel-topbar.tsx b/play.pokemonshowdown.com/src/panel-topbar.tsx index a0d9d0af4..04c930279 100644 --- a/play.pokemonshowdown.com/src/panel-topbar.tsx +++ b/play.pokemonshowdown.com/src/panel-topbar.tsx @@ -10,7 +10,7 @@ */ import preact from "../js/lib/preact"; -import { PS, type PSRoom, type RoomID } from "./client-main"; +import { Config, PS, type PSRoom, type RoomID } from "./client-main"; import { PSView } from "./panels"; import type { Battle } from "./battle"; import { BattleLog } from "./battle-log"; // optional diff --git a/teams.pokemonshowdown.com/src/teams-index.tsx b/teams.pokemonshowdown.com/src/teams-index.tsx index 76bb2b555..23e525e0f 100644 --- a/teams.pokemonshowdown.com/src/teams-index.tsx +++ b/teams.pokemonshowdown.com/src/teams-index.tsx @@ -3,6 +3,7 @@ import preact from '../../play.pokemonshowdown.com/js/lib/preact'; import { Net, MiniTeam, type ServerTeam } from './utils'; import type { PageProps } from './teams'; +import { Config } from '../../play.pokemonshowdown.com/src/client-main'; declare const toID: (val: any) => string; diff --git a/teams.pokemonshowdown.com/src/teams-search.tsx b/teams.pokemonshowdown.com/src/teams-search.tsx index ba114b07e..6466b758a 100644 --- a/teams.pokemonshowdown.com/src/teams-search.tsx +++ b/teams.pokemonshowdown.com/src/teams-search.tsx @@ -3,6 +3,7 @@ import preact from '../../play.pokemonshowdown.com/js/lib/preact'; import { Net, type ServerTeam, MiniTeam } from './utils'; import type { PageProps } from './teams'; +import { Config } from '../../play.pokemonshowdown.com/src/client-main'; declare const toID: (val: any) => string; declare const BattleAliases: Record; diff --git a/teams.pokemonshowdown.com/src/teams-view.tsx b/teams.pokemonshowdown.com/src/teams-view.tsx index 5ad4f58cb..1608ca963 100644 --- a/teams.pokemonshowdown.com/src/teams-view.tsx +++ b/teams.pokemonshowdown.com/src/teams-view.tsx @@ -6,6 +6,7 @@ import { BattleLog } from '../../play.pokemonshowdown.com/src/battle-log'; import type { PageProps } from './teams'; import { Dex } from '../../play.pokemonshowdown.com/src/battle-dex'; import { BattleStatNames } from '../../play.pokemonshowdown.com/src/battle-dex-data'; +import { Config } from '../../play.pokemonshowdown.com/src/client-main'; declare const toID: (str: any) => string; declare const BattleAliases: Record;