@nestia/sdk 13.0.4 → 14.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/README.md +1 -1
  2. package/assets/bundle/distribute/package.json +2 -2
  3. package/assets/bundle/distribute/tsconfig.json +15 -105
  4. package/lib/INestiaConfig.d.ts +19 -10
  5. package/lib/NestiaSdkApplication.js +58 -27
  6. package/lib/NestiaSdkApplication.js.map +1 -1
  7. package/lib/NestiaSwaggerComposer.js +11 -10
  8. package/lib/NestiaSwaggerComposer.js.map +1 -1
  9. package/lib/analyses/ConfigAnalyzer.js +4 -4
  10. package/lib/analyses/ConfigAnalyzer.js.map +1 -1
  11. package/lib/analyses/ParameterNameAnalyzer.d.ts +20 -0
  12. package/lib/analyses/ParameterNameAnalyzer.js +48 -0
  13. package/lib/analyses/ParameterNameAnalyzer.js.map +1 -0
  14. package/lib/analyses/PathAnalyzer.d.ts +30 -0
  15. package/lib/analyses/PathAnalyzer.js +108 -16
  16. package/lib/analyses/PathAnalyzer.js.map +1 -1
  17. package/lib/analyses/ReflectControllerAnalyzer.js +2 -1
  18. package/lib/analyses/ReflectControllerAnalyzer.js.map +1 -1
  19. package/lib/analyses/ReflectHttpOperationAnalyzer.js +7 -7
  20. package/lib/analyses/ReflectHttpOperationAnalyzer.js.map +1 -1
  21. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js +122 -23
  22. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js.map +1 -1
  23. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js +5 -2
  24. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js.map +1 -1
  25. package/lib/analyses/ReflectMcpOperationAnalyzer.js +5 -2
  26. package/lib/analyses/ReflectMcpOperationAnalyzer.js.map +1 -1
  27. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js +6 -3
  28. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js.map +1 -1
  29. package/lib/analyses/SecurityAnalyzer.d.ts +10 -0
  30. package/lib/analyses/SecurityAnalyzer.js +24 -19
  31. package/lib/analyses/SecurityAnalyzer.js.map +1 -1
  32. package/lib/analyses/SwaggerExampleAnalyzer.d.ts +15 -0
  33. package/lib/analyses/SwaggerExampleAnalyzer.js +20 -0
  34. package/lib/analyses/SwaggerExampleAnalyzer.js.map +1 -0
  35. package/lib/analyses/TypedHttpRouteAnalyzer.js +30 -21
  36. package/lib/analyses/TypedHttpRouteAnalyzer.js.map +1 -1
  37. package/lib/analyses/TypedWebSocketRouteAnalyzer.js +1 -1
  38. package/lib/analyses/TypedWebSocketRouteAnalyzer.js.map +1 -1
  39. package/lib/executable/internal/NestiaSdkWatcher.js +3 -3
  40. package/lib/executable/internal/NestiaSdkWatcher.js.map +1 -1
  41. package/lib/executable/sdk.js +16 -1
  42. package/lib/executable/sdk.js.map +1 -1
  43. package/lib/factories/ExpressionFactory.d.ts +3 -0
  44. package/lib/factories/ExpressionFactory.js +6 -2
  45. package/lib/factories/ExpressionFactory.js.map +1 -1
  46. package/lib/factories/LiteralFactory.js +3 -1
  47. package/lib/factories/LiteralFactory.js.map +1 -1
  48. package/lib/generates/SdkGenerator.js +3 -3
  49. package/lib/generates/SdkGenerator.js.map +1 -1
  50. package/lib/generates/SwaggerGenerator.js +135 -27
  51. package/lib/generates/SwaggerGenerator.js.map +1 -1
  52. package/lib/generates/internal/FilePrinter.d.ts +14 -0
  53. package/lib/generates/internal/FilePrinter.js +31 -0
  54. package/lib/generates/internal/FilePrinter.js.map +1 -1
  55. package/lib/generates/internal/ImportDictionary.d.ts +2 -0
  56. package/lib/generates/internal/ImportDictionary.js +13 -0
  57. package/lib/generates/internal/ImportDictionary.js.map +1 -1
  58. package/lib/generates/internal/SdkAliasCollection.d.ts +2 -1
  59. package/lib/generates/internal/SdkAliasCollection.js +8 -4
  60. package/lib/generates/internal/SdkAliasCollection.js.map +1 -1
  61. package/lib/generates/internal/SdkDistributionComposer.js +72 -14
  62. package/lib/generates/internal/SdkDistributionComposer.js.map +1 -1
  63. package/lib/generates/internal/SdkFileProgrammer.js +83 -12
  64. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  65. package/lib/generates/internal/SdkHttpFunctionProgrammer.js +21 -23
  66. package/lib/generates/internal/SdkHttpFunctionProgrammer.js.map +1 -1
  67. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js +27 -34
  68. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js.map +1 -1
  69. package/lib/generates/internal/SdkHttpParameterProgrammer.d.ts +40 -1
  70. package/lib/generates/internal/SdkHttpParameterProgrammer.js +105 -6
  71. package/lib/generates/internal/SdkHttpParameterProgrammer.js.map +1 -1
  72. package/lib/generates/internal/SdkHttpRouteProgrammer.js +16 -32
  73. package/lib/generates/internal/SdkHttpRouteProgrammer.js.map +1 -1
  74. package/lib/generates/internal/SdkHttpSimulationProgrammer.js +18 -14
  75. package/lib/generates/internal/SdkHttpSimulationProgrammer.js.map +1 -1
  76. package/lib/generates/internal/SdkMcpRouteProgrammer.js +39 -11
  77. package/lib/generates/internal/SdkMcpRouteProgrammer.js.map +1 -1
  78. package/lib/generates/internal/SdkPathTemplate.d.ts +21 -0
  79. package/lib/generates/internal/SdkPathTemplate.js +50 -0
  80. package/lib/generates/internal/SdkPathTemplate.js.map +1 -0
  81. package/lib/generates/internal/SdkTypeProgrammer.js +15 -15
  82. package/lib/generates/internal/SdkTypeProgrammer.js.map +1 -1
  83. package/lib/generates/internal/SdkTypeTagProgrammer.d.ts +20 -1
  84. package/lib/generates/internal/SdkTypeTagProgrammer.js +386 -67
  85. package/lib/generates/internal/SdkTypeTagProgrammer.js.map +1 -1
  86. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js +27 -36
  87. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js.map +1 -1
  88. package/lib/generates/internal/SdkWebSocketParameterProgrammer.d.ts +35 -1
  89. package/lib/generates/internal/SdkWebSocketParameterProgrammer.js +72 -5
  90. package/lib/generates/internal/SdkWebSocketParameterProgrammer.js.map +1 -1
  91. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js +57 -33
  92. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js.map +1 -1
  93. package/lib/generates/internal/SwaggerOperationComposer.js +19 -8
  94. package/lib/generates/internal/SwaggerOperationComposer.js.map +1 -1
  95. package/lib/generates/internal/SwaggerOperationParameterComposer.d.ts +1 -1
  96. package/lib/generates/internal/SwaggerOperationParameterComposer.js +201 -19
  97. package/lib/generates/internal/SwaggerOperationParameterComposer.js.map +1 -1
  98. package/lib/generates/internal/SwaggerOperationResponseComposer.d.ts +2 -0
  99. package/lib/generates/internal/SwaggerOperationResponseComposer.js +39 -7
  100. package/lib/generates/internal/SwaggerOperationResponseComposer.js.map +1 -1
  101. package/lib/internal/legacy.d.ts +49 -18
  102. package/lib/internal/legacy.js +84 -25
  103. package/lib/internal/legacy.js.map +1 -1
  104. package/lib/structures/IOperationMetadata.d.ts +22 -0
  105. package/lib/structures/IReflectHttpOperationException.d.ts +3 -2
  106. package/lib/structures/IReflectHttpOperationParameter.d.ts +8 -3
  107. package/lib/structures/IReflectHttpOperationSuccess.d.ts +4 -3
  108. package/lib/structures/ITypedHttpRoute.d.ts +8 -0
  109. package/lib/structures/ITypedHttpRouteException.d.ts +3 -1
  110. package/lib/structures/ITypedHttpRouteParameter.d.ts +3 -1
  111. package/lib/structures/ITypedHttpRouteSuccess.d.ts +3 -1
  112. package/lib/structures/ITypedWebSocketRoute.d.ts +8 -0
  113. package/lib/utils/SourceFinder.d.ts +10 -0
  114. package/lib/utils/SourceFinder.js +27 -4
  115. package/lib/utils/SourceFinder.js.map +1 -1
  116. package/lib/utils/VersioningStrategy.d.ts +13 -1
  117. package/lib/utils/VersioningStrategy.js +24 -12
  118. package/lib/utils/VersioningStrategy.js.map +1 -1
  119. package/native/go.mod +1 -1
  120. package/native/go.sum +2 -2
  121. package/native/sdk/sdk_http_rules.go +210 -0
  122. package/native/sdk/sdk_metadata_json.go +73 -3
  123. package/native/sdk/sdk_transform.go +801 -49
  124. package/package.json +8 -8
  125. package/src/INestiaConfig.ts +19 -10
  126. package/src/NestiaSdkApplication.ts +63 -34
  127. package/src/NestiaSwaggerComposer.ts +11 -8
  128. package/src/analyses/ConfigAnalyzer.ts +3 -3
  129. package/src/analyses/ParameterNameAnalyzer.ts +51 -0
  130. package/src/analyses/PathAnalyzer.ts +106 -14
  131. package/src/analyses/ReflectControllerAnalyzer.ts +2 -1
  132. package/src/analyses/ReflectHttpOperationAnalyzer.ts +4 -4
  133. package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +122 -39
  134. package/src/analyses/ReflectHttpOperationResponseAnalyzer.ts +6 -7
  135. package/src/analyses/ReflectMcpOperationAnalyzer.ts +6 -2
  136. package/src/analyses/ReflectWebSocketOperationAnalyzer.ts +7 -3
  137. package/src/analyses/SecurityAnalyzer.ts +30 -20
  138. package/src/analyses/SwaggerExampleAnalyzer.ts +23 -0
  139. package/src/analyses/TypedHttpRouteAnalyzer.ts +29 -20
  140. package/src/analyses/TypedWebSocketRouteAnalyzer.ts +1 -0
  141. package/src/executable/internal/NestiaSdkWatcher.ts +2 -2
  142. package/src/executable/sdk.ts +24 -1
  143. package/src/factories/ExpressionFactory.ts +8 -2
  144. package/src/factories/LiteralFactory.ts +7 -2
  145. package/src/generates/SdkGenerator.ts +3 -3
  146. package/src/generates/SwaggerGenerator.ts +173 -32
  147. package/src/generates/internal/FilePrinter.ts +28 -0
  148. package/src/generates/internal/ImportDictionary.ts +11 -0
  149. package/src/generates/internal/SdkAliasCollection.ts +11 -4
  150. package/src/generates/internal/SdkDistributionComposer.ts +89 -15
  151. package/src/generates/internal/SdkFileProgrammer.ts +108 -16
  152. package/src/generates/internal/SdkHttpFunctionProgrammer.ts +28 -30
  153. package/src/generates/internal/SdkHttpNamespaceProgrammer.ts +34 -64
  154. package/src/generates/internal/SdkHttpParameterProgrammer.ts +193 -13
  155. package/src/generates/internal/SdkHttpRouteProgrammer.ts +17 -31
  156. package/src/generates/internal/SdkHttpSimulationProgrammer.ts +51 -14
  157. package/src/generates/internal/SdkMcpRouteProgrammer.ts +112 -15
  158. package/src/generates/internal/SdkPathTemplate.ts +73 -0
  159. package/src/generates/internal/SdkTypeProgrammer.ts +19 -22
  160. package/src/generates/internal/SdkTypeTagProgrammer.ts +506 -78
  161. package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +43 -68
  162. package/src/generates/internal/SdkWebSocketParameterProgrammer.ts +126 -5
  163. package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +71 -48
  164. package/src/generates/internal/SwaggerOperationComposer.ts +20 -6
  165. package/src/generates/internal/SwaggerOperationParameterComposer.ts +279 -30
  166. package/src/generates/internal/SwaggerOperationResponseComposer.ts +55 -11
  167. package/src/internal/legacy.ts +114 -26
  168. package/src/structures/IOperationMetadata.ts +28 -0
  169. package/src/structures/IReflectHttpOperationException.ts +7 -2
  170. package/src/structures/IReflectHttpOperationParameter.ts +9 -2
  171. package/src/structures/IReflectHttpOperationSuccess.ts +8 -3
  172. package/src/structures/ITypedHttpRoute.ts +8 -0
  173. package/src/structures/ITypedHttpRouteException.ts +4 -1
  174. package/src/structures/ITypedHttpRouteParameter.ts +3 -1
  175. package/src/structures/ITypedHttpRouteSuccess.ts +4 -1
  176. package/src/structures/ITypedWebSocketRoute.ts +8 -0
  177. package/src/utils/SourceFinder.ts +25 -4
  178. package/src/utils/VersioningStrategy.ts +28 -13
  179. package/lib/validators/HttpHeadersValidator.d.ts +0 -11
  180. package/lib/validators/HttpHeadersValidator.js +0 -15
  181. package/lib/validators/HttpHeadersValidator.js.map +0 -1
  182. package/lib/validators/HttpQueryValidator.d.ts +0 -10
  183. package/lib/validators/HttpQueryValidator.js +0 -14
  184. package/lib/validators/HttpQueryValidator.js.map +0 -1
  185. package/src/validators/HttpHeadersValidator.ts +0 -12
  186. package/src/validators/HttpQueryValidator.ts +0 -11
@@ -4,8 +4,8 @@
4
4
  // its runtime classes.
5
5
  //
6
6
  // The utilities index components, resolve references, read metadata flags
7
- // and precomputed fields, validate SDK policy, and compose schemas for
8
- // decomposed parameters whose metadata has no precomputed JSON schema.
7
+ // and precomputed fields, validate SDK policy, and read the precomputed JSON
8
+ // schemas, including the per-property ones decomposed parameters use.
9
9
  import type {
10
10
  IJsonSchemaCollection,
11
11
  IMetadataComponents,
@@ -53,6 +53,19 @@ export interface IReflectJsonSchema {
53
53
  version: "3.0" | "3.1";
54
54
  components: OpenApi.IComponents;
55
55
  schema: OpenApi.IJsonSchema;
56
+
57
+ /**
58
+ * The schema of each property of the first object type, keyed by property
59
+ * name and resolved against {@link components}: the property schema typia's
60
+ * object schema holds, without the title, description, deprecation, and
61
+ * readOnly an OpenAPI parameter carries in its own fields or cannot use.
62
+ *
63
+ * Baked on the resolved schema of route parameters only, for the Swagger
64
+ * generator to decompose a query or headers object into one parameter per
65
+ * property. A property typia's object schema omits (`@hidden`, `@ignore`,
66
+ * `@internal`, or a value with no JSON form) has no entry.
67
+ */
68
+ properties?: Record<string, OpenApi.IJsonSchema>;
56
69
  }
57
70
 
58
71
  /**
@@ -133,6 +146,39 @@ export const emptyOf = (m: IMetadataSchema): boolean =>
133
146
  export const isRequiredOf = (m: IMetadataSchema): boolean =>
134
147
  m.required && !m.optional;
135
148
 
149
+ /**
150
+ * Reads a constant's value as the SDK's Go contributor writes it.
151
+ *
152
+ * JSON holds neither a bigint nor NaN or ±Infinity, so the metadata carries a
153
+ * bigint value as its decimal digits and a non-finite number by its name
154
+ * (`"Infinity"`), both as strings. `type` is the constant's type, which is its
155
+ * value's own, so a bigint or number constant's string is always one of those;
156
+ * every other value is returned as it is.
157
+ */
158
+ export const decodeMetadataValue = (type: string, value: unknown): unknown =>
159
+ typeof value !== "string"
160
+ ? value
161
+ : type === "bigint"
162
+ ? BigInt(value)
163
+ : type === "number"
164
+ ? Number(value)
165
+ : value;
166
+
167
+ /**
168
+ * Reads a type tag's value as the SDK's Go contributor writes it.
169
+ *
170
+ * A tag's `target` is the type it tags, not its value's: `tags.Sequence<1>` on
171
+ * a bigint holds a number, and `tags.Example<"Infinity">` on a number holds a
172
+ * string. So a value encoded as a string, a bigint's digits or a non-finite
173
+ * number's name, arrives with the type it stands for in `encoding`.
174
+ */
175
+ export const decodeTagValue = (
176
+ tag: IMetadataTypeTag & { encoding?: "bigint" | "number" },
177
+ ): unknown =>
178
+ tag.encoding !== undefined
179
+ ? decodeMetadataValue(tag.encoding, tag.value)
180
+ : tag.value;
181
+
136
182
  /**
137
183
  * Equivalent of the legacy `MetadataSchema.isSoleLiteral()` method: `true` when
138
184
  * the schema represents exactly one constant literal value and nothing else.
@@ -393,22 +439,6 @@ export namespace JsonMetadataFactory {
393
439
  };
394
440
  }
395
441
 
396
- export namespace HttpQueryProgrammer {
397
- export const validate: MetadataFactory.Validator = () => [];
398
- }
399
-
400
- export namespace HttpHeadersProgrammer {
401
- export const validate: MetadataFactory.Validator = () => [];
402
- }
403
-
404
- export namespace HttpParameterProgrammer {
405
- export const validate: MetadataFactory.Validator = () => [];
406
- }
407
-
408
- export namespace HttpFormDataProgrammer {
409
- export const validate: MetadataFactory.Validator = () => [];
410
- }
411
-
412
442
  // ---------------------------------------------------------------------
413
443
  // `JsonSchemasProgrammer.writeSchemas` — consumes the per-metadata
414
444
  // pre-baked `jsonSchema` field the nestia transform emits.
@@ -418,12 +448,16 @@ export namespace JsonSchemasProgrammer {
418
448
  /**
419
449
  * Consumes the per-metadata `jsonSchema` field the nestia transform
420
450
  * pre-bakes. Top-level route metadata (success / parameter / exception)
421
- * always carries a baked schema; for nested metadata (object property values
422
- * reached by the decomposed-query path), the bake is absent and this function
423
- * falls back to a minimal JS-side converter that handles the schema shapes
424
- * decompose actually emits — atomics, constants, templates, arrays of those,
425
- * named references — without re-implementing the typia native programmer
426
- * wholesale.
451
+ * carries a baked schema whenever typia can describe the type. Metadata
452
+ * without one falls back to a minimal JS-side converter that reads only the
453
+ * atomic kinds — no type tags, template patterns, or constant annotations —
454
+ * so it is no substitute for the bake.
455
+ *
456
+ * The schemas and components are copies. The bake belongs to the route
457
+ * metadata, which every composition in the process reads, while the composer
458
+ * edits what it is given in place (the readonly-array emender), and so can a
459
+ * `SwaggerCustomizer`; handing the bake out by reference let each document
460
+ * inherit the previous one's edits.
427
461
  */
428
462
  export const writeSchemas = (props: {
429
463
  version: "3.0" | "3.1";
@@ -434,7 +468,7 @@ export namespace JsonSchemasProgrammer {
434
468
  for (const m of props.metadatas) {
435
469
  const baked = (m as IReflectMetadata).jsonSchema;
436
470
  if (baked !== undefined) {
437
- schemas.push(baked.schema);
471
+ schemas.push(copy(baked.schema));
438
472
  Object.assign(
439
473
  (components.schemas ??= {}),
440
474
  baked.components.schemas ?? {},
@@ -443,14 +477,57 @@ export namespace JsonSchemasProgrammer {
443
477
  schemas.push(schemaFromMetadata(m));
444
478
  }
445
479
  }
480
+ // Copied once the last bake of each name has won, rather than per bake.
481
+ if (components.schemas !== undefined)
482
+ components.schemas = copy(components.schemas);
446
483
  return {
447
484
  version: props.version,
448
485
  components,
449
486
  schemas,
450
487
  } as IJsonSchemaCollection;
451
488
  };
489
+
490
+ /**
491
+ * Writes the schema of one property of `metadata`'s first object type, for a
492
+ * decomposed query or headers parameter.
493
+ *
494
+ * Reads the schema baked beside `metadata`'s own schema (see
495
+ * {@link IReflectJsonSchema.properties}), resolved against the same
496
+ * components. The schema and components are copies, for the reason
497
+ * {@link writeSchemas} gives. Returns `null` when that bake exists but has no
498
+ * entry for the property, because typia's object schema omits it, so no
499
+ * parameter describes it either. Only metadata the transform did not bake
500
+ * falls back to {@link writeSchemas} over the property value.
501
+ */
502
+ export const writeProperty = (props: {
503
+ version: "3.0" | "3.1";
504
+ metadata: IMetadataSchema;
505
+ key: string;
506
+ value: IMetadataSchema;
507
+ }): IJsonSchemaCollection | null => {
508
+ const properties: Record<string, OpenApi.IJsonSchema> | undefined = (
509
+ props.metadata as IReflectMetadata
510
+ ).jsonSchema?.properties;
511
+ if (properties === undefined)
512
+ return writeSchemas({
513
+ version: props.version,
514
+ metadatas: [props.value],
515
+ });
516
+ if (Object.prototype.hasOwnProperty.call(properties, props.key) === false)
517
+ return null;
518
+ return {
519
+ version: props.version,
520
+ components: copy(
521
+ (props.metadata as IReflectMetadata).jsonSchema!.components,
522
+ ),
523
+ schemas: [copy(properties[props.key]!)],
524
+ } as IJsonSchemaCollection;
525
+ };
452
526
  }
453
527
 
528
+ /** Deep copy of baked data, which is parsed JSON, so JSON copies it exactly. */
529
+ const copy = <T>(value: T): T => JSON.parse(JSON.stringify(value));
530
+
454
531
  const schemaFromMetadata = (m: IMetadataSchema): OpenApi.IJsonSchema => {
455
532
  const union: OpenApi.IJsonSchema[] = [];
456
533
  if (m.nullable) union.push({ type: "null" } as OpenApi.IJsonSchema);
@@ -459,7 +536,7 @@ const schemaFromMetadata = (m: IMetadataSchema): OpenApi.IJsonSchema => {
459
536
  for (const constant of m.constants)
460
537
  for (const value of constant.values)
461
538
  union.push({
462
- const: value.value,
539
+ const: jsonValue(decodeMetadataValue(constant.type, value.value)),
463
540
  } as unknown as OpenApi.IJsonSchema);
464
541
  for (const tpl of m.templates) {
465
542
  union.push({ type: "string" } as OpenApi.IJsonSchema);
@@ -491,6 +568,17 @@ const schemaFromMetadata = (m: IMetadataSchema): OpenApi.IJsonSchema => {
491
568
  return { oneOf: union } as unknown as OpenApi.IJsonSchema;
492
569
  };
493
570
 
571
+ /**
572
+ * A value as a JSON document holds it: the number a bigint is, and null for a
573
+ * non-finite number, as `JSON.stringify` writes it.
574
+ */
575
+ const jsonValue = (value: unknown): unknown =>
576
+ typeof value === "bigint"
577
+ ? Number(value)
578
+ : typeof value === "number" && Number.isFinite(value) === false
579
+ ? null
580
+ : value;
581
+
494
582
  const schemaFromAtomic = (atomic: IMetadataSchema.IAtomic): unknown => {
495
583
  if (atomic.type === "boolean") return { type: "boolean" };
496
584
  if (atomic.type === "bigint" || atomic.type === "number")
@@ -32,6 +32,34 @@ export namespace IOperationMetadata {
32
32
  export interface ISchema {
33
33
  components: IMetadataComponents;
34
34
  metadata: IMetadataSchema;
35
+
36
+ /**
37
+ * Violations of each HTTP input's wire rules, baked on the resolved schema
38
+ * of a route parameter only; the SDK picks the one its decorator selects.
39
+ */
40
+ http?: IHttpRules;
41
+ }
42
+
43
+ /**
44
+ * The violations of each HTTP input category's rules, which are typia's own
45
+ * validators except the path parameter rule typia keeps unexported and the
46
+ * one of a field-named `@Query("key")` or `@Headers("key")`.
47
+ */
48
+ export interface IHttpRules {
49
+ /** A query object: `@TypedQuery()`, `@Query()`, `@TypedQuery.Body()`. */
50
+ query: IError[];
51
+
52
+ /** A headers object: `@TypedHeaders()`, `@Headers()`. */
53
+ headers: IError[];
54
+
55
+ /** A path parameter: `@TypedParam("key")`, `@Param("key")`. */
56
+ param: IError[];
57
+
58
+ /** One query key or header: `@Query("key")`, `@Headers("key")`. */
59
+ field: IError[];
60
+
61
+ /** A multipart body: `@TypedFormData.Body()`. */
62
+ formData: IError[];
35
63
  }
36
64
  export interface IError {
37
65
  name: string;
@@ -1,4 +1,8 @@
1
- import { IMetadataComponents, IMetadataSchema } from "@typia/interface";
1
+ import {
2
+ IMetadataComponents,
3
+ IMetadataSchema,
4
+ OpenApi,
5
+ } from "@typia/interface";
2
6
 
3
7
  import { MetadataFactory } from "../internal/legacy";
4
8
  import { IReflectType } from "./IReflectType";
@@ -8,7 +12,8 @@ export interface IReflectHttpOperationException {
8
12
  status: number | "2XX" | "3XX" | "4XX" | "5XX";
9
13
  description: string | null;
10
14
  example?: any;
11
- examples?: Record<string, any>;
15
+ /** Named examples, as OpenAPI Example Objects. */
16
+ examples?: Record<string, OpenApi.IExample>;
12
17
 
13
18
  // REFLECTED PROPERTIES
14
19
  type: IReflectType;
@@ -2,6 +2,7 @@ import {
2
2
  IJsDocTagInfo,
3
3
  IMetadataComponents,
4
4
  IMetadataSchema,
5
+ OpenApi,
5
6
  } from "@typia/interface";
6
7
 
7
8
  import { MetadataFactory } from "../internal/legacy";
@@ -37,9 +38,15 @@ export namespace IReflectHttpOperationParameter {
37
38
  type: IReflectType;
38
39
  metadata: IMetadataSchema;
39
40
  components: IMetadataComponents;
40
- validate: MetadataFactory.Validator;
41
+
42
+ /**
43
+ * SDK policy checked over the metadata, for a JSON or text body. An HTTP
44
+ * input's wire rules are typia's instead, baked beside its metadata.
45
+ */
46
+ validate?: MetadataFactory.Validator;
41
47
  example?: any;
42
- examples?: Record<string, any>;
48
+ /** Named examples, as OpenAPI Example Objects. */
49
+ examples?: Record<string, OpenApi.IExample>;
43
50
  description: string | null;
44
51
  jsDocTags: IJsDocTagInfo[];
45
52
  }
@@ -1,4 +1,8 @@
1
- import { IMetadataComponents, IMetadataSchema } from "@typia/interface";
1
+ import {
2
+ IMetadataComponents,
3
+ IMetadataSchema,
4
+ OpenApi,
5
+ } from "@typia/interface";
2
6
 
3
7
  import { MetadataFactory } from "../internal/legacy";
4
8
  import { HttpResponseContentTypeUtil } from "../utils/HttpResponseContentTypeUtil";
@@ -12,7 +16,8 @@ export interface IReflectHttpOperationSuccess {
12
16
  encrypted: boolean;
13
17
  components: IMetadataComponents;
14
18
  metadata: IMetadataSchema;
15
- validate: MetadataFactory.Validator;
19
+ validate?: MetadataFactory.Validator;
16
20
  example?: any;
17
- examples?: Record<string, any>;
21
+ /** Named examples, as OpenAPI Example Objects. */
22
+ examples?: Record<string, OpenApi.IExample>;
18
23
  }
@@ -10,6 +10,14 @@ export interface ITypedHttpRoute {
10
10
  protocol: "http";
11
11
  function: Function;
12
12
  controller: IReflectController;
13
+ /**
14
+ * Property key of the controller method.
15
+ *
16
+ * {@link name} is the SDK function's name, which the accessor analysis
17
+ * renames: a reserved word such as `delete` becomes `_delete`. Metadata the
18
+ * method's decorators define, and what names the method, read this key.
19
+ */
20
+ key: string;
13
21
  name: string;
14
22
  method: string;
15
23
  path: string;
@@ -1,3 +1,5 @@
1
+ import { OpenApi } from "@typia/interface";
2
+
1
3
  import { MetadataSchema } from "../internal/legacy";
2
4
  import { IReflectType } from "./IReflectType";
3
5
 
@@ -6,7 +8,8 @@ export interface ITypedHttpRouteException {
6
8
  status: number | "2XX" | "3XX" | "4XX" | "5XX";
7
9
  description: string | null;
8
10
  example: any;
9
- examples: Record<string, any>;
11
+ /** Named examples, as OpenAPI Example Objects. */
12
+ examples: Record<string, OpenApi.IExample>;
10
13
 
11
14
  // REFLECTED PROPERTIES
12
15
  type: IReflectType;
@@ -1,3 +1,4 @@
1
+ import { OpenApi } from "@typia/interface";
1
2
  import { IJsDocTagInfo } from "typia";
2
3
 
3
4
  import { MetadataSchema } from "../internal/legacy";
@@ -34,7 +35,8 @@ export namespace ITypedHttpRouteParameter {
34
35
  type: IReflectType;
35
36
  metadata: MetadataSchema;
36
37
  example?: any;
37
- examples?: Record<string, any>;
38
+ /** Named examples, as OpenAPI Example Objects. */
39
+ examples?: Record<string, OpenApi.IExample>;
38
40
  description: string | null;
39
41
  jsDocTags: IJsDocTagInfo[];
40
42
  }
@@ -1,3 +1,5 @@
1
+ import { OpenApi } from "@typia/interface";
2
+
1
3
  import { MetadataSchema } from "../internal/legacy";
2
4
  import { HttpResponseContentTypeUtil } from "../utils/HttpResponseContentTypeUtil";
3
5
  import { IReflectType } from "./IReflectType";
@@ -10,7 +12,8 @@ export interface ITypedHttpRouteSuccess {
10
12
  encrypted: boolean;
11
13
  metadata: MetadataSchema;
12
14
  example?: any;
13
- examples?: Record<string, any>;
15
+ /** Named examples, as OpenAPI Example Objects. */
16
+ examples?: Record<string, OpenApi.IExample>;
14
17
  setHeaders: Array<
15
18
  | { type: "setter"; source: string; target?: string }
16
19
  | { type: "assigner"; source: string }
@@ -8,6 +8,14 @@ import { ITypedWebSocketRouteParameter } from "./ITypedWebSocketRouteParameter";
8
8
  export interface ITypedWebSocketRoute {
9
9
  protocol: "websocket";
10
10
  controller: IReflectController;
11
+ /**
12
+ * Property key of the controller method.
13
+ *
14
+ * {@link name} is the SDK function's name, which the accessor analysis
15
+ * renames: a reserved word such as `delete` becomes `_delete`. Metadata the
16
+ * method's decorators define, and what names the method, read this key.
17
+ */
18
+ key: string;
11
19
  name: string;
12
20
  path: string;
13
21
  accessor: string[];
@@ -28,7 +28,7 @@ export namespace SourceFinder {
28
28
  closure(path.resolve(pattern));
29
29
  continue;
30
30
  }
31
- for (const file of await _Glob(pattern)) {
31
+ for (const file of await expand(pattern)) {
32
32
  const stats: fs.Stats = await fs.promises.stat(file);
33
33
  if (stats.isDirectory() === true)
34
34
  await iterate(filter)(closure)(file);
@@ -51,9 +51,30 @@ export namespace SourceFinder {
51
51
  }
52
52
  };
53
53
 
54
- const _Glob = async (pattern: string): Promise<string[]> => {
55
- const matches = await glob(pattern);
56
- return matches.map((str) => path.resolve(str));
54
+ /**
55
+ * Files and directories a path or glob pattern names.
56
+ *
57
+ * An existing path is taken literally, whatever characters it holds, as a
58
+ * directory such as `app [v2]` would otherwise read as a character class. For
59
+ * a pattern, the longest existing ancestor is the literal base and only the
60
+ * rest is globbed, with `/` separators, since glob reads a Windows backslash
61
+ * as an escape.
62
+ */
63
+ export const expand = async (pattern: string): Promise<string[]> => {
64
+ const absolute: string = path.resolve(pattern);
65
+ if (fs.existsSync(absolute)) return [absolute];
66
+ let base: string = absolute;
67
+ while (fs.existsSync(base) === false) {
68
+ const parent: string = path.dirname(base);
69
+ if (parent === base) return [];
70
+ base = parent;
71
+ }
72
+ const rest: string = path
73
+ .relative(base, absolute)
74
+ .split(path.sep)
75
+ .join("/");
76
+ const matches: string[] = await glob(rest, { cwd: base });
77
+ return matches.map((str) => path.resolve(base, str));
57
78
  };
58
79
 
59
80
  const _Is_file = (pattern: string): boolean =>
@@ -8,21 +8,36 @@ export namespace VersioningStrategy {
8
8
  ): Array<string | typeof VERSION_NEUTRAL> =>
9
9
  value === undefined ? [] : Array.isArray(value) ? value : [value];
10
10
 
11
+ /**
12
+ * Version path segments of a route, resolved as NestJS resolves them: the
13
+ * method's versions, else the controller's, else the default version, and no
14
+ * version at all is the unversioned path.
15
+ *
16
+ * The controller's and the method's versions were joined, so a method
17
+ * overriding its controller's version was also described at the controller's,
18
+ * and a route with no version and no default got no path at all (#1735).
19
+ */
11
20
  export const merge =
12
21
  (project: Omit<INestiaProject, "config">) =>
13
- (values: Array<string | typeof VERSION_NEUTRAL>): string[] => {
14
- if (project.input.versioning === undefined) return [""];
15
- const set: Set<string | typeof VERSION_NEUTRAL> = new Set(values);
16
- const array: Array<string | typeof VERSION_NEUTRAL> =
17
- set.size === 0
18
- ? cast(project.input.versioning?.defaultVersion)
19
- : Array.from(set);
20
- return !!array?.length
21
- ? array.map((x) =>
22
- typeof x === "symbol"
23
- ? ""
24
- : `${project.input.versioning!.prefix}${x}`,
22
+ (props: {
23
+ controller: Array<string | typeof VERSION_NEUTRAL> | undefined;
24
+ method: Array<string | typeof VERSION_NEUTRAL> | undefined;
25
+ }): string[] => {
26
+ const versioning = project.input.versioning;
27
+ if (versioning === undefined) return [""];
28
+ const chosen: Array<string | typeof VERSION_NEUTRAL> = props.method
29
+ ?.length
30
+ ? props.method
31
+ : props.controller?.length
32
+ ? props.controller
33
+ : cast(versioning.defaultVersion);
34
+ const unique: Array<string | typeof VERSION_NEUTRAL> = [
35
+ ...new Set(chosen),
36
+ ];
37
+ return unique.length
38
+ ? unique.map((x) =>
39
+ typeof x === "symbol" ? "" : `${versioning.prefix}${x}`,
25
40
  )
26
- : [];
41
+ : [""];
27
42
  };
28
43
  }
@@ -1,11 +0,0 @@
1
- import { MetadataFactory } from "../internal/legacy";
2
- /**
3
- * Validator slot reserved for `@TypedHeaders` per-field SDK-side checks.
4
- * Returns `[]` because the typia native transform already enforces the
5
- * "atomic-or-array-of-atomic" constraint at compile time, and
6
- * `MetadataFactory.validate` — the only call site — is itself a passthrough on
7
- * the v13 runtime.
8
- */
9
- export declare namespace HttpHeadersValidator {
10
- const validate: MetadataFactory.Validator;
11
- }
@@ -1,15 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpHeadersValidator = void 0;
4
- /**
5
- * Validator slot reserved for `@TypedHeaders` per-field SDK-side checks.
6
- * Returns `[]` because the typia native transform already enforces the
7
- * "atomic-or-array-of-atomic" constraint at compile time, and
8
- * `MetadataFactory.validate` — the only call site — is itself a passthrough on
9
- * the v13 runtime.
10
- */
11
- var HttpHeadersValidator;
12
- (function (HttpHeadersValidator) {
13
- HttpHeadersValidator.validate = () => [];
14
- })(HttpHeadersValidator || (exports.HttpHeadersValidator = HttpHeadersValidator = {}));
15
- //# sourceMappingURL=HttpHeadersValidator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"HttpHeadersValidator.js","sourceRoot":"","sources":["../../src/validators/HttpHeadersValidator.ts"],"names":[],"mappings":";;;AAEA;;;;;;GAMG;AACH,IAAiB,oBAAoB,CAEpC;AAFD,WAAiB,oBAAoB;IACtB,6BAAQ,GAA8B,GAAG,EAAE,CAAC,EAAE,CAAC;AAC9D,CAAC,EAFgB,oBAAoB,aAApB,oBAAoB,GAApB,oBAAoB,QAEpC"}
@@ -1,10 +0,0 @@
1
- import { MetadataFactory } from "../internal/legacy";
2
- /**
3
- * Validator slot reserved for `@TypedQuery` per-field SDK-side checks. Returns
4
- * `[]` because the typia native transform already enforces the atomic-only
5
- * constraint at compile time, and `MetadataFactory.validate` — the only call
6
- * site — is itself a passthrough on the v13 runtime.
7
- */
8
- export declare namespace HttpQueryValidator {
9
- const validate: MetadataFactory.Validator;
10
- }
@@ -1,14 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpQueryValidator = void 0;
4
- /**
5
- * Validator slot reserved for `@TypedQuery` per-field SDK-side checks. Returns
6
- * `[]` because the typia native transform already enforces the atomic-only
7
- * constraint at compile time, and `MetadataFactory.validate` — the only call
8
- * site — is itself a passthrough on the v13 runtime.
9
- */
10
- var HttpQueryValidator;
11
- (function (HttpQueryValidator) {
12
- HttpQueryValidator.validate = () => [];
13
- })(HttpQueryValidator || (exports.HttpQueryValidator = HttpQueryValidator = {}));
14
- //# sourceMappingURL=HttpQueryValidator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"HttpQueryValidator.js","sourceRoot":"","sources":["../../src/validators/HttpQueryValidator.ts"],"names":[],"mappings":";;;AAEA;;;;;GAKG;AACH,IAAiB,kBAAkB,CAElC;AAFD,WAAiB,kBAAkB;IACpB,2BAAQ,GAA8B,GAAG,EAAE,CAAC,EAAE,CAAC;AAC9D,CAAC,EAFgB,kBAAkB,aAAlB,kBAAkB,GAAlB,kBAAkB,QAElC"}
@@ -1,12 +0,0 @@
1
- import { MetadataFactory } from "../internal/legacy";
2
-
3
- /**
4
- * Validator slot reserved for `@TypedHeaders` per-field SDK-side checks.
5
- * Returns `[]` because the typia native transform already enforces the
6
- * "atomic-or-array-of-atomic" constraint at compile time, and
7
- * `MetadataFactory.validate` — the only call site — is itself a passthrough on
8
- * the v13 runtime.
9
- */
10
- export namespace HttpHeadersValidator {
11
- export const validate: MetadataFactory.Validator = () => [];
12
- }
@@ -1,11 +0,0 @@
1
- import { MetadataFactory } from "../internal/legacy";
2
-
3
- /**
4
- * Validator slot reserved for `@TypedQuery` per-field SDK-side checks. Returns
5
- * `[]` because the typia native transform already enforces the atomic-only
6
- * constraint at compile time, and `MetadataFactory.validate` — the only call
7
- * site — is itself a passthrough on the v13 runtime.
8
- */
9
- export namespace HttpQueryValidator {
10
- export const validate: MetadataFactory.Validator = () => [];
11
- }