all repos — kitten @ 76d8fb0bdcaf8f5f8404dd930691e52756e68f01

pkgs/core/src/options.ts (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
import {
  type AutocompleteInteraction,
  type User,
  type Attachment,
  type Role,
  type GuildBasedChannel,
  type ApplicationCommandOptionChoiceData,
} from "discord.js";

export const OPTION_TYPES = {
  subcommand: 1,
  subcommandGroup: 2,
  string: 3,
  integer: 4,
  boolean: 5,
  user: 6,
  channel: 7,
  role: 8,
  mentionable: 9,
  number: 10,
  attachment: 11,
} as const;
type OptionType = keyof typeof OPTION_TYPES;

export interface Option<T, Req extends boolean> {
  type: OptionType;
  description: string;
  required: Req;
  autocomplete?: (
    interaction: AutocompleteInteraction,
    value: T,
  ) => Promise<ApplicationCommandOptionChoiceData[]> | ApplicationCommandOptionChoiceData[];
  __type?: T;
}

export type InferOptions<O> = {
  [K in keyof O]: O[K] extends Option<infer Type, infer Required>
    ? Required extends true
      ? Type
      : Type | undefined
    : never;
};

export type AutocompleteFn<T> = (
  interaction: AutocompleteInteraction,
  value: T,
) => Promise<ApplicationCommandOptionChoiceData[]> | ApplicationCommandOptionChoiceData[];

const createOption = <T>(type: OptionType) => {
  return ((description: string, config?: any): Option<T, any> => ({
    type,
    description,
    required: config?.required ?? false,
    autocomplete: config?.autocomplete,
  })) as {
    (
      description: string,
      config: { required: true; autocomplete?: AutocompleteFn<T> },
    ): Option<T, true>;
    (
      description: string,
      config?: { required?: false; autocomplete?: AutocompleteFn<T> },
    ): Option<T, false>;
  };
};

export const option = {
  string: createOption<string>("string"),
  integer: createOption<number>("integer"),
  number: createOption<number>("number"),
  boolean: createOption<boolean>("boolean"),
  user: createOption<User>("user"),
  channel: createOption<GuildBasedChannel>("channel"),
  role: createOption<Role>("role"),
  mentionable: createOption<User | Role | any>("mentionable"),
  attachment: createOption<Attachment>("attachment"),
};