registerExtension で印を足す手順。TypeScript を推奨し、配る前に JavaScript へ変換する
使う側のアプリが自分の印を文書に書けるようにするとき、その印を描くモジュールを足すときに実行する。
dist/ にある型定義(index.d.ts と、それが読み込む .d.ts)を、拡張を書くプロジェクトに置くdraw を書くimport type { MdmarkMarkArgs } from "./mdmark/index.js";
export function draw(slot: HTMLElement, value: MdmarkMarkArgs): void {
slot.textContent = `こんにちは、${value.args[0]}`;
}
拡張は TypeScript と JavaScript のどちらでも書ける。
TypeScript で書くことを推奨する。
draw の引数に配布物の型が付き、書き間違いを配る前に型検査で見つけられる。
slot は印の場所の要素、value.args は キー=値 でない引数を書いた順に並べたもの、value.keys は キー=値 の引数。
draw は Promise を返す非同期でもよい。
draw が例外を投げると、その印の場所だけが知らせの枠に替わる。
// @ts-check
/** @type {import("../mdmark/index.js").MdmarkExtension} */
const extension = {
name: "greet",
directive: "greet",
load: async () => ({
draw(slot, value) {
slot.textContent = `こんにちは、${value.args[0] ?? ""}`;
},
}),
};
export default extension;
JavaScript は変換を挟まずに、先頭の // @ts-check と JSDoc で型を付けて書く。
型は TypeScript と同じ配布物の型定義を読む。
npx tsc --noEmit で点検すると、型を誤った行がファイルと行つきで出る。
mdmark init --js が、この形の雛形と JavaScript も点検する tsconfig.json を置く(雛形を置く)。
固有の部品と CSS を文書に当てる手順は 固有の部品とCSSを当てる。
npx @biomejs/biome check extensions
拡張を書くときは、TypeScript と JavaScript のどちらでも linter を使う。 型検査で見つからない、使っていない変数や書き方の誤りを、配る前に見つけられる。 linter は Biome を推奨する。 1 つのコマンドで linter と整形の点検ができる。
npx esbuild extensions/greet.ts --format=esm --outfile=public/extensions/greet.js
load が import() で読むのはブラウザなので、配るのは JavaScript にしたファイルだけ。
TypeScript のファイルは配らない。
変換の道具は使う側で選ぶ。
上は esbuild の例。
registerExtension を呼ぶimport { registerExtension } from "https://cdn.jsdelivr.net/gh/shuhei1101/mdmark@{タグ}/dist/index.js";
registerExtension({
name: "greet",
directive: "greet",
load: () => import("/extensions/greet.js"),
});
{タグ} は CSS を読み込んだタグに置き換える。
mount や update で描く前に呼ぶ。
描いた後に登録した印は、次の mount・update から効く。
name は知らせの枠・書き方の警告・console.error に出す名前、directive は印の名前。
directive は英小文字で始まり、英小文字・数字・- だけを持つ。
features と記法の印(table・tabs・steps・section・row-detail・fig・toc・glossary・view)と、登録済みの拡張の directive は使えず、Error を投げて登録しない。
書式に合わない項目があると TypeError を投げて登録しない。
設定の libraries や図の部品の印(flow・sequence・chart・param)に同じ名前があるときは、拡張を優先する。
import * as v from "valibot";
registerExtension({
name: "greet",
directive: "greet",
load: () => import("/extensions/greet.js"),
schema: v.object({
args: v.strictTuple([v.pipe(v.string(), v.regex(/^[a-z]+$/))]),
keys: v.record(v.string(), v.string()),
}),
});
印の引数を検査するときだけ schema を渡す。
schema は Standard Schema で、zod・valibot など ~standard を持つ検査ライブラリの schema をそのまま渡せる。
mdmark は検査ライブラリを束ねない。
検査する値は { args: string[]; keys: Record<string, string> }。
valibot の tuple は余る引数を許すため、引数の数を限るときは strictTuple を使う。
引数が合わない印の場所は、モジュールを読まずに書き方の警告に替わる。
<!-- greet: world lang=ja -->
draw は { args: ["world"], keys: { lang: "ja" } } を受け取る。
文書にその印があるときだけ、mount と update が load を呼ぶ。
同じ文書の同じ拡張の印は、load を 1 回だけ呼ぶ。
render は拡張の印を読み込み中の枠に置き換えるだけで、load も検査も呼ばない。
<!-- greet -->
```json
{ "title": "段取り", "items": ["a", "b", "c"] }
```
<!-- /greet -->
印を範囲(<!-- greet --> 〜 <!-- /greet -->)で書き、範囲に言語 json のコードブロックを 1 つ置くと、その JSON を読んだ値が value.definition に入る。
schema の検査と draw は同じ値を受け取る。
定義の中身の形は schema が確かめる。
コードブロックが 2 つ以上あるか、JSON として読めないときは、schema も load も呼ばず、印の場所が書き方の警告に替わる。
import { mountView } from "https://cdn.jsdelivr.net/gh/shuhei1101/mdmark@{タグ}/dist/index.js";
export async function draw(slot, value) {
await mountView(slot, value.definition);
}
draw の中で、配布物が出すビューを描く関数 mountView とコメントを付ける関数 mountComments を、slot に対して呼べる。
draw が部品の Promise を待つと、mount はその後に印の場所を描き終えたものとして扱う。
update と destroy で印の場所を片付けるとき、その中の部品の destroy も行う。
引数と動きは 部品をJavaScriptから使う。
即時。登録は同期で終わり、次に mount か update で描く文書から効く。
拡張の印を書いた文書を描く。
印の場所の要素に、draw が書いた内容が出る。
ブラウザの開発者ツールのネットワークで、拡張のモジュールへの要求が 1 件ある。
拡張の印を書いていない文書を描く。 拡張のモジュールへの要求が 0 件になる。
schema に合わない引数の印を書いて描く。
印の場所に題 書き方の警告 の枠が出て、本文に印の文字と拡張の名前(greet)がある。
拡張のモジュールへの要求は 0 件になる。
load が指す先を存在しない URL に変えて描く。
印の場所に知らせの枠が出て、題が この図を表示できません、本文が 表示に使う拡張(greet)を読み込めませんでした。 で始まる。
console.error に拡張の名前と元のエラーが出て、ほかの箇所は描かれる。
TypeScript か、// @ts-check を付けた JavaScript で書いたとき、型検査を流す。
npx tsc --noEmit
型エラーが 0 件になる。
npx @biomejs/biome check extensions
違反が 0 件になる。
registerExtension の呼び出しを消す。
登録は同じページの間だけ効き、消すと文書の拡張の印は未知の印として取り除かれる。
配った JavaScript のファイルは別に消す。