本文说明 markdown-it-ts 与上游 markdown-it 的兼容性合同、主要差异、迁移风险和验证清单。
markdown-it-ts 的目标是兼容 markdown-it 的公开 API,而不是兼容上游包里的每一个私有实现细节。
这些接口属于明确支持的兼容目标:
- 主解析/渲染 API:
parse、parseInline、render、renderInline、renderAsync - 与 markdown-it 行为对齐的公开选项和 preset 风格用法
Tokenshape 和常见 token mutation helperRuler/CoreRuler/BlockRuler/InlineRuler风格的规则注册md.renderer.rules渲染规则扩展- 遵循
function plugin(md, options)模式的常见插件 hook - 本包文档化并通过
exports发布的稳定子路径
这些场景会尽量验证,但迁移时仍需要用户在自己的 workload 上测试:
- 不依赖上游私有文件的第三方 markdown-it 插件
- 在 ESM 项目中通过 Node 或 bundler interop 加载的 CJS 插件
- 使用
renderAsync的异步 renderer/highlight 集成 - 面向大输入或 append-heavy 编辑器场景的 stream、chunked、unbounded、editable-buffer API(通过
markdown-it-ts/experimental使用;部分 helper 也有显式子路径:markdown-it-ts/stream/buffer、markdown-it-ts/stream/chunked、markdown-it-ts/stream/debounced、markdown-it-ts/support/chunk_recommend)
这些模式不属于兼容性承诺:
- 直接导入上游私有路径,例如
markdown-it/lib/... - 依赖未文档化的内部 parser state shape 或规则实现细节
- 在 CommonJS 中直接
require('markdown-it-ts'),而不使用动态import() - Node.js 18 以下运行时
- 假设 chunked 或 streaming API 在尚未看到后续全局定义时,也一定能产出与完整 parse 完全一致的中间结果
- 语言与打包:
markdown-it-ts使用 TypeScript 实现,并以 ESM-only package exports 发布。 - 运行时:要求 Node.js >= 18。
- 子路径导出:请使用文档化的
markdown-it-ts/...exports,不要依赖上游私有路径。 - Renderer 集成:主入口包含
render、renderInline、renderAsync、renderer和 advancedwithRenderer;markdown-it-ts/plugins/with-renderer也保留给 custom/core-shaped instance。 - 大输入 API:
stream、chunkedParse、StreamBuffer、UnboundedBuffer、EditableBuffer是本包扩展能力,只适合特定输入形态,并有独立正确性边界;它们从markdown-it-ts/experimental导入,部分 helper 也可从markdown-it-ts/stream/buffer、markdown-it-ts/stream/chunked、markdown-it-ts/stream/debounced、markdown-it-ts/support/chunk_recommend导入,不从 1.0 根入口导出。
import markdownIt from 'markdown-it-ts'
import emoji from 'markdown-it-emoji'
const md = markdownIt({ html: true })
md.use(emoji)
console.log(md.render('# Hello'))markdown-it-ts 是 ESM-only。CommonJS 项目里使用动态 import:
async function main() {
const { default: markdownIt } = await import('markdown-it-ts')
const md = markdownIt({ html: true })
console.log(md.render('# Hello'))
}
main().catch((error) => {
console.error(error)
process.exitCode = 1
})大多数使用 markdown-it 公开 API 的插件,在替换 import 后应当可以工作。当前 CI 的插件矩阵覆盖 abbreviation、container、definition list、emoji、footnote、inline hook、ins、mark、sub、sup 等常见插件。
以下插件需要重点验证:
- 导入
markdown-it/lib/...等上游内部路径 - patch 未文档化的 state 对象
- 假设 CommonJS-only 加载方式
- 在 streaming/chunked parsing 期间修改 renderer 或 parser state
Markdown 不总是 chunk-local。Reference definition、footnote definition、abbreviation definition,以及插件自定义全局状态,都可能影响前文内容。
chunkedParse() 和完整字符串的 unbounded parsing 默认对已知全局状态语法采用 correctness-first fallback。Iterable/sink parsing 更偏 stream 场景,可能在看到后续定义前就提交前面的 chunk;如果需要严格 full-parse parity,请使用完整字符串解析,或避免过早 flush。
关闭 global-state fallback 属于性能模式,可能产生与 full parse 不同的输出。
- 将导入改为 ESM import,或在 CommonJS 中使用动态
import()。 - 用业务 fixture 同时对比旧版和新版渲染输出。
- 验证所有第三方插件,尤其是依赖上游私有路径的插件。
- 检查安全敏感行为:
html、link validation、highlight 输出,以及外部 sanitization。 - 优先使用普通
md.parse/md.render。只有大输入或 append-heavy workload 才引入 stream/chunk API。 - 如果关注性能,请带上
docs/perf-latest.json记录的 Node、CPU、OS、依赖版本、commit 等元数据复现 benchmark。
markdown-it-ts targets the markdown-it public API, not every private upstream implementation detail.
- Stable: main parse/render APIs,
Tokenshape, ruler APIs, renderer rules, common public plugin hooks, and documented stable package exports. - Best effort: third-party plugins that avoid private upstream files, CJS plugin interop from ESM, async render/highlight integrations, and large-input stream/chunk/editable APIs imported from
markdown-it-ts/experimental; selected helpers also have explicit subpaths:markdown-it-ts/stream/buffer,markdown-it-ts/stream/chunked,markdown-it-ts/stream/debounced, andmarkdown-it-ts/support/chunk_recommend. - Unsupported: private upstream imports such as
markdown-it/lib/..., undocumented internal state dependencies, direct CommonJSrequire('markdown-it-ts'), Node.js < 18, and assuming stream/chunk output is always equivalent before future document-level definitions are known.
Use normal md.parse / md.render first. The stable default path keeps plugin/custom-rule instances on plain full parse unless chunking is explicitly enabled. Adopt stream/chunk APIs only for large-input or append-heavy workloads, and validate output against full parse when exact parity matters.