Projekt

Obecné

Profil

Stáhnout (4.29 KB) Statistiky
| Větev: | Revize:
1 3a515b92 cagy
'use strict';
2
3
var utils = require('./utils');
4
var define = require('define-property');
5
6
/**
7
 * Text regex
8
 */
9
10
var TEXT_REGEX = '(\\[(?=.*\\])|\\])+';
11
var not = utils.createRegex(TEXT_REGEX);
12
13
/**
14
 * Brackets parsers
15
 */
16
17
function parsers(brackets) {
18
  brackets.state = brackets.state || {};
19
  brackets.parser.sets.bracket = brackets.parser.sets.bracket || [];
20
  brackets.parser
21
22
    .capture('escape', function() {
23
      if (this.isInside('bracket')) return;
24
      var pos = this.position();
25
      var m = this.match(/^\\(.)/);
26
      if (!m) return;
27
28
      return pos({
29
        type: 'escape',
30
        val: m[0]
31
      });
32
    })
33
34
    /**
35
     * Text parser
36
     */
37
38
    .capture('text', function() {
39
      if (this.isInside('bracket')) return;
40
      var pos = this.position();
41
      var m = this.match(not);
42
      if (!m || !m[0]) return;
43
44
      return pos({
45
        type: 'text',
46
        val: m[0]
47
      });
48
    })
49
50
    /**
51
     * POSIX character classes: "[[:alpha:][:digits:]]"
52
     */
53
54
    .capture('posix', function() {
55
      var pos = this.position();
56
      var m = this.match(/^\[:(.*?):\](?=.*\])/);
57
      if (!m) return;
58
59
      var inside = this.isInside('bracket');
60
      if (inside) {
61
        brackets.posix++;
62
      }
63
64
      return pos({
65
        type: 'posix',
66
        insideBracket: inside,
67
        inner: m[1],
68
        val: m[0]
69
      });
70
    })
71
72
    /**
73
     * Bracket (noop)
74
     */
75
76
    .capture('bracket', function() {})
77
78
    /**
79
     * Open: '['
80
     */
81
82
    .capture('bracket.open', function() {
83
      var parsed = this.parsed;
84
      var pos = this.position();
85
      var m = this.match(/^\[(?=.*\])/);
86
      if (!m) return;
87
88
      var prev = this.prev();
89
      var last = utils.last(prev.nodes);
90
91
      if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) {
92
        last.val = last.val.slice(0, last.val.length - 1);
93
        return pos({
94
          type: 'escape',
95
          val: m[0]
96
        });
97
      }
98
99
      var open = pos({
100
        type: 'bracket.open',
101
        val: m[0]
102
      });
103
104
      if (last.type === 'bracket.open' || this.isInside('bracket')) {
105
        open.val = '\\' + open.val;
106
        open.type = 'bracket.inner';
107
        open.escaped = true;
108
        return open;
109
      }
110
111
      var node = pos({
112
        type: 'bracket',
113
        nodes: [open]
114
      });
115
116
      define(node, 'parent', prev);
117
      define(open, 'parent', node);
118
      this.push('bracket', node);
119
      prev.nodes.push(node);
120
    })
121
122
    /**
123
     * Bracket text
124
     */
125
126
    .capture('bracket.inner', function() {
127
      if (!this.isInside('bracket')) return;
128
      var pos = this.position();
129
      var m = this.match(not);
130
      if (!m || !m[0]) return;
131
132
      var next = this.input.charAt(0);
133
      var val = m[0];
134
135
      var node = pos({
136
        type: 'bracket.inner',
137
        val: val
138
      });
139
140
      if (val === '\\\\') {
141
        return node;
142
      }
143
144
      var first = val.charAt(0);
145
      var last = val.slice(-1);
146
147
      if (first === '!') {
148
        val = '^' + val.slice(1);
149
      }
150
151
      if (last === '\\' || (val === '^' && next === ']')) {
152
        val += this.input[0];
153
        this.consume(1);
154
      }
155
156
      node.val = val;
157
      return node;
158
    })
159
160
    /**
161
     * Close: ']'
162
     */
163
164
    .capture('bracket.close', function() {
165
      var parsed = this.parsed;
166
      var pos = this.position();
167
      var m = this.match(/^\]/);
168
      if (!m) return;
169
170
      var prev = this.prev();
171
      var last = utils.last(prev.nodes);
172
173
      if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) {
174
        last.val = last.val.slice(0, last.val.length - 1);
175
176
        return pos({
177
          type: 'escape',
178
          val: m[0]
179
        });
180
      }
181
182
      var node = pos({
183
        type: 'bracket.close',
184
        rest: this.input,
185
        val: m[0]
186
      });
187
188
      if (last.type === 'bracket.open') {
189
        node.type = 'bracket.inner';
190
        node.escaped = true;
191
        return node;
192
      }
193
194
      var bracket = this.pop('bracket');
195
      if (!this.isType(bracket, 'bracket')) {
196
        if (this.options.strict) {
197
          throw new Error('missing opening "["');
198
        }
199
        node.type = 'bracket.inner';
200
        node.escaped = true;
201
        return node;
202
      }
203
204
      bracket.nodes.push(node);
205
      define(node, 'parent', bracket);
206
    });
207
}
208
209
/**
210
 * Brackets parsers
211
 */
212
213
module.exports = parsers;
214
215
/**
216
 * Expose text regex
217
 */
218
219
module.exports.TEXT_REGEX = TEXT_REGEX;