mirror of
https://github.com/swc-project/swc.git
synced 2024-12-22 21:21:31 +03:00
feat(config): Make all configuration overridable (#4575)
This commit is contained in:
parent
29811e28ee
commit
7fc9bbccd9
8
.github/workflows/cargo.yml
vendored
8
.github/workflows/cargo.yml
vendored
@ -93,10 +93,14 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
- crate: better_scoped_tls
|
||||
os: ubuntu-latest
|
||||
- crate: binding_commons
|
||||
os: ubuntu-latest
|
||||
- crate: binding_core_node
|
||||
os: ubuntu-latest
|
||||
- crate: binding_core_wasm
|
||||
os: ubuntu-latest
|
||||
- crate: binding_css_node
|
||||
os: ubuntu-latest
|
||||
- crate: enum_kind
|
||||
os: ubuntu-latest
|
||||
- crate: from_variant
|
||||
@ -136,6 +140,10 @@ jobs:
|
||||
cargo hack check --feature-powerset --no-dev-deps
|
||||
- crate: swc_common
|
||||
os: windows-latest
|
||||
- crate: swc_config
|
||||
os: ubuntu-latest
|
||||
- crate: swc_config_macro
|
||||
os: ubuntu-latest
|
||||
- crate: swc_css
|
||||
os: ubuntu-latest
|
||||
- crate: swc_css_ast
|
||||
|
45
Cargo.lock
generated
45
Cargo.lock
generated
@ -60,9 +60,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.56"
|
||||
version = "1.0.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
|
||||
checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
@ -2553,9 +2553,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.136"
|
||||
version = "1.0.137"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
||||
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@ -2593,9 +2593,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.136"
|
||||
version = "1.0.137"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
|
||||
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2892,12 +2892,14 @@ dependencies = [
|
||||
"pathdiff",
|
||||
"rayon",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sourcemap",
|
||||
"swc_atoms",
|
||||
"swc_cached",
|
||||
"swc_common",
|
||||
"swc_config",
|
||||
"swc_ecma_ast",
|
||||
"swc_ecma_codegen",
|
||||
"swc_ecma_ext_transforms",
|
||||
@ -3051,6 +3053,28 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_config"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"swc_config_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_config_macro"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"pmutil",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"swc_macros_common",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_css"
|
||||
version = "0.104.2"
|
||||
@ -3271,6 +3295,7 @@ dependencies = [
|
||||
"serde",
|
||||
"swc_atoms",
|
||||
"swc_common",
|
||||
"swc_config",
|
||||
"swc_ecma_ast",
|
||||
"swc_ecma_codegen",
|
||||
"swc_ecma_parser",
|
||||
@ -3324,6 +3349,7 @@ dependencies = [
|
||||
"swc_atoms",
|
||||
"swc_cached",
|
||||
"swc_common",
|
||||
"swc_config",
|
||||
"swc_ecma_ast",
|
||||
"swc_ecma_codegen",
|
||||
"swc_ecma_parser",
|
||||
@ -3555,6 +3581,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"once_cell",
|
||||
"rayon",
|
||||
"rustc-hash",
|
||||
"serde_json",
|
||||
"swc_atoms",
|
||||
"swc_common",
|
||||
@ -3878,7 +3905,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_macros_common"
|
||||
version = "0.3.4"
|
||||
version = "0.3.5"
|
||||
dependencies = [
|
||||
"pmutil",
|
||||
"proc-macro2",
|
||||
@ -4053,9 +4080,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.86"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
||||
checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -19,7 +19,7 @@ napi = { version = "2", default-features = false, features = [
|
||||
"serde-json",
|
||||
] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
serde_json = { version = "1", features = ["unbounded_depth"] }
|
||||
swc_node_base = { path = "../swc_node_base" }
|
||||
tracing = { version = "0.1.32", features = ["release_max_level_info"] }
|
||||
tracing-subscriber = { version = "0.3.9", features = ["env-filter"] }
|
||||
|
@ -115,7 +115,7 @@ impl Task for BundleTask {
|
||||
.config
|
||||
.options
|
||||
.as_ref()
|
||||
.map(|v| v.config.minify)
|
||||
.map(|v| v.config.minify.into_bool())
|
||||
.unwrap_or(false);
|
||||
|
||||
let output = self.swc.print(
|
||||
|
@ -43,7 +43,7 @@ impl Task for PrintTask {
|
||||
.unwrap_or(SourceMapsConfig::Bool(false)),
|
||||
&Default::default(),
|
||||
None,
|
||||
options.config.minify,
|
||||
options.config.minify.into_bool(),
|
||||
None,
|
||||
)
|
||||
.convert_err()
|
||||
@ -100,7 +100,7 @@ pub fn print_sync(program: String, options: Buffer) -> napi::Result<TransformOut
|
||||
.unwrap_or(SourceMapsConfig::Bool(false)),
|
||||
&Default::default(),
|
||||
None,
|
||||
options.config.minify,
|
||||
options.config.minify.into_bool(),
|
||||
None,
|
||||
)
|
||||
.convert_err()
|
||||
|
@ -48,7 +48,7 @@ impl Task for TransformTask {
|
||||
|
||||
try_with(
|
||||
self.c.cm.clone(),
|
||||
!options.config.error.filename,
|
||||
!options.config.error.filename.into_bool(),
|
||||
|handler| {
|
||||
self.c.run(|| match &self.input {
|
||||
Input::Program(ref s) => {
|
||||
@ -130,25 +130,29 @@ pub fn transform_sync(s: String, is_module: bool, opts: Buffer) -> napi::Result<
|
||||
options.config.adjust(Path::new(&options.filename));
|
||||
}
|
||||
|
||||
try_with(c.cm.clone(), !options.config.error.filename, |handler| {
|
||||
c.run(|| {
|
||||
if is_module {
|
||||
let program: Program =
|
||||
deserialize_json(s.as_str()).context("failed to deserialize Program")?;
|
||||
c.process_js(handler, program, &options)
|
||||
} else {
|
||||
let fm = c.cm.new_source_file(
|
||||
if options.filename.is_empty() {
|
||||
FileName::Anon
|
||||
} else {
|
||||
FileName::Real(options.filename.clone().into())
|
||||
},
|
||||
s,
|
||||
);
|
||||
c.process_js_file(fm, handler, &options)
|
||||
}
|
||||
})
|
||||
})
|
||||
try_with(
|
||||
c.cm.clone(),
|
||||
!options.config.error.filename.into_bool(),
|
||||
|handler| {
|
||||
c.run(|| {
|
||||
if is_module {
|
||||
let program: Program =
|
||||
deserialize_json(s.as_str()).context("failed to deserialize Program")?;
|
||||
c.process_js(handler, program, &options)
|
||||
} else {
|
||||
let fm = c.cm.new_source_file(
|
||||
if options.filename.is_empty() {
|
||||
FileName::Anon
|
||||
} else {
|
||||
FileName::Real(options.filename.clone().into())
|
||||
},
|
||||
s,
|
||||
);
|
||||
c.process_js_file(fm, handler, &options)
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
.convert_err()
|
||||
}
|
||||
|
||||
@ -189,17 +193,21 @@ pub fn transform_file_sync(
|
||||
options.config.adjust(Path::new(&options.filename));
|
||||
}
|
||||
|
||||
try_with(c.cm.clone(), !options.config.error.filename, |handler| {
|
||||
c.run(|| {
|
||||
if is_module {
|
||||
let program: Program =
|
||||
deserialize_json(s.as_str()).context("failed to deserialize Program")?;
|
||||
c.process_js(handler, program, &options)
|
||||
} else {
|
||||
let fm = c.cm.load_file(Path::new(&s)).expect("failed to load file");
|
||||
c.process_js_file(fm, handler, &options)
|
||||
}
|
||||
})
|
||||
})
|
||||
try_with(
|
||||
c.cm.clone(),
|
||||
!options.config.error.filename.into_bool(),
|
||||
|handler| {
|
||||
c.run(|| {
|
||||
if is_module {
|
||||
let program: Program =
|
||||
deserialize_json(s.as_str()).context("failed to deserialize Program")?;
|
||||
c.process_js(handler, program, &options)
|
||||
} else {
|
||||
let fm = c.cm.load_file(Path::new(&s)).expect("failed to load file");
|
||||
c.process_js_file(fm, handler, &options)
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
.convert_err()
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ pub fn print_sync(s: JsValue, opts: JsValue) -> Result<JsValue, JsValue> {
|
||||
.unwrap_or(SourceMapsConfig::Bool(false)),
|
||||
&Default::default(),
|
||||
None,
|
||||
opts.config.minify,
|
||||
opts.config.minify.into(),
|
||||
None,
|
||||
)
|
||||
.context("failed to print code")?;
|
||||
|
@ -30,7 +30,7 @@ napi-derive = { version = "2", default-features = false, features = [
|
||||
node_macro_deps = { path = "../node_macro_deps" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
swc_common = { path = "../swc_common", features = ["perf"] }
|
||||
swc_common = { path = "../swc_common", features = ["perf", "sourcemap"] }
|
||||
swc_css_ast = { path = "../swc_css_ast" }
|
||||
swc_css_codegen = { path = "../swc_css_codegen" }
|
||||
swc_css_minifier = { path = "../swc_css_minifier" }
|
||||
|
@ -30,56 +30,58 @@ anyhow = "1"
|
||||
base64 = "0.13.0"
|
||||
dashmap = "5.1.0"
|
||||
either = "1"
|
||||
indexmap = {version = "1", features = ["serde"]}
|
||||
indexmap = { version = "1", features = ["serde"] }
|
||||
json_comments = "0.2.0"
|
||||
lru = "0.7.1"
|
||||
once_cell = "1.10.0"
|
||||
parking_lot = "0.12.0"
|
||||
pathdiff = "0.2.0"
|
||||
regex = "1"
|
||||
serde = {version = "1", features = ["derive"]}
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
sourcemap = "6"
|
||||
swc_atoms = {version = "0.2", path = "../swc_atoms"}
|
||||
swc_cached = {version = "0.1.0", path = "../swc_cached"}
|
||||
swc_common = {version = "0.17.23", path = "../swc_common", features = [
|
||||
swc_atoms = { version = "0.2", path = "../swc_atoms" }
|
||||
swc_cached = { version = "0.1.0", path = "../swc_cached" }
|
||||
swc_common = { version = "0.17.23", path = "../swc_common", features = [
|
||||
"sourcemap",
|
||||
"concurrent",
|
||||
"parking_lot",
|
||||
]}
|
||||
swc_ecma_ast = {version = "0.77.0", path = "../swc_ecma_ast"}
|
||||
swc_ecma_codegen = {version = "0.106.0", path = "../swc_ecma_codegen"}
|
||||
swc_ecma_ext_transforms = {version = "0.69.0", path = "../swc_ecma_ext_transforms"}
|
||||
swc_ecma_lints = {version = "0.38.0", path = "../swc_ecma_lints"}
|
||||
swc_ecma_loader = {version = "0.29.0", path = "../swc_ecma_loader", features = [
|
||||
] }
|
||||
swc_config = { version = "0.1.0", path = "../swc_config" }
|
||||
swc_ecma_ast = { version = "0.77.0", path = "../swc_ecma_ast" }
|
||||
swc_ecma_codegen = { version = "0.106.0", path = "../swc_ecma_codegen" }
|
||||
swc_ecma_ext_transforms = { version = "0.69.0", path = "../swc_ecma_ext_transforms" }
|
||||
swc_ecma_lints = { version = "0.38.0", path = "../swc_ecma_lints" }
|
||||
swc_ecma_loader = { version = "0.29.0", path = "../swc_ecma_loader", features = [
|
||||
"cache",
|
||||
"node",
|
||||
"tsc",
|
||||
]}
|
||||
swc_ecma_minifier = {version = "0.110.0", path = "../swc_ecma_minifier"}
|
||||
swc_ecma_parser = {version = "0.103.0", path = "../swc_ecma_parser"}
|
||||
swc_ecma_preset_env = {version = "0.125.0", path = "../swc_ecma_preset_env"}
|
||||
swc_ecma_transforms = {version = "0.150.0", path = "../swc_ecma_transforms", features = [
|
||||
] }
|
||||
swc_ecma_minifier = { version = "0.110.0", path = "../swc_ecma_minifier" }
|
||||
swc_ecma_parser = { version = "0.103.0", path = "../swc_ecma_parser" }
|
||||
swc_ecma_preset_env = { version = "0.125.0", path = "../swc_ecma_preset_env" }
|
||||
swc_ecma_transforms = { version = "0.150.0", path = "../swc_ecma_transforms", features = [
|
||||
"compat",
|
||||
"module",
|
||||
"optimization",
|
||||
"proposal",
|
||||
"react",
|
||||
"typescript",
|
||||
]}
|
||||
swc_ecma_transforms_base = {version = "0.82.0", path = "../swc_ecma_transforms_base"}
|
||||
swc_ecma_transforms_compat = {version = "0.96.0", path = "../swc_ecma_transforms_compat"}
|
||||
swc_ecma_transforms_optimization = {version = "0.120.0", path = "../swc_ecma_transforms_optimization"}
|
||||
swc_ecma_utils = {version = "0.83.0", path = "../swc_ecma_utils"}
|
||||
swc_ecma_visit = {version = "0.63.0", path = "../swc_ecma_visit"}
|
||||
swc_ecmascript = {version = "0.153.0", path = "../swc_ecmascript"}
|
||||
swc_error_reporters = {version = "0.1.2", path = "../swc_error_reporters"}
|
||||
swc_node_comments = {version = "0.4.0", path = "../swc_node_comments"}
|
||||
swc_plugin_proxy = {version = "0.2.1", path = "../swc_plugin_proxy", optional = true}
|
||||
swc_plugin_runner = {version = "0.54.0", path = "../swc_plugin_runner", optional = true, default-features = false}
|
||||
swc_timer = {version = "0.5.0", path = "../swc_timer"}
|
||||
swc_visit = {version = "0.3.0", path = "../swc_visit"}
|
||||
] }
|
||||
swc_ecma_transforms_base = { version = "0.82.0", path = "../swc_ecma_transforms_base" }
|
||||
swc_ecma_transforms_compat = { version = "0.96.0", path = "../swc_ecma_transforms_compat" }
|
||||
swc_ecma_transforms_optimization = { version = "0.120.0", path = "../swc_ecma_transforms_optimization" }
|
||||
swc_ecma_utils = { version = "0.83.0", path = "../swc_ecma_utils" }
|
||||
swc_ecma_visit = { version = "0.63.0", path = "../swc_ecma_visit" }
|
||||
swc_ecmascript = { version = "0.153.0", path = "../swc_ecmascript" }
|
||||
swc_error_reporters = { version = "0.1.2", path = "../swc_error_reporters" }
|
||||
swc_node_comments = { version = "0.4.0", path = "../swc_node_comments" }
|
||||
swc_plugin_proxy = { version = "0.2.1", path = "../swc_plugin_proxy", optional = true }
|
||||
swc_plugin_runner = { version = "0.54.0", path = "../swc_plugin_runner", optional = true, default-features = false }
|
||||
swc_timer = { version = "0.5.0", path = "../swc_timer" }
|
||||
swc_visit = { version = "0.3.0", path = "../swc_visit" }
|
||||
tracing = "0.1.32"
|
||||
rustc-hash = "1.1.0"
|
||||
|
||||
[dependencies.napi-derive]
|
||||
default-features = false
|
||||
@ -97,11 +99,11 @@ version = "2.0.0"
|
||||
ansi_term = "0.12"
|
||||
criterion = "0.3"
|
||||
rayon = "1.5.1"
|
||||
swc_ecma_lints = {version = "0.38.0", path = "../swc_ecma_lints", features = [
|
||||
swc_ecma_lints = { version = "0.38.0", path = "../swc_ecma_lints", features = [
|
||||
"non_critical_lints",
|
||||
]}
|
||||
swc_node_base = {version = "0.5.0", path = "../swc_node_base"}
|
||||
testing = {version = "0.19.0", path = "../testing"}
|
||||
] }
|
||||
swc_node_base = { version = "0.5.0", path = "../swc_node_base" }
|
||||
testing = { version = "0.19.0", path = "../testing" }
|
||||
walkdir = "2"
|
||||
|
||||
[[example]]
|
||||
|
@ -4,7 +4,7 @@ extern crate swc_node_base;
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion};
|
||||
use swc::{config::JsMinifyOptions, try_with_handler};
|
||||
use swc::{config::JsMinifyOptions, try_with_handler, BoolOrDataConfig};
|
||||
use swc_common::{FilePathMapping, SourceMap};
|
||||
|
||||
fn mk() -> swc::Compiler {
|
||||
@ -35,8 +35,8 @@ fn bench_minify(b: &mut Bencher, filename: &str) {
|
||||
fm,
|
||||
handler,
|
||||
&JsMinifyOptions {
|
||||
compress: true.into(),
|
||||
mangle: true.into(),
|
||||
compress: BoolOrDataConfig::from_bool(true),
|
||||
mangle: BoolOrDataConfig::from_bool(true),
|
||||
format: Default::default(),
|
||||
ecma: Default::default(),
|
||||
keep_classnames: Default::default(),
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::{path::Path, sync::Arc};
|
||||
|
||||
use anyhow::Context;
|
||||
use swc::{self, config::JsMinifyOptions, try_with_handler, HandlerOpts};
|
||||
use swc::{self, config::JsMinifyOptions, try_with_handler, BoolOrDataConfig, HandlerOpts};
|
||||
use swc_common::SourceMap;
|
||||
|
||||
fn main() {
|
||||
@ -23,8 +23,8 @@ fn main() {
|
||||
fm,
|
||||
handler,
|
||||
&JsMinifyOptions {
|
||||
compress: true.into(),
|
||||
mangle: true.into(),
|
||||
compress: BoolOrDataConfig::from_bool(true),
|
||||
mangle: BoolOrDataConfig::from_bool(true),
|
||||
format: Default::default(),
|
||||
ecma: Default::default(),
|
||||
keep_classnames: Default::default(),
|
||||
|
@ -1,7 +1,8 @@
|
||||
use std::{cell::RefCell, collections::HashMap, path::PathBuf, rc::Rc, sync::Arc};
|
||||
use std::{cell::RefCell, path::PathBuf, rc::Rc, sync::Arc};
|
||||
|
||||
use compat::{es2015::regenerator, es2020::export_namespace_from};
|
||||
use either::Either;
|
||||
use rustc_hash::FxHashMap;
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::{
|
||||
chain,
|
||||
@ -21,9 +22,7 @@ use swc_ecma_transforms::{
|
||||
};
|
||||
use swc_ecma_visit::{as_folder, noop_visit_mut_type, VisitMut};
|
||||
|
||||
use crate::config::{
|
||||
util::BoolOrObject, CompiledPaths, GlobalPassOption, JsMinifyOptions, ModuleConfig,
|
||||
};
|
||||
use crate::config::{CompiledPaths, GlobalPassOption, JsMinifyOptions, ModuleConfig};
|
||||
|
||||
/// Builder is used to create a high performance `Compiler`.
|
||||
pub struct PassBuilder<'a, 'b, P: swc_ecma_visit::Fold> {
|
||||
@ -124,7 +123,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
|
||||
|
||||
pub fn const_modules(
|
||||
self,
|
||||
globals: HashMap<JsWord, HashMap<JsWord, String>>,
|
||||
globals: FxHashMap<JsWord, FxHashMap<JsWord, String>>,
|
||||
) -> PassBuilder<'a, 'b, impl swc_ecma_visit::Fold> {
|
||||
let cm = self.cm.clone();
|
||||
self.then(const_modules(cm, globals))
|
||||
@ -296,7 +295,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
|
||||
let is_mangler_enabled = self
|
||||
.minify
|
||||
.as_ref()
|
||||
.map(|v| matches!(v.mangle, BoolOrObject::Bool(true) | BoolOrObject::Obj(_)))
|
||||
.map(|v| v.mangle.is_obj() || v.mangle.is_true())
|
||||
.unwrap_or(false);
|
||||
|
||||
let module_scope = Rc::new(RefCell::new(Scope::default()));
|
||||
@ -351,17 +350,30 @@ impl VisitMut for MinifierPass {
|
||||
fn visit_mut_module(&mut self, m: &mut Module) {
|
||||
if let Some(options) = &self.options {
|
||||
let opts = MinifyOptions {
|
||||
compress: options.compress.clone().into_obj().map(|mut v| {
|
||||
if v.const_to_let.is_none() {
|
||||
v.const_to_let = Some(true);
|
||||
}
|
||||
if v.toplevel.is_none() {
|
||||
v.toplevel = Some(TerserTopLevelOptions::Bool(true));
|
||||
}
|
||||
compress: options
|
||||
.compress
|
||||
.clone()
|
||||
.unwrap_as_option(|default| match default {
|
||||
Some(true) => Some(Default::default()),
|
||||
_ => None,
|
||||
})
|
||||
.map(|mut v| {
|
||||
if v.const_to_let.is_none() {
|
||||
v.const_to_let = Some(true);
|
||||
}
|
||||
if v.toplevel.is_none() {
|
||||
v.toplevel = Some(TerserTopLevelOptions::Bool(true));
|
||||
}
|
||||
|
||||
v.into_config(self.cm.clone())
|
||||
}),
|
||||
mangle: options.mangle.clone().into_obj(),
|
||||
v.into_config(self.cm.clone())
|
||||
}),
|
||||
mangle: options
|
||||
.mangle
|
||||
.clone()
|
||||
.unwrap_as_option(|default| match default {
|
||||
Some(true) => Some(Default::default()),
|
||||
_ => None,
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
@ -3,7 +3,6 @@ use std::{
|
||||
cell::RefCell,
|
||||
collections::{HashMap, HashSet},
|
||||
env, fmt,
|
||||
hash::BuildHasher,
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc as RustRc,
|
||||
sync::Arc,
|
||||
@ -15,6 +14,7 @@ use dashmap::DashMap;
|
||||
use either::Either;
|
||||
use indexmap::IndexMap;
|
||||
use once_cell::sync::Lazy;
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::{
|
||||
de::{Unexpected, Visitor},
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
@ -28,6 +28,10 @@ use swc_common::{
|
||||
errors::Handler,
|
||||
FileName, Mark, SourceMap, SyntaxContext,
|
||||
};
|
||||
use swc_config::{
|
||||
config_types::{BoolConfig, BoolOr, BoolOrDataConfig},
|
||||
merge::Merge,
|
||||
};
|
||||
use swc_ecma_ast::{EsVersion, Expr, Program};
|
||||
use swc_ecma_ext_transforms::jest;
|
||||
use swc_ecma_lints::{
|
||||
@ -40,7 +44,7 @@ use swc_ecma_loader::{
|
||||
};
|
||||
use swc_ecma_minifier::option::{
|
||||
terser::{TerserCompressorOptions, TerserEcmaVersion, TerserTopLevelOptions},
|
||||
MangleOptions, ManglePropertiesOptions,
|
||||
MangleOptions,
|
||||
};
|
||||
#[allow(deprecated)]
|
||||
pub use swc_ecma_parser::JscTarget;
|
||||
@ -61,7 +65,6 @@ use swc_ecma_transforms_compat::es2015::regenerator;
|
||||
use swc_ecma_transforms_optimization::{inline_globals2, GlobalExprMap};
|
||||
use swc_ecma_visit::{Fold, VisitMutWith};
|
||||
|
||||
use self::util::BoolOrObject;
|
||||
use crate::{
|
||||
builder::PassBuilder,
|
||||
dropped_comments_preserver::dropped_comments_preserver,
|
||||
@ -71,7 +74,6 @@ use crate::{
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
pub mod util;
|
||||
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
pub enum IsModule {
|
||||
@ -269,7 +271,6 @@ impl Options {
|
||||
output_path: Option<&Path>,
|
||||
source_file_name: Option<String>,
|
||||
handler: &Handler,
|
||||
is_module: IsModule,
|
||||
config: Option<Config>,
|
||||
comments: Option<&'a SingleThreadedComments>,
|
||||
custom_before_pass: impl FnOnce(&Program) -> P,
|
||||
@ -277,11 +278,12 @@ impl Options {
|
||||
where
|
||||
P: 'a + swc_ecma_visit::Fold,
|
||||
{
|
||||
let mut config = config.unwrap_or_default();
|
||||
config.merge(&self.config);
|
||||
let mut cfg = self.config.clone();
|
||||
cfg.merge(config.unwrap_or_default());
|
||||
let is_module = self.is_module;
|
||||
|
||||
let mut source_maps = self.source_maps.clone();
|
||||
source_maps.merge(&config.source_maps);
|
||||
source_maps.merge(cfg.source_maps.clone());
|
||||
|
||||
let JscConfig {
|
||||
assumptions,
|
||||
@ -298,7 +300,11 @@ impl Options {
|
||||
lints,
|
||||
preserve_all_comments,
|
||||
..
|
||||
} = config.jsc;
|
||||
} = cfg.jsc;
|
||||
let loose = loose.into_bool();
|
||||
let preserve_all_comments = preserve_all_comments.into_bool();
|
||||
let keep_class_names = keep_class_names.into_bool();
|
||||
let external_helpers = external_helpers.into_bool();
|
||||
|
||||
let mut assumptions = assumptions.unwrap_or_else(|| {
|
||||
if loose {
|
||||
@ -338,7 +344,10 @@ impl Options {
|
||||
js_minify = js_minify.map(|c| {
|
||||
let compress = c
|
||||
.compress
|
||||
.into_obj()
|
||||
.unwrap_as_option(|default| match default {
|
||||
Some(true) => Some(Default::default()),
|
||||
_ => None,
|
||||
})
|
||||
.map(|mut c| {
|
||||
if c.toplevel.is_none() {
|
||||
c.toplevel = Some(TerserTopLevelOptions::Bool(true));
|
||||
@ -346,19 +355,22 @@ impl Options {
|
||||
|
||||
c
|
||||
})
|
||||
.map(BoolOrObject::Obj)
|
||||
.unwrap_or(BoolOrObject::Bool(false));
|
||||
.map(BoolOrDataConfig::from_obj)
|
||||
.unwrap_or_else(|| BoolOrDataConfig::from_bool(false));
|
||||
|
||||
let mangle = c
|
||||
.mangle
|
||||
.into_obj()
|
||||
.unwrap_as_option(|default| match default {
|
||||
Some(true) => Some(Default::default()),
|
||||
_ => None,
|
||||
})
|
||||
.map(|mut c| {
|
||||
c.top_level = true;
|
||||
|
||||
c
|
||||
})
|
||||
.map(BoolOrObject::Obj)
|
||||
.unwrap_or(BoolOrObject::Bool(false));
|
||||
.map(BoolOrDataConfig::from_obj)
|
||||
.unwrap_or_else(|| BoolOrDataConfig::from_bool(false));
|
||||
|
||||
JsMinifyOptions {
|
||||
compress,
|
||||
@ -371,9 +383,21 @@ impl Options {
|
||||
let regenerator = transform.regenerator.clone();
|
||||
|
||||
let preserve_comments = if preserve_all_comments {
|
||||
Some(BoolOrObject::from(true))
|
||||
BoolOr::Bool(true)
|
||||
} else {
|
||||
js_minify.as_ref().map(|v| v.format.comments.clone())
|
||||
js_minify
|
||||
.as_ref()
|
||||
.map(|v| match v.format.comments.clone().into_inner() {
|
||||
Some(v) => v,
|
||||
None => BoolOr::Bool(false),
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
BoolOr::Data(if cfg.minify.into_bool() {
|
||||
JsMinifyCommentOption::PreserveSomeComments
|
||||
} else {
|
||||
JsMinifyCommentOption::PreserveAllComments
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
if syntax.typescript() {
|
||||
@ -397,7 +421,10 @@ impl Options {
|
||||
}
|
||||
};
|
||||
|
||||
let enable_simplifier = optimizer.as_ref().map(|v| v.simplify).unwrap_or_default();
|
||||
let enable_simplifier = optimizer
|
||||
.as_ref()
|
||||
.map(|v| v.simplify.into_bool())
|
||||
.unwrap_or_default();
|
||||
|
||||
let optimization = {
|
||||
if let Some(opts) = optimizer.and_then(|o| o.globals) {
|
||||
@ -439,18 +466,18 @@ impl Options {
|
||||
Some(hygiene::Config { keep_class_names })
|
||||
})
|
||||
.fixer(!self.disable_fixer)
|
||||
.preset_env(config.env)
|
||||
.preset_env(cfg.env)
|
||||
.regenerator(regenerator)
|
||||
.finalize(
|
||||
base_url,
|
||||
paths.into_iter().collect(),
|
||||
base,
|
||||
syntax,
|
||||
config.module,
|
||||
cfg.module,
|
||||
comments,
|
||||
);
|
||||
|
||||
let keep_import_assertions = experimental.keep_import_assertions;
|
||||
let keep_import_assertions = experimental.keep_import_assertions.into_bool();
|
||||
|
||||
// Embedded runtime plugin target, based on assumption we have
|
||||
// 1. filesystem access for the cache
|
||||
@ -570,15 +597,15 @@ impl Options {
|
||||
|
||||
Ok(BuiltInput {
|
||||
program,
|
||||
minify: config.minify,
|
||||
minify: cfg.minify.into_bool(),
|
||||
pass,
|
||||
external_helpers,
|
||||
syntax,
|
||||
target: es_version,
|
||||
is_module,
|
||||
source_maps: source_maps.unwrap_or(SourceMapsConfig::Bool(false)),
|
||||
inline_sources_content: config.inline_sources_content,
|
||||
input_source_map: config.input_source_map.clone(),
|
||||
inline_sources_content: cfg.inline_sources_content.into_bool(),
|
||||
input_source_map: cfg.input_source_map.clone().unwrap_or_default(),
|
||||
output_path: output_path.map(|v| v.to_path_buf()),
|
||||
source_file_name,
|
||||
comments: comments.cloned(),
|
||||
@ -648,17 +675,8 @@ impl Default for Rc {
|
||||
exclude: Some(FileMatcher::Regex("\\.tsx?$".into())),
|
||||
jsc: JscConfig {
|
||||
syntax: Some(Default::default()),
|
||||
transform: None,
|
||||
external_helpers: false,
|
||||
target: Default::default(),
|
||||
loose: false,
|
||||
keep_class_names: false,
|
||||
..Default::default()
|
||||
},
|
||||
module: None,
|
||||
minify: false,
|
||||
source_maps: None,
|
||||
input_source_map: InputSourceMap::default(),
|
||||
..Default::default()
|
||||
},
|
||||
Config {
|
||||
@ -670,17 +688,8 @@ impl Default for Rc {
|
||||
tsx: true,
|
||||
..Default::default()
|
||||
})),
|
||||
transform: None,
|
||||
external_helpers: false,
|
||||
target: Default::default(),
|
||||
loose: false,
|
||||
keep_class_names: false,
|
||||
..Default::default()
|
||||
},
|
||||
module: None,
|
||||
minify: false,
|
||||
source_maps: None,
|
||||
input_source_map: InputSourceMap::default(),
|
||||
..Default::default()
|
||||
},
|
||||
Config {
|
||||
@ -692,17 +701,8 @@ impl Default for Rc {
|
||||
tsx: false,
|
||||
..Default::default()
|
||||
})),
|
||||
transform: None,
|
||||
external_helpers: false,
|
||||
target: Default::default(),
|
||||
loose: false,
|
||||
keep_class_names: false,
|
||||
..Default::default()
|
||||
},
|
||||
module: None,
|
||||
minify: false,
|
||||
source_maps: None,
|
||||
input_source_map: InputSourceMap::default(),
|
||||
..Default::default()
|
||||
},
|
||||
])
|
||||
@ -747,7 +747,7 @@ impl Rc {
|
||||
}
|
||||
|
||||
/// A single object in the `.swcrc` file
|
||||
#[derive(Debug, Default, Clone, Deserialize)]
|
||||
#[derive(Debug, Default, Clone, Deserialize, Merge)]
|
||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||
pub struct Config {
|
||||
#[serde(default)]
|
||||
@ -766,17 +766,17 @@ pub struct Config {
|
||||
pub module: Option<ModuleConfig>,
|
||||
|
||||
#[serde(default)]
|
||||
pub minify: bool,
|
||||
pub minify: BoolConfig<false>,
|
||||
|
||||
#[serde(default)]
|
||||
pub input_source_map: InputSourceMap,
|
||||
pub input_source_map: Option<InputSourceMap>,
|
||||
|
||||
/// Possible values are: `'inline'`, `true`, `false`.
|
||||
#[serde(default)]
|
||||
pub source_maps: Option<SourceMapsConfig>,
|
||||
|
||||
#[serde(default = "true_by_default")]
|
||||
pub inline_sources_content: bool,
|
||||
#[serde(default)]
|
||||
pub inline_sources_content: BoolConfig<true>,
|
||||
|
||||
#[serde(default)]
|
||||
pub error: ErrorConfig,
|
||||
@ -790,10 +790,10 @@ pub struct Config {
|
||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||
pub struct JsMinifyOptions {
|
||||
#[serde(default)]
|
||||
pub compress: BoolOrObject<TerserCompressorOptions>,
|
||||
pub compress: BoolOrDataConfig<TerserCompressorOptions>,
|
||||
|
||||
#[serde(default)]
|
||||
pub mangle: BoolOrObject<MangleOptions>,
|
||||
pub mangle: BoolOrDataConfig<MangleOptions>,
|
||||
|
||||
#[serde(default)]
|
||||
pub format: JsMinifyFormatOptions,
|
||||
@ -817,7 +817,7 @@ pub struct JsMinifyOptions {
|
||||
pub toplevel: bool,
|
||||
|
||||
#[serde(default)]
|
||||
pub source_map: BoolOrObject<TerserSourceMapOption>,
|
||||
pub source_map: BoolOrDataConfig<TerserSourceMapOption>,
|
||||
|
||||
#[serde(default)]
|
||||
pub output_path: Option<String>,
|
||||
@ -864,7 +864,7 @@ pub struct JsMinifyFormatOptions {
|
||||
pub braces: bool,
|
||||
|
||||
#[serde(default)]
|
||||
pub comments: BoolOrObject<JsMinifyCommentOption>,
|
||||
pub comments: BoolOrDataConfig<JsMinifyCommentOption>,
|
||||
|
||||
/// Not implemented yet.
|
||||
#[serde(default)]
|
||||
@ -872,7 +872,7 @@ pub struct JsMinifyFormatOptions {
|
||||
|
||||
/// Not implemented yet.
|
||||
#[serde(default, alias = "indent_level")]
|
||||
pub indent_level: usize,
|
||||
pub indent_level: Option<usize>,
|
||||
|
||||
/// Not implemented yet.
|
||||
#[serde(default, alias = "indent_start")]
|
||||
@ -892,7 +892,7 @@ pub struct JsMinifyFormatOptions {
|
||||
|
||||
/// Not implemented yet.
|
||||
#[serde(default, alias = "max_line_len")]
|
||||
pub max_line_len: BoolOrObject<usize>,
|
||||
pub max_line_len: usize,
|
||||
|
||||
/// Not implemented yet.
|
||||
#[serde(default)]
|
||||
@ -1054,13 +1054,13 @@ pub struct BuiltInput<P: swc_ecma_visit::Fold> {
|
||||
pub source_file_name: Option<String>,
|
||||
|
||||
pub comments: Option<SingleThreadedComments>,
|
||||
pub preserve_comments: Option<BoolOrObject<JsMinifyCommentOption>>,
|
||||
pub preserve_comments: BoolOr<JsMinifyCommentOption>,
|
||||
|
||||
pub inline_sources_content: bool,
|
||||
}
|
||||
|
||||
/// `jsc` in `.swcrc`.
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, Merge)]
|
||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||
pub struct JscConfig {
|
||||
#[serde(default)]
|
||||
@ -1073,16 +1073,16 @@ pub struct JscConfig {
|
||||
pub transform: Option<TransformConfig>,
|
||||
|
||||
#[serde(default)]
|
||||
pub external_helpers: bool,
|
||||
pub external_helpers: BoolConfig<false>,
|
||||
|
||||
#[serde(default)]
|
||||
pub target: Option<EsVersion>,
|
||||
|
||||
#[serde(default)]
|
||||
pub loose: bool,
|
||||
pub loose: BoolConfig<false>,
|
||||
|
||||
#[serde(default)]
|
||||
pub keep_class_names: bool,
|
||||
pub keep_class_names: BoolConfig<false>,
|
||||
|
||||
#[serde(default)]
|
||||
pub base_url: PathBuf,
|
||||
@ -1100,11 +1100,11 @@ pub struct JscConfig {
|
||||
pub lints: LintConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub preserve_all_comments: bool,
|
||||
pub preserve_all_comments: BoolConfig<false>,
|
||||
}
|
||||
|
||||
/// `jsc.experimental` in `.swcrc`
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, Merge)]
|
||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||
pub struct JscExperimental {
|
||||
/// This requires cargo feature `plugin`.
|
||||
@ -1112,7 +1112,7 @@ pub struct JscExperimental {
|
||||
pub plugins: Option<Vec<PluginConfig>>,
|
||||
/// If true, keeps import assertions in the output.
|
||||
#[serde(default)]
|
||||
pub keep_import_assertions: bool,
|
||||
pub keep_import_assertions: BoolConfig<false>,
|
||||
/// Location where swc may stores its intermediate cache.
|
||||
/// Currently this is only being used for wasm plugin's bytecache.
|
||||
/// Path should be absolute directory, which will be created if not exist.
|
||||
@ -1122,19 +1122,6 @@ pub struct JscExperimental {
|
||||
pub cache_root: Option<String>,
|
||||
}
|
||||
|
||||
impl Merge for JscExperimental {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
if self.plugins.is_none() {
|
||||
self.plugins = from.plugins.clone();
|
||||
}
|
||||
if self.cache_root.is_none() {
|
||||
self.cache_root = from.cache_root.clone();
|
||||
}
|
||||
|
||||
self.keep_import_assertions |= from.keep_import_assertions;
|
||||
}
|
||||
}
|
||||
|
||||
/// `paths` section of `tsconfig.json`.
|
||||
pub type Paths = IndexMap<String, Vec<String>, ahash::RandomState>;
|
||||
pub(crate) type CompiledPaths = Vec<(String, Vec<String>)>;
|
||||
@ -1296,21 +1283,21 @@ pub struct HiddenTransformConfig {
|
||||
pub jest: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, Merge)]
|
||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||
pub struct ConstModulesConfig {
|
||||
#[serde(default)]
|
||||
pub globals: HashMap<JsWord, HashMap<JsWord, String>>,
|
||||
pub globals: FxHashMap<JsWord, FxHashMap<JsWord, String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, Merge)]
|
||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||
pub struct OptimizerConfig {
|
||||
#[serde(default)]
|
||||
pub globals: Option<GlobalPassOption>,
|
||||
|
||||
#[serde(default = "true_by_default")]
|
||||
pub simplify: bool,
|
||||
#[serde(default)]
|
||||
pub simplify: BoolConfig<true>,
|
||||
|
||||
#[serde(default)]
|
||||
pub jsonify: Option<JsonifyOption>,
|
||||
@ -1327,15 +1314,10 @@ fn default_jsonify_min_cost() -> usize {
|
||||
1024
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, Merge)]
|
||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||
pub struct ErrorConfig {
|
||||
pub filename: bool,
|
||||
}
|
||||
impl Default for ErrorConfig {
|
||||
fn default() -> Self {
|
||||
ErrorConfig { filename: true }
|
||||
}
|
||||
pub filename: BoolConfig<true>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
@ -1538,284 +1520,6 @@ fn default_env_name() -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Merge {
|
||||
/// Apply overrides from `from`
|
||||
fn merge(&mut self, from: &Self);
|
||||
}
|
||||
|
||||
impl<T: Clone> Merge for Option<T>
|
||||
where
|
||||
T: Merge,
|
||||
{
|
||||
fn merge(&mut self, from: &Option<T>) {
|
||||
if let Some(ref from) = *from {
|
||||
match *self {
|
||||
Some(ref mut v) => v.merge(from),
|
||||
None => *self = Some(from.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for Config {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
self.jsc.merge(&from.jsc);
|
||||
self.module.merge(&from.module);
|
||||
self.minify.merge(&from.minify);
|
||||
self.env.merge(&from.env);
|
||||
self.source_maps.merge(&from.source_maps);
|
||||
self.input_source_map.merge(&from.input_source_map);
|
||||
self.inline_sources_content
|
||||
.merge(&from.inline_sources_content);
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for JsMinifyOptions {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
self.compress.merge(&from.compress);
|
||||
self.mangle.merge(&from.mangle);
|
||||
self.format.merge(&from.format);
|
||||
self.ecma.merge(&from.ecma);
|
||||
self.keep_classnames |= from.keep_classnames;
|
||||
self.keep_fnames |= from.keep_fnames;
|
||||
self.safari10 |= from.safari10;
|
||||
self.toplevel |= from.toplevel;
|
||||
self.inline_sources_content |= from.inline_sources_content;
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for TerserCompressorOptions {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
self.defaults |= from.defaults;
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for MangleOptions {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
self.props.merge(&from.props);
|
||||
|
||||
self.top_level |= from.top_level;
|
||||
self.keep_class_names |= from.keep_class_names;
|
||||
self.keep_fn_names |= from.keep_fn_names;
|
||||
self.keep_private_props |= from.keep_private_props;
|
||||
self.safari10 |= from.safari10;
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for JsMinifyFormatOptions {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
self.comments.merge(&from.comments);
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for JsMinifyCommentOption {
|
||||
fn merge(&mut self, _: &Self) {}
|
||||
}
|
||||
|
||||
impl Merge for ManglePropertiesOptions {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
self.undeclared |= from.undeclared;
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for TerserEcmaVersion {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
*self = from.clone();
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for SourceMapsConfig {
|
||||
fn merge(&mut self, _: &Self) {}
|
||||
}
|
||||
|
||||
impl Merge for InputSourceMap {
|
||||
fn merge(&mut self, r: &Self) {
|
||||
if let InputSourceMap::Bool(false) = *self {
|
||||
*self = r.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for swc_ecma_preset_env::Config {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
*self = from.clone();
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for JscConfig {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
self.assumptions.merge(&from.assumptions);
|
||||
self.syntax.merge(&from.syntax);
|
||||
self.transform.merge(&from.transform);
|
||||
self.external_helpers.merge(&from.external_helpers);
|
||||
self.target.merge(&from.target);
|
||||
self.loose.merge(&from.loose);
|
||||
self.keep_class_names.merge(&from.keep_class_names);
|
||||
self.paths.merge(&from.paths);
|
||||
self.minify.merge(&from.minify);
|
||||
self.experimental.merge(&from.experimental);
|
||||
self.preserve_all_comments
|
||||
.merge(&from.preserve_all_comments)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, S> Merge for IndexMap<K, V, S>
|
||||
where
|
||||
K: Clone + Eq + std::hash::Hash,
|
||||
V: Clone,
|
||||
S: Clone + BuildHasher,
|
||||
{
|
||||
fn merge(&mut self, from: &Self) {
|
||||
if self.is_empty() {
|
||||
*self = (*from).clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, S> Merge for HashMap<K, V, S>
|
||||
where
|
||||
K: Clone + Eq + std::hash::Hash,
|
||||
V: Clone,
|
||||
S: Clone + BuildHasher,
|
||||
{
|
||||
fn merge(&mut self, from: &Self) {
|
||||
if self.is_empty() {
|
||||
*self = (*from).clone();
|
||||
} else {
|
||||
for (k, v) in from {
|
||||
self.entry(k.clone()).or_insert_with(|| v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for EsVersion {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
if *self < *from {
|
||||
*self = *from
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for Option<ModuleConfig> {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
if let Some(ref c2) = *from {
|
||||
*self = Some(c2.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for bool {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
*self |= *from
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for Syntax {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
match (&mut *self, from) {
|
||||
(Syntax::Es(a), Syntax::Es(b)) => {
|
||||
a.merge(b);
|
||||
}
|
||||
(Syntax::Typescript(a), Syntax::Typescript(b)) => {
|
||||
a.merge(b);
|
||||
}
|
||||
_ => {
|
||||
*self = *from;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for swc_ecma_parser::EsConfig {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
self.jsx |= from.jsx;
|
||||
self.fn_bind |= from.fn_bind;
|
||||
self.decorators |= from.decorators;
|
||||
self.decorators_before_export |= from.decorators_before_export;
|
||||
self.export_default_from |= from.export_default_from;
|
||||
self.import_assertions |= from.import_assertions;
|
||||
self.private_in_object |= from.private_in_object;
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for swc_ecma_parser::TsConfig {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
self.tsx |= from.tsx;
|
||||
self.decorators |= from.decorators;
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for Assumptions {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
self.array_like_is_iterable |= from.array_like_is_iterable;
|
||||
self.constant_reexports |= from.constant_reexports;
|
||||
self.constant_super |= from.constant_super;
|
||||
self.enumerable_module_meta |= from.enumerable_module_meta;
|
||||
self.ignore_function_length |= from.ignore_function_length;
|
||||
self.ignore_function_name |= from.ignore_function_name;
|
||||
self.ignore_to_primitive_hint |= from.ignore_to_primitive_hint;
|
||||
self.iterable_is_array |= from.iterable_is_array;
|
||||
self.mutable_template_object |= from.mutable_template_object;
|
||||
self.no_class_calls |= from.no_class_calls;
|
||||
self.no_document_all |= from.no_document_all;
|
||||
self.no_incomplete_ns_import_detection |= from.no_incomplete_ns_import_detection;
|
||||
self.no_new_arrows |= from.no_new_arrows;
|
||||
self.object_rest_no_symbols |= from.object_rest_no_symbols;
|
||||
self.private_fields_as_properties |= from.private_fields_as_properties;
|
||||
self.pure_getters |= from.pure_getters;
|
||||
self.set_class_methods |= from.set_class_methods;
|
||||
self.set_computed_properties |= from.set_computed_properties;
|
||||
self.set_public_class_fields |= from.set_public_class_fields;
|
||||
self.set_spread_properties |= from.set_spread_properties;
|
||||
self.skip_for_of_iterator_closing |= from.skip_for_of_iterator_closing;
|
||||
self.super_is_callable_constructor |= from.super_is_callable_constructor;
|
||||
self.ts_enum_is_readonly |= from.ts_enum_is_readonly;
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for TransformConfig {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
self.optimizer.merge(&from.optimizer);
|
||||
self.const_modules.merge(&from.const_modules);
|
||||
self.react.merge(&from.react);
|
||||
self.hidden.merge(&from.hidden);
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for OptimizerConfig {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
self.globals.merge(&from.globals)
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for GlobalPassOption {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
*self = from.clone();
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for react::Options {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
if *from != react::Options::default() {
|
||||
*self = from.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for ConstModulesConfig {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
*self = from.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge for HiddenTransformConfig {
|
||||
fn merge(&mut self, from: &Self) {
|
||||
self.jest |= from.jest;
|
||||
}
|
||||
}
|
||||
|
||||
fn build_resolver(base_url: PathBuf, paths: CompiledPaths) -> Box<SwcImportResolver> {
|
||||
static CACHE: Lazy<DashMap<(PathBuf, CompiledPaths), SwcImportResolver, ahash::RandomState>> =
|
||||
Lazy::new(Default::default);
|
||||
|
@ -1,102 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::Merge;
|
||||
|
||||
/// Note: `{}` (empty object) is treated as `true`.
|
||||
#[derive(Clone, Serialize, Debug)]
|
||||
#[serde(untagged)]
|
||||
pub enum BoolOrObject<T> {
|
||||
Bool(bool),
|
||||
Obj(T),
|
||||
}
|
||||
|
||||
impl<T> From<bool> for BoolOrObject<T> {
|
||||
fn from(v: bool) -> Self {
|
||||
BoolOrObject::Bool(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for BoolOrObject<T> {
|
||||
fn default() -> Self {
|
||||
Self::Bool(false)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> BoolOrObject<T> {
|
||||
pub fn into_obj(self) -> Option<T>
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
match self {
|
||||
BoolOrObject::Bool(true) => Some(Default::default()),
|
||||
BoolOrObject::Bool(false) => None,
|
||||
BoolOrObject::Obj(o) => Some(o),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Merge for BoolOrObject<T>
|
||||
where
|
||||
T: Clone + Merge + Default,
|
||||
{
|
||||
fn merge(&mut self, from: &Self) {
|
||||
match self {
|
||||
BoolOrObject::Bool(l) => match from {
|
||||
BoolOrObject::Bool(r) => {
|
||||
*l |= *r;
|
||||
}
|
||||
BoolOrObject::Obj(_) => *self = from.clone(),
|
||||
},
|
||||
BoolOrObject::Obj(o) => match from {
|
||||
BoolOrObject::Bool(r) => {
|
||||
if *r {
|
||||
o.merge(&Default::default())
|
||||
}
|
||||
}
|
||||
BoolOrObject::Obj(r) => o.merge(r),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for BoolOrObject<T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Deser<T> {
|
||||
Bool(bool),
|
||||
Obj(T),
|
||||
EmptyObject(EmptyStruct),
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct EmptyStruct {}
|
||||
|
||||
let content = swc_common::private::serde::de::Content::deserialize(deserializer)?;
|
||||
|
||||
let deserializer =
|
||||
swc_common::private::serde::de::ContentRefDeserializer::<D::Error>::new(&content);
|
||||
|
||||
let res = Deser::deserialize(deserializer);
|
||||
|
||||
match res {
|
||||
Ok(v) => Ok(match v {
|
||||
Deser::Bool(v) => BoolOrObject::Bool(v),
|
||||
Deser::Obj(v) => BoolOrObject::Obj(v),
|
||||
Deser::EmptyObject(_) => BoolOrObject::Bool(true),
|
||||
}),
|
||||
Err(..) => {
|
||||
let d =
|
||||
swc_common::private::serde::de::ContentDeserializer::<D::Error>::new(content);
|
||||
Ok(BoolOrObject::Obj(T::deserialize(d)?))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -120,8 +120,8 @@ use std::{
|
||||
|
||||
use anyhow::{bail, Context, Error};
|
||||
use atoms::JsWord;
|
||||
use common::{collections::AHashMap, comments::SingleThreadedComments, errors::HANDLER, Span};
|
||||
use config::{util::BoolOrObject, IsModule, JsMinifyCommentOption, JsMinifyOptions};
|
||||
use common::{collections::AHashMap, comments::SingleThreadedComments, errors::HANDLER};
|
||||
use config::{IsModule, JsMinifyCommentOption, JsMinifyOptions};
|
||||
use json_comments::StripComments;
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::Serialize;
|
||||
@ -135,6 +135,8 @@ use swc_common::{
|
||||
sync::Lrc,
|
||||
BytePos, FileName, Globals, Mark, SourceFile, SourceMap, Spanned, GLOBALS,
|
||||
};
|
||||
pub use swc_config::config_types::{BoolConfig, BoolOr, BoolOrDataConfig};
|
||||
use swc_config::merge::Merge;
|
||||
use swc_ecma_ast::{EsVersion, Ident, Program};
|
||||
use swc_ecma_codegen::{self, text_writer::WriteJs, Emitter, Node};
|
||||
use swc_ecma_loader::resolvers::{
|
||||
@ -159,7 +161,7 @@ use swc_timer::timer;
|
||||
|
||||
pub use crate::builder::PassBuilder;
|
||||
use crate::config::{
|
||||
BuiltInput, Config, ConfigFile, InputSourceMap, Merge, Options, Rc, RootMode, SourceMapsConfig,
|
||||
BuiltInput, Config, ConfigFile, InputSourceMap, Options, Rc, RootMode, SourceMapsConfig,
|
||||
};
|
||||
|
||||
mod builder;
|
||||
@ -584,74 +586,14 @@ impl SourceMapGenConfig for SwcSourceMapConfig<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn minify_global_comments(
|
||||
comments: &SwcComments,
|
||||
span: Span,
|
||||
minify: bool,
|
||||
preserve_comments: Option<BoolOrObject<JsMinifyCommentOption>>,
|
||||
) {
|
||||
let preserve_comments = preserve_comments.unwrap_or({
|
||||
if minify {
|
||||
BoolOrObject::Obj(JsMinifyCommentOption::PreserveSomeComments)
|
||||
} else {
|
||||
BoolOrObject::Obj(JsMinifyCommentOption::PreserveAllComments)
|
||||
}
|
||||
});
|
||||
|
||||
match preserve_comments {
|
||||
BoolOrObject::Bool(true)
|
||||
| BoolOrObject::Obj(JsMinifyCommentOption::PreserveAllComments) => {}
|
||||
|
||||
BoolOrObject::Obj(JsMinifyCommentOption::PreserveSomeComments) => {
|
||||
let preserve_excl = |pos: &BytePos, vc: &mut Vec<Comment>| -> bool {
|
||||
if *pos < span.lo || *pos >= span.hi {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Preserve license comments.
|
||||
if vc.iter().any(|c| c.text.contains("@license")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
vc.retain(|c: &Comment| c.text.starts_with('!'));
|
||||
!vc.is_empty()
|
||||
};
|
||||
comments.leading.retain(preserve_excl);
|
||||
comments.trailing.retain(preserve_excl);
|
||||
}
|
||||
|
||||
BoolOrObject::Bool(false) => {
|
||||
let remove_all_in_range = |pos: &BytePos, _: &mut Vec<Comment>| -> bool {
|
||||
if *pos < span.lo || *pos >= span.hi {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
};
|
||||
comments.leading.retain(remove_all_in_range);
|
||||
comments.trailing.retain(remove_all_in_range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn minify_file_comments(
|
||||
pub(crate) fn minify_file_comments(
|
||||
comments: &SingleThreadedComments,
|
||||
minify: bool,
|
||||
preserve_comments: Option<BoolOrObject<JsMinifyCommentOption>>,
|
||||
preserve_comments: BoolOr<JsMinifyCommentOption>,
|
||||
) {
|
||||
let preserve_comments = preserve_comments.unwrap_or({
|
||||
if minify {
|
||||
BoolOrObject::Obj(JsMinifyCommentOption::PreserveSomeComments)
|
||||
} else {
|
||||
BoolOrObject::Obj(JsMinifyCommentOption::PreserveAllComments)
|
||||
}
|
||||
});
|
||||
|
||||
match preserve_comments {
|
||||
BoolOrObject::Bool(true)
|
||||
| BoolOrObject::Obj(JsMinifyCommentOption::PreserveAllComments) => {}
|
||||
BoolOr::Bool(true) | BoolOr::Data(JsMinifyCommentOption::PreserveAllComments) => {}
|
||||
|
||||
BoolOrObject::Obj(JsMinifyCommentOption::PreserveSomeComments) => {
|
||||
BoolOr::Data(JsMinifyCommentOption::PreserveSomeComments) => {
|
||||
let preserve_excl = |_: &BytePos, vc: &mut Vec<Comment>| -> bool {
|
||||
// Preserve license comments.
|
||||
if vc.iter().any(|c| c.text.contains("@license")) {
|
||||
@ -667,7 +609,7 @@ pub fn minify_file_comments(
|
||||
t.retain(preserve_excl);
|
||||
}
|
||||
|
||||
BoolOrObject::Bool(false) => {
|
||||
BoolOr::Bool(false) => {
|
||||
let (mut l, mut t) = comments.borrow_all_mut();
|
||||
l.clear();
|
||||
t.clear();
|
||||
@ -725,7 +667,7 @@ impl Compiler {
|
||||
.context("failed to process config file")?;
|
||||
|
||||
if let Some(config_file) = config_file {
|
||||
config.merge(&config_file.into_config(Some(path))?)
|
||||
config.merge(config_file.into_config(Some(path))?)
|
||||
}
|
||||
|
||||
if let Some(c) = &mut config {
|
||||
@ -831,7 +773,6 @@ impl Compiler {
|
||||
opts.output_path.as_deref(),
|
||||
opts.source_file_name.clone(),
|
||||
handler,
|
||||
opts.is_module,
|
||||
Some(config),
|
||||
comments,
|
||||
before_pass,
|
||||
@ -963,10 +904,10 @@ impl Compiler {
|
||||
|
||||
let target = opts.ecma.clone().into();
|
||||
|
||||
let (source_map, orig) = match &opts.source_map {
|
||||
BoolOrObject::Bool(false) => (SourceMapsConfig::Bool(false), None),
|
||||
BoolOrObject::Bool(true) => (SourceMapsConfig::Bool(true), None),
|
||||
BoolOrObject::Obj(obj) => {
|
||||
let (source_map, orig) = opts
|
||||
.source_map
|
||||
.as_ref()
|
||||
.map(|obj| -> Result<_, Error> {
|
||||
let orig = obj
|
||||
.content
|
||||
.as_ref()
|
||||
@ -975,17 +916,32 @@ impl Compiler {
|
||||
Some(v) => Some(v?),
|
||||
None => None,
|
||||
};
|
||||
(SourceMapsConfig::Bool(true), orig)
|
||||
}
|
||||
};
|
||||
Ok((SourceMapsConfig::Bool(true), orig))
|
||||
})
|
||||
.unwrap_as_option(|v| {
|
||||
Some(Ok(match v {
|
||||
Some(true) => (SourceMapsConfig::Bool(true), None),
|
||||
_ => (SourceMapsConfig::Bool(false), None),
|
||||
}))
|
||||
})
|
||||
.unwrap()?;
|
||||
|
||||
let mut min_opts = MinifyOptions {
|
||||
compress: opts
|
||||
.compress
|
||||
.clone()
|
||||
.into_obj()
|
||||
.unwrap_as_option(|default| match default {
|
||||
Some(true) | None => Some(Default::default()),
|
||||
_ => None,
|
||||
})
|
||||
.map(|v| v.into_config(self.cm.clone())),
|
||||
mangle: opts.mangle.clone().into_obj(),
|
||||
mangle: opts
|
||||
.mangle
|
||||
.clone()
|
||||
.unwrap_as_option(|default| match default {
|
||||
Some(true) | None => Some(Default::default()),
|
||||
_ => None,
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@ -1065,7 +1021,13 @@ impl Compiler {
|
||||
module.fold_with(&mut fixer(Some(&comments as &dyn Comments)))
|
||||
});
|
||||
|
||||
minify_file_comments(&comments, true, Some(opts.format.comments.clone()));
|
||||
let preserve_comments = opts
|
||||
.format
|
||||
.comments
|
||||
.clone()
|
||||
.into_inner()
|
||||
.unwrap_or(BoolOr::Data(JsMinifyCommentOption::PreserveSomeComments));
|
||||
minify_file_comments(&comments, preserve_comments);
|
||||
|
||||
self.print(
|
||||
&module,
|
||||
@ -1135,7 +1097,7 @@ impl Compiler {
|
||||
});
|
||||
|
||||
if let Some(comments) = &config.comments {
|
||||
minify_file_comments(comments, config.minify, config.preserve_comments);
|
||||
minify_file_comments(comments, config.preserve_comments);
|
||||
}
|
||||
|
||||
self.print(
|
||||
|
@ -8,7 +8,7 @@ use std::{
|
||||
use anyhow::{bail, Context, Error};
|
||||
use swc::{
|
||||
config::{Config, JsMinifyOptions, JscConfig, ModuleConfig, Options, SourceMapsConfig},
|
||||
try_with_handler, Compiler, HandlerOpts,
|
||||
try_with_handler, BoolOrDataConfig, Compiler, HandlerOpts,
|
||||
};
|
||||
use swc_common::{errors::ColorConfig, SourceMap};
|
||||
use swc_ecma_ast::EsVersion;
|
||||
@ -84,12 +84,12 @@ fn create_matrix(entry: &Path) -> Vec<Options> {
|
||||
jsc: JscConfig {
|
||||
syntax: Some(syntax),
|
||||
transform: None,
|
||||
external_helpers,
|
||||
external_helpers: external_helpers.into(),
|
||||
target: Some(target),
|
||||
minify: if minify {
|
||||
Some(JsMinifyOptions {
|
||||
compress: true.into(),
|
||||
mangle: true.into(),
|
||||
compress: BoolOrDataConfig::from_bool(true),
|
||||
mangle: BoolOrDataConfig::from_bool(true),
|
||||
format: Default::default(),
|
||||
ecma: Default::default(),
|
||||
keep_classnames: Default::default(),
|
||||
@ -107,7 +107,7 @@ fn create_matrix(entry: &Path) -> Vec<Options> {
|
||||
..Default::default()
|
||||
},
|
||||
module: Some(ModuleConfig::CommonJs(Default::default())),
|
||||
minify,
|
||||
minify: minify.into(),
|
||||
..Default::default()
|
||||
},
|
||||
source_maps: if source_map {
|
||||
|
@ -9,7 +9,7 @@ use swc::{
|
||||
BuiltInput, Config, IsModule, JscConfig, ModuleConfig, Options, SourceMapsConfig,
|
||||
TransformConfig,
|
||||
},
|
||||
minify_file_comments, Compiler, TransformOutput,
|
||||
Compiler, TransformOutput,
|
||||
};
|
||||
use swc_common::{
|
||||
chain,
|
||||
@ -772,8 +772,6 @@ fn should_visit() {
|
||||
})
|
||||
});
|
||||
|
||||
minify_file_comments(&comments, config.minify, config.preserve_comments);
|
||||
|
||||
Ok(c.print(
|
||||
&program,
|
||||
None,
|
||||
@ -831,7 +829,7 @@ fn tests(input_dir: PathBuf) {
|
||||
output_path: Some(output.join(entry.file_name())),
|
||||
config: Config {
|
||||
jsc: JscConfig {
|
||||
external_helpers: true,
|
||||
external_helpers: true.into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
|
@ -139,23 +139,23 @@ fn shopify_2_same_opt() {
|
||||
no_early_errors: false,
|
||||
})),
|
||||
transform: None,
|
||||
external_helpers: false,
|
||||
external_helpers: false.into(),
|
||||
target: Some(EsVersion::Es5),
|
||||
loose: false,
|
||||
keep_class_names: false,
|
||||
loose: false.into(),
|
||||
keep_class_names: false.into(),
|
||||
base_url: Default::default(),
|
||||
paths: Default::default(),
|
||||
minify: None,
|
||||
experimental: Default::default(),
|
||||
lints: Default::default(),
|
||||
assumptions: Default::default(),
|
||||
preserve_all_comments: false,
|
||||
preserve_all_comments: false.into(),
|
||||
},
|
||||
module: None,
|
||||
minify: false,
|
||||
input_source_map: InputSourceMap::Bool(false),
|
||||
minify: false.into(),
|
||||
input_source_map: Some(InputSourceMap::Bool(false)),
|
||||
source_maps: None,
|
||||
inline_sources_content: false,
|
||||
inline_sources_content: false.into(),
|
||||
..Default::default()
|
||||
},
|
||||
skip_helper_injection: false,
|
||||
@ -218,10 +218,10 @@ fn shopify_3_reduce_defaults() {
|
||||
..Default::default()
|
||||
},
|
||||
module: None,
|
||||
minify: false,
|
||||
input_source_map: InputSourceMap::Bool(false),
|
||||
minify: false.into(),
|
||||
input_source_map: InputSourceMap::Bool(false).into(),
|
||||
source_maps: None,
|
||||
inline_sources_content: false,
|
||||
inline_sources_content: false.into(),
|
||||
..Default::default()
|
||||
},
|
||||
cwd: "/Users/kdy1/projects/example-swcify".into(),
|
||||
|
@ -30,7 +30,7 @@ fn file(f: &str) -> Result<(), StdErr> {
|
||||
&handler,
|
||||
&Options {
|
||||
config: Config {
|
||||
inline_sources_content: true,
|
||||
inline_sources_content: true.into(),
|
||||
..Default::default()
|
||||
},
|
||||
swcrc: true,
|
||||
@ -85,7 +85,7 @@ fn inline(f: &str) -> Result<(), StdErr> {
|
||||
&handler,
|
||||
&Options {
|
||||
config: Config {
|
||||
inline_sources_content: true,
|
||||
inline_sources_content: true.into(),
|
||||
..Default::default()
|
||||
},
|
||||
swcrc: true,
|
||||
|
@ -137,9 +137,9 @@ fn compile(input: &Path, output: &Path, opts: Options) {
|
||||
tsx: input.to_string_lossy().ends_with(".tsx"),
|
||||
decorators: true,
|
||||
dts: false,
|
||||
no_early_errors: true,
|
||||
no_early_errors: false,
|
||||
})),
|
||||
external_helpers: true,
|
||||
external_helpers: true.into(),
|
||||
..opts.config.jsc
|
||||
},
|
||||
source_maps: Some(SourceMapsConfig::Bool(
|
||||
|
16
crates/swc_config/Cargo.toml
Normal file
16
crates/swc_config/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||
description = "Types for configuring swc"
|
||||
documentation = "https://rustdoc.swc.rs/swc_config/"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
name = "swc_config"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
indexmap = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
swc_config_macro = { version = "0.1.0", path = "../swc_config_macro" }
|
51
crates/swc_config/src/config_types/bool_config.rs
Normal file
51
crates/swc_config/src/config_types/bool_config.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::merge::Merge;
|
||||
|
||||
#[derive(
|
||||
Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
|
||||
)]
|
||||
pub struct BoolConfig<const DEFAULT: bool>(#[serde(default)] Option<bool>);
|
||||
|
||||
impl<const DEFAULT: bool> BoolConfig<DEFAULT> {
|
||||
#[inline]
|
||||
pub fn new(value: Option<bool>) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_bool(self) -> bool {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const DEFAULT: bool> From<BoolConfig<DEFAULT>> for bool {
|
||||
#[inline]
|
||||
fn from(v: BoolConfig<DEFAULT>) -> Self {
|
||||
match v.0 {
|
||||
Some(v) => v,
|
||||
_ => DEFAULT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const DEFAULT: bool> From<Option<bool>> for BoolConfig<DEFAULT> {
|
||||
#[inline]
|
||||
fn from(v: Option<bool>) -> Self {
|
||||
Self(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const DEFAULT: bool> From<bool> for BoolConfig<DEFAULT> {
|
||||
#[inline]
|
||||
fn from(v: bool) -> Self {
|
||||
Self(Some(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl<const DEFAULT: bool> Merge for BoolConfig<DEFAULT> {
|
||||
#[inline]
|
||||
fn merge(&mut self, other: Self) {
|
||||
self.0.merge(other.0);
|
||||
}
|
||||
}
|
140
crates/swc_config/src/config_types/bool_or_data.rs
Normal file
140
crates/swc_config/src/config_types/bool_or_data.rs
Normal file
@ -0,0 +1,140 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::merge::Merge;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
pub struct BoolOrDataConfig<T>(#[serde(default)] Option<BoolOr<T>>);
|
||||
|
||||
impl<T> BoolOrDataConfig<T> {
|
||||
pub fn from_bool(v: bool) -> Self {
|
||||
Self(Some(BoolOr::Bool(v)))
|
||||
}
|
||||
|
||||
pub fn from_obj(v: T) -> Self {
|
||||
v.into()
|
||||
}
|
||||
|
||||
pub fn as_ref(&self) -> BoolOrDataConfig<&T> {
|
||||
match &self.0 {
|
||||
Some(BoolOr::Data(v)) => BoolOrDataConfig::from_obj(v),
|
||||
Some(BoolOr::Bool(b)) => BoolOrDataConfig::from_bool(*b),
|
||||
None => BoolOrDataConfig::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or<F>(self, default: F) -> Self
|
||||
where
|
||||
F: FnOnce() -> Self,
|
||||
{
|
||||
match self.0 {
|
||||
Some(..) => self,
|
||||
None => default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_as_option<F>(self, default: F) -> Option<T>
|
||||
where
|
||||
F: FnOnce(Option<bool>) -> Option<T>,
|
||||
{
|
||||
match self.0 {
|
||||
Some(BoolOr::Data(v)) => Some(v),
|
||||
Some(BoolOr::Bool(b)) => default(Some(b)),
|
||||
None => default(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map<F, N>(self, op: F) -> BoolOrDataConfig<N>
|
||||
where
|
||||
F: FnOnce(T) -> N,
|
||||
{
|
||||
match self.0 {
|
||||
Some(BoolOr::Data(v)) => BoolOrDataConfig::from_obj(op(v)),
|
||||
Some(BoolOr::Bool(b)) => BoolOrDataConfig::from_bool(b),
|
||||
None => BoolOrDataConfig::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_true(&self) -> bool {
|
||||
matches!(self.0, Some(BoolOr::Bool(true)))
|
||||
}
|
||||
|
||||
pub fn is_false(&self) -> bool {
|
||||
matches!(self.0, Some(BoolOr::Bool(false)))
|
||||
}
|
||||
|
||||
pub fn is_obj(&self) -> bool {
|
||||
matches!(self.0, Some(BoolOr::Data(_)))
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> Option<BoolOr<T>> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for BoolOrDataConfig<T> {
|
||||
fn from(v: T) -> Self {
|
||||
Self(Some(BoolOr::Data(v)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for BoolOrDataConfig<T> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Merge for BoolOrDataConfig<T> {
|
||||
#[inline]
|
||||
fn merge(&mut self, other: Self) {
|
||||
self.0.merge(other.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum BoolOr<T> {
|
||||
Bool(bool),
|
||||
Data(T),
|
||||
}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for BoolOr<T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Deser<T> {
|
||||
Bool(bool),
|
||||
Obj(T),
|
||||
EmptyObject(EmptyStruct),
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct EmptyStruct {}
|
||||
|
||||
use serde::__private::de;
|
||||
|
||||
let content = de::Content::deserialize(deserializer)?;
|
||||
|
||||
let deserializer = de::ContentRefDeserializer::<D::Error>::new(&content);
|
||||
|
||||
let res = Deser::deserialize(deserializer);
|
||||
|
||||
match res {
|
||||
Ok(v) => Ok(match v {
|
||||
Deser::Bool(v) => BoolOr::Bool(v),
|
||||
Deser::Obj(v) => BoolOr::Data(v),
|
||||
Deser::EmptyObject(_) => BoolOr::Bool(true),
|
||||
}),
|
||||
Err(..) => {
|
||||
let d = de::ContentDeserializer::<D::Error>::new(content);
|
||||
Ok(BoolOr::Data(T::deserialize(d)?))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
crates/swc_config/src/config_types/mod.rs
Normal file
7
crates/swc_config/src/config_types/mod.rs
Normal file
@ -0,0 +1,7 @@
|
||||
pub use self::{
|
||||
bool_config::BoolConfig,
|
||||
bool_or_data::{BoolOr, BoolOrDataConfig},
|
||||
};
|
||||
|
||||
mod bool_config;
|
||||
mod bool_or_data;
|
4
crates/swc_config/src/lib.rs
Normal file
4
crates/swc_config/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
pub mod config_types;
|
||||
pub mod merge;
|
1
crates/swc_config/src/macros.rs
Normal file
1
crates/swc_config/src/macros.rs
Normal file
@ -0,0 +1 @@
|
||||
|
83
crates/swc_config/src/merge.rs
Normal file
83
crates/swc_config/src/merge.rs
Normal file
@ -0,0 +1,83 @@
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
pub use swc_config_macro::Merge;
|
||||
|
||||
/// Deriavable trait for overrding configurations.
|
||||
///
|
||||
/// Typically, correct implementation of this trait for a struct is calling
|
||||
/// merge for all fields, and `#[derive(Merge)]` will do it for you.
|
||||
pub trait Merge: Sized {
|
||||
/// `self` has higher priority.
|
||||
fn merge(&mut self, other: Self);
|
||||
}
|
||||
|
||||
/// Modifies `self` iff `self` is [None]
|
||||
impl<T> Merge for Option<T> {
|
||||
#[inline]
|
||||
fn merge(&mut self, other: Self) {
|
||||
if self.is_none() {
|
||||
*self = other;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Merge for Box<T>
|
||||
where
|
||||
T: Merge,
|
||||
{
|
||||
#[inline]
|
||||
fn merge(&mut self, other: Self) {
|
||||
(**self).merge(*other);
|
||||
}
|
||||
}
|
||||
|
||||
/// Modifies `self` iff `self` is empty.
|
||||
impl<T> Merge for Vec<T> {
|
||||
#[inline]
|
||||
fn merge(&mut self, other: Self) {
|
||||
if self.is_empty() {
|
||||
*self = other;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Modifies `self` iff `self` is empty.
|
||||
impl<K, V, S> Merge for HashMap<K, V, S> {
|
||||
#[inline]
|
||||
fn merge(&mut self, other: Self) {
|
||||
if self.is_empty() {
|
||||
*self = other;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Modifies `self` iff `self` is empty.
|
||||
impl<K, V, S> Merge for IndexMap<K, V, S> {
|
||||
#[inline]
|
||||
fn merge(&mut self, other: Self) {
|
||||
if self.is_empty() {
|
||||
*self = other;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Modifies `self` iff `self` is empty.
|
||||
impl Merge for String {
|
||||
#[inline]
|
||||
fn merge(&mut self, other: Self) {
|
||||
if self.is_empty() {
|
||||
*self = other;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Modifies `self` iff `self` is empty.
|
||||
impl Merge for PathBuf {
|
||||
#[inline]
|
||||
fn merge(&mut self, other: Self) {
|
||||
if self.as_os_str().is_empty() {
|
||||
*self = other;
|
||||
}
|
||||
}
|
||||
}
|
29
crates/swc_config/tests/config_types.rs
Normal file
29
crates/swc_config/tests/config_types.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use serde_json::Value;
|
||||
use swc_config::config_types::BoolConfig;
|
||||
|
||||
fn bool_config(v: Value) -> BoolConfig<false> {
|
||||
serde_json::from_value(v).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bool_config_serde() {
|
||||
assert_eq!(bool_config(Value::Null), BoolConfig::new(None));
|
||||
|
||||
assert_eq!(bool_config(Value::Bool(true)), BoolConfig::new(Some(true)));
|
||||
assert_eq!(
|
||||
bool_config(Value::Bool(false)),
|
||||
BoolConfig::new(Some(false))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bool_config_default() {
|
||||
assert_eq!(
|
||||
BoolConfig::<false>::default(),
|
||||
BoolConfig::<false>::new(None)
|
||||
);
|
||||
assert_eq!(BoolConfig::<true>::default(), BoolConfig::<true>::new(None));
|
||||
|
||||
assert!(!BoolConfig::<false>::default().into_bool());
|
||||
assert!(BoolConfig::<true>::default().into_bool());
|
||||
}
|
24
crates/swc_config/tests/derive_merge.rs
Normal file
24
crates/swc_config/tests/derive_merge.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use swc_config::merge::Merge;
|
||||
|
||||
#[derive(Merge)]
|
||||
struct Fields {
|
||||
a: Option<()>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fields() {
|
||||
let mut fields = Fields { a: None };
|
||||
fields.merge(Fields { a: Some(()) });
|
||||
|
||||
assert_eq!(fields.a, Some(()));
|
||||
}
|
||||
|
||||
#[derive(Merge)]
|
||||
struct Tuple(Option<()>);
|
||||
#[test]
|
||||
fn test_tuple() {
|
||||
let mut tuple = Tuple(None);
|
||||
tuple.merge(Tuple(Some(())));
|
||||
|
||||
assert_eq!(tuple.0, Some(()));
|
||||
}
|
19
crates/swc_config_macro/Cargo.toml
Normal file
19
crates/swc_config_macro/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||
description = "Macros to prevent mistakes"
|
||||
documentation = "https://rustdoc.swc.rs/swc_config_macro/"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
name = "swc_config_macro"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.1.0"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
pmutil = "0.5.3"
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
swc_macros_common = { version = "0.3.5", path = "../swc_macros_common" }
|
||||
syn = "1"
|
10
crates/swc_config_macro/src/lib.rs
Normal file
10
crates/swc_config_macro/src/lib.rs
Normal file
@ -0,0 +1,10 @@
|
||||
extern crate proc_macro;
|
||||
|
||||
mod merge;
|
||||
|
||||
#[proc_macro_derive(Merge)]
|
||||
pub fn derive_merge(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input = syn::parse(input).expect("failed to parse input as DeriveInput");
|
||||
|
||||
self::merge::expand(input).into()
|
||||
}
|
64
crates/swc_config_macro/src/merge.rs
Normal file
64
crates/swc_config_macro/src/merge.rs
Normal file
@ -0,0 +1,64 @@
|
||||
use pmutil::{q, SpanExt};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use swc_macros_common::{access_field, join_stmts};
|
||||
use syn::{DeriveInput, Expr, Field, Fields, Stmt};
|
||||
|
||||
pub fn expand(input: DeriveInput) -> TokenStream {
|
||||
match &input.data {
|
||||
syn::Data::Struct(s) => {
|
||||
let body = call_merge_for_fields(&q!({ self }), &s.fields);
|
||||
let body = join_stmts(&body);
|
||||
|
||||
q!(
|
||||
Vars {
|
||||
Type: &input.ident,
|
||||
body
|
||||
},
|
||||
{
|
||||
#[automatically_derived]
|
||||
impl swc_config::merge::Merge for Type {
|
||||
fn merge(&mut self, _other: Self) {
|
||||
body
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
.into()
|
||||
}
|
||||
syn::Data::Enum(_) => unimplemented!("derive(Merge) does not support an enum"),
|
||||
syn::Data::Union(_) => unimplemented!("derive(Merge) does not support a union"),
|
||||
}
|
||||
}
|
||||
|
||||
fn call_merge_for_fields(obj: &dyn ToTokens, fields: &Fields) -> Vec<Stmt> {
|
||||
fn call_merge(obj: &dyn ToTokens, idx: usize, f: &Field) -> Expr {
|
||||
let r = q!({ _other });
|
||||
q!(
|
||||
Vars {
|
||||
l: access_field(obj, idx, f),
|
||||
r: access_field(&r, idx, f),
|
||||
},
|
||||
{ swc_config::merge::Merge::merge(&mut l, r) }
|
||||
)
|
||||
.parse()
|
||||
}
|
||||
|
||||
match fields {
|
||||
Fields::Named(fs) => fs
|
||||
.named
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, f)| call_merge(obj, idx, f))
|
||||
.map(|expr| Stmt::Semi(expr, fs.brace_token.span.as_token()))
|
||||
.collect(),
|
||||
Fields::Unnamed(fs) => fs
|
||||
.unnamed
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, f)| call_merge(obj, idx, f))
|
||||
.map(|expr| Stmt::Semi(expr, fs.paren_token.span.as_token()))
|
||||
.collect(),
|
||||
Fields::Unit => unimplemented!("derive(Merge) does not support a unit struct"),
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ swc_atoms = { version = "0.2.9", path = "../swc_atoms" }
|
||||
swc_common = { version = "0.17.23", path = "../swc_common", features = [
|
||||
"concurrent",
|
||||
] }
|
||||
swc_config = { version = "0.1.0", path = "../swc_config" }
|
||||
swc_ecma_ast = { version = "0.77.0", path = "../swc_ecma_ast" }
|
||||
swc_ecma_utils = { version = "0.83.0", path = "../swc_ecma_utils" }
|
||||
swc_ecma_visit = { version = "0.63.0", path = "../swc_ecma_visit" }
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use swc_config::merge::Merge;
|
||||
|
||||
#[cfg(feature = "non_critical_lints")]
|
||||
use crate::rules::non_critical_lints::{
|
||||
@ -32,11 +33,12 @@ impl Default for LintRuleReaction {
|
||||
enum LintRuleLevel {
|
||||
Str(LintRuleReaction),
|
||||
Number(u8),
|
||||
Unspecified,
|
||||
}
|
||||
|
||||
impl Default for LintRuleLevel {
|
||||
fn default() -> Self {
|
||||
Self::Str(LintRuleReaction::Off)
|
||||
Self::Unspecified
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,6 +51,7 @@ impl From<LintRuleLevel> for LintRuleReaction {
|
||||
2 => LintRuleReaction::Error,
|
||||
_ => LintRuleReaction::Off,
|
||||
},
|
||||
LintRuleLevel::Unspecified => LintRuleReaction::Off,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -69,7 +72,19 @@ impl<T: Debug + Clone + Serialize + Default> RuleConfig<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
impl<T> Merge for RuleConfig<T>
|
||||
where
|
||||
T: Debug + Clone + Serialize + Default,
|
||||
{
|
||||
fn merge(&mut self, other: Self) {
|
||||
if let LintRuleLevel::Unspecified = self.0 {
|
||||
self.0 = other.0;
|
||||
self.1 = other.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, Merge)]
|
||||
#[non_exhaustive]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct LintConfig {
|
||||
|
@ -37,6 +37,7 @@ serde_json = "1.0.61"
|
||||
swc_atoms = { version = "0.2", path = "../swc_atoms" }
|
||||
swc_cached = { version = "0.1.0", path = "../swc_cached" }
|
||||
swc_common = { version = "0.17.23", path = "../swc_common" }
|
||||
swc_config = { version = "0.1.0", path = "../swc_config" }
|
||||
swc_ecma_ast = { version = "0.77.0", path = "../swc_ecma_ast" }
|
||||
swc_ecma_codegen = { version = "0.106.0", path = "../swc_ecma_codegen" }
|
||||
swc_ecma_parser = { version = "0.103.0", path = "../swc_ecma_parser" }
|
||||
|
@ -2,6 +2,7 @@ use serde::{Deserialize, Serialize};
|
||||
use swc_atoms::JsWord;
|
||||
use swc_cached::regex::CachedRegex;
|
||||
use swc_common::{collections::AHashMap, Mark};
|
||||
use swc_config::merge::Merge;
|
||||
use swc_ecma_ast::{EsVersion, Expr};
|
||||
|
||||
pub mod terser;
|
||||
@ -68,13 +69,13 @@ pub struct MangleOptions {
|
||||
pub reserved: Vec<JsWord>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, Merge)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ManglePropertiesOptions {
|
||||
#[serde(default, alias = "reserved")]
|
||||
pub reserved: Vec<JsWord>,
|
||||
#[serde(default, alias = "undeclared")]
|
||||
pub undeclared: bool,
|
||||
pub undeclared: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub regex: Option<CachedRegex>,
|
||||
}
|
||||
|
@ -75,9 +75,7 @@ fn compressed(compressed_file: PathBuf) {
|
||||
&MinifyOptions {
|
||||
mangle: Some(MangleOptions {
|
||||
props: Some(ManglePropertiesOptions {
|
||||
reserved: Default::default(),
|
||||
undeclared: false,
|
||||
regex: Default::default(),
|
||||
..Default::default()
|
||||
}),
|
||||
top_level: true,
|
||||
keep_class_names: false,
|
||||
|
@ -21,23 +21,24 @@ ahash = "0.7.4"
|
||||
dashmap = "5.1.0"
|
||||
indexmap = "1.6.1"
|
||||
once_cell = "1.10.0"
|
||||
rayon = {version = "1.5.1", optional = true}
|
||||
rayon = { version = "1.5.1", optional = true }
|
||||
rustc-hash = "1.1.0"
|
||||
serde_json = "1.0.61"
|
||||
swc_atoms = {version = "0.2", path = "../swc_atoms"}
|
||||
swc_common = {version = "0.17.23", path = "../swc_common"}
|
||||
swc_ecma_ast = {version = "0.77.0", path = "../swc_ecma_ast"}
|
||||
swc_ecma_parser = {version = "0.103.0", path = "../swc_ecma_parser"}
|
||||
swc_ecma_transforms_base = {version = "0.82.0", path = "../swc_ecma_transforms_base"}
|
||||
swc_ecma_transforms_macros = {version = "0.3.0", path = "../swc_ecma_transforms_macros"}
|
||||
swc_ecma_utils = {version = "0.83.0", path = "../swc_ecma_utils"}
|
||||
swc_ecma_visit = {version = "0.63.0", path = "../swc_ecma_visit"}
|
||||
swc_atoms = { version = "0.2", path = "../swc_atoms" }
|
||||
swc_common = { version = "0.17.23", path = "../swc_common" }
|
||||
swc_ecma_ast = { version = "0.77.0", path = "../swc_ecma_ast" }
|
||||
swc_ecma_parser = { version = "0.103.0", path = "../swc_ecma_parser" }
|
||||
swc_ecma_transforms_base = { version = "0.82.0", path = "../swc_ecma_transforms_base" }
|
||||
swc_ecma_transforms_macros = { version = "0.3.0", path = "../swc_ecma_transforms_macros" }
|
||||
swc_ecma_utils = { version = "0.83.0", path = "../swc_ecma_utils" }
|
||||
swc_ecma_visit = { version = "0.63.0", path = "../swc_ecma_visit" }
|
||||
tracing = "0.1.32"
|
||||
|
||||
[dev-dependencies]
|
||||
swc_ecma_transforms_compat = {version = "0.96.0", path = "../swc_ecma_transforms_compat"}
|
||||
swc_ecma_transforms_module = {version = "0.109.0", path = "../swc_ecma_transforms_module"}
|
||||
swc_ecma_transforms_proposal = {version = "0.104.0", path = "../swc_ecma_transforms_proposal"}
|
||||
swc_ecma_transforms_react = {version = "0.111.0", path = "../swc_ecma_transforms_react"}
|
||||
swc_ecma_transforms_testing = {version = "0.84.0", path = "../swc_ecma_transforms_testing"}
|
||||
swc_ecma_transforms_typescript = {version = "0.114.0", path = "../swc_ecma_transforms_typescript"}
|
||||
testing = {version = "0.19.0", path = "../testing"}
|
||||
swc_ecma_transforms_compat = { version = "0.96.0", path = "../swc_ecma_transforms_compat" }
|
||||
swc_ecma_transforms_module = { version = "0.109.0", path = "../swc_ecma_transforms_module" }
|
||||
swc_ecma_transforms_proposal = { version = "0.104.0", path = "../swc_ecma_transforms_proposal" }
|
||||
swc_ecma_transforms_react = { version = "0.111.0", path = "../swc_ecma_transforms_react" }
|
||||
swc_ecma_transforms_testing = { version = "0.84.0", path = "../swc_ecma_transforms_testing" }
|
||||
swc_ecma_transforms_typescript = { version = "0.114.0", path = "../swc_ecma_transforms_typescript" }
|
||||
testing = { version = "0.19.0", path = "../testing" }
|
||||
|
@ -2,6 +2,7 @@ use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use dashmap::DashMap;
|
||||
use once_cell::sync::Lazy;
|
||||
use rustc_hash::FxHashMap;
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::{errors::HANDLER, sync::Lrc, util::move_map::MoveMap, FileName, SourceMap};
|
||||
use swc_ecma_ast::*;
|
||||
@ -11,7 +12,7 @@ use swc_ecma_visit::{noop_fold_type, Fold, FoldWith};
|
||||
|
||||
pub fn const_modules(
|
||||
cm: Lrc<SourceMap>,
|
||||
globals: HashMap<JsWord, HashMap<JsWord, String>>,
|
||||
globals: FxHashMap<JsWord, FxHashMap<JsWord, String>>,
|
||||
) -> impl Fold {
|
||||
ConstModules {
|
||||
globals: globals
|
||||
|
@ -6,7 +6,7 @@ edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
name = "swc_macros_common"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.3.4"
|
||||
version = "0.3.5"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
@ -1,9 +1,10 @@
|
||||
extern crate proc_macro;
|
||||
|
||||
use pmutil::synom_ext::FromSpan;
|
||||
#[cfg(procmacro2_semver_exempt)]
|
||||
use pmutil::SpanExt;
|
||||
use pmutil::{synom_ext::FromSpan, Quote, SpanExt};
|
||||
use proc_macro2::Span;
|
||||
use quote::ToTokens;
|
||||
use syn::*;
|
||||
|
||||
pub mod binder;
|
||||
@ -78,6 +79,32 @@ pub fn doc_str(attr: &Attribute) -> Option<String> {
|
||||
Some(parse_tts(attr))
|
||||
}
|
||||
|
||||
pub fn access_field(obj: &dyn ToTokens, idx: usize, f: &Field) -> Expr {
|
||||
Expr::Field(ExprField {
|
||||
attrs: Default::default(),
|
||||
base: syn::parse2(obj.to_token_stream())
|
||||
.expect("swc_macros_common::access_field: failed to parse object"),
|
||||
dot_token: Span::call_site().as_token(),
|
||||
member: match &f.ident {
|
||||
Some(id) => Member::Named(id.clone()),
|
||||
_ => Member::Unnamed(Index {
|
||||
index: idx as _,
|
||||
span: Span::call_site(),
|
||||
}),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub fn join_stmts(stmts: &[Stmt]) -> Quote {
|
||||
let mut q = Quote::new_call_site();
|
||||
|
||||
for s in stmts {
|
||||
q.push_tokens(s);
|
||||
}
|
||||
|
||||
q
|
||||
}
|
||||
|
||||
/// fail! is a panic! with location reporting.
|
||||
#[macro_export]
|
||||
macro_rules! fail {
|
||||
|
@ -202,12 +202,12 @@ impl SwcLoader {
|
||||
..Default::default()
|
||||
})
|
||||
},
|
||||
external_helpers: true,
|
||||
external_helpers: true.into(),
|
||||
..c.jsc.clone()
|
||||
},
|
||||
module: None,
|
||||
minify: false,
|
||||
input_source_map: InputSourceMap::Bool(false),
|
||||
minify: false.into(),
|
||||
input_source_map: InputSourceMap::Bool(false).into(),
|
||||
..c.clone()
|
||||
}
|
||||
},
|
||||
|
@ -6,9 +6,7 @@ it("should compress", async () => {
|
||||
console.log(foo)
|
||||
`);
|
||||
|
||||
expect(code).toMatchInlineSnapshot(
|
||||
`"import foo from\\"@src/app\\";console.log(foo)"`
|
||||
);
|
||||
expect(code).toMatchInlineSnapshot(`"import a from\\"@src/app\\";console.log(a)"`);
|
||||
});
|
||||
|
||||
it("should accept object", async () => {
|
||||
@ -20,9 +18,7 @@ it("should accept object", async () => {
|
||||
{}
|
||||
);
|
||||
|
||||
expect(code).toMatchInlineSnapshot(
|
||||
`"import foo from\\"@src/app\\";console.log(foo)"`
|
||||
);
|
||||
expect(code).toMatchInlineSnapshot(`"import a from\\"@src/app\\";console.log(a)"`);
|
||||
});
|
||||
|
||||
it("should accept { mangle = true }", async () => {
|
||||
|
@ -176,18 +176,16 @@ it("should respect `error.filename = false`", async () => {
|
||||
|
||||
});
|
||||
|
||||
it("should merge parser config", async () => {
|
||||
it("should support overring `jsc.externalHelpers` using js api", async () => {
|
||||
const filename = path.resolve(
|
||||
__dirname + "/../../tests/issue-2546/input.ts"
|
||||
__dirname + "/../../tests/issue-3834/input.js"
|
||||
);
|
||||
|
||||
const { code } = await swc.transformFile(filename, {
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: "typescript",
|
||||
}
|
||||
externalHelpers: false,
|
||||
}
|
||||
})
|
||||
|
||||
expect(code).not.toBeFalsy()
|
||||
expect(code).toContain('function _classCallCheck')
|
||||
});
|
4
node-swc/src/binding.d.ts
vendored
4
node-swc/src/binding.d.ts
vendored
@ -5,7 +5,7 @@
|
||||
|
||||
export interface TransformOutput {
|
||||
code: string
|
||||
map?: string | undefined | null
|
||||
map?: string
|
||||
}
|
||||
export function bundle(confItems: Buffer, signal?: AbortSignal | undefined | null): Promise<{ [index: string]: { code: string, map?: string } }>
|
||||
export function minify(code: Buffer, opts: Buffer, signal?: AbortSignal | undefined | null): Promise<TransformOutput>
|
||||
@ -25,7 +25,7 @@ export function initCustomTraceSubscriber(traceOutFilePath?: string | undefined
|
||||
/** Hack for `Type Generation` */
|
||||
export interface TransformOutput {
|
||||
code: string
|
||||
map?: string | undefined | null
|
||||
map?: string
|
||||
}
|
||||
export type JsCompiler = Compiler
|
||||
export class Compiler {
|
||||
|
8
node-swc/tests/issue-3834/.swcrc
Normal file
8
node-swc/tests/issue-3834/.swcrc
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"jsc": {
|
||||
"externalHelpers": true
|
||||
},
|
||||
"module": {
|
||||
"type": "commonjs"
|
||||
}
|
||||
}
|
4
node-swc/tests/issue-3834/input.js
Normal file
4
node-swc/tests/issue-3834/input.js
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
|
||||
export default class MyClass {
|
||||
}
|
Loading…
Reference in New Issue
Block a user