Initial commit
[yaffs-website] / node_modules / globule / lib / globule.js
1 /*
2  * globule
3  * https://github.com/cowboy/node-globule
4  *
5  * Copyright (c) 2013 "Cowboy" Ben Alman
6  * Licensed under the MIT license.
7  */
8
9 'use strict';
10
11 var fs = require('fs');
12 var path = require('path');
13
14 var _ = require('lodash');
15 var glob = require('glob');
16 var minimatch = require('minimatch');
17
18 // The module.
19 var globule = exports;
20
21 // Process specified wildcard glob patterns or filenames against a
22 // callback, excluding and uniquing files in the result set.
23 function processPatterns(patterns, fn) {
24   return _.flatten(patterns).reduce(function(result, pattern) {
25     if (pattern.indexOf('!') === 0) {
26       // If the first character is ! all matches via this pattern should be
27       // removed from the result set.
28       pattern = pattern.slice(1);
29       return _.difference(result, fn(pattern));
30     } else {
31       // Otherwise, add all matching filepaths to the result set.
32       return _.union(result, fn(pattern));
33     }
34   }, []);
35 }
36
37 // Match a filepath or filepaths against one or more wildcard patterns. Returns
38 // all matching filepaths. This behaves just like minimatch.match, but supports
39 // any number of patterns.
40 globule.match = function(patterns, filepaths, options) {
41   // Return empty set if either patterns or filepaths was omitted.
42   if (patterns == null || filepaths == null) { return []; }
43   // Normalize patterns and filepaths to arrays.
44   if (!_.isArray(patterns)) { patterns = [patterns]; }
45   if (!_.isArray(filepaths)) { filepaths = [filepaths]; }
46   // Return empty set if there are no patterns or filepaths.
47   if (patterns.length === 0 || filepaths.length === 0) { return []; }
48   // Return all matching filepaths.
49   return processPatterns(patterns, function(pattern) {
50     return minimatch.match(filepaths, pattern, options || {});
51   });
52 };
53
54 // Match a filepath or filepaths against one or more wildcard patterns. Returns
55 // true if any of the patterns match.
56 globule.isMatch = function() {
57   return globule.match.apply(null, arguments).length > 0;
58 };
59
60 // Return an array of all file paths that match the given wildcard patterns.
61 globule.find = function() {
62   var args = _.toArray(arguments);
63   // If the last argument is an options object, remove it from args.
64   var options = _.isPlainObject(args[args.length - 1]) ? args.pop() : {};
65   // Use the first argument if it's an Array, otherwise use all arguments.
66   var patterns = _.isArray(args[0]) ? args[0] : args;
67   // Return empty set if there are no patterns or filepaths.
68   if (patterns.length === 0) { return []; }
69   var srcBase = options.srcBase || options.cwd;
70   // Create glob-specific options object.
71   var globOptions = _.extend({}, options);
72   if (srcBase) {
73     globOptions.cwd = srcBase;
74   }
75   // Get all matching filepaths.
76   var matches = processPatterns(patterns, function(pattern) {
77     return glob.sync(pattern, globOptions);
78   });
79   // If srcBase and prefixBase were specified, prefix srcBase to matched paths.
80   if (srcBase && options.prefixBase) {
81     matches = matches.map(function(filepath) {
82       return path.join(srcBase, filepath);
83     });
84   }
85   // Filter result set?
86   if (options.filter) {
87     matches = matches.filter(function(filepath) {
88       // If srcBase was specified but prefixBase was NOT, prefix srcBase
89       // temporarily, for filtering.
90       if (srcBase && !options.prefixBase) {
91         filepath = path.join(srcBase, filepath);
92       }
93       try {
94         if (_.isFunction(options.filter)) {
95           return options.filter(filepath, options);
96         } else {
97           // If the file is of the right type and exists, this should work.
98           return fs.statSync(filepath)[options.filter]();
99         }
100       } catch(err) {
101         // Otherwise, it's probably not the right type.
102         return false;
103       }
104     });
105   }
106   return matches;
107 };
108
109 var pathSeparatorRe = /[\/\\]/g;
110 var extDotRe = {
111   first: /(\.[^\/]*)?$/,
112   last: /(\.[^\/\.]*)?$/,
113 };
114 function rename(dest, options) {
115   // Flatten path?
116   if (options.flatten) {
117     dest = path.basename(dest);
118   }
119   // Change the extension?
120   if (options.ext) {
121     dest = dest.replace(extDotRe[options.extDot], options.ext);
122   }
123   // Join dest and destBase?
124   if (options.destBase) {
125     dest = path.join(options.destBase, dest);
126   }
127   return dest;
128 }
129
130 // Build a mapping of src-dest filepaths from the given set of filepaths.
131 globule.mapping = function(filepaths, options) {
132   // Return empty set if filepaths was omitted.
133   if (filepaths == null) { return []; }
134   options = _.defaults({}, options, {
135     extDot: 'first',
136     rename: rename,
137   });
138   var files = [];
139   var fileByDest = {};
140   // Find all files matching pattern, using passed-in options.
141   filepaths.forEach(function(src) {
142     // Generate destination filename.
143     var dest = options.rename(src, options);
144     // Prepend srcBase to all src paths.
145     if (options.srcBase) {
146       src = path.join(options.srcBase, src);
147     }
148     // Normalize filepaths to be unix-style.
149     dest = dest.replace(pathSeparatorRe, '/');
150     src = src.replace(pathSeparatorRe, '/');
151     // Map correct src path to dest path.
152     if (fileByDest[dest]) {
153       // If dest already exists, push this src onto that dest's src array.
154       fileByDest[dest].src.push(src);
155     } else {
156       // Otherwise create a new src-dest file mapping object.
157       files.push({
158         src: [src],
159         dest: dest,
160       });
161       // And store a reference for later use.
162       fileByDest[dest] = files[files.length - 1];
163     }
164   });
165   return files;
166 };
167
168 // Return a mapping of src-dest filepaths from files matching the given
169 // wildcard patterns.
170 globule.findMapping = function(patterns, options) {
171   return globule.mapping(globule.find(patterns, options), options);
172 };