From 0d787e9f797b53974a49f56727acb6318cd8d650 Mon Sep 17 00:00:00 2001 From: Danial Raza Date: Fri, 25 Aug 2023 12:06:13 +0200 Subject: [PATCH] feat: add new markdown formatters (#9613) * feat: add new markdown formatters Co-authored-by: Jaw0r3k * Update packages/formatters/src/formatters.ts Co-authored-by: Sugden <28943913+NotSugden@users.noreply.github.com> * refactor: remove unnecessary index tracking and rename 'array' to 'items' Co-authored-by: Almeida * refactor: rename 'array' to 'items' Co-authored-by: Almeida * refactor(heading): consolidate heading functions into a single function Also correct param names from array to items. Co-authored-by: Jaw0r3k * refactor: add HeadingLevel enum and use switch case * fix: export HeadingLevel enum Co-authored-by: Jaw0r3k * feat(heading): add missing documentation for level parameter * refactor: update list formatters * docs: correct heading formatter description * refactor: update list formatters * fix(heading): remove unnecessary space * refactor: move list callback function to outer scope * test: add tests * refactor: requested changes * refactor: suggested changes * docs: add missing documentation * style: suggested change Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> * refactor: use math max method instead Co-authored-by: Almeida --------- Co-authored-by: Jaw0r3k Co-authored-by: Sugden <28943913+NotSugden@users.noreply.github.com> Co-authored-by: Almeida Co-authored-by: Jaw0r3k Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> Co-authored-by: space --- .../formatters/__tests__/formatters.test.ts | 40 ++++++++ packages/formatters/src/formatters.ts | 93 +++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/packages/formatters/__tests__/formatters.test.ts b/packages/formatters/__tests__/formatters.test.ts index b6d3ea075..1719a98dc 100644 --- a/packages/formatters/__tests__/formatters.test.ts +++ b/packages/formatters/__tests__/formatters.test.ts @@ -10,11 +10,14 @@ import { codeBlock, Faces, formatEmoji, + heading, + HeadingLevel, hideLinkEmbed, hyperlink, inlineCode, italic, messageLink, + orderedList, quote, roleMention, spoiler, @@ -22,6 +25,7 @@ import { time, TimestampStyles, underscore, + unorderedList, userMention, } from '../src/index.js'; @@ -202,6 +206,42 @@ describe('Message formatters', () => { }); }); + describe('heading', () => { + test('GIVEN "discord.js" THEN returns "# discord.js"', () => { + expect<'# discord.js'>(heading('discord.js')).toEqual('# discord.js'); + }); + + test('GIVEN "discord.js" AND a heading level 2 from number THEN returns "## discord.js"', () => { + expect<'## discord.js'>(heading('discord.js', 2)).toEqual('## discord.js'); + }); + + test('GIVEN "discord.js" AND a heading level 3 from enum THEN returns "### discord.js"', () => { + expect<'### discord.js'>(heading('discord.js', HeadingLevel.Three)).toEqual('### discord.js'); + }); + }); + + describe('orderedList', () => { + test('GIVEN ["discord.js", "discord.js 2", ["discord.js 3"]] THEN returns "1. discord.js\n1. discord.js 2\n 1. discord.js"', () => { + expect(orderedList(['discord.js', 'discord.js 2', ['discord.js 3']])).toEqual( + '1. discord.js\n1. discord.js 2\n 1. discord.js 3', + ); + }); + + test('GIVEN ["discord.js", "discord.js 2", ["discord.js 3"]] AND a startNumber THEN returns "${startNumber}. discord.js\n${startNumber}. discord.js 2\n ${startNumber}. discord.js"', () => { + expect(orderedList(['discord.js', 'discord.js 2', ['discord.js 3']], 50)).toEqual( + '50. discord.js\n50. discord.js 2\n 50. discord.js 3', + ); + }); + }); + + describe('unorderedList', () => { + test('GIVEN ["discord.js", "discord.js 2", ["discord.js 3"]] THEN returns "- discord.js\n- discord.js 2\n - discord.js"', () => { + expect(unorderedList(['discord.js', 'discord.js 2', ['discord.js 3']])).toEqual( + '- discord.js\n- discord.js 2\n - discord.js 3', + ); + }); + }); + describe('time', () => { test('GIVEN no arguments THEN returns ""', () => { vitest.useFakeTimers(); diff --git a/packages/formatters/src/formatters.ts b/packages/formatters/src/formatters.ts index 1faeb0c45..f56dd91a4 100644 --- a/packages/formatters/src/formatters.ts +++ b/packages/formatters/src/formatters.ts @@ -373,6 +373,99 @@ export function messageLink(content: C, level?: HeadingLevel.One): `# ${C}`; + +/** + * Formats the content into a heading level. + * + * @typeParam C - This is inferred by the supplied content + * @param content - The content to wrap + * @param level - The heading level + */ +export function heading(content: C, level: HeadingLevel.Two): `## ${C}`; + +/** + * Formats the content into a heading level. + * + * @typeParam C - This is inferred by the supplied content + * @param content - The content to wrap + * @param level - The heading level + */ +export function heading(content: C, level: HeadingLevel.Three): `### ${C}`; + +export function heading(content: string, level?: HeadingLevel) { + switch (level) { + case HeadingLevel.Three: + return `### ${content}`; + case HeadingLevel.Two: + return `## ${content}`; + default: + return `# ${content}`; + } +} + +/** + * A type that recursively traverses into arrays. + */ +export type RecursiveArray = readonly (RecursiveArray | T)[]; + +/** + * Callback function for list formatters. + * + * @internal + */ +function listCallback(element: RecursiveArray, startNumber?: number, depth = 0): string { + if (Array.isArray(element)) { + return element.map((element) => listCallback(element, startNumber, depth + 1)).join('\n'); + } + + return `${' '.repeat(depth - 1)}${startNumber ? `${startNumber}.` : '-'} ${element}`; +} + +/** + * Formats the elements in the array to an ordered list. + * + * @param list - The array of elements to list + * @param startNumber - The starting number for the list + */ +export function orderedList(list: RecursiveArray, startNumber = 1): string { + return listCallback(list, Math.max(startNumber, 1)); +} + +/** + * Formats the elements in the array to an unordered list. + * + * @param list - The array of elements to list + */ +export function unorderedList(list: RecursiveArray): string { + return listCallback(list); +} + /** * Formats a date into a short date-time string. *