@workos/oagen-emitters 0.12.5 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/plugin.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { t as workosEmittersPlugin } from "./plugin-Ca9LUkWW.mjs";
1
+ import { t as workosEmittersPlugin } from "./plugin-BxVeu2v9.mjs";
2
2
  export { workosEmittersPlugin };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workos/oagen-emitters",
3
- "version": "0.12.5",
3
+ "version": "0.14.0",
4
4
  "description": "WorkOS' oagen emitters",
5
5
  "license": "MIT",
6
6
  "author": "WorkOS",
@@ -40,20 +40,20 @@
40
40
  "devDependencies": {
41
41
  "@commitlint/cli": "^21.0.1",
42
42
  "@commitlint/config-conventional": "^21.0.1",
43
- "@types/node": "^25.9.0",
43
+ "@types/node": "^25.9.1",
44
44
  "husky": "^9.1.7",
45
- "oxfmt": "^0.50.0",
46
- "oxlint": "^1.65.0",
45
+ "oxfmt": "^0.51.0",
46
+ "oxlint": "^1.66.0",
47
47
  "prettier": "^3.8.3",
48
48
  "tsdown": "^0.22.0",
49
- "tsx": "^4.22.2",
49
+ "tsx": "^4.22.3",
50
50
  "typescript": "^6.0.3",
51
- "vitest": "^4.1.6"
51
+ "vitest": "^4.1.7"
52
52
  },
53
53
  "engines": {
54
54
  "node": ">=24.10.0"
55
55
  },
56
56
  "dependencies": {
57
- "@workos/oagen": "^0.19.1"
57
+ "@workos/oagen": "^0.20.0"
58
58
  }
59
59
  }
@@ -1,5 +1,5 @@
1
1
  import type { ApiSpec, EmitterContext, GeneratedFile, Service } from '@workos/oagen';
2
- import { apiClassName, packageSegment, servicePropertyName } from './naming.js';
2
+ import { resolveApiClassName, packageSegment, servicePropertyName, buildExportedClassNameSet } from './naming.js';
3
3
  import { getMountTarget } from '../shared/resolved-ops.js';
4
4
 
5
5
  const KOTLIN_SRC_PREFIX = 'src/main/kotlin/';
@@ -23,8 +23,9 @@ export function generateClient(spec: ApiSpec, ctx: EmitterContext): GeneratedFil
23
23
 
24
24
  const imports = new Set<string>();
25
25
  const accessorLines: string[] = [];
26
+ const exportedClasses = buildExportedClassNameSet(ctx);
26
27
  for (const mount of targets) {
27
- const apiCls = apiClassName(mount);
28
+ const apiCls = resolveApiClassName(mount, exportedClasses);
28
29
  const fqn = `com.workos.${packageSegment(mount)}.${apiCls}`;
29
30
  imports.add(fqn);
30
31
  const prop = servicePropertyName(mount);
@@ -1,4 +1,8 @@
1
1
  import type { Operation, Service, EmitterContext, TypeRef } from '@workos/oagen';
2
+ import {
3
+ buildExportedClassNameSet as buildExportedClassNameSetShared,
4
+ resolveServiceTarget as resolveServiceTargetShared,
5
+ } from '../shared/service-name-collision.js';
2
6
  import { toPascalCase, toCamelCase, toSnakeCase } from '@workos/oagen';
3
7
  import { buildResolvedLookup, lookupMethodName, getMountTarget } from '../shared/resolved-ops.js';
4
8
  import { stripUrnPrefix } from '../shared/naming-utils.js';
@@ -73,6 +77,36 @@ export function apiClassName(name: string): string {
73
77
  return className(name);
74
78
  }
75
79
 
80
+ /**
81
+ * Resolve the Kotlin service class name with the collision suffix applied
82
+ * when needed. Wraps `apiClassName` so callers don't need to thread the
83
+ * exported-classes set through unrelated emission logic.
84
+ */
85
+ export function resolveApiClassName(name: string, exportedClasses: Set<string>): string {
86
+ return apiClassName(resolveServiceTarget(name, exportedClasses));
87
+ }
88
+
89
+ /**
90
+ * Build the set of model + enum class names exported by the SDK. Used to
91
+ * detect collisions with operation-client class names — a colliding service
92
+ * gets a `Service` suffix appended.
93
+ */
94
+ export function buildExportedClassNameSet(ctx: EmitterContext): Set<string> {
95
+ return buildExportedClassNameSetShared(ctx, className);
96
+ }
97
+
98
+ /**
99
+ * Resolve a service's mount-target identifier, appending `Service` on
100
+ * collision with an exported model/enum class. Kotlin sees the collision
101
+ * when a service class shares a simple name with an imported model class
102
+ * (e.g. `com.workos.models.OrganizationMembership` vs
103
+ * `com.workos.organizationmembership.OrganizationMembership`) — the file's
104
+ * local declaration shadows the import for unqualified references.
105
+ */
106
+ export function resolveServiceTarget(target: string, exportedClasses: Set<string>): string {
107
+ return resolveServiceTargetShared(target, exportedClasses, className);
108
+ }
109
+
76
110
  /** Accessor property exposed on the WorkOS client (camelCase). */
77
111
  export function servicePropertyName(name: string): string {
78
112
  return toCamelCase(name);
@@ -16,7 +16,7 @@ import { enumCanonicalMap } from './enums.js';
16
16
  import {
17
17
  className,
18
18
  propertyName,
19
- apiClassName,
19
+ resolveApiClassName,
20
20
  packageSegment,
21
21
  resolveMethodName,
22
22
  ktLiteral,
@@ -24,6 +24,7 @@ import {
24
24
  escapeReserved,
25
25
  humanize,
26
26
  maybeShortenEnumParamDescription,
27
+ buildExportedClassNameSet,
27
28
  } from './naming.js';
28
29
  import {
29
30
  buildResolvedLookup,
@@ -96,13 +97,14 @@ export function generateResources(services: Service[], ctx: EmitterContext): Gen
96
97
 
97
98
  const files: GeneratedFile[] = [];
98
99
  const resolvedLookup = buildResolvedLookup(ctx);
100
+ const exportedClasses = buildExportedClassNameSet(ctx);
99
101
 
100
102
  for (const [mountName, group] of mountGroups) {
101
103
  const classCode = generateApiClass(mountName, group.operations, ctx, resolvedLookup);
102
104
  if (!classCode) continue;
103
105
  const pkg = packageSegment(mountName);
104
106
  files.push({
105
- path: `${KOTLIN_SRC_PREFIX}com/workos/${pkg}/${apiClassName(mountName)}.kt`,
107
+ path: `${KOTLIN_SRC_PREFIX}com/workos/${pkg}/${resolveApiClassName(mountName, exportedClasses)}.kt`,
106
108
  content: classCode,
107
109
  overwriteExisting: true,
108
110
  });
@@ -118,7 +120,7 @@ function generateApiClass(
118
120
  resolvedLookup: Map<string, ResolvedOperation>,
119
121
  ): string | null {
120
122
  if (operations.length === 0) return null;
121
- const apiClass = apiClassName(mountName);
123
+ const apiClass = resolveApiClassName(mountName, buildExportedClassNameSet(ctx));
122
124
  const pkg = `com.workos.${packageSegment(mountName)}`;
123
125
 
124
126
  const imports = new Set<string>();
@@ -10,7 +10,15 @@ import type {
10
10
  ResolvedWrapper,
11
11
  } from '@workos/oagen';
12
12
  import { planOperation } from '@workos/oagen';
13
- import { apiClassName, packageSegment, resolveMethodName, ktStringLiteral, className, propertyName } from './naming.js';
13
+ import {
14
+ resolveApiClassName,
15
+ packageSegment,
16
+ resolveMethodName,
17
+ ktStringLiteral,
18
+ className,
19
+ propertyName,
20
+ buildExportedClassNameSet,
21
+ } from './naming.js';
14
22
  import { mapTypeRef } from './type-map.js';
15
23
  import {
16
24
  groupByMount,
@@ -70,12 +78,13 @@ export function generateTests(spec: ApiSpec, ctx: EmitterContext): GeneratedFile
70
78
  const mountGroups = groupByMount(ctx);
71
79
  const resolvedLookup = buildResolvedLookup(ctx);
72
80
 
81
+ const exportedClasses = buildExportedClassNameSet(ctx);
73
82
  for (const [mountName, group] of mountGroups) {
74
83
  const content = generateServiceTestClass(mountName, group.operations, ctx, resolvedLookup);
75
84
  if (!content) continue;
76
85
  const pkg = packageSegment(mountName);
77
86
  files.push({
78
- path: `${TEST_PREFIX}com/workos/${pkg}/${apiClassName(mountName)}Test.kt`,
87
+ path: `${TEST_PREFIX}com/workos/${pkg}/${resolveApiClassName(mountName, exportedClasses)}Test.kt`,
79
88
  content,
80
89
  overwriteExisting: true,
81
90
  });
@@ -203,7 +212,7 @@ function generateServiceTestClass(
203
212
  }
204
213
 
205
214
  const pkg = packageSegment(mountName);
206
- const apiCls = apiClassName(mountName);
215
+ const apiCls = resolveApiClassName(mountName, buildExportedClassNameSet(ctx));
207
216
 
208
217
  // If any operation would emit a disabled placeholder test, preregister
209
218
  // the `Disabled` import before we serialize the header.
@@ -2,7 +2,13 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import type { ApiSpec, AuthScheme, EmitterContext, GeneratedFile } from '@workos/oagen';
4
4
 
5
- import { fileName, servicePropertyName, resolveInterfaceName, wireInterfaceName } from './naming.js';
5
+ import {
6
+ fileName,
7
+ servicePropertyName,
8
+ resolveInterfaceName,
9
+ wireInterfaceName,
10
+ resolveServiceName,
11
+ } from './naming.js';
6
12
  import { isInlineEnum } from './type-map.js';
7
13
  import {
8
14
  docComment,
@@ -89,7 +95,10 @@ function generateWorkOSClient(spec: ApiSpec, ctx: EmitterContext): GeneratedFile
89
95
  for (const service of spec.services) {
90
96
  if (coveredServices.has(service.name)) continue;
91
97
  const resolvedName = resolveResourceClassName(service, ctx);
92
- const propName = servicePropertyName(resolvedName);
98
+ // Accessor name uses the un-suffixed service name so that the public API
99
+ // stays `client.organizationMembership` even when the class itself was
100
+ // renamed to `OrganizationMembershipService` to avoid a model collision.
101
+ const propName = servicePropertyName(resolveServiceName(service, ctx));
93
102
  if (existingProps.has(propName)) continue;
94
103
  // Propagate `@deprecated` from the service class to the property so
95
104
  // IDEs surface the strikethrough at `workos.xyz` access sites, not