UNPKG

@nestia/sdk

Version:

Nestia SDK and Swagger generator

220 lines 12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ReflectHttpOperationParameterAnalyzer = void 0; const constants_1 = require("@nestjs/common/constants"); const route_paramtypes_enum_1 = require("@nestjs/common/enums/route-paramtypes.enum"); const JsonMetadataFactory_1 = require("typia/lib/factories/JsonMetadataFactory"); const HttpFormDataProgrammer_1 = require("typia/lib/programmers/http/HttpFormDataProgrammer"); const HttpHeadersProgrammer_1 = require("typia/lib/programmers/http/HttpHeadersProgrammer"); const HttpParameterProgrammer_1 = require("typia/lib/programmers/http/HttpParameterProgrammer"); const HttpQueryProgrammer_1 = require("typia/lib/programmers/http/HttpQueryProgrammer"); const TextPlainValidator_1 = require("../transformers/TextPlainValidator"); const HttpHeadersValidator_1 = require("../validators/HttpHeadersValidator"); const HttpQueryValidator_1 = require("../validators/HttpQueryValidator"); var ReflectHttpOperationParameterAnalyzer; (function (ReflectHttpOperationParameterAnalyzer) { ReflectHttpOperationParameterAnalyzer.analyze = (ctx) => { const preconfigured = analyzePreconfigured(ctx); const errors = []; //---- // FIND CONTRADICTIONS //---- // GET AND HEAD METHOD const contradictErrors = []; const contradict = (message) => { contradictErrors.push(message); }; if ((ctx.httpMethod === "GET" || ctx.httpMethod === "HEAD") && preconfigured.some((x) => x.category === "body")) contradict(`@Body() is not allowed in the ${ctx.httpMethod} method.`); // FIND DUPLICATED BODY if (preconfigured.filter((x) => x.category === "body" && x.field === undefined).length > 1) contradict(`Duplicated @Body() is not allowed.`); if (preconfigured.filter((x) => x.category === "query" && x.field === undefined).length > 1) contradict(`Duplicated @Query() without field name is not allowed.`); if (preconfigured.filter((x) => x.category === "headers" && x.field === undefined).length > 1) contradict(`Duplicated @Headers() without field name is not allowed.`); // FIND DUPLICATED FIELDS if (isUnique(preconfigured .filter((x) => x.category === "param") .map((x) => x.field) .filter((field) => field !== undefined)) === false) contradict(`Duplicated field names of path are not allowed.`); if (isUnique(preconfigured .filter((x) => x.category === "query") .map((x) => x.field) .filter((field) => field !== undefined)) === false) contradict(`Duplicated field names of query are not allowed.`); if (isUnique(preconfigured .filter((x) => x.category === "headers") .map((x) => x.field) .filter((field) => field !== undefined)) === false) contradict(`Duplicated field names of headers are not allowed.`); if (contradictErrors.length) errors.push({ file: ctx.controller.file, class: ctx.controller.class.name, function: ctx.functionName, from: "", contents: contradictErrors, }); //---- // COMPOSE PARAMETERS //---- const parameters = preconfigured .map((p) => { var _a, _b, _c; // METADATA INFO const pErrorContents = []; const matched = ctx.metadata.parameters.find((x) => x.index === p.index); const report = () => { errors.push({ file: ctx.controller.file, class: ctx.controller.class.name, function: ctx.functionName, from: `parameter ${matched ? JSON.stringify(matched.name) : `of ${p.index} th`}`, contents: pErrorContents, }); return null; }; // VALIDATE TYPE if (matched === undefined) pErrorContents.push(`Unable to find parameter type.`); else if (matched.type === null) pErrorContents.push(`Failed to get the type info.`); // CONSIDER KIND const schema = (() => { if (matched === undefined) return null; const result = p.category === "body" && (p.contentType === "application/json" || p.encrypted === true) ? matched.primitive : matched.resolved; return result.success ? result.data : null; })(); if (p.category === "body" && p.field !== undefined) pErrorContents.push(`@Body() must not have a field name.`); else if (p.category === "param" && p.field === undefined) pErrorContents.push(`@Param() must have a field name.`); if (pErrorContents.length) return report(); else if (matched === undefined || matched.type === null || schema === null) return null; // unreachable const example = ((_a = Reflect.getMetadata("nestia/SwaggerExample/Parameters", ctx.controller.class.prototype, ctx.functionName)) !== null && _a !== void 0 ? _a : []).find((x) => x.index === matched.index); // COMPOSITION if (p.category === "param") return Object.assign({ category: p.category, index: p.index, field: p.field, name: matched.name, type: matched.type, validate: HttpParameterProgrammer_1.HttpParameterProgrammer.validate, description: matched.description, jsDocTags: matched.jsDocTags, example: example === null || example === void 0 ? void 0 : example.example, examples: example === null || example === void 0 ? void 0 : example.examples }, schema); else if (p.category === "query") return Object.assign({ category: p.category, index: p.index, field: (_b = p.field) !== null && _b !== void 0 ? _b : null, name: matched.name, type: matched.type, validate: p.field ? HttpQueryValidator_1.HttpQueryValidator.validate : HttpQueryProgrammer_1.HttpQueryProgrammer.validate, description: matched.description, jsDocTags: matched.jsDocTags, example: example === null || example === void 0 ? void 0 : example.example, examples: example === null || example === void 0 ? void 0 : example.examples }, schema); else if (p.category === "headers") return Object.assign({ category: p.category, index: p.index, field: (_c = p.field) !== null && _c !== void 0 ? _c : null, name: matched.name, type: matched.type, validate: p.field ? HttpHeadersValidator_1.HttpHeadersValidator.validate : HttpHeadersProgrammer_1.HttpHeadersProgrammer.validate, description: matched.description, jsDocTags: matched.jsDocTags, example: example === null || example === void 0 ? void 0 : example.example, examples: example === null || example === void 0 ? void 0 : example.examples }, schema); else if (p.category === "body") return Object.assign({ category: p.category, index: p.index, encrypted: !!p.encrypted, contentType: p.contentType, name: matched.name, type: matched.type, validate: p.contentType === "application/json" || p.encrypted === true ? JsonMetadataFactory_1.JsonMetadataFactory.validate : p.contentType === "application/x-www-form-urlencoded" ? HttpQueryProgrammer_1.HttpQueryProgrammer.validate : p.contentType === "multipart/form-data" ? HttpFormDataProgrammer_1.HttpFormDataProgrammer.validate : TextPlainValidator_1.TextPlainValidator.validate, description: matched.description, jsDocTags: matched.jsDocTags, example: example === null || example === void 0 ? void 0 : example.example, examples: example === null || example === void 0 ? void 0 : example.examples }, schema); else { pErrorContents.push(`Unknown kind of the parameter.`); return report(); } }) .filter((x) => x !== null); if (errors.length) ctx.errors.push(...errors); return parameters; }; const analyzePreconfigured = (props) => { const dict = Reflect.getMetadata(constants_1.ROUTE_ARGS_METADATA, props.controller.class, props.functionName); if (dict === undefined) return []; return Object.entries(dict) .map(([key, param]) => analyzeHttpParameter(key, param)) .filter((x) => x !== null) .sort((x, y) => x.index - y.index); }; const analyzeHttpParameter = (key, param) => { const symbol = key.split(":")[0]; if (symbol.indexOf("__custom") !== -1) return analyzeCustomParameter(param); const category = getNestParamType(Number(symbol[0])); if (category === null) return null; if (category === "body") return { category: "body", index: param.index, field: param.data, contentType: "application/json", }; else return { category, index: param.index, field: param.data, }; }; const analyzeCustomParameter = (param) => { if (param.factory === undefined) return null; else if (param.factory.name === "EncryptedBody" || param.factory.name === "PlainBody" || param.factory.name === "TypedQueryBody" || param.factory.name === "TypedBody" || param.factory.name === "TypedFormDataBody") return { category: "body", index: param.index, encrypted: param.factory.name === "EncryptedBody", contentType: param.factory.name === "PlainBody" || param.factory.name === "EncryptedBody" ? "text/plain" : param.factory.name === "TypedQueryBody" ? "application/x-www-form-urlencoded" : param.factory.name === "TypedFormDataBody" ? "multipart/form-data" : "application/json", }; else if (param.factory.name === "TypedHeaders") return { category: "headers", index: param.index, field: param.data, }; else if (param.factory.name === "TypedParam") return { category: "param", index: param.index, field: param.data, }; else if (param.factory.name === "TypedQuery") return { category: "query", index: param.index, field: undefined, }; else return null; }; const isUnique = (values) => new Set(values).size === values.length; })(ReflectHttpOperationParameterAnalyzer || (exports.ReflectHttpOperationParameterAnalyzer = ReflectHttpOperationParameterAnalyzer = {})); const getNestParamType = (value) => { if (value === route_paramtypes_enum_1.RouteParamtypes.BODY) return "body"; else if (value === route_paramtypes_enum_1.RouteParamtypes.HEADERS) return "headers"; else if (value === route_paramtypes_enum_1.RouteParamtypes.QUERY) return "query"; else if (value === route_paramtypes_enum_1.RouteParamtypes.PARAM) return "param"; return null; }; //# sourceMappingURL=ReflectHttpOperationParameterAnalyzer.js.map