re-introduce `enclose` (#3163)
authorJiavan <jiavan.com@gmail.com>
Fri, 1 Jun 2018 08:47:11 +0000 (16:47 +0800)
committerAlex Lam S.L <alexlamsl@gmail.com>
Fri, 1 Jun 2018 08:47:11 +0000 (16:47 +0800)
fixes #2443

README.md
bin/uglifyjs
lib/ast.js
lib/minify.js
test/input/enclose/input.js [new file with mode: 0644]
test/mocha/cli.js
test/mocha/minify.js

index 6d1cdf8..663ce7b 100644 (file)
--- a/README.md
+++ b/README.md
@@ -104,6 +104,8 @@ a double dash to prevent input files being used as option arguments:
                                 sequences.
     --config-file <file>        Read `minify()` options from JSON file.
     -d, --define <expr>[=value] Global definitions.
+    -e, --enclose [arg[:value]] Embed everything in a big function, with configurable
+                                argument(s) & value(s).
     --ie8                       Support non-standard Internet Explorer 8.
                                 Equivalent to setting `ie8: true` in `minify()`
                                 for `compress`, `mangle` and `output` options.
index 7617d78..fb6ae2f 100755 (executable)
@@ -40,6 +40,7 @@ program.option("-o, --output <file>", "Output file (default STDOUT).");
 program.option("--comments [filter]", "Preserve copyright comments in the output.");
 program.option("--config-file <file>", "Read minify() options from JSON file.");
 program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
+program.option("-e, --enclose [arg[,...][:value[,...]]]", "Embed everything in a big function, with configurable argument(s) & value(s).");
 program.option("--ie8", "Support non-standard Internet Explorer 8.");
 program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
 program.option("--name-cache <file>", "File to hold mangled name mappings.");
@@ -47,7 +48,7 @@ program.option("--rename", "Force symbol expansion.");
 program.option("--no-rename", "Disable symbol expansion.");
 program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)");
 program.option("--source-map [options]", "Enable source map/specify source map options.", parse_js());
-program.option("--timings", "Display operations run time on STDERR.")
+program.option("--timings", "Display operations run time on STDERR.");
 program.option("--toplevel", "Compress and/or mangle variables in toplevel scope.");
 program.option("--verbose", "Print diagnostic messages.");
 program.option("--warn", "Print warning messages.");
@@ -61,6 +62,7 @@ if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
 }
 [
     "compress",
+    "enclose",
     "ie8",
     "mangle",
     "sourceMap",
index 331d340..1a77a59 100644 (file)
@@ -335,6 +335,23 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
             }
         }));
         return wrapped_tl;
+    },
+    wrap_enclose: function(args_values) {
+        if (typeof args_values != "string") args_values = "";
+        var index = args_values.indexOf(":");
+        if (index < 0) index = args_values.length;
+        var body = this.body;
+        return parse([
+            "(function(",
+            args_values.slice(0, index),
+            '){"$ORIG"})(',
+            args_values.slice(index + 1),
+            ")"
+        ].join("")).transform(new TreeTransformer(function(node) {
+            if (node instanceof AST_Directive && node.value == "$ORIG") {
+                return MAP.splice(body);
+            }
+        }));
     }
 }, AST_Scope);
 
index 399b861..d84f682 100644 (file)
@@ -55,6 +55,7 @@ function minify(files, options) {
     try {
         options = defaults(options, {
             compress: {},
+            enclose: false,
             ie8: false,
             keep_fnames: false,
             mangle: {},
@@ -157,6 +158,9 @@ function minify(files, options) {
         if (options.wrap) {
             toplevel = toplevel.wrap_commonjs(options.wrap);
         }
+        if (options.enclose) {
+            toplevel = toplevel.wrap_enclose(options.enclose);
+        }
         if (timings) timings.rename = Date.now();
         if (options.rename) {
             toplevel.figure_out_scope(options.mangle);
diff --git a/test/input/enclose/input.js b/test/input/enclose/input.js
new file mode 100644 (file)
index 0000000..5f53997
--- /dev/null
@@ -0,0 +1,4 @@
+function enclose() {
+    console.log("test enclose");
+}
+enclose();
index 3b3dcab..2e1c3b6 100644 (file)
@@ -6,7 +6,7 @@ function read(path) {
     return fs.readFileSync(path, "utf8");
 }
 
-describe("bin/uglifyjs", function () {
+describe("bin/uglifyjs", function() {
     var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
     it("should produce a functional build when using --self", function (done) {
         this.timeout(30000);
@@ -744,4 +744,36 @@ describe("bin/uglifyjs", function () {
             done();
         });
     });
+    it("Should work with --enclose", function(done) {
+        var command = uglifyjscmd + " test/input/enclose/input.js --enclose";
+        exec(command, function(err, stdout, stderr) {
+            if (err) throw err;
+            assert.strictEqual(stdout, '(function(){function enclose(){console.log("test enclose")}enclose()})();\n');
+            done();
+        });
+    });
+    it("Should work with --enclose arg", function(done) {
+        var command = uglifyjscmd + " test/input/enclose/input.js --enclose undefined";
+        exec(command, function(err, stdout, stderr) {
+            if (err) throw err;
+            assert.strictEqual(stdout, '(function(undefined){function enclose(){console.log("test enclose")}enclose()})();\n');
+            done();
+        });
+    });
+    it("Should work with --enclose arg:value", function(done) {
+        var command = uglifyjscmd + " test/input/enclose/input.js --enclose window,undefined:window";
+        exec(command, function(err, stdout, stderr) {
+            if (err) throw err;
+            assert.strictEqual(stdout, '(function(window,undefined){function enclose(){console.log("test enclose")}enclose()})(window);\n');
+            done();
+        });
+    });
+    it("Should work with --enclose & --wrap", function(done) {
+        var command = uglifyjscmd + " test/input/enclose/input.js --enclose window,undefined:window --wrap exports";
+        exec(command, function(err, stdout, stderr) {
+            if (err) throw err;
+            assert.strictEqual(stdout, '(function(window,undefined){(function(exports){function enclose(){console.log("test enclose")}enclose()})(typeof exports=="undefined"?exports={}:exports)})(window);\n');
+            done();
+        });
+    });
 });
index c8c1777..f394cc6 100644 (file)
@@ -303,4 +303,45 @@ describe("minify", function() {
             }
         });
     });
+
+    describe("enclose", function() {
+        var code = read("test/input/enclose/input.js");
+        it("Should work with true", function() {
+            var result = Uglify.minify(code, {
+                compress: false,
+                enclose: true,
+                mangle: false,
+            });
+            if (result.error) throw result.error;
+            assert.strictEqual(result.code, '(function(){function enclose(){console.log("test enclose")}enclose()})();');
+        });
+        it("Should work with arg", function() {
+            var result = Uglify.minify(code, {
+                compress: false,
+                enclose: 'undefined',
+                mangle: false,
+            });
+            if (result.error) throw result.error;
+            assert.strictEqual(result.code, '(function(undefined){function enclose(){console.log("test enclose")}enclose()})();');
+        });
+        it("Should work with arg:value", function() {
+            var result = Uglify.minify(code, {
+                compress: false,
+                enclose: 'window,undefined:window',
+                mangle: false,
+            });
+            if (result.error) throw result.error;
+            assert.strictEqual(result.code, '(function(window,undefined){function enclose(){console.log("test enclose")}enclose()})(window);');
+        });
+        it("Should work alongside wrap", function() {
+            var result = Uglify.minify(code, {
+                compress: false,
+                enclose: 'window,undefined:window',
+                mangle: false,
+                wrap: 'exports',
+            });
+            if (result.error) throw result.error;
+            assert.strictEqual(result.code, '(function(window,undefined){(function(exports){function enclose(){console.log("test enclose")}enclose()})(typeof exports=="undefined"?exports={}:exports)})(window);');
+        });
+    });
 });