@workos/oagen-emitters 0.14.2 → 0.14.4

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-BbSmT2kj.mjs";
1
+ import { t as workosEmittersPlugin } from "./plugin-BGVaMGqe.mjs";
2
2
  export { workosEmittersPlugin };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workos/oagen-emitters",
3
- "version": "0.14.2",
3
+ "version": "0.14.4",
4
4
  "description": "WorkOS' oagen emitters",
5
5
  "license": "MIT",
6
6
  "author": "WorkOS",
@@ -42,8 +42,8 @@
42
42
  "@commitlint/config-conventional": "^21.0.1",
43
43
  "@types/node": "^25.9.1",
44
44
  "husky": "^9.1.7",
45
- "oxfmt": "^0.51.0",
46
- "oxlint": "^1.66.0",
45
+ "oxfmt": "^0.52.0",
46
+ "oxlint": "^1.67.0",
47
47
  "prettier": "^3.8.3",
48
48
  "tsdown": "^0.22.0",
49
49
  "tsx": "^4.22.3",
@@ -54,6 +54,6 @@
54
54
  "node": ">=24.10.0"
55
55
  },
56
56
  "dependencies": {
57
- "@workos/oagen": "^0.20.0"
57
+ "@workos/oagen": "^0.21.0"
58
58
  }
59
59
  }
@@ -146,6 +146,22 @@ export function generateModelFixture(
146
146
  }
147
147
  }
148
148
 
149
+ if (model.discriminator) {
150
+ const [firstValue, variantName] = Object.entries(model.discriminator.mapping)[0];
151
+ fixture[model.discriminator.property] = firstValue;
152
+ const variantModel = modelMap.get(variantName);
153
+ if (variantModel) {
154
+ for (const field of variantModel.fields) {
155
+ if (!(field.name in fixture)) {
156
+ fixture[field.name] =
157
+ field.example !== undefined
158
+ ? field.example
159
+ : generateFieldValue(field.type, field.name, model.name, modelMap, enumMap);
160
+ }
161
+ }
162
+ }
163
+ }
164
+
149
165
  return fixture;
150
166
  }
151
167
 
@@ -124,14 +124,14 @@ export function detectDiscriminatedShape(
124
124
  return {
125
125
  nameSuffix: variantNameSuffix(discValue),
126
126
  discriminatorValue: discValue,
127
- fields: variantFields(fv, discProp, modelName, rawSchemas),
127
+ fields: variantFields(fv, discProp, modelName),
128
128
  };
129
129
  })
130
130
  .filter((v): v is VariantSpec => v !== null);
131
131
 
132
132
  if (variants.length !== flattenedVariants.length) return null;
133
133
 
134
- const baseFields = baseObject ? collectObjectFields(baseObject, modelName, rawSchemas) : [];
134
+ const baseFields = baseObject ? collectObjectFields(baseObject, modelName) : [];
135
135
 
136
136
  return {
137
137
  modelName,
@@ -146,7 +146,7 @@ function mergeBase(prev: RawSchema | null, next: RawSchema): RawSchema {
146
146
  if (!prev) return next;
147
147
  return {
148
148
  type: 'object',
149
- properties: { ...(prev.properties ?? {}), ...(next.properties ?? {}) },
149
+ properties: { ...prev.properties, ...next.properties },
150
150
  required: [...new Set([...(prev.required ?? []), ...(next.required ?? [])])],
151
151
  };
152
152
  }
@@ -328,48 +328,33 @@ function variantNameSuffix(constValue: string): string {
328
328
  // Field extraction
329
329
  // ---------------------------------------------------------------------------
330
330
 
331
- function collectObjectFields(
332
- schema: RawSchema,
333
- parentName: string,
334
- rawSchemas: Record<string, RawSchema>,
335
- ): FieldSpec[] {
331
+ function collectObjectFields(schema: RawSchema, parentName: string): FieldSpec[] {
336
332
  const props = schema.properties ?? {};
337
333
  const required = new Set(schema.required ?? []);
338
334
  const fields: FieldSpec[] = [];
339
335
  for (const [name, propSchema] of Object.entries(props)) {
340
- fields.push(buildField(name, propSchema, required.has(name), parentName, rawSchemas));
336
+ fields.push(buildField(name, propSchema, required.has(name), parentName));
341
337
  }
342
338
  return fields;
343
339
  }
344
340
 
345
- function variantFields(
346
- fv: FlattenedVariant,
347
- discriminatorProperty: string,
348
- parentName: string,
349
- rawSchemas: Record<string, RawSchema>,
350
- ): FieldSpec[] {
341
+ function variantFields(fv: FlattenedVariant, discriminatorProperty: string, parentName: string): FieldSpec[] {
351
342
  const fields: FieldSpec[] = [];
352
343
  for (const [name, propSchema] of fv.alwaysProperties) {
353
344
  if (name === discriminatorProperty) continue;
354
- fields.push(buildField(name, propSchema, fv.required.has(name), parentName, rawSchemas));
345
+ fields.push(buildField(name, propSchema, fv.required.has(name), parentName));
355
346
  }
356
347
  for (const [name, propSchema] of fv.optionalProperties) {
357
348
  if (name === discriminatorProperty) continue;
358
- fields.push(buildField(name, propSchema, false, parentName, rawSchemas));
349
+ fields.push(buildField(name, propSchema, false, parentName));
359
350
  }
360
351
  return fields;
361
352
  }
362
353
 
363
- function buildField(
364
- rawName: string,
365
- schema: RawSchema,
366
- required: boolean,
367
- parentName: string,
368
- rawSchemas: Record<string, RawSchema>,
369
- ): FieldSpec {
354
+ function buildField(rawName: string, schema: RawSchema, required: boolean, parentName: string): FieldSpec {
370
355
  const modelDeps = new Set<string>();
371
- const domainType = rawSchemaToTS(schema, parentName, rawName, false, modelDeps, rawSchemas);
372
- const wireType = rawSchemaToTS(schema, parentName, rawName, true, modelDeps, rawSchemas);
356
+ const domainType = rawSchemaToTS(schema, parentName, rawName, false, modelDeps);
357
+ const wireType = rawSchemaToTS(schema, parentName, rawName, true, modelDeps);
373
358
  return {
374
359
  name: rawName,
375
360
  description: schema.description,
@@ -404,7 +389,6 @@ function rawSchemaToTS(
404
389
  fieldName: string,
405
390
  isWire: boolean,
406
391
  modelDeps: Set<string>,
407
- rawSchemas: Record<string, RawSchema>,
408
392
  ): string {
409
393
  if (schema.$ref) {
410
394
  const refName = schema.$ref.split('/').pop()!;
@@ -428,7 +412,7 @@ function rawSchemaToTS(
428
412
  } else if (baseType === 'boolean') {
429
413
  core = 'boolean';
430
414
  } else if (baseType === 'array' && schema.items) {
431
- const items = rawSchemaToTS(schema.items, parentName, singularize(fieldName), isWire, modelDeps, rawSchemas);
415
+ const items = rawSchemaToTS(schema.items, parentName, singularize(fieldName), isWire, modelDeps);
432
416
  core = `${parenthesizeUnion(items)}[]`;
433
417
  } else if (baseType === 'object' && schema.properties) {
434
418
  // Inline object — refer to the synthetic model name that
@@ -165,6 +165,23 @@ export function generateModelFixture(
165
165
  }
166
166
  }
167
167
 
168
+ if (model.discriminator) {
169
+ const [firstValue, variantName] = Object.entries(model.discriminator.mapping)[0];
170
+ fixture[wireFieldName(model.discriminator.property)] = firstValue;
171
+ const variantModel = modelMap.get(variantName);
172
+ if (variantModel) {
173
+ for (const field of variantModel.fields) {
174
+ const wireName = wireFieldName(field.name);
175
+ if (!(wireName in fixture)) {
176
+ fixture[wireName] =
177
+ field.example !== undefined
178
+ ? field.example
179
+ : generateFieldValue(field.type, field.name, model.name, modelMap, enumMap);
180
+ }
181
+ }
182
+ }
183
+ }
184
+
168
185
  return fixture;
169
186
  }
170
187
 
package/src/node/index.ts CHANGED
@@ -195,6 +195,11 @@ function markPriorManifestAutogen(
195
195
  if (!surface.files.has(relPath)) continue;
196
196
  if (surface.protectedFiles.has(relPath)) continue;
197
197
 
198
+ if (/\/fixtures\/[^/]+\.json$/.test(relPath)) {
199
+ surface.autogenFiles.add(relPath);
200
+ continue;
201
+ }
202
+
198
203
  try {
199
204
  const text = fs.readFileSync(path.join(root, relPath), 'utf8');
200
205
  if (/auto-generated by oagen/i.test(text.slice(0, 400))) {
@@ -123,6 +123,22 @@ export function generateModelFixture(
123
123
  }
124
124
  }
125
125
 
126
+ if (model.discriminator) {
127
+ const [firstValue, variantName] = Object.entries(model.discriminator.mapping)[0];
128
+ fixture[model.discriminator.property] = firstValue;
129
+ const variantModel = modelMap.get(variantName);
130
+ if (variantModel) {
131
+ for (const field of variantModel.fields) {
132
+ if (!(field.name in fixture)) {
133
+ fixture[field.name] =
134
+ field.example !== undefined
135
+ ? field.example
136
+ : generateFieldValue(field.type, field.name, model.name, modelMap, enumMap);
137
+ }
138
+ }
139
+ }
140
+ }
141
+
126
142
  return fixture;
127
143
  }
128
144
 
package/src/ruby/rbi.ts CHANGED
@@ -49,7 +49,7 @@ function mapSorbetType(ref: TypeRef): string {
49
49
  if (unique.length === 1) return unique[0];
50
50
  return `T.any(${unique.join(', ')})`;
51
51
  },
52
- nullable: (_ref, inner) => `T.nilable(${inner})`,
52
+ nullable: (_ref, inner) => wrapNilable(inner),
53
53
  literal: (r) =>
54
54
  typeof r.value === 'string'
55
55
  ? 'String'
@@ -95,7 +95,7 @@ export function generateRbiFiles(spec: ApiSpec, ctx: EmitterContext): GeneratedF
95
95
  const fname = fieldName(f.name);
96
96
  if (seenFieldNames.has(fname)) continue;
97
97
  seenFieldNames.add(fname);
98
- const sorbetType = f.required ? mapSorbetType(f.type) : `T.nilable(${unwrapNilable(mapSorbetType(f.type))})`;
98
+ const sorbetType = f.required ? mapSorbetType(f.type) : wrapNilable(mapSorbetType(f.type));
99
99
  lines.push(` sig { returns(${sorbetType}) }`);
100
100
  lines.push(` def ${fname}; end`);
101
101
  lines.push('');
@@ -238,7 +238,7 @@ export function generateRbiFiles(spec: ApiSpec, ctx: EmitterContext): GeneratedF
238
238
  const n = fieldName(f.name);
239
239
  if (seen.has(n)) continue;
240
240
  seen.add(n);
241
- sigParams.push(`${n}: T.nilable(${unwrapNilable(mapSorbetType(f.type))})`);
241
+ sigParams.push(`${n}: ${wrapNilable(mapSorbetType(f.type))}`);
242
242
  }
243
243
  for (const q of queryParams) {
244
244
  if (hiddenParams.has(q.name)) continue;
@@ -246,14 +246,14 @@ export function generateRbiFiles(spec: ApiSpec, ctx: EmitterContext): GeneratedF
246
246
  const n = safeParamName(q.name);
247
247
  if (seen.has(n)) continue;
248
248
  seen.add(n);
249
- sigParams.push(`${n}: T.nilable(${unwrapNilable(mapSorbetType(q.type))})`);
249
+ sigParams.push(`${n}: ${wrapNilable(mapSorbetType(q.type))}`);
250
250
  }
251
251
  for (const group of parameterGroups) {
252
252
  if (!group.optional) continue;
253
253
  const n = fieldName(group.name);
254
254
  if (seen.has(n)) continue;
255
255
  seen.add(n);
256
- sigParams.push(`${n}: T.nilable(${groupSorbetType(group)})`);
256
+ sigParams.push(`${n}: ${wrapNilable(groupSorbetType(group))}`);
257
257
  }
258
258
  sigParams.push('request_options: T::Hash[Symbol, T.untyped]');
259
259
 
@@ -321,6 +321,12 @@ function unwrapNilable(type: string): string {
321
321
  return match ? match[1] : type;
322
322
  }
323
323
 
324
+ /** Wrap a type in T.nilable(), skipping T.untyped (which already includes nil) and avoiding double-wrapping. */
325
+ function wrapNilable(type: string): string {
326
+ if (type === 'T.untyped') return type;
327
+ return `T.nilable(${unwrapNilable(type)})`;
328
+ }
329
+
324
330
  /** Map a response TypeRef to a Sorbet return type. */
325
331
  function mapSorbetReturnType(ref: TypeRef, listWrapperModels: Map<string, Model>, modelNames: Set<string>): string {
326
332
  if (ref.kind === 'model' && listWrapperModels.has(ref.name)) {
@@ -333,7 +339,7 @@ function mapSorbetReturnType(ref: TypeRef, listWrapperModels: Map<string, Model>
333
339
  return `T::Array[WorkOS::${className(ref.items.name)}]`;
334
340
  }
335
341
  if (ref.kind === 'nullable') {
336
- return `T.nilable(${mapSorbetReturnType(ref.inner, listWrapperModels, modelNames)})`;
342
+ return wrapNilable(mapSorbetReturnType(ref.inner, listWrapperModels, modelNames));
337
343
  }
338
344
  if (ref.kind === 'primitive' && ref.type === 'unknown') {
339
345
  return 'NilClass';
@@ -49,6 +49,22 @@ export function generateModelFixture(
49
49
  fromExample !== undefined ? fromExample : exampleFor(field.type, modelMap, enumMap, visiting, field.name);
50
50
  }
51
51
 
52
+ if (model.discriminator) {
53
+ const [firstValue, variantName] = Object.entries(model.discriminator.mapping)[0];
54
+ result[model.discriminator.property] = firstValue;
55
+ const variantModel = modelMap.get(variantName);
56
+ if (variantModel) {
57
+ for (const field of variantModel.fields) {
58
+ if (!(field.name in result)) {
59
+ if (!field.required) continue;
60
+ const fromExample = exampleFromSpec(field.example, field.type, enumMap);
61
+ result[field.name] =
62
+ fromExample !== undefined ? fromExample : exampleFor(field.type, modelMap, enumMap, visiting, field.name);
63
+ }
64
+ }
65
+ }
66
+ }
67
+
52
68
  visiting.delete(model.name);
53
69
  return result;
54
70
  }