@ajsf/core
Version:
Angular JSON Schema Form builder core
784 lines • 102 kB
JavaScript
import cloneDeep from 'lodash/cloneDeep';
import { forEach, hasOwn, mergeFilteredObject } from './utility.functions';
import { getType, hasValue, inArray, isArray, isNumber, isObject, isString } from './validator.functions';
import { JsonPointer } from './jsonpointer.functions';
import { mergeSchemas } from './merge-schemas.function';
/**
* JSON Schema function library:
*
* buildSchemaFromLayout: TODO: Write this function
*
* buildSchemaFromData:
*
* getFromSchema:
*
* removeRecursiveReferences:
*
* getInputType:
*
* checkInlineType:
*
* isInputRequired:
*
* updateInputOptions:
*
* getTitleMapFromOneOf:
*
* getControlValidators:
*
* resolveSchemaReferences:
*
* getSubSchema:
*
* combineAllOf:
*
* fixRequiredArrayProperties:
*/
/**
* 'buildSchemaFromLayout' function
*
* TODO: Build a JSON Schema from a JSON Form layout
*
* // layout - The JSON Form layout
* // - The new JSON Schema
*/
export function buildSchemaFromLayout(layout) {
return;
// let newSchema: any = { };
// const walkLayout = (layoutItems: any[], callback: Function): any[] => {
// let returnArray: any[] = [];
// for (let layoutItem of layoutItems) {
// const returnItem: any = callback(layoutItem);
// if (returnItem) { returnArray = returnArray.concat(callback(layoutItem)); }
// if (layoutItem.items) {
// returnArray = returnArray.concat(walkLayout(layoutItem.items, callback));
// }
// }
// return returnArray;
// };
// walkLayout(layout, layoutItem => {
// let itemKey: string;
// if (typeof layoutItem === 'string') {
// itemKey = layoutItem;
// } else if (layoutItem.key) {
// itemKey = layoutItem.key;
// }
// if (!itemKey) { return; }
// //
// });
}
/**
* 'buildSchemaFromData' function
*
* Build a JSON Schema from a data object
*
* // data - The data object
* // { boolean = false } requireAllFields - Require all fields?
* // { boolean = true } isRoot - is root
* // - The new JSON Schema
*/
export function buildSchemaFromData(data, requireAllFields = false, isRoot = true) {
const newSchema = {};
const getFieldType = (value) => {
const fieldType = getType(value, 'strict');
return { integer: 'number', null: 'string' }[fieldType] || fieldType;
};
const buildSubSchema = (value) => buildSchemaFromData(value, requireAllFields, false);
if (isRoot) {
newSchema.$schema = 'http://json-schema.org/draft-06/schema#';
}
newSchema.type = getFieldType(data);
if (newSchema.type === 'object') {
newSchema.properties = {};
if (requireAllFields) {
newSchema.required = [];
}
for (const key of Object.keys(data)) {
newSchema.properties[key] = buildSubSchema(data[key]);
if (requireAllFields) {
newSchema.required.push(key);
}
}
}
else if (newSchema.type === 'array') {
newSchema.items = data.map(buildSubSchema);
// If all items are the same type, use an object for items instead of an array
if ((new Set(data.map(getFieldType))).size === 1) {
newSchema.items = newSchema.items.reduce((a, b) => ({ ...a, ...b }), {});
}
if (requireAllFields) {
newSchema.minItems = 1;
}
}
return newSchema;
}
/**
* 'getFromSchema' function
*
* Uses a JSON Pointer for a value within a data object to retrieve
* the schema for that value within schema for the data object.
*
* The optional third parameter can also be set to return something else:
* 'schema' (default): the schema for the value indicated by the data pointer
* 'parentSchema': the schema for the value's parent object or array
* 'schemaPointer': a pointer to the value's schema within the object's schema
* 'parentSchemaPointer': a pointer to the schema for the value's parent object or array
*
* // schema - The schema to get the sub-schema from
* // { Pointer } dataPointer - JSON Pointer (string or array)
* // { string = 'schema' } returnType - what to return?
* // - The located sub-schema
*/
export function getFromSchema(schema, dataPointer, returnType = 'schema') {
const dataPointerArray = JsonPointer.parse(dataPointer);
if (dataPointerArray === null) {
console.error(`getFromSchema error: Invalid JSON Pointer: ${dataPointer}`);
return null;
}
let subSchema = schema;
const schemaPointer = [];
const length = dataPointerArray.length;
if (returnType.slice(0, 6) === 'parent') {
dataPointerArray.length--;
}
for (let i = 0; i < length; ++i) {
const parentSchema = subSchema;
const key = dataPointerArray[i];
let subSchemaFound = false;
if (typeof subSchema !== 'object') {
console.error(`getFromSchema error: Unable to find "${key}" key in schema.`);
console.error(schema);
console.error(dataPointer);
return null;
}
if (subSchema.type === 'array' && (!isNaN(key) || key === '-')) {
if (hasOwn(subSchema, 'items')) {
if (isObject(subSchema.items)) {
subSchemaFound = true;
subSchema = subSchema.items;
schemaPointer.push('items');
}
else if (isArray(subSchema.items)) {
if (!isNaN(key) && subSchema.items.length >= +key) {
subSchemaFound = true;
subSchema = subSchema.items[+key];
schemaPointer.push('items', key);
}
}
}
if (!subSchemaFound && isObject(subSchema.additionalItems)) {
subSchemaFound = true;
subSchema = subSchema.additionalItems;
schemaPointer.push('additionalItems');
}
else if (subSchema.additionalItems !== false) {
subSchemaFound = true;
subSchema = {};
schemaPointer.push('additionalItems');
}
}
else if (subSchema.type === 'object') {
if (isObject(subSchema.properties) && hasOwn(subSchema.properties, key)) {
subSchemaFound = true;
subSchema = subSchema.properties[key];
schemaPointer.push('properties', key);
}
else if (isObject(subSchema.additionalProperties)) {
subSchemaFound = true;
subSchema = subSchema.additionalProperties;
schemaPointer.push('additionalProperties');
}
else if (subSchema.additionalProperties !== false) {
subSchemaFound = true;
subSchema = {};
schemaPointer.push('additionalProperties');
}
}
if (!subSchemaFound) {
console.error(`getFromSchema error: Unable to find "${key}" item in schema.`);
console.error(schema);
console.error(dataPointer);
return;
}
}
return returnType.slice(-7) === 'Pointer' ? schemaPointer : subSchema;
}
/**
* 'removeRecursiveReferences' function
*
* Checks a JSON Pointer against a map of recursive references and returns
* a JSON Pointer to the shallowest equivalent location in the same object.
*
* Using this functions enables an object to be constructed with unlimited
* recursion, while maintaing a fixed set of metadata, such as field data types.
* The object can grow as large as it wants, and deeply recursed nodes can
* just refer to the metadata for their shallow equivalents, instead of having
* to add additional redundant metadata for each recursively added node.
*
* Example:
*
* pointer: '/stuff/and/more/and/more/and/more/and/more/stuff'
* recursiveRefMap: [['/stuff/and/more/and/more', '/stuff/and/more/']]
* returned: '/stuff/and/more/stuff'
*
* // { Pointer } pointer -
* // { Map<string, string> } recursiveRefMap -
* // { Map<string, number> = new Map() } arrayMap - optional
* // { string } -
*/
export function removeRecursiveReferences(pointer, recursiveRefMap, arrayMap = new Map()) {
if (!pointer) {
return '';
}
let genericPointer = JsonPointer.toGenericPointer(JsonPointer.compile(pointer), arrayMap);
if (genericPointer.indexOf('/') === -1) {
return genericPointer;
}
let possibleReferences = true;
while (possibleReferences) {
possibleReferences = false;
recursiveRefMap.forEach((toPointer, fromPointer) => {
if (JsonPointer.isSubPointer(toPointer, fromPointer)) {
while (JsonPointer.isSubPointer(fromPointer, genericPointer, true)) {
genericPointer = JsonPointer.toGenericPointer(toPointer + genericPointer.slice(fromPointer.length), arrayMap);
possibleReferences = true;
}
}
});
}
return genericPointer;
}
/**
* 'getInputType' function
*
* // schema
* // { any = null } layoutNode
* // { string }
*/
export function getInputType(schema, layoutNode = null) {
// x-schema-form = Angular Schema Form compatibility
// widget & component = React Jsonschema Form compatibility
const controlType = JsonPointer.getFirst([
[schema, '/x-schema-form/type'],
[schema, '/x-schema-form/widget/component'],
[schema, '/x-schema-form/widget'],
[schema, '/widget/component'],
[schema, '/widget']
]);
if (isString(controlType)) {
return checkInlineType(controlType, schema, layoutNode);
}
let schemaType = schema.type;
if (schemaType) {
if (isArray(schemaType)) { // If multiple types listed, use most inclusive type
schemaType =
inArray('object', schemaType) && hasOwn(schema, 'properties') ? 'object' :
inArray('array', schemaType) && hasOwn(schema, 'items') ? 'array' :
inArray('array', schemaType) && hasOwn(schema, 'additionalItems') ? 'array' :
inArray('string', schemaType) ? 'string' :
inArray('number', schemaType) ? 'number' :
inArray('integer', schemaType) ? 'integer' :
inArray('boolean', schemaType) ? 'boolean' : 'unknown';
}
if (schemaType === 'boolean') {
return 'checkbox';
}
if (schemaType === 'object') {
if (hasOwn(schema, 'properties') || hasOwn(schema, 'additionalProperties')) {
return 'section';
}
// TODO: Figure out how to handle additionalProperties
if (hasOwn(schema, '$ref')) {
return '$ref';
}
}
if (schemaType === 'array') {
const itemsObject = JsonPointer.getFirst([
[schema, '/items'],
[schema, '/additionalItems']
]) || {};
return hasOwn(itemsObject, 'enum') && schema.maxItems !== 1 ?
checkInlineType('checkboxes', schema, layoutNode) : 'array';
}
if (schemaType === 'null') {
return 'none';
}
if (JsonPointer.has(layoutNode, '/options/titleMap') ||
hasOwn(schema, 'enum') || getTitleMapFromOneOf(schema, null, true)) {
return 'select';
}
if (schemaType === 'number' || schemaType === 'integer') {
return (schemaType === 'integer' || hasOwn(schema, 'multipleOf')) &&
hasOwn(schema, 'maximum') && hasOwn(schema, 'minimum') ? 'range' : schemaType;
}
if (schemaType === 'string') {
return {
'color': 'color',
'date': 'date',
'date-time': 'datetime-local',
'email': 'email',
'uri': 'url',
}[schema.format] || 'text';
}
}
if (hasOwn(schema, '$ref')) {
return '$ref';
}
if (isArray(schema.oneOf) || isArray(schema.anyOf)) {
return 'one-of';
}
console.error(`getInputType error: Unable to determine input type for ${schemaType}`);
console.error('schema', schema);
if (layoutNode) {
console.error('layoutNode', layoutNode);
}
return 'none';
}
/**
* 'checkInlineType' function
*
* Checks layout and schema nodes for 'inline: true', and converts
* 'radios' or 'checkboxes' to 'radios-inline' or 'checkboxes-inline'
*
* // { string } controlType -
* // schema -
* // { any = null } layoutNode -
* // { string }
*/
export function checkInlineType(controlType, schema, layoutNode = null) {
if (!isString(controlType) || (controlType.slice(0, 8) !== 'checkbox' && controlType.slice(0, 5) !== 'radio')) {
return controlType;
}
if (JsonPointer.getFirst([
[layoutNode, '/inline'],
[layoutNode, '/options/inline'],
[schema, '/inline'],
[schema, '/x-schema-form/inline'],
[schema, '/x-schema-form/options/inline'],
[schema, '/x-schema-form/widget/inline'],
[schema, '/x-schema-form/widget/component/inline'],
[schema, '/x-schema-form/widget/component/options/inline'],
[schema, '/widget/inline'],
[schema, '/widget/component/inline'],
[schema, '/widget/component/options/inline'],
]) === true) {
return controlType.slice(0, 5) === 'radio' ?
'radios-inline' : 'checkboxes-inline';
}
else {
return controlType;
}
}
/**
* 'isInputRequired' function
*
* Checks a JSON Schema to see if an item is required
*
* // schema - the schema to check
* // { string } schemaPointer - the pointer to the item to check
* // { boolean } - true if the item is required, false if not
*/
export function isInputRequired(schema, schemaPointer) {
if (!isObject(schema)) {
console.error('isInputRequired error: Input schema must be an object.');
return false;
}
const listPointerArray = JsonPointer.parse(schemaPointer);
if (isArray(listPointerArray)) {
if (!listPointerArray.length) {
return schema.required === true;
}
const keyName = listPointerArray.pop();
const nextToLastKey = listPointerArray[listPointerArray.length - 1];
if (['properties', 'additionalProperties', 'patternProperties', 'items', 'additionalItems']
.includes(nextToLastKey)) {
listPointerArray.pop();
}
const parentSchema = JsonPointer.get(schema, listPointerArray) || {};
if (isArray(parentSchema.required)) {
return parentSchema.required.includes(keyName);
}
if (parentSchema.type === 'array') {
return hasOwn(parentSchema, 'minItems') &&
isNumber(keyName) &&
+parentSchema.minItems > +keyName;
}
}
return false;
}
/**
* 'updateInputOptions' function
*
* // layoutNode
* // schema
* // jsf
* // { void }
*/
export function updateInputOptions(layoutNode, schema, jsf) {
if (!isObject(layoutNode) || !isObject(layoutNode.options)) {
return;
}
// Set all option values in layoutNode.options
const newOptions = {};
const fixUiKeys = key => key.slice(0, 3).toLowerCase() === 'ui:' ? key.slice(3) : key;
mergeFilteredObject(newOptions, jsf.formOptions.defautWidgetOptions, [], fixUiKeys);
[[JsonPointer.get(schema, '/ui:widget/options'), []],
[JsonPointer.get(schema, '/ui:widget'), []],
[schema, [
'additionalProperties', 'additionalItems', 'properties', 'items',
'required', 'type', 'x-schema-form', '$ref'
]],
[JsonPointer.get(schema, '/x-schema-form/options'), []],
[JsonPointer.get(schema, '/x-schema-form'), ['items', 'options']],
[layoutNode, [
'_id', '$ref', 'arrayItem', 'arrayItemType', 'dataPointer', 'dataType',
'items', 'key', 'name', 'options', 'recursiveReference', 'type', 'widget'
]],
[layoutNode.options, []],
].forEach(([object, excludeKeys]) => mergeFilteredObject(newOptions, object, excludeKeys, fixUiKeys));
if (!hasOwn(newOptions, 'titleMap')) {
let newTitleMap = null;
newTitleMap = getTitleMapFromOneOf(schema, newOptions.flatList);
if (newTitleMap) {
newOptions.titleMap = newTitleMap;
}
if (!hasOwn(newOptions, 'titleMap') && !hasOwn(newOptions, 'enum') && hasOwn(schema, 'items')) {
if (JsonPointer.has(schema, '/items/titleMap')) {
newOptions.titleMap = schema.items.titleMap;
}
else if (JsonPointer.has(schema, '/items/enum')) {
newOptions.enum = schema.items.enum;
if (!hasOwn(newOptions, 'enumNames') && JsonPointer.has(schema, '/items/enumNames')) {
newOptions.enumNames = schema.items.enumNames;
}
}
else if (JsonPointer.has(schema, '/items/oneOf')) {
newTitleMap = getTitleMapFromOneOf(schema.items, newOptions.flatList);
if (newTitleMap) {
newOptions.titleMap = newTitleMap;
}
}
}
}
// If schema type is integer, enforce by setting multipleOf = 1
if (schema.type === 'integer' && !hasValue(newOptions.multipleOf)) {
newOptions.multipleOf = 1;
}
// Copy any typeahead word lists to options.typeahead.source
if (JsonPointer.has(newOptions, '/autocomplete/source')) {
newOptions.typeahead = newOptions.autocomplete;
}
else if (JsonPointer.has(newOptions, '/tagsinput/source')) {
newOptions.typeahead = newOptions.tagsinput;
}
else if (JsonPointer.has(newOptions, '/tagsinput/typeahead/source')) {
newOptions.typeahead = newOptions.tagsinput.typeahead;
}
layoutNode.options = newOptions;
}
/**
* 'getTitleMapFromOneOf' function
*
* // { schema } schema
* // { boolean = null } flatList
* // { boolean = false } validateOnly
* // { validators }
*/
export function getTitleMapFromOneOf(schema = {}, flatList = null, validateOnly = false) {
let titleMap = null;
const oneOf = schema.oneOf || schema.anyOf || null;
if (isArray(oneOf) && oneOf.every(item => item.title)) {
if (oneOf.every(item => isArray(item.enum) && item.enum.length === 1)) {
if (validateOnly) {
return true;
}
titleMap = oneOf.map(item => ({ name: item.title, value: item.enum[0] }));
}
else if (oneOf.every(item => item.const)) {
if (validateOnly) {
return true;
}
titleMap = oneOf.map(item => ({ name: item.title, value: item.const }));
}
// if flatList !== false and some items have colons, make grouped map
if (flatList !== false && (titleMap || [])
.filter(title => ((title || {}).name || '').indexOf(': ')).length > 1) {
// Split name on first colon to create grouped map (name -> group: name)
const newTitleMap = titleMap.map(title => {
const [group, name] = title.name.split(/: (.+)/);
return group && name ? { ...title, group, name } : title;
});
// If flatList === true or at least one group has multiple items, use grouped map
if (flatList === true || newTitleMap.some((title, index) => index &&
hasOwn(title, 'group') && title.group === newTitleMap[index - 1].group)) {
titleMap = newTitleMap;
}
}
}
return validateOnly ? false : titleMap;
}
/**
* 'getControlValidators' function
*
* // schema
* // { validators }
*/
export function getControlValidators(schema) {
if (!isObject(schema)) {
return null;
}
const validators = {};
if (hasOwn(schema, 'type')) {
switch (schema.type) {
case 'string':
forEach(['pattern', 'format', 'minLength', 'maxLength'], (prop) => {
if (hasOwn(schema, prop)) {
validators[prop] = [schema[prop]];
}
});
break;
case 'number':
case 'integer':
forEach(['Minimum', 'Maximum'], (ucLimit) => {
const eLimit = 'exclusive' + ucLimit;
const limit = ucLimit.toLowerCase();
if (hasOwn(schema, limit)) {
const exclusive = hasOwn(schema, eLimit) && schema[eLimit] === true;
validators[limit] = [schema[limit], exclusive];
}
});
forEach(['multipleOf', 'type'], (prop) => {
if (hasOwn(schema, prop)) {
validators[prop] = [schema[prop]];
}
});
break;
case 'object':
forEach(['minProperties', 'maxProperties', 'dependencies'], (prop) => {
if (hasOwn(schema, prop)) {
validators[prop] = [schema[prop]];
}
});
break;
case 'array':
forEach(['minItems', 'maxItems', 'uniqueItems'], (prop) => {
if (hasOwn(schema, prop)) {
validators[prop] = [schema[prop]];
}
});
break;
}
}
if (hasOwn(schema, 'enum')) {
validators.enum = [schema.enum];
}
return validators;
}
/**
* 'resolveSchemaReferences' function
*
* Find all $ref links in schema and save links and referenced schemas in
* schemaRefLibrary, schemaRecursiveRefMap, and dataRecursiveRefMap
*
* // schema
* // schemaRefLibrary
* // { Map<string, string> } schemaRecursiveRefMap
* // { Map<string, string> } dataRecursiveRefMap
* // { Map<string, number> } arrayMap
* //
*/
export function resolveSchemaReferences(schema, schemaRefLibrary, schemaRecursiveRefMap, dataRecursiveRefMap, arrayMap) {
if (!isObject(schema)) {
console.error('resolveSchemaReferences error: schema must be an object.');
return;
}
const refLinks = new Set();
const refMapSet = new Set();
const refMap = new Map();
const recursiveRefMap = new Map();
const refLibrary = {};
// Search schema for all $ref links, and build full refLibrary
JsonPointer.forEachDeep(schema, (subSchema, subSchemaPointer) => {
if (hasOwn(subSchema, '$ref') && isString(subSchema['$ref'])) {
const refPointer = JsonPointer.compile(subSchema['$ref']);
refLinks.add(refPointer);
refMapSet.add(subSchemaPointer + '~~' + refPointer);
refMap.set(subSchemaPointer, refPointer);
}
});
refLinks.forEach(ref => refLibrary[ref] = getSubSchema(schema, ref));
// Follow all ref links and save in refMapSet,
// to find any multi-link recursive refernces
let checkRefLinks = true;
while (checkRefLinks) {
checkRefLinks = false;
Array.from(refMap).forEach(([fromRef1, toRef1]) => Array.from(refMap)
.filter(([fromRef2, toRef2]) => JsonPointer.isSubPointer(toRef1, fromRef2, true) &&
!JsonPointer.isSubPointer(toRef2, toRef1, true) &&
!refMapSet.has(fromRef1 + fromRef2.slice(toRef1.length) + '~~' + toRef2))
.forEach(([fromRef2, toRef2]) => {
refMapSet.add(fromRef1 + fromRef2.slice(toRef1.length) + '~~' + toRef2);
checkRefLinks = true;
}));
}
// Build full recursiveRefMap
// First pass - save all internally recursive refs from refMapSet
Array.from(refMapSet)
.map(refLink => refLink.split('~~'))
.filter(([fromRef, toRef]) => JsonPointer.isSubPointer(toRef, fromRef))
.forEach(([fromRef, toRef]) => recursiveRefMap.set(fromRef, toRef));
// Second pass - create recursive versions of any other refs that link to recursive refs
Array.from(refMap)
.filter(([fromRef1, toRef1]) => Array.from(recursiveRefMap.keys())
.every(fromRef2 => !JsonPointer.isSubPointer(fromRef1, fromRef2, true)))
.forEach(([fromRef1, toRef1]) => Array.from(recursiveRefMap)
.filter(([fromRef2, toRef2]) => !recursiveRefMap.has(fromRef1 + fromRef2.slice(toRef1.length)) &&
JsonPointer.isSubPointer(toRef1, fromRef2, true) &&
!JsonPointer.isSubPointer(toRef1, fromRef1, true))
.forEach(([fromRef2, toRef2]) => recursiveRefMap.set(fromRef1 + fromRef2.slice(toRef1.length), fromRef1 + toRef2.slice(toRef1.length))));
// Create compiled schema by replacing all non-recursive $ref links with
// thieir linked schemas and, where possible, combining schemas in allOf arrays.
let compiledSchema = { ...schema };
delete compiledSchema.definitions;
compiledSchema =
getSubSchema(compiledSchema, '', refLibrary, recursiveRefMap);
// Make sure all remaining schema $refs are recursive, and build final
// schemaRefLibrary, schemaRecursiveRefMap, dataRecursiveRefMap, & arrayMap
JsonPointer.forEachDeep(compiledSchema, (subSchema, subSchemaPointer) => {
if (isString(subSchema['$ref'])) {
let refPointer = JsonPointer.compile(subSchema['$ref']);
if (!JsonPointer.isSubPointer(refPointer, subSchemaPointer, true)) {
refPointer = removeRecursiveReferences(subSchemaPointer, recursiveRefMap);
JsonPointer.set(compiledSchema, subSchemaPointer, { $ref: `#${refPointer}` });
}
if (!hasOwn(schemaRefLibrary, 'refPointer')) {
schemaRefLibrary[refPointer] = !refPointer.length ? compiledSchema :
getSubSchema(compiledSchema, refPointer, schemaRefLibrary, recursiveRefMap);
}
if (!schemaRecursiveRefMap.has(subSchemaPointer)) {
schemaRecursiveRefMap.set(subSchemaPointer, refPointer);
}
const fromDataRef = JsonPointer.toDataPointer(subSchemaPointer, compiledSchema);
if (!dataRecursiveRefMap.has(fromDataRef)) {
const toDataRef = JsonPointer.toDataPointer(refPointer, compiledSchema);
dataRecursiveRefMap.set(fromDataRef, toDataRef);
}
}
if (subSchema.type === 'array' &&
(hasOwn(subSchema, 'items') || hasOwn(subSchema, 'additionalItems'))) {
const dataPointer = JsonPointer.toDataPointer(subSchemaPointer, compiledSchema);
if (!arrayMap.has(dataPointer)) {
const tupleItems = isArray(subSchema.items) ? subSchema.items.length : 0;
arrayMap.set(dataPointer, tupleItems);
}
}
}, true);
return compiledSchema;
}
/**
* 'getSubSchema' function
*
* // schema
* // { Pointer } pointer
* // { object } schemaRefLibrary
* // { Map<string, string> } schemaRecursiveRefMap
* // { string[] = [] } usedPointers
* //
*/
export function getSubSchema(schema, pointer, schemaRefLibrary = null, schemaRecursiveRefMap = null, usedPointers = []) {
if (!schemaRefLibrary || !schemaRecursiveRefMap) {
return JsonPointer.getCopy(schema, pointer);
}
if (typeof pointer !== 'string') {
pointer = JsonPointer.compile(pointer);
}
usedPointers = [...usedPointers, pointer];
let newSchema = null;
if (pointer === '') {
newSchema = cloneDeep(schema);
}
else {
const shortPointer = removeRecursiveReferences(pointer, schemaRecursiveRefMap);
if (shortPointer !== pointer) {
usedPointers = [...usedPointers, shortPointer];
}
newSchema = JsonPointer.getFirstCopy([
[schemaRefLibrary, [shortPointer]],
[schema, pointer],
[schema, shortPointer]
]);
}
return JsonPointer.forEachDeepCopy(newSchema, (subSchema, subPointer) => {
if (isObject(subSchema)) {
// Replace non-recursive $ref links with referenced schemas
if (isString(subSchema.$ref)) {
const refPointer = JsonPointer.compile(subSchema.$ref);
if (refPointer.length && usedPointers.every(ptr => !JsonPointer.isSubPointer(refPointer, ptr, true))) {
const refSchema = getSubSchema(schema, refPointer, schemaRefLibrary, schemaRecursiveRefMap, usedPointers);
if (Object.keys(subSchema).length === 1) {
return refSchema;
}
else {
const extraKeys = { ...subSchema };
delete extraKeys.$ref;
return mergeSchemas(refSchema, extraKeys);
}
}
}
// TODO: Convert schemas with 'type' arrays to 'oneOf'
// Combine allOf subSchemas
if (isArray(subSchema.allOf)) {
return combineAllOf(subSchema);
}
// Fix incorrectly placed array object required lists
if (subSchema.type === 'array' && isArray(subSchema.required)) {
return fixRequiredArrayProperties(subSchema);
}
}
return subSchema;
}, true, pointer);
}
/**
* 'combineAllOf' function
*
* Attempt to convert an allOf schema object into
* a non-allOf schema object with equivalent rules.
*
* // schema - allOf schema object
* // - converted schema object
*/
export function combineAllOf(schema) {
if (!isObject(schema) || !isArray(schema.allOf)) {
return schema;
}
let mergedSchema = mergeSchemas(...schema.allOf);
if (Object.keys(schema).length > 1) {
const extraKeys = { ...schema };
delete extraKeys.allOf;
mergedSchema = mergeSchemas(mergedSchema, extraKeys);
}
return mergedSchema;
}
/**
* 'fixRequiredArrayProperties' function
*
* Fixes an incorrectly placed required list inside an array schema, by moving
* it into items.properties or additionalItems.properties, where it belongs.
*
* // schema - allOf schema object
* // - converted schema object
*/
export function fixRequiredArrayProperties(schema) {
if (schema.type === 'array' && isArray(schema.required)) {
const itemsObject = hasOwn(schema.items, 'properties') ? 'items' :
hasOwn(schema.additionalItems, 'properties') ? 'additionalItems' : null;
if (itemsObject && !hasOwn(schema[itemsObject], 'required') && (hasOwn(schema[itemsObject], 'additionalProperties') ||
schema.required.every(key => hasOwn(schema[itemsObject].properties, key)))) {
schema = cloneDeep(schema);
schema[itemsObject].required = schema.required;
delete schema.required;
}
}
return schema;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoianNvbi1zY2hlbWEuZnVuY3Rpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYWpzZi1jb3JlL3NyYy9saWIvc2hhcmVkL2pzb24tc2NoZW1hLmZ1bmN0aW9ucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLFNBQVMsTUFBTSxrQkFBa0IsQ0FBQztBQUN6QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzNFLE9BQU8sRUFDTCxPQUFPLEVBQ1AsUUFBUSxFQUNSLE9BQU8sRUFDUCxPQUFPLEVBQ1AsUUFBUSxFQUNSLFFBQVEsRUFDUixRQUFRLEVBQ1AsTUFBTSx1QkFBdUIsQ0FBQztBQUNqQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDdEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBR3hEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E4Qkc7QUFFSDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLHFCQUFxQixDQUFDLE1BQU07SUFDMUMsT0FBTztJQUNQLDRCQUE0QjtJQUM1QiwwRUFBMEU7SUFDMUUsaUNBQWlDO0lBQ2pDLDBDQUEwQztJQUMxQyxvREFBb0Q7SUFDcEQsa0ZBQWtGO0lBQ2xGLDhCQUE4QjtJQUM5QixrRkFBa0Y7SUFDbEYsUUFBUTtJQUNSLE1BQU07SUFDTix3QkFBd0I7SUFDeEIsS0FBSztJQUNMLHFDQUFxQztJQUNyQyx5QkFBeUI7SUFDekIsMENBQTBDO0lBQzFDLDRCQUE0QjtJQUM1QixpQ0FBaUM7SUFDakMsZ0NBQWdDO0lBQ2hDLE1BQU07SUFDTiw4QkFBOEI7SUFDOUIsT0FBTztJQUNQLE1BQU07QUFDUixDQUFDO0FBRUQ7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBTSxVQUFVLG1CQUFtQixDQUNqQyxJQUFJLEVBQUUsZ0JB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QUksRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1NBQzNFO2FBQU0sSUFBSSxLQUFLLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFO1lBQzFDLElBQUksWUFBWSxFQUFFO2dCQUFFLE9BQU8sSUFBSSxDQUFDO2FBQUU7WUFDbEMsUUFBUSxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7U0FDekU7UUFFRCxxRUFBcUU7UUFDckUsSUFBSSxRQUFRLEtBQUssS0FBSyxJQUFJLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQzthQUN2QyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUNyRTtZQ