cogsbox-shape 0.5.212 → 0.5.213
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.
|
@@ -37,6 +37,7 @@ type FormUpdateParams = {
|
|
|
37
37
|
path: string[];
|
|
38
38
|
event: {
|
|
39
39
|
activityType: string;
|
|
40
|
+
details?: Record<string, unknown>;
|
|
40
41
|
};
|
|
41
42
|
getState: () => unknown;
|
|
42
43
|
addZodErrors: (errors: Array<{
|
|
@@ -44,7 +45,7 @@ type FormUpdateParams = {
|
|
|
44
45
|
message: string;
|
|
45
46
|
code?: string;
|
|
46
47
|
}>) => void;
|
|
47
|
-
clearZodErrors
|
|
48
|
+
clearZodErrors?: (paths: string[][]) => void;
|
|
48
49
|
};
|
|
49
50
|
export declare function wireShapeValidationOptions(box: ShapeSchemaBox, params: TransformStateParams): void;
|
|
50
51
|
/** Cross-field refine errors only — field rules are handled by state via setOptions. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createPluginContext } from "cogsbox-state";
|
|
1
|
+
import { createPluginContext, getGlobalStore } from "cogsbox-state";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
function pathKey(path) {
|
|
4
4
|
return path.join("\0");
|
|
@@ -14,6 +14,100 @@ function mapZodIssues(issues) {
|
|
|
14
14
|
code: issue.code,
|
|
15
15
|
}));
|
|
16
16
|
}
|
|
17
|
+
function cloneStateForInputEvent(state, path, value) {
|
|
18
|
+
if (path.length === 0)
|
|
19
|
+
return value;
|
|
20
|
+
if (state === null || typeof state !== "object")
|
|
21
|
+
return state;
|
|
22
|
+
const root = Array.isArray(state)
|
|
23
|
+
? [...state]
|
|
24
|
+
: { ...state };
|
|
25
|
+
let cursor = root;
|
|
26
|
+
for (let index = 0; index < path.length - 1; index++) {
|
|
27
|
+
const segment = path[index];
|
|
28
|
+
if (Array.isArray(cursor)) {
|
|
29
|
+
const arrayIndex = Number(segment);
|
|
30
|
+
if (!Number.isInteger(arrayIndex))
|
|
31
|
+
return root;
|
|
32
|
+
const next = cursor[arrayIndex];
|
|
33
|
+
const cloned = next && typeof next === "object"
|
|
34
|
+
? Array.isArray(next)
|
|
35
|
+
? [...next]
|
|
36
|
+
: { ...next }
|
|
37
|
+
: {};
|
|
38
|
+
cursor[arrayIndex] = cloned;
|
|
39
|
+
cursor = cloned;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const next = cursor[segment];
|
|
43
|
+
const cloned = next && typeof next === "object"
|
|
44
|
+
? Array.isArray(next)
|
|
45
|
+
? [...next]
|
|
46
|
+
: { ...next }
|
|
47
|
+
: {};
|
|
48
|
+
cursor[segment] = cloned;
|
|
49
|
+
cursor = cloned;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const leaf = path[path.length - 1];
|
|
53
|
+
if (Array.isArray(cursor)) {
|
|
54
|
+
const arrayIndex = Number(leaf);
|
|
55
|
+
if (Number.isInteger(arrayIndex))
|
|
56
|
+
cursor[arrayIndex] = value;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
cursor[leaf] = value;
|
|
60
|
+
}
|
|
61
|
+
return root;
|
|
62
|
+
}
|
|
63
|
+
function getStateForValidation(params) {
|
|
64
|
+
const state = params.getState();
|
|
65
|
+
if (params.event.activityType !== "input" ||
|
|
66
|
+
!("details" in params.event) ||
|
|
67
|
+
!params.event.details ||
|
|
68
|
+
typeof params.event.details !== "object" ||
|
|
69
|
+
!("value" in params.event.details)) {
|
|
70
|
+
return state;
|
|
71
|
+
}
|
|
72
|
+
return cloneStateForInputEvent(state, params.path, params.event.details.value);
|
|
73
|
+
}
|
|
74
|
+
function notifyValidationPaths(stateKey, paths) {
|
|
75
|
+
const store = getGlobalStore.getState();
|
|
76
|
+
for (const path of paths) {
|
|
77
|
+
store.notifyPathSubscribers([stateKey, ...path].join("."), {
|
|
78
|
+
type: "VALIDATION_UPDATE",
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function clearValidationPaths(params, paths) {
|
|
83
|
+
if (paths.length === 0)
|
|
84
|
+
return;
|
|
85
|
+
if (params.clearZodErrors) {
|
|
86
|
+
params.clearZodErrors(paths);
|
|
87
|
+
notifyValidationPaths(params.stateKey, paths);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const store = getGlobalStore.getState();
|
|
91
|
+
for (const path of paths) {
|
|
92
|
+
const currentMeta = store.getShadowMetadata(params.stateKey, path) || {};
|
|
93
|
+
store.setShadowMetadata(params.stateKey, path, {
|
|
94
|
+
...currentMeta,
|
|
95
|
+
validation: {
|
|
96
|
+
status: "NOT_VALIDATED",
|
|
97
|
+
errors: [],
|
|
98
|
+
lastValidated: Date.now(),
|
|
99
|
+
validatedValue: undefined,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
notifyValidationPaths(params.stateKey, paths);
|
|
104
|
+
}
|
|
105
|
+
function addValidationIssues(params, issues) {
|
|
106
|
+
if (issues.length === 0)
|
|
107
|
+
return;
|
|
108
|
+
params.addZodErrors(issues);
|
|
109
|
+
notifyValidationPaths(params.stateKey, issues.map((issue) => issue.path));
|
|
110
|
+
}
|
|
17
111
|
function getRelatedFields(entry, field) {
|
|
18
112
|
const groupIndexes = entry.refineInfo?.fieldToGroup[field];
|
|
19
113
|
if (!groupIndexes?.length)
|
|
@@ -32,11 +126,23 @@ function issueMatchesRelatedFields(issue, relatedFields) {
|
|
|
32
126
|
const leaf = String(issue.path.at(-1) ?? "");
|
|
33
127
|
return relatedFields.has(leaf);
|
|
34
128
|
}
|
|
35
|
-
export function wireShapeValidationOptions(box, params) {
|
|
129
|
+
export function wireShapeValidationOptions(box, params) {
|
|
130
|
+
const entry = box[params.stateKey];
|
|
131
|
+
if (!entry)
|
|
132
|
+
return;
|
|
133
|
+
params.setOptions({
|
|
134
|
+
validation: {
|
|
135
|
+
zodSchemaV4: entry.validators?.client ?? entry.schemas.client,
|
|
136
|
+
onBlur: "error",
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
36
140
|
/** Cross-field refine errors only — field rules are handled by state via setOptions. */
|
|
37
141
|
export function validateShapeRefines(box, params) {
|
|
38
|
-
if (params.event.activityType !== "blur"
|
|
142
|
+
if (params.event.activityType !== "blur" &&
|
|
143
|
+
params.event.activityType !== "input") {
|
|
39
144
|
return;
|
|
145
|
+
}
|
|
40
146
|
const entry = box[params.stateKey];
|
|
41
147
|
const clientSchema = entry?.validators?.client ?? entry?.schemas.client;
|
|
42
148
|
if (!entry || !clientSchema)
|
|
@@ -48,21 +154,17 @@ export function validateShapeRefines(box, params) {
|
|
|
48
154
|
if (!relatedFields)
|
|
49
155
|
return;
|
|
50
156
|
const relatedPaths = resolveRelatedPaths(params.path, relatedFields);
|
|
51
|
-
const result = clientSchema.safeParse(params
|
|
157
|
+
const result = clientSchema.safeParse(getStateForValidation(params));
|
|
52
158
|
if (result.success) {
|
|
53
|
-
params
|
|
159
|
+
clearValidationPaths(params, relatedPaths);
|
|
54
160
|
return;
|
|
55
161
|
}
|
|
56
162
|
const issues = result.error.issues.filter((issue) => issueMatchesRelatedFields(issue, relatedFields));
|
|
57
163
|
const mapped = mapZodIssues(issues);
|
|
58
164
|
const activeKeys = new Set(mapped.map((entry) => pathKey(entry.path)));
|
|
59
165
|
const stalePaths = relatedPaths.filter((targetPath) => !activeKeys.has(pathKey(targetPath)));
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
if (mapped.length > 0) {
|
|
64
|
-
params.addZodErrors(mapped);
|
|
65
|
-
}
|
|
166
|
+
clearValidationPaths(params, stalePaths);
|
|
167
|
+
addValidationIssues(params, mapped);
|
|
66
168
|
}
|
|
67
169
|
function buildInitialState(box) {
|
|
68
170
|
const state = {};
|
|
@@ -84,15 +186,7 @@ export function createShapePlugin(box) {
|
|
|
84
186
|
return createPlugin("shape")
|
|
85
187
|
.initialState(() => buildInitialState(box))
|
|
86
188
|
.transformState((params) => {
|
|
87
|
-
|
|
88
|
-
if (!entry)
|
|
89
|
-
return;
|
|
90
|
-
params.setOptions({
|
|
91
|
-
validation: {
|
|
92
|
-
zodSchemaV4: entry.validators?.client ?? entry.schemas.client,
|
|
93
|
-
onBlur: "error",
|
|
94
|
-
},
|
|
95
|
-
});
|
|
189
|
+
wireShapeValidationOptions(box, params);
|
|
96
190
|
})
|
|
97
191
|
.onFormUpdate((params) => {
|
|
98
192
|
if (params.options?.logs) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cogsbox-shape",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.213",
|
|
4
4
|
"description": "A TypeScript library for creating type-safe database schemas with Zod validation, SQL type definitions, and automatic client/server transformations. Unifies client, server, and database types through a single schema definition, with built-in support for relationships and serialization.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|