@nestia/sdk 12.0.0-dev.20260601.1 → 12.0.0-dev.20260619.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 (259) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +93 -93
  3. package/assets/bundle/api/HttpError.ts +1 -1
  4. package/assets/bundle/api/IConnection.ts +1 -1
  5. package/assets/bundle/api/Primitive.ts +1 -1
  6. package/assets/bundle/api/Resolved.ts +1 -1
  7. package/assets/bundle/api/index.ts +4 -4
  8. package/assets/bundle/api/module.ts +6 -6
  9. package/assets/bundle/distribute/README.md +37 -37
  10. package/assets/bundle/distribute/package.json +28 -28
  11. package/assets/bundle/distribute/tsconfig.json +109 -109
  12. package/assets/bundle/e2e/index.ts +42 -42
  13. package/assets/config/nestia.config.ts +97 -97
  14. package/lib/NestiaSdkApplication.js +29 -7
  15. package/lib/NestiaSdkApplication.js.map +1 -1
  16. package/lib/NestiaSwaggerComposer.js +21 -13
  17. package/lib/NestiaSwaggerComposer.js.map +1 -1
  18. package/lib/analyses/AccessorAnalyzer.d.ts +4 -1
  19. package/lib/analyses/AccessorAnalyzer.js.map +1 -1
  20. package/lib/analyses/ConfigAnalyzer.js +1 -1
  21. package/lib/analyses/PathAnalyzer.d.ts +18 -3
  22. package/lib/analyses/PathAnalyzer.js +32 -0
  23. package/lib/analyses/PathAnalyzer.js.map +1 -1
  24. package/lib/analyses/ReflectControllerAnalyzer.js +3 -2
  25. package/lib/analyses/ReflectControllerAnalyzer.js.map +1 -1
  26. package/lib/analyses/ReflectHttpOperationAnalyzer.d.ts +1 -1
  27. package/lib/analyses/ReflectHttpOperationAnalyzer.js +1 -1
  28. package/lib/analyses/ReflectHttpOperationAnalyzer.js.map +1 -1
  29. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.d.ts +1 -1
  30. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js +53 -20
  31. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js.map +1 -1
  32. package/lib/analyses/ReflectMcpOperationAnalyzer.d.ts +14 -0
  33. package/lib/analyses/ReflectMcpOperationAnalyzer.js +79 -0
  34. package/lib/analyses/ReflectMcpOperationAnalyzer.js.map +1 -0
  35. package/lib/analyses/TypedMcpRouteAnalyzer.d.ts +9 -0
  36. package/lib/analyses/TypedMcpRouteAnalyzer.js +31 -0
  37. package/lib/analyses/TypedMcpRouteAnalyzer.js.map +1 -0
  38. package/lib/executable/internal/NestiaConfigLoader.js +5 -1
  39. package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
  40. package/lib/executable/internal/NestiaSdkCommand.js +30 -14
  41. package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
  42. package/lib/executable/internal/NestiaSdkWatcher.d.ts +10 -0
  43. package/lib/executable/internal/NestiaSdkWatcher.js +322 -0
  44. package/lib/executable/internal/NestiaSdkWatcher.js.map +1 -0
  45. package/lib/executable/sdk.js +12 -12
  46. package/lib/executable/sdk.js.map +1 -1
  47. package/lib/factories/ExpressionFactory.d.ts +9 -0
  48. package/lib/factories/ExpressionFactory.js +16 -0
  49. package/lib/factories/ExpressionFactory.js.map +1 -0
  50. package/lib/factories/IdentifierFactory.d.ts +22 -0
  51. package/lib/factories/IdentifierFactory.js +50 -0
  52. package/lib/factories/IdentifierFactory.js.map +1 -0
  53. package/lib/factories/LiteralFactory.d.ts +9 -0
  54. package/lib/factories/LiteralFactory.js +48 -0
  55. package/lib/factories/LiteralFactory.js.map +1 -0
  56. package/lib/factories/StatementFactory.d.ts +14 -0
  57. package/lib/factories/StatementFactory.js +20 -0
  58. package/lib/factories/StatementFactory.js.map +1 -0
  59. package/lib/factories/TypeFactory.d.ts +24 -0
  60. package/lib/factories/TypeFactory.js +27 -0
  61. package/lib/factories/TypeFactory.js.map +1 -0
  62. package/lib/generates/CloneGenerator.js +6 -4
  63. package/lib/generates/CloneGenerator.js.map +1 -1
  64. package/lib/generates/SdkGenerator.js +50 -1
  65. package/lib/generates/SdkGenerator.js.map +1 -1
  66. package/lib/generates/SwaggerGenerator.js +18 -2
  67. package/lib/generates/SwaggerGenerator.js.map +1 -1
  68. package/lib/generates/internal/E2eFileProgrammer.js +32 -29
  69. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  70. package/lib/generates/internal/FilePrinter.d.ts +2 -2
  71. package/lib/generates/internal/FilePrinter.js +14 -25
  72. package/lib/generates/internal/FilePrinter.js.map +1 -1
  73. package/lib/generates/internal/ImportDictionary.d.ts +2 -1
  74. package/lib/generates/internal/ImportDictionary.js +16 -10
  75. package/lib/generates/internal/ImportDictionary.js.map +1 -1
  76. package/lib/generates/internal/SdkAliasCollection.d.ts +12 -10
  77. package/lib/generates/internal/SdkAliasCollection.js +29 -22
  78. package/lib/generates/internal/SdkAliasCollection.js.map +1 -1
  79. package/lib/generates/internal/SdkDistributionComposer.d.ts +1 -0
  80. package/lib/generates/internal/SdkDistributionComposer.js +3 -0
  81. package/lib/generates/internal/SdkDistributionComposer.js.map +1 -1
  82. package/lib/generates/internal/SdkFileProgrammer.js +6 -3
  83. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  84. package/lib/generates/internal/SdkHttpCloneProgrammer.d.ts +1 -1
  85. package/lib/generates/internal/SdkHttpCloneProgrammer.js +3 -3
  86. package/lib/generates/internal/SdkHttpCloneProgrammer.js.map +1 -1
  87. package/lib/generates/internal/SdkHttpCloneReferencer.d.ts +1 -1
  88. package/lib/generates/internal/SdkHttpCloneReferencer.js +42 -9
  89. package/lib/generates/internal/SdkHttpCloneReferencer.js.map +1 -1
  90. package/lib/generates/internal/SdkHttpFunctionProgrammer.d.ts +1 -1
  91. package/lib/generates/internal/SdkHttpFunctionProgrammer.js +47 -51
  92. package/lib/generates/internal/SdkHttpFunctionProgrammer.js.map +1 -1
  93. package/lib/generates/internal/SdkHttpNamespaceProgrammer.d.ts +1 -1
  94. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js +63 -61
  95. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js.map +1 -1
  96. package/lib/generates/internal/SdkHttpParameterProgrammer.d.ts +2 -2
  97. package/lib/generates/internal/SdkHttpParameterProgrammer.js +11 -13
  98. package/lib/generates/internal/SdkHttpParameterProgrammer.js.map +1 -1
  99. package/lib/generates/internal/SdkHttpRouteProgrammer.d.ts +1 -1
  100. package/lib/generates/internal/SdkHttpSimulationProgrammer.d.ts +1 -1
  101. package/lib/generates/internal/SdkHttpSimulationProgrammer.js +52 -47
  102. package/lib/generates/internal/SdkHttpSimulationProgrammer.js.map +1 -1
  103. package/lib/generates/internal/SdkMcpRouteProgrammer.d.ts +15 -0
  104. package/lib/generates/internal/SdkMcpRouteProgrammer.js +149 -0
  105. package/lib/generates/internal/SdkMcpRouteProgrammer.js.map +1 -0
  106. package/lib/generates/internal/SdkRouteDirectory.d.ts +2 -1
  107. package/lib/generates/internal/SdkRouteDirectory.js.map +1 -1
  108. package/lib/generates/internal/SdkTypeProgrammer.d.ts +3 -3
  109. package/lib/generates/internal/SdkTypeProgrammer.js +42 -43
  110. package/lib/generates/internal/SdkTypeProgrammer.js.map +1 -1
  111. package/lib/generates/internal/SdkTypeTagProgrammer.d.ts +2 -1
  112. package/lib/generates/internal/SdkTypeTagProgrammer.js +7 -9
  113. package/lib/generates/internal/SdkTypeTagProgrammer.js.map +1 -1
  114. package/lib/generates/internal/SdkWebSocketCloneProgrammer.d.ts +6 -0
  115. package/lib/generates/internal/SdkWebSocketCloneProgrammer.js +283 -0
  116. package/lib/generates/internal/SdkWebSocketCloneProgrammer.js.map +1 -0
  117. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.d.ts +2 -2
  118. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js +45 -47
  119. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js.map +1 -1
  120. package/lib/generates/internal/SdkWebSocketParameterProgrammer.d.ts +3 -3
  121. package/lib/generates/internal/SdkWebSocketParameterProgrammer.js +9 -9
  122. package/lib/generates/internal/SdkWebSocketParameterProgrammer.js.map +1 -1
  123. package/lib/generates/internal/SdkWebSocketRouteProgrammer.d.ts +2 -2
  124. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js +37 -41
  125. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js.map +1 -1
  126. package/lib/generates/internal/SwaggerOperationParameterComposer.js +10 -2
  127. package/lib/generates/internal/SwaggerOperationParameterComposer.js.map +1 -1
  128. package/lib/generates/internal/SwaggerOperationResponseComposer.d.ts +1 -1
  129. package/lib/generates/internal/SwaggerOperationResponseComposer.js +6 -1
  130. package/lib/generates/internal/SwaggerOperationResponseComposer.js.map +1 -1
  131. package/lib/generates/internal/SwaggerReadonlyArrayEmender.d.ts +9 -0
  132. package/lib/generates/internal/SwaggerReadonlyArrayEmender.js +174 -0
  133. package/lib/generates/internal/SwaggerReadonlyArrayEmender.js.map +1 -0
  134. package/lib/structures/INestiaSdkInput.d.ts +9 -2
  135. package/lib/structures/IReflectController.d.ts +2 -1
  136. package/lib/structures/IReflectHttpOperationSuccess.d.ts +4 -2
  137. package/lib/structures/IReflectMcpOperation.d.ts +35 -0
  138. package/lib/structures/IReflectMcpOperation.js +3 -0
  139. package/lib/structures/IReflectMcpOperation.js.map +1 -0
  140. package/lib/structures/IReflectMcpOperationParameter.d.ts +19 -0
  141. package/lib/structures/IReflectMcpOperationParameter.js +3 -0
  142. package/lib/structures/IReflectMcpOperationParameter.js.map +1 -0
  143. package/lib/structures/ITypedApplication.d.ts +2 -1
  144. package/lib/structures/ITypedHttpRouteSuccess.d.ts +3 -1
  145. package/lib/structures/ITypedMcpRoute.d.ts +31 -0
  146. package/lib/structures/ITypedMcpRoute.js +3 -0
  147. package/lib/structures/ITypedMcpRoute.js.map +1 -0
  148. package/lib/transform.d.ts +5 -9
  149. package/lib/transform.js +8 -31
  150. package/lib/transform.js.map +1 -1
  151. package/lib/utils/HttpResponseContentTypeUtil.d.ts +5 -0
  152. package/lib/utils/HttpResponseContentTypeUtil.js +22 -0
  153. package/lib/utils/HttpResponseContentTypeUtil.js.map +1 -0
  154. package/native/go.mod +52 -52
  155. package/native/go.sum +84 -54
  156. package/native/sdk/register.go +322 -165
  157. package/native/sdk/sdk.go +17 -17
  158. package/native/sdk/sdk_metadata_json.go +327 -327
  159. package/native/sdk/sdk_transform.go +1879 -1549
  160. package/package.json +13 -11
  161. package/src/INestiaConfig.ts +267 -267
  162. package/src/NestiaSdkApplication.ts +39 -8
  163. package/src/NestiaSwaggerComposer.ts +153 -142
  164. package/src/analyses/AccessorAnalyzer.ts +64 -67
  165. package/src/analyses/ConfigAnalyzer.ts +330 -330
  166. package/src/analyses/ImportAnalyzer.ts +92 -92
  167. package/src/analyses/PathAnalyzer.ts +130 -69
  168. package/src/analyses/ReflectControllerAnalyzer.ts +112 -105
  169. package/src/analyses/ReflectHttpOperationAnalyzer.ts +183 -183
  170. package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +90 -90
  171. package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +350 -350
  172. package/src/analyses/ReflectHttpOperationResponseAnalyzer.ts +163 -130
  173. package/src/analyses/ReflectMcpOperationAnalyzer.ts +124 -0
  174. package/src/analyses/ReflectMetadataAnalyzer.ts +44 -44
  175. package/src/analyses/SecurityAnalyzer.ts +25 -25
  176. package/src/analyses/TypedMcpRouteAnalyzer.ts +34 -0
  177. package/src/decorators/OperationMetadata.ts +29 -29
  178. package/src/executable/internal/CommandParser.ts +15 -15
  179. package/src/executable/internal/NestiaConfigLoader.ts +451 -446
  180. package/src/executable/internal/NestiaSdkCommand.ts +124 -106
  181. package/src/executable/internal/NestiaSdkWatcher.ts +342 -0
  182. package/src/executable/sdk.ts +90 -88
  183. package/src/factories/ExpressionFactory.ts +23 -0
  184. package/src/factories/IdentifierFactory.ts +84 -0
  185. package/src/factories/LiteralFactory.ts +54 -0
  186. package/src/factories/StatementFactory.ts +56 -0
  187. package/src/factories/TypeFactory.ts +27 -0
  188. package/src/generates/CloneGenerator.ts +74 -66
  189. package/src/generates/E2eGenerator.ts +32 -32
  190. package/src/generates/SdkGenerator.ts +176 -118
  191. package/src/generates/SwaggerGenerator.ts +342 -310
  192. package/src/generates/internal/E2eFileProgrammer.ts +246 -233
  193. package/src/generates/internal/FilePrinter.ts +57 -65
  194. package/src/generates/internal/ImportDictionary.ts +207 -204
  195. package/src/generates/internal/SdkAliasCollection.ts +280 -261
  196. package/src/generates/internal/SdkDistributionComposer.ts +123 -116
  197. package/src/generates/internal/SdkFileProgrammer.ts +113 -112
  198. package/src/generates/internal/SdkHttpCloneProgrammer.ts +124 -126
  199. package/src/generates/internal/SdkHttpCloneReferencer.ts +131 -77
  200. package/src/generates/internal/SdkHttpFunctionProgrammer.ts +290 -301
  201. package/src/generates/internal/SdkHttpNamespaceProgrammer.ts +507 -510
  202. package/src/generates/internal/SdkHttpParameterProgrammer.ts +163 -165
  203. package/src/generates/internal/SdkHttpRouteProgrammer.ts +109 -109
  204. package/src/generates/internal/SdkHttpSimulationProgrammer.ts +322 -314
  205. package/src/generates/internal/SdkImportWizard.ts +62 -62
  206. package/src/generates/internal/SdkMcpRouteProgrammer.ts +447 -0
  207. package/src/generates/internal/SdkRouteDirectory.ts +21 -18
  208. package/src/generates/internal/SdkTypeProgrammer.ts +389 -382
  209. package/src/generates/internal/SdkTypeTagProgrammer.ts +110 -114
  210. package/src/generates/internal/SdkWebSocketCloneProgrammer.ts +319 -0
  211. package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +383 -389
  212. package/src/generates/internal/SdkWebSocketParameterProgrammer.ts +91 -89
  213. package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +304 -323
  214. package/src/generates/internal/SwaggerDescriptionComposer.ts +64 -64
  215. package/src/generates/internal/SwaggerOperationComposer.ts +119 -119
  216. package/src/generates/internal/SwaggerOperationParameterComposer.ts +175 -162
  217. package/src/generates/internal/SwaggerOperationResponseComposer.ts +115 -110
  218. package/src/generates/internal/SwaggerReadonlyArrayEmender.ts +262 -0
  219. package/src/index.ts +4 -4
  220. package/src/internal/legacy.ts +492 -492
  221. package/src/module.ts +4 -4
  222. package/src/structures/INestiaProject.ts +10 -10
  223. package/src/structures/INestiaSdkInput.ts +27 -20
  224. package/src/structures/IOperationMetadata.ts +41 -41
  225. package/src/structures/IReflectController.ts +18 -15
  226. package/src/structures/IReflectHttpOperation.ts +26 -26
  227. package/src/structures/IReflectHttpOperationException.ts +18 -18
  228. package/src/structures/IReflectHttpOperationParameter.ts +79 -79
  229. package/src/structures/IReflectHttpOperationSuccess.ts +18 -21
  230. package/src/structures/IReflectImport.ts +6 -6
  231. package/src/structures/IReflectMcpOperation.ts +38 -0
  232. package/src/structures/IReflectMcpOperationParameter.ts +27 -0
  233. package/src/structures/IReflectOperationError.ts +26 -26
  234. package/src/structures/IReflectType.ts +4 -4
  235. package/src/structures/IReflectWebSocketOperation.ts +17 -17
  236. package/src/structures/ITypedApplication.ts +12 -11
  237. package/src/structures/ITypedHttpRoute.ts +41 -41
  238. package/src/structures/ITypedHttpRouteException.ts +15 -15
  239. package/src/structures/ITypedHttpRouteParameter.ts +41 -41
  240. package/src/structures/ITypedHttpRouteSuccess.ts +18 -22
  241. package/src/structures/ITypedMcpRoute.ts +33 -0
  242. package/src/structures/ITypedWebSocketRoute.ts +24 -24
  243. package/src/structures/ITypedWebSocketRouteParameter.ts +3 -3
  244. package/src/transform.ts +28 -59
  245. package/src/typings/get-function-location.d.ts +7 -7
  246. package/src/utils/ArrayUtil.ts +26 -26
  247. package/src/utils/EmittedJavaScriptPatcher.ts +88 -88
  248. package/src/utils/FileRetriever.ts +22 -22
  249. package/src/utils/HttpResponseContentTypeUtil.ts +30 -0
  250. package/src/utils/MapUtil.ts +14 -14
  251. package/src/utils/PathUtil.ts +10 -10
  252. package/src/utils/SourceFinder.ts +63 -63
  253. package/src/utils/StringUtil.ts +17 -17
  254. package/src/utils/TsConfigReader.ts +108 -108
  255. package/src/utils/TtscExecutor.ts +68 -68
  256. package/src/utils/VersioningStrategy.ts +28 -28
  257. package/src/validators/HttpHeadersValidator.ts +11 -11
  258. package/src/validators/HttpQueryValidator.ts +11 -11
  259. package/src/validators/TextPlainValidator.ts +17 -17
@@ -1,106 +1,124 @@
1
- import { INestiaConfig } from "../../INestiaConfig";
2
- import { NestiaSdkApplication } from "../../NestiaSdkApplication";
3
- import { NestiaConfigLoader } from "./NestiaConfigLoader";
4
-
5
- export namespace NestiaSdkCommand {
6
- export const sdk = () =>
7
- main({
8
- title: "SDK library",
9
- generate: (app) => app.sdk(),
10
- validate: (config) => !!config.output,
11
- solution: "configure INestiaConfig.output property.",
12
- });
13
-
14
- export const swagger = () =>
15
- main({
16
- title: "Swagger Document",
17
- generate: (app) => app.swagger(),
18
- validate: (config) => !!config.swagger?.output,
19
- solution: "configure INestiaConfig.swagger property.",
20
- });
21
-
22
- export const e2e = () =>
23
- main({
24
- title: "E2E Functions",
25
- generate: (app) => app.e2e(),
26
- validate: (config) => !!config.e2e,
27
- solution: [
28
- "configure two properties:",
29
- "",
30
- " - INestiaConfig.output",
31
- " - INestiaConfig.e2e",
32
- ].join("\n"),
33
- });
34
-
35
- export const all = () =>
36
- main({
37
- title: "everything",
38
- generate: (app) => app.all(),
39
- validate: () => true,
40
- solution: [
41
- "configure at least one property of below:",
42
- "",
43
- " - INestiaConfig.output",
44
- " - INestiaConfig.swagger.output",
45
- ].join("\n"),
46
- });
47
-
48
- const main = async (props: {
49
- title: string;
50
- solution: string;
51
- generate: (app: NestiaSdkApplication) => Promise<void>;
52
- validate: (config: INestiaConfig) => boolean;
53
- }) => {
54
- // LOAD CONFIG INFO
55
- const project: string =
56
- getFileArgument({
57
- type: "project",
58
- extension: "json",
59
- }) ?? "tsconfig.json";
60
- process.env.NESTIA_PROJECT = project;
61
- const command: NestiaConfigLoader.ICompilerOptions =
62
- await NestiaConfigLoader.compilerOptions(project);
63
-
64
- const configurations: INestiaConfig[] =
65
- await NestiaConfigLoader.configurations(
66
- getFileArgument({
67
- type: "config",
68
- extension: "ts",
69
- }) ?? "nestia.config.ts",
70
- command.raw.compilerOptions ?? {},
71
- );
72
-
73
- // GENERATE
74
- if (
75
- configurations.length > 1 &&
76
- configurations.some(props.validate) === false
77
- )
78
- throw new Error(
79
- `Every configurations are invalid to generate ${props.title}, ${props.solution}`,
80
- );
81
- for (const config of configurations) {
82
- if (configurations.length > 1 && props.validate(config) === false)
83
- continue;
84
- const app: NestiaSdkApplication = new NestiaSdkApplication(config);
85
- await props.generate(app);
86
- }
87
- };
88
-
89
- const getFileArgument = (props: {
90
- type: string;
91
- extension: string;
92
- }): string | null => {
93
- const argv: string[] = process.argv.slice(3);
94
- if (argv.length === 0) return null;
95
-
96
- const index: number = argv.findIndex((str) => str === `--${props.type}`);
97
- if (index === -1) return null;
98
- else if (argv.length === 1)
99
- throw new Error(`${props.type} file must be provided`);
100
-
101
- const file: string = argv[index + 1]!;
102
- if (file.endsWith(props.extension) === false)
103
- throw new Error(`${props.type} file must be ${props.extension} file`);
104
- return file;
105
- };
106
- }
1
+ import { INestiaConfig } from "../../INestiaConfig";
2
+ import { NestiaSdkApplication } from "../../NestiaSdkApplication";
3
+ import { NestiaConfigLoader } from "./NestiaConfigLoader";
4
+ import { NestiaSdkWatcher } from "./NestiaSdkWatcher";
5
+
6
+ export namespace NestiaSdkCommand {
7
+ export const sdk = () =>
8
+ main({
9
+ title: "SDK library",
10
+ generate: (app) => app.sdk(),
11
+ validate: (config) => !!config.output,
12
+ solution: "configure INestiaConfig.output property.",
13
+ });
14
+
15
+ export const swagger = () =>
16
+ main({
17
+ title: "Swagger Document",
18
+ generate: (app) => app.swagger(),
19
+ validate: (config) => !!config.swagger?.output,
20
+ solution: "configure INestiaConfig.swagger property.",
21
+ watch: hasFlagArgument("watch"),
22
+ });
23
+
24
+ export const e2e = () =>
25
+ main({
26
+ title: "E2E Functions",
27
+ generate: (app) => app.e2e(),
28
+ validate: (config) => !!config.e2e,
29
+ solution: [
30
+ "configure two properties:",
31
+ "",
32
+ " - INestiaConfig.output",
33
+ " - INestiaConfig.e2e",
34
+ ].join("\n"),
35
+ });
36
+
37
+ export const all = () =>
38
+ main({
39
+ title: "everything",
40
+ generate: (app) => app.all(),
41
+ validate: () => true,
42
+ solution: [
43
+ "configure at least one property of below:",
44
+ "",
45
+ " - INestiaConfig.output",
46
+ " - INestiaConfig.swagger.output",
47
+ ].join("\n"),
48
+ });
49
+
50
+ const main = async (props: {
51
+ title: string;
52
+ solution: string;
53
+ generate: (app: NestiaSdkApplication) => Promise<void>;
54
+ validate: (config: INestiaConfig) => boolean;
55
+ watch?: boolean;
56
+ }) => {
57
+ // LOAD CONFIG INFO
58
+ const project: string =
59
+ getFileArgument({
60
+ type: "project",
61
+ extension: "json",
62
+ }) ?? "tsconfig.json";
63
+ process.env.NESTIA_PROJECT = project;
64
+ const configFile: string =
65
+ getFileArgument({
66
+ type: "config",
67
+ extension: "ts",
68
+ }) ?? "nestia.config.ts";
69
+ const configurations = async (): Promise<INestiaConfig[]> => {
70
+ const command: NestiaConfigLoader.ICompilerOptions =
71
+ await NestiaConfigLoader.compilerOptions(project);
72
+ return NestiaConfigLoader.configurations(
73
+ configFile,
74
+ command.raw.compilerOptions ?? {},
75
+ );
76
+ };
77
+ const generate = async (configurations: INestiaConfig[]): Promise<void> => {
78
+ if (
79
+ configurations.length > 1 &&
80
+ configurations.some(props.validate) === false
81
+ )
82
+ throw new Error(
83
+ `Every configurations are invalid to generate ${props.title}, ${props.solution}`,
84
+ );
85
+ for (const config of configurations) {
86
+ if (configurations.length > 1 && props.validate(config) === false)
87
+ continue;
88
+ const app: NestiaSdkApplication = new NestiaSdkApplication(config);
89
+ await props.generate(app);
90
+ }
91
+ };
92
+
93
+ if (props.watch === true)
94
+ return NestiaSdkWatcher.watch({
95
+ configFile,
96
+ configurations,
97
+ generate,
98
+ projectFile: project,
99
+ });
100
+
101
+ await generate(await configurations());
102
+ };
103
+
104
+ const getFileArgument = (props: {
105
+ type: string;
106
+ extension: string;
107
+ }): string | null => {
108
+ const argv: string[] = process.argv.slice(3);
109
+ if (argv.length === 0) return null;
110
+
111
+ const index: number = argv.findIndex((str) => str === `--${props.type}`);
112
+ if (index === -1) return null;
113
+ else if (argv.length === 1)
114
+ throw new Error(`${props.type} file must be provided`);
115
+
116
+ const file: string = argv[index + 1]!;
117
+ if (file.endsWith(props.extension) === false)
118
+ throw new Error(`${props.type} file must be ${props.extension} file`);
119
+ return file;
120
+ };
121
+
122
+ const hasFlagArgument = (type: string): boolean =>
123
+ process.argv.slice(3).some((str) => str === `--${type}`);
124
+ }
@@ -0,0 +1,342 @@
1
+ import fs from "fs";
2
+ import { glob } from "glob";
3
+ import path from "path";
4
+
5
+ import { INestiaConfig } from "../../INestiaConfig";
6
+
7
+ export namespace NestiaSdkWatcher {
8
+ export interface IProps {
9
+ configFile: string;
10
+ configurations: () => Promise<INestiaConfig[]>;
11
+ generate: (configurations: INestiaConfig[]) => Promise<void>;
12
+ projectFile: string;
13
+ }
14
+
15
+ export const watch = async (props: IProps): Promise<void> => {
16
+ const session = new WatchSession(props);
17
+ session.registerSignals();
18
+ await session.regenerate("initial generation");
19
+ await new Promise<void>(() => {});
20
+ };
21
+ }
22
+
23
+ class WatchSession {
24
+ private readonly watchers: Map<string, fs.FSWatcher> = new Map();
25
+ private debounce: NodeJS.Timeout | null = null;
26
+ private ignored: string[] = [];
27
+ private pending: string | null = null;
28
+ private running: boolean = false;
29
+ private stopped: boolean = false;
30
+
31
+ public constructor(private readonly props: NestiaSdkWatcher.IProps) {}
32
+
33
+ public registerSignals(): void {
34
+ const stop = (): void => {
35
+ this.dispose();
36
+ process.exit(0);
37
+ };
38
+ process.once("SIGINT", stop);
39
+ process.once("SIGTERM", stop);
40
+ }
41
+
42
+ public async regenerate(reason: string): Promise<void> {
43
+ if (this.stopped) return;
44
+ if (this.running) {
45
+ this.pending = reason;
46
+ return;
47
+ }
48
+
49
+ this.running = true;
50
+ let nextReason: string | null = reason;
51
+ do {
52
+ const current: string = nextReason;
53
+ nextReason = null;
54
+ this.pending = null;
55
+ let configurations: INestiaConfig[] = [];
56
+ try {
57
+ if (current === "initial generation")
58
+ console.log("Starting nestia swagger watch mode");
59
+ else console.log(`Change detected (${current}); regenerating swagger`);
60
+
61
+ configurations = await this.props.configurations();
62
+ await this.props.generate(configurations);
63
+ await this.refresh(configurations);
64
+ console.log(
65
+ `Watching ${this.watchers.size} directories. Press Ctrl+C to stop.`,
66
+ );
67
+ } catch (error) {
68
+ await this.refresh(configurations);
69
+ console.error("Nestia swagger watch generation failed:");
70
+ printError(error);
71
+ }
72
+ nextReason = this.pending;
73
+ } while (nextReason !== null && !this.stopped);
74
+ this.running = false;
75
+ }
76
+
77
+ private schedule(reason: string): void {
78
+ if (this.stopped) return;
79
+ if (this.debounce !== null) clearTimeout(this.debounce);
80
+ this.debounce = setTimeout(() => {
81
+ this.debounce = null;
82
+ void this.regenerate(reason);
83
+ }, 250);
84
+ }
85
+
86
+ private async refresh(configurations: INestiaConfig[]): Promise<void> {
87
+ const next = await collectWatchPlan({
88
+ configurations,
89
+ configFile: this.props.configFile,
90
+ projectFile: this.props.projectFile,
91
+ });
92
+ this.ignored = next.ignored;
93
+
94
+ const directories: Set<string> = new Set();
95
+ for (const target of next.targets)
96
+ await collectDirectories({
97
+ directories,
98
+ ignored: next.ignored,
99
+ target,
100
+ });
101
+ this.sync(directories);
102
+ }
103
+
104
+ private sync(next: Set<string>): void {
105
+ for (const [directory, watcher] of this.watchers)
106
+ if (next.has(directory) === false) {
107
+ watcher.close();
108
+ this.watchers.delete(directory);
109
+ }
110
+
111
+ for (const directory of next) {
112
+ if (this.watchers.has(directory)) continue;
113
+ try {
114
+ const watcher = fs.watch(directory, (event, filename) => {
115
+ const target =
116
+ filename === null || filename === undefined
117
+ ? directory
118
+ : path.resolve(directory, String(filename));
119
+ if (shouldIgnore(target, this.ignored)) return;
120
+ if (shouldReact({ event, target }) === false) return;
121
+ this.schedule(relative(target));
122
+ });
123
+ watcher.on("error", () => {
124
+ watcher.close();
125
+ this.watchers.delete(directory);
126
+ this.schedule(relative(directory));
127
+ });
128
+ this.watchers.set(directory, watcher);
129
+ } catch {
130
+ continue;
131
+ }
132
+ }
133
+ }
134
+
135
+ private dispose(): void {
136
+ this.stopped = true;
137
+ if (this.debounce !== null) clearTimeout(this.debounce);
138
+ for (const watcher of this.watchers.values()) watcher.close();
139
+ this.watchers.clear();
140
+ }
141
+ }
142
+
143
+ interface IWatchPlan {
144
+ ignored: string[];
145
+ targets: string[];
146
+ }
147
+
148
+ const collectWatchPlan = async (props: {
149
+ configurations: INestiaConfig[];
150
+ configFile: string;
151
+ projectFile: string;
152
+ }): Promise<IWatchPlan> => {
153
+ const targets: Set<string> = new Set([
154
+ path.resolve(props.configFile),
155
+ path.resolve(props.projectFile),
156
+ ]);
157
+ const ignored: Set<string> = new Set([
158
+ path.resolve("node_modules"),
159
+ path.resolve(".git"),
160
+ ]);
161
+
162
+ for (const config of props.configurations) {
163
+ for (const target of await inputTargets(config.input)) targets.add(target);
164
+ for (const target of outputTargets(config)) ignored.add(target);
165
+ }
166
+ return {
167
+ ignored: [...ignored],
168
+ targets: [...targets],
169
+ };
170
+ };
171
+
172
+ const inputTargets = async (
173
+ input: INestiaConfig["input"],
174
+ ): Promise<string[]> => {
175
+ if (typeof input === "function") {
176
+ const fallback: string = path.resolve("src");
177
+ return [fs.existsSync(fallback) ? fallback : process.cwd()];
178
+ }
179
+
180
+ const patterns: string[] = Array.isArray(input)
181
+ ? input
182
+ : typeof input === "object"
183
+ ? input.include
184
+ : [input];
185
+ const output: Set<string> = new Set();
186
+ for (const pattern of patterns) {
187
+ for (const target of await patternTargets(pattern)) output.add(target);
188
+ }
189
+ return [...output];
190
+ };
191
+
192
+ const patternTargets = async (pattern: string): Promise<string[]> => {
193
+ const output: Set<string> = new Set();
194
+ const direct: string = path.resolve(pattern);
195
+ if (fs.existsSync(direct)) output.add(direct);
196
+
197
+ if (hasGlobMagic(pattern)) {
198
+ const root: string = staticRoot(pattern);
199
+ if (fs.existsSync(root)) output.add(root);
200
+ for (const match of await glob(pattern)) output.add(path.resolve(match));
201
+ }
202
+ return [...output];
203
+ };
204
+
205
+ const outputTargets = (config: INestiaConfig): string[] => {
206
+ const output: string[] = [];
207
+ for (const value of [config.output, config.e2e, config.distribute])
208
+ if (typeof value === "string") output.push(path.resolve(value));
209
+ if (config.swagger?.output !== undefined) {
210
+ const parsed: path.ParsedPath = path.parse(config.swagger.output);
211
+ output.push(
212
+ parsed.ext
213
+ ? path.resolve(config.swagger.output)
214
+ : path.resolve(config.swagger.output, "swagger.json"),
215
+ );
216
+ }
217
+ return output;
218
+ };
219
+
220
+ const collectDirectories = async (props: {
221
+ directories: Set<string>;
222
+ ignored: string[];
223
+ target: string;
224
+ }): Promise<void> => {
225
+ const stats: fs.Stats | null = await safeStat(props.target);
226
+ if (stats === null) return;
227
+ const root: string = stats.isDirectory()
228
+ ? props.target
229
+ : path.dirname(props.target);
230
+ await iterateDirectories({
231
+ directories: props.directories,
232
+ ignored: props.ignored,
233
+ root,
234
+ });
235
+ };
236
+
237
+ const iterateDirectories = async (props: {
238
+ directories: Set<string>;
239
+ ignored: string[];
240
+ root: string;
241
+ }): Promise<void> => {
242
+ const location: string = path.resolve(props.root);
243
+ if (shouldIgnore(location, props.ignored)) return;
244
+ props.directories.add(location);
245
+
246
+ let entries: fs.Dirent[];
247
+ try {
248
+ entries = await fs.promises.readdir(location, { withFileTypes: true });
249
+ } catch {
250
+ return;
251
+ }
252
+
253
+ for (const entry of entries) {
254
+ if (entry.isDirectory() === false) continue;
255
+ if (SKIPPED_DIRECTORIES.has(entry.name)) continue;
256
+ await iterateDirectories({
257
+ directories: props.directories,
258
+ ignored: props.ignored,
259
+ root: path.join(location, entry.name),
260
+ });
261
+ }
262
+ };
263
+
264
+ const safeStat = async (location: string): Promise<fs.Stats | null> => {
265
+ try {
266
+ return await fs.promises.stat(location);
267
+ } catch {
268
+ return null;
269
+ }
270
+ };
271
+
272
+ const shouldReact = (props: { event: string; target: string }): boolean => {
273
+ const ext: string = path.extname(props.target).toLowerCase();
274
+ if (SOURCE_EXTENSIONS.has(ext)) return true;
275
+ return props.event === "rename" && ext.length === 0;
276
+ };
277
+
278
+ const shouldIgnore = (location: string, ignored: string[]): boolean =>
279
+ ignored.some((elem) => isSameOrInside(location, elem));
280
+
281
+ const isSameOrInside = (child: string, parent: string): boolean => {
282
+ const left: string = comparable(child);
283
+ const right: string = comparable(parent);
284
+ return left === right || left.startsWith(`${right}${path.sep}`);
285
+ };
286
+
287
+ const comparable = (location: string): string => {
288
+ const resolved: string = path.resolve(location);
289
+ return process.platform === "win32" ? resolved.toLowerCase() : resolved;
290
+ };
291
+
292
+ const staticRoot = (pattern: string): string => {
293
+ const absolute: string = path.resolve(pattern);
294
+ const parsed: path.ParsedPath = path.parse(absolute);
295
+ const segments: string[] = absolute
296
+ .slice(parsed.root.length)
297
+ .split(/[\\/]+/)
298
+ .filter((segment) => segment.length !== 0);
299
+ const stable: string[] = [];
300
+ for (const segment of segments) {
301
+ if (hasGlobMagic(segment)) break;
302
+ stable.push(segment);
303
+ }
304
+ return stable.length === 0 ? parsed.root : path.join(parsed.root, ...stable);
305
+ };
306
+
307
+ const hasGlobMagic = (pattern: string): boolean => /[*?[\]{}]/.test(pattern);
308
+
309
+ const relative = (location: string): string => {
310
+ const output: string = path.relative(process.cwd(), location);
311
+ return output.length === 0 ? "." : output.split(path.sep).join("/");
312
+ };
313
+
314
+ const printError = (error: unknown): void => {
315
+ let current: unknown = error;
316
+ let depth: number = 0;
317
+ while (current !== undefined && current !== null && depth < 10) {
318
+ const message: string =
319
+ current instanceof Error ? current.message : String(current);
320
+ console.error(
321
+ `${" ".repeat(depth)}${depth === 0 ? "" : "caused by: "}${message}`,
322
+ );
323
+ if (current instanceof Error && current.cause !== undefined) {
324
+ current = current.cause;
325
+ ++depth;
326
+ } else break;
327
+ }
328
+ };
329
+
330
+ const SOURCE_EXTENSIONS: Set<string> = new Set([
331
+ ".cts",
332
+ ".json",
333
+ ".mts",
334
+ ".ts",
335
+ ".tsx",
336
+ ]);
337
+
338
+ const SKIPPED_DIRECTORIES: Set<string> = new Set([
339
+ ".git",
340
+ ".nestia",
341
+ "node_modules",
342
+ ]);