@ir-kit/openapi-kotlin 0.1.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/LICENSE.md +21 -0
- package/README.md +259 -0
- package/dist/generate.d.ts +41 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +64 -0
- package/dist/generate.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/ir/constants.d.ts +6 -0
- package/dist/ir/constants.d.ts.map +1 -0
- package/dist/ir/constants.js +6 -0
- package/dist/ir/constants.js.map +1 -0
- package/dist/ir/identifiers.d.ts +23 -0
- package/dist/ir/identifiers.d.ts.map +1 -0
- package/dist/ir/identifiers.js +71 -0
- package/dist/ir/identifiers.js.map +1 -0
- package/dist/ir/impl/body.d.ts +30 -0
- package/dist/ir/impl/body.d.ts.map +1 -0
- package/dist/ir/impl/body.js +116 -0
- package/dist/ir/impl/body.js.map +1 -0
- package/dist/ir/impl/decode.d.ts +14 -0
- package/dist/ir/impl/decode.d.ts.map +1 -0
- package/dist/ir/impl/decode.js +110 -0
- package/dist/ir/impl/decode.js.map +1 -0
- package/dist/ir/impl/headers.d.ts +8 -0
- package/dist/ir/impl/headers.d.ts.map +1 -0
- package/dist/ir/impl/headers.js +22 -0
- package/dist/ir/impl/headers.js.map +1 -0
- package/dist/ir/impl/index.d.ts +23 -0
- package/dist/ir/impl/index.d.ts.map +1 -0
- package/dist/ir/impl/index.js +141 -0
- package/dist/ir/impl/index.js.map +1 -0
- package/dist/ir/impl/request.d.ts +14 -0
- package/dist/ir/impl/request.d.ts.map +1 -0
- package/dist/ir/impl/request.js +25 -0
- package/dist/ir/impl/request.js.map +1 -0
- package/dist/ir/impl/serializer.d.ts +20 -0
- package/dist/ir/impl/serializer.d.ts.map +1 -0
- package/dist/ir/impl/serializer.js +62 -0
- package/dist/ir/impl/serializer.js.map +1 -0
- package/dist/ir/impl/url.d.ts +16 -0
- package/dist/ir/impl/url.d.ts.map +1 -0
- package/dist/ir/impl/url.js +77 -0
- package/dist/ir/impl/url.js.map +1 -0
- package/dist/ir/index.d.ts +4 -0
- package/dist/ir/index.d.ts.map +1 -0
- package/dist/ir/index.js +3 -0
- package/dist/ir/index.js.map +1 -0
- package/dist/ir/operation/body.d.ts +18 -0
- package/dist/ir/operation/body.d.ts.map +1 -0
- package/dist/ir/operation/body.js +51 -0
- package/dist/ir/operation/body.js.map +1 -0
- package/dist/ir/operation/index.d.ts +7 -0
- package/dist/ir/operation/index.d.ts.map +1 -0
- package/dist/ir/operation/index.js +5 -0
- package/dist/ir/operation/index.js.map +1 -0
- package/dist/ir/operation/params.d.ts +16 -0
- package/dist/ir/operation/params.d.ts.map +1 -0
- package/dist/ir/operation/params.js +28 -0
- package/dist/ir/operation/params.js.map +1 -0
- package/dist/ir/operation/response.d.ts +26 -0
- package/dist/ir/operation/response.d.ts.map +1 -0
- package/dist/ir/operation/response.js +58 -0
- package/dist/ir/operation/response.js.map +1 -0
- package/dist/ir/operation/signature.d.ts +32 -0
- package/dist/ir/operation/signature.d.ts.map +1 -0
- package/dist/ir/operation/signature.js +53 -0
- package/dist/ir/operation/signature.js.map +1 -0
- package/dist/ir/operations.d.ts +43 -0
- package/dist/ir/operations.d.ts.map +1 -0
- package/dist/ir/operations.js +124 -0
- package/dist/ir/operations.js.map +1 -0
- package/dist/ir/runtime/index.d.ts +3 -0
- package/dist/ir/runtime/index.d.ts.map +1 -0
- package/dist/ir/runtime/index.js +2 -0
- package/dist/ir/runtime/index.js.map +1 -0
- package/dist/ir/runtime/templates.d.ts +31 -0
- package/dist/ir/runtime/templates.d.ts.map +1 -0
- package/dist/ir/runtime/templates.js +431 -0
- package/dist/ir/runtime/templates.js.map +1 -0
- package/dist/ir/schema.d.ts +11 -0
- package/dist/ir/schema.d.ts.map +1 -0
- package/dist/ir/schema.js +51 -0
- package/dist/ir/schema.js.map +1 -0
- package/dist/ir/type/context.d.ts +4 -0
- package/dist/ir/type/context.d.ts.map +1 -0
- package/dist/ir/type/context.js +2 -0
- package/dist/ir/type/context.js.map +1 -0
- package/dist/ir/type/index.d.ts +27 -0
- package/dist/ir/type/index.d.ts.map +1 -0
- package/dist/ir/type/index.js +35 -0
- package/dist/ir/type/index.js.map +1 -0
- package/dist/ir/type/primitive.d.ts +9 -0
- package/dist/ir/type/primitive.d.ts.map +1 -0
- package/dist/ir/type/primitive.js +50 -0
- package/dist/ir/type/primitive.js.map +1 -0
- package/dist/ir/type/property-naming.d.ts +26 -0
- package/dist/ir/type/property-naming.d.ts.map +1 -0
- package/dist/ir/type/property-naming.js +27 -0
- package/dist/ir/type/property-naming.js.map +1 -0
- package/dist/ir/type-ops.d.ts +13 -0
- package/dist/ir/type-ops.d.ts.map +1 -0
- package/dist/ir/type-ops.js +80 -0
- package/dist/ir/type-ops.js.map +1 -0
- package/dist/kt-compiler/decl/class.d.ts +6 -0
- package/dist/kt-compiler/decl/class.d.ts.map +1 -0
- package/dist/kt-compiler/decl/class.js +38 -0
- package/dist/kt-compiler/decl/class.js.map +1 -0
- package/dist/kt-compiler/decl/dataClass.d.ts +3 -0
- package/dist/kt-compiler/decl/dataClass.d.ts.map +1 -0
- package/dist/kt-compiler/decl/dataClass.js +18 -0
- package/dist/kt-compiler/decl/dataClass.js.map +1 -0
- package/dist/kt-compiler/decl/enum.d.ts +3 -0
- package/dist/kt-compiler/decl/enum.d.ts.map +1 -0
- package/dist/kt-compiler/decl/enum.js +32 -0
- package/dist/kt-compiler/decl/enum.js.map +1 -0
- package/dist/kt-compiler/decl/fun.d.ts +11 -0
- package/dist/kt-compiler/decl/fun.d.ts.map +1 -0
- package/dist/kt-compiler/decl/fun.js +69 -0
- package/dist/kt-compiler/decl/fun.js.map +1 -0
- package/dist/kt-compiler/decl/index.d.ts +13 -0
- package/dist/kt-compiler/decl/index.d.ts.map +1 -0
- package/dist/kt-compiler/decl/index.js +39 -0
- package/dist/kt-compiler/decl/index.js.map +1 -0
- package/dist/kt-compiler/decl/interface.d.ts +3 -0
- package/dist/kt-compiler/decl/interface.d.ts.map +1 -0
- package/dist/kt-compiler/decl/interface.js +15 -0
- package/dist/kt-compiler/decl/interface.js.map +1 -0
- package/dist/kt-compiler/decl/object.d.ts +3 -0
- package/dist/kt-compiler/decl/object.d.ts.map +1 -0
- package/dist/kt-compiler/decl/object.js +19 -0
- package/dist/kt-compiler/decl/object.js.map +1 -0
- package/dist/kt-compiler/decl/prop.d.ts +20 -0
- package/dist/kt-compiler/decl/prop.d.ts.map +1 -0
- package/dist/kt-compiler/decl/prop.js +42 -0
- package/dist/kt-compiler/decl/prop.js.map +1 -0
- package/dist/kt-compiler/decl/sealedClass.d.ts +3 -0
- package/dist/kt-compiler/decl/sealedClass.d.ts.map +1 -0
- package/dist/kt-compiler/decl/sealedClass.js +32 -0
- package/dist/kt-compiler/decl/sealedClass.js.map +1 -0
- package/dist/kt-compiler/decl/topLevel.d.ts +3 -0
- package/dist/kt-compiler/decl/topLevel.d.ts.map +1 -0
- package/dist/kt-compiler/decl/topLevel.js +5 -0
- package/dist/kt-compiler/decl/topLevel.js.map +1 -0
- package/dist/kt-compiler/decl/typeAlias.d.ts +3 -0
- package/dist/kt-compiler/decl/typeAlias.d.ts.map +1 -0
- package/dist/kt-compiler/decl/typeAlias.js +6 -0
- package/dist/kt-compiler/decl/typeAlias.js.map +1 -0
- package/dist/kt-compiler/expr.d.ts +4 -0
- package/dist/kt-compiler/expr.d.ts.map +1 -0
- package/dist/kt-compiler/expr.js +123 -0
- package/dist/kt-compiler/expr.js.map +1 -0
- package/dist/kt-compiler/format.d.ts +20 -0
- package/dist/kt-compiler/format.d.ts.map +1 -0
- package/dist/kt-compiler/format.js +27 -0
- package/dist/kt-compiler/format.js.map +1 -0
- package/dist/kt-compiler/index.d.ts +7 -0
- package/dist/kt-compiler/index.d.ts.map +1 -0
- package/dist/kt-compiler/index.js +24 -0
- package/dist/kt-compiler/index.js.map +1 -0
- package/dist/kt-compiler/stmt.d.ts +4 -0
- package/dist/kt-compiler/stmt.d.ts.map +1 -0
- package/dist/kt-compiler/stmt.js +72 -0
- package/dist/kt-compiler/stmt.js.map +1 -0
- package/dist/kt-compiler/type.d.ts +3 -0
- package/dist/kt-compiler/type.d.ts.map +1 -0
- package/dist/kt-compiler/type.js +28 -0
- package/dist/kt-compiler/type.js.map +1 -0
- package/dist/kt-dsl/decl/class.d.ts +50 -0
- package/dist/kt-dsl/decl/class.d.ts.map +1 -0
- package/dist/kt-dsl/decl/class.js +33 -0
- package/dist/kt-dsl/decl/class.js.map +1 -0
- package/dist/kt-dsl/decl/dataClass.d.ts +36 -0
- package/dist/kt-dsl/decl/dataClass.d.ts.map +1 -0
- package/dist/kt-dsl/decl/dataClass.js +25 -0
- package/dist/kt-dsl/decl/dataClass.js.map +1 -0
- package/dist/kt-dsl/decl/enum.d.ts +60 -0
- package/dist/kt-dsl/decl/enum.d.ts.map +1 -0
- package/dist/kt-dsl/decl/enum.js +38 -0
- package/dist/kt-dsl/decl/enum.js.map +1 -0
- package/dist/kt-dsl/decl/index.d.ts +11 -0
- package/dist/kt-dsl/decl/index.d.ts.map +1 -0
- package/dist/kt-dsl/decl/index.js +11 -0
- package/dist/kt-dsl/decl/index.js.map +1 -0
- package/dist/kt-dsl/decl/interface.d.ts +33 -0
- package/dist/kt-dsl/decl/interface.d.ts.map +1 -0
- package/dist/kt-dsl/decl/interface.js +24 -0
- package/dist/kt-dsl/decl/interface.js.map +1 -0
- package/dist/kt-dsl/decl/object.d.ts +34 -0
- package/dist/kt-dsl/decl/object.d.ts.map +1 -0
- package/dist/kt-dsl/decl/object.js +24 -0
- package/dist/kt-dsl/decl/object.js.map +1 -0
- package/dist/kt-dsl/decl/prop.d.ts +47 -0
- package/dist/kt-dsl/decl/prop.d.ts.map +1 -0
- package/dist/kt-dsl/decl/prop.js +28 -0
- package/dist/kt-dsl/decl/prop.js.map +1 -0
- package/dist/kt-dsl/decl/sealedClass.d.ts +68 -0
- package/dist/kt-dsl/decl/sealedClass.d.ts.map +1 -0
- package/dist/kt-dsl/decl/sealedClass.js +52 -0
- package/dist/kt-dsl/decl/sealedClass.js.map +1 -0
- package/dist/kt-dsl/decl/topLevel.d.ts +19 -0
- package/dist/kt-dsl/decl/topLevel.d.ts.map +1 -0
- package/dist/kt-dsl/decl/topLevel.js +17 -0
- package/dist/kt-dsl/decl/topLevel.js.map +1 -0
- package/dist/kt-dsl/decl/typeAlias.d.ts +23 -0
- package/dist/kt-dsl/decl/typeAlias.d.ts.map +1 -0
- package/dist/kt-dsl/decl/typeAlias.js +18 -0
- package/dist/kt-dsl/decl/typeAlias.js.map +1 -0
- package/dist/kt-dsl/decl/types.d.ts +10 -0
- package/dist/kt-dsl/decl/types.d.ts.map +1 -0
- package/dist/kt-dsl/decl/types.js +2 -0
- package/dist/kt-dsl/decl/types.js.map +1 -0
- package/dist/kt-dsl/expr/access.d.ts +48 -0
- package/dist/kt-dsl/expr/access.d.ts.map +1 -0
- package/dist/kt-dsl/expr/access.js +59 -0
- package/dist/kt-dsl/expr/access.js.map +1 -0
- package/dist/kt-dsl/expr/call.d.ts +38 -0
- package/dist/kt-dsl/expr/call.d.ts.map +1 -0
- package/dist/kt-dsl/expr/call.js +38 -0
- package/dist/kt-dsl/expr/call.js.map +1 -0
- package/dist/kt-dsl/expr/index.d.ts +7 -0
- package/dist/kt-dsl/expr/index.d.ts.map +1 -0
- package/dist/kt-dsl/expr/index.js +7 -0
- package/dist/kt-dsl/expr/index.js.map +1 -0
- package/dist/kt-dsl/expr/literal.d.ts +100 -0
- package/dist/kt-dsl/expr/literal.d.ts.map +1 -0
- package/dist/kt-dsl/expr/literal.js +108 -0
- package/dist/kt-dsl/expr/literal.js.map +1 -0
- package/dist/kt-dsl/expr/misc.d.ts +45 -0
- package/dist/kt-dsl/expr/misc.d.ts.map +1 -0
- package/dist/kt-dsl/expr/misc.js +63 -0
- package/dist/kt-dsl/expr/misc.js.map +1 -0
- package/dist/kt-dsl/expr/op.d.ts +25 -0
- package/dist/kt-dsl/expr/op.d.ts.map +1 -0
- package/dist/kt-dsl/expr/op.js +24 -0
- package/dist/kt-dsl/expr/op.js.map +1 -0
- package/dist/kt-dsl/expr/types.d.ts +93 -0
- package/dist/kt-dsl/expr/types.d.ts.map +1 -0
- package/dist/kt-dsl/expr/types.js +2 -0
- package/dist/kt-dsl/expr/types.js.map +1 -0
- package/dist/kt-dsl/file.d.ts +14 -0
- package/dist/kt-dsl/file.d.ts.map +1 -0
- package/dist/kt-dsl/file.js +9 -0
- package/dist/kt-dsl/file.js.map +1 -0
- package/dist/kt-dsl/fun.d.ts +73 -0
- package/dist/kt-dsl/fun.d.ts.map +1 -0
- package/dist/kt-dsl/fun.js +50 -0
- package/dist/kt-dsl/fun.js.map +1 -0
- package/dist/kt-dsl/index.d.ts +8 -0
- package/dist/kt-dsl/index.d.ts.map +1 -0
- package/dist/kt-dsl/index.js +8 -0
- package/dist/kt-dsl/index.js.map +1 -0
- package/dist/kt-dsl/stmt/binding.d.ts +56 -0
- package/dist/kt-dsl/stmt/binding.d.ts.map +1 -0
- package/dist/kt-dsl/stmt/binding.js +70 -0
- package/dist/kt-dsl/stmt/binding.js.map +1 -0
- package/dist/kt-dsl/stmt/control.d.ts +80 -0
- package/dist/kt-dsl/stmt/control.d.ts.map +1 -0
- package/dist/kt-dsl/stmt/control.js +77 -0
- package/dist/kt-dsl/stmt/control.js.map +1 -0
- package/dist/kt-dsl/stmt/index.d.ts +4 -0
- package/dist/kt-dsl/stmt/index.d.ts.map +1 -0
- package/dist/kt-dsl/stmt/index.js +4 -0
- package/dist/kt-dsl/stmt/index.js.map +1 -0
- package/dist/kt-dsl/stmt/types.d.ts +62 -0
- package/dist/kt-dsl/stmt/types.d.ts.map +1 -0
- package/dist/kt-dsl/stmt/types.js +2 -0
- package/dist/kt-dsl/stmt/types.js.map +1 -0
- package/dist/kt-dsl/type/builders.d.ts +75 -0
- package/dist/kt-dsl/type/builders.d.ts.map +1 -0
- package/dist/kt-dsl/type/builders.js +83 -0
- package/dist/kt-dsl/type/builders.js.map +1 -0
- package/dist/kt-dsl/type/index.d.ts +3 -0
- package/dist/kt-dsl/type/index.d.ts.map +1 -0
- package/dist/kt-dsl/type/index.js +3 -0
- package/dist/kt-dsl/type/index.js.map +1 -0
- package/dist/kt-dsl/type/types.d.ts +25 -0
- package/dist/kt-dsl/type/types.d.ts.map +1 -0
- package/dist/kt-dsl/type/types.js +2 -0
- package/dist/kt-dsl/type/types.js.map +1 -0
- package/dist/kt-dsl/visibility.d.ts +2 -0
- package/dist/kt-dsl/visibility.d.ts.map +1 -0
- package/dist/kt-dsl/visibility.js +2 -0
- package/dist/kt-dsl/visibility.js.map +1 -0
- package/dist/project/build.d.ts +33 -0
- package/dist/project/build.d.ts.map +1 -0
- package/dist/project/build.js +73 -0
- package/dist/project/build.js.map +1 -0
- package/dist/project/gradle.d.ts +48 -0
- package/dist/project/gradle.d.ts.map +1 -0
- package/dist/project/gradle.js +46 -0
- package/dist/project/gradle.js.map +1 -0
- package/dist/project/imports.d.ts +21 -0
- package/dist/project/imports.d.ts.map +1 -0
- package/dist/project/imports.js +162 -0
- package/dist/project/imports.js.map +1 -0
- package/dist/project/index.d.ts +6 -0
- package/dist/project/index.d.ts.map +1 -0
- package/dist/project/index.js +3 -0
- package/dist/project/index.js.map +1 -0
- package/dist/project/layout.d.ts +30 -0
- package/dist/project/layout.d.ts.map +1 -0
- package/dist/project/layout.js +57 -0
- package/dist/project/layout.js.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { pascal } from "@ir-kit/codegen-core";
|
|
2
|
+
import { iterOperations } from "@ir-kit/openapi";
|
|
3
|
+
import { ktArg, ktCall, ktExprStmt, ktFun, ktIdent, ktInterface, ktMember, ktRef, ktReturn, ktTopLevelFun, } from "../kt-dsl/index.js";
|
|
4
|
+
import { buildClientClass } from "./impl/index.js";
|
|
5
|
+
import { operationSignature, } from "./operation/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* Translate `IR.Model.paths` into Kotlin interfaces (one per tag) and
|
|
8
|
+
* matching OkHttp + kotlinx-serialization impl classes. Inline body /
|
|
9
|
+
* response / param schemas are promoted to synthetic top-level decls
|
|
10
|
+
* in the same output array.
|
|
11
|
+
*/
|
|
12
|
+
export function operationsToDecls(paths, opts = {}) {
|
|
13
|
+
const defaultTag = opts.defaultTag ?? "Default";
|
|
14
|
+
const interfaceName = opts.interfaceName ?? ((tag) => `${pascal(tag)}Api`);
|
|
15
|
+
const clientClassName = opts.clientClassName ?? ((p) => `OkHttp${p}`);
|
|
16
|
+
const decls = [];
|
|
17
|
+
const emit = (d) => decls.push(d);
|
|
18
|
+
const byTag = new Map();
|
|
19
|
+
for (const { pathStr, method, op, schemeNames } of iterOperations(paths, opts.securitySchemeNames)) {
|
|
20
|
+
const sig = operationSignature(op, method, pathStr, emit, schemeNames);
|
|
21
|
+
const tag = op.tags?.[0] ?? defaultTag;
|
|
22
|
+
const list = byTag.get(tag);
|
|
23
|
+
if (list)
|
|
24
|
+
list.push(sig);
|
|
25
|
+
else
|
|
26
|
+
byTag.set(tag, [sig]);
|
|
27
|
+
}
|
|
28
|
+
let needsMultipart = false;
|
|
29
|
+
let needsAuth = false;
|
|
30
|
+
for (const [tag, sigs] of byTag) {
|
|
31
|
+
const ifaceName = interfaceName(tag);
|
|
32
|
+
const allSigs = sigs.flatMap((s) => [
|
|
33
|
+
s,
|
|
34
|
+
withResponseSignature(s),
|
|
35
|
+
]);
|
|
36
|
+
decls.push(ktInterface({
|
|
37
|
+
name: ifaceName,
|
|
38
|
+
funs: allSigs.map(signatureToInterfaceFun),
|
|
39
|
+
}));
|
|
40
|
+
for (const sig of allSigs) {
|
|
41
|
+
decls.push(ktTopLevelFun(signatureToConvenienceFun(sig, ifaceName)));
|
|
42
|
+
}
|
|
43
|
+
if (sigs.some(hasSecurity))
|
|
44
|
+
needsAuth = true;
|
|
45
|
+
if (!opts.interfaceOnly) {
|
|
46
|
+
const result = buildClientClass(clientClassName(ifaceName), ifaceName, allSigs, {
|
|
47
|
+
open: opts.openImpl,
|
|
48
|
+
});
|
|
49
|
+
decls.push(result.class);
|
|
50
|
+
if (result.needsMultipart)
|
|
51
|
+
needsMultipart = true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { decls, needsMultipart, needsAuth };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Derive the `*WithResponse` companion of a signature: name suffix
|
|
58
|
+
* `WithResponse`, and return type wraps the original alongside
|
|
59
|
+
* OkHttp's `Response`. Void operations bundle to just `Response`
|
|
60
|
+
* (no payload to pair with).
|
|
61
|
+
*/
|
|
62
|
+
function withResponseSignature(sig) {
|
|
63
|
+
return {
|
|
64
|
+
...sig,
|
|
65
|
+
name: `${sig.name}WithResponse`,
|
|
66
|
+
returnType: withResponseReturnType(sig.returnType),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function withResponseReturnType(t) {
|
|
70
|
+
const isUnit = t.kind === "primitive" && t.name === "Unit";
|
|
71
|
+
return isUnit ? ktRef("Response") : ktRef("Pair", [t, ktRef("Response")]);
|
|
72
|
+
}
|
|
73
|
+
function hasSecurity(sig) {
|
|
74
|
+
return sig.securitySchemeNames.length > 0;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Strip defaults from interface-fun parameters. Kotlin allows defaults
|
|
78
|
+
* on interface methods, but the convention is to keep interface
|
|
79
|
+
* signatures lean and put defaults on the implementation; the
|
|
80
|
+
* convenience extension below provides the no-options overload.
|
|
81
|
+
*/
|
|
82
|
+
function signatureToInterfaceFun(sig) {
|
|
83
|
+
const ifaceParams = sig.params.map((p) => p.default === undefined ? p : { ...p, default: undefined });
|
|
84
|
+
return ktFun({
|
|
85
|
+
name: sig.name,
|
|
86
|
+
params: ifaceParams,
|
|
87
|
+
returnType: sig.returnType,
|
|
88
|
+
modifiers: ["suspend"],
|
|
89
|
+
doc: sig.doc,
|
|
90
|
+
// No body — interface requirement.
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Convenience overload emitted as a top-level extension fun. Drops the
|
|
95
|
+
* trailing `options` param and forwards with `RequestOptions()` defaults.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```kotlin
|
|
99
|
+
* public suspend fun PetApi.getPetById(petId: Long): Pet {
|
|
100
|
+
* return getPetById(petId = petId, options = RequestOptions())
|
|
101
|
+
* }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
function signatureToConvenienceFun(sig, receiverName) {
|
|
105
|
+
// Drop the trailing options param — that's the whole point of the overload.
|
|
106
|
+
const baseParams = sig.params.slice(0, -1).map((p) =>
|
|
107
|
+
// The convenience overload also drops defaults — when callers reach
|
|
108
|
+
// for it, they already opted into the no-options shape.
|
|
109
|
+
p.default === undefined ? p : { ...p, default: undefined });
|
|
110
|
+
const callArgs = baseParams.map((p) => ktArg(ktIdent(p.name), p.name));
|
|
111
|
+
callArgs.push(ktArg(ktCall(ktIdent("RequestOptions"), []), "options"));
|
|
112
|
+
const forwarded = ktCall(ktMember(ktIdent("this"), sig.name), callArgs);
|
|
113
|
+
const isUnit = sig.returnType.kind === "primitive" && sig.returnType.name === "Unit";
|
|
114
|
+
return ktFun({
|
|
115
|
+
name: sig.name,
|
|
116
|
+
params: baseParams,
|
|
117
|
+
returnType: sig.returnType,
|
|
118
|
+
modifiers: ["suspend"],
|
|
119
|
+
doc: sig.doc,
|
|
120
|
+
receiver: ktRef(receiverName),
|
|
121
|
+
body: [isUnit ? ktExprStmt(forwarded) : ktReturn(forwarded)],
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=operations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operations.js","sourceRoot":"","sources":["../../src/ir/operations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ir/runtime/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ir/runtime/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime helper sources. These files ship verbatim into every generated
|
|
3
|
+
* SDK — no spec-driven content beyond the package name. Encoding them as
|
|
4
|
+
* fixed Kotlin strings (rather than DSL-built) keeps the codegen surface
|
|
5
|
+
* small: the DSL only has to model what the per-operation impl actually
|
|
6
|
+
* uses.
|
|
7
|
+
*
|
|
8
|
+
* Convention: `__PACKAGE__` is replaced by the consumer-chosen package
|
|
9
|
+
* name during `buildRuntimeFiles(...)`.
|
|
10
|
+
*/
|
|
11
|
+
export interface RuntimeOpts {
|
|
12
|
+
/** Emit `var auth: MutableMap<String, Auth>` on `APIClient` and the
|
|
13
|
+
* `Auth` / `APIKeyLocation` files. Set when the spec declares any
|
|
14
|
+
* `securitySchemes`. */
|
|
15
|
+
hasAuth: boolean;
|
|
16
|
+
/** Emit the `multipart/form-data` helper. Set when at least one op has
|
|
17
|
+
* a `multipart/form-data` body. */
|
|
18
|
+
hasMultipart: boolean;
|
|
19
|
+
/** Emit the `application/x-www-form-urlencoded` helper file (`FormUrlEncoder`
|
|
20
|
+
* object). Currently this is folded into ad-hoc `FormBody.Builder` calls
|
|
21
|
+
* in the impl, so we don't ship a dedicated runtime file for it. */
|
|
22
|
+
hasFormUrlEncoded: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface RuntimeFile {
|
|
25
|
+
name: string;
|
|
26
|
+
content: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function apiClientKt(opts: RuntimeOpts): string;
|
|
29
|
+
/** Ordered runtime files. The orchestrator places them under `API/`. */
|
|
30
|
+
export declare function buildRuntimeFiles(opts: RuntimeOpts, pkg: string): RuntimeFile[];
|
|
31
|
+
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/ir/runtime/templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,WAAW;IAC1B;;6BAEyB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB;wCACoC;IACpC,YAAY,EAAE,OAAO,CAAC;IACtB;;yEAEqE;IACrE,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AA+YD,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAKrD;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,MAAM,GACV,WAAW,EAAE,CAwBf"}
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime helper sources. These files ship verbatim into every generated
|
|
3
|
+
* SDK — no spec-driven content beyond the package name. Encoding them as
|
|
4
|
+
* fixed Kotlin strings (rather than DSL-built) keeps the codegen surface
|
|
5
|
+
* small: the DSL only has to model what the per-operation impl actually
|
|
6
|
+
* uses.
|
|
7
|
+
*
|
|
8
|
+
* Convention: `__PACKAGE__` is replaced by the consumer-chosen package
|
|
9
|
+
* name during `buildRuntimeFiles(...)`.
|
|
10
|
+
*/
|
|
11
|
+
const API_INTERCEPTORS_KT = `package __PACKAGE__
|
|
12
|
+
|
|
13
|
+
import okhttp3.Request
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Bag of per-request mutation hooks. Mirrors hey-api's TS client where
|
|
17
|
+
* \`client.interceptors.request.use(fn)\` registers an interceptor that
|
|
18
|
+
* runs against every outgoing request. Multiple interceptors compose —
|
|
19
|
+
* auth, logging, and tracing all coexist as separate entries instead
|
|
20
|
+
* of being chained inside one closure.
|
|
21
|
+
*/
|
|
22
|
+
public class APIInterceptors {
|
|
23
|
+
public val request: MutableList<suspend (Request) -> Request> = mutableListOf()
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
const API_ERROR_KT = `package __PACKAGE__
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The typed error every impl method throws on non-2xx responses.
|
|
30
|
+
*
|
|
31
|
+
* - \`ClientError(statusCode, body)\` — 4XX
|
|
32
|
+
* - \`ServerError(statusCode, body)\` — 5XX
|
|
33
|
+
* - \`UnexpectedStatus(statusCode, body)\` — 1XX/3XX/anything outside 2-5
|
|
34
|
+
* - \`DecodingFailed(cause)\` — kotlinx-serialization threw on a 2XX body
|
|
35
|
+
* - \`Transport(cause)\` — OkHttp / network-layer failure
|
|
36
|
+
*
|
|
37
|
+
* Consumers \`catch\` and pattern-match. Bodies are surfaced as raw
|
|
38
|
+
* \`ByteArray\` so callers can decode error envelopes themselves with the
|
|
39
|
+
* codec they prefer.
|
|
40
|
+
*/
|
|
41
|
+
public sealed class APIError(message: String? = null, cause: Throwable? = null) :
|
|
42
|
+
RuntimeException(message, cause) {
|
|
43
|
+
|
|
44
|
+
public class ClientError(
|
|
45
|
+
public val statusCode: Int,
|
|
46
|
+
public val body: ByteArray,
|
|
47
|
+
) : APIError("Client error: \$statusCode")
|
|
48
|
+
|
|
49
|
+
public class ServerError(
|
|
50
|
+
public val statusCode: Int,
|
|
51
|
+
public val body: ByteArray,
|
|
52
|
+
) : APIError("Server error: \$statusCode")
|
|
53
|
+
|
|
54
|
+
public class UnexpectedStatus(
|
|
55
|
+
public val statusCode: Int,
|
|
56
|
+
public val body: ByteArray,
|
|
57
|
+
) : APIError("Unexpected status: \$statusCode")
|
|
58
|
+
|
|
59
|
+
public class DecodingFailed(cause: Throwable) :
|
|
60
|
+
APIError("Decoding failed: \${cause.message}", cause)
|
|
61
|
+
|
|
62
|
+
public class Transport(cause: Throwable) :
|
|
63
|
+
APIError("Transport failure: \${cause.message}", cause)
|
|
64
|
+
}
|
|
65
|
+
`;
|
|
66
|
+
const QUERY_STYLE_KT = `package __PACKAGE__
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Query-array serialization style — matches the OpenAPI 3 \`style\` field
|
|
70
|
+
* for query parameters whose value is an array. The default is \`form\`
|
|
71
|
+
* with explode=true; the others appear when the spec opts into them.
|
|
72
|
+
*/
|
|
73
|
+
public enum class QueryStyle {
|
|
74
|
+
FORM,
|
|
75
|
+
SPACE_DELIMITED,
|
|
76
|
+
PIPE_DELIMITED,
|
|
77
|
+
}
|
|
78
|
+
`;
|
|
79
|
+
const URL_ENCODING_KT = `package __PACKAGE__
|
|
80
|
+
|
|
81
|
+
import okhttp3.HttpUrl
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Helpers used by generated impl code to add OpenAPI-shaped query
|
|
85
|
+
* parameters onto an \`HttpUrl.Builder\` without each call site having to
|
|
86
|
+
* know the style/explode rules.
|
|
87
|
+
*
|
|
88
|
+
* - \`addScalar\` skips when the value is \`null\` so optional-and-missing
|
|
89
|
+
* params don't emit a key at all.
|
|
90
|
+
* - \`addArray\` honours \`style\` + \`explode\`: explode=true emits one
|
|
91
|
+
* \`?name=v\` per element; explode=false joins per the style separator.
|
|
92
|
+
*/
|
|
93
|
+
public object URLEncoding {
|
|
94
|
+
public fun addScalar(builder: HttpUrl.Builder, name: String, value: Any?) {
|
|
95
|
+
if (value == null) return
|
|
96
|
+
builder.addQueryParameter(name, value.toString())
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public fun addArray(
|
|
100
|
+
builder: HttpUrl.Builder,
|
|
101
|
+
name: String,
|
|
102
|
+
values: List<Any>?,
|
|
103
|
+
style: QueryStyle = QueryStyle.FORM,
|
|
104
|
+
explode: Boolean = true,
|
|
105
|
+
) {
|
|
106
|
+
if (values == null) return
|
|
107
|
+
if (explode) {
|
|
108
|
+
for (v in values) builder.addQueryParameter(name, v.toString())
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
val sep = when (style) {
|
|
112
|
+
QueryStyle.FORM -> ","
|
|
113
|
+
QueryStyle.SPACE_DELIMITED -> " "
|
|
114
|
+
QueryStyle.PIPE_DELIMITED -> "|"
|
|
115
|
+
}
|
|
116
|
+
builder.addQueryParameter(name, values.joinToString(sep) { it.toString() })
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
`;
|
|
120
|
+
const MULTIPART_KT = `package __PACKAGE__
|
|
121
|
+
|
|
122
|
+
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
|
123
|
+
import okhttp3.MultipartBody
|
|
124
|
+
import okhttp3.RequestBody
|
|
125
|
+
import okhttp3.RequestBody.Companion.toRequestBody
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Thin wrapper over OkHttp's \`MultipartBody.Builder\` — keeps the impl
|
|
129
|
+
* code symmetric with the JSON / form-urlencoded paths.
|
|
130
|
+
*
|
|
131
|
+
* - \`appendText(name, value)\` — text part.
|
|
132
|
+
* - \`appendFile(name, filename, bytes,\`
|
|
133
|
+
* \`mimeType)\` — binary part.
|
|
134
|
+
* - \`build()\` — finalizes and returns a
|
|
135
|
+
* \`RequestBody\` ready to pass
|
|
136
|
+
* into \`.method("POST", body)\`.
|
|
137
|
+
*/
|
|
138
|
+
public class MultipartFormBody {
|
|
139
|
+
private val builder: MultipartBody.Builder =
|
|
140
|
+
MultipartBody.Builder().setType(MultipartBody.FORM)
|
|
141
|
+
|
|
142
|
+
public fun appendText(name: String, value: String) {
|
|
143
|
+
builder.addFormDataPart(name, value)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public fun appendFile(
|
|
147
|
+
name: String,
|
|
148
|
+
filename: String,
|
|
149
|
+
bytes: ByteArray,
|
|
150
|
+
mimeType: String = "application/octet-stream",
|
|
151
|
+
) {
|
|
152
|
+
val body: RequestBody = bytes.toRequestBody(mimeType.toMediaTypeOrNull())
|
|
153
|
+
builder.addFormDataPart(name, filename, body)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public fun build(): RequestBody = builder.build()
|
|
157
|
+
}
|
|
158
|
+
`;
|
|
159
|
+
const REQUEST_OPTIONS_KT = `package __PACKAGE__
|
|
160
|
+
|
|
161
|
+
import okhttp3.HttpUrl
|
|
162
|
+
import okhttp3.Request
|
|
163
|
+
import okhttp3.Response
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Per-call options bag — every generated method takes a
|
|
167
|
+
* \`RequestOptions\` last param. Mirrors hey-api's TS SDK options shape.
|
|
168
|
+
*
|
|
169
|
+
* - \`client\` — override the impl's bound \`APIClient\`.
|
|
170
|
+
* - \`baseUrl\` — override \`client.baseUrl\` for one call.
|
|
171
|
+
* - \`timeout\` — per-call call-timeout in milliseconds.
|
|
172
|
+
* - \`headers\` — extra/override headers, applied last.
|
|
173
|
+
* - \`requestInterceptors\` — extra suspend interceptors, run after
|
|
174
|
+
* client-level ones.
|
|
175
|
+
* - \`responseValidator\` — runs after a 2xx response; throwing
|
|
176
|
+
* converts the call into an exception.
|
|
177
|
+
* - \`responseTransformer\` — rewrite the response body before decode.
|
|
178
|
+
*/
|
|
179
|
+
public data class RequestOptions(
|
|
180
|
+
public val client: APIClient? = null,
|
|
181
|
+
public val baseUrl: HttpUrl? = null,
|
|
182
|
+
public val timeout: Long? = null,
|
|
183
|
+
public val headers: Map<String, String> = emptyMap(),
|
|
184
|
+
public val requestInterceptors: List<suspend (Request) -> Request> = emptyList(),
|
|
185
|
+
public val responseValidator: (suspend (ByteArray, Response) -> Unit)? = null,
|
|
186
|
+
public val responseTransformer: (suspend (ByteArray) -> ByteArray)? = null,
|
|
187
|
+
)
|
|
188
|
+
`;
|
|
189
|
+
const API_KEY_LOCATION_KT = `package __PACKAGE__
|
|
190
|
+
|
|
191
|
+
public enum class APIKeyLocation {
|
|
192
|
+
HEADER,
|
|
193
|
+
QUERY,
|
|
194
|
+
COOKIE,
|
|
195
|
+
}
|
|
196
|
+
`;
|
|
197
|
+
const AUTH_KT = `package __PACKAGE__
|
|
198
|
+
|
|
199
|
+
import java.util.Base64
|
|
200
|
+
import okhttp3.HttpUrl
|
|
201
|
+
import okhttp3.Request
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Auth schemes consumers reach for in practice:
|
|
205
|
+
*
|
|
206
|
+
* - \`Bearer(token)\` — \`Authorization: Bearer <token>\`.
|
|
207
|
+
* - \`ApiKey(name, value, in)\` — header / query / cookie placement,
|
|
208
|
+
* matching the spec's
|
|
209
|
+
* \`securitySchemes.<name>.in\`.
|
|
210
|
+
* - \`Basic(username, password)\` — \`Authorization: Basic <base64>\`.
|
|
211
|
+
*
|
|
212
|
+
* Per-operation auth is auto-wired by the generator when an op has
|
|
213
|
+
* \`security\` requirements; it walks the requirement names and applies
|
|
214
|
+
* any matching scheme value the consumer has placed on \`APIClient.auth\`.
|
|
215
|
+
*
|
|
216
|
+
* \`apply\` mutates the request builder in-place for header / cookie
|
|
217
|
+
* auth and returns the (possibly rewritten) \`HttpUrl\` so query auth
|
|
218
|
+
* can re-thread its name=value into the URL.
|
|
219
|
+
*/
|
|
220
|
+
public sealed class Auth {
|
|
221
|
+
public abstract fun apply(builder: Request.Builder, url: HttpUrl): HttpUrl
|
|
222
|
+
|
|
223
|
+
public data class Bearer(public val token: String) : Auth() {
|
|
224
|
+
override fun apply(builder: Request.Builder, url: HttpUrl): HttpUrl {
|
|
225
|
+
builder.header("Authorization", "Bearer \$token")
|
|
226
|
+
return url
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
public data class ApiKey(
|
|
231
|
+
public val name: String,
|
|
232
|
+
public val value: String,
|
|
233
|
+
public val location: APIKeyLocation,
|
|
234
|
+
) : Auth() {
|
|
235
|
+
override fun apply(builder: Request.Builder, url: HttpUrl): HttpUrl =
|
|
236
|
+
when (location) {
|
|
237
|
+
APIKeyLocation.HEADER -> {
|
|
238
|
+
builder.header(name, value)
|
|
239
|
+
url
|
|
240
|
+
}
|
|
241
|
+
APIKeyLocation.QUERY ->
|
|
242
|
+
url.newBuilder().addQueryParameter(name, value).build()
|
|
243
|
+
APIKeyLocation.COOKIE -> {
|
|
244
|
+
val cookie = "\$name=\$value"
|
|
245
|
+
val existing = builder.build().header("Cookie")
|
|
246
|
+
builder.header("Cookie", existing?.let { "\$it; \$cookie" } ?: cookie)
|
|
247
|
+
url
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
public data class Basic(
|
|
253
|
+
public val username: String,
|
|
254
|
+
public val password: String,
|
|
255
|
+
) : Auth() {
|
|
256
|
+
override fun apply(builder: Request.Builder, url: HttpUrl): HttpUrl {
|
|
257
|
+
val encoded = Base64.getEncoder()
|
|
258
|
+
.encodeToString("\$username:\$password".toByteArray(Charsets.UTF_8))
|
|
259
|
+
builder.header("Authorization", "Basic \$encoded")
|
|
260
|
+
return url
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
`;
|
|
265
|
+
const API_CLIENT_KT_BASE = `package __PACKAGE__
|
|
266
|
+
|
|
267
|
+
import java.util.concurrent.TimeUnit
|
|
268
|
+
import kotlinx.coroutines.Dispatchers
|
|
269
|
+
import kotlinx.coroutines.withContext
|
|
270
|
+
import kotlinx.serialization.json.Json
|
|
271
|
+
import okhttp3.HttpUrl
|
|
272
|
+
import okhttp3.OkHttpClient
|
|
273
|
+
import okhttp3.Request
|
|
274
|
+
import okhttp3.Response
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Runtime helper every per-tag impl class delegates to. Owns the
|
|
278
|
+
* transport-level concerns — \`OkHttpClient\`, \`Json\`, the interceptor
|
|
279
|
+
* pipeline — and provides one source of truth for status-code
|
|
280
|
+
* dispatch and decoding.
|
|
281
|
+
*
|
|
282
|
+
* - \`execute<T>(request, deserializer, …)\` — decodes a 2xx body to \`T\`.
|
|
283
|
+
* - \`executeUnit(request, …)\` — discards the body.
|
|
284
|
+
* - \`executeWithResponse<T>(request, deserializer,\`
|
|
285
|
+
* \`…)\` — decode + raw \`Response\`.
|
|
286
|
+
* - \`executeUnitWithResponse(request, …)\` — raw \`Response\` only.
|
|
287
|
+
* - \`executeRaw(request, …)\` — raw \`(ByteArray, Response)\`,
|
|
288
|
+
* used by multi-2xx ops.
|
|
289
|
+
*
|
|
290
|
+
* Status-code dispatch lives in \`sendAndDispatch\`; 2xx returns the
|
|
291
|
+
* body bytes, 4xx/5xx throw the matching \`APIError\` subclass.
|
|
292
|
+
*/
|
|
293
|
+
public class APIClient(
|
|
294
|
+
public var baseUrl: HttpUrl,
|
|
295
|
+
public val httpClient: OkHttpClient = OkHttpClient(),
|
|
296
|
+
public val json: Json = Json {
|
|
297
|
+
ignoreUnknownKeys = true
|
|
298
|
+
encodeDefaults = true
|
|
299
|
+
},
|
|
300
|
+
public val interceptors: APIInterceptors = APIInterceptors(),__AUTH_FIELD__
|
|
301
|
+
) {
|
|
302
|
+
public suspend fun <T> execute(
|
|
303
|
+
request: Request,
|
|
304
|
+
deserializer: kotlinx.serialization.DeserializationStrategy<T>,
|
|
305
|
+
timeout: Long? = null,
|
|
306
|
+
extraInterceptors: List<suspend (Request) -> Request> = emptyList(),
|
|
307
|
+
responseValidator: (suspend (ByteArray, Response) -> Unit)? = null,
|
|
308
|
+
responseTransformer: (suspend (ByteArray) -> ByteArray)? = null,
|
|
309
|
+
): T {
|
|
310
|
+
val (data, response) = sendAndDispatch(request, timeout, extraInterceptors)
|
|
311
|
+
responseValidator?.invoke(data, response)
|
|
312
|
+
val body = responseTransformer?.invoke(data) ?: data
|
|
313
|
+
return try {
|
|
314
|
+
json.decodeFromString(deserializer, body.decodeToString())
|
|
315
|
+
} catch (e: Throwable) {
|
|
316
|
+
throw APIError.DecodingFailed(e)
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
public suspend fun executeUnit(
|
|
321
|
+
request: Request,
|
|
322
|
+
timeout: Long? = null,
|
|
323
|
+
extraInterceptors: List<suspend (Request) -> Request> = emptyList(),
|
|
324
|
+
responseValidator: (suspend (ByteArray, Response) -> Unit)? = null,
|
|
325
|
+
) {
|
|
326
|
+
val (data, response) = sendAndDispatch(request, timeout, extraInterceptors)
|
|
327
|
+
responseValidator?.invoke(data, response)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
public suspend fun <T> executeWithResponse(
|
|
331
|
+
request: Request,
|
|
332
|
+
deserializer: kotlinx.serialization.DeserializationStrategy<T>,
|
|
333
|
+
timeout: Long? = null,
|
|
334
|
+
extraInterceptors: List<suspend (Request) -> Request> = emptyList(),
|
|
335
|
+
responseValidator: (suspend (ByteArray, Response) -> Unit)? = null,
|
|
336
|
+
responseTransformer: (suspend (ByteArray) -> ByteArray)? = null,
|
|
337
|
+
): Pair<T, Response> {
|
|
338
|
+
val (data, response) = sendAndDispatch(request, timeout, extraInterceptors)
|
|
339
|
+
responseValidator?.invoke(data, response)
|
|
340
|
+
val body = responseTransformer?.invoke(data) ?: data
|
|
341
|
+
return try {
|
|
342
|
+
json.decodeFromString(deserializer, body.decodeToString()) to response
|
|
343
|
+
} catch (e: Throwable) {
|
|
344
|
+
throw APIError.DecodingFailed(e)
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
public suspend fun executeUnitWithResponse(
|
|
349
|
+
request: Request,
|
|
350
|
+
timeout: Long? = null,
|
|
351
|
+
extraInterceptors: List<suspend (Request) -> Request> = emptyList(),
|
|
352
|
+
responseValidator: (suspend (ByteArray, Response) -> Unit)? = null,
|
|
353
|
+
): Response {
|
|
354
|
+
val (data, response) = sendAndDispatch(request, timeout, extraInterceptors)
|
|
355
|
+
responseValidator?.invoke(data, response)
|
|
356
|
+
return response
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
public suspend fun executeRaw(
|
|
360
|
+
request: Request,
|
|
361
|
+
timeout: Long? = null,
|
|
362
|
+
extraInterceptors: List<suspend (Request) -> Request> = emptyList(),
|
|
363
|
+
responseValidator: (suspend (ByteArray, Response) -> Unit)? = null,
|
|
364
|
+
responseTransformer: (suspend (ByteArray) -> ByteArray)? = null,
|
|
365
|
+
): Pair<ByteArray, Response> {
|
|
366
|
+
val (data, response) = sendAndDispatch(request, timeout, extraInterceptors)
|
|
367
|
+
responseValidator?.invoke(data, response)
|
|
368
|
+
val body = responseTransformer?.invoke(data) ?: data
|
|
369
|
+
return body to response
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
private suspend fun sendAndDispatch(
|
|
373
|
+
request: Request,
|
|
374
|
+
timeout: Long?,
|
|
375
|
+
extraInterceptors: List<suspend (Request) -> Request>,
|
|
376
|
+
): Pair<ByteArray, Response> {
|
|
377
|
+
var req = request
|
|
378
|
+
for (interceptor in interceptors.request) req = interceptor(req)
|
|
379
|
+
for (interceptor in extraInterceptors) req = interceptor(req)
|
|
380
|
+
val callClient = if (timeout == null) httpClient else
|
|
381
|
+
httpClient.newBuilder().callTimeout(timeout, TimeUnit.MILLISECONDS).build()
|
|
382
|
+
val response = try {
|
|
383
|
+
withContext(Dispatchers.IO) {
|
|
384
|
+
callClient.newCall(req).execute()
|
|
385
|
+
}
|
|
386
|
+
} catch (e: Throwable) {
|
|
387
|
+
throw APIError.Transport(e)
|
|
388
|
+
}
|
|
389
|
+
val body = response.body?.bytes() ?: ByteArray(0)
|
|
390
|
+
return when (val code = response.code) {
|
|
391
|
+
in 200..299 -> body to response
|
|
392
|
+
in 400..499 -> throw APIError.ClientError(code, body)
|
|
393
|
+
in 500..599 -> throw APIError.ServerError(code, body)
|
|
394
|
+
else -> throw APIError.UnexpectedStatus(code, body)
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
`;
|
|
399
|
+
export function apiClientKt(opts) {
|
|
400
|
+
const authField = opts.hasAuth
|
|
401
|
+
? "\n public val auth: MutableMap<String, Auth> = mutableMapOf(),"
|
|
402
|
+
: "";
|
|
403
|
+
return API_CLIENT_KT_BASE.replace("__AUTH_FIELD__", authField);
|
|
404
|
+
}
|
|
405
|
+
/** Ordered runtime files. The orchestrator places them under `API/`. */
|
|
406
|
+
export function buildRuntimeFiles(opts, pkg) {
|
|
407
|
+
const subst = (s) => s.replace(/__PACKAGE__/g, pkg);
|
|
408
|
+
const files = [
|
|
409
|
+
{ name: "APIClient.kt", content: subst(apiClientKt(opts)) },
|
|
410
|
+
{ name: "APIError.kt", content: subst(API_ERROR_KT) },
|
|
411
|
+
{ name: "APIInterceptors.kt", content: subst(API_INTERCEPTORS_KT) },
|
|
412
|
+
{ name: "QueryStyle.kt", content: subst(QUERY_STYLE_KT) },
|
|
413
|
+
{ name: "URLEncoding.kt", content: subst(URL_ENCODING_KT) },
|
|
414
|
+
{ name: "RequestOptions.kt", content: subst(REQUEST_OPTIONS_KT) },
|
|
415
|
+
];
|
|
416
|
+
if (opts.hasAuth) {
|
|
417
|
+
files.push({ name: "Auth.kt", content: subst(AUTH_KT) });
|
|
418
|
+
files.push({
|
|
419
|
+
name: "APIKeyLocation.kt",
|
|
420
|
+
content: subst(API_KEY_LOCATION_KT),
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
if (opts.hasMultipart) {
|
|
424
|
+
files.push({
|
|
425
|
+
name: "MultipartFormBody.kt",
|
|
426
|
+
content: subst(MULTIPART_KT),
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
return files;
|
|
430
|
+
}
|
|
431
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../../src/ir/runtime/templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAqBH,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;CAc3B,CAAC;AAEF,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuCpB,CAAC;AAEF,MAAM,cAAc,GAAG;;;;;;;;;;;;CAYtB,CAAC;AAEF,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCvB,CAAC;AAEF,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCpB,CAAC;AAEF,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6B1B,CAAC;AAEF,MAAM,mBAAmB,GAAG;;;;;;;CAO3B,CAAC;AAEF,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmEf,CAAC;AAEF,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqI1B,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,IAAiB;IAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO;QAC5B,CAAC,CAAC,mEAAmE;QACrE,CAAC,CAAC,EAAE,CAAC;IACP,OAAO,kBAAkB,CAAC,OAAO,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;AACjE,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,iBAAiB,CAC/B,IAAiB,EACjB,GAAW;IAEX,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAkB;QAC3B,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,EAAE;QAC3D,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC,EAAE;QACrD,EAAE,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,KAAK,CAAC,mBAAmB,CAAC,EAAE;QACnE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,EAAE;QACzD,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,KAAK,CAAC,eAAe,CAAC,EAAE;QAC3D,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,KAAK,CAAC,kBAAkB,CAAC,EAAE;KAClE,CAAC;IACF,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACzD,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,mBAAmB;YACzB,OAAO,EAAE,KAAK,CAAC,mBAAmB,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,sBAAsB;YAC5B,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC;SAC7B,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IR } from "@hey-api/shared";
|
|
2
|
+
import { type KtDecl } from "../kt-dsl/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Translate `IR.Model.components.schemas` into Kotlin decls. Object schemas
|
|
5
|
+
* with properties become `@Serializable` data classes; `enum` schemas
|
|
6
|
+
* become `String`-raw `@Serializable` enums; primitives/arrays/unions
|
|
7
|
+
* become typealiases. Inline nested objects/enums are promoted to
|
|
8
|
+
* top-level synthetic decls (`Owner_PropertyName`).
|
|
9
|
+
*/
|
|
10
|
+
export declare function schemasToDecls(schemas: Record<string, IR.SchemaObject>): KtDecl[];
|
|
11
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/ir/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAG1C,OAAO,EACL,KAAK,MAAM,EAMZ,MAAM,oBAAoB,CAAC;AAG5B;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,GACvC,MAAM,EAAE,CA6CV"}
|