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