@workos/oagen-emitters 0.14.0 → 0.14.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.
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +18 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{plugin-BxVeu2v9.mjs → plugin-BbSmT2kj.mjs} +266 -64
- package/dist/plugin-BbSmT2kj.mjs.map +1 -0
- package/dist/plugin.mjs +1 -1
- package/package.json +1 -1
- package/src/dotnet/models.ts +31 -6
- package/src/dotnet/type-map.ts +18 -1
- package/src/go/fixtures.ts +6 -2
- package/src/go/models.ts +18 -3
- package/src/kotlin/models.ts +22 -6
- package/src/kotlin/resources.ts +17 -2
- package/src/node/fixtures.ts +13 -3
- package/src/node/index.ts +92 -4
- package/src/node/models.ts +58 -32
- package/src/node/naming.ts +25 -1
- package/src/node/resources.ts +9 -1
- package/src/node/tests.ts +8 -1
- package/src/node/utils.ts +6 -1
- package/src/php/models.ts +11 -2
- package/src/python/fixtures.ts +6 -2
- package/src/python/models.ts +18 -3
- package/src/python/resources.ts +8 -2
- package/src/python/tests.ts +7 -1
- package/src/ruby/index.ts +3 -3
- package/src/ruby/models.ts +13 -3
- package/src/ruby/parameter-groups.ts +4 -2
- package/src/ruby/rbi.ts +1 -0
- package/src/rust/models.ts +5 -1
- package/src/rust/resources.ts +4 -1
- package/src/shared/model-utils.ts +70 -3
- package/test/node/naming.test.ts +45 -1
- package/test/node/tests.test.ts +69 -0
- package/test/rust/models.test.ts +3 -3
- package/test/shared/model-utils.test.ts +97 -0
- package/dist/plugin-BxVeu2v9.mjs.map +0 -1
|
@@ -2286,6 +2286,24 @@ dumper.dump;
|
|
|
2286
2286
|
//#endregion
|
|
2287
2287
|
//#region src/shared/model-utils.ts
|
|
2288
2288
|
/**
|
|
2289
|
+
* Collect model names referenced as the return type of any non-paginated
|
|
2290
|
+
* operation. The list-wrapper skip rule below assumes a wrapper is always
|
|
2291
|
+
* replaced by the SDK's pagination machinery — but a few endpoints
|
|
2292
|
+
* (e.g. `GET /vault/v1/kv/{id}/versions`) have a list-envelope response
|
|
2293
|
+
* shape with no pagination params, so the parser leaves them as a plain
|
|
2294
|
+
* model reference. We must still emit those wrappers as regular models;
|
|
2295
|
+
* otherwise the generated resource code references an undefined name.
|
|
2296
|
+
*/
|
|
2297
|
+
function collectNonPaginatedResponseModelNames(services) {
|
|
2298
|
+
const names = /* @__PURE__ */ new Set();
|
|
2299
|
+
for (const service of services) for (const op of service.operations) {
|
|
2300
|
+
if (op.pagination) continue;
|
|
2301
|
+
walkTypeRef(op.response, { model: (r) => names.add(r.name) });
|
|
2302
|
+
for (const sr of op.successResponses ?? []) walkTypeRef(sr.type, { model: (r) => names.add(r.name) });
|
|
2303
|
+
}
|
|
2304
|
+
return names;
|
|
2305
|
+
}
|
|
2306
|
+
/**
|
|
2289
2307
|
* Detect whether a model is a list wrapper -- the standard paginated
|
|
2290
2308
|
* list envelope with `data` (array), `list_metadata`, and optionally `object: 'list'`.
|
|
2291
2309
|
*
|
|
@@ -2316,6 +2334,35 @@ function isListMetadataModel(model) {
|
|
|
2316
2334
|
if (!before || !after) return false;
|
|
2317
2335
|
return isNullableString(before) && isNullableString(after);
|
|
2318
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
|
+
}
|
|
2319
2366
|
/** Check if a field type is nullable string (nullable<string> or just string). */
|
|
2320
2367
|
function isNullableString(field) {
|
|
2321
2368
|
if (field.type.kind === "primitive" && field.type.type === "string") return true;
|
|
@@ -2636,7 +2683,7 @@ function detectDiscriminators(models) {
|
|
|
2636
2683
|
* Returns a new array of enriched models (original models are not mutated).
|
|
2637
2684
|
* Synthetic enums are stored internally; retrieve them via `getSyntheticEnums()`.
|
|
2638
2685
|
*/
|
|
2639
|
-
function enrichModelsFromSpec(models) {
|
|
2686
|
+
function enrichModelsFromSpec(models, enums = []) {
|
|
2640
2687
|
if (!loadRawSpec()) {
|
|
2641
2688
|
_lastSyntheticEnums = [];
|
|
2642
2689
|
return models;
|
|
@@ -2646,6 +2693,10 @@ function enrichModelsFromSpec(models) {
|
|
|
2646
2693
|
collector.usedNames.add(m.name);
|
|
2647
2694
|
collector.usedNames.add(toSnakeCase(m.name));
|
|
2648
2695
|
}
|
|
2696
|
+
for (const e of enums) {
|
|
2697
|
+
collector.usedNames.add(e.name);
|
|
2698
|
+
collector.usedNames.add(toSnakeCase(e.name));
|
|
2699
|
+
}
|
|
2649
2700
|
const enriched2 = models.map((model) => {
|
|
2650
2701
|
const rawSchema = lookupRawSchema(model.name);
|
|
2651
2702
|
if (!rawSchema) return model;
|
|
@@ -2804,6 +2855,22 @@ function isAdoptedModelName(name) {
|
|
|
2804
2855
|
return adoptedModelNames.has(name);
|
|
2805
2856
|
}
|
|
2806
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
|
+
/**
|
|
2807
2874
|
* Wire/response interface name.
|
|
2808
2875
|
*
|
|
2809
2876
|
* Resolution order:
|
|
@@ -2826,7 +2893,7 @@ function wireInterfaceName(domainName) {
|
|
|
2826
2893
|
if (domainName.endsWith("Response")) {
|
|
2827
2894
|
const wireForm = `${domainName}Wire`;
|
|
2828
2895
|
if (baselineInterfaceNames.has(wireForm)) return wireForm;
|
|
2829
|
-
if (baselineInterfaceNames.has(domainName)) return domainName;
|
|
2896
|
+
if (structurallyRenamedDomainNames.has(domainName) && baselineInterfaceNames.has(domainName)) return domainName;
|
|
2830
2897
|
return wireForm;
|
|
2831
2898
|
}
|
|
2832
2899
|
return `${domainName}Response`;
|
|
@@ -4870,8 +4937,11 @@ function generateResourceClass(service, ctx) {
|
|
|
4870
4937
|
importedTypeNames.add(resolved);
|
|
4871
4938
|
const modelServiceDir = resolveDir(modelToService.get(name));
|
|
4872
4939
|
const relPath = modelServiceDir === serviceDir ? `./interfaces/${fileName$3(name)}.interface` : `../${modelServiceDir}/interfaces/${fileName$3(name)}.interface`;
|
|
4873
|
-
if (usedWireTypes.has(resolved))
|
|
4874
|
-
|
|
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}';`);
|
|
4875
4945
|
}
|
|
4876
4946
|
for (const name of requestModels) {
|
|
4877
4947
|
if (allModels.has(name)) continue;
|
|
@@ -5799,11 +5869,13 @@ function generateFixtures$5(spec, ctx) {
|
|
|
5799
5869
|
walk(field.type);
|
|
5800
5870
|
}
|
|
5801
5871
|
}
|
|
5872
|
+
const nonPaginatedRefs = collectNonPaginatedResponseModelNames(spec.services);
|
|
5873
|
+
const listMetadataNeeded = collectReferencedListMetadataModels(spec.models, nonPaginatedRefs);
|
|
5802
5874
|
const seenFixturePaths = /* @__PURE__ */ new Set();
|
|
5803
5875
|
for (const model of spec.models) {
|
|
5804
5876
|
if (!fixtureReachable.has(model.name)) continue;
|
|
5805
|
-
if (isListMetadataModel(model)) continue;
|
|
5806
|
-
if (isListWrapperModel(model)) continue;
|
|
5877
|
+
if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
|
|
5878
|
+
if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
|
|
5807
5879
|
const fixturePath = `src/${resolveDir(modelToService.get(model.name))}/fixtures/${fileName$3(model.name)}.json`;
|
|
5808
5880
|
if (seenFixturePaths.has(fixturePath)) continue;
|
|
5809
5881
|
seenFixturePaths.add(fixturePath);
|
|
@@ -5991,12 +6063,14 @@ function generateModels$7(models, ctx, shared) {
|
|
|
5991
6063
|
}
|
|
5992
6064
|
}
|
|
5993
6065
|
const discriminatedSkip = ctx._discriminatedModelNames;
|
|
6066
|
+
const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
|
|
6067
|
+
const listMetadataNeeded = collectReferencedListMetadataModels(models, nonPaginatedRefs);
|
|
5994
6068
|
for (const originalModel of models) {
|
|
5995
6069
|
const model = projectedByName.get(originalModel.name) ?? originalModel;
|
|
5996
6070
|
if (!reachableModels.has(model.name)) continue;
|
|
5997
6071
|
if (interfaceEligibleModels && !interfaceEligibleModels.has(model.name)) continue;
|
|
5998
|
-
if (isListMetadataModel(model)) continue;
|
|
5999
|
-
if (isListWrapperModel(model)) continue;
|
|
6072
|
+
if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
|
|
6073
|
+
if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
|
|
6000
6074
|
if (discriminatedSkip?.has(model.name)) continue;
|
|
6001
6075
|
const service = modelToService.get(model.name);
|
|
6002
6076
|
const isOwnedModel = isNodeOwnedService(ctx, service);
|
|
@@ -6185,25 +6259,27 @@ function generateModels$7(models, ctx, shared) {
|
|
|
6185
6259
|
lines.push("}");
|
|
6186
6260
|
}
|
|
6187
6261
|
lines.push("");
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
const
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6262
|
+
if (responseName !== domainName) {
|
|
6263
|
+
const seenWireFields = /* @__PURE__ */ new Set();
|
|
6264
|
+
if (model.fields.length === 0) lines.push(`export type ${responseName}${typeParams} = object;`);
|
|
6265
|
+
else {
|
|
6266
|
+
lines.push(`export interface ${responseName}${typeParams} {`);
|
|
6267
|
+
for (const field of model.fields) {
|
|
6268
|
+
const wireField = wireFieldName(field.name);
|
|
6269
|
+
if (seenWireFields.has(wireField)) continue;
|
|
6270
|
+
seenWireFields.add(wireField);
|
|
6271
|
+
const baselineField = baselineResponse?.fields?.[wireField];
|
|
6272
|
+
if (baselineField && baselineTypeResolvable(baselineField.type, importableNames) && baselineFieldCompatible(baselineField, field)) {
|
|
6273
|
+
const opt = baselineField.optional ? "?" : "";
|
|
6274
|
+
lines.push(` ${wireField}${opt}: ${baselineField.type};`);
|
|
6275
|
+
} else {
|
|
6276
|
+
const isNewFieldOnExistingModel = baselineResponse && !baselineField;
|
|
6277
|
+
const opt = baselineField?.optional === true || !field.required || isNewFieldOnExistingModel ? "?" : "";
|
|
6278
|
+
lines.push(` ${wireField}${opt}: ${mapWireTypeRef(field.type, modelWireTypeRefOpts)};`);
|
|
6279
|
+
}
|
|
6204
6280
|
}
|
|
6281
|
+
lines.push("}");
|
|
6205
6282
|
}
|
|
6206
|
-
lines.push("}");
|
|
6207
6283
|
}
|
|
6208
6284
|
const filePath = `src/${dirName}/interfaces/${fileName$3(model.name)}.interface.ts`;
|
|
6209
6285
|
if (ctx.apiSurface && ctx.targetDir) {
|
|
@@ -6330,13 +6406,15 @@ function generateSerializers(models, ctx, shared) {
|
|
|
6330
6406
|
}
|
|
6331
6407
|
}
|
|
6332
6408
|
const discriminatedSerializerSkip = ctx._discriminatedModelNames;
|
|
6409
|
+
const serializerNonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
|
|
6410
|
+
const serializerListMetadataNeeded = collectReferencedListMetadataModels(models, serializerNonPaginatedRefs);
|
|
6333
6411
|
const eligibleModels = [];
|
|
6334
6412
|
for (const originalModel of models) {
|
|
6335
6413
|
const model = projectedByName.get(originalModel.name) ?? originalModel;
|
|
6336
6414
|
if (!serializerReachable.has(model.name)) continue;
|
|
6337
6415
|
if (serializerEligibleModels && !serializerEligibleModels.has(model.name)) continue;
|
|
6338
|
-
if (isListMetadataModel(model)) continue;
|
|
6339
|
-
if (isListWrapperModel(model)) continue;
|
|
6416
|
+
if (isListMetadataModel(model) && !serializerListMetadataNeeded.has(model.name)) continue;
|
|
6417
|
+
if (isListWrapperModel(model) && !serializerNonPaginatedRefs.has(model.name)) continue;
|
|
6340
6418
|
if (discriminatedSerializerSkip?.has(model.name)) continue;
|
|
6341
6419
|
if (!isNodeOwnedService(ctx, modelToService.get(model.name)) && !modelHasNewFields(model, ctx) && !forceGenerateSerializer.has(model.name)) continue;
|
|
6342
6420
|
eligibleModels.push(model);
|
|
@@ -7391,7 +7469,11 @@ function buildFieldAssertions(model, accessor, modelMap) {
|
|
|
7391
7469
|
const domainField = fieldName$6(field.name);
|
|
7392
7470
|
const fieldAccessor = isDateTimeFieldType(field.type) ? `${accessor}.${domainField}.toISOString()` : `${accessor}.${domainField}`;
|
|
7393
7471
|
if (field.example !== void 0) {
|
|
7394
|
-
if (
|
|
7472
|
+
if (field.example === null) {
|
|
7473
|
+
assertions.push(`expect(${accessor}.${domainField}).toBeNull();`);
|
|
7474
|
+
continue;
|
|
7475
|
+
}
|
|
7476
|
+
if (typeof field.example === "object") assertions.push(`expect(${accessor}.${domainField}).toEqual(${JSON.stringify(field.example)});`);
|
|
7395
7477
|
else {
|
|
7396
7478
|
const exampleLiteral = typeof field.example === "string" ? `'${field.example}'` : String(field.example);
|
|
7397
7479
|
assertions.push(`expect(${fieldAccessor}).toBe(${exampleLiteral});`);
|
|
@@ -8183,6 +8265,22 @@ function withNodeOperationOverrides(ctx) {
|
|
|
8183
8265
|
* one oagen run, so we walk the target SDK once and reuse it.
|
|
8184
8266
|
*/
|
|
8185
8267
|
const surfaceCache = /* @__PURE__ */ new WeakMap();
|
|
8268
|
+
/**
|
|
8269
|
+
* Paths the node emitter has produced so far in this ctx, accumulated across
|
|
8270
|
+
* `applyLiveSurface` calls. Drives `carryForwardManagedFiles` so files in the
|
|
8271
|
+
* prior manifest that we did not re-emit this run still land in the new
|
|
8272
|
+
* manifest as "still managed" — without that, the orchestrator's prune diff
|
|
8273
|
+
* treats every untouched autogen file as stale.
|
|
8274
|
+
*/
|
|
8275
|
+
const emittedPathsCache = /* @__PURE__ */ new WeakMap();
|
|
8276
|
+
function getEmittedPaths(ctx) {
|
|
8277
|
+
let set = emittedPathsCache.get(ctx);
|
|
8278
|
+
if (!set) {
|
|
8279
|
+
set = /* @__PURE__ */ new Set();
|
|
8280
|
+
emittedPathsCache.set(ctx, set);
|
|
8281
|
+
}
|
|
8282
|
+
return set;
|
|
8283
|
+
}
|
|
8186
8284
|
function getSurface(ctx) {
|
|
8187
8285
|
let surface = surfaceCache.get(ctx);
|
|
8188
8286
|
if (surface) return surface;
|
|
@@ -8205,6 +8303,12 @@ function getSurface(ctx) {
|
|
|
8205
8303
|
setBaselineInterfaceNames(allInterfaces);
|
|
8206
8304
|
setInlineEnumUnions(/* @__PURE__ */ new Map());
|
|
8207
8305
|
setAdoptedModelNames(computeAdoptedModelNames(ctx, surface));
|
|
8306
|
+
const renamed = /* @__PURE__ */ new Set();
|
|
8307
|
+
for (const model of ctx.spec.models) {
|
|
8308
|
+
const resolved = resolveInterfaceName(model.name, ctx);
|
|
8309
|
+
if (resolved !== model.name) renamed.add(resolved);
|
|
8310
|
+
}
|
|
8311
|
+
setStructurallyRenamedDomainNames(renamed);
|
|
8208
8312
|
return surface;
|
|
8209
8313
|
}
|
|
8210
8314
|
/**
|
|
@@ -8229,8 +8333,10 @@ function getSurface(ctx) {
|
|
|
8229
8333
|
* `integrateTarget: false` files (smoke-manifest.json etc.) are also dropped:
|
|
8230
8334
|
* with no `--target` step they would otherwise land as untracked cruft.
|
|
8231
8335
|
*
|
|
8232
|
-
* Note:
|
|
8233
|
-
*
|
|
8336
|
+
* Note: the carry-forward step in `generateTests` re-declares prior-manifest
|
|
8337
|
+
* paths we didn't touch this run, so the orchestrator's prune diff stays
|
|
8338
|
+
* accurate without needing `--no-prune` at the call site. See
|
|
8339
|
+
* `carryForwardManagedFiles` below.
|
|
8234
8340
|
*/
|
|
8235
8341
|
/**
|
|
8236
8342
|
* `*.spec.ts`, `*.test.ts`, and JSON fixtures under `fixtures/` are owned by
|
|
@@ -8380,6 +8486,52 @@ function applyLiveSurface(files, ctx, surface) {
|
|
|
8380
8486
|
if (f.content && !f.content.endsWith("\n")) f.content += "\n";
|
|
8381
8487
|
out.push(f);
|
|
8382
8488
|
}
|
|
8489
|
+
const emitted = getEmittedPaths(ctx);
|
|
8490
|
+
for (const f of out) emitted.add(f.path);
|
|
8491
|
+
return out;
|
|
8492
|
+
}
|
|
8493
|
+
/**
|
|
8494
|
+
* Re-declare prior-manifest paths that we did not emit this run so manifest
|
|
8495
|
+
* pruning can tell "intentionally removed" from "untouched but still managed."
|
|
8496
|
+
*
|
|
8497
|
+
* The node emitter only outputs files it actually wants to write each run —
|
|
8498
|
+
* untouched-but-up-to-date autogen files don't come back through any
|
|
8499
|
+
* `generateXxx` method. Without this carry-forward, the orchestrator's
|
|
8500
|
+
* `prevManifest.files − currentEmission` diff treats every such file as stale
|
|
8501
|
+
* and prunes the whole tree on a regen. That's why `scripts/sdk-generate.sh`
|
|
8502
|
+
* historically paired the node emitter with `--no-prune` — at the cost of
|
|
8503
|
+
* never pruning legitimately-removed files (e.g. an enum file orphaned by a
|
|
8504
|
+
* `schemaNameTransform` rename like `RadarAction` → `RadarListAction`).
|
|
8505
|
+
*
|
|
8506
|
+
* The carry-forward entry uses `skipIfExists: true`, so writer.ts skips the
|
|
8507
|
+
* write and only ensures the header is present (no-op for files that already
|
|
8508
|
+
* have it). The path still lands in `outputEmittedPaths` and therefore in the
|
|
8509
|
+
* new manifest, which restores correct prune semantics.
|
|
8510
|
+
*
|
|
8511
|
+
* Files dropped from the carry-forward set:
|
|
8512
|
+
* - Not on disk anymore (file was hand-deleted — let prune confirm absence).
|
|
8513
|
+
* - `@oagen-ignore-file` protected (user has explicitly taken ownership).
|
|
8514
|
+
* - `.ts` files that no longer carry the auto-gen header (user has taken
|
|
8515
|
+
* ownership in-place; the next prune cycle will clear the manifest entry).
|
|
8516
|
+
*/
|
|
8517
|
+
function carryForwardManagedFiles(ctx, surface) {
|
|
8518
|
+
const priorPaths = ctx.priorTargetManifestPaths;
|
|
8519
|
+
if (!priorPaths || priorPaths.size === 0) return [];
|
|
8520
|
+
const emitted = getEmittedPaths(ctx);
|
|
8521
|
+
const out = [];
|
|
8522
|
+
for (const relPath of priorPaths) {
|
|
8523
|
+
if (emitted.has(relPath)) continue;
|
|
8524
|
+
if (!surface.files.has(relPath)) continue;
|
|
8525
|
+
if (surface.protectedFiles.has(relPath)) continue;
|
|
8526
|
+
if (relPath.endsWith(".ts") && !surface.autogenFiles.has(relPath)) continue;
|
|
8527
|
+
out.push({
|
|
8528
|
+
path: relPath,
|
|
8529
|
+
content: "",
|
|
8530
|
+
skipIfExists: true,
|
|
8531
|
+
headerPlacement: "skip"
|
|
8532
|
+
});
|
|
8533
|
+
emitted.add(relPath);
|
|
8534
|
+
}
|
|
8383
8535
|
return out;
|
|
8384
8536
|
}
|
|
8385
8537
|
/**
|
|
@@ -8446,9 +8598,8 @@ const nodeEmitter = {
|
|
|
8446
8598
|
},
|
|
8447
8599
|
generateTests(spec, ctx) {
|
|
8448
8600
|
const nodeCtx = withNodeOperationOverrides(ctx);
|
|
8449
|
-
if (!nodeOptions(nodeCtx).regenerateOwnedTests) return [];
|
|
8450
8601
|
const surface = getSurface(nodeCtx);
|
|
8451
|
-
return applyLiveSurface(generateTests$7(spec, nodeCtx), nodeCtx, surface);
|
|
8602
|
+
return [...nodeOptions(nodeCtx).regenerateOwnedTests ? applyLiveSurface(generateTests$7(spec, nodeCtx), nodeCtx, surface) : [], ...carryForwardManagedFiles(nodeCtx, surface)];
|
|
8452
8603
|
},
|
|
8453
8604
|
buildOperationsMap() {
|
|
8454
8605
|
return {};
|
|
@@ -9225,9 +9376,11 @@ function generateModels$6(models, ctx) {
|
|
|
9225
9376
|
const symbolToFile = /* @__PURE__ */ new Map();
|
|
9226
9377
|
const symbolToOriginalService = /* @__PURE__ */ new Map();
|
|
9227
9378
|
const emittedFilePaths = /* @__PURE__ */ new Set();
|
|
9379
|
+
const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
|
|
9380
|
+
const listMetadataNeeded = collectReferencedListMetadataModels(models, nonPaginatedRefs);
|
|
9228
9381
|
for (const model of models) {
|
|
9229
|
-
if (isListWrapperModel(model)) continue;
|
|
9230
|
-
if (isListMetadataModel(model)) continue;
|
|
9382
|
+
if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
|
|
9383
|
+
if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
|
|
9231
9384
|
const dirName = resolveDir(modelToService.get(model.name));
|
|
9232
9385
|
const modelClassName = className$5(model.name);
|
|
9233
9386
|
const modelFilePath = `src/${ctx.namespace}/${dirName}/models/${fileName$2(model.name)}.py`;
|
|
@@ -10640,7 +10793,9 @@ function generateResources$6(services, ctx) {
|
|
|
10640
10793
|
}
|
|
10641
10794
|
for (const op of allOperations) {
|
|
10642
10795
|
const plan = planOperation(op);
|
|
10643
|
-
if (plan.responseModelName
|
|
10796
|
+
if (plan.responseModelName) {
|
|
10797
|
+
if (!listWrapperNames.has(plan.responseModelName) || !plan.isPaginated) modelImports.add(plan.responseModelName);
|
|
10798
|
+
}
|
|
10644
10799
|
if (op.requestBody?.kind === "model") {
|
|
10645
10800
|
const requestBodyRef = op.requestBody;
|
|
10646
10801
|
modelImports.add(requestBodyRef.name);
|
|
@@ -11248,9 +11403,11 @@ function generateFixtures$4(spec) {
|
|
|
11248
11403
|
const modelMap = new Map(spec.models.map((m) => [m.name, m]));
|
|
11249
11404
|
const enumMap = new Map(spec.enums.map((e) => [e.name, e]));
|
|
11250
11405
|
const files = [];
|
|
11406
|
+
const nonPaginatedRefs = collectNonPaginatedResponseModelNames(spec.services);
|
|
11407
|
+
const listMetadataNeeded = collectReferencedListMetadataModels(spec.models, nonPaginatedRefs);
|
|
11251
11408
|
for (const model of spec.models) {
|
|
11252
|
-
if (isListMetadataModel(model)) continue;
|
|
11253
|
-
if (isListWrapperModel(model)) continue;
|
|
11409
|
+
if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
|
|
11410
|
+
if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
|
|
11254
11411
|
if (model.fields.length === 0) continue;
|
|
11255
11412
|
const fixture = generateModelFixture$4(model, modelMap, enumMap);
|
|
11256
11413
|
files.push({
|
|
@@ -12328,7 +12485,9 @@ function generateModelRoundTripTests(spec, ctx) {
|
|
|
12328
12485
|
}
|
|
12329
12486
|
}
|
|
12330
12487
|
for (const name of responseModelNames) requestOnlyModelNames.delete(name);
|
|
12331
|
-
const
|
|
12488
|
+
const nonPaginatedRefs = collectNonPaginatedResponseModelNames(spec.services);
|
|
12489
|
+
const listMetadataNeeded = collectReferencedListMetadataModels(spec.models, nonPaginatedRefs);
|
|
12490
|
+
const models = spec.models.filter((m) => !(isListWrapperModel(m) && !nonPaginatedRefs.has(m.name)) && !(isListMetadataModel(m) && !listMetadataNeeded.has(m.name)) && !requestOnlyModelNames.has(m.name));
|
|
12332
12491
|
if (models.length === 0) return null;
|
|
12333
12492
|
const modelToService = computeSchemaPlacement(spec, ctx).originalModelToService;
|
|
12334
12493
|
const roundTripDirMap = buildMountDirMap$1(ctx);
|
|
@@ -12769,9 +12928,10 @@ function generateModels$5(models, ctx) {
|
|
|
12769
12928
|
].join("\n"),
|
|
12770
12929
|
overwriteExisting: true
|
|
12771
12930
|
});
|
|
12931
|
+
const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
|
|
12772
12932
|
for (const model of models) {
|
|
12773
12933
|
if (isListMetadataModel(model)) continue;
|
|
12774
|
-
if (isListWrapperModel(model)) continue;
|
|
12934
|
+
if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
|
|
12775
12935
|
const name = className$4(model.name);
|
|
12776
12936
|
const lines = [];
|
|
12777
12937
|
lines.push(`namespace ${ctx.namespacePascal}\\Resource;`);
|
|
@@ -14671,10 +14831,14 @@ function generateModels$4(models, ctx) {
|
|
|
14671
14831
|
lines.push(`package ${ctx.namespace}`);
|
|
14672
14832
|
lines.push("");
|
|
14673
14833
|
const requestBodyOnly = collectRequestBodyOnlyModelNames$1(ctx.spec.services, models);
|
|
14834
|
+
const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
|
|
14835
|
+
const skipAsListWrapper = (m) => isListWrapperModel(m) && !nonPaginatedRefs.has(m.name);
|
|
14836
|
+
const listMetadataNeeded = collectReferencedListMetadataModels(models, nonPaginatedRefs);
|
|
14837
|
+
const skipAsListMetadata = (m) => isListMetadataModel(m) && !listMetadataNeeded.has(m.name);
|
|
14674
14838
|
const modelHashMap = /* @__PURE__ */ new Map();
|
|
14675
14839
|
const hashGroups = /* @__PURE__ */ new Map();
|
|
14676
14840
|
for (const model of models) {
|
|
14677
|
-
if (
|
|
14841
|
+
if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
|
|
14678
14842
|
if (requestBodyOnly.has(model.name)) continue;
|
|
14679
14843
|
const hash = structuralHash$2(model);
|
|
14680
14844
|
modelHashMap.set(model.name, hash);
|
|
@@ -14691,7 +14855,7 @@ function generateModels$4(models, ctx) {
|
|
|
14691
14855
|
}
|
|
14692
14856
|
const batchedAliases = /* @__PURE__ */ new Set();
|
|
14693
14857
|
for (const model of models) {
|
|
14694
|
-
if (
|
|
14858
|
+
if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
|
|
14695
14859
|
if (requestBodyOnly.has(model.name)) continue;
|
|
14696
14860
|
const structName = className$3(model.name);
|
|
14697
14861
|
const canonicalName = aliasOf.get(model.name);
|
|
@@ -16233,9 +16397,11 @@ function generateFixtures$2(spec) {
|
|
|
16233
16397
|
const modelMap = new Map(spec.models.map((m) => [m.name, m]));
|
|
16234
16398
|
const enumMap = new Map(spec.enums.map((e) => [e.name, e]));
|
|
16235
16399
|
const files = [];
|
|
16400
|
+
const nonPaginatedRefs = collectNonPaginatedResponseModelNames(spec.services);
|
|
16401
|
+
const listMetadataNeeded = collectReferencedListMetadataModels(spec.models, nonPaginatedRefs);
|
|
16236
16402
|
for (const model of spec.models) {
|
|
16237
|
-
if (isListMetadataModel(model)) continue;
|
|
16238
|
-
if (isListWrapperModel(model)) continue;
|
|
16403
|
+
if (isListMetadataModel(model) && !listMetadataNeeded.has(model.name)) continue;
|
|
16404
|
+
if (isListWrapperModel(model) && !nonPaginatedRefs.has(model.name)) continue;
|
|
16239
16405
|
const fixture = model.fields.length === 0 ? {} : generateModelFixture$2(model, modelMap, enumMap);
|
|
16240
16406
|
files.push({
|
|
16241
16407
|
path: `testdata/${fileName$1(model.name)}.json`,
|
|
@@ -17324,7 +17490,15 @@ function isEnumRef(ref) {
|
|
|
17324
17490
|
* omission so the API returns a clear `missing required field` error instead
|
|
17325
17491
|
* of a confusing 422.
|
|
17326
17492
|
*/
|
|
17327
|
-
function emitJsonPropertyAttributes(
|
|
17493
|
+
function emitJsonPropertyAttributes(wireName, options = {}) {
|
|
17494
|
+
if (options.explicitWireName) {
|
|
17495
|
+
if (options.isRequiredEnum) return [
|
|
17496
|
+
` [JsonProperty("${wireName}", DefaultValueHandling = DefaultValueHandling.Ignore)]`,
|
|
17497
|
+
` [STJS.JsonIgnore(Condition = STJS.JsonIgnoreCondition.WhenWritingDefault)]`,
|
|
17498
|
+
` [STJS.JsonPropertyName("${wireName}")]`
|
|
17499
|
+
];
|
|
17500
|
+
return [` [JsonProperty("${wireName}")]`, ` [STJS.JsonPropertyName("${wireName}")]`];
|
|
17501
|
+
}
|
|
17328
17502
|
if (options.isRequiredEnum) return [` [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]`, ` [STJS.JsonIgnore(Condition = STJS.JsonIgnoreCondition.WhenWritingDefault)]`];
|
|
17329
17503
|
return [];
|
|
17330
17504
|
}
|
|
@@ -17377,16 +17551,23 @@ function generateModels$3(models, ctx, discCtx) {
|
|
|
17377
17551
|
const files = [];
|
|
17378
17552
|
primeModelAliases(models);
|
|
17379
17553
|
const requestBodyOnlyNames = collectRequestBodyOnlyModelNames(ctx.spec.services, models);
|
|
17554
|
+
const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
|
|
17555
|
+
const skipAsListWrapper = (m) => isListWrapperModel(m) && !nonPaginatedRefs.has(m.name);
|
|
17380
17556
|
const baseFieldLookup = /* @__PURE__ */ new Map();
|
|
17381
17557
|
if (discCtx) {
|
|
17382
17558
|
for (const model of models) if (discCtx.discriminatorBases.has(model.name)) {
|
|
17559
|
+
const baseClassName = modelClassName(model.name);
|
|
17383
17560
|
const fieldMap = /* @__PURE__ */ new Map();
|
|
17384
|
-
for (const field of model.fields)
|
|
17561
|
+
for (const field of model.fields) {
|
|
17562
|
+
let csName = fieldName$2(field.name);
|
|
17563
|
+
if (csName === baseClassName) csName = `${csName}Value`;
|
|
17564
|
+
fieldMap.set(csName, mapTypeRef$3(field.type));
|
|
17565
|
+
}
|
|
17385
17566
|
baseFieldLookup.set(model.name, fieldMap);
|
|
17386
17567
|
}
|
|
17387
17568
|
}
|
|
17388
17569
|
for (const model of models) {
|
|
17389
|
-
if (
|
|
17570
|
+
if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
|
|
17390
17571
|
if (requestBodyOnlyNames.has(model.name)) continue;
|
|
17391
17572
|
const csClassName = modelClassName(model.name);
|
|
17392
17573
|
if (isModelAlias(model.name)) continue;
|
|
@@ -17394,7 +17575,7 @@ function generateModels$3(models, ctx, discCtx) {
|
|
|
17394
17575
|
const fieldTypes = model.fields.map((f) => mapTypeRef$3(f.type));
|
|
17395
17576
|
const needsCollections = fieldTypes.some((t) => t.startsWith("List<") || t.startsWith("Dictionary<"));
|
|
17396
17577
|
const needsSystem = fieldTypes.some((t) => t.includes("DateTimeOffset"));
|
|
17397
|
-
const needsJsonAttrs = model.fields.some((f) => f.required && isEnumRef(f.type));
|
|
17578
|
+
const needsJsonAttrs = model.fields.some((f) => fieldName$2(f.name) === csClassName) || model.fields.some((f) => f.required && isEnumRef(f.type));
|
|
17398
17579
|
lines.push(`namespace ${ctx.namespacePascal}`);
|
|
17399
17580
|
lines.push("{");
|
|
17400
17581
|
if (needsSystem) lines.push(" using System;");
|
|
@@ -17420,7 +17601,9 @@ function generateModels$3(models, ctx, discCtx) {
|
|
|
17420
17601
|
const dictObjectFields = [];
|
|
17421
17602
|
const seenFieldNames = /* @__PURE__ */ new Set();
|
|
17422
17603
|
for (const field of model.fields) {
|
|
17423
|
-
|
|
17604
|
+
let csFieldName = fieldName$2(field.name);
|
|
17605
|
+
const collidesWithClassName = csFieldName === csClassName;
|
|
17606
|
+
if (collidesWithClassName) csFieldName = `${csFieldName}Value`;
|
|
17424
17607
|
if (seenFieldNames.has(csFieldName)) continue;
|
|
17425
17608
|
seenFieldNames.add(csFieldName);
|
|
17426
17609
|
let useNewModifier = false;
|
|
@@ -17465,7 +17648,10 @@ function generateModels$3(models, ctx, discCtx) {
|
|
|
17465
17648
|
lines.push(` [System.Obsolete("${msg}")]`);
|
|
17466
17649
|
}
|
|
17467
17650
|
const isRequiredEnum = field.required && isEnumRef(field.type) && constInit === null;
|
|
17468
|
-
lines.push(...emitJsonPropertyAttributes(field.name, {
|
|
17651
|
+
lines.push(...emitJsonPropertyAttributes(field.name, {
|
|
17652
|
+
isRequiredEnum,
|
|
17653
|
+
explicitWireName: collidesWithClassName
|
|
17654
|
+
}));
|
|
17469
17655
|
const discriminatedUnionConverter = discriminatedUnionConverterName(field.type);
|
|
17470
17656
|
if (discriminatedUnionConverter) lines.push(` [Newtonsoft.Json.JsonConverter(typeof(${discriminatedUnionConverter}))]`);
|
|
17471
17657
|
const newMod = useNewModifier ? "new " : "";
|
|
@@ -20050,14 +20236,18 @@ function promoteFieldType$1(f) {
|
|
|
20050
20236
|
* List wrappers (`{ data, list_metadata }`) and the shared `ListMetadata`
|
|
20051
20237
|
* model are skipped — the hand-maintained runtime provides [Page]/[ListMetadata].
|
|
20052
20238
|
*/
|
|
20053
|
-
function generateModels$2(models,
|
|
20239
|
+
function generateModels$2(models, ctx) {
|
|
20054
20240
|
if (models.length === 0) return [];
|
|
20055
20241
|
for (const model of models) for (const field of model.fields) mapTypeRef$2(field.type);
|
|
20056
20242
|
const files = [];
|
|
20243
|
+
const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
|
|
20244
|
+
const skipAsListWrapper = (m) => isListWrapperModel(m) && !nonPaginatedRefs.has(m.name);
|
|
20245
|
+
const listMetadataNeeded = collectReferencedListMetadataModels(models, nonPaginatedRefs);
|
|
20246
|
+
const skipAsListMetadata = (m) => isListMetadataModel(m) && !listMetadataNeeded.has(m.name);
|
|
20057
20247
|
modelAliasMap = null;
|
|
20058
20248
|
const hashGroupsPass1 = /* @__PURE__ */ new Map();
|
|
20059
20249
|
for (const model of models) {
|
|
20060
|
-
if (
|
|
20250
|
+
if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
|
|
20061
20251
|
if (model.fields.length === 0 && discriminatedUnions.has(className$1(model.name))) continue;
|
|
20062
20252
|
const hash = structuralHash(model);
|
|
20063
20253
|
if (!hashGroupsPass1.has(hash)) hashGroupsPass1.set(hash, []);
|
|
@@ -20076,7 +20266,7 @@ function generateModels$2(models, _ctx) {
|
|
|
20076
20266
|
modelAliasMap = aliasOf;
|
|
20077
20267
|
const hashGroupsPass2 = /* @__PURE__ */ new Map();
|
|
20078
20268
|
for (const model of models) {
|
|
20079
|
-
if (
|
|
20269
|
+
if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
|
|
20080
20270
|
if (model.fields.length === 0 && discriminatedUnions.has(className$1(model.name))) continue;
|
|
20081
20271
|
if (aliasOf.has(model.name)) continue;
|
|
20082
20272
|
const hash = structuralHash(model);
|
|
@@ -20094,7 +20284,7 @@ function generateModels$2(models, _ctx) {
|
|
|
20094
20284
|
}
|
|
20095
20285
|
}
|
|
20096
20286
|
for (const model of models) {
|
|
20097
|
-
if (
|
|
20287
|
+
if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
|
|
20098
20288
|
const typeName = className$1(model.name);
|
|
20099
20289
|
if (model.fields.length === 0 && discriminatedUnions.has(typeName)) {
|
|
20100
20290
|
files.push(emitSealedUnion(typeName, discriminatedUnions.get(typeName)));
|
|
@@ -20122,7 +20312,7 @@ function generateModels$2(models, _ctx) {
|
|
|
20122
20312
|
}
|
|
20123
20313
|
const eventMapping = [];
|
|
20124
20314
|
for (const model of models) {
|
|
20125
|
-
if (
|
|
20315
|
+
if (skipAsListWrapper(model) || skipAsListMetadata(model)) continue;
|
|
20126
20316
|
if (aliasOf.has(model.name)) continue;
|
|
20127
20317
|
if (!isEventEnvelopeModel(model)) continue;
|
|
20128
20318
|
const eventField = model.fields.find((f) => f.name === "event");
|
|
@@ -21433,6 +21623,8 @@ function resolveBodyModel$2(op, ctx) {
|
|
|
21433
21623
|
function registerTypeImports(ref, imports, ctx) {
|
|
21434
21624
|
const mapped = mapTypeRef$2(ref);
|
|
21435
21625
|
for (const imp of implicitImportsFor(mapped)) imports.add(imp);
|
|
21626
|
+
const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
|
|
21627
|
+
const listMetadataNeeded = collectReferencedListMetadataModels(ctx.spec.models, nonPaginatedRefs);
|
|
21436
21628
|
walk(ref, (r) => {
|
|
21437
21629
|
if (r.kind === "enum") {
|
|
21438
21630
|
const canonicalName = enumCanonicalMap.get(r.name) ?? r.name;
|
|
@@ -21440,7 +21632,11 @@ function registerTypeImports(ref, imports, ctx) {
|
|
|
21440
21632
|
}
|
|
21441
21633
|
if (r.kind === "model") {
|
|
21442
21634
|
const referenced = ctx.spec.models.find((m) => m.name === r.name);
|
|
21443
|
-
if (referenced
|
|
21635
|
+
if (referenced) {
|
|
21636
|
+
const skipWrapper = isListWrapperModel(referenced) && !nonPaginatedRefs.has(referenced.name);
|
|
21637
|
+
const skipMetadata = isListMetadataModel(referenced) && !listMetadataNeeded.has(referenced.name);
|
|
21638
|
+
if (skipWrapper || skipMetadata) return;
|
|
21639
|
+
}
|
|
21444
21640
|
imports.add(`com.workos.models.${className$1(r.name)}`);
|
|
21445
21641
|
}
|
|
21446
21642
|
});
|
|
@@ -22839,10 +23035,12 @@ function generateModels$1(models, ctx) {
|
|
|
22839
23035
|
return mountDirMap.get(service) ?? classifyUnassignedModel(modelName);
|
|
22840
23036
|
};
|
|
22841
23037
|
const files = [];
|
|
23038
|
+
const nonPaginatedRefs = collectNonPaginatedResponseModelNames(ctx.spec.services);
|
|
23039
|
+
const skipAsListWrapper = (m) => isListWrapperModel(m) && !nonPaginatedRefs.has(m.name);
|
|
22842
23040
|
const recursiveHashes = buildRecursiveHashMap(models, enumNames);
|
|
22843
23041
|
const hashGroups = /* @__PURE__ */ new Map();
|
|
22844
23042
|
for (const m of models) {
|
|
22845
|
-
if (
|
|
23043
|
+
if (skipAsListWrapper(m) || isListMetadataModel(m)) continue;
|
|
22846
23044
|
const h = recursiveHashes.get(m.name) ?? "";
|
|
22847
23045
|
if (!hashGroups.has(h)) hashGroups.set(h, []);
|
|
22848
23046
|
hashGroups.get(h).push(m.name);
|
|
@@ -22855,7 +23053,7 @@ function generateModels$1(models, ctx) {
|
|
|
22855
23053
|
for (let i = 1; i < sorted.length; i++) aliasOf.set(sorted[i], canonical);
|
|
22856
23054
|
}
|
|
22857
23055
|
for (const model of models) {
|
|
22858
|
-
if (
|
|
23056
|
+
if (skipAsListWrapper(model) || isListMetadataModel(model)) continue;
|
|
22859
23057
|
const cls = className(model.name);
|
|
22860
23058
|
const file = fileName(model.name);
|
|
22861
23059
|
const canonical = aliasOf.get(model.name);
|
|
@@ -23328,7 +23526,10 @@ function mapSorbetType$1(ref) {
|
|
|
23328
23526
|
case "array": return `T::Array[${mapSorbetType$1(ref.items)}]`;
|
|
23329
23527
|
case "model": return `WorkOS::${className(ref.name)}`;
|
|
23330
23528
|
case "enum": return "String";
|
|
23331
|
-
case "nullable":
|
|
23529
|
+
case "nullable": {
|
|
23530
|
+
const inner = mapSorbetType$1(ref.inner);
|
|
23531
|
+
return inner === "T.untyped" ? inner : `T.nilable(${inner})`;
|
|
23532
|
+
}
|
|
23332
23533
|
case "literal":
|
|
23333
23534
|
if (typeof ref.value === "string") return "String";
|
|
23334
23535
|
if (ref.value === null) return "NilClass";
|
|
@@ -24932,6 +25133,7 @@ function generateRbiFiles(spec, ctx) {
|
|
|
24932
25133
|
}
|
|
24933
25134
|
/** Unwrap T.nilable(...) if already wrapped, to avoid double-wrapping. */
|
|
24934
25135
|
function unwrapNilable(type) {
|
|
25136
|
+
if (type === "T.untyped") return type;
|
|
24935
25137
|
const match = type.match(/^T\.nilable\((.+)\)$/);
|
|
24936
25138
|
return match ? match[1] : type;
|
|
24937
25139
|
}
|
|
@@ -24986,8 +25188,8 @@ function ensureTrailingNewlines$1(files) {
|
|
|
24986
25188
|
* has its original fields restored — otherwise `ConnectApplication`-style
|
|
24987
25189
|
* bases would silently lose every variant field they had previously.
|
|
24988
25190
|
*/
|
|
24989
|
-
function enrichModelsForRuby(models) {
|
|
24990
|
-
const enriched = enrichModelsFromSpec(models);
|
|
25191
|
+
function enrichModelsForRuby(models, enums) {
|
|
25192
|
+
const enriched = enrichModelsFromSpec(models, enums);
|
|
24991
25193
|
const originalByName = new Map(models.map((m) => [m.name, m]));
|
|
24992
25194
|
return enriched.map((m) => {
|
|
24993
25195
|
if (m.discriminator && m.fields.length === 0) {
|
|
@@ -25003,7 +25205,7 @@ function enrichModelsForRuby(models) {
|
|
|
25003
25205
|
const rubyEmitter = {
|
|
25004
25206
|
language: "ruby",
|
|
25005
25207
|
generateModels(models, ctx) {
|
|
25006
|
-
return ensureTrailingNewlines$1(generateModels$1(enrichModelsForRuby(models), ctx));
|
|
25208
|
+
return ensureTrailingNewlines$1(generateModels$1(enrichModelsForRuby(models, ctx.spec.enums), ctx));
|
|
25007
25209
|
},
|
|
25008
25210
|
generateEnums(enums, ctx) {
|
|
25009
25211
|
const syntheticEnums = getSyntheticEnums();
|
|
@@ -25469,7 +25671,7 @@ function renderField(field, rustField, modelName, registry) {
|
|
|
25469
25671
|
function renderModelsBarrel(modules) {
|
|
25470
25672
|
const sorted = [...new Set(modules)].sort();
|
|
25471
25673
|
const lines = [];
|
|
25472
|
-
for (const m of sorted) lines.push(`
|
|
25674
|
+
for (const m of sorted) lines.push(`mod ${m};`);
|
|
25473
25675
|
lines.push("");
|
|
25474
25676
|
for (const m of sorted) lines.push(`pub use ${m}::*;`);
|
|
25475
25677
|
return lines.join("\n") + "\n";
|
|
@@ -26552,7 +26754,7 @@ function renderResourcesBarrel(exports) {
|
|
|
26552
26754
|
}
|
|
26553
26755
|
unique.sort((a, b) => a.module.localeCompare(b.module));
|
|
26554
26756
|
const lines = [];
|
|
26555
|
-
for (const { module } of unique) lines.push(`
|
|
26757
|
+
for (const { module } of unique) lines.push(`mod ${module};`);
|
|
26556
26758
|
lines.push("");
|
|
26557
26759
|
for (const { module, struct } of unique) lines.push(`pub use ${module}::${struct};`);
|
|
26558
26760
|
return lines.join("\n") + "\n";
|
|
@@ -27402,4 +27604,4 @@ const workosEmittersPlugin = {
|
|
|
27402
27604
|
//#endregion
|
|
27403
27605
|
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 };
|
|
27404
27606
|
|
|
27405
|
-
//# sourceMappingURL=plugin-
|
|
27607
|
+
//# sourceMappingURL=plugin-BbSmT2kj.mjs.map
|