From 00c96e6c541cf5f4282372f51d41e49b1fa4e3b7 Mon Sep 17 00:00:00 2001 From: MARCROCK22 <57925328+MARCROCK22@users.noreply.github.com> Date: Fri, 25 Oct 2024 11:05:42 -0400 Subject: [PATCH] feat: allow to extend RC and localized choices (#283) --- package.json | 2 +- pnpm-lock.yaml | 88 +++++++++++++------------- src/client/base.ts | 36 ++++++----- src/client/client.ts | 2 +- src/client/workerclient.ts | 4 +- src/commands/applications/options.ts | 12 +++- src/commands/applications/shared.ts | 2 + src/commands/handler.ts | 94 +++++++++++++++++++--------- 8 files changed, 146 insertions(+), 94 deletions(-) diff --git a/package.json b/package.json index 1899ff5..0c1c6e2 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "@biomejs/biome": "1.9.4", "@commitlint/cli": "^19.5.0", "@commitlint/config-conventional": "^19.5.0", - "@types/node": "^22.7.7", + "@types/node": "^22.7.9", "husky": "^9.1.6", "lint-staged": "^15.2.10", "typescript": "^5.6.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 868f588..25dde93 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,13 +13,13 @@ importers: version: 1.9.4 '@commitlint/cli': specifier: ^19.5.0 - version: 19.5.0(@types/node@22.7.7)(typescript@5.6.3) + version: 19.5.0(@types/node@22.7.9)(typescript@5.6.3) '@commitlint/config-conventional': specifier: ^19.5.0 version: 19.5.0 '@types/node': - specifier: ^22.7.7 - version: 22.7.7 + specifier: ^22.7.9 + version: 22.7.9 husky: specifier: ^9.1.6 version: 9.1.6 @@ -31,20 +31,20 @@ importers: version: 5.6.3 vitest: specifier: ^2.1.3 - version: 2.1.3(@types/node@22.7.7) + version: 2.1.3(@types/node@22.7.9) packages: - '@babel/code-frame@7.25.7': - resolution: {integrity: sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==} + '@babel/code-frame@7.25.9': + resolution: {integrity: sha512-z88xeGxnzehn2sqZ8UdGQEvYErF1odv2CftxInpSYJt6uHuPe9YjahKZITGs3l5LeI9d2ROG+obuDAoSlqbNfQ==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.25.7': - resolution: {integrity: sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==} + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.25.7': - resolution: {integrity: sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==} + '@babel/highlight@7.25.9': + resolution: {integrity: sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==} engines: {node: '>=6.9.0'} '@biomejs/biome@1.9.4': @@ -396,8 +396,8 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - '@types/node@22.7.7': - resolution: {integrity: sha512-SRxCrrg9CL/y54aiMCG3edPKdprgMVGDXjA3gB8UmmBW5TcXzRUYAh8EWzTnSJFAd1rgImPELza+A3bJ+qxz8Q==} + '@types/node@22.7.9': + resolution: {integrity: sha512-jrTfRC7FM6nChvU7X2KqcrgquofrWLFDeYC1hKfwNWomVvrn7JIksqf344WN2X/y8xrgqBd2dJATZV4GbatBfg==} '@vitest/expect@2.1.3': resolution: {integrity: sha512-SNBoPubeCJhZ48agjXruCI57DvxcsivVDdWz+SSsmjTT4QN/DfHk3zB/xKsJqMs26bLZ/pNRLnCf0j679i0uWQ==} @@ -482,8 +482,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - chai@5.1.1: - resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} + chai@5.1.2: + resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} engines: {node: '>=12'} chalk@2.4.2: @@ -1041,8 +1041,8 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite@5.4.9: - resolution: {integrity: sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==} + vite@5.4.10: + resolution: {integrity: sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -1138,16 +1138,16 @@ packages: snapshots: - '@babel/code-frame@7.25.7': + '@babel/code-frame@7.25.9': dependencies: - '@babel/highlight': 7.25.7 + '@babel/highlight': 7.25.9 picocolors: 1.1.1 - '@babel/helper-validator-identifier@7.25.7': {} + '@babel/helper-validator-identifier@7.25.9': {} - '@babel/highlight@7.25.7': + '@babel/highlight@7.25.9': dependencies: - '@babel/helper-validator-identifier': 7.25.7 + '@babel/helper-validator-identifier': 7.25.9 chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.1.1 @@ -1187,11 +1187,11 @@ snapshots: '@biomejs/cli-win32-x64@1.9.4': optional: true - '@commitlint/cli@19.5.0(@types/node@22.7.7)(typescript@5.6.3)': + '@commitlint/cli@19.5.0(@types/node@22.7.9)(typescript@5.6.3)': dependencies: '@commitlint/format': 19.5.0 '@commitlint/lint': 19.5.0 - '@commitlint/load': 19.5.0(@types/node@22.7.7)(typescript@5.6.3) + '@commitlint/load': 19.5.0(@types/node@22.7.9)(typescript@5.6.3) '@commitlint/read': 19.5.0 '@commitlint/types': 19.5.0 tinyexec: 0.3.1 @@ -1238,7 +1238,7 @@ snapshots: '@commitlint/rules': 19.5.0 '@commitlint/types': 19.5.0 - '@commitlint/load@19.5.0(@types/node@22.7.7)(typescript@5.6.3)': + '@commitlint/load@19.5.0(@types/node@22.7.9)(typescript@5.6.3)': dependencies: '@commitlint/config-validator': 19.5.0 '@commitlint/execute-rule': 19.5.0 @@ -1246,7 +1246,7 @@ snapshots: '@commitlint/types': 19.5.0 chalk: 5.3.0 cosmiconfig: 9.0.0(typescript@5.6.3) - cosmiconfig-typescript-loader: 5.1.0(@types/node@22.7.7)(cosmiconfig@9.0.0(typescript@5.6.3))(typescript@5.6.3) + cosmiconfig-typescript-loader: 5.1.0(@types/node@22.7.9)(cosmiconfig@9.0.0(typescript@5.6.3))(typescript@5.6.3) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -1418,11 +1418,11 @@ snapshots: '@types/conventional-commits-parser@5.0.0': dependencies: - '@types/node': 22.7.7 + '@types/node': 22.7.9 '@types/estree@1.0.6': {} - '@types/node@22.7.7': + '@types/node@22.7.9': dependencies: undici-types: 6.19.8 @@ -1430,16 +1430,16 @@ snapshots: dependencies: '@vitest/spy': 2.1.3 '@vitest/utils': 2.1.3 - chai: 5.1.1 + chai: 5.1.2 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.3(@vitest/spy@2.1.3)(vite@5.4.9(@types/node@22.7.7))': + '@vitest/mocker@2.1.3(@vitest/spy@2.1.3)(vite@5.4.10(@types/node@22.7.9))': dependencies: '@vitest/spy': 2.1.3 estree-walker: 3.0.3 magic-string: 0.30.12 optionalDependencies: - vite: 5.4.9(@types/node@22.7.7) + vite: 5.4.10(@types/node@22.7.9) '@vitest/pretty-format@2.1.3': dependencies: @@ -1510,7 +1510,7 @@ snapshots: callsites@3.1.0: {} - chai@5.1.1: + chai@5.1.2: dependencies: assertion-error: 2.0.1 check-error: 2.1.1 @@ -1579,9 +1579,9 @@ snapshots: meow: 12.1.1 split2: 4.2.0 - cosmiconfig-typescript-loader@5.1.0(@types/node@22.7.7)(cosmiconfig@9.0.0(typescript@5.6.3))(typescript@5.6.3): + cosmiconfig-typescript-loader@5.1.0(@types/node@22.7.9)(cosmiconfig@9.0.0(typescript@5.6.3))(typescript@5.6.3): dependencies: - '@types/node': 22.7.7 + '@types/node': 22.7.9 cosmiconfig: 9.0.0(typescript@5.6.3) jiti: 1.21.6 typescript: 5.6.3 @@ -1866,7 +1866,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.25.7 + '@babel/code-frame': 7.25.9 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -2012,12 +2012,12 @@ snapshots: unicorn-magic@0.1.0: {} - vite-node@2.1.3(@types/node@22.7.7): + vite-node@2.1.3(@types/node@22.7.9): dependencies: cac: 6.7.14 debug: 4.3.7 pathe: 1.1.2 - vite: 5.4.9(@types/node@22.7.7) + vite: 5.4.10(@types/node@22.7.9) transitivePeerDependencies: - '@types/node' - less @@ -2029,25 +2029,25 @@ snapshots: - supports-color - terser - vite@5.4.9(@types/node@22.7.7): + vite@5.4.10(@types/node@22.7.9): dependencies: esbuild: 0.21.5 postcss: 8.4.47 rollup: 4.24.0 optionalDependencies: - '@types/node': 22.7.7 + '@types/node': 22.7.9 fsevents: 2.3.3 - vitest@2.1.3(@types/node@22.7.7): + vitest@2.1.3(@types/node@22.7.9): dependencies: '@vitest/expect': 2.1.3 - '@vitest/mocker': 2.1.3(@vitest/spy@2.1.3)(vite@5.4.9(@types/node@22.7.7)) + '@vitest/mocker': 2.1.3(@vitest/spy@2.1.3)(vite@5.4.10(@types/node@22.7.9)) '@vitest/pretty-format': 2.1.3 '@vitest/runner': 2.1.3 '@vitest/snapshot': 2.1.3 '@vitest/spy': 2.1.3 '@vitest/utils': 2.1.3 - chai: 5.1.1 + chai: 5.1.2 debug: 4.3.7 magic-string: 0.30.12 pathe: 1.1.2 @@ -2056,11 +2056,11 @@ snapshots: tinyexec: 0.3.1 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.4.9(@types/node@22.7.7) - vite-node: 2.1.3(@types/node@22.7.7) + vite: 5.4.10(@types/node@22.7.9) + vite-node: 2.1.3(@types/node@22.7.9) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.7.7 + '@types/node': 22.7.9 transitivePeerDependencies: - less - lightningcss diff --git a/src/client/base.ts b/src/client/base.ts index b2c034e..f875de4 100644 --- a/src/client/base.ts +++ b/src/client/base.ts @@ -7,6 +7,8 @@ import type { CommandContext, ContextMenuCommand, EntryPointCommand, + ExtendedRC, + ExtendedRCLocations, ExtraProps, MenuCommandContext, RegisteredMiddlewares, @@ -365,7 +367,7 @@ export class BaseClient { } async loadCommands(dir?: string) { - dir ??= await this.getRC().then(x => x.commands); + dir ??= await this.getRC().then(x => x.locations.commands); if (dir && this.commands) { await this.commands.load(dir, this); this.logger.info('CommandHandler loaded'); @@ -373,7 +375,7 @@ export class BaseClient { } async loadComponents(dir?: string) { - dir ??= await this.getRC().then(x => x.components); + dir ??= await this.getRC().then(x => x.locations.components); if (dir && this.components) { await this.components.load(dir); this.logger.info('ComponentHandler loaded'); @@ -381,7 +383,7 @@ export class BaseClient { } async loadLangs(dir?: string) { - dir ??= await this.getRC().then(x => x.langs); + dir ??= await this.getRC().then(x => x.locations.langs); if (dir && this.langs) { await this.langs.load(dir); this.logger.info('LangsHandler loaded'); @@ -410,17 +412,22 @@ export class BaseClient { const { locations, debug, ...env } = seyfertConfig; + const locationsFullPaths: MakeRequired>, 'base' | 'output'> = { + base: locations.base, + output: locations.output, + }; + + for (const i in locations) { + const key = i as keyof typeof locations; + const location = locations[i as keyof typeof locations]; + if (!location || locationsFullPaths[key]) continue; + locationsFullPaths[key] = join(process.cwd(), locations.output, location); + } + const obj = { debug: !!debug, ...env, - templates: locations.templates ? join(process.cwd(), locations.base, locations.templates) : undefined, - langs: locations.langs ? join(process.cwd(), locations.output, locations.langs) : undefined, - events: - 'events' in locations && locations.events ? join(process.cwd(), locations.output, locations.events) : undefined, - components: locations.components ? join(process.cwd(), locations.output, locations.components) : undefined, - commands: locations.commands ? join(process.cwd(), locations.output, locations.commands) : undefined, - base: join(process.cwd(), locations.base), - output: join(process.cwd(), locations.output), + locations: locationsFullPaths, }; return obj; @@ -494,7 +501,7 @@ export interface StartOptions { token: string; } -interface RC extends Variables { +interface RC extends ExtendedRC { debug?: boolean; locations: { base: string; @@ -504,10 +511,7 @@ interface RC extends Variables { templates?: string; events?: string; components?: string; - }; -} - -export interface Variables { + } & ExtendedRCLocations; token: string; intents?: number; applicationId?: string; diff --git a/src/client/client.ts b/src/client/client.ts index 985db04..eb74f6b 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -55,7 +55,7 @@ export class Client extends BaseClient { } async loadEvents(dir?: string) { - dir ??= await this.getRC().then(x => x.events); + dir ??= await this.getRC().then(x => ('events' in x.locations ? x.locations.events : undefined)); if (dir && this.events) { await this.events.load(dir); this.logger.info('EventHandler loaded'); diff --git a/src/client/workerclient.ts b/src/client/workerclient.ts index c068c19..26ac2ca 100644 --- a/src/client/workerclient.ts +++ b/src/client/workerclient.ts @@ -168,7 +168,7 @@ export class WorkerClient extends BaseClient { } async loadEvents(dir?: string) { - dir ??= await this.getRC().then(x => x.events); + dir ??= await this.getRC().then(x => ('events' in x.locations ? x.locations.events : undefined)); if (dir && this.events) { await this.events.load(dir); this.logger.info('EventHandler loaded'); @@ -549,7 +549,7 @@ export class WorkerClient extends BaseClient { } as WorkerShardsConnected); await this.events?.runEvent('WORKER_SHARDS_CONNECTED', this, this.me, -1); } - if (!this.__handleGuilds!.length) { + if (!this.__handleGuilds?.length) { if ([...this.shards.values()].every(shard => shard.data.session_id)) { this.postMessage({ type: 'WORKER_READY', diff --git a/src/commands/applications/options.ts b/src/commands/applications/options.ts index 2c268f1..9ccbb93 100644 --- a/src/commands/applications/options.ts +++ b/src/commands/applications/options.ts @@ -15,6 +15,7 @@ import { ApplicationCommandOptionType, type ChannelType, } from '../../types'; +import type { LocalizationMap } from '../../types/payloads'; import type { CommandContext } from './chatcontext'; import type { DefaultLocale, MiddlewareContext, OKFunction, StopFunction } from './shared'; @@ -53,8 +54,15 @@ export interface SeyfertBaseChoiceableOption< } export type SeyfertChoice = - | { readonly name: string; readonly value: T } - | APIApplicationCommandOptionChoice; + | { + readonly name: string; + readonly value: T; + name_localizations?: LocalizationMap | null; + locales?: FlatObjectKeys; + } + | (APIApplicationCommandOptionChoice & { + locales?: FlatObjectKeys; + }); export type ChoiceableTypes = | ApplicationCommandOptionType.String diff --git a/src/commands/applications/shared.ts b/src/commands/applications/shared.ts index ef3a8ec..44bf125 100644 --- a/src/commands/applications/shared.ts +++ b/src/commands/applications/shared.ts @@ -15,6 +15,8 @@ export interface DefaultLocale {} export interface ExtendContext {} export interface ExtraProps {} export interface UsingClient extends BaseClient {} +export interface ExtendedRC {} +export interface ExtendedRCLocations {} export type ParseClient = T; export type ParseGlobalMiddlewares> = { [K in keyof T]: MetadataMiddleware; diff --git a/src/commands/handler.ts b/src/commands/handler.ts index 825643d..d0f964f 100644 --- a/src/commands/handler.ts +++ b/src/commands/handler.ts @@ -1,12 +1,13 @@ import { promises } from 'node:fs'; import { basename, dirname } from 'node:path'; import type { EntryPointCommand } from '.'; -import type { Logger, MakeRequired, NulleableCoalising, OmitInsert } from '../common'; +import type { Logger, NulleableCoalising, OmitInsert } from '../common'; import { BaseHandler, isCloudfareWorker } from '../common'; import { PermissionsBitField } from '../structures/extra/Permissions'; import { type APIApplicationCommandChannelOption, type APIApplicationCommandIntegerOption, + type APIApplicationCommandNumberOption, type APIApplicationCommandOption, type APIApplicationCommandStringOption, type APIApplicationCommandSubcommandGroupOption, @@ -59,20 +60,44 @@ export class CommandHandler extends BaseHandler { if (!(locales || cachedLocales)) return false; if (!locales && cachedLocales) return true; if (locales && !cachedLocales) return true; - if (locales && cachedLocales) { - const localesEntries = Object.entries(locales); - const cachedLocalesEntries = Object.entries(cachedLocales); - if (localesEntries.length !== cachedLocalesEntries.length) return true; + if (!(locales && cachedLocales)) return true; - for (const [key, value] of localesEntries) { - const cached = cachedLocalesEntries.find(x => x[0] === key); - if (!cached) return true; - if (value !== cached[1]) return true; - } + const localesEntries = Object.entries(locales); + const cachedLocalesEntries = Object.entries(cachedLocales); + if (localesEntries.length !== cachedLocalesEntries.length) return true; + + for (const [key, value] of localesEntries) { + const cached = cachedLocalesEntries.find(x => x[0] === key); + if (!cached) return true; + if (value !== cached[1]) return true; } + return false; } + protected shoudUploadChoices(option: APIApplicationCommandOption, cached: APIApplicationCommandOption) { + const optionChoiceable = option as + | APIApplicationCommandStringOption + | APIApplicationCommandIntegerOption + | APIApplicationCommandNumberOption; + const cachedChoiceable = cached as + | APIApplicationCommandStringOption + | APIApplicationCommandIntegerOption + | APIApplicationCommandNumberOption; + + if (!(optionChoiceable.choices?.length && cachedChoiceable.choices?.length)) return false; + if (optionChoiceable.choices.length !== cachedChoiceable.choices.length) return true; + + return !optionChoiceable.choices.every((choice, index) => { + const cachedChoice = cachedChoiceable.choices![index]; + return ( + choice.name === cachedChoice.name && + choice.value === cachedChoice.value && + !this.shouldUploadLocales(choice.name_localizations, cachedChoice.name_localizations) + ); + }); + } + protected shouldUploadOption(option: APIApplicationCommandOption, cached: APIApplicationCommandOption) { if (option.description !== cached.description) return true; if (option.type !== cached.type) return true; @@ -87,7 +112,9 @@ export class CommandHandler extends BaseHandler { case ApplicationCommandOptionType.String: return ( option.min_length !== (cached as APIApplicationCommandStringOption).min_length || - option.max_length !== (cached as APIApplicationCommandStringOption).max_length + option.max_length !== (cached as APIApplicationCommandStringOption).max_length || + !!option.autocomplete !== !!(cached as APIApplicationCommandStringOption).autocomplete || + this.shoudUploadChoices(option, cached) ); case ApplicationCommandOptionType.Channel: { @@ -126,7 +153,9 @@ export class CommandHandler extends BaseHandler { case ApplicationCommandOptionType.Number: return ( option.min_value !== (cached as APIApplicationCommandIntegerOption).min_value || - option.max_value !== (cached as APIApplicationCommandIntegerOption).max_value + option.max_value !== (cached as APIApplicationCommandIntegerOption).max_value || + !!option.autocomplete !== !!(cached as APIApplicationCommandIntegerOption).autocomplete || + this.shoudUploadChoices(option, cached) ); case ApplicationCommandOptionType.Attachment: case ApplicationCommandOptionType.Boolean: @@ -279,7 +308,7 @@ export class CommandHandler extends BaseHandler { } for (const fileSubCommand of fileSubCommands) { const subCommand = this.onSubCommand(fileSubCommand as HandleableSubCommand); - if (subCommand && subCommand instanceof SubCommand) { + if (subCommand instanceof SubCommand) { subCommand.__filePath = option; commandInstance.options!.push(subCommand); } else { @@ -313,15 +342,14 @@ export class CommandHandler extends BaseHandler { return command; } - if (command instanceof Command && command.__tGroups) { + if (command instanceof Command) { this.parseCommandLocales(command); for (const option of command.options ?? []) { if (option instanceof SubCommand) { this.parseSubCommandLocales(option); continue; } - // @ts-expect-error - if (option.locales) this.parseCommandOptionLocales(option); + this.parseCommandOptionLocales(option); } } if (command instanceof SubCommand) { @@ -332,8 +360,8 @@ export class CommandHandler extends BaseHandler { parseGlobalLocales(command: InstanceType) { if (command.__t) { - command.name_localizations = {}; - command.description_localizations = {}; + command.name_localizations ??= {}; + command.description_localizations ??= {}; for (const locale of Object.keys(this.client.langs!.values)) { const locales = this.client.langs!.aliases.find(x => x[0] === locale)?.[1] ?? []; if (Object.values(Locale).includes(locale)) locales.push(locale as LocaleString); @@ -355,31 +383,42 @@ export class CommandHandler extends BaseHandler { } } - parseCommandOptionLocales(option: MakeRequired) { - option.name_localizations = {}; - option.description_localizations = {}; + parseCommandOptionLocales(option: CommandOption) { + option.name_localizations ??= {}; + option.description_localizations ??= {}; for (const locale of Object.keys(this.client.langs!.values)) { const locales = this.client.langs!.aliases.find(x => x[0] === locale)?.[1] ?? []; if (Object.values(Locale).includes(locale)) locales.push(locale as LocaleString); - if (option.locales.name) { + if (option.locales?.name) { for (const i of locales) { - const valueName = this.client.langs!.getKey(locale, option.locales.name!); + const valueName = this.client.langs!.getKey(locale, option.locales.name); if (valueName) option.name_localizations[i] = valueName; } } - if (option.locales.description) { + if (option.locales?.description) { for (const i of locales) { - const valueKey = this.client.langs!.getKey(locale, option.locales.description!); + const valueKey = this.client.langs!.getKey(locale, option.locales.description); if (valueKey) option.description_localizations[i] = valueKey; } } + + if ('choices' in option && option.choices?.length) { + for (const c of option.choices) { + c.name_localizations ??= {}; + if (!c.locales) continue; + for (const i of locales) { + const valueKey = this.client.langs!.getKey(locale, c.locales); + if (valueKey) c.name_localizations[i] = valueKey; + } + } + } } } parseCommandLocales(command: Command) { - command.groups = {}; + command.groups ??= {}; for (const locale of Object.keys(this.client.langs!.values)) { const locales = this.client.langs!.aliases.find(x => x[0] === locale)?.[1] ?? []; if (Object.values(Locale).includes(locale)) locales.push(locale as LocaleString); @@ -417,8 +456,7 @@ export class CommandHandler extends BaseHandler { parseSubCommandLocales(command: SubCommand) { for (const i of command.options ?? []) { - // @ts-expect-error - if (i.locales) this.parseCommandOptionLocales(i); + this.parseCommandOptionLocales(i); } return command; }