255 lines
12 KiB
JavaScript
255 lines
12 KiB
JavaScript
"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.AbstractRouteGenerator = void 0;
|
|
const path = __importStar(require("path"));
|
|
const runtime_1 = require("@tsoa/runtime");
|
|
const internalTypeGuards_1 = require("../utils/internalTypeGuards");
|
|
const pathUtils_1 = require("../utils/pathUtils");
|
|
const fs_1 = require("../utils/fs");
|
|
class AbstractRouteGenerator {
|
|
constructor(metadata, options) {
|
|
this.metadata = metadata;
|
|
this.options = options;
|
|
}
|
|
buildModels() {
|
|
const models = {};
|
|
Object.keys(this.metadata.referenceTypeMap).forEach(name => {
|
|
const referenceType = this.metadata.referenceTypeMap[name];
|
|
let model;
|
|
if (referenceType.dataType === 'refEnum') {
|
|
const refEnumModel = {
|
|
dataType: 'refEnum',
|
|
enums: referenceType.enums,
|
|
};
|
|
model = refEnumModel;
|
|
}
|
|
else if (referenceType.dataType === 'refObject') {
|
|
const propertySchemaDictionary = {};
|
|
referenceType.properties.forEach(property => {
|
|
propertySchemaDictionary[property.name] = this.buildPropertySchema(property);
|
|
});
|
|
const refObjModel = {
|
|
dataType: 'refObject',
|
|
properties: propertySchemaDictionary,
|
|
};
|
|
if (referenceType.additionalProperties) {
|
|
refObjModel.additionalProperties = this.buildProperty(referenceType.additionalProperties);
|
|
}
|
|
else if (this.options.noImplicitAdditionalProperties !== 'ignore') {
|
|
refObjModel.additionalProperties = false;
|
|
}
|
|
else {
|
|
// Since Swagger allows "excess properties" (to use a TypeScript term) by default
|
|
refObjModel.additionalProperties = true;
|
|
}
|
|
model = refObjModel;
|
|
}
|
|
else if (referenceType.dataType === 'refAlias') {
|
|
const refType = {
|
|
dataType: 'refAlias',
|
|
type: {
|
|
...this.buildProperty(referenceType.type),
|
|
validators: referenceType.validators,
|
|
default: referenceType.default,
|
|
},
|
|
};
|
|
model = refType;
|
|
}
|
|
else {
|
|
model = (0, runtime_1.assertNever)(referenceType);
|
|
}
|
|
models[name] = model;
|
|
});
|
|
return models;
|
|
}
|
|
pathTransformer(path) {
|
|
return (0, pathUtils_1.convertBracesPathParams)(path);
|
|
}
|
|
buildContext() {
|
|
const authenticationModule = this.options.authenticationModule ? this.getRelativeImportPath(this.options.authenticationModule) : undefined;
|
|
const iocModule = this.options.iocModule ? this.getRelativeImportPath(this.options.iocModule) : undefined;
|
|
// Left in for backwards compatibility, previously if we're working locally then tsoa runtime code wasn't an importable module but now it is.
|
|
const canImportByAlias = true;
|
|
const normalisedBasePath = (0, pathUtils_1.normalisePath)(this.options.basePath, '/');
|
|
return {
|
|
authenticationModule,
|
|
basePath: normalisedBasePath,
|
|
canImportByAlias,
|
|
controllers: this.metadata.controllers.map(controller => {
|
|
const normalisedControllerPath = this.pathTransformer((0, pathUtils_1.normalisePath)(controller.path, '/'));
|
|
return {
|
|
actions: controller.methods.map(method => {
|
|
const parameterObjs = {};
|
|
method.parameters.forEach(parameter => {
|
|
parameterObjs[parameter.parameterName] = this.buildParameterSchema(parameter);
|
|
});
|
|
const normalisedMethodPath = this.pathTransformer((0, pathUtils_1.normalisePath)(method.path, '/'));
|
|
const normalisedFullPath = (0, pathUtils_1.normalisePath)(`${normalisedBasePath}${normalisedControllerPath}${normalisedMethodPath}`, '/', '', false);
|
|
const uploadFilesWithDifferentFieldParameter = method.parameters.filter(parameter => parameter.type.dataType === 'file' || (parameter.type.dataType === 'array' && parameter.type.elementType.dataType === 'file'));
|
|
return {
|
|
fullPath: normalisedFullPath,
|
|
method: method.method.toLowerCase(),
|
|
name: method.name,
|
|
parameters: parameterObjs,
|
|
path: normalisedMethodPath,
|
|
uploadFile: uploadFilesWithDifferentFieldParameter.length > 0,
|
|
uploadFileName: uploadFilesWithDifferentFieldParameter.map(parameter => ({
|
|
name: parameter.name,
|
|
maxCount: parameter.type.dataType === 'file' ? 1 : undefined,
|
|
multiple: parameter.type.dataType === 'array' && parameter.type.elementType.dataType === 'file',
|
|
})),
|
|
security: method.security,
|
|
successStatus: method.successStatus ? method.successStatus : 'undefined',
|
|
};
|
|
}),
|
|
modulePath: this.getRelativeImportPath(controller.location),
|
|
name: controller.name,
|
|
path: normalisedControllerPath,
|
|
};
|
|
}),
|
|
environment: process.env,
|
|
iocModule,
|
|
minimalSwaggerConfig: { noImplicitAdditionalProperties: this.options.noImplicitAdditionalProperties, bodyCoercion: this.options.bodyCoercion },
|
|
models: this.buildModels(),
|
|
useFileUploads: this.metadata.controllers.some(controller => controller.methods.some(method => !!method.parameters.find(parameter => {
|
|
if (parameter.type.dataType === 'file') {
|
|
return true;
|
|
}
|
|
else if (parameter.type.dataType === 'array' && parameter.type.elementType.dataType === 'file') {
|
|
return true;
|
|
}
|
|
return false;
|
|
}))),
|
|
multerOpts: {
|
|
limits: {
|
|
fileSize: 8388608, // 8mb
|
|
},
|
|
...this.options.multerOpts,
|
|
},
|
|
useSecurity: this.metadata.controllers.some(controller => controller.methods.some(method => !!method.security.length)),
|
|
esm: this.options.esm,
|
|
};
|
|
}
|
|
getRelativeImportPath(fileLocation) {
|
|
const currentExt = path.extname(fileLocation);
|
|
let newExtension = this.options.rewriteRelativeImportExtensions ? currentExt : '';
|
|
if (this.options.esm && !this.options.rewriteRelativeImportExtensions) {
|
|
switch (currentExt) {
|
|
case '.ts':
|
|
default:
|
|
newExtension = '.js';
|
|
break;
|
|
case '.mts':
|
|
newExtension = '.mjs';
|
|
break;
|
|
case '.cts':
|
|
newExtension = '.cjs';
|
|
break;
|
|
}
|
|
}
|
|
fileLocation = fileLocation.replace(/\.(ts|mts|cts)$/, ''); // no ts extension in import
|
|
return `./${path.relative(this.options.routesDir, fileLocation).replace(/\\/g, '/')}${newExtension}`;
|
|
}
|
|
buildPropertySchema(source) {
|
|
const propertySchema = this.buildProperty(source.type);
|
|
propertySchema.default = source.default;
|
|
propertySchema.required = source.required ? true : undefined;
|
|
if (Object.keys(source.validators).length > 0) {
|
|
propertySchema.validators = source.validators;
|
|
}
|
|
return propertySchema;
|
|
}
|
|
buildParameterSchema(source) {
|
|
const property = this.buildProperty(source.type);
|
|
const parameter = {
|
|
default: source.default,
|
|
in: source.in,
|
|
name: source.name,
|
|
required: source.required ? true : undefined,
|
|
};
|
|
const parameterSchema = Object.assign(parameter, property);
|
|
if (Object.keys(source.validators).length > 0) {
|
|
parameterSchema.validators = source.validators;
|
|
}
|
|
return parameterSchema;
|
|
}
|
|
buildProperty(type) {
|
|
const schema = {
|
|
dataType: type.dataType,
|
|
};
|
|
if ((0, internalTypeGuards_1.isRefType)(type)) {
|
|
schema.dataType = undefined;
|
|
schema.ref = type.refName;
|
|
}
|
|
if (type.dataType === 'array') {
|
|
const arrayType = type;
|
|
if ((0, internalTypeGuards_1.isRefType)(arrayType.elementType)) {
|
|
schema.array = {
|
|
dataType: arrayType.elementType.dataType,
|
|
ref: arrayType.elementType.refName,
|
|
};
|
|
}
|
|
else {
|
|
schema.array = this.buildProperty(arrayType.elementType);
|
|
}
|
|
}
|
|
if (type.dataType === 'enum') {
|
|
schema.enums = type.enums;
|
|
}
|
|
if (type.dataType === 'union' || type.dataType === 'intersection') {
|
|
schema.subSchemas = type.types.map(type => this.buildProperty(type));
|
|
}
|
|
if (type.dataType === 'nestedObjectLiteral') {
|
|
const objLiteral = type;
|
|
schema.nestedProperties = objLiteral.properties.reduce((acc, prop) => {
|
|
return { ...acc, [prop.name]: this.buildPropertySchema(prop) };
|
|
}, {});
|
|
schema.additionalProperties = objLiteral.additionalProperties && this.buildProperty(objLiteral.additionalProperties);
|
|
}
|
|
return schema;
|
|
}
|
|
async shouldWriteFile(fileName, content) {
|
|
if (this.options.noWriteIfUnchanged) {
|
|
if (await (0, fs_1.fsExists)(fileName)) {
|
|
const existingContent = (await (0, fs_1.fsReadFile)(fileName)).toString();
|
|
return content !== existingContent;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
exports.AbstractRouteGenerator = AbstractRouteGenerator;
|
|
//# sourceMappingURL=routeGenerator.js.map
|