md-review 0.0.1

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 ADDED
@@ -0,0 +1,220 @@
1
+ # md-preview
2
+
3
+ ローカルのMarkdownファイルをブラウザで見やすくプレビューするCLIツール
4
+
5
+ ## 特徴
6
+
7
+ - 🎨 GitHub風の見やすいデザイン
8
+ - 🌈 シンタックスハイライト対応(highlight.js)
9
+ - ✅ GitHub Flavored Markdown (GFM) サポート
10
+ - テーブル
11
+ - タスクリスト
12
+ - 取り消し線
13
+ - 📁 **ファイルツリー表示** - カレントディレクトリ内の全Markdownファイルを一覧表示
14
+ - 🗂️ **2カラムレイアウト** - 左側にツリー、右側にプレビュー
15
+ - ⚡ 高速な起動(Vite)
16
+ - 🚀 軽量なAPIサーバー(Hono)
17
+ - 📦 TypeScript + React 19
18
+
19
+ ## インストール
20
+
21
+ ```bash
22
+ # 依存パッケージのインストール
23
+ pnpm install
24
+ ```
25
+
26
+ ## 使い方
27
+
28
+ md-previewには**2つのモード**があります:
29
+
30
+ ### 1. 開発モード(推奨)
31
+
32
+ カレントディレクトリ内の全Markdownファイルをツリー表示し、選択してプレビューできます。
33
+
34
+ ```bash
35
+ # APIサーバーを起動
36
+ node server/index.js &
37
+
38
+ # 開発サーバーを起動
39
+ pnpm run dev
40
+ ```
41
+
42
+ または、両方同時に起動:
43
+
44
+ ```bash
45
+ # APIサーバーをバックグラウンドで起動
46
+ node server/index.js &
47
+
48
+ # Viteサーバーを起動(http://localhost:6060 が自動で開きます)
49
+ pnpm run dev
50
+ ```
51
+
52
+ ブラウザで `http://localhost:6060` を開くと、以下のようなUIが表示されます:
53
+ - **左側**: ファイルツリー(カレントディレクトリ内の全Markdownファイル:.md、.markdown)
54
+ - **右側**: 選択されたMarkdownファイルのプレビュー
55
+
56
+ ### 2. CLI モード
57
+
58
+ 特定のMarkdownファイルのみをプレビューします。
59
+
60
+ ```bash
61
+ node bin/md-preview.js <markdown-file-path>
62
+ ```
63
+
64
+ #### 例
65
+
66
+ ```bash
67
+ # サンプルファイルをプレビュー
68
+ node bin/md-preview.js test-samples/sample.md
69
+
70
+ # 任意のMarkdownファイルをプレビュー
71
+ node bin/md-preview.js ./docs/README.md
72
+ node bin/md-preview.js ~/Documents/notes.md
73
+ ```
74
+
75
+ ### オプション
76
+
77
+ ```bash
78
+ # ポート番号を指定
79
+ node bin/md-preview.js --port 8080 --api-port 3000 file.md
80
+
81
+ # ブラウザを自動的に開かない
82
+ node bin/md-preview.js --no-open file.md
83
+
84
+ # ヘルプを表示
85
+ node bin/md-preview.js --help
86
+
87
+ # バージョンを表示
88
+ node bin/md-preview.js --version
89
+ ```
90
+
91
+ ## オプション一覧
92
+
93
+ | オプション | 短縮形 | デフォルト | 説明 |
94
+ |-----------|--------|-----------|------|
95
+ | `--port` | `-p` | `6060` | Viteサーバーのポート番号 |
96
+ | `--api-port` | - | `3030` | APIサーバーのポート番号 |
97
+ | `--no-open` | - | - | ブラウザを自動的に開かない |
98
+ | `--help` | `-h` | - | ヘルプを表示 |
99
+ | `--version` | `-v` | - | バージョンを表示 |
100
+
101
+ ## 起動の流れ
102
+
103
+ 1. CLIコマンドを実行すると、以下のサーバーが起動します:
104
+ - **APIサーバー(Hono)**: `http://localhost:3030` - Markdownファイルを読み込むAPI
105
+ - **Viteサーバー**: `http://localhost:6060` - Reactアプリケーション
106
+
107
+ 2. 自動的にブラウザで `http://localhost:6060` が開き、Markdownファイルが表示されます
108
+
109
+ 3. 終了するには `Ctrl+C` を押してください
110
+
111
+ ## 技術スタック
112
+
113
+ ### フロントエンド
114
+ - **React** 19 - UIライブラリ
115
+ - **TypeScript** - 型安全な開発
116
+ - **Vite** - 高速な開発サーバー
117
+ - **react-markdown** - Markdownレンダリング
118
+ - **remark-gfm** - GFM記法サポート
119
+ - **rehype-highlight** - シンタックスハイライト
120
+ - **highlight.js** - コードハイライトライブラリ
121
+
122
+ ### バックエンド
123
+ - **Hono** - 高速で軽量なWebフレームワーク
124
+ - **@hono/node-server** - Node.js用アダプター
125
+
126
+ ### CLI
127
+ - **commander** - コマンドライン引数のパース
128
+ - **chalk** - ターミナル出力の色付け
129
+ - **open** - ブラウザを開く
130
+
131
+ ## プロジェクト構成
132
+
133
+ ```
134
+ md-preview/
135
+ ├── bin/
136
+ │ └── md-preview.js # CLI エントリーポイント
137
+ ├── server/
138
+ │ └── index.js # Hono APIサーバー
139
+ ├── src/
140
+ │ ├── components/
141
+ │ │ ├── ErrorDisplay.tsx # エラー表示
142
+ │ │ └── MarkdownPreview.tsx # Markdownプレビュー
143
+ │ ├── hooks/
144
+ │ │ └── useMarkdown.ts # Markdown取得フック
145
+ │ ├── styles/
146
+ │ │ └── markdown.css # Markdownスタイル
147
+ │ ├── App.tsx
148
+ │ ├── main.tsx
149
+ │ └── index.css
150
+ ├── test-samples/
151
+ │ └── sample.md # テスト用サンプル
152
+ ├── index.html
153
+ ├── vite.config.ts
154
+ ├── tsconfig.json
155
+ └── package.json
156
+ ```
157
+
158
+ ## サポートするMarkdown記法
159
+
160
+ ### 基本記法
161
+ - 見出し (h1-h6)
162
+ - 段落
163
+ - 強調 (**太字**, *斜体*)
164
+ - リスト(順序付き/順序なし)
165
+ - インラインコード
166
+ - コードブロック(シンタックスハイライト付き)
167
+ - リンク
168
+ - 引用
169
+ - 水平線
170
+
171
+ ### GFM拡張記法
172
+ - テーブル
173
+ - タスクリスト
174
+ - 取り消し線 (~~text~~)
175
+
176
+ ## 開発
177
+
178
+ ### 開発サーバーの起動
179
+
180
+ ```bash
181
+ # Vite開発サーバーのみ起動
182
+ pnpm run dev
183
+
184
+ # APIサーバーのみ起動
185
+ pnpm run server
186
+ ```
187
+
188
+ ### ビルド
189
+
190
+ ```bash
191
+ pnpm run build
192
+ ```
193
+
194
+ ## トラブルシューティング
195
+
196
+ ### ポートが既に使用されている
197
+
198
+ デフォルトのポート(6060, 3030)が既に使用されている場合は、別のポートを指定してください:
199
+
200
+ ```bash
201
+ node bin/md-preview.js --port 8080 --api-port 3000 file.md
202
+ ```
203
+
204
+ ### ブラウザが自動的に開かない
205
+
206
+ `--no-open` オプションを付けずに実行してください。または、手動で以下のURLを開いてください:
207
+
208
+ ```
209
+ http://localhost:6060
210
+ ```
211
+
212
+ ### Markdownが表示されない
213
+
214
+ 1. APIサーバーが正常に起動しているか確認してください(`http://localhost:3030/api/health` にアクセス)
215
+ 2. ファイルパスが正しいか確認してください
216
+ 3. ファイルが読み取り可能か確認してください
217
+
218
+ ## ライセンス
219
+
220
+ MIT
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawn } from 'child_process';
4
+ import { resolve, dirname } from 'path';
5
+ import { existsSync, readFileSync } from 'fs';
6
+ import { fileURLToPath } from 'url';
7
+ import mri from 'mri';
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = dirname(__filename);
11
+ const packageRoot = resolve(__dirname, '..');
12
+
13
+ const pkg = JSON.parse(readFileSync(resolve(packageRoot, 'package.json'), 'utf-8'));
14
+
15
+ const SERVER_READY_MESSAGE = 'md-review server started';
16
+
17
+ // Port validation function
18
+ function validatePort(value, name) {
19
+ const port = parseInt(value, 10);
20
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
21
+ console.error(`Error: Invalid ${name}: ${value}. Must be between 1 and 65535`);
22
+ process.exit(1);
23
+ }
24
+ return port;
25
+ }
26
+
27
+ // Check if file has markdown extension
28
+ function isMarkdownFile(filePath) {
29
+ return filePath.endsWith('.md') || filePath.endsWith('.markdown');
30
+ }
31
+
32
+ // Parse arguments
33
+ const args = mri(process.argv.slice(2), {
34
+ alias: {
35
+ p: 'port',
36
+ h: 'help',
37
+ v: 'version'
38
+ },
39
+ default: {
40
+ port: '6060',
41
+ 'api-port': '3030',
42
+ open: true
43
+ },
44
+ boolean: ['help', 'version', 'open']
45
+ });
46
+
47
+ // Help message
48
+ if (args.help) {
49
+ console.log(`
50
+ md-review - Review and annotate Markdown files with comments
51
+
52
+ Usage:
53
+ md-review [options] Start in dev mode (browse all markdown files)
54
+ md-review <file> [options] Preview a specific markdown file (.md or .markdown)
55
+
56
+ Options:
57
+ -p, --port <port> Vite server port (default: 6060)
58
+ --api-port <port> API server port (default: 3030)
59
+ --no-open Do not open browser automatically
60
+ -h, --help Show this help message
61
+ -v, --version Show version number
62
+
63
+ Examples:
64
+ md-review Start dev mode in current directory
65
+ md-review README.md Preview README.md
66
+ md-review docs/guide.md --port 8080
67
+ `);
68
+ process.exit(0);
69
+ }
70
+
71
+ // Version
72
+ if (args.version) {
73
+ console.log(pkg.version);
74
+ process.exit(0);
75
+ }
76
+
77
+ const file = args._[0];
78
+ const port = validatePort(args.port, 'port');
79
+ const apiPort = validatePort(args['api-port'], 'api-port');
80
+ const shouldOpen = args.open;
81
+
82
+ // Set environment variables
83
+ process.env.API_PORT = apiPort;
84
+ process.env.VITE_PORT = port;
85
+
86
+ // If file is specified, validate it
87
+ if (file) {
88
+ const filePath = resolve(file);
89
+
90
+ if (!existsSync(filePath)) {
91
+ console.error(`Error: File not found: ${filePath}`);
92
+ process.exit(1);
93
+ }
94
+
95
+ if (!isMarkdownFile(filePath)) {
96
+ console.error(`Error: File must have .md or .markdown extension: ${filePath}`);
97
+ process.exit(1);
98
+ }
99
+
100
+ process.env.MARKDOWN_FILE_PATH = filePath;
101
+ console.log(`File: ${filePath}`);
102
+ } else {
103
+ // Dev mode - browse all markdown files
104
+ process.env.BASE_DIR = process.cwd();
105
+ console.log(`Directory: ${process.cwd()}`);
106
+ }
107
+
108
+ console.log('Starting md-review...');
109
+ console.log(` API Port: ${apiPort}`);
110
+ console.log(` Vite Port: ${port}`);
111
+
112
+ // Start API server
113
+ const apiProcess = spawn('node', ['server/index.js'], {
114
+ cwd: packageRoot,
115
+ stdio: ['inherit', 'pipe', 'inherit'],
116
+ env: process.env
117
+ });
118
+
119
+ let viteProcess = null;
120
+ let serverReady = false;
121
+
122
+ // Wait for API server to be ready before starting Vite
123
+ apiProcess.stdout.on('data', (data) => {
124
+ process.stdout.write(data);
125
+ const output = data.toString();
126
+
127
+ if (!serverReady && output.includes(SERVER_READY_MESSAGE)) {
128
+ serverReady = true;
129
+ console.log('Starting Vite dev server...');
130
+
131
+ viteProcess = spawn('node', [
132
+ 'node_modules/vite/bin/vite.js',
133
+ '--port', port,
134
+ ...(shouldOpen ? ['--open'] : [])
135
+ ], {
136
+ cwd: packageRoot,
137
+ stdio: 'inherit',
138
+ env: process.env
139
+ });
140
+
141
+ viteProcess.on('error', (err) => {
142
+ console.error('Vite server error:', err.message);
143
+ });
144
+ }
145
+ });
146
+
147
+ // Handle graceful shutdown
148
+ const shutdown = () => {
149
+ console.log('\nShutting down...');
150
+ apiProcess.kill('SIGINT');
151
+ viteProcess?.kill('SIGINT');
152
+ process.exit(0);
153
+ };
154
+
155
+ process.on('SIGINT', shutdown);
156
+ process.on('SIGTERM', shutdown);
157
+
158
+ // Handle API server exit
159
+ apiProcess.on('exit', (code) => {
160
+ if (code !== 0 && code !== null) {
161
+ console.error(`API server exited with code ${code}`);
162
+ }
163
+ viteProcess?.kill('SIGINT');
164
+ process.exit(code || 0);
165
+ });
166
+
167
+ apiProcess.on('error', (err) => {
168
+ console.error('Failed to start API server:', err.message);
169
+ process.exit(1);
170
+ });