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).
237 lines
7.0 KiB
JavaScript
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 + "";
|
|
};
|