kotoba_docs/
lib.rs

1//! Kotoba Documentation Generator
2//!
3//! ソースコードから美しいドキュメントを自動生成するツールです。
4//! HTML、Markdown、JSONなどの形式でドキュメントを出力できます。
5//!
6//! ## 使用方法
7//!
8//! ```bash
9//! # プロジェクトのドキュメントを生成
10//! kotoba docs generate
11//!
12//! # 開発サーバーを起動
13//! kotoba docs serve
14//!
15//! # ドキュメントを検索
16//! kotoba docs search "function_name"
17//!
18//! # ヘルプ表示
19//! kotoba docs --help
20//! ```
21
22use std::collections::HashMap;
23use std::path::{Path, PathBuf};
24use serde::{Deserialize, Serialize};
25use chrono::{DateTime, Utc};
26use uuid::Uuid;
27
28/// ドキュメントジェネレータのエラー型
29#[derive(Debug, thiserror::Error)]
30pub enum DocsError {
31    #[error("IO error: {0}")]
32    Io(#[from] std::io::Error),
33
34    #[error("JSON error: {0}")]
35    Json(#[from] serde_json::Error),
36
37    #[error("YAML error: {0}")]
38    Yaml(#[from] serde_yaml::Error),
39
40    #[error("TOML error: {0}")]
41    Toml(#[from] toml::de::Error),
42
43    #[error("Regex error: {0}")]
44    Regex(#[from] regex::Error),
45
46    #[error("Template error: {0}")]
47    Template(String),
48
49    #[error("Parse error: {0}")]
50    Parse(String),
51
52    #[error("Search error: {0}")]
53    Search(String),
54
55    #[error("Config error: {0}")]
56    Config(String),
57
58    #[error("Server error: {0}")]
59    Server(String),
60
61    #[error("Anyhow error: {0}")]
62    Anyhow(#[from] anyhow::Error),
63}
64
65pub type Result<T> = std::result::Result<T, DocsError>;
66
67/// ドキュメントの種類
68#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
69pub enum DocType {
70    /// モジュール/パッケージ
71    Module,
72    /// 関数
73    Function,
74    /// 構造体
75    Struct,
76    /// 列挙型
77    Enum,
78    /// トレイト
79    Trait,
80    /// 定数
81    Constant,
82    /// マクロ
83    Macro,
84    /// 型エイリアス
85    TypeAlias,
86    /// メソッド
87    Method,
88    /// フィールド
89    Field,
90    /// バリアント
91    Variant,
92    /// 関連型
93    AssociatedType,
94    /// 関連定数
95    AssociatedConstant,
96}
97
98impl std::fmt::Display for DocType {
99    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100        let name = match self {
101            DocType::Module => "Module",
102            DocType::Function => "Function",
103            DocType::Struct => "Struct",
104            DocType::Enum => "Enum",
105            DocType::Trait => "Trait",
106            DocType::Constant => "Constant",
107            DocType::Macro => "Macro",
108            DocType::TypeAlias => "TypeAlias",
109            DocType::Method => "Method",
110            DocType::Field => "Field",
111            DocType::Variant => "Variant",
112            DocType::AssociatedType => "AssociatedType",
113            DocType::AssociatedConstant => "AssociatedConstant",
114        };
115        write!(f, "{}", name)
116    }
117}
118
119/// ドキュメント項目
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct DocItem {
122    /// ユニークID
123    pub id: String,
124
125    /// 名前
126    pub name: String,
127
128    /// ドキュメントの種類
129    pub doc_type: DocType,
130
131    /// ドキュメント本文
132    pub content: String,
133
134    /// 署名(関数や型のシグネチャ)
135    pub signature: Option<String>,
136
137    /// ファイルパス
138    pub file_path: PathBuf,
139
140    /// 行番号
141    pub line_number: Option<usize>,
142
143    /// 親要素のID
144    pub parent_id: Option<String>,
145
146    /// 子要素のIDリスト
147    pub children: Vec<String>,
148
149    /// 作成日時
150    pub created_at: DateTime<Utc>,
151
152    /// 更新日時
153    pub updated_at: DateTime<Utc>,
154
155    /// メタデータ
156    pub metadata: HashMap<String, serde_json::Value>,
157
158    /// 関連項目
159    pub related_items: Vec<String>,
160
161    /// タグ
162    pub tags: Vec<String>,
163}
164
165impl DocItem {
166    /// 新しいドキュメント項目を作成
167    pub fn new(name: String, doc_type: DocType, content: String) -> Self {
168        let now = Utc::now();
169        Self {
170            id: Uuid::new_v4().to_string(),
171            name,
172            doc_type,
173            content,
174            signature: None,
175            file_path: PathBuf::new(),
176            line_number: None,
177            parent_id: None,
178            children: vec![],
179            created_at: now,
180            updated_at: now,
181            metadata: HashMap::new(),
182            related_items: vec![],
183            tags: vec![],
184        }
185    }
186
187    /// ファイルパスを設定
188    pub fn with_file_path(mut self, path: PathBuf) -> Self {
189        self.file_path = path;
190        self
191    }
192
193    /// 行番号を設定
194    pub fn with_line_number(mut self, line: usize) -> Self {
195        self.line_number = Some(line);
196        self
197    }
198
199    /// 署名を設定
200    pub fn with_signature(mut self, signature: String) -> Self {
201        self.signature = Some(signature);
202        self
203    }
204
205    /// 親要素を設定
206    pub fn with_parent(mut self, parent_id: String) -> Self {
207        self.parent_id = Some(parent_id);
208        self
209    }
210
211    /// タグを追加
212    pub fn with_tag(mut self, tag: String) -> Self {
213        self.tags.push(tag);
214        self
215    }
216
217    /// メタデータを設定
218    pub fn with_metadata(mut self, key: String, value: serde_json::Value) -> Self {
219        self.metadata.insert(key, value);
220        self
221    }
222
223    /// HTML IDを生成
224    pub fn html_id(&self) -> String {
225        format!("{}-{}", self.doc_type.to_string().to_lowercase(), self.id)
226    }
227
228    /// URLスラグを生成
229    pub fn slug(&self) -> String {
230        self.name
231            .to_lowercase()
232            .replace(" ", "-")
233            .replace("_", "-")
234            .chars()
235            .filter(|c| c.is_alphanumeric() || *c == '-')
236            .collect::<String>()
237    }
238}
239
240impl Default for DocItem {
241    fn default() -> Self {
242        Self::new(String::new(), DocType::Module, String::new())
243    }
244}
245
246/// ドキュメント設定
247#[derive(Debug, Clone, Serialize, Deserialize)]
248pub struct DocsConfig {
249    /// プロジェクト名
250    pub name: String,
251
252    /// バージョン
253    pub version: String,
254
255    /// 説明
256    pub description: Option<String>,
257
258    /// 作成者
259    pub authors: Vec<String>,
260
261    /// リポジトリURL
262    pub repository: Option<String>,
263
264    /// ホームページURL
265    pub homepage: Option<String>,
266
267    /// ライセンス
268    pub license: Option<String>,
269
270    /// 入力ディレクトリ
271    pub input_dir: PathBuf,
272
273    /// 出力ディレクトリ
274    pub output_dir: PathBuf,
275
276    /// テンプレートディレクトリ
277    pub template_dir: Option<PathBuf>,
278
279    /// テーマ
280    pub theme: String,
281
282    /// 出力形式
283    pub formats: Vec<OutputFormat>,
284
285    /// 除外パターン
286    pub exclude_patterns: Vec<String>,
287
288    /// 含める拡張子
289    pub include_extensions: Vec<String>,
290
291    /// サーバー設定
292    pub server: ServerConfig,
293
294    /// 検索設定
295    pub search: SearchConfig,
296
297    /// 追加設定
298    pub extra: HashMap<String, serde_json::Value>,
299}
300
301impl Default for DocsConfig {
302    fn default() -> Self {
303        Self {
304            name: "My Project".to_string(),
305            version: "0.1.0".to_string(),
306            description: None,
307            authors: vec![],
308            repository: None,
309            homepage: None,
310            license: None,
311            input_dir: PathBuf::from("src"),
312            output_dir: PathBuf::from("docs"),
313            template_dir: None,
314            theme: "default".to_string(),
315            formats: vec![OutputFormat::Html],
316            exclude_patterns: vec![
317                "target".to_string(),
318                "node_modules".to_string(),
319                ".git".to_string(),
320                "*.tmp".to_string(),
321            ],
322            include_extensions: vec![
323                "rs".to_string(),
324                "js".to_string(),
325                "ts".to_string(),
326                "py".to_string(),
327                "go".to_string(),
328                "md".to_string(),
329            ],
330            server: ServerConfig::default(),
331            search: SearchConfig::default(),
332            extra: HashMap::new(),
333        }
334    }
335}
336
337/// 出力形式
338#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
339pub enum OutputFormat {
340    /// HTML
341    Html,
342    /// Markdown
343    Markdown,
344    /// JSON
345    Json,
346    /// PDF(将来の拡張)
347    Pdf,
348}
349
350/// サーバー設定
351#[derive(Debug, Clone, Serialize, Deserialize)]
352pub struct ServerConfig {
353    /// ホスト
354    pub host: String,
355
356    /// ポート
357    pub port: u16,
358
359    /// HTTPSを使用
360    pub https: bool,
361
362    /// オープン
363    pub open: bool,
364
365    /// リロード
366    pub reload: bool,
367}
368
369impl Default for ServerConfig {
370    fn default() -> Self {
371        Self {
372            host: "localhost".to_string(),
373            port: 3000,
374            https: false,
375            open: false,
376            reload: true,
377        }
378    }
379}
380
381/// 検索設定
382#[derive(Debug, Clone, Serialize, Deserialize)]
383pub struct SearchConfig {
384    /// 検索を有効化
385    pub enabled: bool,
386
387    /// インデックスファイル
388    pub index_file: String,
389
390    /// 最大結果数
391    pub max_results: usize,
392
393    /// ファジー検索
394    pub fuzzy: bool,
395}
396
397impl Default for SearchConfig {
398    fn default() -> Self {
399        Self {
400            enabled: true,
401            index_file: "search-index.json".to_string(),
402            max_results: 50,
403            fuzzy: true,
404        }
405    }
406}
407
408/// ドキュメント生成結果
409#[derive(Debug, Clone)]
410pub struct GenerateResult {
411    /// 生成されたドキュメント数
412    pub documents_generated: usize,
413
414    /// 処理されたファイル数
415    pub files_processed: usize,
416
417    /// 出力ディレクトリ
418    pub output_dir: PathBuf,
419
420    /// 生成時間
421    pub generation_time: std::time::Duration,
422
423    /// タイムスタンプ
424    pub timestamp: DateTime<Utc>,
425
426    /// エラー数
427    pub errors: usize,
428}
429
430impl GenerateResult {
431    pub fn new() -> Self {
432        Self {
433            documents_generated: 0,
434            files_processed: 0,
435            output_dir: PathBuf::new(),
436            generation_time: std::time::Duration::default(),
437            timestamp: Utc::now(),
438            errors: 0,
439        }
440    }
441
442    pub fn success(
443        mut self,
444        docs: usize,
445        files: usize,
446        output_dir: PathBuf,
447        duration: std::time::Duration,
448    ) -> Self {
449        self.documents_generated = docs;
450        self.files_processed = files;
451        self.output_dir = output_dir;
452        self.generation_time = duration;
453        self
454    }
455
456    pub fn with_errors(mut self, errors: usize) -> Self {
457        self.errors = errors;
458        self
459    }
460}
461
462// 各モジュールの再エクスポート
463pub mod parser;
464pub mod generator;
465pub mod server;
466pub mod search;
467pub mod template;
468pub mod config;