@mks2508/telegram-message-builder 0.2.0 → 0.3.0
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/dist/index.cjs +1057 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1022 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/builder/builder.d.ts +55 -0
- package/src/builder/builder.d.ts.map +1 -1
- package/src/builder/builder.ts +145 -10
- package/src/builder/index.d.ts +2 -1
- package/src/builder/index.d.ts.map +1 -1
- package/src/builder/index.ts +2 -1
- package/src/builder/media.d.ts +352 -0
- package/src/builder/media.d.ts.map +1 -0
- package/src/builder/media.test.ts +664 -0
- package/src/builder/media.ts +484 -0
- package/src/builder.test.ts +465 -0
- package/src/escaping.test.ts +2 -2
- package/src/formatters/index.d.ts +47 -0
- package/src/formatters/index.d.ts.map +1 -1
- package/src/formatters/index.ts +92 -1
- package/src/formatters/markdown.d.ts +179 -0
- package/src/formatters/markdown.d.ts.map +1 -0
- package/src/formatters/markdown.test.ts +417 -0
- package/src/formatters/markdown.ts +220 -0
- package/src/formatters/markdownv2.d.ts +184 -0
- package/src/formatters/markdownv2.d.ts.map +1 -0
- package/src/formatters/markdownv2.ts +235 -0
- package/src/formatters.test.ts +17 -7
- package/src/index.d.ts +2 -0
- package/src/index.d.ts.map +1 -1
- package/src/index.ts +12 -0
- package/src/integration.test.ts +523 -0
- package/src/media-integration.test.ts +384 -0
- package/src/types/index.d.ts +1 -0
- package/src/types/index.d.ts.map +1 -1
- package/src/types/index.ts +1 -0
- package/src/types/media.types.d.ts +158 -0
- package/src/types/media.types.d.ts.map +1 -0
- package/src/types/media.types.ts +178 -0
- package/src/types.test.ts +539 -0
- package/src/utils/index.d.ts +1 -1
- package/src/utils/index.ts +0 -5
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Markdown (Legacy) Formatters
|
|
3
|
+
* @description Text formatting functions for Telegram's legacy Markdown parse mode
|
|
4
|
+
* @module telegram-message-builder/formatters
|
|
5
|
+
*
|
|
6
|
+
* @see {@link https://core.telegram.org/bots/api#formatting-options | Telegram Bot API - Formatting Options}
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Formats text as bold in Markdown
|
|
10
|
+
*
|
|
11
|
+
* @param text - The text to format
|
|
12
|
+
* @returns Bold formatted text
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* boldMD("Hello") // "*Hello*"
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function boldMD(text: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Formats text as italic in Markdown
|
|
21
|
+
*
|
|
22
|
+
* @param text - The text to format
|
|
23
|
+
* @returns Italic formatted text
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* italicMD("Hello") // "_Hello_"
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function italicMD(text: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Formats text as monospace code in Markdown
|
|
32
|
+
*
|
|
33
|
+
* @param text - The text to format
|
|
34
|
+
* @returns Code formatted text
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* codeMD("const x = 1") // "`const x = 1`"
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function codeMD(text: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Formats text as a code block in Markdown
|
|
43
|
+
*
|
|
44
|
+
* @param text - The code to format
|
|
45
|
+
* @param language - Optional programming language for syntax highlighting
|
|
46
|
+
* @returns Code block formatted text
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* codeBlockMD("console.log('Hello')") // "```console.log('Hello')```"
|
|
50
|
+
* codeBlockMD("const x = 1", "javascript") // "```javascript\nconst x = 1\n```"
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function codeBlockMD(text: string, language?: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Creates a link in Markdown format
|
|
56
|
+
*
|
|
57
|
+
* @param text - The link text
|
|
58
|
+
* @param url - The URL to link to
|
|
59
|
+
* @returns Link formatted text
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* linkMD("Google", "https://google.com") // "[Google](https://google.com)"
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare function linkMD(text: string, url: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* Creates a user mention link in Markdown format
|
|
68
|
+
*
|
|
69
|
+
* @param userId - The user's ID
|
|
70
|
+
* @param name - Optional display name
|
|
71
|
+
* @returns Mention formatted text
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* mentionMD(123456) // "tg://user?id=123456"
|
|
75
|
+
* mentionMD(123456, "John") // "tg://user?id=123456"
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export declare function mentionMD(userId: number, _name?: string): string;
|
|
79
|
+
/**
|
|
80
|
+
* Creates a hashtag link in Markdown format
|
|
81
|
+
*
|
|
82
|
+
* @param tag - The hashtag text (without #)
|
|
83
|
+
* @returns Hashtag formatted text
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* hashtagMD("test") // "#test"
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export declare function hashtagMD(tag: string): string;
|
|
90
|
+
/**
|
|
91
|
+
* Formats text as underline in Markdown (limited support)
|
|
92
|
+
*
|
|
93
|
+
* Note: Standard Markdown doesn't support underline. This uses HTML which
|
|
94
|
+
* may not work in all Telegram clients.
|
|
95
|
+
*
|
|
96
|
+
* @param text - The text to format
|
|
97
|
+
* @returns Underline formatted text (HTML fallback)
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* underlineMD("Hello") // "<u>Hello</u>"
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export declare function underlineMD(text: string): string;
|
|
104
|
+
/**
|
|
105
|
+
* Formats text as strikethrough in Markdown (limited support)
|
|
106
|
+
*
|
|
107
|
+
* Note: Standard Markdown doesn't support strikethrough. This uses HTML which
|
|
108
|
+
* may not work in all Telegram clients.
|
|
109
|
+
*
|
|
110
|
+
* @param text - The text to format
|
|
111
|
+
* @returns Strikethrough formatted text (HTML fallback)
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* strikethroughMD("Hello") // "<s>Hello</s>"
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export declare function strikethroughMD(text: string): string;
|
|
118
|
+
/**
|
|
119
|
+
* Formats text as spoiler in Markdown (limited support)
|
|
120
|
+
*
|
|
121
|
+
* Note: Standard Markdown doesn't support spoiler. This uses HTML which
|
|
122
|
+
* may not work in all Telegram clients.
|
|
123
|
+
*
|
|
124
|
+
* @param text - The text to format
|
|
125
|
+
* @returns Spoiler formatted text (HTML fallback)
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* spoilerMD("Secret") // "<tg-spoiler>Secret</tg-spoiler>"
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export declare function spoilerMD(text: string): string;
|
|
132
|
+
/**
|
|
133
|
+
* Creates an email link in Markdown format
|
|
134
|
+
*
|
|
135
|
+
* @param email - The email address
|
|
136
|
+
* @returns Email link formatted text
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* emailMD("test@example.com") // "[test@example.com](mailto:test@example.com)"
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export declare function emailMD(email: string): string;
|
|
143
|
+
/**
|
|
144
|
+
* Creates a URL link in Markdown format
|
|
145
|
+
*
|
|
146
|
+
* @param url - The URL
|
|
147
|
+
* @returns URL link formatted text
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* urlMD("https://example.com") // "[https://example.com](https://example.com)"
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
export declare function urlMD(url: string): string;
|
|
154
|
+
/**
|
|
155
|
+
* Creates a custom emoji in Markdown format (limited support)
|
|
156
|
+
*
|
|
157
|
+
* Note: Standard Markdown doesn't support custom emoji. This uses HTML which
|
|
158
|
+
* may not work in all Telegram clients.
|
|
159
|
+
*
|
|
160
|
+
* @param emojiId - The custom emoji ID
|
|
161
|
+
* @returns Custom emoji formatted text (HTML fallback)
|
|
162
|
+
* @example
|
|
163
|
+
* ```typescript
|
|
164
|
+
* customEmojiMD("5368324170672642286") // "<tg-emoji emoji-id=\"5368324170672642286\">👻</tg-emoji>"
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
export declare function customEmojiMD(emojiId: string): string;
|
|
168
|
+
/**
|
|
169
|
+
* Raw Markdown string - bypasses any automatic formatting
|
|
170
|
+
*
|
|
171
|
+
* @param markdown - Pre-formatted Markdown string
|
|
172
|
+
* @returns The Markdown string unchanged
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* rawMD("*Hello*") // "*Hello*"
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
export declare function rawMD(markdown: string): string;
|
|
179
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["markdown.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE9C"}
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import { describe, it, expect } from "bun:test";
|
|
2
|
+
import * as fmt from "..";
|
|
3
|
+
|
|
4
|
+
describe("Markdown (Legacy) Formatters", () => {
|
|
5
|
+
describe("Text Formatting", () => {
|
|
6
|
+
it("should format bold text", () => {
|
|
7
|
+
const result = fmt.boldMD("Hello");
|
|
8
|
+
expect(result).toBe("*Hello*");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("should format italic text", () => {
|
|
12
|
+
const result = fmt.italicMD("Hello");
|
|
13
|
+
expect(result).toBe("_Hello_");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should format code text", () => {
|
|
17
|
+
const result = fmt.codeMD("const x = 1");
|
|
18
|
+
expect(result).toBe("`const x = 1`");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("should format code block without language", () => {
|
|
22
|
+
const result = fmt.codeBlockMD("const x = 1");
|
|
23
|
+
expect(result).toBe("const x = 1\n");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should format code block with language", () => {
|
|
27
|
+
const result = fmt.codeBlockMD("const x = 1", "javascript");
|
|
28
|
+
expect(result).toBe("javascript\nconst x = 1\n");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should format multiline code block", () => {
|
|
32
|
+
const code = "const x = 1;\nconst y = 2;";
|
|
33
|
+
const result = fmt.codeBlockMD(code);
|
|
34
|
+
expect(result).toBe("const x = 1;\nconst y = 2;\n");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should format underline (HTML fallback)", () => {
|
|
38
|
+
const result = fmt.underlineMD("Hello");
|
|
39
|
+
expect(result).toBe("<u>Hello</u>");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should format strikethrough (HTML fallback)", () => {
|
|
43
|
+
const result = fmt.strikethroughMD("Hello");
|
|
44
|
+
expect(result).toBe("<s>Hello</s>");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should format spoiler (HTML fallback)", () => {
|
|
48
|
+
const result = fmt.spoilerMD("Secret");
|
|
49
|
+
expect(result).toBe("<tg-spoiler>Secret</tg-spoiler>");
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe("Links and Mentions", () => {
|
|
54
|
+
it("should format link", () => {
|
|
55
|
+
const result = fmt.linkMD("Google", "https://google.com");
|
|
56
|
+
expect(result).toBe("[Google](https://google.com)");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("should format mention without name", () => {
|
|
60
|
+
const result = fmt.mentionMD(123456);
|
|
61
|
+
expect(result).toBe("tg://user?id=123456");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("should format mention with name (ignored in MD)", () => {
|
|
65
|
+
const result = fmt.mentionMD(123456, "John Doe");
|
|
66
|
+
expect(result).toBe("tg://user?id=123456");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("should format hashtag", () => {
|
|
70
|
+
const result = fmt.hashtagMD("test");
|
|
71
|
+
expect(result).toBe("#test");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("should format email link", () => {
|
|
75
|
+
const result = fmt.emailMD("test@example.com");
|
|
76
|
+
expect(result).toBe("[test@example.com](mailto:test@example.com)");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("should format URL link", () => {
|
|
80
|
+
const result = fmt.urlMD("https://example.com");
|
|
81
|
+
expect(result).toBe("[https://example.com](https://example.com)");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should format custom emoji (HTML fallback)", () => {
|
|
85
|
+
const result = fmt.customEmojiMD("5368324170672642286");
|
|
86
|
+
expect(result).toContain('<tg-emoji emoji-id="5368324170672642286">');
|
|
87
|
+
expect(result).toContain("👻");
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe("Raw Helper", () => {
|
|
92
|
+
it("should return input unchanged", () => {
|
|
93
|
+
const markdown = "*Hello* _World_";
|
|
94
|
+
const result = fmt.rawMD(markdown);
|
|
95
|
+
expect(result).toBe(markdown);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should preserve complex markdown", () => {
|
|
99
|
+
const markdown = "[Link](url) `code` **bold**";
|
|
100
|
+
const result = fmt.rawMD(markdown);
|
|
101
|
+
expect(result).toBe(markdown);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe("Combined Formatting", () => {
|
|
106
|
+
it("should format bold + italic", () => {
|
|
107
|
+
const result = `${fmt.boldMD("Bold")} ${fmt.italicMD("Italic")}`;
|
|
108
|
+
expect(result).toBe("*Bold* _Italic_");
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("should format link + code", () => {
|
|
112
|
+
const result = `${fmt.linkMD("Docs", "https://example.com")} - ${fmt.codeMD("v1.0")}`;
|
|
113
|
+
expect(result).toBe("[Docs](https://example.com) - `v1.0`");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("should format complex message", () => {
|
|
117
|
+
const message = `${fmt.boldMD("Title")}\n\n${fmt.codeBlockMD("const x = 1;", "js")}\n\nLink: ${fmt.linkMD("Click", "https://example.com")}`;
|
|
118
|
+
expect(message).toContain("*Title*");
|
|
119
|
+
expect(message).toContain("js"); // language prefix
|
|
120
|
+
expect(message).toContain("const x = 1;");
|
|
121
|
+
expect(message).toContain("[Click](https://example.com)");
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe("Edge Cases", () => {
|
|
126
|
+
it("should handle empty string", () => {
|
|
127
|
+
expect(fmt.boldMD("")).toBe("**"); // Empty string between asterisks
|
|
128
|
+
expect(fmt.italicMD("")).toBe("__"); // Empty string between underscores
|
|
129
|
+
expect(fmt.codeMD("")).toBe("``"); // Empty string between backticks
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("should handle special characters", () => {
|
|
133
|
+
const result = fmt.boldMD("Test [with] (special) chars");
|
|
134
|
+
expect(result).toBe("*Test [with] (special) chars*");
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("should handle unicode", () => {
|
|
138
|
+
const result = fmt.boldMD("🎉 Party! 🎊");
|
|
139
|
+
expect(result).toBe("*🎉 Party! 🎊*");
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("should handle very long text", () => {
|
|
143
|
+
const longText = "a".repeat(1000);
|
|
144
|
+
const result = fmt.boldMD(longText);
|
|
145
|
+
expect(result).toBe(`*${longText}*`);
|
|
146
|
+
expect(result.length).toBe(1002);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe("MarkdownV2 Formatters", () => {
|
|
152
|
+
describe("Text Formatting", () => {
|
|
153
|
+
it("should format bold text", () => {
|
|
154
|
+
const result = fmt.boldMDv2("Hello");
|
|
155
|
+
expect(result).toBe("*Hello*");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("should format italic text", () => {
|
|
159
|
+
const result = fmt.italicMDv2("Hello");
|
|
160
|
+
expect(result).toBe("_Hello_");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("should format underline text", () => {
|
|
164
|
+
const result = fmt.underlineMDv2("Hello");
|
|
165
|
+
expect(result).toBe("__Hello__");
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("should format strikethrough text", () => {
|
|
169
|
+
const result = fmt.strikethroughMDv2("Hello");
|
|
170
|
+
expect(result).toBe("~Hello~");
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("should format spoiler text", () => {
|
|
174
|
+
const result = fmt.spoilerMDv2("Secret");
|
|
175
|
+
expect(result).toBe("||Secret||");
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("should format code text", () => {
|
|
179
|
+
const result = fmt.codeMDv2("const x = 1");
|
|
180
|
+
expect(result).toBe("`const x = 1`");
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("should format code block without language", () => {
|
|
184
|
+
const result = fmt.codeBlockMDv2("const x = 1");
|
|
185
|
+
expect(result).toBe("const x = 1\n");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("should format code block with language", () => {
|
|
189
|
+
const result = fmt.codeBlockMDv2("const x = 1", "javascript");
|
|
190
|
+
expect(result).toBe("javascript\nconst x = 1\n");
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe("Links and Mentions", () => {
|
|
195
|
+
it("should format link", () => {
|
|
196
|
+
const result = fmt.linkMDv2("Google", "https://google.com");
|
|
197
|
+
expect(result).toBe("[Google](https://google.com)");
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("should format mention without name", () => {
|
|
201
|
+
const result = fmt.mentionMDv2(123456);
|
|
202
|
+
expect(result).toBe("[user](tg://user?id=123456)");
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("should format mention with custom name", () => {
|
|
206
|
+
const result = fmt.mentionMDv2(123456, "John Doe");
|
|
207
|
+
expect(result).toBe("[John Doe](tg://user?id=123456)");
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("should format hashtag", () => {
|
|
211
|
+
const result = fmt.hashtagMDv2("test");
|
|
212
|
+
expect(result).toBe("#test");
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("should format email link", () => {
|
|
216
|
+
const result = fmt.emailMDv2("test@example.com");
|
|
217
|
+
expect(result).toBe("[test@example.com](mailto:test@example.com)");
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("should format URL link", () => {
|
|
221
|
+
const result = fmt.urlMDv2("https://example.com");
|
|
222
|
+
expect(result).toBe("[https://example.com](https://example.com)");
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("should format custom emoji", () => {
|
|
226
|
+
const result = fmt.customEmojiMDv2("5368324170672642286");
|
|
227
|
+
expect(result).toContain("👻");
|
|
228
|
+
expect(result).toContain("5368324170672642286");
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
describe("Escape Function", () => {
|
|
233
|
+
it("should escape all reserved characters", () => {
|
|
234
|
+
const text = "_*[]()~`>#+-=|{}.!";
|
|
235
|
+
const result = fmt.escapeMDv2(text);
|
|
236
|
+
expect(result).toBe(
|
|
237
|
+
"\\_\\*\\[\\]\\(\\)\\~\\`\\>\\#\\+\\-\\=\\|\\{\\}\\.\\!",
|
|
238
|
+
);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("should not escape regular text", () => {
|
|
242
|
+
const text = "Hello World 123";
|
|
243
|
+
const result = fmt.escapeMDv2(text);
|
|
244
|
+
expect(result).toBe("Hello World 123");
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("should escape mixed content", () => {
|
|
248
|
+
const text = "Click [here](url) for *bold* text";
|
|
249
|
+
const result = fmt.escapeMDv2(text);
|
|
250
|
+
expect(result).toContain("\\[");
|
|
251
|
+
expect(result).toContain("\\]");
|
|
252
|
+
expect(result).toContain("\\*");
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("should handle empty string", () => {
|
|
256
|
+
const result = fmt.escapeMDv2("");
|
|
257
|
+
expect(result).toBe("");
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it("should escape repeated characters", () => {
|
|
261
|
+
const text = "***";
|
|
262
|
+
const result = fmt.escapeMDv2(text);
|
|
263
|
+
expect(result).toBe("\\*\\*\\*");
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
describe("Raw Helper", () => {
|
|
268
|
+
it("should return input unchanged", () => {
|
|
269
|
+
const markdown = "*Hello* _World_";
|
|
270
|
+
const result = fmt.rawMDv2(markdown);
|
|
271
|
+
expect(result).toBe(markdown);
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
describe("Combined Formatting", () => {
|
|
276
|
+
it("should format bold + italic + underline", () => {
|
|
277
|
+
const result = `${fmt.boldMDv2("Bold")} ${fmt.italicMDv2("Italic")} ${fmt.underlineMDv2("Underline")}`;
|
|
278
|
+
expect(result).toBe("*Bold* _Italic_ __Underline__");
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it("should format strikethrough + spoiler", () => {
|
|
282
|
+
const result = `${fmt.strikethroughMDv2("Old")} ${fmt.spoilerMDv2("Secret")}`;
|
|
283
|
+
expect(result).toBe("~Old~ ||Secret||");
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it("should format complex message", () => {
|
|
287
|
+
const message =
|
|
288
|
+
`${fmt.boldMDv2("Title")}\n\n` +
|
|
289
|
+
`${fmt.codeBlockMDv2("const x = 1;", "js")}\n\n` +
|
|
290
|
+
`Link: ${fmt.linkMDv2("Click", "https://example.com")}\n` +
|
|
291
|
+
`Mention: ${fmt.mentionMDv2(123456, "User")}\n` +
|
|
292
|
+
`Hashtag: ${fmt.hashtagMDv2("test")}`;
|
|
293
|
+
|
|
294
|
+
expect(message).toContain("*Title*");
|
|
295
|
+
expect(message).toContain("js"); // language prefix
|
|
296
|
+
expect(message).toContain("const x = 1;");
|
|
297
|
+
expect(message).toContain("[Click]");
|
|
298
|
+
expect(message).toContain("[User](tg://user?id=123456)");
|
|
299
|
+
expect(message).toContain("#test");
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
describe("Edge Cases", () => {
|
|
304
|
+
it("should handle empty string", () => {
|
|
305
|
+
expect(fmt.boldMDv2("")).toBe("**"); // Empty string between asterisks
|
|
306
|
+
expect(fmt.italicMDv2("")).toBe("__"); // Empty string between underscores
|
|
307
|
+
expect(fmt.underlineMDv2("")).toBe("____"); // Empty string between double underscores
|
|
308
|
+
expect(fmt.strikethroughMDv2("")).toBe("~~"); // Empty string between tildes
|
|
309
|
+
expect(fmt.spoilerMDv2("")).toBe("||||"); // Empty string between double pipes
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it("should handle special characters that need escaping", () => {
|
|
313
|
+
const text = "Text with [brackets] and (parens)";
|
|
314
|
+
const escaped = fmt.escapeMDv2(text);
|
|
315
|
+
expect(escaped).toContain("\\[");
|
|
316
|
+
expect(escaped).toContain("\\]");
|
|
317
|
+
expect(escaped).toContain("\\(");
|
|
318
|
+
expect(escaped).toContain("\\)");
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it("should handle unicode", () => {
|
|
322
|
+
const result = fmt.boldMDv2("🎉 Party! 🎊");
|
|
323
|
+
expect(result).toBe("*🎉 Party! 🎊*");
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it("should handle very long text", () => {
|
|
327
|
+
const longText = "a".repeat(1000);
|
|
328
|
+
const result = fmt.boldMDv2(longText);
|
|
329
|
+
expect(result).toBe(`*${longText}*`);
|
|
330
|
+
expect(result.length).toBe(1002);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it("should escape all reserved chars in formatter context", () => {
|
|
334
|
+
const text = "Text with * and _ and ~ and |";
|
|
335
|
+
const escaped = fmt.escapeMDv2(text);
|
|
336
|
+
expect(escaped).toContain("\\*");
|
|
337
|
+
expect(escaped).toContain("\\_");
|
|
338
|
+
expect(escaped).toContain("\\~");
|
|
339
|
+
expect(escaped).toContain("\\|");
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
describe("MarkdownV2-Specific Features", () => {
|
|
344
|
+
it("should format underline which is MDv2-only", () => {
|
|
345
|
+
const result = fmt.underlineMDv2("Important");
|
|
346
|
+
expect(result).toBe("__Important__");
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it("should format strikethrough which is MDv2-only", () => {
|
|
350
|
+
const result = fmt.strikethroughMDv2("Deleted");
|
|
351
|
+
expect(result).toBe("~Deleted~");
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it("should format spoiler which is MDv2-only", () => {
|
|
355
|
+
const result = fmt.spoilerMDv2("Surprise!");
|
|
356
|
+
expect(result).toBe("||Surprise!||");
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it("should combine multiple MDv2-exclusive features", () => {
|
|
360
|
+
const result =
|
|
361
|
+
`${fmt.underlineMDv2("Under")} ` +
|
|
362
|
+
`${fmt.strikethroughMDv2("Strike")} ` +
|
|
363
|
+
`${fmt.spoilerMDv2("Spoiler")}`;
|
|
364
|
+
expect(result).toBe("__Under__ ~Strike~ ||Spoiler||");
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
describe("Markdown vs MarkdownV2 Comparison", () => {
|
|
370
|
+
it("should format bold the same way", () => {
|
|
371
|
+
expect(fmt.boldMD("Test")).toBe(fmt.boldMDv2("Test"));
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it("should format italic the same way", () => {
|
|
375
|
+
expect(fmt.italicMD("Test")).toBe(fmt.italicMDv2("Test"));
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it("should format code the same way", () => {
|
|
379
|
+
expect(fmt.codeMD("Test")).toBe(fmt.codeMDv2("Test"));
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
it("should format code block the same way", () => {
|
|
383
|
+
expect(fmt.codeBlockMD("Test")).toBe(fmt.codeBlockMDv2("Test"));
|
|
384
|
+
expect(fmt.codeBlockMD("Test", "js")).toBe(fmt.codeBlockMDv2("Test", "js"));
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
it("should differ in underline (MD uses HTML, MDv2 uses __)", () => {
|
|
388
|
+
expect(fmt.underlineMD("Test")).toBe("<u>Test</u>");
|
|
389
|
+
expect(fmt.underlineMDv2("Test")).toBe("__Test__");
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it("should differ in strikethrough (MD uses HTML, MDv2 uses ~)", () => {
|
|
393
|
+
expect(fmt.strikethroughMD("Test")).toBe("<s>Test</s>");
|
|
394
|
+
expect(fmt.strikethroughMDv2("Test")).toBe("~Test~");
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it("should differ in spoiler (MD uses HTML, MDv2 uses ||)", () => {
|
|
398
|
+
expect(fmt.spoilerMD("Test")).toBe("<tg-spoiler>Test</tg-spoiler>");
|
|
399
|
+
expect(fmt.spoilerMDv2("Test")).toBe("||Test||");
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it("should differ in mention (MD is URL-only, MDv2 is link)", () => {
|
|
403
|
+
expect(fmt.mentionMD(123456, "John")).toBe("tg://user?id=123456");
|
|
404
|
+
expect(fmt.mentionMDv2(123456, "John")).toBe("[John](tg://user?id=123456)");
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
it("should have different escape functions", () => {
|
|
408
|
+
const text = "*_[]()~`>#+-=|{}.!";
|
|
409
|
+
const mdEscaped = fmt.escapeMarkdown(text);
|
|
410
|
+
const mdv2Escaped = fmt.escapeMarkdownV2(text);
|
|
411
|
+
|
|
412
|
+
expect(mdEscaped).not.toBe(mdv2Escaped);
|
|
413
|
+
expect(mdv2Escaped).toContain("\\~");
|
|
414
|
+
expect(mdv2Escaped).toContain("\\>");
|
|
415
|
+
expect(mdv2Escaped).toContain("\\#");
|
|
416
|
+
});
|
|
417
|
+
});
|