@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
package/dist/cli/index.mjs
CHANGED
|
@@ -456,17 +456,64 @@ function extractInlineModelsFromProperties(schema, results, parentName) {
|
|
|
456
456
|
}
|
|
457
457
|
}
|
|
458
458
|
if (fieldSchema.oneOf) {
|
|
459
|
-
const
|
|
460
|
-
if (
|
|
459
|
+
const inlineObjectVariants = fieldSchema.oneOf.filter((v) => !v.$ref && v.properties && (v.type === "object" || !v.type));
|
|
460
|
+
if (inlineObjectVariants.length > 0) {
|
|
461
461
|
const modelName = qualifyInlineModelName(toPascalCase(fieldName), parentName);
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
462
|
+
const existingNames = new Set(results.map((r) => r.name));
|
|
463
|
+
const namingDiscProp = deriveOneOfNamingDiscriminator(inlineObjectVariants);
|
|
464
|
+
const emittedNames = [];
|
|
465
|
+
for (const variant of inlineObjectVariants) {
|
|
466
|
+
const variantName = nameOneOfVariant(variant, modelName, emittedNames, namingDiscProp);
|
|
467
|
+
emittedNames.push(variantName);
|
|
468
|
+
if (!existingNames.has(variantName)) {
|
|
469
|
+
existingNames.add(variantName);
|
|
470
|
+
results.push(buildInlineModel(variantName, variant));
|
|
471
|
+
extractInlineModelsFromProperties(variant, results, variantName);
|
|
472
|
+
}
|
|
465
473
|
}
|
|
466
474
|
}
|
|
467
475
|
}
|
|
468
476
|
}
|
|
469
477
|
}
|
|
478
|
+
/** Find a single string-const-valued property shared by every variant whose
|
|
479
|
+
* values are all distinct — the implicit discriminator. Returns null when no
|
|
480
|
+
* such property exists. Mirrors `deriveConstNamingDiscriminator` in schemas.ts. */
|
|
481
|
+
function deriveOneOfNamingDiscriminator(variants) {
|
|
482
|
+
if (variants.length < 2) return null;
|
|
483
|
+
const candidates = Object.keys(variants[0]?.properties ?? {});
|
|
484
|
+
for (const propName of candidates) {
|
|
485
|
+
const values = variants.map((v) => readConstString(v.properties?.[propName]));
|
|
486
|
+
if (values.some((v) => v === null)) continue;
|
|
487
|
+
if (new Set(values).size !== values.length) continue;
|
|
488
|
+
return propName;
|
|
489
|
+
}
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
function readConstString(prop) {
|
|
493
|
+
if (!prop) return null;
|
|
494
|
+
if (typeof prop.const === "string") return prop.const;
|
|
495
|
+
if (Array.isArray(prop.enum) && prop.enum.length === 1 && typeof prop.enum[0] === "string") return prop.enum[0];
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
/** Produce a per-variant model name. Variant 0 keeps the bare parent name;
|
|
499
|
+
* later variants are prefixed by the const-derived label. Mirrors
|
|
500
|
+
* `nameVariantModel` in schemas.ts. Falls back to a numeric suffix when no
|
|
501
|
+
* discriminator is available, the const value PascalCases to nothing, or
|
|
502
|
+
* the derived candidate collides with the parent or an already-emitted name. */
|
|
503
|
+
function nameOneOfVariant(variant, parentName, alreadyEmitted, discriminatorProperty) {
|
|
504
|
+
if (alreadyEmitted.length === 0) return parentName;
|
|
505
|
+
if (discriminatorProperty) {
|
|
506
|
+
const constValue = readConstString(variant.properties?.[discriminatorProperty]);
|
|
507
|
+
if (constValue) {
|
|
508
|
+
const prefix = toPascalCase(constValue);
|
|
509
|
+
if (prefix) {
|
|
510
|
+
const candidate = parentName.startsWith(prefix) ? parentName : `${prefix}${parentName}`;
|
|
511
|
+
if (!(candidate === parentName || alreadyEmitted.includes(candidate))) return candidate;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return `${parentName}${alreadyEmitted.length + 1}`;
|
|
516
|
+
}
|
|
470
517
|
function buildInlineModel(name, schema) {
|
|
471
518
|
const requiredSet = new Set(schema.required ?? []);
|
|
472
519
|
const fields = [];
|
|
@@ -487,6 +534,14 @@ function buildInlineModel(name, schema) {
|
|
|
487
534
|
* to apply the same name transform to $ref model/enum references.
|
|
488
535
|
*/
|
|
489
536
|
let activeSchemaNameTransform = null;
|
|
537
|
+
/**
|
|
538
|
+
* Module-level set of resolved schema names whose components/schemas entry is
|
|
539
|
+
* an enum (i.e. has `enum:`). Populated by extractSchemas() so schemaToTypeRef()
|
|
540
|
+
* can classify a `$ref` to a top-level enum schema as `kind: 'enum'` instead of
|
|
541
|
+
* `kind: 'model'`. Without this, every `$ref` was naively returned as a model
|
|
542
|
+
* ref, even when the target was a shared enum like `PaginationOrder`.
|
|
543
|
+
*/
|
|
544
|
+
let activeEnumSchemaNames = /* @__PURE__ */ new Set();
|
|
490
545
|
/** Apply cleanSchemaName + the active transform (if any) to a raw schema name. */
|
|
491
546
|
function resolveSchemaName(rawName) {
|
|
492
547
|
let name = cleanSchemaName(toPascalCase(rawName));
|
|
@@ -512,6 +567,8 @@ function extractSchemas(schemas, options) {
|
|
|
512
567
|
for (const [, originals] of transformedToOriginals) if (originals.length > 1) for (const n of originals) unsafeToTransform.add(n);
|
|
513
568
|
activeSchemaNameTransform = (name) => unsafeToTransform.has(name) ? name : transform(name);
|
|
514
569
|
} else activeSchemaNameTransform = null;
|
|
570
|
+
activeEnumSchemaNames = /* @__PURE__ */ new Set();
|
|
571
|
+
for (const [name, schema] of Object.entries(schemas)) if (schema.enum) activeEnumSchemaNames.add(resolveSchemaName(name));
|
|
515
572
|
const modelsByCleanName = /* @__PURE__ */ new Map();
|
|
516
573
|
for (const [name, schema] of Object.entries(schemas)) {
|
|
517
574
|
const pascalName = resolveSchemaName(name);
|
|
@@ -546,6 +603,7 @@ function extractSchemas(schemas, options) {
|
|
|
546
603
|
/** Clear the module-level schemaNameTransform. Called by parseSpec() after all extraction phases. */
|
|
547
604
|
function clearSchemaNameTransform() {
|
|
548
605
|
activeSchemaNameTransform = null;
|
|
606
|
+
activeEnumSchemaNames = /* @__PURE__ */ new Set();
|
|
549
607
|
}
|
|
550
608
|
/**
|
|
551
609
|
* Walk a single TypeRef and extract inline enum refs as top-level enum definitions.
|
|
@@ -833,6 +891,51 @@ function resolveVariantModelName(schema) {
|
|
|
833
891
|
if (title) return resolveSchemaName(title);
|
|
834
892
|
return null;
|
|
835
893
|
}
|
|
894
|
+
/** Look up the discriminator's mapped variant name for an inline object
|
|
895
|
+
* variant by reading its const-valued discriminator property. Returns null
|
|
896
|
+
* when the variant doesn't pin the property to a string const, or when
|
|
897
|
+
* the value isn't in the mapping. */
|
|
898
|
+
function mapVariantToDiscriminatorEntry(variant, discriminator) {
|
|
899
|
+
const value = getConstPropertyValue(variant, discriminator.property);
|
|
900
|
+
if (value === null) return null;
|
|
901
|
+
return discriminator.mapping[value] ?? null;
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Derive a discriminator value → variant model name mapping for an inline-
|
|
905
|
+
* variant `oneOf` whose explicit `discriminator:` has no `mapping:` clause.
|
|
906
|
+
*
|
|
907
|
+
* Each variant model name is reproduced via `nameVariantModel` so it matches
|
|
908
|
+
* what `extractNestedSchema` registered when it walked the same `oneOf` to
|
|
909
|
+
* pull variants out as named models. Variant 0 keeps the bare parent name
|
|
910
|
+
* (e.g. `ApiKeyOwner`); subsequent variants get a const-derived prefix
|
|
911
|
+
* (e.g. `UserApiKeyOwner` for the `type: const: user` variant).
|
|
912
|
+
*
|
|
913
|
+
* The "parent name" used here mirrors the one `collectNestedInlineModels`
|
|
914
|
+
* passes to `extractNestedSchema`: it's the qualified inline model name
|
|
915
|
+
* built from `contextName` (the field name) plus `parentModelName` (the
|
|
916
|
+
* containing model). Returns null when any non-object variant is present
|
|
917
|
+
* or when a variant lacks a const value on the discriminator property.
|
|
918
|
+
*/
|
|
919
|
+
function deriveInlineVariantMapping(variants, discriminatorProperty, contextName, parentModelName) {
|
|
920
|
+
if (variants.length === 0 || !contextName) return null;
|
|
921
|
+
const inlineObjectVariants = variants.filter((v) => !v.$ref && v.properties && (v.type === "object" || !v.type));
|
|
922
|
+
if (inlineObjectVariants.length !== variants.length) return null;
|
|
923
|
+
const baseInlineName = qualifyInlineModelName(toPascalCase(contextName), parentModelName);
|
|
924
|
+
const namingDiscriminator = { property: discriminatorProperty };
|
|
925
|
+
const mapping = {};
|
|
926
|
+
const emittedSoFar = [];
|
|
927
|
+
for (const variant of inlineObjectVariants) {
|
|
928
|
+
const constValue = getConstPropertyValue(variant, discriminatorProperty);
|
|
929
|
+
if (constValue === null) return null;
|
|
930
|
+
const variantName = nameVariantModel(variant, baseInlineName, emittedSoFar, namingDiscriminator);
|
|
931
|
+
mapping[constValue] = variantName;
|
|
932
|
+
emittedSoFar.push({
|
|
933
|
+
name: variantName,
|
|
934
|
+
fields: []
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
return mapping;
|
|
938
|
+
}
|
|
836
939
|
function extractEnum(name, schema) {
|
|
837
940
|
return {
|
|
838
941
|
name,
|
|
@@ -1031,8 +1134,20 @@ function extractInlineModelDeep(name, schema) {
|
|
|
1031
1134
|
}));
|
|
1032
1135
|
}
|
|
1033
1136
|
if (fieldSchema.oneOf) {
|
|
1034
|
-
const
|
|
1035
|
-
if (
|
|
1137
|
+
const inlineObjectVariants = fieldSchema.oneOf.filter((v) => !v.$ref && v.properties && (v.type === "object" || !v.type));
|
|
1138
|
+
if (inlineObjectVariants.length > 0) {
|
|
1139
|
+
const baseQualified = qualifyNestedInlineName(name, fieldName);
|
|
1140
|
+
const namingDisc = deriveConstNamingDiscriminator(inlineObjectVariants);
|
|
1141
|
+
const emitted = [];
|
|
1142
|
+
for (const variant of inlineObjectVariants) {
|
|
1143
|
+
const variantName = nameVariantModel(variant, baseQualified, emitted, namingDisc);
|
|
1144
|
+
emitted.push({
|
|
1145
|
+
name: variantName,
|
|
1146
|
+
fields: []
|
|
1147
|
+
});
|
|
1148
|
+
nestedModels.push(...extractInlineModelDeep(variantName, variant));
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1036
1151
|
}
|
|
1037
1152
|
}
|
|
1038
1153
|
return [{
|
|
@@ -1053,9 +1168,14 @@ function schemaToTypeRef(schema, contextName, parentModelName) {
|
|
|
1053
1168
|
if (schema.$ref) {
|
|
1054
1169
|
const segments = schema.$ref.split("/");
|
|
1055
1170
|
const rawName = segments[segments.length - 1];
|
|
1171
|
+
const resolved = resolveSchemaName(rawName);
|
|
1172
|
+
if (activeEnumSchemaNames.has(resolved)) return {
|
|
1173
|
+
kind: "enum",
|
|
1174
|
+
name: resolved
|
|
1175
|
+
};
|
|
1056
1176
|
return {
|
|
1057
1177
|
kind: "model",
|
|
1058
|
-
name:
|
|
1178
|
+
name: resolved
|
|
1059
1179
|
};
|
|
1060
1180
|
}
|
|
1061
1181
|
if (Array.isArray(schema.type)) {
|
|
@@ -1129,17 +1249,49 @@ function schemaToTypeRef(schema, contextName, parentModelName) {
|
|
|
1129
1249
|
inner: enumRef
|
|
1130
1250
|
} : enumRef;
|
|
1131
1251
|
}
|
|
1132
|
-
|
|
1133
|
-
|
|
1252
|
+
let resolvedDiscriminator;
|
|
1253
|
+
if (schema.discriminator) {
|
|
1254
|
+
const property = schema.discriminator.propertyName;
|
|
1255
|
+
const explicitMapping = schema.discriminator.mapping ?? {};
|
|
1256
|
+
let mapping = Object.fromEntries(Object.entries(explicitMapping).map(([k, v]) => [k, v.replace(/^#\/components\/schemas\//, "")]));
|
|
1257
|
+
if (Object.keys(mapping).length === 0) {
|
|
1258
|
+
const inlineMapping = deriveInlineVariantMapping(nonNullVariants, property, contextName, parentModelName);
|
|
1259
|
+
if (inlineMapping) mapping = inlineMapping;
|
|
1260
|
+
}
|
|
1261
|
+
resolvedDiscriminator = {
|
|
1262
|
+
property,
|
|
1263
|
+
mapping
|
|
1264
|
+
};
|
|
1265
|
+
} else if (compositionKind === "oneOf") {
|
|
1266
|
+
const synthetic = detectConstPropertyDiscriminator(nonNullVariants);
|
|
1267
|
+
if (synthetic) resolvedDiscriminator = synthetic;
|
|
1268
|
+
else {
|
|
1269
|
+
const namingDisc = deriveConstNamingDiscriminator(nonNullVariants);
|
|
1270
|
+
if (namingDisc) {
|
|
1271
|
+
const inlineMapping = deriveInlineVariantMapping(nonNullVariants, namingDisc.property, contextName, parentModelName);
|
|
1272
|
+
if (inlineMapping) resolvedDiscriminator = {
|
|
1273
|
+
property: namingDisc.property,
|
|
1274
|
+
mapping: inlineMapping
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
const variants = [];
|
|
1280
|
+
for (const v of rawVariants) {
|
|
1281
|
+
if (v === nullVariant) continue;
|
|
1282
|
+
const inlineMappingName = resolvedDiscriminator && !v.$ref && v.properties && (v.type === "object" || !v.type) ? mapVariantToDiscriminatorEntry(v, resolvedDiscriminator) : null;
|
|
1283
|
+
if (inlineMappingName) variants.push({
|
|
1284
|
+
kind: "model",
|
|
1285
|
+
name: inlineMappingName
|
|
1286
|
+
});
|
|
1287
|
+
else variants.push(schemaToTypeRef(v, contextName, parentModelName));
|
|
1288
|
+
}
|
|
1134
1289
|
const hasNull = !!nullVariant;
|
|
1135
1290
|
const union = {
|
|
1136
1291
|
kind: "union",
|
|
1137
1292
|
variants,
|
|
1138
1293
|
compositionKind,
|
|
1139
|
-
...
|
|
1140
|
-
property: schema.discriminator.propertyName,
|
|
1141
|
-
mapping: Object.fromEntries(Object.entries(schema.discriminator.mapping ?? {}).map(([k, v]) => [k, v.replace(/^#\/components\/schemas\//, "")]))
|
|
1142
|
-
} } : syntheticDiscriminator ? { discriminator: syntheticDiscriminator } : {}
|
|
1294
|
+
...resolvedDiscriminator ? { discriminator: resolvedDiscriminator } : {}
|
|
1143
1295
|
};
|
|
1144
1296
|
return hasNull ? {
|
|
1145
1297
|
kind: "nullable",
|
|
@@ -1711,10 +1863,23 @@ function inferServiceName(path, tag) {
|
|
|
1711
1863
|
if (first.startsWith("{")) return "Default";
|
|
1712
1864
|
return toPascalCase(first);
|
|
1713
1865
|
}
|
|
1866
|
+
/**
|
|
1867
|
+
* Strip overload indices (e.g. NestJS emits `Foo_bar[0]` when a controller
|
|
1868
|
+
* method handles multiple routes) from an operationId so derived names never
|
|
1869
|
+
* leak the bracketed digit. Without this, `authenticate[0]` would surface as
|
|
1870
|
+
* `authenticate0` in method names and `Authenticate0Request` in body model
|
|
1871
|
+
* names. Brackets at the end (or with trailing whitespace) are common in
|
|
1872
|
+
* NestJS-style backends; this regex is intentionally narrow to avoid eating
|
|
1873
|
+
* legitimate digits like `oauth2`.
|
|
1874
|
+
*/
|
|
1875
|
+
function normalizeOperationIdForNaming(operationId) {
|
|
1876
|
+
return operationId.replace(/\[\d+\]\s*$/, "");
|
|
1877
|
+
}
|
|
1714
1878
|
function inferOperationName(method, path, operationId, operationIdTransform) {
|
|
1715
1879
|
if (operationId) {
|
|
1716
|
-
|
|
1717
|
-
return
|
|
1880
|
+
const normalized = normalizeOperationIdForNaming(operationId);
|
|
1881
|
+
if (operationIdTransform) return operationIdTransform(normalized);
|
|
1882
|
+
return toCamelCase(normalized);
|
|
1718
1883
|
}
|
|
1719
1884
|
const verb = inferVerb(method, path);
|
|
1720
1885
|
const resource = inferResourceFromPath(path);
|
|
@@ -2032,7 +2197,7 @@ function extractRequestBody(body, op, inlineModels) {
|
|
|
2032
2197
|
};
|
|
2033
2198
|
return {};
|
|
2034
2199
|
}
|
|
2035
|
-
const contextName = cleanSchemaName(op?.operationId ? toPascalCase(op.operationId) + "Request" : "RequestBody");
|
|
2200
|
+
const contextName = cleanSchemaName(op?.operationId ? toPascalCase(normalizeOperationIdForNaming(op.operationId)) + "Request" : "RequestBody");
|
|
2036
2201
|
if (schema.properties && (schema.type === "object" || !schema.type)) {
|
|
2037
2202
|
const requiredSet = new Set(schema.required ?? []);
|
|
2038
2203
|
const fields = [];
|
|
@@ -2113,7 +2278,7 @@ function deriveOneOfVariantName(variant, baseName, existingModels) {
|
|
|
2113
2278
|
return name;
|
|
2114
2279
|
}
|
|
2115
2280
|
function deriveResponseName(op, path, method) {
|
|
2116
|
-
if (op?.operationId) return cleanSchemaName(toPascalCase(op.operationId) + "Response");
|
|
2281
|
+
if (op?.operationId) return cleanSchemaName(toPascalCase(normalizeOperationIdForNaming(op.operationId)) + "Response");
|
|
2117
2282
|
return toPascalCase(path.split("/").filter(Boolean)[0] ?? "Unknown") + toPascalCase(method) + "Response";
|
|
2118
2283
|
}
|
|
2119
2284
|
function extractResponses(responses, op, path, method) {
|