UNPKG

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