UNPKG

steal-tools

Version:

Futuristic build tools for ES6 Module applications.

248 lines (214 loc) 6.82 kB
var _ = require('lodash'); var fs = require('fs-extra'); var path = require('path'); var denodeify = require("pdenodeify"); var eachGraph = require("../graph/each_dependencies"); var transformImport = require("../build/transform"); var helpers = require('./helpers/helpers'); var winston = require('winston'); var logging = require("../logger"); var mergeModules = function(items, modules){ var i = 0, item; while(i < items.length) { item = items[i]; if(typeof item === "object" && !(item instanceof RegExp) ) { var moduleNames = _.map( _.filter(modules, item), "moduleName"); items.splice.apply(items,[i,1].concat(moduleNames)); i = i + moduleNames.length; } else { i++; } } }; var addDefaults = function(name, obj, defaults){ var helpers = []; name.replace(/\+([\w-]+)/g,function(whole, part){ var defs = defaults[part]; if(defs) { if(typeof defs === "function") { defs = defs(obj); _.assign(obj, defs); } else { _.defaults(obj, defs); } helpers.push(part); } }); if(helpers.length) { winston.debug(" added helpers: "+helpers.join(",")); } }; /** * Normalize module names * @param {string|Array.<string>} mods A module name (or a list of them) * @return {Array.<Promise.<string>>} An array of promises that resolved * to normalized module names. */ function normalize(loader, mods) { var modNames = (mods && !Array.isArray(mods)) ? [mods] : mods; return (modNames || []).map(function(moduleName) { return !_.isString(moduleName) ? Promise.resolve(moduleName) : loader.normalize(moduleName); }); } function writeFile(filename, data, config) { var code = data.code; var map = data.map; var mkdir = denodeify(fs.mkdirs); var writeFile = denodeify(fs.writeFile); return mkdir(path.dirname(filename)) .then(function() { return writeFile(filename, code); }) .then(function() { var sourceMaps = map && config.options && config.options.sourceMaps; if (sourceMaps) { return writeFile(filename + ".map", map+""); } }); } // config {steal: {}, options: {}, outputs: {}} module.exports = function(config, defaults, modules){ logging.setup(config.options || {}, config.steal || {}); // allow defaults that overwrite our helpers var defaultHelpers = _.assign(_.clone(helpers), defaults); // converts to an array of outputs config.outputs = _.map( config.outputs || config.transforms, function(output, name) { addDefaults(name, output, defaultHelpers || {}, config.options || {}); // merge modules and graphs mergeModules(output.modules || [], modules); mergeModules(output.eachModule || [], modules); mergeModules(output.graphs || [], modules); mergeModules(output.ignore || [], modules); return { name: name, output: output }; } ); var transformAndWriteOut = function(transform, moduleNames, out, outputOptions) { var modulesMap = _.keyBy(modules, "moduleName"); var options = _.assign({}, outputOptions, out.output, { ignore: outputOptions.ignore || out.output.ignore }); var result = transform(moduleNames, options); var filePath; if (_.isUndefined(out.output.dest)) { return Promise.reject(new Error( "Attribute 'dest' is required\n" + "Add 'dest' to the ExportOutput object.\n" + "See http://stealjs.com/docs/steal-tools.export.output.html#dest for more details." )); } else if (_.isString(out.output.dest)) { filePath = out.output.dest; } else if (_.isFunction(out.output.dest)) { // pull out the load objects of the modules being written out var loads = (_.isString(moduleNames) ? transform.graph[moduleNames].load : moduleNames.map(function(moduleName){ return transform.graph[moduleName].load; })); filePath = out.output.dest(moduleNames, modulesMap[moduleNames], loads, transform.loader); } winston.info("> " + filePath); return writeFile(filePath, result, config); }; var processOutput = function(transform, out) { winston.info("OUTPUT: " + out.name); var modsPromise; var doTransform; var loader = transform.loader; // write out each module and its dependencies in the list if(out.output.eachModule) { if (Array.isArray(out.output.eachModule)) { modsPromise = normalize(loader, out.output.eachModule); } else { modsPromise = normalize(loader, _.map( _.filter(modules, out.output.eachModule), "moduleName" )); } doTransform = function(mods, ignores){ return Promise.all(mods.map(function(mod) { return transformAndWriteOut(transform, mod, out, { ignore: ignores }); })); }; // write out the graphs } else if(out.output.graphs){ if (typeof out.output.graphs === "function") { modsPromise = normalize(loader, out.output.graphs(loader)); } else { modsPromise = normalize(loader, out.output.graphs); } doTransform = function(mods, ignores) { var promises = []; eachGraph(transform.graph, mods, function(name, node) { if(node && !transformImport.matches(ignores, name, node.load)) { var promise = transformAndWriteOut(transform, name, out, { ignoreAllDependencies: true }); promises.push(promise); } }); return Promise.all(promises); }; // write out all the modules combined } else { if(Array.isArray( out.output.modules) ) { modsPromise = normalize(loader, out.output.modules); } else if(typeof out.output.modules === "function"){ modsPromise = normalize(loader, out.output.modules(loader)); } else if(out.output.modules) { modsPromise = normalize(loader, [out.output.modules]); } doTransform = function(mods, ignores){ return transformAndWriteOut(transform, mods, out, { ignore: ignores }); }; } var normalized; return Promise.all(modsPromise) .then(function(mods) { normalized = mods; var ignore = out.output.ignore || []; return Promise.all(normalize(loader, ignore)); }) .then(function(outputIgnore){ var ignores = transformImport .getAllIgnores(outputIgnore, transform.graph); return doTransform(normalized, ignores); }); }; if (!config.steal) { var message; if(config.system) { message = "The 'system' option was removed in 1.0, use 'steal' instead: http://stealjs.com/docs/steal-tools.export.object.html"; } else { message = "A 'steal' option is required."; } return Promise.reject(new Error(message)); } return transformImport(config.steal, config.options) .then(function(configPluginify){ var buildResult = configPluginify.data; return Promise.all(config.outputs.map(function(out) { return processOutput(configPluginify, out); })) .then(function(){ return buildResult; }); }); };