@strapi/plugin-documentation 4.10.0-beta.1 → 4.10.1-experimental.0
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.
- package/admin/src/pages/PluginPage/index.js +3 -3
- package/admin/src/pages/utils/useReactQuery.js +34 -14
- package/jest.config.front.js +5 -0
- package/jest.config.js +5 -0
- package/package.json +8 -5
- package/server/config/default-plugin-config.js +2 -41
- package/server/services/__mocks__/mock-content-types.js +269 -0
- package/server/services/__mocks__/mock-strapi-data.js +183 -0
- package/server/services/__tests__/build-component-schema.test.js +761 -0
- package/server/services/__tests__/documentation.test.js +481 -0
- package/server/services/__tests__/override.test.js +85 -0
- package/server/services/documentation.js +123 -84
- package/server/services/helpers/build-api-endpoint-path.js +3 -2
- package/server/services/helpers/build-component-schema.js +108 -70
- package/server/services/helpers/utils/clean-schema-attributes.js +15 -7
- package/server/services/helpers/utils/loop-content-type-names.js +3 -1
- package/server/services/index.js +2 -0
- package/server/services/override.js +52 -0
- package/server/services/utils/default-openapi-components.js +40 -0
- package/server/services/utils/get-plugins-that-need-documentation.js +24 -0
- package/__mocks__/strapi.js +0 -41
- package/__tests__/build-component-schema.test.js +0 -271
- package/admin/src/pages/utils/api.js +0 -31
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { getPluginsThatNeedDocumentation } = require('./utils/get-plugins-that-need-documentation');
|
|
4
|
+
|
|
5
|
+
module.exports = ({ strapi }) => {
|
|
6
|
+
const registeredOverrides = [];
|
|
7
|
+
const excludedFromGeneration = [];
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
registeredOverrides,
|
|
11
|
+
excludedFromGeneration,
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param {(string | string[])} api - The name of the api or and array of apis to exclude from generation
|
|
15
|
+
*/
|
|
16
|
+
excludeFromGeneration(api) {
|
|
17
|
+
if (Array.isArray(api)) {
|
|
18
|
+
excludedFromGeneration.push(...api);
|
|
19
|
+
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
excludedFromGeneration.push(api);
|
|
24
|
+
},
|
|
25
|
+
/**
|
|
26
|
+
* @TODO pluginOrigin should be required in next major release
|
|
27
|
+
* @param {object} doc - The openapi specifcation to override
|
|
28
|
+
* @param {object} options - The options to override the documentation
|
|
29
|
+
* @param {(string | undefined)} options.pluginOrigin - The name of the plugin that is overriding the documentation
|
|
30
|
+
* @param {string[]} options.excludeFromGeneration - The list of apis or plugins to exclude from generation
|
|
31
|
+
*/
|
|
32
|
+
registerOverride(override, { pluginOrigin, excludeFromGeneration = [] } = {}) {
|
|
33
|
+
const pluginsThatNeedDocumentation = getPluginsThatNeedDocumentation(
|
|
34
|
+
strapi.config.get('plugin.documentation')
|
|
35
|
+
);
|
|
36
|
+
// Don't apply the override if the plugin is not in the list of plugins that need documentation
|
|
37
|
+
if (pluginOrigin && !pluginsThatNeedDocumentation.includes(pluginOrigin)) return;
|
|
38
|
+
|
|
39
|
+
if (excludeFromGeneration.length) {
|
|
40
|
+
this.excludeFromGeneration(excludeFromGeneration);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let overrideToRegister = override;
|
|
44
|
+
// Parse yaml if we receive a string
|
|
45
|
+
if (typeof override === 'string') {
|
|
46
|
+
overrideToRegister = require('yaml').parse(overrideToRegister);
|
|
47
|
+
}
|
|
48
|
+
// receive an object we can register it directly
|
|
49
|
+
registeredOverrides.push(overrideToRegister);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
securitySchemes: {
|
|
5
|
+
bearerAuth: {
|
|
6
|
+
type: 'http',
|
|
7
|
+
scheme: 'bearer',
|
|
8
|
+
bearerFormat: 'JWT',
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
schemas: {
|
|
12
|
+
Error: {
|
|
13
|
+
type: 'object',
|
|
14
|
+
required: ['error'],
|
|
15
|
+
properties: {
|
|
16
|
+
data: {
|
|
17
|
+
nullable: true,
|
|
18
|
+
oneOf: [{ type: 'object' }, { type: 'array', items: { type: 'object' } }],
|
|
19
|
+
},
|
|
20
|
+
error: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
status: {
|
|
24
|
+
type: 'integer',
|
|
25
|
+
},
|
|
26
|
+
name: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
},
|
|
29
|
+
message: {
|
|
30
|
+
type: 'string',
|
|
31
|
+
},
|
|
32
|
+
details: {
|
|
33
|
+
type: 'object',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const getPluginsThatNeedDocumentation = (config) => {
|
|
4
|
+
// Default plugins that need documentation generated
|
|
5
|
+
const defaultPlugins = ['upload', 'users-permissions'];
|
|
6
|
+
|
|
7
|
+
// User specified plugins that need documentation generated
|
|
8
|
+
const userPluginsConfig = config['x-strapi-config'].plugins;
|
|
9
|
+
|
|
10
|
+
if (userPluginsConfig === null) {
|
|
11
|
+
// The user hasn't specified any plugins to document, use the defaults
|
|
12
|
+
return defaultPlugins;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (userPluginsConfig.length) {
|
|
16
|
+
// The user has specified certain plugins to document, use them
|
|
17
|
+
return userPluginsConfig;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// The user has specified that no plugins should be documented
|
|
21
|
+
return [];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
module.exports = { getPluginsThatNeedDocumentation };
|
package/__mocks__/strapi.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const strapi = {
|
|
4
|
-
plugins: {
|
|
5
|
-
'users-permissions': {
|
|
6
|
-
contentTypes: {
|
|
7
|
-
role: {
|
|
8
|
-
attributes: {
|
|
9
|
-
name: {
|
|
10
|
-
type: 'string',
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
routes: {
|
|
16
|
-
'content-api': {
|
|
17
|
-
routes: [],
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
api: {
|
|
23
|
-
restaurant: {
|
|
24
|
-
contentTypes: {
|
|
25
|
-
restaurant: {
|
|
26
|
-
attributes: {
|
|
27
|
-
name: {
|
|
28
|
-
type: 'string',
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
routes: {
|
|
34
|
-
restaurant: { routes: [] },
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
contentType: () => ({ info: {}, attributes: { test: { type: 'string' } } }),
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
module.exports = strapi;
|
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const _ = require('lodash');
|
|
4
|
-
const buildComponentSchema = require('../server/services/helpers/build-component-schema');
|
|
5
|
-
const strapi = require('../__mocks__/strapi');
|
|
6
|
-
|
|
7
|
-
describe('Build Component Schema', () => {
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
// Reset the mocked strapi instance
|
|
10
|
-
global.strapi = _.cloneDeep(strapi);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('builds the Response schema', () => {
|
|
14
|
-
const apiMocks = [
|
|
15
|
-
{
|
|
16
|
-
name: 'users-permissions',
|
|
17
|
-
getter: 'plugin',
|
|
18
|
-
ctNames: ['role'],
|
|
19
|
-
},
|
|
20
|
-
{ name: 'restaurant', getter: 'api', ctNames: ['restaurant'] },
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
let schemas = {};
|
|
24
|
-
for (const mock of apiMocks) {
|
|
25
|
-
schemas = {
|
|
26
|
-
...schemas,
|
|
27
|
-
...buildComponentSchema(mock),
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const schemaNames = Object.keys(schemas);
|
|
32
|
-
const [pluginResponseName, apiResponseName] = Object.keys(schemas);
|
|
33
|
-
const [pluginResponseValue, apiResponseValue] = Object.values(schemas);
|
|
34
|
-
|
|
35
|
-
const expectedShape = {
|
|
36
|
-
type: 'object',
|
|
37
|
-
properties: {
|
|
38
|
-
data: {
|
|
39
|
-
type: 'object',
|
|
40
|
-
properties: {
|
|
41
|
-
id: { type: 'string' },
|
|
42
|
-
attributes: { type: 'object', properties: { test: { type: 'string' } } },
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
meta: { type: 'object' },
|
|
46
|
-
},
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
expect(schemaNames.length).toBe(2);
|
|
50
|
-
expect(pluginResponseName).toBe('UsersPermissionsRoleResponse');
|
|
51
|
-
expect(apiResponseName).toBe('RestaurantResponse');
|
|
52
|
-
expect(pluginResponseValue).toStrictEqual(expectedShape);
|
|
53
|
-
expect(apiResponseValue).toStrictEqual(expectedShape);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('builds the ResponseList schema', () => {
|
|
57
|
-
global.strapi.plugins['users-permissions'].routes['content-api'].routes = [
|
|
58
|
-
{ method: 'GET', path: '/test', handler: 'test.find' },
|
|
59
|
-
];
|
|
60
|
-
global.strapi.api.restaurant.routes.restaurant.routes = [
|
|
61
|
-
{ method: 'GET', path: '/test', handler: 'test.find' },
|
|
62
|
-
];
|
|
63
|
-
|
|
64
|
-
const apiMocks = [
|
|
65
|
-
{
|
|
66
|
-
name: 'users-permissions',
|
|
67
|
-
getter: 'plugin',
|
|
68
|
-
ctNames: ['role'],
|
|
69
|
-
},
|
|
70
|
-
{ name: 'restaurant', getter: 'api', ctNames: ['restaurant'] },
|
|
71
|
-
];
|
|
72
|
-
|
|
73
|
-
let schemas = {};
|
|
74
|
-
for (const mock of apiMocks) {
|
|
75
|
-
schemas = {
|
|
76
|
-
...schemas,
|
|
77
|
-
...buildComponentSchema(mock),
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const schemaNames = Object.keys(schemas);
|
|
82
|
-
const pluginListResponseValue = schemas.UsersPermissionsRoleListResponse;
|
|
83
|
-
const apiListResponseValue = schemas.RestaurantListResponse;
|
|
84
|
-
|
|
85
|
-
const expectedShape = {
|
|
86
|
-
type: 'object',
|
|
87
|
-
properties: {
|
|
88
|
-
data: {
|
|
89
|
-
type: 'array',
|
|
90
|
-
items: {
|
|
91
|
-
type: 'object',
|
|
92
|
-
properties: {
|
|
93
|
-
id: { type: 'string' },
|
|
94
|
-
attributes: { type: 'object', properties: { test: { type: 'string' } } },
|
|
95
|
-
},
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
meta: {
|
|
99
|
-
type: 'object',
|
|
100
|
-
properties: {
|
|
101
|
-
pagination: {
|
|
102
|
-
properties: {
|
|
103
|
-
page: { type: 'integer' },
|
|
104
|
-
pageSize: { type: 'integer', minimum: 25 },
|
|
105
|
-
pageCount: { type: 'integer', maximum: 1 },
|
|
106
|
-
total: { type: 'integer' },
|
|
107
|
-
},
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
expect(schemaNames.length).toBe(4);
|
|
115
|
-
expect(schemaNames.includes('UsersPermissionsRoleListResponse')).toBe(true);
|
|
116
|
-
expect(schemaNames.includes('RestaurantListResponse')).toBe(true);
|
|
117
|
-
expect(pluginListResponseValue).toStrictEqual(expectedShape);
|
|
118
|
-
expect(apiListResponseValue).toStrictEqual(expectedShape);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('builds the Request schema', () => {
|
|
122
|
-
global.strapi.plugins['users-permissions'].routes['content-api'].routes = [
|
|
123
|
-
{ method: 'POST', path: '/test', handler: 'test.create' },
|
|
124
|
-
];
|
|
125
|
-
global.strapi.api.restaurant.routes.restaurant.routes = [
|
|
126
|
-
{ method: 'POST', path: '/test', handler: 'test.create' },
|
|
127
|
-
];
|
|
128
|
-
|
|
129
|
-
const apiMocks = [
|
|
130
|
-
{
|
|
131
|
-
name: 'users-permissions',
|
|
132
|
-
getter: 'plugin',
|
|
133
|
-
ctNames: ['role'],
|
|
134
|
-
},
|
|
135
|
-
{ name: 'restaurant', getter: 'api', ctNames: ['restaurant'] },
|
|
136
|
-
];
|
|
137
|
-
|
|
138
|
-
let schemas = {};
|
|
139
|
-
for (const mock of apiMocks) {
|
|
140
|
-
schemas = {
|
|
141
|
-
...schemas,
|
|
142
|
-
...buildComponentSchema(mock),
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const schemaNames = Object.keys(schemas);
|
|
147
|
-
const pluginListResponseValue = schemas.UsersPermissionsRoleRequest;
|
|
148
|
-
const apiListResponseValue = schemas.RestaurantRequest;
|
|
149
|
-
|
|
150
|
-
const expectedShape = {
|
|
151
|
-
type: 'object',
|
|
152
|
-
required: ['data'],
|
|
153
|
-
properties: {
|
|
154
|
-
data: {
|
|
155
|
-
required: [],
|
|
156
|
-
type: 'object',
|
|
157
|
-
properties: { test: { type: 'string' } },
|
|
158
|
-
},
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
expect(schemaNames.length).toBe(4);
|
|
163
|
-
expect(schemaNames.includes('UsersPermissionsRoleRequest')).toBe(true);
|
|
164
|
-
expect(schemaNames.includes('RestaurantRequest')).toBe(true);
|
|
165
|
-
expect(pluginListResponseValue).toStrictEqual(expectedShape);
|
|
166
|
-
expect(apiListResponseValue).toStrictEqual(expectedShape);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it('builds the LocalizationResponse schema', () => {
|
|
170
|
-
global.strapi.plugins['users-permissions'].routes['content-api'].routes = [
|
|
171
|
-
{ method: 'GET', path: '/localizations', handler: 'test' },
|
|
172
|
-
];
|
|
173
|
-
global.strapi.api.restaurant.routes.restaurant.routes = [
|
|
174
|
-
{ method: 'GET', path: '/localizations', handler: 'test' },
|
|
175
|
-
];
|
|
176
|
-
|
|
177
|
-
const apiMocks = [
|
|
178
|
-
{
|
|
179
|
-
name: 'users-permissions',
|
|
180
|
-
getter: 'plugin',
|
|
181
|
-
ctNames: ['role'],
|
|
182
|
-
},
|
|
183
|
-
{ name: 'restaurant', getter: 'api', ctNames: ['restaurant'] },
|
|
184
|
-
];
|
|
185
|
-
|
|
186
|
-
let schemas = {};
|
|
187
|
-
for (const mock of apiMocks) {
|
|
188
|
-
schemas = {
|
|
189
|
-
...schemas,
|
|
190
|
-
...buildComponentSchema(mock),
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const schemaNames = Object.keys(schemas);
|
|
195
|
-
const pluginListResponseValue = schemas.UsersPermissionsRoleLocalizationResponse;
|
|
196
|
-
const apiListResponseValue = schemas.RestaurantLocalizationResponse;
|
|
197
|
-
|
|
198
|
-
const expectedShape = {
|
|
199
|
-
type: 'object',
|
|
200
|
-
properties: {
|
|
201
|
-
id: { type: 'string' },
|
|
202
|
-
test: { type: 'string' },
|
|
203
|
-
},
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
expect(schemaNames.length).toBe(4);
|
|
207
|
-
expect(schemaNames.includes('UsersPermissionsRoleLocalizationResponse')).toBe(true);
|
|
208
|
-
expect(schemaNames.includes('RestaurantLocalizationResponse')).toBe(true);
|
|
209
|
-
expect(pluginListResponseValue).toStrictEqual(expectedShape);
|
|
210
|
-
expect(apiListResponseValue).toStrictEqual(expectedShape);
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
it('builds the LocalizationRequest schema', () => {
|
|
214
|
-
global.strapi.plugins['users-permissions'].routes['content-api'].routes = [
|
|
215
|
-
{ method: 'POST', path: '/localizations', handler: 'test' },
|
|
216
|
-
];
|
|
217
|
-
global.strapi.api.restaurant.routes.restaurant.routes = [
|
|
218
|
-
{ method: 'POST', path: '/localizations', handler: 'test' },
|
|
219
|
-
];
|
|
220
|
-
|
|
221
|
-
const apiMocks = [
|
|
222
|
-
{
|
|
223
|
-
name: 'users-permissions',
|
|
224
|
-
getter: 'plugin',
|
|
225
|
-
ctNames: ['role'],
|
|
226
|
-
},
|
|
227
|
-
{ name: 'restaurant', getter: 'api', ctNames: ['restaurant'] },
|
|
228
|
-
];
|
|
229
|
-
|
|
230
|
-
let schemas = {};
|
|
231
|
-
for (const mock of apiMocks) {
|
|
232
|
-
schemas = {
|
|
233
|
-
...schemas,
|
|
234
|
-
...buildComponentSchema(mock),
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const schemaNames = Object.keys(schemas);
|
|
239
|
-
const pluginListResponseValue = schemas.UsersPermissionsRoleLocalizationRequest;
|
|
240
|
-
const apiListResponseValue = schemas.RestaurantLocalizationRequest;
|
|
241
|
-
|
|
242
|
-
const expectedShape = {
|
|
243
|
-
type: 'object',
|
|
244
|
-
required: ['locale'],
|
|
245
|
-
properties: { test: { type: 'string' } },
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
expect(schemaNames.length).toBe(8);
|
|
249
|
-
expect(schemaNames.includes('UsersPermissionsRoleLocalizationRequest')).toBe(true);
|
|
250
|
-
expect(schemaNames.includes('RestaurantLocalizationRequest')).toBe(true);
|
|
251
|
-
expect(pluginListResponseValue).toStrictEqual(expectedShape);
|
|
252
|
-
expect(apiListResponseValue).toStrictEqual(expectedShape);
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
it('creates the correct name given multiple content types', () => {
|
|
256
|
-
const apiMock = {
|
|
257
|
-
name: 'users-permissions',
|
|
258
|
-
getter: 'plugin',
|
|
259
|
-
ctNames: ['permission', 'role', 'user'],
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
const schemas = buildComponentSchema(apiMock);
|
|
263
|
-
const schemaNames = Object.keys(schemas);
|
|
264
|
-
const [permission, role, user] = schemaNames;
|
|
265
|
-
|
|
266
|
-
expect(schemaNames.length).toBe(3);
|
|
267
|
-
expect(permission).toBe('UsersPermissionsPermissionResponse');
|
|
268
|
-
expect(role).toBe('UsersPermissionsRoleResponse');
|
|
269
|
-
expect(user).toBe('UsersPermissionsUserResponse');
|
|
270
|
-
});
|
|
271
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { request } from '@strapi/helper-plugin';
|
|
2
|
-
import pluginId from '../../pluginId';
|
|
3
|
-
|
|
4
|
-
const deleteDoc = ({ prefix, version }) => {
|
|
5
|
-
return request(`${prefix}/deleteDoc/${version}`, { method: 'DELETE' });
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
const fetchDocumentationVersions = async (toggleNotification) => {
|
|
9
|
-
try {
|
|
10
|
-
const data = await request(`/${pluginId}/getInfos`, { method: 'GET' });
|
|
11
|
-
|
|
12
|
-
return data;
|
|
13
|
-
} catch (err) {
|
|
14
|
-
toggleNotification({
|
|
15
|
-
type: 'warning',
|
|
16
|
-
message: { id: 'notification.error' },
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
// FIXME
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const regenerateDoc = ({ prefix, version }) => {
|
|
25
|
-
return request(`${prefix}/regenerateDoc`, { method: 'POST', body: { version } });
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const updateSettings = ({ prefix, body }) =>
|
|
29
|
-
request(`${prefix}/updateSettings`, { method: 'PUT', body });
|
|
30
|
-
|
|
31
|
-
export { deleteDoc, fetchDocumentationVersions, regenerateDoc, updateSettings };
|