@alova/wormhole
Version:
More modern openAPI generating solution for alova.js
196 lines (195 loc) • 6.42 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.applyModifierSchema = applyModifierSchema;
// Convert Schema (custom spec) -> OpenAPI SchemaObject
function toSchemaObject(base, s) {
const result = { ...base };
const cleanType = (schema) => {
delete schema.type;
delete schema.enum;
delete schema.oneOf;
delete schema.anyOf;
delete schema.allOf;
delete schema.items;
delete schema.properties;
delete schema.required;
return schema;
};
// Legacy union as array (treated as oneOf)
if (Array.isArray(s)) {
const baseOneOf = base.oneOf || [];
cleanType(result);
result.oneOf = s.map((item, idx) => toSchemaObject(baseOneOf[idx] || {}, item));
return result;
}
// Primitive types and no-op primitives
if (typeof s === 'string') {
result.type = s;
return result;
}
// Handle union keywords: overwrite arrays but preserve unrelated fields
if (s.oneOf) {
const spec = s;
const baseOneOf = base.oneOf || [];
cleanType(result);
result.oneOf = spec.oneOf.map((item, idx) => toSchemaObject(baseOneOf[idx] || {}, item));
}
if (s.anyOf) {
const spec = s;
const baseAnyOf = base.anyOf || [];
cleanType(result);
result.anyOf = spec.anyOf.map((item, idx) => toSchemaObject(baseAnyOf[idx] || {}, item));
}
if (s.allOf) {
const spec = s;
const baseAllOf = base.allOf || [];
cleanType(result);
result.allOf = spec.allOf.map((item, idx) => toSchemaObject(baseAllOf[idx] || {}, item));
}
// Enum: set enum and optional type
if (s.enum) {
const spec = s;
result.enum = spec.enum;
if (spec.type) {
result.type = spec.type;
}
}
// Array: set/merge items
if (s.type === 'array') {
const spec = s;
result.type = 'array';
const baseItems = result.items;
if (Array.isArray(spec.items)) {
// Tuple items: replace entire items with tuple
const items = spec.items.map(item => toSchemaObject({}, item));
result.items = items;
}
else {
// Single items: merge into existing items schema
const patchItem = toSchemaObject(typeof baseItems === 'object' ? baseItems : {}, spec.items);
result.items = patchItem;
}
return result;
}
// Object (reference-like map): merge properties and required
const ref = s;
if (ref && typeof ref === 'object') {
result.type = 'object';
const properties = { ...result.properties };
const requiredSet = new Set(Array.isArray(result.required) ? result.required : []);
for (const key in ref) {
const val = ref[key];
if (!val) {
continue;
}
const optional = key.endsWith('?');
const cleanKey = optional ? key.slice(0, -1) : key;
const baseProp = properties[cleanKey];
properties[cleanKey] = toSchemaObject(baseProp || {}, val);
if (optional) {
requiredSet.delete(cleanKey);
}
else {
requiredSet.add(cleanKey);
}
}
result.properties = properties;
result.required = Array.from(requiredSet);
return result;
}
return result;
}
function schemaTypeToPrimitiveType(t) {
if (t === null) {
return 'null';
}
if (t === undefined) {
return 'undefined';
}
if (!t) {
return 'unknown';
}
if (t === 'integer') {
return 'number';
}
return t;
}
// Convert existing OpenAPI SchemaObject -> Schema (best-effort, for handler input)
function toSchemaSpec(obj) {
if (!obj || typeof obj !== 'object') {
return 'unknown';
}
// Union keywords
if (Array.isArray(obj.oneOf)) {
const arr = obj.oneOf;
return { oneOf: arr.map(item => toSchemaSpec(item)) };
}
if (Array.isArray(obj.anyOf)) {
const arr = obj.anyOf;
return { anyOf: arr.map(item => toSchemaSpec(item)) };
}
if (Array.isArray(obj.allOf)) {
const arr = obj.allOf;
return { allOf: arr.map(item => toSchemaSpec(item)) };
}
// Enum
if (Array.isArray(obj.enum) && obj.enum.length > 0) {
const type = typeof obj.type === 'string' ? obj.type : undefined;
return { enum: obj.enum, type };
}
// Array
if (obj.type === 'array' || obj.items) {
const items = obj.items;
if (Array.isArray(items)) {
return { type: 'array', items: items.map((it) => toSchemaSpec(it)) };
}
if (items) {
return { type: 'array', items: toSchemaSpec(items) };
}
return { type: 'array', items: 'unknown' };
}
// Object
if (obj.type === 'object' || obj.properties) {
const properties = obj.properties || {};
const requiredSet = new Set(Array.isArray(obj.required) ? obj.required : []);
const result = {};
for (const key of Object.keys(properties)) {
const spec = toSchemaSpec(properties[key]);
const finalKey = requiredSet.has(key) ? key : `${key}?`;
result[finalKey] = spec;
}
return result;
}
// type union as array
if (Array.isArray(obj.type)) {
const typeArr = obj.type;
const mapped = typeArr.map(schemaTypeToPrimitiveType);
return { oneOf: mapped };
}
return schemaTypeToPrimitiveType(obj.type);
}
// Replace whole schema based on handler result (used for params/pathParams)
function applyModifierSchema(schema, config, { required }) {
if (!schema || typeof schema !== 'object') {
return schema;
}
const cloned = { ...schema };
const currentSpec = toSchemaSpec(cloned);
const ret = config.handler(currentSpec);
if (!ret) {
return {
required,
value: null,
};
}
if (typeof ret === 'object' && 'required' in ret && 'value' in ret) {
return {
required: !!(ret.required ?? required),
value: toSchemaObject(cloned, ret.value),
};
}
return {
required,
value: toSchemaObject(cloned, ret),
};
}