@nestia/sdk 11.2.1 → 12.0.0-dev.20260520.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 (270) hide show
  1. package/assets/bundle/distribute/package.json +1 -1
  2. package/lib/NestiaSdkApplication.js +5 -4
  3. package/lib/NestiaSdkApplication.js.map +1 -1
  4. package/lib/NestiaSwaggerComposer.js +2 -2
  5. package/lib/NestiaSwaggerComposer.js.map +1 -1
  6. package/lib/analyses/AccessorAnalyzer.js.map +1 -1
  7. package/lib/analyses/ConfigAnalyzer.js +133 -7
  8. package/lib/analyses/ConfigAnalyzer.js.map +1 -1
  9. package/lib/analyses/ImportAnalyzer.d.ts +9 -2
  10. package/lib/analyses/ImportAnalyzer.js +13 -50
  11. package/lib/analyses/ImportAnalyzer.js.map +1 -1
  12. package/lib/analyses/PathAnalyzer.js.map +1 -1
  13. package/lib/analyses/ReflectControllerAnalyzer.js.map +1 -1
  14. package/lib/analyses/ReflectHttpOperationAnalyzer.d.ts +1 -1
  15. package/lib/analyses/ReflectHttpOperationAnalyzer.js +5 -4
  16. package/lib/analyses/ReflectHttpOperationAnalyzer.js.map +1 -1
  17. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.d.ts +1 -1
  18. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.js +22 -5
  19. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.js.map +1 -1
  20. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.d.ts +1 -1
  21. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js +8 -8
  22. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js.map +1 -1
  23. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.d.ts +1 -1
  24. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js +15 -15
  25. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js.map +1 -1
  26. package/lib/analyses/ReflectMetadataAnalyzer.js.map +1 -1
  27. package/lib/analyses/ReflectWebSocketOperationAnalyzer.d.ts +1 -1
  28. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js +1 -1
  29. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js.map +1 -1
  30. package/lib/analyses/SecurityAnalyzer.js.map +1 -1
  31. package/lib/analyses/TypedHttpRouteAnalyzer.d.ts +2 -1
  32. package/lib/analyses/TypedHttpRouteAnalyzer.js +296 -39
  33. package/lib/analyses/TypedHttpRouteAnalyzer.js.map +1 -1
  34. package/lib/analyses/TypedWebSocketRouteAnalyzer.js +1 -4
  35. package/lib/analyses/TypedWebSocketRouteAnalyzer.js.map +1 -1
  36. package/lib/decorators/OperationMetadata.d.ts +1 -1
  37. package/lib/decorators/OperationMetadata.js.map +1 -1
  38. package/lib/executable/internal/CommandParser.js.map +1 -1
  39. package/lib/executable/internal/NestiaConfigLoader.d.ts +6 -2
  40. package/lib/executable/internal/NestiaConfigLoader.js +285 -793
  41. package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
  42. package/lib/executable/internal/NestiaSdkCommand.js +6 -4
  43. package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
  44. package/lib/executable/sdk.js +17 -5
  45. package/lib/executable/sdk.js.map +1 -1
  46. package/lib/generates/CloneGenerator.js +2 -2
  47. package/lib/generates/CloneGenerator.js.map +1 -1
  48. package/lib/generates/E2eGenerator.js.map +1 -1
  49. package/lib/generates/SdkGenerator.js +6 -9
  50. package/lib/generates/SdkGenerator.js.map +1 -1
  51. package/lib/generates/SwaggerGenerator.js +20 -107
  52. package/lib/generates/SwaggerGenerator.js.map +1 -1
  53. package/lib/generates/internal/E2eFileProgrammer.js +44 -28
  54. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  55. package/lib/generates/internal/FilePrinter.d.ts +4 -4
  56. package/lib/generates/internal/FilePrinter.js +25 -16
  57. package/lib/generates/internal/FilePrinter.js.map +1 -1
  58. package/lib/generates/internal/ImportDictionary.d.ts +2 -2
  59. package/lib/generates/internal/ImportDictionary.js +7 -5
  60. package/lib/generates/internal/ImportDictionary.js.map +1 -1
  61. package/lib/generates/internal/SdkAliasCollection.d.ts +11 -11
  62. package/lib/generates/internal/SdkAliasCollection.js +27 -31
  63. package/lib/generates/internal/SdkAliasCollection.js.map +1 -1
  64. package/lib/generates/internal/SdkDistributionComposer.js +15 -70
  65. package/lib/generates/internal/SdkDistributionComposer.js.map +1 -1
  66. package/lib/generates/internal/SdkFileProgrammer.js +2 -2
  67. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  68. package/lib/generates/internal/SdkHttpCloneProgrammer.d.ts +2 -2
  69. package/lib/generates/internal/SdkHttpCloneProgrammer.js +6 -12
  70. package/lib/generates/internal/SdkHttpCloneProgrammer.js.map +1 -1
  71. package/lib/generates/internal/SdkHttpCloneReferencer.js +2 -1
  72. package/lib/generates/internal/SdkHttpCloneReferencer.js.map +1 -1
  73. package/lib/generates/internal/SdkHttpFunctionProgrammer.d.ts +2 -2
  74. package/lib/generates/internal/SdkHttpFunctionProgrammer.js +73 -77
  75. package/lib/generates/internal/SdkHttpFunctionProgrammer.js.map +1 -1
  76. package/lib/generates/internal/SdkHttpNamespaceProgrammer.d.ts +2 -2
  77. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js +64 -66
  78. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js.map +1 -1
  79. package/lib/generates/internal/SdkHttpParameterProgrammer.d.ts +4 -10
  80. package/lib/generates/internal/SdkHttpParameterProgrammer.js +15 -22
  81. package/lib/generates/internal/SdkHttpParameterProgrammer.js.map +1 -1
  82. package/lib/generates/internal/SdkHttpRouteProgrammer.d.ts +2 -2
  83. package/lib/generates/internal/SdkHttpRouteProgrammer.js +18 -20
  84. package/lib/generates/internal/SdkHttpRouteProgrammer.js.map +1 -1
  85. package/lib/generates/internal/SdkHttpSimulationProgrammer.d.ts +3 -3
  86. package/lib/generates/internal/SdkHttpSimulationProgrammer.js +47 -49
  87. package/lib/generates/internal/SdkHttpSimulationProgrammer.js.map +1 -1
  88. package/lib/generates/internal/SdkImportWizard.js.map +1 -1
  89. package/lib/generates/internal/SdkRouteDirectory.js.map +1 -1
  90. package/lib/generates/internal/SdkTypeProgrammer.d.ts +4 -4
  91. package/lib/generates/internal/SdkTypeProgrammer.js +66 -67
  92. package/lib/generates/internal/SdkTypeProgrammer.js.map +1 -1
  93. package/lib/generates/internal/SdkTypeTagProgrammer.d.ts +1 -2
  94. package/lib/generates/internal/SdkTypeTagProgrammer.js +29 -11
  95. package/lib/generates/internal/SdkTypeTagProgrammer.js.map +1 -1
  96. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.d.ts +2 -2
  97. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js +55 -55
  98. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js.map +1 -1
  99. package/lib/generates/internal/SdkWebSocketParameterProgrammer.d.ts +3 -3
  100. package/lib/generates/internal/SdkWebSocketParameterProgrammer.js +9 -12
  101. package/lib/generates/internal/SdkWebSocketParameterProgrammer.js.map +1 -1
  102. package/lib/generates/internal/SdkWebSocketRouteProgrammer.d.ts +2 -2
  103. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js +43 -45
  104. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js.map +1 -1
  105. package/lib/generates/internal/SwaggerDescriptionComposer.js.map +1 -1
  106. package/lib/generates/internal/SwaggerOperationComposer.d.ts +1 -1
  107. package/lib/generates/internal/SwaggerOperationComposer.js +5 -4
  108. package/lib/generates/internal/SwaggerOperationComposer.js.map +1 -1
  109. package/lib/generates/internal/SwaggerOperationParameterComposer.d.ts +0 -3
  110. package/lib/generates/internal/SwaggerOperationParameterComposer.js +19 -20
  111. package/lib/generates/internal/SwaggerOperationParameterComposer.js.map +1 -1
  112. package/lib/generates/internal/SwaggerOperationResponseComposer.d.ts +1 -1
  113. package/lib/generates/internal/SwaggerOperationResponseComposer.js +4 -3
  114. package/lib/generates/internal/SwaggerOperationResponseComposer.js.map +1 -1
  115. package/lib/index.js.map +1 -1
  116. package/lib/internal/legacy.d.ts +180 -0
  117. package/lib/internal/legacy.js +361 -0
  118. package/lib/internal/legacy.js.map +1 -0
  119. package/lib/structures/INestiaProject.d.ts +0 -2
  120. package/lib/{transformers → structures}/IOperationMetadata.d.ts +2 -7
  121. package/lib/structures/IOperationMetadata.js.map +1 -0
  122. package/lib/structures/IReflectHttpOperationException.d.ts +1 -1
  123. package/lib/structures/IReflectHttpOperationParameter.d.ts +1 -1
  124. package/lib/structures/IReflectHttpOperationSuccess.d.ts +1 -1
  125. package/lib/structures/IReflectOperationError.d.ts +1 -1
  126. package/lib/structures/IReflectOperationError.js.map +1 -1
  127. package/lib/structures/IReflectWebSocketOperation.d.ts +2 -2
  128. package/lib/structures/ITypedApplication.d.ts +1 -1
  129. package/lib/structures/ITypedHttpRouteException.d.ts +1 -1
  130. package/lib/structures/ITypedHttpRouteParameter.d.ts +1 -1
  131. package/lib/structures/ITypedHttpRouteSuccess.d.ts +1 -1
  132. package/lib/structures/ITypedWebSocketRoute.d.ts +2 -2
  133. package/lib/transform.d.ts +9 -3
  134. package/lib/transform.js +47 -5
  135. package/lib/transform.js.map +1 -1
  136. package/lib/utils/ArrayUtil.js.map +1 -1
  137. package/lib/utils/FileRetriever.js.map +1 -1
  138. package/lib/utils/MapUtil.js.map +1 -1
  139. package/lib/utils/PathUtil.js.map +1 -1
  140. package/lib/utils/SourceFinder.js.map +1 -1
  141. package/lib/utils/StringUtil.js.map +1 -1
  142. package/lib/utils/TsConfigReader.d.ts +7 -0
  143. package/lib/utils/TsConfigReader.js +102 -0
  144. package/lib/utils/TsConfigReader.js.map +1 -0
  145. package/lib/utils/TtscExecutor.d.ts +8 -0
  146. package/lib/utils/TtscExecutor.js +58 -0
  147. package/lib/utils/TtscExecutor.js.map +1 -0
  148. package/lib/utils/VersioningStrategy.js.map +1 -1
  149. package/lib/validators/HttpHeadersValidator.d.ts +8 -5
  150. package/lib/validators/HttpHeadersValidator.js +7 -26
  151. package/lib/validators/HttpHeadersValidator.js.map +1 -1
  152. package/lib/validators/HttpQueryValidator.d.ts +8 -5
  153. package/lib/validators/HttpQueryValidator.js +7 -26
  154. package/lib/validators/HttpQueryValidator.js.map +1 -1
  155. package/lib/{transformers → validators}/TextPlainValidator.d.ts +1 -1
  156. package/lib/{transformers → validators}/TextPlainValidator.js +2 -1
  157. package/lib/validators/TextPlainValidator.js.map +1 -0
  158. package/package.json +21 -19
  159. package/src/NestiaSdkApplication.ts +9 -5
  160. package/src/NestiaSwaggerComposer.ts +2 -3
  161. package/src/analyses/ConfigAnalyzer.ts +175 -1
  162. package/src/analyses/ImportAnalyzer.ts +15 -49
  163. package/src/analyses/ReflectControllerAnalyzer.ts +1 -1
  164. package/src/analyses/ReflectHttpOperationAnalyzer.ts +1 -1
  165. package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +24 -6
  166. package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +3 -3
  167. package/src/analyses/ReflectHttpOperationResponseAnalyzer.ts +14 -10
  168. package/src/analyses/ReflectWebSocketOperationAnalyzer.ts +2 -2
  169. package/src/analyses/TypedHttpRouteAnalyzer.ts +354 -22
  170. package/src/decorators/OperationMetadata.ts +1 -1
  171. package/src/executable/internal/NestiaConfigLoader.ts +419 -53
  172. package/src/executable/internal/NestiaSdkCommand.ts +9 -10
  173. package/src/executable/sdk.ts +15 -4
  174. package/src/generates/CloneGenerator.ts +10 -10
  175. package/src/generates/SwaggerGenerator.ts +28 -9
  176. package/src/generates/internal/E2eFileProgrammer.ts +80 -43
  177. package/src/generates/internal/FilePrinter.ts +38 -37
  178. package/src/generates/internal/ImportDictionary.ts +18 -16
  179. package/src/generates/internal/SdkAliasCollection.ts +41 -40
  180. package/src/generates/internal/SdkDistributionComposer.ts +21 -8
  181. package/src/generates/internal/SdkFileProgrammer.ts +7 -5
  182. package/src/generates/internal/SdkHttpCloneProgrammer.ts +10 -10
  183. package/src/generates/internal/SdkHttpCloneReferencer.ts +6 -6
  184. package/src/generates/internal/SdkHttpFunctionProgrammer.ts +101 -78
  185. package/src/generates/internal/SdkHttpNamespaceProgrammer.ts +153 -145
  186. package/src/generates/internal/SdkHttpParameterProgrammer.ts +20 -33
  187. package/src/generates/internal/SdkHttpRouteProgrammer.ts +2 -2
  188. package/src/generates/internal/SdkHttpSimulationProgrammer.ts +88 -86
  189. package/src/generates/internal/SdkTypeProgrammer.ts +93 -99
  190. package/src/generates/internal/SdkTypeTagProgrammer.ts +12 -12
  191. package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +128 -118
  192. package/src/generates/internal/SdkWebSocketParameterProgrammer.ts +15 -13
  193. package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +133 -112
  194. package/src/generates/internal/SwaggerOperationComposer.ts +1 -1
  195. package/src/generates/internal/SwaggerOperationParameterComposer.ts +10 -9
  196. package/src/generates/internal/SwaggerOperationResponseComposer.ts +1 -1
  197. package/src/internal/legacy.ts +492 -0
  198. package/src/structures/INestiaProject.ts +0 -3
  199. package/src/{transformers → structures}/IOperationMetadata.ts +2 -7
  200. package/src/structures/IReflectHttpOperationException.ts +1 -1
  201. package/src/structures/IReflectHttpOperationParameter.ts +1 -1
  202. package/src/structures/IReflectHttpOperationSuccess.ts +1 -1
  203. package/src/structures/IReflectOperationError.ts +1 -1
  204. package/src/structures/IReflectWebSocketOperation.ts +2 -2
  205. package/src/structures/ITypedApplication.ts +1 -1
  206. package/src/structures/ITypedHttpRouteException.ts +1 -1
  207. package/src/structures/ITypedHttpRouteParameter.ts +1 -1
  208. package/src/structures/ITypedHttpRouteSuccess.ts +1 -1
  209. package/src/structures/ITypedWebSocketRoute.ts +2 -2
  210. package/src/transform.ts +68 -7
  211. package/src/utils/TsConfigReader.ts +108 -0
  212. package/src/utils/TtscExecutor.ts +63 -0
  213. package/src/validators/HttpHeadersValidator.ts +8 -37
  214. package/src/validators/HttpQueryValidator.ts +8 -37
  215. package/src/{transformers → validators}/TextPlainValidator.ts +2 -2
  216. package/lib/analyses/DtoAnalyzer.d.ts +0 -21
  217. package/lib/analyses/DtoAnalyzer.js +0 -219
  218. package/lib/analyses/DtoAnalyzer.js.map +0 -1
  219. package/lib/analyses/ExceptionAnalyzer.d.ts +0 -0
  220. package/lib/analyses/ExceptionAnalyzer.js +0 -2
  221. package/lib/analyses/ExceptionAnalyzer.js.map +0 -1
  222. package/lib/analyses/GenericAnalyzer.d.ts +0 -4
  223. package/lib/analyses/GenericAnalyzer.js +0 -42
  224. package/lib/analyses/GenericAnalyzer.js.map +0 -1
  225. package/lib/structures/IReflectApplication.d.ts +0 -6
  226. package/lib/structures/IReflectApplication.js +0 -3
  227. package/lib/structures/IReflectApplication.js.map +0 -1
  228. package/lib/structures/MethodType.d.ts +0 -4
  229. package/lib/structures/MethodType.js +0 -8
  230. package/lib/structures/MethodType.js.map +0 -1
  231. package/lib/structures/ParamCategory.d.ts +0 -1
  232. package/lib/structures/ParamCategory.js +0 -3
  233. package/lib/structures/ParamCategory.js.map +0 -1
  234. package/lib/structures/TypeEntry.d.ts +0 -9
  235. package/lib/structures/TypeEntry.js +0 -21
  236. package/lib/structures/TypeEntry.js.map +0 -1
  237. package/lib/transformers/IOperationMetadata.js.map +0 -1
  238. package/lib/transformers/ISdkOperationTransformerContext.d.ts +0 -7
  239. package/lib/transformers/ISdkOperationTransformerContext.js +0 -3
  240. package/lib/transformers/ISdkOperationTransformerContext.js.map +0 -1
  241. package/lib/transformers/SdkOperationProgrammer.d.ts +0 -15
  242. package/lib/transformers/SdkOperationProgrammer.js +0 -186
  243. package/lib/transformers/SdkOperationProgrammer.js.map +0 -1
  244. package/lib/transformers/SdkOperationTransformer.d.ts +0 -4
  245. package/lib/transformers/SdkOperationTransformer.js +0 -128
  246. package/lib/transformers/SdkOperationTransformer.js.map +0 -1
  247. package/lib/transformers/TextPlainValidator.js.map +0 -1
  248. package/lib/utils/MetadataUtil.d.ts +0 -4
  249. package/lib/utils/MetadataUtil.js +0 -34
  250. package/lib/utils/MetadataUtil.js.map +0 -1
  251. package/lib/utils/StripEnums.d.ts +0 -3
  252. package/lib/utils/StripEnums.js +0 -3
  253. package/lib/utils/StripEnums.js.map +0 -1
  254. package/lib/utils/TypeLiteralExpression.d.ts +0 -0
  255. package/lib/utils/TypeLiteralExpression.js +0 -2
  256. package/lib/utils/TypeLiteralExpression.js.map +0 -1
  257. package/src/analyses/DtoAnalyzer.ts +0 -260
  258. package/src/analyses/ExceptionAnalyzer.ts +0 -154
  259. package/src/analyses/GenericAnalyzer.ts +0 -49
  260. package/src/structures/IReflectApplication.ts +0 -8
  261. package/src/structures/MethodType.ts +0 -5
  262. package/src/structures/ParamCategory.ts +0 -1
  263. package/src/structures/TypeEntry.ts +0 -22
  264. package/src/transformers/ISdkOperationTransformerContext.ts +0 -8
  265. package/src/transformers/SdkOperationProgrammer.ts +0 -240
  266. package/src/transformers/SdkOperationTransformer.ts +0 -248
  267. package/src/utils/MetadataUtil.ts +0 -26
  268. package/src/utils/StripEnums.ts +0 -5
  269. package/src/utils/TypeLiteralExpression.ts +0 -0
  270. /package/lib/{transformers → structures}/IOperationMetadata.js +0 -0
@@ -1,34 +1,33 @@
1
1
  import { doNotThrowTransformError } from "@nestia/core";
2
2
  import fs from "fs";
3
3
  import path from "path";
4
- import { register } from "ts-node";
5
- import { parse } from "tsconfck";
6
- import ts from "typescript";
7
- import typia from "typia";
4
+ import { pathToFileURL } from "url";
8
5
 
9
6
  import { INestiaConfig } from "../../INestiaConfig";
7
+ import { TsConfigReader } from "../../utils/TsConfigReader";
8
+ import { TtscExecutor } from "../../utils/TtscExecutor";
10
9
 
11
10
  export namespace NestiaConfigLoader {
11
+ export interface ICompilerOptions {
12
+ raw: {
13
+ compilerOptions?: Record<string, any>;
14
+ };
15
+ }
16
+
12
17
  export const compilerOptions = async (
13
18
  project: string,
14
- ): Promise<ts.ParsedCommandLine> => {
15
- const configFileName = ts.findConfigFile(
16
- process.cwd(),
17
- ts.sys.fileExists,
18
- project,
19
- );
19
+ ): Promise<ICompilerOptions> => {
20
+ const configFileName = findConfigFile(process.cwd(), project);
20
21
  if (!configFileName) throw new Error(`unable to find "${project}" file.`);
21
- const { tsconfig } = await parse(configFileName);
22
- const configFileText = JSON.stringify(tsconfig);
23
- const { config } = ts.parseConfigFileTextToJson(
24
- configFileName,
25
- configFileText,
26
- );
27
- return ts.parseJsonConfigFileContent(
28
- config,
29
- ts.sys,
30
- path.dirname(configFileName),
31
- );
22
+ const tsconfig = await TsConfigReader.read(configFileName);
23
+ return {
24
+ raw: {
25
+ compilerOptions:
26
+ typeof tsconfig?.compilerOptions === "object"
27
+ ? (tsconfig.compilerOptions as Record<string, any>)
28
+ : {},
29
+ },
30
+ };
32
31
  };
33
32
 
34
33
  export const configurations = async (
@@ -38,45 +37,412 @@ export namespace NestiaConfigLoader {
38
37
  if (fs.existsSync(path.resolve(file)) === false)
39
38
  throw new Error(`Unable to find "${file}" file.`);
40
39
 
41
- doNotThrowTransformError(true);
40
+ doNotThrowTransformError(false);
42
41
 
43
- const setup: boolean = typia
44
- .assert<object[]>(compilerOptions.plugins ?? [])
45
- .some((x: any) => x.transform === "@nestia/sdk/lib/transform");
46
- const plugins: any[] = [
47
- ...(compilerOptions.plugins ?? []),
48
- ...(setup ? [] : [{ transform: "@nestia/sdk/lib/transform" }]),
49
- ];
50
- const hasPathAliases = Object.keys(compilerOptions.paths ?? {}).length > 0;
51
- if (!(process as any)[Symbol.for("ts-node.register.instance")])
52
- register({
53
- emit: false,
54
- compilerOptions: {
55
- ...compilerOptions,
56
- plugins,
57
- },
58
- require: (compilerOptions.baseUrl || hasPathAliases)
59
- ? ["tsconfig-paths/register"]
60
- : undefined,
61
- });
42
+ if (compilerOptions.plugins !== undefined)
43
+ assertPlugins(file, compilerOptions.plugins);
62
44
 
63
- const loaded: (INestiaConfig | INestiaConfig[]) & {
64
- default?: INestiaConfig | INestiaConfig[];
65
- } = await import(path.resolve(file));
66
- const instance: INestiaConfig | INestiaConfig[] =
67
- typeof loaded?.default === "object" && loaded.default !== null
68
- ? loaded.default
69
- : loaded;
45
+ const configFile: string = await materializeConfiguration({
46
+ file,
47
+ compilerOptions,
48
+ });
49
+ const loaded: unknown = await loadMaterializedModule(configFile);
50
+ const instance: INestiaConfig | INestiaConfig[] = extractConfiguration(
51
+ file,
52
+ loaded,
53
+ );
70
54
  const configurations: INestiaConfig[] = Array.isArray(instance)
71
55
  ? instance
72
56
  : [instance];
73
57
 
58
+ return assertConfigurations(file, configurations);
59
+ };
60
+
61
+ const MATERIALIZED_ROOTS: Set<string> = new Set();
62
+ let CLEANUP_REGISTERED: boolean = false;
63
+
64
+ const materializeConfiguration = async (props: {
65
+ file: string;
66
+ compilerOptions: Record<string, any>;
67
+ }): Promise<string> => {
68
+ const configFile: string = path.resolve(props.file);
69
+ const project: string = process.env.NESTIA_PROJECT ?? "tsconfig.json";
70
+ const projectFile: string | undefined = findConfigFile(
71
+ process.cwd(),
72
+ project,
73
+ );
74
+ if (projectFile === undefined)
75
+ throw new Error(`unable to find "${project}" file.`);
76
+
77
+ const projectRoot: string = path.dirname(path.resolve(projectFile));
78
+ const wrapperRoot: string = fs.mkdtempSync(
79
+ path.join(ensureMaterializedRoot(projectRoot), "tsconfig-"),
80
+ );
81
+ const outputRoot: string = fs.mkdtempSync(
82
+ path.join(ensureMaterializedRoot(projectRoot), "run-"),
83
+ );
84
+ const wrapperFile: string = path.join(wrapperRoot, "tsconfig.json");
85
+ const wrapperConfig = {
86
+ extends: projectFile,
87
+ compilerOptions: {
88
+ noEmit: false,
89
+ noUnusedLocals: false,
90
+ noUnusedParameters: false,
91
+ ...nodeAmbientCompilerOptions(projectRoot, props.compilerOptions),
92
+ outDir: outputRoot,
93
+ plugins: materializePlugins(props.compilerOptions.plugins),
94
+ rootDir: projectRoot,
95
+ },
96
+ include: [configFile],
97
+ exclude: [path.join(projectRoot, "src", "test", "**", "*")],
98
+ };
99
+ fs.writeFileSync(
100
+ wrapperFile,
101
+ JSON.stringify(wrapperConfig, null, 2),
102
+ "utf8",
103
+ );
104
+
74
105
  try {
75
- return typia.assert(configurations);
76
- } catch (exp) {
77
- if (typia.is<typia.TypeGuardError>(exp))
78
- exp.message = `invalid "${file}" data.`;
79
- throw exp;
106
+ TtscExecutor.run({
107
+ cwd: projectRoot,
108
+ project: wrapperFile,
109
+ });
110
+ } catch (error) {
111
+ const stderr: string = readChildOutput(error, "stderr");
112
+ const stdout: string = readChildOutput(error, "stdout");
113
+ const detail: string = stderr || stdout;
114
+ const cause: Error =
115
+ error instanceof Error ? error : new Error(String(error));
116
+ const status: number | string | undefined =
117
+ (cause as { status?: number }).status ??
118
+ (cause as NodeJS.ErrnoException).code;
119
+ throw new Error(
120
+ detail
121
+ ? `failed to compile "${props.file}" through ttsc:\n${detail}`
122
+ : `failed to compile "${props.file}" through ttsc (exit code ${status ?? "unknown"}). Run \`npx ttsc -p ${projectFile}\` to see the underlying diagnostics.`,
123
+ { cause },
124
+ );
125
+ } finally {
126
+ fs.rmSync(wrapperRoot, { force: true, recursive: true });
127
+ }
128
+
129
+ const configKey: string = emittedJavaScriptKey(projectRoot, configFile);
130
+ const next: string = path.join(outputRoot, configKey);
131
+ if (fs.existsSync(next) === false)
132
+ throw new Error(
133
+ `failed to materialize "${props.file}" through ttsc native transform.`,
134
+ );
135
+ return next;
136
+ };
137
+
138
+ const ensureMaterializedRoot = (projectRoot: string): string => {
139
+ const root: string = path.join(
140
+ projectRoot,
141
+ "node_modules",
142
+ ".nestia",
143
+ "config-loader",
144
+ );
145
+ fs.mkdirSync(root, { recursive: true });
146
+ MATERIALIZED_ROOTS.add(root);
147
+ if (CLEANUP_REGISTERED === false) {
148
+ CLEANUP_REGISTERED = true;
149
+ const sweep = (): void => {
150
+ for (const location of MATERIALIZED_ROOTS)
151
+ fs.rmSync(location, { force: true, recursive: true });
152
+ };
153
+ process.once("exit", sweep);
154
+ // process.once("exit", …) does not fire on SIGINT/SIGTERM. Without
155
+ // these handlers a Ctrl-C during codegen leaves `run-*` and
156
+ // `tsconfig-*` mkdtempSync directories behind under
157
+ // node_modules/.nestia/config-loader/ until a subsequent clean exit.
158
+ // The module-level CLEANUP_REGISTERED flag above guards against
159
+ // re-entrancy within this module; we deliberately do NOT gate on
160
+ // `process.listenerCount(signal) > 0` because the parallel sweep in
161
+ // `ConfigAnalyzer.ensureRuntimeCleanup` (or any user-app SIGINT
162
+ // handler) could register first, and that gate would skip our
163
+ // registration — leaving MATERIALIZED_ROOTS unswept on Ctrl-C.
164
+ // Windows note: `process.kill(pid, "SIGINT")` calls TerminateProcess
165
+ // rather than re-raising; whichever module registers FIRST runs its
166
+ // sweep, the second is skipped, RUNTIME/MATERIALIZED cleanup is
167
+ // best-effort on Windows. SIGHUP is a no-op for most common code
168
+ // paths on Windows (Node fires it on console-close and exits within
169
+ // seconds).
170
+ const onSignal = (signal: NodeJS.Signals): void => {
171
+ sweep();
172
+ process.kill(process.pid, signal);
173
+ };
174
+ for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"] as const) {
175
+ process.once(signal, onSignal);
176
+ }
177
+ }
178
+ return root;
179
+ };
180
+
181
+ const emittedJavaScriptKey = (projectRoot: string, file: string): string => {
182
+ const relative: string = path.relative(projectRoot, file);
183
+ const extension: string = path.extname(relative).toLowerCase();
184
+ const emitted: string =
185
+ extension === ".mts" ? ".mjs" : extension === ".cts" ? ".cjs" : ".js";
186
+ return path
187
+ .join(
188
+ path.dirname(relative),
189
+ `${path.basename(relative, extension)}${emitted}`,
190
+ )
191
+ .split(path.sep)
192
+ .join(path.posix.sep);
193
+ };
194
+
195
+ const nodeAmbientCompilerOptions = (
196
+ projectRoot: string,
197
+ compilerOptions: Record<string, any>,
198
+ ): { typeRoots?: string[]; types: string[] } => {
199
+ const typeRoots: string[] = uniqueStrings([
200
+ ...asStringArray(compilerOptions.typeRoots),
201
+ ...resolveNodeTypeRoots(projectRoot),
202
+ ]);
203
+ const types: string[] = uniqueStrings([
204
+ "node",
205
+ ...asStringArray(compilerOptions.types).filter((value) => value !== "*"),
206
+ ]);
207
+ return {
208
+ ...(typeRoots.length !== 0 ? { typeRoots } : {}),
209
+ types,
210
+ };
211
+ };
212
+
213
+ const resolveNodeTypeRoots = (projectRoot: string): string[] => {
214
+ const roots: string[] = [];
215
+ for (const base of [projectRoot, process.cwd(), __dirname])
216
+ try {
217
+ const location: string = require.resolve("@types/node/package.json", {
218
+ paths: [base],
219
+ });
220
+ roots.push(path.dirname(path.dirname(location)));
221
+ } catch {
222
+ continue;
223
+ }
224
+ return roots;
225
+ };
226
+
227
+ const asStringArray = (input: unknown): string[] =>
228
+ Array.isArray(input)
229
+ ? input.filter((elem): elem is string => typeof elem === "string")
230
+ : [];
231
+
232
+ const uniqueStrings = (input: string[]): string[] => [...new Set(input)];
233
+
234
+ type MaterializePlugin = Record<string, unknown> & { transform?: unknown };
235
+
236
+ const materializePlugins = (input: unknown): MaterializePlugin[] => {
237
+ const plugins: MaterializePlugin[] = Array.isArray(input)
238
+ ? input
239
+ .filter((p) => typeof p === "object" && p !== null)
240
+ .map((p) => ({ ...(p as MaterializePlugin) }))
241
+ : [];
242
+ const typia: MaterializePlugin | undefined = plugins.find((p) =>
243
+ isTransform(p, "typia"),
244
+ );
245
+ const sdk: MaterializePlugin | undefined = plugins.find((p) =>
246
+ isTransform(p, "@nestia/sdk"),
247
+ );
248
+ const core: MaterializePlugin | undefined = plugins.find((p) =>
249
+ isTransform(p, "@nestia/core"),
250
+ );
251
+ return [
252
+ {
253
+ ...(typia ?? {}),
254
+ transform: "typia/lib/transform",
255
+ enabled: false,
256
+ },
257
+ normalizePlugin({
258
+ ...(sdk ?? {}),
259
+ transform: "@nestia/sdk/lib/transform",
260
+ }),
261
+ normalizePlugin({
262
+ ...(core ?? {}),
263
+ transform: "@nestia/core/native/transform.cjs",
264
+ }),
265
+ ];
266
+ };
267
+
268
+ const normalizePlugin = (plugin: MaterializePlugin): MaterializePlugin => {
269
+ const output: MaterializePlugin = { ...plugin };
270
+ if (output.enabled === false) delete output.enabled;
271
+ return output;
272
+ };
273
+
274
+ const isTransform = (plugin: MaterializePlugin, name: string): boolean =>
275
+ typeof plugin.transform === "string" && plugin.transform.includes(name);
276
+
277
+ const findConfigFile = (
278
+ cwd: string,
279
+ project: string,
280
+ ): string | undefined => {
281
+ const candidate: string = path.isAbsolute(project)
282
+ ? project
283
+ : path.resolve(cwd, project);
284
+ if (fs.existsSync(candidate)) return candidate;
285
+ if (path.isAbsolute(project) || project.includes(path.sep))
286
+ return undefined;
287
+
288
+ let current: string = path.resolve(cwd);
289
+ while (true) {
290
+ const next: string = path.join(current, project);
291
+ if (fs.existsSync(next)) return next;
292
+ const parent: string = path.dirname(current);
293
+ if (parent === current) return undefined;
294
+ current = parent;
295
+ }
296
+ };
297
+
298
+ const extractConfiguration = (
299
+ file: string,
300
+ loaded: unknown,
301
+ ): INestiaConfig | INestiaConfig[] => {
302
+ const candidates: unknown[] = [];
303
+ const collect = (value: unknown): void => {
304
+ if (isObject(value)) {
305
+ candidates.push(value.default);
306
+ candidates.push(value.NESTIA_CONFIG);
307
+ if (isObject(value.default)) {
308
+ candidates.push(value.default.default);
309
+ candidates.push(value.default.NESTIA_CONFIG);
310
+ }
311
+ }
312
+ candidates.push(value);
313
+ };
314
+ collect(loaded);
315
+ const matched: unknown = candidates.find(
316
+ (value) =>
317
+ Array.isArray(value) ||
318
+ (isObject(value) && Object.hasOwn(value, "input")),
319
+ );
320
+ if (matched === undefined)
321
+ throw new Error(
322
+ `invalid "${file}" data: configuration must be exported.`,
323
+ );
324
+ return matched as INestiaConfig | INestiaConfig[];
325
+ };
326
+
327
+ const loadMaterializedModule = async (file: string): Promise<unknown> => {
328
+ if (file.endsWith(".mjs")) {
329
+ const dynamicImport = new Function(
330
+ "specifier",
331
+ "return import(specifier)",
332
+ ) as (specifier: string) => Promise<unknown>;
333
+ return dynamicImport(pathToFileURL(file).href);
80
334
  }
335
+ return require(file);
336
+ };
337
+
338
+ const assertPlugins = (
339
+ file: string,
340
+ input: unknown,
341
+ ): Array<Record<string, any>> => {
342
+ if (
343
+ Array.isArray(input) &&
344
+ input.every((elem) => typeof elem === "object" && elem !== null)
345
+ )
346
+ return input as Array<Record<string, any>>;
347
+ throw new Error(
348
+ `invalid "${file}" data: compilerOptions.plugins must be an array.`,
349
+ );
350
+ };
351
+
352
+ const assertConfigurations = (
353
+ file: string,
354
+ input: unknown[],
355
+ ): INestiaConfig[] => {
356
+ input.forEach((config, index) => assertConfig(file, config, index));
357
+ return input as INestiaConfig[];
358
+ };
359
+
360
+ const assertConfig = (file: string, input: unknown, index: number): void => {
361
+ if (isObject(input) === false)
362
+ throw new Error(
363
+ `invalid "${file}" data: configuration #${index} must be an object.`,
364
+ );
365
+ const config: INestiaConfig = input as unknown as INestiaConfig;
366
+ if (isInput(config.input) === false)
367
+ throw new Error(
368
+ `invalid "${file}" data: configuration #${index}.input is invalid.`,
369
+ );
370
+ for (const [key, value] of [
371
+ ["output", config.output],
372
+ ["distribute", config.distribute],
373
+ ["e2e", config.e2e],
374
+ ] as const)
375
+ if (value !== undefined && typeof value !== "string")
376
+ throw new Error(
377
+ `invalid "${file}" data: configuration #${index}.${key} must be a string.`,
378
+ );
379
+ for (const [key, value] of [
380
+ ["keyword", config.keyword],
381
+ ["simulate", config.simulate],
382
+ ["propagate", config.propagate],
383
+ ["clone", config.clone],
384
+ ["primitive", config.primitive],
385
+ ["assert", config.assert],
386
+ ["json", config.json],
387
+ ] as const)
388
+ if (value !== undefined && typeof value !== "boolean")
389
+ throw new Error(
390
+ `invalid "${file}" data: configuration #${index}.${key} must be a boolean.`,
391
+ );
392
+ if (config.swagger !== undefined && isSwagger(config.swagger) === false)
393
+ throw new Error(
394
+ `invalid "${file}" data: configuration #${index}.swagger is invalid.`,
395
+ );
396
+ };
397
+
398
+ const isInput = (input: unknown): input is INestiaConfig["input"] => {
399
+ if (
400
+ typeof input === "string" ||
401
+ typeof input === "function" ||
402
+ isStringArray(input)
403
+ )
404
+ return true;
405
+ if (isObject(input) === false) return false;
406
+ return (
407
+ isStringArray(input.include) &&
408
+ (input.exclude === undefined || isStringArray(input.exclude))
409
+ );
410
+ };
411
+
412
+ const isSwagger = (input: unknown): input is INestiaConfig.ISwaggerConfig => {
413
+ if (isObject(input) === false) return false;
414
+ return (
415
+ typeof input.output === "string" &&
416
+ (input.openapi === undefined ||
417
+ ["2.0", "3.0", "3.1", "3.2"].includes(input.openapi as string)) &&
418
+ (input.beautify === undefined ||
419
+ typeof input.beautify === "boolean" ||
420
+ typeof input.beautify === "number") &&
421
+ (input.additional === undefined ||
422
+ typeof input.additional === "boolean") &&
423
+ (input.decompose === undefined || typeof input.decompose === "boolean") &&
424
+ (input.operationId === undefined ||
425
+ typeof input.operationId === "function")
426
+ );
427
+ };
428
+
429
+ const isObject = (input: unknown): input is Record<string, unknown> =>
430
+ typeof input === "object" &&
431
+ input !== null &&
432
+ Array.isArray(input) === false;
433
+
434
+ const isStringArray = (input: unknown): input is string[] =>
435
+ Array.isArray(input) && input.every((elem) => typeof elem === "string");
436
+
437
+ const readChildOutput = (
438
+ error: unknown,
439
+ key: "stderr" | "stdout",
440
+ ): string => {
441
+ if (!error || typeof error !== "object" || !(key in error)) return "";
442
+ const value = (error as Record<string, unknown>)[key];
443
+ if (value === null || value === undefined) return "";
444
+ if (typeof value === "string") return value.trim();
445
+ if (Buffer.isBuffer(value)) return value.toString("utf8").trim();
446
+ return "";
81
447
  };
82
448
  }
@@ -1,5 +1,3 @@
1
- import ts from "typescript";
2
-
3
1
  import { INestiaConfig } from "../../INestiaConfig";
4
2
  import { NestiaSdkApplication } from "../../NestiaSdkApplication";
5
3
  import { NestiaConfigLoader } from "./NestiaConfigLoader";
@@ -54,13 +52,14 @@ export namespace NestiaSdkCommand {
54
52
  validate: (config: INestiaConfig) => boolean;
55
53
  }) => {
56
54
  // LOAD CONFIG INFO
57
- const command: ts.ParsedCommandLine =
58
- await NestiaConfigLoader.compilerOptions(
59
- getFileArgument({
60
- type: "project",
61
- extension: "json",
62
- }) ?? "tsconfig.json",
63
- );
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);
64
63
 
65
64
  const configurations: INestiaConfig[] =
66
65
  await NestiaConfigLoader.configurations(
@@ -68,7 +67,7 @@ export namespace NestiaSdkCommand {
68
67
  type: "config",
69
68
  extension: "ts",
70
69
  }) ?? "nestia.config.ts",
71
- command.raw.compilerOptions,
70
+ command.raw.compilerOptions ?? {},
72
71
  );
73
72
 
74
73
  // GENERATE
@@ -17,7 +17,7 @@ npx @nestia/sdk [command] [options?]
17
17
  3. npx @nestia/sdk sdk --config? [config file] --project? [project file]
18
18
  4. npx @nestia/sdk swagger --config? [config file] --project? [project file]
19
19
  5. npx @nestia/sdk e2e --config? [config file] --project? [project file]
20
- 6. npx @nestia/sdk generate --config? [config file] --project? [project file]
20
+ 6. npx @nestia/sdk all --config? [config file] --project? [project file]
21
21
  `;
22
22
 
23
23
  function halt(desc: string): never {
@@ -27,10 +27,11 @@ function halt(desc: string): never {
27
27
 
28
28
  function dependencies(argv: string[]): void {
29
29
  // INSTALL DEPENDENCIES
30
- const module = CommandParser.parse(argv).module ?? "npm";
30
+ const options = CommandParser.parse(argv);
31
+ const module = options.manager ?? options.module ?? "npm";
31
32
  const prefix: string = module === "yarn" ? "yarn add" : `${module} install`;
32
33
 
33
- for (const lib of ["@nestia/fetcher", "typia"]) {
34
+ for (const lib of ["@nestia/e2e", "@nestia/fetcher", "typia"]) {
34
35
  const command: string = `${prefix} ${lib}`;
35
36
  console.log(`\n$ ${command}`);
36
37
  cp.execSync(command, { stdio: "inherit" });
@@ -72,6 +73,16 @@ async function main() {
72
73
  process.exit(0);
73
74
  }
74
75
  main().catch((exp) => {
75
- console.log(exp);
76
+ let current: unknown = exp;
77
+ let depth = 0;
78
+ while (current !== undefined && current !== null && depth < 10) {
79
+ const message: string =
80
+ current instanceof Error ? current.message : String(current);
81
+ console.error(`${" ".repeat(depth)}${depth === 0 ? "" : "caused by: "}${message}`);
82
+ if (current instanceof Error && current.cause !== undefined) {
83
+ current = current.cause;
84
+ depth++;
85
+ } else break;
86
+ }
76
87
  process.exit(-1);
77
88
  });
@@ -1,5 +1,5 @@
1
+ import { Node, NodeFlags, SyntaxKind, TypeScriptFactory } from "@nestia/factory";
1
2
  import fs from "fs";
2
- import ts from "typescript";
3
3
 
4
4
  import { INestiaProject } from "../structures/INestiaProject";
5
5
  import { ITypedApplication } from "../structures/ITypedApplication";
@@ -30,7 +30,7 @@ export namespace CloneGenerator {
30
30
  ): Promise<void> => {
31
31
  const location: string = `${project.config.output}/structures/${key}.ts`;
32
32
  const importer: ImportDictionary = new ImportDictionary(location);
33
- const statements: ts.Statement[] = iterate(importer)(value);
33
+ const statements: Node[] = iterate(importer)(value);
34
34
  if (statements.length === 0) return;
35
35
 
36
36
  await FilePrinter.write({
@@ -45,19 +45,19 @@ export namespace CloneGenerator {
45
45
 
46
46
  const iterate =
47
47
  (importer: ImportDictionary) =>
48
- (modulo: SdkHttpCloneProgrammer.IModule): ts.Statement[] => {
49
- const output: ts.Statement[] = [];
48
+ (modulo: SdkHttpCloneProgrammer.IModule): Node[] => {
49
+ const output: Node[] = [];
50
50
  if (modulo.programmer !== null) output.push(modulo.programmer(importer));
51
51
  if (modulo.children.size) {
52
- const internal: ts.Statement[] = [];
52
+ const internal: Node[] = [];
53
53
  for (const child of modulo.children.values())
54
54
  internal.push(...iterate(importer)(child));
55
55
  output.push(
56
- ts.factory.createModuleDeclaration(
57
- [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
58
- ts.factory.createIdentifier(modulo.name),
59
- ts.factory.createModuleBlock(internal),
60
- ts.NodeFlags.Namespace,
56
+ TypeScriptFactory.createModuleDeclaration(
57
+ [TypeScriptFactory.createModifier(SyntaxKind.ExportKeyword)],
58
+ TypeScriptFactory.createIdentifier(modulo.name),
59
+ TypeScriptFactory.createModuleBlock(internal),
60
+ NodeFlags.Namespace,
61
61
  ),
62
62
  );
63
63
  }