@workos/oagen 0.15.0 → 0.17.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/cli/index.mjs +214 -14
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.mjs +214 -14
- package/dist/index.mjs.map +1 -1
- package/dist/scripts/smoke/baseline.mjs +214 -14
- package/dist/scripts/smoke/baseline.mjs.map +1 -1
- package/dist/smoke.mjs +214 -14
- package/dist/smoke.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -208,17 +208,64 @@ function extractInlineModelsFromProperties(schema, results, parentName) {
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
if (fieldSchema.oneOf) {
|
|
211
|
-
const
|
|
212
|
-
if (
|
|
211
|
+
const inlineObjectVariants = fieldSchema.oneOf.filter((v) => !v.$ref && v.properties && (v.type === "object" || !v.type));
|
|
212
|
+
if (inlineObjectVariants.length > 0) {
|
|
213
213
|
const modelName = qualifyInlineModelName(toPascalCase(fieldName), parentName);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
214
|
+
const existingNames = new Set(results.map((r) => r.name));
|
|
215
|
+
const namingDiscProp = deriveOneOfNamingDiscriminator(inlineObjectVariants);
|
|
216
|
+
const emittedNames = [];
|
|
217
|
+
for (const variant of inlineObjectVariants) {
|
|
218
|
+
const variantName = nameOneOfVariant(variant, modelName, emittedNames, namingDiscProp);
|
|
219
|
+
emittedNames.push(variantName);
|
|
220
|
+
if (!existingNames.has(variantName)) {
|
|
221
|
+
existingNames.add(variantName);
|
|
222
|
+
results.push(buildInlineModel(variantName, variant));
|
|
223
|
+
extractInlineModelsFromProperties(variant, results, variantName);
|
|
224
|
+
}
|
|
217
225
|
}
|
|
218
226
|
}
|
|
219
227
|
}
|
|
220
228
|
}
|
|
221
229
|
}
|
|
230
|
+
/** Find a single string-const-valued property shared by every variant whose
|
|
231
|
+
* values are all distinct — the implicit discriminator. Returns null when no
|
|
232
|
+
* such property exists. Mirrors `deriveConstNamingDiscriminator` in schemas.ts. */
|
|
233
|
+
function deriveOneOfNamingDiscriminator(variants) {
|
|
234
|
+
if (variants.length < 2) return null;
|
|
235
|
+
const candidates = Object.keys(variants[0]?.properties ?? {});
|
|
236
|
+
for (const propName of candidates) {
|
|
237
|
+
const values = variants.map((v) => readConstString(v.properties?.[propName]));
|
|
238
|
+
if (values.some((v) => v === null)) continue;
|
|
239
|
+
if (new Set(values).size !== values.length) continue;
|
|
240
|
+
return propName;
|
|
241
|
+
}
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
function readConstString(prop) {
|
|
245
|
+
if (!prop) return null;
|
|
246
|
+
if (typeof prop.const === "string") return prop.const;
|
|
247
|
+
if (Array.isArray(prop.enum) && prop.enum.length === 1 && typeof prop.enum[0] === "string") return prop.enum[0];
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
/** Produce a per-variant model name. Variant 0 keeps the bare parent name;
|
|
251
|
+
* later variants are prefixed by the const-derived label. Mirrors
|
|
252
|
+
* `nameVariantModel` in schemas.ts. Falls back to a numeric suffix when no
|
|
253
|
+
* discriminator is available, the const value PascalCases to nothing, or
|
|
254
|
+
* the derived candidate collides with the parent or an already-emitted name. */
|
|
255
|
+
function nameOneOfVariant(variant, parentName, alreadyEmitted, discriminatorProperty) {
|
|
256
|
+
if (alreadyEmitted.length === 0) return parentName;
|
|
257
|
+
if (discriminatorProperty) {
|
|
258
|
+
const constValue = readConstString(variant.properties?.[discriminatorProperty]);
|
|
259
|
+
if (constValue) {
|
|
260
|
+
const prefix = toPascalCase(constValue);
|
|
261
|
+
if (prefix) {
|
|
262
|
+
const candidate = parentName.startsWith(prefix) ? parentName : `${prefix}${parentName}`;
|
|
263
|
+
if (!(candidate === parentName || alreadyEmitted.includes(candidate))) return candidate;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return `${parentName}${alreadyEmitted.length + 1}`;
|
|
268
|
+
}
|
|
222
269
|
function buildInlineModel(name, schema) {
|
|
223
270
|
const requiredSet = new Set(schema.required ?? []);
|
|
224
271
|
const fields = [];
|
|
@@ -380,6 +427,7 @@ function findNestedFieldSchema(fieldName, parentSchema, schemas) {
|
|
|
380
427
|
function extractNestedSchema(name, schema) {
|
|
381
428
|
if (schema.oneOf) {
|
|
382
429
|
const models = [];
|
|
430
|
+
const constNamingDiscriminator = deriveConstNamingDiscriminator(schema.oneOf.filter((v) => !v.$ref && v.properties && (v.type === "object" || !v.type)));
|
|
383
431
|
for (const variant of schema.oneOf) {
|
|
384
432
|
if (variant.$ref) continue;
|
|
385
433
|
if (variant.properties && (variant.type === "object" || !variant.type)) {
|
|
@@ -389,7 +437,7 @@ function extractNestedSchema(name, schema) {
|
|
|
389
437
|
if (!fs) continue;
|
|
390
438
|
fields.push(buildFieldFromSchema(fn, fs, name, requiredSet));
|
|
391
439
|
}
|
|
392
|
-
const variantName =
|
|
440
|
+
const variantName = nameVariantModel(variant, name, models, constNamingDiscriminator);
|
|
393
441
|
models.push({
|
|
394
442
|
name: variantName,
|
|
395
443
|
description: variant.description,
|
|
@@ -427,6 +475,69 @@ function extractNestedSchema(name, schema) {
|
|
|
427
475
|
}
|
|
428
476
|
return [];
|
|
429
477
|
}
|
|
478
|
+
/**
|
|
479
|
+
* Derive a meaningful name for a oneOf object variant past the first,
|
|
480
|
+
* falling back to the numeric-suffix scheme (`Foo2`, `Foo3`) when no
|
|
481
|
+
* better signal is available. The "better signal" is a const-valued
|
|
482
|
+
* discriminator property that distinguishes one variant from the others.
|
|
483
|
+
*
|
|
484
|
+
* For a schema like `ApiKey.owner` whose oneOf has two variants — one
|
|
485
|
+
* with `type: { const: "organization" }` and one with `type: { const:
|
|
486
|
+
* "user" }` — this returns `ApiKeyOwner` for the first variant (the
|
|
487
|
+
* baseline name that the union TypeRef will reference, so consumer-
|
|
488
|
+
* visible typed fields stay backward-compatible) and `UserApiKeyOwner`
|
|
489
|
+
* for the second instead of `ApiKeyOwner2`. SDK consumers reading the
|
|
490
|
+
* generated types can tell the variants apart at a glance.
|
|
491
|
+
*
|
|
492
|
+
* The first variant always keeps the bare parent name because
|
|
493
|
+
* `schemaToTypeRef` builds union variants whose model refs collapse to
|
|
494
|
+
* `qualifyInlineModelName(field, parent)` — so the first model name
|
|
495
|
+
* must match for the union's degenerate-collapse to land on a valid
|
|
496
|
+
* type. Renaming variant 0 would orphan it.
|
|
497
|
+
*
|
|
498
|
+
* Falls back to numeric suffix when:
|
|
499
|
+
* - The variant has no discriminator property (no shared const
|
|
500
|
+
* property across all object variants), OR
|
|
501
|
+
* - The const value PascalCases to an empty/whitespace name, OR
|
|
502
|
+
* - The derived name collides with the parent name or an already-
|
|
503
|
+
* emitted variant name (numeric keeps uniqueness).
|
|
504
|
+
*/
|
|
505
|
+
function nameVariantModel(variant, parentName, alreadyEmitted, discriminator) {
|
|
506
|
+
if (alreadyEmitted.length === 0) return parentName;
|
|
507
|
+
if (discriminator) {
|
|
508
|
+
const constValue = getConstPropertyValue(variant, discriminator.property);
|
|
509
|
+
if (constValue) {
|
|
510
|
+
const prefix = toPascalCase(constValue);
|
|
511
|
+
if (prefix) {
|
|
512
|
+
const candidate = parentName.startsWith(prefix) ? parentName : `${prefix}${parentName}`;
|
|
513
|
+
if (!(candidate === parentName || alreadyEmitted.some((m) => m.name === candidate))) return candidate;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return `${parentName}${alreadyEmitted.length + 1}`;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Returns a discriminator descriptor when every inline object variant in a
|
|
521
|
+
* oneOf has a string-const value on the same property — the signature of a
|
|
522
|
+
* discriminated union without an explicit `discriminator:` keyword. Used by
|
|
523
|
+
* `nameVariantModel` to derive variant names from the const values.
|
|
524
|
+
*
|
|
525
|
+
* Distinct from `detectConstPropertyDiscriminator` (which requires every
|
|
526
|
+
* variant to carry a `$ref` or `title` so a name mapping can be built):
|
|
527
|
+
* this pass operates on inline anonymous variants, where naming is exactly
|
|
528
|
+
* what we're trying to derive.
|
|
529
|
+
*/
|
|
530
|
+
function deriveConstNamingDiscriminator(variants) {
|
|
531
|
+
if (variants.length < 2) return null;
|
|
532
|
+
const candidates = Object.keys(variants[0]?.properties ?? {});
|
|
533
|
+
for (const propName of candidates) {
|
|
534
|
+
const values = variants.map((v) => getConstPropertyValue(v, propName));
|
|
535
|
+
if (values.some((v) => v === null)) continue;
|
|
536
|
+
if (new Set(values).size !== values.length) continue;
|
|
537
|
+
return { property: propName };
|
|
538
|
+
}
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
430
541
|
/** Build a single Field from a schema property entry. Shared across all extraction sites. */
|
|
431
542
|
function buildFieldFromSchema(fieldName, fieldSchema, contextName, requiredSet) {
|
|
432
543
|
return {
|
|
@@ -521,6 +632,51 @@ function resolveVariantModelName(schema) {
|
|
|
521
632
|
if (title) return resolveSchemaName(title);
|
|
522
633
|
return null;
|
|
523
634
|
}
|
|
635
|
+
/** Look up the discriminator's mapped variant name for an inline object
|
|
636
|
+
* variant by reading its const-valued discriminator property. Returns null
|
|
637
|
+
* when the variant doesn't pin the property to a string const, or when
|
|
638
|
+
* the value isn't in the mapping. */
|
|
639
|
+
function mapVariantToDiscriminatorEntry(variant, discriminator) {
|
|
640
|
+
const value = getConstPropertyValue(variant, discriminator.property);
|
|
641
|
+
if (value === null) return null;
|
|
642
|
+
return discriminator.mapping[value] ?? null;
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Derive a discriminator value → variant model name mapping for an inline-
|
|
646
|
+
* variant `oneOf` whose explicit `discriminator:` has no `mapping:` clause.
|
|
647
|
+
*
|
|
648
|
+
* Each variant model name is reproduced via `nameVariantModel` so it matches
|
|
649
|
+
* what `extractNestedSchema` registered when it walked the same `oneOf` to
|
|
650
|
+
* pull variants out as named models. Variant 0 keeps the bare parent name
|
|
651
|
+
* (e.g. `ApiKeyOwner`); subsequent variants get a const-derived prefix
|
|
652
|
+
* (e.g. `UserApiKeyOwner` for the `type: const: user` variant).
|
|
653
|
+
*
|
|
654
|
+
* The "parent name" used here mirrors the one `collectNestedInlineModels`
|
|
655
|
+
* passes to `extractNestedSchema`: it's the qualified inline model name
|
|
656
|
+
* built from `contextName` (the field name) plus `parentModelName` (the
|
|
657
|
+
* containing model). Returns null when any non-object variant is present
|
|
658
|
+
* or when a variant lacks a const value on the discriminator property.
|
|
659
|
+
*/
|
|
660
|
+
function deriveInlineVariantMapping(variants, discriminatorProperty, contextName, parentModelName) {
|
|
661
|
+
if (variants.length === 0 || !contextName) return null;
|
|
662
|
+
const inlineObjectVariants = variants.filter((v) => !v.$ref && v.properties && (v.type === "object" || !v.type));
|
|
663
|
+
if (inlineObjectVariants.length !== variants.length) return null;
|
|
664
|
+
const baseInlineName = qualifyInlineModelName(toPascalCase(contextName), parentModelName);
|
|
665
|
+
const namingDiscriminator = { property: discriminatorProperty };
|
|
666
|
+
const mapping = {};
|
|
667
|
+
const emittedSoFar = [];
|
|
668
|
+
for (const variant of inlineObjectVariants) {
|
|
669
|
+
const constValue = getConstPropertyValue(variant, discriminatorProperty);
|
|
670
|
+
if (constValue === null) return null;
|
|
671
|
+
const variantName = nameVariantModel(variant, baseInlineName, emittedSoFar, namingDiscriminator);
|
|
672
|
+
mapping[constValue] = variantName;
|
|
673
|
+
emittedSoFar.push({
|
|
674
|
+
name: variantName,
|
|
675
|
+
fields: []
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
return mapping;
|
|
679
|
+
}
|
|
524
680
|
function extractEnum(name, schema) {
|
|
525
681
|
return {
|
|
526
682
|
name,
|
|
@@ -719,8 +875,20 @@ function extractInlineModelDeep(name, schema) {
|
|
|
719
875
|
}));
|
|
720
876
|
}
|
|
721
877
|
if (fieldSchema.oneOf) {
|
|
722
|
-
const
|
|
723
|
-
if (
|
|
878
|
+
const inlineObjectVariants = fieldSchema.oneOf.filter((v) => !v.$ref && v.properties && (v.type === "object" || !v.type));
|
|
879
|
+
if (inlineObjectVariants.length > 0) {
|
|
880
|
+
const baseQualified = qualifyNestedInlineName(name, fieldName);
|
|
881
|
+
const namingDisc = deriveConstNamingDiscriminator(inlineObjectVariants);
|
|
882
|
+
const emitted = [];
|
|
883
|
+
for (const variant of inlineObjectVariants) {
|
|
884
|
+
const variantName = nameVariantModel(variant, baseQualified, emitted, namingDisc);
|
|
885
|
+
emitted.push({
|
|
886
|
+
name: variantName,
|
|
887
|
+
fields: []
|
|
888
|
+
});
|
|
889
|
+
nestedModels.push(...extractInlineModelDeep(variantName, variant));
|
|
890
|
+
}
|
|
891
|
+
}
|
|
724
892
|
}
|
|
725
893
|
}
|
|
726
894
|
return [{
|
|
@@ -817,17 +985,49 @@ function schemaToTypeRef(schema, contextName, parentModelName) {
|
|
|
817
985
|
inner: enumRef
|
|
818
986
|
} : enumRef;
|
|
819
987
|
}
|
|
820
|
-
|
|
821
|
-
|
|
988
|
+
let resolvedDiscriminator;
|
|
989
|
+
if (schema.discriminator) {
|
|
990
|
+
const property = schema.discriminator.propertyName;
|
|
991
|
+
const explicitMapping = schema.discriminator.mapping ?? {};
|
|
992
|
+
let mapping = Object.fromEntries(Object.entries(explicitMapping).map(([k, v]) => [k, v.replace(/^#\/components\/schemas\//, "")]));
|
|
993
|
+
if (Object.keys(mapping).length === 0) {
|
|
994
|
+
const inlineMapping = deriveInlineVariantMapping(nonNullVariants, property, contextName, parentModelName);
|
|
995
|
+
if (inlineMapping) mapping = inlineMapping;
|
|
996
|
+
}
|
|
997
|
+
resolvedDiscriminator = {
|
|
998
|
+
property,
|
|
999
|
+
mapping
|
|
1000
|
+
};
|
|
1001
|
+
} else if (compositionKind === "oneOf") {
|
|
1002
|
+
const synthetic = detectConstPropertyDiscriminator(nonNullVariants);
|
|
1003
|
+
if (synthetic) resolvedDiscriminator = synthetic;
|
|
1004
|
+
else {
|
|
1005
|
+
const namingDisc = deriveConstNamingDiscriminator(nonNullVariants);
|
|
1006
|
+
if (namingDisc) {
|
|
1007
|
+
const inlineMapping = deriveInlineVariantMapping(nonNullVariants, namingDisc.property, contextName, parentModelName);
|
|
1008
|
+
if (inlineMapping) resolvedDiscriminator = {
|
|
1009
|
+
property: namingDisc.property,
|
|
1010
|
+
mapping: inlineMapping
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
const variants = [];
|
|
1016
|
+
for (const v of rawVariants) {
|
|
1017
|
+
if (v === nullVariant) continue;
|
|
1018
|
+
const inlineMappingName = resolvedDiscriminator && !v.$ref && v.properties && (v.type === "object" || !v.type) ? mapVariantToDiscriminatorEntry(v, resolvedDiscriminator) : null;
|
|
1019
|
+
if (inlineMappingName) variants.push({
|
|
1020
|
+
kind: "model",
|
|
1021
|
+
name: inlineMappingName
|
|
1022
|
+
});
|
|
1023
|
+
else variants.push(schemaToTypeRef(v, contextName, parentModelName));
|
|
1024
|
+
}
|
|
822
1025
|
const hasNull = !!nullVariant;
|
|
823
1026
|
const union = {
|
|
824
1027
|
kind: "union",
|
|
825
1028
|
variants,
|
|
826
1029
|
compositionKind,
|
|
827
|
-
...
|
|
828
|
-
property: schema.discriminator.propertyName,
|
|
829
|
-
mapping: Object.fromEntries(Object.entries(schema.discriminator.mapping ?? {}).map(([k, v]) => [k, v.replace(/^#\/components\/schemas\//, "")]))
|
|
830
|
-
} } : syntheticDiscriminator ? { discriminator: syntheticDiscriminator } : {}
|
|
1030
|
+
...resolvedDiscriminator ? { discriminator: resolvedDiscriminator } : {}
|
|
831
1031
|
};
|
|
832
1032
|
return hasNull ? {
|
|
833
1033
|
kind: "nullable",
|