mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
feat(codegen)!: new code gen API (#3740)
This PR introduces two type alias to avoid the confusing const generic `pub struct Codegen<'a, const MINIFY: bool>` * CodeGenerator - Code generator without whitespace removal. * WhitespaceRemover - Code generator with whitespace removal. Usage is changed to a builder pattern: ```rust CodeGenerator::new() .enable_comment(...) .enable_sourcemap(...) .build(&program); ```
This commit is contained in:
parent
527bfc82f5
commit
5c38a0fd69
26 changed files with 296 additions and 410 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1746,7 +1746,6 @@ dependencies = [
|
|||
"napi-build",
|
||||
"napi-derive",
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
"oxc_codegen",
|
||||
"oxc_diagnostics",
|
||||
"oxc_isolated_declarations",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
use std::{env, path::Path};
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::{CodeGenerator, WhitespaceRemover};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
|
||||
|
|
@ -29,16 +29,11 @@ fn main() -> std::io::Result<()> {
|
|||
println!("Original:");
|
||||
println!("{source_text}");
|
||||
|
||||
let options = CodegenOptions::default();
|
||||
let printed = Codegen::<false>::new("", &source_text, ret.trivias.clone(), options)
|
||||
.build(&ret.program)
|
||||
.source_text;
|
||||
let printed = CodeGenerator::new().build(&ret.program).source_text;
|
||||
println!("Printed:");
|
||||
println!("{printed}");
|
||||
|
||||
let minified = Codegen::<true>::new("", &source_text, ret.trivias, options)
|
||||
.build(&ret.program)
|
||||
.source_text;
|
||||
let minified = WhitespaceRemover::new().build(&ret.program).source_text;
|
||||
println!("Minified:");
|
||||
println!("{minified}");
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{env, path::Path};
|
|||
|
||||
use base64::{prelude::BASE64_STANDARD, Engine};
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions, CodegenReturn};
|
||||
use oxc_codegen::{CodeGenerator, CodegenReturn};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
|
||||
|
|
@ -27,15 +27,9 @@ fn main() -> std::io::Result<()> {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let codegen_options = CodegenOptions { enable_source_map: true, ..Default::default() };
|
||||
|
||||
let CodegenReturn { source_text, source_map } = Codegen::<false>::new(
|
||||
path.to_string_lossy().as_ref(),
|
||||
&source_text,
|
||||
ret.trivias,
|
||||
codegen_options,
|
||||
)
|
||||
.build(&ret.program);
|
||||
let CodegenReturn { source_text, source_map } = CodeGenerator::new()
|
||||
.enable_source_map(path.to_string_lossy().as_ref(), &source_text)
|
||||
.build(&ret.program);
|
||||
|
||||
if let Some(source_map) = source_map {
|
||||
let result = source_map.to_json_string().unwrap();
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ pub fn print_comment<const MINIFY: bool>(
|
|||
}
|
||||
|
||||
pub fn gen_comment<const MINIFY: bool>(node_start: u32, codegen: &mut Codegen<{ MINIFY }>) {
|
||||
if !codegen.options.preserve_annotate_comments {
|
||||
if !codegen.comment_options.preserve_annotate_comments {
|
||||
return;
|
||||
}
|
||||
if let Some((comment_start, comment)) = codegen.try_take_moved_comment(node_start) {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use oxc_syntax::{
|
|||
};
|
||||
|
||||
use crate::annotation_comment::{gen_comment, get_leading_annotate_comment};
|
||||
use crate::{Codegen, Context, Operator, Separator};
|
||||
use crate::{Codegen, Context, Operator};
|
||||
|
||||
pub trait Gen<const MINIFY: bool> {
|
||||
fn gen(&self, _p: &mut Codegen<{ MINIFY }>, _ctx: Context) {}
|
||||
|
|
@ -591,7 +591,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for VariableDeclaration<'a> {
|
|||
p.print_str(b"declare ");
|
||||
}
|
||||
|
||||
if p.options.preserve_annotate_comments
|
||||
if p.comment_options.preserve_annotate_comments
|
||||
&& matches!(self.kind, VariableDeclarationKind::Const)
|
||||
{
|
||||
if let Some(declarator) = self.declarations.first() {
|
||||
|
|
@ -823,7 +823,9 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for WithClause<'a> {
|
|||
p.add_source_mapping(self.span.start);
|
||||
self.attributes_keyword.gen(p, ctx);
|
||||
p.print_soft_space();
|
||||
p.print_block(&self.with_entries, Separator::Comma, ctx, self.span);
|
||||
p.print_block_start(self.span.start);
|
||||
p.print_sequence(&self.with_entries, ctx);
|
||||
p.print_block_end(self.span.end);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -845,7 +847,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ExportNamedDeclaration<'a> {
|
|||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.add_source_mapping(self.span.start);
|
||||
p.print_indent();
|
||||
if p.options.preserve_annotate_comments {
|
||||
if p.comment_options.preserve_annotate_comments {
|
||||
match &self.declaration {
|
||||
Some(Declaration::FunctionDeclaration(_)) => {
|
||||
gen_comment(self.span.start, p);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,5 @@
|
|||
//! Oxc Codegen
|
||||
//!
|
||||
//! Supports
|
||||
//!
|
||||
//! * whitespace removal
|
||||
//! * sourcemaps
|
||||
//!
|
||||
//! Code adapted from
|
||||
//! * [esbuild](https://github.com/evanw/esbuild/blob/main/internal/js_printer/js_printer.go)
|
||||
|
||||
|
|
@ -16,8 +11,9 @@ mod sourcemap_builder;
|
|||
|
||||
use std::{borrow::Cow, ops::Range};
|
||||
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use oxc_ast::ast::*;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use oxc_ast::ast::{BlockStatement, Directive, Expression, Program, Statement};
|
||||
use oxc_ast::{Comment, Trivias};
|
||||
use oxc_span::{Atom, Span};
|
||||
use oxc_syntax::{
|
||||
|
|
@ -26,23 +22,23 @@ use oxc_syntax::{
|
|||
precedence::Precedence,
|
||||
symbol::SymbolId,
|
||||
};
|
||||
use rustc_hash::FxHashMap;
|
||||
use sourcemap_builder::SourcemapBuilder;
|
||||
|
||||
use crate::operator::Operator;
|
||||
use crate::sourcemap_builder::SourcemapBuilder;
|
||||
|
||||
pub use crate::{
|
||||
context::Context,
|
||||
gen::{Gen, GenExpr},
|
||||
operator::Operator,
|
||||
};
|
||||
// use crate::mangler::Mangler;
|
||||
|
||||
pub type MoveCommentMap = FxHashMap<u32, (u32, Comment)>;
|
||||
/// Code generator without whitespace removal.
|
||||
pub type CodeGenerator<'a> = Codegen<'a, false>;
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct CodegenOptions {
|
||||
/// Pass in the filename to enable source map support.
|
||||
pub enable_source_map: bool,
|
||||
/// Code generator with whitespace removal.
|
||||
pub type WhitespaceRemover<'a> = Codegen<'a, true>;
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub struct CommentOptions {
|
||||
/// Enable preserve annotate comments, like `/* #__PURE__ */` and `/* #__NO_SIDE_EFFECTS__ */`.
|
||||
pub preserve_annotate_comments: bool,
|
||||
}
|
||||
|
|
@ -52,31 +48,13 @@ pub struct CodegenReturn {
|
|||
pub source_map: Option<oxc_sourcemap::SourceMap>,
|
||||
}
|
||||
|
||||
impl From<CodegenReturn> for String {
|
||||
fn from(val: CodegenReturn) -> Self {
|
||||
val.source_text
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const MINIFY: bool> From<Codegen<'a, MINIFY>> for String {
|
||||
fn from(mut val: Codegen<'a, MINIFY>) -> Self {
|
||||
val.into_source_text()
|
||||
}
|
||||
}
|
||||
impl<'a, const MINIFY: bool> From<Codegen<'a, MINIFY>> for Cow<'a, str> {
|
||||
fn from(mut val: Codegen<'a, MINIFY>) -> Self {
|
||||
Cow::Owned(val.into_source_text())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Codegen<'a, const MINIFY: bool> {
|
||||
options: CodegenOptions,
|
||||
comment_options: CommentOptions,
|
||||
|
||||
source_text: &'a str,
|
||||
|
||||
trivias: Trivias,
|
||||
|
||||
// mangler: Option<Mangler>,
|
||||
/// Output Code
|
||||
code: Vec<u8>,
|
||||
|
||||
|
|
@ -107,37 +85,33 @@ pub struct Codegen<'a, const MINIFY: bool> {
|
|||
move_comment_map: MoveCommentMap,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Separator {
|
||||
Comma,
|
||||
Semicolon,
|
||||
None,
|
||||
impl<'a, const MINIFY: bool> Default for Codegen<'a, MINIFY> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const MINIFY: bool> From<Codegen<'a, MINIFY>> for String {
|
||||
fn from(mut val: Codegen<'a, MINIFY>) -> Self {
|
||||
val.into_source_text()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const MINIFY: bool> From<Codegen<'a, MINIFY>> for Cow<'a, str> {
|
||||
fn from(mut val: Codegen<'a, MINIFY>) -> Self {
|
||||
Cow::Owned(val.into_source_text())
|
||||
}
|
||||
}
|
||||
|
||||
// Public APIs
|
||||
impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
||||
pub fn new(
|
||||
source_name: &str,
|
||||
source_text: &'a str,
|
||||
trivias: Trivias,
|
||||
options: CodegenOptions,
|
||||
) -> Self {
|
||||
// Initialize the output code buffer to reduce memory reallocation.
|
||||
// Minification will reduce by at least half of the original size.
|
||||
let source_len = source_text.len();
|
||||
let capacity = if MINIFY { source_len / 2 } else { source_len };
|
||||
|
||||
let sourcemap_builder = options.enable_source_map.then(|| {
|
||||
let mut sourcemap_builder = SourcemapBuilder::default();
|
||||
sourcemap_builder.with_name_and_source(source_name, source_text);
|
||||
sourcemap_builder
|
||||
});
|
||||
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
options,
|
||||
source_text,
|
||||
trivias,
|
||||
// mangler: None,
|
||||
code: Vec::with_capacity(capacity),
|
||||
comment_options: CommentOptions::default(),
|
||||
source_text: "",
|
||||
trivias: Trivias::default(),
|
||||
code: vec![],
|
||||
needs_semicolon: false,
|
||||
need_space_before_dot: 0,
|
||||
print_next_indent_as_space: false,
|
||||
|
|
@ -148,15 +122,42 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
start_of_arrow_expr: 0,
|
||||
start_of_default_export: 0,
|
||||
indent: 0,
|
||||
sourcemap_builder,
|
||||
sourcemap_builder: None,
|
||||
move_comment_map: MoveCommentMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
// fn with_mangler(&mut self, mangler: Mangler) {
|
||||
// self.mangler = Some(mangler);
|
||||
// }
|
||||
#[must_use]
|
||||
pub fn enable_comment(
|
||||
mut self,
|
||||
source_text: &'a str,
|
||||
trivias: Trivias,
|
||||
options: CommentOptions,
|
||||
) -> Self {
|
||||
self.source_text = source_text;
|
||||
self.trivias = trivias;
|
||||
self.comment_options = options;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn enable_source_map(mut self, source_name: &str, source_text: &str) -> Self {
|
||||
let mut sourcemap_builder = SourcemapBuilder::default();
|
||||
sourcemap_builder.with_name_and_source(source_name, source_text);
|
||||
self.sourcemap_builder = Some(sourcemap_builder);
|
||||
self
|
||||
}
|
||||
|
||||
/// Initialize the output code buffer to reduce memory reallocation.
|
||||
/// Minification will reduce by at least half of the original size.
|
||||
#[must_use]
|
||||
pub fn with_capacity(mut self, source_text_len: usize) -> Self {
|
||||
let capacity = if MINIFY { source_text_len / 2 } else { source_text_len };
|
||||
self.code = Vec::with_capacity(capacity);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn build(mut self, program: &Program<'_>) -> CodegenReturn {
|
||||
program.gen(&mut self, Context::default());
|
||||
let source_text = self.into_source_text();
|
||||
|
|
@ -164,6 +165,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
CodegenReturn { source_text, source_map }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn into_source_text(&mut self) -> String {
|
||||
// SAFETY: criteria of `from_utf8_unchecked` are met.
|
||||
#[allow(unsafe_code)]
|
||||
|
|
@ -172,14 +174,6 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
}
|
||||
}
|
||||
|
||||
fn code(&self) -> &Vec<u8> {
|
||||
&self.code
|
||||
}
|
||||
|
||||
fn code_len(&self) -> usize {
|
||||
self.code().len()
|
||||
}
|
||||
|
||||
/// Push a single character into the buffer
|
||||
pub fn print(&mut self, ch: u8) {
|
||||
self.code.push(ch);
|
||||
|
|
@ -189,41 +183,16 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
pub fn print_str<T: AsRef<[u8]>>(&mut self, s: T) {
|
||||
self.code.extend_from_slice(s.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
/// This method to avoid rustc borrow checker issue.
|
||||
/// Since if you want to print a range of source code, you need to borrow the source code
|
||||
/// immutable first, and call the [Self::print_str] which is a mutable borrow.
|
||||
pub fn print_range_of_source_code(&mut self, range: Range<usize>) {
|
||||
self.code.extend_from_slice(self.source_text[range].as_bytes());
|
||||
// Private APIs
|
||||
impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
||||
fn code(&self) -> &Vec<u8> {
|
||||
&self.code
|
||||
}
|
||||
|
||||
/// In some scenario, we want to move the comment that should be codegened to another position.
|
||||
/// ```js
|
||||
/// /* @__NO_SIDE_EFFECTS__ */ export const a = function() {
|
||||
///
|
||||
/// }, b = 10000;
|
||||
///
|
||||
/// ```
|
||||
/// should generate such output:
|
||||
/// ```js
|
||||
/// export const /* @__NO_SIDE_EFFECTS__ */ a = function() {
|
||||
///
|
||||
/// }, b = 10000;
|
||||
/// ```
|
||||
pub fn move_comment(&mut self, position: u32, full_comment_info: (u32, Comment)) {
|
||||
self.move_comment_map.insert(position, full_comment_info);
|
||||
}
|
||||
|
||||
pub fn try_get_leading_comment(&self, start: u32) -> Option<(&u32, &Comment)> {
|
||||
self.trivias.comments_range(0..start).next_back()
|
||||
}
|
||||
|
||||
pub fn try_take_moved_comment(&mut self, node_start: u32) -> Option<(u32, Comment)> {
|
||||
self.move_comment_map.remove(&node_start)
|
||||
}
|
||||
|
||||
pub fn try_get_leading_comment_from_move_map(&self, start: u32) -> Option<&(u32, Comment)> {
|
||||
self.move_comment_map.get(&start)
|
||||
fn code_len(&self) -> usize {
|
||||
self.code().len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -331,14 +300,10 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
self.print(b'=');
|
||||
}
|
||||
|
||||
fn print_sequence<T: Gen<MINIFY>>(&mut self, items: &[T], separator: Separator, ctx: Context) {
|
||||
fn print_sequence<T: Gen<MINIFY>>(&mut self, items: &[T], ctx: Context) {
|
||||
for item in items {
|
||||
item.gen(self, ctx);
|
||||
match separator {
|
||||
Separator::Semicolon => self.print_semicolon(),
|
||||
Separator::Comma => self.print(b','),
|
||||
Separator::None => {}
|
||||
}
|
||||
self.print_comma();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -400,18 +365,6 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
self.needs_semicolon = false;
|
||||
}
|
||||
|
||||
fn print_block<T: Gen<MINIFY>>(
|
||||
&mut self,
|
||||
items: &[T],
|
||||
separator: Separator,
|
||||
ctx: Context,
|
||||
span: Span,
|
||||
) {
|
||||
self.print_block_start(span.start);
|
||||
self.print_sequence(items, separator, ctx);
|
||||
self.print_block_end(span.end);
|
||||
}
|
||||
|
||||
fn print_list<T: Gen<MINIFY>>(&mut self, items: &[T], ctx: Context) {
|
||||
for (index, item) in items.iter().enumerate() {
|
||||
if index != 0 {
|
||||
|
|
@ -499,7 +452,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
|
||||
#[inline]
|
||||
fn wrap_quote<F: FnMut(&mut Self, char)>(&mut self, s: &str, mut f: F) {
|
||||
let quote = choose_quote(s);
|
||||
let quote = Self::choose_quote(s);
|
||||
self.print(quote as u8);
|
||||
f(self, quote);
|
||||
self.print(quote as u8);
|
||||
|
|
@ -543,22 +496,59 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
sourcemap_builder.add_source_mapping_for_name(&self.code, span, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn choose_quote(s: &str) -> char {
|
||||
let mut single_cost = 0;
|
||||
let mut double_cost = 0;
|
||||
for c in s.chars() {
|
||||
match c {
|
||||
'\'' => single_cost += 1,
|
||||
'"' => double_cost += 1,
|
||||
_ => {}
|
||||
fn choose_quote(s: &str) -> char {
|
||||
let mut single_cost = 0;
|
||||
let mut double_cost = 0;
|
||||
for c in s.chars() {
|
||||
match c {
|
||||
'\'' => single_cost += 1,
|
||||
'"' => double_cost += 1,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if single_cost > double_cost {
|
||||
'"'
|
||||
} else {
|
||||
'\''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if single_cost > double_cost {
|
||||
'"'
|
||||
} else {
|
||||
'\''
|
||||
pub(crate) type MoveCommentMap = FxHashMap<u32, (u32, Comment)>;
|
||||
|
||||
// Comment related
|
||||
impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
||||
/// This method to avoid rustc borrow checker issue.
|
||||
/// Since if you want to print a range of source code, you need to borrow the source code
|
||||
/// immutable first, and call the [Self::print_str] which is a mutable borrow.
|
||||
fn print_range_of_source_code(&mut self, range: Range<usize>) {
|
||||
self.code.extend_from_slice(self.source_text[range].as_bytes());
|
||||
}
|
||||
|
||||
/// In some scenario, we want to move the comment that should be codegened to another position.
|
||||
/// ```js
|
||||
/// /* @__NO_SIDE_EFFECTS__ */ export const a = function() {
|
||||
///
|
||||
/// }, b = 10000;
|
||||
///
|
||||
/// ```
|
||||
/// should generate such output:
|
||||
/// ```js
|
||||
/// export const /* @__NO_SIDE_EFFECTS__ */ a = function() {
|
||||
///
|
||||
/// }, b = 10000;
|
||||
/// ```
|
||||
fn move_comment(&mut self, position: u32, full_comment_info: (u32, Comment)) {
|
||||
self.move_comment_map.insert(position, full_comment_info);
|
||||
}
|
||||
|
||||
fn try_get_leading_comment(&self, start: u32) -> Option<(&u32, &Comment)> {
|
||||
self.trivias.comments_range(0..start).next_back()
|
||||
}
|
||||
|
||||
fn try_take_moved_comment(&mut self, node_start: u32) -> Option<(u32, Comment)> {
|
||||
self.move_comment_map.remove(&node_start)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,13 @@
|
|||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::{CodeGenerator, CommentOptions};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
|
||||
fn test(source_text: &str, expected: &str, options: Option<CodegenOptions>) {
|
||||
fn test(source_text: &str, expected: &str) {
|
||||
let allocator = Allocator::default();
|
||||
let source_type = SourceType::default().with_module(true);
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let options = options.unwrap_or_default();
|
||||
let result = Codegen::<false>::new("", source_text, ret.trivias, options)
|
||||
.build(&ret.program)
|
||||
.source_text;
|
||||
let result = CodeGenerator::new().build(&ret.program).source_text;
|
||||
assert_eq!(expected, result, "for source {source_text}, expect {expected}, got {result}");
|
||||
}
|
||||
|
||||
|
|
@ -21,49 +18,46 @@ fn test_ts(source_text: &str, expected: &str, is_typescript_definition: bool) {
|
|||
.with_typescript_definition(is_typescript_definition)
|
||||
.with_module(true);
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let codegen_options = CodegenOptions::default();
|
||||
let result = Codegen::<false>::new("", source_text, ret.trivias, codegen_options)
|
||||
.build(&ret.program)
|
||||
.source_text;
|
||||
let result = CodeGenerator::new().build(&ret.program).source_text;
|
||||
assert_eq!(expected, result, "for source {source_text}, expect {expected}, got {result}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string() {
|
||||
test("let x = ''", "let x = '';\n", None);
|
||||
test(r"let x = '\b'", "let x = '\\b';\n", None);
|
||||
test(r"let x = '\f'", "let x = '\\f';\n", None);
|
||||
test("let x = '\t'", "let x = '\t';\n", None);
|
||||
test(r"let x = '\v'", "let x = '\\v';\n", None);
|
||||
test("let x = '\\n'", "let x = '\\n';\n", None);
|
||||
test("let x = '\\''", "let x = \"'\";\n", None);
|
||||
test("let x = '\\\"'", "let x = '\"';\n", None);
|
||||
// test( "let x = '\\'''", "let x = `''`;\n", None);
|
||||
test("let x = '\\\\'", "let x = '\\\\';\n", None);
|
||||
test("let x = '\x00'", "let x = '\\0';\n", None);
|
||||
test("let x = '\x00!'", "let x = '\\0!';\n", None);
|
||||
test("let x = '\x001'", "let x = '\\x001';\n", None);
|
||||
test("let x = '\\0'", "let x = '\\0';\n", None);
|
||||
test("let x = '\\0!'", "let x = '\\0!';\n", None);
|
||||
test("let x = '\x07'", "let x = '\\x07';\n", None);
|
||||
test("let x = '\x07!'", "let x = '\\x07!';\n", None);
|
||||
test("let x = '\x071'", "let x = '\\x071';\n", None);
|
||||
test("let x = '\\7'", "let x = '\\x07';\n", None);
|
||||
test("let x = '\\7!'", "let x = '\\x07!';\n", None);
|
||||
test("let x = '\\01'", "let x = '\x01';\n", None);
|
||||
test("let x = '\x10'", "let x = '\x10';\n", None);
|
||||
test("let x = '\\x10'", "let x = '\x10';\n", None);
|
||||
test("let x = '\x1B'", "let x = '\\x1B';\n", None);
|
||||
test("let x = '\\x1B'", "let x = '\\x1B';\n", None);
|
||||
test("let x = '\\uABCD'", "let x = 'ꯍ';\n", None);
|
||||
// test( "let x = '\\uABCD'", r#"let x = '\uABCD';\n"#, None);
|
||||
// test( r#"let x = '\U000123AB'"#, r#"let x = '\U000123AB';\n"#, None);
|
||||
// test( "let x = '\\u{123AB}'", r#"let x = '\U000123AB';\n"#, None);
|
||||
// test( "let x = '\\uD808\\uDFAB'", r#"let x = '\U000123AB';\n"#, None);
|
||||
test("let x = '\\uD808'", "let x = '\\\\ud808';\n", None);
|
||||
test("let x = '\\uD808X'", "let x = '\\\\ud808X';\n", None);
|
||||
test("let x = '\\uDFAB'", "let x = '\\\\udfab';\n", None);
|
||||
test("let x = '\\uDFABX'", "let x = '\\\\udfabX';\n", None);
|
||||
test("let x = ''", "let x = '';\n");
|
||||
test(r"let x = '\b'", "let x = '\\b';\n");
|
||||
test(r"let x = '\f'", "let x = '\\f';\n");
|
||||
test("let x = '\t'", "let x = '\t';\n");
|
||||
test(r"let x = '\v'", "let x = '\\v';\n");
|
||||
test("let x = '\\n'", "let x = '\\n';\n");
|
||||
test("let x = '\\''", "let x = \"'\";\n");
|
||||
test("let x = '\\\"'", "let x = '\"';\n");
|
||||
// test( "let x = '\\'''", "let x = `''`;\n");
|
||||
test("let x = '\\\\'", "let x = '\\\\';\n");
|
||||
test("let x = '\x00'", "let x = '\\0';\n");
|
||||
test("let x = '\x00!'", "let x = '\\0!';\n");
|
||||
test("let x = '\x001'", "let x = '\\x001';\n");
|
||||
test("let x = '\\0'", "let x = '\\0';\n");
|
||||
test("let x = '\\0!'", "let x = '\\0!';\n");
|
||||
test("let x = '\x07'", "let x = '\\x07';\n");
|
||||
test("let x = '\x07!'", "let x = '\\x07!';\n");
|
||||
test("let x = '\x071'", "let x = '\\x071';\n");
|
||||
test("let x = '\\7'", "let x = '\\x07';\n");
|
||||
test("let x = '\\7!'", "let x = '\\x07!';\n");
|
||||
test("let x = '\\01'", "let x = '\x01';\n");
|
||||
test("let x = '\x10'", "let x = '\x10';\n");
|
||||
test("let x = '\\x10'", "let x = '\x10';\n");
|
||||
test("let x = '\x1B'", "let x = '\\x1B';\n");
|
||||
test("let x = '\\x1B'", "let x = '\\x1B';\n");
|
||||
test("let x = '\\uABCD'", "let x = 'ꯍ';\n");
|
||||
// test( "let x = '\\uABCD'", r#"let x = '\uABCD';\n"#);
|
||||
// test( r#"let x = '\U000123AB'"#, r#"let x = '\U000123AB';\n"#);
|
||||
// test( "let x = '\\u{123AB}'", r#"let x = '\U000123AB';\n"#);
|
||||
// test( "let x = '\\uD808\\uDFAB'", r#"let x = '\U000123AB';\n"#);
|
||||
test("let x = '\\uD808'", "let x = '\\\\ud808';\n");
|
||||
test("let x = '\\uD808X'", "let x = '\\\\ud808X';\n");
|
||||
test("let x = '\\uDFAB'", "let x = '\\\\udfab';\n");
|
||||
test("let x = '\\uDFABX'", "let x = '\\\\udfabX';\n");
|
||||
|
||||
// test( "let x = '\\x80'", r#"let x = '\U00000080';\n"#);
|
||||
// test( "let x = '\\xFF'", r#"let x = '\U000000FF';\n"#);
|
||||
|
|
@ -73,72 +67,72 @@ fn string() {
|
|||
|
||||
#[test]
|
||||
fn template() {
|
||||
test("let x = `\\0`", "let x = `\\0`;\n", None);
|
||||
test("let x = `\\x01`", "let x = `\\x01`;\n", None);
|
||||
test("let x = `\\0${0}`", "let x = `\\0${0}`;\n", None);
|
||||
// test("let x = `\\x01${0}`", "let x = `\x01${0}`;\n", None);
|
||||
test("let x = `${0}\\0`", "let x = `${0}\\0`;\n", None);
|
||||
// test("let x = `${0}\\x01`", "let x = `${0}\x01`;\n", None);
|
||||
test("let x = `${0}\\0${1}`", "let x = `${0}\\0${1}`;\n", None);
|
||||
// test("let x = `${0}\\x01${1}`", "let x = `${0}\x01${1}`;\n", None);
|
||||
test("let x = `\\0`", "let x = `\\0`;\n");
|
||||
test("let x = `\\x01`", "let x = `\\x01`;\n");
|
||||
test("let x = `\\0${0}`", "let x = `\\0${0}`;\n");
|
||||
// test("let x = `\\x01${0}`", "let x = `\x01${0}`;\n");
|
||||
test("let x = `${0}\\0`", "let x = `${0}\\0`;\n");
|
||||
// test("let x = `${0}\\x01`", "let x = `${0}\x01`;\n");
|
||||
test("let x = `${0}\\0${1}`", "let x = `${0}\\0${1}`;\n");
|
||||
// test("let x = `${0}\\x01${1}`", "let x = `${0}\x01${1}`;\n");
|
||||
|
||||
test("let x = String.raw`\\1`", "let x = String.raw`\\1`;\n", None);
|
||||
test("let x = String.raw`\\x01`", "let x = String.raw`\\x01`;\n", None);
|
||||
test("let x = String.raw`\\1${0}`", "let x = String.raw`\\1${0}`;\n", None);
|
||||
test("let x = String.raw`\\x01${0}`", "let x = String.raw`\\x01${0}`;\n", None);
|
||||
test("let x = String.raw`${0}\\1`", "let x = String.raw`${0}\\1`;\n", None);
|
||||
test("let x = String.raw`${0}\\x01`", "let x = String.raw`${0}\\x01`;\n", None);
|
||||
test("let x = String.raw`${0}\\1${1}`", "let x = String.raw`${0}\\1${1}`;\n", None);
|
||||
test("let x = String.raw`${0}\\x01${1}`", "let x = String.raw`${0}\\x01${1}`;\n", None);
|
||||
test("let x = String.raw`\\1`", "let x = String.raw`\\1`;\n");
|
||||
test("let x = String.raw`\\x01`", "let x = String.raw`\\x01`;\n");
|
||||
test("let x = String.raw`\\1${0}`", "let x = String.raw`\\1${0}`;\n");
|
||||
test("let x = String.raw`\\x01${0}`", "let x = String.raw`\\x01${0}`;\n");
|
||||
test("let x = String.raw`${0}\\1`", "let x = String.raw`${0}\\1`;\n");
|
||||
test("let x = String.raw`${0}\\x01`", "let x = String.raw`${0}\\x01`;\n");
|
||||
test("let x = String.raw`${0}\\1${1}`", "let x = String.raw`${0}\\1${1}`;\n");
|
||||
test("let x = String.raw`${0}\\x01${1}`", "let x = String.raw`${0}\\x01${1}`;\n");
|
||||
|
||||
test("let x = `${y}`", "let x = `${y}`;\n", None);
|
||||
test("let x = `$(y)`", "let x = `$(y)`;\n", None);
|
||||
test("let x = `{y}$`", "let x = `{y}$`;\n", None);
|
||||
test("let x = `$}y{`", "let x = `$}y{`;\n", None);
|
||||
test("let x = `\\${y}`", "let x = `\\${y}`;\n", None);
|
||||
// test("let x = `$\\{y}`", "let x = `\\${y}`;\n", None);
|
||||
test("let x = `${y}`", "let x = `${y}`;\n");
|
||||
test("let x = `$(y)`", "let x = `$(y)`;\n");
|
||||
test("let x = `{y}$`", "let x = `{y}$`;\n");
|
||||
test("let x = `$}y{`", "let x = `$}y{`;\n");
|
||||
test("let x = `\\${y}`", "let x = `\\${y}`;\n");
|
||||
// test("let x = `$\\{y}`", "let x = `\\${y}`;\n");
|
||||
|
||||
test("await tag`x`", "await tag`x`;\n", None);
|
||||
test("await (tag`x`)", "await tag`x`;\n", None);
|
||||
test("(await tag)`x`", "(await tag)`x`;\n", None);
|
||||
test("await tag`x`", "await tag`x`;\n");
|
||||
test("await (tag`x`)", "await tag`x`;\n");
|
||||
test("(await tag)`x`", "(await tag)`x`;\n");
|
||||
|
||||
test("await tag`${x}`", "await tag`${x}`;\n", None);
|
||||
test("await (tag`${x}`)", "await tag`${x}`;\n", None);
|
||||
test("(await tag)`${x}`", "(await tag)`${x}`;\n", None);
|
||||
test("await tag`${x}`", "await tag`${x}`;\n");
|
||||
test("await (tag`${x}`)", "await tag`${x}`;\n");
|
||||
test("(await tag)`${x}`", "(await tag)`${x}`;\n");
|
||||
|
||||
test("new tag`x`", "new tag`x`();\n", None);
|
||||
test("new (tag`x`)", "new tag`x`();\n", None);
|
||||
test("new tag()`x`", "new tag()`x`;\n", None);
|
||||
test("(new tag)`x`", "new tag()`x`;\n", None);
|
||||
test("new tag`x`", "new tag`x`();\n");
|
||||
test("new (tag`x`)", "new tag`x`();\n");
|
||||
test("new tag()`x`", "new tag()`x`;\n");
|
||||
test("(new tag)`x`", "new tag()`x`;\n");
|
||||
|
||||
test("new tag`${x}`", "new tag`${x}`();\n", None);
|
||||
test("new (tag`${x}`)", "new tag`${x}`();\n", None);
|
||||
test("new tag()`${x}`", "new tag()`${x}`;\n", None);
|
||||
test("(new tag)`${x}`", "new tag()`${x}`;\n", None);
|
||||
test("new tag`${x}`", "new tag`${x}`();\n");
|
||||
test("new (tag`${x}`)", "new tag`${x}`();\n");
|
||||
test("new tag()`${x}`", "new tag()`${x}`;\n");
|
||||
test("(new tag)`${x}`", "new tag()`${x}`;\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn module_decl() {
|
||||
test("export * as foo from 'foo'", "export * as foo from 'foo';\n", None);
|
||||
test("import x from './foo.js' with {}", "import x from './foo.js' with {\n};\n", None);
|
||||
test("import {} from './foo.js' with {}", "import {} from './foo.js' with {\n};\n", None);
|
||||
test("export * from './foo.js' with {}", "export * from './foo.js' with {\n};\n", None);
|
||||
test("export * as foo from 'foo'", "export * as foo from 'foo';\n");
|
||||
test("import x from './foo.js' with {}", "import x from './foo.js' with {\n};\n");
|
||||
test("import {} from './foo.js' with {}", "import {} from './foo.js' with {\n};\n");
|
||||
test("export * from './foo.js' with {}", "export * from './foo.js' with {\n};\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_expr() {
|
||||
test("new (foo()).bar();", "new (foo()).bar();\n", None);
|
||||
test("new (foo()).bar();", "new (foo()).bar();\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_stmt() {
|
||||
test("for (let x = 0; x < 10; x++) {}", "for (let x = 0; x < 10; x++) {}\n", None);
|
||||
test("for (;;) {}", "for (;;) {}\n", None);
|
||||
test("for (let x = 1;;) {}", "for (let x = 1;;) {}\n", None);
|
||||
test("for (;true;) {}", "for (; true;) {}\n", None);
|
||||
test("for (;;i++) {}", "for (;; i++) {}\n", None);
|
||||
test("for (let x = 0; x < 10; x++) {}", "for (let x = 0; x < 10; x++) {}\n");
|
||||
test("for (;;) {}", "for (;;) {}\n");
|
||||
test("for (let x = 1;;) {}", "for (let x = 1;;) {}\n");
|
||||
test("for (;true;) {}", "for (; true;) {}\n");
|
||||
test("for (;;i++) {}", "for (;; i++) {}\n");
|
||||
|
||||
test("for (using x = 1;;) {}", "for (using x = 1;;) {}\n", None);
|
||||
test("for (using x = 1;;) {}", "for (using x = 1;;) {}\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -190,12 +184,20 @@ fn typescript() {
|
|||
}
|
||||
|
||||
fn test_comment_helper(source_text: &str, expected: &str) {
|
||||
test(
|
||||
source_text,
|
||||
expected,
|
||||
Some(CodegenOptions { enable_source_map: true, preserve_annotate_comments: true }),
|
||||
);
|
||||
let allocator = Allocator::default();
|
||||
let source_type = SourceType::default().with_module(true);
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let result = CodeGenerator::new()
|
||||
.enable_comment(
|
||||
source_text,
|
||||
ret.trivias,
|
||||
CommentOptions { preserve_annotate_comments: true },
|
||||
)
|
||||
.build(&ret.program)
|
||||
.source_text;
|
||||
assert_eq!(expected, result, "for source {source_text}, expect {expected}, got {result}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn annotate_comment() {
|
||||
test_comment_helper(
|
||||
|
|
@ -337,8 +339,8 @@ const c2 = /* #__NO_SIDE_EFFECTS__ */ () => {}, c3 = () => {};
|
|||
|
||||
#[test]
|
||||
fn unicode_escape() {
|
||||
test("console.log('你好');", "console.log('你好');\n", None);
|
||||
test("console.log('こんにちは');", "console.log('こんにちは');\n", None);
|
||||
test("console.log('안녕하세요');", "console.log('안녕하세요');\n", None);
|
||||
test("console.log('🧑🤝🧑');", "console.log('🧑🤝🧑');\n", None);
|
||||
test("console.log('你好');", "console.log('你好');\n");
|
||||
test("console.log('こんにちは');", "console.log('こんにちは');\n");
|
||||
test("console.log('안녕하세요');", "console.log('안녕하세요');\n");
|
||||
test("console.log('🧑🤝🧑');", "console.log('🧑🤝🧑');\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
use std::{env, path::Path};
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_ast::Trivias;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::CodeGenerator;
|
||||
use oxc_isolated_declarations::IsolatedDeclarations;
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
|
|
@ -34,10 +33,7 @@ fn main() {
|
|||
println!("{source_text}\n");
|
||||
|
||||
let ret = IsolatedDeclarations::new(&allocator).build(&ret.program);
|
||||
let printed =
|
||||
Codegen::<false>::new("", &source_text, Trivias::default(), CodegenOptions::default())
|
||||
.build(&ret.program)
|
||||
.source_text;
|
||||
let printed = CodeGenerator::new().build(&ret.program).source_text;
|
||||
|
||||
println!("Dts Emit:\n");
|
||||
println!("{printed}\n");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use oxc_ast::Trivias;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::Codegen;
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
|
|
@ -65,7 +64,7 @@ impl<'c, 'a: 'c> RuleFixer<'c, 'a> {
|
|||
|
||||
#[allow(clippy::unused_self)]
|
||||
pub fn codegen(self) -> Codegen<'a, false> {
|
||||
Codegen::<false>::new("", "", Trivias::default(), CodegenOptions::default())
|
||||
Codegen::<false>::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
use std::path::Path;
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::{CodeGenerator, WhitespaceRemover};
|
||||
use oxc_minifier::{Minifier, MinifierOptions};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
|
|
@ -44,10 +44,9 @@ fn minify(source_text: &str, source_type: SourceType, mangle: bool, whitespace:
|
|||
let options = MinifierOptions { mangle, ..MinifierOptions::default() };
|
||||
Minifier::new(options).build(&allocator, program);
|
||||
if whitespace {
|
||||
Codegen::<true>::new("", source_text, ret.trivias, CodegenOptions::default()).build(program)
|
||||
WhitespaceRemover::new().build(program)
|
||||
} else {
|
||||
Codegen::<false>::new("", source_text, ret.trivias, CodegenOptions::default())
|
||||
.build(program)
|
||||
CodeGenerator::new().build(program)
|
||||
}
|
||||
.source_text
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ mod tdewolff;
|
|||
mod terser;
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::WhitespaceRemover;
|
||||
use oxc_minifier::{CompressOptions, Minifier, MinifierOptions};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
|
|
@ -19,9 +19,7 @@ pub(crate) fn minify(
|
|||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let program = allocator.alloc(ret.program);
|
||||
Minifier::new(options).build(&allocator, program);
|
||||
Codegen::<true>::new("", source_text, ret.trivias, CodegenOptions::default())
|
||||
.build(program)
|
||||
.source_text
|
||||
WhitespaceRemover::new().build(program).source_text
|
||||
}
|
||||
|
||||
pub(crate) fn test(source_text: &str, expected: &str) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
use std::{env, path::Path};
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::CodeGenerator;
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
use oxc_transformer::{
|
||||
|
|
@ -57,9 +57,7 @@ fn main() {
|
|||
)
|
||||
.build(&mut program);
|
||||
|
||||
let printed = Codegen::<false>::new("", &source_text, ret.trivias, CodegenOptions::default())
|
||||
.build(&program)
|
||||
.source_text;
|
||||
let printed = CodeGenerator::new().build(&program).source_text;
|
||||
println!("Transformed:\n");
|
||||
println!("{printed}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::{cell::RefCell, path::PathBuf, rc::Rc};
|
|||
use oxc::{
|
||||
allocator::Allocator,
|
||||
ast::{CommentKind, Trivias},
|
||||
codegen::{Codegen, CodegenOptions},
|
||||
codegen::{CodeGenerator, WhitespaceRemover},
|
||||
diagnostics::Error,
|
||||
minifier::{CompressOptions, Minifier, MinifierOptions},
|
||||
parser::Parser,
|
||||
|
|
@ -283,15 +283,10 @@ impl Oxc {
|
|||
Minifier::new(options).build(&allocator, program);
|
||||
}
|
||||
|
||||
let codegen_options = CodegenOptions::default();
|
||||
self.codegen_text = if minifier_options.whitespace() {
|
||||
Codegen::<true>::new("", source_text, ret.trivias, codegen_options)
|
||||
.build(program)
|
||||
.source_text
|
||||
WhitespaceRemover::new().build(program).source_text
|
||||
} else {
|
||||
Codegen::<false>::new("", source_text, ret.trivias, codegen_options)
|
||||
.build(program)
|
||||
.source_text
|
||||
CodeGenerator::new().build(program).source_text
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ doctest = false
|
|||
[dependencies]
|
||||
oxc_allocator = { workspace = true }
|
||||
oxc_parser = { workspace = true }
|
||||
oxc_ast = { workspace = true }
|
||||
oxc_span = { workspace = true }
|
||||
oxc_diagnostics = { workspace = true }
|
||||
oxc_codegen = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use napi_derive::napi;
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_ast::Trivias;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::CodeGenerator;
|
||||
use oxc_diagnostics::{Error, NamedSource};
|
||||
use oxc_isolated_declarations::IsolatedDeclarations;
|
||||
use oxc_parser::Parser;
|
||||
|
|
@ -23,14 +22,7 @@ pub fn isolated_declaration(filename: String, source_text: String) -> IsolatedDe
|
|||
let allocator = Allocator::default();
|
||||
let parser_ret = Parser::new(&allocator, &source_text, source_type).parse();
|
||||
let transformed_ret = IsolatedDeclarations::new(&allocator).build(&parser_ret.program);
|
||||
let printed = Codegen::<false>::new(
|
||||
&filename,
|
||||
&source_text,
|
||||
Trivias::default(),
|
||||
CodegenOptions::default(),
|
||||
)
|
||||
.build(&transformed_ret.program)
|
||||
.source_text;
|
||||
let printed = CodeGenerator::new().build(&transformed_ret.program).source_text;
|
||||
|
||||
let mut errors = vec![];
|
||||
if !parser_ret.errors.is_empty() || !transformed_ret.errors.is_empty() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use oxc_allocator::Allocator;
|
||||
use oxc_benchmark::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::CodeGenerator;
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
use oxc_tasks_common::TestFiles;
|
||||
|
|
@ -14,17 +14,11 @@ fn bench_codegen_sourcemap(criterion: &mut Criterion) {
|
|||
group.bench_with_input(id, &file.source_text, |b, source_text| {
|
||||
let allocator = Allocator::default();
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let codegen_options =
|
||||
CodegenOptions { enable_source_map: true, ..CodegenOptions::default() };
|
||||
b.iter_with_large_drop(|| {
|
||||
Codegen::<false>::new(
|
||||
file.file_name.as_str(),
|
||||
source_text,
|
||||
ret.trivias.clone(),
|
||||
codegen_options,
|
||||
)
|
||||
.build(&ret.program)
|
||||
.source_map
|
||||
CodeGenerator::new()
|
||||
.enable_source_map(file.file_name.as_str(), source_text)
|
||||
.build(&ret.program)
|
||||
.source_map
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use oxc_allocator::Allocator;
|
||||
use oxc_benchmark::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
use oxc_codegen::{Codegen, CodegenOptions, CodegenReturn};
|
||||
use oxc_codegen::{CodeGenerator, CodegenReturn};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_sourcemap::ConcatSourceMapBuilder;
|
||||
use oxc_span::SourceType;
|
||||
|
|
@ -16,16 +16,10 @@ fn bench_sourcemap(criterion: &mut Criterion) {
|
|||
group.bench_with_input(id, &file.source_text, |b, source_text| {
|
||||
let allocator = Allocator::default();
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let codegen_options =
|
||||
CodegenOptions { enable_source_map: true, ..CodegenOptions::default() };
|
||||
b.iter(|| {
|
||||
let CodegenReturn { source_map, source_text } = Codegen::<false>::new(
|
||||
file.file_name.as_str(),
|
||||
source_text,
|
||||
ret.trivias.clone(),
|
||||
codegen_options,
|
||||
)
|
||||
.build(&ret.program);
|
||||
let CodegenReturn { source_map, source_text } = CodeGenerator::new()
|
||||
.enable_source_map(file.file_name.as_str(), source_text)
|
||||
.build(&ret.program);
|
||||
let line = source_text.matches('\n').count() as u32;
|
||||
if let Some(sourcemap) = source_map {
|
||||
let mut concat_sourcemap_builder = ConcatSourceMapBuilder::default();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::{CodeGenerator, WhitespaceRemover};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
|
||||
|
|
@ -29,36 +29,25 @@ fn get_result(source_text: &str, source_type: SourceType) -> TestResult {
|
|||
|
||||
/// Idempotency test
|
||||
fn get_normal_result(source_text: &str, source_type: SourceType) -> bool {
|
||||
let options = CodegenOptions::default();
|
||||
let allocator = Allocator::default();
|
||||
let source_text1 = {
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
Codegen::<false>::new("", source_text, ret.trivias, options).build(&ret.program).source_text
|
||||
CodeGenerator::new().build(&ret.program).source_text
|
||||
};
|
||||
|
||||
let source_text2 = {
|
||||
let ret = Parser::new(&allocator, &source_text1, source_type).parse();
|
||||
Codegen::<false>::new("", &source_text1, ret.trivias, options)
|
||||
.build(&ret.program)
|
||||
.source_text
|
||||
CodeGenerator::new().build(&ret.program).source_text
|
||||
};
|
||||
|
||||
source_text1 == source_text2
|
||||
}
|
||||
|
||||
/// Minify idempotency test
|
||||
fn get_minify_result(source_text: &str, source_type: SourceType) -> bool {
|
||||
let options = CodegenOptions::default();
|
||||
let allocator = Allocator::default();
|
||||
let parse_result1 = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let source_text1 =
|
||||
Codegen::<true>::new("", source_text, parse_result1.trivias.clone(), options)
|
||||
.build(&parse_result1.program)
|
||||
.source_text;
|
||||
let source_text1 = WhitespaceRemover::new().build(&parse_result1.program).source_text;
|
||||
let parse_result2 = Parser::new(&allocator, source_text1.as_str(), source_type).parse();
|
||||
let source_text2 = Codegen::<true>::new("", &source_text1, parse_result2.trivias, options)
|
||||
.build(&parse_result2.program)
|
||||
.source_text;
|
||||
let source_text2 = WhitespaceRemover::new().build(&parse_result2.program).source_text;
|
||||
source_text1 == source_text2
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::WhitespaceRemover;
|
||||
use oxc_minifier::{CompressOptions, Minifier, MinifierOptions};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
|
|
@ -100,7 +100,5 @@ fn minify(source_text: &str, source_type: SourceType, options: MinifierOptions)
|
|||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let program = allocator.alloc(ret.program);
|
||||
Minifier::new(options).build(&allocator, program);
|
||||
Codegen::<true>::new("", source_text, ret.trivias, CodegenOptions::default())
|
||||
.build(program)
|
||||
.source_text
|
||||
WhitespaceRemover::new().build(program).source_text
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use oxc_tasks_common::{agent, project_root};
|
|||
use phf::{phf_set, Set};
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::CodeGenerator;
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
use serde_json::json;
|
||||
|
|
@ -141,10 +141,7 @@ impl Case for CodegenRuntimeTest262Case {
|
|||
let source_type = SourceType::default().with_module(is_module);
|
||||
let allocator = Allocator::default();
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let mut text =
|
||||
Codegen::<false>::new("", source_text, ret.trivias, CodegenOptions::default())
|
||||
.build(&ret.program)
|
||||
.source_text;
|
||||
let mut text = CodeGenerator::new().build(&ret.program).source_text;
|
||||
if is_only_strict {
|
||||
text = format!("\"use strict\";\n{text}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::{
|
|||
};
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::CodeGenerator;
|
||||
use oxc_parser::Parser;
|
||||
use oxc_sourcemap::SourcemapVisualizer;
|
||||
use oxc_span::SourceType;
|
||||
|
|
@ -127,15 +127,9 @@ impl Case for SourcemapCase {
|
|||
}
|
||||
}
|
||||
|
||||
let codegen_options =
|
||||
CodegenOptions { enable_source_map: true, ..CodegenOptions::default() };
|
||||
let codegen_ret = Codegen::<false>::new(
|
||||
self.path.to_string_lossy().as_ref(),
|
||||
source_text,
|
||||
ret.trivias,
|
||||
codegen_options,
|
||||
)
|
||||
.build(&ret.program);
|
||||
let codegen_ret = CodeGenerator::new()
|
||||
.enable_source_map(self.path.to_string_lossy().as_ref(), source_text)
|
||||
.build(&ret.program);
|
||||
|
||||
TestResult::Snapshot(
|
||||
SourcemapVisualizer::new(&codegen_ret.source_text, &codegen_ret.source_map.unwrap())
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::CodeGenerator;
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
use oxc_transformer::{
|
||||
|
|
@ -25,7 +25,6 @@ fn get_result(
|
|||
options: Option<TransformOptions>,
|
||||
) -> TestResult {
|
||||
let allocator = Allocator::default();
|
||||
let filename = source_path.file_name().unwrap().to_string_lossy();
|
||||
let options = options.unwrap_or_else(get_default_transformer_options);
|
||||
|
||||
// First pass
|
||||
|
|
@ -40,14 +39,7 @@ fn get_result(
|
|||
options.clone(),
|
||||
)
|
||||
.build(&mut ret1.program);
|
||||
Codegen::<false>::new(
|
||||
&filename,
|
||||
source_text,
|
||||
ret1.trivias.clone(),
|
||||
CodegenOptions::default(),
|
||||
)
|
||||
.build(&ret1.program)
|
||||
.source_text
|
||||
CodeGenerator::new().build(&ret1.program).source_text
|
||||
};
|
||||
|
||||
// Second pass with only JavaScript parsing
|
||||
|
|
@ -63,9 +55,7 @@ fn get_result(
|
|||
options,
|
||||
)
|
||||
.build(&mut ret2.program);
|
||||
Codegen::<false>::new(&filename, source_text, ret2.trivias, CodegenOptions::default())
|
||||
.build(&ret2.program)
|
||||
.source_text
|
||||
CodeGenerator::new().build(&ret2.program).source_text
|
||||
};
|
||||
|
||||
if transformed1 == transformed2 {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
use std::{collections::HashMap, fs, path::Path, sync::Arc};
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::CodeGenerator;
|
||||
use oxc_diagnostics::{NamedSource, OxcDiagnostic};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
|
|
@ -177,10 +177,7 @@ impl Baseline {
|
|||
let allocator = Allocator::default();
|
||||
let source_type = SourceType::from_path(Path::new(&self.name)).unwrap();
|
||||
let ret = Parser::new(&allocator, &self.original, source_type).parse();
|
||||
let printed =
|
||||
Codegen::<false>::new("", &self.original, ret.trivias, CodegenOptions::default())
|
||||
.build(&ret.program)
|
||||
.source_text;
|
||||
let printed = CodeGenerator::new().build(&ret.program).source_text;
|
||||
self.oxc_printed = printed;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_ast::Trivias;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::CodeGenerator;
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_isolated_declarations::IsolatedDeclarations;
|
||||
use oxc_parser::Parser;
|
||||
|
|
@ -166,8 +165,6 @@ fn transpile(path: &Path, source_text: &str) -> (String, Vec<OxcDiagnostic>) {
|
|||
let source_type = SourceType::from_path(path).unwrap();
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let ret = IsolatedDeclarations::new(&allocator).build(&ret.program);
|
||||
let printed = Codegen::<false>::new("", "", Trivias::default(), CodegenOptions::default())
|
||||
.build(&ret.program)
|
||||
.source_text;
|
||||
let printed = CodeGenerator::new().build(&ret.program).source_text;
|
||||
(printed, ret.errors)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use flate2::{write::GzEncoder, Compression};
|
|||
use humansize::{format_size, DECIMAL};
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::WhitespaceRemover;
|
||||
use oxc_minifier::{CompressOptions, Minifier, MinifierOptions};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
|
|
@ -74,9 +74,7 @@ fn minify(source_text: &str, source_type: SourceType, options: MinifierOptions)
|
|||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let program = allocator.alloc(ret.program);
|
||||
Minifier::new(options).build(&allocator, program);
|
||||
Codegen::<true>::new("", source_text, ret.trivias, CodegenOptions::default())
|
||||
.build(program)
|
||||
.source_text
|
||||
WhitespaceRemover::new().build(program).source_text
|
||||
}
|
||||
|
||||
fn gzip_size(s: &str) -> usize {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::{
|
|||
};
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_codegen::CodeGenerator;
|
||||
use oxc_diagnostics::{Error, OxcDiagnostic};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::{SourceType, VALID_EXTENSIONS};
|
||||
|
|
@ -180,12 +180,7 @@ pub trait TestCase {
|
|||
transform_options.clone(),
|
||||
)
|
||||
.build(&mut program);
|
||||
|
||||
result.map(|()| {
|
||||
Codegen::<false>::new("", &source_text, ret.trivias, CodegenOptions::default())
|
||||
.build(&program)
|
||||
.source_text
|
||||
})
|
||||
result.map(|()| CodeGenerator::new().build(&program).source_text)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -251,7 +246,6 @@ impl TestCase for ConformanceTestCase {
|
|||
println!("output_path: {output_path:?}");
|
||||
}
|
||||
|
||||
let codegen_options = CodegenOptions::default();
|
||||
let mut transformed_code = String::new();
|
||||
let mut actual_errors = String::new();
|
||||
|
||||
|
|
@ -270,10 +264,7 @@ impl TestCase for ConformanceTestCase {
|
|||
);
|
||||
let result = transformer.build(&mut program);
|
||||
if result.is_ok() {
|
||||
transformed_code =
|
||||
Codegen::<false>::new("", &input, ret.trivias, codegen_options)
|
||||
.build(&program)
|
||||
.source_text;
|
||||
transformed_code = CodeGenerator::new().build(&program).source_text;
|
||||
} else {
|
||||
let error = result
|
||||
.err()
|
||||
|
|
@ -315,9 +306,7 @@ impl TestCase for ConformanceTestCase {
|
|||
|output| {
|
||||
// Get expected code by parsing the source text, so we can get the same code generated result.
|
||||
let ret = Parser::new(&allocator, &output, source_type).parse();
|
||||
Codegen::<false>::new("", &output, ret.trivias, codegen_options)
|
||||
.build(&ret.program)
|
||||
.source_text
|
||||
CodeGenerator::new().build(&ret.program).source_text
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -382,17 +371,8 @@ impl ExecTestCase {
|
|||
let source_text = fs::read_to_string(&target_path).unwrap();
|
||||
let source_type = SourceType::from_path(&target_path).unwrap();
|
||||
let transformed_ret = Parser::new(&allocator, &source_text, source_type).parse();
|
||||
let result = Codegen::<false>::new(
|
||||
"",
|
||||
&source_text,
|
||||
transformed_ret.trivias,
|
||||
CodegenOptions::default(),
|
||||
)
|
||||
.build(&transformed_ret.program)
|
||||
.source_text;
|
||||
|
||||
let result = CodeGenerator::new().build(&transformed_ret.program).source_text;
|
||||
fs::write(&target_path, result).unwrap();
|
||||
|
||||
target_path
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue