Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: paulmillr/chokidar
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 3.3.1
Choose a base ref
...
head repository: paulmillr/chokidar
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 3.4.0
Choose a head ref

Commits on Dec 23, 2019

  1. Bump nyc from 14.1.1 to 15.0.0

    Bumps [nyc](https://github.com/istanbuljs/nyc) from 14.1.1 to 15.0.0.
    - [Release notes](https://github.com/istanbuljs/nyc/releases)
    - [Changelog](https://github.com/istanbuljs/nyc/blob/master/CHANGELOG.md)
    - [Commits](istanbuljs/nyc@v14.1.1...v15.0.0)
    
    Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
    dependabot-preview[bot] authored Dec 23, 2019
    Copy the full SHA
    769b73e View commit details

Commits on Dec 24, 2019

  1. Copy the full SHA
    1ac3988 View commit details
  2. Bump sinon from 7.5.0 to 8.0.1 (#964)

    Bumps [sinon](https://github.com/sinonjs/sinon) from 7.5.0 to 8.0.1.
    - [Release notes](https://github.com/sinonjs/sinon/releases)
    - [Changelog](https://github.com/sinonjs/sinon/blob/master/CHANGELOG.md)
    - [Commits](sinonjs/sinon@v7.5.0...v8.0.1)
    
    Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
    dependabot-preview[bot] authored and paulmillr committed Dec 24, 2019
    Copy the full SHA
    2226c0f View commit details
  3. Merge pull request #963 from paulmillr/dependabot/npm_and_yarn/types/…

    …node-13.1.0
    
    Bump @types/node from 12.12.22 to 13.1.0
    paulmillr authored Dec 24, 2019
    Copy the full SHA
    97e43aa View commit details
  4. Merge pull request #962 from paulmillr/dependabot/npm_and_yarn/nyc-15…

    ….0.0
    
    Bump nyc from 14.1.1 to 15.0.0
    paulmillr authored Dec 24, 2019
    Copy the full SHA
    47e013b View commit details

Commits on Jan 1, 2020

  1. Lint fix and test event-constants refactor
    ehsankhfr committed Jan 1, 2020
    Copy the full SHA
    30a2daa View commit details
  2. Merge pull request #1 from ehsankhfr/broken-lint-and-test-fix

    Lint fix and test event-constants refactor
    ehsankhfr authored Jan 1, 2020
    Copy the full SHA
    c14b3fc View commit details

Commits on Jan 2, 2020

  1. Merge pull request #965 from ehsankhfr/master

    Lint fix and test event-constants refactor
    paulmillr authored Jan 2, 2020
    Copy the full SHA
    99732da View commit details

Commits on Jan 6, 2020

  1. Bump mocha from 6.2.2 to 7.0.0

    Bumps [mocha](https://github.com/mochajs/mocha) from 6.2.2 to 7.0.0.
    - [Release notes](https://github.com/mochajs/mocha/releases)
    - [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)
    - [Commits](mochajs/mocha@v6.2.2...v7.0.0)
    
    Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
    dependabot-preview[bot] authored Jan 6, 2020
    Copy the full SHA
    6ae0f87 View commit details
  2. Merge pull request #968 from paulmillr/dependabot/npm_and_yarn/mocha-…

    …7.0.0
    
    Bump mocha from 6.2.2 to 7.0.0
    paulmillr authored Jan 6, 2020
    Copy the full SHA
    ba33062 View commit details

Commits on Mar 3, 2020

  1. Bump dtslint from 2.0.6 to 3.3.0

    Bumps [dtslint](https://github.com/Microsoft/dtslint) from 2.0.6 to 3.3.0.
    - [Release notes](https://github.com/Microsoft/dtslint/releases)
    - [Commits](https://github.com/Microsoft/dtslint/commits)
    
    Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
    dependabot-preview[bot] authored Mar 3, 2020
    Copy the full SHA
    84de4e5 View commit details
  2. Merge pull request #981 from paulmillr/dependabot/npm_and_yarn/dtslin…

    …t-3.3.0
    
    Bump dtslint from 2.0.6 to 3.3.0
    paulmillr authored Mar 3, 2020
    Copy the full SHA
    6217706 View commit details

Commits on Mar 5, 2020

  1. Clarify async unwatch.

    paulmillr authored Mar 5, 2020
    2
    Copy the full SHA
    8ca2b6f View commit details

Commits on Mar 10, 2020

  1. Bump sinon from 8.1.1 to 9.0.1

    Bumps [sinon](https://github.com/sinonjs/sinon) from 8.1.1 to 9.0.1.
    - [Release notes](https://github.com/sinonjs/sinon/releases)
    - [Changelog](https://github.com/sinonjs/sinon/blob/master/CHANGELOG.md)
    - [Commits](sinonjs/sinon@v8.1.1...v9.0.1)
    
    Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
    dependabot-preview[bot] authored Mar 10, 2020
    Copy the full SHA
    7d65e15 View commit details

Commits on Mar 11, 2020

  1. Merge pull request #989 from paulmillr/dependabot/npm_and_yarn/sinon-…

    …9.0.1
    
    Bump sinon from 8.1.1 to 9.0.1
    paulmillr authored Mar 11, 2020
    Copy the full SHA
    bd0dbf2 View commit details

Commits on Mar 13, 2020

  1. Add failing test

    raphinesse committed Mar 13, 2020
    Copy the full SHA
    6619f98 View commit details
  2. Copy the full SHA
    9619a84 View commit details
  3. Merge pull request #992 from raphinesse/make-close-always-return-prom…

    …ises
    
    Make close always return promises
    paulmillr authored Mar 13, 2020
    Copy the full SHA
    71e94d2 View commit details

Commits on Mar 19, 2020

  1. Bump readdirp from 3.3.0 to 3.4.0

    Bumps [readdirp](https://github.com/paulmillr/readdirp) from 3.3.0 to 3.4.0.
    - [Release notes](https://github.com/paulmillr/readdirp/releases)
    - [Commits](paulmillr/readdirp@3.3.0...3.4.0)
    
    Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
    dependabot-preview[bot] authored Mar 19, 2020
    Copy the full SHA
    e1c37c6 View commit details
  2. Merge pull request #995 from paulmillr/dependabot/npm_and_yarn/readdi…

    …rp-3.4.0
    
    Bump readdirp from 3.3.0 to 3.4.0
    paulmillr authored Mar 19, 2020
    Copy the full SHA
    1926fc7 View commit details

Commits on Apr 26, 2020

  1. Copy the full SHA
    e79ebea View commit details
  2. Bump changelog.

    paulmillr committed Apr 26, 2020
    Copy the full SHA
    9becdfc View commit details
  3. Node 14 support in CI.

    paulmillr committed Apr 26, 2020
    Copy the full SHA
    2488596 View commit details
  4. Handle replacement with other type with fsevents (#997)

    Fixes #996
    
      When using `fsevents` on macOS, if a directory is replaced by a file,
      an `addDir` event is emitted instead of an `unlinkDir` event followed
      by a `change` event instead of an `add` event.
      If a directory is replaced by a file, a `change` event is emitted
      instead of an `unlink` event is emitted, followed by a correct `addDir`
      event.
    
      This issue comes from the way we detect the existence of a file or
      directory when handling an event with wrong flags or no type.
      We check the document's existence with a call to `fs.open` and expect
      it to error out if the document does not exist anymore. But, in case
      the document was replaced before we got to handle its removal, we will
      be able to open its replacement and will then emit an add or change
      event.
    
      The proposed solution here is to compare the type given by a call to
      `fs.stat` and the type returned by fsevents. If they're equal, we'll
      assume we're dealing with an addition or a change. If they're
      different, we'll assume we're dealing with a replacement and thus emit
      an unlink event.
    taratatach authored Apr 26, 2020
    Copy the full SHA
    455f420 View commit details
  5. Changelog.

    paulmillr committed Apr 26, 2020
    Copy the full SHA
    6e8af0f View commit details
  6. Copy the full SHA
    faefe7c View commit details
  7. Release 3.4.0.

    paulmillr committed Apr 26, 2020
    Copy the full SHA
    b67d208 View commit details
Showing with 524 additions and 455 deletions.
  1. +7 −0 .github/full_changelog.md
  2. +1 −1 .github/workflows/nodejs.yml
  3. +5 −5 README.md
  4. +20 −16 index.js
  5. +1 −0 lib/constants.js
  6. +22 −12 lib/fsevents-handler.js
  7. +7 −7 package.json
  8. +461 −414 test.js
7 changes: 7 additions & 0 deletions .github/full_changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
### Chokidar 3.4.0 (Apr 26, 2020)
* Support for directory-based symlinks.
* Fix a case on macos when replacing a file with a dir of the same name
emitted invalid events.
* Fix error swallowing inside `.on()` event handlers
* Known issue: `followSymlinks: false` on macos still follows symlinked directories

### Chokidar 3.3.0 (Nov 2, 2019)
* `FSWatcher#close()` method became async. This ensures IO operations
are finished properly and fixes a few segfaulty crashes.
2 changes: 1 addition & 1 deletion .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [8, 10, 12]
node-version: [8, 10, 12, 14]
os: [ubuntu-latest, windows-latest, macOS-latest]

steps:
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -114,7 +114,7 @@ watcher.add(['new-file-2', 'new-file-3', '**/other-file*']);
var watchedPaths = watcher.getWatched();

// Un-watch some files.
watcher.unwatch('new-file*');
await watcher.unwatch('new-file*');

// Stop watching.
// The method is async!
@@ -253,8 +253,8 @@ 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.
* `.unwatch(path / paths)`: **async** Stop watching files, directories, or glob patterns.
Takes an array of strings or just one string. Use with `await` to ensure bugs don't happen.
* `.close()`: Removes all listeners from watched files. Asynchronous, returns Promise.
* `.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
@@ -286,8 +286,8 @@ execute a command on each change, or get a stdio stream of change events.
## Changelog

For more detailed changelog, see [`full_changelog.md`](.github/full_changelog.md).

- **v3.3 (Nov 2, 2019):** `FSWatcher#close()` method became async.
- **v3.4 (Apr 26, 2020):** Support for directory-based symlinks. Macos file replacement fixes.
- **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.
36 changes: 20 additions & 16 deletions index.js
Original file line number Diff line number Diff line change
@@ -152,12 +152,13 @@ class DirEntry {
const {items} = this;
if (!items) return;
items.delete(item);
if (items.size > 0) return;

if (!items.size) {
const dir = this.path;
try {
await readdir(dir);
} catch (err) {
const dir = this.path;
try {
await readdir(dir);
} catch (err) {
if (this._removeWatcher) {
this._removeWatcher(sysPath.dirname(dir), sysPath.basename(dir));
}
}
@@ -483,7 +484,7 @@ unwatch(paths_) {
* @returns {Promise<void>}.
*/
close() {
if (this.closed) return this;
if (this.closed) return this._closePromise;
this.closed = true;

// Memory management.
@@ -501,7 +502,9 @@ close() {
['closers', 'watched', 'streams', 'symlinkPaths', 'throttled'].forEach(key => {
this[`_${key}`].clear();
});
return closers.length ? Promise.all(closers).then(() => undefined) : Promise.resolve();

this._closePromise = closers.length ? Promise.all(closers).then(() => undefined) : Promise.resolve();
return this._closePromise;
}

/**
@@ -602,16 +605,15 @@ async _emit(event, path, val1, val2, val3) {
(event === EV_ADD || event === EV_ADD_DIR || event === EV_CHANGE)
) {
const fullPath = opts.cwd ? sysPath.join(opts.cwd, path) : path;
let stats;
try {
const stats = await stat(fullPath);
// Suppress event when fs_stat fails, to avoid sending undefined 'stat'
if (!stats) return;
args.push(stats);
this.emitWithAll(event, args);
stats = await stat(fullPath);
} catch (err) {}
} else {
this.emitWithAll(event, args);
// 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;
}
@@ -820,13 +822,15 @@ _hasReadPermissions(stats) {
* @param {String} item base path of item/directory
* @returns {void}
*/
_remove(directory, item) {
_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);
const isDirectory = this._watched.has(path) || this._watched.has(fullPath);
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)
1 change: 1 addition & 0 deletions lib/constants.js
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ 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';

34 changes: 22 additions & 12 deletions lib/fsevents-handler.js
Original file line number Diff line number Diff line change
@@ -37,6 +37,7 @@ const {
FSEVENT_MOVED,
// FSEVENT_CLONED,
FSEVENT_UNKNOWN,
FSEVENT_TYPE_FILE,
FSEVENT_TYPE_DIRECTORY,
FSEVENT_TYPE_SYMLINK,

@@ -47,13 +48,10 @@ const {
EMPTY_FN,
IDENTITY_FN
} = require('./constants');
const FS_MODE_READ = 'r';

const Depth = (value) => isNaN(value) ? {} : {depth: value};

const stat = promisify(fs.stat);
const open = promisify(fs.open);
const close = promisify(fs.close);
const lstat = promisify(fs.lstat);
const realpath = promisify(fs.realpath);

@@ -202,6 +200,14 @@ const calcDepth = (path, root) => {
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
*/
@@ -232,13 +238,16 @@ addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts) {
this.handleEvent(event, path, fullPath, realPath, parent, watchedDir, item, info, opts);
}

async checkFd(path, fullPath, realPath, parent, watchedDir, item, info, opts) {
async checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts) {
try {
const fd = await open(path, FS_MODE_READ);
const stats = await stat(path)
if (this.fsw.closed) return;
await close(fd);
if (this.fsw.closed) return;
this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts);
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);
@@ -252,9 +261,10 @@ handleEvent(event, path, fullPath, realPath, parent, watchedDir, item, info, opt
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 (info.type === FSEVENT_TYPE_DIRECTORY || watchedDir.has(item)) {
this.fsw._remove(parent, item);
if (isDirectory || watchedDir.has(item)) {
this.fsw._remove(parent, item, isDirectory);
}
} else {
if (event === EV_ADD) {
@@ -319,13 +329,13 @@ _watchWithFsEvents(watchPath, realPath, transform, globFilter) {
} catch (error) {}
if (this.fsw.closed) return;
if (this.checkIgnored(path, stats)) return;
if (stats) {
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.checkFd(path, fullPath, realPath, parent, watchedDir, item, info, opts);
this.checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts);
}
} else {
switch (info.event) {
@@ -334,7 +344,7 @@ _watchWithFsEvents(watchPath, realPath, transform, globFilter) {
return this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts);
case FSEVENT_DELETED:
case FSEVENT_MOVED:
return this.checkFd(path, fullPath, realPath, parent, watchedDir, item, info, opts);
return this.checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts);
}
}
};
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "chokidar",
"description": "A neat wrapper around node.js fs.watch / fs.watchFile / fsevents.",
"version": "3.3.1",
"version": "3.4.0",
"homepage": "https://github.com/paulmillr/chokidar",
"author": "Paul Miller (https://paulmillr.com)",
"contributors": [
@@ -19,20 +19,20 @@
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.3.0"
"readdirp": "~3.4.0"
},
"optionalDependencies": {
"fsevents": "~2.1.2"
},
"devDependencies": {
"@types/node": "^12",
"@types/node": "^13",
"chai": "^4.2",
"dtslint": "^2.0.0",
"dtslint": "^3.3.0",
"eslint": "^6.6.0",
"mocha": "^6.2.2",
"nyc": "^14.1.1",
"mocha": "^7.0.0",
"nyc": "^15.0.0",
"rimraf": "^3.0.0",
"sinon": "^7.5.0",
"sinon": "^9.0.1",
"sinon-chai": "^3.3.0",
"upath": "^1.2.0"
},
Loading