@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.
Files changed (87) hide show
  1. package/assets/bundle/distribute/package.json +1 -1
  2. package/assets/config/nestia.config.ts +19 -19
  3. package/lib/NestiaSwaggerComposer.js +2 -0
  4. package/lib/NestiaSwaggerComposer.js.map +1 -1
  5. package/lib/analyses/ImportAnalyzer.d.ts +6 -5
  6. package/lib/analyses/ImportAnalyzer.js +30 -15
  7. package/lib/analyses/ImportAnalyzer.js.map +1 -1
  8. package/lib/analyses/ReflectControllerAnalyzer.js +18 -9
  9. package/lib/analyses/ReflectControllerAnalyzer.js.map +1 -1
  10. package/lib/analyses/ReflectHttpOperationAnalyzer.d.ts +1 -1
  11. package/lib/analyses/ReflectHttpOperationAnalyzer.js +8 -6
  12. package/lib/analyses/ReflectHttpOperationAnalyzer.js.map +1 -1
  13. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.d.ts +1 -1
  14. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.js.map +1 -1
  15. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.d.ts +1 -1
  16. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js +1 -1
  17. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js.map +1 -1
  18. package/lib/analyses/ReflectWebSocketOperationAnalyzer.d.ts +1 -1
  19. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js +10 -6
  20. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js.map +1 -1
  21. package/lib/analyses/TypedHttpRouteAnalyzer.js +13 -7
  22. package/lib/analyses/TypedHttpRouteAnalyzer.js.map +1 -1
  23. package/lib/executable/internal/NestiaSdkCommand.js +7 -4
  24. package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
  25. package/lib/generates/E2eGenerator.js +1 -4
  26. package/lib/generates/E2eGenerator.js.map +1 -1
  27. package/lib/generates/SdkGenerator.js +1 -4
  28. package/lib/generates/SdkGenerator.js.map +1 -1
  29. package/lib/generates/SwaggerGenerator.js +5 -5
  30. package/lib/generates/SwaggerGenerator.js.map +1 -1
  31. package/lib/generates/internal/ImportDictionary.js +14 -6
  32. package/lib/generates/internal/ImportDictionary.js.map +1 -1
  33. package/lib/generates/internal/SdkDistributionComposer.js +27 -22
  34. package/lib/generates/internal/SdkDistributionComposer.js.map +1 -1
  35. package/lib/generates/internal/SdkFileProgrammer.js +1 -4
  36. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  37. package/lib/generates/internal/SdkHttpCloneReferencer.js +13 -9
  38. package/lib/generates/internal/SdkHttpCloneReferencer.js.map +1 -1
  39. package/lib/generates/internal/SdkWebSocketCloneProgrammer.js +6 -3
  40. package/lib/generates/internal/SdkWebSocketCloneProgrammer.js.map +1 -1
  41. package/lib/generates/internal/SwaggerOperationComposer.d.ts +1 -1
  42. package/lib/generates/internal/SwaggerOperationComposer.js.map +1 -1
  43. package/lib/internal/legacy.d.ts +44 -46
  44. package/lib/internal/legacy.js +35 -48
  45. package/lib/internal/legacy.js.map +1 -1
  46. package/lib/structures/IReflectHttpOperationException.d.ts +1 -1
  47. package/lib/structures/IReflectHttpOperationParameter.d.ts +1 -1
  48. package/lib/structures/IReflectImport.d.ts +2 -0
  49. package/lib/structures/ITypedHttpRouteParameter.d.ts +1 -1
  50. package/lib/utils/TsConfigReader.js +3 -1
  51. package/lib/utils/TsConfigReader.js.map +1 -1
  52. package/lib/validators/HttpHeadersValidator.d.ts +3 -2
  53. package/lib/validators/HttpHeadersValidator.js +3 -2
  54. package/lib/validators/HttpHeadersValidator.js.map +1 -1
  55. package/lib/validators/HttpQueryValidator.d.ts +4 -4
  56. package/lib/validators/HttpQueryValidator.js +4 -4
  57. package/native/sdk/register.go +6 -35
  58. package/native/sdk/sdk_transform.go +80 -304
  59. package/package.json +9 -9
  60. package/src/NestiaSwaggerComposer.ts +2 -0
  61. package/src/analyses/ImportAnalyzer.ts +24 -15
  62. package/src/analyses/ReflectControllerAnalyzer.ts +19 -10
  63. package/src/analyses/ReflectHttpOperationAnalyzer.ts +5 -2
  64. package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +2 -2
  65. package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +3 -3
  66. package/src/analyses/ReflectWebSocketOperationAnalyzer.ts +14 -7
  67. package/src/analyses/TypedHttpRouteAnalyzer.ts +74 -35
  68. package/src/executable/internal/NestiaSdkCommand.ts +8 -5
  69. package/src/generates/E2eGenerator.ts +1 -3
  70. package/src/generates/SdkGenerator.ts +1 -3
  71. package/src/generates/SwaggerGenerator.ts +5 -6
  72. package/src/generates/internal/ImportDictionary.ts +23 -11
  73. package/src/generates/internal/SdkDistributionComposer.ts +25 -23
  74. package/src/generates/internal/SdkFileProgrammer.ts +1 -3
  75. package/src/generates/internal/SdkHttpCloneReferencer.ts +15 -10
  76. package/src/generates/internal/SdkWebSocketCloneProgrammer.ts +4 -3
  77. package/src/generates/internal/SwaggerOperationComposer.ts +1 -1
  78. package/src/internal/legacy.ts +83 -73
  79. package/src/structures/IReflectHttpOperationException.ts +1 -1
  80. package/src/structures/IReflectHttpOperationParameter.ts +1 -1
  81. package/src/structures/IReflectImport.ts +2 -0
  82. package/src/structures/ITypedApplication.ts +0 -1
  83. package/src/structures/ITypedHttpRouteException.ts +0 -1
  84. package/src/structures/ITypedHttpRouteParameter.ts +1 -1
  85. package/src/utils/TsConfigReader.ts +11 -3
  86. package/src/validators/HttpHeadersValidator.ts +3 -2
  87. 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 keyList = Object.getOwnPropertyNames(creator.prototype);
101
- const entries: Array<[string, unknown]> = keyList.map((key) => [
102
- key,
103
- creator.prototype[key],
104
- ]);
100
+ const visited: Set<string> = new Set();
101
+ return iterate(creator);
105
102
 
106
- const parent = Object.getPrototypeOf(creator);
107
- if (parent.prototype !== undefined)
108
- entries.push(..._Get_prototype_entries(parent));
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
- return entries;
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
- ...Object.values(props.metadata.exceptions).map((e) => e.imports),
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 errors.push(
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 errors.push(
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 errors.push(`@WebSocketRoute.Param() must have a field name.`);
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 `@WebSocketRoute.Acceptor() must have three type arguments.`;
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 errors.push(
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
- errors.push(
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)) clearMetadataNameCache(metadata);
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((array.type as MetadataArrayType)) === false) {
312
- visited.arrays.add((array.type as MetadataArrayType));
313
- entries.push(componentEntry(route, "arrays", (array.type as MetadataArrayType)));
314
- collectComponentEntries(entries, route, ((array.type as MetadataArrayType) as MetadataArrayType).value, visited);
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((tuple.type as MetadataTupleType)) === false) {
318
- visited.tuples.add((tuple.type as MetadataTupleType));
319
- entries.push(componentEntry(route, "tuples", (tuple.type as MetadataTupleType)));
320
- for (const elem of ((tuple.type as MetadataTupleType) as MetadataTupleType).elements)
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((alias.type as MetadataAliasType)) === false) {
325
- visited.aliases.add((alias.type as MetadataAliasType));
326
- entries.push(componentEntry(route, "aliases", (alias.type as MetadataAliasType)));
327
- collectComponentEntries(entries, route, ((alias.type as MetadataAliasType) as MetadataAliasType).value, visited);
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((obj.type as MetadataObjectType)) === false) {
331
- visited.objects.add((obj.type as MetadataObjectType));
332
- entries.push(componentEntry(route, "objects", (obj.type as MetadataObjectType)));
333
- for (const p of ((obj.type as MetadataObjectType) as MetadataObjectType).properties) {
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(((array.type as MetadataArrayType) as MetadataArrayType).value, visited);
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 ((tuple.type as MetadataTupleType) as MetadataTupleType).elements)
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(((alias.type as MetadataAliasType) as MetadataAliasType).value, visited);
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 ((obj.type as MetadataObjectType) as MetadataObjectType).properties) {
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) enrollMetadata(dictionary, metadata.rest, visited);
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, (array.type as MetadataArrayType)))
480
- enrollMetadata(dictionary, ((array.type as MetadataArrayType) as MetadataArrayType).value, visited);
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, (tuple.type as MetadataTupleType)))
483
- for (const elem of ((tuple.type as MetadataTupleType) as MetadataTupleType).elements)
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, (alias.type as MetadataAliasType)))
487
- enrollMetadata(dictionary, ((alias.type as MetadataAliasType) as MetadataAliasType).value, visited);
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, (obj.type as MetadataObjectType)))
490
- for (const p of ((obj.type as MetadataObjectType) as MetadataObjectType).properties) {
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
- const file: string = argv[index + 1]!;
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;
@@ -26,7 +26,5 @@ export namespace E2eGenerator {
26
26
  }
27
27
 
28
28
  const mkdir = async (location: string): Promise<void> => {
29
- try {
30
- await fs.promises.mkdir(location);
31
- } catch {}
29
+ await fs.promises.mkdir(location, { recursive: true });
32
30
  };
@@ -19,9 +19,7 @@ export namespace SdkGenerator {
19
19
 
20
20
  // PREPARE NEW DIRECTORIES
21
21
  console.log("Generating SDK Library");
22
- try {
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 directory: string = path.dirname(parsed.dir);
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 { type ImportClause, type Node, factory } from "@ttsc/factory";
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: elem,
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 | null>(),
80
+ elements: new TreeMap<string, string>(),
74
81
  }));
75
- if (props.type === "element")
76
- value.elements.set(props.name, props.alias ?? null);
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: name, second: alias }) =>
155
+ Array.from(c.elements).map(({ first: local, second: imported }) =>
147
156
  factory.createImportSpecifier(
148
157
  false,
149
- alias !== null ? factory.createIdentifier(name) : undefined,
150
- factory.createIdentifier(alias ?? name),
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
- elements: TreeMap<string, string | null>;
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
- const exit = () => process.chdir(root);
21
- if (await configured()) return exit();
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
- // COPY FILES
24
- console.log("Composing SDK distribution environments...");
25
- for (const file of await fs.promises.readdir(BUNDLE))
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
- // CONFIGURE PATHS
29
- for (const file of ["package.json", "tsconfig.json"])
30
- await replace({ root, output })(file);
31
-
32
- // INSTALL PACKAGES
33
- const v: IDependencies = await dependencies({ websocket: props.websocket });
34
- execute("npm install --save-dev rimraf");
35
- execute(`npm install --save @nestia/fetcher@${v.version}`);
36
- execute(`npm install --save typia@${v.typia}`);
37
- if (props.mcp && v.mcp !== undefined)
38
- execute(`npm install --save @modelcontextprotocol/sdk@${v.mcp}`);
39
- if (props.websocket && v.tgrid !== undefined)
40
- execute(`npm install --save tgrid@${v.tgrid}`);
41
- execute("npx typia setup --manager npm");
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
- try {
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: Set<string> = new Set();
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
- props.cloned.has(
81
- SdkWebSocketCloneProgrammer.importKey(imp.file, elem),
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) unique.add(elem);
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((str) => ({
102
- file: `${props.directory}/${str}`,
103
+ ...Array.from(unique).map(([local, imported]) => ({
104
+ file: `${props.directory}/${imported}`,
103
105
  asterisk: null,
104
106
  default: null,
105
- elements: [str],
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 name of imp.elements) {
18
- if (await clone(ctx)(imp.file, name))
19
- cloned.add(importKey(imp.file, name));
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
  };