Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(es/minifier): Avoid paren when compressing ternary #9920

Merged
merged 1 commit into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ var f = function(e) {
return e.props.indexId === t;
}, h = function(e, t) {
var r = p(e), a = p(t);
return r && !a ? -1 : +(!r && !!a);
return r && !a ? -1 : !r && a ? 1 : 0;
};
export default function S(u) {
var o, l, S = u.indexName, v = u.initialState, x = u.searchClient, _ = u.resultsState, y = u.stalledSearchDelay, w = s(x, S, t({}, c));
Expand Down
23 changes: 1 addition & 22 deletions crates/swc_ecma_minifier/src/compress/pure/bools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use swc_ecma_utils::{ExprCtx, ExprExt, Type, Value};

use super::Pure;
use crate::{
compress::util::{is_pure_undefined, negate, negate_cost},
compress::util::{can_absorb_negate, is_eq, is_pure_undefined, negate, negate_cost},
option::CompressOptions,
util::make_bool,
};
Expand Down Expand Up @@ -81,27 +81,6 @@ impl Pure<'_> {
}

pub(super) fn optimize_negate_eq(&mut self, e: &mut Expr) {
fn is_eq(op: BinaryOp) -> bool {
matches!(op, op!("==") | op!("===") | op!("!=") | op!("!=="))
}

fn can_absorb_negate(e: &Expr, ctx: ExprCtx) -> bool {
match e {
Expr::Lit(_) => true,
Expr::Bin(BinExpr {
op: op!("&&") | op!("||"),
left,
right,
..
}) => can_absorb_negate(left, ctx) && can_absorb_negate(right, ctx),
Expr::Bin(BinExpr { op, .. }) if is_eq(*op) => true,
Expr::Unary(UnaryExpr {
op: op!("!"), arg, ..
}) => arg.get_type(ctx) == Value::Known(Type::Bool),
_ => false,
}
}

fn negate_eq(op: BinaryOp) -> BinaryOp {
match op {
op!("==") => op!("!="),
Expand Down
14 changes: 11 additions & 3 deletions crates/swc_ecma_minifier/src/compress/pure/conds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use swc_ecma_utils::{ExprExt, Type, Value};
use super::Pure;
#[cfg(feature = "debug")]
use crate::debug::dump;
use crate::{compress::util::negate_cost, util::make_bool};
use crate::{
compress::util::{can_absorb_negate, negate_cost},
util::make_bool,
};

impl Pure<'_> {
///
Expand Down Expand Up @@ -145,7 +148,10 @@ impl Pure<'_> {
(
Expr::Lit(Lit::Num(Number { value, .. })),
Expr::Lit(Lit::Num(Number { value: 0.0, .. })),
) if *value > 0.0 => {
) if *value > 0.0
&& (!cond.test.is_bin()
|| cond.test.get_type(self.expr_ctx) == Value::Known(Type::Bool)) =>
{
report_change!("conditionals: `foo ? num : 0` => `num * !!foo`");
self.changed = true;

Expand All @@ -163,7 +169,9 @@ impl Pure<'_> {
(
Expr::Lit(Lit::Num(Number { value: 0.0, .. })),
Expr::Lit(Lit::Num(Number { value, .. })),
) if *value > 0.0 => {
) if *value > 0.0
&& (!cond.test.is_bin() || can_absorb_negate(&cond.test, self.expr_ctx)) =>
{
report_change!("conditionals: `foo ? 0 : num` => `num * !foo`");
self.changed = true;

Expand Down
23 changes: 22 additions & 1 deletion crates/swc_ecma_minifier/src/compress/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{cmp::Ordering, f64};

use swc_common::{util::take::Take, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_utils::{number::JsNumber, ExprCtx, ExprExt, IdentUsageFinder, Value};
use swc_ecma_utils::{number::JsNumber, ExprCtx, ExprExt, IdentUsageFinder, Type, Value};
use swc_ecma_visit::{
noop_visit_mut_type, noop_visit_type, Visit, VisitMut, VisitMutWith, VisitWith,
};
Expand Down Expand Up @@ -744,3 +744,24 @@ fn cmp_num(a: f64, b: f64) -> Ordering {

a.partial_cmp(&b).unwrap()
}

pub(crate) fn is_eq(op: BinaryOp) -> bool {
matches!(op, op!("==") | op!("===") | op!("!=") | op!("!=="))
}

pub(crate) fn can_absorb_negate(e: &Expr, expr_ctx: ExprCtx) -> bool {
match e {
Expr::Lit(_) => true,
Expr::Bin(BinExpr {
op: op!("&&") | op!("||"),
left,
right,
..
}) => can_absorb_negate(left, expr_ctx) && can_absorb_negate(right, expr_ctx),
Expr::Bin(BinExpr { op, .. }) if is_eq(*op) => true,
Expr::Unary(UnaryExpr {
op: op!("!"), arg, ..
}) => arg.get_type(expr_ctx) == Value::Known(Type::Bool),
_ => false,
}
}
2 changes: 1 addition & 1 deletion crates/swc_ecma_minifier/tests/benches-full/d3.js
Original file line number Diff line number Diff line change
Expand Up @@ -5192,7 +5192,7 @@ function(global, factory) {
else stream.point(to[0], to[1]);
}
function corner(p, direction) {
return 1e-6 > abs$2(p[0] - x0) ? 3 * !(direction > 0) : 1e-6 > abs$2(p[0] - x1) ? direction > 0 ? 2 : 1 : 1e-6 > abs$2(p[1] - y0) ? +(direction > 0) : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
return 1e-6 > abs$2(p[0] - x0) ? direction > 0 ? 0 : 3 : 1e-6 > abs$2(p[0] - x1) ? direction > 0 ? 2 : 1 : 1e-6 > abs$2(p[1] - y0) ? +(direction > 0) : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
}
function compareIntersection(a, b) {
return comparePoint(a.x, b.x);
Expand Down
22 changes: 11 additions & 11 deletions crates/swc_ecma_minifier/tests/benches-full/echarts.js
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@
e.zrDelta = wheelDelta ? wheelDelta / 120 : -(e.detail || 0) / 3;
}
var button = e.button;
return null == e.which && void 0 !== button && MOUSE_EVENT_REG.test(e.type) && (e.which = 1 & button ? 1 : 2 & button ? 3 : 2 * !!(4 & button)), e;
return null == e.which && void 0 !== button && MOUSE_EVENT_REG.test(e.type) && (e.which = 1 & button ? 1 : 2 & button ? 3 : 4 & button ? 2 : 0), e;
}
function addEventListener(el, name, handler, opt) {
isDomLevel2 ? el.addEventListener(name, handler, opt) : el.attachEvent('on' + name, handler);
Expand Down Expand Up @@ -11392,8 +11392,8 @@
getBuilder(subBlock).planLayout(subBlock);
var subGapLevel = subBlock.__gapLevelBetweenSubBlocks; // If the some of the sub-blocks have some gaps (like 10px) inside, this block
// should use a larger gap (like 20px) to distinguish those sub-blocks.
subGapLevel >= thisGapLevelBetweenSubBlocks && (thisGapLevelBetweenSubBlocks = subGapLevel + +(!!thisBlockHasInnerGap && (!subGapLevel // If no header, always keep the sub gap level. Otherwise
|| 'section' === subBlock.type && !subBlock.noHeader)));
subGapLevel >= thisGapLevelBetweenSubBlocks && (thisGapLevelBetweenSubBlocks = subGapLevel + (!thisBlockHasInnerGap || subGapLevel // If no header, always keep the sub gap level. Otherwise
&& ('section' !== subBlock.type || subBlock.noHeader) ? 0 : 1));
}), fragment.__gapLevelBetweenSubBlocks = thisGapLevelBetweenSubBlocks;
},
build: function(ctx, fragment, topMarginForOuterGap, toolTipTextStyle) {
Expand Down Expand Up @@ -13611,7 +13611,7 @@
var prevEl = scope.prevEl;
prevEl || (forceSetStyle = forceSetTransform = !0);
var canBatchPath = el instanceof Path && el.autoBatch && (hasFill = styleHasFill(style = el.style), hasStroke = styleHasStroke(style), !(style.lineDash || !(+hasFill ^ +hasStroke) || hasFill && 'string' != typeof style.fill || hasStroke && 'string' != typeof style.stroke || style.strokePercent < 1 || style.strokeOpacity < 1 || style.fillOpacity < 1));
!forceSetTransform && (m1 = prevEl.transform, m && m1 ? m[0] === m1[0] && m[1] === m1[1] && m[2] === m1[2] && m[3] === m1[3] && m[4] === m1[4] && m[5] === m1[5] : +(!m && !m1)) ? canBatchPath || flushPathDrawn(ctx, scope) : (flushPathDrawn(ctx, scope), setContextTransform(ctx, el));
!forceSetTransform && (m1 = prevEl.transform, m && m1 ? m[0] === m1[0] && m[1] === m1[1] && m[2] === m1[2] && m[3] === m1[3] && m[4] === m1[4] && m[5] === m1[5] : m || m1 ? 0 : 1) ? canBatchPath || flushPathDrawn(ctx, scope) : (flushPathDrawn(ctx, scope), setContextTransform(ctx, el));
var style1 = getStyle(el, scope.inHover);
el instanceof Path ? (1 !== scope.lastDrawType && (forceSetStyle = !0, scope.lastDrawType = 1), bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetStyle, scope), canBatchPath && (scope.batchFill || scope.batchStroke) || ctx.beginPath(), function(ctx, el, style, inBatch) {
var hasStroke = styleHasStroke(style), hasFill = styleHasFill(style), strokePercent = style.strokePercent, strokePart = strokePercent < 1, firstDraw = !el.path;
Expand Down Expand Up @@ -16349,7 +16349,7 @@
}).start('circularInOut'), arc.animateShape(!0).when(1000, {
startAngle: 3 * PI$3 / 2
}).delay(300).start('circularInOut'), group.add(arc)), group.resize = function() {
var textWidth = textContent.getBoundingRect().width, r = opts.showSpinner ? opts.spinnerRadius : 0, cx = (api.getWidth() - 2 * r - 10 * (!!opts.showSpinner && !!textWidth) - textWidth) / 2 - (opts.showSpinner && textWidth ? 0 : 5 + textWidth / 2 // only show the text
var textWidth = textContent.getBoundingRect().width, r = opts.showSpinner ? opts.spinnerRadius : 0, cx = (api.getWidth() - 2 * r - (opts.showSpinner && textWidth ? 10 : 0) - textWidth) / 2 - (opts.showSpinner && textWidth ? 0 : 5 + textWidth / 2 // only show the text
) + (opts.showSpinner ? 0 : textWidth / 2 // only show the spinner
) + (textWidth ? 0 : r), cy = api.getHeight() / 2;
opts.showSpinner && arc.setShape({
Expand Down Expand Up @@ -19363,7 +19363,7 @@
* should be implemented in axis.
*/ function(axis) {
var labelModel, params = (labelModel = axis.getLabelModel(), {
axisRotate: axis.getRotate ? axis.getRotate() : 90 * (!!axis.isHorizontal && !axis.isHorizontal()),
axisRotate: axis.getRotate ? axis.getRotate() : axis.isHorizontal && !axis.isHorizontal() ? 90 : 0,
labelRotate: labelModel.get('rotate') || 0,
font: labelModel.getFont()
}), labelFormatter = makeLabelFormatter(axis), rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI, ordinalScale = axis.scale, ordinalExtent = ordinalScale.getExtent(), tickCount = ordinalScale.count();
Expand Down Expand Up @@ -28790,11 +28790,11 @@
// if totalLen is Longer createCurveness
var totalLen = getEdgeMapLengthWithKey(getKeyOfEdges(edge.node1, edge.node2, seriesModel), seriesModel) + getEdgeMapLengthWithKey(getKeyOfEdges(edge.node2, edge.node1, seriesModel), seriesModel);
createCurveness(seriesModel, totalLen), edge.lineStyle = edge.lineStyle || {};
var curKey = getKeyOfEdges(edge.node1, edge.node2, seriesModel), curvenessList = seriesModel.__curvenessList, parityCorrection = isArrayParam ? 0 : +!(totalLen % 2);
var curKey = getKeyOfEdges(edge.node1, edge.node2, seriesModel), curvenessList = seriesModel.__curvenessList, parityCorrection = isArrayParam ? 0 : totalLen % 2 ? 0 : 1;
if (edgeArray.isForward) return curvenessList[parityCorrection + edgeIndex];
var len = getEdgeMapLengthWithKey(getOppositeKey(curKey), seriesModel), resValue = curvenessList[edgeIndex + len + parityCorrection];
return needReverse ? // set as array may make the parity handle with the len of opposite
isArrayParam ? autoCurvenessParams && 0 === autoCurvenessParams[0] ? (len + parityCorrection) % 2 ? resValue : -resValue : (+!(len % 2) + parityCorrection) % 2 ? resValue : -resValue : (len + parityCorrection) % 2 ? resValue : -resValue : curvenessList[edgeIndex + len + parityCorrection];
isArrayParam ? autoCurvenessParams && 0 === autoCurvenessParams[0] ? (len + parityCorrection) % 2 ? resValue : -resValue : ((len % 2 ? 0 : 1) + parityCorrection) % 2 ? resValue : -resValue : (len + parityCorrection) % 2 ? resValue : -resValue : curvenessList[edgeIndex + len + parityCorrection];
}
function simpleLayout(seriesModel) {
var coordSys = seriesModel.coordinateSystem;
Expand Down Expand Up @@ -43534,7 +43534,7 @@
var mainBoundIdx = +('+' !== labelPosOpt);
toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx), toBound(labelsPosition, labelBound, viewBound, 1, 1 - mainBoundIdx);
} else {
var mainBoundIdx = +!(labelPosOpt >= 0);
var mainBoundIdx = labelPosOpt >= 0 ? 0 : 1;
toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx), labelsPosition[1] = mainPosition[1] + labelPosOpt;
}
function setOrigin(targetGroup) {
Expand Down Expand Up @@ -44955,7 +44955,7 @@
} // Fix auto color to real color
if ('auto' === itemStyle.fill && (itemStyle.fill = itemVisualStyle.fill), 'auto' === itemStyle.stroke && (itemStyle.stroke = itemVisualStyle.fill), 'auto' === lineStyle.stroke && (lineStyle.stroke = itemVisualStyle.fill), !isSelected) {
var borderWidth = legendModel.get('inactiveBorderWidth'), visualHasBorder = itemStyle[symbolType.indexOf('empty') > -1 ? 'fill' : 'stroke'];
itemStyle.lineWidth = 'auto' === borderWidth ? 2 * (itemVisualStyle.lineWidth > 0 && !!visualHasBorder) : itemStyle.lineWidth, itemStyle.fill = legendModel.get('inactiveColor'), itemStyle.stroke = legendModel.get('inactiveBorderColor'), lineStyle.stroke = legendLineStyle.get('inactiveColor'), lineStyle.lineWidth = legendLineStyle.get('inactiveWidth');
itemStyle.lineWidth = 'auto' === borderWidth ? itemVisualStyle.lineWidth > 0 && visualHasBorder ? 2 : 0 : itemStyle.lineWidth, itemStyle.fill = legendModel.get('inactiveColor'), itemStyle.stroke = legendModel.get('inactiveBorderColor'), lineStyle.stroke = legendLineStyle.get('inactiveColor'), lineStyle.lineWidth = legendLineStyle.get('inactiveWidth');
}
return {
itemStyle: itemStyle,
Expand Down Expand Up @@ -46866,7 +46866,7 @@
0
]
][realIndex], rect = getLayoutRect(layoutInput, ecSize, modelOption.padding);
return reals[+!((rect.margin[rParam[2]] || 0) + rect[rParam[0]] + 0.5 * rect[rParam[1]] < 0.5 * ecSize[rParam[1]])];
return reals[(rect.margin[rParam[2]] || 0) + rect[rParam[0]] + 0.5 * rect[rParam[1]] < 0.5 * ecSize[rParam[1]] ? 0 : 1];
}
/**
* Prepare dataIndex for outside usage, where dataIndex means rawIndex, and
Expand Down
2 changes: 1 addition & 1 deletion crates/swc_ecma_minifier/tests/benches-full/jquery.js
Original file line number Diff line number Diff line change
Expand Up @@ -2467,7 +2467,7 @@
which: function(event) {
var button = event.button;
return(// Add which for key events
null == event.which && rkeyEvent.test(event.type) ? null != event.charCode ? event.charCode : event.keyCode : !event.which && void 0 !== button && rmouseEvent.test(event.type) ? 1 & button ? 1 : 2 & button ? 3 : 2 * !!(4 & button) : event.which);
null == event.which && rkeyEvent.test(event.type) ? null != event.charCode ? event.charCode : event.keyCode : !event.which && void 0 !== button && rmouseEvent.test(event.type) ? 1 & button ? 1 : 2 & button ? 3 : 4 & button ? 2 : 0 : event.which);
}
}, jQuery.event.addProp), jQuery.each({
focus: "focusin",
Expand Down
2 changes: 1 addition & 1 deletion crates/swc_ecma_minifier/tests/benches-full/lodash.js
Original file line number Diff line number Diff line change
Expand Up @@ -3249,7 +3249,7 @@
// Exit early if metadata can't be merged.
if (isCommon || isCombo) {
1 & srcBitmask && (data[2] = source[2], // Set when currying a bound function.
newBitmask |= 4 * !(1 & bitmask));
newBitmask |= 1 & bitmask ? 0 : 4);
// Compose partial arguments.
var value = source[3];
if (value) {
Expand Down
4 changes: 2 additions & 2 deletions crates/swc_ecma_minifier/tests/benches-full/three.js
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ function(global, factory) {
uv.x = uv.x - Math.floor(uv.x);
break;
case 1001:
uv.x = +!(uv.x < 0);
uv.x = uv.x < 0 ? 0 : 1;
break;
case 1002:
1 === Math.abs(Math.floor(uv.x) % 2) ? uv.x = Math.ceil(uv.x) - uv.x : uv.x = uv.x - Math.floor(uv.x);
Expand All @@ -522,7 +522,7 @@ function(global, factory) {
uv.y = uv.y - Math.floor(uv.y);
break;
case 1001:
uv.y = +!(uv.y < 0);
uv.y = uv.y < 0 ? 0 : 1;
break;
case 1002:
1 === Math.abs(Math.floor(uv.y) % 2) ? uv.y = Math.ceil(uv.y) - uv.y : uv.y = uv.y - Math.floor(uv.y);
Expand Down
2 changes: 1 addition & 1 deletion crates/swc_ecma_minifier/tests/benches-full/victory.js
Original file line number Diff line number Diff line change
Expand Up @@ -18692,7 +18692,7 @@ object-assign
return target;
}
/*eslint no-magic-numbers: ["error", { "ignore": [0, 1, 2, 180] }]*/ var getArcPath = function(props) {
var cx = props.cx, cy = props.cy, r = props.r, startAngle = props.startAngle, endAngle = props.endAngle, closedPath = props.closedPath, halfAngle = Math.abs(endAngle - startAngle) / 2 + startAngle, x1 = cx + r * Math.cos(_victory_util_helpers__WEBPACK_IMPORTED_MODULE_3__.default.degreesToRadians(startAngle)), y1 = cy - r * Math.sin(_victory_util_helpers__WEBPACK_IMPORTED_MODULE_3__.default.degreesToRadians(startAngle)), x2 = cx + r * Math.cos(_victory_util_helpers__WEBPACK_IMPORTED_MODULE_3__.default.degreesToRadians(halfAngle)), y2 = cy - r * Math.sin(_victory_util_helpers__WEBPACK_IMPORTED_MODULE_3__.default.degreesToRadians(halfAngle)), x3 = cx + r * Math.cos(_victory_util_helpers__WEBPACK_IMPORTED_MODULE_3__.default.degreesToRadians(endAngle)), y3 = cy - r * Math.sin(_victory_util_helpers__WEBPACK_IMPORTED_MODULE_3__.default.degreesToRadians(endAngle)), largerArcFlag1 = +!(halfAngle - startAngle <= 180), largerArcFlag2 = +!(endAngle - halfAngle <= 180), arcStart = closedPath ? " M ".concat(cx, ", ").concat(cy, " L ").concat(x1, ", ").concat(y1) : "M ".concat(x1, ", ").concat(y1), arc1 = "A ".concat(r, ", ").concat(r, ", 0, ").concat(largerArcFlag1, ", 0, ").concat(x2, ", ").concat(y2), arc2 = "A ".concat(r, ", ").concat(r, ", 0, ").concat(largerArcFlag2, ", 0, ").concat(x3, ", ").concat(y3); // Always draw the path as two arcs so that complete circles may be rendered.
var cx = props.cx, cy = props.cy, r = props.r, startAngle = props.startAngle, endAngle = props.endAngle, closedPath = props.closedPath, halfAngle = Math.abs(endAngle - startAngle) / 2 + startAngle, x1 = cx + r * Math.cos(_victory_util_helpers__WEBPACK_IMPORTED_MODULE_3__.default.degreesToRadians(startAngle)), y1 = cy - r * Math.sin(_victory_util_helpers__WEBPACK_IMPORTED_MODULE_3__.default.degreesToRadians(startAngle)), x2 = cx + r * Math.cos(_victory_util_helpers__WEBPACK_IMPORTED_MODULE_3__.default.degreesToRadians(halfAngle)), y2 = cy - r * Math.sin(_victory_util_helpers__WEBPACK_IMPORTED_MODULE_3__.default.degreesToRadians(halfAngle)), x3 = cx + r * Math.cos(_victory_util_helpers__WEBPACK_IMPORTED_MODULE_3__.default.degreesToRadians(endAngle)), y3 = cy - r * Math.sin(_victory_util_helpers__WEBPACK_IMPORTED_MODULE_3__.default.degreesToRadians(endAngle)), largerArcFlag1 = halfAngle - startAngle <= 180 ? 0 : 1, largerArcFlag2 = endAngle - halfAngle <= 180 ? 0 : 1, arcStart = closedPath ? " M ".concat(cx, ", ").concat(cy, " L ").concat(x1, ", ").concat(y1) : "M ".concat(x1, ", ").concat(y1), arc1 = "A ".concat(r, ", ").concat(r, ", 0, ").concat(largerArcFlag1, ", 0, ").concat(x2, ", ").concat(y2), arc2 = "A ".concat(r, ", ").concat(r, ", 0, ").concat(largerArcFlag2, ", 0, ").concat(x3, ", ").concat(y3); // Always draw the path as two arcs so that complete circles may be rendered.
return "".concat(arcStart, " ").concat(arc1, " ").concat(arc2, " ").concat(closedPath ? "Z" : "");
}, evaluateProps = function(props) {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13368,7 +13368,7 @@
return d;
}
function Wc(a) {
return 0 != (a = -1073741825 & a.pendingLanes) ? a : 1073741824 * !!(1073741824 & a);
return 0 != (a = -1073741825 & a.pendingLanes) ? a : 1073741824 & a ? 1073741824 : 0;
}
function Xc(a, b) {
var a1, a2, a3, a4, a5;
Expand Down
Loading
Loading