Skip to content

Commit

Permalink
Merge pull request #972 from samchon/feature/implicit
Browse files Browse the repository at this point in the history
Support #203: allow implicit type when generating swagger file.
  • Loading branch information
samchon authored Jul 27, 2024
2 parents 62794ee + 0bce092 commit 674697d
Showing 106 changed files with 358 additions and 302 deletions.
2 changes: 1 addition & 1 deletion benchmark/package.json
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@
"reflect-metadata": "^0.2.2",
"tgrid": "^1.0.2",
"tstl": "^3.0.0",
"typia": "^6.5.4"
"typia": "^6.6.0"
},
"devDependencies": {
"@types/autocannon": "^7.9.0",
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@nestia/station",
"version": "3.8.1",
"version": "3.9.0",
"description": "Nestia station",
"scripts": {
"build": "node build/index.js",
2 changes: 1 addition & 1 deletion packages/benchmark/package.json
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@
"ts-patch": "^3.2.1",
"typescript": "^5.5.4",
"typescript-transform-paths": "^3.4.7",
"typia": "^6.5.4",
"typia": "^6.6.0",
"uuid": "^10.0.0"
},
"dependencies": {
10 changes: 5 additions & 5 deletions packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nestia/core",
"version": "3.8.1",
"version": "3.9.0",
"description": "Super-fast validation decorators of NestJS",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
@@ -36,7 +36,7 @@
},
"homepage": "https://nestia.io",
"dependencies": {
"@nestia/fetcher": "^3.8.1",
"@nestia/fetcher": "^3.9.0",
"@nestjs/common": ">=7.0.1",
"@nestjs/core": ">=7.0.1",
"@samchon/openapi": "^0.4.2",
@@ -49,16 +49,16 @@
"reflect-metadata": ">=0.1.12",
"rxjs": ">=6.0.3",
"tgrid": "^1.0.0",
"typia": "^6.5.4",
"typia": "^6.6.0",
"ws": "^7.5.3"
},
"peerDependencies": {
"@nestia/fetcher": ">=3.8.1",
"@nestia/fetcher": ">=3.9.0",
"@nestjs/common": ">=7.0.1",
"@nestjs/core": ">=7.0.1",
"reflect-metadata": ">=0.1.12",
"rxjs": ">=6.0.3",
"typia": ">=6.5.4 <7.0.0"
"typia": ">=6.6.0 <7.0.0"
},
"devDependencies": {
"@fastify/multipart": "^8.1.0",
2 changes: 1 addition & 1 deletion packages/e2e/package.json
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@
"ts-patch": "^3.2.1",
"typescript": "^5.5.3",
"typescript-transform-paths": "^3.4.7",
"typia": "^6.5.4"
"typia": "^6.6.0"
},
"files": [
"lib",
2 changes: 1 addition & 1 deletion packages/fetcher/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nestia/fetcher",
"version": "3.8.1",
"version": "3.9.0",
"description": "Fetcher library of Nestia SDK",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
14 changes: 7 additions & 7 deletions packages/sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nestia/sdk",
"version": "3.8.1",
"version": "3.9.0",
"description": "Nestia SDK and Swagger generator",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
@@ -32,8 +32,8 @@
},
"homepage": "https://nestia.io",
"dependencies": {
"@nestia/core": "^3.8.1",
"@nestia/fetcher": "^3.8.1",
"@nestia/core": "^3.9.0",
"@nestia/fetcher": "^3.9.0",
"@samchon/openapi": "^0.4.2",
"@wrtnio/openai-function-schema": "^0.2.3",
"cli": "^1.0.1",
@@ -45,16 +45,16 @@
"tsconfck": "^2.1.2",
"tsconfig-paths": "^4.1.1",
"tstl": "^3.0.0",
"typia": "^6.5.4"
"typia": "^6.6.0"
},
"peerDependencies": {
"@nestia/core": ">=3.8.1",
"@nestia/fetcher": ">=3.8.1",
"@nestia/core": ">=3.9.0",
"@nestia/fetcher": ">=3.9.0",
"@nestjs/common": ">=7.0.1",
"@nestjs/core": ">=7.0.1",
"reflect-metadata": ">=0.1.12",
"ts-node": ">=10.6.0",
"typia": ">=6.5.4 <7.0.0"
"typia": ">=6.6.0 <7.0.0"
},
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
8 changes: 2 additions & 6 deletions packages/sdk/src/analyses/ExceptionAnalyzer.ts
Original file line number Diff line number Diff line change
@@ -91,16 +91,12 @@ export namespace ExceptionAnalyzer {
imports: props.imports,
type,
});
if (
tuple === null ||
(project.config.clone !== true &&
(tuple.typeName === "__type" || tuple.typeName === "__object"))
) {
if (tuple === null) {
project.errors.push({
file: props.controller.file,
controller: props.controller.name,
function: props.operation.name,
message: "TypeException() with implicit (unnamed) type.",
message: `TypeException() with unknown type on ${status} status.`,
});
return false;
}
17 changes: 4 additions & 13 deletions packages/sdk/src/analyses/TypedHttpOperationAnalyzer.ts
Original file line number Diff line number Diff line change
@@ -72,17 +72,12 @@ export namespace TypedHttpOperationAnalyzer {
imports: importDict,
type: signature.getReturnType(),
});
if (
outputType === null ||
(project.config.clone !== true &&
(outputType.typeName === "__type" ||
outputType.typeName === "__object"))
) {
if (outputType === null) {
project.errors.push({
file: props.controller.file,
controller: props.controller.name,
function: props.operation.name,
message: "implicit (unnamed) return type.",
message: "unknown return type.",
});
return [];
} else if (
@@ -324,16 +319,12 @@ export namespace TypedHttpOperationAnalyzer {
imports: props.imports,
type,
});
if (
tuple === null ||
(project.config.clone !== true &&
(tuple.typeName === "__type" || tuple.typeName === "__object"))
)
if (tuple === null)
errors.push({
file: props.controller.file,
controller: props.controller.name,
function: props.function,
message: `implicit (unnamed) parameter type from "${name}".`,
message: `unknown parameter type from ${JSON.stringify(name)}.`,
});
if (errors.length) {
project.errors.push(...errors);
20 changes: 13 additions & 7 deletions packages/sdk/src/analyses/TypedWebSocketOperationAnalyzer.ts
Original file line number Diff line number Diff line change
@@ -157,16 +157,24 @@ export namespace TypedWebSocketOperationAnalyzer {
imports: props.imports,
type,
});
if (
tuple === null ||
if (tuple === null)
errors.push({
file: props.controller.file,
controller: props.controller.name,
function: props.function,
message: `unknown parameter type from "${props.function}@${name}".`,
});
else if (
tuple.typeName === "__type" ||
tuple.typeName === "__object"
tuple.typeName === "__object" ||
tuple.typeName.startsWith("__type.") ||
tuple.typeName.startsWith("__object.")
)
errors.push({
file: props.controller.file,
controller: props.controller.name,
function: props.function,
message: `implicit (unnamed) parameter type from ${JSON.stringify(name)}.`,
message: `implicit (unnamed) parameter type from "${props.function}@${name}".`,
});
_Check_optional({
...project,
@@ -358,9 +366,7 @@ export namespace TypedWebSocketOperationAnalyzer {
file: props.controller.file,
controller: props.controller.name,
function: props.function,
message: `@WebSocketRoute() does not allow optional parameter, but be detected from ${JSON.stringify(
props.parameter.symbol.getEscapedName().toString(),
)}.`,
message: `@WebSocketRoute() does not allow optional parameter, but be detected from ${props.function}@${props.parameter.symbol.getEscapedName().toString()}.`,
});
};
}
52 changes: 50 additions & 2 deletions packages/sdk/src/generates/SdkGenerator.ts
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ export namespace SdkGenerator {

// VALIDATE THROUGH SWAGGER GENERATOR
const errors: ISwaggerError[] = [];
const validator = SwaggerGenerator.generate_route({
const validate = SwaggerGenerator.generate_route({
config: { output: "" },
checker: project.checker,
collection: new MetadataCollection({
@@ -36,7 +36,11 @@ export namespace SdkGenerator {
project.config.swagger ?? { output: "" },
),
});
for (const r of routes) if (r.protocol === "http") validator(r);
for (const r of routes)
if (r.protocol === "http") {
validate(r);
if (project.config.clone !== true) validateImplicity(project)(r);
}
if (errors.length) {
for (const e of errors)
console.error(
@@ -49,6 +53,14 @@ export namespace SdkGenerator {
"\n\n",
);
throw new TypeError("Invalid type detected");
} else if (project.errors.length) {
for (const e of project.errors)
console.error(
`${path.relative(process.cwd(), e.file)}:${
e.controller
}.${e.function}: error TS(@nestia/sdk): ${e.message}`,
);
throw new TypeError("Invalid type detected");
}

// PREPARE NEW DIRECTORIES
@@ -95,6 +107,42 @@ export namespace SdkGenerator {
);
};

const validateImplicity =
(project: INestiaProject) =>
(route: ITypedHttpRoute): void => {
for (const p of route.parameters) {
if (isImplicitType(p.typeName))
project.errors.push({
file: route.location,
controller: route.controller.name,
function: route.name,
message: `implicit (unnamed) parameter type from "${route.name}@${p.name}".`,
});
}
if (project.config.propagate !== true)
for (const [key, value] of Object.entries(route.exceptions))
if (isImplicitType(value.typeName))
project.errors.push({
file: route.location,
controller: route.controller.name,
function: route.name,
message: `implicit (unnamed) exception type of ${key} status from "${route.name}".`,
});
if (isImplicitType(route.output.typeName))
project.errors.push({
file: route.location,
controller: route.controller.name,
function: route.name,
message: `implicit (unnamed) return type from "${route.name}".`,
});
};

const isImplicitType = (typeName: string): boolean =>
typeName === "__type" ||
typeName === "__object" ||
typeName.startsWith("__type.") ||
typeName.startsWith("__object.");

export const BUNDLE_PATH = NodePath.join(
__dirname,
"..",
2 changes: 1 addition & 1 deletion test/features/all/swagger.json
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@
}
],
"info": {
"version": "3.8.0-dev.20240722",
"version": "3.9.0-dev.20240728",
"title": "@samchon/nestia-test",
"description": "Test program of Nestia",
"license": {

Large diffs are not rendered by default.

Loading

0 comments on commit 674697d

Please sign in to comment.