@finsys/core 1.1.0 → 1.3.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/form-spec.js DELETED
@@ -1,278 +0,0 @@
1
- import { FormFieldCategory } from "./form-field-category.js";
2
- import FormField from "./form-field.js";
3
- import { validateFormConfig } from "./validator.js";
4
- import semver from "semver";
5
- export class FormSpec {
6
- constructor(displayName, categories, fields, pages = [], templateIcon, schemaVersion = FormSpec.MAX_PARSER_SCHEMA_VERSION) {
7
- this._categories = [];
8
- this._fields = [];
9
- this._pages = [];
10
- this._displayName = displayName;
11
- this._templateIcon = templateIcon;
12
- this._categories = categories;
13
- this._fields = fields;
14
- this._pages = pages;
15
- this._schemaVersion = schemaVersion;
16
- }
17
- get fieldNames() {
18
- let names = [];
19
- this.fields.forEach((field) => {
20
- names = names.concat(field.getFieldNames());
21
- });
22
- return names;
23
- }
24
- get schemaVersion() {
25
- return this._schemaVersion;
26
- }
27
- get requiresUpgrade() {
28
- return semver.lt(this._schemaVersion, FormSpec.MAX_PARSER_SCHEMA_VERSION);
29
- }
30
- upgradeToV2() {
31
- this._schemaVersion = FormSpec.MAX_PARSER_SCHEMA_VERSION;
32
- }
33
- get displayName() {
34
- return this._displayName;
35
- }
36
- set displayName(newDisplayName) {
37
- this._displayName = newDisplayName;
38
- }
39
- get templateIcon() {
40
- return this._templateIcon;
41
- }
42
- set templateIcon(value) {
43
- this._templateIcon = value;
44
- }
45
- get categories() {
46
- return this._categories;
47
- }
48
- set categories(categories) {
49
- this._categories = categories;
50
- }
51
- get fields() {
52
- return this._fields;
53
- }
54
- set fields(fields) {
55
- this._fields = fields;
56
- }
57
- get pages() {
58
- return this._pages;
59
- }
60
- set pages(value) {
61
- this._pages = value;
62
- }
63
- addField(field) {
64
- this._fields.push(field);
65
- }
66
- updateField(field) {
67
- const index = this._fields.findIndex((f) => f.name === field.name);
68
- if (index !== -1) {
69
- this._fields[index] = field;
70
- }
71
- else {
72
- throw new Error(`${field.name} not found. Form Spec of ${this._displayName} cannot update ${field.name}`);
73
- }
74
- }
75
- removeField(fieldName) {
76
- const fieldIndex = this._fields.findIndex((f) => f.name === fieldName);
77
- if (fieldIndex !== -1) {
78
- this._fields.splice(fieldIndex, 1);
79
- this._pages.forEach((page) => {
80
- page.fields = page.fields.filter((fieldRef) => {
81
- let refName;
82
- if (typeof fieldRef === 'string') {
83
- refName = fieldRef;
84
- }
85
- else if ('ref' in fieldRef) {
86
- refName = fieldRef.ref;
87
- }
88
- else if ('definition' in fieldRef) {
89
- refName = fieldRef.definition.name;
90
- }
91
- return refName !== fieldName;
92
- });
93
- });
94
- }
95
- }
96
- getFieldsByCategory(categoryName) {
97
- const foundCategory = this.categories.find((category) => category.name === categoryName);
98
- if (!foundCategory) {
99
- return [];
100
- }
101
- return this._fields.filter((field) => field.categoryId === foundCategory.id);
102
- }
103
- validate() {
104
- const config = this.toJSON();
105
- const result = validateFormConfig(config);
106
- const errors = [];
107
- if (result.errors) {
108
- result.errors.forEach((err) => {
109
- let path = err.instancePath || err.dataPath || '';
110
- path = path.replace(/^\//, '').replace(/\//g, '.');
111
- const prefix = path ? `${path}: ` : '';
112
- errors.push({
113
- message: `${prefix}${err.message}`,
114
- path: path,
115
- });
116
- });
117
- }
118
- if (!this._displayName || this._displayName.trim() === '') {
119
- errors.push({
120
- message: 'displayName: Form display name is required',
121
- path: 'displayName',
122
- });
123
- }
124
- const categoryIds = new Set(this._categories.map((c) => String(c.id)));
125
- this._fields.forEach((field) => {
126
- if (field.categoryId && !categoryIds.has(String(field.categoryId))) {
127
- errors.push({
128
- message: `fields.${field.name}.category: references non-existent category '${field.categoryId}'`,
129
- path: `fields.${field.name}.category`,
130
- });
131
- }
132
- });
133
- const fieldNames = new Set(this._fields.map((f) => f.name));
134
- this._pages.forEach((page, pageIndex) => {
135
- page.fields.forEach((fieldRef, fieldIndex) => {
136
- let refName;
137
- if (typeof fieldRef === 'string') {
138
- refName = fieldRef;
139
- }
140
- else if (fieldRef && fieldRef.ref) {
141
- refName = fieldRef.ref;
142
- }
143
- else if (fieldRef && fieldRef.definition) {
144
- refName = fieldRef.definition.name;
145
- }
146
- if (refName && !fieldNames.has(refName)) {
147
- errors.push({
148
- message: `pages.${pageIndex}.fields.${fieldIndex}: references non-existent field '${refName}'`,
149
- path: `pages.${pageIndex}.fields.${fieldIndex}`,
150
- });
151
- }
152
- });
153
- });
154
- return {
155
- valid: result.valid && errors.length === (result.errors?.length || 0),
156
- errors: errors.length > 0 ? errors : undefined,
157
- };
158
- }
159
- cleanObject(obj) {
160
- if (obj === null || obj === undefined)
161
- return obj;
162
- let target = obj;
163
- if (typeof obj.toJSON === 'function' && obj !== this) {
164
- target = obj.toJSON();
165
- }
166
- if (Array.isArray(target)) {
167
- return target.map((v) => (typeof v === 'object' ? this.cleanObject(v) : v));
168
- }
169
- if (typeof target !== 'object')
170
- return target;
171
- const cleaned = {};
172
- Object.keys(target).forEach((key) => {
173
- const value = target[key];
174
- if (value !== null && value !== undefined && value !== '') {
175
- if (typeof value === 'object') {
176
- cleaned[key] = this.cleanObject(value);
177
- }
178
- else {
179
- cleaned[key] = value;
180
- }
181
- }
182
- });
183
- return cleaned;
184
- }
185
- toJSON() {
186
- const fieldsMap = {};
187
- this._fields.forEach((field) => {
188
- fieldsMap[field.name] = field.toJSON();
189
- delete fieldsMap[field.name].name;
190
- });
191
- return this.cleanObject({
192
- $schema: '../../../node_modules/@finsys/core/dist/schema/unified-form.schema.json',
193
- schemaVersion: this._schemaVersion,
194
- displayName: this._displayName,
195
- templateIcon: this._templateIcon,
196
- categories: this._categories,
197
- fields: fieldsMap,
198
- pages: this._pages,
199
- });
200
- }
201
- static fromJSON(jsonString) {
202
- let jsonData;
203
- try {
204
- jsonData = JSON.parse(jsonString);
205
- }
206
- catch (error) {
207
- console.error(`Error parsing JSON for Loantype with string: ${jsonString}`);
208
- throw error;
209
- }
210
- if (!jsonData.schemaVersion) {
211
- throw new Error('Invalid JSON: schemaVersion is missing or invalid');
212
- }
213
- if (semver.lt(jsonData.schemaVersion, FormSpec.MIN_PARSER_SCHEMA_VERSION)) {
214
- throw new Error(`This form spec file is using an outdated schema version ${jsonData.schemaVersion}. Minimum supported version is ${FormSpec.MIN_PARSER_SCHEMA_VERSION}`);
215
- }
216
- if (!jsonData.displayName) {
217
- throw new Error('Invalid JSON: displayName is missing or invalid');
218
- }
219
- if (!jsonData.categories) {
220
- throw new Error('Invalid JSON: categories is missing or invalid');
221
- }
222
- if (!jsonData.fields) {
223
- throw new Error('Invalid JSON: fields is missing or invalid');
224
- }
225
- if (!jsonData.pages || jsonData.pages.length === 0) {
226
- if (semver.satisfies(jsonData.schemaVersion, '>=2.0.0')) {
227
- console.warn(`v2.0.0 template ${jsonData.displayName} is missing pages. Generating default pages.`);
228
- }
229
- }
230
- let fieldObjects = [];
231
- if (Array.isArray(jsonData.fields)) {
232
- fieldObjects = jsonData.fields;
233
- }
234
- else if (typeof jsonData.fields === 'object' && jsonData.fields !== null) {
235
- fieldObjects = Object.entries(jsonData.fields).map(([name, data]) => {
236
- return {
237
- name,
238
- ...data,
239
- };
240
- });
241
- }
242
- fieldObjects.forEach((f) => {
243
- if (f.categoryId && !f.category) {
244
- f.category = String(f.categoryId);
245
- }
246
- else if (f.category) {
247
- f.category = String(f.category);
248
- }
249
- });
250
- const categories = (jsonData.categories || []).map((cat) => {
251
- return new FormFieldCategory(String(cat.id), cat.name);
252
- });
253
- const fields = fieldObjects.map((fieldObject) => {
254
- return FormField.fromObject(fieldObject);
255
- });
256
- let pages = jsonData.pages || [];
257
- if (pages.length === 0) {
258
- const categoriesMap = {};
259
- fields.forEach((f) => {
260
- const catId = f.categoryId;
261
- if (!categoriesMap[catId]) {
262
- categoriesMap[catId] = [];
263
- }
264
- categoriesMap[catId].push(f.name);
265
- });
266
- pages = categories
267
- .map((cat) => ({
268
- id: `page-${cat.id}`,
269
- title: cat.name,
270
- fields: categoriesMap[cat.id] || [],
271
- }))
272
- .filter((p) => p.fields.length > 0);
273
- }
274
- return new FormSpec(jsonData.displayName, categories, fields, pages, jsonData.templateIcon, jsonData.schemaVersion);
275
- }
276
- }
277
- FormSpec.MIN_PARSER_SCHEMA_VERSION = 'v1.0.0';
278
- FormSpec.MAX_PARSER_SCHEMA_VERSION = 'v2.0.0';
@@ -1 +0,0 @@
1
- export {};
@@ -1,322 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { FormSpec } from "./form-spec.js";
3
- import { FormFieldCategory } from "./form-field-category.js";
4
- import FormField from "./form-field.js";
5
- describe("FormSpec", () => {
6
- it("manages display name", () => {
7
- const spec = new FormSpec("Spec", [], [], []);
8
- expect(spec.displayName).toBe("Spec");
9
- spec.displayName = "New Spec";
10
- expect(spec.displayName).toBe("New Spec");
11
- });
12
- it("manages template icon", () => {
13
- const spec = new FormSpec("Spec", [], [], []);
14
- expect(spec.templateIcon).toBeUndefined();
15
- spec.templateIcon = "icon";
16
- expect(spec.templateIcon).toBe("icon");
17
- });
18
- it("manages categories", () => {
19
- const spec = new FormSpec("Spec", [], [], []);
20
- spec.categories = [new FormFieldCategory("c1", "C1")];
21
- expect(spec.categories.length).toBe(1);
22
- });
23
- it("manages fields", () => {
24
- const spec = new FormSpec("Spec", [], [], []);
25
- spec.fields = [
26
- FormField.fromObject({ name: "f1", displayName: "F1", type: "text", category: "c1" }),
27
- ];
28
- expect(spec.fields.length).toBe(1);
29
- });
30
- it("manages pages", () => {
31
- const spec = new FormSpec("Spec", [], [], []);
32
- spec.pages = [{ id: "p1", title: "P1", fields: ["f1"] }];
33
- expect(spec.pages.length).toBe(1);
34
- });
35
- it("adds field", () => {
36
- const cat1 = new FormFieldCategory("cat1", "Category 1");
37
- const field1 = FormField.fromObject({ name: "f1", displayName: "F1", type: "text", category: "cat1" });
38
- const spec = new FormSpec("Spec", [cat1], [field1], []);
39
- const field2 = FormField.fromObject({ name: "f2", displayName: "F2", type: "text", category: "cat1" });
40
- spec.addField(field2);
41
- expect(spec.fields.length).toBe(2);
42
- });
43
- it("updates existing field", () => {
44
- const field1 = FormField.fromObject({ name: "f1", displayName: "F1", type: "text", category: "cat1" });
45
- const spec = new FormSpec("Spec", [], [field1], []);
46
- spec.updateField(FormField.fromObject({ name: "f1", displayName: "F1 Updated", type: "text", category: "cat1" }));
47
- expect(spec.fields[0].displayName).toBe("F1 Updated");
48
- });
49
- it("throws when updating non-existent field", () => {
50
- const spec = new FormSpec("Spec", [], [], []);
51
- expect(() => spec.updateField(FormField.fromObject({ name: "missing", displayName: "Err", type: "text", category: "cat1" }))).toThrow(/not found/);
52
- });
53
- it("removes field", () => {
54
- const field1 = FormField.fromObject({ name: "f1", displayName: "F1", type: "text", category: "cat1" });
55
- const field2 = FormField.fromObject({ name: "f2", displayName: "F2", type: "text", category: "cat1" });
56
- const spec = new FormSpec("Spec", [], [field1, field2], []);
57
- spec.removeField("f1");
58
- expect(spec.fields.length).toBe(1);
59
- spec.removeField("f2");
60
- expect(spec.fields.length).toBe(0);
61
- });
62
- it("removes field from pages", () => {
63
- const field1 = FormField.fromObject({ name: "f1", displayName: "F1", type: "text", category: "cat1" });
64
- const pages = [
65
- {
66
- id: "p1",
67
- title: "P1",
68
- fields: ["f1", { ref: "f1" }, { definition: { name: "f1" } }, "f2"],
69
- },
70
- ];
71
- const spec = new FormSpec("Spec", [], [field1], pages);
72
- spec.removeField("f1");
73
- expect(spec.pages[0].fields).toEqual(["f2"]);
74
- });
75
- it("gets fields by category", () => {
76
- const cat1 = new FormFieldCategory("cat1", "Category 1");
77
- const field1 = FormField.fromObject({ name: "f1", displayName: "F1", type: "text", category: "cat1" });
78
- const field2 = FormField.fromObject({ name: "f2", displayName: "F2", type: "text", category: "cat1" });
79
- const spec = new FormSpec("Spec", [cat1], [field1, field2], []);
80
- expect(spec.getFieldsByCategory("Category 1").length).toBe(2);
81
- expect(spec.getFieldsByCategory("Missing").length).toBe(0);
82
- });
83
- it("gets fieldNames", () => {
84
- const field1 = FormField.fromObject({ name: "f1", displayName: "F1", type: "text", category: "cat1" });
85
- const field2 = FormField.fromObject({ name: "f2", displayName: "F2", type: "text", category: "cat1" });
86
- const spec = new FormSpec("Spec", [], [field1, field2], []);
87
- expect(spec.fieldNames).toEqual(["f1", "f2"]);
88
- });
89
- });
90
- describe("FormSpec schema version", () => {
91
- it("detects requiresUpgrade", () => {
92
- const spec = new FormSpec("Spec", [], [], [], undefined, "v1.0.0");
93
- expect(spec.requiresUpgrade).toBe(true);
94
- });
95
- it("upgrades to v2", () => {
96
- const spec = new FormSpec("Spec", [], [], [], undefined, "v1.0.0");
97
- spec.upgradeToV2();
98
- expect(spec.schemaVersion).toBe("v2.0.0");
99
- expect(spec.requiresUpgrade).toBe(false);
100
- });
101
- });
102
- describe("FormSpec toJSON", () => {
103
- it("serializes correctly", () => {
104
- const field = FormField.fromObject({ name: "f1", displayName: "F1", type: "text", category: "c1" });
105
- const spec = new FormSpec("Valid", [], [field], []);
106
- const json = spec.toJSON();
107
- expect(json.displayName).toBe("Valid");
108
- expect(json.$schema).toBeDefined();
109
- expect(json.fields.f1).toBeDefined();
110
- expect(json.fields.f1.name).toBeUndefined();
111
- });
112
- it("cleans null and empty optional fields", () => {
113
- const categories = [new FormFieldCategory("personal", "Personal Information")];
114
- const fieldObj = {
115
- name: "age",
116
- displayName: "Age",
117
- type: "number",
118
- category: "personal",
119
- visibleIf: null,
120
- min: "",
121
- max: undefined,
122
- };
123
- const fields = [FormField.fromObject(fieldObj)];
124
- const pages = [{ id: "p1", title: "P1", fields: ["age"] }];
125
- const spec = new FormSpec("Form", categories, fields, pages);
126
- const json = spec.toJSON();
127
- const ageField = json.fields.age;
128
- expect(ageField.visibleIf).toBeUndefined();
129
- expect(ageField.min).toBeUndefined();
130
- expect(ageField.max).toBeUndefined();
131
- });
132
- it("persists defaultValue", () => {
133
- const categories = [new FormFieldCategory("personal", "Personal Information")];
134
- const fields = [
135
- FormField.fromObject({
136
- name: "amount",
137
- displayName: "Loan Amount",
138
- type: "number",
139
- category: "personal",
140
- defaultValue: "5000",
141
- }),
142
- ];
143
- const pages = [{ id: "p1", title: "P1", fields: ["amount"] }];
144
- const spec = new FormSpec("Form", categories, fields, pages);
145
- const json = spec.toJSON();
146
- expect(json.fields.amount.defaultValue).toBe("5000");
147
- });
148
- });
149
- describe("FormSpec validate", () => {
150
- it("valid form spec passes", () => {
151
- const categories = [new FormFieldCategory("personal", "Personal Information")];
152
- const fields = [
153
- FormField.fromObject({ name: "full_name", displayName: "Full Name", type: "text", category: "personal" }),
154
- ];
155
- const pages = [{ id: "page1", title: "Step 1", fields: ["full_name"] }];
156
- const spec = new FormSpec("Valid Form", categories, fields, pages);
157
- const result = spec.validate();
158
- expect(result.valid).toBe(true);
159
- });
160
- it("missing display name fails", () => {
161
- const categories = [new FormFieldCategory("personal", "Personal Information")];
162
- const fields = [
163
- FormField.fromObject({ name: "full_name", displayName: "Full Name", type: "text", category: "personal" }),
164
- ];
165
- const pages = [{ id: "p1", title: "P1", fields: ["full_name"] }];
166
- const spec = new FormSpec("", categories, fields, pages);
167
- const result = spec.validate();
168
- expect(result.valid).toBe(false);
169
- expect(result.errors[0].message).toMatch(/displayName: Form display name is required/);
170
- });
171
- it("invalid schema version fails", () => {
172
- const categories = [new FormFieldCategory("personal", "Personal Information")];
173
- const fields = [
174
- FormField.fromObject({ name: "full_name", displayName: "Full Name", type: "text", category: "personal" }),
175
- ];
176
- const pages = [{ id: "p1", title: "P1", fields: ["full_name"] }];
177
- const spec = new FormSpec("Form", categories, fields, pages, "icon", "invalid-version");
178
- const result = spec.validate();
179
- expect(result.valid).toBe(false);
180
- expect(result.errors[0].message).toMatch(/schemaVersion: must match pattern/);
181
- });
182
- it("orphaned category fails", () => {
183
- const categories = [new FormFieldCategory("personal", "Personal Information")];
184
- const fields = [
185
- FormField.fromObject({
186
- name: "full_name",
187
- displayName: "Full Name",
188
- type: "text",
189
- category: "non-existent-category",
190
- }),
191
- ];
192
- const pages = [{ id: "p1", title: "P1", fields: ["full_name"] }];
193
- const spec = new FormSpec("Form", categories, fields, pages);
194
- const result = spec.validate();
195
- expect(result.valid).toBe(false);
196
- expect(result.errors[0].message).toMatch(/references non-existent category/);
197
- });
198
- it("page referencing non-existent field fails", () => {
199
- const categories = [new FormFieldCategory("personal", "Personal Information")];
200
- const fields = [
201
- FormField.fromObject({ name: "full_name", displayName: "Full Name", type: "text", category: "personal" }),
202
- ];
203
- const pages = [{ id: "page1", title: "Step 1", fields: ["missing_field"] }];
204
- const spec = new FormSpec("Form", categories, fields, pages);
205
- const result = spec.validate();
206
- expect(result.valid).toBe(false);
207
- expect(result.errors[0].message).toMatch(/references non-existent field/);
208
- });
209
- });
210
- describe("FormSpec fromJSON", () => {
211
- it("throws for missing schemaVersion", () => {
212
- expect(() => FormSpec.fromJSON(JSON.stringify({ displayName: "Err" }))).toThrow(/schemaVersion is missing/);
213
- });
214
- it("throws for outdated version", () => {
215
- expect(() => FormSpec.fromJSON(JSON.stringify({ schemaVersion: "v0.9.0", displayName: "Err" }))).toThrow(/outdated schema version/);
216
- });
217
- it("throws for missing displayName", () => {
218
- expect(() => FormSpec.fromJSON(JSON.stringify({ schemaVersion: "v1.0.0" }))).toThrow(/displayName is missing/);
219
- });
220
- it("throws for missing categories", () => {
221
- expect(() => FormSpec.fromJSON(JSON.stringify({ schemaVersion: "v1.0.0", displayName: "D" }))).toThrow(/categories is missing/);
222
- });
223
- it("throws for missing fields", () => {
224
- expect(() => FormSpec.fromJSON(JSON.stringify({ schemaVersion: "v1.0.0", displayName: "D", categories: [] }))).toThrow(/fields is missing/);
225
- });
226
- it("throws for invalid JSON", () => {
227
- expect(() => FormSpec.fromJSON("invalid")).toThrow();
228
- });
229
- it("parses legacy fields array with categoryId", () => {
230
- const legacyJson = {
231
- schemaVersion: "v1.0.0",
232
- displayName: "Legacy",
233
- categories: [{ id: 1, name: "C1" }],
234
- fields: [{ name: "f1", displayName: "F1", type: "text", categoryId: 1 }],
235
- };
236
- const spec = FormSpec.fromJSON(JSON.stringify(legacyJson));
237
- expect(spec.fields.length).toBe(1);
238
- expect(spec.pages.length).toBe(1);
239
- });
240
- it("parses v2 object fields format", () => {
241
- const v2Json = {
242
- schemaVersion: "v2.0.0",
243
- displayName: "v2",
244
- categories: [{ id: "c1", name: "C1" }],
245
- fields: { f1: { displayName: "F1", type: "text", category: "c1" } },
246
- pages: [{ id: "p1", fields: ["f1"] }],
247
- };
248
- const spec = FormSpec.fromJSON(JSON.stringify(v2Json));
249
- expect(spec.fields.length).toBe(1);
250
- expect(spec.fields[0].name).toBe("f1");
251
- });
252
- it("generates default pages when missing", () => {
253
- const v2NoPages = {
254
- schemaVersion: "v2.0.0",
255
- displayName: "v2",
256
- categories: [{ id: "c1", name: "C1" }],
257
- fields: { f1: { displayName: "F1", type: "text", category: "c1" } },
258
- };
259
- const spec = FormSpec.fromJSON(JSON.stringify(v2NoPages));
260
- expect(spec.pages.length).toBe(1);
261
- });
262
- it("throws error when displayName is missing from JSON", () => {
263
- const formSpecFile = {
264
- schemaVersion: "v2.0.0",
265
- categories: [{ id: "1", name: "Basic Information" }],
266
- fields: {
267
- dateOfBirth: {
268
- displayName: "Date of Birth",
269
- type: "text",
270
- inputType: "date",
271
- category: "2",
272
- visible: false,
273
- },
274
- },
275
- pages: [{ id: "page-1", fields: ["dateOfBirth"] }],
276
- };
277
- expect(() => FormSpec.fromJSON(JSON.stringify(formSpecFile))).toThrow("Invalid JSON: displayName is missing or invalid");
278
- });
279
- it("throws error when categories are missing from JSON", () => {
280
- const formSpecFile = {
281
- schemaVersion: "v2.0.0",
282
- displayName: "test",
283
- fields: {
284
- dateOfBirth: {
285
- displayName: "Date of Birth",
286
- type: "text",
287
- inputType: "date",
288
- category: "2",
289
- visible: false,
290
- },
291
- },
292
- pages: [{ id: "page-1", fields: ["dateOfBirth"] }],
293
- };
294
- expect(() => FormSpec.fromJSON(JSON.stringify(formSpecFile))).toThrow("Invalid JSON: categories is missing or invalid");
295
- });
296
- it("throws error when fields are missing from JSON", () => {
297
- const formSpecFile = {
298
- schemaVersion: "v2.0.0",
299
- displayName: "test",
300
- categories: [{ id: "1", name: "Basic Information" }],
301
- pages: [{ id: "page-1", fields: ["dateOfBirth"] }],
302
- };
303
- expect(() => FormSpec.fromJSON(JSON.stringify(formSpecFile))).toThrow("Invalid JSON: fields is missing or invalid");
304
- });
305
- });
306
- describe("FormFieldCategory", () => {
307
- it("manages id, name, and toJSON", () => {
308
- const category = new FormFieldCategory("cat1", "Category 1");
309
- expect(category.id).toBe("cat1");
310
- expect(category.name).toBe("Category 1");
311
- category.name = "Updated Category";
312
- expect(category.name).toBe("Updated Category");
313
- expect(category.toJSON()).toEqual({
314
- id: "cat1",
315
- name: "Updated Category",
316
- });
317
- });
318
- it("converts numeric id to string", () => {
319
- const category = new FormFieldCategory(42, "Test");
320
- expect(category.id).toBe("42");
321
- });
322
- });
@@ -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>;