@kubb/adapter-oas 5.0.0-beta.74 → 5.0.0-beta.76

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/index.cjs CHANGED
@@ -155,6 +155,17 @@ const formatMap = {
155
155
  * ```
156
156
  */
157
157
  const enumExtensionKeys = ["x-enumNames", "x-enum-varnames"];
158
+ /**
159
+ * Vendor extension keys that attach human-readable descriptions to enum values, checked in priority order.
160
+ *
161
+ * @example
162
+ * ```ts
163
+ * import { enumDescriptionKeys } from '@kubb/adapter-oas'
164
+ *
165
+ * const key = enumDescriptionKeys.find((k) => k in schema) // 'x-enumDescriptions' | 'x-enum-descriptions' | undefined
166
+ * ```
167
+ */
168
+ const enumDescriptionKeys = ["x-enumDescriptions", "x-enum-descriptions"];
158
169
  //#endregion
159
170
  //#region ../../internals/utils/src/casing.ts
160
171
  /**
@@ -171,18 +182,6 @@ function toCamelOrPascal(text, pascal) {
171
182
  }).join("").replace(/[^a-zA-Z0-9]/g, "");
172
183
  }
173
184
  /**
174
- * Converts `text` to camelCase.
175
- *
176
- * @example Word boundaries
177
- * `camelCase('hello-world') // 'helloWorld'`
178
- *
179
- * @example With a prefix
180
- * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
181
- */
182
- function camelCase(text, { prefix = "", suffix = "" } = {}) {
183
- return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
184
- }
185
- /**
186
185
  * Converts `text` to PascalCase.
187
186
  *
188
187
  * @example Word boundaries
@@ -295,209 +294,6 @@ async function read(path) {
295
294
  return (0, node_fs_promises.readFile)(path, { encoding: "utf8" });
296
295
  }
297
296
  //#endregion
298
- //#region ../../internals/utils/src/reserved.ts
299
- /**
300
- * JavaScript and Java reserved words.
301
- * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
302
- */
303
- const reservedWords = new Set([
304
- "abstract",
305
- "arguments",
306
- "boolean",
307
- "break",
308
- "byte",
309
- "case",
310
- "catch",
311
- "char",
312
- "class",
313
- "const",
314
- "continue",
315
- "debugger",
316
- "default",
317
- "delete",
318
- "do",
319
- "double",
320
- "else",
321
- "enum",
322
- "eval",
323
- "export",
324
- "extends",
325
- "false",
326
- "final",
327
- "finally",
328
- "float",
329
- "for",
330
- "function",
331
- "goto",
332
- "if",
333
- "implements",
334
- "import",
335
- "in",
336
- "instanceof",
337
- "int",
338
- "interface",
339
- "let",
340
- "long",
341
- "native",
342
- "new",
343
- "null",
344
- "package",
345
- "private",
346
- "protected",
347
- "public",
348
- "return",
349
- "short",
350
- "static",
351
- "super",
352
- "switch",
353
- "synchronized",
354
- "this",
355
- "throw",
356
- "throws",
357
- "transient",
358
- "true",
359
- "try",
360
- "typeof",
361
- "var",
362
- "void",
363
- "volatile",
364
- "while",
365
- "with",
366
- "yield",
367
- "Array",
368
- "Date",
369
- "hasOwnProperty",
370
- "Infinity",
371
- "isFinite",
372
- "isNaN",
373
- "isPrototypeOf",
374
- "length",
375
- "Math",
376
- "name",
377
- "NaN",
378
- "Number",
379
- "Object",
380
- "prototype",
381
- "String",
382
- "toString",
383
- "undefined",
384
- "valueOf"
385
- ]);
386
- /**
387
- * Returns `true` when `name` is a syntactically valid JavaScript variable name.
388
- *
389
- * @example
390
- * ```ts
391
- * isValidVarName('status') // true
392
- * isValidVarName('class') // false (reserved word)
393
- * isValidVarName('42foo') // false (starts with digit)
394
- * ```
395
- */
396
- function isValidVarName(name) {
397
- if (!name || reservedWords.has(name)) return false;
398
- return isIdentifier(name);
399
- }
400
- /**
401
- * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
402
- *
403
- * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
404
- * even though they are not valid variable names, so use this (not {@link isValidVarName}) when
405
- * deciding whether an object key needs quoting.
406
- *
407
- * @example
408
- * ```ts
409
- * isIdentifier('name') // true
410
- * isIdentifier('x-total')// false
411
- * ```
412
- */
413
- function isIdentifier(name) {
414
- return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
415
- }
416
- //#endregion
417
- //#region ../../internals/utils/src/url.ts
418
- function transformParam(raw, casing) {
419
- const param = isValidVarName(raw) ? raw : camelCase(raw);
420
- return casing === "camelcase" ? camelCase(param) : param;
421
- }
422
- function toParamsObject(path, { replacer, casing } = {}) {
423
- const params = {};
424
- for (const match of path.matchAll(/\{([^}]+)\}/g)) {
425
- const param = transformParam(match[1], casing);
426
- const key = replacer ? replacer(param) : param;
427
- params[key] = key;
428
- }
429
- return Object.keys(params).length > 0 ? params : null;
430
- }
431
- /**
432
- * Helpers for OpenAPI/Swagger paths, plus a thin wrapper over the native `URL`.
433
- */
434
- var Url = class Url {
435
- /**
436
- * Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.
437
- *
438
- * @example
439
- * Url.canParse('https://petstore.swagger.io/v2') // true
440
- * Url.canParse('/pet/{petId}') // false
441
- */
442
- static canParse(url, base) {
443
- return URL.canParse(url, base);
444
- }
445
- /**
446
- * Converts an OpenAPI/Swagger path to Express-style colon syntax.
447
- *
448
- * @example
449
- * Url.toPath('/pet/{petId}') // '/pet/:petId'
450
- */
451
- static toPath(path) {
452
- return path.replace(/\{([^}]+)\}/g, ":$1");
453
- }
454
- /**
455
- * Converts an OpenAPI/Swagger path to a TypeScript template literal string.
456
- * `prefix` is prepended inside the literal, `replacer` transforms each parameter name,
457
- * and `casing` controls parameter identifier casing.
458
- *
459
- * @example
460
- * Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
461
- *
462
- * @example
463
- * Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
464
- */
465
- static toTemplateString(path, { prefix, replacer, casing } = {}) {
466
- const result = path.split(/\{([^}]+)\}/).map((part, i) => {
467
- if (i % 2 === 0) return part;
468
- const param = transformParam(part, casing);
469
- return `\${${replacer ? replacer(param) : param}}`;
470
- }).join("");
471
- return `\`${prefix ?? ""}${result}\``;
472
- }
473
- /**
474
- * Returns the path and its extracted params as a structured `URLObject`, or as a stringified
475
- * expression when `stringify` is set.
476
- *
477
- * @example
478
- * Url.toObject('/pet/{petId}')
479
- * // { url: '/pet/:petId', params: { petId: 'petId' } }
480
- */
481
- static toObject(path, { type = "path", replacer, stringify, casing } = {}) {
482
- const object = {
483
- url: type === "path" ? Url.toPath(path) : Url.toTemplateString(path, {
484
- replacer,
485
- casing
486
- }),
487
- params: toParamsObject(path, {
488
- replacer,
489
- casing
490
- })
491
- };
492
- if (stringify) {
493
- if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
494
- if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`;
495
- return `{ url: '${object.url}' }`;
496
- }
497
- return object;
498
- }
499
- };
500
- //#endregion
501
297
  //#region src/bundler.ts
502
298
  const urlRegExp = /^https?:\/+/i;
503
299
  async function readSource(sourcePath) {
@@ -575,7 +371,7 @@ async function parseDocument(pathOrApi) {
575
371
  */
576
372
  async function parseFromConfig(source) {
577
373
  if (source.type === "data") return parseDocument(typeof source.data === "string" ? (0, yaml.parse)(source.data) : structuredClone(source.data));
578
- if (Url.canParse(source.path)) return parseDocument(source.path);
374
+ if (URL.canParse(source.path)) return parseDocument(source.path);
579
375
  const resolved = node_path.default.resolve(node_path.default.dirname(source.path), source.path);
580
376
  await assertInputExists(resolved);
581
377
  return parseDocument(resolved);
@@ -586,7 +382,7 @@ async function parseFromConfig(source) {
586
382
  * its parse error instead.
587
383
  */
588
384
  async function assertInputExists(input) {
589
- if (Url.canParse(input)) return;
385
+ if (URL.canParse(input)) return;
590
386
  if (!await exists(input)) throw new _kubb_core.Diagnostics.Error({
591
387
  code: _kubb_core.Diagnostics.code.inputNotFound,
592
388
  severity: "error",
@@ -1488,7 +1284,7 @@ function normalizeArrayEnum(schema) {
1488
1284
  * Builds a `null` scalar node carrying the schema's documentation. Shared by the `const: null`
1489
1285
  * and the drf-spectacular `NullEnum` (`{ enum: [null] }`) branches, which render identically.
1490
1286
  */
1491
- function createNullSchema(schema, name) {
1287
+ function createNullSchema(schema, name, nullable) {
1492
1288
  return _kubb_core.ast.factory.createSchema({
1493
1289
  type: "null",
1494
1290
  primitive: "null",
@@ -1496,6 +1292,7 @@ function createNullSchema(schema, name) {
1496
1292
  title: schema.title,
1497
1293
  description: schema.description,
1498
1294
  deprecated: schema.deprecated,
1295
+ nullable,
1499
1296
  format: schema.format
1500
1297
  });
1501
1298
  }
@@ -1674,6 +1471,34 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1674
1471
  properties: [discriminatorProperty]
1675
1472
  });
1676
1473
  }
1474
+ function resolveRefSilent($ref) {
1475
+ if (!$ref.startsWith("#")) return null;
1476
+ return decodeURIComponent($ref.substring(1)).split("/").filter(Boolean).reduce((obj, key) => obj?.[key], document) ?? null;
1477
+ }
1478
+ function implicitDiscriminantValue(member) {
1479
+ if (!discriminator || discriminator.mapping || !dialect.schema.isReference(member)) return null;
1480
+ const value = (0, _kubb_ast_utils.extractRefName)(member.$ref);
1481
+ if (!value) return null;
1482
+ const variant = resolveRefSilent(member.$ref);
1483
+ if (!variant) return null;
1484
+ const propertyName = discriminator.propertyName;
1485
+ const seen = new Set([member.$ref]);
1486
+ function constrains(v) {
1487
+ const prop = v.properties?.[propertyName];
1488
+ const resolved = prop && dialect.schema.isReference(prop) ? resolveRefSilent(prop.$ref) : prop;
1489
+ if (resolved && (Array.isArray(resolved.enum) || resolved.const !== void 0)) return true;
1490
+ const composition = v.allOf ?? v.oneOf ?? v.anyOf;
1491
+ if (!composition) return false;
1492
+ return composition.some((m) => {
1493
+ if (!dialect.schema.isReference(m)) return constrains(m);
1494
+ if (seen.has(m.$ref)) return false;
1495
+ seen.add(m.$ref);
1496
+ const r = resolveRefSilent(m.$ref);
1497
+ return r ? constrains(r) : false;
1498
+ });
1499
+ }
1500
+ return constrains(variant) ? null : value;
1501
+ }
1677
1502
  const unionMembers = [...schema.oneOf ?? [], ...schema.anyOf ?? []];
1678
1503
  const strategy = schema.oneOf ? "one" : "any";
1679
1504
  const unionBase = {
@@ -1682,17 +1507,15 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1682
1507
  strategy
1683
1508
  };
1684
1509
  const discriminator = dialect.schema.isDiscriminator(schema) ? schema.discriminator : void 0;
1685
- const sharedPropertiesNode = schema.properties ? (() => {
1686
- const { oneOf: _oneOf, anyOf: _anyOf, ...schemaWithoutUnion } = schema;
1687
- return parseSchema({
1688
- schema: discriminator ? Object.fromEntries(Object.entries(schemaWithoutUnion).filter(([key]) => key !== "discriminator")) : schemaWithoutUnion,
1689
- name
1690
- }, rawOptions);
1691
- })() : void 0;
1692
- if (sharedPropertiesNode || discriminator?.mapping) {
1510
+ const { oneOf: _o, anyOf: _a, discriminator: _d, ...memberBaseSchema } = schema;
1511
+ const sharedPropertiesNode = schema.properties ? parseSchema({
1512
+ schema: memberBaseSchema,
1513
+ name
1514
+ }, rawOptions) : void 0;
1515
+ if (sharedPropertiesNode || discriminator) {
1693
1516
  const members = unionMembers.map((s) => {
1694
1517
  const ref = dialect.schema.isReference(s) ? s.$ref : void 0;
1695
- const discriminatorValue = findDiscriminator(discriminator?.mapping, ref);
1518
+ const discriminatorValue = findDiscriminator(discriminator?.mapping, ref) ?? implicitDiscriminantValue(s);
1696
1519
  const memberNode = parseSchema({
1697
1520
  schema: s,
1698
1521
  name
@@ -1845,9 +1668,11 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1845
1668
  format: schema.format
1846
1669
  };
1847
1670
  const extensionKey = enumExtensionKeys.find((key) => key in schema);
1848
- if (extensionKey || enumPrimitive === "number" || enumPrimitive === "integer" || enumPrimitive === "boolean") {
1671
+ const descriptionKey = enumDescriptionKeys.find((key) => key in schema);
1672
+ if (extensionKey || descriptionKey || enumPrimitive === "number" || enumPrimitive === "integer" || enumPrimitive === "boolean") {
1849
1673
  const enumPrimitiveType = enumPrimitive === "number" || enumPrimitive === "integer" ? "number" : enumPrimitive === "boolean" ? "boolean" : "string";
1850
1674
  const rawEnumNames = extensionKey ? schema[extensionKey] : void 0;
1675
+ const rawEnumDescriptions = descriptionKey ? schema[descriptionKey] : void 0;
1851
1676
  const uniqueValues = [...new Set(filteredValues)];
1852
1677
  const seenNames = /* @__PURE__ */ new Set();
1853
1678
  return _kubb_core.ast.factory.createSchema({
@@ -1856,7 +1681,8 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1856
1681
  namedEnumValues: uniqueValues.map((value, index) => ({
1857
1682
  name: String(rawEnumNames?.[index] ?? value),
1858
1683
  value,
1859
- primitive: enumPrimitiveType
1684
+ primitive: enumPrimitiveType,
1685
+ description: rawEnumDescriptions?.[index]
1860
1686
  })).filter((entry) => {
1861
1687
  if (seenNames.has(entry.name)) return false;
1862
1688
  seenNames.add(entry.name);
@@ -1926,22 +1752,11 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1926
1752
  return objectNode;
1927
1753
  }
1928
1754
  /**
1929
- * Resolves a tuple's rest-element schema from the `items` keyword that sits alongside `prefixItems`.
1930
- *
1931
- * `items: false` closes the tuple, so no rest element is emitted. An absent `items` widens the tail
1932
- * to `any`, and a schema object (or `items: true`) becomes the homogeneous rest type.
1933
- */
1934
- function resolveTupleRest(items, rawOptions) {
1935
- if (items === false) return void 0;
1936
- if (!items || items === true) return _kubb_core.ast.factory.createSchema({ type: "any" });
1937
- return parseSchema({ schema: items }, rawOptions);
1938
- }
1939
- /**
1940
1755
  * Converts an OAS 3.1 `prefixItems` tuple into a `TupleSchemaNode`.
1941
1756
  */
1942
1757
  function convertTuple({ schema, name, nullable, defaultValue, rawOptions }) {
1943
1758
  const tupleItems = (schema.prefixItems ?? []).map((item) => parseSchema({ schema: item }, rawOptions));
1944
- const rest = resolveTupleRest(schema.items, rawOptions);
1759
+ const rest = schema.items === false ? void 0 : !schema.items || schema.items === true ? _kubb_core.ast.factory.createSchema({ type: "any" }) : parseSchema({ schema: schema.items }, rawOptions);
1945
1760
  return _kubb_core.ast.factory.createSchema({
1946
1761
  type: "tuple",
1947
1762
  primitive: "array",
@@ -2011,21 +1826,6 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2011
1826
  });
2012
1827
  }
2013
1828
  /**
2014
- * Converts an explicit `type: 'null'` schema.
2015
- */
2016
- function convertNull({ schema, name, nullable }) {
2017
- return _kubb_core.ast.factory.createSchema({
2018
- type: "null",
2019
- primitive: "null",
2020
- name,
2021
- title: schema.title,
2022
- description: schema.description,
2023
- deprecated: schema.deprecated,
2024
- nullable,
2025
- format: schema.format
2026
- });
2027
- }
2028
- /**
2029
1829
  * Converts a binary string schema (`type: 'string'`, `contentMediaType: 'application/octet-stream'`)
2030
1830
  * into a `blob` node.
2031
1831
  */
@@ -2067,94 +1867,76 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2067
1867
  */
2068
1868
  const schemaRules = [
2069
1869
  {
2070
- name: "ref",
2071
1870
  match: ({ schema }) => dialect.schema.isReference(schema),
2072
1871
  convert: convertRef
2073
1872
  },
2074
1873
  {
2075
- name: "allOf",
2076
1874
  match: ({ schema }) => !!schema.allOf?.length,
2077
1875
  convert: convertAllOf
2078
1876
  },
2079
1877
  {
2080
- name: "union",
2081
1878
  match: ({ schema }) => !!(schema.oneOf?.length || schema.anyOf?.length),
2082
1879
  convert: convertUnion
2083
1880
  },
2084
1881
  {
2085
- name: "const",
2086
1882
  match: ({ schema }) => "const" in schema && schema.const !== void 0,
2087
1883
  convert: convertConst
2088
1884
  },
2089
1885
  {
2090
- name: "format",
2091
1886
  match: ({ schema }) => !!schema.format,
2092
1887
  convert: convertFormat
2093
1888
  },
2094
1889
  {
2095
- name: "blob",
2096
1890
  match: ({ schema }) => dialect.schema.isBinary(schema),
2097
1891
  convert: convertBlob
2098
1892
  },
2099
1893
  {
2100
- name: "multi-type",
2101
1894
  match: ({ schema }) => Array.isArray(schema.type) && schema.type.length > 1,
2102
1895
  convert: convertMultiType
2103
1896
  },
2104
1897
  {
2105
- name: "constrained-string",
2106
1898
  match: ({ schema, type }) => !type && (schema.minLength !== void 0 || schema.maxLength !== void 0 || schema.pattern !== void 0),
2107
1899
  convert: convertString
2108
1900
  },
2109
1901
  {
2110
- name: "constrained-number",
2111
1902
  match: ({ schema, type }) => !type && (schema.minimum !== void 0 || schema.maximum !== void 0),
2112
1903
  convert: (ctx) => convertNumeric(ctx, "number")
2113
1904
  },
2114
1905
  {
2115
- name: "enum",
2116
1906
  match: ({ schema }) => !!schema.enum?.length,
2117
1907
  convert: convertEnum
2118
1908
  },
2119
1909
  {
2120
- name: "object",
2121
1910
  match: ({ schema, type }) => type === "object" || !!schema.properties || !!schema.additionalProperties || "patternProperties" in schema,
2122
1911
  convert: convertObject
2123
1912
  },
2124
1913
  {
2125
- name: "tuple",
2126
1914
  match: ({ schema }) => "prefixItems" in schema,
2127
1915
  convert: convertTuple
2128
1916
  },
2129
1917
  {
2130
- name: "array",
2131
1918
  match: ({ schema, type }) => type === "array" || "items" in schema,
2132
1919
  convert: convertArray
2133
1920
  },
2134
1921
  {
2135
- name: "string",
2136
1922
  match: ({ type }) => type === "string",
2137
1923
  convert: convertString
2138
1924
  },
2139
1925
  {
2140
- name: "number",
2141
1926
  match: ({ type }) => type === "number",
2142
1927
  convert: (ctx) => convertNumeric(ctx, "number")
2143
1928
  },
2144
1929
  {
2145
- name: "integer",
2146
1930
  match: ({ type }) => type === "integer",
2147
1931
  convert: (ctx) => convertNumeric(ctx, "integer")
2148
1932
  },
2149
1933
  {
2150
- name: "boolean",
2151
1934
  match: ({ type }) => type === "boolean",
2152
1935
  convert: convertBoolean
2153
1936
  },
2154
1937
  {
2155
- name: "null",
2156
1938
  match: ({ type }) => type === "null",
2157
- convert: convertNull
1939
+ convert: ({ schema, name, nullable }) => createNullSchema(schema, name, nullable)
2158
1940
  }
2159
1941
  ];
2160
1942
  /**
@@ -2209,6 +1991,8 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2209
1991
  schema: param["schema"],
2210
1992
  name: schemaName
2211
1993
  }, options) : _kubb_core.ast.factory.createSchema({ type: options.unknownType });
1994
+ const style = param["style"];
1995
+ const explode = param["explode"];
2212
1996
  return _kubb_core.ast.factory.createParameter({
2213
1997
  name: paramName,
2214
1998
  in: param["in"],
@@ -2216,7 +2000,9 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2216
2000
  ...schema,
2217
2001
  description: param["description"] ?? schema.description
2218
2002
  },
2219
- required
2003
+ required,
2004
+ ...style !== void 0 ? { style } : {},
2005
+ ...explode !== void 0 ? { explode } : {}
2220
2006
  });
2221
2007
  }
2222
2008
  /**
@@ -2232,17 +2018,6 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2232
2018
  };
2233
2019
  }
2234
2020
  /**
2235
- * Reads the inline response object (not a `$ref`) and returns its description plus its `content` map.
2236
- */
2237
- function getResponseMeta(responseObj) {
2238
- if (typeof responseObj !== "object" || responseObj === null || Array.isArray(responseObj)) return {};
2239
- const inline = responseObj;
2240
- return {
2241
- description: inline.description,
2242
- content: inline.content
2243
- };
2244
- }
2245
- /**
2246
2021
  * Collects property names whose schema has a truthy boolean flag (`readOnly` or `writeOnly`).
2247
2022
  * `$ref` entries are skipped since their flags live on the dereferenced target.
2248
2023
  */
@@ -2289,7 +2064,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2289
2064
  statusCode
2290
2065
  });
2291
2066
  const responseName = operationName ? `${operationName}Status${statusCode}` : void 0;
2292
- const { description } = getResponseMeta(responseObj);
2067
+ const description = typeof responseObj === "object" && responseObj !== null ? responseObj.description : void 0;
2293
2068
  const parseEntrySchema = (contentType) => {
2294
2069
  const raw = getResponseSchema(document, operation, statusCode, { contentType });
2295
2070
  return {
@@ -2358,6 +2133,7 @@ function collectInlineEnums(roots, topLevelNames) {
2358
2133
  const isSchemaRoot = root.kind === "Schema";
2359
2134
  for (const node of _kubb_core.ast.collect(root, { schema: (schemaNode) => schemaNode })) {
2360
2135
  if (node.type !== "enum" || !node.name) continue;
2136
+ if ((node.namedEnumValues ?? node.enumValues ?? []).length === 1) continue;
2361
2137
  if (isSchemaRoot && node === root) continue;
2362
2138
  if (topLevelNames.has(node.name)) continue;
2363
2139
  if (!promoted.has(node.name)) promoted.set(node.name, {
@@ -2507,7 +2283,9 @@ function preScan({ schemas, parseSchema, parseOperation, document, parserOptions
2507
2283
  name
2508
2284
  });
2509
2285
  if (node.type === "ref" && node.name && node.name !== name) refAliasMap.set(name, node);
2510
- if (_kubb_core.ast.narrowSchema(node, _kubb_core.ast.schemaTypes.enum) && node.name) enumNames.push(node.name);
2286
+ const enumNode = _kubb_core.ast.narrowSchema(node, _kubb_core.ast.schemaTypes.enum);
2287
+ const isConstEnum = (enumNode?.namedEnumValues ?? enumNode?.enumValues ?? []).length === 1;
2288
+ if (enumNode && node.name && !isConstEnum) enumNames.push(node.name);
2511
2289
  if (discriminator === "propagate" && (schema.oneOf ?? schema.anyOf) && schema.discriminator?.propertyName) discriminatorParentNodes.push(node);
2512
2290
  }
2513
2291
  const circularNames = [...(0, _kubb_ast_utils.findCircularSchemas)(allNodes)];