@nestia/sdk 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 (391) hide show
  1. package/README.md +1 -1
  2. package/assets/bundle/distribute/build-sdk.cjs +28 -0
  3. package/assets/bundle/distribute/package.json +7 -3
  4. package/assets/bundle/distribute/tsconfig.json +15 -105
  5. package/lib/INestiaConfig.d.ts +74 -34
  6. package/lib/NestiaSdkApplication.d.ts +60 -0
  7. package/lib/NestiaSdkApplication.js +121 -32
  8. package/lib/NestiaSdkApplication.js.map +1 -1
  9. package/lib/NestiaSwaggerComposer.d.ts +21 -0
  10. package/lib/NestiaSwaggerComposer.js +32 -13
  11. package/lib/NestiaSwaggerComposer.js.map +1 -1
  12. package/lib/analyses/AccessorAnalyzer.d.ts +26 -0
  13. package/lib/analyses/AccessorAnalyzer.js +26 -0
  14. package/lib/analyses/AccessorAnalyzer.js.map +1 -1
  15. package/lib/analyses/ConfigAnalyzer.d.ts +41 -0
  16. package/lib/analyses/ConfigAnalyzer.js +52 -77
  17. package/lib/analyses/ConfigAnalyzer.js.map +1 -1
  18. package/lib/analyses/ImportAnalyzer.d.ts +25 -0
  19. package/lib/analyses/ImportAnalyzer.js +25 -0
  20. package/lib/analyses/ImportAnalyzer.js.map +1 -1
  21. package/lib/analyses/ParameterNameAnalyzer.d.ts +44 -0
  22. package/lib/analyses/ParameterNameAnalyzer.js +63 -0
  23. package/lib/analyses/ParameterNameAnalyzer.js.map +1 -0
  24. package/lib/analyses/PathAnalyzer.d.ts +93 -1
  25. package/lib/analyses/PathAnalyzer.js +160 -23
  26. package/lib/analyses/PathAnalyzer.js.map +1 -1
  27. package/lib/analyses/ReflectControllerAnalyzer.d.ts +32 -0
  28. package/lib/analyses/ReflectControllerAnalyzer.js +24 -1
  29. package/lib/analyses/ReflectControllerAnalyzer.js.map +1 -1
  30. package/lib/analyses/ReflectHttpOperationAnalyzer.d.ts +29 -0
  31. package/lib/analyses/ReflectHttpOperationAnalyzer.js +35 -24
  32. package/lib/analyses/ReflectHttpOperationAnalyzer.js.map +1 -1
  33. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.d.ts +31 -0
  34. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.js +21 -0
  35. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.js.map +1 -1
  36. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.d.ts +31 -0
  37. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js +143 -23
  38. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js.map +1 -1
  39. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.d.ts +32 -0
  40. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js +27 -2
  41. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js.map +1 -1
  42. package/lib/analyses/ReflectMcpOperationAnalyzer.d.ts +29 -0
  43. package/lib/analyses/ReflectMcpOperationAnalyzer.js +35 -11
  44. package/lib/analyses/ReflectMcpOperationAnalyzer.js.map +1 -1
  45. package/lib/analyses/ReflectMetadataAnalyzer.d.ts +47 -0
  46. package/lib/analyses/ReflectMetadataAnalyzer.js +47 -0
  47. package/lib/analyses/ReflectMetadataAnalyzer.js.map +1 -1
  48. package/lib/analyses/ReflectWebSocketOperationAnalyzer.d.ts +29 -0
  49. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js +27 -5
  50. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js.map +1 -1
  51. package/lib/analyses/SecurityAnalyzer.d.ts +25 -0
  52. package/lib/analyses/SecurityAnalyzer.js +39 -19
  53. package/lib/analyses/SecurityAnalyzer.js.map +1 -1
  54. package/lib/analyses/SwaggerExampleAnalyzer.d.ts +31 -0
  55. package/lib/analyses/SwaggerExampleAnalyzer.js +36 -0
  56. package/lib/analyses/SwaggerExampleAnalyzer.js.map +1 -0
  57. package/lib/analyses/TypedHttpRouteAnalyzer.d.ts +41 -3
  58. package/lib/analyses/TypedHttpRouteAnalyzer.js +196 -172
  59. package/lib/analyses/TypedHttpRouteAnalyzer.js.map +1 -1
  60. package/lib/analyses/TypedMcpRouteAnalyzer.d.ts +29 -0
  61. package/lib/analyses/TypedMcpRouteAnalyzer.js +152 -20
  62. package/lib/analyses/TypedMcpRouteAnalyzer.js.map +1 -1
  63. package/lib/analyses/TypedWebSocketRouteAnalyzer.d.ts +19 -0
  64. package/lib/analyses/TypedWebSocketRouteAnalyzer.js +20 -1
  65. package/lib/analyses/TypedWebSocketRouteAnalyzer.js.map +1 -1
  66. package/lib/decorators/OperationMetadata.d.ts +6 -0
  67. package/lib/decorators/OperationMetadata.js +6 -0
  68. package/lib/decorators/OperationMetadata.js.map +1 -1
  69. package/lib/executable/internal/CommandParser.d.ts +19 -0
  70. package/lib/executable/internal/CommandParser.js +19 -0
  71. package/lib/executable/internal/CommandParser.js.map +1 -1
  72. package/lib/executable/internal/NestiaConfigLoader.d.ts +56 -0
  73. package/lib/executable/internal/NestiaConfigLoader.js +48 -42
  74. package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
  75. package/lib/executable/internal/NestiaSdkCommand.d.ts +60 -0
  76. package/lib/executable/internal/NestiaSdkCommand.js +95 -3
  77. package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
  78. package/lib/executable/internal/NestiaSdkWatcher.d.ts +81 -0
  79. package/lib/executable/internal/NestiaSdkWatcher.js +125 -41
  80. package/lib/executable/internal/NestiaSdkWatcher.js.map +1 -1
  81. package/lib/executable/internal/NestiaSwaggerWatch.d.ts +80 -0
  82. package/lib/executable/internal/NestiaSwaggerWatch.js +308 -0
  83. package/lib/executable/internal/NestiaSwaggerWatch.js.map +1 -0
  84. package/lib/executable/sdk.js +16 -1
  85. package/lib/executable/sdk.js.map +1 -1
  86. package/lib/factories/ExpressionFactory.d.ts +18 -0
  87. package/lib/factories/ExpressionFactory.js +21 -2
  88. package/lib/factories/ExpressionFactory.js.map +1 -1
  89. package/lib/factories/IdentifierFactory.d.ts +24 -0
  90. package/lib/factories/IdentifierFactory.js +24 -0
  91. package/lib/factories/IdentifierFactory.js.map +1 -1
  92. package/lib/factories/LiteralFactory.d.ts +22 -4
  93. package/lib/factories/LiteralFactory.js +33 -11
  94. package/lib/factories/LiteralFactory.js.map +1 -1
  95. package/lib/factories/StatementFactory.d.ts +28 -1
  96. package/lib/factories/StatementFactory.js +28 -1
  97. package/lib/factories/StatementFactory.js.map +1 -1
  98. package/lib/factories/TypeFactory.d.ts +24 -0
  99. package/lib/factories/TypeFactory.js +15 -0
  100. package/lib/factories/TypeFactory.js.map +1 -1
  101. package/lib/generates/CloneGenerator.d.ts +22 -0
  102. package/lib/generates/CloneGenerator.js +26 -5
  103. package/lib/generates/CloneGenerator.js.map +1 -1
  104. package/lib/generates/E2eGenerator.d.ts +19 -0
  105. package/lib/generates/E2eGenerator.js +19 -0
  106. package/lib/generates/E2eGenerator.js.map +1 -1
  107. package/lib/generates/SdkGenerator.d.ts +38 -0
  108. package/lib/generates/SdkGenerator.js +43 -5
  109. package/lib/generates/SdkGenerator.js.map +1 -1
  110. package/lib/generates/SwaggerGenerator.d.ts +36 -6
  111. package/lib/generates/SwaggerGenerator.js +190 -40
  112. package/lib/generates/SwaggerGenerator.js.map +1 -1
  113. package/lib/generates/internal/E2eFileProgrammer.d.ts +19 -0
  114. package/lib/generates/internal/E2eFileProgrammer.js +20 -1
  115. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  116. package/lib/generates/internal/FilePrinter.d.ts +57 -0
  117. package/lib/generates/internal/FilePrinter.js +74 -0
  118. package/lib/generates/internal/FilePrinter.js.map +1 -1
  119. package/lib/generates/internal/ImportDictionary.d.ts +93 -1
  120. package/lib/generates/internal/ImportDictionary.js +103 -2
  121. package/lib/generates/internal/ImportDictionary.js.map +1 -1
  122. package/lib/generates/internal/SdkAliasCollection.d.ts +121 -1
  123. package/lib/generates/internal/SdkAliasCollection.js +132 -11
  124. package/lib/generates/internal/SdkAliasCollection.js.map +1 -1
  125. package/lib/generates/internal/SdkDistributionComposer.d.ts +19 -0
  126. package/lib/generates/internal/SdkDistributionComposer.js +149 -52
  127. package/lib/generates/internal/SdkDistributionComposer.js.map +1 -1
  128. package/lib/generates/internal/SdkFileProgrammer.d.ts +18 -0
  129. package/lib/generates/internal/SdkFileProgrammer.js +101 -12
  130. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  131. package/lib/generates/internal/SdkHttpCloneProgrammer.d.ts +29 -0
  132. package/lib/generates/internal/SdkHttpCloneProgrammer.js +33 -0
  133. package/lib/generates/internal/SdkHttpCloneProgrammer.js.map +1 -1
  134. package/lib/generates/internal/SdkHttpCloneReferencer.d.ts +19 -0
  135. package/lib/generates/internal/SdkHttpCloneReferencer.js +78 -25
  136. package/lib/generates/internal/SdkHttpCloneReferencer.js.map +1 -1
  137. package/lib/generates/internal/SdkHttpFunctionProgrammer.d.ts +19 -0
  138. package/lib/generates/internal/SdkHttpFunctionProgrammer.js +40 -23
  139. package/lib/generates/internal/SdkHttpFunctionProgrammer.js.map +1 -1
  140. package/lib/generates/internal/SdkHttpNamespaceProgrammer.d.ts +19 -0
  141. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js +46 -34
  142. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js.map +1 -1
  143. package/lib/generates/internal/SdkHttpParameterProgrammer.d.ts +142 -1
  144. package/lib/generates/internal/SdkHttpParameterProgrammer.js +175 -6
  145. package/lib/generates/internal/SdkHttpParameterProgrammer.js.map +1 -1
  146. package/lib/generates/internal/SdkHttpRouteProgrammer.d.ts +20 -0
  147. package/lib/generates/internal/SdkHttpRouteProgrammer.js +36 -32
  148. package/lib/generates/internal/SdkHttpRouteProgrammer.js.map +1 -1
  149. package/lib/generates/internal/SdkHttpSimulationProgrammer.d.ts +38 -0
  150. package/lib/generates/internal/SdkHttpSimulationProgrammer.js +66 -18
  151. package/lib/generates/internal/SdkHttpSimulationProgrammer.js.map +1 -1
  152. package/lib/generates/internal/SdkImportWizard.d.ts +63 -0
  153. package/lib/generates/internal/SdkImportWizard.js +63 -0
  154. package/lib/generates/internal/SdkImportWizard.js.map +1 -1
  155. package/lib/generates/internal/SdkMcpRouteProgrammer.d.ts +17 -2
  156. package/lib/generates/internal/SdkMcpRouteProgrammer.js +72 -24
  157. package/lib/generates/internal/SdkMcpRouteProgrammer.js.map +1 -1
  158. package/lib/generates/internal/SdkPathTemplate.d.ts +36 -0
  159. package/lib/generates/internal/SdkPathTemplate.js +65 -0
  160. package/lib/generates/internal/SdkPathTemplate.js.map +1 -0
  161. package/lib/generates/internal/SdkRouteDirectory.d.ts +10 -0
  162. package/lib/generates/internal/SdkRouteDirectory.js +10 -0
  163. package/lib/generates/internal/SdkRouteDirectory.js.map +1 -1
  164. package/lib/generates/internal/SdkTypeProgrammer.d.ts +54 -1
  165. package/lib/generates/internal/SdkTypeProgrammer.js +111 -27
  166. package/lib/generates/internal/SdkTypeProgrammer.js.map +1 -1
  167. package/lib/generates/internal/SdkTypeTagProgrammer.d.ts +53 -1
  168. package/lib/generates/internal/SdkTypeTagProgrammer.js +407 -67
  169. package/lib/generates/internal/SdkTypeTagProgrammer.js.map +1 -1
  170. package/lib/generates/internal/SdkWebSocketCloneProgrammer.d.ts +40 -0
  171. package/lib/generates/internal/SdkWebSocketCloneProgrammer.js +149 -142
  172. package/lib/generates/internal/SdkWebSocketCloneProgrammer.js.map +1 -1
  173. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.d.ts +19 -0
  174. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js +46 -36
  175. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js.map +1 -1
  176. package/lib/generates/internal/SdkWebSocketParameterProgrammer.d.ts +114 -1
  177. package/lib/generates/internal/SdkWebSocketParameterProgrammer.js +120 -5
  178. package/lib/generates/internal/SdkWebSocketParameterProgrammer.js.map +1 -1
  179. package/lib/generates/internal/SdkWebSocketRouteProgrammer.d.ts +18 -0
  180. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js +75 -33
  181. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js.map +1 -1
  182. package/lib/generates/internal/SwaggerDescriptionComposer.d.ts +42 -0
  183. package/lib/generates/internal/SwaggerDescriptionComposer.js +44 -1
  184. package/lib/generates/internal/SwaggerDescriptionComposer.js.map +1 -1
  185. package/lib/generates/internal/SwaggerOperationComposer.d.ts +18 -0
  186. package/lib/generates/internal/SwaggerOperationComposer.js +37 -8
  187. package/lib/generates/internal/SwaggerOperationComposer.js.map +1 -1
  188. package/lib/generates/internal/SwaggerOperationParameterComposer.d.ts +40 -1
  189. package/lib/generates/internal/SwaggerOperationParameterComposer.js +230 -25
  190. package/lib/generates/internal/SwaggerOperationParameterComposer.js.map +1 -1
  191. package/lib/generates/internal/SwaggerOperationResponseComposer.d.ts +21 -0
  192. package/lib/generates/internal/SwaggerOperationResponseComposer.js +58 -7
  193. package/lib/generates/internal/SwaggerOperationResponseComposer.js.map +1 -1
  194. package/lib/internal/legacy.d.ts +342 -31
  195. package/lib/internal/legacy.js +207 -31
  196. package/lib/internal/legacy.js.map +1 -1
  197. package/lib/structures/INestiaProject.d.ts +10 -0
  198. package/lib/structures/INestiaSdkInput.d.ts +30 -0
  199. package/lib/structures/IOperationMetadata.d.ts +77 -0
  200. package/lib/structures/IReflectController.d.ts +10 -0
  201. package/lib/structures/IReflectHttpOperation.d.ts +10 -0
  202. package/lib/structures/IReflectHttpOperationException.d.ts +13 -2
  203. package/lib/structures/IReflectHttpOperationParameter.d.ts +55 -3
  204. package/lib/structures/IReflectHttpOperationSuccess.d.ts +15 -3
  205. package/lib/structures/IReflectImport.d.ts +10 -0
  206. package/lib/structures/IReflectMcpOperation.d.ts +19 -0
  207. package/lib/structures/IReflectMcpOperationParameter.d.ts +9 -0
  208. package/lib/structures/IReflectOperationError.d.ts +28 -0
  209. package/lib/structures/IReflectOperationError.js +22 -2
  210. package/lib/structures/IReflectOperationError.js.map +1 -1
  211. package/lib/structures/IReflectType.d.ts +9 -0
  212. package/lib/structures/IReflectWebSocketOperation.d.ts +10 -0
  213. package/lib/structures/IReflectWebSocketOperationParameter.d.ts +55 -0
  214. package/lib/structures/ITypedApplication.d.ts +10 -0
  215. package/lib/structures/ITypedHttpRoute.d.ts +18 -0
  216. package/lib/structures/ITypedHttpRouteException.d.ts +13 -1
  217. package/lib/structures/ITypedHttpRouteParameter.d.ts +48 -1
  218. package/lib/structures/ITypedHttpRouteSuccess.d.ts +13 -1
  219. package/lib/structures/ITypedMcpRoute.d.ts +11 -0
  220. package/lib/structures/ITypedWebSocketRoute.d.ts +18 -0
  221. package/lib/transform.d.ts +6 -0
  222. package/lib/transform.js +6 -0
  223. package/lib/transform.js.map +1 -1
  224. package/lib/utils/ArrayUtil.d.ts +31 -1
  225. package/lib/utils/ArrayUtil.js +32 -11
  226. package/lib/utils/ArrayUtil.js.map +1 -1
  227. package/lib/utils/EmittedJavaScriptPatcher.d.ts +20 -0
  228. package/lib/utils/EmittedJavaScriptPatcher.js +65 -46
  229. package/lib/utils/EmittedJavaScriptPatcher.js.map +1 -1
  230. package/lib/utils/FileRetriever.d.ts +29 -0
  231. package/lib/utils/FileRetriever.js +29 -0
  232. package/lib/utils/FileRetriever.js.map +1 -1
  233. package/lib/utils/HttpResponseContentTypeUtil.d.ts +41 -0
  234. package/lib/utils/HttpResponseContentTypeUtil.js +31 -0
  235. package/lib/utils/HttpResponseContentTypeUtil.js.map +1 -1
  236. package/lib/utils/MapUtil.d.ts +64 -1
  237. package/lib/utils/MapUtil.js +24 -3
  238. package/lib/utils/MapUtil.js.map +1 -1
  239. package/lib/utils/PathUtil.d.ts +31 -0
  240. package/lib/utils/PathUtil.js +38 -0
  241. package/lib/utils/PathUtil.js.map +1 -1
  242. package/lib/utils/SdkBundlePath.d.ts +2 -0
  243. package/lib/utils/SdkBundlePath.js +10 -0
  244. package/lib/utils/SdkBundlePath.js.map +1 -0
  245. package/lib/utils/SdkInputFilter.d.ts +31 -0
  246. package/lib/utils/SdkInputFilter.js +115 -0
  247. package/lib/utils/SdkInputFilter.js.map +1 -0
  248. package/lib/utils/SourceFinder.d.ts +45 -0
  249. package/lib/utils/SourceFinder.js +74 -16
  250. package/lib/utils/SourceFinder.js.map +1 -1
  251. package/lib/utils/StringUtil.d.ts +77 -2
  252. package/lib/utils/StringUtil.js +166 -4
  253. package/lib/utils/StringUtil.js.map +1 -1
  254. package/lib/utils/TemporaryDirectory.d.ts +60 -0
  255. package/lib/utils/TemporaryDirectory.js +112 -0
  256. package/lib/utils/TemporaryDirectory.js.map +1 -0
  257. package/lib/utils/TsConfigReader.d.ts +42 -0
  258. package/lib/utils/TsConfigReader.js +98 -14
  259. package/lib/utils/TsConfigReader.js.map +1 -1
  260. package/lib/utils/TtscExecutor.d.ts +23 -1
  261. package/lib/utils/TtscExecutor.js +22 -0
  262. package/lib/utils/TtscExecutor.js.map +1 -1
  263. package/lib/utils/VersioningStrategy.d.ts +39 -2
  264. package/lib/utils/VersioningStrategy.js +46 -13
  265. package/lib/utils/VersioningStrategy.js.map +1 -1
  266. package/lib/validators/TextPlainValidator.d.ts +19 -0
  267. package/lib/validators/TextPlainValidator.js +19 -0
  268. package/lib/validators/TextPlainValidator.js.map +1 -1
  269. package/native/go.mod +1 -1
  270. package/native/go.sum +2 -2
  271. package/native/sdk/register.go +12 -2
  272. package/native/sdk/sdk_http_rules.go +210 -0
  273. package/native/sdk/sdk_metadata_json.go +79 -4
  274. package/native/sdk/sdk_transform.go +1157 -414
  275. package/package.json +8 -6
  276. package/src/INestiaConfig.ts +74 -34
  277. package/src/NestiaSdkApplication.ts +129 -41
  278. package/src/NestiaSwaggerComposer.ts +32 -14
  279. package/src/analyses/AccessorAnalyzer.ts +26 -0
  280. package/src/analyses/ConfigAnalyzer.ts +52 -90
  281. package/src/analyses/ImportAnalyzer.ts +25 -0
  282. package/src/analyses/ParameterNameAnalyzer.ts +75 -0
  283. package/src/analyses/PathAnalyzer.ts +167 -23
  284. package/src/analyses/ReflectControllerAnalyzer.ts +34 -1
  285. package/src/analyses/ReflectHttpOperationAnalyzer.ts +36 -14
  286. package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +31 -0
  287. package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +153 -39
  288. package/src/analyses/ReflectHttpOperationResponseAnalyzer.ts +38 -7
  289. package/src/analyses/ReflectMcpOperationAnalyzer.ts +38 -3
  290. package/src/analyses/ReflectMetadataAnalyzer.ts +47 -0
  291. package/src/analyses/ReflectWebSocketOperationAnalyzer.ts +40 -7
  292. package/src/analyses/SecurityAnalyzer.ts +45 -20
  293. package/src/analyses/SwaggerExampleAnalyzer.ts +39 -0
  294. package/src/analyses/TypedHttpRouteAnalyzer.ts +263 -198
  295. package/src/analyses/TypedMcpRouteAnalyzer.ts +180 -20
  296. package/src/analyses/TypedWebSocketRouteAnalyzer.ts +20 -0
  297. package/src/decorators/OperationMetadata.ts +6 -0
  298. package/src/executable/internal/CommandParser.ts +19 -0
  299. package/src/executable/internal/NestiaConfigLoader.ts +66 -50
  300. package/src/executable/internal/NestiaSdkCommand.ts +96 -3
  301. package/src/executable/internal/NestiaSdkWatcher.ts +172 -44
  302. package/src/executable/internal/NestiaSwaggerWatch.ts +359 -0
  303. package/src/executable/sdk.ts +24 -1
  304. package/src/factories/ExpressionFactory.ts +23 -2
  305. package/src/factories/IdentifierFactory.ts +24 -0
  306. package/src/factories/LiteralFactory.ts +51 -13
  307. package/src/factories/StatementFactory.ts +28 -1
  308. package/src/factories/TypeFactory.ts +24 -0
  309. package/src/generates/CloneGenerator.ts +26 -5
  310. package/src/generates/E2eGenerator.ts +19 -0
  311. package/src/generates/SdkGenerator.ts +43 -12
  312. package/src/generates/SwaggerGenerator.ts +229 -46
  313. package/src/generates/internal/E2eFileProgrammer.ts +20 -0
  314. package/src/generates/internal/FilePrinter.ts +71 -0
  315. package/src/generates/internal/ImportDictionary.ts +120 -2
  316. package/src/generates/internal/SdkAliasCollection.ts +144 -15
  317. package/src/generates/internal/SdkDistributionComposer.ts +181 -56
  318. package/src/generates/internal/SdkFileProgrammer.ts +126 -16
  319. package/src/generates/internal/SdkHttpCloneProgrammer.ts +55 -0
  320. package/src/generates/internal/SdkHttpCloneReferencer.ts +97 -23
  321. package/src/generates/internal/SdkHttpFunctionProgrammer.ts +47 -30
  322. package/src/generates/internal/SdkHttpNamespaceProgrammer.ts +53 -64
  323. package/src/generates/internal/SdkHttpParameterProgrammer.ts +295 -13
  324. package/src/generates/internal/SdkHttpRouteProgrammer.ts +37 -31
  325. package/src/generates/internal/SdkHttpSimulationProgrammer.ts +122 -18
  326. package/src/generates/internal/SdkImportWizard.ts +63 -0
  327. package/src/generates/internal/SdkMcpRouteProgrammer.ts +150 -33
  328. package/src/generates/internal/SdkPathTemplate.ts +88 -0
  329. package/src/generates/internal/SdkRouteDirectory.ts +10 -0
  330. package/src/generates/internal/SdkTypeProgrammer.ts +137 -36
  331. package/src/generates/internal/SdkTypeTagProgrammer.ts +536 -78
  332. package/src/generates/internal/SdkWebSocketCloneProgrammer.ts +185 -142
  333. package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +62 -68
  334. package/src/generates/internal/SdkWebSocketParameterProgrammer.ts +205 -5
  335. package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +89 -48
  336. package/src/generates/internal/SwaggerDescriptionComposer.ts +47 -1
  337. package/src/generates/internal/SwaggerOperationComposer.ts +38 -6
  338. package/src/generates/internal/SwaggerOperationParameterComposer.ts +318 -36
  339. package/src/generates/internal/SwaggerOperationResponseComposer.ts +74 -11
  340. package/src/internal/legacy-augmentation.d.ts +16 -0
  341. package/src/internal/legacy.ts +407 -49
  342. package/src/structures/INestiaProject.ts +10 -0
  343. package/src/structures/INestiaSdkInput.ts +30 -0
  344. package/src/structures/IOperationMetadata.ts +83 -0
  345. package/src/structures/IReflectController.ts +10 -0
  346. package/src/structures/IReflectHttpOperation.ts +10 -0
  347. package/src/structures/IReflectHttpOperationException.ts +17 -2
  348. package/src/structures/IReflectHttpOperationParameter.ts +56 -2
  349. package/src/structures/IReflectHttpOperationSuccess.ts +19 -3
  350. package/src/structures/IReflectImport.ts +10 -0
  351. package/src/structures/IReflectMcpOperation.ts +19 -0
  352. package/src/structures/IReflectMcpOperationParameter.ts +9 -0
  353. package/src/structures/IReflectOperationError.ts +31 -2
  354. package/src/structures/IReflectType.ts +9 -0
  355. package/src/structures/IReflectWebSocketOperation.ts +10 -0
  356. package/src/structures/IReflectWebSocketOperationParameter.ts +55 -0
  357. package/src/structures/ITypedApplication.ts +10 -0
  358. package/src/structures/ITypedHttpRoute.ts +18 -0
  359. package/src/structures/ITypedHttpRouteException.ts +14 -1
  360. package/src/structures/ITypedHttpRouteParameter.ts +48 -1
  361. package/src/structures/ITypedHttpRouteSuccess.ts +14 -1
  362. package/src/structures/ITypedMcpRoute.ts +12 -0
  363. package/src/structures/ITypedWebSocketRoute.ts +18 -0
  364. package/src/transform.ts +6 -0
  365. package/src/utils/ArrayUtil.ts +32 -13
  366. package/src/utils/EmittedJavaScriptPatcher.ts +70 -47
  367. package/src/utils/FileRetriever.ts +29 -0
  368. package/src/utils/HttpResponseContentTypeUtil.ts +41 -0
  369. package/src/utils/MapUtil.ts +68 -3
  370. package/src/utils/PathUtil.ts +38 -0
  371. package/src/utils/SdkBundlePath.ts +11 -0
  372. package/src/utils/SdkInputFilter.ts +108 -0
  373. package/src/utils/SourceFinder.ts +76 -18
  374. package/src/utils/StringUtil.ts +182 -5
  375. package/src/utils/TemporaryDirectory.ts +108 -0
  376. package/src/utils/TsConfigReader.ts +124 -26
  377. package/src/utils/TtscExecutor.ts +23 -1
  378. package/src/utils/VersioningStrategy.ts +51 -16
  379. package/src/validators/TextPlainValidator.ts +19 -0
  380. package/lib/generates/internal/SwaggerReadonlyArrayEmender.d.ts +0 -9
  381. package/lib/generates/internal/SwaggerReadonlyArrayEmender.js +0 -178
  382. package/lib/generates/internal/SwaggerReadonlyArrayEmender.js.map +0 -1
  383. package/lib/validators/HttpHeadersValidator.d.ts +0 -11
  384. package/lib/validators/HttpHeadersValidator.js +0 -15
  385. package/lib/validators/HttpHeadersValidator.js.map +0 -1
  386. package/lib/validators/HttpQueryValidator.d.ts +0 -10
  387. package/lib/validators/HttpQueryValidator.js +0 -14
  388. package/lib/validators/HttpQueryValidator.js.map +0 -1
  389. package/src/generates/internal/SwaggerReadonlyArrayEmender.ts +0 -264
  390. package/src/validators/HttpHeadersValidator.ts +0 -12
  391. package/src/validators/HttpQueryValidator.ts +0 -11
@@ -6,7 +6,33 @@ import { ITypedWebSocketRoute } from "../structures/ITypedWebSocketRoute";
6
6
 
7
7
  type AnyRoute = ITypedHttpRoute | ITypedWebSocketRoute | ITypedMcpRoute;
8
8
 
9
+ /**
10
+ * Assigns each route the accessor path under which the generated SDK exposes
11
+ * it.
12
+ *
13
+ * @evidence contracts/common.md#principled-implementation The accessors are shrunk where a name repeats, escaped into valid unique identifiers, shrunk again, and each route is renamed to its last accessor segment.
14
+ * @evidence contracts/common.md#clear-and-simple-design One public function over three private passes.
15
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The passes follow the accessor structure and no route or controller name is special-cased.
16
+ * @evidence contracts/common.md#meaningful-documentation The comment states its purpose.
17
+ * efficient algorithms: For R routes of at most D accessor segments, the prefix maps avoid repeated route-to-route searches. Prefix slicing and joining costs O(R D²) character work before collision escapes; collisions add probes and longer names. Two shrink passes are required around escaping because escaping changes the names being shrunk.
18
+ * reuse equivalent work: This invocation computes its own result and coordinates no completed or in-flight computation across requests.
19
+ * bound retention and release resources: This operation owns only invocation-local values, with no retained cache, handle or background task.
20
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation AccessorAnalyzer analyzes reflected route metadata; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
21
+ */
9
22
  export namespace AccessorAnalyzer {
23
+ /**
24
+ * Rewrites the accessor of every route in place so that accessors are valid,
25
+ * unique, and as short as they can be.
26
+ *
27
+ * @evidence contracts/common.md#principled-implementation Segments that repeat their parent are removed when no sibling shares the parent, non-identifier characters become underscores, a segment that collides with an existing accessor gets an underscore prefix, and the route name becomes the last segment.
28
+ * @evidence contracts/common.md#clear-and-simple-design One function that runs the passes in a fixed order.
29
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The rules apply to every route, and reserved names are computed from the routes themselves.
30
+ * @evidence contracts/common.md#meaningful-documentation The comment states the passes and the in-place rewrite.
31
+ * efficient algorithms: For R routes of at most D accessor segments, the prefix maps avoid repeated route-to-route searches. Prefix slicing and joining costs O(R D²) character work before collision escapes; collisions add probes and longer names. Two shrink passes are required around escaping because escaping changes the names being shrunk.
32
+ * reuse equivalent work: This invocation computes its own result and coordinates no completed or in-flight computation across requests.
33
+ * bound retention and release resources: This operation owns only invocation-local values, with no retained cache, handle or background task.
34
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation AccessorAnalyzer.analyze analyzes reflected route metadata; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
35
+ */
10
36
  export const analyze = (routes: Array<AnyRoute>) => {
11
37
  shrink(routes);
12
38
  variable(routes);
@@ -6,20 +6,49 @@ import { Module } from "@nestjs/core/injector/module";
6
6
  import fs from "fs";
7
7
  import getFunctionLocation from "get-function-location";
8
8
  import path from "path";
9
- import { HashMap, Pair, Singleton } from "tstl";
9
+ import { HashMap } from "tstl";
10
10
  import { pathToFileURL } from "url";
11
11
 
12
12
  import { INestiaConfig } from "../INestiaConfig";
13
- import { SdkGenerator } from "../generates/SdkGenerator";
14
13
  import { INestiaSdkInput } from "../structures/INestiaSdkInput";
15
- import { ArrayUtil } from "../utils/ArrayUtil";
16
14
  import { EmittedJavaScriptPatcher } from "../utils/EmittedJavaScriptPatcher";
17
15
  import { MapUtil } from "../utils/MapUtil";
16
+ import { PathUtil } from "../utils/PathUtil";
17
+ import { SdkInputFilter } from "../utils/SdkInputFilter";
18
18
  import { SourceFinder } from "../utils/SourceFinder";
19
+ import { TemporaryDirectory } from "../utils/TemporaryDirectory";
19
20
  import { TsConfigReader } from "../utils/TsConfigReader";
20
21
  import { TtscExecutor } from "../utils/TtscExecutor";
21
22
 
23
+ /**
24
+ * Finds the controllers a configuration names, either by compiling and
25
+ * importing sources or by reading a running application.
26
+ *
27
+ * @evidence contracts/common.md#principled-implementation Sources are compiled once through ttsc into a temporary directory, imported, and the exports that carry the Nest `path` metadata are the controllers; an application is read from its module container; results are memoized per configuration object in a weakly keyed map, so a configuration the watcher reloads releases its entry with the object.
28
+ * @evidence contracts/common.md#clear-and-simple-design Two public functions and a private runtime compiler; the output-specific bundle filter comes from SdkInputFilter and configuration/runtime materializations share the owned-child cleanup registry.
29
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The generated SDK's own files are excluded from the input by the bundle list of the SDK, not by name, and the container is read through internals, as noted at `application`.
30
+ * @evidence contracts/common.md#meaningful-documentation The comment states its purpose.
31
+ * efficient algorithms: Discovery traverses candidate files once, compiles one runtime project and inspects every exported value; work scales with source/compiler input and export population. Application input instead traverses container controllers and resolves each unique class location.
32
+ * reuse equivalent work: The promise cache shares concurrent and completed analyses for the same config object. It assumes that object, its input sources and application state remain unchanged during its lifetime; callers must supply a fresh config object after changes. Bundle exclusion shares only installed asset descriptions and derives native/realpath roots separately for each output; distinct outputs never reuse one captured prefix.
33
+ * bound retention and release resources: The weakly keyed input map does not retain released config objects, but emitted directories are registered until owned generation cleanup or process exit. Imported CommonJS/ESM modules remain in the hosting Node loader; direct programmatic callers have no per-generation unload guarantee. CLI watch generations isolate this state in a short-lived child.
34
+ * @evidence contracts/portability.md#os-neutral-implementation Source/controller identity is obtained from Node path/file-URL conversion, module resolution and native fs. Compiler projects use explicit cwd and native paths; emitted module imports use file URLs. Route prefix/version spelling is kept as protocol text, not treated as filesystem identity.
35
+ */
22
36
  export namespace ConfigAnalyzer {
37
+ /**
38
+ * Returns the analyzed input of a configuration: the controllers with their
39
+ * files and the global prefix and versioning options.
40
+ *
41
+ * The result is cached per configuration object.
42
+ *
43
+ * @evidence contracts/common.md#principled-implementation A function input is asked for the application and read as a running app; otherwise the matched TypeScript sources are compiled and imported, and the memo stores the promise so concurrent callers share one compilation.
44
+ * @evidence contracts/common.md#clear-and-simple-design One function delegating to `application` or to the runtime compiler.
45
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The cache is keyed by the identity of the configuration object, so a different or reloaded configuration object is never served another's result; one object keeps its first result, which is the contract of a configuration that is not mutated between generations.
46
+ * @evidence contracts/common.md#meaningful-documentation The comment states the two input forms and the caching.
47
+ * efficient algorithms: Discovery traverses candidate files once, compiles one runtime project and inspects every exported value; work scales with source/compiler input and export population. Application input instead traverses container controllers and resolves each unique class location.
48
+ * reuse equivalent work: The promise cache shares concurrent and completed analyses for the same config object. It assumes that object, its input sources and application state remain unchanged during its lifetime; callers must supply a fresh config object after changes. Bundle exclusion shares only installed asset descriptions and derives native/realpath roots separately for each output; distinct outputs never reuse one captured prefix.
49
+ * bound retention and release resources: The weakly keyed input map does not retain released config objects, but emitted directories are registered until owned generation cleanup or process exit. Imported CommonJS/ESM modules remain in the hosting Node loader; direct programmatic callers have no per-generation unload guarantee. CLI watch generations isolate this state in a short-lived child.
50
+ * @evidence contracts/portability.md#os-neutral-implementation Source/controller identity is obtained from Node path/file-URL conversion, module resolution and native fs. Compiler projects use explicit cwd and native paths; emitted module imports use file URLs. Route prefix/version spelling is kept as protocol text, not treated as filesystem identity.
51
+ */
23
52
  export const input = async (
24
53
  config: INestiaConfig,
25
54
  ): Promise<INestiaSdkInput> => {
@@ -37,7 +66,7 @@ export namespace ConfigAnalyzer {
37
66
  typeof config.input === "object" && !Array.isArray(config.input)
38
67
  ? (config.input.exclude ?? [])
39
68
  : [],
40
- filter: filter(config),
69
+ filter: await SdkInputFilter.create(config.output),
41
70
  });
42
71
  const runtime: RuntimeCompiler = await RuntimeCompiler.compile(sources);
43
72
  const controllers: INestiaSdkInput.IController[] = [];
@@ -62,6 +91,19 @@ export namespace ConfigAnalyzer {
62
91
  });
63
92
  };
64
93
 
94
+ /**
95
+ * Reads the controllers, the global prefix, and the versioning options of a
96
+ * running NestJS application.
97
+ *
98
+ * @evidence contracts/common.md#principled-implementation The controllers come from the module container with their module paths, their files from the location of each class, decoded from the `file:` URL, and the prefix and versioning options from the application's configuration.
99
+ * @evidence contracts/common.md#clear-and-simple-design One function.
100
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts NestJS exposes no public accessor for the container or the configuration, so the function reads `app.container` and `app.config`; this is the one foreign-internal read of the package and stays a stated limit.
101
+ * @evidence contracts/common.md#meaningful-documentation The comment states what is read.
102
+ * efficient algorithms: The container is traversed once and a hash map groups each class with its module prefixes, so location lookup occurs once per unique controller class.
103
+ * reuse equivalent work: This invocation computes its own result and coordinates no completed or in-flight computation across requests.
104
+ * bound retention and release resources: The invocation retains local module/controller collections until it returns. The running application and its controllers remain caller-owned; this reader neither starts nor closes the app.
105
+ * @evidence contracts/portability.md#os-neutral-implementation Source/controller identity is obtained from Node path/file-URL conversion, module resolution and native fs. Compiler projects use explicit cwd and native paths; emitted module imports use file URLs. Route prefix/version spelling is kept as protocol text, not treated as filesystem identity.
106
+ */
65
107
  export const application = async (
66
108
  app: INestApplication,
67
109
  ): Promise<INestiaSdkInput> => {
@@ -88,7 +130,7 @@ export namespace ConfigAnalyzer {
88
130
  const file: string | null =
89
131
  (await getFunctionLocation(it.first))?.source ?? null;
90
132
  if (file === null) continue;
91
- const location: string = normalize_file(file);
133
+ const location: string = PathUtil.location(file);
92
134
  if (location.length === 0) continue;
93
135
  controllers.push({
94
136
  class: it.first,
@@ -111,16 +153,16 @@ export namespace ConfigAnalyzer {
111
153
  versioning === undefined || versioning.type !== VersioningType.URI
112
154
  ? undefined
113
155
  : {
156
+ // as NestJS's RoutePathFactory.getVersionPrefix(): `false` is no
157
+ // prefix at all, and only an absent one is the default "v"
114
158
  prefix:
115
- versioning.prefix === undefined || versioning.prefix === false
116
- ? "v"
117
- : versioning.prefix,
159
+ versioning.prefix === false ? "" : (versioning.prefix ?? "v"),
118
160
  defaultVersion: versioning.defaultVersion,
119
161
  },
120
162
  };
121
163
  };
122
164
  }
123
- const memory = new Map<INestiaConfig, Promise<INestiaSdkInput>>();
165
+ const memory = new WeakMap<INestiaConfig, Promise<INestiaSdkInput>>();
124
166
  class RuntimeCompiler {
125
167
  private constructor(
126
168
  private readonly cwd: string,
@@ -135,11 +177,7 @@ class RuntimeCompiler {
135
177
  ".nestia",
136
178
  "runtime",
137
179
  );
138
- await fs.promises.mkdir(runtimeRoot, { recursive: true });
139
- ensureRuntimeCleanup(runtimeRoot);
140
- const outDir: string = await fs.promises.mkdtemp(
141
- path.join(runtimeRoot, "run-"),
142
- );
180
+ const outDir: string = TemporaryDirectory.create(runtimeRoot, "run-");
143
181
  const project: string = path.join(
144
182
  cwd,
145
183
  `.nestia.runtime.${process.pid}.${Date.now()}.json`,
@@ -195,42 +233,6 @@ class RuntimeCompiler {
195
233
  }
196
234
  }
197
235
 
198
- const RUNTIME_ROOTS: Set<string> = new Set();
199
- let RUNTIME_CLEANUP_REGISTERED: boolean = false;
200
-
201
- const ensureRuntimeCleanup = (runtimeRoot: string): void => {
202
- RUNTIME_ROOTS.add(runtimeRoot);
203
- if (RUNTIME_CLEANUP_REGISTERED === true) return;
204
- RUNTIME_CLEANUP_REGISTERED = true;
205
- const sweep = (): void => {
206
- for (const location of RUNTIME_ROOTS)
207
- fs.rmSync(location, { force: true, recursive: true });
208
- };
209
- process.once("exit", sweep);
210
- // process.once("exit", …) does not fire on SIGINT/SIGTERM. Without these
211
- // handlers a Ctrl-C during codegen leaves `run-*` mkdtemp directories
212
- // behind under node_modules/.nestia/runtime/ until a subsequent clean exit.
213
- // The module-level RUNTIME_CLEANUP_REGISTERED flag above guards against
214
- // re-entrancy within this module; we deliberately do NOT gate on
215
- // `process.listenerCount(signal) > 0` because NestiaConfigLoader's parallel
216
- // sweep registers first, and that gate would skip our registration —
217
- // leaving RUNTIME_ROOTS unswept on Ctrl-C while config-loader cleans up.
218
- // Windows note: `process.kill(pid, "SIGINT")` calls TerminateProcess
219
- // rather than re-raising through the listener queue, so the handler
220
- // cascade documented above only holds on POSIX. On Windows, whichever
221
- // module registers FIRST runs its sweep and the second is skipped —
222
- // RUNTIME_ROOTS cleanup is best-effort there. SIGHUP is a no-op for
223
- // most common code paths on Windows (Node fires it on console-close
224
- // and exits within seconds).
225
- const onSignal = (signal: NodeJS.Signals): void => {
226
- sweep();
227
- process.kill(process.pid, signal);
228
- };
229
- for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"] as const) {
230
- process.once(signal, onSignal);
231
- }
232
- };
233
-
234
236
  type RuntimePlugin = Record<string, unknown> & { transform?: unknown };
235
237
 
236
238
  const sdkTransformEnv = (): NodeJS.ProcessEnv =>
@@ -298,47 +300,7 @@ const normalizeProjectPath = (project: string | undefined): string => {
298
300
  return path.isAbsolute(next) || next.startsWith(".") ? next : `./${next}`;
299
301
  };
300
302
 
301
- const normalize_file = (str: string) =>
302
- str.substring(
303
- str.startsWith("file:///")
304
- ? process.cwd()[0] === "/"
305
- ? 7
306
- : 8
307
- : str.startsWith("file://")
308
- ? 7
309
- : 0,
310
- );
311
-
312
- const filter =
313
- (config: INestiaConfig) =>
314
- async (location: string): Promise<boolean> =>
315
- SourceFinder.isTypeScriptSource(location) &&
316
- (config.output === undefined ||
317
- (location.indexOf(path.join(config.output, "functional")) === -1 &&
318
- (await (
319
- await bundler.get(config.output)
320
- )(location))) === false);
321
-
322
303
  const dynamicImport: (specifier: string) => Promise<any> = Function(
323
304
  "specifier",
324
305
  "return import(specifier);",
325
306
  ) as (specifier: string) => Promise<any>;
326
-
327
- const bundler = new Singleton(async (output: string) => {
328
- const assets: string[] = await fs.promises.readdir(SdkGenerator.BUNDLE_PATH);
329
- const tuples: Pair<string, boolean>[] = await ArrayUtil.asyncMap(
330
- assets,
331
- async (file) => {
332
- const relative: string = path.join(output, file);
333
- const location: string = path.join(SdkGenerator.BUNDLE_PATH, file);
334
- const stats: fs.Stats = await fs.promises.stat(location);
335
- return new Pair(relative, stats.isDirectory());
336
- },
337
- );
338
- return async (file: string): Promise<boolean> => {
339
- for (const it of tuples)
340
- if (it.second === false && file === it.first) return true;
341
- else if (it.second === true && file.indexOf(it.first) === 0) return true;
342
- return false;
343
- };
344
- });
@@ -1,6 +1,15 @@
1
1
  import { IReflectImport } from "../structures/IReflectImport";
2
2
  import { MapUtil } from "../utils/MapUtil";
3
3
 
4
+ /**
5
+ * Helpers for the import lists of routes.
6
+ *
7
+ * @evidence contracts/common.md#principled-implementation The namespace merges the imports collected for one route and keeps a removal notice for the old analysis entry.
8
+ * @evidence contracts/common.md#clear-and-simple-design Two functions.
9
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The merge is generic.
10
+ * @evidence contracts/common.md#meaningful-documentation The comment states its purpose.
11
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation ImportAnalyzer analyzes reflected route metadata; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
12
+ */
4
13
  export namespace ImportAnalyzer {
5
14
  /**
6
15
  * @deprecated Removed in the Go-migration cycle. Import metadata is now
@@ -10,6 +19,11 @@ export namespace ImportAnalyzer {
10
19
  * `ts.SourceFile` to derive imports should read the metadata delivered
11
20
  * through `Reflect.getMetadata("nestia/OperationMetadata", …)` instead. See
12
21
  * `packages/core/MIGRATION.md`.
22
+ * @evidence contracts/common.md#principled-implementation The function exists only to give an actionable error to a caller of the removed API, and always throws.
23
+ * @evidence contracts/common.md#clear-and-simple-design One statement.
24
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It reports the removal instead of failing later with a missing function.
25
+ * @evidence contracts/common.md#meaningful-documentation The comment names the replacement.
26
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation ImportAnalyzer.analyze analyzes reflected route metadata; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
13
27
  */
14
28
  export const analyze = (): never => {
15
29
  throw new Error(
@@ -19,6 +33,17 @@ export namespace ImportAnalyzer {
19
33
  );
20
34
  };
21
35
 
36
+ /**
37
+ * Merges import records by file: namespace imports and default imports are
38
+ * deduplicated and sorted, and the named elements of every import of a file
39
+ * are combined with their aliases.
40
+ *
41
+ * @evidence contracts/common.md#principled-implementation Imports are grouped by file, each group emits its namespace imports, default imports, and one element list with an alias map for renamed elements, so the same file is imported once per kind.
42
+ * @evidence contracts/common.md#clear-and-simple-design One function over one group merger.
43
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The merge follows the import records, with no file special-cased.
44
+ * @evidence contracts/common.md#meaningful-documentation The comment states the grouping and the merging.
45
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation ImportAnalyzer.merge analyzes reflected route metadata; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
46
+ */
22
47
  export const merge = (imports: IReflectImport[]): IReflectImport[] => {
23
48
  // group by files
24
49
  const fileGroups: Map<string, IReflectImport[]> = new Map();
@@ -0,0 +1,75 @@
1
+ import { NamingConvention } from "@typia/utils";
2
+
3
+ import { StringUtil } from "../utils/StringUtil";
4
+
5
+ /**
6
+ * Gives names to parameters that declare none, such as destructured ones.
7
+ *
8
+ * @evidence contracts/common.md#principled-implementation A missing name is derived from the field, camel-cased when it is not an identifier, or from the category, and then made unique against the names already taken.
9
+ * @evidence contracts/common.md#clear-and-simple-design One function, one record type, and one private candidate rule.
10
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The rule is generic.
11
+ * @evidence contracts/common.md#meaningful-documentation The comment states its purpose.
12
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation ParameterNameAnalyzer analyzes reflected route metadata; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
13
+ */
14
+ export namespace ParameterNameAnalyzer {
15
+ /**
16
+ * A parameter to name: its current name, its category, and an optional field.
17
+ *
18
+ * @evidence contracts/common.md#principled-implementation The three members are the inputs of the naming rule.
19
+ * @evidence contracts/common.md#clear-and-simple-design A flat record with no behavior.
20
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
21
+ * @evidence contracts/common.md#meaningful-documentation The comment states what the type describes and the meaning of its members.
22
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation ParameterNameAnalyzer.IParameter analyzes reflected route metadata; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
23
+ */
24
+ export interface IParameter {
25
+ name: string;
26
+ category: string;
27
+ field?: string | null;
28
+ }
29
+
30
+ /**
31
+ * Names every parameter that declares no name of its own.
32
+ *
33
+ * A destructured parameter, `@TypedBody() { title }: IBody`, binds names but
34
+ * is not one, so the SDK's metadata carries it with an empty name. Its source
35
+ * text is no identifier the SDK could declare, and passing it as one would
36
+ * send `{ title }` alone. It is named after what it carries instead: its
37
+ * field when that is an identifier, or reads as one with its separators
38
+ * dropped in camel case, otherwise its category, such as `body` or `query`.
39
+ * The name yields to every other parameter's, which are the user's and are
40
+ * kept.
41
+ *
42
+ * @evidence contracts/common.md#principled-implementation The names in use are collected first, and each new name is escaped against them with underscores and added, so the result has no duplicates.
43
+ * @evidence contracts/common.md#clear-and-simple-design One function.
44
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Existing names are never changed.
45
+ * @evidence contracts/common.md#meaningful-documentation The comment states the rule.
46
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation ParameterNameAnalyzer.name analyzes reflected route metadata; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
47
+ */
48
+ export const name = <T extends IParameter>(parameters: T[]): T[] => {
49
+ const taken: string[] = parameters
50
+ .map((p) => p.name)
51
+ .filter((name) => name.length !== 0);
52
+ return parameters.map((p) => {
53
+ if (p.name.length !== 0) return p;
54
+ const name: string = StringUtil.escapeDuplicate(taken)(candidate(p));
55
+ taken.push(name);
56
+ return { ...p, name };
57
+ });
58
+ };
59
+
60
+ const candidate = (p: IParameter): string => {
61
+ if (p.field !== undefined && p.field !== null && p.field.length !== 0) {
62
+ if (NamingConvention.variable(p.field)) return p.field;
63
+ // `x-tenant` as `xTenant`
64
+ const camel: string = p.field
65
+ .split(/[^A-Za-z0-9_$]+/)
66
+ .filter((word) => word.length !== 0)
67
+ .map((word, i) =>
68
+ i === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1),
69
+ )
70
+ .join("");
71
+ if (NamingConvention.variable(camel)) return camel;
72
+ }
73
+ return p.category;
74
+ };
75
+ }
@@ -1,17 +1,46 @@
1
1
  import { RequestMethod } from "@nestjs/common";
2
- import path from "path";
3
2
  import { Token, parse } from "path-to-regexp";
4
3
 
4
+ /**
5
+ * Helpers for route paths: joining, prefixing, and reading their parameters the
6
+ * way the router does.
7
+ *
8
+ * @evidence contracts/common.md#principled-implementation Paths are parsed by `path-to-regexp` after Fastify colon escapes are converted, so the parameters and literals are those the server reads.
9
+ * @evidence contracts/common.md#clear-and-simple-design Several small functions over one tokenizer and one parser.
10
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The router's own grammar decides, and no path is special-cased.
11
+ * @evidence contracts/common.md#meaningful-documentation The comment states its purpose.
12
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation PathAnalyzer interprets router protocol paths; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
13
+ */
5
14
  export namespace PathAnalyzer {
15
+ /**
16
+ * The route paths joined as the router joins them: one `/` between them, and
17
+ * none doubled. A route path is router syntax, never a file path, so a
18
+ * backslash stays the escape of the character after it (`items\\:batchGet`).
19
+ *
20
+ * @evidence contracts/common.md#principled-implementation The parts are joined, split on slashes, and empty segments are dropped, so any number of slashes at the boundaries collapses.
21
+ * @evidence contracts/common.md#clear-and-simple-design One expression.
22
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It applies to every input.
23
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result form.
24
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation PathAnalyzer.join interprets router protocol paths; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
25
+ */
6
26
  export const join = (...args: string[]) =>
7
27
  "/" +
8
- _Trim(
9
- path
10
- .join(...args.filter((s) => !!s.length))
11
- .split("\\")
12
- .join("/"),
13
- );
28
+ args
29
+ .join("/")
30
+ .split("/")
31
+ .filter((str) => str.length !== 0)
32
+ .join("/");
14
33
 
34
+ /**
35
+ * Joins a path with the global prefix, unless the route is excluded from the
36
+ * prefix.
37
+ *
38
+ * @evidence contracts/common.md#principled-implementation The exclusion list is matched by method and by exact path or pattern, as NestJS does, and an excluded route is joined with an empty prefix.
39
+ * @evidence contracts/common.md#clear-and-simple-design One function delegating the exclusion test to a private helper.
40
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The exclusion rule is NestJS's.
41
+ * @evidence contracts/common.md#meaningful-documentation The comment states the exclusion.
42
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation PathAnalyzer.joinWithGlobalPrefix interprets router protocol paths; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
43
+ */
15
44
  export const joinWithGlobalPrefix = (props: {
16
45
  globalPrefix: string;
17
46
  exclude: IGlobalPrefixExclude[] | undefined;
@@ -30,31 +59,115 @@ export namespace PathAnalyzer {
30
59
  props.path,
31
60
  );
32
61
 
33
- export const escape = (str: string): string | null => {
34
- const args = _Parse(str);
35
- if (args === null) return null;
36
- return (
37
- "/" +
38
- args
39
- .map((arg) => (arg.type === "param" ? `:${arg.value}` : arg.value))
40
- .join("/")
41
- );
62
+ /**
63
+ * Whether a route path holds a wildcard: a `*` not escaped as the literal
64
+ * character (`\\*`), which a route path may hold since #1713.
65
+ *
66
+ * @evidence contracts/common.md#principled-implementation A star preceded by a backslash is a literal, so the test looks for a star at the start or after a non-backslash character.
67
+ * @evidence contracts/common.md#clear-and-simple-design One regular expression.
68
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It follows the router's escaping rule.
69
+ * @evidence contracts/common.md#meaningful-documentation The comment states the escaped case.
70
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation PathAnalyzer.wildcard interprets router protocol paths; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
71
+ */
72
+ export const wildcard = (str: string): boolean => /(^|[^\\])\*/.test(str);
73
+
74
+ /**
75
+ * The literal text and parameters of a path, in order, as path-to-regexp
76
+ * reads it: `/files/:id.json` is `/files/`, the parameter `id`, then `.json`,
77
+ * and `/range/:from-:to` holds two parameters parted by `-`. Every generator
78
+ * that writes a path with its parameters filled in reads it from here, never
79
+ * by splitting the text at `:` or `/`. `null` for a path it cannot parse.
80
+ *
81
+ * @evidence contracts/common.md#principled-implementation Tokens come from `path-to-regexp`, so text next to a parameter in one segment, such as `/files/:id.json`, is kept in place, adjacent literals merge, and an unnamed parameter makes the path unreadable.
82
+ * @evidence contracts/common.md#clear-and-simple-design One function over the tokenizer.
83
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The grammar is the router's.
84
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result and why generators use it.
85
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation PathAnalyzer.segments interprets router protocol paths; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
86
+ */
87
+ export const segments = (str: string): ISegment[] | null => {
88
+ const tokens: Token[] | null = _Tokenize(str);
89
+ if (tokens === null) return null;
90
+ const output: ISegment[] = [];
91
+ const literal = (value: string): void => {
92
+ if (value.length === 0) return;
93
+ const last: ISegment | undefined = output[output.length - 1];
94
+ if (last?.type === "literal") last.value += value;
95
+ else output.push({ type: "literal", value });
96
+ };
97
+ for (const token of tokens)
98
+ if (typeof token === "string") literal(token);
99
+ else if (typeof token.name === "number") return null;
100
+ else {
101
+ literal(token.prefix);
102
+ output.push({ type: "param", name: token.name });
103
+ literal(token.suffix);
104
+ }
105
+ return output;
106
+ };
107
+
108
+ /**
109
+ * The path in OpenAPI's template syntax, each parameter written `{name}`:
110
+ * `/files/:id.json` is `/files/{id}.json`.
111
+ *
112
+ * @evidence contracts/common.md#principled-implementation The segments are joined with literals verbatim and parameters in braces.
113
+ * @evidence contracts/common.md#clear-and-simple-design One expression over `segments`.
114
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It uses the same segmenter as the SDK generator.
115
+ * @evidence contracts/common.md#meaningful-documentation The comment states the fallback.
116
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation PathAnalyzer.toOpenApi interprets router protocol paths; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
117
+ */
118
+ export const toOpenApi = (str: string): string => {
119
+ const list: ISegment[] | null = segments(str);
120
+ return list === null
121
+ ? str
122
+ : list
123
+ .map((s) => (s.type === "literal" ? s.value : `{${s.name}}`))
124
+ .join("");
42
125
  };
43
126
 
127
+ /**
128
+ * A segment of a path: literal text or a named parameter.
129
+ *
130
+ * @evidence contracts/common.md#principled-implementation The union is discriminated by `type`, so a consumer handles each case once.
131
+ * @evidence contracts/common.md#clear-and-simple-design A two-member union.
132
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
133
+ * @evidence contracts/common.md#meaningful-documentation The comment names the two cases.
134
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation PathAnalyzer.ISegment interprets router protocol paths; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
135
+ */
136
+ export type ISegment =
137
+ | { type: "literal"; value: string }
138
+ | { type: "param"; name: string };
139
+
140
+ /**
141
+ * Returns the names of the parameters of a path, or `null` when the path
142
+ * cannot be parsed.
143
+ *
144
+ * @evidence contracts/common.md#principled-implementation The parsed arguments are filtered to the parameters, and an empty parameter name makes the path unreadable.
145
+ * @evidence contracts/common.md#clear-and-simple-design One filter over the private parser.
146
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The grammar is the router's.
147
+ * @evidence contracts/common.md#meaningful-documentation The comment states the result.
148
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation PathAnalyzer.parameters interprets router protocol paths; it does not resolve native file identity or launch a process. Source resolution and file emission belong to their filesystem owners.
149
+ */
44
150
  export const parameters = (str: string): string[] | null => {
45
151
  const args = _Parse(str);
46
152
  if (args === null) return null;
47
153
  return args.filter((arg) => arg.type === "param").map((arg) => arg.value);
48
154
  };
49
155
 
156
+ /**
157
+ * The route's tokens, its literal text unescaped. Both routers' spellings of
158
+ * a literal colon are read: path-to-regexp's (Express) `\\:`, and
159
+ * find-my-way's (Fastify) `::`, which path-to-regexp would reject.
160
+ */
161
+ function _Tokenize(str: string): Token[] | null {
162
+ try {
163
+ return parse(fromFastifyColons(join(str)));
164
+ } catch {
165
+ return null;
166
+ }
167
+ }
168
+
50
169
  function _Parse(str: string): IArgument[] | null {
51
- const tokens: Token[] | null = (() => {
52
- try {
53
- return parse(path.join(str).split("\\").join("/"));
54
- } catch {
55
- return null;
56
- }
57
- })();
170
+ const tokens: Token[] | null = _Tokenize(str);
58
171
  if (tokens === null) return null;
59
172
 
60
173
  const output: IArgument[] = [];
@@ -128,3 +241,34 @@ const REQUEST_METHODS: Record<string, RequestMethod> = {
128
241
  POST: RequestMethod.POST,
129
242
  PUT: RequestMethod.PUT,
130
243
  };
244
+
245
+ /**
246
+ * A route with find-my-way's (Fastify) literal colon `::` spelled as
247
+ * path-to-regexp's `\:`. find-my-way reads `::` as a colon in static text
248
+ * alone: after a parameter it is part of the parameter's name, so it is left as
249
+ * is there, and path-to-regexp then rejects the route, as no parameter of that
250
+ * name is what the handler reads.
251
+ *
252
+ * @internal
253
+ */
254
+ const fromFastifyColons = (route: string): string => {
255
+ let output: string = "";
256
+ for (let i: number = 0; i < route.length; ) {
257
+ if (route[i] === "\\") {
258
+ output += route.slice(i, i + 2);
259
+ i += 2;
260
+ } else if (route.startsWith("::", i)) {
261
+ output += "\\:";
262
+ i += 2;
263
+ } else if (route[i] === ":") {
264
+ const name: string = /^:[A-Za-z0-9_$]*/.exec(route.slice(i))![0];
265
+ output += name;
266
+ i += name.length;
267
+ if (route.startsWith("::", i)) {
268
+ output += "::";
269
+ i += 2;
270
+ }
271
+ } else output += route[i++];
272
+ }
273
+ return output;
274
+ };