diff --git a/.changeset/shiny-guests-check.md b/.changeset/shiny-guests-check.md new file mode 100644 index 000000000000..3aadac3e3bde --- /dev/null +++ b/.changeset/shiny-guests-check.md @@ -0,0 +1,6 @@ +--- +swc_ecma_usage_analyzer: patch +swc_core: patch +--- + +fix(es/minifier): Mark LHS of for-in/of as update diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/9466/config.json b/crates/swc_ecma_minifier/tests/fixture/issues/9466/config.json new file mode 100644 index 000000000000..e24c2f770eb5 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/9466/config.json @@ -0,0 +1,46 @@ +{ + "arguments": false, + "arrows": true, + "booleans": true, + "booleans_as_integers": false, + "collapse_vars": true, + "comparisons": true, + "computed_props": true, + "conditionals": true, + "dead_code": true, + "directives": true, + "drop_console": false, + "drop_debugger": true, + "evaluate": true, + "expression": false, + "hoist_funs": false, + "hoist_props": true, + "hoist_vars": false, + "if_return": true, + "join_vars": true, + "keep_classnames": false, + "keep_fargs": true, + "keep_fnames": false, + "keep_infinity": false, + "loops": true, + "negate_iife": true, + "properties": true, + "reduce_funcs": false, + "reduce_vars": false, + "side_effects": true, + "switches": true, + "typeofs": true, + "unsafe": false, + "unsafe_arrows": false, + "unsafe_comps": false, + "unsafe_Function": false, + "unsafe_math": false, + "unsafe_symbols": false, + "unsafe_methods": false, + "unsafe_proto": false, + "unsafe_regexp": false, + "unsafe_undefined": false, + "unused": true, + "const_to_let": true, + "pristine_globals": true +} diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/9466/input.js b/crates/swc_ecma_minifier/tests/fixture/issues/9466/input.js new file mode 100644 index 000000000000..af1c6cf1fdcb --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/9466/input.js @@ -0,0 +1,7 @@ +"use strict"; +let k = function () { + function x() { } + class y { } + for (x of ['']); + for (y in ['']); +}(); \ No newline at end of file diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/9466/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/9466/output.js new file mode 100644 index 000000000000..113908328fda --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/9466/output.js @@ -0,0 +1,12 @@ +"use strict"; +let k = function() { + function x() {} + class y { + } + for (x of [ + '' + ]); + for(y in [ + '' + ]); +}(); diff --git a/crates/swc_ecma_minifier/tests/projects/output/yui-3.12.0.js b/crates/swc_ecma_minifier/tests/projects/output/yui-3.12.0.js index 38efb3d8310c..43d2b24627d7 100644 --- a/crates/swc_ecma_minifier/tests/projects/output/yui-3.12.0.js +++ b/crates/swc_ecma_minifier/tests/projects/output/yui-3.12.0.js @@ -4115,7 +4115,7 @@ Contains the core of YUI's feature test architecture. * @private * @param {Object} o The new configuration */ _config: function(o) { - var i, j, val, a, f, group, groupName, mod, self = this, mods = []; + var i, j, val, a, f, group, mod, self = this, mods = []; // apply config values if (o) { for(i in o)if (o.hasOwnProperty(i)) { @@ -4125,7 +4125,7 @@ Contains the core of YUI's feature test architecture. defaultSkin: val }), Y.mix(self.skin, val, !0); else if ("groups" === i) { - for(j in val)if (val.hasOwnProperty(j) && (groupName = j, group = val[j], self.addGroup(group, groupName), group.aliases)) for(a in group.aliases)group.aliases.hasOwnProperty(a) && self.addAlias(group.aliases[a], a); + for(j in val)if (val.hasOwnProperty(j) && (group = val[j], self.addGroup(group, j), group.aliases)) for(a in group.aliases)group.aliases.hasOwnProperty(a) && self.addAlias(group.aliases[a], a); } else if ("modules" === i) // add a hash of module definitions for(j in val)val.hasOwnProperty(j) && self.addModule(val[j], j); else if ("aliases" === i) for(j in val)val.hasOwnProperty(j) && self.addAlias(val[j], j); @@ -4787,7 +4787,7 @@ Contains the core of YUI's feature test architecture. * var out = loader.resolve(true); * */ resolve: function(calc, s) { - var len, i, m, url, group, groupName, j, frag, comboSource, comboSources, mods, comboBase, base, urls, tmpBase, baseLen, comboSep, maxURLLength, addSingle, u = [], resCombos = {}, self = this, inserted = self.ignoreRegistered ? {} : self.inserted, resolved = { + var len, i, m, url, group, groupName, j, frag, comboSource, comboSources, mods, comboBase, urls, tmpBase, baseLen, comboSep, maxURLLength, addSingle, u = [], resCombos = {}, self = this, inserted = self.ignoreRegistered ? {} : self.inserted, resolved = { js: [], jsMods: [], css: [], @@ -4821,12 +4821,12 @@ Contains the core of YUI's feature test architecture. cssMods: [] }, url = j, len = (mods = comboSources[j]).length)) for(i = 0; i < len; i++)!inserted[mods[i]] && ((m = mods[i]) && (m.combine || !m.ext) ? (resCombos[j].comboSep = m.comboSep, resCombos[j].group = m.group, resCombos[j].maxURLLength = m.maxURLLength, frag = (L.isValue(m.root) ? m.root : self.root) + (m.path || m.fullpath), frag = self._filter(frag, m.name), resCombos[j][m.type].push(frag), resCombos[j][m.type + "Mods"].push(m)) : mods[i] && addSingle(mods[i])); for(j in resCombos)if (resCombos.hasOwnProperty(j)) { - for(type in comboSep = resCombos[base = j].comboSep || self.comboSep, maxURLLength = resCombos[base].maxURLLength || self.maxURLLength, resCombos[base])if ("js" === type || "css" === type) { - if (urls = resCombos[base][type], mods = resCombos[base][type + "Mods"], len = urls.length, baseLen = (tmpBase = base + urls.join(comboSep)).length, maxURLLength <= base.length && (maxURLLength = 1024), len) { + for(type in comboSep = resCombos[j].comboSep || self.comboSep, maxURLLength = resCombos[j].maxURLLength || self.maxURLLength, resCombos[j])if ("js" === type || "css" === type) { + if (urls = resCombos[j][type], mods = resCombos[j][type + "Mods"], len = urls.length, baseLen = (tmpBase = j + urls.join(comboSep)).length, maxURLLength <= j.length && (maxURLLength = 1024), len) { if (baseLen > maxURLLength) { - for(s = 0, u = []; s < len; s++)u.push(urls[s]), (tmpBase = base + u.join(comboSep)).length > maxURLLength && (m = u.pop(), tmpBase = base + u.join(comboSep), resolved[type].push(self._filter(tmpBase, null, resCombos[base].group)), u = [], m && u.push(m)); - u.length && (tmpBase = base + u.join(comboSep), resolved[type].push(self._filter(tmpBase, null, resCombos[base].group))); - } else resolved[type].push(self._filter(tmpBase, null, resCombos[base].group)); + for(s = 0, u = []; s < len; s++)u.push(urls[s]), (tmpBase = j + u.join(comboSep)).length > maxURLLength && (m = u.pop(), tmpBase = j + u.join(comboSep), resolved[type].push(self._filter(tmpBase, null, resCombos[j].group)), u = [], m && u.push(m)); + u.length && (tmpBase = j + u.join(comboSep), resolved[type].push(self._filter(tmpBase, null, resCombos[j].group))); + } else resolved[type].push(self._filter(tmpBase, null, resCombos[j].group)); } resolved[type + "Mods"] = resolved[type + "Mods"].concat(mods); } diff --git a/crates/swc_ecma_usage_analyzer/src/analyzer/mod.rs b/crates/swc_ecma_usage_analyzer/src/analyzer/mod.rs index f09da333f919..c901df71a48b 100644 --- a/crates/swc_ecma_usage_analyzer/src/analyzer/mod.rs +++ b/crates/swc_ecma_usage_analyzer/src/analyzer/mod.rs @@ -153,14 +153,14 @@ where self.data.report_usage(self.ctx, i) } - fn report_assign_pat(&mut self, p: &Pat, is_op: bool) { + fn report_assign_pat(&mut self, p: &Pat, is_read_modify: bool) { for id in find_pat_ids(p) { - self.data.report_assign(self.ctx, id, is_op) + self.data.report_assign(self.ctx, id, is_read_modify) } if let Pat::Expr(e) = p { match &**e { - Expr::Ident(i) => self.data.report_assign(self.ctx, i.to_id(), is_op), + Expr::Ident(i) => self.data.report_assign(self.ctx, i.to_id(), is_read_modify), _ => self.mark_mutation_if_member(e.as_member()), } } @@ -793,7 +793,7 @@ where n.right.visit_with(child); if let ForHead::Pat(pat) = &n.left { - child.with_ctx(head_ctx).report_assign_pat(pat, false) + child.with_ctx(head_ctx).report_assign_pat(pat, true) } let ctx = Ctx { @@ -821,7 +821,7 @@ where n.left.visit_with(&mut *child.with_ctx(head_ctx)); if let ForHead::Pat(pat) = &n.left { - child.with_ctx(head_ctx).report_assign_pat(pat, false) + child.with_ctx(head_ctx).report_assign_pat(pat, true) } let ctx = Ctx {