svstate 1.0.0 → 1.1.0
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/README.md +2 -0
- package/dist/index.js +2 -10
- package/dist/proxy.js +6 -10
- package/dist/state.svelte.js +16 -20
- package/dist/validators.js +8 -14
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
[](https://svelte.dev/)
|
|
7
7
|
[](https://opensource.org/licenses/ISC)
|
|
8
|
+
[]()
|
|
9
|
+
[]()
|
|
8
10
|
|
|
9
11
|
> **Deep reactive proxy with validation, snapshot/undo, and side effects — built for complex, real-world applications.**
|
|
10
12
|
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.stringValidator = exports.numberValidator = exports.dateValidator = exports.arrayValidator = exports.createSvState = void 0;
|
|
4
|
-
var state_svelte_1 = require("./state.svelte");
|
|
5
|
-
Object.defineProperty(exports, "createSvState", { enumerable: true, get: function () { return state_svelte_1.createSvState; } });
|
|
6
|
-
var validators_1 = require("./validators");
|
|
7
|
-
Object.defineProperty(exports, "arrayValidator", { enumerable: true, get: function () { return validators_1.arrayValidator; } });
|
|
8
|
-
Object.defineProperty(exports, "dateValidator", { enumerable: true, get: function () { return validators_1.dateValidator; } });
|
|
9
|
-
Object.defineProperty(exports, "numberValidator", { enumerable: true, get: function () { return validators_1.numberValidator; } });
|
|
10
|
-
Object.defineProperty(exports, "stringValidator", { enumerable: true, get: function () { return validators_1.stringValidator; } });
|
|
1
|
+
export { createSvState } from './state.svelte';
|
|
2
|
+
export { arrayValidator, dateValidator, numberValidator, stringValidator } from './validators';
|
package/dist/proxy.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ChangeProxy = void 0;
|
|
4
1
|
const isProxiable = (value) => typeof value === 'object' &&
|
|
5
2
|
value !== null &&
|
|
6
3
|
!(value instanceof Date) &&
|
|
@@ -11,10 +8,10 @@ const isProxiable = (value) => typeof value === 'object' &&
|
|
|
11
8
|
!(value instanceof RegExp) &&
|
|
12
9
|
!(value instanceof Error) &&
|
|
13
10
|
!(value instanceof Promise);
|
|
14
|
-
const ChangeProxy = (source, changed) => {
|
|
11
|
+
export const ChangeProxy = (source, changed) => {
|
|
15
12
|
const createProxy = (target, parentPath) => new Proxy(target, {
|
|
16
|
-
get(object, property
|
|
17
|
-
const value =
|
|
13
|
+
get(object, property) {
|
|
14
|
+
const value = object[property];
|
|
18
15
|
if (isProxiable(value)) {
|
|
19
16
|
const pathSegment = Number.isInteger(Number(property)) ? '' : String(property);
|
|
20
17
|
const childPath = pathSegment ? (parentPath ? `${parentPath}.${pathSegment}` : pathSegment) : parentPath;
|
|
@@ -22,10 +19,10 @@ const ChangeProxy = (source, changed) => {
|
|
|
22
19
|
}
|
|
23
20
|
return value;
|
|
24
21
|
},
|
|
25
|
-
set(object, property, incomingValue
|
|
26
|
-
const oldValue =
|
|
22
|
+
set(object, property, incomingValue) {
|
|
23
|
+
const oldValue = object[property];
|
|
27
24
|
if (oldValue !== incomingValue) {
|
|
28
|
-
|
|
25
|
+
object[property] = incomingValue;
|
|
29
26
|
const pathSegment = Number.isInteger(Number(property)) ? '' : String(property);
|
|
30
27
|
const fullPath = pathSegment ? (parentPath ? `${parentPath}.${pathSegment}` : pathSegment) : parentPath;
|
|
31
28
|
changed(data, fullPath, incomingValue, oldValue);
|
|
@@ -36,4 +33,3 @@ const ChangeProxy = (source, changed) => {
|
|
|
36
33
|
const data = createProxy(source, '');
|
|
37
34
|
return data;
|
|
38
35
|
};
|
|
39
|
-
exports.ChangeProxy = ChangeProxy;
|
package/dist/state.svelte.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.createSvState = createSvState;
|
|
4
|
-
const store_1 = require("svelte/store");
|
|
5
|
-
const proxy_1 = require("./proxy");
|
|
1
|
+
import { derived, get, writable } from 'svelte/store';
|
|
2
|
+
import { ChangeProxy } from './proxy';
|
|
6
3
|
const checkHasErrors = (validator) => Object.values(validator).some((item) => (typeof item === 'string' ? !!item : checkHasErrors(item)));
|
|
7
4
|
const hasAnyErrors = ($errors) => !!$errors && checkHasErrors($errors);
|
|
8
5
|
const deepClone = (object) => {
|
|
@@ -13,9 +10,8 @@ const deepClone = (object) => {
|
|
|
13
10
|
if (Array.isArray(object))
|
|
14
11
|
return object.map((item) => deepClone(item));
|
|
15
12
|
const cloned = {};
|
|
16
|
-
for (const key
|
|
17
|
-
|
|
18
|
-
cloned[key] = deepClone(object[key]);
|
|
13
|
+
for (const key of Object.keys(object))
|
|
14
|
+
cloned[key] = deepClone(object[key]);
|
|
19
15
|
return cloned;
|
|
20
16
|
};
|
|
21
17
|
const defaultOptions = {
|
|
@@ -24,18 +20,18 @@ const defaultOptions = {
|
|
|
24
20
|
allowConcurrentActions: false,
|
|
25
21
|
persistActionError: false
|
|
26
22
|
};
|
|
27
|
-
function createSvState(init, actuators, options) {
|
|
23
|
+
export function createSvState(init, actuators, options) {
|
|
28
24
|
const usedOptions = { ...defaultOptions, ...options };
|
|
29
25
|
const { validator, effect } = actuators ?? {};
|
|
30
|
-
const errors =
|
|
31
|
-
const hasErrors =
|
|
32
|
-
const isDirty =
|
|
33
|
-
const actionInProgress =
|
|
34
|
-
const actionError =
|
|
35
|
-
const snapshots =
|
|
26
|
+
const errors = writable();
|
|
27
|
+
const hasErrors = derived(errors, hasAnyErrors);
|
|
28
|
+
const isDirty = writable(false);
|
|
29
|
+
const actionInProgress = writable(false);
|
|
30
|
+
const actionError = writable();
|
|
31
|
+
const snapshots = writable([{ title: 'Initial', data: deepClone(init) }]);
|
|
36
32
|
const stateObject = $state(init);
|
|
37
33
|
const createSnapshot = (title, replace = true) => {
|
|
38
|
-
const currentSnapshots =
|
|
34
|
+
const currentSnapshots = get(snapshots);
|
|
39
35
|
const createdSnapshot = { title, data: deepClone(stateObject) };
|
|
40
36
|
const lastSnapshot = currentSnapshots.at(-1);
|
|
41
37
|
if (replace && lastSnapshot && lastSnapshot.title === title)
|
|
@@ -64,7 +60,7 @@ function createSvState(init, actuators, options) {
|
|
|
64
60
|
});
|
|
65
61
|
}
|
|
66
62
|
};
|
|
67
|
-
const data =
|
|
63
|
+
const data = ChangeProxy(stateObject, (target, property, currentValue, oldValue) => {
|
|
68
64
|
if (!usedOptions.persistActionError)
|
|
69
65
|
actionError.set(undefined);
|
|
70
66
|
isDirty.set(true);
|
|
@@ -76,7 +72,7 @@ function createSvState(init, actuators, options) {
|
|
|
76
72
|
if (validator)
|
|
77
73
|
errors.set(validator(data));
|
|
78
74
|
const execute = async (parameters) => {
|
|
79
|
-
if (!usedOptions.allowConcurrentActions &&
|
|
75
|
+
if (!usedOptions.allowConcurrentActions && get(actionInProgress))
|
|
80
76
|
return;
|
|
81
77
|
actionError.set(undefined);
|
|
82
78
|
actionInProgress.set(true);
|
|
@@ -96,7 +92,7 @@ function createSvState(init, actuators, options) {
|
|
|
96
92
|
}
|
|
97
93
|
};
|
|
98
94
|
const rollback = (steps = 1) => {
|
|
99
|
-
const currentSnapshots =
|
|
95
|
+
const currentSnapshots = get(snapshots);
|
|
100
96
|
if (currentSnapshots.length <= 1)
|
|
101
97
|
return;
|
|
102
98
|
const targetIndex = Math.max(0, currentSnapshots.length - 1 - steps);
|
|
@@ -109,7 +105,7 @@ function createSvState(init, actuators, options) {
|
|
|
109
105
|
errors.set(validator(data));
|
|
110
106
|
};
|
|
111
107
|
const reset = () => {
|
|
112
|
-
const currentSnapshots =
|
|
108
|
+
const currentSnapshots = get(snapshots);
|
|
113
109
|
const initialSnapshot = currentSnapshots[0];
|
|
114
110
|
if (!initialSnapshot)
|
|
115
111
|
return;
|
package/dist/validators.js
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.stringValidator = stringValidator;
|
|
4
|
-
exports.numberValidator = numberValidator;
|
|
5
|
-
exports.arrayValidator = arrayValidator;
|
|
6
|
-
exports.dateValidator = dateValidator;
|
|
7
1
|
const prepareOps = {
|
|
8
2
|
trim: (s) => s.trim(),
|
|
9
3
|
normalize: (s) => s.replaceAll(/\s{2,}/g, ' '),
|
|
10
|
-
upper: (s) => s.
|
|
11
|
-
lower: (s) => s.
|
|
4
|
+
upper: (s) => s.toUpperCase(),
|
|
5
|
+
lower: (s) => s.toLowerCase()
|
|
12
6
|
};
|
|
13
|
-
function stringValidator(input, ...prepares) {
|
|
7
|
+
export function stringValidator(input, ...prepares) {
|
|
14
8
|
let error = '';
|
|
15
9
|
const setError = (message) => {
|
|
16
10
|
if (!error)
|
|
@@ -39,12 +33,12 @@ function stringValidator(input, ...prepares) {
|
|
|
39
33
|
return builder;
|
|
40
34
|
},
|
|
41
35
|
uppercase() {
|
|
42
|
-
if (!error && processedInput !== processedInput.
|
|
36
|
+
if (!error && processedInput !== processedInput.toUpperCase())
|
|
43
37
|
setError('Uppercase only');
|
|
44
38
|
return builder;
|
|
45
39
|
},
|
|
46
40
|
lowercase() {
|
|
47
|
-
if (!error && processedInput !== processedInput.
|
|
41
|
+
if (!error && processedInput !== processedInput.toLowerCase())
|
|
48
42
|
setError('Lowercase only');
|
|
49
43
|
return builder;
|
|
50
44
|
},
|
|
@@ -113,7 +107,7 @@ function stringValidator(input, ...prepares) {
|
|
|
113
107
|
};
|
|
114
108
|
return builder;
|
|
115
109
|
}
|
|
116
|
-
function numberValidator(input) {
|
|
110
|
+
export function numberValidator(input) {
|
|
117
111
|
let error = '';
|
|
118
112
|
const setError = (message) => {
|
|
119
113
|
if (!error)
|
|
@@ -185,7 +179,7 @@ function numberValidator(input) {
|
|
|
185
179
|
};
|
|
186
180
|
return builder;
|
|
187
181
|
}
|
|
188
|
-
function arrayValidator(input) {
|
|
182
|
+
export function arrayValidator(input) {
|
|
189
183
|
let error = '';
|
|
190
184
|
const setError = (message) => {
|
|
191
185
|
if (!error)
|
|
@@ -227,7 +221,7 @@ function arrayValidator(input) {
|
|
|
227
221
|
};
|
|
228
222
|
return builder;
|
|
229
223
|
}
|
|
230
|
-
function dateValidator(input) {
|
|
224
|
+
export function dateValidator(input) {
|
|
231
225
|
let error = '';
|
|
232
226
|
const setError = (message) => {
|
|
233
227
|
if (!error)
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svstate",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Supercharged $state() for Svelte 5: deep reactive proxy with validation, cross-field rules, computed & side-effects",
|
|
5
5
|
"author": "BCsabaEngine",
|
|
6
6
|
"license": "ISC",
|
|
7
|
+
"type": "module",
|
|
7
8
|
"main": "./dist/index.js",
|
|
8
9
|
"types": "./dist/index.d.ts",
|
|
9
10
|
"exports": {
|
|
10
11
|
".": {
|
|
11
12
|
"types": "./dist/index.d.ts",
|
|
12
|
-
"
|
|
13
|
+
"import": "./dist/index.js"
|
|
13
14
|
}
|
|
14
15
|
},
|
|
15
16
|
"engines": {
|
|
@@ -54,8 +55,8 @@
|
|
|
54
55
|
"devDependencies": {
|
|
55
56
|
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
|
56
57
|
"@types/node": "^25.0.9",
|
|
57
|
-
"@typescript-eslint/eslint-plugin": "^8.53.
|
|
58
|
-
"@typescript-eslint/parser": "^8.53.
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "^8.53.1",
|
|
59
|
+
"@typescript-eslint/parser": "^8.53.1",
|
|
59
60
|
"@vitest/coverage-v8": "^4.0.17",
|
|
60
61
|
"eslint": "^9.39.2",
|
|
61
62
|
"eslint-config-prettier": "^10.1.8",
|
|
@@ -63,7 +64,7 @@
|
|
|
63
64
|
"eslint-plugin-unicorn": "^62.0.0",
|
|
64
65
|
"nodemon": "^3.1.11",
|
|
65
66
|
"prettier": "^3.8.0",
|
|
66
|
-
"svelte": "^5.
|
|
67
|
+
"svelte": "^5.47.1",
|
|
67
68
|
"ts-node": "^10.9.2",
|
|
68
69
|
"tsx": "^4.21.0",
|
|
69
70
|
"typescript": "^5.9.3",
|