@kubb/adapter-oas 5.0.0-beta.61 → 5.0.0-beta.62

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
@@ -837,6 +837,23 @@ function dereferenceWithRef(document, schema) {
837
837
  //#endregion
838
838
  //#region src/dialect.ts
839
839
  /**
840
+ * Derives a schema's `optional`/`nullish` flags from a parent's `required` value and the
841
+ * schema's own `nullable`. How "required" and "nullable" combine is OpenAPI-specific, so it
842
+ * lives in the dialect.
843
+ *
844
+ * - Non-required + non-nullable → `optional: true`.
845
+ * - Non-required + nullable → `nullish: true`.
846
+ * - Required → both flags cleared.
847
+ */
848
+ function optionality(schema, required) {
849
+ const nullable = schema.nullable ?? false;
850
+ return {
851
+ ...schema,
852
+ optional: !required && !nullable ? true : void 0,
853
+ nullish: !required && nullable ? true : void 0
854
+ };
855
+ }
856
+ /**
840
857
  * The OpenAPI / Swagger dialect, the default used by `@kubb/adapter-oas`.
841
858
  *
842
859
  * Implements the spec-agnostic {@link ast.SchemaDialect} contract: it isolates the
@@ -855,13 +872,16 @@ function dereferenceWithRef(document, schema) {
855
872
  * const parser = createSchemaParser(context, oasDialect) // explicit
856
873
  * ```
857
874
  */
858
- const oasDialect = _kubb_core.ast.defineSchemaDialect({
875
+ const oasDialect = _kubb_core.ast.defineDialect({
859
876
  name: "oas",
860
- isNullable,
861
- isReference,
862
- isDiscriminator,
863
- isBinary: (schema) => schema.type === "string" && schema.contentMediaType === "application/octet-stream",
864
- resolveRef
877
+ schema: {
878
+ isNullable,
879
+ isReference,
880
+ isDiscriminator,
881
+ isBinary: (schema) => schema.type === "string" && schema.contentMediaType === "application/octet-stream",
882
+ resolveRef,
883
+ optionality
884
+ }
865
885
  });
866
886
  //#endregion
867
887
  //#region src/discriminator.ts
@@ -1584,6 +1604,21 @@ function normalizeArrayEnum(schema) {
1584
1604
  };
1585
1605
  }
1586
1606
  /**
1607
+ * Builds a `null` scalar node carrying the schema's documentation. Shared by the `const: null`
1608
+ * and the drf-spectacular `NullEnum` (`{ enum: [null] }`) branches, which render identically.
1609
+ */
1610
+ function createNullSchema(schema, name) {
1611
+ return _kubb_core.ast.factory.createSchema({
1612
+ type: "null",
1613
+ primitive: "null",
1614
+ name,
1615
+ title: schema.title,
1616
+ description: schema.description,
1617
+ deprecated: schema.deprecated,
1618
+ format: schema.format
1619
+ });
1620
+ }
1621
+ /**
1587
1622
  * Names the inline enums on a property's schema, and on each item when the property is a tuple, from
1588
1623
  * the parent and property name. Wraps `macroEnumName` at the property construction site.
1589
1624
  */
@@ -1639,7 +1674,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1639
1674
  if (refPath && !resolvingRefs.has(refPath)) {
1640
1675
  if (!resolvedRefCache.has(refPath)) {
1641
1676
  try {
1642
- const referenced = dialect.resolveRef(document, refPath);
1677
+ const referenced = dialect.schema.resolveRef(document, refPath);
1643
1678
  if (referenced) {
1644
1679
  resolvingRefs.add(refPath);
1645
1680
  resolvedSchema = parseSchema({ schema: referenced }, rawOptions);
@@ -1688,13 +1723,13 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1688
1723
  }
1689
1724
  const filteredDiscriminantValues = [];
1690
1725
  const allOfMembers = schema.allOf.filter((item) => {
1691
- if (!dialect.isReference(item) || !name) return true;
1692
- const deref = dialect.resolveRef(document, item.$ref);
1693
- if (!deref || !dialect.isDiscriminator(deref)) return true;
1726
+ if (!dialect.schema.isReference(item) || !name) return true;
1727
+ const deref = dialect.schema.resolveRef(document, item.$ref);
1728
+ if (!deref || !dialect.schema.isDiscriminator(deref)) return true;
1694
1729
  const parentUnion = deref.oneOf ?? deref.anyOf;
1695
1730
  if (!parentUnion) return true;
1696
1731
  const childRef = `${SCHEMA_REF_PREFIX}${name}`;
1697
- const inOneOf = parentUnion.some((oneOfItem) => dialect.isReference(oneOfItem) && oneOfItem.$ref === childRef);
1732
+ const inOneOf = parentUnion.some((oneOfItem) => dialect.schema.isReference(oneOfItem) && oneOfItem.$ref === childRef);
1698
1733
  const inMapping = Object.values(deref.discriminator.mapping ?? {}).some((v) => v === childRef);
1699
1734
  if (inOneOf || inMapping) {
1700
1735
  const discriminatorValue = findDiscriminator(deref.discriminator.mapping, childRef);
@@ -1715,9 +1750,9 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1715
1750
  const missingRequired = schema.required.filter((key) => !outerKeys.has(key));
1716
1751
  if (missingRequired.length) {
1717
1752
  const resolvedMembers = schema.allOf.flatMap((item) => {
1718
- if (!dialect.isReference(item)) return [item];
1719
- const deref = dialect.resolveRef(document, item.$ref);
1720
- return deref && !dialect.isReference(deref) ? [deref] : [];
1753
+ if (!dialect.schema.isReference(item)) return [item];
1754
+ const deref = dialect.schema.resolveRef(document, item.$ref);
1755
+ return deref && !dialect.schema.isReference(deref) ? [deref] : [];
1721
1756
  });
1722
1757
  for (const key of missingRequired) for (const resolved of resolvedMembers) if (resolved.properties?.[key]) {
1723
1758
  allOfMembers.push(parseSchema({
@@ -1762,10 +1797,10 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1762
1797
  const strategy = schema.oneOf ? "one" : "any";
1763
1798
  const unionBase = {
1764
1799
  ...buildSchemaNode(schema, name, nullable, defaultValue),
1765
- discriminatorPropertyName: dialect.isDiscriminator(schema) ? schema.discriminator.propertyName : void 0,
1800
+ discriminatorPropertyName: dialect.schema.isDiscriminator(schema) ? schema.discriminator.propertyName : void 0,
1766
1801
  strategy
1767
1802
  };
1768
- const discriminator = dialect.isDiscriminator(schema) ? schema.discriminator : void 0;
1803
+ const discriminator = dialect.schema.isDiscriminator(schema) ? schema.discriminator : void 0;
1769
1804
  const sharedPropertiesNode = schema.properties ? (() => {
1770
1805
  const { oneOf: _oneOf, anyOf: _anyOf, ...schemaWithoutUnion } = schema;
1771
1806
  return parseSchema({
@@ -1775,7 +1810,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1775
1810
  })() : void 0;
1776
1811
  if (sharedPropertiesNode || discriminator?.mapping) {
1777
1812
  const members = unionMembers.map((s) => {
1778
- const ref = dialect.isReference(s) ? s.$ref : void 0;
1813
+ const ref = dialect.schema.isReference(s) ? s.$ref : void 0;
1779
1814
  const discriminatorValue = findDiscriminator(discriminator?.mapping, ref);
1780
1815
  const memberNode = parseSchema({
1781
1816
  schema: s,
@@ -1821,15 +1856,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1821
1856
  */
1822
1857
  function convertConst({ schema, name, nullable, defaultValue }) {
1823
1858
  const constValue = schema.const;
1824
- if (constValue === null) return _kubb_core.ast.factory.createSchema({
1825
- type: "null",
1826
- primitive: "null",
1827
- name,
1828
- title: schema.title,
1829
- description: schema.description,
1830
- deprecated: schema.deprecated,
1831
- format: schema.format
1832
- });
1859
+ if (constValue === null) return createNullSchema(schema, name);
1833
1860
  const constPrimitive = getPrimitiveType(typeof constValue === "number" ? "number" : typeof constValue === "boolean" ? "boolean" : "string");
1834
1861
  return _kubb_core.ast.factory.createSchema({
1835
1862
  type: "enum",
@@ -1918,15 +1945,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1918
1945
  }, rawOptions);
1919
1946
  const nullInEnum = schema.enum.includes(null);
1920
1947
  const filteredValues = nullInEnum ? schema.enum.filter((v) => v !== null) : schema.enum;
1921
- if (nullInEnum && filteredValues.length === 0) return _kubb_core.ast.factory.createSchema({
1922
- type: "null",
1923
- primitive: "null",
1924
- name,
1925
- title: schema.title,
1926
- description: schema.description,
1927
- deprecated: schema.deprecated,
1928
- format: schema.format
1929
- });
1948
+ if (nullInEnum && filteredValues.length === 0) return createNullSchema(schema, name);
1930
1949
  const enumNullable = nullable || nullInEnum || void 0;
1931
1950
  const enumDefault = schema.default === null && enumNullable ? void 0 : schema.default;
1932
1951
  const enumPrimitive = getPrimitiveType(type);
@@ -1976,7 +1995,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1976
1995
  const properties = schema.properties ? Object.entries(schema.properties).map(([propName, propSchema]) => {
1977
1996
  const required = Array.isArray(schema.required) ? schema.required.includes(propName) : !!schema.required;
1978
1997
  const resolvedPropSchema = propSchema;
1979
- const propNullable = dialect.isNullable(resolvedPropSchema);
1998
+ const propNullable = dialect.schema.isNullable(resolvedPropSchema);
1980
1999
  const schemaNode = nameEnums(parseSchema({
1981
2000
  schema: resolvedPropSchema,
1982
2001
  name: (0, _kubb_ast_utils.childName)(name, propName)
@@ -1992,7 +2011,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1992
2011
  nullable: schemaNode.type === "null" ? void 0 : propNullable || void 0
1993
2012
  },
1994
2013
  required
1995
- });
2014
+ }, dialect);
1996
2015
  }) : [];
1997
2016
  const additionalProperties = schema.additionalProperties;
1998
2017
  const additionalPropertiesNode = (() => {
@@ -2013,7 +2032,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2013
2032
  maxProperties: schema.maxProperties,
2014
2033
  ...buildSchemaNode(schema, name, nullable, defaultValue)
2015
2034
  });
2016
- if (dialect.isDiscriminator(schema) && schema.discriminator.mapping) {
2035
+ if (dialect.schema.isDiscriminator(schema) && schema.discriminator.mapping) {
2017
2036
  const discPropName = schema.discriminator.propertyName;
2018
2037
  const values = Object.keys(schema.discriminator.mapping);
2019
2038
  const enumName = name ? (0, _kubb_ast_utils.enumPropName)(name, discPropName, options.enumSuffix) : void 0;
@@ -2157,7 +2176,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2157
2176
  const schemaRules = [
2158
2177
  {
2159
2178
  name: "ref",
2160
- match: ({ schema }) => dialect.isReference(schema),
2179
+ match: ({ schema }) => dialect.schema.isReference(schema),
2161
2180
  convert: convertRef
2162
2181
  },
2163
2182
  {
@@ -2182,7 +2201,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2182
2201
  },
2183
2202
  {
2184
2203
  name: "blob",
2185
- match: ({ schema }) => dialect.isBinary(schema),
2204
+ match: ({ schema }) => dialect.schema.isBinary(schema),
2186
2205
  convert: convertBlob
2187
2206
  },
2188
2207
  {
@@ -2263,7 +2282,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2263
2282
  schema: flattenedSchema,
2264
2283
  name
2265
2284
  }, rawOptions);
2266
- const nullable = dialect.isNullable(schema) || void 0;
2285
+ const nullable = dialect.schema.isNullable(schema) || void 0;
2267
2286
  const schemaCtx = {
2268
2287
  schema,
2269
2288
  name,
@@ -2306,7 +2325,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2306
2325
  description: param["description"] ?? schema.description
2307
2326
  },
2308
2327
  required
2309
- });
2328
+ }, dialect);
2310
2329
  }
2311
2330
  /**
2312
2331
  * Reads the inline `requestBody` metadata (description / required) that OAS exposes
@@ -2340,7 +2359,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2340
2359
  const keys = [];
2341
2360
  for (const key in schema.properties) {
2342
2361
  const prop = schema.properties[key];
2343
- if (prop && !dialect.isReference(prop) && prop[flag]) keys.push(key);
2362
+ if (prop && !dialect.schema.isReference(prop) && prop[flag]) keys.push(key);
2344
2363
  }
2345
2364
  return keys.length ? keys : null;
2346
2365
  }
@@ -2357,14 +2376,14 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2357
2376
  const content = allContentTypes.flatMap((ct) => {
2358
2377
  const schema = getRequestSchema(document, operation, { contentType: ct });
2359
2378
  if (!schema) return [];
2360
- return [{
2379
+ return [_kubb_core.ast.factory.createContent({
2361
2380
  contentType: ct,
2362
- schema: _kubb_core.ast.syncOptionality(parseSchema({
2381
+ schema: dialect.schema.optionality(parseSchema({
2363
2382
  schema,
2364
2383
  name: requestBodyName
2365
2384
  }, options), requestBodyMeta.required),
2366
2385
  keysToOmit: collectPropertyKeysByFlag(schema, "readOnly")
2367
- }];
2386
+ })];
2368
2387
  });
2369
2388
  const requestBody = content.length > 0 || requestBodyMeta.description ? {
2370
2389
  description: requestBodyMeta.description,
@@ -2389,17 +2408,17 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2389
2408
  keysToOmit: collectPropertyKeysByFlag(raw, "writeOnly")
2390
2409
  };
2391
2410
  };
2392
- const content = (ctx.contentType ? [ctx.contentType] : getResponseBodyContentTypes(document, operation, statusCode)).map((contentType) => ({
2411
+ const content = (ctx.contentType ? [ctx.contentType] : getResponseBodyContentTypes(document, operation, statusCode)).map((contentType) => _kubb_core.ast.factory.createContent({
2393
2412
  contentType,
2394
2413
  ...parseEntrySchema(contentType)
2395
2414
  }));
2396
- if (content.length === 0) content.push({
2415
+ if (content.length === 0) content.push(_kubb_core.ast.factory.createContent({
2397
2416
  contentType: getRequestContentType({
2398
2417
  document,
2399
2418
  operation
2400
2419
  }) || "application/json",
2401
2420
  ...parseEntrySchema(ctx.contentType)
2402
- });
2421
+ }));
2403
2422
  return _kubb_core.ast.factory.createResponse({
2404
2423
  statusCode,
2405
2424
  description,
@@ -2407,7 +2426,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2407
2426
  });
2408
2427
  });
2409
2428
  const pathItem = document.paths?.[operation.path];
2410
- const pathItemDoc = pathItem && !dialect.isReference(pathItem) ? pathItem : void 0;
2429
+ const pathItemDoc = pathItem && !dialect.schema.isReference(pathItem) ? pathItem : void 0;
2411
2430
  const pickDoc = (key) => {
2412
2431
  const own = operation.schema[key];
2413
2432
  if (typeof own === "string") return own;
@@ -2492,36 +2511,6 @@ function visit(node, pointer) {
2492
2511
  //#endregion
2493
2512
  //#region src/stream.ts
2494
2513
  /**
2495
- * Builds the deduplication plan from the already-parsed top-level schema nodes plus a
2496
- * single extra parse pass over operations (so duplicates in request/response bodies are seen).
2497
- *
2498
- * Only enums and objects are candidates, and object shapes that reference a circular schema are
2499
- * rejected to avoid hoisting recursive structures. Inline shapes reuse their context-derived
2500
- * name (collision-resolved against existing component names). Shapes without a name stay inline.
2501
- */
2502
- function createDedupePlan({ schemaNodes, operationNodes, schemaNames, circularNames }) {
2503
- const circularSchemas = new Set(circularNames);
2504
- const usedNames = new Set(schemaNames);
2505
- return _kubb_core.ast.buildDedupePlan([...schemaNodes, ...operationNodes], {
2506
- isCandidate: (node) => {
2507
- if (node.type === "enum") return true;
2508
- if (node.type !== "object") return false;
2509
- if (node.name && circularSchemas.has(node.name)) return false;
2510
- return !(0, _kubb_ast_utils.containsCircularRef)(node, { circularSchemas });
2511
- },
2512
- nameFor: (node) => {
2513
- const base = node.name;
2514
- if (!base) return null;
2515
- let name = base;
2516
- let counter = 2;
2517
- while (usedNames.has(name)) name = `${base}${counter++}`;
2518
- usedNames.add(name);
2519
- return name;
2520
- },
2521
- refFor: (name) => `${SCHEMA_REF_PREFIX}${name}`
2522
- });
2523
- }
2524
- /**
2525
2514
  * Reads the server URL from the document's `servers` array at `serverIndex`,
2526
2515
  * interpolating any `serverVariables` into the URL template.
2527
2516
  *
@@ -2590,11 +2579,25 @@ function preScan({ schemas, parseSchema, parseOperation, document, parserOptions
2590
2579
  const operationNode = parseOperation(parserOptions, operation);
2591
2580
  if (operationNode) operationNodes.push(operationNode);
2592
2581
  }
2593
- dedupePlan = createDedupePlan({
2594
- schemaNodes: allNodes,
2595
- operationNodes,
2596
- schemaNames: Object.keys(schemas),
2597
- circularNames
2582
+ const circularSchemas = new Set(circularNames);
2583
+ const usedNames = new Set(Object.keys(schemas));
2584
+ dedupePlan = _kubb_core.ast.buildDedupePlan([...allNodes, ...operationNodes], {
2585
+ isCandidate: (node) => {
2586
+ if (node.type === "enum") return true;
2587
+ if (node.type !== "object") return false;
2588
+ if (node.name && circularSchemas.has(node.name)) return false;
2589
+ return !(0, _kubb_ast_utils.containsCircularRef)(node, { circularSchemas });
2590
+ },
2591
+ nameFor: (node) => {
2592
+ const base = node.name;
2593
+ if (!base) return null;
2594
+ let name = base;
2595
+ let counter = 2;
2596
+ while (usedNames.has(name)) name = `${base}${counter++}`;
2597
+ usedNames.add(name);
2598
+ return name;
2599
+ },
2600
+ refFor: (name) => `${SCHEMA_REF_PREFIX}${name}`
2598
2601
  });
2599
2602
  for (const definition of dedupePlan.hoisted) if (definition.type === "enum" && definition.name) enumNames.push(definition.name);
2600
2603
  }