├── .editorconfig ├── .eslintrc.json ├── .gitattributes ├── .gitignore ├── .npmrc ├── .travis.yml ├── .verb.md ├── CHANGELOG.md ├── LICENSE ├── README.md ├── examples ├── clear.js ├── custom-prop.js ├── defaults.js ├── del.js ├── merge.js └── set.js ├── index.js ├── package.json └── test ├── custom-property.js ├── events.js ├── fixtures ├── a.yml ├── data │ ├── alert.json │ ├── data.json │ └── test.json └── namespace │ ├── a.yml │ ├── b.yml │ └── c.json └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org/ 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [{**/{actual,fixtures,expected,templates}/**,*.md}] 13 | trim_trailing_whitespace = false 14 | insert_final_newline = false 15 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended" 4 | ], 5 | 6 | "env": { 7 | "browser": false, 8 | "es6": true, 9 | "node": true, 10 | "mocha": true 11 | }, 12 | 13 | "parserOptions":{ 14 | "ecmaVersion": 9, 15 | "sourceType": "module", 16 | "ecmaFeatures": { 17 | "modules": true, 18 | "experimentalObjectRestSpread": true 19 | } 20 | }, 21 | 22 | "globals": { 23 | "document": false, 24 | "navigator": false, 25 | "window": false 26 | }, 27 | 28 | "rules": { 29 | "accessor-pairs": 2, 30 | "arrow-spacing": [2, { "before": true, "after": true }], 31 | "block-spacing": [2, "always"], 32 | "brace-style": [2, "1tbs", { "allowSingleLine": true }], 33 | "comma-dangle": [2, "never"], 34 | "comma-spacing": [2, { "before": false, "after": true }], 35 | "comma-style": [2, "last"], 36 | "constructor-super": 2, 37 | "curly": [2, "multi-line"], 38 | "dot-location": [2, "property"], 39 | "eol-last": 2, 40 | "eqeqeq": [2, "allow-null"], 41 | "generator-star-spacing": [2, { "before": true, "after": true }], 42 | "handle-callback-err": [2, "^(err|error)$" ], 43 | "indent": [2, 2, { "SwitchCase": 1 }], 44 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }], 45 | "keyword-spacing": [2, { "before": true, "after": true }], 46 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }], 47 | "new-parens": 2, 48 | "no-array-constructor": 2, 49 | "no-caller": 2, 50 | "no-class-assign": 2, 51 | "no-cond-assign": 2, 52 | "no-const-assign": 2, 53 | "no-control-regex": 2, 54 | "no-debugger": 2, 55 | "no-delete-var": 2, 56 | "no-dupe-args": 2, 57 | "no-dupe-class-members": 2, 58 | "no-dupe-keys": 2, 59 | "no-duplicate-case": 2, 60 | "no-empty-character-class": 2, 61 | "no-eval": 2, 62 | "no-ex-assign": 2, 63 | "no-extend-native": 2, 64 | "no-extra-bind": 2, 65 | "no-extra-boolean-cast": 2, 66 | "no-extra-parens": [2, "functions"], 67 | "no-fallthrough": 2, 68 | "no-floating-decimal": 2, 69 | "no-func-assign": 2, 70 | "no-implied-eval": 2, 71 | "no-inner-declarations": [2, "functions"], 72 | "no-invalid-regexp": 2, 73 | "no-irregular-whitespace": 2, 74 | "no-iterator": 2, 75 | "no-label-var": 2, 76 | "no-labels": 2, 77 | "no-lone-blocks": 2, 78 | "no-mixed-spaces-and-tabs": 2, 79 | "no-multi-spaces": 2, 80 | "no-multi-str": 2, 81 | "no-multiple-empty-lines": [2, { "max": 1 }], 82 | "no-native-reassign": 0, 83 | "no-negated-in-lhs": 2, 84 | "no-new": 2, 85 | "no-new-func": 2, 86 | "no-new-object": 2, 87 | "no-new-require": 2, 88 | "no-new-wrappers": 2, 89 | "no-obj-calls": 2, 90 | "no-octal": 2, 91 | "no-octal-escape": 2, 92 | "no-proto": 0, 93 | "no-redeclare": 2, 94 | "no-regex-spaces": 2, 95 | "no-return-assign": 2, 96 | "no-self-compare": 2, 97 | "no-sequences": 2, 98 | "no-shadow-restricted-names": 2, 99 | "no-spaced-func": 2, 100 | "no-sparse-arrays": 2, 101 | "no-this-before-super": 2, 102 | "no-throw-literal": 2, 103 | "no-trailing-spaces": 0, 104 | "no-undef": 2, 105 | "no-undef-init": 2, 106 | "no-unexpected-multiline": 2, 107 | "no-unneeded-ternary": [2, { "defaultAssignment": false }], 108 | "no-unreachable": 2, 109 | "no-unused-vars": [2, { "vars": "all", "args": "none" }], 110 | "no-useless-call": 0, 111 | "no-with": 2, 112 | "one-var": [0, { "initialized": "never" }], 113 | "operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }], 114 | "padded-blocks": [0, "never"], 115 | "quotes": [2, "single", "avoid-escape"], 116 | "radix": 2, 117 | "semi": [2, "always"], 118 | "semi-spacing": [2, { "before": false, "after": true }], 119 | "space-before-blocks": [2, "always"], 120 | "space-before-function-paren": [2, "never"], 121 | "space-in-parens": [2, "never"], 122 | "space-infix-ops": 2, 123 | "space-unary-ops": [2, { "words": true, "nonwords": false }], 124 | "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }], 125 | "use-isnan": 2, 126 | "valid-typeof": 2, 127 | "wrap-iife": [2, "any"], 128 | "yoda": [2, "never"] 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Enforce Unix newlines 2 | * text eol=lf 3 | 4 | # binaries 5 | *.ai binary 6 | *.psd binary 7 | *.jpg binary 8 | *.gif binary 9 | *.png binary 10 | *.jpeg binary -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # always ignore files 2 | *.DS_Store 3 | .idea 4 | .vscode 5 | *.sublime-* 6 | 7 | # test related, or directories generated by tests 8 | test/actual 9 | actual 10 | coverage 11 | .nyc* 12 | 13 | # npm 14 | node_modules 15 | npm-debug.log 16 | 17 | # yarn 18 | yarn.lock 19 | yarn-error.log 20 | 21 | # misc 22 | _gh_pages 23 | _draft 24 | _drafts 25 | bower_components 26 | vendor 27 | temp 28 | tmp 29 | TODO.md 30 | package-lock.json -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | os: 3 | - linux 4 | - osx 5 | language: node_js 6 | node_js: 7 | - node 8 | - '9' 9 | - '8' 10 | - '7' 11 | - '6' 12 | -------------------------------------------------------------------------------- /.verb.md: -------------------------------------------------------------------------------- 1 | ## Quickstart 2 | 3 | ```js 4 | const CacheBase = require('cache-base'); 5 | const app = new CacheBase(); 6 | 7 | app.set('a.b', 'c'); 8 | 9 | console.log(app.cache.a); //=> { b: 'c' } 10 | console.log(app.cache.a.b); //=> 'c' 11 | 12 | console.log(app.get('a')); //=> { b: 'c' } 13 | console.log(app.get('a.b')); //=> 'c' 14 | ``` 15 | 16 | More [usage examples](#usage-examples) below. 17 | 18 | 19 | ## API 20 | 21 | {%= apidocs("index.js") %} 22 | 23 | 24 | ## Usage examples 25 | 26 | **Create an instance of cache-base** 27 | 28 | ```js 29 | const app = new CacheBase(); 30 | 31 | app.set('a', 'b'); 32 | app.set('c.d', 'e'); 33 | 34 | console.log(app.get('a')); 35 | //=> 'b' 36 | console.log(app.get('c')); 37 | //=> { d: 'e' } 38 | console.log(app); 39 | //=> CacheBase { a: 'b' } 40 | ``` 41 | 42 | **Initialize with an object** 43 | 44 | ```js 45 | const app = new CacheBase({ a: 'b', c: { d: 'e' } }); 46 | 47 | console.log(app.get('a')); 48 | //=> 'b' 49 | console.log(app.get('c')); 50 | //=> { d: 'e' } 51 | console.log(app.get('c.d')); 52 | //=> 'e' 53 | console.log(app); 54 | //=> CacheBase { cache: { a: 'b' } } 55 | ``` 56 | 57 | **Inherit** 58 | 59 | ```js 60 | class MyApp extends CacheBase {} 61 | 62 | const app = new MyApp(); 63 | app.set('a', 'b'); 64 | app.set('c', 'd'); 65 | 66 | console.log(app.get('a')); 67 | //=> 'b' 68 | 69 | console.log(app); 70 | //=> MyApp { cache: { a: 'b', c: 'd' } } 71 | ``` 72 | 73 | **Custom namespace** 74 | 75 | Pass a string as the first value to the contructor to define a custom property name to use for the cache. By default values are stored on the `cache` property. 76 | 77 | ```js 78 | const CacheBase = require('cache-base'); 79 | const app = new CacheBase('data', { a: 'b' }); 80 | app.set('c.d', 'e'); 81 | 82 | // get values 83 | console.log(app.get('a')); 84 | //=> 'b' 85 | console.log(app.get('c')); 86 | //=> { d: 'e' } 87 | console.log(app.data); 88 | //=> { a: 'b', c: { d: 'e' } } 89 | console.log(app); 90 | //=> CacheBase { data: { a: 'b', c: { d: 'e' } } } 91 | ``` 92 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Release history 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | This changelog's format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 6 | and versioning in this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 7 | 8 |
9 | Guiding Principles 10 | 11 | - Changelogs are for humans, not machines. 12 | - There should be an entry for every single version. 13 | - The same types of changes should be grouped. 14 | - Versions and sections should be linkable. 15 | - The latest version comes first. 16 | - The release date of each versions is displayed. 17 | - Mention whether you follow Semantic Versioning. 18 | 19 |
20 | 21 |
22 | Types of changes 23 | 24 | Changelog entries are classified using the following labels _(from [keep-a-changelog](http://keepachangelog.com/)_): 25 | 26 | - `Added` for new features. 27 | - `Changed` for changes in existing functionality. 28 | - `Deprecated` for soon-to-be removed features. 29 | - `Removed` for now removed features. 30 | - `Fixed` for any bug fixes. 31 | - `Security` in case of vulnerabilities. 32 | 33 |
34 | 35 | 36 | ## [3.0.0] - 2018-01-27 37 | 38 | **Changed** 39 | 40 | - adds `.prime()` and `.default()` methods 41 | 42 | 43 | ## [2.0.0] - 2017-12-17 44 | 45 | **Changed** 46 | 47 | - convert to class 48 | - refactor to allow namespace to be set on constructor, thus `.namespace` was removed from the main export. Please see the readme for details. 49 | 50 | 51 | ## [1.0.1] - 2017-07-22 52 | 53 | - run update, lint, update deps 54 | 55 | 56 | ## [0.8.5] - 2017-02-25 57 | 58 | - Bump `isobject`. 59 | - Bump `set-value`. 60 | - Merge pull request #7 from wtgtybhertgeghgtwtg/bump-dependencies 61 | - run udpate 62 | 63 | ## [0.8.4] - 2016-05-30 64 | 65 | - run update 66 | - adds `.union` method. resolves https://github.com/jonschlinkert/cache-base/issues/3 67 | - generate docs 68 | - run update, update deps 69 | - make `.union` key behavior consistent with other methods 70 | - generate docs 71 | 72 | ## [0.8.2] - 2016-03-02 73 | 74 | - handle single arg key as an array 75 | - generate docs 76 | 77 | ## [0.8.1] - 2016-02-29 78 | 79 | - ensure value is a non-array object, only clear if `prop` is defined 80 | 81 | ## [0.8.0] - 2016-02-09 82 | 83 | - run update 84 | - run update, lint 85 | - minor refactor 86 | - generate docs with verb 87 | 88 | ## [0.7.1] - 2015-11-23 89 | 90 | - update deps 91 | - lint 92 | - adds lazy-cache, event emitting 93 | - events tests 94 | 95 | ## [0.7.0] - 2015-11-23 96 | 97 | - use eslint, lint 98 | - refactor, simplify 99 | 100 | ## [0.6.0] - 2015-03-11 101 | 102 | - fix pick docs 103 | - lint 104 | - get rid of deps 105 | 106 | ## [0.4.0] - 2015-02-14 107 | 108 | - adds `.pick()` and `.omit()` methods 109 | - adds tests 110 | - build docs/readme 111 | 112 | ## [0.3.0] - 2015-02-13 113 | 114 | - adds npmignore 115 | - adds travis 116 | - rename 117 | - copyright year, lint 118 | - update deps 119 | - build readme 120 | 121 | ## [0.2.0] - 2014-11-15 122 | 123 | - remove namespace stuff 124 | - update fixtures 125 | - update verbfile 126 | - clean up, refactor a number of methods: 127 | - update docs, run verb 128 | 129 | ## 0.1.0 130 | 131 | - first commit 132 | 133 | [2.0.0]: https://github.com/jonschlinkert/cache-base/compare/1.0.1...2.0.0 134 | [1.0.1]: https://github.com/jonschlinkert/cache-base/compare/1.0.0...1.0.1 135 | [1.0.0]: https://github.com/jonschlinkert/cache-base/compare/0.8.5...1.0.0 136 | [0.8.5]: https://github.com/jonschlinkert/cache-base/compare/0.8.4...0.8.5 137 | [0.8.4]: https://github.com/jonschlinkert/cache-base/compare/0.8.2...0.8.4 138 | [0.8.2]: https://github.com/jonschlinkert/cache-base/compare/0.8.1...0.8.2 139 | [0.8.1]: https://github.com/jonschlinkert/cache-base/compare/0.8.0...0.8.1 140 | [0.8.0]: https://github.com/jonschlinkert/cache-base/compare/0.7.1...0.8.0 141 | [0.7.1]: https://github.com/jonschlinkert/cache-base/compare/0.7.0...0.7.1 142 | [0.7.0]: https://github.com/jonschlinkert/cache-base/compare/0.6.0...0.7.0 143 | [0.6.0]: https://github.com/jonschlinkert/cache-base/compare/0.4.0...0.6.0 144 | [0.4.0]: https://github.com/jonschlinkert/cache-base/compare/0.3.0...0.4.0 145 | [0.3.0]: https://github.com/jonschlinkert/cache-base/compare/0.2.0...0.3.0 146 | 147 | [keep-a-changelog]: https://github.com/olivierlacan/keep-a-changelog 148 | 149 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2018, Jon Schlinkert. 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cache-base [![NPM version](https://img.shields.io/npm/v/cache-base.svg?style=flat)](https://www.npmjs.com/package/cache-base) [![NPM monthly downloads](https://img.shields.io/npm/dm/cache-base.svg?style=flat)](https://npmjs.org/package/cache-base) [![NPM total downloads](https://img.shields.io/npm/dt/cache-base.svg?style=flat)](https://npmjs.org/package/cache-base) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/cache-base.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/cache-base) 2 | 3 | > Basic object cache with `get`, `set`, `del`, and `has` methods for node.js/javascript projects. 4 | 5 | Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support. 6 | 7 | - [Install](#install) 8 | - [Quickstart](#quickstart) 9 | - [API](#api) 10 | - [Usage examples](#usage-examples) 11 | - [About](#about) 12 | 13 | _(TOC generated by [verb](https://github.com/verbose/verb) using [markdown-toc](https://github.com/jonschlinkert/markdown-toc))_ 14 | 15 | ## Install 16 | 17 | Install with [npm](https://www.npmjs.com/): 18 | 19 | ```sh 20 | $ npm install --save cache-base 21 | ``` 22 | 23 | ## Quickstart 24 | 25 | ```js 26 | const CacheBase = require('cache-base'); 27 | const app = new CacheBase(); 28 | 29 | app.set('a.b', 'c'); 30 | 31 | console.log(app.cache.a); //=> { b: 'c' } 32 | console.log(app.cache.a.b); //=> 'c' 33 | 34 | console.log(app.get('a')); //=> { b: 'c' } 35 | console.log(app.get('a.b')); //=> 'c' 36 | ``` 37 | 38 | More [usage examples](#usage-examples) below. 39 | 40 | ## API 41 | 42 | **Params** 43 | 44 | * `prop` **{String|Object}**: (optional) Property name to use for the cache, or the object to initialize with. 45 | * `cache` **{Object}**: (optional) An object to initialize with. 46 | 47 | **Example** 48 | 49 | ```js 50 | const app = new CacheBase(); 51 | ``` 52 | 53 | ### [.set](index.js#L65) 54 | 55 | Assign `value` to `key`. Also emits `set` with the key and value. 56 | 57 | **Params** 58 | 59 | * `key` **{String|Array}**: The name of the property to set. Dot-notation may be used to set nested properties. 60 | * `value` **{any}** 61 | * `returns` **{Object}**: Returns the instance for chaining. 62 | 63 | **Events** 64 | 65 | * `emits`: `set` with `key` and `value` as arguments. 66 | 67 | **Example** 68 | 69 | ```js 70 | app.on('set', function(key, val) { 71 | // do something when `set` is emitted 72 | }); 73 | 74 | app.set('admin', true); 75 | 76 | // also takes an object or an array of objects 77 | app.set({ name: 'Brian' }); 78 | app.set([{ foo: 'bar' }, { baz: 'quux' }]); 79 | console.log(app); 80 | //=> { name: 'Brian', foo: 'bar', baz: 'quux' } 81 | ``` 82 | 83 | ### [.get](index.js#L90) 84 | 85 | Return the value of `key`. 86 | 87 | **Params** 88 | 89 | * `key` **{String|Array}**: The name of the property to get. Dot-notation may be used to set nested properties. 90 | * `returns` **{any}**: Returns the value of `key` 91 | 92 | **Events** 93 | 94 | * `emits`: `get` with `key` and `value` as arguments. 95 | 96 | **Example** 97 | 98 | ```js 99 | app.set('a.b.c', 'd'); 100 | app.get('a.b'); 101 | //=> { c: 'd' } 102 | ``` 103 | 104 | ### [.prime](index.js#L120) 105 | 106 | Create a property on the cache with the given `value` only if it doesn't already exist. 107 | 108 | **Params** 109 | 110 | * `key` **{String}**: Property name or object path notation. 111 | * `val` **{any}** 112 | * `returns` **{Object}**: Returns the instance for chaining. 113 | 114 | **Example** 115 | 116 | ```js 117 | console.log(app.cache); //=> {} 118 | app.set('one', { foo: 'bar' }); 119 | app.prime('one', { a: 'b' }); 120 | app.prime('two', { c: 'd' }); 121 | console.log(app.cache.one); //=> { foo: 'bar' } 122 | console.log(app.cache.two); //=> { c: 'd' } 123 | ``` 124 | 125 | ### [.default](index.js#L162) 126 | 127 | Set a default value to be used when `.get()` is called and the value is not defined on the cache. Returns a value from the defaults when only a key is passed. 128 | 129 | **Params** 130 | 131 | * `key` **{String|Array}**: The name of the property to set. Dot-notation may be used to set nested properties. 132 | * `value` **{any}**: (optional) The value to set on the defaults object. 133 | * `returns` **{Object}**: Returns the instance for chaining. 134 | 135 | **Example** 136 | 137 | ```js 138 | app.set('foo', 'xxx'); 139 | app.default('foo', 'one'); 140 | app.default('bar', 'two'); 141 | app.default('baz', 'three'); 142 | app.set('baz', 'zzz'); 143 | 144 | console.log(app.get('foo')); 145 | //=> 'xxx' 146 | 147 | console.log(app.get('bar')); 148 | //=> 'two' 149 | 150 | console.log(app.get('baz')); 151 | //=> 'zzz' 152 | 153 | console.log(app); 154 | // CacheBase { 155 | // cache: { foo: 'xxx', bar: 'two', baz: 'zzz' }, 156 | // defaults: { foo: 'one', bar: 'two', baz: 'three' } } 157 | ``` 158 | 159 | ### [.union](index.js#L199) 160 | 161 | Set an array of unique values on cache `key`. 162 | 163 | **Params** 164 | 165 | * `key` **{String|Array}**: The name of the property to union. Dot-notation may be used to set nested properties. 166 | * `value` **{any}** 167 | * `returns` **{Object}**: Returns the instance for chaining. 168 | 169 | **Example** 170 | 171 | ```js 172 | app.union('a.b.c', 'foo'); 173 | app.union('a.b.c', 'bar'); 174 | app.union('a.b.c', ['bar', 'baz']); 175 | console.log(app.get('a')); 176 | //=> { b: { c: ['foo', 'bar', 'baz'] } } 177 | ``` 178 | 179 | ### [.has](index.js#L223) 180 | 181 | Return true if the value of property `key` is not `undefined`. 182 | 183 | **Params** 184 | 185 | * `key` **{String|Array}**: The name of the property to check. Dot-notation may be used to set nested properties. 186 | * `returns` **{Boolean}** 187 | 188 | **Example** 189 | 190 | ```js 191 | app.set('foo', true); 192 | app.set('baz', null); 193 | app.set('bar', undefined); 194 | 195 | app.has('foo'); //=> true 196 | app.has('bar'); //=> true 197 | app.has('baz'); //=> false 198 | ``` 199 | 200 | ### [.hasOwn](index.js#L253) 201 | 202 | Returns true if the specified property is an own (not inherited) property. Similar to [.has()](#has), but returns true if the key exists, even if the value is `undefined`. 203 | 204 | **Params** 205 | 206 | * `key` **{String}** 207 | * `returns` **{Boolean}**: Returns true if object `key` exists. Dot-notation may be used to set nested properties. 208 | 209 | **Example** 210 | 211 | ```js 212 | app.set('a.b.c', 'd'); 213 | app.set('x', false); 214 | app.set('y', null); 215 | app.set('z', undefined); 216 | 217 | app.hasOwn('a'); //=> true 218 | app.hasOwn('b'); //=> true 219 | app.hasOwn('c'); //=> true 220 | app.hasOwn('a.b.c'); //=> true 221 | app.hasOwn('x'); //=> true 222 | app.hasOwn('y'); //=> true 223 | app.hasOwn('z'); //=> true 224 | app.hasOwn('lslsls'); //=> false 225 | ``` 226 | 227 | ### [.del](index.js#L278) 228 | 229 | Delete one or more properties from the instance. 230 | 231 | **Params** 232 | 233 | * `key` **{String|Array}**: The name of the property to delete. Dot-notation may be used to set nested properties. 234 | * `returns` **{Object}**: Returns the instance for chaining. 235 | 236 | **Events** 237 | 238 | * `emits`: `del` with the `key` as the only argument. 239 | 240 | **Example** 241 | 242 | ```js 243 | // setup a listener to update a property with a default 244 | // value when it's deleted by the user 245 | app.on('del', key => app.set(key, app.default(key))); 246 | 247 | app.del(); // delete all properties on the cache 248 | // or 249 | app.del('foo'); 250 | // or an array of keys 251 | app.del(['foo', 'bar']); 252 | ``` 253 | 254 | ### [.clear](index.js#L301) 255 | 256 | Reset the entire cache to an empty object. Note that this does not also clear the `defaults` object, since you can manually do `cache.defaults = {}` if you want to reset that object as well. 257 | 258 | **Example** 259 | 260 | ```js 261 | // clear "defaults" whenever the cache is cleared 262 | app.on('clear', key => (app.defaults = {})); 263 | app.clear(); 264 | ``` 265 | 266 | ### [.visit](index.js#L318) 267 | 268 | Visit (or map visit) the specified method (`key`) over the properties in the 269 | given object or array. 270 | 271 | **Params** 272 | 273 | * `key` **{String|Array}**: The name of the method to visit. 274 | * `val` **{Object|Array}**: The object or array to iterate over. 275 | * `returns` **{Object}**: Returns the instance for chaining. 276 | 277 | ### [.keys](index.js#L338) 278 | 279 | Gets an array of names of all enumerable properties on the cache. 280 | 281 | **Example** 282 | 283 | ```js 284 | const app = new CacheBase(); 285 | app.set('user', true); 286 | app.set('admin', false); 287 | 288 | console.log(app.keys); 289 | //=> ['user', 'admin'] 290 | ``` 291 | 292 | ### [.size](index.js#L357) 293 | 294 | Gets the length of [keys](#keys). 295 | 296 | **Example** 297 | 298 | ```js 299 | const app = new CacheBase(); 300 | app.set('user', true); 301 | app.set('admin', false); 302 | 303 | console.log(app.size); 304 | //=> 2 305 | ``` 306 | 307 | ## Usage examples 308 | 309 | **Create an instance of cache-base** 310 | 311 | ```js 312 | const app = new CacheBase(); 313 | 314 | app.set('a', 'b'); 315 | app.set('c.d', 'e'); 316 | 317 | console.log(app.get('a')); 318 | //=> 'b' 319 | console.log(app.get('c')); 320 | //=> { d: 'e' } 321 | console.log(app); 322 | //=> CacheBase { a: 'b' } 323 | ``` 324 | 325 | **Initialize with an object** 326 | 327 | ```js 328 | const app = new CacheBase({ a: 'b', c: { d: 'e' } }); 329 | 330 | console.log(app.get('a')); 331 | //=> 'b' 332 | console.log(app.get('c')); 333 | //=> { d: 'e' } 334 | console.log(app.get('c.d')); 335 | //=> 'e' 336 | console.log(app); 337 | //=> CacheBase { cache: { a: 'b' } } 338 | ``` 339 | 340 | **Inherit** 341 | 342 | ```js 343 | class MyApp extends CacheBase {} 344 | 345 | const app = new MyApp(); 346 | app.set('a', 'b'); 347 | app.set('c', 'd'); 348 | 349 | console.log(app.get('a')); 350 | //=> 'b' 351 | 352 | console.log(app); 353 | //=> MyApp { cache: { a: 'b', c: 'd' } } 354 | ``` 355 | 356 | **Custom namespace** 357 | 358 | Pass a string as the first value to the contructor to define a custom property name to use for the cache. By default values are stored on the `cache` property. 359 | 360 | ```js 361 | const CacheBase = require('cache-base'); 362 | const app = new CacheBase('data', { a: 'b' }); 363 | app.set('c.d', 'e'); 364 | 365 | // get values 366 | console.log(app.get('a')); 367 | //=> 'b' 368 | console.log(app.get('c')); 369 | //=> { d: 'e' } 370 | console.log(app.data); 371 | //=> { a: 'b', c: { d: 'e' } } 372 | console.log(app); 373 | //=> CacheBase { data: { a: 'b', c: { d: 'e' } } } 374 | ``` 375 | 376 | ## About 377 | 378 |
379 | Contributing 380 | 381 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new). 382 | 383 |
384 | 385 |
386 | Running Tests 387 | 388 | Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command: 389 | 390 | ```sh 391 | $ npm install && npm test 392 | ``` 393 | 394 |
395 | 396 |
397 | Building docs 398 | 399 | _(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_ 400 | 401 | To generate the readme, run the following command: 402 | 403 | ```sh 404 | $ npm install -g verbose/verb#dev verb-generate-readme && verb 405 | ``` 406 | 407 |
408 | 409 | ### Related projects 410 | 411 | You might also be interested in these projects: 412 | 413 | * [base-methods](https://www.npmjs.com/package/base-methods): base-methods is the foundation for creating modular, unit testable and highly pluggable node.js applications, starting… [more](https://github.com/jonschlinkert/base-methods) | [homepage](https://github.com/jonschlinkert/base-methods "base-methods is the foundation for creating modular, unit testable and highly pluggable node.js applications, starting with a handful of common methods, like `set`, `get`, `del` and `use`.") 414 | * [get-value](https://www.npmjs.com/package/get-value): Use property paths like 'a.b.c' to get a nested value from an object. Even works… [more](https://github.com/jonschlinkert/get-value) | [homepage](https://github.com/jonschlinkert/get-value "Use property paths like 'a.b.c' to get a nested value from an object. Even works when keys have dots in them (no other dot-prop library can do this!).") 415 | * [has-value](https://www.npmjs.com/package/has-value): Returns true if a value exists, false if empty. Works with deeply nested values using… [more](https://github.com/jonschlinkert/has-value) | [homepage](https://github.com/jonschlinkert/has-value "Returns true if a value exists, false if empty. Works with deeply nested values using object paths.") 416 | * [option-cache](https://www.npmjs.com/package/option-cache): Simple API for managing options in JavaScript applications. | [homepage](https://github.com/jonschlinkert/option-cache "Simple API for managing options in JavaScript applications.") 417 | * [set-value](https://www.npmjs.com/package/set-value): Create nested values and any intermediaries using dot notation (`'a.b.c'`) paths. | [homepage](https://github.com/jonschlinkert/set-value "Create nested values and any intermediaries using dot notation (`'a.b.c'`) paths.") 418 | * [unset-value](https://www.npmjs.com/package/unset-value): Delete nested properties from an object using dot notation. | [homepage](https://github.com/jonschlinkert/unset-value "Delete nested properties from an object using dot notation.") 419 | 420 | ### Contributors 421 | 422 | | **Commits** | **Contributor** | 423 | | --- | --- | 424 | | 67 | [jonschlinkert](https://github.com/jonschlinkert) | 425 | | 2 | [wtgtybhertgeghgtwtg](https://github.com/wtgtybhertgeghgtwtg) | 426 | 427 | ### Author 428 | 429 | **Jon Schlinkert** 430 | 431 | * [LinkedIn Profile](https://linkedin.com/in/jonschlinkert) 432 | * [GitHub Profile](https://github.com/jonschlinkert) 433 | * [Twitter Profile](https://twitter.com/jonschlinkert) 434 | 435 | ### License 436 | 437 | Copyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert). 438 | Released under the [MIT License](LICENSE). 439 | 440 | *** 441 | 442 | _This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on March 23, 2018._ -------------------------------------------------------------------------------- /examples/clear.js: -------------------------------------------------------------------------------- 1 | const CacheBase = require('..'); 2 | const app = new CacheBase(); 3 | 4 | app.default('foo', 42); 5 | app.default('fez', 42); 6 | app.set('foo', 1); 7 | app.set('bar', 2); 8 | app.set('baz', 3); 9 | app.set('qux', 4); 10 | app.set('fez', 5); 11 | 12 | console.log(app.cache); 13 | console.log(app.defaults); 14 | console.log('---'); 15 | 16 | app.clear(); 17 | 18 | console.log(app.cache); 19 | console.log(app.defaults); 20 | console.log('---'); 21 | 22 | app.on('clear', key => (app.defaults = {})); 23 | app.clear(); 24 | 25 | console.log(app.cache); 26 | console.log(app.defaults); 27 | console.log('---'); 28 | -------------------------------------------------------------------------------- /examples/custom-prop.js: -------------------------------------------------------------------------------- 1 | const Cache = require('..'); 2 | const app = new Cache('data'); 3 | 4 | app.set('a', 'b'); 5 | app.set({ c: 'd' }); 6 | app.set('e.f', 'g') 7 | 8 | console.log(app.get('e.f')); 9 | //=> 'g' 10 | 11 | console.log(app.get()); 12 | //=> { a: 'b', c: 'd', e: { f: 'g' } } 13 | 14 | console.log(app.data); 15 | //=> { a: 'b', c: 'd', e: { f: 'g' } } 16 | 17 | console.log(app); 18 | //=> Cache { data: { a: 'b', c: 'd', e: { f: 'g' } } } 19 | -------------------------------------------------------------------------------- /examples/defaults.js: -------------------------------------------------------------------------------- 1 | const CacheBase = require('..'); 2 | const app = new CacheBase(); 3 | 4 | app.set('foo', 'xxx'); 5 | app.default('foo', 'one'); 6 | app.default('bar', 'two'); 7 | app.default('baz', 'three'); 8 | app.set('baz', 'zzz'); 9 | 10 | console.log(app.get('foo')); 11 | //=> 'xxx' 12 | 13 | console.log(app.get('bar')); 14 | //=> 'two' 15 | 16 | console.log(app.get('baz')); 17 | //=> 'zzz' 18 | 19 | console.log(app); 20 | // Cache { 21 | // cache: { foo: 'xxx', bar: 'two', baz: 'zzz' }, 22 | // defaults: { foo: 'one', bar: 'two', baz: 'three' } } 23 | -------------------------------------------------------------------------------- /examples/del.js: -------------------------------------------------------------------------------- 1 | const CacheBase = require('..'); 2 | const app = new CacheBase(); 3 | 4 | // app.on('del', key => app.set(key, app.default(key))); 5 | 6 | app.set('foo', 'xxx'); 7 | app.default('foo', 'one'); 8 | 9 | console.log(app.get('foo')); //=> 'xxx' 10 | console.log(app.cache.foo); //=> 'xxx' 11 | app.del('foo'); 12 | 13 | console.log(app.get('foo')); //=> 'xxx' 14 | console.log(app.cache.foo); //=> undefined 15 | -------------------------------------------------------------------------------- /examples/merge.js: -------------------------------------------------------------------------------- 1 | const CacheBase = require('..'); 2 | const app = new CacheBase(); 3 | 4 | app.set('foo', 'xxx'); 5 | app.default('foo', 'one'); 6 | app.default('bar', 'two'); 7 | app.default('baz', 'three'); 8 | app.default('qux', 'faz'); 9 | app.set('baz', 'zzz'); 10 | 11 | console.log(app.get('foo')); 12 | //=> 'xxx' 13 | 14 | console.log(app.get('bar')); 15 | //=> 'two' 16 | 17 | console.log(app.get('baz')); 18 | //=> 'zzz' 19 | 20 | console.log(app.merge()); 21 | //=> { foo: 'xxx', bar: 'two', baz: 'zzz', qux: 'faz' } 22 | 23 | console.log(app.merge({qux: 'aaa'})); 24 | //=> { foo: 'xxx', bar: 'two', baz: 'zzz', qux: 'aaa' } 25 | 26 | console.log(app); 27 | // Cache { 28 | // cache: { foo: 'xxx', bar: 'two', baz: 'zzz' }, 29 | // defaults: { foo: 'one', bar: 'two', baz: 'three' } } 30 | -------------------------------------------------------------------------------- /examples/set.js: -------------------------------------------------------------------------------- 1 | const Cache = require('..'); 2 | const app = new Cache(); 3 | 4 | app.set('a', 'b'); 5 | app.set({ c: 'd' }); 6 | app.set('e.f', 'g') 7 | 8 | console.log(app.get('e.f')); //=> 'g' 9 | console.log(app.get()); //=> { a: 'b', c: 'd', e: { f: 'g' } } 10 | console.log(app.data); //=> { a: 'b', c: 'd', e: { f: 'g' } } 11 | console.log(app); 12 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const typeOf = require('kind-of'); 4 | const Emitter = require('@sellside/emitter'); 5 | const visit = require('collection-visit'); 6 | const hasOwn = require('has-own-deep'); 7 | const union = require('union-value'); 8 | const del = require('unset-value'); 9 | const get = require('get-value'); 10 | const set = require('set-value'); 11 | 12 | /** 13 | * Create an instance of `CacheBase`. 14 | * 15 | * ```js 16 | * const app = new CacheBase(); 17 | * ``` 18 | * @param {String|Object} `prop` (optional) Property name to use for the cache, or the object to initialize with. 19 | * @param {Object} `cache` (optional) An object to initialize with. 20 | * @constructor 21 | * @api public 22 | */ 23 | 24 | class CacheBase extends Emitter { 25 | constructor(prop, cache) { 26 | super(); 27 | 28 | if (typeof prop !== 'string') { 29 | cache = prop || cache; 30 | prop = 'cache'; 31 | } 32 | 33 | Reflect.defineProperty(this, 'prop', { value: prop }); 34 | this[this.prop] = {}; 35 | 36 | if (cache) { 37 | this.set(cache); 38 | } 39 | } 40 | 41 | /** 42 | * Assign `value` to `key`. Also emits `set` with the key and value. 43 | * 44 | * ```js 45 | * app.on('set', function(key, val) { 46 | * // do something when `set` is emitted 47 | * }); 48 | * 49 | * app.set('admin', true); 50 | * 51 | * // also takes an object or an array of objects 52 | * app.set({ name: 'Brian' }); 53 | * app.set([{ foo: 'bar' }, { baz: 'quux' }]); 54 | * console.log(app); 55 | * //=> { name: 'Brian', foo: 'bar', baz: 'quux' } 56 | * ``` 57 | * @name .set 58 | * @emits `set` with `key` and `value` as arguments. 59 | * @param {String|Array} `key` The name of the property to set. Dot-notation may be used to set nested properties. 60 | * @param {any} `value` 61 | * @return {Object} Returns the instance for chaining. 62 | * @api public 63 | */ 64 | 65 | set(key, ...rest) { 66 | if (isObject(key) || (rest.length === 0 && Array.isArray(key))) { 67 | return this.visit('set', key, ...rest); 68 | } 69 | if (Array.isArray(key)) key = key.join('.'); 70 | set(this[this.prop], key, ...rest); 71 | this.emit('set', key, ...rest); 72 | return this; 73 | } 74 | 75 | /** 76 | * Return the value of `key`. 77 | * 78 | * ```js 79 | * app.set('a.b.c', 'd'); 80 | * app.get('a.b'); 81 | * //=> { c: 'd' } 82 | * ``` 83 | * @name .get 84 | * @emits `get` with `key` and `value` as arguments. 85 | * @param {String|Array} `key` The name of the property to get. Dot-notation may be used to set nested properties. 86 | * @return {any} Returns the value of `key` 87 | * @api public 88 | */ 89 | 90 | get(key) { 91 | if (Array.isArray(key)) key = key.join('.'); 92 | let val = get(this[this.prop], key); 93 | 94 | if (typeof val === 'undefined' && this.defaults) { 95 | val = get(this.defaults, key); 96 | } 97 | 98 | this.emit('get', key, val); 99 | return val; 100 | } 101 | 102 | /** 103 | * Create a property on the cache with the given `value` only if it doesn't 104 | * already exist. 105 | * 106 | * ```js 107 | * console.log(app.cache); //=> {} 108 | * app.set('one', { foo: 'bar' }); 109 | * app.prime('one', { a: 'b' }); 110 | * app.prime('two', { c: 'd' }); 111 | * console.log(app.cache.one); //=> { foo: 'bar' } 112 | * console.log(app.cache.two); //=> { c: 'd' } 113 | * ``` 114 | * @name .prime 115 | * @param {String} `key` Property name or object path notation. 116 | * @param {any} `val` 117 | * @return {Object} Returns the instance for chaining. 118 | * @api public 119 | */ 120 | 121 | prime(key, ...rest) { 122 | if (isObject(key) || (rest.length === 0 && Array.isArray(key))) { 123 | return this.visit('prime', key, ...rest); 124 | } 125 | if (Array.isArray(key)) key = key.join('.'); 126 | if (!this.has(key)) { 127 | this.set(key, ...rest); 128 | } 129 | return this; 130 | } 131 | 132 | /** 133 | * Set a default value to be used when `.get()` is called and the value is not defined 134 | * on the cache. Returns a value from the defaults when only a key is passed. 135 | * 136 | * ```js 137 | * app.set('foo', 'xxx'); 138 | * app.default('foo', 'one'); 139 | * app.default('bar', 'two'); 140 | * app.default('baz', 'three'); 141 | * app.set('baz', 'zzz'); 142 | * 143 | * console.log(app.get('foo')); 144 | * //=> 'xxx' 145 | * 146 | * console.log(app.get('bar')); 147 | * //=> 'two' 148 | * 149 | * console.log(app.get('baz')); 150 | * //=> 'zzz' 151 | * 152 | * console.log(app); 153 | * // CacheBase { 154 | * // cache: { foo: 'xxx', bar: 'two', baz: 'zzz' }, 155 | * // defaults: { foo: 'one', bar: 'two', baz: 'three' } } 156 | * ``` 157 | * @name .default 158 | * @param {String|Array} `key` The name of the property to set. Dot-notation may be used to set nested properties. 159 | * @param {any} `value` (optional) The value to set on the defaults object. 160 | * @return {Object} Returns the instance for chaining. 161 | * @api public 162 | */ 163 | 164 | default(key, ...rest) { 165 | this.defaults = this.defaults || {}; 166 | 167 | if (isObject(key) || (rest.length === 0 && Array.isArray(key))) { 168 | return this.visit('default', key, ...rest); 169 | } 170 | 171 | if (Array.isArray(key)) key = key.join('.'); 172 | if (!isString(key)) { 173 | throw new TypeError('expected "key" to be a string, object or array'); 174 | } 175 | 176 | if (rest.length === 0) { 177 | return get(this.defaults, key); 178 | } 179 | 180 | set(this.defaults, key, ...rest); 181 | this.emit('default', key, rest); 182 | return this; 183 | } 184 | 185 | /** 186 | * Set an array of unique values on cache `key`. 187 | * 188 | * ```js 189 | * app.union('a.b.c', 'foo'); 190 | * app.union('a.b.c', 'bar'); 191 | * app.union('a.b.c', ['bar', 'baz']); 192 | * console.log(app.get('a')); 193 | * //=> { b: { c: ['foo', 'bar', 'baz'] } } 194 | * ``` 195 | * @name .union 196 | * @param {String|Array} `key` The name of the property to union. Dot-notation may be used to set nested properties. 197 | * @param {any} `value` 198 | * @return {Object} Returns the instance for chaining. 199 | * @api public 200 | */ 201 | 202 | union(key, ...rest) { 203 | if (Array.isArray(key)) key = key.join('.'); 204 | union(this[this.prop], key, ...rest); 205 | this.emit('union', ...rest); 206 | return this; 207 | } 208 | 209 | /** 210 | * Return true if the value of property `key` is not `undefined`. 211 | * 212 | * ```js 213 | * app.set('foo', true); 214 | * app.set('baz', null); 215 | * app.set('bar', undefined); 216 | * 217 | * app.has('foo'); //=> true 218 | * app.has('bar'); //=> true 219 | * app.has('baz'); //=> false 220 | * ``` 221 | * @name .has 222 | * @param {String|Array} `key` The name of the property to check. Dot-notation may be used to set nested properties. 223 | * @return {Boolean} 224 | * @api public 225 | */ 226 | 227 | has(key) { 228 | if (Array.isArray(key)) key = key.join('.'); 229 | return typeof get(this[this.prop], key) !== 'undefined'; 230 | } 231 | 232 | /** 233 | * Returns true if the specified property is an own (not inherited) property. 234 | * Similar to [.has()](#has), but returns true if the key exists, even if the 235 | * value is `undefined`. 236 | * 237 | * ```js 238 | * app.set('a.b.c', 'd'); 239 | * app.set('x', false); 240 | * app.set('y', null); 241 | * app.set('z', undefined); 242 | * 243 | * app.hasOwn('a'); //=> true 244 | * app.hasOwn('b'); //=> true 245 | * app.hasOwn('c'); //=> true 246 | * app.hasOwn('a.b.c'); //=> true 247 | * app.hasOwn('x'); //=> true 248 | * app.hasOwn('y'); //=> true 249 | * app.hasOwn('z'); //=> true 250 | * app.hasOwn('lslsls'); //=> false 251 | * ``` 252 | * @name .hasOwn 253 | * @param {String} `key` 254 | * @return {Boolean} Returns true if object `key` exists. Dot-notation may be used to set nested properties. 255 | * @api public 256 | */ 257 | 258 | hasOwn(key) { 259 | if (Array.isArray(key)) key = key.join('.'); 260 | return hasOwn(this[this.prop], key); 261 | } 262 | 263 | /** 264 | * Delete one or more properties from the instance. 265 | * 266 | * ```js 267 | * // setup a listener to update a property with a default 268 | * // value when it's deleted by the user 269 | * app.on('del', key => app.set(key, app.default(key))); 270 | * 271 | * app.del(); // delete all properties on the cache 272 | * // or 273 | * app.del('foo'); 274 | * // or an array of keys 275 | * app.del(['foo', 'bar']); 276 | * ``` 277 | * @name .del 278 | * @emits `del` with the `key` as the only argument. 279 | * @param {string} `key` The name of the property to delete. Dot-notation may be used to delete nested properties. This method does not accept key as an array. 280 | * @return {Object} Returns the instance for chaining. 281 | * @api public 282 | */ 283 | 284 | del(key) { 285 | if (!key) return this.clear(); 286 | del(this[this.prop], key); 287 | this.emit('del', key); 288 | return this; 289 | } 290 | 291 | /** 292 | * Reset the entire cache to an empty object. Note that this does not also clear the `defaults` 293 | * object, since you can manually do `cache.defaults = {}` if you want to reset that object as well. 294 | * 295 | * ```js 296 | * // clear "defaults" whenever the cache is cleared 297 | * app.on('clear', key => (app.defaults = {})); 298 | * app.clear(); 299 | * ``` 300 | * @name .clear 301 | * @api public 302 | */ 303 | 304 | clear() { 305 | this[this.prop] = {}; 306 | this.emit('clear'); 307 | return this; 308 | } 309 | 310 | /** 311 | * Visit (or map visit) the specified method (`key`) over the properties in the 312 | * given object or array. 313 | * 314 | * @name .visit 315 | * @param {String|Array} `key` The name of the method to visit. 316 | * @param {Object|Array} `val` The object or array to iterate over. 317 | * @return {Object} Returns the instance for chaining. 318 | * @api public 319 | */ 320 | 321 | visit(key, ...rest) { 322 | visit(this, key, ...rest); 323 | return this; 324 | } 325 | 326 | /** 327 | * Gets an array of names of all enumerable properties on the cache. 328 | * 329 | * ```js 330 | * const app = new CacheBase(); 331 | * app.set('user', true); 332 | * app.set('admin', false); 333 | * 334 | * console.log(app.keys); 335 | * //=> ['user', 'admin'] 336 | * ``` 337 | * @name .keys 338 | * @api public 339 | */ 340 | 341 | get keys() { 342 | return Object.keys(this[this.prop]); 343 | } 344 | 345 | /** 346 | * Gets the length of [keys](#keys). 347 | * 348 | * ```js 349 | * const app = new CacheBase(); 350 | * app.set('user', true); 351 | * app.set('admin', false); 352 | * 353 | * console.log(app.size); 354 | * //=> 2 355 | * ``` 356 | * @name .size 357 | * @api public 358 | */ 359 | 360 | get size() { 361 | return this.keys.length; 362 | } 363 | } 364 | 365 | /** 366 | * Returns true if `value` is a non-empty string. 367 | */ 368 | 369 | function isString(value) { 370 | return typeof value === 'string' && value !== ''; 371 | } 372 | 373 | /** 374 | * Returns true if `value` is an object 375 | */ 376 | 377 | function isObject(value) { 378 | return typeOf(value) === 'object'; 379 | } 380 | 381 | /** 382 | * Expose `CacheBase` 383 | */ 384 | 385 | module.exports = CacheBase; 386 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cache-base", 3 | "description": "Basic object cache with `get`, `set`, `del`, and `has` methods for node.js/javascript projects.", 4 | "version": "4.0.2", 5 | "homepage": "https://github.com/jonschlinkert/cache-base", 6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)", 7 | "contributors": [ 8 | "Jon Schlinkert (http://twitter.com/jonschlinkert)", 9 | "(https://github.com/wtgtybhertgeghgtwtg)" 10 | ], 11 | "repository": "jonschlinkert/cache-base", 12 | "bugs": { 13 | "url": "https://github.com/jonschlinkert/cache-base/issues" 14 | }, 15 | "license": "MIT", 16 | "files": [ 17 | "index.js" 18 | ], 19 | "main": "index.js", 20 | "engines": { 21 | "node": ">=6" 22 | }, 23 | "scripts": { 24 | "test": "nyc --reporter=text --reporter=html mocha" 25 | }, 26 | "dependencies": { 27 | "@sellside/emitter": "^1.2.1", 28 | "collection-visit": "^1.0.0", 29 | "get-value": "^3.0.1", 30 | "has-own-deep": "^1.1.0", 31 | "kind-of": "^6.0.2", 32 | "set-value": "^4.1.0", 33 | "union-value": "^1.0.0", 34 | "unset-value": "^1.0.0" 35 | }, 36 | "devDependencies": { 37 | "gulp-format-md": "^1.0.0", 38 | "mocha": "^3.5.3", 39 | "nyc": "^11.6.0" 40 | }, 41 | "keywords": [ 42 | "base", 43 | "cache", 44 | "config", 45 | "data", 46 | "get", 47 | "has", 48 | "hash", 49 | "hasown", 50 | "object", 51 | "set", 52 | "store" 53 | ], 54 | "verb": { 55 | "run": true, 56 | "toc": true, 57 | "layout": "default", 58 | "tasks": [ 59 | "readme" 60 | ], 61 | "plugins": [ 62 | "gulp-format-md" 63 | ], 64 | "related": { 65 | "highligh": "base", 66 | "list": [ 67 | "base-methods", 68 | "get-value", 69 | "has-value", 70 | "option-cache", 71 | "set-value", 72 | "unset-value" 73 | ] 74 | }, 75 | "reflinks": [ 76 | "verb" 77 | ], 78 | "lint": { 79 | "reflinks": true 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /test/custom-property.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * cache-base 3 | * 4 | * Copyright (c) 2014-2018, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | require('mocha'); 11 | const assert = require('assert'); 12 | const Cache = require('../'); 13 | let app, cache; 14 | 15 | describe('custom property', function() { 16 | beforeEach(function() { 17 | app = new Cache('data'); 18 | }); 19 | 20 | describe('constructor:', function() { 21 | it('should create an instance of Cache', function() { 22 | assert(app instanceof Cache); 23 | }); 24 | 25 | it('should set ', function() { 26 | app = new Cache('data', { one: 1, two: 2 }); 27 | assert.equal(app.data.one, 1); 28 | assert.equal(app.data.two, 2); 29 | }); 30 | }); 31 | 32 | describe('get/set:', function() { 33 | describe('set() - add:', function() { 34 | it('should set a new property with the given value', function() { 35 | app.set('one', 1); 36 | assert.equal(app.get('one'), 1); 37 | assert.equal(app.data.one, 1); 38 | }); 39 | }); 40 | 41 | describe('set() - update:', function() { 42 | it('should update an existing property with the given value', function() { 43 | app.set('one', 2); 44 | assert.equal(app.get('one'), 2); 45 | assert.equal(app.data.one, 2); 46 | }); 47 | 48 | it('should get the given property', function() { 49 | app.set('a', 'b'); 50 | assert.equal(app.get('a'), 'b'); 51 | assert.equal(app.data.a, 'b'); 52 | }); 53 | }); 54 | }); 55 | 56 | describe('.set()', function() { 57 | it('should set a value', function() { 58 | app.set('a', 'b'); 59 | assert.equal(app.get('a'), 'b'); 60 | assert.equal(app.data.a, 'b'); 61 | }); 62 | 63 | it('should set properties on the `data` object', function() { 64 | app.set('a', 'b'); 65 | assert.equal(app.data.a, 'b'); 66 | }); 67 | 68 | it('should allow an object to be set directly', function() { 69 | app.set({x: 'y'}); 70 | assert.equal(app.data.x, 'y'); 71 | assert.equal(app.get('x'), 'y'); 72 | }); 73 | 74 | it('should set nested properties on the `data` object', function() { 75 | app.set('c', {d: 'e'}); 76 | assert.equal(app.get('c').d, 'e'); 77 | }); 78 | 79 | it('should return the instance', function() { 80 | assert.equal(app.set('a', 'b'), app); 81 | }); 82 | 83 | it('should be chainable', function() { 84 | app 85 | .set('aa', 'bb') 86 | .set('bb', 'cc') 87 | .set('cc', 'dd'); 88 | 89 | assert.equal(app.get('aa'), 'bb'); 90 | assert.equal(app.get('bb'), 'cc'); 91 | assert.equal(app.get('cc'), 'dd'); 92 | 93 | assert.equal(app.data.aa, 'bb'); 94 | assert.equal(app.data.bb, 'cc'); 95 | assert.equal(app.data.cc, 'dd'); 96 | }); 97 | 98 | it('should return undefined when not set', function() { 99 | assert.equal(app.set('sfsfsdfs', undefined), app); 100 | }); 101 | }); 102 | 103 | describe('.get()', function() { 104 | it('should otherwise return the value', function() { 105 | app.set('a', 'b'); 106 | assert.equal(app.get('a'), 'b'); 107 | assert.equal(app.data.a, 'b'); 108 | assert.equal(app.get('zllzzl'), undefined); 109 | }); 110 | }); 111 | }); 112 | -------------------------------------------------------------------------------- /test/events.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * cache-base 3 | * 4 | * Copyright (c) 2014-2018, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | require('mocha'); 11 | const assert = require('assert'); 12 | const Cache = require('../'); 13 | let app, cache; 14 | 15 | describe('events', function() { 16 | beforeEach(function() { 17 | app = new Cache(); 18 | }); 19 | 20 | describe('set', function() { 21 | it('should emit a "set" event', function(cb) { 22 | app.on('set', () => cb()); 23 | app.set('a', 'b'); 24 | }); 25 | 26 | it('should emit the key with "set" events', function(cb) { 27 | app.on('set', function(key, val) { 28 | assert.equal(key, 'a'); 29 | cb(); 30 | }); 31 | app.set('a', 'b'); 32 | }); 33 | 34 | it('should emit the value with "set" events', function(cb) { 35 | app.on('set', function(key, val) { 36 | assert.equal(val, 'b'); 37 | cb(); 38 | }); 39 | app.set('a', 'b'); 40 | }); 41 | }); 42 | 43 | describe('get', function() { 44 | it('should emit a get event', function(cb) { 45 | app.on('get', () => cb()); 46 | app.get('a'); 47 | }); 48 | 49 | it('should emit the key with "get" events', function(cb) { 50 | app.on('get', function(key, val) { 51 | assert.equal(key, 'a'); 52 | cb(); 53 | }); 54 | app.set('a', 'b'); 55 | app.get('a'); 56 | }); 57 | 58 | it('should emit the value with "get" events', function(cb) { 59 | app.on('get', function(key, val) { 60 | assert.equal(val, 'b'); 61 | cb(); 62 | }); 63 | app.set('a', 'b'); 64 | app.get('a'); 65 | }); 66 | }); 67 | 68 | describe('del', function() { 69 | it('should emit a del event', function(cb) { 70 | app.on('del', () => cb()); 71 | app.del('a'); 72 | }); 73 | 74 | it('should emit the key with "del" events', function(cb) { 75 | app.on('del', function(key) { 76 | assert.equal(key, 'a'); 77 | cb(); 78 | }); 79 | app.set('a', 'b'); 80 | app.del('a'); 81 | }); 82 | 83 | it('should emit each deleted key when multiple properties are deleted', function(cb) { 84 | var keys = []; 85 | app.on('del', key => keys.push(key)); 86 | 87 | app.set('a', 'b'); 88 | app.set('c', 'd'); 89 | 90 | app.del('a'); 91 | app.del('c'); 92 | assert.deepEqual(keys, ['a', 'c']); 93 | assert(!app.a); 94 | assert(!app.c); 95 | cb(); 96 | }); 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /test/fixtures/a.yml: -------------------------------------------------------------------------------- 1 | a: b -------------------------------------------------------------------------------- /test/fixtures/data/alert.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": { 3 | "test": true, 4 | "strong": "Heads up! This is a warning!", 5 | "text": "You forgot a field!" 6 | } 7 | } -------------------------------------------------------------------------------- /test/fixtures/data/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": "Whoa, I should be at the root!" 3 | } -------------------------------------------------------------------------------- /test/fixtures/data/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "alpha": "one", 3 | "beta": "two" 4 | } -------------------------------------------------------------------------------- /test/fixtures/namespace/a.yml: -------------------------------------------------------------------------------- 1 | one: ${site.two} -------------------------------------------------------------------------------- /test/fixtures/namespace/b.yml: -------------------------------------------------------------------------------- 1 | two: ${site.three} -------------------------------------------------------------------------------- /test/fixtures/namespace/c.json: -------------------------------------------------------------------------------- 1 | { 2 | "three": "data was processed!" 3 | } -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * cache-base 3 | * 4 | * Copyright (c) 2014-2018, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | require('mocha'); 11 | const assert = require('assert'); 12 | const Cache = require('../'); 13 | let app, cache; 14 | 15 | describe('cache-base', function() { 16 | beforeEach(function() { 17 | app = new Cache(); 18 | }); 19 | 20 | describe('constructor:', function() { 21 | it('should create an instance of Cache', function() { 22 | assert(app instanceof Cache); 23 | }); 24 | 25 | it('should set values passed on the ctor', function() { 26 | app = new Cache({ one: 1, two: 2 }); 27 | assert.equal(app.cache.one, 1); 28 | assert.equal(app.cache.two, 2); 29 | }); 30 | }); 31 | 32 | describe('prime', function() { 33 | it('should prime a property on the cache with the given value', function() { 34 | app.prime('life', 42); 35 | assert.equal(app.cache.life, 42); 36 | }); 37 | 38 | it('should not prime a property if it already exists', function() { 39 | app.set('life', 51); 40 | app.prime('life', 42); 41 | assert.equal(app.cache.life, 51); 42 | }); 43 | 44 | it('should prime an object', function() { 45 | app.prime({ life: 42 }); 46 | assert.equal(app.cache.life, 42); 47 | }); 48 | }); 49 | 50 | describe('default', function() { 51 | it('should set a default value on cache.defaults', function() { 52 | app.default('life', 42); 53 | assert.equal(app.defaults.life, 42); 54 | }); 55 | 56 | it('should not set a default value on the cache object', function() { 57 | app.default('life', 42); 58 | assert.equal(app.cache.life, undefined); 59 | }); 60 | 61 | it('should be overridden when values are set', function() { 62 | app.default('life', 42); 63 | app.set('life', 51); 64 | assert.equal(app.cache.life, 51); 65 | }); 66 | 67 | it('should not set a default if it already exists', function() { 68 | app.set('life', 51); 69 | app.default('life', 42); 70 | assert.equal(app.cache.life, 51); 71 | }); 72 | 73 | it('should take an object', function() { 74 | app.default({ life: 41 }); 75 | assert.equal(app.defaults.life, 41); 76 | }); 77 | 78 | it('should take an array of objects', function() { 79 | app.default([{ meaning: 41, life: 42 }]); 80 | assert.equal(app.defaults.meaning, 41); 81 | assert.equal(app.defaults.life, 42); 82 | }); 83 | 84 | it('should return a value from cache.defaults when only the key is passed', function() { 85 | app.default({ foo: 1, bar: 2 }); 86 | assert.equal(app.default('foo'), 1); 87 | }); 88 | 89 | it('should return the default value with `.get()`', function() { 90 | app.default({ foo: 1, bar: 2 }); 91 | 92 | app.set('foo', 42); 93 | assert.equal(app.get('foo'), 42); 94 | 95 | app.del('foo'); 96 | assert.equal(app.get('foo'), 1); 97 | assert.equal(app.get('bar'), 2); 98 | }); 99 | }); 100 | 101 | describe('set', function() { 102 | it('should set a value', function() { 103 | app.set('a', 'b'); 104 | assert.equal(app.get('a'), 'b'); 105 | }); 106 | 107 | it('should set properties on `app.cache` when defined as key-value pairs', function() { 108 | app.set('a', 'b'); 109 | assert.equal(app.cache.a, 'b'); 110 | }); 111 | 112 | it('should set properties on `app.cache` when defined as as an object', function() { 113 | app.set({x: 'y'}); 114 | assert.equal(app.cache.x, 'y'); 115 | assert.equal(app.get('x'), 'y'); 116 | }); 117 | 118 | it('should set nested properties on the `app.cache`', function() { 119 | app.set('c', {d: 'e'}); 120 | assert.equal(app.get('c.d'), 'e'); 121 | }); 122 | 123 | it('should be chainable', function() { 124 | assert.equal(app.set('a', 'b'), app); 125 | app 126 | .set('aa', 'bb') 127 | .set('bb', 'cc') 128 | .set('cc', 'dd'); 129 | assert.equal(app.get('aa'), 'bb'); 130 | assert.equal(app.get('bb'), 'cc'); 131 | assert.equal(app.get('cc'), 'dd'); 132 | }); 133 | 134 | it('should return undefined when not set', function() { 135 | assert.equal(app.set('a', undefined), app); 136 | }); 137 | }); 138 | 139 | describe('get', function() { 140 | it('should return undefined when no set', function() { 141 | assert(app.get('a') === undefined); 142 | }); 143 | 144 | it('should get a value', function() { 145 | app.set('a', 'b'); 146 | assert.equal(app.get('a'), 'b'); 147 | }); 148 | 149 | it('should get a nested property value', function() { 150 | app.set('a.b.c', 'z'); 151 | assert.equal(app.cache.a.b.c, 'z'); 152 | assert.deepEqual(app.get('a.b'), {c: 'z'}); 153 | }); 154 | 155 | it('should support passing key as an array', function() { 156 | app.set('a.b.c', 'z'); 157 | assert.equal(app.cache.a.b.c, 'z'); 158 | assert.deepEqual(app.get(['a', 'b']), {c: 'z'}); 159 | }); 160 | }); 161 | 162 | describe('union', function() { 163 | it('should union a string value', function() { 164 | app.union('a', 'b'); 165 | assert.deepEqual(app.get('a'), ['b']); 166 | }); 167 | 168 | it('should union multiple string values', function() { 169 | app.union('a', 'b'); 170 | app.union('a', 'c'); 171 | app.union('a', 'd'); 172 | assert.deepEqual(app.get('a'), ['b', 'c', 'd']); 173 | }); 174 | 175 | it('should union multiple arrays', function() { 176 | app.union('a', ['b']); 177 | app.union('a', ['c']); 178 | app.union('a', ['d']); 179 | assert.deepEqual(app.get('a'), ['b', 'c', 'd']); 180 | }); 181 | 182 | it('should union strings and arrays', function() { 183 | app.union('a', 'a'); 184 | app.union('a', ['b']); 185 | app.union('a', ['c', 'd']); 186 | assert.deepEqual(app.get('a'), ['a', 'b', 'c', 'd']); 187 | }); 188 | 189 | it('should union nested string values', function() { 190 | app.union('a.b', 'b'); 191 | app.union('a.b', 'c'); 192 | app.union('a.b', 'd'); 193 | assert.deepEqual(app.get('a'), {b: ['b', 'c', 'd']}); 194 | }); 195 | 196 | it('should union and uniquify arrays', function() { 197 | app.union('a.b', ['b', 'foo']); 198 | app.union('a.b', ['c', 'foo']); 199 | app.union('a.b', ['d', 'foo']); 200 | assert.deepEqual(app.get('a'), {b: ['b', 'foo', 'c', 'd']}); 201 | }); 202 | }); 203 | 204 | describe('has', function() { 205 | it('should return true if cache has a value for the given key', function() { 206 | app.set('foo', 'bar'); 207 | app.set('baz', null); 208 | app.set('qux', undefined); 209 | 210 | assert(app.has('foo')); 211 | assert(!app.has('bar')); 212 | assert(app.has('baz')); 213 | assert(!app.has('qux')); 214 | }); 215 | 216 | it('should work with escaped keys', function() { 217 | app.set('foo\\.baz', 'bar'); 218 | 219 | assert(!app.has('foo')); 220 | assert(!app.has('bar')); 221 | assert(app.has('foo.baz')); 222 | }); 223 | 224 | it('should return true if a nested key value on the cache', function() { 225 | app.set('a.b.c.d', { x: 'zzz' }); 226 | app.set('a.b.c.e', { f: null }); 227 | app.set('a.b.g.j', { k: undefined }); 228 | 229 | assert(app.has('a')); 230 | assert(app.has('a.b')); 231 | assert(app.has('a.b.c')); 232 | assert(app.has('a.b.c.d')); 233 | assert(app.has('a.b.c.d.x')); 234 | assert(app.has('a.b.c.e.f')); 235 | assert(!app.has('a.b.g.j.k')); 236 | 237 | assert(!app.has('a.b.bar')); 238 | assert(!app.has('a.b.c.d.z')); 239 | assert(!app.has('a.b.c.e.bar')); 240 | assert(!app.has('a.b.g.j.foo')); 241 | }); 242 | }); 243 | 244 | describe('hasOwn', function() { 245 | it('should return true if a cache has own key', function() { 246 | app.set('foo', 'bar'); 247 | app.set('baz', null); 248 | app.set('qux', undefined); 249 | 250 | assert(app.hasOwn('foo')); 251 | assert(!app.hasOwn('bar')); 252 | assert(app.hasOwn('baz')); 253 | assert(!app.hasOwn('qux')); 254 | }); 255 | 256 | it('should work with escaped keys', function() { 257 | app.set('foo\\.baz', 'bar'); 258 | app.set('baz', null); 259 | app.set('qux', undefined); 260 | 261 | assert(!app.hasOwn('foo')); 262 | assert(!app.hasOwn('bar')); 263 | assert(app.hasOwn('foo.baz')); 264 | assert(app.hasOwn('baz')); 265 | assert(!app.hasOwn('qux')); 266 | }); 267 | 268 | it('should return true if a nested key exists `.hasOwn()` on the cache', function() { 269 | app.set('a.b.c.d', { x: 'zzz' }); 270 | app.set('a.b.c.e', { f: null }); 271 | app.set('a.b.g.j', { k: undefined }); 272 | 273 | assert(app.hasOwn('a')); 274 | assert(app.hasOwn('a.b')); 275 | assert(app.hasOwn('a.b.c')); 276 | assert(app.hasOwn('a.b.c.d')); 277 | assert(app.hasOwn('a.b.c.d.x')); 278 | assert(app.hasOwn('a.b.c.e.f')); 279 | assert(app.hasOwn('a.b.g.j.k')); 280 | assert(app.hasOwn('a.b.g.j.k')); 281 | assert(app.hasOwn('a.b.c.e.f')); 282 | 283 | assert(!app.hasOwn('a.b.bar')); 284 | assert(!app.hasOwn('a.b.c.d.z')); 285 | assert(!app.hasOwn('a.b.c.e.bar')); 286 | assert(!app.hasOwn('a.b.g.j.foo')); 287 | }); 288 | }); 289 | 290 | describe('del', function() { 291 | it('should delete a property from the cache', function() { 292 | app.set('foo', 42); 293 | app.set('bar', 43); 294 | 295 | assert.equal(app.get('foo'), 42); 296 | assert.equal(app.get('bar'), 43); 297 | app.del('foo'); 298 | 299 | assert.equal(app.get('foo'), undefined); 300 | assert.equal(app.get('bar'), 43); 301 | }); 302 | 303 | it('should delete all property from the cache when no key is passed', function() { 304 | app.set('foo', 42); 305 | app.set('bar', 43); 306 | 307 | assert.equal(app.get('foo'), 42); 308 | assert.equal(app.get('bar'), 43); 309 | app.del(); 310 | 311 | assert.equal(app.get('foo'), undefined); 312 | assert.equal(app.get('bar'), undefined); 313 | }); 314 | }); 315 | 316 | describe('keys', function() { 317 | it('should return all enumerable property names from the cache', function() { 318 | app.set('foo', 42); 319 | app.set('bar', null); 320 | app.set('baz', undefined); 321 | 322 | assert.deepEqual(app.keys, ['foo', 'bar']); 323 | }); 324 | }); 325 | 326 | describe('size', function() { 327 | it('should return the length of cache.keys', function() { 328 | app.set('foo', 'bar'); 329 | app.set('baz', null); 330 | app.set('qux', undefined); 331 | 332 | assert.equal(app.size, 2); 333 | }); 334 | }); 335 | }); 336 | --------------------------------------------------------------------------------