UNPKG

121 kBJavaScriptView Raw
1/*
2 @license
3 Rollup.js v2.75.7
4 Mon, 20 Jun 2022 07:24:02 GMT - commit 057171c2d3bc2092b7f543fc05ead01f12595f12
5
6 https://github.com/rollup/rollup
7
8 Released under the MIT License.
9*/
10'use strict';
11
12const rollup = require('./rollup.js');
13const require$$0$1 = require('fs');
14const require$$2 = require('util');
15const require$$1 = require('stream');
16const require$$0$2 = require('path');
17const require$$2$1 = require('os');
18const require$$0$3 = require('events');
19
20var chokidar = {};
21
22const fs$3 = require$$0$1;
23const { Readable } = require$$1;
24const sysPath$3 = require$$0$2;
25const { promisify: promisify$3 } = require$$2;
26const picomatch$1 = rollup.picomatch.exports;
27
28const readdir$1 = promisify$3(fs$3.readdir);
29const stat$3 = promisify$3(fs$3.stat);
30const lstat$2 = promisify$3(fs$3.lstat);
31const realpath$1 = promisify$3(fs$3.realpath);
32
33/**
34 * @typedef {Object} EntryInfo
35 * @property {String} path
36 * @property {String} fullPath
37 * @property {fs.Stats=} stats
38 * @property {fs.Dirent=} dirent
39 * @property {String} basename
40 */
41
42const BANG$2 = '!';
43const RECURSIVE_ERROR_CODE = 'READDIRP_RECURSIVE_ERROR';
44const NORMAL_FLOW_ERRORS = new Set(['ENOENT', 'EPERM', 'EACCES', 'ELOOP', RECURSIVE_ERROR_CODE]);
45const FILE_TYPE = 'files';
46const DIR_TYPE = 'directories';
47const FILE_DIR_TYPE = 'files_directories';
48const EVERYTHING_TYPE = 'all';
49const ALL_TYPES = [FILE_TYPE, DIR_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE];
50
51const isNormalFlowError = error => NORMAL_FLOW_ERRORS.has(error.code);
52const [maj, min] = process.versions.node.split('.').slice(0, 2).map(n => Number.parseInt(n, 10));
53const wantBigintFsStats = process.platform === 'win32' && (maj > 10 || (maj === 10 && min >= 5));
54
55const normalizeFilter = filter => {
56 if (filter === undefined) return;
57 if (typeof filter === 'function') return filter;
58
59 if (typeof filter === 'string') {
60 const glob = picomatch$1(filter.trim());
61 return entry => glob(entry.basename);
62 }
63
64 if (Array.isArray(filter)) {
65 const positive = [];
66 const negative = [];
67 for (const item of filter) {
68 const trimmed = item.trim();
69 if (trimmed.charAt(0) === BANG$2) {
70 negative.push(picomatch$1(trimmed.slice(1)));
71 } else {
72 positive.push(picomatch$1(trimmed));
73 }
74 }
75
76 if (negative.length > 0) {
77 if (positive.length > 0) {
78 return entry =>
79 positive.some(f => f(entry.basename)) && !negative.some(f => f(entry.basename));
80 }
81 return entry => !negative.some(f => f(entry.basename));
82 }
83 return entry => positive.some(f => f(entry.basename));
84 }
85};
86
87class ReaddirpStream extends Readable {
88 static get defaultOptions() {
89 return {
90 root: '.',
91 /* eslint-disable no-unused-vars */
92 fileFilter: (path) => true,
93 directoryFilter: (path) => true,
94 /* eslint-enable no-unused-vars */
95 type: FILE_TYPE,
96 lstat: false,
97 depth: 2147483648,
98 alwaysStat: false
99 };
100 }
101
102 constructor(options = {}) {
103 super({
104 objectMode: true,
105 autoDestroy: true,
106 highWaterMark: options.highWaterMark || 4096
107 });
108 const opts = { ...ReaddirpStream.defaultOptions, ...options };
109 const { root, type } = opts;
110
111 this._fileFilter = normalizeFilter(opts.fileFilter);
112 this._directoryFilter = normalizeFilter(opts.directoryFilter);
113
114 const statMethod = opts.lstat ? lstat$2 : stat$3;
115 // Use bigint stats if it's windows and stat() supports options (node 10+).
116 if (wantBigintFsStats) {
117 this._stat = path => statMethod(path, { bigint: true });
118 } else {
119 this._stat = statMethod;
120 }
121
122 this._maxDepth = opts.depth;
123 this._wantsDir = [DIR_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE].includes(type);
124 this._wantsFile = [FILE_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE].includes(type);
125 this._wantsEverything = type === EVERYTHING_TYPE;
126 this._root = sysPath$3.resolve(root);
127 this._isDirent = ('Dirent' in fs$3) && !opts.alwaysStat;
128 this._statsProp = this._isDirent ? 'dirent' : 'stats';
129 this._rdOptions = { encoding: 'utf8', withFileTypes: this._isDirent };
130
131 // Launch stream with one parent, the root dir.
132 this.parents = [this._exploreDir(root, 1)];
133 this.reading = false;
134 this.parent = undefined;
135 }
136
137 async _read(batch) {
138 if (this.reading) return;
139 this.reading = true;
140
141 try {
142 while (!this.destroyed && batch > 0) {
143 const { path, depth, files = [] } = this.parent || {};
144
145 if (files.length > 0) {
146 const slice = files.splice(0, batch).map(dirent => this._formatEntry(dirent, path));
147 for (const entry of await Promise.all(slice)) {
148 if (this.destroyed) return;
149
150 const entryType = await this._getEntryType(entry);
151 if (entryType === 'directory' && this._directoryFilter(entry)) {
152 if (depth <= this._maxDepth) {
153 this.parents.push(this._exploreDir(entry.fullPath, depth + 1));
154 }
155
156 if (this._wantsDir) {
157 this.push(entry);
158 batch--;
159 }
160 } else if ((entryType === 'file' || this._includeAsFile(entry)) && this._fileFilter(entry)) {
161 if (this._wantsFile) {
162 this.push(entry);
163 batch--;
164 }
165 }
166 }
167 } else {
168 const parent = this.parents.pop();
169 if (!parent) {
170 this.push(null);
171 break;
172 }
173 this.parent = await parent;
174 if (this.destroyed) return;
175 }
176 }
177 } catch (error) {
178 this.destroy(error);
179 } finally {
180 this.reading = false;
181 }
182 }
183
184 async _exploreDir(path, depth) {
185 let files;
186 try {
187 files = await readdir$1(path, this._rdOptions);
188 } catch (error) {
189 this._onError(error);
190 }
191 return { files, depth, path };
192 }
193
194 async _formatEntry(dirent, path) {
195 let entry;
196 try {
197 const basename = this._isDirent ? dirent.name : dirent;
198 const fullPath = sysPath$3.resolve(sysPath$3.join(path, basename));
199 entry = { path: sysPath$3.relative(this._root, fullPath), fullPath, basename };
200 entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
201 } catch (err) {
202 this._onError(err);
203 }
204 return entry;
205 }
206
207 _onError(err) {
208 if (isNormalFlowError(err) && !this.destroyed) {
209 this.emit('warn', err);
210 } else {
211 this.destroy(err);
212 }
213 }
214
215 async _getEntryType(entry) {
216 // entry may be undefined, because a warning or an error were emitted
217 // and the statsProp is undefined
218 const stats = entry && entry[this._statsProp];
219 if (!stats) {
220 return;
221 }
222 if (stats.isFile()) {
223 return 'file';
224 }
225 if (stats.isDirectory()) {
226 return 'directory';
227 }
228 if (stats && stats.isSymbolicLink()) {
229 const full = entry.fullPath;
230 try {
231 const entryRealPath = await realpath$1(full);
232 const entryRealPathStats = await lstat$2(entryRealPath);
233 if (entryRealPathStats.isFile()) {
234 return 'file';
235 }
236 if (entryRealPathStats.isDirectory()) {
237 const len = entryRealPath.length;
238 if (full.startsWith(entryRealPath) && full.substr(len, 1) === sysPath$3.sep) {
239 const recursiveError = new Error(
240 `Circular symlink detected: "${full}" points to "${entryRealPath}"`
241 );
242 recursiveError.code = RECURSIVE_ERROR_CODE;
243 return this._onError(recursiveError);
244 }
245 return 'directory';
246 }
247 } catch (error) {
248 this._onError(error);
249 }
250 }
251 }
252
253 _includeAsFile(entry) {
254 const stats = entry && entry[this._statsProp];
255
256 return stats && this._wantsEverything && !stats.isDirectory();
257 }
258}
259
260/**
261 * @typedef {Object} ReaddirpArguments
262 * @property {Function=} fileFilter
263 * @property {Function=} directoryFilter
264 * @property {String=} type
265 * @property {Number=} depth
266 * @property {String=} root
267 * @property {Boolean=} lstat
268 * @property {Boolean=} bigint
269 */
270
271/**
272 * Main function which ends up calling readdirRec and reads all files and directories in given root recursively.
273 * @param {String} root Root directory
274 * @param {ReaddirpArguments=} options Options to specify root (start directory), filters and recursion depth
275 */
276const readdirp$1 = (root, options = {}) => {
277 let type = options.entryType || options.type;
278 if (type === 'both') type = FILE_DIR_TYPE; // backwards-compatibility
279 if (type) options.type = type;
280 if (!root) {
281 throw new Error('readdirp: root argument is required. Usage: readdirp(root, options)');
282 } else if (typeof root !== 'string') {
283 throw new TypeError('readdirp: root argument must be a string. Usage: readdirp(root, options)');
284 } else if (type && !ALL_TYPES.includes(type)) {
285 throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(', ')}`);
286 }
287
288 options.root = root;
289 return new ReaddirpStream(options);
290};
291
292const readdirpPromise = (root, options = {}) => {
293 return new Promise((resolve, reject) => {
294 const files = [];
295 readdirp$1(root, options)
296 .on('data', entry => files.push(entry))
297 .on('end', () => resolve(files))
298 .on('error', error => reject(error));
299 });
300};
301
302readdirp$1.promise = readdirpPromise;
303readdirp$1.ReaddirpStream = ReaddirpStream;
304readdirp$1.default = readdirp$1;
305
306var readdirp_1 = readdirp$1;
307
308var anymatch$2 = {exports: {}};
309
310/*!
311 * normalize-path <https://github.com/jonschlinkert/normalize-path>
312 *
313 * Copyright (c) 2014-2018, Jon Schlinkert.
314 * Released under the MIT License.
315 */
316
317var normalizePath$2 = function(path, stripTrailing) {
318 if (typeof path !== 'string') {
319 throw new TypeError('expected path to be a string');
320 }
321
322 if (path === '\\' || path === '/') return '/';
323
324 var len = path.length;
325 if (len <= 1) return path;
326
327 // ensure that win32 namespaces has two leading slashes, so that the path is
328 // handled properly by the win32 version of path.parse() after being normalized
329 // https://msdn.microsoft.com/library/windows/desktop/aa365247(v=vs.85).aspx#namespaces
330 var prefix = '';
331 if (len > 4 && path[3] === '\\') {
332 var ch = path[2];
333 if ((ch === '?' || ch === '.') && path.slice(0, 2) === '\\\\') {
334 path = path.slice(2);
335 prefix = '//';
336 }
337 }
338
339 var segs = path.split(/[/\\]+/);
340 if (stripTrailing !== false && segs[segs.length - 1] === '') {
341 segs.pop();
342 }
343 return prefix + segs.join('/');
344};
345
346Object.defineProperty(anymatch$2.exports, "__esModule", { value: true });
347
348const picomatch = rollup.picomatch.exports;
349const normalizePath$1 = normalizePath$2;
350
351/**
352 * @typedef {(testString: string) => boolean} AnymatchFn
353 * @typedef {string|RegExp|AnymatchFn} AnymatchPattern
354 * @typedef {AnymatchPattern|AnymatchPattern[]} AnymatchMatcher
355 */
356const BANG$1 = '!';
357const DEFAULT_OPTIONS = {returnIndex: false};
358const arrify$1 = (item) => Array.isArray(item) ? item : [item];
359
360/**
361 * @param {AnymatchPattern} matcher
362 * @param {object} options
363 * @returns {AnymatchFn}
364 */
365const createPattern = (matcher, options) => {
366 if (typeof matcher === 'function') {
367 return matcher;
368 }
369 if (typeof matcher === 'string') {
370 const glob = picomatch(matcher, options);
371 return (string) => matcher === string || glob(string);
372 }
373 if (matcher instanceof RegExp) {
374 return (string) => matcher.test(string);
375 }
376 return (string) => false;
377};
378
379/**
380 * @param {Array<Function>} patterns
381 * @param {Array<Function>} negPatterns
382 * @param {String|Array} args
383 * @param {Boolean} returnIndex
384 * @returns {boolean|number}
385 */
386const matchPatterns = (patterns, negPatterns, args, returnIndex) => {
387 const isList = Array.isArray(args);
388 const _path = isList ? args[0] : args;
389 if (!isList && typeof _path !== 'string') {
390 throw new TypeError('anymatch: second argument must be a string: got ' +
391 Object.prototype.toString.call(_path))
392 }
393 const path = normalizePath$1(_path);
394
395 for (let index = 0; index < negPatterns.length; index++) {
396 const nglob = negPatterns[index];
397 if (nglob(path)) {
398 return returnIndex ? -1 : false;
399 }
400 }
401
402 const applied = isList && [path].concat(args.slice(1));
403 for (let index = 0; index < patterns.length; index++) {
404 const pattern = patterns[index];
405 if (isList ? pattern(...applied) : pattern(path)) {
406 return returnIndex ? index : true;
407 }
408 }
409
410 return returnIndex ? -1 : false;
411};
412
413/**
414 * @param {AnymatchMatcher} matchers
415 * @param {Array|string} testString
416 * @param {object} options
417 * @returns {boolean|number|Function}
418 */
419const anymatch$1 = (matchers, testString, options = DEFAULT_OPTIONS) => {
420 if (matchers == null) {
421 throw new TypeError('anymatch: specify first argument');
422 }
423 const opts = typeof options === 'boolean' ? {returnIndex: options} : options;
424 const returnIndex = opts.returnIndex || false;
425
426 // Early cache for matchers.
427 const mtchers = arrify$1(matchers);
428 const negatedGlobs = mtchers
429 .filter(item => typeof item === 'string' && item.charAt(0) === BANG$1)
430 .map(item => item.slice(1))
431 .map(item => picomatch(item, opts));
432 const patterns = mtchers
433 .filter(item => typeof item !== 'string' || (typeof item === 'string' && item.charAt(0) !== BANG$1))
434 .map(matcher => createPattern(matcher, opts));
435
436 if (testString == null) {
437 return (testString, ri = false) => {
438 const returnIndex = typeof ri === 'boolean' ? ri : false;
439 return matchPatterns(patterns, negatedGlobs, testString, returnIndex);
440 }
441 }
442
443 return matchPatterns(patterns, negatedGlobs, testString, returnIndex);
444};
445
446anymatch$1.default = anymatch$1;
447anymatch$2.exports = anymatch$1;
448
449/*!
450 * is-extglob <https://github.com/jonschlinkert/is-extglob>
451 *
452 * Copyright (c) 2014-2016, Jon Schlinkert.
453 * Licensed under the MIT License.
454 */
455
456var isExtglob$1 = function isExtglob(str) {
457 if (typeof str !== 'string' || str === '') {
458 return false;
459 }
460
461 var match;
462 while ((match = /(\\).|([@?!+*]\(.*\))/g.exec(str))) {
463 if (match[2]) return true;
464 str = str.slice(match.index + match[0].length);
465 }
466
467 return false;
468};
469
470/*!
471 * is-glob <https://github.com/jonschlinkert/is-glob>
472 *
473 * Copyright (c) 2014-2017, Jon Schlinkert.
474 * Released under the MIT License.
475 */
476
477var isExtglob = isExtglob$1;
478var chars = { '{': '}', '(': ')', '[': ']'};
479var strictCheck = function(str) {
480 if (str[0] === '!') {
481 return true;
482 }
483 var index = 0;
484 var pipeIndex = -2;
485 var closeSquareIndex = -2;
486 var closeCurlyIndex = -2;
487 var closeParenIndex = -2;
488 var backSlashIndex = -2;
489 while (index < str.length) {
490 if (str[index] === '*') {
491 return true;
492 }
493
494 if (str[index + 1] === '?' && /[\].+)]/.test(str[index])) {
495 return true;
496 }
497
498 if (closeSquareIndex !== -1 && str[index] === '[' && str[index + 1] !== ']') {
499 if (closeSquareIndex < index) {
500 closeSquareIndex = str.indexOf(']', index);
501 }
502 if (closeSquareIndex > index) {
503 if (backSlashIndex === -1 || backSlashIndex > closeSquareIndex) {
504 return true;
505 }
506 backSlashIndex = str.indexOf('\\', index);
507 if (backSlashIndex === -1 || backSlashIndex > closeSquareIndex) {
508 return true;
509 }
510 }
511 }
512
513 if (closeCurlyIndex !== -1 && str[index] === '{' && str[index + 1] !== '}') {
514 closeCurlyIndex = str.indexOf('}', index);
515 if (closeCurlyIndex > index) {
516 backSlashIndex = str.indexOf('\\', index);
517 if (backSlashIndex === -1 || backSlashIndex > closeCurlyIndex) {
518 return true;
519 }
520 }
521 }
522
523 if (closeParenIndex !== -1 && str[index] === '(' && str[index + 1] === '?' && /[:!=]/.test(str[index + 2]) && str[index + 3] !== ')') {
524 closeParenIndex = str.indexOf(')', index);
525 if (closeParenIndex > index) {
526 backSlashIndex = str.indexOf('\\', index);
527 if (backSlashIndex === -1 || backSlashIndex > closeParenIndex) {
528 return true;
529 }
530 }
531 }
532
533 if (pipeIndex !== -1 && str[index] === '(' && str[index + 1] !== '|') {
534 if (pipeIndex < index) {
535 pipeIndex = str.indexOf('|', index);
536 }
537 if (pipeIndex !== -1 && str[pipeIndex + 1] !== ')') {
538 closeParenIndex = str.indexOf(')', pipeIndex);
539 if (closeParenIndex > pipeIndex) {
540 backSlashIndex = str.indexOf('\\', pipeIndex);
541 if (backSlashIndex === -1 || backSlashIndex > closeParenIndex) {
542 return true;
543 }
544 }
545 }
546 }
547
548 if (str[index] === '\\') {
549 var open = str[index + 1];
550 index += 2;
551 var close = chars[open];
552
553 if (close) {
554 var n = str.indexOf(close, index);
555 if (n !== -1) {
556 index = n + 1;
557 }
558 }
559
560 if (str[index] === '!') {
561 return true;
562 }
563 } else {
564 index++;
565 }
566 }
567 return false;
568};
569
570var relaxedCheck = function(str) {
571 if (str[0] === '!') {
572 return true;
573 }
574 var index = 0;
575 while (index < str.length) {
576 if (/[*?{}()[\]]/.test(str[index])) {
577 return true;
578 }
579
580 if (str[index] === '\\') {
581 var open = str[index + 1];
582 index += 2;
583 var close = chars[open];
584
585 if (close) {
586 var n = str.indexOf(close, index);
587 if (n !== -1) {
588 index = n + 1;
589 }
590 }
591
592 if (str[index] === '!') {
593 return true;
594 }
595 } else {
596 index++;
597 }
598 }
599 return false;
600};
601
602var isGlob$2 = function isGlob(str, options) {
603 if (typeof str !== 'string' || str === '') {
604 return false;
605 }
606
607 if (isExtglob(str)) {
608 return true;
609 }
610
611 var check = strictCheck;
612
613 // optionally relax check
614 if (options && options.strict === false) {
615 check = relaxedCheck;
616 }
617
618 return check(str);
619};
620
621var isGlob$1 = isGlob$2;
622var pathPosixDirname = require$$0$2.posix.dirname;
623var isWin32 = require$$2$1.platform() === 'win32';
624
625var slash = '/';
626var backslash = /\\/g;
627var enclosure = /[\{\[].*[\}\]]$/;
628var globby = /(^|[^\\])([\{\[]|\([^\)]+$)/;
629var escaped = /\\([\!\*\?\|\[\]\(\)\{\}])/g;
630
631/**
632 * @param {string} str
633 * @param {Object} opts
634 * @param {boolean} [opts.flipBackslashes=true]
635 * @returns {string}
636 */
637var globParent$1 = function globParent(str, opts) {
638 var options = Object.assign({ flipBackslashes: true }, opts);
639
640 // flip windows path separators
641 if (options.flipBackslashes && isWin32 && str.indexOf(slash) < 0) {
642 str = str.replace(backslash, slash);
643 }
644
645 // special case for strings ending in enclosure containing path separator
646 if (enclosure.test(str)) {
647 str += slash;
648 }
649
650 // preserves full path in case of trailing path separator
651 str += 'a';
652
653 // remove path parts that are globby
654 do {
655 str = pathPosixDirname(str);
656 } while (isGlob$1(str) || globby.test(str));
657
658 // remove escape chars and return result
659 return str.replace(escaped, '$1');
660};
661
662var utils$3 = {};
663
664(function (exports) {
665
666 exports.isInteger = num => {
667 if (typeof num === 'number') {
668 return Number.isInteger(num);
669 }
670 if (typeof num === 'string' && num.trim() !== '') {
671 return Number.isInteger(Number(num));
672 }
673 return false;
674 };
675
676 /**
677 * Find a node of the given type
678 */
679
680 exports.find = (node, type) => node.nodes.find(node => node.type === type);
681
682 /**
683 * Find a node of the given type
684 */
685
686 exports.exceedsLimit = (min, max, step = 1, limit) => {
687 if (limit === false) return false;
688 if (!exports.isInteger(min) || !exports.isInteger(max)) return false;
689 return ((Number(max) - Number(min)) / Number(step)) >= limit;
690 };
691
692 /**
693 * Escape the given node with '\\' before node.value
694 */
695
696 exports.escapeNode = (block, n = 0, type) => {
697 let node = block.nodes[n];
698 if (!node) return;
699
700 if ((type && node.type === type) || node.type === 'open' || node.type === 'close') {
701 if (node.escaped !== true) {
702 node.value = '\\' + node.value;
703 node.escaped = true;
704 }
705 }
706 };
707
708 /**
709 * Returns true if the given brace node should be enclosed in literal braces
710 */
711
712 exports.encloseBrace = node => {
713 if (node.type !== 'brace') return false;
714 if ((node.commas >> 0 + node.ranges >> 0) === 0) {
715 node.invalid = true;
716 return true;
717 }
718 return false;
719 };
720
721 /**
722 * Returns true if a brace node is invalid.
723 */
724
725 exports.isInvalidBrace = block => {
726 if (block.type !== 'brace') return false;
727 if (block.invalid === true || block.dollar) return true;
728 if ((block.commas >> 0 + block.ranges >> 0) === 0) {
729 block.invalid = true;
730 return true;
731 }
732 if (block.open !== true || block.close !== true) {
733 block.invalid = true;
734 return true;
735 }
736 return false;
737 };
738
739 /**
740 * Returns true if a node is an open or close node
741 */
742
743 exports.isOpenOrClose = node => {
744 if (node.type === 'open' || node.type === 'close') {
745 return true;
746 }
747 return node.open === true || node.close === true;
748 };
749
750 /**
751 * Reduce an array of text nodes.
752 */
753
754 exports.reduce = nodes => nodes.reduce((acc, node) => {
755 if (node.type === 'text') acc.push(node.value);
756 if (node.type === 'range') node.type = 'text';
757 return acc;
758 }, []);
759
760 /**
761 * Flatten an array
762 */
763
764 exports.flatten = (...args) => {
765 const result = [];
766 const flat = arr => {
767 for (let i = 0; i < arr.length; i++) {
768 let ele = arr[i];
769 Array.isArray(ele) ? flat(ele) : ele !== void 0 && result.push(ele);
770 }
771 return result;
772 };
773 flat(args);
774 return result;
775 };
776} (utils$3));
777
778const utils$2 = utils$3;
779
780var stringify$4 = (ast, options = {}) => {
781 let stringify = (node, parent = {}) => {
782 let invalidBlock = options.escapeInvalid && utils$2.isInvalidBrace(parent);
783 let invalidNode = node.invalid === true && options.escapeInvalid === true;
784 let output = '';
785
786 if (node.value) {
787 if ((invalidBlock || invalidNode) && utils$2.isOpenOrClose(node)) {
788 return '\\' + node.value;
789 }
790 return node.value;
791 }
792
793 if (node.value) {
794 return node.value;
795 }
796
797 if (node.nodes) {
798 for (let child of node.nodes) {
799 output += stringify(child);
800 }
801 }
802 return output;
803 };
804
805 return stringify(ast);
806};
807
808/*!
809 * is-number <https://github.com/jonschlinkert/is-number>
810 *
811 * Copyright (c) 2014-present, Jon Schlinkert.
812 * Released under the MIT License.
813 */
814
815var isNumber$2 = function(num) {
816 if (typeof num === 'number') {
817 return num - num === 0;
818 }
819 if (typeof num === 'string' && num.trim() !== '') {
820 return Number.isFinite ? Number.isFinite(+num) : isFinite(+num);
821 }
822 return false;
823};
824
825/*!
826 * to-regex-range <https://github.com/micromatch/to-regex-range>
827 *
828 * Copyright (c) 2015-present, Jon Schlinkert.
829 * Released under the MIT License.
830 */
831
832const isNumber$1 = isNumber$2;
833
834const toRegexRange$1 = (min, max, options) => {
835 if (isNumber$1(min) === false) {
836 throw new TypeError('toRegexRange: expected the first argument to be a number');
837 }
838
839 if (max === void 0 || min === max) {
840 return String(min);
841 }
842
843 if (isNumber$1(max) === false) {
844 throw new TypeError('toRegexRange: expected the second argument to be a number.');
845 }
846
847 let opts = { relaxZeros: true, ...options };
848 if (typeof opts.strictZeros === 'boolean') {
849 opts.relaxZeros = opts.strictZeros === false;
850 }
851
852 let relax = String(opts.relaxZeros);
853 let shorthand = String(opts.shorthand);
854 let capture = String(opts.capture);
855 let wrap = String(opts.wrap);
856 let cacheKey = min + ':' + max + '=' + relax + shorthand + capture + wrap;
857
858 if (toRegexRange$1.cache.hasOwnProperty(cacheKey)) {
859 return toRegexRange$1.cache[cacheKey].result;
860 }
861
862 let a = Math.min(min, max);
863 let b = Math.max(min, max);
864
865 if (Math.abs(a - b) === 1) {
866 let result = min + '|' + max;
867 if (opts.capture) {
868 return `(${result})`;
869 }
870 if (opts.wrap === false) {
871 return result;
872 }
873 return `(?:${result})`;
874 }
875
876 let isPadded = hasPadding(min) || hasPadding(max);
877 let state = { min, max, a, b };
878 let positives = [];
879 let negatives = [];
880
881 if (isPadded) {
882 state.isPadded = isPadded;
883 state.maxLen = String(state.max).length;
884 }
885
886 if (a < 0) {
887 let newMin = b < 0 ? Math.abs(b) : 1;
888 negatives = splitToPatterns(newMin, Math.abs(a), state, opts);
889 a = state.a = 0;
890 }
891
892 if (b >= 0) {
893 positives = splitToPatterns(a, b, state, opts);
894 }
895
896 state.negatives = negatives;
897 state.positives = positives;
898 state.result = collatePatterns(negatives, positives);
899
900 if (opts.capture === true) {
901 state.result = `(${state.result})`;
902 } else if (opts.wrap !== false && (positives.length + negatives.length) > 1) {
903 state.result = `(?:${state.result})`;
904 }
905
906 toRegexRange$1.cache[cacheKey] = state;
907 return state.result;
908};
909
910function collatePatterns(neg, pos, options) {
911 let onlyNegative = filterPatterns(neg, pos, '-', false) || [];
912 let onlyPositive = filterPatterns(pos, neg, '', false) || [];
913 let intersected = filterPatterns(neg, pos, '-?', true) || [];
914 let subpatterns = onlyNegative.concat(intersected).concat(onlyPositive);
915 return subpatterns.join('|');
916}
917
918function splitToRanges(min, max) {
919 let nines = 1;
920 let zeros = 1;
921
922 let stop = countNines(min, nines);
923 let stops = new Set([max]);
924
925 while (min <= stop && stop <= max) {
926 stops.add(stop);
927 nines += 1;
928 stop = countNines(min, nines);
929 }
930
931 stop = countZeros(max + 1, zeros) - 1;
932
933 while (min < stop && stop <= max) {
934 stops.add(stop);
935 zeros += 1;
936 stop = countZeros(max + 1, zeros) - 1;
937 }
938
939 stops = [...stops];
940 stops.sort(compare);
941 return stops;
942}
943
944/**
945 * Convert a range to a regex pattern
946 * @param {Number} `start`
947 * @param {Number} `stop`
948 * @return {String}
949 */
950
951function rangeToPattern(start, stop, options) {
952 if (start === stop) {
953 return { pattern: start, count: [], digits: 0 };
954 }
955
956 let zipped = zip(start, stop);
957 let digits = zipped.length;
958 let pattern = '';
959 let count = 0;
960
961 for (let i = 0; i < digits; i++) {
962 let [startDigit, stopDigit] = zipped[i];
963
964 if (startDigit === stopDigit) {
965 pattern += startDigit;
966
967 } else if (startDigit !== '0' || stopDigit !== '9') {
968 pattern += toCharacterClass(startDigit, stopDigit);
969
970 } else {
971 count++;
972 }
973 }
974
975 if (count) {
976 pattern += options.shorthand === true ? '\\d' : '[0-9]';
977 }
978
979 return { pattern, count: [count], digits };
980}
981
982function splitToPatterns(min, max, tok, options) {
983 let ranges = splitToRanges(min, max);
984 let tokens = [];
985 let start = min;
986 let prev;
987
988 for (let i = 0; i < ranges.length; i++) {
989 let max = ranges[i];
990 let obj = rangeToPattern(String(start), String(max), options);
991 let zeros = '';
992
993 if (!tok.isPadded && prev && prev.pattern === obj.pattern) {
994 if (prev.count.length > 1) {
995 prev.count.pop();
996 }
997
998 prev.count.push(obj.count[0]);
999 prev.string = prev.pattern + toQuantifier(prev.count);
1000 start = max + 1;
1001 continue;
1002 }
1003
1004 if (tok.isPadded) {
1005 zeros = padZeros(max, tok, options);
1006 }
1007
1008 obj.string = zeros + obj.pattern + toQuantifier(obj.count);
1009 tokens.push(obj);
1010 start = max + 1;
1011 prev = obj;
1012 }
1013
1014 return tokens;
1015}
1016
1017function filterPatterns(arr, comparison, prefix, intersection, options) {
1018 let result = [];
1019
1020 for (let ele of arr) {
1021 let { string } = ele;
1022
1023 // only push if _both_ are negative...
1024 if (!intersection && !contains(comparison, 'string', string)) {
1025 result.push(prefix + string);
1026 }
1027
1028 // or _both_ are positive
1029 if (intersection && contains(comparison, 'string', string)) {
1030 result.push(prefix + string);
1031 }
1032 }
1033 return result;
1034}
1035
1036/**
1037 * Zip strings
1038 */
1039
1040function zip(a, b) {
1041 let arr = [];
1042 for (let i = 0; i < a.length; i++) arr.push([a[i], b[i]]);
1043 return arr;
1044}
1045
1046function compare(a, b) {
1047 return a > b ? 1 : b > a ? -1 : 0;
1048}
1049
1050function contains(arr, key, val) {
1051 return arr.some(ele => ele[key] === val);
1052}
1053
1054function countNines(min, len) {
1055 return Number(String(min).slice(0, -len) + '9'.repeat(len));
1056}
1057
1058function countZeros(integer, zeros) {
1059 return integer - (integer % Math.pow(10, zeros));
1060}
1061
1062function toQuantifier(digits) {
1063 let [start = 0, stop = ''] = digits;
1064 if (stop || start > 1) {
1065 return `{${start + (stop ? ',' + stop : '')}}`;
1066 }
1067 return '';
1068}
1069
1070function toCharacterClass(a, b, options) {
1071 return `[${a}${(b - a === 1) ? '' : '-'}${b}]`;
1072}
1073
1074function hasPadding(str) {
1075 return /^-?(0+)\d/.test(str);
1076}
1077
1078function padZeros(value, tok, options) {
1079 if (!tok.isPadded) {
1080 return value;
1081 }
1082
1083 let diff = Math.abs(tok.maxLen - String(value).length);
1084 let relax = options.relaxZeros !== false;
1085
1086 switch (diff) {
1087 case 0:
1088 return '';
1089 case 1:
1090 return relax ? '0?' : '0';
1091 case 2:
1092 return relax ? '0{0,2}' : '00';
1093 default: {
1094 return relax ? `0{0,${diff}}` : `0{${diff}}`;
1095 }
1096 }
1097}
1098
1099/**
1100 * Cache
1101 */
1102
1103toRegexRange$1.cache = {};
1104toRegexRange$1.clearCache = () => (toRegexRange$1.cache = {});
1105
1106/**
1107 * Expose `toRegexRange`
1108 */
1109
1110var toRegexRange_1 = toRegexRange$1;
1111
1112/*!
1113 * fill-range <https://github.com/jonschlinkert/fill-range>
1114 *
1115 * Copyright (c) 2014-present, Jon Schlinkert.
1116 * Licensed under the MIT License.
1117 */
1118
1119const util = require$$2;
1120const toRegexRange = toRegexRange_1;
1121
1122const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val);
1123
1124const transform = toNumber => {
1125 return value => toNumber === true ? Number(value) : String(value);
1126};
1127
1128const isValidValue = value => {
1129 return typeof value === 'number' || (typeof value === 'string' && value !== '');
1130};
1131
1132const isNumber = num => Number.isInteger(+num);
1133
1134const zeros = input => {
1135 let value = `${input}`;
1136 let index = -1;
1137 if (value[0] === '-') value = value.slice(1);
1138 if (value === '0') return false;
1139 while (value[++index] === '0');
1140 return index > 0;
1141};
1142
1143const stringify$3 = (start, end, options) => {
1144 if (typeof start === 'string' || typeof end === 'string') {
1145 return true;
1146 }
1147 return options.stringify === true;
1148};
1149
1150const pad = (input, maxLength, toNumber) => {
1151 if (maxLength > 0) {
1152 let dash = input[0] === '-' ? '-' : '';
1153 if (dash) input = input.slice(1);
1154 input = (dash + input.padStart(dash ? maxLength - 1 : maxLength, '0'));
1155 }
1156 if (toNumber === false) {
1157 return String(input);
1158 }
1159 return input;
1160};
1161
1162const toMaxLen = (input, maxLength) => {
1163 let negative = input[0] === '-' ? '-' : '';
1164 if (negative) {
1165 input = input.slice(1);
1166 maxLength--;
1167 }
1168 while (input.length < maxLength) input = '0' + input;
1169 return negative ? ('-' + input) : input;
1170};
1171
1172const toSequence = (parts, options) => {
1173 parts.negatives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
1174 parts.positives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
1175
1176 let prefix = options.capture ? '' : '?:';
1177 let positives = '';
1178 let negatives = '';
1179 let result;
1180
1181 if (parts.positives.length) {
1182 positives = parts.positives.join('|');
1183 }
1184
1185 if (parts.negatives.length) {
1186 negatives = `-(${prefix}${parts.negatives.join('|')})`;
1187 }
1188
1189 if (positives && negatives) {
1190 result = `${positives}|${negatives}`;
1191 } else {
1192 result = positives || negatives;
1193 }
1194
1195 if (options.wrap) {
1196 return `(${prefix}${result})`;
1197 }
1198
1199 return result;
1200};
1201
1202const toRange = (a, b, isNumbers, options) => {
1203 if (isNumbers) {
1204 return toRegexRange(a, b, { wrap: false, ...options });
1205 }
1206
1207 let start = String.fromCharCode(a);
1208 if (a === b) return start;
1209
1210 let stop = String.fromCharCode(b);
1211 return `[${start}-${stop}]`;
1212};
1213
1214const toRegex = (start, end, options) => {
1215 if (Array.isArray(start)) {
1216 let wrap = options.wrap === true;
1217 let prefix = options.capture ? '' : '?:';
1218 return wrap ? `(${prefix}${start.join('|')})` : start.join('|');
1219 }
1220 return toRegexRange(start, end, options);
1221};
1222
1223const rangeError = (...args) => {
1224 return new RangeError('Invalid range arguments: ' + util.inspect(...args));
1225};
1226
1227const invalidRange = (start, end, options) => {
1228 if (options.strictRanges === true) throw rangeError([start, end]);
1229 return [];
1230};
1231
1232const invalidStep = (step, options) => {
1233 if (options.strictRanges === true) {
1234 throw new TypeError(`Expected step "${step}" to be a number`);
1235 }
1236 return [];
1237};
1238
1239const fillNumbers = (start, end, step = 1, options = {}) => {
1240 let a = Number(start);
1241 let b = Number(end);
1242
1243 if (!Number.isInteger(a) || !Number.isInteger(b)) {
1244 if (options.strictRanges === true) throw rangeError([start, end]);
1245 return [];
1246 }
1247
1248 // fix negative zero
1249 if (a === 0) a = 0;
1250 if (b === 0) b = 0;
1251
1252 let descending = a > b;
1253 let startString = String(start);
1254 let endString = String(end);
1255 let stepString = String(step);
1256 step = Math.max(Math.abs(step), 1);
1257
1258 let padded = zeros(startString) || zeros(endString) || zeros(stepString);
1259 let maxLen = padded ? Math.max(startString.length, endString.length, stepString.length) : 0;
1260 let toNumber = padded === false && stringify$3(start, end, options) === false;
1261 let format = options.transform || transform(toNumber);
1262
1263 if (options.toRegex && step === 1) {
1264 return toRange(toMaxLen(start, maxLen), toMaxLen(end, maxLen), true, options);
1265 }
1266
1267 let parts = { negatives: [], positives: [] };
1268 let push = num => parts[num < 0 ? 'negatives' : 'positives'].push(Math.abs(num));
1269 let range = [];
1270 let index = 0;
1271
1272 while (descending ? a >= b : a <= b) {
1273 if (options.toRegex === true && step > 1) {
1274 push(a);
1275 } else {
1276 range.push(pad(format(a, index), maxLen, toNumber));
1277 }
1278 a = descending ? a - step : a + step;
1279 index++;
1280 }
1281
1282 if (options.toRegex === true) {
1283 return step > 1
1284 ? toSequence(parts, options)
1285 : toRegex(range, null, { wrap: false, ...options });
1286 }
1287
1288 return range;
1289};
1290
1291const fillLetters = (start, end, step = 1, options = {}) => {
1292 if ((!isNumber(start) && start.length > 1) || (!isNumber(end) && end.length > 1)) {
1293 return invalidRange(start, end, options);
1294 }
1295
1296
1297 let format = options.transform || (val => String.fromCharCode(val));
1298 let a = `${start}`.charCodeAt(0);
1299 let b = `${end}`.charCodeAt(0);
1300
1301 let descending = a > b;
1302 let min = Math.min(a, b);
1303 let max = Math.max(a, b);
1304
1305 if (options.toRegex && step === 1) {
1306 return toRange(min, max, false, options);
1307 }
1308
1309 let range = [];
1310 let index = 0;
1311
1312 while (descending ? a >= b : a <= b) {
1313 range.push(format(a, index));
1314 a = descending ? a - step : a + step;
1315 index++;
1316 }
1317
1318 if (options.toRegex === true) {
1319 return toRegex(range, null, { wrap: false, options });
1320 }
1321
1322 return range;
1323};
1324
1325const fill$2 = (start, end, step, options = {}) => {
1326 if (end == null && isValidValue(start)) {
1327 return [start];
1328 }
1329
1330 if (!isValidValue(start) || !isValidValue(end)) {
1331 return invalidRange(start, end, options);
1332 }
1333
1334 if (typeof step === 'function') {
1335 return fill$2(start, end, 1, { transform: step });
1336 }
1337
1338 if (isObject(step)) {
1339 return fill$2(start, end, 0, step);
1340 }
1341
1342 let opts = { ...options };
1343 if (opts.capture === true) opts.wrap = true;
1344 step = step || opts.step || 1;
1345
1346 if (!isNumber(step)) {
1347 if (step != null && !isObject(step)) return invalidStep(step, opts);
1348 return fill$2(start, end, 1, step);
1349 }
1350
1351 if (isNumber(start) && isNumber(end)) {
1352 return fillNumbers(start, end, step, opts);
1353 }
1354
1355 return fillLetters(start, end, Math.max(Math.abs(step), 1), opts);
1356};
1357
1358var fillRange = fill$2;
1359
1360const fill$1 = fillRange;
1361const utils$1 = utils$3;
1362
1363const compile$1 = (ast, options = {}) => {
1364 let walk = (node, parent = {}) => {
1365 let invalidBlock = utils$1.isInvalidBrace(parent);
1366 let invalidNode = node.invalid === true && options.escapeInvalid === true;
1367 let invalid = invalidBlock === true || invalidNode === true;
1368 let prefix = options.escapeInvalid === true ? '\\' : '';
1369 let output = '';
1370
1371 if (node.isOpen === true) {
1372 return prefix + node.value;
1373 }
1374 if (node.isClose === true) {
1375 return prefix + node.value;
1376 }
1377
1378 if (node.type === 'open') {
1379 return invalid ? (prefix + node.value) : '(';
1380 }
1381
1382 if (node.type === 'close') {
1383 return invalid ? (prefix + node.value) : ')';
1384 }
1385
1386 if (node.type === 'comma') {
1387 return node.prev.type === 'comma' ? '' : (invalid ? node.value : '|');
1388 }
1389
1390 if (node.value) {
1391 return node.value;
1392 }
1393
1394 if (node.nodes && node.ranges > 0) {
1395 let args = utils$1.reduce(node.nodes);
1396 let range = fill$1(...args, { ...options, wrap: false, toRegex: true });
1397
1398 if (range.length !== 0) {
1399 return args.length > 1 && range.length > 1 ? `(${range})` : range;
1400 }
1401 }
1402
1403 if (node.nodes) {
1404 for (let child of node.nodes) {
1405 output += walk(child, node);
1406 }
1407 }
1408 return output;
1409 };
1410
1411 return walk(ast);
1412};
1413
1414var compile_1 = compile$1;
1415
1416const fill = fillRange;
1417const stringify$2 = stringify$4;
1418const utils = utils$3;
1419
1420const append = (queue = '', stash = '', enclose = false) => {
1421 let result = [];
1422
1423 queue = [].concat(queue);
1424 stash = [].concat(stash);
1425
1426 if (!stash.length) return queue;
1427 if (!queue.length) {
1428 return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash;
1429 }
1430
1431 for (let item of queue) {
1432 if (Array.isArray(item)) {
1433 for (let value of item) {
1434 result.push(append(value, stash, enclose));
1435 }
1436 } else {
1437 for (let ele of stash) {
1438 if (enclose === true && typeof ele === 'string') ele = `{${ele}}`;
1439 result.push(Array.isArray(ele) ? append(item, ele, enclose) : (item + ele));
1440 }
1441 }
1442 }
1443 return utils.flatten(result);
1444};
1445
1446const expand$1 = (ast, options = {}) => {
1447 let rangeLimit = options.rangeLimit === void 0 ? 1000 : options.rangeLimit;
1448
1449 let walk = (node, parent = {}) => {
1450 node.queue = [];
1451
1452 let p = parent;
1453 let q = parent.queue;
1454
1455 while (p.type !== 'brace' && p.type !== 'root' && p.parent) {
1456 p = p.parent;
1457 q = p.queue;
1458 }
1459
1460 if (node.invalid || node.dollar) {
1461 q.push(append(q.pop(), stringify$2(node, options)));
1462 return;
1463 }
1464
1465 if (node.type === 'brace' && node.invalid !== true && node.nodes.length === 2) {
1466 q.push(append(q.pop(), ['{}']));
1467 return;
1468 }
1469
1470 if (node.nodes && node.ranges > 0) {
1471 let args = utils.reduce(node.nodes);
1472
1473 if (utils.exceedsLimit(...args, options.step, rangeLimit)) {
1474 throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.');
1475 }
1476
1477 let range = fill(...args, options);
1478 if (range.length === 0) {
1479 range = stringify$2(node, options);
1480 }
1481
1482 q.push(append(q.pop(), range));
1483 node.nodes = [];
1484 return;
1485 }
1486
1487 let enclose = utils.encloseBrace(node);
1488 let queue = node.queue;
1489 let block = node;
1490
1491 while (block.type !== 'brace' && block.type !== 'root' && block.parent) {
1492 block = block.parent;
1493 queue = block.queue;
1494 }
1495
1496 for (let i = 0; i < node.nodes.length; i++) {
1497 let child = node.nodes[i];
1498
1499 if (child.type === 'comma' && node.type === 'brace') {
1500 if (i === 1) queue.push('');
1501 queue.push('');
1502 continue;
1503 }
1504
1505 if (child.type === 'close') {
1506 q.push(append(q.pop(), queue, enclose));
1507 continue;
1508 }
1509
1510 if (child.value && child.type !== 'open') {
1511 queue.push(append(queue.pop(), child.value));
1512 continue;
1513 }
1514
1515 if (child.nodes) {
1516 walk(child, node);
1517 }
1518 }
1519
1520 return queue;
1521 };
1522
1523 return utils.flatten(walk(ast));
1524};
1525
1526var expand_1 = expand$1;
1527
1528var constants$1 = {
1529 MAX_LENGTH: 1024 * 64,
1530
1531 // Digits
1532 CHAR_0: '0', /* 0 */
1533 CHAR_9: '9', /* 9 */
1534
1535 // Alphabet chars.
1536 CHAR_UPPERCASE_A: 'A', /* A */
1537 CHAR_LOWERCASE_A: 'a', /* a */
1538 CHAR_UPPERCASE_Z: 'Z', /* Z */
1539 CHAR_LOWERCASE_Z: 'z', /* z */
1540
1541 CHAR_LEFT_PARENTHESES: '(', /* ( */
1542 CHAR_RIGHT_PARENTHESES: ')', /* ) */
1543
1544 CHAR_ASTERISK: '*', /* * */
1545
1546 // Non-alphabetic chars.
1547 CHAR_AMPERSAND: '&', /* & */
1548 CHAR_AT: '@', /* @ */
1549 CHAR_BACKSLASH: '\\', /* \ */
1550 CHAR_BACKTICK: '`', /* ` */
1551 CHAR_CARRIAGE_RETURN: '\r', /* \r */
1552 CHAR_CIRCUMFLEX_ACCENT: '^', /* ^ */
1553 CHAR_COLON: ':', /* : */
1554 CHAR_COMMA: ',', /* , */
1555 CHAR_DOLLAR: '$', /* . */
1556 CHAR_DOT: '.', /* . */
1557 CHAR_DOUBLE_QUOTE: '"', /* " */
1558 CHAR_EQUAL: '=', /* = */
1559 CHAR_EXCLAMATION_MARK: '!', /* ! */
1560 CHAR_FORM_FEED: '\f', /* \f */
1561 CHAR_FORWARD_SLASH: '/', /* / */
1562 CHAR_HASH: '#', /* # */
1563 CHAR_HYPHEN_MINUS: '-', /* - */
1564 CHAR_LEFT_ANGLE_BRACKET: '<', /* < */
1565 CHAR_LEFT_CURLY_BRACE: '{', /* { */
1566 CHAR_LEFT_SQUARE_BRACKET: '[', /* [ */
1567 CHAR_LINE_FEED: '\n', /* \n */
1568 CHAR_NO_BREAK_SPACE: '\u00A0', /* \u00A0 */
1569 CHAR_PERCENT: '%', /* % */
1570 CHAR_PLUS: '+', /* + */
1571 CHAR_QUESTION_MARK: '?', /* ? */
1572 CHAR_RIGHT_ANGLE_BRACKET: '>', /* > */
1573 CHAR_RIGHT_CURLY_BRACE: '}', /* } */
1574 CHAR_RIGHT_SQUARE_BRACKET: ']', /* ] */
1575 CHAR_SEMICOLON: ';', /* ; */
1576 CHAR_SINGLE_QUOTE: '\'', /* ' */
1577 CHAR_SPACE: ' ', /* */
1578 CHAR_TAB: '\t', /* \t */
1579 CHAR_UNDERSCORE: '_', /* _ */
1580 CHAR_VERTICAL_LINE: '|', /* | */
1581 CHAR_ZERO_WIDTH_NOBREAK_SPACE: '\uFEFF' /* \uFEFF */
1582};
1583
1584const stringify$1 = stringify$4;
1585
1586/**
1587 * Constants
1588 */
1589
1590const {
1591 MAX_LENGTH,
1592 CHAR_BACKSLASH, /* \ */
1593 CHAR_BACKTICK, /* ` */
1594 CHAR_COMMA, /* , */
1595 CHAR_DOT, /* . */
1596 CHAR_LEFT_PARENTHESES, /* ( */
1597 CHAR_RIGHT_PARENTHESES, /* ) */
1598 CHAR_LEFT_CURLY_BRACE, /* { */
1599 CHAR_RIGHT_CURLY_BRACE, /* } */
1600 CHAR_LEFT_SQUARE_BRACKET, /* [ */
1601 CHAR_RIGHT_SQUARE_BRACKET, /* ] */
1602 CHAR_DOUBLE_QUOTE, /* " */
1603 CHAR_SINGLE_QUOTE, /* ' */
1604 CHAR_NO_BREAK_SPACE,
1605 CHAR_ZERO_WIDTH_NOBREAK_SPACE
1606} = constants$1;
1607
1608/**
1609 * parse
1610 */
1611
1612const parse$1 = (input, options = {}) => {
1613 if (typeof input !== 'string') {
1614 throw new TypeError('Expected a string');
1615 }
1616
1617 let opts = options || {};
1618 let max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
1619 if (input.length > max) {
1620 throw new SyntaxError(`Input length (${input.length}), exceeds max characters (${max})`);
1621 }
1622
1623 let ast = { type: 'root', input, nodes: [] };
1624 let stack = [ast];
1625 let block = ast;
1626 let prev = ast;
1627 let brackets = 0;
1628 let length = input.length;
1629 let index = 0;
1630 let depth = 0;
1631 let value;
1632
1633 /**
1634 * Helpers
1635 */
1636
1637 const advance = () => input[index++];
1638 const push = node => {
1639 if (node.type === 'text' && prev.type === 'dot') {
1640 prev.type = 'text';
1641 }
1642
1643 if (prev && prev.type === 'text' && node.type === 'text') {
1644 prev.value += node.value;
1645 return;
1646 }
1647
1648 block.nodes.push(node);
1649 node.parent = block;
1650 node.prev = prev;
1651 prev = node;
1652 return node;
1653 };
1654
1655 push({ type: 'bos' });
1656
1657 while (index < length) {
1658 block = stack[stack.length - 1];
1659 value = advance();
1660
1661 /**
1662 * Invalid chars
1663 */
1664
1665 if (value === CHAR_ZERO_WIDTH_NOBREAK_SPACE || value === CHAR_NO_BREAK_SPACE) {
1666 continue;
1667 }
1668
1669 /**
1670 * Escaped chars
1671 */
1672
1673 if (value === CHAR_BACKSLASH) {
1674 push({ type: 'text', value: (options.keepEscaping ? value : '') + advance() });
1675 continue;
1676 }
1677
1678 /**
1679 * Right square bracket (literal): ']'
1680 */
1681
1682 if (value === CHAR_RIGHT_SQUARE_BRACKET) {
1683 push({ type: 'text', value: '\\' + value });
1684 continue;
1685 }
1686
1687 /**
1688 * Left square bracket: '['
1689 */
1690
1691 if (value === CHAR_LEFT_SQUARE_BRACKET) {
1692 brackets++;
1693 let next;
1694
1695 while (index < length && (next = advance())) {
1696 value += next;
1697
1698 if (next === CHAR_LEFT_SQUARE_BRACKET) {
1699 brackets++;
1700 continue;
1701 }
1702
1703 if (next === CHAR_BACKSLASH) {
1704 value += advance();
1705 continue;
1706 }
1707
1708 if (next === CHAR_RIGHT_SQUARE_BRACKET) {
1709 brackets--;
1710
1711 if (brackets === 0) {
1712 break;
1713 }
1714 }
1715 }
1716
1717 push({ type: 'text', value });
1718 continue;
1719 }
1720
1721 /**
1722 * Parentheses
1723 */
1724
1725 if (value === CHAR_LEFT_PARENTHESES) {
1726 block = push({ type: 'paren', nodes: [] });
1727 stack.push(block);
1728 push({ type: 'text', value });
1729 continue;
1730 }
1731
1732 if (value === CHAR_RIGHT_PARENTHESES) {
1733 if (block.type !== 'paren') {
1734 push({ type: 'text', value });
1735 continue;
1736 }
1737 block = stack.pop();
1738 push({ type: 'text', value });
1739 block = stack[stack.length - 1];
1740 continue;
1741 }
1742
1743 /**
1744 * Quotes: '|"|`
1745 */
1746
1747 if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) {
1748 let open = value;
1749 let next;
1750
1751 if (options.keepQuotes !== true) {
1752 value = '';
1753 }
1754
1755 while (index < length && (next = advance())) {
1756 if (next === CHAR_BACKSLASH) {
1757 value += next + advance();
1758 continue;
1759 }
1760
1761 if (next === open) {
1762 if (options.keepQuotes === true) value += next;
1763 break;
1764 }
1765
1766 value += next;
1767 }
1768
1769 push({ type: 'text', value });
1770 continue;
1771 }
1772
1773 /**
1774 * Left curly brace: '{'
1775 */
1776
1777 if (value === CHAR_LEFT_CURLY_BRACE) {
1778 depth++;
1779
1780 let dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true;
1781 let brace = {
1782 type: 'brace',
1783 open: true,
1784 close: false,
1785 dollar,
1786 depth,
1787 commas: 0,
1788 ranges: 0,
1789 nodes: []
1790 };
1791
1792 block = push(brace);
1793 stack.push(block);
1794 push({ type: 'open', value });
1795 continue;
1796 }
1797
1798 /**
1799 * Right curly brace: '}'
1800 */
1801
1802 if (value === CHAR_RIGHT_CURLY_BRACE) {
1803 if (block.type !== 'brace') {
1804 push({ type: 'text', value });
1805 continue;
1806 }
1807
1808 let type = 'close';
1809 block = stack.pop();
1810 block.close = true;
1811
1812 push({ type, value });
1813 depth--;
1814
1815 block = stack[stack.length - 1];
1816 continue;
1817 }
1818
1819 /**
1820 * Comma: ','
1821 */
1822
1823 if (value === CHAR_COMMA && depth > 0) {
1824 if (block.ranges > 0) {
1825 block.ranges = 0;
1826 let open = block.nodes.shift();
1827 block.nodes = [open, { type: 'text', value: stringify$1(block) }];
1828 }
1829
1830 push({ type: 'comma', value });
1831 block.commas++;
1832 continue;
1833 }
1834
1835 /**
1836 * Dot: '.'
1837 */
1838
1839 if (value === CHAR_DOT && depth > 0 && block.commas === 0) {
1840 let siblings = block.nodes;
1841
1842 if (depth === 0 || siblings.length === 0) {
1843 push({ type: 'text', value });
1844 continue;
1845 }
1846
1847 if (prev.type === 'dot') {
1848 block.range = [];
1849 prev.value += value;
1850 prev.type = 'range';
1851
1852 if (block.nodes.length !== 3 && block.nodes.length !== 5) {
1853 block.invalid = true;
1854 block.ranges = 0;
1855 prev.type = 'text';
1856 continue;
1857 }
1858
1859 block.ranges++;
1860 block.args = [];
1861 continue;
1862 }
1863
1864 if (prev.type === 'range') {
1865 siblings.pop();
1866
1867 let before = siblings[siblings.length - 1];
1868 before.value += prev.value + value;
1869 prev = before;
1870 block.ranges--;
1871 continue;
1872 }
1873
1874 push({ type: 'dot', value });
1875 continue;
1876 }
1877
1878 /**
1879 * Text
1880 */
1881
1882 push({ type: 'text', value });
1883 }
1884
1885 // Mark imbalanced braces and brackets as invalid
1886 do {
1887 block = stack.pop();
1888
1889 if (block.type !== 'root') {
1890 block.nodes.forEach(node => {
1891 if (!node.nodes) {
1892 if (node.type === 'open') node.isOpen = true;
1893 if (node.type === 'close') node.isClose = true;
1894 if (!node.nodes) node.type = 'text';
1895 node.invalid = true;
1896 }
1897 });
1898
1899 // get the location of the block on parent.nodes (block's siblings)
1900 let parent = stack[stack.length - 1];
1901 let index = parent.nodes.indexOf(block);
1902 // replace the (invalid) block with it's nodes
1903 parent.nodes.splice(index, 1, ...block.nodes);
1904 }
1905 } while (stack.length > 0);
1906
1907 push({ type: 'eos' });
1908 return ast;
1909};
1910
1911var parse_1 = parse$1;
1912
1913const stringify = stringify$4;
1914const compile = compile_1;
1915const expand = expand_1;
1916const parse = parse_1;
1917
1918/**
1919 * Expand the given pattern or create a regex-compatible string.
1920 *
1921 * ```js
1922 * const braces = require('braces');
1923 * console.log(braces('{a,b,c}', { compile: true })); //=> ['(a|b|c)']
1924 * console.log(braces('{a,b,c}')); //=> ['a', 'b', 'c']
1925 * ```
1926 * @param {String} `str`
1927 * @param {Object} `options`
1928 * @return {String}
1929 * @api public
1930 */
1931
1932const braces$1 = (input, options = {}) => {
1933 let output = [];
1934
1935 if (Array.isArray(input)) {
1936 for (let pattern of input) {
1937 let result = braces$1.create(pattern, options);
1938 if (Array.isArray(result)) {
1939 output.push(...result);
1940 } else {
1941 output.push(result);
1942 }
1943 }
1944 } else {
1945 output = [].concat(braces$1.create(input, options));
1946 }
1947
1948 if (options && options.expand === true && options.nodupes === true) {
1949 output = [...new Set(output)];
1950 }
1951 return output;
1952};
1953
1954/**
1955 * Parse the given `str` with the given `options`.
1956 *
1957 * ```js
1958 * // braces.parse(pattern, [, options]);
1959 * const ast = braces.parse('a/{b,c}/d');
1960 * console.log(ast);
1961 * ```
1962 * @param {String} pattern Brace pattern to parse
1963 * @param {Object} options
1964 * @return {Object} Returns an AST
1965 * @api public
1966 */
1967
1968braces$1.parse = (input, options = {}) => parse(input, options);
1969
1970/**
1971 * Creates a braces string from an AST, or an AST node.
1972 *
1973 * ```js
1974 * const braces = require('braces');
1975 * let ast = braces.parse('foo/{a,b}/bar');
1976 * console.log(stringify(ast.nodes[2])); //=> '{a,b}'
1977 * ```
1978 * @param {String} `input` Brace pattern or AST.
1979 * @param {Object} `options`
1980 * @return {Array} Returns an array of expanded values.
1981 * @api public
1982 */
1983
1984braces$1.stringify = (input, options = {}) => {
1985 if (typeof input === 'string') {
1986 return stringify(braces$1.parse(input, options), options);
1987 }
1988 return stringify(input, options);
1989};
1990
1991/**
1992 * Compiles a brace pattern into a regex-compatible, optimized string.
1993 * This method is called by the main [braces](#braces) function by default.
1994 *
1995 * ```js
1996 * const braces = require('braces');
1997 * console.log(braces.compile('a/{b,c}/d'));
1998 * //=> ['a/(b|c)/d']
1999 * ```
2000 * @param {String} `input` Brace pattern or AST.
2001 * @param {Object} `options`
2002 * @return {Array} Returns an array of expanded values.
2003 * @api public
2004 */
2005
2006braces$1.compile = (input, options = {}) => {
2007 if (typeof input === 'string') {
2008 input = braces$1.parse(input, options);
2009 }
2010 return compile(input, options);
2011};
2012
2013/**
2014 * Expands a brace pattern into an array. This method is called by the
2015 * main [braces](#braces) function when `options.expand` is true. Before
2016 * using this method it's recommended that you read the [performance notes](#performance))
2017 * and advantages of using [.compile](#compile) instead.
2018 *
2019 * ```js
2020 * const braces = require('braces');
2021 * console.log(braces.expand('a/{b,c}/d'));
2022 * //=> ['a/b/d', 'a/c/d'];
2023 * ```
2024 * @param {String} `pattern` Brace pattern
2025 * @param {Object} `options`
2026 * @return {Array} Returns an array of expanded values.
2027 * @api public
2028 */
2029
2030braces$1.expand = (input, options = {}) => {
2031 if (typeof input === 'string') {
2032 input = braces$1.parse(input, options);
2033 }
2034
2035 let result = expand(input, options);
2036
2037 // filter out empty strings if specified
2038 if (options.noempty === true) {
2039 result = result.filter(Boolean);
2040 }
2041
2042 // filter out duplicates if specified
2043 if (options.nodupes === true) {
2044 result = [...new Set(result)];
2045 }
2046
2047 return result;
2048};
2049
2050/**
2051 * Processes a brace pattern and returns either an expanded array
2052 * (if `options.expand` is true), a highly optimized regex-compatible string.
2053 * This method is called by the main [braces](#braces) function.
2054 *
2055 * ```js
2056 * const braces = require('braces');
2057 * console.log(braces.create('user-{200..300}/project-{a,b,c}-{1..10}'))
2058 * //=> 'user-(20[0-9]|2[1-9][0-9]|300)/project-(a|b|c)-([1-9]|10)'
2059 * ```
2060 * @param {String} `pattern` Brace pattern
2061 * @param {Object} `options`
2062 * @return {Array} Returns an array of expanded values.
2063 * @api public
2064 */
2065
2066braces$1.create = (input, options = {}) => {
2067 if (input === '' || input.length < 3) {
2068 return [input];
2069 }
2070
2071 return options.expand !== true
2072 ? braces$1.compile(input, options)
2073 : braces$1.expand(input, options);
2074};
2075
2076/**
2077 * Expose "braces"
2078 */
2079
2080var braces_1 = braces$1;
2081
2082var binaryExtensions$1 = {exports: {}};
2083
2084const require$$0 = [
2085 "3dm",
2086 "3ds",
2087 "3g2",
2088 "3gp",
2089 "7z",
2090 "a",
2091 "aac",
2092 "adp",
2093 "ai",
2094 "aif",
2095 "aiff",
2096 "alz",
2097 "ape",
2098 "apk",
2099 "appimage",
2100 "ar",
2101 "arj",
2102 "asf",
2103 "au",
2104 "avi",
2105 "bak",
2106 "baml",
2107 "bh",
2108 "bin",
2109 "bk",
2110 "bmp",
2111 "btif",
2112 "bz2",
2113 "bzip2",
2114 "cab",
2115 "caf",
2116 "cgm",
2117 "class",
2118 "cmx",
2119 "cpio",
2120 "cr2",
2121 "cur",
2122 "dat",
2123 "dcm",
2124 "deb",
2125 "dex",
2126 "djvu",
2127 "dll",
2128 "dmg",
2129 "dng",
2130 "doc",
2131 "docm",
2132 "docx",
2133 "dot",
2134 "dotm",
2135 "dra",
2136 "DS_Store",
2137 "dsk",
2138 "dts",
2139 "dtshd",
2140 "dvb",
2141 "dwg",
2142 "dxf",
2143 "ecelp4800",
2144 "ecelp7470",
2145 "ecelp9600",
2146 "egg",
2147 "eol",
2148 "eot",
2149 "epub",
2150 "exe",
2151 "f4v",
2152 "fbs",
2153 "fh",
2154 "fla",
2155 "flac",
2156 "flatpak",
2157 "fli",
2158 "flv",
2159 "fpx",
2160 "fst",
2161 "fvt",
2162 "g3",
2163 "gh",
2164 "gif",
2165 "graffle",
2166 "gz",
2167 "gzip",
2168 "h261",
2169 "h263",
2170 "h264",
2171 "icns",
2172 "ico",
2173 "ief",
2174 "img",
2175 "ipa",
2176 "iso",
2177 "jar",
2178 "jpeg",
2179 "jpg",
2180 "jpgv",
2181 "jpm",
2182 "jxr",
2183 "key",
2184 "ktx",
2185 "lha",
2186 "lib",
2187 "lvp",
2188 "lz",
2189 "lzh",
2190 "lzma",
2191 "lzo",
2192 "m3u",
2193 "m4a",
2194 "m4v",
2195 "mar",
2196 "mdi",
2197 "mht",
2198 "mid",
2199 "midi",
2200 "mj2",
2201 "mka",
2202 "mkv",
2203 "mmr",
2204 "mng",
2205 "mobi",
2206 "mov",
2207 "movie",
2208 "mp3",
2209 "mp4",
2210 "mp4a",
2211 "mpeg",
2212 "mpg",
2213 "mpga",
2214 "mxu",
2215 "nef",
2216 "npx",
2217 "numbers",
2218 "nupkg",
2219 "o",
2220 "odp",
2221 "ods",
2222 "odt",
2223 "oga",
2224 "ogg",
2225 "ogv",
2226 "otf",
2227 "ott",
2228 "pages",
2229 "pbm",
2230 "pcx",
2231 "pdb",
2232 "pdf",
2233 "pea",
2234 "pgm",
2235 "pic",
2236 "png",
2237 "pnm",
2238 "pot",
2239 "potm",
2240 "potx",
2241 "ppa",
2242 "ppam",
2243 "ppm",
2244 "pps",
2245 "ppsm",
2246 "ppsx",
2247 "ppt",
2248 "pptm",
2249 "pptx",
2250 "psd",
2251 "pya",
2252 "pyc",
2253 "pyo",
2254 "pyv",
2255 "qt",
2256 "rar",
2257 "ras",
2258 "raw",
2259 "resources",
2260 "rgb",
2261 "rip",
2262 "rlc",
2263 "rmf",
2264 "rmvb",
2265 "rpm",
2266 "rtf",
2267 "rz",
2268 "s3m",
2269 "s7z",
2270 "scpt",
2271 "sgi",
2272 "shar",
2273 "snap",
2274 "sil",
2275 "sketch",
2276 "slk",
2277 "smv",
2278 "snk",
2279 "so",
2280 "stl",
2281 "suo",
2282 "sub",
2283 "swf",
2284 "tar",
2285 "tbz",
2286 "tbz2",
2287 "tga",
2288 "tgz",
2289 "thmx",
2290 "tif",
2291 "tiff",
2292 "tlz",
2293 "ttc",
2294 "ttf",
2295 "txz",
2296 "udf",
2297 "uvh",
2298 "uvi",
2299 "uvm",
2300 "uvp",
2301 "uvs",
2302 "uvu",
2303 "viv",
2304 "vob",
2305 "war",
2306 "wav",
2307 "wax",
2308 "wbmp",
2309 "wdp",
2310 "weba",
2311 "webm",
2312 "webp",
2313 "whl",
2314 "wim",
2315 "wm",
2316 "wma",
2317 "wmv",
2318 "wmx",
2319 "woff",
2320 "woff2",
2321 "wrm",
2322 "wvx",
2323 "xbm",
2324 "xif",
2325 "xla",
2326 "xlam",
2327 "xls",
2328 "xlsb",
2329 "xlsm",
2330 "xlsx",
2331 "xlt",
2332 "xltm",
2333 "xltx",
2334 "xm",
2335 "xmind",
2336 "xpi",
2337 "xpm",
2338 "xwd",
2339 "xz",
2340 "z",
2341 "zip",
2342 "zipx"
2343];
2344
2345(function (module) {
2346 module.exports = require$$0;
2347} (binaryExtensions$1));
2348
2349const path = require$$0$2;
2350const binaryExtensions = binaryExtensions$1.exports;
2351
2352const extensions = new Set(binaryExtensions);
2353
2354var isBinaryPath$1 = filePath => extensions.has(path.extname(filePath).slice(1).toLowerCase());
2355
2356var constants = {};
2357
2358(function (exports) {
2359
2360 const {sep} = require$$0$2;
2361 const {platform} = process;
2362 const os = require$$2$1;
2363
2364 exports.EV_ALL = 'all';
2365 exports.EV_READY = 'ready';
2366 exports.EV_ADD = 'add';
2367 exports.EV_CHANGE = 'change';
2368 exports.EV_ADD_DIR = 'addDir';
2369 exports.EV_UNLINK = 'unlink';
2370 exports.EV_UNLINK_DIR = 'unlinkDir';
2371 exports.EV_RAW = 'raw';
2372 exports.EV_ERROR = 'error';
2373
2374 exports.STR_DATA = 'data';
2375 exports.STR_END = 'end';
2376 exports.STR_CLOSE = 'close';
2377
2378 exports.FSEVENT_CREATED = 'created';
2379 exports.FSEVENT_MODIFIED = 'modified';
2380 exports.FSEVENT_DELETED = 'deleted';
2381 exports.FSEVENT_MOVED = 'moved';
2382 exports.FSEVENT_CLONED = 'cloned';
2383 exports.FSEVENT_UNKNOWN = 'unknown';
2384 exports.FSEVENT_TYPE_FILE = 'file';
2385 exports.FSEVENT_TYPE_DIRECTORY = 'directory';
2386 exports.FSEVENT_TYPE_SYMLINK = 'symlink';
2387
2388 exports.KEY_LISTENERS = 'listeners';
2389 exports.KEY_ERR = 'errHandlers';
2390 exports.KEY_RAW = 'rawEmitters';
2391 exports.HANDLER_KEYS = [exports.KEY_LISTENERS, exports.KEY_ERR, exports.KEY_RAW];
2392
2393 exports.DOT_SLASH = `.${sep}`;
2394
2395 exports.BACK_SLASH_RE = /\\/g;
2396 exports.DOUBLE_SLASH_RE = /\/\//;
2397 exports.SLASH_OR_BACK_SLASH_RE = /[/\\]/;
2398 exports.DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;
2399 exports.REPLACER_RE = /^\.[/\\]/;
2400
2401 exports.SLASH = '/';
2402 exports.SLASH_SLASH = '//';
2403 exports.BRACE_START = '{';
2404 exports.BANG = '!';
2405 exports.ONE_DOT = '.';
2406 exports.TWO_DOTS = '..';
2407 exports.STAR = '*';
2408 exports.GLOBSTAR = '**';
2409 exports.ROOT_GLOBSTAR = '/**/*';
2410 exports.SLASH_GLOBSTAR = '/**';
2411 exports.DIR_SUFFIX = 'Dir';
2412 exports.ANYMATCH_OPTS = {dot: true};
2413 exports.STRING_TYPE = 'string';
2414 exports.FUNCTION_TYPE = 'function';
2415 exports.EMPTY_STR = '';
2416 exports.EMPTY_FN = () => {};
2417 exports.IDENTITY_FN = val => val;
2418
2419 exports.isWindows = platform === 'win32';
2420 exports.isMacos = platform === 'darwin';
2421 exports.isLinux = platform === 'linux';
2422 exports.isIBMi = os.type() === 'OS400';
2423} (constants));
2424
2425const fs$2 = require$$0$1;
2426const sysPath$2 = require$$0$2;
2427const { promisify: promisify$2 } = require$$2;
2428const isBinaryPath = isBinaryPath$1;
2429const {
2430 isWindows: isWindows$1,
2431 isLinux,
2432 EMPTY_FN: EMPTY_FN$2,
2433 EMPTY_STR: EMPTY_STR$1,
2434 KEY_LISTENERS,
2435 KEY_ERR,
2436 KEY_RAW,
2437 HANDLER_KEYS,
2438 EV_CHANGE: EV_CHANGE$2,
2439 EV_ADD: EV_ADD$2,
2440 EV_ADD_DIR: EV_ADD_DIR$2,
2441 EV_ERROR: EV_ERROR$2,
2442 STR_DATA: STR_DATA$1,
2443 STR_END: STR_END$2,
2444 BRACE_START: BRACE_START$1,
2445 STAR
2446} = constants;
2447
2448const THROTTLE_MODE_WATCH = 'watch';
2449
2450const open = promisify$2(fs$2.open);
2451const stat$2 = promisify$2(fs$2.stat);
2452const lstat$1 = promisify$2(fs$2.lstat);
2453const close = promisify$2(fs$2.close);
2454const fsrealpath = promisify$2(fs$2.realpath);
2455
2456const statMethods$1 = { lstat: lstat$1, stat: stat$2 };
2457
2458// TODO: emit errors properly. Example: EMFILE on Macos.
2459const foreach = (val, fn) => {
2460 if (val instanceof Set) {
2461 val.forEach(fn);
2462 } else {
2463 fn(val);
2464 }
2465};
2466
2467const addAndConvert = (main, prop, item) => {
2468 let container = main[prop];
2469 if (!(container instanceof Set)) {
2470 main[prop] = container = new Set([container]);
2471 }
2472 container.add(item);
2473};
2474
2475const clearItem = cont => key => {
2476 const set = cont[key];
2477 if (set instanceof Set) {
2478 set.clear();
2479 } else {
2480 delete cont[key];
2481 }
2482};
2483
2484const delFromSet = (main, prop, item) => {
2485 const container = main[prop];
2486 if (container instanceof Set) {
2487 container.delete(item);
2488 } else if (container === item) {
2489 delete main[prop];
2490 }
2491};
2492
2493const isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
2494
2495/**
2496 * @typedef {String} Path
2497 */
2498
2499// fs_watch helpers
2500
2501// object to hold per-process fs_watch instances
2502// (may be shared across chokidar FSWatcher instances)
2503
2504/**
2505 * @typedef {Object} FsWatchContainer
2506 * @property {Set} listeners
2507 * @property {Set} errHandlers
2508 * @property {Set} rawEmitters
2509 * @property {fs.FSWatcher=} watcher
2510 * @property {Boolean=} watcherUnusable
2511 */
2512
2513/**
2514 * @type {Map<String,FsWatchContainer>}
2515 */
2516const FsWatchInstances = new Map();
2517
2518/**
2519 * Instantiates the fs_watch interface
2520 * @param {String} path to be watched
2521 * @param {Object} options to be passed to fs_watch
2522 * @param {Function} listener main event handler
2523 * @param {Function} errHandler emits info about errors
2524 * @param {Function} emitRaw emits raw event data
2525 * @returns {fs.FSWatcher} new fsevents instance
2526 */
2527function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
2528 const handleEvent = (rawEvent, evPath) => {
2529 listener(path);
2530 emitRaw(rawEvent, evPath, {watchedPath: path});
2531
2532 // emit based on events occurring for files from a directory's watcher in
2533 // case the file's watcher misses it (and rely on throttling to de-dupe)
2534 if (evPath && path !== evPath) {
2535 fsWatchBroadcast(
2536 sysPath$2.resolve(path, evPath), KEY_LISTENERS, sysPath$2.join(path, evPath)
2537 );
2538 }
2539 };
2540 try {
2541 return fs$2.watch(path, options, handleEvent);
2542 } catch (error) {
2543 errHandler(error);
2544 }
2545}
2546
2547/**
2548 * Helper for passing fs_watch event data to a collection of listeners
2549 * @param {Path} fullPath absolute path bound to fs_watch instance
2550 * @param {String} type listener type
2551 * @param {*=} val1 arguments to be passed to listeners
2552 * @param {*=} val2
2553 * @param {*=} val3
2554 */
2555const fsWatchBroadcast = (fullPath, type, val1, val2, val3) => {
2556 const cont = FsWatchInstances.get(fullPath);
2557 if (!cont) return;
2558 foreach(cont[type], (listener) => {
2559 listener(val1, val2, val3);
2560 });
2561};
2562
2563/**
2564 * Instantiates the fs_watch interface or binds listeners
2565 * to an existing one covering the same file system entry
2566 * @param {String} path
2567 * @param {String} fullPath absolute path
2568 * @param {Object} options to be passed to fs_watch
2569 * @param {Object} handlers container for event listener functions
2570 */
2571const setFsWatchListener = (path, fullPath, options, handlers) => {
2572 const {listener, errHandler, rawEmitter} = handlers;
2573 let cont = FsWatchInstances.get(fullPath);
2574
2575 /** @type {fs.FSWatcher=} */
2576 let watcher;
2577 if (!options.persistent) {
2578 watcher = createFsWatchInstance(
2579 path, options, listener, errHandler, rawEmitter
2580 );
2581 return watcher.close.bind(watcher);
2582 }
2583 if (cont) {
2584 addAndConvert(cont, KEY_LISTENERS, listener);
2585 addAndConvert(cont, KEY_ERR, errHandler);
2586 addAndConvert(cont, KEY_RAW, rawEmitter);
2587 } else {
2588 watcher = createFsWatchInstance(
2589 path,
2590 options,
2591 fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
2592 errHandler, // no need to use broadcast here
2593 fsWatchBroadcast.bind(null, fullPath, KEY_RAW)
2594 );
2595 if (!watcher) return;
2596 watcher.on(EV_ERROR$2, async (error) => {
2597 const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR);
2598 cont.watcherUnusable = true; // documented since Node 10.4.1
2599 // Workaround for https://github.com/joyent/node/issues/4337
2600 if (isWindows$1 && error.code === 'EPERM') {
2601 try {
2602 const fd = await open(path, 'r');
2603 await close(fd);
2604 broadcastErr(error);
2605 } catch (err) {}
2606 } else {
2607 broadcastErr(error);
2608 }
2609 });
2610 cont = {
2611 listeners: listener,
2612 errHandlers: errHandler,
2613 rawEmitters: rawEmitter,
2614 watcher
2615 };
2616 FsWatchInstances.set(fullPath, cont);
2617 }
2618 // const index = cont.listeners.indexOf(listener);
2619
2620 // removes this instance's listeners and closes the underlying fs_watch
2621 // instance if there are no more listeners left
2622 return () => {
2623 delFromSet(cont, KEY_LISTENERS, listener);
2624 delFromSet(cont, KEY_ERR, errHandler);
2625 delFromSet(cont, KEY_RAW, rawEmitter);
2626 if (isEmptySet(cont.listeners)) {
2627 // Check to protect against issue gh-730.
2628 // if (cont.watcherUnusable) {
2629 cont.watcher.close();
2630 // }
2631 FsWatchInstances.delete(fullPath);
2632 HANDLER_KEYS.forEach(clearItem(cont));
2633 cont.watcher = undefined;
2634 Object.freeze(cont);
2635 }
2636 };
2637};
2638
2639// fs_watchFile helpers
2640
2641// object to hold per-process fs_watchFile instances
2642// (may be shared across chokidar FSWatcher instances)
2643const FsWatchFileInstances = new Map();
2644
2645/**
2646 * Instantiates the fs_watchFile interface or binds listeners
2647 * to an existing one covering the same file system entry
2648 * @param {String} path to be watched
2649 * @param {String} fullPath absolute path
2650 * @param {Object} options options to be passed to fs_watchFile
2651 * @param {Object} handlers container for event listener functions
2652 * @returns {Function} closer
2653 */
2654const setFsWatchFileListener = (path, fullPath, options, handlers) => {
2655 const {listener, rawEmitter} = handlers;
2656 let cont = FsWatchFileInstances.get(fullPath);
2657
2658 const copts = cont && cont.options;
2659 if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
2660 fs$2.unwatchFile(fullPath);
2661 cont = undefined;
2662 }
2663
2664 /* eslint-enable no-unused-vars, prefer-destructuring */
2665
2666 if (cont) {
2667 addAndConvert(cont, KEY_LISTENERS, listener);
2668 addAndConvert(cont, KEY_RAW, rawEmitter);
2669 } else {
2670 // TODO
2671 // listeners.add(listener);
2672 // rawEmitters.add(rawEmitter);
2673 cont = {
2674 listeners: listener,
2675 rawEmitters: rawEmitter,
2676 options,
2677 watcher: fs$2.watchFile(fullPath, options, (curr, prev) => {
2678 foreach(cont.rawEmitters, (rawEmitter) => {
2679 rawEmitter(EV_CHANGE$2, fullPath, {curr, prev});
2680 });
2681 const currmtime = curr.mtimeMs;
2682 if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
2683 foreach(cont.listeners, (listener) => listener(path, curr));
2684 }
2685 })
2686 };
2687 FsWatchFileInstances.set(fullPath, cont);
2688 }
2689 // const index = cont.listeners.indexOf(listener);
2690
2691 // Removes this instance's listeners and closes the underlying fs_watchFile
2692 // instance if there are no more listeners left.
2693 return () => {
2694 delFromSet(cont, KEY_LISTENERS, listener);
2695 delFromSet(cont, KEY_RAW, rawEmitter);
2696 if (isEmptySet(cont.listeners)) {
2697 FsWatchFileInstances.delete(fullPath);
2698 fs$2.unwatchFile(fullPath);
2699 cont.options = cont.watcher = undefined;
2700 Object.freeze(cont);
2701 }
2702 };
2703};
2704
2705/**
2706 * @mixin
2707 */
2708class NodeFsHandler$1 {
2709
2710/**
2711 * @param {import("../index").FSWatcher} fsW
2712 */
2713constructor(fsW) {
2714 this.fsw = fsW;
2715 this._boundHandleError = (error) => fsW._handleError(error);
2716}
2717
2718/**
2719 * Watch file for changes with fs_watchFile or fs_watch.
2720 * @param {String} path to file or dir
2721 * @param {Function} listener on fs change
2722 * @returns {Function} closer for the watcher instance
2723 */
2724_watchWithNodeFs(path, listener) {
2725 const opts = this.fsw.options;
2726 const directory = sysPath$2.dirname(path);
2727 const basename = sysPath$2.basename(path);
2728 const parent = this.fsw._getWatchedDir(directory);
2729 parent.add(basename);
2730 const absolutePath = sysPath$2.resolve(path);
2731 const options = {persistent: opts.persistent};
2732 if (!listener) listener = EMPTY_FN$2;
2733
2734 let closer;
2735 if (opts.usePolling) {
2736 options.interval = opts.enableBinaryInterval && isBinaryPath(basename) ?
2737 opts.binaryInterval : opts.interval;
2738 closer = setFsWatchFileListener(path, absolutePath, options, {
2739 listener,
2740 rawEmitter: this.fsw._emitRaw
2741 });
2742 } else {
2743 closer = setFsWatchListener(path, absolutePath, options, {
2744 listener,
2745 errHandler: this._boundHandleError,
2746 rawEmitter: this.fsw._emitRaw
2747 });
2748 }
2749 return closer;
2750}
2751
2752/**
2753 * Watch a file and emit add event if warranted.
2754 * @param {Path} file Path
2755 * @param {fs.Stats} stats result of fs_stat
2756 * @param {Boolean} initialAdd was the file added at watch instantiation?
2757 * @returns {Function} closer for the watcher instance
2758 */
2759_handleFile(file, stats, initialAdd) {
2760 if (this.fsw.closed) {
2761 return;
2762 }
2763 const dirname = sysPath$2.dirname(file);
2764 const basename = sysPath$2.basename(file);
2765 const parent = this.fsw._getWatchedDir(dirname);
2766 // stats is always present
2767 let prevStats = stats;
2768
2769 // if the file is already being watched, do nothing
2770 if (parent.has(basename)) return;
2771
2772 const listener = async (path, newStats) => {
2773 if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5)) return;
2774 if (!newStats || newStats.mtimeMs === 0) {
2775 try {
2776 const newStats = await stat$2(file);
2777 if (this.fsw.closed) return;
2778 // Check that change event was not fired because of changed only accessTime.
2779 const at = newStats.atimeMs;
2780 const mt = newStats.mtimeMs;
2781 if (!at || at <= mt || mt !== prevStats.mtimeMs) {
2782 this.fsw._emit(EV_CHANGE$2, file, newStats);
2783 }
2784 if (isLinux && prevStats.ino !== newStats.ino) {
2785 this.fsw._closeFile(path);
2786 prevStats = newStats;
2787 this.fsw._addPathCloser(path, this._watchWithNodeFs(file, listener));
2788 } else {
2789 prevStats = newStats;
2790 }
2791 } catch (error) {
2792 // Fix issues where mtime is null but file is still present
2793 this.fsw._remove(dirname, basename);
2794 }
2795 // add is about to be emitted if file not already tracked in parent
2796 } else if (parent.has(basename)) {
2797 // Check that change event was not fired because of changed only accessTime.
2798 const at = newStats.atimeMs;
2799 const mt = newStats.mtimeMs;
2800 if (!at || at <= mt || mt !== prevStats.mtimeMs) {
2801 this.fsw._emit(EV_CHANGE$2, file, newStats);
2802 }
2803 prevStats = newStats;
2804 }
2805 };
2806 // kick off the watcher
2807 const closer = this._watchWithNodeFs(file, listener);
2808
2809 // emit an add event if we're supposed to
2810 if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) {
2811 if (!this.fsw._throttle(EV_ADD$2, file, 0)) return;
2812 this.fsw._emit(EV_ADD$2, file, stats);
2813 }
2814
2815 return closer;
2816}
2817
2818/**
2819 * Handle symlinks encountered while reading a dir.
2820 * @param {Object} entry returned by readdirp
2821 * @param {String} directory path of dir being read
2822 * @param {String} path of this item
2823 * @param {String} item basename of this item
2824 * @returns {Promise<Boolean>} true if no more processing is needed for this entry.
2825 */
2826async _handleSymlink(entry, directory, path, item) {
2827 if (this.fsw.closed) {
2828 return;
2829 }
2830 const full = entry.fullPath;
2831 const dir = this.fsw._getWatchedDir(directory);
2832
2833 if (!this.fsw.options.followSymlinks) {
2834 // watch symlink directly (don't follow) and detect changes
2835 this.fsw._incrReadyCount();
2836
2837 let linkPath;
2838 try {
2839 linkPath = await fsrealpath(path);
2840 } catch (e) {
2841 this.fsw._emitReady();
2842 return true;
2843 }
2844
2845 if (this.fsw.closed) return;
2846 if (dir.has(item)) {
2847 if (this.fsw._symlinkPaths.get(full) !== linkPath) {
2848 this.fsw._symlinkPaths.set(full, linkPath);
2849 this.fsw._emit(EV_CHANGE$2, path, entry.stats);
2850 }
2851 } else {
2852 dir.add(item);
2853 this.fsw._symlinkPaths.set(full, linkPath);
2854 this.fsw._emit(EV_ADD$2, path, entry.stats);
2855 }
2856 this.fsw._emitReady();
2857 return true;
2858 }
2859
2860 // don't follow the same symlink more than once
2861 if (this.fsw._symlinkPaths.has(full)) {
2862 return true;
2863 }
2864
2865 this.fsw._symlinkPaths.set(full, true);
2866}
2867
2868_handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {
2869 // Normalize the directory name on Windows
2870 directory = sysPath$2.join(directory, EMPTY_STR$1);
2871
2872 if (!wh.hasGlob) {
2873 throttler = this.fsw._throttle('readdir', directory, 1000);
2874 if (!throttler) return;
2875 }
2876
2877 const previous = this.fsw._getWatchedDir(wh.path);
2878 const current = new Set();
2879
2880 let stream = this.fsw._readdirp(directory, {
2881 fileFilter: entry => wh.filterPath(entry),
2882 directoryFilter: entry => wh.filterDir(entry),
2883 depth: 0
2884 }).on(STR_DATA$1, async (entry) => {
2885 if (this.fsw.closed) {
2886 stream = undefined;
2887 return;
2888 }
2889 const item = entry.path;
2890 let path = sysPath$2.join(directory, item);
2891 current.add(item);
2892
2893 if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path, item)) {
2894 return;
2895 }
2896
2897 if (this.fsw.closed) {
2898 stream = undefined;
2899 return;
2900 }
2901 // Files that present in current directory snapshot
2902 // but absent in previous are added to watch list and
2903 // emit `add` event.
2904 if (item === target || !target && !previous.has(item)) {
2905 this.fsw._incrReadyCount();
2906
2907 // ensure relativeness of path is preserved in case of watcher reuse
2908 path = sysPath$2.join(dir, sysPath$2.relative(dir, path));
2909
2910 this._addToNodeFs(path, initialAdd, wh, depth + 1);
2911 }
2912 }).on(EV_ERROR$2, this._boundHandleError);
2913
2914 return new Promise(resolve =>
2915 stream.once(STR_END$2, () => {
2916 if (this.fsw.closed) {
2917 stream = undefined;
2918 return;
2919 }
2920 const wasThrottled = throttler ? throttler.clear() : false;
2921
2922 resolve();
2923
2924 // Files that absent in current directory snapshot
2925 // but present in previous emit `remove` event
2926 // and are removed from @watched[directory].
2927 previous.getChildren().filter((item) => {
2928 return item !== directory &&
2929 !current.has(item) &&
2930 // in case of intersecting globs;
2931 // a path may have been filtered out of this readdir, but
2932 // shouldn't be removed because it matches a different glob
2933 (!wh.hasGlob || wh.filterPath({
2934 fullPath: sysPath$2.resolve(directory, item)
2935 }));
2936 }).forEach((item) => {
2937 this.fsw._remove(directory, item);
2938 });
2939
2940 stream = undefined;
2941
2942 // one more time for any missed in case changes came in extremely quickly
2943 if (wasThrottled) this._handleRead(directory, false, wh, target, dir, depth, throttler);
2944 })
2945 );
2946}
2947
2948/**
2949 * Read directory to add / remove files from `@watched` list and re-read it on change.
2950 * @param {String} dir fs path
2951 * @param {fs.Stats} stats
2952 * @param {Boolean} initialAdd
2953 * @param {Number} depth relative to user-supplied path
2954 * @param {String} target child path targeted for watch
2955 * @param {Object} wh Common watch helpers for this path
2956 * @param {String} realpath
2957 * @returns {Promise<Function>} closer for the watcher instance.
2958 */
2959async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath) {
2960 const parentDir = this.fsw._getWatchedDir(sysPath$2.dirname(dir));
2961 const tracked = parentDir.has(sysPath$2.basename(dir));
2962 if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {
2963 if (!wh.hasGlob || wh.globFilter(dir)) this.fsw._emit(EV_ADD_DIR$2, dir, stats);
2964 }
2965
2966 // ensure dir is tracked (harmless if redundant)
2967 parentDir.add(sysPath$2.basename(dir));
2968 this.fsw._getWatchedDir(dir);
2969 let throttler;
2970 let closer;
2971
2972 const oDepth = this.fsw.options.depth;
2973 if ((oDepth == null || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath)) {
2974 if (!target) {
2975 await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler);
2976 if (this.fsw.closed) return;
2977 }
2978
2979 closer = this._watchWithNodeFs(dir, (dirPath, stats) => {
2980 // if current directory is removed, do nothing
2981 if (stats && stats.mtimeMs === 0) return;
2982
2983 this._handleRead(dirPath, false, wh, target, dir, depth, throttler);
2984 });
2985 }
2986 return closer;
2987}
2988
2989/**
2990 * Handle added file, directory, or glob pattern.
2991 * Delegates call to _handleFile / _handleDir after checks.
2992 * @param {String} path to file or ir
2993 * @param {Boolean} initialAdd was the file added at watch instantiation?
2994 * @param {Object} priorWh depth relative to user-supplied path
2995 * @param {Number} depth Child path actually targeted for watch
2996 * @param {String=} target Child path actually targeted for watch
2997 * @returns {Promise}
2998 */
2999async _addToNodeFs(path, initialAdd, priorWh, depth, target) {
3000 const ready = this.fsw._emitReady;
3001 if (this.fsw._isIgnored(path) || this.fsw.closed) {
3002 ready();
3003 return false;
3004 }
3005
3006 const wh = this.fsw._getWatchHelpers(path, depth);
3007 if (!wh.hasGlob && priorWh) {
3008 wh.hasGlob = priorWh.hasGlob;
3009 wh.globFilter = priorWh.globFilter;
3010 wh.filterPath = entry => priorWh.filterPath(entry);
3011 wh.filterDir = entry => priorWh.filterDir(entry);
3012 }
3013
3014 // evaluate what is at the path we're being asked to watch
3015 try {
3016 const stats = await statMethods$1[wh.statMethod](wh.watchPath);
3017 if (this.fsw.closed) return;
3018 if (this.fsw._isIgnored(wh.watchPath, stats)) {
3019 ready();
3020 return false;
3021 }
3022
3023 const follow = this.fsw.options.followSymlinks && !path.includes(STAR) && !path.includes(BRACE_START$1);
3024 let closer;
3025 if (stats.isDirectory()) {
3026 const absPath = sysPath$2.resolve(path);
3027 const targetPath = follow ? await fsrealpath(path) : path;
3028 if (this.fsw.closed) return;
3029 closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
3030 if (this.fsw.closed) return;
3031 // preserve this symlink's target path
3032 if (absPath !== targetPath && targetPath !== undefined) {
3033 this.fsw._symlinkPaths.set(absPath, targetPath);
3034 }
3035 } else if (stats.isSymbolicLink()) {
3036 const targetPath = follow ? await fsrealpath(path) : path;
3037 if (this.fsw.closed) return;
3038 const parent = sysPath$2.dirname(wh.watchPath);
3039 this.fsw._getWatchedDir(parent).add(wh.watchPath);
3040 this.fsw._emit(EV_ADD$2, wh.watchPath, stats);
3041 closer = await this._handleDir(parent, stats, initialAdd, depth, path, wh, targetPath);
3042 if (this.fsw.closed) return;
3043
3044 // preserve this symlink's target path
3045 if (targetPath !== undefined) {
3046 this.fsw._symlinkPaths.set(sysPath$2.resolve(path), targetPath);
3047 }
3048 } else {
3049 closer = this._handleFile(wh.watchPath, stats, initialAdd);
3050 }
3051 ready();
3052
3053 this.fsw._addPathCloser(path, closer);
3054 return false;
3055
3056 } catch (error) {
3057 if (this.fsw._handleError(error)) {
3058 ready();
3059 return path;
3060 }
3061 }
3062}
3063
3064}
3065
3066var nodefsHandler = NodeFsHandler$1;
3067
3068var fseventsHandler = {exports: {}};
3069
3070const require$$3 = /*@__PURE__*/rollup.getAugmentedNamespace(rollup.fseventsImporter);
3071
3072const fs$1 = require$$0$1;
3073const sysPath$1 = require$$0$2;
3074const { promisify: promisify$1 } = require$$2;
3075
3076let fsevents;
3077try {
3078 fsevents = require$$3.getFsEvents();
3079} catch (error) {
3080 if (process.env.CHOKIDAR_PRINT_FSEVENTS_REQUIRE_ERROR) console.error(error);
3081}
3082
3083if (fsevents) {
3084 // TODO: real check
3085 const mtch = process.version.match(/v(\d+)\.(\d+)/);
3086 if (mtch && mtch[1] && mtch[2]) {
3087 const maj = Number.parseInt(mtch[1], 10);
3088 const min = Number.parseInt(mtch[2], 10);
3089 if (maj === 8 && min < 16) {
3090 fsevents = undefined;
3091 }
3092 }
3093}
3094
3095const {
3096 EV_ADD: EV_ADD$1,
3097 EV_CHANGE: EV_CHANGE$1,
3098 EV_ADD_DIR: EV_ADD_DIR$1,
3099 EV_UNLINK: EV_UNLINK$1,
3100 EV_ERROR: EV_ERROR$1,
3101 STR_DATA,
3102 STR_END: STR_END$1,
3103 FSEVENT_CREATED,
3104 FSEVENT_MODIFIED,
3105 FSEVENT_DELETED,
3106 FSEVENT_MOVED,
3107 // FSEVENT_CLONED,
3108 FSEVENT_UNKNOWN,
3109 FSEVENT_TYPE_FILE,
3110 FSEVENT_TYPE_DIRECTORY,
3111 FSEVENT_TYPE_SYMLINK,
3112
3113 ROOT_GLOBSTAR,
3114 DIR_SUFFIX,
3115 DOT_SLASH,
3116 FUNCTION_TYPE: FUNCTION_TYPE$1,
3117 EMPTY_FN: EMPTY_FN$1,
3118 IDENTITY_FN
3119} = constants;
3120
3121const Depth = (value) => isNaN(value) ? {} : {depth: value};
3122
3123const stat$1 = promisify$1(fs$1.stat);
3124const lstat = promisify$1(fs$1.lstat);
3125const realpath = promisify$1(fs$1.realpath);
3126
3127const statMethods = { stat: stat$1, lstat };
3128
3129/**
3130 * @typedef {String} Path
3131 */
3132
3133/**
3134 * @typedef {Object} FsEventsWatchContainer
3135 * @property {Set<Function>} listeners
3136 * @property {Function} rawEmitter
3137 * @property {{stop: Function}} watcher
3138 */
3139
3140// fsevents instance helper functions
3141/**
3142 * Object to hold per-process fsevents instances (may be shared across chokidar FSWatcher instances)
3143 * @type {Map<Path,FsEventsWatchContainer>}
3144 */
3145const FSEventsWatchers = new Map();
3146
3147// Threshold of duplicate path prefixes at which to start
3148// consolidating going forward
3149const consolidateThreshhold = 10;
3150
3151const wrongEventFlags = new Set([
3152 69888, 70400, 71424, 72704, 73472, 131328, 131840, 262912
3153]);
3154
3155/**
3156 * Instantiates the fsevents interface
3157 * @param {Path} path path to be watched
3158 * @param {Function} callback called when fsevents is bound and ready
3159 * @returns {{stop: Function}} new fsevents instance
3160 */
3161const createFSEventsInstance = (path, callback) => {
3162 const stop = fsevents.watch(path, callback);
3163 return {stop};
3164};
3165
3166/**
3167 * Instantiates the fsevents interface or binds listeners to an existing one covering
3168 * the same file tree.
3169 * @param {Path} path - to be watched
3170 * @param {Path} realPath - real path for symlinks
3171 * @param {Function} listener - called when fsevents emits events
3172 * @param {Function} rawEmitter - passes data to listeners of the 'raw' event
3173 * @returns {Function} closer
3174 */
3175function setFSEventsListener(path, realPath, listener, rawEmitter) {
3176 let watchPath = sysPath$1.extname(realPath) ? sysPath$1.dirname(realPath) : realPath;
3177
3178 const parentPath = sysPath$1.dirname(watchPath);
3179 let cont = FSEventsWatchers.get(watchPath);
3180
3181 // If we've accumulated a substantial number of paths that
3182 // could have been consolidated by watching one directory
3183 // above the current one, create a watcher on the parent
3184 // path instead, so that we do consolidate going forward.
3185 if (couldConsolidate(parentPath)) {
3186 watchPath = parentPath;
3187 }
3188
3189 const resolvedPath = sysPath$1.resolve(path);
3190 const hasSymlink = resolvedPath !== realPath;
3191
3192 const filteredListener = (fullPath, flags, info) => {
3193 if (hasSymlink) fullPath = fullPath.replace(realPath, resolvedPath);
3194 if (
3195 fullPath === resolvedPath ||
3196 !fullPath.indexOf(resolvedPath + sysPath$1.sep)
3197 ) listener(fullPath, flags, info);
3198 };
3199
3200 // check if there is already a watcher on a parent path
3201 // modifies `watchPath` to the parent path when it finds a match
3202 let watchedParent = false;
3203 for (const watchedPath of FSEventsWatchers.keys()) {
3204 if (realPath.indexOf(sysPath$1.resolve(watchedPath) + sysPath$1.sep) === 0) {
3205 watchPath = watchedPath;
3206 cont = FSEventsWatchers.get(watchPath);
3207 watchedParent = true;
3208 break;
3209 }
3210 }
3211
3212 if (cont || watchedParent) {
3213 cont.listeners.add(filteredListener);
3214 } else {
3215 cont = {
3216 listeners: new Set([filteredListener]),
3217 rawEmitter,
3218 watcher: createFSEventsInstance(watchPath, (fullPath, flags) => {
3219 if (!cont.listeners.size) return;
3220 const info = fsevents.getInfo(fullPath, flags);
3221 cont.listeners.forEach(list => {
3222 list(fullPath, flags, info);
3223 });
3224
3225 cont.rawEmitter(info.event, fullPath, info);
3226 })
3227 };
3228 FSEventsWatchers.set(watchPath, cont);
3229 }
3230
3231 // removes this instance's listeners and closes the underlying fsevents
3232 // instance if there are no more listeners left
3233 return () => {
3234 const lst = cont.listeners;
3235
3236 lst.delete(filteredListener);
3237 if (!lst.size) {
3238 FSEventsWatchers.delete(watchPath);
3239 if (cont.watcher) return cont.watcher.stop().then(() => {
3240 cont.rawEmitter = cont.watcher = undefined;
3241 Object.freeze(cont);
3242 });
3243 }
3244 };
3245}
3246
3247// Decide whether or not we should start a new higher-level
3248// parent watcher
3249const couldConsolidate = (path) => {
3250 let count = 0;
3251 for (const watchPath of FSEventsWatchers.keys()) {
3252 if (watchPath.indexOf(path) === 0) {
3253 count++;
3254 if (count >= consolidateThreshhold) {
3255 return true;
3256 }
3257 }
3258 }
3259
3260 return false;
3261};
3262
3263// returns boolean indicating whether fsevents can be used
3264const canUse = () => fsevents && FSEventsWatchers.size < 128;
3265
3266// determines subdirectory traversal levels from root to path
3267const calcDepth = (path, root) => {
3268 let i = 0;
3269 while (!path.indexOf(root) && (path = sysPath$1.dirname(path)) !== root) i++;
3270 return i;
3271};
3272
3273// returns boolean indicating whether the fsevents' event info has the same type
3274// as the one returned by fs.stat
3275const sameTypes = (info, stats) => (
3276 info.type === FSEVENT_TYPE_DIRECTORY && stats.isDirectory() ||
3277 info.type === FSEVENT_TYPE_SYMLINK && stats.isSymbolicLink() ||
3278 info.type === FSEVENT_TYPE_FILE && stats.isFile()
3279);
3280
3281/**
3282 * @mixin
3283 */
3284class FsEventsHandler$1 {
3285
3286/**
3287 * @param {import('../index').FSWatcher} fsw
3288 */
3289constructor(fsw) {
3290 this.fsw = fsw;
3291}
3292checkIgnored(path, stats) {
3293 const ipaths = this.fsw._ignoredPaths;
3294 if (this.fsw._isIgnored(path, stats)) {
3295 ipaths.add(path);
3296 if (stats && stats.isDirectory()) {
3297 ipaths.add(path + ROOT_GLOBSTAR);
3298 }
3299 return true;
3300 }
3301
3302 ipaths.delete(path);
3303 ipaths.delete(path + ROOT_GLOBSTAR);
3304}
3305
3306addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts) {
3307 const event = watchedDir.has(item) ? EV_CHANGE$1 : EV_ADD$1;
3308 this.handleEvent(event, path, fullPath, realPath, parent, watchedDir, item, info, opts);
3309}
3310
3311async checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts) {
3312 try {
3313 const stats = await stat$1(path);
3314 if (this.fsw.closed) return;
3315 if (sameTypes(info, stats)) {
3316 this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts);
3317 } else {
3318 this.handleEvent(EV_UNLINK$1, path, fullPath, realPath, parent, watchedDir, item, info, opts);
3319 }
3320 } catch (error) {
3321 if (error.code === 'EACCES') {
3322 this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts);
3323 } else {
3324 this.handleEvent(EV_UNLINK$1, path, fullPath, realPath, parent, watchedDir, item, info, opts);
3325 }
3326 }
3327}
3328
3329handleEvent(event, path, fullPath, realPath, parent, watchedDir, item, info, opts) {
3330 if (this.fsw.closed || this.checkIgnored(path)) return;
3331
3332 if (event === EV_UNLINK$1) {
3333 const isDirectory = info.type === FSEVENT_TYPE_DIRECTORY;
3334 // suppress unlink events on never before seen files
3335 if (isDirectory || watchedDir.has(item)) {
3336 this.fsw._remove(parent, item, isDirectory);
3337 }
3338 } else {
3339 if (event === EV_ADD$1) {
3340 // track new directories
3341 if (info.type === FSEVENT_TYPE_DIRECTORY) this.fsw._getWatchedDir(path);
3342
3343 if (info.type === FSEVENT_TYPE_SYMLINK && opts.followSymlinks) {
3344 // push symlinks back to the top of the stack to get handled
3345 const curDepth = opts.depth === undefined ?
3346 undefined : calcDepth(fullPath, realPath) + 1;
3347 return this._addToFsEvents(path, false, true, curDepth);
3348 }
3349
3350 // track new paths
3351 // (other than symlinks being followed, which will be tracked soon)
3352 this.fsw._getWatchedDir(parent).add(item);
3353 }
3354 /**
3355 * @type {'add'|'addDir'|'unlink'|'unlinkDir'}
3356 */
3357 const eventName = info.type === FSEVENT_TYPE_DIRECTORY ? event + DIR_SUFFIX : event;
3358 this.fsw._emit(eventName, path);
3359 if (eventName === EV_ADD_DIR$1) this._addToFsEvents(path, false, true);
3360 }
3361}
3362
3363/**
3364 * Handle symlinks encountered during directory scan
3365 * @param {String} watchPath - file/dir path to be watched with fsevents
3366 * @param {String} realPath - real path (in case of symlinks)
3367 * @param {Function} transform - path transformer
3368 * @param {Function} globFilter - path filter in case a glob pattern was provided
3369 * @returns {Function} closer for the watcher instance
3370*/
3371_watchWithFsEvents(watchPath, realPath, transform, globFilter) {
3372 if (this.fsw.closed || this.fsw._isIgnored(watchPath)) return;
3373 const opts = this.fsw.options;
3374 const watchCallback = async (fullPath, flags, info) => {
3375 if (this.fsw.closed) return;
3376 if (
3377 opts.depth !== undefined &&
3378 calcDepth(fullPath, realPath) > opts.depth
3379 ) return;
3380 const path = transform(sysPath$1.join(
3381 watchPath, sysPath$1.relative(watchPath, fullPath)
3382 ));
3383 if (globFilter && !globFilter(path)) return;
3384 // ensure directories are tracked
3385 const parent = sysPath$1.dirname(path);
3386 const item = sysPath$1.basename(path);
3387 const watchedDir = this.fsw._getWatchedDir(
3388 info.type === FSEVENT_TYPE_DIRECTORY ? path : parent
3389 );
3390
3391 // correct for wrong events emitted
3392 if (wrongEventFlags.has(flags) || info.event === FSEVENT_UNKNOWN) {
3393 if (typeof opts.ignored === FUNCTION_TYPE$1) {
3394 let stats;
3395 try {
3396 stats = await stat$1(path);
3397 } catch (error) {}
3398 if (this.fsw.closed) return;
3399 if (this.checkIgnored(path, stats)) return;
3400 if (sameTypes(info, stats)) {
3401 this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts);
3402 } else {
3403 this.handleEvent(EV_UNLINK$1, path, fullPath, realPath, parent, watchedDir, item, info, opts);
3404 }
3405 } else {
3406 this.checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts);
3407 }
3408 } else {
3409 switch (info.event) {
3410 case FSEVENT_CREATED:
3411 case FSEVENT_MODIFIED:
3412 return this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts);
3413 case FSEVENT_DELETED:
3414 case FSEVENT_MOVED:
3415 return this.checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts);
3416 }
3417 }
3418 };
3419
3420 const closer = setFSEventsListener(
3421 watchPath,
3422 realPath,
3423 watchCallback,
3424 this.fsw._emitRaw
3425 );
3426
3427 this.fsw._emitReady();
3428 return closer;
3429}
3430
3431/**
3432 * Handle symlinks encountered during directory scan
3433 * @param {String} linkPath path to symlink
3434 * @param {String} fullPath absolute path to the symlink
3435 * @param {Function} transform pre-existing path transformer
3436 * @param {Number} curDepth level of subdirectories traversed to where symlink is
3437 * @returns {Promise<void>}
3438 */
3439async _handleFsEventsSymlink(linkPath, fullPath, transform, curDepth) {
3440 // don't follow the same symlink more than once
3441 if (this.fsw.closed || this.fsw._symlinkPaths.has(fullPath)) return;
3442
3443 this.fsw._symlinkPaths.set(fullPath, true);
3444 this.fsw._incrReadyCount();
3445
3446 try {
3447 const linkTarget = await realpath(linkPath);
3448 if (this.fsw.closed) return;
3449 if (this.fsw._isIgnored(linkTarget)) {
3450 return this.fsw._emitReady();
3451 }
3452
3453 this.fsw._incrReadyCount();
3454
3455 // add the linkTarget for watching with a wrapper for transform
3456 // that causes emitted paths to incorporate the link's path
3457 this._addToFsEvents(linkTarget || linkPath, (path) => {
3458 let aliasedPath = linkPath;
3459 if (linkTarget && linkTarget !== DOT_SLASH) {
3460 aliasedPath = path.replace(linkTarget, linkPath);
3461 } else if (path !== DOT_SLASH) {
3462 aliasedPath = sysPath$1.join(linkPath, path);
3463 }
3464 return transform(aliasedPath);
3465 }, false, curDepth);
3466 } catch(error) {
3467 if (this.fsw._handleError(error)) {
3468 return this.fsw._emitReady();
3469 }
3470 }
3471}
3472
3473/**
3474 *
3475 * @param {Path} newPath
3476 * @param {fs.Stats} stats
3477 */
3478emitAdd(newPath, stats, processPath, opts, forceAdd) {
3479 const pp = processPath(newPath);
3480 const isDir = stats.isDirectory();
3481 const dirObj = this.fsw._getWatchedDir(sysPath$1.dirname(pp));
3482 const base = sysPath$1.basename(pp);
3483
3484 // ensure empty dirs get tracked
3485 if (isDir) this.fsw._getWatchedDir(pp);
3486 if (dirObj.has(base)) return;
3487 dirObj.add(base);
3488
3489 if (!opts.ignoreInitial || forceAdd === true) {
3490 this.fsw._emit(isDir ? EV_ADD_DIR$1 : EV_ADD$1, pp, stats);
3491 }
3492}
3493
3494initWatch(realPath, path, wh, processPath) {
3495 if (this.fsw.closed) return;
3496 const closer = this._watchWithFsEvents(
3497 wh.watchPath,
3498 sysPath$1.resolve(realPath || wh.watchPath),
3499 processPath,
3500 wh.globFilter
3501 );
3502 this.fsw._addPathCloser(path, closer);
3503}
3504
3505/**
3506 * Handle added path with fsevents
3507 * @param {String} path file/dir path or glob pattern
3508 * @param {Function|Boolean=} transform converts working path to what the user expects
3509 * @param {Boolean=} forceAdd ensure add is emitted
3510 * @param {Number=} priorDepth Level of subdirectories already traversed.
3511 * @returns {Promise<void>}
3512 */
3513async _addToFsEvents(path, transform, forceAdd, priorDepth) {
3514 if (this.fsw.closed) {
3515 return;
3516 }
3517 const opts = this.fsw.options;
3518 const processPath = typeof transform === FUNCTION_TYPE$1 ? transform : IDENTITY_FN;
3519
3520 const wh = this.fsw._getWatchHelpers(path);
3521
3522 // evaluate what is at the path we're being asked to watch
3523 try {
3524 const stats = await statMethods[wh.statMethod](wh.watchPath);
3525 if (this.fsw.closed) return;
3526 if (this.fsw._isIgnored(wh.watchPath, stats)) {
3527 throw null;
3528 }
3529 if (stats.isDirectory()) {
3530 // emit addDir unless this is a glob parent
3531 if (!wh.globFilter) this.emitAdd(processPath(path), stats, processPath, opts, forceAdd);
3532
3533 // don't recurse further if it would exceed depth setting
3534 if (priorDepth && priorDepth > opts.depth) return;
3535
3536 // scan the contents of the dir
3537 this.fsw._readdirp(wh.watchPath, {
3538 fileFilter: entry => wh.filterPath(entry),
3539 directoryFilter: entry => wh.filterDir(entry),
3540 ...Depth(opts.depth - (priorDepth || 0))
3541 }).on(STR_DATA, (entry) => {
3542 // need to check filterPath on dirs b/c filterDir is less restrictive
3543 if (this.fsw.closed) {
3544 return;
3545 }
3546 if (entry.stats.isDirectory() && !wh.filterPath(entry)) return;
3547
3548 const joinedPath = sysPath$1.join(wh.watchPath, entry.path);
3549 const {fullPath} = entry;
3550
3551 if (wh.followSymlinks && entry.stats.isSymbolicLink()) {
3552 // preserve the current depth here since it can't be derived from
3553 // real paths past the symlink
3554 const curDepth = opts.depth === undefined ?
3555 undefined : calcDepth(joinedPath, sysPath$1.resolve(wh.watchPath)) + 1;
3556
3557 this._handleFsEventsSymlink(joinedPath, fullPath, processPath, curDepth);
3558 } else {
3559 this.emitAdd(joinedPath, entry.stats, processPath, opts, forceAdd);
3560 }
3561 }).on(EV_ERROR$1, EMPTY_FN$1).on(STR_END$1, () => {
3562 this.fsw._emitReady();
3563 });
3564 } else {
3565 this.emitAdd(wh.watchPath, stats, processPath, opts, forceAdd);
3566 this.fsw._emitReady();
3567 }
3568 } catch (error) {
3569 if (!error || this.fsw._handleError(error)) {
3570 // TODO: Strange thing: "should not choke on an ignored watch path" will be failed without 2 ready calls -__-
3571 this.fsw._emitReady();
3572 this.fsw._emitReady();
3573 }
3574 }
3575
3576 if (opts.persistent && forceAdd !== true) {
3577 if (typeof transform === FUNCTION_TYPE$1) {
3578 // realpath has already been resolved
3579 this.initWatch(undefined, path, wh, processPath);
3580 } else {
3581 let realPath;
3582 try {
3583 realPath = await realpath(wh.watchPath);
3584 } catch (e) {}
3585 this.initWatch(realPath, path, wh, processPath);
3586 }
3587 }
3588}
3589
3590}
3591
3592fseventsHandler.exports = FsEventsHandler$1;
3593fseventsHandler.exports.canUse = canUse;
3594
3595const { EventEmitter } = require$$0$3;
3596const fs = require$$0$1;
3597const sysPath = require$$0$2;
3598const { promisify } = require$$2;
3599const readdirp = readdirp_1;
3600const anymatch = anymatch$2.exports.default;
3601const globParent = globParent$1;
3602const isGlob = isGlob$2;
3603const braces = braces_1;
3604const normalizePath = normalizePath$2;
3605
3606const NodeFsHandler = nodefsHandler;
3607const FsEventsHandler = fseventsHandler.exports;
3608const {
3609 EV_ALL,
3610 EV_READY,
3611 EV_ADD,
3612 EV_CHANGE,
3613 EV_UNLINK,
3614 EV_ADD_DIR,
3615 EV_UNLINK_DIR,
3616 EV_RAW,
3617 EV_ERROR,
3618
3619 STR_CLOSE,
3620 STR_END,
3621
3622 BACK_SLASH_RE,
3623 DOUBLE_SLASH_RE,
3624 SLASH_OR_BACK_SLASH_RE,
3625 DOT_RE,
3626 REPLACER_RE,
3627
3628 SLASH,
3629 SLASH_SLASH,
3630 BRACE_START,
3631 BANG,
3632 ONE_DOT,
3633 TWO_DOTS,
3634 GLOBSTAR,
3635 SLASH_GLOBSTAR,
3636 ANYMATCH_OPTS,
3637 STRING_TYPE,
3638 FUNCTION_TYPE,
3639 EMPTY_STR,
3640 EMPTY_FN,
3641
3642 isWindows,
3643 isMacos,
3644 isIBMi
3645} = constants;
3646
3647const stat = promisify(fs.stat);
3648const readdir = promisify(fs.readdir);
3649
3650/**
3651 * @typedef {String} Path
3652 * @typedef {'all'|'add'|'addDir'|'change'|'unlink'|'unlinkDir'|'raw'|'error'|'ready'} EventName
3653 * @typedef {'readdir'|'watch'|'add'|'remove'|'change'} ThrottleType
3654 */
3655
3656/**
3657 *
3658 * @typedef {Object} WatchHelpers
3659 * @property {Boolean} followSymlinks
3660 * @property {'stat'|'lstat'} statMethod
3661 * @property {Path} path
3662 * @property {Path} watchPath
3663 * @property {Function} entryPath
3664 * @property {Boolean} hasGlob
3665 * @property {Object} globFilter
3666 * @property {Function} filterPath
3667 * @property {Function} filterDir
3668 */
3669
3670const arrify = (value = []) => Array.isArray(value) ? value : [value];
3671const flatten = (list, result = []) => {
3672 list.forEach(item => {
3673 if (Array.isArray(item)) {
3674 flatten(item, result);
3675 } else {
3676 result.push(item);
3677 }
3678 });
3679 return result;
3680};
3681
3682const unifyPaths = (paths_) => {
3683 /**
3684 * @type {Array<String>}
3685 */
3686 const paths = flatten(arrify(paths_));
3687 if (!paths.every(p => typeof p === STRING_TYPE)) {
3688 throw new TypeError(`Non-string provided as watch path: ${paths}`);
3689 }
3690 return paths.map(normalizePathToUnix);
3691};
3692
3693// If SLASH_SLASH occurs at the beginning of path, it is not replaced
3694// because "//StoragePC/DrivePool/Movies" is a valid network path
3695const toUnix = (string) => {
3696 let str = string.replace(BACK_SLASH_RE, SLASH);
3697 let prepend = false;
3698 if (str.startsWith(SLASH_SLASH)) {
3699 prepend = true;
3700 }
3701 while (str.match(DOUBLE_SLASH_RE)) {
3702 str = str.replace(DOUBLE_SLASH_RE, SLASH);
3703 }
3704 if (prepend) {
3705 str = SLASH + str;
3706 }
3707 return str;
3708};
3709
3710// Our version of upath.normalize
3711// TODO: this is not equal to path-normalize module - investigate why
3712const normalizePathToUnix = (path) => toUnix(sysPath.normalize(toUnix(path)));
3713
3714const normalizeIgnored = (cwd = EMPTY_STR) => (path) => {
3715 if (typeof path !== STRING_TYPE) return path;
3716 return normalizePathToUnix(sysPath.isAbsolute(path) ? path : sysPath.join(cwd, path));
3717};
3718
3719const getAbsolutePath = (path, cwd) => {
3720 if (sysPath.isAbsolute(path)) {
3721 return path;
3722 }
3723 if (path.startsWith(BANG)) {
3724 return BANG + sysPath.join(cwd, path.slice(1));
3725 }
3726 return sysPath.join(cwd, path);
3727};
3728
3729const undef = (opts, key) => opts[key] === undefined;
3730
3731/**
3732 * Directory entry.
3733 * @property {Path} path
3734 * @property {Set<Path>} items
3735 */
3736class DirEntry {
3737 /**
3738 * @param {Path} dir
3739 * @param {Function} removeWatcher
3740 */
3741 constructor(dir, removeWatcher) {
3742 this.path = dir;
3743 this._removeWatcher = removeWatcher;
3744 /** @type {Set<Path>} */
3745 this.items = new Set();
3746 }
3747
3748 add(item) {
3749 const {items} = this;
3750 if (!items) return;
3751 if (item !== ONE_DOT && item !== TWO_DOTS) items.add(item);
3752 }
3753
3754 async remove(item) {
3755 const {items} = this;
3756 if (!items) return;
3757 items.delete(item);
3758 if (items.size > 0) return;
3759
3760 const dir = this.path;
3761 try {
3762 await readdir(dir);
3763 } catch (err) {
3764 if (this._removeWatcher) {
3765 this._removeWatcher(sysPath.dirname(dir), sysPath.basename(dir));
3766 }
3767 }
3768 }
3769
3770 has(item) {
3771 const {items} = this;
3772 if (!items) return;
3773 return items.has(item);
3774 }
3775
3776 /**
3777 * @returns {Array<String>}
3778 */
3779 getChildren() {
3780 const {items} = this;
3781 if (!items) return;
3782 return [...items.values()];
3783 }
3784
3785 dispose() {
3786 this.items.clear();
3787 delete this.path;
3788 delete this._removeWatcher;
3789 delete this.items;
3790 Object.freeze(this);
3791 }
3792}
3793
3794const STAT_METHOD_F = 'stat';
3795const STAT_METHOD_L = 'lstat';
3796class WatchHelper {
3797 constructor(path, watchPath, follow, fsw) {
3798 this.fsw = fsw;
3799 this.path = path = path.replace(REPLACER_RE, EMPTY_STR);
3800 this.watchPath = watchPath;
3801 this.fullWatchPath = sysPath.resolve(watchPath);
3802 this.hasGlob = watchPath !== path;
3803 /** @type {object|boolean} */
3804 if (path === EMPTY_STR) this.hasGlob = false;
3805 this.globSymlink = this.hasGlob && follow ? undefined : false;
3806 this.globFilter = this.hasGlob ? anymatch(path, undefined, ANYMATCH_OPTS) : false;
3807 this.dirParts = this.getDirParts(path);
3808 this.dirParts.forEach((parts) => {
3809 if (parts.length > 1) parts.pop();
3810 });
3811 this.followSymlinks = follow;
3812 this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;
3813 }
3814
3815 checkGlobSymlink(entry) {
3816 // only need to resolve once
3817 // first entry should always have entry.parentDir === EMPTY_STR
3818 if (this.globSymlink === undefined) {
3819 this.globSymlink = entry.fullParentDir === this.fullWatchPath ?
3820 false : {realPath: entry.fullParentDir, linkPath: this.fullWatchPath};
3821 }
3822
3823 if (this.globSymlink) {
3824 return entry.fullPath.replace(this.globSymlink.realPath, this.globSymlink.linkPath);
3825 }
3826
3827 return entry.fullPath;
3828 }
3829
3830 entryPath(entry) {
3831 return sysPath.join(this.watchPath,
3832 sysPath.relative(this.watchPath, this.checkGlobSymlink(entry))
3833 );
3834 }
3835
3836 filterPath(entry) {
3837 const {stats} = entry;
3838 if (stats && stats.isSymbolicLink()) return this.filterDir(entry);
3839 const resolvedPath = this.entryPath(entry);
3840 const matchesGlob = this.hasGlob && typeof this.globFilter === FUNCTION_TYPE ?
3841 this.globFilter(resolvedPath) : true;
3842 return matchesGlob &&
3843 this.fsw._isntIgnored(resolvedPath, stats) &&
3844 this.fsw._hasReadPermissions(stats);
3845 }
3846
3847 getDirParts(path) {
3848 if (!this.hasGlob) return [];
3849 const parts = [];
3850 const expandedPath = path.includes(BRACE_START) ? braces.expand(path) : [path];
3851 expandedPath.forEach((path) => {
3852 parts.push(sysPath.relative(this.watchPath, path).split(SLASH_OR_BACK_SLASH_RE));
3853 });
3854 return parts;
3855 }
3856
3857 filterDir(entry) {
3858 if (this.hasGlob) {
3859 const entryParts = this.getDirParts(this.checkGlobSymlink(entry));
3860 let globstar = false;
3861 this.unmatchedGlob = !this.dirParts.some((parts) => {
3862 return parts.every((part, i) => {
3863 if (part === GLOBSTAR) globstar = true;
3864 return globstar || !entryParts[0][i] || anymatch(part, entryParts[0][i], ANYMATCH_OPTS);
3865 });
3866 });
3867 }
3868 return !this.unmatchedGlob && this.fsw._isntIgnored(this.entryPath(entry), entry.stats);
3869 }
3870}
3871
3872/**
3873 * Watches files & directories for changes. Emitted events:
3874 * `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error`
3875 *
3876 * new FSWatcher()
3877 * .add(directories)
3878 * .on('add', path => log('File', path, 'was added'))
3879 */
3880class FSWatcher extends EventEmitter {
3881// Not indenting methods for history sake; for now.
3882constructor(_opts) {
3883 super();
3884
3885 const opts = {};
3886 if (_opts) Object.assign(opts, _opts); // for frozen objects
3887
3888 /** @type {Map<String, DirEntry>} */
3889 this._watched = new Map();
3890 /** @type {Map<String, Array>} */
3891 this._closers = new Map();
3892 /** @type {Set<String>} */
3893 this._ignoredPaths = new Set();
3894
3895 /** @type {Map<ThrottleType, Map>} */
3896 this._throttled = new Map();
3897
3898 /** @type {Map<Path, String|Boolean>} */
3899 this._symlinkPaths = new Map();
3900
3901 this._streams = new Set();
3902 this.closed = false;
3903
3904 // Set up default options.
3905 if (undef(opts, 'persistent')) opts.persistent = true;
3906 if (undef(opts, 'ignoreInitial')) opts.ignoreInitial = false;
3907 if (undef(opts, 'ignorePermissionErrors')) opts.ignorePermissionErrors = false;
3908 if (undef(opts, 'interval')) opts.interval = 100;
3909 if (undef(opts, 'binaryInterval')) opts.binaryInterval = 300;
3910 if (undef(opts, 'disableGlobbing')) opts.disableGlobbing = false;
3911 opts.enableBinaryInterval = opts.binaryInterval !== opts.interval;
3912
3913 // Enable fsevents on OS X when polling isn't explicitly enabled.
3914 if (undef(opts, 'useFsEvents')) opts.useFsEvents = !opts.usePolling;
3915
3916 // If we can't use fsevents, ensure the options reflect it's disabled.
3917 const canUseFsEvents = FsEventsHandler.canUse();
3918 if (!canUseFsEvents) opts.useFsEvents = false;
3919
3920 // Use polling on Mac if not using fsevents.
3921 // Other platforms use non-polling fs_watch.
3922 if (undef(opts, 'usePolling') && !opts.useFsEvents) {
3923 opts.usePolling = isMacos;
3924 }
3925
3926 // Always default to polling on IBM i because fs.watch() is not available on IBM i.
3927 if(isIBMi) {
3928 opts.usePolling = true;
3929 }
3930
3931 // Global override (useful for end-developers that need to force polling for all
3932 // instances of chokidar, regardless of usage/dependency depth)
3933 const envPoll = process.env.CHOKIDAR_USEPOLLING;
3934 if (envPoll !== undefined) {
3935 const envLower = envPoll.toLowerCase();
3936
3937 if (envLower === 'false' || envLower === '0') {
3938 opts.usePolling = false;
3939 } else if (envLower === 'true' || envLower === '1') {
3940 opts.usePolling = true;
3941 } else {
3942 opts.usePolling = !!envLower;
3943 }
3944 }
3945 const envInterval = process.env.CHOKIDAR_INTERVAL;
3946 if (envInterval) {
3947 opts.interval = Number.parseInt(envInterval, 10);
3948 }
3949
3950 // Editor atomic write normalization enabled by default with fs.watch
3951 if (undef(opts, 'atomic')) opts.atomic = !opts.usePolling && !opts.useFsEvents;
3952 if (opts.atomic) this._pendingUnlinks = new Map();
3953
3954 if (undef(opts, 'followSymlinks')) opts.followSymlinks = true;
3955
3956 if (undef(opts, 'awaitWriteFinish')) opts.awaitWriteFinish = false;
3957 if (opts.awaitWriteFinish === true) opts.awaitWriteFinish = {};
3958 const awf = opts.awaitWriteFinish;
3959 if (awf) {
3960 if (!awf.stabilityThreshold) awf.stabilityThreshold = 2000;
3961 if (!awf.pollInterval) awf.pollInterval = 100;
3962 this._pendingWrites = new Map();
3963 }
3964 if (opts.ignored) opts.ignored = arrify(opts.ignored);
3965
3966 let readyCalls = 0;
3967 this._emitReady = () => {
3968 readyCalls++;
3969 if (readyCalls >= this._readyCount) {
3970 this._emitReady = EMPTY_FN;
3971 this._readyEmitted = true;
3972 // use process.nextTick to allow time for listener to be bound
3973 process.nextTick(() => this.emit(EV_READY));
3974 }
3975 };
3976 this._emitRaw = (...args) => this.emit(EV_RAW, ...args);
3977 this._readyEmitted = false;
3978 this.options = opts;
3979
3980 // Initialize with proper watcher.
3981 if (opts.useFsEvents) {
3982 this._fsEventsHandler = new FsEventsHandler(this);
3983 } else {
3984 this._nodeFsHandler = new NodeFsHandler(this);
3985 }
3986
3987 // You’re frozen when your heart’s not open.
3988 Object.freeze(opts);
3989}
3990
3991// Public methods
3992
3993/**
3994 * Adds paths to be watched on an existing FSWatcher instance
3995 * @param {Path|Array<Path>} paths_
3996 * @param {String=} _origAdd private; for handling non-existent paths to be watched
3997 * @param {Boolean=} _internal private; indicates a non-user add
3998 * @returns {FSWatcher} for chaining
3999 */
4000add(paths_, _origAdd, _internal) {
4001 const {cwd, disableGlobbing} = this.options;
4002 this.closed = false;
4003 let paths = unifyPaths(paths_);
4004 if (cwd) {
4005 paths = paths.map((path) => {
4006 const absPath = getAbsolutePath(path, cwd);
4007
4008 // Check `path` instead of `absPath` because the cwd portion can't be a glob
4009 if (disableGlobbing || !isGlob(path)) {
4010 return absPath;
4011 }
4012 return normalizePath(absPath);
4013 });
4014 }
4015
4016 // set aside negated glob strings
4017 paths = paths.filter((path) => {
4018 if (path.startsWith(BANG)) {
4019 this._ignoredPaths.add(path.slice(1));
4020 return false;
4021 }
4022
4023 // if a path is being added that was previously ignored, stop ignoring it
4024 this._ignoredPaths.delete(path);
4025 this._ignoredPaths.delete(path + SLASH_GLOBSTAR);
4026
4027 // reset the cached userIgnored anymatch fn
4028 // to make ignoredPaths changes effective
4029 this._userIgnored = undefined;
4030
4031 return true;
4032 });
4033
4034 if (this.options.useFsEvents && this._fsEventsHandler) {
4035 if (!this._readyCount) this._readyCount = paths.length;
4036 if (this.options.persistent) this._readyCount *= 2;
4037 paths.forEach((path) => this._fsEventsHandler._addToFsEvents(path));
4038 } else {
4039 if (!this._readyCount) this._readyCount = 0;
4040 this._readyCount += paths.length;
4041 Promise.all(
4042 paths.map(async path => {
4043 const res = await this._nodeFsHandler._addToNodeFs(path, !_internal, 0, 0, _origAdd);
4044 if (res) this._emitReady();
4045 return res;
4046 })
4047 ).then(results => {
4048 if (this.closed) return;
4049 results.filter(item => item).forEach(item => {
4050 this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item));
4051 });
4052 });
4053 }
4054
4055 return this;
4056}
4057
4058/**
4059 * Close watchers or start ignoring events from specified paths.
4060 * @param {Path|Array<Path>} paths_ - string or array of strings, file/directory paths and/or globs
4061 * @returns {FSWatcher} for chaining
4062*/
4063unwatch(paths_) {
4064 if (this.closed) return this;
4065 const paths = unifyPaths(paths_);
4066 const {cwd} = this.options;
4067
4068 paths.forEach((path) => {
4069 // convert to absolute path unless relative path already matches
4070 if (!sysPath.isAbsolute(path) && !this._closers.has(path)) {
4071 if (cwd) path = sysPath.join(cwd, path);
4072 path = sysPath.resolve(path);
4073 }
4074
4075 this._closePath(path);
4076
4077 this._ignoredPaths.add(path);
4078 if (this._watched.has(path)) {
4079 this._ignoredPaths.add(path + SLASH_GLOBSTAR);
4080 }
4081
4082 // reset the cached userIgnored anymatch fn
4083 // to make ignoredPaths changes effective
4084 this._userIgnored = undefined;
4085 });
4086
4087 return this;
4088}
4089
4090/**
4091 * Close watchers and remove all listeners from watched paths.
4092 * @returns {Promise<void>}.
4093*/
4094close() {
4095 if (this.closed) return this._closePromise;
4096 this.closed = true;
4097
4098 // Memory management.
4099 this.removeAllListeners();
4100 const closers = [];
4101 this._closers.forEach(closerList => closerList.forEach(closer => {
4102 const promise = closer();
4103 if (promise instanceof Promise) closers.push(promise);
4104 }));
4105 this._streams.forEach(stream => stream.destroy());
4106 this._userIgnored = undefined;
4107 this._readyCount = 0;
4108 this._readyEmitted = false;
4109 this._watched.forEach(dirent => dirent.dispose());
4110 ['closers', 'watched', 'streams', 'symlinkPaths', 'throttled'].forEach(key => {
4111 this[`_${key}`].clear();
4112 });
4113
4114 this._closePromise = closers.length ? Promise.all(closers).then(() => undefined) : Promise.resolve();
4115 return this._closePromise;
4116}
4117
4118/**
4119 * Expose list of watched paths
4120 * @returns {Object} for chaining
4121*/
4122getWatched() {
4123 const watchList = {};
4124 this._watched.forEach((entry, dir) => {
4125 const key = this.options.cwd ? sysPath.relative(this.options.cwd, dir) : dir;
4126 watchList[key || ONE_DOT] = entry.getChildren().sort();
4127 });
4128 return watchList;
4129}
4130
4131emitWithAll(event, args) {
4132 this.emit(...args);
4133 if (event !== EV_ERROR) this.emit(EV_ALL, ...args);
4134}
4135
4136// Common helpers
4137// --------------
4138
4139/**
4140 * Normalize and emit events.
4141 * Calling _emit DOES NOT MEAN emit() would be called!
4142 * @param {EventName} event Type of event
4143 * @param {Path} path File or directory path
4144 * @param {*=} val1 arguments to be passed with event
4145 * @param {*=} val2
4146 * @param {*=} val3
4147 * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
4148 */
4149async _emit(event, path, val1, val2, val3) {
4150 if (this.closed) return;
4151
4152 const opts = this.options;
4153 if (isWindows) path = sysPath.normalize(path);
4154 if (opts.cwd) path = sysPath.relative(opts.cwd, path);
4155 /** @type Array<any> */
4156 const args = [event, path];
4157 if (val3 !== undefined) args.push(val1, val2, val3);
4158 else if (val2 !== undefined) args.push(val1, val2);
4159 else if (val1 !== undefined) args.push(val1);
4160
4161 const awf = opts.awaitWriteFinish;
4162 let pw;
4163 if (awf && (pw = this._pendingWrites.get(path))) {
4164 pw.lastChange = new Date();
4165 return this;
4166 }
4167
4168 if (opts.atomic) {
4169 if (event === EV_UNLINK) {
4170 this._pendingUnlinks.set(path, args);
4171 setTimeout(() => {
4172 this._pendingUnlinks.forEach((entry, path) => {
4173 this.emit(...entry);
4174 this.emit(EV_ALL, ...entry);
4175 this._pendingUnlinks.delete(path);
4176 });
4177 }, typeof opts.atomic === 'number' ? opts.atomic : 100);
4178 return this;
4179 }
4180 if (event === EV_ADD && this._pendingUnlinks.has(path)) {
4181 event = args[0] = EV_CHANGE;
4182 this._pendingUnlinks.delete(path);
4183 }
4184 }
4185
4186 if (awf && (event === EV_ADD || event === EV_CHANGE) && this._readyEmitted) {
4187 const awfEmit = (err, stats) => {
4188 if (err) {
4189 event = args[0] = EV_ERROR;
4190 args[1] = err;
4191 this.emitWithAll(event, args);
4192 } else if (stats) {
4193 // if stats doesn't exist the file must have been deleted
4194 if (args.length > 2) {
4195 args[2] = stats;
4196 } else {
4197 args.push(stats);
4198 }
4199 this.emitWithAll(event, args);
4200 }
4201 };
4202
4203 this._awaitWriteFinish(path, awf.stabilityThreshold, event, awfEmit);
4204 return this;
4205 }
4206
4207 if (event === EV_CHANGE) {
4208 const isThrottled = !this._throttle(EV_CHANGE, path, 50);
4209 if (isThrottled) return this;
4210 }
4211
4212 if (opts.alwaysStat && val1 === undefined &&
4213 (event === EV_ADD || event === EV_ADD_DIR || event === EV_CHANGE)
4214 ) {
4215 const fullPath = opts.cwd ? sysPath.join(opts.cwd, path) : path;
4216 let stats;
4217 try {
4218 stats = await stat(fullPath);
4219 } catch (err) {}
4220 // Suppress event when fs_stat fails, to avoid sending undefined 'stat'
4221 if (!stats || this.closed) return;
4222 args.push(stats);
4223 }
4224 this.emitWithAll(event, args);
4225
4226 return this;
4227}
4228
4229/**
4230 * Common handler for errors
4231 * @param {Error} error
4232 * @returns {Error|Boolean} The error if defined, otherwise the value of the FSWatcher instance's `closed` flag
4233 */
4234_handleError(error) {
4235 const code = error && error.code;
4236 if (error && code !== 'ENOENT' && code !== 'ENOTDIR' &&
4237 (!this.options.ignorePermissionErrors || (code !== 'EPERM' && code !== 'EACCES'))
4238 ) {
4239 this.emit(EV_ERROR, error);
4240 }
4241 return error || this.closed;
4242}
4243
4244/**
4245 * Helper utility for throttling
4246 * @param {ThrottleType} actionType type being throttled
4247 * @param {Path} path being acted upon
4248 * @param {Number} timeout duration of time to suppress duplicate actions
4249 * @returns {Object|false} tracking object or false if action should be suppressed
4250 */
4251_throttle(actionType, path, timeout) {
4252 if (!this._throttled.has(actionType)) {
4253 this._throttled.set(actionType, new Map());
4254 }
4255
4256 /** @type {Map<Path, Object>} */
4257 const action = this._throttled.get(actionType);
4258 /** @type {Object} */
4259 const actionPath = action.get(path);
4260
4261 if (actionPath) {
4262 actionPath.count++;
4263 return false;
4264 }
4265
4266 let timeoutObject;
4267 const clear = () => {
4268 const item = action.get(path);
4269 const count = item ? item.count : 0;
4270 action.delete(path);
4271 clearTimeout(timeoutObject);
4272 if (item) clearTimeout(item.timeoutObject);
4273 return count;
4274 };
4275 timeoutObject = setTimeout(clear, timeout);
4276 const thr = {timeoutObject, clear, count: 0};
4277 action.set(path, thr);
4278 return thr;
4279}
4280
4281_incrReadyCount() {
4282 return this._readyCount++;
4283}
4284
4285/**
4286 * Awaits write operation to finish.
4287 * Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback.
4288 * @param {Path} path being acted upon
4289 * @param {Number} threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished
4290 * @param {EventName} event
4291 * @param {Function} awfEmit Callback to be called when ready for event to be emitted.
4292 */
4293_awaitWriteFinish(path, threshold, event, awfEmit) {
4294 let timeoutHandler;
4295
4296 let fullPath = path;
4297 if (this.options.cwd && !sysPath.isAbsolute(path)) {
4298 fullPath = sysPath.join(this.options.cwd, path);
4299 }
4300
4301 const now = new Date();
4302
4303 const awaitWriteFinish = (prevStat) => {
4304 fs.stat(fullPath, (err, curStat) => {
4305 if (err || !this._pendingWrites.has(path)) {
4306 if (err && err.code !== 'ENOENT') awfEmit(err);
4307 return;
4308 }
4309
4310 const now = Number(new Date());
4311
4312 if (prevStat && curStat.size !== prevStat.size) {
4313 this._pendingWrites.get(path).lastChange = now;
4314 }
4315 const pw = this._pendingWrites.get(path);
4316 const df = now - pw.lastChange;
4317
4318 if (df >= threshold) {
4319 this._pendingWrites.delete(path);
4320 awfEmit(undefined, curStat);
4321 } else {
4322 timeoutHandler = setTimeout(
4323 awaitWriteFinish,
4324 this.options.awaitWriteFinish.pollInterval,
4325 curStat
4326 );
4327 }
4328 });
4329 };
4330
4331 if (!this._pendingWrites.has(path)) {
4332 this._pendingWrites.set(path, {
4333 lastChange: now,
4334 cancelWait: () => {
4335 this._pendingWrites.delete(path);
4336 clearTimeout(timeoutHandler);
4337 return event;
4338 }
4339 });
4340 timeoutHandler = setTimeout(
4341 awaitWriteFinish,
4342 this.options.awaitWriteFinish.pollInterval
4343 );
4344 }
4345}
4346
4347_getGlobIgnored() {
4348 return [...this._ignoredPaths.values()];
4349}
4350
4351/**
4352 * Determines whether user has asked to ignore this path.
4353 * @param {Path} path filepath or dir
4354 * @param {fs.Stats=} stats result of fs.stat
4355 * @returns {Boolean}
4356 */
4357_isIgnored(path, stats) {
4358 if (this.options.atomic && DOT_RE.test(path)) return true;
4359 if (!this._userIgnored) {
4360 const {cwd} = this.options;
4361 const ign = this.options.ignored;
4362
4363 const ignored = ign && ign.map(normalizeIgnored(cwd));
4364 const paths = arrify(ignored)
4365 .filter((path) => typeof path === STRING_TYPE && !isGlob(path))
4366 .map((path) => path + SLASH_GLOBSTAR);
4367 const list = this._getGlobIgnored().map(normalizeIgnored(cwd)).concat(ignored, paths);
4368 this._userIgnored = anymatch(list, undefined, ANYMATCH_OPTS);
4369 }
4370
4371 return this._userIgnored([path, stats]);
4372}
4373
4374_isntIgnored(path, stat) {
4375 return !this._isIgnored(path, stat);
4376}
4377
4378/**
4379 * Provides a set of common helpers and properties relating to symlink and glob handling.
4380 * @param {Path} path file, directory, or glob pattern being watched
4381 * @param {Number=} depth at any depth > 0, this isn't a glob
4382 * @returns {WatchHelper} object containing helpers for this path
4383 */
4384_getWatchHelpers(path, depth) {
4385 const watchPath = depth || this.options.disableGlobbing || !isGlob(path) ? path : globParent(path);
4386 const follow = this.options.followSymlinks;
4387
4388 return new WatchHelper(path, watchPath, follow, this);
4389}
4390
4391// Directory helpers
4392// -----------------
4393
4394/**
4395 * Provides directory tracking objects
4396 * @param {String} directory path of the directory
4397 * @returns {DirEntry} the directory's tracking object
4398 */
4399_getWatchedDir(directory) {
4400 if (!this._boundRemove) this._boundRemove = this._remove.bind(this);
4401 const dir = sysPath.resolve(directory);
4402 if (!this._watched.has(dir)) this._watched.set(dir, new DirEntry(dir, this._boundRemove));
4403 return this._watched.get(dir);
4404}
4405
4406// File helpers
4407// ------------
4408
4409/**
4410 * Check for read permissions.
4411 * Based on this answer on SO: https://stackoverflow.com/a/11781404/1358405
4412 * @param {fs.Stats} stats - object, result of fs_stat
4413 * @returns {Boolean} indicates whether the file can be read
4414*/
4415_hasReadPermissions(stats) {
4416 if (this.options.ignorePermissionErrors) return true;
4417
4418 // stats.mode may be bigint
4419 const md = stats && Number.parseInt(stats.mode, 10);
4420 const st = md & 0o777;
4421 const it = Number.parseInt(st.toString(8)[0], 10);
4422 return Boolean(4 & it);
4423}
4424
4425/**
4426 * Handles emitting unlink events for
4427 * files and directories, and via recursion, for
4428 * files and directories within directories that are unlinked
4429 * @param {String} directory within which the following item is located
4430 * @param {String} item base path of item/directory
4431 * @returns {void}
4432*/
4433_remove(directory, item, isDirectory) {
4434 // if what is being deleted is a directory, get that directory's paths
4435 // for recursive deleting and cleaning of watched object
4436 // if it is not a directory, nestedDirectoryChildren will be empty array
4437 const path = sysPath.join(directory, item);
4438 const fullPath = sysPath.resolve(path);
4439 isDirectory = isDirectory != null
4440 ? isDirectory
4441 : this._watched.has(path) || this._watched.has(fullPath);
4442
4443 // prevent duplicate handling in case of arriving here nearly simultaneously
4444 // via multiple paths (such as _handleFile and _handleDir)
4445 if (!this._throttle('remove', path, 100)) return;
4446
4447 // if the only watched file is removed, watch for its return
4448 if (!isDirectory && !this.options.useFsEvents && this._watched.size === 1) {
4449 this.add(directory, item, true);
4450 }
4451
4452 // This will create a new entry in the watched object in either case
4453 // so we got to do the directory check beforehand
4454 const wp = this._getWatchedDir(path);
4455 const nestedDirectoryChildren = wp.getChildren();
4456
4457 // Recursively remove children directories / files.
4458 nestedDirectoryChildren.forEach(nested => this._remove(path, nested));
4459
4460 // Check if item was on the watched list and remove it
4461 const parent = this._getWatchedDir(directory);
4462 const wasTracked = parent.has(item);
4463 parent.remove(item);
4464
4465 // Fixes issue #1042 -> Relative paths were detected and added as symlinks
4466 // (https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L612),
4467 // but never removed from the map in case the path was deleted.
4468 // This leads to an incorrect state if the path was recreated:
4469 // https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L553
4470 if (this._symlinkPaths.has(fullPath)) {
4471 this._symlinkPaths.delete(fullPath);
4472 }
4473
4474 // If we wait for this file to be fully written, cancel the wait.
4475 let relPath = path;
4476 if (this.options.cwd) relPath = sysPath.relative(this.options.cwd, path);
4477 if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
4478 const event = this._pendingWrites.get(relPath).cancelWait();
4479 if (event === EV_ADD) return;
4480 }
4481
4482 // The Entry will either be a directory that just got removed
4483 // or a bogus entry to a file, in either case we have to remove it
4484 this._watched.delete(path);
4485 this._watched.delete(fullPath);
4486 const eventName = isDirectory ? EV_UNLINK_DIR : EV_UNLINK;
4487 if (wasTracked && !this._isIgnored(path)) this._emit(eventName, path);
4488
4489 // Avoid conflicts if we later create another file with the same name
4490 if (!this.options.useFsEvents) {
4491 this._closePath(path);
4492 }
4493}
4494
4495/**
4496 * Closes all watchers for a path
4497 * @param {Path} path
4498 */
4499_closePath(path) {
4500 this._closeFile(path);
4501 const dir = sysPath.dirname(path);
4502 this._getWatchedDir(dir).remove(sysPath.basename(path));
4503}
4504
4505/**
4506 * Closes only file-specific watchers
4507 * @param {Path} path
4508 */
4509_closeFile(path) {
4510 const closers = this._closers.get(path);
4511 if (!closers) return;
4512 closers.forEach(closer => closer());
4513 this._closers.delete(path);
4514}
4515
4516/**
4517 *
4518 * @param {Path} path
4519 * @param {Function} closer
4520 */
4521_addPathCloser(path, closer) {
4522 if (!closer) return;
4523 let list = this._closers.get(path);
4524 if (!list) {
4525 list = [];
4526 this._closers.set(path, list);
4527 }
4528 list.push(closer);
4529}
4530
4531_readdirp(root, opts) {
4532 if (this.closed) return;
4533 const options = {type: EV_ALL, alwaysStat: true, lstat: true, ...opts};
4534 let stream = readdirp(root, options);
4535 this._streams.add(stream);
4536 stream.once(STR_CLOSE, () => {
4537 stream = undefined;
4538 });
4539 stream.once(STR_END, () => {
4540 if (stream) {
4541 this._streams.delete(stream);
4542 stream = undefined;
4543 }
4544 });
4545 return stream;
4546}
4547
4548}
4549
4550// Export FSWatcher class
4551chokidar.FSWatcher = FSWatcher;
4552
4553/**
4554 * Instantiates watcher with paths to be tracked.
4555 * @param {String|Array<String>} paths file/directory paths and/or globs
4556 * @param {Object=} options chokidar opts
4557 * @returns an instance of FSWatcher for chaining.
4558 */
4559const watch = (paths, options) => {
4560 const watcher = new FSWatcher(options);
4561 watcher.add(paths);
4562 return watcher;
4563};
4564
4565chokidar.watch = watch;
4566
4567exports.chokidar = chokidar;
4568//# sourceMappingURL=index.js.map