@cosense-toolbox/parser 0.1.0-beta.0 → 0.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -758
- package/dist/{ast-uYWtkHwT.cjs → ast-C0BGz7X2.cjs} +2 -2
- package/dist/ast-C0BGz7X2.cjs.map +1 -0
- package/dist/{ast-CIKXwSl5.mjs → ast-CMQYawYl.mjs} +2 -2
- package/dist/ast-CMQYawYl.mjs.map +1 -0
- package/dist/compile.cjs +2 -212
- package/dist/compile.cjs.map +1 -1
- package/dist/compile.d.cts +17 -125
- package/dist/compile.d.cts.map +1 -1
- package/dist/compile.d.mts +17 -125
- package/dist/compile.d.mts.map +1 -1
- package/dist/compile.mjs +3 -206
- package/dist/compile.mjs.map +1 -1
- package/dist/decoration-BB1cS4lH.mjs +72 -0
- package/dist/decoration-BB1cS4lH.mjs.map +1 -0
- package/dist/decoration-BYXIXxCA.cjs +107 -0
- package/dist/decoration-BYXIXxCA.cjs.map +1 -0
- package/dist/extensions.cjs +32 -0
- package/dist/extensions.cjs.map +1 -0
- package/dist/extensions.d.cts +26 -0
- package/dist/extensions.d.cts.map +1 -0
- package/dist/extensions.d.mts +26 -0
- package/dist/extensions.d.mts.map +1 -0
- package/dist/extensions.mjs +30 -0
- package/dist/extensions.mjs.map +1 -0
- package/dist/html.cjs +458 -0
- package/dist/html.cjs.map +1 -0
- package/dist/html.d.cts +274 -0
- package/dist/html.d.cts.map +1 -0
- package/dist/html.d.mts +274 -0
- package/dist/html.d.mts.map +1 -0
- package/dist/html.mjs +447 -0
- package/dist/html.mjs.map +1 -0
- package/dist/image-url-YcTed8tg.cjs.map +1 -1
- package/dist/image-url-eQ6X-oN0.mjs.map +1 -1
- package/dist/index-CrIlOW1k.d.mts +78 -0
- package/dist/index-CrIlOW1k.d.mts.map +1 -0
- package/dist/index-_o1STNhP.d.cts +78 -0
- package/dist/index-_o1STNhP.d.cts.map +1 -0
- package/dist/index.cjs +118 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -77
- package/dist/index.d.mts +4 -77
- package/dist/index.mjs +110 -86
- package/dist/index.mjs.map +1 -1
- package/dist/schema.cjs +2 -0
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +1 -1
- package/dist/schema.d.cts.map +1 -1
- package/dist/schema.d.mts +1 -1
- package/dist/schema.d.mts.map +1 -1
- package/dist/schema.mjs +2 -0
- package/dist/schema.mjs.map +1 -1
- package/dist/{types-BXlnUFr0.d.mts → types-CdiHju1P.d.mts} +15 -12
- package/dist/types-CdiHju1P.d.mts.map +1 -0
- package/dist/{types-DVwlUtla.d.cts → types-_-ZAyNkz.d.cts} +15 -12
- package/dist/types-_-ZAyNkz.d.cts.map +1 -0
- package/dist/{types-Bo_BrmvK.d.cts → types-gWMrsXPX.d.cts} +31 -22
- package/dist/types-gWMrsXPX.d.cts.map +1 -0
- package/dist/{types-Bo_BrmvK.d.mts → types-gWMrsXPX.d.mts} +31 -22
- package/dist/types-gWMrsXPX.d.mts.map +1 -0
- package/dist/utils.cjs +2 -2
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +2 -2
- package/dist/utils.d.cts.map +1 -1
- package/dist/utils.d.mts +2 -2
- package/dist/utils.d.mts.map +1 -1
- package/dist/utils.mjs +2 -2
- package/dist/utils.mjs.map +1 -1
- package/package.json +33 -10
- package/dist/ast-CIKXwSl5.mjs.map +0 -1
- package/dist/ast-uYWtkHwT.cjs.map +0 -1
- package/dist/create-compiler-CvlndKOA.d.cts +0 -23
- package/dist/create-compiler-CvlndKOA.d.cts.map +0 -1
- package/dist/create-compiler-jdA408ny.d.mts +0 -23
- package/dist/create-compiler-jdA408ny.d.mts.map +0 -1
- package/dist/index.d.cts.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/plugin.cjs +0 -0
- package/dist/plugin.d.cts +0 -4
- package/dist/plugin.d.mts +0 -4
- package/dist/plugin.mjs +0 -1
- package/dist/types-BXlnUFr0.d.mts.map +0 -1
- package/dist/types-Bo_BrmvK.d.cts.map +0 -1
- package/dist/types-Bo_BrmvK.d.mts.map +0 -1
- package/dist/types-DVwlUtla.d.cts.map +0 -1
package/README.md
CHANGED
|
@@ -1,794 +1,112 @@
|
|
|
1
1
|
# @cosense-toolbox/parser
|
|
2
2
|
|
|
3
|
-
Cosense (旧 Scrapbox)
|
|
4
|
-
位置情報つきの unist 風 AST を返す。
|
|
3
|
+
Cosense (旧 Scrapbox) の記法を、位置情報つきの AST に変換する。
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
> 安定するまでは `^` ではなくバージョンを固定して使うほうが安全。
|
|
5
|
+
**ドキュメント → <https://cosense-toolbox.qaynam.dev/parser/>**
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import { parse } from '@cosense-toolbox/parser'
|
|
15
|
-
|
|
16
|
-
const page = parse('タイトル\nこれは [リンク] です')
|
|
17
|
-
|
|
18
|
-
page.children[1].children
|
|
19
|
-
// [ { type: 'text', value: 'これは ', position: {…} },
|
|
20
|
-
// { type: 'internalLink', label: 'リンク', target: 'リンク', position: {…} },
|
|
21
|
-
// { type: 'text', value: ' です', position: {…} } ]
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
- 依存は `effect` だけで、DOM も Node の API も使わない。
|
|
25
|
-
- すべてのノードが位置情報を持つので、エディタのハイライトやキャレット連携に使える。
|
|
26
|
-
- AST は plain object なので、`JSON.stringify` と `JSON.parse` で往復でき、worklet や postMessage を跨げる。
|
|
27
|
-
- 記法と出力の両方をプラグインで拡張できる。
|
|
28
|
-
- サブパスごとに export が分かれていて tree-shaking が効く (`parse` だけなら gzip 約 8 KB)。
|
|
29
|
-
|
|
30
|
-
> このパッケージは Cosense (Scrapbox) の記法を解釈する非公式の実装である。
|
|
31
|
-
> 開発元である Helpfeel社 とは関係がなく、公認も受けていない。
|
|
32
|
-
|
|
33
|
-
## パース
|
|
34
|
-
|
|
35
|
-
### parse
|
|
36
|
-
|
|
37
|
-
ページ全文を受け取り、ブロックの並びを返す。
|
|
38
|
-
どんな入力でも例外を投げず、必ず `Page` を返す。
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
import { parse } from '@cosense-toolbox/parser'
|
|
42
|
-
|
|
43
|
-
const page = parse('タイトル\nこれは [リンク] です')
|
|
44
|
-
|
|
45
|
-
for (const block of page.children) {
|
|
46
|
-
switch (block.type) {
|
|
47
|
-
case 'title':
|
|
48
|
-
console.log('title:', block.value)
|
|
49
|
-
break
|
|
50
|
-
case 'line':
|
|
51
|
-
console.log('line:', block.children.map((node) => node.type))
|
|
52
|
-
break
|
|
53
|
-
case 'codeBlock':
|
|
54
|
-
console.log(block.filename, block.lines.map((line) => line.value))
|
|
55
|
-
break
|
|
56
|
-
case 'table':
|
|
57
|
-
console.log(block.name, block.rows.length)
|
|
58
|
-
break
|
|
59
|
-
default:
|
|
60
|
-
// ノード型は minor で増えうるので default を置く
|
|
61
|
-
break
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
`code:` と `table:` は、ページの文脈があって初めてブロックにまとまる。
|
|
67
|
-
1 行目は無条件でタイトルとして扱う。
|
|
68
|
-
|
|
69
|
-
### parseLine
|
|
70
|
-
|
|
71
|
-
1 行だけを通常行としてパースする。
|
|
72
|
-
エディタのように行単位で扱うときに使う。
|
|
73
|
-
|
|
74
|
-
```ts
|
|
75
|
-
import { parseLine } from '@cosense-toolbox/parser'
|
|
76
|
-
|
|
77
|
-
parseLine(' > [リンク]')
|
|
78
|
-
// LineBlock { indent: 2, quote: true, monospace: false, children: [...] }
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
ページの文脈がないので、`code:` と `table:` もブロックにはならず通常行になる。
|
|
82
|
-
その行がページの何行目かは `{ line, offset }` で渡せる。位置情報がページ全体と揃う。
|
|
83
|
-
|
|
84
|
-
### tokenizeInline
|
|
85
|
-
|
|
86
|
-
行の中だけを解析して、インラインノードの並びを返す。
|
|
87
|
-
|
|
88
|
-
```ts
|
|
89
|
-
import { tokenizeInline } from '@cosense-toolbox/parser'
|
|
90
|
-
|
|
91
|
-
tokenizeInline('[* 太字] と [リンク]') // → readonly InlineNode[]
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
改行を含まない 1 行分の文字列を渡す。
|
|
95
|
-
|
|
96
|
-
### createParser
|
|
97
|
-
|
|
98
|
-
拡張を固定したパーサーを作る。
|
|
99
|
-
同じ拡張で何度もパースするときに、毎回 `extensions` を渡さずに済む。
|
|
100
|
-
|
|
101
|
-
```ts
|
|
102
|
-
import { createParser } from '@cosense-toolbox/parser'
|
|
103
|
-
|
|
104
|
-
const parser = createParser({ extensions: [mentions] })
|
|
105
|
-
parser.parse(source)
|
|
106
|
-
parser.parseLine(line)
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### asImageSrc
|
|
110
|
-
|
|
111
|
-
画像 URL を `<img src>` に入れられる形にする。
|
|
112
|
-
画像でなければ `null` を返す。
|
|
113
|
-
|
|
114
|
-
```ts
|
|
115
|
-
import { asImageSrc } from '@cosense-toolbox/parser'
|
|
116
|
-
|
|
117
|
-
asImageSrc('https://gyazo.com/503a911fea542532aa5aba0a88eb7b60')
|
|
118
|
-
// → 'https://i.gyazo.com/503a911fea542532aa5aba0a88eb7b60.png'
|
|
119
|
-
asImageSrc('https://example.test/page')
|
|
120
|
-
// → null
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
Gyazo のページ URL は画像そのものではないので、ここでだけ画像 URL に差し替わる。
|
|
124
|
-
`parse` はこの変換をしない。AST はソースに書かれた文字列を保つ。
|
|
125
|
-
|
|
126
|
-
### normalizeLineEndings
|
|
127
|
-
|
|
128
|
-
CRLF と CR を LF に揃える。
|
|
129
|
-
`parse` は必ずこれを通してから解析するので、位置情報を自分で計算するときに使う。
|
|
130
|
-
|
|
131
|
-
## AST
|
|
132
|
-
|
|
133
|
-
```
|
|
134
|
-
Page
|
|
135
|
-
├─ TitleBlock 1 行目。value に生テキスト、children にインラインノード
|
|
136
|
-
├─ CodeBlock code:filename とその配下 (CodeLine[])
|
|
137
|
-
├─ TableBlock table:name とその配下 (TableRow[] → TableCell[])
|
|
138
|
-
└─ LineBlock 通常の行 (indent / quote / monospace + InlineNode[])
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
インラインノードは次の 10 種類で、すべて `type` で判別できる。
|
|
142
|
-
|
|
143
|
-
| type | 記法 |
|
|
144
|
-
| :--- | :--- |
|
|
145
|
-
| `text` | 記法にならなかった素のテキスト |
|
|
146
|
-
| `internalLink` | `[title]` |
|
|
147
|
-
| `externalLink` | 裸の URL、`[url]`、`[url label]`、`[label url]` |
|
|
148
|
-
| `projectLink` | `[/project/title]` (`project` と `title` に分解済み) |
|
|
149
|
-
| `hashtag` | `#tag` |
|
|
150
|
-
| `inlineCode` | `` `code` `` |
|
|
151
|
-
| `image` | `[url.png]`、`[[url.png]]` (large)、`[linkUrl imageUrl]` (link つき) |
|
|
152
|
-
| `icon` | `[user.icon]`、`[user.icon*5]` |
|
|
153
|
-
| `formula` | `[$ x^2]` |
|
|
154
|
-
| `decoration` | `[* 太字]` `[/ 斜体]` `[- 打消し]` `[_ 下線]` とその複合、`[[太字]]` |
|
|
155
|
-
|
|
156
|
-
装飾は Markdown のような入れ子の強調にならない。
|
|
157
|
-
Cosense では 1 つの記法が複数の装飾を同時に持つ (`[-/ x]` は打消しかつ斜体) ので、1 ノードが複数のフラグを持つ形にしている。
|
|
158
|
-
|
|
159
|
-
`image` の `src` はソースに書かれた URL のままで、パーサーは書き換えない。
|
|
160
|
-
Gyazo のページ URL (`https://gyazo.com/{hash}`) のように、そのままでは `<img>` に入れられない URL を表示用に直すのは描画側の仕事になる。
|
|
161
|
-
その変換は [`asImageSrc`](#asimagesrc) が担当する。
|
|
162
|
-
|
|
163
|
-
## 位置情報
|
|
164
|
-
|
|
165
|
-
すべてのノードが `position` を持つ。
|
|
166
|
-
|
|
167
|
-
```ts
|
|
168
|
-
interface Point { line: number; column: number; offset: number } // すべて 0-based
|
|
169
|
-
interface Position { start: Point; end: Point } // end は exclusive
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
`line` はページ内の行番号で、0 がタイトル行になる。
|
|
173
|
-
`column` は行内の文字オフセット、`offset` はページ全文の中の文字オフセットを指す。
|
|
174
|
-
|
|
175
|
-
`source.slice(start.offset, end.offset)` は、その記法の生テキスト全体と一致する。
|
|
176
|
-
`[` や `#` などのマーカーも含む。
|
|
177
|
-
|
|
178
|
-
unist は 1-based だが、JS の `slice` とそのまま噛み合うよう 0-based を採用している。
|
|
179
|
-
CRLF と CR は LF に正規化されてから解析されるので、位置は正規化後の文字列が基準になる。
|
|
180
|
-
|
|
181
|
-
ノードの生テキストを切り出すには [`rawTextOf`](#rawtextof) を使う。
|
|
182
|
-
|
|
183
|
-
## utils
|
|
184
|
-
|
|
185
|
-
`@cosense-toolbox/parser/utils` は AST を走査して中身を取り出す。
|
|
186
|
-
パースはしないので、AST を作る側と使う側を分けて import できる。
|
|
187
|
-
|
|
188
|
-
### visit
|
|
189
|
-
|
|
190
|
-
木を深さ優先で辿る。
|
|
191
|
-
型を渡すとその型のノードだけが visitor に届く。
|
|
192
|
-
|
|
193
|
-
```ts
|
|
194
|
-
import { visit } from '@cosense-toolbox/parser/utils'
|
|
195
|
-
|
|
196
|
-
visit(page, 'internalLink', (node) => {
|
|
197
|
-
console.log(node.target)
|
|
198
|
-
})
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
visitor は `'skip'` を返すとそのノードの子を辿らず、`'exit'` を返すと走査全体を打ち切る。
|
|
202
|
-
第 2 引数を省くとすべてのノードが届く。
|
|
203
|
-
visitor の第 2 引数には、ルートからそのノードまでの祖先が配列で渡る。
|
|
204
|
-
|
|
205
|
-
### find
|
|
206
|
-
|
|
207
|
-
その型の最初のノードを返す。
|
|
208
|
-
無ければ `null`。
|
|
209
|
-
|
|
210
|
-
```ts
|
|
211
|
-
import { find } from '@cosense-toolbox/parser/utils'
|
|
212
|
-
|
|
213
|
-
find(page, 'codeBlock') // → CodeBlock | null
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### collect
|
|
217
|
-
|
|
218
|
-
その型のノードを出現順にすべて返す。
|
|
219
|
-
|
|
220
|
-
```ts
|
|
221
|
-
import { collect } from '@cosense-toolbox/parser/utils'
|
|
222
|
-
|
|
223
|
-
collect(page, 'icon') // → IconNode[]
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
戻り値の型はノード型から導出されるので、`collect(page, 'icon')` は `IconNode[]` になる。
|
|
227
|
-
|
|
228
|
-
### collectLinks
|
|
229
|
-
|
|
230
|
-
内部リンクとハッシュタグの指す先を、出現順、重複なしで返す。
|
|
231
|
-
|
|
232
|
-
```ts
|
|
233
|
-
import { collectLinks } from '@cosense-toolbox/parser/utils'
|
|
234
|
-
|
|
235
|
-
collectLinks(parse('t\n[A] と #B と [A]')) // → ['A', 'B']
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### firstImage
|
|
239
|
-
|
|
240
|
-
最初の画像ノードを返す。
|
|
241
|
-
無ければ `null`。ページのサムネイルを選ぶときに使う。
|
|
242
|
-
|
|
243
|
-
```ts
|
|
244
|
-
import { firstImage } from '@cosense-toolbox/parser/utils'
|
|
245
|
-
|
|
246
|
-
firstImage(page)?.src
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
### rawTextOf
|
|
250
|
-
|
|
251
|
-
そのノードがソースで占めていた生テキストを返す。
|
|
252
|
-
位置情報から切り出すので、記法のマーカーも含む。
|
|
253
|
-
|
|
254
|
-
```ts
|
|
255
|
-
import { rawTextOf } from '@cosense-toolbox/parser/utils'
|
|
256
|
-
|
|
257
|
-
const source = 'title\nこれは [リンク] です'
|
|
258
|
-
const link = parse(source).children[1].children[1]
|
|
259
|
-
rawTextOf(source, link) // → '[リンク]'
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
## compile
|
|
263
|
-
|
|
264
|
-
`@cosense-toolbox/parser/compile` は AST を別の形式に変える。
|
|
265
|
-
この層はパーサー本体を import しないので、変換だけを使う側のバンドルにパーサーは入らない。
|
|
266
|
-
|
|
267
|
-
### toHtml
|
|
268
|
-
|
|
269
|
-
AST を HTML 文字列にする。
|
|
270
|
-
引数はページ全体でなくてもよく、`parseLine` が返した 1 行でも AST の任意のノードでも受け取る。
|
|
271
|
-
|
|
272
|
-
```ts
|
|
273
|
-
import { parse } from '@cosense-toolbox/parser'
|
|
274
|
-
import { toHtml } from '@cosense-toolbox/parser/compile'
|
|
275
|
-
|
|
276
|
-
toHtml(parse('タイトル\nこれは [リンク] です'))
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
```html
|
|
280
|
-
<div class="page">
|
|
281
|
-
<h1 class="title">タイトル</h1>
|
|
282
|
-
<div class="line">
|
|
283
|
-
これは <a class="link" href="/%E3%83%AA%E3%83%B3%E3%82%AF">リンク</a> です
|
|
284
|
-
</div>
|
|
285
|
-
</div>
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
以降の HTML は読みやすさのために字下げして示す。
|
|
289
|
-
実際の出力に要素間の空白は入らない。
|
|
290
|
-
|
|
291
|
-
既定の見た目は [`@cosense-toolbox/style`](https://github.com/qaynam/cosense-toolbox/blob/main/packages/style/README.md) が別パッケージとして持っている。
|
|
292
|
-
|
|
293
|
-
#### 出力の形
|
|
294
|
-
|
|
295
|
-
class 名は接頭辞を持たず、すべて [`classNames`](#classnames) で差し替えられる。
|
|
296
|
-
|
|
297
|
-
ブロックの対応は次のとおり。
|
|
298
|
-
|
|
299
|
-
| 記法 | HTML |
|
|
300
|
-
| :--- | :--- |
|
|
301
|
-
| 1 行目 | `<h1 class="title">タイトル</h1>` |
|
|
302
|
-
| 通常の行 | `<div class="line">本文</div>` |
|
|
303
|
-
| 字下げした行 | `<div class="line" data-indent="2">本文</div>` |
|
|
304
|
-
| 空行 | `<div class="line"><br></div>` |
|
|
305
|
-
| `> 引用` | `<blockquote class="quote">引用</blockquote>` |
|
|
306
|
-
| `$ ls` | `<code class="monospace">$ ls</code>` |
|
|
307
|
-
|
|
308
|
-
ページ全体は `<div class="page">` で包まれる。
|
|
309
|
-
インデントの深さは class ではなく `data-indent` 属性で表す。
|
|
310
|
-
中点は要素を持たず、CSS の擬似要素が描く。
|
|
311
|
-
本家と同じ `.indent-mark` と `.pad` と `.dot` の要素が要る場合は [`showPads`](#showpads) を渡す。
|
|
312
|
-
|
|
313
|
-
テーブルは `<table>` になる。
|
|
314
|
-
|
|
315
|
-
```html
|
|
316
|
-
<table class="table">
|
|
317
|
-
<caption>テーブル名</caption>
|
|
318
|
-
<tbody>
|
|
319
|
-
<tr>
|
|
320
|
-
<td>abc</td>
|
|
321
|
-
<td>def</td>
|
|
322
|
-
</tr>
|
|
323
|
-
</tbody>
|
|
324
|
-
</table>
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
コードブロックは本家と同じく 1 行を 1 要素に切る。
|
|
328
|
-
|
|
329
|
-
```html
|
|
330
|
-
<div class="line code-block">
|
|
331
|
-
<code class="code-start">
|
|
332
|
-
<span class="code-block-start">a.js</span>
|
|
333
|
-
</code>
|
|
334
|
-
</div>
|
|
335
|
-
<div class="line code-block" data-indent="1">
|
|
336
|
-
<code class="code-body">const a = 1</code>
|
|
337
|
-
</div>
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
本体行はヘッダより 1 段深い `data-indent` を持つ。
|
|
341
|
-
それより深い字下げは中身の文字列に残る。
|
|
342
|
-
|
|
343
|
-
インラインの対応は次のとおり。
|
|
344
|
-
|
|
345
|
-
| 記法 | HTML |
|
|
346
|
-
| :--- | :--- |
|
|
347
|
-
| `[title]` | `<a class="link" href="/title">title</a>` |
|
|
348
|
-
| `https://a.test/x` | `<a class="link link-external" href="https://a.test/x">https://a.test/x</a>` |
|
|
349
|
-
| `[https://a.test/x label]` | `<a class="link link-external" href="https://a.test/x">label</a>` |
|
|
350
|
-
| `[/proj/page]` | `<a class="link link-project" href="/proj/page">/proj/page</a>` |
|
|
351
|
-
| `#tag` | `<a class="hashtag" href="/tag">#tag</a>` |
|
|
352
|
-
| `` `code` `` | `<code class="code">code</code>` |
|
|
353
|
-
| `[a.png]` | `<img class="image" src="a.png" alt="">` |
|
|
354
|
-
| `[[a.png]]` | `<img class="image" src="a.png" alt="" data-large="true">` |
|
|
355
|
-
| `[user.icon]` | `<a class="link icon" href="/user">user</a>` |
|
|
356
|
-
| `[$ x^2]` | `<span class="formula">x^2</span>` |
|
|
357
|
-
|
|
358
|
-
装飾はフラグの集合を入れ子の要素に開く。
|
|
359
|
-
|
|
360
|
-
```html
|
|
361
|
-
<!-- [* 太字] -->
|
|
362
|
-
<span class="decoration">
|
|
363
|
-
<strong>太字</strong>
|
|
364
|
-
</span>
|
|
365
|
-
|
|
366
|
-
<!-- [-/ x] は打消しかつ斜体 -->
|
|
367
|
-
<span class="decoration">
|
|
368
|
-
<em>
|
|
369
|
-
<s>x</s>
|
|
370
|
-
</em>
|
|
371
|
-
</span>
|
|
372
|
-
|
|
373
|
-
<!-- [*** 見出し] -->
|
|
374
|
-
<span class="decoration" data-size-level="2">
|
|
375
|
-
<strong>見出し</strong>
|
|
376
|
-
</span>
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
見出しの段階は `data-size-level` 属性で表す。
|
|
380
|
-
|
|
381
|
-
数式は組版せず、記法を外した中身をそのまま置く。
|
|
382
|
-
KaTeX に渡したい場合は [`handlers`](#handlers) で差し替える。
|
|
383
|
-
|
|
384
|
-
アイコンは既定では画像を出さない。
|
|
385
|
-
[`iconImageUrl`](#iconimageurl) を渡すと `<img>` が入る。
|
|
386
|
-
|
|
387
|
-
#### オプション
|
|
388
|
-
|
|
389
|
-
| オプション | 型 | 既定 |
|
|
390
|
-
| :--- | :--- | :--- |
|
|
391
|
-
| [`pageUrl`](#pageurl) | `(title, node) => string` | `/{title}` |
|
|
392
|
-
| [`iconImageUrl`](#iconimageurl) | `(node) => string \| null` | 常に `null` |
|
|
393
|
-
| [`highlight`](#highlight) | `(code, language) => string` | 色付けしない |
|
|
394
|
-
| [`classNames`](#classnames) | `HtmlClassNames` | `defaultClassNames` |
|
|
395
|
-
| [`showPads`](#showpads) | `boolean` | `false` |
|
|
396
|
-
| [`handlers`](#handlers) | `NodeHandlers<string>` | 既定のハンドラ |
|
|
397
|
-
| [`style`](#style) | `string` | `<style>` を出さない |
|
|
398
|
-
|
|
399
|
-
上の 3 つは、記法に書かれていないので AST から導けない情報を外から渡す。
|
|
400
|
-
ページをどの URL で配信しているか、アイコン画像がどこにあるか、コードの構文がどう色分けされるかは、どれもソースには存在しない。
|
|
401
|
-
残りは出力の見た目と構造を調整する。
|
|
402
|
-
|
|
403
|
-
#### pageUrl
|
|
404
|
-
|
|
405
|
-
```ts
|
|
406
|
-
pageUrl?: (title: string, node: PageRefNode) => string
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
ページを指す記法の遷移先を決める。
|
|
410
|
-
対象は `[title]` と `[/proj/page]` と `#tag` と `[user.icon]` の 4 つ。
|
|
411
|
-
アイコンについてはリンク先だけを決め、画像は `iconImageUrl` が決める。
|
|
412
|
-
|
|
413
|
-
`title` は記法に書かれたタイトルそのままで、`[title]` なら `title`、`[/proj/page]` なら `/proj/page`、`#tag` なら `tag`、`[user.icon]` なら `user` が渡る。
|
|
414
|
-
ノード型で分岐する必要はない。
|
|
415
|
-
|
|
416
|
-
```ts
|
|
417
|
-
toHtml(page, { pageUrl: (title) => `/wiki/${encodeURIComponent(title)}` })
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
既定は `/{title}` で、区切りを含むタイトルは区切りを残して各段を encode する。
|
|
421
|
-
`defaultPageUrl` として export しているので、独自のハンドラからも呼べる。
|
|
422
|
-
|
|
423
|
-
外部リンクには効かない。
|
|
424
|
-
外部リンクは記法そのものが URL なので、解決するものがない。
|
|
425
|
-
|
|
426
|
-
#### iconImageUrl
|
|
427
|
-
|
|
428
|
-
```ts
|
|
429
|
-
iconImageUrl?: (node: IconNode) => string | null
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
`[user.icon]` の画像 URL を決める。
|
|
433
|
-
`null` を返すと `<img>` を出さず、ユーザー名のテキストリンクになる。
|
|
434
|
-
|
|
435
|
-
```ts
|
|
436
|
-
toHtml(page, {
|
|
437
|
-
iconImageUrl: (node) => `/api/pages/help-jp/${encodeURIComponent(node.user)}/icon`,
|
|
438
|
-
})
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
```html
|
|
442
|
-
<a class="link icon" href="/rakusai">
|
|
443
|
-
<img class="icon" src="/api/pages/help-jp/rakusai/icon" alt="rakusai" title="rakusai">
|
|
444
|
-
</a>
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
既定が `null` なのは、本家の画像 URL がプロジェクト名を含む (`/api/pages/{project}/{user}/icon`) 一方で、記法にプロジェクト名が書かれていないためである。
|
|
448
|
-
|
|
449
|
-
`[/icons/name.icon]` のように別プロジェクトを指す場合、`node.user` には `/icons/name` が入る。
|
|
450
|
-
|
|
451
|
-
> **注意**:
|
|
452
|
-
> `https://scrapbox.io/api/pages/{project}/{user}/icon` は `Cross-Origin-Resource-Policy: same-origin` を返す。
|
|
453
|
-
> scrapbox.io 以外のページの `<img>` からは読めず、`Access-Control-Allow-Origin` も無いので `crossorigin` 属性でも回避できない。
|
|
454
|
-
> 別オリジンで表示するなら、自前のサーバーやワーカーで中継してそちらに向ける。
|
|
455
|
-
|
|
456
|
-
#### highlight
|
|
457
|
-
|
|
458
|
-
```ts
|
|
459
|
-
highlight?: (code: string, language: string) => string
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
コードブロックの中身を色付けする。
|
|
463
|
-
シグネチャは markdown-it の同名オプションと同じなので、たいていのハイライタがそのまま嵌る。
|
|
464
|
-
|
|
465
|
-
```ts
|
|
466
|
-
import hljs from 'highlight.js'
|
|
467
|
-
|
|
468
|
-
toHtml(page, {
|
|
469
|
-
highlight: (code, language) =>
|
|
470
|
-
hljs.highlight(code, { language: hljs.getLanguage(language) ? language : 'plaintext' }).value,
|
|
471
|
-
})
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
`language` はファイル名から推測した名前で、拡張子があればそれ、無ければファイル名全体が渡る。
|
|
475
|
-
`code:hello.js` なら `js`、`code:python` なら `python` になる。
|
|
476
|
-
言語名の綴りはライブラリごとに違うので、必要なら受け取った側で読み替える。
|
|
477
|
-
|
|
478
|
-
戻り値は HTML としてそのまま埋め込まれるので、エスケープはハイライタの責任になる。
|
|
479
|
-
|
|
480
|
-
これを渡すと、コードブロックの本体は 1 行 1 要素ではなく 1 つの要素にまとまる。
|
|
481
|
-
ハイライタの出力が複数行にまたがるタグを含みうるためで、行で切るとタグが壊れる。
|
|
482
|
-
ヘッダ行とファイル名は変わらない。
|
|
483
|
-
|
|
484
|
-
```html
|
|
485
|
-
<div class="line code-block">
|
|
486
|
-
<code class="code-start">
|
|
487
|
-
<span class="code-block-start">a.js</span>
|
|
488
|
-
</code>
|
|
489
|
-
</div>
|
|
490
|
-
<div class="line code-block" data-indent="1">
|
|
491
|
-
<code class="code-body highlight">…ハイライタの出力…</code>
|
|
492
|
-
</div>
|
|
493
|
-
```
|
|
494
|
-
|
|
495
|
-
ライブラリごとの書きかたは次のとおり。
|
|
496
|
-
|
|
497
|
-
```ts
|
|
498
|
-
// Prism
|
|
499
|
-
highlight: (code, lang) => Prism.highlight(code, Prism.languages[lang] ?? Prism.languages.plain, lang)
|
|
500
|
-
|
|
501
|
-
// sugar-high
|
|
502
|
-
highlight: (code) => sugarHigh(code)
|
|
503
|
-
|
|
504
|
-
// Shiki は既定で <pre><code> ごと返すので、structure: 'inline' で中身だけにする
|
|
505
|
-
const shiki = await createHighlighter({ themes: ['github-light'], langs: ['js'] })
|
|
506
|
-
highlight: (code, lang) => shiki.codeToHtml(code, { lang, theme: 'github-light', structure: 'inline' })
|
|
507
|
-
```
|
|
7
|
+
- 依存は `effect` だけ。DOM も Node の API も使わないので、ブラウザでも Node でも Workers でも動く
|
|
8
|
+
- どのノードも元のテキストの何行目の何文字目から始まるかを持つので、エディタの色付けやカーソル位置の判定に使える
|
|
9
|
+
- AST はメソッドを持たないただのオブジェクト。`JSON.stringify` して保存しておき、あとで読み直せる
|
|
10
|
+
- 記法そのものを増やせる。プロジェクト固有の書きかたも元からある記法と同じように扱える
|
|
11
|
+
- パースだけなら gzip 約 8 KB。HTML 変換や走査は別の import 元なので、使わなければバンドルに入らない
|
|
508
12
|
|
|
509
|
-
|
|
13
|
+
> **beta**:公開 API はまだ変わりうる。安定するまではバージョンを固定して使うほうが安全。
|
|
510
14
|
|
|
511
|
-
|
|
512
|
-
toHtml(page, { highlight, classNames: { codeHighlight: 'highlight hljs' } })
|
|
513
|
-
```
|
|
15
|
+
### 次のリリースでの変更
|
|
514
16
|
|
|
515
|
-
|
|
17
|
+
- 記法の拡張 (`InlineConstruct` / `BracketRule`) は、成立しなければ **`null` を返す**普通の関数になった。
|
|
18
|
+
これまでは effect の `Option` を返す必要があり、拡張を書くのに effect が要った。
|
|
19
|
+
`Option.none()` は `null` に、`Option.some(x)` は `x` に書き換える。
|
|
20
|
+
- 拡張のルールに渡る文脈から `bracketRules` を外した。拡張から使う場面が無く、中の型が漏れていたため。
|
|
516
21
|
|
|
517
|
-
|
|
518
|
-
classNames?: HtmlClassNames
|
|
519
|
-
```
|
|
22
|
+
### 0.1.0-beta.1 の変更
|
|
520
23
|
|
|
521
|
-
|
|
522
|
-
指定したキーだけが既定を上書きする。
|
|
24
|
+
beta.0 から上げるときは次の 2 点に注意。
|
|
523
25
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
空文字を渡すと class 属性そのものを出さない。
|
|
26
|
+
- サブパス `./plugin` を **`./extensions`** に改名した。渡すものが `Extension` で
|
|
27
|
+
オプション名も `extensions` なのに、置き場所だけ別の語彙だったため。
|
|
28
|
+
コンパイラを書くための型 (`NodeHandlers` 等) は `./compile` にある。
|
|
29
|
+
- `decoration` ノードに **`markers`** を足した (必須)。書かれた装飾記号が
|
|
30
|
+
出現順・重複なしで入る。`toHtml` はこれを `deco-*` のような class として出す。
|
|
31
|
+
装飾ノードを自分で組み立てている拡張は追随が要る。
|
|
531
32
|
|
|
532
|
-
|
|
533
|
-
キーはノード型のほか、要素を持つ細部にも用意してある。
|
|
33
|
+
記号を増やす [`customDecorations`](https://cosense-toolbox.qaynam.dev/parser/extend/) も足した。
|
|
534
34
|
|
|
535
|
-
|
|
536
|
-
| :--- | :--- |
|
|
537
|
-
| `page` `title` `line` | ページ全体、1 行目、通常の行 |
|
|
538
|
-
| `quote` `monospace` | 引用行の `<blockquote>`、等幅行の `<code>` |
|
|
539
|
-
| `codeBlock` | コードブロックに属する行 (ヘッダと本体の両方) |
|
|
540
|
-
| `codeStart` `codeFilename` `codeBody` `codeHighlight` | ヘッダの `<code>`、ファイル名、本体の `<code>`、色付けした本体に足す class |
|
|
541
|
-
| `indentMark` `pad` `dot` | `showPads` のときだけ出る要素 |
|
|
542
|
-
| `internalLink` `externalLink` `projectLink` `hashtag` | 各リンク |
|
|
543
|
-
| `inlineCode` `image` `icon` `formula` `decoration` `table` | 各インライン記法とテーブル |
|
|
35
|
+
## インストール
|
|
544
36
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
```ts
|
|
548
|
-
showPads?: boolean
|
|
549
|
-
```
|
|
550
|
-
|
|
551
|
-
インデントを本家と同じ要素として書き出す。
|
|
552
|
-
深さ 1 段につき `pad` が 1 つ並び、その右端に中点が付く。
|
|
553
|
-
|
|
554
|
-
```html
|
|
555
|
-
<div class="line" data-indent="2">
|
|
556
|
-
<span class="indent-mark">
|
|
557
|
-
<span class="pad"> </span>
|
|
558
|
-
<span class="pad"> </span>
|
|
559
|
-
<span class="dot"></span>
|
|
560
|
-
</span>
|
|
561
|
-
字下げ
|
|
562
|
-
</div>
|
|
563
|
-
```
|
|
564
|
-
|
|
565
|
-
既定では要素を出さず、深さは `data-indent` 属性だけで表す。
|
|
566
|
-
中点は CSS の擬似要素で描けるので、見た目はどちらでも変わらない。
|
|
567
|
-
|
|
568
|
-
#### handlers
|
|
569
|
-
|
|
570
|
-
```ts
|
|
571
|
-
handlers?: NodeHandlers<string>
|
|
572
|
-
```
|
|
573
|
-
|
|
574
|
-
ノード型ごとの出力そのものを差し替える。
|
|
575
|
-
既定のハンドラに自動で重ねられるので、変えたい型だけ書けばよい。
|
|
576
|
-
|
|
577
|
-
```ts
|
|
578
|
-
toHtml(page, {
|
|
579
|
-
handlers: { formula: (node) => katex.renderToString(node.value) },
|
|
580
|
-
})
|
|
581
|
-
```
|
|
582
|
-
|
|
583
|
-
ハンドラは `(node, ctx)` を受け取る。
|
|
584
|
-
`ctx.children(node)` で子ノードの変換結果が配列で得られる。
|
|
585
|
-
|
|
586
|
-
```ts
|
|
587
|
-
handlers: {
|
|
588
|
-
line: (node, ctx) => `<p>${ctx.children(node).join('')}</p>`,
|
|
589
|
-
}
|
|
590
|
-
```
|
|
591
|
-
|
|
592
|
-
既定のハンドラ一式は `createHtmlHandlers(options)` で取れる。
|
|
593
|
-
既定の出力を包みたいときに使う。
|
|
594
|
-
|
|
595
|
-
拡張が足した独自のノード型も、`InlineNodeMap` を declaration merging で拡張してあればここのキーになる。
|
|
596
|
-
ハンドラを書かなかった独自ノードは、子があればその中身が出力される。
|
|
597
|
-
|
|
598
|
-
#### style
|
|
599
|
-
|
|
600
|
-
```ts
|
|
601
|
-
style?: string
|
|
602
|
-
```
|
|
603
|
-
|
|
604
|
-
渡した CSS を `<style>` 要素として出力の先頭に差し込む。
|
|
605
|
-
|
|
606
|
-
```ts
|
|
607
|
-
import css from '@cosense-toolbox/style/style.css?raw'
|
|
608
|
-
|
|
609
|
-
toHtml(page, { style: css })
|
|
610
|
-
// <style>…</style><div class="page">…</div>
|
|
611
|
-
```
|
|
612
|
-
|
|
613
|
-
iframe の `srcdoc` のように、1 つの文字列で完結させたいときに使う。
|
|
614
|
-
CSS そのものはこのパッケージに含まれていない。
|
|
615
|
-
|
|
616
|
-
#### 独自のハンドラを書く
|
|
617
|
-
|
|
618
|
-
`handlers` で要素ごと差し替えると、既定のハンドラがやっているエスケープと URL の検査が無くなる。
|
|
619
|
-
同じことをするための部品を export している。
|
|
620
|
-
|
|
621
|
-
| export | 役割 |
|
|
622
|
-
| :--- | :--- |
|
|
623
|
-
| `escapeHtml(value)` | `& < > " '` を実体参照にする |
|
|
624
|
-
| `safeHref(url)` | href に入れて安全な URL だけを返す。script が動くスキームなら `null` |
|
|
625
|
-
| `safeSrc(url)` | src 版。`data:` 画像は許す |
|
|
626
|
-
| `defaultPageUrl(title)` | `pageUrl` の既定の実装 |
|
|
627
|
-
| `defaultClassNames` | 既定の class 名 |
|
|
628
|
-
|
|
629
|
-
外部リンクを別タブで開く例を示す。
|
|
630
|
-
|
|
631
|
-
```ts
|
|
632
|
-
import { escapeHtml, safeHref, toHtml } from '@cosense-toolbox/parser/compile'
|
|
633
|
-
|
|
634
|
-
toHtml(page, {
|
|
635
|
-
handlers: {
|
|
636
|
-
externalLink: (node) => {
|
|
637
|
-
const href = safeHref(node.target)
|
|
638
|
-
return `<a class="link link-external" href="${escapeHtml(href ?? '')}" target="_blank" rel="noreferrer">${escapeHtml(node.label)}</a>`
|
|
639
|
-
},
|
|
640
|
-
},
|
|
641
|
-
})
|
|
642
|
-
```
|
|
643
|
-
|
|
644
|
-
ハンドラは `classNames` の設定を受け取らない。
|
|
645
|
-
両方を使う場合、class 名は書いた側で決めることになる。
|
|
646
|
-
|
|
647
|
-
#### エスケープと URL の検査
|
|
648
|
-
|
|
649
|
-
既定のハンドラは、テキストと属性値をすべてエスケープする。
|
|
650
|
-
`javascript:` と `vbscript:` のスキームは href と src の両方から落とし、`data:` は href からだけ落とす。
|
|
651
|
-
`data:` 画像には正当な使い道があるためである。
|
|
652
|
-
|
|
653
|
-
スキームの判定では、先に空白と制御文字を落とす。
|
|
654
|
-
ブラウザは途中にタブや改行が挟まった `javascript:` もスキームとして解釈するので、それを潰す。
|
|
655
|
-
|
|
656
|
-
`handlers` と `highlight` が返した文字列はそのまま埋め込む。
|
|
657
|
-
そこでのエスケープは書いた人の責任になる。
|
|
658
|
-
|
|
659
|
-
### toPlainText
|
|
660
|
-
|
|
661
|
-
記法を外したテキストを返す。
|
|
662
|
-
オプションは無い。
|
|
663
|
-
|
|
664
|
-
```ts
|
|
665
|
-
import { toPlainText } from '@cosense-toolbox/parser/compile'
|
|
666
|
-
|
|
667
|
-
toPlainText(parse('タイトル\n[* 太字] と [リンク]'))
|
|
668
|
-
// 'タイトル\n太字 と リンク'
|
|
37
|
+
```sh
|
|
38
|
+
npm i @cosense-toolbox/parser@beta
|
|
669
39
|
```
|
|
670
40
|
|
|
671
|
-
|
|
672
|
-
コードブロックとテーブルは中身がそのまま出る。
|
|
41
|
+
既定の見た目が要るなら [`@cosense-toolbox/style`](https://github.com/qaynam/cosense-toolbox/tree/main/packages/style) を別途入れる。
|
|
673
42
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
HTML 以外を出すときに使う。
|
|
677
|
-
`toHtml` も `toPlainText` もこれで書かれている。
|
|
43
|
+
## 使ってみる
|
|
678
44
|
|
|
679
45
|
```ts
|
|
680
|
-
import {
|
|
46
|
+
import { parse } from "@cosense-toolbox/parser"
|
|
47
|
+
import { collectLinks } from "@cosense-toolbox/parser/utils"
|
|
48
|
+
import { toHtml } from "@cosense-toolbox/parser/html"
|
|
681
49
|
|
|
682
|
-
const
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
decoration: (node, ctx) => `**${ctx.children(node).join('')}**`,
|
|
686
|
-
text: (node) => node.value,
|
|
687
|
-
},
|
|
688
|
-
fallback: (node, ctx) => ctx.children(node).join(''),
|
|
689
|
-
})
|
|
690
|
-
```
|
|
50
|
+
const page = parse(`今日のメモ
|
|
51
|
+
[プロジェクトA] の進捗を確認する
|
|
52
|
+
#あとで読む`)
|
|
691
53
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
## schema
|
|
696
|
-
|
|
697
|
-
`@cosense-toolbox/parser/schema` は、worklet や postMessage を跨いで受け取った、本当に `Page` か分からない値を検証する。
|
|
698
|
-
|
|
699
|
-
```ts
|
|
700
|
-
import { decodePage } from '@cosense-toolbox/parser/schema'
|
|
701
|
-
import { Either } from 'effect'
|
|
702
|
-
|
|
703
|
-
const decoded = decodePage(JSON.parse(input))
|
|
704
|
-
if (Either.isRight(decoded)) {
|
|
705
|
-
// decoded.right は Page
|
|
706
|
-
}
|
|
54
|
+
collectLinks(page) // → ['プロジェクトA', 'あとで読む']
|
|
55
|
+
toHtml(page) // → '<div class="page"><h1 class="title">今日のメモ</h1>…'
|
|
707
56
|
```
|
|
708
57
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
## plugin
|
|
58
|
+
## API
|
|
712
59
|
|
|
713
|
-
|
|
714
|
-
このサブパスは型だけを持ち、実行時のコードを含まない。
|
|
60
|
+
モジュールごとに export が分かれている。使うものだけ import すればよい。
|
|
715
61
|
|
|
716
|
-
|
|
62
|
+
| モジュール | 役割 | API |
|
|
63
|
+
| :----------------------------------- | :-------------------------------------------------- | :-------------------------------------------------------------------------------------- |
|
|
64
|
+
| `@cosense-toolbox/parser` | テキストを AST にする | `parse` `parseLine` `tokenizeInline` `createParser` `asImageSrc` `normalizeLineEndings` |
|
|
65
|
+
| `@cosense-toolbox/parser/utils` | ヘルパー。AST から取り出す | `visit` `find` `collect` `collectLinks` `firstImage` `rawTextOf` |
|
|
66
|
+
| `@cosense-toolbox/parser/html` | AST を HTML 系の出力 (hast と HTML の文字列) にする | `toHast` `toHtml` `codeLineNumbers` `tableCellLineBreaks` |
|
|
67
|
+
| `@cosense-toolbox/parser/compile` | AST を HTML 以外の形式にする | `toPlainText` `createCompiler` |
|
|
68
|
+
| `@cosense-toolbox/parser/extensions` | 記法を足す | `Extension` `InlineConstruct` `BracketRule` `customDecorations` `tableCellNotation` |
|
|
69
|
+
| `@cosense-toolbox/parser/schema` | 外から来た値を検証する | `decodePage` |
|
|
717
70
|
|
|
718
|
-
|
|
719
|
-
既定のルールより先に試されるので、既存の記法を上書きすることもできる。
|
|
720
|
-
|
|
721
|
-
```ts
|
|
722
|
-
import { Option } from 'effect'
|
|
723
|
-
import { parse } from '@cosense-toolbox/parser'
|
|
724
|
-
import type { Extension, InlineConstruct } from '@cosense-toolbox/parser/plugin'
|
|
71
|
+
各 API の詳細はドキュメントにある。
|
|
725
72
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
73
|
+
| ページ | 内容 |
|
|
74
|
+
| :--------------------------------------------------------------------- | :-------------------------------------------------------- |
|
|
75
|
+
| [概要](https://cosense-toolbox.qaynam.dev/parser/) | インストールと、どの API を使うかの早見表 |
|
|
76
|
+
| [例](https://cosense-toolbox.qaynam.dev/parser/demo/) | 記法をひととおり変換した結果とコード |
|
|
77
|
+
| [パース](https://cosense-toolbox.qaynam.dev/parser/parse/) | `parse` / `parseLine` / `tokenizeInline` / `createParser` |
|
|
78
|
+
| [AST と位置情報](https://cosense-toolbox.qaynam.dev/parser/ast/) | ノードの構造と `position` の意味 |
|
|
79
|
+
| [ヘルパー](https://cosense-toolbox.qaynam.dev/parser/utils/) | `visit` / `find` / `collect` など |
|
|
80
|
+
| [HTML への変換](https://cosense-toolbox.qaynam.dev/parser/html/) | `toHast` / `toHtml` と 8 つのオプション |
|
|
81
|
+
| [独自形式への変換](https://cosense-toolbox.qaynam.dev/parser/compile/) | `toPlainText` / `createCompiler` |
|
|
82
|
+
| [記法の拡張](https://cosense-toolbox.qaynam.dev/parser/extend/) | `Extension` と独自のノード型 |
|
|
735
83
|
|
|
736
|
-
|
|
737
|
-
parse(source, { extensions: [mentions] })
|
|
738
|
-
```
|
|
739
|
-
|
|
740
|
-
`[...]` の中身の解釈を足すなら `bracketRules` を使う。
|
|
741
|
-
同じ拡張で何度もパースするなら、`createParser({ extensions })` でパーサーを固定できる。
|
|
84
|
+
## 互換性の方針
|
|
742
85
|
|
|
743
|
-
|
|
86
|
+
| 変更 | バージョン |
|
|
87
|
+
| :------------------------------------------- | :--------- |
|
|
88
|
+
| 新しいノード `type` の追加 | minor |
|
|
89
|
+
| 既存ノードへの optional フィールド追加 | minor |
|
|
90
|
+
| オプションへの optional フィールド追加 | minor |
|
|
91
|
+
| 既存ノードのフィールドの削除、型変更、必須化 | major |
|
|
92
|
+
| `position` の意味論の変更 | major |
|
|
93
|
+
| ノード `type` 文字列のリネーム | major |
|
|
744
94
|
|
|
745
|
-
|
|
746
|
-
mdast と同じ手法で、`NodeHandlers` のキーにも `visit` の型引数にも自動で現れるので、描画まで型が通る。
|
|
95
|
+
ノード型は minor で増えうるので、`switch (node.type)` には `default` を置いておく。
|
|
747
96
|
|
|
748
|
-
|
|
749
|
-
declare module '@cosense-toolbox/parser' {
|
|
750
|
-
interface InlineNodeMap {
|
|
751
|
-
mention: { type: 'mention'; user: string; position: Position }
|
|
752
|
-
}
|
|
753
|
-
}
|
|
97
|
+
## 開発
|
|
754
98
|
|
|
755
|
-
|
|
756
|
-
const mention: InlineConstruct = (source, index) => { /* → { type: 'mention', user } */ }
|
|
99
|
+
規約は [CLAUDE.md](./CLAUDE.md) にある。
|
|
757
100
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
101
|
+
```sh
|
|
102
|
+
bun install
|
|
103
|
+
bun run test
|
|
104
|
+
bun run build
|
|
762
105
|
```
|
|
763
106
|
|
|
764
|
-
ハンドラを書かなかった独自ノードは、子があればその中身が出力される。
|
|
765
|
-
|
|
766
|
-
## 設計
|
|
767
|
-
|
|
768
|
-
パースは総関数で、どんな入力でも例外を投げず必ず `Page` を返す。
|
|
769
|
-
記法として成立しない部分は素のテキストになるだけで、エラーにはならない。
|
|
770
|
-
|
|
771
|
-
I/O をしない。
|
|
772
|
-
oEmbed の取得や動画判定のような URL の意味解決は、このパッケージの外の仕事になる。
|
|
773
|
-
画像かどうかの判定だけは、記法の構造そのものを決めるので含んでいる。
|
|
774
|
-
|
|
775
|
-
構造は micromark の「位置つきノードと記法ハンドラの登録制」と、markdown-it の「優先順位付きルールを先頭から試す」形を参考にしている。
|
|
776
|
-
|
|
777
|
-
開発時の規約は [CLAUDE.md](./CLAUDE.md) にある。
|
|
778
|
-
|
|
779
|
-
## 互換性の方針
|
|
780
|
-
|
|
781
|
-
| 変更 | バージョン |
|
|
782
|
-
| :--- | :--- |
|
|
783
|
-
| 新しいノード `type` の追加 | minor |
|
|
784
|
-
| 既存ノードへの optional フィールド追加 | minor |
|
|
785
|
-
| オプションへの optional フィールド追加 | minor |
|
|
786
|
-
| 既存ノードのフィールドの削除、型変更、必須化 | major |
|
|
787
|
-
| `position` の意味論の変更 | major |
|
|
788
|
-
| ノード `type` 文字列のリネーム | major |
|
|
789
|
-
|
|
790
|
-
ノード型は minor で増えうるので、`switch (node.type)` には `default` を置いておくとよい。
|
|
791
|
-
|
|
792
107
|
## ライセンス
|
|
793
108
|
|
|
794
|
-
MIT
|
|
109
|
+
MIT。
|
|
110
|
+
|
|
111
|
+
このパッケージは Cosense (Scrapbox) の記法を解釈する非公式の実装である。
|
|
112
|
+
開発元である Helpfeel 社とは関係がなく、公認も受けていない。
|