@ovencord/formatters 0.6.1
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/LICENSE +191 -0
- package/README.md +86 -0
- package/package.json +58 -0
- package/src/escapers.ts +359 -0
- package/src/formatters.ts +827 -0
- package/src/index.ts +10 -0
|
@@ -0,0 +1,827 @@
|
|
|
1
|
+
import type { Snowflake } from 'discord-api-types/globals';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wraps the content inside a code block with no language.
|
|
5
|
+
*
|
|
6
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
7
|
+
* @param content - The content to wrap
|
|
8
|
+
*/
|
|
9
|
+
export function codeBlock<Content extends string>(content: Content): `\`\`\`\n${Content}\n\`\`\``;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Wraps the content inside a code block with the specified language.
|
|
13
|
+
*
|
|
14
|
+
* @typeParam Language - This is inferred by the supplied language
|
|
15
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
16
|
+
* @param language - The language for the code block
|
|
17
|
+
* @param content - The content to wrap
|
|
18
|
+
*/
|
|
19
|
+
export function codeBlock<Language extends string, Content extends string>(
|
|
20
|
+
language: Language,
|
|
21
|
+
content: Content,
|
|
22
|
+
): `\`\`\`${Language}\n${Content}\n\`\`\``;
|
|
23
|
+
|
|
24
|
+
export function codeBlock(language: string, content?: string): string {
|
|
25
|
+
return content === undefined ? `\`\`\`\n${language}\n\`\`\`` : `\`\`\`${language}\n${content}\n\`\`\``;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Wraps the content inside \`backticks\` which formats it as inline code.
|
|
30
|
+
*
|
|
31
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
32
|
+
* @param content - The content to wrap
|
|
33
|
+
*/
|
|
34
|
+
export function inlineCode<Content extends string>(content: Content): `\`${Content}\`` {
|
|
35
|
+
return `\`${content}\``;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Formats the content into italic text.
|
|
40
|
+
*
|
|
41
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
42
|
+
* @param content - The content to wrap
|
|
43
|
+
*/
|
|
44
|
+
export function italic<Content extends string>(content: Content): `_${Content}_` {
|
|
45
|
+
return `_${content}_`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Formats the content into bold text.
|
|
50
|
+
*
|
|
51
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
52
|
+
* @param content - The content to wrap
|
|
53
|
+
*/
|
|
54
|
+
export function bold<Content extends string>(content: Content): `**${Content}**` {
|
|
55
|
+
return `**${content}**`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Formats the content into underlined text.
|
|
60
|
+
*
|
|
61
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
62
|
+
* @param content - The content to wrap
|
|
63
|
+
*/
|
|
64
|
+
export function underline<Content extends string>(content: Content): `__${Content}__` {
|
|
65
|
+
return `__${content}__`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Formats the content into strike-through text.
|
|
70
|
+
*
|
|
71
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
72
|
+
* @param content - The content to wrap
|
|
73
|
+
*/
|
|
74
|
+
export function strikethrough<Content extends string>(content: Content): `~~${Content}~~` {
|
|
75
|
+
return `~~${content}~~`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Formats the content into a quote.
|
|
80
|
+
*
|
|
81
|
+
* @remarks This needs to be at the start of the line for Discord to format it.
|
|
82
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
83
|
+
* @param content - The content to wrap
|
|
84
|
+
*/
|
|
85
|
+
export function quote<Content extends string>(content: Content): `> ${Content}` {
|
|
86
|
+
return `> ${content}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Formats the content into a block quote.
|
|
91
|
+
*
|
|
92
|
+
* @remarks This needs to be at the start of the line for Discord to format it.
|
|
93
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
94
|
+
* @param content - The content to wrap
|
|
95
|
+
*/
|
|
96
|
+
export function blockQuote<Content extends string>(content: Content): `>>> ${Content}` {
|
|
97
|
+
return `>>> ${content}`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Wraps the URL into `<>` which stops it from embedding.
|
|
102
|
+
*
|
|
103
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
104
|
+
* @param url - The URL to wrap
|
|
105
|
+
*/
|
|
106
|
+
export function hideLinkEmbed<Content extends string>(url: Content): `<${Content}>`;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Wraps the URL into `<>` which stops it from embedding.
|
|
110
|
+
*
|
|
111
|
+
* @param url - The URL to wrap
|
|
112
|
+
*/
|
|
113
|
+
export function hideLinkEmbed(url: URL): `<${string}>`;
|
|
114
|
+
|
|
115
|
+
export function hideLinkEmbed(url: URL | string) {
|
|
116
|
+
return `<${url}>`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Formats the content and the URL into a masked URL.
|
|
121
|
+
*
|
|
122
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
123
|
+
* @param content - The content to display
|
|
124
|
+
* @param url - The URL the content links to
|
|
125
|
+
*/
|
|
126
|
+
export function hyperlink<Content extends string>(content: Content, url: URL): `[${Content}](${string})`;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Formats the content and the URL into a masked URL.
|
|
130
|
+
*
|
|
131
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
132
|
+
* @typeParam Url - This is inferred by the supplied URL
|
|
133
|
+
* @param content - The content to display
|
|
134
|
+
* @param url - The URL the content links to
|
|
135
|
+
*/
|
|
136
|
+
export function hyperlink<Content extends string, Url extends string>(
|
|
137
|
+
content: Content,
|
|
138
|
+
url: Url,
|
|
139
|
+
): `[${Content}](${Url})`;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Formats the content and the URL into a masked URL with a custom tooltip.
|
|
143
|
+
*
|
|
144
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
145
|
+
* @typeParam Title - This is inferred by the supplied title
|
|
146
|
+
* @param content - The content to display
|
|
147
|
+
* @param url - The URL the content links to
|
|
148
|
+
* @param title - The title shown when hovering on the masked link
|
|
149
|
+
*/
|
|
150
|
+
export function hyperlink<Content extends string, Title extends string>(
|
|
151
|
+
content: Content,
|
|
152
|
+
url: URL,
|
|
153
|
+
title: Title,
|
|
154
|
+
): `[${Content}](${string} "${Title}")`;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Formats the content and the URL into a masked URL with a custom tooltip.
|
|
158
|
+
*
|
|
159
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
160
|
+
* @typeParam Url - This is inferred by the supplied URL
|
|
161
|
+
* @typeParam Title - This is inferred by the supplied title
|
|
162
|
+
* @param content - The content to display
|
|
163
|
+
* @param url - The URL the content links to
|
|
164
|
+
* @param title - The title shown when hovering on the masked link
|
|
165
|
+
*/
|
|
166
|
+
export function hyperlink<Content extends string, Url extends string, Title extends string>(
|
|
167
|
+
content: Content,
|
|
168
|
+
url: Url,
|
|
169
|
+
title: Title,
|
|
170
|
+
): `[${Content}](${Url} "${Title}")`;
|
|
171
|
+
|
|
172
|
+
export function hyperlink(content: string, url: URL | string, title?: string) {
|
|
173
|
+
return title ? `[${content}](${url} "${title}")` : `[${content}](${url})`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Formats the content into a spoiler.
|
|
178
|
+
*
|
|
179
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
180
|
+
* @param content - The content to wrap
|
|
181
|
+
*/
|
|
182
|
+
export function spoiler<Content extends string>(content: Content): `||${Content}||` {
|
|
183
|
+
return `||${content}||`;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Formats a user id into a user mention.
|
|
188
|
+
*
|
|
189
|
+
* @typeParam UserId - This is inferred by the supplied user id
|
|
190
|
+
* @param userId - The user id to format
|
|
191
|
+
*/
|
|
192
|
+
export function userMention<UserId extends Snowflake>(userId: UserId): `<@${UserId}>` {
|
|
193
|
+
return `<@${userId}>`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Formats a channel id into a channel mention.
|
|
198
|
+
*
|
|
199
|
+
* @typeParam ChannelId - This is inferred by the supplied channel id
|
|
200
|
+
* @param channelId - The channel id to format
|
|
201
|
+
*/
|
|
202
|
+
export function channelMention<ChannelId extends Snowflake>(channelId: ChannelId): `<#${ChannelId}>` {
|
|
203
|
+
return `<#${channelId}>`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Formats a role id into a role mention.
|
|
208
|
+
*
|
|
209
|
+
* @typeParam RoleId - This is inferred by the supplied role id
|
|
210
|
+
* @param roleId - The role id to format
|
|
211
|
+
*/
|
|
212
|
+
export function roleMention<RoleId extends Snowflake>(roleId: RoleId): `<@&${RoleId}>` {
|
|
213
|
+
return `<@&${roleId}>`;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Formats a role id into a linked role mention.
|
|
218
|
+
*
|
|
219
|
+
* @typeParam RoleId - This is inferred by the supplied role id
|
|
220
|
+
* @param roleId - The role id to format
|
|
221
|
+
*/
|
|
222
|
+
export function linkedRoleMention<RoleId extends Snowflake>(roleId: RoleId): `<id:linked-roles:${RoleId}>` {
|
|
223
|
+
return `<id:linked-roles:${roleId}>`;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Formats an application command name and id into an application command mention.
|
|
228
|
+
*
|
|
229
|
+
* @typeParam CommandId - This is inferred by the supplied command id
|
|
230
|
+
* @typeParam CommandName - This is inferred by the supplied command name
|
|
231
|
+
* @param commandId - The application command id to format
|
|
232
|
+
* @param commandName - The application command name to format
|
|
233
|
+
*/
|
|
234
|
+
export function chatInputApplicationCommandMention<CommandId extends Snowflake, CommandName extends string>(
|
|
235
|
+
commandId: CommandId,
|
|
236
|
+
commandName: CommandName,
|
|
237
|
+
): `</${CommandName}:${CommandId}>`;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Formats an application command name, subcommand name, and id into an application command mention.
|
|
241
|
+
*
|
|
242
|
+
* @typeParam CommandId - This is inferred by the supplied command id
|
|
243
|
+
* @typeParam CommandName - This is inferred by the supplied command name
|
|
244
|
+
* @typeParam SubcommandName - This is inferred by the supplied subcommand name
|
|
245
|
+
* @param commandId - The application command id to format
|
|
246
|
+
* @param commandName - The application command name to format
|
|
247
|
+
* @param subcommandName - The subcommand name to format
|
|
248
|
+
*/
|
|
249
|
+
export function chatInputApplicationCommandMention<
|
|
250
|
+
CommandId extends Snowflake,
|
|
251
|
+
CommandName extends string,
|
|
252
|
+
SubcommandName extends string,
|
|
253
|
+
>(
|
|
254
|
+
commandId: CommandId,
|
|
255
|
+
commandName: CommandName,
|
|
256
|
+
subcommandName: SubcommandName,
|
|
257
|
+
): `</${CommandName} ${SubcommandName}:${CommandId}>`;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Formats an application command name, subcommand group name, subcommand name, and id into an application command mention.
|
|
261
|
+
*
|
|
262
|
+
* @typeParam CommandId - This is inferred by the supplied command id
|
|
263
|
+
* @typeParam CommandName - This is inferred by the supplied command name
|
|
264
|
+
* @typeParam SubcommandName - This is inferred by the supplied subcommand name
|
|
265
|
+
* @typeParam SubcommandGroupName - This is inferred by the supplied subcommand group name
|
|
266
|
+
* @param commandId - The application command id to format
|
|
267
|
+
* @param commandName - The application command name to format
|
|
268
|
+
* @param subcommandName - The subcommand name to format
|
|
269
|
+
* @param subcommandGroupName - The subcommand group name to format
|
|
270
|
+
*/
|
|
271
|
+
export function chatInputApplicationCommandMention<
|
|
272
|
+
CommandId extends Snowflake,
|
|
273
|
+
CommandName extends string,
|
|
274
|
+
SubcommandName extends string,
|
|
275
|
+
SubcommandGroupName extends string,
|
|
276
|
+
>(
|
|
277
|
+
commandId: CommandId,
|
|
278
|
+
commandName: CommandName,
|
|
279
|
+
subcommandName: SubcommandName,
|
|
280
|
+
subcommandGroupName: SubcommandGroupName,
|
|
281
|
+
): `</${CommandName} ${SubcommandGroupName} ${SubcommandName}:${CommandId}>`;
|
|
282
|
+
|
|
283
|
+
export function chatInputApplicationCommandMention<
|
|
284
|
+
CommandId extends Snowflake,
|
|
285
|
+
CommandName extends string,
|
|
286
|
+
SubcommandName extends string,
|
|
287
|
+
SubcommandGroupName extends string,
|
|
288
|
+
>(
|
|
289
|
+
commandId: CommandId,
|
|
290
|
+
commandName: CommandName,
|
|
291
|
+
subcommandName?: SubcommandName | undefined,
|
|
292
|
+
subcommandGroupName?: SubcommandGroupName | undefined,
|
|
293
|
+
):
|
|
294
|
+
| `</${CommandName} ${SubcommandGroupName} ${SubcommandName}:${CommandId}>`
|
|
295
|
+
| `</${CommandName} ${SubcommandName}:${CommandId}>`
|
|
296
|
+
| `</${CommandName}:${CommandId}>` {
|
|
297
|
+
if (subcommandGroupName !== undefined && subcommandName !== undefined) {
|
|
298
|
+
return `</${commandName} ${subcommandGroupName} ${subcommandName}:${commandId}>`;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (subcommandName !== undefined) {
|
|
302
|
+
return `</${commandName} ${subcommandName}:${commandId}>`;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return `</${commandName}:${commandId}>`;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Formats a non-animated emoji id into a fully qualified emoji identifier.
|
|
310
|
+
*
|
|
311
|
+
* @typeParam EmojiId - This is inferred by the supplied emoji id
|
|
312
|
+
* @param emojiId - The emoji id to format
|
|
313
|
+
*/
|
|
314
|
+
export function formatEmoji<EmojiId extends Snowflake>(emojiId: EmojiId, animated?: false): `<:emoji:${EmojiId}>`;
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Formats an animated emoji id into a fully qualified emoji identifier.
|
|
318
|
+
*
|
|
319
|
+
* @typeParam EmojiId - This is inferred by the supplied emoji id
|
|
320
|
+
* @param emojiId - The emoji id to format
|
|
321
|
+
* @param animated - Whether the emoji is animated
|
|
322
|
+
*/
|
|
323
|
+
export function formatEmoji<EmojiId extends Snowflake>(emojiId: EmojiId, animated?: true): `<a:emoji:${EmojiId}>`;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Formats an emoji id into a fully qualified emoji identifier.
|
|
327
|
+
*
|
|
328
|
+
* @typeParam EmojiId - This is inferred by the supplied emoji id
|
|
329
|
+
* @param emojiId - The emoji id to format
|
|
330
|
+
* @param animated - Whether the emoji is animated
|
|
331
|
+
*/
|
|
332
|
+
export function formatEmoji<EmojiId extends Snowflake>(
|
|
333
|
+
emojiId: EmojiId,
|
|
334
|
+
animated?: boolean,
|
|
335
|
+
): `<:emoji:${EmojiId}>` | `<a:emoji:${EmojiId}>`;
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Formats a non-animated emoji id and name into a fully qualified emoji identifier.
|
|
339
|
+
*
|
|
340
|
+
* @typeParam EmojiId - This is inferred by the supplied emoji id
|
|
341
|
+
* @typeParam EmojiName - This is inferred by the supplied name
|
|
342
|
+
* @param options - The options for formatting an emoji
|
|
343
|
+
*/
|
|
344
|
+
export function formatEmoji<EmojiId extends Snowflake, EmojiName extends string>(
|
|
345
|
+
options: FormatEmojiOptions<EmojiId, EmojiName> & { animated: true },
|
|
346
|
+
): `<a:${EmojiName}:${EmojiId}>`;
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Formats an animated emoji id and name into a fully qualified emoji identifier.
|
|
350
|
+
*
|
|
351
|
+
* @typeParam EmojiId - This is inferred by the supplied emoji id
|
|
352
|
+
* @typeParam EmojiName - This is inferred by the supplied name
|
|
353
|
+
* @param options - The options for formatting an emoji
|
|
354
|
+
*/
|
|
355
|
+
export function formatEmoji<EmojiId extends Snowflake, EmojiName extends string>(
|
|
356
|
+
options: FormatEmojiOptions<EmojiId, EmojiName> & { animated?: false },
|
|
357
|
+
): `<:${EmojiName}:${EmojiId}>`;
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Formats an emoji id and name into a fully qualified emoji identifier.
|
|
361
|
+
*
|
|
362
|
+
* @typeParam EmojiId - This is inferred by the supplied emoji id
|
|
363
|
+
* @typeParam EmojiName - This is inferred by the supplied emoji name
|
|
364
|
+
* @param options - The options for formatting an emoji
|
|
365
|
+
*/
|
|
366
|
+
export function formatEmoji<EmojiId extends Snowflake, EmojiName extends string>(
|
|
367
|
+
options: FormatEmojiOptions<EmojiId, EmojiName>,
|
|
368
|
+
): `<:${EmojiName}:${EmojiId}>` | `<a:${EmojiName}:${EmojiId}>`;
|
|
369
|
+
|
|
370
|
+
export function formatEmoji<EmojiId extends Snowflake, EmojiName extends string>(
|
|
371
|
+
emojiIdOrOptions: EmojiId | FormatEmojiOptions<EmojiId, EmojiName>,
|
|
372
|
+
animated?: boolean,
|
|
373
|
+
): `<:${string}:${EmojiId}>` | `<a:${string}:${EmojiId}>` {
|
|
374
|
+
const options =
|
|
375
|
+
typeof emojiIdOrOptions === 'string'
|
|
376
|
+
? {
|
|
377
|
+
id: emojiIdOrOptions,
|
|
378
|
+
animated: animated ?? false,
|
|
379
|
+
}
|
|
380
|
+
: emojiIdOrOptions;
|
|
381
|
+
|
|
382
|
+
const { id, animated: isAnimated, name: emojiName } = options;
|
|
383
|
+
|
|
384
|
+
return `<${isAnimated ? 'a' : ''}:${emojiName ?? 'emoji'}:${id}>`;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* The options for formatting an emoji.
|
|
389
|
+
*
|
|
390
|
+
* @typeParam EmojiId - This is inferred by the supplied emoji id
|
|
391
|
+
* @typeParam EmojiName - This is inferred by the supplied emoji name
|
|
392
|
+
*/
|
|
393
|
+
export interface FormatEmojiOptions<EmojiId extends Snowflake, EmojiName extends string> {
|
|
394
|
+
/**
|
|
395
|
+
* Whether the emoji is animated
|
|
396
|
+
*/
|
|
397
|
+
animated?: boolean;
|
|
398
|
+
/**
|
|
399
|
+
* The emoji id to format
|
|
400
|
+
*/
|
|
401
|
+
id: EmojiId;
|
|
402
|
+
/**
|
|
403
|
+
* The name of the emoji
|
|
404
|
+
*/
|
|
405
|
+
name?: EmojiName;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Formats a channel link for a direct message channel.
|
|
410
|
+
*
|
|
411
|
+
* @typeParam ChannelId - This is inferred by the supplied channel id
|
|
412
|
+
* @param channelId - The channel's id
|
|
413
|
+
*/
|
|
414
|
+
export function channelLink<ChannelId extends Snowflake>(
|
|
415
|
+
channelId: ChannelId,
|
|
416
|
+
): `https://discord.com/channels/@me/${ChannelId}`;
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Formats a channel link for a guild channel.
|
|
420
|
+
*
|
|
421
|
+
* @typeParam ChannelId - This is inferred by the supplied channel id
|
|
422
|
+
* @typeParam GuildId - This is inferred by the supplied guild id
|
|
423
|
+
* @param channelId - The channel's id
|
|
424
|
+
* @param guildId - The guild's id
|
|
425
|
+
*/
|
|
426
|
+
export function channelLink<ChannelId extends Snowflake, GuildId extends Snowflake>(
|
|
427
|
+
channelId: ChannelId,
|
|
428
|
+
guildId: GuildId,
|
|
429
|
+
): `https://discord.com/channels/${GuildId}/${ChannelId}`;
|
|
430
|
+
|
|
431
|
+
export function channelLink<ChannelId extends Snowflake, GuildId extends Snowflake>(
|
|
432
|
+
channelId: ChannelId,
|
|
433
|
+
guildId?: GuildId,
|
|
434
|
+
): `https://discord.com/channels/@me/${ChannelId}` | `https://discord.com/channels/${GuildId}/${ChannelId}` {
|
|
435
|
+
return `https://discord.com/channels/${guildId ?? '@me'}/${channelId}`;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Formats a message link for a direct message channel.
|
|
440
|
+
*
|
|
441
|
+
* @typeParam ChannelId - This is inferred by the supplied channel id
|
|
442
|
+
* @typeParam MessageId - This is inferred by the supplied message id
|
|
443
|
+
* @param channelId - The channel's id
|
|
444
|
+
* @param messageId - The message's id
|
|
445
|
+
*/
|
|
446
|
+
export function messageLink<ChannelId extends Snowflake, MessageId extends Snowflake>(
|
|
447
|
+
channelId: ChannelId,
|
|
448
|
+
messageId: MessageId,
|
|
449
|
+
): `https://discord.com/channels/@me/${ChannelId}/${MessageId}`;
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Formats a message link for a guild channel.
|
|
453
|
+
*
|
|
454
|
+
* @typeParam ChannelId - This is inferred by the supplied channel id
|
|
455
|
+
* @typeParam MessageId - This is inferred by the supplied message id
|
|
456
|
+
* @typeParam GuildId - This is inferred by the supplied guild id
|
|
457
|
+
* @param channelId - The channel's id
|
|
458
|
+
* @param messageId - The message's id
|
|
459
|
+
* @param guildId - The guild's id
|
|
460
|
+
*/
|
|
461
|
+
export function messageLink<ChannelId extends Snowflake, MessageId extends Snowflake, GuildId extends Snowflake>(
|
|
462
|
+
channelId: ChannelId,
|
|
463
|
+
messageId: MessageId,
|
|
464
|
+
guildId: GuildId,
|
|
465
|
+
): `https://discord.com/channels/${GuildId}/${ChannelId}/${MessageId}`;
|
|
466
|
+
|
|
467
|
+
export function messageLink<ChannelId extends Snowflake, MessageId extends Snowflake, GuildId extends Snowflake>(
|
|
468
|
+
channelId: ChannelId,
|
|
469
|
+
messageId: MessageId,
|
|
470
|
+
guildId?: GuildId,
|
|
471
|
+
):
|
|
472
|
+
| `https://discord.com/channels/@me/${ChannelId}/${MessageId}`
|
|
473
|
+
| `https://discord.com/channels/${GuildId}/${ChannelId}/${MessageId}` {
|
|
474
|
+
return `${guildId === undefined ? channelLink(channelId) : channelLink(channelId, guildId)}/${messageId}`;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* The heading levels for expanded markdown.
|
|
479
|
+
*/
|
|
480
|
+
export enum HeadingLevel {
|
|
481
|
+
/**
|
|
482
|
+
* The first heading level.
|
|
483
|
+
*/
|
|
484
|
+
One = 1,
|
|
485
|
+
/**
|
|
486
|
+
* The second heading level.
|
|
487
|
+
*/
|
|
488
|
+
Two,
|
|
489
|
+
/**
|
|
490
|
+
* The third heading level.
|
|
491
|
+
*/
|
|
492
|
+
Three,
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Formats the content into a heading level.
|
|
497
|
+
*
|
|
498
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
499
|
+
* @param content - The content to wrap
|
|
500
|
+
* @param level - The heading level
|
|
501
|
+
*/
|
|
502
|
+
export function heading<Content extends string>(content: Content, level?: HeadingLevel.One): `# ${Content}`;
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Formats the content into a heading level.
|
|
506
|
+
*
|
|
507
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
508
|
+
* @param content - The content to wrap
|
|
509
|
+
* @param level - The heading level
|
|
510
|
+
*/
|
|
511
|
+
export function heading<Content extends string>(content: Content, level: HeadingLevel.Two): `## ${Content}`;
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Formats the content into a heading level.
|
|
515
|
+
*
|
|
516
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
517
|
+
* @param content - The content to wrap
|
|
518
|
+
* @param level - The heading level
|
|
519
|
+
*/
|
|
520
|
+
export function heading<Content extends string>(content: Content, level: HeadingLevel.Three): `### ${Content}`;
|
|
521
|
+
|
|
522
|
+
export function heading(content: string, level?: HeadingLevel) {
|
|
523
|
+
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
|
|
524
|
+
switch (level) {
|
|
525
|
+
case HeadingLevel.Three:
|
|
526
|
+
return `### ${content}`;
|
|
527
|
+
case HeadingLevel.Two:
|
|
528
|
+
return `## ${content}`;
|
|
529
|
+
default:
|
|
530
|
+
return `# ${content}`;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* A type that recursively traverses into arrays.
|
|
536
|
+
*/
|
|
537
|
+
export type RecursiveArray<ItemType> = readonly (ItemType | RecursiveArray<ItemType>)[];
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Callback function for list formatters.
|
|
541
|
+
*
|
|
542
|
+
* @internal
|
|
543
|
+
*/
|
|
544
|
+
function listCallback(element: RecursiveArray<string>, startNumber?: number, depth = 0): string {
|
|
545
|
+
if (Array.isArray(element)) {
|
|
546
|
+
return element.map((element) => listCallback(element, startNumber, depth + 1)).join('\n');
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
return `${' '.repeat(depth - 1)}${startNumber ? `${startNumber}.` : '-'} ${element}`;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Formats the elements in the array to an ordered list.
|
|
554
|
+
*
|
|
555
|
+
* @param list - The array of elements to list
|
|
556
|
+
* @param startNumber - The starting number for the list
|
|
557
|
+
*/
|
|
558
|
+
export function orderedList(list: RecursiveArray<string>, startNumber = 1): string {
|
|
559
|
+
return listCallback(list, Math.max(startNumber, 1));
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Formats the elements in the array to an unordered list.
|
|
564
|
+
*
|
|
565
|
+
* @param list - The array of elements to list
|
|
566
|
+
*/
|
|
567
|
+
export function unorderedList(list: RecursiveArray<string>): string {
|
|
568
|
+
return listCallback(list);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Formats the content into a subtext.
|
|
573
|
+
*
|
|
574
|
+
* @typeParam Content - This is inferred by the supplied content
|
|
575
|
+
* @param content - The content to wrap
|
|
576
|
+
*/
|
|
577
|
+
export function subtext<Content extends string>(content: Content): `-# ${Content}` {
|
|
578
|
+
return `-# ${content}`;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Formats a date into a short date-time string.
|
|
583
|
+
*
|
|
584
|
+
* @param date - The date to format. Defaults to the current time
|
|
585
|
+
*/
|
|
586
|
+
export function time(date?: Date): `<t:${bigint}>`;
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Formats a date given a format style.
|
|
590
|
+
*
|
|
591
|
+
* @typeParam Style - This is inferred by the supplied {@link TimestampStylesString}
|
|
592
|
+
* @param date - The date to format
|
|
593
|
+
* @param style - The style to use
|
|
594
|
+
*/
|
|
595
|
+
export function time<Style extends TimestampStylesString>(date: Date, style: Style): `<t:${bigint}:${Style}>`;
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Formats the given timestamp into a short date-time string.
|
|
599
|
+
*
|
|
600
|
+
* @typeParam Seconds - This is inferred by the supplied timestamp
|
|
601
|
+
* @param seconds - A Unix timestamp in seconds
|
|
602
|
+
*/
|
|
603
|
+
export function time<Seconds extends number>(seconds: Seconds): `<t:${Seconds}>`;
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Formats the given timestamp into a short date-time string.
|
|
607
|
+
*
|
|
608
|
+
* @typeParam Seconds - This is inferred by the supplied timestamp
|
|
609
|
+
* @typeParam Style - This is inferred by the supplied {@link TimestampStylesString}
|
|
610
|
+
* @param seconds - A Unix timestamp in seconds
|
|
611
|
+
* @param style - The style to use
|
|
612
|
+
*/
|
|
613
|
+
export function time<Seconds extends number, Style extends TimestampStylesString>(
|
|
614
|
+
seconds: Seconds,
|
|
615
|
+
style: Style,
|
|
616
|
+
): `<t:${Seconds}:${Style}>`;
|
|
617
|
+
|
|
618
|
+
export function time(timeOrSeconds?: Date | number, style?: TimestampStylesString): string {
|
|
619
|
+
if (typeof timeOrSeconds !== 'number') {
|
|
620
|
+
// eslint-disable-next-line no-param-reassign
|
|
621
|
+
timeOrSeconds = Math.floor((timeOrSeconds?.getTime() ?? Date.now()) / 1_000);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
return typeof style === 'string' ? `<t:${timeOrSeconds}:${style}>` : `<t:${timeOrSeconds}>`;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Formats an application directory link.
|
|
629
|
+
*
|
|
630
|
+
* @typeParam ApplicationId - This is inferred by the supplied application id
|
|
631
|
+
* @param applicationId - The application id
|
|
632
|
+
*/
|
|
633
|
+
export function applicationDirectory<ApplicationId extends Snowflake>(
|
|
634
|
+
applicationId: ApplicationId,
|
|
635
|
+
): `https://discord.com/application-directory/${ApplicationId}/store`;
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Formats an application directory SKU link.
|
|
639
|
+
*
|
|
640
|
+
* @typeParam ApplicationId - This is inferred by the supplied application id
|
|
641
|
+
* @typeParam SKUId - This is inferred by the supplied SKU id
|
|
642
|
+
* @param applicationId - The application id
|
|
643
|
+
* @param skuId - The SKU id
|
|
644
|
+
*/
|
|
645
|
+
export function applicationDirectory<ApplicationId extends Snowflake, SKUId extends Snowflake>(
|
|
646
|
+
applicationId: ApplicationId,
|
|
647
|
+
skuId: SKUId,
|
|
648
|
+
): `https://discord.com/application-directory/${ApplicationId}/store/${SKUId}`;
|
|
649
|
+
|
|
650
|
+
export function applicationDirectory<ApplicationId extends Snowflake, SKUId extends Snowflake>(
|
|
651
|
+
applicationId: ApplicationId,
|
|
652
|
+
skuId?: SKUId,
|
|
653
|
+
):
|
|
654
|
+
| `https://discord.com/application-directory/${ApplicationId}/store/${SKUId}`
|
|
655
|
+
| `https://discord.com/application-directory/${ApplicationId}/store` {
|
|
656
|
+
const url = `https://discord.com/application-directory/${applicationId}/store` as const;
|
|
657
|
+
return skuId ? `${url}/${skuId}` : url;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Formats an email address into an email mention.
|
|
662
|
+
*
|
|
663
|
+
* @typeParam Email - This is inferred by the supplied email address
|
|
664
|
+
* @param email - The email address to format
|
|
665
|
+
*/
|
|
666
|
+
export function email<Email extends string>(email: Email): `<${Email}>`;
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Formats an email address and headers into an email mention.
|
|
670
|
+
*
|
|
671
|
+
* @typeParam Email - This is inferred by the supplied email address
|
|
672
|
+
* @param email - The email address to format
|
|
673
|
+
* @param headers - Optional headers to include in the email mention
|
|
674
|
+
*/
|
|
675
|
+
export function email<Email extends string>(
|
|
676
|
+
email: Email,
|
|
677
|
+
headers: Record<string, string | readonly string[]> | undefined,
|
|
678
|
+
): `<${Email}?${string}>`;
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Formats an email address into an email mention.
|
|
682
|
+
*
|
|
683
|
+
* @typeParam Email - This is inferred by the supplied email address
|
|
684
|
+
* @param email - The email address to format
|
|
685
|
+
* @param headers - Optional headers to include in the email mention
|
|
686
|
+
*/
|
|
687
|
+
export function email<Email extends string>(email: Email, headers?: Record<string, string | readonly string[]>) {
|
|
688
|
+
if (headers) {
|
|
689
|
+
const searchParams = new URLSearchParams(
|
|
690
|
+
Object.fromEntries(Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value])),
|
|
691
|
+
);
|
|
692
|
+
|
|
693
|
+
return `<${email}?${searchParams.toString()}>` as const;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
return `<${email}>` as const;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Formats a phone number into a phone number mention.
|
|
701
|
+
*
|
|
702
|
+
* @typeParam PhoneNumber - This is inferred by the supplied phone number
|
|
703
|
+
* @param phoneNumber - The phone number to format. Must start with a `+` sign.
|
|
704
|
+
*/
|
|
705
|
+
export function phoneNumber<PhoneNumber extends `+${string}`>(phoneNumber: PhoneNumber) {
|
|
706
|
+
if (!phoneNumber.startsWith('+')) {
|
|
707
|
+
throw new Error('Phone number must start with a "+" sign.');
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
return `<${phoneNumber}>` as const;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* The {@link https://discord.com/developers/docs/reference#message-formatting-timestamp-styles | message formatting timestamp styles}
|
|
715
|
+
* supported by Discord.
|
|
716
|
+
*/
|
|
717
|
+
export const TimestampStyles = {
|
|
718
|
+
/**
|
|
719
|
+
* Short time format, consisting of hours and minutes.
|
|
720
|
+
*
|
|
721
|
+
* @example `16:20`
|
|
722
|
+
*/
|
|
723
|
+
ShortTime: 't',
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Medium time format, consisting of hours, minutes, and seconds.
|
|
727
|
+
*
|
|
728
|
+
* @example `16:20:30`
|
|
729
|
+
*/
|
|
730
|
+
MediumTime: 'T',
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Short date format, consisting of day, month, and year.
|
|
734
|
+
*
|
|
735
|
+
* @example `20/04/2021`
|
|
736
|
+
*/
|
|
737
|
+
ShortDate: 'd',
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Long date format, consisting of day, month, and year.
|
|
741
|
+
*
|
|
742
|
+
* @example `April 20, 2021`
|
|
743
|
+
*/
|
|
744
|
+
LongDate: 'D',
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Long date-short time format, consisting of long date and short time.
|
|
748
|
+
*
|
|
749
|
+
* @example `April 20, 2021 at 16:20`
|
|
750
|
+
*/
|
|
751
|
+
LongDateShortTime: 'f',
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* Full date-short time format, consisting of full date and short time.
|
|
755
|
+
*
|
|
756
|
+
* @example `Tuesday, April 20, 2021 at 16:20`
|
|
757
|
+
*/
|
|
758
|
+
FullDateShortTime: 'F',
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* Short date, short time format, consisting of short date and short time.
|
|
762
|
+
*
|
|
763
|
+
* @example `20/04/2021, 16:20`
|
|
764
|
+
*/
|
|
765
|
+
ShortDateShortTime: 's',
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Short date, medium time format, consisting of short date and medium time.
|
|
769
|
+
*
|
|
770
|
+
* @example `20/04/2021, 16:20:30`
|
|
771
|
+
*/
|
|
772
|
+
ShortDateMediumTime: 'S',
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* Relative time format, consisting of a relative duration format.
|
|
776
|
+
*
|
|
777
|
+
* @example `2 months ago`
|
|
778
|
+
*/
|
|
779
|
+
RelativeTime: 'R',
|
|
780
|
+
} as const satisfies Record<string, string>;
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* The possible {@link TimestampStyles} values.
|
|
784
|
+
*/
|
|
785
|
+
export type TimestampStylesString = (typeof TimestampStyles)[keyof typeof TimestampStyles];
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* All the available faces from Discord's native slash commands.
|
|
789
|
+
*/
|
|
790
|
+
export enum Faces {
|
|
791
|
+
/**
|
|
792
|
+
* `¯\_(ツ)_/¯`
|
|
793
|
+
*/
|
|
794
|
+
Shrug = '¯\\_(ツ)_/¯',
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* `(╯°□°)╯︵ ┻━┻`
|
|
798
|
+
*/
|
|
799
|
+
Tableflip = '(╯°□°)╯︵ ┻━┻',
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* `┬─┬ノ( º _ ºノ)`
|
|
803
|
+
*/
|
|
804
|
+
Unflip = '┬─┬ノ( º _ ºノ)',
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* All the available guild navigation mentions.
|
|
809
|
+
*/
|
|
810
|
+
export enum GuildNavigationMentions {
|
|
811
|
+
/**
|
|
812
|
+
* Browse Channels tab.
|
|
813
|
+
*/
|
|
814
|
+
Browse = '<id:browse>',
|
|
815
|
+
/**
|
|
816
|
+
* Customize tab with the server's {@link https://discord.com/developers/docs/resources/guild#guild-onboarding-object | onboarding prompts}.
|
|
817
|
+
*/
|
|
818
|
+
Customize = '<id:customize>',
|
|
819
|
+
/**
|
|
820
|
+
* {@link https://support.discord.com/hc/articles/13497665141655 | Server Guide} tab.
|
|
821
|
+
*/
|
|
822
|
+
Guide = '<id:guide>',
|
|
823
|
+
/**
|
|
824
|
+
* {@link https://support.discord.com/hc/articles/10388356626711 | Linked Roles} tab.
|
|
825
|
+
*/
|
|
826
|
+
LinkedRoles = '<id:linked-roles>',
|
|
827
|
+
}
|