@workos/oagen-emitters 0.9.1 → 0.10.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-Dh9JSScr.mjs";
1
+ import { t as workosEmittersPlugin } from "./plugin-H0KhxbN7.mjs";
2
2
  export { workosEmittersPlugin };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workos/oagen-emitters",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "description": "WorkOS' oagen emitters",
5
5
  "license": "MIT",
6
6
  "author": "WorkOS",
@@ -54,6 +54,6 @@
54
54
  "node": ">=24.10.0"
55
55
  },
56
56
  "dependencies": {
57
- "@workos/oagen": "^0.17.3"
57
+ "@workos/oagen": "^0.18.0"
58
58
  }
59
59
  }
@@ -70,18 +70,37 @@ export function generateEnums(enums: Enum[], ctx: EmitterContext): GeneratedFile
70
70
  lines.push(' [STJS.JsonConverter(typeof(WorkOSStringEnumConverterFactory))]');
71
71
  lines.push(` public enum ${typeName}`);
72
72
  lines.push(' {');
73
- // Unknown sentinel as first member (value 0) for forward-compatibility
74
- lines.push(` [EnumMember(Value = "unknown")]`);
75
- lines.push(` Unknown,`);
76
- lines.push('');
73
+
74
+ // If the spec defines a default that matches a member, promote it to
75
+ // ordinal 0 so `default(EnumType)` returns that variant. Other members
76
+ // get explicit ascending ordinals, and the Unknown sentinel is pushed
77
+ // to a high explicit ordinal (99) so it never sits at 0.
78
+ const defaultMatch =
79
+ enumDef.default !== undefined ? uniqueValues.find((v) => v.value === enumDef.default) : undefined;
80
+
81
+ const orderedValues = defaultMatch
82
+ ? [defaultMatch, ...uniqueValues.filter((v) => v !== defaultMatch)]
83
+ : uniqueValues;
77
84
 
78
85
  const usedNames = new Set<string>();
79
- usedNames.add('Unknown');
80
- // Track used EnumMember wire values to avoid duplicates (sentinel uses "unknown")
81
86
  const usedWireValues = new Set<string>();
82
- usedWireValues.add('unknown');
83
- for (let i = 0; i < uniqueValues.length; i++) {
84
- const v = uniqueValues[i];
87
+
88
+ if (defaultMatch) {
89
+ // Reserve the sentinel name and wire value so spec values that collide
90
+ // with "unknown"/Unknown still get the existing skip/dedup behavior.
91
+ usedNames.add('Unknown');
92
+ usedWireValues.add('unknown');
93
+ } else {
94
+ // Existing behavior: Unknown sentinel at ordinal 0.
95
+ lines.push(` [EnumMember(Value = "unknown")]`);
96
+ lines.push(` Unknown,`);
97
+ lines.push('');
98
+ usedNames.add('Unknown');
99
+ usedWireValues.add('unknown');
100
+ }
101
+
102
+ for (let i = 0; i < orderedValues.length; i++) {
103
+ const v = orderedValues[i];
85
104
  // Skip values whose wire representation collides with the sentinel
86
105
  if (usedWireValues.has(String(v.value))) continue;
87
106
  usedWireValues.add(String(v.value));
@@ -102,8 +121,15 @@ export function generateEnums(enums: Enum[], ctx: EmitterContext): GeneratedFile
102
121
  lines.push(` [System.Obsolete("${msg}")]`);
103
122
  }
104
123
  lines.push(` [EnumMember(Value = "${v.value}")]`);
105
- const comma = i < uniqueValues.length - 1 ? ',' : ',';
106
- lines.push(` ${memberName}${comma}`);
124
+ // Explicit ordinals only when we promoted a default to position 0.
125
+ const ordinal = defaultMatch ? ` = ${i}` : '';
126
+ lines.push(` ${memberName}${ordinal},`);
127
+ }
128
+
129
+ if (defaultMatch) {
130
+ lines.push('');
131
+ lines.push(` [EnumMember(Value = "unknown")]`);
132
+ lines.push(` Unknown = 99,`);
107
133
  }
108
134
 
109
135
  lines.push(' }');
@@ -152,6 +152,152 @@ describe('dotnet/enums', () => {
152
152
  expect(files).toHaveLength(0);
153
153
  });
154
154
 
155
+ it('promotes spec-default member to ordinal 0 and pushes Unknown to 99', () => {
156
+ const enums: Enum[] = [
157
+ {
158
+ name: 'PaginationOrder',
159
+ values: [
160
+ { name: 'NORMAL', value: 'normal' },
161
+ { name: 'DESC', value: 'desc' },
162
+ { name: 'ASC', value: 'asc' },
163
+ ],
164
+ default: 'desc',
165
+ },
166
+ ];
167
+
168
+ const service: Service = {
169
+ name: 'Test',
170
+ operations: [
171
+ {
172
+ name: 'test',
173
+ httpMethod: 'get',
174
+ path: '/test',
175
+ pathParams: [],
176
+ queryParams: [{ name: 'order', type: { kind: 'enum', name: 'PaginationOrder' }, required: false }],
177
+ headerParams: [],
178
+ response: { kind: 'primitive', type: 'unknown' },
179
+ errors: [],
180
+ injectIdempotencyKey: false,
181
+ },
182
+ ],
183
+ };
184
+
185
+ const files = generateEnums(enums, {
186
+ ...ctx,
187
+ spec: { ...emptySpec, services: [service], enums },
188
+ });
189
+ expect(files).toHaveLength(1);
190
+ expect(files[0].content).toMatchInlineSnapshot(`
191
+ "namespace WorkOS
192
+ {
193
+ using System.Runtime.Serialization;
194
+ using Newtonsoft.Json;
195
+ using STJS = System.Text.Json.Serialization;
196
+
197
+ /// <summary>Represents pagination order values.</summary>
198
+ [JsonConverter(typeof(WorkOSNewtonsoftStringEnumConverter))]
199
+ [STJS.JsonConverter(typeof(WorkOSStringEnumConverterFactory))]
200
+ public enum PaginationOrder
201
+ {
202
+ [EnumMember(Value = "desc")]
203
+ Desc = 0,
204
+ [EnumMember(Value = "normal")]
205
+ Normal = 1,
206
+ [EnumMember(Value = "asc")]
207
+ Asc = 2,
208
+
209
+ [EnumMember(Value = "unknown")]
210
+ Unknown = 99,
211
+ }
212
+ }"
213
+ `);
214
+ });
215
+
216
+ it('falls back to Unknown=0 layout when no default is set', () => {
217
+ const enums: Enum[] = [
218
+ {
219
+ name: 'Status',
220
+ values: [
221
+ { name: 'ACTIVE', value: 'active' },
222
+ { name: 'INACTIVE', value: 'inactive' },
223
+ ],
224
+ },
225
+ ];
226
+
227
+ const service: Service = {
228
+ name: 'Test',
229
+ operations: [
230
+ {
231
+ name: 'test',
232
+ httpMethod: 'get',
233
+ path: '/test',
234
+ pathParams: [],
235
+ queryParams: [{ name: 'status', type: { kind: 'enum', name: 'Status' }, required: false }],
236
+ headerParams: [],
237
+ response: { kind: 'primitive', type: 'unknown' },
238
+ errors: [],
239
+ injectIdempotencyKey: false,
240
+ },
241
+ ],
242
+ };
243
+
244
+ const files = generateEnums(enums, {
245
+ ...ctx,
246
+ spec: { ...emptySpec, services: [service], enums },
247
+ });
248
+ expect(files).toHaveLength(1);
249
+ const content = files[0].content;
250
+ // No explicit ordinals when no default
251
+ expect(content).not.toMatch(/= \d+,/);
252
+ // Unknown sentinel emitted first (no = N)
253
+ const unknownIdx = content.indexOf('Unknown,');
254
+ const activeIdx = content.indexOf('Active,');
255
+ expect(unknownIdx).toBeGreaterThan(0);
256
+ expect(unknownIdx).toBeLessThan(activeIdx);
257
+ });
258
+
259
+ it('drops a spec value that collides with the unknown sentinel even when default is set', () => {
260
+ const enums: Enum[] = [
261
+ {
262
+ name: 'WithUnknown',
263
+ values: [
264
+ { name: 'NORMAL', value: 'normal' },
265
+ { name: 'UNKNOWN', value: 'unknown' },
266
+ ],
267
+ default: 'normal',
268
+ },
269
+ ];
270
+
271
+ const service: Service = {
272
+ name: 'Test',
273
+ operations: [
274
+ {
275
+ name: 'test',
276
+ httpMethod: 'get',
277
+ path: '/test',
278
+ pathParams: [],
279
+ queryParams: [{ name: 'x', type: { kind: 'enum', name: 'WithUnknown' }, required: false }],
280
+ headerParams: [],
281
+ response: { kind: 'primitive', type: 'unknown' },
282
+ errors: [],
283
+ injectIdempotencyKey: false,
284
+ },
285
+ ],
286
+ };
287
+
288
+ const files = generateEnums(enums, {
289
+ ...ctx,
290
+ spec: { ...emptySpec, services: [service], enums },
291
+ });
292
+ expect(files).toHaveLength(1);
293
+ const content = files[0].content;
294
+ expect(content).toContain('Normal = 0,');
295
+ expect(content).toContain('Unknown = 99,');
296
+ // The spec's "unknown" wire value collides with the sentinel and is dropped,
297
+ // so the body should not contain a non-99 ordinal for Unknown.
298
+ expect(content).not.toMatch(/Unknown = [0-8],/);
299
+ });
300
+
155
301
  it('generates deprecated enum values with Obsolete attribute', () => {
156
302
  const enums: Enum[] = [
157
303
  {