192 lines
6.2 KiB
JavaScript
192 lines
6.2 KiB
JavaScript
/*
|
|
* 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);
|
|
};
|