Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add type declarations #16

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export const version: string;

export * from './types/Base';

export * from './types/2048';
export * from './types/Connect4';
export * from './types/FastType';
export * from './types/FindEmoji';
export * from './types/Fishy';
export * from './types/Flood';
export * from './types/GuessThePokemon';
export * from './types/Hangman';
export * from './types/MatchPairs';
export * from './types/Minesweeper';
export * from './types/RockPaperScissors';
export * from './types/Slots';
export * from './types/Snake';
export * from './types/TicTacToe';
export * from './types/Trivia';
export * from './types/Wordle';
export * from './types/WouldYouRather';

export * from './types/Emojify';
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "4.2.0",
"description": "Discord Gamecord is a powerful npm package with a collection of minigames for your discord bot",
"main": "index.js",
"types": "index.d.ts",
"scripts": {
"test": "cd test && node ."
},
Expand Down Expand Up @@ -30,4 +31,5 @@
"directories": {
"src": "src"
}
}
}

54 changes: 54 additions & 0 deletions types/2048.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {
AttachmentBuilder,
InteractionEditReplyOptions,
Message,
MessageEditOptions,
MessagePayload,
User,
} from 'discord.js';
import { EventEmitter } from 'node:events';
import { BaseConstructorOptions, ButtonStyle, DeepRequired, MessageType, Position } from './Base';

export interface TwoZeroFourEightConstructorOptions<IsSlashGame extends boolean>
extends BaseConstructorOptions<IsSlashGame> {
embed?: {
title?: string;
color?: string;
};
emojis?: {
up?: string;
down?: string;
left?: string;
right?: string;
};
timeoutTime?: number;
buttonStyle?: ButtonStyle;
}

export class TwoZeroFourEight<IsSlashGame extends boolean = false> extends EventEmitter {
options: DeepRequired<TwoZeroFourEightConstructorOptions<IsSlashGame>>;
message: MessageType<IsSlashGame>;
gameBoard: string[];
mergedPos: Position[];
length: number;
score: number;

on(eventName: 'gameOver', listener: (result: { result: 'win' | 'lose'; player: User; score: number }) => void): this;
once(...args: Parameters<this['on']>): this;

constructor(options: TwoZeroFourEightConstructorOptions<IsSlashGame>);

sendMessage(
content: string | MessagePayload | (IsSlashGame extends true ? InteractionEditReplyOptions : MessageEditOptions)
): Promise<Message>;
getBoardImage(): Promise<AttachmentBuilder>; // There is literally no reason to make this asynchronous
startGame(): Promise<void>;
placeRandomTile(): void;
handleButtons(msg: Message): void;
gameOver(msg: Message): Promise<Message>;
isGameOver(): boolean;
shiftVertical(dir: 'up' | 'down'): boolean;
shiftHorizontal(dir: 'left' | 'right'): boolean;
isInsideBlock(pos: Position): boolean;
shift(pos: Position, dir: 'up' | 'down' | 'left' | 'right'): boolean;
}
31 changes: 31 additions & 0 deletions types/Approve.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Message, User } from 'discord.js';
import { EventEmitter } from 'node:events';
import { DeepRequired, MessageType } from './Base';

export interface ApproveConstructorOptions {
embed?: {
requestTitle?: string;
requestColor?: string;
rejectTitle?: string;
rejectColor?: string;
};
buttons?: {
accept?: string;
reject?: string;
};
reqTimeoutTime?: number;
mentionUser?: boolean;
requestMessage?: string;
rejectMessage?: string;
reqTimeoutMessage?: string;
}

export class Approve extends EventEmitter {
options: DeepRequired<ApproveConstructorOptions>;
message: MessageType<boolean>;
opponent: User;

constructor(options: ApproveConstructorOptions);
approve(): Promise<Message | false>;
formatTurnMessage<Options extends object>(options: Options, contentMsg: keyof Options): string;
}
21 changes: 21 additions & 0 deletions types/Base.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ChatInputCommandInteraction, Message } from 'discord.js';

// Helper type
export type DeepRequired<T> = T extends object ? { [K in keyof T]-?: DeepRequired<T[K]> } : T;
export type Tuple<N extends number, T> = N extends N ? (number extends N ? T[] : _TupleOf<T, N, []>) : never;
type _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N ? R : _TupleOf<T, N, [T, ...R]>;

export type ButtonStyle = 'PRIMARY' | 'SECONDARY' | 'SUCCESS' | 'DANGER';

export interface Position {
x: number;
y: number;
}

export type MessageType<IsSlashGame extends boolean> = IsSlashGame extends true ? ChatInputCommandInteraction : Message;

export interface BaseConstructorOptions<IsSlashGame extends boolean> {
isSlashGame?: IsSlashGame;
message: MessageType<IsSlashGame>;
playerOnlyMessage: string | false; // Wouldn't string | null be more natural?
}
54 changes: 54 additions & 0 deletions types/Connect4.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { InteractionEditReplyOptions, Message, MessageEditOptions, MessagePayload, User } from 'discord.js';
import { Approve, ApproveConstructorOptions } from './Approve';
import { BaseConstructorOptions, ButtonStyle, DeepRequired, MessageType } from './Base';

export interface Connect4ConstructorOptions<IsSlashGame extends boolean> extends BaseConstructorOptions<IsSlashGame> {
opponent: User;
embed?: {
title?: string;
statusTitle?: string;
color?: string;
};
emojis?: {
board?: string;
player1?: string;
player2?: string;
};
timeoutTime?: number;
buttonStyle?: ButtonStyle;
turnMessage?: string;
winMessage?: string;
tieMessage?: string;
timeoutMessage?: string;
requestMessage?: string;
rejectMessage?: string;
}

export class Connect4<IsSlashGame extends boolean = false> extends Approve {
options: DeepRequired<ApproveConstructorOptions & Connect4ConstructorOptions<IsSlashGame>>;
message: MessageType<IsSlashGame>;
opponent: User;
player1Turn: boolean;
gameBoard: string[];

on(
eventName: 'gameOver',
listener: (result: { result: 'win' | 'tie' | 'timeout'; player: User; opponent: User }) => void
): this;
once(...args: Parameters<this['on']>): this;

constructor(options: ApproveConstructorOptions & Connect4ConstructorOptions<IsSlashGame>);

getBoardContent(): string;
sendMessage(
content: string | MessagePayload | (IsSlashGame extends true ? InteractionEditReplyOptions : MessageEditOptions)
): Promise<Message>;
startGame(): Promise<void>;
connect4Game(msg: Message): Promise<void>;
handleButtons(msg: Message): void;
gameOver(msg: Message, result: 'win' | 'tie' | 'timeout'): Promise<Message>;
getPlayerEmoji(): string;
getTurnMessage(msg?: string): string;
isBoardFull(): boolean;
foundCheck(blockX: number, blockY: number): boolean;
}
26 changes: 26 additions & 0 deletions types/Emojify.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
type CharsKeys =
| '0'
| '1'
| '2'
| '3'
| '4'
| '5'
| '6'
| '7'
| '8'
| '9'
| '#'
| '*'
| '?'
| '!'
| '+'
| '-'
| '×'
| '$'
| '/'
| ' ';

export const Emojify: {
(content: string): string;
chars: Record<CharsKeys, string>;
};
36 changes: 36 additions & 0 deletions types/FastType.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { InteractionEditReplyOptions, Message, MessageEditOptions, MessagePayload, User } from 'discord.js';
import { EventEmitter } from 'node:events';
import { BaseConstructorOptions, DeepRequired, MessageType } from './Base';

export interface FastTypeConstructorOptions<IsSlashGame extends boolean> extends BaseConstructorOptions<IsSlashGame> {
embed?: {
title?: string;
color?: string;
description?: string;
};
sentense?: string;
timeoutTime?: number;
winMessage?: string;
loseMessage?: string;
}

export class FastType<IsSlashGame extends boolean = false> extends EventEmitter {
options: DeepRequired<FastTypeConstructorOptions<IsSlashGame>>;
message: MessageType<IsSlashGame>;
timeTaken: number | null;
wpm: number;

on(
eventName: 'gameOver',
listener: (result: { result: 'win' | 'lose'; player: User; timeTaken: number; wpm: number }) => void
): this;
once(...args: Parameters<this['on']>): this;

constructor(options: FastTypeConstructorOptions<IsSlashGame>);

sendMessage(
content: string | MessagePayload | (IsSlashGame extends true ? InteractionEditReplyOptions : MessageEditOptions)
): Promise<Message>;
startGame(): Promise<void>;
gameOver(msg: Message, result: boolean): Promise<Message>;
}
55 changes: 55 additions & 0 deletions types/FindEmoji.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {
ActionRowBuilder,
ButtonBuilder,
InteractionEditReplyOptions,
Message,
MessageEditOptions,
MessagePayload,
User,
} from 'discord.js';
import { EventEmitter } from 'node:events';
import { BaseConstructorOptions, ButtonStyle, DeepRequired, MessageType } from './Base';

export interface FindEmojiConstructorOptions<IsSlashGame extends boolean> extends BaseConstructorOptions<IsSlashGame> {
embed?: {
title?: string;
color?: string;
description?: string;
findDescription?: string;
};
timeoutTime?: number;
hideEmojiTime?: number;
buttonStyle?: ButtonStyle;
emojis?: string[];
winMessage?: string;
loseMessage?: string;
timeoutMessage?: string;
}

export class FindEmoji<IsSlashGame extends boolean = false> extends EventEmitter {
options: DeepRequired<FindEmojiConstructorOptions<IsSlashGame>>;
message: MessageType<IsSlashGame>;
emojis: string[];
selected: string | null;
emoji: string | null;

on(
eventName: 'gameOver',
listener: (result: {
result: 'win' | 'lose' | 'timeout';
player: User;
selectedEmoji: string | null;
correctEmoji: string | null;
}) => void
): this;
once(...args: Parameters<this['on']>): this;

constructor(options: FindEmojiConstructorOptions<IsSlashGame>);

sendMessage(
content: string | MessagePayload | (IsSlashGame extends true ? InteractionEditReplyOptions : MessageEditOptions)
): Promise<Message>;
startGame(): Promise<void>;
gameOver(msg: Message, result: boolean): Promise<Message>;
getComponents(showEmoji: boolean): ActionRowBuilder<ButtonBuilder>[];
}
55 changes: 55 additions & 0 deletions types/Fishy.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { InteractionEditReplyOptions, Message, MessageEditOptions, MessagePayload, Snowflake, User } from 'discord.js';
import { EventEmitter } from 'node:events';
import { BaseConstructorOptions, DeepRequired, MessageType } from './Base';

export interface Fish {
emoji: string;
price: number;
}

export type Fishes = Record<'junk' | 'common' | 'uncommon' | 'rare', Fish>;

// XXX: Someone suggest a better name, this name has a lot of ambiguity
export interface Player {
id: Snowflake;
balance: number;
fishes: object;
}

export interface FishyConstructorOptions<IsSlashGame extends boolean> extends BaseConstructorOptions<IsSlashGame> {
embed?: {
title?: string;
color?: string;
};
player?: Partial<Player>;
fishes?: Partial<Fishes>;
fishyRodPrice?: number;
catchMessage?: string;
sellMessage?: string;
noBalanceMessage?: string;
invalidTypeMessage?: string;
invalidAmountMessage?: string;
noItemMesaage?: string;
}

export class Fishy<IsSlashGame extends boolean = false> extends EventEmitter {
options: DeepRequired<FishyConstructorOptions<IsSlashGame>>;
message: MessageType<IsSlashGame>;
player: Player;
fishes: Fishes;

on(
eventName: 'catchFish' | 'sellFish',
listener: (fishy: { player: User; fishType: keyof Fishes; fish: Fish }) => void
): this;
once(...args: Parameters<this['on']>): this;

constructor(options: FishyConstructorOptions<IsSlashGame>);

sendMessage(
content: string | MessagePayload | (IsSlashGame extends true ? InteractionEditReplyOptions : MessageEditOptions)
): Promise<Message>;
catchFish(): Promise<Message>;
sellFish(type: string, amount: number): Promise<Message>;
fishyInventory(): Promise<Message>;
}
Loading