├── .gitignore ├── LICENSE ├── README.md ├── browser └── assentials.min.js ├── dist └── main.js ├── index.js ├── package.json ├── test ├── index.html └── index.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Simon Y. Blackwell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # assentials 2 | 3 | Essential polymorphic async functions ... every, forEach, map, reduce, some, flow, pipe, when, route and more! 4 | 5 | The `assentials` library provides asynchronous polymorphic versions of `forEach`, `every`, `map`, `reduce` and `some`. By "polymorphic" we mean you can pass in an `Array`, `Map`, `Set`, `generator`, `async generator`, or even an `object`. 6 | 7 | The `assentials` library also provides asynchronous sequenced processing of functions, Regular Expressions, and literals through versions of `flow`, `pipe`, `when`, `route` and `router`. 8 | 9 | `router` deserves special attention. It can handle just about anything as a condition. You can use literal matching, object destructuring, regular expressions, or functions as tests. The literal matching includes support for objects including nested values, Sets, and Maps. 10 | 11 | Finally, there is a `parallel` function which will provide the same argument to multiple functions and run them in parallel (to the degree JavaScript supports parallel processing). It returns a `Promise` for an array of the final results in the order they are resolved. 12 | 13 | All the above in about 2K minimized and gziped, 7K minimized, 12K raw! 14 | 15 | # installation 16 | 17 | npm install assentials 18 | 19 | # usage 20 | 21 | In NodeJS use: 22 | 23 | `const assentials = require("assentials");` 24 | 25 | In the browser, use the browserified version, `assentials.js`, in the browser directory. 26 | 27 | There are unit tests for just about every common case in the `test/index.js` file. You can load them in a browser using `test/index.html`. 28 | 29 | # API 30 | 31 | ## Iterating Functions 32 | 33 | All iterating functions take the target of iteration as their first argument. When passing an `object`, the leaf nodes are by default considered the members of the item being iterated. This means that `forEach` and other functions can walk the leaves of an entire JavaScript object that might be used to represent a graph. Optionally, the branch nodes of the object can also be included in iteration. 34 | 35 | The second argument to all the iterating functions is a function to apply to the current item being processed. This function can optionally be asynchronous itself and will be awaited. 36 | 37 | 38 | ```javascript 39 | async every(Iterable||object object, 40 | boolean [async] (any value,any key,Iterable||object)=>..., 41 | boolean nodes) 42 | ``` 43 | 44 | * Works like the regular JavaScript `every` function, except it supports `Generator`, `AsyncGenerator`, and `object` as `iterable`. If an `object` is passed in `nodes` can be set to `true` to process branches as well as leaves. 45 | 46 | 47 | ```javascript 48 | undefined forEach(Iterable||object iterable, 49 | undefined [async] (any value,any key,object object)=>..., 50 | boolean nodes) 51 | ``` 52 | 53 | * Works like the regular JavaScript `forEach` function, except it supports `Generator`, `AsyncGenerator`, and `object` as `iterable`. If an `object` is passed in `nodes` can be set to `true` to process branches as well as leaves. This is useful if processing a feedback graph like a neural net. 54 | 55 | 56 | ```javascript 57 | async any map(Iterable||object iterable, 58 | any [async] (any value,any key,object object)=>..., 59 | boolean skipUndefined = false, 60 | boolean nodes) 61 | ``` 62 | 63 | * Works like the regular JavaScript `map` function, except it returns the same class of iterable or object it was passed, e.g. if you map a `Set`, you will get a `Set` back. It also supports `Generator`, `AsyncGenerator`, and `object` as `iterable`. You can set `skipUndefined` to `true` in order to simply skip over `undefined` values returned from the map function. In the regular JavaScript function there is no way to do this without a subsequent filter, which could be expensive. If an `object` is passed in, `nodes` can be set to `true` to process branches as well as leaves. This is useful if processing a feedback graph like a neural net. 64 | 65 | ```javascript 66 | async any reduce(Iterable||object iterable, 67 | any [async] (any value,any key,object object)=>..., 68 | any accum, 69 | boolean continuable = true, 70 | boolean nodes) 71 | ``` 72 | 73 | * Works like the regular JavaScript `reduce` function, except it supports `Generator`, `AsyncGenerator`, and `object` as `iterable` Setting `continuable` to `false` will abort the reduce operation as soon as the reducing function returns `undefined`. If an `object` is passed in `nodes` can be set to `true` to process branches as well as leaves. This is useful if processing a graph database structure. 74 | 75 | 76 | ``` 77 | async some(Iterable||object object, 78 | boolean [async] (any value,any key,object object)=>..., 79 | boolean nodes) 80 | ``` 81 | 82 | * Works like the regular JavaScript `some` function, except it supports `Generator`, `AsyncGenerator`, and `object` as `iterable`. If an `object` is passed in `nodes` can be set to `true` to process branches as well as leaves. 83 | 84 | ## Sequential Processing Functions 85 | 86 | All sequence processing functions take one or more functions or literal values as their arguments. During processing, literal values are treated like they are functions of the form `(value) => value`. 87 | 88 | `async any flow(function||any arg[,...])(any input)` 89 | 90 | * Processes each argument by providing as an input the output of the previous argument's evaluation. As a result, any literals will simply replace the value from upstream and become the input for the next argument's evaluation. The flow will abort and return `undefined` if anything evaluates to `undefined`; otherwise, it will return the final evaluation. Think of it like a stream that stops flowing when there is nothing left. 91 | 92 | 93 | `async any pipe(function||any arg[,...])(any input)` 94 | 95 | * Processes each argument by providing as an input the output of the previous argument's evaluation. As a result, any literals will simply replace the value from upstream and become the input for the next argument's evaluation. The flow will continue through the last argument and return its evaluation. Functions within the flow must know how to handle `undefined` if an upstream argument can possibly evaluate to `undefined`. Think of it like a a real peipe that still exists even when there is nothing flowing through it. 96 | 97 | `async any route(any condition,function||any arg[,...])(input)` 98 | 99 | * Tests the `condition` against the `input`, and if `true` process each arg until the end or one evaluates to `undefined` or 100 | `{value: any value, done: boolean true}`. Note: if returning a done indicator, it must have at most two keys, `done` and `value` or just `done`. This minimizes the chance of accidental aborts when inputs happen to contain properties by the name `value` or `done`, which would be hard to debug. Returns either the replacement `value` or `undefined`. 101 | 102 | * For convenience, there is a `router(route aRoute[,...])` which takes a bunch of routes as its arguments. This function is itself a `until` whose condition is met when a route returns a value that is not undefined. This allows nesting of routes. 103 | 104 | * When used in the context of a `router`, a `route` that returns `{done: true}` will cause the router to immediatelly return; whereas `undefined` will allow the next route to be processed. 105 | 106 | * A router always returns the `input` or the `value` from `{value,done:true}`. Think of it like a package routing through many handlers who may look at or modify the contents of the package, but at the end of the day must deliver it to the next recipient in the chain before it utlimately gets delivered to the requestor, unless a valid substituion is provided via `{value,done:true}`. 107 | 108 | * If the `condition` is a function it receives the argument and must return true if the route is to be proceesed. 109 | 110 | * Otherwise, a single value is expected that must left equal the `condition`. By "left equal" we mean that the values satisfy `===`, the condition is a regular expression and the value matches it, or the condition and value are objects and all condition property values recursively left equal the value property values. This will even work with `Map` and `Set`. Additionally, if the condition property names can be converted into regular expressions or functions (even async ones!), they will be used to match which properties to test in the submitted value. At least one property must match. If destructuring is used, then the test must be a function that checks the destructured variables. The only thing that can't be matched is `undefined`. For example, 111 | 112 | ```javascript 113 | const route = assentials.route, 114 | 115 | handler = assentials.router( 116 | 117 | route(new Set("a","b"),(item) => ...), // literal left equal test 118 | 119 | route({age:21},(item) => ...), // literal left equal test 120 | 121 | route(({age}) => age>21,(item) => ...) // destructuring function test 122 | 123 | route( // property matching 124 | { 125 | // trivial case, something with a name property that has value "bill" 126 | [(key) => /name/.test(key)]:"bill" 127 | }, 128 | (item) => ... 129 | ), 130 | ) 131 | ``` 132 | 133 | 134 | * Typically, routes will be used with destructuring assignment or object left equal testing. You can route just about any object, but frequently they will be http request/response pairs or browser events, e.g. 135 | 136 | ```javascript 137 | const route = assentials.route, 138 | 139 | handler = assentials.router( 140 | 141 | // normalize urls to industry standard URL object 142 | route(({request:{url}}) => url!=null,({request}) => request.URL = new URL(url)), 143 | 144 | // literal match on "/" to change to "/index.html" 145 | route({request:{URL:{pathname:"/"}}, 146 | ({request}) => request.url.pathname = "/index.html"), 147 | 148 | // if no request body, abort by using {done: true} 149 | route(({request:{body}}) => !body || body.length=0, 150 | ({response}) => { response.end(""); return {done:true}; }), 151 | 152 | // parse the body 153 | route(({request:{body}}) => body.length>0, 154 | ({request}) => { request.body = bodyParser(request.body); }), 155 | 156 | ... 157 | 158 | route(({response:{sent}}) => !sent, 159 | ({response}) => { response.status = 404; response.end("Not Found"); }) 160 | ); 161 | 162 | http.createServer(function (request, response) { 163 | handler({request,response}); 164 | }).listen(8080); 165 | 166 | ``` 167 | 168 | You can also use a router for generalized destructive object transformation, which is effectively what is happening above. For non-destructive transformation us `map`. 169 | 170 | `async boolean trigger(any condition,function callback,[...])(input)` 171 | 172 | * Immediately returns the result of evaluating condition. The calls each callback. If you want to to conditionalize how the callbacks operate, then wrap them in a `flow`, `route`, `when`, or even another `trigger`. 173 | 174 | * See `route` for how `condition` is tested. 175 | 176 | `async any until(condition,...functions)(input)` 177 | 178 | Calls functions with `input` until condition is met and then returns the `input`' 179 | 180 | 181 | `async any when(any condition,function||any arg[,...])(input)` 182 | 183 | * Tests the `condition` against the `input`, and if `true` process each arg until the end or one evaluates to `undefined` or `{value: any value, done: boolean true}`. Note: if returning a done indicator, it must have at most two keys, `done` and `value` or just `done`. This minimizes the chance of accidental aborts which would be hard to debug. Returns the last evalutation. Otherwise, if the condition fails, returns the `input`. 184 | 185 | 186 | 187 | ## Parallel Processing Functions 188 | 189 | `async Array parallel(function f,[...])(any arg[,...])` 190 | 191 | Calls all the functions with the provided arguments. If any are asynchronous will await their resolution and returns a `Promise` for an array of results in the order they were resolved. 192 | 193 | 194 | # Internals 195 | 196 | For the iterating functions, `assentials` first turns the target of iteration into an asynchronous generator. This allows all subsequent logic to, for the most part, avoid conditionalizing on the type of item being iterated and keeps the code base small and easy to test. 197 | 198 | Converting keys into regular expression tests or functions. For keys that start with "/" and using a try block an attempt is made to convert the key into a regular expression using `const regxp = new RegExp(key)`. If it works, the function `(value) => regexp.test(value)` is returned. For keys that start with the word "function" or matches `/\(*\)*=>*` and sucessfully compiles to function using a try block. To ensure that your keys are always compilable, create them using structured assignment, e.g.: 199 | 200 | ``` 201 | { 202 | [/myregexp/]: value, 203 | // or a functionally identical key to the preceding key in the context of left equal 204 | [(key) => /myregexp/.test(key)]: value 205 | } 206 | 207 | ``` 208 | 209 | # Updates (reverse chronological order) 210 | 211 | 2019-05-10 v1.0.2 Reverted to old module format. Too many interal projects at AnyWhichWay were breaking when trying to use new module format. 212 | 213 | 2019-05-09 v1.0.1 Revised export to export specific functions not entire module. 214 | 215 | 2019-05-08 v1.0.0 Moved to JavaScript modules format for index.js. Webpack produces ./browser/assentials.min.js. There is no longer a non-minified browser file. The index.js file is webpack tree shaking compatible. 216 | 217 | 2019-03-21 v0.0.14 Further refinements to router. WARNING: The behavior of `route` has changed. To exit a route return `{value:value,done:true}`. If a route does not exit, if now returns `undefined` by default. 218 | 219 | 2019-03-21 v0.0.13 Added `until`. Modified `router` to use `until` rather than `when`, which could have resulted in extra routes being run. 220 | 221 | 2019-03-20 v0.0.12 `router` was returning the Iterable control object instead of just its value, fixed. 222 | 223 | 2019-03-16 v0.0.11 exported `leftEqual`, corrected issue where `leftEqual` did not work on arrays. 224 | 225 | 2019-03-08 v0.0.10 added `trigger` 226 | 227 | 2019-03-04 v0.0.9 added regular expression and functional keys in left equal 228 | 229 | 2019-03-03 v0.0.8 documentation updates 230 | 231 | 2019-02-20 v0.0.7b `router` redefined to use a `when` as its top level to allow it to return the `value` in `{value,done:true}` if it is not `undefined`. 232 | 233 | 2019-02-19 v0.0.6b In one case leftEqual switched order or left and right. Fixed. 234 | 235 | 2019-02-19 v0.0.5b Correct object matching for routes to be leftEqual. 236 | 237 | 2019-02-18 v0.0.4b Added support for the `Iterable` continuation object `{value,done}` with `when` and `route`. 238 | 239 | 2019-02-18 v0.0.3b Minor deep equal enhancement. 240 | 241 | 2019-02-16 v0.0.2b Added object literal routing. 242 | 243 | 2019-02-16 v0.0.0b Initial public release. 244 | -------------------------------------------------------------------------------- /browser/assentials.min.js: -------------------------------------------------------------------------------- 1 | !function(t){var e={};function n(r){if(e[r])return e[r].exports;var a=e[r]={i:r,l:!1,exports:{}};return t[r].call(a.exports,a,a.exports,n),a.l=!0,a.exports}n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var a in t)n.d(r,a,function(e){return t[e]}.bind(null,a));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=0)}([function(t,e,n){(function(){"use strict";const e=Object.getPrototypeOf(function*(){}()).constructor,n=(Object.getPrototypeOf(async function*(){}()).constructor,async(t,e)=>{if(t===e)return!0;if(typeof t!=typeof e)return!1;if(t&&!e||!t&&e)return!1;if(t&&"object"==typeof t){if(t instanceof RegExp)return t.test(e);if(Array.isArray(t)&&!Array.isArray(e))return!1;if(t instanceof Date)return e instanceof Date&&t.getTime()===e.getTime();if(t instanceof Map){if(!(e instanceof Map))return!1;if(t.size!==e.size)return!1;for(const[r,a]of t)if(!await n(a,e.get(r)))return!1;return!0}if(t instanceof Set){if(!(e instanceof Set))return!1;if(t.size!==e.size)return!1;const r=new Set;for(const a of t)if(e.has(a))r.add(a);else for(const t of e)await n(a,t)&&r.add(a);return r.size==t.size}return await c(Object.keys(t),async r=>{const a=s(r,!0);if("function"==typeof a){let o=0;return await c(Object.keys(e),async i=>!await a.call(t,i)||(o++,await n(t[r],e[i])))&&o>0}return await n(t[r],e[r])})}return!1}),r=async(t,e,n,{continuable:r,data:o,tree:i,nodes:c})=>{let f=0;for await(const s of t){let[t,u]=o instanceof Map||i?s:[f,s];if(n=void 0===n&&0===f?i&&"object"==typeof u?await a(u,e,n,r,c,t):u:i&&"object"==typeof u?await a(u,e,n,r,c,t):await e(n,u,t,o),f++,void 0===n&&!r)break}return n},a=async(t,e,n,a=!0,o,i)=>{if(!t||"object"!=typeof t)return e(n,t);o&&i&&await e(t,i,t);let c,f=t;return Symbol.iterator in t?f=async function*(t){for(const e of t)yield e}(t):Array.isArray(t)||Symbol.asyncIterator in t||(f=Object.entries(t),c=!0),r(f,e,n,{continuable:a,data:t,tree:c,nodes:o})},o=async(t,n,r)=>{if(!t||"object"!=typeof t)return n(t);let a,i,c=t;return Symbol.iterator in t?c=async function*(t){for(const e of t)yield e}(t):Array.isArray(t)||Symbol.asyncIterator in t||(c=Object.entries(t),a=!0),i=Array.isArray(t)?[]:t instanceof Set?new Set:t instanceof Map?new Map:Symbol.iterator in t||Symbol.asyncIterator in t?[]:Object.create(Object.getPrototypeOf(t)),i=await(async(t,e,n,{skipUndefined:r,tree:a,data:i})=>{let c=0;for await(const s of t){const[t,u]=i instanceof Map||a?s:[c,s];let y;c++,void 0===(y=a&&u&&"object"==typeof u?await o(u,e,r):await e(u,t,i))&&r||(n instanceof Set?await n.add(y):n instanceof Map||f(n,{del:!0,get:!0,set:!0})?await n.set(t,y):f(n,{getItem:!0,removeItem:!0,setItem:!0})?await n.setItem(t,y):n[t]=y)}return n})(c,n,i,{skipUndefined:r,tree:a,data:t}),t instanceof e?Symbol.iterator in t?function*(){for(const t of i)yield i}():async function*(){for(const t of i)yield i}():i},i=async(t,e,n,r)=>{if(!t||"object"!=typeof t)return e(t);n&&r&&await e(t,r,t);let a,o=t;return Symbol.iterator in t?o=async function*(t){for(const e of t)yield e}(t):Array.isArray(t)||Symbol.asyncIterator in t||(o=Object.entries(t),a=!0),await(async(t,e,{nodes:n,tree:r,data:a})=>{let o=0;for await(const c of t){const[t,f]=a instanceof Map||r?c:[o,c];o++,await i(f,e,n,t)}})(o,e,{nodes:n,tree:a,data:t}),!0},c=async(t,e,n)=>{let a,o=t;return Symbol.iterator in t?o=async function*(t){for(const e of t)yield e}(t):Array.isArray(t)||Symbol.asyncIterator in t||(o=Object.entries(t),a=!0),!!await r(o,async(t,n)=>await e(n)?t:void 0,!0,{continuable:!1,nodes:n,tree:a,data:t})},f=(t,e)=>Object.keys(e).every(e=>"function"==typeof t[e]),s=(t,e)=>{const r=typeof t;if("function"===r)return t;if(e&&"string"===r){const e=t.replace(/\n/g,"");try{const t=e.lastIndexOf("/");if("/"===e[0]&&t>0){const n=e.substring(1,t),r=e.substring(t+1),a=new RegExp(n,r);return t=>a.test(t)}if(e.startswith("function")||"/(*)*=>*".test(e))return Function("return "+e)()}catch(t){}}return null===t||["boolean","number","string"].includes(r)?e=>e===t:t&&"object"===r&&t instanceof RegExp?e=>t.test(e):e=>n(t,e)},u={every:c,exposes:f,flow:(...t)=>async e=>await a(t,async(t,e)=>"function"==typeof e?await e(t):e,e,!1),forEach:i,map:o,parallel:(...t)=>async(...e)=>{const n=[],r=[];for(const a of t){const t=(async()=>"function"==typeof a?a(...e).then(t=>r.push(t)):a)();n.push(t)}return await Promise.all(n),r},pipe:(...t)=>async e=>await a(t,async(t,e)=>"function"==typeof e?await e(t):e,e),reduce:a,route:(t,...e)=>async n=>{if(void 0!==t&&await s(t)(n))for(let t of e){if("function"==typeof(t=await t)&&(t=await t(n)),t&&"object"==typeof t){const e=Object.keys(t);if(t.done&&e.every(t=>"done"===t||"value"===t))return t.value}if(void 0===t)return}},router:(...t)=>async e=>{const n=await((t,...e)=>async n=>{const r=s(await t);for(let t of e)if("function"==typeof(t=await s(await t))&&(t=await t(n)),await r(t))return t;return n})(t=>void 0!==t,...t)(e);return n&&"object"==typeof n&&Object.keys(e).every(t=>"done"===t||"value"===t)?n.value:void 0!==n?n:e},some:async(t,e,n)=>{let a,o,i=t;return Symbol.iterator in t?i=async function*(t){for(const e of t)yield e}(t):Array.isArray(t)||Symbol.asyncIterator in t||(i=Object.entries(t),a=!0),await r(i,async(t,n)=>{if(!await e(n))return!0;o=!0},!0,{continuable:!1,nodes:n,tree:a,data:t}),o},when:(t,...e)=>async n=>{let r;if(void 0!==t&&await s(t)(n)){let t;for(let a of e){if("function"==typeof(a=await a)&&(t=await a(n)),t&&"object"==typeof t){const e=Object.keys(t);e.length<=2&&t.done&&e.every(t=>"done"===t||"value"===t)&&(r=t)}if(void 0===t||r)break}return r&&void 0!==r.value?r.value:t}return n},trigger:(t,...e)=>async n=>!(void 0===t||!await s(t)(n)||(setTimeout(()=>e.forEach(t=>t(n))),0)),leftEqual:n};t.exports=u,"undefined"!=typeof window&&(window.assentials=u)}).call(this)}]); -------------------------------------------------------------------------------- /dist/main.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | /******/ 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | /******/ 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) { 10 | /******/ return installedModules[moduleId].exports; 11 | /******/ } 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ i: moduleId, 15 | /******/ l: false, 16 | /******/ exports: {} 17 | /******/ }; 18 | /******/ 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | /******/ 22 | /******/ // Flag the module as loaded 23 | /******/ module.l = true; 24 | /******/ 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | /******/ 29 | /******/ 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | /******/ 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | /******/ 36 | /******/ // define getter function for harmony exports 37 | /******/ __webpack_require__.d = function(exports, name, getter) { 38 | /******/ if(!__webpack_require__.o(exports, name)) { 39 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 40 | /******/ } 41 | /******/ }; 42 | /******/ 43 | /******/ // define __esModule on exports 44 | /******/ __webpack_require__.r = function(exports) { 45 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 46 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 47 | /******/ } 48 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 49 | /******/ }; 50 | /******/ 51 | /******/ // create a fake namespace object 52 | /******/ // mode & 1: value is a module id, require it 53 | /******/ // mode & 2: merge all properties of value into the ns 54 | /******/ // mode & 4: return value when already ns object 55 | /******/ // mode & 8|1: behave like require 56 | /******/ __webpack_require__.t = function(value, mode) { 57 | /******/ if(mode & 1) value = __webpack_require__(value); 58 | /******/ if(mode & 8) return value; 59 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 60 | /******/ var ns = Object.create(null); 61 | /******/ __webpack_require__.r(ns); 62 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 63 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 64 | /******/ return ns; 65 | /******/ }; 66 | /******/ 67 | /******/ // getDefaultExport function for compatibility with non-harmony modules 68 | /******/ __webpack_require__.n = function(module) { 69 | /******/ var getter = module && module.__esModule ? 70 | /******/ function getDefault() { return module['default']; } : 71 | /******/ function getModuleExports() { return module; }; 72 | /******/ __webpack_require__.d(getter, 'a', getter); 73 | /******/ return getter; 74 | /******/ }; 75 | /******/ 76 | /******/ // Object.prototype.hasOwnProperty.call 77 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 78 | /******/ 79 | /******/ // __webpack_public_path__ 80 | /******/ __webpack_require__.p = ""; 81 | /******/ 82 | /******/ 83 | /******/ // Load entry module and return exports 84 | /******/ return __webpack_require__(__webpack_require__.s = 0); 85 | /******/ }) 86 | /************************************************************************/ 87 | /******/ ([ 88 | /* 0 */ 89 | /***/ (function(module, exports, __webpack_require__) { 90 | 91 | __webpack_require__(1); 92 | module.exports = __webpack_require__(2); 93 | 94 | 95 | /***/ }), 96 | /* 1 */ 97 | /***/ (function(module, exports, __webpack_require__) { 98 | 99 | (function() { 100 | "use strict"; 101 | 102 | const Generator = Object.getPrototypeOf((function*() {})()).constructor, 103 | AsyncGenerator = Object.getPrototypeOf((async function*() {})()).constructor, 104 | leftEqual = async (a,b) => { 105 | if(a===b) return true; 106 | if(typeof(a)!==typeof(b)) return false; 107 | if((a && !b) || (!a && b)) return false; 108 | if(a && typeof(a)==="object") { 109 | if(a instanceof RegExp) { 110 | return a.test(b); 111 | } 112 | if(Array.isArray(a)) { 113 | if(!Array.isArray(b)) return false; 114 | } 115 | if(a instanceof Date) { 116 | if(!(b instanceof Date)) return false; 117 | return a.getTime()===b.getTime(); 118 | } else if(a instanceof Map) { 119 | if(!(b instanceof Map)) return false; 120 | if(a.size!==b.size) return false; 121 | for(const [key,value] of a) { 122 | if(!await leftEqual(value,b.get(key))) return false; 123 | } 124 | return true; 125 | } else if(a instanceof Set) { 126 | if(!(b instanceof Set)) return false; 127 | if(a.size!==b.size) return false; 128 | const results = new Set(); 129 | for(const avalue of a) { 130 | if(b.has(avalue)) { 131 | results.add(avalue); 132 | } else { 133 | for(const bvalue of b) { 134 | if(await leftEqual(avalue,bvalue)) { 135 | results.add(avalue); 136 | } 137 | } 138 | } 139 | } 140 | if(results.size!=a.size) return false; 141 | return true; 142 | } else{ 143 | return await every(Object.keys(a),async (key) => { 144 | const test = toTest(key,true); 145 | if(typeof(test)==="function") { 146 | let count = 0; 147 | return await every(Object.keys(b),async (rkey) => { 148 | if(await test.call(a,rkey)) { 149 | count++; 150 | return await leftEqual(a[key],b[rkey]); 151 | } 152 | return true; 153 | }) && count > 0; 154 | } 155 | return await leftEqual(a[key],b[key]); 156 | }); 157 | } 158 | } 159 | return false; 160 | }, 161 | _reduceIterable = async (iterable,f,accum,{continuable,data,tree,nodes}) => { 162 | let i = 0; 163 | for await(const item of iterable) { 164 | let [key,value] = data instanceof Map || tree ? item : [i,item]; 165 | if(accum===undefined && i===0) { 166 | if(tree && typeof(value)==="object") { 167 | accum = await reduce(value,f,accum,continuable,nodes,key) 168 | } else { 169 | accum = value; 170 | } 171 | } else { 172 | if(tree && typeof(value)==="object") { 173 | accum = await reduce(value,f,accum,continuable,nodes,key) 174 | } else { 175 | accum = await f(accum,value,key,data); 176 | } 177 | } 178 | i++; 179 | if(accum===undefined && !continuable) break; 180 | } 181 | return accum; 182 | }, 183 | reduce = async (data,f,accum,continuable=true,nodes,recursing) => { 184 | if(!data || typeof(data)!=="object") { 185 | return f(accum,data); 186 | } 187 | if(nodes && recursing) await f(data,recursing,data); 188 | let iterable = data, tree; 189 | if(Symbol.iterator in data) { 190 | iterable = (async function*(data) { 191 | for(const item of data) { 192 | yield item; 193 | } 194 | })(data); 195 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 196 | iterable = Object.entries(data); 197 | tree = true; 198 | } 199 | return _reduceIterable(iterable,f,accum,{continuable,data,tree,nodes}); 200 | }, 201 | _mapIterable = async (asyncIterable,f,accum,{skipUndefined,tree,data}) => { 202 | let i = 0; 203 | for await(const item of asyncIterable) { 204 | const [key,value] = data instanceof Map || tree ? item : [i,item]; 205 | i++; 206 | let newvalue; 207 | if(tree && value && typeof(value)==="object") { 208 | newvalue = await map(value,f,skipUndefined); 209 | } else { 210 | newvalue = await f(value,key,data); 211 | } 212 | if(newvalue===undefined && skipUndefined) { 213 | continue; 214 | } 215 | if(accum instanceof Set) { 216 | await accum.add(newvalue); 217 | } else if(accum instanceof Map || exposes(accum,{del:true,get:true,set:true,})) { 218 | await accum.set(key,newvalue); 219 | } else if(exposes(accum,{getItem:true,removeItem:true,setItem:true})) { 220 | await accum.setItem(key,newvalue); 221 | } else { 222 | accum[key] = newvalue; 223 | } 224 | } 225 | return accum; 226 | }, 227 | map = async (data,f,skipUndefined) => { 228 | if(!data || typeof(data)!=="object") { 229 | return f(data); 230 | } 231 | let tree, iterable = data, accum; 232 | if(Symbol.iterator in data) { 233 | iterable = (async function*(data) { 234 | for(const item of data) { 235 | yield item; 236 | } 237 | })(data); 238 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 239 | iterable = Object.entries(data); 240 | tree = true; 241 | } 242 | if(Array.isArray(data)) { 243 | accum = []; 244 | } else if(data instanceof Set) { 245 | accum = new Set(); 246 | } else if(data instanceof Map) { 247 | accum = new Map(); 248 | } else if(Symbol.iterator in data || Symbol.asyncIterator in data) { 249 | accum = []; 250 | } else { 251 | accum = Object.create(Object.getPrototypeOf(data)); 252 | } 253 | accum = await _mapIterable(iterable,f,accum,{skipUndefined,tree,data}); 254 | if(data instanceof Generator) { 255 | if(Symbol.iterator in data) { 256 | return (function*() { for(const item of accum) yield accum; })(); 257 | } 258 | return (async function*() { for(const item of accum) yield accum; })(); 259 | } 260 | return accum; 261 | }, 262 | _forEachIterable = async (asyncIterable,f,{nodes,tree,data}) => { 263 | let i = 0; 264 | for await(const item of asyncIterable) { 265 | const [key,value] = data instanceof Map || tree ? item : [i,item]; 266 | i++; 267 | await forEach(value,f,nodes,key); 268 | } 269 | }, 270 | forEach = async (data,f,nodes,recursing) => { 271 | if(!data || typeof(data)!=="object") { 272 | return f(data); 273 | } 274 | if(nodes && recursing) await f(data,recursing,data); 275 | let tree, iterable = data; 276 | if(Symbol.iterator in data) { 277 | iterable = (async function*(data) { 278 | for(const item of data) { 279 | yield item; 280 | } 281 | })(data); 282 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 283 | iterable = Object.entries(data); 284 | tree = true; 285 | } 286 | await _forEachIterable(iterable,f,{nodes,tree,data}); 287 | return true; 288 | }, 289 | every = async (data,f,nodes) => { 290 | let iterable = data, tree; 291 | if(Symbol.iterator in data) { 292 | iterable = (async function*(data) { 293 | for(const item of data) { 294 | yield item; 295 | } 296 | })(data); 297 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 298 | iterable = Object.entries(data); 299 | tree = true; 300 | } 301 | return await _reduceIterable(iterable,async (accum,value) => await f(value) ? accum : undefined,true,{continuable:false,nodes,tree,data}) ? true : false; 302 | }, 303 | some = async (data,f,nodes) => { 304 | let iterable = data, tree, found; 305 | if(Symbol.iterator in data) { 306 | iterable = (async function*(data) { 307 | for(const item of data) { 308 | yield item; 309 | } 310 | })(data); 311 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 312 | iterable = Object.entries(data); 313 | tree = true; 314 | } 315 | await _reduceIterable(iterable,async (accum,value) => { 316 | if(await f(value)) { 317 | found = true; 318 | return undefined; 319 | } 320 | return true; 321 | }, 322 | true,{continuable:false,nodes,tree,data}); 323 | return found; 324 | }, 325 | exposes = (target,api) => Object.keys(api).every((key) => typeof(target[key])==="function"), 326 | toTest = (data,property) => { 327 | const type = typeof(data); 328 | if(type==="function") { 329 | return data; 330 | } 331 | if(property) { 332 | if(type==="string") { 333 | const key = data.replace(/\n/g,""); 334 | try { 335 | const i = key.lastIndexOf("/"); 336 | if(key[0]==="/" && i>0) { 337 | const exp = key.substring(1,i), 338 | flags = key.substring(i+1), 339 | regexp = new RegExp(exp,flags); 340 | return (key) => regexp.test(key); 341 | } else if(key.startswith("function") || `/\(*\)*=>*`.test(key)) { 342 | return Function("return " + key)(); 343 | } 344 | } catch(e) { 345 | ; 346 | } 347 | } 348 | } 349 | if(data===null || ["boolean","number","string"].includes(type)) { 350 | return arg => arg===data; 351 | } 352 | if(data && type==="object") { 353 | if(data instanceof RegExp) { 354 | return arg => data.test(arg); 355 | } 356 | } 357 | return (arg) => leftEqual(data,arg); 358 | }, 359 | // like pipe, but stops when accum is undefined 360 | flow = (...values) => async (arg) => { 361 | return await reduce(values,async (arg,value) => { 362 | return typeof(value)==="function" 363 | ? await value(arg) 364 | : value 365 | },arg,false) 366 | }, 367 | // passes an initial value through a series of funtions, literals may be injecte dand will replace the reduction at the point of injection 368 | pipe = (...values) => async (arg) => { 369 | return await reduce(values,async (arg,value) => { 370 | return typeof(value)==="function" 371 | ? await value(arg) 372 | : value 373 | },arg) 374 | }, 375 | // returns condition (a function, a RegExp, a literal to compare to arg) evaluation 376 | // if true before returning sets a timeout to start processing all callbacks 377 | trigger = (condition,...results) => async (arg) => { 378 | let done; 379 | if(condition!==undefined && await toTest(condition)(arg)) { 380 | setTimeout(() => results.forEach((result) => result(arg))); 381 | return true; 382 | } 383 | return false; 384 | }, 385 | // condition = (a function, a RegExp, a literal to compare to arg) is true; 386 | // evaluates the results using the arg until one satifies condition or all are evaluated, return satisfying result 387 | // else returns the arg passed in (which may have been modified) 388 | until = (condition,...functions) => async (arg) => { 389 | const test = toTest(await condition); 390 | let result; 391 | for(let value of functions) { 392 | value = await toTest(await value); 393 | if(typeof(value)==="function") { 394 | value = await value(arg); 395 | } 396 | if(await test(value)) { 397 | return value; 398 | } 399 | } 400 | return arg; 401 | }, 402 | // if condition (a function, a RegExp, a literal to compare to arg) is true; 403 | // evaluates the results using the arg until one is undefined or all are evaluated, return final evaluation 404 | // else returns the arg passed in (which may have been modified) 405 | when = (condition,...results) => async (arg) => { 406 | let done; 407 | if(condition!==undefined && await toTest(condition)(arg)) { 408 | let result; 409 | for(let value of results) { 410 | value = await value; 411 | if(typeof(value)==="function") { 412 | result = await value(arg); 413 | } 414 | if(result && typeof(result)==="object") { 415 | const keys = Object.keys(result); 416 | if(keys.length<=2 && result.done && keys.every(key => key==="done" || key==="value")) { 417 | done = result; 418 | } 419 | } 420 | if(result===undefined || done) break; 421 | } 422 | return done && done.value!==undefined ? done.value : result; 423 | } 424 | return arg; 425 | }, 426 | // if condition (a function, a RegExp, a literal to compare to arg) is true; 427 | // evaluates the results using the arg until one is undefined, {done: true}, or all are evaluated 428 | // returns value from {value:value,done:true} when it occurs or undefined no step returns {value:value,done:true} 429 | route = (condition,...results) => async (arg) => { 430 | if(condition!==undefined && await toTest(condition)(arg)) { 431 | for(let value of results) { 432 | value = await value; 433 | if(typeof(value)==="function") { 434 | value = await value(arg); 435 | } 436 | if(value && typeof(value)==="object") { 437 | const keys = Object.keys(value); 438 | if(value.done && keys.every(key => key==="done" || key==="value")) { 439 | return value.value; 440 | } 441 | } 442 | if(value===undefined) return; 443 | } 444 | } 445 | return; 446 | }, 447 | router = (...routes) => { 448 | return async (arg) => { 449 | const result = await until((arg) => arg!==undefined,...routes)(arg); 450 | return result && typeof(result)==="object" && Object.keys(arg).every(key => key==="done" || key==="value") ? result.value : result!==undefined ? result : arg; 451 | } 452 | }, 453 | parallel = (...values) => async (...args) => { 454 | const promises = [], 455 | results = []; 456 | let i = 0; 457 | for(const value of values) { 458 | const promise = (async () => typeof(value)==="function" ? value(...args).then(result => results.push(result)) : value)(); 459 | promises.push(promise); 460 | i++; 461 | } 462 | await Promise.all(promises); 463 | return results; 464 | }, 465 | 466 | assentials = {every,exposes,flow,forEach,map,parallel,pipe,reduce,route,router,some,when,trigger,leftEqual} 467 | 468 | if(true) module.exports = assentials; 469 | if(typeof(window)!=="undefined") window.assentials = assentials; 470 | }).call(this) 471 | 472 | /***/ }), 473 | /* 2 */ 474 | /***/ (function(module, exports, __webpack_require__) { 475 | 476 | (function() { 477 | "use strict"; 478 | 479 | const Generator = Object.getPrototypeOf((function*() {})()).constructor, 480 | AsyncGenerator = Object.getPrototypeOf((async function*() {})()).constructor, 481 | leftEqual = async (a,b) => { 482 | if(a===b) return true; 483 | if(typeof(a)!==typeof(b)) return false; 484 | if((a && !b) || (!a && b)) return false; 485 | if(a && typeof(a)==="object") { 486 | if(a instanceof RegExp) { 487 | return a.test(b); 488 | } 489 | if(Array.isArray(a)) { 490 | if(!Array.isArray(b)) return false; 491 | } 492 | if(a instanceof Date) { 493 | if(!(b instanceof Date)) return false; 494 | return a.getTime()===b.getTime(); 495 | } else if(a instanceof Map) { 496 | if(!(b instanceof Map)) return false; 497 | if(a.size!==b.size) return false; 498 | for(const [key,value] of a) { 499 | if(!await leftEqual(value,b.get(key))) return false; 500 | } 501 | return true; 502 | } else if(a instanceof Set) { 503 | if(!(b instanceof Set)) return false; 504 | if(a.size!==b.size) return false; 505 | const results = new Set(); 506 | for(const avalue of a) { 507 | if(b.has(avalue)) { 508 | results.add(avalue); 509 | } else { 510 | for(const bvalue of b) { 511 | if(await leftEqual(avalue,bvalue)) { 512 | results.add(avalue); 513 | } 514 | } 515 | } 516 | } 517 | if(results.size!=a.size) return false; 518 | return true; 519 | } else{ 520 | return await every(Object.keys(a),async (key) => { 521 | const test = toTest(key,true); 522 | if(typeof(test)==="function") { 523 | let count = 0; 524 | return await every(Object.keys(b),async (rkey) => { 525 | if(await test.call(a,rkey)) { 526 | count++; 527 | return await leftEqual(a[key],b[rkey]); 528 | } 529 | return true; 530 | }) && count > 0; 531 | } 532 | return await leftEqual(a[key],b[key]); 533 | }); 534 | } 535 | } 536 | return false; 537 | }, 538 | _reduceIterable = async (iterable,f,accum,{continuable,data,tree,nodes}) => { 539 | let i = 0; 540 | for await(const item of iterable) { 541 | let [key,value] = data instanceof Map || tree ? item : [i,item]; 542 | if(accum===undefined && i===0) { 543 | if(tree && typeof(value)==="object") { 544 | accum = await reduce(value,f,accum,continuable,nodes,key) 545 | } else { 546 | accum = value; 547 | } 548 | } else { 549 | if(tree && typeof(value)==="object") { 550 | accum = await reduce(value,f,accum,continuable,nodes,key) 551 | } else { 552 | accum = await f(accum,value,key,data); 553 | } 554 | } 555 | i++; 556 | if(accum===undefined && !continuable) break; 557 | } 558 | return accum; 559 | }, 560 | reduce = async (data,f,accum,continuable=true,nodes,recursing) => { 561 | if(!data || typeof(data)!=="object") { 562 | return f(accum,data); 563 | } 564 | if(nodes && recursing) await f(data,recursing,data); 565 | let iterable = data, tree; 566 | if(Symbol.iterator in data) { 567 | iterable = (async function*(data) { 568 | for(const item of data) { 569 | yield item; 570 | } 571 | })(data); 572 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 573 | iterable = Object.entries(data); 574 | tree = true; 575 | } 576 | return _reduceIterable(iterable,f,accum,{continuable,data,tree,nodes}); 577 | }, 578 | _mapIterable = async (asyncIterable,f,accum,{skipUndefined,tree,data}) => { 579 | let i = 0; 580 | for await(const item of asyncIterable) { 581 | const [key,value] = data instanceof Map || tree ? item : [i,item]; 582 | i++; 583 | let newvalue; 584 | if(tree && value && typeof(value)==="object") { 585 | newvalue = await map(value,f,skipUndefined); 586 | } else { 587 | newvalue = await f(value,key,data); 588 | } 589 | if(newvalue===undefined && skipUndefined) { 590 | continue; 591 | } 592 | if(accum instanceof Set) { 593 | await accum.add(newvalue); 594 | } else if(accum instanceof Map || exposes(accum,{del:true,get:true,set:true,})) { 595 | await accum.set(key,newvalue); 596 | } else if(exposes(accum,{getItem:true,removeItem:true,setItem:true})) { 597 | await accum.setItem(key,newvalue); 598 | } else { 599 | accum[key] = newvalue; 600 | } 601 | } 602 | return accum; 603 | }, 604 | map = async (data,f,skipUndefined) => { 605 | if(!data || typeof(data)!=="object") { 606 | return f(data); 607 | } 608 | let tree, iterable = data, accum; 609 | if(Symbol.iterator in data) { 610 | iterable = (async function*(data) { 611 | for(const item of data) { 612 | yield item; 613 | } 614 | })(data); 615 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 616 | iterable = Object.entries(data); 617 | tree = true; 618 | } 619 | if(Array.isArray(data)) { 620 | accum = []; 621 | } else if(data instanceof Set) { 622 | accum = new Set(); 623 | } else if(data instanceof Map) { 624 | accum = new Map(); 625 | } else if(Symbol.iterator in data || Symbol.asyncIterator in data) { 626 | accum = []; 627 | } else { 628 | accum = Object.create(Object.getPrototypeOf(data)); 629 | } 630 | accum = await _mapIterable(iterable,f,accum,{skipUndefined,tree,data}); 631 | if(data instanceof Generator) { 632 | if(Symbol.iterator in data) { 633 | return (function*() { for(const item of accum) yield accum; })(); 634 | } 635 | return (async function*() { for(const item of accum) yield accum; })(); 636 | } 637 | return accum; 638 | }, 639 | _forEachIterable = async (asyncIterable,f,{nodes,tree,data}) => { 640 | let i = 0; 641 | for await(const item of asyncIterable) { 642 | const [key,value] = data instanceof Map || tree ? item : [i,item]; 643 | i++; 644 | await forEach(value,f,nodes,key); 645 | } 646 | }, 647 | forEach = async (data,f,nodes,recursing) => { 648 | if(!data || typeof(data)!=="object") { 649 | return f(data); 650 | } 651 | if(nodes && recursing) await f(data,recursing,data); 652 | let tree, iterable = data; 653 | if(Symbol.iterator in data) { 654 | iterable = (async function*(data) { 655 | for(const item of data) { 656 | yield item; 657 | } 658 | })(data); 659 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 660 | iterable = Object.entries(data); 661 | tree = true; 662 | } 663 | await _forEachIterable(iterable,f,{nodes,tree,data}); 664 | return true; 665 | }, 666 | every = async (data,f,nodes) => { 667 | let iterable = data, tree; 668 | if(Symbol.iterator in data) { 669 | iterable = (async function*(data) { 670 | for(const item of data) { 671 | yield item; 672 | } 673 | })(data); 674 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 675 | iterable = Object.entries(data); 676 | tree = true; 677 | } 678 | return await _reduceIterable(iterable,async (accum,value) => await f(value) ? accum : undefined,true,{continuable:false,nodes,tree,data}) ? true : false; 679 | }, 680 | some = async (data,f,nodes) => { 681 | let iterable = data, tree, found; 682 | if(Symbol.iterator in data) { 683 | iterable = (async function*(data) { 684 | for(const item of data) { 685 | yield item; 686 | } 687 | })(data); 688 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 689 | iterable = Object.entries(data); 690 | tree = true; 691 | } 692 | await _reduceIterable(iterable,async (accum,value) => { 693 | if(await f(value)) { 694 | found = true; 695 | return undefined; 696 | } 697 | return true; 698 | }, 699 | true,{continuable:false,nodes,tree,data}); 700 | return found; 701 | }, 702 | exposes = (target,api) => Object.keys(api).every((key) => typeof(target[key])==="function"), 703 | toTest = (data,property) => { 704 | const type = typeof(data); 705 | if(type==="function") { 706 | return data; 707 | } 708 | if(property) { 709 | if(type==="string") { 710 | const key = data.replace(/\n/g,""); 711 | try { 712 | const i = key.lastIndexOf("/"); 713 | if(key[0]==="/" && i>0) { 714 | const exp = key.substring(1,i), 715 | flags = key.substring(i+1), 716 | regexp = new RegExp(exp,flags); 717 | return (key) => regexp.test(key); 718 | } else if(key.startswith("function") || `/\(*\)*=>*`.test(key)) { 719 | return Function("return " + key)(); 720 | } 721 | } catch(e) { 722 | ; 723 | } 724 | } 725 | } 726 | if(data===null || ["boolean","number","string"].includes(type)) { 727 | return arg => arg===data; 728 | } 729 | if(data && type==="object") { 730 | if(data instanceof RegExp) { 731 | return arg => data.test(arg); 732 | } 733 | } 734 | return (arg) => leftEqual(data,arg); 735 | }, 736 | // like pipe, but stops when accum is undefined 737 | flow = (...values) => async (arg) => { 738 | return await reduce(values,async (arg,value) => { 739 | return typeof(value)==="function" 740 | ? await value(arg) 741 | : value 742 | },arg,false) 743 | }, 744 | // passes an initial value through a series of funtions, literals may be injecte dand will replace the reduction at the point of injection 745 | pipe = (...values) => async (arg) => { 746 | return await reduce(values,async (arg,value) => { 747 | return typeof(value)==="function" 748 | ? await value(arg) 749 | : value 750 | },arg) 751 | }, 752 | // returns condition (a function, a RegExp, a literal to compare to arg) evaluation 753 | // if true before returning sets a timeout to start processing all callbacks 754 | trigger = (condition,...results) => async (arg) => { 755 | let done; 756 | if(condition!==undefined && await toTest(condition)(arg)) { 757 | setTimeout(() => results.forEach((result) => result(arg))); 758 | return true; 759 | } 760 | return false; 761 | }, 762 | // condition = (a function, a RegExp, a literal to compare to arg) is true; 763 | // evaluates the results using the arg until one satifies condition or all are evaluated, return satisfying result 764 | // else returns the arg passed in (which may have been modified) 765 | until = (condition,...functions) => async (arg) => { 766 | const test = toTest(await condition); 767 | let result; 768 | for(let value of functions) { 769 | value = await toTest(await value); 770 | if(typeof(value)==="function") { 771 | value = await value(arg); 772 | } 773 | if(await test(value)) { 774 | return value; 775 | } 776 | } 777 | return arg; 778 | }, 779 | // if condition (a function, a RegExp, a literal to compare to arg) is true; 780 | // evaluates the results using the arg until one is undefined or all are evaluated, return final evaluation 781 | // else returns the arg passed in (which may have been modified) 782 | when = (condition,...results) => async (arg) => { 783 | let done; 784 | if(condition!==undefined && await toTest(condition)(arg)) { 785 | let result; 786 | for(let value of results) { 787 | value = await value; 788 | if(typeof(value)==="function") { 789 | result = await value(arg); 790 | } 791 | if(result && typeof(result)==="object") { 792 | const keys = Object.keys(result); 793 | if(keys.length<=2 && result.done && keys.every(key => key==="done" || key==="value")) { 794 | done = result; 795 | } 796 | } 797 | if(result===undefined || done) break; 798 | } 799 | return done && done.value!==undefined ? done.value : result; 800 | } 801 | return arg; 802 | }, 803 | // if condition (a function, a RegExp, a literal to compare to arg) is true; 804 | // evaluates the results using the arg until one is undefined, {done: true}, or all are evaluated 805 | // returns value from {value:value,done:true} when it occurs or undefined no step returns {value:value,done:true} 806 | route = (condition,...results) => async (arg) => { 807 | if(condition!==undefined && await toTest(condition)(arg)) { 808 | for(let value of results) { 809 | value = await value; 810 | if(typeof(value)==="function") { 811 | value = await value(arg); 812 | } 813 | if(value && typeof(value)==="object") { 814 | const keys = Object.keys(value); 815 | if(value.done && keys.every(key => key==="done" || key==="value")) { 816 | return value.value; 817 | } 818 | } 819 | if(value===undefined) return; 820 | } 821 | } 822 | return; 823 | }, 824 | router = (...routes) => { 825 | return async (arg) => { 826 | const result = await until((arg) => arg!==undefined,...routes)(arg); 827 | return result && typeof(result)==="object" && Object.keys(arg).every(key => key==="done" || key==="value") ? result.value : result!==undefined ? result : arg; 828 | } 829 | }, 830 | parallel = (...values) => async (...args) => { 831 | const promises = [], 832 | results = []; 833 | let i = 0; 834 | for(const value of values) { 835 | const promise = (async () => typeof(value)==="function" ? value(...args).then(result => results.push(result)) : value)(); 836 | promises.push(promise); 837 | i++; 838 | } 839 | await Promise.all(promises); 840 | return results; 841 | }, 842 | 843 | assentials = {every,exposes,flow,forEach,map,parallel,pipe,reduce,route,router,some,when,trigger,leftEqual} 844 | 845 | if(true) module.exports = assentials; 846 | if(typeof(window)!=="undefined") window.assentials = assentials; 847 | }).call(this) 848 | 849 | /***/ }) 850 | /******/ ]); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | 4 | const Generator = Object.getPrototypeOf((function*() {})()).constructor, 5 | AsyncGenerator = Object.getPrototypeOf((async function*() {})()).constructor, 6 | leftEqual = async (a,b) => { 7 | if(a===b) return true; 8 | if(typeof(a)!==typeof(b)) return false; 9 | if((a && !b) || (!a && b)) return false; 10 | if(a && typeof(a)==="object") { 11 | if(a instanceof RegExp) { 12 | return a.test(b); 13 | } 14 | if(Array.isArray(a)) { 15 | if(!Array.isArray(b)) return false; 16 | } 17 | if(a instanceof Date) { 18 | if(!(b instanceof Date)) return false; 19 | return a.getTime()===b.getTime(); 20 | } else if(a instanceof Map) { 21 | if(!(b instanceof Map)) return false; 22 | if(a.size!==b.size) return false; 23 | for(const [key,value] of a) { 24 | if(!await leftEqual(value,b.get(key))) return false; 25 | } 26 | return true; 27 | } else if(a instanceof Set) { 28 | if(!(b instanceof Set)) return false; 29 | if(a.size!==b.size) return false; 30 | const results = new Set(); 31 | for(const avalue of a) { 32 | if(b.has(avalue)) { 33 | results.add(avalue); 34 | } else { 35 | for(const bvalue of b) { 36 | if(await leftEqual(avalue,bvalue)) { 37 | results.add(avalue); 38 | } 39 | } 40 | } 41 | } 42 | if(results.size!=a.size) return false; 43 | return true; 44 | } else{ 45 | return await every(Object.keys(a),async (key) => { 46 | const test = toTest(key,true); 47 | if(typeof(test)==="function") { 48 | let count = 0; 49 | return await every(Object.keys(b),async (rkey) => { 50 | if(await test.call(a,rkey)) { 51 | count++; 52 | return await leftEqual(a[key],b[rkey]); 53 | } 54 | return true; 55 | }) && count > 0; 56 | } 57 | return await leftEqual(a[key],b[key]); 58 | }); 59 | } 60 | } 61 | return false; 62 | }, 63 | _reduceIterable = async (iterable,f,accum,{continuable,data,tree,nodes}) => { 64 | let i = 0; 65 | for await(const item of iterable) { 66 | let [key,value] = data instanceof Map || tree ? item : [i,item]; 67 | if(accum===undefined && i===0) { 68 | if(tree && typeof(value)==="object") { 69 | accum = await reduce(value,f,accum,continuable,nodes,key) 70 | } else { 71 | accum = value; 72 | } 73 | } else { 74 | if(tree && typeof(value)==="object") { 75 | accum = await reduce(value,f,accum,continuable,nodes,key) 76 | } else { 77 | accum = await f(accum,value,key,data); 78 | } 79 | } 80 | i++; 81 | if(accum===undefined && !continuable) break; 82 | } 83 | return accum; 84 | }, 85 | reduce = async (data,f,accum,continuable=true,nodes,recursing) => { 86 | if(!data || typeof(data)!=="object") { 87 | return f(accum,data); 88 | } 89 | if(nodes && recursing) await f(data,recursing,data); 90 | let iterable = data, tree; 91 | if(Symbol.iterator in data) { 92 | iterable = (async function*(data) { 93 | for(const item of data) { 94 | yield item; 95 | } 96 | })(data); 97 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 98 | iterable = Object.entries(data); 99 | tree = true; 100 | } 101 | return _reduceIterable(iterable,f,accum,{continuable,data,tree,nodes}); 102 | }, 103 | _mapIterable = async (asyncIterable,f,accum,{skipUndefined,tree,data}) => { 104 | let i = 0; 105 | for await(const item of asyncIterable) { 106 | const [key,value] = data instanceof Map || tree ? item : [i,item]; 107 | i++; 108 | let newvalue; 109 | if(tree && value && typeof(value)==="object") { 110 | newvalue = await map(value,f,skipUndefined); 111 | } else { 112 | newvalue = await f(value,key,data); 113 | } 114 | if(newvalue===undefined && skipUndefined) { 115 | continue; 116 | } 117 | if(accum instanceof Set) { 118 | await accum.add(newvalue); 119 | } else if(accum instanceof Map || exposes(accum,{del:true,get:true,set:true,})) { 120 | await accum.set(key,newvalue); 121 | } else if(exposes(accum,{getItem:true,removeItem:true,setItem:true})) { 122 | await accum.setItem(key,newvalue); 123 | } else { 124 | accum[key] = newvalue; 125 | } 126 | } 127 | return accum; 128 | }, 129 | map = async (data,f,skipUndefined) => { 130 | if(!data || typeof(data)!=="object") { 131 | return f(data); 132 | } 133 | let tree, iterable = data, accum; 134 | if(Symbol.iterator in data) { 135 | iterable = (async function*(data) { 136 | for(const item of data) { 137 | yield item; 138 | } 139 | })(data); 140 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 141 | iterable = Object.entries(data); 142 | tree = true; 143 | } 144 | if(Array.isArray(data)) { 145 | accum = []; 146 | } else if(data instanceof Set) { 147 | accum = new Set(); 148 | } else if(data instanceof Map) { 149 | accum = new Map(); 150 | } else if(Symbol.iterator in data || Symbol.asyncIterator in data) { 151 | accum = []; 152 | } else { 153 | accum = Object.create(Object.getPrototypeOf(data)); 154 | } 155 | accum = await _mapIterable(iterable,f,accum,{skipUndefined,tree,data}); 156 | if(data instanceof Generator) { 157 | if(Symbol.iterator in data) { 158 | return (function*() { for(const item of accum) yield accum; })(); 159 | } 160 | return (async function*() { for(const item of accum) yield accum; })(); 161 | } 162 | return accum; 163 | }, 164 | _forEachIterable = async (asyncIterable,f,{nodes,tree,data}) => { 165 | let i = 0; 166 | for await(const item of asyncIterable) { 167 | const [key,value] = data instanceof Map || tree ? item : [i,item]; 168 | i++; 169 | await forEach(value,f,nodes,key); 170 | } 171 | }, 172 | forEach = async (data,f,nodes,recursing) => { 173 | if(!data || typeof(data)!=="object") { 174 | return f(data); 175 | } 176 | if(nodes && recursing) await f(data,recursing,data); 177 | let tree, iterable = data; 178 | if(Symbol.iterator in data) { 179 | iterable = (async function*(data) { 180 | for(const item of data) { 181 | yield item; 182 | } 183 | })(data); 184 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 185 | iterable = Object.entries(data); 186 | tree = true; 187 | } 188 | await _forEachIterable(iterable,f,{nodes,tree,data}); 189 | return true; 190 | }, 191 | every = async (data,f,nodes) => { 192 | let iterable = data, tree; 193 | if(Symbol.iterator in data) { 194 | iterable = (async function*(data) { 195 | for(const item of data) { 196 | yield item; 197 | } 198 | })(data); 199 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 200 | iterable = Object.entries(data); 201 | tree = true; 202 | } 203 | return await _reduceIterable(iterable,async (accum,value) => await f(value) ? accum : undefined,true,{continuable:false,nodes,tree,data}) ? true : false; 204 | }, 205 | some = async (data,f,nodes) => { 206 | let iterable = data, tree, found; 207 | if(Symbol.iterator in data) { 208 | iterable = (async function*(data) { 209 | for(const item of data) { 210 | yield item; 211 | } 212 | })(data); 213 | } else if(!Array.isArray(data) && !(Symbol.asyncIterator in data)) { 214 | iterable = Object.entries(data); 215 | tree = true; 216 | } 217 | await _reduceIterable(iterable,async (accum,value) => { 218 | if(await f(value)) { 219 | found = true; 220 | return undefined; 221 | } 222 | return true; 223 | }, 224 | true,{continuable:false,nodes,tree,data}); 225 | return found; 226 | }, 227 | exposes = (target,api) => Object.keys(api).every((key) => typeof(target[key])==="function"), 228 | toTest = (data,property) => { 229 | const type = typeof(data); 230 | if(type==="function") { 231 | return data; 232 | } 233 | if(property) { 234 | if(type==="string") { 235 | const key = data.replace(/\n/g,""); 236 | try { 237 | const i = key.lastIndexOf("/"); 238 | if(key[0]==="/" && i>0) { 239 | const exp = key.substring(1,i), 240 | flags = key.substring(i+1), 241 | regexp = new RegExp(exp,flags); 242 | return (key) => regexp.test(key); 243 | } else if(key.startswith("function") || `/\(*\)*=>*`.test(key)) { 244 | return Function("return " + key)(); 245 | } 246 | } catch(e) { 247 | ; 248 | } 249 | } 250 | } 251 | if(data===null || ["boolean","number","string"].includes(type)) { 252 | return arg => arg===data; 253 | } 254 | if(data && type==="object") { 255 | if(data instanceof RegExp) { 256 | return arg => data.test(arg); 257 | } 258 | } 259 | return (arg) => leftEqual(data,arg); 260 | }, 261 | // like pipe, but stops when accum is undefined 262 | flow = (...values) => async (arg) => { 263 | return await reduce(values,async (arg,value) => { 264 | return typeof(value)==="function" 265 | ? await value(arg) 266 | : value 267 | },arg,false) 268 | }, 269 | // passes an initial value through a series of funtions, literals may be injecte dand will replace the reduction at the point of injection 270 | pipe = (...values) => async (arg) => { 271 | return await reduce(values,async (arg,value) => { 272 | return typeof(value)==="function" 273 | ? await value(arg) 274 | : value 275 | },arg) 276 | }, 277 | // returns condition (a function, a RegExp, a literal to compare to arg) evaluation 278 | // if true before returning sets a timeout to start processing all callbacks 279 | trigger = (condition,...results) => async (arg) => { 280 | let done; 281 | if(condition!==undefined && await toTest(condition)(arg)) { 282 | setTimeout(() => results.forEach((result) => result(arg))); 283 | return true; 284 | } 285 | return false; 286 | }, 287 | // condition = (a function, a RegExp, a literal to compare to arg) is true; 288 | // evaluates the results using the arg until one satifies condition or all are evaluated, return satisfying result 289 | // else returns the arg passed in (which may have been modified) 290 | until = (condition,...functions) => async (arg) => { 291 | const test = toTest(await condition); 292 | let result; 293 | for(let value of functions) { 294 | value = await toTest(await value); 295 | if(typeof(value)==="function") { 296 | value = await value(arg); 297 | } 298 | if(await test(value)) { 299 | return value; 300 | } 301 | } 302 | return arg; 303 | }, 304 | // if condition (a function, a RegExp, a literal to compare to arg) is true; 305 | // evaluates the results using the arg until one is undefined or all are evaluated, return final evaluation 306 | // else returns the arg passed in (which may have been modified) 307 | when = (condition,...results) => async (arg) => { 308 | let done; 309 | if(condition!==undefined && await toTest(condition)(arg)) { 310 | let result; 311 | for(let value of results) { 312 | value = await value; 313 | if(typeof(value)==="function") { 314 | result = await value(arg); 315 | } 316 | if(result && typeof(result)==="object") { 317 | const keys = Object.keys(result); 318 | if(keys.length<=2 && result.done && keys.every(key => key==="done" || key==="value")) { 319 | done = result; 320 | } 321 | } 322 | if(result===undefined || done) break; 323 | } 324 | return done && done.value!==undefined ? done.value : result; 325 | } 326 | return arg; 327 | }, 328 | // if condition (a function, a RegExp, a literal to compare to arg) is true; 329 | // evaluates the results using the arg until one is undefined, {done: true}, or all are evaluated 330 | // returns value from {value:value,done:true} when it occurs or undefined no step returns {value:value,done:true} 331 | route = (condition,...results) => async (arg) => { 332 | if(condition!==undefined && await toTest(condition)(arg)) { 333 | for(let value of results) { 334 | value = await value; 335 | if(typeof(value)==="function") { 336 | value = await value(arg); 337 | } 338 | if(value && typeof(value)==="object") { 339 | const keys = Object.keys(value); 340 | if(value.done && keys.every(key => key==="done" || key==="value")) { 341 | return value.value; 342 | } 343 | } 344 | if(value===undefined) return; 345 | } 346 | } 347 | return; 348 | }, 349 | router = (...routes) => { 350 | return async (arg) => { 351 | const result = await until((arg) => arg!==undefined,...routes)(arg); 352 | return result && typeof(result)==="object" && Object.keys(arg).every(key => key==="done" || key==="value") ? result.value : result!==undefined ? result : arg; 353 | } 354 | }, 355 | parallel = (...values) => async (...args) => { 356 | const promises = [], 357 | results = []; 358 | let i = 0; 359 | for(const value of values) { 360 | const promise = (async () => typeof(value)==="function" ? value(...args).then(result => results.push(result)) : value)(); 361 | promises.push(promise); 362 | i++; 363 | } 364 | await Promise.all(promises); 365 | return results; 366 | }; 367 | 368 | const assentials = {every,exposes,flow,forEach,map,parallel,pipe,reduce,route,router,some,when,trigger,leftEqual}; 369 | 370 | if(typeof(module)!=="undefined") { 371 | module.exports = assentials; 372 | } 373 | if(typeof(window)!=="undefined") { 374 | window.assentials = assentials; 375 | } 376 | }).call(this); 377 | 378 | 379 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "assentials", 3 | "version": "v1.0.2", 4 | "description": "Essential polymorphic async functions ... every, forEach, map, reduce, some, flow, pipe, when, route and more!", 5 | "engines": {}, 6 | "license": "MIT", 7 | "sideEffects": false, 8 | "scripts": { 9 | "prepare": "webpack index.js -o ./browser/assentials.min.js", 10 | "test": "mocha test/index.js" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/anywhichway/assentials.git" 15 | }, 16 | "keywords": [], 17 | "author": "Simon Y. Blackwell (http://www.github.com/anywhichway)", 18 | "bugs": { 19 | "url": "https://github.com/anywhichway/assentials/issues" 20 | }, 21 | "homepage": "https://github.com/anywhichway/assentials#readme", 22 | "devDependencies": { 23 | "benchmark": "^2.1.3", 24 | "blanket": "^1.2.3", 25 | "chai": "^3.4.1", 26 | "codacy-coverage": "^2.0.0", 27 | "codeclimate-test-reporter": "^0.2.0", 28 | "istanbul": "^0.4.2", 29 | "mocha": "^2.3.4", 30 | "uglify-es": "^3.1.6", 31 | "benchtest": "^2.0.2", 32 | "webpack": "^4.30.0", 33 | "webpack-cli": "^3.3.0" 34 | }, 35 | "dependencies": {} 36 | } 37 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | var mocha, 2 | chai, 3 | expect, 4 | assentials; 5 | if(typeof(window)==="undefined") { 6 | chai = require("chai"); 7 | expect = chai.expect; 8 | assentials = require("../index.js"); 9 | } 10 | 11 | describe("leftEqual",function() { 12 | it("array",async () => { 13 | const result = await assentials.leftEqual([1,2],[1,2,3]); 14 | expect(result).equal(true); 15 | }); 16 | it("array fail",async () => { 17 | const result = await assentials.leftEqual([1,2],[1,3,2]); 18 | expect(result).equal(false); 19 | }) 20 | }); 21 | 22 | describe("every",function() { 23 | it("array",async () => { 24 | const result = await assentials.every([1,2,3],item => typeof(item)==="number"); 25 | expect(result).equal(true); 26 | }); 27 | it("Set",async () => { 28 | const result = await assentials.every(new Set([1,2,3]),item => typeof(item)==="number"); 29 | expect(result).equal(true); 30 | }); 31 | it("Map",async () => { 32 | const result = await assentials.every(new Map([[1,1],[2,2],[3,3]]),item => typeof(item)==="number"); 33 | expect(result).equal(true); 34 | }) 35 | it("generator", async () => { 36 | const result = await assentials.every((function *() { for(const item of [1,2,3]) yield item;})(),item => typeof(item)==="number"); 37 | expect(result).equal(true); 38 | }); 39 | it("async generator", async () => { 40 | const result = await assentials.every((async function *() { for(const item of [1,2,3]) yield item;})(),item => typeof(item)==="number"); 41 | expect(result).equal(true); 42 | }); 43 | it("document tree",async () => { 44 | const result = await assentials.every({1:1,2:{2:2}},item => typeof(item)==="number"); 45 | expect(result).equal(true); 46 | }); 47 | it("document tree nodes",async () => { 48 | const result = await assentials.every({1:1,2:{2:2}},item => typeof(item)==="number" || (item && typeof(item)==="object"),true); 49 | expect(result).equal(true); 50 | }) 51 | }); 52 | describe("some",function() { 53 | it("array",async () => { 54 | const result = await assentials.some(["1",2,3],item => typeof(item)==="number"); 55 | expect(result).equal(true); 56 | }); 57 | it("Set",async () => { 58 | const result = await assentials.some(new Set(["1",2,3]),item => typeof(item)==="number"); 59 | expect(result).equal(true); 60 | }); 61 | it("Map",async () => { 62 | const result = await assentials.some(new Map([[1,"1"],[2,2],[3,3]]),item => typeof(item)==="number"); 63 | expect(result).equal(true); 64 | }) 65 | it("generator", async () => { 66 | const result = await assentials.some((function *() { for(const item of ["1",2,3]) yield item;})(),item => typeof(item)==="number"); 67 | expect(result).equal(true); 68 | }); 69 | it("async generator", async () => { 70 | const result = await assentials.some((async function *() { for(const item of ["1",2,3]) yield item;})(),item => typeof(item)==="number"); 71 | expect(result).equal(true); 72 | }); 73 | it("document tree",async () => { 74 | const result = await assentials.some({1:"1",2:{2:2}},item => typeof(item)==="number"); 75 | expect(result).equal(true); 76 | }); 77 | it("document tree nodes",async () => { 78 | const result = await assentials.some({1:"1",2:{2:2}},item => typeof(item)==="number",true); 79 | expect(result).equal(true); 80 | }) 81 | }); 82 | 83 | describe("forEach",function() { 84 | it("array",async () => { 85 | const result = []; 86 | await assentials.forEach([1,2,3],item => result.push(item)); 87 | expect(result.length).equal(3); 88 | }); 89 | it("Set",async () => { 90 | const result = []; 91 | await assentials.forEach(new Set([1,2,3]),item => result.push(item)); 92 | expect(result.length).equal(3); 93 | }); 94 | it("Map",async () => { 95 | const result = []; 96 | await assentials.forEach(new Map([[1,1],[2,2],[3,3]]),item => result.push(item)); 97 | expect(result.length).equal(3); 98 | }) 99 | it("generator", async () => { 100 | const result = []; 101 | await assentials.forEach((function *() { for(const item of [1,2,3]) yield item;})(),item => result.push(item)); 102 | expect(result.length).equal(3); 103 | }); 104 | it("async generator", async () => { 105 | const result = []; 106 | await assentials.forEach((async function *() { for(const item of [1,2,3]) yield item;})(),item => result.push(item)); 107 | expect(result.length).equal(3); 108 | }); 109 | it("document tree", async () => { 110 | const result = []; 111 | await assentials.forEach({name:"joe",address:{city:"Seattle",zipcode:{base:"98101"}},age:27},item => result.push(item)); 112 | expect(result.length).equal(4); 113 | }); 114 | it("document tree nodes", async () => { 115 | const result = []; 116 | await assentials.forEach({name:"joe",address:{city:"Seattle",zipcode:{base:"98101"}},age:27},item => result.push(item),true); 117 | expect(result.length).equal(6); 118 | //console.log(result); 119 | }) 120 | }); 121 | 122 | describe("map",function() { 123 | it("array",async () => { 124 | const result = await assentials.map([1,2,3],item => item); 125 | expect(result.length).equal(3); 126 | }); 127 | it("Set",async () => { 128 | const result = await assentials.map(new Set([1,2,3]),item => item); 129 | expect(result.size).equal(3); 130 | }); 131 | it("Map",async () => { 132 | const result = await assentials.map(new Map([[1,1],[2,2],[3,3]]),item => item); 133 | expect(result.size).equal(3); 134 | }) 135 | it("generator", async () => { 136 | const result = await assentials.map((function *() { for(const item of [1,2,3]) yield item;})(),item => item); 137 | let i = 0; 138 | for(const item of result) i++; 139 | expect(i).equal(3); 140 | }); 141 | it("async generator", async () => { 142 | const result = await assentials.map((async function *() { for(const item of [1,2,3]) yield item;})(),item => item); 143 | let i = 0; 144 | for await(const item of result) i++; 145 | expect(i).equal(3); 146 | }); 147 | it("document tree", async () => { 148 | const object = {name:"joe",address:{city:"Seattle",zipcode:{base:"98101"}}}, 149 | result = await assentials.map(object,item => item); 150 | expect(JSON.stringify(result)).equal(JSON.stringify(object)); 151 | }) 152 | }); 153 | 154 | describe("reduce",function() { 155 | it("array",async () => { 156 | const result = await assentials.reduce([1,2,3],(accum,item) => accum += item); 157 | expect(result).equal(6); 158 | }); 159 | it("Set",async () => { 160 | const result = await assentials.reduce(new Set([1,2,3]),(accum,item) => accum += item); 161 | expect(result).equal(6); 162 | }); 163 | it("Map",async () => { 164 | const result = await assentials.reduce(new Map([[1,1],[2,2],[3,3]]),(accum,item) => accum += item); 165 | expect(result).equal(6); 166 | }) 167 | it("generator", async () => { 168 | const result = await assentials.reduce((function *() { for(const item of [1,2,3]) yield item;})(),(accum,item) => accum += item); 169 | expect(result).equal(6); 170 | }); 171 | it("async generator", async () => { 172 | const result = await assentials.reduce((async function *() { for(const item of [1,2,3]) yield item;})(),(accum,item) => accum += item); 173 | expect(result).equal(6); 174 | }); 175 | it("document tree", async () => { 176 | const result = await assentials.reduce({1:1,2:{2:2},3:{3:{3:3}}},(accum,item) => accum += item); 177 | expect(result).equal(6); 178 | }) 179 | }); 180 | 181 | describe("pipe",function() { 182 | it("sum",async () => { 183 | const result = await assentials.pipe(n => n+1,n => n+2,n => n+3)(0); 184 | expect(result).equal(6); 185 | }); 186 | it("undefined",async () => { 187 | const result = await assentials.pipe(n => n+1,n => n+2,n => undefined,n => n+3)(0); 188 | expect(isNaN(result)).equal(true); 189 | }); 190 | it("override",async () => { 191 | const result = await assentials.pipe(n => n+1,2,n => n+3)(0); 192 | expect(result).equal(5); 193 | }); 194 | }) 195 | 196 | describe("flow",function() { 197 | it("sum",async () => { 198 | const result = await assentials.flow(n => n+1,n => n+2,n => n+3)(0); 199 | expect(result).equal(6); 200 | }); 201 | it("undefined",async () => { 202 | const result = await assentials.flow(n => n+1,n => n+2,n => undefined, n => n+3)(0); 203 | expect(result).equal(undefined); 204 | }); 205 | it("override",async () => { 206 | const result = await assentials.flow(n => n+1,2,n => n+3)(0); 207 | expect(result).equal(5); 208 | }); 209 | }) 210 | 211 | describe("when",function() { 212 | it("literal",async () => { 213 | const result = await assentials.when(0,assentials.pipe(n => n+1,n => n+2,n => n+3))(0); 214 | expect(result).equal(6); 215 | }); 216 | it("literal fail",async () => { 217 | const result = await assentials.when(1,assentials.pipe(n => n+1,n => n+2,n => n+3))(0); 218 | expect(result).equal(0); 219 | }); 220 | it("function",async () => { 221 | const result = await assentials.when(value => value===0,assentials.pipe(n => n+1,n => n+2,n => n+3))(0); 222 | expect(result).equal(6); 223 | }); 224 | it("function fail",async () => { 225 | const result = await assentials.when(value => value===1,assentials.pipe(n => n+1,n => n+2,n => n+3))(0); 226 | expect(result).equal(0); 227 | }); 228 | it("RegExp",async () => { 229 | const result = await assentials.when(/0/,assentials.pipe(n => n+1,n => n+2,n => n+3))("0"); 230 | expect(result).equal("0123"); 231 | }); 232 | it("RegExp fail",async () => { 233 | const result = await assentials.when(/1/,assentials.pipe(n => n+1,n => n+2,n => n+3))("0"); 234 | expect(result).equal("0"); 235 | }); 236 | }) 237 | 238 | describe("trigger",function() { 239 | it("true",async () => { 240 | let resolver = false; 241 | const promise = new Promise((resolve) => resolver = resolve); 242 | const result = await assentials.trigger(async (arg)=>arg,(arg) => resolver(triggered=arg))(true); 243 | expect(result).equal(true); 244 | await promise; 245 | expect(triggered).equal(true); 246 | }); 247 | it("false",async () => { 248 | let triggered = false; 249 | const promise = new Promise((resolve) => resolver = resolve); 250 | const result = await assentials.trigger(async (arg)=>arg,(arg) => resolver(triggered=arg))(false); 251 | expect(result).equal(false); 252 | setTimeout(() => resolver(result)); 253 | await promise; 254 | expect(triggered).equal(false); 255 | }); 256 | }) 257 | 258 | describe("route",function() { 259 | it("all succeed",async () => { 260 | const result = await assentials.route(({sum}) => typeof(sum)==="number",o => o.sum+=1,o => o.sum+=2,o => o.sum+=3,o => ({value:o,done:true}))({sum:0}); 261 | expect(result.sum).equal(6); 262 | }); 263 | describe("router",function() { 264 | let num, object, map, set; 265 | const router = assentials.router( 266 | assentials.route(({id})=>id===1,(item) => item.done=true), 267 | assentials.route(/aPath/,(item) => { 268 | return {value:true,done:true}; 269 | }), 270 | assentials.route(1,(item) => { 271 | return {done:true,value:item}; 272 | }), 273 | assentials.route({name:"joe",age:27}, 274 | (item) => { 275 | return object = true; 276 | }), 277 | assentials.route(new Map([[1,1],[2,2]]),(item) => map = true), 278 | assentials.route(new Set([1,2]),(item) => set = true), 279 | //assentials.route(1,() => { return {done:true}; }), 280 | //assentials.route(1,() => num = undefined), 281 | assentials.route( 282 | { 283 | [/name/]:"mary" 284 | }, 285 | (item) => object = true 286 | ), 287 | assentials.route( 288 | { 289 | [(key) => /name/.test(key)]:"bill" 290 | }, 291 | (item) => object = true 292 | ), 293 | assentials.route( 294 | { 295 | [function (key) { 296 | /name/.test(key) 297 | }]:"john" 298 | }, 299 | (item) => object = true 300 | ) 301 | ); 302 | it("object", async () => { 303 | const result = await router({id:1}); 304 | expect(result.done).equal(true); 305 | }); 306 | it("object fail", async () => { 307 | const result = await router({id:2}); 308 | expect(result.done).equal(undefined); 309 | }); 310 | it("regexp", async () => { 311 | const result = await router("aPath"); 312 | expect(result).equal(true); 313 | }); 314 | it("regexp fail", async () => { 315 | regexp = undefined; 316 | const result = await router("anotherPath"); 317 | expect(regexp).equal(undefined); 318 | }); 319 | it("literal with done", async () => { 320 | const result = await router(1); 321 | expect(result).equal(1); 322 | }); 323 | it("literal fail", async () => { 324 | num = undefined; 325 | const result = await router(2); 326 | expect(num).equal(undefined); 327 | }); 328 | it("object", async () => { 329 | const result = await router({name:"joe",age:27}); 330 | expect(object).equal(true); 331 | }); 332 | it("object fail", async () => { 333 | object = undefined; 334 | const result = await router({name:"joe",age:26}); 335 | expect(object).equal(undefined); 336 | }); 337 | it("Map", async () => { 338 | const result = await router(new Map([[1,1],[2,2]])); 339 | expect(map).equal(true); 340 | }); 341 | it("Map fail", async () => { 342 | map = undefined; 343 | const result = await router(new Map([[1,1],[2,1]])); 344 | expect(map).equal(undefined); 345 | }); 346 | it("Set", async () => { 347 | const result = await router(new Set([1,2])); 348 | expect(set).equal(true); 349 | }); 350 | it("Set fail", async () => { 351 | set = undefined; 352 | const result = await router(new Set([1,3])); 353 | expect(set).equal(undefined); 354 | }); 355 | it("object regexp", async () => { 356 | const result = await router({age:27,name:"mary"}); 357 | expect(object).equal(true); 358 | }); 359 | it("object arrow", async () => { 360 | const result = await router({age:27,name:"bill"}); 361 | expect(object).equal(true); 362 | }); 363 | it("object function", async () => { 364 | const result = await router({age:27,name:"john"}); 365 | expect(object).equal(true); 366 | }); 367 | }); 368 | }); 369 | 370 | describe("parallel",function() { 371 | it("ordered",async () => { 372 | const r1 = () => new Promise(resolve => setTimeout(() => resolve(2),500)), 373 | r2 = () => new Promise(resolve => resolve(0)), 374 | r3 = () => new Promise(resolve => setTimeout(() => resolve(1))), 375 | r4 = () => new Promise(resolve => setTimeout(() => resolve(3),1000)); 376 | const results = await assentials.parallel(r1,r2,r3,r4)(); 377 | expect(results.every((item,index) => item===index)).equal(true); 378 | }) 379 | }) 380 | 381 | 382 | 383 | 384 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = { 4 | optimization: { 5 | minimize: true 6 | } 7 | } --------------------------------------------------------------------------------