sensortoy/www/libs/bluebird/tools/build.js
Martin Donnelly 939a7aff4c init
2016-05-20 17:10:40 +01:00

338 lines
14 KiB
JavaScript

var Promise = require("bluebird");
var path = require("path");
var jobRunner = require("./job-runner/job-runner.js");
Promise.longStackTraces();
var utils = require("./utils.js");
var glob = Promise.promisify(require("glob"));
var fs = Promise.promisifyAll(require("fs"));
var mkdirp = Promise.promisify(require("mkdirp"));
var rimraf = Promise.promisify(require("rimraf"));
jobRunner.init(path.join(__dirname, ".."), function() {
var fs = Promise.promisifyAll(require("fs"));
var utils = require("./tools/utils.js");
var path = require("path");
var astPasses = require("./tools/ast_passes.js");
var Mocha = require("mocha");
astPasses.readConstants(
fs.readFileSync("./src/constants.js", "utf8"),
"constants.js"
);
function applyOptionalRequires(code, depsRequireCode) {
return code.replace( /};([^}]*)$/, depsRequireCode + "\n};$1");
}
});
var optionalModuleRequireMap = {
"race.js": true,
"call_get.js": true,
"generators.js": true,
"map.js": true,
"nodeify.js": true,
"promisify.js": true,
"props.js": true,
"reduce.js": true,
"settle.js": true,
"some.js": true,
"using.js": true,
"timers.js": true,
"filter.js": ["map.js"],
"any.js": ["some.js"],
"each.js": ["reduce.js"]
};
var lastLineCode = " \n\
util.toFastProperties(Promise); \n\
util.toFastProperties(Promise.prototype); \n\
function fillTypes(value) { \n\
var p = new Promise(INTERNAL); \n\
p._fulfillmentHandler0 = value; \n\
p._rejectionHandler0 = value; \n\
p._promise0 = value; \n\
p._receiver0 = value; \n\
} \n\
// Complete slack tracking, opt out of field-type tracking and \n\
// stabilize map \n\
fillTypes({a: 1}); \n\
fillTypes({b: 2}); \n\
fillTypes({c: 3}); \n\
fillTypes(1); \n\
fillTypes(function(){}); \n\
fillTypes(undefined); \n\
fillTypes(false); \n\
fillTypes(new Promise(INTERNAL)); \n\
debug.setBounds(Async.firstLineError, util.lastLineError); \n\
return Promise; \n\
";
function getOptionalRequireCode(srcs) {
return srcs.sort(function(a, b) {
var aHasDeps = Array.isArray(optionalModuleRequireMap[a.sourceFileName]);
var bHasDeps = Array.isArray(optionalModuleRequireMap[b.sourceFileName]);
return aHasDeps - bHasDeps;
}).reduce(function(ret, cur, i) {
if(optionalModuleRequireMap[cur.sourceFileName]) {
ret += "require('./"+cur.sourceFileName+"')("+ cur.deps.join(", ") +");\n";
}
return ret;
}, "") + lastLineCode;
}
function getBrowserBuildHeader(sources, npmPackage) {
var header = "/**\n * bluebird build version " + npmPackage.version + "\n";
var enabledFeatures = ["core"];
var disabledFeatures = [];
featureLoop: for (var key in optionalModuleRequireMap) {
for (var i = 0, len = sources.length; i < len; ++i) {
var source = sources[i];
if(source.sourceFileName === key) {
enabledFeatures.push(key.replace( ".js", ""));
continue featureLoop;
}
}
disabledFeatures.push(key.replace(".js", ""));
}
header += (" * Features enabled: " + enabledFeatures.join(", ") + "\n");
if (disabledFeatures.length) {
header += " * Features disabled: " + disabledFeatures.join(", ") + "\n";
}
header += "*/\n";
return header;
}
function getSourcePaths(features) {
return glob("./src/*.js").map(function(v) {
return path.basename(v);
}).then(function(results) {
if (features) features = features.toLowerCase().split(/\s+/g);
return results.filter(function(fileName) {
if (features && optionalModuleRequireMap[fileName] !== undefined) {
for (var i = 0; i < features.length; ++i) {
if (fileName.indexOf(features[i]) >= 0) {
return true;
}
}
return false;
}
return fileName !== "constants.js";
});
});
}
function ensureDirectory(dir, isUsed, clean) {
return (clean ? rimraf(dir) : Promise.resolve()).then(function() {
if (!isUsed) return dir;
return mkdirp(dir).thenReturn(dir);
});
}
function buildRelease(sources, depsRequireCode, dir) {
return dir.then(function(dir) {
return Promise.map(sources, function(source) {
return jobRunner.run(function() {
var code = source.source;
var sourceFileName = source.sourceFileName;
code = astPasses.removeAsserts(code, sourceFileName);
code = astPasses.inlineExpansion(code, sourceFileName);
code = astPasses.expandConstants(code, sourceFileName);
code = code.replace( /__DEBUG__/g, "false" );
code = code.replace( /__BROWSER__/g, "false" );
if (sourceFileName === "promise.js") {
code = applyOptionalRequires(code, depsRequireCode);
}
return fs.writeFileAsync(path.join(root, sourceFileName), code);
}, {
context: {
depsRequireCode: depsRequireCode,
source: source,
root: dir
}
});
});
});
}
function buildDebug(sources, depsRequireCode, dir) {
return dir.then(function(dir) {
return Promise.map(sources, function(source) {
return jobRunner.run(function() {
var code = source.source;
var sourceFileName = source.sourceFileName;
code = astPasses.expandAsserts(code, sourceFileName);
code = astPasses.inlineExpansion(code, sourceFileName);
code = astPasses.expandConstants(code, sourceFileName);
code = code.replace( /__DEBUG__/g, "true" );
code = code.replace( /__BROWSER__/g, "false" );
if (sourceFileName === "promise.js") {
code = applyOptionalRequires(code, depsRequireCode);
}
return fs.writeFileAsync(path.join(root, sourceFileName), code);
}, {
context: {
depsRequireCode: depsRequireCode,
source: source,
root: dir
}
});
});
});
}
function buildBrowser(sources, dir, tmpDir, depsRequireCode, minify, npmPackage, license) {
return Promise.join(dir, tmpDir, npmPackage, license, function(dir, tmpDir, npmPackage, license) {
return Promise.map(sources, function(source) {
return jobRunner.run(function() {
var code = source.source;
var sourceFileName = source.sourceFileName;
code = astPasses.removeAsserts(code, sourceFileName);
code = astPasses.inlineExpansion(code, sourceFileName, true);
code = astPasses.expandConstants(code, sourceFileName);
code = code.replace( /__BROWSER__/g, "true" );
if (sourceFileName === "promise.js") {
code = applyOptionalRequires(code, depsRequireCode);
}
return fs.writeFileAsync(path.join(root, sourceFileName), code);
}, {
context: {
depsRequireCode: depsRequireCode,
source: source,
root: tmpDir
}
});
}).then(function() {
var header = getBrowserBuildHeader(sources, npmPackage);
return jobRunner.run(function() {
var UglifyJS = require("uglify-js");
var browserify = require("browserify");
var dest = path.join(root, "bluebird.js");
var minDest = path.join(root, "bluebird.min.js");
var b = browserify({
entries: entries,
detectGlobals: false,
standalone: "Promise"
});
return Promise.promisify(b.bundle, b)().then(function(src) {
var alias = "\
;if (typeof window !== 'undefined' && window !== null) { \
window.P = window.Promise; \
} else if (typeof self !== 'undefined' && self !== null) { \
self.P = self.Promise; \
}";
src = src + alias;
src = src.replace(/\brequire\b/g, "_dereq_");
var minWrite, write;
if (minify) {
var minSrc = src.replace( /__DEBUG__/g, "false" );
minSrc = UglifyJS.minify(minSrc, {
comments: false,
compress: true,
fromString: true
}).code;
minSrc = license + header + minSrc;
minWrite = fs.writeFileAsync(minDest, minSrc);
}
src = src.replace( /__DEBUG__/g, "true" );
src = license + header + src;
write = fs.writeFileAsync(dest, src);
return Promise.all([write, minWrite]);
})
}, {
context: {
header: header,
root: dir,
entries: path.join(tmpDir, "bluebird.js"),
license: license,
minify: minify
}
})
});
});
}
var root = process.cwd();
// Since rm -rf is called, better be sure...
if (path.basename(root).toLowerCase() !== "bluebird") {
throw new Error("cwd must be se to bluebird project root. Cwd is currently\n\n" +
" " + process.cwd() + "\n");
}
var dirs = {
release: path.join(root, "js", "release"),
debug: path.join(root, "js", "debug"),
browser: path.join(root, "js", "browser"),
browserTmp: path.join(root, "js", "tmp"),
instrumented: path.join(root, "js", "instrumented"),
coverage: path.join(root, "coverage")
};
function build(options) {
options = Object(options);
var clean = (typeof options.clean !== "boolean" ? true : options.clean);
var npmPackage = fs.readFileAsync("./package.json").then(JSON.parse);
var sourceFileNames = getSourcePaths(options.features);
var license = utils.getLicense();
var releaseDir = ensureDirectory(dirs.release, options.release, clean);
var debugDir = ensureDirectory(dirs.debug, options.debug, clean);
var browserDir = ensureDirectory(dirs.browser, options.browser, clean);
var browserTmpDir = ensureDirectory(dirs.browserTmp, options.browser, clean);
return license.then(function(license) {
return sourceFileNames.map(function(sourceFileName) {
return jobRunner.run(function() {
var sourcePath = path.join("./src", sourceFileName);
var source = fs.readFileAsync(sourcePath, "utf8");
return source.then(function(source) {
utils.checkAscii(sourceFileName, source);
var deps = null;
if (optionalModuleRequireMap[sourceFileName] !== undefined) {
deps = utils.parseDeps(source);
}
source = astPasses.removeComments(source, sourceFileName);
return {
sourceFileName: sourceFileName,
source: source,
deps: deps
};
});
}, {
context: {
sourceFileName: sourceFileName,
optionalModuleRequireMap: optionalModuleRequireMap,
license: license
}
});
});
}).then(function(results) {
var depsRequireCode = getOptionalRequireCode(results);
var release, debug, browser;
if (options.release)
release = buildRelease(results, depsRequireCode, releaseDir);
if (options.debug)
debug = buildDebug(results, depsRequireCode, debugDir);
if (options.browser)
browser = buildBrowser(results, browserDir, browserTmpDir, depsRequireCode, options.minify, npmPackage, license);
return Promise.all([release, debug, browser]);
});
}
module.exports = build;
module.exports.ensureDirectory = ensureDirectory;
module.exports.dirs = dirs;
if (require.main === module) {
var argv = require("optimist").argv;
var browser = (typeof argv.browser !== "boolean" ? false : argv.browser) || !!argv.features;
var clean = (typeof argv.clean !== "boolean" ? true : argv.clean);
module.exports({
minify: browser && (typeof argv.minify !== "boolean" ? true : argv.minify),
browser: browser,
debug: !!argv.debug,
release: !!argv.release,
features: argv.features || null,
clean: clean
});
}