@tenjuu99/blog 0.3.4 → 0.3.6

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/docs/develop.md CHANGED
@@ -105,8 +105,8 @@ tenjuu99-blog/
105
105
 
106
106
  1. **Red(テスト作成)**: 失敗するテストを書く
107
107
  ```bash
108
- # test/ ディレクトリにテストファイルを作成
109
- # 例: test/category-tree.test.js
108
+ # tests/ ディレクトリにテストファイルを作成
109
+ # 例: tests/category-tree.test.js
110
110
  ```
111
111
 
112
112
  2. **Green(最小限の実装)**: テストがパスする最小限のコードを書く
@@ -124,13 +124,13 @@ tenjuu99-blog/
124
124
 
125
125
  **テストファイルの配置:**
126
126
 
127
- - `test/` ディレクトリに `*.test.js` 形式で配置
127
+ - `tests/` ディレクトリに `*.test.js` 形式で配置
128
128
  - Node.js標準のテストランナーを使用(`node --test`)
129
129
 
130
130
  **テストの例:**
131
131
 
132
132
  ```javascript
133
- // test/example.test.js
133
+ // tests/example.test.js
134
134
  import { test } from 'node:test'
135
135
  import assert from 'node:assert'
136
136
  import { myFunction } from '../lib/myModule.js'
@@ -143,7 +143,7 @@ test('機能の説明', () => {
143
143
 
144
144
  **実装例(カテゴリー機能の場合):**
145
145
 
146
- 1. `test/category-tree.test.js` - カテゴリーツリー構築のテスト(12件)
146
+ 1. `tests/category-tree.test.js` - カテゴリーツリー構築のテスト(12件)
147
147
  2. `packages/category/helper/category.js` - 実装
148
148
  3. `npm test` - テスト実行
149
149
  4. すべてパス後、次のテストを作成
@@ -480,7 +480,7 @@ npm run test:watch # ウォッチモード
480
480
  新しいテストを追加する場合:
481
481
 
482
482
  ```javascript
483
- // test/example.test.js
483
+ // tests/example.test.js
484
484
  import { test } from 'node:test';
485
485
  import assert from 'node:assert';
486
486
 
@@ -0,0 +1,553 @@
1
+ # 語彙定義: tenjuu99-blog
2
+
3
+ **最終更新:** 2026-06-25(editor-image-converter 昇格 - ビルトインコンバーター・ビルド画像配布器を追加)
4
+
5
+ ---
6
+
7
+ ## SSGコア
8
+
9
+ **dir:** ssg-core
10
+ **対象領域:** Markdownソースファイルから静的HTMLサイトを生成すること。
11
+ **主なユーザー:** SSGエンジンを開発・保守する技術者。
12
+ **境界の内:** ページのフロントマター解析、テンプレート適用、Markdown→HTMLレンダリング、全ページのインデックス化、ビルド出力、パッケージシステム(キャッシュ機構)。
13
+ **境界の外:** 誰がどうコンテンツを編集するか(エディタ)、ページをどのカテゴリーに分類するか(カテゴリー)、HTTPサーバーとしての動作(サーバー)、ファイル監視・ホットリロード(開発サーバー)。
14
+
15
+ ---
16
+
17
+ **アプリケーションドメイン**
18
+
19
+ ### ページ
20
+
21
+ **定義:** Markdownソースファイルを起点に生成されるコンテンツの単位。[フロントマター](#フロントマター)と本文から成り、[テンプレート](#テンプレート)を通じてHTMLとして出力される。
22
+ **関係:** [フロントマター](#フロントマター)を持つ。[テンプレート](#テンプレート)が適用される。[ページインデックス](#ページインデックス)に収録される。
23
+
24
+ ---
25
+
26
+ ### フロントマター
27
+
28
+ **定義:** ページ冒頭の `---` または `<!--` で囲んだメタデータ領域。タイトル・URL・公開日・テンプレート名など、[ページ](#ページ)の属性を定義する。
29
+ **関係:** [ページ](#ページ)が持つ。[テンプレート](#テンプレート)内で変数として展開される。[ページインデックス](#ページインデックス)のデータ源となる。
30
+
31
+ ---
32
+
33
+ ### テンプレート
34
+
35
+ **定義:** [ページ](#ページ)のHTML構造を定義するファイル。変数展開・条件分岐・[SSGスクリプト](#ssgスクリプト)を記述でき、[フロントマター](#フロントマター)の値を参照してHTMLを生成する。
36
+ **関係:** [ページ](#ページ)に適用される。[フロントマター](#フロントマター)の変数を参照する。[ヘルパー関数](#ヘルパー関数)を呼び出せる。[SSGスクリプト](#ssgスクリプト)を含む。
37
+
38
+ ---
39
+
40
+ ### ヘルパー関数
41
+
42
+ **定義:** [テンプレート](#テンプレート)や[SSGスクリプト](#ssgスクリプト)から呼び出せる拡張関数。[ページインデックス](#ページインデックス)へのアクセス・日付フォーマット・一覧生成など、テンプレートエンジンの組み込み機能を超えた処理を担う。[パッケージ](#パッケージ)が自動提供することがある。
43
+ **関係:** [テンプレート](#テンプレート)から呼び出される。[ページインデックス](#ページインデックス)を参照できる。[パッケージ](#パッケージ)が提供することがある。
44
+
45
+ ---
46
+
47
+ ### ページインデックス
48
+
49
+ **定義:** 全[ページ](#ページ)の[フロントマター](#フロントマター)データを収めたコレクション(`allData`)。一覧ページや関連ページの生成、カテゴリー分類など、複数ページにまたがる処理の参照源となる。[ビルド](#ビルド)時に全ページをスキャンして生成される。
50
+ **関係:** 全[ページ](#ページ)の[フロントマター](#フロントマター)を収める。[ヘルパー関数](#ヘルパー関数)・[SSGスクリプト](#ssgスクリプト)から参照される。[ビルド](#ビルド)の産物。
51
+
52
+ ---
53
+
54
+ ### SSGスクリプト
55
+
56
+ **定義:** [テンプレート](#テンプレート)内の `<script type="ssg">` ブロックに記述し、[ビルド](#ビルド)時に実行されるJavaScriptコード。`return` で返した値がHTMLに展開される。[ページインデックス](#ページインデックス)や[ヘルパー関数](#ヘルパー関数)を参照できる。
57
+ **関係:** [テンプレート](#テンプレート)に記述される。[ヘルパー関数](#ヘルパー関数)を呼び出せる。[ページインデックス](#ページインデックス)を参照できる。
58
+
59
+ ---
60
+
61
+ ### パッケージ
62
+
63
+ **定義:** [ヘルパー関数](#ヘルパー関数)・[テンプレート](#テンプレート)・CSSをひとまとめにした拡張モジュール。`blog.json` で有効化することでSSGの機能を拡張する。パッケージのファイルはユーザーコードで上書きできる。
64
+ **関係:** [ヘルパー関数](#ヘルパー関数)・[テンプレート](#テンプレート)を提供する。[ページインデックス](#ページインデックス)を参照できる。[ビルド](#ビルド)時に[キャッシュ](#キャッシュ)に展開される。
65
+
66
+ ---
67
+
68
+ ### キャッシュ
69
+
70
+ en: Cache
71
+ **定義:** [ビルド](#ビルド)前にソースファイルと[パッケージ](#パッケージ)のファイルを集積するステージングディレクトリ(`.cache/`)。[パッケージ](#パッケージ)のファイルが先に展開され、その後ユーザーの `src/` が上書きコピーされる。ビルドエンジンはこのディレクトリを実際の処理対象とする。
72
+ **関係:** [パッケージ](#パッケージ)のファイルを受け取る。[ビルド](#ビルド)の入力源となる。[サーバーハンドラー](#サーバーハンドラー)(サーバー)の配置先でもある。
73
+
74
+ ---
75
+
76
+ ### ビルド
77
+
78
+ **定義:** 全ソースファイルをスキャンして[ページインデックス](#ページインデックス)を構築し、各[ページ](#ページ)に[テンプレート](#テンプレート)を適用してHTMLを出力するプロセス。`npx generate` または開発サーバーが担う。
79
+ **関係:** [ページインデックス](#ページインデックス)を生成する。[テンプレート](#テンプレート)を[ページ](#ページ)に適用する。[パッケージ](#パッケージ)の展開も含む。
80
+
81
+ ---
82
+
83
+ **ソリューションドメイン**
84
+
85
+ ### フィルター
86
+
87
+ en: Filter
88
+ **定義:** [テンプレート](#テンプレート)テキストを処理する変換関数の総称。変数展開・条件分岐(`{if}`)・[SSGスクリプト](#ssgスクリプト)実行の各処理が独立したフィルターとして実装され、パイプライン状に適用される。
89
+ **関係:** [テンプレート](#テンプレート)に適用される。[SSGスクリプト](#ssgスクリプト)はフィルターの一種として実行される。
90
+ **src:** `lib/filter.js`、`lib/replaceVariablesFilter.js`、`lib/includeFilter.js`
91
+
92
+ ---
93
+
94
+ ### ビルド画像配布器
95
+
96
+ en: BuildImageDistributor
97
+ **定義:** ビルドコマンド実行時に、変換設定に従い画像を dist ディレクトリに出力する装置。変換設定がある場合は各画像ファイルを[コンバーターファクトリー](#コンバーターファクトリー)が解決した変換ドライバーに通し、ない場合はそのままコピーする。
98
+ **インターフェース:**
99
+ ```js
100
+ distributeImages(srcDir, distDir, { fn, ext })
101
+ // fn: Buffer → Promise<Buffer>
102
+ // ext: 出力拡張子(null のとき元の拡張子を保持)
103
+ ```
104
+ **関係:**
105
+ - `references`: [コンバーターファクトリー](#コンバーターファクトリー) — 解決済みの変換関数 `{ fn, ext }` を受け取る
106
+ - `references`: [ビルド](#ビルド) — ビルドの一部として実行される
107
+ **src:** `lib/imageDistributor.js`
108
+
109
+ ---
110
+
111
+ ## サーバー
112
+
113
+ **dir:** server
114
+ **対象領域:** HTTPリクエストをハンドラースクリプトに振り分ける拡張機構。`src/server/` にスクリプトを配置することでAPIエンドポイントを追加できる。
115
+ **主なユーザー:** エディタ等のパッケージ開発者、サーバーサイド機能を追加したいユーザー。
116
+ **境界の内:** ハンドラースクリプトの登録・ディスパッチ、サーバーディレクトリ規約。
117
+ **境界の外:** ページのHTMLレンダリング(SSGコア)、開発時のファイル監視・ホットリロード(開発サーバー)。
118
+
119
+ ---
120
+
121
+ **アプリケーションドメイン**
122
+
123
+ ### サーバーハンドラー
124
+
125
+ en: ServerHandler
126
+ **定義:** `path` とHTTPメソッド関数(`get`・`post` 等)をエクスポートするスクリプト。[サーバーディレクトリ](#サーバーディレクトリ)に配置することで自動登録され、対応するURLへのリクエストを処理する。
127
+ **関係:** [サーバーディレクトリ](#サーバーディレクトリ)に配置される。[ハンドラー登録](#ハンドラー登録)によってパスと紐づけられる。エディタパッケージが具体的な実装例を提供する。
128
+
129
+ ---
130
+
131
+ ### サーバーディレクトリ
132
+
133
+ en: ServerDir
134
+ **定義:** [サーバーハンドラー](#サーバーハンドラー)スクリプトを配置するディレクトリ。[キャッシュ](#キャッシュ)(SSGコア)の `.cache/server/` が実際の参照先で、`src/server/` の内容が[パッケージ](#パッケージ)(SSGコア)の仕組みで展開される。
135
+ **関係:** [サーバーハンドラー](#サーバーハンドラー)を格納する。[ハンドラー登録](#ハンドラー登録)の対象となる。
136
+
137
+ ---
138
+
139
+ **ソリューションドメイン**
140
+
141
+ ### ハンドラー登録
142
+
143
+ en: HandlerRegistration
144
+ **定義:** [サーバーディレクトリ](#サーバーディレクトリ)のスクリプトを動的ロードし、各スクリプトの `path` エクスポートをキーにして[サーバーハンドラー](#サーバーハンドラー)を登録する仕組み。初回リクエスト時に一度だけ実行される。
145
+ **関係:** [サーバーディレクトリ](#サーバーディレクトリ)のスクリプトを読み込む。[サーバーハンドラー](#サーバーハンドラー)を `path` と紐づける。
146
+ **src:** `lib/tryServer.js`
147
+
148
+ ---
149
+
150
+ ## 開発サーバー
151
+
152
+ **dir:** dev-server
153
+ **対象領域:** ソースファイルの変更を検知して自動再ビルドし、ブラウザへホットリロードで反映する開発支援環境。
154
+ **主なユーザー:** ブログの開発者・コンテンツ作成者(`npx server` で起動)。
155
+ **境界の内:** ファイル監視、変更時の再ビルドトリガー、ホットリロード通知。
156
+ **境界の外:** ページのHTMLレンダリング(SSGコア)、HTTPリクエストのディスパッチ(サーバー)。
157
+
158
+ ---
159
+
160
+ **アプリケーションドメイン**
161
+
162
+ ### ウォッチャー
163
+
164
+ en: Watcher
165
+ **定義:** ソースファイルの変更・追加・削除を監視し、登録されたコールバックをトリガーする機構。複数のウォッチャーを優先度付きで登録でき、優先ウォッチャーが先に実行される。
166
+ **関係:** [開発サーバー](#開発サーバー)が利用する。変更検知時に[ビルド](#ビルド)(SSGコア)の再実行をトリガーする。
167
+ **src:** `lib/watcher.js`
168
+
169
+ ---
170
+
171
+ ### ホットリロード
172
+
173
+ en: HotReload
174
+ **定義:** ファイル変更検知後に自動再ビルドを実行し、ブラウザを更新する一連の動作。[ウォッチャー](#ウォッチャー)が変更を検知して[ビルド](#ビルド)を再実行し、結果をブラウザに反映する。
175
+ **関係:** [ウォッチャー](#ウォッチャー)によってトリガーされる。[ビルド](#ビルド)(SSGコア)を再実行する。
176
+
177
+ ---
178
+
179
+ **ソリューションドメイン**
180
+
181
+ (実装後に定義する)
182
+
183
+ ---
184
+
185
+ ## エディタ
186
+
187
+ **dir:** editor
188
+ **対象領域:** ブラウザUIで非技術者がコンテンツを作成・編集・公開すること。
189
+ **主なユーザー:** ターミナルを使わないコンテンツ作成者。
190
+ **境界の内:** ファイルの選択と表示、テキスト編集、プレビュー、保存、公開(git push)、AIへの相談、画像アップロード、サイドバーナビゲーション。
191
+ **境界の外:** ファイルがHTMLにどう変換されるか(SSGコア)、カテゴリー階層の生成(カテゴリー)。
192
+
193
+ ---
194
+
195
+ **アプリケーションドメイン**
196
+
197
+ ### サイドバー
198
+
199
+ **定義:** エディタ左部に表示されるナビゲーション領域。ファイルの一覧を表示し、目的のファイルへ移動する起点となる。
200
+ **関係:** [ディレクトリツリー](#ディレクトリツリー)を表示する。
201
+
202
+ ---
203
+
204
+ ### ファイルリスト
205
+
206
+ **定義:** ファイルパスを一次元配列として表現したファイルの一覧。ディレクトリ構造を無視してフラットに並べた形式。[ツリービルダー](#ツリービルダー)が[ネスト変換](#ネスト変換)する際の入力データとなる。
207
+ **関係:** [ツリービルダー](#ツリービルダー)への入力となる。[ネスト変換](#ネスト変換)によって[ディレクトリツリー](#ディレクトリツリー)のデータ表現へと変換される。
208
+
209
+ ---
210
+
211
+ ### ディレクトリツリー
212
+
213
+ **定義:** ファイルをディレクトリ階層に従って整理した木構造の表示。[ファイルリスト](#ファイルリスト)を置き換えて[サイドバー](#サイドバー)に表示される。
214
+ **関係:** [サイドバー](#サイドバー)に表示される。[ディレクトリノード](#ディレクトリノード)と[ファイルノード](#ファイルノード)から成る。[ツリービルダー](#ツリービルダー)と[ツリーレンダラー](#ツリーレンダラー)によって実現される。
215
+
216
+ ---
217
+
218
+ ### ディレクトリノード
219
+
220
+ **定義:** [ディレクトリツリー](#ディレクトリツリー)を構成する枝要素。配下の[ファイルノード](#ファイルノード)や子[ディレクトリノード](#ディレクトリノード)を含み、[展開状態](#展開状態)を持つ。
221
+ **関係:** [ディレクトリツリー](#ディレクトリツリー)を構成する。[展開状態](#展開状態)を持つ。[ファイルノード](#ファイルノード)や子[ディレクトリノード](#ディレクトリノード)を含む。[ツリーレンダラー](#ツリーレンダラー)によって `<details>/<summary>` として具現化される。
222
+
223
+ ---
224
+
225
+ ### ファイルノード
226
+
227
+ **定義:** [ディレクトリツリー](#ディレクトリツリー)の葉要素。エディタで開くファイルへのリンクを提供する。[アクティブファイル](#アクティブファイル)のファイルノードは他と区別して表示される。
228
+ **関係:** [ディレクトリノード](#ディレクトリノード)の子として存在する。[アクティブファイル](#アクティブファイル)かどうかで表示状態が変わる。[ツリーレンダラー](#ツリーレンダラー)によってエディタリンク `<a>` として具現化される。
229
+
230
+ ---
231
+
232
+ ### アクティブファイル
233
+
234
+ **定義:** 現在エディタで開いているファイル。URLパラメータ `?md=` で識別される。[サイドバー](#サイドバー)初期化時に参照され、対応する[ファイルノード](#ファイルノード)をハイライトし、その親[ディレクトリノード](#ディレクトリノード)を自動展開する。
235
+ **関係:** [ファイルノード](#ファイルノード)の属性として現れる。[ディレクトリノード](#ディレクトリノード)の初期[展開状態](#展開状態)に影響する。
236
+
237
+ ---
238
+
239
+ ### 展開状態
240
+
241
+ **定義:** [ディレクトリノード](#ディレクトリノード)が開いているか閉じているかの状態。localStorage を通じてセッション間で永続化される。
242
+ **関係:** [ディレクトリノード](#ディレクトリノード)が持つ。[アクティブファイル](#アクティブファイル)を含む[ディレクトリノード](#ディレクトリノード)は初期状態で展開される。
243
+
244
+ ---
245
+
246
+ ### 保存
247
+
248
+ **定義:** テキストエリアの内容をローカルファイルシステムに書き込む操作。エディタの save ボタンで実行され、成功すると対応するページへリダイレクトされる。
249
+ **関係:** [ページ](#ページ)(SSGコア)のソースファイルを更新する。[公開](#公開)とは別操作(保存はローカル変更のみ、公開は外部への反映)。
250
+
251
+ ---
252
+
253
+ ### プレビュー
254
+
255
+ **定義:** テキストエリアの Markdown を HTML レンダリングしてリアルタイムに表示する領域。開発サーバーが生成した HTML が `<iframe>` 内に埋め込まれる。
256
+ **関係:** [ページ](#ページ)(SSGコア)のレンダリング結果を表示する。[テンプレート](#テンプレート)(SSGコア)が適用された状態が反映される。
257
+
258
+ ---
259
+
260
+ ### インライン画像挿入
261
+
262
+ **定義:** ドラッグ&ドロップで画像をアップロードし、本文カーソル位置に `![](url)` 形式の Markdown 画像構文を挿入する操作。フロントマターへのURL挿入など他の画像参照ユースケースとは区別される。
263
+ **関係:**
264
+ - `references`: [保存](#保存) — テキスト保存とは別操作
265
+ - `references`: [ドロップレシーバー](#ドロップレシーバー) — 起点となる装置
266
+ - `references`: [画像アップローダー](#画像アップローダー) — アップロードを担う装置
267
+ - `references`: [アップロードエンドポイント](#アップロードエンドポイント) — サーバー側の処理を担う装置
268
+ - `references`: [Markdown挿入器](#markdown挿入器) — 挿入を担う装置
269
+ - `references`: [画像保存先パス](#画像保存先パス) — 自動決定される
270
+
271
+ ---
272
+
273
+ ### 画像保存先パス
274
+
275
+ **定義:** 編集中のMarkdownファイルパスから自動決定される、画像の配置先。例: `book/painting/claude-monet.md` を編集中なら `src/image/book/painting/claude-monet/` 配下。
276
+ **関係:**
277
+ - `belongs_to`: [インライン画像挿入](#インライン画像挿入) — インライン画像挿入の際に自動決定される
278
+ - `references`: [パスリゾルバー](#パスリゾルバー) — パスリゾルバーが導出する
279
+
280
+ ---
281
+
282
+ **ソリューションドメイン**
283
+
284
+ ### ツリービルダー
285
+
286
+ **定義:** フラットな[ファイルリスト](#ファイルリスト)を、ディレクトリ階層を反映したネストオブジェクト(ツリーデータ)に変換する装置。[ネスト変換](#ネスト変換)を核操作として持つ。実装は `buildTree(files)` 関数。
287
+ **関係:** [ファイルリスト](#ファイルリスト)(アプリドメイン)を受け取り、[ディレクトリツリー](#ディレクトリツリー)(アプリドメイン)のデータ表現を生成する。[ツリーレンダラー](#ツリーレンダラー)への入力となる。[ネスト変換](#ネスト変換)を行う。
288
+
289
+ ---
290
+
291
+ ### ツリーレンダラー
292
+
293
+ **定義:** [ツリービルダー](#ツリービルダー)が生成したツリーデータを HTML 文字列に変換する装置。[ディレクトリノード](#ディレクトリノード)を `<details>/<summary>`、[ファイルノード](#ファイルノード)をエディタリンク `<a>` として出力する。[アクティブファイル](#アクティブファイル)のノードには `class="active"` を付与する。実装は `renderTreeHtml(tree, activeFile)` 関数。
294
+ **関係:** [ツリービルダー](#ツリービルダー)の出力を受け取る。[ディレクトリノード](#ディレクトリノード)・[ファイルノード](#ファイルノード)・[アクティブファイル](#アクティブファイル)(すべてアプリドメイン)を HTML として具現化する。
295
+
296
+ ---
297
+
298
+ ### ネスト変換
299
+
300
+ **定義:** フラットな[ファイルリスト](#ファイルリスト)を、ディレクトリ階層を反映したネスト構造のオブジェクトに変換する操作。パスを `/` で分割し、各ディレクトリを `dirs` に、最終要素をファイルとして `files` に格納する。
301
+ **関係:** [ツリービルダー](#ツリービルダー)が担う核操作。[ファイルリスト](#ファイルリスト)(アプリドメイン)を[ディレクトリツリー](#ディレクトリツリー)(アプリドメイン)のデータ表現へと変換する橋渡し。
302
+
303
+ ---
304
+
305
+ ### ディレクトリ
306
+
307
+ **定義:** コンテンツファイルを格納するファイルシステム上のフォルダ。[サイドバー](#サイドバー)の[ディレクトリツリー](#ディレクトリツリー)として表示される階層単位であり、[フロントマターテンプレート](#フロントマターテンプレート)の適用単位にもなる。
308
+ **関係:**
309
+ - `references`: [サイドバー](#サイドバー) — ディレクトリツリーとして表示される
310
+ - `references`: [フロントマターテンプレート](#フロントマターテンプレート) — テンプレートの適用単位として使われる
311
+
312
+ ---
313
+
314
+ ### フロントマターテンプレート
315
+
316
+ **定義:** 特定の[ディレクトリ](#ディレクトリ)配下に新規ページを作るとき、エディタのテキストエリアにあらかじめ挿入される[フロントマター](#フロントマター)の雛形。変数名とデフォルト値のペアで構成される。
317
+ **関係:**
318
+ - `references`: [ディレクトリ](#ディレクトリ) — ディレクトリに対応する
319
+ - `references`: [フロントマター](#フロントマター) — SSGコアのフロントマターの初期値を提供する
320
+
321
+ ---
322
+
323
+ ### テンプレート設定
324
+
325
+ **定義:** `blog.json` に記述される、[ディレクトリ](#ディレクトリ)と[フロントマターテンプレート](#フロントマターテンプレート)の対応関係の定義。`frontmatter_templates` キーとして配列で保持される。
326
+ **関係:**
327
+ - `references`: [ディレクトリ](#ディレクトリ) — ディレクトリとフロントマターテンプレートを対応付ける
328
+ - `references`: [フロントマターテンプレート](#フロントマターテンプレート) — エディタが読み込む設定源となる
329
+
330
+ ---
331
+
332
+ ### フロントマターテンプレートローダー
333
+
334
+ **定義:** ファイルパスと[テンプレート設定](#テンプレート設定)一覧を受け取り、マッチする[フロントマターテンプレート](#フロントマターテンプレート)を文字列に変換して返す装置。[テンプレートマッチャー](#テンプレートマッチャー)と[テンプレートインジェクター](#テンプレートインジェクター)を組み合わせた合成。マッチするテンプレートがない場合は null を返す。
335
+ **関係:**
336
+ - `references`: [テンプレートマッチャー](#テンプレートマッチャー) — マッチャーとインジェクターを合成する
337
+ - `references`: [テンプレートインジェクター](#テンプレートインジェクター)
338
+ **src:** `packages/editor/js/frontmatter_template.js` `loadFrontmatterTemplate(filePath, templates)`
339
+ **注記:** `packages/editor/js/editor.js` にブラウザ環境用のインライン実装が存在する(ESモジュール import 不可のため)。変更時は両方に同じ修正を適用すること。
340
+
341
+ ---
342
+
343
+ ### テンプレートマッチャー
344
+
345
+ **定義:** 入力された新規ファイル名のパスを検査して、[テンプレート設定](#テンプレート設定)の中から最もマッチする[フロントマターテンプレート](#フロントマターテンプレート)を選択する装置。複数マッチする場合は最も長いプレフィックスを優先する。
346
+ **関係:**
347
+ - `references`: [テンプレート設定](#テンプレート設定) — テンプレート設定を参照する
348
+ - `references`: [フロントマターテンプレート](#フロントマターテンプレート) — マッチしたテンプレートを返す
349
+ **src:** `packages/editor/js/frontmatter_template.js` `matchTemplate(filePath, templates)`
350
+ **注記:** `packages/editor/js/editor.js` にブラウザ環境用のインライン実装が存在する(ESモジュール import 不可のため)。変更時は両方に同じ修正を適用すること。
351
+
352
+ ---
353
+
354
+ ### テンプレートレゾルバー
355
+
356
+ **定義:** [テンプレート設定](#テンプレート設定)をサーバーから取得し、[テンプレートマッチャー](#テンプレートマッチャー)に渡す調停役。エディタ初期化時に一度だけ呼ばれる。
357
+ **関係:**
358
+ - `references`: [テンプレート設定](#テンプレート設定) — サーバーエンドポイントからテンプレート設定を取得する
359
+ - `references`: [テンプレートマッチャー](#テンプレートマッチャー) — 設定をマッチャーに渡す
360
+ **src:** `packages/editor/js/editor.js` `initFrontmatterTemplate()` / `packages/editor/server/get_frontmatter_templates.js`
361
+
362
+ ---
363
+
364
+ ### テンプレートインジェクター
365
+
366
+ **定義:** 選択された[フロントマターテンプレート](#フロントマターテンプレート)をフロントマター文字列に変換して、エディタのテキストエリアに挿入する装置。ファイル名からタイトルを導出して `title` に埋め、`---` で囲んだ形式で出力する。
367
+ **関係:**
368
+ - `references`: [フロントマターテンプレート](#フロントマターテンプレート) — テンプレートを受け取りフロントマター文字列を生成する
369
+ **src:** `packages/editor/js/frontmatter_template.js` `buildFrontmatterString(template, baseName)`
370
+ **注記:** `packages/editor/js/editor.js` にブラウザ環境用のインライン実装が存在する(ESモジュール import 不可のため)。変更時は両方に同じ修正を適用すること。
371
+
372
+ ---
373
+
374
+ ### ドロップレシーバー
375
+
376
+ **定義:** テキストエリア上のドロップ操作から画像ファイルを取り出す装置。
377
+ **関係:**
378
+ - `references`: [インライン画像挿入](#インライン画像挿入) — インライン画像挿入の起点
379
+ - `references`: [画像アップローダー](#画像アップローダー) — 取り出した画像ファイルを渡す
380
+ **src:** `packages/editor/js/editor.js`
381
+
382
+ ---
383
+
384
+ ### 画像アップローダー
385
+
386
+ **定義:** 画像ファイルをサーバーに送信し、保存後の画像パスを受け取る装置。
387
+ **関係:**
388
+ - `references`: [ドロップレシーバー](#ドロップレシーバー) — 画像を受け取る
389
+ - `references`: [アップロードエンドポイント](#アップロードエンドポイント) — 通信する
390
+ - `references`: [Markdown挿入器](#markdown挿入器) — 受け取った画像パスを渡す
391
+ **src:** `packages/editor/js/editor.js`
392
+
393
+ ---
394
+
395
+ ### アップロードエンドポイント
396
+
397
+ **定義:** 画像データを受け取り、保存先を決定して変換・保存し、画像パスを返すHTTPハンドラ。
398
+ **関係:**
399
+ - `references`: [画像アップローダー](#画像アップローダー) — リクエストを受け取る
400
+ - `references`: [パスリゾルバー](#パスリゾルバー) — 呼び出す
401
+ - `references`: [画像コンバーター](#画像コンバーター) — 呼び出す
402
+ - `references`: [ファイルライター](#ファイルライター) — 呼び出す
403
+ - `references`: [画像保存先パス](#画像保存先パス) — レスポンスで返す
404
+ **src:** `packages/editor/server/image_upload.js` `post` / `handleImageUpload`
405
+
406
+ ---
407
+
408
+ ### パスリゾルバー
409
+
410
+ **定義:** 編集中MarkdownファイルのパスとファイルURLから、画像の保存先パスとMarkdown埋め込みURLを導出する装置。
411
+ **関係:**
412
+ - `references`: [アップロードエンドポイント](#アップロードエンドポイント) — 呼び出される
413
+ - `references`: [画像保存先パス](#画像保存先パス) — 具現化する
414
+ **src:** `packages/editor/server/image_upload.js` `resolveImagePath`
415
+
416
+ ---
417
+
418
+ ### コンバーターファクトリー
419
+
420
+ **定義:** 設定(blog.json)の `image_converter` を解釈し[画像コンバーター](#画像コンバーター)を生成する装置。ビルトイン名(例: `"sharp"`)はパッケージ内の `converters/` から解決し、パス(`.` または `/` で始まる)はプロジェクトルートを起点に[ユーザー提供コンバーターモジュール](#ユーザー提供コンバーターモジュール)を解決する。コンバーターが利用不可の場合はパススルーにフォールバックする。
421
+ **関係:**
422
+ - `references`: [アップロードエンドポイント](#アップロードエンドポイント) — 初期化時に呼ばれる
423
+ - `references`: [変換ドライバー](#変換ドライバー) — 解決して画像コンバーターに注入する
424
+ - `references`: [画像コンバーター](#画像コンバーター) — 生成して返す
425
+ - `references`: [ユーザー提供コンバーターモジュール](#ユーザー提供コンバーターモジュール) — パス指定時に読み込む
426
+ **src:** `packages/editor/server/createConverter.js` `createConverter`
427
+
428
+ ---
429
+
430
+ ### 画像コンバーター
431
+
432
+ **定義:** 画像データをWeb向けフォーマットに変換する装置。変換ドライバーが注入されている場合はそれを使って変換し、注入されていない場合は画像をそのまま通過させる。
433
+ **関係:**
434
+ - `references`: [コンバーターファクトリー](#コンバーターファクトリー) — 生成される
435
+ - `references`: [アップロードエンドポイント](#アップロードエンドポイント) — 使用される
436
+ - `references`: [変換ドライバー](#変換ドライバー) — 注入される
437
+ **src:** `packages/editor/server/createConverter.js` `createConverter` の返り値 `fn`
438
+
439
+ ---
440
+
441
+ ### 変換ドライバー
442
+
443
+ **定義:** 画像コンバーターに差し込む変換処理の実装。sharp 等の画像処理ライブラリをラップする形で提供される。
444
+ **関係:**
445
+ - `references`: [コンバーターファクトリー](#コンバーターファクトリー) — 生成され画像コンバーターに注入される
446
+ - `references`: [画像コンバーター](#画像コンバーター) — 注入される
447
+ **src:** `packages/editor/server/converters/sharp.js`
448
+
449
+ ---
450
+
451
+ ### ユーザー提供コンバーターモジュール
452
+
453
+ en: UserProvidedConverterModule
454
+ **定義:** ユーザーがプロジェクトに配置する JavaScript モジュール。変換関数をデフォルトエクスポートし、出力拡張子を `ext` としてエクスポートする。`blog.json` の `image_converter` にパスを指定することで[コンバーターファクトリー](#コンバーターファクトリー)が解決する。
455
+ **インターフェース:**
456
+ ```js
457
+ export default async function(buffer) { return convertedBuffer }
458
+ export const ext = 'webp' // 省略可
459
+ ```
460
+ **関係:**
461
+ - `references`: [コンバーターファクトリー](#コンバーターファクトリー) — 読み込まれる
462
+ - `references`: [変換ドライバー](#変換ドライバー) — の具体的な実装形態
463
+ **src:** `src-sample/converters/webp.js`(サンプル実装)
464
+
465
+ ---
466
+
467
+ ### ビルトインコンバーター
468
+
469
+ en: BuiltinConverter
470
+ **定義:** `@tenjuu99/blog` パッケージに同梱された[変換ドライバー](#変換ドライバー)。`blog.json` の `image_converter` でビルトイン名(例: `"sharp"`)を指定することで[コンバーターファクトリー](#コンバーターファクトリー)が解決する。ユーザーが別途ライブラリをインストールしなくても変換が動作することを保証する。
471
+ **関係:**
472
+ - `references`: [コンバーターファクトリー](#コンバーターファクトリー) — ビルトイン名から解決される
473
+ - `references`: [変換ドライバー](#変換ドライバー) — の一種
474
+ **src:** `packages/editor/server/converters/sharp.js`
475
+
476
+ ---
477
+
478
+ ### Markdown挿入器
479
+
480
+ **定義:** テキストエリアのカーソル位置に画像参照文字列を挿入する装置。
481
+ **関係:**
482
+ - `references`: [画像アップローダー](#画像アップローダー) — 画像パスを受け取った後に呼び出す
483
+ **src:** `packages/editor/js/image_upload.js` `insertImageMarkdown`
484
+
485
+ ---
486
+
487
+ ### ファイルライター
488
+
489
+ **定義:** 保存先パスを許可ディレクトリ内に限定して検証し、画像バッファをファイルに書き込む装置。
490
+ **関係:**
491
+ - `references`: [アップロードエンドポイント](#アップロードエンドポイント) — 呼び出される
492
+ - `references`: [画像保存先パス](#画像保存先パス) — パスを受け取り書き込む
493
+ **src:** `packages/editor/server/image_upload.js` `writeImageFile`
494
+
495
+ ---
496
+
497
+ ## カテゴリー
498
+
499
+ **dir:** category
500
+ **対象領域:** ページをディレクトリ階層に基づいて分類し、カテゴリーページとして一覧表示すること。
501
+ **主なユーザー:** サイト構造を設計する人(カテゴリーを設定し、閲覧者がナビゲートする)。
502
+ **境界の内:** カテゴリー定義、階層構造、カテゴリーページの自動生成、ページのカテゴリーへの割り当て、ページネーション。
503
+ **境界の外:** ページの内容をどう描画するか(SSGコア)、編集UI(エディタ)。
504
+
505
+ ---
506
+
507
+ **アプリケーションドメイン**
508
+
509
+ ### カテゴリー
510
+
511
+ **定義:** [ページ](#ページ)に付与するラベル。階層を持てる(例: `["Tech", "Frontend", "React"]`)。[ページ](#ページ)の[フロントマター](#フロントマター)で配列として指定する。
512
+ **関係:** [ページ](#ページ)(SSGコア)の[フロントマター](#フロントマター)に付与される。[カテゴリーパス](#カテゴリーパス)で階層を表現する。[カテゴリーシステム](#カテゴリーシステム)によって分類される。
513
+
514
+ ---
515
+
516
+ ### カテゴリーパス
517
+
518
+ **定義:** [カテゴリー](#カテゴリー)の階層を表す文字列の配列(例: `["Tech", "Frontend"]`)。先頭が最上位カテゴリー、末尾が最も具体的なカテゴリー。このパスから[カテゴリーページ](#カテゴリーページ)のURLが導出される。
519
+ **関係:** [カテゴリー](#カテゴリー)を階層として表現する。[カテゴリーページ](#カテゴリーページ)のURLと対応する。
520
+
521
+ ---
522
+
523
+ ### カテゴリーシステム
524
+
525
+ **定義:** 独立した分類の枠組み。`blog.json` の `categories` 配列の各要素として定義し、対象ページの範囲(`path_filter`)とURLプレフィックスを持つ。複数の[カテゴリーシステム](#カテゴリーシステム)は互いに独立して動作する。
526
+ **関係:** [カテゴリーページ](#カテゴリーページ)を生成する。`path_filter` で[ページ](#ページ)(SSGコア)の範囲を絞り込む。[カテゴリー](#カテゴリー)を分類する単位。
527
+
528
+ ---
529
+
530
+ ### サブカテゴリー
531
+
532
+ **定義:** ある[カテゴリーパス](#カテゴリーパス)の直下に位置する子カテゴリー。[カテゴリーページ](#カテゴリーページ)に `category_children` として列挙される。
533
+ **関係:** [カテゴリーパス](#カテゴリーパス)の階層関係から導出される。[カテゴリーページ](#カテゴリーページ)に表示される。
534
+
535
+ ---
536
+
537
+ ### カテゴリーページ
538
+
539
+ **定義:** [カテゴリー](#カテゴリー)に属する[ページ](#ページ)の一覧を表示する、[ビルド](#ビルド)時に自動生成されるページ。[カテゴリーパス](#カテゴリーパス)に対応するURLに出力される。[ページネーション](#ページネーション)が有効な場合は複数ページに分割される。
540
+ **関係:** [カテゴリーシステム](#カテゴリーシステム)によって自動生成される。[カテゴリーパス](#カテゴリーパス)と1対1で対応する。[ページインデックス](#ページインデックス)(SSGコア)に追加される。[ページネーション](#ページネーション)によって分割されることがある。[サブカテゴリー](#サブカテゴリー)を表示できる。
541
+
542
+ ---
543
+
544
+ ### ページネーション
545
+
546
+ **定義:** [カテゴリーページ](#カテゴリーページ)を複数の静的HTMLに分割する仕組み。`per_page` で1ページあたりの件数を指定する。1ページ目のURLはページネーション未設定時と同じで後方互換を保つ。
547
+ **関係:** [カテゴリーページ](#カテゴリーページ)を分割する。[カテゴリーシステム](#カテゴリーシステム)に設定される。
548
+
549
+ ---
550
+
551
+ **ソリューションドメイン**
552
+
553
+ (実装後に定義する)
package/docs/spec.md CHANGED
@@ -129,7 +129,7 @@ url: /custom-url
129
129
  |--------|-------------|------|
130
130
  | `name` | ファイル名(拡張子なし) | ページの内部名 |
131
131
  | `title` | `name` の値 | ページタイトル |
132
- | `url` | `/${name}` | URLパス |
132
+ | `url` | `/${name}` | URLパス(出力先も決定する。後述) |
133
133
  | `description` | 本文先頭150文字 | ページ説明 |
134
134
  | `og_description` | `description` と同じ | OGP説明文 |
135
135
  | `published` | `"1970-01-01"` | 公開日 |
@@ -146,9 +146,41 @@ url: /custom-url
146
146
  | `markdown` | 解析後のHTML | Markdown変換後のHTML |
147
147
  | `markdown_not_parsed` | フロントマター除去後 | 変換前のMarkdown |
148
148
  | `full_url` | 自動生成 | 完全なURL |
149
- | `__output` | 自動生成 | 出力ファイルパス |
149
+ | `__output` | 自動生成 | 出力ファイルパス(`url` から導出) |
150
150
  | `__filetype` | 拡張子 | 元ファイルの拡張子 |
151
151
 
152
+ ### `url` と出力先の関係
153
+
154
+ `url` フィールドはリンクの `href` に使われるだけでなく、**出力ファイルパス(`__output`)の導出元**にもなっています。
155
+
156
+ | `url` の形式 | `__output` |
157
+ |-------------|-----------|
158
+ | `/foo/bar`(末尾スラッシュなし) | `/foo/bar.html` |
159
+ | `/foo/bar/`(末尾スラッシュあり) | `/foo/bar/index.html` |
160
+
161
+ フロントマターで `url` を上書きすると `__output` も再計算されるため、ファイルの物理的な配置とは無関係に出力先を変更できます。
162
+
163
+ ```markdown
164
+ ---
165
+ url: /book/new/book
166
+ ---
167
+ ```
168
+
169
+ この場合、ファイルが `src/pages/book/new_book.md` であっても、出力先は `dist/book/new/book.html` になります。
170
+
171
+ **例外**: ファイル名が `index` の場合は `__output = /index.html` 固定(`url` に関係なし)。また、カテゴリーパッケージの仮想ページのように `__output` を明示的に設定するケースでは、この導出は行われません。
172
+
173
+ ### URLの末尾スラッシュ規約
174
+
175
+ S3+CDN 等のファイルシステムベースのホスティングでは、`/book` というURLが `book.html` を指すのか `book/index.html` を指すのかをURLだけから判断できません。これを避けるため、以下の規約を推奨します。
176
+
177
+ | ページ種別 | URL形式 | 出力先 |
178
+ |-----------|---------|-------|
179
+ | アイテム系(記事・個別ページ) | 末尾スラッシュなし `/book/foo` | `dist/book/foo.html` |
180
+ | リスト系(一覧・カテゴリー・ページネーション) | 末尾スラッシュあり `/book/` | `dist/book/index.html` |
181
+
182
+ リスト系ページを作る場合は、フロントマターで `url` を末尾スラッシュつきで指定するか、ファイル名を `index.md` にします。カテゴリーパッケージの仮想ページはこの規約に従い、`url` に末尾スラッシュを付与しています。
183
+
152
184
  ### データ型の記述
153
185
 
154
186
  フロントマター内のデータ型: