@workos/oagen-emitters 0.12.0 → 0.12.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.
Files changed (53) hide show
  1. package/.github/workflows/ci.yml +1 -1
  2. package/.github/workflows/lint-pr-title.yml +1 -1
  3. package/.github/workflows/lint.yml +1 -1
  4. package/.github/workflows/release-please.yml +2 -2
  5. package/.github/workflows/release.yml +1 -1
  6. package/.node-version +1 -1
  7. package/.release-please-manifest.json +1 -1
  8. package/CHANGELOG.md +14 -0
  9. package/dist/index.d.mts.map +1 -1
  10. package/dist/index.mjs +1 -1
  11. package/dist/{plugin-C408Wh-o.mjs → plugin-eCuvoL1T.mjs} +3914 -2121
  12. package/dist/plugin-eCuvoL1T.mjs.map +1 -0
  13. package/dist/plugin.d.mts.map +1 -1
  14. package/dist/plugin.mjs +1 -1
  15. package/package.json +10 -10
  16. package/renovate.json +46 -6
  17. package/src/node/client.ts +19 -32
  18. package/src/node/enums.ts +67 -30
  19. package/src/node/errors.ts +2 -8
  20. package/src/node/field-plan.ts +188 -52
  21. package/src/node/fixtures.ts +11 -33
  22. package/src/node/index.ts +345 -20
  23. package/src/node/live-surface.ts +378 -0
  24. package/src/node/models.ts +540 -351
  25. package/src/node/naming.ts +119 -25
  26. package/src/node/node-overrides.ts +77 -0
  27. package/src/node/options.ts +41 -0
  28. package/src/node/resources.ts +455 -46
  29. package/src/node/sdk-errors.ts +0 -16
  30. package/src/node/tests.ts +108 -83
  31. package/src/node/type-map.ts +40 -18
  32. package/src/node/utils.ts +89 -102
  33. package/src/node/wrappers.ts +0 -20
  34. package/src/rust/fixtures.ts +87 -1
  35. package/src/rust/models.ts +17 -2
  36. package/src/rust/resources.ts +697 -62
  37. package/src/rust/tests.ts +540 -20
  38. package/test/node/client.test.ts +106 -1201
  39. package/test/node/enums.test.ts +59 -130
  40. package/test/node/errors.test.ts +2 -3
  41. package/test/node/live-surface.test.ts +240 -0
  42. package/test/node/models.test.ts +396 -765
  43. package/test/node/naming.test.ts +69 -234
  44. package/test/node/resources.test.ts +376 -2036
  45. package/test/node/tests.test.ts +119 -0
  46. package/test/node/type-map.test.ts +49 -54
  47. package/test/node/utils.test.ts +29 -80
  48. package/test/rust/fixtures.test.ts +227 -0
  49. package/test/rust/models.test.ts +38 -0
  50. package/test/rust/resources.test.ts +505 -2
  51. package/test/rust/tests.test.ts +504 -0
  52. package/dist/plugin-C408Wh-o.mjs.map +0 -1
  53. package/test/node/serializers.test.ts +0 -444
@@ -1,242 +1,77 @@
1
- import { describe, it, expect } from 'vitest';
2
- import {
3
- className,
4
- fileName,
5
- methodName,
6
- fieldName,
7
- wireFieldName,
8
- wireInterfaceName,
9
- serviceDirName,
10
- servicePropertyName,
11
- resolveServiceName,
12
- buildServiceNameMap,
13
- stripNoiseSuffixes,
14
- } from '../../src/node/naming.js';
15
- import type { EmitterContext, ApiSpec, Service } from '@workos/oagen';
1
+ import { afterEach, describe, expect, it } from 'vitest';
2
+ import type { EmitterContext } from '@workos/oagen';
16
3
  import { defaultSdkBehavior } from '@workos/oagen';
4
+ import { resolveInterfaceName, setAdoptedModelNames } from '../../src/node/naming.js';
5
+
6
+ const ctx: EmitterContext = {
7
+ namespace: 'workos',
8
+ namespacePascal: 'WorkOS',
9
+ spec: {
10
+ name: 'Test',
11
+ version: '1.0.0',
12
+ baseUrl: '',
13
+ services: [],
14
+ models: [],
15
+ enums: [],
16
+ sdk: defaultSdkBehavior(),
17
+ },
18
+ };
19
+
20
+ afterEach(() => {
21
+ setAdoptedModelNames(new Set());
22
+ });
17
23
 
18
- describe('naming', () => {
19
- describe('stripNoiseSuffixes', () => {
20
- it('strips trailing Dto', () => {
21
- expect(stripNoiseSuffixes('OrganizationDto')).toBe('Organization');
22
- expect(stripNoiseSuffixes('UpdateOrganizationDto')).toBe('UpdateOrganization');
23
- });
24
-
25
- it('is case-insensitive for the Dto suffix', () => {
26
- expect(stripNoiseSuffixes('OrganizationDTO')).toBe('Organization');
27
- });
28
-
29
- it('does not strip Dto from the middle of a name', () => {
30
- expect(stripNoiseSuffixes('DtoFactory')).toBe('DtoFactory');
31
- });
32
-
33
- it('leaves names without Dto unchanged', () => {
34
- expect(stripNoiseSuffixes('Organization')).toBe('Organization');
35
- });
36
- });
37
-
38
- describe('className', () => {
39
- it('converts to PascalCase', () => {
40
- expect(className('organizations')).toBe('Organizations');
41
- expect(className('user_management')).toBe('UserManagement');
42
- expect(className('api_keys')).toBe('ApiKeys');
43
- });
44
- });
45
-
46
- describe('fileName', () => {
47
- it('converts to kebab-case', () => {
48
- expect(fileName('Organization')).toBe('organization');
49
- expect(fileName('OrganizationDomain')).toBe('organization-domain');
50
- expect(fileName('UserManagement')).toBe('user-management');
51
- });
52
- });
53
-
54
- describe('methodName', () => {
55
- it('converts to camelCase', () => {
56
- expect(methodName('list_organizations')).toBe('listOrganizations');
57
- expect(methodName('create_organization')).toBe('createOrganization');
58
- expect(methodName('get_organization')).toBe('getOrganization');
59
- });
60
- });
61
-
62
- describe('fieldName', () => {
63
- it('converts to camelCase', () => {
64
- expect(fieldName('allow_profiles_outside_organization')).toBe('allowProfilesOutsideOrganization');
65
- expect(fieldName('stripe_customer_id')).toBe('stripeCustomerId');
66
- expect(fieldName('id')).toBe('id');
67
- });
68
- });
69
-
70
- describe('wireFieldName', () => {
71
- it('converts to snake_case', () => {
72
- expect(wireFieldName('allowProfilesOutsideOrganization')).toBe('allow_profiles_outside_organization');
73
- expect(wireFieldName('id')).toBe('id');
74
- expect(wireFieldName('created_at')).toBe('created_at');
75
- });
76
- });
77
-
78
- describe('wireInterfaceName', () => {
79
- it('appends Response for normal names', () => {
80
- expect(wireInterfaceName('Organization')).toBe('OrganizationResponse');
81
- });
82
-
83
- it('appends Wire when name already ends in Response', () => {
84
- expect(wireInterfaceName('PortalSessionsCreateResponse')).toBe('PortalSessionsCreateResponseWire');
85
- });
86
- });
87
-
88
- describe('serviceDirName', () => {
89
- it('converts to kebab-case', () => {
90
- expect(serviceDirName('Organizations')).toBe('organizations');
91
- expect(serviceDirName('UserManagement')).toBe('user-management');
92
- expect(serviceDirName('ApiKeys')).toBe('api-keys');
93
- });
94
- });
95
-
96
- describe('servicePropertyName', () => {
97
- it('converts to camelCase', () => {
98
- expect(servicePropertyName('Organizations')).toBe('organizations');
99
- expect(servicePropertyName('UserManagement')).toBe('userManagement');
100
- expect(servicePropertyName('ApiKeys')).toBe('apiKeys');
101
- });
102
- });
103
-
104
- describe('resolveServiceName', () => {
105
- const emptySpec: ApiSpec = {
106
- name: 'Test',
107
- version: '1.0.0',
108
- baseUrl: '',
109
- services: [],
110
- models: [],
111
- enums: [],
112
- sdk: defaultSdkBehavior(),
113
- };
114
-
115
- it('returns overlay class name when available', () => {
116
- const service: Service = {
117
- name: 'MultiFactorAuth',
118
- operations: [
119
- {
120
- name: 'enrollFactor',
121
- httpMethod: 'post',
122
- path: '/auth/factors/enroll',
123
- pathParams: [],
124
- queryParams: [],
125
- headerParams: [],
126
- response: { kind: 'primitive', type: 'string' },
127
- errors: [],
128
- injectIdempotencyKey: true,
129
- },
130
- ],
131
- };
132
-
133
- const ctx: EmitterContext = {
134
- namespace: 'workos',
135
- namespacePascal: 'WorkOS',
136
- spec: emptySpec,
137
- overlayLookup: {
138
- methodByOperation: new Map([
139
- [
140
- 'POST /auth/factors/enroll',
141
- {
142
- className: 'Mfa',
143
- methodName: 'enrollFactor',
144
- params: [],
145
- returnType: 'void',
146
- },
147
- ],
148
- ]),
149
- httpKeyByMethod: new Map(),
150
- interfaceByName: new Map(),
151
- typeAliasByName: new Map(),
152
- requiredExports: new Map(),
153
- modelNameByIR: new Map(),
154
- fileBySymbol: new Map(),
24
+ describe('resolveInterfaceName', () => {
25
+ it('normalizes structural matches that point at legacy Serialized* wire interfaces', () => {
26
+ const result = resolveInterfaceName('OrganizationApiKey', {
27
+ ...ctx,
28
+ apiSurface: {
29
+ language: 'node',
30
+ extractedFrom: '/tmp/workos-node',
31
+ extractedAt: '2026-05-12T00:00:00Z',
32
+ classes: {},
33
+ interfaces: {
34
+ CreatedApiKey: {},
35
+ SerializedCreatedApiKey: {},
155
36
  },
156
- };
157
-
158
- expect(resolveServiceName(service, ctx)).toBe('Mfa');
159
- });
160
-
161
- it('falls back to PascalCase of service.name', () => {
162
- const service: Service = {
163
- name: 'SomeNewService',
164
- operations: [],
165
- };
166
-
167
- const ctx: EmitterContext = {
168
- namespace: 'workos',
169
- namespacePascal: 'WorkOS',
170
- spec: emptySpec,
171
- };
172
-
173
- expect(resolveServiceName(service, ctx)).toBe('SomeNewService');
174
- });
37
+ typeAliases: {},
38
+ enums: {},
39
+ exports: {},
40
+ } as any,
41
+ overlayLookup: {
42
+ methodByOperation: new Map(),
43
+ interfaceByName: new Map(),
44
+ modelNameByIR: new Map([['OrganizationApiKey', 'SerializedCreatedApiKey']]),
45
+ } as any,
46
+ });
47
+
48
+ expect(result).toBe('CreatedApiKey');
175
49
  });
176
50
 
177
- describe('buildServiceNameMap', () => {
178
- const emptySpec: ApiSpec = {
179
- name: 'Test',
180
- version: '1.0.0',
181
- baseUrl: '',
182
- services: [],
183
- models: [],
184
- enums: [],
185
- sdk: defaultSdkBehavior(),
186
- };
187
-
188
- it('maps IR names to resolved names', () => {
189
- const services: Service[] = [
190
- {
191
- name: 'MultiFactorAuth',
192
- operations: [
193
- {
194
- name: 'enrollFactor',
195
- httpMethod: 'post',
196
- path: '/auth/factors/enroll',
197
- pathParams: [],
198
- queryParams: [],
199
- headerParams: [],
200
- response: { kind: 'primitive', type: 'string' },
201
- errors: [],
202
- injectIdempotencyKey: true,
203
- },
204
- ],
205
- },
206
- {
207
- name: 'Organizations',
208
- operations: [],
209
- },
210
- ];
211
-
212
- const ctx: EmitterContext = {
213
- namespace: 'workos',
214
- namespacePascal: 'WorkOS',
215
- spec: emptySpec,
216
- overlayLookup: {
217
- methodByOperation: new Map([
218
- [
219
- 'POST /auth/factors/enroll',
220
- {
221
- className: 'Mfa',
222
- methodName: 'enrollFactor',
223
- params: [],
224
- returnType: 'void',
225
- },
226
- ],
227
- ]),
228
- httpKeyByMethod: new Map(),
229
- interfaceByName: new Map(),
230
- typeAliasByName: new Map(),
231
- requiredExports: new Map(),
232
- modelNameByIR: new Map(),
233
- fileBySymbol: new Map(),
51
+ it('does not apply unrelated structural matches to adopted-service models', () => {
52
+ setAdoptedModelNames(new Set(['CreateM2MApplication']));
53
+
54
+ const result = resolveInterfaceName('CreateM2MApplication', {
55
+ ...ctx,
56
+ apiSurface: {
57
+ language: 'node',
58
+ extractedFrom: '/tmp/workos-node',
59
+ extractedAt: '2026-05-12T00:00:00Z',
60
+ classes: {},
61
+ interfaces: {
62
+ CreateGroupOptions: {},
234
63
  },
235
- };
236
-
237
- const map = buildServiceNameMap(services, ctx);
238
- expect(map.get('MultiFactorAuth')).toBe('Mfa');
239
- expect(map.get('Organizations')).toBe('Organizations');
240
- });
64
+ typeAliases: {},
65
+ enums: {},
66
+ exports: {},
67
+ } as any,
68
+ overlayLookup: {
69
+ methodByOperation: new Map(),
70
+ interfaceByName: new Map(),
71
+ modelNameByIR: new Map([['CreateM2MApplication', 'CreateGroupOptions']]),
72
+ } as any,
73
+ });
74
+
75
+ expect(result).toBe('CreateM2MApplication');
241
76
  });
242
77
  });