feat(es/minifier): Implement more rules (#1717)

swc_ecma_minifier:
 - Implement `global-defs` pass.
 - Implement `properties` pass partially.
This commit is contained in:
강동윤 2021-05-21 15:57:17 +09:00 committed by GitHub
parent a1341dcdc6
commit d20c1d3089
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 684 additions and 343 deletions

View File

@ -5,6 +5,7 @@ documentation = "https://rustdoc.swc.rs/swc_babel_compat/"
edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_babel_compat"
publish = false
repository = "https://github.com/swc-project/swc.git"
version = "0.1.0"

View File

@ -31,7 +31,7 @@ typescript = ["swc_ecma_transforms/typescript"]
swc_ecma_ast = {version = "0.45.0", path = "./ast"}
swc_ecma_codegen = {version = "0.55.0", path = "./codegen", optional = true}
swc_ecma_dep_graph = {version = "0.25.0", path = "./dep-graph", optional = true}
swc_ecma_minifier = {version = "0.1.0-beta.0", path = "./minifier", optional = true}
swc_ecma_minifier = {version = "0.2.0-beta.0", path = "./minifier", optional = true}
swc_ecma_parser = {version = "0.57.0", path = "./parser", optional = true}
swc_ecma_transforms = {version = "0.50.0", path = "./transforms", optional = true}
swc_ecma_utils = {version = "0.36.0", path = "./utils", optional = true}

View File

@ -7,12 +7,13 @@ include = ["Cargo.toml", "src/**/*.rs", "src/lists/*.json"]
license = "Apache-2.0/MIT"
name = "swc_ecma_minifier"
repository = "https://github.com/swc-project/swc.git"
version = "0.1.0-beta.0"
version = "0.2.0-beta.0"
[dependencies]
fxhash = "0.2.1"
log = "0.4"
once_cell = "1.5.2"
pretty_assertions = {version = "0.6.1", optional = true}
regex = "1.5.3"
retain_mut = "0.1.2"
serde = {version = "1.0.118", features = ["derive"]}
@ -22,6 +23,7 @@ swc_atoms = {version = "0.2", path = "../../atoms"}
swc_common = {version = "0.10.8", path = "../../common"}
swc_ecma_ast = {version = "0.45.0", path = "../ast"}
swc_ecma_codegen = {version = "0.55.0", path = "../codegen"}
swc_ecma_parser = {version = "0.57.0", path = "../parser"}
swc_ecma_transforms = {version = "0.50.0", path = "../transforms/", features = ["optimization"]}
swc_ecma_transforms_base = {version = "0.15.0", path = "../transforms/base"}
swc_ecma_utils = {version = "0.36.0", path = "../utils"}
@ -30,6 +32,5 @@ swc_ecma_visit = {version = "0.31.0", path = "../visit"}
[dev-dependencies]
ansi_term = "0.12.1"
pretty_assertions = "0.6.1"
swc_ecma_parser = {version = "0.57.0", path = "../parser"}
testing = {version = "0.10.2", path = "../../testing"}
walkdir = "2.3.1"

View File

@ -4,7 +4,7 @@
# Note that this is append-only.
set -eu
cargo test --test compress \
cargo test --test compress --all-features \
| grep 'js .\.\. ok$' \
| sed -e 's!test fixture_terser__compress__!!' \
| sed -e 's! ... ok!!' \

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -eu
cargo test --test compress $1 \
cargo test --test compress --all-features $1 \
| grep 'js .\.\. FAILED$' \
| sed -e 's!test fixture_terser__compress__!!' \
| sed -e 's! ... FAILED!!' \

View File

@ -16,7 +16,7 @@ if [ -z "$@" ]; then
export RUST_LOG=swc_ecma_minifier=trace
GOLDEN_ONLY=1 cargo test --test compress
GOLDEN_ONLY=1 cargo test --test compress --all-features
fi
cargo test --test compress $@
cargo test --test compress --all-features $@

View File

@ -8,4 +8,8 @@ cat tests/golden.txt | awk NF | sort | uniq | awk '{$1=$1};1' | uniq | sort > te
mv tests/golden_sorted.txt tests/golden.txt
cat tests/ignored.txt | awk NF | sort | uniq | awk '{$1=$1};1' | uniq | sort > tests/ignored_sorted.txt
mv tests/ignored_sorted.txt tests/ignored.txt
mv tests/ignored_sorted.txt tests/ignored.txt
# Don't mark ignored test as golden
comm -23 tests/golden.txt tests/ignored.txt > tests/nodup.txt
mv tests/nodup.txt tests/golden.txt

View File

@ -5,6 +5,8 @@ use crate::compress::hoist_decls::decl_hoister;
use crate::debug::dump;
use crate::option::CompressOptions;
use crate::util::Optional;
#[cfg(feature = "pretty_assertions")]
use pretty_assertions::assert_eq;
use std::borrow::Cow;
use std::fmt;
use std::fmt::Debug;

View File

@ -1,6 +1,7 @@
use super::Optimizer;
use crate::compress::optimize::Ctx;
use std::mem::swap;
use swc_common::Spanned;
use swc_common::DUMMY_SP;
use swc_ecma_ast::*;
use swc_ecma_transforms_base::ext::MapWithMut;
@ -160,7 +161,14 @@ impl Optimizer<'_> {
/// ```
pub(super) fn invoke_iife(&mut self, e: &mut Expr) {
if self.options.inline == 0 {
return;
let skip = match e {
Expr::Call(v) => !v.callee.span().is_dummy(),
_ => true,
};
if skip {
return;
}
}
if self.ctx.inline_prevented {

View File

@ -47,6 +47,7 @@ mod inline;
mod join_vars;
mod loops;
mod ops;
mod properties;
mod sequences;
mod strings;
mod switches;
@ -485,6 +486,8 @@ impl Optimizer<'_> {
}
}
/// Returns [None] if expression is side-effect-free.
/// If an expression has a side effect, only side effects are returned.
fn ignore_return_value(&mut self, e: &mut Expr) -> Option<Expr> {
match e {
Expr::Ident(..) | Expr::This(_) | Expr::Invalid(_) | Expr::Lit(..) => {
@ -1411,6 +1414,8 @@ impl VisitMut for Optimizer<'_> {
self.optimize_bools(e);
self.handle_property_access(e);
self.lift_seqs_of_cond_assign(e);
if self.options.negate_iife {
@ -1444,6 +1449,21 @@ impl VisitMut for Optimizer<'_> {
|| self.options.side_effects
|| (self.options.sequences() && n.expr.is_seq())
{
// Preserve top-level negated iifes.
match &*n.expr {
Expr::Unary(unary) => match &*unary.arg {
Expr::Call(CallExpr {
callee: ExprOrSuper::Expr(callee),
..
}) => match &**callee {
Expr::Fn(..) => return,
_ => {}
},
_ => {}
},
_ => {}
}
let expr = self.ignore_return_value(&mut n.expr);
n.expr = expr.map(Box::new).unwrap_or_else(|| undefined(DUMMY_SP));
}
@ -1562,6 +1582,8 @@ impl VisitMut for Optimizer<'_> {
if n.computed {
n.prop.visit_mut_with(self);
}
self.handle_known_computed_member_expr(n);
}
fn visit_mut_module_items(&mut self, stmts: &mut Vec<ModuleItem>) {

View File

@ -0,0 +1,131 @@
use crate::compress::optimize::Optimizer;
use crate::util::deeply_contains_this_expr;
use swc_atoms::js_word;
use swc_common::SyntaxContext;
use swc_ecma_ast::*;
use swc_ecma_utils::prop_name_eq;
use swc_ecma_utils::ExprExt;
impl Optimizer<'_> {
/// Converts `{ a: 1 }.a` into `1`.
pub(super) fn handle_property_access(&mut self, e: &mut Expr) {
if !self.options.props {
return;
}
if self.ctx.is_update_arg {
return;
}
let me = match e {
Expr::Member(m) => m,
_ => return,
};
if me.computed {
return;
}
let key = match &*me.prop {
Expr::Ident(prop) => prop,
_ => return,
};
let obj = match &mut me.obj {
ExprOrSuper::Expr(e) => &mut **e,
_ => return,
};
let obj = match obj {
Expr::Object(o) => o,
_ => return,
};
let duplicate_prop = obj
.props
.iter()
.filter(|prop| match prop {
PropOrSpread::Spread(_) => false,
PropOrSpread::Prop(p) => match &**p {
Prop::Shorthand(p) => p.sym == key.sym,
Prop::KeyValue(p) => prop_name_eq(&p.key, &key.sym),
Prop::Assign(p) => p.key.sym == key.sym,
Prop::Getter(p) => prop_name_eq(&p.key, &key.sym),
Prop::Setter(p) => prop_name_eq(&p.key, &key.sym),
Prop::Method(p) => prop_name_eq(&p.key, &key.sym),
},
})
.count()
!= 1;
if duplicate_prop {
return;
}
if obj.props.iter().any(|prop| match prop {
PropOrSpread::Spread(_) => false,
PropOrSpread::Prop(p) => match &**p {
Prop::Shorthand(..) => false,
Prop::KeyValue(p) => {
p.key.is_computed()
|| p.value.may_have_side_effects()
|| deeply_contains_this_expr(&p.value)
}
Prop::Assign(p) => {
p.value.may_have_side_effects() || deeply_contains_this_expr(&p.value)
}
Prop::Getter(p) => p.key.is_computed(),
Prop::Setter(p) => p.key.is_computed(),
Prop::Method(p) => p.key.is_computed(),
},
}) {
return;
}
for prop in &obj.props {
match prop {
PropOrSpread::Spread(_) => {}
PropOrSpread::Prop(p) => match &**p {
Prop::Shorthand(_) => {}
Prop::KeyValue(p) => {
if prop_name_eq(&p.key, &key.sym) {
log::trace!("properties: Inlining a key-value property `{}`", key.sym);
self.changed = true;
*e = *p.value.clone();
return;
}
}
Prop::Assign(_) => {}
Prop::Getter(_) => {}
Prop::Setter(_) => {}
Prop::Method(_) => {}
},
}
}
}
pub(super) fn handle_known_computed_member_expr(&mut self, e: &mut MemberExpr) {
if !self.options.props || !self.options.evaluate {
return;
}
if !e.computed {
return;
}
match &*e.prop {
Expr::Lit(Lit::Str(s)) => {
if s.value == js_word!("") || s.value.starts_with(|c: char| c.is_digit(10)) {
return;
}
self.changed = true;
e.computed = false;
e.prop = Box::new(Expr::Ident(Ident::new(
s.value.clone(),
s.span.with_ctxt(SyntaxContext::empty()),
)));
}
_ => {}
}
}
}

View File

@ -6,9 +6,11 @@
use crate::compress::compressor;
use crate::hygiene::unique_marker;
use crate::option::ExtraOptions;
use crate::option::MinifyOptions;
use crate::pass::compute_char_freq::compute_char_freq;
use crate::pass::expand_names::name_expander;
use crate::pass::global_defs;
use crate::pass::hygiene::hygiene_optimizer;
use crate::pass::mangle_names::name_mangler;
use crate::pass::mangle_props::mangle_properties;
@ -34,7 +36,21 @@ pub fn optimize(
comments: Option<&dyn Comments>,
mut timings: Option<&mut Timings>,
options: &MinifyOptions,
extra: &ExtraOptions,
) -> Module {
if let Some(defs) = options.compress.as_ref().map(|c| &c.global_defs) {
// Apply global defs.
//
// As terser treats `CONFIG['VALUE']` and `CONFIG.VALUE` differently, we don't
// have to see if optimized code matches global definition and wecan run
// this at startup.
if !defs.is_empty() {
let defs = defs.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
m.visit_mut_with(&mut global_defs::globals_defs(defs, extra.top_level_mark));
}
}
m.visit_mut_with(&mut unique_marker());
if options.wrap {

View File

@ -3,10 +3,19 @@ use regex::Regex;
use serde::Deserialize;
use serde::Serialize;
use swc_atoms::JsWord;
use swc_common::Mark;
use swc_ecma_ast::EsVersion;
use swc_ecma_ast::Lit;
use swc_ecma_ast::Expr;
pub mod terser;
/// This is not serializable.
#[derive(Debug)]
pub struct ExtraOptions {
/// The [Mark] used for `resolver_with_mark`.
pub top_level_mark: Mark,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
@ -128,9 +137,11 @@ pub struct CompressOptions {
#[serde(alias = "expression")]
pub expr: bool,
#[serde(default)]
/// All expressions should have dummy span. Use [swc_ecma_utils::drop_span]
/// to remove spans.
#[serde(skip)]
#[serde(alias = "global_defs")]
pub global_defs: FxHashMap<JsWord, Lit>,
pub global_defs: FxHashMap<Box<Expr>, Box<Expr>>,
#[serde(default)]
#[serde(alias = "hoist_funs")]

View File

@ -6,8 +6,15 @@ use fxhash::FxHashMap;
use serde::Deserialize;
use serde_json::Value;
use swc_atoms::JsWord;
use swc_common::input::SourceFileInput;
use swc_common::sync::Lrc;
use swc_common::FileName;
use swc_common::SourceMap;
use swc_common::DUMMY_SP;
use swc_ecma_ast::*;
use swc_ecma_parser::lexer::Lexer;
use swc_ecma_parser::Parser;
use swc_ecma_utils::drop_span;
#[derive(Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
@ -237,59 +244,77 @@ fn ecma_default() -> TerserEcmaVersion {
TerserEcmaVersion::Num(5)
}
impl From<TerserCompressorOptions> for CompressOptions {
fn from(c: TerserCompressorOptions) -> Self {
impl TerserCompressorOptions {
pub fn into_config(self, cm: Lrc<SourceMap>) -> CompressOptions {
CompressOptions {
arguments: c.arguments,
arrows: c.arrows.unwrap_or(c.defaults),
bools: c.booleans.unwrap_or(c.defaults),
bools_as_ints: c.booleans_as_integers,
collapse_vars: c.collapse_vars.unwrap_or(c.defaults),
comparisons: c.comparisons.unwrap_or(c.defaults),
computed_props: c.computed_props,
conditionals: c.conditionals,
dead_code: c.dead_code,
directives: c.directives,
drop_console: c.drop_console,
drop_debugger: c.drop_debugger.unwrap_or(c.defaults),
ecma: c.ecma.into(),
evaluate: c.evaluate.unwrap_or(c.defaults),
expr: c.expression,
global_defs: c
arguments: self.arguments,
arrows: self.arrows.unwrap_or(self.defaults),
bools: self.booleans.unwrap_or(self.defaults),
bools_as_ints: self.booleans_as_integers,
collapse_vars: self.collapse_vars.unwrap_or(self.defaults),
comparisons: self.comparisons.unwrap_or(self.defaults),
computed_props: self.computed_props,
conditionals: self.conditionals,
dead_code: self.dead_code,
directives: self.directives,
drop_console: self.drop_console,
drop_debugger: self.drop_debugger.unwrap_or(self.defaults),
ecma: self.ecma.into(),
evaluate: self.evaluate.unwrap_or(self.defaults),
expr: self.expression,
global_defs: self
.global_defs
.into_iter()
.map(|(k, v)| {
let parse = |input: String| {
let fm = cm.new_source_file(FileName::Anon, input);
let lexer = Lexer::new(
Default::default(),
Default::default(),
SourceFileInput::from(&*fm),
None,
);
let mut parser = Parser::new_from(lexer);
parser.parse_expr().map(drop_span).unwrap_or_else(|err| {
panic!(
"failed to parse `global_defs.{}` of minifier options: {:?}",
k, err
)
})
};
let key = parse(if k.starts_with('@') {
k[1..].to_string()
} else {
k.to_string()
});
(
k,
match v {
Value::Null => Lit::Null(Null { span: DUMMY_SP }),
Value::Bool(value) => Lit::Bool(Bool {
span: DUMMY_SP,
value,
}),
Value::Number(v) => Lit::Num(Number {
span: DUMMY_SP,
value: v.as_f64().unwrap(),
}),
Value::String(v) => Lit::Str(Str {
span: DUMMY_SP,
value: v.into(),
has_escape: false,
kind: Default::default(),
}),
Value::Object(_) | Value::Array(_) => {
unreachable!()
}
key,
if k.starts_with('@') {
parse(
v.as_str()
.unwrap_or_else(|| {
panic!(
"Value of `global_defs.{}` must be a string literal: ",
k
)
})
.into(),
)
} else {
value_to_expr(v)
},
)
})
.collect(),
hoist_fns: c.hoist_funs,
hoist_props: c.hoist_props.unwrap_or(c.defaults),
hoist_vars: c.hoist_vars,
ie8: c.ie8,
if_return: c.if_return.unwrap_or(c.defaults),
inline: c
hoist_fns: self.hoist_funs,
hoist_props: self.hoist_props.unwrap_or(self.defaults),
hoist_vars: self.hoist_vars,
ie8: self.ie8,
if_return: self.if_return.unwrap_or(self.defaults),
inline: self
.inline
.map(|v| match v {
TerserInlineOption::Bool(v) => {
@ -301,19 +326,19 @@ impl From<TerserCompressorOptions> for CompressOptions {
}
TerserInlineOption::Num(n) => n,
})
.unwrap_or(if c.defaults { 3 } else { 0 }),
join_vars: c.join_vars.unwrap_or(c.defaults),
keep_classnames: c.keep_classnames,
keep_fargs: c.keep_fargs.unwrap_or(c.defaults),
keep_fnames: c.keep_fnames,
keep_infinity: c.keep_infinity,
loops: c.loops.unwrap_or(c.defaults),
negate_iife: c.negate_iife.unwrap_or(c.defaults),
passes: c.passes,
props: c.properties.unwrap_or(c.defaults),
reduce_fns: c.reduce_funcs,
reduce_vars: c.reduce_vars,
sequences: c
.unwrap_or(if self.defaults { 3 } else { 0 }),
join_vars: self.join_vars.unwrap_or(self.defaults),
keep_classnames: self.keep_classnames,
keep_fargs: self.keep_fargs.unwrap_or(self.defaults),
keep_fnames: self.keep_fnames,
keep_infinity: self.keep_infinity,
loops: self.loops.unwrap_or(self.defaults),
negate_iife: self.negate_iife.unwrap_or(self.defaults),
passes: self.passes,
props: self.properties.unwrap_or(self.defaults),
reduce_fns: self.reduce_funcs,
reduce_vars: self.reduce_vars,
sequences: self
.sequences
.map(|v| match v {
TerserSequenceOptions::Bool(v) => {
@ -325,23 +350,23 @@ impl From<TerserCompressorOptions> for CompressOptions {
}
TerserSequenceOptions::Num(v) => v,
})
.unwrap_or(if c.defaults { 3 } else { 0 }),
side_effects: c.side_effects.unwrap_or(c.defaults),
switches: c.switches,
top_retain: c.top_retain.map(From::from).unwrap_or_default(),
top_level: c.toplevel.map(From::from),
typeofs: c.typeofs.unwrap_or(c.defaults),
unsafe_passes: c.unsafe_passes,
unsafe_arrows: c.unsafe_arrows,
unsafe_comps: c.unsafe_comps,
unsafe_function: c.unsafe_function,
unsafe_math: c.unsafe_math,
unsafe_symbols: c.unsafe_symbols,
unsafe_methods: c.unsafe_methods,
unsafe_proto: c.unsafe_proto,
unsafe_regexp: c.unsafe_regexp,
unsafe_undefined: c.unsafe_undefined,
unused: c.unused.unwrap_or(c.defaults),
.unwrap_or(if self.defaults { 3 } else { 0 }),
side_effects: self.side_effects.unwrap_or(self.defaults),
switches: self.switches,
top_retain: self.top_retain.map(From::from).unwrap_or_default(),
top_level: self.toplevel.map(From::from),
typeofs: self.typeofs.unwrap_or(self.defaults),
unsafe_passes: self.unsafe_passes,
unsafe_arrows: self.unsafe_arrows,
unsafe_comps: self.unsafe_comps,
unsafe_function: self.unsafe_function,
unsafe_math: self.unsafe_math,
unsafe_symbols: self.unsafe_symbols,
unsafe_methods: self.unsafe_methods,
unsafe_proto: self.unsafe_proto,
unsafe_regexp: self.unsafe_regexp,
unsafe_undefined: self.unsafe_undefined,
unused: self.unused.unwrap_or(self.defaults),
}
}
}
@ -394,3 +419,59 @@ impl From<TerserTopRetainOption> for Vec<JsWord> {
}
}
}
fn value_to_expr(v: Value) -> Box<Expr> {
match v {
Value::Null => Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))),
Value::Bool(value) => Box::new(Expr::Lit(Lit::Bool(Bool {
span: DUMMY_SP,
value,
}))),
Value::Number(v) => Box::new(Expr::Lit(Lit::Num(Number {
span: DUMMY_SP,
value: v.as_f64().unwrap(),
}))),
Value::String(v) => Box::new(Expr::Lit(Lit::Str(Str {
span: DUMMY_SP,
value: v.into(),
has_escape: false,
kind: Default::default(),
}))),
Value::Array(arr) => {
let elems = arr
.into_iter()
.map(value_to_expr)
.map(|expr| Some(ExprOrSpread { spread: None, expr }))
.collect();
Box::new(Expr::Array(ArrayLit {
span: DUMMY_SP,
elems,
}))
}
Value::Object(obj) => {
let props = obj
.into_iter()
.map(|(k, v)| (k, value_to_expr(v)))
.map(|(key, value)| KeyValueProp {
key: PropName::Str(Str {
span: DUMMY_SP,
value: key.into(),
has_escape: false,
kind: Default::default(),
}),
value,
})
.map(Prop::KeyValue)
.map(Box::new)
.map(PropOrSpread::Prop)
.collect();
Box::new(Expr::Object(ObjectLit {
span: DUMMY_SP,
props,
}))
}
}
}

View File

@ -0,0 +1,151 @@
use fxhash::FxHashSet;
use std::borrow::Cow;
use swc_common::pass::CompilerPass;
use swc_common::EqIgnoreSpan;
use swc_common::Mark;
use swc_common::SyntaxContext;
use swc_ecma_ast::*;
use swc_ecma_utils::ident::IdentLike;
use swc_ecma_utils::Id;
use swc_ecma_visit::noop_visit_mut_type;
use swc_ecma_visit::noop_visit_type;
use swc_ecma_visit::Visit;
use swc_ecma_visit::VisitMut;
use swc_ecma_visit::VisitMutWith;
pub fn globals_defs(defs: Vec<(Box<Expr>, Box<Expr>)>, top_level_mark: Mark) -> impl VisitMut {
GlobalDefs {
defs,
top_level_ctxt: SyntaxContext::empty().apply_mark(top_level_mark),
..Default::default()
}
}
#[derive(Default)]
struct GlobalDefs {
defs: Vec<(Box<Expr>, Box<Expr>)>,
/// If syntax context of a identifier reference is not top-level, it means
/// the reference points a binding (var / fn / class or whatever).
top_level_ctxt: SyntaxContext,
/// If a varaible is registered in this variable, it's not a global
/// constant.
///
/// Non-top level bindings are filtered using `top_level_mark`.
top_level_bindings: FxHashSet<Id>,
in_lhs_of_assign: bool,
}
impl CompilerPass for GlobalDefs {
fn name() -> Cow<'static, str> {
Cow::Borrowed("global-defs")
}
}
/// Finds top-level bindings.
impl Visit for GlobalDefs {
noop_visit_type!();
}
/// We use [VisitMut] instead of [swc_ecma_visit::Fold] because it's faster.
impl VisitMut for GlobalDefs {
noop_visit_mut_type!();
fn visit_mut_assign_expr(&mut self, n: &mut AssignExpr) {
let old = self.in_lhs_of_assign;
self.in_lhs_of_assign = true;
n.left.visit_mut_with(self);
self.in_lhs_of_assign = false;
n.right.visit_mut_with(self);
self.in_lhs_of_assign = old;
}
fn visit_mut_expr(&mut self, n: &mut Expr) {
if self.in_lhs_of_assign {
return;
}
match n {
Expr::Ident(i) => {
if i.span.ctxt != self.top_level_ctxt
|| self.top_level_bindings.contains(&i.to_id())
{
return;
}
}
Expr::Member(MemberExpr {
obj: ExprOrSuper::Expr(obj),
..
}) => match &**obj {
Expr::Ident(i) => {
if i.span.ctxt != self.top_level_ctxt
|| self.top_level_bindings.contains(&i.to_id())
{
return;
}
}
_ => {}
},
_ => {}
}
if let Some((_, new)) = self.defs.iter().find(|(pred, _)| should_replace(&pred, &n)) {
*n = *new.clone();
return;
}
n.visit_mut_children_with(self);
}
#[inline]
fn visit_mut_update_expr(&mut self, e: &mut UpdateExpr) {
match &mut *e.arg {
Expr::Ident(..) => {}
Expr::Member(MemberExpr {
computed: false, ..
}) => {
// TODO: Check for `obj`
}
_ => {
e.arg.visit_mut_with(self);
}
}
}
}
/// This is used to detect optional chaining expressions like `a?.b.c` without
/// allocation.
fn should_replace(pred: &Expr, node: &Expr) -> bool {
if pred.eq_ignore_span(node) {
return true;
}
match (pred, node) {
(pred, Expr::OptChain(node)) => {
if should_replace(pred, &node.expr) {
return true;
}
}
(Expr::Member(pred), Expr::Member(node)) => {
if pred.computed || node.computed {
return false;
}
if !pred.prop.eq_ignore_span(&node.prop) {
return false;
}
match (&pred.obj, &node.obj) {
(ExprOrSuper::Expr(pred_obj), ExprOrSuper::Expr(node_obj)) => {
return should_replace(pred_obj, node_obj)
}
_ => {}
}
}
_ => {}
}
false
}

View File

@ -1,5 +1,6 @@
pub mod compute_char_freq;
pub mod expand_names;
pub mod global_defs;
pub mod hygiene;
pub mod mangle_names;
pub mod mangle_props;

View File

@ -245,3 +245,24 @@ where
module.fold_with(&mut self.visitor)
}
}
pub struct DeepThisExprVisitor {
found: bool,
}
impl Visit for DeepThisExprVisitor {
noop_visit_type!();
fn visit_this_expr(&mut self, _: &ThisExpr, _: &dyn Node) {
self.found = true;
}
}
pub fn deeply_contains_this_expr<N>(body: &N) -> bool
where
N: VisitWith<DeepThisExprVisitor>,
{
let mut visitor = DeepThisExprVisitor { found: false };
body.visit_with(&Invalid { span: DUMMY_SP } as _, &mut visitor);
visitor.found
}

View File

@ -14,12 +14,14 @@ use std::process::Command;
use swc_common::comments::SingleThreadedComments;
use swc_common::sync::Lrc;
use swc_common::FileName;
use swc_common::Mark;
use swc_common::SourceMap;
use swc_ecma_codegen::text_writer::JsWriter;
use swc_ecma_codegen::Emitter;
use swc_ecma_minifier::optimize;
use swc_ecma_minifier::option::terser::TerserCompressorOptions;
use swc_ecma_minifier::option::CompressOptions;
use swc_ecma_minifier::option::ExtraOptions;
use swc_ecma_minifier::option::MangleOptions;
use swc_ecma_minifier::option::MinifyOptions;
use swc_ecma_parser::lexer::input::SourceFileInput;
@ -27,7 +29,7 @@ use swc_ecma_parser::lexer::Lexer;
use swc_ecma_parser::Parser;
use swc_ecma_transforms::fixer;
use swc_ecma_transforms::hygiene;
use swc_ecma_transforms::resolver;
use swc_ecma_transforms::resolver_with_mark;
use swc_ecma_visit::FoldWith;
use testing::assert_eq;
use testing::NormalizedOutput;
@ -76,11 +78,11 @@ enum TestMangleOptions {
Normal(MangleOptions),
}
fn parse_compressor_config(s: &str) -> (bool, CompressOptions) {
fn parse_compressor_config(cm: Lrc<SourceMap>, s: &str) -> (bool, CompressOptions) {
let c: TerserCompressorOptions =
serde_json::from_str(s).expect("failed to deserialize value into a compressor config");
(c.module, c.into())
(c.module, c.into_config(cm))
}
/// Tests ported from terser.
@ -94,40 +96,44 @@ fn fixture(input: PathBuf) {
let config = dir.join("config.json");
let config = read_to_string(&config).expect("failed to read config.json");
eprintln!("---- {} -----\n{}", Color::Green.paint("Config"), config);
let (_module, config) = parse_compressor_config(&config);
let mangle = dir.join("mangle.json");
let mangle = read_to_string(&mangle).ok();
if let Some(mangle) = &mangle {
eprintln!(
"---- {} -----\n{}",
Color::Green.paint("Mangle config"),
mangle
);
}
let mangle: Option<TestMangleOptions> =
mangle.map(|s| serde_json::from_str(&s).expect("failed to deserialize mangle.json"));
testing::run_test2(false, |cm, handler| {
let (_module, config) = parse_compressor_config(cm.clone(), &config);
let mangle = dir.join("mangle.json");
let mangle = read_to_string(&mangle).ok();
if let Some(mangle) = &mangle {
eprintln!(
"---- {} -----\n{}",
Color::Green.paint("Mangle config"),
mangle
);
}
let mangle: Option<TestMangleOptions> =
mangle.map(|s| serde_json::from_str(&s).expect("failed to deserialize mangle.json"));
let fm = cm.load_file(&input).expect("failed to load input.js");
let comments = SingleThreadedComments::default();
eprintln!("---- {} -----\n{}", Color::Green.paint("Input"), fm.src);
let top_level_mark = Mark::fresh(Mark::root());
let lexer = Lexer::new(
Default::default(),
Default::default(),
SourceFileInput::from(&*fm),
Some(&comments),
);
let mut parser = Parser::new_from(lexer);
let program = parser
.parse_module()
.map_err(|err| {
err.into_diagnostic(&handler).emit();
})
.map(|module| module.fold_with(&mut resolver()));
.map(|module| module.fold_with(&mut resolver_with_mark(top_level_mark)));
// Ignore parser errors.
//
@ -155,6 +161,7 @@ fn fixture(input: PathBuf) {
}),
..Default::default()
},
&ExtraOptions { top_level_mark },
)
.fold_with(&mut hygiene())
.fold_with(&mut fixer(None));

View File

@ -5,14 +5,7 @@ arguments/issue_687/input.js
arguments/modified/input.js
arguments/replace_index_keep_fargs_strict/input.js
array_constructor/array_constructor/input.js
array_constructor/array_constructor_unsafe/input.js
arrays/constant_join/input.js
arrays/constant_join_2/input.js
arrays/constant_join_3/input.js
arrays/for_loop/input.js
arrays/holes_and_undefined/input.js
arrays/index/input.js
arrays/index_length/input.js
arrays/length/input.js
arrays/spread_with_array_at_end/input.js
arrays/spread_with_logical_expression_at_end/input.js
@ -37,10 +30,8 @@ arrow/issue_2271/input.js
arrow/issue_3092a/input.js
arrow/no_leading_parentheses/input.js
arrow/object_parens/input.js
ascii/ascii_only_false/input.js
ascii/ascii_only_false_identifier_es2015/input.js
ascii/ascii_only_false_identifier_es5/input.js
ascii/ascii_only_true/input.js
ascii/ascii_only_true_identifier_es2015/input.js
ascii/ascii_only_true_identifier_es5/input.js
asm/asm_function_expression/input.js
@ -83,6 +74,7 @@ big_int/big_int_octal/input.js
big_int/big_int_positive/input.js
big_int/regression_big_int_hex_lower_with_e/input.js
block_scope/do_not_hoist_let/input.js
block_scope/do_not_remove_anon_blocks_if_they_have_decls/input.js
block_scope/issue_241/input.js
block_scope/issue_508/input.js
block_scope/let_statement/input.js
@ -104,17 +96,9 @@ classes/class_recursive_refs/input.js
collapse_vars/anonymous_function/input.js
collapse_vars/boolean_binary_1/input.js
collapse_vars/boolean_binary_2/input.js
collapse_vars/cascade_call/input.js
collapse_vars/cascade_conditional/input.js
collapse_vars/cascade_forin/input.js
collapse_vars/cascade_if_1/input.js
collapse_vars/cascade_if_2/input.js
collapse_vars/cascade_return/input.js
collapse_vars/cascade_statement/input.js
collapse_vars/cascade_switch/input.js
collapse_vars/chained_1/input.js
collapse_vars/chained_2/input.js
collapse_vars/chained_3/input.js
collapse_vars/collapse_rhs_array/input.js
collapse_vars/collapse_rhs_boolean_1/input.js
collapse_vars/collapse_rhs_boolean_2/input.js
@ -133,7 +117,7 @@ collapse_vars/collapse_rhs_this/input.js
collapse_vars/collapse_rhs_undefined/input.js
collapse_vars/collapse_rhs_var/input.js
collapse_vars/collapse_rhs_vardef/input.js
collapse_vars/collapse_vars_array/input.js
collapse_vars/collapse_vars_properties/input.js
collapse_vars/collapse_vars_try/input.js
collapse_vars/collapse_vars_unary_2/input.js
collapse_vars/cond_branch_switch/input.js
@ -149,9 +133,8 @@ collapse_vars/issue_1537_destructuring_for_in/input.js
collapse_vars/issue_1537_destructuring_for_of/input.js
collapse_vars/issue_1537_for_of/input.js
collapse_vars/issue_1605_1/input.js
collapse_vars/issue_2203_1/input.js
collapse_vars/issue_2203_3/input.js
collapse_vars/issue_2313_1/input.js
collapse_vars/issue_2313_2/input.js
collapse_vars/issue_2319_2/input.js
collapse_vars/issue_2364_6/input.js
collapse_vars/issue_2364_7/input.js
@ -162,7 +145,6 @@ collapse_vars/issue_2425_3/input.js
collapse_vars/issue_2437_2/input.js
collapse_vars/issue_2571_1/input.js
collapse_vars/issue_2571_2/input.js
collapse_vars/issue_27/input.js
collapse_vars/issue_2858/input.js
collapse_vars/issue_2873_1/input.js
collapse_vars/issue_2873_2/input.js
@ -205,16 +187,13 @@ conditionals/cond_3/input.js
conditionals/cond_4/input.js
conditionals/cond_5/input.js
conditionals/cond_7/input.js
conditionals/cond_7_1/input.js
conditionals/cond_8/input.js
conditionals/cond_8b/input.js
conditionals/cond_8c/input.js
conditionals/cond_9/input.js
conditionals/condition_symbol_matches_consequent/input.js
conditionals/delete_conditional_1/input.js
conditionals/delete_conditional_2/input.js
conditionals/equality_conditionals_false/input.js
conditionals/equality_conditionals_true/input.js
conditionals/hoist_decl/input.js
conditionals/ifs_1/input.js
conditionals/ifs_2/input.js
@ -241,7 +220,6 @@ dead_code/issue_2666/input.js
dead_code/issue_2701/input.js
dead_code/issue_2929/input.js
dead_code/throw_assignment/input.js
dead_code/try_catch_finally/input.js
debugger/drop_debugger/input.js
debugger/keep_debugger/input.js
defaults/defaults_false_evaluate_true/input.js
@ -249,7 +227,6 @@ defaults/defaults_true/input.js
defaults/defaults_true_conditionals_false/input.js
destructuring/destructure_empty_array_1/input.js
destructuring/destructure_empty_array_2/input.js
destructuring/destructure_empty_array_3/input.js
destructuring/destructuring_arrays/input.js
destructuring/destructuring_arrays_holes/input.js
destructuring/destructuring_assign_of_numeric_key/input.js
@ -260,6 +237,8 @@ destructuring/destructuring_expressions/input.js
destructuring/destructuring_letdef_in_loops/input.js
destructuring/destructuring_objects/input.js
destructuring/destructuring_objects_trailing_elision/input.js
destructuring/destructuring_remove_unused_1/input.js
destructuring/destructuring_remove_unused_2/input.js
destructuring/destructuring_vardef_in_loops/input.js
destructuring/empty_object_destructuring_1/input.js
destructuring/empty_object_destructuring_2/input.js
@ -269,9 +248,9 @@ destructuring/issue_2044_ecma_5/input.js
destructuring/issue_2044_ecma_5_beautify/input.js
destructuring/issue_2044_ecma_6/input.js
destructuring/issue_2044_ecma_6_beautify/input.js
destructuring/issue_2140/input.js
destructuring/issue_3205_1/input.js
destructuring/issue_t111_4/input.js
destructuring/mangle_destructuring_decl_array/input.js
destructuring/nested_destructuring_objects/input.js
destructuring/object_destructuring_may_need_parentheses/input.js
destructuring/reduce_vars/input.js
@ -287,20 +266,17 @@ destructuring/unused_destructuring_getter_side_effect_1/input.js
directives/class_directives_compression/input.js
directives/simple_statement_is_not_a_directive/input.js
drop_console/drop_console_1/input.js
drop_unused/assign_binding/input.js
drop_unused/assign_chain/input.js
drop_unused/cascade_drop_assign/input.js
drop_unused/const_assign/input.js
drop_unused/double_assign_3/input.js
drop_unused/drop_fnames/input.js
drop_unused/drop_toplevel_all/input.js
drop_unused/drop_toplevel_retain_array/input.js
drop_unused/drop_value/input.js
drop_unused/function_argument_modified_by_function_statement/input.js
drop_unused/iife/input.js
drop_unused/issue_1539/input.js
drop_unused/issue_1709/input.js
drop_unused/issue_2063/input.js
drop_unused/issue_2136_1/input.js
drop_unused/issue_3146_2/input.js
drop_unused/issue_805_1/input.js
drop_unused/issue_805_2/input.js
@ -311,7 +287,6 @@ drop_unused/issue_t161_top_retain_12/input.js
drop_unused/issue_t161_top_retain_13/input.js
drop_unused/issue_t161_top_retain_14/input.js
drop_unused/issue_t161_top_retain_2/input.js
drop_unused/issue_t161_top_retain_3/input.js
drop_unused/issue_t161_top_retain_5/input.js
drop_unused/issue_t161_top_retain_6/input.js
drop_unused/issue_t161_top_retain_7/input.js
@ -332,11 +307,10 @@ drop_unused/unused_keep_setter_arg/input.js
drop_unused/unused_nested_function/input.js
drop_unused/unused_seq_elements/input.js
drop_unused/unused_var_in_catch/input.js
drop_unused/used_var_in_catch/input.js
drop_unused/used_block_decls_in_catch/input.js
drop_unused/vardef_value/input.js
evaluate/Infinity_NaN_undefined_LHS/input.js
evaluate/and/input.js
evaluate/array_slice_index/input.js
evaluate/call_args/input.js
evaluate/call_args_drop_param/input.js
evaluate/delete_binary_1/input.js
@ -362,9 +336,9 @@ evaluate/pow_sequence_with_constants_and_parens/input.js
evaluate/pow_sequence_with_parens/input.js
evaluate/pow_sequence_with_parens_evaluated/input.js
evaluate/pow_with_right_side_evaluating_to_unary/input.js
evaluate/prop_function/input.js
evaluate/string_case/input.js
evaluate/unary_prefix/input.js
evaluate/unsafe_array/input.js
evaluate/unsafe_array_bad_index/input.js
evaluate/unsafe_constant/input.js
evaluate/unsafe_string/input.js
@ -385,7 +359,6 @@ export/export_default_anonymous_function_not_call/input.js
export/export_default_anonymous_generator/input.js
export/export_default_arrow/input.js
export/export_default_async_arrow_function/input.js
export/export_default_seq/input.js
export/issue_2038_1/input.js
export/issue_2129/input.js
export/issue_2131/input.js
@ -419,23 +392,27 @@ functions/issue_2737_1/input.js
functions/issue_2737_2/input.js
functions/issue_3054/input.js
functions/no_webkit/input.js
functions/non_ascii_function_identifier_name/input.js
functions/recursive_inline_1/input.js
functions/webkit/input.js
global_defs/conditional_chains/input.js
global_defs/expanded/input.js
global_defs/issue_1801/input.js
global_defs/issue_1986/input.js
global_defs/issue_2167/input.js
global_defs/issue_3217/input.js
global_defs/keyword/input.js
global_defs/mixed/input.js
global_defs/must_replace/input.js
global_defs/object/input.js
harmony/array_literal_with_spread_1/input.js
harmony/array_literal_with_spread_2a/input.js
harmony/array_literal_with_spread_2b/input.js
harmony/array_literal_with_spread_3a/input.js
harmony/array_literal_with_spread_3b/input.js
harmony/array_literal_with_spread_4a/input.js
harmony/array_literal_with_spread_4b/input.js
harmony/array_spread_of_sequence/input.js
harmony/arrow_function_parens/input.js
harmony/arrow_function_parens_2/input.js
harmony/class_expression_statement/input.js
harmony/class_expression_statement_unused/input.js
harmony/class_expression_statement_unused_toplevel/input.js
harmony/class_extends/input.js
harmony/class_extends_class/input.js
harmony/class_extends_function/input.js
harmony/class_extends_regex/input.js
@ -457,7 +434,6 @@ harmony/export_default_object_expression/input.js
harmony/export_module_statement/input.js
harmony/export_statement/input.js
harmony/export_statement_mangling/input.js
harmony/fat_arrow_as_param/input.js
harmony/format_methods/input.js
harmony/import_all_statement/input.js
harmony/import_meta/input.js
@ -535,18 +511,15 @@ issue_1041/const_pragma/input.js
issue_1041/not_const/input.js
issue_1044/issue_1044/input.js
issue_1105/Infinity_not_in_with_scope/input.js
issue_1105/check_drop_unused_in_peer_function/input.js
issue_1105/with_in_global_scope/input.js
issue_12/keep_name_of_getter/input.js
issue_12/setter_with_operator_keys/input.js
issue_1212/issue_1212_debug_false/input.js
issue_1212/issue_1212_debug_true/input.js
issue_143/tranformation_sort_order_equal/input.js
issue_143/tranformation_sort_order_greater_or_equal/input.js
issue_143/tranformation_sort_order_lesser_or_equal/input.js
issue_143/tranformation_sort_order_unequal/input.js
issue_1466/same_variable_in_multiple_forIn_sequences_const/input.js
issue_1466/same_variable_in_multiple_forIn_sequences_let/input.js
issue_1466/same_variable_in_multiple_forOf_sequences_const/input.js
issue_1466/same_variable_in_multiple_forOf_sequences_let/input.js
issue_1588/runtime_error/input.js
issue_1588/support_ie8/input.js
issue_1656/f7/input.js
@ -556,16 +529,8 @@ issue_1673/side_effects_finally/input.js
issue_1673/side_effects_label/input.js
issue_1673/side_effects_switch/input.js
issue_1704/mangle_catch_ie8/input.js
issue_1704/mangle_catch_redef_1/input.js
issue_1704/mangle_catch_redef_1_ie8/input.js
issue_1704/mangle_catch_redef_2/input.js
issue_1704/mangle_catch_redef_2_ie8/input.js
issue_1704/mangle_catch_redef_3_ie8_toplevel/input.js
issue_1704/mangle_catch_redef_3_toplevel/input.js
issue_1704/mangle_catch_var_ie8/input.js
issue_1733/function_catch_catch/input.js
issue_1733/function_catch_catch_ie8/input.js
issue_1770/numeric_literal/input.js
issue_1833/iife_for/input.js
issue_1833/iife_for_in/input.js
issue_1833/iife_while/input.js
@ -586,7 +551,8 @@ issue_2001/export_func_3/input.js
issue_2001/export_toplevel_1/input.js
issue_2001/export_toplevel_2/input.js
issue_208/do_not_update_lhs/input.js
issue_229/template_strings/input.js
issue_208/do_update_rhs/input.js
issue_208/mixed/input.js
issue_2652/insert_semicolon/input.js
issue_2652/unary_postfix/input.js
issue_267/issue_267/input.js
@ -618,12 +584,7 @@ issue_640/issue_1254_negate_iife_true/input.js
issue_640/negate_iife_3_off/input.js
issue_640/negate_iife_5_off/input.js
issue_751/negate_booleans_2/input.js
issue_782/dont_remove_this_binding_sequence/input.js
issue_782/remove_redundant_sequence_items/input.js
issue_926/template_strings/input.js
issue_973/this_binding_collapse_vars/input.js
issue_973/this_binding_conditionals/input.js
issue_973/this_binding_side_effects/input.js
issue_t50/issue_t50/input.js
issue_t50/issue_t50_const/input.js
issue_t50/issue_t50_let/input.js
@ -685,17 +646,14 @@ new/dot_parenthesis_2/input.js
new/new_constructor_with_unary_arguments/input.js
new/new_statement/input.js
new/new_statements_2/input.js
new/new_statements_3/input.js
new/new_with_assignement_expression/input.js
new/new_with_many_parameters/input.js
new/new_with_rewritten_true_value/input.js
new/new_with_unary_prefix/input.js
node_version/eval_let_6/input.js
nullish/nullish_coalescing_boolean_context/input.js
nullish/nullish_coalescing_mandatory_parens/input.js
nullish/nullish_coalescing_parens/input.js
nullish/simplify_nullish_coalescing/input.js
numbers/comparisons/input.js
numbers/compress_numbers/input.js
numbers/issue_1710/input.js
numbers/keep_numbers/input.js
@ -738,7 +696,6 @@ parameters/arrow_return/input.js
parameters/default_values_in_destructurings/input.js
parameters/destructuring_arguments_1/input.js
parameters/destructuring_arguments_2/input.js
parameters/destructuring_arguments_3/input.js
parameters/regression_arrow_functions_and_hoist/input.js
parameters/regression_assign_arrow_functions/input.js
properties/accessor_1/input.js
@ -750,11 +707,13 @@ properties/accessor_number/input.js
properties/accessor_string/input.js
properties/accessor_this/input.js
properties/array_hole/input.js
properties/evaluate_array_length/input.js
properties/evaluate_string_length/input.js
properties/first_256_chars_as_properties/input.js
properties/first_256_hex_chars_as_properties/input.js
properties/first_256_unicode_chars_as_properties/input.js
properties/issue_2208_1/input.js
properties/issue_2208_2/input.js
properties/issue_2208_6/input.js
properties/issue_2321/input.js
properties/issue_2893_1/input.js
properties/issue_2893_2/input.js
@ -776,7 +735,6 @@ properties/mangle_define_property_arg/input.js
properties/mangle_private_properties/input.js
properties/mangle_properties_which_matches_pattern/input.js
properties/native_prototype_lhs/input.js
pure_funcs/array/input.js
pure_funcs/assign/input.js
pure_funcs/issue_3065_1/input.js
pure_getters/chained/input.js
@ -802,6 +760,7 @@ pure_getters/issue_2313_5/input.js
pure_getters/issue_2313_7/input.js
pure_getters/issue_2678/input.js
pure_getters/issue_2938_1/input.js
pure_getters/issue_2938_2/input.js
pure_getters/set_immutable_2/input.js
pure_getters/set_immutable_4/input.js
reduce_vars/accessor_1/input.js
@ -824,23 +783,17 @@ reduce_vars/conditional_nested_3/input.js
reduce_vars/const_expr_1/input.js
reduce_vars/const_expr_2/input.js
reduce_vars/defun_assign/input.js
reduce_vars/defun_catch_1/input.js
reduce_vars/defun_catch_2/input.js
reduce_vars/defun_catch_3/input.js
reduce_vars/defun_catch_4/input.js
reduce_vars/defun_catch_5/input.js
reduce_vars/defun_catch_6/input.js
reduce_vars/defun_reference/input.js
reduce_vars/defun_single_use_loop/input.js
reduce_vars/defun_var_1/input.js
reduce_vars/defun_var_2/input.js
reduce_vars/delay_def_lhs/input.js
reduce_vars/do_while/input.js
reduce_vars/double_reference/input.js
reduce_vars/duplicate_lambda_defun_name_2/input.js
reduce_vars/escape_await/input.js
reduce_vars/escape_conditional/input.js
reduce_vars/escape_local_conditional/input.js
reduce_vars/escape_local_sequence/input.js
reduce_vars/escape_local_throw/input.js
reduce_vars/escape_throw/input.js
reduce_vars/escape_yield/input.js
@ -912,6 +865,7 @@ reduce_vars/multi_def_2/input.js
reduce_vars/multi_def_3/input.js
reduce_vars/obj_for_2/input.js
reduce_vars/obj_var_1/input.js
reduce_vars/obj_var_2/input.js
reduce_vars/perf_5/input.js
reduce_vars/pure_getters_1/input.js
reduce_vars/recursive_inlining_5/input.js
@ -935,17 +889,12 @@ reduce_vars/toplevel_on_loops_2/input.js
reduce_vars/toplevel_on_loops_3/input.js
reduce_vars/try_abort/input.js
reduce_vars/unary_delete/input.js
reduce_vars/unsafe_evaluate_array_1/input.js
reduce_vars/unsafe_evaluate_array_2/input.js
reduce_vars/unsafe_evaluate_array_3/input.js
reduce_vars/unsafe_evaluate_array_4/input.js
reduce_vars/unsafe_evaluate_array_5/input.js
reduce_vars/unsafe_evaluate_object_3/input.js
reduce_vars/unsafe_evaluate_side_effect_free_2/input.js
reduce_vars/unsafe_evaluate_unknown/input.js
reduce_vars/use_before_var/input.js
reduce_vars/var_assign_1/input.js
reduce_vars/var_assign_2/input.js
reduce_vars/var_assign_3/input.js
reduce_vars/var_assign_4/input.js
reduce_vars/var_assign_5/input.js
@ -956,45 +905,27 @@ regexp/regexp_1/input.js
regexp/regexp_2/input.js
regexp/regexp_simple/input.js
regexp/regexp_slashes/input.js
rename/function_catch_catch/input.js
rename/function_catch_catch_ie8/input.js
rename/function_iife_catch/input.js
rename/issue_2120_2/input.js
rename/mangle_catch_ie8/input.js
rename/mangle_catch_redef_1/input.js
rename/mangle_catch_redef_1_ie8/input.js
rename/mangle_catch_redef_2/input.js
rename/mangle_catch_redef_2_ie8/input.js
rename/mangle_catch_var_ie8/input.js
rename/mangle_catch_var_ie8_toplevel/input.js
rename/mangle_catch_var_toplevel/input.js
return_undefined/return_undefined/input.js
return_undefined/return_void/input.js
sandbox/console_log/input.js
sequences/cascade_assignment_in_return/input.js
sequences/delete_seq_1/input.js
sequences/delete_seq_2/input.js
sequences/delete_seq_3/input.js
sequences/delete_seq_4/input.js
sequences/delete_seq_5/input.js
sequences/delete_seq_6/input.js
sequences/forin/input.js
sequences/func_def_1/input.js
sequences/func_def_2/input.js
sequences/func_def_3/input.js
sequences/func_def_4/input.js
sequences/func_def_5/input.js
sequences/hoist_decl/input.js
sequences/hoist_defun/input.js
sequences/iife/input.js
sequences/issue_1685/input.js
sequences/issue_2062/input.js
sequences/issue_2313/input.js
sequences/lift_sequences_1/input.js
sequences/lift_sequences_2/input.js
sequences/lift_sequences_3/input.js
sequences/lift_sequences_4/input.js
sequences/lift_sequences_5/input.js
sequences/lift_sequences_6/input.js
sequences/limit_1/input.js
sequences/limit_2/input.js
@ -1005,10 +936,7 @@ sequences/make_sequences_4/input.js
sequences/negate_iife_for/input.js
sequences/reassign_const/input.js
sequences/side_effects/input.js
sequences/side_effects_cascade_1/input.js
sequences/side_effects_cascade_2/input.js
sequences/side_effects_cascade_3/input.js
sequences/unsafe_undefined/input.js
string_literal/issue_1929/input.js
string_literal/octal_escape_sequence/input.js
super/super_can_be_parsed/input.js
@ -1044,68 +972,51 @@ switch/keep_case/input.js
switch/keep_default/input.js
template_string/allow_chained_templates/input.js
template_string/allow_null_character/input.js
template_string/array_join/input.js
template_string/check_escaped_chars/input.js
template_string/coerce_to_string/input.js
template_string/do_not_optimize_tagged_template_1/input.js
template_string/do_not_optimize_tagged_template_2/input.js
template_string/equality/input.js
template_string/es2018_revision_of_template_escapes_1/input.js
template_string/escape_dollar_curly/input.js
template_string/evaluate_nested_templates/input.js
template_string/issue_1856/input.js
template_string/issue_1856_ascii_only/input.js
template_string/keep_raw_content_in_tagged_template/input.js
template_string/regex_1/input.js
template_string/regex_2/input.js
template_string/respect_inline_script/input.js
template_string/return_template_string_with_trailing_backslash/input.js
template_string/semicolons/input.js
template_string/sequence_1/input.js
template_string/sequence_2/input.js
template_string/side_effects/input.js
template_string/simple_string/input.js
template_string/tagged_call_with_invalid_escape/input.js
template_string/tagged_call_with_invalid_escape_2/input.js
template_string/tagged_template_function_inline_1/input.js
template_string/tagged_template_function_inline_2/input.js
template_string/tagged_template_function_inline_3/input.js
template_string/tagged_template_function_inline_4/input.js
template_string/tagged_template_function_inline_5/input.js
template_string/tagged_template_parens/input.js
template_string/tagged_template_valid_strict_legacy_octal/input.js
template_string/tagged_template_with_comment/input.js
template_string/tagged_template_with_ill_formed_unicode_escape/input.js
template_string/tagged_template_with_invalid_escape/input.js
template_string/template_concattenating_string/input.js
template_string/template_ending_with_newline/input.js
template_string/template_evaluate_undefined/input.js
template_string/template_literal_plus/input.js
template_string/template_literal_plus_grouping/input.js
template_string/template_starting_with_newline/input.js
template_string/template_string_evaluate_with_many_segments/input.js
template_string/template_string_prefixes/input.js
template_string/template_string_to_normal_string/input.js
template_string/template_string_with_constant_expression/input.js
template_string/template_string_with_many_segments/input.js
template_string/template_string_with_predefined_constants/input.js
template_string/template_strings/input.js
template_string/template_strings_ascii_only/input.js
template_string/template_strings_without_ascii_only/input.js
template_string/template_with_newline/input.js
transform/booleans_evaluate/input.js
transform/booleans_global_defs/input.js
transform/if_else_empty/input.js
try_catch/catch_destructuring_with_sequence/input.js
try_catch/issue_452/input.js
try_catch/parameterless_catch/input.js
try_catch/parent_scope_of_catch_block_is_not_the_try_block/input.js
typeof/duplicate_defun_arg_name/input.js
typeof/duplicate_lambda_arg_name/input.js
typeof/issue_1668/input.js
typeof/issue_2728_1/input.js
typeof/issue_2728_2/input.js
typeof/issue_2728_5/input.js
typeof/issue_2728_6/input.js
typeof/typeof_defun_1/input.js
typeof/typeof_defun_2/input.js
typeof/typeof_evaluation/input.js
typeof/typeof_in_boolean_context/input.js

View File

@ -49,7 +49,6 @@ collapse_vars/cascade_switch/input.js
collapse_vars/chained_1/input.js
collapse_vars/chained_2/input.js
collapse_vars/chained_3/input.js
collapse_vars/collapse_rhs_lhs_2/input.js
collapse_vars/collapse_vars_arguments/input.js
collapse_vars/collapse_vars_array/input.js
collapse_vars/collapse_vars_assignment/input.js
@ -64,7 +63,6 @@ collapse_vars/collapse_vars_lvalues/input.js
collapse_vars/collapse_vars_lvalues_drop_assign/input.js
collapse_vars/collapse_vars_misc1/input.js
collapse_vars/collapse_vars_object/input.js
collapse_vars/collapse_vars_properties/input.js
collapse_vars/collapse_vars_regexp/input.js
collapse_vars/collapse_vars_repeated/input.js
collapse_vars/collapse_vars_self_reference/input.js
@ -217,7 +215,6 @@ destructuring/empty_object_destructuring_4/input.js
destructuring/empty_object_destructuring_misc/input.js
destructuring/export_function_containing_destructuring_decl/input.js
destructuring/export_unreferenced_declarations_2/input.js
destructuring/issue_2140/input.js
destructuring/issue_3205_2/input.js
destructuring/issue_3205_3/input.js
destructuring/issue_3205_4/input.js
@ -278,7 +275,6 @@ drop_unused/issue_1968/input.js
drop_unused/issue_2063/input.js
drop_unused/issue_2105_1/input.js
drop_unused/issue_2105_2/input.js
drop_unused/issue_2136_1/input.js
drop_unused/issue_2136_2/input.js
drop_unused/issue_2136_3/input.js
drop_unused/issue_2163/input.js
@ -327,7 +323,6 @@ evaluate/issue_2231_3/input.js
evaluate/issue_2535_1/input.js
evaluate/issue_2535_2/input.js
evaluate/issue_2535_3/input.js
evaluate/issue_2822/input.js
evaluate/issue_2916_2/input.js
evaluate/issue_2919/input.js
evaluate/issue_2926_1/input.js
@ -339,7 +334,6 @@ evaluate/null_conditional_chain_eval/input.js
evaluate/positive_zero/input.js
evaluate/pow_sequence_with_parens_exact/input.js
evaluate/pow_with_number_constants/input.js
evaluate/prop_function/input.js
evaluate/prototype_function/input.js
evaluate/self_comparison_1/input.js
evaluate/self_comparison_2/input.js
@ -462,18 +456,7 @@ functions/unsafe_call_3/input.js
functions/unsafe_call_expansion_1/input.js
functions/unsafe_call_expansion_2/input.js
functions/use_before_init_in_loop/input.js
global_defs/conditional_chains/input.js
global_defs/expanded/input.js
global_defs/issue_1801/input.js
global_defs/issue_1986/input.js
global_defs/issue_2167/input.js
global_defs/issue_3217/input.js
global_defs/keyword/input.js
global_defs/mixed/input.js
global_defs/must_replace/input.js
global_defs/object/input.js
harmony/array_literal_with_spread_2b/input.js
harmony/array_literal_with_spread_3b/input.js
harmony/array_literal_with_spread_4a/input.js
harmony/array_literal_with_spread_4b/input.js
harmony/array_spread_of_sequence/input.js
@ -599,8 +582,6 @@ issue_1105/with_using_existing_variable_outside_scope/input.js
issue_12/keep_name_of_setter/input.js
issue_1202/mangle_keep_fnames_false/input.js
issue_1202/mangle_keep_fnames_true/input.js
issue_1212/issue_1212_debug_false/input.js
issue_1212/issue_1212_debug_true/input.js
issue_126/concatenate_rhs_strings/input.js
issue_1261/pure_function_calls/input.js
issue_1261/pure_function_calls_toplevel/input.js
@ -682,8 +663,6 @@ issue_2001/export_mangle_6/input.js
issue_203/compress_new_function/input.js
issue_203/compress_new_function_with_destruct/input.js
issue_203/compress_new_function_with_destruct_arrows/input.js
issue_208/do_update_rhs/input.js
issue_208/mixed/input.js
issue_22/return_with_no_value_in_if_body/input.js
issue_229/template_strings/input.js
issue_269/issue_269_1/input.js
@ -814,7 +793,6 @@ object/prop_func_to_concise_method_various/input.js
object/shorthand_properties/input.js
parameters/default_arguments/input.js
parameters/destructuring_arguments_3/input.js
properties/array_hole/input.js
properties/computed_property/input.js
properties/const_prop_assign_pure/input.js
properties/const_prop_assign_strict/input.js
@ -823,12 +801,9 @@ properties/dont_mangle_computed_property_2/input.js
properties/dot_properties/input.js
properties/dot_properties_es5/input.js
properties/evaluate_array_length/input.js
properties/evaluate_string_length/input.js
properties/issue_2208_1/input.js
properties/issue_2208_3/input.js
properties/issue_2208_4/input.js
properties/issue_2208_5/input.js
properties/issue_2208_6/input.js
properties/issue_2208_7/input.js
properties/issue_2208_8/input.js
properties/issue_2208_9/input.js
@ -1010,7 +985,6 @@ reduce_vars/named_function_with_recursive_ref_reuse/input.js
reduce_vars/obj_arg_1/input.js
reduce_vars/obj_arg_2/input.js
reduce_vars/obj_for_1/input.js
reduce_vars/obj_var_2/input.js
reduce_vars/passes/input.js
reduce_vars/perf_1/input.js
reduce_vars/perf_3/input.js
@ -1037,7 +1011,6 @@ reduce_vars/unsafe_evaluate_modified/input.js
reduce_vars/unsafe_evaluate_object_1/input.js
reduce_vars/unsafe_evaluate_object_2/input.js
reduce_vars/unsafe_evaluate_side_effect_free_1/input.js
reduce_vars/unsafe_evaluate_side_effect_free_2/input.js
reduce_vars/unused_modified/input.js
reduce_vars/var_assign_1/input.js
reduce_vars/var_assign_2/input.js
@ -1090,12 +1063,10 @@ template_string/equality/input.js
template_string/escape_dollar_curly/input.js
template_string/evaluate_nested_templates/input.js
template_string/regex_2/input.js
template_string/sequence_1/input.js
template_string/sequence_2/input.js
template_string/side_effects/input.js
template_string/simple_string/input.js
template_string/special_chars_in_string/input.js
template_string/tagged_template_function_inline_4/input.js
template_string/tagged_template_function_inline_5/input.js
template_string/tagged_template_parens/input.js
template_string/template_concattenating_string/input.js
@ -1103,7 +1074,6 @@ template_string/template_evaluate_undefined/input.js
template_string/template_literal_plus/input.js
template_string/template_literal_plus_grouping/input.js
template_string/template_string_with_predefined_constants/input.js
transform/booleans_global_defs/input.js
transform/condition_evaluate/input.js
transform/if_return/input.js
transform/label_if_break/input.js
@ -1111,7 +1081,6 @@ transform/while_if_break/input.js
try_catch/broken_safari_catch_scope/input.js
try_catch/broken_safari_catch_scope_caveat/input.js
try_catch/catch_destructuring_with_sequence/input.js
typeof/duplicate_lambda_arg_name/input.js
typeof/issue_2728_3/input.js
typeof/issue_2728_4/input.js
typeof/typeof_defun_1/input.js

View File

@ -2,10 +2,12 @@ function f(CONFIG) {
return CONFIG.VALUE;
}
function g() {
var CONFIG = { VALUE: 1 };
var CONFIG = {
VALUE: 1
};
return CONFIG.VALUE;
}
function h() {
return 42;
}
if ([0][0]) console.debug("foo");
if (0) console.debug("foo");

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_transforms_optimization"
repository = "https://github.com/swc-project/swc.git"
version = "0.20.0"
version = "0.20.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -190,6 +190,7 @@ impl SimplifyExpr {
});
}
self.changed = true;
let idx = match op {
KnownOp::Index(i) => i,
_ => unreachable!(),

View File

@ -1,87 +1,87 @@
{
"name": "@swc/core",
"version": "1.2.58",
"description": "Super-fast alternative for babel",
"homepage": "https://swc.rs",
"main": "./index.js",
"author": "강동윤 <kdy1997.dev@gmail.com>",
"license": "MIT",
"keywords": [
"swc",
"spack",
"babel",
"typescript",
"rust",
"webpack",
"tsc"
],
"engines": {
"node": ">=10"
},
"repository": {
"type": "git",
"url": "git+https://github.com/swc-project/swc.git"
},
"bugs": {
"url": "https://github.com/swc-project/swc/issues"
},
"napi": {
"name": "swc",
"triples": {
"defaults": true,
"additional": [
"x86_64-unknown-linux-musl",
"i686-pc-windows-msvc",
"aarch64-unknown-linux-gnu",
"armv7-unknown-linux-gnueabihf",
"aarch64-apple-darwin",
"aarch64-linux-android"
]
"name": "@swc/core",
"version": "1.2.59",
"description": "Super-fast alternative for babel",
"homepage": "https://swc.rs",
"main": "./index.js",
"author": "강동윤 <kdy1997.dev@gmail.com>",
"license": "MIT",
"keywords": [
"swc",
"spack",
"babel",
"typescript",
"rust",
"webpack",
"tsc"
],
"engines": {
"node": ">=10"
},
"repository": {
"type": "git",
"url": "git+https://github.com/swc-project/swc.git"
},
"bugs": {
"url": "https://github.com/swc-project/swc/issues"
},
"napi": {
"name": "swc",
"triples": {
"defaults": true,
"additional": [
"x86_64-unknown-linux-musl",
"i686-pc-windows-msvc",
"aarch64-unknown-linux-gnu",
"armv7-unknown-linux-gnueabihf",
"aarch64-apple-darwin",
"aarch64-linux-android"
]
}
},
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"dependencies": {
"@node-rs/helper": "^1.0.0"
},
"types": "./lib/index.d.ts",
"scripts": {
"artifacts": "napi artifacts --dist scripts/npm",
"prepublishOnly": "tsc -d && napi prepublish -p scripts/npm --tagstyle npm",
"build": "tsc -d && napi build --platform --release --cargo-name node --cargo-flags=\"-p node\"",
"build:dev": "tsc -d && napi build --platform --cargo-name node --cargo-flags=\"-p node\"",
"test": "jest node-swc/__tests__",
"version": "napi version -p scripts/npm"
},
"devDependencies": {
"@babel/core": "^7.13.16",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/plugin-proposal-decorators": "^7.13.15",
"@babel/plugin-proposal-object-rest-spread": "^7.13.8",
"@babel/preset-env": "^7.13.15",
"@babel/preset-react": "^7.13.13",
"@babel/preset-typescript": "^7.13.0",
"@babel/types": "^7.14.0",
"@napi-rs/cli": "^1.0.4",
"@swc/helpers": "^0.2.10",
"@types/browserslist": "^4.15.0",
"@types/jest": "^25.2.3",
"@types/node": "^14.14.41",
"axios": "^0.21.1",
"babel-plugin-transform-node-env-inline": "^0.4.3",
"browserslist": "^4.16.5",
"jest": "^23.6.0",
"lodash": "^4.17.21",
"progress": "^2.0.3",
"source-map": "^0.7.3",
"source-map-support": "^0.5.19",
"sourcemap-validator": "^1.1.1",
"typescript": "^4.2.0-beta"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/swc"
}
},
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"dependencies": {
"@node-rs/helper": "^1.0.0"
},
"types": "./lib/index.d.ts",
"scripts": {
"artifacts": "napi artifacts --dist scripts/npm",
"prepublishOnly": "tsc -d && napi prepublish -p scripts/npm --tagstyle npm",
"build": "tsc -d && napi build --platform --release --cargo-name node --cargo-flags=\"-p node\"",
"build:dev": "tsc -d && napi build --platform --cargo-name node --cargo-flags=\"-p node\"",
"test": "jest node-swc/__tests__",
"version": "napi version -p scripts/npm"
},
"devDependencies": {
"@babel/core": "^7.13.16",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/plugin-proposal-decorators": "^7.13.15",
"@babel/plugin-proposal-object-rest-spread": "^7.13.8",
"@babel/preset-env": "^7.13.15",
"@babel/preset-react": "^7.13.13",
"@babel/preset-typescript": "^7.13.0",
"@babel/types": "^7.14.0",
"@napi-rs/cli": "^1.0.4",
"@swc/helpers": "^0.2.10",
"@types/browserslist": "^4.15.0",
"@types/jest": "^25.2.3",
"@types/node": "^14.14.41",
"axios": "^0.21.1",
"babel-plugin-transform-node-env-inline": "^0.4.3",
"browserslist": "^4.16.5",
"jest": "^23.6.0",
"lodash": "^4.17.21",
"progress": "^2.0.3",
"source-map": "^0.7.3",
"source-map-support": "^0.5.19",
"sourcemap-validator": "^1.1.1",
"typescript": "^4.2.0-beta"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/swc"
}
}

View File

@ -4,8 +4,9 @@ description = "wasm module for swc"
edition = "2018"
license = "Apache-2.0/MIT"
name = "wasm"
publish = false
repository = "https://github.com/swc-project/swc.git"
version = "1.2.58"
version = "1.2.59"
[lib]
crate-type = ["cdylib"]