@arrirpc/codegen-kotlin 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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;