@mintlify/common
Version:
Commonly shared code within Mintlify
181 lines (180 loc) • 8.01 kB
JavaScript
import { getEnumValues } from '../getEnumValues.js';
const combinationKeys = ['oneOf', 'anyOf', 'allOf'];
const getCombinationKey = (value) => {
return combinationKeys.find((key) => key in value && Array.isArray(value[key]));
};
const getTypeFromCombination = (value, combKey) => {
var _a;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const schemas = value[combKey];
const types = [
...new Set(schemas
.map((s) => (typeof s === 'object' ? s.type : undefined))
.filter((t) => typeof t === 'string' && t !== 'null')),
];
if (types.length === 1)
return (_a = types[0]) !== null && _a !== void 0 ? _a : combKey;
return combKey;
};
const getSchemaType = (value, keys) => {
if ('type' in value) {
return value.type;
}
const customTypeKey = keys.find((key) => /^x-.*type$/.test(key));
if (customTypeKey) {
return value[customTypeKey];
}
const enumValues = getEnumValues(value);
if (enumValues === null || enumValues === void 0 ? void 0 : enumValues.length) {
const firstValue = enumValues[0];
if (typeof firstValue === 'boolean')
return 'boolean';
if (typeof firstValue === 'number')
return 'number';
return 'string';
}
return undefined;
};
export const extractSchemaProperties = (schema) => {
if (!schema) {
return [];
}
const properties = [];
const requiredFields = new Set(schema.required || []);
for (const [key, value] of Object.entries(schema)) {
const name = key;
if (name === 'required' || name.includes('x-parser')) {
continue;
}
if (name === 'oneOf' || name === 'anyOf' || name === 'allOf') {
const descriptions = {
oneOf: 'Must be one of these types',
anyOf: 'Can be any of these types',
allOf: 'Must contain all of these types',
};
const prop = {
name,
type: name,
description: descriptions[name],
properties: value
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.map((item) => {
const schemaWithRequired = Object.assign(Object.assign({}, (item.properties || item)), { required: item.required });
const extracted = extractSchemaProperties(schemaWithRequired);
return extracted;
})
.flat(),
};
properties.push(prop);
continue;
}
if (value === null || value === undefined) {
continue;
}
if (typeof value === 'object' && !Array.isArray(value)) {
const keys = Object.keys(value);
const type = getSchemaType(value, keys);
if (type !== undefined) {
const prop = {
name: name,
type,
title: value.title,
description: value.description || value['const'],
enumValues: getEnumValues(value),
examples: value.examples,
deprecated: value.deprecated,
required: requiredFields.has(name),
};
if (value.properties) {
prop.properties = extractSchemaProperties(Object.assign(Object.assign({}, value.properties), { required: value.required }));
}
else if (type === 'array' &&
value.items &&
typeof value.items === 'object' &&
!Array.isArray(value.items)) {
if (value.items.properties) {
const itemSchemaWithRequired = Object.assign(Object.assign({}, value.items.properties), { required: value.items.required });
prop.properties = extractSchemaProperties(itemSchemaWithRequired);
}
else {
const itemProps = extractSchemaProperties({ item: value.items });
if (itemProps.length > 0) {
prop.properties = itemProps;
}
}
}
properties.push(prop);
}
else {
const combKey = getCombinationKey(value);
if (combKey) {
const inferredType = getTypeFromCombination(value, combKey);
const prop = {
name,
type: inferredType,
title: value.title,
description: value.description,
enumValues: getEnumValues(value),
examples: value.examples,
deprecated: value.deprecated,
required: requiredFields.has(name),
};
// Extract child properties from combination schemas
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const combSchemas = value[combKey];
if (combKey === 'allOf') {
// allOf: merge all sub-schema properties together
const mergedProps = combSchemas.flatMap(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(item) => {
if (item.properties) {
const schemaWithRequired = Object.assign(Object.assign({}, item.properties), { required: item.required });
return extractSchemaProperties(schemaWithRequired);
}
return [];
});
if (mergedProps.length > 0) {
prop.properties = mergedProps;
if (inferredType === 'allOf')
prop.type = 'object';
}
}
else {
// oneOf/anyOf: extract properties from sub-schemas that have them
const subProps = combSchemas.flatMap(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(item) => {
if (item.properties) {
const schemaWithRequired = Object.assign(Object.assign({}, item.properties), { required: item.required });
return extractSchemaProperties(schemaWithRequired);
}
if (item.items && typeof item.items === 'object') {
if (item.items.properties) {
const schemaWithRequired = Object.assign(Object.assign({}, item.items.properties), { required: item.items.required });
return extractSchemaProperties(schemaWithRequired);
}
}
return [];
});
if (subProps.length > 0) {
prop.properties = subProps;
}
}
properties.push(prop);
}
else {
properties.push(...extractSchemaProperties(value));
}
}
}
else {
properties.push({
name,
type: Array.isArray(value) ? 'array' : typeof value,
description: typeof value === 'string' ? value : undefined,
required: requiredFields.has(name),
});
}
}
return properties;
};