@nestia/migrate 14.0.0 → 14.0.2

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 (182) hide show
  1. package/README.md +1 -1
  2. package/lib/NestiaMigrateApplication.d.ts +111 -0
  3. package/lib/NestiaMigrateApplication.js +148 -9
  4. package/lib/NestiaMigrateApplication.js.map +1 -1
  5. package/lib/NestiaMigrateApplication.mjs +147 -5
  6. package/lib/analyzers/NestiaMigrateControllerAnalyzer.d.ts +58 -0
  7. package/lib/analyzers/NestiaMigrateControllerAnalyzer.js +88 -2
  8. package/lib/analyzers/NestiaMigrateControllerAnalyzer.js.map +1 -1
  9. package/lib/analyzers/NestiaMigrateControllerAnalyzer.mjs +20 -2
  10. package/lib/archivers/NestiaMigrateFileArchiver.d.ts +34 -0
  11. package/lib/archivers/NestiaMigrateFileArchiver.js +34 -0
  12. package/lib/archivers/NestiaMigrateFileArchiver.js.map +1 -1
  13. package/lib/bundles/NEST_TEMPLATE.js +1 -1
  14. package/lib/bundles/NEST_TEMPLATE.js.map +1 -1
  15. package/lib/bundles/NEST_TEMPLATE.mjs +1 -1
  16. package/lib/bundles/SDK_TEMPLATE.js +1 -1
  17. package/lib/bundles/SDK_TEMPLATE.js.map +1 -1
  18. package/lib/bundles/SDK_TEMPLATE.mjs +1 -1
  19. package/lib/executable/NestiaMigrateCommander.d.ts +36 -0
  20. package/lib/executable/NestiaMigrateCommander.js +43 -1
  21. package/lib/executable/NestiaMigrateCommander.js.map +1 -1
  22. package/lib/executable/NestiaMigrateCommander.mjs +4 -2
  23. package/lib/executable/NestiaMigrateInquirer.d.ts +29 -0
  24. package/lib/executable/NestiaMigrateInquirer.js +27 -25
  25. package/lib/executable/NestiaMigrateInquirer.js.map +1 -1
  26. package/lib/executable/NestiaMigrateInquirer.mjs +5 -7
  27. package/lib/factories/ExpressionFactory.d.ts +14 -0
  28. package/lib/factories/ExpressionFactory.js +14 -0
  29. package/lib/factories/ExpressionFactory.js.map +1 -1
  30. package/lib/factories/IdentifierFactory.d.ts +20 -0
  31. package/lib/factories/IdentifierFactory.js +20 -0
  32. package/lib/factories/IdentifierFactory.js.map +1 -1
  33. package/lib/factories/LiteralFactory.d.ts +18 -2
  34. package/lib/factories/LiteralFactory.js +18 -2
  35. package/lib/factories/LiteralFactory.js.map +1 -1
  36. package/lib/factories/StatementFactory.d.ts +26 -1
  37. package/lib/factories/StatementFactory.js +26 -1
  38. package/lib/factories/StatementFactory.js.map +1 -1
  39. package/lib/factories/SupportedStringFormats.d.ts +6 -0
  40. package/lib/factories/SupportedStringFormats.js +33 -0
  41. package/lib/factories/SupportedStringFormats.js.map +1 -0
  42. package/lib/factories/SupportedStringFormats.mjs +34 -0
  43. package/lib/factories/SupportedStringFormats.mjs.map +1 -0
  44. package/lib/factories/TypeFactory.d.ts +21 -0
  45. package/lib/factories/TypeFactory.js +13 -0
  46. package/lib/factories/TypeFactory.js.map +1 -1
  47. package/lib/factories/TypeLiteralFactory.d.ts +18 -0
  48. package/lib/factories/TypeLiteralFactory.js +18 -0
  49. package/lib/factories/TypeLiteralFactory.js.map +1 -1
  50. package/lib/internal/ts.d.ts +153 -0
  51. package/lib/internal/ts.js.map +1 -1
  52. package/lib/programmers/NestiaMigrateApiFileProgrammer.d.ts +31 -0
  53. package/lib/programmers/NestiaMigrateApiFileProgrammer.js +17 -0
  54. package/lib/programmers/NestiaMigrateApiFileProgrammer.js.map +1 -1
  55. package/lib/programmers/NestiaMigrateApiFunctionProgrammer.d.ts +40 -0
  56. package/lib/programmers/NestiaMigrateApiFunctionProgrammer.js +34 -5
  57. package/lib/programmers/NestiaMigrateApiFunctionProgrammer.js.map +1 -1
  58. package/lib/programmers/NestiaMigrateApiFunctionProgrammer.mjs +4 -2
  59. package/lib/programmers/NestiaMigrateApiNamespaceProgrammer.d.ts +39 -0
  60. package/lib/programmers/NestiaMigrateApiNamespaceProgrammer.js +57 -13
  61. package/lib/programmers/NestiaMigrateApiNamespaceProgrammer.js.map +1 -1
  62. package/lib/programmers/NestiaMigrateApiNamespaceProgrammer.mjs +17 -8
  63. package/lib/programmers/NestiaMigrateApiProgrammer.d.ts +18 -0
  64. package/lib/programmers/NestiaMigrateApiProgrammer.js +18 -0
  65. package/lib/programmers/NestiaMigrateApiProgrammer.js.map +1 -1
  66. package/lib/programmers/NestiaMigrateApiProgrammer.mjs +1 -1
  67. package/lib/programmers/NestiaMigrateApiSimulationProgrammer.d.ts +40 -0
  68. package/lib/programmers/NestiaMigrateApiSimulationProgrammer.js +51 -22
  69. package/lib/programmers/NestiaMigrateApiSimulationProgrammer.js.map +1 -1
  70. package/lib/programmers/NestiaMigrateApiSimulationProgrammer.mjs +13 -20
  71. package/lib/programmers/NestiaMigrateApiStartProgrammer.d.ts +17 -0
  72. package/lib/programmers/NestiaMigrateApiStartProgrammer.js +19 -8
  73. package/lib/programmers/NestiaMigrateApiStartProgrammer.js.map +1 -1
  74. package/lib/programmers/NestiaMigrateApiStartProgrammer.mjs +1 -6
  75. package/lib/programmers/NestiaMigrateDtoProgrammer.d.ts +30 -0
  76. package/lib/programmers/NestiaMigrateDtoProgrammer.js +17 -0
  77. package/lib/programmers/NestiaMigrateDtoProgrammer.js.map +1 -1
  78. package/lib/programmers/NestiaMigrateE2eFileProgrammer.d.ts +39 -0
  79. package/lib/programmers/NestiaMigrateE2eFileProgrammer.js +46 -5
  80. package/lib/programmers/NestiaMigrateE2eFileProgrammer.js.map +1 -1
  81. package/lib/programmers/NestiaMigrateE2eFileProgrammer.mjs +6 -2
  82. package/lib/programmers/NestiaMigrateE2eProgrammer.d.ts +16 -0
  83. package/lib/programmers/NestiaMigrateE2eProgrammer.js +16 -0
  84. package/lib/programmers/NestiaMigrateE2eProgrammer.js.map +1 -1
  85. package/lib/programmers/NestiaMigrateImportProgrammer.d.ts +75 -0
  86. package/lib/programmers/NestiaMigrateImportProgrammer.js +58 -3
  87. package/lib/programmers/NestiaMigrateImportProgrammer.js.map +1 -1
  88. package/lib/programmers/NestiaMigrateImportProgrammer.mjs +58 -3
  89. package/lib/programmers/NestiaMigrateNestControllerProgrammer.d.ts +28 -0
  90. package/lib/programmers/NestiaMigrateNestControllerProgrammer.js +16 -0
  91. package/lib/programmers/NestiaMigrateNestControllerProgrammer.js.map +1 -1
  92. package/lib/programmers/NestiaMigrateNestMethodProgrammer.d.ts +30 -0
  93. package/lib/programmers/NestiaMigrateNestMethodProgrammer.js +85 -13
  94. package/lib/programmers/NestiaMigrateNestMethodProgrammer.js.map +1 -1
  95. package/lib/programmers/NestiaMigrateNestMethodProgrammer.mjs +46 -9
  96. package/lib/programmers/NestiaMigrateNestModuleProgrammer.d.ts +16 -0
  97. package/lib/programmers/NestiaMigrateNestModuleProgrammer.js +16 -0
  98. package/lib/programmers/NestiaMigrateNestModuleProgrammer.js.map +1 -1
  99. package/lib/programmers/NestiaMigrateNestProgrammer.d.ts +17 -0
  100. package/lib/programmers/NestiaMigrateNestProgrammer.js +17 -0
  101. package/lib/programmers/NestiaMigrateNestProgrammer.js.map +1 -1
  102. package/lib/programmers/NestiaMigrateSchemaProgrammer.d.ts +16 -0
  103. package/lib/programmers/NestiaMigrateSchemaProgrammer.js +45 -9
  104. package/lib/programmers/NestiaMigrateSchemaProgrammer.js.map +1 -1
  105. package/lib/programmers/NestiaMigrateSchemaProgrammer.mjs +19 -8
  106. package/lib/structures/INestiaMigrateConfig.d.ts +21 -0
  107. package/lib/structures/INestiaMigrateContext.d.ts +15 -0
  108. package/lib/structures/INestiaMigrateController.d.ts +13 -0
  109. package/lib/structures/INestiaMigrateFile.d.ts +11 -0
  110. package/lib/utils/FilePrinter.d.ts +33 -0
  111. package/lib/utils/FilePrinter.js +33 -0
  112. package/lib/utils/FilePrinter.js.map +1 -1
  113. package/lib/utils/MapUtil.d.ts +17 -0
  114. package/lib/utils/MapUtil.js +19 -3
  115. package/lib/utils/MapUtil.js.map +1 -1
  116. package/lib/utils/MapUtil.mjs +1 -2
  117. package/lib/utils/PathTemplate.d.ts +41 -0
  118. package/lib/utils/PathTemplate.js +56 -0
  119. package/lib/utils/PathTemplate.js.map +1 -0
  120. package/lib/utils/PathTemplate.mjs +34 -0
  121. package/lib/utils/PathTemplate.mjs.map +1 -0
  122. package/lib/utils/RequestBody.d.ts +22 -0
  123. package/lib/utils/RequestBody.js +29 -0
  124. package/lib/utils/RequestBody.js.map +1 -0
  125. package/lib/utils/RequestBody.mjs +9 -0
  126. package/lib/utils/RequestBody.mjs.map +1 -0
  127. package/lib/utils/StringUtil.d.ts +55 -0
  128. package/lib/utils/StringUtil.js +93 -8
  129. package/lib/utils/StringUtil.js.map +1 -1
  130. package/lib/utils/StringUtil.mjs +30 -8
  131. package/lib/utils/SuccessStatus.d.ts +34 -0
  132. package/lib/utils/SuccessStatus.js +48 -0
  133. package/lib/utils/SuccessStatus.js.map +1 -0
  134. package/lib/utils/SuccessStatus.mjs +14 -0
  135. package/lib/utils/SuccessStatus.mjs.map +1 -0
  136. package/package.json +5 -4
  137. package/src/NestiaMigrateApplication.ts +151 -13
  138. package/src/analyzers/NestiaMigrateControllerAnalyzer.ts +94 -2
  139. package/src/archivers/NestiaMigrateFileArchiver.ts +34 -0
  140. package/src/bundles/NEST_TEMPLATE.ts +1 -1
  141. package/src/bundles/SDK_TEMPLATE.ts +1 -1
  142. package/src/executable/NestiaMigrateCommander.ts +47 -1
  143. package/src/executable/NestiaMigrateInquirer.ts +41 -26
  144. package/src/factories/ExpressionFactory.ts +14 -0
  145. package/src/factories/IdentifierFactory.ts +20 -0
  146. package/src/factories/LiteralFactory.ts +18 -2
  147. package/src/factories/StatementFactory.ts +26 -1
  148. package/src/factories/SupportedStringFormats.ts +29 -0
  149. package/src/factories/TypeFactory.ts +21 -0
  150. package/src/factories/TypeLiteralFactory.ts +18 -0
  151. package/src/internal/ts.ts +153 -0
  152. package/src/programmers/NestiaMigrateApiFileProgrammer.ts +35 -0
  153. package/src/programmers/NestiaMigrateApiFunctionProgrammer.ts +53 -4
  154. package/src/programmers/NestiaMigrateApiNamespaceProgrammer.ts +83 -20
  155. package/src/programmers/NestiaMigrateApiProgrammer.ts +18 -0
  156. package/src/programmers/NestiaMigrateApiSimulationProgrammer.ts +66 -73
  157. package/src/programmers/NestiaMigrateApiStartProgrammer.ts +19 -10
  158. package/src/programmers/NestiaMigrateDtoProgrammer.ts +33 -0
  159. package/src/programmers/NestiaMigrateE2eFileProgrammer.ts +83 -8
  160. package/src/programmers/NestiaMigrateE2eProgrammer.ts +16 -0
  161. package/src/programmers/NestiaMigrateImportProgrammer.ts +86 -5
  162. package/src/programmers/NestiaMigrateNestControllerProgrammer.ts +30 -0
  163. package/src/programmers/NestiaMigrateNestMethodProgrammer.ts +122 -29
  164. package/src/programmers/NestiaMigrateNestModuleProgrammer.ts +16 -0
  165. package/src/programmers/NestiaMigrateNestProgrammer.ts +17 -0
  166. package/src/programmers/NestiaMigrateSchemaProgrammer.ts +53 -18
  167. package/src/structures/INestiaMigrateConfig.ts +26 -0
  168. package/src/structures/INestiaMigrateContext.ts +17 -0
  169. package/src/structures/INestiaMigrateController.ts +16 -0
  170. package/src/structures/INestiaMigrateFile.ts +13 -0
  171. package/src/utils/FilePrinter.ts +33 -0
  172. package/src/utils/MapUtil.ts +18 -2
  173. package/src/utils/PathTemplate.ts +61 -0
  174. package/src/utils/RequestBody.ts +27 -0
  175. package/src/utils/StringUtil.ts +101 -9
  176. package/src/utils/SuccessStatus.ts +49 -0
  177. package/lib/factories/FormatCheatSheet.d.ts +0 -25
  178. package/lib/factories/FormatCheatSheet.js +0 -34
  179. package/lib/factories/FormatCheatSheet.js.map +0 -1
  180. package/lib/factories/FormatCheatSheet.mjs +0 -31
  181. package/lib/factories/FormatCheatSheet.mjs.map +0 -1
  182. package/src/factories/FormatCheatSheet.ts +0 -71
@@ -1,20 +1,48 @@
1
- import { SyntaxKind, factory } from "@ttsc/factory";
1
+ import { type EntityName, SyntaxKind, factory } from "@ttsc/factory";
2
2
 
3
3
  import { TypeLiteralFactory } from "../factories/TypeLiteralFactory";
4
4
  import ts from "../internal/ts";
5
5
  import { FilePrinter } from "../utils/FilePrinter";
6
6
  import { MapUtil } from "../utils/MapUtil";
7
7
 
8
+ /**
9
+ * Collects the imports that generated code needs and turns them into import
10
+ * statements.
11
+ *
12
+ * @evidence contracts/common.md#principled-implementation External imports are grouped by library into one clause with an optional default and a set of named instances, DTO imports are grouped by module specifier and emitted type-only, and a DTO is never imported into its own file.
13
+ * @evidence contracts/common.md#clear-and-simple-design One class with two collections and one emitter; the tag helper builds `typia.tags` references.
14
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The imports follow the code that asks for them.
15
+ * @evidence contracts/common.md#meaningful-documentation The comment states its purpose.
16
+ */
8
17
  export class NestiaMigrateImportProgrammer {
9
18
  private external_: Map<string, IClause> = new Map();
10
19
  private dtos_: Set<string> = new Set();
11
20
 
12
21
  public constructor() {}
13
22
 
23
+ /**
24
+ * Reports whether no import has been requested.
25
+ *
26
+ * @evidence contracts/common.md#principled-implementation The importer is empty exactly when both collections are empty.
27
+ * @evidence contracts/common.md#clear-and-simple-design One expression.
28
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It reads the state.
29
+ * @evidence contracts/common.md#meaningful-documentation The comment states the meaning.
30
+ */
14
31
  public empty(): boolean {
15
32
  return this.external_.size === 0 && this.dtos_.size === 0;
16
33
  }
17
34
 
35
+ /**
36
+ * Requests an import from a library and returns the local name to use.
37
+ *
38
+ * The returned name is the first segment of the requested name, so a nested
39
+ * name such as `tags.Type` imports `tags`.
40
+ *
41
+ * @evidence contracts/common.md#principled-implementation A default import replaces the clause's default and an instance import adds a named import, and the first segment of a dotted name is what the code refers to.
42
+ * @evidence contracts/common.md#clear-and-simple-design One function over one map.
43
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The library and the name come from the caller.
44
+ * @evidence contracts/common.md#meaningful-documentation The comment states the returned name.
45
+ */
18
46
  public external(props: MigrateImportProgrammer.IProps): string {
19
47
  const clause: IClause = MapUtil.take(this.external_)(props.library)(() => ({
20
48
  default: null,
@@ -26,19 +54,41 @@ export class NestiaMigrateImportProgrammer {
26
54
  return name;
27
55
  }
28
56
 
57
+ /**
58
+ * Requests a DTO import and returns a reference to it, qualified by a
59
+ * namespace when one is given.
60
+ *
61
+ * @evidence contracts/common.md#principled-implementation The DTO is recorded by the first segment of its dotted name, which is the file that exports it, and the returned reference keeps the full name, with the namespace prepended when one is given.
62
+ * @evidence contracts/common.md#clear-and-simple-design One function over one set.
63
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The name comes from the caller.
64
+ * @evidence contracts/common.md#meaningful-documentation The comment states the reference.
65
+ */
29
66
  public dto(name: string, namespace?: string): ts.TypeReferenceNode {
30
- const file: string = name.split(".")[0]!;
31
- this.dtos_.add(file);
67
+ const segments: string[] = name.split(".");
68
+ this.dtos_.add(segments[0]!);
32
69
  return factory.createTypeReferenceNode(
33
70
  namespace?.length
34
- ? factory.createQualifiedName(
71
+ ? segments.reduce<EntityName>(
72
+ (left, segment) =>
73
+ factory.createQualifiedName(
74
+ left,
75
+ factory.createIdentifier(segment),
76
+ ),
35
77
  factory.createIdentifier(namespace),
36
- factory.createIdentifier(file),
37
78
  )
38
79
  : name,
39
80
  );
40
81
  }
41
82
 
83
+ /**
84
+ * Requests the `typia` tags import and returns a reference to a tag with an
85
+ * optional literal argument.
86
+ *
87
+ * @evidence contracts/common.md#principled-implementation The argument is converted to a literal type, so `Minimum<3>` is written as a type reference with the literal.
88
+ * @evidence contracts/common.md#clear-and-simple-design One function delegating the literal building.
89
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The tag name and the argument come from the caller.
90
+ * @evidence contracts/common.md#meaningful-documentation The comment states the reference.
91
+ */
42
92
  public tag(type: string, arg?: any): ts.TypeReferenceNode {
43
93
  const instance: string = this.external({
44
94
  type: "instance",
@@ -51,6 +101,15 @@ export class NestiaMigrateImportProgrammer {
51
101
  );
52
102
  }
53
103
 
104
+ /**
105
+ * Returns the import statements: the external imports, a blank line when both
106
+ * kinds exist, and the type-only DTO imports.
107
+ *
108
+ * @evidence contracts/common.md#principled-implementation DTO names are grouped by the specifier that `dtoPath` returns, a name equal to the current file is skipped so a file never imports itself, and package specifiers merge into one clause.
109
+ * @evidence contracts/common.md#clear-and-simple-design One function with two emit sections.
110
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The specifier rule is the caller's.
111
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result and the self-import rule.
112
+ */
54
113
  public toStatements(
55
114
  dtoPath: (name: string) => string,
56
115
  current?: string,
@@ -114,10 +173,32 @@ export class NestiaMigrateImportProgrammer {
114
173
  ];
115
174
  }
116
175
  }
176
+ /**
177
+ * Types of the importer: the properties of an external import request.
178
+ *
179
+ * @evidence contracts/common.md#principled-implementation The record names the import kind, the library, and the name.
180
+ * @evidence contracts/common.md#clear-and-simple-design One namespace with one interface.
181
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It contains types only.
182
+ * @evidence contracts/common.md#meaningful-documentation The comment names its content.
183
+ */
117
184
  export namespace MigrateImportProgrammer {
185
+ /**
186
+ * An external import request: `default` or `instance`, the library, and the
187
+ * name.
188
+ *
189
+ * @evidence contracts/common.md#principled-implementation The kind selects between the default clause and a named import.
190
+ * @evidence contracts/common.md#clear-and-simple-design A three-field record.
191
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
192
+ * @evidence contracts/common.md#meaningful-documentation The comment states each field.
193
+ */
118
194
  export interface IProps {
195
+ /** Select the default export or a named import. */
119
196
  type: "default" | "instance";
197
+
198
+ /** Module specifier emitted in the import declaration. */
120
199
  library: string;
200
+
201
+ /** Requested binding; named imports use its leading dotted segment. */
121
202
  name: string;
122
203
  }
123
204
  }
@@ -8,13 +8,43 @@ import { FilePrinter } from "../utils/FilePrinter";
8
8
  import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
9
9
  import { NestiaMigrateNestMethodProgrammer } from "./NestiaMigrateNestMethodProgrammer";
10
10
 
11
+ /**
12
+ * Generates the source of one NestJS controller.
13
+ *
14
+ * @evidence contracts/common.md#principled-implementation The controller class is decorated with `@Controller` and its path, each route becomes a method written by the configured method programmer or the default one, and the DTO types are imported by package name because they live in the API package.
15
+ * @evidence contracts/common.md#clear-and-simple-design One function; the method programmer is replaceable through the configuration.
16
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The replaceable programmer is a documented extension point.
17
+ * @evidence contracts/common.md#meaningful-documentation The comment states what is generated.
18
+ */
11
19
  export namespace NestiaMigrateNestControllerProgrammer {
20
+ /**
21
+ * The input of one controller: the configuration, the components, and the
22
+ * controller.
23
+ *
24
+ * @evidence contracts/common.md#principled-implementation The record holds exactly what the generation needs.
25
+ * @evidence contracts/common.md#clear-and-simple-design A flat record.
26
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
27
+ * @evidence contracts/common.md#meaningful-documentation The comment lists the fields.
28
+ */
12
29
  export interface IProps {
30
+ /** Generation options and an optional controller-method writer. */
13
31
  config: INestiaMigrateConfig;
32
+
33
+ /** Schemas needed by generated controller method types. */
14
34
  components: OpenApi.IComponents;
35
+
36
+ /** Controller name, router prefix and grouped operations. */
15
37
  controller: INestiaMigrateController;
16
38
  }
17
39
 
40
+ /**
41
+ * Returns the statements of a controller file.
42
+ *
43
+ * @evidence contracts/common.md#principled-implementation Blank lines separate the methods, and the imports come first.
44
+ * @evidence contracts/common.md#clear-and-simple-design One function.
45
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The content follows the controller.
46
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result.
47
+ */
18
48
  export const write = (props: IProps): ts.Statement[] => {
19
49
  const importer: NestiaMigrateImportProgrammer =
20
50
  new NestiaMigrateImportProgrammer();
@@ -2,6 +2,7 @@ import { SyntaxKind, factory } from "@ttsc/factory";
2
2
  import { IHttpMigrateRoute } from "@typia/interface";
3
3
  import { OpenApi } from "typia";
4
4
 
5
+ import { NestiaMigrateControllerAnalyzer } from "../analyzers/NestiaMigrateControllerAnalyzer";
5
6
  import { ExpressionFactory } from "../factories/ExpressionFactory";
6
7
  import { IdentifierFactory } from "../factories/IdentifierFactory";
7
8
  import { LiteralFactory } from "../factories/LiteralFactory";
@@ -10,19 +11,55 @@ import ts from "../internal/ts";
10
11
  import { INestiaMigrateConfig } from "../structures/INestiaMigrateConfig";
11
12
  import { INestiaMigrateController } from "../structures/INestiaMigrateController";
12
13
  import { FilePrinter } from "../utils/FilePrinter";
14
+ import { RequestBody } from "../utils/RequestBody";
13
15
  import { StringUtil } from "../utils/StringUtil";
16
+ import { SuccessStatus } from "../utils/SuccessStatus";
14
17
  import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
15
18
  import { NestiaMigrateSchemaProgrammer } from "./NestiaMigrateSchemaProgrammer";
16
19
 
20
+ /**
21
+ * Generates the controller method of one route.
22
+ *
23
+ * @evidence contracts/common.md#principled-implementation The method carries `TypedRoute`, `TypedException`, `HumanRoute`, and example decorators as the route requires, one parameter per path, header, query, and body input with the matching typed decorator, and a body that mentions each parameter and returns `typia.random` of the response type.
24
+ * @evidence contracts/common.md#clear-and-simple-design One entry function and private writers for the description, the decorators, and the parameters.
25
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The output derives from the route; the body is a stub that returns random data because the document does not define the behavior.
26
+ * @evidence contracts/common.md#meaningful-documentation The comment states what is generated.
27
+ */
17
28
  export namespace NestiaMigrateNestMethodProgrammer {
29
+ /**
30
+ * The input of one method: the configuration, the components, the importer,
31
+ * the controller, and the route.
32
+ *
33
+ * @evidence contracts/common.md#principled-implementation The record holds exactly what the generation needs.
34
+ * @evidence contracts/common.md#clear-and-simple-design A flat record.
35
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
36
+ * @evidence contracts/common.md#meaningful-documentation The comment lists the fields.
37
+ */
18
38
  export interface IContext {
39
+ /** Generation options, including the author tag used on the handler. */
19
40
  config: INestiaMigrateConfig;
41
+
42
+ /** Component schemas referenced by request and response types. */
20
43
  components: OpenApi.IComponents;
44
+
45
+ /** Controller-file import collector shared by all its methods. */
21
46
  importer: NestiaMigrateImportProgrammer;
47
+
48
+ /** Controller prefix removed from this operation's router path. */
22
49
  controller: INestiaMigrateController;
50
+
51
+ /** Analyzed operation supplying method, schemas and examples. */
23
52
  route: IHttpMigrateRoute;
24
53
  }
25
54
 
55
+ /**
56
+ * Returns the method declaration of a route.
57
+ *
58
+ * @evidence contracts/common.md#principled-implementation The decorators and the parameters follow the route's HTTP method, path relative to the controller, and inputs.
59
+ * @evidence contracts/common.md#clear-and-simple-design One function composing the private writers.
60
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The method follows the route.
61
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result.
62
+ */
26
63
  export const write = (ctx: IContext): ts.MethodDeclaration => {
27
64
  const output: ts.TypeNode = ctx.route.success
28
65
  ? NestiaMigrateSchemaProgrammer.write({
@@ -121,7 +158,9 @@ export namespace NestiaMigrateNestMethodProgrammer {
121
158
  );
122
159
 
123
160
  // ROUTER
124
- const localPath: string = ctx.route.emendedPath
161
+ const localPath: string = NestiaMigrateControllerAnalyzer.routePath(
162
+ ctx.route,
163
+ )
125
164
  .slice(ctx.controller.path.length)
126
165
  .split("/")
127
166
  .filter((str) => !!str.length)
@@ -139,35 +178,43 @@ export namespace NestiaMigrateNestMethodProgrammer {
139
178
  : undefined,
140
179
  ),
141
180
  );
181
+ // a vanilla NestJS method decorator, relative to the controller like the
182
+ // nestia ones: the document's full path would be joined onto the
183
+ // controller's again
184
+ const nest = (method: string) =>
185
+ factory.createDecorator(
186
+ factory.createCallExpression(
187
+ external("@nestjs/common", method),
188
+ [],
189
+ localPath.length
190
+ ? [factory.createStringLiteral(localPath)]
191
+ : undefined,
192
+ ),
193
+ );
142
194
  if (ctx.route.success?.["x-nestia-encrypted"])
143
195
  decorators.push(router("EncryptedRoute"));
144
196
  else if (ctx.route.success?.type === "text/plain")
145
- decorators.push(
146
- factory.createDecorator(
147
- factory.createCallExpression(
148
- external("@nestjs/common", StringUtil.capitalize(ctx.route.method)),
149
- [],
150
- [factory.createStringLiteral(ctx.route.path)],
151
- ),
152
- ),
153
- );
197
+ decorators.push(nest(StringUtil.capitalize(ctx.route.method)));
154
198
  else if (ctx.route.success?.type === "application/x-www-form-urlencoded")
155
199
  decorators.push(router("TypedQuery"));
156
- else if (ctx.route.method === "head")
200
+ else if (ctx.route.method === "head") decorators.push(nest("Head"));
201
+ else if (
202
+ ctx.route.success === null ||
203
+ ctx.route.success?.type === "application/json"
204
+ )
205
+ decorators.push(router("TypedRoute"));
206
+ // NestJS answers 201 for POST and 200 otherwise
207
+ const status: number | null = SuccessStatus.of(ctx.route);
208
+ if (status !== null && status !== SuccessStatus.nest(ctx.route))
157
209
  decorators.push(
158
210
  factory.createDecorator(
159
211
  factory.createCallExpression(
160
- external("@nestjs/common", "Head"),
161
- [],
162
- [factory.createStringLiteral(ctx.route.path)],
212
+ external("@nestjs/common", "HttpCode"),
213
+ undefined,
214
+ [ExpressionFactory.number(status)],
163
215
  ),
164
216
  ),
165
217
  );
166
- else if (
167
- ctx.route.success === null ||
168
- ctx.route.success?.type === "application/json"
169
- )
170
- decorators.push(router("TypedRoute"));
171
218
  for (const [key, value] of Object.entries(ctx.route.exceptions ?? {}))
172
219
  decorators.push(
173
220
  factory.createDecorator(
@@ -291,11 +338,7 @@ export namespace NestiaMigrateNestMethodProgrammer {
291
338
  : [],
292
339
  })(ctx.components)(ctx.importer)({
293
340
  schema: ctx.route.body.schema,
294
- required: !(
295
- (ctx.route.body.type === "application/json" ||
296
- ctx.route.body.type === "text/plain") &&
297
- ctx.route.operation().requestBody?.required === false
298
- ),
341
+ required: RequestBody.optional(ctx.route) === false,
299
342
  example: ctx.route.body.media().example,
300
343
  examples: ctx.route.body.media().examples,
301
344
  }),
@@ -380,8 +423,10 @@ export namespace NestiaMigrateNestMethodProgrammer {
380
423
  ),
381
424
  ]
382
425
  : []),
383
- ...Object.entries(media.examples ?? {}).map(([key, value]) =>
384
- factory.createDecorator(
426
+ ...Object.entries(media.examples ?? {}).flatMap(([key, example]) => {
427
+ const value: { value: unknown } | null = exampleValue(example);
428
+ if (value === null) return [];
429
+ return factory.createDecorator(
385
430
  factory.createCallExpression(
386
431
  IdentifierFactory.access(
387
432
  factory.createIdentifier(
@@ -394,9 +439,57 @@ export namespace NestiaMigrateNestMethodProgrammer {
394
439
  kind,
395
440
  ),
396
441
  [],
397
- [factory.createStringLiteral(key), LiteralFactory.write(value)],
442
+ [
443
+ factory.createStringLiteral(key),
444
+ LiteralFactory.write(value.value),
445
+ ],
398
446
  ),
399
- ),
400
- ),
447
+ );
448
+ }),
401
449
  ];
402
450
  }
451
+
452
+ /**
453
+ * The value a named example stands for, or `null` when it names none.
454
+ *
455
+ * OpenAPI names examples with Example Objects, whose `value` (or, since 3.2,
456
+ * `dataValue`) holds the value, and a `$ref` to one arrives resolved. Documents
457
+ * from earlier nestia versions held the values themselves, so an object is read
458
+ * as an Example Object only when it is one: it has one of the value fields, and
459
+ * every other key is an Example Object field or an extension. A raw value of
460
+ * exactly that shape is ambiguous and is read as an Example Object, as a
461
+ * conforming document means it. An Example Object that only points at its value
462
+ * (`externalValue`) or only serializes it (`serializedValue`) gives
463
+ * `SwaggerExample` nothing to hold.
464
+ */
465
+ const exampleValue = (example: unknown): { value: unknown } | null => {
466
+ if (isExampleObject(example) === false) return { value: example };
467
+ const record = example as Record<string, unknown>;
468
+ if (Object.prototype.hasOwnProperty.call(record, "value"))
469
+ return { value: record.value };
470
+ if (Object.prototype.hasOwnProperty.call(record, "dataValue"))
471
+ return { value: record.dataValue };
472
+ return null;
473
+ };
474
+
475
+ const isExampleObject = (example: unknown): boolean =>
476
+ typeof example === "object" &&
477
+ example !== null &&
478
+ Array.isArray(example) === false &&
479
+ VALUE_KEYS.some((key) =>
480
+ Object.prototype.hasOwnProperty.call(example, key),
481
+ ) &&
482
+ Object.keys(example).every(
483
+ (key) =>
484
+ VALUE_KEYS.includes(key) ||
485
+ key === "summary" ||
486
+ key === "description" ||
487
+ key.startsWith("x-"),
488
+ );
489
+
490
+ const VALUE_KEYS: string[] = [
491
+ "value",
492
+ "dataValue",
493
+ "serializedValue",
494
+ "externalValue",
495
+ ];
@@ -4,7 +4,23 @@ import ts from "../internal/ts";
4
4
  import { INestiaMigrateController } from "../structures/INestiaMigrateController";
5
5
  import { FilePrinter } from "../utils/FilePrinter";
6
6
 
7
+ /**
8
+ * Generates the NestJS module that lists the controllers.
9
+ *
10
+ * @evidence contracts/common.md#principled-implementation The module imports every controller from its location and lists them in the `controllers` array of a decorated class.
11
+ * @evidence contracts/common.md#clear-and-simple-design One function and one private import builder.
12
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The controllers follow the analysis.
13
+ * @evidence contracts/common.md#meaningful-documentation The comment states what is generated.
14
+ */
7
15
  export namespace NestiaMigrateNestModuleProgrammer {
16
+ /**
17
+ * Returns the statements of the module file.
18
+ *
19
+ * @evidence contracts/common.md#principled-implementation The import paths turn the `src/` prefix of a controller location into `./`, so the module can import from its own directory.
20
+ * @evidence contracts/common.md#clear-and-simple-design One function.
21
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The names follow the controllers.
22
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result.
23
+ */
8
24
  export const write = (
9
25
  controllers: INestiaMigrateController[],
10
26
  ): ts.Statement[] => [
@@ -10,7 +10,24 @@ import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
10
10
  import { NestiaMigrateNestControllerProgrammer } from "./NestiaMigrateNestControllerProgrammer";
11
11
  import { NestiaMigrateNestModuleProgrammer } from "./NestiaMigrateNestModuleProgrammer";
12
12
 
13
+ /**
14
+ * Generates the NestJS side of a monorepo project: the module, the controllers,
15
+ * and the DTO structures.
16
+ *
17
+ * @evidence contracts/common.md#principled-implementation The controllers come from the analyzer, each DTO tree becomes a structure file, and a barrel file re-exports every non-empty structure file so the template's module keeps working.
18
+ * @evidence contracts/common.md#clear-and-simple-design One public function and private helpers for the DTO files and the barrel.
19
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The layout follows the analysis.
20
+ * @evidence contracts/common.md#meaningful-documentation The comment states what is generated.
21
+ */
13
22
  export namespace NestiaMigrateNestProgrammer {
23
+ /**
24
+ * Returns the map from file path to content of the NestJS files.
25
+ *
26
+ * @evidence contracts/common.md#principled-implementation The barrel is computed from the generated structure files, sorted by name, so its content is deterministic.
27
+ * @evidence contracts/common.md#clear-and-simple-design One function.
28
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The names follow the document.
29
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result.
30
+ */
14
31
  export const write = (
15
32
  context: INestiaMigrateContext,
16
33
  ): Record<string, string> => {
@@ -2,17 +2,33 @@ import { SyntaxKind, factory } from "@ttsc/factory";
2
2
  import { NamingConvention, OpenApiTypeChecker } from "@typia/utils";
3
3
  import type { OpenApi } from "typia";
4
4
 
5
- import { FormatCheatSheet } from "../factories/FormatCheatSheet";
5
+ import { SUPPORTED_STRING_FORMATS } from "../factories/SupportedStringFormats";
6
6
  import { TypeFactory } from "../factories/TypeFactory";
7
7
  import ts from "../internal/ts";
8
8
  import { FilePrinter } from "../utils/FilePrinter";
9
9
  import { StringUtil } from "../utils/StringUtil";
10
10
  import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
11
11
 
12
+ /**
13
+ * Generates the TypeScript type of an OpenAPI schema.
14
+ *
15
+ * @evidence contracts/common.md#principled-implementation The schema kind is decided by the type checker of `@typia/utils`, and each kind becomes a type: constants as literal types, numbers, integers, and strings with their constraints as `typia.tags` intersections, arrays, tuples, objects, references, and unions, with `any` for an unknown schema.
16
+ * @evidence contracts/common.md#clear-and-simple-design One entry function that dispatches to one private writer per kind.
17
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The dispatch follows the schema kinds of OpenAPI, and no schema name is special-cased.
18
+ * @evidence contracts/common.md#meaningful-documentation The comment states what is generated.
19
+ */
12
20
  export namespace NestiaMigrateSchemaProgrammer {
13
21
  /* -----------------------------------------------------------
14
22
  FACADE
15
23
  ----------------------------------------------------------- */
24
+ /**
25
+ * Returns the type node of a schema.
26
+ *
27
+ * @evidence contracts/common.md#principled-implementation An unknown schema is `any`, a `oneOf` becomes a TypeScript union, integer formats outside the supported four use the migration default `int64`, a binary string becomes `File`, and known string formats become typia tags. TypeScript unions do not encode oneOf exclusivity, and unsupported formats impose no generated constraint.
28
+ * @evidence contracts/common.md#clear-and-simple-design One function with an ordered chain of schema kind tests.
29
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Schema-kind dispatch applies uniformly; the int64 fallback and supported-format table are generator policies rather than constraints supplied by the document.
30
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result.
31
+ */
16
32
  export const write = (props: {
17
33
  components: OpenApi.IComponents;
18
34
  importer: NestiaMigrateImportProgrammer;
@@ -123,12 +139,29 @@ export namespace NestiaMigrateSchemaProgrammer {
123
139
  writeNumeric({
124
140
  factory: () => [
125
141
  TypeFactory.keyword("number"),
126
- props.importer.tag("Type", "int32"),
142
+ props.importer.tag("Type", integerType(props.schema)),
127
143
  ],
128
144
  importer: props.importer,
129
145
  schema: props.schema,
130
146
  });
131
147
 
148
+ /**
149
+ * The typia integer type admitting what the schema admits: its own `format`
150
+ * when it names one typia has, else `int64`, as an integer schema without a
151
+ * format admits any integer.
152
+ */
153
+ const integerType = (
154
+ schema: OpenApi.IJsonSchema.IInteger,
155
+ ): "int32" | "uint32" | "int64" | "uint64" => {
156
+ const format: unknown = (schema as { format?: unknown }).format;
157
+ return format === "int32" ||
158
+ format === "uint32" ||
159
+ format === "int64" ||
160
+ format === "uint64"
161
+ ? format
162
+ : "int64";
163
+ };
164
+
132
165
  const writeNumber = (props: {
133
166
  importer: NestiaMigrateImportProgrammer;
134
167
  schema: OpenApi.IJsonSchema.INumber;
@@ -147,19 +180,19 @@ export namespace NestiaMigrateSchemaProgrammer {
147
180
  const intersection: ts.TypeNode[] = props.factory();
148
181
  if (props.schema.default !== undefined)
149
182
  intersection.push(props.importer.tag("Default", props.schema.default));
183
+ // the emended schema holds each bound as a number, as OpenAPI 3.1 does;
184
+ // an OpenAPI 3.0 boolean `exclusiveMinimum` is converted into that form
150
185
  if (props.schema.minimum !== undefined)
186
+ intersection.push(props.importer.tag("Minimum", props.schema.minimum));
187
+ if (typeof props.schema.exclusiveMinimum === "number")
151
188
  intersection.push(
152
- props.importer.tag(
153
- props.schema.exclusiveMinimum ? "ExclusiveMinimum" : "Minimum",
154
- props.schema.minimum,
155
- ),
189
+ props.importer.tag("ExclusiveMinimum", props.schema.exclusiveMinimum),
156
190
  );
157
191
  if (props.schema.maximum !== undefined)
192
+ intersection.push(props.importer.tag("Maximum", props.schema.maximum));
193
+ if (typeof props.schema.exclusiveMaximum === "number")
158
194
  intersection.push(
159
- props.importer.tag(
160
- props.schema.exclusiveMaximum ? "ExclusiveMaximum" : "Maximum",
161
- props.schema.maximum,
162
- ),
195
+ props.importer.tag("ExclusiveMaximum", props.schema.exclusiveMaximum),
163
196
  );
164
197
  if (props.schema.multipleOf !== undefined)
165
198
  intersection.push(
@@ -192,8 +225,7 @@ export namespace NestiaMigrateSchemaProgrammer {
192
225
  intersection.push(props.importer.tag("Pattern", props.schema.pattern));
193
226
  if (
194
227
  props.schema.format !== undefined &&
195
- (FormatCheatSheet as Record<string, string>)[props.schema.format] !==
196
- undefined
228
+ SUPPORTED_STRING_FORMATS.has(props.schema.format)
197
229
  )
198
230
  intersection.push(props.importer.tag("Format", props.schema.format));
199
231
  if (props.schema.contentMediaType !== undefined)
@@ -250,11 +282,13 @@ export namespace NestiaMigrateSchemaProgrammer {
250
282
  props.schema.additionalItems !== null
251
283
  ? [
252
284
  factory.createRestTypeNode(
253
- write({
254
- components: props.components,
255
- importer: props.importer,
256
- schema: props.schema.additionalItems,
257
- }),
285
+ factory.createArrayTypeNode(
286
+ write({
287
+ components: props.components,
288
+ importer: props.importer,
289
+ schema: props.schema.additionalItems,
290
+ }),
291
+ ),
258
292
  ),
259
293
  ]
260
294
  : props.schema.additionalItems === true
@@ -299,7 +333,8 @@ export namespace NestiaMigrateSchemaProgrammer {
299
333
  schema: props.schema.additionalProperties as OpenApi.IJsonSchema,
300
334
  }),
301
335
  ]);
302
- return !!props.schema.properties?.length &&
336
+ // `properties` is a record, which has no length
337
+ return Object.keys(props.schema.properties ?? {}).length !== 0 &&
303
338
  typeof props.schema.additionalProperties === "object"
304
339
  ? factory.createIntersectionTypeNode([regular(), dynamic()])
305
340
  : typeof props.schema.additionalProperties === "object"
@@ -1,15 +1,41 @@
1
1
  import ts from "../internal/ts";
2
2
  import { NestiaMigrateNestMethodProgrammer } from "../programmers/NestiaMigrateNestMethodProgrammer";
3
3
 
4
+ /**
5
+ * Options of the migration: simulation, e2e tests, the package name, keyword
6
+ * parameters, the author tag, and a replaceable controller method programmer.
7
+ *
8
+ * @evidence contracts/common.md#principled-implementation The flags choose which parts are generated and the parameter style, the package name replaces the placeholder in every file, and the programmer option lets a caller generate controller methods differently.
9
+ * @evidence contracts/common.md#clear-and-simple-design A flat record whose optional members are the extension points.
10
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
11
+ * @evidence contracts/common.md#meaningful-documentation The comment lists the options.
12
+ */
4
13
  export interface INestiaMigrateConfig {
14
+ /** Include runtime request validation and random-response simulator members. */
5
15
  simulate: boolean;
16
+
17
+ /** Emit a generated test feature for each migrated operation. */
6
18
  e2e: boolean;
19
+
20
+ /** Replace the template package placeholder; omission retains the placeholder. */
7
21
  package?: string;
22
+
23
+ /**
24
+ * Use a props object when true; false or omission selects positional
25
+ * parameters.
26
+ */
8
27
  keyword?: boolean;
28
+
29
+ /** Override the generated declaration attribution tag and its text. */
9
30
  author?: {
10
31
  tag: string;
11
32
  value: string;
12
33
  };
34
+
35
+ /**
36
+ * Replace controller method emission while retaining the surrounding
37
+ * controller.
38
+ */
13
39
  programmer?: {
14
40
  controllerMethod?: (
15
41
  ctx: NestiaMigrateNestMethodProgrammer.IContext,
@@ -2,8 +2,25 @@ import { IHttpMigrateApplication } from "@typia/interface";
2
2
 
3
3
  import { INestiaMigrateConfig } from "./INestiaMigrateConfig";
4
4
 
5
+ /**
6
+ * The shared input of the programmers: the mode, the analyzed application, and
7
+ * the configuration.
8
+ *
9
+ * @evidence contracts/common.md#principled-implementation The record is built once per migration, so every programmer sees the same routes and options.
10
+ * @evidence contracts/common.md#clear-and-simple-design A three-member record.
11
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
12
+ * @evidence contracts/common.md#meaningful-documentation The comment lists the members.
13
+ */
5
14
  export interface INestiaMigrateContext {
15
+ /** Select backend/API workspace output or a standalone SDK project. */
6
16
  mode: "nest" | "sdk";
17
+
18
+ /**
19
+ * Generation-local route/accessor copies backed by the shared analyzed
20
+ * document.
21
+ */
7
22
  application: IHttpMigrateApplication;
23
+
24
+ /** Options used consistently by each programmer in this generation. */
8
25
  config: INestiaMigrateConfig;
9
26
  }