AST と位置情報


parse が返す Page の構造と、各ノードが持つ position を説明します。

ブロックの構造


Page の直下には、タイトル、通常行、コードブロック、テーブルのいずれかが並びます。ブロック同士は入れ子にならず、インデントの深さは LineBlock.indent に数値で記録されます。

Text
Page
├─ TitleBlock 1 行目。value と、書いたままの文字の children
├─ CodeBlock code:filename と CodeLine[]
├─ TableBlock TableRow[] → TableCell[]
└─ LineBlock indent / quote / monospace / InlineNode[]

インラインノード


タイトル行、通常行、テーブルセルの中にはインラインノードが入ります。各ノードは type で判別します。
ただしタイトル行は Cosense Web と同じく記法を読まないので、TitleBlock の children は書いたままの文字の text 1 つです (タイトルが空なら無し)。

text は通常の文字列、internalLink / externalLink / projectLink は各種リンク、hashtag はタグです。inlineCode、image、video、audio、embed、location、icon、formula、decoration もそれぞれ別のノードになります。

テーブルセルは既定ではリンク記法だけを解析し、それ以外は文字として残します。セル内で装飾などを読みたい場合は tableCellNotation() を使います。

動画・音声・埋め込み・地図


Cosense Web がプレーヤーとして表示する URL は、外部リンクではなく専用のノードになります。どれも角括弧で囲んだときだけで、裸の URL は外部リンクのままです。

video は [https://…/a.mp4] です。拡張子は mp4、webm、mov で、[[…]] で囲むと large、URL を 2 つ並べると link が付きます。
audio は [https://…/a.mp3] です。拡張子は wav、mp3、weba、ogg、aac で、URL の前後に書いた文字が label になります。
embed は YouTube、Vimeo、Spotify、anchor.fm の URL です。provider と、サービスの中での id を持ちます。YouTube と Spotify は id が何を指すかを kind に持ちます。

location は [N35.68,E139.76] の地図です。,Z14 でズームを付けられ、座標の前後に書いた文字が label になります。緯度と経度は数値で、南緯と西経は負の数です。

どのノードも URL は書かれたままです。埋め込みを <iframe> に入れる URL は asEmbedSrc で、地図の Google マップの URL は asMapUrl で作ります。

装飾ノード


Cosense の装飾は入れ子ではなく、1つのノードが複数の記号を markers に保持します。たとえば [-/ 文字] は打ち消しと斜体の記号を同じノードに持ちます。

markers は記号の出現順で、重複しません。見た目のフラグとして解釈するのは *、/、-、_ です。ほかの装飾記号は描画側で扱います。

position


すべてのノードは position.start と position.end を持ちます。line、column、offset はいずれも 0 始まりで、end は範囲に含みません。

TypeScript
interface Point {
line: number
column: number
offset: number
}
interface Position {
start: Point
end: Point
}

offset はバイト数ではなく JavaScript の文字列オフセットです。source.slice(start.offset, end.offset) で、そのノードに対応する元テキストを切り出せます。

CRLF と CR は解析前に LF へ正規化されます。したがって位置は正規化後の文字列を基準にします。

位置情報の使い道


位置情報は、エディターのシンタックスハイライト、カーソル下の記法判定、描画結果と元テキストの対応付け、範囲選択による編集などに使えます。

走査用の関数は AST のヘルパー をご覧ください。