@kubb/adapter-oas 5.0.0-alpha.12 → 5.0.0-alpha.14

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
@@ -914,12 +914,13 @@ function extractSchemaFromContent(content, preferredContentType) {
914
914
  * Returns the PascalCase suffix appended to a component name when resolving
915
915
  * cross-source name collisions (schemas vs. responses vs. requestBodies).
916
916
  */
917
+ const semanticSuffixes = {
918
+ schemas: "Schema",
919
+ responses: "Response",
920
+ requestBodies: "Request"
921
+ };
917
922
  function getSemanticSuffix(source) {
918
- switch (source) {
919
- case "schemas": return "Schema";
920
- case "responses": return "Response";
921
- case "requestBodies": return "Request";
922
- }
923
+ return semanticSuffixes[source];
923
924
  }
924
925
  /**
925
926
  * Builds `GetSchemasResult` without any collision detection.
@@ -1281,6 +1282,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1281
1282
  pattern: schema.pattern ?? ("pattern" in memberNode ? memberNode.pattern : void 0)
1282
1283
  });
1283
1284
  }
1285
+ const filteredDiscriminantValues = [];
1284
1286
  const allOfMembers = schema.allOf.filter((item) => {
1285
1287
  if (!isReference(item) || !name) return true;
1286
1288
  const deref = oas.get(item.$ref);
@@ -1290,7 +1292,15 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1290
1292
  const childRef = `#/components/schemas/${name}`;
1291
1293
  const inOneOf = parentUnion.some((oneOfItem) => isReference(oneOfItem) && oneOfItem.$ref === childRef);
1292
1294
  const inMapping = Object.values(deref.discriminator.mapping ?? {}).some((v) => v === childRef);
1293
- return !inOneOf && !inMapping;
1295
+ if (inOneOf || inMapping) {
1296
+ const discriminatorValue = Object.entries(deref.discriminator.mapping ?? {}).find(([, v]) => v === childRef)?.[0];
1297
+ if (discriminatorValue) filteredDiscriminantValues.push({
1298
+ propertyName: deref.discriminator.propertyName,
1299
+ value: discriminatorValue
1300
+ });
1301
+ return false;
1302
+ }
1303
+ return true;
1294
1304
  }).map((s) => convertSchema({ schema: s }, options));
1295
1305
  const syntheticStart = allOfMembers.length;
1296
1306
  if (Array.isArray(schema.required) && schema.required.length) {
@@ -1315,9 +1325,22 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1315
1325
  const { allOf: _allOf, ...schemaWithoutAllOf } = schema;
1316
1326
  allOfMembers.push(convertSchema({ schema: schemaWithoutAllOf }, options));
1317
1327
  }
1328
+ for (const { propertyName, value } of filteredDiscriminantValues) allOfMembers.push((0, _kubb_ast.createSchema)({
1329
+ type: "object",
1330
+ primitive: "object",
1331
+ properties: [(0, _kubb_ast.createProperty)({
1332
+ name: propertyName,
1333
+ schema: (0, _kubb_ast.createSchema)({
1334
+ type: "enum",
1335
+ primitive: "string",
1336
+ enumValues: [value]
1337
+ }),
1338
+ required: true
1339
+ })]
1340
+ }));
1318
1341
  return (0, _kubb_ast.createSchema)({
1319
1342
  type: "intersection",
1320
- members: [...allOfMembers.slice(0, syntheticStart), ...mergeAdjacentAnonymousObjects(allOfMembers.slice(syntheticStart))],
1343
+ members: [...mergeAdjacentAnonymousObjects(allOfMembers.slice(0, syntheticStart)), ...mergeAdjacentAnonymousObjects(allOfMembers.slice(syntheticStart))],
1321
1344
  ...renderSchemaBase(schema, name, nullable, defaultValue)
1322
1345
  });
1323
1346
  }
@@ -1361,6 +1384,33 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1361
1384
  })
1362
1385
  });
1363
1386
  }
1387
+ const discriminator = isDiscriminator(schema) ? schema.discriminator : void 0;
1388
+ if (discriminator?.mapping) return (0, _kubb_ast.createSchema)({
1389
+ type: "union",
1390
+ ...unionBase,
1391
+ members: unionMembers.map((s) => {
1392
+ const ref = isReference(s) ? s.$ref : void 0;
1393
+ const discriminatorValue = ref ? Object.entries(discriminator.mapping).find(([, v]) => v === ref)?.[0] : void 0;
1394
+ const memberNode = convertSchema({ schema: s }, options);
1395
+ if (!discriminatorValue) return memberNode;
1396
+ return (0, _kubb_ast.createSchema)({
1397
+ type: "intersection",
1398
+ members: [memberNode, (0, _kubb_ast.createSchema)({
1399
+ type: "object",
1400
+ primitive: "object",
1401
+ properties: [(0, _kubb_ast.createProperty)({
1402
+ name: discriminator.propertyName,
1403
+ schema: (0, _kubb_ast.createSchema)({
1404
+ type: "enum",
1405
+ primitive: "string",
1406
+ enumValues: [discriminatorValue]
1407
+ }),
1408
+ required: true
1409
+ })]
1410
+ })]
1411
+ });
1412
+ })
1413
+ });
1364
1414
  return (0, _kubb_ast.createSchema)({
1365
1415
  type: "union",
1366
1416
  ...unionBase,
@@ -1380,8 +1430,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1380
1430
  name,
1381
1431
  title: schema.title,
1382
1432
  description: schema.description,
1383
- deprecated: schema.deprecated,
1384
- nullable
1433
+ deprecated: schema.deprecated
1385
1434
  });
1386
1435
  return (0, _kubb_ast.createSchema)({
1387
1436
  type: "enum",
@@ -1583,16 +1632,23 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1583
1632
  const required = Array.isArray(schema.required) ? schema.required.includes(propName) : !!schema.required;
1584
1633
  const resolvedPropSchema = propSchema;
1585
1634
  const propNullable = isNullable(resolvedPropSchema);
1635
+ let schemaNode = applyEnumName(convertSchema({
1636
+ schema: resolvedPropSchema,
1637
+ name: resolveChildName(name, propName)
1638
+ }, options), name, propName, mergedOptions.enumSuffix);
1639
+ const tupleNode = (0, _kubb_ast.narrowSchema)(schemaNode, "tuple");
1640
+ if (tupleNode?.items) {
1641
+ const namedItems = tupleNode.items.map((item) => applyEnumName(item, name, propName, mergedOptions.enumSuffix));
1642
+ if (namedItems.some((item, i) => item !== tupleNode.items[i])) schemaNode = {
1643
+ ...tupleNode,
1644
+ items: namedItems
1645
+ };
1646
+ }
1586
1647
  return (0, _kubb_ast.createProperty)({
1587
1648
  name: propName,
1588
1649
  schema: {
1589
- ...applyEnumName(convertSchema({
1590
- schema: resolvedPropSchema,
1591
- name: resolveChildName(name, propName)
1592
- }, options), name, propName, mergedOptions.enumSuffix),
1593
- nullable: propNullable || void 0,
1594
- optional: !required && !propNullable ? true : void 0,
1595
- nullish: !required && propNullable ? true : void 0
1650
+ ...schemaNode,
1651
+ nullable: schemaNode.type === "null" ? void 0 : propNullable || void 0
1596
1652
  },
1597
1653
  required
1598
1654
  });
@@ -1627,15 +1683,17 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1627
1683
  /**
1628
1684
  * Converts an OAS 3.1 `prefixItems` tuple into a `TupleSchemaNode`.
1629
1685
  *
1630
- * Each `prefixItems` element maps to a positional tuple slot. An optional `items` schema
1631
- * after the prefix items is mapped to the rest parameter of the tuple.
1686
+ * Each `prefixItems` element maps to a positional tuple slot. When an explicit `items` schema
1687
+ * is present alongside `prefixItems`, it becomes the rest element. When `items` is absent,
1688
+ * a rest element of type `any` is emitted to match JSON Schema semantics (absent `items`
1689
+ * means additional items are allowed).
1632
1690
  */
1633
1691
  function convertTuple({ schema, name, nullable, defaultValue, options }) {
1634
1692
  return (0, _kubb_ast.createSchema)({
1635
1693
  type: "tuple",
1636
1694
  primitive: "array",
1637
1695
  items: (schema.prefixItems ?? []).map((item) => convertSchema({ schema: item }, options)),
1638
- rest: schema.items ? convertSchema({ schema: schema.items }, options) : void 0,
1696
+ rest: schema.items ? convertSchema({ schema: schema.items }, options) : (0, _kubb_ast.createSchema)({ type: "any" }),
1639
1697
  min: schema.minItems,
1640
1698
  max: schema.maxItems,
1641
1699
  ...renderSchemaBase(schema, name, nullable, defaultValue)
@@ -1802,18 +1860,17 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1802
1860
  }
1803
1861
  /**
1804
1862
  * Converts a single dereferenced OAS parameter object into a `ParameterNode`.
1805
- * When the parameter has no `schema` or its schema is a `$ref`, falls back to `unknownType`.
1863
+ * When the parameter has no `schema`, falls back to `unknownType`; `$ref` schemas are resolved through `convertSchema` to produce a proper named type reference.
1806
1864
  */
1807
1865
  function parseParameter(options, param) {
1808
1866
  const required = param["required"] ?? false;
1809
- const schema = param["schema"] && !isReference(param["schema"]) ? convertSchema({ schema: param["schema"] }, options) : (0, _kubb_ast.createSchema)({ type: resolveTypeOption(options.unknownType) });
1867
+ const schema = param["schema"] ? convertSchema({ schema: param["schema"] }, options) : (0, _kubb_ast.createSchema)({ type: resolveTypeOption(options.unknownType) });
1810
1868
  return (0, _kubb_ast.createParameter)({
1811
1869
  name: param["name"],
1812
1870
  in: param["in"],
1813
1871
  schema: {
1814
1872
  ...schema,
1815
- description: param["description"] ?? schema.description,
1816
- optional: !required || !!schema.optional ? true : void 0
1873
+ description: param["description"] ?? schema.description
1817
1874
  },
1818
1875
  required
1819
1876
  });
@@ -1826,8 +1883,10 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1826
1883
  const parameters = oas.getParameters(operation).map((param) => parseParameter(options, param));
1827
1884
  const requestBodySchema = oas.getRequestSchema(operation);
1828
1885
  const requestBodySchemaNode = requestBodySchema ? convertSchema({ schema: requestBodySchema }, options) : void 0;
1886
+ const requestBodyDescription = operation.schema.requestBody && !isReference(operation.schema.requestBody) ? operation.schema.requestBody.description : void 0;
1829
1887
  const requestBodyKeysToOmit = requestBodySchema?.properties ? Object.entries(requestBodySchema.properties).filter(([, prop]) => !isReference(prop) && prop.readOnly).map(([key]) => key) : void 0;
1830
1888
  const requestBody = requestBodySchemaNode ? {
1889
+ description: requestBodyDescription,
1831
1890
  schema: requestBodySchemaNode,
1832
1891
  keysToOmit: requestBodyKeysToOmit?.length ? requestBodyKeysToOmit : void 0
1833
1892
  } : void 0;
@@ -1978,16 +2037,17 @@ const adapterOas = (0, _kubb_core.createAdapter)((options) => {
1978
2037
  contentType,
1979
2038
  collisionDetection
1980
2039
  });
2040
+ const root = parser.parse({
2041
+ dateType,
2042
+ integerType,
2043
+ unknownType,
2044
+ emptySchemaType,
2045
+ enumSuffix
2046
+ });
1981
2047
  nameMapping.clear();
1982
2048
  for (const [key, value] of parser.nameMapping) nameMapping.set(key, value);
1983
2049
  return (0, _kubb_ast.createRoot)({
1984
- ...parser.parse({
1985
- dateType,
1986
- integerType,
1987
- unknownType,
1988
- emptySchemaType,
1989
- enumSuffix
1990
- }),
2050
+ ...root,
1991
2051
  meta: {
1992
2052
  title: oas.api.info?.title,
1993
2053
  description: oas.api.info?.description,