Projekt

Obecné

Profil

Stáhnout (4.29 KB) Statistiky
| Větev: | Revize:
1
'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;
(2-2/3)