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