import ChainStorage, {
AssignRejecter
} from 'chain-storage';
function log(label, config) {
const entries = `color: ${config.get("color")}; font-size: ${config.get("fontSize")}; font-weight: ${config.get("fontWeight")}`
console.log(`%c${label} ==>`, entries, entries);
}
// Create a storage
var globalConfig = new ChainStorage({
color: "#2b85e4",
fontSize: 12,
fontWeight: 500
});
// Monitor storage value changes Monitor storage value changes and print logs;
globalConfig.watch(function (key, value, oldValue) {
console.log(`globalConfig.${key} has changed:`, oldValue, "==>", value);
})
// Register property assignment hijacking function,
// if it does not conform to the specification,
// return AssignRejecter to refuse assignment,
// otherwise return the new value
globalConfig.registerHandler("fontSize", function (value) {
value = parseInt(value);
if (Number.isNaN(value) || value < 8) return AssignRejecter;
return value;
});
// Create a branch storage
var branchConfig = globalConfig.branch({
fontSize: "14.5"
});
branchConfig.watch(function (key, value, oldValue) {
console.log(`branchConfig.${key} has changed:`, oldValue, "==>", value);
})
// Create a leaf storage
var leafConfig = branchConfig.branch();
leafConfig.set({
fontSize: "Invalid value",
fontWeight: 700
});
console.log("\n\n\n================== First round ===================");
log("globalConfig", globalConfig);
log("branchConfig", branchConfig);
log(" leafConfig", leafConfig);
console.log("====================================================\n\n\n");
globalConfig.set({
color: "#515a6e",
fontSize: 10
});
leafConfig.set({
color: "#ff9900"
});
console.log("\n\n\n================== Second round ===================");
log("globalConfig", globalConfig);
log("branchConfig", branchConfig);
log(" leafConfig", leafConfig);
console.log("====================================================\n\n\n");
globalConfig.set("color", "#2db7f5");
branchConfig.set("color", "#ed4014")
console.log("\n\n\n================== Third round ===================");
log("globalConfig", globalConfig);
log("branchConfig", branchConfig);
log(" leafConfig", leafConfig);
console.log("====================================================\n\n\n");
declare const AssignRejecter: Readonly<{
"@@Assign.rejecter": boolean;
}>;
declare class ChainStorage<S extends object = any, K extends keyof S = keyof S> {
/**
* @description Create an empty storage
* @constructor
*/
constructor();
/**
* @description Create a storage, use [[source]] as the value, and the prototype-chain is null
* @constructor
* @param { object } source
*/
constructor(source: S);
/**
* @description Create a storage, use [[source]] as the value, use [[proto]] as the prototype-chain
* @constructor
* @param { object } source
* @param { object | null } proto
*/
constructor(source: S | undefined, proto: S | null);
/**
* @description Create a branch storage, the branch uses the current storage as the prototype-chain,
* @description the modification on the branch will not affect the upper-level warehouse,
* @description but the modification of the upper-level warehouse will affect the prototype-chain of its branch storage
*
* @description Create an empty branch storage
* @returns { ChainStorage }
*/
branch<T extends object = any>(): ChainStorage<S & T>;
/**
* @description Create an empty branch storage, use [[source]] as the value
* @param { object } source
* @returns { ChainStorage }
*/
branch<T extends object = any>(source?: T): ChainStorage<S & T>;
/**
* @description Determine whether the storage has this property, it will go deep into the prototype-chain, similar to the "in" operator
* @param { PropertyKey } key
* @returns { boolean }
*/
has(key: K): boolean;
/**
* @description Get storage object property [[key]]
* @param { PropertyKey } key
* @returns { any }
*/
get(key: K): S[K] | undefined;
/**
* @description Use object to merge storage object,
* @description will not merge deeply, just simply overwriting properties
* @param { object } entries
* @returns { this }
*/
set(entries: Partial<S>): this;
/**
* @description Set a single property value
* @param { PropertyKey } key
* @param { any } value
* @returns { this }
*/
set(key: K, value: S[K]): this;
/**
* @description Delete a single property value
* @param { PropertyKey } key
* @returns { this }
*/
delete(key: K): this;
/**
* @description Returns whether the storage is frozen
* @returns { boolean }
*/
isFrozen(): boolean;
/**
* @description Returns whether the storage is destroyed
* @returns { boolean }
*/
isDestroyed(): boolean;
/**
* @description To freeze the storage, you can provide a [[lock]] for unlocking.
* @description If you don’t provide a [[lock]], this storage will not be unlocked.
* @description Return true if the freeze is successful, false if the freeze fails (for example, it is already frozen by another lock)
*
* @description If you don't want your storage to be unlocked by others, please avoid using string / number / boolean / null.
* @description If you use NaN as a [[lock]], this repository will never be unlocked, including yourself, because NaN !== NaN
* @param { object? } lock
* @returns { boolean }
*/
freeze(lock?: any): boolean;
/**
* @description To unfreeze the storage, use the [[lock]] provided when locking to unlock
* @description Return true if the unfreeze is successful, false if the unfreeze fails
* @param { object? } lock
* @returns { boolean }
*/
unfreeze(lock: any): boolean;
/**
* @description Destroy the storage, the storage will be frozen but still readable,
* @description all data monitoring on the warehouse will be cleared, and no new monitoring will be accepted
* @returns { this }
*/
destroy(): this;
/**
* @description Monitor changes in storage object properties
* @param { PropertyKey } prop
* @param { Function } watcher
* @returns { this }
*/
watch(prop: K, watcher: PropertyWatcher<S, K>): this;
/**
* @description Monitor changes in storage objects
* @param { PropertyKey } prop
* @param { Function } watcher
* @returns { this }
*/
watch(watcher: Watcher<S, K>): this;
/**
* @description Clear all monitors
* @returns { this }
*/
unwatch(): this;
/**
* @description Remove storage object monitoring
* @param { Function } watcher
* @returns { this }
*/
unwatch(watcher: Watcher<S, K>): this;
/**
* @description Remove storage object properties monitoring
* @param { Function } watcher
* @returns { this }
*/
unwatch(prop: K | Watcher<S, K>, watcher: PropertyWatcher<S, K>): this;
/**
* @description Register property assignment hijacking function to normalize attributes
* @description After registration, if the property exists, it will be executed immediately
* @param { PropertyKey } key
* @param { Function } handler
* @returns { this }
*/
registerHandler(key: K, handler: PropertyHandler): this;
}
declare type AssignRejecter = object;
interface Watcher<S extends object = any, K extends keyof S = keyof S> {
/**
* @description Monitor object changes
* @param { PropertyKey } key - Modified property
* @param { any } value - New value
* @param { any } oldValue - Old value
*/
(key: K, value: S[K] | undefined, oldValue: S[K] | undefined): void;
}
interface PropertyWatcher<S extends object = any, K extends keyof S = keyof S> {
/**
* @description Monitor property changes
* @param { any } value - New value
* @param { any } oldValue - Old value
*/
(value: S[K] | undefined, oldValue: S[K] | undefined): void;
}
interface PropertyHandler<S extends object = any, K extends keyof S = keyof S> {
/**
* @description Monitor property changes
* @param { any } value - New value
* @param { any } oldValue - Old value
*/
(value: S[K], key: K): S[K] | AssignRejecter;
}
export default ChainStorage;
export { AssignRejecter };