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.
156 lines
3.1 KiB
156 lines
3.1 KiB
'use strict'; |
|
|
|
var brackets = require('expand-brackets'); |
|
var define = require('define-property'); |
|
var utils = require('./utils'); |
|
|
|
/** |
|
* Characters to use in text regex (we want to "not" match |
|
* characters that are matched by other parsers) |
|
*/ |
|
|
|
var TEXT_REGEX = '([!@*?+]?\\(|\\)|[*?.+\\\\]|\\[:?(?=.*\\])|:?\\])+'; |
|
var not = utils.createRegex(TEXT_REGEX); |
|
|
|
/** |
|
* Extglob parsers |
|
*/ |
|
|
|
function parsers(extglob) { |
|
extglob.state = extglob.state || {}; |
|
|
|
/** |
|
* Use `expand-brackets` parsers |
|
*/ |
|
|
|
extglob.use(brackets.parsers); |
|
extglob.parser.sets.paren = extglob.parser.sets.paren || []; |
|
extglob.parser |
|
|
|
/** |
|
* Extglob open: "*(" |
|
*/ |
|
|
|
.capture('paren.open', function() { |
|
var parsed = this.parsed; |
|
var pos = this.position(); |
|
var m = this.match(/^([!@*?+])?\(/); |
|
if (!m) return; |
|
|
|
var prev = this.prev(); |
|
var prefix = m[1]; |
|
var val = m[0]; |
|
|
|
var open = pos({ |
|
type: 'paren.open', |
|
parsed: parsed, |
|
val: val |
|
}); |
|
|
|
var node = pos({ |
|
type: 'paren', |
|
prefix: prefix, |
|
nodes: [open] |
|
}); |
|
|
|
// if nested negation extglobs, just cancel them out to simplify |
|
if (prefix === '!' && prev.type === 'paren' && prev.prefix === '!') { |
|
prev.prefix = '@'; |
|
node.prefix = '@'; |
|
} |
|
|
|
define(node, 'rest', this.input); |
|
define(node, 'parsed', parsed); |
|
define(node, 'parent', prev); |
|
define(open, 'parent', node); |
|
|
|
this.push('paren', node); |
|
prev.nodes.push(node); |
|
}) |
|
|
|
/** |
|
* Extglob close: ")" |
|
*/ |
|
|
|
.capture('paren.close', function() { |
|
var parsed = this.parsed; |
|
var pos = this.position(); |
|
var m = this.match(/^\)/); |
|
if (!m) return; |
|
|
|
var parent = this.pop('paren'); |
|
var node = pos({ |
|
type: 'paren.close', |
|
rest: this.input, |
|
parsed: parsed, |
|
val: m[0] |
|
}); |
|
|
|
if (!this.isType(parent, 'paren')) { |
|
if (this.options.strict) { |
|
throw new Error('missing opening paren: "("'); |
|
} |
|
node.escaped = true; |
|
return node; |
|
} |
|
|
|
node.prefix = parent.prefix; |
|
parent.nodes.push(node); |
|
define(node, 'parent', parent); |
|
}) |
|
|
|
/** |
|
* Escape: "\\." |
|
*/ |
|
|
|
.capture('escape', function() { |
|
var pos = this.position(); |
|
var m = this.match(/^\\(.)/); |
|
if (!m) return; |
|
|
|
return pos({ |
|
type: 'escape', |
|
val: m[0], |
|
ch: m[1] |
|
}); |
|
}) |
|
|
|
/** |
|
* Question marks: "?" |
|
*/ |
|
|
|
.capture('qmark', function() { |
|
var parsed = this.parsed; |
|
var pos = this.position(); |
|
var m = this.match(/^\?+(?!\()/); |
|
if (!m) return; |
|
extglob.state.metachar = true; |
|
return pos({ |
|
type: 'qmark', |
|
rest: this.input, |
|
parsed: parsed, |
|
val: m[0] |
|
}); |
|
}) |
|
|
|
/** |
|
* Character parsers |
|
*/ |
|
|
|
.capture('star', /^\*(?!\()/) |
|
.capture('plus', /^\+(?!\()/) |
|
.capture('dot', /^\./) |
|
.capture('text', not); |
|
}; |
|
|
|
/** |
|
* Expose text regex string |
|
*/ |
|
|
|
module.exports.TEXT_REGEX = TEXT_REGEX; |
|
|
|
/** |
|
* Extglob parsers |
|
*/ |
|
|
|
module.exports = parsers;
|
|
|