2021-09-02 11:25:24 +02:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const _ = require('lodash');
|
|
|
|
const getSchemaData = require('./get-schema-data');
|
2022-06-03 14:57:30 +02:00
|
|
|
const pascalCase = require('./pascal-case');
|
2021-09-02 11:25:24 +02:00
|
|
|
/**
|
2022-03-17 16:54:37 +01:00
|
|
|
* @description - Converts types found on attributes to OpenAPI acceptable data types
|
2021-10-19 09:39:10 +02:00
|
|
|
*
|
2021-09-02 11:25:24 +02:00
|
|
|
* @param {object} attributes - The attributes found on a contentType
|
2022-08-01 13:44:21 +02:00
|
|
|
* @param {{ typeMap: Map, isRequest: boolean, addComponentSchema: function, componentSchemaRefName: string }} opts
|
2021-09-02 11:25:24 +02:00
|
|
|
* @returns Attributes using OpenAPI acceptable data types
|
|
|
|
*/
|
2022-06-30 13:01:19 +02:00
|
|
|
const cleanSchemaAttributes = (
|
|
|
|
attributes,
|
2022-08-23 15:58:05 +02:00
|
|
|
{
|
|
|
|
typeMap = new Map(),
|
|
|
|
isRequest = false,
|
|
|
|
addComponentSchema = () => {},
|
|
|
|
componentSchemaRefName = '',
|
|
|
|
} = {}
|
2022-06-30 13:01:19 +02:00
|
|
|
) => {
|
2021-09-02 11:25:24 +02:00
|
|
|
const attributesCopy = _.cloneDeep(attributes);
|
|
|
|
|
2022-08-08 23:33:39 +02:00
|
|
|
for (const prop of Object.keys(attributesCopy)) {
|
2021-09-02 11:25:24 +02:00
|
|
|
const attribute = attributesCopy[prop];
|
|
|
|
if (attribute.default) {
|
|
|
|
delete attributesCopy[prop].default;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (attribute.type) {
|
2021-10-19 10:55:11 +02:00
|
|
|
case 'password': {
|
|
|
|
if (!isRequest) {
|
|
|
|
delete attributesCopy[prop];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
attributesCopy[prop] = { type: 'string', format: 'password', example: '*******' };
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'email': {
|
|
|
|
attributesCopy[prop] = { type: 'string', format: 'email' };
|
|
|
|
break;
|
|
|
|
}
|
2021-10-19 09:39:10 +02:00
|
|
|
case 'string':
|
2021-10-13 12:39:34 -04:00
|
|
|
case 'text':
|
2021-10-19 10:55:11 +02:00
|
|
|
case 'richtext': {
|
2021-09-02 11:25:24 +02:00
|
|
|
attributesCopy[prop] = { type: 'string' };
|
|
|
|
break;
|
|
|
|
}
|
2021-10-19 10:55:11 +02:00
|
|
|
case 'timestamp': {
|
|
|
|
attributesCopy[prop] = { type: 'string', format: 'timestamp', example: Date.now() };
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'time': {
|
|
|
|
attributesCopy[prop] = { type: 'string', format: 'time', example: '12:54.000' };
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'date': {
|
|
|
|
attributesCopy[prop] = { type: 'string', format: 'date' };
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'datetime': {
|
|
|
|
attributesCopy[prop] = { type: 'string', format: 'date-time' };
|
|
|
|
break;
|
|
|
|
}
|
2021-10-19 09:39:10 +02:00
|
|
|
case 'boolean': {
|
|
|
|
attributesCopy[prop] = { type: 'boolean' };
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'enumeration': {
|
|
|
|
attributesCopy[prop] = { type: 'string', enum: attribute.enum };
|
|
|
|
break;
|
|
|
|
}
|
2021-10-13 12:39:34 -04:00
|
|
|
case 'decimal':
|
|
|
|
case 'float': {
|
2021-09-02 11:25:24 +02:00
|
|
|
attributesCopy[prop] = { type: 'number', format: 'float' };
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'integer': {
|
|
|
|
attributesCopy[prop] = { type: 'integer' };
|
|
|
|
break;
|
|
|
|
}
|
2021-10-19 10:55:11 +02:00
|
|
|
case 'biginteger': {
|
|
|
|
attributesCopy[prop] = { type: 'string', pattern: '^\\d*$', example: '123456789' };
|
|
|
|
break;
|
|
|
|
}
|
2021-09-02 11:25:24 +02:00
|
|
|
case 'json': {
|
|
|
|
attributesCopy[prop] = {};
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'uid': {
|
2021-10-19 10:55:11 +02:00
|
|
|
attributesCopy[prop] = { type: 'string' };
|
2021-09-02 11:25:24 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'component': {
|
|
|
|
const componentAttributes = strapi.components[attribute.component].attributes;
|
2022-06-30 13:01:19 +02:00
|
|
|
const rawComponentSchema = {
|
|
|
|
type: 'object',
|
|
|
|
properties: {
|
2022-09-06 05:35:56 +00:00
|
|
|
...(isRequest ? {} : { id: { type: 'number' } }),
|
2022-06-30 13:01:19 +02:00
|
|
|
...cleanSchemaAttributes(componentAttributes, {
|
|
|
|
typeMap,
|
|
|
|
isRequest,
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
const refComponentSchema = {
|
2022-08-01 13:44:21 +02:00
|
|
|
$ref: `#/components/schemas/${pascalCase(attribute.component)}Component`,
|
2022-06-30 13:01:19 +02:00
|
|
|
};
|
2022-08-01 13:44:21 +02:00
|
|
|
const componentExists = addComponentSchema(
|
2022-06-30 13:01:19 +02:00
|
|
|
`${pascalCase(attribute.component)}Component`,
|
|
|
|
rawComponentSchema
|
|
|
|
);
|
|
|
|
const finalComponentSchema = componentExists ? refComponentSchema : rawComponentSchema;
|
2021-10-13 12:39:34 -04:00
|
|
|
if (attribute.repeatable) {
|
|
|
|
attributesCopy[prop] = {
|
|
|
|
type: 'array',
|
2022-06-30 13:01:19 +02:00
|
|
|
items: finalComponentSchema,
|
2021-10-13 12:39:34 -04:00
|
|
|
};
|
|
|
|
} else {
|
2022-06-30 13:01:19 +02:00
|
|
|
attributesCopy[prop] = finalComponentSchema;
|
2021-10-19 09:39:10 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'dynamiczone': {
|
2022-08-08 23:33:39 +02:00
|
|
|
const components = attribute.components.map((component) => {
|
2021-10-19 09:39:10 +02:00
|
|
|
const componentAttributes = strapi.components[component].attributes;
|
2022-06-30 13:01:19 +02:00
|
|
|
const rawComponentSchema = {
|
2021-10-19 09:39:10 +02:00
|
|
|
type: 'object',
|
|
|
|
properties: {
|
2022-08-31 10:37:08 +00:00
|
|
|
...(isRequest ? {} : { id: { type: 'number' } }),
|
2021-10-19 09:39:10 +02:00
|
|
|
__component: { type: 'string' },
|
2022-08-23 15:58:05 +02:00
|
|
|
...cleanSchemaAttributes(componentAttributes, {
|
|
|
|
typeMap,
|
|
|
|
isRequest,
|
|
|
|
addComponentSchema,
|
|
|
|
}),
|
2021-10-13 12:39:34 -04:00
|
|
|
},
|
|
|
|
};
|
2022-06-30 13:01:19 +02:00
|
|
|
const refComponentSchema = { $ref: `#/components/schemas/${pascalCase(component)}` };
|
2022-08-01 13:44:21 +02:00
|
|
|
const componentExists = addComponentSchema(pascalCase(component), rawComponentSchema);
|
2022-06-30 13:01:19 +02:00
|
|
|
const finalComponentSchema = componentExists ? refComponentSchema : rawComponentSchema;
|
|
|
|
return finalComponentSchema;
|
2021-10-19 09:39:10 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
attributesCopy[prop] = {
|
|
|
|
type: 'array',
|
|
|
|
items: {
|
|
|
|
anyOf: components,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'media': {
|
|
|
|
const imageAttributes = strapi.contentType('plugin::upload.file').attributes;
|
|
|
|
const isListOfEntities = attribute.multiple;
|
|
|
|
|
|
|
|
if (isRequest) {
|
|
|
|
const oneOfType = {
|
|
|
|
oneOf: [{ type: 'integer' }, { type: 'string' }],
|
|
|
|
example: 'string or id',
|
|
|
|
};
|
|
|
|
|
|
|
|
attributesCopy[prop] = isListOfEntities ? { type: 'array', items: oneOfType } : oneOfType;
|
|
|
|
break;
|
2021-10-13 12:39:34 -04:00
|
|
|
}
|
2021-10-19 09:39:10 +02:00
|
|
|
|
|
|
|
attributesCopy[prop] = {
|
|
|
|
type: 'object',
|
|
|
|
properties: {
|
|
|
|
data: getSchemaData(isListOfEntities, cleanSchemaAttributes(imageAttributes)),
|
|
|
|
},
|
|
|
|
};
|
2021-09-02 11:25:24 +02:00
|
|
|
break;
|
|
|
|
}
|
2021-10-19 09:39:10 +02:00
|
|
|
|
2021-09-02 11:25:24 +02:00
|
|
|
case 'relation': {
|
|
|
|
const isListOfEntities = attribute.relation.includes('ToMany');
|
2021-10-19 09:39:10 +02:00
|
|
|
|
|
|
|
if (isRequest) {
|
|
|
|
const oneOfType = {
|
|
|
|
oneOf: [{ type: 'integer' }, { type: 'string' }],
|
|
|
|
example: 'string or id',
|
|
|
|
};
|
|
|
|
|
|
|
|
attributesCopy[prop] = isListOfEntities ? { type: 'array', items: oneOfType } : oneOfType;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-05-05 12:32:22 +02:00
|
|
|
if (prop === 'localizations') {
|
|
|
|
attributesCopy[prop] = {
|
2022-06-03 14:57:30 +02:00
|
|
|
type: 'object',
|
2022-06-30 13:01:19 +02:00
|
|
|
properties: {
|
|
|
|
data: {
|
|
|
|
type: 'array',
|
|
|
|
items: componentSchemaRefName.length ? { $ref: componentSchemaRefName } : {},
|
|
|
|
},
|
|
|
|
},
|
2022-05-05 12:32:22 +02:00
|
|
|
};
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-10-08 12:06:16 -04:00
|
|
|
if (!attribute.target || typeMap.has(attribute.target)) {
|
|
|
|
attributesCopy[prop] = {
|
|
|
|
type: 'object',
|
|
|
|
properties: { data: getSchemaData(isListOfEntities, {}) },
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
typeMap.set(attribute.target, true);
|
|
|
|
const targetAttributes = strapi.contentType(attribute.target).attributes;
|
|
|
|
|
2021-09-02 11:25:24 +02:00
|
|
|
attributesCopy[prop] = {
|
|
|
|
type: 'object',
|
|
|
|
properties: {
|
2021-10-19 09:39:10 +02:00
|
|
|
data: getSchemaData(
|
|
|
|
isListOfEntities,
|
|
|
|
cleanSchemaAttributes(targetAttributes, { typeMap, isRequest })
|
|
|
|
),
|
2021-09-02 11:25:24 +02:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2021-10-19 09:39:10 +02:00
|
|
|
default: {
|
|
|
|
throw new Error(`Invalid type ${attribute.type} while generating open api schema.`);
|
2021-10-13 12:39:34 -04:00
|
|
|
}
|
2021-09-02 11:25:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return attributesCopy;
|
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = cleanSchemaAttributes;
|