Skip to content

Commit

Permalink
fix(es/minifer): Fix bugs (#2397)
Browse files Browse the repository at this point in the history
swc_ecma_codegen:
 - Fix sourcemap of `export` tokens.
 - Fix codegen of numeric operands in left of a binary expression.
 - Fix codegen of unary operations.

swc_ecma_minifier:
 - Visit `AssignPatProp.valie`.
 - Move `inline_prevented` to analyzer.
 - Add `Ctx.dont_invoke_iife`.
 - `iife`: Check for `arugments`

swc:
 - `inline_sources_content`: true by default for `minify()`.
  • Loading branch information
kdy1 authored Oct 11, 2021
1 parent f560789 commit 98cc79a
Show file tree
Hide file tree
Showing 38 changed files with 1,459 additions and 486 deletions.
243 changes: 122 additions & 121 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc"
repository = "https://github.com/swc-project/swc.git"
version = "0.67.0"
version = "0.67.1"

[lib]
name = "swc"
Expand Down
2 changes: 1 addition & 1 deletion ecmascript/codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"]
license = "Apache-2.0/MIT"
name = "swc_ecma_codegen"
repository = "https://github.com/swc-project/swc.git"
version = "0.74.3"
version = "0.74.4"

[dependencies]
bitflags = "1"
Expand Down
78 changes: 59 additions & 19 deletions ecmascript/codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,38 +138,60 @@ where
}

#[emitter]
fn emit_export_decl(&mut self, node: &ExportDecl) -> Result {
keyword!("export");
fn emit_export_decl(&mut self, n: &ExportDecl) -> Result {
{
let span = if n.span.is_dummy() {
DUMMY_SP
} else {
Span::new(n.span.lo, n.span.lo + BytePos(6), Default::default())
};
keyword!(span, "export");
}
space!();
emit!(node.decl);
emit!(n.decl);
}

#[emitter]
fn emit_export_default_expr(&mut self, node: &ExportDefaultExpr) -> Result {
keyword!("export");
fn emit_export_default_expr(&mut self, n: &ExportDefaultExpr) -> Result {
{
let span = if n.span.is_dummy() {
DUMMY_SP
} else {
Span::new(n.span.lo, n.span.lo + BytePos(6), Default::default())
};
keyword!(span, "export");
}

space!();
keyword!("default");
{
let starts_with_alpha_num = node.expr.starts_with_alpha_num();
let starts_with_alpha_num = n.expr.starts_with_alpha_num();
if starts_with_alpha_num {
space!();
} else {
formatting_space!();
}
emit!(node.expr);
emit!(n.expr);
}
formatting_semi!();
}

#[emitter]
fn emit_export_default_decl(&mut self, node: &ExportDefaultDecl) -> Result {
self.emit_leading_comments_of_span(node.span(), false)?;
fn emit_export_default_decl(&mut self, n: &ExportDefaultDecl) -> Result {
self.emit_leading_comments_of_span(n.span(), false)?;

keyword!("export");
{
let span = if n.span.is_dummy() {
DUMMY_SP
} else {
Span::new(n.span.lo, n.span.lo + BytePos(6), Default::default())
};
keyword!(span, "export");
}
space!();
keyword!("default");
space!();
match node.decl {
match n.decl {
DefaultDecl::Class(ref n) => emit!(n),
DefaultDecl::Fn(ref n) => emit!(n),
DefaultDecl::TsInterfaceDecl(ref n) => emit!(n),
Expand Down Expand Up @@ -347,7 +369,15 @@ where
},
);

keyword!("export");
{
let span = if node.span.is_dummy() {
DUMMY_SP
} else {
Span::new(node.span.lo, node.span.lo + BytePos(6), Default::default())
};
keyword!(span, "export");
}

formatting_space!();
if let Some(spec) = namespace_spec {
emit!(spec);
Expand Down Expand Up @@ -856,12 +886,7 @@ where
}),
) => false,

(_, Expr::Update(UpdateExpr { prefix: true, .. }) | Expr::Unary(..)) => true,

(_, Expr::Bin(BinExpr { left, .. })) => match &**left {
Expr::Update(UpdateExpr { prefix: true, .. }) | Expr::Unary(..) => true,
_ => false,
},
(_, r) if is_space_require_before_rhs(r) => true,

_ => false,
}
Expand Down Expand Up @@ -2799,7 +2824,7 @@ fn should_emit_whitespace_before_operand(node: &UnaryExpr) -> bool {
_ => {}
}

match *node.arg {
match &*node.arg {
Expr::Update(UpdateExpr {
op: op!("++"),
prefix: true,
Expand All @@ -2818,6 +2843,9 @@ fn should_emit_whitespace_before_operand(node: &UnaryExpr) -> bool {
op: op!(unary, "-"),
..
}) if node.op == op!(unary, "-") => true,

Expr::Lit(Lit::Num(v)) if v.value.is_sign_negative() && node.op == op!(unary, "-") => true,

_ => false,
}
}
Expand Down Expand Up @@ -3201,3 +3229,15 @@ fn handle_invalid_unicodes(s: &str) -> Cow<str> {

Cow::Owned(s.replace("\\\0", "\\"))
}

fn is_space_require_before_rhs(rhs: &Expr) -> bool {
match rhs {
Expr::Lit(Lit::Num(v)) if v.value.is_sign_negative() => true,

Expr::Update(UpdateExpr { prefix: true, .. }) | Expr::Unary(..) => true,

Expr::Bin(BinExpr { left, .. }) => is_space_require_before_rhs(&left),

_ => false,
}
}
28 changes: 28 additions & 0 deletions ecmascript/codegen/tests/fixture/vercel/d3-color/1/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import define, { extend } from "./define.js";
import { Color, rgbConvert, Rgb, darker, brighter } from "./color.js";
import { deg2rad, rad2deg } from "./math.js";
var A = -0.14861, B = 1.78277, C = -0.29227, D = -0.90649, E = 1.97294, ED = E * D, EB = E * B, BC_DA = B * C - D * A;
function cubehelixConvert(o) {
if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
o instanceof Rgb || (o = rgbConvert(o));
var r = o.r / 255, g = o.g / 255, b = o.b / 255, l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB), bl = b - l, k = (E * (g - l) - C * bl) / D, s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;
return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
}
export default function cubehelix(h, s, l, opacity) {
return 1 === arguments.length ? cubehelixConvert(h) : new Cubehelix(h, s, l, null == opacity ? 1 : opacity);
};
export function Cubehelix(h, s, l, opacity) {
this.h = +h, this.s = +s, this.l = +l, this.opacity = +opacity;
}
define(Cubehelix, cubehelix, extend(Color, {
brighter: function (k) {
return k = null == k ? brighter : Math.pow(brighter, k), new Cubehelix(this.h, this.s, this.l * k, this.opacity);
},
darker: function (k) {
return k = null == k ? darker : Math.pow(darker, k), new Cubehelix(this.h, this.s, this.l * k, this.opacity);
},
rgb: function () {
var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad, l = +this.l, a = isNaN(this.s) ? 0 : this.s * l * (1 - l), cosh = Math.cos(h), sinh = Math.sin(h);
return new Rgb(255 * (l + a * (A * cosh + B * sinh)), 255 * (l + a * (C * cosh + D * sinh)), 255 * (l + a * (E * cosh)), this.opacity);
}
}));
29 changes: 29 additions & 0 deletions ecmascript/codegen/tests/fixture/vercel/d3-color/1/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import define, { extend } from "./define.js";
import { Color, rgbConvert, Rgb, darker, brighter } from "./color.js";
import { deg2rad, rad2deg } from "./math.js";
var A = -0.14861, B = 1.78277, C = -0.29227, D = -0.90649, E = 1.97294, ED = E * D, EB = E * B, BC_DA = B * C - D * A;
function cubehelixConvert(o) {
if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
o instanceof Rgb || (o = rgbConvert(o));
var r = o.r / 255, g = o.g / 255, b = o.b / 255, l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB), bl = b - l, k = (E * (g - l) - C * bl) / D, s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;
return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
}
export default function cubehelix(h, s, l, opacity) {
return 1 === arguments.length ? cubehelixConvert(h) : new Cubehelix(h, s, l, null == opacity ? 1 : opacity);
};
;
export function Cubehelix(h, s, l, opacity) {
this.h = +h, this.s = +s, this.l = +l, this.opacity = +opacity;
}
define(Cubehelix, cubehelix, extend(Color, {
brighter: function(k) {
return k = null == k ? brighter : Math.pow(brighter, k), new Cubehelix(this.h, this.s, this.l * k, this.opacity);
},
darker: function(k) {
return k = null == k ? darker : Math.pow(darker, k), new Cubehelix(this.h, this.s, this.l * k, this.opacity);
},
rgb: function() {
var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad, l = +this.l, a = isNaN(this.s) ? 0 : this.s * l * (1 - l), cosh = Math.cos(h), sinh = Math.sin(h);
return new Rgb(255 * (l + a * (A * cosh + B * sinh)), 255 * (l + a * (C * cosh + D * sinh)), 255 * (l + a * (E * cosh)), this.opacity);
}
}));

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ecmascript/minifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ 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.37.1"
version = "0.37.2"

[features]
debug = ["backtrace"]
Expand Down
44 changes: 33 additions & 11 deletions ecmascript/minifier/src/analyzer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
util::{can_end_conditionally, idents_used_by, now},
};
use std::time::Instant;
use swc_atoms::JsWord;
use swc_atoms::{js_word, JsWord};
use swc_common::{
collections::{AHashMap, AHashSet},
SyntaxContext, DUMMY_SP,
Expand Down Expand Up @@ -733,18 +733,40 @@ where
}

fn visit_var_declarator(&mut self, e: &VarDeclarator, _: &dyn Node) {
let ctx = Ctx {
in_pat_of_var_decl: true,
in_pat_of_var_decl_with_init: e.init.is_some(),
in_var_decl_with_no_side_effect_for_member_access: match e.init.as_deref() {
Some(Expr::Array(..) | Expr::Lit(..)) => true,
_ => false,
},
..self.ctx
let prevent_inline = match &e.name {
Pat::Ident(BindingIdent {
id:
Ident {
sym: js_word!("arguments"),
..
},
..
}) => true,
_ => false,
};
e.name.visit_with(e, &mut *self.with_ctx(ctx));
{
let ctx = Ctx {
inline_prevented: self.ctx.inline_prevented || prevent_inline,
in_pat_of_var_decl: true,
in_pat_of_var_decl_with_init: e.init.is_some(),
in_var_decl_with_no_side_effect_for_member_access: match e.init.as_deref() {
Some(Expr::Array(..) | Expr::Lit(..)) => true,
_ => false,
},
..self.ctx
};
e.name.visit_with(e, &mut *self.with_ctx(ctx));
}

e.init.visit_with(e, self);
{
let ctx = Ctx {
inline_prevented: self.ctx.inline_prevented || prevent_inline,
in_pat_of_var_decl: false,
..self.ctx
};

e.init.visit_with(e, &mut *self.with_ctx(ctx));
}
}

fn visit_while_stmt(&mut self, n: &WhileStmt, _: &dyn Node) {
Expand Down
17 changes: 11 additions & 6 deletions ecmascript/minifier/src/compress/optimize/iife.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,12 +263,9 @@ where
if cfg!(feature = "debug") {
tracing::trace!("inline: inline_vars_in_node");
}
let ctx = Ctx {
inline_prevented: false,
..self.ctx
};

let orig_vars = replace(&mut self.state.vars_for_inlining, vars);
n.visit_mut_with(&mut *self.with_ctx(ctx));
n.visit_mut_with(self);
self.state.vars_for_inlining = orig_vars;
}

Expand Down Expand Up @@ -316,7 +313,7 @@ where
ExprOrSuper::Expr(e) => &mut **e,
};

if self.ctx.inline_prevented {
if self.ctx.dont_invoke_iife {
tracing::trace!("iife: [x] Inline is prevented");
return;
}
Expand Down Expand Up @@ -531,6 +528,14 @@ where
..
})) => {
if decls.iter().any(|decl| match decl.name {
Pat::Ident(BindingIdent {
id:
Ident {
sym: js_word!("arguments"),
..
},
..
}) => true,
Pat::Ident(..) => false,
_ => true,
}) {
Expand Down
5 changes: 1 addition & 4 deletions ecmascript/minifier/src/compress/optimize/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,10 +535,6 @@ where

/// Actually inlines variables.
pub(super) fn inline(&mut self, e: &mut Expr) {
if self.ctx.inline_prevented {
return;
}

match e {
Expr::Ident(i) => {
//
Expand Down Expand Up @@ -577,6 +573,7 @@ where
return;
}

// Check witohut cloning
if let Some(value) = self.state.vars_for_inlining.get(&i.to_id()) {
if self.ctx.is_exact_lhs_of_assign && !is_valid_for_lhs(&value) {
return;
Expand Down
Loading

0 comments on commit 98cc79a

Please sign in to comment.