Skip to content

Commit 06cbb90

Browse files
authoredMar 4, 2023
feat(es/minifier): Optimize calls to Boolean/Number/String/Symbol (#7006)
1 parent 6b48896 commit 06cbb90

File tree

18 files changed

+154
-53
lines changed

18 files changed

+154
-53
lines changed
 

‎crates/swc/tests/vercel/full/react-instantsearch/2/output/index.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ var f = function(e) {
2020
}, m = function(e, t) {
2121
return e.props.indexContextValue.targetedIndex === t;
2222
}, p = function(e) {
23-
return Boolean(e.props.indexId);
23+
return !!e.props.indexId;
2424
}, g = function(e, t) {
2525
return e.props.indexId === t;
2626
}, h = function(e, t) {
@@ -30,26 +30,26 @@ var f = function(e) {
3030
export default function S(u) {
3131
var o, l, S = u.indexName, v = u.initialState, x = u.searchClient, y = u.resultsState, w = u.stalledSearchDelay, F = function(e) {
3232
return O.getWidgets().filter(function(e) {
33-
return Boolean(e.getMetadata);
33+
return !!e.getMetadata;
3434
}).map(function(t) {
3535
return t.getMetadata(e);
3636
});
3737
}, _ = function() {
3838
var a = O.getWidgets().filter(function(e) {
39-
return Boolean(e.getSearchParameters);
39+
return !!e.getSearchParameters;
4040
}).filter(function(e) {
4141
return !f(e) && !p(e);
4242
}).reduce(function(e, t) {
4343
return t.getSearchParameters(e);
4444
}, N), n = O.getWidgets().filter(function(e) {
45-
return Boolean(e.getSearchParameters);
45+
return !!e.getSearchParameters;
4646
}).filter(function(e) {
4747
var t = f(e) && m(e, S), r = p(e) && g(e, S);
4848
return t || r;
4949
}).sort(h).reduce(function(e, t) {
5050
return t.getSearchParameters(e);
5151
}, a), s = O.getWidgets().filter(function(e) {
52-
return Boolean(e.getSearchParameters);
52+
return !!e.getSearchParameters;
5353
}).filter(function(e) {
5454
var t = f(e) && !m(e, S), r = p(e) && !g(e, S);
5555
return t || r;
@@ -324,7 +324,7 @@ export default function S(u) {
324324
transitionState: function(e) {
325325
var t = q.getState().widgets;
326326
return O.getWidgets().filter(function(e) {
327-
return Boolean(e.transitionState);
327+
return !!e.transitionState;
328328
}).reduce(function(e, r) {
329329
return r.transitionState(t, e);
330330
}, e);

‎crates/swc_ecma_minifier/src/compress/pure/misc.rs

+101
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,107 @@ impl Pure<'_> {
434434
return;
435435
}
436436
}
437+
Expr::Call(CallExpr {
438+
span,
439+
callee: Callee::Expr(callee),
440+
args,
441+
..
442+
}) if callee.is_one_of_global_ref_to(
443+
&self.expr_ctx,
444+
&["Boolean", "Number", "String", "Symbol"],
445+
) =>
446+
{
447+
let new_expr = match &**callee {
448+
Expr::Ident(Ident {
449+
sym: js_word!("Boolean"),
450+
..
451+
}) => match &mut args[..] {
452+
[] => Some(Expr::Lit(Lit::Bool(Bool {
453+
span: *span,
454+
value: false,
455+
}))),
456+
[ExprOrSpread { spread: None, expr }] => Some(Expr::Unary(UnaryExpr {
457+
span: *span,
458+
op: op!("!"),
459+
arg: Expr::Unary(UnaryExpr {
460+
span: *span,
461+
op: op!("!"),
462+
arg: expr.take(),
463+
})
464+
.into(),
465+
})),
466+
_ => None,
467+
},
468+
Expr::Ident(Ident {
469+
sym: js_word!("Number"),
470+
..
471+
}) => match &mut args[..] {
472+
[] => Some(Expr::Lit(Lit::Num(Number {
473+
span: *span,
474+
value: 0.0,
475+
raw: None,
476+
}))),
477+
// this is indeed very unsafe in case of BigInt
478+
[ExprOrSpread { spread: None, expr }] if self.options.unsafe_math => {
479+
Some(Expr::Unary(UnaryExpr {
480+
span: *span,
481+
op: op!(unary, "+"),
482+
arg: expr.take(),
483+
}))
484+
}
485+
_ => None,
486+
},
487+
Expr::Ident(Ident {
488+
sym: js_word!("String"),
489+
..
490+
}) => match &mut args[..] {
491+
[] => Some(Expr::Lit(Lit::Str(Str {
492+
span: *span,
493+
value: "".into(),
494+
raw: None,
495+
}))),
496+
// this is also very unsafe in case of Symbol
497+
[ExprOrSpread { spread: None, expr }] if self.options.unsafe_passes => {
498+
Some(Expr::Bin(BinExpr {
499+
span: *span,
500+
left: expr.take(),
501+
op: op!(bin, "+"),
502+
right: Expr::Lit(Lit::Str(Str {
503+
span: *span,
504+
value: "".into(),
505+
raw: None,
506+
}))
507+
.into(),
508+
}))
509+
}
510+
_ => None,
511+
},
512+
Expr::Ident(Ident {
513+
sym: js_word!("Symbol"),
514+
..
515+
}) => {
516+
if let [ExprOrSpread { spread: None, .. }] = &mut args[..] {
517+
if self.options.unsafe_symbols {
518+
args.clear();
519+
report_change!("Remove Symbol call parameter");
520+
self.changed = true;
521+
}
522+
}
523+
None
524+
}
525+
_ => unreachable!(),
526+
};
527+
528+
if let Some(new_expr) = new_expr {
529+
report_change!(
530+
"Converting Boolean/Number/String/Symbol call to native constructor to \
531+
literal"
532+
);
533+
self.changed = true;
534+
*e = new_expr;
535+
return;
536+
}
537+
}
437538
_ => {}
438539
};
439540

‎crates/swc_ecma_minifier/tests/TODO.txt

-3
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,6 @@ issue_203/compress_new_function/input.js
250250
issue_203/compress_new_function_with_destruct/input.js
251251
issue_203/compress_new_function_with_destruct_arrows/input.js
252252
issue_22/return_with_no_value_in_if_body/input.js
253-
issue_269/issue_269_1/input.js
254-
issue_269/regexp/input.js
255-
issue_269/strings_concat/input.js
256253
issue_281/collapse_vars_constants/input.js
257254
issue_281/issue_1758/input.js
258255
issue_2871/comparison_with_undefined/input.js

‎crates/swc_ecma_minifier/tests/benches-full/terser.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1919,7 +1919,7 @@
19191919
this.prototype[name] = method;
19201920
}, ctor;
19211921
}
1922-
const has_tok_flag = (tok, flag)=>Boolean(tok.flags & flag), set_tok_flag = (tok, flag, truth)=>{
1922+
const has_tok_flag = (tok, flag)=>!!(tok.flags & flag), set_tok_flag = (tok, flag, truth)=>{
19231923
truth ? tok.flags |= flag : tok.flags &= ~flag;
19241924
};
19251925
class AST_Token {

‎crates/swc_ecma_minifier/tests/benches-full/victory.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -26588,7 +26588,7 @@
2658826588
{
2658926589
key: "shouldAnimate",
2659026590
value: function() {
26591-
return Boolean(this.props.animate);
26591+
return !!this.props.animate;
2659226592
}
2659326593
},
2659426594
{

‎crates/swc_ecma_minifier/tests/fixture/issues/2257/full/output.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10310,7 +10310,7 @@
1031010310
}
1031110311
return !1 === options.sort ? ret : (!0 === options.sort ? Object.keys(ret).sort() : Object.keys(ret).sort(options.sort)).reduce((result, key)=>{
1031210312
const value = ret[key];
10313-
return Boolean(value) && "object" == typeof value && !Array.isArray(value) ? result[key] = function keysSorter(input) {
10313+
return value && "object" == typeof value && !Array.isArray(value) ? result[key] = function keysSorter(input) {
1031410314
return Array.isArray(input) ? input.sort() : "object" == typeof input ? keysSorter(Object.keys(input)).sort((a, b)=>Number(a) - Number(b)).map((key)=>input[key]) : input;
1031510315
}(value) : result[key] = value, result;
1031610316
}, Object.create(null));

‎crates/swc_ecma_minifier/tests/fixture/issues/react-instancesearch/002/output.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ function addAlgoliaAgents(searchClient) {
1111
const isMultiIndexContext = (widget)=>hasMultipleIndices({
1212
ais: widget.props.contextValue,
1313
multiIndexContext: widget.props.indexContextValue
14-
}), isTargetedIndexEqualIndex = (widget, indexId)=>widget.props.indexContextValue.targetedIndex === indexId, isIndexWidget = (widget)=>Boolean(widget.props.indexId), isIndexWidgetEqualIndex = (widget, indexId)=>widget.props.indexId === indexId, sortIndexWidgetsFirst = (firstWidget, secondWidget)=>{
14+
}), isTargetedIndexEqualIndex = (widget, indexId)=>widget.props.indexContextValue.targetedIndex === indexId, isIndexWidget = (widget)=>!!widget.props.indexId, isIndexWidgetEqualIndex = (widget, indexId)=>widget.props.indexId === indexId, sortIndexWidgetsFirst = (firstWidget, secondWidget)=>{
1515
const isFirstWidgetIndex = isIndexWidget(firstWidget), isSecondWidgetIndex = isIndexWidget(secondWidget);
1616
return isFirstWidgetIndex && !isSecondWidgetIndex ? -1 : !isFirstWidgetIndex && isSecondWidgetIndex ? 1 : 0;
1717
};
@@ -149,13 +149,13 @@ export default function createInstantSearchManager({ indexName , initialState ={
149149
searchingForFacetValues: !1
150150
});
151151
function getMetadata(state) {
152-
return widgetsManager.getWidgets().filter((widget)=>Boolean(widget.getMetadata)).map((widget)=>widget.getMetadata(state));
152+
return widgetsManager.getWidgets().filter((widget)=>!!widget.getMetadata).map((widget)=>widget.getMetadata(state));
153153
}
154154
function getSearchParameters() {
155-
const sharedParameters = widgetsManager.getWidgets().filter((widget)=>Boolean(widget.getSearchParameters)).filter((widget)=>!isMultiIndexContext(widget) && !isIndexWidget(widget)).reduce((res, widget)=>widget.getSearchParameters(res), initialSearchParameters), mainParameters = widgetsManager.getWidgets().filter((widget)=>Boolean(widget.getSearchParameters)).filter((widget)=>{
155+
const sharedParameters = widgetsManager.getWidgets().filter((widget)=>!!widget.getSearchParameters).filter((widget)=>!isMultiIndexContext(widget) && !isIndexWidget(widget)).reduce((res, widget)=>widget.getSearchParameters(res), initialSearchParameters), mainParameters = widgetsManager.getWidgets().filter((widget)=>!!widget.getSearchParameters).filter((widget)=>{
156156
const targetedIndexEqualMainIndex = isMultiIndexContext(widget) && isTargetedIndexEqualIndex(widget, indexName), subIndexEqualMainIndex = isIndexWidget(widget) && isIndexWidgetEqualIndex(widget, indexName);
157157
return targetedIndexEqualMainIndex || subIndexEqualMainIndex;
158-
}).sort(sortIndexWidgetsFirst).reduce((res, widget)=>widget.getSearchParameters(res), sharedParameters), derivedIndices = widgetsManager.getWidgets().filter((widget)=>Boolean(widget.getSearchParameters)).filter((widget)=>{
158+
}).sort(sortIndexWidgetsFirst).reduce((res, widget)=>widget.getSearchParameters(res), sharedParameters), derivedIndices = widgetsManager.getWidgets().filter((widget)=>!!widget.getSearchParameters).filter((widget)=>{
159159
const targetedIndexNotEqualMainIndex = isMultiIndexContext(widget) && !isTargetedIndexEqualIndex(widget, indexName), subIndexNotEqualMainIndex = isIndexWidget(widget) && !isIndexWidgetEqualIndex(widget, indexName);
160160
return targetedIndexNotEqualMainIndex || subIndexNotEqualMainIndex;
161161
}).sort(sortIndexWidgetsFirst).reduce((indices, widget)=>{
@@ -264,7 +264,7 @@ export default function createInstantSearchManager({ indexName , initialState ={
264264
},
265265
transitionState: function(nextSearchState) {
266266
const searchState = store.getState().widgets;
267-
return widgetsManager.getWidgets().filter((widget)=>Boolean(widget.transitionState)).reduce((res, widget)=>widget.transitionState(searchState, res), nextSearchState);
267+
return widgetsManager.getWidgets().filter((widget)=>!!widget.transitionState).reduce((res, widget)=>widget.transitionState(searchState, res), nextSearchState);
268268
},
269269
updateClient: function(client) {
270270
addAlgoliaAgents(client), helper.setClient(client), search();

‎crates/swc_ecma_minifier/tests/fixture/issues/react-instancesearch/003/output.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ function addAlgoliaAgents(searchClient) {
1111
const isMultiIndexContext = (widget)=>hasMultipleIndices({
1212
ais: widget.props.contextValue,
1313
multiIndexContext: widget.props.indexContextValue
14-
}), isTargetedIndexEqualIndex = (widget, indexId)=>widget.props.indexContextValue.targetedIndex === indexId, isIndexWidget = (widget)=>Boolean(widget.props.indexId), isIndexWidgetEqualIndex = (widget, indexId)=>widget.props.indexId === indexId, sortIndexWidgetsFirst = (firstWidget, secondWidget)=>{
14+
}), isTargetedIndexEqualIndex = (widget, indexId)=>widget.props.indexContextValue.targetedIndex === indexId, isIndexWidget = (widget)=>!!widget.props.indexId, isIndexWidgetEqualIndex = (widget, indexId)=>widget.props.indexId === indexId, sortIndexWidgetsFirst = (firstWidget, secondWidget)=>{
1515
const isFirstWidgetIndex = isIndexWidget(firstWidget), isSecondWidgetIndex = isIndexWidget(secondWidget);
1616
return isFirstWidgetIndex && !isSecondWidgetIndex ? -1 : !isFirstWidgetIndex && isSecondWidgetIndex ? 1 : 0;
1717
};
@@ -164,13 +164,13 @@ export default function createInstantSearchManager({ indexName , initialState ={
164164
searchingForFacetValues: !1
165165
});
166166
function getMetadata(state) {
167-
return widgetsManager.getWidgets().filter((widget)=>Boolean(widget.getMetadata)).map((widget)=>widget.getMetadata(state));
167+
return widgetsManager.getWidgets().filter((widget)=>!!widget.getMetadata).map((widget)=>widget.getMetadata(state));
168168
}
169169
function getSearchParameters() {
170-
const sharedParameters = widgetsManager.getWidgets().filter((widget)=>Boolean(widget.getSearchParameters)).filter((widget)=>!isMultiIndexContext(widget) && !isIndexWidget(widget)).reduce((res, widget)=>widget.getSearchParameters(res), initialSearchParameters), mainParameters = widgetsManager.getWidgets().filter((widget)=>Boolean(widget.getSearchParameters)).filter((widget)=>{
170+
const sharedParameters = widgetsManager.getWidgets().filter((widget)=>!!widget.getSearchParameters).filter((widget)=>!isMultiIndexContext(widget) && !isIndexWidget(widget)).reduce((res, widget)=>widget.getSearchParameters(res), initialSearchParameters), mainParameters = widgetsManager.getWidgets().filter((widget)=>!!widget.getSearchParameters).filter((widget)=>{
171171
const targetedIndexEqualMainIndex = isMultiIndexContext(widget) && isTargetedIndexEqualIndex(widget, indexName), subIndexEqualMainIndex = isIndexWidget(widget) && isIndexWidgetEqualIndex(widget, indexName);
172172
return targetedIndexEqualMainIndex || subIndexEqualMainIndex;
173-
}).sort(sortIndexWidgetsFirst).reduce((res, widget)=>widget.getSearchParameters(res), sharedParameters), derivedIndices = widgetsManager.getWidgets().filter((widget)=>Boolean(widget.getSearchParameters)).filter((widget)=>{
173+
}).sort(sortIndexWidgetsFirst).reduce((res, widget)=>widget.getSearchParameters(res), sharedParameters), derivedIndices = widgetsManager.getWidgets().filter((widget)=>!!widget.getSearchParameters).filter((widget)=>{
174174
const targetedIndexNotEqualMainIndex = isMultiIndexContext(widget) && !isTargetedIndexEqualIndex(widget, indexName), subIndexNotEqualMainIndex = isIndexWidget(widget) && !isIndexWidgetEqualIndex(widget, indexName);
175175
return targetedIndexNotEqualMainIndex || subIndexNotEqualMainIndex;
176176
}).sort(sortIndexWidgetsFirst).reduce((indices, widget)=>{
@@ -279,7 +279,7 @@ export default function createInstantSearchManager({ indexName , initialState ={
279279
},
280280
transitionState: function(nextSearchState) {
281281
const searchState = store.getState().widgets;
282-
return widgetsManager.getWidgets().filter((widget)=>Boolean(widget.transitionState)).reduce((res, widget)=>widget.transitionState(searchState, res), nextSearchState);
282+
return widgetsManager.getWidgets().filter((widget)=>!!widget.transitionState).reduce((res, widget)=>widget.transitionState(searchState, res), nextSearchState);
283283
},
284284
updateClient: function(client) {
285285
addAlgoliaAgents(client), helper.setClient(client), search();

‎crates/swc_ecma_minifier/tests/fixture/issues/react-instancesearch/004/output.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ var _obj, isMultiIndexContext = function(widget) {
1616
}, isTargetedIndexEqualIndex = function(widget, indexId) {
1717
return widget.props.indexContextValue.targetedIndex === indexId;
1818
}, isIndexWidget = function(widget) {
19-
return Boolean(widget.props.indexId);
19+
return !!widget.props.indexId;
2020
}, isIndexWidgetEqualIndex = function(widget, indexId) {
2121
return widget.props.indexId === indexId;
2222
}, sortIndexWidgetsFirst = function(firstWidget, secondWidget) {
@@ -26,26 +26,26 @@ var _obj, isMultiIndexContext = function(widget) {
2626
export default function createInstantSearchManager(param) {
2727
var state, listeners, indexName = param.indexName, _initialState = param.initialState, searchClient = param.searchClient, resultsState = param.resultsState, stalledSearchDelay = param.stalledSearchDelay, getMetadata = function(state) {
2828
return widgetsManager.getWidgets().filter(function(widget) {
29-
return Boolean(widget.getMetadata);
29+
return !!widget.getMetadata;
3030
}).map(function(widget) {
3131
return widget.getMetadata(state);
3232
});
3333
}, getSearchParameters = function() {
3434
var sharedParameters = widgetsManager.getWidgets().filter(function(widget) {
35-
return Boolean(widget.getSearchParameters);
35+
return !!widget.getSearchParameters;
3636
}).filter(function(widget) {
3737
return !isMultiIndexContext(widget) && !isIndexWidget(widget);
3838
}).reduce(function(res, widget) {
3939
return widget.getSearchParameters(res);
4040
}, initialSearchParameters), mainParameters = widgetsManager.getWidgets().filter(function(widget) {
41-
return Boolean(widget.getSearchParameters);
41+
return !!widget.getSearchParameters;
4242
}).filter(function(widget) {
4343
var targetedIndexEqualMainIndex = isMultiIndexContext(widget) && isTargetedIndexEqualIndex(widget, indexName), subIndexEqualMainIndex = isIndexWidget(widget) && isIndexWidgetEqualIndex(widget, indexName);
4444
return targetedIndexEqualMainIndex || subIndexEqualMainIndex;
4545
}).sort(sortIndexWidgetsFirst).reduce(function(res, widget) {
4646
return widget.getSearchParameters(res);
4747
}, sharedParameters), derivedIndices = widgetsManager.getWidgets().filter(function(widget) {
48-
return Boolean(widget.getSearchParameters);
48+
return !!widget.getSearchParameters;
4949
}).filter(function(widget) {
5050
var targetedIndexNotEqualMainIndex = isMultiIndexContext(widget) && !isTargetedIndexEqualIndex(widget, indexName), subIndexNotEqualMainIndex = isIndexWidget(widget) && !isIndexWidgetEqualIndex(widget, indexName);
5151
return targetedIndexNotEqualMainIndex || subIndexNotEqualMainIndex;
@@ -319,7 +319,7 @@ export default function createInstantSearchManager(param) {
319319
transitionState: function(nextSearchState) {
320320
var searchState = store.getState().widgets;
321321
return widgetsManager.getWidgets().filter(function(widget) {
322-
return Boolean(widget.transitionState);
322+
return !!widget.transitionState;
323323
}).reduce(function(res, widget) {
324324
return widget.transitionState(searchState, res);
325325
}, nextSearchState);

0 commit comments

Comments
 (0)