varstor 0.6.62 → 0.6.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/varstor.js CHANGED
@@ -12,6 +12,38 @@ return /******/ (() => { // webpackBootstrap
12
12
  /******/ "use strict";
13
13
  /******/ var __webpack_modules__ = ({
14
14
 
15
+ /***/ "./src/actions.ts"
16
+ /*!************************!*\
17
+ !*** ./src/actions.ts ***!
18
+ \************************/
19
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
20
+
21
+ __webpack_require__.r(__webpack_exports__);
22
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
23
+ /* harmony export */ addStateActions: () => (/* binding */ addStateActions)
24
+ /* harmony export */ });
25
+ /* harmony import */ var ___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! . */ "./src/index.ts");
26
+
27
+ function addStateActions(namespace, actions) {
28
+ const stateAcessor = {
29
+ get: ___WEBPACK_IMPORTED_MODULE_0__.getState.bind(null, namespace),
30
+ set: ___WEBPACK_IMPORTED_MODULE_0__.setState.bind(null, namespace),
31
+ reset: ___WEBPACK_IMPORTED_MODULE_0__.resetState.bind(null, namespace),
32
+ };
33
+ for (let [actionName, actionFn] of Object.entries(actions)) {
34
+ ___WEBPACK_IMPORTED_MODULE_0__.STATE[namespace(actionName)] = {
35
+ key: actionName,
36
+ namespace,
37
+ value: actionFn.bind(null, stateAcessor),
38
+ isAction: true,
39
+ listeners: [],
40
+ };
41
+ }
42
+ }
43
+
44
+
45
+ /***/ },
46
+
15
47
  /***/ "./src/constants.ts"
16
48
  /*!**************************!*\
17
49
  !*** ./src/constants.ts ***!
@@ -39,11 +71,13 @@ __webpack_require__.r(__webpack_exports__);
39
71
  /* harmony export */ forEach: () => (/* binding */ forEach),
40
72
  /* harmony export */ getParamNames: () => (/* binding */ getParamNames),
41
73
  /* harmony export */ isArray: () => (/* binding */ isArray),
74
+ /* harmony export */ isAsyncFunction: () => (/* binding */ isAsyncFunction),
42
75
  /* harmony export */ isFunction: () => (/* binding */ isFunction),
43
76
  /* harmony export */ isObject: () => (/* binding */ isObject),
44
77
  /* harmony export */ isString: () => (/* binding */ isString),
45
78
  /* harmony export */ map: () => (/* binding */ map),
46
- /* harmony export */ recreateStructure: () => (/* binding */ recreateStructure)
79
+ /* harmony export */ recreateStructure: () => (/* binding */ recreateStructure),
80
+ /* harmony export */ uid: () => (/* binding */ uid)
47
81
  /* harmony export */ });
48
82
  const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;
49
83
  const ARGUMENT_NAMES = /([^\s,]+)/g;
@@ -56,6 +90,9 @@ function isString(obj) {
56
90
  function isFunction(obj) {
57
91
  return getObjectType(obj) === "[object Function]";
58
92
  }
93
+ function isAsyncFunction(obj) {
94
+ return getObjectType(obj) === "[object AsyncFunction]";
95
+ }
59
96
  function isObject(obj) {
60
97
  return getObjectType(obj) === "[object Object]";
61
98
  }
@@ -101,6 +138,9 @@ function recreateStructure(value) {
101
138
  }
102
139
  return newValue;
103
140
  }
141
+ function uid() {
142
+ return Date.now().toString(36) + Math.random().toString(36).substr(2);
143
+ }
104
144
 
105
145
 
106
146
  /***/ },
@@ -116,12 +156,17 @@ __webpack_require__.r(__webpack_exports__);
116
156
  /* harmony export */ STATE: () => (/* binding */ STATE),
117
157
  /* harmony export */ createStore: () => (/* binding */ createStore),
118
158
  /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
119
- /* harmony export */ getValues: () => (/* binding */ getValues)
159
+ /* harmony export */ getState: () => (/* binding */ getState),
160
+ /* harmony export */ getValues: () => (/* binding */ getValues),
161
+ /* harmony export */ joinStateChanges: () => (/* binding */ joinStateChanges),
162
+ /* harmony export */ resetState: () => (/* binding */ resetState),
163
+ /* harmony export */ setState: () => (/* binding */ setState),
164
+ /* harmony export */ setupValue: () => (/* binding */ setupValue)
120
165
  /* harmony export */ });
121
166
  /* harmony import */ var _storage__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./storage */ "./src/storage.ts");
122
167
  /* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./helpers */ "./src/helpers.ts");
123
- /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./constants */ "./src/constants.ts");
124
- /* harmony import */ var _validation__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./validation */ "./src/validation.ts");
168
+ /* harmony import */ var _actions__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./actions */ "./src/actions.ts");
169
+ /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./constants */ "./src/constants.ts");
125
170
  /* harmony import */ var _listeners__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./listeners */ "./src/listeners.ts");
126
171
 
127
172
 
@@ -129,6 +174,7 @@ __webpack_require__.r(__webpack_exports__);
129
174
 
130
175
 
131
176
  const STATE = {};
177
+ const WAITING_CHANGES = {};
132
178
  const STORAGE = {};
133
179
  setStorageUtils(_storage__WEBPACK_IMPORTED_MODULE_0__["default"]);
134
180
  async function addState(namespace, initialState, isPersistent) {
@@ -143,7 +189,6 @@ async function addState(namespace, initialState, isPersistent) {
143
189
  }
144
190
  for (const key in initialState) {
145
191
  const fullKey = namespace(key);
146
- _validation__WEBPACK_IMPORTED_MODULE_3__.isValid.Defining(fullKey);
147
192
  STATE[fullKey] = setupValue(key, namespace, values[fullKey], defaultValues[key], storageType);
148
193
  }
149
194
  return createStore(namespace());
@@ -194,6 +239,26 @@ function getArguments(dependencies, namespace) {
194
239
  const values = getValues(namespace);
195
240
  return dependencies.map((name) => values[name]);
196
241
  }
242
+ async function joinStateChanges(changesPiece) {
243
+ for (const [updateId, { storageTypes, readyStorageTypes, changes },] of Object.entries(WAITING_CHANGES)) {
244
+ if (changesPiece[updateId]) {
245
+ const storageType = changesPiece[updateId].newValue;
246
+ readyStorageTypes[storageType] = true;
247
+ delete changesPiece[updateId];
248
+ Object.assign(changes, changesPiece);
249
+ if (STORAGE.IS_AVAILABE(storageType)) {
250
+ STORAGE.REMOVE_KEY(storageType, updateId);
251
+ }
252
+ for (const key in storageTypes) {
253
+ if (!readyStorageTypes[key]) {
254
+ return;
255
+ }
256
+ }
257
+ delete WAITING_CHANGES[updateId];
258
+ await onStateChange(changes);
259
+ }
260
+ }
261
+ }
197
262
  async function onStateChange(changes) {
198
263
  const realChanges = {};
199
264
  for (const key in changes) {
@@ -241,19 +306,27 @@ function getState(namespace, arg) {
241
306
  }
242
307
  async function setState(namespace, changes) {
243
308
  const storageChanges = {};
309
+ const updateId = (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.uid)();
310
+ const storageTypes = {};
244
311
  (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.forEach)(changes, (k, v) => {
245
312
  const fullKey = namespace(k);
246
- const { storageType, computeFn } = STATE[fullKey];
247
- if (computeFn) {
313
+ const { storageType, computeFn, isAction } = STATE[fullKey];
314
+ if (computeFn || isAction) {
248
315
  return;
249
316
  }
250
317
  if (!storageChanges[storageType]) {
251
318
  storageChanges[storageType] = {};
252
319
  }
320
+ storageTypes[storageType] = true;
253
321
  storageChanges[storageType][fullKey] = v;
254
322
  });
323
+ WAITING_CHANGES[updateId] = {
324
+ storageTypes,
325
+ readyStorageTypes: {},
326
+ changes: {},
327
+ };
255
328
  for (let [storageType, changes] of Object.entries(storageChanges)) {
256
- await setValues(storageType, changes);
329
+ await setValues(storageType, { ...changes, [updateId]: storageType });
257
330
  }
258
331
  return createStore(namespace());
259
332
  }
@@ -264,7 +337,7 @@ async function setValues(storageType, changes) {
264
337
  return;
265
338
  }
266
339
  }
267
- onStateChange((0,_helpers__WEBPACK_IMPORTED_MODULE_1__.map)(changes, (k, newValue) => [k, { newValue }]));
340
+ joinStateChanges((0,_helpers__WEBPACK_IMPORTED_MODULE_1__.map)(changes, (k, newValue) => [k, { newValue }]));
268
341
  }
269
342
  async function resetState(namespace, keys) {
270
343
  const namespaceState = getNamespaceState(namespace);
@@ -288,7 +361,7 @@ function setStorageUtils(storageUtils) {
288
361
  Object.assign(STORAGE, storageUtils);
289
362
  }
290
363
  function addNamespace(namespace, str) {
291
- return `${namespace}${((0,_helpers__WEBPACK_IMPORTED_MODULE_1__.isString)(str) && _constants__WEBPACK_IMPORTED_MODULE_2__.NAMESPACE_DELIMITER) || ""}${str || ""}`;
364
+ return `${namespace}${((0,_helpers__WEBPACK_IMPORTED_MODULE_1__.isString)(str) && _constants__WEBPACK_IMPORTED_MODULE_3__.NAMESPACE_DELIMITER) || ""}${str || ""}`;
292
365
  }
293
366
  function createStore(_namespace) {
294
367
  const namespace = ((key) => addNamespace(_namespace, key));
@@ -300,8 +373,10 @@ function createStore(_namespace) {
300
373
  reset: (keys) => resetState(namespace, keys),
301
374
  onChange: (keys, cb) => (0,_listeners__WEBPACK_IMPORTED_MODULE_4__.addStateListener)(namespace, keys, cb),
302
375
  removeListener: (keys, cb) => (0,_listeners__WEBPACK_IMPORTED_MODULE_4__.removeStateListener)(namespace, keys, cb),
376
+ actions: (actions) => (0,_actions__WEBPACK_IMPORTED_MODULE_2__.addStateActions)(namespace, actions),
303
377
  setStorageUtils,
304
- onStateChange,
378
+ joinStateChanges,
379
+ namespace,
305
380
  });
306
381
  }
307
382
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (createStore(""));
@@ -336,20 +411,33 @@ async function runStateChangeListeners(realChanges) {
336
411
  for (let [changeKey, change] of Object.entries(realChanges)) {
337
412
  const { listeners, key } = ___WEBPACK_IMPORTED_MODULE_0__.STATE[changeKey];
338
413
  for (const cb of listeners) {
339
- await cb([key], stateValues, change);
414
+ const fn = cb.bind(null, [key], stateValues, change);
415
+ if ((0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isAsyncFunction)(cb)) {
416
+ await fn();
417
+ }
418
+ else {
419
+ fn();
420
+ }
340
421
  }
341
422
  }
342
- const readableKeys = (0,_helpers__WEBPACK_IMPORTED_MODULE_2__.map)(realChanges, (k) => k.slice(_constants__WEBPACK_IMPORTED_MODULE_1__.NAMESPACE_DELIMITER.length));
423
+ const namespaceLength = `${namespace()}${_constants__WEBPACK_IMPORTED_MODULE_1__.NAMESPACE_DELIMITER}`.length;
424
+ const readableKeys = (0,_helpers__WEBPACK_IMPORTED_MODULE_2__.map)(realChanges, (k) => k.slice(namespaceLength));
343
425
  for (const cb of LISTENERS[namespace()]) {
344
- await cb(readableKeys, stateValues, (0,_helpers__WEBPACK_IMPORTED_MODULE_2__.map)(realChanges, (k, v) => [
345
- k.slice(_constants__WEBPACK_IMPORTED_MODULE_1__.NAMESPACE_DELIMITER.length),
426
+ const fn = cb.bind(null, readableKeys, stateValues, (0,_helpers__WEBPACK_IMPORTED_MODULE_2__.map)(realChanges, (k, v) => [
427
+ k.slice(namespaceLength),
346
428
  v,
347
429
  ]));
430
+ if ((0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isAsyncFunction)(cb)) {
431
+ await fn();
432
+ }
433
+ else {
434
+ fn();
435
+ }
348
436
  }
349
437
  }
350
438
  }
351
439
  function addStateListener(namespace, observables, cb) {
352
- if ((0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isFunction)(observables)) {
440
+ if ((0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isFunction)(observables) || (0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isAsyncFunction)(observables)) {
353
441
  LISTENERS[namespace()].push(observables);
354
442
  return (0,___WEBPACK_IMPORTED_MODULE_0__.createStore)(namespace());
355
443
  }
@@ -357,7 +445,7 @@ function addStateListener(namespace, observables, cb) {
357
445
  return (0,___WEBPACK_IMPORTED_MODULE_0__.createStore)(namespace());
358
446
  }
359
447
  function removeStateListener(namespace, observables, removeCb) {
360
- if ((0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isFunction)(observables)) {
448
+ if ((0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isFunction)(observables) || (0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isAsyncFunction)(observables)) {
361
449
  const removeIdx = LISTENERS[namespace()].findIndex((cb) => cb === observables);
362
450
  LISTENERS[namespace()].splice(removeIdx, 1);
363
451
  return (0,___WEBPACK_IMPORTED_MODULE_0__.createStore)(namespace());
@@ -405,52 +493,20 @@ async function setStorageValue(storageType, changes) {
405
493
  }
406
494
  return false;
407
495
  }
496
+ function removeStorageKey(type, key) {
497
+ if (type) {
498
+ localStorage.removeItem(key);
499
+ }
500
+ }
408
501
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({
409
502
  GET_TYPE: getStorageType,
410
503
  IS_AVAILABE: isStorageAvailable,
411
504
  UPDATE_STATE: updateFromLocalStorage,
412
505
  SET_VALUES: setStorageValue,
506
+ REMOVE_KEY: removeStorageKey,
413
507
  });
414
508
 
415
509
 
416
- /***/ },
417
-
418
- /***/ "./src/validation.ts"
419
- /*!***************************!*\
420
- !*** ./src/validation.ts ***!
421
- \***************************/
422
- (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
423
-
424
- __webpack_require__.r(__webpack_exports__);
425
- /* harmony export */ __webpack_require__.d(__webpack_exports__, {
426
- /* harmony export */ isValid: () => (/* binding */ isValid)
427
- /* harmony export */ });
428
- /* harmony import */ var ___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! . */ "./src/index.ts");
429
- /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./constants */ "./src/constants.ts");
430
-
431
-
432
- function splitFullKey(fullKey) {
433
- const segments = fullKey.split(_constants__WEBPACK_IMPORTED_MODULE_1__.NAMESPACE_DELIMITER);
434
- return [segments.slice(-1)[0], segments.join(_constants__WEBPACK_IMPORTED_MODULE_1__.NAMESPACE_DELIMITER)];
435
- }
436
- const isValid = {
437
- Setting: (fullKey) => {
438
- if (!___WEBPACK_IMPORTED_MODULE_0__.STATE[fullKey]) {
439
- const [key, namespace] = splitFullKey(fullKey);
440
- throw new Error(`Setting "${key}" key in "${namespace}" namespace. DOES NOT EXIST`);
441
- }
442
- return true;
443
- },
444
- Defining: (fullKey) => {
445
- if (___WEBPACK_IMPORTED_MODULE_0__.STATE[fullKey]) {
446
- const [key, namespace] = splitFullKey(fullKey);
447
- throw new Error(`Redefining "${key}" key in "${namespace}" namespace. ALREADY DEFINED`);
448
- }
449
- return true;
450
- },
451
- };
452
-
453
-
454
510
  /***/ }
455
511
 
456
512
  /******/ });
@@ -1,2 +1,2 @@
1
1
  /*! For license information please see varstor.min.js.LICENSE.txt */
2
- !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Varstor=t():e.Varstor=t()}(this,()=>(()=>{"use strict";var e={"./src/constants.ts"(e,t,n){n.r(t),n.d(t,{NAMESPACE_DELIMITER:()=>r});const r="::"},"./src/helpers.ts"(e,t,n){n.r(t),n.d(t,{filter:()=>p,forEach:()=>d,getParamNames:()=>l,isArray:()=>o,isFunction:()=>i,isObject:()=>a,isString:()=>c,map:()=>f,recreateStructure:()=>E});const r=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,s=/([^\s,]+)/g;function o(e){return"[object Array]"===u(e)}function c(e){return"[object String]"===u(e)}function i(e){return"[object Function]"===u(e)}function a(e){return"[object Object]"===u(e)}function u(e){return Object.prototype.toString.call(e)}function l(e){const t=e.toString().replace(r,"").split("=>")[0],n=t.slice(t.indexOf("(")+1,t.indexOf(")")).match(s);return null===n?[]:n}function f(e,t){const n=Object.entries(e).map(([e,n])=>t(e,n));return 2===n[0]?.length?Object.fromEntries(n):n}function d(e,t){Object.entries(e||{}).forEach(([e,n])=>t(e,n))}function p(e,t){return Object.fromEntries(Object.entries(e||{}).filter(([e,n])=>!0===t(e,n)))}function E(e){let t=e;if(o(e))return t=[],e.forEach(e=>t.push(E(e))),t;if(a(e)){t={};for(let n in e)t[n]=E(e[n]);return t}return t}},"./src/index.ts"(e,t,n){n.r(t),n.d(t,{STATE:()=>a,createStore:()=>j,default:()=>O,getValues:()=>p});var r=n("./src/storage.ts"),s=n("./src/helpers.ts"),o=n("./src/constants.ts"),c=n("./src/validation.ts"),i=n("./src/listeners.ts");const a={},u={};async function l(e,t,n){const r=u.GET_TYPE(n),o=Object.assign({},t),l=(0,s.map)(t,(t,n)=>[e(t),n]);u.IS_AVAILABE(r)&&await u.UPDATE_STATE(l,r),i.LISTENERS[e()]||(i.LISTENERS[e()]=[]);for(const n in t){const t=e(n);c.isValid.Defining(t),a[t]=f(n,e,l[t],o[n],r)}return j(e())}function f(e,t,n,r,o){const c=t(e),i=(0,s.isFunction)(n),u=i?(0,s.getParamNames)(n):[];return u.forEach(e=>{const n=t(e);a[n]||(a[n]={dependants:[],dependencies:[],namespace:t,storageType:o}),a[n].dependants?.push(c)}),{key:e,fullKey:c,value:i?n.apply(null,E(u,t)):n,computeFn:i&&n,dependencies:u,dependants:[],listeners:[],defaultValue:r,storageType:o,namespace:t}}function d(e){return(0,s.filter)(a,(t,{key:n})=>t===e(n))}function p(e){return(0,s.map)(d(e),(e,{key:t,value:n})=>[t,n])}function E(e,t){const n=p(t);return e.map(e=>n[e])}async function S(e){const t={};for(const n in e){const r=a[n].value,s=e[n].newValue;r!==s?(t[n]={newValue:s,prevValue:r},a[n].value=s):t[n]={isSame:!0},y(n,e,t)}await(0,i.runStateChangeListeners)((0,s.filter)(t,(e,t)=>!t.isSame))}function y(e,t,n){a[e].dependants?.forEach(e=>{const{dependencies:r,namespace:s}=a[e];if(!function(e,t,n,r){return e.every(e=>{const s=t(e);return n.includes(s)&&r.includes(s)||!n.includes(s)})}(r,s,Object.keys(t),Object.keys(n))||n[e])return;const o=a[e].value,c=a[e].computeFn?.apply(null,E(r,s));o!==c&&(n[e]={newValue:c,prevValue:o},a[e].value=c,y(e,t,n))})}function g(e,t){return(0,s.isString)(t)?j(t):(0,s.recreateStructure)(p(e))}async function T(e,t){const n={};(0,s.forEach)(t,(t,r)=>{const s=e(t),{storageType:o,computeFn:c}=a[s];c||(n[o]||(n[o]={}),n[o][s]=r)});for(let[e,t]of Object.entries(n))await m(e,t);return j(e())}async function m(e,t){if(u.IS_AVAILABE(e)){if(await u.SET_VALUES(e,t))return}S((0,s.map)(t,(e,t)=>[e,{newValue:t}]))}function A(e){return!arguments[1]||(0,s.isString)(arguments[1])?g.apply(null,arguments):(0,s.isArray)(arguments[1])?i.addStateListener.apply(null,arguments):(0,s.isObject)(arguments[1])?T.apply(null,arguments):void 0}function b(e){Object.assign(u,e)}function j(e){const t=t=>function(e,t){return`${e}${(0,s.isString)(t)&&o.NAMESPACE_DELIMITER||""}${t||""}`}(e,t);return Object.assign(A.bind(null,t),{add:e=>l(t,e,!1),addPersistent:e=>l(t,e,!0),get:e=>g(t,e),set:async e=>await T(t,e),reset:e=>async function(e,t){const n=d(e);return await T(e,(0,s.map)(t?(0,s.filter)(n,(e,{key:n})=>t.includes(n)):n,(e,{key:t,defaultValue:n})=>[t,n])),j(e())}(t,e),onChange:(e,n)=>(0,i.addStateListener)(t,e,n),removeListener:(e,n)=>(0,i.removeStateListener)(t,e,n),setStorageUtils:b,onStateChange:S})}b(r.default);const O=j("")},"./src/listeners.ts"(e,t,n){n.r(t),n.d(t,{LISTENERS:()=>c,addStateListener:()=>a,removeStateListener:()=>u,runStateChangeListeners:()=>i});var r=n("./src/index.ts"),s=n("./src/constants.ts"),o=n("./src/helpers.ts");const c={};async function i(e){if(Object.keys(e).length){const{namespace:t}=r.STATE[Object.keys(e)[0]],n=(0,r.getValues)(t);for(let[t,s]of Object.entries(e)){const{listeners:e,key:o}=r.STATE[t];for(const t of e)await t([o],n,s)}const i=(0,o.map)(e,e=>e.slice(s.NAMESPACE_DELIMITER.length));for(const r of c[t()])await r(i,n,(0,o.map)(e,(e,t)=>[e.slice(s.NAMESPACE_DELIMITER.length),t]))}}function a(e,t,n){return(0,o.isFunction)(t)?(c[e()].push(t),(0,r.createStore)(e())):(t.forEach(t=>r.STATE[e(t)].listeners?.push(n)),(0,r.createStore)(e()))}function u(e,t,n){if((0,o.isFunction)(t)){const n=c[e()].findIndex(e=>e===t);return c[e()].splice(n,1),(0,r.createStore)(e())}return t.forEach(t=>{const s=r.STATE[e(t)].listeners,o=s?.findIndex(e=>e===n);s?.splice(o,1)}),(0,r.createStore)(e())}},"./src/storage.ts"(e,t,n){n.r(t),n.d(t,{default:()=>r});const r={GET_TYPE:function(e){return e?"localStorage":""},IS_AVAILABE:function(e){return!!e},UPDATE_STATE:async function(e){const t={};for(const n in e){const e=localStorage.getItem(n);null!==e&&(t[n]=e)}return Object.assign(e,t)},SET_VALUES:async function(e,t){for(let[e,n]of Object.entries(t))localStorage.setItem(e,n);return!1}}},"./src/validation.ts"(e,t,n){n.r(t),n.d(t,{isValid:()=>c});var r=n("./src/index.ts"),s=n("./src/constants.ts");function o(e){const t=e.split(s.NAMESPACE_DELIMITER);return[t.slice(-1)[0],t.join(s.NAMESPACE_DELIMITER)]}const c={Setting:e=>{if(!r.STATE[e]){const[t,n]=o(e);throw new Error(`Setting "${t}" key in "${n}" namespace. DOES NOT EXIST`)}return!0},Defining:e=>{if(r.STATE[e]){const[t,n]=o(e);throw new Error(`Redefining "${t}" key in "${n}" namespace. ALREADY DEFINED`)}return!0}}}};const t={};function n(r){const s=t[r];if(void 0!==s)return s.exports;const o=t[r]={exports:{}};if(!(r in e)){delete t[r];const e=new Error("Cannot find module '"+r+"'");throw e.code="MODULE_NOT_FOUND",e}return e[r](o,o.exports,n),o.exports}n.d=(e,t)=>{if(Array.isArray(t))for(var r=0;r<t.length;){var s=t[r++],o=t[r++];n.o(e,s)?0===o&&r++:0===o?Object.defineProperty(e,s,{enumerable:!0,value:t[r++]}):Object.defineProperty(e,s,{enumerable:!0,get:o})}else for(var s in t)n.o(t,s)&&!n.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};let r=n("./src/index.ts");return r=r.default,r})());
2
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Varstor=t():e.Varstor=t()}(this,()=>(()=>{"use strict";var e={"./src/actions.ts"(e,t,n){n.r(t),n.d(t,{addStateActions:()=>s});var r=n("./src/index.ts");function s(e,t){const n={get:r.getState.bind(null,e),set:r.setState.bind(null,e),reset:r.resetState.bind(null,e)};for(let[s,o]of Object.entries(t))r.STATE[e(s)]={key:s,namespace:e,value:o.bind(null,n),isAction:!0,listeners:[]}}},"./src/constants.ts"(e,t,n){n.r(t),n.d(t,{NAMESPACE_DELIMITER:()=>r});const r="::"},"./src/helpers.ts"(e,t,n){n.r(t),n.d(t,{filter:()=>S,forEach:()=>p,getParamNames:()=>f,isArray:()=>o,isAsyncFunction:()=>a,isFunction:()=>i,isObject:()=>u,isString:()=>c,map:()=>d,recreateStructure:()=>y,uid:()=>E});const r=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,s=/([^\s,]+)/g;function o(e){return"[object Array]"===l(e)}function c(e){return"[object String]"===l(e)}function i(e){return"[object Function]"===l(e)}function a(e){return"[object AsyncFunction]"===l(e)}function u(e){return"[object Object]"===l(e)}function l(e){return Object.prototype.toString.call(e)}function f(e){const t=e.toString().replace(r,"").split("=>")[0],n=t.slice(t.indexOf("(")+1,t.indexOf(")")).match(s);return null===n?[]:n}function d(e,t){const n=Object.entries(e).map(([e,n])=>t(e,n));return 2===n[0]?.length?Object.fromEntries(n):n}function p(e,t){Object.entries(e||{}).forEach(([e,n])=>t(e,n))}function S(e,t){return Object.fromEntries(Object.entries(e||{}).filter(([e,n])=>!0===t(e,n)))}function y(e){let t=e;if(o(e))return t=[],e.forEach(e=>t.push(y(e))),t;if(u(e)){t={};for(let n in e)t[n]=y(e[n]);return t}return t}function E(){return Date.now().toString(36)+Math.random().toString(36).substr(2)}},"./src/index.ts"(e,t,n){n.r(t),n.d(t,{STATE:()=>a,createStore:()=>v,default:()=>I,getState:()=>m,getValues:()=>S,joinStateChanges:()=>E,resetState:()=>j,setState:()=>A,setupValue:()=>d});var r=n("./src/storage.ts"),s=n("./src/helpers.ts"),o=n("./src/actions.ts"),c=n("./src/constants.ts"),i=n("./src/listeners.ts");const a={},u={},l={};async function f(e,t,n){const r=l.GET_TYPE(n),o=Object.assign({},t),c=(0,s.map)(t,(t,n)=>[e(t),n]);l.IS_AVAILABE(r)&&await l.UPDATE_STATE(c,r),i.LISTENERS[e()]||(i.LISTENERS[e()]=[]);for(const n in t){const t=e(n);a[t]=d(n,e,c[t],o[n],r)}return v(e())}function d(e,t,n,r,o){const c=t(e),i=(0,s.isFunction)(n),u=i?(0,s.getParamNames)(n):[];return u.forEach(e=>{const n=t(e);a[n]||(a[n]={dependants:[],dependencies:[],namespace:t,storageType:o}),a[n].dependants?.push(c)}),{key:e,fullKey:c,value:i?n.apply(null,y(u,t)):n,computeFn:i&&n,dependencies:u,dependants:[],listeners:[],defaultValue:r,storageType:o,namespace:t}}function p(e){return(0,s.filter)(a,(t,{key:n})=>t===e(n))}function S(e){return(0,s.map)(p(e),(e,{key:t,value:n})=>[t,n])}function y(e,t){const n=S(t);return e.map(e=>n[e])}async function E(e){for(const[t,{storageTypes:n,readyStorageTypes:r,changes:s}]of Object.entries(u))if(e[t]){const o=e[t].newValue;r[o]=!0,delete e[t],Object.assign(s,e),l.IS_AVAILABE(o)&&l.REMOVE_KEY(o,t);for(const e in n)if(!r[e])return;delete u[t],await g(s)}}async function g(e){const t={};for(const n in e){const r=a[n].value,s=e[n].newValue;r!==s?(t[n]={newValue:s,prevValue:r},a[n].value=s):t[n]={isSame:!0},b(n,e,t)}await(0,i.runStateChangeListeners)((0,s.filter)(t,(e,t)=>!t.isSame))}function b(e,t,n){a[e].dependants?.forEach(e=>{const{dependencies:r,namespace:s}=a[e];if(!function(e,t,n,r){return e.every(e=>{const s=t(e);return n.includes(s)&&r.includes(s)||!n.includes(s)})}(r,s,Object.keys(t),Object.keys(n))||n[e])return;const o=a[e].value,c=a[e].computeFn?.apply(null,y(r,s));o!==c&&(n[e]={newValue:c,prevValue:o},a[e].value=c,b(e,t,n))})}function m(e,t){return(0,s.isString)(t)?v(t):(0,s.recreateStructure)(S(e))}async function A(e,t){const n={},r=(0,s.uid)(),o={};(0,s.forEach)(t,(t,r)=>{const s=e(t),{storageType:c,computeFn:i,isAction:u}=a[s];i||u||(n[c]||(n[c]={}),o[c]=!0,n[c][s]=r)}),u[r]={storageTypes:o,readyStorageTypes:{},changes:{}};for(let[e,t]of Object.entries(n))await T(e,{...t,[r]:e});return v(e())}async function T(e,t){if(l.IS_AVAILABE(e)){if(await l.SET_VALUES(e,t))return}E((0,s.map)(t,(e,t)=>[e,{newValue:t}]))}async function j(e,t){const n=p(e);return await A(e,(0,s.map)(t?(0,s.filter)(n,(e,{key:n})=>t.includes(n)):n,(e,{key:t,defaultValue:n})=>[t,n])),v(e())}function O(e){return!arguments[1]||(0,s.isString)(arguments[1])?m.apply(null,arguments):(0,s.isArray)(arguments[1])?i.addStateListener.apply(null,arguments):(0,s.isObject)(arguments[1])?A.apply(null,arguments):void 0}function h(e){Object.assign(l,e)}function v(e){const t=t=>function(e,t){return`${e}${(0,s.isString)(t)&&c.NAMESPACE_DELIMITER||""}${t||""}`}(e,t);return Object.assign(O.bind(null,t),{add:e=>f(t,e,!1),addPersistent:e=>f(t,e,!0),get:e=>m(t,e),set:async e=>await A(t,e),reset:e=>j(t,e),onChange:(e,n)=>(0,i.addStateListener)(t,e,n),removeListener:(e,n)=>(0,i.removeStateListener)(t,e,n),actions:e=>(0,o.addStateActions)(t,e),setStorageUtils:h,joinStateChanges:E,namespace:t})}h(r.default);const I=v("")},"./src/listeners.ts"(e,t,n){n.r(t),n.d(t,{LISTENERS:()=>c,addStateListener:()=>a,removeStateListener:()=>u,runStateChangeListeners:()=>i});var r=n("./src/index.ts"),s=n("./src/constants.ts"),o=n("./src/helpers.ts");const c={};async function i(e){if(Object.keys(e).length){const{namespace:t}=r.STATE[Object.keys(e)[0]],n=(0,r.getValues)(t);for(let[t,s]of Object.entries(e)){const{listeners:e,key:c}=r.STATE[t];for(const t of e){const e=t.bind(null,[c],n,s);(0,o.isAsyncFunction)(t)?await e():e()}}const i=`${t()}${s.NAMESPACE_DELIMITER}`.length,a=(0,o.map)(e,e=>e.slice(i));for(const r of c[t()]){const t=r.bind(null,a,n,(0,o.map)(e,(e,t)=>[e.slice(i),t]));(0,o.isAsyncFunction)(r)?await t():t()}}}function a(e,t,n){return(0,o.isFunction)(t)||(0,o.isAsyncFunction)(t)?(c[e()].push(t),(0,r.createStore)(e())):(t.forEach(t=>r.STATE[e(t)].listeners?.push(n)),(0,r.createStore)(e()))}function u(e,t,n){if((0,o.isFunction)(t)||(0,o.isAsyncFunction)(t)){const n=c[e()].findIndex(e=>e===t);return c[e()].splice(n,1),(0,r.createStore)(e())}return t.forEach(t=>{const s=r.STATE[e(t)].listeners,o=s?.findIndex(e=>e===n);s?.splice(o,1)}),(0,r.createStore)(e())}},"./src/storage.ts"(e,t,n){n.r(t),n.d(t,{default:()=>r});const r={GET_TYPE:function(e){return e?"localStorage":""},IS_AVAILABE:function(e){return!!e},UPDATE_STATE:async function(e){const t={};for(const n in e){const e=localStorage.getItem(n);null!==e&&(t[n]=e)}return Object.assign(e,t)},SET_VALUES:async function(e,t){for(let[e,n]of Object.entries(t))localStorage.setItem(e,n);return!1},REMOVE_KEY:function(e,t){e&&localStorage.removeItem(t)}}}};const t={};function n(r){const s=t[r];if(void 0!==s)return s.exports;const o=t[r]={exports:{}};if(!(r in e)){delete t[r];const e=new Error("Cannot find module '"+r+"'");throw e.code="MODULE_NOT_FOUND",e}return e[r](o,o.exports,n),o.exports}n.d=(e,t)=>{if(Array.isArray(t))for(var r=0;r<t.length;){var s=t[r++],o=t[r++];n.o(e,s)?0===o&&r++:0===o?Object.defineProperty(e,s,{enumerable:!0,value:t[r++]}):Object.defineProperty(e,s,{enumerable:!0,get:o})}else for(var s in t)n.o(t,s)&&!n.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};let r=n("./src/index.ts");return r=r.default,r})());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "varstor",
3
- "version": "0.6.62",
3
+ "version": "0.6.64",
4
4
  "description": "State manager for web applications and webextensions, employing reactivity, wrapping, and uniting the usage of different storages' values and common variables into a simple universal interface",
5
5
  "license": "MIT",
6
6
  "author": "Igor Morozov <ismorozs@gmail.com>",
package/src/actions.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { STATE, getState, setState, resetState } from ".";
2
+
3
+ export function addStateActions(namespace: INamespace, actions: IStateActions) {
4
+ const stateAcessor = {
5
+ get: getState.bind(null, namespace),
6
+ set: setState.bind(null, namespace),
7
+ reset: resetState.bind(null, namespace),
8
+ };
9
+
10
+ for (let [actionName, actionFn] of Object.entries(actions)) {
11
+ STATE[namespace(actionName)] = {
12
+ key: actionName,
13
+ namespace,
14
+ value: actionFn.bind(null, stateAcessor),
15
+ isAction: true,
16
+ listeners: [],
17
+ };
18
+ }
19
+ }
package/src/helpers.ts CHANGED
@@ -13,6 +13,10 @@ export function isFunction(obj: unknown) {
13
13
  return getObjectType(obj) === "[object Function]";
14
14
  }
15
15
 
16
+ export function isAsyncFunction (obj: unknown) {
17
+ return getObjectType(obj) === "[object AsyncFunction]";
18
+ }
19
+
16
20
  export function isObject(obj: unknown) {
17
21
  return getObjectType(obj) === "[object Object]";
18
22
  }
@@ -86,3 +90,7 @@ export function recreateStructure(value: unknown) {
86
90
 
87
91
  return newValue;
88
92
  }
93
+
94
+ export function uid() {
95
+ return Date.now().toString(36) + Math.random().toString(36).substr(2);
96
+ }
package/src/index.ts CHANGED
@@ -10,11 +10,13 @@ import {
10
10
  filter,
11
11
  recreateStructure,
12
12
  forEach,
13
+ uid,
13
14
  } from "./helpers";
14
15
 
16
+ import { addStateActions } from "./actions";
17
+
15
18
  import { NAMESPACE_DELIMITER } from "./constants";
16
19
 
17
- import { isValid } from "./validation";
18
20
  import {
19
21
  runStateChangeListeners,
20
22
  addStateListener,
@@ -23,6 +25,7 @@ import {
23
25
  } from "./listeners";
24
26
 
25
27
  export const STATE = {} as IState;
28
+ const WAITING_CHANGES = {} as IStateUpdatePieces;
26
29
  const STORAGE = {} as IStorageFunctions;
27
30
 
28
31
  setStorageUtils(storageUtils);
@@ -49,7 +52,6 @@ async function addState(
49
52
 
50
53
  for (const key in initialState) {
51
54
  const fullKey = namespace(key);
52
- isValid.Defining(fullKey);
53
55
  STATE[fullKey] = setupValue(
54
56
  key,
55
57
  namespace,
@@ -62,7 +64,7 @@ async function addState(
62
64
  return createStore(namespace());
63
65
  }
64
66
 
65
- function setupValue(
67
+ export function setupValue(
66
68
  key: string,
67
69
  namespace: INamespace,
68
70
  value: unknown,
@@ -123,6 +125,33 @@ function getArguments(dependencies: string[], namespace: INamespace) {
123
125
  return dependencies.map((name) => values[name as keyof typeof values]);
124
126
  }
125
127
 
128
+ export async function joinStateChanges(changesPiece: IStateChanges) {
129
+ for (const [
130
+ updateId,
131
+ { storageTypes, readyStorageTypes, changes },
132
+ ] of Object.entries(WAITING_CHANGES)) {
133
+ if (changesPiece[updateId]) {
134
+ const storageType = changesPiece[updateId].newValue;
135
+ readyStorageTypes[storageType] = true;
136
+ delete changesPiece[updateId];
137
+ Object.assign(changes, changesPiece);
138
+ if (STORAGE.IS_AVAILABE(storageType)) {
139
+ STORAGE.REMOVE_KEY(storageType, updateId);
140
+ }
141
+
142
+ for (const key in storageTypes) {
143
+ if (!readyStorageTypes[key]) {
144
+ return;
145
+ }
146
+ }
147
+
148
+ delete WAITING_CHANGES[updateId];
149
+
150
+ await onStateChange(changes);
151
+ }
152
+ }
153
+ }
154
+
126
155
  async function onStateChange(changes: IStateChanges) {
127
156
  const realChanges = {} as IStateChanges;
128
157
 
@@ -153,7 +182,7 @@ function updateDependencies(
153
182
 
154
183
  if (
155
184
  !isEveryDependencyReady(
156
- dependencies,
185
+ dependencies!,
157
186
  namespace,
158
187
  Object.keys(changes),
159
188
  Object.keys(realChanges),
@@ -166,7 +195,7 @@ function updateDependencies(
166
195
  const prevValue = STATE[name].value;
167
196
  const newValue = (STATE[name].computeFn as IComputeFunction)?.apply(
168
197
  null,
169
- getArguments(dependencies, namespace),
198
+ getArguments(dependencies!, namespace),
170
199
  );
171
200
 
172
201
  if (prevValue !== newValue) {
@@ -192,7 +221,7 @@ function isEveryDependencyReady(
192
221
  });
193
222
  }
194
223
 
195
- function getState(namespace: INamespace, arg: string) {
224
+ export function getState(namespace: INamespace, arg: string) {
196
225
  if (isString(arg)) {
197
226
  return createStore(arg);
198
227
  }
@@ -200,29 +229,39 @@ function getState(namespace: INamespace, arg: string) {
200
229
  return recreateStructure(getValues(namespace));
201
230
  }
202
231
 
203
- async function setState(
232
+ export async function setState(
204
233
  namespace: INamespace,
205
234
  changes: Record<string, unknown>,
206
235
  ): Promise<unknown> {
207
236
  const storageChanges: Record<string, any> = {};
237
+ const updateId = uid();
238
+ const storageTypes = {} as Record<string, boolean>;
208
239
 
209
240
  forEach(changes, (k, v) => {
210
241
  const fullKey = namespace(k);
211
- const { storageType, computeFn } = STATE[fullKey];
242
+ const { storageType, computeFn, isAction } = STATE[fullKey];
212
243
 
213
- if (computeFn) {
244
+ if (computeFn || isAction) {
214
245
  return;
215
246
  }
216
247
 
217
- if (!storageChanges[storageType]) {
218
- storageChanges[storageType] = {};
248
+ if (!storageChanges[storageType!]) {
249
+ storageChanges[storageType!] = {};
219
250
  }
220
251
 
221
- storageChanges[storageType][fullKey] = v;
252
+ storageTypes[storageType!] = true;
253
+
254
+ storageChanges[storageType!][fullKey] = v;
222
255
  });
223
256
 
257
+ WAITING_CHANGES[updateId] = {
258
+ storageTypes,
259
+ readyStorageTypes: {},
260
+ changes: {},
261
+ };
262
+
224
263
  for (let [storageType, changes] of Object.entries(storageChanges)) {
225
- await setValues(storageType, changes);
264
+ await setValues(storageType, { ...changes, [updateId]: storageType });
226
265
  }
227
266
 
228
267
  return createStore(namespace());
@@ -239,12 +278,12 @@ async function setValues(
239
278
  }
240
279
  }
241
280
 
242
- onStateChange(
281
+ joinStateChanges(
243
282
  map(changes, (k, newValue) => [k, { newValue }]) as Record<string, any>,
244
283
  );
245
284
  }
246
285
 
247
- async function resetState(namespace: INamespace, keys?: string[]) {
286
+ export async function resetState(namespace: INamespace, keys?: string[]) {
248
287
  const namespaceState = getNamespaceState(namespace);
249
288
 
250
289
  await setState(
@@ -303,8 +342,10 @@ export function createStore(_namespace: string) {
303
342
  addStateListener(namespace, keys, cb),
304
343
  removeListener: (keys: string[], cb: () => {}) =>
305
344
  removeStateListener(namespace, keys, cb),
345
+ actions: (actions: IStateActions) => addStateActions(namespace, actions),
306
346
  setStorageUtils,
307
- onStateChange,
347
+ joinStateChanges,
348
+ namespace,
308
349
  });
309
350
  }
310
351
 
package/src/listeners.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { STATE, getValues, createStore } from ".";
2
2
  import { NAMESPACE_DELIMITER } from "./constants";
3
- import { map, isFunction } from "./helpers";
3
+ import { map, isFunction, isAsyncFunction } from "./helpers";
4
4
 
5
5
  export const LISTENERS = {} as IStateListeners;
6
6
 
@@ -13,23 +13,35 @@ export async function runStateChangeListeners(realChanges: IStateChanges) {
13
13
  for (let [changeKey, change] of Object.entries(realChanges)) {
14
14
  const { listeners, key } = STATE[changeKey];
15
15
  for (const cb of listeners!) {
16
- await cb([key], stateValues, change);
16
+ const fn = cb.bind(null, [key], stateValues, change);
17
+ if (isAsyncFunction(cb)) {
18
+ await fn();
19
+ } else {
20
+ fn();
21
+ }
17
22
  }
18
23
  }
19
24
 
25
+ const namespaceLength = `${namespace()}${NAMESPACE_DELIMITER}`.length;
20
26
  const readableKeys = map(realChanges, (k) =>
21
- k.slice(NAMESPACE_DELIMITER.length),
27
+ k.slice(namespaceLength),
22
28
  ) as string[];
23
29
 
24
30
  for (const cb of LISTENERS[namespace()]) {
25
- await cb(
31
+ const fn = cb.bind(
32
+ null,
26
33
  readableKeys,
27
34
  stateValues,
28
35
  map(realChanges, (k, v) => [
29
- k.slice(NAMESPACE_DELIMITER.length),
36
+ k.slice(namespaceLength),
30
37
  v,
31
38
  ]) as IStateChanges,
32
39
  );
40
+ if (isAsyncFunction(cb)) {
41
+ await fn();
42
+ } else {
43
+ fn();
44
+ }
33
45
  }
34
46
  }
35
47
  }
@@ -39,7 +51,7 @@ export function addStateListener(
39
51
  observables: string[] | IStateListener,
40
52
  cb: () => {},
41
53
  ) {
42
- if (isFunction(observables)) {
54
+ if (isFunction(observables) || isAsyncFunction(observables)) {
43
55
  LISTENERS[namespace()].push(observables as IStateListener);
44
56
  return createStore(namespace());
45
57
  }
@@ -56,7 +68,7 @@ export function removeStateListener(
56
68
  observables: string[] | IStateListener,
57
69
  removeCb: () => {},
58
70
  ) {
59
- if (isFunction(observables)) {
71
+ if (isFunction(observables) || isAsyncFunction(observables)) {
60
72
  const removeIdx = LISTENERS[namespace()].findIndex(
61
73
  (cb) => cb === observables,
62
74
  );
package/src/storage.ts CHANGED
@@ -29,9 +29,16 @@ async function setStorageValue(
29
29
  return false;
30
30
  }
31
31
 
32
+ function removeStorageKey (type: string, key: string) {
33
+ if (type) {
34
+ localStorage.removeItem(key);
35
+ }
36
+ }
37
+
32
38
  export default {
33
39
  GET_TYPE: getStorageType,
34
40
  IS_AVAILABE: isStorageAvailable,
35
41
  UPDATE_STATE: updateFromLocalStorage,
36
42
  SET_VALUES: setStorageValue,
43
+ REMOVE_KEY: removeStorageKey,
37
44
  };