kobp
Version:
Koa Boilerplate with MikroORM
171 lines • 7.83 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.deriveApiSpec = void 0;
require("reflect-metadata");
const __1 = require("..");
/**
* Extract API specification from given router object
*/
const deriveApiSpec = (title, someOptions, builder, router) => {
const options = {
skipMethods: ['HEAD'],
skipPaths: ['swagger'],
version: '1.0.0',
basePath: '',
description: (desc) => desc,
servers: [],
availableTags: [],
securitySchemes: {},
securityOnAllOperations: [],
...someOptions,
};
const skipPaths = options.skipPaths;
const skipMethods = new Set(options.skipMethods);
const cleanPath = options.basePath
? (path) => path
.replace(options.basePath, '')
.replace(/^\/*/, '/')
.replace(/:(\w+)/g, '{$1}')
: (path) => path.replace(/^\/*/, '/').replace(/:(\w+)/g, '{$1}'); // make sure there is only one path
const skipPathPredicate = typeof skipPaths === 'function'
? skipPaths
: (path) => {
for (const skipPath of skipPaths) {
if (typeof skipPath === 'string') {
return path.startsWith(skipPath);
}
return skipPath.test(path);
}
return false;
};
const description = options.description;
builder.addInfo({
title: title,
version: options.version,
description: typeof description === 'function'
? description("**NOTE**: The OpenAPI's specification is also available at [spec.json](./spec.json)")
: description,
});
for (const tag of options.availableTags) {
builder.addTag(tag);
}
for (const server of options.servers) {
builder.addServer(server);
}
for (const schemeName of Object.keys(options.securitySchemes)) {
builder.addSecurityScheme(schemeName, options.securitySchemes[schemeName]);
}
for (const layer of router.stack) {
// Skip the path
if (skipPathPredicate(layer.path)) {
continue;
}
// String array of path parameter keys
const pathParameterKeys = [...layer.path.matchAll(/:(\w+)/g)].map((d) => d[1]);
const methods = layer.methods;
let pathItem = {};
for (const method of methods) {
if (skipMethods.has(method)) {
continue;
}
// Extract document data
let opDoc = {};
// initialize operation document with default security
if (options.securityOnAllOperations) {
opDoc.security = options.securityOnAllOperations || [];
}
let validationSpecBuffer = {};
layer.stack.map((stack) => {
// try to access the metadata defined within the stack
const keys = Reflect.getMetadataKeys(stack).filter((k) => __1.ALL_METADATA_KEYS.has(k));
for (const key of keys) {
// Found a meta of documentation node!
if (key === __1.METADATA_KEYS.DOC_KEY) {
const opSpecFn = Reflect.getMetadata(__1.METADATA_KEYS.DOC_KEY, stack);
const builder = new __1.OperationDocumentBuilder({ ...opDoc, ...opSpecFn() });
// FIXME: Handle the path definition
// merge?
if (validationSpecBuffer.body) {
// inject body
builder.useBody({
required: true,
content: {
'application/json': {
schema: validationSpecBuffer.body,
},
},
});
}
// Add default doc first
const undocumentedParams = new Set(pathParameterKeys);
if (validationSpecBuffer.parameters) {
const shape = validationSpecBuffer.parameters;
for (const key of Object.keys(shape.properties)) {
const { description } = shape.properties[key];
undocumentedParams.delete(key);
builder.useParameter('path', key, {
schema: shape.properties[key],
description,
required: true,
});
}
}
if (undocumentedParams.size > 0) {
for (const key of undocumentedParams) {
builder.useParameter('path', key, {
schema: {
type: 'string',
},
required: true,
});
}
}
if (validationSpecBuffer.headers) {
const shape = validationSpecBuffer.headers;
for (const key of Object.keys(shape.properties)) {
const { description } = shape.properties[key];
builder.useParameter('header', key, {
schema: shape.properties[key],
description,
});
}
}
if (validationSpecBuffer.query) {
const shape = validationSpecBuffer.query;
for (const key of Object.keys(shape.properties)) {
const { description } = shape.properties[key];
builder.useParameter('query', key, {
schema: shape.properties[key],
description,
});
}
}
opDoc = builder.build();
}
else if (key === __1.METADATA_KEYS.DOC_BODY_SHAPE_VALIDATION_KEY) {
validationSpecBuffer.body = Reflect.getMetadata(__1.METADATA_KEYS.DOC_BODY_SHAPE_VALIDATION_KEY, stack);
}
else if (key === __1.METADATA_KEYS.DOC_HEADERS_SHAPE_VALIDATION_KEY) {
validationSpecBuffer.headers = Reflect.getMetadata(__1.METADATA_KEYS.DOC_HEADERS_SHAPE_VALIDATION_KEY, stack);
}
else if (key === __1.METADATA_KEYS.DOC_PARAMS_SHAPE_VALIDATION_KEY) {
validationSpecBuffer.parameters = Reflect.getMetadata(__1.METADATA_KEYS.DOC_PARAMS_SHAPE_VALIDATION_KEY, stack);
}
else if (key === __1.METADATA_KEYS.DOC_QUERY_SHAPE_VALIDATION_KEY) {
validationSpecBuffer.query = Reflect.getMetadata(__1.METADATA_KEYS.DOC_QUERY_SHAPE_VALIDATION_KEY, stack);
}
}
});
pathItem = {
[method.toLowerCase()]: {
responses: [],
...opDoc,
},
};
}
builder.addPath(cleanPath(layer.path), pathItem);
}
return builder.getSpec();
};
exports.deriveApiSpec = deriveApiSpec;
//# sourceMappingURL=swagger.js.map