1 | 'use strict';
|
---|
2 |
|
---|
3 | var brackets = require('expand-brackets');
|
---|
4 | var define = require('define-property');
|
---|
5 | var utils = require('./utils');
|
---|
6 |
|
---|
7 | /**
|
---|
8 | * Characters to use in text regex (we want to "not" match
|
---|
9 | * characters that are matched by other parsers)
|
---|
10 | */
|
---|
11 |
|
---|
12 | var TEXT_REGEX = '([!@*?+]?\\(|\\)|[*?.+\\\\]|\\[:?(?=.*\\])|:?\\])+';
|
---|
13 | var not = utils.createRegex(TEXT_REGEX);
|
---|
14 |
|
---|
15 | /**
|
---|
16 | * Extglob parsers
|
---|
17 | */
|
---|
18 |
|
---|
19 | function parsers(extglob) {
|
---|
20 | extglob.state = extglob.state || {};
|
---|
21 |
|
---|
22 | /**
|
---|
23 | * Use `expand-brackets` parsers
|
---|
24 | */
|
---|
25 |
|
---|
26 | extglob.use(brackets.parsers);
|
---|
27 | extglob.parser.sets.paren = extglob.parser.sets.paren || [];
|
---|
28 | extglob.parser
|
---|
29 |
|
---|
30 | /**
|
---|
31 | * Extglob open: "*("
|
---|
32 | */
|
---|
33 |
|
---|
34 | .capture('paren.open', function() {
|
---|
35 | var parsed = this.parsed;
|
---|
36 | var pos = this.position();
|
---|
37 | var m = this.match(/^([!@*?+])?\(/);
|
---|
38 | if (!m) return;
|
---|
39 |
|
---|
40 | var prev = this.prev();
|
---|
41 | var prefix = m[1];
|
---|
42 | var val = m[0];
|
---|
43 |
|
---|
44 | var open = pos({
|
---|
45 | type: 'paren.open',
|
---|
46 | parsed: parsed,
|
---|
47 | val: val
|
---|
48 | });
|
---|
49 |
|
---|
50 | var node = pos({
|
---|
51 | type: 'paren',
|
---|
52 | prefix: prefix,
|
---|
53 | nodes: [open]
|
---|
54 | });
|
---|
55 |
|
---|
56 | // if nested negation extglobs, just cancel them out to simplify
|
---|
57 | if (prefix === '!' && prev.type === 'paren' && prev.prefix === '!') {
|
---|
58 | prev.prefix = '@';
|
---|
59 | node.prefix = '@';
|
---|
60 | }
|
---|
61 |
|
---|
62 | define(node, 'rest', this.input);
|
---|
63 | define(node, 'parsed', parsed);
|
---|
64 | define(node, 'parent', prev);
|
---|
65 | define(open, 'parent', node);
|
---|
66 |
|
---|
67 | this.push('paren', node);
|
---|
68 | prev.nodes.push(node);
|
---|
69 | })
|
---|
70 |
|
---|
71 | /**
|
---|
72 | * Extglob close: ")"
|
---|
73 | */
|
---|
74 |
|
---|
75 | .capture('paren.close', function() {
|
---|
76 | var parsed = this.parsed;
|
---|
77 | var pos = this.position();
|
---|
78 | var m = this.match(/^\)/);
|
---|
79 | if (!m) return;
|
---|
80 |
|
---|
81 | var parent = this.pop('paren');
|
---|
82 | var node = pos({
|
---|
83 | type: 'paren.close',
|
---|
84 | rest: this.input,
|
---|
85 | parsed: parsed,
|
---|
86 | val: m[0]
|
---|
87 | });
|
---|
88 |
|
---|
89 | if (!this.isType(parent, 'paren')) {
|
---|
90 | if (this.options.strict) {
|
---|
91 | throw new Error('missing opening paren: "("');
|
---|
92 | }
|
---|
93 | node.escaped = true;
|
---|
94 | return node;
|
---|
95 | }
|
---|
96 |
|
---|
97 | node.prefix = parent.prefix;
|
---|
98 | parent.nodes.push(node);
|
---|
99 | define(node, 'parent', parent);
|
---|
100 | })
|
---|
101 |
|
---|
102 | /**
|
---|
103 | * Escape: "\\."
|
---|
104 | */
|
---|
105 |
|
---|
106 | .capture('escape', function() {
|
---|
107 | var pos = this.position();
|
---|
108 | var m = this.match(/^\\(.)/);
|
---|
109 | if (!m) return;
|
---|
110 |
|
---|
111 | return pos({
|
---|
112 | type: 'escape',
|
---|
113 | val: m[0],
|
---|
114 | ch: m[1]
|
---|
115 | });
|
---|
116 | })
|
---|
117 |
|
---|
118 | /**
|
---|
119 | * Question marks: "?"
|
---|
120 | */
|
---|
121 |
|
---|
122 | .capture('qmark', function() {
|
---|
123 | var parsed = this.parsed;
|
---|
124 | var pos = this.position();
|
---|
125 | var m = this.match(/^\?+(?!\()/);
|
---|
126 | if (!m) return;
|
---|
127 | extglob.state.metachar = true;
|
---|
128 | return pos({
|
---|
129 | type: 'qmark',
|
---|
130 | rest: this.input,
|
---|
131 | parsed: parsed,
|
---|
132 | val: m[0]
|
---|
133 | });
|
---|
134 | })
|
---|
135 |
|
---|
136 | /**
|
---|
137 | * Character parsers
|
---|
138 | */
|
---|
139 |
|
---|
140 | .capture('star', /^\*(?!\()/)
|
---|
141 | .capture('plus', /^\+(?!\()/)
|
---|
142 | .capture('dot', /^\./)
|
---|
143 | .capture('text', not);
|
---|
144 | };
|
---|
145 |
|
---|
146 | /**
|
---|
147 | * Expose text regex string
|
---|
148 | */
|
---|
149 |
|
---|
150 | module.exports.TEXT_REGEX = TEXT_REGEX;
|
---|
151 |
|
---|
152 | /**
|
---|
153 | * Extglob parsers
|
---|
154 | */
|
---|
155 |
|
---|
156 | module.exports = parsers;
|
---|