|
|
- '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;
|