220 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			220 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
'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;
 |