160 lines
6.7 KiB
Plaintext
160 lines
6.7 KiB
Plaintext
"use strict";
|
|
// For internal usage only
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.getNodeTypesFromJSONSchema = getNodeTypesFromJSONSchema;
|
|
const _2020_1 = require("@redocly/ajv/dist/2020");
|
|
const utils_1 = require("../utils");
|
|
const ajv = new _2020_1.default({
|
|
strictSchema: false,
|
|
allowUnionTypes: true,
|
|
useDefaults: true,
|
|
allErrors: true,
|
|
discriminator: true,
|
|
strictTypes: false,
|
|
verbose: true,
|
|
});
|
|
function findOneOf(schemaOneOf, oneOfs) {
|
|
if (oneOfs.some((option) => typeof option === 'function')) {
|
|
throw new Error('Unexpected oneOf inside oneOf.');
|
|
}
|
|
return (value) => {
|
|
let index = schemaOneOf.findIndex((option) => ajv.validate(option, value));
|
|
if (index === -1) {
|
|
index = 0;
|
|
}
|
|
return oneOfs[index];
|
|
};
|
|
}
|
|
function transformJSONSchemaToNodeType(propertyName, schema, ctx) {
|
|
if (!schema || typeof schema === 'boolean') {
|
|
throw new Error(`Unexpected schema in ${propertyName}.`);
|
|
}
|
|
if (schema instanceof Array) {
|
|
throw new Error(`Unexpected array schema in ${propertyName}. Try using oneOf instead.`);
|
|
}
|
|
if (schema.type === 'null') {
|
|
throw new Error(`Unexpected null schema type in ${propertyName} schema.`);
|
|
}
|
|
if (schema.type instanceof Array) {
|
|
throw new Error(`Unexpected array schema type in ${propertyName} schema. Try using oneOf instead.`);
|
|
}
|
|
if (schema.type === 'string' ||
|
|
schema.type === 'number' ||
|
|
schema.type === 'integer' ||
|
|
schema.type === 'boolean') {
|
|
const { default: _, format: _format, ...rest } = schema;
|
|
return rest;
|
|
}
|
|
if (schema.type === 'object' && !schema.properties && !schema.oneOf) {
|
|
if (schema.additionalProperties === undefined || schema.additionalProperties === true) {
|
|
return { type: 'object' };
|
|
}
|
|
else if (schema.additionalProperties === false) {
|
|
return { type: 'object', properties: {} };
|
|
}
|
|
}
|
|
if (schema.allOf) {
|
|
throw new Error(`Unexpected allOf in ${propertyName}.`);
|
|
}
|
|
if (schema.anyOf) {
|
|
throw new Error(`Unexpected anyOf in ${propertyName}.`);
|
|
}
|
|
if ((0, utils_1.isPlainObject)(schema.properties) ||
|
|
(0, utils_1.isPlainObject)(schema.additionalProperties) ||
|
|
((0, utils_1.isPlainObject)(schema.items) &&
|
|
((0, utils_1.isPlainObject)(schema.items.properties) ||
|
|
(0, utils_1.isPlainObject)(schema.items.additionalProperties) ||
|
|
schema.items.oneOf)) // exclude scalar array types
|
|
) {
|
|
return extractNodeToContext(propertyName, schema, ctx);
|
|
}
|
|
if (schema.oneOf) {
|
|
if (schema.discriminator) {
|
|
const discriminatedPropertyName = schema.discriminator?.propertyName;
|
|
if (!discriminatedPropertyName) {
|
|
throw new Error(`Unexpected discriminator without a propertyName in ${propertyName}.`);
|
|
}
|
|
const oneOfs = schema.oneOf.map((option, i) => {
|
|
if (typeof option === 'boolean') {
|
|
throw new Error(`Unexpected boolean schema in ${propertyName} at position ${i} in oneOf.`);
|
|
}
|
|
const discriminatedProperty = option?.properties?.[discriminatedPropertyName];
|
|
if (!discriminatedProperty || typeof discriminatedProperty === 'boolean') {
|
|
throw new Error(`Unexpected property '${discriminatedProperty}' schema in ${propertyName} at position ${i} in oneOf.`);
|
|
}
|
|
const name = discriminatedProperty.const;
|
|
return transformJSONSchemaToNodeType(name, option, ctx);
|
|
});
|
|
return (value, key) => {
|
|
if ((0, utils_1.isPlainObject)(value)) {
|
|
const discriminatedTypeName = value[discriminatedPropertyName];
|
|
if (typeof discriminatedTypeName === 'string' && ctx[discriminatedTypeName]) {
|
|
return discriminatedTypeName;
|
|
}
|
|
}
|
|
return findOneOf(schema.oneOf, oneOfs)(value, key);
|
|
};
|
|
}
|
|
else {
|
|
const oneOfs = schema.oneOf.map((option, i) => transformJSONSchemaToNodeType(propertyName + '_' + i, option, ctx));
|
|
return findOneOf(schema.oneOf, oneOfs);
|
|
}
|
|
}
|
|
return schema;
|
|
}
|
|
function extractNodeToContext(propertyName, schema, ctx) {
|
|
if (!schema || typeof schema === 'boolean') {
|
|
throw new Error(`Unexpected schema in ${propertyName}.`);
|
|
}
|
|
if (schema instanceof Array) {
|
|
throw new Error(`Unexpected array schema in ${propertyName}. Try using oneOf instead.`);
|
|
}
|
|
if (schema.type === 'null') {
|
|
throw new Error(`Unexpected null schema type in ${propertyName} schema.`);
|
|
}
|
|
if (schema.type instanceof Array) {
|
|
throw new Error(`Unexpected array schema type in ${propertyName} schema. Try using oneOf instead.`);
|
|
}
|
|
const properties = {};
|
|
for (const [name, property] of Object.entries(schema.properties || {})) {
|
|
properties[name] = transformJSONSchemaToNodeType(propertyName + '.' + name, property, ctx);
|
|
}
|
|
let additionalProperties;
|
|
if ((0, utils_1.isPlainObject)(schema.additionalProperties)) {
|
|
additionalProperties = transformJSONSchemaToNodeType(propertyName + '_additionalProperties', schema.additionalProperties, ctx);
|
|
}
|
|
if (schema.additionalProperties === true) {
|
|
additionalProperties = {};
|
|
}
|
|
let items;
|
|
if ((0, utils_1.isPlainObject)(schema.items) &&
|
|
((0, utils_1.isPlainObject)(schema.items.properties) ||
|
|
(0, utils_1.isPlainObject)(schema.items.additionalProperties) ||
|
|
schema.items.oneOf) // exclude scalar array types
|
|
) {
|
|
items = transformJSONSchemaToNodeType(propertyName + '_items', schema.items, ctx);
|
|
}
|
|
let required = schema.required;
|
|
// Translate required in oneOfs into a ResolveTypeFn.
|
|
if (schema.oneOf && schema.oneOf.every((option) => !!option.required)) {
|
|
required = (value) => {
|
|
const requiredList = schema.oneOf.map((option) => [
|
|
...(schema.required || []),
|
|
...option.required,
|
|
]);
|
|
let index = requiredList.findIndex((r) => r.every((requiredProp) => value[requiredProp] !== undefined));
|
|
if (index === -1) {
|
|
index = 0;
|
|
}
|
|
return requiredList[index];
|
|
};
|
|
}
|
|
ctx[propertyName] = { properties, additionalProperties, items, required };
|
|
return propertyName;
|
|
}
|
|
function getNodeTypesFromJSONSchema(schemaName, entrySchema) {
|
|
const ctx = {};
|
|
transformJSONSchemaToNodeType(schemaName, entrySchema, ctx);
|
|
return ctx;
|
|
}
|