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