@nestia/sdk 7.1.1 → 7.2.1

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 (76) hide show
  1. package/lib/analyses/DtoAnalyzer.d.ts +21 -0
  2. package/lib/analyses/DtoAnalyzer.js +203 -0
  3. package/lib/analyses/DtoAnalyzer.js.map +1 -0
  4. package/lib/analyses/ImportAnalyzer.d.ts +3 -8
  5. package/lib/analyses/ImportAnalyzer.js +84 -102
  6. package/lib/analyses/ImportAnalyzer.js.map +1 -1
  7. package/lib/analyses/ReflectHttpOperationAnalyzer.js +1 -1
  8. package/lib/analyses/ReflectHttpOperationAnalyzer.js.map +1 -1
  9. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js +1 -1
  10. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js.map +1 -1
  11. package/lib/generates/internal/E2eFileProgrammer.js +3 -9
  12. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  13. package/lib/generates/internal/ImportDictionary.d.ts +9 -11
  14. package/lib/generates/internal/ImportDictionary.js +55 -48
  15. package/lib/generates/internal/ImportDictionary.js.map +1 -1
  16. package/lib/generates/internal/SdkAliasCollection.js +24 -18
  17. package/lib/generates/internal/SdkAliasCollection.js.map +1 -1
  18. package/lib/generates/internal/SdkFileProgrammer.js +1 -7
  19. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  20. package/lib/generates/internal/SdkHttpCloneReferencer.js +3 -1
  21. package/lib/generates/internal/SdkHttpCloneReferencer.js.map +1 -1
  22. package/lib/generates/internal/SdkHttpSimulationProgrammer.js +4 -3
  23. package/lib/generates/internal/SdkHttpSimulationProgrammer.js.map +1 -1
  24. package/lib/generates/internal/SdkImportWizard.js +28 -21
  25. package/lib/generates/internal/SdkImportWizard.js.map +1 -1
  26. package/lib/generates/internal/SdkTypeProgrammer.js +3 -2
  27. package/lib/generates/internal/SdkTypeProgrammer.js.map +1 -1
  28. package/lib/generates/internal/SdkTypeTagProgrammer.js +10 -8
  29. package/lib/generates/internal/SdkTypeTagProgrammer.js.map +1 -1
  30. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js +8 -6
  31. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js.map +1 -1
  32. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js +12 -9
  33. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js.map +1 -1
  34. package/lib/structures/IReflectHttpOperation.d.ts +2 -2
  35. package/lib/structures/IReflectImport.d.ts +6 -0
  36. package/lib/structures/{IReflectTypeImport.js → IReflectImport.js} +1 -1
  37. package/lib/structures/IReflectImport.js.map +1 -0
  38. package/lib/structures/IReflectWebSocketOperation.d.ts +2 -2
  39. package/lib/structures/IReflectWebSocketOperationParameter.d.ts +2 -2
  40. package/lib/structures/ITypedHttpRoute.d.ts +2 -2
  41. package/lib/structures/ITypedWebSocketRoute.d.ts +2 -2
  42. package/lib/transformers/IOperationMetadata.d.ts +3 -3
  43. package/lib/transformers/SdkOperationProgrammer.d.ts +3 -1
  44. package/lib/transformers/SdkOperationProgrammer.js +57 -26
  45. package/lib/transformers/SdkOperationProgrammer.js.map +1 -1
  46. package/lib/transformers/SdkOperationTransformer.js +3 -3
  47. package/lib/transformers/SdkOperationTransformer.js.map +1 -1
  48. package/package.json +4 -4
  49. package/src/analyses/DtoAnalyzer.ts +246 -0
  50. package/src/analyses/ImportAnalyzer.ts +110 -155
  51. package/src/analyses/ReflectHttpOperationAnalyzer.ts +1 -1
  52. package/src/analyses/ReflectWebSocketOperationAnalyzer.ts +3 -3
  53. package/src/generates/internal/E2eFileProgrammer.ts +3 -11
  54. package/src/generates/internal/ImportDictionary.ts +111 -84
  55. package/src/generates/internal/SdkAliasCollection.ts +24 -18
  56. package/src/generates/internal/SdkFileProgrammer.ts +1 -7
  57. package/src/generates/internal/SdkHttpCloneReferencer.ts +3 -1
  58. package/src/generates/internal/SdkHttpSimulationProgrammer.ts +4 -3
  59. package/src/generates/internal/SdkImportWizard.ts +28 -21
  60. package/src/generates/internal/SdkTypeProgrammer.ts +3 -2
  61. package/src/generates/internal/SdkTypeTagProgrammer.ts +10 -8
  62. package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +8 -6
  63. package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +12 -9
  64. package/src/structures/IReflectHttpOperation.ts +2 -2
  65. package/src/structures/IReflectHttpOperationParameter.ts +2 -6
  66. package/src/structures/IReflectImport.ts +6 -0
  67. package/src/structures/IReflectWebSocketOperation.ts +2 -2
  68. package/src/structures/IReflectWebSocketOperationParameter.ts +3 -5
  69. package/src/structures/ITypedHttpRoute.ts +2 -2
  70. package/src/structures/ITypedWebSocketRoute.ts +2 -2
  71. package/src/transformers/IOperationMetadata.ts +3 -3
  72. package/src/transformers/SdkOperationProgrammer.ts +60 -31
  73. package/src/transformers/SdkOperationTransformer.ts +7 -8
  74. package/lib/structures/IReflectTypeImport.d.ts +0 -4
  75. package/lib/structures/IReflectTypeImport.js.map +0 -1
  76. package/src/structures/IReflectTypeImport.ts +0 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nestia/sdk",
3
- "version": "7.1.1",
3
+ "version": "7.2.1",
4
4
  "description": "Nestia SDK and Swagger generator",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
@@ -32,8 +32,8 @@
32
32
  },
33
33
  "homepage": "https://nestia.io",
34
34
  "dependencies": {
35
- "@nestia/core": "^7.1.1",
36
- "@nestia/fetcher": "^7.1.1",
35
+ "@nestia/core": "^7.2.1",
36
+ "@nestia/fetcher": "^7.2.1",
37
37
  "@samchon/openapi": "^4.5.0",
38
38
  "cli": "^1.0.1",
39
39
  "get-function-location": "^2.0.0",
@@ -47,7 +47,7 @@
47
47
  "typia": "^9.5.0"
48
48
  },
49
49
  "peerDependencies": {
50
- "@nestia/core": ">=7.1.1"
50
+ "@nestia/core": ">=7.2.1"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@nestjs/common": "^11.0.13",
@@ -0,0 +1,246 @@
1
+ import ts from "typescript";
2
+
3
+ import { IReflectImport } from "../structures/IReflectImport";
4
+ import { IReflectType } from "../structures/IReflectType";
5
+ import { ImportAnalyzer } from "./ImportAnalyzer";
6
+
7
+ export namespace DtoAnalyzer {
8
+ export interface INodeProps {
9
+ checker: ts.TypeChecker;
10
+ imports: IReflectImport[];
11
+ typeNode: ts.TypeNode;
12
+ }
13
+ export interface ITypeProps {
14
+ checker: ts.TypeChecker;
15
+ imports: IReflectImport[];
16
+ type: ts.Type;
17
+ }
18
+ export interface IOutput {
19
+ imports: IReflectImport[];
20
+ type: IReflectType;
21
+ }
22
+
23
+ export const analyzeNode = (props: INodeProps): IOutput | null => {
24
+ try {
25
+ const container: IReflectImport[] = [];
26
+ const type: IReflectType = exploreNode(
27
+ {
28
+ checker: props.checker,
29
+ imports: props.imports,
30
+ container,
31
+ },
32
+ props.typeNode,
33
+ );
34
+ return {
35
+ type,
36
+ imports: ImportAnalyzer.merge(container),
37
+ };
38
+ } catch {
39
+ return null;
40
+ }
41
+ };
42
+
43
+ export const analyzeType = (props: ITypeProps): IOutput | null => {
44
+ try {
45
+ const container: IReflectImport[] = [];
46
+ const type: IReflectType = exploreType(
47
+ {
48
+ checker: props.checker,
49
+ imports: props.imports,
50
+ container,
51
+ },
52
+ props.type,
53
+ );
54
+ return {
55
+ type,
56
+ imports: ImportAnalyzer.merge(container),
57
+ };
58
+ } catch {
59
+ return null;
60
+ }
61
+ };
62
+
63
+ type IContext = Omit<INodeProps, "typeNode"> & {
64
+ container: IReflectImport[];
65
+ };
66
+
67
+ const exploreNode = (ctx: IContext, typeNode: ts.TypeNode): IReflectType => {
68
+ // Analyze symbol, and take special cares
69
+ if (ts.isIntersectionTypeNode(typeNode))
70
+ return {
71
+ name: typeNode.types
72
+ .map((child) => exploreNode(ctx, child))
73
+ .map(getEscapedText)
74
+ .join(" & "),
75
+ };
76
+ else if (ts.isUnionTypeNode(typeNode))
77
+ return {
78
+ name: typeNode.types
79
+ .map((child) => exploreNode(ctx, child))
80
+ .map(getEscapedText)
81
+ .join(" | "),
82
+ };
83
+ else if (ts.isParenthesizedTypeNode(typeNode))
84
+ return {
85
+ name: `(${exploreNode(ctx, typeNode.type).name})`,
86
+ };
87
+ else if (ts.isTypeOperatorNode(typeNode)) {
88
+ const prefix: string | null =
89
+ typeNode.operator === ts.SyntaxKind.KeyOfKeyword
90
+ ? "keyof"
91
+ : typeNode.operator === ts.SyntaxKind.UniqueKeyword
92
+ ? "unique"
93
+ : typeNode.operator === ts.SyntaxKind.ReadonlyKeyword
94
+ ? "readonly"
95
+ : null;
96
+ if (prefix === null)
97
+ return exploreType(ctx, ctx.checker.getTypeFromTypeNode(typeNode));
98
+ return {
99
+ name: `${prefix} ${exploreNode(ctx, typeNode.type).name}`,
100
+ };
101
+ } else if (ts.isTypePredicateNode(typeNode) || ts.isTypeQueryNode(typeNode))
102
+ return exploreType(ctx, ctx.checker.getTypeFromTypeNode(typeNode));
103
+ else if (ts.isTypeReferenceNode(typeNode) === false)
104
+ return {
105
+ name: typeNode.getText(),
106
+ };
107
+
108
+ // Find matched import statement
109
+ const name: string = typeNode.typeName.getText();
110
+ const prefix: string = name.split(".")[0];
111
+
112
+ let matched: boolean = false;
113
+ const insert = (imp: IReflectImport): void => {
114
+ matched ||= true;
115
+ ctx.container.push(imp);
116
+ };
117
+ for (const imp of ctx.imports)
118
+ if (prefix === imp.default)
119
+ insert({
120
+ file: imp.file,
121
+ asterisk: null,
122
+ default: prefix,
123
+ elements: [],
124
+ });
125
+ else if (prefix === imp.asterisk)
126
+ insert({
127
+ file: imp.file,
128
+ asterisk: prefix,
129
+ default: null,
130
+ elements: [],
131
+ });
132
+ else if (imp.elements.includes(prefix))
133
+ insert({
134
+ file: imp.file,
135
+ asterisk: null,
136
+ default: null,
137
+ elements: [prefix],
138
+ });
139
+ if (prefix !== "Promise" && matched === false)
140
+ return exploreType(ctx, ctx.checker.getTypeFromTypeNode(typeNode));
141
+
142
+ // Finalize with generic arguments
143
+ if (!!typeNode.typeArguments?.length) {
144
+ const top: ts.TypeNode = typeNode.typeArguments[0];
145
+ if (name === "Promise") return exploreNode(ctx, top);
146
+ return {
147
+ name,
148
+ typeArguments: typeNode.typeArguments.map((child) =>
149
+ exploreNode(ctx, child),
150
+ ),
151
+ };
152
+ }
153
+ return { name };
154
+ };
155
+
156
+ const exploreType = (ctx: IContext, type: ts.Type): IReflectType => {
157
+ // Analyze symbol, and take special cares
158
+ const symbol: ts.Symbol | undefined = type.aliasSymbol ?? type.symbol;
159
+ if (type.aliasSymbol === undefined && type.isUnionOrIntersection()) {
160
+ const joiner: string = type.isIntersection() ? " & " : " | ";
161
+ return {
162
+ name: type.types
163
+ .map((child) => exploreType(ctx, child))
164
+ .map(getEscapedText)
165
+ .join(joiner),
166
+ };
167
+ } else if (symbol === undefined)
168
+ return {
169
+ name: ctx.checker.typeToString(
170
+ type,
171
+ undefined,
172
+ ts.TypeFormatFlags.NoTruncation,
173
+ ),
174
+ };
175
+
176
+ // Find matched import statement
177
+ const name: string = getNameOfSymbol(symbol);
178
+ const prefix: string = name.split(".")[0];
179
+
180
+ let matched: boolean = false;
181
+ const insert = (imp: IReflectImport): void => {
182
+ matched ||= true;
183
+ ctx.container.push(imp);
184
+ };
185
+ for (const imp of ctx.imports)
186
+ if (imp.elements.includes(prefix))
187
+ insert({
188
+ file: imp.file,
189
+ asterisk: null,
190
+ default: null,
191
+ elements: [prefix],
192
+ });
193
+ if (prefix !== "Promise" && matched === false)
194
+ emplaceSymbol(ctx, symbol, prefix);
195
+
196
+ // Finalize with generic arguments
197
+ const generic: readonly ts.Type[] = type.aliasSymbol
198
+ ? (type.aliasTypeArguments ?? [])
199
+ : ctx.checker.getTypeArguments(type as ts.TypeReference);
200
+ return generic.length
201
+ ? name === "Promise"
202
+ ? exploreType(ctx, generic[0])
203
+ : {
204
+ name,
205
+ typeArguments: generic.map((child) => exploreType(ctx, child)),
206
+ }
207
+ : { name };
208
+ };
209
+
210
+ const emplaceSymbol = (
211
+ ctx: IContext,
212
+ symbol: ts.Symbol,
213
+ prefix: string,
214
+ ): void => {
215
+ // GET SOURCE FILE
216
+ const sourceFile: ts.SourceFile | undefined =
217
+ symbol.declarations?.[0]?.getSourceFile();
218
+ if (sourceFile === undefined) return;
219
+ if (sourceFile.fileName.indexOf("/typescript/lib") === -1)
220
+ ctx.container.push({
221
+ file: sourceFile.fileName,
222
+ asterisk: null,
223
+ default: null,
224
+ elements: [prefix],
225
+ });
226
+ };
227
+ }
228
+
229
+ const getEscapedText = (type: IReflectType): string =>
230
+ type.typeArguments
231
+ ? `${type.name}<${type.typeArguments.map(getEscapedText).join(", ")}>`
232
+ : type.name;
233
+
234
+ const getNameOfSymbol = (symbol: ts.Symbol): string =>
235
+ exploreName(
236
+ symbol.escapedName.toString(),
237
+ symbol.getDeclarations()?.[0]?.parent,
238
+ );
239
+
240
+ const exploreName = (name: string, decl?: ts.Node): string =>
241
+ decl && ts.isModuleBlock(decl)
242
+ ? exploreName(
243
+ `${decl.parent.name.getFullText().trim()}.${name}`,
244
+ decl.parent.parent,
245
+ )
246
+ : name;
@@ -1,171 +1,126 @@
1
+ import path from "path";
1
2
  import ts from "typescript";
2
3
 
3
- import { IReflectType } from "../structures/IReflectType";
4
- import { IReflectTypeImport } from "../structures/IReflectTypeImport";
4
+ import { IReflectImport } from "../structures/IReflectImport";
5
5
  import { MapUtil } from "../utils/MapUtil";
6
6
 
7
7
  export namespace ImportAnalyzer {
8
- export interface IOutput {
9
- imports: IReflectTypeImport[];
10
- type: IReflectType | null;
11
- }
12
- export const analyze = (
13
- checker: ts.TypeChecker,
14
- generics: WeakMap<ts.Type, ts.Type>,
15
- type: ts.Type,
16
- ): IOutput => {
17
- const imports: Map<string, Set<string>> = new Map();
18
- try {
19
- type = escape(checker, type);
20
- return {
21
- type: explore({
22
- checker,
23
- generics,
24
- imports,
25
- type,
26
- }),
27
- imports: [...imports].map(([file, instances]) => ({
28
- file,
29
- instances: Array.from(instances),
30
- })),
31
- };
32
- } catch {
33
- return {
34
- imports: [],
35
- type: null,
36
- };
37
- }
38
- };
8
+ export const analyze = (file: ts.SourceFile): IReflectImport[] =>
9
+ file.statements
10
+ .filter(ts.isImportDeclaration)
11
+ .map((imp) => {
12
+ const clause: ts.ImportClause | undefined = imp.importClause;
13
+ if (clause === undefined) return null;
14
+ try {
15
+ // no real position
16
+ // import statement generated by transformer like typia
17
+ imp.moduleSpecifier.getText();
18
+ } catch {
19
+ return null;
20
+ }
39
21
 
40
- export const unique = (
41
- imports: IReflectTypeImport[],
42
- ): IReflectTypeImport[] => {
43
- const map: Map<string, Set<string>> = new Map();
44
- imports.forEach(({ file, instances }) => {
45
- const set: Set<string> = MapUtil.take(map, file, () => new Set());
46
- instances.forEach((instance) => set.add(instance));
47
- });
48
- return [...map].map(([file, instances]) => ({
49
- file,
50
- instances: Array.from(instances),
51
- }));
52
- };
22
+ const reflect: IReflectImport = {
23
+ file: normalizePath(
24
+ path.dirname(file.fileName),
25
+ ts.isStringLiteral(imp.moduleSpecifier)
26
+ ? imp.moduleSpecifier.text
27
+ : escapeQuotes(imp.moduleSpecifier.getText()),
28
+ ),
29
+ elements: [],
30
+ default: null,
31
+ asterisk: null,
32
+ };
33
+ if (clause.name) reflect.default = clause.name.getText();
34
+ if (clause.namedBindings === undefined) return reflect;
35
+ else if (ts.isNamedImports(clause.namedBindings))
36
+ reflect.elements = clause.namedBindings.elements.map((e) =>
37
+ e.name.getText(),
38
+ );
39
+ else if (ts.isNamespaceImport(clause.namedBindings))
40
+ reflect.asterisk = clause.namedBindings.name.getText();
41
+ return reflect;
42
+ })
43
+ .filter((r) => r !== null);
53
44
 
54
- /* ---------------------------------------------------------
55
- TYPE
56
- --------------------------------------------------------- */
57
- const escape = (checker: ts.TypeChecker, type: ts.Type): ts.Type => {
58
- if (type.symbol && getNameOfSymbol(type.symbol) === "Promise") {
59
- const generic: readonly ts.Type[] = checker.getTypeArguments(
60
- type as ts.TypeReference,
45
+ export const merge = (imports: IReflectImport[]): IReflectImport[] => {
46
+ // group by files
47
+ const fileGroups: Map<string, IReflectImport[]> = new Map();
48
+ for (const imp of imports) {
49
+ const array: IReflectImport[] = MapUtil.take(
50
+ fileGroups,
51
+ imp.file,
52
+ () => [],
61
53
  );
62
- if (generic.length !== 1)
63
- throw new Error(
64
- "Error on ImportAnalyzer.analyze(): invalid promise type.",
65
- );
66
- type = generic[0];
54
+ array.push(imp);
67
55
  }
68
- return type;
56
+ return Array.from(fileGroups.entries())
57
+ .map(([key, value]) => mergeGroup(key, value))
58
+ .flat();
69
59
  };
70
60
 
71
- const getNameOfSymbol = (symbol: ts.Symbol): string =>
72
- exploreName(
73
- symbol.escapedName.toString(),
74
- symbol.getDeclarations()?.[0]?.parent,
75
- );
76
-
77
- /* ---------------------------------------------------------
78
- ESCAPED TEXT WITH IMPORT STATEMENTS
79
- --------------------------------------------------------- */
80
- const explore = (props: {
81
- checker: ts.TypeChecker;
82
- generics: WeakMap<ts.Type, ts.Type>;
83
- imports: Map<string, Set<string>>;
84
- type: ts.Type;
85
- }): IReflectType => {
86
- //----
87
- // CONDITIONAL BRANCHES
88
- //----
89
- // DECOMPOSE GENERIC ARGUMENT
90
- let type: ts.Type = props.type;
91
- while (props.generics.has(type) === true) type = props.generics.get(type)!;
92
-
93
- // PRIMITIVE
94
- const symbol: ts.Symbol | undefined = type.aliasSymbol ?? type.symbol;
95
-
96
- // UNION OR INTERSECT
97
- if (type.aliasSymbol === undefined && type.isUnionOrIntersection()) {
98
- const joiner: string = type.isIntersection() ? " & " : " | ";
99
- return {
100
- name: type.types
101
- .map((child) =>
102
- explore({
103
- ...props,
104
- type: child,
105
- }),
106
- )
107
- .map(getEscapedText)
108
- .join(joiner),
109
- };
110
- }
111
- // NO SYMBOL
112
- else if (symbol === undefined)
113
- return {
114
- name: props.checker.typeToString(
115
- type,
116
- undefined,
117
- ts.TypeFormatFlags.NoTruncation,
118
- ),
119
- };
120
-
121
- //----
122
- // SPECIALIZATION
123
- //----
124
- const name: string = getNameOfSymbol(symbol);
125
- const sourceFile: ts.SourceFile | undefined =
126
- symbol.declarations?.[0]?.getSourceFile();
127
- if (sourceFile === undefined) return { name };
128
- else if (sourceFile.fileName.indexOf("typescript/lib") === -1) {
129
- const set: Set<string> = MapUtil.take(
130
- props.imports,
131
- sourceFile.fileName,
132
- () => new Set(),
61
+ function mergeGroup(
62
+ file: string,
63
+ imports: IReflectImport[],
64
+ ): IReflectImport[] {
65
+ const allStarImports: IReflectImport[] = Array.from(
66
+ new Set(
67
+ imports
68
+ .filter((imp) => imp.asterisk !== null)
69
+ .map((imp) => imp.asterisk!),
70
+ ),
71
+ )
72
+ .sort()
73
+ .map(
74
+ (allStarImport) =>
75
+ ({
76
+ file,
77
+ elements: [],
78
+ default: null,
79
+ asterisk: allStarImport,
80
+ }) satisfies IReflectImport,
81
+ );
82
+ const defaultImports: IReflectImport[] = Array.from(
83
+ new Set(
84
+ imports
85
+ .filter((imp) => imp.default !== null)
86
+ .map((imp) => imp.default!),
87
+ ),
88
+ )
89
+ .sort()
90
+ .map(
91
+ (defaultImport) =>
92
+ ({
93
+ file,
94
+ elements: [],
95
+ default: defaultImport,
96
+ asterisk: null,
97
+ }) satisfies IReflectImport,
133
98
  );
134
- set.add(name.split(".")[0]);
99
+ const instances: Set<string> = new Set(
100
+ imports.map((imp) => imp.elements).flat(),
101
+ );
102
+ if (instances.size !== 0) {
103
+ if (defaultImports.length !== 0)
104
+ defaultImports[0].elements = Array.from(instances).sort();
105
+ else
106
+ defaultImports.push({
107
+ file,
108
+ elements: Array.from(instances).sort(),
109
+ default: null,
110
+ asterisk: null,
111
+ });
135
112
  }
113
+ return [...allStarImports, ...defaultImports];
114
+ }
136
115
 
137
- // CHECK GENERIC
138
- const generic: readonly ts.Type[] = type.aliasSymbol
139
- ? type.aliasTypeArguments ?? []
140
- : props.checker.getTypeArguments(type as ts.TypeReference);
141
- return generic.length
142
- ? name === "Promise"
143
- ? explore({
144
- ...props,
145
- type: generic[0],
146
- })
147
- : {
148
- name,
149
- typeArguments: generic.map((child) =>
150
- explore({
151
- ...props,
152
- type: child,
153
- }),
154
- ),
155
- }
156
- : { name };
157
- };
158
-
159
- const exploreName = (name: string, decl?: ts.Node): string =>
160
- decl && ts.isModuleBlock(decl)
161
- ? exploreName(
162
- `${decl.parent.name.getFullText().trim()}.${name}`,
163
- decl.parent.parent,
164
- )
165
- : name;
116
+ function escapeQuotes(str: string): string {
117
+ if (str.startsWith("'") && str.endsWith("'")) return str.slice(1, -1);
118
+ else if (str.startsWith('"') && str.endsWith('"')) return str.slice(1, -1);
119
+ return str;
120
+ }
166
121
 
167
- const getEscapedText = (type: IReflectType): string =>
168
- type.typeArguments
169
- ? `${type.name}<${type.typeArguments.map(getEscapedText).join(", ")}>`
170
- : type.name;
122
+ function normalizePath(root: string, str: string): string {
123
+ if (str.startsWith(".")) return path.resolve(root, str);
124
+ return `node_modules/${str}`;
125
+ }
171
126
  }
@@ -101,7 +101,7 @@ export namespace ReflectHttpOperationAnalyzer {
101
101
  errors,
102
102
  }),
103
103
  tags: Reflect.getMetadata("swagger/apiUseTags", props.function) ?? [],
104
- imports: ImportAnalyzer.unique(
104
+ imports: ImportAnalyzer.merge(
105
105
  [
106
106
  ...props.metadata.parameters
107
107
  .filter((x) => parameters.some((y) => x.index === y.index))
@@ -2,7 +2,7 @@ import { ranges } from "tstl";
2
2
 
3
3
  import { INestiaProject } from "../structures/INestiaProject";
4
4
  import { IReflectController } from "../structures/IReflectController";
5
- import { IReflectTypeImport } from "../structures/IReflectTypeImport";
5
+ import { IReflectImport } from "../structures/IReflectImport";
6
6
  import { IReflectWebSocketOperation } from "../structures/IReflectWebSocketOperation";
7
7
  import { IReflectWebSocketOperationParameter } from "../structures/IReflectWebSocketOperationParameter";
8
8
  import { IOperationMetadata } from "../transformers/IOperationMetadata";
@@ -50,7 +50,7 @@ export namespace ReflectWebSocketOperationAnalyzer {
50
50
  ].join("\n"),
51
51
  );
52
52
 
53
- const imports: IReflectTypeImport[] = [];
53
+ const imports: IReflectImport[] = [];
54
54
  const parameters: IReflectWebSocketOperationParameter[] = preconfigured
55
55
  .map((p) => {
56
56
  // METADATA INFO
@@ -164,7 +164,7 @@ export namespace ReflectWebSocketOperationAnalyzer {
164
164
  function: ctx.function,
165
165
  versions: ReflectMetadataAnalyzer.versions(ctx.function),
166
166
  parameters,
167
- imports: ImportAnalyzer.unique(imports),
167
+ imports: ImportAnalyzer.merge(imports),
168
168
  description: ctx.metadata.description ?? null,
169
169
  jsDocTags: ctx.metadata.jsDocTags,
170
170
  };
@@ -18,21 +18,13 @@ export namespace E2eFileProgrammer {
18
18
  const importer: ImportDictionary = new ImportDictionary(
19
19
  `${props.current}/${getFunctionName(route)}.ts`,
20
20
  );
21
- if (project.config.clone !== true)
22
- for (const tuple of route.imports)
23
- for (const instance of tuple.instances)
24
- importer.internal({
25
- file: tuple.file,
26
- type: true,
27
- instance,
28
- });
21
+ if (project.config.clone !== true) importer.declarations(route.imports);
29
22
  importer.internal({
30
- type: false,
31
23
  file: props.api,
32
- instance: null,
24
+ declaration: false,
25
+ type: "default",
33
26
  name: "api",
34
27
  });
35
-
36
28
  const functor: ts.Statement = generateFunctor(project)(importer)(route);
37
29
  await FilePrinter.write({
38
30
  location: importer.file,