-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathutils.js
193 lines (171 loc) · 5.95 KB
/
utils.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
'use strict';
var ops = require('./lib/lazypipe-ops');
var lazypipe = require('./lib/lazypipe').lazypipe;
var libSource = require('./lib/source');
var errors = require('./lib/errors');
module.exports = function ($) {
var _ = $.lodash;
var runSequence = require('run-sequence').use($.gulp);
// get pipes with given prefix from specific list
function _getPipesFrom(pipes, prefix) {
return pipes ? _.reject(pipes, function (val, key) {
return prefix ? key.indexOf(prefix) : true; // no prefix means no filtering
}) : [];
}
/**
* Retrive a list of published pipes with specified prefix from all loaded recipes
* Note: Suitable for both sequential definitions and plain lazypipes, but type is not checked!
* @param prefix pipe prefix
* @returns {*} array of pipe definitions
*/
function getPipes(prefix) {
return _.reduce(Object.getOwnPropertyNames($.recipes), function (mem, moduleName) {
var m = $.recipes[moduleName];
if(!_.isPlainObject(m)) {
throw new errors.NamedRecipeError(moduleName, 'Recipe function should return an object.');
}
var pipes = _getPipesFrom(m.pipes, prefix);
return pipes ? mem.concat(pipes) : mem;
}, []);
}
// prepare lazypipes with source files, as defined in "sources" configuration
/**
* Transform source config into actual source pipes
* @param sourceDefs sources configuration
* @returns {*} hash of source pipes (lazy loaded)
*/
function makeSources(sourceDefs, sourceProcessor) {
var defaultBase = _.isUndefined(sourceDefs.defaultBase) ? '.' : sourceDefs.defaultBase;
return _.transform(sourceDefs, function (obj, source, key) {
Object.defineProperty(obj, key, {
enumerable: true,
get: _.once(function () {
try {
var stream = libSource.make(source, $.gulp.src, defaultBase);
if(_.isFunction(sourceProcessor)) {
return stream.pipe(sourceProcessor);
}
return stream;
}
catch (e) {
console.log(e.stack);
throw new errors.RecipeError('Configured source `' + $.gutil.colors.cyan(key) + '` is invalid.');
}
})
});
}, {});
}
var processSourceHook = _.once(function () {
return $.utils.sequentialLazypipe($.utils.getPipes('processSource'));
});
/**
* Watch source files and do action when any file is added, modified, renamed or deleted
* @param sources Source or array of sources to watch
* @param options options for gulp-watch
* @param callback Callback to gulp-sass, called when fs event occurs
* @returns {*} Endless pipe emitting changed files
*/
function watchSource(sources, options, callback) {
if (_.isFunction(options) || _.isArray(options) && !callback) {
callback = options;
options = {};
}
if (!_.isObject(options)) {
options = {};
}
if (!_.isArray(sources)) {
sources = [sources];
}
// handle array of tasks as callback
if(_.isArray(callback)) {
var tasks = callback;
callback = function () {
runSubtasks(tasks);
};
}
// load watch as external dep
var distincts = _.filter(_.flatten(_.pluck(sources, 'distinct')), {watch: true});
return ops.mergedLazypipe(_.map(distincts, function (opts) {
return lazypipe()
.pipe($.watch, opts.globs, _.defaults({base: opts.base}, options), callback)
.pipe(processSourceHook());
}));
}
/**
* Run gulp tasks and provide end callback
* @param tasks Array of single task name to be started
* @param cb Function to be called when tasks end
*/
function runSubtasks(tasks, cb) {
if (!_.isArray(tasks)) {
tasks = [tasks];
}
if (!_.isFunction(cb)) {
cb = _.noop;
}
// exit when
if (tasks.length === 0) {
cb();
return;
}
runSequence(tasks, cb);
}
/**
* Conditionaly register gulp task only when name is present
* @param name
* @returns {*}
*/
function maybeTask(name) {
if (name) {
return $.gulp.task.apply($.gulp, arguments);
}
}
// sort files in pipe
function sort(comp) {
var buff = [];
return $.through2.obj(function (file, enc, done) {
buff.push(file);
done(null);
}, function (done) {
buff.sort(comp).forEach(this.push.bind(this));
buff.length = 0;
done(null);
});
}
/**
* pipe transformer for file sorting
* @returns {lazypipe}
*/
function sortFiles() {
return sort(function (a, b) {
return b.path === a.path ? 0 : b.path > a.path ? 1 : -1;
});
}
/**
* Collect all hooks with given name from tasks
* @returns [string]
*/
function getHooks(name, recipes) {
return _.chain(recipes)
.pluck(name)
.filter()
.flatten()
.value();
}
return {
getPipes: getPipes,
mergedLazypipe: ops.mergedLazypipe,
parseSources: libSource.parse,
sequentialLazypipe: ops.sequentialLazypipe,
queuedLazypipe: ops.queuedLazypipe,
watchSource: watchSource,
runSubtasks: runSubtasks,
maybeTask: maybeTask,
RecipeError: errors.RecipeError,
NamedRecipeError: errors.NamedRecipeError,
checkMandatory: errors.checkMandatory,
sortFiles: sortFiles,
makeSources: makeSources,
getHooks: getHooks
};
};