You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							219 lines
						
					
					
						
							4.3 KiB
						
					
					
				
			
		
		
	
	
							219 lines
						
					
					
						
							4.3 KiB
						
					
					
				'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;
 | 
						|
 |