@aws/nx-plugin 1.0.0-rc.30 → 1.0.0-rc.31
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-THIRD-PARTY +235 -1336
- package/README.md +1 -1
- package/package.json +1 -2
- package/src/mcp-server/tools/create-workspace-command.js +2 -2
- package/src/mcp-server/tools/create-workspace-command.js.map +1 -1
- package/src/open-api/ts-client/__snapshots__/generator.additional-properties.spec.ts.snap +147 -33
- package/src/open-api/ts-client/__snapshots__/generator.arrays.spec.ts.snap +308 -75
- package/src/open-api/ts-client/__snapshots__/generator.complex-types.spec.ts.snap +286 -62
- package/src/open-api/ts-client/__snapshots__/generator.composite-types.spec.ts.snap +674 -93
- package/src/open-api/ts-client/__snapshots__/generator.content-type.spec.ts.snap +147 -33
- package/src/open-api/ts-client/__snapshots__/generator.duplicate-types.spec.ts.snap +196 -44
- package/src/open-api/ts-client/__snapshots__/generator.edge-cases.spec.ts.snap +5507 -0
- package/src/open-api/ts-client/__snapshots__/generator.fast-api.spec.ts.snap +219 -60
- package/src/open-api/ts-client/__snapshots__/generator.primitive-types.spec.ts.snap +351 -80
- package/src/open-api/ts-client/__snapshots__/generator.request.spec.ts.snap +170 -49
- package/src/open-api/ts-client/__snapshots__/generator.reserved-keywords.spec.ts.snap +98 -22
- package/src/open-api/ts-client/__snapshots__/generator.response.spec.ts.snap +147 -33
- package/src/open-api/ts-client/__snapshots__/generator.streaming.spec.ts.snap +392 -88
- package/src/open-api/ts-client/__snapshots__/generator.tags.spec.ts.snap +196 -44
- package/src/open-api/ts-client/files/client.gen.ts.template +130 -18
- package/src/open-api/ts-client/files/types.gen.ts.template +4 -4
- package/src/open-api/ts-client/generator.js +1 -1
- package/src/open-api/ts-client/generator.js.map +1 -1
- package/src/open-api/ts-hooks/files/options-proxy.gen.ts.template +5 -0
- package/src/open-api/ts-hooks/generator.spec.tsx +70 -0
- package/src/open-api/utils/codegen-data/languages.d.ts +0 -6
- package/src/open-api/utils/codegen-data/languages.js +23 -18
- package/src/open-api/utils/codegen-data/languages.js.map +1 -1
- package/src/open-api/utils/codegen-data/types.d.ts +240 -10
- package/src/open-api/utils/codegen-data/types.js +24 -1
- package/src/open-api/utils/codegen-data/types.js.map +1 -1
- package/src/open-api/utils/codegen-data.d.ts +2 -2
- package/src/open-api/utils/codegen-data.js +357 -617
- package/src/open-api/utils/codegen-data.js.map +1 -1
- package/src/open-api/utils/normalise.js +157 -19
- package/src/open-api/utils/normalise.js.map +1 -1
- package/src/open-api/utils/parser.d.ts +55 -0
- package/src/open-api/utils/parser.js +743 -0
- package/src/open-api/utils/parser.js.map +1 -0
- package/src/open-api/utils/types.d.ts +15 -0
- package/src/open-api/utils/types.js.map +1 -1
- package/src/preset/__snapshots__/generator.spec.ts.snap +6 -6
- package/src/utils/mcp.js +1 -1
- package/src/utils/mcp.js.map +1 -1
- package/src/utils/names.d.ts +6 -0
- package/src/utils/names.js +6 -1
- package/src/utils/names.js.map +1 -1
|
@@ -11,7 +11,7 @@ exports[`openApiTsClientGenerator - tags > should allow duplicate operation ids
|
|
|
11
11
|
* Utility for serialisation and deserialisation of API types.
|
|
12
12
|
*/
|
|
13
13
|
export class $IO {
|
|
14
|
-
|
|
14
|
+
public static $mapValues = (data: any, fn: (item: any) => any) =>
|
|
15
15
|
Object.fromEntries(Object.entries(data).map(([k, v]) => [k, fn(v)]));
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -54,11 +54,31 @@ export class TestApi {
|
|
|
54
54
|
this._usersPeopleList = this._usersPeopleList.bind(this);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
private $collectionDelimiters: { [format: string]: string } = {
|
|
58
|
+
csv: ',',
|
|
59
|
+
ssv: ' ',
|
|
60
|
+
pipes: '|',
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
private $deepObject = (key: string, value: any): string[] => {
|
|
64
|
+
if (value === undefined || value === null) {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
if (typeof value !== 'object') {
|
|
68
|
+
return [\`\${key}=\${encodeURIComponent(String(value))}\`];
|
|
69
|
+
}
|
|
70
|
+
return Object.entries(value).flatMap(([prop, v]) =>
|
|
71
|
+
this.$deepObject(\`\${key}[\${encodeURIComponent(prop)}]\`, v),
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
57
75
|
private $url = (
|
|
58
76
|
path: string,
|
|
59
77
|
pathParameters: { [key: string]: any },
|
|
60
78
|
queryParameters: { [key: string]: any },
|
|
61
|
-
collectionFormats?: {
|
|
79
|
+
collectionFormats?: {
|
|
80
|
+
[key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' | 'deepObject';
|
|
81
|
+
},
|
|
62
82
|
): string => {
|
|
63
83
|
const baseUrl = this.$config.url.endsWith('/')
|
|
64
84
|
? this.$config.url.slice(0, -1)
|
|
@@ -69,15 +89,24 @@ export class TestApi {
|
|
|
69
89
|
path,
|
|
70
90
|
);
|
|
71
91
|
const queryString = Object.entries(queryParameters)
|
|
72
|
-
.
|
|
92
|
+
.flatMap(([key, value]) => {
|
|
73
93
|
if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
|
|
74
|
-
return value
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
94
|
+
return value.map(
|
|
95
|
+
(v) => \`\${encodeURIComponent(key)}=\${encodeURIComponent(\`\${v}\`)}\`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
if (
|
|
99
|
+
collectionFormats?.[key] === 'deepObject' &&
|
|
100
|
+
value !== null &&
|
|
101
|
+
typeof value === 'object'
|
|
102
|
+
) {
|
|
103
|
+
return this.$deepObject(encodeURIComponent(key), value);
|
|
79
104
|
}
|
|
80
|
-
|
|
105
|
+
const delimiter =
|
|
106
|
+
this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
|
|
107
|
+
return [
|
|
108
|
+
\`\${encodeURIComponent(key)}=\${encodeURIComponent(Array.isArray(value) ? value.map(String).join(delimiter) : String(value))}\`,
|
|
109
|
+
];
|
|
81
110
|
})
|
|
82
111
|
.join('&');
|
|
83
112
|
return (
|
|
@@ -87,13 +116,22 @@ export class TestApi {
|
|
|
87
116
|
|
|
88
117
|
private $headers = (
|
|
89
118
|
headerParameters: { [key: string]: any },
|
|
90
|
-
collectionFormats?: { [key: string]: 'multi' | 'csv' },
|
|
119
|
+
collectionFormats?: { [key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' },
|
|
91
120
|
): [string, string][] => {
|
|
92
121
|
return Object.entries(headerParameters).flatMap(([key, value]) => {
|
|
93
122
|
if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
|
|
94
123
|
return value.map((v) => [key, String(v)]) as [string, string][];
|
|
95
124
|
}
|
|
96
|
-
|
|
125
|
+
const delimiter =
|
|
126
|
+
this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
|
|
127
|
+
return [
|
|
128
|
+
[
|
|
129
|
+
key,
|
|
130
|
+
Array.isArray(value)
|
|
131
|
+
? value.map(String).join(delimiter)
|
|
132
|
+
: String(value),
|
|
133
|
+
],
|
|
134
|
+
];
|
|
97
135
|
});
|
|
98
136
|
};
|
|
99
137
|
|
|
@@ -190,7 +228,7 @@ exports[`openApiTsClientGenerator - tags > should allow duplicate operation ids
|
|
|
190
228
|
* Utility for serialisation and deserialisation of API types.
|
|
191
229
|
*/
|
|
192
230
|
export class $IO {
|
|
193
|
-
|
|
231
|
+
public static $mapValues = (data: any, fn: (item: any) => any) =>
|
|
194
232
|
Object.fromEntries(Object.entries(data).map(([k, v]) => [k, fn(v)]));
|
|
195
233
|
}
|
|
196
234
|
|
|
@@ -233,11 +271,31 @@ export class TestApi {
|
|
|
233
271
|
this._usersList = this._usersList.bind(this);
|
|
234
272
|
}
|
|
235
273
|
|
|
274
|
+
private $collectionDelimiters: { [format: string]: string } = {
|
|
275
|
+
csv: ',',
|
|
276
|
+
ssv: ' ',
|
|
277
|
+
pipes: '|',
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
private $deepObject = (key: string, value: any): string[] => {
|
|
281
|
+
if (value === undefined || value === null) {
|
|
282
|
+
return [];
|
|
283
|
+
}
|
|
284
|
+
if (typeof value !== 'object') {
|
|
285
|
+
return [\`\${key}=\${encodeURIComponent(String(value))}\`];
|
|
286
|
+
}
|
|
287
|
+
return Object.entries(value).flatMap(([prop, v]) =>
|
|
288
|
+
this.$deepObject(\`\${key}[\${encodeURIComponent(prop)}]\`, v),
|
|
289
|
+
);
|
|
290
|
+
};
|
|
291
|
+
|
|
236
292
|
private $url = (
|
|
237
293
|
path: string,
|
|
238
294
|
pathParameters: { [key: string]: any },
|
|
239
295
|
queryParameters: { [key: string]: any },
|
|
240
|
-
collectionFormats?: {
|
|
296
|
+
collectionFormats?: {
|
|
297
|
+
[key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' | 'deepObject';
|
|
298
|
+
},
|
|
241
299
|
): string => {
|
|
242
300
|
const baseUrl = this.$config.url.endsWith('/')
|
|
243
301
|
? this.$config.url.slice(0, -1)
|
|
@@ -248,15 +306,24 @@ export class TestApi {
|
|
|
248
306
|
path,
|
|
249
307
|
);
|
|
250
308
|
const queryString = Object.entries(queryParameters)
|
|
251
|
-
.
|
|
309
|
+
.flatMap(([key, value]) => {
|
|
252
310
|
if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
|
|
253
|
-
return value
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
311
|
+
return value.map(
|
|
312
|
+
(v) => \`\${encodeURIComponent(key)}=\${encodeURIComponent(\`\${v}\`)}\`,
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
if (
|
|
316
|
+
collectionFormats?.[key] === 'deepObject' &&
|
|
317
|
+
value !== null &&
|
|
318
|
+
typeof value === 'object'
|
|
319
|
+
) {
|
|
320
|
+
return this.$deepObject(encodeURIComponent(key), value);
|
|
258
321
|
}
|
|
259
|
-
|
|
322
|
+
const delimiter =
|
|
323
|
+
this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
|
|
324
|
+
return [
|
|
325
|
+
\`\${encodeURIComponent(key)}=\${encodeURIComponent(Array.isArray(value) ? value.map(String).join(delimiter) : String(value))}\`,
|
|
326
|
+
];
|
|
260
327
|
})
|
|
261
328
|
.join('&');
|
|
262
329
|
return (
|
|
@@ -266,13 +333,22 @@ export class TestApi {
|
|
|
266
333
|
|
|
267
334
|
private $headers = (
|
|
268
335
|
headerParameters: { [key: string]: any },
|
|
269
|
-
collectionFormats?: { [key: string]: 'multi' | 'csv' },
|
|
336
|
+
collectionFormats?: { [key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' },
|
|
270
337
|
): [string, string][] => {
|
|
271
338
|
return Object.entries(headerParameters).flatMap(([key, value]) => {
|
|
272
339
|
if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
|
|
273
340
|
return value.map((v) => [key, String(v)]) as [string, string][];
|
|
274
341
|
}
|
|
275
|
-
|
|
342
|
+
const delimiter =
|
|
343
|
+
this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
|
|
344
|
+
return [
|
|
345
|
+
[
|
|
346
|
+
key,
|
|
347
|
+
Array.isArray(value)
|
|
348
|
+
? value.map(String).join(delimiter)
|
|
349
|
+
: String(value),
|
|
350
|
+
],
|
|
351
|
+
];
|
|
276
352
|
});
|
|
277
353
|
};
|
|
278
354
|
|
|
@@ -357,7 +433,7 @@ exports[`openApiTsClientGenerator - tags > should handle operation tags and mult
|
|
|
357
433
|
* Utility for serialisation and deserialisation of API types.
|
|
358
434
|
*/
|
|
359
435
|
export class $IO {
|
|
360
|
-
|
|
436
|
+
public static $mapValues = (data: any, fn: (item: any) => any) =>
|
|
361
437
|
Object.fromEntries(Object.entries(data).map(([k, v]) => [k, fn(v)]));
|
|
362
438
|
}
|
|
363
439
|
|
|
@@ -402,11 +478,31 @@ export class TestApi {
|
|
|
402
478
|
this._getUsers = this._getUsers.bind(this);
|
|
403
479
|
}
|
|
404
480
|
|
|
481
|
+
private $collectionDelimiters: { [format: string]: string } = {
|
|
482
|
+
csv: ',',
|
|
483
|
+
ssv: ' ',
|
|
484
|
+
pipes: '|',
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
private $deepObject = (key: string, value: any): string[] => {
|
|
488
|
+
if (value === undefined || value === null) {
|
|
489
|
+
return [];
|
|
490
|
+
}
|
|
491
|
+
if (typeof value !== 'object') {
|
|
492
|
+
return [\`\${key}=\${encodeURIComponent(String(value))}\`];
|
|
493
|
+
}
|
|
494
|
+
return Object.entries(value).flatMap(([prop, v]) =>
|
|
495
|
+
this.$deepObject(\`\${key}[\${encodeURIComponent(prop)}]\`, v),
|
|
496
|
+
);
|
|
497
|
+
};
|
|
498
|
+
|
|
405
499
|
private $url = (
|
|
406
500
|
path: string,
|
|
407
501
|
pathParameters: { [key: string]: any },
|
|
408
502
|
queryParameters: { [key: string]: any },
|
|
409
|
-
collectionFormats?: {
|
|
503
|
+
collectionFormats?: {
|
|
504
|
+
[key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' | 'deepObject';
|
|
505
|
+
},
|
|
410
506
|
): string => {
|
|
411
507
|
const baseUrl = this.$config.url.endsWith('/')
|
|
412
508
|
? this.$config.url.slice(0, -1)
|
|
@@ -417,15 +513,24 @@ export class TestApi {
|
|
|
417
513
|
path,
|
|
418
514
|
);
|
|
419
515
|
const queryString = Object.entries(queryParameters)
|
|
420
|
-
.
|
|
516
|
+
.flatMap(([key, value]) => {
|
|
421
517
|
if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
|
|
422
|
-
return value
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
518
|
+
return value.map(
|
|
519
|
+
(v) => \`\${encodeURIComponent(key)}=\${encodeURIComponent(\`\${v}\`)}\`,
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
if (
|
|
523
|
+
collectionFormats?.[key] === 'deepObject' &&
|
|
524
|
+
value !== null &&
|
|
525
|
+
typeof value === 'object'
|
|
526
|
+
) {
|
|
527
|
+
return this.$deepObject(encodeURIComponent(key), value);
|
|
427
528
|
}
|
|
428
|
-
|
|
529
|
+
const delimiter =
|
|
530
|
+
this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
|
|
531
|
+
return [
|
|
532
|
+
\`\${encodeURIComponent(key)}=\${encodeURIComponent(Array.isArray(value) ? value.map(String).join(delimiter) : String(value))}\`,
|
|
533
|
+
];
|
|
429
534
|
})
|
|
430
535
|
.join('&');
|
|
431
536
|
return (
|
|
@@ -435,13 +540,22 @@ export class TestApi {
|
|
|
435
540
|
|
|
436
541
|
private $headers = (
|
|
437
542
|
headerParameters: { [key: string]: any },
|
|
438
|
-
collectionFormats?: { [key: string]: 'multi' | 'csv' },
|
|
543
|
+
collectionFormats?: { [key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' },
|
|
439
544
|
): [string, string][] => {
|
|
440
545
|
return Object.entries(headerParameters).flatMap(([key, value]) => {
|
|
441
546
|
if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
|
|
442
547
|
return value.map((v) => [key, String(v)]) as [string, string][];
|
|
443
548
|
}
|
|
444
|
-
|
|
549
|
+
const delimiter =
|
|
550
|
+
this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
|
|
551
|
+
return [
|
|
552
|
+
[
|
|
553
|
+
key,
|
|
554
|
+
Array.isArray(value)
|
|
555
|
+
? value.map(String).join(delimiter)
|
|
556
|
+
: String(value),
|
|
557
|
+
],
|
|
558
|
+
];
|
|
445
559
|
});
|
|
446
560
|
};
|
|
447
561
|
|
|
@@ -579,7 +693,7 @@ exports[`openApiTsClientGenerator - tags > should handle operations with multipl
|
|
|
579
693
|
* Utility for serialisation and deserialisation of API types.
|
|
580
694
|
*/
|
|
581
695
|
export class $IO {
|
|
582
|
-
|
|
696
|
+
public static $mapValues = (data: any, fn: (item: any) => any) =>
|
|
583
697
|
Object.fromEntries(Object.entries(data).map(([k, v]) => [k, fn(v)]));
|
|
584
698
|
}
|
|
585
699
|
|
|
@@ -622,11 +736,31 @@ export class TestApi {
|
|
|
622
736
|
this._postMultiTagged = this._postMultiTagged.bind(this);
|
|
623
737
|
}
|
|
624
738
|
|
|
739
|
+
private $collectionDelimiters: { [format: string]: string } = {
|
|
740
|
+
csv: ',',
|
|
741
|
+
ssv: ' ',
|
|
742
|
+
pipes: '|',
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
private $deepObject = (key: string, value: any): string[] => {
|
|
746
|
+
if (value === undefined || value === null) {
|
|
747
|
+
return [];
|
|
748
|
+
}
|
|
749
|
+
if (typeof value !== 'object') {
|
|
750
|
+
return [\`\${key}=\${encodeURIComponent(String(value))}\`];
|
|
751
|
+
}
|
|
752
|
+
return Object.entries(value).flatMap(([prop, v]) =>
|
|
753
|
+
this.$deepObject(\`\${key}[\${encodeURIComponent(prop)}]\`, v),
|
|
754
|
+
);
|
|
755
|
+
};
|
|
756
|
+
|
|
625
757
|
private $url = (
|
|
626
758
|
path: string,
|
|
627
759
|
pathParameters: { [key: string]: any },
|
|
628
760
|
queryParameters: { [key: string]: any },
|
|
629
|
-
collectionFormats?: {
|
|
761
|
+
collectionFormats?: {
|
|
762
|
+
[key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' | 'deepObject';
|
|
763
|
+
},
|
|
630
764
|
): string => {
|
|
631
765
|
const baseUrl = this.$config.url.endsWith('/')
|
|
632
766
|
? this.$config.url.slice(0, -1)
|
|
@@ -637,15 +771,24 @@ export class TestApi {
|
|
|
637
771
|
path,
|
|
638
772
|
);
|
|
639
773
|
const queryString = Object.entries(queryParameters)
|
|
640
|
-
.
|
|
774
|
+
.flatMap(([key, value]) => {
|
|
641
775
|
if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
|
|
642
|
-
return value
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
776
|
+
return value.map(
|
|
777
|
+
(v) => \`\${encodeURIComponent(key)}=\${encodeURIComponent(\`\${v}\`)}\`,
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
if (
|
|
781
|
+
collectionFormats?.[key] === 'deepObject' &&
|
|
782
|
+
value !== null &&
|
|
783
|
+
typeof value === 'object'
|
|
784
|
+
) {
|
|
785
|
+
return this.$deepObject(encodeURIComponent(key), value);
|
|
647
786
|
}
|
|
648
|
-
|
|
787
|
+
const delimiter =
|
|
788
|
+
this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
|
|
789
|
+
return [
|
|
790
|
+
\`\${encodeURIComponent(key)}=\${encodeURIComponent(Array.isArray(value) ? value.map(String).join(delimiter) : String(value))}\`,
|
|
791
|
+
];
|
|
649
792
|
})
|
|
650
793
|
.join('&');
|
|
651
794
|
return (
|
|
@@ -655,13 +798,22 @@ export class TestApi {
|
|
|
655
798
|
|
|
656
799
|
private $headers = (
|
|
657
800
|
headerParameters: { [key: string]: any },
|
|
658
|
-
collectionFormats?: { [key: string]: 'multi' | 'csv' },
|
|
801
|
+
collectionFormats?: { [key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' },
|
|
659
802
|
): [string, string][] => {
|
|
660
803
|
return Object.entries(headerParameters).flatMap(([key, value]) => {
|
|
661
804
|
if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
|
|
662
805
|
return value.map((v) => [key, String(v)]) as [string, string][];
|
|
663
806
|
}
|
|
664
|
-
|
|
807
|
+
const delimiter =
|
|
808
|
+
this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
|
|
809
|
+
return [
|
|
810
|
+
[
|
|
811
|
+
key,
|
|
812
|
+
Array.isArray(value)
|
|
813
|
+
? value.map(String).join(delimiter)
|
|
814
|
+
: String(value),
|
|
815
|
+
],
|
|
816
|
+
];
|
|
665
817
|
});
|
|
666
818
|
};
|
|
667
819
|
|
|
@@ -16,7 +16,19 @@ const uniqStrings = (strings) => {
|
|
|
16
16
|
return true;
|
|
17
17
|
});
|
|
18
18
|
};
|
|
19
|
-
const returnTypeSet = new Set(allOperations.
|
|
19
|
+
const returnTypeSet = new Set(allOperations.flatMap(op => op.result ? [op.result.typescriptType] : []));
|
|
20
|
+
// Names of discriminator "base" models (an object schema whose subtypes allOf-
|
|
21
|
+
// compose it). A subtype composes its base's non-dispatching `$toJsonBase`/
|
|
22
|
+
// `$fromJsonBase` body, so composing the dispatching `toJson`/`fromJson` would
|
|
23
|
+
// recurse infinitely (base -> subtype -> base).
|
|
24
|
+
const discriminatorBaseNames = new Set(models.filter(m => m.discriminator && m.discriminator.isBase).map(m => m.name));
|
|
25
|
+
const modelByName = Object.fromEntries(models.map(m => [m.name, m]));
|
|
26
|
+
// The $IO marshaller call for a composed member: a subtype composes its base's
|
|
27
|
+
// non-dispatching body to avoid recursing back through the base's dispatch.
|
|
28
|
+
const composedMarshaller = (property, method) =>
|
|
29
|
+
property.export === 'reference' && discriminatorBaseNames.has(property.type)
|
|
30
|
+
? `$IO.${property.typescriptType}.$${method}Base`
|
|
31
|
+
: `$IO.${property.typescriptType}.${method}`;
|
|
20
32
|
_%>
|
|
21
33
|
<%_ if ((models.length + allOperations.filter(p => p.parameters.length > 0).length) > 0) { _%>
|
|
22
34
|
import type {
|
|
@@ -44,14 +56,18 @@ const renderToJsonDateValue = (identifier, format) => {
|
|
|
44
56
|
// Renders the appropriate nested function for .map() or $mapValues() for arrays and dictionaries for the given type
|
|
45
57
|
const renderNestedToJsonValue = (type, argumentType = undefined, depth = 0) => {
|
|
46
58
|
const itemIdentifier = `item${depth}`;
|
|
47
|
-
|
|
59
|
+
// Nested items (depth > 0) come from mapping over an `any`, so annotate them
|
|
60
|
+
// to satisfy noImplicitAny.
|
|
61
|
+
const argType = `${argumentType ? `: ${argumentType}` : (depth > 0 ? ': any' : '')}`;
|
|
48
62
|
if (type.isPrimitive || type.typescriptType === 'unknown' || type.export === 'enum' || type.isEnum) {
|
|
49
63
|
return `(${itemIdentifier}${argType}) => ${["date", "date-time"].includes(type.format) ? renderToJsonDateValue(itemIdentifier, type.format) : itemIdentifier}`;
|
|
50
64
|
} else if (type.export === "array") {
|
|
51
65
|
return `(${itemIdentifier}${argType}) => ${itemIdentifier}.map(${renderNestedToJsonValue(type.link, argumentType, depth + 1)})`;
|
|
52
66
|
} else if (type.export === "dictionary") {
|
|
53
67
|
return `(${itemIdentifier}${argType}) => $IO.$mapValues(${itemIdentifier}, ${renderNestedToJsonValue(type.link, argumentType, depth + 1)})`;
|
|
54
|
-
} else if (type.type === 'unknown') {
|
|
68
|
+
} else if (type.type === 'unknown' && !["one-of", "any-of", "all-of"].includes(type.export)) {
|
|
69
|
+
// A bare `unknown` element passes through; a composite has type `unknown`
|
|
70
|
+
// but must still be marshalled via its own $IO entry.
|
|
55
71
|
return `(${itemIdentifier}${argType}) => ${itemIdentifier}`;
|
|
56
72
|
}
|
|
57
73
|
return `$IO.${type.typescriptType || type.typescriptName}.toJson`;
|
|
@@ -83,14 +99,18 @@ const renderToJsonValue = (property, value, argumentType = undefined) => {
|
|
|
83
99
|
// Renders the appropriate nested function for .map() or $mapValues() for arrays and dictionaries for the given type
|
|
84
100
|
const renderNestedFromJsonValue = (type, argumentType = undefined, depth = 0) => {
|
|
85
101
|
const itemIdentifier = `item${depth}`;
|
|
86
|
-
|
|
102
|
+
// Nested items (depth > 0) come from mapping over an `any`, so annotate them
|
|
103
|
+
// to satisfy noImplicitAny.
|
|
104
|
+
const argType = `${argumentType ? `: ${argumentType}` : (depth > 0 ? ': any' : '')}`;
|
|
87
105
|
if (type.isPrimitive || type.typescriptType === 'unknown' || type.export === 'enum' || type.isEnum) {
|
|
88
106
|
return `(${itemIdentifier}${argType}) => ${["date", "date-time"].includes(type.format) ? `new Date(${itemIdentifier})` : itemIdentifier}`;
|
|
89
107
|
} else if (type.export === "array") {
|
|
90
108
|
return `(${itemIdentifier}${argType}) => ${itemIdentifier}.map(${renderNestedFromJsonValue(type.link, argumentType, depth + 1)})`;
|
|
91
109
|
} else if (type.export === "dictionary") {
|
|
92
110
|
return `(${itemIdentifier}${argType}) => $IO.$mapValues(${itemIdentifier}, ${renderNestedFromJsonValue(type.link, argumentType, depth + 1)})`;
|
|
93
|
-
} else if (type.type === 'unknown') {
|
|
111
|
+
} else if (type.type === 'unknown' && !["one-of", "any-of", "all-of"].includes(type.export)) {
|
|
112
|
+
// A bare `unknown` element passes through; a composite has type `unknown`
|
|
113
|
+
// but must still be marshalled via its own $IO entry.
|
|
94
114
|
return `(${itemIdentifier}${argType}) => ${itemIdentifier}`;
|
|
95
115
|
}
|
|
96
116
|
return `$IO.${type.typescriptType || type.typescriptName}.fromJson`;
|
|
@@ -163,13 +183,44 @@ _%>
|
|
|
163
183
|
* Utility for serialisation and deserialisation of API types.
|
|
164
184
|
*/
|
|
165
185
|
export class $IO {
|
|
166
|
-
|
|
186
|
+
public static $mapValues = (data: any, fn: (item: any) => any) =>
|
|
167
187
|
Object.fromEntries(Object.entries(data).map(([k, v]) => [k, fn(v)]));
|
|
168
188
|
<%_ models.filter(m => m.export !== 'enum').forEach((model) => { _%>
|
|
169
189
|
<%_ const isComposite = model.export === "one-of" || model.export === "any-of" || model.export === "all-of"; _%>
|
|
190
|
+
<%_ /* A discriminator base emits its plain (own-fields) body under a $-prefixed
|
|
191
|
+
name that its subtypes compose, while its public toJson/fromJson dispatch
|
|
192
|
+
to the matching subtype — so composing a subtype never recurses back into
|
|
193
|
+
the dispatch. */ _%>
|
|
194
|
+
<%_ const isBase = model.discriminator && model.discriminator.isBase; _%>
|
|
195
|
+
<%_ const toJsonName = isBase ? '$toJsonBase' : 'toJson'; _%>
|
|
196
|
+
<%_ const fromJsonName = isBase ? '$fromJsonBase' : 'fromJson'; _%>
|
|
170
197
|
|
|
171
198
|
public static <%- model.typescriptName %> = {
|
|
199
|
+
<%_ if (isBase) { _%>
|
|
172
200
|
toJson: (model: <%- model.typescriptName %>): any => {
|
|
201
|
+
if (model === undefined || model === null) {
|
|
202
|
+
return model;
|
|
203
|
+
}
|
|
204
|
+
switch ((model as any).<%- model.discriminator.typescriptPropertyName %>) {
|
|
205
|
+
<%_ model.discriminator.mapping.filter(m => modelByName[m.modelName]).forEach(({ value, modelName }) => { _%>
|
|
206
|
+
case <%- JSON.stringify(value) %>: return $IO.<%- modelByName[modelName].typescriptName %>.toJson(model as <%- modelByName[modelName].typescriptName %>);
|
|
207
|
+
<%_ }); _%>
|
|
208
|
+
}
|
|
209
|
+
return $IO.<%- model.typescriptName %>.$toJsonBase(model);
|
|
210
|
+
},
|
|
211
|
+
fromJson: (json: any): <%- model.typescriptName %> => {
|
|
212
|
+
if (json === undefined || json === null) {
|
|
213
|
+
return json;
|
|
214
|
+
}
|
|
215
|
+
switch (json?.[<%- JSON.stringify(model.discriminator.propertyName) %>]) {
|
|
216
|
+
<%_ model.discriminator.mapping.filter(m => modelByName[m.modelName]).forEach(({ value, modelName }) => { _%>
|
|
217
|
+
case <%- JSON.stringify(value) %>: return $IO.<%- modelByName[modelName].typescriptName %>.fromJson(json);
|
|
218
|
+
<%_ }); _%>
|
|
219
|
+
}
|
|
220
|
+
return $IO.<%- model.typescriptName %>.$fromJsonBase(json);
|
|
221
|
+
},
|
|
222
|
+
<%_ } _%>
|
|
223
|
+
<%- toJsonName %>: (model: <%- model.typescriptName %>): any => {
|
|
173
224
|
if (model === undefined || model === null) {
|
|
174
225
|
return model;
|
|
175
226
|
}
|
|
@@ -202,10 +253,25 @@ export class $IO {
|
|
|
202
253
|
return <%- renderToJsonValue(arrayOfNonPrimitives, 'model') %>;
|
|
203
254
|
}
|
|
204
255
|
<%_ } _%>
|
|
256
|
+
<%_ /* A discriminated composite marshals directly to the matching branch,
|
|
257
|
+
rather than merging every branch (which would leak fields from the
|
|
258
|
+
non-matching branches). Unknown values fall through to the merge. */ _%>
|
|
259
|
+
<%_ if (model.discriminator) { _%>
|
|
260
|
+
<%_ const discToJsonByName = Object.fromEntries(model.composedModels.map(m => [m.name, m.typescriptName])); _%>
|
|
261
|
+
switch ((model as any).<%- model.discriminator.typescriptPropertyName %>) {
|
|
262
|
+
<%_ model.discriminator.mapping.filter(m => discToJsonByName[m.modelName]).forEach(({ value, modelName }) => { _%>
|
|
263
|
+
case <%- JSON.stringify(value) %>: return $IO.<%- discToJsonByName[modelName] %>.toJson(model as <%- discToJsonByName[modelName] %>);
|
|
264
|
+
<%_ }); _%>
|
|
265
|
+
}
|
|
266
|
+
<%_ } _%>
|
|
205
267
|
<%_ if (model.composedModels.length > 0) { _%>
|
|
206
268
|
return {
|
|
207
269
|
<%_ model.properties.filter(p => !p.isPrimitive && p.export !== 'array').forEach((property, i) => { _%>
|
|
270
|
+
<%_ if (property.export === 'reference' && discriminatorBaseNames.has(property.type)) { _%>
|
|
271
|
+
...<%- composedMarshaller(property, 'toJson') %>(model),
|
|
272
|
+
<%_ } else { _%>
|
|
208
273
|
...<%- renderToJsonValue(property, `model${(model.export !== 'all-of' && property.export !== 'dictionary') ? ` as ${property.typescriptType}` : ''}`) %>,
|
|
274
|
+
<%_ } _%>
|
|
209
275
|
<%_ }); _%>
|
|
210
276
|
};
|
|
211
277
|
<%_ } else { _%>
|
|
@@ -238,7 +304,7 @@ export class $IO {
|
|
|
238
304
|
};
|
|
239
305
|
<%_ } _%>
|
|
240
306
|
},
|
|
241
|
-
|
|
307
|
+
<%- fromJsonName %>: (json: any): <%- model.typescriptName %> => {
|
|
242
308
|
if (json === undefined || json === null) {
|
|
243
309
|
return json;
|
|
244
310
|
}
|
|
@@ -270,10 +336,25 @@ export class $IO {
|
|
|
270
336
|
return <%- renderFromJsonValue(arrayOfNonPrimitives, 'json') %>;
|
|
271
337
|
}
|
|
272
338
|
<%_ } _%>
|
|
339
|
+
<%_ /* A discriminated composite marshals directly to the matching branch;
|
|
340
|
+
the discriminator value comes off the raw json by its wire name.
|
|
341
|
+
Unknown values fall through to the merge. */ _%>
|
|
342
|
+
<%_ if (model.discriminator) { _%>
|
|
343
|
+
<%_ const discFromJsonByName = Object.fromEntries(model.composedModels.map(m => [m.name, m.typescriptName])); _%>
|
|
344
|
+
switch (json?.[<%- JSON.stringify(model.discriminator.propertyName) %>]) {
|
|
345
|
+
<%_ model.discriminator.mapping.filter(m => discFromJsonByName[m.modelName]).forEach(({ value, modelName }) => { _%>
|
|
346
|
+
case <%- JSON.stringify(value) %>: return $IO.<%- discFromJsonByName[modelName] %>.fromJson(json);
|
|
347
|
+
<%_ }); _%>
|
|
348
|
+
}
|
|
349
|
+
<%_ } _%>
|
|
273
350
|
<%_ if (model.composedModels.length > 0) { _%>
|
|
274
351
|
return {
|
|
275
352
|
<%_ model.properties.filter(p => !p.isPrimitive && p.export !== 'array').forEach((composedType) => { _%>
|
|
353
|
+
<%_ if (composedType.export === 'reference' && discriminatorBaseNames.has(composedType.type)) { _%>
|
|
354
|
+
...<%- composedMarshaller(composedType, 'fromJson') %>(json),
|
|
355
|
+
<%_ } else { _%>
|
|
276
356
|
...<%- renderFromJsonValue(composedType, 'json') %>,
|
|
357
|
+
<%_ } _%>
|
|
277
358
|
<%_ }); _%>
|
|
278
359
|
};
|
|
279
360
|
<%_ } else { _%>
|
|
@@ -355,26 +436,45 @@ export class <%- className %> {
|
|
|
355
436
|
<%_ }); _%>
|
|
356
437
|
}
|
|
357
438
|
|
|
358
|
-
private $
|
|
439
|
+
private $collectionDelimiters: { [format: string]: string } = { csv: ',', ssv: ' ', pipes: '|' };
|
|
440
|
+
|
|
441
|
+
private $deepObject = (key: string, value: any): string[] => {
|
|
442
|
+
if (value === undefined || value === null) {
|
|
443
|
+
return [];
|
|
444
|
+
}
|
|
445
|
+
if (typeof value !== 'object') {
|
|
446
|
+
return [`${key}=${encodeURIComponent(String(value))}`];
|
|
447
|
+
}
|
|
448
|
+
return Object.entries(value).flatMap(([prop, v]) =>
|
|
449
|
+
this.$deepObject(`${key}[${encodeURIComponent(prop)}]`, v),
|
|
450
|
+
);
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
private $url = (path: string, pathParameters: { [key: string]: any }, queryParameters: { [key: string]: any }, collectionFormats?: { [key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' | 'deepObject' }): string => {
|
|
359
454
|
const baseUrl = this.$config.url.endsWith('/') ? this.$config.url.slice(0, -1) : this.$config.url;
|
|
360
455
|
const pathWithParameters = Object.entries(pathParameters).reduce((withParams, [key, value]) =>
|
|
361
456
|
withParams.replace(`{${key}}`, encodeURIComponent(`${value}`))
|
|
362
457
|
, path);
|
|
363
|
-
const queryString = Object.entries(queryParameters).
|
|
458
|
+
const queryString = Object.entries(queryParameters).flatMap(([key, value]) => {
|
|
364
459
|
if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
|
|
365
|
-
return value.map(v => `${encodeURIComponent(key)}=${encodeURIComponent(`${v}`)}`)
|
|
460
|
+
return value.map(v => `${encodeURIComponent(key)}=${encodeURIComponent(`${v}`)}`);
|
|
461
|
+
}
|
|
462
|
+
if (collectionFormats?.[key] === 'deepObject' && value !== null && typeof value === 'object') {
|
|
463
|
+
return this.$deepObject(encodeURIComponent(key), value);
|
|
366
464
|
}
|
|
367
|
-
|
|
465
|
+
const delimiter = this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
|
|
466
|
+
return [`${encodeURIComponent(key)}=${encodeURIComponent(Array.isArray(value) ? value.map(String).join(delimiter) : String(value))}`];
|
|
368
467
|
}).join('&');
|
|
369
468
|
return baseUrl + pathWithParameters + (queryString ? `?${queryString}` : '');
|
|
370
469
|
};
|
|
371
470
|
|
|
372
|
-
private $headers = (headerParameters: { [key: string]: any }, collectionFormats?: { [key: string]: 'multi' | 'csv' }): [string, string][] => {
|
|
471
|
+
private $headers = (headerParameters: { [key: string]: any }, collectionFormats?: { [key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' }): [string, string][] => {
|
|
373
472
|
return Object.entries(headerParameters).flatMap(([key, value]) => {
|
|
374
473
|
if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
|
|
375
474
|
return value.map(v => [key, String(v)]) as [string, string][];
|
|
376
475
|
}
|
|
377
|
-
|
|
476
|
+
const delimiter = this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
|
|
477
|
+
return [[key, Array.isArray(value) ? value.map(String).join(delimiter) : String(value)]];
|
|
378
478
|
});
|
|
379
479
|
};
|
|
380
480
|
|
|
@@ -418,9 +518,21 @@ export class <%- className %> {
|
|
|
418
518
|
}
|
|
419
519
|
<%_ } _%>
|
|
420
520
|
<%_ } _%>
|
|
421
|
-
<%_
|
|
422
|
-
|
|
423
|
-
|
|
521
|
+
<%_ /* Query and header collection formats are kept in separate maps: a
|
|
522
|
+
query and a header parameter may share a name, which would collide
|
|
523
|
+
in a single object literal. */ _%>
|
|
524
|
+
<%_ const queryCollectionParams = op.parameters.filter(p => p.collectionFormat && p.in === 'query'); _%>
|
|
525
|
+
<%_ const headerCollectionParams = op.parameters.filter(p => p.collectionFormat && p.in === 'header'); _%>
|
|
526
|
+
<%_ if (queryCollectionParams.length > 0) { _%>
|
|
527
|
+
const queryCollectionFormats = {
|
|
528
|
+
<%_ queryCollectionParams.forEach((parameter) => { _%>
|
|
529
|
+
'<%- parameter.prop %>': '<%- parameter.collectionFormat %>',
|
|
530
|
+
<%_ }); _%>
|
|
531
|
+
} as const;
|
|
532
|
+
<%_ } _%>
|
|
533
|
+
<%_ if (headerCollectionParams.length > 0) { _%>
|
|
534
|
+
const headerCollectionFormats = {
|
|
535
|
+
<%_ headerCollectionParams.forEach((parameter) => { _%>
|
|
424
536
|
'<%- parameter.prop %>': '<%- parameter.collectionFormat %>',
|
|
425
537
|
<%_ }); _%>
|
|
426
538
|
} as const;
|
|
@@ -457,8 +569,8 @@ export class <%- className %> {
|
|
|
457
569
|
const body = undefined;
|
|
458
570
|
<%_ } _%>
|
|
459
571
|
|
|
460
|
-
const response = await this.$fetch(this.$url('<%- op.path %>', pathParameters, queryParameters<% if (
|
|
461
|
-
headers: this.$headers(headerParameters<% if (
|
|
572
|
+
const response = await this.$fetch(this.$url('<%- op.path %>', pathParameters, queryParameters<% if (queryCollectionParams.length > 0) { %>, queryCollectionFormats<% } %>), {
|
|
573
|
+
headers: this.$headers(headerParameters<% if (headerCollectionParams.length > 0) { %>, headerCollectionFormats<% } %>),
|
|
462
574
|
method: '<%- op.method %>',
|
|
463
575
|
body,
|
|
464
576
|
});
|
|
@@ -22,7 +22,8 @@ _%>
|
|
|
22
22
|
<%_ if (model.export === "enum") { _%>
|
|
23
23
|
<%- docString(model, '') %>export type <%= model.typescriptName %> =
|
|
24
24
|
<%_ model.enum.forEach((enumMember, i) => { _%>
|
|
25
|
-
|
|
25
|
+
<%_ /* JSON.stringify escapes quotes, newlines and backslashes in values */ _%>
|
|
26
|
+
| <%- JSON.stringify(`${enumMember.value}`) %>
|
|
26
27
|
<%_ }); _%>
|
|
27
28
|
<%_ } else if (isComposite) { _%>
|
|
28
29
|
<%- docString(model, '') %>export type <%- model.typescriptName %> =<% model.properties.forEach((composedType, i) => { %><% if (i > 0) { %><% if (model.export === "all-of") { %> &<% } else { %> |<% } %><% } %> <%- composedType.typescriptType %><% }); %>;
|
|
@@ -30,9 +31,8 @@ _%>
|
|
|
30
31
|
<%- docString(model, '') %>export type <%= model.typescriptName %> = <% if (model.isNullable && model.type !== 'null') { %>null | <% } %>{
|
|
31
32
|
<%_ if (model.export === "dictionary" && model.link) { _%>
|
|
32
33
|
<%_ /* When the spec says `type: object` with `additionalProperties: true`
|
|
33
|
-
(or omits additionalProperties),
|
|
34
|
-
|
|
35
|
-
emitted code valid. */ _%>
|
|
34
|
+
(or omits additionalProperties), the value model has an unknown type —
|
|
35
|
+
fall back to `unknown` to keep the emitted code valid. */ _%>
|
|
36
36
|
<%- docString(model.link, ' ') %> [key: string]: <%- model.link.typescriptType || 'unknown' %>;
|
|
37
37
|
<%_ } _%>
|
|
38
38
|
<%_ model.properties.forEach((property) => { _%>
|