1use std::sync::atomic::{AtomicUsize, Ordering};
10
11use oxc_allocator::Allocator;
12use oxc_parser::{Parser, ParserReturn};
13use oxc_span::SourceType;
14use tracing::{debug, info, trace, warn};
15
16pub struct ParseResult {
32 pub program:oxc_ast::ast::Program<'static>,
34
35 pub allocator:Allocator,
38
39 pub errors:Vec<String>,
41
42 #[allow(dead_code)]
44 pub file_path:String,
45}
46
47#[derive(Debug, Clone)]
49pub struct ParserConfig {
50 pub target:String,
52
53 pub jsx:bool,
55
56 pub decorators:bool,
58
59 pub typescript:bool,
61}
62
63impl Default for ParserConfig {
64 fn default() -> Self { Self { target:"es2024".to_string(), jsx:false, decorators:true, typescript:true } }
65}
66
67impl ParserConfig {
68 pub fn new(target:String, jsx:bool, decorators:bool, typescript:bool) -> Self {
70 Self { target, jsx, decorators, typescript }
71 }
72}
73
74static PARSE_COUNT:AtomicUsize = AtomicUsize::new(0);
84
85#[tracing::instrument(skip(source_text, config))]
86pub fn parse(source_text:&str, file_path:&str, config:&ParserConfig) -> Result<ParseResult, Vec<String>> {
87 let parse_id = PARSE_COUNT.fetch_add(1, Ordering::SeqCst);
88
89 info!("[Parser #{parse_id}] Starting parse of: {}", file_path);
90
91 trace!("[Parser #{parse_id}] Source text length: {} bytes", source_text.len());
92
93 let allocator = Allocator::default();
94
95 trace!("[Parser #{parse_id}] Allocator created at: {:p}", &allocator);
96
97 let source_type = determine_source_type(file_path, config);
99
100 info!("[Parser #{parse_id}] Parsing {} as {:?}", file_path, source_type);
101
102 let parse_start = std::time::Instant::now();
103
104 let parser_return:ParserReturn = Parser::new(&allocator, source_text, source_type).parse();
106
107 info!("[Parser #{parse_id}] Parse completed in {:?}", parse_start.elapsed());
108
109 let errors:Vec<String> = parser_return.errors.iter().map(|e| e.to_string()).collect();
110
111 if !errors.is_empty() {
112 warn!("[Parser #{parse_id}] Parsing errors for {}: {:?}", file_path, errors);
113
114 return Err(errors);
115 }
116
117 let program = unsafe {
134 std::mem::transmute::<oxc_ast::ast::Program<'_>, oxc_ast::ast::Program<'static>>(parser_return.program)
135 };
136
137 debug!("[Parser #{parse_id}] Program transmute complete at: {:p}", &program);
138
139 trace!(
140 "[Parser #{parse_id}] AST body pointer: {:p}, len: {}",
141 program.body.as_ptr(),
142 program.body.len()
143 );
144
145 info!(
146 "[Parser #{parse_id}] SUCCESS: ParseResult<'static> created (allocator={:p})",
147 &allocator
148 );
149
150 Ok(ParseResult { program, allocator, errors:vec![], file_path:file_path.to_string() })
151}
152
153fn determine_source_type(file_path:&str, _config:&ParserConfig) -> SourceType {
155 let path = std::path::Path::new(file_path);
156
157 let extension = path.extension().and_then(|e| e.to_str()).unwrap_or("");
158
159 match extension {
160 "ts" | "mts" => SourceType::ts(),
161
162 "tsx" => SourceType::tsx(),
163
164 "mjs" => SourceType::mjs(),
165
166 "cjs" => SourceType::cjs(),
167
168 "js" => SourceType::unambiguous(),
169
170 "jsx" => SourceType::jsx(),
171
172 _ => SourceType::unambiguous(),
173 }
174}