@workos/oagen-emitters 0.8.1 → 0.8.2
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/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +7 -0
- package/dist/index.mjs +1 -1
- package/dist/{plugin-DOE0FqrZ.mjs → plugin-CeNME04k.mjs} +221 -52
- package/dist/plugin-CeNME04k.mjs.map +1 -0
- package/dist/plugin.mjs +1 -1
- package/package.json +1 -1
- package/src/kotlin/models.ts +67 -3
- package/src/kotlin/resources.ts +128 -37
- package/src/kotlin/tests.ts +33 -5
- package/src/kotlin/wrappers.ts +60 -18
- package/dist/plugin-DOE0FqrZ.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.8.2](https://github.com/workos/oagen-emitters/compare/v0.8.1...v0.8.2) (2026-05-05)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **kotlin:** improve emitter output quality ([#86](https://github.com/workos/oagen-emitters/issues/86)) ([6dd9b2a](https://github.com/workos/oagen-emitters/commit/6dd9b2ad6904ebb088cba65801d4987a2af61482))
|
|
9
|
+
|
|
3
10
|
## [0.8.1](https://github.com/workos/oagen-emitters/compare/v0.8.0...v0.8.1) (2026-05-05)
|
|
4
11
|
|
|
5
12
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as nodeEmitter, a as rustExtractor, c as pythonExtractor, d as rubyEmitter, f as kotlinEmitter, g as pythonEmitter, h as phpEmitter, i as kotlinExtractor, l as rubyExtractor, m as goEmitter, n as elixirExtractor, o as goExtractor, p as dotnetEmitter, r as dotnetExtractor, s as phpExtractor, t as workosEmittersPlugin, u as nodeExtractor } from "./plugin-
|
|
1
|
+
import { _ as nodeEmitter, a as rustExtractor, c as pythonExtractor, d as rubyEmitter, f as kotlinEmitter, g as pythonEmitter, h as phpEmitter, i as kotlinExtractor, l as rubyExtractor, m as goEmitter, n as elixirExtractor, o as goExtractor, p as dotnetEmitter, r as dotnetExtractor, s as phpExtractor, t as workosEmittersPlugin, u as nodeExtractor } from "./plugin-CeNME04k.mjs";
|
|
2
2
|
export { dotnetEmitter, dotnetExtractor, elixirExtractor, goEmitter, goExtractor, kotlinEmitter, kotlinExtractor, nodeEmitter, nodeExtractor, phpEmitter, phpExtractor, pythonEmitter, pythonExtractor, rubyEmitter, rubyExtractor, rustExtractor, workosEmittersPlugin };
|
|
@@ -17749,6 +17749,40 @@ const KOTLIN_SRC_PREFIX$2 = "src/main/kotlin/";
|
|
|
17749
17749
|
const MODELS_PACKAGE = "com.workos.models";
|
|
17750
17750
|
const MODELS_DIR = "com/workos/models";
|
|
17751
17751
|
/**
|
|
17752
|
+
* Some specs leave string fields without `format: date-time` even though the
|
|
17753
|
+
* description (or the example) makes clear they carry an ISO-8601 timestamp.
|
|
17754
|
+
* Detect that here so we can promote the type to `OffsetDateTime` in the
|
|
17755
|
+
* Kotlin output.
|
|
17756
|
+
*/
|
|
17757
|
+
const ISO_8601_DESCRIPTION_RE$2 = /\bISO[-_ ]?8601\b/i;
|
|
17758
|
+
function looksLikeIso8601String$2(description) {
|
|
17759
|
+
if (!description) return false;
|
|
17760
|
+
return ISO_8601_DESCRIPTION_RE$2.test(description);
|
|
17761
|
+
}
|
|
17762
|
+
function promoteIso8601TypeRef$2(type, description) {
|
|
17763
|
+
if (!looksLikeIso8601String$2(description)) return type;
|
|
17764
|
+
const promote = (t) => {
|
|
17765
|
+
if (t.kind === "primitive" && t.type === "string" && !t.format) return {
|
|
17766
|
+
kind: "primitive",
|
|
17767
|
+
type: "string",
|
|
17768
|
+
format: "date-time"
|
|
17769
|
+
};
|
|
17770
|
+
if (t.kind === "nullable") return {
|
|
17771
|
+
kind: "nullable",
|
|
17772
|
+
inner: promote(t.inner)
|
|
17773
|
+
};
|
|
17774
|
+
return t;
|
|
17775
|
+
};
|
|
17776
|
+
return promote(type);
|
|
17777
|
+
}
|
|
17778
|
+
function promoteFieldType$1(f) {
|
|
17779
|
+
const promoted = promoteIso8601TypeRef$2(f.type, f.description);
|
|
17780
|
+
return promoted === f.type ? f : {
|
|
17781
|
+
...f,
|
|
17782
|
+
type: promoted
|
|
17783
|
+
};
|
|
17784
|
+
}
|
|
17785
|
+
/**
|
|
17752
17786
|
* Generate Kotlin `data class` models. Each model becomes a separate `.kt`
|
|
17753
17787
|
* file under `com.workos.models`. Discriminated unions emit a sealed class
|
|
17754
17788
|
* with Jackson `@JsonTypeInfo` / `@JsonSubTypes` annotations so the base type
|
|
@@ -17985,7 +18019,8 @@ function emitWorkOSEvent(eventMapping) {
|
|
|
17985
18019
|
function renderFields(fields, overrideFields = /* @__PURE__ */ new Set()) {
|
|
17986
18020
|
const seen = /* @__PURE__ */ new Set();
|
|
17987
18021
|
const lines = [];
|
|
17988
|
-
for (const
|
|
18022
|
+
for (const rawField of fields) {
|
|
18023
|
+
const field = promoteFieldType$1(rawField);
|
|
17989
18024
|
const kotlinName = propertyName(field.name);
|
|
17990
18025
|
if (seen.has(kotlinName)) continue;
|
|
17991
18026
|
seen.add(kotlinName);
|
|
@@ -18004,7 +18039,7 @@ function renderFields(fields, overrideFields = /* @__PURE__ */ new Set()) {
|
|
|
18004
18039
|
const isOverride = overrideFields.has(kotlinName);
|
|
18005
18040
|
const annotations = [];
|
|
18006
18041
|
annotations.push(`@JsonProperty(${ktStringLiteral(field.name)})`);
|
|
18007
|
-
if (field.deprecated) annotations.push(
|
|
18042
|
+
if (field.deprecated) annotations.push(buildDeprecatedAnnotation(field.description));
|
|
18008
18043
|
const paramParts = [];
|
|
18009
18044
|
if (field.description?.trim()) {
|
|
18010
18045
|
const line = field.description.split("\n").find((l) => l.trim()) ?? "";
|
|
@@ -18035,6 +18070,26 @@ function collapseFieldEntries(rawLines) {
|
|
|
18035
18070
|
return entries;
|
|
18036
18071
|
}
|
|
18037
18072
|
/**
|
|
18073
|
+
* Pull the most useful free-form deprecation hint out of a field description
|
|
18074
|
+
* and lift it into the `@Deprecated(...)` message argument. Most WorkOS
|
|
18075
|
+
* deprecations are written as a description that begins with "Deprecated"
|
|
18076
|
+
* (e.g. "Deprecated. Use `domain_data` instead."). When the description
|
|
18077
|
+
* doesn't carry a hint we fall back to a short, self-explanatory message
|
|
18078
|
+
* rather than the generic "Deprecated field" placeholder.
|
|
18079
|
+
*/
|
|
18080
|
+
function deprecationMessageFromDescription(description) {
|
|
18081
|
+
if (!description) return "Deprecated.";
|
|
18082
|
+
const firstLine = description.split("\n").map((l) => l.trim()).find((l) => l.length > 0);
|
|
18083
|
+
if (!firstLine) return "Deprecated.";
|
|
18084
|
+
const collapsed = firstLine.replace(/\s+/g, " ").trim();
|
|
18085
|
+
if (collapsed.length === 0) return "Deprecated.";
|
|
18086
|
+
if (/\bdeprecat/i.test(collapsed)) return collapsed;
|
|
18087
|
+
return "Deprecated.";
|
|
18088
|
+
}
|
|
18089
|
+
function buildDeprecatedAnnotation(description) {
|
|
18090
|
+
return `@Deprecated(${ktStringLiteral(deprecationMessageFromDescription(description))})`;
|
|
18091
|
+
}
|
|
18092
|
+
/**
|
|
18038
18093
|
* If the TypeRef is a literal (const) with a string, number, or boolean value,
|
|
18039
18094
|
* return the Kotlin expression for that default. Otherwise return null.
|
|
18040
18095
|
*/
|
|
@@ -18049,7 +18104,8 @@ function collectImports(fields) {
|
|
|
18049
18104
|
const imports = /* @__PURE__ */ new Set();
|
|
18050
18105
|
if (fields.length === 0) return imports;
|
|
18051
18106
|
imports.add("com.fasterxml.jackson.annotation.JsonProperty");
|
|
18052
|
-
for (const
|
|
18107
|
+
for (const rawField of fields) {
|
|
18108
|
+
const field = promoteFieldType$1(rawField);
|
|
18053
18109
|
const mapped = mapTypeRef$1(field.type);
|
|
18054
18110
|
if (/\bOffsetDateTime\b/.test(mapped)) imports.add("java.time.OffsetDateTime");
|
|
18055
18111
|
for (const enumName of collectEnumNames(field.type)) {
|
|
@@ -18206,21 +18262,21 @@ function emitWrapperMethod$1(resolvedOp, wrapper, ctx) {
|
|
|
18206
18262
|
if (opDesc) kdocLines.push(opDesc.split("\n")[0]);
|
|
18207
18263
|
else kdocLines.push(`${wrapperHumanName.charAt(0).toUpperCase()}${wrapperHumanName.slice(1)}.`);
|
|
18208
18264
|
const paramDocs = [];
|
|
18209
|
-
|
|
18210
|
-
|
|
18211
|
-
const
|
|
18212
|
-
|
|
18213
|
-
|
|
18265
|
+
const pushParamDoc = (kotlinName, sourceName, description) => {
|
|
18266
|
+
const firstLine = description?.split("\n").find((l) => l.trim())?.trim() ?? "";
|
|
18267
|
+
const fallback = `the ${humanize(sourceName)} of the request.`;
|
|
18268
|
+
const text = firstLine || fallback;
|
|
18269
|
+
paramDocs.push(`@param ${kotlinName} ${escapeKdoc$1(text)}`);
|
|
18270
|
+
};
|
|
18271
|
+
for (const pp of pathParams) pushParamDoc(propertyName(pp.name), pp.name, pp.description);
|
|
18272
|
+
for (const rp of resolvedParams) pushParamDoc(propertyName(rp.paramName), rp.paramName, rp.field?.description);
|
|
18273
|
+
pushParamDoc("requestOptions", "request_options", "per-request overrides (idempotency key, API key, headers, timeout)");
|
|
18214
18274
|
if (responseClass) paramDocs.push(`@return the ${responseClass}`);
|
|
18215
|
-
|
|
18216
|
-
|
|
18217
|
-
|
|
18218
|
-
|
|
18219
|
-
|
|
18220
|
-
for (const p of paramDocs) lines.push(` * ${p}`);
|
|
18221
|
-
}
|
|
18222
|
-
lines.push(" */");
|
|
18223
|
-
}
|
|
18275
|
+
lines.push(" /**");
|
|
18276
|
+
for (const l of kdocLines) lines.push(` * ${escapeKdoc$1(l)}`);
|
|
18277
|
+
lines.push(" *");
|
|
18278
|
+
for (const p of paramDocs) lines.push(` * ${p}`);
|
|
18279
|
+
lines.push(" */");
|
|
18224
18280
|
lines.push(" @JvmOverloads");
|
|
18225
18281
|
const params = [];
|
|
18226
18282
|
for (const pp of pathParams) params.push(` ${propertyName(pp.name)}: String`);
|
|
@@ -18243,6 +18299,25 @@ function emitWrapperMethod$1(resolvedOp, wrapper, ctx) {
|
|
|
18243
18299
|
}
|
|
18244
18300
|
lines.push(` )${returnClause} {`);
|
|
18245
18301
|
}
|
|
18302
|
+
const inferred = wrapper.inferFromClient ?? [];
|
|
18303
|
+
const usesStandardClientCreds = inferred.includes("client_id") && inferred.includes("client_secret");
|
|
18304
|
+
if (op.path === "/user_management/authenticate" && op.httpMethod.toUpperCase() === "POST" && responseClass === "AuthenticateResponse" && typeof wrapper.defaults?.grant_type === "string" && usesStandardClientCreds) {
|
|
18305
|
+
const grantType = wrapper.defaults.grant_type;
|
|
18306
|
+
lines.push(` return authenticate(`);
|
|
18307
|
+
lines.push(` grantType = ${ktLiteral(grantType)},`);
|
|
18308
|
+
lines.push(` requestOptions = requestOptions,`);
|
|
18309
|
+
const entryLines = resolvedParams.map((rp) => {
|
|
18310
|
+
const paramName = propertyName(rp.paramName);
|
|
18311
|
+
return ` ${ktLiteral(rp.paramName)} to ${paramName}`;
|
|
18312
|
+
});
|
|
18313
|
+
for (let i = 0; i < entryLines.length; i++) {
|
|
18314
|
+
const sep = i === entryLines.length - 1 ? "" : ",";
|
|
18315
|
+
lines.push(`${entryLines[i]}${sep}`);
|
|
18316
|
+
}
|
|
18317
|
+
lines.push(` )`);
|
|
18318
|
+
lines.push(" }");
|
|
18319
|
+
return lines;
|
|
18320
|
+
}
|
|
18246
18321
|
const bodyEntries = [];
|
|
18247
18322
|
for (const rp of resolvedParams) {
|
|
18248
18323
|
const paramName = propertyName(rp.paramName);
|
|
@@ -18301,6 +18376,52 @@ function isHandwrittenOverride(op) {
|
|
|
18301
18376
|
//#region src/kotlin/resources.ts
|
|
18302
18377
|
const KOTLIN_SRC_PREFIX$1 = "src/main/kotlin/";
|
|
18303
18378
|
/**
|
|
18379
|
+
* Some specs leave query params / fields typed as plain `string` even though
|
|
18380
|
+
* the description (or the field name) makes clear they carry an ISO-8601
|
|
18381
|
+
* timestamp. Detecting that here lets us emit `OffsetDateTime` so callers
|
|
18382
|
+
* don't have to format the wire string themselves.
|
|
18383
|
+
*/
|
|
18384
|
+
const ISO_8601_DESCRIPTION_RE$1 = /\bISO[-_ ]?8601\b/i;
|
|
18385
|
+
function looksLikeIso8601String$1(description) {
|
|
18386
|
+
if (!description) return false;
|
|
18387
|
+
return ISO_8601_DESCRIPTION_RE$1.test(description);
|
|
18388
|
+
}
|
|
18389
|
+
/**
|
|
18390
|
+
* Promote a string `TypeRef` to a `format: date-time` primitive when the
|
|
18391
|
+
* accompanying description identifies it as an ISO-8601 timestamp. Leaves
|
|
18392
|
+
* non-string types untouched.
|
|
18393
|
+
*/
|
|
18394
|
+
function promoteIso8601TypeRef$1(type, description) {
|
|
18395
|
+
if (!looksLikeIso8601String$1(description)) return type;
|
|
18396
|
+
const promote = (t) => {
|
|
18397
|
+
if (t.kind === "primitive" && t.type === "string" && !t.format) return {
|
|
18398
|
+
kind: "primitive",
|
|
18399
|
+
type: "string",
|
|
18400
|
+
format: "date-time"
|
|
18401
|
+
};
|
|
18402
|
+
if (t.kind === "nullable") return {
|
|
18403
|
+
kind: "nullable",
|
|
18404
|
+
inner: promote(t.inner)
|
|
18405
|
+
};
|
|
18406
|
+
return t;
|
|
18407
|
+
};
|
|
18408
|
+
return promote(type);
|
|
18409
|
+
}
|
|
18410
|
+
function promoteParameterType(p) {
|
|
18411
|
+
const promoted = promoteIso8601TypeRef$1(p.type, p.description);
|
|
18412
|
+
return promoted === p.type ? p : {
|
|
18413
|
+
...p,
|
|
18414
|
+
type: promoted
|
|
18415
|
+
};
|
|
18416
|
+
}
|
|
18417
|
+
function promoteFieldType(f) {
|
|
18418
|
+
const promoted = promoteIso8601TypeRef$1(f.type, f.description);
|
|
18419
|
+
return promoted === f.type ? f : {
|
|
18420
|
+
...f,
|
|
18421
|
+
type: promoted
|
|
18422
|
+
};
|
|
18423
|
+
}
|
|
18424
|
+
/**
|
|
18304
18425
|
* Generate one API class per mount group. Methods map 1:1 to IR operations.
|
|
18305
18426
|
* Path params, query params, and body fields are flattened into the method
|
|
18306
18427
|
* signature so callers never need to construct an intermediate options object.
|
|
@@ -18431,9 +18552,9 @@ function renderMethod(_mountName, method, op, ctx, resolvedOp, imports) {
|
|
|
18431
18552
|
const pathParams = sortPathParamsByTemplateOrder(op);
|
|
18432
18553
|
const groupedParamNames = collectGroupedParamNames(op);
|
|
18433
18554
|
const hasGroups = (op.parameterGroups?.length ?? 0) > 0;
|
|
18434
|
-
const queryParams = op.queryParams.filter((p) => !hidden.has(p.name) && !groupedParamNames.has(p.name));
|
|
18555
|
+
const queryParams = op.queryParams.filter((p) => !hidden.has(p.name) && !groupedParamNames.has(p.name)).map(promoteParameterType);
|
|
18435
18556
|
const bodyModel = resolveBodyModel$2(op, ctx);
|
|
18436
|
-
const bodyFields = bodyModel ? bodyModel.fields.filter((f) => !hidden.has(f.name) && !groupedParamNames.has(f.name)) : [];
|
|
18557
|
+
const bodyFields = bodyModel ? bodyModel.fields.filter((f) => !hidden.has(f.name) && !groupedParamNames.has(f.name)).map(promoteFieldType) : [];
|
|
18437
18558
|
for (const p of [...pathParams, ...queryParams]) registerTypeImports(p.type, imports, ctx);
|
|
18438
18559
|
for (const f of bodyFields) registerTypeImports(f.type, imports, ctx);
|
|
18439
18560
|
const paginatedItemName = resolvePaginatedItemName(plan.paginatedItemModelName, ctx);
|
|
@@ -18544,9 +18665,8 @@ function renderMethod(_mountName, method, op, ctx, resolvedOp, imports) {
|
|
|
18544
18665
|
lines.push(` before = ${pickNamedQueryParam(sortedQuery, "before")},`);
|
|
18545
18666
|
lines.push(` after = ${pickNamedQueryParam(sortedQuery, "after")}`);
|
|
18546
18667
|
lines.push(` ) {`);
|
|
18547
|
-
|
|
18548
|
-
for (const
|
|
18549
|
-
for (const group of op.parameterGroups ?? []) for (const ln of emitGroupQueryDispatch(group, groupParamNames.get(group.name), " ")) lines.push(ln);
|
|
18668
|
+
for (const qp of sortedQuery.filter((p) => p.name !== "after" && p.name !== "before")) for (const ln of emitQueryParam(qp, " ", true)) lines.push(ln);
|
|
18669
|
+
for (const group of op.parameterGroups ?? []) for (const ln of emitGroupQueryDispatch(group, groupParamNames.get(group.name), " ", true)) lines.push(ln);
|
|
18550
18670
|
lines.push(` }`);
|
|
18551
18671
|
} else {
|
|
18552
18672
|
const groupsGoToQuery = hasGroups && !hasBody;
|
|
@@ -18666,14 +18786,15 @@ function buildMethodKdoc(op, pathParams, queryParams, bodyFields, bodyParamNames
|
|
|
18666
18786
|
if (descriptionRaw) for (const l of descriptionRaw.split("\n")) textLines.push(escapeKdoc(l));
|
|
18667
18787
|
const paramDocs = [];
|
|
18668
18788
|
const seenParamDocs = /* @__PURE__ */ new Set();
|
|
18669
|
-
const pushParamDoc = (name, description, deprecated) => {
|
|
18789
|
+
const pushParamDoc = (name, sourceName, description, deprecated) => {
|
|
18670
18790
|
if (seenParamDocs.has(name)) return;
|
|
18671
18791
|
seenParamDocs.add(name);
|
|
18672
|
-
paramDocs.push(formatParamDoc(name, description, deprecated));
|
|
18792
|
+
paramDocs.push(formatParamDoc(name, description, deprecated, sourceName));
|
|
18673
18793
|
};
|
|
18674
|
-
for (const pp of pathParams)
|
|
18675
|
-
for (const qp of queryParams)
|
|
18676
|
-
for (const bf of bodyFields)
|
|
18794
|
+
for (const pp of pathParams) pushParamDoc(propertyName(pp.name), pp.name, pp.description, pp.deprecated);
|
|
18795
|
+
for (const qp of queryParams) pushParamDoc(propertyName(qp.name), qp.name, qp.description, qp.deprecated);
|
|
18796
|
+
for (const bf of bodyFields) pushParamDoc(bodyParamNames.get(bf.name), bf.name, bf.description, bf.deprecated);
|
|
18797
|
+
pushParamDoc("requestOptions", "request_options", REQUEST_OPTIONS_PARAM_DESCRIPTION);
|
|
18677
18798
|
const returnDoc = plan.isPaginated ? "@return a [com.workos.common.http.Page] of results" : plan.responseModelName ? `@return the ${plan.isArrayResponse ? `list of ${className$1(plan.responseModelName)}` : className$1(plan.responseModelName)}` : null;
|
|
18678
18799
|
if (!(textLines.length > 0 || paramDocs.length > 0 || returnDoc !== null)) return [];
|
|
18679
18800
|
const out = [" /**"];
|
|
@@ -18687,10 +18808,17 @@ function buildMethodKdoc(op, pathParams, queryParams, bodyFields, bodyParamNames
|
|
|
18687
18808
|
out.push(" */");
|
|
18688
18809
|
return out;
|
|
18689
18810
|
}
|
|
18690
|
-
|
|
18691
|
-
|
|
18692
|
-
|
|
18693
|
-
|
|
18811
|
+
/**
|
|
18812
|
+
* Stable, canned description for the trailing `requestOptions` parameter that
|
|
18813
|
+
* every generated method exposes. Kept as a constant so the same phrasing
|
|
18814
|
+
* appears across resource methods, wrapper methods, and union-split helpers.
|
|
18815
|
+
*/
|
|
18816
|
+
const REQUEST_OPTIONS_PARAM_DESCRIPTION = "per-request overrides (idempotency key, API key, headers, timeout)";
|
|
18817
|
+
function formatParamDoc(kotlinName, description, deprecated, sourceName) {
|
|
18818
|
+
const specText = (description?.split("\n").find((l) => l.trim()) ?? "").trim();
|
|
18819
|
+
const deprecationNote = deprecated ? "**Deprecated.**" : "";
|
|
18820
|
+
const fallback = `the ${humanize(sourceName ?? kotlinName)} of the request.`;
|
|
18821
|
+
return `@param ${kotlinName} ${escapeKdoc([deprecationNote, specText || fallback].filter(Boolean).join(" "))}`;
|
|
18694
18822
|
}
|
|
18695
18823
|
/**
|
|
18696
18824
|
* Unwrap a possibly-nullable type to check if the inner type is an array,
|
|
@@ -18709,32 +18837,43 @@ function unwrapArray(t) {
|
|
|
18709
18837
|
function valueExprForQuery(type) {
|
|
18710
18838
|
const inner = type.kind === "nullable" ? type.inner : type;
|
|
18711
18839
|
if (inner.kind === "enum") return "it.value";
|
|
18712
|
-
if (inner.kind === "primitive" && inner.type === "string") return "it";
|
|
18840
|
+
if (inner.kind === "primitive" && inner.type === "string") return inner.format === "date-time" ? "it.toString()" : "it";
|
|
18713
18841
|
return "it.toString()";
|
|
18714
18842
|
}
|
|
18715
|
-
function emitQueryParam(p, indent) {
|
|
18843
|
+
function emitQueryParam(p, indent, receiverMode = false) {
|
|
18716
18844
|
const prop = propertyName(p.name);
|
|
18717
18845
|
const rendered = queryParamToString(p.type, prop);
|
|
18718
18846
|
const inner = p.type.kind === "nullable" ? p.type.inner : p.type;
|
|
18719
18847
|
const arrayItem = unwrapArray(p.type);
|
|
18848
|
+
const callPrefix = receiverMode ? "" : "params.";
|
|
18849
|
+
const addPair = (pair) => receiverMode ? `add(${pair})` : `params += ${pair}`;
|
|
18720
18850
|
if (arrayItem) {
|
|
18721
18851
|
const explode = p.explode ?? true;
|
|
18722
18852
|
const itemExpr = valueExprForQuery(arrayItem);
|
|
18853
|
+
const isIdentity = itemExpr === "it";
|
|
18723
18854
|
if (!explode) {
|
|
18724
|
-
if (p.required)
|
|
18725
|
-
|
|
18855
|
+
if (p.required) {
|
|
18856
|
+
const arg = isIdentity ? prop : `${prop}.map { ${itemExpr} }`;
|
|
18857
|
+
return [`${indent}${callPrefix}addJoinedIfNotNull(${ktLiteral(p.name)}, ${arg})`];
|
|
18858
|
+
}
|
|
18859
|
+
const arg = isIdentity ? prop : `${prop}?.map { ${itemExpr} }`;
|
|
18860
|
+
return [`${indent}${callPrefix}addJoinedIfNotNull(${ktLiteral(p.name)}, ${arg})`];
|
|
18726
18861
|
}
|
|
18727
|
-
if (p.required)
|
|
18728
|
-
|
|
18862
|
+
if (p.required) {
|
|
18863
|
+
const arg = isIdentity ? prop : `${prop}.map { ${itemExpr} }`;
|
|
18864
|
+
return [`${indent}${callPrefix}addEach(${ktLiteral(p.name)}, ${arg})`];
|
|
18865
|
+
}
|
|
18866
|
+
if (isIdentity) return [`${indent}${prop}?.let { ${callPrefix}addEach(${ktLiteral(p.name)}, it) }`];
|
|
18867
|
+
return [`${indent}${prop}?.let { ${callPrefix}addEach(${ktLiteral(p.name)}, it.map { ${itemExpr} }) }`];
|
|
18729
18868
|
}
|
|
18730
|
-
if (p.required) return [`${indent}
|
|
18731
|
-
if (inner.kind === "primitive" && inner.type === "string") return [`${indent}
|
|
18732
|
-
return [`${indent}${prop}?.let {
|
|
18869
|
+
if (p.required) return [`${indent}${addPair(`${ktLiteral(p.name)} to ${rendered}`)}`];
|
|
18870
|
+
if (inner.kind === "primitive" && inner.type === "string" && inner.format !== "date-time") return [`${indent}${callPrefix}addIfNotNull(${ktLiteral(p.name)}, ${prop})`];
|
|
18871
|
+
return [`${indent}${prop}?.let { ${addPair(`${ktLiteral(p.name)} to ${queryParamToString(inner, "it")}`)} }`];
|
|
18733
18872
|
}
|
|
18734
18873
|
function queryParamToString(type, varName) {
|
|
18735
18874
|
if (type.kind === "enum") return `${varName}.value`;
|
|
18736
18875
|
if (type.kind === "nullable") return queryParamToString(type.inner, varName);
|
|
18737
|
-
if (type.kind === "primitive" && type.type === "string") return varName;
|
|
18876
|
+
if (type.kind === "primitive" && type.type === "string") return type.format === "date-time" ? `${varName}.toString()` : varName;
|
|
18738
18877
|
return `${varName}.toString()`;
|
|
18739
18878
|
}
|
|
18740
18879
|
function pickNamedQueryParam(sorted, name) {
|
|
@@ -18848,14 +18987,14 @@ function generateSealedClass(group, bodyFieldTypes) {
|
|
|
18848
18987
|
return lines;
|
|
18849
18988
|
}
|
|
18850
18989
|
/** Emit `when` dispatch that serializes a parameter group into query params. */
|
|
18851
|
-
function emitGroupQueryDispatch(group, prop, indent) {
|
|
18990
|
+
function emitGroupQueryDispatch(group, prop, indent, receiverMode = false) {
|
|
18852
18991
|
const sealedName = sealedGroupName$1(group.name);
|
|
18853
18992
|
const lines = [];
|
|
18854
18993
|
if (group.optional) {
|
|
18855
18994
|
lines.push(`${indent}if (${prop} != null) {`);
|
|
18856
|
-
emitWhenBlock(lines, group, sealedName, prop, `${indent}
|
|
18995
|
+
emitWhenBlock(lines, group, sealedName, prop, `${indent} `, receiverMode);
|
|
18857
18996
|
lines.push(`${indent}}`);
|
|
18858
|
-
} else emitWhenBlock(lines, group, sealedName, prop, indent);
|
|
18997
|
+
} else emitWhenBlock(lines, group, sealedName, prop, indent, receiverMode);
|
|
18859
18998
|
return lines;
|
|
18860
18999
|
}
|
|
18861
19000
|
function assignGroupParameterNames$1(op, occupiedNames) {
|
|
@@ -18882,13 +19021,14 @@ function reserveUniqueGroupParameterName$1(base, occupiedNames) {
|
|
|
18882
19021
|
occupiedNames.add(fallback);
|
|
18883
19022
|
return fallback;
|
|
18884
19023
|
}
|
|
18885
|
-
function emitWhenBlock(lines, group, sealedName, prop, indent) {
|
|
19024
|
+
function emitWhenBlock(lines, group, sealedName, prop, indent, receiverMode = false) {
|
|
18886
19025
|
lines.push(`${indent}when (${prop}) {`);
|
|
18887
19026
|
for (const variant of group.variants) {
|
|
18888
19027
|
const variantName = className$1(variant.name);
|
|
18889
19028
|
const entries = variant.parameters.map((p) => {
|
|
18890
19029
|
const fieldProp = deriveShortPropertyName(p.name, group.name);
|
|
18891
|
-
|
|
19030
|
+
const pair = `${ktLiteral(p.name)} to ${prop}.${fieldProp}`;
|
|
19031
|
+
return receiverMode ? `add(${pair})` : `params += ${pair}`;
|
|
18892
19032
|
});
|
|
18893
19033
|
if (entries.length === 1) lines.push(`${indent} is ${sealedName}.${variantName} -> ${entries[0]}`);
|
|
18894
19034
|
else {
|
|
@@ -18986,6 +19126,33 @@ function deduplicateByMount(services, ctx) {
|
|
|
18986
19126
|
//#region src/kotlin/tests.ts
|
|
18987
19127
|
const TEST_PREFIX = "src/test/kotlin/";
|
|
18988
19128
|
/**
|
|
19129
|
+
* Mirror the ISO-8601 hint promotion the resource/model emitters use so tests
|
|
19130
|
+
* synthesize values whose Kotlin type matches the generated method signature.
|
|
19131
|
+
* Kept in sync with the helpers in `resources.ts` / `models.ts`; if the
|
|
19132
|
+
* detection rule changes, update all three.
|
|
19133
|
+
*/
|
|
19134
|
+
const ISO_8601_DESCRIPTION_RE = /\bISO[-_ ]?8601\b/i;
|
|
19135
|
+
function looksLikeIso8601String(description) {
|
|
19136
|
+
if (!description) return false;
|
|
19137
|
+
return ISO_8601_DESCRIPTION_RE.test(description);
|
|
19138
|
+
}
|
|
19139
|
+
function promoteIso8601TypeRef(type, description) {
|
|
19140
|
+
if (!looksLikeIso8601String(description)) return type;
|
|
19141
|
+
const promote = (t) => {
|
|
19142
|
+
if (t.kind === "primitive" && t.type === "string" && !t.format) return {
|
|
19143
|
+
kind: "primitive",
|
|
19144
|
+
type: "string",
|
|
19145
|
+
format: "date-time"
|
|
19146
|
+
};
|
|
19147
|
+
if (t.kind === "nullable") return {
|
|
19148
|
+
kind: "nullable",
|
|
19149
|
+
inner: promote(t.inner)
|
|
19150
|
+
};
|
|
19151
|
+
return t;
|
|
19152
|
+
};
|
|
19153
|
+
return promote(type);
|
|
19154
|
+
}
|
|
19155
|
+
/**
|
|
18989
19156
|
* Generate one JUnit 5 + WireMock test class per API mount group, plus a
|
|
18990
19157
|
* cross-cutting model round-trip test.
|
|
18991
19158
|
*
|
|
@@ -19120,10 +19287,11 @@ function buildOperationTest(op, resolved, ctx) {
|
|
|
19120
19287
|
}
|
|
19121
19288
|
for (const qp of sortedQuery) {
|
|
19122
19289
|
if (!qp.required) break;
|
|
19123
|
-
const
|
|
19290
|
+
const promotedType = promoteIso8601TypeRef(qp.type, qp.description);
|
|
19291
|
+
const val = synthValue(promotedType, ctx, imports);
|
|
19124
19292
|
if (val === null) return null;
|
|
19125
19293
|
argParts.push(val);
|
|
19126
|
-
const regex = queryValueRegexFor(
|
|
19294
|
+
const regex = queryValueRegexFor(promotedType);
|
|
19127
19295
|
if (regex !== null) requiredQueryAssertions.push({
|
|
19128
19296
|
name: qp.name,
|
|
19129
19297
|
valueRegex: regex
|
|
@@ -19143,10 +19311,11 @@ function buildOperationTest(op, resolved, ctx) {
|
|
|
19143
19311
|
for (const bf of sortedBody) {
|
|
19144
19312
|
if (sharedQueryBodyParams.has(bf.name)) continue;
|
|
19145
19313
|
if (!bf.required) break;
|
|
19146
|
-
const
|
|
19314
|
+
const promotedType = promoteIso8601TypeRef(bf.type, bf.description);
|
|
19315
|
+
const val = synthValue(promotedType, ctx, imports);
|
|
19147
19316
|
if (val === null) return null;
|
|
19148
19317
|
argParts.push(val);
|
|
19149
|
-
if (isScalarBodyField(
|
|
19318
|
+
if (isScalarBodyField(promotedType)) requiredBodyPaths.push(bf.name);
|
|
19150
19319
|
}
|
|
19151
19320
|
}
|
|
19152
19321
|
const plan2 = plan;
|
|
@@ -19264,7 +19433,7 @@ function buildWrapperTest(op, wrapper, ctx) {
|
|
|
19264
19433
|
argParts.push(ktStringLiteral("sample-arg"));
|
|
19265
19434
|
continue;
|
|
19266
19435
|
}
|
|
19267
|
-
const val = synthValue(rp.field.type, ctx, imports);
|
|
19436
|
+
const val = synthValue(promoteIso8601TypeRef(rp.field.type, rp.field.description), ctx, imports);
|
|
19268
19437
|
if (val === null) return null;
|
|
19269
19438
|
argParts.push(val);
|
|
19270
19439
|
}
|
|
@@ -22300,4 +22469,4 @@ const workosEmittersPlugin = {
|
|
|
22300
22469
|
//#endregion
|
|
22301
22470
|
export { nodeEmitter as _, rustExtractor as a, pythonExtractor as c, rubyEmitter as d, kotlinEmitter as f, pythonEmitter as g, phpEmitter as h, kotlinExtractor as i, rubyExtractor as l, goEmitter as m, elixirExtractor as n, goExtractor as o, dotnetEmitter as p, dotnetExtractor as r, phpExtractor as s, workosEmittersPlugin as t, nodeExtractor as u };
|
|
22302
22471
|
|
|
22303
|
-
//# sourceMappingURL=plugin-
|
|
22472
|
+
//# sourceMappingURL=plugin-CeNME04k.mjs.map
|