feat: docker compose maybe
This commit is contained in:
		
							
								
								
									
										21
									
								
								node_modules/chokidar/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								node_modules/chokidar/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
The MIT License (MIT)
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2012-2019 Paul Miller (https://paulmillr.com), Elan Shanker
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the “Software”), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in
 | 
			
		||||
all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
THE SOFTWARE.
 | 
			
		||||
							
								
								
									
										308
									
								
								node_modules/chokidar/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								node_modules/chokidar/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,308 @@
 | 
			
		||||
# Chokidar [](https://github.com/paulmillr/chokidar) [](https://github.com/paulmillr/chokidar)
 | 
			
		||||
 | 
			
		||||
> Minimal and efficient cross-platform file watching library
 | 
			
		||||
 | 
			
		||||
[](https://www.npmjs.com/package/chokidar)
 | 
			
		||||
 | 
			
		||||
## Why?
 | 
			
		||||
 | 
			
		||||
Node.js `fs.watch`:
 | 
			
		||||
 | 
			
		||||
* Doesn't report filenames on MacOS.
 | 
			
		||||
* Doesn't report events at all when using editors like Sublime on MacOS.
 | 
			
		||||
* Often reports events twice.
 | 
			
		||||
* Emits most changes as `rename`.
 | 
			
		||||
* Does not provide an easy way to recursively watch file trees.
 | 
			
		||||
* Does not support recursive watching on Linux.
 | 
			
		||||
 | 
			
		||||
Node.js `fs.watchFile`:
 | 
			
		||||
 | 
			
		||||
* Almost as bad at event handling.
 | 
			
		||||
* Also does not provide any recursive watching.
 | 
			
		||||
* Results in high CPU utilization.
 | 
			
		||||
 | 
			
		||||
Chokidar resolves these problems.
 | 
			
		||||
 | 
			
		||||
Initially made for **[Brunch](https://brunch.io/)** (an ultra-swift web app build tool), it is now used in
 | 
			
		||||
[Microsoft's Visual Studio Code](https://github.com/microsoft/vscode),
 | 
			
		||||
[gulp](https://github.com/gulpjs/gulp/),
 | 
			
		||||
[karma](https://karma-runner.github.io/),
 | 
			
		||||
[PM2](https://github.com/Unitech/PM2),
 | 
			
		||||
[browserify](http://browserify.org/),
 | 
			
		||||
[webpack](https://webpack.github.io/),
 | 
			
		||||
[BrowserSync](https://www.browsersync.io/),
 | 
			
		||||
and [many others](https://www.npmjs.com/browse/depended/chokidar).
 | 
			
		||||
It has proven itself in production environments.
 | 
			
		||||
 | 
			
		||||
Version 3 is out! Check out our blog post about it: [Chokidar 3: How to save 32TB of traffic every week](https://paulmillr.com/posts/chokidar-3-save-32tb-of-traffic/)
 | 
			
		||||
 | 
			
		||||
## How?
 | 
			
		||||
 | 
			
		||||
Chokidar does still rely on the Node.js core `fs` module, but when using
 | 
			
		||||
`fs.watch` and `fs.watchFile` for watching, it normalizes the events it
 | 
			
		||||
receives, often checking for truth by getting file stats and/or dir contents.
 | 
			
		||||
 | 
			
		||||
On MacOS, chokidar by default uses a native extension exposing the Darwin
 | 
			
		||||
`FSEvents` API. This provides very efficient recursive watching compared with
 | 
			
		||||
implementations like `kqueue` available on most \*nix platforms. Chokidar still
 | 
			
		||||
does have to do some work to normalize the events received that way as well.
 | 
			
		||||
 | 
			
		||||
On most other platforms, the `fs.watch`-based implementation is the default, which
 | 
			
		||||
avoids polling and keeps CPU usage down. Be advised that chokidar will initiate
 | 
			
		||||
watchers recursively for everything within scope of the paths that have been
 | 
			
		||||
specified, so be judicious about not wasting system resources by watching much
 | 
			
		||||
more than needed.
 | 
			
		||||
 | 
			
		||||
## Getting started
 | 
			
		||||
 | 
			
		||||
Install with npm:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
npm install chokidar
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then `require` and use it in your code:
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
const chokidar = require('chokidar');
 | 
			
		||||
 | 
			
		||||
// One-liner for current directory
 | 
			
		||||
chokidar.watch('.').on('all', (event, path) => {
 | 
			
		||||
  console.log(event, path);
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## API
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
// Example of a more typical implementation structure
 | 
			
		||||
 | 
			
		||||
// Initialize watcher.
 | 
			
		||||
const watcher = chokidar.watch('file, dir, glob, or array', {
 | 
			
		||||
  ignored: /(^|[\/\\])\../, // ignore dotfiles
 | 
			
		||||
  persistent: true
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Something to use when events are received.
 | 
			
		||||
const log = console.log.bind(console);
 | 
			
		||||
// Add event listeners.
 | 
			
		||||
watcher
 | 
			
		||||
  .on('add', path => log(`File ${path} has been added`))
 | 
			
		||||
  .on('change', path => log(`File ${path} has been changed`))
 | 
			
		||||
  .on('unlink', path => log(`File ${path} has been removed`));
 | 
			
		||||
 | 
			
		||||
// More possible events.
 | 
			
		||||
watcher
 | 
			
		||||
  .on('addDir', path => log(`Directory ${path} has been added`))
 | 
			
		||||
  .on('unlinkDir', path => log(`Directory ${path} has been removed`))
 | 
			
		||||
  .on('error', error => log(`Watcher error: ${error}`))
 | 
			
		||||
  .on('ready', () => log('Initial scan complete. Ready for changes'))
 | 
			
		||||
  .on('raw', (event, path, details) => { // internal
 | 
			
		||||
    log('Raw event info:', event, path, details);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
// 'add', 'addDir' and 'change' events also receive stat() results as second
 | 
			
		||||
// argument when available: https://nodejs.org/api/fs.html#fs_class_fs_stats
 | 
			
		||||
watcher.on('change', (path, stats) => {
 | 
			
		||||
  if (stats) console.log(`File ${path} changed size to ${stats.size}`);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Watch new files.
 | 
			
		||||
watcher.add('new-file');
 | 
			
		||||
watcher.add(['new-file-2', 'new-file-3', '**/other-file*']);
 | 
			
		||||
 | 
			
		||||
// Get list of actual paths being watched on the filesystem
 | 
			
		||||
var watchedPaths = watcher.getWatched();
 | 
			
		||||
 | 
			
		||||
// Un-watch some files.
 | 
			
		||||
await watcher.unwatch('new-file*');
 | 
			
		||||
 | 
			
		||||
// Stop watching.
 | 
			
		||||
// The method is async!
 | 
			
		||||
watcher.close().then(() => console.log('closed'));
 | 
			
		||||
 | 
			
		||||
// Full list of options. See below for descriptions.
 | 
			
		||||
// Do not use this example!
 | 
			
		||||
chokidar.watch('file', {
 | 
			
		||||
  persistent: true,
 | 
			
		||||
 | 
			
		||||
  ignored: '*.txt',
 | 
			
		||||
  ignoreInitial: false,
 | 
			
		||||
  followSymlinks: true,
 | 
			
		||||
  cwd: '.',
 | 
			
		||||
  disableGlobbing: false,
 | 
			
		||||
 | 
			
		||||
  usePolling: false,
 | 
			
		||||
  interval: 100,
 | 
			
		||||
  binaryInterval: 300,
 | 
			
		||||
  alwaysStat: false,
 | 
			
		||||
  depth: 99,
 | 
			
		||||
  awaitWriteFinish: {
 | 
			
		||||
    stabilityThreshold: 2000,
 | 
			
		||||
    pollInterval: 100
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  ignorePermissionErrors: false,
 | 
			
		||||
  atomic: true // or a custom 'atomicity delay', in milliseconds (default 100)
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
`chokidar.watch(paths, [options])`
 | 
			
		||||
 | 
			
		||||
* `paths` (string or array of strings). Paths to files, dirs to be watched
 | 
			
		||||
recursively, or glob patterns.
 | 
			
		||||
    - Note: globs must not contain windows separators (`\`),
 | 
			
		||||
    because that's how they work by the standard —
 | 
			
		||||
    you'll need to replace them with forward slashes (`/`).
 | 
			
		||||
    - Note 2: for additional glob documentation, check out low-level
 | 
			
		||||
    library: [picomatch](https://github.com/micromatch/picomatch).
 | 
			
		||||
* `options` (object) Options object as defined below:
 | 
			
		||||
 | 
			
		||||
#### Persistence
 | 
			
		||||
 | 
			
		||||
* `persistent` (default: `true`). Indicates whether the process
 | 
			
		||||
should continue to run as long as files are being watched. If set to
 | 
			
		||||
`false` when using `fsevents` to watch, no more events will be emitted
 | 
			
		||||
after `ready`, even if the process continues to run.
 | 
			
		||||
 | 
			
		||||
#### Path filtering
 | 
			
		||||
 | 
			
		||||
* `ignored` ([anymatch](https://github.com/es128/anymatch)-compatible definition)
 | 
			
		||||
Defines files/paths to be ignored. The whole relative or absolute path is
 | 
			
		||||
tested, not just filename. If a function with two arguments is provided, it
 | 
			
		||||
gets called twice per path - once with a single argument (the path), second
 | 
			
		||||
time with two arguments (the path and the
 | 
			
		||||
[`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats)
 | 
			
		||||
object of that path).
 | 
			
		||||
* `ignoreInitial` (default: `false`). If set to `false` then `add`/`addDir` events are also emitted for matching paths while
 | 
			
		||||
instantiating the watching as chokidar discovers these file paths (before the `ready` event).
 | 
			
		||||
* `followSymlinks` (default: `true`). When `false`, only the
 | 
			
		||||
symlinks themselves will be watched for changes instead of following
 | 
			
		||||
the link references and bubbling events through the link's path.
 | 
			
		||||
* `cwd` (no default). The base directory from which watch `paths` are to be
 | 
			
		||||
derived. Paths emitted with events will be relative to this.
 | 
			
		||||
* `disableGlobbing` (default: `false`). If set to `true` then the strings passed to `.watch()` and `.add()` are treated as
 | 
			
		||||
literal path names, even if they look like globs.
 | 
			
		||||
 | 
			
		||||
#### Performance
 | 
			
		||||
 | 
			
		||||
* `usePolling` (default: `false`).
 | 
			
		||||
Whether to use fs.watchFile (backed by polling), or fs.watch. If polling
 | 
			
		||||
leads to high CPU utilization, consider setting this to `false`. It is
 | 
			
		||||
typically necessary to **set this to `true` to successfully watch files over
 | 
			
		||||
a network**, and it may be necessary to successfully watch files in other
 | 
			
		||||
non-standard situations. Setting to `true` explicitly on MacOS overrides the
 | 
			
		||||
`useFsEvents` default. You may also set the CHOKIDAR_USEPOLLING env variable
 | 
			
		||||
to true (1) or false (0) in order to override this option.
 | 
			
		||||
* _Polling-specific settings_ (effective when `usePolling: true`)
 | 
			
		||||
  * `interval` (default: `100`). Interval of file system polling, in milliseconds. You may also
 | 
			
		||||
    set the CHOKIDAR_INTERVAL env variable to override this option.
 | 
			
		||||
  * `binaryInterval` (default: `300`). Interval of file system
 | 
			
		||||
  polling for binary files.
 | 
			
		||||
  ([see list of binary extensions](https://github.com/sindresorhus/binary-extensions/blob/master/binary-extensions.json))
 | 
			
		||||
* `useFsEvents` (default: `true` on MacOS). Whether to use the
 | 
			
		||||
`fsevents` watching interface if available. When set to `true` explicitly
 | 
			
		||||
and `fsevents` is available this supercedes the `usePolling` setting. When
 | 
			
		||||
set to `false` on MacOS, `usePolling: true` becomes the default.
 | 
			
		||||
* `alwaysStat` (default: `false`). If relying upon the
 | 
			
		||||
[`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats)
 | 
			
		||||
object that may get passed with `add`, `addDir`, and `change` events, set
 | 
			
		||||
this to `true` to ensure it is provided even in cases where it wasn't
 | 
			
		||||
already available from the underlying watch events.
 | 
			
		||||
* `depth` (default: `undefined`). If set, limits how many levels of
 | 
			
		||||
subdirectories will be traversed.
 | 
			
		||||
* `awaitWriteFinish` (default: `false`).
 | 
			
		||||
By default, the `add` event will fire when a file first appears on disk, before
 | 
			
		||||
the entire file has been written. Furthermore, in some cases some `change`
 | 
			
		||||
events will be emitted while the file is being written. In some cases,
 | 
			
		||||
especially when watching for large files there will be a need to wait for the
 | 
			
		||||
write operation to finish before responding to a file creation or modification.
 | 
			
		||||
Setting `awaitWriteFinish` to `true` (or a truthy value) will poll file size,
 | 
			
		||||
holding its `add` and `change` events until the size does not change for a
 | 
			
		||||
configurable amount of time. The appropriate duration setting is heavily
 | 
			
		||||
dependent on the OS and hardware. For accurate detection this parameter should
 | 
			
		||||
be relatively high, making file watching much less responsive.
 | 
			
		||||
Use with caution.
 | 
			
		||||
  * *`options.awaitWriteFinish` can be set to an object in order to adjust
 | 
			
		||||
  timing params:*
 | 
			
		||||
  * `awaitWriteFinish.stabilityThreshold` (default: 2000). Amount of time in
 | 
			
		||||
  milliseconds for a file size to remain constant before emitting its event.
 | 
			
		||||
  * `awaitWriteFinish.pollInterval` (default: 100). File size polling interval, in milliseconds.
 | 
			
		||||
 | 
			
		||||
#### Errors
 | 
			
		||||
 | 
			
		||||
* `ignorePermissionErrors` (default: `false`). Indicates whether to watch files
 | 
			
		||||
that don't have read permissions if possible. If watching fails due to `EPERM`
 | 
			
		||||
or `EACCES` with this set to `true`, the errors will be suppressed silently.
 | 
			
		||||
* `atomic` (default: `true` if `useFsEvents` and `usePolling` are `false`).
 | 
			
		||||
Automatically filters out artifacts that occur when using editors that use
 | 
			
		||||
"atomic writes" instead of writing directly to the source file. If a file is
 | 
			
		||||
re-added within 100 ms of being deleted, Chokidar emits a `change` event
 | 
			
		||||
rather than `unlink` then `add`. If the default of 100 ms does not work well
 | 
			
		||||
for you, you can override it by setting `atomic` to a custom value, in
 | 
			
		||||
milliseconds.
 | 
			
		||||
 | 
			
		||||
### Methods & Events
 | 
			
		||||
 | 
			
		||||
`chokidar.watch()` produces an instance of `FSWatcher`. Methods of `FSWatcher`:
 | 
			
		||||
 | 
			
		||||
* `.add(path / paths)`: Add files, directories, or glob patterns for tracking.
 | 
			
		||||
Takes an array of strings or just one string.
 | 
			
		||||
* `.on(event, callback)`: Listen for an FS event.
 | 
			
		||||
Available events: `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `ready`,
 | 
			
		||||
`raw`, `error`.
 | 
			
		||||
Additionally `all` is available which gets emitted with the underlying event
 | 
			
		||||
name and path for every event other than `ready`, `raw`, and `error`.  `raw` is internal, use it carefully.
 | 
			
		||||
* `.unwatch(path / paths)`: Stop watching files, directories, or glob patterns.
 | 
			
		||||
Takes an array of strings or just one string.
 | 
			
		||||
* `.close()`: **async** Removes all listeners from watched files. Asynchronous, returns Promise. Use with `await` to ensure bugs don't happen.
 | 
			
		||||
* `.getWatched()`: Returns an object representing all the paths on the file
 | 
			
		||||
system being watched by this `FSWatcher` instance. The object's keys are all the
 | 
			
		||||
directories (using absolute paths unless the `cwd` option was used), and the
 | 
			
		||||
values are arrays of the names of the items contained in each directory.
 | 
			
		||||
 | 
			
		||||
## CLI
 | 
			
		||||
 | 
			
		||||
If you need a CLI interface for your file watching, check out
 | 
			
		||||
[chokidar-cli](https://github.com/open-cli-tools/chokidar-cli), allowing you to
 | 
			
		||||
execute a command on each change, or get a stdio stream of change events.
 | 
			
		||||
 | 
			
		||||
## Install Troubleshooting
 | 
			
		||||
 | 
			
		||||
* `npm WARN optional dep failed, continuing fsevents@n.n.n`
 | 
			
		||||
  * This message is normal part of how `npm` handles optional dependencies and is
 | 
			
		||||
    not indicative of a problem. Even if accompanied by other related error messages,
 | 
			
		||||
    Chokidar should function properly.
 | 
			
		||||
 | 
			
		||||
* `TypeError: fsevents is not a constructor`
 | 
			
		||||
  * Update chokidar by doing `rm -rf node_modules package-lock.json yarn.lock && npm install`, or update your dependency that uses chokidar.
 | 
			
		||||
 | 
			
		||||
* Chokidar is producing `ENOSP` error on Linux, like this:
 | 
			
		||||
  * `bash: cannot set terminal process group (-1): Inappropriate ioctl for device bash: no job control in this shell`
 | 
			
		||||
  `Error: watch /home/ ENOSPC`
 | 
			
		||||
  * This means Chokidar ran out of file handles and you'll need to increase their count by executing the following command in Terminal:
 | 
			
		||||
  `echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p`
 | 
			
		||||
 | 
			
		||||
## Changelog
 | 
			
		||||
 | 
			
		||||
For more detailed changelog, see [`full_changelog.md`](.github/full_changelog.md).
 | 
			
		||||
- **v3.5 (Jan 6, 2021):** Support for ARM Macs with Apple Silicon. Fixes for deleted symlinks.
 | 
			
		||||
- **v3.4 (Apr 26, 2020):** Support for directory-based symlinks. Fixes for macos file replacement.
 | 
			
		||||
- **v3.3 (Nov 2, 2019):** `FSWatcher#close()` method became async. That fixes IO race conditions related to close method.
 | 
			
		||||
- **v3.2 (Oct 1, 2019):** Improve Linux RAM usage by 50%. Race condition fixes. Windows glob fixes. Improve stability by using tight range of dependency versions.
 | 
			
		||||
- **v3.1 (Sep 16, 2019):** dotfiles are no longer filtered out by default. Use `ignored` option if needed. Improve initial Linux scan time by 50%.
 | 
			
		||||
- **v3 (Apr 30, 2019):** massive CPU & RAM consumption improvements; reduces deps / package size by a factor of 17x and bumps Node.js requirement to v8.16 and higher.
 | 
			
		||||
- **v2 (Dec 29, 2017):** Globs are now posix-style-only; without windows support. Tons of bugfixes.
 | 
			
		||||
- **v1 (Apr 7, 2015):** Glob support, symlink support, tons of bugfixes. Node 0.8+ is supported
 | 
			
		||||
- **v0.1 (Apr 20, 2012):** Initial release, extracted from [Brunch](https://github.com/brunch/brunch/blob/9847a065aea300da99bd0753f90354cde9de1261/src/helpers.coffee#L66)
 | 
			
		||||
 | 
			
		||||
## Also
 | 
			
		||||
 | 
			
		||||
Why was chokidar named this way? What's the meaning behind it?
 | 
			
		||||
 | 
			
		||||
>Chowkidar is a transliteration of a Hindi word meaning 'watchman, gatekeeper', चौकीदार. This ultimately comes from Sanskrit _ चतुष्क_ (crossway, quadrangle, consisting-of-four).
 | 
			
		||||
 | 
			
		||||
## License
 | 
			
		||||
 | 
			
		||||
MIT (c) Paul Miller (<https://paulmillr.com>), see [LICENSE](LICENSE) file.
 | 
			
		||||
							
								
								
									
										973
									
								
								node_modules/chokidar/index.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										973
									
								
								node_modules/chokidar/index.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,973 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
const { EventEmitter } = require('events');
 | 
			
		||||
const fs = require('fs');
 | 
			
		||||
const sysPath = require('path');
 | 
			
		||||
const { promisify } = require('util');
 | 
			
		||||
const readdirp = require('readdirp');
 | 
			
		||||
const anymatch = require('anymatch').default;
 | 
			
		||||
const globParent = require('glob-parent');
 | 
			
		||||
const isGlob = require('is-glob');
 | 
			
		||||
const braces = require('braces');
 | 
			
		||||
const normalizePath = require('normalize-path');
 | 
			
		||||
 | 
			
		||||
const NodeFsHandler = require('./lib/nodefs-handler');
 | 
			
		||||
const FsEventsHandler = require('./lib/fsevents-handler');
 | 
			
		||||
const {
 | 
			
		||||
  EV_ALL,
 | 
			
		||||
  EV_READY,
 | 
			
		||||
  EV_ADD,
 | 
			
		||||
  EV_CHANGE,
 | 
			
		||||
  EV_UNLINK,
 | 
			
		||||
  EV_ADD_DIR,
 | 
			
		||||
  EV_UNLINK_DIR,
 | 
			
		||||
  EV_RAW,
 | 
			
		||||
  EV_ERROR,
 | 
			
		||||
 | 
			
		||||
  STR_CLOSE,
 | 
			
		||||
  STR_END,
 | 
			
		||||
 | 
			
		||||
  BACK_SLASH_RE,
 | 
			
		||||
  DOUBLE_SLASH_RE,
 | 
			
		||||
  SLASH_OR_BACK_SLASH_RE,
 | 
			
		||||
  DOT_RE,
 | 
			
		||||
  REPLACER_RE,
 | 
			
		||||
 | 
			
		||||
  SLASH,
 | 
			
		||||
  SLASH_SLASH,
 | 
			
		||||
  BRACE_START,
 | 
			
		||||
  BANG,
 | 
			
		||||
  ONE_DOT,
 | 
			
		||||
  TWO_DOTS,
 | 
			
		||||
  GLOBSTAR,
 | 
			
		||||
  SLASH_GLOBSTAR,
 | 
			
		||||
  ANYMATCH_OPTS,
 | 
			
		||||
  STRING_TYPE,
 | 
			
		||||
  FUNCTION_TYPE,
 | 
			
		||||
  EMPTY_STR,
 | 
			
		||||
  EMPTY_FN,
 | 
			
		||||
 | 
			
		||||
  isWindows,
 | 
			
		||||
  isMacos,
 | 
			
		||||
  isIBMi
 | 
			
		||||
} = require('./lib/constants');
 | 
			
		||||
 | 
			
		||||
const stat = promisify(fs.stat);
 | 
			
		||||
const readdir = promisify(fs.readdir);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef {String} Path
 | 
			
		||||
 * @typedef {'all'|'add'|'addDir'|'change'|'unlink'|'unlinkDir'|'raw'|'error'|'ready'} EventName
 | 
			
		||||
 * @typedef {'readdir'|'watch'|'add'|'remove'|'change'} ThrottleType
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * @typedef {Object} WatchHelpers
 | 
			
		||||
 * @property {Boolean} followSymlinks
 | 
			
		||||
 * @property {'stat'|'lstat'} statMethod
 | 
			
		||||
 * @property {Path} path
 | 
			
		||||
 * @property {Path} watchPath
 | 
			
		||||
 * @property {Function} entryPath
 | 
			
		||||
 * @property {Boolean} hasGlob
 | 
			
		||||
 * @property {Object} globFilter
 | 
			
		||||
 * @property {Function} filterPath
 | 
			
		||||
 * @property {Function} filterDir
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
const arrify = (value = []) => Array.isArray(value) ? value : [value];
 | 
			
		||||
const flatten = (list, result = []) => {
 | 
			
		||||
  list.forEach(item => {
 | 
			
		||||
    if (Array.isArray(item)) {
 | 
			
		||||
      flatten(item, result);
 | 
			
		||||
    } else {
 | 
			
		||||
      result.push(item);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  return result;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const unifyPaths = (paths_) => {
 | 
			
		||||
  /**
 | 
			
		||||
   * @type {Array<String>}
 | 
			
		||||
   */
 | 
			
		||||
  const paths = flatten(arrify(paths_));
 | 
			
		||||
  if (!paths.every(p => typeof p === STRING_TYPE)) {
 | 
			
		||||
    throw new TypeError(`Non-string provided as watch path: ${paths}`);
 | 
			
		||||
  }
 | 
			
		||||
  return paths.map(normalizePathToUnix);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// If SLASH_SLASH occurs at the beginning of path, it is not replaced
 | 
			
		||||
//     because "//StoragePC/DrivePool/Movies" is a valid network path
 | 
			
		||||
const toUnix = (string) => {
 | 
			
		||||
  let str = string.replace(BACK_SLASH_RE, SLASH);
 | 
			
		||||
  let prepend = false;
 | 
			
		||||
  if (str.startsWith(SLASH_SLASH)) {
 | 
			
		||||
    prepend = true;
 | 
			
		||||
  }
 | 
			
		||||
  while (str.match(DOUBLE_SLASH_RE)) {
 | 
			
		||||
    str = str.replace(DOUBLE_SLASH_RE, SLASH);
 | 
			
		||||
  }
 | 
			
		||||
  if (prepend) {
 | 
			
		||||
    str = SLASH + str;
 | 
			
		||||
  }
 | 
			
		||||
  return str;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Our version of upath.normalize
 | 
			
		||||
// TODO: this is not equal to path-normalize module - investigate why
 | 
			
		||||
const normalizePathToUnix = (path) => toUnix(sysPath.normalize(toUnix(path)));
 | 
			
		||||
 | 
			
		||||
const normalizeIgnored = (cwd = EMPTY_STR) => (path) => {
 | 
			
		||||
  if (typeof path !== STRING_TYPE) return path;
 | 
			
		||||
  return normalizePathToUnix(sysPath.isAbsolute(path) ? path : sysPath.join(cwd, path));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getAbsolutePath = (path, cwd) => {
 | 
			
		||||
  if (sysPath.isAbsolute(path)) {
 | 
			
		||||
    return path;
 | 
			
		||||
  }
 | 
			
		||||
  if (path.startsWith(BANG)) {
 | 
			
		||||
    return BANG + sysPath.join(cwd, path.slice(1));
 | 
			
		||||
  }
 | 
			
		||||
  return sysPath.join(cwd, path);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const undef = (opts, key) => opts[key] === undefined;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Directory entry.
 | 
			
		||||
 * @property {Path} path
 | 
			
		||||
 * @property {Set<Path>} items
 | 
			
		||||
 */
 | 
			
		||||
class DirEntry {
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {Path} dir
 | 
			
		||||
   * @param {Function} removeWatcher
 | 
			
		||||
   */
 | 
			
		||||
  constructor(dir, removeWatcher) {
 | 
			
		||||
    this.path = dir;
 | 
			
		||||
    this._removeWatcher = removeWatcher;
 | 
			
		||||
    /** @type {Set<Path>} */
 | 
			
		||||
    this.items = new Set();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  add(item) {
 | 
			
		||||
    const {items} = this;
 | 
			
		||||
    if (!items) return;
 | 
			
		||||
    if (item !== ONE_DOT && item !== TWO_DOTS) items.add(item);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async remove(item) {
 | 
			
		||||
    const {items} = this;
 | 
			
		||||
    if (!items) return;
 | 
			
		||||
    items.delete(item);
 | 
			
		||||
    if (items.size > 0) return;
 | 
			
		||||
 | 
			
		||||
    const dir = this.path;
 | 
			
		||||
    try {
 | 
			
		||||
      await readdir(dir);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      if (this._removeWatcher) {
 | 
			
		||||
        this._removeWatcher(sysPath.dirname(dir), sysPath.basename(dir));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  has(item) {
 | 
			
		||||
    const {items} = this;
 | 
			
		||||
    if (!items) return;
 | 
			
		||||
    return items.has(item);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @returns {Array<String>}
 | 
			
		||||
   */
 | 
			
		||||
  getChildren() {
 | 
			
		||||
    const {items} = this;
 | 
			
		||||
    if (!items) return;
 | 
			
		||||
    return [...items.values()];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  dispose() {
 | 
			
		||||
    this.items.clear();
 | 
			
		||||
    delete this.path;
 | 
			
		||||
    delete this._removeWatcher;
 | 
			
		||||
    delete this.items;
 | 
			
		||||
    Object.freeze(this);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const STAT_METHOD_F = 'stat';
 | 
			
		||||
const STAT_METHOD_L = 'lstat';
 | 
			
		||||
class WatchHelper {
 | 
			
		||||
  constructor(path, watchPath, follow, fsw) {
 | 
			
		||||
    this.fsw = fsw;
 | 
			
		||||
    this.path = path = path.replace(REPLACER_RE, EMPTY_STR);
 | 
			
		||||
    this.watchPath = watchPath;
 | 
			
		||||
    this.fullWatchPath = sysPath.resolve(watchPath);
 | 
			
		||||
    this.hasGlob = watchPath !== path;
 | 
			
		||||
    /** @type {object|boolean} */
 | 
			
		||||
    if (path === EMPTY_STR) this.hasGlob = false;
 | 
			
		||||
    this.globSymlink = this.hasGlob && follow ? undefined : false;
 | 
			
		||||
    this.globFilter = this.hasGlob ? anymatch(path, undefined, ANYMATCH_OPTS) : false;
 | 
			
		||||
    this.dirParts = this.getDirParts(path);
 | 
			
		||||
    this.dirParts.forEach((parts) => {
 | 
			
		||||
      if (parts.length > 1) parts.pop();
 | 
			
		||||
    });
 | 
			
		||||
    this.followSymlinks = follow;
 | 
			
		||||
    this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  checkGlobSymlink(entry) {
 | 
			
		||||
    // only need to resolve once
 | 
			
		||||
    // first entry should always have entry.parentDir === EMPTY_STR
 | 
			
		||||
    if (this.globSymlink === undefined) {
 | 
			
		||||
      this.globSymlink = entry.fullParentDir === this.fullWatchPath ?
 | 
			
		||||
        false : {realPath: entry.fullParentDir, linkPath: this.fullWatchPath};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this.globSymlink) {
 | 
			
		||||
      return entry.fullPath.replace(this.globSymlink.realPath, this.globSymlink.linkPath);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return entry.fullPath;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  entryPath(entry) {
 | 
			
		||||
    return sysPath.join(this.watchPath,
 | 
			
		||||
      sysPath.relative(this.watchPath, this.checkGlobSymlink(entry))
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  filterPath(entry) {
 | 
			
		||||
    const {stats} = entry;
 | 
			
		||||
    if (stats && stats.isSymbolicLink()) return this.filterDir(entry);
 | 
			
		||||
    const resolvedPath = this.entryPath(entry);
 | 
			
		||||
    const matchesGlob = this.hasGlob && typeof this.globFilter === FUNCTION_TYPE ?
 | 
			
		||||
      this.globFilter(resolvedPath) : true;
 | 
			
		||||
    return matchesGlob &&
 | 
			
		||||
      this.fsw._isntIgnored(resolvedPath, stats) &&
 | 
			
		||||
      this.fsw._hasReadPermissions(stats);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getDirParts(path) {
 | 
			
		||||
    if (!this.hasGlob) return [];
 | 
			
		||||
    const parts = [];
 | 
			
		||||
    const expandedPath = path.includes(BRACE_START) ? braces.expand(path) : [path];
 | 
			
		||||
    expandedPath.forEach((path) => {
 | 
			
		||||
      parts.push(sysPath.relative(this.watchPath, path).split(SLASH_OR_BACK_SLASH_RE));
 | 
			
		||||
    });
 | 
			
		||||
    return parts;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  filterDir(entry) {
 | 
			
		||||
    if (this.hasGlob) {
 | 
			
		||||
      const entryParts = this.getDirParts(this.checkGlobSymlink(entry));
 | 
			
		||||
      let globstar = false;
 | 
			
		||||
      this.unmatchedGlob = !this.dirParts.some((parts) => {
 | 
			
		||||
        return parts.every((part, i) => {
 | 
			
		||||
          if (part === GLOBSTAR) globstar = true;
 | 
			
		||||
          return globstar || !entryParts[0][i] || anymatch(part, entryParts[0][i], ANYMATCH_OPTS);
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    return !this.unmatchedGlob && this.fsw._isntIgnored(this.entryPath(entry), entry.stats);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Watches files & directories for changes. Emitted events:
 | 
			
		||||
 * `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error`
 | 
			
		||||
 *
 | 
			
		||||
 *     new FSWatcher()
 | 
			
		||||
 *       .add(directories)
 | 
			
		||||
 *       .on('add', path => log('File', path, 'was added'))
 | 
			
		||||
 */
 | 
			
		||||
class FSWatcher extends EventEmitter {
 | 
			
		||||
// Not indenting methods for history sake; for now.
 | 
			
		||||
constructor(_opts) {
 | 
			
		||||
  super();
 | 
			
		||||
 | 
			
		||||
  const opts = {};
 | 
			
		||||
  if (_opts) Object.assign(opts, _opts); // for frozen objects
 | 
			
		||||
 | 
			
		||||
  /** @type {Map<String, DirEntry>} */
 | 
			
		||||
  this._watched = new Map();
 | 
			
		||||
  /** @type {Map<String, Array>} */
 | 
			
		||||
  this._closers = new Map();
 | 
			
		||||
  /** @type {Set<String>} */
 | 
			
		||||
  this._ignoredPaths = new Set();
 | 
			
		||||
 | 
			
		||||
  /** @type {Map<ThrottleType, Map>} */
 | 
			
		||||
  this._throttled = new Map();
 | 
			
		||||
 | 
			
		||||
  /** @type {Map<Path, String|Boolean>} */
 | 
			
		||||
  this._symlinkPaths = new Map();
 | 
			
		||||
 | 
			
		||||
  this._streams = new Set();
 | 
			
		||||
  this.closed = false;
 | 
			
		||||
 | 
			
		||||
  // Set up default options.
 | 
			
		||||
  if (undef(opts, 'persistent')) opts.persistent = true;
 | 
			
		||||
  if (undef(opts, 'ignoreInitial')) opts.ignoreInitial = false;
 | 
			
		||||
  if (undef(opts, 'ignorePermissionErrors')) opts.ignorePermissionErrors = false;
 | 
			
		||||
  if (undef(opts, 'interval')) opts.interval = 100;
 | 
			
		||||
  if (undef(opts, 'binaryInterval')) opts.binaryInterval = 300;
 | 
			
		||||
  if (undef(opts, 'disableGlobbing')) opts.disableGlobbing = false;
 | 
			
		||||
  opts.enableBinaryInterval = opts.binaryInterval !== opts.interval;
 | 
			
		||||
 | 
			
		||||
  // Enable fsevents on OS X when polling isn't explicitly enabled.
 | 
			
		||||
  if (undef(opts, 'useFsEvents')) opts.useFsEvents = !opts.usePolling;
 | 
			
		||||
 | 
			
		||||
  // If we can't use fsevents, ensure the options reflect it's disabled.
 | 
			
		||||
  const canUseFsEvents = FsEventsHandler.canUse();
 | 
			
		||||
  if (!canUseFsEvents) opts.useFsEvents = false;
 | 
			
		||||
 | 
			
		||||
  // Use polling on Mac if not using fsevents.
 | 
			
		||||
  // Other platforms use non-polling fs_watch.
 | 
			
		||||
  if (undef(opts, 'usePolling') && !opts.useFsEvents) {
 | 
			
		||||
    opts.usePolling = isMacos;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Always default to polling on IBM i because fs.watch() is not available on IBM i.
 | 
			
		||||
  if(isIBMi) {
 | 
			
		||||
    opts.usePolling = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Global override (useful for end-developers that need to force polling for all
 | 
			
		||||
  // instances of chokidar, regardless of usage/dependency depth)
 | 
			
		||||
  const envPoll = process.env.CHOKIDAR_USEPOLLING;
 | 
			
		||||
  if (envPoll !== undefined) {
 | 
			
		||||
    const envLower = envPoll.toLowerCase();
 | 
			
		||||
 | 
			
		||||
    if (envLower === 'false' || envLower === '0') {
 | 
			
		||||
      opts.usePolling = false;
 | 
			
		||||
    } else if (envLower === 'true' || envLower === '1') {
 | 
			
		||||
      opts.usePolling = true;
 | 
			
		||||
    } else {
 | 
			
		||||
      opts.usePolling = !!envLower;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  const envInterval = process.env.CHOKIDAR_INTERVAL;
 | 
			
		||||
  if (envInterval) {
 | 
			
		||||
    opts.interval = Number.parseInt(envInterval, 10);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Editor atomic write normalization enabled by default with fs.watch
 | 
			
		||||
  if (undef(opts, 'atomic')) opts.atomic = !opts.usePolling && !opts.useFsEvents;
 | 
			
		||||
  if (opts.atomic) this._pendingUnlinks = new Map();
 | 
			
		||||
 | 
			
		||||
  if (undef(opts, 'followSymlinks')) opts.followSymlinks = true;
 | 
			
		||||
 | 
			
		||||
  if (undef(opts, 'awaitWriteFinish')) opts.awaitWriteFinish = false;
 | 
			
		||||
  if (opts.awaitWriteFinish === true) opts.awaitWriteFinish = {};
 | 
			
		||||
  const awf = opts.awaitWriteFinish;
 | 
			
		||||
  if (awf) {
 | 
			
		||||
    if (!awf.stabilityThreshold) awf.stabilityThreshold = 2000;
 | 
			
		||||
    if (!awf.pollInterval) awf.pollInterval = 100;
 | 
			
		||||
    this._pendingWrites = new Map();
 | 
			
		||||
  }
 | 
			
		||||
  if (opts.ignored) opts.ignored = arrify(opts.ignored);
 | 
			
		||||
 | 
			
		||||
  let readyCalls = 0;
 | 
			
		||||
  this._emitReady = () => {
 | 
			
		||||
    readyCalls++;
 | 
			
		||||
    if (readyCalls >= this._readyCount) {
 | 
			
		||||
      this._emitReady = EMPTY_FN;
 | 
			
		||||
      this._readyEmitted = true;
 | 
			
		||||
      // use process.nextTick to allow time for listener to be bound
 | 
			
		||||
      process.nextTick(() => this.emit(EV_READY));
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  this._emitRaw = (...args) => this.emit(EV_RAW, ...args);
 | 
			
		||||
  this._readyEmitted = false;
 | 
			
		||||
  this.options = opts;
 | 
			
		||||
 | 
			
		||||
  // Initialize with proper watcher.
 | 
			
		||||
  if (opts.useFsEvents) {
 | 
			
		||||
    this._fsEventsHandler = new FsEventsHandler(this);
 | 
			
		||||
  } else {
 | 
			
		||||
    this._nodeFsHandler = new NodeFsHandler(this);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // You’re frozen when your heart’s not open.
 | 
			
		||||
  Object.freeze(opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Public methods
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Adds paths to be watched on an existing FSWatcher instance
 | 
			
		||||
 * @param {Path|Array<Path>} paths_
 | 
			
		||||
 * @param {String=} _origAdd private; for handling non-existent paths to be watched
 | 
			
		||||
 * @param {Boolean=} _internal private; indicates a non-user add
 | 
			
		||||
 * @returns {FSWatcher} for chaining
 | 
			
		||||
 */
 | 
			
		||||
add(paths_, _origAdd, _internal) {
 | 
			
		||||
  const {cwd, disableGlobbing} = this.options;
 | 
			
		||||
  this.closed = false;
 | 
			
		||||
  let paths = unifyPaths(paths_);
 | 
			
		||||
  if (cwd) {
 | 
			
		||||
    paths = paths.map((path) => {
 | 
			
		||||
      const absPath = getAbsolutePath(path, cwd);
 | 
			
		||||
 | 
			
		||||
      // Check `path` instead of `absPath` because the cwd portion can't be a glob
 | 
			
		||||
      if (disableGlobbing || !isGlob(path)) {
 | 
			
		||||
        return absPath;
 | 
			
		||||
      }
 | 
			
		||||
      return normalizePath(absPath);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // set aside negated glob strings
 | 
			
		||||
  paths = paths.filter((path) => {
 | 
			
		||||
    if (path.startsWith(BANG)) {
 | 
			
		||||
      this._ignoredPaths.add(path.slice(1));
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // if a path is being added that was previously ignored, stop ignoring it
 | 
			
		||||
    this._ignoredPaths.delete(path);
 | 
			
		||||
    this._ignoredPaths.delete(path + SLASH_GLOBSTAR);
 | 
			
		||||
 | 
			
		||||
    // reset the cached userIgnored anymatch fn
 | 
			
		||||
    // to make ignoredPaths changes effective
 | 
			
		||||
    this._userIgnored = undefined;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  if (this.options.useFsEvents && this._fsEventsHandler) {
 | 
			
		||||
    if (!this._readyCount) this._readyCount = paths.length;
 | 
			
		||||
    if (this.options.persistent) this._readyCount *= 2;
 | 
			
		||||
    paths.forEach((path) => this._fsEventsHandler._addToFsEvents(path));
 | 
			
		||||
  } else {
 | 
			
		||||
    if (!this._readyCount) this._readyCount = 0;
 | 
			
		||||
    this._readyCount += paths.length;
 | 
			
		||||
    Promise.all(
 | 
			
		||||
      paths.map(async path => {
 | 
			
		||||
        const res = await this._nodeFsHandler._addToNodeFs(path, !_internal, 0, 0, _origAdd);
 | 
			
		||||
        if (res) this._emitReady();
 | 
			
		||||
        return res;
 | 
			
		||||
      })
 | 
			
		||||
    ).then(results => {
 | 
			
		||||
      if (this.closed) return;
 | 
			
		||||
      results.filter(item => item).forEach(item => {
 | 
			
		||||
        this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item));
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Close watchers or start ignoring events from specified paths.
 | 
			
		||||
 * @param {Path|Array<Path>} paths_ - string or array of strings, file/directory paths and/or globs
 | 
			
		||||
 * @returns {FSWatcher} for chaining
 | 
			
		||||
*/
 | 
			
		||||
unwatch(paths_) {
 | 
			
		||||
  if (this.closed) return this;
 | 
			
		||||
  const paths = unifyPaths(paths_);
 | 
			
		||||
  const {cwd} = this.options;
 | 
			
		||||
 | 
			
		||||
  paths.forEach((path) => {
 | 
			
		||||
    // convert to absolute path unless relative path already matches
 | 
			
		||||
    if (!sysPath.isAbsolute(path) && !this._closers.has(path)) {
 | 
			
		||||
      if (cwd) path = sysPath.join(cwd, path);
 | 
			
		||||
      path = sysPath.resolve(path);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this._closePath(path);
 | 
			
		||||
 | 
			
		||||
    this._ignoredPaths.add(path);
 | 
			
		||||
    if (this._watched.has(path)) {
 | 
			
		||||
      this._ignoredPaths.add(path + SLASH_GLOBSTAR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // reset the cached userIgnored anymatch fn
 | 
			
		||||
    // to make ignoredPaths changes effective
 | 
			
		||||
    this._userIgnored = undefined;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Close watchers and remove all listeners from watched paths.
 | 
			
		||||
 * @returns {Promise<void>}.
 | 
			
		||||
*/
 | 
			
		||||
close() {
 | 
			
		||||
  if (this.closed) return this._closePromise;
 | 
			
		||||
  this.closed = true;
 | 
			
		||||
 | 
			
		||||
  // Memory management.
 | 
			
		||||
  this.removeAllListeners();
 | 
			
		||||
  const closers = [];
 | 
			
		||||
  this._closers.forEach(closerList => closerList.forEach(closer => {
 | 
			
		||||
    const promise = closer();
 | 
			
		||||
    if (promise instanceof Promise) closers.push(promise);
 | 
			
		||||
  }));
 | 
			
		||||
  this._streams.forEach(stream => stream.destroy());
 | 
			
		||||
  this._userIgnored = undefined;
 | 
			
		||||
  this._readyCount = 0;
 | 
			
		||||
  this._readyEmitted = false;
 | 
			
		||||
  this._watched.forEach(dirent => dirent.dispose());
 | 
			
		||||
  ['closers', 'watched', 'streams', 'symlinkPaths', 'throttled'].forEach(key => {
 | 
			
		||||
    this[`_${key}`].clear();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  this._closePromise = closers.length ? Promise.all(closers).then(() => undefined) : Promise.resolve();
 | 
			
		||||
  return this._closePromise;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Expose list of watched paths
 | 
			
		||||
 * @returns {Object} for chaining
 | 
			
		||||
*/
 | 
			
		||||
getWatched() {
 | 
			
		||||
  const watchList = {};
 | 
			
		||||
  this._watched.forEach((entry, dir) => {
 | 
			
		||||
    const key = this.options.cwd ? sysPath.relative(this.options.cwd, dir) : dir;
 | 
			
		||||
    watchList[key || ONE_DOT] = entry.getChildren().sort();
 | 
			
		||||
  });
 | 
			
		||||
  return watchList;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
emitWithAll(event, args) {
 | 
			
		||||
  this.emit(...args);
 | 
			
		||||
  if (event !== EV_ERROR) this.emit(EV_ALL, ...args);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Common helpers
 | 
			
		||||
// --------------
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Normalize and emit events.
 | 
			
		||||
 * Calling _emit DOES NOT MEAN emit() would be called!
 | 
			
		||||
 * @param {EventName} event Type of event
 | 
			
		||||
 * @param {Path} path File or directory path
 | 
			
		||||
 * @param {*=} val1 arguments to be passed with event
 | 
			
		||||
 * @param {*=} val2
 | 
			
		||||
 * @param {*=} val3
 | 
			
		||||
 * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
 | 
			
		||||
 */
 | 
			
		||||
async _emit(event, path, val1, val2, val3) {
 | 
			
		||||
  if (this.closed) return;
 | 
			
		||||
 | 
			
		||||
  const opts = this.options;
 | 
			
		||||
  if (isWindows) path = sysPath.normalize(path);
 | 
			
		||||
  if (opts.cwd) path = sysPath.relative(opts.cwd, path);
 | 
			
		||||
  /** @type Array<any> */
 | 
			
		||||
  const args = [event, path];
 | 
			
		||||
  if (val3 !== undefined) args.push(val1, val2, val3);
 | 
			
		||||
  else if (val2 !== undefined) args.push(val1, val2);
 | 
			
		||||
  else if (val1 !== undefined) args.push(val1);
 | 
			
		||||
 | 
			
		||||
  const awf = opts.awaitWriteFinish;
 | 
			
		||||
  let pw;
 | 
			
		||||
  if (awf && (pw = this._pendingWrites.get(path))) {
 | 
			
		||||
    pw.lastChange = new Date();
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (opts.atomic) {
 | 
			
		||||
    if (event === EV_UNLINK) {
 | 
			
		||||
      this._pendingUnlinks.set(path, args);
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        this._pendingUnlinks.forEach((entry, path) => {
 | 
			
		||||
          this.emit(...entry);
 | 
			
		||||
          this.emit(EV_ALL, ...entry);
 | 
			
		||||
          this._pendingUnlinks.delete(path);
 | 
			
		||||
        });
 | 
			
		||||
      }, typeof opts.atomic === 'number' ? opts.atomic : 100);
 | 
			
		||||
      return this;
 | 
			
		||||
    }
 | 
			
		||||
    if (event === EV_ADD && this._pendingUnlinks.has(path)) {
 | 
			
		||||
      event = args[0] = EV_CHANGE;
 | 
			
		||||
      this._pendingUnlinks.delete(path);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (awf && (event === EV_ADD || event === EV_CHANGE) && this._readyEmitted) {
 | 
			
		||||
    const awfEmit = (err, stats) => {
 | 
			
		||||
      if (err) {
 | 
			
		||||
        event = args[0] = EV_ERROR;
 | 
			
		||||
        args[1] = err;
 | 
			
		||||
        this.emitWithAll(event, args);
 | 
			
		||||
      } else if (stats) {
 | 
			
		||||
        // if stats doesn't exist the file must have been deleted
 | 
			
		||||
        if (args.length > 2) {
 | 
			
		||||
          args[2] = stats;
 | 
			
		||||
        } else {
 | 
			
		||||
          args.push(stats);
 | 
			
		||||
        }
 | 
			
		||||
        this.emitWithAll(event, args);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this._awaitWriteFinish(path, awf.stabilityThreshold, event, awfEmit);
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (event === EV_CHANGE) {
 | 
			
		||||
    const isThrottled = !this._throttle(EV_CHANGE, path, 50);
 | 
			
		||||
    if (isThrottled) return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (opts.alwaysStat && val1 === undefined &&
 | 
			
		||||
    (event === EV_ADD || event === EV_ADD_DIR || event === EV_CHANGE)
 | 
			
		||||
  ) {
 | 
			
		||||
    const fullPath = opts.cwd ? sysPath.join(opts.cwd, path) : path;
 | 
			
		||||
    let stats;
 | 
			
		||||
    try {
 | 
			
		||||
      stats = await stat(fullPath);
 | 
			
		||||
    } catch (err) {}
 | 
			
		||||
    // Suppress event when fs_stat fails, to avoid sending undefined 'stat'
 | 
			
		||||
    if (!stats || this.closed) return;
 | 
			
		||||
    args.push(stats);
 | 
			
		||||
  }
 | 
			
		||||
  this.emitWithAll(event, args);
 | 
			
		||||
 | 
			
		||||
  return this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Common handler for errors
 | 
			
		||||
 * @param {Error} error
 | 
			
		||||
 * @returns {Error|Boolean} The error if defined, otherwise the value of the FSWatcher instance's `closed` flag
 | 
			
		||||
 */
 | 
			
		||||
_handleError(error) {
 | 
			
		||||
  const code = error && error.code;
 | 
			
		||||
  if (error && code !== 'ENOENT' && code !== 'ENOTDIR' &&
 | 
			
		||||
    (!this.options.ignorePermissionErrors || (code !== 'EPERM' && code !== 'EACCES'))
 | 
			
		||||
  ) {
 | 
			
		||||
    this.emit(EV_ERROR, error);
 | 
			
		||||
  }
 | 
			
		||||
  return error || this.closed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper utility for throttling
 | 
			
		||||
 * @param {ThrottleType} actionType type being throttled
 | 
			
		||||
 * @param {Path} path being acted upon
 | 
			
		||||
 * @param {Number} timeout duration of time to suppress duplicate actions
 | 
			
		||||
 * @returns {Object|false} tracking object or false if action should be suppressed
 | 
			
		||||
 */
 | 
			
		||||
_throttle(actionType, path, timeout) {
 | 
			
		||||
  if (!this._throttled.has(actionType)) {
 | 
			
		||||
    this._throttled.set(actionType, new Map());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @type {Map<Path, Object>} */
 | 
			
		||||
  const action = this._throttled.get(actionType);
 | 
			
		||||
  /** @type {Object} */
 | 
			
		||||
  const actionPath = action.get(path);
 | 
			
		||||
 | 
			
		||||
  if (actionPath) {
 | 
			
		||||
    actionPath.count++;
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let timeoutObject;
 | 
			
		||||
  const clear = () => {
 | 
			
		||||
    const item = action.get(path);
 | 
			
		||||
    const count = item ? item.count : 0;
 | 
			
		||||
    action.delete(path);
 | 
			
		||||
    clearTimeout(timeoutObject);
 | 
			
		||||
    if (item) clearTimeout(item.timeoutObject);
 | 
			
		||||
    return count;
 | 
			
		||||
  };
 | 
			
		||||
  timeoutObject = setTimeout(clear, timeout);
 | 
			
		||||
  const thr = {timeoutObject, clear, count: 0};
 | 
			
		||||
  action.set(path, thr);
 | 
			
		||||
  return thr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_incrReadyCount() {
 | 
			
		||||
  return this._readyCount++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Awaits write operation to finish.
 | 
			
		||||
 * Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback.
 | 
			
		||||
 * @param {Path} path being acted upon
 | 
			
		||||
 * @param {Number} threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished
 | 
			
		||||
 * @param {EventName} event
 | 
			
		||||
 * @param {Function} awfEmit Callback to be called when ready for event to be emitted.
 | 
			
		||||
 */
 | 
			
		||||
_awaitWriteFinish(path, threshold, event, awfEmit) {
 | 
			
		||||
  let timeoutHandler;
 | 
			
		||||
 | 
			
		||||
  let fullPath = path;
 | 
			
		||||
  if (this.options.cwd && !sysPath.isAbsolute(path)) {
 | 
			
		||||
    fullPath = sysPath.join(this.options.cwd, path);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const now = new Date();
 | 
			
		||||
 | 
			
		||||
  const awaitWriteFinish = (prevStat) => {
 | 
			
		||||
    fs.stat(fullPath, (err, curStat) => {
 | 
			
		||||
      if (err || !this._pendingWrites.has(path)) {
 | 
			
		||||
        if (err && err.code !== 'ENOENT') awfEmit(err);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const now = Number(new Date());
 | 
			
		||||
 | 
			
		||||
      if (prevStat && curStat.size !== prevStat.size) {
 | 
			
		||||
        this._pendingWrites.get(path).lastChange = now;
 | 
			
		||||
      }
 | 
			
		||||
      const pw = this._pendingWrites.get(path);
 | 
			
		||||
      const df = now - pw.lastChange;
 | 
			
		||||
 | 
			
		||||
      if (df >= threshold) {
 | 
			
		||||
        this._pendingWrites.delete(path);
 | 
			
		||||
        awfEmit(undefined, curStat);
 | 
			
		||||
      } else {
 | 
			
		||||
        timeoutHandler = setTimeout(
 | 
			
		||||
          awaitWriteFinish,
 | 
			
		||||
          this.options.awaitWriteFinish.pollInterval,
 | 
			
		||||
          curStat
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (!this._pendingWrites.has(path)) {
 | 
			
		||||
    this._pendingWrites.set(path, {
 | 
			
		||||
      lastChange: now,
 | 
			
		||||
      cancelWait: () => {
 | 
			
		||||
        this._pendingWrites.delete(path);
 | 
			
		||||
        clearTimeout(timeoutHandler);
 | 
			
		||||
        return event;
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    timeoutHandler = setTimeout(
 | 
			
		||||
      awaitWriteFinish,
 | 
			
		||||
      this.options.awaitWriteFinish.pollInterval
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_getGlobIgnored() {
 | 
			
		||||
  return [...this._ignoredPaths.values()];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Determines whether user has asked to ignore this path.
 | 
			
		||||
 * @param {Path} path filepath or dir
 | 
			
		||||
 * @param {fs.Stats=} stats result of fs.stat
 | 
			
		||||
 * @returns {Boolean}
 | 
			
		||||
 */
 | 
			
		||||
_isIgnored(path, stats) {
 | 
			
		||||
  if (this.options.atomic && DOT_RE.test(path)) return true;
 | 
			
		||||
  if (!this._userIgnored) {
 | 
			
		||||
    const {cwd} = this.options;
 | 
			
		||||
    const ign = this.options.ignored;
 | 
			
		||||
 | 
			
		||||
    const ignored = ign && ign.map(normalizeIgnored(cwd));
 | 
			
		||||
    const paths = arrify(ignored)
 | 
			
		||||
      .filter((path) => typeof path === STRING_TYPE && !isGlob(path))
 | 
			
		||||
      .map((path) => path + SLASH_GLOBSTAR);
 | 
			
		||||
    const list = this._getGlobIgnored().map(normalizeIgnored(cwd)).concat(ignored, paths);
 | 
			
		||||
    this._userIgnored = anymatch(list, undefined, ANYMATCH_OPTS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return this._userIgnored([path, stats]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_isntIgnored(path, stat) {
 | 
			
		||||
  return !this._isIgnored(path, stat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provides a set of common helpers and properties relating to symlink and glob handling.
 | 
			
		||||
 * @param {Path} path file, directory, or glob pattern being watched
 | 
			
		||||
 * @param {Number=} depth at any depth > 0, this isn't a glob
 | 
			
		||||
 * @returns {WatchHelper} object containing helpers for this path
 | 
			
		||||
 */
 | 
			
		||||
_getWatchHelpers(path, depth) {
 | 
			
		||||
  const watchPath = depth || this.options.disableGlobbing || !isGlob(path) ? path : globParent(path);
 | 
			
		||||
  const follow = this.options.followSymlinks;
 | 
			
		||||
 | 
			
		||||
  return new WatchHelper(path, watchPath, follow, this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Directory helpers
 | 
			
		||||
// -----------------
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provides directory tracking objects
 | 
			
		||||
 * @param {String} directory path of the directory
 | 
			
		||||
 * @returns {DirEntry} the directory's tracking object
 | 
			
		||||
 */
 | 
			
		||||
_getWatchedDir(directory) {
 | 
			
		||||
  if (!this._boundRemove) this._boundRemove = this._remove.bind(this);
 | 
			
		||||
  const dir = sysPath.resolve(directory);
 | 
			
		||||
  if (!this._watched.has(dir)) this._watched.set(dir, new DirEntry(dir, this._boundRemove));
 | 
			
		||||
  return this._watched.get(dir);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// File helpers
 | 
			
		||||
// ------------
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check for read permissions.
 | 
			
		||||
 * Based on this answer on SO: https://stackoverflow.com/a/11781404/1358405
 | 
			
		||||
 * @param {fs.Stats} stats - object, result of fs_stat
 | 
			
		||||
 * @returns {Boolean} indicates whether the file can be read
 | 
			
		||||
*/
 | 
			
		||||
_hasReadPermissions(stats) {
 | 
			
		||||
  if (this.options.ignorePermissionErrors) return true;
 | 
			
		||||
 | 
			
		||||
  // stats.mode may be bigint
 | 
			
		||||
  const md = stats && Number.parseInt(stats.mode, 10);
 | 
			
		||||
  const st = md & 0o777;
 | 
			
		||||
  const it = Number.parseInt(st.toString(8)[0], 10);
 | 
			
		||||
  return Boolean(4 & it);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handles emitting unlink events for
 | 
			
		||||
 * files and directories, and via recursion, for
 | 
			
		||||
 * files and directories within directories that are unlinked
 | 
			
		||||
 * @param {String} directory within which the following item is located
 | 
			
		||||
 * @param {String} item      base path of item/directory
 | 
			
		||||
 * @returns {void}
 | 
			
		||||
*/
 | 
			
		||||
_remove(directory, item, isDirectory) {
 | 
			
		||||
  // if what is being deleted is a directory, get that directory's paths
 | 
			
		||||
  // for recursive deleting and cleaning of watched object
 | 
			
		||||
  // if it is not a directory, nestedDirectoryChildren will be empty array
 | 
			
		||||
  const path = sysPath.join(directory, item);
 | 
			
		||||
  const fullPath = sysPath.resolve(path);
 | 
			
		||||
  isDirectory = isDirectory != null
 | 
			
		||||
    ? isDirectory
 | 
			
		||||
    : this._watched.has(path) || this._watched.has(fullPath);
 | 
			
		||||
 | 
			
		||||
  // prevent duplicate handling in case of arriving here nearly simultaneously
 | 
			
		||||
  // via multiple paths (such as _handleFile and _handleDir)
 | 
			
		||||
  if (!this._throttle('remove', path, 100)) return;
 | 
			
		||||
 | 
			
		||||
  // if the only watched file is removed, watch for its return
 | 
			
		||||
  if (!isDirectory && !this.options.useFsEvents && this._watched.size === 1) {
 | 
			
		||||
    this.add(directory, item, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // This will create a new entry in the watched object in either case
 | 
			
		||||
  // so we got to do the directory check beforehand
 | 
			
		||||
  const wp = this._getWatchedDir(path);
 | 
			
		||||
  const nestedDirectoryChildren = wp.getChildren();
 | 
			
		||||
 | 
			
		||||
  // Recursively remove children directories / files.
 | 
			
		||||
  nestedDirectoryChildren.forEach(nested => this._remove(path, nested));
 | 
			
		||||
 | 
			
		||||
  // Check if item was on the watched list and remove it
 | 
			
		||||
  const parent = this._getWatchedDir(directory);
 | 
			
		||||
  const wasTracked = parent.has(item);
 | 
			
		||||
  parent.remove(item);
 | 
			
		||||
 | 
			
		||||
  // Fixes issue #1042 -> Relative paths were detected and added as symlinks
 | 
			
		||||
  // (https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L612),
 | 
			
		||||
  // but never removed from the map in case the path was deleted.
 | 
			
		||||
  // This leads to an incorrect state if the path was recreated:
 | 
			
		||||
  // https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L553
 | 
			
		||||
  if (this._symlinkPaths.has(fullPath)) {
 | 
			
		||||
    this._symlinkPaths.delete(fullPath);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // If we wait for this file to be fully written, cancel the wait.
 | 
			
		||||
  let relPath = path;
 | 
			
		||||
  if (this.options.cwd) relPath = sysPath.relative(this.options.cwd, path);
 | 
			
		||||
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
 | 
			
		||||
    const event = this._pendingWrites.get(relPath).cancelWait();
 | 
			
		||||
    if (event === EV_ADD) return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // The Entry will either be a directory that just got removed
 | 
			
		||||
  // or a bogus entry to a file, in either case we have to remove it
 | 
			
		||||
  this._watched.delete(path);
 | 
			
		||||
  this._watched.delete(fullPath);
 | 
			
		||||
  const eventName = isDirectory ? EV_UNLINK_DIR : EV_UNLINK;
 | 
			
		||||
  if (wasTracked && !this._isIgnored(path)) this._emit(eventName, path);
 | 
			
		||||
 | 
			
		||||
  // Avoid conflicts if we later create another file with the same name
 | 
			
		||||
  if (!this.options.useFsEvents) {
 | 
			
		||||
    this._closePath(path);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Closes all watchers for a path
 | 
			
		||||
 * @param {Path} path
 | 
			
		||||
 */
 | 
			
		||||
_closePath(path) {
 | 
			
		||||
  this._closeFile(path)
 | 
			
		||||
  const dir = sysPath.dirname(path);
 | 
			
		||||
  this._getWatchedDir(dir).remove(sysPath.basename(path));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Closes only file-specific watchers
 | 
			
		||||
 * @param {Path} path
 | 
			
		||||
 */
 | 
			
		||||
_closeFile(path) {
 | 
			
		||||
  const closers = this._closers.get(path);
 | 
			
		||||
  if (!closers) return;
 | 
			
		||||
  closers.forEach(closer => closer());
 | 
			
		||||
  this._closers.delete(path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Path} path
 | 
			
		||||
 * @param {Function} closer
 | 
			
		||||
 */
 | 
			
		||||
_addPathCloser(path, closer) {
 | 
			
		||||
  if (!closer) return;
 | 
			
		||||
  let list = this._closers.get(path);
 | 
			
		||||
  if (!list) {
 | 
			
		||||
    list = [];
 | 
			
		||||
    this._closers.set(path, list);
 | 
			
		||||
  }
 | 
			
		||||
  list.push(closer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_readdirp(root, opts) {
 | 
			
		||||
  if (this.closed) return;
 | 
			
		||||
  const options = {type: EV_ALL, alwaysStat: true, lstat: true, ...opts};
 | 
			
		||||
  let stream = readdirp(root, options);
 | 
			
		||||
  this._streams.add(stream);
 | 
			
		||||
  stream.once(STR_CLOSE, () => {
 | 
			
		||||
    stream = undefined;
 | 
			
		||||
  });
 | 
			
		||||
  stream.once(STR_END, () => {
 | 
			
		||||
    if (stream) {
 | 
			
		||||
      this._streams.delete(stream);
 | 
			
		||||
      stream = undefined;
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  return stream;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Export FSWatcher class
 | 
			
		||||
exports.FSWatcher = FSWatcher;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Instantiates watcher with paths to be tracked.
 | 
			
		||||
 * @param {String|Array<String>} paths file/directory paths and/or globs
 | 
			
		||||
 * @param {Object=} options chokidar opts
 | 
			
		||||
 * @returns an instance of FSWatcher for chaining.
 | 
			
		||||
 */
 | 
			
		||||
const watch = (paths, options) => {
 | 
			
		||||
  const watcher = new FSWatcher(options);
 | 
			
		||||
  watcher.add(paths);
 | 
			
		||||
  return watcher;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
exports.watch = watch;
 | 
			
		||||
							
								
								
									
										65
									
								
								node_modules/chokidar/lib/constants.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								node_modules/chokidar/lib/constants.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
const {sep} = require('path');
 | 
			
		||||
const {platform} = process;
 | 
			
		||||
const os = require('os');
 | 
			
		||||
 | 
			
		||||
exports.EV_ALL = 'all';
 | 
			
		||||
exports.EV_READY = 'ready';
 | 
			
		||||
exports.EV_ADD = 'add';
 | 
			
		||||
exports.EV_CHANGE = 'change';
 | 
			
		||||
exports.EV_ADD_DIR = 'addDir';
 | 
			
		||||
exports.EV_UNLINK = 'unlink';
 | 
			
		||||
exports.EV_UNLINK_DIR = 'unlinkDir';
 | 
			
		||||
exports.EV_RAW = 'raw';
 | 
			
		||||
exports.EV_ERROR = 'error';
 | 
			
		||||
 | 
			
		||||
exports.STR_DATA = 'data';
 | 
			
		||||
exports.STR_END = 'end';
 | 
			
		||||
exports.STR_CLOSE = 'close';
 | 
			
		||||
 | 
			
		||||
exports.FSEVENT_CREATED = 'created';
 | 
			
		||||
exports.FSEVENT_MODIFIED = 'modified';
 | 
			
		||||
exports.FSEVENT_DELETED = 'deleted';
 | 
			
		||||
exports.FSEVENT_MOVED = 'moved';
 | 
			
		||||
exports.FSEVENT_CLONED = 'cloned';
 | 
			
		||||
exports.FSEVENT_UNKNOWN = 'unknown';
 | 
			
		||||
exports.FSEVENT_TYPE_FILE = 'file';
 | 
			
		||||
exports.FSEVENT_TYPE_DIRECTORY = 'directory';
 | 
			
		||||
exports.FSEVENT_TYPE_SYMLINK = 'symlink';
 | 
			
		||||
 | 
			
		||||
exports.KEY_LISTENERS = 'listeners';
 | 
			
		||||
exports.KEY_ERR = 'errHandlers';
 | 
			
		||||
exports.KEY_RAW = 'rawEmitters';
 | 
			
		||||
exports.HANDLER_KEYS = [exports.KEY_LISTENERS, exports.KEY_ERR, exports.KEY_RAW];
 | 
			
		||||
 | 
			
		||||
exports.DOT_SLASH = `.${sep}`;
 | 
			
		||||
 | 
			
		||||
exports.BACK_SLASH_RE = /\\/g;
 | 
			
		||||
exports.DOUBLE_SLASH_RE = /\/\//;
 | 
			
		||||
exports.SLASH_OR_BACK_SLASH_RE = /[/\\]/;
 | 
			
		||||
exports.DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;
 | 
			
		||||
exports.REPLACER_RE = /^\.[/\\]/;
 | 
			
		||||
 | 
			
		||||
exports.SLASH = '/';
 | 
			
		||||
exports.SLASH_SLASH = '//';
 | 
			
		||||
exports.BRACE_START = '{';
 | 
			
		||||
exports.BANG = '!';
 | 
			
		||||
exports.ONE_DOT = '.';
 | 
			
		||||
exports.TWO_DOTS = '..';
 | 
			
		||||
exports.STAR = '*';
 | 
			
		||||
exports.GLOBSTAR = '**';
 | 
			
		||||
exports.ROOT_GLOBSTAR = '/**/*';
 | 
			
		||||
exports.SLASH_GLOBSTAR = '/**';
 | 
			
		||||
exports.DIR_SUFFIX = 'Dir';
 | 
			
		||||
exports.ANYMATCH_OPTS = {dot: true};
 | 
			
		||||
exports.STRING_TYPE = 'string';
 | 
			
		||||
exports.FUNCTION_TYPE = 'function';
 | 
			
		||||
exports.EMPTY_STR = '';
 | 
			
		||||
exports.EMPTY_FN = () => {};
 | 
			
		||||
exports.IDENTITY_FN = val => val;
 | 
			
		||||
 | 
			
		||||
exports.isWindows = platform === 'win32';
 | 
			
		||||
exports.isMacos = platform === 'darwin';
 | 
			
		||||
exports.isLinux = platform === 'linux';
 | 
			
		||||
exports.isIBMi = os.type() === 'OS400';
 | 
			
		||||
							
								
								
									
										524
									
								
								node_modules/chokidar/lib/fsevents-handler.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										524
									
								
								node_modules/chokidar/lib/fsevents-handler.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,524 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
const fs = require('fs');
 | 
			
		||||
const sysPath = require('path');
 | 
			
		||||
const { promisify } = require('util');
 | 
			
		||||
 | 
			
		||||
let fsevents;
 | 
			
		||||
try {
 | 
			
		||||
  fsevents = require('fsevents');
 | 
			
		||||
} catch (error) {
 | 
			
		||||
  if (process.env.CHOKIDAR_PRINT_FSEVENTS_REQUIRE_ERROR) console.error(error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if (fsevents) {
 | 
			
		||||
  // TODO: real check
 | 
			
		||||
  const mtch = process.version.match(/v(\d+)\.(\d+)/);
 | 
			
		||||
  if (mtch && mtch[1] && mtch[2]) {
 | 
			
		||||
    const maj = Number.parseInt(mtch[1], 10);
 | 
			
		||||
    const min = Number.parseInt(mtch[2], 10);
 | 
			
		||||
    if (maj === 8 && min < 16) {
 | 
			
		||||
      fsevents = undefined;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const {
 | 
			
		||||
  EV_ADD,
 | 
			
		||||
  EV_CHANGE,
 | 
			
		||||
  EV_ADD_DIR,
 | 
			
		||||
  EV_UNLINK,
 | 
			
		||||
  EV_ERROR,
 | 
			
		||||
  STR_DATA,
 | 
			
		||||
  STR_END,
 | 
			
		||||
  FSEVENT_CREATED,
 | 
			
		||||
  FSEVENT_MODIFIED,
 | 
			
		||||
  FSEVENT_DELETED,
 | 
			
		||||
  FSEVENT_MOVED,
 | 
			
		||||
  // FSEVENT_CLONED,
 | 
			
		||||
  FSEVENT_UNKNOWN,
 | 
			
		||||
  FSEVENT_TYPE_FILE,
 | 
			
		||||
  FSEVENT_TYPE_DIRECTORY,
 | 
			
		||||
  FSEVENT_TYPE_SYMLINK,
 | 
			
		||||
 | 
			
		||||
  ROOT_GLOBSTAR,
 | 
			
		||||
  DIR_SUFFIX,
 | 
			
		||||
  DOT_SLASH,
 | 
			
		||||
  FUNCTION_TYPE,
 | 
			
		||||
  EMPTY_FN,
 | 
			
		||||
  IDENTITY_FN
 | 
			
		||||
} = require('./constants');
 | 
			
		||||
 | 
			
		||||
const Depth = (value) => isNaN(value) ? {} : {depth: value};
 | 
			
		||||
 | 
			
		||||
const stat = promisify(fs.stat);
 | 
			
		||||
const lstat = promisify(fs.lstat);
 | 
			
		||||
const realpath = promisify(fs.realpath);
 | 
			
		||||
 | 
			
		||||
const statMethods = { stat, lstat };
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef {String} Path
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef {Object} FsEventsWatchContainer
 | 
			
		||||
 * @property {Set<Function>} listeners
 | 
			
		||||
 * @property {Function} rawEmitter
 | 
			
		||||
 * @property {{stop: Function}} watcher
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// fsevents instance helper functions
 | 
			
		||||
/**
 | 
			
		||||
 * Object to hold per-process fsevents instances (may be shared across chokidar FSWatcher instances)
 | 
			
		||||
 * @type {Map<Path,FsEventsWatchContainer>}
 | 
			
		||||
 */
 | 
			
		||||
const FSEventsWatchers = new Map();
 | 
			
		||||
 | 
			
		||||
// Threshold of duplicate path prefixes at which to start
 | 
			
		||||
// consolidating going forward
 | 
			
		||||
const consolidateThreshhold = 10;
 | 
			
		||||
 | 
			
		||||
const wrongEventFlags = new Set([
 | 
			
		||||
  69888, 70400, 71424, 72704, 73472, 131328, 131840, 262912
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Instantiates the fsevents interface
 | 
			
		||||
 * @param {Path} path path to be watched
 | 
			
		||||
 * @param {Function} callback called when fsevents is bound and ready
 | 
			
		||||
 * @returns {{stop: Function}} new fsevents instance
 | 
			
		||||
 */
 | 
			
		||||
const createFSEventsInstance = (path, callback) => {
 | 
			
		||||
  const stop = fsevents.watch(path, callback);
 | 
			
		||||
  return {stop};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Instantiates the fsevents interface or binds listeners to an existing one covering
 | 
			
		||||
 * the same file tree.
 | 
			
		||||
 * @param {Path} path           - to be watched
 | 
			
		||||
 * @param {Path} realPath       - real path for symlinks
 | 
			
		||||
 * @param {Function} listener   - called when fsevents emits events
 | 
			
		||||
 * @param {Function} rawEmitter - passes data to listeners of the 'raw' event
 | 
			
		||||
 * @returns {Function} closer
 | 
			
		||||
 */
 | 
			
		||||
function setFSEventsListener(path, realPath, listener, rawEmitter) {
 | 
			
		||||
  let watchPath = sysPath.extname(realPath) ? sysPath.dirname(realPath) : realPath;
 | 
			
		||||
 | 
			
		||||
  const parentPath = sysPath.dirname(watchPath);
 | 
			
		||||
  let cont = FSEventsWatchers.get(watchPath);
 | 
			
		||||
 | 
			
		||||
  // If we've accumulated a substantial number of paths that
 | 
			
		||||
  // could have been consolidated by watching one directory
 | 
			
		||||
  // above the current one, create a watcher on the parent
 | 
			
		||||
  // path instead, so that we do consolidate going forward.
 | 
			
		||||
  if (couldConsolidate(parentPath)) {
 | 
			
		||||
    watchPath = parentPath;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const resolvedPath = sysPath.resolve(path);
 | 
			
		||||
  const hasSymlink = resolvedPath !== realPath;
 | 
			
		||||
 | 
			
		||||
  const filteredListener = (fullPath, flags, info) => {
 | 
			
		||||
    if (hasSymlink) fullPath = fullPath.replace(realPath, resolvedPath);
 | 
			
		||||
    if (
 | 
			
		||||
      fullPath === resolvedPath ||
 | 
			
		||||
      !fullPath.indexOf(resolvedPath + sysPath.sep)
 | 
			
		||||
    ) listener(fullPath, flags, info);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // check if there is already a watcher on a parent path
 | 
			
		||||
  // modifies `watchPath` to the parent path when it finds a match
 | 
			
		||||
  let watchedParent = false;
 | 
			
		||||
  for (const watchedPath of FSEventsWatchers.keys()) {
 | 
			
		||||
    if (realPath.indexOf(sysPath.resolve(watchedPath) + sysPath.sep) === 0) {
 | 
			
		||||
      watchPath = watchedPath;
 | 
			
		||||
      cont = FSEventsWatchers.get(watchPath);
 | 
			
		||||
      watchedParent = true;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (cont || watchedParent) {
 | 
			
		||||
    cont.listeners.add(filteredListener);
 | 
			
		||||
  } else {
 | 
			
		||||
    cont = {
 | 
			
		||||
      listeners: new Set([filteredListener]),
 | 
			
		||||
      rawEmitter,
 | 
			
		||||
      watcher: createFSEventsInstance(watchPath, (fullPath, flags) => {
 | 
			
		||||
        if (!cont.listeners.size) return;
 | 
			
		||||
        const info = fsevents.getInfo(fullPath, flags);
 | 
			
		||||
        cont.listeners.forEach(list => {
 | 
			
		||||
          list(fullPath, flags, info);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        cont.rawEmitter(info.event, fullPath, info);
 | 
			
		||||
      })
 | 
			
		||||
    };
 | 
			
		||||
    FSEventsWatchers.set(watchPath, cont);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // removes this instance's listeners and closes the underlying fsevents
 | 
			
		||||
  // instance if there are no more listeners left
 | 
			
		||||
  return () => {
 | 
			
		||||
    const lst = cont.listeners;
 | 
			
		||||
 | 
			
		||||
    lst.delete(filteredListener);
 | 
			
		||||
    if (!lst.size) {
 | 
			
		||||
      FSEventsWatchers.delete(watchPath);
 | 
			
		||||
      if (cont.watcher) return cont.watcher.stop().then(() => {
 | 
			
		||||
        cont.rawEmitter = cont.watcher = undefined;
 | 
			
		||||
        Object.freeze(cont);
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decide whether or not we should start a new higher-level
 | 
			
		||||
// parent watcher
 | 
			
		||||
const couldConsolidate = (path) => {
 | 
			
		||||
  let count = 0;
 | 
			
		||||
  for (const watchPath of FSEventsWatchers.keys()) {
 | 
			
		||||
    if (watchPath.indexOf(path) === 0) {
 | 
			
		||||
      count++;
 | 
			
		||||
      if (count >= consolidateThreshhold) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// returns boolean indicating whether fsevents can be used
 | 
			
		||||
const canUse = () => fsevents && FSEventsWatchers.size < 128;
 | 
			
		||||
 | 
			
		||||
// determines subdirectory traversal levels from root to path
 | 
			
		||||
const calcDepth = (path, root) => {
 | 
			
		||||
  let i = 0;
 | 
			
		||||
  while (!path.indexOf(root) && (path = sysPath.dirname(path)) !== root) i++;
 | 
			
		||||
  return i;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// returns boolean indicating whether the fsevents' event info has the same type
 | 
			
		||||
// as the one returned by fs.stat
 | 
			
		||||
const sameTypes = (info, stats) => (
 | 
			
		||||
  info.type === FSEVENT_TYPE_DIRECTORY && stats.isDirectory() ||
 | 
			
		||||
  info.type === FSEVENT_TYPE_SYMLINK && stats.isSymbolicLink() ||
 | 
			
		||||
  info.type === FSEVENT_TYPE_FILE && stats.isFile()
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @mixin
 | 
			
		||||
 */
 | 
			
		||||
class FsEventsHandler {
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {import('../index').FSWatcher} fsw
 | 
			
		||||
 */
 | 
			
		||||
constructor(fsw) {
 | 
			
		||||
  this.fsw = fsw;
 | 
			
		||||
}
 | 
			
		||||
checkIgnored(path, stats) {
 | 
			
		||||
  const ipaths = this.fsw._ignoredPaths;
 | 
			
		||||
  if (this.fsw._isIgnored(path, stats)) {
 | 
			
		||||
    ipaths.add(path);
 | 
			
		||||
    if (stats && stats.isDirectory()) {
 | 
			
		||||
      ipaths.add(path + ROOT_GLOBSTAR);
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ipaths.delete(path);
 | 
			
		||||
  ipaths.delete(path + ROOT_GLOBSTAR);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts) {
 | 
			
		||||
  const event = watchedDir.has(item) ? EV_CHANGE : EV_ADD;
 | 
			
		||||
  this.handleEvent(event, path, fullPath, realPath, parent, watchedDir, item, info, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts) {
 | 
			
		||||
  try {
 | 
			
		||||
    const stats = await stat(path)
 | 
			
		||||
    if (this.fsw.closed) return;
 | 
			
		||||
    if (sameTypes(info, stats)) {
 | 
			
		||||
      this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts);
 | 
			
		||||
    } else {
 | 
			
		||||
      this.handleEvent(EV_UNLINK, path, fullPath, realPath, parent, watchedDir, item, info, opts);
 | 
			
		||||
    }
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    if (error.code === 'EACCES') {
 | 
			
		||||
      this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts);
 | 
			
		||||
    } else {
 | 
			
		||||
      this.handleEvent(EV_UNLINK, path, fullPath, realPath, parent, watchedDir, item, info, opts);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
handleEvent(event, path, fullPath, realPath, parent, watchedDir, item, info, opts) {
 | 
			
		||||
  if (this.fsw.closed || this.checkIgnored(path)) return;
 | 
			
		||||
 | 
			
		||||
  if (event === EV_UNLINK) {
 | 
			
		||||
    const isDirectory = info.type === FSEVENT_TYPE_DIRECTORY
 | 
			
		||||
    // suppress unlink events on never before seen files
 | 
			
		||||
    if (isDirectory || watchedDir.has(item)) {
 | 
			
		||||
      this.fsw._remove(parent, item, isDirectory);
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    if (event === EV_ADD) {
 | 
			
		||||
      // track new directories
 | 
			
		||||
      if (info.type === FSEVENT_TYPE_DIRECTORY) this.fsw._getWatchedDir(path);
 | 
			
		||||
 | 
			
		||||
      if (info.type === FSEVENT_TYPE_SYMLINK && opts.followSymlinks) {
 | 
			
		||||
        // push symlinks back to the top of the stack to get handled
 | 
			
		||||
        const curDepth = opts.depth === undefined ?
 | 
			
		||||
          undefined : calcDepth(fullPath, realPath) + 1;
 | 
			
		||||
        return this._addToFsEvents(path, false, true, curDepth);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // track new paths
 | 
			
		||||
      // (other than symlinks being followed, which will be tracked soon)
 | 
			
		||||
      this.fsw._getWatchedDir(parent).add(item);
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @type {'add'|'addDir'|'unlink'|'unlinkDir'}
 | 
			
		||||
     */
 | 
			
		||||
    const eventName = info.type === FSEVENT_TYPE_DIRECTORY ? event + DIR_SUFFIX : event;
 | 
			
		||||
    this.fsw._emit(eventName, path);
 | 
			
		||||
    if (eventName === EV_ADD_DIR) this._addToFsEvents(path, false, true);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handle symlinks encountered during directory scan
 | 
			
		||||
 * @param {String} watchPath  - file/dir path to be watched with fsevents
 | 
			
		||||
 * @param {String} realPath   - real path (in case of symlinks)
 | 
			
		||||
 * @param {Function} transform  - path transformer
 | 
			
		||||
 * @param {Function} globFilter - path filter in case a glob pattern was provided
 | 
			
		||||
 * @returns {Function} closer for the watcher instance
 | 
			
		||||
*/
 | 
			
		||||
_watchWithFsEvents(watchPath, realPath, transform, globFilter) {
 | 
			
		||||
  if (this.fsw.closed || this.fsw._isIgnored(watchPath)) return;
 | 
			
		||||
  const opts = this.fsw.options;
 | 
			
		||||
  const watchCallback = async (fullPath, flags, info) => {
 | 
			
		||||
    if (this.fsw.closed) return;
 | 
			
		||||
    if (
 | 
			
		||||
      opts.depth !== undefined &&
 | 
			
		||||
      calcDepth(fullPath, realPath) > opts.depth
 | 
			
		||||
    ) return;
 | 
			
		||||
    const path = transform(sysPath.join(
 | 
			
		||||
      watchPath, sysPath.relative(watchPath, fullPath)
 | 
			
		||||
    ));
 | 
			
		||||
    if (globFilter && !globFilter(path)) return;
 | 
			
		||||
    // ensure directories are tracked
 | 
			
		||||
    const parent = sysPath.dirname(path);
 | 
			
		||||
    const item = sysPath.basename(path);
 | 
			
		||||
    const watchedDir = this.fsw._getWatchedDir(
 | 
			
		||||
      info.type === FSEVENT_TYPE_DIRECTORY ? path : parent
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // correct for wrong events emitted
 | 
			
		||||
    if (wrongEventFlags.has(flags) || info.event === FSEVENT_UNKNOWN) {
 | 
			
		||||
      if (typeof opts.ignored === FUNCTION_TYPE) {
 | 
			
		||||
        let stats;
 | 
			
		||||
        try {
 | 
			
		||||
          stats = await stat(path);
 | 
			
		||||
        } catch (error) {}
 | 
			
		||||
        if (this.fsw.closed) return;
 | 
			
		||||
        if (this.checkIgnored(path, stats)) return;
 | 
			
		||||
        if (sameTypes(info, stats)) {
 | 
			
		||||
          this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts);
 | 
			
		||||
        } else {
 | 
			
		||||
          this.handleEvent(EV_UNLINK, path, fullPath, realPath, parent, watchedDir, item, info, opts);
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        this.checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts);
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      switch (info.event) {
 | 
			
		||||
      case FSEVENT_CREATED:
 | 
			
		||||
      case FSEVENT_MODIFIED:
 | 
			
		||||
        return this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts);
 | 
			
		||||
      case FSEVENT_DELETED:
 | 
			
		||||
      case FSEVENT_MOVED:
 | 
			
		||||
        return this.checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const closer = setFSEventsListener(
 | 
			
		||||
    watchPath,
 | 
			
		||||
    realPath,
 | 
			
		||||
    watchCallback,
 | 
			
		||||
    this.fsw._emitRaw
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  this.fsw._emitReady();
 | 
			
		||||
  return closer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handle symlinks encountered during directory scan
 | 
			
		||||
 * @param {String} linkPath path to symlink
 | 
			
		||||
 * @param {String} fullPath absolute path to the symlink
 | 
			
		||||
 * @param {Function} transform pre-existing path transformer
 | 
			
		||||
 * @param {Number} curDepth level of subdirectories traversed to where symlink is
 | 
			
		||||
 * @returns {Promise<void>}
 | 
			
		||||
 */
 | 
			
		||||
async _handleFsEventsSymlink(linkPath, fullPath, transform, curDepth) {
 | 
			
		||||
  // don't follow the same symlink more than once
 | 
			
		||||
  if (this.fsw.closed || this.fsw._symlinkPaths.has(fullPath)) return;
 | 
			
		||||
 | 
			
		||||
  this.fsw._symlinkPaths.set(fullPath, true);
 | 
			
		||||
  this.fsw._incrReadyCount();
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    const linkTarget = await realpath(linkPath);
 | 
			
		||||
    if (this.fsw.closed) return;
 | 
			
		||||
    if (this.fsw._isIgnored(linkTarget)) {
 | 
			
		||||
      return this.fsw._emitReady();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.fsw._incrReadyCount();
 | 
			
		||||
 | 
			
		||||
    // add the linkTarget for watching with a wrapper for transform
 | 
			
		||||
    // that causes emitted paths to incorporate the link's path
 | 
			
		||||
    this._addToFsEvents(linkTarget || linkPath, (path) => {
 | 
			
		||||
      let aliasedPath = linkPath;
 | 
			
		||||
      if (linkTarget && linkTarget !== DOT_SLASH) {
 | 
			
		||||
        aliasedPath = path.replace(linkTarget, linkPath);
 | 
			
		||||
      } else if (path !== DOT_SLASH) {
 | 
			
		||||
        aliasedPath = sysPath.join(linkPath, path);
 | 
			
		||||
      }
 | 
			
		||||
      return transform(aliasedPath);
 | 
			
		||||
    }, false, curDepth);
 | 
			
		||||
  } catch(error) {
 | 
			
		||||
    if (this.fsw._handleError(error)) {
 | 
			
		||||
      return this.fsw._emitReady();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Path} newPath
 | 
			
		||||
 * @param {fs.Stats} stats
 | 
			
		||||
 */
 | 
			
		||||
emitAdd(newPath, stats, processPath, opts, forceAdd) {
 | 
			
		||||
  const pp = processPath(newPath);
 | 
			
		||||
  const isDir = stats.isDirectory();
 | 
			
		||||
  const dirObj = this.fsw._getWatchedDir(sysPath.dirname(pp));
 | 
			
		||||
  const base = sysPath.basename(pp);
 | 
			
		||||
 | 
			
		||||
  // ensure empty dirs get tracked
 | 
			
		||||
  if (isDir) this.fsw._getWatchedDir(pp);
 | 
			
		||||
  if (dirObj.has(base)) return;
 | 
			
		||||
  dirObj.add(base);
 | 
			
		||||
 | 
			
		||||
  if (!opts.ignoreInitial || forceAdd === true) {
 | 
			
		||||
    this.fsw._emit(isDir ? EV_ADD_DIR : EV_ADD, pp, stats);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
initWatch(realPath, path, wh, processPath) {
 | 
			
		||||
  if (this.fsw.closed) return;
 | 
			
		||||
  const closer = this._watchWithFsEvents(
 | 
			
		||||
    wh.watchPath,
 | 
			
		||||
    sysPath.resolve(realPath || wh.watchPath),
 | 
			
		||||
    processPath,
 | 
			
		||||
    wh.globFilter
 | 
			
		||||
  );
 | 
			
		||||
  this.fsw._addPathCloser(path, closer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handle added path with fsevents
 | 
			
		||||
 * @param {String} path file/dir path or glob pattern
 | 
			
		||||
 * @param {Function|Boolean=} transform converts working path to what the user expects
 | 
			
		||||
 * @param {Boolean=} forceAdd ensure add is emitted
 | 
			
		||||
 * @param {Number=} priorDepth Level of subdirectories already traversed.
 | 
			
		||||
 * @returns {Promise<void>}
 | 
			
		||||
 */
 | 
			
		||||
async _addToFsEvents(path, transform, forceAdd, priorDepth) {
 | 
			
		||||
  if (this.fsw.closed) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  const opts = this.fsw.options;
 | 
			
		||||
  const processPath = typeof transform === FUNCTION_TYPE ? transform : IDENTITY_FN;
 | 
			
		||||
 | 
			
		||||
  const wh = this.fsw._getWatchHelpers(path);
 | 
			
		||||
 | 
			
		||||
  // evaluate what is at the path we're being asked to watch
 | 
			
		||||
  try {
 | 
			
		||||
    const stats = await statMethods[wh.statMethod](wh.watchPath);
 | 
			
		||||
    if (this.fsw.closed) return;
 | 
			
		||||
    if (this.fsw._isIgnored(wh.watchPath, stats)) {
 | 
			
		||||
      throw null;
 | 
			
		||||
    }
 | 
			
		||||
    if (stats.isDirectory()) {
 | 
			
		||||
      // emit addDir unless this is a glob parent
 | 
			
		||||
      if (!wh.globFilter) this.emitAdd(processPath(path), stats, processPath, opts, forceAdd);
 | 
			
		||||
 | 
			
		||||
      // don't recurse further if it would exceed depth setting
 | 
			
		||||
      if (priorDepth && priorDepth > opts.depth) return;
 | 
			
		||||
 | 
			
		||||
      // scan the contents of the dir
 | 
			
		||||
      this.fsw._readdirp(wh.watchPath, {
 | 
			
		||||
        fileFilter: entry => wh.filterPath(entry),
 | 
			
		||||
        directoryFilter: entry => wh.filterDir(entry),
 | 
			
		||||
        ...Depth(opts.depth - (priorDepth || 0))
 | 
			
		||||
      }).on(STR_DATA, (entry) => {
 | 
			
		||||
        // need to check filterPath on dirs b/c filterDir is less restrictive
 | 
			
		||||
        if (this.fsw.closed) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        if (entry.stats.isDirectory() && !wh.filterPath(entry)) return;
 | 
			
		||||
 | 
			
		||||
        const joinedPath = sysPath.join(wh.watchPath, entry.path);
 | 
			
		||||
        const {fullPath} = entry;
 | 
			
		||||
 | 
			
		||||
        if (wh.followSymlinks && entry.stats.isSymbolicLink()) {
 | 
			
		||||
          // preserve the current depth here since it can't be derived from
 | 
			
		||||
          // real paths past the symlink
 | 
			
		||||
          const curDepth = opts.depth === undefined ?
 | 
			
		||||
            undefined : calcDepth(joinedPath, sysPath.resolve(wh.watchPath)) + 1;
 | 
			
		||||
 | 
			
		||||
          this._handleFsEventsSymlink(joinedPath, fullPath, processPath, curDepth);
 | 
			
		||||
        } else {
 | 
			
		||||
          this.emitAdd(joinedPath, entry.stats, processPath, opts, forceAdd);
 | 
			
		||||
        }
 | 
			
		||||
      }).on(EV_ERROR, EMPTY_FN).on(STR_END, () => {
 | 
			
		||||
        this.fsw._emitReady();
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      this.emitAdd(wh.watchPath, stats, processPath, opts, forceAdd);
 | 
			
		||||
      this.fsw._emitReady();
 | 
			
		||||
    }
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    if (!error || this.fsw._handleError(error)) {
 | 
			
		||||
      // TODO: Strange thing: "should not choke on an ignored watch path" will be failed without 2 ready calls -__-
 | 
			
		||||
      this.fsw._emitReady();
 | 
			
		||||
      this.fsw._emitReady();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (opts.persistent && forceAdd !== true) {
 | 
			
		||||
    if (typeof transform === FUNCTION_TYPE) {
 | 
			
		||||
      // realpath has already been resolved
 | 
			
		||||
      this.initWatch(undefined, path, wh, processPath);
 | 
			
		||||
    } else {
 | 
			
		||||
      let realPath;
 | 
			
		||||
      try {
 | 
			
		||||
        realPath = await realpath(wh.watchPath);
 | 
			
		||||
      } catch (e) {}
 | 
			
		||||
      this.initWatch(realPath, path, wh, processPath);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = FsEventsHandler;
 | 
			
		||||
module.exports.canUse = canUse;
 | 
			
		||||
							
								
								
									
										654
									
								
								node_modules/chokidar/lib/nodefs-handler.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										654
									
								
								node_modules/chokidar/lib/nodefs-handler.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,654 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
const fs = require('fs');
 | 
			
		||||
const sysPath = require('path');
 | 
			
		||||
const { promisify } = require('util');
 | 
			
		||||
const isBinaryPath = require('is-binary-path');
 | 
			
		||||
const {
 | 
			
		||||
  isWindows,
 | 
			
		||||
  isLinux,
 | 
			
		||||
  EMPTY_FN,
 | 
			
		||||
  EMPTY_STR,
 | 
			
		||||
  KEY_LISTENERS,
 | 
			
		||||
  KEY_ERR,
 | 
			
		||||
  KEY_RAW,
 | 
			
		||||
  HANDLER_KEYS,
 | 
			
		||||
  EV_CHANGE,
 | 
			
		||||
  EV_ADD,
 | 
			
		||||
  EV_ADD_DIR,
 | 
			
		||||
  EV_ERROR,
 | 
			
		||||
  STR_DATA,
 | 
			
		||||
  STR_END,
 | 
			
		||||
  BRACE_START,
 | 
			
		||||
  STAR
 | 
			
		||||
} = require('./constants');
 | 
			
		||||
 | 
			
		||||
const THROTTLE_MODE_WATCH = 'watch';
 | 
			
		||||
 | 
			
		||||
const open = promisify(fs.open);
 | 
			
		||||
const stat = promisify(fs.stat);
 | 
			
		||||
const lstat = promisify(fs.lstat);
 | 
			
		||||
const close = promisify(fs.close);
 | 
			
		||||
const fsrealpath = promisify(fs.realpath);
 | 
			
		||||
 | 
			
		||||
const statMethods = { lstat, stat };
 | 
			
		||||
 | 
			
		||||
// TODO: emit errors properly. Example: EMFILE on Macos.
 | 
			
		||||
const foreach = (val, fn) => {
 | 
			
		||||
  if (val instanceof Set) {
 | 
			
		||||
    val.forEach(fn);
 | 
			
		||||
  } else {
 | 
			
		||||
    fn(val);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const addAndConvert = (main, prop, item) => {
 | 
			
		||||
  let container = main[prop];
 | 
			
		||||
  if (!(container instanceof Set)) {
 | 
			
		||||
    main[prop] = container = new Set([container]);
 | 
			
		||||
  }
 | 
			
		||||
  container.add(item);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const clearItem = cont => key => {
 | 
			
		||||
  const set = cont[key];
 | 
			
		||||
  if (set instanceof Set) {
 | 
			
		||||
    set.clear();
 | 
			
		||||
  } else {
 | 
			
		||||
    delete cont[key];
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const delFromSet = (main, prop, item) => {
 | 
			
		||||
  const container = main[prop];
 | 
			
		||||
  if (container instanceof Set) {
 | 
			
		||||
    container.delete(item);
 | 
			
		||||
  } else if (container === item) {
 | 
			
		||||
    delete main[prop];
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef {String} Path
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// fs_watch helpers
 | 
			
		||||
 | 
			
		||||
// object to hold per-process fs_watch instances
 | 
			
		||||
// (may be shared across chokidar FSWatcher instances)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef {Object} FsWatchContainer
 | 
			
		||||
 * @property {Set} listeners
 | 
			
		||||
 * @property {Set} errHandlers
 | 
			
		||||
 * @property {Set} rawEmitters
 | 
			
		||||
 * @property {fs.FSWatcher=} watcher
 | 
			
		||||
 * @property {Boolean=} watcherUnusable
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @type {Map<String,FsWatchContainer>}
 | 
			
		||||
 */
 | 
			
		||||
const FsWatchInstances = new Map();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Instantiates the fs_watch interface
 | 
			
		||||
 * @param {String} path to be watched
 | 
			
		||||
 * @param {Object} options to be passed to fs_watch
 | 
			
		||||
 * @param {Function} listener main event handler
 | 
			
		||||
 * @param {Function} errHandler emits info about errors
 | 
			
		||||
 * @param {Function} emitRaw emits raw event data
 | 
			
		||||
 * @returns {fs.FSWatcher} new fsevents instance
 | 
			
		||||
 */
 | 
			
		||||
function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
 | 
			
		||||
  const handleEvent = (rawEvent, evPath) => {
 | 
			
		||||
    listener(path);
 | 
			
		||||
    emitRaw(rawEvent, evPath, {watchedPath: path});
 | 
			
		||||
 | 
			
		||||
    // emit based on events occurring for files from a directory's watcher in
 | 
			
		||||
    // case the file's watcher misses it (and rely on throttling to de-dupe)
 | 
			
		||||
    if (evPath && path !== evPath) {
 | 
			
		||||
      fsWatchBroadcast(
 | 
			
		||||
        sysPath.resolve(path, evPath), KEY_LISTENERS, sysPath.join(path, evPath)
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  try {
 | 
			
		||||
    return fs.watch(path, options, handleEvent);
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    errHandler(error);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper for passing fs_watch event data to a collection of listeners
 | 
			
		||||
 * @param {Path} fullPath absolute path bound to fs_watch instance
 | 
			
		||||
 * @param {String} type listener type
 | 
			
		||||
 * @param {*=} val1 arguments to be passed to listeners
 | 
			
		||||
 * @param {*=} val2
 | 
			
		||||
 * @param {*=} val3
 | 
			
		||||
 */
 | 
			
		||||
const fsWatchBroadcast = (fullPath, type, val1, val2, val3) => {
 | 
			
		||||
  const cont = FsWatchInstances.get(fullPath);
 | 
			
		||||
  if (!cont) return;
 | 
			
		||||
  foreach(cont[type], (listener) => {
 | 
			
		||||
    listener(val1, val2, val3);
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Instantiates the fs_watch interface or binds listeners
 | 
			
		||||
 * to an existing one covering the same file system entry
 | 
			
		||||
 * @param {String} path
 | 
			
		||||
 * @param {String} fullPath absolute path
 | 
			
		||||
 * @param {Object} options to be passed to fs_watch
 | 
			
		||||
 * @param {Object} handlers container for event listener functions
 | 
			
		||||
 */
 | 
			
		||||
const setFsWatchListener = (path, fullPath, options, handlers) => {
 | 
			
		||||
  const {listener, errHandler, rawEmitter} = handlers;
 | 
			
		||||
  let cont = FsWatchInstances.get(fullPath);
 | 
			
		||||
 | 
			
		||||
  /** @type {fs.FSWatcher=} */
 | 
			
		||||
  let watcher;
 | 
			
		||||
  if (!options.persistent) {
 | 
			
		||||
    watcher = createFsWatchInstance(
 | 
			
		||||
      path, options, listener, errHandler, rawEmitter
 | 
			
		||||
    );
 | 
			
		||||
    return watcher.close.bind(watcher);
 | 
			
		||||
  }
 | 
			
		||||
  if (cont) {
 | 
			
		||||
    addAndConvert(cont, KEY_LISTENERS, listener);
 | 
			
		||||
    addAndConvert(cont, KEY_ERR, errHandler);
 | 
			
		||||
    addAndConvert(cont, KEY_RAW, rawEmitter);
 | 
			
		||||
  } else {
 | 
			
		||||
    watcher = createFsWatchInstance(
 | 
			
		||||
      path,
 | 
			
		||||
      options,
 | 
			
		||||
      fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
 | 
			
		||||
      errHandler, // no need to use broadcast here
 | 
			
		||||
      fsWatchBroadcast.bind(null, fullPath, KEY_RAW)
 | 
			
		||||
    );
 | 
			
		||||
    if (!watcher) return;
 | 
			
		||||
    watcher.on(EV_ERROR, async (error) => {
 | 
			
		||||
      const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR);
 | 
			
		||||
      cont.watcherUnusable = true; // documented since Node 10.4.1
 | 
			
		||||
      // Workaround for https://github.com/joyent/node/issues/4337
 | 
			
		||||
      if (isWindows && error.code === 'EPERM') {
 | 
			
		||||
        try {
 | 
			
		||||
          const fd = await open(path, 'r');
 | 
			
		||||
          await close(fd);
 | 
			
		||||
          broadcastErr(error);
 | 
			
		||||
        } catch (err) {}
 | 
			
		||||
      } else {
 | 
			
		||||
        broadcastErr(error);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    cont = {
 | 
			
		||||
      listeners: listener,
 | 
			
		||||
      errHandlers: errHandler,
 | 
			
		||||
      rawEmitters: rawEmitter,
 | 
			
		||||
      watcher
 | 
			
		||||
    };
 | 
			
		||||
    FsWatchInstances.set(fullPath, cont);
 | 
			
		||||
  }
 | 
			
		||||
  // const index = cont.listeners.indexOf(listener);
 | 
			
		||||
 | 
			
		||||
  // removes this instance's listeners and closes the underlying fs_watch
 | 
			
		||||
  // instance if there are no more listeners left
 | 
			
		||||
  return () => {
 | 
			
		||||
    delFromSet(cont, KEY_LISTENERS, listener);
 | 
			
		||||
    delFromSet(cont, KEY_ERR, errHandler);
 | 
			
		||||
    delFromSet(cont, KEY_RAW, rawEmitter);
 | 
			
		||||
    if (isEmptySet(cont.listeners)) {
 | 
			
		||||
      // Check to protect against issue gh-730.
 | 
			
		||||
      // if (cont.watcherUnusable) {
 | 
			
		||||
      cont.watcher.close();
 | 
			
		||||
      // }
 | 
			
		||||
      FsWatchInstances.delete(fullPath);
 | 
			
		||||
      HANDLER_KEYS.forEach(clearItem(cont));
 | 
			
		||||
      cont.watcher = undefined;
 | 
			
		||||
      Object.freeze(cont);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// fs_watchFile helpers
 | 
			
		||||
 | 
			
		||||
// object to hold per-process fs_watchFile instances
 | 
			
		||||
// (may be shared across chokidar FSWatcher instances)
 | 
			
		||||
const FsWatchFileInstances = new Map();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Instantiates the fs_watchFile interface or binds listeners
 | 
			
		||||
 * to an existing one covering the same file system entry
 | 
			
		||||
 * @param {String} path to be watched
 | 
			
		||||
 * @param {String} fullPath absolute path
 | 
			
		||||
 * @param {Object} options options to be passed to fs_watchFile
 | 
			
		||||
 * @param {Object} handlers container for event listener functions
 | 
			
		||||
 * @returns {Function} closer
 | 
			
		||||
 */
 | 
			
		||||
const setFsWatchFileListener = (path, fullPath, options, handlers) => {
 | 
			
		||||
  const {listener, rawEmitter} = handlers;
 | 
			
		||||
  let cont = FsWatchFileInstances.get(fullPath);
 | 
			
		||||
 | 
			
		||||
  /* eslint-disable no-unused-vars, prefer-destructuring */
 | 
			
		||||
  let listeners = new Set();
 | 
			
		||||
  let rawEmitters = new Set();
 | 
			
		||||
 | 
			
		||||
  const copts = cont && cont.options;
 | 
			
		||||
  if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
 | 
			
		||||
    // "Upgrade" the watcher to persistence or a quicker interval.
 | 
			
		||||
    // This creates some unlikely edge case issues if the user mixes
 | 
			
		||||
    // settings in a very weird way, but solving for those cases
 | 
			
		||||
    // doesn't seem worthwhile for the added complexity.
 | 
			
		||||
    listeners = cont.listeners;
 | 
			
		||||
    rawEmitters = cont.rawEmitters;
 | 
			
		||||
    fs.unwatchFile(fullPath);
 | 
			
		||||
    cont = undefined;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* eslint-enable no-unused-vars, prefer-destructuring */
 | 
			
		||||
 | 
			
		||||
  if (cont) {
 | 
			
		||||
    addAndConvert(cont, KEY_LISTENERS, listener);
 | 
			
		||||
    addAndConvert(cont, KEY_RAW, rawEmitter);
 | 
			
		||||
  } else {
 | 
			
		||||
    // TODO
 | 
			
		||||
    // listeners.add(listener);
 | 
			
		||||
    // rawEmitters.add(rawEmitter);
 | 
			
		||||
    cont = {
 | 
			
		||||
      listeners: listener,
 | 
			
		||||
      rawEmitters: rawEmitter,
 | 
			
		||||
      options,
 | 
			
		||||
      watcher: fs.watchFile(fullPath, options, (curr, prev) => {
 | 
			
		||||
        foreach(cont.rawEmitters, (rawEmitter) => {
 | 
			
		||||
          rawEmitter(EV_CHANGE, fullPath, {curr, prev});
 | 
			
		||||
        });
 | 
			
		||||
        const currmtime = curr.mtimeMs;
 | 
			
		||||
        if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
 | 
			
		||||
          foreach(cont.listeners, (listener) => listener(path, curr));
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    };
 | 
			
		||||
    FsWatchFileInstances.set(fullPath, cont);
 | 
			
		||||
  }
 | 
			
		||||
  // const index = cont.listeners.indexOf(listener);
 | 
			
		||||
 | 
			
		||||
  // Removes this instance's listeners and closes the underlying fs_watchFile
 | 
			
		||||
  // instance if there are no more listeners left.
 | 
			
		||||
  return () => {
 | 
			
		||||
    delFromSet(cont, KEY_LISTENERS, listener);
 | 
			
		||||
    delFromSet(cont, KEY_RAW, rawEmitter);
 | 
			
		||||
    if (isEmptySet(cont.listeners)) {
 | 
			
		||||
      FsWatchFileInstances.delete(fullPath);
 | 
			
		||||
      fs.unwatchFile(fullPath);
 | 
			
		||||
      cont.options = cont.watcher = undefined;
 | 
			
		||||
      Object.freeze(cont);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @mixin
 | 
			
		||||
 */
 | 
			
		||||
class NodeFsHandler {
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {import("../index").FSWatcher} fsW
 | 
			
		||||
 */
 | 
			
		||||
constructor(fsW) {
 | 
			
		||||
  this.fsw = fsW;
 | 
			
		||||
  this._boundHandleError = (error) => fsW._handleError(error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Watch file for changes with fs_watchFile or fs_watch.
 | 
			
		||||
 * @param {String} path to file or dir
 | 
			
		||||
 * @param {Function} listener on fs change
 | 
			
		||||
 * @returns {Function} closer for the watcher instance
 | 
			
		||||
 */
 | 
			
		||||
_watchWithNodeFs(path, listener) {
 | 
			
		||||
  const opts = this.fsw.options;
 | 
			
		||||
  const directory = sysPath.dirname(path);
 | 
			
		||||
  const basename = sysPath.basename(path);
 | 
			
		||||
  const parent = this.fsw._getWatchedDir(directory);
 | 
			
		||||
  parent.add(basename);
 | 
			
		||||
  const absolutePath = sysPath.resolve(path);
 | 
			
		||||
  const options = {persistent: opts.persistent};
 | 
			
		||||
  if (!listener) listener = EMPTY_FN;
 | 
			
		||||
 | 
			
		||||
  let closer;
 | 
			
		||||
  if (opts.usePolling) {
 | 
			
		||||
    options.interval = opts.enableBinaryInterval && isBinaryPath(basename) ?
 | 
			
		||||
      opts.binaryInterval : opts.interval;
 | 
			
		||||
    closer = setFsWatchFileListener(path, absolutePath, options, {
 | 
			
		||||
      listener,
 | 
			
		||||
      rawEmitter: this.fsw._emitRaw
 | 
			
		||||
    });
 | 
			
		||||
  } else {
 | 
			
		||||
    closer = setFsWatchListener(path, absolutePath, options, {
 | 
			
		||||
      listener,
 | 
			
		||||
      errHandler: this._boundHandleError,
 | 
			
		||||
      rawEmitter: this.fsw._emitRaw
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  return closer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Watch a file and emit add event if warranted.
 | 
			
		||||
 * @param {Path} file Path
 | 
			
		||||
 * @param {fs.Stats} stats result of fs_stat
 | 
			
		||||
 * @param {Boolean} initialAdd was the file added at watch instantiation?
 | 
			
		||||
 * @returns {Function} closer for the watcher instance
 | 
			
		||||
 */
 | 
			
		||||
_handleFile(file, stats, initialAdd) {
 | 
			
		||||
  if (this.fsw.closed) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  const dirname = sysPath.dirname(file);
 | 
			
		||||
  const basename = sysPath.basename(file);
 | 
			
		||||
  const parent = this.fsw._getWatchedDir(dirname);
 | 
			
		||||
  // stats is always present
 | 
			
		||||
  let prevStats = stats;
 | 
			
		||||
 | 
			
		||||
  // if the file is already being watched, do nothing
 | 
			
		||||
  if (parent.has(basename)) return;
 | 
			
		||||
 | 
			
		||||
  const listener = async (path, newStats) => {
 | 
			
		||||
    if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5)) return;
 | 
			
		||||
    if (!newStats || newStats.mtimeMs === 0) {
 | 
			
		||||
      try {
 | 
			
		||||
        const newStats = await stat(file);
 | 
			
		||||
        if (this.fsw.closed) return;
 | 
			
		||||
        // Check that change event was not fired because of changed only accessTime.
 | 
			
		||||
        const at = newStats.atimeMs;
 | 
			
		||||
        const mt = newStats.mtimeMs;
 | 
			
		||||
        if (!at || at <= mt || mt !== prevStats.mtimeMs) {
 | 
			
		||||
          this.fsw._emit(EV_CHANGE, file, newStats);
 | 
			
		||||
        }
 | 
			
		||||
        if (isLinux && prevStats.ino !== newStats.ino) {
 | 
			
		||||
          this.fsw._closeFile(path)
 | 
			
		||||
          prevStats = newStats;
 | 
			
		||||
          this.fsw._addPathCloser(path, this._watchWithNodeFs(file, listener));
 | 
			
		||||
        } else {
 | 
			
		||||
          prevStats = newStats;
 | 
			
		||||
        }
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        // Fix issues where mtime is null but file is still present
 | 
			
		||||
        this.fsw._remove(dirname, basename);
 | 
			
		||||
      }
 | 
			
		||||
      // add is about to be emitted if file not already tracked in parent
 | 
			
		||||
    } else if (parent.has(basename)) {
 | 
			
		||||
      // Check that change event was not fired because of changed only accessTime.
 | 
			
		||||
      const at = newStats.atimeMs;
 | 
			
		||||
      const mt = newStats.mtimeMs;
 | 
			
		||||
      if (!at || at <= mt || mt !== prevStats.mtimeMs) {
 | 
			
		||||
        this.fsw._emit(EV_CHANGE, file, newStats);
 | 
			
		||||
      }
 | 
			
		||||
      prevStats = newStats;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // kick off the watcher
 | 
			
		||||
  const closer = this._watchWithNodeFs(file, listener);
 | 
			
		||||
 | 
			
		||||
  // emit an add event if we're supposed to
 | 
			
		||||
  if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) {
 | 
			
		||||
    if (!this.fsw._throttle(EV_ADD, file, 0)) return;
 | 
			
		||||
    this.fsw._emit(EV_ADD, file, stats);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return closer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handle symlinks encountered while reading a dir.
 | 
			
		||||
 * @param {Object} entry returned by readdirp
 | 
			
		||||
 * @param {String} directory path of dir being read
 | 
			
		||||
 * @param {String} path of this item
 | 
			
		||||
 * @param {String} item basename of this item
 | 
			
		||||
 * @returns {Promise<Boolean>} true if no more processing is needed for this entry.
 | 
			
		||||
 */
 | 
			
		||||
async _handleSymlink(entry, directory, path, item) {
 | 
			
		||||
  if (this.fsw.closed) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  const full = entry.fullPath;
 | 
			
		||||
  const dir = this.fsw._getWatchedDir(directory);
 | 
			
		||||
 | 
			
		||||
  if (!this.fsw.options.followSymlinks) {
 | 
			
		||||
    // watch symlink directly (don't follow) and detect changes
 | 
			
		||||
    this.fsw._incrReadyCount();
 | 
			
		||||
 | 
			
		||||
    let linkPath;
 | 
			
		||||
    try {
 | 
			
		||||
      linkPath = await fsrealpath(path);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      this.fsw._emitReady();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this.fsw.closed) return;
 | 
			
		||||
    if (dir.has(item)) {
 | 
			
		||||
      if (this.fsw._symlinkPaths.get(full) !== linkPath) {
 | 
			
		||||
        this.fsw._symlinkPaths.set(full, linkPath);
 | 
			
		||||
        this.fsw._emit(EV_CHANGE, path, entry.stats);
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      dir.add(item);
 | 
			
		||||
      this.fsw._symlinkPaths.set(full, linkPath);
 | 
			
		||||
      this.fsw._emit(EV_ADD, path, entry.stats);
 | 
			
		||||
    }
 | 
			
		||||
    this.fsw._emitReady();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // don't follow the same symlink more than once
 | 
			
		||||
  if (this.fsw._symlinkPaths.has(full)) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this.fsw._symlinkPaths.set(full, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {
 | 
			
		||||
  // Normalize the directory name on Windows
 | 
			
		||||
  directory = sysPath.join(directory, EMPTY_STR);
 | 
			
		||||
 | 
			
		||||
  if (!wh.hasGlob) {
 | 
			
		||||
    throttler = this.fsw._throttle('readdir', directory, 1000);
 | 
			
		||||
    if (!throttler) return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const previous = this.fsw._getWatchedDir(wh.path);
 | 
			
		||||
  const current = new Set();
 | 
			
		||||
 | 
			
		||||
  let stream = this.fsw._readdirp(directory, {
 | 
			
		||||
    fileFilter: entry => wh.filterPath(entry),
 | 
			
		||||
    directoryFilter: entry => wh.filterDir(entry),
 | 
			
		||||
    depth: 0
 | 
			
		||||
  }).on(STR_DATA, async (entry) => {
 | 
			
		||||
    if (this.fsw.closed) {
 | 
			
		||||
      stream = undefined;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const item = entry.path;
 | 
			
		||||
    let path = sysPath.join(directory, item);
 | 
			
		||||
    current.add(item);
 | 
			
		||||
 | 
			
		||||
    if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path, item)) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this.fsw.closed) {
 | 
			
		||||
      stream = undefined;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    // Files that present in current directory snapshot
 | 
			
		||||
    // but absent in previous are added to watch list and
 | 
			
		||||
    // emit `add` event.
 | 
			
		||||
    if (item === target || !target && !previous.has(item)) {
 | 
			
		||||
      this.fsw._incrReadyCount();
 | 
			
		||||
 | 
			
		||||
      // ensure relativeness of path is preserved in case of watcher reuse
 | 
			
		||||
      path = sysPath.join(dir, sysPath.relative(dir, path));
 | 
			
		||||
 | 
			
		||||
      this._addToNodeFs(path, initialAdd, wh, depth + 1);
 | 
			
		||||
    }
 | 
			
		||||
  }).on(EV_ERROR, this._boundHandleError);
 | 
			
		||||
 | 
			
		||||
  return new Promise(resolve =>
 | 
			
		||||
    stream.once(STR_END, () => {
 | 
			
		||||
      if (this.fsw.closed) {
 | 
			
		||||
        stream = undefined;
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      const wasThrottled = throttler ? throttler.clear() : false;
 | 
			
		||||
 | 
			
		||||
      resolve();
 | 
			
		||||
 | 
			
		||||
      // Files that absent in current directory snapshot
 | 
			
		||||
      // but present in previous emit `remove` event
 | 
			
		||||
      // and are removed from @watched[directory].
 | 
			
		||||
      previous.getChildren().filter((item) => {
 | 
			
		||||
        return item !== directory &&
 | 
			
		||||
          !current.has(item) &&
 | 
			
		||||
          // in case of intersecting globs;
 | 
			
		||||
          // a path may have been filtered out of this readdir, but
 | 
			
		||||
          // shouldn't be removed because it matches a different glob
 | 
			
		||||
          (!wh.hasGlob || wh.filterPath({
 | 
			
		||||
            fullPath: sysPath.resolve(directory, item)
 | 
			
		||||
          }));
 | 
			
		||||
      }).forEach((item) => {
 | 
			
		||||
        this.fsw._remove(directory, item);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      stream = undefined;
 | 
			
		||||
 | 
			
		||||
      // one more time for any missed in case changes came in extremely quickly
 | 
			
		||||
      if (wasThrottled) this._handleRead(directory, false, wh, target, dir, depth, throttler);
 | 
			
		||||
    })
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Read directory to add / remove files from `@watched` list and re-read it on change.
 | 
			
		||||
 * @param {String} dir fs path
 | 
			
		||||
 * @param {fs.Stats} stats
 | 
			
		||||
 * @param {Boolean} initialAdd
 | 
			
		||||
 * @param {Number} depth relative to user-supplied path
 | 
			
		||||
 * @param {String} target child path targeted for watch
 | 
			
		||||
 * @param {Object} wh Common watch helpers for this path
 | 
			
		||||
 * @param {String} realpath
 | 
			
		||||
 * @returns {Promise<Function>} closer for the watcher instance.
 | 
			
		||||
 */
 | 
			
		||||
async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath) {
 | 
			
		||||
  const parentDir = this.fsw._getWatchedDir(sysPath.dirname(dir));
 | 
			
		||||
  const tracked = parentDir.has(sysPath.basename(dir));
 | 
			
		||||
  if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {
 | 
			
		||||
    if (!wh.hasGlob || wh.globFilter(dir)) this.fsw._emit(EV_ADD_DIR, dir, stats);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // ensure dir is tracked (harmless if redundant)
 | 
			
		||||
  parentDir.add(sysPath.basename(dir));
 | 
			
		||||
  this.fsw._getWatchedDir(dir);
 | 
			
		||||
  let throttler;
 | 
			
		||||
  let closer;
 | 
			
		||||
 | 
			
		||||
  const oDepth = this.fsw.options.depth;
 | 
			
		||||
  if ((oDepth == null || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath)) {
 | 
			
		||||
    if (!target) {
 | 
			
		||||
      await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler);
 | 
			
		||||
      if (this.fsw.closed) return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    closer = this._watchWithNodeFs(dir, (dirPath, stats) => {
 | 
			
		||||
      // if current directory is removed, do nothing
 | 
			
		||||
      if (stats && stats.mtimeMs === 0) return;
 | 
			
		||||
 | 
			
		||||
      this._handleRead(dirPath, false, wh, target, dir, depth, throttler);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  return closer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handle added file, directory, or glob pattern.
 | 
			
		||||
 * Delegates call to _handleFile / _handleDir after checks.
 | 
			
		||||
 * @param {String} path to file or ir
 | 
			
		||||
 * @param {Boolean} initialAdd was the file added at watch instantiation?
 | 
			
		||||
 * @param {Object} priorWh depth relative to user-supplied path
 | 
			
		||||
 * @param {Number} depth Child path actually targeted for watch
 | 
			
		||||
 * @param {String=} target Child path actually targeted for watch
 | 
			
		||||
 * @returns {Promise}
 | 
			
		||||
 */
 | 
			
		||||
async _addToNodeFs(path, initialAdd, priorWh, depth, target) {
 | 
			
		||||
  const ready = this.fsw._emitReady;
 | 
			
		||||
  if (this.fsw._isIgnored(path) || this.fsw.closed) {
 | 
			
		||||
    ready();
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const wh = this.fsw._getWatchHelpers(path, depth);
 | 
			
		||||
  if (!wh.hasGlob && priorWh) {
 | 
			
		||||
    wh.hasGlob = priorWh.hasGlob;
 | 
			
		||||
    wh.globFilter = priorWh.globFilter;
 | 
			
		||||
    wh.filterPath = entry => priorWh.filterPath(entry);
 | 
			
		||||
    wh.filterDir = entry => priorWh.filterDir(entry);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // evaluate what is at the path we're being asked to watch
 | 
			
		||||
  try {
 | 
			
		||||
    const stats = await statMethods[wh.statMethod](wh.watchPath);
 | 
			
		||||
    if (this.fsw.closed) return;
 | 
			
		||||
    if (this.fsw._isIgnored(wh.watchPath, stats)) {
 | 
			
		||||
      ready();
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const follow = this.fsw.options.followSymlinks && !path.includes(STAR) && !path.includes(BRACE_START);
 | 
			
		||||
    let closer;
 | 
			
		||||
    if (stats.isDirectory()) {
 | 
			
		||||
      const absPath = sysPath.resolve(path);
 | 
			
		||||
      const targetPath = follow ? await fsrealpath(path) : path;
 | 
			
		||||
      if (this.fsw.closed) return;
 | 
			
		||||
      closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
 | 
			
		||||
      if (this.fsw.closed) return;
 | 
			
		||||
      // preserve this symlink's target path
 | 
			
		||||
      if (absPath !== targetPath && targetPath !== undefined) {
 | 
			
		||||
        this.fsw._symlinkPaths.set(absPath, targetPath);
 | 
			
		||||
      }
 | 
			
		||||
    } else if (stats.isSymbolicLink()) {
 | 
			
		||||
      const targetPath = follow ? await fsrealpath(path) : path;
 | 
			
		||||
      if (this.fsw.closed) return;
 | 
			
		||||
      const parent = sysPath.dirname(wh.watchPath);
 | 
			
		||||
      this.fsw._getWatchedDir(parent).add(wh.watchPath);
 | 
			
		||||
      this.fsw._emit(EV_ADD, wh.watchPath, stats);
 | 
			
		||||
      closer = await this._handleDir(parent, stats, initialAdd, depth, path, wh, targetPath);
 | 
			
		||||
      if (this.fsw.closed) return;
 | 
			
		||||
 | 
			
		||||
      // preserve this symlink's target path
 | 
			
		||||
      if (targetPath !== undefined) {
 | 
			
		||||
        this.fsw._symlinkPaths.set(sysPath.resolve(path), targetPath);
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      closer = this._handleFile(wh.watchPath, stats, initialAdd);
 | 
			
		||||
    }
 | 
			
		||||
    ready();
 | 
			
		||||
 | 
			
		||||
    this.fsw._addPathCloser(path, closer);
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    if (this.fsw._handleError(error)) {
 | 
			
		||||
      ready();
 | 
			
		||||
      return path;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = NodeFsHandler;
 | 
			
		||||
							
								
								
									
										110
									
								
								node_modules/chokidar/node_modules/glob-parent/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								node_modules/chokidar/node_modules/glob-parent/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
### [5.1.2](https://github.com/gulpjs/glob-parent/compare/v5.1.1...v5.1.2) (2021-03-06)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Bug Fixes
 | 
			
		||||
 | 
			
		||||
* eliminate ReDoS ([#36](https://github.com/gulpjs/glob-parent/issues/36)) ([f923116](https://github.com/gulpjs/glob-parent/commit/f9231168b0041fea3f8f954b3cceb56269fc6366))
 | 
			
		||||
 | 
			
		||||
### [5.1.1](https://github.com/gulpjs/glob-parent/compare/v5.1.0...v5.1.1) (2021-01-27)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Bug Fixes
 | 
			
		||||
 | 
			
		||||
* unescape exclamation mark ([#26](https://github.com/gulpjs/glob-parent/issues/26)) ([a98874f](https://github.com/gulpjs/glob-parent/commit/a98874f1a59e407f4fb1beb0db4efa8392da60bb))
 | 
			
		||||
 | 
			
		||||
## [5.1.0](https://github.com/gulpjs/glob-parent/compare/v5.0.0...v5.1.0) (2021-01-27)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
* add `flipBackslashes` option to disable auto conversion of slashes (closes [#24](https://github.com/gulpjs/glob-parent/issues/24)) ([#25](https://github.com/gulpjs/glob-parent/issues/25)) ([eecf91d](https://github.com/gulpjs/glob-parent/commit/eecf91d5e3834ed78aee39c4eaaae654d76b87b3))
 | 
			
		||||
 | 
			
		||||
## [5.0.0](https://github.com/gulpjs/glob-parent/compare/v4.0.0...v5.0.0) (2021-01-27)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### ⚠ BREAKING CHANGES
 | 
			
		||||
 | 
			
		||||
* Drop support for node <6 & bump dependencies
 | 
			
		||||
 | 
			
		||||
### Miscellaneous Chores
 | 
			
		||||
 | 
			
		||||
* Drop support for node <6 & bump dependencies ([896c0c0](https://github.com/gulpjs/glob-parent/commit/896c0c00b4e7362f60b96e7fc295ae929245255a))
 | 
			
		||||
 | 
			
		||||
## [4.0.0](https://github.com/gulpjs/glob-parent/compare/v3.1.0...v4.0.0) (2021-01-27)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### ⚠ BREAKING CHANGES
 | 
			
		||||
 | 
			
		||||
* question marks are valid path characters on Windows so avoid flagging as a glob when alone
 | 
			
		||||
* Update is-glob dependency
 | 
			
		||||
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
* hoist regexps and strings for performance gains ([4a80667](https://github.com/gulpjs/glob-parent/commit/4a80667c69355c76a572a5892b0f133c8e1f457e))
 | 
			
		||||
* question marks are valid path characters on Windows so avoid flagging as a glob when alone ([2a551dd](https://github.com/gulpjs/glob-parent/commit/2a551dd0dc3235e78bf3c94843d4107072d17841))
 | 
			
		||||
* Update is-glob dependency ([e41fcd8](https://github.com/gulpjs/glob-parent/commit/e41fcd895d1f7bc617dba45c9d935a7949b9c281))
 | 
			
		||||
 | 
			
		||||
## [3.1.0](https://github.com/gulpjs/glob-parent/compare/v3.0.1...v3.1.0) (2021-01-27)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
* allow basic win32 backslash use ([272afa5](https://github.com/gulpjs/glob-parent/commit/272afa5fd070fc0f796386a5993d4ee4a846988b))
 | 
			
		||||
* handle extglobs (parentheses) containing separators ([7db1bdb](https://github.com/gulpjs/glob-parent/commit/7db1bdb0756e55fd14619e8ce31aa31b17b117fd))
 | 
			
		||||
* new approach to braces/brackets handling ([8269bd8](https://github.com/gulpjs/glob-parent/commit/8269bd89290d99fac9395a354fb56fdcdb80f0be))
 | 
			
		||||
* pre-process braces/brackets sections ([9ef8a87](https://github.com/gulpjs/glob-parent/commit/9ef8a87f66b1a43d0591e7a8e4fc5a18415ee388))
 | 
			
		||||
* preserve escaped brace/bracket at end of string ([8cfb0ba](https://github.com/gulpjs/glob-parent/commit/8cfb0ba84202d51571340dcbaf61b79d16a26c76))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Bug Fixes
 | 
			
		||||
 | 
			
		||||
* trailing escaped square brackets ([99ec9fe](https://github.com/gulpjs/glob-parent/commit/99ec9fecc60ee488ded20a94dd4f18b4f55c4ccf))
 | 
			
		||||
 | 
			
		||||
### [3.0.1](https://github.com/gulpjs/glob-parent/compare/v3.0.0...v3.0.1) (2021-01-27)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
* use path-dirname ponyfill ([cdbea5f](https://github.com/gulpjs/glob-parent/commit/cdbea5f32a58a54e001a75ddd7c0fccd4776aacc))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Bug Fixes
 | 
			
		||||
 | 
			
		||||
* unescape glob-escaped dirnames on output ([598c533](https://github.com/gulpjs/glob-parent/commit/598c533bdf49c1428bc063aa9b8db40c5a86b030))
 | 
			
		||||
 | 
			
		||||
## [3.0.0](https://github.com/gulpjs/glob-parent/compare/v2.0.0...v3.0.0) (2021-01-27)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### ⚠ BREAKING CHANGES
 | 
			
		||||
 | 
			
		||||
* update is-glob dependency
 | 
			
		||||
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
* update is-glob dependency ([5c5f8ef](https://github.com/gulpjs/glob-parent/commit/5c5f8efcee362a8e7638cf8220666acd8784f6bd))
 | 
			
		||||
 | 
			
		||||
## [2.0.0](https://github.com/gulpjs/glob-parent/compare/v1.3.0...v2.0.0) (2021-01-27)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
* move up to dirname regardless of glob characters ([f97fb83](https://github.com/gulpjs/glob-parent/commit/f97fb83be2e0a9fc8d3b760e789d2ecadd6aa0c2))
 | 
			
		||||
 | 
			
		||||
## [1.3.0](https://github.com/gulpjs/glob-parent/compare/v1.2.0...v1.3.0) (2021-01-27)
 | 
			
		||||
 | 
			
		||||
## [1.2.0](https://github.com/gulpjs/glob-parent/compare/v1.1.0...v1.2.0) (2021-01-27)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Reverts
 | 
			
		||||
 | 
			
		||||
* feat: make regex test strings smaller ([dc80fa9](https://github.com/gulpjs/glob-parent/commit/dc80fa9658dca20549cfeba44bbd37d5246fcce0))
 | 
			
		||||
 | 
			
		||||
## [1.1.0](https://github.com/gulpjs/glob-parent/compare/v1.0.0...v1.1.0) (2021-01-27)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
* make regex test strings smaller ([cd83220](https://github.com/gulpjs/glob-parent/commit/cd832208638f45169f986d80fcf66e401f35d233))
 | 
			
		||||
 | 
			
		||||
## 1.0.0 (2021-01-27)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								node_modules/chokidar/node_modules/glob-parent/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								node_modules/chokidar/node_modules/glob-parent/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
The ISC License
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2015, 2019 Elan Shanker
 | 
			
		||||
 | 
			
		||||
Permission to use, copy, modify, and/or distribute this software for any
 | 
			
		||||
purpose with or without fee is hereby granted, provided that the above
 | 
			
		||||
copyright notice and this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
			
		||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
			
		||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
			
		||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
			
		||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
			
		||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
 | 
			
		||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
							
								
								
									
										137
									
								
								node_modules/chokidar/node_modules/glob-parent/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								node_modules/chokidar/node_modules/glob-parent/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,137 @@
 | 
			
		||||
<p align="center">
 | 
			
		||||
  <a href="https://gulpjs.com">
 | 
			
		||||
    <img height="257" width="114" src="https://raw.githubusercontent.com/gulpjs/artwork/master/gulp-2x.png">
 | 
			
		||||
  </a>
 | 
			
		||||
</p>
 | 
			
		||||
 | 
			
		||||
# glob-parent
 | 
			
		||||
 | 
			
		||||
[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Azure Pipelines Build Status][azure-pipelines-image]][azure-pipelines-url] [![Travis Build Status][travis-image]][travis-url] [![AppVeyor Build Status][appveyor-image]][appveyor-url] [![Coveralls Status][coveralls-image]][coveralls-url] [![Gitter chat][gitter-image]][gitter-url]
 | 
			
		||||
 | 
			
		||||
Extract the non-magic parent path from a glob string.
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var globParent = require('glob-parent');
 | 
			
		||||
 | 
			
		||||
globParent('path/to/*.js'); // 'path/to'
 | 
			
		||||
globParent('/root/path/to/*.js'); // '/root/path/to'
 | 
			
		||||
globParent('/*.js'); // '/'
 | 
			
		||||
globParent('*.js'); // '.'
 | 
			
		||||
globParent('**/*.js'); // '.'
 | 
			
		||||
globParent('path/{to,from}'); // 'path'
 | 
			
		||||
globParent('path/!(to|from)'); // 'path'
 | 
			
		||||
globParent('path/?(to|from)'); // 'path'
 | 
			
		||||
globParent('path/+(to|from)'); // 'path'
 | 
			
		||||
globParent('path/*(to|from)'); // 'path'
 | 
			
		||||
globParent('path/@(to|from)'); // 'path'
 | 
			
		||||
globParent('path/**/*'); // 'path'
 | 
			
		||||
 | 
			
		||||
// if provided a non-glob path, returns the nearest dir
 | 
			
		||||
globParent('path/foo/bar.js'); // 'path/foo'
 | 
			
		||||
globParent('path/foo/'); // 'path/foo'
 | 
			
		||||
globParent('path/foo'); // 'path' (see issue #3 for details)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## API
 | 
			
		||||
 | 
			
		||||
### `globParent(maybeGlobString, [options])`
 | 
			
		||||
 | 
			
		||||
Takes a string and returns the part of the path before the glob begins. Be aware of Escaping rules and Limitations below.
 | 
			
		||||
 | 
			
		||||
#### options
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
{
 | 
			
		||||
  // Disables the automatic conversion of slashes for Windows
 | 
			
		||||
  flipBackslashes: true
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Escaping
 | 
			
		||||
 | 
			
		||||
The following characters have special significance in glob patterns and must be escaped if you want them to be treated as regular path characters:
 | 
			
		||||
 | 
			
		||||
- `?` (question mark) unless used as a path segment alone
 | 
			
		||||
- `*` (asterisk)
 | 
			
		||||
- `|` (pipe)
 | 
			
		||||
- `(` (opening parenthesis)
 | 
			
		||||
- `)` (closing parenthesis)
 | 
			
		||||
- `{` (opening curly brace)
 | 
			
		||||
- `}` (closing curly brace)
 | 
			
		||||
- `[` (opening bracket)
 | 
			
		||||
- `]` (closing bracket)
 | 
			
		||||
 | 
			
		||||
**Example**
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
globParent('foo/[bar]/') // 'foo'
 | 
			
		||||
globParent('foo/\\[bar]/') // 'foo/[bar]'
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Limitations
 | 
			
		||||
 | 
			
		||||
### Braces & Brackets
 | 
			
		||||
This library attempts a quick and imperfect method of determining which path
 | 
			
		||||
parts have glob magic without fully parsing/lexing the pattern. There are some
 | 
			
		||||
advanced use cases that can trip it up, such as nested braces where the outer
 | 
			
		||||
pair is escaped and the inner one contains a path separator. If you find
 | 
			
		||||
yourself in the unlikely circumstance of being affected by this or need to
 | 
			
		||||
ensure higher-fidelity glob handling in your library, it is recommended that you
 | 
			
		||||
pre-process your input with [expand-braces] and/or [expand-brackets].
 | 
			
		||||
 | 
			
		||||
### Windows
 | 
			
		||||
Backslashes are not valid path separators for globs. If a path with backslashes
 | 
			
		||||
is provided anyway, for simple cases, glob-parent will replace the path
 | 
			
		||||
separator for you and return the non-glob parent path (now with
 | 
			
		||||
forward-slashes, which are still valid as Windows path separators).
 | 
			
		||||
 | 
			
		||||
This cannot be used in conjunction with escape characters.
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// BAD
 | 
			
		||||
globParent('C:\\Program Files \\(x86\\)\\*.ext') // 'C:/Program Files /(x86/)'
 | 
			
		||||
 | 
			
		||||
// GOOD
 | 
			
		||||
globParent('C:/Program Files\\(x86\\)/*.ext') // 'C:/Program Files (x86)'
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If you are using escape characters for a pattern without path parts (i.e.
 | 
			
		||||
relative to `cwd`), prefix with `./` to avoid confusing glob-parent.
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// BAD
 | 
			
		||||
globParent('foo \\[bar]') // 'foo '
 | 
			
		||||
globParent('foo \\[bar]*') // 'foo '
 | 
			
		||||
 | 
			
		||||
// GOOD
 | 
			
		||||
globParent('./foo \\[bar]') // 'foo [bar]'
 | 
			
		||||
globParent('./foo \\[bar]*') // '.'
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## License
 | 
			
		||||
 | 
			
		||||
ISC
 | 
			
		||||
 | 
			
		||||
[expand-braces]: https://github.com/jonschlinkert/expand-braces
 | 
			
		||||
[expand-brackets]: https://github.com/jonschlinkert/expand-brackets
 | 
			
		||||
 | 
			
		||||
[downloads-image]: https://img.shields.io/npm/dm/glob-parent.svg
 | 
			
		||||
[npm-url]: https://www.npmjs.com/package/glob-parent
 | 
			
		||||
[npm-image]: https://img.shields.io/npm/v/glob-parent.svg
 | 
			
		||||
 | 
			
		||||
[azure-pipelines-url]: https://dev.azure.com/gulpjs/gulp/_build/latest?definitionId=2&branchName=master
 | 
			
		||||
[azure-pipelines-image]: https://dev.azure.com/gulpjs/gulp/_apis/build/status/glob-parent?branchName=master
 | 
			
		||||
 | 
			
		||||
[travis-url]: https://travis-ci.org/gulpjs/glob-parent
 | 
			
		||||
[travis-image]: https://img.shields.io/travis/gulpjs/glob-parent.svg?label=travis-ci
 | 
			
		||||
 | 
			
		||||
[appveyor-url]: https://ci.appveyor.com/project/gulpjs/glob-parent
 | 
			
		||||
[appveyor-image]: https://img.shields.io/appveyor/ci/gulpjs/glob-parent.svg?label=appveyor
 | 
			
		||||
 | 
			
		||||
[coveralls-url]: https://coveralls.io/r/gulpjs/glob-parent
 | 
			
		||||
[coveralls-image]: https://img.shields.io/coveralls/gulpjs/glob-parent/master.svg
 | 
			
		||||
 | 
			
		||||
[gitter-url]: https://gitter.im/gulpjs/gulp
 | 
			
		||||
[gitter-image]: https://badges.gitter.im/gulpjs/gulp.svg
 | 
			
		||||
							
								
								
									
										42
									
								
								node_modules/chokidar/node_modules/glob-parent/index.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								node_modules/chokidar/node_modules/glob-parent/index.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var isGlob = require('is-glob');
 | 
			
		||||
var pathPosixDirname = require('path').posix.dirname;
 | 
			
		||||
var isWin32 = require('os').platform() === 'win32';
 | 
			
		||||
 | 
			
		||||
var slash = '/';
 | 
			
		||||
var backslash = /\\/g;
 | 
			
		||||
var enclosure = /[\{\[].*[\}\]]$/;
 | 
			
		||||
var globby = /(^|[^\\])([\{\[]|\([^\)]+$)/;
 | 
			
		||||
var escaped = /\\([\!\*\?\|\[\]\(\)\{\}])/g;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {string} str
 | 
			
		||||
 * @param {Object} opts
 | 
			
		||||
 * @param {boolean} [opts.flipBackslashes=true]
 | 
			
		||||
 * @returns {string}
 | 
			
		||||
 */
 | 
			
		||||
module.exports = function globParent(str, opts) {
 | 
			
		||||
  var options = Object.assign({ flipBackslashes: true }, opts);
 | 
			
		||||
 | 
			
		||||
  // flip windows path separators
 | 
			
		||||
  if (options.flipBackslashes && isWin32 && str.indexOf(slash) < 0) {
 | 
			
		||||
    str = str.replace(backslash, slash);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // special case for strings ending in enclosure containing path separator
 | 
			
		||||
  if (enclosure.test(str)) {
 | 
			
		||||
    str += slash;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // preserves full path in case of trailing path separator
 | 
			
		||||
  str += 'a';
 | 
			
		||||
 | 
			
		||||
  // remove path parts that are globby
 | 
			
		||||
  do {
 | 
			
		||||
    str = pathPosixDirname(str);
 | 
			
		||||
  } while (isGlob(str) || globby.test(str));
 | 
			
		||||
 | 
			
		||||
  // remove escape chars and return result
 | 
			
		||||
  return str.replace(escaped, '$1');
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										48
									
								
								node_modules/chokidar/node_modules/glob-parent/package.json
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								node_modules/chokidar/node_modules/glob-parent/package.json
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "glob-parent",
 | 
			
		||||
  "version": "5.1.2",
 | 
			
		||||
  "description": "Extract the non-magic parent path from a glob string.",
 | 
			
		||||
  "author": "Gulp Team <team@gulpjs.com> (https://gulpjs.com/)",
 | 
			
		||||
  "contributors": [
 | 
			
		||||
    "Elan Shanker (https://github.com/es128)",
 | 
			
		||||
    "Blaine Bublitz <blaine.bublitz@gmail.com>"
 | 
			
		||||
  ],
 | 
			
		||||
  "repository": "gulpjs/glob-parent",
 | 
			
		||||
  "license": "ISC",
 | 
			
		||||
  "engines": {
 | 
			
		||||
    "node": ">= 6"
 | 
			
		||||
  },
 | 
			
		||||
  "main": "index.js",
 | 
			
		||||
  "files": [
 | 
			
		||||
    "LICENSE",
 | 
			
		||||
    "index.js"
 | 
			
		||||
  ],
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "lint": "eslint .",
 | 
			
		||||
    "pretest": "npm run lint",
 | 
			
		||||
    "test": "nyc mocha --async-only",
 | 
			
		||||
    "azure-pipelines": "nyc mocha --async-only --reporter xunit -O output=test.xunit",
 | 
			
		||||
    "coveralls": "nyc report --reporter=text-lcov | coveralls"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "is-glob": "^4.0.1"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "coveralls": "^3.0.11",
 | 
			
		||||
    "eslint": "^2.13.1",
 | 
			
		||||
    "eslint-config-gulp": "^3.0.1",
 | 
			
		||||
    "expect": "^1.20.2",
 | 
			
		||||
    "mocha": "^6.0.2",
 | 
			
		||||
    "nyc": "^13.3.0"
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "glob",
 | 
			
		||||
    "parent",
 | 
			
		||||
    "strip",
 | 
			
		||||
    "path",
 | 
			
		||||
    "dirname",
 | 
			
		||||
    "directory",
 | 
			
		||||
    "base",
 | 
			
		||||
    "wildcard"
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										85
									
								
								node_modules/chokidar/package.json
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								node_modules/chokidar/package.json
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "chokidar",
 | 
			
		||||
  "description": "Minimal and efficient cross-platform file watching library",
 | 
			
		||||
  "version": "3.5.3",
 | 
			
		||||
  "homepage": "https://github.com/paulmillr/chokidar",
 | 
			
		||||
  "author": "Paul Miller (https://paulmillr.com)",
 | 
			
		||||
  "contributors": [
 | 
			
		||||
    "Paul Miller (https://paulmillr.com)",
 | 
			
		||||
    "Elan Shanker"
 | 
			
		||||
  ],
 | 
			
		||||
  "engines": {
 | 
			
		||||
    "node": ">= 8.10.0"
 | 
			
		||||
  },
 | 
			
		||||
  "main": "index.js",
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "anymatch": "~3.1.2",
 | 
			
		||||
    "braces": "~3.0.2",
 | 
			
		||||
    "glob-parent": "~5.1.2",
 | 
			
		||||
    "is-binary-path": "~2.1.0",
 | 
			
		||||
    "is-glob": "~4.0.1",
 | 
			
		||||
    "normalize-path": "~3.0.0",
 | 
			
		||||
    "readdirp": "~3.6.0"
 | 
			
		||||
  },
 | 
			
		||||
  "optionalDependencies": {
 | 
			
		||||
    "fsevents": "~2.3.2"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@types/node": "^14",
 | 
			
		||||
    "chai": "^4.3",
 | 
			
		||||
    "dtslint": "^3.3.0",
 | 
			
		||||
    "eslint": "^7.0.0",
 | 
			
		||||
    "mocha": "^7.0.0",
 | 
			
		||||
    "nyc": "^15.0.0",
 | 
			
		||||
    "rimraf": "^3.0.0",
 | 
			
		||||
    "sinon": "^9.0.1",
 | 
			
		||||
    "sinon-chai": "^3.3.0",
 | 
			
		||||
    "typescript": "~4.4.3",
 | 
			
		||||
    "upath": "^1.2.0"
 | 
			
		||||
  },
 | 
			
		||||
  "files": [
 | 
			
		||||
    "index.js",
 | 
			
		||||
    "lib/*.js",
 | 
			
		||||
    "types/index.d.ts"
 | 
			
		||||
  ],
 | 
			
		||||
  "repository": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
    "url": "git+https://github.com/paulmillr/chokidar.git"
 | 
			
		||||
  },
 | 
			
		||||
  "bugs": {
 | 
			
		||||
    "url": "https://github.com/paulmillr/chokidar/issues"
 | 
			
		||||
  },
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "dtslint": "dtslint types",
 | 
			
		||||
    "lint": "eslint --report-unused-disable-directives --ignore-path .gitignore .",
 | 
			
		||||
    "mocha": "mocha --exit --timeout 90000",
 | 
			
		||||
    "test": "npm run lint && npm run mocha"
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "fs",
 | 
			
		||||
    "watch",
 | 
			
		||||
    "watchFile",
 | 
			
		||||
    "watcher",
 | 
			
		||||
    "watching",
 | 
			
		||||
    "file",
 | 
			
		||||
    "fsevents"
 | 
			
		||||
  ],
 | 
			
		||||
  "types": "./types/index.d.ts",
 | 
			
		||||
  "nyc": {
 | 
			
		||||
    "include": [
 | 
			
		||||
      "index.js",
 | 
			
		||||
      "lib/*.js"
 | 
			
		||||
    ],
 | 
			
		||||
    "reporter": [
 | 
			
		||||
      "html",
 | 
			
		||||
      "text"
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
  "funding": [
 | 
			
		||||
    {
 | 
			
		||||
      "type": "individual",
 | 
			
		||||
      "url": "https://paulmillr.com/funding/"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										188
									
								
								node_modules/chokidar/types/index.d.ts
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								node_modules/chokidar/types/index.d.ts
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,188 @@
 | 
			
		||||
// TypeScript Version: 3.0
 | 
			
		||||
 | 
			
		||||
/// <reference types="node" />
 | 
			
		||||
 | 
			
		||||
import * as fs from "fs";
 | 
			
		||||
import { EventEmitter } from "events";
 | 
			
		||||
import { Matcher } from 'anymatch';
 | 
			
		||||
 | 
			
		||||
export class FSWatcher extends EventEmitter implements fs.FSWatcher {
 | 
			
		||||
  options: WatchOptions;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Constructs a new FSWatcher instance with optional WatchOptions parameter.
 | 
			
		||||
   */
 | 
			
		||||
  constructor(options?: WatchOptions);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Add files, directories, or glob patterns for tracking. Takes an array of strings or just one
 | 
			
		||||
   * string.
 | 
			
		||||
   */
 | 
			
		||||
  add(paths: string | ReadonlyArray<string>): this;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Stop watching files, directories, or glob patterns. Takes an array of strings or just one
 | 
			
		||||
   * string.
 | 
			
		||||
   */
 | 
			
		||||
  unwatch(paths: string | ReadonlyArray<string>): this;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns an object representing all the paths on the file system being watched by this
 | 
			
		||||
   * `FSWatcher` instance. The object's keys are all the directories (using absolute paths unless
 | 
			
		||||
   * the `cwd` option was used), and the values are arrays of the names of the items contained in
 | 
			
		||||
   * each directory.
 | 
			
		||||
   */
 | 
			
		||||
  getWatched(): {
 | 
			
		||||
    [directory: string]: string[];
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Removes all listeners from watched files.
 | 
			
		||||
   */
 | 
			
		||||
  close(): Promise<void>;
 | 
			
		||||
 | 
			
		||||
  on(event: 'add'|'addDir'|'change', listener: (path: string, stats?: fs.Stats) => void): this;
 | 
			
		||||
 | 
			
		||||
  on(event: 'all', listener: (eventName: 'add'|'addDir'|'change'|'unlink'|'unlinkDir', path: string, stats?: fs.Stats) => void): this;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Error occurred
 | 
			
		||||
   */
 | 
			
		||||
  on(event: 'error', listener: (error: Error) => void): this;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Exposes the native Node `fs.FSWatcher events`
 | 
			
		||||
   */
 | 
			
		||||
  on(event: 'raw', listener: (eventName: string, path: string, details: any) => void): this;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Fires when the initial scan is complete
 | 
			
		||||
   */
 | 
			
		||||
  on(event: 'ready', listener: () => void): this;
 | 
			
		||||
 | 
			
		||||
  on(event: 'unlink'|'unlinkDir', listener: (path: string) => void): this;
 | 
			
		||||
 | 
			
		||||
  on(event: string, listener: (...args: any[]) => void): this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface WatchOptions {
 | 
			
		||||
  /**
 | 
			
		||||
   * Indicates whether the process should continue to run as long as files are being watched. If
 | 
			
		||||
   * set to `false` when using `fsevents` to watch, no more events will be emitted after `ready`,
 | 
			
		||||
   * even if the process continues to run.
 | 
			
		||||
   */
 | 
			
		||||
  persistent?: boolean;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * ([anymatch](https://github.com/micromatch/anymatch)-compatible definition) Defines files/paths to
 | 
			
		||||
   * be ignored. The whole relative or absolute path is tested, not just filename. If a function
 | 
			
		||||
   * with two arguments is provided, it gets called twice per path - once with a single argument
 | 
			
		||||
   * (the path), second time with two arguments (the path and the
 | 
			
		||||
   * [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object of that path).
 | 
			
		||||
   */
 | 
			
		||||
  ignored?: Matcher;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * If set to `false` then `add`/`addDir` events are also emitted for matching paths while
 | 
			
		||||
   * instantiating the watching as chokidar discovers these file paths (before the `ready` event).
 | 
			
		||||
   */
 | 
			
		||||
  ignoreInitial?: boolean;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * When `false`, only the symlinks themselves will be watched for changes instead of following
 | 
			
		||||
   * the link references and bubbling events through the link's path.
 | 
			
		||||
   */
 | 
			
		||||
  followSymlinks?: boolean;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The base directory from which watch `paths` are to be derived. Paths emitted with events will
 | 
			
		||||
   * be relative to this.
 | 
			
		||||
   */
 | 
			
		||||
  cwd?: string;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   *  If set to true then the strings passed to .watch() and .add() are treated as literal path
 | 
			
		||||
   *  names, even if they look like globs. Default: false.
 | 
			
		||||
   */
 | 
			
		||||
  disableGlobbing?: boolean;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Whether to use fs.watchFile (backed by polling), or fs.watch. If polling leads to high CPU
 | 
			
		||||
   * utilization, consider setting this to `false`. It is typically necessary to **set this to
 | 
			
		||||
   * `true` to successfully watch files over a network**, and it may be necessary to successfully
 | 
			
		||||
   * watch files in other non-standard situations. Setting to `true` explicitly on OS X overrides
 | 
			
		||||
   * the `useFsEvents` default.
 | 
			
		||||
   */
 | 
			
		||||
  usePolling?: boolean;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Whether to use the `fsevents` watching interface if available. When set to `true` explicitly
 | 
			
		||||
   * and `fsevents` is available this supercedes the `usePolling` setting. When set to `false` on
 | 
			
		||||
   * OS X, `usePolling: true` becomes the default.
 | 
			
		||||
   */
 | 
			
		||||
  useFsEvents?: boolean;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * If relying upon the [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object that
 | 
			
		||||
   * may get passed with `add`, `addDir`, and `change` events, set this to `true` to ensure it is
 | 
			
		||||
   * provided even in cases where it wasn't already available from the underlying watch events.
 | 
			
		||||
   */
 | 
			
		||||
  alwaysStat?: boolean;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * If set, limits how many levels of subdirectories will be traversed.
 | 
			
		||||
   */
 | 
			
		||||
  depth?: number;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Interval of file system polling.
 | 
			
		||||
   */
 | 
			
		||||
  interval?: number;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Interval of file system polling for binary files. ([see list of binary extensions](https://gi
 | 
			
		||||
   * thub.com/sindresorhus/binary-extensions/blob/master/binary-extensions.json))
 | 
			
		||||
   */
 | 
			
		||||
  binaryInterval?: number;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   *  Indicates whether to watch files that don't have read permissions if possible. If watching
 | 
			
		||||
   *  fails due to `EPERM` or `EACCES` with this set to `true`, the errors will be suppressed
 | 
			
		||||
   *  silently.
 | 
			
		||||
   */
 | 
			
		||||
  ignorePermissionErrors?: boolean;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * `true` if `useFsEvents` and `usePolling` are `false`). Automatically filters out artifacts
 | 
			
		||||
   * that occur when using editors that use "atomic writes" instead of writing directly to the
 | 
			
		||||
   * source file. If a file is re-added within 100 ms of being deleted, Chokidar emits a `change`
 | 
			
		||||
   * event rather than `unlink` then `add`. If the default of 100 ms does not work well for you,
 | 
			
		||||
   * you can override it by setting `atomic` to a custom value, in milliseconds.
 | 
			
		||||
   */
 | 
			
		||||
  atomic?: boolean | number;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * can be set to an object in order to adjust timing params:
 | 
			
		||||
   */
 | 
			
		||||
  awaitWriteFinish?: AwaitWriteFinishOptions | boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AwaitWriteFinishOptions {
 | 
			
		||||
  /**
 | 
			
		||||
   * Amount of time in milliseconds for a file size to remain constant before emitting its event.
 | 
			
		||||
   */
 | 
			
		||||
  stabilityThreshold?: number;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * File size polling interval.
 | 
			
		||||
   */
 | 
			
		||||
  pollInterval?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * produces an instance of `FSWatcher`.
 | 
			
		||||
 */
 | 
			
		||||
export function watch(
 | 
			
		||||
  paths: string | ReadonlyArray<string>,
 | 
			
		||||
  options?: WatchOptions
 | 
			
		||||
): FSWatcher;
 | 
			
		||||
		Reference in New Issue
	
	Block a user