blob: 2ba7352e9e2425259be77e80fcefb8a446af8c58 [file] [log] [blame]
'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;