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