UNPKG

@rjsf/utils

Version:
1,467 lines (1,435 loc) 111 kB
// src/isObject.ts function isObject(thing) { if (typeof thing !== "object" || thing === null) { return false; } if (typeof thing.lastModified === "number" && typeof File !== "undefined" && thing instanceof File) { return false; } if (typeof thing.getMonth === "function" && typeof Date !== "undefined" && thing instanceof Date) { return false; } return !Array.isArray(thing); } // src/allowAdditionalItems.ts function allowAdditionalItems(schema) { if (schema.additionalItems === true) { console.warn("additionalItems=true is currently not supported"); } return isObject(schema.additionalItems); } // src/asNumber.ts function asNumber(value) { if (value === "") { return void 0; } if (value === null) { return null; } if (/\.$/.test(value)) { return value; } if (/\.0$/.test(value)) { return value; } if (/\.\d*0$/.test(value)) { return value; } const n = Number(value); const valid = typeof n === "number" && !Number.isNaN(n); return valid ? n : value; } // src/constants.ts var ADDITIONAL_PROPERTY_FLAG = "__additional_property"; var ADDITIONAL_PROPERTIES_KEY = "additionalProperties"; var ALL_OF_KEY = "allOf"; var ANY_OF_KEY = "anyOf"; var CONST_KEY = "const"; var DEFAULT_KEY = "default"; var DEFINITIONS_KEY = "definitions"; var DEPENDENCIES_KEY = "dependencies"; var ENUM_KEY = "enum"; var ERRORS_KEY = "__errors"; var ID_KEY = "$id"; var IF_KEY = "if"; var ITEMS_KEY = "items"; var JUNK_OPTION_ID = "_$junk_option_schema_id$_"; var NAME_KEY = "$name"; var ONE_OF_KEY = "oneOf"; var PROPERTIES_KEY = "properties"; var REQUIRED_KEY = "required"; var SUBMIT_BTN_OPTIONS_KEY = "submitButtonOptions"; var REF_KEY = "$ref"; var RJSF_ADDITONAL_PROPERTIES_FLAG = "__rjsf_additionalProperties"; var RJSF_ADDITIONAL_PROPERTIES_FLAG = "__rjsf_additionalProperties"; var ROOT_SCHEMA_PREFIX = "__rjsf_rootSchema"; var UI_FIELD_KEY = "ui:field"; var UI_WIDGET_KEY = "ui:widget"; var UI_OPTIONS_KEY = "ui:options"; var UI_GLOBAL_OPTIONS_KEY = "ui:globalOptions"; // src/getUiOptions.ts function getUiOptions(uiSchema = {}, globalOptions = {}) { return Object.keys(uiSchema).filter((key) => key.indexOf("ui:") === 0).reduce( (options, key) => { const value = uiSchema[key]; if (key === UI_WIDGET_KEY && isObject(value)) { console.error("Setting options via ui:widget object is no longer supported, use ui:options instead"); return options; } if (key === UI_OPTIONS_KEY && isObject(value)) { return { ...options, ...value }; } return { ...options, [key.substring(3)]: value }; }, { ...globalOptions } ); } // src/canExpand.ts function canExpand(schema, uiSchema = {}, formData) { if (!schema.additionalProperties) { return false; } const { expandable = true } = getUiOptions(uiSchema); if (expandable === false) { return expandable; } if (schema.maxProperties !== void 0 && formData) { return Object.keys(formData).length < schema.maxProperties; } return true; } // src/createErrorHandler.ts import isPlainObject from "lodash/isPlainObject"; function createErrorHandler(formData) { const handler = { // We store the list of errors for this node in a property named __errors // to avoid name collision with a possible sub schema field named // 'errors' (see `utils.toErrorSchema`). [ERRORS_KEY]: [], addError(message) { this[ERRORS_KEY].push(message); } }; if (Array.isArray(formData)) { return formData.reduce((acc, value, key) => { return { ...acc, [key]: createErrorHandler(value) }; }, handler); } if (isPlainObject(formData)) { const formObject = formData; return Object.keys(formObject).reduce((acc, key) => { return { ...acc, [key]: createErrorHandler(formObject[key]) }; }, handler); } return handler; } // src/deepEquals.ts import isEqualWith from "lodash/isEqualWith"; function deepEquals(a, b) { return isEqualWith(a, b, (obj, other) => { if (typeof obj === "function" && typeof other === "function") { return true; } return void 0; }); } // src/schema/getDefaultFormState.ts import get7 from "lodash/get"; import isEmpty from "lodash/isEmpty"; // src/findSchemaDefinition.ts import jsonpointer from "jsonpointer"; import omit from "lodash/omit"; function splitKeyElementFromObject(key, object) { const value = object[key]; const remaining = omit(object, [key]); return [remaining, value]; } function findSchemaDefinitionRecursive($ref, rootSchema = {}, recurseList = []) { const ref = $ref || ""; let decodedRef; if (ref.startsWith("#")) { decodedRef = decodeURIComponent(ref.substring(1)); } else { throw new Error(`Could not find a definition for ${$ref}.`); } const current = jsonpointer.get(rootSchema, decodedRef); if (current === void 0) { throw new Error(`Could not find a definition for ${$ref}.`); } const nextRef = current[REF_KEY]; if (nextRef) { if (recurseList.includes(nextRef)) { if (recurseList.length === 1) { throw new Error(`Definition for ${$ref} is a circular reference`); } const [firstRef, ...restRefs] = recurseList; const circularPath = [...restRefs, ref, firstRef].join(" -> "); throw new Error(`Definition for ${firstRef} contains a circular reference through ${circularPath}`); } const [remaining, theRef] = splitKeyElementFromObject(REF_KEY, current); const subSchema = findSchemaDefinitionRecursive(theRef, rootSchema, [...recurseList, ref]); if (Object.keys(remaining).length > 0) { return { ...remaining, ...subSchema }; } return subSchema; } return current; } function findSchemaDefinition($ref, rootSchema = {}) { const recurseList = []; return findSchemaDefinitionRecursive($ref, rootSchema, recurseList); } // src/schema/getClosestMatchingOption.ts import get5 from "lodash/get"; import has2 from "lodash/has"; import isNumber2 from "lodash/isNumber"; import isObject2 from "lodash/isObject"; import isString2 from "lodash/isString"; import reduce from "lodash/reduce"; import times2 from "lodash/times"; // src/schema/getMatchingOption.ts import get2 from "lodash/get"; import has from "lodash/has"; import isNumber from "lodash/isNumber"; // src/getOptionMatchingSimpleDiscriminator.ts import get from "lodash/get"; function getOptionMatchingSimpleDiscriminator(formData, options, discriminatorField) { if (formData && discriminatorField) { const value = get(formData, discriminatorField); if (value === void 0) { return; } for (let i = 0; i < options.length; i++) { const option = options[i]; const discriminator = get(option, [PROPERTIES_KEY, discriminatorField], {}); if (discriminator.type === "object" || discriminator.type === "array") { continue; } if (discriminator.const === value) { return i; } if (discriminator.enum?.includes(value)) { return i; } } } return; } // src/schema/getMatchingOption.ts function getMatchingOption(validator, formData, options, rootSchema, discriminatorField) { if (formData === void 0) { return 0; } const simpleDiscriminatorMatch = getOptionMatchingSimpleDiscriminator(formData, options, discriminatorField); if (isNumber(simpleDiscriminatorMatch)) { return simpleDiscriminatorMatch; } for (let i = 0; i < options.length; i++) { const option = options[i]; if (discriminatorField && has(option, [PROPERTIES_KEY, discriminatorField])) { const value = get2(formData, discriminatorField); const discriminator = get2(option, [PROPERTIES_KEY, discriminatorField], {}); if (validator.isValid(discriminator, value, rootSchema)) { return i; } } else if (option[PROPERTIES_KEY]) { const requiresAnyOf = { anyOf: Object.keys(option[PROPERTIES_KEY]).map((key) => ({ required: [key] })) }; let augmentedSchema; if (option.anyOf) { const { ...shallowClone } = option; if (!shallowClone.allOf) { shallowClone.allOf = []; } else { shallowClone.allOf = shallowClone.allOf.slice(); } shallowClone.allOf.push(requiresAnyOf); augmentedSchema = shallowClone; } else { augmentedSchema = Object.assign({}, option, requiresAnyOf); } delete augmentedSchema.required; if (validator.isValid(augmentedSchema, formData, rootSchema)) { return i; } } else if (validator.isValid(option, formData, rootSchema)) { return i; } } return 0; } // src/schema/getFirstMatchingOption.ts function getFirstMatchingOption(validator, formData, options, rootSchema, discriminatorField) { return getMatchingOption(validator, formData, options, rootSchema, discriminatorField); } // src/schema/retrieveSchema.ts import get4 from "lodash/get"; import set from "lodash/set"; import times from "lodash/times"; import transform from "lodash/transform"; import merge from "lodash/merge"; import flattenDeep from "lodash/flattenDeep"; import uniq from "lodash/uniq"; import mergeAllOf from "json-schema-merge-allof"; // src/getDiscriminatorFieldFromSchema.ts import get3 from "lodash/get"; import isString from "lodash/isString"; function getDiscriminatorFieldFromSchema(schema) { let discriminator; const maybeString = get3(schema, "discriminator.propertyName", void 0); if (isString(maybeString)) { discriminator = maybeString; } else if (maybeString !== void 0) { console.warn(`Expecting discriminator to be a string, got "${typeof maybeString}" instead`); } return discriminator; } // src/guessType.ts function guessType(value) { if (Array.isArray(value)) { return "array"; } if (typeof value === "string") { return "string"; } if (value == null) { return "null"; } if (typeof value === "boolean") { return "boolean"; } if (!isNaN(value)) { return "number"; } if (typeof value === "object") { return "object"; } return "string"; } // src/mergeSchemas.ts import union from "lodash/union"; // src/getSchemaType.ts function getSchemaType(schema) { let { type } = schema; if (!type && schema.const) { return guessType(schema.const); } if (!type && schema.enum) { return "string"; } if (!type && (schema.properties || schema.additionalProperties)) { return "object"; } if (Array.isArray(type)) { if (type.length === 2 && type.includes("null")) { type = type.find((type2) => type2 !== "null"); } else { type = type[0]; } } return type; } // src/mergeSchemas.ts function mergeSchemas(obj1, obj2) { const acc = Object.assign({}, obj1); return Object.keys(obj2).reduce((acc2, key) => { const left = obj1 ? obj1[key] : {}, right = obj2[key]; if (obj1 && key in obj1 && isObject(right)) { acc2[key] = mergeSchemas(left, right); } else if (obj1 && obj2 && (getSchemaType(obj1) === "object" || getSchemaType(obj2) === "object") && key === REQUIRED_KEY && Array.isArray(left) && Array.isArray(right)) { acc2[key] = union(left, right); } else { acc2[key] = right; } return acc2; }, acc); } // src/schema/retrieveSchema.ts function retrieveSchema(validator, schema, rootSchema = {}, rawFormData, experimental_customMergeAllOf) { return retrieveSchemaInternal( validator, schema, rootSchema, rawFormData, void 0, void 0, experimental_customMergeAllOf )[0]; } function resolveCondition(validator, schema, rootSchema, expandAllBranches, recurseList, formData, experimental_customMergeAllOf) { const { if: expression, then, else: otherwise, ...resolvedSchemaLessConditional } = schema; const conditionValue = validator.isValid(expression, formData || {}, rootSchema); let resolvedSchemas = [resolvedSchemaLessConditional]; let schemas = []; if (expandAllBranches) { if (then && typeof then !== "boolean") { schemas = schemas.concat( retrieveSchemaInternal( validator, then, rootSchema, formData, expandAllBranches, recurseList, experimental_customMergeAllOf ) ); } if (otherwise && typeof otherwise !== "boolean") { schemas = schemas.concat( retrieveSchemaInternal( validator, otherwise, rootSchema, formData, expandAllBranches, recurseList, experimental_customMergeAllOf ) ); } } else { const conditionalSchema = conditionValue ? then : otherwise; if (conditionalSchema && typeof conditionalSchema !== "boolean") { schemas = schemas.concat( retrieveSchemaInternal( validator, conditionalSchema, rootSchema, formData, expandAllBranches, recurseList, experimental_customMergeAllOf ) ); } } if (schemas.length) { resolvedSchemas = schemas.map((s) => mergeSchemas(resolvedSchemaLessConditional, s)); } return resolvedSchemas.flatMap( (s) => retrieveSchemaInternal( validator, s, rootSchema, formData, expandAllBranches, recurseList, experimental_customMergeAllOf ) ); } function getAllPermutationsOfXxxOf(listOfLists) { const allPermutations = listOfLists.reduce( (permutations, list) => { if (list.length > 1) { return list.flatMap((element) => times(permutations.length, (i) => [...permutations[i]].concat(element))); } permutations.forEach((permutation) => permutation.push(list[0])); return permutations; }, [[]] // Start with an empty list ); return allPermutations; } function resolveSchema(validator, schema, rootSchema, expandAllBranches, recurseList, formData, experimental_customMergeAllOf) { const updatedSchemas = resolveReference( validator, schema, rootSchema, expandAllBranches, recurseList, formData ); if (updatedSchemas.length > 1 || updatedSchemas[0] !== schema) { return updatedSchemas; } if (DEPENDENCIES_KEY in schema) { const resolvedSchemas = resolveDependencies( validator, schema, rootSchema, expandAllBranches, recurseList, formData ); return resolvedSchemas.flatMap((s) => { return retrieveSchemaInternal( validator, s, rootSchema, formData, expandAllBranches, recurseList, experimental_customMergeAllOf ); }); } if (ALL_OF_KEY in schema && Array.isArray(schema.allOf)) { const allOfSchemaElements = schema.allOf.map( (allOfSubschema) => retrieveSchemaInternal( validator, allOfSubschema, rootSchema, formData, expandAllBranches, recurseList, experimental_customMergeAllOf ) ); const allPermutations = getAllPermutationsOfXxxOf(allOfSchemaElements); return allPermutations.map((permutation) => ({ ...schema, allOf: permutation })); } return [schema]; } function resolveReference(validator, schema, rootSchema, expandAllBranches, recurseList, formData, experimental_customMergeAllOf) { const updatedSchema = resolveAllReferences(schema, rootSchema, recurseList); if (updatedSchema !== schema) { return retrieveSchemaInternal( validator, updatedSchema, rootSchema, formData, expandAllBranches, recurseList, experimental_customMergeAllOf ); } return [schema]; } function resolveAllReferences(schema, rootSchema, recurseList) { if (!isObject(schema)) { return schema; } let resolvedSchema = schema; if (REF_KEY in resolvedSchema) { const { $ref, ...localSchema } = resolvedSchema; if (recurseList.includes($ref)) { return resolvedSchema; } recurseList.push($ref); const refSchema = findSchemaDefinition($ref, rootSchema); resolvedSchema = { ...refSchema, ...localSchema }; } if (PROPERTIES_KEY in resolvedSchema) { const childrenLists = []; const updatedProps = transform( resolvedSchema[PROPERTIES_KEY], (result, value, key) => { const childList = [...recurseList]; result[key] = resolveAllReferences(value, rootSchema, childList); childrenLists.push(childList); }, {} ); merge(recurseList, uniq(flattenDeep(childrenLists))); resolvedSchema = { ...resolvedSchema, [PROPERTIES_KEY]: updatedProps }; } if (ITEMS_KEY in resolvedSchema && !Array.isArray(resolvedSchema.items) && typeof resolvedSchema.items !== "boolean") { resolvedSchema = { ...resolvedSchema, items: resolveAllReferences(resolvedSchema.items, rootSchema, recurseList) }; } return deepEquals(schema, resolvedSchema) ? schema : resolvedSchema; } function stubExistingAdditionalProperties(validator, theSchema, rootSchema, aFormData, experimental_customMergeAllOf) { const schema = { ...theSchema, properties: { ...theSchema.properties } }; const formData = aFormData && isObject(aFormData) ? aFormData : {}; Object.keys(formData).forEach((key) => { if (key in schema.properties) { return; } let additionalProperties = {}; if (typeof schema.additionalProperties !== "boolean") { if (REF_KEY in schema.additionalProperties) { additionalProperties = retrieveSchema( validator, { $ref: get4(schema.additionalProperties, [REF_KEY]) }, rootSchema, formData, experimental_customMergeAllOf ); } else if ("type" in schema.additionalProperties) { additionalProperties = { ...schema.additionalProperties }; } else if (ANY_OF_KEY in schema.additionalProperties || ONE_OF_KEY in schema.additionalProperties) { additionalProperties = { type: "object", ...schema.additionalProperties }; } else { additionalProperties = { type: guessType(get4(formData, [key])) }; } } else { additionalProperties = { type: guessType(get4(formData, [key])) }; } schema.properties[key] = additionalProperties; set(schema.properties, [key, ADDITIONAL_PROPERTY_FLAG], true); }); return schema; } function retrieveSchemaInternal(validator, schema, rootSchema, rawFormData, expandAllBranches = false, recurseList = [], experimental_customMergeAllOf) { if (!isObject(schema)) { return [{}]; } const resolvedSchemas = resolveSchema( validator, schema, rootSchema, expandAllBranches, recurseList, rawFormData, experimental_customMergeAllOf ); return resolvedSchemas.flatMap((s) => { let resolvedSchema = s; if (IF_KEY in resolvedSchema) { return resolveCondition( validator, resolvedSchema, rootSchema, expandAllBranches, recurseList, rawFormData, experimental_customMergeAllOf ); } if (ALL_OF_KEY in resolvedSchema) { if (expandAllBranches) { const { allOf, ...restOfSchema } = resolvedSchema; return [...allOf, restOfSchema]; } try { const withContainsSchemas = []; const withoutContainsSchemas = []; resolvedSchema.allOf?.forEach((s2) => { if (typeof s2 === "object" && s2.contains) { withContainsSchemas.push(s2); } else { withoutContainsSchemas.push(s2); } }); if (withContainsSchemas.length) { resolvedSchema = { ...resolvedSchema, allOf: withoutContainsSchemas }; } resolvedSchema = experimental_customMergeAllOf ? experimental_customMergeAllOf(resolvedSchema) : mergeAllOf(resolvedSchema, { deep: false }); if (withContainsSchemas.length) { resolvedSchema.allOf = withContainsSchemas; } } catch (e) { console.warn("could not merge subschemas in allOf:\n", e); const { allOf, ...resolvedSchemaWithoutAllOf } = resolvedSchema; return resolvedSchemaWithoutAllOf; } } const hasAdditionalProperties = ADDITIONAL_PROPERTIES_KEY in resolvedSchema && resolvedSchema.additionalProperties !== false; if (hasAdditionalProperties) { return stubExistingAdditionalProperties( validator, resolvedSchema, rootSchema, rawFormData, experimental_customMergeAllOf ); } return resolvedSchema; }); } function resolveAnyOrOneOfSchemas(validator, schema, rootSchema, expandAllBranches, rawFormData) { let anyOrOneOf; const { oneOf, anyOf, ...remaining } = schema; if (Array.isArray(oneOf)) { anyOrOneOf = oneOf; } else if (Array.isArray(anyOf)) { anyOrOneOf = anyOf; } if (anyOrOneOf) { const formData = rawFormData === void 0 && expandAllBranches ? {} : rawFormData; const discriminator = getDiscriminatorFieldFromSchema(schema); anyOrOneOf = anyOrOneOf.map((s) => { return resolveAllReferences(s, rootSchema, []); }); const option = getFirstMatchingOption(validator, formData, anyOrOneOf, rootSchema, discriminator); if (expandAllBranches) { return anyOrOneOf.map((item) => mergeSchemas(remaining, item)); } schema = mergeSchemas(remaining, anyOrOneOf[option]); } return [schema]; } function resolveDependencies(validator, schema, rootSchema, expandAllBranches, recurseList, formData, experimental_customMergeAllOf) { const { dependencies, ...remainingSchema } = schema; const resolvedSchemas = resolveAnyOrOneOfSchemas( validator, remainingSchema, rootSchema, expandAllBranches, formData ); return resolvedSchemas.flatMap( (resolvedSchema) => processDependencies( validator, dependencies, resolvedSchema, rootSchema, expandAllBranches, recurseList, formData, experimental_customMergeAllOf ) ); } function processDependencies(validator, dependencies, resolvedSchema, rootSchema, expandAllBranches, recurseList, formData, experimental_customMergeAllOf) { let schemas = [resolvedSchema]; for (const dependencyKey in dependencies) { if (!expandAllBranches && get4(formData, [dependencyKey]) === void 0) { continue; } if (resolvedSchema.properties && !(dependencyKey in resolvedSchema.properties)) { continue; } const [remainingDependencies, dependencyValue] = splitKeyElementFromObject( dependencyKey, dependencies ); if (Array.isArray(dependencyValue)) { schemas[0] = withDependentProperties(resolvedSchema, dependencyValue); } else if (isObject(dependencyValue)) { schemas = withDependentSchema( validator, resolvedSchema, rootSchema, dependencyKey, dependencyValue, expandAllBranches, recurseList, formData, experimental_customMergeAllOf ); } return schemas.flatMap( (schema) => processDependencies( validator, remainingDependencies, schema, rootSchema, expandAllBranches, recurseList, formData, experimental_customMergeAllOf ) ); } return schemas; } function withDependentProperties(schema, additionallyRequired) { if (!additionallyRequired) { return schema; } const required = Array.isArray(schema.required) ? Array.from(/* @__PURE__ */ new Set([...schema.required, ...additionallyRequired])) : additionallyRequired; return { ...schema, required }; } function withDependentSchema(validator, schema, rootSchema, dependencyKey, dependencyValue, expandAllBranches, recurseList, formData, experimental_customMergeAllOf) { const dependentSchemas = retrieveSchemaInternal( validator, dependencyValue, rootSchema, formData, expandAllBranches, recurseList, experimental_customMergeAllOf ); return dependentSchemas.flatMap((dependent) => { const { oneOf, ...dependentSchema } = dependent; schema = mergeSchemas(schema, dependentSchema); if (oneOf === void 0) { return schema; } const resolvedOneOfs = oneOf.map((subschema) => { if (typeof subschema === "boolean" || !(REF_KEY in subschema)) { return [subschema]; } return resolveReference(validator, subschema, rootSchema, expandAllBranches, recurseList, formData); }); const allPermutations = getAllPermutationsOfXxxOf(resolvedOneOfs); return allPermutations.flatMap( (resolvedOneOf) => withExactlyOneSubschema( validator, schema, rootSchema, dependencyKey, resolvedOneOf, expandAllBranches, recurseList, formData, experimental_customMergeAllOf ) ); }); } function withExactlyOneSubschema(validator, schema, rootSchema, dependencyKey, oneOf, expandAllBranches, recurseList, formData, experimental_customMergeAllOf) { const validSubschemas = oneOf.filter((subschema) => { if (typeof subschema === "boolean" || !subschema || !subschema.properties) { return false; } const { [dependencyKey]: conditionPropertySchema } = subschema.properties; if (conditionPropertySchema) { const conditionSchema = { type: "object", properties: { [dependencyKey]: conditionPropertySchema } }; return validator.isValid(conditionSchema, formData, rootSchema) || expandAllBranches; } return false; }); if (!expandAllBranches && validSubschemas.length !== 1) { console.warn("ignoring oneOf in dependencies because there isn't exactly one subschema that is valid"); return [schema]; } return validSubschemas.flatMap((s) => { const subschema = s; const [dependentSubschema] = splitKeyElementFromObject(dependencyKey, subschema.properties); const dependentSchema = { ...subschema, properties: dependentSubschema }; const schemas = retrieveSchemaInternal( validator, dependentSchema, rootSchema, formData, expandAllBranches, recurseList, experimental_customMergeAllOf ); return schemas.map((s2) => mergeSchemas(schema, s2)); }); } // src/schema/getClosestMatchingOption.ts var JUNK_OPTION = { type: "object", $id: JUNK_OPTION_ID, properties: { __not_really_there__: { type: "number" } } }; function calculateIndexScore(validator, rootSchema, schema, formData, experimental_customMergeAllOf) { let totalScore = 0; if (schema) { if (isObject2(schema.properties)) { totalScore += reduce( schema.properties, (score, value, key) => { const formValue = get5(formData, key); if (typeof value === "boolean") { return score; } if (has2(value, REF_KEY)) { const newSchema = retrieveSchema( validator, value, rootSchema, formValue, experimental_customMergeAllOf ); return score + calculateIndexScore( validator, rootSchema, newSchema, formValue || {}, experimental_customMergeAllOf ); } if ((has2(value, ONE_OF_KEY) || has2(value, ANY_OF_KEY)) && formValue) { const key2 = has2(value, ONE_OF_KEY) ? ONE_OF_KEY : ANY_OF_KEY; const discriminator = getDiscriminatorFieldFromSchema(value); return score + getClosestMatchingOption( validator, rootSchema, formValue, get5(value, key2), -1, discriminator, experimental_customMergeAllOf ); } if (value.type === "object") { if (isObject2(formValue)) { score += 1; } return score + calculateIndexScore(validator, rootSchema, value, formValue, experimental_customMergeAllOf); } if (value.type === guessType(formValue)) { let newScore = score + 1; if (value.default) { newScore += formValue === value.default ? 1 : -1; } else if (value.const) { newScore += formValue === value.const ? 1 : -1; } return newScore; } return score; }, 0 ); } else if (isString2(schema.type) && schema.type === guessType(formData)) { totalScore += 1; } } return totalScore; } function getClosestMatchingOption(validator, rootSchema, formData, options, selectedOption = -1, discriminatorField, experimental_customMergeAllOf) { const resolvedOptions = options.map((option) => { return resolveAllReferences(option, rootSchema, []); }); const simpleDiscriminatorMatch = getOptionMatchingSimpleDiscriminator(formData, options, discriminatorField); if (isNumber2(simpleDiscriminatorMatch)) { return simpleDiscriminatorMatch; } const allValidIndexes = resolvedOptions.reduce((validList, option, index) => { const testOptions = [JUNK_OPTION, option]; const match = getFirstMatchingOption(validator, formData, testOptions, rootSchema, discriminatorField); if (match === 1) { validList.push(index); } return validList; }, []); if (allValidIndexes.length === 1) { return allValidIndexes[0]; } if (!allValidIndexes.length) { times2(resolvedOptions.length, (i) => allValidIndexes.push(i)); } const scoreCount = /* @__PURE__ */ new Set(); const { bestIndex } = allValidIndexes.reduce( (scoreData, index) => { const { bestScore } = scoreData; const option = resolvedOptions[index]; const score = calculateIndexScore(validator, rootSchema, option, formData, experimental_customMergeAllOf); scoreCount.add(score); if (score > bestScore) { return { bestIndex: index, bestScore: score }; } return scoreData; }, { bestIndex: selectedOption, bestScore: 0 } ); if (scoreCount.size === 1 && selectedOption >= 0) { return selectedOption; } return bestIndex; } // src/isFixedItems.ts function isFixedItems(schema) { return Array.isArray(schema.items) && schema.items.length > 0 && schema.items.every((item) => isObject(item)); } // src/mergeDefaultsWithFormData.ts import get6 from "lodash/get"; import isNil from "lodash/isNil"; function mergeDefaultsWithFormData(defaults, formData, mergeExtraArrayDefaults = false, defaultSupercedesUndefined = false, overrideFormDataWithDefaults = false) { if (Array.isArray(formData)) { const defaultsArray = Array.isArray(defaults) ? defaults : []; const overrideArray = overrideFormDataWithDefaults ? defaultsArray : formData; const overrideOppositeArray = overrideFormDataWithDefaults ? formData : defaultsArray; const mapped = overrideArray.map((value, idx) => { if (overrideOppositeArray[idx] !== void 0) { return mergeDefaultsWithFormData( defaultsArray[idx], formData[idx], mergeExtraArrayDefaults, defaultSupercedesUndefined, overrideFormDataWithDefaults ); } return value; }); if ((mergeExtraArrayDefaults || overrideFormDataWithDefaults) && mapped.length < overrideOppositeArray.length) { mapped.push(...overrideOppositeArray.slice(mapped.length)); } return mapped; } if (isObject(formData)) { const acc = Object.assign({}, defaults); return Object.keys(formData).reduce((acc2, key) => { const keyValue = get6(formData, key); const keyExistsInDefaults = isObject(defaults) && key in defaults; const keyExistsInFormData = key in formData; acc2[key] = mergeDefaultsWithFormData( defaults ? get6(defaults, key) : {}, keyValue, mergeExtraArrayDefaults, defaultSupercedesUndefined, // overrideFormDataWithDefaults can be true only when the key value exists in defaults // Or if the key value doesn't exist in formData overrideFormDataWithDefaults && (keyExistsInDefaults || !keyExistsInFormData) ); return acc2; }, acc); } if (defaultSupercedesUndefined && (!isNil(defaults) && isNil(formData) || typeof formData === "number" && isNaN(formData)) || overrideFormDataWithDefaults && !isNil(formData)) { return defaults; } return formData; } // src/mergeObjects.ts function mergeObjects(obj1, obj2, concatArrays = false) { return Object.keys(obj2).reduce((acc, key) => { const left = obj1 ? obj1[key] : {}, right = obj2[key]; if (obj1 && key in obj1 && isObject(right)) { acc[key] = mergeObjects(left, right, concatArrays); } else if (concatArrays && Array.isArray(left) && Array.isArray(right)) { let toMerge = right; if (concatArrays === "preventDuplicates") { toMerge = right.reduce((result, value) => { if (!left.includes(value)) { result.push(value); } return result; }, []); } acc[key] = left.concat(toMerge); } else { acc[key] = right; } return acc; }, Object.assign({}, obj1)); } // src/isConstant.ts function isConstant(schema) { return Array.isArray(schema.enum) && schema.enum.length === 1 || CONST_KEY in schema; } // src/schema/isSelect.ts function isSelect(validator, theSchema, rootSchema = {}, experimental_customMergeAllOf) { const schema = retrieveSchema(validator, theSchema, rootSchema, void 0, experimental_customMergeAllOf); const altSchemas = schema.oneOf || schema.anyOf; if (Array.isArray(schema.enum)) { return true; } if (Array.isArray(altSchemas)) { return altSchemas.every((altSchemas2) => typeof altSchemas2 !== "boolean" && isConstant(altSchemas2)); } return false; } // src/schema/isMultiSelect.ts function isMultiSelect(validator, schema, rootSchema, experimental_customMergeAllOf) { if (!schema.uniqueItems || !schema.items || typeof schema.items === "boolean") { return false; } return isSelect(validator, schema.items, rootSchema, experimental_customMergeAllOf); } // src/constIsAjvDataReference.ts import isString3 from "lodash/isString"; function constIsAjvDataReference(schema) { const schemaConst = schema[CONST_KEY]; const schemaType = getSchemaType(schema); return isObject(schemaConst) && isString3(schemaConst?.$data) && schemaType !== "object" && schemaType !== "array"; } // src/toConstant.ts function toConstant(schema) { if (ENUM_KEY in schema && Array.isArray(schema.enum) && schema.enum.length === 1) { return schema.enum[0]; } if (CONST_KEY in schema) { return schema.const; } throw new Error("schema cannot be inferred as a constant"); } // src/optionsList.ts function optionsList(schema, uiSchema) { const schemaWithEnumNames = schema; if (schema.enum) { let enumNames; if (uiSchema) { const { enumNames: uiEnumNames } = getUiOptions(uiSchema); enumNames = uiEnumNames; } if (!enumNames && schemaWithEnumNames.enumNames) { if (true) { console.warn( 'The "enumNames" property in the schema is deprecated and will be removed in a future major release. Use the "ui:enumNames" property in the uiSchema instead.' ); } enumNames = schemaWithEnumNames.enumNames; } return schema.enum.map((value, i) => { const label = enumNames?.[i] || String(value); return { label, value }; }); } let altSchemas = void 0; let altUiSchemas = void 0; if (schema.anyOf) { altSchemas = schema.anyOf; altUiSchemas = uiSchema?.anyOf; } else if (schema.oneOf) { altSchemas = schema.oneOf; altUiSchemas = uiSchema?.oneOf; } return altSchemas && altSchemas.map((aSchemaDef, index) => { const { title } = getUiOptions(altUiSchemas?.[index]); const aSchema = aSchemaDef; const value = toConstant(aSchema); const label = title || aSchema.title || String(value); return { schema: aSchema, label, value }; }); } // src/schema/getDefaultFormState.ts var PRIMITIVE_TYPES = ["string", "number", "integer", "boolean", "null"]; function getInnerSchemaForArrayItem(schema, additionalItems = 0 /* Ignore */, idx = -1) { if (idx >= 0) { if (Array.isArray(schema.items) && idx < schema.items.length) { const item = schema.items[idx]; if (typeof item !== "boolean") { return item; } } } else if (schema.items && !Array.isArray(schema.items) && typeof schema.items !== "boolean") { return schema.items; } if (additionalItems !== 0 /* Ignore */ && isObject(schema.additionalItems)) { return schema.additionalItems; } return {}; } function maybeAddDefaultToObject(obj, key, computedDefault, includeUndefinedValues, isParentRequired, requiredFields = [], experimental_defaultFormStateBehavior = {}, isConst = false) { const { emptyObjectFields = "populateAllDefaults" } = experimental_defaultFormStateBehavior; if (includeUndefinedValues || isConst) { obj[key] = computedDefault; } else if (emptyObjectFields !== "skipDefaults") { const isSelfOrParentRequired = isParentRequired === void 0 ? requiredFields.includes(key) : isParentRequired; if (isObject(computedDefault)) { if (emptyObjectFields === "skipEmptyDefaults") { if (!isEmpty(computedDefault)) { obj[key] = computedDefault; } } else if ((!isEmpty(computedDefault) || requiredFields.includes(key)) && (isSelfOrParentRequired || emptyObjectFields !== "populateRequiredDefaults")) { obj[key] = computedDefault; } } else if ( // Store computedDefault if it's a defined primitive (e.g., true) and satisfies certain conditions // Condition 1: computedDefault is not undefined // Condition 2: If emptyObjectFields is 'populateAllDefaults' or 'skipEmptyDefaults) // Or if isSelfOrParentRequired is 'true' and the key is a required field computedDefault !== void 0 && (emptyObjectFields === "populateAllDefaults" || emptyObjectFields === "skipEmptyDefaults" || isSelfOrParentRequired && requiredFields.includes(key)) ) { obj[key] = computedDefault; } } } function computeDefaults(validator, rawSchema, computeDefaultsProps = {}) { const { parentDefaults, rawFormData, rootSchema = {}, includeUndefinedValues = false, _recurseList = [], experimental_defaultFormStateBehavior = void 0, experimental_customMergeAllOf = void 0, required, shouldMergeDefaultsIntoFormData = false } = computeDefaultsProps; let formData = isObject(rawFormData) ? rawFormData : {}; const schema = isObject(rawSchema) ? rawSchema : {}; let defaults = parentDefaults; let schemaToCompute = null; let experimental_dfsb_to_compute = experimental_defaultFormStateBehavior; let updatedRecurseList = _recurseList; if (schema[CONST_KEY] !== void 0 && experimental_defaultFormStateBehavior?.constAsDefaults !== "never" && !constIsAjvDataReference(schema)) { defaults = schema[CONST_KEY]; } else if (isObject(defaults) && isObject(schema.default)) { defaults = mergeObjects(defaults, schema.default); } else if (DEFAULT_KEY in schema && !schema[ANY_OF_KEY] && !schema[ONE_OF_KEY]) { defaults = schema.default; } else if (REF_KEY in schema) { const refName = schema[REF_KEY]; if (!_recurseList.includes(refName)) { updatedRecurseList = _recurseList.concat(refName); schemaToCompute = findSchemaDefinition(refName, rootSchema); } if (schemaToCompute && !defaults) { defaults = schema.default; } if (shouldMergeDefaultsIntoFormData && schemaToCompute && !isObject(rawFormData)) { formData = rawFormData; } } else if (DEPENDENCIES_KEY in schema) { const defaultFormData = { ...getDefaultBasedOnSchemaType(validator, schema, computeDefaultsProps, defaults), ...formData }; const resolvedSchema = resolveDependencies( validator, schema, rootSchema, false, [], defaultFormData, experimental_customMergeAllOf ); schemaToCompute = resolvedSchema[0]; } else if (isFixedItems(schema)) { defaults = schema.items.map( (itemSchema, idx) => computeDefaults(validator, itemSchema, { rootSchema, includeUndefinedValues, _recurseList, experimental_defaultFormStateBehavior, experimental_customMergeAllOf, parentDefaults: Array.isArray(parentDefaults) ? parentDefaults[idx] : void 0, rawFormData: formData, required, shouldMergeDefaultsIntoFormData }) ); } else if (ONE_OF_KEY in schema) { const { oneOf, ...remaining } = schema; if (oneOf.length === 0) { return void 0; } const discriminator = getDiscriminatorFieldFromSchema(schema); const { type = "null" } = remaining; if (!Array.isArray(type) && PRIMITIVE_TYPES.includes(type) && experimental_dfsb_to_compute?.constAsDefaults === "skipOneOf") { experimental_dfsb_to_compute = { ...experimental_dfsb_to_compute, constAsDefaults: "never" }; } schemaToCompute = oneOf[getClosestMatchingOption( validator, rootSchema, rawFormData ?? schema.default, oneOf, 0, discriminator, experimental_customMergeAllOf )]; schemaToCompute = mergeSchemas(remaining, schemaToCompute); } else if (ANY_OF_KEY in schema) { const { anyOf, ...remaining } = schema; if (anyOf.length === 0) { return void 0; } const discriminator = getDiscriminatorFieldFromSchema(schema); schemaToCompute = anyOf[getClosestMatchingOption( validator, rootSchema, rawFormData ?? schema.default, anyOf, 0, discriminator, experimental_customMergeAllOf )]; schemaToCompute = mergeSchemas(remaining, schemaToCompute); } if (schemaToCompute) { return computeDefaults(validator, schemaToCompute, { rootSchema, includeUndefinedValues, _recurseList: updatedRecurseList, experimental_defaultFormStateBehavior: experimental_dfsb_to_compute, experimental_customMergeAllOf, parentDefaults: defaults, rawFormData: rawFormData ?? formData, required, shouldMergeDefaultsIntoFormData }); } if (defaults === void 0) { defaults = schema.default; } const defaultBasedOnSchemaType = getDefaultBasedOnSchemaType(validator, schema, computeDefaultsProps, defaults); let defaultsWithFormData = defaultBasedOnSchemaType ?? defaults; if (shouldMergeDefaultsIntoFormData) { const { arrayMinItems = {} } = experimental_defaultFormStateBehavior || {}; const { mergeExtraDefaults } = arrayMinItems; const matchingFormData = ensureFormDataMatchingSchema( validator, schema, rootSchema, rawFormData, experimental_defaultFormStateBehavior, experimental_customMergeAllOf ); if (!isObject(rawFormData) || ALL_OF_KEY in schema) { defaultsWithFormData = mergeDefaultsWithFormData( defaultsWithFormData, matchingFormData, mergeExtraDefaults, true ); } } return defaultsWithFormData; } function ensureFormDataMatchingSchema(validator, schema, rootSchema, formData, experimental_defaultFormStateBehavior, experimental_customMergeAllOf) { const isSelectField = !isConstant(schema) && isSelect(validator, schema, rootSchema, experimental_customMergeAllOf); let validFormData = formData; if (isSelectField) { const getOptionsList = optionsList(schema); const isValid = getOptionsList?.some((option) => deepEquals(option.value, formData)); validFormData = isValid ? formData : void 0; } const constTakesPrecedence = schema[CONST_KEY] && experimental_defaultFormStateBehavior?.constAsDefaults === "always"; if (constTakesPrecedence) { validFormData = schema.const; } return validFormData; } function getObjectDefaults(validator, rawSchema, { rawFormData, rootSchema = {}, includeUndefinedValues = false, _recurseList = [], experimental_defaultFormStateBehavior = void 0, experimental_customMergeAllOf = void 0, required, shouldMergeDefaultsIntoFormData } = {}, defaults) { { const formData = isObject(rawFormData) ? rawFormData : {}; const schema = rawSchema; const retrievedSchema = experimental_defaultFormStateBehavior?.allOf === "populateDefaults" && ALL_OF_KEY in schema ? retrieveSchema(validator, schema, rootSchema, formData, experimental_customMergeAllOf) : schema; const parentConst = retrievedSchema[CONST_KEY]; const objectDefaults = Object.keys(retrievedSchema.properties || {}).reduce( (acc, key) => { const propertySchema = get7(retrievedSchema, [PROPERTIES_KEY, key]); const hasParentConst = isObject(parentConst) && parentConst[key] !== void 0; const hasConst = (isObject(propertySchema) && CONST_KEY in propertySchema || hasParentConst) && experimental_defaultFormStateBehavior?.constAsDefaults !== "never" && !constIsAjvDataReference(propertySchema); const computedDefault = computeDefaults(validator, propertySchema, { rootSchema, _recurseList, experimental_defaultFormStateBehavior, experimental_customMergeAllOf, includeUndefinedValues: includeUndefinedValues === true, parentDefaults: get7(defaults, [key]), rawFormData: get7(formData, [key]), required: retrievedSchema.required?.includes(key), shouldMergeDefaultsIntoFormData }); maybeAddDefaultToObject( acc, key, computedDefault, includeUndefinedValues, required, retrievedSchema.required, experimental_defaultFormStateBehavior, hasConst ); return acc; }, {} ); if (retrievedSchema.additionalProperties) { const additionalPropertiesSchema = isObject(retrievedSchema.additionalProperties) ? retrievedSchema.additionalProperties : {}; const keys2 = /* @__PURE__ */ new Set(); if (isObject(defaults)) { Object.keys(defaults).filter((key) => !retrievedSchema.properties || !retrievedSchema.properties[key]).forEach((key) => keys2.add(key)); } const formDataRequired = []; Object.keys(formData).filter((key) => !retrievedSchema.properties || !retrievedSchema.properties[key]).forEach((key) => { keys2.add(key); formDataRequired.push(key); }); keys2.forEach((key) => { const computedDefault = computeDefaults(validator, additionalPropertiesSchema, { rootSchema, _recurseList, experimental_defaultFormStateBehavior, experimental_customMergeAllOf, includeUndefinedValues: includeUndefinedValues === true, parentDefaults: get7(defaults, [key]), rawFormData: get7(formData, [key]), required: retrievedSchema.required?.includes(key), shouldMergeDefaultsIntoFormData }); maybeAddDefaultToObject( objectDefaults, key, computedDefault, includeUndefinedValues, required, formDataRequired ); }); } return objectDefaults; } } function getArrayDefaults(validator, rawSchema, { rawFormData, rootSchema = {}, _recurseList = [], experimental_defaultFormStateBehavior = void 0, experimental_customMergeAllOf = void 0, required, shouldMergeDefaultsIntoFormData } = {}, defaults) { const schema = rawSchema; const arrayMinItemsStateBehavior = experimental_defaultFormStateBehavior?.arrayMinItems ?? {}; const { populate: arrayMinItemsPopulate, mergeExtraDefaults: arrayMergeExtraDefaults } = arrayMinItemsStateBehavior; const neverPopulate = arrayMinItemsPopulate === "never"; const ignoreMinItemsFlagSet = arrayMinItemsPopulate === "requiredOnly"; const isPopulateAll = arrayMinItemsPopulate === "all" || !neverPopulate && !ignoreMinItemsFlagSet; const computeSkipPopulate = arrayMinItemsStateBehavior?.computeSkipPopulate ?? (() => false); const isSkipEmptyDefaults = experimental_defaultFormStateBehavior?.emptyObjectFields === "skipEmptyDefaults"; const emptyDefault = isSkipEmptyDefaults ? void 0 : []; if (Array.isArray(defaults)) { defaults = defaults.map((item, idx) => { const schemaItem = getInnerSchemaForArrayItem(schema, 2 /* Fallback */, idx); return computeDefaults(validator, schemaItem, { rootSchema, _recurseList, experimental_defaultFormStateBehavior, experimental_customMergeAllOf, parentDefaults: item, required, shouldMergeDefaultsIntoFormData }); }); } if (Array.isArray(rawFormData)) { const schemaItem = getInnerSchemaForArrayItem(schema); if (neverPopulate) { defaults = rawFormData; } else { const itemDefaults = rawFormData.map((item, idx) => { return computeDefaults(validator, schemaItem, { rootSchema, _recurseList, experimental_defaultFormStateBehavior, experimental_customMergeAllOf, rawFormData: item, parentDefaults: get7(defaults, [idx]), required, shouldMergeDefaultsIntoFormData }); }); const mergeExtraDefaults = (ignoreMinItemsFlagSet && required || isPopulateAll) && arrayMergeExtraDefaults; defaults = mergeDefaultsWithFormData(defaults, itemDefaults, mergeExtraDefaults); } } const hasConst = isObject(schema) && CONST_KEY in schema && experimental_defaultFormStateBehavior?.constAsDefaults !== "never"; if (hasConst === false) { if (neverPopulate) { return defaults ?? emptyDefault; } if (ignoreMinItemsFlagSet && !required) { return defaults ? defaults : void