| 'use strict'; | 
|   | 
| var utils = require('./utils'); | 
| var define = require('define-property'); | 
|   | 
| /** | 
|  * Text regex | 
|  */ | 
|   | 
| var TEXT_REGEX = '(\\[(?=.*\\])|\\])+'; | 
| var not = utils.createRegex(TEXT_REGEX); | 
|   | 
| /** | 
|  * Brackets parsers | 
|  */ | 
|   | 
| function parsers(brackets) { | 
|   brackets.state = brackets.state || {}; | 
|   brackets.parser.sets.bracket = brackets.parser.sets.bracket || []; | 
|   brackets.parser | 
|   | 
|     .capture('escape', function() { | 
|       if (this.isInside('bracket')) return; | 
|       var pos = this.position(); | 
|       var m = this.match(/^\\(.)/); | 
|       if (!m) return; | 
|   | 
|       return pos({ | 
|         type: 'escape', | 
|         val: m[0] | 
|       }); | 
|     }) | 
|   | 
|     /** | 
|      * Text parser | 
|      */ | 
|   | 
|     .capture('text', function() { | 
|       if (this.isInside('bracket')) return; | 
|       var pos = this.position(); | 
|       var m = this.match(not); | 
|       if (!m || !m[0]) return; | 
|   | 
|       return pos({ | 
|         type: 'text', | 
|         val: m[0] | 
|       }); | 
|     }) | 
|   | 
|     /** | 
|      * POSIX character classes: "[[:alpha:][:digits:]]" | 
|      */ | 
|   | 
|     .capture('posix', function() { | 
|       var pos = this.position(); | 
|       var m = this.match(/^\[:(.*?):\](?=.*\])/); | 
|       if (!m) return; | 
|   | 
|       var inside = this.isInside('bracket'); | 
|       if (inside) { | 
|         brackets.posix++; | 
|       } | 
|   | 
|       return pos({ | 
|         type: 'posix', | 
|         insideBracket: inside, | 
|         inner: m[1], | 
|         val: m[0] | 
|       }); | 
|     }) | 
|   | 
|     /** | 
|      * Bracket (noop) | 
|      */ | 
|   | 
|     .capture('bracket', function() {}) | 
|   | 
|     /** | 
|      * Open: '[' | 
|      */ | 
|   | 
|     .capture('bracket.open', function() { | 
|       var parsed = this.parsed; | 
|       var pos = this.position(); | 
|       var m = this.match(/^\[(?=.*\])/); | 
|       if (!m) return; | 
|   | 
|       var prev = this.prev(); | 
|       var last = utils.last(prev.nodes); | 
|   | 
|       if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) { | 
|         last.val = last.val.slice(0, last.val.length - 1); | 
|         return pos({ | 
|           type: 'escape', | 
|           val: m[0] | 
|         }); | 
|       } | 
|   | 
|       var open = pos({ | 
|         type: 'bracket.open', | 
|         val: m[0] | 
|       }); | 
|   | 
|       if (last.type === 'bracket.open' || this.isInside('bracket')) { | 
|         open.val = '\\' + open.val; | 
|         open.type = 'bracket.inner'; | 
|         open.escaped = true; | 
|         return open; | 
|       } | 
|   | 
|       var node = pos({ | 
|         type: 'bracket', | 
|         nodes: [open] | 
|       }); | 
|   | 
|       define(node, 'parent', prev); | 
|       define(open, 'parent', node); | 
|       this.push('bracket', node); | 
|       prev.nodes.push(node); | 
|     }) | 
|   | 
|     /** | 
|      * Bracket text | 
|      */ | 
|   | 
|     .capture('bracket.inner', function() { | 
|       if (!this.isInside('bracket')) return; | 
|       var pos = this.position(); | 
|       var m = this.match(not); | 
|       if (!m || !m[0]) return; | 
|   | 
|       var next = this.input.charAt(0); | 
|       var val = m[0]; | 
|   | 
|       var node = pos({ | 
|         type: 'bracket.inner', | 
|         val: val | 
|       }); | 
|   | 
|       if (val === '\\\\') { | 
|         return node; | 
|       } | 
|   | 
|       var first = val.charAt(0); | 
|       var last = val.slice(-1); | 
|   | 
|       if (first === '!') { | 
|         val = '^' + val.slice(1); | 
|       } | 
|   | 
|       if (last === '\\' || (val === '^' && next === ']')) { | 
|         val += this.input[0]; | 
|         this.consume(1); | 
|       } | 
|   | 
|       node.val = val; | 
|       return node; | 
|     }) | 
|   | 
|     /** | 
|      * Close: ']' | 
|      */ | 
|   | 
|     .capture('bracket.close', function() { | 
|       var parsed = this.parsed; | 
|       var pos = this.position(); | 
|       var m = this.match(/^\]/); | 
|       if (!m) return; | 
|   | 
|       var prev = this.prev(); | 
|       var last = utils.last(prev.nodes); | 
|   | 
|       if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) { | 
|         last.val = last.val.slice(0, last.val.length - 1); | 
|   | 
|         return pos({ | 
|           type: 'escape', | 
|           val: m[0] | 
|         }); | 
|       } | 
|   | 
|       var node = pos({ | 
|         type: 'bracket.close', | 
|         rest: this.input, | 
|         val: m[0] | 
|       }); | 
|   | 
|       if (last.type === 'bracket.open') { | 
|         node.type = 'bracket.inner'; | 
|         node.escaped = true; | 
|         return node; | 
|       } | 
|   | 
|       var bracket = this.pop('bracket'); | 
|       if (!this.isType(bracket, 'bracket')) { | 
|         if (this.options.strict) { | 
|           throw new Error('missing opening "["'); | 
|         } | 
|         node.type = 'bracket.inner'; | 
|         node.escaped = true; | 
|         return node; | 
|       } | 
|   | 
|       bracket.nodes.push(node); | 
|       define(node, 'parent', bracket); | 
|     }); | 
| } | 
|   | 
| /** | 
|  * Brackets parsers | 
|  */ | 
|   | 
| module.exports = parsers; | 
|   | 
| /** | 
|  * Expose text regex | 
|  */ | 
|   | 
| module.exports.TEXT_REGEX = TEXT_REGEX; |