Skip to content

Commit

Permalink
fix(es/minifier): Visit RHS while hoisting properties (#9032)
Browse files Browse the repository at this point in the history
**Description:**

Handles 

```js
var FRUITS = { MANGO: "mango" }, getMangoLabel = (label) => label[FRUITS.MANGO];
```

while hoisting properties. In the code above, the initializer of the second variable declarator should be visited after hoisting the first variable declarator. Otherwise `FRUITS.MANGO` cannot be handled.


**Related issue:**

 - Closes #9030
  • Loading branch information
kdy1 authored Jun 11, 2024
1 parent 328cb4b commit cb16994
Show file tree
Hide file tree
Showing 24 changed files with 320 additions and 286 deletions.
5 changes: 5 additions & 0 deletions crates/swc_ecma_minifier/src/compress/optimize/props.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use swc_common::{util::take::Take, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_utils::{contains_this_expr, private_ident, prop_name_eq, ExprExt};
use swc_ecma_visit::VisitMutWith;

use super::{unused::PropertyAccessOpts, Optimizer};
use crate::util::deeply_contains_this_expr;
Expand All @@ -23,6 +24,10 @@ impl Optimizer<'_> {

let mut new = Vec::with_capacity(n.len());
for mut n in n.take() {
if let Some(init) = &mut n.init {
init.visit_mut_with(self);
}

let new_vars = self.hoist_props_of_var(&mut n);

if let Some(new_vars) = new_vars {
Expand Down
30 changes: 15 additions & 15 deletions crates/swc_ecma_minifier/tests/benches-full/echarts.js
Original file line number Diff line number Diff line change
Expand Up @@ -9609,7 +9609,7 @@
], upstreamSignList = [];
assert(resultSourceList && upstreamSignList), this._setLocalSource(resultSourceList, upstreamSignList);
}, SourceManager.prototype._applyTransform = function(upMgrList) {
var encodeDefine, source, sourceList, datasetModel = this._sourceHost, transformOption = datasetModel.get('transform', !0), fromTransformResult = datasetModel.get('fromTransformResult', !0);
var source, encodeDefine, sourceList, datasetModel = this._sourceHost, transformOption = datasetModel.get('transform', !0), fromTransformResult = datasetModel.get('fromTransformResult', !0);
assert(null != fromTransformResult || null != transformOption), null != fromTransformResult && 1 !== upMgrList.length && doThrow('When using `fromTransformResult`, there should be only one upstream dataset');
var upSourceList = [], upstreamSignList = [];
return (each(upMgrList, function(upMgr) {
Expand Down Expand Up @@ -15070,10 +15070,10 @@
return null == precision ? precision = getPrecisionSafe(data.value) || 0 : 'auto' === precision && (precision = this._intervalPrecision), addCommas(round(data.value, precision, !0));
}, IntervalScale.prototype.niceTicks = function(splitNumber, minInterval, maxInterval) {
splitNumber = splitNumber || 5;
var splitNumber1, result, span, interval, precision, extent = this._extent, span1 = extent[1] - extent[0];
var splitNumber1, result, span, interval, precision, niceTickExtent, extent = this._extent, span1 = extent[1] - extent[0];
if (isFinite(span1)) {
span1 < 0 && (span1 = -span1, extent.reverse());
var niceTickExtent, result1 = (splitNumber1 = splitNumber, result = {}, span = extent[1] - extent[0], interval = result.interval = nice(span / splitNumber1, !0), null != minInterval && interval < minInterval && (interval = result.interval = minInterval), null != maxInterval && interval > maxInterval && (interval = result.interval = maxInterval), precision = result.intervalPrecision = getPrecisionSafe(interval) + 2, isFinite((niceTickExtent = result.niceTickExtent = [
var result1 = (splitNumber1 = splitNumber, result = {}, span = extent[1] - extent[0], interval = result.interval = nice(span / splitNumber1, !0), null != minInterval && interval < minInterval && (interval = result.interval = minInterval), null != maxInterval && interval > maxInterval && (interval = result.interval = maxInterval), precision = result.intervalPrecision = getPrecisionSafe(interval) + 2, isFinite((niceTickExtent = result.niceTickExtent = [
round(Math.ceil(extent[0] / interval) * interval, precision),
round(Math.floor(extent[1] / interval) * interval, precision)
])[0]) || (niceTickExtent[0] = extent[0]), isFinite(niceTickExtent[1]) || (niceTickExtent[1] = extent[1]), clamp(niceTickExtent, 0, extent), clamp(niceTickExtent, 1, extent), niceTickExtent[0] > niceTickExtent[1] && (niceTickExtent[0] = niceTickExtent[1]), result);
Expand Down Expand Up @@ -16083,7 +16083,7 @@
return ('category' === this.type ? (result = makeCategoryLabelsActually(this, labelModel = this.getLabelModel()), !labelModel.get('show') || this.scale.isBlank() ? {
labels: [],
labelCategoryInterval: result.labelCategoryInterval
} : result) : (axis = this, ticks = axis.scale.getTicks(), labelFormatter = makeLabelFormatter(axis), {
} : result) : (ticks = (axis = this).scale.getTicks(), labelFormatter = makeLabelFormatter(axis), {
labels: map(ticks, function(tick, idx) {
return {
formattedLabel: labelFormatter(tick, idx),
Expand Down Expand Up @@ -19281,13 +19281,13 @@
this._ctx = null;
for(var i = 0; i < points.length;){
var x = points[i++], y = points[i++];
!(isNaN(x) || isNaN(y)) && (!this.softClipShape || this.softClipShape.contain(x, y)) && (symbolProxyShape.x = x - size[0] / 2, symbolProxyShape.y = y - size[1] / 2, symbolProxyShape.width = size[0], symbolProxyShape.height = size[1], symbolProxy.buildPath(path, symbolProxyShape, !0));
isNaN(x) || isNaN(y) || this.softClipShape && !this.softClipShape.contain(x, y) || (symbolProxyShape.x = x - size[0] / 2, symbolProxyShape.y = y - size[1] / 2, symbolProxyShape.width = size[0], symbolProxyShape.height = size[1], symbolProxy.buildPath(path, symbolProxyShape, !0));
}
}, LargeSymbolPath.prototype.afterBrush = function() {
var shape = this.shape, points = shape.points, size = shape.size, ctx = this._ctx;
if (ctx) for(var i = 0; i < points.length;){
var x = points[i++], y = points[i++];
!(isNaN(x) || isNaN(y)) && (!this.softClipShape || this.softClipShape.contain(x, y)) && ctx.fillRect(x - size[0] / 2, y - size[1] / 2, size[0], size[1]);
isNaN(x) || isNaN(y) || this.softClipShape && !this.softClipShape.contain(x, y) || ctx.fillRect(x - size[0] / 2, y - size[1] / 2, size[0], size[1]);
}
}, LargeSymbolPath.prototype.findDataIndex = function(x, y) {
for(var shape = this.shape, points = shape.points, size = shape.size, w = Math.max(size[0], 4), h = Math.max(size[1], 4), idx = points.length / 2 - 1; idx >= 0; idx--){
Expand Down Expand Up @@ -20188,11 +20188,11 @@
axisName: function(opt, axisModel, group, transformGroup) {
var labelLayout, axisNameAvailableWidth, name = retrieve(opt.axisName, axisModel.get('name'));
if (name) {
var rotation, textAlign, textVerticalAlign, rotationDiff, inverse, onLeft, nameLocation = axisModel.get('nameLocation'), nameDirection = opt.nameDirection, textStyleModel = axisModel.getModel('nameTextStyle'), gap = axisModel.get('nameGap') || 0, extent = axisModel.axis.getExtent(), gapSignal = extent[0] > extent[1] ? -1 : 1, pos = [
var textAlign, textVerticalAlign, rotationDiff, inverse, onLeft, nameLocation = axisModel.get('nameLocation'), nameDirection = opt.nameDirection, textStyleModel = axisModel.getModel('nameTextStyle'), gap = axisModel.get('nameGap') || 0, extent = axisModel.axis.getExtent(), gapSignal = extent[0] > extent[1] ? -1 : 1, pos = [
'start' === nameLocation ? extent[0] - gapSignal * gap : 'end' === nameLocation ? extent[1] + gapSignal * gap : (extent[0] + extent[1]) / 2,
isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * gap : 0
], nameRotation = axisModel.get('nameRotate');
null != nameRotation && (nameRotation = nameRotation * PI$5 / 180), isNameLocationCenter(nameLocation) ? labelLayout = AxisBuilder.innerTextLayout(opt.rotation, null != nameRotation ? nameRotation : opt.rotation, nameDirection) : (rotation = opt.rotation, rotationDiff = remRadian((nameRotation || 0) - rotation), inverse = extent[0] > extent[1], onLeft = 'start' === nameLocation && !inverse || 'start' !== nameLocation && inverse, isRadianAroundZero(rotationDiff - PI$5 / 2) ? (textVerticalAlign = onLeft ? 'bottom' : 'top', textAlign = 'center') : isRadianAroundZero(rotationDiff - 1.5 * PI$5) ? (textVerticalAlign = onLeft ? 'top' : 'bottom', textAlign = 'center') : (textVerticalAlign = 'middle', textAlign = rotationDiff < 1.5 * PI$5 && rotationDiff > PI$5 / 2 ? onLeft ? 'left' : 'right' : onLeft ? 'right' : 'left'), labelLayout = {
null != nameRotation && (nameRotation = nameRotation * PI$5 / 180), isNameLocationCenter(nameLocation) ? labelLayout = AxisBuilder.innerTextLayout(opt.rotation, null != nameRotation ? nameRotation : opt.rotation, nameDirection) : (rotationDiff = remRadian((nameRotation || 0) - opt.rotation), inverse = extent[0] > extent[1], onLeft = 'start' === nameLocation && !inverse || 'start' !== nameLocation && inverse, isRadianAroundZero(rotationDiff - PI$5 / 2) ? (textVerticalAlign = onLeft ? 'bottom' : 'top', textAlign = 'center') : isRadianAroundZero(rotationDiff - 1.5 * PI$5) ? (textVerticalAlign = onLeft ? 'top' : 'bottom', textAlign = 'center') : (textVerticalAlign = 'middle', textAlign = rotationDiff < 1.5 * PI$5 && rotationDiff > PI$5 / 2 ? onLeft ? 'left' : 'right' : onLeft ? 'right' : 'left'), labelLayout = {
rotation: rotationDiff,
textAlign: textAlign,
textVerticalAlign: textVerticalAlign
Expand Down Expand Up @@ -22924,19 +22924,19 @@
],
[
x + itemWidth,
y + itemHeight
0 + itemHeight
],
[
head ? x : x - 5,
y + itemHeight
0 + itemHeight
]
];
return tail || points.splice(2, 0, [
x + itemWidth + 5,
y + itemHeight / 2
0 + itemHeight / 2
]), head || points.push([
x,
y + itemHeight / 2
0 + itemHeight / 2
]), points;
}(lastX, 0, itemWidth, height, i === renderList.length - 1, 0 === i)
},
Expand Down Expand Up @@ -28681,7 +28681,7 @@
]);
}, LinesView.prototype._clearLayer = function(api) {
var zr = api.getZr();
'svg' !== zr.painter.getType() && null != this._lastZlevel && zr.painter.getLayer(this._lastZlevel).clear(!0);
'svg' === zr.painter.getType() || null == this._lastZlevel || zr.painter.getLayer(this._lastZlevel).clear(!0);
}, LinesView.prototype.remove = function(ecModel, api) {
this._lineDraw && this._lineDraw.remove(), this._lineDraw = null, this._clearLayer(api);
}, LinesView.type = 'lines', LinesView;
Expand Down Expand Up @@ -34689,7 +34689,7 @@
return null !== _super && _super.apply(this, arguments) || this;
}
return __extends(DataView, _super), DataView.prototype.onclick = function(ecModel, api) {
var seriesGroupByCategoryAxis, otherSeries, meta, groups, tables, result, container = api.getDom(), model = this.model;
var seriesGroupByCategoryAxis, otherSeries, meta, result, groups, tables, container = api.getDom(), model = this.model;
this._dom && container.removeChild(this._dom);
var root = document.createElement('div');
root.style.cssText = 'position:absolute;left:5px;top:5px;bottom:5px;right:5px;', root.style.backgroundColor = model.get('backgroundColor') || '#fff';
Expand Down Expand Up @@ -35481,7 +35481,7 @@
}, TooltipHTMLContent.prototype.show = function(tooltipModel, nearPointColor) {
clearTimeout(this._hideTimeout), clearTimeout(this._longHideTimeout);
var enableTransition, onlyFade, cssText, transitionDuration, backgroundColor, shadowBlur, shadowColor, shadowOffsetX, shadowOffsetY, textStyleModel, padding, transitionCurve, transitionOption, transitionText, cssText1, fontSize, color, shadowColor1, shadowBlur1, shadowOffsetX1, shadowOffsetY1, el = this.el, style = el.style, styleCoord = this._styleCoord;
el.innerHTML ? style.cssText = gCssText + (enableTransition = !this._firstShow, onlyFade = this._longHide, cssText = [], transitionDuration = tooltipModel.get('transitionDuration'), backgroundColor = tooltipModel.get('backgroundColor'), shadowBlur = tooltipModel.get('shadowBlur'), shadowColor = tooltipModel.get('shadowColor'), shadowOffsetX = tooltipModel.get('shadowOffsetX'), shadowOffsetY = tooltipModel.get('shadowOffsetY'), textStyleModel = tooltipModel.getModel('textStyle'), padding = getPaddingFromTooltipModel(tooltipModel, 'html'), cssText.push('box-shadow:' + (shadowOffsetX + "px " + shadowOffsetY + "px ") + shadowBlur + "px " + shadowColor), enableTransition && transitionDuration && cssText.push((transitionText = "opacity" + (transitionOption = " " + transitionDuration / 2 + "s " + (transitionCurve = 'cubic-bezier(0.23,1,0.32,1)')) + ",visibility" + transitionOption, onlyFade || (transitionOption = " " + transitionDuration + "s " + transitionCurve, transitionText += env.transformSupported ? "," + TRANSFORM_VENDOR + transitionOption : ",left" + transitionOption + ",top" + transitionOption), CSS_TRANSITION_VENDOR + ':' + transitionText)), backgroundColor && (env.canvasSupported ? cssText.push('background-color:' + backgroundColor) : (cssText.push('background-color:#' + toHex(backgroundColor)), cssText.push('filter:alpha(opacity=70)'))), each([
el.innerHTML ? style.cssText = gCssText + (enableTransition = !this._firstShow, onlyFade = this._longHide, cssText = [], transitionDuration = tooltipModel.get('transitionDuration'), backgroundColor = tooltipModel.get('backgroundColor'), shadowBlur = tooltipModel.get('shadowBlur'), shadowColor = tooltipModel.get('shadowColor'), shadowOffsetX = tooltipModel.get('shadowOffsetX'), shadowOffsetY = tooltipModel.get('shadowOffsetY'), textStyleModel = tooltipModel.getModel('textStyle'), padding = getPaddingFromTooltipModel(tooltipModel, 'html'), cssText.push('box-shadow:' + shadowOffsetX + "px " + shadowOffsetY + "px " + shadowBlur + "px " + shadowColor), enableTransition && transitionDuration && cssText.push((transitionText = "opacity" + (transitionOption = " " + transitionDuration / 2 + "s " + (transitionCurve = 'cubic-bezier(0.23,1,0.32,1)')) + ",visibility" + transitionOption, onlyFade || (transitionOption = " " + transitionDuration + "s " + transitionCurve, transitionText += env.transformSupported ? "," + TRANSFORM_VENDOR + transitionOption : ",left" + transitionOption + ",top" + transitionOption), CSS_TRANSITION_VENDOR + ':' + transitionText)), backgroundColor && (env.canvasSupported ? cssText.push('background-color:' + backgroundColor) : (cssText.push('background-color:#' + toHex(backgroundColor)), cssText.push('filter:alpha(opacity=70)'))), each([
'width',
'color',
'radius'
Expand Down
3 changes: 1 addition & 2 deletions crates/swc_ecma_minifier/tests/benches-full/jquery.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,7 @@
}
function createDisabledPseudo(disabled) {
return function(elem) {
if ("form" in elem) return elem.parentNode && !1 === elem.disabled ? "label" in elem ? "label" in elem.parentNode ? elem.parentNode.disabled === disabled : elem.disabled === disabled : elem.isDisabled === disabled || !disabled !== elem.isDisabled && inDisabledFieldset(elem) === disabled : elem.disabled === disabled;
return "label" in elem && elem.disabled === disabled;
return "form" in elem ? elem.parentNode && !1 === elem.disabled ? "label" in elem ? "label" in elem.parentNode ? elem.parentNode.disabled === disabled : elem.disabled === disabled : elem.isDisabled === disabled || !disabled !== elem.isDisabled && inDisabledFieldset(elem) === disabled : elem.disabled === disabled : "label" in elem && elem.disabled === disabled;
};
}
function createPositionalPseudo(fn) {
Expand Down
9 changes: 4 additions & 5 deletions crates/swc_ecma_minifier/tests/benches-full/lodash.js
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@
var length, result1, object1, object2, object3, tag = getTag(value), isFunc = tag == funcTag || tag == genTag;
if (isBuffer(value)) return cloneBuffer(value, isDeep);
if (tag == objectTag || tag == argsTag || isFunc && !object) {
if (result = isFlat || isFunc ? {} : initCloneObject(value), !isDeep) return isFlat ? (object1 = (object3 = result) && copyObject(value, keysIn(value), object3), copyObject(value, getSymbolsIn(value), object1)) : (object2 = baseAssign(result, value), copyObject(value, getSymbols(value), object2));
if (result = isFlat || isFunc ? {} : initCloneObject(value), !isDeep) return isFlat ? (object2 = (object1 = result) && copyObject(value, keysIn(value), object1), copyObject(value, getSymbolsIn(value), object2)) : (object3 = baseAssign(result, value), copyObject(value, getSymbols(value), object3));
} else {
if (!cloneableTags[tag]) return object ? value : {};
result = function(object, tag, isDeep) {
Expand Down Expand Up @@ -976,7 +976,7 @@
return !0;
}
function baseIsNative(value) {
return !(!isObject(value) || maskSrcKey && maskSrcKey in value) && (isFunction(value) ? reIsNative : reIsHostCtor).test(toSource(value));
return !!isObject(value) && (!maskSrcKey || !(maskSrcKey in value)) && (isFunction(value) ? reIsNative : reIsHostCtor).test(toSource(value));
}
function baseIteratee(value) {
return 'function' == typeof value ? value : null == value ? identity : 'object' == typeof value ? isArray(value) ? baseMatchesProperty(value[0], value[1]) : baseMatches(value) : property(value);
Expand All @@ -1003,8 +1003,7 @@
};
}
function baseMatchesProperty(path, srcValue) {
var value;
return isKey(path) && (value = srcValue) == value && !isObject(value) ? matchesStrictComparable(toKey(path), srcValue) : function(object) {
return isKey(path) && srcValue == srcValue && !isObject(srcValue) ? matchesStrictComparable(toKey(path), srcValue) : function(object) {
var objValue = get(object, path);
return undefined === objValue && objValue === srcValue ? hasIn(object, path) : baseIsEqual(srcValue, objValue, 3);
};
Expand Down Expand Up @@ -1730,7 +1729,7 @@
return root.setTimeout(func, wait);
}, setToString = shortOut(baseSetToString);
function setWrapToString(wrapper, reference, bitmask) {
var details, match, source = reference + '';
var match, details, source = reference + '';
return setToString(wrapper, function(source, details) {
var length = details.length;
if (!length) return source;
Expand Down
Loading

0 comments on commit cb16994

Please sign in to comment.