UNPKG

obj-chain-core

Version:

fluent chaining for obj with dot-prop access

425 lines (362 loc) 11.8 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>index.js - Documentation</title> <script src="scripts/prettify/prettify.js"></script> <script src="scripts/prettify/lang-css.js"></script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc.css"> </head> <body> <input type="checkbox" id="nav-trigger" class="nav-trigger" /> <label for="nav-trigger" class="navicon-button x"> <div class="navicon"></div> </label> <label for="nav-trigger" class="overlay"></label> <nav> <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ObjChain.html">ObjChain</a><ul class='methods'><li data-type='method'><a href="ObjChain.html#.init">init</a></li><li data-type='method'><a href="ObjChain.html#escape">escape</a></li><li data-type='method'><a href="ObjChain.html#extend">extend</a></li><li data-type='method'><a href="ObjChain.html#has">has</a></li><li data-type='method'><a href="ObjChain.html#setIfNotEmpty">setIfNotEmpty</a></li><li data-type='method'><a href="ObjChain.html#toString">toString</a></li><li data-type='method'><a href="ObjChain.html#use">use</a></li><li data-type='method'><a href="ObjChain.html#val">val</a></li></ul></li></ul><h3>Global</h3><ul><li><a href="global.html"></a></li><li><a href="global.html#configPlugin">configPlugin</a></li><li><a href="global.html#flow">flow</a></li><li><a href="global.html#remove">remove</a></li><li><a href="global.html#set">set</a></li><li><a href="global.html#write">write</a></li></ul> </nav> <div id="main"> <h1 class="page-title">index.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>const log = require('fliplog') const Boss = require('likeaboss') const ChainedMap = require('flipchain/ChainedMapExtendable') const pkg = require('../package.json') // @TODO: // add `read-pkg-up` compatible with monorepo symlinks, // because cannot store configstore values the same for every repo globally // https://www.youtube.com/watch?v=SwSle66O5sU const OFF = `${~315 >>> 3}@@` let dynamics = {} /** * @param {Function[]} funcs functions to flow left to right * @return {Function} passes args through the functions, bound to this */ function flow(...funcs) { const length = funcs ? funcs.length : 0 return function flowing(...args) { let index = 0 // log // .data({length, index, f: funcs[index], args, funcs}) // .blue('flow') // .echo() // eslint-disable-next-line let result = length ? funcs[index].apply(this, args) : args[0] while (++index &lt; length) { // eslint-disable-next-line result = funcs[index].call(this, result) } return result } } /** * @NOTE: only issue with this, is if the keys are the same... * @TODO: * - [ ] could auto define a `get` on every set, and a `set`... * - [ ] make a lightweight, and dynamic version - with plugins * * changed to obj chain because it doesn't need to be json * then we add middleware for observable, ~[immutable], json, file */ class ObjChain extends ChainedMap { /** * @param {string | Object} data json data * @param {Array&lt;string>} [plugins=[]] * @return {ObjChain} */ static init(data, plugins) { return new ObjChain(data, plugins) } /** * @param {string | Object} data * @param {Array&lt;string>} [plugins=[]] */ constructor(data = {}, plugins = []) { super() // single arg just plugins if (Array.isArray(data) === true) { if (data[0] &amp;&amp; data[0].includes('Plugin') === true) { plugins = data data = {} } } this.pkg = pkg this.data = data || {} this.current = null // @TODO: each of these, + pre &amp; post // @TODO: should use `sortByProp(['index'])` this.middleware = { setIfNotEmpty: [], set: [], get: [], has: [], del: [], // val: [], override: [], init: [], merge: [], save: [], } // const aliased = { // write: 'save', // } this.use = this.use.bind(this) this.extend = this.extend.bind(this) // plugins.push('MapPlugin') this.store.set('debug', false) plugins.forEach(plugin => { log.magenta('using plugin').data(plugin).echo(this.store.get('debug')) if (typeof plugin !== 'string') { log .magenta('using plugin - non-string') .data(plugin) .echo(this.store.get('debug')) this.use(plugin) } else if (dynamics.exports[plugin]) { log .magenta('using plugin - dynamic') .data(dynamics.exports[plugin]) .echo(this.store.get('debug')) this.use(dynamics.exports[plugin]) } else { // log.quick({plugin, dynamics}) } }) this.update = this.update.bind(this) this.setIfNotEmpty = this.setIfNotEmpty.bind(this) this.has = this.has.bind(this) this.write = this.save.bind(this) this.set = this.update.bind(this) this.get = this.val.bind(this) this.delete = this.del.bind(this) this.remove = this.del.bind(this) } /** * @alias set * @param {string | any} key * @param {Serializable | any} val * @return {ObjChain} @chainable */ update(key, val) { this.middleware.set.forEach(fn => fn(key, val)) return this } /** * @param {string} key key with `.` * @return {string} string with escaped `\\.` */ escape(key) { return (key = key.replace('.', '\\.')) } /** * @description sets !.has(key) * @see ObjChain.has * @param {string | any} key * @param {Serializable | any} val * @return {ObjChain} @chainable */ setIfNotEmpty(key, val) { if (this.has(key)) return this this.set(key, val) return this } /** * @param {string | any} key * @return {Boolean} */ has(key) { return this.middleware.has.map(fn => fn(key)).includes(true) } /** * @alias delete * @alias remove * @description delete. remove * @param {string | any} key * @return {ObjChain} */ del(key) { this.middleware.del.forEach(fn => fn(key)) return this } /** * @description get a value * @param {string | any | null} [key=null] * @return {any} current key or named if there is key param */ val(key = null) { // log.quick(this.middleware.val) // .bind(this) // return flow.apply(this, this.middleware.val)(key) // return flow.apply(this, this.middleware.val)(key) let val = key this.middleware.get.forEach(fn => { val = fn(key, val) }) // log.quick(val, key) return val // const args = [key] // const funcs = this.middleware.val // const length = funcs ? funcs.length : 0 // // let index = 0 // let result = length ? funcs[index].apply(this, args) : args[0] // while (++index &lt; length) { // result = funcs[index].call(this, result) // } // log.quick(this) } /** * @alias write * @description save/write data * @return {ObjChain} */ save() { this.middleware.save.forEach(fn => fn(this)) return this } // --- plugins / middleware --- /** * @description use middleware * @param {Object} obj * @return {ObjChain} */ use(obj) { if (typeof obj === 'function' &amp;&amp; Object.keys(obj).length === 0) { log.blue('use.fn').echo(this.store.get('debug')) obj(this) // obj = return this } if (obj.init) { obj.init(this) // delete obj.init } const keys = Object.keys(obj) log.red('use.keys').data({keys}).echo(this.store.get('debug')) for (let k = 0; k &lt; keys.length; k++) { const key = keys[k] if (key === 'middleware') { log.red('key is middlware').echo(this.store.get('debug')) Object.keys(obj[key]).forEach(method => { let fn = obj[key][method] log .data({method, key, k, fn, obj}) .green('using middleware') .echo(this.store.get('debug')) if (fn &amp;&amp; fn.bind !== undefined) fn = fn.bind(this) if (this.middleware[method] !== undefined) { this.middleware[method].push(fn) } else { log.data({method}).red('middleware for method not found 0.0') } }) // continue } else if (!obj[key] || obj[key].bind === undefined) { log.yellow('use.else no bind').data({key}).echo(this.store.get('debug')) this[key] = obj[key] } else { log.yellow('use.else').data({key}).echo(this.store.get('debug')) this[key] = obj[key].bind(this) } } // log.quick(this.middleware) return this } /** * @TODO: * - [ ] should validate here * - [ ] .files('array') * - [ ] allow nesting * - [ ] (scripts().eh()) * * * @description take strings, make them methods to .set on * @param {Array&lt;string>} methods * @param {boolean} [nest=false] nest the .set * @return {ObjChain} */ extend(methods, nest = false) { if (nest === true) { methods.forEach(method => { this[method] = (keyPath, data) => { this.set(method + '.' + keyPath, data) return this } }) return this } methods.forEach(method => { const cb = data => { this.set(method, data) return this } // @TODO: should make each part a function instead of an obj... if (method.includes('.') === true) this.set(method, cb) else this[method] = cb }) return this } /** * @return {string} */ toString() { return this.middleware.toString.forEach(fn => fn(this)).join('') } } /** * @param {string | Object} data json data * @param {Array&lt;string>} [plugins=[]] * @return {ObjChain} */ // function ObjChainable(data, plugins = []) { // // console.log({data}, Array.isArray(data), data[0]) // if (Array.isArray(data) === true) { // if (data[0] &amp;&amp; data[0].includes('Plugin') === true) { // return new ObjChain({}, plugins) // } // } // return new ObjChain(data, plugins) // } exports = module.exports = Boss.module(dynamics) .dir(__dirname) .main(ObjChain) .props({pkg}) .dynamics([ {name: 'ConfigPlugin', path: './plugins/ConfigPlugin'}, {name: 'FilePlugin', path: './plugins/FilePlugin'}, {name: 'KebabPlugin', path: './plugins/KebabPlugin'}, {name: 'JSONPlugin', path: './plugins/JSONPlugin'}, {name: 'DotPropPlugin', path: './plugins/DotPropPlugin'}, {name: 'MapPlugin', path: './plugins/MapPlugin'}, {name: 'SnapshotPlugin', path: './plugins/SnapshotPlugin'}, {name: 'DiffPlugin', path: './plugins/DiffPlugin'}, // {name: 'FlowPlugin', path: './plugins/FlowPlugin'}, // {name: 'ObservablePlugin', path: './plugins/ObservablePlugin'}, // {name: 'DebugPlugin', path: './plugins/DebugPlugin'}, // {name: 'GetSetPlugin', path: './plugins/GetSetPlugin'}, // {name: 'ProxyPlugin', path: './plugins/ProxyPlugin'}, // {name: 'ZipPlugin', path: './plugins/ZipPlugin'}, ]) .end() </code></pre> </article> </section> </div> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.3</a> on Fri Apr 28 2017 01:03:22 GMT-0700 (PDT) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme. </footer> <script>prettyPrint();</script> <script src="scripts/linenumber.js"></script> </body> </html>