Projekt

Obecné

Profil

Stáhnout (6.73 KB) Statistiky
| Větev: | Revize:
1
'use strict';
2

    
3
var utils = require('./utils');
4

    
5
module.exports = function(braces, options) {
6
  braces.compiler
7

    
8
    /**
9
     * bos
10
     */
11

    
12
    .set('bos', function() {
13
      if (this.output) return;
14
      this.ast.queue = isEscaped(this.ast) ? [this.ast.val] : [];
15
      this.ast.count = 1;
16
    })
17

    
18
    /**
19
     * Square brackets
20
     */
21

    
22
    .set('bracket', function(node) {
23
      var close = node.close;
24
      var open = !node.escaped ? '[' : '\\[';
25
      var negated = node.negated;
26
      var inner = node.inner;
27

    
28
      inner = inner.replace(/\\(?=[\\\w]|$)/g, '\\\\');
29
      if (inner === ']-') {
30
        inner = '\\]\\-';
31
      }
32

    
33
      if (negated && inner.indexOf('.') === -1) {
34
        inner += '.';
35
      }
36
      if (negated && inner.indexOf('/') === -1) {
37
        inner += '/';
38
      }
39

    
40
      var val = open + negated + inner + close;
41
      var queue = node.parent.queue;
42
      var last = utils.arrayify(queue.pop());
43

    
44
      queue.push(utils.join(last, val));
45
      queue.push.apply(queue, []);
46
    })
47

    
48
    /**
49
     * Brace
50
     */
51

    
52
    .set('brace', function(node) {
53
      node.queue = isEscaped(node) ? [node.val] : [];
54
      node.count = 1;
55
      return this.mapVisit(node.nodes);
56
    })
57

    
58
    /**
59
     * Open
60
     */
61

    
62
    .set('brace.open', function(node) {
63
      node.parent.open = node.val;
64
    })
65

    
66
    /**
67
     * Inner
68
     */
69

    
70
    .set('text', function(node) {
71
      var queue = node.parent.queue;
72
      var escaped = node.escaped;
73
      var segs = [node.val];
74

    
75
      if (node.optimize === false) {
76
        options = utils.extend({}, options, {optimize: false});
77
      }
78

    
79
      if (node.multiplier > 1) {
80
        node.parent.count *= node.multiplier;
81
      }
82

    
83
      if (options.quantifiers === true && utils.isQuantifier(node.val)) {
84
        escaped = true;
85

    
86
      } else if (node.val.length > 1) {
87
        if (isType(node.parent, 'brace') && !isEscaped(node)) {
88
          var expanded = utils.expand(node.val, options);
89
          segs = expanded.segs;
90

    
91
          if (expanded.isOptimized) {
92
            node.parent.isOptimized = true;
93
          }
94

    
95
          // if nothing was expanded, we probably have a literal brace
96
          if (!segs.length) {
97
            var val = (expanded.val || node.val);
98
            if (options.unescape !== false) {
99
              // unescape unexpanded brace sequence/set separators
100
              val = val.replace(/\\([,.])/g, '$1');
101
              // strip quotes
102
              val = val.replace(/["'`]/g, '');
103
            }
104

    
105
            segs = [val];
106
            escaped = true;
107
          }
108
        }
109

    
110
      } else if (node.val === ',') {
111
        if (options.expand) {
112
          node.parent.queue.push(['']);
113
          segs = [''];
114
        } else {
115
          segs = ['|'];
116
        }
117
      } else {
118
        escaped = true;
119
      }
120

    
121
      if (escaped && isType(node.parent, 'brace')) {
122
        if (node.parent.nodes.length <= 4 && node.parent.count === 1) {
123
          node.parent.escaped = true;
124
        } else if (node.parent.length <= 3) {
125
          node.parent.escaped = true;
126
        }
127
      }
128

    
129
      if (!hasQueue(node.parent)) {
130
        node.parent.queue = segs;
131
        return;
132
      }
133

    
134
      var last = utils.arrayify(queue.pop());
135
      if (node.parent.count > 1 && options.expand) {
136
        last = multiply(last, node.parent.count);
137
        node.parent.count = 1;
138
      }
139

    
140
      queue.push(utils.join(utils.flatten(last), segs.shift()));
141
      queue.push.apply(queue, segs);
142
    })
143

    
144
    /**
145
     * Close
146
     */
147

    
148
    .set('brace.close', function(node) {
149
      var queue = node.parent.queue;
150
      var prev = node.parent.parent;
151
      var last = prev.queue.pop();
152
      var open = node.parent.open;
153
      var close = node.val;
154

    
155
      if (open && close && isOptimized(node, options)) {
156
        open = '(';
157
        close = ')';
158
      }
159

    
160
      // if a close brace exists, and the previous segment is one character
161
      // don't wrap the result in braces or parens
162
      var ele = utils.last(queue);
163
      if (node.parent.count > 1 && options.expand) {
164
        ele = multiply(queue.pop(), node.parent.count);
165
        node.parent.count = 1;
166
        queue.push(ele);
167
      }
168

    
169
      if (close && typeof ele === 'string' && ele.length === 1) {
170
        open = '';
171
        close = '';
172
      }
173

    
174
      if ((isLiteralBrace(node, options) || noInner(node)) && !node.parent.hasEmpty) {
175
        queue.push(utils.join(open, queue.pop() || ''));
176
        queue = utils.flatten(utils.join(queue, close));
177
      }
178

    
179
      if (typeof last === 'undefined') {
180
        prev.queue = [queue];
181
      } else {
182
        prev.queue.push(utils.flatten(utils.join(last, queue)));
183
      }
184
    })
185

    
186
    /**
187
     * eos
188
     */
189

    
190
    .set('eos', function(node) {
191
      if (this.input) return;
192

    
193
      if (options.optimize !== false) {
194
        this.output = utils.last(utils.flatten(this.ast.queue));
195
      } else if (Array.isArray(utils.last(this.ast.queue))) {
196
        this.output = utils.flatten(this.ast.queue.pop());
197
      } else {
198
        this.output = utils.flatten(this.ast.queue);
199
      }
200

    
201
      if (node.parent.count > 1 && options.expand) {
202
        this.output = multiply(this.output, node.parent.count);
203
      }
204

    
205
      this.output = utils.arrayify(this.output);
206
      this.ast.queue = [];
207
    });
208

    
209
};
210

    
211
/**
212
 * Multiply the segments in the current brace level
213
 */
214

    
215
function multiply(queue, n, options) {
216
  return utils.flatten(utils.repeat(utils.arrayify(queue), n));
217
}
218

    
219
/**
220
 * Return true if `node` is escaped
221
 */
222

    
223
function isEscaped(node) {
224
  return node.escaped === true;
225
}
226

    
227
/**
228
 * Returns true if regex parens should be used for sets. If the parent `type`
229
 * is not `brace`, then we're on a root node, which means we should never
230
 * expand segments and open/close braces should be `{}` (since this indicates
231
 * a brace is missing from the set)
232
 */
233

    
234
function isOptimized(node, options) {
235
  if (node.parent.isOptimized) return true;
236
  return isType(node.parent, 'brace')
237
    && !isEscaped(node.parent)
238
    && options.expand !== true;
239
}
240

    
241
/**
242
 * Returns true if the value in `node` should be wrapped in a literal brace.
243
 * @return {Boolean}
244
 */
245

    
246
function isLiteralBrace(node, options) {
247
  return isEscaped(node.parent) || options.optimize !== false;
248
}
249

    
250
/**
251
 * Returns true if the given `node` does not have an inner value.
252
 * @return {Boolean}
253
 */
254

    
255
function noInner(node, type) {
256
  if (node.parent.queue.length === 1) {
257
    return true;
258
  }
259
  var nodes = node.parent.nodes;
260
  return nodes.length === 3
261
    && isType(nodes[0], 'brace.open')
262
    && !isType(nodes[1], 'text')
263
    && isType(nodes[2], 'brace.close');
264
}
265

    
266
/**
267
 * Returns true if the given `node` is the given `type`
268
 * @return {Boolean}
269
 */
270

    
271
function isType(node, type) {
272
  return typeof node !== 'undefined' && node.type === type;
273
}
274

    
275
/**
276
 * Returns true if the given `node` has a non-empty queue.
277
 * @return {Boolean}
278
 */
279

    
280
function hasQueue(node) {
281
  return Array.isArray(node.queue) && node.queue.length;
282
}
(2-2/4)