mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
feat(codegen)!: remove const generic MINIFY (#5001)
This is a premature optimization, makes the code complicated, and bloats the final binary size. The minify option is moved to `CodegenOptions`
This commit is contained in:
parent
b2ff2df5af
commit
ce4d4698b4
17 changed files with 478 additions and 479 deletions
|
|
@ -2,7 +2,7 @@ use std::{mem, ops::ControlFlow, path::Path};
|
|||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_ast::{ast::Program, Trivias};
|
||||
use oxc_codegen::{CodeGenerator, CodegenOptions, CommentOptions, WhitespaceRemover};
|
||||
use oxc_codegen::{CodeGenerator, CodegenOptions, CommentOptions};
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_parser::{ParseOptions, Parser, ParserReturn};
|
||||
use oxc_span::SourceType;
|
||||
|
|
@ -216,14 +216,10 @@ pub trait CompilerInterface {
|
|||
) -> String {
|
||||
let comment_options = CommentOptions { preserve_annotate_comments: true };
|
||||
|
||||
if self.remove_whitespace() {
|
||||
WhitespaceRemover::new().with_options(options).build(program).source_text
|
||||
} else {
|
||||
CodeGenerator::new()
|
||||
.with_options(options)
|
||||
.enable_comment(source_text, trivias.clone(), comment_options)
|
||||
.build(program)
|
||||
.source_text
|
||||
}
|
||||
CodeGenerator::new()
|
||||
.with_options(CodegenOptions { minify: self.remove_whitespace(), ..options })
|
||||
.enable_comment(source_text, trivias.clone(), comment_options)
|
||||
.build(program)
|
||||
.source_text
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
use std::{env, path::Path};
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{CodeGenerator, CommentOptions, WhitespaceRemover};
|
||||
use oxc_codegen::{CodeGenerator, CodegenOptions, CommentOptions};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
use pico_args::Arguments;
|
||||
|
|
@ -68,7 +68,10 @@ fn main() -> std::io::Result<()> {
|
|||
if minify {
|
||||
let allocator = Allocator::default();
|
||||
let ret = Parser::new(&allocator, &source_text, source_type).parse();
|
||||
let minified = WhitespaceRemover::new().build(&ret.program).source_text;
|
||||
let minified = CodeGenerator::new()
|
||||
.with_options(CodegenOptions { minify: true, ..CodegenOptions::default() })
|
||||
.build(&ret.program)
|
||||
.source_text;
|
||||
println!("Minified:");
|
||||
println!("{minified}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ impl From<(Comment, AnnotationKind)> for AnnotationComment {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
||||
impl<'a> Codegen<'a> {
|
||||
pub(crate) fn get_leading_annotate_comments(
|
||||
&mut self,
|
||||
node_start: u32,
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ pub enum BinaryishOperator {
|
|||
Logical(LogicalOperator),
|
||||
}
|
||||
|
||||
impl<const MINIFY: bool> Gen<MINIFY> for BinaryishOperator {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
impl Gen for BinaryishOperator {
|
||||
fn gen(&self, p: &mut Codegen, ctx: Context) {
|
||||
match self {
|
||||
Self::Binary(op) => op.gen(p, ctx),
|
||||
Self::Logical(op) => op.gen(p, ctx),
|
||||
|
|
@ -89,7 +89,7 @@ pub struct BinaryExpressionVisitor<'a> {
|
|||
}
|
||||
|
||||
impl<'a> BinaryExpressionVisitor<'a> {
|
||||
pub fn gen_expr<const MINIFY: bool>(v: Self, p: &mut Codegen<'a, { MINIFY }>) {
|
||||
pub fn gen_expr(v: Self, p: &mut Codegen<'a>) {
|
||||
let mut v = v;
|
||||
let stack_bottom = p.binary_expr_stack.len();
|
||||
loop {
|
||||
|
|
@ -133,7 +133,7 @@ impl<'a> BinaryExpressionVisitor<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_and_prepare<const MINIFY: bool>(&mut self, p: &mut Codegen<{ MINIFY }>) -> bool {
|
||||
pub fn check_and_prepare(&mut self, p: &mut Codegen) -> bool {
|
||||
let e = self.e;
|
||||
self.operator = e.operator();
|
||||
|
||||
|
|
@ -181,7 +181,7 @@ impl<'a> BinaryExpressionVisitor<'a> {
|
|||
true
|
||||
}
|
||||
|
||||
pub fn visit_right_and_finish<const MINIFY: bool>(&self, p: &mut Codegen<{ MINIFY }>) {
|
||||
pub fn visit_right_and_finish(&self, p: &mut Codegen) {
|
||||
p.print_soft_space();
|
||||
self.operator.gen(p, Context::empty());
|
||||
p.print_soft_space();
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -34,15 +34,14 @@ pub use crate::{
|
|||
};
|
||||
|
||||
/// Code generator without whitespace removal.
|
||||
pub type CodeGenerator<'a> = Codegen<'a, false>;
|
||||
|
||||
/// Code generator with whitespace removal.
|
||||
pub type WhitespaceRemover<'a> = Codegen<'a, true>;
|
||||
pub type CodeGenerator<'a> = Codegen<'a>;
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub struct CodegenOptions {
|
||||
/// Use single quotes instead of double quotes.
|
||||
pub single_quote: bool,
|
||||
|
||||
pub minify: bool,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
|
|
@ -56,7 +55,7 @@ pub struct CodegenReturn {
|
|||
pub source_map: Option<oxc_sourcemap::SourceMap>,
|
||||
}
|
||||
|
||||
pub struct Codegen<'a, const MINIFY: bool> {
|
||||
pub struct Codegen<'a> {
|
||||
options: CodegenOptions,
|
||||
comment_options: CommentOptions,
|
||||
|
||||
|
|
@ -97,26 +96,26 @@ pub struct Codegen<'a, const MINIFY: bool> {
|
|||
latest_consumed_comment_end: u32,
|
||||
}
|
||||
|
||||
impl<'a, const MINIFY: bool> Default for Codegen<'a, MINIFY> {
|
||||
impl<'a> Default for Codegen<'a> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const MINIFY: bool> From<Codegen<'a, MINIFY>> for String {
|
||||
fn from(mut val: Codegen<'a, MINIFY>) -> Self {
|
||||
impl<'a> From<Codegen<'a>> for String {
|
||||
fn from(mut val: Codegen<'a>) -> 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 {
|
||||
impl<'a> From<Codegen<'a>> for Cow<'a, str> {
|
||||
fn from(mut val: Codegen<'a>) -> Self {
|
||||
Cow::Owned(val.into_source_text())
|
||||
}
|
||||
}
|
||||
|
||||
// Public APIs
|
||||
impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
||||
impl<'a> Codegen<'a> {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
|
|
@ -147,7 +146,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
/// 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 };
|
||||
let capacity = if self.options.minify { source_text_len / 2 } else { source_text_len };
|
||||
self.code = Vec::with_capacity(capacity);
|
||||
self
|
||||
}
|
||||
|
|
@ -215,7 +214,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
}
|
||||
|
||||
// Private APIs
|
||||
impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
||||
impl<'a> Codegen<'a> {
|
||||
fn code(&self) -> &Vec<u8> {
|
||||
&self.code
|
||||
}
|
||||
|
|
@ -226,7 +225,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
|
||||
#[inline]
|
||||
fn print_soft_space(&mut self) {
|
||||
if !MINIFY {
|
||||
if !self.options.minify {
|
||||
self.print_char(b' ');
|
||||
}
|
||||
}
|
||||
|
|
@ -238,7 +237,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
|
||||
#[inline]
|
||||
fn print_soft_newline(&mut self) {
|
||||
if !MINIFY {
|
||||
if !self.options.minify {
|
||||
self.print_char(b'\n');
|
||||
}
|
||||
}
|
||||
|
|
@ -271,21 +270,21 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
|
||||
#[inline]
|
||||
fn indent(&mut self) {
|
||||
if !MINIFY {
|
||||
if !self.options.minify {
|
||||
self.indent += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn dedent(&mut self) {
|
||||
if !MINIFY {
|
||||
if !self.options.minify {
|
||||
self.indent -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn print_indent(&mut self) {
|
||||
if MINIFY {
|
||||
if self.options.minify {
|
||||
return;
|
||||
}
|
||||
if self.print_next_indent_as_space {
|
||||
|
|
@ -298,7 +297,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
|
||||
#[inline]
|
||||
fn print_semicolon_after_statement(&mut self) {
|
||||
if MINIFY {
|
||||
if self.options.minify {
|
||||
self.needs_semicolon = true;
|
||||
} else {
|
||||
self.print_str(";\n");
|
||||
|
|
@ -328,7 +327,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
self.print_char(b'=');
|
||||
}
|
||||
|
||||
fn print_sequence<T: Gen<MINIFY>>(&mut self, items: &[T], ctx: Context) {
|
||||
fn print_sequence<T: Gen>(&mut self, items: &[T], ctx: Context) {
|
||||
for item in items {
|
||||
item.gen(self, ctx);
|
||||
self.print_comma();
|
||||
|
|
@ -377,7 +376,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
self.print_soft_newline();
|
||||
}
|
||||
stmt => {
|
||||
if need_space && MINIFY {
|
||||
if need_space && self.options.minify {
|
||||
self.print_hard_space();
|
||||
}
|
||||
self.print_next_indent_as_space = true;
|
||||
|
|
@ -396,7 +395,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
self.needs_semicolon = false;
|
||||
}
|
||||
|
||||
fn print_list<T: Gen<MINIFY>>(&mut self, items: &[T], ctx: Context) {
|
||||
fn print_list<T: Gen>(&mut self, items: &[T], ctx: Context) {
|
||||
for (index, item) in items.iter().enumerate() {
|
||||
if index != 0 {
|
||||
self.print_comma();
|
||||
|
|
@ -411,12 +410,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
expr.gen_expr(self, Precedence::Lowest, Context::empty());
|
||||
}
|
||||
|
||||
fn print_expressions<T: GenExpr<MINIFY>>(
|
||||
&mut self,
|
||||
items: &[T],
|
||||
precedence: Precedence,
|
||||
ctx: Context,
|
||||
) {
|
||||
fn print_expressions<T: GenExpr>(&mut self, items: &[T], precedence: Precedence, ctx: Context) {
|
||||
for (index, item) in items.iter().enumerate() {
|
||||
if index != 0 {
|
||||
self.print_comma();
|
||||
|
|
@ -513,7 +507,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
}
|
||||
|
||||
// Comment related
|
||||
impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
||||
impl<'a> Codegen<'a> {
|
||||
/// Avoid issue related to rustc borrow checker .
|
||||
/// Since if you want to print a range of source code, you need to borrow the source code
|
||||
/// as immutable first, and call the [Self::print_str] which is a mutable borrow.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{CodeGenerator, CommentOptions, WhitespaceRemover};
|
||||
use oxc_codegen::{CodeGenerator, CodegenOptions, CommentOptions};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
|
||||
|
|
@ -25,7 +25,10 @@ pub fn test_minify(source_text: &str, expected: &str) {
|
|||
let source_type = SourceType::default().with_module(true).with_jsx(true);
|
||||
let allocator = Allocator::default();
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let result = WhitespaceRemover::new().build(&ret.program).source_text;
|
||||
let result = CodeGenerator::new()
|
||||
.with_options(CodegenOptions { minify: true, ..CodegenOptions::default() })
|
||||
.build(&ret.program)
|
||||
.source_text;
|
||||
assert_eq!(
|
||||
result, expected,
|
||||
"\nfor minify source {source_text}\nexpect {expected}\ngot {result:?}"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ fn codegen(source_text: &str) -> String {
|
|||
let source_type = SourceType::default().with_typescript(true).with_module(true);
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
CodeGenerator::new()
|
||||
.with_options(CodegenOptions { single_quote: true })
|
||||
.with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() })
|
||||
.build(&ret.program)
|
||||
.source_text
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,7 +170,8 @@ impl<'c, 'a: 'c> RuleFixer<'c, 'a> {
|
|||
|
||||
#[allow(clippy::unused_self)]
|
||||
pub fn codegen(self) -> CodeGenerator<'a> {
|
||||
CodeGenerator::new().with_options(CodegenOptions { single_quote: true })
|
||||
CodeGenerator::new()
|
||||
.with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() })
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self)]
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ fn run(source_text: &str, source_type: SourceType, options: Option<CompressOptio
|
|||
Compressor::new(&allocator, options).build(program);
|
||||
}
|
||||
CodeGenerator::new()
|
||||
.with_options(CodegenOptions { single_quote: true })
|
||||
.with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() })
|
||||
.build(program)
|
||||
.source_text
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub(crate) fn test(source_text: &str, expected: &str, config: InjectGlobalVariab
|
|||
.into_symbol_table_and_scope_tree();
|
||||
InjectGlobalVariables::new(&allocator, config).build(&mut symbols, &mut scopes, program);
|
||||
let result = CodeGenerator::new()
|
||||
.with_options(CodegenOptions { single_quote: true })
|
||||
.with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() })
|
||||
.build(program)
|
||||
.source_text;
|
||||
let expected = run(expected, source_type, None);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ pub(crate) fn test(source_text: &str, expected: &str, config: ReplaceGlobalDefin
|
|||
let program = allocator.alloc(ret.program);
|
||||
ReplaceGlobalDefines::new(&allocator, config).build(program);
|
||||
let result = CodeGenerator::new()
|
||||
.with_options(CodegenOptions { single_quote: true })
|
||||
.with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() })
|
||||
.build(program)
|
||||
.source_text;
|
||||
let expected = run(expected, source_type, None);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::{cell::RefCell, path::PathBuf, rc::Rc};
|
|||
use oxc::{
|
||||
allocator::Allocator,
|
||||
ast::{CommentKind, Trivias},
|
||||
codegen::{CodeGenerator, WhitespaceRemover},
|
||||
codegen::{CodeGenerator, CodegenOptions},
|
||||
diagnostics::Error,
|
||||
minifier::{CompressOptions, Minifier, MinifierOptions},
|
||||
parser::{ParseOptions, Parser},
|
||||
|
|
@ -293,11 +293,13 @@ impl Oxc {
|
|||
Minifier::new(options).build(&allocator, program);
|
||||
}
|
||||
|
||||
self.codegen_text = if minifier_options.whitespace() {
|
||||
WhitespaceRemover::new().build(program).source_text
|
||||
} else {
|
||||
CodeGenerator::new().build(program).source_text
|
||||
};
|
||||
self.codegen_text = CodeGenerator::new()
|
||||
.with_options(CodegenOptions {
|
||||
minify: minifier_options.whitespace(),
|
||||
..CodegenOptions::default()
|
||||
})
|
||||
.build(program)
|
||||
.source_text;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,8 +121,8 @@ impl<'a> TransformContext<'a> {
|
|||
self.program.borrow_mut()
|
||||
}
|
||||
|
||||
pub fn codegen<const MINIFY: bool>(&self) -> Codegen<'a, MINIFY> {
|
||||
let codegen = Codegen::<MINIFY>::new();
|
||||
pub fn codegen(&self) -> Codegen<'a> {
|
||||
let codegen = Codegen::new();
|
||||
if self.source_map {
|
||||
codegen.enable_source_map(self.file_name(), self.source_text())
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -32,5 +32,5 @@ pub fn isolated_declaration(filename: String, source_text: String) -> IsolatedDe
|
|||
pub(crate) fn build_declarations(ctx: &TransformContext<'_>) -> CodegenReturn {
|
||||
let transformed_ret = IsolatedDeclarations::new(ctx.allocator).build(&ctx.program());
|
||||
ctx.add_diagnostics(transformed_ret.errors);
|
||||
ctx.codegen::<false>().build(&transformed_ret.program)
|
||||
ctx.codegen().build(&transformed_ret.program)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,5 +108,5 @@ fn transpile(ctx: &TransformContext<'_>) -> CodegenReturn {
|
|||
.build(&mut ctx.program_mut());
|
||||
|
||||
ctx.add_diagnostics(ret.errors);
|
||||
ctx.codegen::<false>().build(&ctx.program())
|
||||
ctx.codegen().build(&ctx.program())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::{
|
|||
use flate2::{write::GzEncoder, Compression};
|
||||
use humansize::{format_size, DECIMAL};
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::WhitespaceRemover;
|
||||
use oxc_codegen::{CodeGenerator, CodegenOptions};
|
||||
use oxc_minifier::{CompressOptions, Minifier, MinifierOptions};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
|
|
@ -111,7 +111,11 @@ 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);
|
||||
let ret = Minifier::new(options).build(&allocator, program);
|
||||
WhitespaceRemover::new().with_mangler(ret.mangler).build(program).source_text
|
||||
CodeGenerator::new()
|
||||
.with_options(CodegenOptions { minify: true, ..CodegenOptions::default() })
|
||||
.with_mangler(ret.mangler)
|
||||
.build(program)
|
||||
.source_text
|
||||
}
|
||||
|
||||
fn gzip_size(s: &str) -> usize {
|
||||
|
|
|
|||
Loading…
Reference in a new issue