UglifyJS/tools/node.js
RefinedSoftwareLLC 368fb1329a beautifyJSON(files, options)
beautifyJSON(files, options)
files = a (single or array of) file names, JSON strings, or JSON Objects.
options = UglifyJS minify options.
NEW OPTIONS:
    fromObject:true allows passing a JSON object or an array of JSON objects.
    replacer:function(key, oldValue){ return newValue; }
    replacer:["Array", "of", "kept", "properties", "all", "others", "discarded"]
UNSUPPORTED: (Source Maps):true, compress:true, quote_keys:false.
WARNING: All input is run through JSON.stringify() which will change some invalid
    values (like NaN and infinity) and error on others (like incorrect syntax).
2013-03-22 17:17:42 -06:00

237 lines
7.0 KiB
JavaScript

var path = require("path");
var fs = require("fs");
var vm = require("vm");
var sys = require("util");
var UglifyJS = vm.createContext({
sys : sys,
console : console,
MOZ_SourceMap : require("source-map")
});
function load_global(file) {
file = path.resolve(path.dirname(module.filename), file);
try {
var code = fs.readFileSync(file, "utf8");
return vm.runInContext(code, UglifyJS, file);
} catch(ex) {
// XXX: in case of a syntax error, the message is kinda
// useless. (no location information).
sys.debug("ERROR in file: " + file + " / " + ex);
process.exit(1);
}
};
var FILES = exports.FILES = [
"../lib/utils.js",
"../lib/ast.js",
"../lib/parse.js",
"../lib/transform.js",
"../lib/scope.js",
"../lib/output.js",
"../lib/compress.js",
"../lib/sourcemap.js",
"../lib/mozilla-ast.js"
].map(function(file){
return path.join(path.dirname(fs.realpathSync(__filename)), file);
});
FILES.forEach(load_global);
UglifyJS.AST_Node.warn_function = function(txt) {
sys.error("WARN: " + txt);
};
// XXX: perhaps we shouldn't export everything but heck, I'm lazy.
for (var i in UglifyJS) {
if (UglifyJS.hasOwnProperty(i)) {
exports[i] = UglifyJS[i];
}
}
exports.minify = function(files, options) {
options = UglifyJS.defaults(options, {
outSourceMap : null,
sourceRoot : null,
inSourceMap : null,
fromString : false,
warnings : false,
mangle : {},
output : null,
compress : {}
});
if (typeof files == "string")
files = [ files ];
// 1. parse
var toplevel = null;
files.forEach(function(file){
var code = options.fromString
? file
: fs.readFileSync(file, "utf8");
toplevel = UglifyJS.parse(code, {
filename: options.fromString ? "?" : file,
toplevel: toplevel
});
});
// 2. compress
if (options.compress) {
var compress = { warnings: options.warnings };
UglifyJS.merge(compress, options.compress);
toplevel.figure_out_scope();
var sq = UglifyJS.Compressor(compress);
toplevel = toplevel.transform(sq);
}
// 3. mangle
if (options.mangle) {
toplevel.figure_out_scope();
toplevel.compute_char_frequency();
toplevel.mangle_names(options.mangle);
}
// 4. output
var inMap = options.inSourceMap;
var output = {};
if (typeof options.inSourceMap == "string") {
inMap = fs.readFileSync(options.inSourceMap, "utf8");
}
if (options.outSourceMap) {
output.source_map = UglifyJS.SourceMap({
file: options.outSourceMap,
orig: inMap,
root: options.sourceRoot
});
}
if (options.output) {
UglifyJS.merge(output, options.output);
}
var stream = UglifyJS.OutputStream(output);
toplevel.print(stream);
return {
code : stream + "",
map : output.source_map + ""
};
};
exports.beautifyJSON = function(files, options) {
// files = a (single or array of) file names, JSON strings, or JSON Objects.
// options = UglifyJS minify options.
// NEW OPTIONS:
// fromObject:true allows passing a JSON object or an array of JSON objects.
// replacer:function(key, oldValue){ return newValue; }
// replacer:["Array", "of", "kept", "properties", "all", "others", "discarded"]
// UNSUPPORTED: (Source Maps):true, compress:true, quote_keys:false.
// WARNING: All input is run through JSON.stringify() which will change some invalid
// values (like NaN and infinity) and error on others (like incorrect syntax).
// 1. updating options with standard beautify settings and overrides:
options = UglifyJS.defaults(options, {
fromString : false,
fromObject : false,
warnings : false,
compress : false,
output : { beautify : true, quote_keys : true }
});
// 2. override unsupported options that have compatibility errors:
options.outSourceMap = null;
options.sourceRoot = null;
options.inSourceMap = null;
options.compress = false;
if (typeof options.output === "undefined" || options.output === null) {
options.output = {};
}
options.output.quote_keys = true;
// 3. reading files, parsing, and (if needed) bundling in to array: (Arrays are legal JavaScript code)
var isArray;
if (Object.prototype.toString.call(files) === "[object Array]") {
isArray = true;
} else {
isArray = false;
files = [ files ];
}
var code;
if (options.fromObject) {
code = files;
} else if (options.fromString) {
code = [];
files.forEach(function(file, i){
code[i] = JSON.parse(file);
});
} else /* if (options.fromFile) */ {
code = [];
files.forEach(function(file, i){
code[i] = JSON.parse( fs.readFileSync(file,"utf8") );
});
}
options.fromString = true;
// 4. filturing (replacer), changing incorrect values, and stringifying:
code = JSON.stringify(code, options.replacer);
// 5. beautifying:
code = UglifyJS.minify(code, options).code;
// 6. removing trailing semicolon and (if needed) unbundling out of array:
if (isArray) {
code = code.substr(0, code.length - 1);
} else {
code = code.substr(2, code.length - 5);
}
return code;
};
// exports.describe_ast = function() {
// function doitem(ctor) {
// var sub = {};
// ctor.SUBCLASSES.forEach(function(ctor){
// sub[ctor.TYPE] = doitem(ctor);
// });
// var ret = {};
// if (ctor.SELF_PROPS.length > 0) ret.props = ctor.SELF_PROPS;
// if (ctor.SUBCLASSES.length > 0) ret.sub = sub;
// return ret;
// }
// return doitem(UglifyJS.AST_Node).sub;
// }
exports.describe_ast = function() {
var out = UglifyJS.OutputStream({ beautify: true });
function doitem(ctor) {
out.print("AST_" + ctor.TYPE);
var props = ctor.SELF_PROPS.filter(function(prop){
return !/^\$/.test(prop);
});
if (props.length > 0) {
out.space();
out.with_parens(function(){
props.forEach(function(prop, i){
if (i) out.space();
out.print(prop);
});
});
}
if (ctor.documentation) {
out.space();
out.print_string(ctor.documentation);
}
if (ctor.SUBCLASSES.length > 0) {
out.space();
out.with_block(function(){
ctor.SUBCLASSES.forEach(function(ctor, i){
out.indent();
doitem(ctor);
out.newline();
});
});
}
};
doitem(UglifyJS.AST_Node);
return out + "";
};