@workos/oagen 0.16.0 → 0.17.1
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 +183 -18
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.mjs +183 -18
- package/dist/index.mjs.map +1 -1
- package/dist/scripts/smoke/baseline.mjs +183 -18
- package/dist/scripts/smoke/baseline.mjs.map +1 -1
- package/dist/smoke.mjs +183 -18
- package/dist/smoke.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -405,17 +405,64 @@ function extractInlineModelsFromProperties(schema, results, parentName) {
|
|
|
405
405
|
}
|
|
406
406
|
}
|
|
407
407
|
if (fieldSchema.oneOf) {
|
|
408
|
-
const
|
|
409
|
-
if (
|
|
408
|
+
const inlineObjectVariants = fieldSchema.oneOf.filter((v) => !v.$ref && v.properties && (v.type === "object" || !v.type));
|
|
409
|
+
if (inlineObjectVariants.length > 0) {
|
|
410
410
|
const modelName = qualifyInlineModelName(toPascalCase(fieldName), parentName);
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
411
|
+
const existingNames = new Set(results.map((r) => r.name));
|
|
412
|
+
const namingDiscProp = deriveOneOfNamingDiscriminator(inlineObjectVariants);
|
|
413
|
+
const emittedNames = [];
|
|
414
|
+
for (const variant of inlineObjectVariants) {
|
|
415
|
+
const variantName = nameOneOfVariant(variant, modelName, emittedNames, namingDiscProp);
|
|
416
|
+
emittedNames.push(variantName);
|
|
417
|
+
if (!existingNames.has(variantName)) {
|
|
418
|
+
existingNames.add(variantName);
|
|
419
|
+
results.push(buildInlineModel(variantName, variant));
|
|
420
|
+
extractInlineModelsFromProperties(variant, results, variantName);
|
|
421
|
+
}
|
|
414
422
|
}
|
|
415
423
|
}
|
|
416
424
|
}
|
|
417
425
|
}
|
|
418
426
|
}
|
|
427
|
+
/** Find a single string-const-valued property shared by every variant whose
|
|
428
|
+
* values are all distinct — the implicit discriminator. Returns null when no
|
|
429
|
+
* such property exists. Mirrors `deriveConstNamingDiscriminator` in schemas.ts. */
|
|
430
|
+
function deriveOneOfNamingDiscriminator(variants) {
|
|
431
|
+
if (variants.length < 2) return null;
|
|
432
|
+
const candidates = Object.keys(variants[0]?.properties ?? {});
|
|
433
|
+
for (const propName of candidates) {
|
|
434
|
+
const values = variants.map((v) => readConstString(v.properties?.[propName]));
|
|
435
|
+
if (values.some((v) => v === null)) continue;
|
|
436
|
+
if (new Set(values).size !== values.length) continue;
|
|
437
|
+
return propName;
|
|
438
|
+
}
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
function readConstString(prop) {
|
|
442
|
+
if (!prop) return null;
|
|
443
|
+
if (typeof prop.const === "string") return prop.const;
|
|
444
|
+
if (Array.isArray(prop.enum) && prop.enum.length === 1 && typeof prop.enum[0] === "string") return prop.enum[0];
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
/** Produce a per-variant model name. Variant 0 keeps the bare parent name;
|
|
448
|
+
* later variants are prefixed by the const-derived label. Mirrors
|
|
449
|
+
* `nameVariantModel` in schemas.ts. Falls back to a numeric suffix when no
|
|
450
|
+
* discriminator is available, the const value PascalCases to nothing, or
|
|
451
|
+
* the derived candidate collides with the parent or an already-emitted name. */
|
|
452
|
+
function nameOneOfVariant(variant, parentName, alreadyEmitted, discriminatorProperty) {
|
|
453
|
+
if (alreadyEmitted.length === 0) return parentName;
|
|
454
|
+
if (discriminatorProperty) {
|
|
455
|
+
const constValue = readConstString(variant.properties?.[discriminatorProperty]);
|
|
456
|
+
if (constValue) {
|
|
457
|
+
const prefix = toPascalCase(constValue);
|
|
458
|
+
if (prefix) {
|
|
459
|
+
const candidate = parentName.startsWith(prefix) ? parentName : `${prefix}${parentName}`;
|
|
460
|
+
if (!(candidate === parentName || alreadyEmitted.includes(candidate))) return candidate;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return `${parentName}${alreadyEmitted.length + 1}`;
|
|
465
|
+
}
|
|
419
466
|
function buildInlineModel(name, schema) {
|
|
420
467
|
const requiredSet = new Set(schema.required ?? []);
|
|
421
468
|
const fields = [];
|
|
@@ -436,6 +483,14 @@ function buildInlineModel(name, schema) {
|
|
|
436
483
|
* to apply the same name transform to $ref model/enum references.
|
|
437
484
|
*/
|
|
438
485
|
let activeSchemaNameTransform = null;
|
|
486
|
+
/**
|
|
487
|
+
* Module-level set of resolved schema names whose components/schemas entry is
|
|
488
|
+
* an enum (i.e. has `enum:`). Populated by extractSchemas() so schemaToTypeRef()
|
|
489
|
+
* can classify a `$ref` to a top-level enum schema as `kind: 'enum'` instead of
|
|
490
|
+
* `kind: 'model'`. Without this, every `$ref` was naively returned as a model
|
|
491
|
+
* ref, even when the target was a shared enum like `PaginationOrder`.
|
|
492
|
+
*/
|
|
493
|
+
let activeEnumSchemaNames = /* @__PURE__ */ new Set();
|
|
439
494
|
/** Apply cleanSchemaName + the active transform (if any) to a raw schema name. */
|
|
440
495
|
function resolveSchemaName(rawName) {
|
|
441
496
|
let name = cleanSchemaName(toPascalCase(rawName));
|
|
@@ -461,6 +516,8 @@ function extractSchemas(schemas, options) {
|
|
|
461
516
|
for (const [, originals] of transformedToOriginals) if (originals.length > 1) for (const n of originals) unsafeToTransform.add(n);
|
|
462
517
|
activeSchemaNameTransform = (name) => unsafeToTransform.has(name) ? name : transform(name);
|
|
463
518
|
} else activeSchemaNameTransform = null;
|
|
519
|
+
activeEnumSchemaNames = /* @__PURE__ */ new Set();
|
|
520
|
+
for (const [name, schema] of Object.entries(schemas)) if (schema.enum) activeEnumSchemaNames.add(resolveSchemaName(name));
|
|
464
521
|
const modelsByCleanName = /* @__PURE__ */ new Map();
|
|
465
522
|
for (const [name, schema] of Object.entries(schemas)) {
|
|
466
523
|
const pascalName = resolveSchemaName(name);
|
|
@@ -495,6 +552,7 @@ function extractSchemas(schemas, options) {
|
|
|
495
552
|
/** Clear the module-level schemaNameTransform. Called by parseSpec() after all extraction phases. */
|
|
496
553
|
function clearSchemaNameTransform() {
|
|
497
554
|
activeSchemaNameTransform = null;
|
|
555
|
+
activeEnumSchemaNames = /* @__PURE__ */ new Set();
|
|
498
556
|
}
|
|
499
557
|
/**
|
|
500
558
|
* Walk a single TypeRef and extract inline enum refs as top-level enum definitions.
|
|
@@ -782,6 +840,51 @@ function resolveVariantModelName(schema) {
|
|
|
782
840
|
if (title) return resolveSchemaName(title);
|
|
783
841
|
return null;
|
|
784
842
|
}
|
|
843
|
+
/** Look up the discriminator's mapped variant name for an inline object
|
|
844
|
+
* variant by reading its const-valued discriminator property. Returns null
|
|
845
|
+
* when the variant doesn't pin the property to a string const, or when
|
|
846
|
+
* the value isn't in the mapping. */
|
|
847
|
+
function mapVariantToDiscriminatorEntry(variant, discriminator) {
|
|
848
|
+
const value = getConstPropertyValue(variant, discriminator.property);
|
|
849
|
+
if (value === null) return null;
|
|
850
|
+
return discriminator.mapping[value] ?? null;
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Derive a discriminator value → variant model name mapping for an inline-
|
|
854
|
+
* variant `oneOf` whose explicit `discriminator:` has no `mapping:` clause.
|
|
855
|
+
*
|
|
856
|
+
* Each variant model name is reproduced via `nameVariantModel` so it matches
|
|
857
|
+
* what `extractNestedSchema` registered when it walked the same `oneOf` to
|
|
858
|
+
* pull variants out as named models. Variant 0 keeps the bare parent name
|
|
859
|
+
* (e.g. `ApiKeyOwner`); subsequent variants get a const-derived prefix
|
|
860
|
+
* (e.g. `UserApiKeyOwner` for the `type: const: user` variant).
|
|
861
|
+
*
|
|
862
|
+
* The "parent name" used here mirrors the one `collectNestedInlineModels`
|
|
863
|
+
* passes to `extractNestedSchema`: it's the qualified inline model name
|
|
864
|
+
* built from `contextName` (the field name) plus `parentModelName` (the
|
|
865
|
+
* containing model). Returns null when any non-object variant is present
|
|
866
|
+
* or when a variant lacks a const value on the discriminator property.
|
|
867
|
+
*/
|
|
868
|
+
function deriveInlineVariantMapping(variants, discriminatorProperty, contextName, parentModelName) {
|
|
869
|
+
if (variants.length === 0 || !contextName) return null;
|
|
870
|
+
const inlineObjectVariants = variants.filter((v) => !v.$ref && v.properties && (v.type === "object" || !v.type));
|
|
871
|
+
if (inlineObjectVariants.length !== variants.length) return null;
|
|
872
|
+
const baseInlineName = qualifyInlineModelName(toPascalCase(contextName), parentModelName);
|
|
873
|
+
const namingDiscriminator = { property: discriminatorProperty };
|
|
874
|
+
const mapping = {};
|
|
875
|
+
const emittedSoFar = [];
|
|
876
|
+
for (const variant of inlineObjectVariants) {
|
|
877
|
+
const constValue = getConstPropertyValue(variant, discriminatorProperty);
|
|
878
|
+
if (constValue === null) return null;
|
|
879
|
+
const variantName = nameVariantModel(variant, baseInlineName, emittedSoFar, namingDiscriminator);
|
|
880
|
+
mapping[constValue] = variantName;
|
|
881
|
+
emittedSoFar.push({
|
|
882
|
+
name: variantName,
|
|
883
|
+
fields: []
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
return mapping;
|
|
887
|
+
}
|
|
785
888
|
function extractEnum(name, schema) {
|
|
786
889
|
return {
|
|
787
890
|
name,
|
|
@@ -980,8 +1083,20 @@ function extractInlineModelDeep(name, schema) {
|
|
|
980
1083
|
}));
|
|
981
1084
|
}
|
|
982
1085
|
if (fieldSchema.oneOf) {
|
|
983
|
-
const
|
|
984
|
-
if (
|
|
1086
|
+
const inlineObjectVariants = fieldSchema.oneOf.filter((v) => !v.$ref && v.properties && (v.type === "object" || !v.type));
|
|
1087
|
+
if (inlineObjectVariants.length > 0) {
|
|
1088
|
+
const baseQualified = qualifyNestedInlineName(name, fieldName);
|
|
1089
|
+
const namingDisc = deriveConstNamingDiscriminator(inlineObjectVariants);
|
|
1090
|
+
const emitted = [];
|
|
1091
|
+
for (const variant of inlineObjectVariants) {
|
|
1092
|
+
const variantName = nameVariantModel(variant, baseQualified, emitted, namingDisc);
|
|
1093
|
+
emitted.push({
|
|
1094
|
+
name: variantName,
|
|
1095
|
+
fields: []
|
|
1096
|
+
});
|
|
1097
|
+
nestedModels.push(...extractInlineModelDeep(variantName, variant));
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
985
1100
|
}
|
|
986
1101
|
}
|
|
987
1102
|
return [{
|
|
@@ -1002,9 +1117,14 @@ function schemaToTypeRef(schema, contextName, parentModelName) {
|
|
|
1002
1117
|
if (schema.$ref) {
|
|
1003
1118
|
const segments = schema.$ref.split("/");
|
|
1004
1119
|
const rawName = segments[segments.length - 1];
|
|
1120
|
+
const resolved = resolveSchemaName(rawName);
|
|
1121
|
+
if (activeEnumSchemaNames.has(resolved)) return {
|
|
1122
|
+
kind: "enum",
|
|
1123
|
+
name: resolved
|
|
1124
|
+
};
|
|
1005
1125
|
return {
|
|
1006
1126
|
kind: "model",
|
|
1007
|
-
name:
|
|
1127
|
+
name: resolved
|
|
1008
1128
|
};
|
|
1009
1129
|
}
|
|
1010
1130
|
if (Array.isArray(schema.type)) {
|
|
@@ -1078,17 +1198,49 @@ function schemaToTypeRef(schema, contextName, parentModelName) {
|
|
|
1078
1198
|
inner: enumRef
|
|
1079
1199
|
} : enumRef;
|
|
1080
1200
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1201
|
+
let resolvedDiscriminator;
|
|
1202
|
+
if (schema.discriminator) {
|
|
1203
|
+
const property = schema.discriminator.propertyName;
|
|
1204
|
+
const explicitMapping = schema.discriminator.mapping ?? {};
|
|
1205
|
+
let mapping = Object.fromEntries(Object.entries(explicitMapping).map(([k, v]) => [k, v.replace(/^#\/components\/schemas\//, "")]));
|
|
1206
|
+
if (Object.keys(mapping).length === 0) {
|
|
1207
|
+
const inlineMapping = deriveInlineVariantMapping(nonNullVariants, property, contextName, parentModelName);
|
|
1208
|
+
if (inlineMapping) mapping = inlineMapping;
|
|
1209
|
+
}
|
|
1210
|
+
resolvedDiscriminator = {
|
|
1211
|
+
property,
|
|
1212
|
+
mapping
|
|
1213
|
+
};
|
|
1214
|
+
} else if (compositionKind === "oneOf") {
|
|
1215
|
+
const synthetic = detectConstPropertyDiscriminator(nonNullVariants);
|
|
1216
|
+
if (synthetic) resolvedDiscriminator = synthetic;
|
|
1217
|
+
else {
|
|
1218
|
+
const namingDisc = deriveConstNamingDiscriminator(nonNullVariants);
|
|
1219
|
+
if (namingDisc) {
|
|
1220
|
+
const inlineMapping = deriveInlineVariantMapping(nonNullVariants, namingDisc.property, contextName, parentModelName);
|
|
1221
|
+
if (inlineMapping) resolvedDiscriminator = {
|
|
1222
|
+
property: namingDisc.property,
|
|
1223
|
+
mapping: inlineMapping
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
const variants = [];
|
|
1229
|
+
for (const v of rawVariants) {
|
|
1230
|
+
if (v === nullVariant) continue;
|
|
1231
|
+
const inlineMappingName = resolvedDiscriminator && !v.$ref && v.properties && (v.type === "object" || !v.type) ? mapVariantToDiscriminatorEntry(v, resolvedDiscriminator) : null;
|
|
1232
|
+
if (inlineMappingName) variants.push({
|
|
1233
|
+
kind: "model",
|
|
1234
|
+
name: inlineMappingName
|
|
1235
|
+
});
|
|
1236
|
+
else variants.push(schemaToTypeRef(v, contextName, parentModelName));
|
|
1237
|
+
}
|
|
1083
1238
|
const hasNull = !!nullVariant;
|
|
1084
1239
|
const union = {
|
|
1085
1240
|
kind: "union",
|
|
1086
1241
|
variants,
|
|
1087
1242
|
compositionKind,
|
|
1088
|
-
...
|
|
1089
|
-
property: schema.discriminator.propertyName,
|
|
1090
|
-
mapping: Object.fromEntries(Object.entries(schema.discriminator.mapping ?? {}).map(([k, v]) => [k, v.replace(/^#\/components\/schemas\//, "")]))
|
|
1091
|
-
} } : syntheticDiscriminator ? { discriminator: syntheticDiscriminator } : {}
|
|
1243
|
+
...resolvedDiscriminator ? { discriminator: resolvedDiscriminator } : {}
|
|
1092
1244
|
};
|
|
1093
1245
|
return hasNull ? {
|
|
1094
1246
|
kind: "nullable",
|
|
@@ -1660,10 +1812,23 @@ function inferServiceName(path, tag) {
|
|
|
1660
1812
|
if (first.startsWith("{")) return "Default";
|
|
1661
1813
|
return toPascalCase(first);
|
|
1662
1814
|
}
|
|
1815
|
+
/**
|
|
1816
|
+
* Strip overload indices (e.g. NestJS emits `Foo_bar[0]` when a controller
|
|
1817
|
+
* method handles multiple routes) from an operationId so derived names never
|
|
1818
|
+
* leak the bracketed digit. Without this, `authenticate[0]` would surface as
|
|
1819
|
+
* `authenticate0` in method names and `Authenticate0Request` in body model
|
|
1820
|
+
* names. Brackets at the end (or with trailing whitespace) are common in
|
|
1821
|
+
* NestJS-style backends; this regex is intentionally narrow to avoid eating
|
|
1822
|
+
* legitimate digits like `oauth2`.
|
|
1823
|
+
*/
|
|
1824
|
+
function normalizeOperationIdForNaming(operationId) {
|
|
1825
|
+
return operationId.replace(/\[\d+\]\s*$/, "");
|
|
1826
|
+
}
|
|
1663
1827
|
function inferOperationName(method, path, operationId, operationIdTransform) {
|
|
1664
1828
|
if (operationId) {
|
|
1665
|
-
|
|
1666
|
-
return
|
|
1829
|
+
const normalized = normalizeOperationIdForNaming(operationId);
|
|
1830
|
+
if (operationIdTransform) return operationIdTransform(normalized);
|
|
1831
|
+
return toCamelCase(normalized);
|
|
1667
1832
|
}
|
|
1668
1833
|
const verb = inferVerb(method, path);
|
|
1669
1834
|
const resource = inferResourceFromPath(path);
|
|
@@ -1981,7 +2146,7 @@ function extractRequestBody(body, op, inlineModels) {
|
|
|
1981
2146
|
};
|
|
1982
2147
|
return {};
|
|
1983
2148
|
}
|
|
1984
|
-
const contextName = cleanSchemaName(op?.operationId ? toPascalCase(op.operationId) + "Request" : "RequestBody");
|
|
2149
|
+
const contextName = cleanSchemaName(op?.operationId ? toPascalCase(normalizeOperationIdForNaming(op.operationId)) + "Request" : "RequestBody");
|
|
1985
2150
|
if (schema.properties && (schema.type === "object" || !schema.type)) {
|
|
1986
2151
|
const requiredSet = new Set(schema.required ?? []);
|
|
1987
2152
|
const fields = [];
|
|
@@ -2062,7 +2227,7 @@ function deriveOneOfVariantName(variant, baseName, existingModels) {
|
|
|
2062
2227
|
return name;
|
|
2063
2228
|
}
|
|
2064
2229
|
function deriveResponseName(op, path, method) {
|
|
2065
|
-
if (op?.operationId) return cleanSchemaName(toPascalCase(op.operationId) + "Response");
|
|
2230
|
+
if (op?.operationId) return cleanSchemaName(toPascalCase(normalizeOperationIdForNaming(op.operationId)) + "Response");
|
|
2066
2231
|
return toPascalCase(path.split("/").filter(Boolean)[0] ?? "Unknown") + toPascalCase(method) + "Response";
|
|
2067
2232
|
}
|
|
2068
2233
|
function extractResponses(responses, op, path, method) {
|