@workos/oagen-emitters 0.7.1 → 0.7.3
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 +14 -0
- package/dist/index.mjs +1 -1
- package/dist/{plugin-h8Onp2Ma.mjs → plugin-BoTAX4nl.mjs} +245 -67
- package/dist/plugin-BoTAX4nl.mjs.map +1 -0
- package/dist/plugin.mjs +1 -1
- package/package.json +1 -1
- package/src/kotlin/path-expression.ts +51 -0
- package/src/kotlin/resources.ts +9 -20
- package/src/kotlin/wrappers.ts +3 -14
- package/src/node/path-expression.ts +37 -0
- package/src/node/resources.ts +2 -2
- package/src/node/wrappers.ts +2 -2
- package/src/php/models.ts +37 -2
- package/src/php/path-expression.ts +52 -0
- package/src/php/resources.ts +4 -11
- package/src/php/wrappers.ts +3 -5
- package/src/python/path-expression.ts +52 -0
- package/src/python/resources.ts +17 -14
- package/src/python/wrappers.ts +2 -10
- package/src/shared/path-template.ts +64 -0
- package/test/php/resources.test.ts +1 -1
- package/test/python/resources.test.ts +2 -1
- package/test/shared/path-template.test.ts +70 -0
- package/dist/plugin-h8Onp2Ma.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.3](https://github.com/workos/oagen-emitters/compare/v0.7.2...v0.7.3) (2026-05-02)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* url-encode path parameters in php/node/python/kotlin emitters ([#75](https://github.com/workos/oagen-emitters/issues/75)) ([34c08fc](https://github.com/workos/oagen-emitters/commit/34c08fc10510db53f1f989edab5b4d0cead15aa9))
|
|
9
|
+
|
|
10
|
+
## [0.7.2](https://github.com/workos/oagen-emitters/compare/v0.7.1...v0.7.2) (2026-05-01)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **php:** wrap degenerate-union models in fromArray/toArray ([#72](https://github.com/workos/oagen-emitters/issues/72)) ([053d34a](https://github.com/workos/oagen-emitters/commit/053d34adcbbecbed6793c54c4fd48a03aef97f21))
|
|
16
|
+
|
|
3
17
|
## [0.7.1](https://github.com/workos/oagen-emitters/compare/v0.7.0...v0.7.1) (2026-05-01)
|
|
4
18
|
|
|
5
19
|
|
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-BoTAX4nl.mjs";
|
|
2
2
|
export { dotnetEmitter, dotnetExtractor, elixirExtractor, goEmitter, goExtractor, kotlinEmitter, kotlinExtractor, nodeEmitter, nodeExtractor, phpEmitter, phpExtractor, pythonEmitter, pythonExtractor, rubyEmitter, rubyExtractor, rustExtractor, workosEmittersPlugin };
|
|
@@ -4475,6 +4475,79 @@ function formatWrapperDescription(name) {
|
|
|
4475
4475
|
return name.split("_").map((w, i) => i === 0 ? w.charAt(0).toUpperCase() + w.slice(1) : w).join(" ");
|
|
4476
4476
|
}
|
|
4477
4477
|
//#endregion
|
|
4478
|
+
//#region src/shared/path-template.ts
|
|
4479
|
+
/**
|
|
4480
|
+
* Parse an OpenAPI path template into an ordered list of literal and
|
|
4481
|
+
* parameter segments. Adjacent literals are coalesced into a single segment
|
|
4482
|
+
* (the only way two literals can be adjacent is if the input had `{}{}`
|
|
4483
|
+
* which is malformed; we still handle it deterministically).
|
|
4484
|
+
*
|
|
4485
|
+
* Examples:
|
|
4486
|
+
* "/orgs/{id}/users/{uid}" → [
|
|
4487
|
+
* { kind: 'literal', value: '/orgs/' },
|
|
4488
|
+
* { kind: 'param', name: 'id' },
|
|
4489
|
+
* { kind: 'literal', value: '/users/' },
|
|
4490
|
+
* { kind: 'param', name: 'uid' },
|
|
4491
|
+
* ]
|
|
4492
|
+
* "/health" → [{ kind: 'literal', value: '/health' }]
|
|
4493
|
+
* "" → []
|
|
4494
|
+
*/
|
|
4495
|
+
function parsePathTemplate(path, options = {}) {
|
|
4496
|
+
const normalized = options.stripLeadingSlash && path.startsWith("/") ? path.slice(1) : path;
|
|
4497
|
+
if (normalized === "") return [];
|
|
4498
|
+
const segments = [];
|
|
4499
|
+
const re = /\{([^{}]+)\}/g;
|
|
4500
|
+
let cursor = 0;
|
|
4501
|
+
let m;
|
|
4502
|
+
while ((m = re.exec(normalized)) !== null) {
|
|
4503
|
+
if (m.index > cursor) segments.push({
|
|
4504
|
+
kind: "literal",
|
|
4505
|
+
value: normalized.slice(cursor, m.index)
|
|
4506
|
+
});
|
|
4507
|
+
segments.push({
|
|
4508
|
+
kind: "param",
|
|
4509
|
+
name: m[1]
|
|
4510
|
+
});
|
|
4511
|
+
cursor = m.index + m[0].length;
|
|
4512
|
+
}
|
|
4513
|
+
if (cursor < normalized.length) segments.push({
|
|
4514
|
+
kind: "literal",
|
|
4515
|
+
value: normalized.slice(cursor)
|
|
4516
|
+
});
|
|
4517
|
+
return segments;
|
|
4518
|
+
}
|
|
4519
|
+
/** True when at least one segment is a parameter placeholder. */
|
|
4520
|
+
function hasPathParams(segments) {
|
|
4521
|
+
return segments.some((s) => s.kind === "param");
|
|
4522
|
+
}
|
|
4523
|
+
//#endregion
|
|
4524
|
+
//#region src/node/path-expression.ts
|
|
4525
|
+
/**
|
|
4526
|
+
* Build the TypeScript expression that the SDK passes as the request path.
|
|
4527
|
+
*
|
|
4528
|
+
* Every {paramName} placeholder becomes `${encodeURIComponent(name)}` inside a
|
|
4529
|
+
* template literal. encodeURIComponent is used (not encodeURI) because we want
|
|
4530
|
+
* "/" to be encoded too — otherwise a caller-supplied id containing "../" can
|
|
4531
|
+
* be normalized by the underlying HTTP transport (libcurl, fetch, etc.) into
|
|
4532
|
+
* a different endpoint of the WorkOS API while still authenticated with the
|
|
4533
|
+
* application's API key.
|
|
4534
|
+
*
|
|
4535
|
+
* "/orgs" → `'orgs'`
|
|
4536
|
+
* "/orgs/{id}" → `` `orgs/${encodeURIComponent(id)}` ``
|
|
4537
|
+
* "/orgs/{id}/foo" → `` `orgs/${encodeURIComponent(id)}/foo` ``
|
|
4538
|
+
*/
|
|
4539
|
+
function buildNodePathExpression(rawPath) {
|
|
4540
|
+
const segments = parsePathTemplate(rawPath);
|
|
4541
|
+
if (!hasPathParams(segments)) return `'${rawPath}'`;
|
|
4542
|
+
let body = "";
|
|
4543
|
+
for (const seg of segments) body += renderSegment(seg);
|
|
4544
|
+
return `\`${body}\``;
|
|
4545
|
+
}
|
|
4546
|
+
function renderSegment(seg) {
|
|
4547
|
+
if (seg.kind === "literal") return seg.value.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
4548
|
+
return `\${encodeURIComponent(${fieldName$5(seg.name)})}`;
|
|
4549
|
+
}
|
|
4550
|
+
//#endregion
|
|
4478
4551
|
//#region src/node/wrappers.ts
|
|
4479
4552
|
/**
|
|
4480
4553
|
* Generate TypeScript wrapper method lines for union split operations.
|
|
@@ -4564,8 +4637,7 @@ function emitWrapperMethod$6(lines, resolvedOp, wrapper, ctx) {
|
|
|
4564
4637
|
}
|
|
4565
4638
|
/** Build a path template string from an Operation. */
|
|
4566
4639
|
function buildPathStr$1(op) {
|
|
4567
|
-
|
|
4568
|
-
return interpolated.includes("${") ? `\`${interpolated}\`` : `'${op.path}'`;
|
|
4640
|
+
return buildNodePathExpression(op.path);
|
|
4569
4641
|
}
|
|
4570
4642
|
/** Convert a JS value to a TypeScript literal. */
|
|
4571
4643
|
function tsLiteral$1(value) {
|
|
@@ -5365,8 +5437,7 @@ function renderQueryExpr(queryParams) {
|
|
|
5365
5437
|
return `options ? { ${parts.join(", ")} } : undefined`;
|
|
5366
5438
|
}
|
|
5367
5439
|
function buildPathStr(op) {
|
|
5368
|
-
|
|
5369
|
-
return interpolated.includes("${") ? `\`${interpolated}\`` : `'${op.path}'`;
|
|
5440
|
+
return buildNodePathExpression(op.path);
|
|
5370
5441
|
}
|
|
5371
5442
|
function buildPathParams(op, specEnumNames) {
|
|
5372
5443
|
const declaredNames = new Set(op.pathParams.map((p) => fieldName$5(p.name)));
|
|
@@ -7638,6 +7709,46 @@ function buildRecursiveHashMap$1(models, enums) {
|
|
|
7638
7709
|
return hashCache;
|
|
7639
7710
|
}
|
|
7640
7711
|
//#endregion
|
|
7712
|
+
//#region src/python/path-expression.ts
|
|
7713
|
+
/**
|
|
7714
|
+
* Build the Python f-string that the SDK passes to the request layer.
|
|
7715
|
+
*
|
|
7716
|
+
* Every {paramName} placeholder is wrapped in
|
|
7717
|
+
* `urllib.parse.quote(str(...), safe="")` so that an unencoded "/" or "../"
|
|
7718
|
+
* in a caller-supplied id cannot be normalized by the underlying HTTP
|
|
7719
|
+
* transport into a different endpoint of the WorkOS API while still
|
|
7720
|
+
* authenticated with the application's API key. `safe=""` is critical:
|
|
7721
|
+
* the stdlib default of `safe="/"` does NOT encode "/" and would leave the
|
|
7722
|
+
* traversal vector open.
|
|
7723
|
+
*
|
|
7724
|
+
* Generated files using this helper must import `quote` (e.g.
|
|
7725
|
+
* `from urllib.parse import quote`).
|
|
7726
|
+
*
|
|
7727
|
+
* "/orgs" → `"orgs"`
|
|
7728
|
+
* "/orgs/{id}" → `f"orgs/{quote(str(id), safe='')}"`
|
|
7729
|
+
* "/orgs/{id}" with id ∈ enums → `f"orgs/{quote(str(enum_value(id)), safe='')}"`
|
|
7730
|
+
*/
|
|
7731
|
+
function buildPythonPathExpression(rawPath, options = {}) {
|
|
7732
|
+
const segments = parsePathTemplate(rawPath, { stripLeadingSlash: true });
|
|
7733
|
+
if (segments.length === 0) return "\"\"";
|
|
7734
|
+
if (!hasPathParams(segments)) {
|
|
7735
|
+
const literal = segments[0].value;
|
|
7736
|
+
return `"${escapePyDoubleQuoted(literal)}"`;
|
|
7737
|
+
}
|
|
7738
|
+
const enums = options.enumParams;
|
|
7739
|
+
let body = "";
|
|
7740
|
+
for (const seg of segments) if (seg.kind === "literal") body += escapePyDoubleQuoted(seg.value);
|
|
7741
|
+
else {
|
|
7742
|
+
const varName = fieldName$4(seg.name);
|
|
7743
|
+
const inner = enums?.has(seg.name) ? `enum_value(${varName})` : varName;
|
|
7744
|
+
body += `{quote(str(${inner}), safe='')}`;
|
|
7745
|
+
}
|
|
7746
|
+
return `f"${body}"`;
|
|
7747
|
+
}
|
|
7748
|
+
function escapePyDoubleQuoted(literal) {
|
|
7749
|
+
return literal.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\{/g, "{{").replace(/\}/g, "}}");
|
|
7750
|
+
}
|
|
7751
|
+
//#endregion
|
|
7641
7752
|
//#region src/python/wrappers.ts
|
|
7642
7753
|
/**
|
|
7643
7754
|
* Generate Python wrapper method lines for split operations.
|
|
@@ -7707,12 +7818,7 @@ function emitWrapperMethod$5(lines, resolvedOp, wrapper, ctx, isAsync) {
|
|
|
7707
7818
|
lines.push(` if ${pyName} is not None:`);
|
|
7708
7819
|
lines.push(` body["${paramName}"] = ${pyName}`);
|
|
7709
7820
|
}
|
|
7710
|
-
|
|
7711
|
-
if (op.pathParams.length > 0) {
|
|
7712
|
-
let path = op.path.replace(/^\//, "");
|
|
7713
|
-
for (const p of op.pathParams) path = path.replace(`{${p.name}}`, `{${fieldName$4(p.name)}}`);
|
|
7714
|
-
pathExpr = `f"${path}"`;
|
|
7715
|
-
} else pathExpr = `"${op.path.replace(/^\//, "")}"`;
|
|
7821
|
+
const pathExpr = buildPythonPathExpression(op.path);
|
|
7716
7822
|
const awaitPrefix = isAsync ? "await " : "";
|
|
7717
7823
|
lines.push("");
|
|
7718
7824
|
if (wrapper.responseModelName) {
|
|
@@ -8397,6 +8503,7 @@ function generateResources$5(services, ctx) {
|
|
|
8397
8503
|
lines.push("from __future__ import annotations");
|
|
8398
8504
|
lines.push("");
|
|
8399
8505
|
lines.push("from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Type, Union, cast");
|
|
8506
|
+
if (allOperations.some((op) => op.pathParams.length > 0) || allOperations.some((op) => /\{[^{}]+\}/.test(op.path))) lines.push("from urllib.parse import quote");
|
|
8400
8507
|
lines.push("");
|
|
8401
8508
|
lines.push("if TYPE_CHECKING:");
|
|
8402
8509
|
lines.push(` from ${importPrefix}_client import AsyncWorkOSClient, WorkOSClient`);
|
|
@@ -8699,15 +8806,12 @@ function buildErrorRaisesBlock(op) {
|
|
|
8699
8806
|
}
|
|
8700
8807
|
/**
|
|
8701
8808
|
* Build a Python f-string path expression from an operation path.
|
|
8702
|
-
* E.g., "/organizations/{id}" -> f"organizations/{id}"
|
|
8809
|
+
* E.g., "/organizations/{id}" -> f"organizations/{quote(str(id), safe='')}"
|
|
8703
8810
|
*/
|
|
8704
8811
|
function buildPathString$1(op) {
|
|
8705
|
-
const
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
for (const param of op.pathParams) if (param.type.kind === "enum" || param.type.kind === "nullable" && param.type.inner?.kind === "enum") fPath = fPath.replace(`{${param.name}}`, `{enum_value(${fieldName$4(param.name)})}`);
|
|
8709
|
-
else fPath = fPath.replace(`{${param.name}}`, `{${fieldName$4(param.name)}}`);
|
|
8710
|
-
return `f"${fPath}"`;
|
|
8812
|
+
const enumParams = /* @__PURE__ */ new Set();
|
|
8813
|
+
for (const p of op.pathParams) if (p.type.kind === "enum" || p.type.kind === "nullable" && p.type.inner?.kind === "enum") enumParams.add(p.name);
|
|
8814
|
+
return buildPythonPathExpression(op.path, { enumParams });
|
|
8711
8815
|
}
|
|
8712
8816
|
//#endregion
|
|
8713
8817
|
//#region src/shared/non-spec-services.ts
|
|
@@ -10624,6 +10728,28 @@ function generateModels$4(models, ctx) {
|
|
|
10624
10728
|
return files;
|
|
10625
10729
|
}
|
|
10626
10730
|
/**
|
|
10731
|
+
* Resolve a degenerate union to a single TypeRef when possible.
|
|
10732
|
+
* - allOf: PHP collapses to the first variant (mirrors `mapTypeRef`).
|
|
10733
|
+
* - oneOf/anyOf where every variant has the same generated PHP type: collapse
|
|
10734
|
+
* to that variant (e.g. discriminated unions whose branches the IR pinned to
|
|
10735
|
+
* one model name).
|
|
10736
|
+
* Returns null when the union is genuinely polymorphic.
|
|
10737
|
+
*/
|
|
10738
|
+
function resolveDegenerateUnion(ref) {
|
|
10739
|
+
if (ref.kind !== "union") return null;
|
|
10740
|
+
if (ref.compositionKind === "allOf") return ref.variants[0] ?? null;
|
|
10741
|
+
if (ref.variants.length === 0) return null;
|
|
10742
|
+
const signature = (v) => {
|
|
10743
|
+
if (v.kind === "model") return `model:${v.name}`;
|
|
10744
|
+
if (v.kind === "enum") return `enum:${v.name}`;
|
|
10745
|
+
return `kind:${v.kind}`;
|
|
10746
|
+
};
|
|
10747
|
+
const first = ref.variants[0];
|
|
10748
|
+
const firstSig = signature(first);
|
|
10749
|
+
for (const v of ref.variants) if (signature(v) !== firstSig) return null;
|
|
10750
|
+
return first;
|
|
10751
|
+
}
|
|
10752
|
+
/**
|
|
10627
10753
|
* Generate the fromArray accessor expression for a field.
|
|
10628
10754
|
*/
|
|
10629
10755
|
function generateFromArrayAccessor(ref, wireName, required) {
|
|
@@ -10654,7 +10780,11 @@ function generateFromArrayValue(ref, accessor) {
|
|
|
10654
10780
|
if (ref.items.kind === "primitive" && ref.items.format === "date-time") return `array_map(fn ($item) => new \\DateTimeImmutable($item), ${accessor})`;
|
|
10655
10781
|
return accessor;
|
|
10656
10782
|
case "nullable": return generateFromArrayValue(ref.inner, accessor);
|
|
10657
|
-
case "union":
|
|
10783
|
+
case "union": {
|
|
10784
|
+
const resolved = resolveDegenerateUnion(ref);
|
|
10785
|
+
if (resolved) return generateFromArrayValue(resolved, accessor);
|
|
10786
|
+
return accessor;
|
|
10787
|
+
}
|
|
10658
10788
|
case "map": return accessor;
|
|
10659
10789
|
case "literal": return accessor;
|
|
10660
10790
|
}
|
|
@@ -10676,6 +10806,10 @@ function isComplexType(ref) {
|
|
|
10676
10806
|
case "enum": return true;
|
|
10677
10807
|
case "array": return isComplexType(ref.items);
|
|
10678
10808
|
case "nullable": return isComplexType(ref.inner);
|
|
10809
|
+
case "union": {
|
|
10810
|
+
const resolved = resolveDegenerateUnion(ref);
|
|
10811
|
+
return resolved ? isComplexType(resolved) : false;
|
|
10812
|
+
}
|
|
10679
10813
|
default: return false;
|
|
10680
10814
|
}
|
|
10681
10815
|
}
|
|
@@ -10697,7 +10831,11 @@ function generateToArrayValue(ref, accessor, nullable = false) {
|
|
|
10697
10831
|
return accessor;
|
|
10698
10832
|
case "nullable": return generateToArrayValue(ref.inner, accessor, true);
|
|
10699
10833
|
case "map": return accessor;
|
|
10700
|
-
case "union":
|
|
10834
|
+
case "union": {
|
|
10835
|
+
const resolved = resolveDegenerateUnion(ref);
|
|
10836
|
+
if (resolved) return generateToArrayValue(resolved, accessor, nullable);
|
|
10837
|
+
return accessor;
|
|
10838
|
+
}
|
|
10701
10839
|
case "literal": return accessor;
|
|
10702
10840
|
}
|
|
10703
10841
|
}
|
|
@@ -10760,6 +10898,39 @@ function generateEnums$4(enums, ctx) {
|
|
|
10760
10898
|
return files;
|
|
10761
10899
|
}
|
|
10762
10900
|
//#endregion
|
|
10901
|
+
//#region src/php/path-expression.ts
|
|
10902
|
+
/**
|
|
10903
|
+
* Build the PHP expression that the SDK passes to HttpClient as `path:`.
|
|
10904
|
+
*
|
|
10905
|
+
* Concatenation, not interpolation: PHP does not allow function calls inside
|
|
10906
|
+
* "..." strings, and every parameter must be wrapped in `rawurlencode(...)` so
|
|
10907
|
+
* that an unencoded "../" in a caller-supplied id cannot be normalized by
|
|
10908
|
+
* libcurl into a different endpoint of the WorkOS API while still
|
|
10909
|
+
* authenticated with the application's API key.
|
|
10910
|
+
*
|
|
10911
|
+
* "/orgs" → `'orgs'`
|
|
10912
|
+
* "/orgs/{id}" → `'orgs/' . rawurlencode($id)`
|
|
10913
|
+
* "/orgs/{id}/users" → `'orgs/' . rawurlencode($id) . '/users'`
|
|
10914
|
+
* "/orgs/{id}" with id ∈ valueAccessorParams → `'orgs/' . rawurlencode($id->value)`
|
|
10915
|
+
*/
|
|
10916
|
+
function buildPhpPathExpression(rawPath, options = {}) {
|
|
10917
|
+
const segments = parsePathTemplate(rawPath, { stripLeadingSlash: true });
|
|
10918
|
+
if (segments.length === 0) return "''";
|
|
10919
|
+
if (!hasPathParams(segments)) return phpSingleQuoted(segments[0].value);
|
|
10920
|
+
const valueAccessor = options.valueAccessorParams;
|
|
10921
|
+
const parts = [];
|
|
10922
|
+
for (const seg of segments) if (seg.kind === "literal") parts.push(phpSingleQuoted(seg.value));
|
|
10923
|
+
else {
|
|
10924
|
+
const varName = fieldName$3(seg.name);
|
|
10925
|
+
const accessor = valueAccessor?.has(seg.name) ? `$${varName}->value` : `$${varName}`;
|
|
10926
|
+
parts.push(`rawurlencode(${accessor})`);
|
|
10927
|
+
}
|
|
10928
|
+
return parts.join(" . ");
|
|
10929
|
+
}
|
|
10930
|
+
function phpSingleQuoted(literal) {
|
|
10931
|
+
return `'${literal.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
10932
|
+
}
|
|
10933
|
+
//#endregion
|
|
10763
10934
|
//#region src/php/wrappers.ts
|
|
10764
10935
|
/**
|
|
10765
10936
|
* Generate PHP wrapper methods for split union operations.
|
|
@@ -10819,14 +10990,11 @@ function emitWrapperMethod$4(lines, resolvedOp, wrapper, ctx) {
|
|
|
10819
10990
|
lines.push(` $body['${clientField}'] = ${clientExpr};`);
|
|
10820
10991
|
}
|
|
10821
10992
|
const httpMethod = op.httpMethod.toUpperCase();
|
|
10822
|
-
|
|
10823
|
-
const hasInterpolation = /\{[^}]+\}/.test(path);
|
|
10824
|
-
path = path.replace(/\{([^}]+)\}/g, (_match, param) => `{$${fieldName$3(param)}}`);
|
|
10825
|
-
const pathQuote = hasInterpolation ? "\"" : "'";
|
|
10993
|
+
const pathExpr = buildPhpPathExpression(op.path);
|
|
10826
10994
|
lines.push("");
|
|
10827
10995
|
lines.push(" $response = $this->client->request(");
|
|
10828
10996
|
lines.push(` method: '${httpMethod}',`);
|
|
10829
|
-
lines.push(` path: ${
|
|
10997
|
+
lines.push(` path: ${pathExpr},`);
|
|
10830
10998
|
lines.push(" body: $body,");
|
|
10831
10999
|
lines.push(" options: $options,");
|
|
10832
11000
|
lines.push(" );");
|
|
@@ -11311,16 +11479,9 @@ function buildBodyParamMap(op, bodyModel) {
|
|
|
11311
11479
|
return map;
|
|
11312
11480
|
}
|
|
11313
11481
|
function buildPathString(op) {
|
|
11314
|
-
|
|
11315
|
-
|
|
11316
|
-
|
|
11317
|
-
for (const p of op.pathParams) {
|
|
11318
|
-
const phpName = fieldName$3(p.name);
|
|
11319
|
-
const isEnum = p.type.kind === "enum" || p.type.kind === "model";
|
|
11320
|
-
paramExprs.set(p.name, isEnum ? `{$${phpName}->value}` : `{$${phpName}}`);
|
|
11321
|
-
}
|
|
11322
|
-
path = path.replace(/\{([^}]+)\}/g, (_match, param) => paramExprs.get(param) ?? `{$${fieldName$3(param)}}`);
|
|
11323
|
-
return `"${path}"`;
|
|
11482
|
+
const valueAccessor = /* @__PURE__ */ new Set();
|
|
11483
|
+
for (const p of op.pathParams) if (p.type.kind === "enum" || p.type.kind === "model") valueAccessor.add(p.name);
|
|
11484
|
+
return buildPhpPathExpression(op.path, { valueAccessorParams: valueAccessor });
|
|
11324
11485
|
}
|
|
11325
11486
|
function isEnumType(ref) {
|
|
11326
11487
|
if (ref.kind === "enum") return true;
|
|
@@ -13224,7 +13385,7 @@ function generateMethod$1(serviceType, mountName, method, op, plan, _ctx, resolv
|
|
|
13224
13385
|
if (paramsType) params.push(`params ${paramsType}`);
|
|
13225
13386
|
params.push("opts ...RequestOption");
|
|
13226
13387
|
lines.push(`func (s *${serviceType}) ${method}(${params.join(", ")}) ${returnType} {`);
|
|
13227
|
-
const pathExpr = buildPathExpr$
|
|
13388
|
+
const pathExpr = buildPathExpr$1(op);
|
|
13228
13389
|
if (isUrlBuilder) {
|
|
13229
13390
|
emitUrlBuilderMethod(lines, op, pathExpr, resolvedOp, paramsType);
|
|
13230
13391
|
lines.push("}");
|
|
@@ -13523,7 +13684,7 @@ function needsStringsImport(operations, resolvedLookup) {
|
|
|
13523
13684
|
}
|
|
13524
13685
|
return false;
|
|
13525
13686
|
}
|
|
13526
|
-
function buildPathExpr$
|
|
13687
|
+
function buildPathExpr$1(op) {
|
|
13527
13688
|
if (op.pathParams.length === 0) return `"${op.path}"`;
|
|
13528
13689
|
let fmtStr = op.path;
|
|
13529
13690
|
const args = [];
|
|
@@ -15967,7 +16128,7 @@ function generateMethod(_serviceType, mountName, method, methodStem, op, plan, c
|
|
|
15967
16128
|
for (const field of inferFromClient) if (field === "client_id") lines.push(` options.${fieldName$1(field)} = this.Client.RequireClientId();`);
|
|
15968
16129
|
else lines.push(` options.${fieldName$1(field)} = this.Client.${clientFieldExpression$1(field)} ?? string.Empty;`);
|
|
15969
16130
|
}
|
|
15970
|
-
const pathExpr = buildPathExpr
|
|
16131
|
+
const pathExpr = buildPathExpr(op);
|
|
15971
16132
|
const needsInlineRequest = isUrlBuilder || hasBearerOverride && !!bearerParamName || hasGroups;
|
|
15972
16133
|
const optionsArg = optionsClass ? "options" : "null";
|
|
15973
16134
|
if (needsInlineRequest) {
|
|
@@ -16031,7 +16192,7 @@ function generateAutoPagingMethod(mountName, method, methodStem, op, plan, ctx,
|
|
|
16031
16192
|
params.push("CancellationToken cancellationToken = default");
|
|
16032
16193
|
lines.push(` public virtual IAsyncEnumerable<${itemType}> ${methodStem}AutoPagingAsync(${params.join(", ")})`);
|
|
16033
16194
|
lines.push(" {");
|
|
16034
|
-
const pathExpr = buildPathExpr
|
|
16195
|
+
const pathExpr = buildPathExpr(op);
|
|
16035
16196
|
const optionsArg = optionsClass ? "options" : "null";
|
|
16036
16197
|
lines.push(` return this.ListAutoPagingAsync<${itemType}>(${pathExpr}, ${optionsArg}, requestOptions, cancellationToken);`);
|
|
16037
16198
|
lines.push(" }");
|
|
@@ -16055,7 +16216,7 @@ function optionsClassName(mountName, method) {
|
|
|
16055
16216
|
if (methodStem.startsWith(prefix)) return `${methodStem}Options`;
|
|
16056
16217
|
return `${prefix}${methodStem}Options`;
|
|
16057
16218
|
}
|
|
16058
|
-
function buildPathExpr
|
|
16219
|
+
function buildPathExpr(op) {
|
|
16059
16220
|
if (op.pathParams.length === 0) return `"${op.path}"`;
|
|
16060
16221
|
let interpolated = op.path;
|
|
16061
16222
|
for (const p of sortPathParamsByTemplateOrder$1(op)) interpolated = interpolated.replace(`{${p.name}}`, `{Uri.EscapeDataString(${localName(p.name)})}`);
|
|
@@ -17834,6 +17995,45 @@ function structuralHash(model) {
|
|
|
17834
17995
|
return model.fields.map((f) => `${f.name}:${JSON.stringify(normalizeTypeForHash(f.type))}:${f.required}`).sort().join("|");
|
|
17835
17996
|
}
|
|
17836
17997
|
//#endregion
|
|
17998
|
+
//#region src/kotlin/path-expression.ts
|
|
17999
|
+
/**
|
|
18000
|
+
* The fully-qualified runtime helper that the generated code calls. Kotlin
|
|
18001
|
+
* doesn't ship a path-segment URL encoder out of the box (java.net.URLEncoder
|
|
18002
|
+
* is form-encoding — it encodes space as "+", which is wrong for path
|
|
18003
|
+
* segments). The runtime helper lives in workos-kotlin at
|
|
18004
|
+
* com.workos.common.http.encodePathSegment.
|
|
18005
|
+
*/
|
|
18006
|
+
const KOTLIN_PATH_ENCODE_IMPORT = "com.workos.common.http.encodePathSegment";
|
|
18007
|
+
/**
|
|
18008
|
+
* Build the Kotlin string-template that the SDK passes as the request path.
|
|
18009
|
+
*
|
|
18010
|
+
* Every {paramName} placeholder is wrapped in `encodePathSegment(...)` so a
|
|
18011
|
+
* caller-supplied id containing "../" cannot be normalized by the underlying
|
|
18012
|
+
* HTTP transport into a different endpoint of the WorkOS API while still
|
|
18013
|
+
* authenticated with the application's API key.
|
|
18014
|
+
*
|
|
18015
|
+
* "/orgs" → `"orgs"`
|
|
18016
|
+
* "/orgs/{id}" → `"orgs/${encodePathSegment(id)}"`
|
|
18017
|
+
* "/orgs/{id}/foo" → `"orgs/${encodePathSegment(id)}/foo"`
|
|
18018
|
+
*/
|
|
18019
|
+
function buildKotlinPathExpression(rawPath) {
|
|
18020
|
+
const segments = parsePathTemplate(rawPath);
|
|
18021
|
+
if (!hasPathParams(segments)) return {
|
|
18022
|
+
expression: ktLiteral(rawPath),
|
|
18023
|
+
requiresEncodeImport: false
|
|
18024
|
+
};
|
|
18025
|
+
let body = "";
|
|
18026
|
+
for (const seg of segments) if (seg.kind === "literal") body += escapeKotlinStringLiteral(seg.value);
|
|
18027
|
+
else body += `\${encodePathSegment(${propertyName(seg.name)})}`;
|
|
18028
|
+
return {
|
|
18029
|
+
expression: `"${body}"`,
|
|
18030
|
+
requiresEncodeImport: true
|
|
18031
|
+
};
|
|
18032
|
+
}
|
|
18033
|
+
function escapeKotlinStringLiteral(literal) {
|
|
18034
|
+
return literal.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\$/g, "\\$");
|
|
18035
|
+
}
|
|
18036
|
+
//#endregion
|
|
17837
18037
|
//#region src/kotlin/wrappers.ts
|
|
17838
18038
|
/**
|
|
17839
18039
|
* Emit Kotlin wrapper methods for a union-split operation. Each wrapper
|
|
@@ -17919,7 +18119,7 @@ function emitWrapperMethod$1(resolvedOp, wrapper, ctx) {
|
|
|
17919
18119
|
}
|
|
17920
18120
|
lines.push(` )`);
|
|
17921
18121
|
} else lines.push(` val body = linkedMapOf<String, Any?>()`);
|
|
17922
|
-
const pathExpr =
|
|
18122
|
+
const pathExpr = buildKotlinPathExpression(op.path).expression;
|
|
17923
18123
|
const httpMethod = op.httpMethod.toUpperCase();
|
|
17924
18124
|
lines.push(` val config =`);
|
|
17925
18125
|
lines.push(` RequestConfig(`);
|
|
@@ -17937,17 +18137,6 @@ function emitWrapperMethod$1(resolvedOp, wrapper, ctx) {
|
|
|
17937
18137
|
function escapeKdoc$1(s) {
|
|
17938
18138
|
return s.replace(/\*\//g, "*/");
|
|
17939
18139
|
}
|
|
17940
|
-
function buildPathExpr(path, pathParams) {
|
|
17941
|
-
if (pathParams.length === 0) return ktLiteral(path);
|
|
17942
|
-
let result = path;
|
|
17943
|
-
for (const pp of pathParams) {
|
|
17944
|
-
const placeholder = `{${pp.name}}`;
|
|
17945
|
-
const propName = propertyName(pp.name);
|
|
17946
|
-
const replacement = /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(propName) ? `\$${propName}` : `\${${propName}}`;
|
|
17947
|
-
result = result.replaceAll(placeholder, replacement);
|
|
17948
|
-
}
|
|
17949
|
-
return `"${result.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
17950
|
-
}
|
|
17951
18140
|
//#endregion
|
|
17952
18141
|
//#region src/kotlin/overrides.ts
|
|
17953
18142
|
/**
|
|
@@ -18020,6 +18209,7 @@ function generateApiClass(mountName, operations, ctx, resolvedLookup) {
|
|
|
18020
18209
|
for (const rp of resolvedParams) if (rp.field) registerTypeImports(rp.field.type, imports, ctx);
|
|
18021
18210
|
}
|
|
18022
18211
|
imports.add("com.workos.common.http.bodyOf");
|
|
18212
|
+
if (/\{[^{}]+\}/.test(resolvedOp.operation.path)) imports.add(KOTLIN_PATH_ENCODE_IMPORT);
|
|
18023
18213
|
const wrapperLines = generateWrapperMethods$1(resolvedOp, ctx);
|
|
18024
18214
|
if (body.length > 0) body.push("");
|
|
18025
18215
|
for (const line of wrapperLines) body.push(line);
|
|
@@ -18182,7 +18372,9 @@ function renderMethod(_mountName, method, op, ctx, resolvedOp, imports) {
|
|
|
18182
18372
|
const specDeclaresBody = op.requestBody !== void 0;
|
|
18183
18373
|
const hasBody = methodAlwaysHasBody || specDeclaresBody && httpMethod !== "GET" || (httpMethod === "PUT" || httpMethod === "PATCH" || httpMethod === "POST" || httpMethod === "DELETE") && (Object.keys(defaults).length > 0 || inferFromClient.length > 0) && specDeclaresBody;
|
|
18184
18374
|
const appendDefaultsAsQuery = !hasBody && (Object.keys(defaults).length > 0 || inferFromClient.length > 0);
|
|
18185
|
-
const
|
|
18375
|
+
const pathBuilt = buildKotlinPathExpression(op.path);
|
|
18376
|
+
const pathExpr = pathBuilt.expression;
|
|
18377
|
+
if (pathBuilt.requiresEncodeImport) imports.add(KOTLIN_PATH_ENCODE_IMPORT);
|
|
18186
18378
|
if (op.path === "/user_management/authenticate" && httpMethod === "POST" && plan.responseModelName === "AuthenticateResponse") {
|
|
18187
18379
|
imports.add("com.workos.models.AuthenticateResponse");
|
|
18188
18380
|
const grantType = defaults.grant_type ?? "authorization_code";
|
|
@@ -18405,20 +18597,6 @@ function queryParamToString(type, varName) {
|
|
|
18405
18597
|
if (type.kind === "primitive" && type.type === "string") return varName;
|
|
18406
18598
|
return `${varName}.toString()`;
|
|
18407
18599
|
}
|
|
18408
|
-
function buildPathExpression(path, pathParams) {
|
|
18409
|
-
if (pathParams.length === 0) return ktLiteral(path);
|
|
18410
|
-
let result = path;
|
|
18411
|
-
for (const pp of pathParams) {
|
|
18412
|
-
const placeholder = `{${pp.name}}`;
|
|
18413
|
-
const propName = propertyName(pp.name);
|
|
18414
|
-
const replacement = isBareIdentifier(propName) ? `\$${propName}` : `\${${propName}}`;
|
|
18415
|
-
result = result.replaceAll(placeholder, replacement);
|
|
18416
|
-
}
|
|
18417
|
-
return `"${result.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
18418
|
-
}
|
|
18419
|
-
function isBareIdentifier(name) {
|
|
18420
|
-
return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name);
|
|
18421
|
-
}
|
|
18422
18600
|
function pickNamedQueryParam(sorted, name) {
|
|
18423
18601
|
const match = sorted.find((p) => p.name === name);
|
|
18424
18602
|
return match ? propertyName(match.name) : "null";
|
|
@@ -21975,4 +22153,4 @@ const workosEmittersPlugin = {
|
|
|
21975
22153
|
//#endregion
|
|
21976
22154
|
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 };
|
|
21977
22155
|
|
|
21978
|
-
//# sourceMappingURL=plugin-
|
|
22156
|
+
//# sourceMappingURL=plugin-BoTAX4nl.mjs.map
|