@rjsf/utils 5.11.2 → 5.12.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/index.js +2544 -5
- package/dist/index.js.map +7 -0
- package/dist/utils.esm.js +1228 -2113
- package/dist/utils.esm.js.map +7 -1
- package/dist/utils.umd.js +2414 -0
- package/lib/ErrorSchemaBuilder.d.ts +60 -0
- package/lib/ErrorSchemaBuilder.js +103 -0
- package/lib/ErrorSchemaBuilder.js.map +1 -0
- package/lib/allowAdditionalItems.d.ts +8 -0
- package/lib/allowAdditionalItems.js +14 -0
- package/lib/allowAdditionalItems.js.map +1 -0
- package/lib/asNumber.d.ts +10 -0
- package/lib/asNumber.js +36 -0
- package/lib/asNumber.js.map +1 -0
- package/lib/canExpand.d.ts +11 -0
- package/lib/canExpand.js +26 -0
- package/lib/canExpand.js.map +1 -0
- package/lib/constants.d.ts +31 -0
- package/lib/constants.js +32 -0
- package/lib/constants.js.map +1 -0
- package/lib/createErrorHandler.d.ts +7 -0
- package/lib/createErrorHandler.js +31 -0
- package/lib/createErrorHandler.js.map +1 -0
- package/lib/createSchemaUtils.d.ts +10 -0
- package/lib/createSchemaUtils.js +207 -0
- package/lib/createSchemaUtils.js.map +1 -0
- package/lib/dataURItoBlob.d.ts +16 -0
- package/lib/dataURItoBlob.js +43 -0
- package/lib/dataURItoBlob.js.map +1 -0
- package/lib/deepEquals.d.ts +8 -0
- package/lib/deepEquals.js +19 -0
- package/lib/deepEquals.js.map +1 -0
- package/lib/englishStringTranslator.d.ts +10 -0
- package/lib/englishStringTranslator.js +13 -0
- package/lib/englishStringTranslator.js.map +1 -0
- package/lib/enumOptionsDeselectValue.d.ts +14 -0
- package/lib/enumOptionsDeselectValue.js +22 -0
- package/lib/enumOptionsDeselectValue.js.map +1 -0
- package/lib/enumOptionsIndexForValue.d.ts +13 -0
- package/lib/enumOptionsIndexForValue.js +22 -0
- package/lib/enumOptionsIndexForValue.js.map +1 -0
- package/lib/enumOptionsIsSelected.d.ts +8 -0
- package/lib/enumOptionsIsSelected.js +14 -0
- package/lib/enumOptionsIsSelected.js.map +1 -0
- package/lib/enumOptionsSelectValue.d.ts +10 -0
- package/lib/enumOptionsSelectValue.js +23 -0
- package/lib/enumOptionsSelectValue.js.map +1 -0
- package/lib/enumOptionsValueForIndex.d.ts +13 -0
- package/lib/enumOptionsValueForIndex.js +21 -0
- package/lib/enumOptionsValueForIndex.js.map +1 -0
- package/lib/enums.d.ts +72 -0
- package/lib/enums.js +76 -0
- package/lib/enums.js.map +1 -0
- package/lib/findSchemaDefinition.d.ts +20 -0
- package/lib/findSchemaDefinition.js +49 -0
- package/lib/findSchemaDefinition.js.map +1 -0
- package/lib/getDiscriminatorFieldFromSchema.d.ts +8 -0
- package/lib/getDiscriminatorFieldFromSchema.js +20 -0
- package/lib/getDiscriminatorFieldFromSchema.js.map +1 -0
- package/lib/getInputProps.d.ts +10 -0
- package/lib/getInputProps.js +41 -0
- package/lib/getInputProps.js.map +1 -0
- package/lib/getSchemaType.d.ts +13 -0
- package/lib/getSchemaType.js +29 -0
- package/lib/getSchemaType.js.map +1 -0
- package/lib/getSubmitButtonOptions.d.ts +10 -0
- package/lib/getSubmitButtonOptions.js +25 -0
- package/lib/getSubmitButtonOptions.js.map +1 -0
- package/lib/getTemplate.d.ts +10 -0
- package/lib/getTemplate.js +19 -0
- package/lib/getTemplate.js.map +1 -0
- package/lib/getUiOptions.d.ts +9 -0
- package/lib/getUiOptions.js +25 -0
- package/lib/getUiOptions.js.map +1 -0
- package/lib/getWidget.d.ts +13 -0
- package/lib/getWidget.js +118 -0
- package/lib/getWidget.js.map +1 -0
- package/lib/guessType.d.ts +7 -0
- package/lib/guessType.js +29 -0
- package/lib/guessType.js.map +1 -0
- package/lib/hasWidget.d.ts +10 -0
- package/lib/hasWidget.js +23 -0
- package/lib/hasWidget.js.map +1 -0
- package/lib/hashForSchema.d.ts +8 -0
- package/lib/hashForSchema.js +29 -0
- package/lib/hashForSchema.js.map +1 -0
- package/lib/idGenerators.d.ts +47 -0
- package/lib/idGenerators.js +73 -0
- package/lib/idGenerators.js.map +1 -0
- package/lib/index.d.ts +57 -0
- package/lib/index.js +58 -0
- package/lib/index.js.map +1 -0
- package/lib/isConstant.d.ts +8 -0
- package/lib/isConstant.js +11 -0
- package/lib/isConstant.js.map +1 -0
- package/lib/isCustomWidget.d.ts +7 -0
- package/lib/isCustomWidget.js +13 -0
- package/lib/isCustomWidget.js.map +1 -0
- package/lib/isFixedItems.d.ts +8 -0
- package/lib/isFixedItems.js +11 -0
- package/lib/isFixedItems.js.map +1 -0
- package/lib/isObject.d.ts +7 -0
- package/lib/isObject.js +16 -0
- package/lib/isObject.js.map +1 -0
- package/lib/labelValue.d.ts +13 -0
- package/lib/labelValue.js +4 -0
- package/lib/labelValue.js.map +1 -0
- package/lib/localToUTC.d.ts +6 -0
- package/lib/localToUTC.js +9 -0
- package/lib/localToUTC.js.map +1 -0
- package/lib/mergeDefaultsWithFormData.d.ts +17 -0
- package/lib/mergeDefaultsWithFormData.js +43 -0
- package/lib/mergeDefaultsWithFormData.js.map +1 -0
- package/lib/mergeObjects.d.ts +11 -0
- package/lib/mergeObjects.js +35 -0
- package/lib/mergeObjects.js.map +1 -0
- package/lib/mergeSchemas.d.ts +10 -0
- package/lib/mergeSchemas.js +35 -0
- package/lib/mergeSchemas.js.map +1 -0
- package/lib/optionsList.d.ts +10 -0
- package/lib/optionsList.js +36 -0
- package/lib/optionsList.js.map +1 -0
- package/lib/orderProperties.d.ts +11 -0
- package/lib/orderProperties.js +38 -0
- package/lib/orderProperties.js.map +1 -0
- package/lib/pad.d.ts +7 -0
- package/lib/pad.js +14 -0
- package/lib/pad.js.map +1 -0
- package/lib/parseDateString.d.ts +9 -0
- package/lib/parseDateString.js +32 -0
- package/lib/parseDateString.js.map +1 -0
- package/lib/parser/ParserValidator.d.ts +70 -0
- package/lib/parser/ParserValidator.js +93 -0
- package/lib/parser/ParserValidator.js.map +1 -0
- package/lib/parser/index.d.ts +4 -0
- package/lib/parser/index.js +3 -0
- package/lib/parser/index.js.map +1 -0
- package/lib/parser/schemaParser.d.ts +9 -0
- package/lib/parser/schemaParser.js +48 -0
- package/lib/parser/schemaParser.js.map +1 -0
- package/lib/rangeSpec.d.ts +9 -0
- package/lib/rangeSpec.js +20 -0
- package/lib/rangeSpec.js.map +1 -0
- package/lib/replaceStringParameters.d.ts +9 -0
- package/lib/replaceStringParameters.js +23 -0
- package/lib/replaceStringParameters.js.map +1 -0
- package/lib/schema/getClosestMatchingOption.d.ts +49 -0
- package/lib/schema/getClosestMatchingOption.js +154 -0
- package/lib/schema/getClosestMatchingOption.js.map +1 -0
- package/lib/schema/getDefaultFormState.d.ts +66 -0
- package/lib/schema/getDefaultFormState.js +351 -0
- package/lib/schema/getDefaultFormState.js.map +1 -0
- package/lib/schema/getDisplayLabel.d.ts +12 -0
- package/lib/schema/getDisplayLabel.js +39 -0
- package/lib/schema/getDisplayLabel.js.map +1 -0
- package/lib/schema/getFirstMatchingOption.d.ts +13 -0
- package/lib/schema/getFirstMatchingOption.js +16 -0
- package/lib/schema/getFirstMatchingOption.js.map +1 -0
- package/lib/schema/getMatchingOption.d.ts +14 -0
- package/lib/schema/getMatchingOption.js +80 -0
- package/lib/schema/getMatchingOption.js.map +1 -0
- package/lib/schema/index.d.ts +14 -0
- package/lib/schema/index.js +15 -0
- package/lib/schema/index.js.map +1 -0
- package/lib/schema/isFilesArray.d.ts +10 -0
- package/lib/schema/isFilesArray.js +21 -0
- package/lib/schema/isFilesArray.js.map +1 -0
- package/lib/schema/isMultiSelect.d.ts +9 -0
- package/lib/schema/isMultiSelect.js +15 -0
- package/lib/schema/isMultiSelect.js.map +1 -0
- package/lib/schema/isSelect.d.ts +9 -0
- package/lib/schema/isSelect.js +21 -0
- package/lib/schema/isSelect.js.map +1 -0
- package/lib/schema/mergeValidationData.d.ts +14 -0
- package/lib/schema/mergeValidationData.js +28 -0
- package/lib/schema/mergeValidationData.js.map +1 -0
- package/lib/schema/retrieveSchema.d.ts +170 -0
- package/lib/schema/retrieveSchema.js +437 -0
- package/lib/schema/retrieveSchema.js.map +1 -0
- package/lib/schema/sanitizeDataForNewSchema.d.ts +49 -0
- package/lib/schema/sanitizeDataForNewSchema.js +173 -0
- package/lib/schema/sanitizeDataForNewSchema.js.map +1 -0
- package/lib/schema/toIdSchema.d.ts +13 -0
- package/lib/schema/toIdSchema.js +59 -0
- package/lib/schema/toIdSchema.js.map +1 -0
- package/lib/schema/toPathSchema.d.ts +11 -0
- package/lib/schema/toPathSchema.js +68 -0
- package/lib/schema/toPathSchema.js.map +1 -0
- package/lib/schemaRequiresTrueValue.d.ts +11 -0
- package/lib/schemaRequiresTrueValue.js +34 -0
- package/lib/schemaRequiresTrueValue.js.map +1 -0
- package/lib/shouldRender.d.ts +10 -0
- package/lib/shouldRender.js +14 -0
- package/lib/shouldRender.js.map +1 -0
- package/lib/toConstant.d.ts +9 -0
- package/lib/toConstant.js +18 -0
- package/lib/toConstant.js.map +1 -0
- package/lib/toDateString.d.ts +9 -0
- package/lib/toDateString.js +14 -0
- package/lib/toDateString.js.map +1 -0
- package/lib/toErrorList.d.ts +8 -0
- package/lib/toErrorList.js +34 -0
- package/lib/toErrorList.js.map +1 -0
- package/lib/toErrorSchema.d.ts +21 -0
- package/lib/toErrorSchema.js +41 -0
- package/lib/toErrorSchema.js.map +1 -0
- package/lib/types.d.ts +982 -0
- package/lib/types.js +2 -0
- package/lib/types.js.map +1 -0
- package/lib/unwrapErrorHandler.d.ts +7 -0
- package/lib/unwrapErrorHandler.js +21 -0
- package/lib/unwrapErrorHandler.js.map +1 -0
- package/lib/utcToLocal.d.ts +6 -0
- package/lib/utcToLocal.js +26 -0
- package/lib/utcToLocal.js.map +1 -0
- package/lib/validationDataMerge.d.ts +11 -0
- package/lib/validationDataMerge.js +26 -0
- package/lib/validationDataMerge.js.map +1 -0
- package/lib/withIdRefPrefix.d.ts +8 -0
- package/lib/withIdRefPrefix.js +47 -0
- package/lib/withIdRefPrefix.js.map +1 -0
- package/package.json +20 -13
- package/src/ErrorSchemaBuilder.ts +112 -0
- package/src/allowAdditionalItems.ts +15 -0
- package/src/asNumber.ts +38 -0
- package/src/canExpand.ts +31 -0
- package/src/constants.ts +31 -0
- package/src/createErrorHandler.ts +33 -0
- package/src/createSchemaUtils.ts +298 -0
- package/src/dataURItoBlob.ts +42 -0
- package/src/deepEquals.ts +19 -0
- package/src/englishStringTranslator.ts +14 -0
- package/src/enumOptionsDeselectValue.ts +28 -0
- package/src/enumOptionsIndexForValue.ts +27 -0
- package/src/enumOptionsIsSelected.ts +19 -0
- package/src/enumOptionsSelectValue.ts +28 -0
- package/src/enumOptionsValueForIndex.ts +26 -0
- package/src/enums.ts +74 -0
- package/src/findSchemaDefinition.ts +54 -0
- package/src/getDiscriminatorFieldFromSchema.ts +21 -0
- package/src/getInputProps.ts +55 -0
- package/src/getSchemaType.ts +37 -0
- package/src/getSubmitButtonOptions.ts +32 -0
- package/src/getTemplate.ts +26 -0
- package/src/getUiOptions.ts +32 -0
- package/src/getWidget.tsx +133 -0
- package/src/guessType.ts +28 -0
- package/src/hasWidget.ts +27 -0
- package/src/hashForSchema.ts +31 -0
- package/src/idGenerators.ts +81 -0
- package/src/index.ts +118 -0
- package/src/isConstant.ts +12 -0
- package/src/isCustomWidget.ts +19 -0
- package/src/isFixedItems.ts +12 -0
- package/src/isObject.ts +15 -0
- package/src/labelValue.ts +16 -0
- package/src/localToUTC.ts +8 -0
- package/src/mergeDefaultsWithFormData.ts +53 -0
- package/src/mergeObjects.ts +39 -0
- package/src/mergeSchemas.ts +38 -0
- package/src/optionsList.ts +41 -0
- package/src/orderProperties.ts +44 -0
- package/src/pad.ts +13 -0
- package/src/parseDateString.ts +33 -0
- package/src/parser/ParserValidator.ts +132 -0
- package/src/parser/index.ts +6 -0
- package/src/parser/schemaParser.ts +60 -0
- package/src/rangeSpec.ts +22 -0
- package/src/replaceStringParameters.ts +22 -0
- package/src/schema/getClosestMatchingOption.ts +191 -0
- package/src/schema/getDefaultFormState.ts +447 -0
- package/src/schema/getDisplayLabel.ts +59 -0
- package/src/schema/getFirstMatchingOption.ts +27 -0
- package/src/schema/getMatchingOption.ts +95 -0
- package/src/schema/index.ts +29 -0
- package/src/schema/isFilesArray.ts +27 -0
- package/src/schema/isMultiSelect.ts +21 -0
- package/src/schema/isSelect.ts +26 -0
- package/src/schema/mergeValidationData.ts +38 -0
- package/src/schema/retrieveSchema.ts +614 -0
- package/src/schema/sanitizeDataForNewSchema.ts +197 -0
- package/src/schema/toIdSchema.ts +105 -0
- package/src/schema/toPathSchema.ts +121 -0
- package/src/schemaRequiresTrueValue.ts +40 -0
- package/src/shouldRender.ts +16 -0
- package/src/toConstant.ts +19 -0
- package/src/toDateString.ts +15 -0
- package/src/toErrorList.ts +41 -0
- package/src/toErrorSchema.ts +43 -0
- package/src/types.ts +1139 -0
- package/src/unwrapErrorHandler.ts +25 -0
- package/src/utcToLocal.ts +30 -0
- package/src/validationDataMerge.ts +31 -0
- package/src/withIdRefPrefix.ts +49 -0
- package/dist/index.d.ts +0 -1911
- package/dist/utils.cjs.development.js +0 -3522
- package/dist/utils.cjs.development.js.map +0 -1
- package/dist/utils.cjs.production.min.js +0 -2
- package/dist/utils.cjs.production.min.js.map +0 -1
- package/dist/utils.umd.development.js +0 -3504
- package/dist/utils.umd.development.js.map +0 -1
- package/dist/utils.umd.production.min.js +0 -2
- package/dist/utils.umd.production.min.js.map +0 -1
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import get from 'lodash/get';
|
|
2
|
+
import has from 'lodash/has';
|
|
3
|
+
|
|
4
|
+
import { FormContextType, GenericObjectType, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types';
|
|
5
|
+
import { PROPERTIES_KEY, REF_KEY } from '../constants';
|
|
6
|
+
import retrieveSchema from './retrieveSchema';
|
|
7
|
+
|
|
8
|
+
const NO_VALUE = Symbol('no Value');
|
|
9
|
+
|
|
10
|
+
/** Sanitize the `data` associated with the `oldSchema` so it is considered appropriate for the `newSchema`. If the new
|
|
11
|
+
* schema does not contain any properties, then `undefined` is returned to clear all the form data. Due to the nature
|
|
12
|
+
* of schemas, this sanitization happens recursively for nested objects of data. Also, any properties in the old schema
|
|
13
|
+
* that are non-existent in the new schema are set to `undefined`. The data sanitization process has the following flow:
|
|
14
|
+
*
|
|
15
|
+
* - If the new schema is an object that contains a `properties` object then:
|
|
16
|
+
* - Create a `removeOldSchemaData` object, setting each key in the `oldSchema.properties` having `data` to undefined
|
|
17
|
+
* - Create an empty `nestedData` object for use in the key filtering below:
|
|
18
|
+
* - Iterate over each key in the `newSchema.properties` as follows:
|
|
19
|
+
* - Get the `formValue` of the key from the `data`
|
|
20
|
+
* - Get the `oldKeySchema` and `newKeyedSchema` for the key, defaulting to `{}` when it doesn't exist
|
|
21
|
+
* - Retrieve the schema for any refs within each `oldKeySchema` and/or `newKeySchema`
|
|
22
|
+
* - Get the types of the old and new keyed schemas and if the old doesn't exist or the old & new are the same then:
|
|
23
|
+
* - If `removeOldSchemaData` has an entry for the key, delete it since the new schema has the same property
|
|
24
|
+
* - If type of the key in the new schema is `object`:
|
|
25
|
+
* - Store the value from the recursive `sanitizeDataForNewSchema` call in `nestedData[key]`
|
|
26
|
+
* - Otherwise, check for default or const values:
|
|
27
|
+
* - Get the old and new `default` values from the schema and check:
|
|
28
|
+
* - If the new `default` value does not match the form value:
|
|
29
|
+
* - If the old `default` value DOES match the form value, then:
|
|
30
|
+
* - Replace `removeOldSchemaData[key]` with the new `default`
|
|
31
|
+
* - Otherwise, if the new schema is `readOnly` then replace `removeOldSchemaData[key]` with undefined
|
|
32
|
+
* - Get the old and new `const` values from the schema and check:
|
|
33
|
+
* - If the new `const` value does not match the form value:
|
|
34
|
+
* - If the old `const` value DOES match the form value, then:
|
|
35
|
+
* - Replace `removeOldSchemaData[key]` with the new `const`
|
|
36
|
+
* - Otherwise, replace `removeOldSchemaData[key]` with undefined
|
|
37
|
+
* - Once all keys have been processed, return an object built as follows:
|
|
38
|
+
* - `{ ...removeOldSchemaData, ...nestedData, ...pick(data, keysToKeep) }`
|
|
39
|
+
* - If the new and old schema types are array and the `data` is an array then:
|
|
40
|
+
* - If the type of the old and new schema `items` are a non-array objects:
|
|
41
|
+
* - Retrieve the schema for any refs within each `oldKeySchema.items` and/or `newKeySchema.items`
|
|
42
|
+
* - If the `type`s of both items are the same (or the old does not have a type):
|
|
43
|
+
* - If the type is "object", then:
|
|
44
|
+
* - For each element in the `data` recursively sanitize the data, stopping at `maxItems` if specified
|
|
45
|
+
* - Otherwise, just return the `data` removing any values after `maxItems` if it is set
|
|
46
|
+
* - If the type of the old and new schema `items` are booleans of the same value, return `data` as is
|
|
47
|
+
* - Otherwise return `undefined`
|
|
48
|
+
*
|
|
49
|
+
* @param validator - An implementation of the `ValidatorType` interface that will be used when necessary
|
|
50
|
+
* @param rootSchema - The root JSON schema of the entire form
|
|
51
|
+
* @param [newSchema] - The new schema for which the data is being sanitized
|
|
52
|
+
* @param [oldSchema] - The old schema from which the data originated
|
|
53
|
+
* @param [data={}] - The form data associated with the schema, defaulting to an empty object when undefined
|
|
54
|
+
* @returns - The new form data, with all the fields uniquely associated with the old schema set
|
|
55
|
+
* to `undefined`. Will return `undefined` if the new schema is not an object containing properties.
|
|
56
|
+
*/
|
|
57
|
+
export default function sanitizeDataForNewSchema<
|
|
58
|
+
T = any,
|
|
59
|
+
S extends StrictRJSFSchema = RJSFSchema,
|
|
60
|
+
F extends FormContextType = any
|
|
61
|
+
>(validator: ValidatorType<T, S, F>, rootSchema: S, newSchema?: S, oldSchema?: S, data: any = {}): T {
|
|
62
|
+
// By default, we will clear the form data
|
|
63
|
+
let newFormData;
|
|
64
|
+
// If the new schema is of type object and that object contains a list of properties
|
|
65
|
+
if (has(newSchema, PROPERTIES_KEY)) {
|
|
66
|
+
// Create an object containing root-level keys in the old schema, setting each key to undefined to remove the data
|
|
67
|
+
const removeOldSchemaData: GenericObjectType = {};
|
|
68
|
+
if (has(oldSchema, PROPERTIES_KEY)) {
|
|
69
|
+
const properties = get(oldSchema, PROPERTIES_KEY, {});
|
|
70
|
+
Object.keys(properties).forEach((key) => {
|
|
71
|
+
if (has(data, key)) {
|
|
72
|
+
removeOldSchemaData[key] = undefined;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
const keys: string[] = Object.keys(get(newSchema, PROPERTIES_KEY, {}));
|
|
77
|
+
// Create a place to store nested data that will be a side-effect of the filter
|
|
78
|
+
const nestedData: GenericObjectType = {};
|
|
79
|
+
keys.forEach((key) => {
|
|
80
|
+
const formValue = get(data, key);
|
|
81
|
+
let oldKeyedSchema: S = get(oldSchema, [PROPERTIES_KEY, key], {});
|
|
82
|
+
let newKeyedSchema: S = get(newSchema, [PROPERTIES_KEY, key], {});
|
|
83
|
+
// Resolve the refs if they exist
|
|
84
|
+
if (has(oldKeyedSchema, REF_KEY)) {
|
|
85
|
+
oldKeyedSchema = retrieveSchema<T, S, F>(validator, oldKeyedSchema, rootSchema, formValue);
|
|
86
|
+
}
|
|
87
|
+
if (has(newKeyedSchema, REF_KEY)) {
|
|
88
|
+
newKeyedSchema = retrieveSchema<T, S, F>(validator, newKeyedSchema, rootSchema, formValue);
|
|
89
|
+
}
|
|
90
|
+
// Now get types and see if they are the same
|
|
91
|
+
const oldSchemaTypeForKey = get(oldKeyedSchema, 'type');
|
|
92
|
+
const newSchemaTypeForKey = get(newKeyedSchema, 'type');
|
|
93
|
+
// Check if the old option has the same key with the same type
|
|
94
|
+
if (!oldSchemaTypeForKey || oldSchemaTypeForKey === newSchemaTypeForKey) {
|
|
95
|
+
if (has(removeOldSchemaData, key)) {
|
|
96
|
+
// SIDE-EFFECT: remove the undefined value for a key that has the same type between the old and new schemas
|
|
97
|
+
delete removeOldSchemaData[key];
|
|
98
|
+
}
|
|
99
|
+
// If it is an object, we'll recurse and store the resulting sanitized data for the key
|
|
100
|
+
if (newSchemaTypeForKey === 'object' || (newSchemaTypeForKey === 'array' && Array.isArray(formValue))) {
|
|
101
|
+
// SIDE-EFFECT: process the new schema type of object recursively to save iterations
|
|
102
|
+
const itemData = sanitizeDataForNewSchema<T, S, F>(
|
|
103
|
+
validator,
|
|
104
|
+
rootSchema,
|
|
105
|
+
newKeyedSchema,
|
|
106
|
+
oldKeyedSchema,
|
|
107
|
+
formValue
|
|
108
|
+
);
|
|
109
|
+
if (itemData !== undefined || newSchemaTypeForKey === 'array') {
|
|
110
|
+
// only put undefined values for the array type and not the object type
|
|
111
|
+
nestedData[key] = itemData;
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
// Ok, the non-object types match, let's make sure that a default or a const of a different value is replaced
|
|
115
|
+
// with the new default or const. This allows the case where two schemas differ that only by the default/const
|
|
116
|
+
// value to be properly selected
|
|
117
|
+
const newOptionDefault = get(newKeyedSchema, 'default', NO_VALUE);
|
|
118
|
+
const oldOptionDefault = get(oldKeyedSchema, 'default', NO_VALUE);
|
|
119
|
+
if (newOptionDefault !== NO_VALUE && newOptionDefault !== formValue) {
|
|
120
|
+
if (oldOptionDefault === formValue) {
|
|
121
|
+
// If the old default matches the formValue, we'll update the new value to match the new default
|
|
122
|
+
removeOldSchemaData[key] = newOptionDefault;
|
|
123
|
+
} else if (get(newKeyedSchema, 'readOnly') === true) {
|
|
124
|
+
// If the new schema has the default set to read-only, treat it like a const and remove the value
|
|
125
|
+
removeOldSchemaData[key] = undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const newOptionConst = get(newKeyedSchema, 'const', NO_VALUE);
|
|
130
|
+
const oldOptionConst = get(oldKeyedSchema, 'const', NO_VALUE);
|
|
131
|
+
if (newOptionConst !== NO_VALUE && newOptionConst !== formValue) {
|
|
132
|
+
// Since this is a const, if the old value matches, replace the value with the new const otherwise clear it
|
|
133
|
+
removeOldSchemaData[key] = oldOptionConst === formValue ? newOptionConst : undefined;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
newFormData = {
|
|
140
|
+
...data,
|
|
141
|
+
...removeOldSchemaData,
|
|
142
|
+
...nestedData,
|
|
143
|
+
};
|
|
144
|
+
// First apply removing the old schema data, then apply the nested data, then apply the old data keys to keep
|
|
145
|
+
} else if (get(oldSchema, 'type') === 'array' && get(newSchema, 'type') === 'array' && Array.isArray(data)) {
|
|
146
|
+
let oldSchemaItems = get(oldSchema, 'items');
|
|
147
|
+
let newSchemaItems = get(newSchema, 'items');
|
|
148
|
+
// If any of the array types `items` are arrays (remember arrays are objects) then we'll just drop the data
|
|
149
|
+
// Eventually, we may want to deal with when either of the `items` are arrays since those tuple validations
|
|
150
|
+
if (
|
|
151
|
+
typeof oldSchemaItems === 'object' &&
|
|
152
|
+
typeof newSchemaItems === 'object' &&
|
|
153
|
+
!Array.isArray(oldSchemaItems) &&
|
|
154
|
+
!Array.isArray(newSchemaItems)
|
|
155
|
+
) {
|
|
156
|
+
if (has(oldSchemaItems, REF_KEY)) {
|
|
157
|
+
oldSchemaItems = retrieveSchema<T, S, F>(validator, oldSchemaItems as S, rootSchema, data as T);
|
|
158
|
+
}
|
|
159
|
+
if (has(newSchemaItems, REF_KEY)) {
|
|
160
|
+
newSchemaItems = retrieveSchema<T, S, F>(validator, newSchemaItems as S, rootSchema, data as T);
|
|
161
|
+
}
|
|
162
|
+
// Now get types and see if they are the same
|
|
163
|
+
const oldSchemaType = get(oldSchemaItems, 'type');
|
|
164
|
+
const newSchemaType = get(newSchemaItems, 'type');
|
|
165
|
+
// Check if the old option has the same key with the same type
|
|
166
|
+
if (!oldSchemaType || oldSchemaType === newSchemaType) {
|
|
167
|
+
const maxItems = get(newSchema, 'maxItems', -1);
|
|
168
|
+
if (newSchemaType === 'object') {
|
|
169
|
+
newFormData = data.reduce((newValue, aValue) => {
|
|
170
|
+
const itemValue = sanitizeDataForNewSchema<T, S, F>(
|
|
171
|
+
validator,
|
|
172
|
+
rootSchema,
|
|
173
|
+
newSchemaItems as S,
|
|
174
|
+
oldSchemaItems as S,
|
|
175
|
+
aValue
|
|
176
|
+
);
|
|
177
|
+
if (itemValue !== undefined && (maxItems < 0 || newValue.length < maxItems)) {
|
|
178
|
+
newValue.push(itemValue);
|
|
179
|
+
}
|
|
180
|
+
return newValue;
|
|
181
|
+
}, []);
|
|
182
|
+
} else {
|
|
183
|
+
newFormData = maxItems > 0 && data.length > maxItems ? data.slice(0, maxItems) : data;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
} else if (
|
|
187
|
+
typeof oldSchemaItems === 'boolean' &&
|
|
188
|
+
typeof newSchemaItems === 'boolean' &&
|
|
189
|
+
oldSchemaItems === newSchemaItems
|
|
190
|
+
) {
|
|
191
|
+
// If they are both booleans and have the same value just return the data as is otherwise fall-thru to undefined
|
|
192
|
+
newFormData = data;
|
|
193
|
+
}
|
|
194
|
+
// Also probably want to deal with `prefixItems` as tuples with the latest 2020 draft
|
|
195
|
+
}
|
|
196
|
+
return newFormData as T;
|
|
197
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import get from 'lodash/get';
|
|
2
|
+
import isEqual from 'lodash/isEqual';
|
|
3
|
+
|
|
4
|
+
import { ALL_OF_KEY, DEPENDENCIES_KEY, ID_KEY, ITEMS_KEY, PROPERTIES_KEY, REF_KEY } from '../constants';
|
|
5
|
+
import isObject from '../isObject';
|
|
6
|
+
import { FormContextType, IdSchema, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types';
|
|
7
|
+
import retrieveSchema from './retrieveSchema';
|
|
8
|
+
import getSchemaType from '../getSchemaType';
|
|
9
|
+
|
|
10
|
+
/** An internal helper that generates an `IdSchema` object for the `schema`, recursively with protection against
|
|
11
|
+
* infinite recursion
|
|
12
|
+
*
|
|
13
|
+
* @param validator - An implementation of the `ValidatorType` interface that will be used when necessary
|
|
14
|
+
* @param schema - The schema for which the `IdSchema` is desired
|
|
15
|
+
* @param idPrefix - The prefix to use for the id
|
|
16
|
+
* @param idSeparator - The separator to use for the path segments in the id
|
|
17
|
+
* @param [id] - The base id for the schema
|
|
18
|
+
* @param [rootSchema] - The root schema, used to primarily to look up `$ref`s
|
|
19
|
+
* @param [formData] - The current formData, if any, to assist retrieving a schema
|
|
20
|
+
* @param [_recurseList=[]] - The list of retrieved schemas currently being recursed, used to prevent infinite recursion
|
|
21
|
+
* @returns - The `IdSchema` object for the `schema`
|
|
22
|
+
*/
|
|
23
|
+
function toIdSchemaInternal<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
24
|
+
validator: ValidatorType<T, S, F>,
|
|
25
|
+
schema: S,
|
|
26
|
+
idPrefix: string,
|
|
27
|
+
idSeparator: string,
|
|
28
|
+
id?: string | null,
|
|
29
|
+
rootSchema?: S,
|
|
30
|
+
formData?: T,
|
|
31
|
+
_recurseList: S[] = []
|
|
32
|
+
): IdSchema<T> {
|
|
33
|
+
if (REF_KEY in schema || DEPENDENCIES_KEY in schema || ALL_OF_KEY in schema) {
|
|
34
|
+
const _schema = retrieveSchema<T, S, F>(validator, schema, rootSchema, formData);
|
|
35
|
+
const sameSchemaIndex = _recurseList.findIndex((item) => isEqual(item, _schema));
|
|
36
|
+
if (sameSchemaIndex === -1) {
|
|
37
|
+
return toIdSchemaInternal<T, S, F>(
|
|
38
|
+
validator,
|
|
39
|
+
_schema,
|
|
40
|
+
idPrefix,
|
|
41
|
+
idSeparator,
|
|
42
|
+
id,
|
|
43
|
+
rootSchema,
|
|
44
|
+
formData,
|
|
45
|
+
_recurseList.concat(_schema)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (ITEMS_KEY in schema && !get(schema, [ITEMS_KEY, REF_KEY])) {
|
|
50
|
+
return toIdSchemaInternal<T, S, F>(
|
|
51
|
+
validator,
|
|
52
|
+
get(schema, ITEMS_KEY) as S,
|
|
53
|
+
idPrefix,
|
|
54
|
+
idSeparator,
|
|
55
|
+
id,
|
|
56
|
+
rootSchema,
|
|
57
|
+
formData,
|
|
58
|
+
_recurseList
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
const $id = id || idPrefix;
|
|
62
|
+
const idSchema: IdSchema = { $id } as IdSchema<T>;
|
|
63
|
+
if (getSchemaType<S>(schema) === 'object' && PROPERTIES_KEY in schema) {
|
|
64
|
+
for (const name in schema.properties) {
|
|
65
|
+
const field = get(schema, [PROPERTIES_KEY, name]);
|
|
66
|
+
const fieldId = idSchema[ID_KEY] + idSeparator + name;
|
|
67
|
+
idSchema[name] = toIdSchemaInternal<T, S, F>(
|
|
68
|
+
validator,
|
|
69
|
+
isObject(field) ? field : {},
|
|
70
|
+
idPrefix,
|
|
71
|
+
idSeparator,
|
|
72
|
+
fieldId,
|
|
73
|
+
rootSchema,
|
|
74
|
+
// It's possible that formData is not an object -- this can happen if an
|
|
75
|
+
// array item has just been added, but not populated with data yet
|
|
76
|
+
get(formData, [name]),
|
|
77
|
+
_recurseList
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return idSchema as IdSchema<T>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Generates an `IdSchema` object for the `schema`, recursively
|
|
85
|
+
*
|
|
86
|
+
* @param validator - An implementation of the `ValidatorType` interface that will be used when necessary
|
|
87
|
+
* @param schema - The schema for which the `IdSchema` is desired
|
|
88
|
+
* @param [id] - The base id for the schema
|
|
89
|
+
* @param [rootSchema] - The root schema, used to primarily to look up `$ref`s
|
|
90
|
+
* @param [formData] - The current formData, if any, to assist retrieving a schema
|
|
91
|
+
* @param [idPrefix='root'] - The prefix to use for the id
|
|
92
|
+
* @param [idSeparator='_'] - The separator to use for the path segments in the id
|
|
93
|
+
* @returns - The `IdSchema` object for the `schema`
|
|
94
|
+
*/
|
|
95
|
+
export default function toIdSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
96
|
+
validator: ValidatorType<T, S, F>,
|
|
97
|
+
schema: S,
|
|
98
|
+
id?: string | null,
|
|
99
|
+
rootSchema?: S,
|
|
100
|
+
formData?: T,
|
|
101
|
+
idPrefix = 'root',
|
|
102
|
+
idSeparator = '_'
|
|
103
|
+
): IdSchema<T> {
|
|
104
|
+
return toIdSchemaInternal<T, S, F>(validator, schema, idPrefix, idSeparator, id, rootSchema, formData);
|
|
105
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import get from 'lodash/get';
|
|
2
|
+
import isEqual from 'lodash/isEqual';
|
|
3
|
+
import set from 'lodash/set';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
ALL_OF_KEY,
|
|
7
|
+
ANY_OF_KEY,
|
|
8
|
+
ADDITIONAL_PROPERTIES_KEY,
|
|
9
|
+
DEPENDENCIES_KEY,
|
|
10
|
+
ITEMS_KEY,
|
|
11
|
+
NAME_KEY,
|
|
12
|
+
ONE_OF_KEY,
|
|
13
|
+
PROPERTIES_KEY,
|
|
14
|
+
REF_KEY,
|
|
15
|
+
RJSF_ADDITONAL_PROPERTIES_FLAG,
|
|
16
|
+
} from '../constants';
|
|
17
|
+
import getDiscriminatorFieldFromSchema from '../getDiscriminatorFieldFromSchema';
|
|
18
|
+
import { FormContextType, PathSchema, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types';
|
|
19
|
+
import getClosestMatchingOption from './getClosestMatchingOption';
|
|
20
|
+
import retrieveSchema from './retrieveSchema';
|
|
21
|
+
|
|
22
|
+
/** An internal helper that generates an `PathSchema` object for the `schema`, recursively with protection against
|
|
23
|
+
* infinite recursion
|
|
24
|
+
*
|
|
25
|
+
* @param validator - An implementation of the `ValidatorType` interface that will be used when necessary
|
|
26
|
+
* @param schema - The schema for which the `PathSchema` is desired
|
|
27
|
+
* @param [name=''] - The base name for the schema
|
|
28
|
+
* @param [rootSchema] - The root schema, used to primarily to look up `$ref`s
|
|
29
|
+
* @param [formData] - The current formData, if any, to assist retrieving a schema
|
|
30
|
+
* @param [_recurseList=[]] - The list of retrieved schemas currently being recursed, used to prevent infinite recursion
|
|
31
|
+
* @returns - The `PathSchema` object for the `schema`
|
|
32
|
+
*/
|
|
33
|
+
function toPathSchemaInternal<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
34
|
+
validator: ValidatorType<T, S, F>,
|
|
35
|
+
schema: S,
|
|
36
|
+
name: string,
|
|
37
|
+
rootSchema?: S,
|
|
38
|
+
formData?: T,
|
|
39
|
+
_recurseList: S[] = []
|
|
40
|
+
): PathSchema<T> {
|
|
41
|
+
if (REF_KEY in schema || DEPENDENCIES_KEY in schema || ALL_OF_KEY in schema) {
|
|
42
|
+
const _schema = retrieveSchema<T, S, F>(validator, schema, rootSchema, formData);
|
|
43
|
+
const sameSchemaIndex = _recurseList.findIndex((item) => isEqual(item, _schema));
|
|
44
|
+
if (sameSchemaIndex === -1) {
|
|
45
|
+
return toPathSchemaInternal<T, S, F>(
|
|
46
|
+
validator,
|
|
47
|
+
_schema,
|
|
48
|
+
name,
|
|
49
|
+
rootSchema,
|
|
50
|
+
formData,
|
|
51
|
+
_recurseList.concat(_schema)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let pathSchema: PathSchema = {
|
|
57
|
+
[NAME_KEY]: name.replace(/^\./, ''),
|
|
58
|
+
} as PathSchema;
|
|
59
|
+
|
|
60
|
+
if (ONE_OF_KEY in schema || ANY_OF_KEY in schema) {
|
|
61
|
+
const xxxOf: S[] = ONE_OF_KEY in schema ? (schema.oneOf as S[]) : (schema.anyOf as S[]);
|
|
62
|
+
const discriminator = getDiscriminatorFieldFromSchema<S>(schema);
|
|
63
|
+
const index = getClosestMatchingOption<T, S, F>(validator, rootSchema!, formData, xxxOf, 0, discriminator);
|
|
64
|
+
const _schema: S = xxxOf![index] as S;
|
|
65
|
+
pathSchema = {
|
|
66
|
+
...pathSchema,
|
|
67
|
+
...toPathSchemaInternal<T, S, F>(validator, _schema, name, rootSchema, formData, _recurseList),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (ADDITIONAL_PROPERTIES_KEY in schema && schema[ADDITIONAL_PROPERTIES_KEY] !== false) {
|
|
72
|
+
set(pathSchema, RJSF_ADDITONAL_PROPERTIES_FLAG, true);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (ITEMS_KEY in schema && Array.isArray(formData)) {
|
|
76
|
+
formData.forEach((element, i: number) => {
|
|
77
|
+
pathSchema[i] = toPathSchemaInternal<T, S, F>(
|
|
78
|
+
validator,
|
|
79
|
+
schema.items as S,
|
|
80
|
+
`${name}.${i}`,
|
|
81
|
+
rootSchema,
|
|
82
|
+
element,
|
|
83
|
+
_recurseList
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
} else if (PROPERTIES_KEY in schema) {
|
|
87
|
+
for (const property in schema.properties) {
|
|
88
|
+
const field = get(schema, [PROPERTIES_KEY, property]);
|
|
89
|
+
pathSchema[property] = toPathSchemaInternal<T, S, F>(
|
|
90
|
+
validator,
|
|
91
|
+
field,
|
|
92
|
+
`${name}.${property}`,
|
|
93
|
+
rootSchema,
|
|
94
|
+
// It's possible that formData is not an object -- this can happen if an
|
|
95
|
+
// array item has just been added, but not populated with data yet
|
|
96
|
+
get(formData, [property]),
|
|
97
|
+
_recurseList
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return pathSchema as PathSchema<T>;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Generates an `PathSchema` object for the `schema`, recursively
|
|
105
|
+
*
|
|
106
|
+
* @param validator - An implementation of the `ValidatorType` interface that will be used when necessary
|
|
107
|
+
* @param schema - The schema for which the `PathSchema` is desired
|
|
108
|
+
* @param [name=''] - The base name for the schema
|
|
109
|
+
* @param [rootSchema] - The root schema, used to primarily to look up `$ref`s
|
|
110
|
+
* @param [formData] - The current formData, if any, to assist retrieving a schema
|
|
111
|
+
* @returns - The `PathSchema` object for the `schema`
|
|
112
|
+
*/
|
|
113
|
+
export default function toPathSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
114
|
+
validator: ValidatorType<T, S, F>,
|
|
115
|
+
schema: S,
|
|
116
|
+
name = '',
|
|
117
|
+
rootSchema?: S,
|
|
118
|
+
formData?: T
|
|
119
|
+
): PathSchema<T> {
|
|
120
|
+
return toPathSchemaInternal(validator, schema, name, rootSchema, formData);
|
|
121
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { RJSFSchema, StrictRJSFSchema } from './types';
|
|
2
|
+
|
|
3
|
+
/** Check to see if a `schema` specifies that a value must be true. This happens when:
|
|
4
|
+
* - `schema.const` is truthy
|
|
5
|
+
* - `schema.enum` == `[true]`
|
|
6
|
+
* - `schema.anyOf` or `schema.oneOf` has a single value which recursively returns true
|
|
7
|
+
* - `schema.allOf` has at least one value which recursively returns true
|
|
8
|
+
*
|
|
9
|
+
* @param schema - The schema to check
|
|
10
|
+
* @returns - True if the schema specifies a value that must be true, false otherwise
|
|
11
|
+
*/
|
|
12
|
+
export default function schemaRequiresTrueValue<S extends StrictRJSFSchema = RJSFSchema>(schema: S): boolean {
|
|
13
|
+
// Check if const is a truthy value
|
|
14
|
+
if (schema.const) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Check if an enum has a single value of true
|
|
19
|
+
if (schema.enum && schema.enum.length === 1 && schema.enum[0] === true) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// If anyOf has a single value, evaluate the subschema
|
|
24
|
+
if (schema.anyOf && schema.anyOf.length === 1) {
|
|
25
|
+
return schemaRequiresTrueValue(schema.anyOf[0] as S);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// If oneOf has a single value, evaluate the subschema
|
|
29
|
+
if (schema.oneOf && schema.oneOf.length === 1) {
|
|
30
|
+
return schemaRequiresTrueValue(schema.oneOf[0] as S);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Evaluate each subschema in allOf, to see if one of them requires a true value
|
|
34
|
+
if (schema.allOf) {
|
|
35
|
+
const schemaSome = (subSchema: S['additionalProperties']) => schemaRequiresTrueValue(subSchema as S);
|
|
36
|
+
return schema.allOf.some(schemaSome);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import deepEquals from './deepEquals';
|
|
4
|
+
|
|
5
|
+
/** Determines whether the given `component` should be rerendered by comparing its current set of props and state
|
|
6
|
+
* against the next set. If either of those two sets are not the same, then the component should be rerendered.
|
|
7
|
+
*
|
|
8
|
+
* @param component - A React component being checked
|
|
9
|
+
* @param nextProps - The next set of props against which to check
|
|
10
|
+
* @param nextState - The next set of state against which to check
|
|
11
|
+
* @returns - True if the component should be re-rendered, false otherwise
|
|
12
|
+
*/
|
|
13
|
+
export default function shouldRender(component: React.Component, nextProps: any, nextState: any) {
|
|
14
|
+
const { props, state } = component;
|
|
15
|
+
return !deepEquals(props, nextProps) || !deepEquals(state, nextState);
|
|
16
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CONST_KEY, ENUM_KEY } from './constants';
|
|
2
|
+
import { RJSFSchema, StrictRJSFSchema } from './types';
|
|
3
|
+
|
|
4
|
+
/** Returns the constant value from the schema when it is either a single value enum or has a const key. Otherwise
|
|
5
|
+
* throws an error.
|
|
6
|
+
*
|
|
7
|
+
* @param schema - The schema from which to obtain the constant value
|
|
8
|
+
* @returns - The constant value for the schema
|
|
9
|
+
* @throws - Error when the schema does not have a constant value
|
|
10
|
+
*/
|
|
11
|
+
export default function toConstant<S extends StrictRJSFSchema = RJSFSchema>(schema: S) {
|
|
12
|
+
if (ENUM_KEY in schema && Array.isArray(schema.enum) && schema.enum.length === 1) {
|
|
13
|
+
return schema.enum[0];
|
|
14
|
+
}
|
|
15
|
+
if (CONST_KEY in schema) {
|
|
16
|
+
return schema.const;
|
|
17
|
+
}
|
|
18
|
+
throw new Error('schema cannot be inferred as a constant');
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DateObject } from './types';
|
|
2
|
+
|
|
3
|
+
/** Returns a UTC date string for the given `dateObject`. If `time` is false, then the time portion of the string is
|
|
4
|
+
* removed.
|
|
5
|
+
*
|
|
6
|
+
* @param dateObject - The `DateObject` to convert to a date string
|
|
7
|
+
* @param [time=true] - Optional flag used to remove the time portion of the date string if false
|
|
8
|
+
* @returns - The UTC date string
|
|
9
|
+
*/
|
|
10
|
+
export default function toDateString(dateObject: DateObject, time = true) {
|
|
11
|
+
const { year, month, day, hour = 0, minute = 0, second = 0 } = dateObject;
|
|
12
|
+
const utcTime = Date.UTC(year, month - 1, day, hour, minute, second);
|
|
13
|
+
const datetime = new Date(utcTime).toJSON();
|
|
14
|
+
return time ? datetime : datetime.slice(0, 10);
|
|
15
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import isPlainObject from 'lodash/isPlainObject';
|
|
2
|
+
|
|
3
|
+
import { ERRORS_KEY } from './constants';
|
|
4
|
+
import { ErrorSchema, GenericObjectType, RJSFValidationError } from './types';
|
|
5
|
+
|
|
6
|
+
/** Converts an `errorSchema` into a list of `RJSFValidationErrors`
|
|
7
|
+
*
|
|
8
|
+
* @param errorSchema - The `ErrorSchema` instance to convert
|
|
9
|
+
* @param [fieldPath=[]] - The current field path, defaults to [] if not specified
|
|
10
|
+
* @returns - The list of `RJSFValidationErrors` extracted from the `errorSchema`
|
|
11
|
+
*/
|
|
12
|
+
export default function toErrorList<T = any>(
|
|
13
|
+
errorSchema?: ErrorSchema<T>,
|
|
14
|
+
fieldPath: string[] = []
|
|
15
|
+
): RJSFValidationError[] {
|
|
16
|
+
if (!errorSchema) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
let errorList: RJSFValidationError[] = [];
|
|
20
|
+
if (ERRORS_KEY in errorSchema) {
|
|
21
|
+
errorList = errorList.concat(
|
|
22
|
+
errorSchema[ERRORS_KEY]!.map((message: string) => {
|
|
23
|
+
const property = `.${fieldPath.join('.')}`;
|
|
24
|
+
return {
|
|
25
|
+
property,
|
|
26
|
+
message,
|
|
27
|
+
stack: `${property} ${message}`,
|
|
28
|
+
};
|
|
29
|
+
})
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return Object.keys(errorSchema).reduce((acc, key) => {
|
|
33
|
+
if (key !== ERRORS_KEY) {
|
|
34
|
+
const childSchema = (errorSchema as GenericObjectType)[key];
|
|
35
|
+
if (isPlainObject(childSchema)) {
|
|
36
|
+
acc = acc.concat(toErrorList(childSchema, [...fieldPath, key]));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return acc;
|
|
40
|
+
}, errorList);
|
|
41
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import toPath from 'lodash/toPath';
|
|
2
|
+
|
|
3
|
+
import { ErrorSchema, RJSFValidationError } from './types';
|
|
4
|
+
import ErrorSchemaBuilder from './ErrorSchemaBuilder';
|
|
5
|
+
|
|
6
|
+
/** Transforms a rjsf validation errors list:
|
|
7
|
+
* [
|
|
8
|
+
* {property: '.level1.level2[2].level3', message: 'err a'},
|
|
9
|
+
* {property: '.level1.level2[2].level3', message: 'err b'},
|
|
10
|
+
* {property: '.level1.level2[4].level3', message: 'err b'},
|
|
11
|
+
* ]
|
|
12
|
+
* Into an error tree:
|
|
13
|
+
* {
|
|
14
|
+
* level1: {
|
|
15
|
+
* level2: {
|
|
16
|
+
* 2: {level3: {errors: ['err a', 'err b']}},
|
|
17
|
+
* 4: {level3: {errors: ['err b']}},
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
* };
|
|
21
|
+
*
|
|
22
|
+
* @param errors - The list of RJSFValidationError objects
|
|
23
|
+
* @returns - The `ErrorSchema` built from the list of `RJSFValidationErrors`
|
|
24
|
+
*/
|
|
25
|
+
export default function toErrorSchema<T = any>(errors: RJSFValidationError[]): ErrorSchema<T> {
|
|
26
|
+
const builder = new ErrorSchemaBuilder<T>();
|
|
27
|
+
if (errors.length) {
|
|
28
|
+
errors.forEach((error) => {
|
|
29
|
+
const { property, message } = error;
|
|
30
|
+
// When the property is the root element, just use an empty array for the path
|
|
31
|
+
const path = property === '.' ? [] : toPath(property);
|
|
32
|
+
// If the property is at the root (.level1) then toPath creates
|
|
33
|
+
// an empty array element at the first index. Remove it.
|
|
34
|
+
if (path.length > 0 && path[0] === '') {
|
|
35
|
+
path.splice(0, 1);
|
|
36
|
+
}
|
|
37
|
+
if (message) {
|
|
38
|
+
builder.addErrors(message, path);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return builder.ErrorSchema;
|
|
43
|
+
}
|