UNPKG

@opra/common

Version:
217 lines (216 loc) 8.08 kB
import typeIs from '@browsery/type-is'; import { isConstructor } from '@jsopen/objects'; import { MimeTypes } from '../../enums/index.js'; import { OpraSchema } from '../../schema/index.js'; import { HTTP_CONTROLLER_METADATA } from '../constants.js'; export function HttpOperationDecoratorFactory(decoratorChain, options) { /** * */ const decorator = ((target, propertyKey) => { if (typeof propertyKey !== 'string') throw new TypeError(`Symbol properties can not be decorated`); const operationMetadata = { ...options, kind: OpraSchema.HttpOperation.Kind, }; const controllerMetadata = (Reflect.getOwnMetadata(HTTP_CONTROLLER_METADATA, target.constructor) || {}); controllerMetadata.operations = controllerMetadata.operations || {}; controllerMetadata.operations[propertyKey] = operationMetadata; for (const fn of decoratorChain) fn(operationMetadata); Reflect.defineMetadata(HTTP_CONTROLLER_METADATA, controllerMetadata, target.constructor); }); /** * */ decorator.Cookie = (name, arg1) => { decoratorChain.push((meta) => { const paramMeta = typeof arg1 === 'string' || typeof arg1 === 'function' ? { name, location: 'cookie', type: arg1, } : { ...arg1, name, location: 'cookie' }; if (isConstructor(paramMeta.type)) paramMeta.designType = paramMeta.type; if (meta.parameters) { meta.parameters = meta.parameters.filter(p => !(p.location === 'cookie' && String(p.name) === String(name))); } else meta.parameters = []; meta.parameters.push(paramMeta); }); return decorator; }; /** * */ decorator.Header = (name, arg1) => { decoratorChain.push((meta) => { const paramMeta = typeof arg1 === 'string' || typeof arg1 === 'function' ? { name, location: 'header', type: arg1, } : { ...arg1, name, location: 'header' }; if (isConstructor(paramMeta.type)) paramMeta.designType = paramMeta.type; if (meta.parameters) { meta.parameters = meta.parameters.filter(p => !(p.location === 'header' && String(p.name) === String(name))); } else meta.parameters = []; meta.parameters.push(paramMeta); }); return decorator; }; /** * */ decorator.QueryParam = (name, arg1) => { decoratorChain.push((meta) => { const paramMeta = typeof arg1 === 'string' || typeof arg1 === 'function' ? { name, location: 'query', type: arg1, } : { ...arg1, name, location: 'query' }; if (isConstructor(paramMeta.type)) paramMeta.designType = paramMeta.type; if (meta.parameters) { meta.parameters = meta.parameters.filter(p => !(p.location === 'query' && String(p.name) === String(name))); } else meta.parameters = []; meta.parameters.push(paramMeta); }); return decorator; }; /** * */ decorator.PathParam = (name, arg1) => { decoratorChain.push((meta) => { const paramMeta = typeof arg1 === 'string' || typeof arg1 === 'function' ? { name, location: 'path', type: arg1, } : { ...arg1, name, location: 'path' }; if (isConstructor(paramMeta.type)) paramMeta.designType = paramMeta.type; if (meta.parameters) { meta.parameters = meta.parameters.filter(p => !(p.location === 'path' && String(p.name) === String(name))); } else meta.parameters = []; meta.parameters.push(paramMeta); }); return decorator; }; /** * */ decorator.Response = (statusCode, responseOptions) => { const responseMeta = { ...responseOptions, statusCode, }; if (responseMeta.type) { responseMeta.contentType = responseMeta.contentType ?? MimeTypes.json; } const contentTypes = responseMeta.contentType ? Array.isArray(responseMeta.contentType) ? responseMeta.contentType : [responseMeta.contentType] : []; if (contentTypes.find(type => type.endsWith('+json') || type.endsWith('+xml') || typeIs.is(type, 'json', 'html', 'text', 'xml'))) { responseMeta.contentEncoding = responseMeta.contentEncoding ?? 'utf-8'; } if (isConstructor(responseMeta.type)) responseMeta.designType = responseMeta.type; decoratorChain.push((meta) => { meta.responses = meta.responses || []; meta.responses.push(responseMeta); }); return decorator; }; decorator.RequestContent = function (arg0) { const contentMeta = typeof arg0 === 'object' ? arg0 : { type: arg0 }; if (contentMeta.type) { contentMeta.contentType = contentMeta.contentType || MimeTypes.json; contentMeta.contentEncoding = contentMeta.contentEncoding || 'utf-8'; if (isConstructor(contentMeta.type)) contentMeta.designType = contentMeta.type; } decoratorChain.push((operationMetadata) => { operationMetadata.requestBody = operationMetadata.requestBody || { required: true, content: [], }; operationMetadata.requestBody.content = operationMetadata.requestBody.content || []; operationMetadata.requestBody.content.push(contentMeta); }); return decorator; }; decorator.MultipartContent = function (contentOpts, subInit) { const contentMetadata = { ...contentOpts, contentType: contentOpts?.contentType || 'multipart/form-data', }; decoratorChain.push((operationMetadata) => { operationMetadata.requestBody = operationMetadata.requestBody || { required: true, content: [], }; operationMetadata.requestBody.content = operationMetadata.requestBody.content || []; operationMetadata.requestBody.content.push(contentMetadata); }); if (subInit) { const configScope = { Field(fieldName, opts) { contentMetadata.multipartFields = contentMetadata.multipartFields || []; contentMetadata.multipartFields.push({ fieldName, fieldType: 'field', ...opts, }); return configScope; }, File(fieldName, opts) { contentMetadata.multipartFields = contentMetadata.multipartFields || []; contentMetadata.multipartFields.push({ fieldName, fieldType: 'file', ...opts, }); return configScope; }, }; subInit(configScope); } return decorator; }; /** * */ decorator.UseType = (...type) => { decoratorChain.push((meta) => { meta.types = meta.types || []; meta.types.push(...type); }); return decorator; }; return decorator; }