mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-17 20:13:30 +01:00
feat: add @discordjs/formatters (#8889)
* feat: add @discordjs/formatters * chore: make requested changes * chore: make requested changes * chore: fix other places * chore: make requested changes Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1,255 +0,0 @@
|
||||
/* eslint-disable no-template-curly-in-string */
|
||||
import { URL } from 'node:url';
|
||||
import { describe, test, expect, vitest } from 'vitest';
|
||||
import {
|
||||
chatInputApplicationCommandMention,
|
||||
blockQuote,
|
||||
bold,
|
||||
channelLink,
|
||||
channelMention,
|
||||
codeBlock,
|
||||
Faces,
|
||||
formatEmoji,
|
||||
hideLinkEmbed,
|
||||
hyperlink,
|
||||
inlineCode,
|
||||
italic,
|
||||
messageLink,
|
||||
quote,
|
||||
roleMention,
|
||||
spoiler,
|
||||
strikethrough,
|
||||
time,
|
||||
TimestampStyles,
|
||||
underscore,
|
||||
userMention,
|
||||
} from '../../src/index.js';
|
||||
|
||||
describe('Message formatters', () => {
|
||||
describe('codeBlock', () => {
|
||||
test('GIVEN "discord.js" with no language THEN returns "```\\ndiscord.js```"', () => {
|
||||
expect<'```\ndiscord.js\n```'>(codeBlock('discord.js')).toEqual('```\ndiscord.js\n```');
|
||||
});
|
||||
|
||||
test('GIVEN "discord.js" with "js" as language THEN returns "```js\\ndiscord.js```"', () => {
|
||||
expect<'```js\ndiscord.js\n```'>(codeBlock('js', 'discord.js')).toEqual('```js\ndiscord.js\n```');
|
||||
});
|
||||
});
|
||||
|
||||
describe('inlineCode', () => {
|
||||
test('GIVEN "discord.js" THEN returns "`discord.js`"', () => {
|
||||
expect<'`discord.js`'>(inlineCode('discord.js')).toEqual('`discord.js`');
|
||||
});
|
||||
});
|
||||
|
||||
describe('italic', () => {
|
||||
test('GIVEN "discord.js" THEN returns "_discord.js_"', () => {
|
||||
expect<'_discord.js_'>(italic('discord.js')).toEqual('_discord.js_');
|
||||
});
|
||||
});
|
||||
|
||||
describe('bold', () => {
|
||||
test('GIVEN "discord.js" THEN returns "**discord.js**"', () => {
|
||||
expect<'**discord.js**'>(bold('discord.js')).toEqual('**discord.js**');
|
||||
});
|
||||
});
|
||||
|
||||
describe('underscore', () => {
|
||||
test('GIVEN "discord.js" THEN returns "__discord.js__"', () => {
|
||||
expect<'__discord.js__'>(underscore('discord.js')).toEqual('__discord.js__');
|
||||
});
|
||||
});
|
||||
|
||||
describe('strikethrough', () => {
|
||||
test('GIVEN "discord.js" THEN returns "~~discord.js~~"', () => {
|
||||
expect<'~~discord.js~~'>(strikethrough('discord.js')).toEqual('~~discord.js~~');
|
||||
});
|
||||
});
|
||||
|
||||
describe('quote', () => {
|
||||
test('GIVEN "discord.js" THEN returns "> discord.js"', () => {
|
||||
expect<'> discord.js'>(quote('discord.js')).toEqual('> discord.js');
|
||||
});
|
||||
});
|
||||
|
||||
describe('blockQuote', () => {
|
||||
test('GIVEN "discord.js" THEN returns ">>> discord.js"', () => {
|
||||
expect<'>>> discord.js'>(blockQuote('discord.js')).toEqual('>>> discord.js');
|
||||
});
|
||||
});
|
||||
|
||||
describe('hideLinkEmbed', () => {
|
||||
test('GIVEN "https://discord.js.org" THEN returns "<https://discord.js.org>"', () => {
|
||||
expect<'<https://discord.js.org>'>(hideLinkEmbed('https://discord.js.org')).toEqual('<https://discord.js.org>');
|
||||
});
|
||||
|
||||
test('GIVEN new URL("https://discord.js.org") THEN returns "<https://discord.js.org>"', () => {
|
||||
expect<`<${string}>`>(hideLinkEmbed(new URL('https://discord.js.org/'))).toEqual('<https://discord.js.org/>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('hyperlink', () => {
|
||||
test('GIVEN content and string URL THEN returns "[content](url)"', () => {
|
||||
expect<'[discord.js](https://discord.js.org)'>(hyperlink('discord.js', 'https://discord.js.org')).toEqual(
|
||||
'[discord.js](https://discord.js.org)',
|
||||
);
|
||||
});
|
||||
|
||||
test('GIVEN content and URL THEN returns "[content](url)"', () => {
|
||||
expect<`[discord.js](${string})`>(hyperlink('discord.js', new URL('https://discord.js.org'))).toEqual(
|
||||
'[discord.js](https://discord.js.org/)',
|
||||
);
|
||||
});
|
||||
|
||||
test('GIVEN content, string URL, and title THEN returns "[content](url "title")"', () => {
|
||||
expect<'[discord.js](https://discord.js.org "Official Documentation")'>(
|
||||
hyperlink('discord.js', 'https://discord.js.org', 'Official Documentation'),
|
||||
).toEqual('[discord.js](https://discord.js.org "Official Documentation")');
|
||||
});
|
||||
|
||||
test('GIVEN content, URL, and title THEN returns "[content](url "title")"', () => {
|
||||
expect<`[discord.js](${string} "Official Documentation")`>(
|
||||
hyperlink('discord.js', new URL('https://discord.js.org'), 'Official Documentation'),
|
||||
).toEqual('[discord.js](https://discord.js.org/ "Official Documentation")');
|
||||
});
|
||||
});
|
||||
|
||||
describe('spoiler', () => {
|
||||
test('GIVEN "discord.js" THEN returns "||discord.js||"', () => {
|
||||
expect<'||discord.js||'>(spoiler('discord.js')).toEqual('||discord.js||');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Mentions', () => {
|
||||
describe('userMention', () => {
|
||||
test('GIVEN userId THEN returns "<@[userId]>"', () => {
|
||||
expect(userMention('139836912335716352')).toEqual('<@139836912335716352>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('channelMention', () => {
|
||||
test('GIVEN channelId THEN returns "<#[channelId]>"', () => {
|
||||
expect(channelMention('829924760309334087')).toEqual('<#829924760309334087>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('roleMention', () => {
|
||||
test('GIVEN roleId THEN returns "<&[roleId]>"', () => {
|
||||
expect(roleMention('815434166602170409')).toEqual('<@&815434166602170409>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('chatInputApplicationCommandMention', () => {
|
||||
test('GIVEN commandName and commandId THEN returns "</[commandName]:[commandId]>"', () => {
|
||||
expect(chatInputApplicationCommandMention('airhorn', '815434166602170409')).toEqual(
|
||||
'</airhorn:815434166602170409>',
|
||||
);
|
||||
});
|
||||
|
||||
test('GIVEN commandName, subcommandName, and commandId THEN returns "</[commandName] [subcommandName]:[commandId]>"', () => {
|
||||
expect(chatInputApplicationCommandMention('airhorn', 'sub', '815434166602170409')).toEqual(
|
||||
'</airhorn sub:815434166602170409>',
|
||||
);
|
||||
});
|
||||
|
||||
test('GIVEN commandName, subcommandGroupName, subcommandName, and commandId THEN returns "</[commandName] [subcommandGroupName] [subcommandName]:[commandId]>"', () => {
|
||||
expect(chatInputApplicationCommandMention('airhorn', 'group', 'sub', '815434166602170409')).toEqual(
|
||||
'</airhorn group sub:815434166602170409>',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatEmoji', () => {
|
||||
test('GIVEN static emojiId THEN returns "<:_:${emojiId}>"', () => {
|
||||
expect<`<:_:851461487498493952>`>(formatEmoji('851461487498493952')).toEqual('<:_:851461487498493952>');
|
||||
});
|
||||
|
||||
test('GIVEN static emojiId WITH animated explicitly false THEN returns "<:_:[emojiId]>"', () => {
|
||||
expect<`<:_:851461487498493952>`>(formatEmoji('851461487498493952', false)).toEqual('<:_:851461487498493952>');
|
||||
});
|
||||
|
||||
test('GIVEN animated emojiId THEN returns "<a:_:${emojiId}>"', () => {
|
||||
expect<`<a:_:827220205352255549>`>(formatEmoji('827220205352255549', true)).toEqual('<a:_:827220205352255549>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('channelLink', () => {
|
||||
test('GIVEN channelId THEN returns "https://discord.com/channels/@me/${channelId}"', () => {
|
||||
expect<'https://discord.com/channels/@me/123456789012345678'>(channelLink('123456789012345678')).toEqual(
|
||||
'https://discord.com/channels/@me/123456789012345678',
|
||||
);
|
||||
});
|
||||
|
||||
test('GIVEN channelId WITH guildId THEN returns "https://discord.com/channels/${guildId}/${channelId}"', () => {
|
||||
expect<'https://discord.com/channels/987654321987654/123456789012345678'>(
|
||||
channelLink('123456789012345678', '987654321987654'),
|
||||
).toEqual('https://discord.com/channels/987654321987654/123456789012345678');
|
||||
});
|
||||
});
|
||||
|
||||
describe('messageLink', () => {
|
||||
test('GIVEN channelId AND messageId THEN returns "https://discord.com/channels/@me/${channelId}/${messageId}"', () => {
|
||||
expect<'https://discord.com/channels/@me/123456789012345678/102938475657483'>(
|
||||
messageLink('123456789012345678', '102938475657483'),
|
||||
).toEqual('https://discord.com/channels/@me/123456789012345678/102938475657483');
|
||||
});
|
||||
|
||||
test('GIVEN channelId AND messageId WITH guildId THEN returns "https://discord.com/channels/${guildId}/${channelId}/${messageId}"', () => {
|
||||
expect<'https://discord.com/channels/987654321987654/123456789012345678/102938475657483'>(
|
||||
messageLink('123456789012345678', '102938475657483', '987654321987654'),
|
||||
).toEqual('https://discord.com/channels/987654321987654/123456789012345678/102938475657483');
|
||||
});
|
||||
});
|
||||
|
||||
describe('time', () => {
|
||||
test('GIVEN no arguments THEN returns "<t:${bigint}>"', () => {
|
||||
vitest.useFakeTimers();
|
||||
vitest.setSystemTime(1_566_424_897_579);
|
||||
|
||||
expect<`<t:${bigint}>`>(time()).toEqual('<t:1566424897>');
|
||||
|
||||
vitest.useRealTimers();
|
||||
});
|
||||
|
||||
test('GIVEN a date THEN returns "<t:${bigint}>"', () => {
|
||||
expect<`<t:${bigint}>`>(time(new Date(1_867_424_897_579))).toEqual('<t:1867424897>');
|
||||
});
|
||||
|
||||
test('GIVEN a date and a style from string THEN returns "<t:${bigint}:${style}>"', () => {
|
||||
expect<`<t:${bigint}:d>`>(time(new Date(1_867_424_897_579), 'd')).toEqual('<t:1867424897:d>');
|
||||
});
|
||||
|
||||
test('GIVEN a date and a format from enum THEN returns "<t:${bigint}:${style}>"', () => {
|
||||
expect<`<t:${bigint}:R>`>(time(new Date(1_867_424_897_579), TimestampStyles.RelativeTime)).toEqual(
|
||||
'<t:1867424897:R>',
|
||||
);
|
||||
});
|
||||
|
||||
test('GIVEN a date THEN returns "<t:${time}>"', () => {
|
||||
expect<'<t:1867424897>'>(time(1_867_424_897)).toEqual('<t:1867424897>');
|
||||
});
|
||||
|
||||
test('GIVEN a date and a style from string THEN returns "<t:${time}:${style}>"', () => {
|
||||
expect<'<t:1867424897:d>'>(time(1_867_424_897, 'd')).toEqual('<t:1867424897:d>');
|
||||
});
|
||||
|
||||
test('GIVEN a date and a format from enum THEN returns "<t:${time}:${style}>"', () => {
|
||||
expect<'<t:1867424897:R>'>(time(1_867_424_897, TimestampStyles.RelativeTime)).toEqual('<t:1867424897:R>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Faces', () => {
|
||||
test('GIVEN Faces.Shrug THEN returns "¯\\_(ツ)\\_/¯"', () => {
|
||||
expect<'¯\\_(ツ)\\_/¯'>(Faces.Shrug).toEqual('¯\\_(ツ)\\_/¯');
|
||||
});
|
||||
|
||||
test('GIVEN Faces.Tableflip THEN returns "(╯°□°)╯︵ ┻━┻"', () => {
|
||||
expect<'(╯°□°)╯︵ ┻━┻'>(Faces.Tableflip).toEqual('(╯°□°)╯︵ ┻━┻');
|
||||
});
|
||||
|
||||
test('GIVEN Faces.Unflip THEN returns "┬─┬ ノ( ゜-゜ノ)"', () => {
|
||||
expect<'┬─┬ ノ( ゜-゜ノ)'>(Faces.Unflip).toEqual('┬─┬ ノ( ゜-゜ノ)');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -54,6 +54,7 @@
|
||||
},
|
||||
"homepage": "https://discord.js.org",
|
||||
"dependencies": {
|
||||
"@discordjs/formatters": "workspace:^",
|
||||
"@discordjs/util": "workspace:^",
|
||||
"@sapphire/shapeshift": "^3.7.1",
|
||||
"discord-api-types": "^0.37.20",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export * as EmbedAssertions from './messages/embed/Assertions.js';
|
||||
export * from './messages/embed/Embed.js';
|
||||
export * from './messages/formatters.js';
|
||||
// TODO: Consider removing this dep in the next major version
|
||||
export * from '@discordjs/formatters';
|
||||
|
||||
export * as ComponentAssertions from './components/Assertions.js';
|
||||
export * from './components/ActionRow.js';
|
||||
|
||||
@@ -1,443 +0,0 @@
|
||||
import type { URL } from 'node:url';
|
||||
import type { Snowflake } from 'discord-api-types/globals';
|
||||
|
||||
/**
|
||||
* Wraps the content inside a codeblock with no language
|
||||
*
|
||||
* @param content - The content to wrap
|
||||
*/
|
||||
export function codeBlock<C extends string>(content: C): `\`\`\`\n${C}\n\`\`\``;
|
||||
|
||||
/**
|
||||
* Wraps the content inside a codeblock with the specified language
|
||||
*
|
||||
* @param language - The language for the codeblock
|
||||
* @param content - The content to wrap
|
||||
*/
|
||||
export function codeBlock<L extends string, C extends string>(language: L, content: C): `\`\`\`${L}\n${C}\n\`\`\``;
|
||||
export function codeBlock(language: string, content?: string): string {
|
||||
return typeof content === 'undefined' ? `\`\`\`\n${language}\n\`\`\`` : `\`\`\`${language}\n${content}\n\`\`\``;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the content inside \`backticks\`, which formats it as inline code
|
||||
*
|
||||
* @param content - The content to wrap
|
||||
*/
|
||||
export function inlineCode<C extends string>(content: C): `\`${C}\`` {
|
||||
return `\`${content}\``;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the content into italic text
|
||||
*
|
||||
* @param content - The content to wrap
|
||||
*/
|
||||
export function italic<C extends string>(content: C): `_${C}_` {
|
||||
return `_${content}_`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the content into bold text
|
||||
*
|
||||
* @param content - The content to wrap
|
||||
*/
|
||||
export function bold<C extends string>(content: C): `**${C}**` {
|
||||
return `**${content}**`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the content into underscored text
|
||||
*
|
||||
* @param content - The content to wrap
|
||||
*/
|
||||
export function underscore<C extends string>(content: C): `__${C}__` {
|
||||
return `__${content}__`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the content into strike-through text
|
||||
*
|
||||
* @param content - The content to wrap
|
||||
*/
|
||||
export function strikethrough<C extends string>(content: C): `~~${C}~~` {
|
||||
return `~~${content}~~`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the content into a quote. This needs to be at the start of the line for Discord to format it
|
||||
*
|
||||
* @param content - The content to wrap
|
||||
*/
|
||||
export function quote<C extends string>(content: C): `> ${C}` {
|
||||
return `> ${content}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the content into a block quote. This needs to be at the start of the line for Discord to format it
|
||||
*
|
||||
* @param content - The content to wrap
|
||||
*/
|
||||
export function blockQuote<C extends string>(content: C): `>>> ${C}` {
|
||||
return `>>> ${content}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the URL into `<>`, which stops it from embedding
|
||||
*
|
||||
* @param url - The URL to wrap
|
||||
*/
|
||||
export function hideLinkEmbed<C extends string>(url: C): `<${C}>`;
|
||||
|
||||
/**
|
||||
* Wraps the URL into `<>`, which stops it from embedding
|
||||
*
|
||||
* @param url - The URL to wrap
|
||||
*/
|
||||
export function hideLinkEmbed(url: URL): `<${string}>`;
|
||||
export function hideLinkEmbed(url: URL | string) {
|
||||
return `<${url}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the content and the URL into a masked URL
|
||||
*
|
||||
* @param content - The content to display
|
||||
* @param url - The URL the content links to
|
||||
*/
|
||||
export function hyperlink<C extends string>(content: C, url: URL): `[${C}](${string})`;
|
||||
|
||||
/**
|
||||
* Formats the content and the URL into a masked URL
|
||||
*
|
||||
* @param content - The content to display
|
||||
* @param url - The URL the content links to
|
||||
*/
|
||||
export function hyperlink<C extends string, U extends string>(content: C, url: U): `[${C}](${U})`;
|
||||
|
||||
/**
|
||||
* Formats the content and the URL into a masked URL
|
||||
*
|
||||
* @param content - The content to display
|
||||
* @param url - The URL the content links to
|
||||
* @param title - The title shown when hovering on the masked link
|
||||
*/
|
||||
export function hyperlink<C extends string, T extends string>(
|
||||
content: C,
|
||||
url: URL,
|
||||
title: T,
|
||||
): `[${C}](${string} "${T}")`;
|
||||
|
||||
/**
|
||||
* Formats the content and the URL into a masked URL
|
||||
*
|
||||
* @param content - The content to display
|
||||
* @param url - The URL the content links to
|
||||
* @param title - The title shown when hovering on the masked link
|
||||
*/
|
||||
export function hyperlink<C extends string, U extends string, T extends string>(
|
||||
content: C,
|
||||
url: U,
|
||||
title: T,
|
||||
): `[${C}](${U} "${T}")`;
|
||||
export function hyperlink(content: string, url: URL | string, title?: string) {
|
||||
return title ? `[${content}](${url} "${title}")` : `[${content}](${url})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the content inside spoiler (hidden text)
|
||||
*
|
||||
* @param content - The content to wrap
|
||||
*/
|
||||
export function spoiler<C extends string>(content: C): `||${C}||` {
|
||||
return `||${content}||`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a user ID into a user mention
|
||||
*
|
||||
* @param userId - The user ID to format
|
||||
*/
|
||||
export function userMention<C extends Snowflake>(userId: C): `<@${C}>` {
|
||||
return `<@${userId}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a channel ID into a channel mention
|
||||
*
|
||||
* @param channelId - The channel ID to format
|
||||
*/
|
||||
export function channelMention<C extends Snowflake>(channelId: C): `<#${C}>` {
|
||||
return `<#${channelId}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a role ID into a role mention
|
||||
*
|
||||
* @param roleId - The role ID to format
|
||||
*/
|
||||
export function roleMention<C extends Snowflake>(roleId: C): `<@&${C}>` {
|
||||
return `<@&${roleId}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an application command name, subcommand group name, subcommand name, and ID into an application command mention
|
||||
*
|
||||
* @param commandName - The application command name to format
|
||||
* @param subcommandGroupName - The subcommand group name to format
|
||||
* @param subcommandName - The subcommand name to format
|
||||
* @param commandId - The application command ID to format
|
||||
*/
|
||||
export function chatInputApplicationCommandMention<
|
||||
N extends string,
|
||||
G extends string,
|
||||
S extends string,
|
||||
I extends Snowflake,
|
||||
>(commandName: N, subcommandGroupName: G, subcommandName: S, commandId: I): `</${N} ${G} ${S}:${I}>`;
|
||||
|
||||
/**
|
||||
* Formats an application command name, subcommand name, and ID into an application command mention
|
||||
*
|
||||
* @param commandName - The application command name to format
|
||||
* @param subcommandName - The subcommand name to format
|
||||
* @param commandId - The application command ID to format
|
||||
*/
|
||||
export function chatInputApplicationCommandMention<N extends string, S extends string, I extends Snowflake>(
|
||||
commandName: N,
|
||||
subcommandName: S,
|
||||
commandId: I,
|
||||
): `</${N} ${S}:${I}>`;
|
||||
|
||||
/**
|
||||
* Formats an application command name and ID into an application command mention
|
||||
*
|
||||
* @param commandName - The application command name to format
|
||||
* @param commandId - The application command ID to format
|
||||
*/
|
||||
export function chatInputApplicationCommandMention<N extends string, I extends Snowflake>(
|
||||
commandName: N,
|
||||
commandId: I,
|
||||
): `</${N}:${I}>`;
|
||||
|
||||
/**
|
||||
* Formats an application command name, subcommand group name, subcommand name, and ID into an application command mention
|
||||
*
|
||||
* @param commandName - The application command name to format
|
||||
* @param subcommandGroupName - The subcommand group name to format
|
||||
* @param subcommandName - The subcommand name to format
|
||||
* @param commandId - The application command ID to format
|
||||
*/
|
||||
export function chatInputApplicationCommandMention<
|
||||
N extends string,
|
||||
G extends Snowflake | string,
|
||||
S extends Snowflake | string,
|
||||
I extends Snowflake,
|
||||
>(
|
||||
commandName: N,
|
||||
subcommandGroupName: G,
|
||||
subcommandName?: S,
|
||||
commandId?: I,
|
||||
): `</${N} ${G} ${S}:${I}>` | `</${N} ${G}:${S}>` | `</${N}:${G}>` {
|
||||
if (typeof commandId !== 'undefined') {
|
||||
return `</${commandName} ${subcommandGroupName} ${subcommandName!}:${commandId}>`;
|
||||
}
|
||||
|
||||
if (typeof subcommandName !== 'undefined') {
|
||||
return `</${commandName} ${subcommandGroupName}:${subcommandName}>`;
|
||||
}
|
||||
|
||||
return `</${commandName}:${subcommandGroupName}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an emoji ID into a fully qualified emoji identifier
|
||||
*
|
||||
* @param emojiId - The emoji ID to format
|
||||
*/
|
||||
export function formatEmoji<C extends Snowflake>(emojiId: C, animated?: false): `<:_:${C}>`;
|
||||
|
||||
/**
|
||||
* Formats an emoji ID into a fully qualified emoji identifier
|
||||
*
|
||||
* @param emojiId - The emoji ID to format
|
||||
* @param animated - Whether the emoji is animated or not. Defaults to `false`
|
||||
*/
|
||||
export function formatEmoji<C extends Snowflake>(emojiId: C, animated?: true): `<a:_:${C}>`;
|
||||
|
||||
/**
|
||||
* Formats an emoji ID into a fully qualified emoji identifier
|
||||
*
|
||||
* @param emojiId - The emoji ID to format
|
||||
* @param animated - Whether the emoji is animated or not. Defaults to `false`
|
||||
*/
|
||||
export function formatEmoji<C extends Snowflake>(emojiId: C, animated?: boolean): `<:_:${C}>` | `<a:_:${C}>`;
|
||||
|
||||
/**
|
||||
* Formats an emoji ID into a fully qualified emoji identifier
|
||||
*
|
||||
* @param emojiId - The emoji ID to format
|
||||
* @param animated - Whether the emoji is animated or not. Defaults to `false`
|
||||
*/
|
||||
export function formatEmoji<C extends Snowflake>(emojiId: C, animated = false): `<:_:${C}>` | `<a:_:${C}>` {
|
||||
return `<${animated ? 'a' : ''}:_:${emojiId}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a channel link for a direct message channel.
|
||||
*
|
||||
* @param channelId - The channel's id
|
||||
*/
|
||||
export function channelLink<C extends Snowflake>(channelId: C): `https://discord.com/channels/@me/${C}`;
|
||||
|
||||
/**
|
||||
* Formats a channel link for a guild channel.
|
||||
*
|
||||
* @param channelId - The channel's id
|
||||
* @param guildId - The guild's id
|
||||
*/
|
||||
export function channelLink<C extends Snowflake, G extends Snowflake>(
|
||||
channelId: C,
|
||||
guildId: G,
|
||||
): `https://discord.com/channels/${G}/${C}`;
|
||||
|
||||
export function channelLink<C extends Snowflake, G extends Snowflake>(
|
||||
channelId: C,
|
||||
guildId?: G,
|
||||
): `https://discord.com/channels/@me/${C}` | `https://discord.com/channels/${G}/${C}` {
|
||||
return `https://discord.com/channels/${guildId ?? '@me'}/${channelId}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a message link for a direct message channel.
|
||||
*
|
||||
* @param channelId - The channel's id
|
||||
* @param messageId - The message's id
|
||||
*/
|
||||
export function messageLink<C extends Snowflake, M extends Snowflake>(
|
||||
channelId: C,
|
||||
messageId: M,
|
||||
): `https://discord.com/channels/@me/${C}/${M}`;
|
||||
|
||||
/**
|
||||
* Formats a message link for a guild channel.
|
||||
*
|
||||
* @param channelId - The channel's id
|
||||
* @param messageId - The message's id
|
||||
* @param guildId - The guild's id
|
||||
*/
|
||||
export function messageLink<C extends Snowflake, M extends Snowflake, G extends Snowflake>(
|
||||
channelId: C,
|
||||
messageId: M,
|
||||
guildId: G,
|
||||
): `https://discord.com/channels/${G}/${C}/${M}`;
|
||||
|
||||
export function messageLink<C extends Snowflake, M extends Snowflake, G extends Snowflake>(
|
||||
channelId: C,
|
||||
messageId: M,
|
||||
guildId?: G,
|
||||
): `https://discord.com/channels/@me/${C}/${M}` | `https://discord.com/channels/${G}/${C}/${M}` {
|
||||
return `${typeof guildId === 'undefined' ? channelLink(channelId) : channelLink(channelId, guildId)}/${messageId}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a date into a short date-time string
|
||||
*
|
||||
* @param date - The date to format, defaults to the current time
|
||||
*/
|
||||
export function time(date?: Date): `<t:${bigint}>`;
|
||||
|
||||
/**
|
||||
* Formats a date given a format style
|
||||
*
|
||||
* @param date - The date to format
|
||||
* @param style - The style to use
|
||||
*/
|
||||
export function time<S extends TimestampStylesString>(date: Date, style: S): `<t:${bigint}:${S}>`;
|
||||
|
||||
/**
|
||||
* Formats the given timestamp into a short date-time string
|
||||
*
|
||||
* @param seconds - The time to format, represents an UNIX timestamp in seconds
|
||||
*/
|
||||
export function time<C extends number>(seconds: C): `<t:${C}>`;
|
||||
|
||||
/**
|
||||
* Formats the given timestamp into a short date-time string
|
||||
*
|
||||
* @param seconds - The time to format, represents an UNIX timestamp in seconds
|
||||
* @param style - The style to use
|
||||
*/
|
||||
export function time<C extends number, S extends TimestampStylesString>(seconds: C, style: S): `<t:${C}:${S}>`;
|
||||
export function time(timeOrSeconds?: Date | number, style?: TimestampStylesString): string {
|
||||
if (typeof timeOrSeconds !== 'number') {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
timeOrSeconds = Math.floor((timeOrSeconds?.getTime() ?? Date.now()) / 1_000);
|
||||
}
|
||||
|
||||
return typeof style === 'string' ? `<t:${timeOrSeconds}:${style}>` : `<t:${timeOrSeconds}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link https://discord.com/developers/docs/reference#message-formatting-timestamp-styles | message formatting timestamp styles} supported by Discord
|
||||
*/
|
||||
export const TimestampStyles = {
|
||||
/**
|
||||
* Short time format, consisting of hours and minutes, e.g. 16:20
|
||||
*/
|
||||
ShortTime: 't',
|
||||
|
||||
/**
|
||||
* Long time format, consisting of hours, minutes, and seconds, e.g. 16:20:30
|
||||
*/
|
||||
LongTime: 'T',
|
||||
|
||||
/**
|
||||
* Short date format, consisting of day, month, and year, e.g. 20/04/2021
|
||||
*/
|
||||
ShortDate: 'd',
|
||||
|
||||
/**
|
||||
* Long date format, consisting of day, month, and year, e.g. 20 April 2021
|
||||
*/
|
||||
LongDate: 'D',
|
||||
|
||||
/**
|
||||
* Short date-time format, consisting of short date and short time formats, e.g. 20 April 2021 16:20
|
||||
*/
|
||||
ShortDateTime: 'f',
|
||||
|
||||
/**
|
||||
* Long date-time format, consisting of long date and short time formats, e.g. Tuesday, 20 April 2021 16:20
|
||||
*/
|
||||
LongDateTime: 'F',
|
||||
|
||||
/**
|
||||
* Relative time format, consisting of a relative duration format, e.g. 2 months ago
|
||||
*/
|
||||
RelativeTime: 'R',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* The possible values, see {@link TimestampStyles} for more information
|
||||
*/
|
||||
export type TimestampStylesString = typeof TimestampStyles[keyof typeof TimestampStyles];
|
||||
|
||||
/**
|
||||
* An enum with all the available faces from Discord's native slash commands
|
||||
*/
|
||||
export enum Faces {
|
||||
/**
|
||||
* ¯\\_(ツ)\\_/¯
|
||||
*/
|
||||
Shrug = '¯\\_(ツ)\\_/¯',
|
||||
|
||||
/**
|
||||
* (╯°□°)╯︵ ┻━┻
|
||||
*/
|
||||
Tableflip = '(╯°□°)╯︵ ┻━┻',
|
||||
|
||||
/**
|
||||
* ┬─┬ ノ( ゜-゜ノ)
|
||||
*/
|
||||
Unflip = '┬─┬ ノ( ゜-゜ノ)',
|
||||
}
|
||||
Reference in New Issue
Block a user