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

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

Update repo after prototype presentation

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