3 var chars = require('./chars');
4 var utils = require('./utils');
10 var Glob = module.exports = function Glob(pattern, options) {
11 if (!(this instanceof Glob)) {
12 return new Glob(pattern, options);
14 this.options = options || {};
15 this.pattern = pattern;
25 Glob.prototype.init = function(pattern) {
27 this.negated = this.isNegated();
28 this.options.track = this.options.track || false;
29 this.options.makeRe = true;
33 * Push a change into `glob.history`. Useful
37 Glob.prototype.track = function(msg) {
38 if (this.options.track) {
39 this.history.push({msg: msg, pattern: this.pattern});
44 * Return true if `glob.pattern` was negated
45 * with `!`, also remove the `!` from the pattern.
50 Glob.prototype.isNegated = function() {
51 if (this.pattern.charCodeAt(0) === 33 /* '!' */) {
52 this.pattern = this.pattern.slice(1);
59 * Expand braces in the given glob pattern.
61 * We only need to use the [braces] lib when
62 * patterns are nested.
65 Glob.prototype.braces = function() {
66 if (this.options.nobraces !== true && this.options.nobrace !== true) {
67 // naive/fast check for imbalanced characters
68 var a = this.pattern.match(/[\{\(\[]/g);
69 var b = this.pattern.match(/[\}\)\]]/g);
71 // if imbalanced, don't optimize the pattern
72 if (a && b && (a.length !== b.length)) {
73 this.options.makeRe = false;
76 // expand brace patterns and join the resulting array
77 var expanded = utils.braces(this.pattern, this.options);
78 this.pattern = expanded.join('|');
83 * Expand bracket expressions in `glob.pattern`
86 Glob.prototype.brackets = function() {
87 if (this.options.nobrackets !== true) {
88 this.pattern = utils.brackets(this.pattern);
93 * Expand bracket expressions in `glob.pattern`
96 Glob.prototype.extglob = function() {
97 if (this.options.noextglob === true) return;
99 if (utils.isExtglob(this.pattern)) {
100 this.pattern = utils.extglob(this.pattern, {escape: true});
105 * Parse the given pattern
108 Glob.prototype.parse = function(pattern) {
109 this.tokens = utils.parseGlob(pattern || this.pattern, true);
114 * Replace `a` with `b`. Also tracks the change before and
115 * after each replacement. This is disabled by default, but
116 * can be enabled by setting `options.track` to true.
118 * Also, when the pattern is a string, `.split()` is used,
119 * because it's much faster than replace.
121 * @param {RegExp|String} `a`
122 * @param {String} `b`
123 * @param {Boolean} `escape` When `true`, escapes `*` and `?` in the replacement.
127 Glob.prototype._replace = function(a, b, escape) {
128 this.track('before (find): "' + a + '" (replace with): "' + b + '"');
129 if (escape) b = esc(b);
130 if (a && b && typeof a === 'string') {
131 this.pattern = this.pattern.split(a).join(b);
133 this.pattern = this.pattern.replace(a, b);
139 * Escape special characters in the given string.
141 * @param {String} `str` Glob pattern
145 Glob.prototype.escape = function(str) {
146 this.track('before escape: ');
147 var re = /["\\](['"]?[^"'\\]['"]?)/g;
149 this.pattern = str.replace(re, function($0, $1) {
155 if (/[a-z]/i.test($0)) {
156 return $0.split('\\').join('');
161 this.track('after escape: ');
165 * Unescape special characters in the given string.
167 * @param {String} `str`
171 Glob.prototype.unescape = function(str) {
172 var re = /__([A-Z]+)_([A-Z]+)__/g;
173 this.pattern = str.replace(re, function($0, $1) {
174 return chars[$1][$0];
176 this.pattern = unesc(this.pattern);
180 * Escape/unescape utils
184 str = str.split('?').join('%~');
185 str = str.split('*').join('%%');
189 function unesc(str) {
190 str = str.split('%~').join('?');
191 str = str.split('%%').join('*');