varstor 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2026 Morozov Igor (ismorozs)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # Varstor
2
+ Library for managing the state of applications, employing reactivity, and seamless usage of storage with a simple unified interface
@@ -0,0 +1,554 @@
1
+ (function webpackUniversalModuleDefinition(root, factory) {
2
+ if(typeof exports === 'object' && typeof module === 'object')
3
+ module.exports = factory();
4
+ else if(typeof define === 'function' && define.amd)
5
+ define([], factory);
6
+ else if(typeof exports === 'object')
7
+ exports["Varstor"] = factory();
8
+ else
9
+ root["Varstor"] = factory();
10
+ })(this, () => {
11
+ return /******/ (() => { // webpackBootstrap
12
+ /******/ "use strict";
13
+ /******/ var __webpack_modules__ = ({
14
+
15
+ /***/ "./src/error.js"
16
+ /*!**********************!*\
17
+ !*** ./src/error.js ***!
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 */ isKeyPresent: () => (/* binding */ isKeyPresent)
24
+ /* harmony export */ });
25
+ /* harmony import */ var ___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! . */ "./src/index.js");
26
+ /* harmony import */ var _namespace__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./namespace */ "./src/namespace.js");
27
+
28
+
29
+
30
+ const isKeyPresent = (fullKey) => {
31
+ if (!___WEBPACK_IMPORTED_MODULE_0__.ACCESSORS[fullKey]) {
32
+ const [key, namespace] = fullKey.split(_namespace__WEBPACK_IMPORTED_MODULE_1__.NAMESPACE_DELIMITER);
33
+ throw new Error (`Trying to access "${key}" key in "${namespace}" namespace, but it doesn't exist`);
34
+ }
35
+
36
+ return true;
37
+ }
38
+
39
+
40
+ /***/ },
41
+
42
+ /***/ "./src/helpers.js"
43
+ /*!************************!*\
44
+ !*** ./src/helpers.js ***!
45
+ \************************/
46
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
47
+
48
+ __webpack_require__.r(__webpack_exports__);
49
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
50
+ /* harmony export */ getKeys: () => (/* binding */ getKeys),
51
+ /* harmony export */ getParamNames: () => (/* binding */ getParamNames),
52
+ /* harmony export */ isArray: () => (/* binding */ isArray),
53
+ /* harmony export */ isFunction: () => (/* binding */ isFunction),
54
+ /* harmony export */ isObject: () => (/* binding */ isObject),
55
+ /* harmony export */ isString: () => (/* binding */ isString),
56
+ /* harmony export */ toCamelCase: () => (/* binding */ toCamelCase)
57
+ /* harmony export */ });
58
+ const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;
59
+ const ARGUMENT_NAMES = /([^\s,]+)/g;
60
+
61
+ function isFunction(x) {
62
+ return typeof x === "function";
63
+ }
64
+
65
+ function isObject(x) {
66
+ return typeof x === "object";
67
+ }
68
+
69
+ function isString(x) {
70
+ return typeof x === "string";
71
+ }
72
+
73
+ function isArray(x) {
74
+ return Array.isArray(x);
75
+ }
76
+
77
+ function getParamNames(fn) {
78
+ const fnStr = fn.toString().replace(STRIP_COMMENTS, "");
79
+ const names = fnStr
80
+ .slice(fnStr.indexOf("(") + 1, fnStr.indexOf(")"))
81
+ .match(ARGUMENT_NAMES);
82
+
83
+ if (names === null) {
84
+ return [];
85
+ }
86
+
87
+ return names;
88
+ }
89
+
90
+ function getKeys(obj, key) {
91
+ return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, v[key]]));
92
+ }
93
+
94
+ function toCamelCase(str, delimiter) {
95
+ const strArr = str.split(delimiter);
96
+ return `${strArr[0]}${strArr.slice(1).reduce((a, c) => `${a}${c.charAt(0).toUpperCase()}${c.slice(1)}`, "")}`;
97
+ }
98
+
99
+
100
+ /***/ },
101
+
102
+ /***/ "./src/index.js"
103
+ /*!**********************!*\
104
+ !*** ./src/index.js ***!
105
+ \**********************/
106
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
107
+
108
+ __webpack_require__.r(__webpack_exports__);
109
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
110
+ /* harmony export */ ACCESSORS: () => (/* binding */ ACCESSORS),
111
+ /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
112
+ /* harmony export */ });
113
+ /* harmony import */ var _storage__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./storage */ "./src/storage.js");
114
+ /* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./helpers */ "./src/helpers.js");
115
+ /* harmony import */ var _namespace__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./namespace */ "./src/namespace.js");
116
+ /* harmony import */ var _error__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./error */ "./src/error.js");
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+ const STATE = {};
126
+ const ACCESSORS = {};
127
+ const COMPUTED_DEPENDENCIES = {};
128
+ const COMPUTED_ARGUMENTS = {};
129
+
130
+ const STORAGE = {
131
+ GET_TYPE: null,
132
+ IS_AVAILABE: null,
133
+ UPDATE_STATE: null,
134
+ SET_VALUE: null
135
+ };
136
+
137
+ setStorageUtils(_storage__WEBPACK_IMPORTED_MODULE_0__["default"]);
138
+
139
+ async function addState (namespace, initialState, isPersistent) {
140
+ const storageType = STORAGE.GET_TYPE(isPersistent);
141
+ const defaultValues = Object.assign({}, initialState);
142
+ const namespacedValues = (0,_namespace__WEBPACK_IMPORTED_MODULE_2__.namespacify)(namespace(), initialState);
143
+
144
+ if (STORAGE.IS_AVAILABE(storageType)) {
145
+ await STORAGE.UPDATE_STATE(namespacedValues, storageType);
146
+ }
147
+
148
+ const accessors = {};
149
+ for (const key in initialState) {
150
+ accessors[namespace(key)] = setupValue(
151
+ namespace(key),
152
+ namespacedValues[namespace(key)],
153
+ defaultValues[key],
154
+ storageType,
155
+ );
156
+ }
157
+
158
+ Object.assign(ACCESSORS, accessors);
159
+ return createStore(namespace());
160
+ }
161
+
162
+ function setupValue (key, value, defaultValue, storageType) {
163
+ const isComputedValue = (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.isFunction)(value);
164
+
165
+ if (isComputedValue) {
166
+ setupDependencies(key, value);
167
+ }
168
+
169
+ STATE[key] = {
170
+ value: isComputedValue ? value.apply(null, getArguments(key)) : value,
171
+ computeFn: value,
172
+ listeners: [],
173
+ defaultValue,
174
+ };
175
+
176
+ return createAccessor(key, value, storageType);
177
+ }
178
+
179
+ function setupDependencies(computedValueName, computeFn) {
180
+ const namespace = (0,_namespace__WEBPACK_IMPORTED_MODULE_2__.getNamespace)(computedValueName);
181
+ const paramNames = (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.getParamNames)(computeFn).map((name) => (0,_namespace__WEBPACK_IMPORTED_MODULE_2__.addNamespace)(namespace, name));
182
+ COMPUTED_ARGUMENTS[computedValueName] = paramNames;
183
+
184
+ paramNames.forEach((param) => {
185
+ if (COMPUTED_DEPENDENCIES[param]) {
186
+ COMPUTED_DEPENDENCIES[param].push(computedValueName);
187
+ } else {
188
+ COMPUTED_DEPENDENCIES[param] = [computedValueName];
189
+ }
190
+ });
191
+ }
192
+
193
+ function getArguments(computedName) {
194
+ const values = getNamespaceValues(computedName);
195
+
196
+ return COMPUTED_ARGUMENTS[computedName]
197
+ .map((name) => values[(0,_namespace__WEBPACK_IMPORTED_MODULE_2__.getKey)(name)])
198
+ .concat(values);
199
+ }
200
+
201
+ function createAccessor(key, value, storageType) {
202
+ const accessor = () => STATE[key].value;
203
+
204
+ Object.assign(accessor, {
205
+ valueOf: () => STATE[key].value,
206
+ toString: () => STATE[key].value,
207
+ set: (value) => setValue(key, value, storageType),
208
+ onChange: (cb) => STATE[key].listeners.push(cb),
209
+ removeListener: (removeCb) =>
210
+ (STATE[key].listeners = STATE[key].listeners.filter(
211
+ (cb) => cb !== removeCb,
212
+ )),
213
+ reset: () => setValue(key, STATE[key].defaultValue, storageType),
214
+ });
215
+
216
+ return new Proxy(accessor, {
217
+ get: (target, prop) => {
218
+ if (Object.keys(accessor).includes(prop)) {
219
+ return target[prop];
220
+ }
221
+
222
+ return STATE[key].value[prop];
223
+ },
224
+ });
225
+ }
226
+
227
+ function setValue (key, value, storageType) {
228
+ if (STORAGE.IS_AVAILABE(storageType)) {
229
+ const isAutoUpdate = STORAGE.SET_VALUE(storageType, key, value);
230
+ if (isAutoUpdate) {
231
+ return;
232
+ }
233
+ }
234
+
235
+ onStateChange({ [key]: { newValue: value } });
236
+ }
237
+
238
+ function onStateChange (changes) {
239
+ const realChanges = {};
240
+
241
+ for (const key in changes) {
242
+ const prevValue = STATE[key].value;
243
+ const newValue = changes[key].newValue;
244
+
245
+ if (prevValue !== newValue) {
246
+ STATE[key].value = newValue;
247
+ realChanges[key] = { newValue, prevValue };
248
+
249
+ updateDependencies(key, realChanges);
250
+ }
251
+ }
252
+
253
+ for (const key in realChanges) {
254
+ STATE[key].listeners.forEach((cb) => cb(STATE[key].value, getNamespaceValues(key), realChanges[key]));
255
+ }
256
+ }
257
+
258
+ function updateDependencies (key, realChanges) {
259
+ const computedDependencies = COMPUTED_DEPENDENCIES[key];
260
+ if (computedDependencies) {
261
+ computedDependencies.forEach((name) => {
262
+ const prevValue = STATE[name].value;
263
+ const newValue = STATE[name].computeFn.apply(null, getArguments(name));
264
+ if (prevValue !== newValue) {
265
+ STATE[name].value = newValue;
266
+ realChanges[name] = { newValue, prevValue };
267
+ updateDependencies(name, realChanges);
268
+ }
269
+ });
270
+ }
271
+ }
272
+
273
+ function getState(namespace, arg) {
274
+ if ((0,_helpers__WEBPACK_IMPORTED_MODULE_1__.isString)(arg)) {
275
+ return createStore(arg);
276
+ }
277
+
278
+ if ((0,_helpers__WEBPACK_IMPORTED_MODULE_1__.isFunction)(arg)) {
279
+ return getNamespaceAccessors(namespace(""), arg);
280
+ }
281
+
282
+ return getNamespaceValues(namespace(""));
283
+ }
284
+
285
+ function getNamespaceValues(namespace) {
286
+ return (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.getKeys)((0,_namespace__WEBPACK_IMPORTED_MODULE_2__.getByNamespace)(namespace, STATE), "value");
287
+ }
288
+
289
+ function getNamespaceAccessors (namespace, cb) {
290
+ const accessors = (0,_namespace__WEBPACK_IMPORTED_MODULE_2__.getByNamespace)(namespace, ACCESSORS);
291
+ return cb.call(null, accessors, createStore(namespace()));
292
+ }
293
+
294
+ function setState (namespace, changes) {
295
+ const noKeys = !Object.keys(changes).length;
296
+
297
+ if (noKeys) {
298
+ resetAllState();
299
+ } else {
300
+ for (const [k,v] of Object.entries(changes)) {
301
+ (0,_error__WEBPACK_IMPORTED_MODULE_3__.isKeyPresent)(namespace(k)) && ACCESSORS[namespace(k)].set(v);
302
+ };
303
+ }
304
+
305
+ return createStore(namespace());
306
+ }
307
+
308
+ function resetAllState (namespace) {
309
+ Object.entries(ACCESSORS)
310
+ .filter(([k]) => k.startsWith(namespace()))
311
+ .forEach((k, { reset }) => reset());
312
+
313
+ return createStore(namespace());
314
+ }
315
+
316
+ function addStateLitener (namespace, observables, cb) {
317
+ observables.forEach((key) => ACCESSORS[namespace(key)].onChange(cb));
318
+
319
+ return createStore(namespace());
320
+ }
321
+
322
+ function removeStateListener(namespace, observables, cb) {
323
+ observables.forEach((key) =>
324
+ ACCESSORS[namespace(key)].removeListener(cb),
325
+ );
326
+
327
+ return createStore(namespace());
328
+ }
329
+
330
+ function main () {
331
+ const arg1 = arguments[1];
332
+
333
+ if (!arg1 || (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.isFunction)(arg1) || (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.isString)(arg1)) {
334
+ return getState.apply(null, arguments);
335
+ }
336
+
337
+ if (Array.isArray(arg1)) {
338
+ return addStateLitener.apply(null, arguments);
339
+ }
340
+
341
+ if ((0,_helpers__WEBPACK_IMPORTED_MODULE_1__.isObject)(arg1)) {
342
+ return setState.apply(null, arguments);
343
+ }
344
+ }
345
+
346
+ function setStorageUtils(storageUtils) {
347
+ Object.assign(STORAGE, storageUtils);
348
+ }
349
+
350
+ function createStore (_namespace) {
351
+ const namespace = (key) => (0,_namespace__WEBPACK_IMPORTED_MODULE_2__.addNamespace)(_namespace, key);
352
+
353
+ return Object.assign(main.bind(null, namespace), {
354
+ add: (state) => addState(namespace, state, false),
355
+ addPersistent: (state) => addState(namespace, state, true),
356
+ get: (arg) => getState(namespace, arg),
357
+ set: (changes) => setState(namespace, changes),
358
+ resetAll: () => resetAllState(namespace),
359
+ onChange: (keys, cb) => addStateLitener(namespace, keys, cb),
360
+ removeListener: (keys, cb) => removeStateListener(namespace, keys, cb),
361
+ setStorageUtils,
362
+ onStateChange,
363
+ });
364
+ }
365
+
366
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (createStore(""));
367
+
368
+
369
+ /***/ },
370
+
371
+ /***/ "./src/namespace.js"
372
+ /*!**************************!*\
373
+ !*** ./src/namespace.js ***!
374
+ \**************************/
375
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
376
+
377
+ __webpack_require__.r(__webpack_exports__);
378
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
379
+ /* harmony export */ NAMESPACE_DELIMITER: () => (/* binding */ NAMESPACE_DELIMITER),
380
+ /* harmony export */ addNamespace: () => (/* binding */ addNamespace),
381
+ /* harmony export */ getByNamespace: () => (/* binding */ getByNamespace),
382
+ /* harmony export */ getKey: () => (/* binding */ getKey),
383
+ /* harmony export */ getNamespace: () => (/* binding */ getNamespace),
384
+ /* harmony export */ namespacify: () => (/* binding */ namespacify)
385
+ /* harmony export */ });
386
+ /* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helpers */ "./src/helpers.js");
387
+
388
+
389
+ const NAMESPACE_DELIMITER = ":";
390
+
391
+ function addNamespace(namespace, str) {
392
+ return `${namespace}${(0,_helpers__WEBPACK_IMPORTED_MODULE_0__.isString)(str) && NAMESPACE_DELIMITER || ""}${str || ""}`;
393
+ }
394
+
395
+ function getNamespace(str) {
396
+ return (
397
+ str.split(NAMESPACE_DELIMITER).slice(0, -1).join(NAMESPACE_DELIMITER)
398
+ );
399
+ }
400
+
401
+ function getKey (str) {
402
+ return str.split(NAMESPACE_DELIMITER).slice(-1)[0];
403
+ }
404
+
405
+ function getByNamespace(str, obj) {
406
+ const namespace = getNamespace(str) + NAMESPACE_DELIMITER;
407
+
408
+ return Object.fromEntries(
409
+ Object.entries(obj)
410
+ .filter(([k, v]) => k.startsWith(namespace))
411
+ .map(([k, v]) => [k.slice(namespace.length), v]),
412
+ );
413
+ }
414
+
415
+ function namespacify (namespace, obj) {
416
+ return Object.fromEntries(
417
+ Object.entries(obj)
418
+ .map(([k,v]) => [addNamespace(namespace, k), v]
419
+ ));
420
+ }
421
+
422
+
423
+ /***/ },
424
+
425
+ /***/ "./src/storage.js"
426
+ /*!************************!*\
427
+ !*** ./src/storage.js ***!
428
+ \************************/
429
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
430
+
431
+ __webpack_require__.r(__webpack_exports__);
432
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
433
+ /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
434
+ /* harmony export */ });
435
+ function updateFromLocalStorage(state) {
436
+ const stored = {};
437
+ for (const key in state) {
438
+ stored[key] = localStorage.getItem(key);
439
+ }
440
+
441
+ return Object.assign(state, stored);
442
+ }
443
+
444
+ function getStorageType(isPersistent) {
445
+ return isPersistent && "localStorage";
446
+ }
447
+
448
+ function isStorageAvailable(storageType) {
449
+ return storageType;
450
+ }
451
+
452
+ function setStorageValue(storageType, key, value) {
453
+ window.localStorage.setItem(key, value);
454
+ return false;
455
+ }
456
+
457
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({
458
+ GET_TYPE: getStorageType,
459
+ IS_AVAILABE: isStorageAvailable,
460
+ UPDATE_STATE: updateFromLocalStorage,
461
+ SET_VALUE: setStorageValue,
462
+ });
463
+
464
+
465
+ /***/ }
466
+
467
+ /******/ });
468
+ /************************************************************************/
469
+ /******/ // The module cache
470
+ /******/ const __webpack_module_cache__ = {};
471
+ /******/
472
+ /******/ // The require function
473
+ /******/ function __webpack_require__(moduleId) {
474
+ /******/ // Check if module is in cache
475
+ /******/ const cachedModule = __webpack_module_cache__[moduleId];
476
+ /******/ if (cachedModule !== undefined) {
477
+ /******/ return cachedModule.exports;
478
+ /******/ }
479
+ /******/ // Create a new module (and put it into the cache)
480
+ /******/ const module = __webpack_module_cache__[moduleId] = {
481
+ /******/ // no module.id needed
482
+ /******/ // no module.loaded needed
483
+ /******/ exports: {}
484
+ /******/ };
485
+ /******/
486
+ /******/ // Execute the module function
487
+ /******/ if (!(moduleId in __webpack_modules__)) {
488
+ /******/ delete __webpack_module_cache__[moduleId];
489
+ /******/ const e = new Error("Cannot find module '" + moduleId + "'");
490
+ /******/ e.code = 'MODULE_NOT_FOUND';
491
+ /******/ throw e;
492
+ /******/ }
493
+ /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
494
+ /******/
495
+ /******/ // Return the exports of the module
496
+ /******/ return module.exports;
497
+ /******/ }
498
+ /******/
499
+ /************************************************************************/
500
+ /******/ /* webpack/runtime/define property getters */
501
+ /******/ (() => {
502
+ /******/ // define getter/value functions for harmony exports
503
+ /******/ __webpack_require__.d = (exports, definition) => {
504
+ /******/ if(Array.isArray(definition)) {
505
+ /******/ var i = 0;
506
+ /******/ while(i < definition.length) {
507
+ /******/ var key = definition[i++];
508
+ /******/ var binding = definition[i++];
509
+ /******/ if(!__webpack_require__.o(exports, key)) {
510
+ /******/ if(binding === 0) {
511
+ /******/ Object.defineProperty(exports, key, { enumerable: true, value: definition[i++] });
512
+ /******/ } else {
513
+ /******/ Object.defineProperty(exports, key, { enumerable: true, get: binding });
514
+ /******/ }
515
+ /******/ } else if(binding === 0) { i++; }
516
+ /******/ }
517
+ /******/ } else {
518
+ /******/ for(var key in definition) {
519
+ /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
520
+ /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
521
+ /******/ }
522
+ /******/ }
523
+ /******/ }
524
+ /******/ };
525
+ /******/ })();
526
+ /******/
527
+ /******/ /* webpack/runtime/hasOwnProperty shorthand */
528
+ /******/ (() => {
529
+ /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
530
+ /******/ })();
531
+ /******/
532
+ /******/ /* webpack/runtime/make namespace object */
533
+ /******/ (() => {
534
+ /******/ // define __esModule on exports
535
+ /******/ __webpack_require__.r = (exports) => {
536
+ /******/ if(Symbol.toStringTag) {
537
+ /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
538
+ /******/ }
539
+ /******/ Object.defineProperty(exports, '__esModule', { value: true });
540
+ /******/ };
541
+ /******/ })();
542
+ /******/
543
+ /************************************************************************/
544
+ /******/
545
+ /******/ // startup
546
+ /******/ // Load entry module and return exports
547
+ /******/ // This entry module is referenced by other modules so it can't be inlined
548
+ /******/ let __webpack_exports__ = __webpack_require__("./src/index.js");
549
+ /******/ __webpack_exports__ = __webpack_exports__["default"];
550
+ /******/
551
+ /******/ return __webpack_exports__;
552
+ /******/ })()
553
+ ;
554
+ });
@@ -0,0 +1,2 @@
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/error.js"(e,t,n){n.r(t),n.d(t,{isKeyPresent:()=>o});var r=n("./src/index.js"),s=n("./src/namespace.js");const o=e=>{if(!r.ACCESSORS[e]){const[t,n]=e.split(s.NAMESPACE_DELIMITER);throw new Error(`Trying to access "${t}" key in "${n}" namespace, but it doesn't exist`)}return!0}},"./src/helpers.js"(e,t,n){n.r(t),n.d(t,{getKeys:()=>l,getParamNames:()=>u,isArray:()=>a,isFunction:()=>o,isObject:()=>c,isString:()=>i,toCamelCase:()=>f});const r=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,s=/([^\s,]+)/g;function o(e){return"function"==typeof e}function c(e){return"object"==typeof e}function i(e){return"string"==typeof e}function a(e){return Array.isArray(e)}function u(e){const t=e.toString().replace(r,""),n=t.slice(t.indexOf("(")+1,t.indexOf(")")).match(s);return null===n?[]:n}function l(e,t){return Object.fromEntries(Object.entries(e).map(([e,n])=>[e,n[t]]))}function f(e,t){const n=e.split(t);return`${n[0]}${n.slice(1).reduce((e,t)=>`${e}${t.charAt(0).toUpperCase()}${t.slice(1)}`,"")}`}},"./src/index.js"(e,t,n){n.r(t),n.d(t,{ACCESSORS:()=>a,default:()=>P});var r=n("./src/storage.js"),s=n("./src/helpers.js"),o=n("./src/namespace.js"),c=n("./src/error.js");const i={},a={},u={},l={},f={GET_TYPE:null,IS_AVAILABE:null,UPDATE_STATE:null,SET_VALUE:null};async function p(e,t,n){const r=f.GET_TYPE(n),s=Object.assign({},t),c=(0,o.namespacify)(e(),t);f.IS_AVAILABE(r)&&await f.UPDATE_STATE(c,r);const i={};for(const n in t)i[e(n)]=d(e(n),c[e(n)],s[n],r);return Object.assign(a,i),T(e())}function d(e,t,n,r){const c=(0,s.isFunction)(t);return c&&function(e,t){const n=(0,o.getNamespace)(e),r=(0,s.getParamNames)(t).map(e=>(0,o.addNamespace)(n,e));l[e]=r,r.forEach(t=>{u[t]?u[t].push(e):u[t]=[e]})}(e,t),i[e]={value:c?t.apply(null,g(e)):t,computeFn:t,listeners:[],defaultValue:n},function(e,t,n){const r=()=>i[e].value;return Object.assign(r,{valueOf:()=>i[e].value,toString:()=>i[e].value,set:t=>m(e,t,n),onChange:t=>i[e].listeners.push(t),removeListener:t=>i[e].listeners=i[e].listeners.filter(e=>e!==t),reset:()=>m(e,i[e].defaultValue,n)}),new Proxy(r,{get:(t,n)=>Object.keys(r).includes(n)?t[n]:i[e].value[n]})}(e,0,r)}function g(e){const t=A(e);return l[e].map(e=>t[(0,o.getKey)(e)]).concat(t)}function m(e,t,n){if(f.IS_AVAILABE(n)){if(f.SET_VALUE(n,e,t))return}y({[e]:{newValue:t}})}function y(e){const t={};for(const n in e){const r=i[n].value,s=e[n].newValue;r!==s&&(i[n].value=s,t[n]={newValue:s,prevValue:r},E(n,t))}for(const e in t)i[e].listeners.forEach(n=>n(i[e].value,A(e),t[e]))}function E(e,t){const n=u[e];n&&n.forEach(e=>{const n=i[e].value,r=i[e].computeFn.apply(null,g(e));n!==r&&(i[e].value=r,t[e]={newValue:r,prevValue:n},E(e,t))})}function j(e,t){return(0,s.isString)(t)?T(t):(0,s.isFunction)(t)?function(e,t){const n=(0,o.getByNamespace)(e,a);return t.call(null,n,T(e()))}(e(""),t):A(e(""))}function A(e){return(0,s.getKeys)((0,o.getByNamespace)(e,i),"value")}function b(e,t){if(!Object.keys(t).length)S();else for(const[n,r]of Object.entries(t))(0,c.isKeyPresent)(e(n))&&a[e(n)].set(r);return T(e())}function S(e){return Object.entries(a).filter(([t])=>t.startsWith(e())).forEach((e,{reset:t})=>t()),T(e())}function O(e,t,n){return t.forEach(t=>a[e(t)].onChange(n)),T(e())}function v(){const e=arguments[1];return!e||(0,s.isFunction)(e)||(0,s.isString)(e)?j.apply(null,arguments):Array.isArray(e)?O.apply(null,arguments):(0,s.isObject)(e)?b.apply(null,arguments):void 0}function h(e){Object.assign(f,e)}function T(e){const t=t=>(0,o.addNamespace)(e,t);return Object.assign(v.bind(null,t),{add:e=>p(t,e,!1),addPersistent:e=>p(t,e,!0),get:e=>j(t,e),set:e=>b(t,e),resetAll:()=>S(t),onChange:(e,n)=>O(t,e,n),removeListener:(e,n)=>function(e,t,n){return t.forEach(t=>a[e(t)].removeListener(n)),T(e())}(t,e,n),setStorageUtils:h,onStateChange:y})}h(r.default);const P=T("")},"./src/namespace.js"(e,t,n){n.r(t),n.d(t,{NAMESPACE_DELIMITER:()=>s,addNamespace:()=>o,getByNamespace:()=>a,getKey:()=>i,getNamespace:()=>c,namespacify:()=>u});var r=n("./src/helpers.js");const s=":";function o(e,t){return`${e}${(0,r.isString)(t)&&s||""}${t||""}`}function c(e){return e.split(s).slice(0,-1).join(s)}function i(e){return e.split(s).slice(-1)[0]}function a(e,t){const n=c(e)+s;return Object.fromEntries(Object.entries(t).filter(([e,t])=>e.startsWith(n)).map(([e,t])=>[e.slice(n.length),t]))}function u(e,t){return Object.fromEntries(Object.entries(t).map(([t,n])=>[o(e,t),n]))}},"./src/storage.js"(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:function(e){const t={};for(const n in e)t[n]=localStorage.getItem(n);return Object.assign(e,t)},SET_VALUE:function(e,t,n){return window.localStorage.setItem(t,n),!1}}}};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.js");return r=r.default,r})());
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "varstor",
3
+ "version": "0.0.1",
4
+ "description": "Library for managing the state of applications, employing reactivity, and seamless usage of storage with a simple unified interface",
5
+ "license": "MIT",
6
+ "author": "Igor Morozov <ismorozs@gmail.com>",
7
+ "main": "./dist/varstor.js",
8
+ "scripts": {
9
+ "start": "webpack",
10
+ "build": "webpack --env production"
11
+ },
12
+ "devDependencies": {
13
+ "minimizer-webpack-plugin": "5.6.1",
14
+ "webpack": "5.108.4",
15
+ "webpack-cli": "7.2.1"
16
+ },
17
+ "homepage": "https://github.com/ismorozs/varstor",
18
+ "repository": "https://github.com/ismorozs/varstor.git",
19
+ "bugs": "https://github.com/ismorozs/varstor/issues"
20
+ }
package/src/error.js ADDED
@@ -0,0 +1,11 @@
1
+ import { ACCESSORS } from "."
2
+ import { NAMESPACE_DELIMITER } from "./namespace";
3
+
4
+ export const isKeyPresent = (fullKey) => {
5
+ if (!ACCESSORS[fullKey]) {
6
+ const [key, namespace] = fullKey.split(NAMESPACE_DELIMITER);
7
+ throw new Error (`Trying to access "${key}" key in "${namespace}" namespace, but it doesn't exist`);
8
+ }
9
+
10
+ return true;
11
+ }
package/src/helpers.js ADDED
@@ -0,0 +1,40 @@
1
+ const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;
2
+ const ARGUMENT_NAMES = /([^\s,]+)/g;
3
+
4
+ export function isFunction(x) {
5
+ return typeof x === "function";
6
+ }
7
+
8
+ export function isObject(x) {
9
+ return typeof x === "object";
10
+ }
11
+
12
+ export function isString(x) {
13
+ return typeof x === "string";
14
+ }
15
+
16
+ export function isArray(x) {
17
+ return Array.isArray(x);
18
+ }
19
+
20
+ export function getParamNames(fn) {
21
+ const fnStr = fn.toString().replace(STRIP_COMMENTS, "");
22
+ const names = fnStr
23
+ .slice(fnStr.indexOf("(") + 1, fnStr.indexOf(")"))
24
+ .match(ARGUMENT_NAMES);
25
+
26
+ if (names === null) {
27
+ return [];
28
+ }
29
+
30
+ return names;
31
+ }
32
+
33
+ export function getKeys(obj, key) {
34
+ return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, v[key]]));
35
+ }
36
+
37
+ export function toCamelCase(str, delimiter) {
38
+ const strArr = str.split(delimiter);
39
+ return `${strArr[0]}${strArr.slice(1).reduce((a, c) => `${a}${c.charAt(0).toUpperCase()}${c.slice(1)}`, "")}`;
40
+ }
package/src/index.js ADDED
@@ -0,0 +1,262 @@
1
+ import storageUtils from './storage';
2
+
3
+ import {
4
+ isArray, isFunction, isObject, isString,
5
+ getParamNames,
6
+ getKeys,
7
+ } from './helpers';
8
+
9
+ import {
10
+ addNamespace,
11
+ getNamespace,
12
+ getKey,
13
+ namespacify,
14
+ getByNamespace,
15
+ } from "./namespace";
16
+
17
+ import {
18
+ isKeyPresent
19
+ } from './error';
20
+
21
+ const STATE = {};
22
+ export const ACCESSORS = {};
23
+ const COMPUTED_DEPENDENCIES = {};
24
+ const COMPUTED_ARGUMENTS = {};
25
+
26
+ const STORAGE = {
27
+ GET_TYPE: null,
28
+ IS_AVAILABE: null,
29
+ UPDATE_STATE: null,
30
+ SET_VALUE: null
31
+ };
32
+
33
+ setStorageUtils(storageUtils);
34
+
35
+ async function addState (namespace, initialState, isPersistent) {
36
+ const storageType = STORAGE.GET_TYPE(isPersistent);
37
+ const defaultValues = Object.assign({}, initialState);
38
+ const namespacedValues = namespacify(namespace(), initialState);
39
+
40
+ if (STORAGE.IS_AVAILABE(storageType)) {
41
+ await STORAGE.UPDATE_STATE(namespacedValues, storageType);
42
+ }
43
+
44
+ const accessors = {};
45
+ for (const key in initialState) {
46
+ accessors[namespace(key)] = setupValue(
47
+ namespace(key),
48
+ namespacedValues[namespace(key)],
49
+ defaultValues[key],
50
+ storageType,
51
+ );
52
+ }
53
+
54
+ Object.assign(ACCESSORS, accessors);
55
+ return createStore(namespace());
56
+ }
57
+
58
+ function setupValue (key, value, defaultValue, storageType) {
59
+ const isComputedValue = isFunction(value);
60
+
61
+ if (isComputedValue) {
62
+ setupDependencies(key, value);
63
+ }
64
+
65
+ STATE[key] = {
66
+ value: isComputedValue ? value.apply(null, getArguments(key)) : value,
67
+ computeFn: value,
68
+ listeners: [],
69
+ defaultValue,
70
+ };
71
+
72
+ return createAccessor(key, value, storageType);
73
+ }
74
+
75
+ function setupDependencies(computedValueName, computeFn) {
76
+ const namespace = getNamespace(computedValueName);
77
+ const paramNames = getParamNames(computeFn).map((name) => addNamespace(namespace, name));
78
+ COMPUTED_ARGUMENTS[computedValueName] = paramNames;
79
+
80
+ paramNames.forEach((param) => {
81
+ if (COMPUTED_DEPENDENCIES[param]) {
82
+ COMPUTED_DEPENDENCIES[param].push(computedValueName);
83
+ } else {
84
+ COMPUTED_DEPENDENCIES[param] = [computedValueName];
85
+ }
86
+ });
87
+ }
88
+
89
+ function getArguments(computedName) {
90
+ const values = getNamespaceValues(computedName);
91
+
92
+ return COMPUTED_ARGUMENTS[computedName]
93
+ .map((name) => values[getKey(name)])
94
+ .concat(values);
95
+ }
96
+
97
+ function createAccessor(key, value, storageType) {
98
+ const accessor = () => STATE[key].value;
99
+
100
+ Object.assign(accessor, {
101
+ valueOf: () => STATE[key].value,
102
+ toString: () => STATE[key].value,
103
+ set: (value) => setValue(key, value, storageType),
104
+ onChange: (cb) => STATE[key].listeners.push(cb),
105
+ removeListener: (removeCb) =>
106
+ (STATE[key].listeners = STATE[key].listeners.filter(
107
+ (cb) => cb !== removeCb,
108
+ )),
109
+ reset: () => setValue(key, STATE[key].defaultValue, storageType),
110
+ });
111
+
112
+ return new Proxy(accessor, {
113
+ get: (target, prop) => {
114
+ if (Object.keys(accessor).includes(prop)) {
115
+ return target[prop];
116
+ }
117
+
118
+ return STATE[key].value[prop];
119
+ },
120
+ });
121
+ }
122
+
123
+ function setValue (key, value, storageType) {
124
+ if (STORAGE.IS_AVAILABE(storageType)) {
125
+ const isAutoUpdate = STORAGE.SET_VALUE(storageType, key, value);
126
+ if (isAutoUpdate) {
127
+ return;
128
+ }
129
+ }
130
+
131
+ onStateChange({ [key]: { newValue: value } });
132
+ }
133
+
134
+ function onStateChange (changes) {
135
+ const realChanges = {};
136
+
137
+ for (const key in changes) {
138
+ const prevValue = STATE[key].value;
139
+ const newValue = changes[key].newValue;
140
+
141
+ if (prevValue !== newValue) {
142
+ STATE[key].value = newValue;
143
+ realChanges[key] = { newValue, prevValue };
144
+
145
+ updateDependencies(key, realChanges);
146
+ }
147
+ }
148
+
149
+ for (const key in realChanges) {
150
+ STATE[key].listeners.forEach((cb) => cb(STATE[key].value, getNamespaceValues(key), realChanges[key]));
151
+ }
152
+ }
153
+
154
+ function updateDependencies (key, realChanges) {
155
+ const computedDependencies = COMPUTED_DEPENDENCIES[key];
156
+ if (computedDependencies) {
157
+ computedDependencies.forEach((name) => {
158
+ const prevValue = STATE[name].value;
159
+ const newValue = STATE[name].computeFn.apply(null, getArguments(name));
160
+ if (prevValue !== newValue) {
161
+ STATE[name].value = newValue;
162
+ realChanges[name] = { newValue, prevValue };
163
+ updateDependencies(name, realChanges);
164
+ }
165
+ });
166
+ }
167
+ }
168
+
169
+ function getState(namespace, arg) {
170
+ if (isString(arg)) {
171
+ return createStore(arg);
172
+ }
173
+
174
+ if (isFunction(arg)) {
175
+ return getNamespaceAccessors(namespace(""), arg);
176
+ }
177
+
178
+ return getNamespaceValues(namespace(""));
179
+ }
180
+
181
+ function getNamespaceValues(namespace) {
182
+ return getKeys(getByNamespace(namespace, STATE), "value");
183
+ }
184
+
185
+ function getNamespaceAccessors (namespace, cb) {
186
+ const accessors = getByNamespace(namespace, ACCESSORS);
187
+ return cb.call(null, accessors, createStore(namespace()));
188
+ }
189
+
190
+ function setState (namespace, changes) {
191
+ const noKeys = !Object.keys(changes).length;
192
+
193
+ if (noKeys) {
194
+ resetAllState();
195
+ } else {
196
+ for (const [k,v] of Object.entries(changes)) {
197
+ isKeyPresent(namespace(k)) && ACCESSORS[namespace(k)].set(v);
198
+ };
199
+ }
200
+
201
+ return createStore(namespace());
202
+ }
203
+
204
+ function resetAllState (namespace) {
205
+ Object.entries(ACCESSORS)
206
+ .filter(([k]) => k.startsWith(namespace()))
207
+ .forEach((k, { reset }) => reset());
208
+
209
+ return createStore(namespace());
210
+ }
211
+
212
+ function addStateLitener (namespace, observables, cb) {
213
+ observables.forEach((key) => ACCESSORS[namespace(key)].onChange(cb));
214
+
215
+ return createStore(namespace());
216
+ }
217
+
218
+ function removeStateListener(namespace, observables, cb) {
219
+ observables.forEach((key) =>
220
+ ACCESSORS[namespace(key)].removeListener(cb),
221
+ );
222
+
223
+ return createStore(namespace());
224
+ }
225
+
226
+ function main () {
227
+ const arg1 = arguments[1];
228
+
229
+ if (!arg1 || isFunction(arg1) || isString(arg1)) {
230
+ return getState.apply(null, arguments);
231
+ }
232
+
233
+ if (Array.isArray(arg1)) {
234
+ return addStateLitener.apply(null, arguments);
235
+ }
236
+
237
+ if (isObject(arg1)) {
238
+ return setState.apply(null, arguments);
239
+ }
240
+ }
241
+
242
+ function setStorageUtils(storageUtils) {
243
+ Object.assign(STORAGE, storageUtils);
244
+ }
245
+
246
+ function createStore (_namespace) {
247
+ const namespace = (key) => addNamespace(_namespace, key);
248
+
249
+ return Object.assign(main.bind(null, namespace), {
250
+ add: (state) => addState(namespace, state, false),
251
+ addPersistent: (state) => addState(namespace, state, true),
252
+ get: (arg) => getState(namespace, arg),
253
+ set: (changes) => setState(namespace, changes),
254
+ resetAll: () => resetAllState(namespace),
255
+ onChange: (keys, cb) => addStateLitener(namespace, keys, cb),
256
+ removeListener: (keys, cb) => removeStateListener(namespace, keys, cb),
257
+ setStorageUtils,
258
+ onStateChange,
259
+ });
260
+ }
261
+
262
+ export default createStore("");
@@ -0,0 +1,36 @@
1
+ import {
2
+ getKeys, isString, toCamelCase
3
+ } from './helpers';
4
+
5
+ export const NAMESPACE_DELIMITER = ":";
6
+
7
+ export function addNamespace(namespace, str) {
8
+ return `${namespace}${isString(str) && NAMESPACE_DELIMITER || ""}${str || ""}`;
9
+ }
10
+
11
+ export function getNamespace(str) {
12
+ return (
13
+ str.split(NAMESPACE_DELIMITER).slice(0, -1).join(NAMESPACE_DELIMITER)
14
+ );
15
+ }
16
+
17
+ export function getKey (str) {
18
+ return str.split(NAMESPACE_DELIMITER).slice(-1)[0];
19
+ }
20
+
21
+ export function getByNamespace(str, obj) {
22
+ const namespace = getNamespace(str) + NAMESPACE_DELIMITER;
23
+
24
+ return Object.fromEntries(
25
+ Object.entries(obj)
26
+ .filter(([k, v]) => k.startsWith(namespace))
27
+ .map(([k, v]) => [k.slice(namespace.length), v]),
28
+ );
29
+ }
30
+
31
+ export function namespacify (namespace, obj) {
32
+ return Object.fromEntries(
33
+ Object.entries(obj)
34
+ .map(([k,v]) => [addNamespace(namespace, k), v]
35
+ ));
36
+ }
package/src/storage.js ADDED
@@ -0,0 +1,28 @@
1
+ function updateFromLocalStorage(state) {
2
+ const stored = {};
3
+ for (const key in state) {
4
+ stored[key] = localStorage.getItem(key);
5
+ }
6
+
7
+ return Object.assign(state, stored);
8
+ }
9
+
10
+ function getStorageType(isPersistent) {
11
+ return isPersistent && "localStorage";
12
+ }
13
+
14
+ function isStorageAvailable(storageType) {
15
+ return storageType;
16
+ }
17
+
18
+ function setStorageValue(storageType, key, value) {
19
+ window.localStorage.setItem(key, value);
20
+ return false;
21
+ }
22
+
23
+ export default {
24
+ GET_TYPE: getStorageType,
25
+ IS_AVAILABE: isStorageAvailable,
26
+ UPDATE_STATE: updateFromLocalStorage,
27
+ SET_VALUE: setStorageValue,
28
+ };
@@ -0,0 +1,33 @@
1
+ const MinimizerPlugin = require("minimizer-webpack-plugin");
2
+
3
+ module.exports = (env) => {
4
+ const options = {
5
+ entry: "./src/index.js",
6
+ output: {
7
+ filename: "varstor.js",
8
+ library: "Varstor",
9
+ libraryTarget: "umd",
10
+ libraryExport: "default",
11
+ globalObject: "this",
12
+ },
13
+ mode: "development",
14
+ watch: true,
15
+
16
+ stats: {
17
+ colors: true,
18
+ },
19
+
20
+ devtool: false,
21
+ };
22
+
23
+ if(env.production) {
24
+ options.optimization = {
25
+ minimize: true,
26
+ minimizer: [new MinimizerPlugin()],
27
+ };
28
+ options.output.filename = "varstor.min.js";
29
+ }
30
+
31
+ return options;
32
+
33
+ };