Merge pull request #13458 from meganoob1337/strapi/fix/issue-13453-documentation-fix

fix #13453 Documentation Plugin doesn't generate Proper Type for the …
This commit is contained in:
markkaylor 2022-08-23 14:57:15 +02:00 committed by GitHub
commit f5a62af92b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 107 additions and 42 deletions

View File

@ -20,6 +20,18 @@ const { hasFindMethod, isLocalizedPath } = require('./utils/routes');
const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => { const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
// Store response and request schemas in an object // Store response and request schemas in an object
let schemas = {}; let schemas = {};
let componentSchemas = {};
// adds a ComponentSchema to the Schemas so it can be used as Ref
const addComponentSchema = (schemaName, schema) => {
if (!Object.keys(schema) || !Object.keys(schema.properties)) {
return false;
}
componentSchemas = {
...componentSchemas,
[schemaName]: schema,
};
return true;
};
// Get all the route methods // Get all the route methods
const routeMethods = routeInfo.routes.map((route) => route.method); const routeMethods = routeInfo.routes.map((route) => route.method);
// Check for localized paths // Check for localized paths
@ -56,7 +68,7 @@ const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
[`${pascalCase(uniqueName)}LocalizationRequest`]: { [`${pascalCase(uniqueName)}LocalizationRequest`]: {
required: [...requiredAttributes, 'locale'], required: [...requiredAttributes, 'locale'],
type: 'object', type: 'object',
properties: cleanSchemaAttributes(attributesForRequest, { isRequest: true }), properties: cleanSchemaAttributes(attributesForRequest, { isRequest: true, addComponentSchema }),
}, },
}; };
} }
@ -71,7 +83,7 @@ const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
data: { data: {
required: requiredAttributes, required: requiredAttributes,
type: 'object', type: 'object',
properties: cleanSchemaAttributes(attributesForRequest, { isRequest: true }), properties: cleanSchemaAttributes(attributesForRequest, { isRequest: true, addComponentSchema }),
}, },
}, },
}, },
@ -85,7 +97,7 @@ const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
type: 'object', type: 'object',
properties: { properties: {
id: { type: 'string' }, id: { type: 'string' },
...cleanSchemaAttributes(attributes), ...cleanSchemaAttributes(attributes, { addComponentSchema }),
}, },
}, },
}; };
@ -97,17 +109,37 @@ const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
// Build the list response schema // Build the list response schema
schemas = { schemas = {
...schemas, ...schemas,
[`${pascalCase(uniqueName)}ListResponse`]: { [`${pascalCase(uniqueName)}ListResponseDataItem`]: {
type: 'object', type: 'object',
properties: {
id: { type: 'string' },
attributes: {
type: 'object',
properties: cleanSchemaAttributes(attributes, {
addComponentSchema,
componentSchemaRefName: `#/components/schemas/${pascalCase(
uniqueName
)}ListResponseDataItemLocalized`,
}),
},
},
},
[`${pascalCase(uniqueName)}ListResponseDataItemLocalized`]: {
type: 'object',
properties: {
id: { type: 'string' },
attributes: {
type: 'object',
properties: cleanSchemaAttributes(attributes, { addComponentSchema }),
},
},
},
[`${pascalCase(uniqueName)}ListResponse`]: {
properties: { properties: {
data: { data: {
type: 'array', type: 'array',
items: { items: {
type: 'object', $ref: `#/components/schemas/${pascalCase(uniqueName)}ListResponseDataItem`,
properties: {
id: { type: 'string' },
attributes: { type: 'object', properties: cleanSchemaAttributes(attributes) },
},
}, },
}, },
meta: { meta: {
@ -131,22 +163,41 @@ const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
// Build the response schema // Build the response schema
schemas = { schemas = {
...schemas, ...schemas,
[`${pascalCase(uniqueName)}Response`]: { [`${pascalCase(uniqueName)}ResponseDataObject`]: {
type: 'object', type: 'object',
properties: { properties: {
data: { id: { type: 'string' },
attributes: {
type: 'object', type: 'object',
properties: { properties: cleanSchemaAttributes(attributes, {
id: { type: 'string' }, addComponentSchema,
attributes: { type: 'object', properties: cleanSchemaAttributes(attributes) }, componentSchemaRefName: `#/components/schemas/${pascalCase(
}, uniqueName
)}ResponseDataObjectLocalized`,
}),
},
},
},
[`${pascalCase(uniqueName)}ResponseDataObjectLocalized`]: {
type: 'object',
properties: {
id: { type: 'string' },
attributes: {
type: 'object',
properties: cleanSchemaAttributes(attributes, { addComponentSchema }),
},
},
},
[`${pascalCase(uniqueName)}Response`]: {
properties: {
data: {
$ref: `#/components/schemas/${pascalCase(uniqueName)}ResponseDataObject`,
}, },
meta: { type: 'object' }, meta: { type: 'object' },
}, },
}, },
}; };
return { ...schemas, ...componentSchemas };
return schemas;
}; };
const buildComponentSchema = (api) => { const buildComponentSchema = (api) => {

View File

@ -2,15 +2,18 @@
const _ = require('lodash'); const _ = require('lodash');
const getSchemaData = require('./get-schema-data'); const getSchemaData = require('./get-schema-data');
const pascalCase = require('./pascal-case');
/** /**
* @description - Converts types found on attributes to OpenAPI acceptable data types * @description - Converts types found on attributes to OpenAPI acceptable data types
* *
* @param {object} attributes - The attributes found on a contentType * @param {object} attributes - The attributes found on a contentType
* @param {{ typeMap: Map, isRequest: boolean }} opts * @param {{ typeMap: Map, isRequest: boolean, addComponentSchema: function, componentSchemaRefName: string }} opts
* @returns Attributes using OpenAPI acceptable data types * @returns Attributes using OpenAPI acceptable data types
*/ */
const cleanSchemaAttributes = (attributes, { typeMap = new Map(), isRequest = false } = {}) => { const cleanSchemaAttributes = (
attributes,
{ typeMap = new Map(), isRequest = false, addComponentSchema = () => {}, componentSchemaRefName = '' } = {}
) => {
const attributesCopy = _.cloneDeep(attributes); const attributesCopy = _.cloneDeep(attributes);
for (const prop of Object.keys(attributesCopy)) { for (const prop of Object.keys(attributesCopy)) {
@ -86,43 +89,49 @@ const cleanSchemaAttributes = (attributes, { typeMap = new Map(), isRequest = fa
} }
case 'component': { case 'component': {
const componentAttributes = strapi.components[attribute.component].attributes; const componentAttributes = strapi.components[attribute.component].attributes;
const rawComponentSchema = {
type: 'object',
properties: {
...(isRequest ? {} : { id: { type: 'string' } }),
...cleanSchemaAttributes(componentAttributes, {
typeMap,
isRequest,
}),
},
};
const refComponentSchema = {
$ref: `#/components/schemas/${pascalCase(attribute.component)}Component`,
};
const componentExists = addComponentSchema(
`${pascalCase(attribute.component)}Component`,
rawComponentSchema
);
const finalComponentSchema = componentExists ? refComponentSchema : rawComponentSchema;
if (attribute.repeatable) { if (attribute.repeatable) {
attributesCopy[prop] = { attributesCopy[prop] = {
type: 'array', type: 'array',
items: { items: finalComponentSchema,
type: 'object',
properties: {
...(isRequest ? {} : { id: { type: 'string' } }),
...cleanSchemaAttributes(componentAttributes, { typeMap, isRequest }),
},
},
}; };
} else { } else {
attributesCopy[prop] = { attributesCopy[prop] = finalComponentSchema;
type: 'object',
properties: {
...(isRequest ? {} : { id: { type: 'string' } }),
...cleanSchemaAttributes(componentAttributes, {
typeMap,
isRequest,
}),
},
};
} }
break; break;
} }
case 'dynamiczone': { case 'dynamiczone': {
const components = attribute.components.map((component) => { const components = attribute.components.map((component) => {
const componentAttributes = strapi.components[component].attributes; const componentAttributes = strapi.components[component].attributes;
return { const rawComponentSchema = {
type: 'object', type: 'object',
properties: { properties: {
...(isRequest ? {} : { id: { type: 'string' } }), ...(isRequest ? {} : { id: { type: 'string' } }),
__component: { type: 'string' }, __component: { type: 'string' },
...cleanSchemaAttributes(componentAttributes, { typeMap, isRequest }), ...cleanSchemaAttributes(componentAttributes, { typeMap, isRequest, addComponentSchema }),
}, },
}; };
const refComponentSchema = { $ref: `#/components/schemas/${pascalCase(component)}` };
const componentExists = addComponentSchema(pascalCase(component), rawComponentSchema);
const finalComponentSchema = componentExists ? refComponentSchema : rawComponentSchema;
return finalComponentSchema;
}); });
attributesCopy[prop] = { attributesCopy[prop] = {
@ -171,8 +180,13 @@ const cleanSchemaAttributes = (attributes, { typeMap = new Map(), isRequest = fa
if (prop === 'localizations') { if (prop === 'localizations') {
attributesCopy[prop] = { attributesCopy[prop] = {
type: 'array', type: 'object',
items: { type: 'object', properties: {} }, properties: {
data: {
type: 'array',
items: componentSchemaRefName.length ? { $ref: componentSchemaRefName } : {},
},
},
}; };
break; break;
} }