1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! Parser façade for reading existing JavaScript/TypeScript code
//!
//! This module provides a unified interface for parsing source code into ASTs
//! that can be manipulated and regenerated using fob-gen's builders.
#[cfg(feature = "parser")]
mod parser_impl {
use crate::error::{GenError, Result};
use oxc_allocator::Allocator;
use oxc_parser::Parser;
use oxc_span::SourceType;
/// Parse options for reading source code
#[derive(Debug, Clone)]
pub struct ParseOptions {
/// Source type (JavaScript, TypeScript, JSX, TSX)
pub source_type: SourceType,
/// Allow parsing errors (returns partial AST)
pub allow_errors: bool,
}
impl Default for ParseOptions {
fn default() -> Self {
Self {
source_type: SourceType::mjs(),
allow_errors: false,
}
}
}
impl ParseOptions {
/// Create parse options from file path (auto-detects source type)
pub fn from_path(path: &str) -> Self {
Self {
source_type: SourceType::from_path(path).unwrap_or(SourceType::mjs()),
allow_errors: false,
}
}
/// Create parse options for TypeScript
pub fn typescript() -> Self {
Self {
source_type: SourceType::ts(),
allow_errors: false,
}
}
/// Create parse options for JSX
pub fn jsx() -> Self {
Self {
source_type: SourceType::jsx(),
allow_errors: false,
}
}
/// Create parse options for TSX
pub fn tsx() -> Self {
Self {
source_type: SourceType::tsx(),
allow_errors: false,
}
}
}
/// Parse diagnostic information
#[derive(Debug, Clone)]
pub struct ParseDiagnostic {
/// Error message
pub message: String,
/// Span information (if available)
pub span: Option<(u32, u32)>,
}
/// Parsed program with AST and metadata
pub struct ParsedProgram<'a> {
/// The parsed AST program
pub program: oxc_ast::ast::Program<'a>,
/// Parse diagnostics (errors/warnings)
pub diagnostics: Vec<ParseDiagnostic>,
/// Original source text
pub source_text: &'a str,
/// Allocator used for AST nodes
pub allocator: &'a Allocator,
}
impl<'a> ParsedProgram<'a> {
/// Get the program AST
pub fn ast(&self) -> &oxc_ast::ast::Program<'a> {
&self.program
}
/// Get mutable access to the program AST
pub fn ast_mut(&mut self) -> &mut oxc_ast::ast::Program<'a> {
&mut self.program
}
/// Get the allocator for creating new AST nodes
pub fn allocator(&self) -> &'a Allocator {
self.allocator
}
/// Check if parsing had errors
pub fn has_errors(&self) -> bool {
!self.diagnostics.is_empty()
}
}
/// Parse source code into an AST
///
/// # Arguments
///
/// * `allocator` - Allocator for AST nodes (must outlive the returned program)
/// * `source` - Source code to parse
/// * `options` - Parse options
///
/// # Returns
///
/// Parsed program with AST and diagnostics
pub fn parse<'a>(
allocator: &'a Allocator,
source: &'a str,
options: ParseOptions,
) -> Result<ParsedProgram<'a>> {
let parser = Parser::new(allocator, source, options.source_type);
let result = parser.parse();
let diagnostics: Vec<ParseDiagnostic> = result
.errors
.iter()
.map(|err| ParseDiagnostic {
message: format!("{:?}", err),
span: None, // Span extraction requires more complex handling
})
.collect();
if !options.allow_errors && !diagnostics.is_empty() {
return Err(GenError::CodegenFailed(format!(
"Parse errors: {}",
diagnostics
.iter()
.map(|d| d.message.clone())
.collect::<Vec<_>>()
.join(", ")
)));
}
Ok(ParsedProgram {
program: result.program,
diagnostics,
source_text: source,
allocator,
})
}
}
#[cfg(feature = "parser")]
pub use parser_impl::*;