@arrirpc/codegen-swift 0.60.0

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.cjs ADDED
@@ -0,0 +1,1536 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const codegenUtils = require('@arrirpc/codegen-utils');
5
+
6
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
7
+
8
+ const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
9
+
10
+ function isNullableType(schema, context) {
11
+ return schema.nullable === true || context.isOptional === true;
12
+ }
13
+ function validTypeName(input) {
14
+ const formatted = codegenUtils.removeDisallowedChars(
15
+ codegenUtils.pascalCase(input.split("[").join("_").split("]").join("_"), {
16
+ normalize: true
17
+ }),
18
+ illegalPropertyChars
19
+ );
20
+ if (reservedKeywords[formatted]) {
21
+ return `_${formatted}`;
22
+ }
23
+ if (codegenUtils.stringStartsWithNumber(formatted)) {
24
+ return `_${formatted}`;
25
+ }
26
+ return formatted;
27
+ }
28
+ function getTypeName(schema, context) {
29
+ if (schema.metadata?.id) {
30
+ const typeName2 = validTypeName(schema.metadata.id);
31
+ return typeName2;
32
+ }
33
+ if (context.discriminatorParent && context.discriminatorValue) {
34
+ const typeName2 = validTypeName(
35
+ `${context.discriminatorParent}_${context.discriminatorValue}`
36
+ );
37
+ return typeName2;
38
+ }
39
+ const typeName = validTypeName(context.instancePath.split("/").join("_"));
40
+ return typeName;
41
+ }
42
+ const reservedKeywords = {
43
+ associatedType: true,
44
+ class: true,
45
+ deinit: true,
46
+ enum: true,
47
+ extension: true,
48
+ fileprivate: true,
49
+ func: true,
50
+ import: true,
51
+ init: true,
52
+ inout: true,
53
+ internal: true,
54
+ let: true,
55
+ open: true,
56
+ operator: true,
57
+ private: true,
58
+ precedencegroup: true,
59
+ protocol: true,
60
+ public: true,
61
+ rethrows: true,
62
+ static: true,
63
+ subscript: true,
64
+ typealias: true,
65
+ var: true,
66
+ break: true,
67
+ case: true,
68
+ catch: true,
69
+ continue: true,
70
+ default: true,
71
+ defer: true,
72
+ do: true,
73
+ else: true,
74
+ fallthrough: true,
75
+ for: true,
76
+ guard: true,
77
+ if: true,
78
+ in: true,
79
+ repeat: true,
80
+ return: true,
81
+ throw: true,
82
+ switch: true,
83
+ where: true,
84
+ while: true,
85
+ Any: true,
86
+ as: true,
87
+ false: true,
88
+ is: true,
89
+ nil: true,
90
+ self: true,
91
+ Self: true,
92
+ super: true,
93
+ true: true,
94
+ try: true
95
+ };
96
+ const illegalPropertyChars = "!@#$%^&*()+=[]{}\\|;:'\",./?><`~";
97
+ function validSwiftKey(input) {
98
+ const key = codegenUtils.removeDisallowedChars(
99
+ codegenUtils.camelCase(input, { normalize: true }),
100
+ illegalPropertyChars
101
+ );
102
+ if (reservedKeywords[key]) {
103
+ return `\`${key}\``;
104
+ }
105
+ if (codegenUtils.stringStartsWithNumber(key)) {
106
+ return `_${key}`;
107
+ }
108
+ return key;
109
+ }
110
+ function codeComments(schema, leading = "") {
111
+ const description = schema.metadata?.description?.split("\n").map((line) => `${leading}/// ${line}`).join("\n");
112
+ if (description && schema.metadata?.isDeprecated) {
113
+ return `${description}
114
+ ${leading}@available(*, deprecated)
115
+ `;
116
+ }
117
+ if (description) {
118
+ return `${description}
119
+ `;
120
+ }
121
+ if (schema.metadata?.isDeprecated) {
122
+ return `${leading}@available(*, deprecated)
123
+ `;
124
+ }
125
+ return "";
126
+ }
127
+
128
+ function swiftAnyFromSchema(schema, context) {
129
+ const isNullable = isNullableType(schema, context);
130
+ let defaultValue = "JSON()";
131
+ if (schema.nullable) {
132
+ defaultValue = 'JSON(parseJSON: "null")';
133
+ } else if (context.isOptional) {
134
+ defaultValue = "";
135
+ }
136
+ return {
137
+ typeName: context.isOptional ? "JSON?" : "JSON",
138
+ defaultValue,
139
+ isNullable,
140
+ canBeQueryString: false,
141
+ hasRequiredRef: false,
142
+ fromJsonTemplate(input, target) {
143
+ if (isNullable) {
144
+ return ` if ${input}.exists() {
145
+ ${target} = ${input}
146
+ }`;
147
+ }
148
+ return ` ${target} = ${input}`;
149
+ },
150
+ toJsonTemplate(input, target) {
151
+ if (context.isOptional) {
152
+ return ` ${target} += serializeAny(input: ${input}!)`;
153
+ }
154
+ return ` ${target} += serializeAny(input: ${input})`;
155
+ },
156
+ toQueryPartTemplate(_, __, ___) {
157
+ return ` print("[WARNING] any's cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
158
+ },
159
+ content: ""
160
+ };
161
+ }
162
+
163
+ function swiftArrayFromSchema(schema, context) {
164
+ const subType = swiftTypeFromSchema(schema.elements, {
165
+ clientVersion: context.clientVersion,
166
+ clientName: context.clientName,
167
+ typePrefix: context.typePrefix,
168
+ instancePath: `${context.instancePath}/[element]`,
169
+ schemaPath: `${context.schemaPath}/elements`,
170
+ generatedTypes: context.generatedTypes,
171
+ containsRequiredRef: context.containsRequiredRef
172
+ });
173
+ const isNullable = isNullableType(schema, context);
174
+ const typeName = isNullable ? `[${subType.typeName}]?` : `[${subType.typeName}]`;
175
+ const defaultValue = isNullable ? "" : "[]";
176
+ return {
177
+ typeName,
178
+ isNullable,
179
+ defaultValue,
180
+ canBeQueryString: false,
181
+ hasRequiredRef: false,
182
+ fromJsonTemplate(input, target, key) {
183
+ const innerKey = validSwiftKey(key);
184
+ const mainContent = ` ${target} = []
185
+ for __${innerKey}JsonElement in ${input}.array ?? [] {
186
+ var __${innerKey}JsonElementValue: ${subType.typeName}
187
+ ${subType.fromJsonTemplate(`__${innerKey}JsonElement`, `__${innerKey}JsonElementValue`, `element`)}
188
+ ${target}${isNullable ? "!" : ""}.append(__${innerKey}JsonElementValue)
189
+ }`;
190
+ if (context.isOptional) {
191
+ return ` if ${input}.exists() {
192
+ ${mainContent}
193
+ }`;
194
+ }
195
+ if (schema.nullable) {
196
+ return ` if ${input}.array != nil {
197
+ ${mainContent}
198
+ }`;
199
+ }
200
+ return mainContent;
201
+ },
202
+ toJsonTemplate(input, target) {
203
+ const mainContent = ` ${target} += "["
204
+ for (__index, __element) in ${input}${isNullable ? "!" : ""}.enumerated() {
205
+ if __index > 0 {
206
+ ${target} += ","
207
+ }
208
+ ${subType.toJsonTemplate(`__element`, target)}
209
+ }
210
+ ${target} += "]"`;
211
+ if (schema.nullable) {
212
+ return ` if ${input} != nil {
213
+ ${mainContent}
214
+ } else {
215
+ ${target} += "null"
216
+ }`;
217
+ }
218
+ return mainContent;
219
+ },
220
+ toQueryPartTemplate(_, __, ___) {
221
+ return ` print("[WARNING] arrays cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
222
+ },
223
+ cloneTemplate(input, key) {
224
+ const innerKey = validSwiftKey(key);
225
+ const subTypeClonedResult = subType.cloneTemplate?.(
226
+ `__${innerKey}Element`,
227
+ `__${innerKey}Element`
228
+ );
229
+ if (isNullable) {
230
+ return {
231
+ bodyContent: `var __${innerKey}Cloned: ${typeName}
232
+ if ${input} != nil {
233
+ __${innerKey}Cloned = []
234
+ for __${innerKey}Element in ${input}! {
235
+ ${subTypeClonedResult?.bodyContent ?? ""}
236
+ __${innerKey}Cloned!.append(${subTypeClonedResult?.fieldContent || `__${innerKey}Element`})
237
+ }
238
+ }`,
239
+ fieldContent: `__${innerKey}Cloned`
240
+ };
241
+ }
242
+ return {
243
+ bodyContent: `var __${innerKey}Cloned: ${typeName} = []
244
+ for __${innerKey}Element in ${input} {
245
+ ${subTypeClonedResult?.bodyContent ?? ""}
246
+ __${innerKey}Cloned.append(${subTypeClonedResult?.fieldContent || `__${innerKey}Element`})
247
+ }`,
248
+ fieldContent: `__${innerKey}Cloned`
249
+ };
250
+ },
251
+ content: subType.content
252
+ };
253
+ }
254
+
255
+ function swiftObjectFromSchema(schema, context) {
256
+ const typeName = getTypeName(schema, context);
257
+ const prefixedTypeName = `${context.typePrefix}${typeName}`;
258
+ const isNullable = isNullableType(schema, context);
259
+ const defaultValue = isNullable ? "" : `${prefixedTypeName}()`;
260
+ const result = {
261
+ typeName: isNullable ? `${prefixedTypeName}?` : prefixedTypeName,
262
+ defaultValue,
263
+ isNullable,
264
+ canBeQueryString: false,
265
+ hasRequiredRef: context.containsRequiredRef[typeName] ?? false,
266
+ fromJsonTemplate(input, target) {
267
+ if (context.isOptional) {
268
+ return ` if ${input}.exists() {
269
+ ${target} = ${prefixedTypeName}(json: ${input})
270
+ }`;
271
+ }
272
+ if (schema.nullable) {
273
+ return ` if ${input}.dictionary != nil {
274
+ ${target} = ${prefixedTypeName}(json: ${input})
275
+ }`;
276
+ }
277
+ return ` ${target} = ${prefixedTypeName}(json: ${input})`;
278
+ },
279
+ toJsonTemplate(input, target) {
280
+ if (context.isOptional) {
281
+ return ` ${target} += ${input}!.toJSONString()`;
282
+ }
283
+ if (schema.nullable) {
284
+ return ` if ${input} != nil {
285
+ ${target} += ${input}!.toJSONString()
286
+ } else {
287
+ ${target} += "null"
288
+ }`;
289
+ }
290
+ return ` ${target} += ${input}.toJSONString()`;
291
+ },
292
+ toQueryPartTemplate(_, __, ___) {
293
+ return ` print("[WARNING] nested objects cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
294
+ },
295
+ cloneTemplate(input, _key) {
296
+ let fieldContent = `${input}.clone()`;
297
+ if (isNullable) {
298
+ fieldContent = `${input}?.clone()`;
299
+ }
300
+ return {
301
+ tempKey: "",
302
+ bodyContent: "",
303
+ fieldContent
304
+ };
305
+ },
306
+ content: ""
307
+ };
308
+ if (context.generatedTypes.includes(typeName)) {
309
+ return result;
310
+ }
311
+ const fieldNames = [];
312
+ const fieldNameParts = [];
313
+ const initArgParts = [];
314
+ const initBodyParts = [];
315
+ const initFromJsonParts = [];
316
+ const toJsonParts = [];
317
+ const toQueryStringParts = [];
318
+ const cloneBodyParts = [];
319
+ const cloneFieldParts = [];
320
+ const subContent = [];
321
+ let numKeys = 0;
322
+ let canBeQueryString = false;
323
+ let hasRecursiveSubType = false;
324
+ if (context.discriminatorKey && context.discriminatorValue) {
325
+ numKeys++;
326
+ canBeQueryString = true;
327
+ const discriminatorKey = validSwiftKey(context.discriminatorKey);
328
+ fieldNames.push(discriminatorKey);
329
+ fieldNameParts.push(
330
+ ` let ${discriminatorKey}: String = "${context.discriminatorValue}"`
331
+ );
332
+ toJsonParts.push(
333
+ ` __json += "\\"${context.discriminatorKey}\\":\\"${context.discriminatorValue}\\""`
334
+ );
335
+ toQueryStringParts.push(
336
+ ` __queryParts.append(URLQueryItem(name: "${context.discriminatorKey}", value: "${context.discriminatorValue}"))`
337
+ );
338
+ }
339
+ for (const key of Object.keys(schema.properties)) {
340
+ const subSchema = schema.properties[key];
341
+ const subType = swiftTypeFromSchema(subSchema, {
342
+ clientVersion: context.clientVersion,
343
+ clientName: context.clientName,
344
+ typePrefix: context.typePrefix,
345
+ instancePath: `/${typeName}/${key}`,
346
+ schemaPath: `${context.schemaPath}/properties/${key}`,
347
+ generatedTypes: context.generatedTypes,
348
+ containsRequiredRef: context.containsRequiredRef
349
+ });
350
+ if (subType.content)
351
+ subContent.push(subType.content);
352
+ if (subType.hasRequiredRef && !subType.isNullable) {
353
+ context.containsRequiredRef[typeName] = true;
354
+ result.hasRequiredRef = true;
355
+ }
356
+ if (codegenUtils.isSchemaFormRef(subSchema)) {
357
+ hasRecursiveSubType = true;
358
+ }
359
+ if (subType.canBeQueryString)
360
+ canBeQueryString = true;
361
+ const fieldName = validSwiftKey(key);
362
+ fieldNames.push(fieldName);
363
+ if (subType.defaultValue) {
364
+ fieldNameParts.push(
365
+ `${codeComments(subSchema, " ")} public var ${fieldName}: ${subType.typeName} = ${subType.defaultValue}`
366
+ );
367
+ } else {
368
+ fieldNameParts.push(
369
+ `${codeComments(subSchema, " ")} public var ${fieldName}: ${subType.typeName}`
370
+ );
371
+ }
372
+ initArgParts.push(` ${fieldName}: ${subType.typeName}`);
373
+ initBodyParts.push(` self.${fieldName} = ${fieldName}`);
374
+ initFromJsonParts.push(
375
+ subType.fromJsonTemplate(
376
+ `json["${key}"]`,
377
+ `self.${fieldName}`,
378
+ key
379
+ )
380
+ );
381
+ if (numKeys > 0) {
382
+ toJsonParts.push(` __json += ",\\"${key}\\":"`);
383
+ } else {
384
+ toJsonParts.push(` __json += "\\"${key}\\":"`);
385
+ }
386
+ toJsonParts.push(subType.toJsonTemplate(`self.${fieldName}`, `__json`));
387
+ if (subType.canBeQueryString)
388
+ canBeQueryString = true;
389
+ toQueryStringParts.push(
390
+ subType.toQueryPartTemplate(
391
+ `self.${fieldName}`,
392
+ `__queryParts`,
393
+ key
394
+ )
395
+ );
396
+ const cloneResult = subType.cloneTemplate?.(
397
+ `self.${fieldName}`,
398
+ fieldName
399
+ );
400
+ if (cloneResult) {
401
+ cloneBodyParts.push(cloneResult.bodyContent);
402
+ cloneFieldParts.push(
403
+ ` ${fieldName}: ${cloneResult.fieldContent}`
404
+ );
405
+ } else {
406
+ cloneFieldParts.push(
407
+ ` ${fieldName.split("`").join("")}: self.${fieldName}`
408
+ );
409
+ }
410
+ numKeys++;
411
+ }
412
+ let numOptionalKeys = 0;
413
+ for (const key of Object.keys(schema.optionalProperties ?? {})) {
414
+ const subSchema = schema.optionalProperties[key];
415
+ const subType = swiftTypeFromSchema(subSchema, {
416
+ clientVersion: context.clientVersion,
417
+ clientName: context.clientName,
418
+ typePrefix: context.typePrefix,
419
+ instancePath: `/${typeName}/${key}`,
420
+ schemaPath: `${context.schemaPath}/optionalProperties/${key}`,
421
+ generatedTypes: context.generatedTypes,
422
+ isOptional: true,
423
+ containsRequiredRef: context.containsRequiredRef
424
+ });
425
+ if (subType.content)
426
+ subContent.push(subType.content);
427
+ if (codegenUtils.isSchemaFormRef(subSchema)) {
428
+ hasRecursiveSubType = true;
429
+ }
430
+ if (subType.canBeQueryString)
431
+ canBeQueryString = true;
432
+ const fieldName = validSwiftKey(key);
433
+ fieldNames.push(fieldName);
434
+ fieldNameParts.push(
435
+ `${codeComments(subSchema, " ")} public var ${fieldName}: ${subType.typeName}`
436
+ );
437
+ initArgParts.push(` ${fieldName}: ${subType.typeName}`);
438
+ initBodyParts.push(` self.${fieldName} = ${fieldName}`);
439
+ initFromJsonParts.push(
440
+ subType.fromJsonTemplate(
441
+ `json["${key}"]`,
442
+ `self.${fieldName}`,
443
+ key
444
+ )
445
+ );
446
+ let toJsonContent = ``;
447
+ if (numKeys > 0) {
448
+ toJsonContent += ` __json += ",\\"${key}\\":"
449
+ `;
450
+ } else {
451
+ if (numOptionalKeys > 0) {
452
+ toJsonContent += ` if __numKeys > 0 {
453
+ __json += ","
454
+ }
455
+ `;
456
+ }
457
+ toJsonContent += ` __json += "\\"${key}\\":"
458
+ `;
459
+ }
460
+ toJsonContent += subType.toJsonTemplate(`self.${fieldName}`, `__json`);
461
+ if (numKeys === 0) {
462
+ toJsonContent += `
463
+ __numKeys += 1`;
464
+ }
465
+ toJsonParts.push(` if self.${fieldName} != nil {
466
+ ${toJsonContent}
467
+ }`);
468
+ if (subType.canBeQueryString)
469
+ canBeQueryString = true;
470
+ toQueryStringParts.push(
471
+ subType.toQueryPartTemplate(
472
+ `self.${fieldName}`,
473
+ `__queryParts`,
474
+ key
475
+ )
476
+ );
477
+ const cloneResult = subType.cloneTemplate?.(
478
+ `self.${fieldName}`,
479
+ fieldName
480
+ );
481
+ if (cloneResult) {
482
+ cloneBodyParts.push(cloneResult.bodyContent);
483
+ cloneFieldParts.push(
484
+ ` ${fieldName}: ${cloneResult.fieldContent}`
485
+ );
486
+ } else {
487
+ cloneFieldParts.push(
488
+ ` ${fieldName.split("`").join("")}: self.${fieldName}`
489
+ );
490
+ }
491
+ numOptionalKeys++;
492
+ }
493
+ const declaration = hasRecursiveSubType ? `final class` : "struct";
494
+ const initPrefix = hasRecursiveSubType ? `public required` : `public`;
495
+ const initJsonStringPrefix = hasRecursiveSubType ? `public required convenience` : `public`;
496
+ let equalsPart = "";
497
+ if (hasRecursiveSubType) {
498
+ equalsPart = `public static func == (lhs: ${prefixedTypeName}, rhs: ${prefixedTypeName}) -> Bool {
499
+ return
500
+ ${fieldNames.map((field) => ` lhs.${field} == rhs.${field}`).join(" &&\n")}
501
+ }`;
502
+ }
503
+ result.content = `${codeComments(schema)}public ${declaration} ${prefixedTypeName}: ArriClientModel {
504
+ ${fieldNameParts.join("\n")}
505
+ ${initPrefix} init(
506
+ ${initArgParts.join(",\n")}
507
+ ) {
508
+ ${initBodyParts.join("\n")}
509
+ }
510
+ ${initPrefix} init() {}
511
+ ${initPrefix} init(json: JSON) {
512
+ ${initFromJsonParts.join("\n")}
513
+ }
514
+ ${initJsonStringPrefix} init(JSONData: Data) {
515
+ do {
516
+ let json = try JSON(data: JSONData)
517
+ self.init(json: json)
518
+ } catch {
519
+ print("[WARNING] Error parsing JSON: \\(error)")
520
+ self.init()
521
+ }
522
+ }
523
+ ${initJsonStringPrefix} init(JSONString: String) {
524
+ do {
525
+ let json = try JSON(data: JSONString.data(using: .utf8) ?? Data())
526
+ self.init(json: json)
527
+ } catch {
528
+ print("[WARNING] Error parsing JSON: \\(error)")
529
+ self.init()
530
+ }
531
+ }
532
+ public func toJSONString() -> String {
533
+ var __json = "{"
534
+ ${numKeys === 0 ? ` var __numKeys = 0` : ""}
535
+ ${toJsonParts.join("\n")}
536
+ __json += "}"
537
+ return __json
538
+ }
539
+ public func toURLQueryParts() -> [URLQueryItem] {
540
+ ${canBeQueryString ? `var __queryParts: [URLQueryItem] = []` : ""}
541
+ ${toQueryStringParts.join("\n")}
542
+ ${canBeQueryString ? `return __queryParts` : `return []`}
543
+ }
544
+ public func clone() -> ${prefixedTypeName} {
545
+ ${cloneBodyParts.join("\n")}
546
+ return ${prefixedTypeName}(
547
+ ${cloneFieldParts.join(",\n")}
548
+ )
549
+ }
550
+ ${equalsPart}
551
+ }
552
+
553
+ ${subContent.join("\n")}`;
554
+ context.generatedTypes.push(typeName);
555
+ return result;
556
+ }
557
+
558
+ function swiftTaggedUnionFromSchema(schema, context) {
559
+ const typeName = getTypeName(schema, context);
560
+ const prefixedTypeName = `${context.typePrefix}${typeName}`;
561
+ const isNullable = isNullableType(schema, context);
562
+ const defaultValue = isNullable ? `` : `${prefixedTypeName}()`;
563
+ const result = {
564
+ typeName: isNullable ? `${prefixedTypeName}?` : prefixedTypeName,
565
+ isNullable,
566
+ defaultValue,
567
+ canBeQueryString: false,
568
+ hasRequiredRef: context.containsRequiredRef[typeName] ?? false,
569
+ fromJsonTemplate(input, target, _) {
570
+ if (context.isOptional) {
571
+ return ` if ${input}.exists() {
572
+ ${target} = ${prefixedTypeName}(json: ${input})
573
+ }`;
574
+ }
575
+ if (schema.nullable) {
576
+ return ` if ${input}.dictionary != nil {
577
+ ${target} = ${prefixedTypeName}(json: ${input})
578
+ }`;
579
+ }
580
+ return ` ${target} = ${prefixedTypeName}(json: ${input})`;
581
+ },
582
+ toJsonTemplate(input, target) {
583
+ if (context.isOptional) {
584
+ return ` ${target} += ${input}!.toJSONString()`;
585
+ }
586
+ if (schema.nullable) {
587
+ return ` if ${input} != nil {
588
+ ${target} += ${input}!.toJSONString()
589
+ } else {
590
+ ${target} += "null"
591
+ }`;
592
+ }
593
+ return ` ${target} += ${input}.toJSONString()`;
594
+ },
595
+ toQueryPartTemplate(_, __, ___) {
596
+ return ` print("[WARNING] nested objects cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
597
+ },
598
+ cloneTemplate(input, _) {
599
+ return {
600
+ fieldContent: `${input}${isNullable ? "?" : ""}.clone()`,
601
+ bodyContent: ""
602
+ };
603
+ },
604
+ content: ""
605
+ };
606
+ if (context.generatedTypes.includes(typeName)) {
607
+ return result;
608
+ }
609
+ const discriminatorParts = [];
610
+ const discriminatorKey = schema.discriminator;
611
+ for (const key of Object.keys(schema.mapping)) {
612
+ const discriminatorValue = key;
613
+ const subSchema = schema.mapping[key];
614
+ const subType = swiftObjectFromSchema(subSchema, {
615
+ clientVersion: context.clientVersion,
616
+ clientName: context.clientName,
617
+ typePrefix: context.typePrefix,
618
+ instancePath: context.instancePath,
619
+ schemaPath: `${context.schemaPath}/mapping/${key}`,
620
+ generatedTypes: context.generatedTypes,
621
+ discriminatorKey,
622
+ discriminatorParent: typeName,
623
+ discriminatorValue: key,
624
+ containsRequiredRef: context.containsRequiredRef
625
+ });
626
+ const discriminatorCase = validSwiftKey(key);
627
+ const discriminatorPart = {
628
+ discriminatorValue,
629
+ discriminatorCase,
630
+ hasRequiredRef: subType.hasRequiredRef,
631
+ typeName: subType.typeName.replace("?", ""),
632
+ content: subType.content
633
+ };
634
+ discriminatorParts.push(discriminatorPart);
635
+ }
636
+ if (!discriminatorParts.length) {
637
+ throw new Error(
638
+ `Invalid schema at ${context.schemaPath}. Discriminators must have at least one mapping.`
639
+ );
640
+ }
641
+ let defaultPart;
642
+ for (const part of discriminatorParts) {
643
+ if (part.hasRequiredRef)
644
+ continue;
645
+ defaultPart = part;
646
+ break;
647
+ }
648
+ if (!defaultPart) {
649
+ throw new Error(
650
+ `Invalid schema a ${context.schemaPath}. All subtypes have a required recursive reference. This creates an infinite loop.`
651
+ );
652
+ }
653
+ result.content = `${codeComments(schema)}public enum ${prefixedTypeName}: ArriClientModel {
654
+ ${discriminatorParts.map((part) => ` case ${part.discriminatorCase}(${part.typeName})`).join("\n")}
655
+ public init() {
656
+ self = .${defaultPart.discriminatorCase}(${defaultPart.typeName}())
657
+ }
658
+ public init(json: JSON) {
659
+ let discriminator = json["${discriminatorKey}"].string ?? ""
660
+ switch (discriminator) {
661
+ ${discriminatorParts.map(
662
+ (part) => ` case "${part.discriminatorValue}":
663
+ self = .${part.discriminatorCase}(${part.typeName}(json: json))
664
+ break`
665
+ ).join("\n")}
666
+ default:
667
+ self = .${defaultPart.discriminatorCase}(${defaultPart.typeName}())
668
+ break
669
+ }
670
+ }
671
+ public init(JSONData: Data) {
672
+ do {
673
+ let json = try JSON(data: JSONData)
674
+ self.init(json: json)
675
+ } catch {
676
+ print("[WARNING] Error parsing JSON: \\(error)")
677
+ self.init()
678
+ }
679
+ }
680
+ public init(JSONString: String) {
681
+ do {
682
+ let json = try JSON(data: JSONString.data(using: .utf8) ?? Data())
683
+ self.init(json: json)
684
+ } catch {
685
+ print("[WARNING] Error parsing JSON: \\(error)")
686
+ self.init()
687
+ }
688
+ }
689
+ public func toJSONString() -> String {
690
+ switch(self) {
691
+ ${discriminatorParts.map(
692
+ (part) => ` case .${part.discriminatorCase}(let __innerVal):
693
+ return __innerVal.toJSONString()`
694
+ ).join("\n")}
695
+ }
696
+ }
697
+ public func toURLQueryParts() -> [URLQueryItem] {
698
+ switch(self) {
699
+ ${discriminatorParts.map(
700
+ (part) => ` case .${part.discriminatorCase}(let __innerVal):
701
+ return __innerVal.toURLQueryParts()`
702
+ ).join("\n")}
703
+ }
704
+ }
705
+ public func clone() -> ${prefixedTypeName} {
706
+ switch(self) {
707
+ ${discriminatorParts.map(
708
+ (part) => ` case .${part.discriminatorCase}(let __innerVal):
709
+ return .${part.discriminatorCase}(__innerVal.clone())`
710
+ ).join("\n")}
711
+ }
712
+ }
713
+ }
714
+
715
+ ${discriminatorParts.map((part) => part.content).join("\n")}`;
716
+ context.generatedTypes.push(typeName);
717
+ return result;
718
+ }
719
+
720
+ function swiftEnumFromSchema(schema, context) {
721
+ if (!schema.enum[0]) {
722
+ throw new Error(
723
+ `Error at ${context.instancePath}. Must have at least one enum value.`
724
+ );
725
+ }
726
+ const typeName = getTypeName(schema, context);
727
+ const isNullable = isNullableType(schema, context);
728
+ const defaultEnumValue = codegenUtils.camelCase(schema.enum[0], { normalize: true });
729
+ const prefixedTypeName = `${context.typePrefix}${typeName}`;
730
+ const defaultValue = isNullable ? "" : `${prefixedTypeName}.${defaultEnumValue}`;
731
+ const result = {
732
+ typeName: isNullable ? `${typeName}?` : typeName,
733
+ isNullable,
734
+ defaultValue,
735
+ canBeQueryString: true,
736
+ hasRequiredRef: false,
737
+ fromJsonTemplate(input, target) {
738
+ if (context.isOptional) {
739
+ return ` if ${input}.exists() {
740
+ ${target} = ${prefixedTypeName}(serialValue: ${input}.string ?? "")
741
+ }`;
742
+ }
743
+ if (schema.nullable) {
744
+ return ` if ${input}.string != nil {
745
+ ${target} = ${prefixedTypeName}(serialValue: ${input}.string ?? "")
746
+ }`;
747
+ }
748
+ return ` ${target} = ${prefixedTypeName}(serialValue: ${input}.string ?? "")`;
749
+ },
750
+ toJsonTemplate(input, target) {
751
+ if (context.isOptional) {
752
+ return ` ${target} += "\\"\\(${input}!.serialValue())\\""`;
753
+ }
754
+ if (schema.nullable) {
755
+ return ` if ${input} != nil {
756
+ ${target} += "\\"\\(${input}!.serialValue())\\""
757
+ } else {
758
+ ${target} += "null"
759
+ }`;
760
+ }
761
+ return ` ${target} += "\\"\\(${input}.serialValue())\\""`;
762
+ },
763
+ toQueryPartTemplate(input, target, key) {
764
+ if (context.isOptional) {
765
+ return ` if ${input} != nil {
766
+ ${target}.append(URLQueryItem(name: "${key}", value: ${input}!.serialValue()))
767
+ }`;
768
+ }
769
+ if (schema.nullable) {
770
+ return ` if ${input} != nil {
771
+ ${target}.append(URLQueryItem(name: "${key}", value: ${input}!.serialValue()))
772
+ } else {
773
+ ${target}.append(URLQueryItem(name: "${key}", value: "null"))
774
+ }`;
775
+ }
776
+ return ` ${target}.append(URLQueryItem(name: "${key}", value: ${input}.serialValue()))`;
777
+ },
778
+ content: ""
779
+ };
780
+ if (context.generatedTypes.includes(typeName)) {
781
+ return result;
782
+ }
783
+ result.content = `public enum ${prefixedTypeName}: ArriClientEnum {
784
+ ${schema.enum.map((val) => ` case ${codegenUtils.camelCase(val, { normalize: true })}`).join("\n")}
785
+ public init() {
786
+ self = .${defaultEnumValue}
787
+ }
788
+ public init(serialValue: String) {
789
+ switch(serialValue) {
790
+ ${schema.enum.map(
791
+ (val) => ` case "${val}":
792
+ self = .${codegenUtils.camelCase(val, { normalize: true })}
793
+ break;`
794
+ ).join("\n")}
795
+ default:
796
+ self = .${defaultEnumValue}
797
+ }
798
+ }
799
+ public func serialValue() -> String {
800
+ switch (self) {
801
+ ${schema.enum.map(
802
+ (val) => ` case .${codegenUtils.camelCase(val, { normalize: true })}:
803
+ return "${val}"`
804
+ ).join("\n")}
805
+ }
806
+ }
807
+ }`;
808
+ context.generatedTypes.push(typeName);
809
+ return result;
810
+ }
811
+
812
+ function swiftStringFromSchema(schema, context) {
813
+ const isNullable = isNullableType(schema, context);
814
+ const typeName = isNullable ? "String?" : "String";
815
+ const defaultValue = isNullable ? "" : '""';
816
+ return {
817
+ typeName,
818
+ isNullable,
819
+ defaultValue,
820
+ canBeQueryString: true,
821
+ hasRequiredRef: false,
822
+ fromJsonTemplate(input, target) {
823
+ if (context.isOptional) {
824
+ return ` if ${input}.exists() {
825
+ ${target} = ${input}.string
826
+ }`;
827
+ }
828
+ if (schema.nullable) {
829
+ return ` if ${input}.string != nil {
830
+ ${target} = ${input}.string
831
+ }`;
832
+ }
833
+ return ` ${target} = ${input}.string ?? ""`;
834
+ },
835
+ toJsonTemplate(input, target) {
836
+ if (context.isOptional) {
837
+ return ` ${target} += serializeString(input: ${input}!)`;
838
+ }
839
+ if (schema.nullable) {
840
+ return ` if ${input} != nil {
841
+ ${target} += serializeString(input: ${input}!)
842
+ } else {
843
+ ${target} += "null"
844
+ }`;
845
+ }
846
+ return ` ${target} += serializeString(input: ${input})`;
847
+ },
848
+ toQueryPartTemplate(input, target, key) {
849
+ if (context.isOptional) {
850
+ return ` if ${input} != nil {
851
+ ${target}.append(URLQueryItem(name: "${key}", value: ${input}!))
852
+ }`;
853
+ }
854
+ if (schema.nullable) {
855
+ return ` if ${input} != nil {
856
+ ${target}.append(URLQueryItem(name: "${key}", value: ${input}!))
857
+ } else {
858
+ ${target}.append(URLQueryItem(name: "${key}", value: "null"))
859
+ }`;
860
+ }
861
+ return ` ${target}.append(URLQueryItem(name: "${key}", value: ${input}))`;
862
+ },
863
+ content: ""
864
+ };
865
+ }
866
+ function swiftBooleanFromSchema(schema, context) {
867
+ const isNullable = isNullableType(schema, context);
868
+ const typeName = isNullable ? "Bool?" : "Bool";
869
+ const defaultValue = isNullable ? "" : "false";
870
+ return {
871
+ typeName,
872
+ isNullable,
873
+ defaultValue,
874
+ canBeQueryString: true,
875
+ hasRequiredRef: false,
876
+ fromJsonTemplate(input, target) {
877
+ if (context.isOptional) {
878
+ return ` if ${input}.exists() {
879
+ ${target} = ${input}.bool
880
+ }`;
881
+ }
882
+ if (schema.nullable) {
883
+ return ` if ${input}.bool != nil {
884
+ ${target} = ${input}.bool
885
+ }`;
886
+ }
887
+ return ` ${target} = ${input}.bool ?? false`;
888
+ },
889
+ toJsonTemplate(input, target) {
890
+ if (context.isOptional) {
891
+ return `${target} += "\\(${input}!)"`;
892
+ }
893
+ if (schema.nullable) {
894
+ return ` if ${input} != nil {
895
+ ${target} += "\\(${input}!)"
896
+ } else {
897
+ ${target} += "null"
898
+ }`;
899
+ }
900
+ return ` ${target} += "\\(${input})"`;
901
+ },
902
+ toQueryPartTemplate(input, target, key) {
903
+ if (context.isOptional) {
904
+ return ` if ${input} != nil {
905
+ ${target}.append(URLQueryItem(name: "${key}", value: "\\(${input}!)"))
906
+ }`;
907
+ }
908
+ if (schema.nullable) {
909
+ return ` if ${input} != nil {
910
+ ${target}.append(URLQueryItem(name: "${key}", value: "\\(${input}!)"))
911
+ } else {
912
+ ${target}.append(URLQueryItem(name: "${key}", value: "null"))
913
+ }`;
914
+ }
915
+ return ` ${target}.append(URLQueryItem(name: "${key}", value: "\\(${input})"))`;
916
+ },
917
+ content: ""
918
+ };
919
+ }
920
+ function swiftTimestampFromSchema(schema, context) {
921
+ const isNullable = isNullableType(schema, context);
922
+ const typeName = isNullable ? "Date?" : "Date";
923
+ const defaultValue = isNullable ? "" : "Date()";
924
+ return {
925
+ typeName,
926
+ defaultValue,
927
+ isNullable,
928
+ canBeQueryString: true,
929
+ hasRequiredRef: false,
930
+ fromJsonTemplate(input, target) {
931
+ if (context.isOptional) {
932
+ return ` if ${input}.exists() {
933
+ ${target} = parseDate(${input}.string ?? "") ?? Date()
934
+ }`;
935
+ }
936
+ if (schema.nullable) {
937
+ return ` if ${input}.string != nil {
938
+ ${target} = parseDate(${input}.string ?? "") ?? Date()
939
+ }`;
940
+ }
941
+ return ` ${target} = parseDate(${input}.string ?? "") ?? Date()`;
942
+ },
943
+ toJsonTemplate(input, target) {
944
+ if (context.isOptional) {
945
+ return ` ${target} += serializeDate(${input}!)`;
946
+ }
947
+ if (schema.nullable) {
948
+ return ` if ${input} != nil {
949
+ ${target} += serializeDate(${input}!)
950
+ } else {
951
+ ${target} += "null"
952
+ }`;
953
+ }
954
+ return ` ${target} += serializeDate(${input})`;
955
+ },
956
+ toQueryPartTemplate(input, target, key) {
957
+ if (context.isOptional) {
958
+ return ` if ${input} != nil {
959
+ ${target}.append(URLQueryItem(name: "${key}", value: serializeDate(${input}!, withQuotes: false)))
960
+ }`;
961
+ }
962
+ if (schema.nullable) {
963
+ return ` if ${input} != nil {
964
+ ${target}.append(URLQueryItem(name: "${key}", value: serializeDate(${input}!, withQuotes: false)))
965
+ } else {
966
+ ${target}.append(URLQueryItem(name: "${key}", value: "null"))
967
+ }`;
968
+ }
969
+ return ` ${target}.append(URLQueryItem(name: "${key}", value: serializeDate(${input}, withQuotes: false)))`;
970
+ },
971
+ content: ""
972
+ };
973
+ }
974
+ function swiftNumberFromSchema(schema, context, typeName, jsonAccessor, defaultValue) {
975
+ const isNullable = isNullableType(schema, context);
976
+ return {
977
+ typeName: isNullable ? `${typeName}?` : typeName,
978
+ defaultValue: isNullable ? "" : defaultValue,
979
+ isNullable,
980
+ canBeQueryString: true,
981
+ hasRequiredRef: false,
982
+ fromJsonTemplate(input, target) {
983
+ if (context.isOptional) {
984
+ return ` if ${input}.exists() {
985
+ ${target} = ${input}.${jsonAccessor}
986
+ }`;
987
+ }
988
+ if (schema.nullable) {
989
+ return ` if ${input}.${jsonAccessor} != nil {
990
+ ${target} = ${input}.${jsonAccessor}
991
+ }`;
992
+ }
993
+ return ` ${target} = ${input}.${jsonAccessor} ?? ${defaultValue}`;
994
+ },
995
+ toJsonTemplate(input, target) {
996
+ if (context.isOptional) {
997
+ return ` ${target} += "\\(${input}!)"`;
998
+ }
999
+ if (schema.nullable) {
1000
+ return ` if ${input} != nil {
1001
+ ${target} += "\\(${input}!)"
1002
+ } else {
1003
+ ${target} += "null"
1004
+ }`;
1005
+ }
1006
+ return ` ${target} += "\\(${input})"`;
1007
+ },
1008
+ toQueryPartTemplate(input, target, key) {
1009
+ if (context.isOptional) {
1010
+ return ` if ${input} != nil {
1011
+ ${target}.append(URLQueryItem(name: "${key}", value: "\\(${input}!)"))
1012
+ }`;
1013
+ }
1014
+ if (schema.nullable) {
1015
+ return ` if ${input} != nil {
1016
+ ${target}.append(URLQueryItem(name: "${key}", value: "\\(${input}!)"))
1017
+ } else {
1018
+ ${target}.append(URLQueryItem(name: "${key}", value: "null"))
1019
+ }`;
1020
+ }
1021
+ return ` ${target}.append(URLQueryItem(name: "${key}", value: "\\(${input})"))`;
1022
+ },
1023
+ content: ""
1024
+ };
1025
+ }
1026
+ function swiftLargeIntFromSchema(schema, context, typeName) {
1027
+ const isNullable = isNullableType(schema, context);
1028
+ return {
1029
+ typeName: isNullable ? `${typeName}?` : typeName,
1030
+ defaultValue: isNullable ? "" : "0",
1031
+ isNullable,
1032
+ canBeQueryString: true,
1033
+ hasRequiredRef: false,
1034
+ fromJsonTemplate(input, target) {
1035
+ if (context.isOptional) {
1036
+ return ` if ${input}.exists() {
1037
+ ${target} = ${typeName}(${input}.string ?? "0")
1038
+ }`;
1039
+ }
1040
+ if (schema.nullable) {
1041
+ return ` if ${input}.string != nil {
1042
+ ${target} = ${typeName}(${input}.string ?? "0")
1043
+ }`;
1044
+ }
1045
+ return ` ${target} = ${typeName}(${input}.string ?? "0") ?? 0`;
1046
+ },
1047
+ toJsonTemplate(input, target) {
1048
+ if (context.isOptional) {
1049
+ return ` ${target} += "\\"\\(${input}!)\\""`;
1050
+ }
1051
+ if (schema.nullable) {
1052
+ return ` if ${input} != nil {
1053
+ ${target} += "\\"\\(${input}!)\\""
1054
+ } else {
1055
+ ${target} += "null"
1056
+ }`;
1057
+ }
1058
+ return ` ${target} += "\\"\\(${input})\\""`;
1059
+ },
1060
+ toQueryPartTemplate(input, target, key) {
1061
+ if (context.isOptional) {
1062
+ return ` if ${input} != nil {
1063
+ ${target}.append(URLQueryItem(name: "${key}", value: "\\(${input}!)"))
1064
+ }`;
1065
+ }
1066
+ if (schema.nullable) {
1067
+ return ` if ${input} != nil {
1068
+ ${target}.append(URLQueryItem(name: "${key}", value: "\\(${input}!)"))
1069
+ } else {
1070
+ ${target}.append(URLQueryItem(name: "${key}", value: "null"))
1071
+ }`;
1072
+ }
1073
+ return ` ${target}.append(URLQueryItem(name: "${key}", value: "\\(${input})"))`;
1074
+ },
1075
+ content: ""
1076
+ };
1077
+ }
1078
+
1079
+ function swiftProcedureFromSchema(schema, context) {
1080
+ switch (schema.transport) {
1081
+ case "http":
1082
+ return swiftHttpProcedureFromSchema(schema, context);
1083
+ case "ws":
1084
+ return swiftWsProcedureFromSchema(schema, context);
1085
+ default:
1086
+ console.warn(
1087
+ `[swift-codegen] Unsupported transport type at ${context.instancePath}`
1088
+ );
1089
+ return "";
1090
+ }
1091
+ }
1092
+ function swiftHttpProcedureFromSchema(schema, context) {
1093
+ const rpcName = getRpcName(context.instancePath);
1094
+ const comments = codeComments(
1095
+ {
1096
+ metadata: {
1097
+ description: schema.description,
1098
+ isDeprecated: schema.isDeprecated
1099
+ }
1100
+ },
1101
+ " "
1102
+ );
1103
+ const params = schema.params ? `${context.typePrefix}${validTypeName(schema.params)}` : void 0;
1104
+ const response = schema.response ? `${context.typePrefix}${validTypeName(schema.response)}` : void 0;
1105
+ if (schema.isEventStream) {
1106
+ return `${comments} public func ${rpcName}(${params ? `_ params: ${params}, ` : ""}options: EventSourceOptions<${response ?? "EmptyArriModel"}>) -> Task<(), Never> {
1107
+ let task = Task {
1108
+ var eventSource = EventSource<${response ?? "EmptyArriModel"}>(
1109
+ url: "\\(self.baseURL)${schema.path}",
1110
+ method: "${schema.method.toUpperCase()}",
1111
+ headers: self.headers,
1112
+ params: ${params ? "params" : "nil"},
1113
+ delegate: self.delegate,
1114
+ clientVersion: "${context.clientVersion}",
1115
+ options: options
1116
+ )
1117
+ await eventSource.sendRequest()
1118
+ }
1119
+ return task
1120
+ }`;
1121
+ }
1122
+ return `${comments} public func ${rpcName}(${params ? `_ params: ${params}` : ""}) async throws -> ${response ?? "()"} {
1123
+ ${response ? `let result: ${response} = ` : "let _: EmptyArriModel = "}try await parsedArriHttpRequest(
1124
+ delegate: self.delegate,
1125
+ url: "\\(self.baseURL)${schema.path}",
1126
+ method: "${schema.method.toUpperCase()}",
1127
+ headers: self.headers,
1128
+ clientVersion: "${context.clientVersion}",
1129
+ ${params ? `params: params` : "params: EmptyArriModel()"}
1130
+ )
1131
+ ${response ? `return result` : ""}
1132
+ }`;
1133
+ }
1134
+ function getRpcName(instancePath) {
1135
+ const part = instancePath.split(".").pop();
1136
+ if (!part) {
1137
+ throw new Error(`Error determining procedure name at ${instancePath}`);
1138
+ }
1139
+ return validSwiftKey(part);
1140
+ }
1141
+ function swiftWsProcedureFromSchema(schema, context) {
1142
+ console.warn(
1143
+ "[swift-codegen] Websocket procedures are not supported at this time."
1144
+ );
1145
+ const name = getRpcName(context.instancePath);
1146
+ const params = schema.params ? `${context.typePrefix}${validTypeName(schema.params)}` : void 0;
1147
+ const response = schema.response ? `${context.typePrefix}${validTypeName(schema.response)}` : void 0;
1148
+ const comments = codeComments(
1149
+ {
1150
+ metadata: {
1151
+ description: schema.description,
1152
+ isDeprecated: schema.isDeprecated
1153
+ }
1154
+ },
1155
+ ` `
1156
+ );
1157
+ return `${comments} public func ${name}(${params ? `_ params: ${params}` : ""}) async throws -> ${response ?? "()"} {
1158
+ throw ArriRequestError.notImplemented
1159
+ }`;
1160
+ }
1161
+ function swiftServiceFromSchema(schema, context) {
1162
+ const serviceName = getServiceName(
1163
+ context.instancePath,
1164
+ context.clientName
1165
+ );
1166
+ const services = [];
1167
+ const procedureParts = [];
1168
+ const subContent = [];
1169
+ for (const key of Object.keys(schema)) {
1170
+ const subSchema = schema[key];
1171
+ if (codegenUtils.isServiceDefinition(subSchema)) {
1172
+ const subService = swiftServiceFromSchema(subSchema, {
1173
+ clientVersion: context.clientVersion,
1174
+ clientName: context.clientName,
1175
+ typePrefix: context.typePrefix,
1176
+ instancePath: `${context.instancePath}.${key}`,
1177
+ schemaPath: `${context.schemaPath}.${key}`,
1178
+ generatedTypes: context.generatedTypes,
1179
+ containsRequiredRef: context.containsRequiredRef
1180
+ });
1181
+ if (subService) {
1182
+ const subServiceKey = validSwiftKey(key);
1183
+ const subServiceName = getServiceName(
1184
+ `${context.instancePath}.${key}`,
1185
+ context.clientName
1186
+ );
1187
+ services.push({
1188
+ key: subServiceKey,
1189
+ typeName: subServiceName
1190
+ });
1191
+ subContent.push(subService);
1192
+ }
1193
+ continue;
1194
+ }
1195
+ if (codegenUtils.isRpcDefinition(subSchema)) {
1196
+ const rpc = swiftProcedureFromSchema(subSchema, {
1197
+ clientVersion: context.clientVersion,
1198
+ clientName: context.clientName,
1199
+ typePrefix: context.typePrefix,
1200
+ instancePath: `${context.instancePath}.${key}`,
1201
+ schemaPath: `${context.schemaPath}.${key}`,
1202
+ generatedTypes: context.generatedTypes,
1203
+ containsRequiredRef: context.containsRequiredRef
1204
+ });
1205
+ if (rpc) {
1206
+ procedureParts.push(rpc);
1207
+ }
1208
+ continue;
1209
+ }
1210
+ }
1211
+ return `public class ${serviceName} {
1212
+ let baseURL: String
1213
+ let delegate: ArriRequestDelegate
1214
+ let headers: () -> Dictionary<String, String>
1215
+ ${services.map((service) => ` public let ${service.key}: ${service.typeName}`).join("\n")}
1216
+ public init(
1217
+ baseURL: String,
1218
+ delegate: ArriRequestDelegate,
1219
+ headers: @escaping () -> Dictionary<String, String>
1220
+ ) {
1221
+ self.baseURL = baseURL
1222
+ self.delegate = delegate
1223
+ self.headers = headers
1224
+ ${services.map(
1225
+ (service) => ` self.${service.key} = ${service.typeName}(
1226
+ baseURL: baseURL,
1227
+ delegate: delegate,
1228
+ headers: headers
1229
+ )`
1230
+ ).join("\n")}
1231
+ }
1232
+ ${procedureParts.join("\n")}
1233
+
1234
+ }
1235
+
1236
+ ${subContent.join("\n")}`;
1237
+ }
1238
+ function getServiceName(instancePath, clientName) {
1239
+ if (instancePath.length === 0) {
1240
+ return clientName;
1241
+ }
1242
+ const name = `${clientName}${validTypeName(instancePath.split(".").join("_"))}Service`;
1243
+ return name;
1244
+ }
1245
+
1246
+ function swiftDictionaryFromSchema(schema, context) {
1247
+ const subType = swiftTypeFromSchema(schema.values, {
1248
+ clientVersion: context.clientVersion,
1249
+ clientName: context.clientName,
1250
+ typePrefix: context.typePrefix,
1251
+ instancePath: `${context.instancePath}/[value]`,
1252
+ schemaPath: `${context.schemaPath}/values`,
1253
+ generatedTypes: context.generatedTypes,
1254
+ containsRequiredRef: context.containsRequiredRef
1255
+ });
1256
+ const isNullable = isNullableType(schema, context);
1257
+ const typeName = isNullable ? `Dictionary<String, ${subType.typeName}>?` : `Dictionary<String, ${subType.typeName}>`;
1258
+ const defaultValue = isNullable ? `` : `Dictionary()`;
1259
+ return {
1260
+ typeName,
1261
+ isNullable,
1262
+ defaultValue,
1263
+ canBeQueryString: false,
1264
+ hasRequiredRef: false,
1265
+ fromJsonTemplate(input, target, _) {
1266
+ const mainContent = ` ${target} = Dictionary()
1267
+ for (__key, __value) in ${input}.dictionary ?? Dictionary() {
1268
+ var __parsedValue: ${subType.typeName}
1269
+ ${subType.fromJsonTemplate(`__value`, `__parsedValue`, `__parsedValue`)}
1270
+ ${target}${isNullable ? "!" : ""}[__key] = __parsedValue
1271
+ }`;
1272
+ if (context.isOptional) {
1273
+ return ` if ${input}.exists() {
1274
+ ${mainContent}
1275
+ }`;
1276
+ }
1277
+ if (schema.nullable) {
1278
+ return ` if ${input}.dictionary != nil {
1279
+ ${mainContent}
1280
+ }`;
1281
+ }
1282
+ return mainContent;
1283
+ },
1284
+ toJsonTemplate(input, target) {
1285
+ const mainContent = ` ${target} += "{"
1286
+ for (__index, (__key, __value)) in ${input}${isNullable ? "!" : ""}.enumerated() {
1287
+ if __index > 0 {
1288
+ ${target} += ","
1289
+ }
1290
+ ${target} += "\\"\\(__key)\\":"
1291
+ ${subType.toJsonTemplate("__value", target)}
1292
+ }
1293
+ ${target} += "}"`;
1294
+ if (schema.nullable) {
1295
+ return `if ${input} != nil {
1296
+ ${mainContent}
1297
+ } else {
1298
+ ${target} += "null"
1299
+ }`;
1300
+ }
1301
+ return mainContent;
1302
+ },
1303
+ toQueryPartTemplate(_, __, ___) {
1304
+ return ` print("[WARNING] nested objects cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
1305
+ },
1306
+ cloneTemplate(input, key) {
1307
+ const innerKey = validSwiftKey(key);
1308
+ const subTypeClonedResult = subType.cloneTemplate?.(
1309
+ `__${innerKey}Value`,
1310
+ `__${innerKey}Value`
1311
+ );
1312
+ if (isNullable) {
1313
+ return {
1314
+ bodyContent: `var __${innerKey}Cloned: ${typeName}
1315
+ if ${input} != nil {
1316
+ __${innerKey}Cloned = Dictionary()
1317
+ for (__${innerKey}Key, __${innerKey}Value) in ${input}! {
1318
+ ${subTypeClonedResult?.bodyContent ?? ""}
1319
+ __${innerKey}Cloned![__${innerKey}Key] = ${subTypeClonedResult?.fieldContent ?? `__${innerKey}Value`}
1320
+ }
1321
+ }`,
1322
+ fieldContent: `__${innerKey}Cloned`
1323
+ };
1324
+ }
1325
+ return {
1326
+ bodyContent: `var __${innerKey}Cloned: ${typeName} = Dictionary()
1327
+ for (__${innerKey}Key, __${innerKey}Value) in ${input} {
1328
+ ${subTypeClonedResult?.bodyContent ?? ""}
1329
+ __${innerKey}Cloned[__${innerKey}Key] = ${subTypeClonedResult?.fieldContent ?? `__${innerKey}Value`}
1330
+ }`,
1331
+ fieldContent: `__${innerKey}Cloned`
1332
+ };
1333
+ },
1334
+ content: subType.content
1335
+ };
1336
+ }
1337
+
1338
+ function swiftRefFromSchema(schema, context) {
1339
+ const typeName = validTypeName(schema.ref);
1340
+ const prefixedTypeName = `${context.typePrefix}${typeName}`;
1341
+ const isNullable = isNullableType(schema, context);
1342
+ const defaultValue = isNullable ? `` : `${prefixedTypeName}()`;
1343
+ return {
1344
+ typeName: isNullable ? `${prefixedTypeName}?` : prefixedTypeName,
1345
+ isNullable,
1346
+ defaultValue,
1347
+ canBeQueryString: false,
1348
+ hasRequiredRef: !isNullable,
1349
+ fromJsonTemplate(input, target, _key) {
1350
+ if (context.isOptional) {
1351
+ return `if ${input}.exists() {
1352
+ ${target} = ${prefixedTypeName}(json: ${input})
1353
+ }`;
1354
+ }
1355
+ if (schema.nullable) {
1356
+ return `if ${input}.dictionary != nil {
1357
+ ${target} = ${prefixedTypeName}(json: ${input})
1358
+ }`;
1359
+ }
1360
+ return `${target} = ${prefixedTypeName}(json: ${input})`;
1361
+ },
1362
+ toJsonTemplate(input, target) {
1363
+ const mainContent = `${target} += ${input}${isNullable ? "!" : ""}.toJSONString()`;
1364
+ if (schema.nullable) {
1365
+ return `if ${input} != nil {
1366
+ ${mainContent}
1367
+ } else {
1368
+ ${target} += "null"
1369
+ }`;
1370
+ }
1371
+ return mainContent;
1372
+ },
1373
+ toQueryPartTemplate(_, __, ___) {
1374
+ return `print("[WARNING] nested objects cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
1375
+ },
1376
+ cloneTemplate(input, _) {
1377
+ return {
1378
+ bodyContent: "",
1379
+ fieldContent: `${input}${isNullable ? "?" : ""}.clone()`
1380
+ };
1381
+ },
1382
+ content: ""
1383
+ };
1384
+ }
1385
+
1386
+ const swiftClientGenerator = codegenUtils.defineGeneratorPlugin(
1387
+ (options) => {
1388
+ return {
1389
+ async generator(def, _isDevServer) {
1390
+ const content = createSwiftClient(def, options);
1391
+ fs__default.writeFileSync(options.outputFile, content, "utf8");
1392
+ },
1393
+ options
1394
+ };
1395
+ }
1396
+ );
1397
+ function createSwiftClient(def, options) {
1398
+ const context = {
1399
+ clientVersion: def.info?.version ?? "",
1400
+ clientName: options.clientName,
1401
+ typePrefix: options.typePrefix ?? "",
1402
+ instancePath: "",
1403
+ schemaPath: "",
1404
+ generatedTypes: [],
1405
+ containsRequiredRef: {}
1406
+ };
1407
+ const services = codegenUtils.unflattenProcedures(def.procedures);
1408
+ const mainService = swiftServiceFromSchema(services, context);
1409
+ const typeContent = [];
1410
+ for (const key of Object.keys(def.definitions)) {
1411
+ const subSchema = def.definitions[key];
1412
+ const subType = swiftTypeFromSchema(subSchema, {
1413
+ clientVersion: context.clientVersion,
1414
+ clientName: context.clientName,
1415
+ typePrefix: context.typePrefix,
1416
+ instancePath: `/${key}`,
1417
+ schemaPath: `/${key}`,
1418
+ generatedTypes: context.generatedTypes,
1419
+ containsRequiredRef: context.containsRequiredRef
1420
+ });
1421
+ if (subType.content) {
1422
+ typeContent.push(subType.content);
1423
+ }
1424
+ }
1425
+ return `import Foundation
1426
+ import ArriClient
1427
+
1428
+ ${mainService}
1429
+ ${typeContent.join("\n")}`;
1430
+ }
1431
+ function swiftTypeFromSchema(schema, context) {
1432
+ if (codegenUtils.isSchemaFormType(schema)) {
1433
+ switch (schema.type) {
1434
+ case "string":
1435
+ return swiftStringFromSchema(schema, context);
1436
+ case "boolean":
1437
+ return swiftBooleanFromSchema(schema, context);
1438
+ case "timestamp":
1439
+ return swiftTimestampFromSchema(schema, context);
1440
+ case "float32":
1441
+ return swiftNumberFromSchema(
1442
+ schema,
1443
+ context,
1444
+ "Float32",
1445
+ "float",
1446
+ "0.0"
1447
+ );
1448
+ case "float64":
1449
+ return swiftNumberFromSchema(
1450
+ schema,
1451
+ context,
1452
+ "Float64",
1453
+ "double",
1454
+ "0.0"
1455
+ );
1456
+ case "int8":
1457
+ return swiftNumberFromSchema(
1458
+ schema,
1459
+ context,
1460
+ "Int8",
1461
+ "int8",
1462
+ "0"
1463
+ );
1464
+ case "uint8":
1465
+ return swiftNumberFromSchema(
1466
+ schema,
1467
+ context,
1468
+ "UInt8",
1469
+ "uInt8",
1470
+ "0"
1471
+ );
1472
+ case "int16":
1473
+ return swiftNumberFromSchema(
1474
+ schema,
1475
+ context,
1476
+ "Int16",
1477
+ "int16",
1478
+ "0"
1479
+ );
1480
+ case "uint16":
1481
+ return swiftNumberFromSchema(
1482
+ schema,
1483
+ context,
1484
+ "UInt16",
1485
+ "uInt16",
1486
+ "0"
1487
+ );
1488
+ case "int32":
1489
+ return swiftNumberFromSchema(
1490
+ schema,
1491
+ context,
1492
+ "Int32",
1493
+ "int32",
1494
+ "0"
1495
+ );
1496
+ case "uint32":
1497
+ return swiftNumberFromSchema(
1498
+ schema,
1499
+ context,
1500
+ "UInt32",
1501
+ "uInt32",
1502
+ "0"
1503
+ );
1504
+ case "int64":
1505
+ return swiftLargeIntFromSchema(schema, context, "Int64");
1506
+ case "uint64":
1507
+ return swiftLargeIntFromSchema(schema, context, "UInt64");
1508
+ default:
1509
+ schema.type;
1510
+ break;
1511
+ }
1512
+ }
1513
+ if (codegenUtils.isSchemaFormEnum(schema)) {
1514
+ return swiftEnumFromSchema(schema, context);
1515
+ }
1516
+ if (codegenUtils.isSchemaFormProperties(schema)) {
1517
+ return swiftObjectFromSchema(schema, context);
1518
+ }
1519
+ if (codegenUtils.isSchemaFormElements(schema)) {
1520
+ return swiftArrayFromSchema(schema, context);
1521
+ }
1522
+ if (codegenUtils.isSchemaFormValues(schema)) {
1523
+ return swiftDictionaryFromSchema(schema, context);
1524
+ }
1525
+ if (codegenUtils.isSchemaFormDiscriminator(schema)) {
1526
+ return swiftTaggedUnionFromSchema(schema, context);
1527
+ }
1528
+ if (codegenUtils.isSchemaFormRef(schema)) {
1529
+ return swiftRefFromSchema(schema, context);
1530
+ }
1531
+ return swiftAnyFromSchema(schema, context);
1532
+ }
1533
+
1534
+ exports.createSwiftClient = createSwiftClient;
1535
+ exports.swiftClientGenerator = swiftClientGenerator;
1536
+ exports.swiftTypeFromSchema = swiftTypeFromSchema;