158 lines
4 KiB
JavaScript
158 lines
4 KiB
JavaScript
import set from 'lodash.set'
|
|
import unset from 'lodash.unset'
|
|
import get from 'lodash.get'
|
|
|
|
// Don't allow setting of these top-level keys in the store
|
|
const avoid = ['set', 'setIfUnset', 'push', 'unset', 'get', 'extend']
|
|
|
|
//////////////////////////////////////////////
|
|
// CONSTRUCTOR //
|
|
//////////////////////////////////////////////
|
|
|
|
/**
|
|
* Constructor for a Store
|
|
*
|
|
* @constructor
|
|
* @param {Array} methods - Any methods to add to the store
|
|
* @return {Store} this - The Store instance
|
|
*/
|
|
export function Store(methods = []) {
|
|
/*
|
|
* Default logging methods
|
|
* You can override these with a plugin
|
|
*/
|
|
const logs = {
|
|
debug: [],
|
|
info: [],
|
|
warning: [],
|
|
error: [],
|
|
}
|
|
this.log = {
|
|
debug: function (...data) {
|
|
logs.debug.push(...data)
|
|
},
|
|
info: function (...data) {
|
|
logs.info.push(...data)
|
|
},
|
|
warning: function (...data) {
|
|
logs.warning.push(...data)
|
|
},
|
|
error: function (...data) {
|
|
if (typeof window !== 'undefined') console.error(...data[0])
|
|
logs.error.push(...data)
|
|
},
|
|
}
|
|
this.logs = logs
|
|
|
|
for (const [path, method] of methods) {
|
|
if (avoid.indexOf(path) !== -1) {
|
|
this.log.warning(`You cannot overwrite \`store.${path}()\``)
|
|
} else set(this, path, method)
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
//////////////////////////////////////////////
|
|
// PUBLIC METHODS //
|
|
//////////////////////////////////////////////
|
|
|
|
/**
|
|
* Extend the store with additional methods
|
|
*
|
|
* @param {function} method - Method to add to the store (variadic)
|
|
* @return {Store} this - The Store instance
|
|
*/
|
|
Store.prototype.extend = function (methods) {
|
|
for (const [path, method] of methods) {
|
|
if (avoid.indexOf(path) !== -1) {
|
|
this.log.warning(`You cannot overwrite \`store.${path}()\``)
|
|
} else {
|
|
this.log.info(`Extending store with \`${path}\``)
|
|
set(this, path, (...args) => method(this, ...args))
|
|
}
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* Retrieve a key from the store
|
|
*
|
|
* @param {string|array} path - Path to the key
|
|
* @param {mixed} dflt - Default method to return if key is undefined
|
|
* @return {mixed} value - The value stored under key
|
|
*/
|
|
Store.prototype.get = function (path, dflt) {
|
|
const val = get(this, path, dflt)
|
|
if (typeof val === 'undefined') {
|
|
this.log.warning(`Store.get(key) on key \`${path}\`, which is undefined`)
|
|
}
|
|
|
|
return val
|
|
}
|
|
|
|
/**
|
|
* Adds a value to an array stored under path
|
|
*
|
|
* @param {string|array} path - Path to the key
|
|
* @param {mixed} values - One or more values to add (variadic)
|
|
* @return {Store} this - The Store instance
|
|
*/
|
|
Store.prototype.push = function (path, ...values) {
|
|
const arr = get(this, path)
|
|
if (Array.isArray(arr)) {
|
|
return this.set(path, [...arr, ...values])
|
|
} else {
|
|
this.log.warning(`Store.push(value) on key \`${path}\`, but key does not hold an array`)
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* Set key at path to value
|
|
*
|
|
* @param {string|array} path - Path to the key
|
|
* @param {mixed} value - The value to set
|
|
* @return {Store} this - The Store instance
|
|
*/
|
|
Store.prototype.set = function (path, value) {
|
|
if (typeof value === 'undefined') {
|
|
this.log.warning(`Store.set(value) on key \`${path}\`, but value is undefined`)
|
|
}
|
|
set(this, path, value)
|
|
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* Set key at path to value, but only if it's not currently set
|
|
*
|
|
* @param {string|array} path - Path to the key
|
|
* @param {mixed} value - The value to set
|
|
* @return {Store} this - The Store instance
|
|
*/
|
|
Store.prototype.setIfUnset = function (path, value) {
|
|
if (typeof value === 'undefined') {
|
|
this.log.warning(`Store.setIfUnset(value) on key \`${path}\`, but value is undefined`)
|
|
}
|
|
if (typeof get(this, path) === 'undefined') {
|
|
return set(this, path, value)
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* Remove the key at path
|
|
*
|
|
* @param {string|array} path - Path to the key
|
|
* @param {mixed} value - The value to set
|
|
* @return {Store} this - The Store instance
|
|
*/
|
|
Store.prototype.unset = function (path) {
|
|
unset(this, path)
|
|
|
|
return this
|
|
}
|