Skip to content

Commit bf0430f

Browse files
almeidxkodiakhq[bot]
authored andcommitted
feat: add email and phoneNumber formatters (#11050)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
1 parent 2da2fa0 commit bf0430f

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

packages/formatters/__tests__/formatters.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import {
2929
underline,
3030
unorderedList,
3131
userMention,
32+
email,
33+
phoneNumber,
3234
} from '../src/index.js';
3335

3436
describe('Message formatters', () => {
@@ -335,6 +337,33 @@ describe('Message formatters', () => {
335337
});
336338
});
337339

340+
describe('email', () => {
341+
test('GIVEN an email THEN returns "<[email]>"', () => {
342+
expect<'<[email protected]>'>(email('[email protected]')).toEqual('<[email protected]>');
343+
});
344+
345+
test('GIVEN an email AND headers THEN returns "<[email]?[headers]>"', () => {
346+
expect<`<[email protected]?${string}>`>(email('[email protected]', { subject: 'Hello', body: 'World' })).toEqual(
347+
'<[email protected]?subject=Hello&body=World>',
348+
);
349+
});
350+
});
351+
352+
describe('phoneNumber', () => {
353+
test('GIVEN a phone number with + THEN returns "<[phoneNumber]>"', () => {
354+
expect<'<+1234567890>'>(phoneNumber('+1234567890')).toEqual('<+1234567890>');
355+
});
356+
357+
test('GIVEN a phone number without + THEN throws', () => {
358+
expect(() =>
359+
phoneNumber(
360+
// @ts-expect-error - Invalid input
361+
'1234567890',
362+
),
363+
).toThrowError();
364+
});
365+
});
366+
338367
describe('Faces', () => {
339368
test('GIVEN Faces.Shrug THEN returns "¯\\_(ツ)_/¯"', () => {
340369
expect<'¯\\_(ツ)_/¯'>(Faces.Shrug).toEqual('¯\\_(ツ)_/¯');

packages/formatters/src/formatters.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,60 @@ export function applicationDirectory<ApplicationId extends Snowflake, SKUId exte
658658
return skuId ? `${url}/${skuId}` : url;
659659
}
660660

661+
/**
662+
* Formats an email address into an email mention.
663+
*
664+
* @typeParam Email - This is inferred by the supplied email address
665+
* @param email - The email address to format
666+
*/
667+
export function email<Email extends string>(email: Email): `<${Email}>`;
668+
669+
/**
670+
* Formats an email address and headers into an email mention.
671+
*
672+
* @typeParam Email - This is inferred by the supplied email address
673+
* @param email - The email address to format
674+
* @param headers - Optional headers to include in the email mention
675+
*/
676+
export function email<Email extends string>(
677+
email: Email,
678+
headers: Record<string, string | readonly string[]> | undefined,
679+
): `<${Email}?${string}>`;
680+
681+
/**
682+
* Formats an email address into an email mention.
683+
*
684+
* @typeParam Email - This is inferred by the supplied email address
685+
* @param email - The email address to format
686+
* @param headers - Optional headers to include in the email mention
687+
*/
688+
export function email<Email extends string>(email: Email, headers?: Record<string, string | readonly string[]>) {
689+
if (headers) {
690+
// eslint-disable-next-line n/prefer-global/url-search-params
691+
const searchParams = new URLSearchParams(
692+
Object.fromEntries(Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value])),
693+
);
694+
695+
return `<${email}?${searchParams.toString()}>` as const;
696+
}
697+
698+
return `<${email}>` as const;
699+
}
700+
701+
/**
702+
* Formats a phone number into a phone number mention.
703+
*
704+
* @typeParam PhoneNumber - This is inferred by the supplied phone number
705+
* @param phoneNumber - The phone number to format. Must start with a `+` sign.
706+
*/
707+
export function phoneNumber<PhoneNumber extends `+${string}`>(phoneNumber: PhoneNumber) {
708+
if (!phoneNumber.startsWith('+')) {
709+
throw new Error('Phone number must start with a "+" sign.');
710+
}
711+
712+
return `<${phoneNumber}>` as const;
713+
}
714+
661715
/**
662716
* The {@link https://discord.com/developers/docs/reference#message-formatting-timestamp-styles | message formatting timestamp styles}
663717
* supported by Discord.

0 commit comments

Comments
 (0)