@nestia/sdk 11.0.0-dev.20260316 → 11.0.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.
- package/LICENSE +21 -21
- package/README.md +93 -93
- package/assets/bundle/api/HttpError.ts +1 -1
- package/assets/bundle/api/IConnection.ts +1 -1
- package/assets/bundle/api/Primitive.ts +1 -1
- package/assets/bundle/api/Resolved.ts +1 -1
- package/assets/bundle/api/index.ts +4 -4
- package/assets/bundle/api/module.ts +6 -6
- package/assets/bundle/distribute/README.md +37 -37
- package/assets/bundle/distribute/package.json +28 -28
- package/assets/bundle/distribute/tsconfig.json +109 -109
- package/assets/bundle/e2e/index.ts +42 -42
- package/assets/config/nestia.config.ts +97 -97
- package/lib/executable/internal/NestiaConfigLoader.js +5 -5
- package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
- package/package.json +8 -8
- package/src/INestiaConfig.ts +267 -267
- package/src/NestiaSdkApplication.ts +307 -307
- package/src/NestiaSwaggerComposer.ts +143 -143
- package/src/analyses/AccessorAnalyzer.ts +67 -67
- package/src/analyses/DtoAnalyzer.ts +260 -260
- package/src/analyses/ImportAnalyzer.ts +126 -126
- package/src/analyses/ReflectHttpOperationAnalyzer.ts +183 -183
- package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +72 -72
- package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +350 -350
- package/src/analyses/ReflectHttpOperationResponseAnalyzer.ts +126 -126
- package/src/analyses/TypedHttpRouteAnalyzer.ts +208 -208
- package/src/executable/internal/NestiaConfigLoader.ts +85 -85
- package/src/executable/internal/NestiaSdkCommand.ts +107 -107
- package/src/generates/SwaggerGenerator.ts +291 -291
- package/src/generates/internal/E2eFileProgrammer.ts +196 -196
- package/src/generates/internal/FilePrinter.ts +64 -64
- package/src/generates/internal/ImportDictionary.ts +192 -192
- package/src/generates/internal/SdkAliasCollection.ts +260 -260
- package/src/generates/internal/SdkFileProgrammer.ts +110 -110
- package/src/generates/internal/SdkHttpCloneProgrammer.ts +126 -126
- package/src/generates/internal/SdkHttpCloneReferencer.ts +77 -77
- package/src/generates/internal/SdkHttpFunctionProgrammer.ts +278 -278
- package/src/generates/internal/SdkHttpNamespaceProgrammer.ts +502 -502
- package/src/generates/internal/SdkHttpRouteProgrammer.ts +109 -109
- package/src/generates/internal/SdkHttpSimulationProgrammer.ts +312 -312
- package/src/generates/internal/SdkImportWizard.ts +62 -62
- package/src/generates/internal/SdkTypeProgrammer.ts +388 -388
- package/src/generates/internal/SdkTypeTagProgrammer.ts +114 -114
- package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +379 -379
- package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +302 -302
- package/src/generates/internal/SwaggerOperationComposer.ts +119 -119
- package/src/generates/internal/SwaggerOperationParameterComposer.ts +161 -161
- package/src/generates/internal/SwaggerOperationResponseComposer.ts +110 -110
- package/src/module.ts +4 -4
- package/src/structures/IReflectHttpOperationException.ts +18 -18
- package/src/structures/IReflectHttpOperationParameter.ts +79 -79
- package/src/structures/IReflectHttpOperationSuccess.ts +21 -21
- package/src/structures/ITypedApplication.ts +11 -11
- package/src/structures/ITypedHttpRouteException.ts +15 -15
- package/src/structures/ITypedHttpRouteParameter.ts +41 -41
- package/src/structures/ITypedHttpRouteSuccess.ts +22 -22
- package/src/transformers/IOperationMetadata.ts +46 -46
- package/src/transformers/ISdkOperationTransformerContext.ts +8 -8
- package/src/transformers/SdkOperationProgrammer.ts +240 -240
- package/src/transformers/SdkOperationTransformer.ts +248 -248
- package/src/transformers/TextPlainValidator.ts +17 -17
- package/src/utils/MetadataUtil.ts +26 -26
- package/src/validators/HttpHeadersValidator.ts +40 -40
- package/src/validators/HttpQueryValidator.ts +40 -40
|
@@ -1,260 +1,260 @@
|
|
|
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.isArrayTypeNode(typeNode)) {
|
|
84
|
-
const element: IReflectType = exploreNode(ctx, typeNode.elementType);
|
|
85
|
-
return {
|
|
86
|
-
name: "Array",
|
|
87
|
-
typeArguments: [element],
|
|
88
|
-
};
|
|
89
|
-
} else if (ts.isParenthesizedTypeNode(typeNode))
|
|
90
|
-
return {
|
|
91
|
-
name: `(${exploreNode(ctx, typeNode.type).name})`,
|
|
92
|
-
};
|
|
93
|
-
else if (ts.isTypeOperatorNode(typeNode)) {
|
|
94
|
-
const prefix: string | null =
|
|
95
|
-
typeNode.operator === ts.SyntaxKind.KeyOfKeyword
|
|
96
|
-
? "keyof"
|
|
97
|
-
: typeNode.operator === ts.SyntaxKind.UniqueKeyword
|
|
98
|
-
? "unique"
|
|
99
|
-
: typeNode.operator === ts.SyntaxKind.ReadonlyKeyword
|
|
100
|
-
? "readonly"
|
|
101
|
-
: null;
|
|
102
|
-
if (prefix === null)
|
|
103
|
-
return exploreType(ctx, ctx.checker.getTypeFromTypeNode(typeNode));
|
|
104
|
-
return {
|
|
105
|
-
name: `${prefix} ${exploreNode(ctx, typeNode.type).name}`,
|
|
106
|
-
};
|
|
107
|
-
} else if (ts.isTypePredicateNode(typeNode) || ts.isTypeQueryNode(typeNode))
|
|
108
|
-
return exploreType(ctx, ctx.checker.getTypeFromTypeNode(typeNode));
|
|
109
|
-
else if (ts.isTypeReferenceNode(typeNode) === false)
|
|
110
|
-
return {
|
|
111
|
-
name: typeNode.getText(),
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
// Find matched import statement
|
|
115
|
-
const name: string = typeNode.typeName.getText();
|
|
116
|
-
const prefix: string = name.split(".")[0]!;
|
|
117
|
-
|
|
118
|
-
let matched: boolean = false;
|
|
119
|
-
const insert = (imp: IReflectImport): void => {
|
|
120
|
-
matched ||= true;
|
|
121
|
-
ctx.container.push(imp);
|
|
122
|
-
};
|
|
123
|
-
for (const imp of ctx.imports)
|
|
124
|
-
if (prefix === imp.default)
|
|
125
|
-
insert({
|
|
126
|
-
file: imp.file,
|
|
127
|
-
asterisk: null,
|
|
128
|
-
default: prefix,
|
|
129
|
-
elements: [],
|
|
130
|
-
});
|
|
131
|
-
else if (prefix === imp.asterisk)
|
|
132
|
-
insert({
|
|
133
|
-
file: imp.file,
|
|
134
|
-
asterisk: prefix,
|
|
135
|
-
default: null,
|
|
136
|
-
elements: [],
|
|
137
|
-
});
|
|
138
|
-
else if (imp.elements.includes(prefix))
|
|
139
|
-
insert({
|
|
140
|
-
file: imp.file,
|
|
141
|
-
asterisk: null,
|
|
142
|
-
default: null,
|
|
143
|
-
elements: [prefix],
|
|
144
|
-
});
|
|
145
|
-
if (prefix !== "Promise" && matched === false)
|
|
146
|
-
return exploreType(ctx, ctx.checker.getTypeFromTypeNode(typeNode));
|
|
147
|
-
|
|
148
|
-
// Finalize with generic arguments
|
|
149
|
-
if (!!typeNode.typeArguments?.length) {
|
|
150
|
-
const top: ts.TypeNode = typeNode.typeArguments[0]!;
|
|
151
|
-
if (name === "Promise") return exploreNode(ctx, top);
|
|
152
|
-
return {
|
|
153
|
-
name,
|
|
154
|
-
typeArguments: typeNode.typeArguments.map((child) =>
|
|
155
|
-
exploreNode(ctx, child),
|
|
156
|
-
),
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
return { name };
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
const exploreType = (ctx: IContext, type: ts.Type): IReflectType => {
|
|
163
|
-
// Analyze symbol, and take special cares
|
|
164
|
-
const symbol: ts.Symbol | undefined = type.aliasSymbol ?? type.symbol;
|
|
165
|
-
if (type.aliasSymbol === undefined && type.isUnionOrIntersection()) {
|
|
166
|
-
const joiner: string = type.isIntersection() ? " & " : " | ";
|
|
167
|
-
return {
|
|
168
|
-
name: type.types
|
|
169
|
-
.map((child) => exploreType(ctx, child))
|
|
170
|
-
.map(getEscapedText)
|
|
171
|
-
.join(joiner),
|
|
172
|
-
};
|
|
173
|
-
} else if (ctx.checker.isArrayLikeType(type)) {
|
|
174
|
-
const arrayItem: ts.Type | undefined =
|
|
175
|
-
ctx.checker.getElementTypeOfArrayType(type);
|
|
176
|
-
if (arrayItem === undefined) return { name: "Array<any>" };
|
|
177
|
-
return {
|
|
178
|
-
name: "Array",
|
|
179
|
-
typeArguments: [exploreType(ctx, arrayItem)],
|
|
180
|
-
};
|
|
181
|
-
} else if (symbol === undefined)
|
|
182
|
-
return {
|
|
183
|
-
name: ctx.checker.typeToString(
|
|
184
|
-
type,
|
|
185
|
-
undefined,
|
|
186
|
-
ts.TypeFormatFlags.NoTruncation,
|
|
187
|
-
),
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
// Find matched import statement
|
|
191
|
-
const name: string = getNameOfSymbol(symbol);
|
|
192
|
-
const prefix: string = name.split(".")[0]!;
|
|
193
|
-
|
|
194
|
-
let matched: boolean = false;
|
|
195
|
-
const insert = (imp: IReflectImport): void => {
|
|
196
|
-
matched ||= true;
|
|
197
|
-
ctx.container.push(imp);
|
|
198
|
-
};
|
|
199
|
-
for (const imp of ctx.imports)
|
|
200
|
-
if (imp.elements.includes(prefix))
|
|
201
|
-
insert({
|
|
202
|
-
file: imp.file,
|
|
203
|
-
asterisk: null,
|
|
204
|
-
default: null,
|
|
205
|
-
elements: [prefix],
|
|
206
|
-
});
|
|
207
|
-
if (prefix !== "Promise" && matched === false)
|
|
208
|
-
emplaceSymbol(ctx, symbol, prefix);
|
|
209
|
-
|
|
210
|
-
// Finalize with generic arguments
|
|
211
|
-
const generic: readonly ts.Type[] = type.aliasSymbol
|
|
212
|
-
? (type.aliasTypeArguments ?? [])
|
|
213
|
-
: ctx.checker.getTypeArguments(type as ts.TypeReference);
|
|
214
|
-
return generic.length
|
|
215
|
-
? name === "Promise"
|
|
216
|
-
? exploreType(ctx, generic[0]!)
|
|
217
|
-
: {
|
|
218
|
-
name,
|
|
219
|
-
typeArguments: generic.map((child) => exploreType(ctx, child)),
|
|
220
|
-
}
|
|
221
|
-
: { name };
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
const emplaceSymbol = (
|
|
225
|
-
ctx: IContext,
|
|
226
|
-
symbol: ts.Symbol,
|
|
227
|
-
prefix: string,
|
|
228
|
-
): void => {
|
|
229
|
-
// GET SOURCE FILE
|
|
230
|
-
const sourceFile: ts.SourceFile | undefined =
|
|
231
|
-
symbol.declarations?.[0]?.getSourceFile();
|
|
232
|
-
if (sourceFile === undefined) return;
|
|
233
|
-
if (sourceFile.fileName.indexOf("/typescript/lib") === -1)
|
|
234
|
-
ctx.container.push({
|
|
235
|
-
file: sourceFile.fileName,
|
|
236
|
-
asterisk: null,
|
|
237
|
-
default: null,
|
|
238
|
-
elements: [prefix],
|
|
239
|
-
});
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const getEscapedText = (type: IReflectType): string =>
|
|
244
|
-
type.typeArguments
|
|
245
|
-
? `${type.name}<${type.typeArguments.map(getEscapedText).join(", ")}>`
|
|
246
|
-
: type.name;
|
|
247
|
-
|
|
248
|
-
const getNameOfSymbol = (symbol: ts.Symbol): string =>
|
|
249
|
-
exploreName(
|
|
250
|
-
symbol.escapedName.toString(),
|
|
251
|
-
symbol.getDeclarations()?.[0]?.parent,
|
|
252
|
-
);
|
|
253
|
-
|
|
254
|
-
const exploreName = (name: string, decl?: ts.Node): string =>
|
|
255
|
-
decl && ts.isModuleBlock(decl)
|
|
256
|
-
? exploreName(
|
|
257
|
-
`${decl.parent.name.getFullText().trim()}.${name}`,
|
|
258
|
-
decl.parent.parent,
|
|
259
|
-
)
|
|
260
|
-
: name;
|
|
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.isArrayTypeNode(typeNode)) {
|
|
84
|
+
const element: IReflectType = exploreNode(ctx, typeNode.elementType);
|
|
85
|
+
return {
|
|
86
|
+
name: "Array",
|
|
87
|
+
typeArguments: [element],
|
|
88
|
+
};
|
|
89
|
+
} else if (ts.isParenthesizedTypeNode(typeNode))
|
|
90
|
+
return {
|
|
91
|
+
name: `(${exploreNode(ctx, typeNode.type).name})`,
|
|
92
|
+
};
|
|
93
|
+
else if (ts.isTypeOperatorNode(typeNode)) {
|
|
94
|
+
const prefix: string | null =
|
|
95
|
+
typeNode.operator === ts.SyntaxKind.KeyOfKeyword
|
|
96
|
+
? "keyof"
|
|
97
|
+
: typeNode.operator === ts.SyntaxKind.UniqueKeyword
|
|
98
|
+
? "unique"
|
|
99
|
+
: typeNode.operator === ts.SyntaxKind.ReadonlyKeyword
|
|
100
|
+
? "readonly"
|
|
101
|
+
: null;
|
|
102
|
+
if (prefix === null)
|
|
103
|
+
return exploreType(ctx, ctx.checker.getTypeFromTypeNode(typeNode));
|
|
104
|
+
return {
|
|
105
|
+
name: `${prefix} ${exploreNode(ctx, typeNode.type).name}`,
|
|
106
|
+
};
|
|
107
|
+
} else if (ts.isTypePredicateNode(typeNode) || ts.isTypeQueryNode(typeNode))
|
|
108
|
+
return exploreType(ctx, ctx.checker.getTypeFromTypeNode(typeNode));
|
|
109
|
+
else if (ts.isTypeReferenceNode(typeNode) === false)
|
|
110
|
+
return {
|
|
111
|
+
name: typeNode.getText(),
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Find matched import statement
|
|
115
|
+
const name: string = typeNode.typeName.getText();
|
|
116
|
+
const prefix: string = name.split(".")[0]!;
|
|
117
|
+
|
|
118
|
+
let matched: boolean = false;
|
|
119
|
+
const insert = (imp: IReflectImport): void => {
|
|
120
|
+
matched ||= true;
|
|
121
|
+
ctx.container.push(imp);
|
|
122
|
+
};
|
|
123
|
+
for (const imp of ctx.imports)
|
|
124
|
+
if (prefix === imp.default)
|
|
125
|
+
insert({
|
|
126
|
+
file: imp.file,
|
|
127
|
+
asterisk: null,
|
|
128
|
+
default: prefix,
|
|
129
|
+
elements: [],
|
|
130
|
+
});
|
|
131
|
+
else if (prefix === imp.asterisk)
|
|
132
|
+
insert({
|
|
133
|
+
file: imp.file,
|
|
134
|
+
asterisk: prefix,
|
|
135
|
+
default: null,
|
|
136
|
+
elements: [],
|
|
137
|
+
});
|
|
138
|
+
else if (imp.elements.includes(prefix))
|
|
139
|
+
insert({
|
|
140
|
+
file: imp.file,
|
|
141
|
+
asterisk: null,
|
|
142
|
+
default: null,
|
|
143
|
+
elements: [prefix],
|
|
144
|
+
});
|
|
145
|
+
if (prefix !== "Promise" && matched === false)
|
|
146
|
+
return exploreType(ctx, ctx.checker.getTypeFromTypeNode(typeNode));
|
|
147
|
+
|
|
148
|
+
// Finalize with generic arguments
|
|
149
|
+
if (!!typeNode.typeArguments?.length) {
|
|
150
|
+
const top: ts.TypeNode = typeNode.typeArguments[0]!;
|
|
151
|
+
if (name === "Promise") return exploreNode(ctx, top);
|
|
152
|
+
return {
|
|
153
|
+
name,
|
|
154
|
+
typeArguments: typeNode.typeArguments.map((child) =>
|
|
155
|
+
exploreNode(ctx, child),
|
|
156
|
+
),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return { name };
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const exploreType = (ctx: IContext, type: ts.Type): IReflectType => {
|
|
163
|
+
// Analyze symbol, and take special cares
|
|
164
|
+
const symbol: ts.Symbol | undefined = type.aliasSymbol ?? type.symbol;
|
|
165
|
+
if (type.aliasSymbol === undefined && type.isUnionOrIntersection()) {
|
|
166
|
+
const joiner: string = type.isIntersection() ? " & " : " | ";
|
|
167
|
+
return {
|
|
168
|
+
name: type.types
|
|
169
|
+
.map((child) => exploreType(ctx, child))
|
|
170
|
+
.map(getEscapedText)
|
|
171
|
+
.join(joiner),
|
|
172
|
+
};
|
|
173
|
+
} else if (ctx.checker.isArrayLikeType(type)) {
|
|
174
|
+
const arrayItem: ts.Type | undefined =
|
|
175
|
+
ctx.checker.getElementTypeOfArrayType(type);
|
|
176
|
+
if (arrayItem === undefined) return { name: "Array<any>" };
|
|
177
|
+
return {
|
|
178
|
+
name: "Array",
|
|
179
|
+
typeArguments: [exploreType(ctx, arrayItem)],
|
|
180
|
+
};
|
|
181
|
+
} else if (symbol === undefined)
|
|
182
|
+
return {
|
|
183
|
+
name: ctx.checker.typeToString(
|
|
184
|
+
type,
|
|
185
|
+
undefined,
|
|
186
|
+
ts.TypeFormatFlags.NoTruncation,
|
|
187
|
+
),
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// Find matched import statement
|
|
191
|
+
const name: string = getNameOfSymbol(symbol);
|
|
192
|
+
const prefix: string = name.split(".")[0]!;
|
|
193
|
+
|
|
194
|
+
let matched: boolean = false;
|
|
195
|
+
const insert = (imp: IReflectImport): void => {
|
|
196
|
+
matched ||= true;
|
|
197
|
+
ctx.container.push(imp);
|
|
198
|
+
};
|
|
199
|
+
for (const imp of ctx.imports)
|
|
200
|
+
if (imp.elements.includes(prefix))
|
|
201
|
+
insert({
|
|
202
|
+
file: imp.file,
|
|
203
|
+
asterisk: null,
|
|
204
|
+
default: null,
|
|
205
|
+
elements: [prefix],
|
|
206
|
+
});
|
|
207
|
+
if (prefix !== "Promise" && matched === false)
|
|
208
|
+
emplaceSymbol(ctx, symbol, prefix);
|
|
209
|
+
|
|
210
|
+
// Finalize with generic arguments
|
|
211
|
+
const generic: readonly ts.Type[] = type.aliasSymbol
|
|
212
|
+
? (type.aliasTypeArguments ?? [])
|
|
213
|
+
: ctx.checker.getTypeArguments(type as ts.TypeReference);
|
|
214
|
+
return generic.length
|
|
215
|
+
? name === "Promise"
|
|
216
|
+
? exploreType(ctx, generic[0]!)
|
|
217
|
+
: {
|
|
218
|
+
name,
|
|
219
|
+
typeArguments: generic.map((child) => exploreType(ctx, child)),
|
|
220
|
+
}
|
|
221
|
+
: { name };
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const emplaceSymbol = (
|
|
225
|
+
ctx: IContext,
|
|
226
|
+
symbol: ts.Symbol,
|
|
227
|
+
prefix: string,
|
|
228
|
+
): void => {
|
|
229
|
+
// GET SOURCE FILE
|
|
230
|
+
const sourceFile: ts.SourceFile | undefined =
|
|
231
|
+
symbol.declarations?.[0]?.getSourceFile();
|
|
232
|
+
if (sourceFile === undefined) return;
|
|
233
|
+
if (sourceFile.fileName.indexOf("/typescript/lib") === -1)
|
|
234
|
+
ctx.container.push({
|
|
235
|
+
file: sourceFile.fileName,
|
|
236
|
+
asterisk: null,
|
|
237
|
+
default: null,
|
|
238
|
+
elements: [prefix],
|
|
239
|
+
});
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const getEscapedText = (type: IReflectType): string =>
|
|
244
|
+
type.typeArguments
|
|
245
|
+
? `${type.name}<${type.typeArguments.map(getEscapedText).join(", ")}>`
|
|
246
|
+
: type.name;
|
|
247
|
+
|
|
248
|
+
const getNameOfSymbol = (symbol: ts.Symbol): string =>
|
|
249
|
+
exploreName(
|
|
250
|
+
symbol.escapedName.toString(),
|
|
251
|
+
symbol.getDeclarations()?.[0]?.parent,
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
const exploreName = (name: string, decl?: ts.Node): string =>
|
|
255
|
+
decl && ts.isModuleBlock(decl)
|
|
256
|
+
? exploreName(
|
|
257
|
+
`${decl.parent.name.getFullText().trim()}.${name}`,
|
|
258
|
+
decl.parent.parent,
|
|
259
|
+
)
|
|
260
|
+
: name;
|