@arrirpc/codegen-kotlin 0.45.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,1932 @@
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
+ const reservedIdentifierKeywords = [
11
+ "as",
12
+ "as?",
13
+ "break",
14
+ "class",
15
+ "continue",
16
+ "do",
17
+ "else",
18
+ "false",
19
+ "for",
20
+ "fun",
21
+ "if",
22
+ "in",
23
+ "!in",
24
+ "interface",
25
+ "is",
26
+ "!is",
27
+ "null",
28
+ "object",
29
+ "package",
30
+ "return",
31
+ "super",
32
+ "this",
33
+ "throw",
34
+ "true",
35
+ "try",
36
+ "typealias",
37
+ "typeof",
38
+ "val",
39
+ "var",
40
+ "when",
41
+ "while"
42
+ ];
43
+ const illegalCharacters = "+-*/%=&|!<>[]?:.@$;";
44
+ function kotlinIdentifier(input) {
45
+ const name = codegenUtils.removeDisallowedChars(codegenUtils.camelCase(input), illegalCharacters);
46
+ if (codegenUtils.stringStartsWithNumber(name) || reservedIdentifierKeywords.includes(name)) {
47
+ return `\`${name}\``;
48
+ }
49
+ return name;
50
+ }
51
+ function kotlinClassName(input) {
52
+ const name = codegenUtils.removeDisallowedChars(
53
+ codegenUtils.pascalCase(input, { normalize: true }),
54
+ illegalCharacters
55
+ );
56
+ if (codegenUtils.stringStartsWithNumber(name) || reservedIdentifierKeywords.includes(name)) {
57
+ return `_${name}`;
58
+ }
59
+ return name;
60
+ }
61
+ function getClassName(schema, context) {
62
+ if (schema.metadata?.id) {
63
+ const className2 = kotlinClassName(
64
+ codegenUtils.pascalCase(schema.metadata.id, {
65
+ normalize: true
66
+ })
67
+ );
68
+ return `${context.modelPrefix}${className2}`;
69
+ }
70
+ const depth = instanceDepth(context);
71
+ if (depth === 1 && !context.discriminatorKey) {
72
+ const className2 = kotlinClassName(
73
+ codegenUtils.pascalCase(context.instancePath.replace("/", ""), {
74
+ normalize: true
75
+ })
76
+ );
77
+ return `${context.modelPrefix}${className2}`;
78
+ }
79
+ if (context.discriminatorParentId && context.discriminatorKey && context.discriminatorValue) {
80
+ const className2 = kotlinClassName(
81
+ codegenUtils.pascalCase(
82
+ `${context.discriminatorParentId}_${context.discriminatorValue}`,
83
+ { normalize: true }
84
+ )
85
+ );
86
+ return `${context.modelPrefix}${className2}`;
87
+ }
88
+ const className = kotlinClassName(
89
+ codegenUtils.pascalCase(
90
+ context.instancePath.split("/").join("_").split("[").join("_").split("]").join("_"),
91
+ {
92
+ normalize: true
93
+ }
94
+ )
95
+ );
96
+ return `${context.modelPrefix}${className}`;
97
+ }
98
+ function instanceDepth(context) {
99
+ const parts = context.instancePath.split("/");
100
+ return parts.length - 1;
101
+ }
102
+ function isNullable(schema, context) {
103
+ return schema.nullable === true || context.isOptional === true;
104
+ }
105
+
106
+ function kotlinAnyFromSchema(schema, context) {
107
+ const nullable = isNullable(schema, context);
108
+ const defaultValue = nullable ? "null" : "JsonNull";
109
+ return {
110
+ typeName: "JsonElement",
111
+ isNullable: nullable,
112
+ defaultValue,
113
+ fromJson(input) {
114
+ if (context.isOptional) {
115
+ return `when (${input}) {
116
+ null -> null
117
+ else -> ${input}
118
+ }`;
119
+ }
120
+ if (schema.nullable) {
121
+ return `when (${input}) {
122
+ JsonNull -> null
123
+ null -> null
124
+ else -> ${input}
125
+ }`;
126
+ }
127
+ return `when (${input}) {
128
+ is JsonElement -> ${input}!!
129
+ else -> JsonNull
130
+ }`;
131
+ },
132
+ toJson(input, target) {
133
+ if (schema.nullable) {
134
+ return `${target} += when (${input}) {
135
+ null -> "null"
136
+ else -> JsonInstance.encodeToString(${input})
137
+ }`;
138
+ }
139
+ return `${target} += JsonInstance.encodeToString(${input})`;
140
+ },
141
+ toQueryString() {
142
+ return `__logError("[WARNING] any's cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
143
+ },
144
+ content: ""
145
+ };
146
+ }
147
+
148
+ function kotlinArrayFromSchema(schema, context) {
149
+ const nullable = isNullable(schema, context);
150
+ const defaultValue = nullable ? "null" : "mutableListOf()";
151
+ const subType = kotlinTypeFromSchema(schema.elements, {
152
+ modelPrefix: context.modelPrefix,
153
+ clientName: context.clientName,
154
+ clientVersion: context.clientVersion,
155
+ instancePath: `${context.instancePath}/[element]`,
156
+ schemaPath: `${context.schemaPath}/elements`,
157
+ existingTypeIds: context.existingTypeIds
158
+ });
159
+ const typeName = `MutableList<${subType.typeName}${subType.isNullable ? "?" : ""}>`;
160
+ return {
161
+ typeName,
162
+ isNullable: nullable,
163
+ defaultValue,
164
+ fromJson(input) {
165
+ if (nullable) {
166
+ return `when (${input}) {
167
+ is JsonArray -> {
168
+ val __value: ${typeName} = mutableListOf()
169
+ for (__element in ${input}!!.jsonArray) {
170
+ __value.add(
171
+ ${subType.fromJson("__element")}
172
+ )
173
+ }
174
+ __value
175
+ }
176
+
177
+ else -> null
178
+ }`;
179
+ }
180
+ return `when (${input}) {
181
+ is JsonArray -> {
182
+ val __value: ${typeName} = mutableListOf()
183
+ for (__element in ${input}!!.jsonArray) {
184
+ __value.add(
185
+ ${subType.fromJson("__element")}
186
+ )
187
+ }
188
+ __value
189
+ }
190
+
191
+ else -> mutableListOf()
192
+ }`;
193
+ },
194
+ toJson(input, target) {
195
+ if (schema.nullable) {
196
+ return `if (${input} == null) {
197
+ ${target} += "null"
198
+ } else {
199
+ ${target} += "["
200
+ for ((__index, __element) in ${input}.withIndex()) {
201
+ if (__index != 0) {
202
+ ${target} += ","
203
+ }
204
+ ${subType.toJson("__element", target)}
205
+ }
206
+ ${target} += "]"
207
+ }`;
208
+ }
209
+ return `${target} += "["
210
+ for ((__index, __element) in ${input}.withIndex()) {
211
+ if (__index != 0) {
212
+ ${target} += ","
213
+ }
214
+ ${subType.toJson("__element", target)}
215
+ }
216
+ ${target} += "]"`;
217
+ },
218
+ toQueryString() {
219
+ return `__logError("[WARNING] arrays cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
220
+ },
221
+ content: subType.content
222
+ };
223
+ }
224
+
225
+ function kotlinObjectFromSchema(schema, context) {
226
+ const className = getClassName(schema, context);
227
+ const nullable = isNullable(schema, context);
228
+ const defaultValue = nullable ? "null" : `${className}.new()`;
229
+ const result = {
230
+ typeName: className,
231
+ isNullable: nullable,
232
+ defaultValue,
233
+ fromJson(input, key) {
234
+ if (nullable) {
235
+ return `when (${input}) {
236
+ is JsonObject -> ${className}.fromJsonElement(
237
+ ${input}!!,
238
+ "$instancePath/${key}",
239
+ )
240
+
241
+ else -> null
242
+ }`;
243
+ }
244
+ return `when (${input}) {
245
+ is JsonObject -> ${className}.fromJsonElement(
246
+ ${input}!!,
247
+ "$instancePath/${key}",
248
+ )
249
+
250
+ else -> ${className}.new()
251
+ }`;
252
+ },
253
+ toJson(input, target) {
254
+ if (schema.nullable) {
255
+ return `${target} += ${input}?.toJson()`;
256
+ }
257
+ return `${target} += ${input}.toJson()`;
258
+ },
259
+ toQueryString() {
260
+ return `__logError("[WARNING] nested objects cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
261
+ },
262
+ content: ""
263
+ };
264
+ if (context.existingTypeIds.includes(className)) {
265
+ return result;
266
+ }
267
+ const subContent = [];
268
+ const kotlinKeys = [];
269
+ const fieldParts = [];
270
+ const defaultParts = [];
271
+ const toJsonParts = [`var output = "{"`];
272
+ const toQueryParts = ["val queryParts = mutableListOf<String>()"];
273
+ const fromJsonParts = [];
274
+ const requiredKeys = Object.keys(schema.properties);
275
+ const optionalKeys = Object.keys(schema.optionalProperties ?? {});
276
+ const hasKnownKeys = requiredKeys.length > 0 || context.discriminatorKey && context.discriminatorValue;
277
+ if (!hasKnownKeys) {
278
+ toJsonParts.push("var hasProperties = false");
279
+ }
280
+ if (context.discriminatorKey && context.discriminatorValue) {
281
+ toJsonParts.push(
282
+ `output += "\\"${context.discriminatorKey}\\":\\"${context.discriminatorValue}\\""`
283
+ );
284
+ toQueryParts.push(
285
+ `queryParts.add("${context.discriminatorKey}=${context.discriminatorValue}")`
286
+ );
287
+ }
288
+ for (let i = 0; i < requiredKeys.length; i++) {
289
+ const key = requiredKeys[i];
290
+ const kotlinKey = kotlinIdentifier(key);
291
+ kotlinKeys.push(kotlinKey);
292
+ const prop = schema.properties[key];
293
+ const type = kotlinTypeFromSchema(prop, {
294
+ modelPrefix: context.modelPrefix,
295
+ clientName: context.clientName,
296
+ clientVersion: context.clientVersion,
297
+ instancePath: `/${className}/${key}`,
298
+ schemaPath: `${context.schemaPath}/properties/${key}`,
299
+ existingTypeIds: context.existingTypeIds
300
+ });
301
+ if (type.content) {
302
+ subContent.push(type.content);
303
+ }
304
+ fieldParts.push(
305
+ ` val ${kotlinKey}: ${type.typeName}${type.isNullable ? "?" : ""},`
306
+ );
307
+ if (i === 0 && !context.discriminatorKey) {
308
+ toJsonParts.push(`output += "\\"${key}\\":"`);
309
+ } else {
310
+ toJsonParts.push(`output += ",\\"${key}\\":"`);
311
+ }
312
+ toJsonParts.push(type.toJson(kotlinKey, "output"));
313
+ toQueryParts.push(type.toQueryString(kotlinKey, "queryParts", key));
314
+ fromJsonParts.push(
315
+ `val ${kotlinKey}: ${type.typeName}${type.isNullable ? "?" : ""} = ${type.fromJson(`__input.jsonObject["${key}"]`, key)}`
316
+ );
317
+ defaultParts.push(
318
+ ` ${kotlinKey} = ${type.defaultValue},`
319
+ );
320
+ }
321
+ for (let i = 0; i < optionalKeys.length; i++) {
322
+ const isFirst = i === 0 && requiredKeys.length === 0 && !context.discriminatorKey;
323
+ const isLast = i === optionalKeys.length - 1;
324
+ const key = optionalKeys[i];
325
+ const kotlinKey = kotlinIdentifier(key);
326
+ kotlinKeys.push(kotlinKey);
327
+ const type = kotlinTypeFromSchema(schema.optionalProperties[key], {
328
+ modelPrefix: context.modelPrefix,
329
+ clientName: context.clientName,
330
+ clientVersion: context.clientVersion,
331
+ instancePath: `/${className}/${key}`,
332
+ schemaPath: `${context.schemaPath}/optionalProperties/${key}`,
333
+ existingTypeIds: context.existingTypeIds,
334
+ isOptional: true
335
+ });
336
+ if (type.content) {
337
+ subContent.push(type.content);
338
+ }
339
+ const addCommaPart = isFirst ? "" : `
340
+ if (hasProperties) output += ","
341
+ `;
342
+ fieldParts.push(` val ${kotlinKey}: ${type.typeName}? = null,`);
343
+ if (hasKnownKeys) {
344
+ toJsonParts.push(`if (${kotlinKey} != null) {
345
+ output += ",\\"${key}\\":"
346
+ ${type.toJson(kotlinKey, "output")}
347
+ }`);
348
+ } else {
349
+ toJsonParts.push(`if (${kotlinKey} != null) {${addCommaPart}
350
+ output += "\\"${key}\\":"
351
+ ${type.toJson(kotlinKey, "output")}
352
+ ${isLast ? "" : " hasProperties = true"}
353
+ }`);
354
+ }
355
+ toQueryParts.push(type.toQueryString(kotlinKey, "queryParts", key));
356
+ fromJsonParts.push(
357
+ `val ${kotlinKey}: ${type.typeName}? = ${type.fromJson(`__input.jsonObject["${key}"]`, key)}`
358
+ );
359
+ }
360
+ toJsonParts.push('output += "}"');
361
+ toJsonParts.push("return output");
362
+ toQueryParts.push('return queryParts.joinToString("&")');
363
+ const implementedClass = context.discriminatorParentId ?? `${context.clientName}Model`;
364
+ let discriminatorField = "";
365
+ if (context.discriminatorKey && context.discriminatorValue) {
366
+ discriminatorField = `
367
+ override val ${kotlinIdentifier(context.discriminatorKey)} get() = "${context.discriminatorValue}"
368
+ `;
369
+ }
370
+ const content = `data class ${className}(
371
+ ${fieldParts.join("\n")}
372
+ ) : ${implementedClass} {${discriminatorField}
373
+ override fun toJson(): String {
374
+ ${toJsonParts.join("\n")}
375
+ }
376
+
377
+ override fun toUrlQueryParams(): String {
378
+ ${toQueryParts.join("\n")}
379
+ }
380
+
381
+ companion object Factory : ${context.clientName}ModelFactory<${className}> {
382
+ @JvmStatic
383
+ override fun new(): ${className} {
384
+ return ${className}(
385
+ ${defaultParts.join("\n")}
386
+ )
387
+ }
388
+
389
+ @JvmStatic
390
+ override fun fromJson(input: String): ${className} {
391
+ return fromJsonElement(JsonInstance.parseToJsonElement(input))
392
+ }
393
+
394
+ @JvmStatic
395
+ override fun fromJsonElement(__input: JsonElement, instancePath: String): ${className} {
396
+ if (__input !is JsonObject) {
397
+ __logError("[WARNING] ${className}.fromJsonElement() expected kotlinx.serialization.json.JsonObject at $instancePath. Got \${__input.javaClass}. Initializing empty ${className}.")
398
+ return new()
399
+ }
400
+ ${fromJsonParts.join("\n")}
401
+ return ${className}(
402
+ ${kotlinKeys.join(",\n ")},
403
+ )
404
+ }
405
+ }
406
+ }
407
+
408
+ ${subContent.join("\n\n")}`;
409
+ context.existingTypeIds.push(className);
410
+ return {
411
+ ...result,
412
+ content
413
+ };
414
+ }
415
+
416
+ function kotlinDiscriminatorFromSchema(schema, context) {
417
+ const kotlinDiscriminatorKey = kotlinIdentifier(schema.discriminator);
418
+ const className = getClassName(schema, context);
419
+ const nullable = isNullable(schema, context);
420
+ const subTypes = [];
421
+ const subContent = [];
422
+ for (const key of Object.keys(schema.mapping)) {
423
+ const subSchema = schema.mapping[key];
424
+ const subType = kotlinObjectFromSchema(subSchema, {
425
+ modelPrefix: context.modelPrefix,
426
+ clientName: context.clientName,
427
+ clientVersion: context.clientVersion,
428
+ instancePath: context.instancePath,
429
+ schemaPath: `${context.schemaPath}/mapping/${key}`,
430
+ existingTypeIds: context.existingTypeIds,
431
+ discriminatorKey: schema.discriminator,
432
+ discriminatorValue: key,
433
+ discriminatorParentId: className
434
+ });
435
+ subTypes.push({
436
+ typeName: subType.typeName,
437
+ discriminatorValue: key
438
+ });
439
+ if (subType.content) {
440
+ subContent.push(subType.content);
441
+ }
442
+ }
443
+ if (subTypes.length === 0) {
444
+ throw new Error("Discriminator schemas must have at least one mapping");
445
+ }
446
+ const defaultValue = nullable ? "null" : `${className}.new()`;
447
+ const result = {
448
+ typeName: className,
449
+ isNullable: nullable,
450
+ defaultValue,
451
+ fromJson(input, key) {
452
+ return `when (${input}) {
453
+ is JsonObject -> ${className}.fromJsonElement(
454
+ ${input}!!,
455
+ "$instancePath/${key}",
456
+ )
457
+ else -> ${defaultValue}
458
+ }`;
459
+ },
460
+ toJson(input, target) {
461
+ if (schema.nullable) {
462
+ return `${target} += ${input}?.toJson()`;
463
+ }
464
+ return `${target} += ${input}.toJson()`;
465
+ },
466
+ toQueryString() {
467
+ return `__logError("[WARNING] nested objects cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
468
+ },
469
+ content: ""
470
+ };
471
+ if (context.existingTypeIds.includes(className)) {
472
+ return result;
473
+ }
474
+ const content = `sealed interface ${className} : ${context.clientName}Model {
475
+ val ${kotlinDiscriminatorKey}: String
476
+
477
+ companion object Factory : ${context.clientName}ModelFactory<${className}> {
478
+ @JvmStatic
479
+ override fun new(): ${className} {
480
+ return ${subTypes[0].typeName}.new()
481
+ }
482
+
483
+ @JvmStatic
484
+ override fun fromJson(input: String): ${className} {
485
+ return fromJsonElement(JsonInstance.parseToJsonElement(input))
486
+ }
487
+
488
+ @JvmStatic
489
+ override fun fromJsonElement(__input: JsonElement, instancePath: String): ${className} {
490
+ if (__input !is JsonObject) {
491
+ __logError("[WARNING] Discriminator.fromJsonElement() expected kotlinx.serialization.json.JsonObject at $instancePath. Got \${__input.javaClass}. Initializing empty ${className}.")
492
+ return new()
493
+ }
494
+ return when (__input.jsonObject["${schema.discriminator}"]) {
495
+ is JsonPrimitive -> when (__input.jsonObject["${schema.discriminator}"]!!.jsonPrimitive.contentOrNull) {
496
+ ${subTypes.map((type) => `"${type.discriminatorValue}" -> ${type.typeName}.fromJsonElement(__input, instancePath)`).join("\n")}
497
+ else -> new()
498
+ }
499
+
500
+ else -> new()
501
+ }
502
+ }
503
+ }
504
+ }
505
+
506
+ ${subContent.join("\n\n")}`;
507
+ context.existingTypeIds.push(className);
508
+ return {
509
+ ...result,
510
+ content
511
+ };
512
+ }
513
+
514
+ function kotlinEnumFromSchema(schema, context) {
515
+ const nullable = isNullable(schema, context);
516
+ const className = getClassName(schema, context);
517
+ const enumItems = schema.enum.map((val) => {
518
+ return {
519
+ name: codegenUtils.pascalCase(val, { normalize: true }),
520
+ value: val
521
+ };
522
+ });
523
+ if (!enumItems.length) {
524
+ throw new Error(
525
+ `Enum schemas must have at least one enum value. At ${context.schemaPath}.`
526
+ );
527
+ }
528
+ const defaultValue = nullable ? "null" : `${className}.new()`;
529
+ let content = "";
530
+ if (!context.existingTypeIds.includes(className)) {
531
+ content = `enum class ${className} {
532
+ ${enumItems.map((item) => item.name).join(",\n ")};
533
+ val serialValue: String
534
+ get() = when (this) {
535
+ ${enumItems.map((item) => `${item.name} -> "${item.value}"`).join("\n ")}
536
+ }
537
+
538
+ companion object Factory : ${context.clientName}ModelFactory<${className}> {
539
+ @JvmStatic
540
+ override fun new(): ${className} {
541
+ return ${enumItems[0].name}
542
+ }
543
+
544
+ @JvmStatic
545
+ override fun fromJson(input: String): ${className} {
546
+ return when (input) {
547
+ ${enumItems.map((item) => `${item.name}.serialValue -> ${item.name}`).join("\n ")}
548
+ else -> ${enumItems[0].name}
549
+ }
550
+ }
551
+
552
+ @JvmStatic
553
+ override fun fromJsonElement(__input: JsonElement, instancePath: String): ${className} {
554
+ if (__input !is JsonPrimitive) {
555
+ __logError("[WARNING] ${className}.fromJsonElement() expected kotlinx.serialization.json.JsonPrimitive at $instancePath. Got \${__input.javaClass}. Initializing empty ${className}.")
556
+ return new()
557
+ }
558
+ return when (__input.jsonPrimitive.contentOrNull) {
559
+ ${enumItems.map((item) => `"${item.value}" -> ${item.name}`).join("\n ")}
560
+ else -> new()
561
+ }
562
+ }
563
+ }
564
+ }`;
565
+ context.existingTypeIds.push(className);
566
+ }
567
+ return {
568
+ typeName: className,
569
+ isNullable: nullable,
570
+ defaultValue,
571
+ fromJson(input, key) {
572
+ if (nullable) {
573
+ return `when (${input}) {
574
+ is JsonNull -> null
575
+ is JsonPrimitive -> ${className}.fromJsonElement(${input}!!, "$instancePath/${key ?? ""}")
576
+ else -> null
577
+ }`;
578
+ }
579
+ return `when (${input}) {
580
+ is JsonNull -> ${defaultValue}
581
+ is JsonPrimitive -> ${className}.fromJsonElement(${input}!!, "$instancePath/${key}")
582
+ else -> ${defaultValue}
583
+ }`;
584
+ },
585
+ toJson(input, target) {
586
+ if (schema.nullable) {
587
+ return `${target} += when (${input}) {
588
+ is ${className} -> "\\"\${${input}.serialValue}\\""
589
+ else -> "null"
590
+ }`;
591
+ }
592
+ return `${target} += "\\"\${${input}.serialValue}\\""`;
593
+ },
594
+ toQueryString(input, target, key) {
595
+ if (context.isOptional) {
596
+ return `if (${input} != null) {
597
+ ${target}.add("${key}=\${${input}.serialValue}")
598
+ }`;
599
+ }
600
+ if (schema.nullable) {
601
+ return `${target}.add("${key}=\${${input}?.serialValue}")`;
602
+ }
603
+ return `${target}.add("${key}=\${${input}.serialValue}")`;
604
+ },
605
+ content
606
+ };
607
+ }
608
+
609
+ function kotlinMapFromSchema(schema, context) {
610
+ const nullable = isNullable(schema, context);
611
+ const subType = kotlinTypeFromSchema(schema.values, {
612
+ modelPrefix: context.modelPrefix,
613
+ clientName: context.clientName,
614
+ clientVersion: context.clientVersion,
615
+ instancePath: `${context.instancePath}/[value]`,
616
+ schemaPath: `${context.schemaPath}/values`,
617
+ existingTypeIds: context.existingTypeIds
618
+ });
619
+ const typeName = `MutableMap<String, ${subType.typeName}${subType.isNullable ? "?" : ""}>`;
620
+ const defaultValue = nullable ? "null" : "mutableMapOf()";
621
+ return {
622
+ typeName,
623
+ isNullable: nullable,
624
+ defaultValue,
625
+ fromJson(input, key) {
626
+ return `when (${input}) {
627
+ is JsonObject -> {
628
+ val __value: ${typeName} = mutableMapOf()
629
+ for (__entry in ${input}!!.jsonObject.entries) {
630
+ __value[__entry.key] = ${subType.fromJson("__entry.value", key)}
631
+ }
632
+ __value
633
+ }
634
+
635
+ else -> ${defaultValue}
636
+ }`;
637
+ },
638
+ toJson(input, target) {
639
+ if (schema.nullable) {
640
+ return `if (${input} == null) {
641
+ ${target} += "null"
642
+ } else {
643
+ ${target} += "{"
644
+ for ((__index, __entry) in ${input}.entries.withIndex()) {
645
+ if (__index != 0) {
646
+ ${target} += ","
647
+ }
648
+ ${target} += "\\"\${__entry.key}\\":"
649
+ ${subType.toJson("__entry.value", target)}
650
+ }
651
+ ${target} += "}"
652
+ }`;
653
+ }
654
+ return `${target} += "{"
655
+ for ((__index, __entry) in ${input}.entries.withIndex()) {
656
+ if (__index != 0) {
657
+ ${target} += ","
658
+ }
659
+ ${target} += "\\"\${__entry.key}\\":"
660
+ ${subType.toJson("__entry.value", target)}
661
+ }
662
+ ${target} += "}"`;
663
+ },
664
+ toQueryString() {
665
+ return `__logError("[WARNING] nested objects cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
666
+ },
667
+ content: subType.content
668
+ };
669
+ }
670
+
671
+ function defaultToQueryString(context, input, target, key) {
672
+ if (context.isOptional) {
673
+ return `if (${input} != null) {
674
+ ${target}.add("${key}=$${input}")
675
+ }`;
676
+ }
677
+ return `${target}.add("${key}=$${input}")`;
678
+ }
679
+ function defaultToJsonString(context, input, target) {
680
+ return `${target} += ${input}`;
681
+ }
682
+ function kotlinStringFromSchema(schema, context) {
683
+ const nullable = isNullable(schema, context);
684
+ const defaultValue = nullable ? "null" : '""';
685
+ return {
686
+ typeName: "String",
687
+ isNullable: nullable,
688
+ defaultValue,
689
+ fromJson(input) {
690
+ if (nullable) {
691
+ return `when (${input}) {
692
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.contentOrNull
693
+ else -> null
694
+ }`;
695
+ }
696
+ return `when (${input}) {
697
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.contentOrNull ?: ${defaultValue}
698
+ else -> ${defaultValue}
699
+ }`;
700
+ },
701
+ toJson(input, target) {
702
+ if (schema.nullable) {
703
+ return `${target} += when (${input}) {
704
+ is String -> buildString { printQuoted(${input}) }
705
+ else -> "null"
706
+ }`;
707
+ }
708
+ return `${target} += buildString { printQuoted(${input}) }`;
709
+ },
710
+ toQueryString(input, target, key) {
711
+ return defaultToQueryString(context, input, target, key);
712
+ },
713
+ content: ""
714
+ };
715
+ }
716
+ function kotlinBooleanFromSchema(schema, context) {
717
+ const nullable = isNullable(schema, context);
718
+ const defaultValue = nullable ? "null" : "false";
719
+ return {
720
+ typeName: "Boolean",
721
+ isNullable: nullable,
722
+ defaultValue,
723
+ fromJson(input) {
724
+ if (nullable) {
725
+ return `when (${input}) {
726
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.booleanOrNull
727
+ else -> null
728
+ }`;
729
+ }
730
+ return `when (${input}) {
731
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.booleanOrNull ?: ${defaultValue}
732
+ else -> ${defaultValue}
733
+ }`;
734
+ },
735
+ toJson(input, target) {
736
+ return defaultToJsonString(context, input, target);
737
+ },
738
+ toQueryString(input, target, key) {
739
+ return defaultToQueryString(context, input, target, key);
740
+ },
741
+ content: ""
742
+ };
743
+ }
744
+ function kotlinTimestampFromSchema(schema, context) {
745
+ const nullable = isNullable(schema, context);
746
+ const defaultValue = nullable ? "null" : "Instant.now()";
747
+ return {
748
+ typeName: "Instant",
749
+ isNullable: nullable,
750
+ defaultValue,
751
+ fromJson(input) {
752
+ return `when (${input}) {
753
+ is JsonPrimitive ->
754
+ if (${input}!!.jsonPrimitive.isString)
755
+ Instant.parse(${input}!!.jsonPrimitive.content)
756
+ else
757
+ ${defaultValue}
758
+ else -> ${defaultValue}
759
+ }`;
760
+ },
761
+ toJson(input, target) {
762
+ if (schema.nullable) {
763
+ return `${target} += when (${input}) {
764
+ is Instant -> "\\"\${timestampFormatter.format(${input})}\\""
765
+ else -> "null"
766
+ }`;
767
+ }
768
+ return `${target} += "\\"\${timestampFormatter.format(${input})}\\""`;
769
+ },
770
+ toQueryString(input, target, key) {
771
+ if (context.isOptional) {
772
+ return `if (${input} != null) {
773
+ ${target}.add(
774
+ "${key}=\${
775
+ timestampFormatter.format(${input})
776
+ }"
777
+ )
778
+ }`;
779
+ }
780
+ if (schema.nullable) {
781
+ return `${target}.add(
782
+ "${key}=\${
783
+ when (${input}) {
784
+ is Instant -> timestampFormatter.format(${input})
785
+ else -> "null"
786
+ }
787
+ }"
788
+ )`;
789
+ }
790
+ return `${target}.add(
791
+ "${key}=\${
792
+ timestampFormatter.format(${input})
793
+ }"
794
+ )`;
795
+ },
796
+ content: ""
797
+ };
798
+ }
799
+ function kotlinFloat32FromSchema(schema, context) {
800
+ const nullable = isNullable(schema, context);
801
+ const defaultValue = nullable ? "null" : "0.0F";
802
+ return {
803
+ typeName: "Float",
804
+ isNullable: nullable,
805
+ defaultValue,
806
+ fromJson(input) {
807
+ if (nullable) {
808
+ return `when (${input}) {
809
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.floatOrNull
810
+ else -> null
811
+ }`;
812
+ }
813
+ return `when (${input}) {
814
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.floatOrNull ?: ${defaultValue}
815
+ else -> ${defaultValue}
816
+ }`;
817
+ },
818
+ toJson(input, target) {
819
+ return defaultToJsonString(context, input, target);
820
+ },
821
+ toQueryString(input, target, key) {
822
+ return defaultToQueryString(context, input, target, key);
823
+ },
824
+ content: ""
825
+ };
826
+ }
827
+ function kotlinFloat64FromSchema(schema, context) {
828
+ const nullable = isNullable(schema, context);
829
+ const defaultValue = nullable ? "null" : "0.0";
830
+ return {
831
+ typeName: "Double",
832
+ isNullable: nullable,
833
+ defaultValue,
834
+ fromJson(input) {
835
+ if (nullable) {
836
+ return `when (${input}) {
837
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.doubleOrNull
838
+ else -> null
839
+ }`;
840
+ }
841
+ return `when (${input}) {
842
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.doubleOrNull ?: 0.0
843
+ else -> 0.0
844
+ }`;
845
+ },
846
+ toJson(input, target) {
847
+ return defaultToJsonString(context, input, target);
848
+ },
849
+ toQueryString(input, target, key) {
850
+ return defaultToQueryString(context, input, target, key);
851
+ },
852
+ content: ""
853
+ };
854
+ }
855
+ function kotlinInt8FromSchema(schema, context) {
856
+ const nullable = isNullable(schema, context);
857
+ const defaultValue = nullable ? "null" : "0";
858
+ return {
859
+ typeName: "Byte",
860
+ isNullable: nullable,
861
+ defaultValue,
862
+ fromJson(input) {
863
+ if (nullable) {
864
+ return `when (${input}) {
865
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.contentOrNull?.toByteOrNull()
866
+ else -> null
867
+ }`;
868
+ }
869
+ return `when (${input}) {
870
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.contentOrNull?.toByteOrNull() ?: 0
871
+ else -> 0
872
+ }`;
873
+ },
874
+ toJson(input, target) {
875
+ return defaultToJsonString(context, input, target);
876
+ },
877
+ toQueryString(input, target, key) {
878
+ return defaultToQueryString(context, input, target, key);
879
+ },
880
+ content: ""
881
+ };
882
+ }
883
+ function kotlinInt16FromSchema(schema, context) {
884
+ const nullable = isNullable(schema, context);
885
+ const defaultValue = nullable ? "null" : "0";
886
+ return {
887
+ typeName: "Short",
888
+ isNullable: nullable,
889
+ defaultValue,
890
+ fromJson(input) {
891
+ if (nullable) {
892
+ return `when (${input}) {
893
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.contentOrNull?.toShortOrNull()
894
+ else -> null
895
+ }`;
896
+ }
897
+ return `when (${input}) {
898
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.contentOrNull?.toShortOrNull() ?: 0
899
+ else -> 0
900
+ }`;
901
+ },
902
+ toJson(input, target) {
903
+ return defaultToJsonString(context, input, target);
904
+ },
905
+ toQueryString(input, target, key) {
906
+ return defaultToQueryString(context, input, target, key);
907
+ },
908
+ content: ""
909
+ };
910
+ }
911
+ function kotlinInt32FromSchema(schema, context) {
912
+ const nullable = isNullable(schema, context);
913
+ const defaultValue = nullable ? "null" : "0";
914
+ return {
915
+ typeName: "Int",
916
+ isNullable: nullable,
917
+ defaultValue,
918
+ fromJson(input) {
919
+ if (nullable) {
920
+ return `when (${input}) {
921
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.intOrNull
922
+ else -> null
923
+ }`;
924
+ }
925
+ return `when (${input}) {
926
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.intOrNull ?: 0
927
+ else -> 0
928
+ }`;
929
+ },
930
+ toJson(input, target) {
931
+ return defaultToJsonString(context, input, target);
932
+ },
933
+ toQueryString(input, target, key) {
934
+ return defaultToQueryString(context, input, target, key);
935
+ },
936
+ content: ""
937
+ };
938
+ }
939
+ function kotlinInt64FromSchema(schema, context) {
940
+ const nullable = isNullable(schema, context);
941
+ const defaultValue = nullable ? "null" : "0L";
942
+ return {
943
+ typeName: "Long",
944
+ isNullable: nullable,
945
+ defaultValue,
946
+ fromJson(input) {
947
+ if (nullable) {
948
+ return `when (${input}) {
949
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.longOrNull
950
+ else -> null
951
+ }`;
952
+ }
953
+ return `when (${input}) {
954
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.longOrNull ?: 0L
955
+ else -> 0L
956
+ }`;
957
+ },
958
+ toJson(input, target) {
959
+ if (schema.nullable) {
960
+ return `${target} += when (${input}) {
961
+ is Long -> "\\"$${input}\\""
962
+ else -> "null"
963
+ }`;
964
+ }
965
+ return `${target} += "\\"$${input}\\""`;
966
+ },
967
+ toQueryString(input, target, key) {
968
+ return defaultToQueryString(context, input, target, key);
969
+ },
970
+ content: ""
971
+ };
972
+ }
973
+ function kotlinUint8FromSchema(schema, context) {
974
+ const nullable = isNullable(schema, context);
975
+ const defaultValue = nullable ? "null" : "0u";
976
+ return {
977
+ typeName: "UByte",
978
+ isNullable: nullable,
979
+ defaultValue,
980
+ fromJson(input) {
981
+ if (nullable) {
982
+ return `when (${input}) {
983
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.contentOrNull?.toUByteOrNull()
984
+ else -> null
985
+ }`;
986
+ }
987
+ return `when (${input}) {
988
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.contentOrNull?.toUByteOrNull() ?: 0u
989
+ else -> 0u
990
+ }`;
991
+ },
992
+ toJson(input, target) {
993
+ return defaultToJsonString(context, input, target);
994
+ },
995
+ toQueryString(input, target, key) {
996
+ return defaultToQueryString(context, input, target, key);
997
+ },
998
+ content: ""
999
+ };
1000
+ }
1001
+ function kotlinUint16FromSchema(schema, context) {
1002
+ const nullable = isNullable(schema, context);
1003
+ const defaultValue = nullable ? "null" : "0u";
1004
+ return {
1005
+ typeName: "UShort",
1006
+ isNullable: nullable,
1007
+ defaultValue,
1008
+ fromJson(input) {
1009
+ if (nullable) {
1010
+ return `when (${input}) {
1011
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.contentOrNull?.toUShortOrNull()
1012
+ else -> null
1013
+ }`;
1014
+ }
1015
+ return `when (${input}) {
1016
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.contentOrNull?.toUShortOrNull() ?: 0u
1017
+ else -> 0u
1018
+ }`;
1019
+ },
1020
+ toJson(input, target) {
1021
+ return defaultToJsonString(context, input, target);
1022
+ },
1023
+ toQueryString(input, target, key) {
1024
+ return defaultToQueryString(context, input, target, key);
1025
+ },
1026
+ content: ""
1027
+ };
1028
+ }
1029
+ function kotlinUint32FromSchema(schema, context) {
1030
+ const nullable = isNullable(schema, context);
1031
+ const defaultValue = nullable ? "null" : "0u";
1032
+ return {
1033
+ typeName: "UInt",
1034
+ isNullable: nullable,
1035
+ defaultValue,
1036
+ fromJson(input) {
1037
+ if (nullable) {
1038
+ return `when (${input}) {
1039
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.contentOrNull?.toUIntOrNull()
1040
+ else -> null
1041
+ }`;
1042
+ }
1043
+ return `when (${input}) {
1044
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.contentOrNull?.toUIntOrNull() ?: 0u
1045
+ else -> 0u
1046
+ }`;
1047
+ },
1048
+ toJson(input, target) {
1049
+ return defaultToJsonString(context, input, target);
1050
+ },
1051
+ toQueryString(input, target, key) {
1052
+ return defaultToQueryString(context, input, target, key);
1053
+ },
1054
+ content: ""
1055
+ };
1056
+ }
1057
+ function kotlinUint64FromSchema(schema, context) {
1058
+ const nullable = isNullable(schema, context);
1059
+ const defaultValue = nullable ? "null" : "0UL";
1060
+ return {
1061
+ typeName: "ULong",
1062
+ isNullable: nullable,
1063
+ defaultValue,
1064
+ fromJson(input) {
1065
+ if (nullable) {
1066
+ return `when (${input}) {
1067
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.contentOrNull?.toULongOrNull()
1068
+ else -> null
1069
+ }`;
1070
+ }
1071
+ return `when (${input}) {
1072
+ is JsonPrimitive -> ${input}!!.jsonPrimitive.contentOrNull?.toULongOrNull() ?: 0UL
1073
+ else -> 0UL
1074
+ }`;
1075
+ },
1076
+ toJson(input, target) {
1077
+ if (schema.nullable) {
1078
+ return `${target} += when (${input}) {
1079
+ is ULong -> "\\"$${input}\\""
1080
+ else -> "null"
1081
+ }`;
1082
+ }
1083
+ return `${target} += "\\"$${input}\\""`;
1084
+ },
1085
+ toQueryString(input, target, key) {
1086
+ return defaultToQueryString(context, input, target, key);
1087
+ },
1088
+ content: ""
1089
+ };
1090
+ }
1091
+
1092
+ function kotlinProcedureFromSchema(schema, context) {
1093
+ switch (schema.transport) {
1094
+ case "http":
1095
+ return kotlinHttpRpcFromSchema(schema, context);
1096
+ case "ws":
1097
+ return kotlinWsRpcFromSchema();
1098
+ default:
1099
+ console.warn(
1100
+ `[codegen-kotlin] Unknown transport type "${schema.transport}". Skipping "${context.instancePath}".`
1101
+ );
1102
+ return "";
1103
+ }
1104
+ }
1105
+ function kotlinHttpRpcFromSchema(schema, context) {
1106
+ const name = getProcedureName(context);
1107
+ const params = schema.params ? kotlinClassName(`${context.modelPrefix}_${schema.params}`) : void 0;
1108
+ const response = schema.response ? kotlinClassName(`${context.modelPrefix}_${schema.response}`) : void 0;
1109
+ if (schema.isEventStream) {
1110
+ return `fun ${name}(
1111
+ scope: CoroutineScope,
1112
+ ${params ? `params: ${params},` : ""}
1113
+ lastEventId: String? = null,
1114
+ bufferCapacity: Int = 1024,
1115
+ onOpen: ((response: HttpResponse) -> Unit) = {},
1116
+ onClose: (() -> Unit) = {},
1117
+ onError: ((error: ${context.clientName}Error) -> Unit) = {},
1118
+ onConnectionError: ((error: ${context.clientName}Error) -> Unit) = {},
1119
+ onData: ((${response ? `data: ${response}` : ""}) -> Unit) = {},
1120
+ ): Job {
1121
+ val job = scope.launch {
1122
+ __handleSseRequest(
1123
+ scope = scope,
1124
+ httpClient = httpClient,
1125
+ url = "$baseUrl${schema.path}",
1126
+ method = HttpMethod.${codegenUtils.pascalCase(schema.method, { normalize: true })},
1127
+ params = ${params ? "params" : "null"},
1128
+ headers = headers,
1129
+ backoffTime = 0,
1130
+ maxBackoffTime = 30000L,
1131
+ lastEventId = lastEventId,
1132
+ bufferCapacity = bufferCapacity,
1133
+ onOpen = onOpen,
1134
+ onClose = onClose,
1135
+ onError = onError,
1136
+ onConnectionError = onConnectionError,
1137
+ onData = { str ->
1138
+ ${response ? `val data = ${response}.fromJson(str)` : ""}
1139
+ onData(${response ? "data" : ""})
1140
+ }
1141
+ )
1142
+ }
1143
+ return job
1144
+ }`;
1145
+ }
1146
+ const headingCheck = `if (response.headers["Content-Type"] != "application/json") {
1147
+ throw ${context.clientName}Error(
1148
+ code = 0,
1149
+ errorMessage = "Expected server to return Content-Type \\"application/json\\". Got \\"\${response.headers["Content-Type"]}\\"",
1150
+ data = JsonPrimitive(response.bodyAsText()),
1151
+ stack = null,
1152
+ )
1153
+ }`;
1154
+ return `suspend fun ${name}(${params ? `params: ${params}` : ""}): ${response ?? "Unit"} {
1155
+ val response = __prepareRequest(
1156
+ client = httpClient,
1157
+ url = "$baseUrl${schema.path}",
1158
+ method = HttpMethod.${codegenUtils.pascalCase(schema.method, { normalize: true })},
1159
+ params = ${params ? "params" : null},
1160
+ headers = headers?.invoke(),
1161
+ ).execute()
1162
+ ${response ? headingCheck : ""}
1163
+ if (response.status.value in 200..299) {
1164
+ return ${response ? `${response}.fromJson(response.bodyAsText())` : ""}
1165
+ }
1166
+ throw ${context.clientName}Error.fromJson(response.bodyAsText())
1167
+ }`;
1168
+ }
1169
+ function kotlinWsRpcFromSchema(schema, context) {
1170
+ return "";
1171
+ }
1172
+ function kotlinServiceFromSchema(schema, context) {
1173
+ const name = getServiceName(context);
1174
+ const procedureParts = [];
1175
+ const subServiceParts = [];
1176
+ for (const key of Object.keys(schema)) {
1177
+ const kotlinKey = kotlinIdentifier(key);
1178
+ const subSchema = schema[key];
1179
+ if (codegenUtils.isServiceDefinition(subSchema)) {
1180
+ const subService = kotlinServiceFromSchema(subSchema, {
1181
+ ...context,
1182
+ instancePath: `${context.instancePath}.${key}`
1183
+ });
1184
+ procedureParts.push(`val ${kotlinKey}: ${subService.name} = ${subService.name}(
1185
+ httpClient = httpClient,
1186
+ baseUrl = baseUrl,
1187
+ headers = headers,
1188
+ )`);
1189
+ if (subService.content) {
1190
+ subServiceParts.push(subService.content);
1191
+ }
1192
+ continue;
1193
+ }
1194
+ if (codegenUtils.isRpcDefinition(subSchema)) {
1195
+ const procedure = kotlinProcedureFromSchema(subSchema, {
1196
+ ...context,
1197
+ instancePath: `${context.instancePath}.${key}`
1198
+ });
1199
+ if (procedure.length > 0) {
1200
+ procedureParts.push(procedure);
1201
+ }
1202
+ continue;
1203
+ }
1204
+ }
1205
+ return {
1206
+ name,
1207
+ content: `class ${name}(
1208
+ private val httpClient: HttpClient,
1209
+ private val baseUrl: String,
1210
+ private val headers: headersFn,
1211
+ ) {
1212
+ ${procedureParts.join("\n\n ")}
1213
+ }
1214
+
1215
+ ${subServiceParts.join("\n\n")}`
1216
+ };
1217
+ }
1218
+ function getProcedureName(context) {
1219
+ const name = context.instancePath.split(".").pop() ?? "";
1220
+ return kotlinIdentifier(name);
1221
+ }
1222
+ function getServiceName(context) {
1223
+ const name = codegenUtils.pascalCase(context.instancePath.split(".").join("_"));
1224
+ return `${context.clientName}${name}Service`;
1225
+ }
1226
+
1227
+ function kotlinRefFromSchema(schema, context) {
1228
+ const typeName = kotlinClassName(schema.ref);
1229
+ const nullable = isNullable(schema, context);
1230
+ const defaultValue = nullable ? "null" : `${typeName}.new()`;
1231
+ return {
1232
+ typeName,
1233
+ isNullable: nullable,
1234
+ defaultValue,
1235
+ fromJson(input, key) {
1236
+ return `when (${input}) {
1237
+ is JsonObject -> ${typeName}.fromJsonElement(
1238
+ ${input}!!,
1239
+ "$instancePath/${key}",
1240
+ )
1241
+ else -> ${defaultValue}
1242
+ }`;
1243
+ },
1244
+ toJson(input, target) {
1245
+ if (schema.nullable) {
1246
+ return `${target} += ${input}?.toJson()`;
1247
+ }
1248
+ return `${target} += ${input}.toJson()`;
1249
+ },
1250
+ toQueryString() {
1251
+ return `__logError("[WARNING] nested objects cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
1252
+ },
1253
+ content: ""
1254
+ };
1255
+ }
1256
+
1257
+ const kotlinClientGenerator = codegenUtils.defineClientGeneratorPlugin(
1258
+ (options) => {
1259
+ return {
1260
+ generator(def) {
1261
+ const client = kotlinClientFromAppDefinition(def, options);
1262
+ fs__default.writeFileSync(options.outputFile, client);
1263
+ },
1264
+ options
1265
+ };
1266
+ }
1267
+ );
1268
+ function kotlinClientFromAppDefinition(def, options) {
1269
+ const clientName = kotlinClassName(options.clientName ?? "Client");
1270
+ const context = {
1271
+ modelPrefix: options.modelPrefix ?? "",
1272
+ clientName,
1273
+ clientVersion: def.info?.version ?? "",
1274
+ instancePath: "",
1275
+ schemaPath: "",
1276
+ existingTypeIds: []
1277
+ };
1278
+ const modelParts = [];
1279
+ for (const key of Object.keys(def.definitions)) {
1280
+ const subSchema = def.definitions[key];
1281
+ const model = kotlinTypeFromSchema(subSchema, {
1282
+ modelPrefix: context.modelPrefix,
1283
+ clientName: context.clientName,
1284
+ clientVersion: context.clientVersion,
1285
+ instancePath: `/${key}`,
1286
+ schemaPath: `/definitions`,
1287
+ existingTypeIds: context.existingTypeIds
1288
+ });
1289
+ if (model.content) {
1290
+ modelParts.push(model.content);
1291
+ }
1292
+ }
1293
+ const procedureParts = [];
1294
+ const subServiceParts = [];
1295
+ const services = codegenUtils.unflattenProcedures(def.procedures);
1296
+ for (const key of Object.keys(services)) {
1297
+ const subSchema = services[key];
1298
+ if (codegenUtils.isServiceDefinition(subSchema)) {
1299
+ const kotlinKey = kotlinIdentifier(key);
1300
+ const subService = kotlinServiceFromSchema(subSchema, {
1301
+ ...context,
1302
+ instancePath: `${key}`
1303
+ });
1304
+ procedureParts.push(`val ${kotlinKey}: ${subService.name} = ${subService.name}(
1305
+ httpClient = httpClient,
1306
+ baseUrl = baseUrl,
1307
+ headers = headers,
1308
+ )`);
1309
+ if (subService.content) {
1310
+ subServiceParts.push(subService.content);
1311
+ }
1312
+ continue;
1313
+ }
1314
+ if (codegenUtils.isRpcDefinition(subSchema)) {
1315
+ const procedure = kotlinProcedureFromSchema(subSchema, {
1316
+ ...context,
1317
+ instancePath: key
1318
+ });
1319
+ if (procedure.length) {
1320
+ procedureParts.push(procedure);
1321
+ }
1322
+ continue;
1323
+ }
1324
+ }
1325
+ if (procedureParts.length === 0) {
1326
+ return `${getHeader({ clientName, clientVersion: context.clientVersion, packageName: "" })}
1327
+ ${getUtilityClasses(clientName)}
1328
+
1329
+ ${modelParts.join("\n\n")}
1330
+
1331
+ ${getUtilityFunctions(clientName)}`;
1332
+ }
1333
+ return `${getHeader({ clientName, clientVersion: context.clientVersion, packageName: "" })}
1334
+
1335
+ class ${clientName}(
1336
+ private val httpClient: HttpClient,
1337
+ private val baseUrl: String,
1338
+ private val headers: headersFn,
1339
+ ) {
1340
+ ${procedureParts.join("\n\n ")}
1341
+ }
1342
+
1343
+ ${subServiceParts.join("\n\n")}
1344
+
1345
+ ${getUtilityClasses(clientName)}
1346
+
1347
+ ${modelParts.join("\n\n")}
1348
+
1349
+ ${getUtilityFunctions(clientName)}`;
1350
+ }
1351
+ function kotlinTypeFromSchema(schema, context) {
1352
+ if (codegenUtils.isSchemaFormType(schema)) {
1353
+ switch (schema.type) {
1354
+ case "string":
1355
+ return kotlinStringFromSchema(schema, context);
1356
+ case "boolean":
1357
+ return kotlinBooleanFromSchema(schema, context);
1358
+ case "timestamp":
1359
+ return kotlinTimestampFromSchema(schema, context);
1360
+ case "float32":
1361
+ return kotlinFloat32FromSchema(schema, context);
1362
+ case "float64":
1363
+ return kotlinFloat64FromSchema(schema, context);
1364
+ case "int8":
1365
+ return kotlinInt8FromSchema(schema, context);
1366
+ case "int16":
1367
+ return kotlinInt16FromSchema(schema, context);
1368
+ case "int32":
1369
+ return kotlinInt32FromSchema(schema, context);
1370
+ case "int64":
1371
+ return kotlinInt64FromSchema(schema, context);
1372
+ case "uint8":
1373
+ return kotlinUint8FromSchema(schema, context);
1374
+ case "uint16":
1375
+ return kotlinUint16FromSchema(schema, context);
1376
+ case "uint32":
1377
+ return kotlinUint32FromSchema(schema, context);
1378
+ case "uint64":
1379
+ return kotlinUint64FromSchema(schema, context);
1380
+ default:
1381
+ schema.type;
1382
+ throw new Error(`Unhandled schema.type case`);
1383
+ }
1384
+ }
1385
+ if (codegenUtils.isSchemaFormEnum(schema)) {
1386
+ return kotlinEnumFromSchema(schema, context);
1387
+ }
1388
+ if (codegenUtils.isSchemaFormProperties(schema)) {
1389
+ return kotlinObjectFromSchema(schema, context);
1390
+ }
1391
+ if (codegenUtils.isSchemaFormElements(schema)) {
1392
+ return kotlinArrayFromSchema(schema, context);
1393
+ }
1394
+ if (codegenUtils.isSchemaFormValues(schema)) {
1395
+ return kotlinMapFromSchema(schema, context);
1396
+ }
1397
+ if (codegenUtils.isSchemaFormDiscriminator(schema)) {
1398
+ return kotlinDiscriminatorFromSchema(schema, context);
1399
+ }
1400
+ if (codegenUtils.isSchemaFormRef(schema)) {
1401
+ return kotlinRefFromSchema(schema, context);
1402
+ }
1403
+ return kotlinAnyFromSchema(schema, context);
1404
+ }
1405
+ function getUtilityClasses(clientName) {
1406
+ return `interface ${clientName}Model {
1407
+ fun toJson(): String
1408
+ fun toUrlQueryParams(): String
1409
+ }
1410
+
1411
+ interface ${clientName}ModelFactory<T> {
1412
+ fun new(): T
1413
+ fun fromJson(input: String): T
1414
+ fun fromJsonElement(
1415
+ __input: JsonElement,
1416
+ instancePath: String = "",
1417
+ ): T
1418
+ }
1419
+
1420
+ data class ${clientName}Error(
1421
+ val code: Int,
1422
+ val errorMessage: String,
1423
+ val data: JsonElement?,
1424
+ val stack: List<String>?,
1425
+ ) : Exception(errorMessage), ${clientName}Model {
1426
+ override fun toJson(): String {
1427
+ var output = "{"
1428
+ output += "\\"code\\":"
1429
+ output += "$code"
1430
+ output += ",\\"message\\":"
1431
+ output += buildString { printQuoted(errorMessage) }
1432
+ if (data != null) {
1433
+ output += ",\\"data\\":"
1434
+ output += JsonInstance.encodeToString(data)
1435
+ }
1436
+ if (stack != null) {
1437
+ output += ",\\"stack\\":"
1438
+ output += "["
1439
+ for ((__index, __element) in stack.withIndex()) {
1440
+ if (__index > 0) {
1441
+ output += ","
1442
+ }
1443
+ output += buildString { printQuoted(__element) }
1444
+ }
1445
+ output += "]"
1446
+ }
1447
+ output += "}"
1448
+ return output
1449
+ }
1450
+
1451
+ override fun toUrlQueryParams(): String {
1452
+ val queryParts = mutableListOf<String>()
1453
+ queryParts.add("code=\${code}")
1454
+ queryParts.add("message=\${errorMessage}")
1455
+ return queryParts.joinToString("&")
1456
+ }
1457
+
1458
+ companion object Factory : ${clientName}ModelFactory<${clientName}Error> {
1459
+ override fun new(): ${clientName}Error {
1460
+ return ${clientName}Error(
1461
+ code = 0,
1462
+ errorMessage = "",
1463
+ data = null,
1464
+ stack = null
1465
+ )
1466
+ }
1467
+
1468
+ override fun fromJson(input: String): ${clientName}Error {
1469
+ return fromJsonElement(JsonInstance.parseToJsonElement(input))
1470
+ }
1471
+
1472
+ override fun fromJsonElement(__input: JsonElement, instancePath: String): ${clientName}Error {
1473
+ if (__input !is JsonObject) {
1474
+ __logError("[WARNING] ${clientName}Error.fromJsonElement() expected JsonObject at $instancePath. Got \${__input.javaClass}. Initializing empty ${clientName}Error.")
1475
+ }
1476
+ val code = when (__input.jsonObject["code"]) {
1477
+ is JsonPrimitive -> __input.jsonObject["code"]!!.jsonPrimitive.intOrNull ?: 0
1478
+ else -> 0
1479
+ }
1480
+ val errorMessage = when (__input.jsonObject["message"]) {
1481
+ is JsonPrimitive -> __input.jsonObject["message"]!!.jsonPrimitive.contentOrNull ?: ""
1482
+ else -> ""
1483
+ }
1484
+ val data = when (__input.jsonObject["data"]) {
1485
+ is JsonNull -> null
1486
+ is JsonElement -> __input.jsonObject["data"]!!
1487
+ else -> null
1488
+ }
1489
+ val stack = when (__input.jsonObject["stack"]) {
1490
+ is JsonArray -> {
1491
+ val stackVal = mutableListOf<String>()
1492
+ for (item in __input.jsonObject["stack"]!!.jsonArray) {
1493
+ stackVal.add(
1494
+ when (item) {
1495
+ is JsonPrimitive -> item.contentOrNull ?: ""
1496
+ else -> ""
1497
+ }
1498
+ )
1499
+ }
1500
+ stackVal
1501
+ }
1502
+
1503
+ else -> null
1504
+
1505
+ }
1506
+ return ${clientName}Error(
1507
+ code,
1508
+ errorMessage,
1509
+ data,
1510
+ stack,
1511
+ )
1512
+ }
1513
+
1514
+ }
1515
+ }`;
1516
+ }
1517
+ function getUtilityFunctions(clientName) {
1518
+ return `// Implementation copied from https://github.com/Kotlin/kotlinx.serialization/blob/d0ae697b9394103879e6c7f836d0f7cf128f4b1e/formats/json/commonMain/src/kotlinx/serialization/json/internal/StringOps.kt#L45
1519
+ internal const val STRING = '"'
1520
+
1521
+ private fun toHexChar(i: Int): Char {
1522
+ val d = i and 0xf
1523
+ return if (d < 10) (d + '0'.code).toChar()
1524
+ else (d - 10 + 'a'.code).toChar()
1525
+ }
1526
+
1527
+ internal val ESCAPE_STRINGS: Array<String?> = arrayOfNulls<String>(93).apply {
1528
+ for (c in 0..0x1f) {
1529
+ val c1 = toHexChar(c shr 12)
1530
+ val c2 = toHexChar(c shr 8)
1531
+ val c3 = toHexChar(c shr 4)
1532
+ val c4 = toHexChar(c)
1533
+ this[c] = "\\\\u$c1$c2$c3$c4"
1534
+ }
1535
+ this['"'.code] = "\\\\\\""
1536
+ this['\\\\'.code] = "\\\\\\\\"
1537
+ this['\\t'.code] = "\\\\t"
1538
+ this['\\b'.code] = "\\\\b"
1539
+ this['\\n'.code] = "\\\\n"
1540
+ this['\\r'.code] = "\\\\r"
1541
+ this[0x0c] = "\\\\f"
1542
+ }
1543
+
1544
+ internal val ESCAPE_MARKERS: ByteArray = ByteArray(93).apply {
1545
+ for (c in 0..0x1f) {
1546
+ this[c] = 1.toByte()
1547
+ }
1548
+ this['"'.code] = '"'.code.toByte()
1549
+ this['\\\\'.code] = '\\\\'.code.toByte()
1550
+ this['\\t'.code] = 't'.code.toByte()
1551
+ this['\\b'.code] = 'b'.code.toByte()
1552
+ this['\\n'.code] = 'n'.code.toByte()
1553
+ this['\\r'.code] = 'r'.code.toByte()
1554
+ this[0x0c] = 'f'.code.toByte()
1555
+ }
1556
+
1557
+ internal fun StringBuilder.printQuoted(value: String) {
1558
+ append(STRING)
1559
+ var lastPos = 0
1560
+ for (i in value.indices) {
1561
+ val c = value[i].code
1562
+ if (c < ESCAPE_STRINGS.size && ESCAPE_STRINGS[c] != null) {
1563
+ append(value, lastPos, i) // flush prev
1564
+ append(ESCAPE_STRINGS[c])
1565
+ lastPos = i + 1
1566
+ }
1567
+ }
1568
+
1569
+ if (lastPos != 0) append(value, lastPos, value.length)
1570
+ else append(value)
1571
+ append(STRING)
1572
+ }
1573
+
1574
+ private fun __logError(string: String) {
1575
+ System.err.println(string)
1576
+ }
1577
+
1578
+ private suspend fun __prepareRequest(
1579
+ client: HttpClient,
1580
+ url: String,
1581
+ method: HttpMethod,
1582
+ params: ${clientName}Model?,
1583
+ headers: MutableMap<String, String>?,
1584
+ ): HttpStatement {
1585
+ var finalUrl = url
1586
+ var finalBody = ""
1587
+ when (method) {
1588
+ HttpMethod.Get, HttpMethod.Head -> {
1589
+ finalUrl = "$finalUrl?\${params?.toUrlQueryParams() ?: ""}"
1590
+ }
1591
+
1592
+ HttpMethod.Post, HttpMethod.Put, HttpMethod.Patch, HttpMethod.Delete -> {
1593
+ finalBody = params?.toJson() ?: ""
1594
+ }
1595
+ }
1596
+ val builder = HttpRequestBuilder()
1597
+ builder.method = method
1598
+ builder.url(finalUrl)
1599
+ builder.timeout {
1600
+ requestTimeoutMillis = 10 * 60 * 1000
1601
+ }
1602
+ if (headers != null) {
1603
+ for (entry in headers.entries) {
1604
+ builder.headers[entry.key] = entry.value
1605
+ }
1606
+ }
1607
+ builder.headers["client-version"] = generatedClientVersion
1608
+ if (method != HttpMethod.Get && method != HttpMethod.Head) {
1609
+ builder.setBody(finalBody)
1610
+ }
1611
+ return client.prepareRequest(builder)
1612
+ }
1613
+
1614
+ private fun __parseSseEvent(input: String): __SseEvent {
1615
+ val lines = input.split("\\n")
1616
+ var id: String? = null
1617
+ var event: String? = null
1618
+ var data: String = ""
1619
+ for (line in lines) {
1620
+ if (line.startsWith("id: ")) {
1621
+ id = line.substring(3).trim()
1622
+ continue
1623
+ }
1624
+ if (line.startsWith("event: ")) {
1625
+ event = line.substring(6).trim()
1626
+ continue
1627
+ }
1628
+ if (line.startsWith("data: ")) {
1629
+ data = line.substring(5).trim()
1630
+ continue
1631
+ }
1632
+ }
1633
+ return __SseEvent(id, event, data)
1634
+ }
1635
+
1636
+ private class __SseEvent(val id: String? = null, val event: String? = null, val data: String)
1637
+
1638
+ private class __SseEventParsingResult(val events: List<__SseEvent>, val leftover: String)
1639
+
1640
+ private fun __parseSseEvents(input: String): __SseEventParsingResult {
1641
+ val inputs = input.split("\\n\\n").toMutableList()
1642
+ if (inputs.isEmpty()) {
1643
+ return __SseEventParsingResult(
1644
+ events = listOf(),
1645
+ leftover = "",
1646
+ )
1647
+ }
1648
+ if (inputs.size == 1) {
1649
+ return __SseEventParsingResult(
1650
+ events = listOf(),
1651
+ leftover = inputs.last(),
1652
+ )
1653
+ }
1654
+ val leftover = inputs.last()
1655
+ inputs.removeLast()
1656
+ val events = mutableListOf<__SseEvent>()
1657
+ for (item in inputs) {
1658
+ if (item.contains("data: ")) {
1659
+ events.add(__parseSseEvent(item))
1660
+ }
1661
+ }
1662
+ return __SseEventParsingResult(
1663
+ events = events,
1664
+ leftover = leftover,
1665
+ )
1666
+ }
1667
+
1668
+ private suspend fun __handleSseRequest(
1669
+ scope: CoroutineScope,
1670
+ httpClient: HttpClient,
1671
+ url: String,
1672
+ method: HttpMethod,
1673
+ params: ${clientName}Model?,
1674
+ headers: headersFn,
1675
+ backoffTime: Long,
1676
+ maxBackoffTime: Long,
1677
+ lastEventId: String?,
1678
+ onOpen: ((response: HttpResponse) -> Unit) = {},
1679
+ onClose: (() -> Unit) = {},
1680
+ onError: ((error: ${clientName}Error) -> Unit) = {},
1681
+ onData: ((data: String) -> Unit) = {},
1682
+ onConnectionError: ((error: ${clientName}Error) -> Unit) = {},
1683
+ bufferCapacity: Int,
1684
+ ) {
1685
+ val finalHeaders = headers?.invoke() ?: mutableMapOf()
1686
+ var lastId = lastEventId
1687
+ // exponential backoff maxing out at 32 seconds
1688
+ if (backoffTime > 0) {
1689
+ withContext(scope.coroutineContext) {
1690
+ Thread.sleep(backoffTime)
1691
+ }
1692
+ }
1693
+ var newBackoffTime =
1694
+ if (backoffTime == 0L) 2L else if (backoffTime * 2L >= maxBackoffTime) maxBackoffTime else backoffTime * 2L
1695
+ if (lastId != null) {
1696
+ finalHeaders["Last-Event-ID"] = lastId.toString()
1697
+ }
1698
+ val request = __prepareRequest(
1699
+ client = httpClient,
1700
+ url = url,
1701
+ method = method,
1702
+ params = params,
1703
+ headers = finalHeaders,
1704
+ )
1705
+ try {
1706
+ request.execute { httpResponse ->
1707
+ try {
1708
+ onOpen(httpResponse)
1709
+ } catch (e: CancellationException) {
1710
+ onClose()
1711
+ return@execute
1712
+ }
1713
+ if (httpResponse.status.value !in 200..299) {
1714
+ try {
1715
+ if (httpResponse.headers["Content-Type"] == "application/json") {
1716
+ onConnectionError(
1717
+ ${clientName}Error.fromJson(httpResponse.bodyAsText())
1718
+ )
1719
+ } else {
1720
+ onConnectionError(
1721
+ ${clientName}Error(
1722
+ code = httpResponse.status.value,
1723
+ errorMessage = httpResponse.status.description,
1724
+ data = JsonPrimitive(httpResponse.bodyAsText()),
1725
+ stack = null,
1726
+ )
1727
+ )
1728
+ }
1729
+ } catch (e: CancellationException) {
1730
+ onClose()
1731
+ return@execute
1732
+ }
1733
+ __handleSseRequest(
1734
+ scope = scope,
1735
+ httpClient = httpClient,
1736
+ url = url,
1737
+ method = method,
1738
+ params = params,
1739
+ headers = headers,
1740
+ backoffTime = newBackoffTime,
1741
+ maxBackoffTime = maxBackoffTime,
1742
+ lastEventId = lastId,
1743
+ bufferCapacity = bufferCapacity,
1744
+ onOpen = onOpen,
1745
+ onClose = onClose,
1746
+ onError = onError,
1747
+ onData = onData,
1748
+ onConnectionError = onConnectionError,
1749
+ )
1750
+ return@execute
1751
+ }
1752
+ if (httpResponse.headers["Content-Type"] != "text/event-stream") {
1753
+ try {
1754
+ onConnectionError(
1755
+ ${clientName}Error(
1756
+ code = 0,
1757
+ errorMessage = "Expected server to return Content-Type \\"text/event-stream\\". Got \\"\${httpResponse.headers["Content-Type"]}\\"",
1758
+ data = JsonPrimitive(httpResponse.bodyAsText()),
1759
+ stack = null,
1760
+ )
1761
+ )
1762
+ } catch (e: CancellationException) {
1763
+ return@execute
1764
+ }
1765
+ __handleSseRequest(
1766
+ scope = scope,
1767
+ httpClient = httpClient,
1768
+ url = url,
1769
+ method = method,
1770
+ params = params,
1771
+ headers = headers,
1772
+ backoffTime = newBackoffTime,
1773
+ maxBackoffTime = maxBackoffTime,
1774
+ lastEventId = lastId,
1775
+ bufferCapacity = bufferCapacity,
1776
+ onOpen = onOpen,
1777
+ onClose = onClose,
1778
+ onError = onError,
1779
+ onData = onData,
1780
+ onConnectionError = onConnectionError,
1781
+ )
1782
+ return@execute
1783
+ }
1784
+ newBackoffTime = 0
1785
+ val channel: ByteReadChannel = httpResponse.bodyAsChannel()
1786
+ var pendingData = ""
1787
+ while (!channel.isClosedForRead) {
1788
+ val buffer = ByteBuffer.allocateDirect(bufferCapacity)
1789
+ val read = channel.readAvailable(buffer)
1790
+ if (read == -1) break
1791
+ buffer.flip()
1792
+ val input = Charsets.UTF_8.decode(buffer).toString()
1793
+ val parsedResult = __parseSseEvents("\${pendingData}\${input}")
1794
+ pendingData = parsedResult.leftover
1795
+ for (event in parsedResult.events) {
1796
+ if (event.id != null) {
1797
+ lastId = event.id
1798
+ }
1799
+ when (event.event) {
1800
+ "message" -> {
1801
+ try {
1802
+ onData(event.data)
1803
+ } catch (e: CancellationException) {
1804
+ onClose()
1805
+ return@execute
1806
+ }
1807
+ }
1808
+
1809
+ "done" -> {
1810
+ onClose()
1811
+ return@execute
1812
+ }
1813
+
1814
+ "error" -> {
1815
+ val error = ${clientName}Error.fromJson(event.data)
1816
+ try {
1817
+ onError(error)
1818
+ } catch (e: CancellationException) {
1819
+ onClose()
1820
+ return@execute
1821
+ }
1822
+ }
1823
+
1824
+ else -> {}
1825
+ }
1826
+ }
1827
+ }
1828
+ __handleSseRequest(
1829
+ scope = scope,
1830
+ httpClient = httpClient,
1831
+ url = url,
1832
+ method = method,
1833
+ params = params,
1834
+ headers = headers,
1835
+ backoffTime = newBackoffTime,
1836
+ maxBackoffTime = maxBackoffTime,
1837
+ lastEventId = lastId,
1838
+ bufferCapacity = bufferCapacity,
1839
+ onOpen = onOpen,
1840
+ onClose = onClose,
1841
+ onError = onError,
1842
+ onData = onData,
1843
+ onConnectionError = onConnectionError,
1844
+ )
1845
+ }
1846
+ } catch (e: java.net.ConnectException) {
1847
+ onConnectionError(
1848
+ ${clientName}Error(
1849
+ code = 503,
1850
+ errorMessage = if (e.message != null) e.message!! else "Error connecting to $url",
1851
+ data = JsonPrimitive(e.toString()),
1852
+ stack = e.stackTraceToString().split("\\n"),
1853
+ )
1854
+ )
1855
+ __handleSseRequest(
1856
+ scope = scope,
1857
+ httpClient = httpClient,
1858
+ url = url,
1859
+ method = method,
1860
+ params = params,
1861
+ headers = headers,
1862
+ backoffTime = newBackoffTime,
1863
+ maxBackoffTime = maxBackoffTime,
1864
+ lastEventId = lastId,
1865
+ bufferCapacity = bufferCapacity,
1866
+ onOpen = onOpen,
1867
+ onClose = onClose,
1868
+ onError = onError,
1869
+ onData = onData,
1870
+ onConnectionError = onConnectionError,
1871
+ )
1872
+ return
1873
+ } catch (e: Exception) {
1874
+ __handleSseRequest(
1875
+ scope = scope,
1876
+ httpClient = httpClient,
1877
+ url = url,
1878
+ method = method,
1879
+ params = params,
1880
+ headers = headers,
1881
+ backoffTime = newBackoffTime,
1882
+ maxBackoffTime = maxBackoffTime,
1883
+ lastEventId = lastId,
1884
+ bufferCapacity = bufferCapacity,
1885
+ onOpen = onOpen,
1886
+ onClose = onClose,
1887
+ onError = onError,
1888
+ onData = onData,
1889
+ onConnectionError = onConnectionError,
1890
+ )
1891
+ }
1892
+ }`;
1893
+ }
1894
+ function getHeader(options) {
1895
+ return `@file:Suppress(
1896
+ "FunctionName", "LocalVariableName", "UNNECESSARY_NOT_NULL_ASSERTION", "ClassName", "NAME_SHADOWING",
1897
+ "USELESS_IS_CHECK", "unused", "RemoveRedundantQualifierName", "CanBeParameter", "RedundantUnitReturnType",
1898
+ "RedundantExplicitType"
1899
+ )
1900
+
1901
+ import io.ktor.client.*
1902
+ import io.ktor.client.plugins.*
1903
+ import io.ktor.client.request.*
1904
+ import io.ktor.client.statement.*
1905
+ import io.ktor.http.*
1906
+ import io.ktor.utils.io.*
1907
+ import kotlinx.coroutines.CoroutineScope
1908
+ import kotlinx.coroutines.Job
1909
+ import kotlinx.coroutines.launch
1910
+ import kotlinx.coroutines.withContext
1911
+ import kotlinx.serialization.encodeToString
1912
+ import kotlinx.serialization.json.*
1913
+ import java.nio.ByteBuffer
1914
+ import java.time.Instant
1915
+ import java.time.ZoneId
1916
+ import java.time.ZoneOffset
1917
+ import java.time.format.DateTimeFormatter
1918
+
1919
+ private const val generatedClientVersion = "${options.clientVersion}"
1920
+ private val timestampFormatter =
1921
+ DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
1922
+ .withZone(ZoneId.ofOffset("GMT", ZoneOffset.UTC))
1923
+ private val JsonInstance = Json {
1924
+ encodeDefaults = true
1925
+ ignoreUnknownKeys = true
1926
+ }
1927
+ private typealias headersFn = (() -> MutableMap<String, String>?)?`;
1928
+ }
1929
+
1930
+ exports.kotlinClientFromAppDefinition = kotlinClientFromAppDefinition;
1931
+ exports.kotlinClientGenerator = kotlinClientGenerator;
1932
+ exports.kotlinTypeFromSchema = kotlinTypeFromSchema;