meocord 4.2.0 → 4.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +322 -0
- package/THIRD_PARTY_NOTICES.md +14 -13
- package/dist/cjs/_shared/{controller.decorator-CRn9kWob.cjs → controller.decorator-U2NBWcoU.cjs} +416 -108
- package/dist/cjs/_shared/{providers-ChvMqnLd.cjs → providers-B4MOFBrW.cjs} +202 -50
- package/dist/cjs/_shared/{sharded-cooldown-store-BdAUTdYs.cjs → sharded-cooldown-store-HTUb3Ii_.cjs} +10 -7
- package/dist/cjs/_shared/{startup-roots-CQo8mSP8.cjs → startup-roots-lA5xkBFq.cjs} +228 -71
- package/dist/cjs/_shared/{translate-error-DhDVbT5M.cjs → translate-error-CbBHUu5P.cjs} +10 -5
- package/dist/cjs/common/index.cjs +3 -3
- package/dist/cjs/core/index.cjs +188 -169
- package/dist/cjs/decorator/index.cjs +52 -7
- package/dist/cjs/testing/index.cjs +1854 -311
- package/dist/cli.json +1 -1
- package/dist/esm/bin/generator.js +4 -5
- package/dist/esm/bin/helper/filter-generator.helper.js +4 -5
- package/dist/esm/bin/helper/guard-generator.helper.js +4 -5
- package/dist/esm/bin/helper/interceptor-generator.helper.js +4 -5
- package/dist/esm/bin/helper/observer-generator.helper.js +4 -5
- package/dist/esm/bin/helper/pipe-generator.helper.js +4 -5
- package/dist/esm/bin/helper/service-generator.helper.js +4 -5
- package/dist/esm/bin/meocord.js +84 -25
- package/dist/esm/build/load-config.pre-entry.js +13 -3
- package/dist/esm/build/rsbuild-config.js +16 -12
- package/dist/esm/build/typed-externals.js +36 -0
- package/dist/esm/common/cooldown-store.js +10 -2
- package/dist/esm/common/errors.js +25 -0
- package/dist/esm/common/meocord-text.js +11 -8
- package/dist/esm/common/response/call-order.js +9 -4
- package/dist/esm/common/response/presenter.js +33 -6
- package/dist/esm/common/response/response-state.js +89 -15
- package/dist/esm/common/route.js +11 -4
- package/dist/esm/common/sharded-cooldown-store.js +1 -1
- package/dist/esm/common/translator.js +52 -11
- package/dist/esm/core/command-registration.js +93 -24
- package/dist/esm/core/command-routes.js +2 -2
- package/dist/esm/core/cooldown-runner.js +29 -8
- package/dist/esm/core/dispatcher.js +9 -8
- package/dist/esm/core/fallback.js +20 -11
- package/dist/esm/core/filter-runner.js +2 -2
- package/dist/esm/core/guard-runner.js +16 -3
- package/dist/esm/core/handler-input.js +4 -3
- package/dist/esm/core/handler-pipeline.js +10 -4
- package/dist/esm/core/lifecycle-hooks.js +134 -47
- package/dist/esm/core/meocord-factory.js +59 -34
- package/dist/esm/core/meocord.app.js +116 -75
- package/dist/esm/core/message-help.js +32 -6
- package/dist/esm/core/observer-runner.js +2 -1
- package/dist/esm/core/providers.js +19 -4
- package/dist/esm/core/running-calls.js +43 -0
- package/dist/esm/core/shard-context.js +5 -6
- package/dist/esm/core/shard-manager.js +16 -10
- package/dist/esm/core/stage-scope.js +2 -1
- package/dist/esm/core/startup-roots.js +21 -1
- package/dist/esm/core/theme-resolvers.js +4 -1
- package/dist/esm/core/theme-scope.js +7 -2
- package/dist/esm/core/theme-validation.js +17 -10
- package/dist/esm/decorator/app.decorator.js +31 -0
- package/dist/esm/decorator/controller.decorator.js +56 -20
- package/dist/esm/decorator/cooldown.decorator.js +17 -0
- package/dist/esm/decorator/filter.decorator.js +2 -2
- package/dist/esm/decorator/guard.decorator.js +3 -2
- package/dist/esm/package.json.js +1 -1
- package/dist/esm/testing/catalog.js +20 -13
- package/dist/esm/testing/cooldown-store-suite.js +67 -5
- package/dist/esm/testing/discord-defaults.js +225 -30
- package/dist/esm/testing/meocord-testing-module.js +158 -44
- package/dist/esm/testing/mock-fn.js +107 -26
- package/dist/esm/testing/mock-interaction.js +1250 -182
- package/dist/esm/testing/snowflake.js +9 -2
- package/dist/esm/testing/strict-mocks.js +40 -17
- package/dist/esm/util/common.util.js +47 -19
- package/dist/esm/util/dev-runner.util.js +8 -8
- package/dist/esm/util/generator-cli.util.js +4 -5
- package/dist/esm/util/interaction.util.js +2 -2
- package/dist/esm/util/meocord-config-loader.util.js +10 -2
- package/dist/esm/util/meocord-config-validation.util.js +3 -5
- package/dist/esm/util/meocord-source-config.util.js +65 -20
- package/dist/esm/util/method-wrapper.util.js +16 -0
- package/dist/esm/util/platform.util.js +10 -10
- package/dist/esm/util/shard-process.util.js +4 -1
- package/dist/esm/util/sharding-mode.util.js +5 -7
- package/dist/esm/util/shared-state.util.js +21 -0
- package/dist/esm/util/tsconfig-paths.util.js +29 -0
- package/dist/esm/util/tsconfig.util.js +10 -10
- package/dist/esm/util/value.util.js +30 -2
- package/dist/types/common/index.d.cts +10 -7
- package/dist/types/common/index.d.ts +10 -7
- package/dist/types/core/index.d.cts +3 -2
- package/dist/types/core/index.d.ts +3 -2
- package/dist/types/decorator/index.d.cts +1 -0
- package/dist/types/decorator/index.d.ts +1 -0
- package/dist/types/{index-CdXsFgjE.d.ts → index-DKJclIi-.d.ts} +45 -21
- package/dist/types/{index-nn5p7OoX.d.cts → index-Dlf0ZZtS.d.cts} +45 -21
- package/dist/types/interface/index.d.cts +1 -1
- package/dist/types/interface/index.d.ts +1 -1
- package/dist/types/{route-BZgFoNeB.d.cts → route-Bh1U13yy.d.cts} +3 -2
- package/dist/types/{route-BZgFoNeB.d.ts → route-Bh1U13yy.d.ts} +3 -2
- package/dist/types/testing/index.d.cts +198 -62
- package/dist/types/testing/index.d.ts +198 -62
- package/dist/types/{theme-resolvers-UKr3-6Ys.d.cts → theme-resolvers-CyEz9pnv.d.cts} +1 -1
- package/dist/types/{theme-resolvers-BcOJVzR9.d.ts → theme-resolvers-DA204O-q.d.ts} +1 -1
- package/dist/types/{translator-DHMkkCpg.d.cts → translator-Bg7hwxDF.d.cts} +21 -8
- package/dist/types/{translator-BViWKtLJ.d.ts → translator-CeP4bCzp.d.ts} +21 -8
- package/package.json +2 -2
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ServiceIdentifier, Container } from 'inversify';
|
|
2
2
|
import { Client, Interaction, Message, MessageReaction, PartialMessageReaction, User, PartialUser, ClientEvents, Base, Locale, GuildMember, Role, GuildBasedChannel, Guild, APIMessageTopLevelComponent, JSONEncodable, APIEmbed, MessageFlagsResolvable, TextBasedChannel, BaseChannel, APIAuthorizingIntegrationOwnersMap, APIInteractionGuildMember, PermissionResolvable, APIUser, CacheType, CommandInteractionOptionResolver, ThreadChannel, AnyThreadChannel, ChatInputCommandInteraction, AutocompleteInteraction, MessageContextMenuCommandInteraction, UserContextMenuCommandInteraction, PrimaryEntryPointCommandInteraction, ContextMenuCommandInteraction, CommandInteraction, ButtonInteraction, StringSelectMenuInteraction, UserSelectMenuInteraction, RoleSelectMenuInteraction, MentionableSelectMenuInteraction, ChannelSelectMenuInteraction, MessageComponentInteraction, ModalSubmitInteraction, BaseInteraction, DMChannel, PartialGroupDMChannel, OmitPartialGroupDMChannel, Attachment, ModalSubmitFields, MessagePayload, InteractionReplyOptions, InteractionUpdateOptions, InteractionEditReplyOptions, MessageEditOptions, APIModalInteractionResponseCallbackData, ModalComponentData, InteractionDeferReplyOptions, InteractionDeferUpdateOptions, MessageResolvable, DiscordAPIError } from 'discord.js';
|
|
3
3
|
import { ReactionHandlerAction, CommandType } from '../enum/index.js';
|
|
4
|
-
import { a8 as Provider, P as ProviderToken } from '../index-
|
|
4
|
+
import { a8 as Provider, P as ProviderToken } from '../index-DKJclIi-.js';
|
|
5
5
|
import { CooldownStore, ExecutionContextType, ExecutionContext, CooldownScope, MetadataDecorator, ResponsePhase, ResponseCall } from '../common/index.js';
|
|
6
6
|
import { DispatchObserver, GuardInterface, InterceptorInterface, ExceptionFilter, ThemeOverride, ThemeResolvers, ThemeResolver, MessageCommandOptions, MessagePrefix, RootTheme, DeepReadonly, MeoCordTheme } from '../interface/index.js';
|
|
7
|
-
export { ao as ClassProvider, F as FactoryProvider, ap as ValueProvider } from '../index-
|
|
7
|
+
export { ao as ClassProvider, F as FactoryProvider, ap as ValueProvider } from '../index-DKJclIi-.js';
|
|
8
8
|
import { ThemeCache } from '../common/index.js';
|
|
9
9
|
import { Translator } from '../common/index.js';
|
|
10
10
|
import '@rsbuild/core';
|
|
@@ -161,7 +161,11 @@ interface DispatchedCall extends InvocationResult {
|
|
|
161
161
|
* @category Module
|
|
162
162
|
*/
|
|
163
163
|
interface EmitResult {
|
|
164
|
-
/**
|
|
164
|
+
/**
|
|
165
|
+
* How many `@On` and `@Once` handlers ran; a handler a guard denied by returning `false` is not counted. A guard
|
|
166
|
+
* that throws `GuardDeniedError` rejects `emit` instead, as the bot's event fallback, which skips the event, doesn't
|
|
167
|
+
* run in a testing module.
|
|
168
|
+
*/
|
|
165
169
|
ran: number;
|
|
166
170
|
}
|
|
167
171
|
/**
|
|
@@ -224,6 +228,8 @@ declare class TestingModule {
|
|
|
224
228
|
private resolving?;
|
|
225
229
|
private readying?;
|
|
226
230
|
private closing?;
|
|
231
|
+
/** The `onReady` hooks' pass, which `close()` waits for, less one whose `onReady` called `close()`. */
|
|
232
|
+
private readonly readyPass;
|
|
227
233
|
/**
|
|
228
234
|
* Resolves the module's `useFactory` providers, awaiting those that return a promise, in dependency
|
|
229
235
|
* order. `invoke`, `dispatch` and `emit` call it first; call it yourself before `get` resolves anything that
|
|
@@ -266,12 +272,21 @@ declare class TestingModule {
|
|
|
266
272
|
* It first gives up the theme read outside calls, if `init({ ready: true })` made it this module's;
|
|
267
273
|
* reads outside calls then return MeoCord's defaults until another module or app is ready.
|
|
268
274
|
*
|
|
275
|
+
* A stopped bot runs nothing more. Once `close()` is called, a module still runs what `dispatch`, `invoke` and `emit`
|
|
276
|
+
* are given, against services shut down, or shutting down, and warns once that it is closed, so a `close()` in the
|
|
277
|
+
* wrong place shows.
|
|
278
|
+
*
|
|
269
279
|
* The cooldown store and what it injects shut down last, in the same sequence as the bot's. When any of them has an
|
|
270
280
|
* `onShutdown`, the calls `invoke`, `dispatch` and `emit` have under way finish first, then the store operations
|
|
271
281
|
* they started, so the store's last writes still reach it. The module stops waiting for the whole sequence after
|
|
272
282
|
* its `shutdownTimeout`, 10 seconds unless set, and logs that it did. Give a test whose fake store never answers, or
|
|
273
283
|
* whose `onShutdown` never settles, a short `shutdownTimeout`.
|
|
274
284
|
*
|
|
285
|
+
* A `close()` while `init({ ready: true })` runs the `onReady` hooks waits for them first, within the same
|
|
286
|
+
* `shutdownTimeout`. An `onReady` still running once only the hooks' share of it is left is named in a warning, and
|
|
287
|
+
* its class is shut down all the same, as everything the module constructed is. One that calls `close()` itself isn't
|
|
288
|
+
* waited for.
|
|
289
|
+
*
|
|
275
290
|
* @returns Once every hook has run. Rejects with the error of a hook that failed, or an
|
|
276
291
|
* `AggregateError` naming each when several did.
|
|
277
292
|
*
|
|
@@ -287,6 +302,9 @@ declare class TestingModule {
|
|
|
287
302
|
* ```
|
|
288
303
|
*/
|
|
289
304
|
close(): Promise<void>;
|
|
305
|
+
private warnedClosed;
|
|
306
|
+
/** Warns once, after `close()`, that a call runs against services already shut down. */
|
|
307
|
+
private warnIfClosed;
|
|
290
308
|
private runReady;
|
|
291
309
|
/**
|
|
292
310
|
* The module's {@link ThemeCache}: the instance its classes inject, holding what `themeFor`, or
|
|
@@ -349,7 +367,9 @@ declare class TestingModule {
|
|
|
349
367
|
* @returns Whether the handler ran, and the error a filter handled, if any. Rejects with an error no
|
|
350
368
|
* filter handles, or with the error a filter throws: the built-in fallback, which answers such
|
|
351
369
|
* errors in the bot, does not run here. Rejects before running anything with an interaction or a
|
|
352
|
-
* message the handler's route does not match, naming both.
|
|
370
|
+
* message the handler's route does not match, naming both. Given fewer arguments than the handler
|
|
371
|
+
* declares, with a first that is neither an interaction nor a message, such as a reaction without its
|
|
372
|
+
* `ReactionEvent`, it rejects under `useStrictMocks()`, and otherwise warns once and runs the handler.
|
|
353
373
|
*
|
|
354
374
|
* @example
|
|
355
375
|
* ```ts
|
|
@@ -372,6 +392,13 @@ declare class TestingModule {
|
|
|
372
392
|
* ```
|
|
373
393
|
*/
|
|
374
394
|
invoke<C extends new (...args: any[]) => unknown, M extends HandlerName<C>>(controller: C, methodName: M, ...args: HandlerArgs<C, M>): Promise<InvocationResult>;
|
|
395
|
+
/** The handlers already warned about for being given fewer arguments than they take, so each is named once. */
|
|
396
|
+
private readonly warnedArgumentCounts;
|
|
397
|
+
/**
|
|
398
|
+
* Refuses under `useStrictMocks()`, or warns once otherwise, a call that gives a handler fewer arguments than it
|
|
399
|
+
* declares when `invoke` builds none for it, as for a reaction given without its `ReactionEvent`.
|
|
400
|
+
*/
|
|
401
|
+
private checkArgumentCount;
|
|
375
402
|
/** The calls under way, each removed once it settles: what `close()` lets finish before the cooldown store stops. */
|
|
376
403
|
private readonly calls;
|
|
377
404
|
/** Counts `call` as under way until it settles. */
|
|
@@ -422,15 +449,20 @@ declare class TestingModule {
|
|
|
422
449
|
action?: ReactionHandlerAction;
|
|
423
450
|
}): Promise<DispatchedCall>;
|
|
424
451
|
/**
|
|
425
|
-
* Emits a client event to the module's `@On` and `@Once` handlers, through the
|
|
426
|
-
*
|
|
427
|
-
* module's controllers, class providers and their dependencies all receive it. A
|
|
428
|
-
* handles only the first event, as it would on a client.
|
|
452
|
+
* Emits a client event to the module's `@On` and `@Once` handlers, through the pipeline the app runs
|
|
453
|
+
* them in up to its event fallback: the global guards of the module's `app`, then each handler's own.
|
|
454
|
+
* Handlers on the module's controllers, class providers and their dependencies all receive it. A
|
|
455
|
+
* `@Once` handler handles only the first event, as it would on a client.
|
|
456
|
+
*
|
|
457
|
+
* The bot's event fallback doesn't run here. On a bot, a guard's `GuardDeniedError` is logged and the
|
|
458
|
+
* event skipped, and a handler's `UserError` is logged and, when the event carries a message, answered
|
|
459
|
+
* as a reply to it; here both reject `emit` as any error does, so a test checks them with `rejects`.
|
|
429
460
|
*
|
|
430
461
|
* @param event - The client event, such as `'guildMemberAdd'`.
|
|
431
462
|
* @param args - The event's arguments, typed from discord.js's `ClientEvents`.
|
|
432
|
-
* @returns How many handlers ran. Rejects once every handler has settled if any threw
|
|
433
|
-
*
|
|
463
|
+
* @returns How many handlers ran. Rejects once every handler has settled if any threw, a guard's
|
|
464
|
+
* `GuardDeniedError` and a handler's `UserError` included: with that error when one handler failed,
|
|
465
|
+
* or an `AggregateError` of them when several did.
|
|
434
466
|
*
|
|
435
467
|
* @example
|
|
436
468
|
* ```ts
|
|
@@ -501,6 +533,10 @@ declare class TestingModuleBuilder {
|
|
|
501
533
|
/**
|
|
502
534
|
* Replaces a guard with a stub wherever it applies, globally or on a controller or handler.
|
|
503
535
|
*
|
|
536
|
+
* It stands in for the guard wherever the guard is bound, a provider of the same token included, and wins over an
|
|
537
|
+
* `overrideProvider` of it. The stub needs a `canActivate`, its own or its prototype's: `compile()` refuses one without
|
|
538
|
+
* it under `useStrictMocks()`, and otherwise warns.
|
|
539
|
+
*
|
|
504
540
|
* @param guard - The guard class to replace.
|
|
505
541
|
* @example
|
|
506
542
|
* ```ts
|
|
@@ -514,6 +550,10 @@ declare class TestingModuleBuilder {
|
|
|
514
550
|
* Replaces an interceptor with a stub wherever it applies, globally or on a controller or handler.
|
|
515
551
|
* The stub's `intercept` receives the context and `next`; call `next.handle()` to run the handler.
|
|
516
552
|
*
|
|
553
|
+
* It stands in for the interceptor wherever it is bound, a provider of the same token included, and wins over an
|
|
554
|
+
* `overrideProvider` of it. A stub without `intercept` is refused by `compile()` under `useStrictMocks()`, and
|
|
555
|
+
* otherwise warned about.
|
|
556
|
+
*
|
|
517
557
|
* @param interceptor - The interceptor class to replace.
|
|
518
558
|
* @example
|
|
519
559
|
* ```ts
|
|
@@ -527,6 +567,10 @@ declare class TestingModuleBuilder {
|
|
|
527
567
|
* Replaces an exception filter with a stub wherever it applies. The filter's `@Catch` still decides
|
|
528
568
|
* which errors reach the stub.
|
|
529
569
|
*
|
|
570
|
+
* It stands in for the filter wherever it is bound, a provider of the same token included, and wins over an
|
|
571
|
+
* `overrideProvider` of it. A stub without `catch` is refused by `compile()` under `useStrictMocks()`, and otherwise
|
|
572
|
+
* warned about.
|
|
573
|
+
*
|
|
530
574
|
* @param filter - The filter class to replace.
|
|
531
575
|
* @example
|
|
532
576
|
* ```ts
|
|
@@ -640,7 +684,8 @@ declare class MeoCordTestingModule {
|
|
|
640
684
|
* @param app - The class `@MeoCord` decorates.
|
|
641
685
|
* @param options - Providers that replace the app's by token, extra controllers, and observers.
|
|
642
686
|
* @returns The builder, whose `override*` methods still apply, for `compile()`.
|
|
643
|
-
* @throws TypeError when `app` is not a `@MeoCord` class.
|
|
687
|
+
* @throws TypeError when `app` is not a `@MeoCord` class. After {@link reportAllStartupErrors}, an app whose
|
|
688
|
+
* `@MeoCord` was refused throws the error it was refused for instead.
|
|
644
689
|
*
|
|
645
690
|
* @example
|
|
646
691
|
* ```ts
|
|
@@ -707,6 +752,22 @@ interface MockResult<T = unknown> {
|
|
|
707
752
|
/** What the call returned, or the error it threw. */
|
|
708
753
|
value: T;
|
|
709
754
|
}
|
|
755
|
+
/**
|
|
756
|
+
* One call's outcome once it has settled, as a mock function records it.
|
|
757
|
+
*
|
|
758
|
+
* It holds what a returned promise resolved or rejected with, or what the call returned or threw. Vitest's
|
|
759
|
+
* `toHaveResolved` and the rest read it.
|
|
760
|
+
*
|
|
761
|
+
* @group Testing
|
|
762
|
+
* @category Mocks
|
|
763
|
+
* @see {@link MockState}
|
|
764
|
+
*/
|
|
765
|
+
interface MockSettledResult<T = unknown> {
|
|
766
|
+
/** `'fulfilled'` once the call resolved or returned, `'rejected'` once it rejected or threw, `'incomplete'` before. */
|
|
767
|
+
type: 'fulfilled' | 'rejected' | 'incomplete';
|
|
768
|
+
/** What the call resolved, returned, rejected or threw with; `undefined` while it is incomplete. */
|
|
769
|
+
value: T | undefined;
|
|
770
|
+
}
|
|
710
771
|
/**
|
|
711
772
|
* What a mock function has recorded: each call's arguments, outcome and `this`, in order.
|
|
712
773
|
*
|
|
@@ -725,12 +786,19 @@ interface MockState<T extends (...args: any[]) => any = (...args: any[]) => any>
|
|
|
725
786
|
readonly instances: any[];
|
|
726
787
|
/** Arguments from the most recent call, or undefined if never called. */
|
|
727
788
|
readonly lastCall?: CallArgs<T>;
|
|
789
|
+
/** Each call's outcome once it has settled, in order. */
|
|
790
|
+
readonly settledResults: MockSettledResult<Awaited<CallResult<T>>>[];
|
|
791
|
+
/** When each call came, as a number that grows across meocord's own mocks. */
|
|
792
|
+
readonly invocationCallOrder: number[];
|
|
793
|
+
/** The `this` each call had, in order. */
|
|
794
|
+
readonly contexts: unknown[];
|
|
728
795
|
}
|
|
729
796
|
/**
|
|
730
797
|
* The mock API of a mock function: what it has recorded, and the methods that change what it does.
|
|
731
798
|
*
|
|
732
799
|
* Every mock from `meocord/testing` has it, with the names jest and Vitest use, so a test written for either runner
|
|
733
|
-
* reads the same.
|
|
800
|
+
* reads the same. The values it takes and records aren't checked against the function it mocks; see
|
|
801
|
+
* {@link MockedFunction}.
|
|
734
802
|
*
|
|
735
803
|
* @group Testing
|
|
736
804
|
* @category Mocks
|
|
@@ -772,9 +840,12 @@ interface MockInstance<T extends (...args: any[]) => any = (...args: any[]) => a
|
|
|
772
840
|
/**
|
|
773
841
|
* A mock function with the signature of `T`, and the mock API of {@link MockInstance}.
|
|
774
842
|
*
|
|
775
|
-
* It takes the place of jest's `MockedFunction<T>` and Vitest's `MockedFunction<T
|
|
776
|
-
* method of a mock with it
|
|
777
|
-
* a
|
|
843
|
+
* It takes the place of jest's `MockedFunction<T>` and Vitest's `MockedFunction<T>`, and the mock factories type each
|
|
844
|
+
* method of a mock with it. Calling the mock is checked against `T`. The values its mock API takes and records are
|
|
845
|
+
* not, for a plain function as for an overloaded one: `mockReturnValue` and `mockResolvedValue` take any value,
|
|
846
|
+
* `mockImplementation` takes any function, and each of `mock.calls`' arguments and each of `mock.results`' values reads
|
|
847
|
+
* as `any`. So a partial fake, such as `guild.members.fetch.mockResolvedValue({ id })`, type-checks, and so does a
|
|
848
|
+
* value of the wrong type.
|
|
778
849
|
*
|
|
779
850
|
* @group Testing
|
|
780
851
|
* @category Mocks
|
|
@@ -926,6 +997,14 @@ declare function resetAllMocks(): void;
|
|
|
926
997
|
* `mockReturnValue`, `mockResolvedValue`, `mockRejectedValue` and `mockImplementation` share one implementation, so
|
|
927
998
|
* the last one set wins. The `*Once` variants queue, and run first, in the order they were set.
|
|
928
999
|
*
|
|
1000
|
+
* It records what Vitest's `toHaveResolved` and `toHaveBeenCalledBefore` read as well. Its call order is counted
|
|
1001
|
+
* across meocord's own mocks, apart from the runner's, so compare the order of two of meocord's mocks, or of two of the
|
|
1002
|
+
* runner's, not one of each.
|
|
1003
|
+
*
|
|
1004
|
+
* A promise the implementation returns is handed back as one that settles the same way, not as the same object: test
|
|
1005
|
+
* it with `toEqual`, `toHaveReturnedWith` or by awaiting it, not with `toBe`. A property set on the given promise, such
|
|
1006
|
+
* as a `cancel` method, isn't carried over.
|
|
1007
|
+
*
|
|
929
1008
|
* @param impl - The implementation to run until another is set.
|
|
930
1009
|
*
|
|
931
1010
|
* @example
|
|
@@ -997,6 +1076,11 @@ type OutsideServer = {
|
|
|
997
1076
|
} | {
|
|
998
1077
|
channel: DMChannel | PartialGroupDMChannel;
|
|
999
1078
|
};
|
|
1079
|
+
type NotRaw<T> = T extends {
|
|
1080
|
+
member: unknown;
|
|
1081
|
+
} ? {
|
|
1082
|
+
member?: Exclude<MockProps<T>['member'], APIInteractionGuildMember>;
|
|
1083
|
+
} : unknown;
|
|
1000
1084
|
/**
|
|
1001
1085
|
* Creates a mock instance of a discord.js class, such as an interaction, keeping its prototype so `instanceof` holds.
|
|
1002
1086
|
*
|
|
@@ -1008,19 +1092,34 @@ type OutsideServer = {
|
|
|
1008
1092
|
* `user` of its own unless given, and its `locale` is `'en-US'`; without a `guildId` it is a DM, and with one its
|
|
1009
1093
|
* `member` is its user: for a `user` given, when the test gives the `guild`, the guild's cached member for that user,
|
|
1010
1094
|
* so a message and an interaction from one user in that server share it, and `memberPermissions` are that member's
|
|
1011
|
-
* permissions (`null` in a DM). A user is a person,
|
|
1012
|
-
*
|
|
1013
|
-
*
|
|
1014
|
-
* `channel` is a text channel of its server, the
|
|
1015
|
-
* `
|
|
1016
|
-
* it: a DM channel is no server, and a server's
|
|
1017
|
-
*
|
|
1018
|
-
* `
|
|
1019
|
-
*
|
|
1020
|
-
*
|
|
1021
|
-
*
|
|
1022
|
-
*
|
|
1023
|
-
*
|
|
1095
|
+
* permissions, with its channel's overwrites applied under `useStrictMocks()` (`null` in a DM). A user is a person,
|
|
1096
|
+
* `bot: false`, and a member has the server's @everyone role and the roles {@link createMockMember} gave it; with a
|
|
1097
|
+
* `guildId` but no `guild`, a server the bot isn't in, that @everyone role has the `guildId`. A DM sent to a member
|
|
1098
|
+
* goes through its user's `send()` and the user's one DM channel. Its `channel` is a text channel of its server, the
|
|
1099
|
+
* one its guild caches under `channelId` when it is read, or the user's DM channel. A `channel` given sets what the test leaves out of
|
|
1100
|
+
* `channelId`, `guildId` and `guild`, as discord.js reads them from it: a DM channel is no server, and a server's
|
|
1101
|
+
* channel its server; one in another server than the `guildId` given is refused, naming both. Under `useStrictMocks()`
|
|
1102
|
+
* a `message` given places it in the message's channel and server, a `guild` or a member's guild in that server, and a
|
|
1103
|
+
* `guildId` alone in a server the bot isn't in, with no `guild` or `channel` and a raw member for its user; a
|
|
1104
|
+
* `channel`, `guild` or `guildId` other than the place a test gave the message is refused, and a message whose place
|
|
1105
|
+
* `createMockMessage()` made moves to the one given. In default mode it stays where its own channel and guild fields
|
|
1106
|
+
* place it, and reading where it is warns once where strict mocks would place it otherwise. A select menu has picked
|
|
1107
|
+
* nothing unless given: its `values` are the ids of the `users` and `members`, `roles` or `channels` given, the
|
|
1108
|
+
* collections of what it picks, each empty unless given. Other data Discord always sends reads as Discord sends it,
|
|
1109
|
+
* such as `false` for a flag and `null` for what may be absent; what picks the handler, `commandName` or `customId`, is
|
|
1110
|
+
* the test's to give. Replies follow Discord's order, so a second `reply()` rejects, and {@link getResponse} reports
|
|
1111
|
+
* every answer the interaction got. Under `useStrictMocks()` an answer marks the interaction `replied` or `deferred`
|
|
1112
|
+
* once it resolves, as discord.js does after Discord takes it: an edit or follow-up made before then rejects with
|
|
1113
|
+
* `InteractionNotReplied`, and a second answer sent while the first is in flight is refused with Discord's 40060. In
|
|
1114
|
+
* default mode the mark is made at the call, with a warning where a bot would fail. Every method is a mock function, and one that returns a promise in discord.js
|
|
1115
|
+
* resolves. What the mock computes for itself, such as `memberPermissions` and `appPermissions`, calls none of them and
|
|
1116
|
+
* caches nothing, so a stub a test sets stays for its own code.
|
|
1117
|
+
*
|
|
1118
|
+
* An answer keeps that order whatever it is set to do: one a test gives a value with `mockResolvedValue` replies or
|
|
1119
|
+
* defers as a real one would, and one that rejects changes nothing. `fetchReply()` reads back what `reply()` or
|
|
1120
|
+
* `update()` sent; after `deleteReply()`, or before any answer, fetching, editing or deleting the original response
|
|
1121
|
+
* rejects with 10008 (Unknown Message), while follow-ups stay reachable by their id. Flags are read as discord.js
|
|
1122
|
+
* reads them, and its errors carry its codes, such as `InteractionAlreadyReplied`.
|
|
1024
1123
|
*
|
|
1025
1124
|
* Given `guild: null`, `member: null` or a DM channel, it is typed as an interaction that may come from anywhere, so
|
|
1026
1125
|
* its `guild` and `member` read as possibly `null`; otherwise as one from a server the bot is in.
|
|
@@ -1045,10 +1144,11 @@ type OutsideServer = {
|
|
|
1045
1144
|
* @see {@link createChatInputOptions}
|
|
1046
1145
|
* @see {@link https://meocord.dev/docs/4.2/mocks | Mocks}
|
|
1047
1146
|
*/
|
|
1048
|
-
declare function createMockInteraction<T extends object>(Class: InteractionClass<T>, props?: MockProps<T>): DeepMocked<T>;
|
|
1147
|
+
declare function createMockInteraction<T extends object>(Class: InteractionClass<T>, props?: MockProps<T> & NotRaw<T>): DeepMocked<T>;
|
|
1049
1148
|
/**
|
|
1050
1149
|
* Creates a mock interaction from a server the bot isn't in: one given a {@link createMockRawMember | raw member} and
|
|
1051
|
-
* that server's `guildId`, as a user-installed command run there
|
|
1150
|
+
* that server's `guildId`, with no `channel`, as discord.js caches none there, as a user-installed command run there
|
|
1151
|
+
* arrives.
|
|
1052
1152
|
*
|
|
1053
1153
|
* It is typed as discord.js types an interaction from such a server, `'raw'`: its `guild` is `null` and its `member`
|
|
1054
1154
|
* the raw member. Everything else is as {@link createMockInteraction} builds it.
|
|
@@ -1067,10 +1167,11 @@ declare function createMockInteraction<T extends object>(Class: InteractionClass
|
|
|
1067
1167
|
* @group Testing
|
|
1068
1168
|
* @category Mocks
|
|
1069
1169
|
*/
|
|
1070
|
-
declare function createMockInteraction<T extends object>(Class: InteractionClass<T>, props: Omit<MockProps<WithCache<T, 'raw'>>, 'options'> & {
|
|
1170
|
+
declare function createMockInteraction<T extends object>(Class: InteractionClass<T>, props: Omit<MockProps<WithCache<T, 'raw'>>, 'options' | 'channel'> & {
|
|
1071
1171
|
options?: object;
|
|
1072
1172
|
guildId: string;
|
|
1073
1173
|
member: APIInteractionGuildMember;
|
|
1174
|
+
channel?: never;
|
|
1074
1175
|
}): DeepMocked<WithCache<T, 'raw'>>;
|
|
1075
1176
|
/**
|
|
1076
1177
|
* Creates a mock interaction from outside a server: one given `guild: null`, `member: null` or a DM channel, as from a
|
|
@@ -1093,7 +1194,7 @@ declare function createMockInteraction<T extends object>(Class: InteractionClass
|
|
|
1093
1194
|
* @group Testing
|
|
1094
1195
|
* @category Mocks
|
|
1095
1196
|
*/
|
|
1096
|
-
declare function createMockInteraction<T extends object>(Class: InteractionClass<T>, props: MockProps<WithCache<T, CacheType>> & OutsideServer): DeepMocked<WithCache<T, CacheType>>;
|
|
1197
|
+
declare function createMockInteraction<T extends object>(Class: InteractionClass<T>, props: MockProps<WithCache<T, CacheType>> & OutsideServer & NotRaw<WithCache<T, CacheType>>): DeepMocked<WithCache<T, CacheType>>;
|
|
1097
1198
|
/**
|
|
1098
1199
|
* Creates a mock of any type, with no class needed, for service doubles and interfaces.
|
|
1099
1200
|
*
|
|
@@ -1152,7 +1253,7 @@ declare function createMock<T extends object>(props?: MockProps<T>): DeepMocked<
|
|
|
1152
1253
|
* @category Mocks
|
|
1153
1254
|
* @see {@link createMockInteraction}
|
|
1154
1255
|
*/
|
|
1155
|
-
declare
|
|
1256
|
+
declare function createMockUser(props?: MockProps<User>): DeepMocked<User>;
|
|
1156
1257
|
/**
|
|
1157
1258
|
* Creates a mock {@link Client}, with `users`, `channels`, `guilds` and `application.commands` ready to stub.
|
|
1158
1259
|
*
|
|
@@ -1202,7 +1303,8 @@ interface MockGuildOverrides {
|
|
|
1202
1303
|
channels?: readonly GuildBasedChannel[];
|
|
1203
1304
|
}
|
|
1204
1305
|
/**
|
|
1205
|
-
* Creates a mock {@link Guild}, with
|
|
1306
|
+
* Creates a mock {@link Guild}, with its `members`, `channels`, `roles`, `bans`, `emojis`, `stickers`, `scheduledEvents`,
|
|
1307
|
+
* `autoModerationRules` and `invites` managers ready to stub.
|
|
1206
1308
|
*
|
|
1207
1309
|
* Use it for the server a message or an interaction came from, with the members, roles and channels a handler looks
|
|
1208
1310
|
* up in it.
|
|
@@ -1212,9 +1314,11 @@ interface MockGuildOverrides {
|
|
|
1212
1314
|
*
|
|
1213
1315
|
* @remarks
|
|
1214
1316
|
* A manager's `fetch(id)` resolves to its cached item with that id, as discord.js looks there first, or to a new one it
|
|
1215
|
-
* caches under that id: a member or
|
|
1216
|
-
*
|
|
1217
|
-
*
|
|
1317
|
+
* caches under that id: a member, channel, emoji, sticker, scheduled event or AutoMod rule in this guild, a role with
|
|
1318
|
+
* that id, a ban, or an invite with that code. `members.fetch({ user: ids })` resolves to a collection of each of those
|
|
1319
|
+
* members, found or made the same way; `create()` and `edit()` resolve to a mock of its item, which `create()` caches
|
|
1320
|
+
* as discord.js does, but for an invite, made for the channel given and cached nowhere; a list fetch resolves to an
|
|
1321
|
+
* empty collection. Members, roles and channels given are put in
|
|
1218
1322
|
* their managers' caches, where dispatch looks first when it resolves a message's typed params; a member
|
|
1219
1323
|
* {@link createMockMember} made without a server is in this one. Its `roles.everyone` is the role given with the
|
|
1220
1324
|
* guild's id, or else an @everyone role of its own at position 0 with no permissions, in `roles.cache` as Discord has
|
|
@@ -1339,8 +1443,9 @@ interface MockMemberOverrides {
|
|
|
1339
1443
|
* highest, by position, then the lower id. `permissions` are computed as discord.js computes them: every permission for
|
|
1340
1444
|
* the server's owner, and otherwise its roles' permissions combined, @everyone's included, so a member with no roles has
|
|
1341
1445
|
* @everyone's alone. The member is put in its guild's member cache, so an interaction or a message from its user in that
|
|
1342
|
-
* server has it as its `member`, and `memberPermissions` are its permissions
|
|
1343
|
-
* user's `send()` and the user's
|
|
1446
|
+
* server has it as its `member`, and `memberPermissions` are its permissions, with the interaction's channel's
|
|
1447
|
+
* overwrites applied under `useStrictMocks()`. A DM sent to the member goes through its user's `send()` and the user's
|
|
1448
|
+
* one DM channel.
|
|
1344
1449
|
*
|
|
1345
1450
|
* @param overrides - The member's user, server, roles and nickname; see {@link MockMemberOverrides}.
|
|
1346
1451
|
* @returns The mock member.
|
|
@@ -1382,9 +1487,12 @@ interface MockMessageOverrides {
|
|
|
1382
1487
|
* on the message's client, and in a server its `member` is the guild's cached member for that user, or a new one.
|
|
1383
1488
|
*/
|
|
1384
1489
|
author?: User;
|
|
1385
|
-
/**
|
|
1490
|
+
/**
|
|
1491
|
+
* Its top-level components: action rows, or Components V2 such as a container. Builders or API JSON, held as
|
|
1492
|
+
* discord.js's classes, such as `ActionRow` and `ButtonComponent`, built from their JSON at the time of the call.
|
|
1493
|
+
*/
|
|
1386
1494
|
components?: readonly (APIMessageTopLevelComponent | JSONEncodable<APIMessageTopLevelComponent>)[];
|
|
1387
|
-
/** Its embeds. */
|
|
1495
|
+
/** Its embeds, builders or API JSON, held as discord.js's `Embed` built from their JSON at the time of the call. */
|
|
1388
1496
|
embeds?: readonly (APIEmbed | JSONEncodable<APIEmbed>)[];
|
|
1389
1497
|
/** Its flags: a number, flag names or a `MessageFlagsBitField`. */
|
|
1390
1498
|
flags?: MessageFlagsResolvable;
|
|
@@ -1412,12 +1520,14 @@ interface MockMessageOverrides {
|
|
|
1412
1520
|
* `@MessageHandler` does not skip it.
|
|
1413
1521
|
*
|
|
1414
1522
|
* @remarks
|
|
1415
|
-
* `delete()`, `edit()`, `reply()`, `react()`, `pin()` and `unpin()` throw once the message is deleted
|
|
1416
|
-
* and `reply()`
|
|
1417
|
-
*
|
|
1418
|
-
* one
|
|
1419
|
-
*
|
|
1420
|
-
*
|
|
1523
|
+
* `delete()`, `edit()`, `reply()`, `react()`, `pin()` and `unpin()` throw once the message is deleted. `edit()` changes
|
|
1524
|
+
* this message and resolves to it, and `reply()` resolves to the reply, sent in this message's channel and holding what
|
|
1525
|
+
* was sent, as a channel's `send()` does. Under `useStrictMocks()` a message the bot sends is its `client.user`'s, and
|
|
1526
|
+
* one sent in a DM is in that DM. Without overrides the message is empty, in a server, from a new person who is its
|
|
1527
|
+
* `member`; with `guild: null` it is a direct message. Give `author` to send several messages as one user, such as to
|
|
1528
|
+
* reach a per-user cooldown. An author given, and the users, roles and channels the content mentions, are cached as the
|
|
1529
|
+
* gateway delivers them. It is typed as discord.js emits a message, never in a group DM, so it fits `messageCreate` and
|
|
1530
|
+
* the other message events.
|
|
1421
1531
|
*
|
|
1422
1532
|
* @param overrides - The message's content, components and the rest; see {@link MockMessageOverrides}.
|
|
1423
1533
|
*
|
|
@@ -1482,6 +1592,10 @@ interface ChatInputOptions {
|
|
|
1482
1592
|
* A whole number is an Integer option and a fraction a Number one, so
|
|
1483
1593
|
* `getInteger()` reads only a whole number, and `getNumber()` reads either.
|
|
1484
1594
|
*
|
|
1595
|
+
* The `focused` option reads as Discord sends it, through `getFocused()`, `getFocused(true)` and `data` alike: a
|
|
1596
|
+
* string, `''` when no value is given, and marked `focused` in `data`. A number given for it is its digits under
|
|
1597
|
+
* `useStrictMocks()`; otherwise it stays the number, with a warning when read.
|
|
1598
|
+
*
|
|
1485
1599
|
* @typeParam Cached - `any` by default, to match `createMockInteraction(ChatInputCommandInteraction)`; pass it when the
|
|
1486
1600
|
* interaction under test is cache-pinned.
|
|
1487
1601
|
*
|
|
@@ -1508,17 +1622,36 @@ declare function createChatInputOptions<Cached extends CacheType = any>(opts?: C
|
|
|
1508
1622
|
*
|
|
1509
1623
|
* Call it once in the test runner's setup file. A message's `editable`, `deletable`, `pinnable`, `crosspostable`,
|
|
1510
1624
|
* `bulkDeletable`, `hasThread` and `partial`, a member's `manageable`, `kickable`, `bannable` and `moderatable`, a
|
|
1511
|
-
* role's `editable`, a channel's and a thread's `viewable`, `manageable`, `deletable`, `joinable` and the rest,
|
|
1512
|
-
* `partial` on users, channels and reactions then run discord.js's own getters against the mock,
|
|
1513
|
-
* is `null` when the channel caches no thread under the message's id.
|
|
1625
|
+
* role's `editable`, a channel's and a thread's `viewable`, `manageable`, `deletable`, `joinable` and the rest, a voice
|
|
1626
|
+
* channel's `full`, and `partial` on users, channels and reactions then run discord.js's own getters against the mock,
|
|
1627
|
+
* and `message.thread` is `null` when the channel caches no thread under the message's id. So do a message's
|
|
1628
|
+
* `editedAt`, a member's `presence`, a server's `verified` and `systemChannel` and a channel's `parent`, each `null` or
|
|
1629
|
+
* `false` until the test gives what it is computed from. A reaction's `me` is `false`, a message's
|
|
1630
|
+
* `mentions.repliedUser` and a modal's `message` are `null`, an interaction's `ephemeral` is `null` until `reply()` or
|
|
1631
|
+
* `deferReply()` decides it, and a reaction has a whole message of its own, so MeoCord's dispatcher fetches neither. No
|
|
1632
|
+
* placeholder warning is logged.
|
|
1514
1633
|
*
|
|
1515
1634
|
* @remarks
|
|
1516
|
-
* Those getters read what a server holds, so strict mocks also have it as Discord sends it: the bot's member is in
|
|
1517
|
-
*
|
|
1518
|
-
*
|
|
1519
|
-
*
|
|
1520
|
-
* a
|
|
1521
|
-
*
|
|
1635
|
+
* Those getters read what a server holds, so strict mocks also have it as Discord sends it: the bot's member is in the
|
|
1636
|
+
* server's member cache from the start, @everyone has the permissions Discord gives it in a new server, and a channel
|
|
1637
|
+
* or thread made without a server has one of its own, a thread with a text channel as its parent. A message has empty
|
|
1638
|
+
* `content`, a thread is neither archived nor locked, and a reaction's `count` is 1. A user, server or channel made
|
|
1639
|
+
* with a generated id was created when the mock was made, as a message is. An interaction's `memberPermissions` apply
|
|
1640
|
+
* its channel's overwrites, a thread's parent's for a thread, to its member's permissions. An interaction is in its
|
|
1641
|
+
* message's channel and server, a guild's or a member's server, or, given a `guildId` alone, a server the bot isn't in.
|
|
1642
|
+
* A message the bot sends is its `client.user`'s, and one it sends in a DM is in that DM. Give the bot's member a role
|
|
1643
|
+
* to let it do more, such as kick a member its role ranks above. A value the test sets on a mock wins over the computed
|
|
1644
|
+
* one. An interaction's answer that discord.js would refuse, such as a second `reply()` after one a test set with
|
|
1645
|
+
* `mockResolvedValue`, is refused too, where without it the mock runs it and warns. An answer marks the interaction
|
|
1646
|
+
* `replied`, `deferred` or `responded` once it resolves, as discord.js does, so code that doesn't await one fails as it
|
|
1647
|
+
* would on a bot, within one run of the test's code. The next major version (5.0) computes these values, and refuses
|
|
1648
|
+
* those answers, without the call.
|
|
1649
|
+
*
|
|
1650
|
+
* `invoke` also refuses a call that gives a handler fewer arguments than it declares where it builds none, such as a
|
|
1651
|
+
* reaction handler given its reaction without its `ReactionEvent`; without strict mocks, it warns once and calls it.
|
|
1652
|
+
*
|
|
1653
|
+
* `compile()` also refuses an `overrideGuard`, `overrideInterceptor` or `overrideFilter` stub without the stage's
|
|
1654
|
+
* method, `canActivate`, `intercept` or `catch`; without strict mocks, it warns and builds the module.
|
|
1522
1655
|
*
|
|
1523
1656
|
* @throws Error when a mock already exists, which was made without it.
|
|
1524
1657
|
*
|
|
@@ -1756,9 +1889,11 @@ declare function createModalFields(values: Record<string, string | string[] | At
|
|
|
1756
1889
|
*
|
|
1757
1890
|
* Use it in a test for a team that wants no fallback in production. It reports the messages a locale lacks, the
|
|
1758
1891
|
* messages the default catalog doesn't have, the plural forms a language needs but a plural lacks, such as `few` for
|
|
1759
|
-
* Russian,
|
|
1760
|
-
*
|
|
1761
|
-
*
|
|
1892
|
+
* Russian, a translation of another shape than the default's, a text for a plural or a plural for a text, and each
|
|
1893
|
+
* `{param}` a translation uses that the message it translates doesn't take. An empty translation, `''`, counts as
|
|
1894
|
+
* lacking, as the translator reads it as missing. It reads the catalogs' own strings, so it checks the params of a
|
|
1895
|
+
* catalog from a plain variable or a JSON file too, which the compiler can't. An object counts as a plural only when
|
|
1896
|
+
* its every key is a plural category, so a group with an `other` key is a group.
|
|
1762
1897
|
*
|
|
1763
1898
|
* @remarks
|
|
1764
1899
|
* MeoCord's own texts, a catalog's `meocord` group, fall back to English by design, so only a key MeoCord lacks, and
|
|
@@ -1827,8 +1962,9 @@ interface CooldownStoreSuiteFramework {
|
|
|
1827
1962
|
*
|
|
1828
1963
|
* @remarks
|
|
1829
1964
|
* The cases cover what a shared store most often gets wrong: a sliding window rather than fixed buckets,
|
|
1830
|
-
* `retryAfterMs` from the oldest
|
|
1831
|
-
* calls at the limit where exactly one may pass
|
|
1965
|
+
* `retryAfterMs` until a use frees up, from the oldest of the newest `uses` calls in the window, calls in the same
|
|
1966
|
+
* millisecond kept apart, concurrent calls at the limit where exactly one may pass, a batch refusal that names the
|
|
1967
|
+
* longest wait, and a release that frees only the call it gave back. They use real time, with windows short enough that the suite takes
|
|
1832
1968
|
* a few seconds and margins wide enough that a correct store passes when timers fire late, as on a busy CI runner,
|
|
1833
1969
|
* and each case counts under keys of its own. Each window is a whole number of milliseconds, as
|
|
1834
1970
|
* `@Cooldown` gives a store: it rounds its `seconds` to the millisecond.
|
|
@@ -2226,4 +2362,4 @@ declare function createMockTheme(...[overrides]: MockThemeArgs): DeepReadonly<Me
|
|
|
2226
2362
|
declare function withTheme<T>(theme: DeepReadonly<MeoCordTheme> | RootTheme, fn: () => T): T;
|
|
2227
2363
|
|
|
2228
2364
|
export { MeoCordTestingModule, Provider, ProviderToken, TestingModule, TestingModuleBuilder, clearAllMocks, createChatInputOptions, createDiscordError, createExecutionContext, createMock, createMockChannel, createMockClient, createMockFn, createMockGuild, createMockInteraction, createMockMember, createMockMessage, createMockRawMember, createMockTheme, createMockUser, createModalFields, expectCompleteCatalog, findRouteConflicts, getResponse, inspectHandler, isMockFunction, reportAllStartupErrors, resetAllMocks, resolveRoute, testCooldownStore, useMockFn, useStrictMocks, withTheme };
|
|
2229
|
-
export type { ChatInputOptions, ComponentCommandType, CooldownStoreSuiteFramework, DeepMocked, DispatchedCall, DispatchedHandler, EmitResult, ExecutionContextOptions, FromAppOptions, HandlerInspection, HandlerName, InspectHandlerOptions, InspectedCooldown, InspectedFilter, InspectedGuard, InspectedInterceptor, InvocationResult, MessageToResolve, Mock, MockFnFactory, MockGuildOverrides, MockInstance, MockMemberOverrides, MockMessageOverrides, MockProps, MockRawMemberOverrides, MockResult, MockState, MockedFunction, ResolvedRoute, ResponseReport, RouteConflict, RunnerMock, TestingModuleInitOptions, TestingModuleOptions };
|
|
2365
|
+
export type { ChatInputOptions, ComponentCommandType, CooldownStoreSuiteFramework, DeepMocked, DispatchedCall, DispatchedHandler, EmitResult, ExecutionContextOptions, FromAppOptions, HandlerInspection, HandlerName, InspectHandlerOptions, InspectedCooldown, InspectedFilter, InspectedGuard, InspectedInterceptor, InvocationResult, MessageToResolve, Mock, MockFnFactory, MockGuildOverrides, MockInstance, MockMemberOverrides, MockMessageOverrides, MockProps, MockRawMemberOverrides, MockResult, MockSettledResult, MockState, MockedFunction, ResolvedRoute, ResponseReport, RouteConflict, RunnerMock, TestingModuleInitOptions, TestingModuleOptions };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Locale, Interaction, Guild } from 'discord.js';
|
|
2
|
-
import { aq as MeoCordMessages } from './index-
|
|
2
|
+
import { aq as MeoCordMessages } from './index-Dlf0ZZtS.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The plural categories `Intl.PluralRules` selects between.
|
|
@@ -33,10 +33,13 @@ type IsPlural<T> = T extends object ? [Exclude<keyof T, PluralCategory>] extends
|
|
|
33
33
|
/**
|
|
34
34
|
* Every message key of a catalog: the dotted path to each message or plural.
|
|
35
35
|
*
|
|
36
|
+
* A key with a `.` in its own name is left out, as a lookup reads it as a path and never finds it; `createTranslator`
|
|
37
|
+
* warns about one. Nest it as a group.
|
|
38
|
+
*
|
|
36
39
|
* @group Types
|
|
37
40
|
*/
|
|
38
41
|
type MessageKey<C> = {
|
|
39
|
-
[K in keyof C & string]: C[K] extends string ? K : IsPlural<C[K]> extends true ? K : `${K}.${MessageKey<C[K]>}`;
|
|
42
|
+
[K in keyof C & string]: K extends `${string}.${string}` ? never : C[K] extends string ? K : IsPlural<C[K]> extends true ? K : `${K}.${MessageKey<C[K]>}`;
|
|
40
43
|
}[keyof C & string];
|
|
41
44
|
/**
|
|
42
45
|
* The keys whose message is a single string rather than plural forms, with or without `{params}`.
|
|
@@ -45,7 +48,7 @@ type MessageKey<C> = {
|
|
|
45
48
|
* @see {@link LocalizationKey}
|
|
46
49
|
*/
|
|
47
50
|
type StringMessageKey<C> = {
|
|
48
|
-
[K in keyof C & string]: C[K] extends string ? K : IsPlural<C[K]> extends true ? never : `${K}.${StringMessageKey<C[K]>}`;
|
|
51
|
+
[K in keyof C & string]: K extends `${string}.${string}` ? never : C[K] extends string ? K : IsPlural<C[K]> extends true ? never : `${K}.${StringMessageKey<C[K]>}`;
|
|
49
52
|
}[keyof C & string];
|
|
50
53
|
/**
|
|
51
54
|
* The keys {@link Translator.localizations} takes: a single string with no `{params}`, since Discord shows a command's
|
|
@@ -105,12 +108,17 @@ type Translate<C> = <K extends MessageKey<C>>(key: K, ...params: ParamsArgs<Mess
|
|
|
105
108
|
* Its messages may use only the `{params}` the default's take: `createTranslator` checks that for a catalog that keeps
|
|
106
109
|
* its text, and `expectCompleteCatalog` for any.
|
|
107
110
|
*
|
|
108
|
-
* A message it leaves out falls back to a related locale, then to the default.
|
|
111
|
+
* A message it leaves out falls back to a related locale, then to the default. Its `meocord` group translates MeoCord's
|
|
112
|
+
* own texts.
|
|
109
113
|
*
|
|
110
114
|
* @group Types
|
|
111
115
|
*/
|
|
112
|
-
type LocaleCatalog<C> = {
|
|
113
|
-
readonly
|
|
116
|
+
type LocaleCatalog<C> = LocaleMessages<C> & {
|
|
117
|
+
readonly meocord?: LocaleMessages<MeoCordMessages>;
|
|
118
|
+
};
|
|
119
|
+
/** Any part of a catalog, in a locale's own wording. */
|
|
120
|
+
type LocaleMessages<C> = {
|
|
121
|
+
readonly [K in keyof C]?: C[K] extends string ? string : IsPlural<C[K]> extends true ? PluralMessage : LocaleMessages<C[K]>;
|
|
114
122
|
};
|
|
115
123
|
/**
|
|
116
124
|
* What is wrong with a catalog's `meocord` group, one message per mistake: a key MeoCord has no text for, a group where
|
|
@@ -266,8 +274,13 @@ declare abstract class Translator<C = CatalogShape> {
|
|
|
266
274
|
/**
|
|
267
275
|
* A message in every locale other than the default whose own catalog has it, for a builder's
|
|
268
276
|
* `setNameLocalizations` or `setDescriptionLocalizations`. Locales without it are left out, so
|
|
269
|
-
* Discord falls back to the default name for them, and so
|
|
270
|
-
* `expectCompleteCatalog` reports.
|
|
277
|
+
* Discord falls back to the default name for them, and so are an empty translation and a translation
|
|
278
|
+
* with a `{param}`, which `expectCompleteCatalog` reports.
|
|
279
|
+
*
|
|
280
|
+
* Discord shows en-US users the en-GB value, en-GB users the en-US one, and es-419 users the es-ES one,
|
|
281
|
+
* when their own locale has none. So when the default is en-US, en-GB or es-419 and its partner is in
|
|
282
|
+
* the result, the default's own message is added under the default's key, and its users keep the default
|
|
283
|
+
* wording.
|
|
271
284
|
*
|
|
272
285
|
* @param key - A plain message key without `{params}`: Discord shows a name or description as written, and has no
|
|
273
286
|
* plural forms for it.
|