@onozaty/growi-uploader 1.5.0 → 1.6.0
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.ja.md +341 -0
- package/README.md +37 -0
- package/dist/index.mjs +16 -2
- package/package.json +1 -1
package/README.ja.md
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
# growi-uploader
|
|
2
|
+
|
|
3
|
+
日本語 | [English](README.md)
|
|
4
|
+
|
|
5
|
+
[](https://github.com/onozaty/growi-uploader/actions/workflows/test.yaml)
|
|
6
|
+
[](https://codecov.io/gh/onozaty/growi-uploader)
|
|
7
|
+
[](https://www.npmjs.com/package/@onozaty/growi-uploader)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
ローカルのMarkdownファイルと添付ファイルを[GROWI](https://growi.org/) Wikiに一括アップロードするCLIツールです。
|
|
11
|
+
|
|
12
|
+
## 機能
|
|
13
|
+
|
|
14
|
+
- 📁 **ディレクトリ構造の維持** - ローカルのフォルダ階層がGROWIのページ階層になります
|
|
15
|
+
- 📝 **Markdownファイルのアップロード** - `.md`ファイルからGROWIページを作成・更新
|
|
16
|
+
- 📎 **添付ファイルの自動検出** - `<ページ名>_attachment_<ファイル名>`パターンのファイルを自動的に添付ファイルとしてアップロード
|
|
17
|
+
- 🔗 **リンクの自動置換** - ローカルの添付ファイルへのリンクをGROWI形式(`/attachment/{id}`)に自動変換
|
|
18
|
+
- 🖼️ **画像の埋め込み** - 画像リンク(``)を自動変換
|
|
19
|
+
- ⚙️ **柔軟な設定** - ベースパス、更新動作などを制御可能
|
|
20
|
+
|
|
21
|
+
## クイックスタート
|
|
22
|
+
|
|
23
|
+
1. 設定ファイル`growi-uploader.json`を作成:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"url": "https://your-growi-instance.com",
|
|
28
|
+
"token": "your-api-token",
|
|
29
|
+
"basePath": "/",
|
|
30
|
+
"update": false
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
2. npxで実行(インストール不要):
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx @onozaty/growi-uploader ./docs
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
これだけです!ローカルの`./docs`ディレクトリがGROWIにアップロードされます。
|
|
41
|
+
|
|
42
|
+
## インストール
|
|
43
|
+
|
|
44
|
+
### npxを使用(推奨)
|
|
45
|
+
|
|
46
|
+
インストール不要で実行できます:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npx @onozaty/growi-uploader <source-dir>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### グローバルインストール
|
|
53
|
+
|
|
54
|
+
頻繁に使用する場合は、グローバルインストールできます:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm install -g @onozaty/growi-uploader
|
|
58
|
+
growi-uploader <source-dir>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## 使い方
|
|
62
|
+
|
|
63
|
+
### 基本コマンド
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
growi-uploader <source-dir> [options]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**引数:**
|
|
70
|
+
- `<source-dir>`: Markdownファイルを含むディレクトリのパス
|
|
71
|
+
|
|
72
|
+
**オプション:**
|
|
73
|
+
- `-c, --config <path>`: 設定ファイルのパス(デフォルト: `growi-uploader.json`)
|
|
74
|
+
- `-v, --verbose`: 詳細なエラー出力を有効化
|
|
75
|
+
- `-V, --version`: バージョン番号を表示
|
|
76
|
+
- `-h, --help`: ヘルプ情報を表示
|
|
77
|
+
|
|
78
|
+
### 実行例
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Upload with default config file
|
|
82
|
+
npx @onozaty/growi-uploader ./docs
|
|
83
|
+
|
|
84
|
+
# Upload with custom config file
|
|
85
|
+
npx @onozaty/growi-uploader ./docs -c my-config.json
|
|
86
|
+
|
|
87
|
+
# Upload with verbose error output
|
|
88
|
+
npx @onozaty/growi-uploader ./docs --verbose
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## ディレクトリ構造の例
|
|
92
|
+
|
|
93
|
+
### ローカルディレクトリ
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
docs/
|
|
97
|
+
guide.md
|
|
98
|
+
guide_attachment_diagram.svg
|
|
99
|
+
guide_attachment_sample.txt
|
|
100
|
+
api/
|
|
101
|
+
overview.md
|
|
102
|
+
overview_attachment_example.json
|
|
103
|
+
authentication.md
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### アップロード後のGROWIページ
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
/docs/guide (from guide.md)
|
|
110
|
+
└─ diagram.svg (attachment)
|
|
111
|
+
└─ sample.txt (attachment)
|
|
112
|
+
/docs/api/overview (from api/overview.md)
|
|
113
|
+
└─ example.json (attachment)
|
|
114
|
+
/docs/api/authentication (from api/authentication.md)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## ページ名の正規化
|
|
118
|
+
|
|
119
|
+
APIエラーを防ぐため、ページ名は以下のルールで自動的に正規化されます:
|
|
120
|
+
|
|
121
|
+
### 正規化ルール
|
|
122
|
+
|
|
123
|
+
1. **スラッシュ前後のスペース** → アンダースコアに置換
|
|
124
|
+
- `a / b.md` → `/a_/_b`
|
|
125
|
+
|
|
126
|
+
2. **特殊文字** → 安全な文字列に置換:
|
|
127
|
+
- `+` → `-plus-`
|
|
128
|
+
- `?` → `-question-`
|
|
129
|
+
- `*` → `-asterisk-`
|
|
130
|
+
- `$` → `-dollar-`
|
|
131
|
+
- `^` → `-caret-`
|
|
132
|
+
- `%` → `-percent-`
|
|
133
|
+
|
|
134
|
+
3. **予約済みページ名** → アンダースコアを末尾に追加:
|
|
135
|
+
- `edit` → `edit_` (パスの最後のセグメントの場合のみ)
|
|
136
|
+
|
|
137
|
+
### 例
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
Local file GROWI page path
|
|
141
|
+
──────────────────────────────────────────────────
|
|
142
|
+
C++.md → /C-plus--plus-
|
|
143
|
+
What?.md → /What-question-
|
|
144
|
+
C++ / Python?.md → /C-plus--plus-_/_Python-question-
|
|
145
|
+
edit.md → /edit_
|
|
146
|
+
docs/edit.md → /docs/edit_
|
|
147
|
+
docs/normal-page.md → /docs/normal-page (no change)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
この正規化により、GROWIのページ名要件との互換性を確保しつつ、ファイル名の可読性を維持します。
|
|
151
|
+
|
|
152
|
+
## 設定ファイル
|
|
153
|
+
|
|
154
|
+
プロジェクトルートに`growi-uploader.json`ファイルを作成:
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"url": "https://your-growi-instance.com",
|
|
159
|
+
"token": "your-api-token",
|
|
160
|
+
"basePath": "/imported",
|
|
161
|
+
"update": true,
|
|
162
|
+
"verbose": false
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 設定オプション
|
|
167
|
+
|
|
168
|
+
| オプション | 型 | 必須 | デフォルト | 説明 |
|
|
169
|
+
|--------|------|----------|---------|-------------|
|
|
170
|
+
| `url` | string | ✅ | - | GROWIインスタンスのURL |
|
|
171
|
+
| `token` | string | ✅ | - | GROWI APIアクセストークン |
|
|
172
|
+
| `basePath` | string | ❌ | `/` | インポートされるページのベースパス |
|
|
173
|
+
| `update` | boolean | ❌ | `false` | trueの場合は既存ページを更新、falseの場合はスキップ |
|
|
174
|
+
| `verbose` | boolean | ❌ | `false` | 詳細なエラー出力を有効化 |
|
|
175
|
+
|
|
176
|
+
### APIトークンの取得方法
|
|
177
|
+
|
|
178
|
+
1. GROWIインスタンスにログイン
|
|
179
|
+
2. **ユーザー設定** → **API設定** に移動
|
|
180
|
+
3. **新しいトークンを発行** をクリック
|
|
181
|
+
4. 生成されたトークンを設定ファイルにコピー
|
|
182
|
+
|
|
183
|
+
## 添付ファイル
|
|
184
|
+
|
|
185
|
+
添付ファイルは2つの方法で自動検出されます:
|
|
186
|
+
|
|
187
|
+
### 方法1: 命名規則
|
|
188
|
+
|
|
189
|
+
以下の命名パターンに従うファイルが添付ファイルとして検出されます:
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
<ページ名>_attachment_<ファイル名>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**例:**
|
|
196
|
+
```
|
|
197
|
+
guide.md → GROWI page: /guide
|
|
198
|
+
guide_attachment_image.png → Attached to /guide
|
|
199
|
+
guide_attachment_document.pdf → Attached to /guide
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### 方法2: リンクベースの検出
|
|
203
|
+
|
|
204
|
+
Markdownリンクで参照されているファイルが自動的に添付ファイルとして検出されます:
|
|
205
|
+
|
|
206
|
+
**ローカルディレクトリ:**
|
|
207
|
+
```
|
|
208
|
+
guide.md
|
|
209
|
+
assets/
|
|
210
|
+
banner.png
|
|
211
|
+
images/
|
|
212
|
+
logo.png
|
|
213
|
+
screenshot.png
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**guide.mdの内容:**
|
|
217
|
+
```markdown
|
|
218
|
+

|
|
219
|
+

|
|
220
|
+

|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
参照されているすべてのファイル(`logo.png`、`screenshot.png`、`banner.png`)は、`_attachment_`命名規則に従っていなくても、`/guide`ページに添付ファイルとしてアップロードされます。
|
|
224
|
+
|
|
225
|
+
**パスの解決:**
|
|
226
|
+
- Markdownエスケープシーケンスは解除されます(`\(` → `(`)
|
|
227
|
+
- URLエンコーディング(パーセントエンコーディング)はデコードされます(`%20` → スペース、`%E7%94%BB%E5%83%8F` → `画像`)
|
|
228
|
+
- 相対パス(`./`、`../`、またはプレフィックスなし): Markdownファイルのディレクトリからの相対パス
|
|
229
|
+
- 絶対パス(`/`で始まる): ソースディレクトリのルートからの絶対パス
|
|
230
|
+
- 例: `/assets/banner.png` → `<source-dir>/assets/banner.png`
|
|
231
|
+
|
|
232
|
+
**サポートされるリンク形式:**
|
|
233
|
+
```markdown
|
|
234
|
+
 # Standard relative path
|
|
235
|
+
 # Relative path without ./
|
|
236
|
+
 # URL-encoded Japanese filename
|
|
237
|
+
[File](./docs/my%20file.pdf) # URL-encoded space
|
|
238
|
+
[File](<./path/file (1).png>) # Special chars with angle brackets
|
|
239
|
+
.png) # Special chars with escaping
|
|
240
|
+
<img src="./images/logo.png" alt="Logo"> # HTML img tag (double quotes)
|
|
241
|
+
<img src='./images/logo.png' alt='Logo'> # HTML img tag (single quotes)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**検出から除外されるもの:**
|
|
245
|
+
- `.md`ファイル(ページリンクとして扱われます)
|
|
246
|
+
- 外部URL(`http://`、`https://`)
|
|
247
|
+
- 存在しないファイル
|
|
248
|
+
|
|
249
|
+
### リンクの自動置換
|
|
250
|
+
|
|
251
|
+
添付ファイルへのMarkdownリンクは自動的にGROWI形式(`/attachment/{id}`)に変換されます。
|
|
252
|
+
|
|
253
|
+
**例(命名規則):**
|
|
254
|
+
|
|
255
|
+
```markdown
|
|
256
|
+
# Before upload
|
|
257
|
+

|
|
258
|
+
Download the [documentation](guide_attachment_document.pdf).
|
|
259
|
+
|
|
260
|
+
# After upload (on GROWI)
|
|
261
|
+

|
|
262
|
+
Download the [documentation](/attachment/68f3a3fa794f665ad2c0d2b3).
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**例(リンクベース):**
|
|
266
|
+
|
|
267
|
+
```markdown
|
|
268
|
+
# Before upload
|
|
269
|
+

|
|
270
|
+
|
|
271
|
+
# After upload (on GROWI)
|
|
272
|
+

|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
両方の検出方法で、複数のリンク形式(`./`あり・なし)がサポートされています。
|
|
276
|
+
|
|
277
|
+
## 高度な使い方
|
|
278
|
+
|
|
279
|
+
### 既存ページの更新
|
|
280
|
+
|
|
281
|
+
設定ファイルで`update: true`を設定すると、既存ページを更新できます:
|
|
282
|
+
|
|
283
|
+
```json
|
|
284
|
+
{
|
|
285
|
+
"url": "https://your-growi-instance.com",
|
|
286
|
+
"token": "your-api-token",
|
|
287
|
+
"update": true
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### 特定のパスへのインポート
|
|
292
|
+
|
|
293
|
+
`basePath`を使用して、すべてのページを特定のパス配下にインポートできます:
|
|
294
|
+
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"url": "https://your-growi-instance.com",
|
|
298
|
+
"token": "your-api-token",
|
|
299
|
+
"basePath": "/imported"
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**結果:**
|
|
304
|
+
```
|
|
305
|
+
docs/guide.md → /imported/docs/guide
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### 出力例
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
Found 5 Markdown file(s) and 3 attachment(s)
|
|
312
|
+
|
|
313
|
+
[SUCCESS] docs/guide.md → /docs/guide (created)
|
|
314
|
+
[SUCCESS] docs/guide_attachment_diagram.svg → /docs/guide (attachment)
|
|
315
|
+
[SUCCESS] docs/guide.md → /docs/guide (attachment links replaced)
|
|
316
|
+
[SUCCESS] docs/api/overview.md → /docs/api/overview (created)
|
|
317
|
+
[SKIP] docs/api/auth.md → /docs/api/auth (page already exists)
|
|
318
|
+
|
|
319
|
+
Completed:
|
|
320
|
+
- Pages created: 2
|
|
321
|
+
- Pages updated: 0
|
|
322
|
+
- Pages skipped: 1
|
|
323
|
+
- Page errors: 0
|
|
324
|
+
- Attachments uploaded: 2
|
|
325
|
+
- Attachments skipped: 0
|
|
326
|
+
- Attachment errors: 0
|
|
327
|
+
- Link replacement errors: 0
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## 必要環境
|
|
331
|
+
|
|
332
|
+
- Node.js 18以降
|
|
333
|
+
- REST API v3をサポートするGROWIインスタンス
|
|
334
|
+
|
|
335
|
+
## ライセンス
|
|
336
|
+
|
|
337
|
+
MIT
|
|
338
|
+
|
|
339
|
+
## 作者
|
|
340
|
+
|
|
341
|
+
[onozaty](https://github.com/onozaty)
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# growi-uploader
|
|
2
2
|
|
|
3
|
+
English | [日本語](README.ja.md)
|
|
4
|
+
|
|
3
5
|
[](https://github.com/onozaty/growi-uploader/actions/workflows/test.yaml)
|
|
4
6
|
[](https://codecov.io/gh/onozaty/growi-uploader)
|
|
5
7
|
[](https://www.npmjs.com/package/@onozaty/growi-uploader)
|
|
@@ -112,6 +114,41 @@ docs/
|
|
|
112
114
|
/docs/api/authentication (from api/authentication.md)
|
|
113
115
|
```
|
|
114
116
|
|
|
117
|
+
## Page Name Normalization
|
|
118
|
+
|
|
119
|
+
To prevent API errors, page names are automatically normalized using the following rules:
|
|
120
|
+
|
|
121
|
+
### Normalization Rules
|
|
122
|
+
|
|
123
|
+
1. **Spaces around slashes** → Replaced with underscores
|
|
124
|
+
- `a / b.md` → `/a_/_b`
|
|
125
|
+
|
|
126
|
+
2. **Special characters** → Replaced with safe alternatives:
|
|
127
|
+
- `+` → `-plus-`
|
|
128
|
+
- `?` → `-question-`
|
|
129
|
+
- `*` → `-asterisk-`
|
|
130
|
+
- `$` → `-dollar-`
|
|
131
|
+
- `^` → `-caret-`
|
|
132
|
+
- `%` → `-percent-`
|
|
133
|
+
|
|
134
|
+
3. **Reserved page names** → Suffixed with underscore:
|
|
135
|
+
- `edit` → `edit_` (only when it's the last path segment)
|
|
136
|
+
|
|
137
|
+
### Examples
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
Local file GROWI page path
|
|
141
|
+
──────────────────────────────────────────────────
|
|
142
|
+
C++.md → /C-plus--plus-
|
|
143
|
+
What?.md → /What-question-
|
|
144
|
+
C++ / Python?.md → /C-plus--plus-_/_Python-question-
|
|
145
|
+
edit.md → /edit_
|
|
146
|
+
docs/edit.md → /docs/edit_
|
|
147
|
+
docs/normal-page.md → /docs/normal-page (no change)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
This normalization ensures compatibility with GROWI's page naming requirements while preserving the readability of your file names.
|
|
151
|
+
|
|
115
152
|
## Configuration File
|
|
116
153
|
|
|
117
154
|
Create a `growi-uploader.json` file in your project root:
|
package/dist/index.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { lookup } from "mime-types";
|
|
|
8
8
|
import { glob } from "glob";
|
|
9
9
|
|
|
10
10
|
//#region package.json
|
|
11
|
-
var version = "1.
|
|
11
|
+
var version = "1.6.0";
|
|
12
12
|
|
|
13
13
|
//#endregion
|
|
14
14
|
//#region src/config.ts
|
|
@@ -363,6 +363,19 @@ const mergeAttachments = (namingAttachments, linkAttachments) => {
|
|
|
363
363
|
}
|
|
364
364
|
return Array.from(map.values());
|
|
365
365
|
};
|
|
366
|
+
/**
|
|
367
|
+
* Normalize GROWI page path to avoid API errors
|
|
368
|
+
*
|
|
369
|
+
* @param path Raw GROWI page path
|
|
370
|
+
* @returns Normalized page path
|
|
371
|
+
*/
|
|
372
|
+
const normalizeGrowiPath = (path) => {
|
|
373
|
+
let normalized = path;
|
|
374
|
+
normalized = normalized.replace(/\s+\/\s+/g, "_/_");
|
|
375
|
+
normalized = normalized.replace(/\+/g, "-plus-").replace(/\?/g, "-question-").replace(/\*/g, "-asterisk-").replace(/\$/g, "-dollar-").replace(/\^/g, "-caret-").replace(/%/g, "-percent-");
|
|
376
|
+
normalized = normalized.replace(/\/edit$/g, "/edit_");
|
|
377
|
+
return normalized;
|
|
378
|
+
};
|
|
366
379
|
const scanMarkdownFiles = async (sourceDir, basePath = "/") => {
|
|
367
380
|
const pageFiles = (await glob("**/*.md", {
|
|
368
381
|
cwd: sourceDir,
|
|
@@ -371,7 +384,8 @@ const scanMarkdownFiles = async (sourceDir, basePath = "/") => {
|
|
|
371
384
|
pageFiles.sort();
|
|
372
385
|
return await Promise.all(pageFiles.map(async (file) => {
|
|
373
386
|
const content = readFileSync(join(sourceDir, file), "utf-8");
|
|
374
|
-
|
|
387
|
+
let growiPath = join(basePath, file.replace(/\.md$/, "")).replace(/\\/g, "/");
|
|
388
|
+
growiPath = normalizeGrowiPath(growiPath);
|
|
375
389
|
const dir = dirname(file);
|
|
376
390
|
const pageName = basename(file, ".md");
|
|
377
391
|
const attachments = mergeAttachments((await glob(dir === "." ? `${pageName}_attachment_*` : `${dir}/${pageName}_attachment_*`, {
|