Skip to content
Merged
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
2 changes: 1 addition & 1 deletion packages/message-parser/tests/abuse.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { paragraph, plain, bold, italic, strike } from '../src/utils';
import { paragraph, plain, bold, italic, strike } from './helpers';

test.each([
[
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/any.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { paragraph, plain } from '../src/utils';
import { paragraph, plain } from './helpers';

test.each([
['free text', [paragraph([plain('free text')])]],
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/blockquotes.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { paragraph, plain, quote, bold } from '../src/utils';
import { paragraph, plain, quote, bold } from './helpers';

test.each([
[
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/codeFence.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { paragraph, plain, codeLine, code } from '../src/utils';
import { paragraph, plain, codeLine, code } from './helpers';

const multiply = <T>(a: number, element: T): Array<T> => Array.from({ length: a }, () => element);

Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/color.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { color, paragraph, plain } from '../src/utils';
import { color, paragraph, plain } from './helpers';

test.each([
['color:#ccc', [paragraph([color(0xcc, 0xcc, 0xcc)])], [paragraph([plain('color:#ccc')])]],
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/email.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { link, paragraph, plain } from '../src/utils';
import { link, paragraph, plain } from './helpers';

test.each([
['joe@joe.com', [paragraph([link('mailto:joe@joe.com', [plain('joe@joe.com')])])]],
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/emoji.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { emoji, bigEmoji, paragraph, plain, emojiUnicode } from '../src/utils';
import { emoji, bigEmoji, paragraph, plain, emojiUnicode } from './helpers';

test.each([
[':smile: asd', [paragraph([emoji('smile'), plain(' asd')])]],
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/emoticons.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { bigEmoji, paragraph, plain, emoticon } from '../src/utils';
import { bigEmoji, paragraph, plain, emoticon } from './helpers';

test.each([
// Should render normal Emojis
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/emphasis.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
mentionChannel,
mentionUser,
inlineCode,
} from '../src/utils';
} from './helpers';

test.each([
['_:smile:_', [paragraph([italic([emoji('smile')])])]],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { paragraph, plain, bold, italic, emoticon } from '../src/utils';
import { paragraph, plain, bold, italic, emoticon } from './helpers';

test.each([
['*test:*', [paragraph([bold([plain('test:')])])]],
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/escaped.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { paragraph, plain, bold } from '../src/utils';
import { paragraph, plain, bold } from './helpers';

test.each([
['¯\\\\_(ツ)_/¯', [paragraph([plain('¯\\_(ツ)_/¯')])]],
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/heading.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { heading, lineBreak, mentionChannel, paragraph, plain } from '../src/utils';
import { heading, lineBreak, mentionChannel, paragraph, plain } from './helpers';

test.each([
['# h1', [heading([plain('h1')], 1)]],
Expand Down
102 changes: 102 additions & 0 deletions packages/message-parser/tests/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
const generate =
<Type extends string>(type: Type) =>
<Value>(value: Value) =>
({ type, value }) as const;

export const paragraph = generate('PARAGRAPH');
export const bold = generate('BOLD');

export const color = (r: number, g: number, b: number, a = 255) => ({
type: 'COLOR' as const,
value: { r, g, b, a },
});

export const heading = (value: unknown[], level = 1) => ({
type: 'HEADING' as const,
level,
value,
});

export const code = (value: unknown[], language = 'none') => ({
type: 'CODE' as const,
language,
value,
});

export const bigEmoji = generate('BIG_EMOJI');
export const task = (value: unknown[], status: boolean) => ({ type: 'TASK' as const, status, value });
export const inlineCode = generate('INLINE_CODE');
export const tasks = generate('TASKS');

export const italic = generate('ITALIC');
export const spoiler = generate('SPOILER');

export const plain = generate('PLAIN_TEXT');
export const strike = generate('STRIKE');

export const codeLine = generate('CODE_LINE');

export const link = (src: string, label?: unknown[]) => ({
type: 'LINK' as const,
value: { src: plain(src), label: label ?? [plain(src)] },
});

export const image = (src: string, label?: unknown) => ({
type: 'IMAGE' as const,
value: { src: plain(src), label: label ?? plain(src) },
});

export const quote = generate('QUOTE');
export const spoilerBlock = generate('SPOILER_BLOCK');

export const mentionChannel = (value: string) => ({
type: 'MENTION_CHANNEL' as const,
value: plain(value),
});

export const orderedList = generate('ORDERED_LIST');
export const unorderedList = generate('UNORDERED_LIST');

export const listItem = (value: unknown[], number?: number) => ({
type: 'LIST_ITEM' as const,
value,
...(number !== undefined ? { number } : {}),
});

export const mentionUser = (value: string) => ({
type: 'MENTION_USER' as const,
value: plain(value),
});

export const emoji = (shortCode: string) => ({
type: 'EMOJI' as const,
value: plain(shortCode),
shortCode,
});

export const emojiUnicode = (unicode: string) => ({
type: 'EMOJI' as const,
value: undefined,
unicode,
});

export const emoticon = (value: string, shortCode: string) => ({
type: 'EMOJI' as const,
value: plain(value),
shortCode,
});

export const lineBreak = () => ({
type: 'LINE_BREAK' as const,
value: undefined,
});

export const katex = (value: string) => ({
type: 'KATEX' as const,
value,
});

export const inlineKatex = (value: string) => ({
type: 'INLINE_KATEX' as const,
value,
});
2 changes: 1 addition & 1 deletion packages/message-parser/tests/image.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { image, paragraph, plain } from '../src/utils';
import { image, paragraph, plain } from './helpers';

test.each([
[
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/inlineCode.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { inlineCode, paragraph, plain } from '../src/utils';
import { inlineCode, paragraph, plain } from './helpers';

test.each([
['`[asd](https://localhost)`', [paragraph([inlineCode(plain('[asd](https://localhost)'))])]],
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/inlineCodeStrike.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { bold, inlineCode, italic, paragraph, plain, strike } from '../src/utils';
import { bold, inlineCode, italic, paragraph, plain, strike } from './helpers';

test.each([
['~~`Striking Inline Code`~~', [paragraph([strike([inlineCode(plain('Striking Inline Code'))])])]],
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/katex.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { inlineKatex, katex, paragraph, plain } from '../src/utils';
import { inlineKatex, katex, paragraph, plain } from './helpers';

test.each([
[
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/lineBreak.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { lineBreak, paragraph, plain } from '../src/utils';
import { lineBreak, paragraph, plain } from './helpers';

test.each([
[
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/link.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { link, paragraph, plain, bold, strike, italic, quote, lineBreak, unorderedList, listItem, orderedList } from '../src/utils';
import { link, paragraph, plain, bold, strike, italic, quote, lineBreak, unorderedList, listItem, orderedList } from './helpers';

test.each([
['<https://domain.com|Test>', [paragraph([link('https://domain.com', [plain('Test')])])]],
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/mention.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { paragraph, plain, mentionUser, mentionChannel } from '../src/utils';
import { paragraph, plain, mentionUser, mentionChannel } from './helpers';

test.each([
['@guilherme.gazzo', [paragraph([mentionUser('guilherme.gazzo')])]],
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/orderedList.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { bold, plain, orderedList, listItem, emoji } from '../src/utils';
import { bold, plain, orderedList, listItem, emoji } from './helpers';

test.each([
[
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/phoneNumber.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { link, paragraph, plain, bold } from '../src/utils';
import { link, paragraph, plain, bold } from './helpers';

test.each([
['+07563546725', [paragraph([link('tel:07563546725', [plain('+07563546725')])])]],
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/spoiler.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { bold, emoji, italic, link, mentionChannel, mentionUser, paragraph, plain, spoiler, strike } from '../src/utils';
import { bold, emoji, italic, link, mentionChannel, mentionUser, paragraph, plain, spoiler, strike } from './helpers';

describe('spoiler parsing', () => {
test.each([
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/spoilerBlock.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { lineBreak, paragraph, plain, spoilerBlock } from '../src/utils';
import { lineBreak, paragraph, plain, spoilerBlock } from './helpers';

describe('block spoiler parsing', () => {
test.each([
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/strikethrough.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { emoji, emojiUnicode, link, mentionChannel, mentionUser, paragraph, plain, strike } from '../src/utils';
import { emoji, emojiUnicode, link, mentionChannel, mentionUser, paragraph, plain, strike } from './helpers';

test.each([
['~:smile:~', [paragraph([strike([emoji('smile')])])]],
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/strongEmphasis.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { bold, link, paragraph, plain, italic, strike, emoji, emojiUnicode, mentionChannel, mentionUser } from '../src/utils';
import { bold, link, paragraph, plain, italic, strike, emoji, emojiUnicode, mentionChannel, mentionUser } from './helpers';

test.each([
['*:smile:*', [paragraph([bold([emoji('smile')])])]],
Expand Down
2 changes: 1 addition & 1 deletion packages/message-parser/tests/tasks.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { plain, tasks, task, mentionUser, mentionChannel, link, bold, emoji } from '../src/utils';
import { plain, tasks, task, mentionUser, mentionChannel, link, bold, emoji } from './helpers';

test.each([
[
Expand Down
63 changes: 45 additions & 18 deletions packages/message-parser/tests/timestamp.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
import { parse } from '../src';
import { bold, paragraph, plain, strike, timestamp, timestampFromHours } from '../src/utils';

const plain = (value: string) => ({ type: 'PLAIN_TEXT' as const, value });
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Duplicate AST builder helpers are redefined inline instead of importing the shared test helpers, increasing maintenance overhead and contradicting the test-helper reuse guideline.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/message-parser/tests/timestamp.test.ts, line 3:

<comment>Duplicate AST builder helpers are redefined inline instead of importing the shared test helpers, increasing maintenance overhead and contradicting the test-helper reuse guideline.</comment>

<file context>
@@ -1,10 +1,26 @@
 import { parse } from '../src';
-import { bold, paragraph, plain, strike, timestamp, timestampFromHours } from '../src/utils';
+
+const plain = (value: string) => ({ type: 'PLAIN_TEXT' as const, value });
+
+const paragraph = (value: Array<Record<string, unknown>>) => ({ type: 'PARAGRAPH' as const, value });
</file context>
Fix with Cubic


const paragraph = (value: Array<Record<string, unknown>>) => ({ type: 'PARAGRAPH' as const, value });

const bold = (value: Array<Record<string, unknown>>) => ({ type: 'BOLD' as const, value });

const strike = (value: Array<Record<string, unknown>>) => ({ type: 'STRIKE' as const, value });

const timestampNode = (value: string, format: 't' | 'T' | 'd' | 'D' | 'f' | 'F' | 'R' = 't') => ({
type: 'TIMESTAMP' as const,
value: {
timestamp: value,
format,
},
fallback: plain(`<t:${value}:${format}>`),
});

test.each([
[`<t:1708551317>`, [paragraph([timestamp('1708551317')])]],
[`<t:1708551317:R>`, [paragraph([timestamp('1708551317', 'R')])]],
['hello <t:1708551317>', [paragraph([plain('hello '), timestamp('1708551317')])]],
[`<t:1708551317>`, [paragraph([timestampNode('1708551317')])]],
[`<t:1708551317:R>`, [paragraph([timestampNode('1708551317', 'R')])]],
['hello <t:1708551317>', [paragraph([plain('hello '), timestampNode('1708551317')])]],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});
Expand All @@ -17,26 +33,37 @@ test.each([
});

test.each([
['~<t:1708551317>~', [paragraph([strike([timestamp('1708551317')])])]],
['~<t:1708551317>~', [paragraph([strike([timestampNode('1708551317')])])]],
['*<t:1708551317>*', [paragraph([bold([plain('<t:1708551317>')])])]],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

test.each([
['<t:2025-07-22T10:00:00.000+00:00:R>', [paragraph([timestamp((Date.parse('2025-07-22T10:00:00.000+00:00') / 1000).toString(), 'R')])]],
['<t:2025-07-22T10:00:00.000+00:00:R>', [paragraph([timestamp((Date.parse('2025-07-22T10:00:00.000+00:00') / 1000).toString(), 'R')])]],
['<t:2025-07-22T10:00:00.000+00:00:R>', [paragraph([timestamp((Date.parse('2025-07-22T10:00:00.000+00:00') / 1000).toString(), 'R')])]],
['<t:2025-07-22T10:00:00+00:00:R>', [paragraph([timestamp((Date.parse('2025-07-22T10:00:00+00:00') / 1000).toString(), 'R')])]],
['<t:10:00:00+00:00:R>', [paragraph([timestamp(timestampFromHours('10', '00', '00', '+00:00'), 'R')])]],
['<t:10:00+00:00:R>', [paragraph([timestamp(timestampFromHours('10', '00', '00', '+00:00'), 'R')])]],
['<t:10:00:05+00:00>', [paragraph([timestamp(timestampFromHours('10', '00', '05', '+00:00'), 't')])]],
['<t:10:00+00:00>', [paragraph([timestamp(timestampFromHours('10', '00', '00', '+00:00'), 't')])]],

[
'<t:2025-07-24T20:19:58.154+00:00:R>',
[paragraph([timestamp(((Date.parse('2025-07-24T20:19:58.154+00:00') / 1000) | 0).toString(), 'R')])],
],
['<t:2025-07-22T10:00:00.000+00:00:R>', [paragraph([timestampNode('1753178400', 'R')])]],
['<t:2025-07-22T10:00:00+00:00:R>', [paragraph([timestampNode('1753178400', 'R')])]],

['<t:2025-07-24T20:19:58.154+00:00:R>', [paragraph([timestampNode('1753388398', 'R')])]],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});

describe('relative hour timestamp parsing', () => {
beforeAll(() => {
jest.useFakeTimers();
jest.setSystemTime(new Date('2025-07-22T00:00:00.000Z'));
});

afterAll(() => {
jest.useRealTimers();
});

test.each([
['<t:10:00:00+00:00:R>', [paragraph([timestampNode('1753178400', 'R')])]],
['<t:10:00+00:00:R>', [paragraph([timestampNode('1753178400', 'R')])]],
['<t:10:00:05+00:00>', [paragraph([timestampNode('1753178405')])]],
['<t:10:00+00:00>', [paragraph([timestampNode('1753178400')])]],
])('parses %p', (input, output) => {
expect(parse(input)).toMatchObject(output);
});
});
2 changes: 1 addition & 1 deletion packages/message-parser/tests/unorderedList.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from '../src';
import { unorderedList, plain, listItem, bold, emoji } from '../src/utils';
import { unorderedList, plain, listItem, bold, emoji } from './helpers';

test.each([
[
Expand Down
Loading
Loading