@nestia/sdk 12.0.0 → 12.1.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/assets/bundle/distribute/package.json +1 -1
- package/assets/config/nestia.config.ts +19 -19
- package/lib/NestiaSwaggerComposer.js +2 -0
- package/lib/NestiaSwaggerComposer.js.map +1 -1
- package/lib/analyses/ImportAnalyzer.d.ts +6 -5
- package/lib/analyses/ImportAnalyzer.js +30 -15
- package/lib/analyses/ImportAnalyzer.js.map +1 -1
- package/lib/analyses/ReflectControllerAnalyzer.js +18 -9
- package/lib/analyses/ReflectControllerAnalyzer.js.map +1 -1
- package/lib/analyses/ReflectHttpOperationAnalyzer.d.ts +1 -1
- package/lib/analyses/ReflectHttpOperationAnalyzer.js +8 -6
- package/lib/analyses/ReflectHttpOperationAnalyzer.js.map +1 -1
- package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.d.ts +1 -1
- package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.js.map +1 -1
- package/lib/analyses/ReflectHttpOperationParameterAnalyzer.d.ts +1 -1
- package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js +1 -1
- package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js.map +1 -1
- package/lib/analyses/ReflectWebSocketOperationAnalyzer.d.ts +1 -1
- package/lib/analyses/ReflectWebSocketOperationAnalyzer.js +10 -6
- package/lib/analyses/ReflectWebSocketOperationAnalyzer.js.map +1 -1
- package/lib/analyses/TypedHttpRouteAnalyzer.js +13 -7
- package/lib/analyses/TypedHttpRouteAnalyzer.js.map +1 -1
- package/lib/executable/internal/NestiaSdkCommand.js +7 -4
- package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
- package/lib/generates/E2eGenerator.js +1 -4
- package/lib/generates/E2eGenerator.js.map +1 -1
- package/lib/generates/SdkGenerator.js +1 -4
- package/lib/generates/SdkGenerator.js.map +1 -1
- package/lib/generates/SwaggerGenerator.js +5 -5
- package/lib/generates/SwaggerGenerator.js.map +1 -1
- package/lib/generates/internal/ImportDictionary.js +14 -6
- package/lib/generates/internal/ImportDictionary.js.map +1 -1
- package/lib/generates/internal/SdkDistributionComposer.js +27 -22
- package/lib/generates/internal/SdkDistributionComposer.js.map +1 -1
- package/lib/generates/internal/SdkFileProgrammer.js +1 -4
- package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkHttpCloneReferencer.js +13 -9
- package/lib/generates/internal/SdkHttpCloneReferencer.js.map +1 -1
- package/lib/generates/internal/SdkWebSocketCloneProgrammer.js +6 -3
- package/lib/generates/internal/SdkWebSocketCloneProgrammer.js.map +1 -1
- package/lib/generates/internal/SwaggerOperationComposer.d.ts +1 -1
- package/lib/generates/internal/SwaggerOperationComposer.js.map +1 -1
- package/lib/internal/legacy.d.ts +44 -46
- package/lib/internal/legacy.js +35 -48
- package/lib/internal/legacy.js.map +1 -1
- package/lib/structures/IReflectHttpOperationException.d.ts +1 -1
- package/lib/structures/IReflectHttpOperationParameter.d.ts +1 -1
- package/lib/structures/IReflectImport.d.ts +2 -0
- package/lib/structures/ITypedHttpRouteParameter.d.ts +1 -1
- package/lib/utils/TsConfigReader.js +3 -1
- package/lib/utils/TsConfigReader.js.map +1 -1
- package/lib/validators/HttpHeadersValidator.d.ts +3 -2
- package/lib/validators/HttpHeadersValidator.js +3 -2
- package/lib/validators/HttpHeadersValidator.js.map +1 -1
- package/lib/validators/HttpQueryValidator.d.ts +4 -4
- package/lib/validators/HttpQueryValidator.js +4 -4
- package/native/sdk/register.go +6 -35
- package/native/sdk/sdk_transform.go +80 -304
- package/package.json +9 -9
- package/src/NestiaSwaggerComposer.ts +2 -0
- package/src/analyses/ImportAnalyzer.ts +24 -15
- package/src/analyses/ReflectControllerAnalyzer.ts +19 -10
- package/src/analyses/ReflectHttpOperationAnalyzer.ts +5 -2
- package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +2 -2
- package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +3 -3
- package/src/analyses/ReflectWebSocketOperationAnalyzer.ts +14 -7
- package/src/analyses/TypedHttpRouteAnalyzer.ts +74 -35
- package/src/executable/internal/NestiaSdkCommand.ts +8 -5
- package/src/generates/E2eGenerator.ts +1 -3
- package/src/generates/SdkGenerator.ts +1 -3
- package/src/generates/SwaggerGenerator.ts +5 -6
- package/src/generates/internal/ImportDictionary.ts +23 -11
- package/src/generates/internal/SdkDistributionComposer.ts +25 -23
- package/src/generates/internal/SdkFileProgrammer.ts +1 -3
- package/src/generates/internal/SdkHttpCloneReferencer.ts +15 -10
- package/src/generates/internal/SdkWebSocketCloneProgrammer.ts +4 -3
- package/src/generates/internal/SwaggerOperationComposer.ts +1 -1
- package/src/internal/legacy.ts +83 -73
- package/src/structures/IReflectHttpOperationException.ts +1 -1
- package/src/structures/IReflectHttpOperationParameter.ts +1 -1
- package/src/structures/IReflectImport.ts +2 -0
- package/src/structures/ITypedApplication.ts +0 -1
- package/src/structures/ITypedHttpRouteException.ts +0 -1
- package/src/structures/ITypedHttpRouteParameter.ts +1 -1
- package/src/utils/TsConfigReader.ts +11 -3
- package/src/validators/HttpHeadersValidator.ts +3 -2
- package/src/validators/HttpQueryValidator.ts +4 -4
|
@@ -6,11 +6,11 @@ import {
|
|
|
6
6
|
|
|
7
7
|
import { INestiaProject } from "../structures/INestiaProject";
|
|
8
8
|
import { INestiaSdkInput } from "../structures/INestiaSdkInput";
|
|
9
|
+
import { IOperationMetadata } from "../structures/IOperationMetadata";
|
|
9
10
|
import { IReflectController } from "../structures/IReflectController";
|
|
10
11
|
import { IReflectHttpOperation } from "../structures/IReflectHttpOperation";
|
|
11
12
|
import { IReflectMcpOperation } from "../structures/IReflectMcpOperation";
|
|
12
13
|
import { IReflectWebSocketOperation } from "../structures/IReflectWebSocketOperation";
|
|
13
|
-
import { IOperationMetadata } from "../structures/IOperationMetadata";
|
|
14
14
|
import { ArrayUtil } from "../utils/ArrayUtil";
|
|
15
15
|
import { ReflectHttpOperationAnalyzer } from "./ReflectHttpOperationAnalyzer";
|
|
16
16
|
import { ReflectMcpOperationAnalyzer } from "./ReflectMcpOperationAnalyzer";
|
|
@@ -97,16 +97,25 @@ export namespace ReflectControllerAnalyzer {
|
|
|
97
97
|
};
|
|
98
98
|
|
|
99
99
|
function _Get_prototype_entries(creator: any): Array<[string, unknown]> {
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
key,
|
|
103
|
-
creator.prototype[key],
|
|
104
|
-
]);
|
|
100
|
+
const visited: Set<string> = new Set();
|
|
101
|
+
return iterate(creator);
|
|
105
102
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
103
|
+
function iterate(target: any): Array<[string, unknown]> {
|
|
104
|
+
const keyList: string[] = Object.getOwnPropertyNames(
|
|
105
|
+
target.prototype,
|
|
106
|
+
).filter((key) => {
|
|
107
|
+
if (visited.has(key)) return false;
|
|
108
|
+
visited.add(key);
|
|
109
|
+
return true;
|
|
110
|
+
});
|
|
111
|
+
const entries: Array<[string, unknown]> = keyList.map((key) => [
|
|
112
|
+
key,
|
|
113
|
+
target.prototype[key],
|
|
114
|
+
]);
|
|
109
115
|
|
|
110
|
-
|
|
116
|
+
const parent: any = Object.getPrototypeOf(target);
|
|
117
|
+
if (parent.prototype !== undefined) entries.push(...iterate(parent));
|
|
118
|
+
return entries;
|
|
119
|
+
}
|
|
111
120
|
}
|
|
112
121
|
}
|
|
@@ -18,7 +18,8 @@ import { ReflectMetadataAnalyzer } from "./ReflectMetadataAnalyzer";
|
|
|
18
18
|
|
|
19
19
|
export namespace ReflectHttpOperationAnalyzer {
|
|
20
20
|
export interface IProps {
|
|
21
|
-
project: Omit<INestiaProject, "config"
|
|
21
|
+
project: Omit<INestiaProject, "config"> &
|
|
22
|
+
Partial<Pick<INestiaProject, "config">>;
|
|
22
23
|
controller: IReflectController;
|
|
23
24
|
function: Function;
|
|
24
25
|
name: string;
|
|
@@ -107,7 +108,9 @@ export namespace ReflectHttpOperationAnalyzer {
|
|
|
107
108
|
.filter((x) => parameters.some((y) => x.index === y.index))
|
|
108
109
|
.map((x) => x.imports),
|
|
109
110
|
...(success.binary === true ? [] : props.metadata.success.imports),
|
|
110
|
-
...
|
|
111
|
+
...(props.project.config?.propagate === true
|
|
112
|
+
? Object.values(props.metadata.exceptions).map((e) => e.imports)
|
|
113
|
+
: []),
|
|
111
114
|
].flat(),
|
|
112
115
|
),
|
|
113
116
|
description: props.metadata.description,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { TypedException } from "@nestia/core";
|
|
2
|
-
import { JsonMetadataFactory } from "../internal/legacy";
|
|
3
2
|
|
|
3
|
+
import { JsonMetadataFactory } from "../internal/legacy";
|
|
4
|
+
import { IOperationMetadata } from "../structures/IOperationMetadata";
|
|
4
5
|
import { IReflectController } from "../structures/IReflectController";
|
|
5
6
|
import { IReflectHttpOperationException } from "../structures/IReflectHttpOperationException";
|
|
6
7
|
import { IReflectOperationError } from "../structures/IReflectOperationError";
|
|
7
|
-
import { IOperationMetadata } from "../structures/IOperationMetadata";
|
|
8
8
|
|
|
9
9
|
export namespace ReflectHttpOperationExceptionAnalyzer {
|
|
10
10
|
export interface IContext {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SwaggerExample } from "@nestia/core";
|
|
2
2
|
import { ROUTE_ARGS_METADATA } from "@nestjs/common/constants";
|
|
3
3
|
import { RouteParamtypes } from "@nestjs/common/enums/route-paramtypes.enum";
|
|
4
|
+
|
|
4
5
|
import {
|
|
5
6
|
HttpFormDataProgrammer,
|
|
6
7
|
HttpHeadersProgrammer,
|
|
@@ -8,14 +9,13 @@ import {
|
|
|
8
9
|
HttpQueryProgrammer,
|
|
9
10
|
JsonMetadataFactory,
|
|
10
11
|
} from "../internal/legacy";
|
|
11
|
-
|
|
12
|
+
import { IOperationMetadata } from "../structures/IOperationMetadata";
|
|
12
13
|
import { IReflectController } from "../structures/IReflectController";
|
|
13
14
|
import { IReflectHttpOperationParameter } from "../structures/IReflectHttpOperationParameter";
|
|
14
15
|
import { IReflectOperationError } from "../structures/IReflectOperationError";
|
|
15
|
-
import { IOperationMetadata } from "../structures/IOperationMetadata";
|
|
16
|
-
import { TextPlainValidator } from "../validators/TextPlainValidator";
|
|
17
16
|
import { HttpHeadersValidator } from "../validators/HttpHeadersValidator";
|
|
18
17
|
import { HttpQueryValidator } from "../validators/HttpQueryValidator";
|
|
18
|
+
import { TextPlainValidator } from "../validators/TextPlainValidator";
|
|
19
19
|
|
|
20
20
|
export namespace ReflectHttpOperationParameterAnalyzer {
|
|
21
21
|
export interface IContext {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ranges } from "tstl";
|
|
2
2
|
|
|
3
3
|
import { INestiaProject } from "../structures/INestiaProject";
|
|
4
|
+
import { IOperationMetadata } from "../structures/IOperationMetadata";
|
|
4
5
|
import { IReflectController } from "../structures/IReflectController";
|
|
5
6
|
import { IReflectImport } from "../structures/IReflectImport";
|
|
6
7
|
import { IReflectWebSocketOperation } from "../structures/IReflectWebSocketOperation";
|
|
7
8
|
import { IReflectWebSocketOperationParameter } from "../structures/IReflectWebSocketOperationParameter";
|
|
8
|
-
import { IOperationMetadata } from "../structures/IOperationMetadata";
|
|
9
9
|
import { StringUtil } from "../utils/StringUtil";
|
|
10
10
|
import { ImportAnalyzer } from "./ImportAnalyzer";
|
|
11
11
|
import { PathAnalyzer } from "./PathAnalyzer";
|
|
@@ -53,34 +53,41 @@ export namespace ReflectWebSocketOperationAnalyzer {
|
|
|
53
53
|
const imports: IReflectImport[] = [];
|
|
54
54
|
const parameters: IReflectWebSocketOperationParameter[] = preconfigured
|
|
55
55
|
.map((p) => {
|
|
56
|
+
const reject = (message: string): null => {
|
|
57
|
+
errors.push(message);
|
|
58
|
+
return null;
|
|
59
|
+
};
|
|
60
|
+
|
|
56
61
|
// METADATA INFO
|
|
57
62
|
const matched: IOperationMetadata.IParameter | undefined =
|
|
58
63
|
ctx.metadata.parameters.find((m) => p.index === m.index);
|
|
59
64
|
|
|
60
65
|
// VALIDATE PARAMETER
|
|
61
66
|
if (matched === undefined)
|
|
62
|
-
return
|
|
67
|
+
return reject(
|
|
63
68
|
`Unable to find parameter type of the ${p.index} (th).`,
|
|
64
69
|
);
|
|
65
70
|
else if (matched.type === null)
|
|
66
|
-
return
|
|
71
|
+
return reject(
|
|
67
72
|
`Failed to analyze the parameter type of the ${JSON.stringify(matched.name)}.`,
|
|
68
73
|
);
|
|
69
74
|
else if (
|
|
70
75
|
p.category === "param" &&
|
|
71
76
|
!(p as IReflectWebSocketOperationParameter.IParam).field?.length
|
|
72
77
|
)
|
|
73
|
-
return
|
|
78
|
+
return reject(`@WebSocketRoute.Param() must have a field name.`);
|
|
74
79
|
else if (
|
|
75
80
|
p.category === "acceptor" &&
|
|
76
81
|
matched.type?.typeArguments?.length !== 3
|
|
77
82
|
)
|
|
78
|
-
return
|
|
83
|
+
return reject(
|
|
84
|
+
`@WebSocketRoute.Acceptor() must have three type arguments.`,
|
|
85
|
+
);
|
|
79
86
|
else if (
|
|
80
87
|
p.category === "driver" &&
|
|
81
88
|
matched.type?.typeArguments?.length !== 1
|
|
82
89
|
)
|
|
83
|
-
return
|
|
90
|
+
return reject(
|
|
84
91
|
`@WebSocketRoute.Driver() must have one type argument.`,
|
|
85
92
|
);
|
|
86
93
|
|
|
@@ -119,7 +126,7 @@ export namespace ReflectWebSocketOperationAnalyzer {
|
|
|
119
126
|
// UNKNOWN TYPE, MAYBE NEW FEATURE
|
|
120
127
|
else {
|
|
121
128
|
if (p.category !== "header")
|
|
122
|
-
|
|
129
|
+
reject(
|
|
123
130
|
`@WebSocketRoute.${StringUtil.capitalize(p.category)}() has not been supported yet. How about upgrading the nestia packages?`,
|
|
124
131
|
);
|
|
125
132
|
return null;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { NamingConvention } from "@typia/utils";
|
|
2
|
+
import { IMetadataComponents, IMetadataSchema } from "typia";
|
|
3
|
+
|
|
1
4
|
import {
|
|
2
5
|
IMetadataDictionary,
|
|
3
6
|
MetadataAliasType,
|
|
@@ -8,9 +11,6 @@ import {
|
|
|
8
11
|
MetadataSchema,
|
|
9
12
|
MetadataTupleType,
|
|
10
13
|
} from "../internal/legacy";
|
|
11
|
-
import { NamingConvention } from "@typia/utils";
|
|
12
|
-
import { IMetadataComponents, IMetadataSchema } from "typia";
|
|
13
|
-
|
|
14
14
|
import { IReflectController } from "../structures/IReflectController";
|
|
15
15
|
import { IReflectHttpOperation } from "../structures/IReflectHttpOperation";
|
|
16
16
|
import { IReflectOperationError } from "../structures/IReflectOperationError";
|
|
@@ -265,7 +265,8 @@ const renameDuplicateComponents = (routes: ITypedHttpRoute[]): void => {
|
|
|
265
265
|
}
|
|
266
266
|
}
|
|
267
267
|
for (const route of routes)
|
|
268
|
-
for (const metadata of routeMetadatas(route))
|
|
268
|
+
for (const metadata of routeMetadatas(route))
|
|
269
|
+
clearMetadataNameCache(metadata);
|
|
269
270
|
};
|
|
270
271
|
|
|
271
272
|
const routeMetadatas = (route: ITypedHttpRoute): MetadataSchema[] => [
|
|
@@ -308,29 +309,49 @@ const collectComponentEntries = (
|
|
|
308
309
|
collectComponentEntries(entries, route, map.value, visited);
|
|
309
310
|
}
|
|
310
311
|
for (const array of metadata.arrays)
|
|
311
|
-
if (visited.arrays.has(
|
|
312
|
-
visited.arrays.add(
|
|
313
|
-
entries.push(
|
|
314
|
-
|
|
312
|
+
if (visited.arrays.has(array.type as MetadataArrayType) === false) {
|
|
313
|
+
visited.arrays.add(array.type as MetadataArrayType);
|
|
314
|
+
entries.push(
|
|
315
|
+
componentEntry(route, "arrays", array.type as MetadataArrayType),
|
|
316
|
+
);
|
|
317
|
+
collectComponentEntries(
|
|
318
|
+
entries,
|
|
319
|
+
route,
|
|
320
|
+
(array.type as MetadataArrayType as MetadataArrayType).value,
|
|
321
|
+
visited,
|
|
322
|
+
);
|
|
315
323
|
}
|
|
316
324
|
for (const tuple of metadata.tuples)
|
|
317
|
-
if (visited.tuples.has(
|
|
318
|
-
visited.tuples.add(
|
|
319
|
-
entries.push(
|
|
320
|
-
|
|
325
|
+
if (visited.tuples.has(tuple.type as MetadataTupleType) === false) {
|
|
326
|
+
visited.tuples.add(tuple.type as MetadataTupleType);
|
|
327
|
+
entries.push(
|
|
328
|
+
componentEntry(route, "tuples", tuple.type as MetadataTupleType),
|
|
329
|
+
);
|
|
330
|
+
for (const elem of (tuple.type as MetadataTupleType as MetadataTupleType)
|
|
331
|
+
.elements)
|
|
321
332
|
collectComponentEntries(entries, route, elem, visited);
|
|
322
333
|
}
|
|
323
334
|
for (const alias of metadata.aliases)
|
|
324
|
-
if (visited.aliases.has(
|
|
325
|
-
visited.aliases.add(
|
|
326
|
-
entries.push(
|
|
327
|
-
|
|
335
|
+
if (visited.aliases.has(alias.type as MetadataAliasType) === false) {
|
|
336
|
+
visited.aliases.add(alias.type as MetadataAliasType);
|
|
337
|
+
entries.push(
|
|
338
|
+
componentEntry(route, "aliases", alias.type as MetadataAliasType),
|
|
339
|
+
);
|
|
340
|
+
collectComponentEntries(
|
|
341
|
+
entries,
|
|
342
|
+
route,
|
|
343
|
+
(alias.type as MetadataAliasType as MetadataAliasType).value,
|
|
344
|
+
visited,
|
|
345
|
+
);
|
|
328
346
|
}
|
|
329
347
|
for (const obj of metadata.objects)
|
|
330
|
-
if (visited.objects.has(
|
|
331
|
-
visited.objects.add(
|
|
332
|
-
entries.push(
|
|
333
|
-
|
|
348
|
+
if (visited.objects.has(obj.type as MetadataObjectType) === false) {
|
|
349
|
+
visited.objects.add(obj.type as MetadataObjectType);
|
|
350
|
+
entries.push(
|
|
351
|
+
componentEntry(route, "objects", obj.type as MetadataObjectType),
|
|
352
|
+
);
|
|
353
|
+
for (const p of (obj.type as MetadataObjectType as MetadataObjectType)
|
|
354
|
+
.properties) {
|
|
334
355
|
collectComponentEntries(entries, route, p.key, visited);
|
|
335
356
|
collectComponentEntries(entries, route, p.value, visited);
|
|
336
357
|
}
|
|
@@ -393,20 +414,28 @@ const clearMetadataNameCache = (
|
|
|
393
414
|
}
|
|
394
415
|
for (const array of metadata.arrays) {
|
|
395
416
|
(array as unknown as { name_?: string }).name_ = undefined;
|
|
396
|
-
clearMetadataNameCache(
|
|
417
|
+
clearMetadataNameCache(
|
|
418
|
+
(array.type as MetadataArrayType as MetadataArrayType).value,
|
|
419
|
+
visited,
|
|
420
|
+
);
|
|
397
421
|
}
|
|
398
422
|
for (const tuple of metadata.tuples) {
|
|
399
423
|
(tuple as unknown as { name_?: string }).name_ = undefined;
|
|
400
|
-
for (const elem of (
|
|
424
|
+
for (const elem of (tuple.type as MetadataTupleType as MetadataTupleType)
|
|
425
|
+
.elements)
|
|
401
426
|
clearMetadataNameCache(elem, visited);
|
|
402
427
|
}
|
|
403
428
|
for (const alias of metadata.aliases) {
|
|
404
429
|
(alias as unknown as { name_?: string }).name_ = undefined;
|
|
405
|
-
clearMetadataNameCache(
|
|
430
|
+
clearMetadataNameCache(
|
|
431
|
+
(alias.type as MetadataAliasType as MetadataAliasType).value,
|
|
432
|
+
visited,
|
|
433
|
+
);
|
|
406
434
|
}
|
|
407
435
|
for (const obj of metadata.objects) {
|
|
408
436
|
(obj as unknown as { name_?: string }).name_ = undefined;
|
|
409
|
-
for (const p of (
|
|
437
|
+
for (const p of (obj.type as MetadataObjectType as MetadataObjectType)
|
|
438
|
+
.properties) {
|
|
410
439
|
clearMetadataNameCache(p.key, visited);
|
|
411
440
|
clearMetadataNameCache(p.value, visited);
|
|
412
441
|
}
|
|
@@ -433,8 +462,7 @@ const uniqueComponents = <T extends { name: string }>(input: T[]): T[] => {
|
|
|
433
462
|
const dict: Record<string, T> = {};
|
|
434
463
|
for (const elem of input) {
|
|
435
464
|
const oldbie: T | undefined = dict[elem.name];
|
|
436
|
-
if (oldbie === undefined)
|
|
437
|
-
dict[elem.name] = elem;
|
|
465
|
+
if (oldbie === undefined) dict[elem.name] = elem;
|
|
438
466
|
else if (
|
|
439
467
|
elem.name.includes(".") ||
|
|
440
468
|
componentScore(oldbie) < componentScore(elem)
|
|
@@ -459,7 +487,8 @@ const enrollMetadata = (
|
|
|
459
487
|
if (visited.schemas.has(metadata)) return;
|
|
460
488
|
visited.schemas.add(metadata);
|
|
461
489
|
|
|
462
|
-
if (metadata.rest !== null)
|
|
490
|
+
if (metadata.rest !== null)
|
|
491
|
+
enrollMetadata(dictionary, metadata.rest, visited);
|
|
463
492
|
if (metadata.escaped !== null) {
|
|
464
493
|
enrollMetadata(dictionary, metadata.escaped.original, visited);
|
|
465
494
|
enrollMetadata(dictionary, metadata.escaped.returns, visited);
|
|
@@ -476,18 +505,28 @@ const enrollMetadata = (
|
|
|
476
505
|
enrollMetadata(dictionary, map.value, visited);
|
|
477
506
|
}
|
|
478
507
|
for (const array of metadata.arrays)
|
|
479
|
-
if (enroll(dictionary.arrays,
|
|
480
|
-
enrollMetadata(
|
|
508
|
+
if (enroll(dictionary.arrays, array.type as MetadataArrayType))
|
|
509
|
+
enrollMetadata(
|
|
510
|
+
dictionary,
|
|
511
|
+
(array.type as MetadataArrayType as MetadataArrayType).value,
|
|
512
|
+
visited,
|
|
513
|
+
);
|
|
481
514
|
for (const tuple of metadata.tuples)
|
|
482
|
-
if (enroll(dictionary.tuples,
|
|
483
|
-
for (const elem of (
|
|
515
|
+
if (enroll(dictionary.tuples, tuple.type as MetadataTupleType))
|
|
516
|
+
for (const elem of (tuple.type as MetadataTupleType as MetadataTupleType)
|
|
517
|
+
.elements)
|
|
484
518
|
enrollMetadata(dictionary, elem, visited);
|
|
485
519
|
for (const alias of metadata.aliases)
|
|
486
|
-
if (enroll(dictionary.aliases,
|
|
487
|
-
enrollMetadata(
|
|
520
|
+
if (enroll(dictionary.aliases, alias.type as MetadataAliasType))
|
|
521
|
+
enrollMetadata(
|
|
522
|
+
dictionary,
|
|
523
|
+
(alias.type as MetadataAliasType as MetadataAliasType).value,
|
|
524
|
+
visited,
|
|
525
|
+
);
|
|
488
526
|
for (const obj of metadata.objects)
|
|
489
|
-
if (enroll(dictionary.objects,
|
|
490
|
-
for (const p of (
|
|
527
|
+
if (enroll(dictionary.objects, obj.type as MetadataObjectType))
|
|
528
|
+
for (const p of (obj.type as MetadataObjectType as MetadataObjectType)
|
|
529
|
+
.properties) {
|
|
491
530
|
enrollMetadata(dictionary, p.key, visited);
|
|
492
531
|
enrollMetadata(dictionary, p.value, visited);
|
|
493
532
|
}
|
|
@@ -106,14 +106,17 @@ export namespace NestiaSdkCommand {
|
|
|
106
106
|
extension: string;
|
|
107
107
|
}): string | null => {
|
|
108
108
|
const argv: string[] = process.argv.slice(3);
|
|
109
|
-
if (argv.length === 0) return null;
|
|
110
|
-
|
|
111
109
|
const index: number = argv.findIndex((str) => str === `--${props.type}`);
|
|
112
110
|
if (index === -1) return null;
|
|
113
|
-
else if (argv.length === 1)
|
|
114
|
-
throw new Error(`${props.type} file must be provided`);
|
|
115
111
|
|
|
116
|
-
|
|
112
|
+
// Bound the VALUE position, not the whole argument list. The two only
|
|
113
|
+
// coincide when the flag is the sole argument, so any preceding token used
|
|
114
|
+
// to send `undefined` into endsWith() and report a TypeError instead of this
|
|
115
|
+
// diagnostic. A following flag is a missing value too, not a badly named
|
|
116
|
+
// file.
|
|
117
|
+
const file: string | undefined = argv[index + 1];
|
|
118
|
+
if (file === undefined || file.startsWith("--"))
|
|
119
|
+
throw new Error(`${props.type} file must be provided`);
|
|
117
120
|
if (file.endsWith(props.extension) === false)
|
|
118
121
|
throw new Error(`${props.type} file must be ${props.extension} file`);
|
|
119
122
|
return file;
|
|
@@ -19,9 +19,7 @@ export namespace SdkGenerator {
|
|
|
19
19
|
|
|
20
20
|
// PREPARE NEW DIRECTORIES
|
|
21
21
|
console.log("Generating SDK Library");
|
|
22
|
-
|
|
23
|
-
await fs.promises.mkdir(app.project.config.output);
|
|
24
|
-
} catch {}
|
|
22
|
+
await fs.promises.mkdir(app.project.config.output, { recursive: true });
|
|
25
23
|
|
|
26
24
|
// BUNDLING
|
|
27
25
|
await bundle(app.project.config.output);
|
|
@@ -35,19 +35,18 @@ export namespace SwaggerGenerator {
|
|
|
35
35
|
|
|
36
36
|
// TARGET LOCATION
|
|
37
37
|
const parsed: path.ParsedPath = path.parse(config.output);
|
|
38
|
-
const
|
|
38
|
+
const location: string = !!parsed.ext
|
|
39
|
+
? path.resolve(config.output)
|
|
40
|
+
: path.join(path.resolve(config.output), "swagger.json");
|
|
41
|
+
const directory: string = path.dirname(location);
|
|
39
42
|
if (fs.existsSync(directory) === false)
|
|
40
43
|
try {
|
|
41
|
-
await fs.promises.mkdir(directory);
|
|
44
|
+
await fs.promises.mkdir(directory, { recursive: true });
|
|
42
45
|
} catch {}
|
|
43
46
|
if (fs.existsSync(directory) === false)
|
|
44
47
|
throw new Error(
|
|
45
48
|
`Error on NestiaApplication.swagger(): failed to create output directory: ${directory}`,
|
|
46
49
|
);
|
|
47
|
-
const location: string = !!parsed.ext
|
|
48
|
-
? path.resolve(config.output)
|
|
49
|
-
: path.join(path.resolve(config.output), "swagger.json");
|
|
50
|
-
|
|
51
50
|
// COMPOSE SWAGGER DOCUMENT
|
|
52
51
|
const document: OpenApi.IDocument = compose({
|
|
53
52
|
config,
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type ImportClause,
|
|
3
|
+
type Node,
|
|
4
|
+
SyntaxKind,
|
|
5
|
+
factory,
|
|
6
|
+
} from "@ttsc/factory";
|
|
2
7
|
import path from "path";
|
|
3
8
|
import { HashMap, TreeMap, hash } from "tstl";
|
|
4
9
|
|
|
@@ -42,10 +47,12 @@ export class ImportDictionary {
|
|
|
42
47
|
});
|
|
43
48
|
for (const elem of imp.elements) {
|
|
44
49
|
if (elem === "WebSocketAcceptor") continue;
|
|
50
|
+
const imported: string = imp.elementAliases?.[elem] ?? elem;
|
|
45
51
|
this.internal({
|
|
46
52
|
type: "element",
|
|
47
53
|
file: imp.file,
|
|
48
|
-
name:
|
|
54
|
+
name: imported,
|
|
55
|
+
alias: imported === elem ? undefined : elem,
|
|
49
56
|
declaration: true,
|
|
50
57
|
});
|
|
51
58
|
}
|
|
@@ -70,10 +77,12 @@ export class ImportDictionary {
|
|
|
70
77
|
};
|
|
71
78
|
const value: ICompositeValue = this.components_.take(key, () => ({
|
|
72
79
|
...key,
|
|
73
|
-
elements: new TreeMap<string, string
|
|
80
|
+
elements: new TreeMap<string, string>(),
|
|
74
81
|
}));
|
|
75
|
-
if (props.type === "element")
|
|
76
|
-
|
|
82
|
+
if (props.type === "element") {
|
|
83
|
+
const local: string = props.alias ?? props.name;
|
|
84
|
+
value.elements.set(local, props.name);
|
|
85
|
+
}
|
|
77
86
|
return props.type === "element" ? (props.alias ?? props.name) : props.name;
|
|
78
87
|
}
|
|
79
88
|
|
|
@@ -132,22 +141,24 @@ export class ImportDictionary {
|
|
|
132
141
|
// generated SDK code references DTO namespaces only in type positions.
|
|
133
142
|
if (c.asterisk !== null)
|
|
134
143
|
return factory.createImportClause(
|
|
135
|
-
c.declaration,
|
|
144
|
+
c.declaration ? SyntaxKind.TypeKeyword : undefined,
|
|
136
145
|
undefined,
|
|
137
146
|
factory.createNamespaceImport(factory.createIdentifier(c.asterisk)),
|
|
138
147
|
);
|
|
139
148
|
// `c.declaration` (type-only) belongs on the import clause, not on each
|
|
140
149
|
// specifier — emitting both produces the invalid `import type { type X }`.
|
|
141
150
|
return factory.createImportClause(
|
|
142
|
-
c.declaration,
|
|
151
|
+
c.declaration ? SyntaxKind.TypeKeyword : undefined,
|
|
143
152
|
c.default !== null ? factory.createIdentifier(c.default) : undefined,
|
|
144
153
|
c.elements.size() !== 0
|
|
145
154
|
? factory.createNamedImports(
|
|
146
|
-
Array.from(c.elements).map(({ first:
|
|
155
|
+
Array.from(c.elements).map(({ first: local, second: imported }) =>
|
|
147
156
|
factory.createImportSpecifier(
|
|
148
157
|
false,
|
|
149
|
-
|
|
150
|
-
|
|
158
|
+
imported !== local
|
|
159
|
+
? factory.createIdentifier(imported)
|
|
160
|
+
: undefined,
|
|
161
|
+
factory.createIdentifier(local),
|
|
151
162
|
),
|
|
152
163
|
),
|
|
153
164
|
)
|
|
@@ -172,7 +183,8 @@ interface ICompositeKey {
|
|
|
172
183
|
default: string | null;
|
|
173
184
|
}
|
|
174
185
|
interface ICompositeValue extends ICompositeKey {
|
|
175
|
-
|
|
186
|
+
/** Maps each local named binding to the exported name. */
|
|
187
|
+
elements: TreeMap<string, string>;
|
|
176
188
|
}
|
|
177
189
|
|
|
178
190
|
const NODE_MODULES = "node_modules/";
|
|
@@ -11,36 +11,38 @@ export namespace SdkDistributionComposer {
|
|
|
11
11
|
websocket: boolean;
|
|
12
12
|
}) => {
|
|
13
13
|
if (!fs.existsSync(props.config.distribute!))
|
|
14
|
-
await fs.promises.mkdir(props.config.distribute
|
|
14
|
+
await fs.promises.mkdir(props.config.distribute!, { recursive: true });
|
|
15
15
|
|
|
16
16
|
const root: string = process.cwd();
|
|
17
17
|
const output: string = path.resolve(props.config.output!);
|
|
18
18
|
process.chdir(props.config.distribute!);
|
|
19
|
+
try {
|
|
20
|
+
if (await configured()) return;
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
// COPY FILES
|
|
23
|
+
console.log("Composing SDK distribution environments...");
|
|
24
|
+
for (const file of await fs.promises.readdir(BUNDLE))
|
|
25
|
+
await fs.promises.copyFile(`${BUNDLE}/${file}`, file);
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
await fs.promises.copyFile(`${BUNDLE}/${file}`, file);
|
|
27
|
+
// CONFIGURE PATHS
|
|
28
|
+
for (const file of ["package.json", "tsconfig.json"])
|
|
29
|
+
await replace({ root, output })(file);
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
exit();
|
|
31
|
+
// INSTALL PACKAGES
|
|
32
|
+
const v: IDependencies = await dependencies({
|
|
33
|
+
websocket: props.websocket,
|
|
34
|
+
});
|
|
35
|
+
execute("npm install --save-dev rimraf");
|
|
36
|
+
execute(`npm install --save @nestia/fetcher@${v.version}`);
|
|
37
|
+
execute(`npm install --save typia@${v.typia}`);
|
|
38
|
+
if (props.mcp && v.mcp !== undefined)
|
|
39
|
+
execute(`npm install --save @modelcontextprotocol/sdk@${v.mcp}`);
|
|
40
|
+
if (props.websocket && v.tgrid !== undefined)
|
|
41
|
+
execute(`npm install --save tgrid@${v.tgrid}`);
|
|
42
|
+
execute("npx typia setup --manager npm");
|
|
43
|
+
} finally {
|
|
44
|
+
process.chdir(root);
|
|
45
|
+
}
|
|
44
46
|
};
|
|
45
47
|
|
|
46
48
|
const configured = async (): Promise<boolean> =>
|
|
@@ -51,9 +51,7 @@ export namespace SdkFileProgrammer {
|
|
|
51
51
|
(directory: SdkRouteDirectory) =>
|
|
52
52
|
async (outDir: string): Promise<void> => {
|
|
53
53
|
// CREATE A NEW DIRECTORY
|
|
54
|
-
|
|
55
|
-
await fs.promises.mkdir(outDir);
|
|
56
|
-
} catch {}
|
|
54
|
+
await fs.promises.mkdir(outDir, { recursive: true });
|
|
57
55
|
|
|
58
56
|
// ITERATE CHILDREN
|
|
59
57
|
const statements: Node[] = [];
|
|
@@ -69,22 +69,24 @@ export namespace SdkHttpCloneReferencer {
|
|
|
69
69
|
directory: string;
|
|
70
70
|
route: ITypedWebSocketRoute;
|
|
71
71
|
}): void => {
|
|
72
|
-
const unique:
|
|
72
|
+
const unique: Map<string, string> = new Map();
|
|
73
73
|
const keep: ITypedWebSocketRoute["imports"] = [];
|
|
74
74
|
for (const imp of props.route.imports) {
|
|
75
75
|
const cloned: string[] = SdkWebSocketCloneProgrammer.isNodeModulesPath(
|
|
76
76
|
imp.file,
|
|
77
77
|
)
|
|
78
78
|
? []
|
|
79
|
-
: imp.elements.filter((elem) =>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
: imp.elements.filter((elem) => {
|
|
80
|
+
const imported: string = imp.elementAliases?.[elem] ?? elem;
|
|
81
|
+
return props.cloned.has(
|
|
82
|
+
SdkWebSocketCloneProgrammer.importKey(imp.file, imported),
|
|
83
|
+
);
|
|
84
|
+
});
|
|
84
85
|
const remained: string[] = imp.elements.filter(
|
|
85
86
|
(elem) => cloned.includes(elem) === false,
|
|
86
87
|
);
|
|
87
|
-
for (const elem of cloned)
|
|
88
|
+
for (const elem of cloned)
|
|
89
|
+
unique.set(elem, imp.elementAliases?.[elem] ?? elem);
|
|
88
90
|
if (
|
|
89
91
|
imp.asterisk !== null ||
|
|
90
92
|
imp.default !== null ||
|
|
@@ -98,11 +100,14 @@ export namespace SdkHttpCloneReferencer {
|
|
|
98
100
|
|
|
99
101
|
props.route.imports = [
|
|
100
102
|
...keep,
|
|
101
|
-
...Array.from(unique).map((
|
|
102
|
-
file: `${props.directory}/${
|
|
103
|
+
...Array.from(unique).map(([local, imported]) => ({
|
|
104
|
+
file: `${props.directory}/${imported}`,
|
|
103
105
|
asterisk: null,
|
|
104
106
|
default: null,
|
|
105
|
-
elements: [
|
|
107
|
+
elements: [local],
|
|
108
|
+
...(local === imported
|
|
109
|
+
? {}
|
|
110
|
+
: { elementAliases: { [local]: imported } }),
|
|
106
111
|
})),
|
|
107
112
|
];
|
|
108
113
|
};
|
|
@@ -14,9 +14,10 @@ export namespace SdkWebSocketCloneProgrammer {
|
|
|
14
14
|
for (const route of app.routes)
|
|
15
15
|
if (route.protocol === "websocket")
|
|
16
16
|
for (const imp of route.imports)
|
|
17
|
-
for (const
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
for (const local of imp.elements) {
|
|
18
|
+
const imported: string = imp.elementAliases?.[local] ?? local;
|
|
19
|
+
if (await clone(ctx)(imp.file, imported))
|
|
20
|
+
cloned.add(importKey(imp.file, imported));
|
|
20
21
|
}
|
|
21
22
|
return cloned;
|
|
22
23
|
};
|