From 23ec215401b912d7553f2c7fb7660b92777d605f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Sat, 9 Jul 2016 21:07:48 +0100 Subject: [PATCH] extend the --define (global_defs) option by allowing dotted and square-bracket syntax --- README.md | 6 ++++- lib/compress.js | 50 ++++++++++++++++++++++++++++++++++++++ test/compress/deep-defs.js | 24 ++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 test/compress/deep-defs.js diff --git a/README.md b/README.md index 3245d404..d1a4ae97 100644 --- a/README.md +++ b/README.md @@ -413,6 +413,9 @@ if (DEBUG) { } ``` +You can also define properties nested in other objects. For example, +`--define 'process.env["NODE_ENV"]="production"` also works. + UglifyJS will warn about the condition being always false and about dropping unreachable code; for now there is no option to turn off only this specific warning, you can pass `warnings=false` to turn off *all* warnings. @@ -448,7 +451,8 @@ uglifyJS.minify([ "input.js"], { compress: { dead_code: true, global_defs: { - DEBUG: false + DEBUG: false, + "process.platform": "uglifyjs", } } }); diff --git a/lib/compress.js b/lib/compress.js index f0f3d09b..8568e48d 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -82,6 +82,20 @@ function Compressor(options, false_by_default) { var sequences = this.options["sequences"]; this.sequences_limit = sequences == 1 ? 200 : sequences | 0; this.warnings_produced = {}; + var defines = this.options["global_defs"] || {}; + var deep_definitions; + for (var key in defines) if (HOP(defines, key)) { + if (/[\.\[\s]/.test(key)) { + deep_definitions = deep_definitions || []; + var parsed = parse(key, { expression: true }); + if (!(parsed instanceof AST_PropAccess)) { + throw new Error('Could not define ' + key); + } + deep_definitions.push([ parsed, defines[key] ]); + delete defines[key]; + } + } + this.deep_definitions = deep_definitions; }; Compressor.prototype = new TreeTransformer; @@ -2852,7 +2866,41 @@ merge(Compressor.prototype, { return self; }); + function find_deep_global_definition(self, compressor) { + if (!compressor.deep_definitions) { return; } + for (var i = 0; i < compressor.deep_definitions.length; i++) { + if (find_deep(compressor.deep_definitions[i][0], self)) { + return make_node_from_constant(compressor, compressor.deep_definitions[i][1], self); + } + } + function find_deep(definition, node) { + if (node instanceof AST_SymbolRef || definition instanceof AST_SymbolRef) { + return ( + node instanceof AST_SymbolRef && + definition instanceof AST_SymbolRef && + node.name === definition.name && + node.undeclared() + ); + } + if ( + node instanceof AST_PropAccess && + property_name(node.property) === property_name(definition.property) + ) { + return find_deep(definition.expression, node.expression); + } + } + function property_name(property) { + if (typeof property === 'string') { return property; } + if (property instanceof AST_Constant) { + return String(property.getValue()); + } + return {}; // Which is different from everything else + } + } + OPT(AST_Sub, function(self, compressor){ + var statically_defined = find_deep_global_definition(self, compressor); + if (statically_defined) { return statically_defined; } var prop = self.property; if (prop instanceof AST_String && compressor.option("properties")) { prop = prop.getValue(); @@ -2873,6 +2921,8 @@ merge(Compressor.prototype, { }); OPT(AST_Dot, function(self, compressor){ + var statically_defined = find_deep_global_definition(self, compressor); + if (statically_defined) { return statically_defined; } var prop = self.property; if (RESERVED_WORDS(prop) && !compressor.option("screw_ie8")) { return make_node(AST_Sub, self, { diff --git a/test/compress/deep-defs.js b/test/compress/deep-defs.js new file mode 100644 index 00000000..9ae5a55d --- /dev/null +++ b/test/compress/deep-defs.js @@ -0,0 +1,24 @@ + +global_defs_works_deeply: { + options = { + global_defs: { + "foo.bar": false, + "window[1]": 0, + "foo.undef": undefined, + }, + }; + input: { + foo.bar; + foo["bar"]; + window[1]; + foo.undef; + } + expect: { + false; + false; + 0; + void 0; + } +} + +