From 0b3acc73488b0e1b96279df38598a6873b925786 Mon Sep 17 00:00:00 2001 From: sttk Date: Sat, 6 Aug 2022 13:57:22 +0900 Subject: [PATCH 1/4] chore!: Normalize repository, dropping node <10.13 support --- .editorconfig | 2 +- .eslintignore | 1 + .eslintrc | 5 ++- .github/support.yml | 2 - .github/workflows/dev.yml | 75 +++++++++++++++++++++++++++++++++++ .github/workflows/release.yml | 16 ++++++++ .gitignore | 54 ++++++++++++++++++++----- .jscsrc | 3 -- .npmrc | 1 + .prettierignore | 3 ++ .travis.yml | 13 ------ LICENSE | 2 +- README.md | 34 ++++++++-------- appveyor.yml | 28 ------------- index.js | 58 ++------------------------- package.json | 46 +++++++++++---------- test/.eslintrc | 3 -- test/index.js | 43 +++++++++++++++----- 18 files changed, 221 insertions(+), 168 deletions(-) create mode 100644 .eslintignore delete mode 100644 .github/support.yml create mode 100644 .github/workflows/dev.yml create mode 100644 .github/workflows/release.yml delete mode 100644 .jscsrc create mode 100644 .npmrc create mode 100644 .prettierignore delete mode 100644 .travis.yml mode change 100755 => 100644 LICENSE delete mode 100644 appveyor.yml delete mode 100644 test/.eslintrc diff --git a/.editorconfig b/.editorconfig index e000b0c..e7b73a7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,4 @@ -# http://editorconfig.org +# https://editorconfig.org root = true [*] diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..404abb2 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +coverage/ diff --git a/.eslintrc b/.eslintrc index a5a4a17..76e7721 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,3 +1,6 @@ { - "extends": "gulp" + "extends": "gulp", + "rules": { + "max-statements": 0 + } } diff --git a/.github/support.yml b/.github/support.yml deleted file mode 100644 index 3ee3d22..0000000 --- a/.github/support.yml +++ /dev/null @@ -1,2 +0,0 @@ -# Configuration for support-requests - https://github.com/dessant/support-requests -_extends: gulp diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml new file mode 100644 index 0000000..3b07263 --- /dev/null +++ b/.github/workflows/dev.yml @@ -0,0 +1,75 @@ +name: dev +on: + pull_request: + push: + branches: + - master + - main +env: + CI: true + +jobs: + prettier: + name: Format code + runs-on: ubuntu-latest + if: ${{ github.event_name == 'push' }} + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Prettier + uses: gulpjs/prettier_action@v3.0 + with: + commit_message: 'chore: Run prettier' + prettier_options: '--write .' + + test: + name: Tests for Node ${{ matrix.node }} on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + node: [10, 12, 14, 16] + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - name: Clone repository + uses: actions/checkout@v2 + + - name: Set Node.js version + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node }} + + - run: node --version + - run: npm --version + + - name: Install npm dependencies + run: npm install + + - name: Run lint + run: npm run lint + + - name: Run tests + run: npm test + + - name: Coveralls + uses: coverallsapp/github-action@v1.1.2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + flag-name: ${{matrix.os}}-node-${{ matrix.node }} + parallel: true + + coveralls: + needs: test + name: Finish up + + runs-on: ubuntu-latest + steps: + - name: Coveralls Finished + uses: coverallsapp/github-action@v1.1.2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + parallel-finished: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..87cd13c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,16 @@ +name: release +on: + push: + branches: + - master + - main + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: GoogleCloudPlatform/release-please-action@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + release-type: node + package-name: release-please-action diff --git a/.gitignore b/.gitignore index da8ada8..aa0c563 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,15 @@ # Logs logs *.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* # Runtime data pids *.pid *.seed +*.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov @@ -13,23 +17,51 @@ lib-cov # Coverage directory used by tools like istanbul coverage -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) .grunt -# Compiled binary addons (http://nodejs.org/api/addons.html) +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) build/Release -# Dependency directory -# Commenting this out is preferred by some people, see -# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- -node_modules +# Dependency directories +node_modules/ +jspm_packages/ -# Users Environment Variables -.lock-wscript +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# next.js build output +.next # Garbage files .DS_Store -# Generated by integration tests -test/fixtures/tmp -test/fixtures/out +# Test results +test.xunit diff --git a/.jscsrc b/.jscsrc deleted file mode 100644 index 703b33f..0000000 --- a/.jscsrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "preset": "gulp" -} diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..43c97e7 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..c96ebe0 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +coverage/ +.nyc_output/ +CHANGELOG.md diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b505be7..0000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -sudo: false -language: node_js -node_js: - - '14' - - '12' - - '10' - - '8' - - '6' - - '4' - - '0.12' - - '0.10' -after_script: - - npm run coveralls diff --git a/LICENSE b/LICENSE old mode 100755 new mode 100644 index b8fc743..ae5c338 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2017 Blaine Bublitz , Eric Schoffstall and other contributors +Copyright (c) 2017-2018, 2020, 2022 Blaine Bublitz and Eric Schoffstall . Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index dba40cf..5c976af 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@

- +

# glob-watcher -[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![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] +[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Coveralls Status][coveralls-image]][coveralls-url] Watch globs and execute a function upon change, with intelligent defaults for debouncing and queueing. @@ -114,24 +114,22 @@ Options are passed directly to [chokidar][chokidar]. MIT -[micromatch]: https://github.com/micromatch/micromatch -[normalize-path]: https://www.npmjs.com/package/normalize-path -[micromatch-backslashes]: https://github.com/micromatch/micromatch#backslashes -[async-completion]: https://github.com/gulpjs/async-done#completion-and-error-resolution -[chokidar]: https://github.com/paulmillr/chokidar - -[downloads-image]: http://img.shields.io/npm/dm/glob-watcher.svg + +[downloads-image]: https://img.shields.io/npm/dm/glob-watcher.svg?style=flat-square [npm-url]: https://npmjs.com/package/glob-watcher -[npm-image]: http://img.shields.io/npm/v/glob-watcher.svg +[npm-image]: https://img.shields.io/npm/v/glob-watcher.svg?style=flat-square -[travis-url]: https://travis-ci.org/gulpjs/glob-watcher -[travis-image]: http://img.shields.io/travis/gulpjs/glob-watcher.svg?label=travis-ci - -[appveyor-url]: https://ci.appveyor.com/project/gulpjs/glob-watcher -[appveyor-image]: https://img.shields.io/appveyor/ci/gulpjs/glob-watcher.svg?label=appveyor +[ci-url]: https://github.com/gulpjs/glob-watcher/actions?query=workflow:dev +[ci-image]: https://img.shields.io/github/workflow/status/gulpjs/glob-watcher/dev?style=flat-square [coveralls-url]: https://coveralls.io/r/gulpjs/glob-watcher -[coveralls-image]: http://img.shields.io/coveralls/gulpjs/glob-watcher/master.svg +[coveralls-image]: https://img.shields.io/coveralls/gulpjs/glob-watcher/master.svg?style=flat-square + -[gitter-url]: https://gitter.im/gulpjs/gulp -[gitter-image]: https://badges.gitter.im/gulpjs/gulp.png + +[micromatch]: https://github.com/micromatch/micromatch +[normalize-path]: https://www.npmjs.com/package/normalize-path +[micromatch-backslashes]: https://github.com/micromatch/micromatch#backslashes +[async-completion]: https://github.com/gulpjs/async-done#completion-and-error-resolution +[chokidar]: https://github.com/paulmillr/chokidar + diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index aba7249..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,28 +0,0 @@ -# http://www.appveyor.com/docs/appveyor-yml -# http://www.appveyor.com/docs/lang/nodejs-iojs - -environment: - matrix: - # node.js - - nodejs_version: "0.10" - - nodejs_version: "0.12" - - nodejs_version: "4" - - nodejs_version: "6" - - nodejs_version: "8" - - nodejs_version: "10" - - nodejs_version: "12" - - nodejs_version: "14" - -install: - - ps: Install-Product node $env:nodejs_version - - npm install - -test_script: - - node --version - - npm --version - - cmd: npm test - -build: off - -# build version format -version: "{build}" diff --git a/index.js b/index.js index 2c51da6..e3595f3 100644 --- a/index.js +++ b/index.js @@ -3,10 +3,6 @@ var chokidar = require('chokidar'); var debounce = require('just-debounce'); var asyncDone = require('async-done'); -var defaults = require('object.defaults/immutable'); -var isNegatedGlob = require('is-negated-glob'); -var anymatch = require('anymatch'); -var normalize = require('normalize-path'); var defaultOpts = { delay: 200, @@ -17,10 +13,12 @@ var defaultOpts = { }; function listenerCount(ee, evtName) { + /* istanbul ignore else */ if (typeof ee.listenerCount === 'function') { return ee.listenerCount(evtName); } + /* istanbul ignore next */ return ee.listeners(evtName).length; } @@ -38,7 +36,7 @@ function watch(glob, options, cb) { options = {}; } - var opt = defaults(options, defaultOpts); + var opt = Object.assign({}, defaultOpts, options); if (!Array.isArray(opt.events)) { opt.events = [opt.events]; @@ -54,55 +52,7 @@ function watch(glob, options, cb) { var queued = false; var running = false; - // These use sparse arrays to keep track of the index in the - // original globs array - var positives = new Array(glob.length); - var negatives = new Array(glob.length); - - // Reverse the glob here so we don't end up with a positive - // and negative glob in position 0 after a reverse - glob.reverse().forEach(sortGlobs); - - function sortGlobs(globString, index) { - var result = isNegatedGlob(globString); - if (result.negated) { - negatives[index] = result.pattern; - } else { - positives[index] = result.pattern; - } - } - - var toWatch = positives.filter(exists); - - function joinCwd(glob) { - if (glob && opt.cwd) { - return normalize(opt.cwd + '/' + glob); - } - - return glob; - } - - // We only do add our custom `ignored` if there are some negative globs - // TODO: I'm not sure how to test this - if (negatives.some(exists)) { - var normalizedPositives = positives.map(joinCwd); - var normalizedNegatives = negatives.map(joinCwd); - var shouldBeIgnored = function(path) { - var positiveMatch = anymatch(normalizedPositives, path, true); - var negativeMatch = anymatch(normalizedNegatives, path, true); - // If negativeMatch is -1, that means it was never negated - if (negativeMatch === -1) { - return false; - } - - // If the negative is "less than" the positive, that means - // it came later in the glob array before we reversed them - return negativeMatch < positiveMatch; - }; - - opt.ignored = [].concat(opt.ignored, shouldBeIgnored); - } - var watcher = chokidar.watch(toWatch, opt); + var watcher = chokidar.watch(glob, opt); function runComplete(err) { running = false; diff --git a/package.json b/package.json index d934112..b6e9a04 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,12 @@ "name": "glob-watcher", "version": "5.0.5", "description": "Watch globs and execute a function upon change, with intelligent defaults for debouncing and queueing.", - "author": "Gulp Team (http://gulpjs.com/)", + "author": "Gulp Team (https://gulpjs.com/)", "contributors": [], "repository": "gulpjs/glob-watcher", "license": "MIT", "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" }, "main": "index.js", "files": [ @@ -16,30 +16,32 @@ "scripts": { "lint": "eslint .", "pretest": "npm run lint", - "test": "mocha --async-only", - "cover": "istanbul cover _mocha --report lcovonly", - "coveralls": "npm run cover && istanbul-coveralls" + "test": "nyc mocha --async-only" }, "dependencies": { - "anymatch": "^2.0.0", - "async-done": "^1.2.0", - "chokidar": "^2.0.0", - "is-negated-glob": "^1.0.0", - "just-debounce": "^1.0.0", - "normalize-path": "^3.0.0", - "object.defaults": "^1.1.0" + "async-done": "^2.0.0", + "chokidar": "^3.5.3", + "just-debounce": "^1.1.0" }, "devDependencies": { - "coveralls": "^2.11.2", - "eslint": "^2.13.1", - "eslint-config-gulp": "^3.0.1", - "expect": "^1.16.0", - "istanbul": "^0.4.0", - "istanbul-coveralls": "^1.0.1", - "mocha": "^2.0.0", - "mocha-lcov-reporter": "^1.2.0", - "rimraf": "^2.6.1", - "through2": "^2.0.1" + "eslint": "^7.32.0", + "eslint-config-gulp": "^5.0.1", + "expect": "^27.5.1", + "mocha": "^8.4.0", + "normalize-path": "^3.0.0", + "nyc": "^15.1.0", + "rimraf": "^3.0.2", + "sinon": "^14.0.0", + "through2": "^4.0.2" + }, + "nyc": { + "reporter": [ + "lcov", + "text-summary" + ] + }, + "prettier": { + "singleQuote": true }, "keywords": [ "watch", diff --git a/test/.eslintrc b/test/.eslintrc deleted file mode 100644 index 06b940f..0000000 --- a/test/.eslintrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "gulp/test" -} diff --git a/test/index.js b/test/index.js index 5acefa8..fdb1075 100644 --- a/test/index.js +++ b/test/index.js @@ -4,6 +4,7 @@ var fs = require('fs'); var path = require('path'); var expect = require('expect'); +var sinon = require('sinon'); var rimraf = require('rimraf'); var through = require('through2'); var normalizePath = require('normalize-path'); @@ -21,8 +22,8 @@ describe('glob-watcher', function() { var outFile1 = path.join(outDir, 'changed.js'); var outFile2 = path.join(outDir, 'added.js'); var globPattern = '**/*.js'; - var outGlob = normalizePath(path.join(outDir, globPattern)); - var singleAdd = normalizePath(path.join(outDir, 'changed.js')); + var outGlob = path.join(outDir, globPattern); + var singleAdd = path.join(outDir, 'changed.js'); var ignoreGlob = '!' + singleAdd; function changeFile() { @@ -257,10 +258,9 @@ describe('glob-watcher', function() { }); it('watches exactly the given event', function(done) { - var spy = expect.createSpy() - .andCall(function(cb) { + var spy = sinon.spy(function(cb) { cb(); - spy.andThrow(new Error('`Add` handler called for `change` event')); + expect(spy.callCount).toEqual(1); setTimeout(done, 500); changeFile(); }); @@ -271,14 +271,18 @@ describe('glob-watcher', function() { }); it('accepts multiple events to watch', function(done) { - var spy = expect.createSpy() - .andThrow(new Error('`Add`/`Unlink` handler called for `change` event')); + var spy = sinon.spy(function(cb) { + cb(); + if (spy.callCount === 2) { + done(); + } + }); - watcher = watch(outGlob, { events: ['add', 'unlink'] }, spy); + watcher = watch(outGlob, { events: ['add', 'change'] }, spy); - watcher.on('ready', function() { - changeFile(); - setTimeout(done, 500); + watcher.on('ready', addFile); + watcher.on('add', function() { + setTimeout(changeFile, 500); }); }); @@ -309,6 +313,23 @@ describe('glob-watcher', function() { watcher.on('ready', changeFile); }); + it('can re-add a glob after it has been negated (unix style path)', function(done) { + watcher = watch([ + normalizePath(outGlob), + normalizePath(ignoreGlob), + normalizePath(singleAdd), + ]); + + watcher.once('change', function(filepath) { + // chokidar pass windows style path on windows. + expect(filepath).toEqual(singleAdd); + done(); + }); + + // We default `ignoreInitial` to true, so always wait for `on('ready')` + watcher.on('ready', changeFile); + }); + it('does not mutate the globs array', function(done) { var globs = [outGlob, ignoreGlob, singleAdd]; watcher = watch(globs); From c7fc1c8083a57d57dfa970d86ed565e9df6f4e9d Mon Sep 17 00:00:00 2001 From: sttk Date: Sat, 6 Aug 2022 23:43:01 +0900 Subject: [PATCH 2/4] update: drop just-debounce from dependencies --- index.js | 2 +- lib/debounce.js | 26 +++++++++++ package.json | 8 ++-- test/lib/debounce.test.js | 90 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 lib/debounce.js create mode 100644 test/lib/debounce.test.js diff --git a/index.js b/index.js index e3595f3..ac3b32b 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,8 @@ 'use strict'; var chokidar = require('chokidar'); -var debounce = require('just-debounce'); var asyncDone = require('async-done'); +var debounce = require('./lib/debounce'); var defaultOpts = { delay: 200, diff --git a/lib/debounce.js b/lib/debounce.js new file mode 100644 index 0000000..7ff1d8d --- /dev/null +++ b/lib/debounce.js @@ -0,0 +1,26 @@ +'use strict'; + +function debounce(fn, delay) { + var timeout; + var args; + var self; + + return function() { + self = this; + args = arguments; + clear(); + timeout = setTimeout(run, delay); + }; + + function run() { + clear(); + fn.apply(self, args); + } + + function clear() { + clearTimeout(timeout); + timeout = null; + } +} + +module.exports = debounce; diff --git a/package.json b/package.json index b6e9a04..fe7e6ec 100644 --- a/package.json +++ b/package.json @@ -11,17 +11,17 @@ }, "main": "index.js", "files": [ - "index.js" + "index.js", + "lib/" ], "scripts": { "lint": "eslint .", "pretest": "npm run lint", - "test": "nyc mocha --async-only" + "test": "nyc mocha test test/lib --async-only" }, "dependencies": { "async-done": "^2.0.0", - "chokidar": "^3.5.3", - "just-debounce": "^1.1.0" + "chokidar": "^3.5.3" }, "devDependencies": { "eslint": "^7.32.0", diff --git a/test/lib/debounce.test.js b/test/lib/debounce.test.js new file mode 100644 index 0000000..6b7fa13 --- /dev/null +++ b/test/lib/debounce.test.js @@ -0,0 +1,90 @@ +'use strict'; + +var expect = require('expect'); +var sinon = require('sinon'); +var debounce = require('../../lib/debounce'); + +describe('lib/debounce', function() { + + it('should call an original function with specified delay', function(done) { + expect.assertions(1); + + var executed = false; + var fn = debounce(function() { + executed = true; + }, 10); + + fn(); + + expect(executed).toBeFalsy(); + + setTimeout(function() { + expect(executed).toBeTruthy(); + done(); + }, 11); + }); + + it('should extend delay against multiple calls', function(done) { + expect.assertions(1); + + var fn = debounce(function(a) { + expect(a).toBe(3); + done(); + }, 50); + + fn(1); + fn(2); + + setTimeout(function() { + fn(3); + }, 3); + }); + + it('should extends delay if a preceding call doesn\'t run yet', function(done) { + expect.assertions(1); + + var fn = debounce(function(a) { + expect(a).toBe(3); + done(); + }, 10); + + fn(1); + + setTimeout(function() { + fn(2); + + setTimeout(function() { + fn(3); + }, 5); + }, 5); + }); + + it('should run if a preceding call already run', function(done) { + expect.assertions(2); + + var spy = sinon.spy(function(a) { + switch (spy.callCount) { + case 1: + expect(a).toBe(2); + break; + case 2: + expect(a).toBe(3); + done(); + break; + default: + throw new Error(); + } + }); + var fn = debounce(spy, 6); + + fn(1); + + setTimeout(function() { + fn(2); + + setTimeout(function() { + fn(3); + }, 10); + }, 3); + }); +}); From e57e49f6c4a50875e44ee9db10d713b65806ac4b Mon Sep 17 00:00:00 2001 From: sttk Date: Sat, 6 Aug 2022 23:45:14 +0900 Subject: [PATCH 3/4] update: move args process to lib/normalize-args.js --- index.js | 69 ++++++-------------------- lib/normalize-args.js | 33 +++++++++++++ test/lib/normalize-args.test.js | 87 +++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 54 deletions(-) create mode 100644 lib/normalize-args.js create mode 100644 test/lib/normalize-args.test.js diff --git a/index.js b/index.js index ac3b32b..9bc887d 100644 --- a/index.js +++ b/index.js @@ -2,62 +2,31 @@ var chokidar = require('chokidar'); var asyncDone = require('async-done'); +var normalizeArgs = require('./lib/normalize-args'); var debounce = require('./lib/debounce'); -var defaultOpts = { - delay: 200, - events: ['add', 'change', 'unlink'], - ignored: [], - ignoreInitial: true, - queue: true, -}; - -function listenerCount(ee, evtName) { - /* istanbul ignore else */ - if (typeof ee.listenerCount === 'function') { - return ee.listenerCount(evtName); - } - - /* istanbul ignore next */ - return ee.listeners(evtName).length; -} - -function hasErrorListener(ee) { - return listenerCount(ee, 'error') !== 0; +function watch(glob, options, cb) { + return normalizeArgs(glob, options, cb, watchProc); } -function exists(val) { - return val != null; +function watchProc(globs, options, cb) { + var watcher = chokidar.watch(globs, options); + registerWatchEvent(watcher, options, cb); + return watcher; } -function watch(glob, options, cb) { - if (typeof options === 'function') { - cb = options; - options = {}; - } - - var opt = Object.assign({}, defaultOpts, options); - - if (!Array.isArray(opt.events)) { - opt.events = [opt.events]; - } - - if (Array.isArray(glob)) { - // We slice so we don't mutate the passed globs array - glob = glob.slice(); - } else { - glob = [glob]; +function registerWatchEvent(watcher, opts, cb) { + if (typeof cb !== 'function') { + return; } var queued = false; var running = false; - var watcher = chokidar.watch(glob, opt); - function runComplete(err) { running = false; - if (err && hasErrorListener(watcher)) { + if (err && watcher.listenerCount('error') > 0) { watcher.emit('error', err); } @@ -70,7 +39,7 @@ function watch(glob, options, cb) { function onChange() { if (running) { - if (opt.queue) { + if (opts.queue) { queued = true; } return; @@ -80,20 +49,12 @@ function watch(glob, options, cb) { asyncDone(cb, runComplete); } - var fn; - if (typeof cb === 'function') { - fn = debounce(onChange, opt.delay); - } + var debounced = debounce(onChange, opts.delay); + opts.events.forEach(watchEvent); function watchEvent(eventName) { - watcher.on(eventName, fn); + watcher.on(eventName, debounced); } - - if (fn) { - opt.events.forEach(watchEvent); - } - - return watcher; } module.exports = watch; diff --git a/lib/normalize-args.js b/lib/normalize-args.js new file mode 100644 index 0000000..f325a56 --- /dev/null +++ b/lib/normalize-args.js @@ -0,0 +1,33 @@ +'use strict'; + +var defaultOpts = { + delay: 200, + events: ['add', 'change', 'unlink'], + ignored: [], + ignoreInitial: true, + queue: true, +}; + +function normalizeArgs(glob, options, cb, next) { + if (typeof options === 'function') { + cb = options; + options = {}; + } + + var opts = Object.assign({}, defaultOpts, options); + + if (!Array.isArray(opts.events)) { + opts.events = [opts.events]; + } + + if (Array.isArray(glob)) { + // We slice so we don't mutate the passed globs array + glob = glob.slice(); + } else { + glob = [glob]; + } + + return next(glob, opts, cb); +} + +module.exports = normalizeArgs; diff --git a/test/lib/normalize-args.test.js b/test/lib/normalize-args.test.js new file mode 100644 index 0000000..3898a93 --- /dev/null +++ b/test/lib/normalize-args.test.js @@ -0,0 +1,87 @@ +'use strict'; + +var expect = require('expect'); +var normalizeArgs = require('../../lib/normalize-args'); + +describe('lib/normalize-args', function() { + + it('should normalize glob to an array', function(done) { + var opts0 = { + delay: 500, + events: ['all'], + ignored: ['.*.txt'], + ignoreInitial: false, + queue: false, + persistent: true, + }; + var cb0 = function() {}; + + normalizeArgs('*.txt', opts0, cb0, function(glob, opts, cb) { + expect(Array.isArray(glob)).toBeTruthy(); + expect(opts).not.toBe(opts0); + expect(opts).toEqual(opts0); + expect(cb).toBe(cb0); + done(); + }); + }); + + it('should complement options with default options', function(done) { + var glob0 = ['*.txt']; + var cb0 = function() {}; + + normalizeArgs(glob0, {}, cb0, function(glob, opts, cb) { + expect(glob).not.toBe(glob0); + expect(glob).toEqual(glob0); + expect(opts).toEqual({ + delay: 200, + events: ['add', 'change', 'unlink'], + ignored: [], + ignoreInitial: true, + queue: true, + }); + expect(cb).toBe(cb0); + done(); + }); + }); + + it('should normalize options.events to an array', function(done) { + var glob0 = ['*.txt']; + var opts0 = { + events: 'all', + }; + var cb0 = function() {}; + + normalizeArgs(glob0, opts0, cb0, function(glob, opts, cb) { + expect(glob).not.toBe(glob0); + expect(glob).toEqual(glob0); + expect(opts).toEqual({ + delay: 200, + events: ['all'], + ignored: [], + ignoreInitial: true, + queue: true, + }); + expect(cb).toBe(cb0); + done(); + }); + }); + + it('should change 2nd arg to cb if 2nd arg is a function', function(done) { + var glob0 = ['*.txt']; + var cb0 = function() {}; + normalizeArgs(glob0, cb0, undefined, function(glob, opts, cb) { + expect(glob).not.toBe(glob0); + expect(glob).toEqual(glob0); + expect(opts).toEqual({ + delay: 200, + events: ['add', 'change', 'unlink'], + ignored: [], + ignoreInitial: true, + queue: true, + }); + expect(cb).toBe(cb0); + done(); + }); + }); + +}); From 6a6fa50043e39adcd258d991c7fc219758e33578 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Tue, 30 May 2023 17:00:08 -0700 Subject: [PATCH 4/4] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index ae5c338..750bb59 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2017-2018, 2020, 2022 Blaine Bublitz and Eric Schoffstall . +Copyright (c) 2017-2018, 2020, 2022-2023 Blaine Bublitz and Eric Schoffstall Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal