2 分钟#tooling #node
让 Markdown 和 Obsidian 对齐
目标是「把 vault 里的笔记直接拖进 content/ 就能发」,于是渲染器把 callout、脚注、内链、任务列表、表格对齐全部补齐了,还顺手收拾了中文软换行。
写作环境是 Obsidian,发布环境是一个零依赖的 Node 脚本。两边语法不一致的话,每次发文都要先检查一遍——那就本末倒置了。
这一轮把渲染器补齐到「复制过来就能发」。
必须支持的清单
| 语法 | 处理方式 |
|---|---|
#–###### |
h1 降级为 h2,自动锚点,重复 id 加后缀 |
**粗** *斜* ~~删~~ ==高亮== |
与 Obsidian 一致 |
| 围栏 / 缩进代码 | 语言 class、完整转义 |
[文本](url) / 裸 URL |
外链自动加 rel="noopener" |
![[图片.webp]] |
内嵌图,读真实宽高防抖 |
任务列表 - [ ] |
真 checkbox(禁用态),完成项加删除线 |
| 引用 / 嵌套引用 | 支持引用里放列表和代码 |
| 表格 + 对齐 | .table-wrap 横向滚动 |
脚注 [^1] |
文末脚注区 + 双向锚点 |
内链 [[笔记]] |
渲染成斜体标记,构建时提示未解析 |
callout > [!note] |
按类型着色 + 图标 + 标题 |
| `` | 整段删除 |
callout 是回报率最高的一项
以前写提示框要手搓 HTML:
<div class="callout callout--warning">…</div>
现在只要:
> [!warning] 注意
> 位移场每帧重算会掉帧。
渲染器会认领首行的 [!type],把剩下的内容当成正常的块级 Markdown 继续渲染——所以 callout 里照样能放列表、代码、链接。
未知识别
没见过的 type 不会炸,会降级成普通引用块,同时打一条构建警告。
内链:诚实地提示
静态站没有「双链索引」,所以我没打算假装有:
参考 [[搜索相似度算法·设计]] 里的阈值公式。
渲染成 <span class="wikilink">(斜体 + 虚线下划线),鼠标悬停显示「未解析引用」,构建时再打印一行警告。
为什么不做跳转
如果哪天真的做了笔记库,这个 span 换成 <a> 就行。现在造一个假的跳转,只会让人点进去 404。
中文软换行
Markdown 里一个换行不产生空格,但中文被换行拆开时如果补一个空格,就成了「中 文」。
const a = out.slice(-1);
const b = line[0];
out += CJK.test(a) && CJK.test(b) ? line : ' ' + line;
两端都是中日韩字符就贴着,否则补空格。三行代码,解决了困扰我很久的排版问题。
测试
渲染器现在有 152 条断言:每种语法的关键 HTML、目录编号(1 / 1.1 / 1.1.1)、脚注双向锚点、未解析内链告警、代码块里的 <script> 是否被转义……
跑一次不到 100ms,构建前顺手执行:
node scripts/test-markdown.mjs
152/152 通过,剩下的事交给写作。