@strapi/plugin-documentation 0.0.0-02af04644a1b236c1add59b27e2da1cfd7843fc5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +151 -0
  3. package/__mocks__/strapi.js +41 -0
  4. package/__tests__/build-component-schema.test.js +271 -0
  5. package/admin/src/components/FieldActionWrapper/index.js +14 -0
  6. package/admin/src/components/PluginIcon/index.js +12 -0
  7. package/admin/src/index.js +80 -0
  8. package/admin/src/pages/PluginPage/index.js +199 -0
  9. package/admin/src/pages/PluginPage/tests/index.test.js +873 -0
  10. package/admin/src/pages/PluginPage/tests/server.js +23 -0
  11. package/admin/src/pages/SettingsPage/index.js +181 -0
  12. package/admin/src/pages/SettingsPage/tests/index.test.js +612 -0
  13. package/admin/src/pages/SettingsPage/tests/server.js +18 -0
  14. package/admin/src/pages/utils/api.js +31 -0
  15. package/admin/src/pages/utils/schema.js +11 -0
  16. package/admin/src/pages/utils/useReactQuery.js +46 -0
  17. package/admin/src/permissions.js +19 -0
  18. package/admin/src/pluginId.js +5 -0
  19. package/admin/src/translations/ar.json +20 -0
  20. package/admin/src/translations/cs.json +21 -0
  21. package/admin/src/translations/de.json +26 -0
  22. package/admin/src/translations/dk.json +39 -0
  23. package/admin/src/translations/en.json +39 -0
  24. package/admin/src/translations/es.json +39 -0
  25. package/admin/src/translations/fr.json +26 -0
  26. package/admin/src/translations/id.json +24 -0
  27. package/admin/src/translations/it.json +26 -0
  28. package/admin/src/translations/ko.json +39 -0
  29. package/admin/src/translations/ms.json +23 -0
  30. package/admin/src/translations/nl.json +21 -0
  31. package/admin/src/translations/pl.json +39 -0
  32. package/admin/src/translations/pt-BR.json +21 -0
  33. package/admin/src/translations/pt.json +21 -0
  34. package/admin/src/translations/ru.json +28 -0
  35. package/admin/src/translations/sk.json +24 -0
  36. package/admin/src/translations/th.json +24 -0
  37. package/admin/src/translations/tr.json +20 -0
  38. package/admin/src/translations/uk.json +23 -0
  39. package/admin/src/translations/vi.json +24 -0
  40. package/admin/src/translations/zh-Hans.json +28 -0
  41. package/admin/src/translations/zh.json +24 -0
  42. package/admin/src/utils/getTrad.js +5 -0
  43. package/admin/src/utils/index.js +2 -0
  44. package/admin/src/utils/openWithNewTab.js +20 -0
  45. package/package.json +66 -0
  46. package/server/bootstrap.js +54 -0
  47. package/server/config/default-plugin-config.js +74 -0
  48. package/server/config/index.js +7 -0
  49. package/server/controllers/documentation.js +241 -0
  50. package/server/controllers/index.js +7 -0
  51. package/server/index.js +17 -0
  52. package/server/middlewares/documentation.js +25 -0
  53. package/server/middlewares/index.js +7 -0
  54. package/server/middlewares/restrict-access.js +24 -0
  55. package/server/public/index.html +70 -0
  56. package/server/public/login.html +145 -0
  57. package/server/register.js +11 -0
  58. package/server/routes/index.js +84 -0
  59. package/server/services/documentation.js +210 -0
  60. package/server/services/helpers/build-api-endpoint-path.js +185 -0
  61. package/server/services/helpers/build-component-schema.js +216 -0
  62. package/server/services/helpers/index.js +9 -0
  63. package/server/services/helpers/utils/clean-schema-attributes.js +235 -0
  64. package/server/services/helpers/utils/get-api-responses.js +105 -0
  65. package/server/services/helpers/utils/get-schema-data.js +32 -0
  66. package/server/services/helpers/utils/loop-content-type-names.js +53 -0
  67. package/server/services/helpers/utils/pascal-case.js +9 -0
  68. package/server/services/helpers/utils/query-params.js +95 -0
  69. package/server/services/helpers/utils/routes.js +10 -0
  70. package/server/services/index.js +7 -0
  71. package/strapi-admin.js +3 -0
  72. package/strapi-server.js +3 -0
@@ -0,0 +1,216 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+
5
+ const cleanSchemaAttributes = require('./utils/clean-schema-attributes');
6
+ const loopContentTypeNames = require('./utils/loop-content-type-names');
7
+ const pascalCase = require('./utils/pascal-case');
8
+ const { hasFindMethod, isLocalizedPath } = require('./utils/routes');
9
+
10
+ /**
11
+ * @decription Get all open api schema objects for a given content type
12
+ *
13
+ * @param {object} apiInfo
14
+ * @property {string} apiInfo.uniqueName - Api name | Api name + Content type name
15
+ * @property {object} apiInfo.attributes - Attributes on content type
16
+ * @property {object} apiInfo.routeInfo - The routes for the api
17
+ *
18
+ * @returns {object} Open API schemas
19
+ */
20
+ const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
21
+ // Store response and request schemas in an object
22
+ let schemas = {};
23
+ let componentSchemas = {};
24
+ // adds a ComponentSchema to the Schemas so it can be used as Ref
25
+ const addComponentSchema = (schemaName, schema) => {
26
+ if (!Object.keys(schema) || !Object.keys(schema.properties)) {
27
+ return false;
28
+ }
29
+ componentSchemas = {
30
+ ...componentSchemas,
31
+ [schemaName]: schema,
32
+ };
33
+ return true;
34
+ };
35
+ // Get all the route methods
36
+ const routeMethods = routeInfo.routes.map((route) => route.method);
37
+ // Check for localized paths
38
+ const hasLocalizationPath = routeInfo.routes.filter((route) =>
39
+ isLocalizedPath(route.path)
40
+ ).length;
41
+ // When the route methods contain any post or put requests
42
+ if (routeMethods.includes('POST') || routeMethods.includes('PUT')) {
43
+ const attributesToOmit = [
44
+ 'createdAt',
45
+ 'updatedAt',
46
+ 'publishedAt',
47
+ 'publishedBy',
48
+ 'updatedBy',
49
+ 'createdBy',
50
+ 'localizations',
51
+ ];
52
+ const attributesForRequest = _.omit(attributes, attributesToOmit);
53
+
54
+ // Get a list of required attribute names
55
+ const requiredAttributes = Object.entries(attributesForRequest).reduce((acc, attribute) => {
56
+ const [attributeKey, attributeValue] = attribute;
57
+
58
+ if (attributeValue.required) {
59
+ acc.push(attributeKey);
60
+ }
61
+
62
+ return acc;
63
+ }, []);
64
+
65
+ if (hasLocalizationPath) {
66
+ schemas = {
67
+ ...schemas,
68
+ [`${pascalCase(uniqueName)}LocalizationRequest`]: {
69
+ required: [...requiredAttributes, 'locale'],
70
+ type: 'object',
71
+ properties: cleanSchemaAttributes(attributesForRequest, {
72
+ isRequest: true,
73
+ addComponentSchema,
74
+ }),
75
+ },
76
+ };
77
+ }
78
+
79
+ // Build the request schema
80
+ schemas = {
81
+ ...schemas,
82
+ [`${pascalCase(uniqueName)}Request`]: {
83
+ type: 'object',
84
+ required: ['data'],
85
+ properties: {
86
+ data: {
87
+ required: requiredAttributes,
88
+ type: 'object',
89
+ properties: cleanSchemaAttributes(attributesForRequest, {
90
+ isRequest: true,
91
+ addComponentSchema,
92
+ }),
93
+ },
94
+ },
95
+ },
96
+ };
97
+ }
98
+
99
+ if (hasLocalizationPath) {
100
+ schemas = {
101
+ ...schemas,
102
+ [`${pascalCase(uniqueName)}LocalizationResponse`]: {
103
+ type: 'object',
104
+ properties: {
105
+ id: { type: 'number' },
106
+ ...cleanSchemaAttributes(attributes, { addComponentSchema }),
107
+ },
108
+ },
109
+ };
110
+ }
111
+
112
+ // Check for routes that need to return a list
113
+ const hasListOfEntities = routeInfo.routes.filter((route) => hasFindMethod(route.handler)).length;
114
+ if (hasListOfEntities) {
115
+ // Build the list response schema
116
+ schemas = {
117
+ ...schemas,
118
+ [`${pascalCase(uniqueName)}ListResponseDataItem`]: {
119
+ type: 'object',
120
+ properties: {
121
+ id: { type: 'number' },
122
+ attributes: {
123
+ type: 'object',
124
+ properties: cleanSchemaAttributes(attributes, {
125
+ addComponentSchema,
126
+ componentSchemaRefName: `#/components/schemas/${pascalCase(
127
+ uniqueName
128
+ )}ListResponseDataItemLocalized`,
129
+ }),
130
+ },
131
+ },
132
+ },
133
+ [`${pascalCase(uniqueName)}ListResponseDataItemLocalized`]: {
134
+ type: 'object',
135
+ properties: {
136
+ id: { type: 'number' },
137
+ attributes: {
138
+ type: 'object',
139
+ properties: cleanSchemaAttributes(attributes, { addComponentSchema }),
140
+ },
141
+ },
142
+ },
143
+ [`${pascalCase(uniqueName)}ListResponse`]: {
144
+ properties: {
145
+ data: {
146
+ type: 'array',
147
+ items: {
148
+ $ref: `#/components/schemas/${pascalCase(uniqueName)}ListResponseDataItem`,
149
+ },
150
+ },
151
+ meta: {
152
+ type: 'object',
153
+ properties: {
154
+ pagination: {
155
+ properties: {
156
+ page: { type: 'integer' },
157
+ pageSize: { type: 'integer', minimum: 25 },
158
+ pageCount: { type: 'integer', maximum: 1 },
159
+ total: { type: 'integer' },
160
+ },
161
+ },
162
+ },
163
+ },
164
+ },
165
+ },
166
+ };
167
+ }
168
+
169
+ // Build the response schema
170
+ schemas = {
171
+ ...schemas,
172
+ [`${pascalCase(uniqueName)}ResponseDataObject`]: {
173
+ type: 'object',
174
+ properties: {
175
+ id: { type: 'number' },
176
+ attributes: {
177
+ type: 'object',
178
+ properties: cleanSchemaAttributes(attributes, {
179
+ addComponentSchema,
180
+ componentSchemaRefName: `#/components/schemas/${pascalCase(
181
+ uniqueName
182
+ )}ResponseDataObjectLocalized`,
183
+ }),
184
+ },
185
+ },
186
+ },
187
+ [`${pascalCase(uniqueName)}ResponseDataObjectLocalized`]: {
188
+ type: 'object',
189
+ properties: {
190
+ id: { type: 'number' },
191
+ attributes: {
192
+ type: 'object',
193
+ properties: cleanSchemaAttributes(attributes, { addComponentSchema }),
194
+ },
195
+ },
196
+ },
197
+ [`${pascalCase(uniqueName)}Response`]: {
198
+ properties: {
199
+ data: {
200
+ $ref: `#/components/schemas/${pascalCase(uniqueName)}ResponseDataObject`,
201
+ },
202
+ meta: { type: 'object' },
203
+ },
204
+ },
205
+ };
206
+ return { ...schemas, ...componentSchemas };
207
+ };
208
+
209
+ const buildComponentSchema = (api) => {
210
+ // A reusable loop for building paths and component schemas
211
+ // Uses the api param to build a new set of params for each content type
212
+ // Passes these new params to the function provided
213
+ return loopContentTypeNames(api, getAllSchemasForContentType);
214
+ };
215
+
216
+ module.exports = buildComponentSchema;
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const builApiEndpointPath = require('./build-api-endpoint-path');
4
+ const buildComponentSchema = require('./build-component-schema');
5
+
6
+ module.exports = {
7
+ builApiEndpointPath,
8
+ buildComponentSchema,
9
+ };
@@ -0,0 +1,235 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+ const getSchemaData = require('./get-schema-data');
5
+ const pascalCase = require('./pascal-case');
6
+ /**
7
+ * @description - Converts types found on attributes to OpenAPI acceptable data types
8
+ *
9
+ * @param {object} attributes - The attributes found on a contentType
10
+ * @param {{ typeMap: Map, isRequest: boolean, addComponentSchema: function, componentSchemaRefName: string }} opts
11
+ * @returns Attributes using OpenAPI acceptable data types
12
+ */
13
+ const cleanSchemaAttributes = (
14
+ attributes,
15
+ {
16
+ typeMap = new Map(),
17
+ isRequest = false,
18
+ addComponentSchema = () => {},
19
+ componentSchemaRefName = '',
20
+ } = {}
21
+ ) => {
22
+ const attributesCopy = _.cloneDeep(attributes);
23
+
24
+ for (const prop of Object.keys(attributesCopy)) {
25
+ const attribute = attributesCopy[prop];
26
+ if (attribute.default) {
27
+ delete attributesCopy[prop].default;
28
+ }
29
+
30
+ switch (attribute.type) {
31
+ case 'password': {
32
+ if (!isRequest) {
33
+ delete attributesCopy[prop];
34
+ break;
35
+ }
36
+
37
+ attributesCopy[prop] = { type: 'string', format: 'password', example: '*******' };
38
+ break;
39
+ }
40
+ case 'email': {
41
+ attributesCopy[prop] = { type: 'string', format: 'email' };
42
+ break;
43
+ }
44
+ case 'string':
45
+ case 'text':
46
+ case 'richtext': {
47
+ attributesCopy[prop] = { type: 'string' };
48
+ break;
49
+ }
50
+ case 'timestamp': {
51
+ attributesCopy[prop] = { type: 'string', format: 'timestamp', example: Date.now() };
52
+ break;
53
+ }
54
+ case 'time': {
55
+ attributesCopy[prop] = { type: 'string', format: 'time', example: '12:54.000' };
56
+ break;
57
+ }
58
+ case 'date': {
59
+ attributesCopy[prop] = { type: 'string', format: 'date' };
60
+ break;
61
+ }
62
+ case 'datetime': {
63
+ attributesCopy[prop] = { type: 'string', format: 'date-time' };
64
+ break;
65
+ }
66
+ case 'boolean': {
67
+ attributesCopy[prop] = { type: 'boolean' };
68
+ break;
69
+ }
70
+ case 'enumeration': {
71
+ attributesCopy[prop] = { type: 'string', enum: attribute.enum };
72
+ break;
73
+ }
74
+ case 'decimal':
75
+ case 'float': {
76
+ attributesCopy[prop] = { type: 'number', format: 'float' };
77
+ break;
78
+ }
79
+ case 'integer': {
80
+ attributesCopy[prop] = { type: 'integer' };
81
+ break;
82
+ }
83
+ case 'biginteger': {
84
+ attributesCopy[prop] = { type: 'string', pattern: '^\\d*$', example: '123456789' };
85
+ break;
86
+ }
87
+ case 'json': {
88
+ attributesCopy[prop] = {};
89
+ break;
90
+ }
91
+ case 'uid': {
92
+ attributesCopy[prop] = { type: 'string' };
93
+ break;
94
+ }
95
+ case 'component': {
96
+ const componentAttributes = strapi.components[attribute.component].attributes;
97
+ const rawComponentSchema = {
98
+ type: 'object',
99
+ properties: {
100
+ ...(isRequest ? {} : { id: { type: 'number' } }),
101
+ ...cleanSchemaAttributes(componentAttributes, {
102
+ typeMap,
103
+ isRequest,
104
+ }),
105
+ },
106
+ };
107
+ const refComponentSchema = {
108
+ $ref: `#/components/schemas/${pascalCase(attribute.component)}Component`,
109
+ };
110
+ const componentExists = addComponentSchema(
111
+ `${pascalCase(attribute.component)}Component`,
112
+ rawComponentSchema
113
+ );
114
+ const finalComponentSchema = componentExists ? refComponentSchema : rawComponentSchema;
115
+ if (attribute.repeatable) {
116
+ attributesCopy[prop] = {
117
+ type: 'array',
118
+ items: finalComponentSchema,
119
+ };
120
+ } else {
121
+ attributesCopy[prop] = finalComponentSchema;
122
+ }
123
+ break;
124
+ }
125
+ case 'dynamiczone': {
126
+ const components = attribute.components.map((component) => {
127
+ const componentAttributes = strapi.components[component].attributes;
128
+ const rawComponentSchema = {
129
+ type: 'object',
130
+ properties: {
131
+ ...(isRequest ? {} : { id: { type: 'number' } }),
132
+ __component: { type: 'string' },
133
+ ...cleanSchemaAttributes(componentAttributes, {
134
+ typeMap,
135
+ isRequest,
136
+ addComponentSchema,
137
+ }),
138
+ },
139
+ };
140
+ const refComponentSchema = { $ref: `#/components/schemas/${pascalCase(component)}` };
141
+ const componentExists = addComponentSchema(pascalCase(component), rawComponentSchema);
142
+ const finalComponentSchema = componentExists ? refComponentSchema : rawComponentSchema;
143
+ return finalComponentSchema;
144
+ });
145
+
146
+ attributesCopy[prop] = {
147
+ type: 'array',
148
+ items: {
149
+ anyOf: components,
150
+ },
151
+ };
152
+ break;
153
+ }
154
+ case 'media': {
155
+ const imageAttributes = strapi.contentType('plugin::upload.file').attributes;
156
+ const isListOfEntities = attribute.multiple;
157
+
158
+ if (isRequest) {
159
+ const oneOfType = {
160
+ oneOf: [{ type: 'integer' }, { type: 'string' }],
161
+ example: 'string or id',
162
+ };
163
+
164
+ attributesCopy[prop] = isListOfEntities ? { type: 'array', items: oneOfType } : oneOfType;
165
+ break;
166
+ }
167
+
168
+ attributesCopy[prop] = {
169
+ type: 'object',
170
+ properties: {
171
+ data: getSchemaData(isListOfEntities, cleanSchemaAttributes(imageAttributes)),
172
+ },
173
+ };
174
+ break;
175
+ }
176
+
177
+ case 'relation': {
178
+ const isListOfEntities = attribute.relation.includes('ToMany');
179
+
180
+ if (isRequest) {
181
+ const oneOfType = {
182
+ oneOf: [{ type: 'integer' }, { type: 'string' }],
183
+ example: 'string or id',
184
+ };
185
+
186
+ attributesCopy[prop] = isListOfEntities ? { type: 'array', items: oneOfType } : oneOfType;
187
+ break;
188
+ }
189
+
190
+ if (prop === 'localizations') {
191
+ attributesCopy[prop] = {
192
+ type: 'object',
193
+ properties: {
194
+ data: {
195
+ type: 'array',
196
+ items: componentSchemaRefName.length ? { $ref: componentSchemaRefName } : {},
197
+ },
198
+ },
199
+ };
200
+ break;
201
+ }
202
+
203
+ if (!attribute.target || typeMap.has(attribute.target)) {
204
+ attributesCopy[prop] = {
205
+ type: 'object',
206
+ properties: { data: getSchemaData(isListOfEntities, {}) },
207
+ };
208
+ break;
209
+ }
210
+
211
+ typeMap.set(attribute.target, true);
212
+ const targetAttributes = strapi.contentType(attribute.target).attributes;
213
+
214
+ attributesCopy[prop] = {
215
+ type: 'object',
216
+ properties: {
217
+ data: getSchemaData(
218
+ isListOfEntities,
219
+ cleanSchemaAttributes(targetAttributes, { typeMap, isRequest })
220
+ ),
221
+ },
222
+ };
223
+
224
+ break;
225
+ }
226
+ default: {
227
+ throw new Error(`Invalid type ${attribute.type} while generating open api schema.`);
228
+ }
229
+ }
230
+ }
231
+
232
+ return attributesCopy;
233
+ };
234
+
235
+ module.exports = cleanSchemaAttributes;
@@ -0,0 +1,105 @@
1
+ 'use strict';
2
+
3
+ const pascalCase = require('./pascal-case');
4
+
5
+ /**
6
+ * @description - Builds the Swagger response object for a given api
7
+ *
8
+ * @param {object} name - Name of the api or plugin
9
+ * @param {object} route - The current route
10
+ * @param {boolean} isListOfEntities - Checks for a list of entitities
11
+ *
12
+ * @returns The Swagger responses
13
+ */
14
+ const getApiResponse = ({
15
+ uniqueName,
16
+ route,
17
+ isListOfEntities = false,
18
+ isLocalizationPath = false,
19
+ }) => {
20
+ const getSchema = () => {
21
+ if (route.method === 'DELETE') {
22
+ return {
23
+ type: 'integer',
24
+ format: 'int64',
25
+ };
26
+ }
27
+
28
+ if (isLocalizationPath) {
29
+ return { $ref: `#/components/schemas/${pascalCase(uniqueName)}LocalizationResponse` };
30
+ }
31
+
32
+ if (isListOfEntities) {
33
+ return { $ref: `#/components/schemas/${pascalCase(uniqueName)}ListResponse` };
34
+ }
35
+
36
+ return { $ref: `#/components/schemas/${pascalCase(uniqueName)}Response` };
37
+ };
38
+
39
+ const schema = getSchema();
40
+
41
+ return {
42
+ responses: {
43
+ 200: {
44
+ description: 'OK',
45
+ content: {
46
+ 'application/json': {
47
+ schema,
48
+ },
49
+ },
50
+ },
51
+ 400: {
52
+ description: 'Bad Request',
53
+ content: {
54
+ 'application/json': {
55
+ schema: {
56
+ $ref: '#/components/schemas/Error',
57
+ },
58
+ },
59
+ },
60
+ },
61
+ 401: {
62
+ description: 'Unauthorized',
63
+ content: {
64
+ 'application/json': {
65
+ schema: {
66
+ $ref: '#/components/schemas/Error',
67
+ },
68
+ },
69
+ },
70
+ },
71
+ 403: {
72
+ description: 'Forbidden',
73
+ content: {
74
+ 'application/json': {
75
+ schema: {
76
+ $ref: '#/components/schemas/Error',
77
+ },
78
+ },
79
+ },
80
+ },
81
+ 404: {
82
+ description: 'Not Found',
83
+ content: {
84
+ 'application/json': {
85
+ schema: {
86
+ $ref: '#/components/schemas/Error',
87
+ },
88
+ },
89
+ },
90
+ },
91
+ 500: {
92
+ description: 'Internal Server Error',
93
+ content: {
94
+ 'application/json': {
95
+ schema: {
96
+ $ref: '#/components/schemas/Error',
97
+ },
98
+ },
99
+ },
100
+ },
101
+ },
102
+ };
103
+ };
104
+
105
+ module.exports = getApiResponse;
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * @description Determines the format of the data response
5
+ *
6
+ * @param {boolean} isListOfEntities - Checks for a multiple entities
7
+ * @param {object} attributes - The attributes found on a contentType
8
+
9
+ * @returns object | array of attributes
10
+ */
11
+ module.exports = (isListOfEntities, attributes) => {
12
+ if (isListOfEntities) {
13
+ return {
14
+ type: 'array',
15
+ items: {
16
+ type: 'object',
17
+ properties: {
18
+ id: { type: 'number' },
19
+ attributes: { type: 'object', properties: attributes },
20
+ },
21
+ },
22
+ };
23
+ }
24
+
25
+ return {
26
+ type: 'object',
27
+ properties: {
28
+ id: { type: 'number' },
29
+ attributes: { type: 'object', properties: attributes },
30
+ },
31
+ };
32
+ };
@@ -0,0 +1,53 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+
5
+ /**
6
+ * @description A reusable loop for building api endpoint paths and component schemas
7
+ *
8
+ * @param {object} api - Api information to pass to the callback
9
+ * @param {function} callback - Logic to execute for the given api
10
+ *
11
+ * @returns {object}
12
+ */
13
+ const loopContentTypeNames = (api, callback) => {
14
+ let result = {};
15
+ for (const contentTypeName of api.ctNames) {
16
+ // Get the attributes found on the api's contentType
17
+ const uid = `${api.getter}::${api.name}.${contentTypeName}`;
18
+ const { attributes, info: contentTypeInfo } = strapi.contentType(uid);
19
+
20
+ // Get the routes for the current api
21
+ const routeInfo =
22
+ api.getter === 'plugin'
23
+ ? strapi.plugin(api.name).routes['content-api']
24
+ : strapi.api[api.name].routes[contentTypeName];
25
+
26
+ // Continue to next iteration if routeInfo is undefined
27
+ if (!routeInfo) continue;
28
+
29
+ // Uppercase the first letter of the api name
30
+ const apiName = _.upperFirst(api.name);
31
+
32
+ // Create a unique name if the api name and contentType name don't match
33
+ const uniqueName =
34
+ api.name === contentTypeName ? apiName : `${apiName} - ${_.upperFirst(contentTypeName)}`;
35
+
36
+ const apiInfo = {
37
+ ...api,
38
+ routeInfo,
39
+ attributes,
40
+ uniqueName,
41
+ contentTypeInfo,
42
+ };
43
+
44
+ result = {
45
+ ...result,
46
+ ...callback(apiInfo),
47
+ };
48
+ }
49
+
50
+ return result;
51
+ };
52
+
53
+ module.exports = loopContentTypeNames;
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+
5
+ const pascalCase = (string) => {
6
+ return _.upperFirst(_.camelCase(string));
7
+ };
8
+
9
+ module.exports = pascalCase;