@nestia/sdk 1.3.1 → 1.3.3

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 (51) hide show
  1. package/assets/config/nestia.config.ts +70 -70
  2. package/lib/INestiaConfig.d.ts +13 -0
  3. package/lib/executable/internal/NestiaSdkConfig.js +6 -2
  4. package/lib/executable/internal/NestiaSdkConfig.js.map +1 -1
  5. package/lib/executable/sdk.js +11 -11
  6. package/lib/generates/SwaggerGenerator.js +9 -9
  7. package/lib/generates/internal/DistributionComposer.js +1 -1
  8. package/lib/generates/internal/DistributionComposer.js.map +1 -1
  9. package/lib/generates/internal/E2eFileProgrammer.js +12 -12
  10. package/lib/generates/internal/SdkFileProgrammer.js +3 -1
  11. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  12. package/lib/generates/internal/SdkFunctionProgrammer.js +24 -43
  13. package/lib/generates/internal/SdkFunctionProgrammer.js.map +1 -1
  14. package/package.json +4 -4
  15. package/src/INestiaConfig.ts +204 -190
  16. package/src/NestiaSdkApplication.ts +262 -262
  17. package/src/analyses/ControllerAnalyzer.ts +261 -261
  18. package/src/analyses/GenericAnalyzer.ts +53 -53
  19. package/src/analyses/ImportAnalyzer.ts +164 -164
  20. package/src/analyses/PathAnalyzer.ts +58 -58
  21. package/src/analyses/ReflectAnalyzer.ts +321 -321
  22. package/src/executable/internal/CommandParser.ts +15 -15
  23. package/src/executable/internal/NestiaConfigCompilerOptions.ts +18 -18
  24. package/src/executable/internal/NestiaSdkCommand.ts +156 -156
  25. package/src/executable/internal/NestiaSdkConfig.ts +36 -36
  26. package/src/executable/internal/nestia.config.getter.ts +12 -12
  27. package/src/executable/sdk.ts +70 -70
  28. package/src/generates/E2eGenerator.ts +67 -67
  29. package/src/generates/SdkGenerator.ts +56 -56
  30. package/src/generates/SwaggerGenerator.ts +504 -504
  31. package/src/generates/internal/DistributionComposer.ts +98 -97
  32. package/src/generates/internal/E2eFileProgrammer.ts +135 -135
  33. package/src/generates/internal/SdkFileProgrammer.ts +148 -144
  34. package/src/generates/internal/SdkFunctionProgrammer.ts +30 -52
  35. package/src/generates/internal/SdkRouteDirectory.ts +21 -21
  36. package/src/index.ts +4 -4
  37. package/src/module.ts +2 -2
  38. package/src/structures/IController.ts +31 -31
  39. package/src/structures/IRoute.ts +39 -39
  40. package/src/structures/ISwaggerDocument.ts +120 -120
  41. package/src/structures/ITypeTuple.ts +6 -6
  42. package/src/structures/MethodType.ts +11 -11
  43. package/src/structures/ParamCategory.ts +1 -1
  44. package/src/structures/TypeEntry.ts +22 -22
  45. package/src/utils/ArrayUtil.ts +26 -26
  46. package/src/utils/FileRetriever.ts +22 -22
  47. package/src/utils/ImportDictionary.ts +56 -56
  48. package/src/utils/MapUtil.ts +14 -14
  49. package/src/utils/NestiaConfigUtil.ts +21 -21
  50. package/src/utils/SourceFinder.ts +60 -60
  51. package/src/utils/StripEnums.ts +10 -10
@@ -1,321 +1,321 @@
1
- import * as Constants from "@nestjs/common/constants";
2
- import { equal } from "tstl/ranges/module";
3
-
4
- import { IController } from "../structures/IController";
5
- import { ParamCategory } from "../structures/ParamCategory";
6
- import { ArrayUtil } from "../utils/ArrayUtil";
7
- import { PathAnalyzer } from "./PathAnalyzer";
8
-
9
- declare const Reflect: any;
10
-
11
- type IModule = {
12
- [key: string]: any;
13
- };
14
-
15
- export namespace ReflectAnalyzer {
16
- export async function analyze(
17
- unique: WeakSet<any>,
18
- file: string,
19
- ): Promise<IController[]> {
20
- const module: IModule = await (async () => {
21
- try {
22
- return await import(file);
23
- } catch (exp) {
24
- console.log(
25
- ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
26
- );
27
- console.log(`Error on "${file}" file. Check your code.`);
28
- console.log(exp);
29
- console.log(
30
- ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
31
- );
32
- process.exit(-1);
33
- }
34
- })();
35
- const ret: IController[] = [];
36
-
37
- for (const tuple of Object.entries(module)) {
38
- if (unique.has(tuple[1])) continue;
39
- else unique.add(tuple[1]);
40
-
41
- const controller: IController | null = _Analyze_controller(
42
- file,
43
- ...tuple,
44
- );
45
- if (controller !== null) ret.push(controller);
46
- }
47
- return ret;
48
- }
49
-
50
- /* ---------------------------------------------------------
51
- CONTROLLER
52
- --------------------------------------------------------- */
53
- function _Analyze_controller(
54
- file: string,
55
- name: string,
56
- creator: any,
57
- ): IController | null {
58
- //----
59
- // VALIDATIONS
60
- //----
61
- // MUST BE TYPE OF A CREATOR WHO HAS THE CONSTRUCTOR
62
- if (
63
- !(
64
- creator instanceof Function &&
65
- creator.constructor instanceof Function
66
- )
67
- )
68
- return null;
69
- // MUST HAVE THOSE MATADATA
70
- else if (
71
- ArrayUtil.has(
72
- Reflect.getMetadataKeys(creator),
73
- Constants.PATH_METADATA,
74
- Constants.HOST_METADATA,
75
- Constants.SCOPE_OPTIONS_METADATA,
76
- ) === false
77
- )
78
- return null;
79
-
80
- //----
81
- // CONSTRUCTION
82
- //----
83
- // BASIC INFO
84
- const paths: string[] = _Get_paths(
85
- Reflect.getMetadata(Constants.PATH_METADATA, creator),
86
- );
87
- const meta: IController = {
88
- file,
89
- name,
90
- paths,
91
- functions: [],
92
- };
93
-
94
- // PARSE CHILDREN DATA
95
- for (const tuple of _Get_prototype_entries(creator)) {
96
- const child: IController.IFunction | null = _Analyze_function(
97
- creator.prototype,
98
- meta,
99
- ...tuple,
100
- );
101
- if (child !== null) meta.functions.push(child);
102
- }
103
-
104
- // RETURNS
105
- return meta;
106
- }
107
-
108
- function _Get_prototype_entries(creator: any): Array<[string, unknown]> {
109
- const keyList = Object.getOwnPropertyNames(creator.prototype);
110
- const entries: Array<[string, unknown]> = keyList.map((key) => [
111
- key,
112
- creator.prototype[key],
113
- ]);
114
-
115
- const parent = Object.getPrototypeOf(creator);
116
- if (parent.prototype !== undefined)
117
- entries.push(..._Get_prototype_entries(parent));
118
-
119
- return entries;
120
- }
121
-
122
- function _Get_paths(value: string | string[]): string[] {
123
- if (typeof value === "string") return [value];
124
- else if (value.length === 0) return [""];
125
- else return value;
126
- }
127
-
128
- /* ---------------------------------------------------------
129
- FUNCTION
130
- --------------------------------------------------------- */
131
- function _Analyze_function(
132
- classProto: any,
133
- controller: IController,
134
- name: string,
135
- proto: any,
136
- ): IController.IFunction | null {
137
- //----
138
- // VALIDATIONS
139
- //----
140
- // MUST BE TYPE OF A FUNCTION
141
- if (!(proto instanceof Function)) return null;
142
- // MUST HAVE THOSE METADATE
143
- else if (
144
- ArrayUtil.has(
145
- Reflect.getMetadataKeys(proto),
146
- Constants.PATH_METADATA,
147
- Constants.METHOD_METADATA,
148
- ) === false
149
- )
150
- return null;
151
-
152
- //----
153
- // CONSTRUCTION
154
- //----
155
- // BASIC INFO
156
- const meta: IController.IFunction = {
157
- name,
158
- method: METHODS[
159
- Reflect.getMetadata(Constants.METHOD_METADATA, proto)
160
- ],
161
- paths: _Get_paths(
162
- Reflect.getMetadata(Constants.PATH_METADATA, proto),
163
- ),
164
- parameters: [],
165
- encrypted:
166
- Reflect.getMetadata(Constants.INTERCEPTORS_METADATA, proto)?.[0]
167
- ?.constructor?.name === "EncryptedRouteInterceptor",
168
- status: Reflect.getMetadata(Constants.HTTP_CODE_METADATA, proto),
169
- };
170
-
171
- // PARSE CHILDREN DATA
172
- const nestParameters: NestParameters | undefined = Reflect.getMetadata(
173
- Constants.ROUTE_ARGS_METADATA,
174
- classProto.constructor,
175
- name,
176
- );
177
- if (nestParameters === undefined) meta.parameters = [];
178
- else {
179
- for (const tuple of Object.entries(nestParameters)) {
180
- const child: IController.IParameter | null = _Analyze_parameter(
181
- ...tuple,
182
- );
183
- if (child !== null) meta.parameters.push(child);
184
- }
185
- meta.parameters = meta.parameters.sort((x, y) => x.index - y.index);
186
- }
187
-
188
- // VALIDATE PATH ARGUMENTS
189
- for (const controllerLocation of controller.paths)
190
- for (const metaLocation of meta.paths) {
191
- // NORMALIZE LOCATION
192
- const location: string = PathAnalyzer.join(
193
- controllerLocation,
194
- metaLocation,
195
- );
196
-
197
- // LIST UP PARAMETERS
198
- const binded: string[] = PathAnalyzer.parameters(
199
- location,
200
- () => `${controller.name}.${name}()`,
201
- ).sort();
202
-
203
- const parameters: string[] = meta.parameters
204
- .filter((param) => param.category === "param")
205
- .map((param) => param.field!)
206
- .sort();
207
-
208
- // DO VALIDATE
209
- if (equal(binded, parameters) === false)
210
- throw new Error(
211
- `Error on ${
212
- controller.name
213
- }.${name}(): binded arguments in the "path" between function's decorator and parameters' decorators are different (function: [${binded.join(
214
- ", ",
215
- )}], parameters: [${parameters.join(", ")}])`,
216
- );
217
- }
218
-
219
- // RETURNS
220
- return meta;
221
- }
222
-
223
- const METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH"];
224
-
225
- /* ---------------------------------------------------------
226
- PARAMETER
227
- --------------------------------------------------------- */
228
- function _Analyze_parameter(
229
- key: string,
230
- param: INestParam,
231
- ): IController.IParameter | null {
232
- const symbol: string = key.split(":")[0];
233
- if (symbol.indexOf("__custom") !== -1)
234
- return _Analyze_custom_parameter(param);
235
-
236
- const typeIndex: number = Number(symbol[0]);
237
- if (isNaN(typeIndex) === true) return null;
238
-
239
- const type: ParamCategory | undefined = NEST_PARAMETER_TYPES[typeIndex];
240
- if (type === undefined) return null;
241
-
242
- return {
243
- name: key,
244
- category: type,
245
- index: param.index,
246
- field: param.data,
247
- encrypted: false,
248
- };
249
- }
250
-
251
- function _Analyze_custom_parameter(
252
- param: INestParam,
253
- ): IController.IParameter | null {
254
- if (param.factory === undefined) return null;
255
- else if (
256
- param.factory.name === "TypedBody" ||
257
- param.factory.name === "EncryptedBody" ||
258
- param.factory.name === "PlainBody"
259
- ) {
260
- return {
261
- category: "body",
262
- index: param.index,
263
- name: param.name,
264
- field: param.data,
265
- encrypted: param.factory.name === "EncryptedBody",
266
- };
267
- } else if (param.factory.name === "TypedParam") {
268
- return {
269
- name: param.name,
270
- category: "param",
271
- index: param.index,
272
- field: param.data,
273
- encrypted: false,
274
- meta: (() => {
275
- const type = (param.factory as any).type;
276
- const nullable = (param.factory as any).nullable;
277
- if (type !== undefined && nullable !== undefined)
278
- return {
279
- type,
280
- nullable,
281
- };
282
- return undefined;
283
- })(),
284
- };
285
- } else if (param.factory.name === "TypedQuery")
286
- return {
287
- name: param.name,
288
- category: "query",
289
- index: param.index,
290
- field: undefined,
291
- encrypted: false,
292
- };
293
- else return null;
294
- }
295
-
296
- type NestParameters = {
297
- [key: string]: INestParam;
298
- };
299
-
300
- interface INestParam {
301
- name: string;
302
- index: number;
303
- factory?: (...args: any) => any;
304
- data: string | undefined;
305
- }
306
-
307
- const NEST_PARAMETER_TYPES = [
308
- undefined,
309
- undefined,
310
- undefined,
311
- "body",
312
- "query",
313
- "param",
314
- undefined,
315
- undefined,
316
- undefined,
317
- undefined,
318
- undefined,
319
- undefined,
320
- ] as const;
321
- }
1
+ import * as Constants from "@nestjs/common/constants";
2
+ import { equal } from "tstl/ranges/module";
3
+
4
+ import { IController } from "../structures/IController";
5
+ import { ParamCategory } from "../structures/ParamCategory";
6
+ import { ArrayUtil } from "../utils/ArrayUtil";
7
+ import { PathAnalyzer } from "./PathAnalyzer";
8
+
9
+ declare const Reflect: any;
10
+
11
+ type IModule = {
12
+ [key: string]: any;
13
+ };
14
+
15
+ export namespace ReflectAnalyzer {
16
+ export async function analyze(
17
+ unique: WeakSet<any>,
18
+ file: string,
19
+ ): Promise<IController[]> {
20
+ const module: IModule = await (async () => {
21
+ try {
22
+ return await import(file);
23
+ } catch (exp) {
24
+ console.log(
25
+ ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
26
+ );
27
+ console.log(`Error on "${file}" file. Check your code.`);
28
+ console.log(exp);
29
+ console.log(
30
+ ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
31
+ );
32
+ process.exit(-1);
33
+ }
34
+ })();
35
+ const ret: IController[] = [];
36
+
37
+ for (const tuple of Object.entries(module)) {
38
+ if (unique.has(tuple[1])) continue;
39
+ else unique.add(tuple[1]);
40
+
41
+ const controller: IController | null = _Analyze_controller(
42
+ file,
43
+ ...tuple,
44
+ );
45
+ if (controller !== null) ret.push(controller);
46
+ }
47
+ return ret;
48
+ }
49
+
50
+ /* ---------------------------------------------------------
51
+ CONTROLLER
52
+ --------------------------------------------------------- */
53
+ function _Analyze_controller(
54
+ file: string,
55
+ name: string,
56
+ creator: any,
57
+ ): IController | null {
58
+ //----
59
+ // VALIDATIONS
60
+ //----
61
+ // MUST BE TYPE OF A CREATOR WHO HAS THE CONSTRUCTOR
62
+ if (
63
+ !(
64
+ creator instanceof Function &&
65
+ creator.constructor instanceof Function
66
+ )
67
+ )
68
+ return null;
69
+ // MUST HAVE THOSE MATADATA
70
+ else if (
71
+ ArrayUtil.has(
72
+ Reflect.getMetadataKeys(creator),
73
+ Constants.PATH_METADATA,
74
+ Constants.HOST_METADATA,
75
+ Constants.SCOPE_OPTIONS_METADATA,
76
+ ) === false
77
+ )
78
+ return null;
79
+
80
+ //----
81
+ // CONSTRUCTION
82
+ //----
83
+ // BASIC INFO
84
+ const paths: string[] = _Get_paths(
85
+ Reflect.getMetadata(Constants.PATH_METADATA, creator),
86
+ );
87
+ const meta: IController = {
88
+ file,
89
+ name,
90
+ paths,
91
+ functions: [],
92
+ };
93
+
94
+ // PARSE CHILDREN DATA
95
+ for (const tuple of _Get_prototype_entries(creator)) {
96
+ const child: IController.IFunction | null = _Analyze_function(
97
+ creator.prototype,
98
+ meta,
99
+ ...tuple,
100
+ );
101
+ if (child !== null) meta.functions.push(child);
102
+ }
103
+
104
+ // RETURNS
105
+ return meta;
106
+ }
107
+
108
+ function _Get_prototype_entries(creator: any): Array<[string, unknown]> {
109
+ const keyList = Object.getOwnPropertyNames(creator.prototype);
110
+ const entries: Array<[string, unknown]> = keyList.map((key) => [
111
+ key,
112
+ creator.prototype[key],
113
+ ]);
114
+
115
+ const parent = Object.getPrototypeOf(creator);
116
+ if (parent.prototype !== undefined)
117
+ entries.push(..._Get_prototype_entries(parent));
118
+
119
+ return entries;
120
+ }
121
+
122
+ function _Get_paths(value: string | string[]): string[] {
123
+ if (typeof value === "string") return [value];
124
+ else if (value.length === 0) return [""];
125
+ else return value;
126
+ }
127
+
128
+ /* ---------------------------------------------------------
129
+ FUNCTION
130
+ --------------------------------------------------------- */
131
+ function _Analyze_function(
132
+ classProto: any,
133
+ controller: IController,
134
+ name: string,
135
+ proto: any,
136
+ ): IController.IFunction | null {
137
+ //----
138
+ // VALIDATIONS
139
+ //----
140
+ // MUST BE TYPE OF A FUNCTION
141
+ if (!(proto instanceof Function)) return null;
142
+ // MUST HAVE THOSE METADATE
143
+ else if (
144
+ ArrayUtil.has(
145
+ Reflect.getMetadataKeys(proto),
146
+ Constants.PATH_METADATA,
147
+ Constants.METHOD_METADATA,
148
+ ) === false
149
+ )
150
+ return null;
151
+
152
+ //----
153
+ // CONSTRUCTION
154
+ //----
155
+ // BASIC INFO
156
+ const meta: IController.IFunction = {
157
+ name,
158
+ method: METHODS[
159
+ Reflect.getMetadata(Constants.METHOD_METADATA, proto)
160
+ ],
161
+ paths: _Get_paths(
162
+ Reflect.getMetadata(Constants.PATH_METADATA, proto),
163
+ ),
164
+ parameters: [],
165
+ encrypted:
166
+ Reflect.getMetadata(Constants.INTERCEPTORS_METADATA, proto)?.[0]
167
+ ?.constructor?.name === "EncryptedRouteInterceptor",
168
+ status: Reflect.getMetadata(Constants.HTTP_CODE_METADATA, proto),
169
+ };
170
+
171
+ // PARSE CHILDREN DATA
172
+ const nestParameters: NestParameters | undefined = Reflect.getMetadata(
173
+ Constants.ROUTE_ARGS_METADATA,
174
+ classProto.constructor,
175
+ name,
176
+ );
177
+ if (nestParameters === undefined) meta.parameters = [];
178
+ else {
179
+ for (const tuple of Object.entries(nestParameters)) {
180
+ const child: IController.IParameter | null = _Analyze_parameter(
181
+ ...tuple,
182
+ );
183
+ if (child !== null) meta.parameters.push(child);
184
+ }
185
+ meta.parameters = meta.parameters.sort((x, y) => x.index - y.index);
186
+ }
187
+
188
+ // VALIDATE PATH ARGUMENTS
189
+ for (const controllerLocation of controller.paths)
190
+ for (const metaLocation of meta.paths) {
191
+ // NORMALIZE LOCATION
192
+ const location: string = PathAnalyzer.join(
193
+ controllerLocation,
194
+ metaLocation,
195
+ );
196
+
197
+ // LIST UP PARAMETERS
198
+ const binded: string[] = PathAnalyzer.parameters(
199
+ location,
200
+ () => `${controller.name}.${name}()`,
201
+ ).sort();
202
+
203
+ const parameters: string[] = meta.parameters
204
+ .filter((param) => param.category === "param")
205
+ .map((param) => param.field!)
206
+ .sort();
207
+
208
+ // DO VALIDATE
209
+ if (equal(binded, parameters) === false)
210
+ throw new Error(
211
+ `Error on ${
212
+ controller.name
213
+ }.${name}(): binded arguments in the "path" between function's decorator and parameters' decorators are different (function: [${binded.join(
214
+ ", ",
215
+ )}], parameters: [${parameters.join(", ")}])`,
216
+ );
217
+ }
218
+
219
+ // RETURNS
220
+ return meta;
221
+ }
222
+
223
+ const METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH"];
224
+
225
+ /* ---------------------------------------------------------
226
+ PARAMETER
227
+ --------------------------------------------------------- */
228
+ function _Analyze_parameter(
229
+ key: string,
230
+ param: INestParam,
231
+ ): IController.IParameter | null {
232
+ const symbol: string = key.split(":")[0];
233
+ if (symbol.indexOf("__custom") !== -1)
234
+ return _Analyze_custom_parameter(param);
235
+
236
+ const typeIndex: number = Number(symbol[0]);
237
+ if (isNaN(typeIndex) === true) return null;
238
+
239
+ const type: ParamCategory | undefined = NEST_PARAMETER_TYPES[typeIndex];
240
+ if (type === undefined) return null;
241
+
242
+ return {
243
+ name: key,
244
+ category: type,
245
+ index: param.index,
246
+ field: param.data,
247
+ encrypted: false,
248
+ };
249
+ }
250
+
251
+ function _Analyze_custom_parameter(
252
+ param: INestParam,
253
+ ): IController.IParameter | null {
254
+ if (param.factory === undefined) return null;
255
+ else if (
256
+ param.factory.name === "TypedBody" ||
257
+ param.factory.name === "EncryptedBody" ||
258
+ param.factory.name === "PlainBody"
259
+ ) {
260
+ return {
261
+ category: "body",
262
+ index: param.index,
263
+ name: param.name,
264
+ field: param.data,
265
+ encrypted: param.factory.name === "EncryptedBody",
266
+ };
267
+ } else if (param.factory.name === "TypedParam") {
268
+ return {
269
+ name: param.name,
270
+ category: "param",
271
+ index: param.index,
272
+ field: param.data,
273
+ encrypted: false,
274
+ meta: (() => {
275
+ const type = (param.factory as any).type;
276
+ const nullable = (param.factory as any).nullable;
277
+ if (type !== undefined && nullable !== undefined)
278
+ return {
279
+ type,
280
+ nullable,
281
+ };
282
+ return undefined;
283
+ })(),
284
+ };
285
+ } else if (param.factory.name === "TypedQuery")
286
+ return {
287
+ name: param.name,
288
+ category: "query",
289
+ index: param.index,
290
+ field: undefined,
291
+ encrypted: false,
292
+ };
293
+ else return null;
294
+ }
295
+
296
+ type NestParameters = {
297
+ [key: string]: INestParam;
298
+ };
299
+
300
+ interface INestParam {
301
+ name: string;
302
+ index: number;
303
+ factory?: (...args: any) => any;
304
+ data: string | undefined;
305
+ }
306
+
307
+ const NEST_PARAMETER_TYPES = [
308
+ undefined,
309
+ undefined,
310
+ undefined,
311
+ "body",
312
+ "query",
313
+ "param",
314
+ undefined,
315
+ undefined,
316
+ undefined,
317
+ undefined,
318
+ undefined,
319
+ undefined,
320
+ ] as const;
321
+ }
@@ -1,15 +1,15 @@
1
- export namespace CommandParser {
2
- export function parse(argList: string[]): Record<string, string> {
3
- const output: Record<string, string> = {};
4
- argList.forEach((arg, i) => {
5
- if (arg.startsWith("--") === false) return;
6
-
7
- const key = arg.slice(2);
8
- const value: string | undefined = argList[i + 1];
9
- if (value === undefined || value.startsWith("--")) return;
10
-
11
- output[key] = value;
12
- });
13
- return output;
14
- }
15
- }
1
+ export namespace CommandParser {
2
+ export function parse(argList: string[]): Record<string, string> {
3
+ const output: Record<string, string> = {};
4
+ argList.forEach((arg, i) => {
5
+ if (arg.startsWith("--") === false) return;
6
+
7
+ const key = arg.slice(2);
8
+ const value: string | undefined = argList[i + 1];
9
+ if (value === undefined || value.startsWith("--")) return;
10
+
11
+ output[key] = value;
12
+ });
13
+ return output;
14
+ }
15
+ }