diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..bad44a5 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,55 @@ +## parse API +入力文字列からノードツリーを生成します。 +全てのMFM構文を利用可能です。 + +例: +```ts +const nodes = mfm.parse('hello [tada world]'); +console.log(JSON.stringify(nodes)); +// => "[{"type":"text","props":{"text":"hello "}},{"type":"fn","props":{"name":"tada","args":{}},"children":[{"type":"text","props":{"text":"world"}}]}]" +``` + +## parsePlain API +入力文字列からノードツリーを生成します。 +絵文字コードとUnicode絵文字を利用可能です。 + +例: +```ts +const nodes = mfm.parsePlain('Hello :surprised_ai:'); +console.log(JSON.stringify(nodes)); +// => "[{"type":"text","props":{"text":"Hello "}},{"type":"emojiCode","props":{"name":"surprised_ai"}}]" +``` + +## toString API +ノードツリーからMFM文字列を生成します。 + +例: +```ts +const nodes = mfm.parse('hello [tada world]'); +const output = mfm.toString(nodes); +console.log(output); // => "hello [tada world]" +``` +※元の文字列とtoString APIで出力される文字列の同一性は保障されません。 + +## inspect API +ノードツリーの全ノードに指定された関数を適用します。 + +例: +```ts +mfm.inspect(nodes, node => { + if (node.type == 'text') { + node.props.text = node.props.text.replace(/Good morning/g, 'Hello'); + } +}); +``` + +## extract API +ブール値を返す関数を渡してノードを抽出します。 +このAPIはノードツリーを再帰的に探索します。 + +例: +```ts +mfm.extract(nodes, (node) => { + return (node.type === 'emojiCode'); +}); +``` diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..84feadc --- /dev/null +++ b/docs/index.md @@ -0,0 +1,7 @@ +## 目次 + +### [API](api) +ライブラリが提供している関数や型定義などについての説明です。 + +### [MFM構文とノード構造の仕様](syntax) +サポートしているMFM構文やノード構造についての説明です。 diff --git a/docs/syntax.md b/docs/syntax.md new file mode 100644 index 0000000..3523b8c --- /dev/null +++ b/docs/syntax.md @@ -0,0 +1,616 @@ +

目次

+ +ブロック構文: +- [引用ブロック](#quote) +- [検索ブロック](#search) +- [コードブロック](#code-block) +- [数式ブロック](#math-block) +- [中央寄せブロック](#center) + +インライン構文: +構文 | 改行可能? +-------------------------------|----------- +[揺れる字](#big) | はい +[太字](#bold) | はい +[目立たない字](#small) | はい +[イタリック](#italic) | はい +[打ち消し線](#strike) | いいえ +[インラインコード](#inline-code) | いいえ +[インライン数式](#math-inline) | いいえ +[メンション](#mention) | いいえ +[ハッシュタグ](#hashtag) | いいえ +[URL](#url) | いいえ +[リンク](#link) | いいえ +[絵文字コード(カスタム絵文字)](#emoji-code) | いいえ +[MFM関数](#fn) | はい +[Unicode絵文字](#unicode-emoji) | いいえ +[テキスト](#text) | はい + + + +

引用ブロック

+ +## 形式 +``` +> abc +>abc +>>nest +``` + +## ノード +```js +{ + type: 'quote', + children: [ + { type: 'text', props: { text: 'abc' } } + ] +} +``` + +## 詳細 +- ブロック構文です。 +- 引用された内容には再度FullParserを適用する。 +- `>`の後に続く0~1文字のスペースを無視する。 +- 隣接する引用の行は一つになる。 +- 複数行の引用では空行も含めることができる。 + + + +

検索ブロック

+ +## 形式 +``` +MFM 書き方 Search +MFM 書き方 検索 +MFM 書き方 [Search] +MFM 書き方 [検索] +``` + +## ノード +```js +{ + type: 'search', + props: { + query: 'MFM 書き方', + content: 'MFM 書き方 Search' + } +} +``` + +## 詳細 +- ブロック構文。 +- Searchの大文字小文字は区別されない。 + + + +

コードブロック

+ +## 形式 +
+```
+a
+
+b```
+```c
+````
+```
+
+ +
+```js
+abc
+````
+
+ +## ノード +```js +{ + type: 'blockCode', + props: { + code: 'abc', + lang: 'js' + } +} +``` + +## 詳細 +- ブロック構文です。 +- langは指定されない場合はnullになる。 + + + +

数式ブロック

+ +## 形式 +``` +\[a = 1\] +``` + +``` +\[ +a = 2 +\] +``` + +## ノード +```js +{ + type: 'mathBlock', + props: { + formula: 'a = 1' + } +} +``` + +## 詳細 +- ブロック構文です。 +- `\[`は行頭でなければならない。 +- `\]`は行末でなければならない。 +- 前後のスペースと改行はトリミングされる。 + + + +

中央寄せブロック

+ +## 形式 +``` +
abc
+``` +``` +
+abc +
+``` + +## ノード +```js +{ + type: 'center', + children: [ + { type: 'text', props: { text: 'abc' } } + ] +} +``` + +## 詳細 +- ブロック構文。 +- `
`は行頭でなければならない。 +- `
`は行末でなければならない。 +- 中身を空にすることはできない。 +- 内容には再度InlineParserを適用する。 + + + +

揺れる字

+ +**廃止予定の構文。代替の構文が用意されています。** +## 形式 +``` +***big!*** +``` + +## ノード +```js +{ + type: 'fn', + props: { + name: 'tada', + args: { } + }, + children: [ + { type: 'text', props: { text: 'big!' } } + ] +} +``` + +## 詳細 +- インライン構文 +- 内容には再度InlineParserを適用する。 +- 内容には改行も含めることが可能です。 + + + +

太字

+ +## 形式 +``` +**bold** +``` + +## ノード +```js +{ + type: 'bold', + children: [ + { type: 'text', props: { text: 'bold' } } + ] +} +``` + +## 詳細 +- インライン構文。 +- 内容には再度InlineParserを適用する。 +- 内容には改行も含めることが可能です。 + + + +

目立たない字

+ +## 形式 +``` +small +``` + +## ノード +```js +{ + type: 'small', + children: [ + { type: 'text', props: { text: 'small' } } + ] +} +``` + +## 詳細 +- インライン構文です。 +- 内容には再度InlineParserを適用する。 +- 内容には改行も含めることが可能です。 + + + +

イタリック

+ +## 形式 +構文1: +``` +italic +``` + +構文2: +``` +*italic* +``` + +構文3: +``` +_italic_ +``` + +## ノード +```js +{ + type: 'italic', + children: [ + { type: 'text', props: { text: 'italic' } } + ] +} +``` + +## 詳細 +- インライン構文。 +- 内容には再度InlineParserを適用する。 + +構文1のみ: +- 内容には改行も含めることが可能です。 + +構文2,3のみ: +※1つ目の`*`と`_`を開始記号と呼ぶ。 +- 内容には`[a-z0-9 \t]i`にマッチする文字が使用できる。 +- 開始記号の前の文字が(無い、改行、半角スペース)のいずれかの時にイタリック文字として判定される。 + + + +

打ち消し線

+ +## 形式 +``` +~~strike~~ +``` + +## ノード +```js +{ + type: 'strike', + children: [ + { type: 'text', props: { text: 'strike' } } + ] +} +``` + +## 詳細 +- インライン構文。 +- 内容には再度InlineParserを適用する。 +- 内容には改行を含めることができない。 +- 内容には`~`を含めることができない。 + + + +

インラインコード

+ +## 形式 +``` +`$abc <- 1` +``` + +## ノード +```js +{ + type: 'inlineCode', + props: { + code: '$abc <- 1' + } +} +``` + +## 詳細 +- インライン構文。 +- 内容には改行を含めることができない。 + + + +

インライン数式

+ +## 形式 +``` +\(y = 2x\) +``` + +## ノード +```js +{ + type: 'mathInline', + props: { + formula: 'y = 2x' + } +} +``` + +## 詳細 +- インライン構文。 +- 内容には改行を含めることができない。 + + + +

メンション

+ +## 形式 +``` +@user@misskey.io +``` +``` +@user +``` + +## ノード +```js +{ + type: 'mention', + props: { + username: 'user', + host: 'misskey.io', + acct: '@user@misskey.io' + } +} +``` + +```js +{ + type: 'mention', + props: { + username: 'user', + host: null, + acct: '@user' + } +} +``` + +## 詳細 +- インライン構文。 +- 最初の`@`の前の文字が(改行、スペース、無し)のいずれかの場合にメンションとして認識する。 + +### ユーザ名 +- 1文字以上。 +- `A`~`Z` `0`~`9` `_` `-`が含められる。 +- 1文字目と最後の文字は`-`にできない。 + +### ホスト名 +- 1文字以上。 +- `A`~`Z` `0`~`9` `_` `-` `.`が含められる。 +- 1文字目と最後の文字は`-` `.`にできない。 + + + +

ハッシュタグ

+ +## 形式 +``` +#abc +``` + +## ノード +```js +{ + type: 'hashtag', + props: { + hashtag: 'abc' + } +} +``` + +## 詳細 +- インライン構文。 +- 内容には半角スペース、全角スペース、改行、タブ文字を含めることができない。 +- 内容には`.` `,` `!` `?` `'` `"` `#` `:` `/` `【` `】` を含めることができない。 +- 括弧は対になっている時のみ内容に含めることができる。対象: `()` `[]` `「」` +- `#`の前の文字が(改行、スペース、無し)のいずれかの場合にハッシュタグとして認識する。 + + + +

URL

+ +## 形式 +``` +https://misskey.io/@ai +``` + +``` +http://hoge.jp/abc +``` + +## ノード +```js +{ + type: 'url', + props: { + url: 'https://misskey.io/@ai' + } +} +``` + +## 詳細 +- インライン構文。 +- 内容には`[.,a-z0-9_/:%#@$&?!~=+-]i`にマッチする文字を使用できる。 +- 内容には対になっている括弧を使用できる。対象: `(` `)` `[` `]` +- `.`や`,`は最後の文字にできない。 + + + +

リンク

+ +## 形式 +silent=false +``` +[Misskey.io](https://misskey.io/) +``` + +silent=true +``` +?[Misskey.io](https://misskey.io/) +``` + +## ノード +```js +[ + { + type: 'link', + props: { + silent: false, + url: 'https://misskey.io/' + }, + children: [ + { + type: 'text', + props: { + text: 'Misskey.io' + } + } + ] + } +] +``` + +## 詳細 +- インライン構文。 +- 内容には再度InlineParserを適用する。 +- 内容に含まれるURLはテキストとしてパースする。 + + + +

絵文字コード(カスタム絵文字)

+ +## 形式 +``` +:thinking_ai: +``` + +## ノード +```js +{ + type: 'emojiCode', + props: { + name: 'thinking_ai' + } +} +``` + +## 詳細 +- インライン構文。 + + + +

関数

+ +## 形式 +``` +[shake 🍮] +``` + +``` +[spin.alternate 🍮] +``` + +``` +[shake.speed=1s 🍮] +``` + +``` +[flip.h,v MisskeyでFediverseの世界が広がります] +``` + +## ノード +```js +{ + type: 'fn', + props: { + name: 'shake', + args: { } + }, + children: [ + { type: 'unicodeEmoji', props: { emoji: '👍' } } + ] +} +``` + +## 詳細 +- インライン構文 +- 内容には再度InlineParserを適用する。 +- 内容には改行も含めることが可能です。 +- 使用できる関数名やパラメータはホスト側で定義され、パーサはその登録状況を関知しません。 + + + +

Unicode絵文字

+ +## 形式 +``` +😇 +``` + +## ノード +```js +{ + type: 'unicodeEmoji', + props: { + emoji: '😇' + } +} +``` + + + +

テキスト

+ +## 形式 +``` +abc +``` + +## ノード +```js +{ + type: 'text', + props: + text: 'abc' + } +} +```