'use strict';
const path = require('path');
const scan = require('./scan');
const parse = require('./parse');
const utils = require('./utils');
const constants = require('./constants');
const isObject = val => val && typeof val === 'object' && !Array.isArray(val);
const picomatch = (glob, options, returnState = false) => {
if (Array.isArray(glob)) {
const fns = glob.map(input => picomatch(input, options, returnState));
const arrayMatcher = str => {
for (const isMatch of fns) {
const state = isMatch(str);
if (state) return state;
}
return false;
};
return arrayMatcher;
}
const isState = isObject(glob) && glob.tokens && glob.input;
if (glob === '' || (typeof glob !== 'string' && !isState)) {
throw new TypeError('Expected pattern to be a non-empty string');
}
const opts = options || {};
const posix = utils.isWindows(options);
const regex = isState
? picomatch.compileRe(glob, options)
: picomatch.makeRe(glob, options, false, true);
const state = regex.state;
delete regex.state;
let isIgnored = () => false;
if (opts.ignore) {
const ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null };
isIgnored = picomatch(opts.ignore, ignoreOpts, returnState);
}
const matcher = (input, returnObject = false) => {
const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix });
const result = { glob, state, regex, posix, input, output, match, isMatch };
if (typeof opts.onResult === 'function') {
opts.onResult(result);
}
if (isMatch === false) {
result.isMatch = false;
return returnObject ? result : false;
}
if (isIgnored(input)) {
if (typeof opts.onIgnore === 'function') {
opts.onIgnore(result);
}
result.isMatch = false;
return returnObject ? result : false;
}
if (typeof opts.onMatch === 'function') {
opts.onMatch(result);
}
return returnObject ? result : true;
};
if (returnState) {
matcher.state = state;
}
return matcher;
};
picomatch.test = (input, regex, options, { glob, posix } = {}) => {
if (typeof input !== 'string') {
throw new TypeError('Expected input to be a string');
}
if (input === '') {
return { isMatch: false, output: '' };
}
const opts = options || {};
const format = opts.format || (posix ? utils.toPosixSlashes : null);
let match = input === glob;
let output = (match && format) ? format(input) : input;
if (match === false) {
output = format ? format(input) : input;
match = output === glob;
}
if (match === false || opts.capture === true) {
if (opts.matchBase === true || opts.basename === true) {
match = picomatch.matchBase(input, regex, options, posix);
} else {
match = regex.exec(output);
}
}
return { isMatch: Boolean(match), match, output };
};
picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => {
const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options);
return regex.test(path.basename(input));
};
picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str);
picomatch.parse = (pattern, options) => {
if (Array.isArray(pattern)) return pattern.map(p => picomatch.parse(p, options));
return parse(pattern, { ...options, fastpaths: false });
};
picomatch.scan = (input, options) => scan(input, options);
picomatch.compileRe = (state, options, returnOutput = false, returnState = false) => {
if (returnOutput === true) {
return state.output;
}
const opts = options || {};
const prepend = opts.contains ? '' : '^';
const append = opts.contains ? '' : '$';
let source = `${prepend}(?:${state.output})${append}`;
if (state && state.negated === true) {
source = `^(?!${source}).*$`;
}
const regex = picomatch.toRegex(source, options);
if (returnState === true) {
regex.state = state;
}
return regex;
};
picomatch.makeRe = (input, options = {}, returnOutput = false, returnState = false) => {
if (!input || typeof input !== 'string') {
throw new TypeError('Expected a non-empty string');
}
let parsed = { negated: false, fastpaths: true };
if (options.fastpaths !== false && (input[0] === '.' || input[0] === '*')) {
parsed.output = parse.fastpaths(input, options);
}
if (!parsed.output) {
parsed = parse(input, options);
}
return picomatch.compileRe(parsed, options, returnOutput, returnState);
};
picomatch.toRegex = (source, options) => {
try {
const opts = options || {};
return new RegExp(source, opts.flags || (opts.nocase ? 'i' : ''));
} catch (err) {
if (options && options.debug === true) throw err;
return /$^/;
}
};
picomatch.constants = constants;
module.exports = picomatch;