"Fossies" - the Fresh Open Source Software Archive

Member "UglifyJS-3.12.1/bin/uglifyjs" (30 Nov 2020, 19840 Bytes) of package /linux/www/UglifyJS-3.12.1.tar.gz:


As a special service "Fossies" has tried to format the requested text file into HTML format (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "uglifyjs": 3.11.6_vs_3.12.0.

    1 #! /usr/bin/env node
    2 // -*- js -*-
    3 
    4 "use strict";
    5 
    6 require("../tools/exit");
    7 
    8 var fs = require("fs");
    9 var info = require("../package.json");
   10 var path = require("path");
   11 var UglifyJS = require("../tools/node");
   12 
   13 var skip_keys = [ "cname", "inlined", "parent_scope", "scope", "uses_eval", "uses_with" ];
   14 var files = {};
   15 var options = {};
   16 var short_forms = {
   17     b: "beautify",
   18     c: "compress",
   19     d: "define",
   20     e: "enclose",
   21     h: "help",
   22     m: "mangle",
   23     o: "output",
   24     O: "output-opts",
   25     p: "parse",
   26     v: "version",
   27     V: "version",
   28 };
   29 var args = process.argv.slice(2);
   30 var paths = [];
   31 var output, nameCache;
   32 var specified = {};
   33 while (args.length) {
   34     var arg = args.shift();
   35     if (arg[0] != "-") {
   36         paths.push(arg);
   37     } else if (arg == "--") {
   38         paths = paths.concat(args);
   39         break;
   40     } else if (arg[1] == "-") {
   41         process_option(arg.slice(2));
   42     } else [].forEach.call(arg.slice(1), function(letter, index, arg) {
   43         if (!(letter in short_forms)) fatal("invalid option -" + letter);
   44         process_option(short_forms[letter], index + 1 < arg.length);
   45     });
   46 }
   47 
   48 function process_option(name, no_value) {
   49     specified[name] = true;
   50     switch (name) {
   51       case "help":
   52         switch (read_value()) {
   53           case "ast":
   54             print(UglifyJS.describe_ast());
   55             break;
   56           case "options":
   57             var text = [];
   58             var toplevels = [];
   59             var padding = "";
   60             var defaults = UglifyJS.default_options();
   61             for (var name in defaults) {
   62                 var option = defaults[name];
   63                 if (option && typeof option == "object") {
   64                     text.push("--" + ({
   65                         output: "beautify",
   66                         sourceMap: "source-map",
   67                     }[name] || name) + " options:");
   68                     text.push(format_object(option));
   69                     text.push("");
   70                 } else {
   71                     if (padding.length < name.length) padding = Array(name.length + 1).join(" ");
   72                     toplevels.push([ {
   73                         keep_fnames: "keep-fnames",
   74                         nameCache: "name-cache",
   75                     }[name] || name, option ]);
   76                 }
   77             }
   78             toplevels.forEach(function(tokens) {
   79                 text.push("--" + tokens[0] + padding.slice(tokens[0].length - 2) + tokens[1]);
   80             });
   81             print(text.join("\n"));
   82             break;
   83           default:
   84             print([
   85                 "Usage: uglifyjs [files...] [options]",
   86                 "",
   87                 "Options:",
   88                 "  -h, --help                               Print usage information.",
   89                 "                                           `--help options` for details on available options.",
   90                 "  -v, -V, --version                        Print version number.",
   91                 "  -p, --parse <options>                    Specify parser options.",
   92                 "  -c, --compress [options]                 Enable compressor/specify compressor options.",
   93                 "  -m, --mangle [options]                   Mangle names/specify mangler options.",
   94                 "  --mangle-props [options]                 Mangle properties/specify mangler options.",
   95                 "  -b, --beautify [options]                 Beautify output/specify output options.",
   96                 "  -O, --output-opts <options>              Output options (beautify disabled).",
   97                 "  -o, --output <file>                      Output file (default STDOUT).",
   98                 "  --comments [filter]                      Preserve copyright comments in the output.",
   99                 "  --config-file <file>                     Read minify() options from JSON file.",
  100                 "  -d, --define <expr>[=value]              Global definitions.",
  101                 "  -e, --enclose [arg[,...][:value[,...]]]  Embed everything in a big function, with configurable argument(s) & value(s).",
  102                 "  --ie8                                    Support non-standard Internet Explorer 8.",
  103                 "  --keep-fnames                            Do not mangle/drop function names. Useful for code relying on Function.prototype.name.",
  104                 "  --name-cache <file>                      File to hold mangled name mappings.",
  105                 "  --rename                                 Force symbol expansion.",
  106                 "  --no-rename                              Disable symbol expansion.",
  107                 "  --self                                   Build UglifyJS as a library (implies --wrap UglifyJS)",
  108                 "  --source-map [options]                   Enable source map/specify source map options.",
  109                 "  --timings                                Display operations run time on STDERR.",
  110                 "  --toplevel                               Compress and/or mangle variables in toplevel scope.",
  111                 "  --validate                               Perform validation during AST manipulations.",
  112                 "  --verbose                                Print diagnostic messages.",
  113                 "  --warn                                   Print warning messages.",
  114                 "  --webkit                                 Support non-standard Safari/Webkit.",
  115                 "  --wrap <name>                            Embed everything as a function with “exports” corresponding to “name” globally.",
  116                 "  --reduce-test                            Reduce a standalone test case (assumes cloned repository).",
  117             ].join("\n"));
  118         }
  119         process.exit();
  120       case "version":
  121         print(info.name + " " + info.version);
  122         process.exit();
  123       case "config-file":
  124         var config = JSON.parse(read_file(read_value(true)));
  125         if (config.mangle && config.mangle.properties && config.mangle.properties.regex) {
  126             config.mangle.properties.regex = UglifyJS.parse(config.mangle.properties.regex, {
  127                 expression: true,
  128             }).value;
  129         }
  130         for (var key in config) if (!(key in options)) options[key] = config[key];
  131         break;
  132       case "compress":
  133       case "mangle":
  134         options[name] = parse_js(read_value(), options[name]);
  135         break;
  136       case "source-map":
  137         options.sourceMap = parse_js(read_value(), options.sourceMap);
  138         break;
  139       case "enclose":
  140         options[name] = read_value();
  141         break;
  142       case "ie8":
  143       case "timings":
  144       case "toplevel":
  145       case "validate":
  146       case "webkit":
  147         options[name] = true;
  148         break;
  149       case "keep-fnames":
  150         options.keep_fnames = true;
  151         break;
  152       case "wrap":
  153         options[name] = read_value(true);
  154         break;
  155       case "verbose":
  156         options.warnings = "verbose";
  157         break;
  158       case "warn":
  159         if (!options.warnings) options.warnings = true;
  160         break;
  161       case "beautify":
  162         options.output = parse_js(read_value(), options.output);
  163         if (!("beautify" in options.output)) options.output.beautify = true;
  164         break;
  165       case "output-opts":
  166         options.output = parse_js(read_value(true), options.output);
  167         break;
  168       case "comments":
  169         if (typeof options.output != "object") options.output = {};
  170         options.output.comments = read_value();
  171         if (options.output.comments === true) options.output.comments = "some";
  172         break;
  173       case "define":
  174         if (typeof options.compress != "object") options.compress = {};
  175         options.compress.global_defs = parse_js(read_value(true), options.compress.global_defs, "define");
  176         break;
  177       case "mangle-props":
  178         if (typeof options.mangle != "object") options.mangle = {};
  179         options.mangle.properties = parse_js(read_value(), options.mangle.properties);
  180         break;
  181       case "name-cache":
  182         nameCache = read_value(true);
  183         options.nameCache = JSON.parse(read_file(nameCache, "{}"));
  184         break;
  185       case "output":
  186         output = read_value(true);
  187         break;
  188       case "parse":
  189         options.parse = parse_js(read_value(true), options.parse);
  190         break;
  191       case "rename":
  192         options.rename = true;
  193         break;
  194       case "no-rename":
  195         options.rename = false;
  196         break;
  197       case "reduce-test":
  198       case "self":
  199         break;
  200       default:
  201         fatal("invalid option --" + name);
  202     }
  203 
  204     function read_value(required) {
  205         if (no_value || !args.length || args[0][0] == "-") {
  206             if (required) fatal("missing option argument for --" + name);
  207             return true;
  208         }
  209         return args.shift();
  210     }
  211 }
  212 if (!output && options.sourceMap && options.sourceMap.url != "inline") fatal("cannot write source map to STDOUT");
  213 if (specified["beautify"] && specified["output-opts"]) fatal("--beautify cannot be used with --output-opts");
  214 [ "compress", "mangle" ].forEach(function(name) {
  215     if (!(name in options)) options[name] = false;
  216 });
  217 if (options.mangle && options.mangle.properties) {
  218     if (options.mangle.properties.domprops) {
  219         delete options.mangle.properties.domprops;
  220     } else {
  221         if (typeof options.mangle.properties != "object") options.mangle.properties = {};
  222         if (!Array.isArray(options.mangle.properties.reserved)) options.mangle.properties.reserved = [];
  223         require("../tools/domprops").forEach(function(name) {
  224             UglifyJS.push_uniq(options.mangle.properties.reserved, name);
  225         });
  226     }
  227 }
  228 if (output == "ast") options.output = {
  229     ast: true,
  230     code: false,
  231 };
  232 if (options.parse && (options.parse.acorn || options.parse.spidermonkey)
  233     && options.sourceMap && options.sourceMap.content == "inline") {
  234     fatal("inline source map only works with built-in parser");
  235 }
  236 if (options.warnings) {
  237     UglifyJS.AST_Node.log_function(print_error, options.warnings == "verbose");
  238     delete options.warnings;
  239 }
  240 var convert_path = function(name) {
  241     return name;
  242 };
  243 if (typeof options.sourceMap == "object" && "base" in options.sourceMap) {
  244     convert_path = function() {
  245         var base = options.sourceMap.base;
  246         delete options.sourceMap.base;
  247         return function(name) {
  248             return path.relative(base, name);
  249         };
  250     }();
  251 }
  252 if (specified["self"]) {
  253     if (paths.length) UglifyJS.AST_Node.warn("Ignoring input files since --self was passed");
  254     if (!options.wrap) options.wrap = "UglifyJS";
  255     paths = UglifyJS.FILES;
  256 }
  257 if (paths.length) {
  258     simple_glob(paths).forEach(function(name) {
  259         files[convert_path(name)] = read_file(name);
  260     });
  261     run();
  262 } else {
  263     var chunks = [];
  264     process.stdin.setEncoding("utf8");
  265     process.stdin.on("data", function(chunk) {
  266         chunks.push(chunk);
  267     }).on("end", function() {
  268         files = [ chunks.join("") ];
  269         run();
  270     });
  271     process.stdin.resume();
  272 }
  273 
  274 function convert_ast(fn) {
  275     return UglifyJS.AST_Node.from_mozilla_ast(Object.keys(files).reduce(fn, null));
  276 }
  277 
  278 function run() {
  279     var content = options.sourceMap && options.sourceMap.content;
  280     if (content && content != "inline") {
  281         UglifyJS.AST_Node.info("Using input source map: {content}", {
  282             content : content,
  283         });
  284         options.sourceMap.content = read_file(content, content);
  285     }
  286     try {
  287         if (options.parse) {
  288             if (options.parse.acorn) {
  289                 files = convert_ast(function(toplevel, name) {
  290                     return require("acorn").parse(files[name], {
  291                         locations: true,
  292                         program: toplevel,
  293                         sourceFile: name
  294                     });
  295                 });
  296             } else if (options.parse.spidermonkey) {
  297                 files = convert_ast(function(toplevel, name) {
  298                     var obj = JSON.parse(files[name]);
  299                     if (!toplevel) return obj;
  300                     toplevel.body = toplevel.body.concat(obj.body);
  301                     return toplevel;
  302                 });
  303             }
  304         }
  305     } catch (ex) {
  306         fatal(ex);
  307     }
  308     var result;
  309     if (specified["reduce-test"]) {
  310         // load on demand - assumes cloned repository
  311         var reduce_test = require("../test/reduce");
  312         if (Object.keys(files).length != 1) fatal("can only test on a single file");
  313         result = reduce_test(files[Object.keys(files)[0]], options, {
  314             log: print_error,
  315             verbose: true,
  316         });
  317     } else {
  318         result = UglifyJS.minify(files, options);
  319     }
  320     if (result.error) {
  321         var ex = result.error;
  322         if (ex.name == "SyntaxError") {
  323             print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col);
  324             var file = files[ex.filename];
  325             if (file) {
  326                 var col = ex.col;
  327                 var lines = file.split(/\r?\n/);
  328                 var line = lines[ex.line - 1];
  329                 if (!line && !col) {
  330                     line = lines[ex.line - 2];
  331                     col = line.length;
  332                 }
  333                 if (line) {
  334                     var limit = 70;
  335                     if (col > limit) {
  336                         line = line.slice(col - limit);
  337                         col = limit;
  338                     }
  339                     print_error(line.slice(0, 80));
  340                     print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
  341                 }
  342             }
  343         } else if (ex.defs) {
  344             print_error("Supported options:");
  345             print_error(format_object(ex.defs));
  346         }
  347         fatal(ex);
  348     } else if (output == "ast") {
  349         if (!options.compress && !options.mangle) {
  350             var toplevel = result.ast;
  351             if (!(toplevel instanceof UglifyJS.AST_Toplevel)) {
  352                 if (!(toplevel instanceof UglifyJS.AST_Statement)) toplevel = new UglifyJS.AST_SimpleStatement({
  353                     body: toplevel,
  354                 });
  355                 toplevel = new UglifyJS.AST_Toplevel({
  356                     body: [ toplevel ],
  357                 });
  358             }
  359             toplevel.figure_out_scope({});
  360         }
  361         print(JSON.stringify(result.ast, function(key, value) {
  362             if (value) switch (key) {
  363               case "thedef":
  364                 return symdef(value);
  365               case "enclosed":
  366                 return value.length ? value.map(symdef) : undefined;
  367               case "variables":
  368               case "functions":
  369               case "globals":
  370                 return value.size() ? value.map(symdef) : undefined;
  371             }
  372             if (skip_key(key)) return;
  373             if (value instanceof UglifyJS.AST_Token) return;
  374             if (value instanceof UglifyJS.Dictionary) return;
  375             if (value instanceof UglifyJS.AST_Node) {
  376                 var result = {
  377                     _class: "AST_" + value.TYPE
  378                 };
  379                 value.CTOR.PROPS.forEach(function(prop) {
  380                     result[prop] = value[prop];
  381                 });
  382                 return result;
  383             }
  384             return value;
  385         }, 2));
  386     } else if (output == "spidermonkey") {
  387         print(JSON.stringify(UglifyJS.minify(result.code, {
  388             compress: false,
  389             mangle: false,
  390             output: {
  391                 ast: true,
  392                 code: false
  393             },
  394         }).ast.to_mozilla_ast(), null, 2));
  395     } else if (output) {
  396         fs.writeFileSync(output, result.code);
  397         if (result.map) fs.writeFileSync(output + ".map", result.map);
  398     } else {
  399         print(result.code);
  400     }
  401     if (nameCache) fs.writeFileSync(nameCache, JSON.stringify(options.nameCache));
  402     if (result.timings) for (var phase in result.timings) {
  403         print_error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s");
  404     }
  405 }
  406 
  407 function fatal(message) {
  408     if (message instanceof Error) {
  409         message = message.stack.replace(/^\S*?Error:/, "ERROR:")
  410     } else {
  411         message = "ERROR: " + message;
  412     }
  413     print_error(message);
  414     process.exit(1);
  415 }
  416 
  417 // A file glob function that only supports "*" and "?" wildcards in the basename.
  418 // Example: "foo/bar/*baz??.*.js"
  419 // Argument `glob` may be a string or an array of strings.
  420 // Returns an array of strings. Garbage in, garbage out.
  421 function simple_glob(glob) {
  422     if (Array.isArray(glob)) {
  423         return [].concat.apply([], glob.map(simple_glob));
  424     }
  425     if (glob.match(/\*|\?/)) {
  426         var dir = path.dirname(glob);
  427         try {
  428             var entries = fs.readdirSync(dir);
  429         } catch (ex) {}
  430         if (entries) {
  431             var pattern = "^" + path.basename(glob)
  432                 .replace(/[.+^$[\]\\(){}]/g, "\\$&")
  433                 .replace(/\*/g, "[^/\\\\]*")
  434                 .replace(/\?/g, "[^/\\\\]") + "$";
  435             var mod = process.platform === "win32" ? "i" : "";
  436             var rx = new RegExp(pattern, mod);
  437             var results = entries.sort().filter(function(name) {
  438                 return rx.test(name);
  439             }).map(function(name) {
  440                 return path.join(dir, name);
  441             });
  442             if (results.length) return results;
  443         }
  444     }
  445     return [ glob ];
  446 }
  447 
  448 function read_file(path, default_value) {
  449     try {
  450         return fs.readFileSync(path, "utf8");
  451     } catch (ex) {
  452         if (ex.code == "ENOENT" && default_value != null) return default_value;
  453         fatal(ex);
  454     }
  455 }
  456 
  457 function parse_js(value, options, flag) {
  458     if (!options || typeof options != "object") options = {};
  459     if (typeof value == "string") try {
  460         UglifyJS.parse(value, {
  461             expression: true
  462         }).walk(new UglifyJS.TreeWalker(function(node) {
  463             if (node instanceof UglifyJS.AST_Assign) {
  464                 var name = node.left.print_to_string();
  465                 var value = node.right;
  466                 if (flag) {
  467                     options[name] = value;
  468                 } else if (value instanceof UglifyJS.AST_Array) {
  469                     options[name] = value.elements.map(to_string);
  470                 } else {
  471                     options[name] = to_string(value);
  472                 }
  473                 return true;
  474             }
  475             if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_PropAccess) {
  476                 var name = node.print_to_string();
  477                 options[name] = true;
  478                 return true;
  479             }
  480             if (!(node instanceof UglifyJS.AST_Sequence)) throw node;
  481 
  482             function to_string(value) {
  483                 return value instanceof UglifyJS.AST_Constant ? value.value : value.print_to_string({
  484                     quote_keys: true
  485                 });
  486             }
  487         }));
  488     } catch (ex) {
  489         if (flag) {
  490             fatal("cannot parse arguments for '" + flag + "': " + value);
  491         } else {
  492             options[value] = null;
  493         }
  494     }
  495     return options;
  496 }
  497 
  498 function skip_key(key) {
  499     return skip_keys.indexOf(key) >= 0;
  500 }
  501 
  502 function symdef(def) {
  503     var ret = (1e6 + def.id) + " " + def.name;
  504     if (def.mangled_name) ret += " " + def.mangled_name;
  505     return ret;
  506 }
  507 
  508 function format_object(obj) {
  509     var lines = [];
  510     var padding = "";
  511     Object.keys(obj).map(function(name) {
  512         if (padding.length < name.length) padding = Array(name.length + 1).join(" ");
  513         return [ name, JSON.stringify(obj[name]) ];
  514     }).forEach(function(tokens) {
  515         lines.push("  " + tokens[0] + padding.slice(tokens[0].length - 2) + tokens[1]);
  516     });
  517     return lines.join("\n");
  518 }
  519 
  520 function print_error(msg) {
  521     process.stderr.write(msg);
  522     process.stderr.write("\n");
  523 }
  524 
  525 function print(txt) {
  526     process.stdout.write(txt);
  527     process.stdout.write("\n");
  528 }