.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / nanomatch / lib / parsers.js
1 'use strict';
2
3 var regexNot = require('regex-not');
4 var toRegex = require('to-regex');
5
6 /**
7  * Characters to use in negation regex (we want to "not" match
8  * characters that are matched by other parsers)
9  */
10
11 var cached;
12 var NOT_REGEX = '[\\[!*+?$^"\'.\\\\/]+';
13 var not = createTextRegex(NOT_REGEX);
14
15 /**
16  * Nanomatch parsers
17  */
18
19 module.exports = function(nanomatch, options) {
20   var parser = nanomatch.parser;
21   var opts = parser.options;
22
23   parser.state = {
24     slashes: 0,
25     paths: []
26   };
27
28   parser.ast.state = parser.state;
29   parser
30
31     /**
32      * Beginning-of-string
33      */
34
35     .capture('prefix', function() {
36       if (this.parsed) return;
37       var m = this.match(/^\.[\\/]/);
38       if (!m) return;
39       this.state.strictOpen = !!this.options.strictOpen;
40       this.state.addPrefix = true;
41     })
42
43     /**
44      * Escape: "\\."
45      */
46
47     .capture('escape', function() {
48       if (this.isInside('bracket')) return;
49       var pos = this.position();
50       var m = this.match(/^(?:\\(.)|([$^]))/);
51       if (!m) return;
52
53       return pos({
54         type: 'escape',
55         val: m[2] || m[1]
56       });
57     })
58
59     /**
60      * Quoted strings
61      */
62
63     .capture('quoted', function() {
64       var pos = this.position();
65       var m = this.match(/^["']/);
66       if (!m) return;
67
68       var quote = m[0];
69       if (this.input.indexOf(quote) === -1) {
70         return pos({
71           type: 'escape',
72           val: quote
73         });
74       }
75
76       var tok = advanceTo(this.input, quote);
77       this.consume(tok.len);
78
79       return pos({
80         type: 'quoted',
81         val: tok.esc
82       });
83     })
84
85     /**
86      * Negations: "!"
87      */
88
89     .capture('not', function() {
90       var parsed = this.parsed;
91       var pos = this.position();
92       var m = this.match(this.notRegex || /^!+/);
93       if (!m) return;
94       var val = m[0];
95
96       var isNegated = (val.length % 2) === 1;
97       if (parsed === '' && !isNegated) {
98         val = '';
99       }
100
101       // if nothing has been parsed, we know `!` is at the start,
102       // so we need to wrap the result in a negation regex
103       if (parsed === '' && isNegated && this.options.nonegate !== true) {
104         this.bos.val = '(?!^(?:';
105         this.append = ')$).*';
106         val = '';
107       }
108       return pos({
109         type: 'not',
110         val: val
111       });
112     })
113
114     /**
115      * Dot: "."
116      */
117
118     .capture('dot', function() {
119       var parsed = this.parsed;
120       var pos = this.position();
121       var m = this.match(/^\.+/);
122       if (!m) return;
123
124       var val = m[0];
125       this.state.dot = val === '.' && (parsed === '' || parsed.slice(-1) === '/');
126
127       return pos({
128         type: 'dot',
129         dotfiles: this.state.dot,
130         val: val
131       });
132     })
133
134     /**
135      * Plus: "+"
136      */
137
138     .capture('plus', /^\+(?!\()/)
139
140     /**
141      * Question mark: "?"
142      */
143
144     .capture('qmark', function() {
145       var parsed = this.parsed;
146       var pos = this.position();
147       var m = this.match(/^\?+(?!\()/);
148       if (!m) return;
149
150       this.state.metachar = true;
151       this.state.qmark = true;
152
153       return pos({
154         type: 'qmark',
155         parsed: parsed,
156         val: m[0]
157       });
158     })
159
160     /**
161      * Globstar: "**"
162      */
163
164     .capture('globstar', function() {
165       var parsed = this.parsed;
166       var pos = this.position();
167       var m = this.match(/^\*{2}(?![*(])(?=[,)/]|$)/);
168       if (!m) return;
169
170       var type = opts.noglobstar !== true ? 'globstar' : 'star';
171       var node = pos({type: type, parsed: parsed});
172       this.state.metachar = true;
173
174       while (this.input.slice(0, 4) === '/**/') {
175         this.input = this.input.slice(3);
176       }
177
178       node.isInside = {
179         brace: this.isInside('brace'),
180         paren: this.isInside('paren')
181       };
182
183       if (type === 'globstar') {
184         this.state.globstar = true;
185         node.val = '**';
186
187       } else {
188         this.state.star = true;
189         node.val = '*';
190       }
191
192       return node;
193     })
194
195     /**
196      * Star: "*"
197      */
198
199     .capture('star', function() {
200       var pos = this.position();
201       var starRe = /^(?:\*(?![*(])|[*]{3,}(?!\()|[*]{2}(?![(/]|$)|\*(?=\*\())/;
202       var m = this.match(starRe);
203       if (!m) return;
204
205       this.state.metachar = true;
206       this.state.star = true;
207       return pos({
208         type: 'star',
209         val: m[0]
210       });
211     })
212
213     /**
214      * Slash: "/"
215      */
216
217     .capture('slash', function() {
218       var pos = this.position();
219       var m = this.match(/^\//);
220       if (!m) return;
221
222       this.state.slashes++;
223       return pos({
224         type: 'slash',
225         val: m[0]
226       });
227     })
228
229     /**
230      * Backslash: "\\"
231      */
232
233     .capture('backslash', function() {
234       var pos = this.position();
235       var m = this.match(/^\\(?![*+?(){}[\]'"])/);
236       if (!m) return;
237
238       var val = m[0];
239
240       if (this.isInside('bracket')) {
241         val = '\\';
242       } else if (val.length > 1) {
243         val = '\\\\';
244       }
245
246       return pos({
247         type: 'backslash',
248         val: val
249       });
250     })
251
252     /**
253      * Square: "[.]"
254      */
255
256     .capture('square', function() {
257       if (this.isInside('bracket')) return;
258       var pos = this.position();
259       var m = this.match(/^\[([^!^\\])\]/);
260       if (!m) return;
261
262       return pos({
263         type: 'square',
264         val: m[1]
265       });
266     })
267
268     /**
269      * Brackets: "[...]" (basic, this can be overridden by other parsers)
270      */
271
272     .capture('bracket', function() {
273       var pos = this.position();
274       var m = this.match(/^(?:\[([!^]?)([^\]]+|\]-)(\]|[^*+?]+)|\[)/);
275       if (!m) return;
276
277       var val = m[0];
278       var negated = m[1] ? '^' : '';
279       var inner = (m[2] || '').replace(/\\\\+/, '\\\\');
280       var close = m[3] || '';
281
282       if (m[2] && inner.length < m[2].length) {
283         val = val.replace(/\\\\+/, '\\\\');
284       }
285
286       var esc = this.input.slice(0, 2);
287       if (inner === '' && esc === '\\]') {
288         inner += esc;
289         this.consume(2);
290
291         var str = this.input;
292         var idx = -1;
293         var ch;
294
295         while ((ch = str[++idx])) {
296           this.consume(1);
297           if (ch === ']') {
298             close = ch;
299             break;
300           }
301           inner += ch;
302         }
303       }
304
305       return pos({
306         type: 'bracket',
307         val: val,
308         escaped: close !== ']',
309         negated: negated,
310         inner: inner,
311         close: close
312       });
313     })
314
315     /**
316      * Text
317      */
318
319     .capture('text', function() {
320       if (this.isInside('bracket')) return;
321       var pos = this.position();
322       var m = this.match(not);
323       if (!m || !m[0]) return;
324
325       return pos({
326         type: 'text',
327         val: m[0]
328       });
329     });
330
331   /**
332    * Allow custom parsers to be passed on options
333    */
334
335   if (options && typeof options.parsers === 'function') {
336     options.parsers(nanomatch.parser);
337   }
338 };
339
340 /**
341  * Advance to the next non-escaped character
342  */
343
344 function advanceTo(input, endChar) {
345   var ch = input.charAt(0);
346   var tok = { len: 1, val: '', esc: '' };
347   var idx = 0;
348
349   function advance() {
350     if (ch !== '\\') {
351       tok.esc += '\\' + ch;
352       tok.val += ch;
353     }
354
355     ch = input.charAt(++idx);
356     tok.len++;
357
358     if (ch === '\\') {
359       advance();
360       advance();
361     }
362   }
363
364   while (ch && ch !== endChar) {
365     advance();
366   }
367   return tok;
368 }
369
370 /**
371  * Create text regex
372  */
373
374 function createTextRegex(pattern) {
375   if (cached) return cached;
376   var opts = {contains: true, strictClose: false};
377   var not = regexNot.create(pattern, opts);
378   var re = toRegex('^(?:[*]\\((?=.)|' + not + ')', opts);
379   return (cached = re);
380 }
381
382 /**
383  * Expose negation string
384  */
385
386 module.exports.not = NOT_REGEX;