英語版: spec.md
lobster.js は拡張Markdown方言をパースしてHTML文書構造を生成するライブラリです。
文書の構造だけを提供し、視覚的な表現はCSSに委ねます。 レンダリングされるHTMLには lbs-* クラス名が付与されるため、任意のスタイルシートで装飾できます。
- パースは各行内で前方一致(左から右、最初にマッチしたものが優先)。
- 各行の末尾スペースはパース前に除去する。
- Markdown内のHTMLタグはプレーンテキストとして扱う(エスケープされる)。
- 同じ定義が複数ある場合、後のものが上書きする(例外あり)。
ヘッダー > フッター >>> 詳細折りたたみ =>
引用 => リスト > 見出し > 水平線 > コードブロック > サイレントテーブル > テーブル >
画像 > インライン脚注 > 脚注参照 > ワープ参照 > インラインリンク > リンク >
コードスパン > 強勢 > 強調 > 打ち消し線
:::header / :::footer / :::warp ブロックはドキュメント全体をスキャンする第一パスで抽出され、本文パースの前に取り出される。
# H1
## H2
### H3
#### H4
##### H5
###### H6
#の数がレベル(1〜6)を決める。#とテキストの間には1つ以上のスペースが必要。- 行末のスペース +
#は無視する:# タイトル ##→ H1「タイトル」。 - 同じ行内の他のMarkdown記法も内包できる。
アンカーID(任意):
見出し行の末尾に {#id} を付けると、HTML の id 属性を明示的に指定できる:
## セクション名 {#section-name}
{#id}は表示テキストから除去され、HTML のid属性として出力される。- ページ内リンク(
href="#section-name")や深いリンクに利用できる。
HTML出力:
<h1 class="lbs-heading-1">…</h1>
<!-- ~ -->
<h6 class="lbs-heading-6">…</h6>
<!-- アンカーID付き -->
<h2 class="lbs-heading-2" id="section-name">セクション名</h2>1つ以上の空行を境に段落を区切る。
HTML出力:
<p class="lbs-paragraph">…</p>段落内の改行は <br> に変換される。段落の最後の改行は変換しない。
注意: 行末2スペースによる改行は特別扱いしない。単純な改行で
<br>が入る。
- または * を3つ以上並べる(間にスペースを挟んでもよい):
---
- - -
***
* * *
混在(--** など)は認識しない。
HTML出力:
<hr class="lbs-hr">``` または ~~~ 3文字以上でフェンスする。開始フェンスに言語識別子とオプションのファイル名を付けられる:
```js:filename.js
console.log("Hello");
```
- 言語: フェンスマーカー直後の英数字。
- ファイル名: 言語の後ろに
:ファイル名で指定。使用不可文字:`と:。 - 言語省略可(ファイル名だけも指定可能)。
- コンテンツはプレーンテキスト(Markdownとして解釈しない)。
HTML出力:
<div class="lbs-code-block">
<div class="lbs-code-filename">filename.js</div> <!-- ファイル名なしの場合は省略 -->
<pre data-language="js" data-filename="filename.js"><code>…</code></pre>
</div>行頭の > で始まる行。連続した > 行(または空行なしの続き行)は一つの引用ブロックになる。> を重ねることで多重引用ができる:
> 外側の引用
> > 内側の引用
引用内では他のMarkdown記法を自由に使える。
HTML出力:
<blockquote class="lbs-blockquote">…</blockquote>先頭記号とテキストの間には1つ以上のスペースが必要。
先頭記号: -, *, +
- アイテム
- アイテム
- ネストされたアイテム
インデントが親より深いとサブアイテムになる。ネスト深さはリストノードで管理される。
HTML出力:
<ul class="lbs-ul lbs-ul-depth-0">
<li class="lbs-list-item">…</li>
</ul>先頭記号: N.(Nは任意の整数)
1. 最初
2. 二番目
1. ネスト
N\.(バックスラッシュエスケープ)はリストとして扱わない。start 属性は最初のアイテムの番号を反映する。
HTML出力:
<ol class="lbs-ol lbs-ol-depth-0" start="1">
<li class="lbs-list-item">…</li>
</ol>順序なし・番号付きリスト両方に適用可能:
- [ ] 未チェック
- [x] チェック済み
- [X] チェック済み(大文字でも可)
HTML出力:
<li class="lbs-list-item">
<input type="checkbox" class="lbs-checkbox" disabled> …
<!-- [x]/[X] には checked 属性が付く -->
</li>最低限、ヘッダー行と整列行が必要。行頭・行末の | はなくてもパースできる。
| 名前 | 年齢 |
| ----- | ---- |
| Alice | 30 |
| セル記法 | 意味 |
|---|---|
--- |
デフォルト(CSSの text-align に従う) |
:--- |
左寄せ |
:---: |
中央寄せ |
---: |
右寄せ |
セルの前後にスペースがあっても可。--- や : の間にスペースは不可。
水平結合 — \| はマージマーカーである。2つのセル間の | セパレーターの直前に \ がある場合、左セルが2列分のcolspanを持つ。コンテンツを左セルに書き、右セルを空にする:
| A | B \| |
制約:
\|の両側にコンテンツがある場合(例:| A \| B |)、右側のコンテンツ(B)は無視される。左側のコンテンツ(A)のみが保持され、colspan=2が付与される。結合を明示する場合は| A \| |のように書く。
垂直結合 — \---(ダッシュ1本以上)で上のセルと結合する:
| A | B |
| \--- | C |
ヘッダーより少ないセル数のアイテム行は、空セルで補完される。
HTML出力:
<table class="lbs-table">
<thead><tr><th>…</th></tr></thead>
<tbody><tr><td>…</td></tr></tbody>
</table>整列はインラインスタイル style="text-align:…" で各セルに付与される。
ブロック内のテキストを左から右にパースする。
`code`
バッククォートを含めたい場合は、使いたいバッククォートの数+1で囲む(前後のスペース1つが必要):
code
開始デリミタが2つ以上のバッククォートの場合、コンテンツの先頭・末尾のスペース1つずつが除去される。
HTML出力: <code class="lbs-code-span">…</code>
*テキスト* または _テキスト_
- 開始・終了デリミタは同じ文字でないと認識しない。
- 改行をまたぐことはできない。
**テキスト*→ リテラル*+ 強調*テキスト*。
HTML出力: <span class="lbs-emphasis">…</span>
**テキスト** または __テキスト__
- 開始・終了デリミタは同じ文字でないと認識しない。
- 改行をまたぐことはできない。
***テキスト***→ リテラル*+ 強勢**テキスト**+ リテラル*。
HTML出力: <span class="lbs-strong">…</span>
~~テキスト~~
~~~テキスト~~~のような場合は一番内側のペアのみを認識する。- 改行をまたぐことはできない。
HTML出力: <span class="lbs-strikethrough">…</span>
[テキスト](URL "タイトル")
]と(の間にスペースがあってはいけない。- タイトルは省略可。
"…"/'…'/(…)いずれでもよい。 - テキスト・URLは空でもパースできる。
HTML出力: <a href="URL" title="タイトル">…</a>
[テキスト][id] ← 参照
[id]: URL "タイトル" ← 定義(ドキュメント内のどこでも可)
[テキスト][]— 省略記法: テキスト自体がidになる。[テキスト]— 定義idと一致すれば解決する(暗黙的ショートカット)。- idの照合は大文字・小文字を区別しない。
- タイトルは
"…"/'…'/(…)いずれでもよい。タイトルは次の行に書いてもよい。 - 複数の
[テキスト][id]が一つの定義を共有できる(N対1)。 - 定義行はコンテンツとして出力されない。
HTML出力: <a href="URL" title="タイトル">…</a>

- インラインリンクと同じルール。
!と[の間にスペースは不可。- サイズは省略可:
=800x600、=800x(幅のみ)、=x600(高さのみ)。
HTML出力:
<img src="URL" alt="alt" title="タイトル" width="800" height="600" class="lbs-image">[^id] ← 参照(インライン)
[^id]: テキスト ← 定義(ドキュメント内のどこでも可)
[^id]と[^id]:の中にスペースを入れてはいけない。- 同じ脚注への複数参照は
[1],[1:1],[1:2], … と番号付けされる。 - 定義行はコンテンツとして出力されない。
- 定義はドキュメント末尾に脚注セクションとして出力される。
HTML出力(参照部):
<sup class="lbs-footnote-ref"><a href="#lbs-fn-id">[1]</a></sup>HTML出力(脚注セクション):
<section class="lbs-footnotes">
<ol>
<li id="lbs-fn-id" class="lbs-footnote-item">[1] …</li>
</ol>
</section>^[テキスト]
^と[の間にスペースは不可。- 名前付き脚注参照と同じように動作するが、定義をインラインに書く形式。
- 脚注参照より優先される(前方一致)。
HTML出力: 脚注参照と同じ。
すべてのカスタムブロック(:::header、:::footer、:::details、:::warp)は ::: 行で閉じる。閉じ ::: の先頭の空白は無視されるため、フォーマッターがインデントしても正しく動作する。
推奨スタイル: 閉じ
:::の直前に空行を入れる。これにより、Markdownフォーマッター(Prettierなど)が:::をリスト項目などの継続行として誤って解釈・インデントするのを防げる。
:::header
コンテンツ
:::
- ドキュメントに1つだけ。複数記述した場合は後のものが上書きする。
:::header/:::footer以外のMarkdownを自由に使える。- 本文より先に出力される。
HTML出力:
<header class="lbs-header">…</header>:::footer
コンテンツ
:::
ヘッダーと同じルール。脚注セクション(あれば)の後、ドキュメントの末尾に出力される。
HTML出力:
<footer class="lbs-footer">…</footer>:::details サマリータイトル
コンテンツ
:::
- タイトルは
:::detailsと同じ行に書く。 :::header/:::footer以外のMarkdownを使える。
HTML出力:
<details class="lbs-details">
<summary class="lbs-summary">サマリータイトル</summary>
…
</details>:::warp my-id
コンテンツ
:::
- 名前付きコンテンツブロックを定義し、
[~my-id]で別の場所に展開する。 - idはドキュメント内で一意でなければならない。重複した場合、内容は全てプレーンテキストとして扱われる。
- 使用可能なid文字: 英数字、
-、_。 - 定義場所では出力されず、参照場所でのみ出力される。
ワープ参照:
[~my-id]
サイレントテーブルのセルで使うと段組みレイアウトを作れる。
例:
サイレントテーブルにはヘッダー行と整列行が最低限必要。ワープ参照はヘッダー行(パターンA)またはデータ行(パターンB)のどちらにも書ける。
パターンA — ヘッダー行にワープ参照(コンテンツは <th> に出力される):
~ | [~col-left] | [~col-right] |
~ | :--- | :--- |
:::warp col-left
左カラムのコンテンツ
:::
:::warp col-right
右カラムのコンテンツ
:::
パターンB — データ行にワープ参照(コンテンツは <td> に出力される。レイアウト用途に推奨):
~ | 左 | 右 |
~ | :--- | :--- |
~ | [~col-left] | [~col-right] |
:::warp col-left
左カラムのコンテンツ
:::
:::warp col-right
右カラムのコンテンツ
:::
テーブルの全行に ~ プレフィックスを付けると枠線が非表示になる:
~ | カラム1 | カラム2 |
~ | ------- | ------- |
~ | A | B |
HTML出力:
<table class="lbs-table lbs-table-silent">…</table>| クラス | 要素 |
|---|---|
lbs-heading-1 〜 lbs-heading-6 |
見出し(<h1>〜<h6>) |
lbs-paragraph |
本文段落 |
lbs-emphasis |
斜体スパン |
lbs-strong |
太字スパン |
lbs-strikethrough |
打ち消し線スパン |
lbs-code-span |
インラインコード |
lbs-hr |
水平線 |
lbs-code-block |
コードブロックのラッパー <div> |
lbs-code-filename |
コードブロック内のファイル名ラベル |
lbs-blockquote |
引用ブロック |
lbs-ul |
順序なしリスト |
lbs-ul-depth-N |
ネスト深さ(0がトップレベル) |
lbs-ol |
番号付きリスト |
lbs-ol-depth-N |
ネスト深さ |
lbs-list-item |
リストアイテム |
lbs-checkbox |
チェックリストのチェックボックス |
lbs-table |
テーブル |
lbs-table-silent |
サイレント(枠線なし)テーブル |
lbs-image |
画像 |
lbs-header |
ページヘッダー |
lbs-footer |
ページフッター |
lbs-details |
詳細折りたたみブロック |
lbs-summary |
詳細折りたたみのサマリー要素 |
lbs-footnote-ref |
脚注の上付き文字 |
lbs-footnotes |
脚注セクション |
lbs-footnote-item |
個別の脚注エントリ |
import { toHTML, parseDocument, renderDocument } from 'lobsterjs';
// 一番シンプル: Markdown → HTML文字列
const html = toHTML(markdownString);
// ステップ分割(ツール連携やカスタムレンダラー向け)
const doc = parseDocument(markdownString); // → Document AST
const html = renderDocument(doc); // → HTML文字列
// ブラウザ: MarkdownファイルをフェッチしてDOM要素にレンダリング
import { loadMarkdown } from 'lobsterjs';
await loadMarkdown('./content.md', document.getElementById('content'));parseDocument が返す Document オブジェクト:
interface Document {
header?: HeaderContainerNode;
footer?: FooterContainerNode;
body: BlockNode[];
linkDefs: Record<string, LinkDef>;
footnoteDefs: Record<string, InlineNode[]>;
footnoteRefs: string[];
warpDefs: Record<string, WarpDefinitionNode>;
}全型定義は src/core/types.ts を参照。