codoc 0.1.0

Unified documentation parser for Ruby and TypeScript codebases
Documentation
//! Source code parsers for Ruby and TypeScript.

pub mod doc_comment;
pub mod ruby;
pub mod typescript;

use crate::error::Result;
use crate::schema::{Document, Entity, Language, Metadata, SymbolEntry};
use std::path::Path;

/// Parser configuration.
#[derive(Debug, Clone)]
pub struct ParserConfig {
    /// Project name.
    pub name: String,

    /// Project version.
    pub version: Option<String>,

    /// Source root directory.
    pub source_root: String,

    /// ID prefix for all entities.
    pub id_prefix: Option<String>,

    /// Source language.
    pub language: Language,
}

impl ParserConfig {
    /// Creates a new parser configuration.
    pub fn new(name: impl Into<String>, language: Language) -> Self {
        Self {
            name: name.into(),
            version: None,
            source_root: ".".to_string(),
            id_prefix: None,
            language,
        }
    }

    /// Sets the project version.
    pub fn with_version(mut self, version: impl Into<String>) -> Self {
        self.version = Some(version.into());
        self
    }

    /// Sets the source root.
    pub fn with_source_root(mut self, root: impl Into<String>) -> Self {
        self.source_root = root.into();
        self
    }

    /// Sets the ID prefix.
    pub fn with_id_prefix(mut self, prefix: impl Into<String>) -> Self {
        self.id_prefix = Some(prefix.into());
        self
    }
}

/// Trait for source code parsers.
pub trait Parser {
    /// Returns the language this parser handles.
    fn language(&self) -> Language;

    /// Parses a single file and returns its entities.
    fn parse_file(&mut self, path: &Path, content: &str) -> Result<Vec<Entity>>;

    /// Generates symbol entries from entities.
    fn generate_symbols(&self, entities: &[Entity], parent: Option<&str>) -> Vec<SymbolEntry>;
}

/// Context for parsing operations.
pub struct ParseContext {
    /// Parser configuration.
    pub config: ParserConfig,

    /// Collected entities.
    pub entities: Vec<Entity>,

    /// Collected symbols.
    pub symbols: Vec<SymbolEntry>,

    /// Parsed files.
    pub files: Vec<String>,
}

impl ParseContext {
    /// Creates a new parse context.
    pub fn new(config: ParserConfig) -> Self {
        Self {
            config,
            entities: Vec::new(),
            symbols: Vec::new(),
            files: Vec::new(),
        }
    }

    /// Builds the final document.
    pub fn into_document(self) -> Document {
        let metadata = Metadata {
            name: self.config.name,
            version: self.config.version,
            language: self.config.language,
            generated_at: chrono::Utc::now().to_rfc3339(),
            source_root: Some(self.config.source_root),
            id_prefix: self.config.id_prefix,
            files: self.files,
            external_links: Default::default(),
        };

        Document {
            schema: crate::SCHEMA_VERSION.to_string(),
            metadata,
            entities: self.entities,
            symbols: self.symbols,
            unresolved_references: Vec::new(),
        }
    }

    /// Prefixes an ID with the configured prefix.
    pub fn prefix_id(&self, id: &str) -> String {
        match &self.config.id_prefix {
            Some(prefix) => format!("{}{}", prefix, id),
            None => id.to_string(),
        }
    }
}

/// Utility to get relative path from source root.
pub fn relative_path(path: &Path, source_root: &Path) -> String {
    path.strip_prefix(source_root)
        .unwrap_or(path)
        .to_string_lossy()
        .to_string()
}