@nestia/sdk 2.0.0-dev.20230904-2 → 2.0.0-dev.20230906

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 (45) hide show
  1. package/lib/INestiaConfig.d.ts +8 -0
  2. package/lib/NestiaSdkApplication.d.ts +1 -1
  3. package/lib/NestiaSdkApplication.js +5 -5
  4. package/lib/NestiaSdkApplication.js.map +1 -1
  5. package/lib/analyses/ControllerAnalyzer.js +4 -4
  6. package/lib/analyses/ControllerAnalyzer.js.map +1 -1
  7. package/lib/analyses/ReflectAnalyzer.js +9 -1
  8. package/lib/analyses/ReflectAnalyzer.js.map +1 -1
  9. package/lib/executable/internal/NestiaConfigLoader.js +5 -1
  10. package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
  11. package/lib/generates/SdkGenerator.d.ts +2 -1
  12. package/lib/generates/SdkGenerator.js +5 -1
  13. package/lib/generates/SdkGenerator.js.map +1 -1
  14. package/lib/generates/SwaggerGenerator.js +9 -6
  15. package/lib/generates/SwaggerGenerator.js.map +1 -1
  16. package/lib/generates/internal/E2eFileProgrammer.js +15 -10
  17. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  18. package/lib/generates/internal/SdkDtoGenerator.d.ts +9 -0
  19. package/lib/generates/internal/SdkDtoGenerator.js +264 -0
  20. package/lib/generates/internal/SdkDtoGenerator.js.map +1 -0
  21. package/lib/generates/internal/SdkFileProgrammer.js +8 -7
  22. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  23. package/lib/generates/internal/SdkFunctionProgrammer.js +11 -7
  24. package/lib/generates/internal/SdkFunctionProgrammer.js.map +1 -1
  25. package/lib/generates/internal/SdkSimulationProgrammer.js +5 -1
  26. package/lib/generates/internal/SdkSimulationProgrammer.js.map +1 -1
  27. package/lib/generates/internal/SwaggerSchemaGenerator.js +2 -2
  28. package/lib/generates/internal/SwaggerSchemaGenerator.js.map +1 -1
  29. package/lib/structures/IController.d.ts +2 -0
  30. package/lib/structures/IRoute.d.ts +5 -1
  31. package/package.json +5 -5
  32. package/src/INestiaConfig.ts +9 -0
  33. package/src/NestiaSdkApplication.ts +5 -9
  34. package/src/analyses/ControllerAnalyzer.ts +5 -5
  35. package/src/analyses/ReflectAnalyzer.ts +8 -0
  36. package/src/generates/SdkGenerator.ts +7 -0
  37. package/src/generates/SwaggerGenerator.ts +11 -7
  38. package/src/generates/internal/E2eFileProgrammer.ts +24 -11
  39. package/src/generates/internal/SdkDtoGenerator.ts +384 -0
  40. package/src/generates/internal/SdkFileProgrammer.ts +8 -7
  41. package/src/generates/internal/SdkFunctionProgrammer.ts +35 -7
  42. package/src/generates/internal/SdkSimulationProgrammer.ts +10 -1
  43. package/src/generates/internal/SwaggerSchemaGenerator.ts +2 -2
  44. package/src/structures/IController.ts +2 -0
  45. package/src/structures/IRoute.ts +7 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nestia/sdk",
3
- "version": "2.0.0-dev.20230904-2",
3
+ "version": "2.0.0-dev.20230906",
4
4
  "description": "Nestia SDK and Swagger generator",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "homepage": "https://nestia.io",
37
37
  "dependencies": {
38
- "@nestia/fetcher": "^2.0.0-dev.20230904-2",
38
+ "@nestia/fetcher": "^2.0.0-dev.20230906",
39
39
  "cli": "^1.0.1",
40
40
  "glob": "^7.2.0",
41
41
  "path-to-regexp": "^6.2.1",
@@ -44,16 +44,16 @@
44
44
  "tsconfck": "^2.0.1",
45
45
  "tsconfig-paths": "^4.1.1",
46
46
  "tstl": "^2.5.13",
47
- "typia": "^5.0.1"
47
+ "typia": "^5.0.2"
48
48
  },
49
49
  "peerDependencies": {
50
- "@nestia/fetcher": ">=2.0.0-dev.20230904-2",
50
+ "@nestia/fetcher": ">=2.0.0-dev.20230906",
51
51
  "@nestjs/common": ">=7.0.1",
52
52
  "@nestjs/core": ">=7.0.1",
53
53
  "reflect-metadata": ">=0.1.12",
54
54
  "ts-node": ">=10.6.0",
55
55
  "typescript": ">=4.8.0",
56
- "typia": ">=5.0.1 <6.0.0"
56
+ "typia": ">=5.0.2 <6.0.0"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@nestjs/common": ">= 7.0.1",
@@ -52,6 +52,15 @@ export interface INestiaConfig {
52
52
  */
53
53
  e2e?: string;
54
54
 
55
+ /**
56
+ * Whether to clone DTO structures or not.
57
+ *
58
+ * If being configured, all of DTOs used in the backend server would be cloned
59
+ * into the `structures` directory, and the SDK library would be refer to the
60
+ * cloned DTOs instead of the original.
61
+ */
62
+ clone?: boolean;
63
+
55
64
  /**
56
65
  * Whether to wrap DTO by primitive type.
57
66
  *
@@ -17,7 +17,7 @@ import { NestiaConfigUtil } from "./utils/NestiaConfigUtil";
17
17
  import { SourceFinder } from "./utils/SourceFinder";
18
18
 
19
19
  export class NestiaSdkApplication {
20
- private readonly checker_: Singleton<Promise<(str: string) => boolean>> =
20
+ private readonly bundler_: Singleton<Promise<(str: string) => boolean>> =
21
21
  new Singleton(async () => {
22
22
  if (!this.config) return () => false;
23
23
 
@@ -59,7 +59,7 @@ export class NestiaSdkApplication {
59
59
  if (this.config.output)
60
60
  return (
61
61
  file.indexOf(path.join(this.config.output, "functional")) ===
62
- -1 && (await this.checker_.get())(file) === false
62
+ -1 && (await this.bundler_.get())(file) === false
63
63
  );
64
64
 
65
65
  const content: string = await fs.promises.readFile(file, "utf8");
@@ -97,8 +97,8 @@ export class NestiaSdkApplication {
97
97
  await this.generate(
98
98
  "e2e",
99
99
  (config) => config,
100
- () => (config) => async (routes) => {
101
- await SdkGenerator.generate(config)(routes);
100
+ (checker) => (config) => async (routes) => {
101
+ await SdkGenerator.generate(checker)(config)(routes);
102
102
  await E2eGenerator.generate(config)(routes);
103
103
  },
104
104
  );
@@ -118,11 +118,7 @@ export class NestiaSdkApplication {
118
118
  );
119
119
 
120
120
  title("Nestia SDK Generator");
121
- await this.generate(
122
- "sdk",
123
- (config) => config,
124
- () => SdkGenerator.generate,
125
- );
121
+ await this.generate("sdk", (config) => config, SdkGenerator.generate);
126
122
  }
127
123
 
128
124
  public async swagger(): Promise<void> {
@@ -145,11 +145,11 @@ export namespace ControllerAnalyzer {
145
145
  .map((pair) => [pair.first, pair.second.toJSON()]);
146
146
 
147
147
  // PARSE COMMENT TAGS
148
- const tags = signature.getJsDocTags();
148
+ const jsDocTags = signature.getJsDocTags();
149
149
  const security: Record<string, string[]>[] = SecurityAnalyzer.merge(
150
150
  ...controller.security,
151
151
  ...func.security,
152
- ...tags
152
+ ...jsDocTags
153
153
  .filter((tag) => tag.name === "security")
154
154
  .map((tag) =>
155
155
  (tag.text ?? []).map((text) => {
@@ -191,12 +191,12 @@ export namespace ControllerAnalyzer {
191
191
  }:${character + 1}`;
192
192
  })(),
193
193
  description: CommentFactory.description(symbol),
194
- operationId: tags
194
+ operationId: jsDocTags
195
195
  .find(({ name }) => name === "operationId")
196
196
  ?.text!?.[0].text.split(" ")[0]
197
197
  .trim(),
198
- tags,
199
- setHeaders: tags
198
+ jsDocTags: jsDocTags,
199
+ setHeaders: jsDocTags
200
200
  .filter(
201
201
  (t) =>
202
202
  t.text?.length &&
@@ -90,6 +90,8 @@ export namespace ReflectAnalyzer {
90
90
  paths,
91
91
  functions: [],
92
92
  security: _Get_securities(creator),
93
+ swaggerTgas:
94
+ Reflect.getMetadata("swagger/apiUseTags", creator) ?? [],
93
95
  };
94
96
 
95
97
  // PARSE CHILDREN DATA
@@ -228,6 +230,12 @@ export namespace ReflectAnalyzer {
228
230
  )?.value ?? "application/json",
229
231
  security: _Get_securities(proto),
230
232
  exceptions: _Get_exceptions(proto),
233
+ swaggerTags: [
234
+ ...new Set([
235
+ ...controller.swaggerTgas,
236
+ ...(Reflect.getMetadata("swagger/apiUseTags", proto) ?? []),
237
+ ]),
238
+ ],
231
239
  };
232
240
 
233
241
  // VALIDATE PATH ARGUMENTS
@@ -1,14 +1,17 @@
1
1
  import fs from "fs";
2
2
  import NodePath from "path";
3
3
  import { IPointer } from "tstl";
4
+ import ts from "typescript";
4
5
 
5
6
  import { INestiaConfig } from "../INestiaConfig";
6
7
  import { IRoute } from "../structures/IRoute";
7
8
  import { DistributionComposer } from "./internal/DistributionComposer";
9
+ import { SdkDtoGenerator } from "./internal/SdkDtoGenerator";
8
10
  import { SdkFileProgrammer } from "./internal/SdkFileProgrammer";
9
11
 
10
12
  export namespace SdkGenerator {
11
13
  export const generate =
14
+ (checker: ts.TypeChecker) =>
12
15
  (config: INestiaConfig) =>
13
16
  async (routes: IRoute[]): Promise<void> => {
14
17
  console.log("Generating SDK Library");
@@ -55,6 +58,10 @@ export namespace SdkGenerator {
55
58
  );
56
59
  }
57
60
 
61
+ // STRUCTURES
62
+ if (config.clone)
63
+ await SdkDtoGenerator.generate(checker)(config)(routes);
64
+
58
65
  // FUNCTIONAL
59
66
  await SdkFileProgrammer.generate(config)(routes);
60
67
 
@@ -71,7 +71,8 @@ export namespace SwaggerGenerator {
71
71
  > = new Map();
72
72
 
73
73
  for (const route of routeList) {
74
- if (route.tags.find((tag) => tag.name === "internal")) continue;
74
+ if (route.jsDocTags.find((tag) => tag.name === "internal"))
75
+ continue;
75
76
 
76
77
  const path: Record<string, ISwaggerRoute> = MapUtil.take(
77
78
  pathDict,
@@ -297,8 +298,8 @@ export namespace SwaggerGenerator {
297
298
  const body = route.parameters.find(
298
299
  (param) => param.category === "body",
299
300
  );
300
- const getTagTexts = (name: string) =>
301
- route.tags
301
+ const getJsDocTexts = (name: string) =>
302
+ route.jsDocTags
302
303
  .filter(
303
304
  (tag) =>
304
305
  tag.name === name &&
@@ -320,7 +321,7 @@ export namespace SwaggerGenerator {
320
321
  const summary: string | undefined = (() => {
321
322
  if (description === undefined) return undefined;
322
323
 
323
- const [explicit] = getTagTexts("summary");
324
+ const [explicit] = getJsDocTexts("summary");
324
325
  if (explicit?.length) return explicit;
325
326
 
326
327
  const index: number = description.indexOf(".");
@@ -329,13 +330,16 @@ export namespace SwaggerGenerator {
329
330
  const content: string = description.substring(0, index).trim();
330
331
  return content.length ? content : undefined;
331
332
  })();
332
- const deprecated = route.tags.find(
333
+ const deprecated = route.jsDocTags.find(
333
334
  (tag) => tag.name === "deprecated",
334
335
  );
335
336
 
336
337
  return {
337
338
  deprecated: deprecated ? true : undefined,
338
- tags: getTagTexts("tag"),
339
+ tags: [
340
+ ...route.swaggerTags,
341
+ ...new Set([...getJsDocTexts("tag")]),
342
+ ],
339
343
  operationId:
340
344
  route.operationId ??
341
345
  props.config.operationId?.({
@@ -363,7 +367,7 @@ export namespace SwaggerGenerator {
363
367
  .filter((str) => str.length && str[0] !== ":"),
364
368
  route.name,
365
369
  ].join("."),
366
- "x-nestia-jsDocTags": route.tags,
370
+ "x-nestia-jsDocTags": route.jsDocTags,
367
371
  "x-nestia-method": route.method,
368
372
  };
369
373
  };
@@ -3,6 +3,7 @@ import fs from "fs";
3
3
  import { INestiaConfig } from "../../INestiaConfig";
4
4
  import { IRoute } from "../../structures/IRoute";
5
5
  import { ImportDictionary } from "../../utils/ImportDictionary";
6
+ import { SdkDtoGenerator } from "./SdkDtoGenerator";
6
7
  import { SdkImportWizard } from "./SdkImportWizard";
7
8
 
8
9
  export namespace E2eFileProgrammer {
@@ -11,20 +12,21 @@ export namespace E2eFileProgrammer {
11
12
  (props: { api: string; current: string }) =>
12
13
  async (route: IRoute): Promise<void> => {
13
14
  const importer: ImportDictionary = new ImportDictionary();
14
- for (const tuple of route.imports)
15
- for (const instance of tuple[1])
16
- importer.internal({
17
- file: tuple[0],
18
- type: true,
19
- instance,
20
- });
21
-
15
+ if (config.clone !== true)
16
+ for (const tuple of route.imports)
17
+ for (const instance of tuple[1])
18
+ importer.internal({
19
+ file: tuple[0],
20
+ type: true,
21
+ instance,
22
+ });
22
23
  importer.internal({
23
24
  type: false,
24
25
  file: props.api,
25
26
  instance: null,
26
27
  name: "api",
27
28
  });
29
+
28
30
  const body: string = arrow(config)(importer)(route);
29
31
  const content: string = [
30
32
  importer.toScript(props.current),
@@ -57,7 +59,9 @@ export namespace E2eFileProgrammer {
57
59
  " ...(connection.headers ?? {}),",
58
60
  ` ...${SdkImportWizard.typia(
59
61
  importer,
60
- )}.random<${headers.typeName}>(),`,
62
+ )}.random<${getTypeName(config)(importer)(
63
+ headers,
64
+ )}>(),`,
61
65
  " },",
62
66
  "},",
63
67
  ]
@@ -77,7 +81,7 @@ export namespace E2eFileProgrammer {
77
81
  ? [` ${output}`]
78
82
  : [
79
83
  ` const output: ${primitive(config)(importer)(
80
- route.output.typeName,
84
+ getTypeName(config)(importer)(route.output),
81
85
  )} = `,
82
86
  ` ${output}`,
83
87
  ` ${SdkImportWizard.typia(
@@ -95,7 +99,9 @@ export namespace E2eFileProgrammer {
95
99
  (param: IRoute.IParameter): string => {
96
100
  const middle: string = `${SdkImportWizard.typia(
97
101
  importer,
98
- )}.random<${primitive(config)(importer)(param.typeName)}>()`;
102
+ )}.random<${primitive(config)(importer)(
103
+ getTypeName(config)(importer)(param),
104
+ )}>()`;
99
105
  return `${" ".repeat(4 * tab)}${middle},`;
100
106
  };
101
107
 
@@ -113,3 +119,10 @@ export namespace E2eFileProgrammer {
113
119
  ? `${SdkImportWizard.Primitive(importer)}<${name}>`
114
120
  : name;
115
121
  }
122
+ const getTypeName =
123
+ (config: INestiaConfig) =>
124
+ (importer: ImportDictionary) =>
125
+ (p: IRoute.IParameter | IRoute.IOutput) =>
126
+ p.metadata
127
+ ? SdkDtoGenerator.decode(config)(importer)(p.metadata)
128
+ : p.typeName;