UNPKG

6.81 kBJavaScriptView Raw
1var _ = require('lodash');
2var fs = require('fs-extra');
3var path = require('path');
4var denodeify = require("pdenodeify");
5var eachGraph = require("../graph/each_dependencies");
6var transformImport = require("../build/transform");
7var helpers = require('./helpers/helpers');
8var winston = require('winston');
9var logging = require("../logger");
10
11var mergeModules = function(items, modules){
12 var i = 0,
13 item;
14 while(i < items.length) {
15 item = items[i];
16 if(typeof item === "object" && !(item instanceof RegExp) ) {
17 var moduleNames = _.map( _.filter(modules, item), "moduleName");
18 items.splice.apply(items,[i,1].concat(moduleNames));
19 i = i + moduleNames.length;
20 } else {
21 i++;
22 }
23 }
24};
25
26var addDefaults = function(name, obj, defaults){
27 var helpers = [];
28
29 name.replace(/\+([\w-]+)/g,function(whole, part){
30 var defs = defaults[part];
31 if(defs) {
32 if(typeof defs === "function") {
33 defs = defs(obj);
34 _.assign(obj, defs);
35 } else {
36 _.defaults(obj, defs);
37 }
38 helpers.push(part);
39 }
40
41 });
42
43 if(helpers.length) {
44 winston.debug(" added helpers: "+helpers.join(","));
45 }
46};
47
48/**
49 * Normalize module names
50 * @param {string|Array.<string>} mods A module name (or a list of them)
51 * @return {Array.<Promise.<string>>} An array of promises that resolved
52 * to normalized module names.
53 */
54function normalize(loader, mods) {
55 var modNames = (mods && !Array.isArray(mods)) ? [mods] : mods;
56
57 return (modNames || []).map(function(moduleName) {
58 return !_.isString(moduleName) ?
59 Promise.resolve(moduleName) :
60 loader.normalize(moduleName);
61 });
62}
63
64function writeFile(filename, data, config) {
65 var code = data.code;
66 var map = data.map;
67 var mkdir = denodeify(fs.mkdirs);
68 var writeFile = denodeify(fs.writeFile);
69
70 return mkdir(path.dirname(filename))
71 .then(function() {
72 return writeFile(filename, code);
73 })
74 .then(function() {
75 var sourceMaps = map && config.options &&
76 config.options.sourceMaps;
77
78 if (sourceMaps) {
79 return writeFile(filename + ".map", map+"");
80 }
81 });
82}
83
84// config {steal: {}, options: {}, outputs: {}}
85module.exports = function(config, defaults, modules){
86 logging.setup(config.options || {}, config.steal || {});
87
88 // allow defaults that overwrite our helpers
89 var defaultHelpers = _.assign(_.clone(helpers), defaults);
90
91 // converts to an array of outputs
92 config.outputs = _.map(
93 config.outputs || config.transforms,
94 function(output, name) {
95 addDefaults(name, output, defaultHelpers || {}, config.options || {});
96
97 // merge modules and graphs
98 mergeModules(output.modules || [], modules);
99 mergeModules(output.eachModule || [], modules);
100 mergeModules(output.graphs || [], modules);
101 mergeModules(output.ignore || [], modules);
102
103 return {
104 name: name,
105 output: output
106 };
107 }
108 );
109
110 var transformAndWriteOut = function(transform, moduleNames, out, outputOptions) {
111 var modulesMap = _.keyBy(modules, "moduleName");
112
113 var options = _.assign({}, outputOptions, out.output, {
114 ignore: outputOptions.ignore || out.output.ignore
115 });
116
117 return transform(moduleNames, options)
118 .then(function(result){
119 var filePath;
120
121 if (_.isUndefined(out.output.dest)) {
122 return Promise.reject(new Error(
123 "Attribute 'dest' is required\n" +
124 "Add 'dest' to the ExportOutput object.\n" +
125 "See http://stealjs.com/docs/steal-tools.export.output.html#dest for more details."
126 ));
127 }
128 else if (_.isString(out.output.dest)) {
129 filePath = out.output.dest;
130 }
131 else if (_.isFunction(out.output.dest)) {
132 // pull out the load objects of the modules being written out
133 var loads = (_.isString(moduleNames) ?
134 transform.graph[moduleNames].load :
135 moduleNames.map(function(moduleName){
136 return transform.graph[moduleName].load;
137 }));
138
139 filePath = out.output.dest(moduleNames,
140 modulesMap[moduleNames], loads, transform.loader);
141 }
142
143 winston.info("> " + filePath);
144 return writeFile(filePath, result, config);
145 });
146 };
147
148 var processOutput = function(transform, out) {
149 winston.info("OUTPUT: " + out.name);
150
151 var modsPromise;
152 var doTransform;
153 var loader = transform.loader;
154
155 // write out each module and its dependencies in the list
156 if(out.output.eachModule) {
157 if (Array.isArray(out.output.eachModule)) {
158 modsPromise = normalize(loader, out.output.eachModule);
159 }
160 else {
161 modsPromise = normalize(loader, _.map(
162 _.filter(modules, out.output.eachModule),
163 "moduleName"
164 ));
165 }
166
167 doTransform = function(mods, ignores){
168 return Promise.all(mods.map(function(mod) {
169 return transformAndWriteOut(transform, mod, out, {
170 ignore: ignores
171 });
172 }));
173 };
174 // write out the graphs
175 } else if(out.output.graphs){
176 if (typeof out.output.graphs === "function") {
177 modsPromise = normalize(loader, out.output.graphs(loader));
178 }
179 else {
180 modsPromise = normalize(loader, out.output.graphs);
181 }
182
183 doTransform = function(mods, ignores) {
184 var promises = [];
185
186 eachGraph(transform.graph, mods, function(name, node) {
187 if(node && !transformImport.matches(ignores, name, node.load)) {
188 var promise = transformAndWriteOut(transform, name, out, {
189 ignoreAllDependencies: true
190 });
191 promises.push(promise);
192 }
193 });
194
195 return Promise.all(promises);
196 };
197 // write out all the modules combined
198 } else {
199 if(Array.isArray( out.output.modules) ) {
200 modsPromise = normalize(loader, out.output.modules);
201 } else if(typeof out.output.modules === "function"){
202 modsPromise = normalize(loader, out.output.modules(loader));
203 } else if(out.output.modules) {
204 modsPromise = normalize(loader, [out.output.modules]);
205 }
206 doTransform = function(mods, ignores){
207 return transformAndWriteOut(transform, mods, out, {
208 ignore: ignores
209 });
210 };
211 }
212
213 var normalized;
214 return Promise.all(modsPromise)
215 .then(function(mods) {
216 normalized = mods;
217 var ignore = out.output.ignore || [];
218
219 return Promise.all(normalize(loader, ignore));
220 })
221 .then(function(outputIgnore){
222 var ignores = transformImport
223 .getAllIgnores(outputIgnore, transform.graph);
224
225 return doTransform(normalized, ignores);
226 });
227 };
228
229 if (!config.steal) {
230 var message;
231 if(config.system) {
232 message = "The 'system' option was removed in 1.0, use 'steal' instead: http://stealjs.com/docs/steal-tools.export.object.html";
233 } else {
234 message = "A 'steal' option is required.";
235 }
236 return Promise.reject(new Error(message));
237 }
238
239 return transformImport(config.steal, config.options)
240 .then(function(configPluginify){
241 var buildResult = configPluginify.data;
242 return Promise.all(config.outputs.map(function(out) {
243 return processOutput(configPluginify, out);
244 }))
245 .then(function(){
246 return buildResult;
247 });
248 });
249};