UNPKG

@greguintow/rjsf-utils

Version:
1,522 lines (1,475 loc) 119 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 READONLY_KEY = "readonly"; var REQUIRED_KEY = "required"; var SUBMIT_BTN_OPTIONS_KEY = "submitButtonOptions"; var REF_KEY = "$ref"; var DISCRIMINATOR_PATH = ["discriminator", "propertyName"]; var FORM_CONTEXT_NAME = "formContext"; var LOOKUP_MAP_NAME = "layoutGridLookupMap"; 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/findFieldInSchema.ts import get7 from "lodash/get"; import has3 from "lodash/has"; // src/schema/findSelectedOptionInXxxOf.ts import get5 from "lodash/get"; import isEqual from "lodash/isEqual"; // 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/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/getDiscriminatorFieldFromSchema.ts import get from "lodash/get"; import isString from "lodash/isString"; function getDiscriminatorFieldFromSchema(schema) { let discriminator; const maybeString = get(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)) { 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/getMatchingOption.ts import get3 from "lodash/get"; import has from "lodash/has"; import isNumber from "lodash/isNumber"; // src/getOptionMatchingSimpleDiscriminator.ts import get2 from "lodash/get"; function getOptionMatchingSimpleDiscriminator(formData, options, discriminatorField) { if (formData && discriminatorField) { const value = get2(formData, discriminatorField); if (value === void 0) { return; } for (let i = 0; i < options.length; i++) { const option = options[i]; const discriminator = get2(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 = get3(formData, discriminatorField); const discriminator = get3(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 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/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 = get5(formData, selectorField); if (data !== void 0) { return xxxOfs.find((xxx2) => { return isEqual( get5(xxx2, [PROPERTIES_KEY, selectorField, DEFAULT_KEY], get5(xxx2, [PROPERTIES_KEY, selectorField, CONST_KEY])), data ); }); } } return void 0; } // src/schema/getFromSchema.ts import get6 from "lodash/get"; import has2 from "lodash/has"; import isEmpty 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 (isEmpty(path)) { return fieldSchema; } const pathList = Array.isArray(path) ? path : path.split("."); const [part, ...nestedPath] = pathList; if (part && has2(fieldSchema, part)) { fieldSchema = get6(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, get7(formData, subPath), experimental_customMergeAllOf ); } else if (has3(parentField, ANY_OF_KEY)) { parentField = findSelectedOptionInXxxOf( validator, rootSchema, parentField, fieldName, ANY_OF_KEY, get7(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 get17 from "lodash/get"; import isEmpty3 from "lodash/isEmpty"; // src/schema/getClosestMatchingOption.ts import get8 from "lodash/get"; import has4 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"; 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 = get8(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, get8(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 get9 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 = get9(formData, key); const keyExistsInDefaults = isObject(defaults) && key in defaults; const keyExistsInFormData = key in formData; acc2[key] = mergeDefaultsWithFormData( defaults ? get9(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/dataURItoBlob.ts function dataURItoBlob(dataURILike) { if (dataURILike.indexOf("data:") === -1) { throw new Error("File is invalid: URI must be a dataURI"); } const dataURI = dataURILike.slice(5); const splitted = dataURI.split(";base64,"); if (splitted.length !== 2) { throw new Error("File is invalid: dataURI must be base64"); } const [media, base64] = splitted; const [mime, ...mediaparams] = media.split(";"); const type = mime || ""; const name = decodeURI( // parse the parameters into key-value pairs, find a key, and extract a value // if no key is found, then the name is unknown mediaparams.map((param) => param.split("=")).find(([key]) => key === "name")?.[1] || "unknown" ); try { const binary = atob(base64); const array = new Array(binary.length); for (let i = 0; i < binary.length; i++) { array[i] = binary.charCodeAt(i); } const blob = new window.Blob([new Uint8Array(array)], { type }); return { blob, name }; } catch (error) { throw new Error("File is invalid: " + error.message); } } // src/pad.ts function pad(num, width) { let s = String(num); while (s.length < width) { s = "0" + s; } return s; } // src/dateRangeOptions.ts function dateRangeOptions(start, stop) { if (start <= 0 && stop <= 0) { start = (/* @__PURE__ */ new Date()).getFullYear() + start; stop = (/* @__PURE__ */ new Date()).getFullYear() + stop; } else if (start < 0 || stop < 0) { throw new Error(`Both start (${start}) and stop (${stop}) must both be <= 0 or > 0, got one of each`); } if (start > stop) { return dateRangeOptions(stop, start).reverse(); } const options = []; for (let i = start; i <= stop; i++) { options.push({ value: i, label: pad(i, 2) }); } return options; } // src/replaceStringParameters.ts function replaceStringParameters(inputString, params) { let output = inputString; if (Array.isArray(params)) { const parts = output.split(/(%\d)/); params.forEach((param, index) => { const partIndex = parts.findIndex((part) => part === `%${index + 1}`); if (partIndex >= 0) { parts[partIndex] = param; } }); output = parts.join(""); } return output; } // src/englishStringTranslator.ts function englishStringTranslator(stringToTranslate, params) { return replaceStringParameters(stringToTranslate, params); } // src/enumOptionsValueForIndex.ts function enumOptionsValueForIndex(valueIndex, allEnumOptions = [], emptyValue) { if (Array.isArray(valueIndex)) { return valueIndex.map((index2) => enumOptionsValueForIndex(index2, allEnumOptions)).filter((val) => val !== emptyValue); } const index = valueIndex === "" || valueIndex === null ? -1 : Number(valueIndex); const option = allEnumOptions[index]; return option ? option.value : emptyValue; } // src/enumOptionsDeselectValue.ts function enumOptionsDeselectValue(valueIndex, selected, allEnumOptions = []) { const value = enumOptionsValueForIndex(valueIndex, allEnumOptions); if (Array.isArray(selected)) { return selected.filter((v) => !deepEquals(v, value)); } return deepEquals(value, selected) ? void 0 : selected; } // src/enumOptionsIsSelected.ts function enumOptionsIsSelected(value, selected) { if (Array.isArray(selected)) { return selected.some((sel) => deepEquals(sel, value)); } return deepEquals(selected, value); } // src/enumOptionsIndexForValue.ts function enumOptionsIndexForValue(value, allEnumOptions = [], multiple = false) { const selectedIndexes = allEnumOptions.map((opt, index) => enumOptionsIsSelected(opt.value, value) ? String(index) : void 0).filter((opt) => typeof opt !== "undefined"); if (!multiple) { return selectedIndexes[0]; } return selectedIndexes; } // src/enumOptionsSelectValue.ts import isNil2 from "lodash/isNil"; function enumOptionsSelectValue(valueIndex, selected, allEnumOptions = []) { const value = enumOptionsValueForIndex(valueIndex, allEnumOptions); if (!isNil2(value)) { const index = allEnumOptions.findIndex((opt) => value === opt.value); const all = allEnumOptions.map(({ value: val }) => val); const updated = selected.slice(0, index).concat(value, selected.slice(index)); return updated.sort((a, b) => Number(all.indexOf(a) > all.indexOf(b))); } return selected; } // src/ErrorSchemaBuilder.ts import cloneDeep from "lodash/cloneDeep"; import get10 from "lodash/get"; import set2 from "lodash/set"; import setWith from "lodash/setWith"; var ErrorSchemaBuilder = class { /** Construct an `ErrorSchemaBuilder` with an optional initial set of errors in an `ErrorSchema`. * * @param [initialSchema] - The optional set of initial errors, that will be cloned into the class */ constructor(initialSchema) { /** The error schema being built * * @private */ this.errorSchema = {}; this.resetAllErrors(initialSchema); } /** Returns the `ErrorSchema` that has been updated by the methods of the `ErrorSchemaBuilder` */ get ErrorSchema() { return this.errorSchema; } /** Will get an existing `ErrorSchema` at the specified `pathOfError` or create and return one. * * @param [pathOfError] - The optional path into the `ErrorSchema` at which to add the error(s) * @returns - The error block for the given `pathOfError` or the root if not provided * @private */ getOrCreateErrorBlock(pathOfError) { const hasPath = Array.isArray(pathOfError) && pathOfError.length > 0 || typeof pathOfError === "string"; let errorBlock = hasPath ? get10(this.errorSchema, pathOfError) : this.errorSchema; if (!errorBlock && pathOfError) { errorBlock = {}; setWith(this.errorSchema, pathOfError, errorBlock, Object); } return errorBlock; } /** Resets all errors in the `ErrorSchemaBuilder` back to the `initialSchema` if provided, otherwise an empty set. * * @param [initialSchema] - The optional set of initial errors, that will be cloned into the class * @returns - The `ErrorSchemaBuilder` object for chaining purposes */ resetAllErrors(initialSchema) { this.errorSchema = initialSchema ? cloneDeep(initialSchema) : {}; return this; } /** Adds the `errorOrList` to the list of errors in the `ErrorSchema` at either the root level or the location within * the schema described by the `pathOfError`. For more information about how to specify the path see the * [eslint lodash plugin docs](https://github.com/wix/eslint-plugin-lodash/blob/master/docs/rules/path-style.md). * * @param errorOrList - The error or list of errors to add into the `ErrorSchema` * @param [pathOfError] - The optional path into the `ErrorSchema` at which to add the error(s) * @returns - The `ErrorSchemaBuilder` object for chaining purposes */ addErrors(errorOrList, pathOfError) { const errorBlock = this.getOrCreateErrorBlock(pathOfError); let errorsList = get10(errorBlock, ERRORS_KEY); if (!Array.isArray(errorsList)) { errorsList = []; errorBlock[ERRORS_KEY] = errorsList; } if (Array.isArray(errorOrList)) { set2(errorBlock, ERRORS_KEY, [.../* @__PURE__ */ new Set([...errorsList, ...errorOrList])]); } else { set2(errorBlock, ERRORS_KEY, [.../* @__PURE__ */ new Set([...errorsList, errorOrList])]); } return this; } /** Sets/replaces the `errorOrList` as the error(s) in the `ErrorSchema` at either the root level or the location * within the schema described by the `pathOfError`. For more information about how to specify the path see the * [eslint lodash plugin docs](https://github.com/wix/eslint-plugin-lodash/blob/master/docs/rules/path-style.md). * * @param errorOrList - The error or list of errors to set into the `ErrorSchema` * @param [pathOfError] - The optional path into the `ErrorSchema` at which to set the error(s) * @returns - The `ErrorSchemaBuilder` object for chaining purposes */ setErrors(errorOrList, pathOfError) { const errorBlock = this.getOrCreateErrorBlock(pathOfError); const listToAdd = Array.isArray(errorOrList) ? [.../* @__PURE__ */ new Set([...errorOrList])] : [errorOrList]; set2(errorBlock, ERRORS_KEY, listToAdd); return this; } /** Clears the error(s) in the `ErrorSchema` at either the root level or the location within the schema described by * the `pathOfError`. For more information about how to specify the path see the * [eslint lodash plugin docs](https://github.com/wix/eslint-plugin-lodash/blob/master/docs/rules/path-style.md). * * @param [pathOfError] - The optional path into the `ErrorSchema` at which to clear the error(s) * @returns - The `ErrorSchemaBuilder` object for chaining purposes */ clearErrors(pathOfError) { const errorBlock = this.getOrCreateErrorBlock(pathOfError); set2(errorBlock, ERRORS_KEY, []); return this; } }; // src/getDateElementProps.ts function getDateElementProps(date, time, yearRange = [1900, (/* @__PURE__ */ new Date()).getFullYear() + 2], format = "YMD") { const { day, month, year, hour, minute, second } = date; const dayObj = { type: "day", range: [1, 31], value: day }; const monthObj = { type: "month", range: [1, 12], value: month }; const yearObj = { type: "year", range: yearRange, value: year }; const dateElementProp = []; switch (format) { case "MDY": dateElementProp.push(monthObj, dayObj, yearObj); break; case "DMY": dateElementProp.push(dayObj, monthObj, yearObj); break; case "YMD": default: dateElementProp.push(yearObj, monthObj, dayObj); } if (time) { dateElementProp.push( { type: "hour", range: [0, 23], value: hour }, { type: "minute", range: [0, 59], value: minute }, { type: "second", range: [0, 59], value: second } ); } return dateElementProp; } // src/rangeSpec.ts function rangeSpec(schema) { const spec = {}; if (schema.multipleOf) { spec.step = schema.multipleOf; } if (schema.minimum || schema.minimum === 0) { spec.min = schema.minimum; } if (schema.maximum || schema.maximum === 0) { spec.max = schema.maximum; } return spec; } // src/getInputProps.ts function getInputProps(schema, defaultType, options = {}, autoDefaultStepAny = true) { const inputProps = { type: defaultType || "text", ...rangeSpec(schema) }; if (options.inputType) { inputProps.type = options.inputType; } else if (!defaultType) { if (schema.type === "number") { inputProps.type = "number"; if (autoDefaultStepAny && inputProps.step === void 0) { inputProps.step = "any"; } } else if (schema.type === "integer") { inputProps.type = "number"; if (inputProps.step === void 0) { inputProps.step = 1; } } } if (options.autocomplete) { inputProps.autoComplete = options.autocomplete; } if (options.accept) { inputProps.accept = options.accept; } return inputProps; } // src/getSubmitButtonOptions.ts var DEFAULT_OPTIONS = { props: { disabled: false }, submitText: "Submit", norender: false }; function getSubmitButtonOptions(uiSchema = {}) { const uiOptions = getUiOptions(uiSchema); if (uiOptions && uiOptions[SUBMIT_BTN_OPTIONS_KEY]) { const options = uiO