@nestia/sdk 2.6.3-dev.20240328 → 2.6.4-dev.20240401

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 +14 -2
  2. package/lib/executable/internal/NestiaConfigLoader.js +31 -5
  3. package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
  4. package/lib/generates/SwaggerGenerator.d.ts +2 -0
  5. package/lib/generates/SwaggerGenerator.js +19 -3
  6. package/lib/generates/SwaggerGenerator.js.map +1 -1
  7. package/lib/structures/ISwagger.d.ts +5 -28
  8. package/lib/structures/ISwaggerServer.d.ts +15 -0
  9. package/lib/structures/ISwaggerServer.js +3 -0
  10. package/lib/structures/ISwaggerServer.js.map +1 -0
  11. package/lib/structures/ISwaggerTag.d.ts +9 -0
  12. package/lib/structures/ISwaggerTag.js +3 -0
  13. package/lib/structures/ISwaggerTag.js.map +1 -0
  14. package/package.json +3 -3
  15. package/src/INestiaConfig.ts +261 -248
  16. package/src/NestiaSdkApplication.ts +255 -255
  17. package/src/analyses/ExceptionAnalyzer.ts +148 -148
  18. package/src/analyses/ImportAnalyzer.ts +137 -137
  19. package/src/analyses/SecurityAnalyzer.ts +24 -24
  20. package/src/generates/CloneGenerator.ts +62 -62
  21. package/src/generates/E2eGenerator.ts +66 -66
  22. package/src/generates/SdkGenerator.ts +84 -84
  23. package/src/generates/SwaggerGenerator.ts +23 -3
  24. package/src/generates/internal/E2eFileProgrammer.ts +182 -182
  25. package/src/generates/internal/FilePrinter.ts +53 -53
  26. package/src/generates/internal/SdkAliasCollection.ts +152 -152
  27. package/src/generates/internal/SdkCloneProgrammer.ts +155 -155
  28. package/src/generates/internal/SdkFileProgrammer.ts +115 -115
  29. package/src/generates/internal/SdkFunctionProgrammer.ts +298 -298
  30. package/src/generates/internal/SdkImportWizard.ts +55 -55
  31. package/src/generates/internal/SdkNamespaceProgrammer.ts +510 -510
  32. package/src/generates/internal/SdkRouteProgrammer.ts +83 -83
  33. package/src/generates/internal/SdkSimulationProgrammer.ts +365 -365
  34. package/src/generates/internal/SdkTypeProgrammer.ts +385 -385
  35. package/src/generates/internal/SwaggerSchemaGenerator.ts +438 -438
  36. package/src/structures/IController.ts +94 -94
  37. package/src/structures/IRoute.ts +53 -53
  38. package/src/structures/ISwagger.ts +66 -91
  39. package/src/structures/ISwaggerRoute.ts +54 -54
  40. package/src/structures/ISwaggerSecurityScheme.ts +65 -65
  41. package/src/structures/ISwaggerServer.ts +16 -0
  42. package/src/structures/ISwaggerTag.ts +9 -0
  43. package/src/structures/ParamCategory.ts +1 -1
  44. package/src/structures/TypeEntry.ts +22 -22
  45. package/src/utils/StringUtil.ts +6 -6
@@ -1,62 +1,62 @@
1
- import fs from "fs";
2
- import ts from "typescript";
3
-
4
- import { INestiaConfig } from "../INestiaConfig";
5
- import { IRoute } from "../structures/IRoute";
6
- import { FilePrinter } from "./internal/FilePrinter";
7
- import { ImportDictionary } from "./internal/ImportDictionary";
8
- import { SdkCloneProgrammer } from "./internal/SdkCloneProgrammer";
9
-
10
- export namespace CloneGenerator {
11
- export const write =
12
- (checker: ts.TypeChecker) =>
13
- (config: INestiaConfig) =>
14
- async (routes: IRoute[]): Promise<void> => {
15
- const dict: Map<string, SdkCloneProgrammer.IModule> =
16
- SdkCloneProgrammer.write(checker)(config)(routes);
17
- if (dict.size === 0) return;
18
- try {
19
- await fs.promises.mkdir(`${config.output}/structures`);
20
- } catch {}
21
- for (const [key, value] of dict) await writeDtoFile(config)(key, value);
22
- };
23
-
24
- const writeDtoFile =
25
- (config: INestiaConfig) =>
26
- async (key: string, value: SdkCloneProgrammer.IModule): Promise<void> => {
27
- const location: string = `${config.output}/structures/${key}.ts`;
28
- const importer: ImportDictionary = new ImportDictionary(location);
29
- const statements: ts.Statement[] = iterate(importer)(value);
30
- if (statements.length === 0) return;
31
-
32
- await FilePrinter.write({
33
- location,
34
- statements: [
35
- ...importer.toStatements(`${config.output}/structures`),
36
- ...(importer.empty() ? [] : [FilePrinter.enter()]),
37
- ...statements,
38
- ],
39
- });
40
- };
41
-
42
- const iterate =
43
- (importer: ImportDictionary) =>
44
- (modulo: SdkCloneProgrammer.IModule): ts.Statement[] => {
45
- const output: ts.Statement[] = [];
46
- if (modulo.programmer !== null) output.push(modulo.programmer(importer));
47
- if (modulo.children.size) {
48
- const internal: ts.Statement[] = [];
49
- for (const child of modulo.children.values())
50
- internal.push(...iterate(importer)(child));
51
- output.push(
52
- ts.factory.createModuleDeclaration(
53
- [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
54
- ts.factory.createIdentifier(modulo.name),
55
- ts.factory.createModuleBlock(internal),
56
- ts.NodeFlags.Namespace,
57
- ),
58
- );
59
- }
60
- return output;
61
- };
62
- }
1
+ import fs from "fs";
2
+ import ts from "typescript";
3
+
4
+ import { INestiaConfig } from "../INestiaConfig";
5
+ import { IRoute } from "../structures/IRoute";
6
+ import { FilePrinter } from "./internal/FilePrinter";
7
+ import { ImportDictionary } from "./internal/ImportDictionary";
8
+ import { SdkCloneProgrammer } from "./internal/SdkCloneProgrammer";
9
+
10
+ export namespace CloneGenerator {
11
+ export const write =
12
+ (checker: ts.TypeChecker) =>
13
+ (config: INestiaConfig) =>
14
+ async (routes: IRoute[]): Promise<void> => {
15
+ const dict: Map<string, SdkCloneProgrammer.IModule> =
16
+ SdkCloneProgrammer.write(checker)(config)(routes);
17
+ if (dict.size === 0) return;
18
+ try {
19
+ await fs.promises.mkdir(`${config.output}/structures`);
20
+ } catch {}
21
+ for (const [key, value] of dict) await writeDtoFile(config)(key, value);
22
+ };
23
+
24
+ const writeDtoFile =
25
+ (config: INestiaConfig) =>
26
+ async (key: string, value: SdkCloneProgrammer.IModule): Promise<void> => {
27
+ const location: string = `${config.output}/structures/${key}.ts`;
28
+ const importer: ImportDictionary = new ImportDictionary(location);
29
+ const statements: ts.Statement[] = iterate(importer)(value);
30
+ if (statements.length === 0) return;
31
+
32
+ await FilePrinter.write({
33
+ location,
34
+ statements: [
35
+ ...importer.toStatements(`${config.output}/structures`),
36
+ ...(importer.empty() ? [] : [FilePrinter.enter()]),
37
+ ...statements,
38
+ ],
39
+ });
40
+ };
41
+
42
+ const iterate =
43
+ (importer: ImportDictionary) =>
44
+ (modulo: SdkCloneProgrammer.IModule): ts.Statement[] => {
45
+ const output: ts.Statement[] = [];
46
+ if (modulo.programmer !== null) output.push(modulo.programmer(importer));
47
+ if (modulo.children.size) {
48
+ const internal: ts.Statement[] = [];
49
+ for (const child of modulo.children.values())
50
+ internal.push(...iterate(importer)(child));
51
+ output.push(
52
+ ts.factory.createModuleDeclaration(
53
+ [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
54
+ ts.factory.createIdentifier(modulo.name),
55
+ ts.factory.createModuleBlock(internal),
56
+ ts.NodeFlags.Namespace,
57
+ ),
58
+ );
59
+ }
60
+ return output;
61
+ };
62
+ }
@@ -1,66 +1,66 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import ts from "typescript";
4
-
5
- import { INestiaConfig } from "../INestiaConfig";
6
- import { ConfigAnalyzer } from "../analyses/ConfigAnalyzer";
7
- import { IRoute } from "../structures/IRoute";
8
- import { E2eFileProgrammer } from "./internal/E2eFileProgrammer";
9
-
10
- export namespace E2eGenerator {
11
- export const generate =
12
- (checker: ts.TypeChecker) =>
13
- (config: INestiaConfig) =>
14
- async (routeList: IRoute[]): Promise<void> => {
15
- console.log("Generating E2E Test Functions");
16
-
17
- // PREPARE DIRECTORIES
18
- const output: string = path.resolve(config.e2e!);
19
- await mkdir(output);
20
- await mkdir(path.join(output, "features"));
21
- await mkdir(path.join(output, "features", "api"));
22
- await mkdir(path.join(output, "features", "api", "automated"));
23
-
24
- // GENERATE TEST INDEX FILE
25
- await index(config)(path.join(config.e2e!, "index.ts"));
26
-
27
- // GENERATE EACH TEST FILES
28
- for (const route of routeList)
29
- await E2eFileProgrammer.generate(checker)(config)({
30
- api: path.resolve(config.output!),
31
- current: path.join(output, "features", "api", "automated"),
32
- })(route);
33
- };
34
-
35
- const index =
36
- (config: INestiaConfig) =>
37
- async (output: string): Promise<void> => {
38
- if (fs.existsSync(output)) return;
39
-
40
- const location: string = path.join(
41
- __dirname,
42
- "..",
43
- "..",
44
- "assets",
45
- "bundle",
46
- "e2e",
47
- "index.ts",
48
- );
49
- const content: string = await fs.promises.readFile(location, "utf8");
50
-
51
- await fs.promises.writeFile(
52
- output,
53
- content.replace(
54
- "${input}",
55
- JSON.stringify(await ConfigAnalyzer.input(config)),
56
- ),
57
- "utf8",
58
- );
59
- };
60
- }
61
-
62
- const mkdir = async (location: string): Promise<void> => {
63
- try {
64
- await fs.promises.mkdir(location);
65
- } catch {}
66
- };
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import ts from "typescript";
4
+
5
+ import { INestiaConfig } from "../INestiaConfig";
6
+ import { ConfigAnalyzer } from "../analyses/ConfigAnalyzer";
7
+ import { IRoute } from "../structures/IRoute";
8
+ import { E2eFileProgrammer } from "./internal/E2eFileProgrammer";
9
+
10
+ export namespace E2eGenerator {
11
+ export const generate =
12
+ (checker: ts.TypeChecker) =>
13
+ (config: INestiaConfig) =>
14
+ async (routeList: IRoute[]): Promise<void> => {
15
+ console.log("Generating E2E Test Functions");
16
+
17
+ // PREPARE DIRECTORIES
18
+ const output: string = path.resolve(config.e2e!);
19
+ await mkdir(output);
20
+ await mkdir(path.join(output, "features"));
21
+ await mkdir(path.join(output, "features", "api"));
22
+ await mkdir(path.join(output, "features", "api", "automated"));
23
+
24
+ // GENERATE TEST INDEX FILE
25
+ await index(config)(path.join(config.e2e!, "index.ts"));
26
+
27
+ // GENERATE EACH TEST FILES
28
+ for (const route of routeList)
29
+ await E2eFileProgrammer.generate(checker)(config)({
30
+ api: path.resolve(config.output!),
31
+ current: path.join(output, "features", "api", "automated"),
32
+ })(route);
33
+ };
34
+
35
+ const index =
36
+ (config: INestiaConfig) =>
37
+ async (output: string): Promise<void> => {
38
+ if (fs.existsSync(output)) return;
39
+
40
+ const location: string = path.join(
41
+ __dirname,
42
+ "..",
43
+ "..",
44
+ "assets",
45
+ "bundle",
46
+ "e2e",
47
+ "index.ts",
48
+ );
49
+ const content: string = await fs.promises.readFile(location, "utf8");
50
+
51
+ await fs.promises.writeFile(
52
+ output,
53
+ content.replace(
54
+ "${input}",
55
+ JSON.stringify(await ConfigAnalyzer.input(config)),
56
+ ),
57
+ "utf8",
58
+ );
59
+ };
60
+ }
61
+
62
+ const mkdir = async (location: string): Promise<void> => {
63
+ try {
64
+ await fs.promises.mkdir(location);
65
+ } catch {}
66
+ };
@@ -1,84 +1,84 @@
1
- import fs from "fs";
2
- import NodePath from "path";
3
- import { IPointer } from "tstl";
4
- import ts from "typescript";
5
-
6
- import { INestiaConfig } from "../INestiaConfig";
7
- import { IRoute } from "../structures/IRoute";
8
- import { CloneGenerator } from "./CloneGenerator";
9
- import { SdkDistributionComposer } from "./internal/SdkDistributionComposer";
10
- import { SdkFileProgrammer } from "./internal/SdkFileProgrammer";
11
-
12
- export namespace SdkGenerator {
13
- export const generate =
14
- (checker: ts.TypeChecker) =>
15
- (config: INestiaConfig) =>
16
- async (routes: IRoute[]): Promise<void> => {
17
- console.log("Generating SDK Library");
18
-
19
- // PREPARE NEW DIRECTORIES
20
- try {
21
- await fs.promises.mkdir(config.output!);
22
- } catch {}
23
-
24
- // BUNDLING
25
- const bundle: string[] = await fs.promises.readdir(BUNDLE_PATH);
26
- for (const file of bundle) {
27
- const current: string = `${BUNDLE_PATH}/${file}`;
28
- const target: string = `${config.output}/${file}`;
29
- const stats: fs.Stats = await fs.promises.stat(current);
30
-
31
- if (stats.isFile() === true) {
32
- const content: string = await fs.promises.readFile(current, "utf8");
33
- if (fs.existsSync(target) === false)
34
- await fs.promises.writeFile(target, content, "utf8");
35
- else if (BUNDLE_CHANGES[file] !== undefined) {
36
- const r: IPointer<string> = {
37
- value: await fs.promises.readFile(target, "utf8"),
38
- };
39
- for (const [before, after] of BUNDLE_CHANGES[file])
40
- r.value = r.value.replace(before, after);
41
- await fs.promises.writeFile(target, r.value, "utf8");
42
- }
43
- }
44
- }
45
-
46
- // STRUCTURES
47
- if (config.clone) await CloneGenerator.write(checker)(config)(routes);
48
-
49
- // FUNCTIONAL
50
- await SdkFileProgrammer.generate(checker)(config)(routes);
51
-
52
- // DISTRIBUTION
53
- if (config.distribute !== undefined)
54
- await SdkDistributionComposer.compose(config);
55
- };
56
-
57
- export const BUNDLE_PATH = NodePath.join(
58
- __dirname,
59
- "..",
60
- "..",
61
- "assets",
62
- "bundle",
63
- "api",
64
- );
65
- }
66
-
67
- const BUNDLE_CHANGES: Record<string, [string, string][]> = {
68
- "IConnection.ts": [
69
- [
70
- `export { IConnection } from "@nestia/fetcher"`,
71
- `export type { IConnection } from "@nestia/fetcher"`,
72
- ],
73
- ],
74
- "module.ts": [
75
- [`export * from "./IConnection"`, `export type * from "./IConnection"`],
76
- [`export * from "./Primitive"`, `export type * from "./Primitive"`],
77
- ],
78
- "Primitive.ts": [
79
- [
80
- `export { Primitive } from "@nestia/fetcher"`,
81
- `export type { Primitive } from "@nestia/fetcher"`,
82
- ],
83
- ],
84
- };
1
+ import fs from "fs";
2
+ import NodePath from "path";
3
+ import { IPointer } from "tstl";
4
+ import ts from "typescript";
5
+
6
+ import { INestiaConfig } from "../INestiaConfig";
7
+ import { IRoute } from "../structures/IRoute";
8
+ import { CloneGenerator } from "./CloneGenerator";
9
+ import { SdkDistributionComposer } from "./internal/SdkDistributionComposer";
10
+ import { SdkFileProgrammer } from "./internal/SdkFileProgrammer";
11
+
12
+ export namespace SdkGenerator {
13
+ export const generate =
14
+ (checker: ts.TypeChecker) =>
15
+ (config: INestiaConfig) =>
16
+ async (routes: IRoute[]): Promise<void> => {
17
+ console.log("Generating SDK Library");
18
+
19
+ // PREPARE NEW DIRECTORIES
20
+ try {
21
+ await fs.promises.mkdir(config.output!);
22
+ } catch {}
23
+
24
+ // BUNDLING
25
+ const bundle: string[] = await fs.promises.readdir(BUNDLE_PATH);
26
+ for (const file of bundle) {
27
+ const current: string = `${BUNDLE_PATH}/${file}`;
28
+ const target: string = `${config.output}/${file}`;
29
+ const stats: fs.Stats = await fs.promises.stat(current);
30
+
31
+ if (stats.isFile() === true) {
32
+ const content: string = await fs.promises.readFile(current, "utf8");
33
+ if (fs.existsSync(target) === false)
34
+ await fs.promises.writeFile(target, content, "utf8");
35
+ else if (BUNDLE_CHANGES[file] !== undefined) {
36
+ const r: IPointer<string> = {
37
+ value: await fs.promises.readFile(target, "utf8"),
38
+ };
39
+ for (const [before, after] of BUNDLE_CHANGES[file])
40
+ r.value = r.value.replace(before, after);
41
+ await fs.promises.writeFile(target, r.value, "utf8");
42
+ }
43
+ }
44
+ }
45
+
46
+ // STRUCTURES
47
+ if (config.clone) await CloneGenerator.write(checker)(config)(routes);
48
+
49
+ // FUNCTIONAL
50
+ await SdkFileProgrammer.generate(checker)(config)(routes);
51
+
52
+ // DISTRIBUTION
53
+ if (config.distribute !== undefined)
54
+ await SdkDistributionComposer.compose(config);
55
+ };
56
+
57
+ export const BUNDLE_PATH = NodePath.join(
58
+ __dirname,
59
+ "..",
60
+ "..",
61
+ "assets",
62
+ "bundle",
63
+ "api",
64
+ );
65
+ }
66
+
67
+ const BUNDLE_CHANGES: Record<string, [string, string][]> = {
68
+ "IConnection.ts": [
69
+ [
70
+ `export { IConnection } from "@nestia/fetcher"`,
71
+ `export type { IConnection } from "@nestia/fetcher"`,
72
+ ],
73
+ ],
74
+ "module.ts": [
75
+ [`export * from "./IConnection"`, `export type * from "./IConnection"`],
76
+ [`export * from "./Primitive"`, `export type * from "./Primitive"`],
77
+ ],
78
+ "Primitive.ts": [
79
+ [
80
+ `export { Primitive } from "@nestia/fetcher"`,
81
+ `export type { Primitive } from "@nestia/fetcher"`,
82
+ ],
83
+ ],
84
+ };
@@ -27,6 +27,7 @@ export namespace SwaggerGenerator {
27
27
  lazySchemas: Array<ISwaggerLazySchema>;
28
28
  lazyProperties: Array<ISwaggerLazyProperty>;
29
29
  errors: ISwaggerError[];
30
+ swagger: ISwagger;
30
31
  }
31
32
 
32
33
  export const generate =
@@ -80,6 +81,7 @@ export namespace SwaggerGenerator {
80
81
  lazySchemas,
81
82
  lazyProperties,
82
83
  errors,
84
+ swagger,
83
85
  })(route);
84
86
  }
85
87
  swagger.paths = {};
@@ -329,6 +331,7 @@ export namespace SwaggerGenerator {
329
331
  },
330
332
  paths: {},
331
333
  components: {},
334
+ tags: config.tags ?? [],
332
335
  };
333
336
  };
334
337
 
@@ -344,8 +347,11 @@ export namespace SwaggerGenerator {
344
347
  const generate_route =
345
348
  (props: IProps) =>
346
349
  (route: IRoute): ISwaggerRoute => {
350
+ // FIND REQUEST BODY
347
351
  const body = route.parameters.find((param) => param.category === "body");
348
- const getJsDocTexts = (name: string) =>
352
+
353
+ // CONSTRUCT SUMMARY & DESCRIPTION
354
+ const getJsDocTexts = (name: string): string[] =>
349
355
  route.jsDocTags
350
356
  .filter(
351
357
  (tag) =>
@@ -356,7 +362,6 @@ export namespace SwaggerGenerator {
356
362
  ) !== undefined,
357
363
  )
358
364
  .map((tag) => tag.text!.find((elem) => elem.kind === "text")!.text);
359
-
360
365
  const description: string | undefined = route.description?.length
361
366
  ? route.description
362
367
  : undefined;
@@ -376,9 +381,24 @@ export namespace SwaggerGenerator {
376
381
  (tag) => tag.name === "deprecated",
377
382
  );
378
383
 
384
+ // CONSTRUCT TAGS
385
+ const tagSet: Set<string> = new Set(
386
+ ...route.swaggerTags,
387
+ getJsDocTexts("tag").map((tag) => tag.split(" ")[0]),
388
+ );
389
+ for (const tag of tagSet)
390
+ if (props.swagger.tags.find((elem) => elem.name === tag) === undefined)
391
+ props.swagger.tags.push({ name: tag });
392
+ for (const tag of getJsDocTexts("tag")) {
393
+ const [name, ...description] = tag.split(" ");
394
+ if (description.length)
395
+ props.swagger.tags.find((elem) => elem.name === name)!.description =
396
+ description.join(" ");
397
+ }
398
+ // FINALIZE
379
399
  return {
380
400
  deprecated: deprecated ? true : undefined,
381
- tags: [...route.swaggerTags, ...new Set([...getJsDocTexts("tag")])],
401
+ tags: [...tagSet],
382
402
  operationId:
383
403
  route.operationId ??
384
404
  props.config.operationId?.({