You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
4.1 KiB
193 lines
4.1 KiB
'use strict'; |
|
|
|
var chars = require('./chars'); |
|
var utils = require('./utils'); |
|
|
|
/** |
|
* Expose `Glob` |
|
*/ |
|
|
|
var Glob = module.exports = function Glob(pattern, options) { |
|
if (!(this instanceof Glob)) { |
|
return new Glob(pattern, options); |
|
} |
|
this.options = options || {}; |
|
this.pattern = pattern; |
|
this.history = []; |
|
this.tokens = {}; |
|
this.init(pattern); |
|
}; |
|
|
|
/** |
|
* Initialize defaults |
|
*/ |
|
|
|
Glob.prototype.init = function(pattern) { |
|
this.orig = pattern; |
|
this.negated = this.isNegated(); |
|
this.options.track = this.options.track || false; |
|
this.options.makeRe = true; |
|
}; |
|
|
|
/** |
|
* Push a change into `glob.history`. Useful |
|
* for debugging. |
|
*/ |
|
|
|
Glob.prototype.track = function(msg) { |
|
if (this.options.track) { |
|
this.history.push({msg: msg, pattern: this.pattern}); |
|
} |
|
}; |
|
|
|
/** |
|
* Return true if `glob.pattern` was negated |
|
* with `!`, also remove the `!` from the pattern. |
|
* |
|
* @return {Boolean} |
|
*/ |
|
|
|
Glob.prototype.isNegated = function() { |
|
if (this.pattern.charCodeAt(0) === 33 /* '!' */) { |
|
this.pattern = this.pattern.slice(1); |
|
return true; |
|
} |
|
return false; |
|
}; |
|
|
|
/** |
|
* Expand braces in the given glob pattern. |
|
* |
|
* We only need to use the [braces] lib when |
|
* patterns are nested. |
|
*/ |
|
|
|
Glob.prototype.braces = function() { |
|
if (this.options.nobraces !== true && this.options.nobrace !== true) { |
|
// naive/fast check for imbalanced characters |
|
var a = this.pattern.match(/[\{\(\[]/g); |
|
var b = this.pattern.match(/[\}\)\]]/g); |
|
|
|
// if imbalanced, don't optimize the pattern |
|
if (a && b && (a.length !== b.length)) { |
|
this.options.makeRe = false; |
|
} |
|
|
|
// expand brace patterns and join the resulting array |
|
var expanded = utils.braces(this.pattern, this.options); |
|
this.pattern = expanded.join('|'); |
|
} |
|
}; |
|
|
|
/** |
|
* Expand bracket expressions in `glob.pattern` |
|
*/ |
|
|
|
Glob.prototype.brackets = function() { |
|
if (this.options.nobrackets !== true) { |
|
this.pattern = utils.brackets(this.pattern); |
|
} |
|
}; |
|
|
|
/** |
|
* Expand bracket expressions in `glob.pattern` |
|
*/ |
|
|
|
Glob.prototype.extglob = function() { |
|
if (this.options.noextglob === true) return; |
|
|
|
if (utils.isExtglob(this.pattern)) { |
|
this.pattern = utils.extglob(this.pattern, {escape: true}); |
|
} |
|
}; |
|
|
|
/** |
|
* Parse the given pattern |
|
*/ |
|
|
|
Glob.prototype.parse = function(pattern) { |
|
this.tokens = utils.parseGlob(pattern || this.pattern, true); |
|
return this.tokens; |
|
}; |
|
|
|
/** |
|
* Replace `a` with `b`. Also tracks the change before and |
|
* after each replacement. This is disabled by default, but |
|
* can be enabled by setting `options.track` to true. |
|
* |
|
* Also, when the pattern is a string, `.split()` is used, |
|
* because it's much faster than replace. |
|
* |
|
* @param {RegExp|String} `a` |
|
* @param {String} `b` |
|
* @param {Boolean} `escape` When `true`, escapes `*` and `?` in the replacement. |
|
* @return {String} |
|
*/ |
|
|
|
Glob.prototype._replace = function(a, b, escape) { |
|
this.track('before (find): "' + a + '" (replace with): "' + b + '"'); |
|
if (escape) b = esc(b); |
|
if (a && b && typeof a === 'string') { |
|
this.pattern = this.pattern.split(a).join(b); |
|
} else { |
|
this.pattern = this.pattern.replace(a, b); |
|
} |
|
this.track('after'); |
|
}; |
|
|
|
/** |
|
* Escape special characters in the given string. |
|
* |
|
* @param {String} `str` Glob pattern |
|
* @return {String} |
|
*/ |
|
|
|
Glob.prototype.escape = function(str) { |
|
this.track('before escape: '); |
|
var re = /["\\](['"]?[^"'\\]['"]?)/g; |
|
|
|
this.pattern = str.replace(re, function($0, $1) { |
|
var o = chars.ESC; |
|
var ch = o && o[$1]; |
|
if (ch) { |
|
return ch; |
|
} |
|
if (/[a-z]/i.test($0)) { |
|
return $0.split('\\').join(''); |
|
} |
|
return $0; |
|
}); |
|
|
|
this.track('after escape: '); |
|
}; |
|
|
|
/** |
|
* Unescape special characters in the given string. |
|
* |
|
* @param {String} `str` |
|
* @return {String} |
|
*/ |
|
|
|
Glob.prototype.unescape = function(str) { |
|
var re = /__([A-Z]+)_([A-Z]+)__/g; |
|
this.pattern = str.replace(re, function($0, $1) { |
|
return chars[$1][$0]; |
|
}); |
|
this.pattern = unesc(this.pattern); |
|
}; |
|
|
|
/** |
|
* Escape/unescape utils |
|
*/ |
|
|
|
function esc(str) { |
|
str = str.split('?').join('%~'); |
|
str = str.split('*').join('%%'); |
|
return str; |
|
} |
|
|
|
function unesc(str) { |
|
str = str.split('%~').join('?'); |
|
str = str.split('%%').join('*'); |
|
return str; |
|
}
|
|
|