@finsys/core 1.0.0 → 1.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/README.md CHANGED
@@ -215,6 +215,16 @@ npm run lint # Type-check without emitting
215
215
 
216
216
  See [CONTRIBUTING.md](./CONTRIBUTING.md).
217
217
 
218
+ ## Security
219
+
220
+ ### Expression Evaluation
221
+
222
+ The `evaluateExpression()` function uses `new Function()` internally to evaluate SurveyJS-style visibility expressions. Expression strings **must come from trusted, developer-authored sources** (e.g., your own form configuration files). Never pass untrusted or user-supplied strings as expressions, as this could allow arbitrary code execution.
223
+
224
+ ## Disclaimer
225
+
226
+ This library provides form configuration utilities and does not constitute financial, legal, or investment advice. It does not perform financial calculations, risk assessments, or lending decisions. The creators and contributors accept no liability for decisions made using forms generated by this library. See the [LICENSE](./LICENSE) file for warranty and liability terms.
227
+
218
228
  ## License
219
229
 
220
230
  [Apache-2.0](./LICENSE)
package/dist/index.js CHANGED
@@ -1,3 +1,18 @@
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
+ */
1
16
  /**
2
17
  * @finsys/core
3
18
  * Convert unified form configurations into Zod schemas, React Hook Form defaults, and SurveyJS JSON
@@ -1,3 +1,18 @@
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
+ */
1
16
  import { z } from "zod";
2
17
  import { resolvePageFields, groupFieldsByCategory, applyDynamicTitles } from "./survey-generator.js";
3
18
  import { evaluateExpression } from "./utils.js";
@@ -1,3 +1,18 @@
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
+ */
1
16
  import { describe, it, expect } from 'vitest';
2
17
  import { generateRHFSchema, getStepSchema, getStepDefaultValues } from './rhf-generator.js';
3
18
  describe('rhf-generator', () => {
@@ -1,8 +1,17 @@
1
- /**
2
- * Survey Generator - Converts unified form configurations into SurveyJS-compatible JSON
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
3
9
  *
4
- * This module converts a unified form-config.json into SurveyJS-compatible JSON,
5
- * resolving field references, applying dynamic titles, and grouping by category.
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.
6
15
  */
7
16
  import { getPastMonthLabel, getPastYearLabel } from "./utils.js";
8
17
  /**
@@ -1,3 +1,18 @@
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
+ */
1
16
  import { describe, it, expect } from 'vitest';
2
17
  import { generateSurveyJson, resolvePageFields, getCategoryName, groupFieldsByCategory, applyDynamicTitles } from './survey-generator.js';
3
18
  // ---- Shared fixtures ----
package/dist/utils.js CHANGED
@@ -1,3 +1,18 @@
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
+ */
1
16
  /**
2
17
  * Utility functions for @finsys/core
3
18
  */
@@ -1,3 +1,18 @@
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
+ */
1
16
  import { describe, it, expect } from 'vitest';
2
17
  import { getPastMonthLabel, getPastYearLabel, evaluateExpression } from './utils.js';
3
18
  describe('getPastMonthLabel', () => {
package/dist/validator.js CHANGED
@@ -1,3 +1,18 @@
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
+ */
1
16
  import AjvModule from "ajv";
2
17
  import addFormats from "ajv-formats";
3
18
  import unifiedFormSchema from "./schema/unified-form.schema.json" with { type: "json" };
@@ -1,3 +1,18 @@
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
+ */
1
16
  import { describe, it, expect } from 'vitest';
2
17
  import { validateFormConfig, validateFormSpec, validatePagesConfig } from './validator.js';
3
18
  describe('validateFormConfig', () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finsys/core",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Convert unified form configurations into Zod schemas, React Hook Form defaults, and SurveyJS JSON",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,266 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "title": "Unified Form Configuration Schema",
4
- "description": "A unified schema combining field definitions and page layout configuration for multi-step forms.",
5
- "type": "object",
6
- "properties": {
7
- "$schema": {
8
- "type": "string",
9
- "description": "Reference to this JSON schema file"
10
- },
11
- "schemaVersion": {
12
- "type": "string",
13
- "pattern": "^v?[0-9]+\\.[0-9]+\\.[0-9]+$",
14
- "description": "Semantic version of the schema format (e.g., 'v2.0.0' or '2.0.0')"
15
- },
16
- "displayName": {
17
- "type": "string",
18
- "description": "The human-readable name of the loan product or form"
19
- },
20
- "templateIcon": {
21
- "type": "string",
22
- "description": "Icon identifier or path for the form template (used in FinSys editor)"
23
- },
24
- "categories": {
25
- "type": "array",
26
- "description": "Category definitions for field organization and grouping",
27
- "items": {
28
- "$ref": "#/definitions/category"
29
- }
30
- },
31
- "fields": {
32
- "type": "object",
33
- "description": "Master field definitions keyed by field name",
34
- "additionalProperties": {
35
- "$ref": "#/definitions/fieldData"
36
- }
37
- },
38
- "pages": {
39
- "type": "array",
40
- "description": "Ordered list of pages in the form wizard. Optional for FinSys editor mode.",
41
- "items": {
42
- "$ref": "#/definitions/pageConfig"
43
- }
44
- }
45
- },
46
- "required": ["categories", "fields", "pages"],
47
- "definitions": {
48
- "category": {
49
- "type": "object",
50
- "description": "A category for grouping related form fields",
51
- "properties": {
52
- "id": {
53
- "type": "string",
54
- "description": "Unique identifier for the category (string)"
55
- },
56
- "name": { "type": "string", "description": "Display name for the category heading" }
57
- },
58
- "required": ["id", "name"]
59
- },
60
- "choice": {
61
- "type": "object",
62
- "description": "A selectable option for dropdown or radiogroup fields",
63
- "properties": {
64
- "value": { "type": "string", "description": "Value submitted when this choice is selected" },
65
- "text": { "type": "string", "description": "Display text for this choice" }
66
- },
67
- "required": ["value", "text"]
68
- },
69
- "validator": {
70
- "type": "object",
71
- "description": "Validation rule for a form field",
72
- "properties": {
73
- "type": {
74
- "type": "string",
75
- "enum": ["regex", "email", "numeric", "text", "expression", "answercount", "custom"],
76
- "description": "Type of validation to perform"
77
- },
78
- "text": { "type": "string", "description": "Error message to display on validation failure" },
79
- "regex": { "type": "string", "description": "Regular expression pattern (for type=regex)" },
80
- "minValue": { "type": "number", "description": "Minimum numeric value (for type=numeric)" },
81
- "maxValue": { "type": "number", "description": "Maximum numeric value (for type=numeric)" },
82
- "minLength": { "type": "integer", "description": "Minimum text length (for type=text)" },
83
- "maxLength": { "type": "integer", "description": "Maximum text length (for type=text)" },
84
- "minCount": { "type": "integer", "description": "Minimum selection count (for type=answercount)" },
85
- "maxCount": { "type": "integer", "description": "Maximum selection count (for type=answercount)" },
86
- "expression": { "type": "string", "description": "SurveyJS expression for custom validation" },
87
- "validator": { "type": "string", "description": "Name of the custom validator function (for type=custom)" }
88
- },
89
- "required": ["type"]
90
- },
91
- "fieldData": {
92
- "type": "object",
93
- "description": "Definition of a form field",
94
- "properties": {
95
- "name": {
96
- "type": "string",
97
- "description": "Field name (optional in fields{} since it's the key, required in arrays)"
98
- },
99
- "displayName": {
100
- "type": "string",
101
- "description": "Human-readable label for the field"
102
- },
103
- "type": {
104
- "type": "string",
105
- "enum": ["text", "number", "email", "file", "dropdown", "checkbox", "boolean", "comment", "radiogroup", "range", "html", "slider"],
106
- "description": "Field type determining rendering and behavior"
107
- },
108
- "inputType": {
109
- "type": "string",
110
- "enum": ["text", "number", "tel", "date", "email", "password", "url"],
111
- "description": "HTML input type override for text fields"
112
- },
113
- "category": {
114
- "type": "string",
115
- "description": "Category ID this field belongs to (string to match category.id)"
116
- },
117
- "categoryId": {
118
- "type": "integer",
119
- "description": "Legacy integer category ID (deprecated, prefer 'category')"
120
- },
121
- "maxLength": { "type": ["integer", "string"], "description": "Maximum character length" },
122
- "min": { "type": ["integer", "string"], "description": "Minimum value for numeric/slider fields" },
123
- "max": { "type": ["integer", "string"], "description": "Maximum value for numeric/slider fields" },
124
- "step": { "type": "number", "description": "Step increment for slider/range fields" },
125
- "html": { "type": "string", "description": "HTML content for type=html fields" },
126
- "choices": {
127
- "type": "array",
128
- "description": "Options for dropdown or radiogroup fields",
129
- "items": { "$ref": "#/definitions/choice" }
130
- },
131
- "validators": {
132
- "type": "array",
133
- "description": "Validation rules to apply to this field",
134
- "items": { "$ref": "#/definitions/validator" }
135
- },
136
- "visible": {
137
- "type": "boolean",
138
- "default": true,
139
- "description": "Whether the field is visible"
140
- },
141
- "visibleIf": {
142
- "type": "string",
143
- "description": "SurveyJS expression for conditional visibility"
144
- },
145
- "required": {
146
- "type": "boolean",
147
- "description": "Whether the field is required for form submission"
148
- },
149
- "isRequired": {
150
- "type": "boolean",
151
- "description": "Alias for 'required' (SurveyJS compatibility)"
152
- },
153
- "placeholder": {
154
- "type": "string",
155
- "description": "Placeholder text shown in empty field"
156
- },
157
- "defaultValue": {
158
- "type": ["string", "number", "boolean", "array"],
159
- "description": "Default value for the field"
160
- },
161
- "readOnly": {
162
- "type": "boolean",
163
- "description": "Whether the field is read-only"
164
- },
165
- "startWithNewLine": {
166
- "type": "boolean",
167
- "default": true,
168
- "description": "If false, field appears on same line as previous field"
169
- },
170
- "enableIf": {
171
- "type": "string",
172
- "description": "SurveyJS expression for conditional enable/disable"
173
- },
174
- "titleLocation": {
175
- "type": "string",
176
- "enum": ["default", "top", "bottom", "left", "hidden"],
177
- "description": "Position of the field label"
178
- },
179
- "ihs_column_names": {
180
- "type": "array",
181
- "description": "FinSys IHS column mappings for file fields (used for data extraction)",
182
- "items": { "type": "string" }
183
- },
184
- "requiredForEvaluation": {
185
- "type": "boolean",
186
- "default": true,
187
- "description": "Whether this field is required for loan evaluation (FinSys specific)"
188
- }
189
- },
190
- "required": ["type"]
191
- },
192
- "fieldReference": {
193
- "description": "Reference to a field in a page, supporting simple refs, refs with overrides, or inline definitions",
194
- "oneOf": [
195
- {
196
- "type": "string",
197
- "description": "Simple field name reference to a field defined in 'fields'"
198
- },
199
- {
200
- "type": "object",
201
- "description": "Field reference with optional property overrides",
202
- "properties": {
203
- "ref": { "type": "string", "description": "Reference to field name in 'fields' object" },
204
- "displayName": { "type": "string", "description": "Override display name for this page" },
205
- "type": { "type": "string", "description": "Override field type for this usage" },
206
- "defaultValue": { "type": ["string", "number", "boolean", "array"] },
207
- "readOnly": { "type": "boolean" },
208
- "visible": { "type": "boolean" },
209
- "visibleIf": { "type": "string" },
210
- "required": { "type": "boolean" },
211
- "min": { "type": ["integer", "string"] },
212
- "max": { "type": ["integer", "string"] },
213
- "choices": { "type": "array", "items": { "$ref": "#/definitions/choice" } }
214
- },
215
- "required": ["ref"]
216
- },
217
- {
218
- "type": "object",
219
- "description": "Inline field definition (page-specific field not in master 'fields')",
220
- "properties": {
221
- "definition": {
222
- "allOf": [
223
- { "$ref": "#/definitions/fieldData" },
224
- {
225
- "type": "object",
226
- "properties": {
227
- "name": { "type": "string" }
228
- },
229
- "required": ["name"]
230
- }
231
- ]
232
- }
233
- },
234
- "required": ["definition"]
235
- }
236
- ]
237
- },
238
- "pageConfig": {
239
- "type": "object",
240
- "description": "Configuration for a single page/step in the form wizard",
241
- "properties": {
242
- "id": { "type": "string", "description": "Unique page identifier" },
243
- "title": { "type": "string", "description": "Page title displayed to user" },
244
- "description": { "type": "string", "description": "Optional page description or instructions" },
245
- "showTOC": { "type": "boolean", "default": false, "description": "Show table of contents" },
246
- "showProgressBar": { "type": "boolean", "default": false, "description": "Show progress indicator" },
247
- "showCategoryHeadings": {
248
- "type": "boolean",
249
- "default": false,
250
- "description": "Render category names as section headings when category changes between fields"
251
- },
252
- "layout": {
253
- "type": "string",
254
- "enum": ["default", "grid", "vertical"],
255
- "description": "Layout mode for the page"
256
- },
257
- "fields": {
258
- "type": "array",
259
- "description": "Ordered list of field references to display on this page",
260
- "items": { "$ref": "#/definitions/fieldReference" }
261
- }
262
- },
263
- "required": ["id", "fields"]
264
- }
265
- }
266
- }