@greguintow/rjsf-utils
Version:
Utility functions for @rjsf/core
1,352 lines (1,324 loc) • 127 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('lodash/isPlainObject'), require('lodash/isEqualWith'), require('lodash/get'), require('lodash/has'), require('lodash/isEqual'), require('lodash/set'), require('lodash/times'), require('lodash/transform'), require('lodash/merge'), require('lodash/flattenDeep'), require('lodash/uniq'), require('json-schema-merge-allof'), require('jsonpointer'), require('lodash/omit'), require('lodash/isString'), require('lodash/union'), require('lodash/isNumber'), require('lodash/isEmpty'), require('lodash/isObject'), require('lodash/reduce'), require('lodash/isNil'), require('lodash/cloneDeep'), require('lodash/setWith'), require('nanoid'), require('react'), require('react-is'), require('react/jsx-runtime'), require('lodash/toPath'), require('lodash/keys'), require('lodash/pickBy'), require('lodash/difference'), require('lodash/forEach')) :
typeof define === 'function' && define.amd ? define(['exports', 'lodash/isPlainObject', 'lodash/isEqualWith', 'lodash/get', 'lodash/has', 'lodash/isEqual', 'lodash/set', 'lodash/times', 'lodash/transform', 'lodash/merge', 'lodash/flattenDeep', 'lodash/uniq', 'json-schema-merge-allof', 'jsonpointer', 'lodash/omit', 'lodash/isString', 'lodash/union', 'lodash/isNumber', 'lodash/isEmpty', 'lodash/isObject', 'lodash/reduce', 'lodash/isNil', 'lodash/cloneDeep', 'lodash/setWith', 'nanoid', 'react', 'react-is', 'react/jsx-runtime', 'lodash/toPath', 'lodash/keys', 'lodash/pickBy', 'lodash/difference', 'lodash/forEach'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["@rjsf/utils"] = {}, global.isPlainObject4, global.isEqualWith, global.get18, global.has6, global.isEqual, global.set2, global.times, global.transform, global.merge, global.flattenDeep, global.uniq, global.mergeAllOf, global.jsonpointer, global.omit, global.isString, global.union, global.isNumber, global.isEmpty3, global.isObject2, global.reduce, global.isNil, global.cloneDeep, global.setWith, null, global.react, global.ReactIs, global.jsxRuntime, global.toPath, global.keys, global.pickBy, global.difference, global.forEach));
})(this, (function (exports, isPlainObject4, isEqualWith, get18, has6, isEqual, set2, times, transform, merge, flattenDeep, uniq, mergeAllOf, jsonpointer, omit, isString, union, isNumber, isEmpty3, isObject2, reduce, isNil, cloneDeep, setWith, nanoid, react, ReactIs, jsxRuntime, toPath, keys, pickBy, difference, forEach) { 'use strict';
// 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;
}
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 (isPlainObject4(formData)) {
const formObject = formData;
return Object.keys(formObject).reduce((acc, key) => {
return { ...acc, [key]: createErrorHandler(formObject[key]) };
}, handler);
}
return handler;
}
function deepEquals(a, b) {
return isEqualWith(a, b, (obj, other) => {
if (typeof obj === "function" && typeof other === "function") {
return true;
}
return void 0;
});
}
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);
}
function getDiscriminatorFieldFromSchema(schema) {
let discriminator;
const maybeString = get18(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/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);
}
function getOptionMatchingSimpleDiscriminator(formData, options, discriminatorField) {
if (formData && discriminatorField) {
const value = get18(formData, discriminatorField);
if (value === void 0) {
return;
}
for (let i = 0; i < options.length; i++) {
const option = options[i];
const discriminator = get18(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 && has6(option, [PROPERTIES_KEY, discriminatorField])) {
const value = get18(formData, discriminatorField);
const discriminator = get18(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: get18(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(get18(formData, [key])) };
}
} else {
additionalProperties = { type: guessType(get18(formData, [key])) };
}
schema.properties[key] = additionalProperties;
set2(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 && get18(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 = get18(formData, selectorField);
if (data !== void 0) {
return xxxOfs.find((xxx2) => {
return isEqual(
get18(xxx2, [PROPERTIES_KEY, selectorField, DEFAULT_KEY], get18(xxx2, [PROPERTIES_KEY, selectorField, CONST_KEY])),
data
);
});
}
}
return void 0;
}
function getFromSchemaInternal(validator, rootSchema, schema, path, experimental_customMergeAllOf) {
let fieldSchema = schema;
if (has6(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 && has6(fieldSchema, part)) {
fieldSchema = get18(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 (has6(parentField, ONE_OF_KEY)) {
parentField = findSelectedOptionInXxxOf(
validator,
rootSchema,
parentField,
fieldName,
ONE_OF_KEY,
get18(formData, subPath),
experimental_customMergeAllOf
);
} else if (has6(parentField, ANY_OF_KEY)) {
parentField = findSelectedOptionInXxxOf(
validator,
rootSchema,
parentField,
fieldName,
ANY_OF_KEY,
get18(formData, subPath),
experimental_customMergeAllOf
);
}
});
}
if (has6(parentField, ONE_OF_KEY)) {
parentField = findSelectedOptionInXxxOf(
validator,
rootSchema,
parentField,
fieldName,
ONE_OF_KEY,
formData,
experimental_customMergeAllOf
);
} else if (has6(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 };
}
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 = get18(formData, key);
if (typeof value === "boolean") {
return score;
}
if (has6(value, REF_KEY)) {
const newSchema = retrieveSchema(
validator,
value,
rootSchema,
formValue,
experimental_customMergeAllOf
);
return score + calculateIndexScore(
validator,
rootSchema,
newSchema,
formValue || {},
experimental_customMergeAllOf
);
}
if ((has6(value, ONE_OF_KEY) || has6(value, ANY_OF_KEY)) && formValue) {
const key2 = has6(value, ONE_OF_KEY) ? ONE_OF_KEY : ANY_OF_KEY;
const discriminator = getDiscriminatorFieldFromSchema(value);
return score + getClosestMatchingOption(
validator,
rootSchema,
formValue,
get18(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 (isString(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 (isNumber(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) {
times(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));
}
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 = get18(formData, key);
const keyExistsInDefaults = isObject(defaults) && key in defaults;
const keyExistsInFormData = key in formData;
acc2[key] = mergeDefaultsWithFormData(
defaults ? get18(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;
}
function enumOptionsSelectValue(valueIndex, selected, allEnumOptions = []) {
const value = enumOptionsValueForIndex(valueIndex, allEnumOptions);
if (!isNil(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;
}
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 ? get18(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 = get18(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