source: imaps-frontend/node_modules/rollup/dist/shared/index.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

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