globule.js
6.2 KB
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
/*
* globule
* https://github.com/cowboy/node-globule
*
* Copyright (c) 2018 "Cowboy" Ben Alman
* Licensed under the MIT license.
*/
'use strict';
var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var glob = require('glob');
var minimatch = require('minimatch');
// The module.
var globule = exports;
// Process specified wildcard glob patterns or filenames against a
// callback, excluding and uniquing files in the result set.
function processPatterns(patterns, options, fn) {
var result = [];
_.each(patterns, function(pattern) {
// The first character is not ! (inclusion). Add all matching filepaths
// to the result set.
if (pattern.indexOf('!') !== 0) {
result = _.union(result, fn(pattern));
return;
}
// The first character is ! (exclusion). Remove any filepaths from the
// result set that match this pattern, sans leading !.
var filterFn = minimatch.filter(pattern.slice(1), options);
result = _.filter(result, function(filepath) {
return !filterFn(filepath);
});
});
return result;
}
// Normalize paths to be unix-style.
var pathSeparatorRe = /[\/\\]/g;
function normalizePath(path) {
return path.replace(pathSeparatorRe, '/');
}
// Match a filepath or filepaths against one or more wildcard patterns. Returns
// all matching filepaths. This behaves just like minimatch.match, but supports
// any number of patterns.
globule.match = function(patterns, filepaths, options) {
// Return empty set if either patterns or filepaths was omitted.
if (patterns == null || filepaths == null) { return []; }
// Normalize patterns and filepaths to flattened arrays.
patterns = _.isArray(patterns) ? _.flattenDeep(patterns) : [patterns];
filepaths = _.isArray(filepaths) ? _.flattenDeep(filepaths) : [filepaths];
// Return empty set if there are no patterns or filepaths.
if (patterns.length === 0 || filepaths.length === 0) { return []; }
// Return all matching filepaths.
return processPatterns(patterns, options, function(pattern) {
return minimatch.match(filepaths, pattern, options || {});
});
};
// Match a filepath or filepaths against one or more wildcard patterns. Returns
// true if any of the patterns match.
globule.isMatch = function() {
return globule.match.apply(null, arguments).length > 0;
};
// Return an array of all file paths that match the given wildcard patterns.
globule.find = function() {
var args = _.toArray(arguments);
// If the last argument is an options object, remove it from args.
var options = _.isPlainObject(args[args.length - 1]) ? args.pop() : {};
// If options.src was specified, use it. Otherwise, use all non-options
// arguments. Flatten nested arrays.
var patterns;
if (options.src) {
patterns = _.isArray(options.src) ? _.flattenDeep(options.src) : [options.src];
} else {
patterns = _.flattenDeep(args);
}
// Return empty set if there are no patterns.
if (patterns.length === 0) { return []; }
var srcBase = options.srcBase || options.cwd;
// Create glob-specific options object.
var globOptions = _.extend({}, options);
if (srcBase) {
globOptions.cwd = srcBase;
}
// Get all matching filepaths.
var matches = processPatterns(patterns, options, function(pattern) {
return glob.sync(pattern, globOptions);
});
// If srcBase and prefixBase were specified, prefix srcBase to matched paths.
if (srcBase && options.prefixBase) {
matches = matches.map(function(filepath) {
return normalizePath(path.join(srcBase, filepath));
});
}
// Filter result set?
if (options.filter) {
matches = matches.filter(function(filepath) {
// If srcBase was specified but prefixBase was NOT, prefix srcBase
// temporarily, for filtering.
if (srcBase && !options.prefixBase) {
filepath = normalizePath(path.join(srcBase, filepath));
}
try {
if (_.isFunction(options.filter)) {
return options.filter(filepath, options);
} else {
// If the file is of the right type and exists, this should work.
return fs.statSync(filepath)[options.filter]();
}
} catch(err) {
// Otherwise, it's probably not the right type.
return false;
}
});
}
return matches;
};
var extDotRe = {
first: /(\.[^\/]*)?$/,
last: /(\.[^\/\.]*)?$/,
};
function rename(dest, options) {
// Flatten path?
if (options.flatten) {
dest = path.basename(dest);
}
// Change the extension?
if (options.ext) {
dest = dest.replace(extDotRe[options.extDot], options.ext);
}
// Join dest and destBase?
if (options.destBase) {
dest = path.join(options.destBase, dest);
}
return dest;
}
// Build a mapping of src-dest filepaths from the given set of filepaths.
globule.mapping = function(filepaths, options) {
// Return empty set if filepaths was omitted.
if (filepaths == null) { return []; }
options = _.defaults({}, options, {
extDot: 'first',
rename: rename,
});
var files = [];
var fileByDest = {};
// Find all files matching pattern, using passed-in options.
filepaths.forEach(function(src) {
// Generate destination filename.
var dest = options.rename(src, options);
// Prepend srcBase to all src paths.
if (options.srcBase) {
src = path.join(options.srcBase, src);
}
// Normalize filepaths to be unix-style.
dest = normalizePath(dest);
src = normalizePath(src);
// Map correct src path to dest path.
if (fileByDest[dest]) {
// If dest already exists, push this src onto that dest's src array.
fileByDest[dest].src.push(src);
} else {
// Otherwise create a new src-dest file mapping object.
files.push({
src: [src],
dest: dest,
});
// And store a reference for later use.
fileByDest[dest] = files[files.length - 1];
}
});
return files;
};
// Return a mapping of src-dest filepaths from files matching the given
// wildcard patterns.
globule.findMapping = function() {
var args = _.toArray(arguments);
// If the last argument is an options object, remove it from args.
var options = _.isPlainObject(args[args.length - 1]) ? args.pop() : {};
// Generate mapping from found filepaths.
return globule.mapping(globule.find(args, options), options);
};