nestia 0.3.5 → 1.0.0
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/README.md +10 -9
- package/package.json +2 -3
- package/src/analyses/ControllerAnalyzer.ts +2 -0
- package/src/analyses/ReflectAnalyzer.ts +10 -4
- package/src/bin/nestia.ts +1 -5
- package/src/bundle/HttpError.ts +1 -33
- package/src/bundle/IConnection.ts +1 -26
- package/src/bundle/Primitive.ts +1 -113
- package/src/bundle/__internal/AesPkcs5.ts +1 -51
- package/src/bundle/__internal/Fetcher.ts +1 -126
- package/src/generates/FileGenerator.ts +20 -14
- package/src/generates/FunctionGenerator.ts +38 -28
- package/src/structures/IController.ts +1 -0
- package/src/utils/ImportDictionary.ts +5 -13
- package/tsconfig.json +1 -0
package/README.md
CHANGED
|
@@ -70,18 +70,19 @@ Just type the `nestia sdk <input> --out <output>` command in the console. If the
|
|
|
70
70
|
|
|
71
71
|
Also, when generating a SDK using the cli options, `compilerOptions` would follow the `tsconfig.json`, that is configured for the backend server. If no `tsconfig.json` file exists in your project, the configuration would be default option (`ES5` with `strict` mode). If you want to use different `compilerOptions` with the `tsconfig.json`, you should configure the [nestia.config.ts](#nestiaconfigts).
|
|
72
72
|
|
|
73
|
-
```bash
|
|
74
|
-
npx nestia install
|
|
75
|
-
```
|
|
76
|
-
|
|
77
73
|
### Dependencies
|
|
78
|
-
SDK library generated by the **Nestia**
|
|
79
|
-
|
|
80
|
-
When you type the `nestia install` command in the console, those dependencies would be automatically installed and enrolled to the `dependencies` and `devDependencies` fields in the `package.json`
|
|
74
|
+
SDK library generated by the **Nestia** requires the [nestia-fetcher](https://github.com/samchon/nestia-fetcher) module.
|
|
81
75
|
|
|
82
|
-
|
|
83
|
-
- [node-fetch](https://github.com/node-fetch/node-fetch)
|
|
76
|
+
Therefore, when you publish an SDK library generated by this **Nestia**, you have to write the [nestia-fetcher](https://github.com/samchon/nestia-fetcher) module into the `dependencies` property of the `package.json` file like below. You also can configure the `dependencies` property of the `package.json` file by typing the `npm install --save nestia-fetcher` command in the console, too.
|
|
84
77
|
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"name": "payments-server-api",
|
|
81
|
+
"dependencies": {
|
|
82
|
+
"nestia-fetcher": "^1.0.2"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
85
86
|
|
|
86
87
|
|
|
87
88
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nestia",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Automatic SDK and Document generator for the NestJS",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"bin": {
|
|
@@ -36,11 +36,10 @@
|
|
|
36
36
|
"del": "^6.0.0",
|
|
37
37
|
"ts-node": "^9.1.1",
|
|
38
38
|
"tstl": "^2.5.0",
|
|
39
|
-
"ttypescript": "^1.5.12",
|
|
40
39
|
"typescript": "^4.3.2"
|
|
41
40
|
},
|
|
42
41
|
"devDependencies": {
|
|
43
|
-
"
|
|
42
|
+
"nestia-helper": "^1.0.0",
|
|
44
43
|
"rimraf": "^3.0.2"
|
|
45
44
|
}
|
|
46
45
|
}
|
|
@@ -104,6 +104,8 @@ export namespace ControllerAnalyzer
|
|
|
104
104
|
let path: string = NodePath.join(controller.path, func.path).split("\\").join("/");
|
|
105
105
|
if (path[0] !== "/")
|
|
106
106
|
path = "/" + path;
|
|
107
|
+
if (path[path.length - 1] === "/" && path !== "/")
|
|
108
|
+
path = path.substr(0, path.length - 1);
|
|
107
109
|
|
|
108
110
|
// RETURNS
|
|
109
111
|
return {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Pather from "path";
|
|
2
2
|
|
|
3
3
|
import { ArrayUtil } from "../utils/ArrayUtil";
|
|
4
4
|
import { StringUtil } from "../utils/StringUtil";
|
|
@@ -128,7 +128,7 @@ export namespace ReflectAnalyzer
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
// VALIDATE PATH ARGUMENTS
|
|
131
|
-
const funcPathArguments: string[] = StringUtil.betweens(
|
|
131
|
+
const funcPathArguments: string[] = StringUtil.betweens(Pather.join(controller.path, meta.path).split("\\").join("/"), ":", "/").sort();
|
|
132
132
|
const paramPathArguments: string[] = meta.parameters.filter(param => param.category === "param").map(param => param.field!).sort();
|
|
133
133
|
|
|
134
134
|
if (equal(funcPathArguments, paramPathArguments) === false)
|
|
@@ -158,6 +158,7 @@ export namespace ReflectAnalyzer
|
|
|
158
158
|
return null;
|
|
159
159
|
|
|
160
160
|
return {
|
|
161
|
+
name: key,
|
|
161
162
|
category: type,
|
|
162
163
|
index: param.index,
|
|
163
164
|
field: param.data,
|
|
@@ -169,15 +170,19 @@ export namespace ReflectAnalyzer
|
|
|
169
170
|
{
|
|
170
171
|
if (param.factory === undefined)
|
|
171
172
|
return null;
|
|
172
|
-
else if (param.factory.name === "EncryptedBody")
|
|
173
|
+
else if (param.factory.name === "EncryptedBody" || param.factory.name === "PlainBody")
|
|
174
|
+
{
|
|
173
175
|
return {
|
|
174
176
|
category: "body",
|
|
175
177
|
index: param.index,
|
|
178
|
+
name: param.name,
|
|
176
179
|
field: param.data,
|
|
177
|
-
encrypted:
|
|
180
|
+
encrypted: param.factory.name === "EncryptedBody"
|
|
178
181
|
};
|
|
182
|
+
}
|
|
179
183
|
else if (param.factory.name === "TypedParam")
|
|
180
184
|
return {
|
|
185
|
+
name: param.name,
|
|
181
186
|
category: "param",
|
|
182
187
|
index: param.index,
|
|
183
188
|
field: param.data,
|
|
@@ -193,6 +198,7 @@ export namespace ReflectAnalyzer
|
|
|
193
198
|
|
|
194
199
|
interface INestParam
|
|
195
200
|
{
|
|
201
|
+
name: string;
|
|
196
202
|
index: number;
|
|
197
203
|
factory?: Function;
|
|
198
204
|
data: string | undefined;
|
package/src/bin/nestia.ts
CHANGED
|
@@ -78,11 +78,7 @@ async function sdk(input: string[], command: ICommand): Promise<void>
|
|
|
78
78
|
|
|
79
79
|
async function install(): Promise<void>
|
|
80
80
|
{
|
|
81
|
-
|
|
82
|
-
{
|
|
83
|
-
console.log(`installing ${module}...`);
|
|
84
|
-
await Terminal.execute(`npm install --save-dev ${module}`);
|
|
85
|
-
}
|
|
81
|
+
await Terminal.execute("npm install --save nestia-fetcher");
|
|
86
82
|
}
|
|
87
83
|
|
|
88
84
|
async function main(): Promise<void>
|
package/src/bundle/HttpError.ts
CHANGED
|
@@ -1,33 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* @packageDocumentation
|
|
3
|
-
* @module api
|
|
4
|
-
*/
|
|
5
|
-
//================================================================
|
|
6
|
-
/**
|
|
7
|
-
* HTTP Error from the backend server.
|
|
8
|
-
*
|
|
9
|
-
* @author Jeongho Nam - https://github.com/samchon
|
|
10
|
-
*/
|
|
11
|
-
export class HttpError extends Error
|
|
12
|
-
{
|
|
13
|
-
public readonly method: string;
|
|
14
|
-
public readonly path: string;
|
|
15
|
-
public readonly status: number;
|
|
16
|
-
|
|
17
|
-
public constructor(method: string, path: string, status: number, message: string)
|
|
18
|
-
{
|
|
19
|
-
super(message);
|
|
20
|
-
|
|
21
|
-
// INHERITANCE POLYFILL
|
|
22
|
-
const proto: HttpError = new.target.prototype;
|
|
23
|
-
if (Object.setPrototypeOf)
|
|
24
|
-
Object.setPrototypeOf(this, proto);
|
|
25
|
-
else
|
|
26
|
-
(this as any).__proto__ = proto;
|
|
27
|
-
|
|
28
|
-
// ASSIGN MEMBERS
|
|
29
|
-
this.method = method;
|
|
30
|
-
this.path = path;
|
|
31
|
-
this.status = status;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
1
|
+
export { HttpError } from "nestia-fetcher";
|
|
@@ -1,26 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* @packageDocumentation
|
|
3
|
-
* @module api
|
|
4
|
-
*/
|
|
5
|
-
//================================================================
|
|
6
|
-
export interface IConnection
|
|
7
|
-
{
|
|
8
|
-
host: string;
|
|
9
|
-
headers?: Record<string, string>;
|
|
10
|
-
encryption?: IConnection.IEncyptionPassword | IConnection.EncryptionClosure;
|
|
11
|
-
path?: (path: string) => string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export namespace IConnection
|
|
15
|
-
{
|
|
16
|
-
export interface IEncyptionPassword
|
|
17
|
-
{
|
|
18
|
-
key: string;
|
|
19
|
-
iv: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface EncryptionClosure
|
|
23
|
-
{
|
|
24
|
-
(content: string, isEncode: boolean): IEncyptionPassword;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
1
|
+
export { IConnection } from "nestia-fetcher";
|
package/src/bundle/Primitive.ts
CHANGED
|
@@ -1,113 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* @packageDocumentation
|
|
3
|
-
* @module api
|
|
4
|
-
*/
|
|
5
|
-
//================================================================
|
|
6
|
-
/**
|
|
7
|
-
* 객체의 원시 타입.
|
|
8
|
-
*
|
|
9
|
-
* `Primitive` 는 대상 인스턴스의 모든 메서드를 제거하여, 그 타입을 pritimive object 의 형태로
|
|
10
|
-
* 바꾸어주는 TMP (Type Meta Programming) 타입이다.
|
|
11
|
-
*
|
|
12
|
-
* @template Instance 대상 인스턴스
|
|
13
|
-
* @author Samchon
|
|
14
|
-
*/
|
|
15
|
-
export type Primitive<Instance> = value_of<Instance> extends object
|
|
16
|
-
? Instance extends object
|
|
17
|
-
? Instance extends IJsonable<infer Raw>
|
|
18
|
-
? value_of<Raw> extends object
|
|
19
|
-
? Raw extends object
|
|
20
|
-
? PrimitiveObject<Raw> // object would be primitified
|
|
21
|
-
: never // cannot be
|
|
22
|
-
: value_of<Raw> // atomic value
|
|
23
|
-
: PrimitiveObject<Instance> // object would be primitified
|
|
24
|
-
: never // cannot be
|
|
25
|
-
: value_of<Instance>;
|
|
26
|
-
|
|
27
|
-
export namespace Primitive
|
|
28
|
-
{
|
|
29
|
-
/**
|
|
30
|
-
* Primitive object 하드 카피.
|
|
31
|
-
*
|
|
32
|
-
* `Primitive.clone()` 은 파라미터 인스턴스를 원시 오브젝트 형태로 hard copy 하는 함수이다.
|
|
33
|
-
*
|
|
34
|
-
* @param instance 복사 대상 인스턴스
|
|
35
|
-
* @return 복사된 객체
|
|
36
|
-
*/
|
|
37
|
-
export function clone<Instance>(instance: Instance): Primitive<Instance>
|
|
38
|
-
{
|
|
39
|
-
return JSON.parse(JSON.stringify(instance));
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* @todo
|
|
44
|
-
*/
|
|
45
|
-
export function equal_to<Instance>(x: Instance, y: Instance): boolean
|
|
46
|
-
{
|
|
47
|
-
return JSON.stringify(x) === JSON.stringify(y) || recursive_equal_to(x, y);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
type PrimitiveObject<Instance extends object> = Instance extends Array<infer T>
|
|
52
|
-
? Primitive<T>[]
|
|
53
|
-
:
|
|
54
|
-
{
|
|
55
|
-
[P in keyof Instance]: Instance[P] extends Function
|
|
56
|
-
? never
|
|
57
|
-
: Primitive<Instance[P]>
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
type value_of<Instance> =
|
|
61
|
-
is_value_of<Instance, Boolean> extends true ? boolean
|
|
62
|
-
: is_value_of<Instance, Number> extends true ? number
|
|
63
|
-
: is_value_of<Instance, String> extends true ? string
|
|
64
|
-
: Instance;
|
|
65
|
-
|
|
66
|
-
type is_value_of<Instance, Object extends IValueOf<any>> =
|
|
67
|
-
Instance extends Object
|
|
68
|
-
? Object extends IValueOf<infer Primitive>
|
|
69
|
-
? Instance extends Primitive
|
|
70
|
-
? false
|
|
71
|
-
: true // not Primitive, but Object
|
|
72
|
-
: false // cannot be
|
|
73
|
-
: false;
|
|
74
|
-
|
|
75
|
-
interface IValueOf<T>
|
|
76
|
-
{
|
|
77
|
-
valueOf(): T;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
interface IJsonable<T>
|
|
81
|
-
{
|
|
82
|
-
toJSON(): T;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function object_equal_to<T extends object>(x: T, y: T): boolean
|
|
86
|
-
{
|
|
87
|
-
for (const key in x)
|
|
88
|
-
if (recursive_equal_to(x[key], y[key]) === false)
|
|
89
|
-
return false;
|
|
90
|
-
return true;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function array_equal_to<T>(x: T[], y: T[]): boolean
|
|
94
|
-
{
|
|
95
|
-
if (x.length !== y.length)
|
|
96
|
-
return false;
|
|
97
|
-
|
|
98
|
-
return x.every((value, index) => recursive_equal_to(value, y[index]));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function recursive_equal_to<T>(x: T, y: T): boolean
|
|
102
|
-
{
|
|
103
|
-
const type = typeof x;
|
|
104
|
-
if (type !== typeof y)
|
|
105
|
-
return false;
|
|
106
|
-
else if (type === "object")
|
|
107
|
-
if (x instanceof Array)
|
|
108
|
-
return array_equal_to(x, y as typeof x);
|
|
109
|
-
else
|
|
110
|
-
return object_equal_to(<any>x as object, <any>y as object);
|
|
111
|
-
else
|
|
112
|
-
return x === y;
|
|
113
|
-
}
|
|
1
|
+
export { Primitive } from "nestia-fetcher";
|
|
@@ -1,51 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* @packageDocumentation
|
|
3
|
-
* @module api.__internal
|
|
4
|
-
*/
|
|
5
|
-
//================================================================
|
|
6
|
-
import * as crypto from "crypto";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Utility class for AES Encryption.
|
|
10
|
-
*
|
|
11
|
-
* - AES-128/256
|
|
12
|
-
* - CBC mode
|
|
13
|
-
* - PKCS#5 Padding
|
|
14
|
-
* - Base64 Encoding
|
|
15
|
-
*
|
|
16
|
-
* @author Jeongho Nam - https://github.com/samchon
|
|
17
|
-
*/
|
|
18
|
-
export namespace AesPkcs5
|
|
19
|
-
{
|
|
20
|
-
/**
|
|
21
|
-
* Encode data
|
|
22
|
-
*
|
|
23
|
-
* @param data Target data
|
|
24
|
-
* @param key Key value of the encryption.
|
|
25
|
-
* @param iv Initializer Vector for the encryption
|
|
26
|
-
* @return Encoded data
|
|
27
|
-
*/
|
|
28
|
-
export function encode(data: string, key: string, iv: string): string
|
|
29
|
-
{
|
|
30
|
-
const bytes: number = key.length * 8;
|
|
31
|
-
const cipher: crypto.Cipher = crypto.createCipheriv(`AES-${bytes}-CBC`, key, iv);
|
|
32
|
-
|
|
33
|
-
return cipher.update(data, "utf8", "base64") + cipher.final("base64");
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Decode data.
|
|
38
|
-
*
|
|
39
|
-
* @param data Target data
|
|
40
|
-
* @param key Key value of the decryption.
|
|
41
|
-
* @param iv Initializer Vector for the decryption
|
|
42
|
-
* @return Decoded data.
|
|
43
|
-
*/
|
|
44
|
-
export function decode(data: string, key: string, iv: string): string
|
|
45
|
-
{
|
|
46
|
-
const bytes: number = key.length * 8;
|
|
47
|
-
const decipher: crypto.Decipher = crypto.createDecipheriv(`AES-${bytes}-CBC`, key, iv);
|
|
48
|
-
|
|
49
|
-
return decipher.update(data, "base64", "utf8") + decipher.final("utf8");
|
|
50
|
-
}
|
|
51
|
-
}
|
|
1
|
+
export { AesPkcs5 } from "nestia-fetcher";
|
|
@@ -1,126 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* @packageDocumentation
|
|
3
|
-
* @module api.__internal
|
|
4
|
-
*/
|
|
5
|
-
//================================================================
|
|
6
|
-
import { AesPkcs5 } from "./AesPkcs5";
|
|
7
|
-
import { HttpError } from "../HttpError";
|
|
8
|
-
import { IConnection } from "../IConnection";
|
|
9
|
-
import { Primitive } from "../Primitive";
|
|
10
|
-
|
|
11
|
-
// POLYFILL FOR NODE
|
|
12
|
-
if (typeof global === "object"
|
|
13
|
-
&& typeof global.process === "object"
|
|
14
|
-
&& typeof global.process.versions === "object"
|
|
15
|
-
&& typeof global.process.versions.node !== undefined)
|
|
16
|
-
(global as any).fetch = require("node-fetch");
|
|
17
|
-
|
|
18
|
-
export class Fetcher
|
|
19
|
-
{
|
|
20
|
-
public static fetch<Output>(connection: IConnection, config: Fetcher.IConfig, method: "GET" | "DELETE", path: string): Promise<Primitive<Output>>;
|
|
21
|
-
public static fetch<Input, Output>(connection: IConnection, config: Fetcher.IConfig, method: "POST" | "PUT" | "PATCH", path: string, input: Input): Promise<Primitive<Output>>;
|
|
22
|
-
|
|
23
|
-
public static async fetch<Output>
|
|
24
|
-
(
|
|
25
|
-
connection: IConnection,
|
|
26
|
-
config: Fetcher.IConfig,
|
|
27
|
-
method: string,
|
|
28
|
-
path: string,
|
|
29
|
-
input?: object
|
|
30
|
-
): Promise<Primitive<Output>>
|
|
31
|
-
{
|
|
32
|
-
if (config.input_encrypted === true || config.output_encrypted === true)
|
|
33
|
-
if (connection.encryption === undefined)
|
|
34
|
-
throw new Error("Error on nestia.Fetcher.encrypt(): the encryption password has not been configured.");
|
|
35
|
-
|
|
36
|
-
//----
|
|
37
|
-
// REQUEST MESSSAGE
|
|
38
|
-
//----
|
|
39
|
-
// METHOD & HEADERS
|
|
40
|
-
const init: RequestInit = {
|
|
41
|
-
method,
|
|
42
|
-
headers: config.input_encrypted === false && input !== undefined && typeof input === "object"
|
|
43
|
-
? {
|
|
44
|
-
...connection.headers,
|
|
45
|
-
"Content-Type": "application/json"
|
|
46
|
-
}
|
|
47
|
-
: connection.headers
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
// REQUEST BODY (WITH ENCRYPTION)
|
|
51
|
-
if (input !== undefined)
|
|
52
|
-
{
|
|
53
|
-
let content: string = JSON.stringify(input);
|
|
54
|
-
if (config.input_encrypted === true)
|
|
55
|
-
{
|
|
56
|
-
const password: IConnection.IEncyptionPassword = connection.encryption instanceof Function
|
|
57
|
-
? connection.encryption!(content, true)
|
|
58
|
-
: connection.encryption!;
|
|
59
|
-
content = AesPkcs5.encode(content, password.key, password.iv);
|
|
60
|
-
}
|
|
61
|
-
init.body = content;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
//----
|
|
65
|
-
// RESPONSE MESSAGE
|
|
66
|
-
//----
|
|
67
|
-
// URL SPECIFICATION
|
|
68
|
-
if (connection.host[connection.host.length - 1] !== "/" && path[0] !== "/")
|
|
69
|
-
path = "/" + path;
|
|
70
|
-
if (connection.path)
|
|
71
|
-
path = connection.path(path);
|
|
72
|
-
|
|
73
|
-
const url: URL = new URL(`${connection.host}${path}`);
|
|
74
|
-
|
|
75
|
-
// DO FETCH
|
|
76
|
-
const response: Response = await fetch(url.href, init);
|
|
77
|
-
let content: string = await response.text();
|
|
78
|
-
|
|
79
|
-
if (!content)
|
|
80
|
-
return undefined!;
|
|
81
|
-
|
|
82
|
-
// CHECK THE STATUS CODE
|
|
83
|
-
if (response.status !== 200 && response.status !== 201)
|
|
84
|
-
throw new HttpError(method, path, response.status, content);
|
|
85
|
-
|
|
86
|
-
// FINALIZATION (WITH DECODING)
|
|
87
|
-
if (config.output_encrypted === true)
|
|
88
|
-
{
|
|
89
|
-
const password: IConnection.IEncyptionPassword = connection.encryption instanceof Function
|
|
90
|
-
? connection.encryption!(content, false)
|
|
91
|
-
: connection.encryption!;
|
|
92
|
-
content = AesPkcs5.decode(content, password.key, password.iv);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
//----
|
|
96
|
-
// OUTPUT
|
|
97
|
-
//----
|
|
98
|
-
let ret: { __set_headers__: Record<string, any> } & Primitive<Output> = content as any;
|
|
99
|
-
try
|
|
100
|
-
{
|
|
101
|
-
// PARSE RESPONSE BODY
|
|
102
|
-
ret = JSON.parse(ret as any);
|
|
103
|
-
|
|
104
|
-
// FIND __SET_HEADERS__ FIELD
|
|
105
|
-
if (ret.__set_headers__ !== undefined && typeof ret.__set_headers__ === "object")
|
|
106
|
-
{
|
|
107
|
-
if (connection.headers === undefined)
|
|
108
|
-
connection.headers = {};
|
|
109
|
-
Object.assign(connection.headers, ret.__set_headers__);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
catch {}
|
|
113
|
-
|
|
114
|
-
// RETURNS
|
|
115
|
-
return ret;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export namespace Fetcher
|
|
120
|
-
{
|
|
121
|
-
export interface IConfig
|
|
122
|
-
{
|
|
123
|
-
input_encrypted?: boolean;
|
|
124
|
-
output_encrypted: boolean;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
1
|
+
export { Fetcher } from "nestia-fetcher";
|
|
@@ -2,7 +2,6 @@ import * as fs from "fs";
|
|
|
2
2
|
import { HashMap } from "tstl/container/HashMap";
|
|
3
3
|
|
|
4
4
|
import { IRoute } from "../structures/IRoute";
|
|
5
|
-
import { DirectoryUtil } from "../utils/DirectoryUtil";
|
|
6
5
|
import { ImportDictionary } from "../utils/ImportDictionary";
|
|
7
6
|
import { FunctionGenerator } from "./FunctionGenerator";
|
|
8
7
|
|
|
@@ -21,14 +20,8 @@ export namespace FileGenerator
|
|
|
21
20
|
// RELOCATE FOR ONLY ONE CONTROLLER METHOD IN AN URL CASE
|
|
22
21
|
relocate(root);
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
defaultImportDict.emplace(`${outDir}/__internal/Fetcher.ts`, true, "Fetcher");
|
|
27
|
-
defaultImportDict.emplace(`${outDir}/Primitive.ts`, true, "Primitive");
|
|
28
|
-
defaultImportDict.emplace(`${outDir}/IConnection.ts`, false, "IConnection");
|
|
29
|
-
|
|
30
|
-
await DirectoryUtil.remove(outDir + "/functional");
|
|
31
|
-
await iterate(defaultImportDict, outDir + "/functional", root);
|
|
23
|
+
// ITERATE FILES
|
|
24
|
+
await iterate(outDir + "/functional", root);
|
|
32
25
|
}
|
|
33
26
|
|
|
34
27
|
function emplace(directory: Directory, route: IRoute): void
|
|
@@ -70,7 +63,7 @@ export namespace FileGenerator
|
|
|
70
63
|
/* ---------------------------------------------------------
|
|
71
64
|
FILE ITERATOR
|
|
72
65
|
--------------------------------------------------------- */
|
|
73
|
-
async function iterate(
|
|
66
|
+
async function iterate(outDir: string, directory: Directory): Promise<void>
|
|
74
67
|
{
|
|
75
68
|
// CREATE A NEW DIRECTORY
|
|
76
69
|
try
|
|
@@ -83,7 +76,7 @@ export namespace FileGenerator
|
|
|
83
76
|
let content: string = "";
|
|
84
77
|
for (const it of directory.directories)
|
|
85
78
|
{
|
|
86
|
-
await iterate(
|
|
79
|
+
await iterate(`${outDir}/${it.first}`, it.second);
|
|
87
80
|
content += `export * as ${it.first} from "./${it.first}";\n`;
|
|
88
81
|
}
|
|
89
82
|
content += "\n";
|
|
@@ -100,10 +93,23 @@ export namespace FileGenerator
|
|
|
100
93
|
|
|
101
94
|
// FINALIZE THE CONTENT
|
|
102
95
|
if (directory.routes.length !== 0)
|
|
103
|
-
content =
|
|
104
|
-
+
|
|
96
|
+
content = ""
|
|
97
|
+
+ `import { AesPkcs5, Fetcher, Primitive } from "nestia-fetcher";\n`
|
|
98
|
+
+ `import type { IConnection } from "nestia-fetcher";\n`
|
|
99
|
+
+
|
|
100
|
+
(
|
|
101
|
+
importDict.empty()
|
|
102
|
+
? ""
|
|
103
|
+
: "\n" + importDict.toScript(outDir) + "\n"
|
|
104
|
+
)
|
|
105
105
|
+ content + "\n\n"
|
|
106
|
-
+
|
|
106
|
+
+ "//---------------------------------------------------------\n"
|
|
107
|
+
+ "// TO PREVENT THE UNUSED VARIABLE ERROR\n"
|
|
108
|
+
+ "//---------------------------------------------------------\n"
|
|
109
|
+
+ "AesPkcs5;\n"
|
|
110
|
+
+ "Fetcher;\n"
|
|
111
|
+
+ "Primitive;";
|
|
112
|
+
|
|
107
113
|
content = "/**\n"
|
|
108
114
|
+ " * @packageDocumentation\n"
|
|
109
115
|
+ ` * @module ${directory.module}\n`
|
|
@@ -2,7 +2,6 @@ import type * as tsc from "typescript";
|
|
|
2
2
|
import { Pair } from "tstl/utility/Pair";
|
|
3
3
|
import { Vector } from "tstl/container/Vector";
|
|
4
4
|
|
|
5
|
-
import { Fetcher } from "../bundle/__internal/Fetcher";
|
|
6
5
|
import { IRoute } from "../structures/IRoute";
|
|
7
6
|
|
|
8
7
|
export namespace FunctionGenerator
|
|
@@ -23,25 +22,17 @@ export namespace FunctionGenerator
|
|
|
23
22
|
--------------------------------------------------------- */
|
|
24
23
|
function body(route: IRoute, query: IRoute.IParameter | undefined, input: IRoute.IParameter | undefined): string
|
|
25
24
|
{
|
|
26
|
-
// PATH WITH ENCRYPTION
|
|
27
|
-
const path: string = get_path(route, query);
|
|
28
|
-
const config: Fetcher.IConfig = {
|
|
29
|
-
input_encrypted: input !== undefined && input.encrypted,
|
|
30
|
-
output_encrypted: route.encrypted
|
|
31
|
-
};
|
|
32
|
-
|
|
33
25
|
// FETCH ARGUMENTS WITH REQUST BODY
|
|
26
|
+
const parameters = filter_parameters(route, query);
|
|
34
27
|
const fetchArguments: string[] =
|
|
35
28
|
[
|
|
36
29
|
"connection",
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
`"${route.method}"`,
|
|
41
|
-
path
|
|
30
|
+
`${route.name}.ENCRYPTED`,
|
|
31
|
+
`${route.name}.METHOD`,
|
|
32
|
+
`${route.name}.path(${parameters.map(p => p.name).join(", ")})`
|
|
42
33
|
];
|
|
43
34
|
if (input !== undefined)
|
|
44
|
-
fetchArguments.push(
|
|
35
|
+
fetchArguments.push(input.name);
|
|
45
36
|
|
|
46
37
|
// RETURNS WITH FINALIZATION
|
|
47
38
|
return "{\n"
|
|
@@ -52,18 +43,12 @@ export namespace FunctionGenerator
|
|
|
52
43
|
+ "}";
|
|
53
44
|
}
|
|
54
45
|
|
|
55
|
-
function
|
|
46
|
+
function filter_parameters(route: IRoute, query: IRoute.IParameter | undefined): IRoute.IParameter[]
|
|
56
47
|
{
|
|
57
48
|
const parameters = route.parameters.filter(param => param.category === "param");
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
path = path.replace(`:${param.field}`, `\${${param.name}}`);
|
|
62
|
-
|
|
63
|
-
new URLSearchParams()
|
|
64
|
-
return (query !== undefined)
|
|
65
|
-
? `\`${path}?\${new URLSearchParams(${query.name} as any).toString()}\``
|
|
66
|
-
: `\`${path}\``
|
|
49
|
+
if (query)
|
|
50
|
+
parameters.push(query);
|
|
51
|
+
return parameters;
|
|
67
52
|
}
|
|
68
53
|
|
|
69
54
|
/* ---------------------------------------------------------
|
|
@@ -149,6 +134,7 @@ export namespace FunctionGenerator
|
|
|
149
134
|
|
|
150
135
|
function tail(route: IRoute, query: IRoute.IParameter | undefined, input: IRoute.IParameter | undefined): string | null
|
|
151
136
|
{
|
|
137
|
+
// LIST UP TYPES
|
|
152
138
|
const types: Pair<string, string>[] = [];
|
|
153
139
|
if (query !== undefined)
|
|
154
140
|
types.push(new Pair("Query", query.type));
|
|
@@ -157,12 +143,36 @@ export namespace FunctionGenerator
|
|
|
157
143
|
if (route.output !== "void")
|
|
158
144
|
types.push(new Pair("Output", route.output));
|
|
159
145
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
146
|
+
// PATH WITH PARAMETERS
|
|
147
|
+
const parameters = filter_parameters(route, query);
|
|
148
|
+
let path: string = route.path;
|
|
149
|
+
for (const param of parameters)
|
|
150
|
+
if (param.category === "param")
|
|
151
|
+
path = path.replace(`:${param.field}`, `\${${param.name}}`);
|
|
152
|
+
path = (query !== undefined)
|
|
153
|
+
? `\`${path}?\${new URLSearchParams(${query.name} as any).toString()}\``
|
|
154
|
+
: `\`${path}\``;
|
|
155
|
+
|
|
163
156
|
return `export namespace ${route.name}\n`
|
|
164
157
|
+ "{\n"
|
|
165
|
-
+
|
|
158
|
+
+
|
|
159
|
+
(
|
|
160
|
+
types.length !== 0
|
|
161
|
+
? types.map(tuple => ` export type ${tuple.first} = Primitive<${tuple.second}>;`).join("\n") + "\n"
|
|
162
|
+
: ""
|
|
163
|
+
)
|
|
164
|
+
+ "\n"
|
|
165
|
+
+ ` export const METHOD = "${route.method}" as const;\n`
|
|
166
|
+
+ ` export const PATH: string = "${route.path}";\n`
|
|
167
|
+
+ ` export const ENCRYPTED: Fetcher.IEncrypted = {\n`
|
|
168
|
+
+ ` request: ${input !== undefined && input.encrypted},\n`
|
|
169
|
+
+ ` response: ${route.encrypted},\n`
|
|
170
|
+
+ ` };\n`
|
|
171
|
+
+ "\n"
|
|
172
|
+
+ ` export function path(${parameters.map(param => `${param.name}: ${param.type}`).join(", ")}): string\n`
|
|
173
|
+
+ ` {\n`
|
|
174
|
+
+ ` return ${path};\n`
|
|
175
|
+
+ ` }\n`
|
|
166
176
|
+ "}";
|
|
167
177
|
}
|
|
168
178
|
}
|
|
@@ -8,6 +8,11 @@ export class ImportDictionary
|
|
|
8
8
|
{
|
|
9
9
|
private readonly dict_: HashMap<string, Pair<boolean, HashSet<string>>> = new HashMap();
|
|
10
10
|
|
|
11
|
+
public empty(): boolean
|
|
12
|
+
{
|
|
13
|
+
return this.dict_.empty();
|
|
14
|
+
}
|
|
15
|
+
|
|
11
16
|
public emplace(file: string, realistic: boolean, instance: string): void
|
|
12
17
|
{
|
|
13
18
|
if (file.substr(-5) === ".d.ts")
|
|
@@ -36,17 +41,4 @@ export class ImportDictionary
|
|
|
36
41
|
}
|
|
37
42
|
return statements.join("\n");
|
|
38
43
|
}
|
|
39
|
-
|
|
40
|
-
public listUp(): string
|
|
41
|
-
{
|
|
42
|
-
let content: string = ""
|
|
43
|
-
+ "//---------------------------------------------------------\n"
|
|
44
|
-
+ "// TO PREVENT THE UNUSED VARIABLE ERROR\n"
|
|
45
|
-
+ "//---------------------------------------------------------\n";
|
|
46
|
-
for (const it of this.dict_)
|
|
47
|
-
if (it.second.first === true)
|
|
48
|
-
for (const instance of it.second.second)
|
|
49
|
-
content += instance + ";\n";
|
|
50
|
-
return content;
|
|
51
|
-
}
|
|
52
44
|
}
|
package/tsconfig.json
CHANGED
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
/* Experimental Options */
|
|
69
69
|
"experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
|
70
70
|
"emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
|
71
|
+
"stripInternal": true,
|
|
71
72
|
|
|
72
73
|
/* Advanced Options */
|
|
73
74
|
"skipLibCheck": true, /* Skip type checking of declaration files. */
|