Skip to main content

oparry_parser/
lib.rs

1//! Multi-language parser for Parry
2
3mod javascript;
4mod rust;
5mod generic;
6// JavaScript complete parser with AST analysis
7mod javascript_complete;
8
9// Simple JS parser (implements Parser trait)
10pub use javascript::JavaScriptParser as SimpleJavaScriptParser;
11// Re-exports from javascript_complete (full AST parser)
12pub use javascript_complete::{
13    ComponentInfo, ExportInfo, HookInfo, ImportInfo, ImportSpecifierInfo,
14    JavaScriptAst as CompleteJavaScriptAst, JavaScriptParser as CompleteJavaScriptParser,
15    ParseResults, is_component_name,
16};
17pub use rust::{RustParser, RustAst};
18pub use generic::GenericParser;
19
20use oparry_core::Result;
21use std::path::Path;
22
23/// Language detection
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum Language {
26    JavaScript,
27    TypeScript,
28    Jsx,
29    Tsx,
30    Rust,
31    Unknown,
32}
33
34impl Language {
35    /// Detect language from file extension
36    pub fn from_path(path: &Path) -> Self {
37        match path.extension().and_then(|e| e.to_str()) {
38            Some("js") | Some("mjs") | Some("cjs") => Language::JavaScript,
39            Some("jsx") => Language::Jsx,
40            Some("ts") => Language::TypeScript,
41            Some("tsx") => Language::Tsx,
42            Some("rs") => Language::Rust,
43            _ => Language::Unknown,
44        }
45    }
46
47    /// Check if this is a JavaScript/TypeScript variant
48    pub fn is_javascript_variant(&self) -> bool {
49        matches!(
50            self,
51            Language::JavaScript | Language::TypeScript | Language::Jsx | Language::Tsx
52        )
53    }
54
55    /// Check if this is Rust
56    pub fn is_rust(&self) -> bool {
57        matches!(self, Language::Rust)
58    }
59}
60
61/// Parsed code representation
62#[derive(Debug)]
63pub enum ParsedCode {
64    Rust(RustAst),
65    Generic(String),
66}
67
68impl ParsedCode {
69    /// Get the raw source
70    pub fn source(&self) -> &str {
71        match self {
72            ParsedCode::Rust(ast) => ast.source(),
73            ParsedCode::Generic(s) => s,
74        }
75    }
76}
77
78/// Parser trait
79pub trait Parser: Send + Sync {
80    /// Parse source code
81    fn parse(&self, source: &str) -> Result<ParsedCode>;
82}
83
84/// Get parser for language
85pub fn parser_for_language(language: Language) -> Box<dyn Parser> {
86    match language {
87        Language::JavaScript | Language::TypeScript | Language::Jsx | Language::Tsx => {
88            Box::new(SimpleJavaScriptParser::new())
89        }
90        Language::Rust => Box::new(RustParser::new()),
91        Language::Unknown => Box::new(GenericParser),
92    }
93}
94
95/// Get parser for file path
96pub fn parser_for_path(path: &Path) -> Box<dyn Parser> {
97    parser_for_language(Language::from_path(path))
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    #[test]
105    fn test_language_detection() {
106        assert_eq!(Language::from_path(Path::new("test.js")), Language::JavaScript);
107        assert_eq!(Language::from_path(Path::new("test.ts")), Language::TypeScript);
108        assert_eq!(Language::from_path(Path::new("test.tsx")), Language::Tsx);
109        assert_eq!(Language::from_path(Path::new("test.rs")), Language::Rust);
110        assert_eq!(Language::from_path(Path::new("test.unknown")), Language::Unknown);
111    }
112}