@workos/oagen-emitters 0.14.1 → 0.14.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.
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.14.1"
2
+ ".": "0.14.3"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.14.3](https://github.com/workos/oagen-emitters/compare/v0.14.2...v0.14.3) (2026-05-22)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * include discriminator fields in generated fixtures ([#125](https://github.com/workos/oagen-emitters/issues/125)) ([6a3633e](https://github.com/workos/oagen-emitters/commit/6a3633e0e3f0497146bf89fc31a5dabc1152cce1))
9
+
10
+ ## [0.14.2](https://github.com/workos/oagen-emitters/compare/v0.14.1...v0.14.2) (2026-05-22)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * emit ListMetadata-shape models referenced by surviving wrappers ([#124](https://github.com/workos/oagen-emitters/issues/124)) ([8d8efe1](https://github.com/workos/oagen-emitters/commit/8d8efe148f3665fc9de92cc6aea0e08e77e0fe78))
16
+ * **node:** stop emitting duplicate Response-suffixed interfaces ([#123](https://github.com/workos/oagen-emitters/issues/123)) ([2077d25](https://github.com/workos/oagen-emitters/commit/2077d250d1dc7968245e9ec31d5ef5f75441fc68))
17
+ * **node:** use toBeNull() when example is null on date-time fields ([#121](https://github.com/workos/oagen-emitters/issues/121)) ([0f5029f](https://github.com/workos/oagen-emitters/commit/0f5029f38d2dafc63df09f49a4562e3ffeeb7558))
18
+
3
19
  ## [0.14.1](https://github.com/workos/oagen-emitters/compare/v0.14.0...v0.14.1) (2026-05-22)
4
20
 
5
21
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/node/index.ts","../src/python/index.ts","../src/php/index.ts","../src/go/index.ts","../src/dotnet/index.ts","../src/kotlin/index.ts","../src/ruby/index.ts","../src/rust/index.ts"],"mappings":";;;;;cAyca,WAAA,EAAa,OA4GzB;;;cC9gBY,aAAA,EAAe,OA+D3B;;;cC5CY,UAAA,EAAY,OA4DxB;;;cCzFY,SAAA,EAAW,OAyEvB;;;cCnCY,aAAA,EAAe,OAiR3B;;;cCrTY,aAAA,EAAe,OA6E3B;;;cCxDY,WAAA,EAAa,OAmEzB;;;cC5DY,WAAA,EAAa,OA2DzB"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/node/index.ts","../src/python/index.ts","../src/php/index.ts","../src/go/index.ts","../src/dotnet/index.ts","../src/kotlin/index.ts","../src/ruby/index.ts","../src/rust/index.ts"],"mappings":";;;;;cA4da,WAAA,EAAa,OA4GzB;;;cCjiBY,aAAA,EAAe,OA+D3B;;;cC5CY,UAAA,EAAY,OA4DxB;;;cCzFY,SAAA,EAAW,OAyEvB;;;cCnCY,aAAA,EAAe,OAiR3B;;;cCrTY,aAAA,EAAe,OA6E3B;;;cCxDY,WAAA,EAAa,OAmEzB;;;cC5DY,WAAA,EAAa,OA2DzB"}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as pythonEmitter, a as rustExtractor, c as pythonExtractor, d as rustEmitter, f as rubyEmitter, g as phpEmitter, h as goEmitter, i as kotlinExtractor, l as rubyExtractor, m as dotnetEmitter, n as elixirExtractor, o as goExtractor, p as kotlinEmitter, r as dotnetExtractor, s as phpExtractor, t as workosEmittersPlugin, u as nodeExtractor, v as nodeEmitter } from "./plugin-DRGwxN88.mjs";
1
+ import { _ as pythonEmitter, a as rustExtractor, c as pythonExtractor, d as rustEmitter, f as rubyEmitter, g as phpEmitter, h as goEmitter, i as kotlinExtractor, l as rubyExtractor, m as dotnetEmitter, n as elixirExtractor, o as goExtractor, p as kotlinEmitter, r as dotnetExtractor, s as phpExtractor, t as workosEmittersPlugin, u as nodeExtractor, v as nodeEmitter } from "./plugin-D0qLBiGv.mjs";
2
2
  export { dotnetEmitter, dotnetExtractor, elixirExtractor, goEmitter, goExtractor, kotlinEmitter, kotlinExtractor, nodeEmitter, nodeExtractor, phpEmitter, phpExtractor, pythonEmitter, pythonExtractor, rubyEmitter, rubyExtractor, rustEmitter, rustExtractor, workosEmittersPlugin };
@@ -2334,6 +2334,35 @@ function isListMetadataModel(model) {
2334
2334
  if (!before || !after) return false;
2335
2335
  return isNullableString(before) && isNullableString(after);
2336
2336
  }
2337
+ /**
2338
+ * Compute the `ListMetadata`-shape model names that must still be emitted
2339
+ * because some surviving wrapper references them.
2340
+ *
2341
+ * Each language emitter blanket-skips `isListMetadataModel` models on the
2342
+ * assumption that the SDK's shared pagination wrapper subsumes them. That
2343
+ * is correct for paginated list envelopes (the iterator unwraps the
2344
+ * envelope and `list_metadata` is handled at runtime), but a *non-paginated*
2345
+ * wrapper like vault's `VersionListResponse` still has a
2346
+ * `list_metadata: ListMetadata` field — and skipping emission of
2347
+ * `ListMetadata` leaves the wrapper's interface importing from a file that
2348
+ * was never written.
2349
+ *
2350
+ * Pass the same `nonPaginatedRefs` set the emitter uses for its own
2351
+ * wrapper-survival decision so the two answers stay in sync.
2352
+ */
2353
+ function collectReferencedListMetadataModels(models, nonPaginatedRefs) {
2354
+ const listMetadataNames = /* @__PURE__ */ new Set();
2355
+ for (const m of models) if (isListMetadataModel(m)) listMetadataNames.add(m.name);
2356
+ if (listMetadataNames.size === 0) return /* @__PURE__ */ new Set();
2357
+ const referenced = /* @__PURE__ */ new Set();
2358
+ for (const model of models) {
2359
+ if (isListMetadataModel(model)) continue;
2360
+ if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
2361
+ const deps = collectFieldDependencies(model);
2362
+ for (const dep of deps.models) if (listMetadataNames.has(dep)) referenced.add(dep);
2363
+ }
2364
+ return referenced;
2365
+ }
2337
2366
  /** Check if a field type is nullable string (nullable<string> or just string). */
2338
2367
  function isNullableString(field) {
2339
2368
  if (field.type.kind === "primitive" && field.type.type === "string") return true;
@@ -2826,6 +2855,22 @@ function isAdoptedModelName(name) {
2826
2855
  return adoptedModelNames.has(name);
2827
2856
  }
2828
2857
  /**
2858
+ * Domain names that `resolveInterfaceName` reached via a structural rename
2859
+ * — the resolved name differs from the IR model's own name. `wireInterfaceName`
2860
+ * consults this set to decide whether to fire the "single-form wire" case:
2861
+ * that case is *only* meant for structurally-renamed models, where the
2862
+ * baseline owns a `*Response` interface representing the wire shape with no
2863
+ * separate `*Wire` companion. Without this signal, a freshly-emitted model
2864
+ * whose IR name already ends in `Response` (e.g. `CreateDataKeyResponse`)
2865
+ * would land in the same case as soon as a prior buggy regen wrote the
2866
+ * baseline — producing two `export interface CreateDataKeyResponse { ... }`
2867
+ * declarations in the same file.
2868
+ */
2869
+ let structurallyRenamedDomainNames = /* @__PURE__ */ new Set();
2870
+ function setStructurallyRenamedDomainNames(names) {
2871
+ structurallyRenamedDomainNames = names;
2872
+ }
2873
+ /**
2829
2874
  * Wire/response interface name.
2830
2875
  *
2831
2876
  * Resolution order:
@@ -2848,7 +2893,7 @@ function wireInterfaceName(domainName) {
2848
2893
  if (domainName.endsWith("Response")) {
2849
2894
  const wireForm = `${domainName}Wire`;
2850
2895
  if (baselineInterfaceNames.has(wireForm)) return wireForm;
2851
- if (baselineInterfaceNames.has(domainName)) return domainName;
2896
+ if (structurallyRenamedDomainNames.has(domainName) && baselineInterfaceNames.has(domainName)) return domainName;
2852
2897
  return wireForm;
2853
2898
  }
2854
2899
  return `${domainName}Response`;
@@ -4892,8 +4937,11 @@ function generateResourceClass(service, ctx) {
4892
4937
  importedTypeNames.add(resolved);
4893
4938
  const modelServiceDir = resolveDir(modelToService.get(name));
4894
4939
  const relPath = modelServiceDir === serviceDir ? `./interfaces/${fileName$3(name)}.interface` : `../${modelServiceDir}/interfaces/${fileName$3(name)}.interface`;
4895
- if (usedWireTypes.has(resolved)) lines.push(`import type { ${resolved}, ${wireInterfaceName(resolved)} } from '${relPath}';`);
4896
- else lines.push(`import type { ${resolved} } from '${relPath}';`);
4940
+ if (usedWireTypes.has(resolved)) {
4941
+ const wireName = wireInterfaceName(resolved);
4942
+ if (wireName === resolved) lines.push(`import type { ${resolved} } from '${relPath}';`);
4943
+ else lines.push(`import type { ${resolved}, ${wireName} } from '${relPath}';`);
4944
+ } else lines.push(`import type { ${resolved} } from '${relPath}';`);
4897
4945
  }
4898
4946
  for (const name of requestModels) {
4899
4947
  if (allModels.has(name)) continue;
@@ -5821,11 +5869,13 @@ function generateFixtures$5(spec, ctx) {
5821
5869
  walk(field.type);
5822
5870
  }
5823
5871
  }
5872
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(spec.services);
5873
+ const listMetadataNeeded = collectReferencedListMetadataModels(spec.models, nonPaginatedRefs);
5824
5874
  const seenFixturePaths = /* @__PURE__ */ new Set();
5825
5875
  for (const model of spec.models) {
5826
5876
  if (!fixtureReachable.has(model.name)) continue;
5827
- if (isListMetadataModel(model)) continue;
5828
- if (isListWrapperModel(model)) continue;
5877
+ if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
5878
+ if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
5829
5879
  const fixturePath = `src/${resolveDir(modelToService.get(model.name))}/fixtures/${fileName$3(model.name)}.json`;
5830
5880
  if (seenFixturePaths.has(fixturePath)) continue;
5831
5881
  seenFixturePaths.add(fixturePath);
@@ -5875,6 +5925,15 @@ function generateModelFixture$5(model, modelMap, enumMap) {
5875
5925
  if (field.example !== void 0) fixture[wireName] = field.example;
5876
5926
  else fixture[wireName] = generateFieldValue$4(field.type, field.name, model.name, modelMap, enumMap);
5877
5927
  }
5928
+ if (model.discriminator) {
5929
+ const [firstValue, variantName] = Object.entries(model.discriminator.mapping)[0];
5930
+ fixture[wireFieldName(model.discriminator.property)] = firstValue;
5931
+ const variantModel = modelMap.get(variantName);
5932
+ if (variantModel) for (const field of variantModel.fields) {
5933
+ const wireName = wireFieldName(field.name);
5934
+ if (!(wireName in fixture)) fixture[wireName] = field.example !== void 0 ? field.example : generateFieldValue$4(field.type, field.name, model.name, modelMap, enumMap);
5935
+ }
5936
+ }
5878
5937
  return fixture;
5879
5938
  }
5880
5939
  function generateFieldValue$4(ref, fName, modelName, modelMap, enumMap) {
@@ -6014,11 +6073,12 @@ function generateModels$7(models, ctx, shared) {
6014
6073
  }
6015
6074
  const discriminatedSkip = ctx._discriminatedModelNames;
6016
6075
  const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
6076
+ const listMetadataNeeded = collectReferencedListMetadataModels(models, nonPaginatedRefs);
6017
6077
  for (const originalModel of models) {
6018
6078
  const model = projectedByName.get(originalModel.name) ?? originalModel;
6019
6079
  if (!reachableModels.has(model.name)) continue;
6020
6080
  if (interfaceEligibleModels && !interfaceEligibleModels.has(model.name)) continue;
6021
- if (isListMetadataModel(model)) continue;
6081
+ if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
6022
6082
  if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
6023
6083
  if (discriminatedSkip?.has(model.name)) continue;
6024
6084
  const service = modelToService.get(model.name);
@@ -6208,25 +6268,27 @@ function generateModels$7(models, ctx, shared) {
6208
6268
  lines.push("}");
6209
6269
  }
6210
6270
  lines.push("");
6211
- const seenWireFields = /* @__PURE__ */ new Set();
6212
- if (model.fields.length === 0) lines.push(`export type ${responseName}${typeParams} = object;`);
6213
- else {
6214
- lines.push(`export interface ${responseName}${typeParams} {`);
6215
- for (const field of model.fields) {
6216
- const wireField = wireFieldName(field.name);
6217
- if (seenWireFields.has(wireField)) continue;
6218
- seenWireFields.add(wireField);
6219
- const baselineField = baselineResponse?.fields?.[wireField];
6220
- if (baselineField && baselineTypeResolvable(baselineField.type, importableNames) && baselineFieldCompatible(baselineField, field)) {
6221
- const opt = baselineField.optional ? "?" : "";
6222
- lines.push(` ${wireField}${opt}: ${baselineField.type};`);
6223
- } else {
6224
- const isNewFieldOnExistingModel = baselineResponse && !baselineField;
6225
- const opt = baselineField?.optional === true || !field.required || isNewFieldOnExistingModel ? "?" : "";
6226
- lines.push(` ${wireField}${opt}: ${mapWireTypeRef(field.type, modelWireTypeRefOpts)};`);
6271
+ if (responseName !== domainName) {
6272
+ const seenWireFields = /* @__PURE__ */ new Set();
6273
+ if (model.fields.length === 0) lines.push(`export type ${responseName}${typeParams} = object;`);
6274
+ else {
6275
+ lines.push(`export interface ${responseName}${typeParams} {`);
6276
+ for (const field of model.fields) {
6277
+ const wireField = wireFieldName(field.name);
6278
+ if (seenWireFields.has(wireField)) continue;
6279
+ seenWireFields.add(wireField);
6280
+ const baselineField = baselineResponse?.fields?.[wireField];
6281
+ if (baselineField && baselineTypeResolvable(baselineField.type, importableNames) && baselineFieldCompatible(baselineField, field)) {
6282
+ const opt = baselineField.optional ? "?" : "";
6283
+ lines.push(` ${wireField}${opt}: ${baselineField.type};`);
6284
+ } else {
6285
+ const isNewFieldOnExistingModel = baselineResponse && !baselineField;
6286
+ const opt = baselineField?.optional === true || !field.required || isNewFieldOnExistingModel ? "?" : "";
6287
+ lines.push(` ${wireField}${opt}: ${mapWireTypeRef(field.type, modelWireTypeRefOpts)};`);
6288
+ }
6227
6289
  }
6290
+ lines.push("}");
6228
6291
  }
6229
- lines.push("}");
6230
6292
  }
6231
6293
  const filePath = `src/${dirName}/interfaces/${fileName$3(model.name)}.interface.ts`;
6232
6294
  if (ctx.apiSurface && ctx.targetDir) {
@@ -6354,12 +6416,13 @@ function generateSerializers(models, ctx, shared) {
6354
6416
  }
6355
6417
  const discriminatedSerializerSkip = ctx._discriminatedModelNames;
6356
6418
  const serializerNonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
6419
+ const serializerListMetadataNeeded = collectReferencedListMetadataModels(models, serializerNonPaginatedRefs);
6357
6420
  const eligibleModels = [];
6358
6421
  for (const originalModel of models) {
6359
6422
  const model = projectedByName.get(originalModel.name) ?? originalModel;
6360
6423
  if (!serializerReachable.has(model.name)) continue;
6361
6424
  if (serializerEligibleModels && !serializerEligibleModels.has(model.name)) continue;
6362
- if (isListMetadataModel(model)) continue;
6425
+ if (isListMetadataModel(model) && !serializerListMetadataNeeded.has(model.name)) continue;
6363
6426
  if (isListWrapperModel(model) && !serializerNonPaginatedRefs.has(model.name)) continue;
6364
6427
  if (discriminatedSerializerSkip?.has(model.name)) continue;
6365
6428
  if (!isNodeOwnedService(ctx, modelToService.get(model.name)) && !modelHasNewFields(model, ctx) && !forceGenerateSerializer.has(model.name)) continue;
@@ -7415,7 +7478,11 @@ function buildFieldAssertions(model, accessor, modelMap) {
7415
7478
  const domainField = fieldName$6(field.name);
7416
7479
  const fieldAccessor = isDateTimeFieldType(field.type) ? `${accessor}.${domainField}.toISOString()` : `${accessor}.${domainField}`;
7417
7480
  if (field.example !== void 0) {
7418
- if (typeof field.example === "object" && field.example !== null) assertions.push(`expect(${accessor}.${domainField}).toEqual(${JSON.stringify(field.example)});`);
7481
+ if (field.example === null) {
7482
+ assertions.push(`expect(${accessor}.${domainField}).toBeNull();`);
7483
+ continue;
7484
+ }
7485
+ if (typeof field.example === "object") assertions.push(`expect(${accessor}.${domainField}).toEqual(${JSON.stringify(field.example)});`);
7419
7486
  else {
7420
7487
  const exampleLiteral = typeof field.example === "string" ? `'${field.example}'` : String(field.example);
7421
7488
  assertions.push(`expect(${fieldAccessor}).toBe(${exampleLiteral});`);
@@ -8245,6 +8312,12 @@ function getSurface(ctx) {
8245
8312
  setBaselineInterfaceNames(allInterfaces);
8246
8313
  setInlineEnumUnions(/* @__PURE__ */ new Map());
8247
8314
  setAdoptedModelNames(computeAdoptedModelNames(ctx, surface));
8315
+ const renamed = /* @__PURE__ */ new Set();
8316
+ for (const model of ctx.spec.models) {
8317
+ const resolved = resolveInterfaceName(model.name, ctx);
8318
+ if (resolved !== model.name) renamed.add(resolved);
8319
+ }
8320
+ setStructurallyRenamedDomainNames(renamed);
8248
8321
  return surface;
8249
8322
  }
8250
8323
  /**
@@ -8298,6 +8371,10 @@ function markPriorManifestAutogen(surface, root, priorManifestPaths) {
8298
8371
  if (!relPath.startsWith("src/")) continue;
8299
8372
  if (!surface.files.has(relPath)) continue;
8300
8373
  if (surface.protectedFiles.has(relPath)) continue;
8374
+ if (/\/fixtures\/[^/]+\.json$/.test(relPath)) {
8375
+ surface.autogenFiles.add(relPath);
8376
+ continue;
8377
+ }
8301
8378
  try {
8302
8379
  const text = fs$1.readFileSync(path$1.join(root, relPath), "utf8");
8303
8380
  if (/auto-generated by oagen/i.test(text.slice(0, 400))) {
@@ -9313,9 +9390,10 @@ function generateModels$6(models, ctx) {
9313
9390
  const symbolToOriginalService = /* @__PURE__ */ new Map();
9314
9391
  const emittedFilePaths = /* @__PURE__ */ new Set();
9315
9392
  const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
9393
+ const listMetadataNeeded = collectReferencedListMetadataModels(models, nonPaginatedRefs);
9316
9394
  for (const model of models) {
9317
9395
  if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
9318
- if (isListMetadataModel(model)) continue;
9396
+ if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
9319
9397
  const dirName = resolveDir(modelToService.get(model.name));
9320
9398
  const modelClassName = className$5(model.name);
9321
9399
  const modelFilePath = `src/${ctx.namespace}/${dirName}/models/${fileName$2(model.name)}.py`;
@@ -11338,9 +11416,11 @@ function generateFixtures$4(spec) {
11338
11416
  const modelMap = new Map(spec.models.map((m) => [m.name, m]));
11339
11417
  const enumMap = new Map(spec.enums.map((e) => [e.name, e]));
11340
11418
  const files = [];
11419
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(spec.services);
11420
+ const listMetadataNeeded = collectReferencedListMetadataModels(spec.models, nonPaginatedRefs);
11341
11421
  for (const model of spec.models) {
11342
- if (isListMetadataModel(model)) continue;
11343
- if (isListWrapperModel(model)) continue;
11422
+ if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
11423
+ if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
11344
11424
  if (model.fields.length === 0) continue;
11345
11425
  const fixture = generateModelFixture$4(model, modelMap, enumMap);
11346
11426
  files.push({
@@ -11392,6 +11472,14 @@ function generateModelFixture$4(model, modelMap, enumMap) {
11392
11472
  if (field.example !== void 0) fixture[wireName] = field.example;
11393
11473
  else fixture[wireName] = generateFieldValue$3(field.type, field.name, model.name, modelMap, enumMap);
11394
11474
  }
11475
+ if (model.discriminator) {
11476
+ const [firstValue, variantName] = Object.entries(model.discriminator.mapping)[0];
11477
+ fixture[model.discriminator.property] = firstValue;
11478
+ const variantModel = modelMap.get(variantName);
11479
+ if (variantModel) {
11480
+ for (const field of variantModel.fields) if (!(field.name in fixture)) fixture[field.name] = field.example !== void 0 ? field.example : generateFieldValue$3(field.type, field.name, model.name, modelMap, enumMap);
11481
+ }
11482
+ }
11395
11483
  return fixture;
11396
11484
  }
11397
11485
  function generateFieldValue$3(ref, fieldName, modelName, modelMap, enumMap) {
@@ -12418,7 +12506,9 @@ function generateModelRoundTripTests(spec, ctx) {
12418
12506
  }
12419
12507
  }
12420
12508
  for (const name of responseModelNames) requestOnlyModelNames.delete(name);
12421
- const models = spec.models.filter((m) => !isListWrapperModel(m) && !isListMetadataModel(m) && !requestOnlyModelNames.has(m.name));
12509
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(spec.services);
12510
+ const listMetadataNeeded = collectReferencedListMetadataModels(spec.models, nonPaginatedRefs);
12511
+ const models = spec.models.filter((m) => !(isListWrapperModel(m) && !nonPaginatedRefs.has(m.name)) && !(isListMetadataModel(m) && !listMetadataNeeded.has(m.name)) && !requestOnlyModelNames.has(m.name));
12422
12512
  if (models.length === 0) return null;
12423
12513
  const modelToService = computeSchemaPlacement(spec, ctx).originalModelToService;
12424
12514
  const roundTripDirMap = buildMountDirMap$1(ctx);
@@ -14764,10 +14854,12 @@ function generateModels$4(models, ctx) {
14764
14854
  const requestBodyOnly = collectRequestBodyOnlyModelNames$1(ctx.spec.services, models);
14765
14855
  const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
14766
14856
  const skipAsListWrapper = (m) => isListWrapperModel(m) && !nonPaginatedRefs.has(m.name);
14857
+ const listMetadataNeeded = collectReferencedListMetadataModels(models, nonPaginatedRefs);
14858
+ const skipAsListMetadata = (m) => isListMetadataModel(m) && !listMetadataNeeded.has(m.name);
14767
14859
  const modelHashMap = /* @__PURE__ */ new Map();
14768
14860
  const hashGroups = /* @__PURE__ */ new Map();
14769
14861
  for (const model of models) {
14770
- if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
14862
+ if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
14771
14863
  if (requestBodyOnly.has(model.name)) continue;
14772
14864
  const hash = structuralHash$2(model);
14773
14865
  modelHashMap.set(model.name, hash);
@@ -14784,7 +14876,7 @@ function generateModels$4(models, ctx) {
14784
14876
  }
14785
14877
  const batchedAliases = /* @__PURE__ */ new Set();
14786
14878
  for (const model of models) {
14787
- if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
14879
+ if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
14788
14880
  if (requestBodyOnly.has(model.name)) continue;
14789
14881
  const structName = className$3(model.name);
14790
14882
  const canonicalName = aliasOf.get(model.name);
@@ -16326,9 +16418,11 @@ function generateFixtures$2(spec) {
16326
16418
  const modelMap = new Map(spec.models.map((m) => [m.name, m]));
16327
16419
  const enumMap = new Map(spec.enums.map((e) => [e.name, e]));
16328
16420
  const files = [];
16421
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(spec.services);
16422
+ const listMetadataNeeded = collectReferencedListMetadataModels(spec.models, nonPaginatedRefs);
16329
16423
  for (const model of spec.models) {
16330
- if (isListMetadataModel(model)) continue;
16331
- if (isListWrapperModel(model)) continue;
16424
+ if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
16425
+ if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
16332
16426
  const fixture = model.fields.length === 0 ? {} : generateModelFixture$2(model, modelMap, enumMap);
16333
16427
  files.push({
16334
16428
  path: `testdata/${fileName$1(model.name)}.json`,
@@ -16398,6 +16492,14 @@ function generateModelFixture$2(model, modelMap, enumMap) {
16398
16492
  if (field.example !== void 0) fixture[wireName] = field.example;
16399
16493
  else fixture[wireName] = generateFieldValue$1(field.type, field.name, model.name, modelMap, enumMap);
16400
16494
  }
16495
+ if (model.discriminator) {
16496
+ const [firstValue, variantName] = Object.entries(model.discriminator.mapping)[0];
16497
+ fixture[model.discriminator.property] = firstValue;
16498
+ const variantModel = modelMap.get(variantName);
16499
+ if (variantModel) {
16500
+ for (const field of variantModel.fields) if (!(field.name in fixture)) fixture[field.name] = field.example !== void 0 ? field.example : generateFieldValue$1(field.type, field.name, model.name, modelMap, enumMap);
16501
+ }
16502
+ }
16401
16503
  return fixture;
16402
16504
  }
16403
16505
  function generateFieldValue$1(ref, fName, modelName, modelMap, enumMap) {
@@ -20169,10 +20271,12 @@ function generateModels$2(models, ctx) {
20169
20271
  const files = [];
20170
20272
  const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
20171
20273
  const skipAsListWrapper = (m) => isListWrapperModel(m) && !nonPaginatedRefs.has(m.name);
20274
+ const listMetadataNeeded = collectReferencedListMetadataModels(models, nonPaginatedRefs);
20275
+ const skipAsListMetadata = (m) => isListMetadataModel(m) && !listMetadataNeeded.has(m.name);
20172
20276
  modelAliasMap = null;
20173
20277
  const hashGroupsPass1 = /* @__PURE__ */ new Map();
20174
20278
  for (const model of models) {
20175
- if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
20279
+ if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
20176
20280
  if (model.fields.length === 0 && discriminatedUnions.has(className$1(model.name))) continue;
20177
20281
  const hash = structuralHash(model);
20178
20282
  if (!hashGroupsPass1.has(hash)) hashGroupsPass1.set(hash, []);
@@ -20191,7 +20295,7 @@ function generateModels$2(models, ctx) {
20191
20295
  modelAliasMap = aliasOf;
20192
20296
  const hashGroupsPass2 = /* @__PURE__ */ new Map();
20193
20297
  for (const model of models) {
20194
- if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
20298
+ if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
20195
20299
  if (model.fields.length === 0 && discriminatedUnions.has(className$1(model.name))) continue;
20196
20300
  if (aliasOf.has(model.name)) continue;
20197
20301
  const hash = structuralHash(model);
@@ -20209,7 +20313,7 @@ function generateModels$2(models, ctx) {
20209
20313
  }
20210
20314
  }
20211
20315
  for (const model of models) {
20212
- if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
20316
+ if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
20213
20317
  const typeName = className$1(model.name);
20214
20318
  if (model.fields.length === 0 && discriminatedUnions.has(typeName)) {
20215
20319
  files.push(emitSealedUnion(typeName, discriminatedUnions.get(typeName)));
@@ -20237,7 +20341,7 @@ function generateModels$2(models, ctx) {
20237
20341
  }
20238
20342
  const eventMapping = [];
20239
20343
  for (const model of models) {
20240
- if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
20344
+ if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
20241
20345
  if (aliasOf.has(model.name)) continue;
20242
20346
  if (!isEventEnvelopeModel(model)) continue;
20243
20347
  const eventField = model.fields.find((f) => f.name === "event");
@@ -21548,6 +21652,8 @@ function resolveBodyModel$2(op, ctx) {
21548
21652
  function registerTypeImports(ref, imports, ctx) {
21549
21653
  const mapped = mapTypeRef$2(ref);
21550
21654
  for (const imp of implicitImportsFor(mapped)) imports.add(imp);
21655
+ const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
21656
+ const listMetadataNeeded = collectReferencedListMetadataModels(ctx.spec.models, nonPaginatedRefs);
21551
21657
  walk(ref, (r) => {
21552
21658
  if (r.kind === "enum") {
21553
21659
  const canonicalName = enumCanonicalMap.get(r.name) ?? r.name;
@@ -21555,7 +21661,11 @@ function registerTypeImports(ref, imports, ctx) {
21555
21661
  }
21556
21662
  if (r.kind === "model") {
21557
21663
  const referenced = ctx.spec.models.find((m) => m.name === r.name);
21558
- if (referenced && (isListWrapperModel(referenced) || isListMetadataModel(referenced))) return;
21664
+ if (referenced) {
21665
+ const skipWrapper = isListWrapperModel(referenced) && !nonPaginatedRefs.has(referenced.name);
21666
+ const skipMetadata = isListMetadataModel(referenced) && !listMetadataNeeded.has(referenced.name);
21667
+ if (skipWrapper || skipMetadata) return;
21668
+ }
21559
21669
  imports.add(`com.workos.models.${className$1(r.name)}`);
21560
21670
  }
21561
21671
  });
@@ -23445,7 +23555,10 @@ function mapSorbetType$1(ref) {
23445
23555
  case "array": return `T::Array[${mapSorbetType$1(ref.items)}]`;
23446
23556
  case "model": return `WorkOS::${className(ref.name)}`;
23447
23557
  case "enum": return "String";
23448
- case "nullable": return `T.nilable(${mapSorbetType$1(ref.inner)})`;
23558
+ case "nullable": {
23559
+ const inner = mapSorbetType$1(ref.inner);
23560
+ return inner === "T.untyped" ? inner : `T.nilable(${inner})`;
23561
+ }
23449
23562
  case "literal":
23450
23563
  if (typeof ref.value === "string") return "String";
23451
23564
  if (ref.value === null) return "NilClass";
@@ -25049,6 +25162,7 @@ function generateRbiFiles(spec, ctx) {
25049
25162
  }
25050
25163
  /** Unwrap T.nilable(...) if already wrapped, to avoid double-wrapping. */
25051
25164
  function unwrapNilable(type) {
25165
+ if (type === "T.untyped") return type;
25052
25166
  const match = type.match(/^T\.nilable\((.+)\)$/);
25053
25167
  return match ? match[1] : type;
25054
25168
  }
@@ -26767,6 +26881,18 @@ function generateModelFixture(model, modelMap, enumMap, visiting) {
26767
26881
  const fromExample = exampleFromSpec(field.example, field.type, enumMap);
26768
26882
  result[field.name] = fromExample !== void 0 ? fromExample : exampleFor(field.type, modelMap, enumMap, visiting, field.name);
26769
26883
  }
26884
+ if (model.discriminator) {
26885
+ const [firstValue, variantName] = Object.entries(model.discriminator.mapping)[0];
26886
+ result[model.discriminator.property] = firstValue;
26887
+ const variantModel = modelMap.get(variantName);
26888
+ if (variantModel) {
26889
+ for (const field of variantModel.fields) if (!(field.name in result)) {
26890
+ if (!field.required) continue;
26891
+ const fromExample = exampleFromSpec(field.example, field.type, enumMap);
26892
+ result[field.name] = fromExample !== void 0 ? fromExample : exampleFor(field.type, modelMap, enumMap, visiting, field.name);
26893
+ }
26894
+ }
26895
+ }
26770
26896
  visiting.delete(model.name);
26771
26897
  return result;
26772
26898
  }
@@ -27519,4 +27645,4 @@ const workosEmittersPlugin = {
27519
27645
  //#endregion
27520
27646
  export { pythonEmitter as _, rustExtractor as a, pythonExtractor as c, rustEmitter as d, rubyEmitter as f, phpEmitter as g, goEmitter as h, kotlinExtractor as i, rubyExtractor as l, dotnetEmitter as m, elixirExtractor as n, goExtractor as o, kotlinEmitter as p, dotnetExtractor as r, phpExtractor as s, workosEmittersPlugin as t, nodeExtractor as u, nodeEmitter as v };
27521
27647
 
27522
- //# sourceMappingURL=plugin-DRGwxN88.mjs.map
27648
+ //# sourceMappingURL=plugin-D0qLBiGv.mjs.map