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

deep-state-observer

Package Overview
Dependencies
Maintainers
1
Versions
225
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

deep-state-observer - npm Package Compare versions

Comparing version 3.26.9 to 4.0.0

test.d.ts

458

index.cjs.js
'use strict';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
Copyright (c) Microsoft Corporation.
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */

@@ -358,6 +358,5 @@

only: [],
source: '',
source: "",
debug: false,
data: undefined,
queue: false,
force: false,

@@ -368,2 +367,11 @@ };

}
/**
* Is object - helper function to determine if specified variable is an object
*
* @param {any} item
* @returns {boolean}
*/
function isObject(item) {
return item && typeof item === "object" && item !== null && item.constructor && item.constructor.name === "Object";
}
function getDefaultOptions() {

@@ -379,3 +387,2 @@ return {

experimentalMatch: false,
queue: false,
maxSimultaneousJobs: 1000,

@@ -390,21 +397,11 @@ maxQueueRuns: 1000,

debug: false,
source: '',
source: "",
data: undefined,
queue: false,
group: false,
};
const handler = {
get(obj, prop) { },
set(obj, prop, value) {
return true;
},
};
class DeepState {
constructor(data = {}, options = {}) {
this.jobsRunning = 0;
this.updateQueue = [];
this.subscribeQueue = [];
this.listenersIgnoreCache = new WeakMap();
this.destroyed = false;
this.queueRuns = 0;
this.groupId = 0;

@@ -417,8 +414,46 @@ this.traceId = 0;

this.collections = 0;
this.proxyPath = [];
this.handler = {
get: (obj, prop) => {
if (obj.hasOwnProperty(prop))
this.proxyPath.push(prop);
return obj[prop];
},
set: (obj, prop, value) => {
this.proxyPath.push(prop);
const path = this.proxyPath.join(".");
if (typeof value === "function") {
value = value(obj[prop]);
}
let final = value;
if (isObject(value)) {
final = new Proxy(this.mergeDeepProxy({}, value), this.handler);
}
else if (Array.isArray(value)) {
final = new Proxy(this.mergeDeepProxy([], value), this.handler);
}
this.proxyPath = [];
this.update(path, final);
obj[prop] = final;
return true;
},
};
this.lastExecs = new WeakMap();
this.listeners = new Map();
this.waitingListeners = new Map();
this.handler.get = this.handler.get.bind(this);
this.handler.set = this.handler.set.bind(this);
const self = this;
this.data = data;
this.proxy = new Proxy(this.data, handler);
this.options = Object.assign({}, getDefaultOptions(), options);
this.proxy = new Proxy(this.mergeDeepProxy({}, data), {
get(obj, prop) {
if (obj.hasOwnProperty(prop))
self.proxyPath = [prop];
return obj[prop];
},
set(obj, prop, value) {
return self.handler.set(obj, prop, value);
},
});
this.$$$ = this.proxy;
this.options = Object.assign(Object.assign({}, getDefaultOptions()), options);
this.id = 0;

@@ -438,2 +473,57 @@ this.pathGet = ObjectPath.get;

}
mergeDeepProxy(target, ...sources) {
const source = sources.shift();
if (isObject(target) && isObject(source)) {
const targetValMain = {};
for (const key in source) {
if (isObject(source[key])) {
targetValMain[key] = new Proxy(this.mergeDeepProxy({}, source[key]), this.handler);
}
else if (Array.isArray(source[key])) {
const targetVal = new Array(source[key].length);
let index = 0;
for (let item of source[key]) {
if (isObject(item) || Array.isArray(item)) {
targetVal[index] = new Proxy(this.mergeDeepProxy({}, item), this.handler);
}
else {
targetVal[index] = item;
}
index++;
}
targetValMain[key] = new Proxy(targetVal, this.handler);
}
else {
targetValMain[key] = source[key];
}
}
if (sources.length) {
target = new Proxy(targetValMain, this.handler);
}
else {
target = targetValMain;
}
}
else if (Array.isArray(source)) {
const targetVal = new Array(source.length);
for (let i = 0, len = source.length; i < len; i++) {
if (isObject(source[i]) || Array.isArray(source[i])) {
targetVal[i] = this.mergeDeepProxy(source[i]);
}
else {
targetVal[i] = source[i];
}
}
if (sources.length) {
target = new Proxy(targetVal, this.handler);
}
else {
target = targetVal;
}
}
if (!sources.length) {
return target;
}
return this.mergeDeepProxy(target, ...sources);
}
loadWasmMatcher(pathToWasmFile) {

@@ -447,4 +537,3 @@ return __awaiter(this, void 0, void 0, function* () {

same(newValue, oldValue) {
return ((['number', 'string', 'undefined', 'boolean'].includes(typeof newValue) ||
newValue === null) &&
return ((["number", "string", "undefined", "boolean"].includes(typeof newValue) || newValue === null) &&
oldValue === newValue);

@@ -459,4 +548,2 @@ }

this.listeners = new Map();
this.updateQueue = [];
this.jobsRunning = 0;
}

@@ -471,4 +558,3 @@ match(first, second, nested = true) {

if (!nested &&
this.getIndicesCount(this.options.delimiter, first) <
this.getIndicesCount(this.options.delimiter, second)) {
this.getIndicesCount(this.options.delimiter, first) < this.getIndicesCount(this.options.delimiter, second)) {
// first < second because first is a listener path and may be longer but not shorter

@@ -520,3 +606,3 @@ return false;

split(path) {
return path === '' ? [] : path.split(this.options.delimiter);
return path === "" ? [] : path.split(this.options.delimiter);
}

@@ -530,5 +616,3 @@ isWildcard(path) {

cleanNotRecursivePath(path) {
return this.isNotRecursive(path)
? path.substring(0, path.length - 1)
: path;
return this.isNotRecursive(path) ? path.substring(0, path.length - 1) : path;
}

@@ -539,3 +623,3 @@ hasParams(path) {

getParamsInfo(path) {
let paramsInfo = { replaced: '', original: path, params: {} };
let paramsInfo = { replaced: "", original: path, params: {} };
let partIndex = 0;

@@ -546,6 +630,6 @@ let fullReplaced = [];

original: part,
replaced: '',
name: '',
replaced: "",
name: "",
};
const reg = new RegExp(`\\${this.options.param}([^\\${this.options.delimiter}\\${this.options.param}]+)`, 'g');
const reg = new RegExp(`\\${this.options.param}([^\\${this.options.delimiter}\\${this.options.param}]+)`, "g");
let param = reg.exec(part);

@@ -581,47 +665,2 @@ if (param) {

}
waitForAll(userPaths, fn) {
const paths = {};
for (let path of userPaths) {
paths[path] = { dirty: false };
if (this.hasParams(path)) {
paths[path].paramsInfo = this.getParamsInfo(path);
}
paths[path].isWildcard = this.isWildcard(path);
paths[path].isRecursive = !this.isNotRecursive(path);
}
this.waitingListeners.set(userPaths, { fn, paths });
fn(paths);
return function unsubscribe() {
this.waitingListeners.delete(userPaths);
};
}
executeWaitingListeners(updatePath) {
if (this.destroyed)
return;
for (const waitingListener of this.waitingListeners.values()) {
const { fn, paths } = waitingListener;
let dirty = 0;
let all = 0;
for (let path in paths) {
const pathInfo = paths[path];
let match = false;
if (pathInfo.isRecursive)
updatePath = this.cutPath(updatePath, path);
if (pathInfo.isWildcard && this.match(path, updatePath))
match = true;
if (updatePath === path)
match = true;
if (match) {
pathInfo.dirty = true;
}
if (pathInfo.dirty) {
dirty++;
}
all++;
}
if (dirty === all) {
fn(paths);
}
}
}
subscribeAll(userPaths, fn, options = defaultListenerOptions) {

@@ -656,3 +695,3 @@ if (this.destroyed)

fn,
options: Object.assign({}, defaultListenerOptions, options),
options: Object.assign(Object.assign({}, defaultListenerOptions), options),
groupId: null,

@@ -673,3 +712,3 @@ };

if (debug) {
console.log('[getListenerCollectionMatch]', {
console.log("[getListenerCollectionMatch]", {
listenerPath,

@@ -710,3 +749,3 @@ scopedListenerPath,

}
let listenersCollection = this.getCleanListenersCollection(Object.assign({}, collCfg, { match: this.getListenerCollectionMatch(collCfg.path, collCfg.isRecursive, collCfg.isWildcard) }));
let listenersCollection = this.getCleanListenersCollection(Object.assign(Object.assign({}, collCfg), { match: this.getListenerCollectionMatch(collCfg.path, collCfg.isRecursive, collCfg.isWildcard) }));
this.id++;

@@ -725,4 +764,3 @@ listenersCollection.listeners.set(this.id, listener);

return () => { };
this.jobsRunning++;
const type = 'subscribe';
const type = "subscribe";
let listener = this.getCleanListener(fn, options);

@@ -737,5 +775,3 @@ if (options.group)

listenersCollection.count++;
if (!options.group ||
(options.group &&
subscribeAllOptions.all.length - 1 === subscribeAllOptions.index)) {
if (!options.group || (options.group && subscribeAllOptions.all.length - 1 === subscribeAllOptions.index)) {
const cleanPath = this.cleanNotRecursivePath(listenersCollection.path);

@@ -807,3 +843,2 @@ if (!listenersCollection.isWildcard) {

this.debugSubscribe(listener, listenersCollection, listenerPath);
this.jobsRunning--;
return this.unsubscribe(listenerPath, this.id);

@@ -827,24 +862,7 @@ }

return;
if (this.jobsRunning === 0) {
this.queueRuns = 0;
const queue = [...this.subscribeQueue];
for (let i = 0, len = queue.length; i < len; i++) {
queue[i]();
}
this.subscribeQueue.length = 0;
const queue = [...this.subscribeQueue];
for (let i = 0, len = queue.length; i < len; i++) {
queue[i]();
}
else {
this.queueRuns++;
if (this.queueRuns >= this.options.maxQueueRuns) {
this.queueRuns = 0;
throw new Error('Maximal number of queue runs exhausted.');
}
else {
Promise.resolve()
.then(() => this.runQueuedListeners())
.catch((e) => {
throw e;
});
}
}
this.subscribeQueue.length = 0;
}

@@ -858,10 +876,5 @@ getQueueNotifyListeners(groupedListeners, queue = []) {

let alreadyInQueue = false;
let resolvedIdPath = singleListener.listener.id +
':' +
singleListener.eventInfo.path.resolved;
let resolvedIdPath = singleListener.listener.id + ":" + singleListener.eventInfo.path.resolved;
if (!singleListener.eventInfo.path.resolved) {
resolvedIdPath =
singleListener.listener.id +
':' +
singleListener.eventInfo.path.listener;
resolvedIdPath = singleListener.listener.id + ":" + singleListener.eventInfo.path.listener;
}

@@ -879,29 +892,17 @@ for (const excludedListener of queue) {

if (!this.isMuted(singleListener.listener.fn)) {
if (singleListener.listener.options.queue && this.jobsRunning) {
this.subscribeQueue.push(() => {
let resolvedIdPath = singleListener.listener.id + ":" + singleListener.eventInfo.path.resolved;
if (!singleListener.eventInfo.path.resolved) {
resolvedIdPath = singleListener.listener.id + ":" + singleListener.eventInfo.path.listener;
}
queue.push({
id: singleListener.listener.id,
resolvedPath: singleListener.eventInfo.path.resolved,
resolvedIdPath,
originalFn: singleListener.listener.fn,
fn: () => {
singleListener.listener.fn(singleListener.value(), singleListener.eventInfo);
});
}
else {
let resolvedIdPath = singleListener.listener.id +
':' +
singleListener.eventInfo.path.resolved;
if (!singleListener.eventInfo.path.resolved) {
resolvedIdPath =
singleListener.listener.id +
':' +
singleListener.eventInfo.path.listener;
}
queue.push({
id: singleListener.listener.id,
resolvedPath: singleListener.eventInfo.path.resolved,
resolvedIdPath,
originalFn: singleListener.listener.fn,
fn: () => {
singleListener.listener.fn(singleListener.value(), singleListener.eventInfo);
},
options: singleListener.listener.options,
groupId: singleListener.listener.groupId,
});
}
},
options: singleListener.listener.options,
groupId: singleListener.listener.groupId,
});
}

@@ -923,36 +924,20 @@ this.debugListener(time, singleListener);

for (const bulk of bulkListener.value) {
bulkValue.push(Object.assign({}, bulk, { value: bulk.value() }));
bulkValue.push(Object.assign(Object.assign({}, bulk), { value: bulk.value() }));
}
if (!this.isMuted(bulkListener.listener.fn)) {
if (bulkListener.listener.options.queue && this.jobsRunning) {
this.subscribeQueue.push(() => {
if (!this.jobsRunning) {
bulkListener.listener.fn(bulkValue, bulkListener.eventInfo);
return true;
}
return false;
});
let resolvedIdPath = bulkListener.listener.id + ":" + bulkListener.eventInfo.path.resolved;
if (!bulkListener.eventInfo.path.resolved) {
resolvedIdPath = bulkListener.listener.id + ":" + bulkListener.eventInfo.path.listener;
}
else {
let resolvedIdPath = bulkListener.listener.id +
':' +
bulkListener.eventInfo.path.resolved;
if (!bulkListener.eventInfo.path.resolved) {
resolvedIdPath =
bulkListener.listener.id +
':' +
bulkListener.eventInfo.path.listener;
}
queue.push({
id: bulkListener.listener.id,
resolvedPath: bulkListener.eventInfo.path.resolved,
resolvedIdPath,
originalFn: bulkListener.listener.fn,
fn: () => {
bulkListener.listener.fn(bulkValue, bulkListener.eventInfo);
},
options: bulkListener.listener.options,
groupId: bulkListener.listener.groupId,
});
}
queue.push({
id: bulkListener.listener.id,
resolvedPath: bulkListener.eventInfo.path.resolved,
resolvedIdPath,
originalFn: bulkListener.listener.fn,
fn: () => {
bulkListener.listener.fn(bulkValue, bulkListener.eventInfo);
},
options: bulkListener.listener.options,
groupId: bulkListener.listener.groupId,
});
}

@@ -984,4 +969,4 @@ this.debugListener(time, bulkListener);

}
getSubscribedListeners(updatePath, newValue, options, type = 'update', originalPath = null) {
options = Object.assign({}, defaultUpdateOptions, options);
getSubscribedListeners(updatePath, newValue, options, type = "update", originalPath = null) {
options = Object.assign(Object.assign({}, defaultUpdateOptions), options);
const listeners = {};

@@ -1066,6 +1051,6 @@ for (let [listenerPath, listenersCollection] of this.listeners) {

}
notifySubscribedListeners(updatePath, newValue, options, type = 'update', originalPath = null) {
notifySubscribedListeners(updatePath, newValue, options, type = "update", originalPath = null) {
return this.getQueueNotifyListeners(this.getSubscribedListeners(updatePath, newValue, options, type, originalPath));
}
getNestedListeners(updatePath, newValue, options, type = 'update', originalPath = null) {
getNestedListeners(updatePath, newValue, options, type = "update", originalPath = null) {
const listeners = {};

@@ -1143,3 +1128,3 @@ for (let [listenerPath, listenersCollection] of this.listeners) {

if (listener.options.debug) {
console.log('[getNestedListeners] Listener was not fired because there was no match.', {
console.log("[getNestedListeners] Listener was not fired because there was no match.", {
listener,

@@ -1156,10 +1141,10 @@ listenersCollection,

}
notifyNestedListeners(updatePath, newValue, options, type = 'update', queue, originalPath = null) {
notifyNestedListeners(updatePath, newValue, options, type = "update", queue, originalPath = null) {
return this.getQueueNotifyListeners(this.getNestedListeners(updatePath, newValue, options, type, originalPath), queue);
}
getNotifyOnlyListeners(updatePath, newValue, options, type = 'update', originalPath = null) {
getNotifyOnlyListeners(updatePath, newValue, options, type = "update", originalPath = null) {
const listeners = {};
if (typeof options.only !== 'object' ||
if (typeof options.only !== "object" ||
!Array.isArray(options.only) ||
typeof options.only[0] === 'undefined' ||
typeof options.only[0] === "undefined" ||
!this.canBeNested(newValue)) {

@@ -1243,3 +1228,3 @@ return listeners;

}
notifyOnly(updatePath, newValue, options, type = 'update', originalPath = '') {
notifyOnly(updatePath, newValue, options, type = "update", originalPath = "") {
const queue = this.getQueueNotifyListeners(this.getNotifyOnlyListeners(updatePath, newValue, options, type, originalPath));

@@ -1249,7 +1234,7 @@ this.sortAndRunQueue(queue, updatePath);

canBeNested(newValue) {
return typeof newValue === 'object' && newValue !== null;
return typeof newValue === "object" && newValue !== null;
}
getUpdateValues(oldValue, split, fn) {
let newValue = fn;
if (typeof fn === 'function') {
if (typeof fn === "function") {
newValue = fn(this.pathGet(split, this.data));

@@ -1259,3 +1244,3 @@ }

}
wildcardNotify(groupedListenersPack, waitingPaths) {
wildcardNotify(groupedListenersPack) {
let queue = [];

@@ -1265,11 +1250,6 @@ for (const groupedListeners of groupedListenersPack) {

}
for (const path of waitingPaths) {
this.executeWaitingListeners(path);
}
this.jobsRunning--;
return queue;
}
wildcardUpdate(updatePath, fn, options = defaultUpdateOptions, multi = false) {
++this.jobsRunning;
options = Object.assign({}, defaultUpdateOptions, options);
options = Object.assign(Object.assign({}, defaultUpdateOptions), options);
const scanned = this.scan.get(updatePath);

@@ -1286,16 +1266,14 @@ const updated = {};

const groupedListenersPack = [];
const waitingPaths = [];
for (const path in updated) {
const newValue = updated[path];
if (options.only.length) {
groupedListenersPack.push(this.getNotifyOnlyListeners(path, newValue, options, 'update', updatePath));
groupedListenersPack.push(this.getNotifyOnlyListeners(path, newValue, options, "update", updatePath));
}
else {
groupedListenersPack.push(this.getSubscribedListeners(path, newValue, options, 'update', updatePath));
groupedListenersPack.push(this.getSubscribedListeners(path, newValue, options, "update", updatePath));
if (this.canBeNested(newValue)) {
groupedListenersPack.push(this.getNestedListeners(path, newValue, options, 'update', updatePath));
groupedListenersPack.push(this.getNestedListeners(path, newValue, options, "update", updatePath));
}
}
options.debug && this.options.log('Wildcard update', { path, newValue });
waitingPaths.push(path);
options.debug && this.options.log("Wildcard update", { path, newValue });
}

@@ -1305,26 +1283,15 @@ if (multi) {

return function () {
const queue = self.wildcardNotify(groupedListenersPack, waitingPaths);
const queue = self.wildcardNotify(groupedListenersPack);
self.sortAndRunQueue(queue, updatePath);
};
}
const queue = this.wildcardNotify(groupedListenersPack, waitingPaths);
const queue = this.wildcardNotify(groupedListenersPack);
this.sortAndRunQueue(queue, updatePath);
}
runUpdateQueue() {
if (this.destroyed)
return;
while (this.updateQueue.length &&
this.updateQueue.length < this.options.maxSimultaneousJobs) {
const params = this.updateQueue.shift();
params.options.queue = false; // prevent infinite loop
this.update(params.updatePath, params.fnOrValue, params.options, params.multi);
}
}
updateNotify(updatePath, newValue, options) {
const queue = this.notifySubscribedListeners(updatePath, newValue, options);
if (this.canBeNested(newValue)) {
this.notifyNestedListeners(updatePath, newValue, options, 'update', queue);
this.notifyNestedListeners(updatePath, newValue, options, "update", queue);
}
this.sortAndRunQueue(queue, updatePath);
this.executeWaitingListeners(updatePath);
}

@@ -1348,3 +1315,3 @@ updateNotifyAll(updateStack) {

if (this.canBeNested(current.newValue)) {
this.notifyNestedListeners(current.updatePath, value, current.options, 'update', queue);
this.notifyNestedListeners(current.updatePath, value, current.options, "update", queue);
}

@@ -1356,3 +1323,2 @@ }

this.notifyOnly(updatePath, newValue, options);
this.executeWaitingListeners(updatePath);
}

@@ -1371,26 +1337,9 @@ update(updatePath, fnOrValue, options = Object.assign({}, defaultUpdateOptions), multi = false) {

}
const jobsRunning = this.jobsRunning;
if ((this.options.queue || options.queue) && jobsRunning) {
if (jobsRunning > this.options.maxSimultaneousJobs) {
throw new Error('Maximal simultaneous jobs limit reached.');
}
this.updateQueue.push({ updatePath, fnOrValue, options, multi });
const result = Promise.resolve().then(() => {
this.runUpdateQueue();
});
if (multi) {
return function () {
return result;
};
}
return result;
}
if (this.isWildcard(updatePath)) {
return this.wildcardUpdate(updatePath, fnOrValue, options, multi);
}
++this.jobsRunning;
const split = this.split(updatePath);
const { oldValue, newValue } = this.getUpdateValues(this.pathGet(split, this.data), split, fnOrValue);
if (options.debug) {
this.options.log(`Updating ${updatePath} ${options.source ? `from ${options.source}` : ''}`, {
this.options.log(`Updating ${updatePath} ${options.source ? `from ${options.source}` : ""}`, {
oldValue,

@@ -1401,3 +1350,2 @@ newValue,

if (this.same(newValue, oldValue) && !options.force) {
--this.jobsRunning;
if (multi)

@@ -1410,5 +1358,4 @@ return function () {

this.pathSet(split, newValue, this.data);
options = Object.assign({}, defaultUpdateOptions, options);
options = Object.assign(Object.assign({}, defaultUpdateOptions), options);
if (options.only === null) {
--this.jobsRunning;
if (multi)

@@ -1419,3 +1366,2 @@ return function () { };

if (options.only.length) {
--this.jobsRunning;
if (multi) {

@@ -1431,3 +1377,2 @@ const self = this;

if (multi) {
--this.jobsRunning;
const self = this;

@@ -1439,3 +1384,2 @@ return function multiUpdate() {

this.updateNotify(updatePath, newValue, options);
--this.jobsRunning;
return newValue;

@@ -1464,3 +1408,3 @@ }

let value = fnOrValue;
if (typeof value === 'function') {
if (typeof value === "function") {
value = value(self.pathGet(split, self.data));

@@ -1522,3 +1466,3 @@ }

return;
if (typeof userPath === 'undefined' || userPath === '') {
if (typeof userPath === "undefined" || userPath === "") {
return this.data;

@@ -1545,3 +1489,3 @@ }

return false;
if (typeof pathOrListenerFunction === 'function') {
if (typeof pathOrListenerFunction === "function") {
return this.isMutedListener(pathOrListenerFunction);

@@ -1570,3 +1514,3 @@ }

mute(pathOrListenerFunction) {
if (typeof pathOrListenerFunction === 'function') {
if (typeof pathOrListenerFunction === "function") {
return this.mutedListeners.add(pathOrListenerFunction);

@@ -1577,3 +1521,3 @@ }

unmute(pathOrListenerFunction) {
if (typeof pathOrListenerFunction === 'function') {
if (typeof pathOrListenerFunction === "function") {
return this.mutedListeners.delete(pathOrListenerFunction);

@@ -1585,3 +1529,3 @@ }

if (listener.options.debug) {
this.options.log('listener subscribed', {
this.options.log("listener subscribed", {
listenerPath,

@@ -1594,5 +1538,4 @@ listener,

debugListener(time, groupedListener) {
if (groupedListener.eventInfo.options.debug ||
groupedListener.listener.options.debug) {
this.options.log('Listener fired', {
if (groupedListener.eventInfo.options.debug || groupedListener.listener.options.debug) {
this.options.log("Listener fired", {
time: Date.now() - time,

@@ -1604,10 +1547,7 @@ info: groupedListener,

debugTime(groupedListener) {
return groupedListener.listener.options.debug ||
groupedListener.eventInfo.options.debug
? Date.now()
: 0;
return groupedListener.listener.options.debug || groupedListener.eventInfo.options.debug ? Date.now() : 0;
}
startTrace(name, additionalData = null) {
this.traceId++;
const id = this.traceId + ':' + name;
const id = this.traceId + ":" + name;
this.traceMap.set(id, {

@@ -1614,0 +1554,0 @@ id,

@@ -23,3 +23,2 @@ export interface PathInfo {

experimentalMatch?: boolean;
queue?: boolean;
maxSimultaneousJobs?: number;

@@ -37,3 +36,2 @@ maxQueueRuns?: number;

data?: any;
queue?: boolean;
ignore?: string[];

@@ -145,5 +143,7 @@ group?: boolean;

}
export interface UnknownObject {
[key: string]: unknown;
}
declare class DeepState<T> {
private listeners;
private waitingListeners;
private data;

@@ -155,4 +155,2 @@ private options;

private scan;
private jobsRunning;
private updateQueue;
private subscribeQueue;

@@ -162,3 +160,2 @@ private listenersIgnoreCache;

private destroyed;
private queueRuns;
private resolved;

@@ -174,4 +171,11 @@ private muted;

private collections;
proxy: any;
private proxyPath;
private handler;
proxy: T;
/**
* @property $$$ proxy shorthand
*/
$$$: T;
constructor(data?: T | object, options?: Options);
private mergeDeepProxy;
loadWasmMatcher(pathToWasmFile: string): Promise<void>;

@@ -193,4 +197,2 @@ private same;

private getParams;
waitForAll(userPaths: string[], fn: WaitingListenerFunction): () => void;
private executeWaitingListeners;
subscribeAll(userPaths: string[], fn: ListenerFunction | WaitingListenerFunction, options?: ListenerOptions): () => void;

@@ -218,3 +220,2 @@ private getCleanListenersCollection;

private wildcardUpdate;
private runUpdateQueue;
private updateNotify;

@@ -221,0 +222,0 @@ private updateNotifyAll;

/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
Copyright (c) Microsoft Corporation.
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */

@@ -356,6 +356,5 @@

only: [],
source: '',
source: "",
debug: false,
data: undefined,
queue: false,
force: false,

@@ -366,2 +365,11 @@ };

}
/**
* Is object - helper function to determine if specified variable is an object
*
* @param {any} item
* @returns {boolean}
*/
function isObject(item) {
return item && typeof item === "object" && item !== null && item.constructor && item.constructor.name === "Object";
}
function getDefaultOptions() {

@@ -377,3 +385,2 @@ return {

experimentalMatch: false,
queue: false,
maxSimultaneousJobs: 1000,

@@ -388,21 +395,11 @@ maxQueueRuns: 1000,

debug: false,
source: '',
source: "",
data: undefined,
queue: false,
group: false,
};
const handler = {
get(obj, prop) { },
set(obj, prop, value) {
return true;
},
};
class DeepState {
constructor(data = {}, options = {}) {
this.jobsRunning = 0;
this.updateQueue = [];
this.subscribeQueue = [];
this.listenersIgnoreCache = new WeakMap();
this.destroyed = false;
this.queueRuns = 0;
this.groupId = 0;

@@ -415,8 +412,46 @@ this.traceId = 0;

this.collections = 0;
this.proxyPath = [];
this.handler = {
get: (obj, prop) => {
if (obj.hasOwnProperty(prop))
this.proxyPath.push(prop);
return obj[prop];
},
set: (obj, prop, value) => {
this.proxyPath.push(prop);
const path = this.proxyPath.join(".");
if (typeof value === "function") {
value = value(obj[prop]);
}
let final = value;
if (isObject(value)) {
final = new Proxy(this.mergeDeepProxy({}, value), this.handler);
}
else if (Array.isArray(value)) {
final = new Proxy(this.mergeDeepProxy([], value), this.handler);
}
this.proxyPath = [];
this.update(path, final);
obj[prop] = final;
return true;
},
};
this.lastExecs = new WeakMap();
this.listeners = new Map();
this.waitingListeners = new Map();
this.handler.get = this.handler.get.bind(this);
this.handler.set = this.handler.set.bind(this);
const self = this;
this.data = data;
this.proxy = new Proxy(this.data, handler);
this.options = Object.assign({}, getDefaultOptions(), options);
this.proxy = new Proxy(this.mergeDeepProxy({}, data), {
get(obj, prop) {
if (obj.hasOwnProperty(prop))
self.proxyPath = [prop];
return obj[prop];
},
set(obj, prop, value) {
return self.handler.set(obj, prop, value);
},
});
this.$$$ = this.proxy;
this.options = Object.assign(Object.assign({}, getDefaultOptions()), options);
this.id = 0;

@@ -436,2 +471,57 @@ this.pathGet = ObjectPath.get;

}
mergeDeepProxy(target, ...sources) {
const source = sources.shift();
if (isObject(target) && isObject(source)) {
const targetValMain = {};
for (const key in source) {
if (isObject(source[key])) {
targetValMain[key] = new Proxy(this.mergeDeepProxy({}, source[key]), this.handler);
}
else if (Array.isArray(source[key])) {
const targetVal = new Array(source[key].length);
let index = 0;
for (let item of source[key]) {
if (isObject(item) || Array.isArray(item)) {
targetVal[index] = new Proxy(this.mergeDeepProxy({}, item), this.handler);
}
else {
targetVal[index] = item;
}
index++;
}
targetValMain[key] = new Proxy(targetVal, this.handler);
}
else {
targetValMain[key] = source[key];
}
}
if (sources.length) {
target = new Proxy(targetValMain, this.handler);
}
else {
target = targetValMain;
}
}
else if (Array.isArray(source)) {
const targetVal = new Array(source.length);
for (let i = 0, len = source.length; i < len; i++) {
if (isObject(source[i]) || Array.isArray(source[i])) {
targetVal[i] = this.mergeDeepProxy(source[i]);
}
else {
targetVal[i] = source[i];
}
}
if (sources.length) {
target = new Proxy(targetVal, this.handler);
}
else {
target = targetVal;
}
}
if (!sources.length) {
return target;
}
return this.mergeDeepProxy(target, ...sources);
}
loadWasmMatcher(pathToWasmFile) {

@@ -445,4 +535,3 @@ return __awaiter(this, void 0, void 0, function* () {

same(newValue, oldValue) {
return ((['number', 'string', 'undefined', 'boolean'].includes(typeof newValue) ||
newValue === null) &&
return ((["number", "string", "undefined", "boolean"].includes(typeof newValue) || newValue === null) &&
oldValue === newValue);

@@ -457,4 +546,2 @@ }

this.listeners = new Map();
this.updateQueue = [];
this.jobsRunning = 0;
}

@@ -469,4 +556,3 @@ match(first, second, nested = true) {

if (!nested &&
this.getIndicesCount(this.options.delimiter, first) <
this.getIndicesCount(this.options.delimiter, second)) {
this.getIndicesCount(this.options.delimiter, first) < this.getIndicesCount(this.options.delimiter, second)) {
// first < second because first is a listener path and may be longer but not shorter

@@ -518,3 +604,3 @@ return false;

split(path) {
return path === '' ? [] : path.split(this.options.delimiter);
return path === "" ? [] : path.split(this.options.delimiter);
}

@@ -528,5 +614,3 @@ isWildcard(path) {

cleanNotRecursivePath(path) {
return this.isNotRecursive(path)
? path.substring(0, path.length - 1)
: path;
return this.isNotRecursive(path) ? path.substring(0, path.length - 1) : path;
}

@@ -537,3 +621,3 @@ hasParams(path) {

getParamsInfo(path) {
let paramsInfo = { replaced: '', original: path, params: {} };
let paramsInfo = { replaced: "", original: path, params: {} };
let partIndex = 0;

@@ -544,6 +628,6 @@ let fullReplaced = [];

original: part,
replaced: '',
name: '',
replaced: "",
name: "",
};
const reg = new RegExp(`\\${this.options.param}([^\\${this.options.delimiter}\\${this.options.param}]+)`, 'g');
const reg = new RegExp(`\\${this.options.param}([^\\${this.options.delimiter}\\${this.options.param}]+)`, "g");
let param = reg.exec(part);

@@ -579,47 +663,2 @@ if (param) {

}
waitForAll(userPaths, fn) {
const paths = {};
for (let path of userPaths) {
paths[path] = { dirty: false };
if (this.hasParams(path)) {
paths[path].paramsInfo = this.getParamsInfo(path);
}
paths[path].isWildcard = this.isWildcard(path);
paths[path].isRecursive = !this.isNotRecursive(path);
}
this.waitingListeners.set(userPaths, { fn, paths });
fn(paths);
return function unsubscribe() {
this.waitingListeners.delete(userPaths);
};
}
executeWaitingListeners(updatePath) {
if (this.destroyed)
return;
for (const waitingListener of this.waitingListeners.values()) {
const { fn, paths } = waitingListener;
let dirty = 0;
let all = 0;
for (let path in paths) {
const pathInfo = paths[path];
let match = false;
if (pathInfo.isRecursive)
updatePath = this.cutPath(updatePath, path);
if (pathInfo.isWildcard && this.match(path, updatePath))
match = true;
if (updatePath === path)
match = true;
if (match) {
pathInfo.dirty = true;
}
if (pathInfo.dirty) {
dirty++;
}
all++;
}
if (dirty === all) {
fn(paths);
}
}
}
subscribeAll(userPaths, fn, options = defaultListenerOptions) {

@@ -654,3 +693,3 @@ if (this.destroyed)

fn,
options: Object.assign({}, defaultListenerOptions, options),
options: Object.assign(Object.assign({}, defaultListenerOptions), options),
groupId: null,

@@ -671,3 +710,3 @@ };

if (debug) {
console.log('[getListenerCollectionMatch]', {
console.log("[getListenerCollectionMatch]", {
listenerPath,

@@ -708,3 +747,3 @@ scopedListenerPath,

}
let listenersCollection = this.getCleanListenersCollection(Object.assign({}, collCfg, { match: this.getListenerCollectionMatch(collCfg.path, collCfg.isRecursive, collCfg.isWildcard) }));
let listenersCollection = this.getCleanListenersCollection(Object.assign(Object.assign({}, collCfg), { match: this.getListenerCollectionMatch(collCfg.path, collCfg.isRecursive, collCfg.isWildcard) }));
this.id++;

@@ -723,4 +762,3 @@ listenersCollection.listeners.set(this.id, listener);

return () => { };
this.jobsRunning++;
const type = 'subscribe';
const type = "subscribe";
let listener = this.getCleanListener(fn, options);

@@ -735,5 +773,3 @@ if (options.group)

listenersCollection.count++;
if (!options.group ||
(options.group &&
subscribeAllOptions.all.length - 1 === subscribeAllOptions.index)) {
if (!options.group || (options.group && subscribeAllOptions.all.length - 1 === subscribeAllOptions.index)) {
const cleanPath = this.cleanNotRecursivePath(listenersCollection.path);

@@ -805,3 +841,2 @@ if (!listenersCollection.isWildcard) {

this.debugSubscribe(listener, listenersCollection, listenerPath);
this.jobsRunning--;
return this.unsubscribe(listenerPath, this.id);

@@ -825,24 +860,7 @@ }

return;
if (this.jobsRunning === 0) {
this.queueRuns = 0;
const queue = [...this.subscribeQueue];
for (let i = 0, len = queue.length; i < len; i++) {
queue[i]();
}
this.subscribeQueue.length = 0;
const queue = [...this.subscribeQueue];
for (let i = 0, len = queue.length; i < len; i++) {
queue[i]();
}
else {
this.queueRuns++;
if (this.queueRuns >= this.options.maxQueueRuns) {
this.queueRuns = 0;
throw new Error('Maximal number of queue runs exhausted.');
}
else {
Promise.resolve()
.then(() => this.runQueuedListeners())
.catch((e) => {
throw e;
});
}
}
this.subscribeQueue.length = 0;
}

@@ -856,10 +874,5 @@ getQueueNotifyListeners(groupedListeners, queue = []) {

let alreadyInQueue = false;
let resolvedIdPath = singleListener.listener.id +
':' +
singleListener.eventInfo.path.resolved;
let resolvedIdPath = singleListener.listener.id + ":" + singleListener.eventInfo.path.resolved;
if (!singleListener.eventInfo.path.resolved) {
resolvedIdPath =
singleListener.listener.id +
':' +
singleListener.eventInfo.path.listener;
resolvedIdPath = singleListener.listener.id + ":" + singleListener.eventInfo.path.listener;
}

@@ -877,29 +890,17 @@ for (const excludedListener of queue) {

if (!this.isMuted(singleListener.listener.fn)) {
if (singleListener.listener.options.queue && this.jobsRunning) {
this.subscribeQueue.push(() => {
let resolvedIdPath = singleListener.listener.id + ":" + singleListener.eventInfo.path.resolved;
if (!singleListener.eventInfo.path.resolved) {
resolvedIdPath = singleListener.listener.id + ":" + singleListener.eventInfo.path.listener;
}
queue.push({
id: singleListener.listener.id,
resolvedPath: singleListener.eventInfo.path.resolved,
resolvedIdPath,
originalFn: singleListener.listener.fn,
fn: () => {
singleListener.listener.fn(singleListener.value(), singleListener.eventInfo);
});
}
else {
let resolvedIdPath = singleListener.listener.id +
':' +
singleListener.eventInfo.path.resolved;
if (!singleListener.eventInfo.path.resolved) {
resolvedIdPath =
singleListener.listener.id +
':' +
singleListener.eventInfo.path.listener;
}
queue.push({
id: singleListener.listener.id,
resolvedPath: singleListener.eventInfo.path.resolved,
resolvedIdPath,
originalFn: singleListener.listener.fn,
fn: () => {
singleListener.listener.fn(singleListener.value(), singleListener.eventInfo);
},
options: singleListener.listener.options,
groupId: singleListener.listener.groupId,
});
}
},
options: singleListener.listener.options,
groupId: singleListener.listener.groupId,
});
}

@@ -921,36 +922,20 @@ this.debugListener(time, singleListener);

for (const bulk of bulkListener.value) {
bulkValue.push(Object.assign({}, bulk, { value: bulk.value() }));
bulkValue.push(Object.assign(Object.assign({}, bulk), { value: bulk.value() }));
}
if (!this.isMuted(bulkListener.listener.fn)) {
if (bulkListener.listener.options.queue && this.jobsRunning) {
this.subscribeQueue.push(() => {
if (!this.jobsRunning) {
bulkListener.listener.fn(bulkValue, bulkListener.eventInfo);
return true;
}
return false;
});
let resolvedIdPath = bulkListener.listener.id + ":" + bulkListener.eventInfo.path.resolved;
if (!bulkListener.eventInfo.path.resolved) {
resolvedIdPath = bulkListener.listener.id + ":" + bulkListener.eventInfo.path.listener;
}
else {
let resolvedIdPath = bulkListener.listener.id +
':' +
bulkListener.eventInfo.path.resolved;
if (!bulkListener.eventInfo.path.resolved) {
resolvedIdPath =
bulkListener.listener.id +
':' +
bulkListener.eventInfo.path.listener;
}
queue.push({
id: bulkListener.listener.id,
resolvedPath: bulkListener.eventInfo.path.resolved,
resolvedIdPath,
originalFn: bulkListener.listener.fn,
fn: () => {
bulkListener.listener.fn(bulkValue, bulkListener.eventInfo);
},
options: bulkListener.listener.options,
groupId: bulkListener.listener.groupId,
});
}
queue.push({
id: bulkListener.listener.id,
resolvedPath: bulkListener.eventInfo.path.resolved,
resolvedIdPath,
originalFn: bulkListener.listener.fn,
fn: () => {
bulkListener.listener.fn(bulkValue, bulkListener.eventInfo);
},
options: bulkListener.listener.options,
groupId: bulkListener.listener.groupId,
});
}

@@ -982,4 +967,4 @@ this.debugListener(time, bulkListener);

}
getSubscribedListeners(updatePath, newValue, options, type = 'update', originalPath = null) {
options = Object.assign({}, defaultUpdateOptions, options);
getSubscribedListeners(updatePath, newValue, options, type = "update", originalPath = null) {
options = Object.assign(Object.assign({}, defaultUpdateOptions), options);
const listeners = {};

@@ -1064,6 +1049,6 @@ for (let [listenerPath, listenersCollection] of this.listeners) {

}
notifySubscribedListeners(updatePath, newValue, options, type = 'update', originalPath = null) {
notifySubscribedListeners(updatePath, newValue, options, type = "update", originalPath = null) {
return this.getQueueNotifyListeners(this.getSubscribedListeners(updatePath, newValue, options, type, originalPath));
}
getNestedListeners(updatePath, newValue, options, type = 'update', originalPath = null) {
getNestedListeners(updatePath, newValue, options, type = "update", originalPath = null) {
const listeners = {};

@@ -1141,3 +1126,3 @@ for (let [listenerPath, listenersCollection] of this.listeners) {

if (listener.options.debug) {
console.log('[getNestedListeners] Listener was not fired because there was no match.', {
console.log("[getNestedListeners] Listener was not fired because there was no match.", {
listener,

@@ -1154,10 +1139,10 @@ listenersCollection,

}
notifyNestedListeners(updatePath, newValue, options, type = 'update', queue, originalPath = null) {
notifyNestedListeners(updatePath, newValue, options, type = "update", queue, originalPath = null) {
return this.getQueueNotifyListeners(this.getNestedListeners(updatePath, newValue, options, type, originalPath), queue);
}
getNotifyOnlyListeners(updatePath, newValue, options, type = 'update', originalPath = null) {
getNotifyOnlyListeners(updatePath, newValue, options, type = "update", originalPath = null) {
const listeners = {};
if (typeof options.only !== 'object' ||
if (typeof options.only !== "object" ||
!Array.isArray(options.only) ||
typeof options.only[0] === 'undefined' ||
typeof options.only[0] === "undefined" ||
!this.canBeNested(newValue)) {

@@ -1241,3 +1226,3 @@ return listeners;

}
notifyOnly(updatePath, newValue, options, type = 'update', originalPath = '') {
notifyOnly(updatePath, newValue, options, type = "update", originalPath = "") {
const queue = this.getQueueNotifyListeners(this.getNotifyOnlyListeners(updatePath, newValue, options, type, originalPath));

@@ -1247,7 +1232,7 @@ this.sortAndRunQueue(queue, updatePath);

canBeNested(newValue) {
return typeof newValue === 'object' && newValue !== null;
return typeof newValue === "object" && newValue !== null;
}
getUpdateValues(oldValue, split, fn) {
let newValue = fn;
if (typeof fn === 'function') {
if (typeof fn === "function") {
newValue = fn(this.pathGet(split, this.data));

@@ -1257,3 +1242,3 @@ }

}
wildcardNotify(groupedListenersPack, waitingPaths) {
wildcardNotify(groupedListenersPack) {
let queue = [];

@@ -1263,11 +1248,6 @@ for (const groupedListeners of groupedListenersPack) {

}
for (const path of waitingPaths) {
this.executeWaitingListeners(path);
}
this.jobsRunning--;
return queue;
}
wildcardUpdate(updatePath, fn, options = defaultUpdateOptions, multi = false) {
++this.jobsRunning;
options = Object.assign({}, defaultUpdateOptions, options);
options = Object.assign(Object.assign({}, defaultUpdateOptions), options);
const scanned = this.scan.get(updatePath);

@@ -1284,16 +1264,14 @@ const updated = {};

const groupedListenersPack = [];
const waitingPaths = [];
for (const path in updated) {
const newValue = updated[path];
if (options.only.length) {
groupedListenersPack.push(this.getNotifyOnlyListeners(path, newValue, options, 'update', updatePath));
groupedListenersPack.push(this.getNotifyOnlyListeners(path, newValue, options, "update", updatePath));
}
else {
groupedListenersPack.push(this.getSubscribedListeners(path, newValue, options, 'update', updatePath));
groupedListenersPack.push(this.getSubscribedListeners(path, newValue, options, "update", updatePath));
if (this.canBeNested(newValue)) {
groupedListenersPack.push(this.getNestedListeners(path, newValue, options, 'update', updatePath));
groupedListenersPack.push(this.getNestedListeners(path, newValue, options, "update", updatePath));
}
}
options.debug && this.options.log('Wildcard update', { path, newValue });
waitingPaths.push(path);
options.debug && this.options.log("Wildcard update", { path, newValue });
}

@@ -1303,26 +1281,15 @@ if (multi) {

return function () {
const queue = self.wildcardNotify(groupedListenersPack, waitingPaths);
const queue = self.wildcardNotify(groupedListenersPack);
self.sortAndRunQueue(queue, updatePath);
};
}
const queue = this.wildcardNotify(groupedListenersPack, waitingPaths);
const queue = this.wildcardNotify(groupedListenersPack);
this.sortAndRunQueue(queue, updatePath);
}
runUpdateQueue() {
if (this.destroyed)
return;
while (this.updateQueue.length &&
this.updateQueue.length < this.options.maxSimultaneousJobs) {
const params = this.updateQueue.shift();
params.options.queue = false; // prevent infinite loop
this.update(params.updatePath, params.fnOrValue, params.options, params.multi);
}
}
updateNotify(updatePath, newValue, options) {
const queue = this.notifySubscribedListeners(updatePath, newValue, options);
if (this.canBeNested(newValue)) {
this.notifyNestedListeners(updatePath, newValue, options, 'update', queue);
this.notifyNestedListeners(updatePath, newValue, options, "update", queue);
}
this.sortAndRunQueue(queue, updatePath);
this.executeWaitingListeners(updatePath);
}

@@ -1346,3 +1313,3 @@ updateNotifyAll(updateStack) {

if (this.canBeNested(current.newValue)) {
this.notifyNestedListeners(current.updatePath, value, current.options, 'update', queue);
this.notifyNestedListeners(current.updatePath, value, current.options, "update", queue);
}

@@ -1354,3 +1321,2 @@ }

this.notifyOnly(updatePath, newValue, options);
this.executeWaitingListeners(updatePath);
}

@@ -1369,26 +1335,9 @@ update(updatePath, fnOrValue, options = Object.assign({}, defaultUpdateOptions), multi = false) {

}
const jobsRunning = this.jobsRunning;
if ((this.options.queue || options.queue) && jobsRunning) {
if (jobsRunning > this.options.maxSimultaneousJobs) {
throw new Error('Maximal simultaneous jobs limit reached.');
}
this.updateQueue.push({ updatePath, fnOrValue, options, multi });
const result = Promise.resolve().then(() => {
this.runUpdateQueue();
});
if (multi) {
return function () {
return result;
};
}
return result;
}
if (this.isWildcard(updatePath)) {
return this.wildcardUpdate(updatePath, fnOrValue, options, multi);
}
++this.jobsRunning;
const split = this.split(updatePath);
const { oldValue, newValue } = this.getUpdateValues(this.pathGet(split, this.data), split, fnOrValue);
if (options.debug) {
this.options.log(`Updating ${updatePath} ${options.source ? `from ${options.source}` : ''}`, {
this.options.log(`Updating ${updatePath} ${options.source ? `from ${options.source}` : ""}`, {
oldValue,

@@ -1399,3 +1348,2 @@ newValue,

if (this.same(newValue, oldValue) && !options.force) {
--this.jobsRunning;
if (multi)

@@ -1408,5 +1356,4 @@ return function () {

this.pathSet(split, newValue, this.data);
options = Object.assign({}, defaultUpdateOptions, options);
options = Object.assign(Object.assign({}, defaultUpdateOptions), options);
if (options.only === null) {
--this.jobsRunning;
if (multi)

@@ -1417,3 +1364,2 @@ return function () { };

if (options.only.length) {
--this.jobsRunning;
if (multi) {

@@ -1429,3 +1375,2 @@ const self = this;

if (multi) {
--this.jobsRunning;
const self = this;

@@ -1437,3 +1382,2 @@ return function multiUpdate() {

this.updateNotify(updatePath, newValue, options);
--this.jobsRunning;
return newValue;

@@ -1462,3 +1406,3 @@ }

let value = fnOrValue;
if (typeof value === 'function') {
if (typeof value === "function") {
value = value(self.pathGet(split, self.data));

@@ -1520,3 +1464,3 @@ }

return;
if (typeof userPath === 'undefined' || userPath === '') {
if (typeof userPath === "undefined" || userPath === "") {
return this.data;

@@ -1543,3 +1487,3 @@ }

return false;
if (typeof pathOrListenerFunction === 'function') {
if (typeof pathOrListenerFunction === "function") {
return this.isMutedListener(pathOrListenerFunction);

@@ -1568,3 +1512,3 @@ }

mute(pathOrListenerFunction) {
if (typeof pathOrListenerFunction === 'function') {
if (typeof pathOrListenerFunction === "function") {
return this.mutedListeners.add(pathOrListenerFunction);

@@ -1575,3 +1519,3 @@ }

unmute(pathOrListenerFunction) {
if (typeof pathOrListenerFunction === 'function') {
if (typeof pathOrListenerFunction === "function") {
return this.mutedListeners.delete(pathOrListenerFunction);

@@ -1583,3 +1527,3 @@ }

if (listener.options.debug) {
this.options.log('listener subscribed', {
this.options.log("listener subscribed", {
listenerPath,

@@ -1592,5 +1536,4 @@ listener,

debugListener(time, groupedListener) {
if (groupedListener.eventInfo.options.debug ||
groupedListener.listener.options.debug) {
this.options.log('Listener fired', {
if (groupedListener.eventInfo.options.debug || groupedListener.listener.options.debug) {
this.options.log("Listener fired", {
time: Date.now() - time,

@@ -1602,10 +1545,7 @@ info: groupedListener,

debugTime(groupedListener) {
return groupedListener.listener.options.debug ||
groupedListener.eventInfo.options.debug
? Date.now()
: 0;
return groupedListener.listener.options.debug || groupedListener.eventInfo.options.debug ? Date.now() : 0;
}
startTrace(name, additionalData = null) {
this.traceId++;
const id = this.traceId + ':' + name;
const id = this.traceId + ":" + name;
this.traceMap.set(id, {

@@ -1644,2 +1584,2 @@ id,

export default DeepState;
export { DeepState as default };

@@ -1,4 +0,4 @@

import WildcardObject from './wildcard-object-scan';
import Path from './ObjectPath';
import init, { is_match } from './wildcard_matcher.js';
import WildcardObject from "./wildcard-object-scan";
import Path from "./ObjectPath";
import init, { is_match } from "./wildcard_matcher.js";

@@ -20,6 +20,3 @@ export interface PathInfo {

export type ListenerFunction = (
value: any,
eventInfo: ListenerFunctionEventInfo
) => void;
export type ListenerFunction = (value: any, eventInfo: ListenerFunctionEventInfo) => void;
export type Match = (path: string, debug?: boolean) => boolean;

@@ -34,3 +31,2 @@

experimentalMatch?: boolean;
queue?: boolean;
maxSimultaneousJobs?: number;

@@ -49,3 +45,2 @@ maxQueueRuns?: number;

data?: any;
queue?: boolean;
ignore?: string[];

@@ -177,6 +172,5 @@ group?: boolean;

only: [],
source: '',
source: "",
debug: false,
data: undefined,
queue: false,
force: false,

@@ -186,7 +180,3 @@ };

export interface Multi {
update: (
updatePath: string,
fn: Updater | any,
options?: UpdateOptions
) => Multi;
update: (updatePath: string, fn: Updater | any, options?: UpdateOptions) => Multi;
done: () => void;

@@ -200,2 +190,16 @@ getStack: () => UpdateStack[];

/**
* Is object - helper function to determine if specified variable is an object
*
* @param {any} item
* @returns {boolean}
*/
function isObject(item: unknown) {
return item && typeof item === "object" && item !== null && item.constructor && item.constructor.name === "Object";
}
export interface UnknownObject {
[key: string]: unknown;
}
function getDefaultOptions(): Options {

@@ -211,3 +215,2 @@ return {

experimentalMatch: false,
queue: false,
maxSimultaneousJobs: 1000,

@@ -223,18 +226,9 @@ maxQueueRuns: 1000,

debug: false,
source: '',
source: "",
data: undefined,
queue: false,
group: false,
};
const handler = {
get(obj, prop) {},
set(obj, prop, value) {
return true;
},
};
class DeepState<T> {
private listeners: Listeners;
private waitingListeners: WaitingListeners;
private data: T | object;

@@ -246,12 +240,6 @@ private options: Options;

private scan: any;
private jobsRunning = 0;
private updateQueue = [];
private subscribeQueue = [];
private listenersIgnoreCache: WeakMap<
Listener,
{ truthy: string[]; falsy: string[] }
> = new WeakMap();
private listenersIgnoreCache: WeakMap<Listener, { truthy: string[]; falsy: string[] }> = new WeakMap();
private is_match: any;
private destroyed = false;
private queueRuns = 0;
private resolved: Promise<unknown> | any;

@@ -267,9 +255,48 @@ private muted: Set<string>;

private collections: number = 0;
public proxy;
private proxyPath = [];
private handler = {
get: (obj, prop) => {
if (obj.hasOwnProperty(prop)) this.proxyPath.push(prop);
return obj[prop];
},
set: (obj, prop, value) => {
this.proxyPath.push(prop);
const path = this.proxyPath.join(".");
if (typeof value === "function") {
value = value(obj[prop]);
}
let final = value;
if (isObject(value)) {
final = new Proxy(this.mergeDeepProxy({}, value), this.handler);
} else if (Array.isArray(value)) {
final = new Proxy(this.mergeDeepProxy([], value), this.handler);
}
this.proxyPath = [];
this.update(path, final);
obj[prop] = final;
return true;
},
};
public proxy: T;
/**
* @property $$$ proxy shorthand
*/
public $$$: T;
constructor(data: T | object = {}, options: Options = {}) {
this.listeners = new Map();
this.waitingListeners = new Map();
this.handler.get = this.handler.get.bind(this);
this.handler.set = this.handler.set.bind(this);
const self = this;
this.data = data;
this.proxy = new Proxy(this.data, handler);
this.proxy = new Proxy(this.mergeDeepProxy({}, data) as object, {
get(obj, prop) {
if (obj.hasOwnProperty(prop)) self.proxyPath = [prop];
return obj[prop];
},
set(obj, prop, value) {
return self.handler.set(obj, prop, value);
},
}) as unknown as T;
this.$$$ = this.proxy;
this.options = { ...getDefaultOptions(), ...options };

@@ -286,19 +313,59 @@ this.id = 0;

this.mutedListeners = new Set();
this.scan = new WildcardObject<T>(
this.data,
this.options.delimiter,
this.options.wildcard
);
this.scan = new WildcardObject<T>(this.data, this.options.delimiter, this.options.wildcard);
this.destroyed = false;
}
private mergeDeepProxy<T>(target: any, ...sources: any[]): T {
const source = sources.shift();
if (isObject(target) && isObject(source)) {
const targetValMain = {};
for (const key in source) {
if (isObject(source[key])) {
targetValMain[key] = new Proxy(this.mergeDeepProxy({}, source[key]), this.handler);
} else if (Array.isArray(source[key])) {
const targetVal = new Array(source[key].length);
let index = 0;
for (let item of source[key]) {
if (isObject(item) || Array.isArray(item)) {
targetVal[index] = new Proxy(this.mergeDeepProxy({}, item), this.handler);
} else {
targetVal[index] = item;
}
index++;
}
targetValMain[key] = new Proxy(targetVal, this.handler);
} else {
targetValMain[key] = source[key];
}
}
if (sources.length) {
target = new Proxy(targetValMain, this.handler);
} else {
target = targetValMain;
}
} else if (Array.isArray(source)) {
const targetVal = new Array(source.length);
for (let i = 0, len = source.length; i < len; i++) {
if (isObject(source[i]) || Array.isArray(source[i])) {
targetVal[i] = this.mergeDeepProxy(source[i]);
} else {
targetVal[i] = source[i];
}
}
if (sources.length) {
target = new Proxy(targetVal, this.handler);
} else {
target = targetVal;
}
}
if (!sources.length) {
return target;
}
return this.mergeDeepProxy(target, ...sources);
}
public async loadWasmMatcher(pathToWasmFile: string) {
await init(pathToWasmFile);
this.is_match = is_match;
this.scan = new WildcardObject(
this.data,
this.options.delimiter,
this.options.wildcard,
this.is_match
);
this.scan = new WildcardObject(this.data, this.options.delimiter, this.options.wildcard, this.is_match);
}

@@ -308,4 +375,3 @@

return (
(['number', 'string', 'undefined', 'boolean'].includes(typeof newValue) ||
newValue === null) &&
(["number", "string", "undefined", "boolean"].includes(typeof newValue) || newValue === null) &&
oldValue === newValue

@@ -323,19 +389,11 @@ );

this.listeners = new Map();
this.updateQueue = [];
this.jobsRunning = 0;
}
private match(
first: string,
second: string,
nested: boolean = true
): boolean {
private match(first: string, second: string, nested: boolean = true): boolean {
if (this.is_match) return this.is_match(first, second);
if (first === second) return true;
if (first === this.options.wildcard || second === this.options.wildcard)
return true;
if (first === this.options.wildcard || second === this.options.wildcard) return true;
if (
!nested &&
this.getIndicesCount(this.options.delimiter, first) <
this.getIndicesCount(this.options.delimiter, second)
this.getIndicesCount(this.options.delimiter, first) < this.getIndicesCount(this.options.delimiter, second)
) {

@@ -382,6 +440,3 @@ // first < second because first is a listener path and may be longer but not shorter

if (longer === shorter) return longer;
const shorterPartsLen = this.getIndicesCount(
this.options.delimiter,
shorter
);
const shorterPartsLen = this.getIndicesCount(this.options.delimiter, shorter);
const longerParts = this.getIndicesOf(this.options.delimiter, longer);

@@ -400,3 +455,3 @@ return longer.substr(0, longerParts[shorterPartsLen]);

private split(path: string) {
return path === '' ? [] : path.split(this.options.delimiter);
return path === "" ? [] : path.split(this.options.delimiter);
}

@@ -413,5 +468,3 @@

private cleanNotRecursivePath(path: string): string {
return this.isNotRecursive(path)
? path.substring(0, path.length - 1)
: path;
return this.isNotRecursive(path) ? path.substring(0, path.length - 1) : path;
}

@@ -424,3 +477,3 @@

private getParamsInfo(path: string): ParamsInfo {
let paramsInfo: ParamsInfo = { replaced: '', original: path, params: {} };
let paramsInfo: ParamsInfo = { replaced: "", original: path, params: {} };
let partIndex = 0;

@@ -431,9 +484,6 @@ let fullReplaced = [];

original: part,
replaced: '',
name: '',
replaced: "",
name: "",
};
const reg = new RegExp(
`\\${this.options.param}([^\\${this.options.delimiter}\\${this.options.param}]+)`,
'g'
);
const reg = new RegExp(`\\${this.options.param}([^\\${this.options.delimiter}\\${this.options.param}]+)`, "g");
let param = reg.exec(part);

@@ -449,6 +499,3 @@ if (param) {

reg.lastIndex = 0;
paramsInfo.params[partIndex].replaced = part.replace(
reg,
this.options.wildcard
);
paramsInfo.params[partIndex].replaced = part.replace(reg, this.options.wildcard);
fullReplaced.push(paramsInfo.params[partIndex].replaced);

@@ -474,45 +521,2 @@ partIndex++;

public waitForAll(userPaths: string[], fn: WaitingListenerFunction) {
const paths = {};
for (let path of userPaths) {
paths[path] = { dirty: false };
if (this.hasParams(path)) {
paths[path].paramsInfo = this.getParamsInfo(path);
}
paths[path].isWildcard = this.isWildcard(path);
paths[path].isRecursive = !this.isNotRecursive(path);
}
this.waitingListeners.set(userPaths, { fn, paths });
fn(paths);
return function unsubscribe() {
this.waitingListeners.delete(userPaths);
};
}
private executeWaitingListeners(updatePath: string) {
if (this.destroyed) return;
for (const waitingListener of this.waitingListeners.values()) {
const { fn, paths } = waitingListener;
let dirty = 0;
let all = 0;
for (let path in paths) {
const pathInfo = paths[path];
let match = false;
if (pathInfo.isRecursive) updatePath = this.cutPath(updatePath, path);
if (pathInfo.isWildcard && this.match(path, updatePath)) match = true;
if (updatePath === path) match = true;
if (match) {
pathInfo.dirty = true;
}
if (pathInfo.dirty) {
dirty++;
}
all++;
}
if (dirty === all) {
fn(paths);
}
}
}
public subscribeAll(

@@ -562,6 +566,3 @@ userPaths: string[],

private getCleanListener(
fn: ListenerFunction,
options: ListenerOptions = defaultListenerOptions
): Listener {
private getCleanListener(fn: ListenerFunction, options: ListenerOptions = defaultListenerOptions): Listener {
return {

@@ -574,7 +575,3 @@ fn,

private getListenerCollectionMatch(
listenerPath: string,
isRecursive: boolean,
isWildcard: boolean
) {
private getListenerCollectionMatch(listenerPath: string, isRecursive: boolean, isWildcard: boolean) {
listenerPath = this.cleanNotRecursivePath(listenerPath);

@@ -587,9 +584,6 @@ const self = this;

} else {
scopedListenerPath = self.cutPath(
self.cleanNotRecursivePath(listenerPath),
path
);
scopedListenerPath = self.cutPath(self.cleanNotRecursivePath(listenerPath), path);
}
if (debug) {
console.log('[getListenerCollectionMatch]', {
console.log("[getListenerCollectionMatch]", {
listenerPath,

@@ -602,4 +596,3 @@ scopedListenerPath,

}
if (isWildcard && self.match(scopedListenerPath, path, isRecursive))
return true;
if (isWildcard && self.match(scopedListenerPath, path, isRecursive)) return true;
return scopedListenerPath === path;

@@ -609,6 +602,3 @@ };

private getListenersCollection(
listenerPath: string,
listener: Listener
): ListenersCollection {
private getListenersCollection(listenerPath: string, listener: Listener): ListenersCollection {
if (this.listeners.has(listenerPath)) {

@@ -638,7 +628,3 @@ let listenersCollection = this.listeners.get(listenerPath);

...collCfg,
match: this.getListenerCollectionMatch(
collCfg.path,
collCfg.isRecursive,
collCfg.isWildcard
),
match: this.getListenerCollectionMatch(collCfg.path, collCfg.isRecursive, collCfg.isWildcard),
});

@@ -663,11 +649,7 @@ this.id++;

if (this.destroyed) return () => {};
this.jobsRunning++;
const type = 'subscribe';
const type = "subscribe";
let listener = this.getCleanListener(fn, options);
if (options.group) listener.groupId = subscribeAllOptions.groupId;
this.listenersIgnoreCache.set(listener, { truthy: [], falsy: [] });
const listenersCollection = this.getListenersCollection(
listenerPath,
listener
);
const listenersCollection = this.getListenersCollection(listenerPath, listener);
if (options.debug) {

@@ -677,7 +659,3 @@ console.log();

listenersCollection.count++;
if (
!options.group ||
(options.group &&
subscribeAllOptions.all.length - 1 === subscribeAllOptions.index)
) {
if (!options.group || (options.group && subscribeAllOptions.all.length - 1 === subscribeAllOptions.index)) {
const cleanPath = this.cleanNotRecursivePath(listenersCollection.path);

@@ -746,3 +724,2 @@ if (!listenersCollection.isWildcard) {

this.debugSubscribe(listener, listenersCollection, listenerPath);
this.jobsRunning--;
return this.unsubscribe(listenerPath, this.id);

@@ -766,28 +743,10 @@ }

if (this.subscribeQueue.length === 0) return;
if (this.jobsRunning === 0) {
this.queueRuns = 0;
const queue = [...this.subscribeQueue];
for (let i = 0, len = queue.length; i < len; i++) {
queue[i]();
}
this.subscribeQueue.length = 0;
} else {
this.queueRuns++;
if (this.queueRuns >= this.options.maxQueueRuns) {
this.queueRuns = 0;
throw new Error('Maximal number of queue runs exhausted.');
} else {
Promise.resolve()
.then(() => this.runQueuedListeners())
.catch((e) => {
throw e;
});
}
const queue = [...this.subscribeQueue];
for (let i = 0, len = queue.length; i < len; i++) {
queue[i]();
}
this.subscribeQueue.length = 0;
}
private getQueueNotifyListeners(
groupedListeners: GroupedListeners,
queue: Queue[] = []
): Queue[] {
private getQueueNotifyListeners(groupedListeners: GroupedListeners, queue: Queue[] = []): Queue[] {
for (const path in groupedListeners) {

@@ -798,11 +757,5 @@ if (this.isMuted(path)) continue;

let alreadyInQueue = false;
let resolvedIdPath =
singleListener.listener.id +
':' +
singleListener.eventInfo.path.resolved;
let resolvedIdPath = singleListener.listener.id + ":" + singleListener.eventInfo.path.resolved;
if (!singleListener.eventInfo.path.resolved) {
resolvedIdPath =
singleListener.listener.id +
':' +
singleListener.eventInfo.path.listener;
resolvedIdPath = singleListener.listener.id + ":" + singleListener.eventInfo.path.listener;
}

@@ -820,35 +773,17 @@ for (const excludedListener of queue) {

if (!this.isMuted(singleListener.listener.fn)) {
if (singleListener.listener.options.queue && this.jobsRunning) {
this.subscribeQueue.push(() => {
singleListener.listener.fn(
singleListener.value(),
singleListener.eventInfo
);
});
} else {
let resolvedIdPath =
singleListener.listener.id +
':' +
singleListener.eventInfo.path.resolved;
if (!singleListener.eventInfo.path.resolved) {
resolvedIdPath =
singleListener.listener.id +
':' +
singleListener.eventInfo.path.listener;
}
queue.push({
id: singleListener.listener.id,
resolvedPath: singleListener.eventInfo.path.resolved,
resolvedIdPath,
originalFn: singleListener.listener.fn,
fn: () => {
singleListener.listener.fn(
singleListener.value(),
singleListener.eventInfo
);
},
options: singleListener.listener.options,
groupId: singleListener.listener.groupId,
});
let resolvedIdPath = singleListener.listener.id + ":" + singleListener.eventInfo.path.resolved;
if (!singleListener.eventInfo.path.resolved) {
resolvedIdPath = singleListener.listener.id + ":" + singleListener.eventInfo.path.listener;
}
queue.push({
id: singleListener.listener.id,
resolvedPath: singleListener.eventInfo.path.resolved,
resolvedIdPath,
originalFn: singleListener.listener.fn,
fn: () => {
singleListener.listener.fn(singleListener.value(), singleListener.eventInfo);
},
options: singleListener.listener.options,
groupId: singleListener.listener.groupId,
});
}

@@ -873,33 +808,17 @@ this.debugListener(time, singleListener);

if (!this.isMuted(bulkListener.listener.fn)) {
if (bulkListener.listener.options.queue && this.jobsRunning) {
this.subscribeQueue.push(() => {
if (!this.jobsRunning) {
bulkListener.listener.fn(bulkValue, bulkListener.eventInfo);
return true;
}
return false;
});
} else {
let resolvedIdPath =
bulkListener.listener.id +
':' +
bulkListener.eventInfo.path.resolved;
if (!bulkListener.eventInfo.path.resolved) {
resolvedIdPath =
bulkListener.listener.id +
':' +
bulkListener.eventInfo.path.listener;
}
queue.push({
id: bulkListener.listener.id,
resolvedPath: bulkListener.eventInfo.path.resolved,
resolvedIdPath,
originalFn: bulkListener.listener.fn,
fn: () => {
bulkListener.listener.fn(bulkValue, bulkListener.eventInfo);
},
options: bulkListener.listener.options,
groupId: bulkListener.listener.groupId,
});
let resolvedIdPath = bulkListener.listener.id + ":" + bulkListener.eventInfo.path.resolved;
if (!bulkListener.eventInfo.path.resolved) {
resolvedIdPath = bulkListener.listener.id + ":" + bulkListener.eventInfo.path.listener;
}
queue.push({
id: bulkListener.listener.id,
resolvedPath: bulkListener.eventInfo.path.resolved,
resolvedIdPath,
originalFn: bulkListener.listener.fn,
fn: () => {
bulkListener.listener.fn(bulkValue, bulkListener.eventInfo);
},
options: bulkListener.listener.options,
groupId: bulkListener.listener.groupId,
});
}

@@ -935,3 +854,3 @@ this.debugListener(time, bulkListener);

options: UpdateOptions,
type: string = 'update',
type: string = "update",
originalPath: string = null

@@ -948,4 +867,3 @@ ): GroupedListeners {

const cutPath = this.cutPath(updatePath, listenerPath);
const traverse =
listenersCollection.isRecursive || listenersCollection.isWildcard;
const traverse = listenersCollection.isRecursive || listenersCollection.isWildcard;
const value = traverse ? () => this.get(cutPath) : () => newValue;

@@ -956,9 +874,6 @@ const bulkValue = [{ value, path: updatePath, params }];

if (listener.options.debug) {
console.log(
`[getSubscribedListeners] Listener was not fired because it was ignored.`,
{
listener,
listenersCollection,
}
);
console.log(`[getSubscribedListeners] Listener was not fired because it was ignored.`, {
listener,
listenersCollection,
});
}

@@ -1009,10 +924,7 @@ continue;

showMatch = true;
console.log(
`[getSubscribedListeners] Listener was not fired because there was no match.`,
{
listener,
listenersCollection,
updatePath,
}
);
console.log(`[getSubscribedListeners] Listener was not fired because there was no match.`, {
listener,
listenersCollection,
updatePath,
});
}

@@ -1032,14 +944,6 @@ }

options: UpdateOptions,
type: string = 'update',
type: string = "update",
originalPath: string = null
): Queue[] {
return this.getQueueNotifyListeners(
this.getSubscribedListeners(
updatePath,
newValue,
options,
type,
originalPath
)
);
return this.getQueueNotifyListeners(this.getSubscribedListeners(updatePath, newValue, options, type, originalPath));
}

@@ -1051,3 +955,3 @@

options: UpdateOptions,
type: string = 'update',
type: string = "update",
originalPath: string = null

@@ -1061,10 +965,6 @@ ): GroupedListeners {

if (this.match(currentCutPath, updatePath)) {
const restPath = this.trimPath(
listenerPath.substr(currentCutPath.length)
const restPath = this.trimPath(listenerPath.substr(currentCutPath.length));
const wildcardNewValues = new WildcardObject(newValue, this.options.delimiter, this.options.wildcard).get(
restPath
);
const wildcardNewValues = new WildcardObject(
newValue,
this.options.delimiter,
this.options.wildcard
).get(restPath);
const params = listenersCollection.paramsInfo

@@ -1077,5 +977,3 @@ ? this.getParams(listenersCollection.paramsInfo, updatePath)

const value = () => wildcardNewValues[currentRestPath];
const fullPath = [updatePath, currentRestPath].join(
this.options.delimiter
);
const fullPath = [updatePath, currentRestPath].join(this.options.delimiter);
for (const [listenerId, listener] of listenersCollection.listeners) {

@@ -1133,11 +1031,8 @@ const eventInfo = {

if (listener.options.debug) {
console.log(
'[getNestedListeners] Listener was not fired because there was no match.',
{
listener,
listenersCollection,
currentCutPath,
updatePath,
}
);
console.log("[getNestedListeners] Listener was not fired because there was no match.", {
listener,
listenersCollection,
currentCutPath,
updatePath,
});
}

@@ -1154,3 +1049,3 @@ }

options: UpdateOptions,
type: string = 'update',
type: string = "update",
queue: Queue[],

@@ -1160,9 +1055,3 @@ originalPath: string = null

return this.getQueueNotifyListeners(
this.getNestedListeners(
updatePath,
newValue,
options,
type,
originalPath
),
this.getNestedListeners(updatePath, newValue, options, type, originalPath),
queue

@@ -1176,3 +1065,3 @@ );

options: UpdateOptions,
type: string = 'update',
type: string = "update",
originalPath: string = null

@@ -1182,5 +1071,5 @@ ): GroupedListeners {

if (
typeof options.only !== 'object' ||
typeof options.only !== "object" ||
!Array.isArray(options.only) ||
typeof options.only[0] === 'undefined' ||
typeof options.only[0] === "undefined" ||
!this.canBeNested(newValue)

@@ -1191,7 +1080,5 @@ ) {

for (const notifyPath of options.only) {
const wildcardScanNewValue = new WildcardObject(
newValue,
this.options.delimiter,
this.options.wildcard
).get(notifyPath);
const wildcardScanNewValue = new WildcardObject(newValue, this.options.delimiter, this.options.wildcard).get(
notifyPath
);
listeners[notifyPath] = { bulk: [], single: [] };

@@ -1222,7 +1109,3 @@ for (const wildcardPath in wildcardScanNewValue) {

if (listener.options.bulk) {
if (
!listeners[notifyPath].bulk.some(
(bulkListener) => bulkListener.listener === listener
)
) {
if (!listeners[notifyPath].bulk.some((bulkListener) => bulkListener.listener === listener)) {
listeners[notifyPath].bulk.push({

@@ -1279,13 +1162,7 @@ listener,

options: UpdateOptions,
type: string = 'update',
originalPath: string = ''
type: string = "update",
originalPath: string = ""
) {
const queue = this.getQueueNotifyListeners(
this.getNotifyOnlyListeners(
updatePath,
newValue,
options,
type,
originalPath
)
this.getNotifyOnlyListeners(updatePath, newValue, options, type, originalPath)
);

@@ -1296,3 +1173,3 @@ this.sortAndRunQueue(queue, updatePath);

private canBeNested(newValue): boolean {
return typeof newValue === 'object' && newValue !== null;
return typeof newValue === "object" && newValue !== null;
}

@@ -1302,3 +1179,3 @@

let newValue = fn;
if (typeof fn === 'function') {
if (typeof fn === "function") {
newValue = fn(this.pathGet(split, this.data));

@@ -1309,3 +1186,3 @@ }

private wildcardNotify(groupedListenersPack, waitingPaths) {
private wildcardNotify(groupedListenersPack) {
let queue = [];

@@ -1315,6 +1192,2 @@ for (const groupedListeners of groupedListenersPack) {

}
for (const path of waitingPaths) {
this.executeWaitingListeners(path);
}
this.jobsRunning--;
return queue;

@@ -1329,3 +1202,2 @@ }

) {
++this.jobsRunning;
options = { ...defaultUpdateOptions, ...options };

@@ -1336,7 +1208,3 @@ const scanned = this.scan.get(updatePath);

const split = this.split(path);
const { oldValue, newValue } = this.getUpdateValues(
scanned[path],
split,
fn
);
const { oldValue, newValue } = this.getUpdateValues(scanned[path], split, fn);
if (!this.same(newValue, oldValue) || options.force) {

@@ -1349,39 +1217,13 @@ this.pathSet(split, newValue, this.data);

const groupedListenersPack = [];
const waitingPaths = [];
for (const path in updated) {
const newValue = updated[path];
if (options.only.length) {
groupedListenersPack.push(
this.getNotifyOnlyListeners(
path,
newValue,
options,
'update',
updatePath
)
);
groupedListenersPack.push(this.getNotifyOnlyListeners(path, newValue, options, "update", updatePath));
} else {
groupedListenersPack.push(
this.getSubscribedListeners(
path,
newValue,
options,
'update',
updatePath
)
);
groupedListenersPack.push(this.getSubscribedListeners(path, newValue, options, "update", updatePath));
if (this.canBeNested(newValue)) {
groupedListenersPack.push(
this.getNestedListeners(
path,
newValue,
options,
'update',
updatePath
)
);
groupedListenersPack.push(this.getNestedListeners(path, newValue, options, "update", updatePath));
}
}
options.debug && this.options.log('Wildcard update', { path, newValue });
waitingPaths.push(path);
options.debug && this.options.log("Wildcard update", { path, newValue });
}

@@ -1391,44 +1233,16 @@ if (multi) {

return function () {
const queue = self.wildcardNotify(groupedListenersPack, waitingPaths);
const queue = self.wildcardNotify(groupedListenersPack);
self.sortAndRunQueue(queue, updatePath);
};
}
const queue = this.wildcardNotify(groupedListenersPack, waitingPaths);
const queue = this.wildcardNotify(groupedListenersPack);
this.sortAndRunQueue(queue, updatePath);
}
private runUpdateQueue() {
if (this.destroyed) return;
while (
this.updateQueue.length &&
this.updateQueue.length < this.options.maxSimultaneousJobs
) {
const params = this.updateQueue.shift();
params.options.queue = false; // prevent infinite loop
this.update(
params.updatePath,
params.fnOrValue,
params.options,
params.multi
);
}
}
private updateNotify(
updatePath: string,
newValue: unknown,
options: UpdateOptions
) {
private updateNotify(updatePath: string, newValue: unknown, options: UpdateOptions) {
const queue = this.notifySubscribedListeners(updatePath, newValue, options);
if (this.canBeNested(newValue)) {
this.notifyNestedListeners(
updatePath,
newValue,
options,
'update',
queue
);
this.notifyNestedListeners(updatePath, newValue, options, "update", queue);
}
this.sortAndRunQueue(queue, updatePath);
this.executeWaitingListeners(updatePath);
}

@@ -1451,17 +1265,5 @@

}
queue = queue.concat(
this.notifySubscribedListeners(
current.updatePath,
value,
current.options
)
);
queue = queue.concat(this.notifySubscribedListeners(current.updatePath, value, current.options));
if (this.canBeNested(current.newValue)) {
this.notifyNestedListeners(
current.updatePath,
value,
current.options,
'update',
queue
);
this.notifyNestedListeners(current.updatePath, value, current.options, "update", queue);
}

@@ -1474,3 +1276,2 @@ }

this.notifyOnly(updatePath, newValue, options);
this.executeWaitingListeners(updatePath);
}

@@ -1494,42 +1295,15 @@

}
const jobsRunning = this.jobsRunning;
if ((this.options.queue || options.queue) && jobsRunning) {
if (jobsRunning > this.options.maxSimultaneousJobs) {
throw new Error('Maximal simultaneous jobs limit reached.');
}
this.updateQueue.push({ updatePath, fnOrValue, options, multi });
const result = Promise.resolve().then(() => {
this.runUpdateQueue();
});
if (multi) {
return function () {
return result;
};
}
return result;
}
if (this.isWildcard(updatePath)) {
return this.wildcardUpdate(updatePath, fnOrValue, options, multi);
}
++this.jobsRunning;
const split = this.split(updatePath);
const { oldValue, newValue } = this.getUpdateValues(
this.pathGet(split, this.data),
split,
fnOrValue
);
const { oldValue, newValue } = this.getUpdateValues(this.pathGet(split, this.data), split, fnOrValue);
if (options.debug) {
this.options.log(
`Updating ${updatePath} ${
options.source ? `from ${options.source}` : ''
}`,
{
oldValue,
newValue,
}
);
this.options.log(`Updating ${updatePath} ${options.source ? `from ${options.source}` : ""}`, {
oldValue,
newValue,
});
}
if (this.same(newValue, oldValue) && !options.force) {
--this.jobsRunning;
if (multi)

@@ -1541,7 +1315,5 @@ return function () {

}
this.pathSet(split, newValue, this.data);
options = { ...defaultUpdateOptions, ...options };
if (options.only === null) {
--this.jobsRunning;
if (multi) return function () {};

@@ -1551,3 +1323,2 @@ return newValue;

if (options.only.length) {
--this.jobsRunning;
if (multi) {

@@ -1563,3 +1334,2 @@ const self = this;

if (multi) {
--this.jobsRunning;
const self = this;

@@ -1571,3 +1341,2 @@ return function multiUpdate() {

this.updateNotify(updatePath, newValue, options);
--this.jobsRunning;
return newValue;

@@ -1592,11 +1361,7 @@ }

const multiObject: Multi = {
update(
updatePath: string,
fnOrValue: Updater | any,
options: UpdateOptions = defaultUpdateOptions
) {
update(updatePath: string, fnOrValue: Updater | any, options: UpdateOptions = defaultUpdateOptions) {
if (grouped) {
const split = self.split(updatePath);
let value = fnOrValue;
if (typeof value === 'function') {
if (typeof value === "function") {
value = value(self.pathGet(split, self.data));

@@ -1659,3 +1424,3 @@ }

if (this.destroyed) return;
if (typeof userPath === 'undefined' || userPath === '') {
if (typeof userPath === "undefined" || userPath === "") {
return this.data;

@@ -1684,3 +1449,3 @@ }

if (!this.options.useMute) return false;
if (typeof pathOrListenerFunction === 'function') {
if (typeof pathOrListenerFunction === "function") {
return this.isMutedListener(pathOrListenerFunction);

@@ -1707,3 +1472,3 @@ }

public mute(pathOrListenerFunction: string | ListenerFunction) {
if (typeof pathOrListenerFunction === 'function') {
if (typeof pathOrListenerFunction === "function") {
return this.mutedListeners.add(pathOrListenerFunction);

@@ -1715,3 +1480,3 @@ }

public unmute(pathOrListenerFunction: string | ListenerFunction) {
if (typeof pathOrListenerFunction === 'function') {
if (typeof pathOrListenerFunction === "function") {
return this.mutedListeners.delete(pathOrListenerFunction);

@@ -1722,9 +1487,5 @@ }

private debugSubscribe(
listener: Listener,
listenersCollection: ListenersCollection,
listenerPath: string
) {
private debugSubscribe(listener: Listener, listenersCollection: ListenersCollection, listenerPath: string) {
if (listener.options.debug) {
this.options.log('listener subscribed', {
this.options.log("listener subscribed", {
listenerPath,

@@ -1738,7 +1499,4 @@ listener,

private debugListener(time: number, groupedListener: GroupedListener) {
if (
groupedListener.eventInfo.options.debug ||
groupedListener.listener.options.debug
) {
this.options.log('Listener fired', {
if (groupedListener.eventInfo.options.debug || groupedListener.listener.options.debug) {
this.options.log("Listener fired", {
time: Date.now() - time,

@@ -1751,6 +1509,3 @@ info: groupedListener,

private debugTime(groupedListener: GroupedListener): number {
return groupedListener.listener.options.debug ||
groupedListener.eventInfo.options.debug
? Date.now()
: 0;
return groupedListener.listener.options.debug || groupedListener.eventInfo.options.debug ? Date.now() : 0;
}

@@ -1760,3 +1515,3 @@

this.traceId++;
const id = this.traceId + ':' + name;
const id = this.traceId + ":" + name;
this.traceMap.set(id, {

@@ -1763,0 +1518,0 @@ id,

"use strict";
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
return {
if (o && typeof o.length === "number") return {
next: function () {

@@ -11,2 +11,3 @@ if (o && i >= o.length) o = void 0;

};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};

@@ -13,0 +14,0 @@ exports.__esModule = true;

{
"name": "deep-state-observer",
"version": "3.26.9",
"version": "4.0.0",
"description": "Deep state observer is an state management library that will fire listeners only when specified object node (which also can be a wildcard) was changed.",

@@ -5,0 +5,0 @@ "main": "index.cjs.js",

@@ -87,2 +87,31 @@ [![GitHub license](https://img.shields.io/github/license/neuronetio/deep-state-observer?style=flat-square)](https://github.com/neuronetio/deep-state-observer/blob/master/LICENSE)

## Update and proxy
You can use proxy instead of `state.update` function.
Proxy is better because values are linted;
```js
const state = new State({ x: { y: { z: 10 } } });
state.update("x.y.z", 20);
// is equivalent of
state.proxy.x.y.z = 20;
// is equivalent of (state.$$$ is just shorthand for state.proxy)
state.$$$.x.y.z = 20;
// and with function
state.update("x.y.z", (value) => {
return value + 10;
});
// is equivalent of
state.proxy.x.y.z = (value) => {
return value + 10;
};
// is equivalent of
state.$$$.x.y.z = (value) => {
return value + 10;
};
```
## Wildcards

@@ -406,22 +435,2 @@

## queue
You can wait with update until all other tasks are finished.
```javascript
const state = new State({ test: 1, other: "x" });
const values = [];
state.subscribe("test", (value) => {
state.update("other", "xx", { queue: true });
values.push(value);
});
// values.length === 1 & values[0] === 1
state.update("test", 2);
// values.length ===2 & values[1] === 2
// state.get('other') === 'x'
setTimeout(() => {
// state.get('other') === 'xx' because updating 'other' was waiting for 'test' listener to end
}, 100);
```
## multi

@@ -428,0 +437,0 @@

@@ -48,2 +48,16 @@ import resolve from "@rollup/plugin-node-resolve";

},
{
input: "test.ts",
output: {
file: "test.esm.js",
format: "esm",
},
plugins: [
typescript(),
resolve({
browser: true,
}),
commonjs({ extensions: [".js", ".ts"] }),
],
},
];
"use strict";
// forked from https://github.com/joonhocho/superwild
exports.__esModule = true;
exports.Match = void 0;
function Matcher(pattern, wchar) {

@@ -5,0 +6,0 @@ if (wchar === void 0) { wchar = '*'; }

@@ -895,96 +895,2 @@ const State = require("../index.cjs.js");

it("should execute listeners only when all values where changed", () => {
const state = new State({
first: { one: 1 },
second: { two: 2 },
third: { three: 3 },
});
const values = [];
state.waitForAll(["first", "second", "third"], (paths) => {
const value = {};
for (const path in paths) {
value[path] = state.get(path);
}
values.push(value);
});
expect(values.length).toEqual(1);
expect(values[0]).toEqual({
first: { one: 1 },
second: { two: 2 },
third: { three: 3 },
});
state.update("first.one", 11);
expect(values.length).toEqual(1);
expect(state.get("")).toEqual({
first: { one: 11 },
second: { two: 2 },
third: { three: 3 },
});
state.update("second.two", 22);
expect(values.length).toEqual(1);
expect(state.get("")).toEqual({
first: { one: 11 },
second: { two: 22 },
third: { three: 3 },
});
state.update("third.three", 33);
expect(values.length).toEqual(2);
expect(state.get("")).toEqual({
first: { one: 11 },
second: { two: 22 },
third: { three: 33 },
});
expect(values[1]).toEqual({
first: { one: 11 },
second: { two: 22 },
third: { three: 33 },
});
});
it("should work with wait option", () => {
const state = new State({ test: 1 }, { queue: true });
const values = [];
state.subscribe("test", (value) => {
values.push(value);
});
expect(values.length).toEqual(1);
expect(values[0]).toEqual(1);
state.update("test", 2);
expect(values[1]).toEqual(2);
});
it("should wait until all jobs are finished", () => {
const state = new State({ test: 1, other: "x" }, { queue: true });
const values = [];
state.subscribe("test", (value) => {
state.update("other", "xx");
values.push(value);
});
expect(values.length).toEqual(1);
expect(values[0]).toEqual(1);
state.update("test", 2);
expect(values[1]).toEqual(2);
expect(state.get("other")).toEqual("x");
setTimeout(() => {
expect(state.get("other")).toEqual("xx");
}, 100);
});
it("should wait until all jobs are finished with update:queue options", () => {
const state = new State({ test: 1, other: "x" });
const values = [];
state.subscribe("test", (value) => {
state.update("other", "xx", { queue: true });
values.push(value);
});
expect(values.length).toEqual(1);
expect(values[0]).toEqual(1);
state.update("test", 2);
expect(values[1]).toEqual(2);
expect(state.get("other")).toEqual("x");
setTimeout(() => {
expect(state.get("other")).toEqual("xx");
}, 100);
});
it("should ignore ignored changes", () => {

@@ -1220,2 +1126,3 @@ const state = new State({ one: { two: { three: { four: { five: 0 } } } } });

state.update("x.*.o", "oo");
expect(values.length).toEqual(2);

@@ -1222,0 +1129,0 @@ expect(values[1]).toEqual("oo");

"use strict";
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
return {
if (o && typeof o.length === "number") return {
next: function () {

@@ -11,2 +11,3 @@ if (o && i >= o.length) o = void 0;

};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};

@@ -13,0 +14,0 @@ exports.__esModule = true;

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

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