@snups/rjsf-utils
Version:
Utility functions for @snups/rjsf-core
1,500 lines (1,464 loc) • 124 kB
JavaScript
// 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