UNPKG

10.3 kBJavaScriptView Raw
1'use strict';
2
3var exit = process.exit.bind(process);
4
5var fs = require('fs'),
6 path = require('path'),
7 util = require('gulp-util'),
8 debug = require('gulp-debug'),
9 watch = require('gulp-watch'),
10 filter = require('gulp-filter'),
11 sequence = require('gulp-sequence');
12
13var getData = require('./utils/data');
14
15var mainBowerFiles = require('main-bower-files');
16
17var errorHandler = function(e) {
18 util.log(util.colors.red(e.message || e.toString()));
19 this.emit('end');
20};
21
22function expandVariables(obj, data) {
23 if (typeof obj === 'string') {
24 return obj.replace(/\$\{(\w+)\}/g, function(match, key) {
25 return data[key] || match;
26 });
27 }
28
29 if (typeof obj === 'object') {
30 for (var key in obj) {
31 obj[key] = expandVariables(obj[key], data);
32 }
33 }
34
35 return obj;
36}
37
38function to_array(obj) {
39 return Array.isArray(obj) ? obj : (obj ? [obj] : []);
40}
41
42function is_file(fullpath) {
43 return fs.existsSync(fullpath) && fs.statSync(fullpath).isFile();
44}
45
46function is_dir(fullpath) {
47 return fs.existsSync(fullpath) && fs.statSync(fullpath).isDirectory();
48}
49
50function hook(chain, set) {
51 if (set) {
52 (Array.isArray(set) ? set : [set])
53 .forEach(function(task) {
54 chain = task(chain, errorHandler)
55 .on('error', errorHandler);
56 });
57 }
58
59 return chain;
60}
61
62module.exports = function(options) {
63 options = options || {};
64
65 var gulp = options.gulp;
66
67 if (!gulp) {
68 util.log(util.colors.red('Missing the main `gulp` instance to work'));
69 exit(1);
70 }
71
72 var base = typeof util.env.base === 'string' ? util.env.base : 'default',
73 base_dir = path.join(process.cwd(), 'src', options.cwd || '', (util.env.base || options.base) !== false ? base : '');
74
75 if (!is_dir(base_dir)) {
76 util.log(util.colors.red('The specified base directory `' + base + '` is missing'));
77 exit(1);
78 }
79
80 var isBuild = options.build || util.env.build,
81 sources = options.files || {},
82 params = options.params || {},
83 iconOptions = options.icons || {},
84 autoprefixerOptions = options.autoprefixer;
85
86 params.base = base;
87 options.build = !!isBuild;
88
89 if (options.bundle === true) {
90 options.bundle = {
91 compact: true
92 };
93 }
94
95 if (typeof options.bundle === 'object') {
96 options.bundle.compact = options.bundle.compact !== false;
97 }
98
99 var _errorHandler = errorHandler;
100
101 errorHandler = function(e) {
102 _errorHandler.call(this, e);
103
104 if (isBuild) {
105 exit(1);
106 }
107 };
108
109 sources.filter = sources.filter || [];
110 sources.vendor = sources.vendor || '';
111 sources.bower = sources.bower || '';
112 sources.env = sources.env || '';
113 sources.dest = sources.dest || '';
114 sources.views = sources.views || {};
115 sources.fonts = sources.fonts || {};
116 sources.styles = sources.styles || {};
117 sources.images = sources.images || {};
118 sources.sprites = sources.sprites || {};
119 sources.scripts = sources.scripts || {};
120 sources.icons = sources.icons || {};
121
122 var env_file = path.join(base_dir, sources.env || 'env.yml');
123
124 options.paths = expandVariables({
125 fonts: {
126 on: path.join(base_dir, sources.fonts.src || 'fonts', '**/*.{ttf,otf,eot,woff,woff2,svg}'),
127 cwd: path.join(base_dir, sources.fonts.src || 'fonts'),
128 dest: sources.fonts.dest || 'fonts',
129 glob: '**/*.{ttf,otf,eot,woff,woff2,svg}'
130 },
131 icons: {
132 on: path.join(base_dir, sources.icons.src || 'icons', '**/*.svg'),
133 cwd: path.join(base_dir, sources.icons.src || 'icons'),
134 dest: sources.fonts.dest || 'fonts',
135 glob: '**/*.svg',
136 iconFont: {
137 fontName: iconOptions.fontName || 'icons',
138 svg: true,
139 appendUnicode: false,
140 fontHeight: 1024,
141 startUnicode: iconOptions.startUnicode || 0xF000,
142 normalize: iconOptions.normalize || true
143 },
144 clean: path.join(base_dir, sources.styles.src || 'styles', '_generated'),
145 defaultTemplateDest: iconOptions.defaultOutputDir || path.join(base_dir, sources.styles.src || 'styles', '_generated'),
146 defaultFontPath: iconOptions.defaultFontPath || sources.fonts.dest || 'fonts',
147 className: iconOptions.className || 'icon',
148 templates: iconOptions.templates || {
149 less: {
150 template: path.join(__dirname, 'stubs/icons/template.less'),
151 outputName: 'icons.less'
152 },
153 htmlCatalog: {
154 template: path.join(__dirname, 'stubs/icons/templateCatalog.html'),
155 outputName: 'iconCatalog.html',
156 fontPath: path.join(process.cwd(), sources.dest || 'generated', sources.fonts.dest || 'fonts')
157 }
158 }
159 },
160 images: {
161 on: path.join(base_dir, sources.images.src || 'images', '**/*.{jpg,jpeg,png,svg}'),
162 cwd: path.join(base_dir, sources.images.src || 'images'),
163 dest: sources.images.dest || 'img',
164 glob: '**/*.{jpg,jpeg,png,svg}'
165 },
166 sprites: {
167 on: path.join(base_dir, sources.sprites.src || 'sprites', '**/*.png'),
168 cwd: path.join(base_dir, sources.sprites.src || 'sprites'),
169 dest: sources.sprites.dest || 'img',
170 glob: '**/*.png'
171 },
172 styles: {
173 on: [
174 path.join(path.dirname(env_file), '_site/**/*.{variables,overrides}'),
175 path.join(base_dir, sources.styles.src || 'styles', '**/*.less'),
176 env_file
177 ],
178 autoprefixer: autoprefixerOptions || { browsers: [ '> 1%', 'last 2 versions' ] },
179 cwd: path.join(base_dir, sources.styles.src || 'styles'),
180 dest: sources.styles.dest || 'css',
181 glob: '**/' + (options.bundle ? 'index' : '*') + '.less',
182 filter: sources.styles.filter || [],
183 watch: sources.styles.watch || []
184 },
185 scripts: {
186 on: path.join(base_dir, sources.scripts.src || 'scripts', '**/*.{coffee,litcoffee}'),
187 cwd: path.join(base_dir, sources.scripts.src || 'scripts'),
188 dest: sources.scripts.dest || 'js',
189 glob: '**/*.{coffee,litcoffee}',
190 filter: sources.scripts.filter || [],
191 watch: sources.scripts.watch || []
192 },
193 views: {
194 on: [
195 path.join(base_dir, sources.views.src || 'views', '**/*.*'),
196 path.join(path.dirname(env_file), 'data/**/*.yml'),
197 path.join(process.cwd(), 'data/**/*.yml')
198 ],
199 ext: sources.views.ext || '.html',
200 cwd: path.join(base_dir, sources.views.src || 'views'),
201 dest: sources.views.dest || '',
202 glob: '**/*.jade',
203 filter: sources.views.filter || [],
204 watch: sources.views.watch || []
205 },
206 data: {
207 src: [
208 path.join(path.dirname(env_file), 'data'),
209 path.join(process.cwd(), 'data')
210 ],
211 glob: '**/*.yml'
212 },
213 vendor: sources.vendor || 'vendor',
214 bower: path.join(process.cwd(), sources.bower || ''),
215 dest: path.join(process.cwd(), sources.dest || 'generated'),
216 env: env_file
217 }, params);
218
219 options.env = util.env;
220
221 var copyTask = require('./tasks/copy');
222
223 var rainbow = {
224 clean: require('./tasks/clean')(options),
225 fonts: copyTask(options, 'fonts'),
226 images: copyTask(options, 'images'),
227 icons: require('./tasks/icons')(options),
228 sprites: require('./tasks/sprites')(options),
229 scripts: require('./tasks/scripts')(options),
230 install: require('./tasks/install')(options),
231 server: require('./tasks/server')(options),
232 styles: require('./tasks/styles')(options),
233 vendor: require('./tasks/vendor')(options),
234 views: require('./tasks/views')(options)
235 };
236
237 var main = [],
238 tasks = [];
239
240 if (isBuild || options.env.clean === true) {
241 tasks.push('clean');
242 }
243
244 if (is_file(path.join(options.paths.bower, 'bower.json'))) {
245 Array.prototype.push.call(tasks, 'install', 'vendor');
246 }
247
248 ['fonts', 'images', 'icons', 'sprites', 'styles', 'scripts', 'views']
249 .forEach(function(task) {
250 if (is_dir(options.paths[task].cwd)) {
251 tasks.push(task);
252 }
253 });
254
255 if (options.server === true && !isBuild) {
256 tasks.push('server');
257 }
258
259 tasks
260 .forEach(function(task) {
261 var files = options.paths[task],
262 callback = rainbow[task];
263
264 if (to_array(sources.skip).indexOf(task) > -1) {
265 return;
266 }
267
268 var prefix = options.prefix ? options.prefix + ':' : 'rainbow:';
269
270 if (callback) {
271 main.push(prefix + task);
272
273 if (typeof callback === 'function') {
274 gulp.task(prefix + task, callback);
275 } else {
276 gulp.task(prefix + task, function() {
277 var chain = gulp.src(callback.src);
278
279 chain = chain
280 .pipe(filter(['**', '!**/_*', '!**/_*/**']
281 .concat(to_array(sources.filter))
282 .concat(to_array(files.filter))));
283
284 if (typeof callback.check === 'function' && (options.env.check !== false)) {
285 chain = hook(chain, callback.check);
286 }
287
288 chain = hook(chain, sources[task].before);
289
290 if (typeof callback.pipe === 'function') {
291 chain = hook(chain, callback.pipe);
292 }
293
294 return hook(chain, sources[task].after)
295 .pipe(gulp.dest(callback.dest))
296 .pipe(debug({ title: prefix + task }));
297 });
298 }
299
300 if (files && files.on && !isBuild) {
301 watch(to_array(files.on).concat(to_array(files.watch)), function() {
302 gulp.start(prefix + task);
303 });
304 }
305 } else {
306 util.log(util.colors.red('Unknown rainbow-task `' + task + '`'));
307 exit(1);
308 }
309 });
310
311 if (options.before) {
312 Array.prototype.unshift.apply(main, to_array(options.before));
313 }
314
315 if (options.after) {
316 Array.prototype.push.apply(main, to_array(options.after));
317 }
318
319 if (options.prefix) {
320 return sequence.use(gulp).apply(null, main);
321 }
322
323 gulp.task('rainbow', sequence.use(gulp).apply(null, main));
324};
325
326module.exports.bowerFiles = function(from) {
327 var bower_dir = path.resolve(from, 'bower_components');
328
329 return mainBowerFiles({
330 paths: {
331 bowerDirectory: path.relative(process.cwd(), bower_dir),
332 bowerJson: path.join(from, 'bower.json')
333 }
334 });
335};
336
337module.exports.server = function(root) {
338 return require('./tasks/server')({
339 paths: { dest: root },
340 env: util.env
341 });
342};
343
344module.exports.data = getData;