diff --git a/packages/reacord/helpers/is-object.ts b/packages/reacord/helpers/is-object.ts new file mode 100644 index 0000000..b6d975d --- /dev/null +++ b/packages/reacord/helpers/is-object.ts @@ -0,0 +1,7 @@ +export function isObject( + value: T, +): value is Exclude { + return typeof value === "object" && value !== null +} +type Primitive = string | number | boolean | undefined | null +type AnyFunction = (...args: any[]) => any diff --git a/packages/reacord/helpers/prune-null-values.ts b/packages/reacord/helpers/prune-null-values.ts deleted file mode 100644 index 5ce7dc3..0000000 --- a/packages/reacord/helpers/prune-null-values.ts +++ /dev/null @@ -1,15 +0,0 @@ -export function pruneNullishValues( - object: T, -): PruneNullishValues { - const result: any = {} - for (const [key, value] of Object.entries(object)) { - if (value != undefined) { - result[key] = value - } - } - return result -} - -type PruneNullishValues = { - [Key in keyof T]: NonNullable -} diff --git a/packages/reacord/helpers/prune-nullish-values.ts b/packages/reacord/helpers/prune-nullish-values.ts new file mode 100644 index 0000000..1bc28e2 --- /dev/null +++ b/packages/reacord/helpers/prune-nullish-values.ts @@ -0,0 +1,27 @@ +import { isObject } from "./is-object" + +export function pruneNullishValues(input: T): PruneNullishValues { + if (Array.isArray(input)) { + return input.filter(Boolean).map((item) => pruneNullishValues(item)) as any + } + + if (!isObject(input)) { + return input as any + } + + const result: any = {} + for (const [key, value] of Object.entries(input)) { + if (value != undefined) { + result[key] = isObject(value) ? pruneNullishValues(value) : value + } + } + return result +} + +type PruneNullishValues = Input extends ReadonlyArray + ? ReadonlyArray> + : Input extends object + ? { + [Key in keyof Input]: NonNullable + } + : Input diff --git a/packages/reacord/library/core/reacord-discord-js.ts b/packages/reacord/library/core/reacord-discord-js.ts index ee1d6dd..466689e 100644 --- a/packages/reacord/library/core/reacord-discord-js.ts +++ b/packages/reacord/library/core/reacord-discord-js.ts @@ -3,7 +3,7 @@ import * as Discord from "discord.js" import type { ReactNode } from "react" import type { Except } from "type-fest" import { pick } from "../../helpers/pick" -import { pruneNullishValues } from "../../helpers/prune-null-values" +import { pruneNullishValues } from "../../helpers/prune-nullish-values" import { raise } from "../../helpers/raise" import { toUpper } from "../../helpers/to-upper" import type { ComponentInteraction } from "../internal/interaction" diff --git a/packages/reacord/test/test-adapter.ts b/packages/reacord/test/test-adapter.ts index 132fbf2..4114089 100644 --- a/packages/reacord/test/test-adapter.ts +++ b/packages/reacord/test/test-adapter.ts @@ -7,6 +7,7 @@ import type { ReactNode } from "react" import { expect } from "vitest" import { logPretty } from "../helpers/log-pretty" import { omit } from "../helpers/omit" +import { pruneNullishValues } from "../helpers/prune-nullish-values" import { raise } from "../helpers/raise" import type { ChannelInfo, @@ -88,14 +89,21 @@ export class ReacordTester extends Reacord { } sampleMessages() { - return this.messages.map((message) => ({ - ...message.options, - actionRows: message.options.actionRows.map((row) => - row.map((component) => - omit(component, ["customId", "onClick", "onSelect", "onSelectValue"]), + return pruneNullishValues( + this.messages.map((message) => ({ + ...message.options, + actionRows: message.options.actionRows.map((row) => + row.map((component) => + omit(component, [ + "customId", + "onClick", + "onSelect", + "onSelectValue", + ]), + ), ), - ), - })) + })), + ) } findButtonByLabel(label: string) {