@finsys/core 1.0.1 → 1.2.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/dist/data/form-field-base-specs.json +7353 -0
- package/dist/data/form-field-types.json +83 -0
- package/dist/data/form-field-validators.json +341 -0
- package/dist/index.cjs +9101 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +375 -0
- package/dist/index.d.ts +374 -11
- package/dist/index.js +9038 -24
- package/dist/index.js.map +1 -0
- package/package.json +14 -10
- package/dist/rhf-generator.d.ts +0 -30
- package/dist/rhf-generator.js +0 -267
- package/dist/rhf-generator.test.d.ts +0 -1
- package/dist/rhf-generator.test.js +0 -583
- package/dist/survey-generator.d.ts +0 -153
- package/dist/survey-generator.js +0 -194
- package/dist/survey-generator.test.d.ts +0 -1
- package/dist/survey-generator.test.js +0 -332
- package/dist/utils.d.ts +0 -13
- package/dist/utils.js +0 -56
- package/dist/utils.test.d.ts +0 -1
- package/dist/utils.test.js +0 -131
- package/dist/validator.d.ts +0 -14
- package/dist/validator.js +0 -49
- package/dist/validator.test.d.ts +0 -1
- package/dist/validator.test.js +0 -142
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finsys/core",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Convert unified form configurations into Zod schemas, React Hook Form defaults, and SurveyJS JSON",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -10,18 +10,19 @@
|
|
|
10
10
|
"bugs": {
|
|
11
11
|
"url": "https://github.com/ExtraGalaxies/finsys-core/issues"
|
|
12
12
|
},
|
|
13
|
-
"main": "dist/index.
|
|
14
|
-
"
|
|
13
|
+
"main": "./dist/index.cjs",
|
|
14
|
+
"module": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
15
16
|
"type": "module",
|
|
16
17
|
"exports": {
|
|
17
18
|
".": {
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"require": "./dist/index.cjs"
|
|
22
22
|
},
|
|
23
23
|
"./schema": {
|
|
24
|
-
"import": "./dist/schema/unified-form.schema.json"
|
|
24
|
+
"import": "./dist/schema/unified-form.schema.json",
|
|
25
|
+
"require": "./dist/schema/unified-form.schema.json"
|
|
25
26
|
}
|
|
26
27
|
},
|
|
27
28
|
"files": [
|
|
@@ -30,8 +31,8 @@
|
|
|
30
31
|
"LICENSE"
|
|
31
32
|
],
|
|
32
33
|
"scripts": {
|
|
33
|
-
"build": "
|
|
34
|
-
"dev": "
|
|
34
|
+
"build": "tsup",
|
|
35
|
+
"dev": "tsup --watch",
|
|
35
36
|
"test": "vitest run",
|
|
36
37
|
"lint": "tsc --noEmit",
|
|
37
38
|
"prepublishOnly": "npm run build"
|
|
@@ -47,11 +48,14 @@
|
|
|
47
48
|
"dependencies": {
|
|
48
49
|
"ajv": "^8.17.1",
|
|
49
50
|
"ajv-formats": "^3.0.1",
|
|
51
|
+
"semver": "^7.7.3",
|
|
50
52
|
"zod": "^4.3.5"
|
|
51
53
|
},
|
|
52
54
|
"devDependencies": {
|
|
53
55
|
"@types/node": "^25.0.10",
|
|
56
|
+
"@types/semver": "^7.5.0",
|
|
54
57
|
"survey-core": "^2.5.6",
|
|
58
|
+
"tsup": "^8.5.1",
|
|
55
59
|
"typescript": "^5.4.0",
|
|
56
60
|
"vitest": "^4.0.18"
|
|
57
61
|
},
|
package/dist/rhf-generator.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { type UnifiedFormConfig, type ResolvedField, type Category, type FieldGroup } from "./survey-generator.js";
|
|
3
|
-
export interface RHFStep {
|
|
4
|
-
id: number;
|
|
5
|
-
title: string;
|
|
6
|
-
description?: string;
|
|
7
|
-
fields: ResolvedField[];
|
|
8
|
-
showCategoryHeadings: boolean;
|
|
9
|
-
layout?: "default" | "grid" | "vertical";
|
|
10
|
-
}
|
|
11
|
-
export interface RHFSchemaOutput {
|
|
12
|
-
zodSchema: z.ZodTypeAny;
|
|
13
|
-
baseSchema: z.ZodObject<any>;
|
|
14
|
-
defaultValues: Record<string, any>;
|
|
15
|
-
fields: ResolvedField[];
|
|
16
|
-
groupedFields: FieldGroup[];
|
|
17
|
-
steps: RHFStep[];
|
|
18
|
-
displayName: string;
|
|
19
|
-
categories: Category[];
|
|
20
|
-
templateIcon?: string;
|
|
21
|
-
}
|
|
22
|
-
export declare function generateRHFSchema(config: UnifiedFormConfig): RHFSchemaOutput;
|
|
23
|
-
/**
|
|
24
|
-
* Get Zod schema for a specific step
|
|
25
|
-
*/
|
|
26
|
-
export declare function getStepSchema(step: RHFStep, fullSchema: any): z.ZodTypeAny;
|
|
27
|
-
/**
|
|
28
|
-
* Extract default values for a specific step
|
|
29
|
-
*/
|
|
30
|
-
export declare function getStepDefaultValues(step: RHFStep, allDefaults: Record<string, any>): Record<string, any>;
|
package/dist/rhf-generator.js
DELETED
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2025 Sisters Inspire Sdn Bhd
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
import { z } from "zod";
|
|
17
|
-
import { resolvePageFields, groupFieldsByCategory, applyDynamicTitles } from "./survey-generator.js";
|
|
18
|
-
import { evaluateExpression } from "./utils.js";
|
|
19
|
-
/**
|
|
20
|
-
* Apply visibility-aware validation to a Zod schema
|
|
21
|
-
*/
|
|
22
|
-
function applyVisibilityValidation(baseObject, fields) {
|
|
23
|
-
return baseObject.superRefine((data, ctx) => {
|
|
24
|
-
fields.forEach((field) => {
|
|
25
|
-
const isRequired = field.isRequired !== false && field.required !== false && field.type !== "html";
|
|
26
|
-
if (!isRequired)
|
|
27
|
-
return;
|
|
28
|
-
// Determine Visibility
|
|
29
|
-
let isVisible = field.visible !== false;
|
|
30
|
-
if (isVisible && field.visibleIf) {
|
|
31
|
-
isVisible = evaluateExpression(field.visibleIf, data);
|
|
32
|
-
}
|
|
33
|
-
if (isVisible) {
|
|
34
|
-
const value = data[field.name];
|
|
35
|
-
const isEmpty = value === undefined ||
|
|
36
|
-
value === null ||
|
|
37
|
-
value === "" ||
|
|
38
|
-
(Array.isArray(value) && value.length === 0);
|
|
39
|
-
if (isEmpty) {
|
|
40
|
-
ctx.addIssue({
|
|
41
|
-
code: z.ZodIssueCode.custom,
|
|
42
|
-
message: "This field is required",
|
|
43
|
-
path: [field.name],
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
export function generateRHFSchema(config) {
|
|
51
|
-
// ... (existing logic for collecting fields/building shape)
|
|
52
|
-
const pages = config.pages || [];
|
|
53
|
-
const categories = config.categories || [];
|
|
54
|
-
const fieldsMap = config.fields || {};
|
|
55
|
-
if (pages.length === 0) {
|
|
56
|
-
throw new Error("v2.0.0 templates must include a 'pages' configuration.");
|
|
57
|
-
}
|
|
58
|
-
// 1. Collect all fields from all pages
|
|
59
|
-
const allFields = [];
|
|
60
|
-
for (const page of pages) {
|
|
61
|
-
const pageFields = resolvePageFields(page, fieldsMap);
|
|
62
|
-
allFields.push(...pageFields);
|
|
63
|
-
}
|
|
64
|
-
// Apply dynamic titles
|
|
65
|
-
const mergedFields = allFields.map(applyDynamicTitles);
|
|
66
|
-
// 2. Build Zod Shape & Default Values
|
|
67
|
-
const shape = {};
|
|
68
|
-
const defaultValues = {};
|
|
69
|
-
mergedFields.forEach((field) => {
|
|
70
|
-
let schema = z.string();
|
|
71
|
-
// Track base type before validators/wrapping transform it via .refine()
|
|
72
|
-
// (instanceof checks won't work after .refine() converts ZodString → ZodEffects)
|
|
73
|
-
let baseType = "string";
|
|
74
|
-
// --- Base Type Handling ---
|
|
75
|
-
if (field.inputType === "number" || field.type === "number" || field.type === "slider" || field.type === "range") {
|
|
76
|
-
schema = z.coerce.number();
|
|
77
|
-
baseType = "number";
|
|
78
|
-
defaultValues[field.name] = field.defaultValue !== undefined ? Number(field.defaultValue) : "";
|
|
79
|
-
}
|
|
80
|
-
else if (field.type === "checkbox") {
|
|
81
|
-
schema = z.array(z.string());
|
|
82
|
-
baseType = "array";
|
|
83
|
-
defaultValues[field.name] = [];
|
|
84
|
-
}
|
|
85
|
-
else if (field.type === "file") {
|
|
86
|
-
schema = z.array(z.any());
|
|
87
|
-
baseType = "array";
|
|
88
|
-
defaultValues[field.name] = [];
|
|
89
|
-
}
|
|
90
|
-
else if (field.type === "boolean") {
|
|
91
|
-
schema = z.boolean();
|
|
92
|
-
baseType = "boolean";
|
|
93
|
-
defaultValues[field.name] = field.defaultValue ?? false;
|
|
94
|
-
}
|
|
95
|
-
else if (field.type === "html") {
|
|
96
|
-
schema = z.any().optional();
|
|
97
|
-
baseType = "any";
|
|
98
|
-
defaultValues[field.name] = "";
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
if (Array.isArray(field.defaultValue)) {
|
|
102
|
-
defaultValues[field.name] = field.defaultValue[0] || "";
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
defaultValues[field.name] = field.defaultValue ?? "";
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
// --- Validation Constraints ---
|
|
109
|
-
// Min/Max for Numbers
|
|
110
|
-
if (baseType === "number" && schema instanceof z.ZodNumber) {
|
|
111
|
-
let numSchema = schema;
|
|
112
|
-
if (field.min !== undefined)
|
|
113
|
-
numSchema = numSchema.min(Number(field.min), { message: `Minimum value is ${field.min}` });
|
|
114
|
-
if (field.max !== undefined)
|
|
115
|
-
numSchema = numSchema.max(Number(field.max), { message: `Maximum value is ${field.max}` });
|
|
116
|
-
schema = numSchema;
|
|
117
|
-
}
|
|
118
|
-
const isRequired = field.isRequired !== false && field.required !== false && field.type !== "html";
|
|
119
|
-
const isAlwaysVisible = field.visible !== false && !field.visibleIf;
|
|
120
|
-
const isActuallyInput = field.type !== "html";
|
|
121
|
-
// --- Required .min(1) for always-visible fields ---
|
|
122
|
-
// Must be applied BEFORE validators (.refine) which change the schema type.
|
|
123
|
-
if (isRequired && isAlwaysVisible && isActuallyInput) {
|
|
124
|
-
if (baseType === "string" && schema instanceof z.ZodString) {
|
|
125
|
-
schema = schema.min(1, { message: "This field is required" });
|
|
126
|
-
}
|
|
127
|
-
else if (baseType === "array" && schema instanceof z.ZodArray) {
|
|
128
|
-
schema = schema.min(1, { message: "Please select at least one option" });
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
// --- Enhancements: Validators ---
|
|
132
|
-
// Applied BEFORE optional wrapping so instanceof checks still work on the
|
|
133
|
-
// base type. The .refine() calls here will transform the schema to ZodEffects,
|
|
134
|
-
// which is why we use baseType for subsequent decisions instead of instanceof.
|
|
135
|
-
// Email
|
|
136
|
-
const hasExplicitEmailValidator = field.validators?.some(v => v.type === "email");
|
|
137
|
-
if ((field.inputType === "email" || field.name === "email") && baseType === "string" && schema instanceof z.ZodString && !hasExplicitEmailValidator) {
|
|
138
|
-
schema = schema.refine(val => val === "" || z.string().email().safeParse(val).success, {
|
|
139
|
-
message: "Invalid email address"
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
// Legacy Validators (Regex / Numeric)
|
|
143
|
-
if (field.validators) {
|
|
144
|
-
field.validators.forEach((v) => {
|
|
145
|
-
if (v.type === "regex" && v.regex) {
|
|
146
|
-
try {
|
|
147
|
-
const regex = new RegExp(v.regex);
|
|
148
|
-
if (baseType === "string") {
|
|
149
|
-
schema = schema.refine((val) => val === "" || regex.test(val), {
|
|
150
|
-
message: v.text || "Invalid format"
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
catch (e) {
|
|
155
|
-
console.warn(`Invalid regex pattern for field ${field.name}:`, v.regex);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
if (v.type === "email" && baseType === "string") {
|
|
159
|
-
schema = schema.refine((val) => val === "" || z.string().email().safeParse(val).success, {
|
|
160
|
-
message: v.text || "Invalid email"
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
if (v.type === "numeric" && schema instanceof z.ZodNumber) {
|
|
164
|
-
let numSchema = schema;
|
|
165
|
-
if (v.minValue !== undefined)
|
|
166
|
-
numSchema = numSchema.min(v.minValue, { message: v.text });
|
|
167
|
-
if (v.maxValue !== undefined)
|
|
168
|
-
numSchema = numSchema.max(v.maxValue, { message: v.text });
|
|
169
|
-
schema = numSchema;
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
// --- Final Wrapper: Optional for conditional/hidden fields ---
|
|
174
|
-
// Uses baseType instead of instanceof since validators may have transformed the schema.
|
|
175
|
-
if (!(isRequired && isAlwaysVisible && isActuallyInput)) {
|
|
176
|
-
if (baseType === "number") {
|
|
177
|
-
schema = schema.optional().or(z.literal("")).or(z.null());
|
|
178
|
-
}
|
|
179
|
-
else if (baseType === "array") {
|
|
180
|
-
schema = schema.optional();
|
|
181
|
-
}
|
|
182
|
-
else if (baseType === "boolean") {
|
|
183
|
-
schema = schema.optional();
|
|
184
|
-
}
|
|
185
|
-
else if (baseType === "string") {
|
|
186
|
-
schema = schema.optional().or(z.literal(""));
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
shape[field.name] = schema;
|
|
190
|
-
});
|
|
191
|
-
// 3. Group Fields by Category
|
|
192
|
-
const groupedFields = groupFieldsByCategory(mergedFields, categories);
|
|
193
|
-
// 4. Build Steps (Dynamic Wizard)
|
|
194
|
-
const steps = pages.map((page, idx) => {
|
|
195
|
-
const pageFields = resolvePageFields(page, fieldsMap);
|
|
196
|
-
return {
|
|
197
|
-
id: idx,
|
|
198
|
-
title: page.title || "",
|
|
199
|
-
description: page.description,
|
|
200
|
-
fields: pageFields,
|
|
201
|
-
showCategoryHeadings: page.showCategoryHeadings ?? false,
|
|
202
|
-
layout: page.layout
|
|
203
|
-
};
|
|
204
|
-
});
|
|
205
|
-
// 5. Build Final Schema with Visibility-Aware Validation
|
|
206
|
-
const baseObject = z.object(shape);
|
|
207
|
-
const zodSchema = applyVisibilityValidation(baseObject, mergedFields);
|
|
208
|
-
return {
|
|
209
|
-
zodSchema,
|
|
210
|
-
baseSchema: baseObject,
|
|
211
|
-
defaultValues,
|
|
212
|
-
fields: mergedFields,
|
|
213
|
-
groupedFields,
|
|
214
|
-
steps,
|
|
215
|
-
displayName: config.displayName || "Application Form",
|
|
216
|
-
categories,
|
|
217
|
-
templateIcon: config.templateIcon
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Get Zod schema for a specific step
|
|
222
|
-
*/
|
|
223
|
-
export function getStepSchema(step, fullSchema) {
|
|
224
|
-
const stepFieldNames = step.fields.map(f => f.name);
|
|
225
|
-
const stepShape = {};
|
|
226
|
-
// 1. Determine the base ZodObject
|
|
227
|
-
let baseObj;
|
|
228
|
-
if (fullSchema instanceof z.ZodObject) {
|
|
229
|
-
baseObj = fullSchema;
|
|
230
|
-
}
|
|
231
|
-
else if (fullSchema && typeof fullSchema === "object" && "baseSchema" in fullSchema) {
|
|
232
|
-
baseObj = fullSchema.baseSchema;
|
|
233
|
-
}
|
|
234
|
-
else if (fullSchema && "_def" in fullSchema && fullSchema._def.schema instanceof z.ZodObject) {
|
|
235
|
-
// Basic Unwrap for ZodEffects
|
|
236
|
-
baseObj = fullSchema._def.schema;
|
|
237
|
-
}
|
|
238
|
-
if (!baseObj) {
|
|
239
|
-
console.warn("[RHF Generator] Could not extract ZodObject shape for step validation");
|
|
240
|
-
return z.object({});
|
|
241
|
-
}
|
|
242
|
-
const shape = baseObj.shape;
|
|
243
|
-
const stepFields = [];
|
|
244
|
-
stepFieldNames.forEach(name => {
|
|
245
|
-
if (name in shape) {
|
|
246
|
-
stepShape[name] = shape[name];
|
|
247
|
-
// Keep track of which fields are in this step
|
|
248
|
-
const fieldDef = step.fields.find(f => f.name === name);
|
|
249
|
-
if (fieldDef)
|
|
250
|
-
stepFields.push(fieldDef);
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
const stepBaseObject = z.object(stepShape);
|
|
254
|
-
return applyVisibilityValidation(stepBaseObject, stepFields);
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Extract default values for a specific step
|
|
258
|
-
*/
|
|
259
|
-
export function getStepDefaultValues(step, allDefaults) {
|
|
260
|
-
const stepDefaults = {};
|
|
261
|
-
step.fields.forEach(field => {
|
|
262
|
-
if (field.name in allDefaults) {
|
|
263
|
-
stepDefaults[field.name] = allDefaults[field.name];
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
return stepDefaults;
|
|
267
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|