@kizunajs/kotlin 2.0.0-beta.1 → 2.0.0-beta.11

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/README.md CHANGED
@@ -10,8 +10,25 @@ pnpm add -D @kizunajs/kotlin
10
10
 
11
11
  ## Usage
12
12
 
13
+ Name the client in your config, and `kizuna generate` writes it with the rest:
14
+
15
+ ```ts
16
+ import { kotlinClient } from '@kizunajs/kotlin';
17
+
18
+ export default defineConfig({
19
+ routes,
20
+ clients: [
21
+ kotlinClient({
22
+ output: '../android/app/src/main/kotlin/com/example/APIClient.kt',
23
+ namespace: 'API',
24
+ package: 'com.example',
25
+ }),
26
+ ],
27
+ });
28
+ ```
29
+
13
30
  ```sh
14
- kizuna-kotlin generate --config kizuna.config.ts --out android/app/src/main/kotlin/com/example/APIClient.kt --namespace-name API --package com.example
31
+ kizuna generate
15
32
  ```
16
33
 
17
34
  ## Documentation
package/dist/cli.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const require_generator = require("./generator-s2pn7vqP.cjs");
2
+ const require_generator = require("./generator-Cs9NkTCg.cjs");
3
3
  let node_fs = require("node:fs");
4
4
  let node_path = require("node:path");
5
5
  let node_util = require("node:util");
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as generateKotlinClient } from "./generator-BvNpSarY.mjs";
2
+ import { t as generateKotlinClient } from "./generator-uzHpr6im.mjs";
3
3
  import { mkdirSync, writeFileSync } from "node:fs";
4
4
  import { dirname, resolve } from "node:path";
5
5
  import { parseArgs } from "node:util";
@@ -117,8 +117,7 @@ const propertyName = (key, camelCase) => {
117
117
  if (!camel) return "field";
118
118
  return /^[0-9]/.test(camel) ? `_${camel}` : camel;
119
119
  };
120
- const objectFields = (schema, registry, hint) => {
121
- const shape = (0, kizunajs_generator.readObjectShape)(schema) ?? {};
120
+ const objectFields = (schema, registry, hint, shape = (0, kizunajs_generator.readObjectShape)(schema) ?? {}) => {
122
121
  const fields = [];
123
122
  const seen = /* @__PURE__ */ new Map();
124
123
  for (const [key, value] of Object.entries(shape)) {
@@ -148,6 +147,10 @@ const mapType = (schema, registry, hint) => {
148
147
  optional: false,
149
148
  isFile: true
150
149
  };
150
+ if ((0, kizunajs_generator.isBinarySchema)(schema)) return {
151
+ expression: "ByteArray",
152
+ optional: false
153
+ };
151
154
  const id = (0, kizunajs_generator.readMetaId)(schema);
152
155
  const def = (0, kizunajs_generator.readDef)(schema);
153
156
  const discriminated = (0, kizunajs_generator.readDiscriminatedUnion)(schema);
@@ -223,8 +226,8 @@ const mapType = (schema, registry, hint) => {
223
226
  optional: false
224
227
  };
225
228
  }
226
- const { inner, optional } = (0, kizunajs_generator.unwrapOptionalWrappers)(schema);
227
- if (optional) {
229
+ const { inner, optional, nullable } = (0, kizunajs_generator.unwrapOptionalWrappers)(schema);
230
+ if (optional || nullable) {
228
231
  const innerResult = mapType(inner, registry, hint);
229
232
  return {
230
233
  expression: innerResult.expression.endsWith("?") ? innerResult.expression : `${innerResult.expression}?`,
@@ -277,8 +280,9 @@ const mapType = (schema, registry, hint) => {
277
280
  optional: false
278
281
  };
279
282
  }
283
+ const elementType = mapType(element, registry, `${hint}Item`).expression.replace(/\?$/, "");
280
284
  return {
281
- expression: `List<${mapType(element, registry, `${hint}Item`).expression.replace(/\?$/, "")}>`,
285
+ expression: `List<${(0, kizunajs_generator.unwrapOptionalWrappers)(element).nullable ? `${elementType}?` : elementType}>`,
282
286
  optional: false
283
287
  };
284
288
  }
@@ -576,7 +580,7 @@ const buildRouteMethod = (routeKey, route, registry, deprecated, deprecationMess
576
580
  stream
577
581
  };
578
582
  };
579
- const kotlinGenerator = (0, kizunajs_generator.createGenerator)((options, _api) => {
583
+ const kotlinRoutesWalk = (options) => {
580
584
  const flatMethods = [];
581
585
  const groupMap = /* @__PURE__ */ new Map();
582
586
  return {
@@ -608,7 +612,7 @@ const kotlinGenerator = (0, kizunajs_generator.createGenerator)((options, _api)
608
612
  };
609
613
  }
610
614
  };
611
- });
615
+ };
612
616
  const KOTLIN_KEYWORDS = new Set([
613
617
  "as",
614
618
  "break",
@@ -653,8 +657,13 @@ const KOTLIN_PRIMITIVE_TYPES = new Set([
653
657
  "Long",
654
658
  "Boolean",
655
659
  "Instant",
656
- "Unit"
660
+ "Unit",
661
+ "ByteArray"
657
662
  ]);
663
+ /**
664
+ * How a response body is read. Raw bytes are the body already.
665
+ */
666
+ const decodeBody = (resolved) => resolved === "ByteArray" ? "data" : `json.decodeFromString<${resolved}>(data.decodeToString())`;
658
667
  const resolveType = (typeName, currentOperation, context, scope = "client") => {
659
668
  const { operationTypeMap, namespaceName, clientName, fileLevelTypeNames } = context;
660
669
  const optional = typeName.endsWith("?");
@@ -1002,7 +1011,7 @@ const emitOperationResultTypes = (writer, method, context) => {
1002
1011
  writer.line(") {");
1003
1012
  writer.indent(() => {
1004
1013
  writer.line("/** How far along the call is. */");
1005
- writer.line("enum class State { Running, Done, Failed }");
1014
+ writer.line("enum class State { Running, NeedsApproval, Done, Failed }");
1006
1015
  });
1007
1016
  writer.line("}");
1008
1017
  writer.blank();
@@ -1012,7 +1021,12 @@ const emitOperationResultTypes = (writer, method, context) => {
1012
1021
  writer.block("for (event in events)", () => {
1013
1022
  writer.line("when (event) {");
1014
1023
  writer.indent(() => {
1015
- writer.line("is Event.ToolCall -> calls[event.data.id] = (calls[event.data.id] ?: ToolCallRecord(event.data.id, event.data.name)).copy(call = event.data)");
1024
+ writer.line("is Event.ToolCall -> {");
1025
+ writer.indent(() => {
1026
+ writer.line("val tracked = (calls[event.data.id] ?: ToolCallRecord(event.data.id, event.data.name)).copy(call = event.data)");
1027
+ writer.line("calls[event.data.id] = if (event.data.needsApproval == true && tracked.state == ToolCallRecord.State.Running) tracked.copy(state = ToolCallRecord.State.NeedsApproval) else tracked");
1028
+ });
1029
+ writer.line("}");
1016
1030
  writer.line("is Event.ToolResult -> calls[event.data.id] = (calls[event.data.id] ?: ToolCallRecord(event.data.id, event.data.name)).copy(state = ToolCallRecord.State.Done, result = event.data)");
1017
1031
  if (eventNames.has("tool_error")) writer.line("is Event.ToolError -> calls[event.data.id] = (calls[event.data.id] ?: ToolCallRecord(event.data.id, event.data.name.wireValue)).copy(state = ToolCallRecord.State.Failed, message = event.data.message)");
1018
1032
  writer.line("else -> Unit");
@@ -1344,7 +1358,7 @@ const emitMethodBody = (writer, method, context) => {
1344
1358
  writer.indent(() => {
1345
1359
  const resolved = resolveType(successResponse.type, method.operationName, context);
1346
1360
  writer.block("try", () => {
1347
- writer.line(`val payload = json.decodeFromString<${resolved}>(data.decodeToString())`);
1361
+ writer.line(`val payload = ${decodeBody(resolved)}`);
1348
1362
  const bodyExpr = isMultiSuccess ? `${operationRef}.Success.Status${successResponse.status}(payload)` : "payload";
1349
1363
  if (hasHeaders) {
1350
1364
  for (const field of successResponse.responseHeaders) writer.line(`val ${escapeKeyword(field.name)} = httpResponse.header(${stringLiteral(field.wireName)})`);
@@ -1381,7 +1395,7 @@ const emitErrorBranches = (writer, method, context) => {
1381
1395
  const resolved = resolveType(errorCase.type, method.operationName, context);
1382
1396
  writer.line("val payload = try {");
1383
1397
  writer.indent(() => {
1384
- writer.line(`json.decodeFromString<${resolved}>(data.decodeToString())`);
1398
+ writer.line(decodeBody(resolved));
1385
1399
  });
1386
1400
  writer.line(`} catch (error: Exception) { throw ${failureRef}.Decoding(error, statusCode, data) }`);
1387
1401
  writer.line(`throw ${failureRef}.${caseName}(body = payload)`);
@@ -1394,7 +1408,7 @@ const emitErrorBranches = (writer, method, context) => {
1394
1408
  const resolved = resolveType(errorCase.type, method.operationName, context);
1395
1409
  writer.line(`val ${errorCase.caseName} = try {`);
1396
1410
  writer.indent(() => {
1397
- writer.line(`json.decodeFromString<${resolved}>(data.decodeToString())`);
1411
+ writer.line(decodeBody(resolved));
1398
1412
  });
1399
1413
  writer.line("} catch (_: Exception) { null }");
1400
1414
  writer.line(`if (${errorCase.caseName} != null) throw ${failureRef}.${caseName}(body = ${errorCase.caseName})`);
@@ -1685,21 +1699,8 @@ const emitClient = (writer, config, partition, context, typesByOperation, regist
1685
1699
  }
1686
1700
  });
1687
1701
  };
1688
- /**
1689
- * Generate a Kotlin API client from a Kizuna api.
1690
- *
1691
- * @param api - What `defineConfig` assembled.
1692
- * @param config - Override the generated names:
1693
- * - `namespaceName`: the object wrapping shared types.
1694
- * - `packageName`: optional package declaration for the generated file.
1695
- */
1696
- const generateKotlinClient = (api, config) => {
1697
- const { namespaceName, packageName, camelCaseProperties = false, unknownEnumCase = false } = config;
1698
- const registry = new TypeRegistry(camelCaseProperties, unknownEnumCase);
1699
- const partition = kotlinGenerator(api, {
1700
- namespaceName,
1701
- registry
1702
- });
1702
+ const renderKotlinClient = (api, partition, registry, config) => {
1703
+ const { namespaceName, packageName, camelCaseProperties = false } = config;
1703
1704
  const allMethods = [...partition.flatMethods, ...partition.groups.flatMap((group) => group.methods)];
1704
1705
  const operationTypeMap = buildOperationTypeMap(allMethods, registry);
1705
1706
  const clientName = `${namespaceName}Client`;
@@ -1791,6 +1792,29 @@ const generateKotlinClient = (api, config) => {
1791
1792
  for (const warning of registry.warnings()) process.stderr.write(`[kizuna/kotlin] JsonElement fallback at ${warning}\n`);
1792
1793
  return writer.toString();
1793
1794
  };
1795
+ /**
1796
+ * The Kotlin client's walk: the routes into a partition, then the file.
1797
+ */
1798
+ const kotlinClientWalk = (api, config) => {
1799
+ const registry = new TypeRegistry(config.camelCaseProperties ?? false, config.unknownEnumCase ?? false);
1800
+ const routes = kotlinRoutesWalk({
1801
+ namespaceName: config.namespaceName,
1802
+ registry
1803
+ });
1804
+ return {
1805
+ processRoute: routes.processRoute,
1806
+ finalize: () => renderKotlinClient(api, routes.finalize(), registry, config)
1807
+ };
1808
+ };
1809
+ /**
1810
+ * Generate a Kotlin API client from a Kizuna api.
1811
+ *
1812
+ * @param api - What `defineConfig` assembled.
1813
+ * @param config - Override the generated names:
1814
+ * - `namespaceName`: the object wrapping shared types.
1815
+ * - `packageName`: optional package declaration for the generated file.
1816
+ */
1817
+ const generateKotlinClient = (api, config) => (0, kizunajs_generator.walkApi)(api, kotlinClientWalk(api, config), { skipHidden: true });
1794
1818
  //#endregion
1795
1819
  Object.defineProperty(exports, "generateKotlinClient", {
1796
1820
  enumerable: true,
@@ -1798,3 +1822,9 @@ Object.defineProperty(exports, "generateKotlinClient", {
1798
1822
  return generateKotlinClient;
1799
1823
  }
1800
1824
  });
1825
+ Object.defineProperty(exports, "kotlinClientWalk", {
1826
+ enumerable: true,
1827
+ get: function() {
1828
+ return kotlinClientWalk;
1829
+ }
1830
+ });
@@ -1,4 +1,4 @@
1
- import { createGenerator, isDiscriminatedUnionSchema, isFileSchema, isHintPrefix, isIntegerSchema, isNamedStream, isObjectSchema, isStreamResponse, isSuccessStatus, localTypeName, mergeHeaderFields, parsePath, readDef, readDefType, readDeprecation, readDiscriminatedUnion, readDiscriminatorStringLiteral, readMetaDescription, readMetaId, readObjectShape, resolveResponseBody, resolveResponseHeaders, routeStreams, sanitizeFieldName, sanitizeIdentifier, shortTypeName, soleStreamResponse, statusToCamelCase, streamMode, toCamelCase, toPascalCase, unwrapOptionalWrappers } from "kizunajs/generator";
1
+ import { isBinarySchema, isDiscriminatedUnionSchema, isFileSchema, isHintPrefix, isIntegerSchema, isNamedStream, isObjectSchema, isStreamResponse, isSuccessStatus, localTypeName, mergeHeaderFields, parsePath, readDef, readDefType, readDeprecation, readDiscriminatedUnion, readDiscriminatorStringLiteral, readMetaDescription, readMetaId, readObjectShape, resolveResponseBody, resolveResponseHeaders, routeStreams, sanitizeFieldName, sanitizeIdentifier, shortTypeName, soleStreamResponse, statusToCamelCase, streamMode, toCamelCase, toPascalCase, unwrapOptionalWrappers, walkApi } from "kizunajs/generator";
2
2
  //#region src/emit.ts
3
3
  var KotlinWriter = class {
4
4
  lines = [];
@@ -117,8 +117,7 @@ const propertyName = (key, camelCase) => {
117
117
  if (!camel) return "field";
118
118
  return /^[0-9]/.test(camel) ? `_${camel}` : camel;
119
119
  };
120
- const objectFields = (schema, registry, hint) => {
121
- const shape = readObjectShape(schema) ?? {};
120
+ const objectFields = (schema, registry, hint, shape = readObjectShape(schema) ?? {}) => {
122
121
  const fields = [];
123
122
  const seen = /* @__PURE__ */ new Map();
124
123
  for (const [key, value] of Object.entries(shape)) {
@@ -148,6 +147,10 @@ const mapType = (schema, registry, hint) => {
148
147
  optional: false,
149
148
  isFile: true
150
149
  };
150
+ if (isBinarySchema(schema)) return {
151
+ expression: "ByteArray",
152
+ optional: false
153
+ };
151
154
  const id = readMetaId(schema);
152
155
  const def = readDef(schema);
153
156
  const discriminated = readDiscriminatedUnion(schema);
@@ -223,8 +226,8 @@ const mapType = (schema, registry, hint) => {
223
226
  optional: false
224
227
  };
225
228
  }
226
- const { inner, optional } = unwrapOptionalWrappers(schema);
227
- if (optional) {
229
+ const { inner, optional, nullable } = unwrapOptionalWrappers(schema);
230
+ if (optional || nullable) {
228
231
  const innerResult = mapType(inner, registry, hint);
229
232
  return {
230
233
  expression: innerResult.expression.endsWith("?") ? innerResult.expression : `${innerResult.expression}?`,
@@ -277,8 +280,9 @@ const mapType = (schema, registry, hint) => {
277
280
  optional: false
278
281
  };
279
282
  }
283
+ const elementType = mapType(element, registry, `${hint}Item`).expression.replace(/\?$/, "");
280
284
  return {
281
- expression: `List<${mapType(element, registry, `${hint}Item`).expression.replace(/\?$/, "")}>`,
285
+ expression: `List<${unwrapOptionalWrappers(element).nullable ? `${elementType}?` : elementType}>`,
282
286
  optional: false
283
287
  };
284
288
  }
@@ -576,7 +580,7 @@ const buildRouteMethod = (routeKey, route, registry, deprecated, deprecationMess
576
580
  stream
577
581
  };
578
582
  };
579
- const kotlinGenerator = createGenerator((options, _api) => {
583
+ const kotlinRoutesWalk = (options) => {
580
584
  const flatMethods = [];
581
585
  const groupMap = /* @__PURE__ */ new Map();
582
586
  return {
@@ -608,7 +612,7 @@ const kotlinGenerator = createGenerator((options, _api) => {
608
612
  };
609
613
  }
610
614
  };
611
- });
615
+ };
612
616
  const KOTLIN_KEYWORDS = new Set([
613
617
  "as",
614
618
  "break",
@@ -653,8 +657,13 @@ const KOTLIN_PRIMITIVE_TYPES = new Set([
653
657
  "Long",
654
658
  "Boolean",
655
659
  "Instant",
656
- "Unit"
660
+ "Unit",
661
+ "ByteArray"
657
662
  ]);
663
+ /**
664
+ * How a response body is read. Raw bytes are the body already.
665
+ */
666
+ const decodeBody = (resolved) => resolved === "ByteArray" ? "data" : `json.decodeFromString<${resolved}>(data.decodeToString())`;
658
667
  const resolveType = (typeName, currentOperation, context, scope = "client") => {
659
668
  const { operationTypeMap, namespaceName, clientName, fileLevelTypeNames } = context;
660
669
  const optional = typeName.endsWith("?");
@@ -1002,7 +1011,7 @@ const emitOperationResultTypes = (writer, method, context) => {
1002
1011
  writer.line(") {");
1003
1012
  writer.indent(() => {
1004
1013
  writer.line("/** How far along the call is. */");
1005
- writer.line("enum class State { Running, Done, Failed }");
1014
+ writer.line("enum class State { Running, NeedsApproval, Done, Failed }");
1006
1015
  });
1007
1016
  writer.line("}");
1008
1017
  writer.blank();
@@ -1012,7 +1021,12 @@ const emitOperationResultTypes = (writer, method, context) => {
1012
1021
  writer.block("for (event in events)", () => {
1013
1022
  writer.line("when (event) {");
1014
1023
  writer.indent(() => {
1015
- writer.line("is Event.ToolCall -> calls[event.data.id] = (calls[event.data.id] ?: ToolCallRecord(event.data.id, event.data.name)).copy(call = event.data)");
1024
+ writer.line("is Event.ToolCall -> {");
1025
+ writer.indent(() => {
1026
+ writer.line("val tracked = (calls[event.data.id] ?: ToolCallRecord(event.data.id, event.data.name)).copy(call = event.data)");
1027
+ writer.line("calls[event.data.id] = if (event.data.needsApproval == true && tracked.state == ToolCallRecord.State.Running) tracked.copy(state = ToolCallRecord.State.NeedsApproval) else tracked");
1028
+ });
1029
+ writer.line("}");
1016
1030
  writer.line("is Event.ToolResult -> calls[event.data.id] = (calls[event.data.id] ?: ToolCallRecord(event.data.id, event.data.name)).copy(state = ToolCallRecord.State.Done, result = event.data)");
1017
1031
  if (eventNames.has("tool_error")) writer.line("is Event.ToolError -> calls[event.data.id] = (calls[event.data.id] ?: ToolCallRecord(event.data.id, event.data.name.wireValue)).copy(state = ToolCallRecord.State.Failed, message = event.data.message)");
1018
1032
  writer.line("else -> Unit");
@@ -1344,7 +1358,7 @@ const emitMethodBody = (writer, method, context) => {
1344
1358
  writer.indent(() => {
1345
1359
  const resolved = resolveType(successResponse.type, method.operationName, context);
1346
1360
  writer.block("try", () => {
1347
- writer.line(`val payload = json.decodeFromString<${resolved}>(data.decodeToString())`);
1361
+ writer.line(`val payload = ${decodeBody(resolved)}`);
1348
1362
  const bodyExpr = isMultiSuccess ? `${operationRef}.Success.Status${successResponse.status}(payload)` : "payload";
1349
1363
  if (hasHeaders) {
1350
1364
  for (const field of successResponse.responseHeaders) writer.line(`val ${escapeKeyword(field.name)} = httpResponse.header(${stringLiteral(field.wireName)})`);
@@ -1381,7 +1395,7 @@ const emitErrorBranches = (writer, method, context) => {
1381
1395
  const resolved = resolveType(errorCase.type, method.operationName, context);
1382
1396
  writer.line("val payload = try {");
1383
1397
  writer.indent(() => {
1384
- writer.line(`json.decodeFromString<${resolved}>(data.decodeToString())`);
1398
+ writer.line(decodeBody(resolved));
1385
1399
  });
1386
1400
  writer.line(`} catch (error: Exception) { throw ${failureRef}.Decoding(error, statusCode, data) }`);
1387
1401
  writer.line(`throw ${failureRef}.${caseName}(body = payload)`);
@@ -1394,7 +1408,7 @@ const emitErrorBranches = (writer, method, context) => {
1394
1408
  const resolved = resolveType(errorCase.type, method.operationName, context);
1395
1409
  writer.line(`val ${errorCase.caseName} = try {`);
1396
1410
  writer.indent(() => {
1397
- writer.line(`json.decodeFromString<${resolved}>(data.decodeToString())`);
1411
+ writer.line(decodeBody(resolved));
1398
1412
  });
1399
1413
  writer.line("} catch (_: Exception) { null }");
1400
1414
  writer.line(`if (${errorCase.caseName} != null) throw ${failureRef}.${caseName}(body = ${errorCase.caseName})`);
@@ -1685,21 +1699,8 @@ const emitClient = (writer, config, partition, context, typesByOperation, regist
1685
1699
  }
1686
1700
  });
1687
1701
  };
1688
- /**
1689
- * Generate a Kotlin API client from a Kizuna api.
1690
- *
1691
- * @param api - What `defineConfig` assembled.
1692
- * @param config - Override the generated names:
1693
- * - `namespaceName`: the object wrapping shared types.
1694
- * - `packageName`: optional package declaration for the generated file.
1695
- */
1696
- const generateKotlinClient = (api, config) => {
1697
- const { namespaceName, packageName, camelCaseProperties = false, unknownEnumCase = false } = config;
1698
- const registry = new TypeRegistry(camelCaseProperties, unknownEnumCase);
1699
- const partition = kotlinGenerator(api, {
1700
- namespaceName,
1701
- registry
1702
- });
1702
+ const renderKotlinClient = (api, partition, registry, config) => {
1703
+ const { namespaceName, packageName, camelCaseProperties = false } = config;
1703
1704
  const allMethods = [...partition.flatMethods, ...partition.groups.flatMap((group) => group.methods)];
1704
1705
  const operationTypeMap = buildOperationTypeMap(allMethods, registry);
1705
1706
  const clientName = `${namespaceName}Client`;
@@ -1791,5 +1792,28 @@ const generateKotlinClient = (api, config) => {
1791
1792
  for (const warning of registry.warnings()) process.stderr.write(`[kizuna/kotlin] JsonElement fallback at ${warning}\n`);
1792
1793
  return writer.toString();
1793
1794
  };
1795
+ /**
1796
+ * The Kotlin client's walk: the routes into a partition, then the file.
1797
+ */
1798
+ const kotlinClientWalk = (api, config) => {
1799
+ const registry = new TypeRegistry(config.camelCaseProperties ?? false, config.unknownEnumCase ?? false);
1800
+ const routes = kotlinRoutesWalk({
1801
+ namespaceName: config.namespaceName,
1802
+ registry
1803
+ });
1804
+ return {
1805
+ processRoute: routes.processRoute,
1806
+ finalize: () => renderKotlinClient(api, routes.finalize(), registry, config)
1807
+ };
1808
+ };
1809
+ /**
1810
+ * Generate a Kotlin API client from a Kizuna api.
1811
+ *
1812
+ * @param api - What `defineConfig` assembled.
1813
+ * @param config - Override the generated names:
1814
+ * - `namespaceName`: the object wrapping shared types.
1815
+ * - `packageName`: optional package declaration for the generated file.
1816
+ */
1817
+ const generateKotlinClient = (api, config) => walkApi(api, kotlinClientWalk(api, config), { skipHidden: true });
1794
1818
  //#endregion
1795
- export { generateKotlinClient as t };
1819
+ export { kotlinClientWalk as n, generateKotlinClient as t };
package/dist/index.cjs CHANGED
@@ -1,17 +1,48 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_generator = require("./generator-s2pn7vqP.cjs");
2
+ const require_generator = require("./generator-Cs9NkTCg.cjs");
3
+ let kizunajs_generator = require("kizunajs/generator");
4
+ let zod = require("zod");
3
5
  //#region src/client-target.ts
6
+ const KotlinClientOptionsSchema = zod.z.object({
7
+ /**
8
+ * Name of the generated namespace object.
9
+ *
10
+ * @default 'API'
11
+ */
12
+ namespace: zod.z.string().default("API"),
13
+ /**
14
+ * Package declaration for the generated file, e.g. `com.example.api`.
15
+ */
16
+ package: zod.z.string().optional(),
17
+ /**
18
+ * Convert wire field names to camelCase properties, mapping the wire name
19
+ * back via `@SerialName`.
20
+ *
21
+ * @default false
22
+ */
23
+ camelCaseProperties: zod.z.boolean().optional(),
24
+ /**
25
+ * Give every enum an `unknown` case, so a value the client has not been
26
+ * generated for decodes instead of throwing.
27
+ *
28
+ * @default false
29
+ */
30
+ unknownEnumCase: zod.z.boolean().optional()
31
+ });
4
32
  /**
5
- * A Kotlin client target for `kizuna.config.ts`.
33
+ * A Kotlin client for `kizuna.config.ts`.
6
34
  *
7
35
  * @example
8
- * kotlinClient({ output: './api/APIClient.kt', package: 'com.example.api' });
36
+ * kotlinClient({
37
+ * output: './api/APIClient.kt',
38
+ * package: 'com.example.api',
39
+ * });
9
40
  */
10
- const kotlinClient = (options) => ({
11
- kind: "kotlin",
12
- output: options.output,
13
- generate: (contract) => require_generator.generateKotlinClient(contract, {
14
- namespaceName: options.namespace ?? "API",
41
+ const kotlinClient = (0, kizunajs_generator.defineClient)({
42
+ target: "kotlin",
43
+ options: KotlinClientOptionsSchema,
44
+ generate: ({ options, api }) => require_generator.kotlinClientWalk(api, {
45
+ namespaceName: options.namespace,
15
46
  packageName: options.package,
16
47
  camelCaseProperties: options.camelCaseProperties,
17
48
  unknownEnumCase: options.unknownEnumCase
package/dist/index.d.cts CHANGED
@@ -1,4 +1,7 @@
1
- import { ApiDefinition, ClientTarget } from "kizunajs";
1
+ import { GeneratedFileOptions } from "kizunajs/generator";
2
+ import * as _$kizunajs from "kizunajs";
3
+ import { ApiDefinition } from "kizunajs";
4
+ import { z } from "zod";
2
5
 
3
6
  //#region src/generator.d.ts
4
7
  interface KotlinConfig {
@@ -38,45 +41,30 @@ interface KotlinConfig {
38
41
  declare const generateKotlinClient: (api: ApiDefinition, config: KotlinConfig) => string;
39
42
  //#endregion
40
43
  //#region src/client-target.d.ts
44
+ declare const KotlinClientOptionsSchema: z.ZodObject<{
45
+ namespace: z.ZodDefault<z.ZodString>;
46
+ package: z.ZodOptional<z.ZodString>;
47
+ camelCaseProperties: z.ZodOptional<z.ZodBoolean>;
48
+ unknownEnumCase: z.ZodOptional<z.ZodBoolean>;
49
+ }, z.core.$strip>;
41
50
  /**
42
51
  * Where a generated Kotlin client is written, and what it is called there.
43
52
  */
44
- interface KotlinClientOptions {
45
- /**
46
- * Path the generated file is written to.
47
- */
48
- output: string;
49
- /**
50
- * Name of the generated namespace object.
51
- *
52
- * @default 'API'
53
- */
54
- namespace?: string;
55
- /**
56
- * Package declaration for the generated file, e.g. `com.example.api`.
57
- */
58
- package?: string;
59
- /**
60
- * Convert wire field names to camelCase properties, mapping the wire name
61
- * back via `@SerialName`.
62
- *
63
- * @default false
64
- */
65
- camelCaseProperties?: boolean;
66
- /**
67
- * Give every enum an `unknown` case, so a value the client has not been
68
- * generated for decodes instead of throwing.
69
- *
70
- * @default false
71
- */
72
- unknownEnumCase?: boolean;
73
- }
53
+ type KotlinClientOptions = z.input<typeof KotlinClientOptionsSchema> & GeneratedFileOptions;
74
54
  /**
75
- * A Kotlin client target for `kizuna.config.ts`.
55
+ * A Kotlin client for `kizuna.config.ts`.
76
56
  *
77
57
  * @example
78
- * kotlinClient({ output: './api/APIClient.kt', package: 'com.example.api' });
58
+ * kotlinClient({
59
+ * output: './api/APIClient.kt',
60
+ * package: 'com.example.api',
61
+ * });
79
62
  */
80
- declare const kotlinClient: (options: KotlinClientOptions) => ClientTarget;
63
+ declare const kotlinClient: (options: {
64
+ namespace?: string | undefined;
65
+ package?: string | undefined;
66
+ camelCaseProperties?: boolean | undefined;
67
+ unknownEnumCase?: boolean | undefined;
68
+ } & GeneratedFileOptions) => _$kizunajs.GeneratedFile;
81
69
  //#endregion
82
70
  export { type KotlinClientOptions, type KotlinConfig, generateKotlinClient, kotlinClient };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,7 @@
1
- import { ApiDefinition, ClientTarget } from "kizunajs";
1
+ import { GeneratedFileOptions } from "kizunajs/generator";
2
+ import { z } from "zod";
3
+ import * as _$kizunajs from "kizunajs";
4
+ import { ApiDefinition } from "kizunajs";
2
5
 
3
6
  //#region src/generator.d.ts
4
7
  interface KotlinConfig {
@@ -38,45 +41,30 @@ interface KotlinConfig {
38
41
  declare const generateKotlinClient: (api: ApiDefinition, config: KotlinConfig) => string;
39
42
  //#endregion
40
43
  //#region src/client-target.d.ts
44
+ declare const KotlinClientOptionsSchema: z.ZodObject<{
45
+ namespace: z.ZodDefault<z.ZodString>;
46
+ package: z.ZodOptional<z.ZodString>;
47
+ camelCaseProperties: z.ZodOptional<z.ZodBoolean>;
48
+ unknownEnumCase: z.ZodOptional<z.ZodBoolean>;
49
+ }, z.core.$strip>;
41
50
  /**
42
51
  * Where a generated Kotlin client is written, and what it is called there.
43
52
  */
44
- interface KotlinClientOptions {
45
- /**
46
- * Path the generated file is written to.
47
- */
48
- output: string;
49
- /**
50
- * Name of the generated namespace object.
51
- *
52
- * @default 'API'
53
- */
54
- namespace?: string;
55
- /**
56
- * Package declaration for the generated file, e.g. `com.example.api`.
57
- */
58
- package?: string;
59
- /**
60
- * Convert wire field names to camelCase properties, mapping the wire name
61
- * back via `@SerialName`.
62
- *
63
- * @default false
64
- */
65
- camelCaseProperties?: boolean;
66
- /**
67
- * Give every enum an `unknown` case, so a value the client has not been
68
- * generated for decodes instead of throwing.
69
- *
70
- * @default false
71
- */
72
- unknownEnumCase?: boolean;
73
- }
53
+ type KotlinClientOptions = z.input<typeof KotlinClientOptionsSchema> & GeneratedFileOptions;
74
54
  /**
75
- * A Kotlin client target for `kizuna.config.ts`.
55
+ * A Kotlin client for `kizuna.config.ts`.
76
56
  *
77
57
  * @example
78
- * kotlinClient({ output: './api/APIClient.kt', package: 'com.example.api' });
58
+ * kotlinClient({
59
+ * output: './api/APIClient.kt',
60
+ * package: 'com.example.api',
61
+ * });
79
62
  */
80
- declare const kotlinClient: (options: KotlinClientOptions) => ClientTarget;
63
+ declare const kotlinClient: (options: {
64
+ namespace?: string | undefined;
65
+ package?: string | undefined;
66
+ camelCaseProperties?: boolean | undefined;
67
+ unknownEnumCase?: boolean | undefined;
68
+ } & GeneratedFileOptions) => _$kizunajs.GeneratedFile;
81
69
  //#endregion
82
70
  export { type KotlinClientOptions, type KotlinConfig, generateKotlinClient, kotlinClient };
package/dist/index.mjs CHANGED
@@ -1,16 +1,45 @@
1
- import { t as generateKotlinClient } from "./generator-BvNpSarY.mjs";
2
- //#region src/client-target.ts
1
+ import { n as kotlinClientWalk, t as generateKotlinClient } from "./generator-uzHpr6im.mjs";
2
+ import { defineClient } from "kizunajs/generator";
3
+ import { z } from "zod";
3
4
  /**
4
- * A Kotlin client target for `kizuna.config.ts`.
5
+ * A Kotlin client for `kizuna.config.ts`.
5
6
  *
6
7
  * @example
7
- * kotlinClient({ output: './api/APIClient.kt', package: 'com.example.api' });
8
+ * kotlinClient({
9
+ * output: './api/APIClient.kt',
10
+ * package: 'com.example.api',
11
+ * });
8
12
  */
9
- const kotlinClient = (options) => ({
10
- kind: "kotlin",
11
- output: options.output,
12
- generate: (contract) => generateKotlinClient(contract, {
13
- namespaceName: options.namespace ?? "API",
13
+ const kotlinClient = defineClient({
14
+ target: "kotlin",
15
+ options: z.object({
16
+ /**
17
+ * Name of the generated namespace object.
18
+ *
19
+ * @default 'API'
20
+ */
21
+ namespace: z.string().default("API"),
22
+ /**
23
+ * Package declaration for the generated file, e.g. `com.example.api`.
24
+ */
25
+ package: z.string().optional(),
26
+ /**
27
+ * Convert wire field names to camelCase properties, mapping the wire name
28
+ * back via `@SerialName`.
29
+ *
30
+ * @default false
31
+ */
32
+ camelCaseProperties: z.boolean().optional(),
33
+ /**
34
+ * Give every enum an `unknown` case, so a value the client has not been
35
+ * generated for decodes instead of throwing.
36
+ *
37
+ * @default false
38
+ */
39
+ unknownEnumCase: z.boolean().optional()
40
+ }),
41
+ generate: ({ options, api }) => kotlinClientWalk(api, {
42
+ namespaceName: options.namespace,
14
43
  packageName: options.package,
15
44
  camelCaseProperties: options.camelCaseProperties,
16
45
  unknownEnumCase: options.unknownEnumCase
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kizunajs/kotlin",
3
- "version": "2.0.0-beta.1",
3
+ "version": "2.0.0-beta.11",
4
4
  "description": "Kotlin client generation for Kizuna.js APIs",
5
5
  "keywords": [
6
6
  "kizunajs",
@@ -60,18 +60,18 @@
60
60
  "access": "public"
61
61
  },
62
62
  "dependencies": {
63
- "@kizunajs/cli": "2.0.0-beta.1"
63
+ "@kizunajs/cli": "2.0.0-beta.11"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "zod": "^4.0.0",
67
- "kizunajs": "2.0.0-beta.1"
67
+ "kizunajs": "2.0.0-beta.11"
68
68
  },
69
69
  "devDependencies": {
70
70
  "@types/node": "^22.9.0",
71
71
  "tsdown": "^0.21.0",
72
72
  "typescript": "^6.0.3",
73
73
  "zod": "^4.0.0",
74
- "kizunajs": "2.0.0-beta.1"
74
+ "kizunajs": "2.0.0-beta.11"
75
75
  },
76
76
  "scripts": {
77
77
  "build": "tsdown src/index.ts src/cli.ts --format esm,cjs --dts --clean --external kizunajs --external @kizunajs/cli --external zod",