| 'use strict'; |
| |
| const path = require('path'); |
| const scan = require('./scan'); |
| const parse = require('./parse'); |
| const utils = require('./utils'); |
| |
| /** |
| * Creates a matcher function from one or more glob patterns. The |
| * returned function takes a string to match as its first argument, |
| * and returns true if the string is a match. The returned matcher |
| * function also takes a boolean as the second argument that, when true, |
| * returns an object with additional information. |
| * |
| * ```js |
| * const picomatch = require('picomatch'); |
| * // picomatch(glob[, options]); |
| * |
| * const isMatch = picomatch('*.!(*a)'); |
| * console.log(isMatch('a.a')); //=> false |
| * console.log(isMatch('a.b')); //=> true |
| * ``` |
| * @name picomatch |
| * @param {String|Array} `globs` One or more glob patterns. |
| * @param {Object=} `options` |
| * @return {Function=} Returns a matcher function. |
| * @api public |
| */ |
| |
| const picomatch = (glob, options, returnState = false) => { |
| if (Array.isArray(glob)) { |
| let fns = glob.map(input => picomatch(input, options, returnState)); |
| return str => { |
| for (let isMatch of fns) { |
| let state = isMatch(str); |
| if (state) return state; |
| } |
| return false; |
| }; |
| } |
| |
| if (typeof glob !== 'string' || glob === '') { |
| throw new TypeError('Expected pattern to be a non-empty string'); |
| } |
| |
| let opts = options || {}; |
| let posix = utils.isWindows(options); |
| let regex = picomatch.makeRe(glob, options, false, true); |
| let state = regex.state; |
| delete regex.state; |
| |
| let isIgnored = () => false; |
| if (opts.ignore) { |
| let ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null }; |
| isIgnored = picomatch(opts.ignore, ignoreOpts, returnState); |
| } |
| |
| const matcher = (input, returnObject = false) => { |
| let { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix }); |
| let 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; |
| }; |
| |
| /** |
| * Test `input` with the given `regex`. This is used by the main |
| * `picomatch()` function to test the input string. |
| * |
| * ```js |
| * const picomatch = require('picomatch'); |
| * // picomatch.test(input, regex[, options]); |
| * |
| * console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/)); |
| * // { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' } |
| * ``` |
| * @param {String} `input` String to test. |
| * @param {RegExp} `regex` |
| * @return {Object} Returns an object with matching info. |
| * @api public |
| */ |
| |
| 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: '' }; |
| } |
| |
| let opts = options || {}; |
| let 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: !!match, match, output }; |
| }; |
| |
| /** |
| * Match the basename of a filepath. |
| * |
| * ```js |
| * const picomatch = require('picomatch'); |
| * // picomatch.matchBase(input, glob[, options]); |
| * console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true |
| * ``` |
| * @param {String} `input` String to test. |
| * @param {RegExp|String} `glob` Glob pattern or regex created by [.makeRe](#makeRe). |
| * @return {Boolean} |
| * @api public |
| */ |
| |
| picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => { |
| let regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options); |
| return regex.test(path.basename(input)); |
| }; |
| |
| /** |
| * Returns true if **any** of the given glob `patterns` match the specified `string`. |
| * |
| * ```js |
| * const picomatch = require('picomatch'); |
| * // picomatch.isMatch(string, patterns[, options]); |
| * |
| * console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true |
| * console.log(picomatch.isMatch('a.a', 'b.*')); //=> false |
| * ``` |
| * @param {String|Array} str The string to test. |
| * @param {String|Array} patterns One or more glob patterns to use for matching. |
| * @param {Object} [options] See available [options](#options). |
| * @return {Boolean} Returns true if any patterns match `str` |
| * @api public |
| */ |
| |
| picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); |
| |
| /** |
| * Parse a glob pattern to create the source string for a regular |
| * expression. |
| * |
| * ```js |
| * const picomatch = require('picomatch'); |
| * const result = picomatch.parse(glob[, options]); |
| * ``` |
| * @param {String} `glob` |
| * @param {Object} `options` |
| * @return {Object} Returns an object with useful properties and output to be used as a regex source string. |
| * @api public |
| */ |
| |
| picomatch.parse = (glob, options) => parse(glob, options); |
| |
| /** |
| * Scan a glob pattern to separate the pattern into segments. |
| * |
| * ```js |
| * const picomatch = require('picomatch'); |
| * // picomatch.scan(input[, options]); |
| * |
| * const result = picomatch.scan('!./foo/*.js'); |
| * console.log(result); |
| * // { prefix: '!./', |
| * // input: '!./foo/*.js', |
| * // base: 'foo', |
| * // glob: '*.js', |
| * // negated: true, |
| * // isGlob: true } |
| * ``` |
| * @param {String} `input` Glob pattern to scan. |
| * @param {Object} `options` |
| * @return {Object} Returns an object with |
| * @api public |
| */ |
| |
| picomatch.scan = (input, options) => scan(input, options); |
| |
| /** |
| * Create a regular expression from a glob pattern. |
| * |
| * ```js |
| * const picomatch = require('picomatch'); |
| * // picomatch.makeRe(input[, options]); |
| * |
| * console.log(picomatch.makeRe('*.js')); |
| * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ |
| * ``` |
| * @param {String} `input` A glob pattern to convert to regex. |
| * @param {Object} `options` |
| * @return {RegExp} Returns a regex created from the given pattern. |
| * @api public |
| */ |
| |
| picomatch.makeRe = (input, options, returnOutput = false, returnState = false) => { |
| if (!input || typeof input !== 'string') { |
| throw new TypeError('Expected a non-empty string'); |
| } |
| |
| let opts = options || {}; |
| let prepend = opts.contains ? '' : '^'; |
| let append = opts.contains ? '' : '$'; |
| let state = { negated: false, fastpaths: true }; |
| let prefix = ''; |
| let output; |
| |
| if (input.startsWith('./')) { |
| input = input.slice(2); |
| prefix = state.prefix = './'; |
| } |
| |
| if (opts.fastpaths !== false && (input[0] === '.' || input[0] === '*')) { |
| output = parse.fastpaths(input, options); |
| } |
| |
| if (output === void 0) { |
| state = picomatch.parse(input, options); |
| state.prefix = prefix + (state.prefix || ''); |
| output = state.output; |
| } |
| |
| if (returnOutput === true) { |
| return output; |
| } |
| |
| let source = `${prepend}(?:${output})${append}`; |
| if (state && state.negated === true) { |
| source = `^(?!${source}).*$`; |
| } |
| |
| let regex = picomatch.toRegex(source, options); |
| if (returnState === true) { |
| regex.state = state; |
| } |
| |
| return regex; |
| }; |
| |
| /** |
| * Create a regular expression from the given regex source string. |
| * |
| * ```js |
| * const picomatch = require('picomatch'); |
| * // picomatch.toRegex(source[, options]); |
| * |
| * const { output } = picomatch.parse('*.js'); |
| * console.log(picomatch.toRegex(output)); |
| * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ |
| * ``` |
| * @param {String} `source` Regular expression source string. |
| * @param {Object} `options` |
| * @return {RegExp} |
| * @api public |
| */ |
| |
| picomatch.toRegex = (source, options) => { |
| try { |
| let opts = options || {}; |
| return new RegExp(source, opts.flags || (opts.nocase ? 'i' : '')); |
| } catch (err) { |
| if (options && options.debug === true) throw err; |
| return /$^/; |
| } |
| }; |
| |
| /** |
| * Picomatch constants. |
| * @return {Object} |
| */ |
| |
| picomatch.constants = require('./constants'); |
| |
| /** |
| * Expose "picomatch" |
| */ |
| |
| module.exports = picomatch; |