Cygni_backend/node_modules/@tsoa/cli/dist/cli.js

355 lines
15 KiB
JavaScript

#!/usr/bin/env node
"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;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateSpecConfig = void 0;
exports.runCLI = runCLI;
exports.generateSpecAndRoutes = generateSpecAndRoutes;
const yaml_1 = __importDefault(require("yaml"));
const yargs_1 = __importDefault(require("yargs"));
const helpers_1 = require("yargs/helpers");
const metadataGenerator_1 = require("./metadataGeneration/metadataGenerator");
const generate_routes_1 = require("./module/generate-routes");
const generate_spec_1 = require("./module/generate-spec");
const fs_1 = require("./utils/fs");
const node_path_1 = require("node:path");
const workingDir = process.cwd();
let packageJson;
const getPackageJsonValue = async (key, defaultValue = '') => {
if (!packageJson) {
try {
const packageJsonRaw = await (0, fs_1.fsReadFile)(`${workingDir}/package.json`);
packageJson = JSON.parse(packageJsonRaw.toString('utf8'));
}
catch (err) {
return defaultValue;
}
}
return packageJson[key] || '';
};
const nameDefault = () => getPackageJsonValue('name', 'TSOA');
const versionDefault = () => getPackageJsonValue('version', '1.0.0');
const descriptionDefault = () => getPackageJsonValue('description', 'Build swagger-compliant REST APIs using TypeScript and Node');
const licenseDefault = () => getPackageJsonValue('license', 'MIT');
const determineNoImplicitAdditionalSetting = (noImplicitAdditionalProperties) => {
if (noImplicitAdditionalProperties === 'silently-remove-extras' || noImplicitAdditionalProperties === 'throw-on-extras' || noImplicitAdditionalProperties === 'ignore') {
return noImplicitAdditionalProperties;
}
else {
return 'ignore';
}
};
const authorInformation = getPackageJsonValue('author', 'unknown');
const isYamlExtension = (extension) => extension === '.yaml' || extension === '.yml';
const isJsExtension = (extension) => extension === '.js' || extension === '.cjs';
const getConfig = async (configPath = 'tsoa.json') => {
let config;
const ext = (0, node_path_1.extname)(configPath);
const configFullPath = (0, node_path_1.isAbsolute)(configPath) ? configPath : `${workingDir}/${configPath}`;
try {
if (isYamlExtension(ext)) {
const configRaw = await (0, fs_1.fsReadFile)(configFullPath);
config = yaml_1.default.parse(configRaw.toString('utf8'));
}
else if (isJsExtension(ext)) {
config = await Promise.resolve(`${configFullPath}`).then(s => __importStar(require(s)));
}
else {
const configRaw = await (0, fs_1.fsReadFile)(configFullPath);
config = JSON.parse(configRaw.toString('utf8'));
}
}
catch (err) {
if (!(err instanceof Error)) {
console.error(err);
throw Error(`Unhandled error encountered loading '${configPath}': ${String(err)}`);
}
else if ('code' in err && err.code === 'MODULE_NOT_FOUND') {
throw Error(`No config file found at '${configPath}'`);
}
else if (err.name === 'SyntaxError') {
console.error(err);
const errorType = isJsExtension(ext) ? 'JS' : 'JSON';
throw Error(`Invalid ${errorType} syntax in config at '${configPath}': ${err.message}`);
}
else {
console.error(err);
throw Error(`Unhandled error encountered loading '${configPath}': ${err.message}`);
}
}
return config;
};
const resolveConfig = async (config) => {
return typeof config === 'object' ? config : getConfig(config);
};
const validateCompilerOptions = (config) => {
return (config || {});
};
const validateSpecConfig = async (config) => {
if (!config.spec) {
throw new Error('Missing spec: configuration must contain spec. Spec used to be called swagger in previous versions of tsoa.');
}
if (!config.spec.outputDirectory) {
throw new Error('Missing outputDirectory: configuration must contain output directory.');
}
if (!config.entryFile && (!config.controllerPathGlobs || !config.controllerPathGlobs.length)) {
throw new Error('Missing entryFile and controllerPathGlobs: Configuration must contain an entry point file or controller path globals.');
}
if (!!config.entryFile && !(await (0, fs_1.fsExists)(config.entryFile))) {
throw new Error(`EntryFile not found: ${config.entryFile} - please check your tsoa config.`);
}
config.spec.version = config.spec.version || (await versionDefault());
config.spec.specVersion = config.spec.specVersion || 2;
if (config.spec.specVersion !== 2 && config.spec.specVersion !== 3) {
throw new Error('Unsupported Spec version.');
}
if (config.spec.spec && !['immediate', 'recursive', 'deepmerge', undefined].includes(config.spec.specMerging)) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
throw new Error(`Invalid specMerging config: ${config.spec.specMerging}`);
}
const noImplicitAdditionalProperties = determineNoImplicitAdditionalSetting(config.noImplicitAdditionalProperties);
config.spec.name = config.spec.name || (await nameDefault());
config.spec.description = config.spec.description || (await descriptionDefault());
config.spec.license = config.spec.license || (await licenseDefault());
config.spec.basePath = config.spec.basePath || '/';
// defaults to template that may generate non-unique operation ids.
// @see https://github.com/lukeautry/tsoa/issues/1005
config.spec.operationIdTemplate = config.spec.operationIdTemplate || '{{titleCase method.name}}';
if (!config.spec.contact) {
config.spec.contact = {};
}
const author = await authorInformation;
if (typeof author === 'string') {
const contact = /^([^<(]*)?\s*(?:<([^>(]*)>)?\s*(?:\(([^)]*)\)|$)/m.exec(author);
config.spec.contact.name = config.spec.contact.name || contact?.[1];
config.spec.contact.email = config.spec.contact.email || contact?.[2];
config.spec.contact.url = config.spec.contact.url || contact?.[3];
}
else if (typeof author === 'object') {
config.spec.contact.name = config.spec.contact.name || author?.name;
config.spec.contact.email = config.spec.contact.email || author?.email;
config.spec.contact.url = config.spec.contact.url || author?.url;
}
if (!config.defaultNumberType) {
config.defaultNumberType = 'double';
}
if (config.spec.rootSecurity) {
if (!Array.isArray(config.spec.rootSecurity)) {
throw new Error('spec.rootSecurity must be an array');
}
if (config.spec.rootSecurity) {
const ok = config.spec.rootSecurity.every(security => typeof security === 'object' && security !== null && Object.values(security).every(scope => Array.isArray(scope)));
if (!ok) {
throw new Error('spec.rootSecurity must be an array of objects whose keys are security scheme names and values are arrays of scopes');
}
}
}
return {
...config.spec,
noImplicitAdditionalProperties,
entryFile: config.entryFile,
controllerPathGlobs: config.controllerPathGlobs,
};
};
exports.validateSpecConfig = validateSpecConfig;
const validateRoutesConfig = async (config) => {
if (!config.entryFile && (!config.controllerPathGlobs || !config.controllerPathGlobs.length)) {
throw new Error('Missing entryFile and controllerPathGlobs: Configuration must contain an entry point file or controller path globals.');
}
if (!!config.entryFile && !(await (0, fs_1.fsExists)(config.entryFile))) {
throw new Error(`EntryFile not found: ${config.entryFile} - Please check your tsoa config.`);
}
if (!config.routes.routesDir) {
throw new Error('Missing routesDir: Configuration must contain a routes file output directory.');
}
if (config.routes.authenticationModule && !((await (0, fs_1.fsExists)(config.routes.authenticationModule)) || (await (0, fs_1.fsExists)(config.routes.authenticationModule + '.ts')))) {
throw new Error(`No authenticationModule file found at '${config.routes.authenticationModule}'`);
}
if (config.routes.iocModule && !((await (0, fs_1.fsExists)(config.routes.iocModule)) || (await (0, fs_1.fsExists)(config.routes.iocModule + '.ts')))) {
throw new Error(`No iocModule file found at '${config.routes.iocModule}'`);
}
const noImplicitAdditionalProperties = determineNoImplicitAdditionalSetting(config.noImplicitAdditionalProperties);
const bodyCoercion = config.routes.bodyCoercion ?? true;
config.routes.basePath = config.routes.basePath || '/';
return {
...config.routes,
entryFile: config.entryFile,
noImplicitAdditionalProperties,
bodyCoercion,
controllerPathGlobs: config.controllerPathGlobs,
multerOpts: config.multerOpts,
rootSecurity: config.spec.rootSecurity,
};
};
const configurationArgs = {
alias: 'c',
describe: 'tsoa configuration file; default is tsoa.json in the working directory',
required: false,
string: true,
};
const hostArgs = {
describe: 'API host',
required: false,
string: true,
};
const basePathArgs = {
describe: 'Base API path',
required: false,
string: true,
};
const yarmlArgs = {
describe: 'Swagger spec yaml format',
required: false,
boolean: true,
};
const jsonArgs = {
describe: 'Swagger spec json format',
required: false,
boolean: true,
};
function runCLI() {
return (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
.usage('Usage: $0 <command> [options]')
.command('spec', 'Generate OpenAPI spec', {
basePath: basePathArgs,
configuration: configurationArgs,
host: hostArgs,
json: jsonArgs,
yaml: yarmlArgs,
}, args => SpecGenerator(args))
.command('routes', 'Generate routes', {
basePath: basePathArgs,
configuration: configurationArgs,
}, args => routeGenerator(args))
.command('spec-and-routes', 'Generate OpenAPI spec and routes', {
basePath: basePathArgs,
configuration: configurationArgs,
host: hostArgs,
json: jsonArgs,
yaml: yarmlArgs,
}, args => void generateSpecAndRoutes(args))
.demandCommand(1, 1, 'Must provide a valid command.')
.help('help')
.alias('help', 'h')
.parse();
}
if (require.main === module) {
void (async () => {
try {
await runCLI();
}
catch (err) {
// eslint-disable-next-line no-console
console.error('tsoa cli error:\n', err);
process.exit(1);
}
})();
}
async function SpecGenerator(args) {
try {
const config = await resolveConfig(args.configuration);
if (args.basePath) {
config.spec.basePath = args.basePath;
}
if (args.host) {
config.spec.host = args.host;
}
if (args.yaml) {
config.spec.yaml = args.yaml;
}
if (args.json) {
config.spec.yaml = false;
}
const compilerOptions = validateCompilerOptions(config.compilerOptions);
const swaggerConfig = await (0, exports.validateSpecConfig)(config);
await (0, generate_spec_1.generateSpec)(swaggerConfig, compilerOptions, config.ignore);
}
catch (err) {
// eslint-disable-next-line no-console
console.error('Generate swagger error.\n', err);
process.exit(1);
}
}
async function routeGenerator(args) {
try {
const config = await resolveConfig(args.configuration);
if (args.basePath) {
config.routes.basePath = args.basePath;
}
const compilerOptions = validateCompilerOptions(config.compilerOptions);
const routesConfig = await validateRoutesConfig(config);
await (0, generate_routes_1.generateRoutes)(routesConfig, compilerOptions, config.ignore);
}
catch (err) {
// eslint-disable-next-line no-console
console.error('Generate routes error.\n', err);
process.exit(1);
}
}
async function generateSpecAndRoutes(args, metadata) {
try {
const config = await resolveConfig(args.configuration);
if (args.basePath) {
config.spec.basePath = args.basePath;
}
if (args.host) {
config.spec.host = args.host;
}
if (args.yaml) {
config.spec.yaml = args.yaml;
}
if (args.json) {
config.spec.yaml = false;
}
const compilerOptions = validateCompilerOptions(config.compilerOptions);
const routesConfig = await validateRoutesConfig(config);
const swaggerConfig = await (0, exports.validateSpecConfig)(config);
if (!metadata) {
metadata = new metadataGenerator_1.MetadataGenerator(config.entryFile, compilerOptions, config.ignore, config.controllerPathGlobs, config.spec.rootSecurity, config.defaultNumberType, config.routes.esm).Generate();
}
await Promise.all([(0, generate_routes_1.generateRoutes)(routesConfig, compilerOptions, config.ignore, metadata), (0, generate_spec_1.generateSpec)(swaggerConfig, compilerOptions, config.ignore, metadata)]);
return metadata;
}
catch (err) {
// eslint-disable-next-line no-console
console.error('Generate routes error.\n', err);
process.exit(1);
throw err;
}
}
//# sourceMappingURL=cli.js.map