diff --git a/.eslintrc.json b/.eslintrc.json
index 61e8895..24b8984 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,4 +1,8 @@
{
+ "extends": [
+ "eslint:recommended"
+ ],
+
"env": {
"browser": false,
"es6": true,
@@ -6,6 +10,15 @@
"mocha": true
},
+ "parserOptions":{
+ "ecmaVersion": 9,
+ "sourceType": "module",
+ "ecmaFeatures": {
+ "modules": true,
+ "experimentalObjectRestSpread": true
+ }
+ },
+
"globals": {
"document": false,
"navigator": false,
diff --git a/.travis.yml b/.travis.yml
index 44adec2..f6cf862 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,8 +11,3 @@ node_js:
- '6'
- '5'
- '4'
-matrix:
- fast_finish: true
- allow_failures:
- - node_js: '5'
- - node_js: '4'
diff --git a/.verb.md b/.verb.md
index 544ae0d..17bca7a 100644
--- a/.verb.md
+++ b/.verb.md
@@ -4,19 +4,18 @@
// default cwd is `~/data-store/` (in user-home)
var store = require('{%= name %}')('my-app');
-store
- .set('a', 'b')
- .set({c: 'd'})
- .set('e.f', 'g')
+store.set('a', 'b')
+ .set({ c: 'd' })
+ .set('e.f', 'g');
console.log(store.get('e.f'));
//=> 'g'
console.log(store.get());
-//=> {name: 'app', data: {a: 'b', c: 'd', e: {f: 'g' }}}
+//=> { name: 'app', data: { a: 'b', c: 'd', e: { f: 'g' } } }
console.log(store.data);
-//=> {a: 'b', c: 'd', e: {f: 'g'}}
+//=> { a: 'b', c: 'd', e: { f: 'g' } }
```
## API
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..767fb95
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,267 @@
+# Release history
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+
+ Guiding Principles
+
+- Changelogs are for humans, not machines.
+- There should be an entry for every single version.
+- The same types of changes should be grouped.
+- Versions and sections should be linkable.
+- The latest version comes first.
+- The release date of each versions is displayed.
+- Mention whether you follow Semantic Versioning.
+
+
+
+
+ Types of changes
+
+Changelog entries are classified using the following labels _(from [keep-a-changelog](http://keepachangelog.com/)_):
+
+- `Added` for new features.
+- `Changed` for changes in existing functionality.
+- `Deprecated` for soon-to-be removed features.
+- `Removed` for now removed features.
+- `Fixed` for any bug fixes.
+- `Security` in case of vulnerabilities.
+
+
+
+
+## [2.0.0] - 2017-05-22
+
+- Use XDG directory
+- Merge pull request #8 from jamen/master
+
+## [1.0.0] - 2017-05-22
+
+- run update
+- update deps, remove verbfile.js
+- add example to readme
+- allow `store.path` to be set directly
+
+## [0.16.1] - 2016-07-11
+
+- run update
+- adds debug, minor edits
+- use `verb-generate-readme`
+- generate docs
+
+## [0.16.0] - 2016-05-19
+
+- expose sub-store data on property of parent store
+- generate docs
+
+## [0.15.5] - 2016-03-02
+
+- allow dashes in sub-store names
+- generate docs
+
+## [0.15.4] - 2016-02-27
+
+- fixes https://github.com/jonschlinkert/data-store/commit/a62b36aa7fc9a7215bb15ab5738dd79686eae25c#commitcomment-16372520, thanks to @tunnckoCore for point it out
+
+## [0.15.3] - 2016-02-27
+
+- simplify to use `this.name`
+- generate docs
+
+## [0.15.2] - 2016-02-27
+
+- handle path differently, fix basename bug
+- generate docs
+
+## [0.15.1] - 2016-02-27
+
+- fix keys getter, path bug
+- generate docs
+
+## [0.15.0] - 2016-02-27
+
+- use `cache-base` lib instead of `base`, also adds `create` method
+- adds verbfile.js
+- update dependencies
+- generate docs
+
+## [0.14.0] - 2016-02-04
+
+- only write data that was set through the API
+
+## [0.13.0] - 2016-01-23
+
+- use `base` lib
+- clean up deps
+- lint
+- update deps, verb config
+
+## [0.12.1] - 2016-01-02
+
+- run `update`
+- copyright date
+- remove code that is already provided by base-methods
+- update deps
+
+## [0.12.0] - 2015-11-09
+
+- use eslint
+- lint
+- update deps
+- `get` now expects key to not be undefined
+- clean up, save on set, update readme
+
+## [0.11.1] - 2015-10-23
+
+- adds events to `has` and `hasOwn`
+- streamline tests, add test for `has` event
+- update docs
+
+## [0.11.0] - 2015-10-21
+
+- make del sync
+- update docs for 0.11.0
+
+## [0.10.1] - 2015-10-19
+
+- use `resolve-dir`
+- rebuild docs
+
+## [0.10.0] - 2015-10-14
+
+- lint
+- update lazy-cache signature
+- adds gulp
+- use base-methods
+- adds coverage
+
+## [0.9.0] - 2015-08-30
+
+- move libs to utils
+- adds static `extend` method
+- adds 0.9.0 tests
+- examples for 0.9.0
+- build docs
+
+## [0.8.2] - 2015-08-19
+
+- add an indent option to pass to JSON.stringify
+- save after union and del commands
+- updating option comments and rebuilding readme
+- Merge pull request #6 from jonschlinkert/indent-and-save
+- update to latest lazy-cache
+
+## [0.8.1] - 2015-08-01
+
+- fix `.has` method
+- add `.hasOwn` method
+- Merge pull request #5 from chorks/hasown-method
+- make it lazier
+
+## [0.8.0] - 2015-07-05
+
+- adds `union` method
+- generate docs
+
+## [0.6.0] - 2015-05-07
+
+- breaking change: `delete` => `del`
+- update metadata
+- fix template
+- generate docs
+
+## [0.5.0] - 2015-04-19
+
+- adds events
+- events tests
+- remove junk
+
+## [0.4.1] - 2015-03-28
+
+- persist store
+
+## [0.4.0] - 2015-03-28
+
+- adds travis badge
+- lint
+- adds example.js to editorconfig
+- update example
+- refactored
+- update examples
+- include example.js
+- update tests
+
+## [0.3.3] - 2015-02-09
+
+- travis
+
+## [0.3.2] - 2015-02-08
+
+- rename license file
+- remove junk
+- build readme
+
+## [0.3.1] - 2014-12-17
+
+- Merge remote-tracking branch 'origin/prev'
+- lint
+
+## [0.3.0] - 2014-12-17
+
+- fix readme
+- adds npmignore
+- adds example, tests
+- update dotfiles
+- remove extra heading in readme
+- update ignore patterns
+- fix examples
+- update ignore patterns
+- adds `extists` and `delete` methods
+- build readme
+
+## [0.2.0] - 2014-11-15
+
+- first commit
+- remove console.log
+- remove old fixtures
+- update verb and dotfiles
+- refactor
+- run verb
+
+[2.0.0]: https://github.com/jonschlinkert/data-store/compare/0.2.0...HEAD
+[1.0.0]: https://github.com/jonschlinkert/data-store/compare/0.16.1...1.0.0
+[0.16.1]: https://github.com/jonschlinkert/data-store/compare/0.16.0...0.16.1
+[0.16.0]: https://github.com/jonschlinkert/data-store/compare/0.15.5...0.16.0
+[0.15.5]: https://github.com/jonschlinkert/data-store/compare/0.15.4...0.15.5
+[0.15.4]: https://github.com/jonschlinkert/data-store/compare/0.15.3...0.15.4
+[0.15.3]: https://github.com/jonschlinkert/data-store/compare/0.15.2...0.15.3
+[0.15.2]: https://github.com/jonschlinkert/data-store/compare/0.15.1...0.15.2
+[0.15.1]: https://github.com/jonschlinkert/data-store/compare/0.15.0...0.15.1
+[0.15.0]: https://github.com/jonschlinkert/data-store/compare/0.14.0...0.15.0
+[0.14.0]: https://github.com/jonschlinkert/data-store/compare/0.13.0...0.14.0
+[0.13.0]: https://github.com/jonschlinkert/data-store/compare/0.12.1...0.13.0
+[0.12.1]: https://github.com/jonschlinkert/data-store/compare/0.12.0...0.12.1
+[0.12.0]: https://github.com/jonschlinkert/data-store/compare/0.11.1...0.12.0
+[0.11.1]: https://github.com/jonschlinkert/data-store/compare/0.11.0...0.11.1
+[0.11.0]: https://github.com/jonschlinkert/data-store/compare/0.10.1...0.11.0
+[0.10.1]: https://github.com/jonschlinkert/data-store/compare/0.10.0...0.10.1
+[0.10.0]: https://github.com/jonschlinkert/data-store/compare/0.9.0...0.10.0
+[0.9.0]: https://github.com/jonschlinkert/data-store/compare/0.8.2...0.9.0
+[0.8.2]: https://github.com/jonschlinkert/data-store/compare/0.8.1...0.8.2
+[0.8.1]: https://github.com/jonschlinkert/data-store/compare/0.8.0...0.8.1
+[0.8.0]: https://github.com/jonschlinkert/data-store/compare/0.6.1...0.8.0
+[0.6.1]: https://github.com/jonschlinkert/data-store/compare/0.6.0...0.6.1
+[0.6.0]: https://github.com/jonschlinkert/data-store/compare/0.5.0...0.6.0
+[0.5.0]: https://github.com/jonschlinkert/data-store/compare/0.4.1...0.5.0
+[0.4.1]: https://github.com/jonschlinkert/data-store/compare/0.4.0...0.4.1
+[0.4.0]: https://github.com/jonschlinkert/data-store/compare/0.3.3...0.4.0
+[0.3.3]: https://github.com/jonschlinkert/data-store/compare/0.3.2...0.3.3
+[0.3.2]: https://github.com/jonschlinkert/data-store/compare/0.3.1...0.3.2
+[0.3.1]: https://github.com/jonschlinkert/data-store/compare/0.3.0...0.3.1
+[0.3.0]: https://github.com/jonschlinkert/data-store/compare/0.2.0...0.3.0
+
+[keep-a-changelog]: https://github.com/olivierlacan/keep-a-changelog
+
diff --git a/README.md b/README.md
index bc4b8f2..fbba63e 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,7 @@
> Easily get, set and persist config data.
-You might also be interested in [base-store](https://github.com/node-base/base-store).
-
-## Table of Contents
+Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.
- [Install](#install)
- [Usage example](#usage-example)
@@ -27,27 +25,22 @@ $ npm install --save data-store
// default cwd is `~/data-store/` (in user-home)
var store = require('data-store')('my-app');
-store
- .set('a', 'b')
- .set({c: 'd'})
- .set('e.f', 'g')
+store.set('a', 'b')
+ .set({ c: 'd' })
+ .set('e.f', 'g');
console.log(store.get('e.f'));
//=> 'g'
console.log(store.get());
-//=> {name: 'app', data: {a: 'b', c: 'd', e: {f: 'g' }}}
+//=> { name: 'app', data: { a: 'b', c: 'd', e: { f: 'g' } } }
console.log(store.data);
-//=> {a: 'b', c: 'd', e: {f: 'g'}}
+//=> { a: 'b', c: 'd', e: { f: 'g' } }
```
## API
-### [Store](index.js#L42)
-
-Initialize a new `Store` with the given `name` and `options`.
-
**Params**
* `name` **{String}**: Store name to use for the basename of the `.json` file.
@@ -58,35 +51,16 @@ Initialize a new `Store` with the given `name` and `options`.
**Example**
```js
-var store = require('data-store')('abc');
+const store = require('data-store')('abc');
//=> '~/data-store/a.json'
-var store = require('data-store')('abc', {
+const store = require('data-store')('abc', {
cwd: 'test/fixtures'
});
//=> './test/fixtures/abc.json'
```
-### [.create](index.js#L99)
-
-Create a namespaced "sub-store" that persists data to its file in a sub-folder of the same directory as the "parent" store.
-
-**Params**
-
-* `name` **{String}**: The name of the sub-store.
-* `options` **{Object}**
-* `returns` **{Object}**: Returns the sub-store instance.
-
-**Example**
-
-```js
-store.create('foo');
-store.foo.set('a', 'b');
-console.log(store.foo.get('a'));
-//=> 'b'
-```
-
-### [.set](index.js#L147)
+### [.set](index.js#L82)
Assign `value` to `key` and save to disk. Can be a key-value pair or an object.
@@ -106,38 +80,29 @@ store.set('a', 'b');
// extend the store with an object
store.set({a: 'b'});
//=> {a: 'b'}
-
-// extend the the given value
-store.set('a', {b: 'c'});
-store.set('a', {d: 'e'}, true);
-//=> {a: {b 'c', d: 'e'}}
-
-// overwrite the the given value
-store.set('a', {b: 'c'});
-store.set('a', {d: 'e'});
-//=> {d: 'e'}
```
-### [.union](index.js#L163)
+### [.union](index.js#L114)
-Add or append an array of unique values to the given `key`.
+Get the stored `value` of `key`, or return the entire store if no `key` is defined.
**Params**
* `key` **{String}**
-* `returns` **{any}**: The array to add or append for `key`.
+* `returns` **{any}**: The value to store for `key`.
**Example**
```js
-store.union('a', ['a']);
-store.union('a', ['b']);
-store.union('a', ['c']);
+store.set('a', {b: 'c'});
store.get('a');
-//=> ['a', 'b', 'c']
+//=> {b: 'c'}
+
+store.get();
+//=> {b: 'c'}
```
-### [.get](index.js#L189)
+### [.get](index.js#L142)
Get the stored `value` of `key`, or return the entire store if no `key` is defined.
@@ -157,9 +122,9 @@ store.get();
//=> {b: 'c'}
```
-### [.has](index.js#L205)
+### [.has](index.js#L162)
-Returns `true` if the specified `key` has truthy value.
+Returns `true` if the specified `key` has a value.
**Params**
@@ -176,10 +141,6 @@ store.has('c'); //=> false
store.has('d'); //=> false
```
-### [.hasOwn](index.js#L226)
-
-Returns `true` if the specified `key` exists.
-
**Params**
* `key` **{String}**
@@ -200,34 +161,6 @@ store.hasOwn('d'); //=> true
store.hasOwn('foo'); //=> false
```
-### [.save](index.js#L246)
-
-Persist the store to disk.
-
-**Params**
-
-* `dest` **{String}**: Optionally define an alternate destination file path.
-
-**Example**
-
-```js
-store.save();
-```
-
-### [.clear](index.js#L261)
-
-Clear in-memory cache.
-
-**Example**
-
-```js
-store.clear();
-```
-
-### [.del](index.js#L286)
-
-Delete `keys` from the store, or delete the entire store if no keys are passed. A `del` event is also emitted for each key deleted.
-
**Note that to delete the entire store you must pass `{force: true}`**
**Params**
@@ -244,38 +177,34 @@ store.del();
store.del({force: true});
```
-### [.define](index.js#L347)
-
-Define a non-enumerable property on the instance.
-
-**Params**
+**Example**
-* `key` **{String}**
-* `value` **{any}**
-* `returns` **{Object}**: Returns the instance for chaining.
+```js
+store.save();
+```
## About
-### Related projects
+
+Contributing
-* [base-store](https://www.npmjs.com/package/base-store): Plugin for getting and persisting config values with your base-methods application. Adds a 'store' object… [more](https://github.com/node-base/base-store) | [homepage](https://github.com/node-base/base-store "Plugin for getting and persisting config values with your base-methods application. Adds a 'store' object that exposes all of the methods from the data-store library. Also now supports sub-stores!")
-* [cache-base](https://www.npmjs.com/package/cache-base): Basic object cache with `get`, `set`, `del`, and `has` methods for node.js/javascript projects. | [homepage](https://github.com/jonschlinkert/cache-base "Basic object cache with `get`, `set`, `del`, and `has` methods for node.js/javascript projects.")
-* [get-value](https://www.npmjs.com/package/get-value): Use property paths (`a.b.c`) to get a nested value from an object. | [homepage](https://github.com/jonschlinkert/get-value "Use property paths (`a.b.c`) to get a nested value from an object.")
-* [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.")
+Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
-### Contributing
+
-Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
+
+Running Tests
-### Contributors
+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:
-| **Commits** | **Contributor** |
-| --- | --- |
-| 128 | [jonschlinkert](https://github.com/jonschlinkert) |
-| 3 | [doowb](https://github.com/doowb) |
-| 2 | [tunnckoCore](https://github.com/tunnckoCore) |
+```sh
+$ npm install && npm test
+```
-### Building docs
+
+
+
+Building docs
_(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.)_
@@ -285,26 +214,40 @@ To generate the readme, run the following command:
$ npm install -g verbose/verb#dev verb-generate-readme && verb
```
-### Running tests
+
-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:
+### Related projects
-```sh
-$ npm install && npm test
-```
+You might also be interested in these projects:
+
+* [base](https://www.npmjs.com/package/base): Framework for rapidly creating high quality, server-side node.js applications, using plugins like building blocks | [homepage](https://github.com/node-base/base "Framework for rapidly creating high quality, server-side node.js applications, using plugins like building blocks")
+* [cache-base](https://www.npmjs.com/package/cache-base): Basic object cache with `get`, `set`, `del`, and `has` methods for node.js/javascript projects. | [homepage](https://github.com/jonschlinkert/cache-base "Basic object cache with `get`, `set`, `del`, and `has` methods for node.js/javascript projects.")
+* [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!).")
+* [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.")
+* [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.")
+
+### Contributors
+
+| **Commits** | **Contributor** |
+| --- | --- |
+| 135 | [jonschlinkert](https://github.com/jonschlinkert) |
+| 3 | [doowb](https://github.com/doowb) |
+| 2 | [charlike-old](https://github.com/charlike-old) |
+| 1 | [jamen](https://github.com/jamen) |
### Author
**Jon Schlinkert**
-* [github/jonschlinkert](https://github.com/jonschlinkert)
-* [twitter/jonschlinkert](https://twitter.com/jonschlinkert)
+* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)
+* [GitHub Profile](https://github.com/jonschlinkert)
+* [Twitter Profile](https://twitter.com/jonschlinkert)
### License
-Copyright © 2017, [Jon Schlinkert](https://github.com/jonschlinkert).
+Copyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert).
Released under the [MIT License](LICENSE).
***
-_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on May 22, 2017._
\ No newline at end of file
+_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on April 19, 2018._
\ No newline at end of file
diff --git a/example.js b/example.js
index 3a400a8..622c6ac 100644
--- a/example.js
+++ b/example.js
@@ -1,16 +1,18 @@
// default cwd is `~/data-store/`
-var store = require('./')('app', {cwd: 'actual'});
+const Store = require('./');
+const store = new Store('app', { cwd: 'test/actual' });
-store
- .set('a', 'b')
- .set({c: 'd'})
- .set('e.f', 'g')
+store.set('a', 'b');
+store.set({ c: 'd' });
+store.set('e.f', 'g')
console.log(store.get('e.f'));
//=> 'g'
console.log(store.get());
-//=> {name: 'app', data: {a: 'b', c: 'd', e: {f: 'g' }}}
+//=> { name: 'app', data: { a: 'b', c: 'd', e: { f: 'g' } } }
console.log(store.data);
-//=> {a: 'b', c: 'd', e: {f: 'g'}}
+//=> { a: 'b', c: 'd', e: { f: 'g' } }
+
+console.log(store.keys)
diff --git a/gulpfile.js b/gulpfile.js
deleted file mode 100644
index 459a7e2..0000000
--- a/gulpfile.js
+++ /dev/null
@@ -1,27 +0,0 @@
-'use strict';
-
-var gulp = require('gulp');
-var mocha = require('gulp-mocha');
-var istanbul = require('gulp-istanbul');
-var eslint = require('gulp-eslint');
-
-var lint = ['index.js', 'utils.js'];
-
-gulp.task('coverage', function() {
- return gulp.src(lint)
- .pipe(istanbul())
- .pipe(istanbul.hookRequire());
-});
-
-gulp.task('mocha', ['coverage'], function() {
- return gulp.src('test.js')
- .pipe(mocha({reporter: 'spec'}))
- .pipe(istanbul.writeReports());
-});
-
-gulp.task('eslint', function() {
- return gulp.src(lint.concat('test.js'))
- .pipe(eslint())
-});
-
-gulp.task('default', ['mocha', 'eslint']);
diff --git a/index.js b/index.js
index 401f426..6db8429 100644
--- a/index.js
+++ b/index.js
@@ -1,32 +1,25 @@
'use strict';
-/**
- * Module dependencies
- */
-
-var path = require('path');
-var util = require('util');
-var base = require('cache-base');
-var Base = base.namespace('cache');
-var debug = require('debug')('data-store');
-var proto = Base.prototype;
-var utils = require('./utils');
-
-/**
- * Expose `Store`
- */
-
-module.exports = Store;
+const fs = require('fs');
+const os = require('os');
+const path = require('path');
+const assert = require('assert');
+const Emitter = require('events');
+const flatten = (...args) => [].concat.apply([], args);
+const unique = arr => arr.filter((v, i) => arr.indexOf(v) === i);
+const mode = opts => opts.mode || (parseInt('0777', 8) & ~process.umask());
+const strip = str => str.replace(/\\(?=\.)/g, '');
+const split = str => str.split(/(? '~/data-store/a.json'
*
- * var store = require('data-store')('abc', {
+ * const store = require('data-store')('abc', {
* cwd: 'test/fixtures'
* });
* //=> './test/fixtures/abc.json'
@@ -39,355 +32,291 @@ module.exports = Store;
* @api public
*/
-function Store(name, options) {
- if (!(this instanceof Store)) {
- return new Store(name, options);
+class Store extends Emitter {
+ constructor(name, options = {}, defaults = {}) {
+ assert.equal(typeof name, 'string', 'expected options.name to be a string');
+ super();
+ this.name = name;
+ this.options = options;
+ this.indent = this.options.indent != null ? this.options.indent : 2;
+ this.cwd = this.options.cwd || os.homedir();
+ this.folder = this.options.folder || '.data-store';
+ this.dirname = path.join(this.cwd, this.folder);
+ this.path = this.options.path || path.join(this.dirname, this.name + '.json');
+ this.relative = path.relative(process.cwd(), this.path);
+ this.data = Object.assign({}, defaults, this.data);
}
- if (typeof name !== 'string') {
- options = name;
- name = null;
- }
-
- Base.call(this);
- this.isStore = true;
- this.options = options || {};
- this.initStore(name);
-}
+ /**
+ * Get and set the `store.data` object that is persisted.
+ */
-/**
- * Inherit `Base`
- */
-
-util.inherits(Store, Base);
-
-/**
- * Initialize store defaults
- */
-
-Store.prototype.initStore = function(name) {
- this.name = name || utils.project(process.cwd());
- this.cwd = utils.resolve(this.options.cwd || '~/.config/data-store');
- this.path = this.options.path || path.resolve(this.cwd, this.name + '.json');
- this.relative = path.relative(process.cwd(), this.path);
-
- debug('Initializing store <%s>', this.path);
-
- this.data = this.readFile(this.path);
- this.define('cache', utils.clone(this.data));
- this.on('set', function() {
+ set data(val) {
+ this._data = val;
this.save();
- }.bind(this));
-};
-
-/**
- * Create a namespaced "sub-store" that persists data to its file
- * in a sub-folder of the same directory as the "parent" store.
- *
- * ```js
- * store.create('foo');
- * store.foo.set('a', 'b');
- * console.log(store.foo.get('a'));
- * //=> 'b'
- * ```
- * @param {String} `name` The name of the sub-store.
- * @param {Object} `options`
- * @return {Object} Returns the sub-store instance.
- * @api public
- */
-
-Store.prototype.create = function(name, options) {
- if (utils.isStore(this, name)) {
- return this[name];
}
- utils.validateName(this, name);
-
- var self = this;
- var cwd = path.join(path.dirname(this.path), this.name);
- var substore = new Store(name, { cwd: cwd });
- this[name] = substore;
-
- substore.on('set', function(key, val) {
- self.set([name, key], val);
- });
-
- return substore;
-};
-
-/**
- * Assign `value` to `key` and save to disk. Can be
- * a key-value pair or an object.
- *
- * ```js
- * // key, value
- * store.set('a', 'b');
- * //=> {a: 'b'}
- *
- * // extend the store with an object
- * store.set({a: 'b'});
- * //=> {a: 'b'}
- *
- * // extend the the given value
- * store.set('a', {b: 'c'});
- * store.set('a', {d: 'e'}, true);
- * //=> {a: {b 'c', d: 'e'}}
- *
- * // overwrite the the given value
- * store.set('a', {b: 'c'});
- * store.set('a', {d: 'e'});
- * //=> {d: 'e'}
- * ```
- * @name .set
- * @param {String} `key`
- * @param {any} `val` The value to save to `key`. Must be a valid JSON type: String, Number, Array or Object.
- * @return {Object} `Store` for chaining
- * @api public
- */
-
-/**
- * Add or append an array of unique values to the given `key`.
- *
- * ```js
- * store.union('a', ['a']);
- * store.union('a', ['b']);
- * store.union('a', ['c']);
- * store.get('a');
- * //=> ['a', 'b', 'c']
- * ```
- *
- * @param {String} `key`
- * @return {any} The array to add or append for `key`.
- * @api public
- */
-
-Store.prototype.union = function(key, val) {
- utils.union(this.cache, key, val);
- this.emit('union', key, val);
- this.save();
- return this;
-};
-
-/**
- * Get the stored `value` of `key`, or return the entire store
- * if no `key` is defined.
- *
- * ```js
- * store.set('a', {b: 'c'});
- * store.get('a');
- * //=> {b: 'c'}
- *
- * store.get();
- * //=> {b: 'c'}
- * ```
- *
- * @name .get
- * @param {String} `key`
- * @return {any} The value to store for `key`.
- * @api public
- */
-
-/**
- * Returns `true` if the specified `key` has truthy value.
- *
- * ```js
- * store.set('a', 'b');
- * store.set('c', null);
- * store.has('a'); //=> true
- * store.has('c'); //=> false
- * store.has('d'); //=> false
- * ```
- * @name .has
- * @param {String} `key`
- * @return {Boolean} Returns true if `key` has
- * @api public
- */
+ get data() {
+ return this._data || (this._data = this.load());
+ }
-/**
- * Returns `true` if the specified `key` exists.
- *
- * ```js
- * store.set('a', 'b');
- * store.set('b', false);
- * store.set('c', null);
- * store.set('d', true);
- *
- * store.hasOwn('a'); //=> true
- * store.hasOwn('b'); //=> true
- * store.hasOwn('c'); //=> true
- * store.hasOwn('d'); //=> true
- * store.hasOwn('foo'); //=> false
- * ```
- *
- * @param {String} `key`
- * @return {Boolean} Returns true if `key` exists
- * @api public
- */
+ /**
+ * Assign `value` to `key` and save to disk. Can be
+ * a key-value pair or an object.
+ *
+ * ```js
+ * // key, value
+ * store.set('a', 'b');
+ * //=> {a: 'b'}
+ *
+ * // extend the store with an object
+ * store.set({a: 'b'});
+ * //=> {a: 'b'}
+ * ```
+ * @name .set
+ * @param {String} `key`
+ * @param {any} `val` The value to save to `key`. Must be a valid JSON type: String, Number, Array or Object.
+ * @return {Object} `Store` for chaining
+ * @api public
+ */
+
+ set(key, val) {
+ if (typeof key !== 'string') {
+ for (const k of Array.isArray(key) ? key : Object.keys(key)) {
+ this.set(k, key[k]);
+ }
+ return this;
+ }
+ assert.equal(typeof key, 'string', 'expected key to be a string');
+ set(this.data, key, val);
+ this.emit('set', key, val);
+ this.save();
+ return this;
+ }
-Store.prototype.hasOwn = function(key) {
- var val;
- if (key.indexOf('.') === -1) {
- val = this.cache.hasOwnProperty(key);
- } else {
- val = utils.hasOwn(this.cache, key);
+ /**
+ * Get the stored `value` of `key`, or return the entire store
+ * if no `key` is defined.
+ *
+ * ```js
+ * store.set('a', {b: 'c'});
+ * store.get('a');
+ * //=> {b: 'c'}
+ *
+ * store.get();
+ * //=> {b: 'c'}
+ * ```
+ * @name .union
+ * @param {String} `key`
+ * @return {any} The value to store for `key`.
+ * @api public
+ */
+
+ union(key, ...rest) {
+ assert.equal(typeof key, 'string', 'expected key to be a string');
+ let arr = this.get(key);
+ if (arr == null) arr = [];
+ if (!Array.isArray(arr)) arr = [arr];
+ this.set(key, unique(flatten(...arr, ...rest)));
+ return this;
}
- return val;
-};
-/**
- * Persist the store to disk.
- *
- * ```js
- * store.save();
- * ```
- * @param {String} `dest` Optionally define an alternate destination file path.
- * @api public
- */
+ /**
+ * Get the stored `value` of `key`, or return the entire store
+ * if no `key` is defined.
+ *
+ * ```js
+ * store.set('a', {b: 'c'});
+ * store.get('a');
+ * //=> {b: 'c'}
+ *
+ * store.get();
+ * //=> {b: 'c'}
+ * ```
+ *
+ * @name .get
+ * @param {String} `key`
+ * @return {any} The value to store for `key`.
+ * @api public
+ */
+
+ get(key) {
+ return key ? get(this.data, key) : this.data;
+ }
-Store.prototype.save = function(dest) {
- this.data = this.cache;
- writeJson(dest || this.path, this.cache, this.options.indent);
- return this;
-};
+ /**
+ * Returns `true` if the specified `key` has a value.
+ *
+ * ```js
+ * store.set('a', 'b');
+ * store.set('c', null);
+ * store.has('a'); //=> true
+ * store.has('c'); //=> false
+ * store.has('d'); //=> false
+ * ```
+ * @name .has
+ * @param {String} `key`
+ * @return {Boolean} Returns true if `key` has
+ * @api public
+ */
+
+ has(key) {
+ assert.equal(typeof key, 'string', 'expected key to be a string');
+ return typeof get(this.data, key) !== 'undefined';
+ }
-/**
- * Clear in-memory cache.
- *
- * ```js
- * store.clear();
- * ```
- * @api public
- */
+ /**
+ * Returns `true` if the specified `key` exists.
+ *
+ * ```js
+ * store.set('a', 'b');
+ * store.set('b', false);
+ * store.set('c', null);
+ * store.set('d', true);
+ *
+ * store.hasOwn('a'); //=> true
+ * store.hasOwn('b'); //=> true
+ * store.hasOwn('c'); //=> true
+ * store.hasOwn('d'); //=> true
+ * store.hasOwn('foo'); //=> false
+ * ```
+ *
+ * @param {String} `key`
+ * @return {Boolean} Returns true if `key` exists
+ * @api public
+ */
+
+ hasOwn(key) {
+ assert.equal(typeof key, 'string', 'expected key to be a string');
+ return hasOwn(this.data, key);
+ }
-Store.prototype.clear = function() {
- this.cache = {};
- this.data = {};
- return this;
-};
+ /**
+ * Delete `keys` from the store, or delete the entire store
+ * if no keys are passed. A `del` event is also emitted for each key
+ * deleted.
+ *
+ * **Note that to delete the entire store you must pass `{force: true}`**
+ *
+ * ```js
+ * store.del();
+ *
+ * // to delete paths outside cwd
+ * store.del({force: true});
+ * ```
+ *
+ * @param {String|Array|Object} `keys` Keys to remove, or options.
+ * @param {Object} `options`
+ * @api public
+ */
+
+ del(key) {
+ if (!key) key = this.keys;
+ if (Array.isArray(key)) {
+ for (const k of key) this.del(k);
+ return this;
+ }
+ assert.equal(typeof key, 'string', 'expected key to be a string');
+ delete this.data[key];
+ this.emit('del', key);
+ this.save();
+ return this;
+ }
-/**
- * Delete `keys` from the store, or delete the entire store
- * if no keys are passed. A `del` event is also emitted for each key
- * deleted.
- *
- * **Note that to delete the entire store you must pass `{force: true}`**
- *
- * ```js
- * store.del();
- *
- * // to delete paths outside cwd
- * store.del({force: true});
- * ```
- *
- * @param {String|Array|Object} `keys` Keys to remove, or options.
- * @param {Object} `options`
- * @api public
- */
+ /**
+ * Stringify the store
+ */
-Store.prototype.del = function(keys, options) {
- var isArray = Array.isArray(keys);
- if (typeof keys === 'string' || isArray) {
- keys = utils.arrayify(keys);
- } else {
- options = keys;
- keys = null;
+ json(replacer = null, space = this.indent) {
+ return JSON.stringify(this.data, replacer, space);
}
- options = options || {};
-
- if (keys) {
- keys.forEach(function(key) {
- proto.del.call(this, key);
- }.bind(this));
- this.save();
+ /**
+ * Persist the store to the file system.
+ *
+ * ```js
+ * store.save();
+ * ```
+ * @api public
+ */
+
+ save() {
+ mkdirSync(path.dirname(this.path), this.options.mkdir);
+ fs.writeFileSync(this.path, this.json(), { mode: 0o0600 });
return this;
}
- if (options.force !== true) {
- throw new Error('options.force is required to delete the entire cache.');
+ /**
+ * Load the store.
+ * @return {Object}
+ */
+
+ load() {
+ try {
+ return JSON.parse(fs.readFileSync(this.path));
+ } catch (err) {
+ if (err.code === 'EACCES') {
+ err.message += '\ndata-store does not have permission to load this file\n';
+ throw err;
+ }
+ if (err.code === 'ENOENT' || err.name === 'SyntaxError') {
+ this.data = {};
+ return {};
+ }
+ }
}
- keys = Object.keys(this.cache);
- this.clear();
-
- // if no keys are passed, delete the entire store
- utils.del.sync(this.path, options);
- keys.forEach(function(key) {
- this.emit('del', key);
- }.bind(this));
- return this;
-};
+ get keys() {
+ return Object.keys(this.data);
+ }
+}
/**
- * Returns an array of all Store properties.
+ * Create a directory and any intermediate directories that might exist.
*/
-utils.define(Store.prototype, 'keys', {
- configurable: true,
- enumerable: true,
- set: function(keys) {
- utils.define(this, 'keys', keys);
- },
- get: function fn() {
- if (fn.keys) return fn.keys;
- fn.keys = [];
- for (var key in this) fn.keys.push(key);
- return fn.keys;
+function mkdirSync(dirname, options = {}) {
+ assert.equal(typeof dirname, 'string', 'expected a string');
+ const opts = Object.assign({ cwd: process.cwd() }, options);
+ const segs = path.relative(opts.cwd, dirname).split(path.sep);
+ for (let i = 0; i <= segs.length; i++) {
+ try {
+ fs.mkdirSync(path.join(opts.cwd, ...segs.slice(0, i)), mode(opts));
+ } catch (err) {
+ if (err.code !== 'EEXIST') {
+ throw err;
+ }
+ }
}
-});
-
-/**
- * Define a non-enumerable property on the instance.
- *
- * @param {String} `key`
- * @param {any} `value`
- * @return {Object} Returns the instance for chaining.
- * @api public
- */
+ return dirname;
+}
-Store.prototype.define = function(key, value) {
- utils.define(this, key, value);
- return this;
-};
+function get(obj = {}, prop = '') {
+ return obj[prop] || split(prop).reduce((acc, k) => acc && acc[strip(k)], obj);
+}
-/**
- * Read JSON files.
- *
- * @param {String} `fp`
- * @return {Object}
- */
+function set(obj = {}, prop = '', val) {
+ return split(prop).reduce((acc, k, i, arr) => {
+ return (acc[k] = arr.length - 1 > i ? (acc[k] || {}) : val);
+ }, obj);
+}
-Store.prototype.readFile = function(filepath) {
- try {
- var str = utils.fs.readFileSync(path.resolve(filepath), 'utf8');
- this.loadedConfig = true;
- return JSON.parse(str);
- } catch (err) {}
- this.loadedConfig = false;
- return {};
-};
+function hasOwn(obj = {}, prop = '') {
+ if (!prop) return false;
+ if (obj.hasOwnProperty(prop)) return true;
+ if (prop.indexOf('.') === -1) {
+ return obj.hasOwnProperty(prop);
+ }
+ const segs = split(prop);
+ const last = segs.pop();
+ const val = get(obj, segs.join('.'));
+ if (val && typeof val === 'object') {
+ return val.hasOwnProperty(last);
+ }
+ return false;
+}
/**
- * Synchronously write files to disk, also creating any
- * intermediary directories if they don't exist.
- *
- * @param {String} `dest`
- * @param {String} `str`
- * @param {Number} `indent` Indent passed to JSON.stringify (default 2)
+ * Expose `Store`
*/
-function writeJson(dest, str, indent) {
- if (typeof indent === 'undefined' || indent === null) {
- indent = 2;
- }
- var dir = path.dirname(dest);
- try {
- if (!utils.fs.existsSync(dir)) {
- utils.mkdirp.sync(dir);
- }
- utils.fs.writeFileSync(dest, JSON.stringify(str, null, indent));
- } catch (err) {
- err.origin = __filename;
- err.reason = 'data-store cannot write to: ' + dest;
- throw new Error(err);
- }
-}
+module.exports = Store;
diff --git a/package.json b/package.json
index 1b2ca06..b389c6d 100644
--- a/package.json
+++ b/package.json
@@ -6,8 +6,9 @@
"author": "Jon Schlinkert (https://github.com/jonschlinkert)",
"contributors": [
"Brian Woodward (https://twitter.com/doowb)",
- "Charlike Mike Reagent (https://i.am.charlike.online)",
- "Jon Schlinkert (http://twitter.com/jonschlinkert)"
+ "Jamen Marz (jamenmarz.com)",
+ "Jon Schlinkert (http://twitter.com/jonschlinkert)",
+ "Olsten Larck (https://i.am.charlike.online)"
],
"repository": "jonschlinkert/data-store",
"bugs": {
@@ -15,38 +16,19 @@
},
"license": "MIT",
"files": [
- "index.js",
- "utils.js"
+ "index.js"
],
"main": "index.js",
"engines": {
- "node": ">=0.10.0"
+ "node": ">=4"
},
"scripts": {
"test": "mocha"
},
- "dependencies": {
- "cache-base": "^1.0.0",
- "clone-deep": "^0.3.0",
- "debug": "^2.6.8",
- "define-property": "^1.0.0",
- "extend-shallow": "^2.0.1",
- "graceful-fs": "^4.1.11",
- "has-own-deep": "^0.1.4",
- "lazy-cache": "^2.0.2",
- "mkdirp": "^0.5.1",
- "project-name": "^0.2.6",
- "resolve-dir": "^1.0.0",
- "rimraf": "^2.6.1",
- "union-value": "^1.0.0"
- },
"devDependencies": {
- "gulp": "^3.9.1",
- "gulp-eslint": "^3.0.1",
- "gulp-format-md": "^0.1.12",
- "gulp-istanbul": "^1.1.1",
- "gulp-mocha": "^3.0.1",
- "mocha": "^3.4.1"
+ "delete": "^1.1.0",
+ "gulp-format-md": "^1.0.0",
+ "mocha": "^3.5.3"
},
"keywords": [
"app",
@@ -83,16 +65,14 @@
"gulp-format-md"
],
"related": {
- "highlight": "base-store",
"list": [
- "base-store",
+ "base",
"cache-base",
"get-value",
+ "has-value",
"set-value"
]
},
- "reflinks": [
- ],
"lint": {
"reflinks": true
}
diff --git a/test.js b/test/test.js
similarity index 58%
rename from test.js
rename to test/test.js
index cd174d2..2153338 100644
--- a/test.js
+++ b/test/test.js
@@ -1,28 +1,22 @@
-/*!
- * data-store
- *
- * Copyright (c) 2014-2015, Jon Schlinkert.
- * Licensed under the MIT License.
- */
-
'use strict';
require('mocha');
-var fs = require('fs');
-var path = require('path');
-var assert = require('assert');
-var utils = require('./utils');
-var Store = require('./');
-var store;
+const fs = require('fs');
+const path = require('path');
+const del = require('delete');
+const assert = require('assert');
+const Store = require('..');
+const tests = (...args) => path.resolve(__dirname, ...args);
+let store;
describe('store', function() {
beforeEach(function() {
- store = new Store('abc');
+ store = new Store('abc', { base: tests() });
});
afterEach(function() {
store.data = {};
- store.del({force: true});
+ return del(tests('actual'));
});
describe('create', function() {
@@ -36,64 +30,26 @@ describe('store', function() {
assert.equal(store.data.foo, 'bar');
});
- it('should return an instance without `new`:', function() {
- store = Store('abc');
- store.set('foo', 'zzz');
- assert(store.data.hasOwnProperty('foo'));
- assert.equal(store.data.foo, 'zzz');
- });
+ // it.only('should create a store at the given `base`', function() {
+ // store = new Store('abc', { base: tests('actual') });
- it('should create a store at the given `cwd`', function() {
- store = new Store('abc', {cwd: 'actual'});
-
- store.set('foo', 'bar');
- assert.equal(path.basename(store.path), 'abc.json');
- assert(store.data.hasOwnProperty('foo'));
- assert.equal(store.data.foo, 'bar');
- assert.equal(fs.existsSync(path.join(__dirname, 'actual/abc.json')), true);
- });
+ // store.set('foo', 'bar');
+ // assert.equal(path.basename(store.path), 'abc.json');
+ // assert.equal(store.path, tests('actual/abc.json'));
+ // assert(store.data.hasOwnProperty('foo'));
+ // assert.equal(store.data.foo, 'bar');
+ // console.log(store.path)
+ // assert.equal(fs.existsSync(tests('actual/abc.json')), true);
+ // });
it('should create a store using the given `indent` value', function() {
- store = new Store('abc', {cwd: 'actual', indent: 0});
+ store = new Store('abc', { base: tests('actual'), indent: 0 });
store.set('foo', 'bar');
- var contents = fs.readFileSync(path.join(__dirname, 'actual/abc.json'), 'utf8');
+ const contents = fs.readFileSync(store.path, 'utf8');
assert.equal(contents, '{"foo":"bar"}');
});
});
- describe('sub-store', function() {
- it('should create a "sub-store" with the given name', function() {
- var created = store.create('created');
- assert.equal(created.name, 'created');
- });
-
- it('should create a "sub-store" with the project name when no name is passed', function() {
- var foo = store.create();
- assert.equal(foo.name, 'data-store');
- });
-
- it('should set values on a sub-store', function() {
- var foo = store.create('created');
- foo.set('one', 'two');
- assert.equal(foo.get('one'), 'two');
- });
-
- it('should expose sub-store data on parent store', function() {
- var foo = store.create('created');
- foo.set('one', 'two');
- assert.equal(foo.get('one'), 'two');
-
- assert.equal(store.get('created.one'), 'two');
- });
-
- it('should work with dots', function() {
- var foo = store.create('one.two');
- foo.set('a', 'b');
- assert.equal(foo.get('a'), 'b');
- assert.equal(store.get('one.two.a'), 'b');
- });
- });
-
describe('set', function() {
it('should `.set()` a value on the store', function() {
store.set('one', 'two');
@@ -101,21 +57,21 @@ describe('store', function() {
});
it('should `.set()` an object', function() {
- store.set({four: 'five', six: 'seven'});
+ store.set({ four: 'five', six: 'seven' });
assert.equal(store.data.four, 'five');
assert.equal(store.data.six, 'seven');
});
it('should `.set()` a nested value', function() {
- store.set('a.b.c.d', {e: 'f'});
+ store.set('a.b.c.d', { e: 'f' });
assert.equal(store.data.a.b.c.d.e, 'f');
});
- it('should not save data that is added directly to `storedata`', function() {
+ it('should save data that is added directly to `storedata`', function() {
store.data.foo = 'bar';
- store.set('a.b.c.d', {e: 'f'});
+ store.set('a.b.c.d', { e: 'f' });
assert.equal(store.data.a.b.c.d.e, 'f');
- assert.equal(typeof store.data.foo, 'undefined');
+ assert.equal(store.data.foo, 'bar');
});
});
@@ -158,9 +114,9 @@ describe('store', function() {
});
it('should return true if a nested key `.has()` on the store', function() {
- store.set('a.b.c.d', {x: 'zzz'});
- store.set('a.b.c.e', {f: null});
- store.set('a.b.g.j', {k: undefined});
+ store.set('a.b.c.d', { x: 'zzz' });
+ store.set('a.b.c.e', { f: null });
+ store.set('a.b.g.j', { k: undefined });
assert(store.has('a.b.c.d'));
assert(store.has('a.b.c.d.x'));
@@ -176,8 +132,8 @@ describe('store', function() {
});
});
- describe('hasOwn', function() {
- it('should return true if a key exists `.hasOwn()` on the store', function() {
+ describe('hasOwn', function() {
+ it('should return true if a key exists on the store', function() {
store.set('foo', 'bar');
store.set('baz', null);
store.set('qux', undefined);
@@ -188,10 +144,25 @@ describe('store', function() {
assert(store.hasOwn('qux'));
});
+ it('should work with escaped keys', function() {
+ store.set('foo\\.baz', 'bar');
+ store.set('baz', null);
+ store.set('qux', undefined);
+
+ assert(!store.hasOwn('foo'));
+ assert(!store.hasOwn('bar'));
+ assert(store.hasOwn('foo.baz'));
+ assert(store.hasOwn('baz'));
+ assert(store.hasOwn('qux'));
+
+ store.set('foo\\.bar.baz\\.qux', 'fez');
+ assert(store.hasOwn('foo\\.bar.baz\\.qux'));
+ });
+
it('should return true if a nested key exists `.hasOwn()` on the store', function() {
- store.set('a.b.c.d', {x: 'zzz'});
- store.set('a.b.c.e', {f: null});
- store.set('a.b.g.j', {k: undefined});
+ store.set('a.b.c.d', { x: 'zzz' });
+ store.set('a.b.c.e', { f: null });
+ store.set('a.b.g.j', { k: undefined });
assert(store.hasOwn('a.b.c.d'));
assert(store.hasOwn('a.b.c.d.x'));
@@ -214,7 +185,7 @@ describe('store', function() {
});
it('should `.get()` a nested value', function() {
- store.set({a: {b: {c: 'd'}}});
+ store.set({ a: { b: { c: 'd' } } });
assert.equal(store.get('a.b.c'), 'd');
});
});
@@ -235,11 +206,11 @@ describe('store', function() {
assert(!store.data.hasOwnProperty('c'));
});
- it('should `.del()` multiple stored values', function() {
+ it('should delete multiple stored values', function() {
store.set('a', 'b');
store.set('c', 'd');
store.set('e', 'f');
- store.del(['a', 'c', 'e']);
+ ['a', 'c', 'e'].forEach(v => store.del(v));
assert.deepEqual(store.data, {});
});
});
@@ -252,22 +223,21 @@ describe('events', function() {
afterEach(function() {
store.data = {};
- store.del({force: true});
});
describe('set', function() {
it('should emit `set` when an object is set:', function() {
- var keys = [];
+ const keys = [];
store.on('set', function(key) {
keys.push(key);
});
- store.set({a: {b: {c: 'd'}}});
+ store.set({ a: { b: { c: 'd' } } });
assert.deepEqual(keys, ['a']);
});
it('should emit `set` when a key/value pair is set:', function() {
- var keys = [];
+ const keys = [];
store.on('set', function(key) {
keys.push(key);
@@ -278,83 +248,54 @@ describe('events', function() {
});
it('should emit `set` when an object value is set:', function() {
- var keys = [];
+ const keys = [];
store.on('set', function(key) {
keys.push(key);
});
- store.set('a', {b: 'c'});
+ store.set('a', { b: 'c' });
assert.deepEqual(keys, ['a']);
});
it('should emit `set` when an array of objects is passed:', function() {
- var keys = [];
+ const keys = [];
store.on('set', function(key) {
keys.push(key);
});
- store.set([{a: 'b'}, {c: 'd'}]);
+ store.set([{ a: 'b' }, { c: 'd' }]);
assert.deepEqual(keys, ['a', 'c']);
});
});
- describe('has', function() {
- it('should emit `has`:', function(done) {
- var keys = [];
-
- store.on('has', function(val) {
- assert(val);
- done();
- });
-
- store.set('a', 'b');
- store.has('a');
- });
- });
-
describe('del', function() {
- it('should emit `del` when a value is delted:', function(done) {
+ it('should emit `del` when a value is delted:', function(cb) {
store.on('del', function(keys) {
assert.deepEqual(keys, 'a');
- assert(typeof store.get('a') === 'undefined');
- done();
+ assert.equal(typeof store.get('a'), 'undefined');
+ cb();
});
- store.set('a', {b: 'c'});
- assert.deepEqual(store.get('a'), {b: 'c'});
+ store.set('a', { b: 'c' });
+ assert.deepEqual(store.get('a'), { b: 'c' });
store.del('a');
});
- it('should emit deleted keys on `del`:', function(done) {
- var arr = [];
-
- store.on('del', function(key) {
- arr.push(key);
- assert(Object.keys(store.data).length === 0);
- });
+ it('should emit deleted keys on `del`:', function(cb) {
+ const arr = [];
+ store.on('del', key => arr.push(key));
store.set('a', 'b');
store.set('c', 'd');
store.set('e', 'f');
- store.del({force: true});
- assert.deepEqual(arr, ['a', 'c', 'e']);
- done();
- });
- it('should throw an error if force is not passed', function(cb) {
- store.set('a', 'b');
- store.set('c', 'd');
- store.set('e', 'f');
+ store.del();
- try {
- store.del();
- cb(new Error('expected an error'));
- } catch (err) {
- assert.equal(err.message, 'options.force is required to delete the entire cache.');
- cb();
- }
+ assert.deepEqual(arr, ['a', 'c', 'e']);
+ assert.equal(Object.keys(store.data).length, 0);
+ cb();
});
});
});
diff --git a/utils.js b/utils.js
deleted file mode 100644
index fb5277f..0000000
--- a/utils.js
+++ /dev/null
@@ -1,71 +0,0 @@
-'use strict';
-
-var utils = module.exports = require('lazy-cache')(require);
-var fn = require;
-require = utils; // eslint-disable-line
-
-/**
- * Utils
- */
-
-require('clone-deep', 'clone');
-require('extend-shallow', 'extend');
-require('define-property', 'define');
-require('graceful-fs', 'fs');
-require('has-own-deep', 'hasOwn');
-require('mkdirp', 'mkdirp');
-require('project-name', 'project');
-require('resolve-dir', 'resolve');
-require('rimraf', 'del');
-require('union-value', 'union');
-require = fn; // eslint-disable-line
-
-utils.noop = function() {
- return;
-};
-
-utils.last = function(arr) {
- return arr[arr.length - 1];
-};
-
-utils.arrayify = function(val) {
- return val ? (Array.isArray(val) ? val : [val]) : [];
-};
-
-/**
- * Throw an error if sub-store `name` is already a key on `store`.
- *
- * @param {Object} `store`
- * @param {String} `name`
- */
-
-utils.validateName = function(store, name) {
- if (~store.keys.indexOf(name) && !utils.isStore(store, name)) {
- throw utils.formatConflictError(name);
- }
-};
-
-/**
- * Return true if `name` is a store object.
- */
-
-utils.isStore = function(store, name) {
- return !!store[name]
- && (typeof store[name] === 'object')
- && store[name].isStore === true;
-};
-
-/**
- * Format the error used when sub-store `name` is
- * invalid.
- *
- * @param {String} `name`
- */
-
-utils.formatConflictError = function(name) {
- var msg = 'Cannot create store: '
- + '"' + name + '", since '
- + '"' + name + '" is a reserved property key. '
- + 'Please choose a different store name.';
- return new Error(msg);
-};