├── .gitignore ├── .jshintrc ├── .travis.yml ├── README.md ├── index.js ├── package.json └── test ├── arrays.js └── mocha.opts /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | 29 | # Idea 30 | .idea -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | // -------------------------------------------------------------------- 3 | // JSHint Configuration, Strict Edition 4 | // -------------------------------------------------------------------- 5 | // 6 | // This is a options template for [JSHint][1], using [JSHint example][2] 7 | // and [Ory Band's example][3] as basis and setting config values to 8 | // be most strict: 9 | // 10 | // * set all enforcing options to true 11 | // * set all relaxing options to false 12 | // * set all environment options to false, except the browser value 13 | // * set all JSLint legacy options to false 14 | // 15 | // [1]: http://www.jshint.com/ 16 | // [2]: https://github.com/jshint/node-jshint/blob/master/example/config.json 17 | // [3]: https://github.com/oryband/dotfiles/blob/master/jshintrc 18 | // 19 | // @author http://michael.haschke.biz/ 20 | // @license http://unlicense.org/ 21 | 22 | // == Enforcing Options =============================================== 23 | // 24 | // These options tell JSHint to be more strict towards your code. Use 25 | // them if you want to allow only a safe subset of JavaScript, very 26 | // useful when your codebase is shared with a big number of developers 27 | // with different skill levels. 28 | 29 | "bitwise" : true, // Prohibit bitwise operators (&, |, ^, etc.). 30 | "curly" : true, // Require {} for every new block or scope. 31 | "eqeqeq" : true, // Require triple equals i.e. `===`. 32 | "forin" : true, // Tolerate `for in` loops without `hasOwnPrototype`. 33 | "immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` 34 | "latedef" : true, // Prohibit variable use before definition. 35 | "newcap" : true, // Require capitalization of all constructor functions e.g. `new F()`. 36 | "noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`. 37 | "noempty" : true, // Prohibit use of empty blocks. 38 | "nonew" : true, // Prohibit use of constructors for side-effects. 39 | "plusplus" : true, // Prohibit use of `++` & `--`. 40 | "regexp" : true, // Prohibit `.` and `[^...]` in regular expressions. 41 | "undef" : true, // Require all non-global variables be declared before they are used. 42 | "strict" : true, // Require `use strict` pragma in every file. 43 | "trailing" : true, // Prohibit trailing whitespaces. 44 | 45 | // == Relaxing Options ================================================ 46 | // 47 | // These options allow you to suppress certain types of warnings. Use 48 | // them only if you are absolutely positive that you know what you are 49 | // doing. 50 | 51 | "asi" : false, // Tolerate Automatic Semicolon Insertion (no semicolons). 52 | "boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments. 53 | "debug" : false, // Allow debugger statements e.g. browser breakpoints. 54 | "eqnull" : false, // Tolerate use of `== null`. 55 | "es5" : false, // Allow EcmaScript 5 syntax. 56 | "esnext" : false, // Allow ES.next specific features such as `const` and `let`. 57 | "evil" : false, // Tolerate use of `eval`. 58 | "expr" : false, // Tolerate `ExpressionStatement` as Programs. 59 | "funcscope" : false, // Tolerate declarations of variables inside of control structures while accessing them later from the outside. 60 | "globalstrict" : false, // Allow global "use strict" (also enables 'strict'). 61 | "iterator" : false, // Allow usage of __iterator__ property. 62 | "lastsemic" : false, // Tolerat missing semicolons when the it is omitted for the last statement in a one-line block. 63 | "laxbreak" : false, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons. 64 | "laxcomma" : false, // Suppress warnings about comma-first coding style. 65 | "loopfunc" : false, // Allow functions to be defined within loops. 66 | "multistr" : false, // Tolerate multi-line strings. 67 | "onecase" : false, // Tolerate switches with just one case. 68 | "proto" : false, // Tolerate __proto__ property. This property is deprecated. 69 | "regexdash" : false, // Tolerate unescaped last dash i.e. `[-...]`. 70 | "scripturl" : false, // Tolerate script-targeted URLs. 71 | "smarttabs" : false, // Tolerate mixed tabs and spaces when the latter are used for alignmnent only. 72 | "shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`. 73 | "sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`. 74 | "supernew" : false, // Tolerate `new function () { ... };` and `new Object;`. 75 | "validthis" : false, // Tolerate strict violations when the code is running in strict mode and you use this in a non-constructor function. 76 | 77 | // == Environments ==================================================== 78 | // 79 | // These options pre-define global variables that are exposed by 80 | // popular JavaScript libraries and runtime environments—such as 81 | // browser or node.js. 82 | 83 | "browser" : true, // Standard browser globals e.g. `window`, `document`. 84 | "couch" : false, // Enable globals exposed by CouchDB. 85 | "devel" : true, // Allow development statements e.g. `console.log();`. 86 | "dojo" : false, // Enable globals exposed by Dojo Toolkit. 87 | "jquery" : false, // Enable globals exposed by jQuery JavaScript library. 88 | "mootools" : false, // Enable globals exposed by MooTools JavaScript framework. 89 | "node" : true, // Enable globals available when code is running inside of the NodeJS runtime environment. 90 | "nonstandard" : false, // Define non-standard but widely adopted globals such as escape and unescape. 91 | "prototypejs" : false, // Enable globals exposed by Prototype JavaScript framework. 92 | "rhino" : false, // Enable globals available when your code is running inside of the Rhino runtime environment. 93 | "wsh" : false, // Enable globals available when your code is running as a script for the Windows Script Host. 94 | 95 | // == JSLint Legacy =================================================== 96 | // 97 | // These options are legacy from JSLint. Aside from bug fixes they will 98 | // not be improved in any way and might be removed at any point. 99 | 100 | "nomen" : false, // Prohibit use of initial or trailing underbars in names. 101 | "onevar" : false, // Allow only one `var` statement per function. 102 | "passfail" : false, // Stop on first error. 103 | "white" : false, // Check against strict whitespace and indentation rules. 104 | 105 | // == Undocumented Options ============================================ 106 | // 107 | // While I've found these options in [example1][2] and [example2][3] 108 | // they are not described in the [JSHint Options documentation][4]. 109 | // 110 | // [4]: http://www.jshint.com/options/ 111 | 112 | "maxerr" : 100, // Maximum errors before stopping. 113 | "predef" : [ // Extra globals. 114 | "define" 115 | ], 116 | "indent" : 4 // Specify indentation spacing 117 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.12" 4 | - "4.0" 5 | - "stable" 6 | - "iojs" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Promise Arrays [![NPM version][npm-version-image]][npm-url] [![Travis Build][travis-build-image]][travis-url] [![MIT License][license-image]][license-url] 2 | === 3 | A super small library to help you map and filter arrays with async operations. The only hard dependency is 4 | `Promise` so it needs to be present some how in your project (polyfill or native). 5 | Compatible with NodeJS, CommonJS, AMD and Browser Globals. 6 | 7 | ## Install 8 | Available on `npm`: 9 | ```bash 10 | $ npm install promise-arrays --save 11 | ``` 12 | 13 | ### NodeJS 14 | Install using `npm` Then: 15 | ```javascript 16 | // ES5: 17 | var PromiseArrays = require('promise-arrays'); 18 | 19 | // ES6: 20 | import PromiseArrays from 'promise-arrays'; 21 | ``` 22 | 23 | ### AMD 24 | Install `npm` and include in your AMD project, then: 25 | ```javascript 26 | // Include as dependency: 27 | define(['promise-arrays'], function (PromiseArrays) { 28 | // Use Here... 29 | }); 30 | ``` 31 | 32 | ### Browser Globals 33 | ```html 34 | 35 | ``` 36 | 37 | ## Usage 38 | All methods in this library return a `Promise` object. The API is similar to JS native `filter` and `map`, although 39 | you can return a `Promise` instead of just returning the result. 40 | 41 | ### PromiseArrays.map(array, callback) → Promise 42 | Mutate elements of an array using a given callback. Return a value to replace the original item or a `Promise` object. 43 | ```javascript 44 | var array = [1, 2, 3, 4, 5]; 45 | 46 | // Sync 47 | var promise = PromiseArrays.map(array, function (item, index) { 48 | return item * 10; 49 | }).then(function (result) { 50 | console.log(result); // [10, 20, 30, 40, 50] 51 | }); 52 | 53 | // Async 54 | var promise = PromiseArrays.map(array, function (item, index) { 55 | return new Promise(function (resolve, reject) { 56 | setTimeout(function () { 57 | resolve(item * 10); 58 | }, 100); 59 | }); 60 | }).then(function (result) { 61 | console.log(result); // [10, 20, 30, 40, 50] After ~ 100ms 62 | }); 63 | ``` 64 | 65 | You can also use `each` instead of `map`, which is basically an alias to `map`. 66 | 67 | ### PromiseArrays.filter(array, callback) → Promise 68 | Filter an array based on given criteria. API usage is similar to `.map` 69 | ```javascript 70 | var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 71 | var promise = PromiseArrays.filter(array, function (item, index) { 72 | return item > 3 && item < 8; // OR return a Promise 73 | }).then(function (result) { 74 | console.log(result); // [4, 5, 6, 7] 75 | }); 76 | ``` 77 | 78 | ## Test 79 | ```bash 80 | $ npm test 81 | ``` 82 | 83 | ## Changelog 84 | 85 | | Version | Date | Notes | 86 | |---------|------------|-------| 87 | | 0.1.0 | 2015-09-13 | `resolve` is no more passed to callbacks. Callbacks should return value or `Promise` | 88 | | 0.0.2 | 2015-09-10 | Added tests | 89 | | 0.0.1 | 2015-09-04 | Initial release | 90 | 91 | ## License 92 | This software is released under the [MIT License](http://sallar.mit-license.org/). 93 | 94 | Copyright © 2015 Sallar Kaboli 95 | 96 | Permission is hereby granted, free of charge, to any person obtaining a copy 97 | of this software and associated documentation files (the “Software”), to deal 98 | in the Software without restriction, including without limitation the rights 99 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 100 | copies of the Software, and to permit persons to whom the Software is 101 | furnished to do so, subject to the following conditions: 102 | 103 | The above copyright notice and this permission notice shall be included in 104 | all copies or substantial portions of the Software. 105 | 106 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 107 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 108 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 109 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 110 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 111 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 112 | THE SOFTWARE. 113 | 114 | [npm-url]: https://npmjs.com/package/promise-arrays 115 | [npm-version-image]: https://img.shields.io/npm/v/promise-arrays.svg 116 | 117 | [travis-url]: https://travis-ci.org/sallar/promise-arrays 118 | [travis-build-image]: https://img.shields.io/travis/sallar/promise-arrays.svg 119 | 120 | [license-url]: http://sallar.mit-license.org/ 121 | [license-image]: https://img.shields.io/npm/l/promise-arrays.svg -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Sallar Kaboli 3 | * @date 07.09.2015 4 | * @license 5 | * The MIT License (C) 2015 Sallar Kaboli 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining 8 | * a copy of this software and associated documentation files (the 9 | * "Software"), to deal in the Software without restriction, including 10 | * without limitation the rights to use, copy, modify, merge, publish, 11 | * distribute, sublicense, and/or sell copies of the Software, and to 12 | * permit persons to whom the Software is furnished to do so, subject to 13 | * the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be 16 | * included in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | 'use strict'; 27 | 28 | // UMD Definitions 29 | (function (name, definition) { 30 | // NodeJS & CommonJS 31 | if (typeof exports !== 'undefined' && typeof module !== 'undefined') { 32 | module.exports = definition(); 33 | } 34 | // AMD 35 | else if (typeof define === 'function' && typeof define.amd === 'object') { 36 | define(definition); 37 | } 38 | // Browser Globals 39 | else { 40 | this[name] = definition(); 41 | } 42 | })('PromiseArrays', function () { 43 | /** 44 | * Async Array Map 45 | * performs async operations on arrays and returns a promise with the results 46 | * @TODO Handle Rejection 47 | * @param array {Array} Array to perform mapping on 48 | * @param callback {function} Function to apply to each item 49 | * @returns {Promise} Promise containing the results 50 | */ 51 | function map (array, callback) { 52 | // Map each item to a new Promise 53 | array = array.map(function (item, index) { 54 | return new Promise(function (resolve) { 55 | // Pass callback to given callback 56 | resolve(callback(item, index)); 57 | }); 58 | }); 59 | 60 | // Wait for all promises to complete 61 | return Promise.all(array); 62 | } 63 | 64 | /** 65 | * Async Array Filter 66 | * Filters an array based on async operations and returns promise with the results 67 | * @param array {Array} Array to perform filtering on 68 | * @param callback {function} Function to use as criteria 69 | * @returns {Promise} Promise containing filtered results 70 | */ 71 | function filter (array, callback) { 72 | // Use async map function 73 | return map(array, callback).then(function (result) { 74 | // Then filter out false results 75 | return array.filter(function (item, index) { 76 | return result[index]; 77 | }); 78 | }); 79 | } 80 | 81 | /* Public Interface */ 82 | return { 83 | map : map, // Map 84 | each : map, // Each, alias to Map 85 | filter : filter // Filter 86 | }; 87 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "promise-arrays", 3 | "version": "0.1.0", 4 | "repository": "https://github.com/sallar/promise-arrays", 5 | "scripts": { 6 | "test": "./node_modules/mocha/bin/mocha" 7 | }, 8 | "author": { 9 | "name": "Sallar Kaboli", 10 | "url": "http://sallar.me", 11 | "email": "sallar.kaboli@gmail.com" 12 | }, 13 | "license": { 14 | "type": "MIT", 15 | "url": "http://sallar.mit-license.org/" 16 | }, 17 | "devDependencies": { 18 | "chai-as-promised": "^5.1.0", 19 | "chai-things": "^0.2.0", 20 | "mocha": "^2.3.2", 21 | "chai": "^3.2.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/arrays.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Sallar Kaboli 3 | * @date 08.09.2015 4 | */ 5 | "use strict"; 6 | 7 | var chai = require('chai'); 8 | chai.use(require('chai-things')); 9 | chai.use(require('chai-as-promised')); 10 | chai.should(); 11 | 12 | var map = require(__dirname + '/..').map, 13 | filter = require(__dirname + '/..').filter; 14 | 15 | describe('Array Map', function() { 16 | it('maps an array correctly', function(done) { 17 | var arr = [1, 2, 3, 4]; 18 | 19 | var arrMap = map(arr, function(item) { 20 | return item * 10; 21 | }); 22 | 23 | Promise.all([ 24 | arrMap.should.eventually.have.length(arr.length), 25 | arrMap.should.eventually.all.be.above(9) 26 | ]).should.notify(done); 27 | }); 28 | 29 | it('maps an array async correctly', function(done) { 30 | var arr = [1, 2, 3, 4]; 31 | 32 | var arrMap = map(arr, function(item) { 33 | return new Promise(function(resolve) { 34 | setTimeout(function() { 35 | resolve(item * 10); 36 | }, 100); 37 | }); 38 | }); 39 | 40 | Promise.all([ 41 | arrMap.should.eventually.have.length(arr.length), 42 | arrMap.should.eventually.all.be.above(9) 43 | ]).should.notify(done); 44 | }); 45 | }); 46 | 47 | describe('Array Filter', function() { 48 | it('filters an array correctly', function(done) { 49 | var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 50 | 51 | var arrFilter = filter(arr, function(item, i, resolve) { 52 | return item > 3 && item < 8; 53 | }); 54 | 55 | Promise.all([ 56 | arrFilter.should.eventually.have.length(4) 57 | ]).should.notify(done); 58 | }); 59 | }); -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --reporter spec --------------------------------------------------------------------------------