');
+ expect(html).toContain('
');
+ expect(html).not.toContain('');
+ });
+});
+
+describe('parseMarkdown - v0.1.4 HTML 注释', () => {
+ test('HTML 注释被透传', () => {
+ const html = parseMarkdown('');
+ expect(html).toContain('');
+ });
+
+ test('HTML 注释内内容不被转义', () => {
+ const html = parseMarkdown('');
+ expect(html).toContain('');
+ });
+});
+
+describe('parseMarkdown - v0.1.4 实体引用保护', () => {
+ test('已有实体引用不被二次转义', () => {
+ const html = parseMarkdown('AT&T');
+ expect(html).toContain('&');
+ // & 应保持为 & 而非 &
+ expect(html).not.toContain('&');
+ });
+
+ test('数字实体引用被保护', () => {
+ const html = parseMarkdown('© 2024');
+ expect(html).toContain('©');
+ });
+
+ test('十六进制实体引用被保护', () => {
+ const html = parseMarkdown('<');
+ expect(html).toContain('<');
+ });
+});
+
+describe('parseMarkdown - v0.1.4 硬换行', () => {
+ test('行尾2空格产生硬换行', () => {
+ const html = parseMarkdown('line1 \nline2');
+ // 硬换行不应产生单独的
,而是保持为真正的
+ // 软换行 \n 产生
,硬换行(2空格+\n)也应产生
+ // 当前实现:2空格换行和普通换行都生成
+ expect(html).toContain('line1');
+ expect(html).toContain('line2');
+ });
+});
+
+describe('parseMarkdown - v0.1.4 链接标题单引号', () => {
+ test('链接 title 使用单引号', () => {
+ const html = parseMarkdown('[text](https://example.com \'title\')');
+ expect(html).toContain('href="https://example.com"');
+ expect(html).toContain('title="title"');
+ });
+
+ test('链接 title 使用双引号(兼容)', () => {
+ const html = parseMarkdown('[text](https://example.com "title")');
+ expect(html).toContain('title="title"');
+ });
+});
+
+describe('parseMarkdown - v0.1.4 LaTeX 数学公式', () => {
+ test('行内公式 $...$', () => {
+ const html = parseMarkdown('Euler: $e^{i\\pi} = -1$');
+ expect(html).toContain('me-math-inline');
+ expect(html).toContain('e^{i\\pi} = -1');
+ });
+
+ test('块级公式 $$...$$(单行)', () => {
+ const html = parseMarkdown('$$\\int_0^\\infty e^{-x} dx = 1$$');
+ expect(html).toContain('me-math-block');
+ });
+
+ test('块级公式 $$...$$(多行)', () => {
+ const md = '$$\n\\begin{aligned}\nx &= 1 + 2 \\\\\ny &= 3 + 4\n\\end{aligned}\n$$';
+ const html = parseMarkdown(md);
+ expect(html).toContain('me-math-block');
+ expect(html).toContain('\\begin{aligned}');
+ });
+});
+
+describe('parseMarkdown - v0.1.4 脚注', () => {
+ test('脚注引用与定义', () => {
+ const md = 'Text with footnote[^1].\n\n[^1]: This is the footnote.';
+ const html = parseMarkdown(md);
+ expect(html).toContain('me-footnote-ref');
+ expect(html).toContain('fnref-1');
+ expect(html).toContain('me-footnotes');
+ expect(html).toContain('fn-1');
+ expect(html).toContain('This is the footnote.');
+ });
+
+ test('多个脚注', () => {
+ const md = 'First[^a] and second[^b].\n\n[^a]: Note A.\n[^b]: Note B.';
+ const html = parseMarkdown(md);
+ expect(html).toContain('me-footnotes');
+ expect(html).toContain('Note A.');
+ expect(html).toContain('Note B.');
+ });
+});
+
+describe('parseMarkdown - v0.1.4 定义列表', () => {
+ test('基本定义列表', () => {
+ const md = 'Term\n: Definition of the term.';
+ const html = parseMarkdown(md);
+ expect(html).toContain('
');
+ expect(html).toContain('- ');
+ expect(html).toContain('Term');
+ expect(html).toContain('
- ');
+ expect(html).toContain('Definition of the term.');
+ });
+
+ test('多条定义', () => {
+ const md = 'Term\n: Definition 1.\n: Definition 2.';
+ const html = parseMarkdown(md);
+ expect(html).toContain('Definition 1.');
+ expect(html).toContain('Definition 2.');
+ });
+});
+
+describe('parseMarkdown - v0.1.4 反引号精确匹配', () => {
+ test('双反引号包裹单反引号', () => {
+ const html = parseMarkdown('`` ` ``');
+ expect(html).toContain('
');
+ expect(html).toContain('`');
+ });
+
+ test('不同长度反引号串', () => {
+ const html = parseMarkdown('``` `code` ```');
+ expect(html).toContain('');
+ // 应包含原始反引号内容
+ expect(html).toContain('`code`');
+ });
+});
+
+describe('parseMarkdown - v0.1.4 斜体优化', () => {
+ test('*text* 正常斜体', () => {
+ const html = parseMarkdown('a *italic* b');
+ expect(html).toContain('italic');
+ });
+
+ test('*** 不作为斜体', () => {
+ const html = parseMarkdown('***');
+ expect(html).not.toContain('');
+ });
+
+ test('__ 不作为粗体误判', () => {
+ const html = parseMarkdown('__bold__');
+ expect(html).toContain('bold');
+ });
+});
+
+describe('parseMarkdown - v0.1.4 引用块优化', () => {
+ test('引用块 >text 无空格', () => {
+ const html = parseMarkdown('>quote text');
+ expect(html).toContain('');
+ expect(html).toContain('quote text');
+ });
+
+ test('嵌套引用', () => {
+ const html = parseMarkdown('> outer\n>> nested');
+ expect(html).toContain('');
+ expect(html).toContain('outer');
+ });
+});
+
+describe('parseMarkdown - v0.1.4 safeUrl 增强', () => {
+ test('正常 http/https url 通过', () => {
+ expect(safeUrl('http://example.com')).toBe('http://example.com');
+ expect(safeUrl('https://example.com')).toBe('https://example.com');
+ });
+
+ test('mailto: 协议通过', () => {
+ expect(safeUrl('mailto:test@example.com')).toBe('mailto:test@example.com');
+ });
+});
+
+describe('parseMarkdown - v0.1.4 slugify 增强', () => {
+ test('全角字符处理', () => {
+ expect(slugify('你好世界')).toBe('你好世界');
+ });
+
+ test('Unicode NFKC 规范化', () => {
+ // 全角英文字母转半角
+ const slug = slugify('Cat');
+ // NFKC 将全角 C/a/t 转为半角
+ expect(slug).toContain('cat');
+ });
+});
+
+describe('parseMarkdown - v0.1.4 表情扩展', () => {
+ test('新增表情 :confetti:', () => {
+ const html = parseMarkdown(':confetti:');
+ expect(html).toContain('🎊');
+ });
+
+ test('新增表情 :rainbow:', () => {
+ const html = parseMarkdown(':rainbow:');
+ expect(html).toContain('🌈');
+ });
+
+ test('新增表情 :hamburger:', () => {
+ const html = parseMarkdown(':hamburger:');
+ expect(html).toContain('🍔');
+ });
+
+ test('新增表情 :earth:', () => {
+ const html = parseMarkdown(':earth:');
+ expect(html).toContain('🌍');
+ });
+});
+
+describe('parseMarkdown - v0.1.4 代码块语言扩展', () => {
+ test('语言标记支持 # + . 等字符', () => {
+ const html = parseMarkdown('```c++\nint main() {}\n```');
+ expect(html).toContain('language-c++');
+ });
+
+ test('语言标记支持点号', () => {
+ const html = parseMarkdown('```file.txt\ncontent\n```');
+ expect(html).toContain('language-file.txt');
+ });
+});
diff --git a/types/index.d.ts b/types/index.d.ts
index 0ad168c..06df18e 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -1,4 +1,4 @@
-// Type definitions for MetonaEditor
+// Type definitions for MetonaEditor v0.1.4
// Project: https://git.metona.cn/MetonaTeam/MetonaEditor
// Author: thzxx
@@ -243,10 +243,12 @@ export function getStatus(): {
// ============ 解析器 ============
/** Markdown 解析函数 */
export function parseMarkdown(markdown: string, env?: RenderEnv): string;
-/** URL 安全过滤 */
+/** URL 安全过滤(增强版) */
export function safeUrl(url: string): string;
-/** 生成标题锚点 id */
+/** 生成标题锚点 id(Unicode NFKC 规范化) */
export function slugify(text: string): string;
+/** 清除渲染缓存(主题切换等场景) */
+export function clearRenderCache(): void;
// ============ 插件 ============
/** 预设插件表 */