mirror of
https://github.com/swc-project/swc.git
synced 2024-11-27 13:38:33 +03:00
4c06a56e52
**Related issue:** - Closes #7274.
10953 lines
218 KiB
Rust
10953 lines
218 KiB
Rust
#![deny(warnings)]
|
|
|
|
extern crate swc_node_base;
|
|
|
|
use ansi_term::Color;
|
|
use anyhow::Error;
|
|
use serde::Deserialize;
|
|
use swc_common::{
|
|
comments::SingleThreadedComments,
|
|
errors::{Handler, HANDLER},
|
|
sync::Lrc,
|
|
FileName, Mark, SourceMap,
|
|
};
|
|
use swc_ecma_ast::Module;
|
|
use swc_ecma_codegen::{
|
|
text_writer::{omit_trailing_semi, JsWriter, WriteJs},
|
|
Emitter,
|
|
};
|
|
use swc_ecma_minifier::{
|
|
optimize,
|
|
option::{
|
|
terser::TerserCompressorOptions, CompressOptions, ExtraOptions, MangleOptions,
|
|
MinifyOptions,
|
|
},
|
|
};
|
|
use swc_ecma_parser::{parse_file_as_module, EsConfig, Syntax};
|
|
use swc_ecma_testing::{exec_node_js, JsExecOptions};
|
|
use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene, resolver};
|
|
use swc_ecma_visit::{FoldWith, VisitMutWith};
|
|
use testing::DebugUsingDisplay;
|
|
use tracing::{info, span, Level};
|
|
|
|
#[derive(Debug, Clone, Deserialize)]
|
|
struct TestOptions {
|
|
#[serde(default)]
|
|
defaults: bool,
|
|
}
|
|
|
|
fn parse_compressor_config(cm: Lrc<SourceMap>, s: &str) -> (bool, CompressOptions) {
|
|
let opts: TestOptions =
|
|
serde_json::from_str(s).expect("failed to deserialize value into a compressor config");
|
|
let mut c: TerserCompressorOptions =
|
|
serde_json::from_str(s).expect("failed to deserialize value into a compressor config");
|
|
|
|
c.defaults = opts.defaults;
|
|
|
|
(c.module, c.into_config(cm))
|
|
}
|
|
|
|
fn stdout_of(code: &str) -> Result<String, Error> {
|
|
let stdout = exec_node_js(
|
|
code,
|
|
JsExecOptions {
|
|
cache: true,
|
|
module: false,
|
|
..Default::default()
|
|
},
|
|
)?;
|
|
|
|
info!("Stdout: {}", stdout);
|
|
|
|
Ok(stdout)
|
|
}
|
|
|
|
fn print<N: swc_ecma_codegen::Node>(
|
|
cm: Lrc<SourceMap>,
|
|
nodes: &[N],
|
|
minify: bool,
|
|
skip_semi: bool,
|
|
) -> String {
|
|
let mut buf = vec![];
|
|
|
|
{
|
|
let mut wr: Box<dyn WriteJs> = Box::new(JsWriter::new(cm.clone(), "\n", &mut buf, None));
|
|
if minify || skip_semi {
|
|
wr = Box::new(omit_trailing_semi(wr));
|
|
}
|
|
|
|
let mut emitter = Emitter {
|
|
cfg: swc_ecma_codegen::Config {
|
|
minify,
|
|
..Default::default()
|
|
},
|
|
cm,
|
|
comments: None,
|
|
wr,
|
|
};
|
|
|
|
for n in nodes {
|
|
n.emit_with(&mut emitter).unwrap();
|
|
}
|
|
}
|
|
|
|
String::from_utf8(buf).unwrap()
|
|
}
|
|
|
|
fn run(
|
|
cm: Lrc<SourceMap>,
|
|
handler: &Handler,
|
|
input: &str,
|
|
config: Option<&str>,
|
|
mangle: Option<MangleOptions>,
|
|
) -> Option<Module> {
|
|
let _ = rayon::ThreadPoolBuilder::new()
|
|
.thread_name(|i| format!("rayon-{}", i + 1))
|
|
.build_global();
|
|
|
|
let compress_config = config.map(|config| parse_compressor_config(cm.clone(), config).1);
|
|
|
|
let fm = cm.new_source_file(FileName::Anon, input.into());
|
|
let comments = SingleThreadedComments::default();
|
|
|
|
eprintln!("---- {} -----\n{}", Color::Green.paint("Input"), fm.src);
|
|
|
|
let unresolved_mark = Mark::new();
|
|
let top_level_mark = Mark::new();
|
|
|
|
let program = parse_file_as_module(
|
|
&fm,
|
|
Syntax::Es(EsConfig {
|
|
jsx: true,
|
|
..Default::default()
|
|
}),
|
|
Default::default(),
|
|
Some(&comments),
|
|
&mut vec![],
|
|
)
|
|
.map_err(|err| {
|
|
err.into_diagnostic(handler).emit();
|
|
})
|
|
.map(|module| module.fold_with(&mut resolver(unresolved_mark, top_level_mark, false)));
|
|
|
|
// Ignore parser errors.
|
|
//
|
|
// This is typically related to strict mode caused by module context.
|
|
let program = match program {
|
|
Ok(v) => v,
|
|
_ => return None,
|
|
};
|
|
|
|
let run_hygiene = mangle.is_none();
|
|
|
|
let mut output = optimize(
|
|
program.into(),
|
|
cm,
|
|
Some(&comments),
|
|
None,
|
|
&MinifyOptions {
|
|
compress: compress_config,
|
|
mangle,
|
|
..Default::default()
|
|
},
|
|
&ExtraOptions {
|
|
unresolved_mark,
|
|
top_level_mark,
|
|
},
|
|
)
|
|
.expect_module();
|
|
|
|
if run_hygiene {
|
|
output.visit_mut_with(&mut hygiene());
|
|
}
|
|
|
|
let output = output.fold_with(&mut fixer(None));
|
|
|
|
Some(output)
|
|
}
|
|
|
|
fn run_exec_test(input_src: &str, config: &str, skip_mangle: bool) {
|
|
eprintln!("---- {} -----\n{}", Color::Green.paint("Config"), config);
|
|
|
|
let expected_output = stdout_of(input_src).unwrap();
|
|
|
|
eprintln!(
|
|
"---- {} -----\n{}",
|
|
Color::Green.paint("Expected"),
|
|
expected_output
|
|
);
|
|
|
|
testing::run_test2(false, |cm, handler| {
|
|
HANDLER.set(&handler, || {
|
|
let _tracing = span!(Level::ERROR, "compress-only").entered();
|
|
|
|
let output = run(cm.clone(), &handler, input_src, Some(config), None);
|
|
let output = output.expect("Parsing in base test should not fail");
|
|
let output = print(cm, &[output], false, false);
|
|
|
|
eprintln!(
|
|
"---- {} -----\n{}",
|
|
Color::Green.paint("Optimized code"),
|
|
output
|
|
);
|
|
|
|
let actual_output = stdout_of(&output).expect("failed to execute the optimized code");
|
|
assert_ne!(actual_output, "");
|
|
|
|
assert_eq!(
|
|
DebugUsingDisplay(&actual_output),
|
|
DebugUsingDisplay(&expected_output)
|
|
);
|
|
|
|
Ok(())
|
|
})
|
|
})
|
|
.unwrap();
|
|
|
|
if !skip_mangle {
|
|
testing::run_test2(false, |cm, handler| {
|
|
let _tracing = span!(Level::ERROR, "with-mangle").entered();
|
|
|
|
let output = run(
|
|
cm.clone(),
|
|
&handler,
|
|
input_src,
|
|
None,
|
|
Some(MangleOptions {
|
|
keep_fn_names: true,
|
|
top_level: Some(true),
|
|
..Default::default()
|
|
}),
|
|
);
|
|
|
|
let output = output.expect("Parsing in base test should not fail");
|
|
let output = print(cm, &[&output], true, false);
|
|
|
|
eprintln!(
|
|
"---- {} -----\n{}",
|
|
Color::Green.paint("Optimized code"),
|
|
output
|
|
);
|
|
|
|
let actual_output = stdout_of(&output).expect("failed to execute the optimized code");
|
|
assert_ne!(actual_output, "");
|
|
|
|
assert_eq!(
|
|
DebugUsingDisplay(&actual_output),
|
|
DebugUsingDisplay(&expected_output)
|
|
);
|
|
|
|
Ok(())
|
|
})
|
|
.unwrap();
|
|
}
|
|
}
|
|
|
|
fn run_default_exec_test(input_src: &str) {
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(input_src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn next_feedback_1_capture_1() {
|
|
let src = r###"
|
|
const arr = [];
|
|
const fns = [];
|
|
|
|
var _loop = function (i) {
|
|
fns.push(() => {
|
|
arr.push(i);
|
|
})
|
|
}
|
|
for (var i = 0; i < 10; i++) _loop(i);
|
|
|
|
fns.forEach(fn => fn());
|
|
|
|
console.log(arr);"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn conditionals_reduce_6() {
|
|
let src = r###"function x() {
|
|
}
|
|
function y() {
|
|
return "foo";
|
|
}
|
|
console.log((y() || false) && x());"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn conditionals_reduce_1() {
|
|
let src = r###"function x() {
|
|
}
|
|
function y() {
|
|
return "foo";
|
|
}
|
|
console.log(x() && true && y());"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn conditionals_reduce_4() {
|
|
let src = r###"function x() {
|
|
}
|
|
function y() {
|
|
return "foo";
|
|
}
|
|
console.log(y() || false || x());"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn conditionals_reduce_3() {
|
|
let src = r###"function x() {
|
|
}
|
|
function y() {
|
|
return "foo";
|
|
}
|
|
console.log(x() || false || y());"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn conditionals_reduce_2() {
|
|
let src = r###"function x() {
|
|
}
|
|
function y() {
|
|
return "foo";
|
|
}
|
|
console.log(y() && true && x());"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn conditionals_reduce_5() {
|
|
let src = r###"function x() {
|
|
}
|
|
function y() {
|
|
return "foo";
|
|
}
|
|
console.log((x() || false) && y());"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn vercel_001() {
|
|
let src = r###"function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
function _class_call_check(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _possible_constructor_return(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
|
|
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
|
|
|
|
|
function ItemsList() {
|
|
var _ref;
|
|
|
|
var _temp, _this, _ret;
|
|
|
|
_class_call_check(this, ItemsList);
|
|
|
|
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
|
|
return _ret = (_temp = (_this = _possible_constructor_return(this, (_ref = ItemsList.__proto__ || Object.getPrototypeOf(ItemsList)).call.apply(_ref, [this].concat(args))), _this), _this.storeHighlightedItemReference = function (highlightedItem) {
|
|
_this.props.onHighlightedItemChange(highlightedItem === null ? null : highlightedItem.item);
|
|
}, _temp), _possible_constructor_return(_this, _ret);
|
|
}
|
|
|
|
|
|
new ItemsList();
|
|
console.log('PASS')"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn vercel_002() {
|
|
let src = r###"function _interop_require_default(obj) {
|
|
return obj && obj.__esModule ? obj : {
|
|
default: obj
|
|
};
|
|
}
|
|
function _class_call_check(instance, Constructor) {
|
|
if (!(instance instanceof Constructor)) {
|
|
throw new TypeError("Cannot call a class as a function");
|
|
}
|
|
}
|
|
function _possible_constructor_return(self, call) {
|
|
if (!self) {
|
|
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
|
}
|
|
return call && ("object" == typeof call || "function" == typeof call) ? call : self;
|
|
}
|
|
function _inherits(subClass, superClass) {
|
|
if ("function" != typeof superClass && null !== superClass) {
|
|
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
|
|
}
|
|
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
|
constructor: {
|
|
value: subClass,
|
|
enumerable: false,
|
|
writable: true,
|
|
configurable: true
|
|
}
|
|
});
|
|
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
|
|
}
|
|
function ItemsList() {
|
|
_class_call_check(this, ItemsList);
|
|
for (var _ref, _temp, _this, _ret, _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
return _ret = (_temp = (_this = _possible_constructor_return(this, (_ref = ItemsList.__proto__ || Object.getPrototypeOf(ItemsList)).call.apply(_ref, [
|
|
this
|
|
].concat(args))), _this), _this.storeHighlightedItemReference = function (highlightedItem) {
|
|
_this.props.onHighlightedItemChange(null === highlightedItem ? null : highlightedItem.item);
|
|
}, _temp), _possible_constructor_return(_this, _ret);
|
|
}
|
|
new ItemsList();
|
|
console.log("PASS");"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn regexp_1() {
|
|
let src = r###"
|
|
|
|
function compile(attributePattern, flags) {
|
|
return new RegExp(`(?:^|;)\\s*${attributePattern}\\s*=\\s*` + `(` + `[^";\\s][^;\\s]*` + `|` + `"(?:[^"\\\\]|\\\\"?)+"?` + `)`, flags);
|
|
}
|
|
|
|
console.log(compile("foo", "g"));
|
|
console.log(compile("bar", "g"));
|
|
console.log(compile("baz", "g"));"###;
|
|
let config = r###"{
|
|
"defaults": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn update_object_1() {
|
|
let src = r###"console.log(function () {
|
|
console.log({
|
|
q: {
|
|
p: 8
|
|
}
|
|
}.q.p++);
|
|
return 8;
|
|
}());"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn update_object_3() {
|
|
let src = r###"console.log(function () {
|
|
var o = {
|
|
p: 7
|
|
};
|
|
console.log([
|
|
o
|
|
][0].p++);
|
|
return o.p;
|
|
}());"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn update_object_2() {
|
|
let src = r###"function inc() {
|
|
this.p++;
|
|
}
|
|
console.log(function () {
|
|
inc.call({
|
|
p: 6
|
|
});
|
|
console.log(6);
|
|
return 6;
|
|
}());"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn iife_reassign_1() {
|
|
let src = r###"console.log(function c() {
|
|
c = 6;
|
|
return c;
|
|
}())"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 3,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn emotion_react_1() {
|
|
let src = r###"
|
|
/* harmony default export */
|
|
var emotion_memoize_browser_esm = (memoize);
|
|
|
|
var hyphenateRegex = /[A-Z]|^ms/g;
|
|
var animationRegex = /_EMO_([^_]+?)_([^]*?)_EMO_/g;
|
|
|
|
|
|
var unitlessKeys = {
|
|
animationIterationCount: 1,
|
|
borderImageOutset: 1,
|
|
borderImageSlice: 1,
|
|
borderImageWidth: 1,
|
|
boxFlex: 1,
|
|
boxFlexGroup: 1,
|
|
boxOrdinalGroup: 1,
|
|
columnCount: 1,
|
|
columns: 1,
|
|
flex: 1,
|
|
flexGrow: 1,
|
|
flexPositive: 1,
|
|
flexShrink: 1,
|
|
flexNegative: 1,
|
|
flexOrder: 1,
|
|
gridRow: 1,
|
|
gridRowEnd: 1,
|
|
gridRowSpan: 1,
|
|
gridRowStart: 1,
|
|
gridColumn: 1,
|
|
gridColumnEnd: 1,
|
|
gridColumnSpan: 1,
|
|
gridColumnStart: 1,
|
|
msGridRow: 1,
|
|
msGridRowSpan: 1,
|
|
msGridColumn: 1,
|
|
msGridColumnSpan: 1,
|
|
fontWeight: 1,
|
|
lineHeight: 1,
|
|
opacity: 1,
|
|
order: 1,
|
|
orphans: 1,
|
|
tabSize: 1,
|
|
widows: 1,
|
|
zIndex: 1,
|
|
zoom: 1,
|
|
WebkitLineClamp: 1,
|
|
// SVG-related properties
|
|
fillOpacity: 1,
|
|
floodOpacity: 1,
|
|
stopOpacity: 1,
|
|
strokeDasharray: 1,
|
|
strokeDashoffset: 1,
|
|
strokeMiterlimit: 1,
|
|
strokeOpacity: 1,
|
|
strokeWidth: 1
|
|
};
|
|
|
|
var unitless_browser_esm = (unitlessKeys);
|
|
|
|
var isCustomProperty = function isCustomProperty(property) {
|
|
return property.charCodeAt(1) === 45;
|
|
};
|
|
|
|
var labelPattern = /label:\s*([^\s;\n{]+)\s*(;|$)/g;
|
|
|
|
var cursor;
|
|
|
|
var hash_browser_esm = (murmur2);
|
|
|
|
|
|
function handleInterpolation(mergedProps, registered, interpolation) {
|
|
if (interpolation == null) {
|
|
return '';
|
|
}
|
|
|
|
if (interpolation.__emotion_styles !== undefined) {
|
|
if (false) { }
|
|
|
|
return interpolation;
|
|
}
|
|
|
|
switch (typeof interpolation) {
|
|
case 'boolean': {
|
|
return '';
|
|
}
|
|
|
|
case 'object': {
|
|
if (interpolation.anim === 1) {
|
|
cursor = {
|
|
name: interpolation.name,
|
|
styles: interpolation.styles,
|
|
next: cursor
|
|
};
|
|
return interpolation.name;
|
|
}
|
|
|
|
if (interpolation.styles !== undefined) {
|
|
var next = interpolation.next;
|
|
|
|
if (next !== undefined) {
|
|
// not the most efficient thing ever but this is a pretty rare case
|
|
// and there will be very few iterations of this generally
|
|
while (next !== undefined) {
|
|
cursor = {
|
|
name: next.name,
|
|
styles: next.styles,
|
|
next: cursor
|
|
};
|
|
next = next.next;
|
|
}
|
|
}
|
|
|
|
var styles = interpolation.styles + ";";
|
|
|
|
if (false) { }
|
|
|
|
return styles;
|
|
}
|
|
|
|
return createStringFromObject(mergedProps, registered, interpolation);
|
|
}
|
|
|
|
case 'function': {
|
|
if (mergedProps !== undefined) {
|
|
var previousCursor = cursor;
|
|
var result = interpolation(mergedProps);
|
|
cursor = previousCursor;
|
|
return handleInterpolation(mergedProps, registered, result);
|
|
} else if (false) { }
|
|
|
|
break;
|
|
}
|
|
|
|
case 'string':
|
|
if (false) {
|
|
var replaced, matched;
|
|
}
|
|
|
|
break;
|
|
} // finalize string values (regular strings and functions interpolated into css calls)
|
|
|
|
|
|
if (registered == null) {
|
|
return interpolation;
|
|
}
|
|
|
|
var cached = registered[interpolation];
|
|
return cached !== undefined ? cached : interpolation;
|
|
}
|
|
|
|
|
|
function serializeStyles(args, registered, mergedProps) {
|
|
if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null && args[0].styles !== undefined) {
|
|
return args[0];
|
|
}
|
|
|
|
var stringMode = true;
|
|
var styles = '';
|
|
cursor = undefined;
|
|
var strings = args[0];
|
|
|
|
if (strings == null || strings.raw === undefined) {
|
|
stringMode = false;
|
|
console.log('stringMode = false')
|
|
styles += handleInterpolation(mergedProps, registered, strings);
|
|
} else {
|
|
if (false) { }
|
|
|
|
styles += strings[0];
|
|
} // we start at 1 since we've already handled the first arg
|
|
|
|
console.log(`Styles: ${styles}`)
|
|
|
|
for (var i = 1; i < args.length; i++) {
|
|
styles += handleInterpolation(mergedProps, registered, args[i]);
|
|
|
|
if (stringMode) {
|
|
if (false) { }
|
|
|
|
styles += strings[i];
|
|
}
|
|
}
|
|
|
|
console.log(`Styles: ${styles}`)
|
|
|
|
var sourceMap;
|
|
|
|
if (false) { } // using a global regex with .exec is stateful so lastIndex has to be reset each time
|
|
|
|
|
|
labelPattern.lastIndex = 0;
|
|
var identifierName = '';
|
|
var match; // https://esbench.com/bench/5b809c2cf2949800a0f61fb5
|
|
|
|
while ((match = labelPattern.exec(styles)) !== null) {
|
|
identifierName += '-' + // $FlowFixMe we know it's not null
|
|
match[1];
|
|
}
|
|
|
|
console.log(`styles = ${styles}`)
|
|
console.log(`identifierName = ${identifierName}`)
|
|
var name = hash_browser_esm(styles) + identifierName;
|
|
|
|
if (false) { }
|
|
|
|
return {
|
|
name: name,
|
|
styles: styles,
|
|
next: cursor
|
|
};
|
|
}
|
|
|
|
function createStringFromObject(mergedProps, registered, obj) {
|
|
var string = '';
|
|
|
|
if (Array.isArray(obj)) {
|
|
for (var i = 0; i < obj.length; i++) {
|
|
string += handleInterpolation(mergedProps, registered, obj[i]) + ";";
|
|
}
|
|
} else {
|
|
for (var _key in obj) {
|
|
var value = obj[_key];
|
|
|
|
if (typeof value !== 'object') {
|
|
if (registered != null && registered[value] !== undefined) {
|
|
string += _key + "{" + registered[value] + "}";
|
|
} else if (isProcessableValue(value)) {
|
|
string += processStyleName(_key) + ":" + processStyleValue(_key, value) + ";";
|
|
}
|
|
} else {
|
|
if (_key === 'NO_COMPONENT_SELECTOR' && "production" !== 'production') { }
|
|
|
|
if (Array.isArray(value) && typeof value[0] === 'string' && (registered == null || registered[value[0]] === undefined)) {
|
|
for (var _i = 0; _i < value.length; _i++) {
|
|
if (isProcessableValue(value[_i])) {
|
|
string += processStyleName(_key) + ":" + processStyleValue(_key, value[_i]) + ";";
|
|
}
|
|
}
|
|
} else {
|
|
var interpolated = handleInterpolation(mergedProps, registered, value);
|
|
|
|
switch (_key) {
|
|
case 'animation':
|
|
case 'animationName': {
|
|
string += processStyleName(_key) + ":" + interpolated + ";";
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
if (false) { }
|
|
|
|
string += _key + "{" + interpolated + "}";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return string;
|
|
}
|
|
|
|
function murmur2(str) {
|
|
// 'm' and 'r' are mixing constants generated offline.
|
|
// They're not really 'magic', they just happen to work well.
|
|
// const m = 0x5bd1e995;
|
|
// const r = 24;
|
|
// Initialize the hash
|
|
var h = 0; // Mix 4 bytes at a time into the hash
|
|
|
|
var k,
|
|
i = 0,
|
|
len = str.length;
|
|
|
|
for (; len >= 4; ++i, len -= 4) {
|
|
k = str.charCodeAt(i) & 0xff | (str.charCodeAt(++i) & 0xff) << 8 | (str.charCodeAt(++i) & 0xff) << 16 | (str.charCodeAt(++i) & 0xff) << 24;
|
|
console.log(`K1: ${k}`);
|
|
k =
|
|
/* Math.imul(k, m): */
|
|
(k & 0xffff) * 0x5bd1e995 + ((k >>> 16) * 0xe995 << 16);
|
|
console.log(`K2: ${k}`);
|
|
k ^=
|
|
/* k >>> r: */
|
|
k >>> 24;
|
|
console.log(`K3: ${k}`);
|
|
h =
|
|
/* Math.imul(k, m): */
|
|
(k & 0xffff) * 0x5bd1e995 + ((k >>> 16) * 0xe995 << 16) ^
|
|
/* Math.imul(h, m): */
|
|
(h & 0xffff) * 0x5bd1e995 + ((h >>> 16) * 0xe995 << 16);
|
|
console.log(`H: ${h}`);
|
|
} // Handle the last few bytes of the input array
|
|
|
|
|
|
switch (len) {
|
|
case 3:
|
|
h ^= (str.charCodeAt(i + 2) & 0xff) << 16;
|
|
|
|
case 2:
|
|
h ^= (str.charCodeAt(i + 1) & 0xff) << 8;
|
|
|
|
case 1:
|
|
h ^= str.charCodeAt(i) & 0xff;
|
|
h =
|
|
/* Math.imul(h, m): */
|
|
(h & 0xffff) * 0x5bd1e995 + ((h >>> 16) * 0xe995 << 16);
|
|
} // Do a few final mixes of the hash to ensure the last few
|
|
// bytes are well-incorporated.
|
|
|
|
|
|
h ^= h >>> 13;
|
|
h =
|
|
/* Math.imul(h, m): */
|
|
(h & 0xffff) * 0x5bd1e995 + ((h >>> 16) * 0xe995 << 16);
|
|
return ((h ^ h >>> 15) >>> 0).toString(36);
|
|
}
|
|
|
|
function isProcessableValue(value) {
|
|
return value != null && typeof value !== 'boolean';
|
|
}
|
|
|
|
var processStyleName = /* #__PURE__ */ emotion_memoize_browser_esm(function (styleName) {
|
|
return isCustomProperty(styleName) ? styleName : styleName.replace(hyphenateRegex, '-$&').toLowerCase();
|
|
});
|
|
|
|
var processStyleValue = function processStyleValue(key, value) {
|
|
switch (key) {
|
|
case 'animation':
|
|
case 'animationName': {
|
|
if (typeof value === 'string') {
|
|
return value.replace(animationRegex, function (match, p1, p2) {
|
|
cursor = {
|
|
name: p1,
|
|
styles: p2,
|
|
next: cursor
|
|
};
|
|
return p1;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (unitless_browser_esm[key] !== 1 && !isCustomProperty(key) && typeof value === 'number' && value !== 0) {
|
|
return value + 'px';
|
|
}
|
|
|
|
return value;
|
|
};
|
|
|
|
function memoize(fn) {
|
|
var cache = Object.create(null);
|
|
return function (arg) {
|
|
if (cache[arg] === undefined) cache[arg] = fn(arg);
|
|
return cache[arg];
|
|
};
|
|
}
|
|
|
|
|
|
console.log(serializeStyles(`:root {
|
|
--background-color: rebeccapurple;
|
|
}`));
|
|
console.log(serializeStyles(`:root {
|
|
--background-color: rebeccapurple;
|
|
}`));
|
|
console.log(serializeStyles(`:root {
|
|
--background-color: rebeccapurple;
|
|
}`));
|
|
console.log(serializeStyles(`:root {
|
|
--background-color: rebeccapurple;
|
|
}`));
|
|
console.log(serializeStyles(`:root {
|
|
--background-color: rebeccapurple;
|
|
}`));
|
|
console.log(serializeStyles(`:root {
|
|
--background-color: rebeccapurple;
|
|
}`));"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn simple_1() {
|
|
let src = r###"console.log('PASS')"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1588_unsafe_undefined() {
|
|
let src = r###"var a, c;
|
|
console.log(
|
|
(function (undefined) {
|
|
return function () {
|
|
if (a) return b;
|
|
if (c) return d;
|
|
};
|
|
})()()
|
|
);"###;
|
|
let config = r###"{
|
|
"conditionals": true,
|
|
"if_return": true,
|
|
"unsafe_undefined": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1588_safe_undefined() {
|
|
let src = r###"var a, c;
|
|
console.log(
|
|
(function (undefined) {
|
|
return function () {
|
|
if (a) return b;
|
|
if (c) return d;
|
|
};
|
|
})(1)()
|
|
);"###;
|
|
let config = r###"{
|
|
"conditionals": true,
|
|
"if_return": true,
|
|
"unsafe": false
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_drop_toplevel_retain() {
|
|
let src = r###"var a,
|
|
b = 1,
|
|
c = g;
|
|
function f(d) {
|
|
return function () {
|
|
c = 2;
|
|
};
|
|
}
|
|
a = 2;
|
|
function g() {}
|
|
function h() {}
|
|
console.log((b = 3));"###;
|
|
let config = r###"{
|
|
"top_retain": "f,a,o",
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_t161_top_retain_15() {
|
|
let src = r###"class Alpha {
|
|
num() {
|
|
return x;
|
|
}
|
|
}
|
|
class Beta {
|
|
num() {
|
|
return y;
|
|
}
|
|
}
|
|
class Carrot {
|
|
num() {
|
|
return z;
|
|
}
|
|
}
|
|
function f() {
|
|
return x;
|
|
}
|
|
const g = () => y;
|
|
const h = () => z;
|
|
let x = 2,
|
|
y = 3,
|
|
z = 4;
|
|
console.log(
|
|
x,
|
|
y,
|
|
z,
|
|
x * y,
|
|
x * z,
|
|
y * z,
|
|
f(),
|
|
g(),
|
|
h(),
|
|
new Alpha().num(),
|
|
new Beta().num(),
|
|
new Carrot().num()
|
|
);"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"inline": 3,
|
|
"passes": 2,
|
|
"top_retain": "Alpha,z"
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_t161_top_retain_4() {
|
|
let src = r###"function f() {
|
|
return 2;
|
|
}
|
|
function g() {
|
|
return 3;
|
|
}
|
|
console.log(f(), f(), g(), g());"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"inline": 3,
|
|
"passes": 3,
|
|
"top_retain": "f"
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_t161_top_retain_3() {
|
|
let src = r###"function f() {
|
|
return 2;
|
|
}
|
|
function g() {
|
|
return 3;
|
|
}
|
|
console.log(f(), g());"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"inline": 3,
|
|
"passes": 3,
|
|
"top_retain": "f"
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_double_assign_1() {
|
|
let src = r###"function f1() {
|
|
var a = {};
|
|
var a = [];
|
|
return a;
|
|
}
|
|
function f2() {
|
|
var a = {};
|
|
a = [];
|
|
return a;
|
|
}
|
|
function f3() {
|
|
a = {};
|
|
var a = [];
|
|
return a;
|
|
}
|
|
function f4(a) {
|
|
a = {};
|
|
a = [];
|
|
return a;
|
|
}
|
|
function f5(a) {
|
|
var a = {};
|
|
a = [];
|
|
return a;
|
|
}
|
|
function f6(a) {
|
|
a = {};
|
|
var a = [];
|
|
return a;
|
|
}
|
|
console.log(f1(), f2(), f3(), f4(), f5(), f6());"###;
|
|
let config = r###"{
|
|
"passes": 2,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_2846() {
|
|
let src = r###"function f(a, b) {
|
|
var a = 0;
|
|
b && b(a);
|
|
return a++;
|
|
}
|
|
var c = f();
|
|
console.log(c);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_2660_2() {
|
|
let src = r###"var a = 1;
|
|
function f(b) {
|
|
b && f();
|
|
--a, a.toString();
|
|
}
|
|
f();
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_drop_toplevel_retain_array() {
|
|
let src = r###"var a,
|
|
b = 1,
|
|
c = g;
|
|
function f(d) {
|
|
return function () {
|
|
c = 2;
|
|
};
|
|
}
|
|
a = 2;
|
|
function g() {}
|
|
function h() {}
|
|
console.log((b = 3));"###;
|
|
let config = r###"{
|
|
"top_retain": ["f", "a", "o"],
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_chained_3() {
|
|
let src = r###"console.log(
|
|
(function (a, b) {
|
|
var c = a,
|
|
c = b;
|
|
b++;
|
|
return c;
|
|
})(1, 2)
|
|
);"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_2665() {
|
|
let src = r###"var a = 1;
|
|
function g() {
|
|
a-- && g();
|
|
}
|
|
typeof h == "function" && h();
|
|
function h() {
|
|
typeof g == "function" && g();
|
|
}
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"keep_fargs": false,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"typeofs": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_2516_2() {
|
|
let src = r###"function foo() {
|
|
function qux(x) {
|
|
bar.call(null, x);
|
|
}
|
|
function bar(x) {
|
|
var FOUR = 4;
|
|
var trouble = x || never_called();
|
|
var value = (FOUR - 1) * trouble;
|
|
console.log(value == 6 ? "PASS" : value);
|
|
}
|
|
Baz = qux;
|
|
}
|
|
var Baz;
|
|
foo();
|
|
Baz(2);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_drop_toplevel_funcs_retain() {
|
|
let src = r###"var a,
|
|
b = 1,
|
|
c = g;
|
|
function f(d) {
|
|
return function () {
|
|
c = 2;
|
|
};
|
|
}
|
|
a = 2;
|
|
function g() {}
|
|
function h() {}
|
|
console.log((b = 3));"###;
|
|
let config = r###"{
|
|
"top_retain": "f,a,o",
|
|
"toplevel": "funcs",
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_1709() {
|
|
let src = r###"console.log(
|
|
(function x() {
|
|
var x = 1;
|
|
return x;
|
|
})(),
|
|
(function y() {
|
|
const y = 2;
|
|
return y;
|
|
})(),
|
|
(function z() {
|
|
function z() {}
|
|
return z;
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_drop_var() {
|
|
let src = r###"var a;
|
|
console.log(a, b);
|
|
var a = 1,
|
|
b = 2;
|
|
console.log(a, b);
|
|
var a = 3;
|
|
console.log(a, b);"###;
|
|
let config = r###"{
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_drop_toplevel_funcs() {
|
|
let src = r###"var a,
|
|
b = 1,
|
|
c = g;
|
|
function f(d) {
|
|
return function () {
|
|
c = 2;
|
|
};
|
|
}
|
|
a = 2;
|
|
function g() {}
|
|
function h() {}
|
|
console.log((b = 3));"###;
|
|
let config = r###"{
|
|
"toplevel": "funcs",
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_delete_assign_1() {
|
|
let src = r###"var a;
|
|
console.log(delete (a = undefined));
|
|
console.log(delete (a = void 0));
|
|
console.log(delete (a = Infinity));
|
|
console.log(delete (a = 1 / 0));
|
|
console.log(delete (a = NaN));
|
|
console.log(delete (a = 0 / 0));"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_2226_3() {
|
|
let src = r###"console.log(
|
|
(function (a, b) {
|
|
a += b;
|
|
return a;
|
|
})(1, 2)
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn terser_drop_unused_issue_3146_3() {
|
|
let src = r###"var g = "PASS";
|
|
(function (f) {
|
|
var g = "FAIL";
|
|
f("console.log(g)", g[g]);
|
|
})(function (a) {
|
|
eval(a);
|
|
});"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn terser_drop_unused_issue_3146_4() {
|
|
let src = r###"var g = "PASS";
|
|
(function (f) {
|
|
var g = "FAIL";
|
|
f("console.log(g)", g[g]);
|
|
})(function (a) {
|
|
eval(a);
|
|
});"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_drop_toplevel_vars_retain() {
|
|
let src = r###"var a,
|
|
b = 1,
|
|
c = g;
|
|
function f(d) {
|
|
return function () {
|
|
c = 2;
|
|
};
|
|
}
|
|
a = 2;
|
|
function g() {}
|
|
function h() {}
|
|
console.log((b = 3));"###;
|
|
let config = r###"{
|
|
"top_retain": "f,a,o",
|
|
"toplevel": "vars",
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_2226_2() {
|
|
let src = r###"console.log(
|
|
(function (a, b) {
|
|
a += b;
|
|
return a;
|
|
})(1, 2)
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_drop_fargs() {
|
|
let src = r###"function f(a) {
|
|
var b = a;
|
|
}
|
|
|
|
console.log(f())"###;
|
|
let config = r###"{
|
|
"keep_fargs": false,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_2136_3() {
|
|
let src = r###"function f(x) {
|
|
console.log(x);
|
|
}
|
|
!(function (a, ...b) {
|
|
f(b[0]);
|
|
})(1, 2, 3);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 3,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unsafe": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_2660_1() {
|
|
let src = r###"var a = 2;
|
|
function f(b) {
|
|
return (b && f()) || a--;
|
|
}
|
|
f(1);
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_double_assign_2() {
|
|
let src = r###"for (var i = 0; i < 2; i++) (a = void 0), (a = {}), console.log(a);
|
|
var a;"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_2136_2() {
|
|
let src = r###"function f(x) {
|
|
console.log(x);
|
|
}
|
|
!(function (a, ...b) {
|
|
f(b[0]);
|
|
})(1, 2, 3);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"inline": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_t183() {
|
|
let src = r###"function foo(val) {
|
|
function bar(x) {
|
|
if (x) return x;
|
|
bar(x - 1);
|
|
}
|
|
return bar(val);
|
|
}
|
|
console.log(foo("PASS"));"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"top_retain": []
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_drop_toplevel_vars() {
|
|
let src = r###"var a,
|
|
b = 1,
|
|
c = g;
|
|
function f(d) {
|
|
return function () {
|
|
c = 2;
|
|
};
|
|
}
|
|
a = 2;
|
|
function g() {}
|
|
function h() {}
|
|
console.log((b = 3));"###;
|
|
let config = r###"{
|
|
"toplevel": "vars",
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_2516_1() {
|
|
let src = r###"function foo() {
|
|
function qux(x) {
|
|
bar.call(null, x);
|
|
}
|
|
function bar(x) {
|
|
var FOUR = 4;
|
|
var trouble = x || never_called();
|
|
var value = (FOUR - 1) * trouble;
|
|
console.log(value == 6 ? "PASS" : value);
|
|
}
|
|
Baz = qux;
|
|
}
|
|
var Baz;
|
|
foo();
|
|
Baz(2);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_defun_lambda_same_name() {
|
|
let src = r###"function f(n) {
|
|
return n ? n * f(n - 1) : 1;
|
|
}
|
|
console.log(
|
|
(function f(n) {
|
|
return n ? n * f(n - 1) : 1;
|
|
})(5)
|
|
);"###;
|
|
let config = r###"{
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_drop_toplevel_vars_fargs() {
|
|
let src = r###"var a,
|
|
b = 1,
|
|
c = g;
|
|
function f(d) {
|
|
return function () {
|
|
c = 2;
|
|
};
|
|
}
|
|
a = 2;
|
|
function g() {}
|
|
function h() {}
|
|
console.log((b = 3));"###;
|
|
let config = r###"{
|
|
"keep_fargs": false,
|
|
"toplevel": "vars",
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_1968() {
|
|
let src = r###"function f(c) {
|
|
var a;
|
|
if (c) {
|
|
let b;
|
|
return (a = 2) + (b = 3);
|
|
}
|
|
}
|
|
console.log(f(1));"###;
|
|
let config = r###"{
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_1715_4() {
|
|
let src = r###"var a = 1;
|
|
!(function a() {
|
|
a++;
|
|
try {
|
|
x();
|
|
} catch (a) {
|
|
var a;
|
|
}
|
|
})();
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_drop_assign() {
|
|
let src = r###"function f1() {
|
|
var a;
|
|
a = 1;
|
|
}
|
|
function f2() {
|
|
var a = 1;
|
|
a = 2;
|
|
}
|
|
function f3(a) {
|
|
a = 1;
|
|
}
|
|
function f4() {
|
|
var a;
|
|
return (a = 1);
|
|
}
|
|
function f5() {
|
|
var a;
|
|
return function () {
|
|
a = 1;
|
|
};
|
|
}
|
|
|
|
console.log(f1())
|
|
console.log(f2())
|
|
console.log(f3())
|
|
console.log(f4())
|
|
console.log(f5())"###;
|
|
let config = r###"{
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_issue_3146_1() {
|
|
let src = r###"(function (f) {
|
|
f("g()");
|
|
})(function (a) {
|
|
eval(a);
|
|
function g(b) {
|
|
if (!b) b = "PASS";
|
|
console.log(b);
|
|
}
|
|
});"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_delete_assign_2() {
|
|
let src = r###"var a;
|
|
console.log(delete (a = undefined));
|
|
console.log(delete (a = void 0));
|
|
console.log(delete (a = Infinity));
|
|
console.log(delete (a = 1 / 0));
|
|
console.log(delete (a = NaN));
|
|
console.log(delete (a = 0 / 0));"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"keep_infinity": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_drop_unused_drop_toplevel_all_retain() {
|
|
let src = r###"var a,
|
|
b = 1,
|
|
c = g;
|
|
function f(d) {
|
|
return function () {
|
|
c = 2;
|
|
};
|
|
}
|
|
a = 2;
|
|
function g() {}
|
|
function h() {}
|
|
console.log((b = 3));"###;
|
|
let config = r###"{
|
|
"top_retain": "f,a,o",
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_comparing_issue_2857_6() {
|
|
let src = r###"function f(a) {
|
|
if ({}.b === undefined || {}.b === null)
|
|
return a.b !== undefined && a.b !== null;
|
|
}
|
|
console.log(
|
|
f({
|
|
a: [null],
|
|
get b() {
|
|
return this.a.shift();
|
|
},
|
|
})
|
|
);"###;
|
|
let config = r###"{
|
|
"comparisons": true,
|
|
"pure_getters": "strict",
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_pure_getters_impure_getter_2() {
|
|
let src = r###"({
|
|
get a() {
|
|
console.log(1);
|
|
},
|
|
b: 1,
|
|
}.a);
|
|
({
|
|
get a() {
|
|
console.log(1);
|
|
},
|
|
b: 1,
|
|
}.b);"###;
|
|
let config = r###"{
|
|
"pure_getters": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_pure_getters_issue_2838() {
|
|
let src = r###"function f(a, b) {
|
|
(a || b).c = "PASS";
|
|
(function () {
|
|
return f(a, b);
|
|
}.prototype.foo = "bar");
|
|
}
|
|
var o = {};
|
|
f(null, o);
|
|
console.log(o.c);"###;
|
|
let config = r###"{
|
|
"pure_getters": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_pure_getters_issue_2938_4() {
|
|
let src = r###"var Parser = function Parser() {};
|
|
var p = Parser.prototype;
|
|
var unused = p.x;
|
|
p.initialContext = function initialContext() {
|
|
p.y;
|
|
console.log("PASS");
|
|
};
|
|
p.braceIsBlock = function () {};
|
|
new Parser().initialContext();"###;
|
|
let config = r###"{
|
|
"pure_getters": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_pure_getters_set_mutable_1() {
|
|
let src = r###"!(function a() {
|
|
a.foo += "";
|
|
if (a.foo) console.log("PASS");
|
|
else console.log("FAIL");
|
|
})();"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"pure_getters": "strict",
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_pure_getters_issue_2938_3() {
|
|
let src = r###"function f(a) {
|
|
var unused = a.a;
|
|
a.b = "PASS";
|
|
a.c;
|
|
}
|
|
var o = {};
|
|
o.d;
|
|
f(o);
|
|
console.log(o.b);"###;
|
|
let config = r###"{
|
|
"pure_getters": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_pure_getters_set_immutable_6() {
|
|
let src = r###"var a = 1;
|
|
a.foo += "";
|
|
if (a.foo) console.log("FAIL");
|
|
else console.log("PASS");"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"pure_getters": "strict",
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_pure_getters_set_immutable_1() {
|
|
let src = r###"var a = 1;
|
|
a.foo += "";
|
|
if (a.foo) console.log("FAIL");
|
|
else console.log("PASS");"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"pure_getters": "strict",
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_pure_getters_set_mutable_2() {
|
|
let src = r###"!(function a() {
|
|
a.foo += "";
|
|
if (a.foo) console.log("PASS");
|
|
else console.log("FAIL");
|
|
})();"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"conditionals": true,
|
|
"pure_getters": "strict",
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_dead_code_issue_2860_1() {
|
|
let src = r###"console.log(
|
|
(function (a) {
|
|
return (a ^= 1);
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_dead_code_global_fns() {
|
|
let src = r###"Boolean(1, 2);
|
|
decodeURI(1, 2);
|
|
decodeURIComponent(1, 2);
|
|
Date(1, 2);
|
|
encodeURI(1, 2);
|
|
encodeURIComponent(1, 2);
|
|
Error(1, 2);
|
|
escape(1, 2);
|
|
EvalError(1, 2);
|
|
isFinite(1, 2);
|
|
isNaN(1, 2);
|
|
Number(1, 2);
|
|
Object(1, 2);
|
|
parseFloat(1, 2);
|
|
parseInt(1, 2);
|
|
RangeError(1, 2);
|
|
ReferenceError(1, 2);
|
|
String(1, 2);
|
|
SyntaxError(1, 2);
|
|
TypeError(1, 2);
|
|
unescape(1, 2);
|
|
URIError(1, 2);
|
|
try {
|
|
Function(1, 2);
|
|
} catch (e) {
|
|
console.log(e.name);
|
|
}
|
|
try {
|
|
RegExp(1, 2);
|
|
} catch (e) {
|
|
console.log(e.name);
|
|
}
|
|
try {
|
|
Array(NaN);
|
|
} catch (e) {
|
|
console.log(e.name);
|
|
}"###;
|
|
let config = r###"{
|
|
"side_effects": true,
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_block_scope_issue_334() {
|
|
let src = r###"(function (A) {
|
|
(function () {
|
|
doPrint();
|
|
})();
|
|
function doPrint() {
|
|
print(A);
|
|
}
|
|
})("Hello World!");
|
|
function print(A) {
|
|
if (!A.x) {
|
|
console.log(A);
|
|
}
|
|
}"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_issue_3021() {
|
|
let src = r###"var a = 1,
|
|
b = 2;
|
|
(function () {
|
|
b = a;
|
|
if (a++ + b--) return 1;
|
|
return;
|
|
var b = {};
|
|
})();
|
|
console.log(a, b);"###;
|
|
let config = r###"{
|
|
"hoist_props": true,
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_contains_this_2() {
|
|
let src = r###"var o = {
|
|
u: function () {
|
|
return this === this;
|
|
},
|
|
p: 1,
|
|
};
|
|
console.log(o.p, o.p, o.u);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"hoist_props": true,
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn terser_hoist_props_issue_851_hoist_to_conflicting_name() {
|
|
let src = r###"const BBB = { CCC: "PASS" };
|
|
if (id(true)) {
|
|
const BBB_CCC = BBB.CCC;
|
|
console.log(BBB_CCC);
|
|
}"###;
|
|
let config = r###"{
|
|
"hoist_props": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_name_collision_1() {
|
|
let src = r###"var obj_foo = 1;
|
|
var obj_bar = 2;
|
|
function f() {
|
|
var obj = { foo: 3, bar: 4, "b-r": 5, "b+r": 6, "b!r": 7 };
|
|
console.log(obj_foo, obj.foo, obj.bar, obj["b-r"], obj["b+r"], obj["b!r"]);
|
|
}
|
|
f();"###;
|
|
let config = r###"{
|
|
"hoist_props": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_new_this() {
|
|
let src = r###"var o = {
|
|
a: 1,
|
|
b: 2,
|
|
f: function (a) {
|
|
this.b = a;
|
|
},
|
|
};
|
|
console.log(new o.f(o.a).b, o.b);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"hoist_props": true,
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_toplevel_let() {
|
|
let src = r###"let a = { b: 1, c: 2 };
|
|
console.log(a.b + a.c);"###;
|
|
let config = r###"{
|
|
"hoist_props": true,
|
|
"reduce_vars": true,
|
|
"toplevel": false
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_undefined_key() {
|
|
let src = r###"var a,
|
|
o = {};
|
|
o[a] = 1;
|
|
o.b = 2;
|
|
console.log(o[a] + o.b);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"hoist_props": true,
|
|
"join_vars": true,
|
|
"passes": 4,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_direct_access_1() {
|
|
let src = r###"var a = 0;
|
|
var obj = { a: 1, b: 2 };
|
|
for (var k in obj) a++;
|
|
console.log(a, obj.a);"###;
|
|
let config = r###"{
|
|
"hoist_props": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_issue_2473_3() {
|
|
let src = r###"var o = { a: 1, b: 2 };
|
|
console.log(o.a, o.b);"###;
|
|
let config = r###"{
|
|
"hoist_props": true,
|
|
"reduce_vars": true,
|
|
"top_retain": "o",
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_issue_2473_4() {
|
|
let src = r###"(function () {
|
|
var o = { a: 1, b: 2 };
|
|
console.log(o.a, o.b);
|
|
})();"###;
|
|
let config = r###"{
|
|
"hoist_props": true,
|
|
"reduce_vars": true,
|
|
"top_retain": "o",
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_toplevel_const() {
|
|
let src = r###"const a = { b: 1, c: 2 };
|
|
console.log(a.b + a.c);"###;
|
|
let config = r###"{
|
|
"hoist_props": true,
|
|
"reduce_vars": true,
|
|
"toplevel": false
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_issue_2377_3() {
|
|
let src = r###"var obj = {
|
|
foo: 1,
|
|
bar: 2,
|
|
square: function (x) {
|
|
return x * x;
|
|
},
|
|
cube: function (x) {
|
|
return x * x * x;
|
|
},
|
|
};
|
|
console.log(obj.foo, obj.cube(3));"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"hoist_props": true,
|
|
"inline": true,
|
|
"passes": 4,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_issue_2508_2() {
|
|
let src = r###"var o = {
|
|
a: { b: 2 },
|
|
f: function (x) {
|
|
console.log(x);
|
|
},
|
|
};
|
|
o.f(o.a);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"hoist_props": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore = "Function anonymous"]
|
|
fn terser_hoist_props_issue_2508_5() {
|
|
let src = r###"var o = {
|
|
f: function (x) {
|
|
console.log(x);
|
|
},
|
|
};
|
|
o.f(o.f);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"hoist_props": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_issue_2377_2() {
|
|
let src = r###"var obj = {
|
|
foo: 1,
|
|
bar: 2,
|
|
square: function (x) {
|
|
return x * x;
|
|
},
|
|
cube: function (x) {
|
|
return x * x * x;
|
|
},
|
|
};
|
|
console.log(obj.foo, obj.cube(3));"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"hoist_props": true,
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_toplevel_var() {
|
|
let src = r###"var a = { b: 1, c: 2 };
|
|
console.log(a.b + a.c);"###;
|
|
let config = r###"{
|
|
"hoist_props": true,
|
|
"reduce_vars": true,
|
|
"toplevel": false
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_issue_3046() {
|
|
let src = r###"console.log(
|
|
(function (a) {
|
|
do {
|
|
var b = { c: a++ };
|
|
} while (b.c && a);
|
|
return a;
|
|
})(0)
|
|
);"###;
|
|
let config = r###"{
|
|
"hoist_props": true,
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_name_collision_3() {
|
|
let src = r###"var o = {
|
|
p: 1,
|
|
"+": function (x) {
|
|
return x;
|
|
},
|
|
"-": function (x) {
|
|
return x + 1;
|
|
},
|
|
},
|
|
o__$0 = 2,
|
|
o__$1 = 3;
|
|
console.log(o.p === o.p, o["+"](4), o["-"](5));"###;
|
|
let config = r###"{
|
|
"hoist_props": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_hoist_class_with_new() {
|
|
let src = r###"var o = {
|
|
p: class Foo {
|
|
constructor(value) {
|
|
this.value = value * 10;
|
|
}
|
|
},
|
|
x: 1,
|
|
y: 2,
|
|
};
|
|
console.log(o.p.name, o.p === o.p, new o.p(o.x).value, new o.p(o.y).value);"###;
|
|
let config = r###"{
|
|
"comparisons": true,
|
|
"evaluate": true,
|
|
"hoist_props": true,
|
|
"inline": true,
|
|
"keep_classnames": true,
|
|
"keep_fnames": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, true);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_hoist_function_with_call() {
|
|
let src = r###"var o = {
|
|
p: function Foo(value) {
|
|
return 10 * value;
|
|
},
|
|
x: 1,
|
|
y: 2,
|
|
};
|
|
console.log(o.p.name, o.p === o.p, o.p(o.x), o.p(o.y));"###;
|
|
let config = r###"{
|
|
"comparisons": true,
|
|
"evaluate": true,
|
|
"hoist_props": true,
|
|
"inline": true,
|
|
"keep_fnames": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_name_collision_2() {
|
|
let src = r###"var o = {
|
|
p: 1,
|
|
"+": function (x) {
|
|
return x;
|
|
},
|
|
"-": function (x) {
|
|
return x + 1;
|
|
},
|
|
},
|
|
o__$0 = 2,
|
|
o__$1 = 3;
|
|
console.log(o.p === o.p, o["+"](4), o["-"](5), o__$0, o__$1);"###;
|
|
let config = r###"{
|
|
"hoist_props": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_direct_access_2() {
|
|
let src = r###"var o = { a: 1 };
|
|
var f = function (k) {
|
|
if (o[k]) return "PASS";
|
|
};
|
|
console.log(f("a"));"###;
|
|
let config = r###"{
|
|
"hoist_props": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_hoist_class() {
|
|
let src = r###"function run(c, v) {
|
|
return new c(v).value;
|
|
}
|
|
var o = {
|
|
p: class Foo {
|
|
constructor(value) {
|
|
this.value = value * 10;
|
|
}
|
|
},
|
|
x: 1,
|
|
y: 2,
|
|
};
|
|
console.log(o.p.name, o.p === o.p, run(o.p, o.x), run(o.p, o.y));"###;
|
|
let config = r###"{
|
|
"comparisons": true,
|
|
"evaluate": true,
|
|
"hoist_props": true,
|
|
"inline": true,
|
|
"keep_classnames": true,
|
|
"keep_fnames": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, true);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_issue_2519() {
|
|
let src = r###"function testFunc() {
|
|
var dimensions = { minX: 5, maxX: 6 };
|
|
var scale = 1;
|
|
var d = { x: (dimensions.maxX + dimensions.minX) / 2 };
|
|
return d.x * scale;
|
|
}
|
|
console.log(testFunc());"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"hoist_props": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_issue_2377_1() {
|
|
let src = r###"var obj = {
|
|
foo: 1,
|
|
bar: 2,
|
|
square: function (x) {
|
|
return x * x;
|
|
},
|
|
cube: function (x) {
|
|
return x * x * x;
|
|
},
|
|
};
|
|
console.log(obj.foo, obj.cube(3));"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"hoist_props": true,
|
|
"inline": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore = "Function anoymous"]
|
|
fn terser_hoist_props_issue_2508_6() {
|
|
let src = r###"var o = {
|
|
f: (x) => {
|
|
console.log(x);
|
|
},
|
|
};
|
|
o.f(o.f);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"hoist_props": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_hoist_props_issue_2508_1() {
|
|
let src = r###"var o = {
|
|
a: [1],
|
|
f: function (x) {
|
|
console.log(x);
|
|
},
|
|
};
|
|
o.f(o.a);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"hoist_props": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_identity_inline_identity_extra_params() {
|
|
let src = r###"const id = (x) => x;
|
|
console.log(id(1, console.log(2)), id(3, 4));"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"reduce_vars": true,
|
|
"unused": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_identity_inline_identity_function() {
|
|
let src = r###"function id(x) {
|
|
return x;
|
|
}
|
|
console.log(id(1), id(2));"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"reduce_vars": true,
|
|
"unused": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_identity_inline_identity_duplicate_arg_var() {
|
|
let src = r###"const id = (x) => {
|
|
return x;
|
|
var x;
|
|
};
|
|
console.log(id(1), id(2));"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"reduce_vars": true,
|
|
"unused": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_template_string_regex_2() {
|
|
let src = r###"console.log(`${/a/} ${6 / 2} ${/b/.test("b")} ${1 ? /c/ : /d/}`);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_template_string_evaluate_nested_templates() {
|
|
let src = r###"/*#__NOINLINE__*/ const any = 'any string, but should not be inlined';
|
|
|
|
var foo = `${`${`${`foo`}`}`}`;
|
|
var bar = `before ${`innerBefore ${any} innerAfter`} after`;
|
|
var baz = `1 ${2 + `3 ${any} 4` + 5} 6`;
|
|
|
|
console.log(foo);
|
|
console.log(bar);
|
|
console.log(baz);"###;
|
|
let config = r###"{
|
|
"evaluate": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_destructuring_assign_of_computed_key() {
|
|
let src = r###"let x;
|
|
let four = 4;
|
|
({ [5 + 2 - four]: x } = { [1 + 2]: 42 });
|
|
console.log(x);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_unused_destructuring_getter_side_effect_2() {
|
|
let src = r###"function extract(obj) {
|
|
const { a: a, b: b } = obj;
|
|
console.log(b);
|
|
}
|
|
extract({ a: 1, b: 2 });
|
|
extract({
|
|
get a() {
|
|
var s = "side effect";
|
|
console.log(s);
|
|
return s;
|
|
},
|
|
b: 4,
|
|
});"###;
|
|
let config = r###"{
|
|
"pure_getters": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_mangle_destructuring_decl_array() {
|
|
let src = r###"var [, t, e, n, s, o = 2, r = [1 + 2]] = [9, 8, 7, 6];
|
|
console.log(t, e, n, s, o, r);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"unused": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_issue_3205_4() {
|
|
let src = r###"(function () {
|
|
function f(o) {
|
|
var { a: x } = o;
|
|
console.log(x);
|
|
}
|
|
f({ a: "PASS" });
|
|
})();"###;
|
|
let config = r###"{
|
|
"inline": 3,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_issue_3205_3() {
|
|
let src = r###"(function () {
|
|
function f(o, { a: x } = o) {
|
|
console.log(x);
|
|
}
|
|
f({ a: "PASS" });
|
|
})();"###;
|
|
let config = r###"{
|
|
"inline": 3,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_unused_destructuring_multipass() {
|
|
let src = r###"let { w: w, x: y, z: z } = { x: 1, y: 2, z: 3 };
|
|
console.log(y);
|
|
if (0) {
|
|
console.log(z);
|
|
}"###;
|
|
let config = r###"{
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"toplevel": true,
|
|
"passes": 2,
|
|
"pure_getters": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_arrow_func_with_destructuring_args() {
|
|
let src = r###"(({ foo: foo = 1 + 0, bar: bar = 2 }, [car = 3, far = 4]) => {
|
|
console.log(foo, bar, car, far);
|
|
})({ bar: 5 - 0 }, [, 6]);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"unused": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_issue_3205_2() {
|
|
let src = r###"(function () {
|
|
function f() {
|
|
var o = { a: "PASS" },
|
|
{ a: x } = o;
|
|
console.log(x);
|
|
}
|
|
f();
|
|
})();"###;
|
|
let config = r###"{
|
|
"inline": 3,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_empty_object_destructuring_3() {
|
|
let src = r###"var {} = Object;
|
|
let { L: L } = Object,
|
|
L2 = "foo";
|
|
const bar = "bar",
|
|
{ prop: C1, C2: C2 = console.log("side effect"), C3: C3 } = Object;"###;
|
|
let config = r###"{
|
|
"pure_getters": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_empty_object_destructuring_4() {
|
|
let src = r###"var {} = Object;
|
|
let { L: L } = Object,
|
|
L2 = "foo";
|
|
const bar = "bar",
|
|
{ prop: C1, C2: C2 = console.log("side effect"), C3: C3 } = Object;"###;
|
|
let config = r###"{
|
|
"pure_getters": true,
|
|
"toplevel": true,
|
|
"unsafe": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_issue_3205_5() {
|
|
let src = r###"(function () {
|
|
function f(g) {
|
|
var o = g,
|
|
{ a: x } = o;
|
|
console.log(x);
|
|
}
|
|
f({ a: "PASS" });
|
|
})();"###;
|
|
let config = r###"{
|
|
"inline": 3,
|
|
"passes": 4,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_unused_destructuring_decl_1() {
|
|
let src = r###"let { x: L, y: y } = { x: 2 };
|
|
var { U: u, V: V } = { V: 3 };
|
|
const { C: C, D: D } = { C: 1, D: 4 };
|
|
console.log(L, V);"###;
|
|
let config = r###"{
|
|
"pure_getters": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_mangle_destructuring_decl() {
|
|
let src = r###"function test(opts) {
|
|
let a = opts.a || { e: 7, n: 8 };
|
|
let { t: t, e: e, n: n, s: s = 5 + 4, o: o, r: r } = a;
|
|
console.log(t, e, n, s, o, r);
|
|
}
|
|
test({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
|
|
test({});"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_unused_destructuring_arrow_param() {
|
|
let src = r###"let bar = ({ w: w = console.log("side effect"), x: x, y: z }) => {
|
|
console.log(x);
|
|
};
|
|
bar({ x: 4, y: 5, z: 6 });"###;
|
|
let config = r###"{
|
|
"pure_getters": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_anon_func_with_destructuring_args() {
|
|
let src = r###"(function ({ foo: foo = 1 + 0, bar: bar = 2 }, [car = 3, far = 4]) {
|
|
console.log(foo, bar, car, far);
|
|
})({ bar: 5 - 0 }, [, 6]);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"unused": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_mangle_destructuring_assign_toplevel_true() {
|
|
let src = r###"function test(opts) {
|
|
let s, o, r;
|
|
let a = opts.a || { e: 7, n: 8 };
|
|
({ t, e, n, s = 5 + 4, o, r } = a);
|
|
console.log(t, e, n, s, o, r);
|
|
}
|
|
let t, e, n;
|
|
test({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
|
|
test({});"###;
|
|
let config = r###"{
|
|
"toplevel": true,
|
|
"evaluate": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_mangle_destructuring_decl_collapse_vars() {
|
|
let src = r###"function test(opts) {
|
|
let a = opts.a || { e: 7, n: 8 };
|
|
let { t: t, e: e, n: n, s: s = 5 + 4, o: o, r: r } = a;
|
|
console.log(t, e, n, s, o, r);
|
|
}
|
|
test({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
|
|
test({});"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_unused_destructuring_decl_5() {
|
|
let src = r###"const { a: a, b: c, d: d = new Object(1) } = { b: 7 };
|
|
let { e: e, f: g, h: h = new Object(2) } = { e: 8 };
|
|
var { w: w, x: y, z: z = new Object(3) } = { w: 4, x: 5, y: 6 };
|
|
console.log(c, e, z + 0);"###;
|
|
let config = r###"{
|
|
"pure_getters": true,
|
|
"toplevel": true,
|
|
"top_retain": ["a", "e", "w"],
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_destructuring_mangle_destructuring_assign_toplevel_false() {
|
|
let src = r###"function test(opts) {
|
|
let s, o, r;
|
|
let a = opts.a || { e: 7, n: 8 };
|
|
({ t, e, n, s = 9, o, r } = a);
|
|
console.log(t, e, n, s, o, r);
|
|
}
|
|
let t, e, n;
|
|
test({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
|
|
test({});"###;
|
|
let config = r###"{
|
|
"toplevel": false,
|
|
"evaluate": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_arrow_issue_2105_2() {
|
|
let src = r###"((factory) => {
|
|
factory();
|
|
})(() =>
|
|
((fn) => {
|
|
fn()().prop();
|
|
})(() => {
|
|
let bar = () => {
|
|
var quux = () => {
|
|
console.log("PASS");
|
|
},
|
|
foo = () => {
|
|
console.log;
|
|
quux();
|
|
};
|
|
return { prop: foo };
|
|
};
|
|
return bar;
|
|
})
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_arrow_issue_2105_1() {
|
|
let src = r###"!(function (factory) {
|
|
factory();
|
|
})(function () {
|
|
return (function (fn) {
|
|
fn()().prop();
|
|
})(function () {
|
|
function bar() {
|
|
var quux = function () {
|
|
console.log("PASS");
|
|
},
|
|
foo = function () {
|
|
console.log;
|
|
quux();
|
|
};
|
|
return { prop: foo };
|
|
}
|
|
return bar;
|
|
});
|
|
});"###;
|
|
let config = r###"{
|
|
"unsafe_arrows": true,
|
|
"collapse_vars": true,
|
|
"ecma": 2015,
|
|
"inline": true,
|
|
"passes": 3,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unsafe_methods": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_arrow_issue_2084() {
|
|
let src = r###"var c = 0;
|
|
!(function () {
|
|
!(function (c) {
|
|
c = 1 + c;
|
|
var c = 0;
|
|
function f14(a_1) {
|
|
if (((c = 1 + c), 0 !== (23).toString()))
|
|
(c = 1 + c), a_1 && (a_1[0] = 0);
|
|
}
|
|
f14();
|
|
})(-1);
|
|
})();
|
|
console.log(c);"###;
|
|
let config = r###"{
|
|
"unsafe_arrows": true,
|
|
"collapse_vars": true,
|
|
"conditionals": true,
|
|
"ecma": 2015,
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_t120_issue_t120_4() {
|
|
let src = r###"for (
|
|
var x = 1,
|
|
t = (o) => {
|
|
var i = +o;
|
|
return console.log(i + i) && 0;
|
|
};
|
|
x--;
|
|
t(2)
|
|
);"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"inline": 3,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_t120_issue_t120_5() {
|
|
let src = r###"for (
|
|
var x = 1,
|
|
t = (o) => {
|
|
var i = +o;
|
|
return console.log(i + i) && 0;
|
|
};
|
|
x--;
|
|
|
|
)
|
|
t(3);"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"inline": 3,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_class_properties_mangle_keep_quoted() {
|
|
let src = r###"class Foo {
|
|
bar = "bar";
|
|
static zzz = "zzz";
|
|
toString() {
|
|
return this.bar + Foo.zzz;
|
|
}
|
|
}
|
|
|
|
console.log(new Foo().toString())"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_class_properties_static_means_execution() {
|
|
let src = r###"let x = 0;
|
|
class NoProps {}
|
|
class WithProps {
|
|
prop = (x = x === 1 ? "PASS" : "FAIL");
|
|
}
|
|
class WithStaticProps {
|
|
static prop = (x = x === 0 ? 1 : "FAIL");
|
|
}
|
|
new NoProps();
|
|
new WithProps();
|
|
new WithStaticProps();
|
|
console.log(x);"###;
|
|
let config = r###"{
|
|
"toplevel": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1447_conditional_false_stray_else_in_loop() {
|
|
let src = r###"for (var i = 1; i <= 4; ++i) {
|
|
if (i <= 2) continue;
|
|
console.log(i);
|
|
}"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"comparisons": true,
|
|
"conditionals": false,
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"hoist_vars": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"loops": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_object_spread_unsafe() {
|
|
let src = r###"var o1 = { x: 1, y: 2 };
|
|
var o2 = { x: 3, z: 4 };
|
|
var cloned = { ...o1 };
|
|
var merged = { ...o1, ...o2 };
|
|
console.log(cloned, merged);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"join_vars": true,
|
|
"passes": 3,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unsafe": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_issue_2794_4() {
|
|
let src = r###"for (var x of ([1, 2], [3, 4])) {
|
|
console.log(x);
|
|
}"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_issue_2794_3() {
|
|
let src = r###"function foo() {
|
|
for (const a of func(value)) {
|
|
console.log(a);
|
|
}
|
|
function func(va) {
|
|
return doSomething(va);
|
|
}
|
|
}
|
|
function doSomething(x) {
|
|
return [x, 2 * x, 3 * x];
|
|
}
|
|
const value = 10;
|
|
foo();"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"inline": 3,
|
|
"passes": 3,
|
|
"properties": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_array_spread_of_sequence() {
|
|
let src = r###"var a = [1];
|
|
console.log([...(a, a)]);
|
|
console.log([...a, a]);
|
|
console.log([...(a || a)]);
|
|
console.log([...(a || a)]);"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_issue_2794_2() {
|
|
let src = r###"function foo() {
|
|
for (const a of func(value)) {
|
|
console.log(a);
|
|
}
|
|
function func(va) {
|
|
return doSomething(va);
|
|
}
|
|
}
|
|
function doSomething(x) {
|
|
return [x, 2 * x, 3 * x];
|
|
}
|
|
const value = 10;
|
|
foo();"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 1,
|
|
"properties": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": false,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_issue_2874_1() {
|
|
let src = r###"(function () {
|
|
function foo() {
|
|
let letters = ["A", "B", "C"];
|
|
let result = [2, 1, 0].map((key) => bar(letters[key] + key));
|
|
return result;
|
|
}
|
|
function bar(value) {
|
|
return () => console.log(value);
|
|
}
|
|
foo().map((fn) => fn());
|
|
})();"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"inline": 3,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_issue_2762() {
|
|
let src = r###"var bar = 1,
|
|
T = true;
|
|
(function () {
|
|
if (T) {
|
|
const a = function () {
|
|
var foo = bar;
|
|
console.log(foo, a.prop, b.prop);
|
|
};
|
|
a.prop = 2;
|
|
const b = { prop: 3 };
|
|
a();
|
|
}
|
|
})();"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_issue_1898() {
|
|
let src = r###"class Foo {
|
|
bar() {
|
|
for (const x of [6, 5]) {
|
|
for (let y of [4, 3]) {
|
|
for (var z of [2, 1]) {
|
|
console.log(x, y, z);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
new Foo().bar();"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_issue_2794_6() {
|
|
let src = r###"for (let e of ([1, 2], [3, 4, 5])) {
|
|
console.log(e);
|
|
}"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_issue_2794_1() {
|
|
let src = r###"function foo() {
|
|
for (const a of func(value)) {
|
|
console.log(a);
|
|
}
|
|
function func(va) {
|
|
return doSomething(va);
|
|
}
|
|
}
|
|
function doSomething(x) {
|
|
return [x, 2 * x, 3 * x];
|
|
}
|
|
const value = 10;
|
|
foo();"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 1,
|
|
"properties": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": false,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_issue_2874_2() {
|
|
let src = r###"(function () {
|
|
let keys = [];
|
|
function foo() {
|
|
var result = [2, 1, 0].map((value) => {
|
|
keys.push(value);
|
|
return bar();
|
|
});
|
|
return result;
|
|
}
|
|
function bar() {
|
|
var letters = ["A", "B", "C"],
|
|
key = keys.shift();
|
|
return () => console.log(letters[key] + key);
|
|
}
|
|
foo().map((fn) => fn());
|
|
})();"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"inline": 3,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_issue_t80() {
|
|
let src = r###"function foo(data = []) {
|
|
var u,
|
|
v = "unused";
|
|
if (arguments.length == 1) {
|
|
data = [data];
|
|
}
|
|
return data;
|
|
}
|
|
console.log(JSON.stringify([foo(), foo(null), foo(5, 6)]));"###;
|
|
let config = r###"{
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_issue_2349() {
|
|
let src = r###"function foo(boo, key) {
|
|
const value = boo.get();
|
|
return value.map(({ [key]: bar }) => bar);
|
|
}
|
|
console.log(foo({ get: () => [{ blah: 42 }] }, "blah"));"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_issue_2874_3() {
|
|
let src = r###"function f() {
|
|
return x + y;
|
|
}
|
|
let x, y;
|
|
let a = (z) => {
|
|
x = "A";
|
|
y = z;
|
|
console.log(f());
|
|
};
|
|
a(1);
|
|
a(2);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"inline": 3,
|
|
"reduce_funcs": false,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_harmony_issue_2349b() {
|
|
let src = r###"function foo(boo, key) {
|
|
const value = boo.get();
|
|
return value.map(function ({ [key]: bar }) {
|
|
return bar;
|
|
});
|
|
}
|
|
console.log(
|
|
foo(
|
|
{
|
|
get: function () {
|
|
return [{ blah: 42 }];
|
|
},
|
|
},
|
|
"blah"
|
|
)
|
|
);"###;
|
|
let config = r###"{
|
|
"arrows": true,
|
|
"collapse_vars": true,
|
|
"ecma": 2015,
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 3,
|
|
"properties": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"side_effects": true,
|
|
"unsafe_arrows": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1275_string_plus_optimization() {
|
|
let src = r###"function foo(anything) {
|
|
function throwing_function() {
|
|
throw "nope";
|
|
}
|
|
try {
|
|
console.log("0" + throwing_function() ? "yes" : "no");
|
|
} catch (ex) {
|
|
console.log(ex);
|
|
}
|
|
console.log("0" + anything ? "yes" : "no");
|
|
console.log(anything + "0" ? "Yes" : "No");
|
|
console.log("" + anything);
|
|
console.log(anything + "");
|
|
}
|
|
foo();"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"comparisons": true,
|
|
"conditionals": true,
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"hoist_funs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_async_async_inline() {
|
|
let src = r###"(async function () {
|
|
return await 3;
|
|
})();
|
|
(async function (x) {
|
|
await console.log(x);
|
|
})(4);
|
|
function invoke(x, y) {
|
|
return x(y);
|
|
}
|
|
invoke(async function () {
|
|
return await 1;
|
|
});
|
|
invoke(async function (x) {
|
|
await console.log(x);
|
|
}, 2);
|
|
function top() {
|
|
console.log("top");
|
|
}
|
|
top();
|
|
async function async_top() {
|
|
console.log("async_top");
|
|
}
|
|
async_top();"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"negate_iife": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn terser_logical_assignments_assign_in_conditional_part() {
|
|
let src = r###"var status = "PASS";
|
|
var nil = null;
|
|
var nil_prop = { prop: null };
|
|
nil &&= console.log((status = "FAIL"));
|
|
nil_prop.prop &&= console.log((status = "FAIL"));
|
|
console.log(status);"###;
|
|
let config = r###"{
|
|
"toplevel": true,
|
|
"evaluate": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn terser_logical_assignments_assignment_in_left_part() {
|
|
let src = r###"var status = "FAIL";
|
|
var x = {};
|
|
x[(status = "PASS")] ||= 1;
|
|
console.log(status);"###;
|
|
let config = r###"{
|
|
"toplevel": true,
|
|
"evaluate": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_labels_labels_4() {
|
|
let src = r###"out: for (var i = 0; i < 5; ++i) {
|
|
if (i < 3) continue out;
|
|
console.log(i);
|
|
}"###;
|
|
let config = r###"{
|
|
"conditionals": true,
|
|
"dead_code": true,
|
|
"if_return": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_labels_labels_3() {
|
|
let src = r###"for (var i = 0; i < 5; ++i) {
|
|
if (i < 3) continue;
|
|
console.log(i);
|
|
}"###;
|
|
let config = r###"{
|
|
"conditionals": true,
|
|
"dead_code": true,
|
|
"if_return": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_labels_labels_6() {
|
|
let src = r###"out: break out;
|
|
|
|
console.log('PASS')"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_t292_no_flatten_with_var_colliding_with_arg_value_inner_scope() {
|
|
let src = r###"var g = ["a"];
|
|
function problem(arg) {
|
|
return g.indexOf(arg);
|
|
}
|
|
function unused(arg) {
|
|
return problem(arg);
|
|
}
|
|
function a(arg) {
|
|
return problem(arg);
|
|
}
|
|
function b(test) {
|
|
var problem = test * 2;
|
|
console.log(problem);
|
|
return g[problem];
|
|
}
|
|
function c(arg) {
|
|
return b(a(arg));
|
|
}
|
|
console.log(c("a"));"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"inline": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_t292_no_flatten_with_arg_colliding_with_arg_value_inner_scope() {
|
|
let src = r###"var g = ["a"];
|
|
function problem(arg) {
|
|
return g.indexOf(arg);
|
|
}
|
|
function unused(arg) {
|
|
return problem(arg);
|
|
}
|
|
function a(arg) {
|
|
return problem(arg);
|
|
}
|
|
function b(problem) {
|
|
return g[problem];
|
|
}
|
|
function c(arg) {
|
|
return b(a(arg));
|
|
}
|
|
console.log(c("a"));"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"inline": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1770_numeric_literal() {
|
|
let src = r###"var obj = {
|
|
0: 0,
|
|
"-0": 1,
|
|
42: 2,
|
|
42: 3,
|
|
37: 4,
|
|
o: 5,
|
|
1e42: 6,
|
|
j: 7,
|
|
1e42: 8,
|
|
};
|
|
|
|
console.log(obj[-0], obj[-""], obj["-0"]);
|
|
|
|
console.log(obj[42], obj["42"]);
|
|
|
|
console.log(obj[37], obj["o"], obj[37], obj["37"]);
|
|
|
|
console.log(obj[1e42], obj["j"], obj["1e+42"]);"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1770_mangle_props() {
|
|
let src = r###"var obj = { undefined: 1, NaN: 2, Infinity: 3, "-Infinity": 4, null: 5 };
|
|
console.log(
|
|
obj[void 0],
|
|
obj[undefined],
|
|
obj["undefined"],
|
|
obj[0 / 0],
|
|
obj[NaN],
|
|
obj["NaN"],
|
|
obj[1 / 0],
|
|
obj[Infinity],
|
|
obj["Infinity"],
|
|
obj[-1 / 0],
|
|
obj[-Infinity],
|
|
obj["-Infinity"],
|
|
obj[null],
|
|
obj["null"]
|
|
);"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1105_infinity_not_in_with_scope() {
|
|
let src = r###"var o = { Infinity: "oInfinity" };
|
|
var vInfinity = "Infinity";
|
|
vInfinity = Infinity;
|
|
|
|
console.log(o)
|
|
console.log(vInfinity)"###;
|
|
let config = r###"{
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_3113_1() {
|
|
let src = r###"var c = 0;
|
|
(function () {
|
|
function f() {
|
|
while (g());
|
|
}
|
|
var a = f();
|
|
function g() {
|
|
a && a[c++];
|
|
}
|
|
g((a = 1));
|
|
})();
|
|
console.log(c);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2799_2() {
|
|
let src = r###"(function () {
|
|
function foo() {
|
|
Function.prototype.call.apply(console.log, [null, "PASS"]);
|
|
}
|
|
foo();
|
|
})();"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"unsafe_proto": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_recursive_inlining_1() {
|
|
let src = r###"!(function () {
|
|
function foo() {
|
|
bar();
|
|
}
|
|
function bar() {
|
|
foo();
|
|
}
|
|
console.log("PASS");
|
|
})();"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_var_assign_2() {
|
|
let src = r###"!(function () {
|
|
var a;
|
|
if ((a = 2)) console.log(a);
|
|
})();"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2757_1() {
|
|
let src = r###"let u;
|
|
(function () {
|
|
let v;
|
|
console.log(u, v);
|
|
})();"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_inverted_var() {
|
|
let src = r###"console.log(
|
|
(function () {
|
|
var a = 1;
|
|
return a;
|
|
})(),
|
|
(function () {
|
|
var b;
|
|
b = 2;
|
|
return b;
|
|
})(),
|
|
(function () {
|
|
c = 3;
|
|
return c;
|
|
var c;
|
|
})(),
|
|
(function (c) {
|
|
c = 4;
|
|
return c;
|
|
})(),
|
|
(function (c) {
|
|
c = 5;
|
|
return c;
|
|
var c;
|
|
})(),
|
|
(function c() {
|
|
c = 6;
|
|
return typeof c;
|
|
})(),
|
|
(function c() {
|
|
c = 7;
|
|
return c;
|
|
var c;
|
|
})(),
|
|
(function () {
|
|
c = 8;
|
|
return c;
|
|
var c = "foo";
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 3,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_pure_getters_3() {
|
|
let src = r###"var a;
|
|
var a = a && a.b;
|
|
console.log(a && a.b)"###;
|
|
let config = r###"{
|
|
"pure_getters": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_unsafe_evaluate_side_effect_free_1() {
|
|
let src = r###"console.log(
|
|
(function () {
|
|
var o = { p: 1 };
|
|
console.log(o.p);
|
|
return o.p;
|
|
})()
|
|
);
|
|
console.log(
|
|
(function () {
|
|
var o = { p: 2 };
|
|
console.log(o.p);
|
|
return o;
|
|
})()
|
|
);
|
|
console.log(
|
|
(function () {
|
|
var o = { p: 3 };
|
|
console.log([o][0].p);
|
|
return o.p;
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unsafe": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2420_2() {
|
|
let src = r###"function f() {
|
|
var that = this;
|
|
if (that.bar) that.foo();
|
|
else
|
|
!(function (that, self) {
|
|
console.log(this === that, self === this, that === self);
|
|
})(that, this);
|
|
}
|
|
f.call({
|
|
bar: 1,
|
|
foo: function () {
|
|
console.log("foo", this.bar);
|
|
},
|
|
});
|
|
f.call({});"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_escape_expansion() {
|
|
let src = r###"function main() {
|
|
var thing = baz();
|
|
if (thing !== (thing = baz())) console.log("FAIL");
|
|
else console.log("PASS");
|
|
}
|
|
function foo() {}
|
|
function bar(...x) {
|
|
return x[0];
|
|
}
|
|
function baz() {
|
|
return bar(...[foo]);
|
|
}
|
|
main();"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_obj_arg_1() {
|
|
let src = r###"var C = 1;
|
|
function f(obj) {
|
|
return obj.bar();
|
|
}
|
|
console.log(
|
|
f({
|
|
bar: function () {
|
|
return C + C;
|
|
},
|
|
})
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2420_3() {
|
|
let src = r###"function f() {
|
|
var that = this;
|
|
if (that.bar) that.foo();
|
|
else
|
|
((that, self) => {
|
|
console.log(this === that, self === this, that === self);
|
|
})(that, this);
|
|
}
|
|
f.call({
|
|
bar: 1,
|
|
foo: function () {
|
|
console.log("foo", this.bar);
|
|
},
|
|
});
|
|
f.call({});"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn terser_reduce_vars_iife_eval_2() {
|
|
let src = r###"(function () {
|
|
var x = function f() {
|
|
return f;
|
|
};
|
|
console.log(x() === eval("x"));
|
|
})();"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_pure_getters_2() {
|
|
let src = r###"var a;
|
|
var a = a && a.b;
|
|
console.log(a && a.b)"###;
|
|
let config = r###"{
|
|
"pure_getters": "strict",
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_func_modified() {
|
|
let src = r###"function f(a) {
|
|
function a() {
|
|
return 1;
|
|
}
|
|
function b() {
|
|
return 2;
|
|
}
|
|
function c() {
|
|
return 3;
|
|
}
|
|
b.inject = [];
|
|
c = function () {
|
|
return 4;
|
|
};
|
|
return a() + b() + c();
|
|
}
|
|
|
|
console.log(f(1423796))"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2860_1() {
|
|
let src = r###"console.log(
|
|
(function (a) {
|
|
return (a ^= 1);
|
|
a ^= 2;
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2836() {
|
|
let src = r###"function f() {
|
|
return "FAIL";
|
|
}
|
|
console.log(f());
|
|
function f() {
|
|
return "PASS";
|
|
}"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_chained_assignments() {
|
|
let src = r###"function f() {
|
|
var a = [94, 173, 190, 239];
|
|
var b = 0;
|
|
b |= a[0];
|
|
b <<= 8;
|
|
b |= a[1];
|
|
b <<= 8;
|
|
b |= a[2];
|
|
b <<= 8;
|
|
b |= a[3];
|
|
return b;
|
|
}
|
|
console.log(f().toString(16));"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unsafe": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_obj_for_1() {
|
|
let src = r###"var o = { a: 1 };
|
|
for (var i = o.a--; i; i--) console.log(i);"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_iife() {
|
|
let src = r###"!(function (a, b, c) {
|
|
b++;
|
|
console.log(a - 1, b * 1, c + 2);
|
|
})(1, 2, 3);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_inner_var_label() {
|
|
let src = r###"function f(a) {
|
|
l: {
|
|
if (a) break l;
|
|
var t = 1;
|
|
}
|
|
console.log(t);
|
|
}
|
|
|
|
f(123123)
|
|
f(0)"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_side_effects_assign() {
|
|
let src = r###"var a = typeof void (a && a.in == 1, 0);
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_defun_catch_6() {
|
|
let src = r###"try {
|
|
throw 42;
|
|
} catch (a) {
|
|
console.log(a);
|
|
}
|
|
function a() {}"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_passes() {
|
|
let src = r###"function f() {
|
|
var a = 1,
|
|
b = 2,
|
|
c = 3;
|
|
if (a) {
|
|
b = c;
|
|
} else {
|
|
c = b;
|
|
}
|
|
console.log(a + b);
|
|
console.log(b + c);
|
|
console.log(a + c);
|
|
console.log(a + b + c);
|
|
}
|
|
|
|
f()"###;
|
|
let config = r###"{
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_defun_catch_1() {
|
|
let src = r###"function a() {}
|
|
try {
|
|
throw 42;
|
|
} catch (a) {
|
|
console.log(a);
|
|
}"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_unsafe_evaluate_array_2() {
|
|
let src = r###"var arr = [
|
|
1,
|
|
2,
|
|
function (x) {
|
|
return x * x;
|
|
},
|
|
function (x) {
|
|
return x * x * x;
|
|
},
|
|
];
|
|
console.log(arr[0], arr[1], arr[2](2), arr[3]);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_1670_6() {
|
|
let src = r###"(function (a) {
|
|
switch (1) {
|
|
case (a = 1):
|
|
console.log(a);
|
|
break;
|
|
default:
|
|
console.log(2);
|
|
break;
|
|
}
|
|
})(1);"###;
|
|
let config = r###"{
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"keep_fargs": false,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"switches": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_redefine_farg_1() {
|
|
let src = r###"function f(a) {
|
|
var a;
|
|
return typeof a;
|
|
}
|
|
function g(a) {
|
|
var a = 42;
|
|
return typeof a;
|
|
}
|
|
function h(a, b) {
|
|
var a = b;
|
|
return typeof a;
|
|
}
|
|
console.log(f([]), g([]), h([]));"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"keep_fargs": false,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_1670_1() {
|
|
let src = r###"(function f() {
|
|
switch (1) {
|
|
case 0:
|
|
var a = true;
|
|
break;
|
|
default:
|
|
if (typeof a === "undefined") console.log("PASS");
|
|
else console.log("FAIL");
|
|
}
|
|
})();"###;
|
|
let config = r###"{
|
|
"comparisons": true,
|
|
"conditionals": true,
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"switches": true,
|
|
"typeofs": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_perf_3() {
|
|
let src = r###"var foo = function (x, y, z) {
|
|
return x < y ? x * y + z : x * z - y;
|
|
};
|
|
var indirect_foo = function (x, y, z) {
|
|
return foo(x, y, z);
|
|
};
|
|
var sum = 0;
|
|
for (var i = 0; i < 100; ++i) sum += indirect_foo(i, i + 1, 3 * i);
|
|
console.log(sum);"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_defun_var_3() {
|
|
let src = r###"function a() {}
|
|
function b() {}
|
|
console.log(typeof a, typeof b);
|
|
var a = 42,
|
|
b;"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"typeofs": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_accessor_2() {
|
|
let src = r###"var A = 1;
|
|
var B = {
|
|
get c() {
|
|
console.log(A);
|
|
},
|
|
};
|
|
B.c;"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_unused_modified() {
|
|
let src = r###"console.log(
|
|
(function () {
|
|
var b = 1,
|
|
c = "FAIL";
|
|
if (0 || b--) c = "PASS";
|
|
b = 1;
|
|
return c;
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_unsafe_evaluate_object_1() {
|
|
let src = r###"function f0() {
|
|
var a = 1;
|
|
var b = {};
|
|
b[a] = 2;
|
|
console.log(a + 3);
|
|
}
|
|
function f1() {
|
|
var a = { b: 1 };
|
|
a.b = 2;
|
|
console.log(a.b + 3);
|
|
}
|
|
|
|
f0()
|
|
f1()"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_duplicate_lambda_defun_name_1() {
|
|
let src = r###"console.log(
|
|
(function f(a) {
|
|
function f() {}
|
|
return f.length;
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2423_5() {
|
|
let src = r###"function x() {
|
|
y();
|
|
}
|
|
function y() {
|
|
console.log(1);
|
|
}
|
|
function z() {
|
|
function y() {
|
|
console.log(2);
|
|
}
|
|
x();
|
|
}
|
|
z();
|
|
z();"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_unsafe_evaluate_array_4() {
|
|
let src = r###"var arr = [
|
|
1,
|
|
2,
|
|
function () {
|
|
return ++this[0];
|
|
},
|
|
];
|
|
console.log(arr[0], arr[1], arr[2], arr[0]);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2774() {
|
|
let src = r###"console.log(
|
|
{
|
|
get a() {
|
|
var b;
|
|
(b = true) && b.c;
|
|
b = void 0;
|
|
},
|
|
}.a
|
|
);"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_lvalues_def_2() {
|
|
let src = r###"var b = 1;
|
|
var a = (b += 1),
|
|
b = NaN;
|
|
console.log(a, b);"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_func_arg_2() {
|
|
let src = r###"var a = 42;
|
|
!(function (a) {
|
|
console.log(a());
|
|
})(function (a) {
|
|
return a;
|
|
});"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_unsafe_evaluate() {
|
|
let src = r###"function f0() {
|
|
var a = { b: 1 };
|
|
console.log(a.b + 3);
|
|
}
|
|
function f1() {
|
|
var a = { b: { c: 1 }, d: 2 };
|
|
console.log(a.b + 3, a.d + 4, a.b.c + 5, a.d.c + 6);
|
|
}
|
|
|
|
console.log(f0())
|
|
console.log(f1())"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unsafe": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2423_3() {
|
|
let src = r###"function c() {
|
|
return 1;
|
|
}
|
|
function p() {
|
|
console.log(c());
|
|
}
|
|
p();"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_defun_inline_3() {
|
|
let src = r###"function f() {
|
|
return g(2);
|
|
function g(b) {
|
|
return b;
|
|
}
|
|
}
|
|
|
|
console.log(f())"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 3,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_3113_2() {
|
|
let src = r###"var c = 0;
|
|
(function () {
|
|
function f() {
|
|
while (g());
|
|
}
|
|
var a = f();
|
|
function g() {
|
|
a && a[c++];
|
|
}
|
|
a = 1;
|
|
g();
|
|
})();
|
|
console.log(c);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2799_1() {
|
|
let src = r###"console.log(
|
|
(function () {
|
|
return f;
|
|
function f(n) {
|
|
function g(i) {
|
|
return i && i + g(i - 1);
|
|
}
|
|
function h(j) {
|
|
return g(j);
|
|
}
|
|
return h(n);
|
|
}
|
|
})()(5)
|
|
);"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_iife_new() {
|
|
let src = r###"var A = new (function (a, b, c) {
|
|
b++;
|
|
console.log(a - 1, b * 1, c + 2);
|
|
})(1, 2, 3);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_recursive_inlining_3() {
|
|
let src = r###"!(function () {
|
|
function foo(x) {
|
|
console.log("foo", x);
|
|
if (x) bar(x - 1);
|
|
}
|
|
function bar(x) {
|
|
console.log("bar", x);
|
|
if (x) qux(x - 1);
|
|
}
|
|
function qux(x) {
|
|
console.log("qux", x);
|
|
if (x) foo(x - 1);
|
|
}
|
|
qux(4);
|
|
})();"###;
|
|
let config = r###"{
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_recursive_inlining_4() {
|
|
let src = r###"!(function () {
|
|
function foo(x) {
|
|
console.log("foo", x);
|
|
if (x) bar(x - 1);
|
|
}
|
|
function bar(x) {
|
|
console.log("bar", x);
|
|
if (x) qux(x - 1);
|
|
}
|
|
function qux(x) {
|
|
console.log("qux", x);
|
|
if (x) foo(x - 1);
|
|
}
|
|
qux(4);
|
|
bar(5);
|
|
})();"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2757_2() {
|
|
let src = r###"(function () {
|
|
let bar;
|
|
const unused = function () {
|
|
bar = true;
|
|
};
|
|
if (!bar) {
|
|
console.log(1);
|
|
}
|
|
console.log(2);
|
|
})();"###;
|
|
let config = r###"{
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_recursive_inlining_2() {
|
|
let src = r###"!(function () {
|
|
function foo() {
|
|
qux();
|
|
}
|
|
function bar() {
|
|
foo();
|
|
}
|
|
function qux() {
|
|
bar();
|
|
}
|
|
console.log("PASS");
|
|
})();"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_var_assign_1() {
|
|
let src = r###"!(function () {
|
|
var a;
|
|
a = 2;
|
|
console.log(a);
|
|
})();"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_1865() {
|
|
let src = r###"function f(some) {
|
|
some.thing = false;
|
|
}
|
|
console.log(
|
|
(function () {
|
|
var some = { thing: true };
|
|
f(some);
|
|
return some.thing;
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2449() {
|
|
let src = r###"var a = "PASS";
|
|
function f() {
|
|
return a;
|
|
}
|
|
function g() {
|
|
return f();
|
|
}
|
|
(function () {
|
|
var a = "FAIL";
|
|
if (a == a) console.log(g());
|
|
})();"###;
|
|
let config = r###"{
|
|
"passes": 10,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2420_1() {
|
|
let src = r###"function run() {
|
|
var self = this;
|
|
if (self.count++) self.foo();
|
|
else self.bar();
|
|
}
|
|
var o = {
|
|
count: 0,
|
|
foo: function () {
|
|
console.log("foo");
|
|
},
|
|
bar: function () {
|
|
console.log("bar");
|
|
},
|
|
};
|
|
run.call(o);
|
|
run.call(o);"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2485() {
|
|
let src = r###"var foo = function (bar) {
|
|
var n = function (a, b) {
|
|
return a + b;
|
|
};
|
|
var sumAll = function (arg) {
|
|
return arg.reduce(n, 0);
|
|
};
|
|
var runSumAll = function (arg) {
|
|
return sumAll(arg);
|
|
};
|
|
bar.baz = function (arg) {
|
|
var n = runSumAll(arg);
|
|
return (n.get = 1), n;
|
|
};
|
|
return bar;
|
|
};
|
|
var bar = foo({});
|
|
console.log(bar.baz([1, 2, 3]));"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_inner_var_for_2() {
|
|
let src = r###"!(function () {
|
|
var a = 1;
|
|
for (var b = 1; --b; ) var a = 2;
|
|
console.log(a);
|
|
})();"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_obj_arg_2() {
|
|
let src = r###"var C = 1;
|
|
function f(obj) {
|
|
return obj.bar();
|
|
}
|
|
console.log(
|
|
f({
|
|
bar: function () {
|
|
return C + C;
|
|
},
|
|
})
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 3,
|
|
"properties": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn terser_reduce_vars_reduce_vars() {
|
|
let src = r###"var A = 1;
|
|
(function f0() {
|
|
var a = 2;
|
|
console.log(a - 5);
|
|
console.log(A - 5);
|
|
})();
|
|
(function f1() {
|
|
var a = 2;
|
|
console.log(a - 5);
|
|
eval("console.log(a);");
|
|
})();
|
|
(function f2(eval) {
|
|
var a = 2;
|
|
console.log(a - 5);
|
|
eval("console.log(a);");
|
|
})(eval);
|
|
(function f3() {
|
|
var b = typeof C !== "undefined";
|
|
var c = 4;
|
|
if (b) {
|
|
return "yes";
|
|
} else {
|
|
return "no";
|
|
}
|
|
})();
|
|
console.log(A + 1);"###;
|
|
let config = r###"{
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"global_defs": {
|
|
"C": 0
|
|
},
|
|
"inline": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_modified() {
|
|
let src = r###"function f0() {
|
|
var a = 1,
|
|
b = 2;
|
|
b++;
|
|
console.log(a + 1);
|
|
console.log(b + 1);
|
|
}
|
|
function f1() {
|
|
var a = 1,
|
|
b = 2;
|
|
--b;
|
|
console.log(a + 1);
|
|
console.log(b + 1);
|
|
}
|
|
function f2() {
|
|
var a = 1,
|
|
b = 2,
|
|
c = 3;
|
|
b = c;
|
|
console.log(a + b);
|
|
console.log(b + c);
|
|
console.log(a + c);
|
|
console.log(a + b + c);
|
|
}
|
|
function f3() {
|
|
var a = 1,
|
|
b = 2,
|
|
c = 3;
|
|
b *= c;
|
|
console.log(a + b);
|
|
console.log(b + c);
|
|
console.log(a + c);
|
|
console.log(a + b + c);
|
|
}
|
|
function f4() {
|
|
var a = 1,
|
|
b = 2,
|
|
c = 3;
|
|
if (a) {
|
|
b = c;
|
|
} else {
|
|
c = b;
|
|
}
|
|
console.log(a + b);
|
|
console.log(b + c);
|
|
console.log(a + c);
|
|
console.log(a + b + c);
|
|
}
|
|
function f5(a) {
|
|
B = a;
|
|
console.log(typeof A ? "yes" : "no");
|
|
console.log(typeof B ? "yes" : "no");
|
|
}
|
|
f0(), f1(), f2(), f3(), f4(), f5();"###;
|
|
let config = r###"{
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_unsafe_evaluate_escaped() {
|
|
let src = r###"console.log(
|
|
(function () {
|
|
var o = { p: 1 };
|
|
console.log(o, o.p);
|
|
return o.p;
|
|
})()
|
|
);
|
|
console.log(
|
|
(function () {
|
|
var o = { p: 2 };
|
|
console.log(o.p, o);
|
|
return o.p;
|
|
})()
|
|
);
|
|
console.log(
|
|
(function () {
|
|
var o = { p: 3 },
|
|
a = [o];
|
|
console.log(a[0].p++);
|
|
return o.p;
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unsafe": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2669() {
|
|
let src = r###"let foo;
|
|
console.log(([foo] = ["PASS"]) && foo);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_defun_catch_3() {
|
|
let src = r###"try {
|
|
throw 42;
|
|
function a() {}
|
|
} catch (a) {
|
|
console.log(a);
|
|
}"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2860_2() {
|
|
let src = r###"console.log(
|
|
(function (a) {
|
|
return (a ^= 1);
|
|
a ^= 2;
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_delay_def() {
|
|
let src = r###"function f() {
|
|
return a;
|
|
var a;
|
|
}
|
|
function g() {
|
|
return a;
|
|
var a = 1;
|
|
}
|
|
console.log(f(), g());"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2496() {
|
|
let src = r###"function execute(callback) {
|
|
callback();
|
|
}
|
|
class Foo {
|
|
constructor(message) {
|
|
this.message = message;
|
|
}
|
|
go() {
|
|
this.message = "PASS";
|
|
console.log(this.message);
|
|
}
|
|
run() {
|
|
execute(() => {
|
|
this.go();
|
|
});
|
|
}
|
|
}
|
|
new Foo("FAIL").run();"###;
|
|
let config = r###"{
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_defun_catch_2() {
|
|
let src = r###"try {
|
|
function a() {}
|
|
throw 42;
|
|
} catch (a) {
|
|
console.log(a);
|
|
}"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2450_5() {
|
|
let src = r###"var a;
|
|
function f(b) {
|
|
console.log(a === b);
|
|
a = b;
|
|
}
|
|
function g() {}
|
|
[1, 2, 3].forEach(function () {
|
|
f(g);
|
|
});"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_1850_2() {
|
|
let src = r###"function f() {
|
|
console.log(a, a, a);
|
|
}
|
|
var a = 1;
|
|
f();"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": "funcs",
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_3110_3() {
|
|
let src = r###"(function () {
|
|
function foo() {
|
|
return isDev ? "foo" : "bar";
|
|
}
|
|
console.log(foo());
|
|
var isDev = true;
|
|
var obj = { foo: foo };
|
|
console.log(obj.foo());
|
|
})();"###;
|
|
let config = r###"{
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"properties": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_defun_redefine() {
|
|
let src = r###"function f() {
|
|
function g() {
|
|
return 1;
|
|
}
|
|
function h() {
|
|
return 2;
|
|
}
|
|
g = function () {
|
|
return 3;
|
|
};
|
|
return g() + h();
|
|
}
|
|
|
|
console.log(f())"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2423_6() {
|
|
let src = r###"function x() {
|
|
y();
|
|
}
|
|
function y() {
|
|
console.log(1);
|
|
}
|
|
function z() {
|
|
function y() {
|
|
console.log(2);
|
|
}
|
|
x();
|
|
y();
|
|
}
|
|
z();
|
|
z();"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_unsafe_evaluate_object_2() {
|
|
let src = r###"var obj = {
|
|
foo: 1,
|
|
bar: 2,
|
|
square: function (x) {
|
|
return x * x;
|
|
},
|
|
cube: function (x) {
|
|
return x * x * x;
|
|
},
|
|
};
|
|
console.log(obj.foo, obj.bar, obj.square(2), obj.cube);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_2423_1() {
|
|
let src = r###"function c() {
|
|
return 1;
|
|
}
|
|
function p() {
|
|
console.log(c());
|
|
}
|
|
p();
|
|
p();"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_redefine_farg_2() {
|
|
let src = r###"function f(a) {
|
|
var a;
|
|
return typeof a;
|
|
}
|
|
function g(a) {
|
|
var a = 42;
|
|
return typeof a;
|
|
}
|
|
function h(a, b) {
|
|
var a = b;
|
|
return typeof a;
|
|
}
|
|
console.log(f([]), g([]), h([]));"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"keep_fargs": false,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_1670_2() {
|
|
let src = r###"(function f() {
|
|
switch (1) {
|
|
case 0:
|
|
var a = true;
|
|
break;
|
|
default:
|
|
if (typeof a === "undefined") console.log("PASS");
|
|
else console.log("FAIL");
|
|
}
|
|
})();"###;
|
|
let config = r###"{
|
|
"conditionals": true,
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"switches": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_unsafe_evaluate_array_1() {
|
|
let src = r###"function f0() {
|
|
var a = 1;
|
|
var b = [];
|
|
b[a] = 2;
|
|
console.log(a + 3);
|
|
}
|
|
function f1() {
|
|
var a = [1];
|
|
a[2] = 3;
|
|
console.log(a.length);
|
|
}
|
|
function f2() {
|
|
var a = [1];
|
|
a.push(2);
|
|
console.log(a.length);
|
|
}
|
|
|
|
console.log(f0())
|
|
console.log(f1())
|
|
console.log(f2())"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_perf_7() {
|
|
let src = r###"var indirect_foo = function (x, y, z) {
|
|
var foo = function (x, y, z) {
|
|
return x < y ? x * y + z : x * z - y;
|
|
};
|
|
return foo(x, y, z);
|
|
};
|
|
var sum = 0;
|
|
for (var i = 0; i < 100; ++i) sum += indirect_foo(i, i + 1, 3 * i);
|
|
console.log(sum);"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_1670_5() {
|
|
let src = r###"(function (a) {
|
|
switch (1) {
|
|
case a:
|
|
console.log(a);
|
|
break;
|
|
default:
|
|
console.log(2);
|
|
break;
|
|
}
|
|
})(1);"###;
|
|
let config = r###"{
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"keep_fargs": false,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"switches": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_escaped_prop_3() {
|
|
let src = r###"var a;
|
|
function f(b) {
|
|
if (a) console.log(a === b.c);
|
|
a = b.c;
|
|
}
|
|
function g() {}
|
|
function h() {
|
|
f({ c: g });
|
|
}
|
|
h();
|
|
h();"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_defun_call() {
|
|
let src = r###"function f() {
|
|
return g() + h(1) - h(g(), 2, 3);
|
|
function g() {
|
|
return 4;
|
|
}
|
|
function h(a) {
|
|
return a;
|
|
}
|
|
}
|
|
|
|
|
|
console.log(f())"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_defun_label() {
|
|
let src = r###"!(function () {
|
|
function f(a) {
|
|
L: {
|
|
if (a) break L;
|
|
return 1;
|
|
}
|
|
}
|
|
console.log(f(2));
|
|
})();"###;
|
|
let config = r###"{
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn terser_reduce_vars_unsafe_evaluate_modified() {
|
|
let src = r###"console.log(
|
|
(function () {
|
|
var o = { p: 1 };
|
|
o.p++;
|
|
console.log(o.p);
|
|
return o.p;
|
|
})()
|
|
);
|
|
console.log(
|
|
(function () {
|
|
var o = { p: 2 };
|
|
--o.p;
|
|
console.log(o.p);
|
|
return o.p;
|
|
})()
|
|
);
|
|
console.log(
|
|
(function () {
|
|
var o = { p: 3 };
|
|
o.p += "";
|
|
console.log(o.p);
|
|
return o.p;
|
|
})()
|
|
);
|
|
console.log(
|
|
(function () {
|
|
var o = { p: 4 };
|
|
o = {};
|
|
console.log(o.p);
|
|
return o.p;
|
|
})()
|
|
);
|
|
console.log(
|
|
(function () {
|
|
var o = { p: 5 };
|
|
o.p = -9;
|
|
console.log(o.p);
|
|
return o.p;
|
|
})()
|
|
);
|
|
function inc() {
|
|
this.p++;
|
|
}
|
|
console.log(
|
|
(function () {
|
|
var o = { p: 6 };
|
|
inc.call(o);
|
|
console.log(o.p);
|
|
return o.p;
|
|
})()
|
|
);
|
|
console.log(
|
|
(function () {
|
|
var o = { p: 7 };
|
|
console.log([o][0].p++);
|
|
return o.p;
|
|
})()
|
|
);
|
|
console.log(
|
|
(function () {
|
|
var o = { p: 8 };
|
|
console.log({ q: o }.q.p++);
|
|
return o.p;
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unsafe": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_lvalues_def_1() {
|
|
let src = r###"var b = 1;
|
|
var a = b++,
|
|
b = NaN;
|
|
console.log(a, b);"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_func_arg_1() {
|
|
let src = r###"var a = 42;
|
|
!(function (a) {
|
|
console.log(a());
|
|
})(function () {
|
|
return a;
|
|
});"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_escape_local_sequence() {
|
|
let src = r###"function main() {
|
|
var thing = baz();
|
|
if (thing !== (thing = baz())) console.log("PASS");
|
|
else console.log("FAIL");
|
|
}
|
|
function baz() {
|
|
function foo() {}
|
|
function bar() {}
|
|
return foo, bar;
|
|
}
|
|
main();"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_regex_loop() {
|
|
let src = r###"function f(x) {
|
|
for (var r, s = "acdabcdeabbb"; (r = x().exec(s)); ) console.log(r[0]);
|
|
}
|
|
var a = /ab*/g;
|
|
f(function () {
|
|
return a;
|
|
});"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_3140_4() {
|
|
let src = r###"(function () {
|
|
var a;
|
|
function f() {}
|
|
f.g = function g() {
|
|
var o = { p: this };
|
|
function h() {
|
|
console.log(a ? "PASS" : "FAIL");
|
|
}
|
|
a = true;
|
|
o.p();
|
|
a = false;
|
|
h.g = g;
|
|
return h;
|
|
};
|
|
return f;
|
|
})()
|
|
.g()
|
|
.g();"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_1670_4() {
|
|
let src = r###"(function f() {
|
|
switch (1) {
|
|
case 0:
|
|
var a = true;
|
|
break;
|
|
case 1:
|
|
if (typeof a === "undefined") console.log("PASS");
|
|
else console.log("FAIL");
|
|
}
|
|
})();"###;
|
|
let config = r###"{
|
|
"conditionals": true,
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"switches": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_redefine_farg_3() {
|
|
let src = r###"function f(a) {
|
|
var a;
|
|
return typeof a;
|
|
}
|
|
function g(a) {
|
|
var a = 42;
|
|
return typeof a;
|
|
}
|
|
function h(a, b) {
|
|
var a = b;
|
|
return typeof a;
|
|
}
|
|
console.log(f([]), g([]), h([]));"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"keep_fargs": false,
|
|
"passes": 3,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_3140_3() {
|
|
let src = r###"(function () {
|
|
var a;
|
|
function f() {}
|
|
f.g = function g() {
|
|
var self = this;
|
|
function h() {
|
|
console.log(a ? "PASS" : "FAIL");
|
|
}
|
|
a = true;
|
|
(function () {
|
|
return self;
|
|
})()();
|
|
a = false;
|
|
h.g = g;
|
|
return h;
|
|
};
|
|
return f;
|
|
})()
|
|
.g()
|
|
.g();"###;
|
|
let config = r###"{
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_issue_1670_3() {
|
|
let src = r###"(function f() {
|
|
switch (1) {
|
|
case 0:
|
|
var a = true;
|
|
break;
|
|
case 1:
|
|
if (typeof a === "undefined") console.log("PASS");
|
|
else console.log("FAIL");
|
|
}
|
|
})();"###;
|
|
let config = r###"{
|
|
"comparisons": true,
|
|
"conditionals": true,
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"switches": true,
|
|
"typeofs": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_reduce_vars_perf_1() {
|
|
let src = r###"function foo(x, y, z) {
|
|
return x < y ? x * y + z : x * z - y;
|
|
}
|
|
function indirect_foo(x, y, z) {
|
|
return foo(x, y, z);
|
|
}
|
|
var sum = 0;
|
|
for (var i = 0; i < 100; ++i) {
|
|
sum += indirect_foo(i, i + 1, 3 * i);
|
|
}
|
|
console.log(sum);"###;
|
|
let config = r###"{
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2187_2() {
|
|
let src = r###"var b = 1;
|
|
console.log(
|
|
(function (a) {
|
|
return a && ++b;
|
|
})(b--)
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2436_14() {
|
|
let src = r###"var a = "PASS";
|
|
var b = {};
|
|
(function () {
|
|
var c = a;
|
|
c &&
|
|
(function (c, d) {
|
|
console.log(c, d);
|
|
})(b, c);
|
|
})();"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2506() {
|
|
let src = r###"var c = 0;
|
|
function f0(bar) {
|
|
function f1(Infinity_2) {
|
|
function f13(NaN) {
|
|
if ((false <= NaN) & (this >> 1 >= 0)) {
|
|
c++;
|
|
}
|
|
}
|
|
var b_2 = f13(NaN, c++);
|
|
}
|
|
var bar = f1(-3, -1);
|
|
}
|
|
f0(false);
|
|
console.log(c);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"passes": 2,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2436_13() {
|
|
let src = r###"var a = "PASS";
|
|
(function () {
|
|
function f(b) {
|
|
(function g(b) {
|
|
var b = b && (b.null = "FAIL");
|
|
})(a);
|
|
}
|
|
f();
|
|
})();
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"passes": 2,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2187_3() {
|
|
let src = r###"var b = 1;
|
|
console.log(
|
|
(function (a) {
|
|
return a && ++b;
|
|
})(b--)
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"inline": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2203_1() {
|
|
let src = r###"a = "FAIL";
|
|
console.log(
|
|
{
|
|
a: "PASS",
|
|
b: function () {
|
|
return (function (c) {
|
|
return c.a;
|
|
})((String, Object, this));
|
|
},
|
|
}.b()
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2914_2() {
|
|
let src = r###"function read(input) {
|
|
var i = 0;
|
|
var e = 0;
|
|
var t = 0;
|
|
while (e < 32) {
|
|
var n = input[i++];
|
|
t = (127 & n) << e;
|
|
if (0 === (128 & n)) return t;
|
|
e += 7;
|
|
}
|
|
}
|
|
console.log(read([129]));"###;
|
|
let config = r###"{
|
|
"collapse_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2319_1() {
|
|
let src = r###"console.log(
|
|
(function (a) {
|
|
return a;
|
|
})(
|
|
!(function () {
|
|
return this;
|
|
})()
|
|
)
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_cascade_forin() {
|
|
let src = r###"var a;
|
|
function f(b) {
|
|
return [b, b, b];
|
|
}
|
|
for (var c in ((a = console), f(a))) console.log(c);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_inner_lvalues() {
|
|
let src = r###"var a,
|
|
b = 10;
|
|
var a = (--b || a || 3).toString(),
|
|
c = --b + -a;
|
|
console.log(null, a, b);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2298() {
|
|
let src = r###"!(function () {
|
|
function f() {
|
|
var a = undefined;
|
|
var undefined = a++;
|
|
try {
|
|
!(function g(b) {
|
|
b[1] = "foo";
|
|
})();
|
|
console.log("FAIL");
|
|
} catch (e) {
|
|
console.log("PASS");
|
|
}
|
|
}
|
|
f();
|
|
})();"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_chained_3() {
|
|
let src = r###"console.log(
|
|
(function (a, b) {
|
|
var c = a,
|
|
c = b;
|
|
b++;
|
|
return c;
|
|
})(1, 2)
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_collapse_vars_self_reference() {
|
|
let src = r###"function f1() {
|
|
var self = {
|
|
inner: function () {
|
|
return self;
|
|
},
|
|
};
|
|
console.log(self)
|
|
}
|
|
function f2() {
|
|
var self = { inner: self };
|
|
console.log(self)
|
|
}
|
|
|
|
f1()
|
|
f2()"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"collapse_vars": true,
|
|
"comparisons": true,
|
|
"conditionals": true,
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"hoist_funs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"keep_fargs": true,
|
|
"loops": true,
|
|
"properties": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": false
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_chained_2() {
|
|
let src = r###"var a;
|
|
var a = 2;
|
|
a = 3 / a;
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_cond_branch_1() {
|
|
let src = r###"function f1(b, c) {
|
|
var log = console.log;
|
|
var a = ++c;
|
|
if (b) b++;
|
|
log(a, b);
|
|
}
|
|
function f2(b, c) {
|
|
var log = console.log;
|
|
var a = ++c;
|
|
b && b++;
|
|
log(a, b);
|
|
}
|
|
function f3(b, c) {
|
|
var log = console.log;
|
|
var a = ++c;
|
|
b ? b++ : b--;
|
|
log(a, b);
|
|
}
|
|
f1(1, 2);
|
|
f2(3, 4);
|
|
f3(5, 6);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"sequences": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_var_side_effects_2() {
|
|
let src = r###"var print = console.log.bind(console);
|
|
function foo(x) {
|
|
var twice = x.y * 2;
|
|
print("Foo:", twice);
|
|
}
|
|
foo({ y: 10 });"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_3032() {
|
|
let src = r###"console.log(
|
|
{
|
|
f: function () {
|
|
this.a = 42;
|
|
return [this.a, !1];
|
|
},
|
|
}.f()[0]
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"pure_getters": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_var_side_effects_3() {
|
|
let src = r###"var print = console.log.bind(console);
|
|
function foo(x) {
|
|
var twice = x.y * 2;
|
|
print("Foo:", twice);
|
|
}
|
|
foo({ y: 10 });"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"pure_getters": true,
|
|
"unsafe": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_collapse_vars_throw() {
|
|
let src = r###"var f1 = function (x, y) {
|
|
var a,
|
|
b,
|
|
r = x + y,
|
|
q = r * r,
|
|
z = q - r;
|
|
(a = z), (b = 7);
|
|
throw a + b;
|
|
};
|
|
try {
|
|
f1(1, 2);
|
|
} catch (e) {
|
|
console.log(e);
|
|
}"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"collapse_vars": true,
|
|
"comparisons": true,
|
|
"conditionals": true,
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"hoist_funs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"keep_fargs": true,
|
|
"loops": true,
|
|
"properties": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2203_4() {
|
|
let src = r###"a = "FAIL";
|
|
console.log(
|
|
{
|
|
a: "PASS",
|
|
b: function () {
|
|
return ((c) => c.a)((String, Object, (() => this)()));
|
|
},
|
|
}.b()
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2203_3() {
|
|
let src = r###"a = "FAIL";
|
|
console.log(
|
|
{
|
|
a: "PASS",
|
|
b: function () {
|
|
return (function (c) {
|
|
return c.a;
|
|
})((String, Object, (() => this)()));
|
|
},
|
|
}.b()
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2187_1() {
|
|
let src = r###"var a = 1;
|
|
!(function (foo) {
|
|
foo();
|
|
var a = 2;
|
|
console.log(a);
|
|
})(function () {
|
|
console.log(a);
|
|
});"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_var_defs() {
|
|
let src = r###"var f1 = function (x, y) {
|
|
var a,
|
|
b,
|
|
r = x + y,
|
|
q = r * r,
|
|
z = q - r,
|
|
a = z,
|
|
b = 7;
|
|
console.log(a + b);
|
|
};
|
|
f1("1", 0);"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"collapse_vars": true,
|
|
"comparisons": true,
|
|
"conditionals": true,
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"hoist_funs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"keep_fargs": true,
|
|
"loops": true,
|
|
"properties": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2203_2() {
|
|
let src = r###"a = "PASS";
|
|
console.log(
|
|
{
|
|
a: "FAIL",
|
|
b: function () {
|
|
return (function (c) {
|
|
return c.a;
|
|
})(
|
|
(String,
|
|
Object,
|
|
(function () {
|
|
return this;
|
|
})())
|
|
);
|
|
},
|
|
}.b()
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_collapse_vars_seq() {
|
|
let src = r###"var f1 = function (x, y) {
|
|
var a,
|
|
b,
|
|
r = x + y,
|
|
q = r * r,
|
|
z = q - r;
|
|
(a = z), (b = 7);
|
|
return a + b;
|
|
};
|
|
console.log(f1(1, 2));"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"collapse_vars": true,
|
|
"comparisons": true,
|
|
"conditionals": true,
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"hoist_funs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"keep_fargs": true,
|
|
"loops": true,
|
|
"properties": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2319_3() {
|
|
let src = r###""use strict";
|
|
console.log(
|
|
(function (a) {
|
|
return a;
|
|
})(
|
|
!(function () {
|
|
return this;
|
|
})()
|
|
)
|
|
);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_may_throw_2() {
|
|
let src = r###"function f(b) {
|
|
try {
|
|
var a = x();
|
|
++b;
|
|
return b(a);
|
|
} catch (e) {}
|
|
console.log(b);
|
|
}
|
|
f(0);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_issue_2453() {
|
|
let src = r###"function log(n) {
|
|
console.log(n);
|
|
}
|
|
const a = 42;
|
|
log(a);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"conditionals": true,
|
|
"inline": true,
|
|
"join_vars": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_cond_branch_2() {
|
|
let src = r###"function f1(b, c) {
|
|
var log = console.log;
|
|
var a = ++c;
|
|
if (b) b += a;
|
|
log(a, b);
|
|
}
|
|
function f2(b, c) {
|
|
var log = console.log;
|
|
var a = ++c;
|
|
b && (b += a);
|
|
log(a, b);
|
|
}
|
|
function f3(b, c) {
|
|
var log = console.log;
|
|
var a = ++c;
|
|
b ? (b += a) : b--;
|
|
log(a, b);
|
|
}
|
|
f1(1, 2);
|
|
f2(3, 4);
|
|
f3(5, 6);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"sequences": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_chained_1() {
|
|
let src = r###"var a = 2;
|
|
var a = 3 / a;
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_collapse_vars_reduce_vars_assign() {
|
|
let src = r###"!(function () {
|
|
var a = 1;
|
|
(a = [].length), console.log(a);
|
|
})();"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_inline_inline_within_extends_2() {
|
|
let src = r###"class Baz extends foo(bar(Array)) {
|
|
constructor() {
|
|
super(...arguments);
|
|
}
|
|
}
|
|
function foo(foo_base) {
|
|
return class extends foo_base {
|
|
constructor() {
|
|
super(...arguments);
|
|
}
|
|
second() {
|
|
return this[1];
|
|
}
|
|
};
|
|
}
|
|
function bar(bar_base) {
|
|
return class extends bar_base {
|
|
constructor(...args) {
|
|
super(...args);
|
|
}
|
|
};
|
|
}
|
|
console.log(new Baz(1, "PASS", 3).second());"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"evaluate": true,
|
|
"inline": 3,
|
|
"passes": 3,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"collapse_vars": false,
|
|
"unused": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_evaluate_unsafe_float_key() {
|
|
let src = r###"console.log(
|
|
{ 2.72: 1 } + 1,
|
|
{ 2.72: 1 }[2.72] + 1,
|
|
{ 2.72: 1 }["2.72"] + 1,
|
|
{ 2.72: 1 }[3.14] + 1,
|
|
{ 2.72: 1 }[2.72][3.14] + 1,
|
|
{ 2.72: 1 }[2.72]["3.14"] + 1
|
|
);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_evaluate_unsafe_float_key_complex() {
|
|
let src = r###"console.log(
|
|
{ 2.72: { 3.14: 1 }, 3.14: 1 } + 1,
|
|
{ 2.72: { 3.14: 1 }, 3.14: 1 }[2.72] + 1,
|
|
{ 2.72: { 3.14: 1 }, 3.14: 1 }["2.72"] + 1,
|
|
{ 2.72: { 3.14: 1 }, 3.14: 1 }[3.14] + 1,
|
|
{ 2.72: { 3.14: 1 }, 3.14: 1 }[2.72][3.14] + 1,
|
|
{ 2.72: { 3.14: 1 }, 3.14: 1 }[2.72]["3.14"] + 1
|
|
);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_892_dont_mangle_arguments() {
|
|
let src = r###"(function () {
|
|
var arguments = arguments,
|
|
not_arguments = 9;
|
|
console.log(not_arguments, arguments);
|
|
})(5, 6, 7);"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"comparisons": true,
|
|
"conditionals": true,
|
|
"dead_code": true,
|
|
"drop_debugger": true,
|
|
"evaluate": true,
|
|
"hoist_funs": true,
|
|
"hoist_vars": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"keep_fargs": true,
|
|
"keep_fnames": false,
|
|
"loops": true,
|
|
"negate_iife": false,
|
|
"properties": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_issue_t64() {
|
|
let src = r###"var obj = {};
|
|
obj.Base = class {
|
|
constructor() {
|
|
this.id = "PASS";
|
|
}
|
|
};
|
|
obj.Derived = class extends obj.Base {
|
|
constructor() {
|
|
super();
|
|
console.log(this.id);
|
|
}
|
|
};
|
|
new obj.Derived();"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"join_vars": true,
|
|
"properties": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_computed_property() {
|
|
let src = r###"console.log({ a: "bar", [console.log("foo")]: 42 }.a);"###;
|
|
let config = r###"{
|
|
"properties": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_sub_properties() {
|
|
let src = r###"const a = {};
|
|
|
|
a[0] = 0;
|
|
a["0"] = 1;
|
|
a[3.14] = 2;
|
|
a["3" + ".14"] = 3;
|
|
a["i" + "f"] = 4;
|
|
a["foo" + " bar"] = 5;
|
|
a[0 / 0] = 6;
|
|
a[null] = 7;
|
|
a[undefined] = 8;
|
|
|
|
console.log(a)"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"properties": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_dont_mangle_computed_property_2() {
|
|
let src = r###"const prop = Symbol("foo");
|
|
const obj = {
|
|
[prop]: "bar",
|
|
baz: 1,
|
|
qux: 2,
|
|
[3 + 4]: "seven",
|
|
0: "zero",
|
|
1: "one",
|
|
null: "Null",
|
|
undefined: "Undefined",
|
|
Infinity: "infinity",
|
|
NaN: "nan",
|
|
void: "Void",
|
|
};
|
|
console.log(
|
|
obj[prop],
|
|
obj["baz"],
|
|
obj.qux,
|
|
obj[7],
|
|
obj[0],
|
|
obj[1 + 0],
|
|
obj[null],
|
|
obj[undefined],
|
|
obj[1 / 0],
|
|
obj[NaN],
|
|
obj.void
|
|
);
|
|
console.log(obj.null, obj.undefined, obj.Infinity, obj.NaN);"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_prop_side_effects_2() {
|
|
let src = r###"var C = 1;
|
|
console.log(C);
|
|
var obj = {
|
|
"": function () {
|
|
return C + C;
|
|
},
|
|
};
|
|
console.log(obj[""]());"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 2,
|
|
"properties": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_join_object_assignments_negative() {
|
|
let src = r###"var o = {};
|
|
o[0] = 0;
|
|
o[-0] = 1;
|
|
o[-1] = 2;
|
|
console.log(o[0], o[-0], o[-1]);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"join_vars": true,
|
|
"properties": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_issue_2208_4() {
|
|
let src = r###"function foo() {}
|
|
console.log(
|
|
{
|
|
a: foo(),
|
|
p: function () {
|
|
return 42;
|
|
},
|
|
}.p()
|
|
);"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"properties": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_issue_869_1() {
|
|
let src = r###"var o = { p: "FAIL" };
|
|
Object.defineProperty(o, "p", {
|
|
get: function () {
|
|
return "PASS";
|
|
},
|
|
});
|
|
console.log(o.p);"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_join_object_assignments_undefined_2() {
|
|
let src = r###"var o = {};
|
|
o[undefined] = 1;
|
|
console.log(o[undefined]);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"join_vars": true,
|
|
"properties": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_issue_2208_5() {
|
|
let src = r###"console.log(
|
|
{
|
|
p: "FAIL",
|
|
p: function () {
|
|
return 42;
|
|
},
|
|
}.p()
|
|
);"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"properties": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_issue_2513() {
|
|
let src = r###"!(function (Infinity, NaN, undefined) {
|
|
console.log("a"[1 / 0], "b"["Infinity"]);
|
|
console.log("c"[0 / 0], "d"["NaN"]);
|
|
console.log("e"[void 0], "f"["undefined"]);
|
|
})(0, 0, 0);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"properties": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_join_object_assignments_return_1() {
|
|
let src = r###"console.log(
|
|
(function () {
|
|
var o = { p: 3 };
|
|
return (o.q = "foo");
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"join_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_issue_2816_ecma6() {
|
|
let src = r###""use strict";
|
|
var o = { a: 1 };
|
|
o.b = 2;
|
|
o.a = 3;
|
|
o.c = 4;
|
|
console.log(o.a, o.b, o.c);"###;
|
|
let config = r###"{
|
|
"ecma": "6",
|
|
"join_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_join_object_assignments_1() {
|
|
let src = r###"console.log(
|
|
(function () {
|
|
var x = { a: 1, c: (console.log("c"), "C") };
|
|
x.b = 2;
|
|
(x[3] = function () {
|
|
console.log(x);
|
|
}),
|
|
(x["a"] = /foo/),
|
|
(x.bar = x);
|
|
return x;
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"join_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_dont_mangle_computed_property_1() {
|
|
let src = r###""AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
|
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
|
|
"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC";
|
|
const prop = Symbol("foo");
|
|
const obj = {
|
|
[prop]: "bar",
|
|
baz: 1,
|
|
qux: 2,
|
|
[3 + 4]: "seven",
|
|
0: "zero",
|
|
1: "one",
|
|
null: "Null",
|
|
undefined: "Undefined",
|
|
Infinity: "infinity",
|
|
NaN: "nan",
|
|
void: "Void",
|
|
};
|
|
console.log(
|
|
obj[prop],
|
|
obj["baz"],
|
|
obj.qux,
|
|
obj[7],
|
|
obj[0],
|
|
obj[1 + 0],
|
|
obj[null],
|
|
obj[undefined],
|
|
obj[1 / 0],
|
|
obj[NaN],
|
|
obj.void
|
|
);
|
|
console.log(obj.null, obj.undefined, obj.Infinity, obj.NaN);"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_join_object_assignments_if() {
|
|
let src = r###"console.log(
|
|
(function () {
|
|
var o = {};
|
|
if ((o.a = "PASS")) return o.a;
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"join_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_join_object_assignments_nan_2() {
|
|
let src = r###"var o = {};
|
|
o[NaN] = 1;
|
|
o[0 / 0] = 2;
|
|
console.log(o[NaN], o[NaN]);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"join_vars": true,
|
|
"properties": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_prop_side_effects_1() {
|
|
let src = r###"var C = 1;
|
|
console.log(C);
|
|
var obj = {
|
|
bar: function () {
|
|
return C + C;
|
|
},
|
|
};
|
|
console.log(obj.bar());"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"properties": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_join_object_assignments_null_1() {
|
|
let src = r###"var o = {};
|
|
o[null] = 1;
|
|
console.log(o[null]);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"join_vars": true,
|
|
"properties": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_issue_2208_7() {
|
|
let src = r###"console.log(
|
|
{
|
|
p() {
|
|
return 42;
|
|
},
|
|
}.p()
|
|
);"###;
|
|
let config = r###"{
|
|
"ecma": 2015,
|
|
"inline": true,
|
|
"properties": true,
|
|
"side_effects": true,
|
|
"unsafe_arrows": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_issue_869_2() {
|
|
let src = r###"var o = { p: "FAIL" };
|
|
Object.defineProperties(o, {
|
|
p: {
|
|
get: function () {
|
|
return "PASS";
|
|
},
|
|
},
|
|
});
|
|
console.log(o.p);"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_issue_2208_9() {
|
|
let src = r###"a = 42;
|
|
console.log(
|
|
{
|
|
p: () =>
|
|
(function () {
|
|
return this.a;
|
|
})(),
|
|
}.p()
|
|
);"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"properties": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_join_object_assignments_undefined_1() {
|
|
let src = r###"var o = {};
|
|
o[undefined] = 1;
|
|
console.log(o[undefined]);"###;
|
|
let config = r###"{
|
|
"join_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_join_object_assignments_forin() {
|
|
let src = r###"console.log(
|
|
(function () {
|
|
var o = {};
|
|
for (var a in ((o.a = "PASS"), o)) return o[a];
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"join_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_join_object_assignments_void_0() {
|
|
let src = r###"var o = {};
|
|
o[void 0] = 1;
|
|
console.log(o[void 0]);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"join_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_join_object_assignments_return_2() {
|
|
let src = r###"console.log(
|
|
(function () {
|
|
var o = { p: 3 };
|
|
return (o.q = /foo/), (o.r = "bar");
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"join_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_join_object_assignments_regex() {
|
|
let src = r###"var o = {};
|
|
o[/rx/] = 1;
|
|
console.log(o[/rx/]);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"join_vars": true,
|
|
"properties": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_join_object_assignments_2() {
|
|
let src = r###"var o = { foo: 1 };
|
|
o.bar = 2;
|
|
o.baz = 3;
|
|
console.log(o.foo, o.bar + o.bar, o.foo * o.bar * o.baz);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"hoist_props": true,
|
|
"join_vars": true,
|
|
"passes": 3,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_properties_join_object_assignments_return_3() {
|
|
let src = r###"console.log(
|
|
(function () {
|
|
var o = { p: 3 };
|
|
return (o.q = "foo"), (o.p += ""), console.log(o.q), o.p;
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"join_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1321_issue_1321_no_debug() {
|
|
let src = r###"var x = {};
|
|
x.foo = 1;
|
|
x["a"] = 2 * x.foo;
|
|
console.log(x.foo, x["a"]);"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1321_issue_1321_with_quoted() {
|
|
let src = r###"var x = {};
|
|
x.foo = 1;
|
|
x["a"] = 2 * x.foo;
|
|
console.log(x.foo, x["a"]);"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1321_issue_1321_debug() {
|
|
let src = r###"var x = {};
|
|
x.foo = 1;
|
|
x["_$foo$_"] = 2 * x.foo;
|
|
console.log(x.foo, x["_$foo$_"]);"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_976_eval_collapse_vars() {
|
|
let src = r###"function f1() {
|
|
var e = 7;
|
|
var s = "abcdef";
|
|
var i = 2;
|
|
var eval = console.log.bind(console);
|
|
var x = s.charAt(i++);
|
|
var y = s.charAt(i++);
|
|
var z = s.charAt(i++);
|
|
eval(x, y, z, e);
|
|
}
|
|
function p1() {
|
|
var a = foo(),
|
|
b = bar(),
|
|
eval = baz();
|
|
return a + b + eval;
|
|
}
|
|
function p2() {
|
|
var a = foo(),
|
|
b = bar(),
|
|
eval = baz;
|
|
return a + b + eval();
|
|
}
|
|
(function f2(eval) {
|
|
var a = 2;
|
|
console.log(a - 5);
|
|
eval("console.log(a);");
|
|
})(eval);"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"collapse_vars": true,
|
|
"comparisons": true,
|
|
"conditionals": true,
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"hoist_funs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"keep_fargs": true,
|
|
"loops": true,
|
|
"properties": true,
|
|
"sequences": false,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_array_constructor_unsafe() {
|
|
let src = r###"const foo = 'string'
|
|
|
|
console.log(new Array());
|
|
console.log(new Array(0));
|
|
console.log(new Array(1));
|
|
console.log(new Array(11));
|
|
console.log(Array(11));
|
|
console.log(new Array(12));
|
|
console.log(Array(12));
|
|
console.log(new Array(foo));
|
|
console.log(Array(foo));
|
|
console.log(new Array("foo"));
|
|
console.log(Array("foo"));"###;
|
|
let config = r###"{
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_sequences_forin() {
|
|
let src = r###"var o = [];
|
|
o.push("PASS");
|
|
for (var a in o) console.log(o[a]);"###;
|
|
let config = r###"{
|
|
"sequences": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_sequences_for_init_var() {
|
|
let src = r###"var a = "PASS";
|
|
(function () {
|
|
var b = 42;
|
|
for (var c = 5; c > 0; ) c--;
|
|
a = "FAIL";
|
|
var a;
|
|
})();
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"join_vars": true,
|
|
"unused": false
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_sequences_func_def_1() {
|
|
let src = r###"function f() {
|
|
return (f = 0), !!f;
|
|
}
|
|
console.log(f());"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1639_issue_1639_1() {
|
|
let src = r###"var a = 100,
|
|
b = 10;
|
|
var L1 = 5;
|
|
while (--L1 > 0) {
|
|
if ((--b, false)) {
|
|
if (b) {
|
|
var ignore = 0;
|
|
}
|
|
}
|
|
}
|
|
console.log(a, b);"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"collapse_vars": true,
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"join_vars": true,
|
|
"loops": true,
|
|
"sequences": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1639_issue_1639_2() {
|
|
let src = r###"var a = 100,
|
|
b = 10;
|
|
function f19() {
|
|
if ((++a, false)) if (a) if (++a);
|
|
}
|
|
f19();
|
|
console.log(a, b);"###;
|
|
let config = r###"{
|
|
"booleans": true,
|
|
"collapse_vars": true,
|
|
"conditionals": true,
|
|
"evaluate": true,
|
|
"join_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_arrays_for_loop() {
|
|
let src = r###"function f0() {
|
|
var a = [1, 2, 3];
|
|
var b = 0;
|
|
for (var i = 0; i < a.length; i++) b += a[i];
|
|
return b;
|
|
}
|
|
function f1() {
|
|
var a = [1, 2, 3];
|
|
var b = 0;
|
|
for (var i = 0, len = a.length; i < len; i++) b += a[i];
|
|
return b;
|
|
}
|
|
function f2() {
|
|
var a = [1, 2, 3];
|
|
for (var i = 0; i < a.length; i++) a[i]++;
|
|
return a[2];
|
|
}
|
|
console.log(f0(), f1(), f2());"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unsafe": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_keep_quoted_strict_keep_quoted_strict() {
|
|
let src = r###"var propa = 1;
|
|
var a = {
|
|
propa,
|
|
get propb() {
|
|
return 2;
|
|
},
|
|
propc: 3,
|
|
get propd() {
|
|
return 4;
|
|
},
|
|
};
|
|
var b = {
|
|
propa: 5,
|
|
get propb() {
|
|
return 6;
|
|
},
|
|
propc: 7,
|
|
get propd() {
|
|
return 8;
|
|
},
|
|
};
|
|
var c = {};
|
|
Object.defineProperty(c, "propa", { value: 9 });
|
|
Object.defineProperty(c, "propc", { value: 10 });
|
|
console.log(a.propa, a.propb, a.propc, a["propc"], a.propd, a["propd"]);
|
|
console.log(b["propa"], b["propb"], b.propc, b["propc"], b.propd, b["propd"]);
|
|
console.log(c.propa, c["propc"]);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"properties": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_switch_issue_1663() {
|
|
let src = r###"var a = 100,
|
|
b = 10;
|
|
function f() {
|
|
switch (1) {
|
|
case 1:
|
|
b = a++;
|
|
return ++b;
|
|
default:
|
|
var b;
|
|
}
|
|
}
|
|
f();
|
|
console.log(a, b);"###;
|
|
let config = r###"{
|
|
"dead_code": true,
|
|
"evaluate": true,
|
|
"side_effects": true,
|
|
"switches": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2107() {
|
|
let src = r###"var c = 0;
|
|
!(function () {
|
|
c++;
|
|
})(
|
|
c++ +
|
|
new (function () {
|
|
this.a = 0;
|
|
var a = (c = c + 1) + (c = 1 + c);
|
|
return c++ + a;
|
|
})()
|
|
);
|
|
console.log(c);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"inline": true,
|
|
"passes": 3,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2630_5() {
|
|
let src = r###"var c = 1;
|
|
!(function () {
|
|
do {
|
|
c *= 10;
|
|
} while (f());
|
|
function f() {
|
|
return (function () {
|
|
return (c = 2 + c) < 100;
|
|
})((c = c + 3));
|
|
}
|
|
})();
|
|
console.log(c);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"inline": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2630_2() {
|
|
let src = r###"var c = 0;
|
|
!(function () {
|
|
while (f()) {}
|
|
function f() {
|
|
var not_used = (function () {
|
|
c = 1 + c;
|
|
})((c = c + 1));
|
|
}
|
|
})();
|
|
console.log(c);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2101() {
|
|
let src = r###"a = {};
|
|
console.log(
|
|
(function () {
|
|
return (function () {
|
|
return this.a;
|
|
})();
|
|
})() ===
|
|
(function () {
|
|
return a;
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"inline": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2630_3() {
|
|
let src = r###"var x = 2,
|
|
a = 1;
|
|
(function () {
|
|
function f1(a) {
|
|
f2();
|
|
--x >= 0 && f1({});
|
|
}
|
|
f1(a++);
|
|
function f2() {
|
|
a++;
|
|
}
|
|
})();
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2630_4() {
|
|
let src = r###"var x = 3,
|
|
a = 1,
|
|
b = 2;
|
|
(function () {
|
|
(function f1() {
|
|
while (--x >= 0 && f2());
|
|
})();
|
|
function f2() {
|
|
a++ + (b += a);
|
|
}
|
|
})();
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"inline": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_1841_2() {
|
|
let src = r###"var b = 10;
|
|
!(function (arg) {
|
|
for (var key in "hi") var n = arg.baz, n = [(b = 42)];
|
|
})(--b);
|
|
console.log(b);"###;
|
|
let config = r###"{
|
|
"keep_fargs": false,
|
|
"pure_getters": false,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_t131a() {
|
|
let src = r###"(function () {
|
|
function thing() {
|
|
return { a: 1 };
|
|
}
|
|
function one() {
|
|
return thing();
|
|
}
|
|
function two() {
|
|
var x = thing();
|
|
x.a = 2;
|
|
x.b = 3;
|
|
return x;
|
|
}
|
|
console.log(JSON.stringify(one()), JSON.stringify(two()));
|
|
})();"###;
|
|
let config = r###"{
|
|
"inline": 1,
|
|
"join_vars": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"passes": 2,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_unsafe_apply_1() {
|
|
let src = r###"(function (a, b) {
|
|
console.log(a, b);
|
|
}.apply("foo", ["bar"]));
|
|
(function (a, b) {
|
|
console.log(this, a, b);
|
|
}.apply("foo", ["bar"]));
|
|
(function (a, b) {
|
|
console.log(a, b);
|
|
}.apply("foo", ["bar"], "baz"));"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unsafe": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2898() {
|
|
let src = r###"var c = 0;
|
|
(function () {
|
|
while (f());
|
|
function f() {
|
|
var b = ((c = 1 + c), void (c = 1 + c));
|
|
b && b[0];
|
|
}
|
|
})();
|
|
console.log(c);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"inline": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_inline_1() {
|
|
let src = r###"(function () {
|
|
console.log(1);
|
|
})();
|
|
(function (a) {
|
|
console.log(a);
|
|
})(2);
|
|
(function (b) {
|
|
var c = b;
|
|
console.log(c);
|
|
})(3);"###;
|
|
let config = r###"{
|
|
"inline": 1,
|
|
"side_effects": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_3125() {
|
|
let src = r###"console.log(
|
|
function () {
|
|
return "PASS";
|
|
}.call()
|
|
);"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_3016_2() {
|
|
let src = r###"var b = 1;
|
|
do {
|
|
(function (a) {
|
|
return a[b];
|
|
try {
|
|
a = 2;
|
|
} catch (a) {
|
|
var a;
|
|
}
|
|
})(3);
|
|
} while (0);
|
|
console.log(b);"###;
|
|
let config = r###"{
|
|
"dead_code": true,
|
|
"inline": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2531_1() {
|
|
let src = r###"function outer() {
|
|
function inner(value) {
|
|
function closure() {
|
|
return value;
|
|
}
|
|
return function () {
|
|
return closure();
|
|
};
|
|
}
|
|
return inner("Hello");
|
|
}
|
|
console.log("Greeting:", outer()());"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_use_before_init_in_loop() {
|
|
let src = r###"var a = "PASS";
|
|
for (var b = 2; --b >= 0; )
|
|
(function () {
|
|
var c = (function () {
|
|
return 1;
|
|
})(c && (a = "FAIL"));
|
|
})();
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"side_effects": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_unsafe_apply_expansion_2() {
|
|
let src = r###"var values = [2, 3];
|
|
console.log.apply(console, [1, ...values, 4]);"###;
|
|
let config = r###"{
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2663_2() {
|
|
let src = r###"(function () {
|
|
var i;
|
|
function fn(j) {
|
|
return (function () {
|
|
console.log(j);
|
|
})();
|
|
}
|
|
for (i in { a: 1, b: 2, c: 3 }) fn(i);
|
|
})();"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_unsafe_call_3() {
|
|
let src = r###"console.log(
|
|
function () {
|
|
return arguments[0] + eval("arguments")[1];
|
|
}.call(0, 1, 2)
|
|
);"###;
|
|
let config = r###"{
|
|
"side_effects": true,
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_unsafe_call_expansion_1() {
|
|
let src = r###"(function (...a) {
|
|
console.log(...a);
|
|
}.call(console, 1, ...[2, 3], 4));"###;
|
|
let config = r###"{
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2630_1() {
|
|
let src = r###"var c = 0;
|
|
(function () {
|
|
while (f());
|
|
function f() {
|
|
var a = (function () {
|
|
var b = c++,
|
|
d = (c = 1 + c);
|
|
})();
|
|
}
|
|
})();
|
|
console.log(c);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_203() {
|
|
let src = r###"var m = {};
|
|
var fn = Function("require", "module", "exports", "module.exports = 42;");
|
|
fn(null, m, m.exports);
|
|
console.log(m.exports);"###;
|
|
let config = r###"{
|
|
"keep_fargs": false,
|
|
"side_effects": true,
|
|
"unsafe_Function": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2842() {
|
|
let src = r###"(function () {
|
|
function inlinedFunction(data) {
|
|
return data[data[0]];
|
|
}
|
|
function testMinify() {
|
|
if (true) {
|
|
const data = inlinedFunction([1, 2, 3]);
|
|
console.log(data);
|
|
}
|
|
}
|
|
return testMinify();
|
|
})();"###;
|
|
let config = r###"{
|
|
"side_effects": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_1841_1() {
|
|
let src = r###"var b = 10;
|
|
!(function (arg) {
|
|
for (var key in "hi") var n = arg.baz, n = [(b = 42)];
|
|
})(--b);
|
|
console.log(b);"###;
|
|
let config = r###"{
|
|
"keep_fargs": false,
|
|
"pure_getters": "strict",
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2476() {
|
|
let src = r###"function foo(x, y, z) {
|
|
return x < y ? x * y + z : x * z - y;
|
|
}
|
|
for (var sum = 0, i = 0; i < 10; i++) sum += foo(i, i + 1, 3 * i);
|
|
console.log(sum);"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_t131b() {
|
|
let src = r###"(function () {
|
|
function thing() {
|
|
return { a: 1 };
|
|
}
|
|
function one() {
|
|
return thing();
|
|
}
|
|
function two() {
|
|
var x = thing();
|
|
x.a = 2;
|
|
x.b = 3;
|
|
return x;
|
|
}
|
|
console.log(JSON.stringify(one()), JSON.stringify(two()));
|
|
})();"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"passes": 2
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_inline_2() {
|
|
let src = r###"(function () {
|
|
console.log(1);
|
|
})();
|
|
(function (a) {
|
|
console.log(a);
|
|
})(2);
|
|
(function (b) {
|
|
var c = b;
|
|
console.log(c);
|
|
})(3);"###;
|
|
let config = r###"{
|
|
"inline": 2,
|
|
"side_effects": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2531_3() {
|
|
let src = r###"function outer() {
|
|
function inner(value) {
|
|
function closure() {
|
|
return value;
|
|
}
|
|
return function () {
|
|
return closure();
|
|
};
|
|
}
|
|
return inner("Hello");
|
|
}
|
|
console.log("Greeting:", outer()());"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 3,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_inline_3() {
|
|
let src = r###"(function () {
|
|
console.log(1);
|
|
})();
|
|
(function (a) {
|
|
console.log(a);
|
|
})(2);
|
|
(function (b) {
|
|
var c = b;
|
|
console.log(c);
|
|
})(3);"###;
|
|
let config = r###"{
|
|
"inline": 3,
|
|
"side_effects": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2657() {
|
|
let src = r###""use strict";
|
|
console.log(
|
|
(function f() {
|
|
return h;
|
|
function g(b) {
|
|
return b || b();
|
|
}
|
|
function h(a) {
|
|
g(a);
|
|
return a;
|
|
}
|
|
})()(42)
|
|
);"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"reduce_vars": true,
|
|
"sequences": true,
|
|
"passes": 2,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_unsafe_apply_expansion_1() {
|
|
let src = r###"console.log.apply(console, [1, ...[2, 3], 4]);"###;
|
|
let config = r###"{
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_3016_1() {
|
|
let src = r###"var b = 1;
|
|
do {
|
|
(function (a) {
|
|
return a[b];
|
|
var a;
|
|
})(3);
|
|
} while (0);
|
|
console.log(b);"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2531_2() {
|
|
let src = r###"function outer() {
|
|
function inner(value) {
|
|
function closure() {
|
|
return value;
|
|
}
|
|
return function () {
|
|
return closure();
|
|
};
|
|
}
|
|
return inner("Hello");
|
|
}
|
|
console.log("Greeting:", outer()());"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 3,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_unsafe_call_expansion_2() {
|
|
let src = r###"var values = [2, 3];
|
|
(function (...a) {
|
|
console.log(...a);
|
|
}.call(console, 1, ...values, 4));"###;
|
|
let config = r###"{
|
|
"unsafe": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_issue_2783() {
|
|
let src = r###"(function () {
|
|
return g;
|
|
function f(a) {
|
|
var b = a.b;
|
|
if (b) return b;
|
|
return a;
|
|
}
|
|
function g(o, i) {
|
|
while (i--) {
|
|
console.log(f(o));
|
|
}
|
|
}
|
|
})()({ b: "PASS" }, 1);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"conditionals": true,
|
|
"if_return": true,
|
|
"inline": true,
|
|
"reduce_vars": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_functions_unsafe_call_1() {
|
|
let src = r###"(function (a, b) {
|
|
console.log(a, b);
|
|
}.call("foo", "bar"));
|
|
(function (a, b) {
|
|
console.log(this, a, b);
|
|
}.call("foo", "bar"));"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"unsafe": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1466_different_variable_in_multiple_for_of() {
|
|
let src = r###"var test = ["a", "b", "c"];
|
|
for (let tmp of test) {
|
|
console.log(tmp);
|
|
let dd;
|
|
dd = ["e", "f", "g"];
|
|
for (let t of dd) {
|
|
console.log(t);
|
|
}
|
|
}"###;
|
|
let config = r###"{
|
|
"hoist_funs": true,
|
|
"dead_code": true,
|
|
"conditionals": true,
|
|
"comparisons": true,
|
|
"evaluate": true,
|
|
"booleans": true,
|
|
"loops": true,
|
|
"unused": true,
|
|
"keep_fargs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"side_effects": true,
|
|
"collapse_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1466_same_variable_in_multiple_for_of() {
|
|
let src = r###"var test = ["a", "b", "c"];
|
|
for (let tmp of test) {
|
|
console.log(tmp);
|
|
let dd;
|
|
dd = ["e", "f", "g"];
|
|
for (let tmp of dd) {
|
|
console.log(tmp);
|
|
}
|
|
}"###;
|
|
let config = r###"{
|
|
"hoist_funs": true,
|
|
"dead_code": true,
|
|
"conditionals": true,
|
|
"comparisons": true,
|
|
"evaluate": true,
|
|
"booleans": true,
|
|
"loops": true,
|
|
"unused": true,
|
|
"keep_fargs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"side_effects": true,
|
|
"collapse_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1466_same_variable_in_multiple_for_of_sequences_let() {
|
|
let src = r###"var test = ["a", "b", "c"];
|
|
for (let tmp of test) {
|
|
console.log(tmp);
|
|
let dd;
|
|
dd = ["e", "f", "g"];
|
|
for (let tmp of dd) {
|
|
console.log(tmp);
|
|
}
|
|
}"###;
|
|
let config = r###"{
|
|
"hoist_funs": true,
|
|
"dead_code": true,
|
|
"conditionals": true,
|
|
"comparisons": true,
|
|
"evaluate": true,
|
|
"booleans": true,
|
|
"loops": true,
|
|
"unused": true,
|
|
"keep_fargs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"collapse_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1466_same_variable_in_multiple_for_in_sequences_const() {
|
|
let src = r###"var test = ["a", "b", "c"];
|
|
for (const tmp in test) {
|
|
console.log(tmp);
|
|
let dd;
|
|
dd = ["e", "f", "g"];
|
|
for (const tmp in test) {
|
|
console.log(tmp);
|
|
}
|
|
}"###;
|
|
let config = r###"{
|
|
"hoist_funs": true,
|
|
"dead_code": true,
|
|
"conditionals": true,
|
|
"comparisons": true,
|
|
"evaluate": true,
|
|
"booleans": true,
|
|
"loops": true,
|
|
"unused": false,
|
|
"keep_fargs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"collapse_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1466_more_variable_in_multiple_for() {
|
|
let src = r###"for (let a = 9, i = 0; i < 20; i += a) {
|
|
let b = a++ + i;
|
|
console.log(a, b, i);
|
|
for (let k = b, m = b * b, i = 0; i < 10; i++) {
|
|
console.log(a, b, m, k, i);
|
|
}
|
|
}"###;
|
|
let config = r###"{
|
|
"hoist_funs": true,
|
|
"dead_code": true,
|
|
"conditionals": true,
|
|
"comparisons": true,
|
|
"evaluate": true,
|
|
"booleans": true,
|
|
"loops": true,
|
|
"unused": false,
|
|
"keep_fargs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"side_effects": true,
|
|
"collapse_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1466_different_variable_in_multiple_for_in() {
|
|
let src = r###"var test = ["a", "b", "c"];
|
|
for (let tmp in test) {
|
|
console.log(tmp);
|
|
let dd;
|
|
dd = ["e", "f", "g"];
|
|
for (let t in test) {
|
|
console.log(t);
|
|
}
|
|
}"###;
|
|
let config = r###"{
|
|
"hoist_funs": true,
|
|
"dead_code": true,
|
|
"conditionals": true,
|
|
"comparisons": true,
|
|
"evaluate": true,
|
|
"booleans": true,
|
|
"loops": true,
|
|
"unused": false,
|
|
"keep_fargs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"side_effects": true,
|
|
"collapse_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1466_same_variable_in_multiple_for_in() {
|
|
let src = r###"var test = ["a", "b", "c"];
|
|
for (let tmp in test) {
|
|
console.log(tmp);
|
|
let dd;
|
|
dd = ["e", "f", "g"];
|
|
for (let tmp in test) {
|
|
console.log(tmp);
|
|
}
|
|
}"###;
|
|
let config = r###"{
|
|
"hoist_funs": true,
|
|
"dead_code": true,
|
|
"conditionals": true,
|
|
"comparisons": true,
|
|
"evaluate": true,
|
|
"booleans": true,
|
|
"loops": true,
|
|
"unused": false,
|
|
"keep_fargs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"side_effects": true,
|
|
"collapse_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1466_same_variable_in_multiple_for_in_sequences_let() {
|
|
let src = r###"var test = ["a", "b", "c"];
|
|
for (let tmp in test) {
|
|
console.log(tmp);
|
|
let dd;
|
|
dd = ["e", "f", "g"];
|
|
for (let tmp in test) {
|
|
console.log(tmp);
|
|
}
|
|
}"###;
|
|
let config = r###"{
|
|
"hoist_funs": true,
|
|
"dead_code": true,
|
|
"conditionals": true,
|
|
"comparisons": true,
|
|
"evaluate": true,
|
|
"booleans": true,
|
|
"loops": true,
|
|
"unused": false,
|
|
"keep_fargs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"collapse_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_1466_same_variable_in_multiple_for_of_sequences_const() {
|
|
let src = r###"var test = ["a", "b", "c"];
|
|
for (const tmp of test) {
|
|
console.log(tmp);
|
|
let dd;
|
|
dd = ["e", "f", "g"];
|
|
for (const tmp of dd) {
|
|
console.log(tmp);
|
|
}
|
|
}"###;
|
|
let config = r###"{
|
|
"hoist_funs": true,
|
|
"dead_code": true,
|
|
"conditionals": true,
|
|
"comparisons": true,
|
|
"evaluate": true,
|
|
"booleans": true,
|
|
"loops": true,
|
|
"unused": true,
|
|
"keep_fargs": true,
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"sequences": true,
|
|
"side_effects": true,
|
|
"collapse_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_747_dont_reuse_prop() {
|
|
let src = r###""aaaaaaaaaabbbbb";
|
|
var obj = {};
|
|
obj.a = 123;
|
|
obj.asd = 256;
|
|
console.log(obj.a);"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_747_unmangleable_props_should_always_be_reserved() {
|
|
let src = r###""aaaaaaaaaabbbbb";
|
|
var obj = {};
|
|
obj.asd = 256;
|
|
obj.a = 123;
|
|
console.log(obj.a);"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_loops_issue_2740_7() {
|
|
let src = r###"let a = 9,
|
|
b = 0;
|
|
for (const a = 1; a < 3; ++b) break;
|
|
console.log(a, b);"###;
|
|
let config = r###"{
|
|
"dead_code": true,
|
|
"loops": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_loops_issue_2740_8() {
|
|
let src = r###"var a = 9,
|
|
b = 0;
|
|
for (const a = 1; a < 3; ++b) break;
|
|
console.log(a, b);"###;
|
|
let config = r###"{
|
|
"dead_code": true,
|
|
"loops": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_loops_issue_2740_6() {
|
|
let src = r###"const a = 9,
|
|
b = 0;
|
|
for (const a = 1; a < 3; ++b) break;
|
|
console.log(a, b);"###;
|
|
let config = r###"{
|
|
"dead_code": true,
|
|
"loops": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_loops_issue_2740_3() {
|
|
let src = r###"L1: for (var x = 0; x < 3; x++) {
|
|
L2: for (var y = 0; y < 2; y++) {
|
|
break L1;
|
|
}
|
|
}
|
|
console.log(x, y);"###;
|
|
let config = r###"{
|
|
"dead_code": true,
|
|
"loops": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_loops_issue_2740_4() {
|
|
let src = r###"L1: for (var x = 0; x < 3; x++) {
|
|
L2: for (var y = 0; y < 2; y++) {
|
|
break L2;
|
|
}
|
|
}
|
|
console.log(x, y);"###;
|
|
let config = r###"{
|
|
"dead_code": true,
|
|
"loops": true,
|
|
"passes": 2
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_loops_issue_2740_5() {
|
|
let src = r###"L1: for (var x = 0; x < 3; x++) {
|
|
break L1;
|
|
L2: for (var y = 0; y < 2; y++) {
|
|
break L2;
|
|
}
|
|
}
|
|
console.log(x, y);"###;
|
|
let config = r###"{
|
|
"dead_code": true,
|
|
"loops": true,
|
|
"passes": 2
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_rename_function_iife_catch() {
|
|
let src = r###"function f(n) {
|
|
!(function () {
|
|
try {
|
|
throw 0;
|
|
} catch (n) {
|
|
var a = 1;
|
|
console.log(n, a);
|
|
}
|
|
})();
|
|
}
|
|
f();"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_rename_mangle_catch_var() {
|
|
let src = r###"var a = "FAIL";
|
|
try {
|
|
throw 1;
|
|
} catch (args) {
|
|
var a = "PASS";
|
|
}
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"ie8": false,
|
|
"toplevel": false
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_negate_iife_issue_1254_negate_iife_true() {
|
|
let src = r###"(function () {
|
|
return function () {
|
|
console.log("test");
|
|
};
|
|
})()();"###;
|
|
let config = r###"{
|
|
"negate_iife": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_try_catch_catch_destructuring_with_sequence() {
|
|
let src = r###"try {
|
|
throw {};
|
|
} catch ({ xCover = (0, function () { }) }) {
|
|
console.log(typeof xCover)
|
|
}"###;
|
|
let config = r###"{}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_281_pure_annotation_1() {
|
|
let src = r###"(function () {
|
|
console.log("hello");
|
|
})();"###;
|
|
let config = r###"{
|
|
"inline": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_281_keep_fargs() {
|
|
let src = r###"var a = 1;
|
|
!(function (a_1) {
|
|
a++;
|
|
})(a++ + (a && a.var));
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"inline": true,
|
|
"keep_fargs": true,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_281_drop_fargs() {
|
|
let src = r###"var a = 1;
|
|
!(function (a_1) {
|
|
a++;
|
|
})(a++ + (a && a.var));
|
|
console.log(a);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"inline": true,
|
|
"keep_fargs": false,
|
|
"side_effects": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_issue_281_pure_annotation_2() {
|
|
let src = r###"(function (n) {
|
|
console.log("hello", n);
|
|
})(42);"###;
|
|
let config = r###"{
|
|
"collapse_vars": true,
|
|
"inline": true,
|
|
"side_effects": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_arguments_duplicate_parameter_with_arguments() {
|
|
let src = r###"(function (a, a) {
|
|
console.log((a = "foo"), arguments[0]);
|
|
})("baz", "Bar");"###;
|
|
let config = r###"{
|
|
"arguments": true,
|
|
"defaults": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_arguments_destructuring_1() {
|
|
let src = r###"(function (a, { d: d }) {
|
|
console.log((a = "foo"), arguments[0]);
|
|
})("baz", { d: "Bar" });"###;
|
|
let config = r###"{
|
|
"arguments": true,
|
|
"defaults": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_arguments_destructuring_2() {
|
|
let src = r###"(function ({ d: d }, a) {
|
|
console.log((a = "foo"), arguments[0].d);
|
|
})({ d: "Bar" }, "baz");"###;
|
|
let config = r###"{
|
|
"arguments": true,
|
|
"defaults": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_arguments_modified_strict() {
|
|
let src = r###""use strict";
|
|
(function (a, b) {
|
|
var c = arguments[0];
|
|
var d = arguments[1];
|
|
var a = "foo";
|
|
b++;
|
|
arguments[0] = "moo";
|
|
arguments[1] *= 2;
|
|
console.log(a, b, c, d, arguments[0], arguments[1]);
|
|
})("bar", 42);"###;
|
|
let config = r###"{
|
|
"arguments": true,
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_arguments_replace_index() {
|
|
let src = r###"var arguments = [];
|
|
console.log(arguments[0]);
|
|
(function () {
|
|
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
|
})("bar", 42);
|
|
(function (a, b) {
|
|
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
|
})("bar", 42);
|
|
(function (arguments) {
|
|
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
|
})("bar", 42);
|
|
(function () {
|
|
var arguments;
|
|
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
|
})("bar", 42);"###;
|
|
let config = r###"{
|
|
"arguments": true,
|
|
"evaluate": true,
|
|
"properties": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_arguments_modified() {
|
|
let src = r###"(function (a, b) {
|
|
var c = arguments[0];
|
|
var d = arguments[1];
|
|
var a = "foo";
|
|
b++;
|
|
arguments[0] = "moo";
|
|
arguments[1] *= 2;
|
|
console.log(a, b, c, d, arguments[0], arguments[1]);
|
|
})("bar", 42);"###;
|
|
let config = r###"{
|
|
"arguments": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_arguments_replace_index_strict() {
|
|
let src = r###""use strict";
|
|
(function () {
|
|
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
|
})("bar", 42);
|
|
(function (a, b) {
|
|
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
|
})("bar", 42);"###;
|
|
let config = r###"{
|
|
"arguments": true,
|
|
"evaluate": true,
|
|
"properties": true,
|
|
"reduce_vars": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_arguments_issue_687() {
|
|
let src = r###"function shouldBePure() {
|
|
return arguments.length;
|
|
}
|
|
console.log(shouldBePure())"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_arguments_replace_index_keep_fargs() {
|
|
let src = r###"var arguments = [];
|
|
console.log(arguments[0]);
|
|
(function () {
|
|
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
|
})("bar", 42);
|
|
(function (a, b) {
|
|
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
|
})("bar", 42);
|
|
(function (arguments) {
|
|
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
|
})("bar", 42);
|
|
(function () {
|
|
var arguments;
|
|
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
|
})("bar", 42);"###;
|
|
let config = r###"{
|
|
"arguments": true,
|
|
"evaluate": true,
|
|
"keep_fargs": false,
|
|
"properties": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_typeof_issue_2728_3() {
|
|
let src = r###"(function () {
|
|
function arguments() {}
|
|
console.log(typeof arguments);
|
|
})();"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_vars": true,
|
|
"typeofs": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_typeof_issue_2728_4() {
|
|
let src = r###"function arguments() {}
|
|
console.log(typeof arguments);"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"reduce_vars": true,
|
|
"toplevel": true,
|
|
"typeofs": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_typeof_typeof_defun_1() {
|
|
let src = r###"function f() {
|
|
console.log("YES");
|
|
}
|
|
function g() {
|
|
h = 42;
|
|
console.log("NOPE");
|
|
}
|
|
function h() {
|
|
console.log("YUP");
|
|
}
|
|
g = 42;
|
|
"function" == typeof f && f();
|
|
"function" == typeof g && g();
|
|
"function" == typeof h && h();"###;
|
|
let config = r###"{
|
|
"evaluate": true,
|
|
"inline": true,
|
|
"passes": 2,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"typeofs": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn terser_pure_funcs_issue_3065_4() {
|
|
let src = r###"var debug = function (msg) {
|
|
console.log(msg);
|
|
};
|
|
debug(
|
|
(function () {
|
|
console.log("PASS");
|
|
return "FAIL";
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"pure_funcs": ["debug"],
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn terser_pure_funcs_issue_3065_3() {
|
|
let src = r###"function debug(msg) {
|
|
console.log(msg);
|
|
}
|
|
debug(
|
|
(function () {
|
|
console.log("PASS");
|
|
return "FAIL";
|
|
})()
|
|
);"###;
|
|
let config = r###"{
|
|
"pure_funcs": ["debug"],
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn issues_vercel_ms_1() {
|
|
let src = r###"const s = 1000;
|
|
const m = s * 60;
|
|
const h = m * 60;
|
|
const d = h * 24;
|
|
const w = d * 7;
|
|
const y = d * 365.25;
|
|
function ms(value, options) {
|
|
try {
|
|
if (typeof value === "string" && value.length > 0) {
|
|
return parse(value);
|
|
} else if (typeof value === "number" && isFinite(value)) {
|
|
return options?.long ? fmtLong(value) : fmtShort(value);
|
|
}
|
|
throw new Error("Value is not a string or number.");
|
|
} catch (error) {
|
|
const message = isError(error) ? `${error.message}. value=${JSON.stringify(value)}` : "An unknown error has occured.";
|
|
throw new Error(message);
|
|
}
|
|
}
|
|
function parse(str) {
|
|
str = String(str);
|
|
if (str.length > 100) {
|
|
throw new Error("Value exceeds the maximum length of 100 characters.");
|
|
}
|
|
const match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(str);
|
|
if (!match) {
|
|
return NaN;
|
|
}
|
|
const n = parseFloat(match[1]);
|
|
const type = (match[2] || "ms").toLowerCase();
|
|
switch (type) {
|
|
case "years":
|
|
case "year":
|
|
case "yrs":
|
|
case "yr":
|
|
case "y":
|
|
return n * y;
|
|
case "weeks":
|
|
case "week":
|
|
case "w":
|
|
return n * w;
|
|
case "days":
|
|
case "day":
|
|
case "d":
|
|
return n * d;
|
|
case "hours":
|
|
case "hour":
|
|
case "hrs":
|
|
case "hr":
|
|
case "h":
|
|
return n * h;
|
|
case "minutes":
|
|
case "minute":
|
|
case "mins":
|
|
case "min":
|
|
case "m":
|
|
return n * m;
|
|
case "seconds":
|
|
case "second":
|
|
case "secs":
|
|
case "sec":
|
|
case "s":
|
|
return n * s;
|
|
case "milliseconds":
|
|
case "millisecond":
|
|
case "msecs":
|
|
case "msec":
|
|
case "ms":
|
|
return n;
|
|
default:
|
|
throw new Error(`The unit ${type} was matched, but no matching case exists.`);
|
|
}
|
|
}
|
|
|
|
function fmtShort(ms) {
|
|
const msAbs = Math.abs(ms);
|
|
if (msAbs >= d) {
|
|
return `${Math.round(ms / d)}d`;
|
|
}
|
|
if (msAbs >= h) {
|
|
return `${Math.round(ms / h)}h`;
|
|
}
|
|
if (msAbs >= m) {
|
|
return `${Math.round(ms / m)}m`;
|
|
}
|
|
if (msAbs >= s) {
|
|
return `${Math.round(ms / s)}s`;
|
|
}
|
|
return `${ms}ms`;
|
|
}
|
|
function fmtLong(ms) {
|
|
const msAbs = Math.abs(ms);
|
|
if (msAbs >= d) {
|
|
return plural(ms, msAbs, d, "day");
|
|
}
|
|
if (msAbs >= h) {
|
|
return plural(ms, msAbs, h, "hour");
|
|
}
|
|
if (msAbs >= m) {
|
|
return plural(ms, msAbs, m, "minute");
|
|
}
|
|
if (msAbs >= s) {
|
|
return plural(ms, msAbs, s, "second");
|
|
}
|
|
return `${ms} ms`;
|
|
}
|
|
function plural(ms, msAbs, n, name) {
|
|
const isPlural = msAbs >= n * 1.5;
|
|
return `${Math.round(ms / n)} ${name}${isPlural ? "s" : ""}`;
|
|
}
|
|
function isError(error) {
|
|
return typeof error === "object" && error !== null && "message" in error;
|
|
}
|
|
|
|
console.log(ms(123))
|
|
console.log(ms('123day'))
|
|
console.log(ms(12321341234217))
|
|
console.log(ms(12321341234217))
|
|
console.log(ms(12321341234217))
|
|
console.log(ms(12321341234217))
|
|
console.log(ms(12321341234217))
|
|
console.log(ms(12321341234217))
|
|
console.log(ms(12321341234217))"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn issues_2011_1() {
|
|
let src = r###"class ClassA {
|
|
constructor() {
|
|
console.log('Class A');
|
|
}
|
|
}
|
|
|
|
const cls = class ClassB {
|
|
static MyA = ClassA;
|
|
|
|
constructor() {
|
|
console.log('Claas B');
|
|
}
|
|
|
|
it() {
|
|
console.log('method it - start');
|
|
|
|
this.bb = new ClassB.MyA();
|
|
|
|
console.log('method it - end');
|
|
}
|
|
}
|
|
|
|
|
|
new cls().it();"###;
|
|
let config = r###"{
|
|
"defaults": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn issues_2011_2() {
|
|
let src = r###"function _class_call_check(instance, Constructor) {
|
|
if (!(instance instanceof Constructor)) {
|
|
throw new TypeError("Cannot call a class as a function");
|
|
}
|
|
}
|
|
function _defineProperties(target, props) {
|
|
for (var i = 0; i < props.length; i++) {
|
|
var descriptor = props[i];
|
|
descriptor.enumerable = descriptor.enumerable || false;
|
|
descriptor.configurable = true;
|
|
if ("value" in descriptor) descriptor.writable = true;
|
|
Object.defineProperty(target, descriptor.key, descriptor);
|
|
}
|
|
}
|
|
function _create_class(Constructor, protoProps, staticProps) {
|
|
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
return Constructor;
|
|
}
|
|
function _define_property(obj, key, value) {
|
|
if (key in obj) {
|
|
Object.defineProperty(obj, key, {
|
|
value: value,
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true
|
|
});
|
|
} else {
|
|
obj[key] = value;
|
|
}
|
|
return obj;
|
|
}
|
|
var ClassA = function ClassA() {
|
|
"use strict";
|
|
_class_call_check(this, ClassA);
|
|
console.log('Class A');
|
|
};
|
|
var cls = function () {
|
|
var ClassB = /*#__PURE__*/ function () {
|
|
"use strict";
|
|
function ClassB() {
|
|
_class_call_check(this, ClassB);
|
|
console.log('Claas B');
|
|
}
|
|
_create_class(ClassB, [
|
|
{
|
|
key: "it",
|
|
value: function it() {
|
|
console.log('method it - start');
|
|
this.bb = new ClassB.MyA();
|
|
console.log('method it - end');
|
|
}
|
|
}
|
|
]);
|
|
return ClassB;
|
|
}();
|
|
_define_property(ClassB, "MyA", ClassA);
|
|
return ClassB;
|
|
}();
|
|
new cls().it();"###;
|
|
let config = r###"{
|
|
"defaults": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn murmur2_1() {
|
|
let src = r###"function murmur2(str) {
|
|
// 'm' and 'r' are mixing constants generated offline.
|
|
// They're not really 'magic', they just happen to work well.
|
|
// const m = 0x5bd1e995;
|
|
// const r = 24;
|
|
// Initialize the hash
|
|
var h = 0; // Mix 4 bytes at a time into the hash
|
|
|
|
var k,
|
|
i = 0,
|
|
len = str.length;
|
|
|
|
for (; len >= 4; ++i, len -= 4) {
|
|
k = str.charCodeAt(i) & 0xff | (str.charCodeAt(++i) & 0xff) << 8 | (str.charCodeAt(++i) & 0xff) << 16 | (str.charCodeAt(++i) & 0xff) << 24;
|
|
k =
|
|
/* Math.imul(k, m): */
|
|
(k & 0xffff) * 0x5bd1e995 + ((k >>> 16) * 0xe995 << 16);
|
|
k ^=
|
|
/* k >>> r: */
|
|
k >>> 24;
|
|
h =
|
|
/* Math.imul(k, m): */
|
|
(k & 0xffff) * 0x5bd1e995 + ((k >>> 16) * 0xe995 << 16) ^
|
|
/* Math.imul(h, m): */
|
|
(h & 0xffff) * 0x5bd1e995 + ((h >>> 16) * 0xe995 << 16);
|
|
} // Handle the last few bytes of the input array
|
|
|
|
|
|
switch (len) {
|
|
case 3:
|
|
h ^= (str.charCodeAt(i + 2) & 0xff) << 16;
|
|
|
|
case 2:
|
|
h ^= (str.charCodeAt(i + 1) & 0xff) << 8;
|
|
|
|
case 1:
|
|
h ^= str.charCodeAt(i) & 0xff;
|
|
h =
|
|
/* Math.imul(h, m): */
|
|
(h & 0xffff) * 0x5bd1e995 + ((h >>> 16) * 0xe995 << 16);
|
|
} // Do a few final mixes of the hash to ensure the last few
|
|
// bytes are well-incorporated.
|
|
|
|
|
|
h ^= h >>> 13;
|
|
h =
|
|
/* Math.imul(h, m): */
|
|
(h & 0xffff) * 0x5bd1e995 + ((h >>> 16) * 0xe995 << 16);
|
|
return ((h ^ h >>> 15) >>> 0).toString(36);
|
|
}
|
|
|
|
console.log(murmur2("123421334"))
|
|
console.log(murmur2("123asd ;nv"))
|
|
console.log(murmur2("1va1ns`klj"))"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn murmur2_reduced() {
|
|
let src = r###"function murmur2(str) {
|
|
var h = 0;
|
|
var k, i = 0, len = str.length;
|
|
for (; len >= 4; ++i, len -= 4) {
|
|
k = 255 & str.charCodeAt(i) | (255 & str.charCodeAt(++i)) << 8 | (255 & str.charCodeAt(++i)) << 16 | (255 & str.charCodeAt(++i)) << 24;
|
|
k = (65535 & k) * 1540483477 + ((k >>> 16) * 59797 << 16);
|
|
k ^= k >>> 24;
|
|
h = (65535 & k) * 1540483477 + ((k >>> 16) * 59797 << 16) ^ (65535 & h) * 1540483477 + ((h >>> 16) * 59797 << 16);
|
|
}
|
|
switch (len) {
|
|
case 3:
|
|
h ^= (255 & str.charCodeAt(i + 2)) << 16;
|
|
case 2:
|
|
h ^= (255 & str.charCodeAt(i + 1)) << 8;
|
|
case 1:
|
|
h ^= 255 & str.charCodeAt(i);
|
|
h = (65535 & h) * 1540483477 + ((h >>> 16) * 59797 << 16);
|
|
}
|
|
h ^= h >>> 13;
|
|
h = (65535 & h) * 1540483477 + ((h >>> 16) * 59797 << 16);
|
|
return ((h ^ h >>> 15) >>> 0).toString(36);
|
|
}
|
|
console.log(murmur2("123421334"));
|
|
console.log(murmur2("123asd ;nv"));
|
|
console.log(murmur2("1va1ns`klj"));"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn plotly_1() {
|
|
let src = r###"
|
|
function log2(v) {
|
|
var r, shift;
|
|
r = (v > 0xFFFF) << 4; v >>>= r;
|
|
shift = (v > 0xFF ) << 3; v >>>= shift; r |= shift;
|
|
shift = (v > 0xF ) << 2; v >>>= shift; r |= shift;
|
|
shift = (v > 0x3 ) << 1; v >>>= shift; r |= shift;
|
|
return r | (v >> 1);
|
|
}
|
|
console.log(log2(65536))
|
|
console.log(log2(2))
|
|
console.log(log2(4))
|
|
console.log(log2(8))
|
|
"###;
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn internal_1() {
|
|
let src = r###"
|
|
function H (x) {
|
|
return function (y, z) {
|
|
return x._ + y + z
|
|
}
|
|
}
|
|
|
|
function P () {
|
|
var a = 0
|
|
a = {
|
|
_: 1
|
|
}
|
|
a.calc = H(a)
|
|
return a
|
|
}
|
|
|
|
console.log(P().calc(1, 1))
|
|
"###;
|
|
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn direct_eval_1() {
|
|
let src = r###"
|
|
const obj = {
|
|
1: function () {
|
|
const foo = 1;
|
|
return {
|
|
test: function (s) {
|
|
return eval(s)
|
|
}
|
|
}
|
|
},
|
|
2: function foo(mod1) {
|
|
console.log(mod1.test('foo'))
|
|
}
|
|
};
|
|
|
|
|
|
obj[2](obj[1]());
|
|
"###;
|
|
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn indirect_eval_1() {
|
|
let src = r###"
|
|
const obj = {
|
|
1: function () {
|
|
const foo = 1;
|
|
return {
|
|
test: function (s) {
|
|
const e = eval;
|
|
return e(s)
|
|
}
|
|
}
|
|
},
|
|
2: function foo(mod1) {
|
|
let success = false;
|
|
try {
|
|
mod1.test('foo')
|
|
} catch (e) {
|
|
success = true;
|
|
console.log('PASS');
|
|
}
|
|
if (!success) {
|
|
throw new Error('indirect eval should not be direct eval');
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
obj[2](obj[1]());
|
|
"###;
|
|
|
|
let config = r###"{
|
|
"defaults": true,
|
|
"toplevel": true
|
|
}"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn try_catch_1() {
|
|
let src = r###"
|
|
var a = "FAIL";
|
|
try {
|
|
throw 1;
|
|
} catch (args) {
|
|
a = "PASS";
|
|
}
|
|
console.log(a);
|
|
|
|
"###;
|
|
|
|
run_default_exec_test(src);
|
|
}
|
|
|
|
#[test]
|
|
fn try_catch_2() {
|
|
let src = r###"
|
|
var a = "PASS";
|
|
try {
|
|
throw "FAIL1";
|
|
} catch (a) {
|
|
var a = "FAIL2";
|
|
}
|
|
console.log(a);
|
|
"###;
|
|
|
|
run_default_exec_test(src);
|
|
}
|
|
|
|
#[test]
|
|
fn try_catch_3() {
|
|
let src = r###"
|
|
var a = "FAIL";
|
|
try {
|
|
throw 1;
|
|
} catch (args) {
|
|
var a = "PASS";
|
|
}
|
|
console.log(a);
|
|
"###;
|
|
|
|
run_default_exec_test(src);
|
|
}
|
|
|
|
#[test]
|
|
fn try_catch_4() {
|
|
let src = r###"
|
|
"aaaaaaaa";
|
|
var a = 1,
|
|
b = "FAIL";
|
|
try {
|
|
throw 1;
|
|
} catch (c) {
|
|
try {
|
|
throw 0;
|
|
} catch (a) {
|
|
if (c) b = "PASS";
|
|
}
|
|
}
|
|
console.log(b);
|
|
"###;
|
|
|
|
run_default_exec_test(src);
|
|
}
|
|
|
|
#[test]
|
|
fn try_catch_5() {
|
|
let src = r###"
|
|
var a = "PASS";
|
|
try {
|
|
throw "FAIL1";
|
|
} catch (a) {
|
|
var a = "FAIL2";
|
|
}
|
|
console.log(a);
|
|
"###;
|
|
|
|
run_default_exec_test(src);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_4444_1() {
|
|
let src = r###"
|
|
const test = () => {
|
|
let a = 0;
|
|
let b = 0;
|
|
let c = [1, 2, 3, 4, 5].map((i) => {
|
|
a += i;
|
|
b += i;
|
|
return i;
|
|
});
|
|
return [a, b, c];
|
|
};
|
|
|
|
const [a, b, c] = test();
|
|
console.log("test", a, b, c);
|
|
"###;
|
|
|
|
let config = r###"
|
|
{
|
|
"arguments": false,
|
|
"arrows": false,
|
|
"booleans": true,
|
|
"booleans_as_integers": false,
|
|
"collapse_vars": true,
|
|
"comparisons": true,
|
|
"computed_props": false,
|
|
"conditionals": false,
|
|
"dead_code": false,
|
|
"directives": false,
|
|
"drop_console": false,
|
|
"drop_debugger": true,
|
|
"evaluate": false,
|
|
"expression": false,
|
|
"hoist_funs": false,
|
|
"hoist_props": false,
|
|
"hoist_vars": false,
|
|
"if_return": true,
|
|
"join_vars": false,
|
|
"keep_classnames": false,
|
|
"keep_fargs": true,
|
|
"keep_fnames": false,
|
|
"keep_infinity": false,
|
|
"loops": true,
|
|
"negate_iife": false,
|
|
"properties": true,
|
|
"reduce_funcs": false,
|
|
"reduce_vars": false,
|
|
"side_effects": true,
|
|
"switches": false,
|
|
"typeofs": false,
|
|
"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
|
|
}
|
|
"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_insane_1() {
|
|
let src = r###"
|
|
function f() {
|
|
a--;
|
|
try {
|
|
a++;
|
|
x();
|
|
} catch (a) {
|
|
if (a) var a;
|
|
var a = 10;
|
|
}
|
|
console.log(a)
|
|
}
|
|
f();
|
|
"###;
|
|
|
|
let config = r###"
|
|
{
|
|
"conditionals": true,
|
|
"negate_iife": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}
|
|
"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn terser_insane_2() {
|
|
let src = r###"
|
|
function f() {
|
|
console.log(a)
|
|
a--;
|
|
console.log(a)
|
|
try {
|
|
console.log(a)
|
|
a++;
|
|
console.log(a)
|
|
x();
|
|
} catch (a) {
|
|
if (a) var a;
|
|
var a = 10;
|
|
}
|
|
console.log(a)
|
|
}
|
|
f();
|
|
"###;
|
|
|
|
let config = r###"
|
|
{
|
|
"conditionals": true,
|
|
"negate_iife": true,
|
|
"passes": 2,
|
|
"reduce_funcs": true,
|
|
"reduce_vars": true,
|
|
"side_effects": true,
|
|
"toplevel": true,
|
|
"unused": true
|
|
}
|
|
"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_4788_1() {
|
|
let src = r###"
|
|
let id = 0;
|
|
|
|
const obj = {
|
|
get foo() {
|
|
console.log("foo", id++);
|
|
},
|
|
};
|
|
|
|
obj.foo;
|
|
|
|
const obj2 = {
|
|
...obj,
|
|
};
|
|
|
|
obj2.foo;
|
|
|
|
const obj3 = {
|
|
...obj,
|
|
foo: 1,
|
|
};
|
|
|
|
obj3.foo;
|
|
"###;
|
|
|
|
run_default_exec_test(src);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_5645() {
|
|
let src = r###"
|
|
const t = {
|
|
1: 'a',
|
|
2: 'b'
|
|
}
|
|
function g(arg) {
|
|
if (t[arg] === undefined) {
|
|
var arg = 2
|
|
}
|
|
return t[arg]
|
|
}
|
|
|
|
console.log(g(1))
|
|
"###;
|
|
let config = r###"
|
|
{
|
|
"arguments": false,
|
|
"arrows": false,
|
|
"booleans": false,
|
|
"booleans_as_integers": false,
|
|
"collapse_vars": false,
|
|
"comparisons": false,
|
|
"computed_props": false,
|
|
"conditionals": false,
|
|
"dead_code": false,
|
|
"directives": false,
|
|
"drop_console": false,
|
|
"drop_debugger": false,
|
|
"evaluate": false,
|
|
"expression": false,
|
|
"hoist_funs": false,
|
|
"hoist_props": false,
|
|
"hoist_vars": false,
|
|
"if_return": false,
|
|
"join_vars": false,
|
|
"keep_classnames": false,
|
|
"keep_fargs": false,
|
|
"keep_fnames": false,
|
|
"keep_infinity": false,
|
|
"loops": false,
|
|
"negate_iife": false,
|
|
"properties": false,
|
|
"reduce_funcs": false,
|
|
"reduce_vars": false,
|
|
"side_effects": false,
|
|
"switches": false,
|
|
"typeofs": false,
|
|
"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": false,
|
|
"const_to_let": false,
|
|
"pristine_globals": false
|
|
}
|
|
"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_5799() {
|
|
let src = r###"
|
|
console.log(`\u2014`)
|
|
"###;
|
|
|
|
run_default_exec_test(src);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_5914() {
|
|
let src = r###"
|
|
class Test {
|
|
constructor(config) {
|
|
const that = this;
|
|
this.config = config;
|
|
this.options = {
|
|
get config() {
|
|
return that.config;
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
const instance = new Test(42);
|
|
console.log(instance.options.config);
|
|
"###;
|
|
|
|
let config = r###"
|
|
{
|
|
"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
|
|
}
|
|
"###;
|
|
|
|
run_exec_test(src, config, false);
|
|
}
|
|
|
|
#[test]
|
|
fn feedback_regex_range() {
|
|
let src = r###"
|
|
const rtlRegEx = new RegExp(
|
|
/* eslint-disable prettier/prettier */
|
|
'[' +
|
|
String.fromCharCode(0x00591) + '-' + String.fromCharCode(0x008ff) +
|
|
String.fromCharCode(0x0fb1d) + '-' + String.fromCharCode(0x0fdff) +
|
|
String.fromCharCode(0x0fe70) + '-' + String.fromCharCode(0x0fefc) +
|
|
String.fromCharCode(0x10800) + '-' + String.fromCharCode(0x10fff) +
|
|
String.fromCharCode(0x1e800) + '-' + String.fromCharCode(0x1efff) +
|
|
']'
|
|
/* eslint-enable prettier/prettier */
|
|
);
|
|
console.log('PASS')
|
|
"###;
|
|
|
|
run_default_exec_test(src);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6004() {
|
|
run_default_exec_test(
|
|
r###"
|
|
const props = {'a': 1, 'b': 2};
|
|
const isBox = 'a' in props || 'b' in props;
|
|
for (const p in props) {
|
|
delete props[p];
|
|
}
|
|
console.log(isBox);
|
|
"###,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6047_1() {
|
|
run_default_exec_test(
|
|
r###"
|
|
let foo = () => 1;
|
|
|
|
const obj = {
|
|
get 0() {
|
|
foo = () => 2;
|
|
return 40;
|
|
},
|
|
};
|
|
console.log(obj)
|
|
|
|
var c = obj[0];
|
|
|
|
console.log(foo(c));
|
|
"###,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6047_2() {
|
|
run_default_exec_test(
|
|
r###"
|
|
let foo = () => 1;
|
|
|
|
const obj = new Proxy({}, {
|
|
get () {
|
|
foo = () => 2;
|
|
return 40;
|
|
},
|
|
});
|
|
console.log(obj)
|
|
|
|
var c = obj[0];
|
|
|
|
console.log(foo(c));
|
|
"###,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6039_1() {
|
|
run_default_exec_test(
|
|
r###"
|
|
function foo() {
|
|
let walker = 0;
|
|
|
|
let arr = [];
|
|
|
|
function bar(defaultValue) {
|
|
const myIndex = walker;
|
|
walker += 1;
|
|
|
|
console.log({ arr });
|
|
|
|
if (arr.length < myIndex + 1) {
|
|
arr[myIndex] = defaultValue;
|
|
}
|
|
}
|
|
|
|
return bar;
|
|
}
|
|
|
|
const bar = foo();
|
|
|
|
bar(null);
|
|
bar(null);
|
|
bar(null);
|
|
bar(null);
|
|
bar(null);
|
|
"###,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6039_2() {
|
|
run_default_exec_test(
|
|
r###"
|
|
var foo = function foo() {
|
|
var walker = 0;
|
|
var arr = [];
|
|
function bar(defaultValue) {
|
|
var myIndex = walker;
|
|
walker += 1;
|
|
console.log({
|
|
arr: arr
|
|
});
|
|
if (arr.length < myIndex + 1) {
|
|
arr[myIndex] = defaultValue;
|
|
}
|
|
}
|
|
return bar;
|
|
};
|
|
var bar = foo();
|
|
bar(null);
|
|
bar(null);
|
|
bar(null);
|
|
bar(null);
|
|
bar(null);
|
|
"###,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6217_1() {
|
|
run_exec_test(
|
|
r###"
|
|
var foo = function foo() {
|
|
var walker = 0;
|
|
var arr = [];
|
|
function bar(defaultValue) {
|
|
var myIndex = walker;
|
|
walker += 1;
|
|
console.log({
|
|
arr: arr
|
|
});
|
|
if (arr.length < myIndex + 1) {
|
|
arr[myIndex] = defaultValue;
|
|
}
|
|
}
|
|
return bar;
|
|
};
|
|
var bar = foo();
|
|
bar(null);
|
|
bar(null);
|
|
bar(null);
|
|
bar(null);
|
|
bar(null);
|
|
"###,
|
|
r###"
|
|
{
|
|
"arguments": false,
|
|
"arrows": false,
|
|
"booleans": false,
|
|
"booleans_as_integers": false,
|
|
"collapse_vars": true,
|
|
"comparisons": false,
|
|
"computed_props": false,
|
|
"conditionals": false,
|
|
"dead_code": false,
|
|
"directives": false,
|
|
"drop_console": false,
|
|
"drop_debugger": false,
|
|
"evaluate": false,
|
|
"expression": false,
|
|
"hoist_funs": false,
|
|
"hoist_props": false,
|
|
"hoist_vars": false,
|
|
"if_return": false,
|
|
"join_vars": false,
|
|
"keep_classnames": false,
|
|
"keep_fargs": false,
|
|
"keep_fnames": false,
|
|
"keep_infinity": false,
|
|
"loops": false,
|
|
"negate_iife": false,
|
|
"properties": false,
|
|
"reduce_funcs": false,
|
|
"reduce_vars": false,
|
|
"side_effects": false,
|
|
"switches": false,
|
|
"typeofs": false,
|
|
"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": false,
|
|
"const_to_let": false,
|
|
"pristine_globals": false
|
|
}
|
|
"###,
|
|
false,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6279_1() {
|
|
run_default_exec_test(
|
|
r###"
|
|
function run(str, r) {
|
|
let m
|
|
while(m = r.exec(str)) {
|
|
console.log(m)
|
|
}
|
|
}
|
|
run('abcda', /a/g)
|
|
"###,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6279_2() {
|
|
run_default_exec_test(
|
|
r###"
|
|
const r = new RegExp('a', 'g');
|
|
function run(str, r) {
|
|
let m
|
|
while (m = r.exec(str)) {
|
|
console.log(m)
|
|
}
|
|
}
|
|
run('abcda', r)
|
|
"###,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6463_1() {
|
|
run_default_exec_test(
|
|
r###"
|
|
var foo_1 = foo;
|
|
|
|
function foo() {
|
|
console.log("foo");
|
|
}
|
|
|
|
foo_1();
|
|
foo_1();
|
|
"###,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6528() {
|
|
run_default_exec_test(
|
|
r###"
|
|
const foo = {
|
|
"+1": 1,
|
|
"2": 2,
|
|
"-3": 3,
|
|
}
|
|
|
|
console.log(foo[1]);
|
|
console.log(foo["+1"]);
|
|
console.log(foo["2"]);
|
|
console.log(foo[2]);
|
|
console.log(foo[-3]);
|
|
console.log(foo["-3"]);
|
|
"###,
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6641() {
|
|
run_default_exec_test(
|
|
r###"
|
|
const iota = (i => () => 1 << ++i)(-1);
|
|
|
|
const a = iota(), b = iota();
|
|
|
|
console.log(a, b);
|
|
"###,
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6728() {
|
|
run_default_exec_test(
|
|
r###"
|
|
async function foo() {
|
|
if (undefined_var_1) {
|
|
let replace;
|
|
|
|
if (undefined_var_2) {
|
|
replace = 1;
|
|
} else {
|
|
replace = 2;
|
|
}
|
|
|
|
await a({ replace })
|
|
}
|
|
}
|
|
console.log('PASS')
|
|
"###,
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6750_1() {
|
|
run_default_exec_test(
|
|
r###"
|
|
let current_component;
|
|
|
|
function set_current_component(component) {
|
|
current_component = component;
|
|
}
|
|
|
|
function f(component) {
|
|
const parent = current_component
|
|
set_current_component(component)
|
|
parent.m()
|
|
}
|
|
|
|
const obj = {
|
|
m() {
|
|
console.log("call m()")
|
|
}
|
|
}
|
|
|
|
try {
|
|
f(obj)
|
|
} catch (e) {
|
|
console.log('PASS')
|
|
}
|
|
"###,
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6750_2() {
|
|
run_exec_test(
|
|
r###"
|
|
let current_component;
|
|
|
|
function set_current_component(component) {
|
|
current_component = component;
|
|
}
|
|
|
|
function f(component) {
|
|
const parent = current_component
|
|
set_current_component(component)
|
|
parent.m()
|
|
}
|
|
|
|
const obj = {
|
|
m() {
|
|
console.log("call m()")
|
|
}
|
|
}
|
|
|
|
try {
|
|
f(obj)
|
|
} catch (e) {
|
|
console.log('PASS')
|
|
}
|
|
"###,
|
|
r###"{
|
|
"defaults": true,
|
|
"sequences": false
|
|
}"###,
|
|
false,
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6899_1() {
|
|
run_exec_test(
|
|
r###"
|
|
// this the original code, just for comparison
|
|
function Limit(min, max) {
|
|
var length = Math.abs(min - max);
|
|
|
|
function reachedMin(n) {
|
|
return n < min;
|
|
}
|
|
|
|
function reachedMax(n) {
|
|
return n > max;
|
|
}
|
|
|
|
function reachedAny(n) {
|
|
return reachedMin(n) || reachedMax(n);
|
|
}
|
|
|
|
function constrain(n) {
|
|
if (!reachedAny(n)) return n;
|
|
return reachedMin(n) ? min : max;
|
|
}
|
|
|
|
function removeOffset(n) {
|
|
if (!length) return n;
|
|
return n - length * Math.ceil((n - max) / length);
|
|
}
|
|
|
|
var self = {
|
|
length: length,
|
|
max: max,
|
|
min: min,
|
|
constrain: constrain,
|
|
reachedAny: reachedAny,
|
|
reachedMax: reachedMax,
|
|
reachedMin: reachedMin,
|
|
removeOffset: removeOffset
|
|
};
|
|
return self;
|
|
}
|
|
console.log("The result should be 0. And it is:", Limit(0,3).constrain(-1))
|
|
"###,
|
|
r###"
|
|
{
|
|
"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
|
|
}
|
|
"###,
|
|
false,
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6899_2() {
|
|
run_default_exec_test(
|
|
r###"
|
|
// this the original code, just for comparison
|
|
function Limit(min, max) {
|
|
var length = Math.abs(min - max);
|
|
|
|
function reachedMin(n) {
|
|
return n < min;
|
|
}
|
|
|
|
function reachedMax(n) {
|
|
return n > max;
|
|
}
|
|
|
|
function reachedAny(n) {
|
|
return reachedMin(n) || reachedMax(n);
|
|
}
|
|
|
|
function constrain(n) {
|
|
if (!reachedAny(n)) return n;
|
|
return reachedMin(n) ? min : max;
|
|
}
|
|
|
|
function removeOffset(n) {
|
|
if (!length) return n;
|
|
return n - length * Math.ceil((n - max) / length);
|
|
}
|
|
|
|
var self = {
|
|
length: length,
|
|
max: max,
|
|
min: min,
|
|
constrain: constrain,
|
|
reachedAny: reachedAny,
|
|
reachedMax: reachedMax,
|
|
reachedMin: reachedMin,
|
|
removeOffset: removeOffset
|
|
};
|
|
return self;
|
|
}
|
|
console.log("The result should be 0. And it is:", Limit(0,3).constrain(-1))
|
|
"###,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6899_3() {
|
|
run_default_exec_test(
|
|
r###"
|
|
console.log("The result should be 0. And it is:", function(n, e) {
|
|
var r = Math.abs(n - e);
|
|
|
|
function t(e) {
|
|
return e < n
|
|
}
|
|
|
|
function u(n) {
|
|
return n > e
|
|
}
|
|
|
|
function c(n) {
|
|
return t(n) || u(n)
|
|
}
|
|
return {
|
|
length: r,
|
|
max: e,
|
|
min: n,
|
|
constrain: function(r) {
|
|
return c(r) ? t(r) ? n : e : r
|
|
},
|
|
reachedAny: c,
|
|
reachedMax: u,
|
|
reachedMin: t,
|
|
removeOffset: function(n) {
|
|
return r ? n - r * Math.ceil((n - e) / r) : n
|
|
}
|
|
}
|
|
}(0, 3).constrain(-1));
|
|
|
|
"###,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6899_4() {
|
|
run_exec_test(
|
|
r###"
|
|
console.log("The result should be 0. And it is:", function(n, e) {
|
|
var r = Math.abs(n - e);
|
|
|
|
function t(e) {
|
|
return e < n
|
|
}
|
|
|
|
function u(n) {
|
|
return n > e
|
|
}
|
|
|
|
function c(n) {
|
|
return t(n) || u(n)
|
|
}
|
|
return {
|
|
length: r,
|
|
max: e,
|
|
min: n,
|
|
constrain: function(r) {
|
|
return c(r) ? t(r) ? n : e : r
|
|
},
|
|
reachedAny: c,
|
|
reachedMax: u,
|
|
reachedMin: t,
|
|
removeOffset: function(n) {
|
|
return r ? n - r * Math.ceil((n - e) / r) : n
|
|
}
|
|
}
|
|
}(0, 3).constrain(-1));
|
|
|
|
"###,
|
|
r###"
|
|
{
|
|
"inline": true,
|
|
"passes": 2
|
|
}
|
|
"###,
|
|
false,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6899_5() {
|
|
run_exec_test(
|
|
r###"
|
|
console.log("The result should be 0. And it is:", function(n, e) {
|
|
var r = Math.abs(n - e);
|
|
|
|
function t(e) {
|
|
return e < n
|
|
}
|
|
|
|
function u(n) {
|
|
return n > e
|
|
}
|
|
|
|
function c(n) {
|
|
return t(n) || u(n)
|
|
}
|
|
return {
|
|
constrain: function(r) {
|
|
return c(r) ? (t(r) ? n : e) : r
|
|
},
|
|
|
|
}
|
|
}(0, 3).constrain(-1));
|
|
"###,
|
|
r###"
|
|
{
|
|
"inline": true,
|
|
"passes": 2
|
|
}
|
|
"###,
|
|
false,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6903_1() {
|
|
run_default_exec_test(
|
|
r###"
|
|
function test(a, b) {
|
|
let wrapper = (e) => e
|
|
wrapper = (e) => (["not", e])
|
|
if (a) {
|
|
return wrapper(b)
|
|
}
|
|
return wrapper(1)
|
|
}
|
|
console.log(test(true, "bad"))
|
|
"###,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6903_2() {
|
|
run_exec_test(
|
|
r###"
|
|
function test(a, b) {
|
|
let wrapper = (e) => e
|
|
wrapper = (e) => (["not", e])
|
|
if (a) {
|
|
return wrapper(b)
|
|
}
|
|
return wrapper(1)
|
|
}
|
|
console.log(test(true, "bad"))
|
|
"###,
|
|
r###"
|
|
{
|
|
"if_return": true,
|
|
"join_vars": true,
|
|
"side_effects": true,
|
|
"conditionals": true
|
|
}"###,
|
|
false,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6903_3() {
|
|
run_exec_test(
|
|
r###"
|
|
function test(a, b) {
|
|
let wrapper = (e)=>e;
|
|
return ((wrapper = (e)=>[
|
|
"not",
|
|
e
|
|
]), a) ? wrapper(b) : wrapper(1);
|
|
}
|
|
console.log(test(true, "bad"));
|
|
"###,
|
|
r###"
|
|
{
|
|
"conditionals": true
|
|
}"###,
|
|
false,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6914_1() {
|
|
run_default_exec_test(
|
|
r###"
|
|
console.log(doSomething())
|
|
|
|
function doSomething() {
|
|
return fabricateEvent()
|
|
}
|
|
|
|
function fabricateEvent() {
|
|
let def = createEventDef()
|
|
|
|
return {
|
|
def,
|
|
ui: compileEventUi(def),
|
|
}
|
|
}
|
|
|
|
function compileEventUi(def) {
|
|
let uis = []
|
|
uis.push(def.ui)
|
|
return uis
|
|
}
|
|
|
|
function createEventDef() {
|
|
return {
|
|
id: 'fakeId',
|
|
ui: 'something'
|
|
}
|
|
}
|
|
"###,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6914_2() {
|
|
run_exec_test(
|
|
r###"
|
|
console.log(doSomething())
|
|
|
|
function doSomething() {
|
|
return fabricateEvent()
|
|
}
|
|
|
|
function fabricateEvent() {
|
|
let def = createEventDef()
|
|
|
|
return {
|
|
def,
|
|
ui: compileEventUi(def),
|
|
}
|
|
}
|
|
|
|
function compileEventUi(def) {
|
|
let uis = []
|
|
uis.push(def.ui)
|
|
return uis
|
|
}
|
|
|
|
function createEventDef() {
|
|
return {
|
|
id: 'fakeId',
|
|
ui: 'something'
|
|
}
|
|
}
|
|
"###,
|
|
r###"
|
|
{
|
|
"inline": true,
|
|
"toplevel": true
|
|
}
|
|
"###,
|
|
false,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6914_3() {
|
|
run_exec_test(
|
|
r###"
|
|
console.log(function() {
|
|
return function() {
|
|
let def = function() {
|
|
return {
|
|
id: 'fakeId',
|
|
ui: 'something'
|
|
};
|
|
}();
|
|
return {
|
|
def,
|
|
ui: function(def) {
|
|
let uis = [];
|
|
uis.push(def.ui);
|
|
return uis;
|
|
}(def)
|
|
};
|
|
}();
|
|
}());
|
|
"###,
|
|
r###"
|
|
{
|
|
"inline": true,
|
|
"toplevel": true
|
|
}
|
|
"###,
|
|
false,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_7274() {
|
|
run_default_exec_test(
|
|
r###"
|
|
if (
|
|
// incorrect:
|
|
"😋📋👌".length === 3
|
|
|
|
// correct:
|
|
// "😋📋👌".length === 6
|
|
) {
|
|
// side effect
|
|
new Response(123);
|
|
}
|
|
console.log('PASS');
|
|
"###,
|
|
);
|
|
}
|