├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── bower.json
├── dist
├── pouchdb.migrate.js
└── pouchdb.migrate.min.js
├── index.js
├── lib
├── checkpointer.js
├── md5.js
└── migrate.js
├── package.json
└── test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | cache:
4 | directories:
5 | - node_modules
6 | notifications:
7 | email: false
8 | node_js:
9 | - 4
10 | - iojs-v3
11 | - iojs-v2
12 | - iojs-v1
13 | - '0.12'
14 | - '0.10'
15 | before_install:
16 | - npm i -g npm@^2.0.0
17 | before_script:
18 | - npm prune
19 | after_success:
20 | - npm run build
21 | - npm run semantic-release
22 | branches:
23 | except:
24 | # ignore git tags created by semantic-release, like "v1.2.3"
25 | - /^v\d+\.\d+\.\d+$/
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you
2 | may not use this file except in compliance with the License. You may
3 | obtain a copy of the License at
4 |
5 | http://www.apache.org/licenses/LICENSE-2.0
6 |
7 | Unless required by applicable law or agreed to in writing, software
8 | distributed under the License is distributed on an "AS IS" BASIS,
9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
10 | implied. See the License for the specific language governing
11 | permissions and limitations under the License.
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # pouchdb-migrate
2 | PouchDB plugin for running migrations.
3 |
4 | [](https://travis-ci.org/eHealthAfrica/pouchdb-migrate)
6 |
7 | ## Setup
8 | ```html
9 |
10 |
11 | ```
12 |
13 | Or to use it in Node.js, just npm install it:
14 |
15 | ```
16 | npm install pouchdb-migrate
17 | ```
18 |
19 | And then attach it to the `PouchDB` object:
20 |
21 | ```js
22 | var PouchDB = require('pouchdb');
23 | PouchDB.plugin(require('pouchdb-migrate'));
24 | ```
25 |
26 | ## Usage
27 | ```js
28 | var db = new PouchDB('mydb')
29 |
30 | // Migration script
31 | // * Return falsy value to skip the doc
32 | // * Make sure to prevent from loops
33 | var migration = function(doc) {
34 | if ('foo' in doc) return
35 |
36 | doc.foo = 'bar'
37 | return [doc]
38 | }
39 |
40 | db.migrate(migration)
41 | .then //... every doc has `foo` now
42 | ```
43 |
44 | ## Testing
45 | Run the tests with
46 | ```sh
47 | npm test
48 | ```
49 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pouchdb-migrate",
3 | "main": "dist/pouchdb.migrate.js",
4 | "version": "1.1.1",
5 | "homepage": "https://github.com/eHealthAfrica/pouchdb-migrate",
6 | "authors": [
7 | "Johannes J. Schmidt "
8 | ],
9 | "description": "PouchDB plugin for running migrations.",
10 | "moduleType": [
11 | "node"
12 | ],
13 | "keywords": [
14 | "pouchdb"
15 | ],
16 | "license": "Apache-2.0",
17 | "ignore": [
18 | "**/.*",
19 | "node_modules",
20 | "bower_components",
21 | "test",
22 | "tests"
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/dist/pouchdb.migrate.js:
--------------------------------------------------------------------------------
1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o>> 8) & 0xff),
159 | ((int >>> 16) & 0xff),
160 | ((int >>> 24) & 0xff)
161 | ];
162 | return bytes.map(function (byte) {
163 | return String.fromCharCode(byte);
164 | }).join('');
165 | }
166 |
167 | // convert an array of 64-bit ints into
168 | // a base64-encoded string
169 | /* istanbul ignore next */
170 | function rawToBase64(raw) {
171 | var res = '';
172 | for (var i = 0; i < raw.length; i++) {
173 | res += intToString(raw[i]);
174 | }
175 | return global.btoa(res);
176 | }
177 |
178 | /* istanbul ignore next */
179 | module.exports = function (data, callback) {
180 | if (!process.browser) {
181 | var base64 = crypto.createHash('md5').update(data).digest('base64');
182 | callback(null, base64);
183 | return;
184 | }
185 | var inputIsString = typeof data === 'string';
186 | var len = inputIsString ? data.length : data.byteLength;
187 | var chunkSize = Math.min(MD5_CHUNK_SIZE, len);
188 | var chunks = Math.ceil(len / chunkSize);
189 | var currentChunk = 0;
190 | var buffer = inputIsString ? new Md5() : new Md5.ArrayBuffer();
191 |
192 | function append(buffer, data, start, end) {
193 | if (inputIsString) {
194 | buffer.appendBinary(data.substring(start, end));
195 | } else {
196 | buffer.append(sliceShim(data, start, end));
197 | }
198 | }
199 |
200 | function loadNextChunk() {
201 | var start = currentChunk * chunkSize;
202 | var end = start + chunkSize;
203 | if ((start + chunkSize) >= data.size) {
204 | end = data.size;
205 | }
206 | currentChunk++;
207 | if (currentChunk < chunks) {
208 | append(buffer, data, start, end);
209 | setImmediateShim(loadNextChunk);
210 | } else {
211 | append(buffer, data, start, end);
212 | var raw = buffer.end(true);
213 | var base64 = rawToBase64(raw);
214 | callback(null, base64);
215 | buffer.destroy();
216 | }
217 | }
218 | loadNextChunk();
219 | };
220 |
221 | }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
222 | },{"_process":12,"crypto":6,"spark-md5":13}],4:[function(require,module,exports){
223 | var Promise = require('pouchdb/extras/promise')
224 | var extend = require('pouchdb-extend')
225 | var async = require('async')
226 |
227 | module.exports = function migrate(db, checkpointer, migration, options) {
228 | return checkpointer.get()
229 | .then(function(since) {
230 | return new Promise(function(resolve, reject) {
231 | var docs = []
232 |
233 | var queue = async.queue(function(result, next) {
234 | if (!result) {
235 | return checkpointer
236 | .set(change.seq)
237 | .then(next.bind({}, null))
238 | .catch(next)
239 | }
240 |
241 | db
242 | .bulkDocs({ docs: result })
243 | .then(function(response) {
244 | return checkpointer.set(change.seq)
245 | })
246 | .then(next.bind({}, null))
247 | .catch(next)
248 | }, 1)
249 |
250 |
251 | var feed = db.changes(extend({}, options, {
252 | include_docs: true,
253 | since: since
254 | }))
255 |
256 | feed.on('change', function(change) {
257 | var result = migration(change.doc)
258 |
259 | if (!options.live) {
260 | docs = result ? docs.concat(result) : docs
261 | return
262 | }
263 |
264 | queue.push(result)
265 | })
266 |
267 | feed.on('complete', function(info) {
268 | if (options.live) { return resolve(info) }
269 |
270 | db
271 | .bulkDocs({ docs: docs })
272 | .then(function(response) {
273 | return checkpointer.set(info.last_seq)
274 | })
275 | .then(function() {
276 | return db.info()
277 | })
278 | .then(function(dbinfo) {
279 | if (dbinfo.update_seq > info.last_seq) {
280 | return migrate(db, checkpointer, migration, options)
281 | }
282 | return info
283 | })
284 | .then(resolve)
285 | })
286 |
287 | feed.on('error', reject)
288 | })
289 | })
290 | }
291 |
292 | },{"async":5,"pouchdb-extend":9,"pouchdb/extras/promise":10}],5:[function(require,module,exports){
293 | (function (process,global){
294 | /*!
295 | * async
296 | * https://github.com/caolan/async
297 | *
298 | * Copyright 2010-2014 Caolan McMahon
299 | * Released under the MIT license
300 | */
301 | (function () {
302 |
303 | var async = {};
304 | function noop() {}
305 | function identity(v) {
306 | return v;
307 | }
308 | function toBool(v) {
309 | return !!v;
310 | }
311 | function notId(v) {
312 | return !v;
313 | }
314 |
315 | // global on the server, window in the browser
316 | var previous_async;
317 |
318 | // Establish the root object, `window` (`self`) in the browser, `global`
319 | // on the server, or `this` in some virtual machines. We use `self`
320 | // instead of `window` for `WebWorker` support.
321 | var root = typeof self === 'object' && self.self === self && self ||
322 | typeof global === 'object' && global.global === global && global ||
323 | this;
324 |
325 | if (root != null) {
326 | previous_async = root.async;
327 | }
328 |
329 | async.noConflict = function () {
330 | root.async = previous_async;
331 | return async;
332 | };
333 |
334 | function only_once(fn) {
335 | return function() {
336 | if (fn === null) throw new Error("Callback was already called.");
337 | fn.apply(this, arguments);
338 | fn = null;
339 | };
340 | }
341 |
342 | function _once(fn) {
343 | return function() {
344 | if (fn === null) return;
345 | fn.apply(this, arguments);
346 | fn = null;
347 | };
348 | }
349 |
350 | //// cross-browser compatiblity functions ////
351 |
352 | var _toString = Object.prototype.toString;
353 |
354 | var _isArray = Array.isArray || function (obj) {
355 | return _toString.call(obj) === '[object Array]';
356 | };
357 |
358 | // Ported from underscore.js isObject
359 | var _isObject = function(obj) {
360 | var type = typeof obj;
361 | return type === 'function' || type === 'object' && !!obj;
362 | };
363 |
364 | function _isArrayLike(arr) {
365 | return _isArray(arr) || (
366 | // has a positive integer length property
367 | typeof arr.length === "number" &&
368 | arr.length >= 0 &&
369 | arr.length % 1 === 0
370 | );
371 | }
372 |
373 | function _each(coll, iterator) {
374 | return _isArrayLike(coll) ?
375 | _arrayEach(coll, iterator) :
376 | _forEachOf(coll, iterator);
377 | }
378 |
379 | function _arrayEach(arr, iterator) {
380 | var index = -1,
381 | length = arr.length;
382 |
383 | while (++index < length) {
384 | iterator(arr[index], index, arr);
385 | }
386 | }
387 |
388 | function _map(arr, iterator) {
389 | var index = -1,
390 | length = arr.length,
391 | result = Array(length);
392 |
393 | while (++index < length) {
394 | result[index] = iterator(arr[index], index, arr);
395 | }
396 | return result;
397 | }
398 |
399 | function _range(count) {
400 | return _map(Array(count), function (v, i) { return i; });
401 | }
402 |
403 | function _reduce(arr, iterator, memo) {
404 | _arrayEach(arr, function (x, i, a) {
405 | memo = iterator(memo, x, i, a);
406 | });
407 | return memo;
408 | }
409 |
410 | function _forEachOf(object, iterator) {
411 | _arrayEach(_keys(object), function (key) {
412 | iterator(object[key], key);
413 | });
414 | }
415 |
416 | function _indexOf(arr, item) {
417 | for (var i = 0; i < arr.length; i++) {
418 | if (arr[i] === item) return i;
419 | }
420 | return -1;
421 | }
422 |
423 | var _keys = Object.keys || function (obj) {
424 | var keys = [];
425 | for (var k in obj) {
426 | if (obj.hasOwnProperty(k)) {
427 | keys.push(k);
428 | }
429 | }
430 | return keys;
431 | };
432 |
433 | function _keyIterator(coll) {
434 | var i = -1;
435 | var len;
436 | var keys;
437 | if (_isArrayLike(coll)) {
438 | len = coll.length;
439 | return function next() {
440 | i++;
441 | return i < len ? i : null;
442 | };
443 | } else {
444 | keys = _keys(coll);
445 | len = keys.length;
446 | return function next() {
447 | i++;
448 | return i < len ? keys[i] : null;
449 | };
450 | }
451 | }
452 |
453 | // Similar to ES6's rest param (http://ariya.ofilabs.com/2013/03/es6-and-rest-parameter.html)
454 | // This accumulates the arguments passed into an array, after a given index.
455 | // From underscore.js (https://github.com/jashkenas/underscore/pull/2140).
456 | function _restParam(func, startIndex) {
457 | startIndex = startIndex == null ? func.length - 1 : +startIndex;
458 | return function() {
459 | var length = Math.max(arguments.length - startIndex, 0);
460 | var rest = Array(length);
461 | for (var index = 0; index < length; index++) {
462 | rest[index] = arguments[index + startIndex];
463 | }
464 | switch (startIndex) {
465 | case 0: return func.call(this, rest);
466 | case 1: return func.call(this, arguments[0], rest);
467 | }
468 | // Currently unused but handle cases outside of the switch statement:
469 | // var args = Array(startIndex + 1);
470 | // for (index = 0; index < startIndex; index++) {
471 | // args[index] = arguments[index];
472 | // }
473 | // args[startIndex] = rest;
474 | // return func.apply(this, args);
475 | };
476 | }
477 |
478 | function _withoutIndex(iterator) {
479 | return function (value, index, callback) {
480 | return iterator(value, callback);
481 | };
482 | }
483 |
484 | //// exported async module functions ////
485 |
486 | //// nextTick implementation with browser-compatible fallback ////
487 |
488 | // capture the global reference to guard against fakeTimer mocks
489 | var _setImmediate = typeof setImmediate === 'function' && setImmediate;
490 |
491 | var _delay = _setImmediate ? function(fn) {
492 | // not a direct alias for IE10 compatibility
493 | _setImmediate(fn);
494 | } : function(fn) {
495 | setTimeout(fn, 0);
496 | };
497 |
498 | if (typeof process === 'object' && typeof process.nextTick === 'function') {
499 | async.nextTick = process.nextTick;
500 | } else {
501 | async.nextTick = _delay;
502 | }
503 | async.setImmediate = _setImmediate ? _delay : async.nextTick;
504 |
505 |
506 | async.forEach =
507 | async.each = function (arr, iterator, callback) {
508 | return async.eachOf(arr, _withoutIndex(iterator), callback);
509 | };
510 |
511 | async.forEachSeries =
512 | async.eachSeries = function (arr, iterator, callback) {
513 | return async.eachOfSeries(arr, _withoutIndex(iterator), callback);
514 | };
515 |
516 |
517 | async.forEachLimit =
518 | async.eachLimit = function (arr, limit, iterator, callback) {
519 | return _eachOfLimit(limit)(arr, _withoutIndex(iterator), callback);
520 | };
521 |
522 | async.forEachOf =
523 | async.eachOf = function (object, iterator, callback) {
524 | callback = _once(callback || noop);
525 | object = object || [];
526 | var size = _isArrayLike(object) ? object.length : _keys(object).length;
527 | var completed = 0;
528 | if (!size) {
529 | return callback(null);
530 | }
531 | _each(object, function (value, key) {
532 | iterator(object[key], key, only_once(done));
533 | });
534 | function done(err) {
535 | if (err) {
536 | callback(err);
537 | }
538 | else {
539 | completed += 1;
540 | if (completed >= size) {
541 | callback(null);
542 | }
543 | }
544 | }
545 | };
546 |
547 | async.forEachOfSeries =
548 | async.eachOfSeries = function (obj, iterator, callback) {
549 | callback = _once(callback || noop);
550 | obj = obj || [];
551 | var nextKey = _keyIterator(obj);
552 | var key = nextKey();
553 | function iterate() {
554 | var sync = true;
555 | if (key === null) {
556 | return callback(null);
557 | }
558 | iterator(obj[key], key, only_once(function (err) {
559 | if (err) {
560 | callback(err);
561 | }
562 | else {
563 | key = nextKey();
564 | if (key === null) {
565 | return callback(null);
566 | } else {
567 | if (sync) {
568 | async.nextTick(iterate);
569 | } else {
570 | iterate();
571 | }
572 | }
573 | }
574 | }));
575 | sync = false;
576 | }
577 | iterate();
578 | };
579 |
580 |
581 |
582 | async.forEachOfLimit =
583 | async.eachOfLimit = function (obj, limit, iterator, callback) {
584 | _eachOfLimit(limit)(obj, iterator, callback);
585 | };
586 |
587 | function _eachOfLimit(limit) {
588 |
589 | return function (obj, iterator, callback) {
590 | callback = _once(callback || noop);
591 | obj = obj || [];
592 | var nextKey = _keyIterator(obj);
593 | if (limit <= 0) {
594 | return callback(null);
595 | }
596 | var done = false;
597 | var running = 0;
598 | var errored = false;
599 |
600 | (function replenish () {
601 | if (done && running <= 0) {
602 | return callback(null);
603 | }
604 |
605 | while (running < limit && !errored) {
606 | var key = nextKey();
607 | if (key === null) {
608 | done = true;
609 | if (running <= 0) {
610 | callback(null);
611 | }
612 | return;
613 | }
614 | running += 1;
615 | iterator(obj[key], key, only_once(function (err) {
616 | running -= 1;
617 | if (err) {
618 | callback(err);
619 | errored = true;
620 | }
621 | else {
622 | replenish();
623 | }
624 | }));
625 | }
626 | })();
627 | };
628 | }
629 |
630 |
631 | function doParallel(fn) {
632 | return function (obj, iterator, callback) {
633 | return fn(async.eachOf, obj, iterator, callback);
634 | };
635 | }
636 | function doParallelLimit(fn) {
637 | return function (obj, limit, iterator, callback) {
638 | return fn(_eachOfLimit(limit), obj, iterator, callback);
639 | };
640 | }
641 | function doSeries(fn) {
642 | return function (obj, iterator, callback) {
643 | return fn(async.eachOfSeries, obj, iterator, callback);
644 | };
645 | }
646 |
647 | function _asyncMap(eachfn, arr, iterator, callback) {
648 | callback = _once(callback || noop);
649 | var results = [];
650 | eachfn(arr, function (value, index, callback) {
651 | iterator(value, function (err, v) {
652 | results[index] = v;
653 | callback(err);
654 | });
655 | }, function (err) {
656 | callback(err, results);
657 | });
658 | }
659 |
660 | async.map = doParallel(_asyncMap);
661 | async.mapSeries = doSeries(_asyncMap);
662 | async.mapLimit = doParallelLimit(_asyncMap);
663 |
664 | // reduce only has a series version, as doing reduce in parallel won't
665 | // work in many situations.
666 | async.inject =
667 | async.foldl =
668 | async.reduce = function (arr, memo, iterator, callback) {
669 | async.eachOfSeries(arr, function (x, i, callback) {
670 | iterator(memo, x, function (err, v) {
671 | memo = v;
672 | callback(err);
673 | });
674 | }, function (err) {
675 | callback(err || null, memo);
676 | });
677 | };
678 |
679 | async.foldr =
680 | async.reduceRight = function (arr, memo, iterator, callback) {
681 | var reversed = _map(arr, identity).reverse();
682 | async.reduce(reversed, memo, iterator, callback);
683 | };
684 |
685 | function _filter(eachfn, arr, iterator, callback) {
686 | var results = [];
687 | eachfn(arr, function (x, index, callback) {
688 | iterator(x, function (v) {
689 | if (v) {
690 | results.push({index: index, value: x});
691 | }
692 | callback();
693 | });
694 | }, function () {
695 | callback(_map(results.sort(function (a, b) {
696 | return a.index - b.index;
697 | }), function (x) {
698 | return x.value;
699 | }));
700 | });
701 | }
702 |
703 | async.select =
704 | async.filter = doParallel(_filter);
705 |
706 | async.selectLimit =
707 | async.filterLimit = doParallelLimit(_filter);
708 |
709 | async.selectSeries =
710 | async.filterSeries = doSeries(_filter);
711 |
712 | function _reject(eachfn, arr, iterator, callback) {
713 | _filter(eachfn, arr, function(value, cb) {
714 | iterator(value, function(v) {
715 | cb(!v);
716 | });
717 | }, callback);
718 | }
719 | async.reject = doParallel(_reject);
720 | async.rejectLimit = doParallelLimit(_reject);
721 | async.rejectSeries = doSeries(_reject);
722 |
723 | function _createTester(eachfn, check, getResult) {
724 | return function(arr, limit, iterator, cb) {
725 | function done() {
726 | if (cb) cb(getResult(false, void 0));
727 | }
728 | function iteratee(x, _, callback) {
729 | if (!cb) return callback();
730 | iterator(x, function (v) {
731 | if (cb && check(v)) {
732 | cb(getResult(true, x));
733 | cb = iterator = false;
734 | }
735 | callback();
736 | });
737 | }
738 | if (arguments.length > 3) {
739 | eachfn(arr, limit, iteratee, done);
740 | } else {
741 | cb = iterator;
742 | iterator = limit;
743 | eachfn(arr, iteratee, done);
744 | }
745 | };
746 | }
747 |
748 | async.any =
749 | async.some = _createTester(async.eachOf, toBool, identity);
750 |
751 | async.someLimit = _createTester(async.eachOfLimit, toBool, identity);
752 |
753 | async.all =
754 | async.every = _createTester(async.eachOf, notId, notId);
755 |
756 | async.everyLimit = _createTester(async.eachOfLimit, notId, notId);
757 |
758 | function _findGetResult(v, x) {
759 | return x;
760 | }
761 | async.detect = _createTester(async.eachOf, identity, _findGetResult);
762 | async.detectSeries = _createTester(async.eachOfSeries, identity, _findGetResult);
763 | async.detectLimit = _createTester(async.eachOfLimit, identity, _findGetResult);
764 |
765 | async.sortBy = function (arr, iterator, callback) {
766 | async.map(arr, function (x, callback) {
767 | iterator(x, function (err, criteria) {
768 | if (err) {
769 | callback(err);
770 | }
771 | else {
772 | callback(null, {value: x, criteria: criteria});
773 | }
774 | });
775 | }, function (err, results) {
776 | if (err) {
777 | return callback(err);
778 | }
779 | else {
780 | callback(null, _map(results.sort(comparator), function (x) {
781 | return x.value;
782 | }));
783 | }
784 |
785 | });
786 |
787 | function comparator(left, right) {
788 | var a = left.criteria, b = right.criteria;
789 | return a < b ? -1 : a > b ? 1 : 0;
790 | }
791 | };
792 |
793 | async.auto = function (tasks, callback) {
794 | callback = _once(callback || noop);
795 | var keys = _keys(tasks);
796 | var remainingTasks = keys.length;
797 | if (!remainingTasks) {
798 | return callback(null);
799 | }
800 |
801 | var results = {};
802 |
803 | var listeners = [];
804 | function addListener(fn) {
805 | listeners.unshift(fn);
806 | }
807 | function removeListener(fn) {
808 | var idx = _indexOf(listeners, fn);
809 | if (idx >= 0) listeners.splice(idx, 1);
810 | }
811 | function taskComplete() {
812 | remainingTasks--;
813 | _arrayEach(listeners.slice(0), function (fn) {
814 | fn();
815 | });
816 | }
817 |
818 | addListener(function () {
819 | if (!remainingTasks) {
820 | callback(null, results);
821 | }
822 | });
823 |
824 | _arrayEach(keys, function (k) {
825 | var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]];
826 | var taskCallback = _restParam(function(err, args) {
827 | if (args.length <= 1) {
828 | args = args[0];
829 | }
830 | if (err) {
831 | var safeResults = {};
832 | _forEachOf(results, function(val, rkey) {
833 | safeResults[rkey] = val;
834 | });
835 | safeResults[k] = args;
836 | callback(err, safeResults);
837 | }
838 | else {
839 | results[k] = args;
840 | async.setImmediate(taskComplete);
841 | }
842 | });
843 | var requires = task.slice(0, task.length - 1);
844 | // prevent dead-locks
845 | var len = requires.length;
846 | var dep;
847 | while (len--) {
848 | if (!(dep = tasks[requires[len]])) {
849 | throw new Error('Has inexistant dependency');
850 | }
851 | if (_isArray(dep) && _indexOf(dep, k) >= 0) {
852 | throw new Error('Has cyclic dependencies');
853 | }
854 | }
855 | function ready() {
856 | return _reduce(requires, function (a, x) {
857 | return (a && results.hasOwnProperty(x));
858 | }, true) && !results.hasOwnProperty(k);
859 | }
860 | if (ready()) {
861 | task[task.length - 1](taskCallback, results);
862 | }
863 | else {
864 | addListener(listener);
865 | }
866 | function listener() {
867 | if (ready()) {
868 | removeListener(listener);
869 | task[task.length - 1](taskCallback, results);
870 | }
871 | }
872 | });
873 | };
874 |
875 |
876 |
877 | async.retry = function(times, task, callback) {
878 | var DEFAULT_TIMES = 5;
879 | var DEFAULT_INTERVAL = 0;
880 |
881 | var attempts = [];
882 |
883 | var opts = {
884 | times: DEFAULT_TIMES,
885 | interval: DEFAULT_INTERVAL
886 | };
887 |
888 | function parseTimes(acc, t){
889 | if(typeof t === 'number'){
890 | acc.times = parseInt(t, 10) || DEFAULT_TIMES;
891 | } else if(typeof t === 'object'){
892 | acc.times = parseInt(t.times, 10) || DEFAULT_TIMES;
893 | acc.interval = parseInt(t.interval, 10) || DEFAULT_INTERVAL;
894 | } else {
895 | throw new Error('Unsupported argument type for \'times\': ' + typeof t);
896 | }
897 | }
898 |
899 | var length = arguments.length;
900 | if (length < 1 || length > 3) {
901 | throw new Error('Invalid arguments - must be either (task), (task, callback), (times, task) or (times, task, callback)');
902 | } else if (length <= 2 && typeof times === 'function') {
903 | callback = task;
904 | task = times;
905 | }
906 | if (typeof times !== 'function') {
907 | parseTimes(opts, times);
908 | }
909 | opts.callback = callback;
910 | opts.task = task;
911 |
912 | function wrappedTask(wrappedCallback, wrappedResults) {
913 | function retryAttempt(task, finalAttempt) {
914 | return function(seriesCallback) {
915 | task(function(err, result){
916 | seriesCallback(!err || finalAttempt, {err: err, result: result});
917 | }, wrappedResults);
918 | };
919 | }
920 |
921 | function retryInterval(interval){
922 | return function(seriesCallback){
923 | setTimeout(function(){
924 | seriesCallback(null);
925 | }, interval);
926 | };
927 | }
928 |
929 | while (opts.times) {
930 |
931 | var finalAttempt = !(opts.times-=1);
932 | attempts.push(retryAttempt(opts.task, finalAttempt));
933 | if(!finalAttempt && opts.interval > 0){
934 | attempts.push(retryInterval(opts.interval));
935 | }
936 | }
937 |
938 | async.series(attempts, function(done, data){
939 | data = data[data.length - 1];
940 | (wrappedCallback || opts.callback)(data.err, data.result);
941 | });
942 | }
943 |
944 | // If a callback is passed, run this as a controll flow
945 | return opts.callback ? wrappedTask() : wrappedTask;
946 | };
947 |
948 | async.waterfall = function (tasks, callback) {
949 | callback = _once(callback || noop);
950 | if (!_isArray(tasks)) {
951 | var err = new Error('First argument to waterfall must be an array of functions');
952 | return callback(err);
953 | }
954 | if (!tasks.length) {
955 | return callback();
956 | }
957 | function wrapIterator(iterator) {
958 | return _restParam(function (err, args) {
959 | if (err) {
960 | callback.apply(null, [err].concat(args));
961 | }
962 | else {
963 | var next = iterator.next();
964 | if (next) {
965 | args.push(wrapIterator(next));
966 | }
967 | else {
968 | args.push(callback);
969 | }
970 | ensureAsync(iterator).apply(null, args);
971 | }
972 | });
973 | }
974 | wrapIterator(async.iterator(tasks))();
975 | };
976 |
977 | function _parallel(eachfn, tasks, callback) {
978 | callback = callback || noop;
979 | var results = _isArrayLike(tasks) ? [] : {};
980 |
981 | eachfn(tasks, function (task, key, callback) {
982 | task(_restParam(function (err, args) {
983 | if (args.length <= 1) {
984 | args = args[0];
985 | }
986 | results[key] = args;
987 | callback(err);
988 | }));
989 | }, function (err) {
990 | callback(err, results);
991 | });
992 | }
993 |
994 | async.parallel = function (tasks, callback) {
995 | _parallel(async.eachOf, tasks, callback);
996 | };
997 |
998 | async.parallelLimit = function(tasks, limit, callback) {
999 | _parallel(_eachOfLimit(limit), tasks, callback);
1000 | };
1001 |
1002 | async.series = function(tasks, callback) {
1003 | _parallel(async.eachOfSeries, tasks, callback);
1004 | };
1005 |
1006 | async.iterator = function (tasks) {
1007 | function makeCallback(index) {
1008 | function fn() {
1009 | if (tasks.length) {
1010 | tasks[index].apply(null, arguments);
1011 | }
1012 | return fn.next();
1013 | }
1014 | fn.next = function () {
1015 | return (index < tasks.length - 1) ? makeCallback(index + 1): null;
1016 | };
1017 | return fn;
1018 | }
1019 | return makeCallback(0);
1020 | };
1021 |
1022 | async.apply = _restParam(function (fn, args) {
1023 | return _restParam(function (callArgs) {
1024 | return fn.apply(
1025 | null, args.concat(callArgs)
1026 | );
1027 | });
1028 | });
1029 |
1030 | function _concat(eachfn, arr, fn, callback) {
1031 | var result = [];
1032 | eachfn(arr, function (x, index, cb) {
1033 | fn(x, function (err, y) {
1034 | result = result.concat(y || []);
1035 | cb(err);
1036 | });
1037 | }, function (err) {
1038 | callback(err, result);
1039 | });
1040 | }
1041 | async.concat = doParallel(_concat);
1042 | async.concatSeries = doSeries(_concat);
1043 |
1044 | async.whilst = function (test, iterator, callback) {
1045 | callback = callback || noop;
1046 | if (test()) {
1047 | var next = _restParam(function(err, args) {
1048 | if (err) {
1049 | callback(err);
1050 | } else if (test.apply(this, args)) {
1051 | iterator(next);
1052 | } else {
1053 | callback(null);
1054 | }
1055 | });
1056 | iterator(next);
1057 | } else {
1058 | callback(null);
1059 | }
1060 | };
1061 |
1062 | async.doWhilst = function (iterator, test, callback) {
1063 | var calls = 0;
1064 | return async.whilst(function() {
1065 | return ++calls <= 1 || test.apply(this, arguments);
1066 | }, iterator, callback);
1067 | };
1068 |
1069 | async.until = function (test, iterator, callback) {
1070 | return async.whilst(function() {
1071 | return !test.apply(this, arguments);
1072 | }, iterator, callback);
1073 | };
1074 |
1075 | async.doUntil = function (iterator, test, callback) {
1076 | return async.doWhilst(iterator, function() {
1077 | return !test.apply(this, arguments);
1078 | }, callback);
1079 | };
1080 |
1081 | async.during = function (test, iterator, callback) {
1082 | callback = callback || noop;
1083 |
1084 | var next = _restParam(function(err, args) {
1085 | if (err) {
1086 | callback(err);
1087 | } else {
1088 | args.push(check);
1089 | test.apply(this, args);
1090 | }
1091 | });
1092 |
1093 | var check = function(err, truth) {
1094 | if (err) {
1095 | callback(err);
1096 | } else if (truth) {
1097 | iterator(next);
1098 | } else {
1099 | callback(null);
1100 | }
1101 | };
1102 |
1103 | test(check);
1104 | };
1105 |
1106 | async.doDuring = function (iterator, test, callback) {
1107 | var calls = 0;
1108 | async.during(function(next) {
1109 | if (calls++ < 1) {
1110 | next(null, true);
1111 | } else {
1112 | test.apply(this, arguments);
1113 | }
1114 | }, iterator, callback);
1115 | };
1116 |
1117 | function _queue(worker, concurrency, payload) {
1118 | if (concurrency == null) {
1119 | concurrency = 1;
1120 | }
1121 | else if(concurrency === 0) {
1122 | throw new Error('Concurrency must not be zero');
1123 | }
1124 | function _insert(q, data, pos, callback) {
1125 | if (callback != null && typeof callback !== "function") {
1126 | throw new Error("task callback must be a function");
1127 | }
1128 | q.started = true;
1129 | if (!_isArray(data)) {
1130 | data = [data];
1131 | }
1132 | if(data.length === 0 && q.idle()) {
1133 | // call drain immediately if there are no tasks
1134 | return async.setImmediate(function() {
1135 | q.drain();
1136 | });
1137 | }
1138 | _arrayEach(data, function(task) {
1139 | var item = {
1140 | data: task,
1141 | callback: callback || noop
1142 | };
1143 |
1144 | if (pos) {
1145 | q.tasks.unshift(item);
1146 | } else {
1147 | q.tasks.push(item);
1148 | }
1149 |
1150 | if (q.tasks.length === q.concurrency) {
1151 | q.saturated();
1152 | }
1153 | });
1154 | async.setImmediate(q.process);
1155 | }
1156 | function _next(q, tasks) {
1157 | return function(){
1158 | workers -= 1;
1159 | var args = arguments;
1160 | _arrayEach(tasks, function (task) {
1161 | task.callback.apply(task, args);
1162 | });
1163 | if (q.tasks.length + workers === 0) {
1164 | q.drain();
1165 | }
1166 | q.process();
1167 | };
1168 | }
1169 |
1170 | var workers = 0;
1171 | var q = {
1172 | tasks: [],
1173 | concurrency: concurrency,
1174 | payload: payload,
1175 | saturated: noop,
1176 | empty: noop,
1177 | drain: noop,
1178 | started: false,
1179 | paused: false,
1180 | push: function (data, callback) {
1181 | _insert(q, data, false, callback);
1182 | },
1183 | kill: function () {
1184 | q.drain = noop;
1185 | q.tasks = [];
1186 | },
1187 | unshift: function (data, callback) {
1188 | _insert(q, data, true, callback);
1189 | },
1190 | process: function () {
1191 | if (!q.paused && workers < q.concurrency && q.tasks.length) {
1192 | while(workers < q.concurrency && q.tasks.length){
1193 | var tasks = q.payload ?
1194 | q.tasks.splice(0, q.payload) :
1195 | q.tasks.splice(0, q.tasks.length);
1196 |
1197 | var data = _map(tasks, function (task) {
1198 | return task.data;
1199 | });
1200 |
1201 | if (q.tasks.length === 0) {
1202 | q.empty();
1203 | }
1204 | workers += 1;
1205 | var cb = only_once(_next(q, tasks));
1206 | worker(data, cb);
1207 | }
1208 | }
1209 | },
1210 | length: function () {
1211 | return q.tasks.length;
1212 | },
1213 | running: function () {
1214 | return workers;
1215 | },
1216 | idle: function() {
1217 | return q.tasks.length + workers === 0;
1218 | },
1219 | pause: function () {
1220 | q.paused = true;
1221 | },
1222 | resume: function () {
1223 | if (q.paused === false) { return; }
1224 | q.paused = false;
1225 | var resumeCount = Math.min(q.concurrency, q.tasks.length);
1226 | // Need to call q.process once per concurrent
1227 | // worker to preserve full concurrency after pause
1228 | for (var w = 1; w <= resumeCount; w++) {
1229 | async.setImmediate(q.process);
1230 | }
1231 | }
1232 | };
1233 | return q;
1234 | }
1235 |
1236 | async.queue = function (worker, concurrency) {
1237 | var q = _queue(function (items, cb) {
1238 | worker(items[0], cb);
1239 | }, concurrency, 1);
1240 |
1241 | return q;
1242 | };
1243 |
1244 | async.priorityQueue = function (worker, concurrency) {
1245 |
1246 | function _compareTasks(a, b){
1247 | return a.priority - b.priority;
1248 | }
1249 |
1250 | function _binarySearch(sequence, item, compare) {
1251 | var beg = -1,
1252 | end = sequence.length - 1;
1253 | while (beg < end) {
1254 | var mid = beg + ((end - beg + 1) >>> 1);
1255 | if (compare(item, sequence[mid]) >= 0) {
1256 | beg = mid;
1257 | } else {
1258 | end = mid - 1;
1259 | }
1260 | }
1261 | return beg;
1262 | }
1263 |
1264 | function _insert(q, data, priority, callback) {
1265 | if (callback != null && typeof callback !== "function") {
1266 | throw new Error("task callback must be a function");
1267 | }
1268 | q.started = true;
1269 | if (!_isArray(data)) {
1270 | data = [data];
1271 | }
1272 | if(data.length === 0) {
1273 | // call drain immediately if there are no tasks
1274 | return async.setImmediate(function() {
1275 | q.drain();
1276 | });
1277 | }
1278 | _arrayEach(data, function(task) {
1279 | var item = {
1280 | data: task,
1281 | priority: priority,
1282 | callback: typeof callback === 'function' ? callback : noop
1283 | };
1284 |
1285 | q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item);
1286 |
1287 | if (q.tasks.length === q.concurrency) {
1288 | q.saturated();
1289 | }
1290 | async.setImmediate(q.process);
1291 | });
1292 | }
1293 |
1294 | // Start with a normal queue
1295 | var q = async.queue(worker, concurrency);
1296 |
1297 | // Override push to accept second parameter representing priority
1298 | q.push = function (data, priority, callback) {
1299 | _insert(q, data, priority, callback);
1300 | };
1301 |
1302 | // Remove unshift function
1303 | delete q.unshift;
1304 |
1305 | return q;
1306 | };
1307 |
1308 | async.cargo = function (worker, payload) {
1309 | return _queue(worker, 1, payload);
1310 | };
1311 |
1312 | function _console_fn(name) {
1313 | return _restParam(function (fn, args) {
1314 | fn.apply(null, args.concat([_restParam(function (err, args) {
1315 | if (typeof console === 'object') {
1316 | if (err) {
1317 | if (console.error) {
1318 | console.error(err);
1319 | }
1320 | }
1321 | else if (console[name]) {
1322 | _arrayEach(args, function (x) {
1323 | console[name](x);
1324 | });
1325 | }
1326 | }
1327 | })]));
1328 | });
1329 | }
1330 | async.log = _console_fn('log');
1331 | async.dir = _console_fn('dir');
1332 | /*async.info = _console_fn('info');
1333 | async.warn = _console_fn('warn');
1334 | async.error = _console_fn('error');*/
1335 |
1336 | async.memoize = function (fn, hasher) {
1337 | var memo = {};
1338 | var queues = {};
1339 | hasher = hasher || identity;
1340 | var memoized = _restParam(function memoized(args) {
1341 | var callback = args.pop();
1342 | var key = hasher.apply(null, args);
1343 | if (key in memo) {
1344 | async.nextTick(function () {
1345 | callback.apply(null, memo[key]);
1346 | });
1347 | }
1348 | else if (key in queues) {
1349 | queues[key].push(callback);
1350 | }
1351 | else {
1352 | queues[key] = [callback];
1353 | fn.apply(null, args.concat([_restParam(function (args) {
1354 | memo[key] = args;
1355 | var q = queues[key];
1356 | delete queues[key];
1357 | for (var i = 0, l = q.length; i < l; i++) {
1358 | q[i].apply(null, args);
1359 | }
1360 | })]));
1361 | }
1362 | });
1363 | memoized.memo = memo;
1364 | memoized.unmemoized = fn;
1365 | return memoized;
1366 | };
1367 |
1368 | async.unmemoize = function (fn) {
1369 | return function () {
1370 | return (fn.unmemoized || fn).apply(null, arguments);
1371 | };
1372 | };
1373 |
1374 | function _times(mapper) {
1375 | return function (count, iterator, callback) {
1376 | mapper(_range(count), iterator, callback);
1377 | };
1378 | }
1379 |
1380 | async.times = _times(async.map);
1381 | async.timesSeries = _times(async.mapSeries);
1382 | async.timesLimit = function (count, limit, iterator, callback) {
1383 | return async.mapLimit(_range(count), limit, iterator, callback);
1384 | };
1385 |
1386 | async.seq = function (/* functions... */) {
1387 | var fns = arguments;
1388 | return _restParam(function (args) {
1389 | var that = this;
1390 |
1391 | var callback = args[args.length - 1];
1392 | if (typeof callback == 'function') {
1393 | args.pop();
1394 | } else {
1395 | callback = noop;
1396 | }
1397 |
1398 | async.reduce(fns, args, function (newargs, fn, cb) {
1399 | fn.apply(that, newargs.concat([_restParam(function (err, nextargs) {
1400 | cb(err, nextargs);
1401 | })]));
1402 | },
1403 | function (err, results) {
1404 | callback.apply(that, [err].concat(results));
1405 | });
1406 | });
1407 | };
1408 |
1409 | async.compose = function (/* functions... */) {
1410 | return async.seq.apply(null, Array.prototype.reverse.call(arguments));
1411 | };
1412 |
1413 |
1414 | function _applyEach(eachfn) {
1415 | return _restParam(function(fns, args) {
1416 | var go = _restParam(function(args) {
1417 | var that = this;
1418 | var callback = args.pop();
1419 | return eachfn(fns, function (fn, _, cb) {
1420 | fn.apply(that, args.concat([cb]));
1421 | },
1422 | callback);
1423 | });
1424 | if (args.length) {
1425 | return go.apply(this, args);
1426 | }
1427 | else {
1428 | return go;
1429 | }
1430 | });
1431 | }
1432 |
1433 | async.applyEach = _applyEach(async.eachOf);
1434 | async.applyEachSeries = _applyEach(async.eachOfSeries);
1435 |
1436 |
1437 | async.forever = function (fn, callback) {
1438 | var done = only_once(callback || noop);
1439 | var task = ensureAsync(fn);
1440 | function next(err) {
1441 | if (err) {
1442 | return done(err);
1443 | }
1444 | task(next);
1445 | }
1446 | next();
1447 | };
1448 |
1449 | function ensureAsync(fn) {
1450 | return _restParam(function (args) {
1451 | var callback = args.pop();
1452 | args.push(function () {
1453 | var innerArgs = arguments;
1454 | if (sync) {
1455 | async.setImmediate(function () {
1456 | callback.apply(null, innerArgs);
1457 | });
1458 | } else {
1459 | callback.apply(null, innerArgs);
1460 | }
1461 | });
1462 | var sync = true;
1463 | fn.apply(this, args);
1464 | sync = false;
1465 | });
1466 | }
1467 |
1468 | async.ensureAsync = ensureAsync;
1469 |
1470 | async.constant = _restParam(function(values) {
1471 | var args = [null].concat(values);
1472 | return function (callback) {
1473 | return callback.apply(this, args);
1474 | };
1475 | });
1476 |
1477 | async.wrapSync =
1478 | async.asyncify = function asyncify(func) {
1479 | return _restParam(function (args) {
1480 | var callback = args.pop();
1481 | var result;
1482 | try {
1483 | result = func.apply(this, args);
1484 | } catch (e) {
1485 | return callback(e);
1486 | }
1487 | // if result is Promise object
1488 | if (_isObject(result) && typeof result.then === "function") {
1489 | result.then(function(value) {
1490 | callback(null, value);
1491 | })["catch"](function(err) {
1492 | callback(err.message ? err : new Error(err));
1493 | });
1494 | } else {
1495 | callback(null, result);
1496 | }
1497 | });
1498 | };
1499 |
1500 | // Node.js
1501 | if (typeof module === 'object' && module.exports) {
1502 | module.exports = async;
1503 | }
1504 | // AMD / RequireJS
1505 | else if (typeof define === 'function' && define.amd) {
1506 | define([], function () {
1507 | return async;
1508 | });
1509 | }
1510 | // included directly via