blob: d7bed252a0e702a22933c5adca4815d0ff264463 [file] [log] [blame]
'use strict';
var brackets = require('expand-brackets');
/**
* Extglob compilers
*/
module.exports = function(extglob) {
function star() {
if (typeof extglob.options.star === 'function') {
return extglob.options.star.apply(this, arguments);
}
if (typeof extglob.options.star === 'string') {
return extglob.options.star;
}
return '.*?';
}
/**
* Use `expand-brackets` compilers
*/
extglob.use(brackets.compilers);
extglob.compiler
/**
* Escaped: "\\*"
*/
.set('escape', function(node) {
return this.emit(node.val, node);
})
/**
* Dot: "."
*/
.set('dot', function(node) {
return this.emit('\\' + node.val, node);
})
/**
* Question mark: "?"
*/
.set('qmark', function(node) {
var val = '[^\\\\/.]';
var prev = this.prev();
if (node.parsed.slice(-1) === '(') {
var ch = node.rest.charAt(0);
if (ch !== '!' && ch !== '=' && ch !== ':') {
return this.emit(val, node);
}
return this.emit(node.val, node);
}
if (prev.type === 'text' && prev.val) {
return this.emit(val, node);
}
if (node.val.length > 1) {
val += '{' + node.val.length + '}';
}
return this.emit(val, node);
})
/**
* Plus: "+"
*/
.set('plus', function(node) {
var prev = node.parsed.slice(-1);
if (prev === ']' || prev === ')') {
return this.emit(node.val, node);
}
var ch = this.output.slice(-1);
if (!this.output || (/[?*+]/.test(ch) && node.parent.type !== 'bracket')) {
return this.emit('\\+', node);
}
if (/\w/.test(ch) && !node.inside) {
return this.emit('+\\+?', node);
}
return this.emit('+', node);
})
/**
* Star: "*"
*/
.set('star', function(node) {
var prev = this.prev();
var prefix = prev.type !== 'text' && prev.type !== 'escape'
? '(?!\\.)'
: '';
return this.emit(prefix + star.call(this, node), node);
})
/**
* Parens
*/
.set('paren', function(node) {
return this.mapVisit(node.nodes);
})
.set('paren.open', function(node) {
var capture = this.options.capture ? '(' : '';
switch (node.parent.prefix) {
case '!':
case '^':
return this.emit(capture + '(?:(?!(?:', node);
case '*':
case '+':
case '?':
case '@':
return this.emit(capture + '(?:', node);
default: {
var val = node.val;
if (this.options.bash === true) {
val = '\\' + val;
} else if (!this.options.capture && val === '(' && node.parent.rest[0] !== '?') {
val += '?:';
}
return this.emit(val, node);
}
}
})
.set('paren.close', function(node) {
var capture = this.options.capture ? ')' : '';
switch (node.prefix) {
case '!':
case '^':
var prefix = /^(\)|$)/.test(node.rest) ? '$' : '';
var str = star.call(this, node);
// if the extglob has a slash explicitly defined, we know the user wants
// to match slashes, so we need to ensure the "star" regex allows for it
if (node.parent.hasSlash && !this.options.star && this.options.slash !== false) {
str = '.*?';
}
return this.emit(prefix + ('))' + str + ')') + capture, node);
case '*':
case '+':
case '?':
return this.emit(')' + node.prefix + capture, node);
case '@':
return this.emit(')' + capture, node);
default: {
var val = (this.options.bash === true ? '\\' : '') + ')';
return this.emit(val, node);
}
}
})
/**
* Text
*/
.set('text', function(node) {
var val = node.val.replace(/[\[\]]/g, '\\$&');
return this.emit(val, node);
});
};