UNPKG

@snups/rjsf-utils

Version:
1,500 lines (1,464 loc) 124 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 PATTERN_PROPERTIES_KEY = "patternProperties"; var PROPERTIES_KEY = "properties"; var READONLY_KEY = "readonly"; var REQUIRED_KEY = "required"; var SUBMIT_BTN_OPTIONS_KEY = "submitButtonOptions"; var REF_KEY = "$ref"; var SCHEMA_KEY = "$schema"; var DISCRIMINATOR_PATH = ["discriminator", "propertyName"]; var FORM_CONTEXT_NAME = "formContext"; var LOOKUP_MAP_NAME = "layoutGridLookupMap"; 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"; var JSON_SCHEMA_DRAFT_2019_09 = "https://json-schema.org/draft/2019-09/schema"; var JSON_SCHEMA_DRAFT_2020_12 = "https://json-schema.org/draft/2020-12/schema"; // src/getUiOptions.ts function getUiOptions(uiSchema = {}, globalOptions = {}) { if (!uiSchema) { return { ...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 || schema.patternProperties)) { 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/findFieldInSchema.ts import get8 from "lodash/get"; import has3 from "lodash/has"; // src/schema/findSelectedOptionInXxxOf.ts import get6 from "lodash/get"; import isEqual from "lodash/isEqual"; // src/schema/retrieveSchema.ts import get5 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/findSchemaDefinition.ts import jsonpointer from "jsonpointer"; import omit from "lodash/omit"; import isObject2 from "lodash/isObject"; import isEmpty from "lodash/isEmpty"; import UriResolver from "fast-uri"; import get from "lodash/get"; function findEmbeddedSchemaRecursive(schema, ref) { if (ID_KEY in schema && UriResolver.equal(schema[ID_KEY], ref)) { return schema; } for (const subSchema of Object.values(schema)) { if (Array.isArray(subSchema)) { for (const item of subSchema) { if (isObject2(item)) { const result = findEmbeddedSchemaRecursive(item, ref); if (result !== void 0) { return result; } } } } else if (isObject2(subSchema)) { const result = findEmbeddedSchemaRecursive(subSchema, ref); if (result !== void 0) { return result; } } } return void 0; } function makeAllReferencesAbsolute(schema, baseURI) { const currentURI = get(schema, ID_KEY, baseURI); if (REF_KEY in schema) { schema = { ...schema, [REF_KEY]: UriResolver.resolve(currentURI, schema[REF_KEY]) }; } for (const [key, subSchema] of Object.entries(schema)) { if (Array.isArray(subSchema)) { schema = { ...schema, [key]: subSchema.map((item) => isObject2(item) ? makeAllReferencesAbsolute(item, currentURI) : item) }; } else if (isObject2(subSchema)) { schema = { ...schema, [key]: makeAllReferencesAbsolute(subSchema, currentURI) }; } } return schema; } function splitKeyElementFromObject(key, object) { const value = object[key]; const remaining = omit(object, [key]); return [remaining, value]; } function findSchemaDefinitionRecursive($ref, rootSchema = {}, recurseList = [], baseURI = get(rootSchema, [ID_KEY])) { const ref = $ref || ""; let current = void 0; if (ref.startsWith("#")) { const decodedRef = decodeURIComponent(ref.substring(1)); if (baseURI === void 0 || ID_KEY in rootSchema && rootSchema[ID_KEY] === baseURI) { current = jsonpointer.get(rootSchema, decodedRef); } else if (rootSchema[SCHEMA_KEY] === JSON_SCHEMA_DRAFT_2020_12) { current = findEmbeddedSchemaRecursive(rootSchema, baseURI.replace(/\/$/, "")); if (current !== void 0) { current = jsonpointer.get(current, decodedRef); } } } else if (rootSchema[SCHEMA_KEY] === JSON_SCHEMA_DRAFT_2020_12) { const resolvedRef = baseURI ? UriResolver.resolve(baseURI, ref) : ref; const [refId, ...refAnchor] = resolvedRef.replace(/#\/?$/, "").split("#"); current = findEmbeddedSchemaRecursive(rootSchema, refId.replace(/\/$/, "")); if (current !== void 0) { baseURI = current[ID_KEY]; if (!isEmpty(refAnchor)) { current = jsonpointer.get(current, decodeURIComponent(refAnchor.join("#"))); } } } 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], baseURI); if (Object.keys(remaining).length > 0) { if (rootSchema[SCHEMA_KEY] === JSON_SCHEMA_DRAFT_2019_09 || rootSchema[SCHEMA_KEY] === JSON_SCHEMA_DRAFT_2020_12) { return { [ALL_OF_KEY]: [remaining, subSchema] }; } else { return { ...remaining, ...subSchema }; } } return subSchema; } return current; } function findSchemaDefinition($ref, rootSchema = {}, baseURI = get(rootSchema, [ID_KEY])) { const recurseList = []; return findSchemaDefinitionRecursive($ref, rootSchema, recurseList, baseURI); } // src/getDiscriminatorFieldFromSchema.ts import get2 from "lodash/get"; import isString from "lodash/isString"; function getDiscriminatorFieldFromSchema(schema) { let discriminator; const maybeString = get2(schema, DISCRIMINATOR_PATH); 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 || schema.patternProperties)) { 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/getFirstMatchingOption.ts import get4 from "lodash/get"; import has from "lodash/has"; import isNumber from "lodash/isNumber"; // src/getOptionMatchingSimpleDiscriminator.ts import get3 from "lodash/get"; function getOptionMatchingSimpleDiscriminator(formData, options, discriminatorField) { if (formData && discriminatorField) { const value = get3(formData, discriminatorField); if (value === void 0) { return; } for (let i = 0; i < options.length; i++) { const option = options[i]; const discriminator = get3(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/getFirstMatchingOption.ts function getFirstMatchingOption(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 = get4(formData, discriminatorField); const discriminator = get4(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/retrieveSchema.ts import isEmpty2 from "lodash/isEmpty"; 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 getMatchingPatternProperties(schema, key) { return Object.keys(schema.patternProperties).filter((pattern) => RegExp(pattern).test(key)).reduce( (obj, pattern) => { set(obj, [pattern], schema.patternProperties[pattern]); return obj; }, {} ); } 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, baseURI) { 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, baseURI); resolvedSchema = { ...refSchema, ...localSchema }; if (ID_KEY in resolvedSchema) { baseURI = resolvedSchema[ID_KEY]; } } 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, baseURI); 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, baseURI) }; } 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; } if (PATTERN_PROPERTIES_KEY in schema) { const matchingProperties = getMatchingPatternProperties(schema, key); if (!isEmpty2(matchingProperties)) { schema.properties[key] = retrieveSchema( validator, { [ALL_OF_KEY]: Object.values(matchingProperties) }, rootSchema, get5(formData, [key]), experimental_customMergeAllOf ); set(schema.properties, [key, ADDITIONAL_PROPERTY_FLAG], true); return; } } if (ADDITIONAL_PROPERTIES_KEY in schema && schema.additionalProperties !== false) { let additionalProperties = {}; if (typeof schema.additionalProperties !== "boolean") { if (REF_KEY in schema.additionalProperties) { additionalProperties = retrieveSchema( validator, { [REF_KEY]: get5(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(get5(formData, [key])) }; } } else { additionalProperties = { type: guessType(get5(formData, [key])) }; } schema.properties[key] = additionalProperties; set(schema.properties, [key, ADDITIONAL_PROPERTY_FLAG], true); } else { schema.properties[key] = { type: "null" }; 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, resolvers: { $defs: mergeAllOf.options.resolvers.definitions } }); if (withContainsSchemas.length) { resolvedSchema.allOf = withContainsSchemas; } } catch (e) { console.warn("could not merge subschemas in allOf:\n", e); const { allOf, ...resolvedSchemaWithoutAllOf } = resolvedSchema; return resolvedSchemaWithoutAllOf; } } if (PROPERTIES_KEY in resolvedSchema && PATTERN_PROPERTIES_KEY in resolvedSchema) { resolvedSchema = Object.keys(resolvedSchema.properties).reduce( (schema2, key) => { const matchingProperties = getMatchingPatternProperties(schema2, key); if (!isEmpty2(matchingProperties)) { schema2.properties[key] = retrieveSchema( validator, { allOf: [schema2.properties[key], ...Object.values(matchingProperties)] }, rootSchema, get5(rawFormData, [key]), experimental_customMergeAllOf ); } return schema2; }, { ...resolvedSchema, properties: { ...resolvedSchema.properties } } ); } const hasAdditionalProperties = PATTERN_PROPERTIES_KEY in resolvedSchema || 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 && get5(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/findSelectedOptionInXxxOf.ts function findSelectedOptionInXxxOf(validator, rootSchema, schema, fallbackField, xxx, formData = {}, experimental_customMergeAllOf) { if (Array.isArray(schema[xxx])) { const discriminator = getDiscriminatorFieldFromSchema(schema); const selectorField = discriminator || fallbackField; const xxxOfs = schema[xxx].map( (xxxOf) => retrieveSchema(validator, xxxOf, rootSchema, formData, experimental_customMergeAllOf) ); const data = get6(formData, selectorField); if (data !== void 0) { return xxxOfs.find((xxx2) => { return isEqual( get6(xxx2, [PROPERTIES_KEY, selectorField, DEFAULT_KEY], get6(xxx2, [PROPERTIES_KEY, selectorField, CONST_KEY])), data ); }); } } return void 0; } // src/schema/getFromSchema.ts import get7 from "lodash/get"; import has2 from "lodash/has"; import isEmpty3 from "lodash/isEmpty"; function getFromSchemaInternal(validator, rootSchema, schema, path, experimental_customMergeAllOf) { let fieldSchema = schema; if (has2(schema, REF_KEY)) { fieldSchema = retrieveSchema(validator, schema, rootSchema, void 0, experimental_customMergeAllOf); } if (isEmpty3(path)) { return fieldSchema; } const pathList = Array.isArray(path) ? path : path.split("."); const [part, ...nestedPath] = pathList; if (part && has2(fieldSchema, part)) { fieldSchema = get7(fieldSchema, part); return getFromSchemaInternal( validator, rootSchema, fieldSchema, nestedPath, experimental_customMergeAllOf ); } return void 0; } function getFromSchema(validator, rootSchema, schema, path, defaultValue, experimental_customMergeAllOf) { const result = getFromSchemaInternal(validator, rootSchema, schema, path, experimental_customMergeAllOf); if (result === void 0) { return defaultValue; } return result; } // src/schema/findFieldInSchema.ts var NOT_FOUND_SCHEMA = { title: "!@#$_UNKNOWN_$#@!" }; function findFieldInSchema(validator, rootSchema, schema, path, formData = {}, experimental_customMergeAllOf) { const pathList = Array.isArray(path) ? [...path] : path.split("."); let parentField = schema; const fieldName = pathList.pop(); if (pathList.length) { pathList.forEach((subPath) => { parentField = getFromSchema( validator, rootSchema, parentField, [PROPERTIES_KEY, subPath], {}, experimental_customMergeAllOf ); if (has3(parentField, ONE_OF_KEY)) { parentField = findSelectedOptionInXxxOf( validator, rootSchema, parentField, fieldName, ONE_OF_KEY, get8(formData, subPath), experimental_customMergeAllOf ); } else if (has3(parentField, ANY_OF_KEY)) { parentField = findSelectedOptionInXxxOf( validator, rootSchema, parentField, fieldName, ANY_OF_KEY, get8(formData, subPath), experimental_customMergeAllOf ); } }); } if (has3(parentField, ONE_OF_KEY)) { parentField = findSelectedOptionInXxxOf( validator, rootSchema, parentField, fieldName, ONE_OF_KEY, formData, experimental_customMergeAllOf ); } else if (has3(parentField, ANY_OF_KEY)) { parentField = findSelectedOptionInXxxOf( validator, rootSchema, parentField, fieldName, ANY_OF_KEY, formData, experimental_customMergeAllOf ); } let field = getFromSchema( validator, rootSchema, parentField, [PROPERTIES_KEY, fieldName], NOT_FOUND_SCHEMA, experimental_customMergeAllOf ); if (field === NOT_FOUND_SCHEMA) { field = void 0; } const requiredArray = getFromSchema( validator, rootSchema, parentField, REQUIRED_KEY, [], experimental_customMergeAllOf ); let isRequired; if (field && Array.isArray(requiredArray)) { isRequired = requiredArray.includes(fieldName); } return { field, isRequired }; } // src/schema/getDefaultFormState.ts import get12 from "lodash/get"; import isEmpty4 from "lodash/isEmpty"; // src/schema/getClosestMatchingOption.ts import get9 from "lodash/get"; import has4 from "lodash/has"; import isNumber2 from "lodash/isNumber"; import isObject3 from "lodash/isObject"; import isString2 from "lodash/isString"; import reduce from "lodash/reduce"; import times2 from "lodash/times"; 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 (isObject3(schema.properties)) { totalScore += reduce( schema.properties, (score, value, key) => { const formValue = get9(formData, key); if (typeof value === "boolean") { return score; } if (has4(value, REF_KEY)) { const newSchema = retrieveSchema( validator, value, rootSchema, formValue, experimental_customMergeAllOf ); return score + calculateIndexScore( validator, rootSchema, newSchema, formValue || {}, experimental_customMergeAllOf ); } if ((has4(value, ONE_OF_KEY) || has4(value, ANY_OF_KEY)) && formValue) { const key2 = has4(value, ONE_OF_KEY) ? ONE_OF_KEY : ANY_OF_KEY; const discriminator = getDiscriminatorFieldFromSchema(value); return score + getClosestMatchingOption( validator, rootSchema, formValue, get9(value, key2), -1, discriminator, experimental_customMergeAllOf ); } if (value.type === "object") { if (isObject3(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 get10 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 = get10(formData, key); const keyExistsInDefaults = isObject(defaults) && key in defaults; const keyExistsInFormData = key in formData; const keyDefault = get10(defaults, key) ?? {}; const defaultValueIsNestedObject = keyExistsInDefaults && Object.entries(keyDefault).some(([, v]) => isObject(v)); const keyDefaultIsObject = keyExistsInDefaults && isObject(get10(defaults, key)); const keyHasFormDataObject = keyExistsInFormData && isObject(keyValue); if (keyDefaultIsObject && keyHasFormDataObject && !defaultValueIsNestedObject) { acc2[key] = { ...get10(defaults, key), ...keyValue }; return acc2; } acc2[key] = mergeDefaultsWithFormData( get10(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 && (!(defaults === void 0) && 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/optionsList.ts import get11 from "lodash/get"; // 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) { if (schema.enum) { let enumNames; if (uiSchema) { const { enumNames: uiEnumNames } = getUiOptions(uiSchema); enumNames = uiEnumNames; } 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; } let selectorField = getDiscriminatorFieldFromSchema(schema); if (uiSchema) { const { optionsSchemaSelector = selectorField } = getUiOptions(uiSchema); selectorField = optionsSchemaSelector; } return altSchemas && altSchemas.map((aSchemaDef, index) => { const { title } = getUiOptions(altUiSchemas?.[index]); const aSchema = aSchemaDef; let value; let label = title; if (selectorField) { const innerSchema = get11(aSchema, [PROPERTIES_KEY, selectorField], {}); value = get11(innerSchema, DEFAULT_KEY, get11(innerSchema, CONST_KEY)); label = label || innerSchema?.title || aSchema.title || String(value); } else { value = toConstant(aSchema); label = label || 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 === true || isConst) { obj[key] = computedDefault; } else if (includeUndefinedValues === "excludeObjectChildren") { if (!isObject(computedDefault) || !isEmpty4(computedDefault)) { obj[key] = computedDefault; } } else if (emptyObjectFields !== "skipDefaults") { const isSelfOrParentRequired = isParentRequired === void 0 ? requiredFields.includes(key) : isParentRequired; if (isObject(computedDefault)) { if (emptyObjectFields === "skipEmptyDefaults") { if (!isEmpty4(computedDefault)) { obj[key] = computedDefault; } } else if ((!isEmpty4(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] && !schema[REF_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; } } e