index.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. 'use strict';
  2. var isObject = require('isobject');
  3. var Emitter = require('component-emitter');
  4. var visit = require('collection-visit');
  5. var toPath = require('to-object-path');
  6. var union = require('union-value');
  7. var del = require('unset-value');
  8. var get = require('get-value');
  9. var has = require('has-value');
  10. var set = require('set-value');
  11. /**
  12. * Create a `Cache` constructor that when instantiated will
  13. * store values on the given `prop`.
  14. *
  15. * ```js
  16. * var Cache = require('cache-base').namespace('data');
  17. * var cache = new Cache();
  18. *
  19. * cache.set('foo', 'bar');
  20. * //=> {data: {foo: 'bar'}}
  21. * ```
  22. * @param {String} `prop` The property name to use for storing values.
  23. * @return {Function} Returns a custom `Cache` constructor
  24. * @api public
  25. */
  26. function namespace(prop) {
  27. /**
  28. * Create a new `Cache`. Internally the `Cache` constructor is created using
  29. * the `namespace` function, with `cache` defined as the storage object.
  30. *
  31. * ```js
  32. * var app = new Cache();
  33. * ```
  34. * @param {Object} `cache` Optionally pass an object to initialize with.
  35. * @constructor
  36. * @api public
  37. */
  38. function Cache(cache) {
  39. if (prop) {
  40. this[prop] = {};
  41. }
  42. if (cache) {
  43. this.set(cache);
  44. }
  45. }
  46. /**
  47. * Inherit Emitter
  48. */
  49. Emitter(Cache.prototype);
  50. /**
  51. * Assign `value` to `key`. Also emits `set` with
  52. * the key and value.
  53. *
  54. * ```js
  55. * app.on('set', function(key, val) {
  56. * // do something when `set` is emitted
  57. * });
  58. *
  59. * app.set(key, value);
  60. *
  61. * // also takes an object or array
  62. * app.set({name: 'Halle'});
  63. * app.set([{foo: 'bar'}, {baz: 'quux'}]);
  64. * console.log(app);
  65. * //=> {name: 'Halle', foo: 'bar', baz: 'quux'}
  66. * ```
  67. *
  68. * @name .set
  69. * @emits `set` with `key` and `value` as arguments.
  70. * @param {String} `key`
  71. * @param {any} `value`
  72. * @return {Object} Returns the instance for chaining.
  73. * @api public
  74. */
  75. Cache.prototype.set = function(key, val) {
  76. if (Array.isArray(key) && arguments.length === 2) {
  77. key = toPath(key);
  78. }
  79. if (isObject(key) || Array.isArray(key)) {
  80. this.visit('set', key);
  81. } else {
  82. set(prop ? this[prop] : this, key, val);
  83. this.emit('set', key, val);
  84. }
  85. return this;
  86. };
  87. /**
  88. * Union `array` to `key`. Also emits `set` with
  89. * the key and value.
  90. *
  91. * ```js
  92. * app.union('a.b', ['foo']);
  93. * app.union('a.b', ['bar']);
  94. * console.log(app.get('a'));
  95. * //=> {b: ['foo', 'bar']}
  96. * ```
  97. * @name .union
  98. * @param {String} `key`
  99. * @param {any} `value`
  100. * @return {Object} Returns the instance for chaining.
  101. * @api public
  102. */
  103. Cache.prototype.union = function(key, val) {
  104. if (Array.isArray(key) && arguments.length === 2) {
  105. key = toPath(key);
  106. }
  107. var ctx = prop ? this[prop] : this;
  108. union(ctx, key, arrayify(val));
  109. this.emit('union', val);
  110. return this;
  111. };
  112. /**
  113. * Return the value of `key`. Dot notation may be used
  114. * to get [nested property values][get-value].
  115. *
  116. * ```js
  117. * app.set('a.b.c', 'd');
  118. * app.get('a.b');
  119. * //=> {c: 'd'}
  120. *
  121. * app.get(['a', 'b']);
  122. * //=> {c: 'd'}
  123. * ```
  124. *
  125. * @name .get
  126. * @emits `get` with `key` and `value` as arguments.
  127. * @param {String} `key` The name of the property to get. Dot-notation may be used.
  128. * @return {any} Returns the value of `key`
  129. * @api public
  130. */
  131. Cache.prototype.get = function(key) {
  132. key = toPath(arguments);
  133. var ctx = prop ? this[prop] : this;
  134. var val = get(ctx, key);
  135. this.emit('get', key, val);
  136. return val;
  137. };
  138. /**
  139. * Return true if app has a stored value for `key`,
  140. * false only if value is `undefined`.
  141. *
  142. * ```js
  143. * app.set('foo', 'bar');
  144. * app.has('foo');
  145. * //=> true
  146. * ```
  147. *
  148. * @name .has
  149. * @emits `has` with `key` and true or false as arguments.
  150. * @param {String} `key`
  151. * @return {Boolean}
  152. * @api public
  153. */
  154. Cache.prototype.has = function(key) {
  155. key = toPath(arguments);
  156. var ctx = prop ? this[prop] : this;
  157. var val = get(ctx, key);
  158. var has = typeof val !== 'undefined';
  159. this.emit('has', key, has);
  160. return has;
  161. };
  162. /**
  163. * Delete one or more properties from the instance.
  164. *
  165. * ```js
  166. * app.del(); // delete all
  167. * // or
  168. * app.del('foo');
  169. * // or
  170. * app.del(['foo', 'bar']);
  171. * ```
  172. * @name .del
  173. * @emits `del` with the `key` as the only argument.
  174. * @param {String|Array} `key` Property name or array of property names.
  175. * @return {Object} Returns the instance for chaining.
  176. * @api public
  177. */
  178. Cache.prototype.del = function(key) {
  179. if (Array.isArray(key)) {
  180. this.visit('del', key);
  181. } else {
  182. del(prop ? this[prop] : this, key);
  183. this.emit('del', key);
  184. }
  185. return this;
  186. };
  187. /**
  188. * Reset the entire cache to an empty object.
  189. *
  190. * ```js
  191. * app.clear();
  192. * ```
  193. * @api public
  194. */
  195. Cache.prototype.clear = function() {
  196. if (prop) {
  197. this[prop] = {};
  198. }
  199. };
  200. /**
  201. * Visit `method` over the properties in the given object, or map
  202. * visit over the object-elements in an array.
  203. *
  204. * @name .visit
  205. * @param {String} `method` The name of the `base` method to call.
  206. * @param {Object|Array} `val` The object or array to iterate over.
  207. * @return {Object} Returns the instance for chaining.
  208. * @api public
  209. */
  210. Cache.prototype.visit = function(method, val) {
  211. visit(this, method, val);
  212. return this;
  213. };
  214. return Cache;
  215. }
  216. /**
  217. * Cast val to an array
  218. */
  219. function arrayify(val) {
  220. return val ? (Array.isArray(val) ? val : [val]) : [];
  221. }
  222. /**
  223. * Expose `Cache`
  224. */
  225. module.exports = namespace();
  226. /**
  227. * Expose `Cache.namespace`
  228. */
  229. module.exports.namespace = namespace;