UNPKG

4.63 kBJavaScriptView Raw
1'use strict';
2
3var brackets = require('expand-brackets');
4var extglob = require('extglob');
5var braces = require('braces');
6var parse = require('parse-glob');
7var chars = require('./chars');
8
9/**
10 * Expose `Glob`
11 */
12
13module.exports = Glob;
14
15function Glob(pattern, options) {
16 this.options = options || {};
17 this.pattern = pattern;
18 this.history = [];
19 this.tokens = {};
20 this.init(pattern);
21}
22
23Glob.prototype.init = function(pattern) {
24 this.orig = pattern;
25 this.negated = this.isNegated();
26 this.options.track = this.options.track || false;
27 this.options.dot = this.options.dot || this.options.dotfiles;
28 this.options.makeRe = true;
29};
30
31/**
32 * Push a change into `glob.history`. Useful
33 * for debugging.
34 */
35
36Glob.prototype.track = function(msg) {
37 if (this.options.track) {
38 this.history.push({msg: msg, pattern: this.pattern});
39 }
40};
41
42/**
43 * Return true if the glob pattern has the given
44 * `ch`aracter.
45 *
46 * @param {String} `pattern`
47 * @param {String} `ch`
48 * @return {Boolean}
49 */
50
51Glob.prototype.has = function(pattern, ch) {
52 if (ch instanceof RegExp) {
53 return ch.test(pattern);
54 }
55 return pattern.indexOf(ch) !== -1;
56};
57
58/**
59 * Return true if `glob.pattern` was negated
60 * with `!`. Also removes the `!` from the pattern.
61 *
62 * @return {Boolean}
63 */
64
65Glob.prototype.isNegated = function() {
66 if (this.pattern.charCodeAt(0) === 33 /* '!' */) {
67 this.pattern = this.pattern.slice(1);
68 return true;
69 }
70 return false;
71};
72
73/**
74 * Return true if the glob pattern has braces
75 *
76 * @param {String} `pattern`
77 * @return {Boolean}
78 */
79
80Glob.prototype.hasBraces = function(pattern) {
81 return this.has((pattern || this.pattern), '{');
82};
83
84/**
85 * Expand braces in the given glob pattern.
86 *
87 * We only need to use the [braces] lib when
88 * patterns are nested.
89 */
90
91Glob.prototype.braces = function() {
92 if (this.hasBraces() && this.options.nobraces !== true) {
93 var a = this.pattern.match(/[\{\(\[]/g);
94 var b = this.pattern.match(/[\}\)\]]/g);
95 if (a && b && (a.length !== b.length)) {
96 this.options.makeRe = false;
97 }
98 var expanded = braces(this.pattern, this.options);
99 this.pattern = expanded.join('|');
100 }
101};
102
103/**
104 * Return true if the glob pattern has a POSIX
105 * bracket expression (character class)
106 *
107 * @param {String} `pattern`
108 * @return {Boolean}
109 */
110
111Glob.prototype.hasBrackets = function(pattern) {
112 return this.has((pattern || this.pattern), '[:');
113};
114
115/**
116 * Expand bracket expressions in `glob.pattern`
117 */
118
119Glob.prototype.brackets = function() {
120 if (this.hasBrackets() && this.options.nobrackets !== true) {
121 this.pattern = brackets(this.pattern);
122 }
123};
124
125/**
126 * Return true if the glob pattern has an extglob
127 * pattern.
128 *
129 * @param {String} `pattern`
130 * @return {Boolean}
131 */
132
133Glob.prototype.hasExtglob = function(pattern) {
134 var re = /[@?!+*]\(/;
135 return this.has((pattern || this.pattern), re);
136};
137
138/**
139 * Expand extended globs in `glob.pattern`
140 */
141
142Glob.prototype.extglob = function() {
143 if (this.hasExtglob() && this.options.noextglob !== true) {
144 this.pattern = extglob(this.pattern);
145 }
146};
147
148/**
149 * Parse the given glob `pattern` or `glob.pattern`
150 */
151
152Glob.prototype.parse = function(pattern) {
153 this.tokens = parse(pattern || this.pattern, true);
154 return this.tokens;
155};
156
157/**
158 * Replace `a` with `b`. Also tracks the change
159 * before and after each replacement. This is
160 * disabled by default, but can be enabled by
161 * setting `options.track` to true.
162 *
163 * @param {RegExp|String} `a`
164 * @param {String} `b`
165 * @return {String}
166 */
167
168Glob.prototype.repl = function(a, b) {
169 this.track('before repl: ');
170 if (a && b && typeof a === 'string') {
171 this.pattern = this.pattern.split(a).join(b);
172 } else if (a instanceof RegExp) {
173 try {
174 this.pattern = this.pattern.replace(a, b);
175 } catch(err) {}
176 }
177 this.track('after repl: ');
178};
179
180/**
181 * Escape special characters in the given string.
182 *
183 * @param {String} `str` Glob pattern
184 * @return {String}
185 */
186
187Glob.prototype.escape = function(str) {
188 this.track('before escape: ');
189
190 var re = /["\\](['"]?[^"'\\]['"]?)/g;
191 this.pattern = str.replace(re, function($0, $1) {
192 var o = chars.ESC;
193 var ch = o && o[$1];
194 if (ch) {
195 return ch;
196 }
197 if (/[a-z]/i.test($0)) {
198 return $0.split('\\').join('');
199 }
200 return $0;
201 });
202
203 this.track('after escape: ');
204};
205
206/**
207 * Unescape special characters in the given string.
208 *
209 * @param {String} `str`
210 * @return {String}
211 */
212
213Glob.prototype.unescape = function(str) {
214 var re = /__([A-Z]+)_([A-Z]+)__/g;
215 this.pattern = str.replace(re, function($0, $1) {
216 return chars[$1][$0];
217 });
218};