@nestia/sdk 2.4.2 → 2.4.3

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 (111) hide show
  1. package/lib/NestiaSdkApplication.js +2 -6
  2. package/lib/NestiaSdkApplication.js.map +1 -1
  3. package/lib/analyses/AccessorAnalyzer.js.map +1 -1
  4. package/lib/analyses/ConfigAnalyzer.js +4 -8
  5. package/lib/analyses/ConfigAnalyzer.js.map +1 -1
  6. package/lib/analyses/ControllerAnalyzer.js +6 -8
  7. package/lib/analyses/ControllerAnalyzer.js.map +1 -1
  8. package/lib/analyses/ExceptionAnalyzer.js.map +1 -1
  9. package/lib/analyses/GenericAnalyzer.js +1 -2
  10. package/lib/analyses/GenericAnalyzer.js.map +1 -1
  11. package/lib/analyses/ImportAnalyzer.js +4 -4
  12. package/lib/analyses/ImportAnalyzer.js.map +1 -1
  13. package/lib/analyses/PathAnalyzer.js.map +1 -1
  14. package/lib/analyses/ReflectAnalyzer.js +7 -8
  15. package/lib/analyses/ReflectAnalyzer.js.map +1 -1
  16. package/lib/analyses/SecurityAnalyzer.js.map +1 -1
  17. package/lib/executable/internal/CommandParser.js.map +1 -1
  18. package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
  19. package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
  20. package/lib/executable/sdk.js +11 -11
  21. package/lib/executable/sdk.js.map +1 -1
  22. package/lib/generates/E2eGenerator.js.map +1 -1
  23. package/lib/generates/SdkGenerator.js.map +1 -1
  24. package/lib/generates/SwaggerGenerator.js +5 -11
  25. package/lib/generates/SwaggerGenerator.js.map +1 -1
  26. package/lib/generates/internal/E2eFileProgrammer.js +2 -8
  27. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  28. package/lib/generates/internal/SdkDistributionComposer.js.map +1 -1
  29. package/lib/generates/internal/SdkDtoGenerator.js +3 -9
  30. package/lib/generates/internal/SdkDtoGenerator.js.map +1 -1
  31. package/lib/generates/internal/SdkFileProgrammer.js +4 -4
  32. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  33. package/lib/generates/internal/SdkFunctionProgrammer.js +12 -20
  34. package/lib/generates/internal/SdkFunctionProgrammer.js.map +1 -1
  35. package/lib/generates/internal/SdkImportWizard.js.map +1 -1
  36. package/lib/generates/internal/SdkRouteDirectory.js +1 -3
  37. package/lib/generates/internal/SdkRouteDirectory.js.map +1 -1
  38. package/lib/generates/internal/SdkSimulationProgrammer.js +5 -7
  39. package/lib/generates/internal/SdkSimulationProgrammer.js.map +1 -1
  40. package/lib/generates/internal/SdkTypeDefiner.js +2 -5
  41. package/lib/generates/internal/SdkTypeDefiner.js.map +1 -1
  42. package/lib/generates/internal/SwaggerSchemaGenerator.js +29 -44
  43. package/lib/generates/internal/SwaggerSchemaGenerator.js.map +1 -1
  44. package/lib/generates/internal/SwaggerSchemaValidator.js +3 -9
  45. package/lib/generates/internal/SwaggerSchemaValidator.js.map +1 -1
  46. package/lib/structures/MethodType.js +1 -7
  47. package/lib/structures/MethodType.js.map +1 -1
  48. package/lib/structures/TypeEntry.js.map +1 -1
  49. package/lib/utils/ArrayUtil.js.map +1 -1
  50. package/lib/utils/FileRetriever.js.map +1 -1
  51. package/lib/utils/ImportDictionary.js +1 -4
  52. package/lib/utils/ImportDictionary.js.map +1 -1
  53. package/lib/utils/MapUtil.js.map +1 -1
  54. package/lib/utils/PathUtil.js.map +1 -1
  55. package/lib/utils/SourceFinder.js.map +1 -1
  56. package/package.json +4 -7
  57. package/src/INestiaConfig.ts +234 -234
  58. package/src/NestiaSdkApplication.ts +253 -268
  59. package/src/analyses/AccessorAnalyzer.ts +60 -60
  60. package/src/analyses/ConfigAnalyzer.ts +147 -164
  61. package/src/analyses/ControllerAnalyzer.ts +379 -399
  62. package/src/analyses/ExceptionAnalyzer.ts +115 -124
  63. package/src/analyses/GenericAnalyzer.ts +51 -57
  64. package/src/analyses/ImportAnalyzer.ts +138 -159
  65. package/src/analyses/PathAnalyzer.ts +98 -100
  66. package/src/analyses/ReflectAnalyzer.ts +425 -433
  67. package/src/analyses/SecurityAnalyzer.ts +20 -20
  68. package/src/executable/internal/CommandParser.ts +15 -15
  69. package/src/executable/internal/NestiaConfigLoader.ts +67 -68
  70. package/src/executable/internal/NestiaSdkCommand.ts +60 -64
  71. package/src/executable/sdk.ts +73 -73
  72. package/src/generates/E2eGenerator.ts +64 -67
  73. package/src/generates/SdkGenerator.ts +96 -100
  74. package/src/generates/SwaggerGenerator.ts +372 -410
  75. package/src/generates/internal/E2eFileProgrammer.ts +123 -129
  76. package/src/generates/internal/SdkDistributionComposer.ts +91 -91
  77. package/src/generates/internal/SdkDtoGenerator.ts +424 -450
  78. package/src/generates/internal/SdkFileProgrammer.ts +106 -111
  79. package/src/generates/internal/SdkFunctionProgrammer.ts +466 -501
  80. package/src/generates/internal/SdkImportWizard.ts +55 -55
  81. package/src/generates/internal/SdkRouteDirectory.ts +17 -19
  82. package/src/generates/internal/SdkSimulationProgrammer.ts +133 -142
  83. package/src/generates/internal/SdkTypeDefiner.ts +119 -124
  84. package/src/generates/internal/SwaggerSchemaGenerator.ts +382 -401
  85. package/src/generates/internal/SwaggerSchemaValidator.ts +198 -210
  86. package/src/index.ts +4 -4
  87. package/src/module.ts +2 -2
  88. package/src/structures/IController.ts +79 -81
  89. package/src/structures/IErrorReport.ts +6 -6
  90. package/src/structures/INestiaProject.ts +13 -13
  91. package/src/structures/INormalizedInput.ts +20 -20
  92. package/src/structures/IRoute.ts +40 -41
  93. package/src/structures/ISwagger.ts +91 -91
  94. package/src/structures/ISwaggerComponents.ts +29 -29
  95. package/src/structures/ISwaggerError.ts +8 -8
  96. package/src/structures/ISwaggerInfo.ts +80 -80
  97. package/src/structures/ISwaggerLazyProperty.ts +7 -7
  98. package/src/structures/ISwaggerLazySchema.ts +7 -7
  99. package/src/structures/ISwaggerRoute.ts +51 -51
  100. package/src/structures/ISwaggerSecurityScheme.ts +65 -65
  101. package/src/structures/ITypeTuple.ts +6 -6
  102. package/src/structures/MethodType.ts +5 -11
  103. package/src/structures/ParamCategory.ts +1 -1
  104. package/src/structures/TypeEntry.ts +22 -22
  105. package/src/utils/ArrayUtil.ts +26 -26
  106. package/src/utils/FileRetriever.ts +22 -22
  107. package/src/utils/ImportDictionary.ts +125 -128
  108. package/src/utils/MapUtil.ts +14 -14
  109. package/src/utils/PathUtil.ts +10 -10
  110. package/src/utils/SourceFinder.ts +66 -70
  111. package/src/utils/StripEnums.ts +5 -10
@@ -1,268 +1,253 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import ts from "typescript";
4
-
5
- import { INestiaConfig } from "./INestiaConfig";
6
- import { AccessorAnalyzer } from "./analyses/AccessorAnalyzer";
7
- import { ConfigAnalyzer } from "./analyses/ConfigAnalyzer";
8
- import { ControllerAnalyzer } from "./analyses/ControllerAnalyzer";
9
- import { ReflectAnalyzer } from "./analyses/ReflectAnalyzer";
10
- import { E2eGenerator } from "./generates/E2eGenerator";
11
- import { SdkGenerator } from "./generates/SdkGenerator";
12
- import { SwaggerGenerator } from "./generates/SwaggerGenerator";
13
- import { IController } from "./structures/IController";
14
- import { IErrorReport } from "./structures/IErrorReport";
15
- import { INestiaProject } from "./structures/INestiaProject";
16
- import { IRoute } from "./structures/IRoute";
17
- import { MapUtil } from "./utils/MapUtil";
18
-
19
- export class NestiaSdkApplication {
20
- public constructor(
21
- private readonly config: INestiaConfig,
22
- private readonly compilerOptions: ts.CompilerOptions,
23
- ) {}
24
-
25
- public async e2e(): Promise<void> {
26
- if (!this.config.output)
27
- throw new Error(
28
- "Error on NestiaApplication.e2e(): output path of SDK is not specified.",
29
- );
30
- else if (!this.config.e2e)
31
- throw new Error(
32
- "Error on NestiaApplication.e2e(): output path of e2e test files is not specified.",
33
- );
34
-
35
- const validate =
36
- (title: string) =>
37
- async (location: string): Promise<void> => {
38
- const parent: string = path.resolve(location + "/..");
39
- const stats: fs.Stats = await fs.promises.lstat(parent);
40
- if (stats.isDirectory() === false)
41
- throw new Error(
42
- `Error on NestiaApplication.e2e(): output directory of ${title} does not exists.`,
43
- );
44
- };
45
- await validate("sdk")(this.config.output);
46
- await validate("e2e")(this.config.e2e);
47
-
48
- print_title("Nestia E2E Generator");
49
- await this.generate(
50
- "e2e",
51
- (config) => config,
52
- (checker) => (config) => async (routes) => {
53
- await SdkGenerator.generate(checker)(config)(routes);
54
- await E2eGenerator.generate(config)(routes);
55
- },
56
- );
57
- }
58
-
59
- public async sdk(): Promise<void> {
60
- if (!this.config.output)
61
- throw new Error(
62
- "Error on NestiaApplication.sdk(): output path is not specified.",
63
- );
64
-
65
- const parent: string = path.resolve(this.config.output + "/..");
66
- const stats: fs.Stats = await fs.promises.lstat(parent);
67
- if (stats.isDirectory() === false)
68
- throw new Error(
69
- "Error on NestiaApplication.sdk(): output directory does not exists.",
70
- );
71
-
72
- print_title("Nestia SDK Generator");
73
- await this.generate("sdk", (config) => config, SdkGenerator.generate);
74
- }
75
-
76
- public async swagger(): Promise<void> {
77
- if (!this.config.swagger?.output)
78
- throw new Error(
79
- `Error on NestiaApplication.swagger(): output path of the "swagger.json" is not specified.`,
80
- );
81
-
82
- const parsed: path.ParsedPath = path.parse(this.config.swagger.output);
83
- const directory: string = !!parsed.ext
84
- ? path.resolve(parsed.dir)
85
- : this.config.swagger.output;
86
- const stats: fs.Stats = await fs.promises.lstat(directory);
87
- if (stats.isDirectory() === false)
88
- throw new Error(
89
- "Error on NestiaApplication.swagger(): output directory does not exists.",
90
- );
91
-
92
- print_title("Nestia Swagger Generator");
93
- await this.generate(
94
- "swagger",
95
- (config) => config.swagger!,
96
- SwaggerGenerator.generate,
97
- );
98
- }
99
-
100
- private async generate<Config>(
101
- method: string,
102
- config: (entire: INestiaConfig) => Config,
103
- archiver: (
104
- checker: ts.TypeChecker,
105
- ) => (config: Config) => (routes: IRoute[]) => Promise<void>,
106
- ): Promise<void> {
107
- //----
108
- // ANALYZE REFLECTS
109
- //----
110
- const unique: WeakSet<any> = new WeakSet();
111
- const controllers: IController[] = [];
112
- const project: INestiaProject = {
113
- config: this.config,
114
- input: await ConfigAnalyzer.input(this.config),
115
- checker: null!,
116
- errors: [],
117
- warnings: [],
118
- };
119
-
120
- console.log("Analyzing reflections");
121
- for (const include of (await ConfigAnalyzer.input(this.config)).include)
122
- controllers.push(
123
- ...(await ReflectAnalyzer.analyze(project)(
124
- unique,
125
- include.file,
126
- include.paths,
127
- include.controller,
128
- )),
129
- );
130
-
131
- const agg: number = (() => {
132
- const set: Set<string> = new Set();
133
- for (const c of controllers)
134
- for (const cPath of c.paths)
135
- for (const f of c.functions)
136
- for (const fPath of f.paths)
137
- set.add(`${f.method}::${cPath}/${fPath}`);
138
- return set.size;
139
- })();
140
-
141
- console.log(` - controllers: #${controllers.length}`);
142
- console.log(` - paths: #${agg}`);
143
- console.log(
144
- ` - routes: #${controllers
145
- .map(
146
- (c) =>
147
- c.paths.length *
148
- c.functions
149
- .map((f) => f.paths.length)
150
- .reduce((a, b) => a + b, 0),
151
- )
152
- .reduce((a, b) => a + b, 0)}`,
153
- );
154
-
155
- //----
156
- // ANALYZE TYPESCRIPT CODE
157
- //----
158
- console.log("Analyzing source codes");
159
-
160
- const program: ts.Program = ts.createProgram(
161
- controllers.map((c) => c.file),
162
- this.compilerOptions,
163
- );
164
- project.checker = program.getTypeChecker();
165
-
166
- const routeList: IRoute[] = [];
167
- for (const c of controllers) {
168
- const file: ts.SourceFile | undefined = program.getSourceFile(
169
- c.file,
170
- );
171
- if (file === undefined) continue;
172
- routeList.push(
173
- ...(await ControllerAnalyzer.analyze(project)(file, c)),
174
- );
175
- }
176
-
177
- // REPORT ERRORS
178
- if (project.errors.length) {
179
- report_errors("error")(project.errors);
180
- process.exit(-1);
181
- }
182
- if (project.warnings.length) report_errors("warning")(project.warnings);
183
-
184
- // FIND IMPLICIT TYPES
185
- const implicit: IRoute[] = routeList.filter(is_implicit_return_typed);
186
- if (implicit.length > 0)
187
- throw new Error(
188
- `NestiaApplication.${method}(): implicit return type is not allowed.\n` +
189
- "\n" +
190
- "List of implicit return typed routes:\n" +
191
- implicit
192
- .map(
193
- (it) =>
194
- ` - ${it.symbol.class}.${it.symbol.function} at "${it.location}"`,
195
- )
196
- .join("\n"),
197
- );
198
-
199
- // DO GENERATE
200
- AccessorAnalyzer.analyze(routeList);
201
- await archiver(project.checker)(config(this.config))(routeList);
202
- }
203
- }
204
-
205
- const print_title = (str: string): void => {
206
- console.log("-----------------------------------------------------------");
207
- console.log(` ${str}`);
208
- console.log("-----------------------------------------------------------");
209
- };
210
-
211
- const is_implicit_return_typed = (route: IRoute): boolean => {
212
- const name: string = route.output.typeName;
213
- if (name === "void") return false;
214
- else if (name.indexOf("readonly [") !== -1) return true;
215
-
216
- const pos: number = name.indexOf("__object");
217
- if (pos === -1) return false;
218
-
219
- const before: number = pos - 1;
220
- const after: number = pos + "__object".length;
221
- for (const i of [before, after])
222
- if (name[i] === undefined) continue;
223
- else if (VARIABLE.test(name[i])) return false;
224
- return true;
225
- };
226
-
227
- const report_errors =
228
- (type: "error" | "warning") =>
229
- (errors: IErrorReport[]): void => {
230
- // key: file
231
- // key: controller
232
- // key: function
233
- // value: message
234
- const map: Map<
235
- string,
236
- Map<string, Map<string, Set<string>>>
237
- > = new Map();
238
- for (const e of errors) {
239
- const file = MapUtil.take(map, e.file, () => new Map());
240
- const controller = MapUtil.take(
241
- file,
242
- e.controller,
243
- () => new Map(),
244
- );
245
- const func = MapUtil.take(controller, e.function, () => new Set());
246
- func.add(e.message);
247
- }
248
-
249
- console.log("");
250
- print_title(`Nestia ${type[0].toUpperCase()}${type.slice(1)} Report`);
251
- for (const [file, cMap] of map) {
252
- for (const [controller, fMap] of cMap)
253
- for (const [func, messages] of fMap) {
254
- const location: string = path.relative(process.cwd(), file);
255
- console.log(
256
- `${location} - ${
257
- func !== null
258
- ? `${controller}.${func}()`
259
- : controller
260
- }`,
261
- );
262
- for (const msg of messages) console.log(` - ${msg}`);
263
- console.log("");
264
- }
265
- }
266
- };
267
-
268
- const VARIABLE = /[a-zA-Z_$0-9]/;
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import ts from "typescript";
4
+
5
+ import { INestiaConfig } from "./INestiaConfig";
6
+ import { AccessorAnalyzer } from "./analyses/AccessorAnalyzer";
7
+ import { ConfigAnalyzer } from "./analyses/ConfigAnalyzer";
8
+ import { ControllerAnalyzer } from "./analyses/ControllerAnalyzer";
9
+ import { ReflectAnalyzer } from "./analyses/ReflectAnalyzer";
10
+ import { E2eGenerator } from "./generates/E2eGenerator";
11
+ import { SdkGenerator } from "./generates/SdkGenerator";
12
+ import { SwaggerGenerator } from "./generates/SwaggerGenerator";
13
+ import { IController } from "./structures/IController";
14
+ import { IErrorReport } from "./structures/IErrorReport";
15
+ import { INestiaProject } from "./structures/INestiaProject";
16
+ import { IRoute } from "./structures/IRoute";
17
+ import { MapUtil } from "./utils/MapUtil";
18
+
19
+ export class NestiaSdkApplication {
20
+ public constructor(
21
+ private readonly config: INestiaConfig,
22
+ private readonly compilerOptions: ts.CompilerOptions,
23
+ ) {}
24
+
25
+ public async e2e(): Promise<void> {
26
+ if (!this.config.output)
27
+ throw new Error(
28
+ "Error on NestiaApplication.e2e(): output path of SDK is not specified.",
29
+ );
30
+ else if (!this.config.e2e)
31
+ throw new Error(
32
+ "Error on NestiaApplication.e2e(): output path of e2e test files is not specified.",
33
+ );
34
+
35
+ const validate =
36
+ (title: string) =>
37
+ async (location: string): Promise<void> => {
38
+ const parent: string = path.resolve(location + "/..");
39
+ const stats: fs.Stats = await fs.promises.lstat(parent);
40
+ if (stats.isDirectory() === false)
41
+ throw new Error(
42
+ `Error on NestiaApplication.e2e(): output directory of ${title} does not exists.`,
43
+ );
44
+ };
45
+ await validate("sdk")(this.config.output);
46
+ await validate("e2e")(this.config.e2e);
47
+
48
+ print_title("Nestia E2E Generator");
49
+ await this.generate(
50
+ "e2e",
51
+ (config) => config,
52
+ (checker) => (config) => async (routes) => {
53
+ await SdkGenerator.generate(checker)(config)(routes);
54
+ await E2eGenerator.generate(config)(routes);
55
+ },
56
+ );
57
+ }
58
+
59
+ public async sdk(): Promise<void> {
60
+ if (!this.config.output)
61
+ throw new Error(
62
+ "Error on NestiaApplication.sdk(): output path is not specified.",
63
+ );
64
+
65
+ const parent: string = path.resolve(this.config.output + "/..");
66
+ const stats: fs.Stats = await fs.promises.lstat(parent);
67
+ if (stats.isDirectory() === false)
68
+ throw new Error(
69
+ "Error on NestiaApplication.sdk(): output directory does not exists.",
70
+ );
71
+
72
+ print_title("Nestia SDK Generator");
73
+ await this.generate("sdk", (config) => config, SdkGenerator.generate);
74
+ }
75
+
76
+ public async swagger(): Promise<void> {
77
+ if (!this.config.swagger?.output)
78
+ throw new Error(
79
+ `Error on NestiaApplication.swagger(): output path of the "swagger.json" is not specified.`,
80
+ );
81
+
82
+ const parsed: path.ParsedPath = path.parse(this.config.swagger.output);
83
+ const directory: string = !!parsed.ext
84
+ ? path.resolve(parsed.dir)
85
+ : this.config.swagger.output;
86
+ const stats: fs.Stats = await fs.promises.lstat(directory);
87
+ if (stats.isDirectory() === false)
88
+ throw new Error(
89
+ "Error on NestiaApplication.swagger(): output directory does not exists.",
90
+ );
91
+
92
+ print_title("Nestia Swagger Generator");
93
+ await this.generate(
94
+ "swagger",
95
+ (config) => config.swagger!,
96
+ SwaggerGenerator.generate,
97
+ );
98
+ }
99
+
100
+ private async generate<Config>(
101
+ method: string,
102
+ config: (entire: INestiaConfig) => Config,
103
+ archiver: (
104
+ checker: ts.TypeChecker,
105
+ ) => (config: Config) => (routes: IRoute[]) => Promise<void>,
106
+ ): Promise<void> {
107
+ //----
108
+ // ANALYZE REFLECTS
109
+ //----
110
+ const unique: WeakSet<any> = new WeakSet();
111
+ const controllers: IController[] = [];
112
+ const project: INestiaProject = {
113
+ config: this.config,
114
+ input: await ConfigAnalyzer.input(this.config),
115
+ checker: null!,
116
+ errors: [],
117
+ warnings: [],
118
+ };
119
+
120
+ console.log("Analyzing reflections");
121
+ for (const include of (await ConfigAnalyzer.input(this.config)).include)
122
+ controllers.push(
123
+ ...(await ReflectAnalyzer.analyze(project)(
124
+ unique,
125
+ include.file,
126
+ include.paths,
127
+ include.controller,
128
+ )),
129
+ );
130
+
131
+ const agg: number = (() => {
132
+ const set: Set<string> = new Set();
133
+ for (const c of controllers)
134
+ for (const cPath of c.paths)
135
+ for (const f of c.functions)
136
+ for (const fPath of f.paths)
137
+ set.add(`${f.method}::${cPath}/${fPath}`);
138
+ return set.size;
139
+ })();
140
+
141
+ console.log(` - controllers: #${controllers.length}`);
142
+ console.log(` - paths: #${agg}`);
143
+ console.log(
144
+ ` - routes: #${controllers
145
+ .map(
146
+ (c) =>
147
+ c.paths.length *
148
+ c.functions.map((f) => f.paths.length).reduce((a, b) => a + b, 0),
149
+ )
150
+ .reduce((a, b) => a + b, 0)}`,
151
+ );
152
+
153
+ //----
154
+ // ANALYZE TYPESCRIPT CODE
155
+ //----
156
+ console.log("Analyzing source codes");
157
+
158
+ const program: ts.Program = ts.createProgram(
159
+ controllers.map((c) => c.file),
160
+ this.compilerOptions,
161
+ );
162
+ project.checker = program.getTypeChecker();
163
+
164
+ const routeList: IRoute[] = [];
165
+ for (const c of controllers) {
166
+ const file: ts.SourceFile | undefined = program.getSourceFile(c.file);
167
+ if (file === undefined) continue;
168
+ routeList.push(...(await ControllerAnalyzer.analyze(project)(file, c)));
169
+ }
170
+
171
+ // REPORT ERRORS
172
+ if (project.errors.length) {
173
+ report_errors("error")(project.errors);
174
+ process.exit(-1);
175
+ }
176
+ if (project.warnings.length) report_errors("warning")(project.warnings);
177
+
178
+ // FIND IMPLICIT TYPES
179
+ const implicit: IRoute[] = routeList.filter(is_implicit_return_typed);
180
+ if (implicit.length > 0)
181
+ throw new Error(
182
+ `NestiaApplication.${method}(): implicit return type is not allowed.\n` +
183
+ "\n" +
184
+ "List of implicit return typed routes:\n" +
185
+ implicit
186
+ .map(
187
+ (it) =>
188
+ ` - ${it.symbol.class}.${it.symbol.function} at "${it.location}"`,
189
+ )
190
+ .join("\n"),
191
+ );
192
+
193
+ // DO GENERATE
194
+ AccessorAnalyzer.analyze(routeList);
195
+ await archiver(project.checker)(config(this.config))(routeList);
196
+ }
197
+ }
198
+
199
+ const print_title = (str: string): void => {
200
+ console.log("-----------------------------------------------------------");
201
+ console.log(` ${str}`);
202
+ console.log("-----------------------------------------------------------");
203
+ };
204
+
205
+ const is_implicit_return_typed = (route: IRoute): boolean => {
206
+ const name: string = route.output.typeName;
207
+ if (name === "void") return false;
208
+ else if (name.indexOf("readonly [") !== -1) return true;
209
+
210
+ const pos: number = name.indexOf("__object");
211
+ if (pos === -1) return false;
212
+
213
+ const before: number = pos - 1;
214
+ const after: number = pos + "__object".length;
215
+ for (const i of [before, after])
216
+ if (name[i] === undefined) continue;
217
+ else if (VARIABLE.test(name[i])) return false;
218
+ return true;
219
+ };
220
+
221
+ const report_errors =
222
+ (type: "error" | "warning") =>
223
+ (errors: IErrorReport[]): void => {
224
+ // key: file
225
+ // key: controller
226
+ // key: function
227
+ // value: message
228
+ const map: Map<string, Map<string, Map<string, Set<string>>>> = new Map();
229
+ for (const e of errors) {
230
+ const file = MapUtil.take(map, e.file, () => new Map());
231
+ const controller = MapUtil.take(file, e.controller, () => new Map());
232
+ const func = MapUtil.take(controller, e.function, () => new Set());
233
+ func.add(e.message);
234
+ }
235
+
236
+ console.log("");
237
+ print_title(`Nestia ${type[0].toUpperCase()}${type.slice(1)} Report`);
238
+ for (const [file, cMap] of map) {
239
+ for (const [controller, fMap] of cMap)
240
+ for (const [func, messages] of fMap) {
241
+ const location: string = path.relative(process.cwd(), file);
242
+ console.log(
243
+ `${location} - ${
244
+ func !== null ? `${controller}.${func}()` : controller
245
+ }`,
246
+ );
247
+ for (const msg of messages) console.log(` - ${msg}`);
248
+ console.log("");
249
+ }
250
+ }
251
+ };
252
+
253
+ const VARIABLE = /[a-zA-Z_$0-9]/;
@@ -1,60 +1,60 @@
1
- import { Escaper } from "typia/lib/utils/Escaper";
2
-
3
- import { IRoute } from "../structures/IRoute";
4
-
5
- export namespace AccessorAnalyzer {
6
- export const analyze = (routes: IRoute[]) => {
7
- shrink(routes);
8
- variable(routes);
9
- shrink(routes);
10
- for (const r of routes) r.name = r.accessors.at(-1) ?? r.name;
11
- };
12
-
13
- const prepare = (routeList: IRoute[]): Map<string, number> => {
14
- const dict: Map<string, number> = new Map();
15
- for (const route of routeList)
16
- route.accessors.forEach((_a, i) => {
17
- const key: string = route.accessors.slice(0, i + 1).join(".");
18
- dict.set(key, (dict.get(key) ?? 0) + 1);
19
- });
20
- return dict;
21
- };
22
-
23
- const variable = (routeList: IRoute[]) => {
24
- const dict: Map<string, number> = prepare(routeList);
25
- for (const route of routeList) {
26
- const emended: string[] = route.accessors.slice();
27
- route.accessors.forEach((accessor, i) => {
28
- if (Escaper.variable(accessor)) return;
29
- while (true) {
30
- accessor = "$" + accessor;
31
- const partial: string = [
32
- ...route.accessors.slice(0, i),
33
- accessor,
34
- ].join(".");
35
- if (dict.has(partial) === false) {
36
- emended[i] = accessor;
37
- break;
38
- }
39
- }
40
- });
41
- route.accessors.splice(0, route.accessors.length, ...emended);
42
- }
43
- };
44
-
45
- const shrink = (routeList: IRoute[]) => {
46
- const dict: Map<string, number> = prepare(routeList);
47
- for (const route of routeList) {
48
- if (
49
- route.accessors.length < 2 ||
50
- route.accessors.at(-1) !== route.accessors.at(-2)
51
- )
52
- continue;
53
-
54
- const cut: string[] = route.accessors.slice(0, -1);
55
- if ((dict.get(cut.join(".")) ?? 0) > 1) continue;
56
-
57
- route.accessors = cut;
58
- }
59
- };
60
- }
1
+ import { Escaper } from "typia/lib/utils/Escaper";
2
+
3
+ import { IRoute } from "../structures/IRoute";
4
+
5
+ export namespace AccessorAnalyzer {
6
+ export const analyze = (routes: IRoute[]) => {
7
+ shrink(routes);
8
+ variable(routes);
9
+ shrink(routes);
10
+ for (const r of routes) r.name = r.accessors.at(-1) ?? r.name;
11
+ };
12
+
13
+ const prepare = (routeList: IRoute[]): Map<string, number> => {
14
+ const dict: Map<string, number> = new Map();
15
+ for (const route of routeList)
16
+ route.accessors.forEach((_a, i) => {
17
+ const key: string = route.accessors.slice(0, i + 1).join(".");
18
+ dict.set(key, (dict.get(key) ?? 0) + 1);
19
+ });
20
+ return dict;
21
+ };
22
+
23
+ const variable = (routeList: IRoute[]) => {
24
+ const dict: Map<string, number> = prepare(routeList);
25
+ for (const route of routeList) {
26
+ const emended: string[] = route.accessors.slice();
27
+ route.accessors.forEach((accessor, i) => {
28
+ if (Escaper.variable(accessor)) return;
29
+ while (true) {
30
+ accessor = "$" + accessor;
31
+ const partial: string = [
32
+ ...route.accessors.slice(0, i),
33
+ accessor,
34
+ ].join(".");
35
+ if (dict.has(partial) === false) {
36
+ emended[i] = accessor;
37
+ break;
38
+ }
39
+ }
40
+ });
41
+ route.accessors.splice(0, route.accessors.length, ...emended);
42
+ }
43
+ };
44
+
45
+ const shrink = (routeList: IRoute[]) => {
46
+ const dict: Map<string, number> = prepare(routeList);
47
+ for (const route of routeList) {
48
+ if (
49
+ route.accessors.length < 2 ||
50
+ route.accessors.at(-1) !== route.accessors.at(-2)
51
+ )
52
+ continue;
53
+
54
+ const cut: string[] = route.accessors.slice(0, -1);
55
+ if ((dict.get(cut.join(".")) ?? 0) > 1) continue;
56
+
57
+ route.accessors = cut;
58
+ }
59
+ };
60
+ }