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): Make sequential inliner respect resolution order #6509

Merged
merged 32 commits into from Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions crates/swc/tests/tsc-references/enumBasics.2.minified.js
@@ -1,8 +1,9 @@
//// [enumBasics.ts]
var E1, E2, E3, E4, E5, E6, E7, E8, E9;
!function(E1) {
E1[E1.A = 0] = "A", E1[E1.B = 1] = "B", E1[E1.C = 2] = "C";
}(E1 || (E1 = {})), E1.A, E1[E1.A], function(E2) {
}(E1 || (E1 = {})), E1.A;
var E1, E2, E3, E4, E5, E6, E7, E8, E9, e = E1;
E1[e.A], function(E2) {
E2[E2.A = 1] = "A", E2[E2.B = 2] = "B", E2[E2.C = 3] = "C";
}(E2 || (E2 = {})), function(E3) {
E3[E3.X = 3] = "X", E3[E3.Y = 7] = "Y", E3[E3.Z = NaN] = "Z";
Expand Down
27 changes: 27 additions & 0 deletions crates/swc_ecma_minifier/src/compress/optimize/sequences.rs
Expand Up @@ -1597,6 +1597,33 @@ where
return Ok(false);
}

// We can't merge into `[]` in some cases because `obj` is **resolved** before
// evaluating `[]`.
//
// See https://github.com/swc-project/swc/pull/6509

// We check only for an identifier because resolution is the problematic part.
// Evalutation order is not a problem.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this true? Wouldn't (1, obj)[obj = {}, 'key'] hit the same problem?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I was wrong. Nice catch, and thank you!

if let Expr::Ident(obj) = &**obj {
match a {
Mergable::Var(a) => {
if IdentUsageFinder::find(&obj.to_id(), &**a) {
return Ok(false);
}
}
Mergable::Expr(a) => {
if IdentUsageFinder::find(&obj.to_id(), &**a) {
return Ok(false);
}
}
Mergable::FnDecl(a) => {
if IdentUsageFinder::find(&obj.to_id(), &**a) {
return Ok(false);
}
}
}
}

trace_op!("seq: Try prop of member (computed)");
return self.merge_sequential_expr(a, &mut c.expr);
}
Expand Down
6 changes: 3 additions & 3 deletions crates/swc_ecma_minifier/tests/benches-full/echarts.js
Expand Up @@ -15339,7 +15339,7 @@
}
if (isArray(template)) {
var levelId = null == tick.level ? 0 : tick.level >= 0 ? tick.level : template.length + tick.level;
template = template[levelId = Math.min(levelId, template.length - 1)];
levelId = Math.min(levelId, template.length - 1), template = template[levelId];
}
}
return format(new Date(tick.value), template, isUTC, lang);
Expand Down Expand Up @@ -23629,7 +23629,7 @@
function getSpecifiedVisual(value) {
var thisOption = this.option, pieceList = thisOption.pieceList;
if (thisOption.hasSpecialVisual) {
var piece = pieceList[VisualMapping.findPieceIndex(value, pieceList)];
var pieceIndex = VisualMapping.findPieceIndex(value, pieceList), piece = pieceList[pieceIndex];
if (piece && piece.visual) return piece.visual[this.type];
}
}
Expand Down Expand Up @@ -27805,7 +27805,7 @@
var result, axisList;
each((result = [], axisList = [], ecModel.eachSeriesByType('boxplot', function(seriesModel) {
var baseAxis = seriesModel.getBaseAxis(), idx = indexOf(axisList, baseAxis);
idx < 0 && (axisList[idx = axisList.length] = baseAxis, result[idx] = {
idx < 0 && (idx = axisList.length, axisList[idx] = baseAxis, result[idx] = {
axis: baseAxis,
seriesModels: []
}), result[idx].seriesModels.push(seriesModel);
Expand Down
2 changes: 1 addition & 1 deletion crates/swc_ecma_minifier/tests/benches-full/jquery.js
Expand Up @@ -487,7 +487,7 @@
"",
argument
], Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) ? markFunction(function(seed, matches) {
for(var idx, matched = fn(seed, argument), i = matched.length; i--;)seed[idx = indexOf(seed, matched[i])] = !(matches[idx] = matched[i]);
for(var idx, matched = fn(seed, argument), i = matched.length; i--;)idx = indexOf(seed, matched[i]), seed[idx] = !(matches[idx] = matched[i]);
}) : function(elem) {
return fn(elem, 0, args);
}) : fn;
Expand Down
7 changes: 5 additions & 2 deletions crates/swc_ecma_minifier/tests/benches-full/three.js
Expand Up @@ -5561,7 +5561,10 @@
return void 0 === program && (program = new WebGLProgram(renderer, cacheKey, parameters, bindingStates), programs.push(program)), program;
},
releaseProgram: function(program) {
0 == --program.usedTimes && (programs[programs.indexOf(program)] = programs[programs.length - 1], programs.pop(), program.destroy());
if (0 == --program.usedTimes) {
var i = programs.indexOf(program);
programs[i] = programs[programs.length - 1], programs.pop(), program.destroy();
}
},
programs: programs
};
Expand Down Expand Up @@ -10006,7 +10009,7 @@
iPrev = i1, tPrev = 2 * t0 - t1;
break;
case 2402:
tPrev = t0 + pp[iPrev = pp.length - 2] - pp[iPrev + 1];
iPrev = pp.length - 2, tPrev = t0 + pp[iPrev] - pp[iPrev + 1];
break;
default:
iPrev = i1, tPrev = t1;
Expand Down
13 changes: 8 additions & 5 deletions crates/swc_ecma_minifier/tests/benches-full/victory.js
Expand Up @@ -22325,6 +22325,13 @@
fontSize: 0,
angle: 0,
fontFamily: ""
}, _getFontData = function(fontFamily) {
var fontMatch = fontFamily.split(",").map(function(f) {
return f.replace(/'|"/g, "");
}).find(function(f) {
return fonts[f];
}) || "Helvetica";
return fonts[fontMatch];
}, _splitToLines = function(text) {
return Array.isArray(text) ? text : text.toString().split(/\r\n|\r|\n/g);
}, _getSizeWithRotate = function(axisSize, dependentSize, angle) {
Expand All @@ -22343,11 +22350,7 @@
}, _approximateTextWidthInternal = function(text, style) {
if (void 0 === text || "" === text || null === text) return 0;
var widths = _splitToLines(text).map(function(line, index) {
var len = line.toString().length, _prepareParams2 = _prepareParams(style, index), fontSize = _prepareParams2.fontSize, letterSpacing = _prepareParams2.letterSpacing, fontData = fonts[_prepareParams2.fontFamily.split(",").map(function(f) {
return f.replace(/'|"/g, "");
}).find(function(f) {
return fonts[f];
}) || "Helvetica"];
var len = line.toString().length, _prepareParams2 = _prepareParams(style, index), fontSize = _prepareParams2.fontSize, letterSpacing = _prepareParams2.letterSpacing, fontData = _getFontData(_prepareParams2.fontFamily);
return line.toString().split("").map(function(c) {
return c.charCodeAt(0) < fontData.widths.length ? fontData.widths[c.charCodeAt(0)] : fontData.avg;
}).reduce(function(cur, acc) {
Expand Down
2 changes: 1 addition & 1 deletion crates/swc_ecma_minifier/tests/benches-full/vue.js
Expand Up @@ -761,7 +761,7 @@
createTextVNode(children)
] : Array.isArray(children) ? function normalizeArrayChildren(children, nestedIndex) {
var i, c, lastIndex, last, res = [];
for(i = 0; i < children.length; i++)!isUndef(c = children[i]) && 'boolean' != typeof c && (last = res[lastIndex = res.length - 1], Array.isArray(c) ? c.length > 0 && (isTextNode((c = normalizeArrayChildren(c, (nestedIndex || '') + "_" + i))[0]) && isTextNode(last) && (res[lastIndex] = createTextVNode(last.text + c[0].text), c.shift()), res.push.apply(res, c)) : isPrimitive(c) ? isTextNode(last) ? res[lastIndex] = createTextVNode(last.text + c) : '' !== c && res.push(createTextVNode(c)) : isTextNode(c) && isTextNode(last) ? res[lastIndex] = createTextVNode(last.text + c.text) : (isTrue(children._isVList) && isDef(c.tag) && isUndef(c.key) && isDef(nestedIndex) && (c.key = "__vlist" + nestedIndex + "_" + i + "__"), res.push(c)));
for(i = 0; i < children.length; i++)!isUndef(c = children[i]) && 'boolean' != typeof c && (lastIndex = res.length - 1, last = res[lastIndex], Array.isArray(c) ? c.length > 0 && (isTextNode((c = normalizeArrayChildren(c, (nestedIndex || '') + "_" + i))[0]) && isTextNode(last) && (res[lastIndex] = createTextVNode(last.text + c[0].text), c.shift()), res.push.apply(res, c)) : isPrimitive(c) ? isTextNode(last) ? res[lastIndex] = createTextVNode(last.text + c) : '' !== c && res.push(createTextVNode(c)) : isTextNode(c) && isTextNode(last) ? res[lastIndex] = createTextVNode(last.text + c.text) : (isTrue(children._isVList) && isDef(c.tag) && isUndef(c.key) && isDef(nestedIndex) && (c.key = "__vlist" + nestedIndex + "_" + i + "__"), res.push(c)));
return res;
}(children) : void 0;
}
Expand Down
@@ -0,0 +1,7 @@
{
"toplevel": true,
"defaults": false,
"inline": true,
"sequences": true,
"conditionals": true
}
113 changes: 113 additions & 0 deletions crates/swc_ecma_minifier/tests/fixture/issues/6509/input.js
@@ -0,0 +1,113 @@


function parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) {
var offsets = [0, 0];

// Use height if placement is left or right and index is 0 otherwise use width
// in this way the first offset will use an axis and the second one
// will use the other one
var useHeight = ['right', 'left'].indexOf(basePlacement) !== -1;

// Split the offset string to obtain a list of values and operands
// The regex addresses values with the plus or minus sign in front (+10, -20, etc)
var fragments = offset.split(/(\+|\-)/).map(function (frag) {
return frag.trim();
});

// Detect if the offset string contains a pair of values or a single one
// they could be separated by comma or space
var divider = fragments.indexOf(find(fragments, function (frag) {
return frag.search(/,|\s/) !== -1;
}));

if (fragments[divider] && fragments[divider].indexOf(',') === -1) {
console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.');
}

// If divider is found, we divide the list of values and operands to divide
// them by ofset X and Y.
var splitRegex = /\s*,\s*|\s+/;
var ops = divider !== -1 ? [fragments.slice(0, divider).concat([fragments[divider].split(splitRegex)[0]]), [fragments[divider].split(splitRegex)[1]].concat(fragments.slice(divider + 1))] : [fragments];

// Convert the values with units to absolute pixels to allow our computations
ops = ops.map(function (op, index) {
// Most of the units rely on the orientation of the popper
var measurement = (index === 1 ? !useHeight : useHeight) ? 'height' : 'width';
var mergeWithPrevious = false;
return op
// This aggregates any `+` or `-` sign that aren't considered operators
// e.g.: 10 + +5 => [10, +, +5]
.reduce(function (a, b) {
if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) {
a[a.length - 1] = b;
mergeWithPrevious = true;
return a;
} else if (mergeWithPrevious) {
a[a.length - 1] += b;
mergeWithPrevious = false;
return a;
} else {
return a.concat(b);
}
}, [])
// Here we convert the string values into number values (in px)
.map(function (str) {
return toValue(str, measurement, popperOffsets, referenceOffsets);
});
});

// Loop trough the offsets arrays and execute the operations
ops.forEach(function (op, index) {
op.forEach(function (frag, index2) {
if (isNumeric(frag)) {
offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1);
}
});
});
return offsets;
}

function offset(data, _ref) {
var offset = _ref.offset;
var placement = data.placement,
_data$offsets = data.offsets,
popper = _data$offsets.popper,
reference = _data$offsets.reference;

var basePlacement = placement.split('-')[0];

var offsets = void 0;
if (isNumeric(+offset)) {
offsets = [+offset, 0];
} else {
offsets = parseOffset(offset, popper, reference, basePlacement);
}

if (basePlacement === 'left') {
popper.top += offsets[0];
popper.left -= offsets[1];
} else if (basePlacement === 'right') {
popper.top += offsets[0];
popper.left += offsets[1];
} else if (basePlacement === 'top') {
popper.left += offsets[0];
popper.top -= offsets[1];
} else if (basePlacement === 'bottom') {
popper.left += offsets[0];
popper.top += offsets[1];
}

data.popper = popper;
return data;
}


export var modifiers = {
offset: {
order: 200,
enabled: true,
fn: offset,
offset: 0
},
};

63 changes: 63 additions & 0 deletions crates/swc_ecma_minifier/tests/fixture/issues/6509/output.js
@@ -0,0 +1,63 @@
export var modifiers = {
offset: {
order: 200,
enabled: true,
fn: function(data, _ref) {
var offset = _ref.offset;
var placement = data.placement, _data$offsets = data.offsets, popper = _data$offsets.popper, reference = _data$offsets.reference;
var basePlacement = placement.split('-')[0];
var offsets = void 0;
if (isNumeric(+offset)) offsets = [
+offset,
0
];
else {
var offsets1;
var useHeight;
var fragments;
var divider;
var splitRegex;
var ops;
offsets1 = [
0,
0
], useHeight = -1 !== [
'right',
'left'
].indexOf(basePlacement), divider = (fragments = offset.split(/(\+|\-)/).map(function(frag) {
return frag.trim();
})).indexOf(find(fragments, function(frag) {
return -1 !== frag.search(/,|\s/);
})), fragments[divider] && -1 === fragments[divider].indexOf(',') && console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.'), splitRegex = /\s*,\s*|\s+/, (ops = (-1 !== divider ? [
fragments.slice(0, divider).concat([
fragments[divider].split(splitRegex)[0]
]),
[
fragments[divider].split(splitRegex)[1]
].concat(fragments.slice(divider + 1))
] : [
fragments
]).map(function(op, index) {
var measurement = (1 === index ? !useHeight : useHeight) ? 'height' : 'width';
var mergeWithPrevious = false;
return op.reduce(function(a, b) {
if ('' === a[a.length - 1] && -1 !== [
'+',
'-'
].indexOf(b)) return a[a.length - 1] = b, mergeWithPrevious = true, a;
if (mergeWithPrevious) return a[a.length - 1] += b, mergeWithPrevious = false, a;
return a.concat(b);
}, []).map(function(str) {
return toValue(str, measurement, popper, reference);
});
})).forEach(function(op, index) {
op.forEach(function(frag, index2) {
isNumeric(frag) && (offsets1[index] += frag * ('-' === op[index2 - 1] ? -1 : 1));
});
}), offsets = offsets1;
}
return 'left' === basePlacement ? (popper.top += offsets[0], popper.left -= offsets[1]) : 'right' === basePlacement ? (popper.top += offsets[0], popper.left += offsets[1]) : 'top' === basePlacement ? (popper.left += offsets[0], popper.top -= offsets[1]) : 'bottom' === basePlacement && (popper.left += offsets[0], popper.top += offsets[1]), data.popper = popper, data;
},
offset: 0
}
};
Expand Up @@ -6263,10 +6263,10 @@
{
key: "_matchCheckChar",
value: function(charArray, index, maxWeight) {
var arrayToCheck = charArray.slice(0, index), length = arrayToCheck.length;
return code_93_reader_ALPHABET[arrayToCheck.reduce(function(sum, _char3, i) {
var arrayToCheck = charArray.slice(0, index), length = arrayToCheck.length, weightedSums = arrayToCheck.reduce(function(sum, _char3, i) {
return sum + ((-1 * i + (length - 1)) % maxWeight + 1) * code_93_reader_ALPHABET.indexOf(_char3.charCodeAt(0));
}, 0) % 47] === charArray[index].charCodeAt(0);
}, 0);
return code_93_reader_ALPHABET[weightedSums % 47] === charArray[index].charCodeAt(0);
}
},
{
Expand Down
Expand Up @@ -10418,7 +10418,7 @@
var tkhd, index, id, mdhd;
return (tkhd = findBox_1(trak, [
"tkhd"
])[0]) && (id = toUnsigned(tkhd[index = 0 === tkhd[0] ? 12 : 20] << 24 | tkhd[index + 1] << 16 | tkhd[index + 2] << 8 | tkhd[index + 3]), mdhd = findBox_1(trak, [
])[0]) && (index = 0 === tkhd[0] ? 12 : 20, id = toUnsigned(tkhd[index] << 24 | tkhd[index + 1] << 16 | tkhd[index + 2] << 8 | tkhd[index + 3]), mdhd = findBox_1(trak, [
"mdia",
"mdhd"
])[0]) ? (index = 0 === mdhd[0] ? 12 : 20, result[id] = toUnsigned(mdhd[index] << 24 | mdhd[index + 1] << 16 | mdhd[index + 2] << 8 | mdhd[index + 3]), result) : null;
Expand Down Expand Up @@ -13053,7 +13053,7 @@
var syncPoint = null, lastDistance = null, partsAndSegments = getPartsAndSegments(playlist);
currentTime = currentTime || 0;
for(var i = 0; i < partsAndSegments.length; i++){
var partAndSegment = partsAndSegments[playlist.endList || 0 === currentTime ? i : partsAndSegments.length - (i + 1)], segment = partAndSegment.segment, datetimeMapping = syncController.timelineToDatetimeMappings[segment.timeline];
var index = playlist.endList || 0 === currentTime ? i : partsAndSegments.length - (i + 1), partAndSegment = partsAndSegments[index], segment = partAndSegment.segment, datetimeMapping = syncController.timelineToDatetimeMappings[segment.timeline];
if (datetimeMapping && segment.dateTimeObject) {
var start = segment.dateTimeObject.getTime() / 1000 + datetimeMapping;
if (segment.parts && "number" == typeof partAndSegment.partIndex) for(var z = 0; z < partAndSegment.partIndex; z++)start += segment.parts[z].duration;
Expand All @@ -13075,7 +13075,7 @@
var syncPoint = null, lastDistance = null;
currentTime = currentTime || 0;
for(var partsAndSegments = getPartsAndSegments(playlist), i = 0; i < partsAndSegments.length; i++){
var partAndSegment = partsAndSegments[playlist.endList || 0 === currentTime ? i : partsAndSegments.length - (i + 1)], segment = partAndSegment.segment, start = partAndSegment.part && partAndSegment.part.start || segment && segment.start;
var index = playlist.endList || 0 === currentTime ? i : partsAndSegments.length - (i + 1), partAndSegment = partsAndSegments[index], segment = partAndSegment.segment, start = partAndSegment.part && partAndSegment.part.start || segment && segment.start;
if (segment.timeline === currentTimeline && void 0 !== start) {
var distance = Math.abs(currentTime - start);
if (null !== lastDistance && lastDistance < distance) break;
Expand Down