Projekt

Obecné

Profil

Stáhnout (8.6 KB) Statistiky
| Větev: | Revize:
1
'use strict';
2

    
3
var utils = module.exports;
4
var path = require('path');
5

    
6
/**
7
 * Module dependencies
8
 */
9

    
10
var isWindows = require('is-windows')();
11
var Snapdragon = require('snapdragon');
12
utils.define = require('define-property');
13
utils.diff = require('arr-diff');
14
utils.extend = require('extend-shallow');
15
utils.pick = require('object.pick');
16
utils.typeOf = require('kind-of');
17
utils.unique = require('array-unique');
18

    
19
/**
20
 * Returns true if the given value is effectively an empty string
21
 */
22

    
23
utils.isEmptyString = function(val) {
24
  return String(val) === '' || String(val) === './';
25
};
26

    
27
/**
28
 * Returns true if the platform is windows, or `path.sep` is `\\`.
29
 * This is defined as a function to allow `path.sep` to be set in unit tests,
30
 * or by the user, if there is a reason to do so.
31
 * @return {Boolean}
32
 */
33

    
34
utils.isWindows = function() {
35
  return path.sep === '\\' || isWindows === true;
36
};
37

    
38
/**
39
 * Return the last element from an array
40
 */
41

    
42
utils.last = function(arr, n) {
43
  return arr[arr.length - (n || 1)];
44
};
45

    
46
/**
47
 * Get the `Snapdragon` instance to use
48
 */
49

    
50
utils.instantiate = function(ast, options) {
51
  var snapdragon;
52
  // if an instance was created by `.parse`, use that instance
53
  if (utils.typeOf(ast) === 'object' && ast.snapdragon) {
54
    snapdragon = ast.snapdragon;
55
  // if the user supplies an instance on options, use that instance
56
  } else if (utils.typeOf(options) === 'object' && options.snapdragon) {
57
    snapdragon = options.snapdragon;
58
  // create a new instance
59
  } else {
60
    snapdragon = new Snapdragon(options);
61
  }
62

    
63
  utils.define(snapdragon, 'parse', function(str, options) {
64
    var parsed = Snapdragon.prototype.parse.call(this, str, options);
65
    parsed.input = str;
66

    
67
    // escape unmatched brace/bracket/parens
68
    var last = this.parser.stack.pop();
69
    if (last && this.options.strictErrors !== true) {
70
      var open = last.nodes[0];
71
      var inner = last.nodes[1];
72
      if (last.type === 'bracket') {
73
        if (inner.val.charAt(0) === '[') {
74
          inner.val = '\\' + inner.val;
75
        }
76

    
77
      } else {
78
        open.val = '\\' + open.val;
79
        var sibling = open.parent.nodes[1];
80
        if (sibling.type === 'star') {
81
          sibling.loose = true;
82
        }
83
      }
84
    }
85

    
86
    // add non-enumerable parser reference
87
    utils.define(parsed, 'parser', this.parser);
88
    return parsed;
89
  });
90

    
91
  return snapdragon;
92
};
93

    
94
/**
95
 * Create the key to use for memoization. The key is generated
96
 * by iterating over the options and concatenating key-value pairs
97
 * to the pattern string.
98
 */
99

    
100
utils.createKey = function(pattern, options) {
101
  if (typeof options === 'undefined') {
102
    return pattern;
103
  }
104
  var key = pattern;
105
  for (var prop in options) {
106
    if (options.hasOwnProperty(prop)) {
107
      key += ';' + prop + '=' + String(options[prop]);
108
    }
109
  }
110
  return key;
111
};
112

    
113
/**
114
 * Cast `val` to an array
115
 * @return {Array}
116
 */
117

    
118
utils.arrayify = function(val) {
119
  if (typeof val === 'string') return [val];
120
  return val ? (Array.isArray(val) ? val : [val]) : [];
121
};
122

    
123
/**
124
 * Return true if `val` is a non-empty string
125
 */
126

    
127
utils.isString = function(val) {
128
  return typeof val === 'string';
129
};
130

    
131
/**
132
 * Return true if `val` is a non-empty string
133
 */
134

    
135
utils.isRegex = function(val) {
136
  return utils.typeOf(val) === 'regexp';
137
};
138

    
139
/**
140
 * Return true if `val` is a non-empty string
141
 */
142

    
143
utils.isObject = function(val) {
144
  return utils.typeOf(val) === 'object';
145
};
146

    
147
/**
148
 * Escape regex characters in the given string
149
 */
150

    
151
utils.escapeRegex = function(str) {
152
  return str.replace(/[-[\]{}()^$|*+?.\\/\s]/g, '\\$&');
153
};
154

    
155
/**
156
 * Combines duplicate characters in the provided `input` string.
157
 * @param {String} `input`
158
 * @returns {String}
159
 */
160

    
161
utils.combineDupes = function(input, patterns) {
162
  patterns = utils.arrayify(patterns).join('|').split('|');
163
  patterns = patterns.map(function(s) {
164
    return s.replace(/\\?([+*\\/])/g, '\\$1');
165
  });
166
  var substr = patterns.join('|');
167
  var regex = new RegExp('(' + substr + ')(?=\\1)', 'g');
168
  return input.replace(regex, '');
169
};
170

    
171
/**
172
 * Returns true if the given `str` has special characters
173
 */
174

    
175
utils.hasSpecialChars = function(str) {
176
  return /(?:(?:(^|\/)[!.])|[*?+()|[\]{}]|[+@]\()/.test(str);
177
};
178

    
179
/**
180
 * Normalize slashes in the given filepath.
181
 *
182
 * @param {String} `filepath`
183
 * @return {String}
184
 */
185

    
186
utils.toPosixPath = function(str) {
187
  return str.replace(/\\+/g, '/');
188
};
189

    
190
/**
191
 * Strip backslashes before special characters in a string.
192
 *
193
 * @param {String} `str`
194
 * @return {String}
195
 */
196

    
197
utils.unescape = function(str) {
198
  return utils.toPosixPath(str.replace(/\\(?=[*+?!.])/g, ''));
199
};
200

    
201
/**
202
 * Strip the drive letter from a windows filepath
203
 * @param {String} `fp`
204
 * @return {String}
205
 */
206

    
207
utils.stripDrive = function(fp) {
208
  return utils.isWindows() ? fp.replace(/^[a-z]:[\\/]+?/i, '/') : fp;
209
};
210

    
211
/**
212
 * Strip the prefix from a filepath
213
 * @param {String} `fp`
214
 * @return {String}
215
 */
216

    
217
utils.stripPrefix = function(str) {
218
  if (str.charAt(0) === '.' && (str.charAt(1) === '/' || str.charAt(1) === '\\')) {
219
    return str.slice(2);
220
  }
221
  return str;
222
};
223

    
224
/**
225
 * Returns true if `str` is a common character that doesn't need
226
 * to be processed to be used for matching.
227
 * @param {String} `str`
228
 * @return {Boolean}
229
 */
230

    
231
utils.isSimpleChar = function(str) {
232
  return str.trim() === '' || str === '.';
233
};
234

    
235
/**
236
 * Returns true if the given str is an escaped or
237
 * unescaped path character
238
 */
239

    
240
utils.isSlash = function(str) {
241
  return str === '/' || str === '\\/' || str === '\\' || str === '\\\\';
242
};
243

    
244
/**
245
 * Returns a function that returns true if the given
246
 * pattern matches or contains a `filepath`
247
 *
248
 * @param {String} `pattern`
249
 * @return {Function}
250
 */
251

    
252
utils.matchPath = function(pattern, options) {
253
  return (options && options.contains)
254
    ? utils.containsPattern(pattern, options)
255
    : utils.equalsPattern(pattern, options);
256
};
257

    
258
/**
259
 * Returns true if the given (original) filepath or unixified path are equal
260
 * to the given pattern.
261
 */
262

    
263
utils._equals = function(filepath, unixPath, pattern) {
264
  return pattern === filepath || pattern === unixPath;
265
};
266

    
267
/**
268
 * Returns true if the given (original) filepath or unixified path contain
269
 * the given pattern.
270
 */
271

    
272
utils._contains = function(filepath, unixPath, pattern) {
273
  return filepath.indexOf(pattern) !== -1 || unixPath.indexOf(pattern) !== -1;
274
};
275

    
276
/**
277
 * Returns a function that returns true if the given
278
 * pattern is the same as a given `filepath`
279
 *
280
 * @param {String} `pattern`
281
 * @return {Function}
282
 */
283

    
284
utils.equalsPattern = function(pattern, options) {
285
  var unixify = utils.unixify(options);
286
  options = options || {};
287

    
288
  return function fn(filepath) {
289
    var equal = utils._equals(filepath, unixify(filepath), pattern);
290
    if (equal === true || options.nocase !== true) {
291
      return equal;
292
    }
293
    var lower = filepath.toLowerCase();
294
    return utils._equals(lower, unixify(lower), pattern);
295
  };
296
};
297

    
298
/**
299
 * Returns a function that returns true if the given
300
 * pattern contains a `filepath`
301
 *
302
 * @param {String} `pattern`
303
 * @return {Function}
304
 */
305

    
306
utils.containsPattern = function(pattern, options) {
307
  var unixify = utils.unixify(options);
308
  options = options || {};
309

    
310
  return function(filepath) {
311
    var contains = utils._contains(filepath, unixify(filepath), pattern);
312
    if (contains === true || options.nocase !== true) {
313
      return contains;
314
    }
315
    var lower = filepath.toLowerCase();
316
    return utils._contains(lower, unixify(lower), pattern);
317
  };
318
};
319

    
320
/**
321
 * Returns a function that returns true if the given
322
 * regex matches the `filename` of a file path.
323
 *
324
 * @param {RegExp} `re` Matching regex
325
 * @return {Function}
326
 */
327

    
328
utils.matchBasename = function(re) {
329
  return function(filepath) {
330
    return re.test(filepath) || re.test(path.basename(filepath));
331
  };
332
};
333

    
334
/**
335
 * Returns the given value unchanced.
336
 * @return {any}
337
 */
338

    
339
utils.identity = function(val) {
340
  return val;
341
};
342

    
343
/**
344
 * Determines the filepath to return based on the provided options.
345
 * @return {any}
346
 */
347

    
348
utils.value = function(str, unixify, options) {
349
  if (options && options.unixify === false) {
350
    return str;
351
  }
352
  if (options && typeof options.unixify === 'function') {
353
    return options.unixify(str);
354
  }
355
  return unixify(str);
356
};
357

    
358
/**
359
 * Returns a function that normalizes slashes in a string to forward
360
 * slashes, strips `./` from beginning of paths, and optionally unescapes
361
 * special characters.
362
 * @return {Function}
363
 */
364

    
365
utils.unixify = function(options) {
366
  var opts = options || {};
367
  return function(filepath) {
368
    if (opts.stripPrefix !== false) {
369
      filepath = utils.stripPrefix(filepath);
370
    }
371
    if (opts.unescape === true) {
372
      filepath = utils.unescape(filepath);
373
    }
374
    if (opts.unixify === true || utils.isWindows()) {
375
      filepath = utils.toPosixPath(filepath);
376
    }
377
    return filepath;
378
  };
379
};
(4-4/4)