@nestia/sdk 11.0.0-dev.20260316 → 11.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +93 -93
  3. package/assets/bundle/api/HttpError.ts +1 -1
  4. package/assets/bundle/api/IConnection.ts +1 -1
  5. package/assets/bundle/api/Primitive.ts +1 -1
  6. package/assets/bundle/api/Resolved.ts +1 -1
  7. package/assets/bundle/api/index.ts +4 -4
  8. package/assets/bundle/api/module.ts +6 -6
  9. package/assets/bundle/distribute/README.md +37 -37
  10. package/assets/bundle/distribute/package.json +28 -28
  11. package/assets/bundle/distribute/tsconfig.json +109 -109
  12. package/assets/bundle/e2e/index.ts +42 -42
  13. package/assets/config/nestia.config.ts +97 -97
  14. package/lib/executable/internal/NestiaConfigLoader.js +5 -5
  15. package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
  16. package/package.json +8 -8
  17. package/src/INestiaConfig.ts +267 -267
  18. package/src/NestiaSdkApplication.ts +307 -307
  19. package/src/NestiaSwaggerComposer.ts +143 -143
  20. package/src/analyses/AccessorAnalyzer.ts +67 -67
  21. package/src/analyses/DtoAnalyzer.ts +260 -260
  22. package/src/analyses/ImportAnalyzer.ts +126 -126
  23. package/src/analyses/ReflectHttpOperationAnalyzer.ts +183 -183
  24. package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +72 -72
  25. package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +350 -350
  26. package/src/analyses/ReflectHttpOperationResponseAnalyzer.ts +126 -126
  27. package/src/analyses/TypedHttpRouteAnalyzer.ts +208 -208
  28. package/src/executable/internal/NestiaConfigLoader.ts +85 -85
  29. package/src/executable/internal/NestiaSdkCommand.ts +107 -107
  30. package/src/generates/SwaggerGenerator.ts +291 -291
  31. package/src/generates/internal/E2eFileProgrammer.ts +196 -196
  32. package/src/generates/internal/FilePrinter.ts +64 -64
  33. package/src/generates/internal/ImportDictionary.ts +192 -192
  34. package/src/generates/internal/SdkAliasCollection.ts +260 -260
  35. package/src/generates/internal/SdkFileProgrammer.ts +110 -110
  36. package/src/generates/internal/SdkHttpCloneProgrammer.ts +126 -126
  37. package/src/generates/internal/SdkHttpCloneReferencer.ts +77 -77
  38. package/src/generates/internal/SdkHttpFunctionProgrammer.ts +278 -278
  39. package/src/generates/internal/SdkHttpNamespaceProgrammer.ts +502 -502
  40. package/src/generates/internal/SdkHttpRouteProgrammer.ts +109 -109
  41. package/src/generates/internal/SdkHttpSimulationProgrammer.ts +312 -312
  42. package/src/generates/internal/SdkImportWizard.ts +62 -62
  43. package/src/generates/internal/SdkTypeProgrammer.ts +388 -388
  44. package/src/generates/internal/SdkTypeTagProgrammer.ts +114 -114
  45. package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +379 -379
  46. package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +302 -302
  47. package/src/generates/internal/SwaggerOperationComposer.ts +119 -119
  48. package/src/generates/internal/SwaggerOperationParameterComposer.ts +161 -161
  49. package/src/generates/internal/SwaggerOperationResponseComposer.ts +110 -110
  50. package/src/module.ts +4 -4
  51. package/src/structures/IReflectHttpOperationException.ts +18 -18
  52. package/src/structures/IReflectHttpOperationParameter.ts +79 -79
  53. package/src/structures/IReflectHttpOperationSuccess.ts +21 -21
  54. package/src/structures/ITypedApplication.ts +11 -11
  55. package/src/structures/ITypedHttpRouteException.ts +15 -15
  56. package/src/structures/ITypedHttpRouteParameter.ts +41 -41
  57. package/src/structures/ITypedHttpRouteSuccess.ts +22 -22
  58. package/src/transformers/IOperationMetadata.ts +46 -46
  59. package/src/transformers/ISdkOperationTransformerContext.ts +8 -8
  60. package/src/transformers/SdkOperationProgrammer.ts +240 -240
  61. package/src/transformers/SdkOperationTransformer.ts +248 -248
  62. package/src/transformers/TextPlainValidator.ts +17 -17
  63. package/src/utils/MetadataUtil.ts +26 -26
  64. package/src/validators/HttpHeadersValidator.ts +40 -40
  65. package/src/validators/HttpQueryValidator.ts +40 -40
@@ -1,119 +1,119 @@
1
- import { MetadataSchema } from "@typia/core";
2
- import { OpenApi } from "@typia/interface";
3
-
4
- import { INestiaConfig } from "../../INestiaConfig";
5
- import { SecurityAnalyzer } from "../../analyses/SecurityAnalyzer";
6
- import { ITypedHttpRoute } from "../../structures/ITypedHttpRoute";
7
- import { SwaggerDescriptionComposer } from "./SwaggerDescriptionComposer";
8
- import { SwaggerOperationParameterComposer } from "./SwaggerOperationParameterComposer";
9
- import { SwaggerOperationResponseComposer } from "./SwaggerOperationResponseComposer";
10
-
11
- export namespace SwaggerOperationComposer {
12
- export const compose = (props: {
13
- config: Omit<INestiaConfig.ISwaggerConfig, "output">;
14
- document: OpenApi.IDocument;
15
- schema: (metadata: MetadataSchema) => OpenApi.IJsonSchema | undefined;
16
- route: ITypedHttpRoute;
17
- }): OpenApi.IOperation => {
18
- // COMPOSE TAGS
19
- const tags: Set<string> = new Set([
20
- ...props.route.controller.tags,
21
- ...props.route.tags,
22
- ...SwaggerDescriptionComposer.getJsDocTexts({
23
- jsDocTags: props.route.jsDocTags,
24
- name: "tag",
25
- }).map((t) => t.split(" ")[0]!),
26
- ]);
27
- if (tags.size) {
28
- props.document.tags ??= [];
29
- for (const t of tags)
30
- if (props.document.tags.find((elem) => elem.name === t) === undefined)
31
- props.document.tags.push({ name: t });
32
- for (const texts of SwaggerDescriptionComposer.getJsDocTexts({
33
- jsDocTags: props.route.jsDocTags,
34
- name: "tag",
35
- })) {
36
- const [name, ...description] = texts.split(" ");
37
- if (description.length)
38
- props.document.tags.find(
39
- (elem) => elem.name === name,
40
- )!.description ??= description.join(" ");
41
- }
42
- }
43
-
44
- // SECURITY
45
- const security: Record<string, string[]>[] = SecurityAnalyzer.merge(
46
- ...props.route.controller.security,
47
- ...props.route.security,
48
- ...props.route.jsDocTags
49
- .filter((tag) => tag.name === "security")
50
- .map((tag) =>
51
- tag.text === undefined
52
- ? [{}]
53
- : tag.text.map((text) => {
54
- const line: string[] = text.text
55
- .split(" ")
56
- .filter((s) => s.trim())
57
- .filter((s) => !!s.length);
58
- if (line.length === 0) return {};
59
- return {
60
- [line[0]!]: line.slice(1),
61
- };
62
- }),
63
- )
64
- .flat(),
65
- );
66
-
67
- // FINALIZE
68
- return {
69
- ...SwaggerDescriptionComposer.compose({
70
- description: props.route.description,
71
- jsDocTags: props.route.jsDocTags,
72
- kind: "summary",
73
- }),
74
- deprecated: props.route.jsDocTags.some((tag) => tag.name === "deprecated")
75
- ? true
76
- : undefined,
77
- tags: Array.from(tags),
78
- operationId:
79
- props.route.operationId ??
80
- props.config.operationId?.({
81
- class: props.route.controller.class.name,
82
- function: props.route.name,
83
- method: props.route.method as "GET",
84
- path: props.route.path,
85
- }),
86
- parameters: [
87
- ...props.route.pathParameters,
88
- ...props.route.queryParameters,
89
- ...(props.route.queryObject ? [props.route.queryObject] : []),
90
- ...(props.route.headerObject ? [props.route.headerObject] : []),
91
- ]
92
- .map((p) =>
93
- SwaggerOperationParameterComposer.compose({
94
- config: props.config,
95
- document: props.document,
96
- schema: props.schema(p.metadata)!,
97
- parameter: p,
98
- jsDocTags: props.route.jsDocTags,
99
- }),
100
- )
101
- .flat(),
102
- requestBody: props.route.body
103
- ? SwaggerOperationParameterComposer.body({
104
- schema: props.schema(props.route.body.metadata)!,
105
- jsDocTags: props.route.jsDocTags,
106
- parameter: props.route.body,
107
- })
108
- : undefined,
109
- responses: SwaggerOperationResponseComposer.compose({
110
- schema: props.schema,
111
- route: props.route,
112
- }),
113
- security: security.length ? security : undefined,
114
- ...(props.route.extensions ?? {}),
115
- "x-samchon-accessor": props.route.accessor,
116
- "x-samchon-controller": props.route.controller.class.name,
117
- };
118
- };
119
- }
1
+ import { MetadataSchema } from "@typia/core";
2
+ import { OpenApi } from "@typia/interface";
3
+
4
+ import { INestiaConfig } from "../../INestiaConfig";
5
+ import { SecurityAnalyzer } from "../../analyses/SecurityAnalyzer";
6
+ import { ITypedHttpRoute } from "../../structures/ITypedHttpRoute";
7
+ import { SwaggerDescriptionComposer } from "./SwaggerDescriptionComposer";
8
+ import { SwaggerOperationParameterComposer } from "./SwaggerOperationParameterComposer";
9
+ import { SwaggerOperationResponseComposer } from "./SwaggerOperationResponseComposer";
10
+
11
+ export namespace SwaggerOperationComposer {
12
+ export const compose = (props: {
13
+ config: Omit<INestiaConfig.ISwaggerConfig, "output">;
14
+ document: OpenApi.IDocument;
15
+ schema: (metadata: MetadataSchema) => OpenApi.IJsonSchema | undefined;
16
+ route: ITypedHttpRoute;
17
+ }): OpenApi.IOperation => {
18
+ // COMPOSE TAGS
19
+ const tags: Set<string> = new Set([
20
+ ...props.route.controller.tags,
21
+ ...props.route.tags,
22
+ ...SwaggerDescriptionComposer.getJsDocTexts({
23
+ jsDocTags: props.route.jsDocTags,
24
+ name: "tag",
25
+ }).map((t) => t.split(" ")[0]!),
26
+ ]);
27
+ if (tags.size) {
28
+ props.document.tags ??= [];
29
+ for (const t of tags)
30
+ if (props.document.tags.find((elem) => elem.name === t) === undefined)
31
+ props.document.tags.push({ name: t });
32
+ for (const texts of SwaggerDescriptionComposer.getJsDocTexts({
33
+ jsDocTags: props.route.jsDocTags,
34
+ name: "tag",
35
+ })) {
36
+ const [name, ...description] = texts.split(" ");
37
+ if (description.length)
38
+ props.document.tags.find(
39
+ (elem) => elem.name === name,
40
+ )!.description ??= description.join(" ");
41
+ }
42
+ }
43
+
44
+ // SECURITY
45
+ const security: Record<string, string[]>[] = SecurityAnalyzer.merge(
46
+ ...props.route.controller.security,
47
+ ...props.route.security,
48
+ ...props.route.jsDocTags
49
+ .filter((tag) => tag.name === "security")
50
+ .map((tag) =>
51
+ tag.text === undefined
52
+ ? [{}]
53
+ : tag.text.map((text) => {
54
+ const line: string[] = text.text
55
+ .split(" ")
56
+ .filter((s) => s.trim())
57
+ .filter((s) => !!s.length);
58
+ if (line.length === 0) return {};
59
+ return {
60
+ [line[0]!]: line.slice(1),
61
+ };
62
+ }),
63
+ )
64
+ .flat(),
65
+ );
66
+
67
+ // FINALIZE
68
+ return {
69
+ ...SwaggerDescriptionComposer.compose({
70
+ description: props.route.description,
71
+ jsDocTags: props.route.jsDocTags,
72
+ kind: "summary",
73
+ }),
74
+ deprecated: props.route.jsDocTags.some((tag) => tag.name === "deprecated")
75
+ ? true
76
+ : undefined,
77
+ tags: Array.from(tags),
78
+ operationId:
79
+ props.route.operationId ??
80
+ props.config.operationId?.({
81
+ class: props.route.controller.class.name,
82
+ function: props.route.name,
83
+ method: props.route.method as "GET",
84
+ path: props.route.path,
85
+ }),
86
+ parameters: [
87
+ ...props.route.pathParameters,
88
+ ...props.route.queryParameters,
89
+ ...(props.route.queryObject ? [props.route.queryObject] : []),
90
+ ...(props.route.headerObject ? [props.route.headerObject] : []),
91
+ ]
92
+ .map((p) =>
93
+ SwaggerOperationParameterComposer.compose({
94
+ config: props.config,
95
+ document: props.document,
96
+ schema: props.schema(p.metadata)!,
97
+ parameter: p,
98
+ jsDocTags: props.route.jsDocTags,
99
+ }),
100
+ )
101
+ .flat(),
102
+ requestBody: props.route.body
103
+ ? SwaggerOperationParameterComposer.body({
104
+ schema: props.schema(props.route.body.metadata)!,
105
+ jsDocTags: props.route.jsDocTags,
106
+ parameter: props.route.body,
107
+ })
108
+ : undefined,
109
+ responses: SwaggerOperationResponseComposer.compose({
110
+ schema: props.schema,
111
+ route: props.route,
112
+ }),
113
+ security: security.length ? security : undefined,
114
+ ...(props.route.extensions ?? {}),
115
+ "x-samchon-accessor": props.route.accessor,
116
+ "x-samchon-controller": props.route.controller.class.name,
117
+ };
118
+ };
119
+ }
@@ -1,161 +1,161 @@
1
- import { JsonSchemasProgrammer } from "@typia/core";
2
- import { OpenApi } from "@typia/interface";
3
- import { VariadicSingleton } from "tstl";
4
- import { IJsDocTagInfo, IJsonSchemaCollection } from "typia";
5
-
6
- import { INestiaConfig } from "../../INestiaConfig";
7
- import { ITypedHttpRouteParameter } from "../../structures/ITypedHttpRouteParameter";
8
- import { SwaggerDescriptionComposer } from "./SwaggerDescriptionComposer";
9
-
10
- export namespace SwaggerOperationParameterComposer {
11
- export interface IProps<Parameter extends ITypedHttpRouteParameter> {
12
- config: Omit<INestiaConfig.ISwaggerConfig, "output">;
13
- document: OpenApi.IDocument;
14
- schema: OpenApi.IJsonSchema;
15
- jsDocTags: IJsDocTagInfo[];
16
- parameter: Parameter;
17
- }
18
-
19
- export const compose = (
20
- props: IProps<ITypedHttpRouteParameter>,
21
- ): OpenApi.IOperation.IParameter[] =>
22
- props.parameter.category === "body"
23
- ? []
24
- : props.parameter.category === "param"
25
- ? [path({ ...props, parameter: props.parameter })]
26
- : props.parameter.category === "query"
27
- ? query({ ...props, parameter: props.parameter })
28
- : header({ ...props, parameter: props.parameter });
29
-
30
- export const body = (
31
- props: Omit<IProps<ITypedHttpRouteParameter.IBody>, "config" | "document">,
32
- ): OpenApi.IOperation.IRequestBody => {
33
- const description: string | undefined =
34
- SwaggerDescriptionComposer.descriptionFromJsDocTag({
35
- jsDocTags: props.jsDocTags,
36
- tag: "param",
37
- parameter: props.parameter.name,
38
- });
39
- return {
40
- description: props.parameter.encrypted
41
- ? `${warning.get(!!description)}${description ?? ""}`
42
- : description,
43
- content: {
44
- [props.parameter.contentType]: {
45
- schema: props.schema,
46
- example: props.parameter.example,
47
- examples: props.parameter.examples,
48
- },
49
- },
50
- required: props.parameter.metadata.isRequired(),
51
- ...(props.parameter.encrypted ? { "x-nestia-encrypted": true } : {}),
52
- };
53
- };
54
-
55
- export const path = (
56
- props: Omit<IProps<ITypedHttpRouteParameter.IPath>, "config" | "document">,
57
- ): OpenApi.IOperation.IParameter => ({
58
- name: props.parameter.field,
59
- in: "path",
60
- schema: props.schema,
61
- required: props.parameter.metadata.isRequired(),
62
- description: parameterDescription(props),
63
- example: props.parameter.example,
64
- examples: props.parameter.examples,
65
- });
66
-
67
- export const query = (
68
- props: IProps<ITypedHttpRouteParameter.IQuery>,
69
- ): OpenApi.IOperation.IParameter[] => decomposible(props);
70
-
71
- export const header = (
72
- props: IProps<ITypedHttpRouteParameter.IHeaders>,
73
- ): OpenApi.IOperation.IParameter[] => decomposible(props);
74
-
75
- const parameterDescription = (
76
- props: Pick<IProps<ITypedHttpRouteParameter>, "parameter" | "jsDocTags">,
77
- ): string | undefined => {
78
- return (
79
- props.parameter.description ??
80
- props.parameter.jsDocTags.find((tag) => tag.name === "description")
81
- ?.text?.[0]?.text ??
82
- props.jsDocTags
83
- .find(
84
- (tag) =>
85
- tag.name === "param" &&
86
- tag.text?.[0]?.text === props.parameter.name,
87
- )
88
- ?.text?.map((e) => e.text)
89
- .join("")
90
- .substring(props.parameter.name.length)
91
- .trim()
92
- );
93
- };
94
-
95
- const decomposible = (
96
- props: IProps<
97
- ITypedHttpRouteParameter.IHeaders | ITypedHttpRouteParameter.IQuery
98
- >,
99
- ): OpenApi.IOperation.IParameter[] => {
100
- const param: OpenApi.IOperation.IParameter = {
101
- name: props.parameter.field ?? props.parameter.name,
102
- in: props.parameter.category === "query" ? "query" : "header",
103
- schema: props.schema,
104
- description: parameterDescription(props),
105
- required: props.parameter.metadata.isRequired(),
106
- example: props.parameter.example,
107
- examples: props.parameter.examples,
108
- };
109
- if (
110
- props.config.decompose === false ||
111
- props.parameter.metadata.objects.length === 0
112
- )
113
- return [param];
114
- return props.parameter.metadata.objects[0]!.type.properties.filter((p) =>
115
- p.jsDocTags.every(
116
- (tag) => tag.name !== "hidden" && tag.name !== "ignore",
117
- ),
118
- ).map((p) => {
119
- const json: IJsonSchemaCollection = JsonSchemasProgrammer.writeSchemas({
120
- version: "3.1",
121
- metadatas: [p.value],
122
- }) as IJsonSchemaCollection;
123
- if (Object.keys(json.components.schemas ?? {}).length !== 0) {
124
- props.document.components ??= {};
125
- props.document.components.schemas ??= {};
126
- Object.assign(
127
- props.document.components.schemas,
128
- json.components.schemas,
129
- );
130
- }
131
- return {
132
- name: p.key.constants[0]!.values[0]!.value as string,
133
- in: props.parameter.category === "query" ? "query" : "header",
134
- schema: json.schemas[0]!,
135
- required: p.value.isRequired(),
136
- description: SwaggerDescriptionComposer.compose({
137
- description: p.description ?? null,
138
- jsDocTags: p.jsDocTags,
139
- kind: "title",
140
- }).description,
141
- };
142
- });
143
- };
144
- }
145
-
146
- const warning = new VariadicSingleton((described: boolean): string => {
147
- const summary = "Request body must be encrypted.";
148
- const component =
149
- "[EncryptedBody](https://github.com/samchon/@nestia/core#encryptedbody)";
150
- const content: string[] = [
151
- "## Warning",
152
- "",
153
- summary,
154
- "",
155
- `The request body data would be encrypted as "AES-128(256) / CBC mode / PKCS#5 Padding / Base64 Encoding", through the ${component} component.`,
156
- "",
157
- `Therefore, just utilize this swagger editor only for referencing. If you need to call the real API, using [SDK](https://github.com/samchon/nestia#software-development-kit) would be much better.`,
158
- ];
159
- if (described === true) content.push("", "----------------", "", "");
160
- return content.join("\n");
161
- });
1
+ import { JsonSchemasProgrammer } from "@typia/core";
2
+ import { OpenApi } from "@typia/interface";
3
+ import { VariadicSingleton } from "tstl";
4
+ import { IJsDocTagInfo, IJsonSchemaCollection } from "typia";
5
+
6
+ import { INestiaConfig } from "../../INestiaConfig";
7
+ import { ITypedHttpRouteParameter } from "../../structures/ITypedHttpRouteParameter";
8
+ import { SwaggerDescriptionComposer } from "./SwaggerDescriptionComposer";
9
+
10
+ export namespace SwaggerOperationParameterComposer {
11
+ export interface IProps<Parameter extends ITypedHttpRouteParameter> {
12
+ config: Omit<INestiaConfig.ISwaggerConfig, "output">;
13
+ document: OpenApi.IDocument;
14
+ schema: OpenApi.IJsonSchema;
15
+ jsDocTags: IJsDocTagInfo[];
16
+ parameter: Parameter;
17
+ }
18
+
19
+ export const compose = (
20
+ props: IProps<ITypedHttpRouteParameter>,
21
+ ): OpenApi.IOperation.IParameter[] =>
22
+ props.parameter.category === "body"
23
+ ? []
24
+ : props.parameter.category === "param"
25
+ ? [path({ ...props, parameter: props.parameter })]
26
+ : props.parameter.category === "query"
27
+ ? query({ ...props, parameter: props.parameter })
28
+ : header({ ...props, parameter: props.parameter });
29
+
30
+ export const body = (
31
+ props: Omit<IProps<ITypedHttpRouteParameter.IBody>, "config" | "document">,
32
+ ): OpenApi.IOperation.IRequestBody => {
33
+ const description: string | undefined =
34
+ SwaggerDescriptionComposer.descriptionFromJsDocTag({
35
+ jsDocTags: props.jsDocTags,
36
+ tag: "param",
37
+ parameter: props.parameter.name,
38
+ });
39
+ return {
40
+ description: props.parameter.encrypted
41
+ ? `${warning.get(!!description)}${description ?? ""}`
42
+ : description,
43
+ content: {
44
+ [props.parameter.contentType]: {
45
+ schema: props.schema,
46
+ example: props.parameter.example,
47
+ examples: props.parameter.examples,
48
+ },
49
+ },
50
+ required: props.parameter.metadata.isRequired(),
51
+ ...(props.parameter.encrypted ? { "x-nestia-encrypted": true } : {}),
52
+ };
53
+ };
54
+
55
+ export const path = (
56
+ props: Omit<IProps<ITypedHttpRouteParameter.IPath>, "config" | "document">,
57
+ ): OpenApi.IOperation.IParameter => ({
58
+ name: props.parameter.field,
59
+ in: "path",
60
+ schema: props.schema,
61
+ required: props.parameter.metadata.isRequired(),
62
+ description: parameterDescription(props),
63
+ example: props.parameter.example,
64
+ examples: props.parameter.examples,
65
+ });
66
+
67
+ export const query = (
68
+ props: IProps<ITypedHttpRouteParameter.IQuery>,
69
+ ): OpenApi.IOperation.IParameter[] => decomposible(props);
70
+
71
+ export const header = (
72
+ props: IProps<ITypedHttpRouteParameter.IHeaders>,
73
+ ): OpenApi.IOperation.IParameter[] => decomposible(props);
74
+
75
+ const parameterDescription = (
76
+ props: Pick<IProps<ITypedHttpRouteParameter>, "parameter" | "jsDocTags">,
77
+ ): string | undefined => {
78
+ return (
79
+ props.parameter.description ??
80
+ props.parameter.jsDocTags.find((tag) => tag.name === "description")
81
+ ?.text?.[0]?.text ??
82
+ props.jsDocTags
83
+ .find(
84
+ (tag) =>
85
+ tag.name === "param" &&
86
+ tag.text?.[0]?.text === props.parameter.name,
87
+ )
88
+ ?.text?.map((e) => e.text)
89
+ .join("")
90
+ .substring(props.parameter.name.length)
91
+ .trim()
92
+ );
93
+ };
94
+
95
+ const decomposible = (
96
+ props: IProps<
97
+ ITypedHttpRouteParameter.IHeaders | ITypedHttpRouteParameter.IQuery
98
+ >,
99
+ ): OpenApi.IOperation.IParameter[] => {
100
+ const param: OpenApi.IOperation.IParameter = {
101
+ name: props.parameter.field ?? props.parameter.name,
102
+ in: props.parameter.category === "query" ? "query" : "header",
103
+ schema: props.schema,
104
+ description: parameterDescription(props),
105
+ required: props.parameter.metadata.isRequired(),
106
+ example: props.parameter.example,
107
+ examples: props.parameter.examples,
108
+ };
109
+ if (
110
+ props.config.decompose === false ||
111
+ props.parameter.metadata.objects.length === 0
112
+ )
113
+ return [param];
114
+ return props.parameter.metadata.objects[0]!.type.properties.filter((p) =>
115
+ p.jsDocTags.every(
116
+ (tag) => tag.name !== "hidden" && tag.name !== "ignore",
117
+ ),
118
+ ).map((p) => {
119
+ const json: IJsonSchemaCollection = JsonSchemasProgrammer.writeSchemas({
120
+ version: "3.1",
121
+ metadatas: [p.value],
122
+ }) as IJsonSchemaCollection;
123
+ if (Object.keys(json.components.schemas ?? {}).length !== 0) {
124
+ props.document.components ??= {};
125
+ props.document.components.schemas ??= {};
126
+ Object.assign(
127
+ props.document.components.schemas,
128
+ json.components.schemas,
129
+ );
130
+ }
131
+ return {
132
+ name: p.key.constants[0]!.values[0]!.value as string,
133
+ in: props.parameter.category === "query" ? "query" : "header",
134
+ schema: json.schemas[0]!,
135
+ required: p.value.isRequired(),
136
+ description: SwaggerDescriptionComposer.compose({
137
+ description: p.description ?? null,
138
+ jsDocTags: p.jsDocTags,
139
+ kind: "title",
140
+ }).description,
141
+ };
142
+ });
143
+ };
144
+ }
145
+
146
+ const warning = new VariadicSingleton((described: boolean): string => {
147
+ const summary = "Request body must be encrypted.";
148
+ const component =
149
+ "[EncryptedBody](https://github.com/samchon/@nestia/core#encryptedbody)";
150
+ const content: string[] = [
151
+ "## Warning",
152
+ "",
153
+ summary,
154
+ "",
155
+ `The request body data would be encrypted as "AES-128(256) / CBC mode / PKCS#5 Padding / Base64 Encoding", through the ${component} component.`,
156
+ "",
157
+ `Therefore, just utilize this swagger editor only for referencing. If you need to call the real API, using [SDK](https://github.com/samchon/nestia#software-development-kit) would be much better.`,
158
+ ];
159
+ if (described === true) content.push("", "----------------", "", "");
160
+ return content.join("\n");
161
+ });