You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							605 lines
						
					
					
						
							23 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							605 lines
						
					
					
						
							23 KiB
						
					
					
				
								#! /usr/bin/env node
							 | 
						|
								// -*- js -*-
							 | 
						|
								
							 | 
						|
								"use strict";
							 | 
						|
								
							 | 
						|
								require("../tools/tty");
							 | 
						|
								
							 | 
						|
								var fs = require("fs");
							 | 
						|
								var info = require("../package.json");
							 | 
						|
								var path = require("path");
							 | 
						|
								var UglifyJS = require("../tools/node");
							 | 
						|
								
							 | 
						|
								var skip_keys = [ "cname", "fixed", "in_arg", "inlined", "length_read", "parent_scope", "redef", "scope", "unused" ];
							 | 
						|
								var truthy_keys = [ "optional", "pure", "terminal", "uses_arguments", "uses_eval", "uses_with" ];
							 | 
						|
								
							 | 
						|
								var files = {};
							 | 
						|
								var options = {};
							 | 
						|
								var short_forms = {
							 | 
						|
								    b: "beautify",
							 | 
						|
								    c: "compress",
							 | 
						|
								    d: "define",
							 | 
						|
								    e: "enclose",
							 | 
						|
								    h: "help",
							 | 
						|
								    m: "mangle",
							 | 
						|
								    o: "output",
							 | 
						|
								    O: "output-opts",
							 | 
						|
								    p: "parse",
							 | 
						|
								    v: "version",
							 | 
						|
								    V: "version",
							 | 
						|
								};
							 | 
						|
								var args = process.argv.slice(2);
							 | 
						|
								var paths = [];
							 | 
						|
								var output, nameCache;
							 | 
						|
								var specified = {};
							 | 
						|
								while (args.length) {
							 | 
						|
								    var arg = args.shift();
							 | 
						|
								    if (arg[0] != "-") {
							 | 
						|
								        paths.push(arg);
							 | 
						|
								    } else if (arg == "--") {
							 | 
						|
								        paths = paths.concat(args);
							 | 
						|
								        break;
							 | 
						|
								    } else if (arg[1] == "-") {
							 | 
						|
								        process_option(arg.slice(2));
							 | 
						|
								    } else [].forEach.call(arg.slice(1), function(letter, index, arg) {
							 | 
						|
								        if (!(letter in short_forms)) fatal("invalid option -" + letter);
							 | 
						|
								        process_option(short_forms[letter], index + 1 < arg.length);
							 | 
						|
								    });
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function process_option(name, no_value) {
							 | 
						|
								    specified[name] = true;
							 | 
						|
								    switch (name) {
							 | 
						|
								      case "help":
							 | 
						|
								        switch (read_value()) {
							 | 
						|
								          case "ast":
							 | 
						|
								            print(UglifyJS.describe_ast());
							 | 
						|
								            break;
							 | 
						|
								          case "options":
							 | 
						|
								            var text = [];
							 | 
						|
								            var toplevels = [];
							 | 
						|
								            var padding = "";
							 | 
						|
								            var defaults = UglifyJS.default_options();
							 | 
						|
								            for (var name in defaults) {
							 | 
						|
								                var option = defaults[name];
							 | 
						|
								                if (option && typeof option == "object") {
							 | 
						|
								                    text.push("--" + ({
							 | 
						|
								                        output: "beautify",
							 | 
						|
								                        sourceMap: "source-map",
							 | 
						|
								                    }[name] || name) + " options:");
							 | 
						|
								                    text.push(format_object(option));
							 | 
						|
								                    text.push("");
							 | 
						|
								                } else {
							 | 
						|
								                    if (padding.length < name.length) padding = Array(name.length + 1).join(" ");
							 | 
						|
								                    toplevels.push([ {
							 | 
						|
								                        keep_fargs: "keep-fargs",
							 | 
						|
								                        keep_fnames: "keep-fnames",
							 | 
						|
								                        nameCache: "name-cache",
							 | 
						|
								                    }[name] || name, option ]);
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								            toplevels.forEach(function(tokens) {
							 | 
						|
								                text.push("--" + tokens[0] + padding.slice(tokens[0].length - 2) + tokens[1]);
							 | 
						|
								            });
							 | 
						|
								            print(text.join("\n"));
							 | 
						|
								            break;
							 | 
						|
								          default:
							 | 
						|
								            print([
							 | 
						|
								                "Usage: uglifyjs [files...] [options]",
							 | 
						|
								                "",
							 | 
						|
								                "Options:",
							 | 
						|
								                "  -h, --help                               Print usage information.",
							 | 
						|
								                "                                           `--help options` for details on available options.",
							 | 
						|
								                "  -v, -V, --version                        Print version number.",
							 | 
						|
								                "  -p, --parse <options>                    Specify parser options.",
							 | 
						|
								                "  -c, --compress [options]                 Enable compressor/specify compressor options.",
							 | 
						|
								                "  -m, --mangle [options]                   Mangle names/specify mangler options.",
							 | 
						|
								                "  --mangle-props [options]                 Mangle properties/specify mangler options.",
							 | 
						|
								                "  -b, --beautify [options]                 Beautify output/specify output options.",
							 | 
						|
								                "  -O, --output-opts <options>              Output options (beautify disabled).",
							 | 
						|
								                "  -o, --output <file>                      Output file (default STDOUT).",
							 | 
						|
								                "  --annotations                            Process and preserve comment annotations.",
							 | 
						|
								                "  --no-annotations                         Ignore and discard comment annotations.",
							 | 
						|
								                "  --comments [filter]                      Preserve copyright comments in the output.",
							 | 
						|
								                "  --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).",
							 | 
						|
								                "  --expression                             Parse a single expression, rather than a program.",
							 | 
						|
								                "  --ie                                     Support non-standard Internet Explorer.",
							 | 
						|
								                "  --keep-fargs                             Do not mangle/drop function arguments.",
							 | 
						|
								                "  --keep-fnames                            Do not mangle/drop function names. Useful for code relying on Function.prototype.name.",
							 | 
						|
								                "  --module                                 Process input as ES module (implies --toplevel)",
							 | 
						|
								                "  --name-cache <file>                      File to hold mangled name mappings.",
							 | 
						|
								                "  --rename                                 Force symbol expansion.",
							 | 
						|
								                "  --no-rename                              Disable symbol expansion.",
							 | 
						|
								                "  --self                                   Build UglifyJS as a library (implies --wrap UglifyJS)",
							 | 
						|
								                "  --source-map [options]                   Enable source map/specify source map options.",
							 | 
						|
								                "  --timings                                Display operations run time on STDERR.",
							 | 
						|
								                "  --toplevel                               Compress and/or mangle variables in toplevel scope.",
							 | 
						|
								                "  --v8                                     Support non-standard Chrome & Node.js.",
							 | 
						|
								                "  --validate                               Perform validation during AST manipulations.",
							 | 
						|
								                "  --verbose                                Print diagnostic messages.",
							 | 
						|
								                "  --warn                                   Print warning messages.",
							 | 
						|
								                "  --webkit                                 Support non-standard Safari/Webkit.",
							 | 
						|
								                "  --wrap <name>                            Embed everything as a function with “exports” corresponding to “name” globally.",
							 | 
						|
								                "",
							 | 
						|
								                "(internal debug use only)",
							 | 
						|
								                "  --in-situ                                Warning: replaces original source files with minified output.",
							 | 
						|
								                "  --reduce-test                            Reduce a standalone test case (assumes cloned repository).",
							 | 
						|
								            ].join("\n"));
							 | 
						|
								        }
							 | 
						|
								        process.exit();
							 | 
						|
								      case "version":
							 | 
						|
								        print(info.name + " " + info.version);
							 | 
						|
								        process.exit();
							 | 
						|
								      case "config-file":
							 | 
						|
								        var config = JSON.parse(read_file(read_value(true)));
							 | 
						|
								        if (config.mangle && config.mangle.properties && config.mangle.properties.regex) {
							 | 
						|
								            config.mangle.properties.regex = UglifyJS.parse(config.mangle.properties.regex, {
							 | 
						|
								                expression: true,
							 | 
						|
								            }).value;
							 | 
						|
								        }
							 | 
						|
								        for (var key in config) if (!(key in options)) options[key] = config[key];
							 | 
						|
								        break;
							 | 
						|
								      case "compress":
							 | 
						|
								      case "mangle":
							 | 
						|
								        options[name] = parse_js(read_value(), options[name]);
							 | 
						|
								        break;
							 | 
						|
								      case "source-map":
							 | 
						|
								        options.sourceMap = parse_js(read_value(), options.sourceMap);
							 | 
						|
								        break;
							 | 
						|
								      case "enclose":
							 | 
						|
								        options[name] = read_value();
							 | 
						|
								        break;
							 | 
						|
								      case "annotations":
							 | 
						|
								      case "expression":
							 | 
						|
								      case "ie":
							 | 
						|
								      case "ie8":
							 | 
						|
								      case "module":
							 | 
						|
								      case "timings":
							 | 
						|
								      case "toplevel":
							 | 
						|
								      case "v8":
							 | 
						|
								      case "validate":
							 | 
						|
								      case "webkit":
							 | 
						|
								        options[name] = true;
							 | 
						|
								        break;
							 | 
						|
								      case "no-annotations":
							 | 
						|
								        options.annotations = false;
							 | 
						|
								        break;
							 | 
						|
								      case "keep-fargs":
							 | 
						|
								        options.keep_fargs = true;
							 | 
						|
								        break;
							 | 
						|
								      case "keep-fnames":
							 | 
						|
								        options.keep_fnames = true;
							 | 
						|
								        break;
							 | 
						|
								      case "wrap":
							 | 
						|
								        options[name] = read_value(true);
							 | 
						|
								        break;
							 | 
						|
								      case "verbose":
							 | 
						|
								        options.warnings = "verbose";
							 | 
						|
								        break;
							 | 
						|
								      case "warn":
							 | 
						|
								        if (!options.warnings) options.warnings = true;
							 | 
						|
								        break;
							 | 
						|
								      case "beautify":
							 | 
						|
								        options.output = parse_js(read_value(), options.output);
							 | 
						|
								        if (!("beautify" in options.output)) options.output.beautify = true;
							 | 
						|
								        break;
							 | 
						|
								      case "output-opts":
							 | 
						|
								        options.output = parse_js(read_value(true), options.output);
							 | 
						|
								        break;
							 | 
						|
								      case "comments":
							 | 
						|
								        if (typeof options.output != "object") options.output = {};
							 | 
						|
								        options.output.comments = read_value();
							 | 
						|
								        if (options.output.comments === true) options.output.comments = "some";
							 | 
						|
								        break;
							 | 
						|
								      case "define":
							 | 
						|
								        if (typeof options.compress != "object") options.compress = {};
							 | 
						|
								        options.compress.global_defs = parse_js(read_value(true), options.compress.global_defs, "define");
							 | 
						|
								        break;
							 | 
						|
								      case "mangle-props":
							 | 
						|
								        if (typeof options.mangle != "object") options.mangle = {};
							 | 
						|
								        options.mangle.properties = parse_js(read_value(), options.mangle.properties);
							 | 
						|
								        break;
							 | 
						|
								      case "name-cache":
							 | 
						|
								        nameCache = read_value(true);
							 | 
						|
								        options.nameCache = JSON.parse(read_file(nameCache, "{}"));
							 | 
						|
								        break;
							 | 
						|
								      case "output":
							 | 
						|
								        output = read_value(true);
							 | 
						|
								        break;
							 | 
						|
								      case "parse":
							 | 
						|
								        options.parse = parse_js(read_value(true), options.parse);
							 | 
						|
								        break;
							 | 
						|
								      case "rename":
							 | 
						|
								        options.rename = true;
							 | 
						|
								        break;
							 | 
						|
								      case "no-rename":
							 | 
						|
								        options.rename = false;
							 | 
						|
								        break;
							 | 
						|
								      case "in-situ":
							 | 
						|
								      case "reduce-test":
							 | 
						|
								      case "self":
							 | 
						|
								        break;
							 | 
						|
								      default:
							 | 
						|
								        fatal("invalid option --" + name);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    function read_value(required) {
							 | 
						|
								        if (no_value || !args.length || args[0][0] == "-") {
							 | 
						|
								            if (required) fatal("missing option argument for --" + name);
							 | 
						|
								            return true;
							 | 
						|
								        }
							 | 
						|
								        return args.shift();
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								if (!output && options.sourceMap && options.sourceMap.url != "inline") fatal("cannot write source map to STDOUT");
							 | 
						|
								if (specified["beautify"] && specified["output-opts"]) fatal("--beautify cannot be used with --output-opts");
							 | 
						|
								[ "compress", "mangle" ].forEach(function(name) {
							 | 
						|
								    if (!(name in options)) options[name] = false;
							 | 
						|
								});
							 | 
						|
								if (options.mangle && options.mangle.properties) {
							 | 
						|
								    if (options.mangle.properties.domprops) {
							 | 
						|
								        delete options.mangle.properties.domprops;
							 | 
						|
								    } else {
							 | 
						|
								        if (typeof options.mangle.properties != "object") options.mangle.properties = {};
							 | 
						|
								        if (!Array.isArray(options.mangle.properties.reserved)) options.mangle.properties.reserved = [];
							 | 
						|
								        require("../tools/domprops").forEach(function(name) {
							 | 
						|
								            UglifyJS.push_uniq(options.mangle.properties.reserved, name);
							 | 
						|
								        });
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								if (/^ast|spidermonkey$/.test(output)) {
							 | 
						|
								    if (typeof options.output != "object") options.output = {};
							 | 
						|
								    options.output.ast = true;
							 | 
						|
								    options.output.code = false;
							 | 
						|
								}
							 | 
						|
								if (options.parse && (options.parse.acorn || options.parse.spidermonkey)
							 | 
						|
								    && options.sourceMap && options.sourceMap.content == "inline") {
							 | 
						|
								    fatal("inline source map only works with built-in parser");
							 | 
						|
								}
							 | 
						|
								if (options.warnings) {
							 | 
						|
								    UglifyJS.AST_Node.log_function(print_error, options.warnings == "verbose");
							 | 
						|
								    delete options.warnings;
							 | 
						|
								}
							 | 
						|
								var convert_path = function(name) {
							 | 
						|
								    return name;
							 | 
						|
								};
							 | 
						|
								if (typeof options.sourceMap == "object" && "base" in options.sourceMap) {
							 | 
						|
								    convert_path = function() {
							 | 
						|
								        var base = options.sourceMap.base;
							 | 
						|
								        delete options.sourceMap.base;
							 | 
						|
								        return function(name) {
							 | 
						|
								            return path.relative(base, name);
							 | 
						|
								        };
							 | 
						|
								    }();
							 | 
						|
								}
							 | 
						|
								if (specified["self"]) {
							 | 
						|
								    if (paths.length) UglifyJS.AST_Node.warn("Ignoring input files since --self was passed");
							 | 
						|
								    if (!options.wrap) options.wrap = "UglifyJS";
							 | 
						|
								    paths = UglifyJS.FILES;
							 | 
						|
								}
							 | 
						|
								if (specified["in-situ"]) {
							 | 
						|
								    if (output && output != "spidermonkey" || specified["reduce-test"] || specified["self"]) {
							 | 
						|
								        fatal("incompatible options specified");
							 | 
						|
								    }
							 | 
						|
								    paths.forEach(function(name) {
							 | 
						|
								        print(name);
							 | 
						|
								        if (/^ast|spidermonkey$/.test(name)) fatal("invalid file name specified");
							 | 
						|
								        files = {};
							 | 
						|
								        files[convert_path(name)] = read_file(name);
							 | 
						|
								        output = name;
							 | 
						|
								        run();
							 | 
						|
								    });
							 | 
						|
								} else if (paths.length) {
							 | 
						|
								    simple_glob(paths).forEach(function(name) {
							 | 
						|
								        files[convert_path(name)] = read_file(name);
							 | 
						|
								    });
							 | 
						|
								    run();
							 | 
						|
								} else {
							 | 
						|
								    var timerId = process.stdin.isTTY && process.argv.length < 3 && setTimeout(function() {
							 | 
						|
								        print_error("Waiting for input... (use `--help` to print usage information)");
							 | 
						|
								    }, 1500);
							 | 
						|
								    var chunks = [];
							 | 
						|
								    process.stdin.setEncoding("utf8");
							 | 
						|
								    process.stdin.once("data", function() {
							 | 
						|
								        clearTimeout(timerId);
							 | 
						|
								    }).on("data", function(chunk) {
							 | 
						|
								        chunks.push(chunk);
							 | 
						|
								    }).on("end", function() {
							 | 
						|
								        files = { STDIN: chunks.join("") };
							 | 
						|
								        run();
							 | 
						|
								    });
							 | 
						|
								    process.stdin.resume();
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function convert_ast(fn) {
							 | 
						|
								    return UglifyJS.AST_Node.from_mozilla_ast(Object.keys(files).reduce(fn, null));
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function run() {
							 | 
						|
								    var content = options.sourceMap && options.sourceMap.content;
							 | 
						|
								    if (content && content != "inline") {
							 | 
						|
								        UglifyJS.AST_Node.info("Using input source map: {content}", {
							 | 
						|
								            content : content,
							 | 
						|
								        });
							 | 
						|
								        options.sourceMap.content = read_file(content, content);
							 | 
						|
								    }
							 | 
						|
								    try {
							 | 
						|
								        if (options.parse) {
							 | 
						|
								            if (options.parse.acorn) {
							 | 
						|
								                var annotations = Object.create(null);
							 | 
						|
								                files = convert_ast(function(toplevel, name) {
							 | 
						|
								                    var content = files[name];
							 | 
						|
								                    var list = annotations[name] = [];
							 | 
						|
								                    var prev = -1;
							 | 
						|
								                    return require("acorn").parse(content, {
							 | 
						|
								                        allowHashBang: true,
							 | 
						|
								                        ecmaVersion: "latest",
							 | 
						|
								                        locations: true,
							 | 
						|
								                        onComment: function(block, text, start, end) {
							 | 
						|
								                            var match = /[@#]__PURE__/.exec(text);
							 | 
						|
								                            if (!match) {
							 | 
						|
								                                if (start != prev) return;
							 | 
						|
								                                match = [ list[prev] ];
							 | 
						|
								                            }
							 | 
						|
								                            while (/\s/.test(content[end])) end++;
							 | 
						|
								                            list[end] = match[0];
							 | 
						|
								                            prev = end;
							 | 
						|
								                        },
							 | 
						|
								                        preserveParens: true,
							 | 
						|
								                        program: toplevel,
							 | 
						|
								                        sourceFile: name,
							 | 
						|
								                        sourceType: "module",
							 | 
						|
								                    });
							 | 
						|
								                });
							 | 
						|
								                files.walk(new UglifyJS.TreeWalker(function(node) {
							 | 
						|
								                    if (!(node instanceof UglifyJS.AST_Call)) return;
							 | 
						|
								                    var list = annotations[node.start.file];
							 | 
						|
								                    var pure = list[node.start.pos];
							 | 
						|
								                    if (!pure) {
							 | 
						|
								                        var tokens = node.start.parens;
							 | 
						|
								                        if (tokens) for (var i = 0; !pure && i < tokens.length; i++) {
							 | 
						|
								                            pure = list[tokens[i].pos];
							 | 
						|
								                        }
							 | 
						|
								                    }
							 | 
						|
								                    if (pure) node.pure = pure;
							 | 
						|
								                }));
							 | 
						|
								            } else if (options.parse.spidermonkey) {
							 | 
						|
								                files = convert_ast(function(toplevel, name) {
							 | 
						|
								                    var obj = JSON.parse(files[name]);
							 | 
						|
								                    if (!toplevel) return obj;
							 | 
						|
								                    toplevel.body = toplevel.body.concat(obj.body);
							 | 
						|
								                    return toplevel;
							 | 
						|
								                });
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								    } catch (ex) {
							 | 
						|
								        fatal(ex);
							 | 
						|
								    }
							 | 
						|
								    var result;
							 | 
						|
								    if (specified["reduce-test"]) {
							 | 
						|
								        // load on demand - assumes cloned repository
							 | 
						|
								        var reduce_test = require("../test/reduce");
							 | 
						|
								        if (Object.keys(files).length != 1) fatal("can only test on a single file");
							 | 
						|
								        result = reduce_test(files[Object.keys(files)[0]], options, {
							 | 
						|
								            log: print_error,
							 | 
						|
								            verbose: true,
							 | 
						|
								        });
							 | 
						|
								    } else {
							 | 
						|
								        result = UglifyJS.minify(files, options);
							 | 
						|
								    }
							 | 
						|
								    if (result.error) {
							 | 
						|
								        var ex = result.error;
							 | 
						|
								        if (ex.name == "SyntaxError") {
							 | 
						|
								            print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col);
							 | 
						|
								            var file = files[ex.filename];
							 | 
						|
								            if (file) {
							 | 
						|
								                var col = ex.col;
							 | 
						|
								                var lines = file.split(/\r?\n/);
							 | 
						|
								                var line = lines[ex.line - 1];
							 | 
						|
								                if (!line && !col) {
							 | 
						|
								                    line = lines[ex.line - 2];
							 | 
						|
								                    col = line.length;
							 | 
						|
								                }
							 | 
						|
								                if (line) {
							 | 
						|
								                    var limit = 70;
							 | 
						|
								                    if (col > limit) {
							 | 
						|
								                        line = line.slice(col - limit);
							 | 
						|
								                        col = limit;
							 | 
						|
								                    }
							 | 
						|
								                    print_error(line.slice(0, 80));
							 | 
						|
								                    print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        } else if (ex.defs) {
							 | 
						|
								            print_error("Supported options:");
							 | 
						|
								            print_error(format_object(ex.defs));
							 | 
						|
								        }
							 | 
						|
								        fatal(ex);
							 | 
						|
								    } else if (output == "ast") {
							 | 
						|
								        if (!options.compress && !options.mangle) {
							 | 
						|
								            var toplevel = result.ast;
							 | 
						|
								            if (!(toplevel instanceof UglifyJS.AST_Toplevel)) {
							 | 
						|
								                if (!(toplevel instanceof UglifyJS.AST_Statement)) toplevel = new UglifyJS.AST_SimpleStatement({
							 | 
						|
								                    body: toplevel,
							 | 
						|
								                });
							 | 
						|
								                toplevel = new UglifyJS.AST_Toplevel({
							 | 
						|
								                    body: [ toplevel ],
							 | 
						|
								                });
							 | 
						|
								            }
							 | 
						|
								            toplevel.figure_out_scope({});
							 | 
						|
								        }
							 | 
						|
								        print(JSON.stringify(result.ast, function(key, value) {
							 | 
						|
								            if (value) switch (key) {
							 | 
						|
								              case "enclosed":
							 | 
						|
								                return value.length ? value.map(symdef) : undefined;
							 | 
						|
								              case "functions":
							 | 
						|
								              case "globals":
							 | 
						|
								              case "variables":
							 | 
						|
								                return value.size() ? value.map(symdef) : undefined;
							 | 
						|
								              case "thedef":
							 | 
						|
								                return symdef(value);
							 | 
						|
								            }
							 | 
						|
								            if (skip_property(key, value)) return;
							 | 
						|
								            if (value instanceof UglifyJS.AST_Token) return;
							 | 
						|
								            if (value instanceof UglifyJS.Dictionary) return;
							 | 
						|
								            if (value instanceof UglifyJS.AST_Node) {
							 | 
						|
								                var result = {
							 | 
						|
								                    _class: "AST_" + value.TYPE
							 | 
						|
								                };
							 | 
						|
								                value.CTOR.PROPS.forEach(function(prop) {
							 | 
						|
								                    result[prop] = value[prop];
							 | 
						|
								                });
							 | 
						|
								                return result;
							 | 
						|
								            }
							 | 
						|
								            return value;
							 | 
						|
								        }, 2));
							 | 
						|
								    } else if (output == "spidermonkey") {
							 | 
						|
								        print(JSON.stringify(result.ast.to_mozilla_ast(), null, 2));
							 | 
						|
								    } else if (output) {
							 | 
						|
								        var code;
							 | 
						|
								        if (result.ast) {
							 | 
						|
								            var opts = {};
							 | 
						|
								            for (var name in options.output) {
							 | 
						|
								                if (!/^ast|code$/.test(name)) opts[name] = options.output[name];
							 | 
						|
								            }
							 | 
						|
								            code = UglifyJS.AST_Node.from_mozilla_ast(result.ast.to_mozilla_ast()).print_to_string(opts);
							 | 
						|
								        } else {
							 | 
						|
								            code = result.code;
							 | 
						|
								        }
							 | 
						|
								        fs.writeFileSync(output, code);
							 | 
						|
								        if (result.map) fs.writeFileSync(output + ".map", result.map);
							 | 
						|
								    } else {
							 | 
						|
								        print(result.code);
							 | 
						|
								    }
							 | 
						|
								    if (nameCache) fs.writeFileSync(nameCache, JSON.stringify(options.nameCache));
							 | 
						|
								    if (result.timings) for (var phase in result.timings) {
							 | 
						|
								        print_error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s");
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function fatal(message) {
							 | 
						|
								    if (message instanceof Error) {
							 | 
						|
								        message = message.stack.replace(/^\S*?Error:/, "ERROR:")
							 | 
						|
								    } else {
							 | 
						|
								        message = "ERROR: " + message;
							 | 
						|
								    }
							 | 
						|
								    print_error(message);
							 | 
						|
								    process.exit(1);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// A file glob function that only supports "*" and "?" wildcards in the basename.
							 | 
						|
								// Example: "foo/bar/*baz??.*.js"
							 | 
						|
								// Argument `glob` may be a string or an array of strings.
							 | 
						|
								// Returns an array of strings. Garbage in, garbage out.
							 | 
						|
								function simple_glob(glob) {
							 | 
						|
								    if (Array.isArray(glob)) {
							 | 
						|
								        return [].concat.apply([], glob.map(simple_glob));
							 | 
						|
								    }
							 | 
						|
								    if (glob.match(/\*|\?/)) {
							 | 
						|
								        var dir = path.dirname(glob);
							 | 
						|
								        try {
							 | 
						|
								            var entries = fs.readdirSync(dir);
							 | 
						|
								        } catch (ex) {}
							 | 
						|
								        if (entries) {
							 | 
						|
								            var pattern = "^" + path.basename(glob)
							 | 
						|
								                .replace(/[.+^$[\]\\(){}]/g, "\\$&")
							 | 
						|
								                .replace(/\*/g, "[^/\\\\]*")
							 | 
						|
								                .replace(/\?/g, "[^/\\\\]") + "$";
							 | 
						|
								            var mod = process.platform === "win32" ? "i" : "";
							 | 
						|
								            var rx = new RegExp(pattern, mod);
							 | 
						|
								            var results = entries.sort().filter(function(name) {
							 | 
						|
								                return rx.test(name);
							 | 
						|
								            }).map(function(name) {
							 | 
						|
								                return path.join(dir, name);
							 | 
						|
								            });
							 | 
						|
								            if (results.length) return results;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								    return [ glob ];
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function read_file(path, default_value) {
							 | 
						|
								    try {
							 | 
						|
								        return fs.readFileSync(path, "utf8");
							 | 
						|
								    } catch (ex) {
							 | 
						|
								        if (ex.code == "ENOENT" && default_value != null) return default_value;
							 | 
						|
								        fatal(ex);
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function parse_js(value, options, flag) {
							 | 
						|
								    if (!options || typeof options != "object") options = Object.create(null);
							 | 
						|
								    if (typeof value == "string") try {
							 | 
						|
								        UglifyJS.parse(value, {
							 | 
						|
								            expression: true
							 | 
						|
								        }).walk(new UglifyJS.TreeWalker(function(node) {
							 | 
						|
								            if (node instanceof UglifyJS.AST_Assign) {
							 | 
						|
								                var name = node.left.print_to_string();
							 | 
						|
								                var value = node.right;
							 | 
						|
								                if (flag) {
							 | 
						|
								                    options[name] = value;
							 | 
						|
								                } else if (value instanceof UglifyJS.AST_Array) {
							 | 
						|
								                    options[name] = value.elements.map(to_string);
							 | 
						|
								                } else {
							 | 
						|
								                    options[name] = to_string(value);
							 | 
						|
								                }
							 | 
						|
								                return true;
							 | 
						|
								            }
							 | 
						|
								            if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_PropAccess) {
							 | 
						|
								                var name = node.print_to_string();
							 | 
						|
								                options[name] = true;
							 | 
						|
								                return true;
							 | 
						|
								            }
							 | 
						|
								            if (!(node instanceof UglifyJS.AST_Sequence)) throw node;
							 | 
						|
								
							 | 
						|
								            function to_string(value) {
							 | 
						|
								                return value instanceof UglifyJS.AST_Constant ? value.value : value.print_to_string({
							 | 
						|
								                    quote_keys: true
							 | 
						|
								                });
							 | 
						|
								            }
							 | 
						|
								        }));
							 | 
						|
								    } catch (ex) {
							 | 
						|
								        if (flag) {
							 | 
						|
								            fatal("cannot parse arguments for '" + flag + "': " + value);
							 | 
						|
								        } else {
							 | 
						|
								            options[value] = null;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								    return options;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function skip_property(key, value) {
							 | 
						|
								    return skip_keys.indexOf(key) >= 0
							 | 
						|
								        // only skip truthy_keys if their value is falsy
							 | 
						|
								        || truthy_keys.indexOf(key) >= 0 && !value;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function symdef(def) {
							 | 
						|
								    var ret = (1e6 + def.id) + " " + def.name;
							 | 
						|
								    if (def.mangled_name) ret += " " + def.mangled_name;
							 | 
						|
								    return ret;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function format_object(obj) {
							 | 
						|
								    var lines = [];
							 | 
						|
								    var padding = "";
							 | 
						|
								    Object.keys(obj).map(function(name) {
							 | 
						|
								        if (padding.length < name.length) padding = Array(name.length + 1).join(" ");
							 | 
						|
								        return [ name, JSON.stringify(obj[name]) ];
							 | 
						|
								    }).forEach(function(tokens) {
							 | 
						|
								        lines.push("  " + tokens[0] + padding.slice(tokens[0].length - 2) + tokens[1]);
							 | 
						|
								    });
							 | 
						|
								    return lines.join("\n");
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function print_error(msg) {
							 | 
						|
								    process.stderr.write(msg);
							 | 
						|
								    process.stderr.write("\n");
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function print(txt) {
							 | 
						|
								    process.stdout.write(txt);
							 | 
						|
								    process.stdout.write("\n");
							 | 
						|
								}
							 | 
						|
								
							 |