Apply module bundling
[platform/framework/web/wrtjs.git] / node_modules / picomatch / lib / picomatch.js
1 'use strict';
2
3 const path = require('path');
4 const scan = require('./scan');
5 const parse = require('./parse');
6 const utils = require('./utils');
7 const constants = require('./constants');
8 const isObject = val => val && typeof val === 'object' && !Array.isArray(val);
9
10 /**
11  * Creates a matcher function from one or more glob patterns. The
12  * returned function takes a string to match as its first argument,
13  * and returns true if the string is a match. The returned matcher
14  * function also takes a boolean as the second argument that, when true,
15  * returns an object with additional information.
16  *
17  * ```js
18  * const picomatch = require('picomatch');
19  * // picomatch(glob[, options]);
20  *
21  * const isMatch = picomatch('*.!(*a)');
22  * console.log(isMatch('a.a')); //=> false
23  * console.log(isMatch('a.b')); //=> true
24  * ```
25  * @name picomatch
26  * @param {String|Array} `globs` One or more glob patterns.
27  * @param {Object=} `options`
28  * @return {Function=} Returns a matcher function.
29  * @api public
30  */
31
32 const picomatch = (glob, options, returnState = false) => {
33   if (Array.isArray(glob)) {
34     const fns = glob.map(input => picomatch(input, options, returnState));
35     const arrayMatcher = str => {
36       for (const isMatch of fns) {
37         const state = isMatch(str);
38         if (state) return state;
39       }
40       return false;
41     };
42     return arrayMatcher;
43   }
44
45   const isState = isObject(glob) && glob.tokens && glob.input;
46
47   if (glob === '' || (typeof glob !== 'string' && !isState)) {
48     throw new TypeError('Expected pattern to be a non-empty string');
49   }
50
51   const opts = options || {};
52   const posix = utils.isWindows(options);
53   const regex = isState
54     ? picomatch.compileRe(glob, options)
55     : picomatch.makeRe(glob, options, false, true);
56
57   const state = regex.state;
58   delete regex.state;
59
60   let isIgnored = () => false;
61   if (opts.ignore) {
62     const ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null };
63     isIgnored = picomatch(opts.ignore, ignoreOpts, returnState);
64   }
65
66   const matcher = (input, returnObject = false) => {
67     const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix });
68     const result = { glob, state, regex, posix, input, output, match, isMatch };
69
70     if (typeof opts.onResult === 'function') {
71       opts.onResult(result);
72     }
73
74     if (isMatch === false) {
75       result.isMatch = false;
76       return returnObject ? result : false;
77     }
78
79     if (isIgnored(input)) {
80       if (typeof opts.onIgnore === 'function') {
81         opts.onIgnore(result);
82       }
83       result.isMatch = false;
84       return returnObject ? result : false;
85     }
86
87     if (typeof opts.onMatch === 'function') {
88       opts.onMatch(result);
89     }
90     return returnObject ? result : true;
91   };
92
93   if (returnState) {
94     matcher.state = state;
95   }
96
97   return matcher;
98 };
99
100 /**
101  * Test `input` with the given `regex`. This is used by the main
102  * `picomatch()` function to test the input string.
103  *
104  * ```js
105  * const picomatch = require('picomatch');
106  * // picomatch.test(input, regex[, options]);
107  *
108  * console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/));
109  * // { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' }
110  * ```
111  * @param {String} `input` String to test.
112  * @param {RegExp} `regex`
113  * @return {Object} Returns an object with matching info.
114  * @api public
115  */
116
117 picomatch.test = (input, regex, options, { glob, posix } = {}) => {
118   if (typeof input !== 'string') {
119     throw new TypeError('Expected input to be a string');
120   }
121
122   if (input === '') {
123     return { isMatch: false, output: '' };
124   }
125
126   const opts = options || {};
127   const format = opts.format || (posix ? utils.toPosixSlashes : null);
128   let match = input === glob;
129   let output = (match && format) ? format(input) : input;
130
131   if (match === false) {
132     output = format ? format(input) : input;
133     match = output === glob;
134   }
135
136   if (match === false || opts.capture === true) {
137     if (opts.matchBase === true || opts.basename === true) {
138       match = picomatch.matchBase(input, regex, options, posix);
139     } else {
140       match = regex.exec(output);
141     }
142   }
143
144   return { isMatch: Boolean(match), match, output };
145 };
146
147 /**
148  * Match the basename of a filepath.
149  *
150  * ```js
151  * const picomatch = require('picomatch');
152  * // picomatch.matchBase(input, glob[, options]);
153  * console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true
154  * ```
155  * @param {String} `input` String to test.
156  * @param {RegExp|String} `glob` Glob pattern or regex created by [.makeRe](#makeRe).
157  * @return {Boolean}
158  * @api public
159  */
160
161 picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => {
162   const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options);
163   return regex.test(path.basename(input));
164 };
165
166 /**
167  * Returns true if **any** of the given glob `patterns` match the specified `string`.
168  *
169  * ```js
170  * const picomatch = require('picomatch');
171  * // picomatch.isMatch(string, patterns[, options]);
172  *
173  * console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true
174  * console.log(picomatch.isMatch('a.a', 'b.*')); //=> false
175  * ```
176  * @param {String|Array} str The string to test.
177  * @param {String|Array} patterns One or more glob patterns to use for matching.
178  * @param {Object} [options] See available [options](#options).
179  * @return {Boolean} Returns true if any patterns match `str`
180  * @api public
181  */
182
183 picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str);
184
185 /**
186  * Parse a glob pattern to create the source string for a regular
187  * expression.
188  *
189  * ```js
190  * const picomatch = require('picomatch');
191  * const result = picomatch.parse(pattern[, options]);
192  * ```
193  * @param {String} `pattern`
194  * @param {Object} `options`
195  * @return {Object} Returns an object with useful properties and output to be used as a regex source string.
196  * @api public
197  */
198
199 picomatch.parse = (pattern, options) => {
200   if (Array.isArray(pattern)) return pattern.map(p => picomatch.parse(p, options));
201   return parse(pattern, { ...options, fastpaths: false });
202 };
203
204 /**
205  * Scan a glob pattern to separate the pattern into segments.
206  *
207  * ```js
208  * const picomatch = require('picomatch');
209  * // picomatch.scan(input[, options]);
210  *
211  * const result = picomatch.scan('!./foo/*.js');
212  * console.log(result);
213  * { prefix: '!./',
214  *   input: '!./foo/*.js',
215  *   start: 3,
216  *   base: 'foo',
217  *   glob: '*.js',
218  *   isBrace: false,
219  *   isBracket: false,
220  *   isGlob: true,
221  *   isExtglob: false,
222  *   isGlobstar: false,
223  *   negated: true }
224  * ```
225  * @param {String} `input` Glob pattern to scan.
226  * @param {Object} `options`
227  * @return {Object} Returns an object with
228  * @api public
229  */
230
231 picomatch.scan = (input, options) => scan(input, options);
232
233 /**
234  * Compile a regular expression from the `state` object returned by the
235  * [parse()](#parse) method.
236  *
237  * @param {Object} `state`
238  * @param {Object} `options`
239  * @param {Boolean} `returnOutput` Intended for implementors, this argument allows you to return the raw output from the parser.
240  * @param {Boolean} `returnState` Adds the state to a `state` property on the returned regex. Useful for implementors and debugging.
241  * @return {RegExp}
242  * @api public
243  */
244
245 picomatch.compileRe = (state, options, returnOutput = false, returnState = false) => {
246   if (returnOutput === true) {
247     return state.output;
248   }
249
250   const opts = options || {};
251   const prepend = opts.contains ? '' : '^';
252   const append = opts.contains ? '' : '$';
253
254   let source = `${prepend}(?:${state.output})${append}`;
255   if (state && state.negated === true) {
256     source = `^(?!${source}).*$`;
257   }
258
259   const regex = picomatch.toRegex(source, options);
260   if (returnState === true) {
261     regex.state = state;
262   }
263
264   return regex;
265 };
266
267 /**
268  * Create a regular expression from a parsed glob pattern.
269  *
270  * ```js
271  * const picomatch = require('picomatch');
272  * const state = picomatch.parse('*.js');
273  * // picomatch.compileRe(state[, options]);
274  *
275  * console.log(picomatch.compileRe(state));
276  * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
277  * ```
278  * @param {String} `state` The object returned from the `.parse` method.
279  * @param {Object} `options`
280  * @param {Boolean} `returnOutput` Implementors may use this argument to return the compiled output, instead of a regular expression. This is not exposed on the options to prevent end-users from mutating the result.
281  * @param {Boolean} `returnState` Implementors may use this argument to return the state from the parsed glob with the returned regular expression.
282  * @return {RegExp} Returns a regex created from the given pattern.
283  * @api public
284  */
285
286 picomatch.makeRe = (input, options = {}, returnOutput = false, returnState = false) => {
287   if (!input || typeof input !== 'string') {
288     throw new TypeError('Expected a non-empty string');
289   }
290
291   let parsed = { negated: false, fastpaths: true };
292
293   if (options.fastpaths !== false && (input[0] === '.' || input[0] === '*')) {
294     parsed.output = parse.fastpaths(input, options);
295   }
296
297   if (!parsed.output) {
298     parsed = parse(input, options);
299   }
300
301   return picomatch.compileRe(parsed, options, returnOutput, returnState);
302 };
303
304 /**
305  * Create a regular expression from the given regex source string.
306  *
307  * ```js
308  * const picomatch = require('picomatch');
309  * // picomatch.toRegex(source[, options]);
310  *
311  * const { output } = picomatch.parse('*.js');
312  * console.log(picomatch.toRegex(output));
313  * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
314  * ```
315  * @param {String} `source` Regular expression source string.
316  * @param {Object} `options`
317  * @return {RegExp}
318  * @api public
319  */
320
321 picomatch.toRegex = (source, options) => {
322   try {
323     const opts = options || {};
324     return new RegExp(source, opts.flags || (opts.nocase ? 'i' : ''));
325   } catch (err) {
326     if (options && options.debug === true) throw err;
327     return /$^/;
328   }
329 };
330
331 /**
332  * Picomatch constants.
333  * @return {Object}
334  */
335
336 picomatch.constants = constants;
337
338 /**
339  * Expose "picomatch"
340  */
341
342 module.exports = picomatch;