UNPKG

3.17 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", { value: true });
4
5const picomatch = require('picomatch');
6const normalizePath = require('normalize-path');
7
8/**
9 * @typedef {(testString: string) => boolean} AnymatchFn
10 * @typedef {string|RegExp|AnymatchFn} AnymatchPattern
11 * @typedef {AnymatchPattern|AnymatchPattern[]} AnymatchMatcher
12 */
13const BANG = '!';
14const DEFAULT_OPTIONS = {returnIndex: false};
15const arrify = (item) => Array.isArray(item) ? item : [item];
16
17/**
18 * @param {AnymatchPattern} matcher
19 * @param {object} options
20 * @returns {AnymatchFn}
21 */
22const createPattern = (matcher, options) => {
23 if (typeof matcher === 'function') {
24 return matcher;
25 }
26 if (typeof matcher === 'string') {
27 const glob = picomatch(matcher, options);
28 return (string) => matcher === string || glob(string);
29 }
30 if (matcher instanceof RegExp) {
31 return (string) => matcher.test(string);
32 }
33 return (string) => false;
34};
35
36/**
37 * @param {Array<Function>} patterns
38 * @param {Array<Function>} negPatterns
39 * @param {String|Array} args
40 * @param {Boolean} returnIndex
41 * @returns {boolean|number}
42 */
43const matchPatterns = (patterns, negPatterns, args, returnIndex) => {
44 const isList = Array.isArray(args);
45 const _path = isList ? args[0] : args;
46 if (!isList && typeof _path !== 'string') {
47 throw new TypeError('anymatch: second argument must be a string: got ' +
48 Object.prototype.toString.call(_path))
49 }
50 const path = normalizePath(_path);
51
52 for (let index = 0; index < negPatterns.length; index++) {
53 const nglob = negPatterns[index];
54 if (nglob(path)) {
55 return returnIndex ? -1 : false;
56 }
57 }
58
59 const applied = isList && [path].concat(args.slice(1));
60 for (let index = 0; index < patterns.length; index++) {
61 const pattern = patterns[index];
62 if (isList ? pattern(...applied) : pattern(path)) {
63 return returnIndex ? index : true;
64 }
65 }
66
67 return returnIndex ? -1 : false;
68};
69
70/**
71 * @param {AnymatchMatcher} matchers
72 * @param {Array|string} testString
73 * @param {object} options
74 * @returns {boolean|number|Function}
75 */
76const anymatch = (matchers, testString, options = DEFAULT_OPTIONS) => {
77 if (matchers == null) {
78 throw new TypeError('anymatch: specify first argument');
79 }
80 const opts = typeof options === 'boolean' ? {returnIndex: options} : options;
81 const returnIndex = opts.returnIndex || false;
82
83 // Early cache for matchers.
84 const mtchers = arrify(matchers);
85 const negatedGlobs = mtchers
86 .filter(item => typeof item === 'string' && item.charAt(0) === BANG)
87 .map(item => item.slice(1))
88 .map(item => picomatch(item, opts));
89 const patterns = mtchers
90 .filter(item => typeof item !== 'string' || (typeof item === 'string' && item.charAt(0) !== BANG))
91 .map(matcher => createPattern(matcher, opts));
92
93 if (testString == null) {
94 return (testString, ri = false) => {
95 const returnIndex = typeof ri === 'boolean' ? ri : false;
96 return matchPatterns(patterns, negatedGlobs, testString, returnIndex);
97 }
98 }
99
100 return matchPatterns(patterns, negatedGlobs, testString, returnIndex);
101};
102
103anymatch.default = anymatch;
104module.exports = anymatch;