Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

data-store

Package Overview
Dependencies
Maintainers
1
Versions
45
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

data-store - npm Package Compare versions

Comparing version 1.0.0 to 2.0.0

CHANGELOG.md

766

index.js
'use strict';
/**
* Module dependencies
*/
const fs = require('fs');
const os = require('os');
const path = require('path');
const assert = require('assert');
const flatten = (...args) => [].concat.apply([], args);
const unique = arr => arr.filter((v, i) => arr.indexOf(v) === i);
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;
/**
* Initialize a new `Store` with the given `name`
* and `options`.
* Initialize a new `Store` with the given `name`, `options` and `default` data.
*
* ```js
* var store = require('data-store')('abc');
* const store = require('data-store')('abc');
* //=> '~/data-store/a.json'
*
* var store = require('data-store')('abc', {
* cwd: 'test/fixtures'
* });
* const store = require('data-store')('abc', { cwd: 'test/fixtures' });
* //=> './test/fixtures/abc.json'
* ```
*
* @param {String} `name` Store name to use for the basename of the `.json` file.
* @param {Object} `options`
* @param {String} `options.cwd` Current working directory for storage. If not defined, the user home directory is used, based on OS. This is the only option currently, other may be added in the future.
* @param {Number} `options.indent` Number passed to `JSON.stringify` when saving the data. Defaults to `2` if `null` or `undefined`
* @name Store
* @param {string} `name` Store name to use for the basename of the `.json` file.
* @param {object} `options` See all [available options](#options).
* @param {object} `defaults` An object to initialize the store with.
* @api public
*/
function Store(name, options) {
if (!(this instanceof Store)) {
return new Store(name, options);
class Store {
constructor(name, options = {}, defaults = {}) {
if (typeof name !== 'string') {
defaults = options;
options = name || {};
name = options.name;
}
assert.equal(typeof name, 'string', 'expected store name to be a string');
const { debounce = 5, indent = 2, home, base } = options;
this.name = name;
this.options = options;
this.defaults = defaults || options.default;
this.indent = indent;
this.debounce = debounce;
this.home = home || process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config');
this.base = base || path.join(this.home, 'data-store');
this.path = this.options.path || path.join(this.base, this.name + '.json');
this._data = null;
}
if (typeof name !== 'string') {
options = name;
name = null;
/**
* Assign `value` to `key` and save to the file system. Can be a key-value pair,
* array of objects, 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 (isObject(key)) {
Object.assign(this.data, key);
} else {
assert.equal(typeof key, 'string', 'expected key to be a string');
set(this.data, key, val);
}
this.save();
return this;
}
Base.call(this);
this.isStore = true;
this.options = options || {};
this.initStore(name);
}
/**
* Add the given `value` to the array at `key`. Creates a new array if one
* doesn't exist, and only adds unique values to the array.
*
* ```js
* store.union('a', 'b');
* store.union('a', 'c');
* store.union('a', 'd');
* store.union('a', 'c');
* console.log(store.get('a'));
* //=> ['b', 'c', 'd']
* ```
* @name .union
* @param {string} `key`
* @param {any} `val` The value to union to `key`. Must be a valid JSON type: String, Number, Array or Object.
* @return {object} `Store` for chaining
* @api public
*/
/**
* Inherit `Base`
*/
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;
}
util.inherits(Store, Base);
/**
* Get the stored `value` of `key`.
*
* ```js
* store.set('a', {b: 'c'});
* store.get('a');
* //=> {b: 'c'}
*
* store.get();
* //=> {a: {b: 'c'}}
* ```
* @name .get
* @param {string} `key`
* @return {any} The value to store for `key`.
* @api public
*/
/**
* Initialize store defaults
*/
get(key) {
assert.equal(typeof key, 'string', 'expected key to be a string');
return get(this.data, key);
}
Store.prototype.initStore = function(name) {
this.name = name || utils.project(process.cwd());
this.cwd = utils.resolve(this.options.cwd || '~/.data-store');
this.path = this.options.path || path.resolve(this.cwd, this.name + '.json');
this.relative = path.relative(process.cwd(), this.path);
/**
* Returns `true` if the specified `key` has a value.
*
* ```js
* store.set('a', 42);
* store.set('c', null);
*
* store.has('a'); //=> true
* store.has('c'); //=> true
* store.has('d'); //=> false
* ```
* @name .has
* @param {string} `key`
* @return {boolean} Returns true if `key` has
* @api public
*/
debug('Initializing store <%s>', this.path);
has(key) {
assert.equal(typeof key, 'string', 'expected key to be a string');
return typeof get(this.data, key) !== 'undefined';
}
this.data = this.readFile(this.path);
this.define('cache', utils.clone(this.data));
this.on('set', function() {
this.save();
}.bind(this));
};
/**
* 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.set('e', undefined);
*
* store.hasOwn('a'); //=> true
* store.hasOwn('b'); //=> true
* store.hasOwn('c'); //=> true
* store.hasOwn('d'); //=> true
* store.hasOwn('e'); //=> true
* store.hasOwn('foo'); //=> false
* ```
* @name .hasOwn
* @param {string} `key`
* @return {boolean} Returns true if `key` exists
* @api public
*/
/**
* 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];
hasOwn(key) {
assert.equal(typeof key, 'string', 'expected key to be a string');
return hasOwn(this.data, key);
}
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;
/**
* Delete one or more properties from the store.
*
* ```js
* store.set('foo.bar', 'baz');
* console.log(store.data); //=> { foo: { bar: 'baz' } }
* store.del('foo.bar');
* console.log(store.data); //=> { foo: {} }
* store.del('foo');
* console.log(store.data); //=> {}
* ```
* @name .del
* @param {string|Array} `keys` One or more properties to delete.
* @api public
*/
substore.on('set', function(key, val) {
self.set([name, key], val);
});
del(key) {
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');
if (del(this.data, key)) {
this.save();
}
return this;
}
return substore;
};
/**
* Return a clone of the `store.data` object.
*
* ```js
* console.log(store.clone());
* ```
* @name .clone
* @return {object}
* @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'}
*
* // 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
*/
clone() {
return cloneDeep(this.data);
}
/**
* 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
*/
/**
* Reset `store.data` to an empty object.
*
* ```js
* store.clear();
* ```
* @name .clear
* @return {undefined}
* @api public
*/
Store.prototype.union = function(key, val) {
utils.union(this.cache, key, val);
this.emit('union', key, val);
this.save();
return this;
};
clear() {
this.data = {};
}
/**
* 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
*/
/**
* Stringify the store. Takes the same arguments as `JSON.stringify`.
*
* ```js
* console.log(store.json(null, 2));
* ```
* @name .json
* @return {string}
* @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
*/
json(replacer = null, space = this.indent) {
return JSON.stringify(this.data, replacer, space);
}
/**
* 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
*/
/**
* Calls [.writeFile()](#writefile) to persist the store to the file system,
* after an optional [debounce](#options) period. This method should probably
* not be called directly as it's used internally by other methods.
*
* ```js
* store.save();
* ```
* @name .save
* @return {undefined}
* @api public
*/
Store.prototype.hasOwn = function(key) {
var val;
if (key.indexOf('.') === -1) {
val = this.cache.hasOwnProperty(key);
} else {
val = utils.hasOwn(this.cache, key);
save() {
if (!this.debounce) return this.writeFile();
if (this.save.debounce) return;
this.save.debounce = setTimeout(() => this.writeFile(), this.debounce);
}
return val;
};
/**
* Persist the store to disk.
*
* ```js
* store.save();
* ```
* @param {String} `dest` Optionally define an alternate destination file path.
* @api public
*/
/**
* Delete the store from the file system.
*
* ```js
* store.unlink();
* ```
* @name .unlink
* @return {undefined}
* @api public
*/
Store.prototype.save = function(dest) {
this.data = this.cache;
writeJson(dest || this.path, this.cache, this.options.indent);
return this;
};
unlink() {
let wait = 0;
/**
* Clear in-memory cache.
*
* ```js
* store.clear();
* ```
* @api public
*/
if (this.unlink.clear) this.unlink.clear();
Store.prototype.clear = function() {
this.cache = {};
this.data = {};
return this;
};
const debounce = () => {
const timeout = setTimeout(() => {
if (this.save.debounce) {
debounce();
} else {
this.deleteFile();
}
}, wait++);
return () => clearTimeout(timeout);
};
/**
* 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
*/
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;
this.unlink.clear = debounce();
}
options = options || {};
/**
* Immediately write the store to the file system. This method should probably
* not be called directly. Unless you are familiar with the inner workings of
* the code it's recommended that you use .save() instead.
*
* ```js
* store.writeFile();
* ```
* @name .writeFile
* @return {undefined}
*/
if (keys) {
keys.forEach(function(key) {
proto.del.call(this, key);
}.bind(this));
this.save();
return this;
writeFile() {
if (this.save.debounce) {
clearTimeout(this.save.debounce);
this.save.debounce = null;
}
if (!this.saved) mkdir(path.dirname(this.path), this.options.mkdir);
this.saved = true;
fs.writeFileSync(this.path, this.json(), { mode: 0o0600 });
}
if (options.force !== true) {
throw new Error('options.force is required to delete the entire cache.');
/**
* Immediately delete the store from the file system. This method should probably
* not be called directly. Unless you are familiar with the inner workings of
* the code, it's recommended that you use .unlink() instead.
*
* ```js
* store.deleteFile();
* ```
* @name .deleteFile
* @return {undefined}
*/
deleteFile() {
if (this.unlink.clear) this.unlink.clear();
tryUnlink(this.path);
}
keys = Object.keys(this.cache);
this.clear();
/**
* Load the store.
* @return {object}
*/
// 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;
};
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 {};
}
}
}
/**
* Returns an array of all Store properties.
*/
/**
* Getter/setter for the `store.data` object, which holds the values
* that are persisted to the file system.
*
* ```js
* console.log(store.data); //=> {}
* store.data.foo = 'bar';
* console.log(store.get('foo')); //=> 'bar'
* ```
* @name .data
* @return {object}
*/
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;
set data(val) {
this._data = val;
this.save();
}
});
get data() {
this._data = this._data || this.load();
if (!this.saved) {
this._data = Object.assign({}, this.defaults, this._data);
}
return this._data;
}
}
/**
* Define a non-enumerable property on the instance.
*
* @param {String} `key`
* @param {any} `value`
* @return {Object} Returns the instance for chaining.
* @api public
* Utils
*/
Store.prototype.define = function(key, value) {
utils.define(this, key, value);
return this;
};
const mode = opts => opts.mode || 0o777 & ~process.umask();
const strip = str => str.replace(/\\(?=\.)/g, '');
const split = str => str.split(/(?<!\\)\./).map(strip);
/**
* Read JSON files.
*
* @param {String} `fp`
* @return {Object}
* Create a directory and any intermediate directories that might exist.
*/
Store.prototype.readFile = function(filepath) {
function mkdir(dirname, options = {}) {
assert.equal(typeof dirname, 'string', 'expected dirname to be a string');
const opts = Object.assign({ cwd: process.cwd(), fs }, options);
const segs = path.relative(opts.cwd, dirname).split(path.sep);
const make = dir => fs.mkdirSync(dir, mode(opts));
for (let i = 0; i <= segs.length; i++) {
try {
make((dirname = path.join(opts.cwd, ...segs.slice(0, i))));
} catch (err) {
handleError(dirname, opts)(err);
}
}
return dirname;
}
function handleError(dir, opts = {}) {
return (err) => {
if (err.code !== 'EEXIST' || path.dirname(dir) === dir || !opts.fs.statSync(dir).isDirectory()) {
throw err;
}
};
}
function tryUnlink(filepath) {
try {
var str = utils.fs.readFileSync(path.resolve(filepath), 'utf8');
this.loadedConfig = true;
return JSON.parse(str);
} catch (err) {}
this.loadedConfig = false;
return {};
};
fs.unlinkSync(filepath);
} catch (err) {
if (err.code !== 'ENOENT') {
throw err;
}
}
}
function get(data = {}, prop = '') {
return data[prop] == null
? split(prop).reduce((acc, k) => acc && acc[strip(k)], data)
: data[prop];
}
function set(data = {}, prop = '', val) {
return split(prop).reduce((acc, k, i, arr) => {
let value = arr.length - 1 > i ? (acc[k] || {}) : val;
if (!isObject(value) && i < arr.length - 1) value = {};
return (acc[k] = value);
}, data);
}
function del(data = {}, prop = '') {
if (!prop) return false;
if (data.hasOwnProperty(prop)) {
delete data[prop];
return true;
}
const segs = split(prop);
const last = segs.pop();
const val = segs.length ? get(data, segs.join('.')) : data;
if (isObject(val) && val.hasOwnProperty(last)) {
delete val[last];
return true;
}
}
function hasOwn(data = {}, prop = '') {
if (!prop) return false;
if (data.hasOwnProperty(prop)) return true;
if (prop.indexOf('.') === -1) return false;
const segs = split(prop);
const last = segs.pop();
const val = segs.length ? get(data, segs.join('.')) : data;
return isObject(val) && val.hasOwnProperty(last);
}
function isObject(val) {
return typeOf(val) === 'object';
}
/**
* 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)
* Deeply clone plain objects and arrays.
*/
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);
function cloneDeep(value) {
const obj = {};
switch (typeOf(value)) {
case 'object':
for (const key of Object.keys(value)) {
obj[key] = cloneDeep(value[key]);
}
return obj;
case 'array':
return value.map(ele => cloneDeep(ele));
default: {
return value;
}
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);
}
}
function typeOf(val) {
if (typeof val === 'string') return 'string';
if (Array.isArray(val)) return 'array';
if (val instanceof RegExp) {
return 'regexp';
}
if (val && typeof val === 'object') {
return 'object';
}
}
/**
* Expose `Store`
*/
module.exports = Store;
{
"name": "data-store",
"description": "Easily get, set and persist config data.",
"version": "1.0.0",
"description": "Easily persist and load config data. No dependencies.",
"version": "2.0.0",
"homepage": "https://github.com/jonschlinkert/data-store",

@@ -9,4 +9,5 @@ "author": "Jon Schlinkert (https://github.com/jonschlinkert)",

"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)"
],

@@ -19,8 +20,7 @@ "repository": "jonschlinkert/data-store",

"files": [
"index.js",
"utils.js"
"index.js"
],
"main": "index.js",
"engines": {
"node": ">=0.10.0"
"node": ">=8"
},

@@ -30,24 +30,6 @@ "scripts": {

},
"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"
},

@@ -89,12 +71,9 @@ "keywords": [

"related": {
"highlight": "base-store",
"list": [
"base-store",
"cache-base",
"get-value",
"set-value"
"has-value",
"set-value",
"write"
]
},
"reflinks": [
],
"lint": {

@@ -101,0 +80,0 @@ "reflinks": true

# data-store [![NPM version](https://img.shields.io/npm/v/data-store.svg?style=flat)](https://www.npmjs.com/package/data-store) [![NPM monthly downloads](https://img.shields.io/npm/dm/data-store.svg?style=flat)](https://npmjs.org/package/data-store) [![NPM total downloads](https://img.shields.io/npm/dt/data-store.svg?style=flat)](https://npmjs.org/package/data-store) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/data-store.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/data-store)
> Easily get, set and persist config data.
> Easily persist and load config data. No dependencies.
You might also be interested in [base-store](https://github.com/node-base/base-store).
Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.
## Table of Contents
- [Install](#install)
- [Usage example](#usage-example)
- [API](#api)
- [Options](#options)
- [About](#about)

@@ -26,11 +25,14 @@

By default a JSON file is created with the name of the store in the `~/.config/data-store/` directory. This is completely customizable via [options](#options).
```js
// default cwd is `~/data-store/` (in user-home)
var store = require('data-store')('my-app');
const Store = require('data-store');
const store = new Store({ path: 'config.json' });
store
.set('a', 'b')
.set({c: 'd'})
.set('e.f', 'g')
store.set('one', 'two');
console.log(store.data); //=> { one: 'two' }
store.set('x.y.z', 'boom!');
store.set({ c: 'd' });
console.log(store.get('e.f'));

@@ -40,6 +42,6 @@ //=> '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' } }
```

@@ -49,12 +51,11 @@

### [Store](index.js#L42)
### [Store](index.js#L27)
Initialize a new `Store` with the given `name` and `options`.
Initialize a new `Store` with the given `name`, `options` and `default` data.
**Params**
* `name` **{String}**: Store name to use for the basename of the `.json` file.
* `options` **{Object}**
* `options.cwd` **{String}**: Current working directory for storage. If not defined, the user home directory is used, based on OS. This is the only option currently, other may be added in the future.
* `options.indent` **{Number}**: Number passed to `JSON.stringify` when saving the data. Defaults to `2` if `null` or `undefined`
* `name` **{string}**: Store name to use for the basename of the `.json` file.
* `options` **{object}**: See all [available options](#options).
* `defaults` **{object}**: An object to initialize the store with.

@@ -64,39 +65,18 @@ **Example**

```js
var store = require('data-store')('abc');
const store = require('data-store')('abc');
//=> '~/data-store/a.json'
var store = require('data-store')('abc', {
cwd: 'test/fixtures'
});
const store = require('data-store')('abc', { cwd: 'test/fixtures' });
//=> './test/fixtures/abc.json'
```
### [.create](index.js#L99)
### [.set](index.js#L68)
Create a namespaced "sub-store" that persists data to its file in a sub-folder of the same directory as the "parent" store.
Assign `value` to `key` and save to the file system. Can be a key-value pair, array of objects, or an object.
**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)
Assign `value` to `key` and save to disk. Can be a key-value pair or an object.
**Params**
* `key` **{String}**
* `key` **{string}**
* `val` **{any}**: The value to save to `key`. Must be a valid JSON type: String, Number, Array or Object.
* `returns` **{Object}** `Store`: for chaining
* `returns` **{object}** `Store`: for chaining

@@ -113,22 +93,13 @@ **Example**

//=> {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#L98)
Add or append an array of unique values to the given `key`.
Add the given `value` to the array at `key`. Creates a new array if one doesn't exist, and only adds unique values to the array.
**Params**
* `key` **{String}**
* `returns` **{any}**: The array to add or append for `key`.
* `key` **{string}**
* `val` **{any}**: The value to union to `key`. Must be a valid JSON type: String, Number, Array or Object.
* `returns` **{object}** `Store`: for chaining

@@ -138,16 +109,17 @@ **Example**

```js
store.union('a', ['a']);
store.union('a', ['b']);
store.union('a', ['c']);
store.get('a');
//=> ['a', 'b', 'c']
store.union('a', 'b');
store.union('a', 'c');
store.union('a', 'd');
store.union('a', 'c');
console.log(store.get('a'));
//=> ['b', 'c', 'd']
```
### [.get](index.js#L189)
### [.get](index.js#L124)
Get the stored `value` of `key`, or return the entire store if no `key` is defined.
Get the stored `value` of `key`.
**Params**
* `key` **{String}**
* `key` **{string}**
* `returns` **{any}**: The value to store for `key`.

@@ -163,13 +135,13 @@

store.get();
//=> {b: 'c'}
//=> {a: {b: 'c'}}
```
### [.has](index.js#L205)
### [.has](index.js#L146)
Returns `true` if the specified `key` has truthy value.
Returns `true` if the specified `key` has a value.
**Params**
* `key` **{String}**
* `returns` **{Boolean}**: Returns true if `key` has
* `key` **{string}**
* `returns` **{boolean}**: Returns true if `key` has

@@ -179,10 +151,11 @@ **Example**

```js
store.set('a', 'b');
store.set('a', 42);
store.set('c', null);
store.has('a'); //=> true
store.has('c'); //=> false
store.has('c'); //=> true
store.has('d'); //=> false
```
### [.hasOwn](index.js#L226)
### [.hasOwn](index.js#L174)

@@ -193,4 +166,4 @@ Returns `true` if the specified `key` exists.

* `key` **{String}**
* `returns` **{Boolean}**: Returns true if `key` exists
* `key` **{string}**
* `returns` **{boolean}**: Returns true if `key` exists

@@ -204,2 +177,3 @@ **Example**

store.set('d', true);
store.set('e', undefined);

@@ -210,12 +184,13 @@ store.hasOwn('a'); //=> true

store.hasOwn('d'); //=> true
store.hasOwn('e'); //=> true
store.hasOwn('foo'); //=> false
```
### [.save](index.js#L246)
### [.del](index.js#L195)
Persist the store to disk.
Delete one or more properties from the store.
**Params**
* `dest` **{String}**: Optionally define an alternate destination file path.
* `keys` **{string|Array}**: One or more properties to delete.

@@ -225,68 +200,104 @@ **Example**

```js
store.save();
store.set('foo.bar', 'baz');
console.log(store.data); //=> { foo: { bar: 'baz' } }
store.del('foo.bar');
console.log(store.data); //=> { foo: {} }
store.del('foo');
console.log(store.data); //=> {}
```
### [.clear](index.js#L261)
### [.clone](index.js#L218)
Clear in-memory cache.
Return a clone of the `store.data` object.
* `returns` **{object}**
**Example**
```js
console.log(store.clone());
```
### [.clear](index.js#L233)
Reset `store.data` to an empty object.
* `returns` **{undefined}**
**Example**
```js
store.clear();
```
### [.del](index.js#L286)
### [.json](index.js#L248)
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.
Stringify the store. Takes the same arguments as `JSON.stringify`.
**Note that to delete the entire store you must pass `{force: true}`**
* `returns` **{string}**
**Params**
**Example**
* `keys` **{String|Array|Object}**: Keys to remove, or options.
* `options` **{Object}**
```js
console.log(store.json(null, 2));
```
### [.save](index.js#L265)
Calls [.writeFile()](#writefile) to persist the store to the file system, after an optional [debounce](#options) period. This method should probably not be called directly as it's used internally by other methods.
* `returns` **{undefined}**
**Example**
```js
store.del();
// to delete paths outside cwd
store.del({force: true});
store.save();
```
### [.define](index.js#L347)
### [.unlink](index.js#L282)
Define a non-enumerable property on the instance.
Delete the store from the file system.
**Params**
* `returns` **{undefined}**
* `key` **{String}**
* `value` **{any}**
* `returns` **{Object}**: Returns the instance for chaining.
**Example**
## About
```js
store.unlink();
```
### Related projects
## Options
* [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.")
| **Option** | **Type** | **Default** | **Description** |
| --- | --- | --- | --- |
| `debounce` | `number` | `undefined` | Milliseconds to delay writing the JSON file to the file system. This can make the store more performant by preventing multiple subsequent writes after calling `.set` or setting/getting `store.data`, but comes with the potential side effect that the config file will be outdated during the timeout. To get around this, use data-store's API to [(re-)load](#load) the file instead of directly reading the file (using `fs.readFile` for example). |
| `indent` | `number | null` | `2` | The indent value to pass to `JSON.stringify()` when writing the file to the fs, or when [.json()](#json) is called |
| `name` | `string` | `undefined` | The name to use for the store file stem (`name + '.json'` is the store's file name) |
| `home` | `string` | `process.env.XDG_CONFIG_HOME` or `path.join(os.homedir(), '.config')` | The root home directory to use |
| `base` | `string` | `path.join(home, 'data-store')` | The directory to use for data-store config files. This value is joined to `home` |
| `path` | `string` | `...` | Absolute file path for the data-store JSON file. This is created by joining `base` to `name + '.json'`. Setting this value directly will override the `name`, `home` and `base` values. |
### Contributing
## About
<details>
<summary><strong>Contributing</strong></summary>
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
### Contributors
</details>
| **Commits** | **Contributor** |
| --- | --- |
| 128 | [jonschlinkert](https://github.com/jonschlinkert) |
| 3 | [doowb](https://github.com/doowb) |
| 2 | [tunnckoCore](https://github.com/tunnckoCore) |
<details>
<summary><strong>Running Tests</strong></summary>
### Building docs
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:
```sh
$ npm install && npm test
```
</details>
<details>
<summary><strong>Building docs</strong></summary>
_(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.)_

@@ -300,10 +311,22 @@

### Running tests
</details>
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:
* [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.")
* [write](https://www.npmjs.com/package/write): Write data to a file, replacing the file if it already exists and creating any… [more](https://github.com/jonschlinkert/write) | [homepage](https://github.com/jonschlinkert/write "Write data to a file, replacing the file if it already exists and creating any intermediate directories if they don't already exist. Thin wrapper around node's native fs methods.")
### 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

@@ -313,8 +336,9 @@

* [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).

@@ -324,2 +348,2 @@

_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on May 22, 2017._
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on May 01, 2018._

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc