1use crate::error::Result;
4use crate::format::FormatOptions;
5use oxc_allocator::Allocator;
6use oxc_ast::ast::*;
7use oxc_ast::{AstBuilder, NONE};
8use oxc_codegen::Codegen;
9use oxc_span::{Atom, SPAN, SourceType};
10use std::io::Write;
11
12pub struct ProgramBuilder<'a> {
17 ast: AstBuilder<'a>,
18 body: Vec<Statement<'a>>,
19 source_type: SourceType,
20}
21
22impl<'a> ProgramBuilder<'a> {
23 pub fn new(allocator: &'a Allocator) -> Self {
25 Self {
26 ast: AstBuilder::new(allocator),
27 body: Vec::new(),
28 source_type: SourceType::mjs(),
29 }
30 }
31
32 pub fn with_source_type(allocator: &'a Allocator, source_type: SourceType) -> Self {
34 Self {
35 ast: AstBuilder::new(allocator),
36 body: Vec::new(),
37 source_type,
38 }
39 }
40
41 pub fn allocator(&self) -> &'a Allocator {
43 self.ast.allocator
44 }
45
46 pub fn ast(&self) -> &AstBuilder<'a> {
48 &self.ast
49 }
50
51 pub fn ident(&self, name: impl Into<Atom<'a>>) -> Expression<'a> {
55 self.ast.expression_identifier(SPAN, name)
56 }
57
58 pub fn string(&self, value: impl Into<Atom<'a>>) -> Expression<'a> {
60 self.ast.expression_string_literal(SPAN, value, None)
61 }
62
63 pub fn number(&self, value: f64) -> Expression<'a> {
65 self.ast
66 .expression_numeric_literal(SPAN, value, None, NumberBase::Decimal)
67 }
68
69 pub fn null(&self) -> Expression<'a> {
71 self.ast.expression_null_literal(SPAN)
72 }
73
74 pub fn bool(&self, value: bool) -> Expression<'a> {
76 self.ast.expression_boolean_literal(SPAN, value)
77 }
78
79 pub fn member(&self, object: Expression<'a>, property: impl Into<Atom<'a>>) -> Expression<'a> {
83 let prop_name = self.ast.identifier_name(SPAN, property);
84 let member = self
85 .ast
86 .member_expression_static(SPAN, object, prop_name, false);
87 Expression::from(member)
88 }
89
90 pub fn computed_member(&self, object: Expression<'a>, index: Expression<'a>) -> Expression<'a> {
94 let member = self
95 .ast
96 .member_expression_computed(SPAN, object, index, false);
97 Expression::from(member)
98 }
99
100 pub fn call(&self, callee: Expression<'a>, args: Vec<Argument<'a>>) -> Expression<'a> {
102 let args_vec = self.ast.vec_from_iter(args);
103 let call = self
104 .ast
105 .call_expression(SPAN, callee, NONE, args_vec, false);
106 Expression::CallExpression(self.ast.alloc(call))
107 }
108
109 pub fn arg(&self, expr: Expression<'a>) -> Argument<'a> {
111 Argument::from(expr)
112 }
113
114 pub fn object(&self, props: Vec<ObjectPropertyKind<'a>>) -> Expression<'a> {
116 let props_vec = self.ast.vec_from_iter(props);
117 self.ast.expression_object(SPAN, props_vec)
118 }
119
120 pub fn prop(&self, key: impl Into<Atom<'a>>, value: Expression<'a>) -> ObjectPropertyKind<'a> {
122 let key_name = self.ast.identifier_name(SPAN, key);
123 let property = self.ast.object_property(
124 SPAN,
125 PropertyKind::Init,
126 PropertyKey::StaticIdentifier(self.ast.alloc(key_name)),
127 value,
128 false,
129 false,
130 false,
131 );
132 ObjectPropertyKind::ObjectProperty(self.ast.alloc(property))
133 }
134
135 pub fn array(&self, elements: Vec<Expression<'a>>) -> Expression<'a> {
137 let array_elements: Vec<_> = elements
138 .into_iter()
139 .map(ArrayExpressionElement::from)
140 .collect();
141 let elements_vec = self.ast.vec_from_iter(array_elements);
142 self.ast.expression_array(SPAN, elements_vec)
143 }
144
145 pub fn arrow_fn(&self, params: Vec<&'a str>, body: Expression<'a>) -> Expression<'a> {
147 let param_items: Vec<_> = params
148 .into_iter()
149 .map(|name| {
150 let pattern = self.ast.binding_pattern(
151 self.ast.binding_pattern_kind_binding_identifier(SPAN, name),
152 NONE,
153 false,
154 );
155 self.ast
156 .formal_parameter(SPAN, self.ast.vec(), pattern, None, false, false)
157 })
158 .collect();
159
160 let items_vec = self.ast.vec_from_iter(param_items);
161 let formal_params = self.ast.formal_parameters(
162 SPAN,
163 FormalParameterKind::ArrowFormalParameters,
164 items_vec,
165 NONE,
166 );
167
168 let return_stmt = self.ast.statement_return(SPAN, Some(body));
170 let stmts = self.ast.vec1(return_stmt);
171 let function_body = self.ast.function_body(SPAN, self.ast.vec(), stmts);
172
173 self.ast.expression_arrow_function(
174 SPAN,
175 false, false, NONE,
178 formal_params,
179 NONE,
180 self.ast.alloc(function_body),
181 )
182 }
183
184 pub fn arrow_fn_block(
186 &self,
187 params: Vec<&'a str>,
188 stmts: Vec<Statement<'a>>,
189 ) -> Expression<'a> {
190 let param_items: Vec<_> = params
191 .into_iter()
192 .map(|name| {
193 let pattern = self.ast.binding_pattern(
194 self.ast.binding_pattern_kind_binding_identifier(SPAN, name),
195 NONE,
196 false,
197 );
198 self.ast
199 .formal_parameter(SPAN, self.ast.vec(), pattern, None, false, false)
200 })
201 .collect();
202
203 let items_vec = self.ast.vec_from_iter(param_items);
204 let formal_params = self.ast.formal_parameters(
205 SPAN,
206 FormalParameterKind::ArrowFormalParameters,
207 items_vec,
208 NONE,
209 );
210
211 let body_stmts = self.ast.vec_from_iter(stmts);
212 let function_body = self.ast.function_body(SPAN, self.ast.vec(), body_stmts);
213
214 self.ast.expression_arrow_function(
215 SPAN,
216 false, false, Option::<TSTypeParameterDeclaration>::None,
219 formal_params,
220 Option::<TSTypeAnnotation>::None,
221 self.ast.alloc(function_body),
222 )
223 }
224
225 pub fn const_decl(&self, name: impl Into<Atom<'a>>, init: Expression<'a>) -> Statement<'a> {
229 let pattern = self.ast.binding_pattern(
230 self.ast.binding_pattern_kind_binding_identifier(SPAN, name),
231 NONE,
232 false,
233 );
234 let declarator = self.ast.variable_declarator(
235 SPAN,
236 VariableDeclarationKind::Const,
237 pattern,
238 Some(init),
239 false,
240 );
241 let declarations = self.ast.vec1(declarator);
242 let var_decl = self.ast.variable_declaration(
243 SPAN,
244 VariableDeclarationKind::Const,
245 declarations,
246 false,
247 );
248 Statement::VariableDeclaration(self.ast.alloc(var_decl))
249 }
250
251 pub fn let_decl(
253 &self,
254 name: impl Into<Atom<'a>>,
255 init: Option<Expression<'a>>,
256 ) -> Statement<'a> {
257 let pattern = self.ast.binding_pattern(
258 self.ast.binding_pattern_kind_binding_identifier(SPAN, name),
259 NONE,
260 false,
261 );
262 let declarator =
263 self.ast
264 .variable_declarator(SPAN, VariableDeclarationKind::Let, pattern, init, false);
265 let declarations = self.ast.vec1(declarator);
266 let var_decl =
267 self.ast
268 .variable_declaration(SPAN, VariableDeclarationKind::Let, declarations, false);
269 Statement::VariableDeclaration(self.ast.alloc(var_decl))
270 }
271
272 pub fn expr_stmt(&self, expr: Expression<'a>) -> Statement<'a> {
274 self.ast.statement_expression(SPAN, expr)
275 }
276
277 pub fn if_stmt(
279 &self,
280 test: Expression<'a>,
281 consequent: Vec<Statement<'a>>,
282 alternate: Option<Vec<Statement<'a>>>,
283 ) -> Statement<'a> {
284 let consequent_stmts = self.ast.vec_from_iter(consequent);
285 let consequent_block = self.ast.statement_block(SPAN, consequent_stmts);
286
287 let alternate_block = alternate.map(|stmts| {
288 let alt_stmts = self.ast.vec_from_iter(stmts);
289 self.ast.statement_block(SPAN, alt_stmts)
290 });
291
292 Statement::IfStatement(self.ast.alloc(IfStatement {
293 span: SPAN,
294 test,
295 consequent: consequent_block,
296 alternate: alternate_block,
297 }))
298 }
299
300 pub fn return_stmt(&self, expr: Option<Expression<'a>>) -> Statement<'a> {
302 Statement::ReturnStatement(self.ast.alloc(ReturnStatement {
303 span: SPAN,
304 argument: expr,
305 }))
306 }
307
308 pub fn throw(&self, expr: Expression<'a>) -> Statement<'a> {
310 Statement::ThrowStatement(self.ast.alloc(ThrowStatement {
311 span: SPAN,
312 argument: expr,
313 }))
314 }
315
316 pub fn import_default(
320 &self,
321 local: impl Into<Atom<'a>>,
322 source: impl Into<Atom<'a>>,
323 ) -> ModuleDeclaration<'a> {
324 let binding = self.ast.binding_identifier(SPAN, local);
325 let specifier = self.ast.import_default_specifier(SPAN, binding);
326 let specifiers = self
327 .ast
328 .vec1(ImportDeclarationSpecifier::ImportDefaultSpecifier(
329 self.ast.alloc(specifier),
330 ));
331 let source_literal = self.ast.string_literal(SPAN, source, None);
332 self.ast.module_declaration_import_declaration(
333 SPAN,
334 Some(specifiers),
335 source_literal,
336 None, NONE, ImportOrExportKind::Value,
339 )
340 }
341
342 pub fn import_side_effect(&self, source: impl Into<Atom<'a>>) -> ModuleDeclaration<'a> {
344 let source_literal = self.ast.string_literal(SPAN, source, None);
345 self.ast.module_declaration_import_declaration(
346 SPAN,
347 None, source_literal,
349 None, NONE, ImportOrExportKind::Value,
352 )
353 }
354
355 pub fn import_named(
357 &self,
358 names: Vec<impl Into<Atom<'a>>>,
359 source: impl Into<Atom<'a>>,
360 ) -> ModuleDeclaration<'a> {
361 let specifiers: Vec<_> = names
362 .into_iter()
363 .map(|name| {
364 let atom = name.into();
365 let imported_name = self.ast.identifier_name(SPAN, atom);
366 let local_binding = self.ast.binding_identifier(SPAN, atom);
367 let specifier = self.ast.import_specifier(
368 SPAN,
369 ModuleExportName::IdentifierName(imported_name),
370 local_binding,
371 ImportOrExportKind::Value,
372 );
373 ImportDeclarationSpecifier::ImportSpecifier(self.ast.alloc(specifier))
374 })
375 .collect();
376
377 let specifiers_vec = self.ast.vec_from_iter(specifiers);
378 let source_literal = self.ast.string_literal(SPAN, source, None);
379 self.ast.module_declaration_import_declaration(
380 SPAN,
381 Some(specifiers_vec),
382 source_literal,
383 None, NONE, ImportOrExportKind::Value,
386 )
387 }
388
389 pub fn export_default(&self, expr: Expression<'a>) -> ModuleDeclaration<'a> {
391 let kind: ExportDefaultDeclarationKind = expr.into();
393 self.ast
394 .module_declaration_export_default_declaration(SPAN, kind)
395 }
396
397 pub fn export_const(
399 &self,
400 name: impl Into<Atom<'a>>,
401 init: Expression<'a>,
402 ) -> ModuleDeclaration<'a> {
403 let decl = self.const_decl(name, init);
404 let declaration = match decl {
405 Statement::VariableDeclaration(var_decl) => Declaration::VariableDeclaration(var_decl),
406 _ => unreachable!(),
407 };
408 ModuleDeclaration::ExportNamedDeclaration(self.ast.alloc(ExportNamedDeclaration {
409 span: SPAN,
410 declaration: Some(declaration),
411 specifiers: self.ast.vec(),
412 source: None,
413 export_kind: ImportOrExportKind::Value,
414 with_clause: None,
415 }))
416 }
417
418 pub fn push(&mut self, stmt: Statement<'a>) {
422 self.body.push(stmt);
423 }
424
425 pub fn extend(&mut self, stmts: impl IntoIterator<Item = Statement<'a>>) {
427 self.body.extend(stmts);
428 }
429
430 pub fn len(&self) -> usize {
432 self.body.len()
433 }
434
435 pub fn is_empty(&self) -> bool {
437 self.body.is_empty()
438 }
439
440 pub fn write_to<W: Write>(self, writer: &mut W, _opts: &FormatOptions) -> Result<()> {
444 let body_vec = self.ast.vec_from_iter(self.body);
445 let program = self.ast.program(
446 SPAN,
447 self.source_type,
448 "",
449 self.ast.vec(), None, self.ast.vec(), body_vec,
453 );
454
455 let codegen = Codegen::new();
456 let result = codegen.build(&program);
457
458 writer.write_all(result.code.as_bytes()).map_err(|e| {
459 crate::error::GenError::CodegenFailed {
460 context: "Write error".to_string(),
461 reason: Some(e.to_string()),
462 }
463 })?;
464
465 Ok(())
466 }
467
468 pub fn generate(self, _opts: &FormatOptions) -> Result<String> {
472 let body_vec = self.ast.vec_from_iter(self.body);
473 let program = self.ast.program(
474 SPAN,
475 self.source_type,
476 "",
477 self.ast.vec(), None, self.ast.vec(), body_vec,
481 );
482
483 let codegen = Codegen::new();
484 let result = codegen.build(&program);
485
486 Ok(result.code)
487 }
488
489 pub fn build_program(self) -> Program<'a> {
493 let body_vec = self.ast.vec_from_iter(self.body);
494 self.ast.program(
495 SPAN,
496 self.source_type,
497 "",
498 self.ast.vec(), None, self.ast.vec(), body_vec,
502 )
503 }
504
505 pub fn not(&self, expr: Expression<'a>) -> Expression<'a> {
509 self.ast
510 .expression_unary(SPAN, UnaryOperator::LogicalNot, expr)
511 }
512
513 pub fn binary(
515 &self,
516 left: Expression<'a>,
517 op: BinaryOperator,
518 right: Expression<'a>,
519 ) -> Expression<'a> {
520 self.ast.expression_binary(SPAN, left, op, right)
521 }
522
523 pub fn logical(
525 &self,
526 left: Expression<'a>,
527 op: LogicalOperator,
528 right: Expression<'a>,
529 ) -> Expression<'a> {
530 self.ast.expression_logical(SPAN, left, op, right)
531 }
532
533 pub fn conditional(
535 &self,
536 test: Expression<'a>,
537 consequent: Expression<'a>,
538 alternate: Expression<'a>,
539 ) -> Expression<'a> {
540 self.ast
541 .expression_conditional(SPAN, test, consequent, alternate)
542 }
543
544 pub fn new_expr(&self, callee: Expression<'a>, args: Vec<Argument<'a>>) -> Expression<'a> {
546 let args_vec = self.ast.vec_from_iter(args);
547 self.ast.expression_new(SPAN, callee, NONE, args_vec)
548 }
549
550 pub fn template_literal(
562 &self,
563 parts: Vec<impl Into<Atom<'a>>>,
564 expressions: Vec<Expression<'a>>,
565 ) -> Expression<'a> {
566 let quasis: Vec<_> = parts
569 .into_iter()
570 .enumerate()
571 .map(|(i, part)| {
572 let atom = part.into();
573 let tail = i == expressions.len(); let value = TemplateElementValue {
575 raw: atom,
576 cooked: Some(atom),
577 };
578 TemplateElement {
579 span: SPAN,
580 value,
581 tail,
582 lone_surrogates: false,
583 }
584 })
585 .collect();
586
587 let quasis_vec = self.ast.vec_from_iter(quasis);
588 let expressions_vec = self.ast.vec_from_iter(expressions);
589
590 self.ast
591 .expression_template_literal(SPAN, quasis_vec, expressions_vec)
592 }
593
594 pub fn spread(&self, expr: Expression<'a>) -> SpreadElement<'a> {
602 SpreadElement {
603 span: SPAN,
604 argument: expr,
605 }
606 }
607}