"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.SpecGenerator = void 0; const runtime_1 = require("@tsoa/runtime"); const handlebars = __importStar(require("handlebars")); class SpecGenerator { constructor(metadata, config) { this.metadata = metadata; this.config = config; this.determineImplicitAdditionalPropertiesValue = () => { if (this.config.noImplicitAdditionalProperties === 'silently-remove-extras') { return false; } else if (this.config.noImplicitAdditionalProperties === 'throw-on-extras') { return false; } else if (this.config.noImplicitAdditionalProperties === 'ignore') { return true; } else { return (0, runtime_1.assertNever)(this.config.noImplicitAdditionalProperties); } }; } buildAdditionalProperties(type) { return this.getSwaggerType(type); } buildOperationIdTemplate(inlineTemplate) { handlebars.registerHelper('titleCase', (value) => (value ? value.charAt(0).toUpperCase() + value.slice(1) : value)); handlebars.registerHelper('replace', (subject, searchValue, withValue = '') => (subject ? subject.replace(searchValue, withValue) : subject)); return handlebars.compile(inlineTemplate, { noEscape: true }); } getOperationId(controllerName, method) { return this.buildOperationIdTemplate(this.config.operationIdTemplate ?? '{{titleCase method.name}}')({ method, controllerName, }); } throwIfNotDataFormat(strToTest) { const guiltyUntilInnocent = strToTest; if (guiltyUntilInnocent === 'int32' || guiltyUntilInnocent === 'int64' || guiltyUntilInnocent === 'float' || guiltyUntilInnocent === 'double' || guiltyUntilInnocent === 'byte' || guiltyUntilInnocent === 'binary' || guiltyUntilInnocent === 'date' || guiltyUntilInnocent === 'date-time' || guiltyUntilInnocent === 'password') { return guiltyUntilInnocent; } else { return (0, runtime_1.assertNever)(guiltyUntilInnocent); } } throwIfNotDataType(strToTest) { const guiltyUntilInnocent = strToTest; if (guiltyUntilInnocent === 'array' || guiltyUntilInnocent === 'boolean' || guiltyUntilInnocent === 'integer' || guiltyUntilInnocent === 'file' || guiltyUntilInnocent === 'number' || guiltyUntilInnocent === 'object' || guiltyUntilInnocent === 'string' || guiltyUntilInnocent === 'undefined') { return guiltyUntilInnocent; } else { return (0, runtime_1.assertNever)(guiltyUntilInnocent); } } getSwaggerType(type, title) { if (type.dataType === 'void' || type.dataType === 'undefined') { return this.getSwaggerTypeForVoid(type.dataType); } else if (type.dataType === 'refEnum' || type.dataType === 'refObject' || type.dataType === 'refAlias') { return this.getSwaggerTypeForReferenceType(type); } else if (type.dataType === 'any' || type.dataType === 'binary' || type.dataType === 'boolean' || type.dataType === 'buffer' || type.dataType === 'byte' || type.dataType === 'date' || type.dataType === 'datetime' || type.dataType === 'double' || type.dataType === 'float' || type.dataType === 'file' || type.dataType === 'integer' || type.dataType === 'long' || type.dataType === 'object' || type.dataType === 'string') { return this.getSwaggerTypeForPrimitiveType(type.dataType); } else if (type.dataType === 'array') { return this.getSwaggerTypeForArrayType(type, title); } else if (type.dataType === 'enum') { return this.getSwaggerTypeForEnumType(type, title); } else if (type.dataType === 'union') { return this.getSwaggerTypeForUnionType(type, title); } else if (type.dataType === 'intersection') { return this.getSwaggerTypeForIntersectionType(type, title); } else if (type.dataType === 'nestedObjectLiteral') { return this.getSwaggerTypeForObjectLiteral(type, title); } else { return (0, runtime_1.assertNever)(type); } } getSwaggerTypeForObjectLiteral(objectLiteral, title) { const properties = this.buildProperties(objectLiteral.properties); const additionalProperties = objectLiteral.additionalProperties && this.getSwaggerType(objectLiteral.additionalProperties); const required = objectLiteral.properties.filter(prop => this.isRequiredWithoutDefault(prop) && !this.hasUndefined(prop)).map(prop => prop.name); // An empty list required: [] is not valid. // If all properties are optional, do not specify the required keyword. return { ...(title && { title }), properties, ...(additionalProperties && { additionalProperties }), ...(required && required.length && { required }), type: 'object', }; } getSwaggerTypeForReferenceType(_referenceType) { return { // Don't set additionalProperties value here since it will be set within the $ref's model when that $ref gets created }; } getSwaggerTypeForVoid(_dataType) { // Described here: https://swagger.io/docs/specification/describing-responses/#empty const voidSchema = { // isn't allowed to have additionalProperties at all (meaning not a boolean or object) }; return voidSchema; } getSwaggerTypeForPrimitiveType(dataType) { if (dataType === 'object') { if (process.env.NODE_ENV !== 'tsoa_test') { // eslint-disable-next-line no-console console.warn(`The type Object is discouraged. Please consider using an interface such as: export interface IStringToStringDictionary { [key: string]: string; } // or export interface IRecordOfAny { [key: string]: any; } `); } } const map = { any: { // While the any type is discouraged, it does explicitly allows anything, so it should always allow additionalProperties additionalProperties: true, }, binary: { type: 'string', format: 'binary' }, boolean: { type: 'boolean' }, buffer: { type: 'string', format: 'byte' }, byte: { type: 'string', format: 'byte' }, date: { type: 'string', format: 'date' }, datetime: { type: 'string', format: 'date-time' }, double: { type: 'number', format: 'double' }, file: { type: 'file' }, float: { type: 'number', format: 'float' }, integer: { type: 'integer', format: 'int32' }, long: { type: 'integer', format: 'int64' }, object: { additionalProperties: this.determineImplicitAdditionalPropertiesValue(), type: 'object', }, string: { type: 'string' }, }; return map[dataType]; } getSwaggerTypeForArrayType(arrayType, title) { return { items: this.getSwaggerType(arrayType.elementType, title), type: 'array', }; } determineTypesUsedInEnum(anEnum) { const typesUsedInEnum = anEnum.reduce((theSet, curr) => { const typeUsed = curr === null ? 'number' : typeof curr; theSet.add(typeUsed); return theSet; }, new Set()); return typesUsedInEnum; } hasUndefined(property) { return property.type.dataType === 'undefined' || (property.type.dataType === 'union' && property.type.types.some(type => type.dataType === 'undefined')); } queriesPropertyToQueryParameter(property) { return { parameterName: property.name, example: [property.example], description: property.description, in: 'query', name: property.name, required: this.isRequiredWithoutDefault(property), type: property.type, default: property.default, validators: property.validators, deprecated: property.deprecated, }; } isRequiredWithoutDefault(prop) { return prop.required && prop.default == null; } } exports.SpecGenerator = SpecGenerator; //# sourceMappingURL=specGenerator.js.map