feat: v0.2.5 — 内置语法高亮 + exportPDF + benchmark + CI 并行

- 新增 src/highlight.ts 零依赖轻量高亮器:13 种语言,先转义后
  着色保证安全,输出 me-hl-* 类,MeEditor.highlight 即插即用
- exportTool 新增 editor.exportPDF()(隐藏 iframe + window.print),
  exportHTML/exportPDF 共用 HTML 构建逻辑
- imagePaste 支持 maxSizeKB 限制,超限 toast 警告
- npm run bench 性能基准:parseMarkdown 1MB ≈ 51ms
- CI 测试拆分为 parser/core/rest 三个并行 job + 跨版本 verify job
- docs.html/README 补齐新 API、事件、高亮文档;取消跟踪 dist 产物;
  版本 0.2.4 → 0.2.5,测试 725 → 768
This commit is contained in:
2026-08-09 08:59:55 +08:00
parent fae31bba60
commit 5919dd9f66
13 changed files with 641 additions and 58 deletions
+8 -8
View File
@@ -4,7 +4,7 @@
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📝</text></svg>"/>
<title>MetonaEditor v0.2.4 — 全功能演示</title>
<title>MetonaEditor v0.2.5 — 全功能演示</title>
<style>
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
:root{--app-bg:#f5f6f8;--app-text:#1a1a2e;--app-card:#fff;--app-border:#e5e7eb;--app-accent:#3b82f6;--app-accent2:#8b5cf6;--header-bg:linear-gradient(135deg,#1e293b 0%,#0f172a 100%);--header-text:#f1f5f9;--badge-bg:rgba(255,255,255,.12);--badge-text:#e2e8f0}
@@ -45,11 +45,11 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Micr
<body>
<header class="header">
<h1><span class="grad">Metona</span>Editor v0.2.4</h1>
<h1><span class="grad">Metona</span>Editor v0.2.5</h1>
<div class="badges">
<span class="badge">TypeScript</span>
<span class="badge">零运行时依赖</span>
<span class="badge">725 tests</span>
<span class="badge">768 tests</span>
<span class="badge">6 个插件</span>
<span class="badge">桌面端优先</span>
</div>
@@ -91,7 +91,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Micr
</div>
<footer class="footer">
MetonaEditor v0.2.4 · TypeScript · <a href="index.html">首页</a> · <a href="docs.html">API 文档</a> · <a href="https://git.metona.cn/MetonaTeam/MetonaEditor" target="_blank" rel="noopener">源码仓库</a> · MIT
MetonaEditor v0.2.5 · TypeScript · <a href="index.html">首页</a> · <a href="docs.html">API 文档</a> · <a href="https://git.metona.cn/MetonaTeam/MetonaEditor" target="_blank" rel="noopener">源码仓库</a> · MIT
</footer>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
@@ -99,12 +99,12 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Micr
<script>
(function(){
var demoMd=[
'# 🚀 MetonaEditor v0.2.4 全功能演示',
'# 🚀 MetonaEditor v0.2.5 全功能演示',
'',
'> TypeScript 重构 · 零运行时依赖 · **桌面端** Markdown Editor 库。',
'> 全模块 TypeScript 严格模式,12 个源文件,725 个测试全部通过。',
'> 全模块 TypeScript 严格模式,12 个源文件,768 个测试全部通过。',
'',
'## ✨ v0.2.4 新特性',
'## ✨ v0.2.5 新特性',
'',
'- 浮动格式工具栏:选中文本自动弹出 bold/italic/code/link',
'- 新增 `getSelectedText()` `getCursorPosition()` 等 10+ API',
@@ -139,7 +139,7 @@ var demoMd=[
'',
'| 版本 | 日期 | 测试 | 主题 |',
'| :--- | :---: | ---: | --- |',
'| v0.2.4 | 2026-07 | 725 | 浮动工具栏+新API |',
'| v0.2.5 | 2026-08 | 768 | 浮动工具栏+新API |',
'| v0.2.2 | 2026-07 | 694 | 法语+表格格式化 |',
'| v0.2.1 | 2026-07 | 684 | 引用链接+右键菜单 |',
'| v0.2.0 | 2026-07 | 610 | TypeScript 重构 |',
+47 -6
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📖</text></svg>"/>
<title>MetonaEditor v0.2.4 · 文档</title>
<title>MetonaEditor v0.2.5 · 文档</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
:root{--bg:#0f1117;--bg-soft:#161922;--card:#1c2029;--card-hover:#232834;--text:#e6e8eb;--muted:#9ca3af;--accent:#3b82f6;--accent-2:#8b5cf6;--accent-soft:rgba(59,130,246,.12);--border:rgba(255,255,255,.08);--gradient:linear-gradient(135deg,#3b82f6 0%,#8b5cf6 50%,#ec4899 100%)}
@@ -65,7 +65,7 @@ footer a{color:var(--accent);text-decoration:none}
<header class="docs-header">
<h1><span class="grad">API 文档</span></h1>
<p class="sub">MetonaEditor v0.2.4 · TypeScript · 完整配置、API 与使用指南</p>
<p class="sub">MetonaEditor v0.2.5 · TypeScript · 完整配置、API 与使用指南</p>
</header>
<div class="container">
@@ -78,6 +78,7 @@ footer a{color:var(--accent);text-decoration:none}
<a href="#toolbar">工具栏</a>
<div class="toc-group">实例 API</div>
<a href="#api-content">内容操作</a>
<a href="#api-cursor">光标与选区</a>
<a href="#api-exec">命令执行</a>
<a href="#api-history">历史栈</a>
<a href="#api-mode">模式 / 全屏 / Zen</a>
@@ -89,6 +90,8 @@ footer a{color:var(--accent);text-decoration:none}
<a href="#api-destroy">生命周期</a>
<div class="toc-group">静态 API</div>
<a href="#static-api">全局函数</a>
<div class="toc-group">语法高亮</div>
<a href="#highlight">内置高亮器</a>
<div class="toc-group">解析器</div>
<a href="#parser-syntax">语法参考</a>
<a href="#parser-api">解析器 API</a>
@@ -142,6 +145,8 @@ footer a{color:var(--accent);text-decoration:none}
historyLimit<span class="c-punc">:</span> <span class="c-num">100</span><span class="c-punc">,</span> historyDebounce<span class="c-punc">:</span> <span class="c-num">400</span><span class="c-punc">,</span>
syncScroll<span class="c-punc">:</span> <span class="c-kw">true</span><span class="c-punc">,</span> autoBrackets<span class="c-punc">:</span> <span class="c-kw">true</span><span class="c-punc">,</span>
zenMode<span class="c-punc">:</span> <span class="c-kw">false</span><span class="c-punc">,</span> wordWrap<span class="c-punc">:</span> <span class="c-kw">true</span><span class="c-punc">,</span>
maxLength<span class="c-punc">:</span> <span class="c-num">0</span><span class="c-punc">,</span> <span class="c-com">// 最大字符数(0=不限)</span>
floatingToolbar<span class="c-punc">:</span> <span class="c-kw">true</span><span class="c-punc">,</span> <span class="c-com">// 选中文本浮动格式栏</span>
<span class="c-com">// 主题 / 语言</span>
theme<span class="c-punc">:</span> <span class="c-str">'auto'</span><span class="c-punc">,</span> locale<span class="c-punc">:</span> <span class="c-str">'zh-CN'</span><span class="c-punc">,</span>
@@ -194,9 +199,23 @@ editor<span class="c-punc">.</span><span class="c-fn">getHTML</span><span class=
editor<span class="c-punc">.</span><span class="c-fn">refresh</span><span class="c-punc">();</span> <span class="c-com">// 强制重渲染</span>
editor<span class="c-punc">.</span><span class="c-fn">insert</span><span class="c-punc">(</span>text<span class="c-punc">,</span> <span class="c-punc">{</span> replace <span class="c-punc">});</span> <span class="c-com">// => this</span>
editor<span class="c-punc">.</span><span class="c-fn">wrap</span><span class="c-punc">(</span>before<span class="c-punc">,</span> after<span class="c-punc">);</span> <span class="c-com">// => this</span>
editor<span class="c-punc">.</span><span class="c-fn">replaceAll</span><span class="c-punc">(</span>search<span class="c-punc">,</span> replace<span class="c-punc">,</span> caseSensitive<span class="c-punc">)</span> <span class="c-com">// => 替换数</span>
editor<span class="c-punc">.</span><span class="c-fn">replaceAllRegex</span><span class="c-punc">(</span>pattern<span class="c-punc">,</span> replace<span class="c-punc">)</span> <span class="c-com">// => 替换数</span>
editor<span class="c-punc">.</span><span class="c-fn">lineCount</span><span class="c-punc">();</span> <span class="c-fn">getLine</span><span class="c-punc">(</span>n<span class="c-punc">);</span>
editor<span class="c-punc">.</span><span class="c-fn">copyAsMarkdown</span><span class="c-punc">();</span> <span class="c-fn">copyAsHTML</span><span class="c-punc">();</span> <span class="c-com">// 剪贴板</span>
editor<span class="c-punc">.</span><span class="c-fn">focus</span><span class="c-punc">();</span> <span class="c-fn">blur</span><span class="c-punc">();</span></pre>
</section>
<section id="api-cursor"><h3>光标与选区</h3>
<pre>editor<span class="c-punc">.</span><span class="c-fn">getSelectedText</span><span class="c-punc">();</span> <span class="c-com">// => string</span>
editor<span class="c-punc">.</span><span class="c-fn">getCursorPosition</span><span class="c-punc">();</span> <span class="c-com">// => { line, column }</span>
editor<span class="c-punc">.</span><span class="c-fn">setCursorPosition</span><span class="c-punc">(</span>line<span class="c-punc">,</span> column<span class="c-punc">);</span> <span class="c-com">// => this</span>
editor<span class="c-punc">.</span><span class="c-fn">scrollToLine</span><span class="c-punc">(</span>line<span class="c-punc">);</span> <span class="c-com">// => this</span>
editor<span class="c-punc">.</span><span class="c-fn">selectLine</span><span class="c-punc">(</span>line<span class="c-punc">);</span> <span class="c-com">// => this</span>
editor<span class="c-punc">.</span><span class="c-fn">selectAll</span><span class="c-punc">();</span> <span class="c-com">// => this</span></pre>
<p>伴随事件 <code>selectionChange</code><code>{ start, end, text }</code>)与 <code>cursorMove</code><code>{ line, column }</code>)。</p>
</section>
<section id="api-exec"><h3>命令执行</h3>
<pre>editor<span class="c-punc">.</span><span class="c-fn">exec</span><span class="c-punc">(</span>action<span class="c-punc">)</span> <span class="c-com">// => this, 支持链式</span></pre>
<table>
@@ -227,11 +246,12 @@ editor<span class="c-punc">.</span><span class="c-fn">focus</span><span class="c
editor<span class="c-punc">.</span><span class="c-fn">canUndo</span><span class="c-punc">();</span> editor<span class="c-punc">.</span><span class="c-fn">canRedo</span><span class="c-punc">();</span></pre>
</section>
<section id="api-mode"><h3>模式 / 全屏 / Zen</h3>
<section id="api-mode"><h3>模式 / 全屏 / Zen / 浮动工具栏</h3>
<pre>editor<span class="c-punc">.</span><span class="c-fn">setMode</span><span class="c-punc">(</span><span class="c-str">'split'</span><span class="c-punc">);</span> editor<span class="c-punc">.</span><span class="c-fn">getMode</span><span class="c-punc">();</span>
editor<span class="c-punc">.</span><span class="c-fn">toggleFullscreen</span><span class="c-punc">();</span> <span class="c-fn">isFullscreen</span><span class="c-punc">();</span> <span class="c-fn">exitFullscreen</span><span class="c-punc">();</span>
editor<span class="c-punc">.</span><span class="c-fn">toggleZen</span><span class="c-punc">();</span> <span class="c-fn">isZen</span><span class="c-punc">();</span>
editor<span class="c-punc">.</span><span class="c-fn">toggleWordWrap</span><span class="c-punc">();</span> <span class="c-fn">setWordWrap</span><span class="c-punc">(</span><span class="c-kw">true</span><span class="c-punc">);</span> <span class="c-fn">isWordWrap</span><span class="c-punc">();</span></pre>
editor<span class="c-punc">.</span><span class="c-fn">toggleZen</span><span class="c-punc">();</span> <span class="c-fn">isZen</span><span class="c-punc">();</span> <span class="c-com">// 或配置 zenMode: true 启动即进入</span>
editor<span class="c-punc">.</span><span class="c-fn">toggleWordWrap</span><span class="c-punc">();</span> <span class="c-fn">setWordWrap</span><span class="c-punc">(</span><span class="c-kw">true</span><span class="c-punc">);</span> <span class="c-fn">isWordWrap</span><span class="c-punc">();</span>
editor<span class="c-punc">.</span><span class="c-fn">toggleFloatingToolbar</span><span class="c-punc">();</span> <span class="c-fn">isFloatingToolbar</span><span class="c-punc">();</span> <span class="c-com">// 选中文本格式栏</span></pre>
</section>
<section id="api-stats"><h3>统计与状态</h3>
@@ -251,6 +271,7 @@ editor<span class="c-punc">.</span><span class="c-fn">setReadOnly</span><span cl
<tr><th>事件</th><th>触发时机</th><th>参数</th></tr>
<tr><td><code>input</code></td><td>textarea 输入</td><td><code>(value, editor)</code></td></tr>
<tr><td><code>change</code></td><td>内容变化</td><td><code>(value, editor)</code></td></tr>
<tr><td><code>beforeChange</code> / <code>afterChange</code></td><td>内容变更前后</td><td><code>(oldValue, newValue, editor)</code></td></tr>
<tr><td><code>focus</code> / <code>blur</code></td><td>聚焦/失焦</td><td><code>(editor)</code></td></tr>
<tr><td><code>save</code></td><td>Ctrl+S</td><td><code>(editor)</code></td></tr>
<tr><td><code>modeChange</code></td><td>模式切换</td><td><code>(mode, editor)</code></td></tr>
@@ -258,10 +279,14 @@ editor<span class="c-punc">.</span><span class="c-fn">setReadOnly</span><span cl
<tr><td><code>themeChange</code></td><td>主题变更</td><td><code>({ theme, resolved, config })</code></td></tr>
<tr><td><code>localeChange</code></td><td>语言变更</td><td><code>({ locale, direction })</code></td></tr>
<tr><td><code>zenChange</code></td><td>Zen 切换</td><td><code>(zen, editor)</code></td></tr>
<tr><td><code>selectionChange</code></td><td>选区变化</td><td><code>({ start, end, text })</code></td></tr>
<tr><td><code>cursorMove</code></td><td>光标移动</td><td><code>({ line, column })</code></td></tr>
<tr><td><code>destroy</code></td><td>销毁</td><td><code>()</code></td></tr>
<tr><td><code>beforeRender</code> / <code>afterRender</code></td><td>渲染前后</td><td><code>(editor)</code></td></tr>
<tr><td><code>autosave</code></td><td>autoSave 触发</td><td><code>({ key, value })</code></td></tr>
<tr><td><code>linkClick</code></td><td>预览链接点击</td><td><code>({ href, text })</code></td></tr>
<tr><td><code>copy</code></td><td>复制到剪贴板</td><td><code>({ type })</code></td></tr>
<tr><td><code>fileOpened</code> / <code>fileSaved</code></td><td>fileSystem 读写</td><td><code>({ name, handle })</code></td></tr>
</table>
<h4>全局钩子</h4>
<table>
@@ -313,6 +338,22 @@ MeEditor<span class="c-punc">.</span><span class="c-fn">setLocale</span><span cl
<span class="c-kw">import</span> <span class="c-punc">{</span> parseMarkdown<span class="c-punc">,</span> parseTokens<span class="c-punc">,</span> renderTokens <span class="c-punc">}</span> <span class="c-kw">from</span> <span class="c-str">'@metona-team/metona-editor'</span><span class="c-punc">;</span></pre>
</section>
<!-- 语法高亮 -->
<section id="highlight"><h2>内置语法高亮</h2>
<p>v0.2.5 起内置零依赖轻量高亮器,支持 js / ts / tsx / jsx / python / bash / css / html / json / yaml / markdown / java / go / rust。</p>
<pre><span class="c-kw">import</span> MeEditor <span class="c-kw">from</span> <span class="c-str">'@metona-team/metona-editor'</span><span class="c-punc">;</span>
<span class="c-com">// 方式一:作为 highlight 钩子(代码块自动高亮)</span>
MeEditor<span class="c-punc">.</span><span class="c-fn">create</span><span class="c-punc">(</span><span class="c-str">'#editor'</span><span class="c-punc">,</span> <span class="c-punc">{</span> highlight<span class="c-punc">:</span> MeEditor<span class="c-punc">.</span><span class="c-fn">highlight</span> <span class="c-punc">});</span>
<span class="c-com">// 方式二:独立调用</span>
<span class="c-kw">const</span> html <span class="c-punc">=</span> MeEditor<span class="c-punc">.</span><span class="c-fn">highlight</span><span class="c-punc">(</span>code<span class="c-punc">,</span> <span class="c-str">'typescript'</span><span class="c-punc">);</span>
<span class="c-com">// 注册自定义语言</span>
MeEditor<span class="c-punc">.</span><span class="c-fn">registerLanguage</span><span class="c-punc">(</span><span class="c-str">'myLang'</span><span class="c-punc">,</span> <span class="c-punc">{</span> keywords<span class="c-punc">:</span> <span class="c-punc">[</span><span class="c-str">'kw'</span><span class="c-punc">]</span><span class="c-punc">,</span> builtins<span class="c-punc">:</span> <span class="c-punc">[]</span> <span class="c-punc">});</span></pre>
<p>高亮输出使用 <code>me-hl-keyword</code> / <code>me-hl-string</code> / <code>me-hl-comment</code> / <code>me-hl-number</code> / <code>me-hl-builtin</code> / <code>me-hl-function</code> 类,可用 CSS 变量或选择器定制颜色。</p>
</section>
<!-- 解析器语法 -->
<section id="parser-syntax"><h2>解析器语法参考</h2>
<table>
@@ -433,7 +474,7 @@ i18nUtils<span class="c-punc">.</span><span class="c-fn">formatDate</span><span
<footer>
<div class="container">
MetonaEditor v0.2.4 · TypeScript · <a href="https://git.metona.cn/MetonaTeam/MetonaEditor" target="_blank" rel="noopener">源码仓库</a> · MIT License
MetonaEditor v0.2.5 · TypeScript · <a href="https://git.metona.cn/MetonaTeam/MetonaEditor" target="_blank" rel="noopener">源码仓库</a> · MIT License
</div>
</footer>
+7 -7
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🚀</text></svg>"/>
<title>MetonaEditor v0.2.4 · TypeScript · 桌面端 Markdown 编辑器</title>
<title>MetonaEditor v0.2.5 · TypeScript · 桌面端 Markdown 编辑器</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
:root{--bg:#0f1117;--bg-soft:#161922;--card:#1c2029;--card-hover:#232834;--text:#e6e8eb;--muted:#9ca3af;--accent:#3b82f6;--accent-2:#8b5cf6;--accent-3:#ec4899;--accent-soft:rgba(59,130,246,.12);--border:rgba(255,255,255,.08);--gradient:linear-gradient(135deg,#3b82f6 0%,#8b5cf6 50%,#ec4899 100%);--shadow:0 20px 50px -20px rgba(0,0,0,.5)}
@@ -106,10 +106,10 @@ footer a:hover{text-decoration:underline}
<h1>TypeScript 重构 · 零依赖<br/><span class="grad">桌面端 Markdown 编辑器</span></h1>
<p class="tagline">全模块 TypeScript 严格模式,内置自研解析器(99% 行覆盖率),6 个预设插件,中文优先。为桌面端现代 Web 应用而生。</p>
<div class="badges">
<span class="badge accent">v0.2.4</span>
<span class="badge accent">v0.2.5</span>
<span class="badge">TypeScript</span>
<span class="badge">零运行时依赖</span>
<span class="badge">725 tests</span>
<span class="badge">768 tests</span>
<span class="badge">桌面端优先</span>
<span class="badge">MIT</span>
</div>
@@ -120,7 +120,7 @@ footer a:hover{text-decoration:underline}
<div class="stats">
<div class="stat"><div class="stat-num">0</div><div class="stat-label">运行时依赖</div></div>
<div class="stat"><div class="stat-num">99%</div><div class="stat-label">解析器行覆盖</div></div>
<div class="stat"><div class="stat-num">725</div><div class="stat-label">单元测试</div></div>
<div class="stat"><div class="stat-num">768</div><div class="stat-label">单元测试</div></div>
<div class="stat"><div class="stat-num">~30KB</div><div class="stat-label">gzip 体积</div></div>
</div>
</header>
@@ -165,7 +165,7 @@ footer a:hover{text-decoration:underline}
<span class="c-kw">const</span> MeEditor <span class="c-punc">=</span> <span class="c-fn">require</span><span class="c-punc">(</span><span class="c-str">'@metona-team/metona-editor'</span><span class="c-punc">);</span>
<span class="c-com">// 方式二:CDN 引入</span>
<span class="c-com">&lt;script src="https://cdn.jsdelivr.net/npm/@metona-team/metona-editor@0.2.4/dist/metona-editor.min.js"&gt;&lt;/script&gt;</span>
<span class="c-com">&lt;script src="https://cdn.jsdelivr.net/npm/@metona-team/metona-editor@0.2.5/dist/metona-editor.min.js"&gt;&lt;/script&gt;</span>
<span class="c-com">// 方式三:本地文件</span>
<span class="c-com">&lt;script src="./dist/metona-editor.min.js"&gt;&lt;/script&gt;</span>
@@ -227,7 +227,7 @@ editor<span class="c-punc">.</span><span class="c-fn">exec</span><span class="c-
<a href="https://git.metona.cn/MetonaTeam/MetonaEditor" target="_blank" rel="noopener">源码仓库</a>
<a href="https://git.metona.cn/MetonaTeam/MetonaEditor/issues" target="_blank" rel="noopener">问题反馈</a>
</div>
<div>MetonaEditor v0.2.4 · TypeScript · MIT License · MetonaTeam</div>
<div>MetonaEditor v0.2.5 · TypeScript · MIT License · MetonaTeam</div>
</div>
</footer>
@@ -237,7 +237,7 @@ MeEditor.themes.switchTheme('dark');
MeEditor.create('#editor', {
mode: 'split', height: 480, theme: 'dark',
value: [
'# 欢迎使用 MetonaEditor v0.2.4',
'# 欢迎使用 MetonaEditor v0.2.5',
'',
'一个 **TypeScript 重构 · 零运行时依赖** 的桌面端 Markdown 编辑器。',
'',