diff options
author | Alex Lam S.L <alexlamsl@gmail.com> | 2020-06-07 06:48:51 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-07 13:48:51 +0800 |
commit | 28b7b15da19a2a081ab768f8315ce39db7c52b63 (patch) | |
tree | f114408c711f62fd2835235c171a136efde73c6c /bin/uglifyjs | |
parent | aa37b196989edc13988ab225e4a7c954565e39eb (diff) | |
download | tracifyjs-28b7b15da19a2a081ab768f8315ce39db7c52b63.tar.gz tracifyjs-28b7b15da19a2a081ab768f8315ce39db7c52b63.zip |
parse command line internally (#3961)
Diffstat (limited to 'bin/uglifyjs')
-rwxr-xr-x | bin/uglifyjs | 481 |
1 files changed, 269 insertions, 212 deletions
diff --git a/bin/uglifyjs b/bin/uglifyjs index 500fe6d8..c15acca6 100755 --- a/bin/uglifyjs +++ b/bin/uglifyjs @@ -8,185 +8,251 @@ require("../tools/exit"); var fs = require("fs"); var info = require("../package.json"); var path = require("path"); -var program = require("commander"); var UglifyJS = require("../tools/node"); var skip_keys = [ "cname", "inlined", "parent_scope", "scope", "uses_eval", "uses_with" ]; var files = {}; -var options = { - compress: false, - mangle: false +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", }; -program.version(info.name + " " + info.version); -program.parseArgv = program.parse; -program.parse = undefined; -if (process.argv.indexOf("ast") >= 0) program.helpInformation = UglifyJS.describe_ast; -else if (process.argv.indexOf("options") >= 0) program.helpInformation = function() { - var text = []; - var toplevels = []; - var padding = ""; - var options = UglifyJS.default_options(); - for (var name in options) { - var option = options[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_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]); +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) { + process_option(short_forms[letter], index + 1 < arg.length); }); - return text.join("\n"); -}; -program.option("-p, --parse <options>", "Specify parser options.", parse_js()); -program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js()); -program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js()); -program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js()); -program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js()); -program.option("-O, --output-opts [options]", "Output options (beautify disabled).", parse_js()); -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."); -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("--toplevel", "Compress and/or mangle variables in toplevel scope."); -program.option("--validate", "Perform validation during AST manipulations."); -program.option("--verbose", "Print diagnostic messages."); -program.option("--warn", "Print warning messages."); -program.option("--wrap <name>", "Embed everything as a function with “exports” corresponding to “name” globally."); -program.option("--reduce-test", "Reduce a standalone `console.log` based test case."); -program.arguments("[files...]").parseArgv(process.argv); -if (program.configFile) { - options = JSON.parse(read_file(program.configFile)); - if (options.mangle && options.mangle.properties && options.mangle.properties.regex) { - options.mangle.properties.regex = UglifyJS.parse(options.mangle.properties.regex, { - expression: true - }).value; - } -} -if (!program.output && program.sourceMap && program.sourceMap.url != "inline") { - fatal("cannot write source map to STDOUT"); -} -[ - "compress", - "enclose", - "ie8", - "mangle", - "sourceMap", - "toplevel", - "validate", - "wrap" -].forEach(function(name) { - if (name in program) { - options[name] = program[name]; - } -}); -if (program.verbose) { - options.warnings = "verbose"; -} else if (program.warn) { - options.warnings = true; -} -if (options.warnings) { - UglifyJS.AST_Node.log_function(print_error, options.warnings == "verbose"); - delete options.warnings; } -if (program.beautify) { - options.output = typeof program.beautify == "object" ? program.beautify : {}; - if (!("beautify" in options.output)) { - options.output.beautify = true; + +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_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).", + " --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).", + " --ie8 Support non-standard Internet Explorer 8.", + " --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name.", + " --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.", + " --validate Perform validation during AST manipulations.", + " --verbose Print diagnostic messages.", + " --warn Print warning messages.", + " --wrap <name> Embed everything as a function with “exports” corresponding to “name” globally.", + " --reduce-test Reduce a standalone test case.", + ].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 "ie8": + case "timings": + case "toplevel": + case "validate": + options[name] = 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 "reduce-test": + case "self": + break; + default: + fatal("invalid option --" + name); } -} -if (program.outputOpts) { - if (program.beautify) fatal("--beautify cannot be used with --output-opts"); - options.output = typeof program.outputOpts == "object" ? program.outputOpts : {}; -} -if (program.comments) { - if (typeof options.output != "object") options.output = {}; - options.output.comments = typeof program.comments == "string" ? program.comments : "some"; -} -if (program.define) { - if (typeof options.compress != "object") options.compress = {}; - if (typeof options.compress.global_defs != "object") options.compress.global_defs = {}; - for (var expr in program.define) { - options.compress.global_defs[expr] = program.define[expr]; + + 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 (program.keepFnames) { - options.keep_fnames = true; -} -if (program.mangleProps) { - if (program.mangleProps.domprops) { - delete program.mangleProps.domprops; +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 program.mangleProps != "object") program.mangleProps = {}; - if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = []; + 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(program.mangleProps.reserved, name); + UglifyJS.push_uniq(options.mangle.properties.reserved, name); }); } - if (typeof options.mangle != "object") options.mangle = {}; - options.mangle.properties = program.mangleProps; } -if (program.nameCache) { - options.nameCache = JSON.parse(read_file(program.nameCache, "{}")); -} -if (program.output == "ast") { - options.output = { - ast: true, - code: false - }; -} -if (program.parse) { - if (!program.parse.acorn && !program.parse.spidermonkey) { - options.parse = program.parse; - } else if (program.sourceMap && program.sourceMap.content == "inline") { - fatal("inline source map only works with built-in parser"); - } +if (output == "ast") options.output = { + ast: true, + 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 (~program.rawArgs.indexOf("--rename")) { - options.rename = true; -} else if (!program.rename) { - options.rename = false; +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 program.sourceMap == "object" && "base" in program.sourceMap) { +if (typeof options.sourceMap == "object" && "base" in options.sourceMap) { convert_path = function() { - var base = program.sourceMap.base; + var base = options.sourceMap.base; delete options.sourceMap.base; return function(name) { return path.relative(base, name); }; }(); } -if (program.self) { - if (program.args.length) UglifyJS.AST_Node.warn("Ignoring input files since --self was passed"); +if (specified["self"]) { + if (paths.length) UglifyJS.AST_Node.warn("Ignoring input files since --self was passed"); if (!options.wrap) options.wrap = "UglifyJS"; - simple_glob(UglifyJS.FILES).forEach(function(name) { - files[convert_path(name)] = read_file(name); - }); - run(); -} else if (program.args.length) { - simple_glob(program.args).forEach(function(name) { + paths = UglifyJS.FILES; +} +if (paths.length) { + simple_glob(paths).forEach(function(name) { files[convert_path(name)] = read_file(name); }); run(); @@ -207,15 +273,14 @@ function convert_ast(fn) { } function run() { - var content = program.sourceMap && program.sourceMap.content; + var content = options.sourceMap && options.sourceMap.content; if (content && content != "inline") { UglifyJS.AST_Node.info("Using input source map: " + content); options.sourceMap.content = read_file(content, content); } - if (program.timings) options.timings = true; try { - if (program.parse) { - if (program.parse.acorn) { + if (options.parse) { + if (options.parse.acorn) { files = convert_ast(function(toplevel, name) { return require("acorn").parse(files[name], { locations: true, @@ -223,7 +288,7 @@ function run() { sourceFile: name }); }); - } else if (program.parse.spidermonkey) { + } else if (options.parse.spidermonkey) { files = convert_ast(function(toplevel, name) { var obj = JSON.parse(files[name]); if (!toplevel) return obj; @@ -235,17 +300,17 @@ function run() { } catch (ex) { fatal(ex); } - if (program.reduceTest) { + var result; + if (specified["reduce-test"]) { // load on demand - assumes dev tree checked out var reduce_test = require("../test/reduce"); - var testcase = files[0] || files[Object.keys(files)[0]]; - var result = reduce_test(testcase, options, { + 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 { - var result = UglifyJS.minify(files, options); + } else { + result = UglifyJS.minify(files, options); } if (result.error) { var ex = result.error; @@ -275,10 +340,8 @@ function run() { print_error(format_object(ex.defs)); } fatal(ex); - } else if (program.output == "ast") { - if (!options.compress && !options.mangle) { - result.ast.figure_out_scope({}); - } + } else if (output == "ast") { + if (!options.compress && !options.mangle) result.ast.figure_out_scope({}); print(JSON.stringify(result.ast, function(key, value) { if (value) switch (key) { case "thedef": @@ -304,26 +367,22 @@ function run() { } return value; }, 2)); - } else if (program.output == "spidermonkey") { + } else if (output == "spidermonkey") { print(JSON.stringify(UglifyJS.minify(result.code, { compress: false, mangle: false, output: { ast: true, code: false - } + }, }).ast.to_mozilla_ast(), null, 2)); - } else if (program.output) { - fs.writeFileSync(program.output, result.code); - if (result.map) { - fs.writeFileSync(program.output + ".map", result.map); - } + } else if (output) { + fs.writeFileSync(output, result.code); + if (result.map) fs.writeFileSync(output + ".map", result.map); } else { print(result.code); } - if (program.nameCache) { - fs.writeFileSync(program.nameCache, JSON.stringify(options.nameCache)); - } + 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"); } @@ -379,47 +438,45 @@ function read_file(path, default_value) { } } -function parse_js(flag) { - return function(value, options) { - options = options || {}; - 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; +function parse_js(value, options, flag) { + if (!options || typeof options != "object") options = {}; + 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); } - if (!(node instanceof UglifyJS.AST_Sequence)) throw node; + 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; + 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; } + return options; } function skip_key(key) { |