mirror of
https://github.com/strapi/strapi.git
synced 2025-08-16 20:57:34 +00:00
Apply overrides for specified versions
This commit is contained in:
parent
0798cf75f3
commit
19ce046512
@ -17,7 +17,7 @@ module.exports = () => ({
|
|||||||
documentation: {
|
documentation: {
|
||||||
config: {
|
config: {
|
||||||
info: {
|
info: {
|
||||||
version: '2.0.0',
|
version: '1.0.0',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -16,12 +16,11 @@ module.exports = {
|
|||||||
name: 'Apache 2.0',
|
name: 'Apache 2.0',
|
||||||
url: 'https://www.apache.org/licenses/LICENSE-2.0.html',
|
url: 'https://www.apache.org/licenses/LICENSE-2.0.html',
|
||||||
},
|
},
|
||||||
'x-strapi-generation-date': new Date().toISOString(),
|
|
||||||
},
|
},
|
||||||
'x-strapi-config': {
|
'x-strapi-config': {
|
||||||
path: '/documentation',
|
path: '/documentation',
|
||||||
plugins: null,
|
plugins: null,
|
||||||
customizer: null,
|
mutateDocumentation: null,
|
||||||
},
|
},
|
||||||
servers: [],
|
servers: [],
|
||||||
externalDocs: {
|
externalDocs: {
|
||||||
|
@ -154,13 +154,15 @@ describe('Documentation service', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
global.strapi.config.get = () => ({ ...userConfig });
|
global.strapi.config.get = () => ({ ...userConfig });
|
||||||
const docService = documentation({ strapi: global.strapi });
|
const docService = documentation({ strapi: global.strapi });
|
||||||
await docService.generateFullDoc();
|
await docService.generateFullDoc();
|
||||||
const lastMockCall = fse.writeJson.mock.calls[fse.writeJson.mock.calls.length - 1];
|
const lastMockCall = fse.writeJson.mock.calls[fse.writeJson.mock.calls.length - 1];
|
||||||
const mockFinalDoc = lastMockCall[1];
|
const mockFinalDoc = lastMockCall[1];
|
||||||
|
// The generation data is dynamically added, it cannot be modified by the user
|
||||||
expect(mockFinalDoc.info).toEqual(userConfig.info);
|
const { 'x-generation-date': generationConfig, ...mockFinalDocInfo } = mockFinalDoc.info;
|
||||||
|
expect(mockFinalDocInfo).toEqual(userConfig.info);
|
||||||
expect(mockFinalDoc['x-strapi-config']).toEqual(userConfig['x-strapi-config']);
|
expect(mockFinalDoc['x-strapi-config']).toEqual(userConfig['x-strapi-config']);
|
||||||
expect(mockFinalDoc.externalDocs).toEqual(userConfig.externalDocs);
|
expect(mockFinalDoc.externalDocs).toEqual(userConfig.externalDocs);
|
||||||
expect(mockFinalDoc.security).toEqual(userConfig.security);
|
expect(mockFinalDoc.security).toEqual(userConfig.security);
|
||||||
@ -319,6 +321,66 @@ describe('Documentation service', () => {
|
|||||||
'test-new-component'
|
'test-new-component'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('overrides only the specified version', async () => {
|
||||||
|
const overrideService = override({ strapi: global.strapi });
|
||||||
|
// Simulate override from upload plugin
|
||||||
|
overrideService.registerOverride(
|
||||||
|
{
|
||||||
|
// Only override for version 1.0.0
|
||||||
|
info: { version: '1.0.0' },
|
||||||
|
components: {
|
||||||
|
schemas: {
|
||||||
|
// This component schema exists after generating with mock data, replace it
|
||||||
|
ShouldNotBeAdded: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ pluginOrigin: 'upload' }
|
||||||
|
);
|
||||||
|
// Simulate override from upload plugin
|
||||||
|
overrideService.registerOverride(
|
||||||
|
{
|
||||||
|
// Only override for version 2.0.0
|
||||||
|
info: { version: '2.0.0' },
|
||||||
|
components: {
|
||||||
|
schemas: {
|
||||||
|
// This component schema exists after generating with mock data, replace it
|
||||||
|
ShouldBeAdded: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ pluginOrigin: 'upload' }
|
||||||
|
);
|
||||||
|
// Simulate override from upload plugin
|
||||||
|
overrideService.registerOverride(
|
||||||
|
{
|
||||||
|
components: {
|
||||||
|
schemas: {
|
||||||
|
// This component schema exists after generating with mock data, replace it
|
||||||
|
ShouldAlsoBeAdded: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ pluginOrigin: 'upload' }
|
||||||
|
);
|
||||||
|
global.strapi.plugins.documentation = {
|
||||||
|
service: jest.fn((name) => {
|
||||||
|
const mockServices = {
|
||||||
|
override: overrideService,
|
||||||
|
};
|
||||||
|
|
||||||
|
return mockServices[name];
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const docService = documentation({ strapi: global.strapi });
|
||||||
|
await docService.generateFullDoc('2.0.0');
|
||||||
|
const lastMockCall = fse.writeJson.mock.calls[fse.writeJson.mock.calls.length - 1];
|
||||||
|
const mockFinalDoc = lastMockCall[1];
|
||||||
|
|
||||||
|
expect(mockFinalDoc.components.schemas.ShouldNotBeAdded).toBeUndefined();
|
||||||
|
expect(mockFinalDoc.components.schemas.ShouldBeAdded).toBeDefined();
|
||||||
|
expect(mockFinalDoc.components.schemas.ShouldAlsoBeAdded).toBeDefined();
|
||||||
|
});
|
||||||
it('excludes apis and plugins from generation', async () => {
|
it('excludes apis and plugins from generation', async () => {
|
||||||
const overrideService = override({ strapi: global.strapi });
|
const overrideService = override({ strapi: global.strapi });
|
||||||
|
|
||||||
@ -346,12 +408,12 @@ describe('Documentation service', () => {
|
|||||||
Object.keys(mockFinalDoc.components.schemas).find((compo) => compo.includes('Kitchensink'))
|
Object.keys(mockFinalDoc.components.schemas).find((compo) => compo.includes('Kitchensink'))
|
||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
});
|
});
|
||||||
it("applies a user's customizer function", async () => {
|
it("applies a user's mutateDocumentation function", async () => {
|
||||||
global.strapi.config.get = () => ({
|
global.strapi.config.get = () => ({
|
||||||
...defaultConfig,
|
...defaultConfig,
|
||||||
'x-strapi-config': {
|
'x-strapi-config': {
|
||||||
...defaultConfig['x-strapi-config'],
|
...defaultConfig['x-strapi-config'],
|
||||||
customizer(draft) {
|
mutateDocumentation(draft) {
|
||||||
draft.paths['/kitchensinks'] = { get: { responses: { 200: { description: 'test' } } } };
|
draft.paths['/kitchensinks'] = { get: { responses: { 200: { description: 'test' } } } };
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -176,7 +176,6 @@ module.exports = ({ strapi }) => {
|
|||||||
'full_documentation.json'
|
'full_documentation.json'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Set config defaults
|
|
||||||
const serverUrl = getAbsoluteServerUrl(strapi.config);
|
const serverUrl = getAbsoluteServerUrl(strapi.config);
|
||||||
const apiPath = strapi.config.get('api.rest.prefix');
|
const apiPath = strapi.config.get('api.rest.prefix');
|
||||||
const generatedDocumentation = produce(config, (draft) => {
|
const generatedDocumentation = produce(config, (draft) => {
|
||||||
@ -189,42 +188,49 @@ module.exports = ({ strapi }) => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
// Set the generated date
|
||||||
|
draft.info['x-generation-date'] = new Date().toISOString();
|
||||||
|
// Set the plugins that need documentation
|
||||||
draft['x-strapi-config'].plugins = pluginsThatNeedDocumentation;
|
draft['x-strapi-config'].plugins = pluginsThatNeedDocumentation;
|
||||||
// Delete it from the config so it doesn't end up in the spec
|
// Delete it from the config so it doesn't end up in the spec
|
||||||
delete draft['x-strapi-config'].customizer;
|
delete draft['x-strapi-config'].mutateDocumentation;
|
||||||
|
|
||||||
// Set the generated paths
|
// Set the generated paths
|
||||||
draft.paths = paths;
|
draft.paths = paths;
|
||||||
// Merge the generated component schemas with the defaults
|
// Merge the generated component schemas with the defaults
|
||||||
draft.components = _.merge(defaultOpenApiComponents, { schemas });
|
draft.components = _.merge(defaultOpenApiComponents, { schemas });
|
||||||
|
// Check for overrides and then add them
|
||||||
|
if (overrideService.registeredOverrides.length > 0) {
|
||||||
|
overrideService.registeredOverrides.forEach((doc) => {
|
||||||
|
// Only run the overrrides when no override version is provided,
|
||||||
|
// or when the generated documentation version matches the override version
|
||||||
|
if (!doc?.info?.version || doc.info.version === version) {
|
||||||
|
if (doc.tags) {
|
||||||
|
// Merge override tags with the generated tags
|
||||||
|
draft.tags = draft.tags || [];
|
||||||
|
draft.tags.push(...doc.tags);
|
||||||
|
}
|
||||||
|
|
||||||
overrideService.registeredOverrides.forEach((doc) => {
|
if (doc.paths) {
|
||||||
if (doc.tags) {
|
// Merge override paths with the generated paths
|
||||||
// Merge override tags with the generated tags
|
// The override will add a new path or replace the value of an existing path
|
||||||
draft.tags = draft.tags || [];
|
draft.paths = { ...draft.paths, ...doc.paths };
|
||||||
draft.tags.push(...doc.tags);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (doc.paths) {
|
if (doc.components) {
|
||||||
// Merge override paths with the generated paths
|
Object.entries(doc.components).forEach(([key, val]) => {
|
||||||
// The override will add a new path or replace the value of an existing path
|
draft.components[key] = draft.components[key] || {};
|
||||||
draft.paths = { ...draft.paths, ...doc.paths };
|
// Merge override components with the generated components,
|
||||||
}
|
// The override will add a new component or replace the value of an existing component
|
||||||
|
draft.components[key] = { ...draft.components[key], ...val };
|
||||||
if (doc.components) {
|
});
|
||||||
Object.entries(doc.components).forEach(([key, val]) => {
|
}
|
||||||
draft.components[key] = draft.components[key] || {};
|
}
|
||||||
// Merge override components with the generated components,
|
});
|
||||||
// The override will add a new component or replace the value of an existing component
|
}
|
||||||
draft.components[key] = { ...draft.components[key], ...val };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
// Get the documentation customizer
|
// Get the documentation mutateDocumentation
|
||||||
const documentationCustomizer = config['x-strapi-config'].customizer;
|
const documentationCustomizer = config['x-strapi-config'].mutateDocumentation;
|
||||||
// Escape hatch, allow the user to provide a customizer function that can manipulate
|
// Escape hatch, allow the user to provide a mutateDocumentation function that can alter any part of
|
||||||
// the generated documentation before it is written to the file system
|
// the generated documentation before it is written to the file system
|
||||||
const finalDocumentation = documentationCustomizer
|
const finalDocumentation = documentationCustomizer
|
||||||
? produce(generatedDocumentation, documentationCustomizer)
|
? produce(generatedDocumentation, documentationCustomizer)
|
||||||
|
@ -5,53 +5,48 @@ const { getPluginsThatNeedDocumentation } = require('./utils/get-plugins-that-ne
|
|||||||
module.exports = ({ strapi }) => {
|
module.exports = ({ strapi }) => {
|
||||||
const registeredOverrides = [];
|
const registeredOverrides = [];
|
||||||
const excludedFromGeneration = [];
|
const excludedFromGeneration = [];
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {string | string[]} api - The name of the api or and array of apis to exclude from generation
|
|
||||||
*/
|
|
||||||
const excludeFromGeneration = (api) => {
|
|
||||||
if (Array.isArray(api)) {
|
|
||||||
excludedFromGeneration.push(...api);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
excludedFromGeneration.push(api);
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* @TODO pluginOrigin should be required in next major release
|
|
||||||
* @param {object} doc - The openapi specifcation to override
|
|
||||||
* @param {object} options - The options to override the documentation
|
|
||||||
* @param {string} options.pluginOrigin - The name of the plugin that is overriding the documentation
|
|
||||||
* @param {string[]} options.excludeFromGeneration - The name of the plugin that is overriding the documentation
|
|
||||||
*/
|
|
||||||
const registerOverride = (override, { pluginOrigin, excludeFromGeneration = [] }) => {
|
|
||||||
const pluginsThatNeedDocumentation = getPluginsThatNeedDocumentation(
|
|
||||||
strapi.config.get('plugin.documentation')
|
|
||||||
);
|
|
||||||
// Don't apply the override if the plugin is not in the list of plugins that need documentation
|
|
||||||
if (pluginOrigin && !pluginsThatNeedDocumentation.includes(pluginOrigin)) return;
|
|
||||||
|
|
||||||
if (excludeFromGeneration.length) {
|
|
||||||
strapi
|
|
||||||
.plugin('documentation')
|
|
||||||
.service('override')
|
|
||||||
.excludeFromGeneration(excludeFromGeneration);
|
|
||||||
}
|
|
||||||
|
|
||||||
let overrideToRegister = override;
|
|
||||||
// Parse yaml if we receive a string
|
|
||||||
if (typeof override === 'string') {
|
|
||||||
overrideToRegister = require('yaml').parse(overrideToRegister);
|
|
||||||
}
|
|
||||||
// receive an object we can register it directly
|
|
||||||
registeredOverrides.push(overrideToRegister);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
registeredOverrides,
|
registeredOverrides,
|
||||||
registerOverride,
|
|
||||||
excludeFromGeneration,
|
|
||||||
excludedFromGeneration,
|
excludedFromGeneration,
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string | string[]} api - The name of the api or and array of apis to exclude from generation
|
||||||
|
*/
|
||||||
|
excludeFromGeneration(api) {
|
||||||
|
if (Array.isArray(api)) {
|
||||||
|
excludedFromGeneration.push(...api);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
excludedFromGeneration.push(api);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @TODO pluginOrigin should be required in next major release
|
||||||
|
* @param {object} doc - The openapi specifcation to override
|
||||||
|
* @param {object} options - The options to override the documentation
|
||||||
|
* @param {string} options.pluginOrigin - The name of the plugin that is overriding the documentation
|
||||||
|
* @param {string[]} options.excludeFromGeneration - The name of the plugin that is overriding the documentation
|
||||||
|
*/
|
||||||
|
registerOverride(override, { pluginOrigin, excludeFromGeneration = [] }) {
|
||||||
|
const pluginsThatNeedDocumentation = getPluginsThatNeedDocumentation(
|
||||||
|
strapi.config.get('plugin.documentation')
|
||||||
|
);
|
||||||
|
// Don't apply the override if the plugin is not in the list of plugins that need documentation
|
||||||
|
if (pluginOrigin && !pluginsThatNeedDocumentation.includes(pluginOrigin)) return;
|
||||||
|
|
||||||
|
if (excludeFromGeneration.length) {
|
||||||
|
this.excludeFromGeneration(excludeFromGeneration);
|
||||||
|
}
|
||||||
|
|
||||||
|
let overrideToRegister = override;
|
||||||
|
// Parse yaml if we receive a string
|
||||||
|
if (typeof override === 'string') {
|
||||||
|
overrideToRegister = require('yaml').parse(overrideToRegister);
|
||||||
|
}
|
||||||
|
// receive an object we can register it directly
|
||||||
|
registeredOverrides.push(overrideToRegister);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user