Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added Redocly config and decorators #116

Merged
merged 2 commits into from Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1,853 changes: 1,796 additions & 57 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion package.json
Expand Up @@ -23,7 +23,11 @@
"publish:postman": "bazel run generator/postman:_postman_bin",
"test": "bazel test ...",
"watch": "ibazel build ...",
"watch:test": "ibazel test ..."
"watch:test": "ibazel test ...",
"extract:dereference": "redocly bundle --config ./redocly-plugins/redocly-config.yaml --dereferenced -o temp-extract-woosmap-openapi --ext json",
"extract:unused": "redocly bundle temp-extract-woosmap-openapi.json --remove-unused-components --output extract-woosmap-openapi-final --ext json",
"extract:lint": "redocly lint --config ./redocly-plugins/redocly-config.yaml extract-woosmap-openapi-final.json",
"extract": "npm run extract:dereference && npm run extract:unused && npm run extract:lint"
},
"devDependencies": {
"@apidevtools/json-schema-ref-parser": "^9.1.0",
Expand All @@ -33,6 +37,7 @@
"@bazel/ibazel": "^0.16.2",
"@bazel/typescript": "4.6.2",
"@google/semantic-release-replace-plugin": "^1.2.0",
"@redocly/cli": "1.8.2",
"@semantic-release/exec": "^6.0.3",
"@semantic-release/npm": "^9.0.1",
"@types/axios": "^0.14.0",
Expand Down
21 changes: 21 additions & 0 deletions redocly-plugins/decorators.js
@@ -0,0 +1,21 @@
const TrimDescription = require('./decorators/trim-description');
const OneSecurityScheme = require('./decorators/one-security-scheme');
const RemoveParameters = require('./decorators/remove-parameters');
const RemoveUnusedTags = require('./decorators/remove-unused-tags');

const id = 'plugin';

/** @type {import('@redocly/cli').DecoratorsConfig} */
const decorators = {
oas3: {
'trim-description': TrimDescription,
'one-security-scheme': OneSecurityScheme,
'remove-parameters': RemoveParameters,
'remove-unused-tags': RemoveUnusedTags,
}
};

module.exports = {
id,
decorators,
};
37 changes: 37 additions & 0 deletions redocly-plugins/decorators/one-security-scheme.js
@@ -0,0 +1,37 @@
module.exports = OneSecurityScheme;

/** @type {import('@redocly/cli').OasDecorator} */

/**
* Returns a decorator that retains only one security scheme.
* @param {Object} options - The options for the decorator.
* @param {string} options.securitySchemeName - The name of the security scheme to retain.
* @returns {Object} The decorator.
*/
function OneSecurityScheme({securitySchemeName}) {
return {
Components: {
leave(components) {
if (components.securitySchemes && components.securitySchemes[securitySchemeName]) {
components.securitySchemes = {
[securitySchemeName]: components.securitySchemes[securitySchemeName]
};
}
}
},
Root: {
leave(root) {
if (root.security) {
root.security = root.security.filter(secName => securitySchemeName in secName);
}
}
},
Operation: {
leave(target) {
if (target.security) {
target.security = target.security.filter(secName => securitySchemeName in secName);
}
}
}
}
}
63 changes: 63 additions & 0 deletions redocly-plugins/decorators/remove-parameters.js
@@ -0,0 +1,63 @@
module.exports = RemoveParameters;

/** @type {import('@redocly/cli').OasDecorator} */
const openAPIExtensions = /x-*/;

/**
* Asserts a condition and throws an error if the condition is not met.
* @param {boolean} condition - The condition to assert.
* @param {string} [message] - The error message to throw if the condition is not met.
*/
function assert(condition, message = 'An error occurred') {
if (!condition) {
throw new Error(message);
}
}

/**
* Removes a parameter from a node.
* @param {Object} node - The node to remove the parameter from.
* @param {string} param - The parameter to remove.
*/
function removeParamFromNode(node, param) {
assert(typeof param === 'string', 'Parameter must be a string');
delete node[param];
console.log('Deleted parameter "%s" from object "%O"', param, node);
}

/**
* Removes parameters from a node. If no parameters are specified, all parameters starting with "x-" are removed.
* @param {Object} node - The node to remove the parameters from.
* @param {string|string[]} parameters - The parameters to remove.
*/
function removeParametersFromNode(node, parameters) {
const parametersType = typeof parameters;
assert(
parametersType === 'undefined' || parametersType === 'string' || parametersType === 'object',
`Parameters must be a string or an array of strings, but received type "${parametersType}"`
);
if (!parameters) {
console.log('Deleting all OpenAPI extensions (parameters starting with "x-")...');
Object.keys(node).filter(param => param.match(openAPIExtensions)).forEach(param => removeParamFromNode(node, param));
} else if (parametersType === 'string') {
Object.keys(node).filter(param => param.match(parameters)).forEach(param => removeParamFromNode(node, param));
} else {
parameters.forEach(parameter => {
Object.keys(node).filter(param => param.match(parameter)).forEach(param => removeParamFromNode(node, param));
});
}
}

/**
* Returns a decorator that removes parameters from nodes.
* @param {Object} options - The options for the decorator.
* @param {string|string[]} options.parameters - The parameters to remove.
* @returns {Object} The decorator.
*/
function RemoveParameters({parameters}) {
return {
any: {
enter: (node) => removeParametersFromNode(node, parameters),
}
}
}
28 changes: 28 additions & 0 deletions redocly-plugins/decorators/remove-unused-tags.js
@@ -0,0 +1,28 @@
module.exports = RemoveUnusedTags;

/** @type {import('@redocly/cli').OasDecorator} */

/**
* Returns a decorator that removes unused tags from operations.
* @returns {Object} The decorator.
*/
function RemoveUnusedTags() {
const usedTags = new Set();

return {
Operation: {
leave(operation) {
if (operation.tags) {
operation.tags.forEach(tag => usedTags.add(tag));
}
}
},
Root: {
leave(root) {
if (root.tags) {
root.tags = root.tags.filter(tag => usedTags.has(tag.name));
}
}
}
}
}
26 changes: 26 additions & 0 deletions redocly-plugins/decorators/trim-description.js
@@ -0,0 +1,26 @@
module.exports = TrimDescription;

/** @type {import('@redocly/cli').OasDecorator} */

/**
* Returns a decorator that trims descriptions to a maximum length.
* @param {Object} options - The options for the decorator.
* @param {number} options.maxParameterDescriptionLength - The maximum length for parameter descriptions.
* @param {number} options.maxOperationDescriptionLength - The maximum length for operation descriptions.
* @returns {Object} The decorator.
*/
function TrimDescription({maxParameterDescriptionLength, maxOperationDescriptionLength}) {
return {
any: {
enter: (node) => {
if (node.description && typeof node.description === 'string') {
if (node.operationId && node.description.length > maxOperationDescriptionLength) {
node.description = `${node.description.substring(0, maxOperationDescriptionLength)}...`;
} else if (node.description.length > maxParameterDescriptionLength) {
node.description = `${node.description.substring(0, maxParameterDescriptionLength)}...`;
}
}
},
},
}
}
34 changes: 34 additions & 0 deletions redocly-plugins/redocly-config.yaml
@@ -0,0 +1,34 @@
apis:
filter:
root: ../dist/merged-woosmap-openapi3.json
decorators:
filter-in:
property: operationId
value:
- localitiesAutocomplete
- localitiesDetails
- localitiesGeocode
- storeSearch
- getDistanceMatrix
plugin/trim-description:
maxParameterDescriptionLength: 690
maxOperationDescriptionLength: 290
plugin/one-security-scheme:
securitySchemeName: PrivateApiKeyHeaderAuth
plugin/remove-parameters:
parameters:
- x-codeSamples
- example
- examples
- 401
- 403
- 429
plugin/remove-unused-tags: on
plugins:
- ./decorators.js
rules:
no-unresolved-refs: error
no-unused-components: error
security-defined: error
spec: error
spec-components-invalid-map-name: error