@nestia/sdk 2.3.0-dev.20231018-4 → 2.3.0-dev.20231019
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.
- package/assets/config/nestia.config.ts +13 -7
- package/lib/INestiaConfig.d.ts +8 -8
- package/lib/NestiaSdkApplication.d.ts +0 -2
- package/lib/NestiaSdkApplication.js +3 -42
- package/lib/NestiaSdkApplication.js.map +1 -1
- package/lib/analyses/ConfigAnalyzer.d.ts +2 -1
- package/lib/analyses/ConfigAnalyzer.js +97 -42
- package/lib/analyses/ConfigAnalyzer.js.map +1 -1
- package/lib/analyses/ControllerAnalyzer.d.ts +1 -1
- package/lib/analyses/ControllerAnalyzer.js +39 -24
- package/lib/analyses/ControllerAnalyzer.js.map +1 -1
- package/lib/analyses/PathAnalyzer.d.ts +2 -2
- package/lib/analyses/PathAnalyzer.js +19 -1
- package/lib/analyses/PathAnalyzer.js.map +1 -1
- package/lib/analyses/ReflectAnalyzer.d.ts +1 -1
- package/lib/analyses/ReflectAnalyzer.js +8 -5
- package/lib/analyses/ReflectAnalyzer.js.map +1 -1
- package/lib/executable/internal/NestiaConfigLoader.js +97 -97
- package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
- package/lib/generates/E2eGenerator.js +1 -1
- package/lib/generates/E2eGenerator.js.map +1 -1
- package/lib/generates/SwaggerGenerator.js +1 -2
- package/lib/generates/SwaggerGenerator.js.map +1 -1
- package/lib/structures/IController.d.ts +1 -0
- package/lib/structures/INormalizedInput.d.ts +19 -0
- package/lib/structures/INormalizedInput.js +3 -0
- package/lib/structures/INormalizedInput.js.map +1 -0
- package/lib/utils/SourceFinder.d.ts +7 -7
- package/lib/utils/SourceFinder.js +2 -2
- package/lib/utils/SourceFinder.js.map +1 -1
- package/package.json +4 -4
- package/src/INestiaConfig.ts +17 -36
- package/src/NestiaSdkApplication.ts +15 -67
- package/src/analyses/ConfigAnalyzer.ts +131 -46
- package/src/analyses/ControllerAnalyzer.ts +32 -19
- package/src/analyses/PathAnalyzer.ts +22 -3
- package/src/analyses/ReflectAnalyzer.ts +8 -2
- package/src/executable/internal/NestiaConfigLoader.ts +3 -1
- package/src/generates/E2eGenerator.ts +1 -1
- package/src/generates/SwaggerGenerator.ts +4 -8
- package/src/structures/IController.ts +1 -0
- package/src/structures/INormalizedInput.ts +20 -0
- package/src/utils/SourceFinder.ts +11 -10
|
@@ -7,9 +7,11 @@ import { CommentFactory } from "typia/lib/factories/CommentFactory";
|
|
|
7
7
|
|
|
8
8
|
import { INestiaConfig } from "../INestiaConfig";
|
|
9
9
|
import { IController } from "../structures/IController";
|
|
10
|
+
import { INormalizedInput } from "../structures/INormalizedInput";
|
|
10
11
|
import { IRoute } from "../structures/IRoute";
|
|
11
12
|
import { ITypeTuple } from "../structures/ITypeTuple";
|
|
12
13
|
import { PathUtil } from "../utils/PathUtil";
|
|
14
|
+
import { ConfigAnalyzer } from "./ConfigAnalyzer";
|
|
13
15
|
import { ExceptionAnalyzer } from "./ExceptionAnalyzer";
|
|
14
16
|
import { GenericAnalyzer } from "./GenericAnalyzer";
|
|
15
17
|
import { ImportAnalyzer } from "./ImportAnalyzer";
|
|
@@ -17,14 +19,16 @@ import { PathAnalyzer } from "./PathAnalyzer";
|
|
|
17
19
|
import { SecurityAnalyzer } from "./SecurityAnalyzer";
|
|
18
20
|
|
|
19
21
|
export namespace ControllerAnalyzer {
|
|
20
|
-
export function analyze(
|
|
22
|
+
export async function analyze(
|
|
21
23
|
config: INestiaConfig,
|
|
22
24
|
checker: ts.TypeChecker,
|
|
23
25
|
sourceFile: ts.SourceFile,
|
|
24
26
|
controller: IController,
|
|
25
|
-
): IRoute[] {
|
|
27
|
+
): Promise<IRoute[]> {
|
|
26
28
|
// FIND CONTROLLER CLASS
|
|
29
|
+
const input: INormalizedInput = await ConfigAnalyzer.input(config);
|
|
27
30
|
const ret: IRoute[] = [];
|
|
31
|
+
|
|
28
32
|
ts.forEachChild(sourceFile, (node) => {
|
|
29
33
|
if (
|
|
30
34
|
ts.isClassDeclaration(node) &&
|
|
@@ -32,7 +36,13 @@ export namespace ControllerAnalyzer {
|
|
|
32
36
|
) {
|
|
33
37
|
// ANALYZE THE CONTROLLER
|
|
34
38
|
ret.push(
|
|
35
|
-
..._Analyze_controller(
|
|
39
|
+
..._Analyze_controller(
|
|
40
|
+
config,
|
|
41
|
+
input,
|
|
42
|
+
checker,
|
|
43
|
+
controller,
|
|
44
|
+
node,
|
|
45
|
+
),
|
|
36
46
|
);
|
|
37
47
|
return;
|
|
38
48
|
}
|
|
@@ -45,6 +55,7 @@ export namespace ControllerAnalyzer {
|
|
|
45
55
|
--------------------------------------------------------- */
|
|
46
56
|
function _Analyze_controller(
|
|
47
57
|
config: INestiaConfig,
|
|
58
|
+
input: INormalizedInput,
|
|
48
59
|
checker: ts.TypeChecker,
|
|
49
60
|
controller: IController,
|
|
50
61
|
classNode: ts.ClassDeclaration,
|
|
@@ -77,6 +88,7 @@ export namespace ControllerAnalyzer {
|
|
|
77
88
|
|
|
78
89
|
const routes: IRoute[] = _Analyze_function(
|
|
79
90
|
config,
|
|
91
|
+
input,
|
|
80
92
|
checker,
|
|
81
93
|
controller,
|
|
82
94
|
genericDict,
|
|
@@ -94,6 +106,7 @@ export namespace ControllerAnalyzer {
|
|
|
94
106
|
--------------------------------------------------------- */
|
|
95
107
|
function _Analyze_function(
|
|
96
108
|
config: INestiaConfig,
|
|
109
|
+
input: INormalizedInput,
|
|
97
110
|
checker: ts.TypeChecker,
|
|
98
111
|
controller: IController,
|
|
99
112
|
genericDict: GenericAnalyzer.Dictionary,
|
|
@@ -115,9 +128,8 @@ export namespace ControllerAnalyzer {
|
|
|
115
128
|
`Error on ControllerAnalyzer.analyze(): unable to get the signature from the ${controller.name}.${func.name}().`,
|
|
116
129
|
);
|
|
117
130
|
|
|
118
|
-
const importDict: ImportAnalyzer.Dictionary = new HashMap();
|
|
119
|
-
|
|
120
131
|
// EXPLORE CHILDREN TYPES
|
|
132
|
+
const importDict: ImportAnalyzer.Dictionary = new HashMap();
|
|
121
133
|
const parameters: IRoute.IParameter[] = func.parameters.map((param) =>
|
|
122
134
|
_Analyze_parameter(
|
|
123
135
|
checker,
|
|
@@ -205,7 +217,7 @@ export namespace ControllerAnalyzer {
|
|
|
205
217
|
description: CommentFactory.description(symbol),
|
|
206
218
|
operationId: jsDocTags
|
|
207
219
|
.find(({ name }) => name === "operationId")
|
|
208
|
-
?.text
|
|
220
|
+
?.text?.[0].text.split(" ")[0]
|
|
209
221
|
.trim(),
|
|
210
222
|
jsDocTags: jsDocTags,
|
|
211
223
|
setHeaders: jsDocTags
|
|
@@ -232,22 +244,23 @@ export namespace ControllerAnalyzer {
|
|
|
232
244
|
};
|
|
233
245
|
|
|
234
246
|
// CONFIGURE PATHS
|
|
235
|
-
const input: INestiaConfig.IInput =
|
|
236
|
-
config.input as INestiaConfig.IInput;
|
|
237
247
|
const pathList: Set<string> = new Set();
|
|
238
248
|
const versions: Array<string | null> = _Analyze_versions(
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
249
|
+
input.versioning === undefined
|
|
250
|
+
? undefined
|
|
251
|
+
: func.versions ??
|
|
252
|
+
controller.versions ??
|
|
253
|
+
(input.versioning?.defaultVersion !== undefined
|
|
254
|
+
? Array.isArray(input.versioning?.defaultVersion)
|
|
255
|
+
? input.versioning?.defaultVersion
|
|
256
|
+
: [input.versioning?.defaultVersion]
|
|
257
|
+
: undefined) ??
|
|
258
|
+
undefined,
|
|
247
259
|
);
|
|
248
|
-
for (const
|
|
249
|
-
for (const
|
|
250
|
-
|
|
260
|
+
for (const prefix of controller.prefixes)
|
|
261
|
+
for (const cPath of controller.paths)
|
|
262
|
+
for (const filePath of func.paths)
|
|
263
|
+
pathList.add(PathAnalyzer.join(prefix, cPath, filePath));
|
|
251
264
|
|
|
252
265
|
return [...pathList]
|
|
253
266
|
.map((individual) =>
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import { RequestMethod } from "@nestjs/common";
|
|
1
2
|
import path from "path";
|
|
2
3
|
import { Token, parse } from "path-to-regexp";
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
+
import { INormalizedInput } from "../structures/INormalizedInput";
|
|
5
6
|
|
|
6
7
|
export namespace PathAnalyzer {
|
|
7
8
|
export const combinate =
|
|
8
|
-
(globalPrefix:
|
|
9
|
+
(globalPrefix: INormalizedInput["globalPrefix"]) =>
|
|
9
10
|
(versions: Array<string | null>) =>
|
|
10
11
|
(props: { path: string; method: string }): string[] => {
|
|
11
12
|
const out = (str: string) =>
|
|
@@ -18,7 +19,7 @@ export namespace PathAnalyzer {
|
|
|
18
19
|
return globalPrefix.exclude.some((exclude) =>
|
|
19
20
|
typeof exclude === "string"
|
|
20
21
|
? RegExp(exclude).test(props.path)
|
|
21
|
-
: (exclude.method
|
|
22
|
+
: METHOD(exclude.method) === props.method &&
|
|
22
23
|
RegExp(exclude.path).test(props.path),
|
|
23
24
|
)
|
|
24
25
|
? out(props.path)
|
|
@@ -79,3 +80,21 @@ export namespace PathAnalyzer {
|
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
const ERROR_MESSAGE = "nestia supports only string typed parameter on path";
|
|
83
|
+
const METHOD = (value: RequestMethod) =>
|
|
84
|
+
value === RequestMethod.ALL
|
|
85
|
+
? "all"
|
|
86
|
+
: value === RequestMethod.DELETE
|
|
87
|
+
? "delete"
|
|
88
|
+
: value === RequestMethod.GET
|
|
89
|
+
? "get"
|
|
90
|
+
: value === RequestMethod.HEAD
|
|
91
|
+
? "head"
|
|
92
|
+
: value === RequestMethod.OPTIONS
|
|
93
|
+
? "options"
|
|
94
|
+
: value === RequestMethod.PATCH
|
|
95
|
+
? "patch"
|
|
96
|
+
: value === RequestMethod.POST
|
|
97
|
+
? "post"
|
|
98
|
+
: value === RequestMethod.PUT
|
|
99
|
+
? "put"
|
|
100
|
+
: "unknown";
|
|
@@ -17,6 +17,8 @@ export namespace ReflectAnalyzer {
|
|
|
17
17
|
export async function analyze(
|
|
18
18
|
unique: WeakSet<any>,
|
|
19
19
|
file: string,
|
|
20
|
+
prefixes: string[],
|
|
21
|
+
target?: Function,
|
|
20
22
|
): Promise<IController[]> {
|
|
21
23
|
const module: IModule = await (async () => {
|
|
22
24
|
try {
|
|
@@ -37,14 +39,16 @@ export namespace ReflectAnalyzer {
|
|
|
37
39
|
|
|
38
40
|
for (const [key, value] of Object.entries(module)) {
|
|
39
41
|
if (typeof value !== "function" || unique.has(value)) continue;
|
|
42
|
+
else if ((target ?? value) !== value) continue;
|
|
40
43
|
else unique.add(value);
|
|
41
44
|
|
|
42
|
-
const
|
|
45
|
+
const result: IController | null = _Analyze_controller(
|
|
43
46
|
file,
|
|
44
47
|
key,
|
|
45
48
|
value,
|
|
49
|
+
prefixes,
|
|
46
50
|
);
|
|
47
|
-
if (
|
|
51
|
+
if (result !== null) ret.push(result);
|
|
48
52
|
}
|
|
49
53
|
return ret;
|
|
50
54
|
}
|
|
@@ -56,6 +60,7 @@ export namespace ReflectAnalyzer {
|
|
|
56
60
|
file: string,
|
|
57
61
|
name: string,
|
|
58
62
|
creator: any,
|
|
63
|
+
prefixes: string[],
|
|
59
64
|
): IController | null {
|
|
60
65
|
//----
|
|
61
66
|
// VALIDATIONS
|
|
@@ -87,6 +92,7 @@ export namespace ReflectAnalyzer {
|
|
|
87
92
|
file,
|
|
88
93
|
name,
|
|
89
94
|
functions: [],
|
|
95
|
+
prefixes,
|
|
90
96
|
paths: _Get_paths(creator),
|
|
91
97
|
versions: _Get_versions(creator),
|
|
92
98
|
security: _Get_securities(creator),
|
|
@@ -71,7 +71,9 @@ export namespace NestiaConfigLoader {
|
|
|
71
71
|
export const project = async (file: string): Promise<string> => {
|
|
72
72
|
const connector = new WorkerConnector(null, null, "process");
|
|
73
73
|
await connector.connect(
|
|
74
|
-
`${__dirname}/nestia.project.getter.${__filename.
|
|
74
|
+
`${__dirname}/nestia.project.getter.${__filename.substring(
|
|
75
|
+
__filename.length - 2,
|
|
76
|
+
)}`,
|
|
75
77
|
);
|
|
76
78
|
|
|
77
79
|
const driver = await connector.getDriver<typeof NestiaProjectGetter>();
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
|
-
import NodePath from "path";
|
|
3
2
|
import path from "path";
|
|
4
3
|
import { Singleton } from "tstl/thread/Singleton";
|
|
5
4
|
import ts from "typescript";
|
|
@@ -41,8 +40,8 @@ export namespace SwaggerGenerator {
|
|
|
41
40
|
validate_security(config)(routeList);
|
|
42
41
|
|
|
43
42
|
// PREPARE ASSETS
|
|
44
|
-
const parsed:
|
|
45
|
-
const directory: string =
|
|
43
|
+
const parsed: path.ParsedPath = path.parse(config.output);
|
|
44
|
+
const directory: string = path.dirname(parsed.dir);
|
|
46
45
|
if (fs.existsSync(directory) === false)
|
|
47
46
|
try {
|
|
48
47
|
await fs.promises.mkdir(directory);
|
|
@@ -53,11 +52,8 @@ export namespace SwaggerGenerator {
|
|
|
53
52
|
);
|
|
54
53
|
|
|
55
54
|
const location: string = !!parsed.ext
|
|
56
|
-
?
|
|
57
|
-
:
|
|
58
|
-
NodePath.resolve(config.output),
|
|
59
|
-
"swagger.json",
|
|
60
|
-
);
|
|
55
|
+
? path.resolve(config.output)
|
|
56
|
+
: path.join(path.resolve(config.output), "swagger.json");
|
|
61
57
|
|
|
62
58
|
const collection: MetadataCollection = new MetadataCollection({
|
|
63
59
|
replace: MetadataCollection.replace,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { RouteInfo, VersionValue } from "@nestjs/common/interfaces";
|
|
2
|
+
|
|
3
|
+
export interface INormalizedInput {
|
|
4
|
+
include: INormalizedInput.IInput[];
|
|
5
|
+
globalPrefix?: {
|
|
6
|
+
prefix: string;
|
|
7
|
+
exclude?: Array<string | RouteInfo>;
|
|
8
|
+
};
|
|
9
|
+
versioning?: {
|
|
10
|
+
prefix: string;
|
|
11
|
+
defaultVersion?: VersionValue;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export namespace INormalizedInput {
|
|
15
|
+
export interface IInput {
|
|
16
|
+
paths: string[];
|
|
17
|
+
file: string;
|
|
18
|
+
controller?: Function;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -3,6 +3,12 @@ import glob from "glob";
|
|
|
3
3
|
import path from "path";
|
|
4
4
|
|
|
5
5
|
export namespace SourceFinder {
|
|
6
|
+
interface IProps {
|
|
7
|
+
exclude?: string[];
|
|
8
|
+
include: string[];
|
|
9
|
+
filter: (location: string) => Promise<boolean>;
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
export const find = async (props: IProps): Promise<string[]> => {
|
|
7
13
|
const dict: Set<string> = new Set();
|
|
8
14
|
|
|
@@ -16,7 +22,7 @@ export namespace SourceFinder {
|
|
|
16
22
|
};
|
|
17
23
|
|
|
18
24
|
const emplace =
|
|
19
|
-
(filter: (file: string) => boolean) =>
|
|
25
|
+
(filter: (file: string) => Promise<boolean>) =>
|
|
20
26
|
(input: string[]) =>
|
|
21
27
|
async (closure: (location: string) => void): Promise<void> => {
|
|
22
28
|
for (const pattern of input) {
|
|
@@ -28,13 +34,14 @@ export namespace SourceFinder {
|
|
|
28
34
|
const stats: fs.Stats = await fs.promises.stat(file);
|
|
29
35
|
if (stats.isDirectory() === true)
|
|
30
36
|
await iterate(filter)(closure)(file);
|
|
31
|
-
else if (stats.isFile() && filter(file))
|
|
37
|
+
else if (stats.isFile() && (await filter(file)))
|
|
38
|
+
closure(file);
|
|
32
39
|
}
|
|
33
40
|
}
|
|
34
41
|
};
|
|
35
42
|
|
|
36
43
|
const iterate =
|
|
37
|
-
(filter: (location: string) => boolean) =>
|
|
44
|
+
(filter: (location: string) => Promise<boolean>) =>
|
|
38
45
|
(closure: (location: string) => void) =>
|
|
39
46
|
async (location: string): Promise<void> => {
|
|
40
47
|
const directory: string[] = await fs.promises.readdir(location);
|
|
@@ -44,7 +51,7 @@ export namespace SourceFinder {
|
|
|
44
51
|
|
|
45
52
|
if (stats.isDirectory() === true)
|
|
46
53
|
await iterate(filter)(closure)(next);
|
|
47
|
-
else if (stats.isFile() && filter(next)) closure(next);
|
|
54
|
+
else if (stats.isFile() && (await filter(next))) closure(next);
|
|
48
55
|
}
|
|
49
56
|
};
|
|
50
57
|
|
|
@@ -61,9 +68,3 @@ export namespace SourceFinder {
|
|
|
61
68
|
!pattern.endsWith(".d.ts") &&
|
|
62
69
|
fs.existsSync(pattern);
|
|
63
70
|
}
|
|
64
|
-
|
|
65
|
-
interface IProps {
|
|
66
|
-
exclude?: string[];
|
|
67
|
-
include: string[];
|
|
68
|
-
filter: (location: string) => boolean;
|
|
69
|
-
}
|