diff --git a/Cargo.lock b/Cargo.lock index d71509d86..aaafe3ca0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1428,13 +1428,16 @@ version = "0.2.0" dependencies = [ "oxc_allocator", "oxc_ast", + "oxc_codegen", "oxc_diagnostics", "oxc_formatter", "oxc_index", + "oxc_minifier", "oxc_parser", "oxc_semantic", "oxc_span", "oxc_syntax", + "oxc_transformer", ] [[package]] @@ -1863,15 +1866,9 @@ name = "oxc_wasm" version = "0.0.0" dependencies = [ "console_error_panic_hook", - "oxc_allocator", - "oxc_ast", - "oxc_diagnostics", - "oxc_formatter", + "oxc", "oxc_linter", - "oxc_parser", "oxc_query", - "oxc_semantic", - "oxc_span", "oxc_type_synthesis", "serde", "serde-wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index b1b454f83..a6d927940 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,16 +26,18 @@ oxc_parser = { version = "0.2.0", path = "crates/oxc_parser" } oxc_semantic = { version = "0.2.0", path = "crates/oxc_semantic" } oxc_span = { version = "0.2.0", path = "crates/oxc_span" } oxc_syntax = { version = "0.2.0", path = "crates/oxc_syntax" } +oxc_transformer = { version = "0.2.0", path = "crates/oxc_transformer" } +oxc_codegen = { version = "0.2.0", path = "crates/oxc_codegen" } # publish = false oxc_macros = { path = "crates/oxc_macros" } oxc_linter = { path = "crates/oxc_linter" } oxc_type_synthesis = { path = "crates/oxc_type_synthesis" } -oxc_resolver = { path = "crates/oxc_resolver" } oxc_query = { path = "crates/oxc_query" } oxc_linter_plugin = { path = "crates/oxc_linter_plugin" } -oxc_transformer = { path = "crates/oxc_transformer" } -oxc_codegen = { path = "crates/oxc_codegen" } + +# published by its own +oxc_resolver = { path = "crates/oxc_resolver" } oxc_tasks_common = { path = "tasks/common" } oxc_vscode = { path = "editor/vscode/server" } diff --git a/crates/oxc/Cargo.toml b/crates/oxc/Cargo.toml index 9792a71c7..2b0a7e4a7 100644 --- a/crates/oxc/Cargo.toml +++ b/crates/oxc/Cargo.toml @@ -25,9 +25,14 @@ oxc_span = { workspace = true } oxc_syntax = { workspace = true } oxc_semantic = { workspace = true, optional = true } oxc_formatter = { workspace = true, optional = true } -# oxc_minifier = { workspace = true, optional = true } +oxc_transformer = { workspace = true, optional = true } +oxc_minifier = { workspace = true, optional = true } +oxc_codegen = { workspace = true, optional = true } [features] -formatter = ["oxc_formatter"] -semantic = ["oxc_semantic"] -# minifier = ["oxc_minifier"] +serde = ["oxc_ast/serde"] +semantic = ["oxc_semantic"] +formatter = ["oxc_formatter"] +transformer = ["oxc_transformer"] +minifier = ["oxc_minifier"] +codegen = ["oxc_codegen"] diff --git a/crates/oxc/src/lib.rs b/crates/oxc/src/lib.rs index d3347dd70..657daf0cd 100644 --- a/crates/oxc/src/lib.rs +++ b/crates/oxc/src/lib.rs @@ -17,34 +17,16 @@ pub mod diagnostics { pub use oxc_diagnostics::*; } -#[cfg(feature = "formatter")] -pub mod formatter { - #[doc(inline)] - pub use oxc_formatter::*; -} - pub mod index { #[doc(inline)] pub use oxc_index::*; } -// #[cfg(feature = "minifier")] -// pub mod minifier { -// #[doc(inline)] -// pub use oxc_minifier::*; -// } - pub mod parser { #[doc(inline)] pub use oxc_parser::*; } -#[cfg(feature = "semantic")] -pub mod semantic { - #[doc(inline)] - pub use oxc_semantic::*; -} - pub mod span { #[doc(inline)] pub use oxc_span::*; @@ -54,3 +36,33 @@ pub mod syntax { #[doc(inline)] pub use oxc_syntax::*; } + +#[cfg(feature = "semantic")] +pub mod semantic { + #[doc(inline)] + pub use oxc_semantic::*; +} + +#[cfg(feature = "formatter")] +pub mod formatter { + #[doc(inline)] + pub use oxc_formatter::*; +} + +#[cfg(feature = "transformer")] +pub mod transformer { + #[doc(inline)] + pub use oxc_transformer::*; +} + +#[cfg(feature = "minifier")] +pub mod minifier { + #[doc(inline)] + pub use oxc_minifier::*; +} + +#[cfg(feature = "codegen")] +pub mod codegen { + #[doc(inline)] + pub use oxc_codegen::*; +} diff --git a/crates/oxc_codegen/Cargo.toml b/crates/oxc_codegen/Cargo.toml index 38dc071ed..f633271ad 100644 --- a/crates/oxc_codegen/Cargo.toml +++ b/crates/oxc_codegen/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "oxc_codegen" version = "0.2.0" -publish = false +publish = true authors.workspace = true description.workspace = true edition.workspace = true diff --git a/crates/oxc_minifier/src/compressor/mod.rs b/crates/oxc_minifier/src/compressor/mod.rs index c63b4ce59..aebcaade6 100644 --- a/crates/oxc_minifier/src/compressor/mod.rs +++ b/crates/oxc_minifier/src/compressor/mod.rs @@ -2,6 +2,7 @@ mod ast_util; mod fold; +mod options; mod prepass; mod util; @@ -15,61 +16,9 @@ use oxc_syntax::{ NumberBase, }; +pub use self::options::CompressOptions; use self::prepass::Prepass; -#[allow(clippy::struct_excessive_bools)] -#[derive(Debug, Clone, Copy)] -pub struct CompressOptions { - /// Various optimizations for boolean context, for example `!!a ? b : c` → `a ? b : c`. - /// - /// Default `true` - pub booleans: bool, - - /// Remove `debugger;` statements. - /// - /// Default `true` - pub drop_debugger: bool, - - /// Remove `console.*` statements. - /// - /// Default `false` - pub drop_console: bool, - - /// Attempt to evaluate constant expressions - /// - /// Default `true` - pub evaluate: bool, - - /// Join consecutive var statements. - /// - /// Default `true` - pub join_vars: bool, - - /// Optimizations for do, while and for loops when we can statically determine the condition - /// - /// Default `true` - pub loops: bool, - - /// Transforms `typeof foo == "undefined" into `foo === void 0` - /// - /// Default `true` - pub typeofs: bool, -} - -impl Default for CompressOptions { - fn default() -> Self { - Self { - booleans: true, - drop_debugger: true, - drop_console: false, - evaluate: true, - join_vars: true, - loops: true, - typeofs: true, - } - } -} - pub struct Compressor<'a> { ast: AstBuilder<'a>, options: CompressOptions, diff --git a/crates/oxc_minifier/src/compressor/options.rs b/crates/oxc_minifier/src/compressor/options.rs new file mode 100644 index 000000000..7fea7f228 --- /dev/null +++ b/crates/oxc_minifier/src/compressor/options.rs @@ -0,0 +1,78 @@ +#[allow(clippy::struct_excessive_bools)] +#[derive(Debug, Clone, Copy)] +pub struct CompressOptions { + /// Various optimizations for boolean context, for example `!!a ? b : c` → `a ? b : c`. + /// + /// Default `true` + pub booleans: bool, + + /// Remove `debugger;` statements. + /// + /// Default `true` + pub drop_debugger: bool, + + /// Remove `console.*` statements. + /// + /// Default `false` + pub drop_console: bool, + + /// Attempt to evaluate constant expressions + /// + /// Default `true` + pub evaluate: bool, + + /// Join consecutive var statements. + /// + /// Default `true` + pub join_vars: bool, + + /// Optimizations for do, while and for loops when we can statically determine the condition + /// + /// Default `true` + pub loops: bool, + + /// Transforms `typeof foo == "undefined" into `foo === void 0` + /// + /// Default `true` + pub typeofs: bool, +} + +impl Default for CompressOptions { + fn default() -> Self { + Self { + booleans: true, + drop_debugger: true, + drop_console: false, + evaluate: true, + join_vars: true, + loops: true, + typeofs: true, + } + } +} + +impl CompressOptions { + pub fn all_true() -> Self { + Self { + booleans: true, + drop_debugger: true, + drop_console: true, + evaluate: true, + join_vars: true, + loops: true, + typeofs: true, + } + } + + pub fn all_false() -> Self { + Self { + booleans: false, + drop_debugger: false, + drop_console: false, + evaluate: false, + join_vars: false, + loops: false, + typeofs: false, + } + } +} diff --git a/crates/oxc_transformer/Cargo.toml b/crates/oxc_transformer/Cargo.toml index 4558954e6..e567bbe16 100644 --- a/crates/oxc_transformer/Cargo.toml +++ b/crates/oxc_transformer/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "oxc_transformer" version = "0.2.0" -publish = false +publish = true authors.workspace = true description.workspace = true edition.workspace = true diff --git a/crates/oxc_wasm/Cargo.toml b/crates/oxc_wasm/Cargo.toml index a2b390bea..df7c4f4ce 100644 --- a/crates/oxc_wasm/Cargo.toml +++ b/crates/oxc_wasm/Cargo.toml @@ -17,20 +17,14 @@ doctest = false default = ["console_error_panic_hook"] [dependencies] -oxc_allocator = { workspace = true } -oxc_diagnostics = { workspace = true } -oxc_ast = { workspace = true, features = ["serde"] } -oxc_parser = { workspace = true } -oxc_semantic = { workspace = true } +oxc = { workspace = true, features = ["serde", "semantic", "formatter", "transformer", "minifier", "codegen"] } + oxc_linter = { workspace = true } -oxc_formatter = { workspace = true } oxc_type_synthesis = { workspace = true } -# oxc_minifier = { workspace = true } -oxc_span = { workspace = true } -oxc_query = { workspace = true } -serde_json = { workspace = true } -trustfall = { workspace = true } -serde = { workspace = true } +oxc_query = { workspace = true } +serde_json = { workspace = true } +trustfall = { workspace = true } +serde = { workspace = true } wasm-bindgen = { version = "0.2" } serde-wasm-bindgen = "0.6.0" diff --git a/crates/oxc_wasm/src/lib.rs b/crates/oxc_wasm/src/lib.rs index 9bdcf11d5..593caa50d 100644 --- a/crates/oxc_wasm/src/lib.rs +++ b/crates/oxc_wasm/src/lib.rs @@ -2,23 +2,27 @@ mod options; use std::{cell::RefCell, collections::BTreeMap, path::PathBuf, rc::Rc, sync::Arc}; -use oxc_allocator::Allocator; -use oxc_diagnostics::Error; -use oxc_formatter::{Formatter, FormatterOptions}; +use oxc::{ + allocator::Allocator, + codegen::{Codegen, CodegenOptions}, + diagnostics::Error, + formatter::{Formatter, FormatterOptions}, + minifier::{CompressOptions, Minifier, MinifierOptions}, + parser::{Parser, ParserReturn}, + semantic::{SemanticBuilder, SemanticBuilderReturn}, + span::SourceType, + transformer::{TransformOptions, TransformTarget, Transformer}, +}; use oxc_linter::{LintContext, Linter}; -// use oxc_minifier::{CompressOptions, Compressor, ManglerBuilder, Printer, PrinterOptions}; -use oxc_parser::{Parser, ParserReturn}; use oxc_query::{schema, Adapter, SCHEMA_TEXT}; -use oxc_semantic::{SemanticBuilder, SemanticBuilderReturn}; -use oxc_span::SourceType; use oxc_type_synthesis::{synthesize_program, Diagnostic as TypeCheckDiagnostic}; use serde::Serialize; use trustfall::{execute_query, TransparentValue}; use wasm_bindgen::prelude::*; use crate::options::{ - OxcFormatterOptions, OxcLinterOptions, /*OxcMinifierOptions, */ OxcParserOptions, - OxcRunOptions, OxcTypeCheckingOptions, + OxcFormatterOptions, OxcLinterOptions, OxcMinifierOptions, OxcParserOptions, OxcRunOptions, + OxcTypeCheckingOptions, }; #[wasm_bindgen(start)] @@ -40,8 +44,8 @@ pub struct Oxc { ast: JsValue, ir: JsValue, + codegen_text: String, formatted_text: String, - minified_text: String, diagnostics: RefCell>, @@ -92,9 +96,9 @@ impl Oxc { self.formatted_text.clone() } - #[wasm_bindgen(getter = minifiedText)] - pub fn minified_text(&self) -> String { - self.minified_text.clone() + #[wasm_bindgen(getter = codegenText)] + pub fn codegen_text(&self) -> String { + self.codegen_text.clone() } /// Returns Array of String @@ -152,7 +156,7 @@ impl Oxc { parser_options: &OxcParserOptions, _linter_options: &OxcLinterOptions, formatter_options: &OxcFormatterOptions, - // minifier_options: &OxcMinifierOptions, + minifier_options: &OxcMinifierOptions, _type_checking_options: &OxcTypeCheckingOptions, ) -> Result<(), serde_wasm_bindgen::Error> { self.diagnostics = RefCell::default(); @@ -200,27 +204,36 @@ impl Oxc { self.formatted_text = printed; } - // if run_options.minify() { - // let ast_lower_ret = AstLower::new(&allocator, source_text, source_type).build(program); - // let semantic = ast_lower_ret.semantic; - - // let mut printer = Printer::new(self.source_text.len(), PrinterOptions); - // let _semantic = - // Compressor::new(&allocator, semantic, CompressOptions::default()).build(hir); - // if minifier_options.mangle() { - // let mangler = ManglerBuilder::new(source_text, source_type).build(hir); - // printer.with_mangler(mangler); - // } - - // self.minified_text = printer.build(hir); - // } - if run_options.type_check() { let (diagnostics, ..) = synthesize_program(program, |_: &std::path::Path| None); - *self.type_check_diagnostics.borrow_mut() = diagnostics.get_diagnostics(); } + if run_options.transform() { + let options = TransformOptions { target: TransformTarget::ES2015, react: None }; + Transformer::new(&allocator, source_type, options).build(program); + } + + let program = allocator.alloc(program); + + if minifier_options.compress() || minifier_options.mangle() { + let options = MinifierOptions { + mangle: minifier_options.mangle(), + compress: if minifier_options.compress() { + CompressOptions::all_true() + } else { + CompressOptions::all_false() + }, + }; + Minifier::new(options).build(&allocator, program); + } + + self.codegen_text = if minifier_options.whitespace() { + Codegen::::new(source_text.len(), CodegenOptions).build(program) + } else { + Codegen::::new(source_text.len(), CodegenOptions).build(program) + }; + Ok(()) } diff --git a/crates/oxc_wasm/src/options.rs b/crates/oxc_wasm/src/options.rs index c67f30c03..c6f2c86f1 100644 --- a/crates/oxc_wasm/src/options.rs +++ b/crates/oxc_wasm/src/options.rs @@ -7,7 +7,7 @@ pub struct OxcRunOptions { syntax: bool, lint: bool, format: bool, - minify: bool, + transform: bool, type_check: bool, } @@ -49,13 +49,13 @@ impl OxcRunOptions { } #[wasm_bindgen(getter)] - pub fn minify(self) -> bool { - self.minify + pub fn transform(self) -> bool { + self.transform } #[wasm_bindgen(setter)] - pub fn set_minify(&mut self, yes: bool) { - self.minify = yes; + pub fn set_transform(&mut self, yes: bool) { + self.transform = yes; } #[wasm_bindgen(getter)] @@ -113,7 +113,9 @@ impl OxcFormatterOptions { #[wasm_bindgen] #[derive(Default, Clone, Copy)] pub struct OxcMinifierOptions { + whitespace: bool, mangle: bool, + compress: bool, } #[wasm_bindgen] @@ -123,6 +125,16 @@ impl OxcMinifierOptions { Self::default() } + #[wasm_bindgen(getter)] + pub fn whitespace(self) -> bool { + self.whitespace + } + + #[wasm_bindgen(setter)] + pub fn set_whitespace(&mut self, yes: bool) { + self.whitespace = yes; + } + #[wasm_bindgen(getter)] pub fn mangle(self) -> bool { self.mangle @@ -132,6 +144,16 @@ impl OxcMinifierOptions { pub fn set_mangle(&mut self, yes: bool) { self.mangle = yes; } + + #[wasm_bindgen(getter)] + pub fn compress(self) -> bool { + self.compress + } + + #[wasm_bindgen(setter)] + pub fn set_compress(&mut self, yes: bool) { + self.compress = yes; + } } #[wasm_bindgen] diff --git a/website/playground/index.html b/website/playground/index.html index 90ab3beeb..af8dc57ea 100644 --- a/website/playground/index.html +++ b/website/playground/index.html @@ -19,10 +19,15 @@ #editor { flex: 1; overflow-y: auto; } #panel { height: 20%; overflow-y: auto; padding: 1em; color: #d1d5da; background-color: #24292e; border-top: 1px solid #444!important; } #right { flex: 1; display:flex; flex-direction: column; min-width: 0; } - .controls { color: white; background: #24292e; padding: .8em 1em; border-bottom: 1px solid #444; display: flex; align-items: center; justify-content: space-between; } + .header { color: white; background: #24292e; border-bottom: 1px solid #444; } + .left-container { padding: .8em 1em; display: flex; align-items: center; justify-content: space-between; } + .controls { padding: .6em; } + .controls > div { padding: .2em 1em; display: flex; align-items: center; } + .controls > div > button { margin-right: 4px; } + .controls > div > label { margin-right: 8px; } .controls label { font-size: 14px; } + #duration { margin-left: auto; } #viewer { flex: 1; overflow-y: auto; } - #mangle { display: inline-flex; align-items: center } .query-button-green { background-color: #32CD59; border-color: #15c541; } .query-button-red { background-color: #e74c3c; border-color: #c0392b; } #query-results-viewer { height: 50%; border-top: 1px solid #444; display: none; } @@ -36,11 +41,11 @@
-
+
- +
@@ -49,18 +54,24 @@