@nestia/sdk 1.6.7 → 2.0.0-dev.20230830
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/lib/generates/E2eGenerator.js +2 -1
- package/lib/generates/E2eGenerator.js.map +1 -1
- package/lib/generates/internal/E2eFileProgrammer.d.ts +2 -1
- package/lib/generates/internal/E2eFileProgrammer.js +30 -19
- package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkFileProgrammer.js +14 -30
- package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkFunctionProgrammer.d.ts +2 -1
- package/lib/generates/internal/SdkFunctionProgrammer.js +72 -26
- package/lib/generates/internal/SdkFunctionProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkSimulationProgrammer.d.ts +3 -1
- package/lib/generates/internal/SdkSimulationProgrammer.js +42 -24
- package/lib/generates/internal/SdkSimulationProgrammer.js.map +1 -1
- package/lib/utils/ImportDictionary.d.ts +16 -2
- package/lib/utils/ImportDictionary.js +66 -25
- package/lib/utils/ImportDictionary.js.map +1 -1
- package/package.json +3 -3
- package/src/generates/E2eGenerator.ts +4 -1
- package/src/generates/internal/E2eFileProgrammer.ts +36 -19
- package/src/generates/internal/SdkFileProgrammer.ts +20 -56
- package/src/generates/internal/SdkFunctionProgrammer.ts +85 -24
- package/src/generates/internal/SdkSimulationProgrammer.ts +107 -73
- package/src/utils/ImportDictionary.ts +97 -33
|
@@ -1,79 +1,113 @@
|
|
|
1
|
+
import { INestiaConfig } from "../../INestiaConfig";
|
|
1
2
|
import { IRoute } from "../../structures/IRoute";
|
|
3
|
+
import { ImportDictionary } from "../../utils/ImportDictionary";
|
|
2
4
|
|
|
3
5
|
export namespace SdkSimulationProgrammer {
|
|
4
|
-
export const generate =
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
6
|
+
export const generate =
|
|
7
|
+
(config: INestiaConfig) =>
|
|
8
|
+
(importer: ImportDictionary) =>
|
|
9
|
+
(route: IRoute): string => {
|
|
10
|
+
const output: boolean = route.output.name !== "void";
|
|
11
|
+
const returns = () => [
|
|
12
|
+
`return random(`,
|
|
13
|
+
` typeof connection.simulate === 'object' &&`,
|
|
14
|
+
` connection.simulate !== null`,
|
|
15
|
+
` ? connection.simulate`,
|
|
16
|
+
` : undefined`,
|
|
17
|
+
`);`,
|
|
18
|
+
];
|
|
19
|
+
const body: string[] = [
|
|
20
|
+
...(route.parameters.filter((p) => p.category !== "headers")
|
|
21
|
+
.length !== 0
|
|
22
|
+
? assert(config)(importer)(route.parameters)
|
|
23
|
+
: []),
|
|
24
|
+
...(output ? returns() : []),
|
|
25
|
+
];
|
|
26
|
+
const connectionType: string = importer.external({
|
|
27
|
+
type: true,
|
|
28
|
+
library: "@nestia/fetcher",
|
|
29
|
+
instance: "IConnection",
|
|
30
|
+
});
|
|
21
31
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
.
|
|
38
|
-
|
|
39
|
-
(
|
|
40
|
-
|
|
41
|
-
p.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
32
|
+
return [
|
|
33
|
+
`export const simulate = async (`,
|
|
34
|
+
` ${
|
|
35
|
+
route.parameters.filter((p) => p.category !== "headers")
|
|
36
|
+
.length === 0 && route.output.name === "void"
|
|
37
|
+
? "_connection"
|
|
38
|
+
: "connection"
|
|
39
|
+
}: ${
|
|
40
|
+
route.parameters.some(
|
|
41
|
+
(p) =>
|
|
42
|
+
p.category === "headers" && p.field === undefined,
|
|
43
|
+
)
|
|
44
|
+
? `${connectionType}<${route.name}.Headers>`
|
|
45
|
+
: connectionType
|
|
46
|
+
},`,
|
|
47
|
+
...route.parameters
|
|
48
|
+
.filter((p) => p.category !== "headers")
|
|
49
|
+
.map(
|
|
50
|
+
(p) =>
|
|
51
|
+
` ${p.name}: ${
|
|
52
|
+
p.category === "query" || p.category === "body"
|
|
53
|
+
? `${route.name}.${
|
|
54
|
+
p.category === "query"
|
|
55
|
+
? "Query"
|
|
56
|
+
: "Input"
|
|
57
|
+
}`
|
|
58
|
+
: p.type.name
|
|
59
|
+
},`,
|
|
60
|
+
),
|
|
61
|
+
`): Promise<${output ? "Output" : "void"}> => {`,
|
|
62
|
+
...body.map((l) => ` ${l}`),
|
|
63
|
+
`}`,
|
|
64
|
+
]
|
|
65
|
+
.map((line) => ` ${line}`)
|
|
66
|
+
.join("\n");
|
|
67
|
+
};
|
|
55
68
|
|
|
56
|
-
const assert =
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
69
|
+
const assert =
|
|
70
|
+
(config: INestiaConfig) =>
|
|
71
|
+
(importer: ImportDictionary) =>
|
|
72
|
+
(parameters: IRoute.IParameter[]): string[] => {
|
|
73
|
+
const typiaType = () =>
|
|
74
|
+
importer.external({
|
|
75
|
+
type: false,
|
|
76
|
+
library: "typia",
|
|
77
|
+
instance: null,
|
|
78
|
+
});
|
|
79
|
+
return [
|
|
80
|
+
`const assert = ${importer.internal({
|
|
81
|
+
file: `${config.output}/utils/NestiaSimulator.ts`,
|
|
82
|
+
instance: "NestiaSimulator",
|
|
83
|
+
type: false,
|
|
84
|
+
})}.assert({`,
|
|
85
|
+
` method: METADATA.method,`,
|
|
86
|
+
` host: connection.host,`,
|
|
87
|
+
` path: path(${parameters
|
|
88
|
+
.filter(
|
|
89
|
+
(p) => p.category === "param" || p.category === "query",
|
|
90
|
+
)
|
|
91
|
+
.map((p) => p.name)
|
|
92
|
+
.join(", ")})`,
|
|
93
|
+
`});`,
|
|
94
|
+
...parameters
|
|
95
|
+
.filter((p) => p.category !== "headers")
|
|
96
|
+
.map((p) =>
|
|
97
|
+
p.category === "body"
|
|
98
|
+
? `assert.body(() => ${typiaType()}.assert(${
|
|
99
|
+
p.name
|
|
100
|
+
}));`
|
|
101
|
+
: p.category === "query"
|
|
102
|
+
? `assert.query(() => ${typiaType()}.assert(${
|
|
103
|
+
p.name
|
|
104
|
+
}));`
|
|
105
|
+
: p.category === "headers"
|
|
106
|
+
? `assert.headers(() => ${typiaType()}.assert(connection.headers);` // not reachable
|
|
107
|
+
: `assert.param("${p.field}")("${
|
|
108
|
+
p.custom && p.meta ? p.meta.type : p.type.name
|
|
109
|
+
}")(() => ${typiaType()}.assert(${p.name}));`,
|
|
110
|
+
),
|
|
111
|
+
];
|
|
112
|
+
};
|
|
79
113
|
}
|
|
@@ -4,53 +4,117 @@ import { HashSet } from "tstl/container/HashSet";
|
|
|
4
4
|
import { Pair } from "tstl/utility/Pair";
|
|
5
5
|
|
|
6
6
|
export class ImportDictionary {
|
|
7
|
-
private readonly
|
|
7
|
+
private readonly externals_: HashMap<Pair<string, boolean>, IComposition> =
|
|
8
|
+
new HashMap();
|
|
9
|
+
private readonly internals_: HashMap<Pair<string, boolean>, IComposition> =
|
|
8
10
|
new HashMap();
|
|
9
11
|
|
|
10
12
|
public empty(): boolean {
|
|
11
|
-
return this.
|
|
13
|
+
return this.internals_.empty() && this.externals_.empty();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public external(props: ImportDictionary.IExternalProps): string {
|
|
17
|
+
const composition: IComposition = this.externals_.take(
|
|
18
|
+
new Pair(props.library, props.type),
|
|
19
|
+
() => ({
|
|
20
|
+
location: props.library,
|
|
21
|
+
elements: new HashSet(),
|
|
22
|
+
default: false,
|
|
23
|
+
type: props.type,
|
|
24
|
+
}),
|
|
25
|
+
);
|
|
26
|
+
if (props.instance === null) composition.default = true;
|
|
27
|
+
else composition.elements.insert(props.instance);
|
|
28
|
+
return props.instance ?? props.library;
|
|
12
29
|
}
|
|
13
30
|
|
|
14
|
-
public
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
31
|
+
public internal(props: ImportDictionary.IInternalProps): string {
|
|
32
|
+
const file: string = (() => {
|
|
33
|
+
if (props.file.substring(props.file.length - 5) === ".d.ts")
|
|
34
|
+
return props.file.substring(0, props.file.length - 5);
|
|
35
|
+
else if (props.file.substring(0, props.file.length - 3) === ".ts")
|
|
36
|
+
return props.file.substring(0, props.file.length - 3);
|
|
19
37
|
throw new Error(
|
|
20
|
-
`Error on ImportDictionary.emplace(): extension of the target file "${file}" is not "ts".`,
|
|
38
|
+
`Error on ImportDictionary.emplace(): extension of the target file "${props.file}" is not "ts".`,
|
|
21
39
|
);
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
file,
|
|
25
|
-
() =>
|
|
40
|
+
})();
|
|
41
|
+
const composition: IComposition = this.internals_.take(
|
|
42
|
+
new Pair(file, props.type),
|
|
43
|
+
() => ({
|
|
44
|
+
location: file,
|
|
45
|
+
elements: new HashSet(),
|
|
46
|
+
default: false,
|
|
47
|
+
type: props.type,
|
|
48
|
+
}),
|
|
26
49
|
);
|
|
27
|
-
|
|
50
|
+
if (props.instance === null) composition.default = true;
|
|
51
|
+
else composition.elements.insert(props.instance);
|
|
52
|
+
return props.instance ?? file;
|
|
28
53
|
}
|
|
29
54
|
|
|
30
55
|
public toScript(outDir: string): string {
|
|
31
56
|
const statements: string[] = [];
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
.
|
|
37
|
-
.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
57
|
+
const enroll =
|
|
58
|
+
(locator: (str: string) => string) =>
|
|
59
|
+
(dict: HashMap<Pair<string, boolean>, IComposition>) => {
|
|
60
|
+
const compositions: IComposition[] = dict
|
|
61
|
+
.toJSON()
|
|
62
|
+
.map((e) => ({
|
|
63
|
+
...e.second,
|
|
64
|
+
location: locator(e.second.location),
|
|
65
|
+
}))
|
|
66
|
+
.sort((a, b) => a.location.localeCompare(b.location));
|
|
67
|
+
for (const c of compositions) {
|
|
68
|
+
const brackets: string[] = [];
|
|
69
|
+
if (c.default) brackets.push(c.location);
|
|
70
|
+
if (c.elements.empty() === false)
|
|
71
|
+
brackets.push(
|
|
72
|
+
`{${c.elements
|
|
73
|
+
.toJSON()
|
|
74
|
+
.sort((a, b) => a.localeCompare(b))
|
|
75
|
+
.join(", ")}`,
|
|
76
|
+
);
|
|
77
|
+
statements.push(
|
|
78
|
+
`import ${c.type ? "type " : ""} ${brackets.join(
|
|
79
|
+
", ",
|
|
80
|
+
)} from "${c.location}";`,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
enroll((str) => str)(this.externals_);
|
|
86
|
+
if (this.internals_.size()) statements.push("");
|
|
87
|
+
enroll((str) => {
|
|
88
|
+
const location: string = path
|
|
89
|
+
.relative(outDir, str)
|
|
90
|
+
.split("\\")
|
|
91
|
+
.join("/");
|
|
92
|
+
const index: number = location.lastIndexOf(NODE_MODULES);
|
|
93
|
+
return index === -1
|
|
94
|
+
? `./${location}`
|
|
95
|
+
: location.substring(index + NODE_MODULES.length);
|
|
96
|
+
})(this.internals_);
|
|
52
97
|
return statements.join("\n");
|
|
53
98
|
}
|
|
54
99
|
}
|
|
100
|
+
export namespace ImportDictionary {
|
|
101
|
+
export interface IInternalProps {
|
|
102
|
+
type: boolean;
|
|
103
|
+
file: string;
|
|
104
|
+
instance: string;
|
|
105
|
+
}
|
|
106
|
+
export interface IExternalProps {
|
|
107
|
+
type: boolean;
|
|
108
|
+
library: string;
|
|
109
|
+
instance: string | null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
interface IComposition {
|
|
114
|
+
location: string;
|
|
115
|
+
type: boolean;
|
|
116
|
+
default: boolean;
|
|
117
|
+
elements: HashSet<string>;
|
|
118
|
+
}
|
|
55
119
|
|
|
56
120
|
const NODE_MODULES = "node_modules/";
|