diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..c13c5f6 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015"] +} diff --git a/README.md b/README.md index e879276..f8259d2 100644 --- a/README.md +++ b/README.md @@ -5,36 +5,65 @@ A gulp task that inserts a delay before calling the next function in a chain. ## Example -The following example will watch for changes to templates and delay the livereload server refresh until after the nodemon script is expected to have restarted. +### Time based delay + +Waits a specified number of milliseconds before executing the next item in the chain. ```javascript -// Gulpfile.js -var gulp = require('gulp') - , r = require('tiny-lr') - , refresh = require('gulp-livereload') - , nodemon = require('gulp-nodemon') - , wait = require('../gulp-wait') - , server = lr(); -gulp.task('dev', function () { + var wait = require('gulp-wait'); - gulp.src('./index.js') - .pipe(nodemon()); + gulp.task('wait', function() { + gulp.src('yourfile.js') + .pipe(wait(1500)) + .pipe(gulp.dest('destfile.js')); + }); - server.listen(35729, function (err) { +``` - if (err) return console.log(err); +### Callback based delay - gulp.watch('./app/views/**/*.html', function (e) { - gulp.src(e.path) - .pipe(wait(1500)) - .pipe(refresh(server)); - }); +Waits for a callback to be truthy before executing the next item in the chain. - }); +```javascript -}) + var wait = require('gulp-wait'); + var fs = require('fs'); + + function doesFileExist(filePath) { + try { + fs.accessSync(filePath); + return true; + } catch () { + return false; + } + } + + gulp.task('wait', function() { + gulp.src('yourfile.js') + .pipe(wait(doesFileExist('../path/to/some/file.js'))) + .pipe(gulp.dest('destfile.js')); + }); ``` -Yes, ideally there would be an event from nodemon to trigger the livereload. \ No newline at end of file +### Using an options object + +You can pass in an options object as well. + +```javascript + +const options = { + time: 100, // same as wait(100) + callback: () => true, // same as wait(() => true) - defaults to callback if both time and callback are passed + before: () => {}, + after: () => {} +}; + +gulp.task('wait', function() { + gulp.src('yourfile.js') + .pipe(wait(options)) + .pipe(gulp.dest('destfile.js')); +}); + +``` diff --git a/index.es6 b/index.es6 new file mode 100644 index 0000000..40b240e --- /dev/null +++ b/index.es6 @@ -0,0 +1,69 @@ +'use strict'; + +const map = require('map-stream'); +let log = console.log; + +function waitByTime(opts) { + return (file, callback) => { + if (opts.before) { + opts.before(opts); + } + + setTimeout(() => { + log(`Waiting for ${opts}ms`); + callback(null, file); + + if (typeof opts.after !== 'undefined') { + opts.after(opts); + } + }, opts.time) + } +} + +function waitByCallback(opts) { + return (file, callback) => { + if (opts.before) { + opts.before(opts); + } + + let run_count = 0; + + log('Waiting for callback to return truthy'); + + while (!opts.callback()) { + run_count++; + } + + callback(null, file); + + log(`Ran callback ${run_count} times`); + + if (opts.after) { + opts.after(opts); + } + } +} + +module.exports = (opts) => { + if (typeof opts === 'number' || typeof opts === 'undefined') { + opts = { + time: opts || 1000 + }; + } + + if (typeof opts === 'function') { + opts = { + callback: opts + } + }; + + if (!opts.verbose) { + log = () => {}; + } + + if (opts.callback) { + return map(waitByCallback(opts)); + } else { + return map(waitByTime(opts)); + } +}; diff --git a/index.js b/index.js index 2d6a423..61f3d7e 100644 --- a/index.js +++ b/index.js @@ -1,41 +1,71 @@ 'use strict'; -var map = require('map-stream'), - _log = console.log; +var map = require('map-stream'); +var log = console.log; -module.exports = function (settings) { +function waitByTime(opts) { + return function (file, callback) { + if (opts.before) { + opts.before(opts); + } - if (typeof settings !== 'object') { - settings = { - duration: settings - }; - } + setTimeout(function () { + log('Waiting for ' + opts + 'ms'); + callback(null, file); - if (!settings.verbose) { - _log = function () { - return; - }; - } + if (typeof opts.after !== 'undefined') { + opts.after(opts); + } + }, opts.time); + }; +} + +function waitByCallback(opts) { + return function (file, callback) { + if (opts.before) { + opts.before(opts); + } - settings.duration = settings.duration || 1000; + var run_count = 0; - return map(function (file, cb) { + log('Waiting for callback to return truthy'); - if (typeof settings.before === 'function') { - _log('Wait: Calling before()'); - settings.before(); + while (!opts.callback()) { + run_count++; } - var timeout = setTimeout(function () { - timeout = null; - _log('Wait: Waited', settings.duration); - if (typeof settings.after === 'function') { - _log('Wait: Calling after()'); - settings.after(); - } - cb(null, file); - }, settings.duration); + callback(null, file); + + log('Ran callback ' + run_count + ' times'); - }); + if (opts.after) { + opts.after(opts); + } + }; +} + +module.exports = function (opts) { + if (typeof opts === 'number' || typeof opts === 'undefined') { + opts = { + time: opts || 1000 + }; + } + + if (typeof opts === 'function') { + opts = { + callback: opts + }; + }; + + if (!opts.verbose) { + log = function log() {}; + } + + if (opts.callback) { + return map(waitByCallback(opts)); + } else { + return map(waitByTime(opts)); + } +}; -}; \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LmVzNiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUFFQSxJQUFNLE1BQU0sUUFBUSxZQUFSLENBQVo7QUFDQSxJQUFJLE1BQU0sUUFBUSxHQUFsQjs7QUFFQSxTQUFTLFVBQVQsQ0FBb0IsSUFBcEIsRUFBMEI7QUFDeEIsU0FBTyxVQUFDLElBQUQsRUFBTyxRQUFQLEVBQW9CO0FBQ3pCLFFBQUksS0FBSyxNQUFULEVBQWlCO0FBQ2YsV0FBSyxNQUFMLENBQVksSUFBWjtBQUNEOztBQUVELGVBQVcsWUFBTTtBQUNmLDJCQUFtQixJQUFuQjtBQUNBLGVBQVMsSUFBVCxFQUFlLElBQWY7O0FBRUEsVUFBSSxPQUFPLEtBQUssS0FBWixLQUFzQixXQUExQixFQUF1QztBQUNyQyxhQUFLLEtBQUwsQ0FBVyxJQUFYO0FBQ0Q7QUFDRixLQVBELEVBT0csS0FBSyxJQVBSO0FBUUQsR0FiRDtBQWNEOztBQUVELFNBQVMsY0FBVCxDQUF3QixJQUF4QixFQUE4QjtBQUM1QixTQUFPLFVBQUMsSUFBRCxFQUFPLFFBQVAsRUFBb0I7QUFDekIsUUFBSSxLQUFLLE1BQVQsRUFBaUI7QUFDZixXQUFLLE1BQUwsQ0FBWSxJQUFaO0FBQ0Q7O0FBRUQsUUFBSSxZQUFZLENBQWhCOztBQUVBLFFBQUksdUNBQUo7O0FBRUEsV0FBTyxDQUFDLEtBQUssUUFBTCxFQUFSLEVBQXlCO0FBQ3ZCO0FBQ0Q7O0FBRUQsYUFBUyxJQUFULEVBQWUsSUFBZjs7QUFFQSwwQkFBb0IsU0FBcEI7O0FBRUEsUUFBSSxLQUFLLEtBQVQsRUFBZ0I7QUFDZCxXQUFLLEtBQUwsQ0FBVyxJQUFYO0FBQ0Q7QUFDRixHQXBCRDtBQXFCRDs7QUFFRCxPQUFPLE9BQVAsR0FBaUIsVUFBQyxJQUFELEVBQVU7QUFDekIsTUFBSSxPQUFPLElBQVAsS0FBZ0IsUUFBaEIsSUFBNEIsT0FBTyxJQUFQLEtBQWdCLFdBQWhELEVBQTZEO0FBQzNELFdBQU87QUFDTCxZQUFNLFFBQVE7QUFEVCxLQUFQO0FBR0Q7O0FBRUQsTUFBSSxPQUFPLElBQVAsS0FBZ0IsVUFBcEIsRUFBZ0M7QUFDOUIsV0FBTztBQUNMLGdCQUFVO0FBREwsS0FBUDtBQUdEOztBQUVELE1BQUksQ0FBQyxLQUFLLE9BQVYsRUFBbUI7QUFDakIsVUFBTSxlQUFNLENBQUUsQ0FBZDtBQUNEOztBQUVELE1BQUksS0FBSyxRQUFULEVBQW1CO0FBQ2pCLFdBQU8sSUFBSSxlQUFlLElBQWYsQ0FBSixDQUFQO0FBQ0QsR0FGRCxNQUVPO0FBQ0wsV0FBTyxJQUFJLFdBQVcsSUFBWCxDQUFKLENBQVA7QUFDRDtBQUNGLENBdEJEIiwiZmlsZSI6ImluZGV4LmpzIiwic291cmNlc0NvbnRlbnQiOlsiJ3VzZSBzdHJpY3QnO1xuXG5jb25zdCBtYXAgPSByZXF1aXJlKCdtYXAtc3RyZWFtJyk7XG5sZXQgbG9nID0gY29uc29sZS5sb2c7XG5cbmZ1bmN0aW9uIHdhaXRCeVRpbWUob3B0cykge1xuICByZXR1cm4gKGZpbGUsIGNhbGxiYWNrKSA9PiB7XG4gICAgaWYgKG9wdHMuYmVmb3JlKSB7XG4gICAgICBvcHRzLmJlZm9yZShvcHRzKTtcbiAgICB9XG5cbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIGxvZyhgV2FpdGluZyBmb3IgJHtvcHRzfW1zYCk7XG4gICAgICBjYWxsYmFjayhudWxsLCBmaWxlKTtcblxuICAgICAgaWYgKHR5cGVvZiBvcHRzLmFmdGVyICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICBvcHRzLmFmdGVyKG9wdHMpO1xuICAgICAgfVxuICAgIH0sIG9wdHMudGltZSlcbiAgfVxufVxuXG5mdW5jdGlvbiB3YWl0QnlDYWxsYmFjayhvcHRzKSB7XG4gIHJldHVybiAoZmlsZSwgY2FsbGJhY2spID0+IHtcbiAgICBpZiAob3B0cy5iZWZvcmUpIHtcbiAgICAgIG9wdHMuYmVmb3JlKG9wdHMpO1xuICAgIH1cblxuICAgIGxldCBydW5fY291bnQgPSAwO1xuXG4gICAgbG9nKCdXYWl0aW5nIGZvciBjYWxsYmFjayB0byByZXR1cm4gdHJ1dGh5Jyk7XG5cbiAgICB3aGlsZSAoIW9wdHMuY2FsbGJhY2soKSkge1xuICAgICAgcnVuX2NvdW50Kys7XG4gICAgfVxuXG4gICAgY2FsbGJhY2sobnVsbCwgZmlsZSk7XG5cbiAgICBsb2coYFJhbiBjYWxsYmFjayAke3J1bl9jb3VudH0gdGltZXNgKTtcblxuICAgIGlmIChvcHRzLmFmdGVyKSB7XG4gICAgICBvcHRzLmFmdGVyKG9wdHMpO1xuICAgIH1cbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IChvcHRzKSA9PiB7XG4gIGlmICh0eXBlb2Ygb3B0cyA9PT0gJ251bWJlcicgfHwgdHlwZW9mIG9wdHMgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgb3B0cyA9IHtcbiAgICAgIHRpbWU6IG9wdHMgfHwgMTAwMFxuICAgIH07XG4gIH1cblxuICBpZiAodHlwZW9mIG9wdHMgPT09ICdmdW5jdGlvbicpIHtcbiAgICBvcHRzID0ge1xuICAgICAgY2FsbGJhY2s6IG9wdHNcbiAgICB9XG4gIH07XG5cbiAgaWYgKCFvcHRzLnZlcmJvc2UpIHtcbiAgICBsb2cgPSAoKSA9PiB7fTtcbiAgfVxuXG4gIGlmIChvcHRzLmNhbGxiYWNrKSB7XG4gICAgcmV0dXJuIG1hcCh3YWl0QnlDYWxsYmFjayhvcHRzKSk7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIG1hcCh3YWl0QnlUaW1lKG9wdHMpKTtcbiAgfVxufTtcbiJdfQ== \ No newline at end of file diff --git a/package.json b/package.json index e2cc3ec..7a92d1c 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,15 @@ { - "name": "gulp-wait", - "version": "0.0.2", - "description": "A gulp task that inserts a delay before calling the next function in a chain.", - "main": "index.js", + "name": "gulp-wait2", + "version": "0.0.5", + "description": "A gulp task that inserts a delay (time or callback-based) before calling the next function in a chain. (Forked from bpartridge/gulp-wait)", + "main": "index-compiled.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "build": "babel index.es6 --out-file index.js --source-maps inline", + "test": "npm run build && tape 'tests/**/*.js'" }, "repository": { "type": "git", - "url": "https://github.com/bpartridge83/gulp-wait.git" + "url": "https://github.com/cwramsey/gulp-wait.git" }, "keywords": [ "gulp", @@ -16,12 +17,20 @@ "delay", "gulpplugin" ], - "author": "Brian Partridge", + "author": "Chris Ramsey", + "contributors": [ + "Brian Partridge" + ], "license": "BSD-2-Clause", "bugs": { - "url": "https://github.com/bpartridge/gulp-wait/issues" + "url": "https://github.com/cwramsey/gulp-wait/issues" }, "dependencies": { "map-stream": "0.0.4" + }, + "devDependencies": { + "babel-cli": "^6.10.1", + "babel-preset-es2015": "^6.9.0", + "tape": "^4.5.1" } } diff --git a/tests/index.spec.js b/tests/index.spec.js new file mode 100644 index 0000000..9b2b534 --- /dev/null +++ b/tests/index.spec.js @@ -0,0 +1,157 @@ +'use strict'; + +const test = require('tape'); +const wait = require('../index'); + +test('wait returns a stream object', (t) => { + t.plan(1); + const res = wait(); + + t.ok(res instanceof require('stream').Stream, 'is instanceof Stream'); +}); + +test('waits 1 second before returning if no params are given', (t) => { + t.plan(1); + + const stream = wait(); + const now = Date.now(); + + stream.on('data', () => { + const time = Date.now() - now; + t.ok(time < 1200 && time > 800, 'Waits for 1 second'); + t.end(); + }); + + stream.write(null); + +}); + +test('Accurately waits before calling the cb if given a number', (t) => { + t.plan(1); + + const stream = wait(100); + const now = Date.now(); + + stream.on('data', () => { + const time = Date.now() - now; + t.ok(time < 120 && time > 80, 'Waits for 150ms'); + t.end(); + }); + + stream.write(null); +}); + +test('Waits until callback returns truthy before calling resuming stream', (t) => { + + let num = 100; + + const stream = wait(() => { + num--; + return num === 0; + }); + + stream.on('data', () => { + t.ok(true, 'Accepts function for timeout'); + t.end(); + }); + + stream.write(null); +}); + +test('Defaults to callback if both cb and time are passed in', (t) => { + + let num = 100; + + const stream = wait({ + time: 5000, + callback() { + num--; + return num === 0; + } + }); + + stream.on('data', () => { + t.ok(true, 'Defaults to callback'); + t.end(); + }); + + stream.write(null); +}); + +test('Runs the `before` callback when using time', (t) => { + + let result = false; + + const stream = wait({ + time: 100, + before() { + result = true; + } + }); + + stream.on('data', () => { + t.ok(result === true, 'Sets variable from `before` callback'); + t.end(); + }); + + stream.write(null); +}); + +test('Runs the `after` callback when using time', (t) => { + + let after_result = false; + + const stream = wait({ + time: 100, + after: () => { + after_result = true; + } + }); + + stream.write(null); + + // wait for stream to finish + setTimeout(() => { + t.ok(after_result === true, 'Sets variable from `after` callback'); + t.end(); + }, 200) +}); + +test('Runs the `before` callback when using callback', (t) => { + + let result = false; + + const stream = wait({ + callback: () => true, + before() { + result = true; + } + }); + + stream.on('data', () => { + t.ok(result === true, 'Sets variable from `before` callback'); + t.end(); + }); + + stream.write(null); +}); + +test('Runs the `after` callback when using callback', (t) => { + + let after_result = false; + + const stream = wait({ + callback: () => true, + after: () => { + after_result = true; + } + }); + + stream.write(null); + + // wait for stream to finish + setTimeout(() => { + t.ok(after_result === true, 'Sets variable from `after` callback'); + t.end(); + }, 200) +});