@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
@@ -9,18 +9,53 @@ import { TypeFactory } from "../factories/TypeFactory";
9
9
  import ts from "../internal/ts";
10
10
  import { INestiaMigrateConfig } from "../structures/INestiaMigrateConfig";
11
11
  import { FilePrinter } from "../utils/FilePrinter";
12
+ import { PathTemplate } from "../utils/PathTemplate";
13
+ import { RequestBody } from "../utils/RequestBody";
12
14
  import { NestiaMigrateApiSimulationProgrammer } from "./NestiaMigrateApiSimulationProgrammer";
13
15
  import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
14
16
  import { NestiaMigrateSchemaProgrammer } from "./NestiaMigrateSchemaProgrammer";
15
17
 
18
+ /**
19
+ * Generates the namespace that accompanies the function of a route: its types,
20
+ * its metadata, its path builder, and, in simulation mode, its simulator.
21
+ *
22
+ * @evidence contracts/common.md#principled-implementation The namespace declares the `Props`, `Query`, `Body`, `Headers`, and `Response` types from the schemas, the route metadata the fetcher reads, the `path` function that fills the parameters into the template, and the simulator members.
23
+ * @evidence contracts/common.md#clear-and-simple-design One entry function, one public path-call builder shared with the simulation programmer, and private helpers per member.
24
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The output derives from the route and the configuration.
25
+ * @evidence contracts/common.md#meaningful-documentation The comment states what is generated.
26
+ */
16
27
  export namespace NestiaMigrateApiNamespaceProgrammer {
28
+ /**
29
+ * The input of one namespace: the configuration, the components, the
30
+ * importer, and the route.
31
+ *
32
+ * @evidence contracts/common.md#principled-implementation The record holds exactly what the namespace generation needs.
33
+ * @evidence contracts/common.md#clear-and-simple-design A flat record.
34
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
35
+ * @evidence contracts/common.md#meaningful-documentation The comment lists the fields.
36
+ */
17
37
  export interface IContext {
38
+ /** Calling convention and optional generated features for this operation. */
18
39
  config: INestiaMigrateConfig;
40
+
41
+ /** Component schemas used to resolve DTO references. */
19
42
  components: OpenApi.IComponents;
43
+
44
+ /** File-local import collector shared with the surrounding file writer. */
20
45
  importer: NestiaMigrateImportProgrammer;
46
+
47
+ /** Analyzed operation, with the accessor chosen for this generation. */
21
48
  route: IHttpMigrateRoute;
22
49
  }
23
50
 
51
+ /**
52
+ * Returns the namespace declaration of a route.
53
+ *
54
+ * @evidence contracts/common.md#principled-implementation The members are written in a fixed order: types, metadata, path function, and the random and simulate members when simulation is enabled.
55
+ * @evidence contracts/common.md#clear-and-simple-design One function composing the private writers.
56
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The members follow the configuration.
57
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result.
58
+ */
24
59
  export const write = (ctx: IContext): ts.ModuleDeclaration => {
25
60
  const types: ts.TypeAliasDeclaration[] = writeTypes(ctx);
26
61
  return factory.createModuleDeclaration(
@@ -43,6 +78,15 @@ export namespace NestiaMigrateApiNamespaceProgrammer {
43
78
  );
44
79
  };
45
80
 
81
+ /**
82
+ * Returns the call expression of the route's `path` function with the
83
+ * arguments the configuration selects.
84
+ *
85
+ * @evidence contracts/common.md#principled-implementation In keyword mode the arguments are the `props` object and otherwise the path and query parameters in order, so the same call is valid in both modes.
86
+ * @evidence contracts/common.md#clear-and-simple-design One function shared by the simulator and the namespace.
87
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The arguments follow the configuration.
88
+ * @evidence contracts/common.md#meaningful-documentation The comment states the two argument forms.
89
+ */
46
90
  export const writePathCallExpression = (
47
91
  config: INestiaMigrateConfig,
48
92
  route: IHttpMigrateRoute,
@@ -116,7 +160,9 @@ export namespace NestiaMigrateApiNamespaceProgrammer {
116
160
  required: [
117
161
  ...ctx.route.parameters.map((p) => p.key),
118
162
  ...(ctx.route.query ? [ctx.route.query.key] : []),
119
- ...(ctx.route.body ? [ctx.route.body.key] : []),
163
+ ...(ctx.route.body && RequestBody.optional(ctx.route) === false
164
+ ? [ctx.route.body.key]
165
+ : []),
120
166
  ],
121
167
  },
122
168
  }),
@@ -280,32 +326,49 @@ export namespace NestiaMigrateApiNamespaceProgrammer {
280
326
  ),
281
327
  );
282
328
  const template = () => {
283
- const path: string = getPath(ctx.route);
284
- const split: string[] = path.split(":");
285
- if (split.length === 1) return factory.createStringLiteral(path);
329
+ // the document's template delimits each parameter; the emended path's
330
+ // `:id.json` would not tell the name from the literal after it
331
+ const segments: PathTemplate.ISegment[] = PathTemplate.segments(
332
+ ctx.route,
333
+ );
334
+ if (segments.every((segment) => segment.type === "literal"))
335
+ return factory.createStringLiteral(getPath(ctx.route));
336
+ const literals: string[] = [""];
337
+ const parameters: IHttpMigrateRoute.IParameter[] = [];
338
+ for (const segment of segments)
339
+ if (segment.type === "literal")
340
+ literals[literals.length - 1] += segment.value;
341
+ else {
342
+ parameters.push(segment.parameter);
343
+ literals.push("");
344
+ }
286
345
  return factory.createTemplateExpression(
287
- factory.createTemplateHead(split[0]!),
288
- split.slice(1).map((s, i, arr) => {
289
- const name: string = s.split("/")[0]!;
290
- return factory.createTemplateSpan(
346
+ factory.createTemplateHead(literals[0]!),
347
+ parameters.map((parameter, i) =>
348
+ factory.createTemplateSpan(
349
+ // URI-encoded, "null" when nullish, and a dot segment refused
291
350
  factory.createCallExpression(
292
- factory.createIdentifier("encodeURIComponent"),
351
+ IdentifierFactory.access(
352
+ factory.createIdentifier(
353
+ ctx.importer.external({
354
+ type: "instance",
355
+ library: "@nestia/fetcher",
356
+ name: "PathParameter",
357
+ }),
358
+ ),
359
+ "encode",
360
+ ),
293
361
  undefined,
294
362
  [
295
- factory.createBinaryExpression(
296
- property(
297
- ctx.route.parameters.find((p) => p.name === name)!.key,
298
- ),
299
- factory.createToken(SyntaxKind.QuestionQuestionToken),
300
- factory.createStringLiteral("null"),
301
- ),
363
+ factory.createStringLiteral(parameter.key),
364
+ property(parameter.key),
302
365
  ],
303
366
  ),
304
- (i !== arr.length - 1
367
+ (i !== parameters.length - 1
305
368
  ? factory.createTemplateMiddle
306
- : factory.createTemplateTail)(s.substring(name.length)),
307
- );
308
- }),
369
+ : factory.createTemplateTail)(literals[i + 1]!),
370
+ ),
371
+ ),
309
372
  );
310
373
  };
311
374
  if (!ctx.route.query) return out(template());
@@ -8,7 +8,25 @@ import { NestiaMigrateApiFileProgrammer } from "./NestiaMigrateApiFileProgrammer
8
8
  import { NestiaMigrateDtoProgrammer } from "./NestiaMigrateDtoProgrammer";
9
9
  import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
10
10
 
11
+ /**
12
+ * Generates the functional API files and, for an SDK project, the DTO structure
13
+ * files.
14
+ *
15
+ * @evidence contracts/common.md#principled-implementation Routes are grouped by namespace path in a hash map, each parent namespace is given its child, and each namespace becomes one `index.ts`; the DTO files are written per top-level component name.
16
+ * @evidence contracts/common.md#clear-and-simple-design One entry function and two private helpers for the DTO files.
17
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The layout follows the accessors of the routes.
18
+ * @evidence contracts/common.md#meaningful-documentation The comment states what is generated.
19
+ */
11
20
  export namespace NestiaMigrateApiProgrammer {
21
+ /**
22
+ * Returns the map from file path to content of the functional API, with the
23
+ * DTO files for an SDK project.
24
+ *
25
+ * @evidence contracts/common.md#principled-implementation The grouping creates every ancestor namespace so that each level has an index, and the paths differ between the two modes only by their root.
26
+ * @evidence contracts/common.md#clear-and-simple-design One function.
27
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The layout follows the accessors.
28
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result.
29
+ */
12
30
  export const write = (ctx: INestiaMigrateContext): Record<string, string> => {
13
31
  const dict: HashMap<string[], NestiaMigrateApiFileProgrammer.IProps> =
14
32
  new HashMap(
@@ -12,14 +12,48 @@ import { NestiaMigrateApiNamespaceProgrammer } from "./NestiaMigrateApiNamespace
12
12
  import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
13
13
  import { NestiaMigrateSchemaProgrammer } from "./NestiaMigrateSchemaProgrammer";
14
14
 
15
+ /**
16
+ * Generates the mockup simulator members of a route: a random response and a
17
+ * simulate function that validates the request first.
18
+ *
19
+ * @evidence contracts/common.md#principled-implementation The random member calls `typia.random` for the response type, and the simulate function validates the parameters, query, body, and headers with `typia.assert` through the fetcher's simulator, so an invalid simulated request throws the error the real server answers.
20
+ * @evidence contracts/common.md#clear-and-simple-design Two public functions and one private assertion writer.
21
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The simulation follows the schemas of the route.
22
+ * @evidence contracts/common.md#meaningful-documentation The comment states what is generated.
23
+ */
15
24
  export namespace NestiaMigrateApiSimulationProgrammer {
25
+ /**
26
+ * The input of the simulation members: the configuration, the components, the
27
+ * importer, and the route.
28
+ *
29
+ * @evidence contracts/common.md#principled-implementation The record holds exactly what the generation needs.
30
+ * @evidence contracts/common.md#clear-and-simple-design A flat record.
31
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
32
+ * @evidence contracts/common.md#meaningful-documentation The comment lists the fields.
33
+ */
16
34
  export interface IContext {
35
+ /** Calling convention and optional generated features for this operation. */
17
36
  config: INestiaMigrateConfig;
37
+
38
+ /** Component schemas used to resolve DTO references. */
18
39
  components: OpenApi.IComponents;
40
+
41
+ /** File-local import collector shared with the surrounding file writer. */
19
42
  importer: NestiaMigrateImportProgrammer;
43
+
44
+ /** Analyzed operation, with the accessor chosen for this generation. */
20
45
  route: IHttpMigrateRoute;
21
46
  }
22
47
 
48
+ /**
49
+ * Returns the `random` constant: a function that returns a random value of
50
+ * the response type.
51
+ *
52
+ * @evidence contracts/common.md#principled-implementation The response schema is written as a type and given to `typia.random`, and a route without a response uses `void`.
53
+ * @evidence contracts/common.md#clear-and-simple-design One expression.
54
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The value is produced by typia at run time.
55
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result.
56
+ */
23
57
  export const random = (ctx: IContext) => {
24
58
  const output = ctx.route.success
25
59
  ? NestiaMigrateSchemaProgrammer.write({
@@ -54,6 +88,15 @@ export namespace NestiaMigrateApiSimulationProgrammer {
54
88
  );
55
89
  };
56
90
 
91
+ /**
92
+ * Returns the `simulate` constant: a function with the route's parameters
93
+ * that validates the request and returns a random response.
94
+ *
95
+ * @evidence contracts/common.md#principled-implementation The parameters are those of the real function, the assertions run first, and an unused connection is renamed so the compiler does not report it.
96
+ * @evidence contracts/common.md#clear-and-simple-design One expression over the shared parameter builder.
97
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The validation is generated from the same schemas as the real function's types.
98
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result.
99
+ */
57
100
  export const simulate = (ctx: IContext): ts.VariableStatement => {
58
101
  const caller = () =>
59
102
  factory.createCallExpression(
@@ -70,7 +113,8 @@ export namespace NestiaMigrateApiSimulationProgrammer {
70
113
  ctx,
71
114
  ctx.route.parameters.length === 0 &&
72
115
  ctx.route.query === null &&
73
- ctx.route.body === null
116
+ ctx.route.body === null &&
117
+ ctx.route.headers === null
74
118
  ? "_connection"
75
119
  : undefined,
76
120
  ),
@@ -127,6 +171,20 @@ export namespace NestiaMigrateApiSimulationProgrammer {
127
171
  },
128
172
  ]
129
173
  : []),
174
+ // the headers travel in the connection, validated as the server does
175
+ ...(ctx.route.headers
176
+ ? [
177
+ {
178
+ category: "headers",
179
+ name: ctx.route.headers.key,
180
+ schema: NestiaMigrateSchemaProgrammer.write({
181
+ components: ctx.components,
182
+ importer: ctx.importer,
183
+ schema: ctx.route.headers.schema,
184
+ }),
185
+ },
186
+ ]
187
+ : []),
130
188
  ];
131
189
  if (parameters.length === 0) return [];
132
190
 
@@ -206,7 +264,9 @@ export namespace NestiaMigrateApiSimulationProgrammer {
206
264
  ),
207
265
  "assert",
208
266
  ),
209
- undefined,
267
+ // `connection.headers` is typed optional with optional
268
+ // members, so the headers name their own type to be checked
269
+ p.category === "headers" ? [p.schema] : undefined,
210
270
  [
211
271
  p.category === "headers"
212
272
  ? factory.createIdentifier("connection.headers")
@@ -218,78 +278,11 @@ export namespace NestiaMigrateApiSimulationProgrammer {
218
278
  ),
219
279
  )
220
280
  .map(factory.createExpressionStatement) as ts.Statement[];
221
- return [validator, tryAndCatch(ctx.importer, individual)];
281
+ // the SDK fetches without propagation, so an invalid simulated request
282
+ // throws its HttpError as the real one does, instead of answering a
283
+ // propagation object in place of the response
284
+ return [validator, ...individual];
222
285
  };
223
-
224
- const tryAndCatch = (
225
- importer: NestiaMigrateImportProgrammer,
226
- individual: ts.Statement[],
227
- ) =>
228
- factory.createTryStatement(
229
- factory.createBlock(individual, true),
230
- factory.createCatchClause(
231
- "exp",
232
- factory.createBlock(
233
- [
234
- factory.createIfStatement(
235
- factory.createLogicalNot(
236
- factory.createCallExpression(
237
- IdentifierFactory.access(
238
- factory.createIdentifier(
239
- importer.external({
240
- type: "default",
241
- library: "typia",
242
- name: "typia",
243
- }),
244
- ),
245
- "is",
246
- ),
247
- [
248
- factory.createTypeReferenceNode(
249
- importer.external({
250
- type: "instance",
251
- library: "@nestia/fetcher",
252
- name: "HttpError",
253
- }),
254
- ),
255
- ],
256
- [factory.createIdentifier("exp")],
257
- ),
258
- ),
259
- factory.createThrowStatement(factory.createIdentifier("exp")),
260
- ),
261
- factory.createReturnStatement(
262
- factory.createAsExpression(
263
- factory.createObjectLiteralExpression(
264
- [
265
- factory.createPropertyAssignment(
266
- "success",
267
- factory.createFalse(),
268
- ),
269
- factory.createPropertyAssignment(
270
- "status",
271
- factory.createIdentifier("exp.status"),
272
- ),
273
- factory.createPropertyAssignment(
274
- "headers",
275
- factory.createIdentifier("exp.headers"),
276
- ),
277
- factory.createPropertyAssignment(
278
- "data",
279
- factory.createIdentifier("exp.toJSON().message"),
280
- ),
281
- ],
282
- true,
283
- ),
284
- TypeFactory.keyword("any"),
285
- ),
286
- ),
287
- ],
288
- true,
289
- ),
290
- ),
291
- undefined,
292
- );
293
286
  }
294
287
 
295
288
  const constant = (name: string, expression: ts.Expression) =>
@@ -9,15 +9,31 @@ import { FilePrinter } from "../utils/FilePrinter";
9
9
  import { NestiaMigrateE2eFunctionProgrammer } from "./NestiaMigrateE2eFileProgrammer";
10
10
  import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
11
11
 
12
+ /**
13
+ * Generates the `test/start.ts` of an SDK project: a small program that calls
14
+ * one API function.
15
+ *
16
+ * @evidence contracts/common.md#principled-implementation The program builds a connection from the global test settings and the first server of the document, adds the simulate flag when requested, and calls the first route the way the generated e2e tests do, so one command can check that the SDK and a server agree.
17
+ * @evidence contracts/common.md#clear-and-simple-design One entry function and private helpers for the connection, the main function, and the starter.
18
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The route is the first one, so the same document always generates the same file.
19
+ * @evidence contracts/common.md#meaningful-documentation The comment states what is generated.
20
+ */
12
21
  export namespace NestiaMigrateApiStartProgrammer {
22
+ /**
23
+ * Returns the `test/start.ts` file of an SDK project.
24
+ *
25
+ * @evidence contracts/common.md#principled-implementation The file imports what the body uses, defines `main`, and starts it, exiting with a failure status when it rejects.
26
+ * @evidence contracts/common.md#clear-and-simple-design One function.
27
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The content derives from the document.
28
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result.
29
+ */
13
30
  export const write = (
14
31
  context: INestiaMigrateContext,
15
32
  ): Record<string, string> => {
16
33
  const importer: NestiaMigrateImportProgrammer =
17
34
  new NestiaMigrateImportProgrammer();
18
- const route: IHttpMigrateRoute | undefined = pick(
19
- context.application.routes,
20
- );
35
+ // the first route, so the same document always generates the same file
36
+ const route: IHttpMigrateRoute | undefined = context.application.routes[0];
21
37
  const main: ts.VariableStatement = writeMain(context, importer, route);
22
38
  const statements: ts.Statement[] = [
23
39
  ...importer.toStatements(
@@ -197,10 +213,3 @@ export namespace NestiaMigrateApiStartProgrammer {
197
213
  ],
198
214
  );
199
215
  }
200
-
201
- const pick = <T>(array: T[]): T | undefined => {
202
- if (array.length === 0) return undefined;
203
- const rand: number = Math.random() * array.length;
204
- const index: number = Math.min(array.length - 1, Math.floor(rand));
205
- return array[index]!;
206
- };
@@ -10,17 +10,50 @@ import { StringUtil } from "../utils/StringUtil";
10
10
  import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
11
11
  import { NestiaMigrateSchemaProgrammer } from "./NestiaMigrateSchemaProgrammer";
12
12
 
13
+ /**
14
+ * Generates the DTO type aliases from the component schemas.
15
+ *
16
+ * @evidence contracts/common.md#principled-implementation Each component name is normalized into a valid dotted name, the dots become nested namespaces, and each schema becomes an exported type alias with its description and its tags as a comment.
17
+ * @evidence contracts/common.md#clear-and-simple-design One public function and private builders for the module tree and the alias.
18
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The names derive from the schema names.
19
+ * @evidence contracts/common.md#meaningful-documentation The comment states what is generated.
20
+ */
13
21
  export namespace NestiaMigrateDtoProgrammer {
22
+ /**
23
+ * A node of the DTO namespace tree: its name, its children, and the writer of
24
+ * its alias, or `null` for a namespace without a type of its own.
25
+ *
26
+ * @evidence contracts/common.md#principled-implementation The tree mirrors the dotted names of the schemas, so a namespace exists exactly when a name passes through it.
27
+ * @evidence contracts/common.md#clear-and-simple-design A three-member record.
28
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
29
+ * @evidence contracts/common.md#meaningful-documentation The comment states the meaning of each member.
30
+ */
14
31
  export interface IModule {
15
32
  name: string;
33
+
34
+ /** Child segments of qualified schema names, preserving insertion order. */
16
35
  children: Map<string, IModule>;
36
+
37
+ /** Alias writer for a schema at this node, or null for a namespace alone. */
17
38
  programmer:
18
39
  | null
19
40
  | ((importer: NestiaMigrateImportProgrammer) => ts.TypeAliasDeclaration);
20
41
  }
21
42
 
43
+ /**
44
+ * Returns the root of the DTO tree: a map from the first name segment to its
45
+ * module.
46
+ *
47
+ * @evidence contracts/common.md#principled-implementation Each schema key is split on slashes, its segments are escaped into valid identifiers and joined, and the result is inserted along its dotted path.
48
+ * @evidence contracts/common.md#clear-and-simple-design One function over one insertion helper.
49
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The names come from the document.
50
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result.
51
+ */
22
52
  export const compose = (props: {
53
+ /** Calling convention and optional generated features for this operation. */
23
54
  config: INestiaMigrateConfig;
55
+
56
+ /** Component schemas used to resolve DTO references. */
24
57
  components: OpenApi.IComponents;
25
58
  }): Map<string, IModule> => {
26
59
  const dict: Map<string, IModule> = new Map();
@@ -9,14 +9,47 @@ import { INestiaMigrateConfig } from "../structures/INestiaMigrateConfig";
9
9
  import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
10
10
  import { NestiaMigrateSchemaProgrammer } from "./NestiaMigrateSchemaProgrammer";
11
11
 
12
+ /**
13
+ * Generates the e2e test function of one route.
14
+ *
15
+ * @evidence contracts/common.md#principled-implementation The function calls the route through the SDK with random arguments made by `typia.random`, including generated headers, and asserts the response with `typia.assert`, so the test checks that the server's answer matches the declared type.
16
+ * @evidence contracts/common.md#clear-and-simple-design One entry function, one public body writer shared with the start programmer, and a private call writer.
17
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The arguments are drawn at run time, and no route is special-cased.
18
+ * @evidence contracts/common.md#meaningful-documentation The comment states what is generated.
19
+ */
12
20
  export namespace NestiaMigrateE2eFunctionProgrammer {
21
+ /**
22
+ * The input of one test function: the configuration, the components, the
23
+ * importer, and the route.
24
+ *
25
+ * @evidence contracts/common.md#principled-implementation The record holds exactly what the generation needs.
26
+ * @evidence contracts/common.md#clear-and-simple-design A flat record.
27
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
28
+ * @evidence contracts/common.md#meaningful-documentation The comment lists the fields.
29
+ */
13
30
  export interface IContext {
31
+ /** Calling convention and optional generated features for this operation. */
14
32
  config: INestiaMigrateConfig;
33
+
34
+ /** Component schemas used to resolve DTO references. */
15
35
  components: OpenApi.IComponents;
36
+
37
+ /** File-local import collector shared with the surrounding file writer. */
16
38
  importer: NestiaMigrateImportProgrammer;
39
+
40
+ /** Analyzed operation, with the accessor chosen for this generation. */
17
41
  route: IHttpMigrateRoute;
18
42
  }
19
43
 
44
+ /**
45
+ * Returns the exported async test function of a route, named `test_api_`
46
+ * followed by its accessor.
47
+ *
48
+ * @evidence contracts/common.md#principled-implementation The name joins `test`, `api`, and the accessor with underscores, so it is unique for a route and matches the prefix that the e2e executor discovers.
49
+ * @evidence contracts/common.md#clear-and-simple-design One expression.
50
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The name derives from the accessor.
51
+ * @evidence contracts/common.md#meaningful-documentation The comment states the naming rule.
52
+ */
20
53
  export const write = (ctx: IContext): ts.FunctionDeclaration =>
21
54
  factory.createFunctionDeclaration(
22
55
  [
@@ -47,6 +80,15 @@ export namespace NestiaMigrateE2eFunctionProgrammer {
47
80
  factory.createBlock(writeBody(ctx), true),
48
81
  );
49
82
 
83
+ /**
84
+ * Returns the statements of the test body: the call with random arguments and
85
+ * the type assertion of its output.
86
+ *
87
+ * @evidence contracts/common.md#principled-implementation The call expression follows the parameter mode of the configuration, and the output is typed by the response schema when there is one.
88
+ * @evidence contracts/common.md#clear-and-simple-design One function shared with the start programmer.
89
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The body follows the route.
90
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result.
91
+ */
50
92
  export const writeBody = (ctx: IContext): ts.Statement[] => [
51
93
  factory.createVariableStatement(
52
94
  [],
@@ -91,14 +133,6 @@ export namespace NestiaMigrateE2eFunctionProgrammer {
91
133
  factory.createIdentifier("api.functional"),
92
134
  factory.createIdentifier(ctx.route.accessor.join(".")),
93
135
  );
94
- const connection = factory.createIdentifier("connection");
95
- if (
96
- ctx.route.parameters.length === 0 &&
97
- ctx.route.query === null &&
98
- ctx.route.body === null
99
- )
100
- return factory.createCallExpression(fetch, undefined, [connection]);
101
-
102
136
  const random = factory.createPropertyAccessExpression(
103
137
  factory.createIdentifier(
104
138
  ctx.importer.external({
@@ -109,6 +143,47 @@ export namespace NestiaMigrateE2eFunctionProgrammer {
109
143
  ),
110
144
  "random",
111
145
  );
146
+ // the route's headers travel in the connection, as the server requires
147
+ const connection: ts.Expression = ctx.route.headers
148
+ ? factory.createObjectLiteralExpression(
149
+ [
150
+ factory.createSpreadAssignment(
151
+ factory.createIdentifier("connection"),
152
+ ),
153
+ factory.createPropertyAssignment(
154
+ "headers",
155
+ factory.createObjectLiteralExpression(
156
+ [
157
+ factory.createSpreadAssignment(
158
+ factory.createIdentifier("connection.headers"),
159
+ ),
160
+ factory.createSpreadAssignment(
161
+ factory.createCallExpression(
162
+ random,
163
+ [
164
+ NestiaMigrateSchemaProgrammer.write({
165
+ components: ctx.components,
166
+ importer: ctx.importer,
167
+ schema: ctx.route.headers.schema,
168
+ }),
169
+ ],
170
+ undefined,
171
+ ),
172
+ ),
173
+ ],
174
+ true,
175
+ ),
176
+ ),
177
+ ],
178
+ true,
179
+ )
180
+ : factory.createIdentifier("connection");
181
+ if (
182
+ ctx.route.parameters.length === 0 &&
183
+ ctx.route.query === null &&
184
+ ctx.route.body === null
185
+ )
186
+ return factory.createCallExpression(fetch, undefined, [connection]);
112
187
  if (ctx.config.keyword === true)
113
188
  return factory.createCallExpression(fetch, undefined, [
114
189
  connection,
@@ -8,7 +8,23 @@ import { FilePrinter } from "../utils/FilePrinter";
8
8
  import { NestiaMigrateE2eFunctionProgrammer } from "./NestiaMigrateE2eFileProgrammer";
9
9
  import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
10
10
 
11
+ /**
12
+ * Generates the e2e test files, one per route.
13
+ *
14
+ * @evidence contracts/common.md#principled-implementation Each route becomes a file whose path depends on the mode and whose imports are resolved through the package name for a monorepo and through the built library path otherwise.
15
+ * @evidence contracts/common.md#clear-and-simple-design One public function and one private file writer.
16
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The layout follows the accessors.
17
+ * @evidence contracts/common.md#meaningful-documentation The comment states what is generated.
18
+ */
11
19
  export namespace NestiaMigrateE2eProgrammer {
20
+ /**
21
+ * Returns the map from file path to content of the e2e tests.
22
+ *
23
+ * @evidence contracts/common.md#principled-implementation The file name is `test_api_` plus the accessor, so each route has exactly one file.
24
+ * @evidence contracts/common.md#clear-and-simple-design One function.
25
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The names follow the accessors.
26
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result.
27
+ */
12
28
  export const write = (ctx: INestiaMigrateContext): Record<string, string> =>
13
29
  Object.fromEntries(
14
30
  ctx.application.routes