form0-core 0.1.16 → 0.1.17
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
|
@@ -57,6 +57,9 @@ Record-side utilities follow this contract:
|
|
|
57
57
|
- `normalizeStructuredRecord()` consumes and returns canonical stored records
|
|
58
58
|
- `buildFormRecordSnapshot()` consumes canonical stored records and returns renderer snapshot values
|
|
59
59
|
- `projectDatasetRowValues()` consumes canonical stored rows
|
|
60
|
+
- Choice `FIELD_SPECS` keep separate validators by context:
|
|
61
|
+
- `valueValidator` validates live engine / renderer values
|
|
62
|
+
- `recordValueValidator` validates canonical stored record values
|
|
60
63
|
|
|
61
64
|
Record status remains top-level as `@status`; it is not stored inside `form_values`.
|
|
62
65
|
|
package/package.json
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "form0-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/"
|
|
6
6
|
},
|
|
7
|
-
"description": "Schema-driven engine that powers form0 ecosystem.",
|
|
7
|
+
"description": "Schema-driven engine that powers form0 ecosystem. Looking for the full form0 ecosystem? Install the CLI: `npm install -g form0-cli`",
|
|
8
8
|
"main": "src/index.js",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"scripts": {
|
|
11
11
|
"test": "node tests/form0-core.test.js && node tests/dataset-descriptors.test.js && node tests/structured-record.test.js && node tests/builtin-metadata.test.js && node tests/calculation-editor.test.js && node tests/form-event-editor.test.js && node tests/security-test.js",
|
|
12
|
-
"postinstall": "node scripts/postinstall.cjs",
|
|
13
12
|
"format": "prettier --write \"**/*.{js,jsx,json,ts,tsx,md}\"",
|
|
14
13
|
"format:check": "prettier --check \"**/*.{js,jsx,json,ts,tsx,md}\""
|
|
15
14
|
},
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// Legacy reference only.
|
|
2
|
+
// This script is intentionally not wired into package.json lifecycle hooks.
|
|
3
|
+
// It is retained as a reference for the previous install-time guidance message.
|
|
4
|
+
|
|
1
5
|
const PACKAGE_NAME = 'form0-core';
|
|
2
6
|
|
|
3
7
|
const npmUserAgent = process.env.npm_config_user_agent || '';
|
package/src/index.js
CHANGED
|
@@ -6,6 +6,12 @@ export {
|
|
|
6
6
|
buildFormRecordSnapshot,
|
|
7
7
|
} from './utilities/structured-record.js';
|
|
8
8
|
export { validateSchema } from './schema/schema-validator.js';
|
|
9
|
+
export {
|
|
10
|
+
validateFieldValue,
|
|
11
|
+
validateRecordFieldValue,
|
|
12
|
+
getFieldValueValidator,
|
|
13
|
+
getRecordFieldValueValidator,
|
|
14
|
+
} from './schema/field-value-registry.js';
|
|
9
15
|
//export { validateSchema, resolveSupportingImagePath } from './schema/schema-validator.js';
|
|
10
16
|
export { generateKey } from './utilities/hash.js';
|
|
11
17
|
export {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { validateChoiceFieldChoices } from '../utilities/field-helpers.js';
|
|
2
|
+
import { validateStoredChoiceValue } from '../utilities/choice-value-shapes.js';
|
|
2
3
|
import {
|
|
3
4
|
isNonEmptyString,
|
|
4
5
|
validateFormLinkRecordDefaults,
|
|
@@ -316,6 +317,10 @@ export const FIELD_SPECS = {
|
|
|
316
317
|
}
|
|
317
318
|
return null;
|
|
318
319
|
},
|
|
320
|
+
recordValueValidator: (field, value) =>
|
|
321
|
+
validateStoredChoiceValue(field, value, {
|
|
322
|
+
context: 'FIELD_SPECS.recordValueValidator',
|
|
323
|
+
}),
|
|
319
324
|
defaultProducer: (field) => {
|
|
320
325
|
if (field.default_value) {
|
|
321
326
|
const choice = field.choices.find((c) => c.value === field.default_value);
|
|
@@ -466,6 +471,10 @@ export const FIELD_SPECS = {
|
|
|
466
471
|
}
|
|
467
472
|
return null;
|
|
468
473
|
},
|
|
474
|
+
recordValueValidator: (field, value) =>
|
|
475
|
+
validateStoredChoiceValue(field, value, {
|
|
476
|
+
context: 'FIELD_SPECS.recordValueValidator',
|
|
477
|
+
}),
|
|
469
478
|
defaultProducer: (field) => {
|
|
470
479
|
if (field.default_value) {
|
|
471
480
|
const selectedChoices = field.choices
|
|
@@ -596,6 +605,10 @@ export const FIELD_SPECS = {
|
|
|
596
605
|
}
|
|
597
606
|
return null;
|
|
598
607
|
},
|
|
608
|
+
recordValueValidator: (field, value) =>
|
|
609
|
+
validateStoredChoiceValue(field, value, {
|
|
610
|
+
context: 'FIELD_SPECS.recordValueValidator',
|
|
611
|
+
}),
|
|
599
612
|
defaultProducer: (field) => {
|
|
600
613
|
if (field.default_value) {
|
|
601
614
|
const choice = field.choices.find((c) => c.value === field.default_value);
|
|
@@ -19,6 +19,29 @@ export function validateFieldValue(field, value) {
|
|
|
19
19
|
return null;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Validates a structured-record field value against its specification
|
|
24
|
+
* @param {object} field - The field definition
|
|
25
|
+
* @param {any} value - The stored record value to validate
|
|
26
|
+
* @returns {string|null} - Error message if validation fails, or null if valid
|
|
27
|
+
*/
|
|
28
|
+
export function validateRecordFieldValue(field, value) {
|
|
29
|
+
const spec = FIELD_SPECS[field.type];
|
|
30
|
+
if (!spec) {
|
|
31
|
+
return `Unsupported field type: ${field.type}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (typeof spec.recordValueValidator === 'function') {
|
|
35
|
+
return spec.recordValueValidator(field, value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (typeof spec.valueValidator === 'function') {
|
|
39
|
+
return spec.valueValidator(field, value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
22
45
|
/**
|
|
23
46
|
* Returns the value validator function for a field type
|
|
24
47
|
* @param {string} fieldType - The field type
|
|
@@ -29,6 +52,25 @@ export function getFieldValueValidator(fieldType) {
|
|
|
29
52
|
return spec ? spec.valueValidator : null;
|
|
30
53
|
}
|
|
31
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Returns the structured-record value validator function for a field type
|
|
57
|
+
* Falls back to the live value validator when no record-specific validator exists.
|
|
58
|
+
* @param {string} fieldType - The field type
|
|
59
|
+
* @returns {function|null} - The record value validator function or null if not found
|
|
60
|
+
*/
|
|
61
|
+
export function getRecordFieldValueValidator(fieldType) {
|
|
62
|
+
const spec = FIELD_SPECS[fieldType];
|
|
63
|
+
if (!spec) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (typeof spec.recordValueValidator === 'function') {
|
|
68
|
+
return spec.recordValueValidator;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return typeof spec.valueValidator === 'function' ? spec.valueValidator : null;
|
|
72
|
+
}
|
|
73
|
+
|
|
32
74
|
/**
|
|
33
75
|
* Validates TextField value
|
|
34
76
|
* @param {object} field - The field definition
|
|
@@ -213,6 +213,34 @@ export function normalizeStoredChoiceValue(field, rawValue, options = {}) {
|
|
|
213
213
|
return normalized;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
export function validateStoredChoiceValue(field, rawValue, options = {}) {
|
|
217
|
+
try {
|
|
218
|
+
const normalized = normalizeStoredChoiceValue(field, rawValue, options);
|
|
219
|
+
const kind = getChoiceKind(field);
|
|
220
|
+
const fieldIdentifier = toFieldIdentifier(field);
|
|
221
|
+
|
|
222
|
+
if (normalized && kind === 'single' && toFieldType(field) === 'BooleanField') {
|
|
223
|
+
if (normalized.other_value.length > 0) {
|
|
224
|
+
return `${fieldIdentifier} does not support 'other_value' values`;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (normalized && kind !== null && toFieldType(field) !== 'BooleanField') {
|
|
229
|
+
if (field.allow_other !== true && normalized.other_value.length > 0) {
|
|
230
|
+
return `${fieldIdentifier} does not allow 'other_value' values`;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return null;
|
|
235
|
+
} catch (error) {
|
|
236
|
+
if (error instanceof Error) {
|
|
237
|
+
return error.message.replace(/^\[form0\] [^:]+: /, '');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return 'stored choice value is invalid';
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
216
244
|
export function toRendererChoiceValue(field, rawValue, options = {}) {
|
|
217
245
|
const kind = getChoiceKind(field);
|
|
218
246
|
if (!kind || rawValue === null || typeof rawValue === 'undefined') {
|