跳到內容

快速上手

先備知識: 什麼是 MDI?核心概念 ―— 本頁假設你已經知道 IR、span、診斷是什麼。也需要 Node.js 20 以上版本。

本頁實作的是 MDI 2.0,其規範性、人類可讀的定義是 SYNTAX.md。以下每個指令與程式碼都可以直接複製貼上執行 ―— 全都對應本專案實際發布的套件,沒有任何空想成分。

建立 novel.mdi

---
mdi: "2.0"
title: 雪女
author: 小泉八雲
lang: ja
writing-mode: vertical
---
# 第一章
{雪女|ゆき.おんな}が現れたのは、第^12^話のことだった。
彼は[[em:決して]]忘れないと誓った。[[br]]
その日は大安[[warichu:六曜の一つで吉日とされる]]であった。

全域安裝 CLI:

Terminal window
npm install --global @illusions-lab/mdi-cli

執行它:

Terminal window
mdi build novel.mdi --to html
Written /path/to/novel.html

完整的指令形式,直接取自 CLI 自己的用法訊息:

mdi build <input.mdi> --to html|pdf|epub|docx|txt|txt-ruby|narou|kakuyomu|aozora|txt-all [--config export.json] [-o <output>]
旗標意義
--to <format>必要。上述格式之一。
-o <path>選用。輸出路徑。省略時,輸出檔會寫在輸入檔旁,使用該格式的副檔名 —— novel.mdi --to pdf 會寫出 novel.pdf--to txt-ruby 會寫出 novel_ruby.txt(CLI 把文字變體命名為 <stem>_<variant>.txt,純 txt 則沒有後綴)。
--config <path>選用。指向匯出設定檔 JSON 檔的路徑,控制頁面大小、字型、邊界與文字縮排設定。

試試每一種輸出格式:

Terminal window
mdi build novel.mdi --to html # novel.html
mdi build novel.mdi --to pdf # novel.pdf
mdi build novel.mdi --to epub -o dist/novel.epub # dist/novel.epub
mdi build novel.mdi --to docx # novel.docx
mdi build novel.mdi --to txt # novel.txt ―— ruby 會被捨棄
mdi build novel.mdi --to txt-ruby # novel_ruby.txt ―— ruby 保留為 {base|reading}
mdi build novel.mdi --to narou # novel_narou.txt ―— 小説家になろう 記法
mdi build novel.mdi --to kakuyomu # novel_kakuyomu.txt ―— カクヨム 記法
mdi build novel.mdi --to aozora # novel_aozora.txt ―— 青空文庫 記法,以 Shift_JIS 編碼
mdi build novel.mdi --to txt-all # 一次寫出全部六種文字檔;不接受 -o
  • HTML、TXT/txt-ruby/narou/kakuyomu/aozora、EPUB、DOCX 全都直接由 Rust 核心渲染(@illusions-lab/mdirenderHtmlrenderTextFormatrenderEpubrenderDocx)―— CLI 中間不會重新剖析或重新詮釋任何東西。
  • PDF 會把同一份 Rust 渲染出的 HTML 交給本機安裝的 Chromium 系瀏覽器,由它負責分頁並呼叫 printToPDF。Chromium 完全不會收到 .mdi 原始碼,也不做任何語法判斷。如果找不到 Chromium 系瀏覽器,指令會失敗並顯示指名缺少哪個相依項目的錯誤 —— 指定特定執行檔的方式請見渲染模型
  • aozora 輸出時會以 Shift_JIS 編碼,符合青空文庫自己投稿工具的期待格式;其他每種文字變體都以 UTF-8 寫出。

CLI 不會印出 stack trace。任何失敗都只會在 stderr 寫一行,並以結束碼 1 結束程序:

Terminal window
mdi build missing.mdi --to html
ENOENT: no such file or directory, open 'missing.mdi'
Terminal window
mdi build novel.mdi --to svg
Usage: mdi build <input.mdi> --to html|pdf|epub|docx|txt|txt-ruby|narou|kakuyomu|aozora|txt-all [--config export.json] [-o <output>]

無法識別的 --to 值(或任何其他格式錯誤的引數列)都會印出上面的用法訊息,而不是嘗試猜測你的意圖。

如果你是在打造應用程式而不是呼叫 CLI,安裝主要套件:

Terminal window
npm install @illusions-lab/mdi
import { readFile } from "node:fs/promises";
import { parse, renderHtml } from "@illusions-lab/mdi";
const source = await readFile("novel.mdi", "utf8");
const { document, diagnostics, syntaxVersion, irVersion } = parse(source);
console.log(syntaxVersion, irVersion); // "2.0" "1.0"
console.log(diagnostics); // 這份檔案是 [] ―— 沒什麼好警告的
console.log(document.frontmatter.entries);
// [{ key: "mdi", value: "2.0" }, { key: "title", value: "雪女" }, ...]
const html = renderHtml(source);

parse 完全不需要宿主端的 Markdown parser ―— CommonMark、GFM、front matter、MDI 全部在單一次 parse 呼叫裡決定。一般的格式錯誤會回傳可用的文件加上(通常是空的)診斷;try/catch 留給程式設計錯誤使用,例如傳入非字串:

parse(42); // 丟出 TypeError: source must be a string

每個匯出函式(renderEpubrenderDocxrenderTextrenderTextFormatserializeMdi)的完整簽章與範例請見 Bindings: JavaScript / TypeScript

novel.mdi 開頭的 front matter 區塊是普通的 YAML,在同一次 parse() 呼叫中被剖析:

---
mdi: "2.0"
title: 雪女
author: 小泉八雲
lang: ja
writing-mode: vertical
---
  • mdi 聲明文件所針對的語法版本。省略時,剖析器會假設自己所支援的最新版本。若聲明的版本新於剖析器支援的版本,會得到一個 mdi.version.unsupported 警告診斷 ―— 剖析仍會以盡力而為的方式繼續進行(見診斷)。
  • writing-mode: vertical 會改變 renderHtml 的排版方式(在根元素加上 writing-mode: vertical-rl),這也是縱中橫與傍點之所以存在的原因 ―— 兩者都是直排排版的裝置,在橫排下也能優雅地退化。
  • 鍵的順序與未知的鍵都會保留在 document.frontmatter.entries 裡;renderer 對不認識的鍵不會報錯,只會忽略。

除非你已經有一套期待 mdast 節點的 unified 管線(例如 Astro、某個靜態網站產生器、以 remark 為基礎的檢查工具),否則可以跳過這一節。@illusions-lab/mdi-remark 是一個adapter,不是第二個剖析器 ―— 它呼叫的是同一個 Rust parse(),只是把結果重新整形成 mdast

import { unified } from "unified";
import remarkMdi from "@illusions-lab/mdi-remark";
import remarkStringify from "remark-stringify";
const processor = unified().use(remarkMdi).use(remarkStringify);
const tree = processor.parse(await readFile("novel.mdi", "utf8"));

哪些東西能正確往返轉換、哪些不行的完整細節,請見 Remark / mdast adapter