@workos/oagen 0.29.2 → 0.29.4
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 +488 -27
- package/dist/cli/index.mjs.map +1 -1
- package/dist/compat/index.d.mts +2 -2
- package/dist/{diff-DqnHHXvr.mjs → diff-B6TjXIwb.mjs} +139 -6
- package/dist/diff-B6TjXIwb.mjs.map +1 -0
- package/dist/{differ-DxWejtEg.d.mts → differ-DHldxZMr.d.mts} +2 -2
- package/dist/{differ-DxWejtEg.d.mts.map → differ-DHldxZMr.d.mts.map} +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +351 -23
- package/dist/index.mjs.map +1 -1
- package/dist/scripts/smoke/baseline.mjs +350 -22
- package/dist/scripts/smoke/baseline.mjs.map +1 -1
- package/dist/smoke.d.mts +20 -0
- package/dist/smoke.d.mts.map +1 -1
- package/dist/smoke.mjs +350 -22
- package/dist/smoke.mjs.map +1 -1
- package/dist/tree-sitter-C6HB4OrC.mjs.map +1 -1
- package/dist/{types-CEMBeTr9.d.mts → types-yrBidOg3.d.mts} +21 -1
- package/dist/{types-CEMBeTr9.d.mts.map → types-yrBidOg3.d.mts.map} +1 -1
- package/dist/verify/index.d.mts +2 -2
- package/dist/verify/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/diff-DqnHHXvr.mjs.map +0 -1
package/dist/smoke.d.mts
CHANGED
|
@@ -209,6 +209,26 @@ interface ParameterGroup {
|
|
|
209
209
|
optional: boolean;
|
|
210
210
|
/** Ordered variants (insertion order matches the spec). */
|
|
211
211
|
variants: ParameterGroupVariant[];
|
|
212
|
+
/**
|
|
213
|
+
* Base name emitters must use for this group's generated wrapper type, in
|
|
214
|
+
* place of `name`.
|
|
215
|
+
*
|
|
216
|
+
* Two operations commonly share one group name — create and update both
|
|
217
|
+
* declare `protocol_options` — and emitters name the wrapper from the group
|
|
218
|
+
* name alone, so both operations collapse onto one type. That is correct
|
|
219
|
+
* only while their members agree. When they disagree (create's
|
|
220
|
+
* `saml_options` is a `CreateConnectionSAMLOptions`, update's is a
|
|
221
|
+
* `PatchConnectionSAMLOptions`) one wrapper silently forces one operation to
|
|
222
|
+
* use the other operation's type.
|
|
223
|
+
*
|
|
224
|
+
* The parser therefore fingerprints each group's members across every
|
|
225
|
+
* operation declaring it and qualifies this with the operation name
|
|
226
|
+
* (`update_connection_protocol_options`) only where they genuinely diverge.
|
|
227
|
+
* Groups that agree — including ones differing only by nullability, or by
|
|
228
|
+
* duplicate inline enums carrying identical values — keep the bare group
|
|
229
|
+
* name, so already-published wrapper types are never renamed.
|
|
230
|
+
*/
|
|
231
|
+
wrapperName?: string;
|
|
212
232
|
}
|
|
213
233
|
/**
|
|
214
234
|
* One variant within a mutually-exclusive parameter group.
|
package/dist/smoke.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smoke.d.mts","names":[],"sources":["../src/ir/sdk-behavior.ts","../src/ir/types.ts","../src/parser/parse.ts","../src/utils/naming.ts","../scripts/smoke/shared.ts"],"mappings":";;;;AAYA;;;;;;UAAiB,WAAA;EAQf;EANA,oBAAA;EAQS;EANT,UAAA;EAMwB;EAJxB,sBAAA;EAY8B;EAV9B,cAAA;EAU8B;EAR9B,OAAA,EAAS,eAAA;AAAA;;;;;AAsBX;UAdiB,eAAA;;EAEf,YAAA;EAeA;EAbA,UAAA;EAeA;EAbA,QAAA;EAiBA;EAfA,YAAA;AAAA;AAqBF;AAAA,UAfiB,WAAA;;;EAGf,aAAA,EAAe,MAAA;EAgBf;EAdA,eAAA;EAgBe;EAdf,eAAA;EAoBe;EAlBf,mBAAA;AAAA;;UAMe,eAAA;EAoBA;EAlBf,gBAAA;;EAEA,UAAA;EAoBmB;EAlBnB,eAAA;AAAA;;UAMe,gBAAA;EAoBf;EAlBA,eAAA;AAAA;;UAMe,iBAAA;EAkBL;EAhBV,UAAA;;EAEA,mBAAA;AAAA;AAyBF;AAAA,UAnBiB,aAAA;;EAEf,OAAA;EAsBA;EApBA,MAAA,EAAQ,QAAA;AAAA;;KAIE,QAAA;;UAWK,eAAA;EAeA;;;;EAVf,qBAAA;EAoBe;EAlBf,qBAAA;;EAEA,YAAA;EAmBU;EAjBV,cAAA,EAAgB,aAAA;AAAA;;UAID,aAAA;EAuBF;EArBb,MAAA;EA4B0B;EA1B1B,SAAA;AAAA;;UAMe,kBAAA;EAwBH;;EArBZ,UAAA;AAAA;;UAMe,aAAA;EAoBO;EAlBtB,qBAAA;EAUA;EARA,aAAA;AAAA;;;UAOe,WAAA;EACf,KAAA,EAAO,WAAA;EACP,MAAA,EAAQ,WAAA;EACR,SAAA,EAAW,eAAA;EACX,UAAA,EAAY,gBAAA;EACZ,WAAA,EAAa,iBAAA;EACb,OAAA,EAAS,aAAA;EACT,SAAA,EAAW,eAAA;EACX,YAAA,EAAc,kBAAA;EACd,OAAA,EAAS,aAAA;AAAA;;;;KC/JC,UAAA;EACN,IAAA;AAAA;EACA,IAAA;EAAgB,EAAA;EAAmC,IAAA;AAAA;EACnD,IAAA;EAAgB,KAAA,EAAO,MAAA;AAAA;;;UAIZ,WAAA;EACf,GAAA;EACA,WAAA;AAAA;;UAIe,OAAA;EACf,IAAA;EACA,OAAA;EACA,WAAA;EACA,OAAA;EACA,OAAA,GAAU,WAAA;EACV,QAAA,EAAU,OAAA;EACV,MAAA,EAAQ,KAAA;EACR,KAAA,EAAO,IAAA;EACP,IAAA,GAAO,UAAA;EDsBP;ECpBA,GAAA,EAAK,WAAA;AAAA;;UAIU,OAAA;EACf,IAAA;EACA,WAAA;EACA,UAAA,EAAY,SAAA;AAAA;;;UAKG,mBAAA;EACf,UAAA;EACA,MAAA;AAAA;AAAA,UAGe,SAAA;EACf,IAAA;EACA,WAAA;EACA,UAAA,EAAY,UAAA;EACZ,IAAA;EACA,UAAA,EAAY,SAAA;EACZ,WAAA,EAAa,SAAA;EACb,YAAA,EAAc,SAAA;EACd,YAAA,GAAe,SAAA;EACf,WAAA,GAAc,OAAA;EACd,mBAAA;EACA,QAAA,EAAU,OAAA;EACV,gBAAA,GAAmB,eAAA;EACnB,MAAA,EAAQ,aAAA;EACR,UAAA,GAAa,cAAA;EACb,oBAAA;EACA,UAAA;EACA,KAAA;EDgCgB;EC9BhB,QAAA,GAAW,mBAAA;EDkCD;;;;;AAWZ;;ECrCE,eAAA,GAAkB,cAAA;AAAA;;;;;UAOH,cAAA;EDyCc;ECvC7B,IAAA;ED2Ce;ECzCf,QAAA;;EAEA,QAAA,EAAU,qBAAA;
|
|
1
|
+
{"version":3,"file":"smoke.d.mts","names":[],"sources":["../src/ir/sdk-behavior.ts","../src/ir/types.ts","../src/parser/parse.ts","../src/utils/naming.ts","../scripts/smoke/shared.ts"],"mappings":"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"}
|
package/dist/smoke.mjs
CHANGED
|
@@ -1940,6 +1940,30 @@ function extractInlineModel(name, schema) {
|
|
|
1940
1940
|
}
|
|
1941
1941
|
//#endregion
|
|
1942
1942
|
//#region src/parser/operations.ts
|
|
1943
|
+
/**
|
|
1944
|
+
* Resolve a raw parameter entry to a concrete Parameter Object, following
|
|
1945
|
+
* `$ref`s into `components/parameters` when present. Follows chains of refs
|
|
1946
|
+
* (a component that itself is a `$ref` to another component), with a cycle
|
|
1947
|
+
* guard for a spec that refs itself.
|
|
1948
|
+
*
|
|
1949
|
+
* Throws when a `$ref` can't be resolved so a malformed spec fails loudly at
|
|
1950
|
+
* parse time instead of silently losing the parameter (see `extractParams`,
|
|
1951
|
+
* which used to drop any entry with no `in` field — every `$ref` object has
|
|
1952
|
+
* none).
|
|
1953
|
+
*/
|
|
1954
|
+
function resolveParameterRef(raw, componentParameters, operationContext) {
|
|
1955
|
+
const seenRefs = /* @__PURE__ */ new Set();
|
|
1956
|
+
let current = raw;
|
|
1957
|
+
while ("$ref" in current) {
|
|
1958
|
+
if (seenRefs.has(current.$ref)) throw new Error(`Circular parameter $ref chain starting at "${current.$ref}" in ${operationContext}.`);
|
|
1959
|
+
seenRefs.add(current.$ref);
|
|
1960
|
+
const refName = /^#\/components\/parameters\/(.+)$/.exec(current.$ref)?.[1].replace(/~1/g, "/").replace(/~0/g, "~");
|
|
1961
|
+
const resolved = refName ? componentParameters?.[refName] : void 0;
|
|
1962
|
+
if (!resolved) throw new Error(`Unresolved parameter $ref "${current.$ref}" in ${operationContext}: no matching entry under components/parameters.`);
|
|
1963
|
+
current = resolved;
|
|
1964
|
+
}
|
|
1965
|
+
return current;
|
|
1966
|
+
}
|
|
1943
1967
|
const HTTP_METHODS = [
|
|
1944
1968
|
"get",
|
|
1945
1969
|
"post",
|
|
@@ -1950,7 +1974,7 @@ const HTTP_METHODS = [
|
|
|
1950
1974
|
"options",
|
|
1951
1975
|
"trace"
|
|
1952
1976
|
];
|
|
1953
|
-
function extractOperations(paths, operationIdTransform, componentSchemas) {
|
|
1977
|
+
function extractOperations(paths, operationIdTransform, componentSchemas, componentParameters) {
|
|
1954
1978
|
if (!paths) return {
|
|
1955
1979
|
services: [],
|
|
1956
1980
|
inlineModels: []
|
|
@@ -1963,7 +1987,7 @@ function extractOperations(paths, operationIdTransform, componentSchemas) {
|
|
|
1963
1987
|
const op = pathItem[method];
|
|
1964
1988
|
if (!op) continue;
|
|
1965
1989
|
const serviceName = inferServiceName(path, op.tags?.[0]);
|
|
1966
|
-
const { operation, inlineModels: opModels } = buildOperation(method, path, op, pathLevelParams, operationIdTransform, serviceName, componentSchemas);
|
|
1990
|
+
const { operation, inlineModels: opModels } = buildOperation(method, path, op, pathLevelParams, operationIdTransform, serviceName, componentSchemas, componentParameters);
|
|
1967
1991
|
inlineModels.push(...opModels);
|
|
1968
1992
|
const ops = serviceMap.get(serviceName) ?? [];
|
|
1969
1993
|
ops.push(operation);
|
|
@@ -2161,19 +2185,11 @@ function extractParameterGroups(op, allIRParams, operationContext) {
|
|
|
2161
2185
|
* the request body. Emitters use the group's presence to generate sum-type
|
|
2162
2186
|
* interfaces and custom JSON marshalling instead of flat optional fields.
|
|
2163
2187
|
*/
|
|
2164
|
-
function extractBodyParameterGroups(op, operationContext) {
|
|
2188
|
+
function extractBodyParameterGroups(op, operationContext, componentSchemas) {
|
|
2165
2189
|
const raw = op["x-mutually-exclusive-body-groups"];
|
|
2166
2190
|
if (!raw || typeof raw !== "object") return void 0;
|
|
2167
2191
|
const bodySchema = op.requestBody?.content?.["application/json"]?.schema;
|
|
2168
|
-
const variantFieldSchemas =
|
|
2169
|
-
if (bodySchema) {
|
|
2170
|
-
for (const sub of bodySchema.allOf ?? []) for (const variant of sub.oneOf ?? []) if (variant.properties) {
|
|
2171
|
-
for (const [name, fieldSchema] of Object.entries(variant.properties)) if (fieldSchema) variantFieldSchemas.set(name, fieldSchema);
|
|
2172
|
-
}
|
|
2173
|
-
for (const variant of bodySchema.oneOf ?? []) if (variant.properties) {
|
|
2174
|
-
for (const [name, fieldSchema] of Object.entries(variant.properties)) if (fieldSchema) variantFieldSchemas.set(name, fieldSchema);
|
|
2175
|
-
}
|
|
2176
|
-
}
|
|
2192
|
+
const variantFieldSchemas = collectVariantFieldSchemas(bodySchema, componentSchemas);
|
|
2177
2193
|
const groups = [];
|
|
2178
2194
|
for (const [groupName, groupDef] of Object.entries(raw)) {
|
|
2179
2195
|
if (!groupDef || typeof groupDef !== "object") continue;
|
|
@@ -2183,10 +2199,12 @@ function extractBodyParameterGroups(op, operationContext) {
|
|
|
2183
2199
|
const variants = Object.entries(groupDef.variants).map(([variantName, paramNames]) => {
|
|
2184
2200
|
if (!Array.isArray(paramNames) || paramNames.length === 0) throw new Error(`Malformed x-mutually-exclusive-body-groups.${groupName}.variants.${variantName} in ${operationContext}: expected a non-empty array of parameter names.`);
|
|
2185
2201
|
const parameters = paramNames.map((pName) => {
|
|
2186
|
-
const
|
|
2202
|
+
const entry = variantFieldSchemas.get(pName);
|
|
2203
|
+
const fieldSchema = entry?.schema;
|
|
2204
|
+
if (!fieldSchema) console.warn(`[oagen] Warning: x-mutually-exclusive-body-groups.${groupName}.variants.${variantName} references "${pName}" in ${operationContext}, but no oneOf branch of the request body declares that property. Falling back to type: string.`);
|
|
2187
2205
|
return {
|
|
2188
2206
|
name: pName,
|
|
2189
|
-
type: fieldSchema ? schemaToTypeRef(fieldSchema, toPascalCase(pName)) : {
|
|
2207
|
+
type: fieldSchema ? schemaToTypeRef(fieldSchema, toPascalCase(pName), entry?.owner) : {
|
|
2190
2208
|
kind: "primitive",
|
|
2191
2209
|
type: "string"
|
|
2192
2210
|
},
|
|
@@ -2210,8 +2228,14 @@ function extractBodyParameterGroups(op, operationContext) {
|
|
|
2210
2228
|
}
|
|
2211
2229
|
return groups.length > 0 ? groups : void 0;
|
|
2212
2230
|
}
|
|
2213
|
-
function buildOperation(method, path, op, pathLevelParams, operationIdTransform, serviceName, componentSchemas) {
|
|
2214
|
-
const
|
|
2231
|
+
function buildOperation(method, path, op, pathLevelParams, operationIdTransform, serviceName, componentSchemas, componentParameters) {
|
|
2232
|
+
const opLabel = op.operationId ?? `${method.toUpperCase()} ${path}`;
|
|
2233
|
+
const paramsByIdentity = /* @__PURE__ */ new Map();
|
|
2234
|
+
for (const raw of [...pathLevelParams, ...op.parameters ?? []]) {
|
|
2235
|
+
const param = resolveParameterRef(raw, componentParameters, opLabel);
|
|
2236
|
+
paramsByIdentity.set(`${param.in}:${param.name}`, param);
|
|
2237
|
+
}
|
|
2238
|
+
const allParams = [...paramsByIdentity.values()];
|
|
2215
2239
|
const hasIdempotencyHeader = allParams.some((p) => p.in === "header" && p.name.toLowerCase() === "idempotency-key");
|
|
2216
2240
|
const opContext = serviceName;
|
|
2217
2241
|
const pathParams = extractParams(allParams, "path", opContext, componentSchemas);
|
|
@@ -2235,15 +2259,13 @@ function buildOperation(method, path, op, pathLevelParams, operationIdTransform,
|
|
|
2235
2259
|
};
|
|
2236
2260
|
} else if (paginationFromParams) pagination = paginationFromParams;
|
|
2237
2261
|
const security = extractOperationSecurity(op.security);
|
|
2238
|
-
const
|
|
2262
|
+
const queryParamGroups = extractParameterGroups(op, [
|
|
2239
2263
|
...pathParams,
|
|
2240
2264
|
...queryParams,
|
|
2241
2265
|
...headerParams,
|
|
2242
2266
|
...cookieParams
|
|
2243
|
-
];
|
|
2244
|
-
const
|
|
2245
|
-
const queryParamGroups = extractParameterGroups(op, allIRParams, opLabel);
|
|
2246
|
-
const bodyParamGroups = extractBodyParameterGroups(op, opLabel);
|
|
2267
|
+
], opLabel);
|
|
2268
|
+
const bodyParamGroups = extractBodyParameterGroups(op, opLabel, componentSchemas);
|
|
2247
2269
|
const parameterGroups = queryParamGroups || bodyParamGroups ? [...queryParamGroups ?? [], ...bodyParamGroups ?? []] : void 0;
|
|
2248
2270
|
return {
|
|
2249
2271
|
operation: {
|
|
@@ -2326,6 +2348,55 @@ function resolveParamSchemaRef(schema, componentSchemas) {
|
|
|
2326
2348
|
if (!match) return void 0;
|
|
2327
2349
|
return componentSchemas[match[1]];
|
|
2328
2350
|
}
|
|
2351
|
+
/**
|
|
2352
|
+
* Collect the property schemas of every `oneOf` branch reachable from a request
|
|
2353
|
+
* body schema, keyed by property name. These are the candidate members of a
|
|
2354
|
+
* mutually-exclusive body group.
|
|
2355
|
+
*
|
|
2356
|
+
* The bundler runs with `dereference: false`, so the body schema is very often
|
|
2357
|
+
* a bare `{ $ref: '#/components/schemas/XDto' }` and the `allOf`/`oneOf`
|
|
2358
|
+
* composition that actually declares the variant properties lives on the
|
|
2359
|
+
* component. Walking without resolving refs finds nothing, and every group
|
|
2360
|
+
* member then falls back to `string` — an SDK that compiles but types
|
|
2361
|
+
* object-valued members (e.g. a connection's `saml_options`) as plain strings.
|
|
2362
|
+
*
|
|
2363
|
+
* Composition keywords nest and may themselves be refs, so resolve and recurse
|
|
2364
|
+
* at each level. `seen` guards against a schema that (directly or transitively)
|
|
2365
|
+
* refs itself.
|
|
2366
|
+
*/
|
|
2367
|
+
function collectVariantFieldSchemas(schema, componentSchemas, owner = void 0, out = /* @__PURE__ */ new Map(), seen = /* @__PURE__ */ new Set()) {
|
|
2368
|
+
if (!schema) return out;
|
|
2369
|
+
const ref = schema.$ref;
|
|
2370
|
+
if (ref) {
|
|
2371
|
+
if (seen.has(ref)) return out;
|
|
2372
|
+
seen.add(ref);
|
|
2373
|
+
const match = /^#\/components\/schemas\/(.+)$/.exec(ref);
|
|
2374
|
+
return collectVariantFieldSchemas(match && componentSchemas ? componentSchemas[match[1]] : void 0, componentSchemas, match ? resolveSchemaName(match[1]) : owner, out, seen);
|
|
2375
|
+
}
|
|
2376
|
+
for (const variant of schema.oneOf ?? []) {
|
|
2377
|
+
const variantRef = variant.$ref;
|
|
2378
|
+
const refMatch = variantRef ? /^#\/components\/schemas\/(.+)$/.exec(variantRef) : null;
|
|
2379
|
+
const resolved = resolveSchemaRefObject(variant, componentSchemas) ?? variant;
|
|
2380
|
+
const variantOwner = refMatch ? resolveSchemaName(refMatch[1]) : owner;
|
|
2381
|
+
for (const [name, fieldSchema] of Object.entries(resolved.properties ?? {})) if (fieldSchema) out.set(name, {
|
|
2382
|
+
schema: fieldSchema,
|
|
2383
|
+
owner: variantOwner
|
|
2384
|
+
});
|
|
2385
|
+
collectVariantFieldSchemas(variant, componentSchemas, owner, out, seen);
|
|
2386
|
+
}
|
|
2387
|
+
for (const sub of schema.allOf ?? []) collectVariantFieldSchemas(sub, componentSchemas, owner, out, seen);
|
|
2388
|
+
for (const sub of schema.anyOf ?? []) collectVariantFieldSchemas(sub, componentSchemas, owner, out, seen);
|
|
2389
|
+
return out;
|
|
2390
|
+
}
|
|
2391
|
+
/** Resolve `{ $ref: '#/components/schemas/X' }` to its component, else undefined. */
|
|
2392
|
+
function resolveSchemaRefObject(schema, componentSchemas) {
|
|
2393
|
+
if (!schema || !componentSchemas) return void 0;
|
|
2394
|
+
const ref = schema.$ref;
|
|
2395
|
+
if (!ref) return void 0;
|
|
2396
|
+
const match = /^#\/components\/schemas\/(.+)$/.exec(ref);
|
|
2397
|
+
if (!match) return void 0;
|
|
2398
|
+
return componentSchemas[match[1]];
|
|
2399
|
+
}
|
|
2329
2400
|
function extractRequestBody(body, op, inlineModels) {
|
|
2330
2401
|
if (!body?.content) return {};
|
|
2331
2402
|
let encoding = "json";
|
|
@@ -2738,6 +2809,262 @@ function collectInlineEnumsFromOperations(services, enums) {
|
|
|
2738
2809
|
]) collectInlineEnumFromRef(param.type, enums, enumNames);
|
|
2739
2810
|
}
|
|
2740
2811
|
//#endregion
|
|
2812
|
+
//#region src/parser/parameter-group-names.ts
|
|
2813
|
+
/**
|
|
2814
|
+
* Assign `ParameterGroup.wrapperName` across the whole spec.
|
|
2815
|
+
*
|
|
2816
|
+
* Emitters derive a group's generated wrapper type name from the group name
|
|
2817
|
+
* alone, so two operations sharing a group name (create and update both
|
|
2818
|
+
* declare `protocol_options`) collapse onto a single type. That is only sound
|
|
2819
|
+
* while the two declarations carry the same members. Where they differ, one
|
|
2820
|
+
* operation ends up typed with the other's member — e.g. a connection update
|
|
2821
|
+
* forced to pass `CreateConnectionSAMLOptions`, which accepts three fields the
|
|
2822
|
+
* PATCH endpoint rejects.
|
|
2823
|
+
*
|
|
2824
|
+
* This pass fingerprints every group's members structurally and qualifies the
|
|
2825
|
+
* wrapper name with the operation name only for groups that genuinely diverge.
|
|
2826
|
+
* Groups whose declarations agree keep the bare group name, so wrapper types
|
|
2827
|
+
* already published in the SDKs are never renamed.
|
|
2828
|
+
*/
|
|
2829
|
+
function assignParameterGroupWrapperNames(spec) {
|
|
2830
|
+
const modelMap = new Map(spec.models.map((m) => [m.name, m]));
|
|
2831
|
+
const enumMap = new Map(spec.enums.map((e) => [e.name, e]));
|
|
2832
|
+
const fingerprints = /* @__PURE__ */ new Map();
|
|
2833
|
+
const occurrences = [];
|
|
2834
|
+
for (const service of spec.services) for (const op of service.operations) for (const group of op.parameterGroups ?? []) {
|
|
2835
|
+
const fp = fingerprintGroup(group, modelMap, enumMap);
|
|
2836
|
+
let seen = fingerprints.get(group.name);
|
|
2837
|
+
if (!seen) {
|
|
2838
|
+
seen = /* @__PURE__ */ new Set();
|
|
2839
|
+
fingerprints.set(group.name, seen);
|
|
2840
|
+
}
|
|
2841
|
+
seen.add(fp);
|
|
2842
|
+
occurrences.push({
|
|
2843
|
+
service,
|
|
2844
|
+
op,
|
|
2845
|
+
group,
|
|
2846
|
+
fingerprint: fp
|
|
2847
|
+
});
|
|
2848
|
+
}
|
|
2849
|
+
for (const { op, group } of occurrences) group.wrapperName = (fingerprints.get(group.name)?.size ?? 0) > 1 ? `${op.name}_${group.name}` : group.name;
|
|
2850
|
+
qualifyResidualCollisions(occurrences);
|
|
2851
|
+
reconcileSharedGroups(occurrences.map((o) => o.group));
|
|
2852
|
+
}
|
|
2853
|
+
/**
|
|
2854
|
+
* Break the collisions the operation-qualified name can still leave behind.
|
|
2855
|
+
*
|
|
2856
|
+
* `${op.name}_${group.name}` is not a unique key, for two separate reasons:
|
|
2857
|
+
*
|
|
2858
|
+
* - `disambiguateOperationNames` makes operation names unique only *within* a
|
|
2859
|
+
* service, so two services that each own an operation named `create`, both
|
|
2860
|
+
* declaring a `password` group with different members, both land on
|
|
2861
|
+
* `create_password`.
|
|
2862
|
+
* - Within one service it deliberately leaves same-name operations alone when
|
|
2863
|
+
* they share a path (see the `uniquePaths.size <= 1` guard — "same path,
|
|
2864
|
+
* different methods"), so `PUT` and `PATCH` on one path both stay `update`
|
|
2865
|
+
* and a service prefix alone still produces one name for both.
|
|
2866
|
+
*
|
|
2867
|
+
* Either way `reconcileSharedGroups` would then fuse two incompatible
|
|
2868
|
+
* declarations into a single type — the exact failure this pass exists to
|
|
2869
|
+
* prevent — and it does not drop the surplus member, so the wrapper would
|
|
2870
|
+
* expose a field one of the operations rejects.
|
|
2871
|
+
*
|
|
2872
|
+
* So escalate in rounds, adding a qualifier at a time and re-testing what still
|
|
2873
|
+
* collides. `(service, path, method)` identifies an operation uniquely, and a
|
|
2874
|
+
* same-name collision within a service implies a shared path, so service then
|
|
2875
|
+
* method is sufficient to separate every case.
|
|
2876
|
+
*
|
|
2877
|
+
* Each round only touches names that *still* group differing fingerprints, so a
|
|
2878
|
+
* name whose sharers agree is never renamed: sharing one wrapper is exactly what
|
|
2879
|
+
* should happen there, and renaming it would move a type the SDKs already
|
|
2880
|
+
* publish. On a spec where no qualified name collides — the WorkOS spec today —
|
|
2881
|
+
* the whole pass is a no-op.
|
|
2882
|
+
*/
|
|
2883
|
+
function qualifyResidualCollisions(occurrences) {
|
|
2884
|
+
const qualifiers = [(o) => o.service.name, (o) => o.op.httpMethod];
|
|
2885
|
+
for (const qualify of qualifiers) for (const sharers of collidingCandidates(occurrences)) {
|
|
2886
|
+
const movable = sharers.filter((o) => o.group.wrapperName !== o.group.name);
|
|
2887
|
+
for (const o of movable) o.group.wrapperName = `${qualify(o)}_${o.group.wrapperName ?? o.group.name}`;
|
|
2888
|
+
}
|
|
2889
|
+
separateRemainingByStructure(occurrences);
|
|
2890
|
+
}
|
|
2891
|
+
/**
|
|
2892
|
+
* Terminal round: separate whatever the operation attributes could not.
|
|
2893
|
+
*
|
|
2894
|
+
* No combination of operation attributes is unique by construction. Two
|
|
2895
|
+
* operations in one service can share a name, a method *and* differ only by
|
|
2896
|
+
* path — `normalizeOperationIdForNaming` strips the `[N]` suffix, so a NestJS
|
|
2897
|
+
* controller method bound to several routes derives one name for all of them.
|
|
2898
|
+
* The WorkOS spec already contains such a pair (`Authorization`'s
|
|
2899
|
+
* `listRoleAssignments` on two paths); it declares no parameter groups today,
|
|
2900
|
+
* so nothing is wrong in the SDKs, but the shape is present rather than
|
|
2901
|
+
* hypothetical. Adding `path` as a fourth qualifier would only move the
|
|
2902
|
+
* boundary again.
|
|
2903
|
+
*
|
|
2904
|
+
* So stop enumerating attributes and separate by the thing that actually
|
|
2905
|
+
* matters: a name still fusing distinct structures gets one wrapper per
|
|
2906
|
+
* distinct fingerprint. That makes "same `wrapperName` implies same structure"
|
|
2907
|
+
* hold unconditionally, which is the invariant every emitter relies on.
|
|
2908
|
+
*
|
|
2909
|
+
* Suffixes are keyed on the fingerprint, not on a per-occurrence counter, so
|
|
2910
|
+
* declarations that agree keep sharing a wrapper.
|
|
2911
|
+
*
|
|
2912
|
+
* Ordering is by first appearance, not by sorted fingerprint: the structure
|
|
2913
|
+
* declared first keeps the unsuffixed name. Sorting by fingerprint would be
|
|
2914
|
+
* equally deterministic but less stable in the way that matters — adding a
|
|
2915
|
+
* member to one operation changes its fingerprint and could swap which of two
|
|
2916
|
+
* published wrappers holds the bare name. Under first-appearance order only
|
|
2917
|
+
* reordering the operations themselves can shift a name, which is both rarer
|
|
2918
|
+
* and visible in the spec diff.
|
|
2919
|
+
*
|
|
2920
|
+
* Either way this is a no-op wherever an earlier round already sufficed —
|
|
2921
|
+
* including the WorkOS spec, which never reaches this round at all.
|
|
2922
|
+
*/
|
|
2923
|
+
function separateRemainingByStructure(occurrences) {
|
|
2924
|
+
const taken = new Set(occurrences.map((o) => o.group.wrapperName ?? o.group.name));
|
|
2925
|
+
for (const sharers of collidingCandidates(occurrences)) {
|
|
2926
|
+
const base = sharers[0].group.wrapperName ?? sharers[0].group.name;
|
|
2927
|
+
const nameFor = /* @__PURE__ */ new Map();
|
|
2928
|
+
let n = 2;
|
|
2929
|
+
for (const o of sharers) {
|
|
2930
|
+
if (nameFor.has(o.fingerprint)) continue;
|
|
2931
|
+
if (nameFor.size === 0) {
|
|
2932
|
+
nameFor.set(o.fingerprint, base);
|
|
2933
|
+
continue;
|
|
2934
|
+
}
|
|
2935
|
+
while (taken.has(`${base}_${n}`)) n++;
|
|
2936
|
+
const name = `${base}_${n}`;
|
|
2937
|
+
taken.add(name);
|
|
2938
|
+
nameFor.set(o.fingerprint, name);
|
|
2939
|
+
n++;
|
|
2940
|
+
}
|
|
2941
|
+
for (const o of sharers) o.group.wrapperName = nameFor.get(o.fingerprint);
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
/**
|
|
2945
|
+
* Candidate wrapper names shared by declarations that do not agree — the only
|
|
2946
|
+
* ones an escalation round may rename.
|
|
2947
|
+
*/
|
|
2948
|
+
function collidingCandidates(occurrences) {
|
|
2949
|
+
const byCandidate = /* @__PURE__ */ new Map();
|
|
2950
|
+
for (const o of occurrences) {
|
|
2951
|
+
const key = o.group.wrapperName ?? o.group.name;
|
|
2952
|
+
const list = byCandidate.get(key);
|
|
2953
|
+
if (list) list.push(o);
|
|
2954
|
+
else byCandidate.set(key, [o]);
|
|
2955
|
+
}
|
|
2956
|
+
return [...byCandidate.values()].filter((sharers) => sharers.length > 1 && new Set(sharers.map((o) => o.fingerprint)).size > 1);
|
|
2957
|
+
}
|
|
2958
|
+
/**
|
|
2959
|
+
* Make every group that shares a `wrapperName` describe literally the same
|
|
2960
|
+
* type.
|
|
2961
|
+
*
|
|
2962
|
+
* Deciding two declarations may share one wrapper is only half the job. The
|
|
2963
|
+
* fingerprint deliberately ignores nullability and member order, so sharers can
|
|
2964
|
+
* still disagree on both — and each emitter renders the wrapper from whichever
|
|
2965
|
+
* operation it happens to reach first while rendering call sites from their own
|
|
2966
|
+
* operation. Kotlin showed the consequence: `ParentResource.ById.id` emitted as
|
|
2967
|
+
* `String` from one operation, while the Java-friendly overload built from
|
|
2968
|
+
* another passed a `String?` into it, and the SDK stopped compiling.
|
|
2969
|
+
*
|
|
2970
|
+
* So normalize the two axes the fingerprint waived:
|
|
2971
|
+
* - a member the sharers disagree on settles as non-nullable. Widening to
|
|
2972
|
+
* nullable instead reads as the friendlier choice, but the nullable form
|
|
2973
|
+
* doesn't survive every emitter's group paths (Kotlin's query dispatch
|
|
2974
|
+
* builds a `Pair<String, String>` from the member, which a `String?` can't
|
|
2975
|
+
* satisfy), and non-nullable is what all sharers carried before group
|
|
2976
|
+
* member types were resolved at all — so it changes no published surface.
|
|
2977
|
+
* A member every sharer agrees is nullable stays nullable.
|
|
2978
|
+
*
|
|
2979
|
+
* The cost: an operation whose spec really does accept null for a member
|
|
2980
|
+
* (`PATCH` on a resource may clear `parent_resource_id`) can't express that
|
|
2981
|
+
* through the shared wrapper. It never could — the member used to be a flat
|
|
2982
|
+
* `string` everywhere — so nothing regresses, but the limitation is real and
|
|
2983
|
+
* removing it means letting that group's wrapper split per operation.
|
|
2984
|
+
* - member order follows the first sharer, so positional constructors and
|
|
2985
|
+
* their call sites agree.
|
|
2986
|
+
*/
|
|
2987
|
+
function reconcileSharedGroups(groups) {
|
|
2988
|
+
const byWrapper = /* @__PURE__ */ new Map();
|
|
2989
|
+
for (const group of groups) {
|
|
2990
|
+
const key = group.wrapperName ?? group.name;
|
|
2991
|
+
const list = byWrapper.get(key);
|
|
2992
|
+
if (list) list.push(group);
|
|
2993
|
+
else byWrapper.set(key, [group]);
|
|
2994
|
+
}
|
|
2995
|
+
for (const sharers of byWrapper.values()) {
|
|
2996
|
+
if (sharers.length < 2) continue;
|
|
2997
|
+
for (const variant of sharers[0].variants) {
|
|
2998
|
+
const peers = sharers.slice(1).map((g) => g.variants.find((v) => v.name === variant.name)).filter((v) => v !== void 0);
|
|
2999
|
+
if (peers.length === 0) continue;
|
|
3000
|
+
for (const member of variant.parameters) {
|
|
3001
|
+
const all = [member, ...peers.map((p) => p.parameters.find((q) => q.name === member.name)).filter(isParameter)];
|
|
3002
|
+
if (all.every((p) => p.type.kind === "nullable")) continue;
|
|
3003
|
+
for (const p of all) if (p.type.kind === "nullable") p.type = p.type.inner;
|
|
3004
|
+
}
|
|
3005
|
+
const canonical = variant.parameters.map((p) => p.name);
|
|
3006
|
+
for (const peer of peers) peer.parameters.sort((a, b) => {
|
|
3007
|
+
const ia = canonical.indexOf(a.name);
|
|
3008
|
+
const ib = canonical.indexOf(b.name);
|
|
3009
|
+
if (ia === -1 && ib === -1) return 0;
|
|
3010
|
+
if (ia === -1) return 1;
|
|
3011
|
+
if (ib === -1) return -1;
|
|
3012
|
+
return ia - ib;
|
|
3013
|
+
});
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
}
|
|
3017
|
+
function isParameter(p) {
|
|
3018
|
+
return p !== void 0;
|
|
3019
|
+
}
|
|
3020
|
+
/**
|
|
3021
|
+
* Structural fingerprint of a group: its variants, their members, and each
|
|
3022
|
+
* member's resolved shape. Two declarations with the same fingerprint can
|
|
3023
|
+
* safely share one generated wrapper type.
|
|
3024
|
+
*/
|
|
3025
|
+
function fingerprintGroup(group, modelMap, enumMap) {
|
|
3026
|
+
return group.variants.map((v) => {
|
|
3027
|
+
const members = [...v.parameters].sort((a, b) => a.name.localeCompare(b.name)).map((p) => `${p.name}:${fingerprintType(p.type, modelMap, enumMap, /* @__PURE__ */ new Set())}`);
|
|
3028
|
+
const optional = [...v.optionalParameters ?? []].sort();
|
|
3029
|
+
return `${v.name}(${members.join(",")})[${optional.join(",")}]`;
|
|
3030
|
+
}).join("|");
|
|
3031
|
+
}
|
|
3032
|
+
/**
|
|
3033
|
+
* Fingerprint a type by shape rather than by name.
|
|
3034
|
+
*
|
|
3035
|
+
* Names cannot be compared directly because the parser synthesizes a separate
|
|
3036
|
+
* name per declaration site for inline schemas: `create_user` and `update_user`
|
|
3037
|
+
* each get their own `PasswordHashType` enum, spelled `CreateUserPasswordHashType`
|
|
3038
|
+
* and `UpdateUserPasswordHashType`, though their values are identical. Comparing
|
|
3039
|
+
* names would report divergence and rename a wrapper for no reason.
|
|
3040
|
+
*
|
|
3041
|
+
* Nullability is also stripped: an update declaring a member nullable while
|
|
3042
|
+
* create declares it plain is not a reason to split the wrapper type.
|
|
3043
|
+
*/
|
|
3044
|
+
function fingerprintType(ref, modelMap, enumMap, visiting) {
|
|
3045
|
+
switch (ref.kind) {
|
|
3046
|
+
case "nullable": return fingerprintType(ref.inner, modelMap, enumMap, visiting);
|
|
3047
|
+
case "primitive": return `p:${ref.type}`;
|
|
3048
|
+
case "literal": return `l:${typeof ref.value}:${String(ref.value)}`;
|
|
3049
|
+
case "array": return `a<${fingerprintType(ref.items, modelMap, enumMap, visiting)}>`;
|
|
3050
|
+
case "map": return `m<${fingerprintType(ref.valueType, modelMap, enumMap, visiting)}>`;
|
|
3051
|
+
case "union": return `u<${ref.variants.map((v) => fingerprintType(v, modelMap, enumMap, visiting)).sort().join(",")}>`;
|
|
3052
|
+
case "enum": {
|
|
3053
|
+
const e = enumMap.get(ref.name);
|
|
3054
|
+
if (!e) return `e:${ref.name}`;
|
|
3055
|
+
return `e<${e.values.map((v) => `${typeof v.value}:${String(v.value)}`).sort().join(",")}>`;
|
|
3056
|
+
}
|
|
3057
|
+
case "model": {
|
|
3058
|
+
const m = modelMap.get(ref.name);
|
|
3059
|
+
if (!m) return `M:${ref.name}`;
|
|
3060
|
+
if (visiting.has(ref.name)) return `M:${ref.name}`;
|
|
3061
|
+
const next = new Set(visiting).add(ref.name);
|
|
3062
|
+
return `M<${[...m.fields].sort((a, b) => a.name.localeCompare(b.name)).map((f) => `${f.name}${f.required ? "!" : "?"}:${fingerprintType(f.type, modelMap, enumMap, next)}`).join(",")}>`;
|
|
3063
|
+
}
|
|
3064
|
+
default: return "unknown";
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
3067
|
+
//#endregion
|
|
2741
3068
|
//#region src/parser/normalize-model-refs.ts
|
|
2742
3069
|
function validateModelRefs(spec) {
|
|
2743
3070
|
const knownNames = /* @__PURE__ */ new Set();
|
|
@@ -2767,7 +3094,7 @@ async function parseSpec(specPath, options) {
|
|
|
2767
3094
|
const version = spec.openapi ?? "";
|
|
2768
3095
|
if (!version.startsWith("3.")) throw new SpecParseError(`Unsupported OpenAPI version: ${version}. oagen requires OpenAPI 3.x`, `Update the spec to OpenAPI 3.0 or 3.1. If you are using Swagger 2.x, convert it first with \`npx swagger2openapi ${specPath}\`.`);
|
|
2769
3096
|
const { models, enums } = extractSchemas(spec.components?.schemas, { schemaNameTransform: options?.schemaNameTransform });
|
|
2770
|
-
const { services, inlineModels } = extractOperations(spec.paths, options?.operationIdTransform, spec.components?.schemas);
|
|
3097
|
+
const { services, inlineModels } = extractOperations(spec.paths, options?.operationIdTransform, spec.components?.schemas, spec.components?.parameters);
|
|
2771
3098
|
const responseNormalizedModels = mergeInlineResponseModels(models, inlineModels);
|
|
2772
3099
|
const fieldInlineModels = extractInlineModelsFromSchemas(spec.components?.schemas);
|
|
2773
3100
|
clearSchemaNameTransform();
|
|
@@ -2792,6 +3119,7 @@ async function parseSpec(specPath, options) {
|
|
|
2792
3119
|
auth,
|
|
2793
3120
|
sdk: defaultSdkBehavior()
|
|
2794
3121
|
};
|
|
3122
|
+
assignParameterGroupWrapperNames(result);
|
|
2795
3123
|
validateModelRefs(result);
|
|
2796
3124
|
return result;
|
|
2797
3125
|
}
|