@kubb/adapter-oas 5.0.0-alpha.11 → 5.0.0-alpha.13

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.js CHANGED
@@ -157,9 +157,12 @@ function toCamelOrPascal(text, pascal) {
157
157
  * Splits `text` on `.` and applies `transformPart` to each segment.
158
158
  * The last segment receives `isLast = true`, all earlier segments receive `false`.
159
159
  * Segments are joined with `/` to form a file path.
160
+ *
161
+ * Only splits on dots followed by a letter so that version numbers
162
+ * embedded in operationIds (e.g. `v2025.0`) are kept intact.
160
163
  */
161
164
  function applyToFileParts(text, transformPart) {
162
- const parts = text.split(".");
165
+ const parts = text.split(/\.(?=[a-zA-Z])/);
163
166
  return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join("/");
164
167
  }
165
168
  /**
@@ -1250,6 +1253,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1250
1253
  pattern: schema.pattern ?? ("pattern" in memberNode ? memberNode.pattern : void 0)
1251
1254
  });
1252
1255
  }
1256
+ const filteredDiscriminantValues = [];
1253
1257
  const allOfMembers = schema.allOf.filter((item) => {
1254
1258
  if (!isReference(item) || !name) return true;
1255
1259
  const deref = oas.get(item.$ref);
@@ -1259,7 +1263,15 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1259
1263
  const childRef = `#/components/schemas/${name}`;
1260
1264
  const inOneOf = parentUnion.some((oneOfItem) => isReference(oneOfItem) && oneOfItem.$ref === childRef);
1261
1265
  const inMapping = Object.values(deref.discriminator.mapping ?? {}).some((v) => v === childRef);
1262
- return !inOneOf && !inMapping;
1266
+ if (inOneOf || inMapping) {
1267
+ const discriminatorValue = Object.entries(deref.discriminator.mapping ?? {}).find(([, v]) => v === childRef)?.[0];
1268
+ if (discriminatorValue) filteredDiscriminantValues.push({
1269
+ propertyName: deref.discriminator.propertyName,
1270
+ value: discriminatorValue
1271
+ });
1272
+ return false;
1273
+ }
1274
+ return true;
1263
1275
  }).map((s) => convertSchema({ schema: s }, options));
1264
1276
  const syntheticStart = allOfMembers.length;
1265
1277
  if (Array.isArray(schema.required) && schema.required.length) {
@@ -1284,9 +1296,22 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1284
1296
  const { allOf: _allOf, ...schemaWithoutAllOf } = schema;
1285
1297
  allOfMembers.push(convertSchema({ schema: schemaWithoutAllOf }, options));
1286
1298
  }
1299
+ for (const { propertyName, value } of filteredDiscriminantValues) allOfMembers.push(createSchema({
1300
+ type: "object",
1301
+ primitive: "object",
1302
+ properties: [createProperty({
1303
+ name: propertyName,
1304
+ schema: createSchema({
1305
+ type: "enum",
1306
+ primitive: "string",
1307
+ enumValues: [value]
1308
+ }),
1309
+ required: true
1310
+ })]
1311
+ }));
1287
1312
  return createSchema({
1288
1313
  type: "intersection",
1289
- members: [...allOfMembers.slice(0, syntheticStart), ...mergeAdjacentAnonymousObjects(allOfMembers.slice(syntheticStart))],
1314
+ members: [...mergeAdjacentAnonymousObjects(allOfMembers.slice(0, syntheticStart)), ...mergeAdjacentAnonymousObjects(allOfMembers.slice(syntheticStart))],
1290
1315
  ...renderSchemaBase(schema, name, nullable, defaultValue)
1291
1316
  });
1292
1317
  }
@@ -1330,6 +1355,33 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1330
1355
  })
1331
1356
  });
1332
1357
  }
1358
+ const discriminator = isDiscriminator(schema) ? schema.discriminator : void 0;
1359
+ if (discriminator?.mapping) return createSchema({
1360
+ type: "union",
1361
+ ...unionBase,
1362
+ members: unionMembers.map((s) => {
1363
+ const ref = isReference(s) ? s.$ref : void 0;
1364
+ const discriminatorValue = ref ? Object.entries(discriminator.mapping).find(([, v]) => v === ref)?.[0] : void 0;
1365
+ const memberNode = convertSchema({ schema: s }, options);
1366
+ if (!discriminatorValue) return memberNode;
1367
+ return createSchema({
1368
+ type: "intersection",
1369
+ members: [memberNode, createSchema({
1370
+ type: "object",
1371
+ primitive: "object",
1372
+ properties: [createProperty({
1373
+ name: discriminator.propertyName,
1374
+ schema: createSchema({
1375
+ type: "enum",
1376
+ primitive: "string",
1377
+ enumValues: [discriminatorValue]
1378
+ }),
1379
+ required: true
1380
+ })]
1381
+ })]
1382
+ });
1383
+ })
1384
+ });
1333
1385
  return createSchema({
1334
1386
  type: "union",
1335
1387
  ...unionBase,
@@ -1349,8 +1401,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1349
1401
  name,
1350
1402
  title: schema.title,
1351
1403
  description: schema.description,
1352
- deprecated: schema.deprecated,
1353
- nullable
1404
+ deprecated: schema.deprecated
1354
1405
  });
1355
1406
  return createSchema({
1356
1407
  type: "enum",
@@ -1552,14 +1603,23 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1552
1603
  const required = Array.isArray(schema.required) ? schema.required.includes(propName) : !!schema.required;
1553
1604
  const resolvedPropSchema = propSchema;
1554
1605
  const propNullable = isNullable(resolvedPropSchema);
1606
+ let schemaNode = applyEnumName(convertSchema({
1607
+ schema: resolvedPropSchema,
1608
+ name: resolveChildName(name, propName)
1609
+ }, options), name, propName, mergedOptions.enumSuffix);
1610
+ const tupleNode = narrowSchema(schemaNode, "tuple");
1611
+ if (tupleNode?.items) {
1612
+ const namedItems = tupleNode.items.map((item) => applyEnumName(item, name, propName, mergedOptions.enumSuffix));
1613
+ if (namedItems.some((item, i) => item !== tupleNode.items[i])) schemaNode = {
1614
+ ...tupleNode,
1615
+ items: namedItems
1616
+ };
1617
+ }
1555
1618
  return createProperty({
1556
1619
  name: propName,
1557
1620
  schema: {
1558
- ...applyEnumName(convertSchema({
1559
- schema: resolvedPropSchema,
1560
- name: resolveChildName(name, propName)
1561
- }, options), name, propName, mergedOptions.enumSuffix),
1562
- nullable: propNullable || void 0,
1621
+ ...schemaNode,
1622
+ nullable: schemaNode.type === "null" ? void 0 : propNullable || void 0,
1563
1623
  optional: !required && !propNullable ? true : void 0,
1564
1624
  nullish: !required && propNullable ? true : void 0
1565
1625
  },
@@ -1596,15 +1656,17 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1596
1656
  /**
1597
1657
  * Converts an OAS 3.1 `prefixItems` tuple into a `TupleSchemaNode`.
1598
1658
  *
1599
- * Each `prefixItems` element maps to a positional tuple slot. An optional `items` schema
1600
- * after the prefix items is mapped to the rest parameter of the tuple.
1659
+ * Each `prefixItems` element maps to a positional tuple slot. When an explicit `items` schema
1660
+ * is present alongside `prefixItems`, it becomes the rest element. When `items` is absent,
1661
+ * a rest element of type `any` is emitted to match JSON Schema semantics (absent `items`
1662
+ * means additional items are allowed).
1601
1663
  */
1602
1664
  function convertTuple({ schema, name, nullable, defaultValue, options }) {
1603
1665
  return createSchema({
1604
1666
  type: "tuple",
1605
1667
  primitive: "array",
1606
1668
  items: (schema.prefixItems ?? []).map((item) => convertSchema({ schema: item }, options)),
1607
- rest: schema.items ? convertSchema({ schema: schema.items }, options) : void 0,
1669
+ rest: schema.items ? convertSchema({ schema: schema.items }, options) : createSchema({ type: "any" }),
1608
1670
  min: schema.minItems,
1609
1671
  max: schema.maxItems,
1610
1672
  ...renderSchemaBase(schema, name, nullable, defaultValue)
@@ -1771,11 +1833,11 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1771
1833
  }
1772
1834
  /**
1773
1835
  * Converts a single dereferenced OAS parameter object into a `ParameterNode`.
1774
- * When the parameter has no `schema` or its schema is a `$ref`, falls back to `unknownType`.
1836
+ * When the parameter has no `schema`, falls back to `unknownType`; `$ref` schemas are resolved through `convertSchema` to produce a proper named type reference.
1775
1837
  */
1776
1838
  function parseParameter(options, param) {
1777
1839
  const required = param["required"] ?? false;
1778
- const schema = param["schema"] && !isReference(param["schema"]) ? convertSchema({ schema: param["schema"] }, options) : createSchema({ type: resolveTypeOption(options.unknownType) });
1840
+ const schema = param["schema"] ? convertSchema({ schema: param["schema"] }, options) : createSchema({ type: resolveTypeOption(options.unknownType) });
1779
1841
  return createParameter({
1780
1842
  name: param["name"],
1781
1843
  in: param["in"],
@@ -1794,18 +1856,28 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1794
1856
  function parseOperation(options, oas, operation) {
1795
1857
  const parameters = oas.getParameters(operation).map((param) => parseParameter(options, param));
1796
1858
  const requestBodySchema = oas.getRequestSchema(operation);
1797
- const requestBody = requestBodySchema ? convertSchema({ schema: requestBodySchema }, options) : void 0;
1859
+ const requestBodySchemaNode = requestBodySchema ? convertSchema({ schema: requestBodySchema }, options) : void 0;
1860
+ const requestBodyDescription = operation.schema.requestBody && !isReference(operation.schema.requestBody) ? operation.schema.requestBody.description : void 0;
1861
+ const requestBodyKeysToOmit = requestBodySchema?.properties ? Object.entries(requestBodySchema.properties).filter(([, prop]) => !isReference(prop) && prop.readOnly).map(([key]) => key) : void 0;
1862
+ const requestBody = requestBodySchemaNode ? {
1863
+ description: requestBodyDescription,
1864
+ schema: requestBodySchemaNode,
1865
+ keysToOmit: requestBodyKeysToOmit?.length ? requestBodyKeysToOmit : void 0
1866
+ } : void 0;
1798
1867
  const responses = operation.getResponseStatusCodes().map((statusCode) => {
1799
1868
  const responseObj = operation.getResponseByStatusCode(statusCode);
1800
1869
  const responseSchema = oas.getResponseSchema(operation, statusCode);
1801
1870
  const schema = responseSchema && Object.keys(responseSchema).length > 0 ? convertSchema({ schema: responseSchema }, options) : createSchema({ type: resolveTypeOption(options.emptySchemaType) });
1802
1871
  const description = typeof responseObj === "object" && responseObj !== null && !Array.isArray(responseObj) ? responseObj.description : void 0;
1803
1872
  const rawContent = typeof responseObj === "object" && responseObj !== null && !Array.isArray(responseObj) ? responseObj.content : void 0;
1873
+ const mediaType = rawContent ? toMediaType(Object.keys(rawContent)[0] ?? "") : toMediaType(operation.contentType ?? "");
1874
+ const keysToOmit = responseSchema?.properties ? Object.entries(responseSchema.properties).filter(([, prop]) => !isReference(prop) && prop.writeOnly).map(([key]) => key) : void 0;
1804
1875
  return createResponse({
1805
1876
  statusCode,
1806
1877
  description,
1807
1878
  schema,
1808
- mediaType: rawContent ? toMediaType(Object.keys(rawContent)[0] ?? "") : toMediaType(operation.contentType ?? "")
1879
+ mediaType,
1880
+ keysToOmit: keysToOmit?.length ? keysToOmit : void 0
1809
1881
  });
1810
1882
  });
1811
1883
  return createOperation({
@@ -1939,16 +2011,17 @@ const adapterOas = createAdapter((options) => {
1939
2011
  contentType,
1940
2012
  collisionDetection
1941
2013
  });
2014
+ const root = parser.parse({
2015
+ dateType,
2016
+ integerType,
2017
+ unknownType,
2018
+ emptySchemaType,
2019
+ enumSuffix
2020
+ });
1942
2021
  nameMapping.clear();
1943
2022
  for (const [key, value] of parser.nameMapping) nameMapping.set(key, value);
1944
2023
  return createRoot({
1945
- ...parser.parse({
1946
- dateType,
1947
- integerType,
1948
- unknownType,
1949
- emptySchemaType,
1950
- enumSuffix
1951
- }),
2024
+ ...root,
1952
2025
  meta: {
1953
2026
  title: oas.api.info?.title,
1954
2027
  description: oas.api.info?.description,