1
0
Fork 0
freesewing/packages/core/src/store.mjs
2023-06-11 09:30:53 +02:00

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
}