@kubb/adapter-oas 5.0.0-beta.58 → 5.0.0-beta.59

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.d.ts CHANGED
@@ -1071,8 +1071,7 @@ type Operation = {
1071
1071
  //#endregion
1072
1072
  //#region src/types.d.ts
1073
1073
  /**
1074
- * Content-type string for selecting request/response schemas from an OpenAPI spec.
1075
- * Supports `'application/json'` or any other media type.
1074
+ * Media type used to pick a schema from an operation's request or response.
1076
1075
  *
1077
1076
  * @example
1078
1077
  * ```ts
@@ -1131,12 +1130,12 @@ type SchemaObject$1 = {
1131
1130
  */
1132
1131
  items?: SchemaObject$1 | ReferenceObject$1;
1133
1132
  /**
1134
- * Enum values for this schema (narrowed from `unknown[]`).
1133
+ * Allowed values for this schema.
1135
1134
  */
1136
1135
  enum?: Array<string | number | boolean | null>;
1137
1136
  } & (OpenAPIV3.SchemaObject | OpenAPIV3_1.SchemaObject | JSONSchema4 | JSONSchema6 | JSONSchema7);
1138
1137
  /**
1139
- * HTTP method as a lowercase string (`'get' | 'post' | ...`).
1138
+ * HTTP method in the lowercase form an OpenAPI path item uses for its keys.
1140
1139
  */
1141
1140
  type HttpMethod = Lowercase<ast.HttpMethod>;
1142
1141
  /**
@@ -1156,7 +1155,7 @@ type DiscriminatorObject$1 = OpenAPIV3.DiscriminatorObject | OpenAPIV3_1.Discrim
1156
1155
  */
1157
1156
  type ReferenceObject$1 = OpenAPIV3.ReferenceObject;
1158
1157
  /**
1159
- * OpenAPI response object from a spec that contains schema, status code, and headers.
1158
+ * OpenAPI response object holding the content and headers for one status code.
1160
1159
  */
1161
1160
  type ResponseObject$1 = OpenAPIV3.ResponseObject | OpenAPIV3_1.ResponseObject;
1162
1161
  /**
@@ -1164,9 +1163,8 @@ type ResponseObject$1 = OpenAPIV3.ResponseObject | OpenAPIV3_1.ResponseObject;
1164
1163
  */
1165
1164
  type MediaTypeObject$1 = OpenAPIV3.MediaTypeObject | OpenAPIV3_1.MediaTypeObject;
1166
1165
  /**
1167
- * Configuration options for the OpenAPI adapter. Controls spec validation,
1168
- * content-type selection, server URL resolution, and how types are derived
1169
- * from the spec.
1166
+ * Configuration for the OpenAPI adapter: spec validation, content-type selection,
1167
+ * server URL resolution, and how schema types are derived.
1170
1168
  *
1171
1169
  * @example
1172
1170
  * ```ts
@@ -1227,9 +1225,9 @@ type AdapterOasOptions = {
1227
1225
  *
1228
1226
  * Duplicated inline shapes (especially enums repeated across many properties) are hoisted
1229
1227
  * into one named schema. Every other occurrence, and any structurally identical top-level
1230
- * component, becomes a `ref` to it. Equality is shape-only: documentation such as
1231
- * `description` and `example` is ignored. Enabled by default. Set to `false` to keep every
1232
- * occurrence inline and produce byte-for-byte identical output to earlier versions.
1228
+ * component, becomes a `ref` to it. Equality is shape-only, so documentation such as
1229
+ * `description` and `example` is ignored. Set to `false` to keep every occurrence inline
1230
+ * and produce byte-for-byte identical output to earlier versions.
1233
1231
  *
1234
1232
  * @default true
1235
1233
  */
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { access, readFile } from "node:fs/promises";
5
5
  import { compileErrors, validate } from "@readme/openapi-parser";
6
6
  import { parse } from "yaml";
7
7
  import { bundle } from "api-ref-bundler";
8
- import { childName, containsCircularRef, enumPropName, extractRefName, findCircularSchemas, findDiscriminator } from "@kubb/ast/utils";
8
+ import { childName, containsCircularRef, enumPropName, extractRefName, findCircularSchemas } from "@kubb/ast/utils";
9
9
  import { collect, narrowSchema } from "@kubb/ast";
10
10
  //#region src/constants.ts
11
11
  /**
@@ -91,7 +91,7 @@ const structuralKeys = new Set([
91
91
  *
92
92
  * Only formats whose AST type differs from the OAS `type` field appear here.
93
93
  * Formats that depend on runtime options (`int64`, `date-time`, `date`, `time`) are handled separately
94
- * in the parser. `ipv4` and `ipv6` map to their own dedicated schema types; `hostname` and
94
+ * in the parser. `ipv4` and `ipv6` map to their own dedicated schema types. `hostname` and
95
95
  * `idn-hostname` map to `'url'` as the closest generic string-format type.
96
96
  *
97
97
  * @example
@@ -144,8 +144,8 @@ const formatMap = {
144
144
  */
145
145
  const enumExtensionKeys = ["x-enumNames", "x-enum-varnames"];
146
146
  /**
147
- * Maps `'any' | 'unknown' | 'void'` option strings to their `ScalarSchemaType` constant.
148
- * Replaces a plain object lookup with a `Map` for explicit key membership testing via `.has()`.
147
+ * Maps the `unknownType`/`emptySchemaType` option string to its `ScalarSchemaType` constant.
148
+ * A `Map` (over a plain object) lets callers test key membership with `.has()`.
149
149
  */
150
150
  const typeOptionMap = new Map([
151
151
  ["any", ast.schemaTypes.any],
@@ -840,6 +840,120 @@ const oasDialect = ast.defineSchemaDialect({
840
840
  resolveRef
841
841
  });
842
842
  //#endregion
843
+ //#region src/discriminator.ts
844
+ /**
845
+ * Builds a map of child schema names → discriminator patch data by scanning the given
846
+ * top-level AST schema nodes for union schemas that carry a `discriminatorPropertyName`.
847
+ *
848
+ * The streaming path calls this on a small pre-parsed subset of schemas (only the
849
+ * discriminator parents) rather than on all schemas at once.
850
+ */
851
+ function buildDiscriminatorChildMap(schemas) {
852
+ const childMap = /* @__PURE__ */ new Map();
853
+ for (const schema of schemas) {
854
+ let unionNode = ast.narrowSchema(schema, "union");
855
+ if (!unionNode) {
856
+ const intersectionMembers = ast.narrowSchema(schema, "intersection")?.members;
857
+ if (intersectionMembers) for (const m of intersectionMembers) {
858
+ const u = ast.narrowSchema(m, "union");
859
+ if (u) {
860
+ unionNode = u;
861
+ break;
862
+ }
863
+ }
864
+ }
865
+ if (!unionNode?.discriminatorPropertyName || !unionNode.members) continue;
866
+ const { discriminatorPropertyName, members } = unionNode;
867
+ for (const member of members) {
868
+ const intersectionNode = ast.narrowSchema(member, "intersection");
869
+ if (!intersectionNode?.members) continue;
870
+ let refNode = null;
871
+ let objNode = null;
872
+ for (const m of intersectionNode.members) {
873
+ refNode ??= ast.narrowSchema(m, "ref");
874
+ objNode ??= ast.narrowSchema(m, "object");
875
+ }
876
+ if (!refNode?.name || !objNode) continue;
877
+ const prop = objNode.properties.find((p) => p.name === discriminatorPropertyName);
878
+ const enumNode = prop ? ast.narrowSchema(prop.schema, "enum") : null;
879
+ if (!enumNode?.enumValues?.length) continue;
880
+ const enumValues = enumNode.enumValues.filter((v) => v !== null);
881
+ if (!enumValues.length) continue;
882
+ const existing = childMap.get(refNode.name);
883
+ if (!existing) {
884
+ childMap.set(refNode.name, {
885
+ propertyName: discriminatorPropertyName,
886
+ enumValues: [...enumValues]
887
+ });
888
+ continue;
889
+ }
890
+ existing.enumValues.push(...enumValues);
891
+ }
892
+ }
893
+ return childMap;
894
+ }
895
+ /**
896
+ * Patches a single top-level `SchemaNode` with its discriminator entry (adds or replaces
897
+ * the discriminant property). Used by the streaming path to apply patches inline per yield
898
+ * without buffering all schemas.
899
+ */
900
+ function patchDiscriminatorNode(node, entry) {
901
+ const objectNode = ast.narrowSchema(node, "object");
902
+ if (!objectNode) return node;
903
+ const { propertyName, enumValues } = entry;
904
+ const enumSchema = ast.factory.createSchema({
905
+ type: "enum",
906
+ enumValues
907
+ });
908
+ const newProp = ast.factory.createProperty({
909
+ name: propertyName,
910
+ required: true,
911
+ schema: enumSchema
912
+ });
913
+ const existingIdx = objectNode.properties.findIndex((p) => p.name === propertyName);
914
+ const newProperties = existingIdx >= 0 ? objectNode.properties.map((p, i) => i === existingIdx ? newProp : p) : [...objectNode.properties, newProp];
915
+ return {
916
+ ...objectNode,
917
+ properties: newProperties
918
+ };
919
+ }
920
+ /**
921
+ * Creates a single-property object schema used as a discriminator literal.
922
+ *
923
+ * @example
924
+ * ```ts
925
+ * createDiscriminantNode({ propertyName: 'type', value: 'dog' })
926
+ * // -> { type: 'object', properties: [{ name: 'type', required: true, schema: enum('dog') }] }
927
+ * ```
928
+ */
929
+ function createDiscriminantNode({ propertyName, value }) {
930
+ return ast.factory.createSchema({
931
+ type: "object",
932
+ primitive: "object",
933
+ properties: [ast.factory.createProperty({
934
+ name: propertyName,
935
+ schema: ast.factory.createSchema({
936
+ type: "enum",
937
+ primitive: "string",
938
+ enumValues: [value]
939
+ }),
940
+ required: true
941
+ })]
942
+ });
943
+ }
944
+ /**
945
+ * Returns the discriminator key whose mapping value matches `ref`, or `null` when there is no match.
946
+ *
947
+ * @example
948
+ * ```ts
949
+ * findDiscriminator({ dog: '#/components/schemas/Dog' }, '#/components/schemas/Dog') // 'dog'
950
+ * ```
951
+ */
952
+ function findDiscriminator(mapping, ref) {
953
+ if (!mapping || !ref) return null;
954
+ return Object.entries(mapping).find(([, value]) => value === ref)?.[0] ?? null;
955
+ }
956
+ //#endregion
843
957
  //#region src/mime.ts
844
958
  /**
845
959
  * MIME type fragments that mark a media type as JSON-like.
@@ -1328,7 +1442,7 @@ function getSchemas(document, { contentType }) {
1328
1442
  }
1329
1443
  /**
1330
1444
  * Resolves the AST type descriptor for a date/time format, honoring the `dateType` option.
1331
- * Returns `null` when `dateType: false`, signalling the format should fall through to `string`.
1445
+ * Returns `null` when `dateType: false`, so the format falls through to `string`.
1332
1446
  */
1333
1447
  function getDateType(options, format) {
1334
1448
  if (!options.dateType) return null;
@@ -1430,9 +1544,9 @@ function getResponseBodyContentTypes(document, operation, statusCode) {
1430
1544
  * Normalizes malformed `{ type: 'array', enum: [...] }` schemas by moving enum values into items.
1431
1545
  *
1432
1546
  * This pattern violates the OpenAPI spec but appears in real specs. The fix moves enum values
1433
- * from the array to its items sub-schema, making them valid for downstream processing.
1547
+ * from the array to its items sub-schema, so they are valid for downstream processing.
1434
1548
  *
1435
- * @note This is a defensive measure for robustness with non-compliant specs.
1549
+ * @note A defensive measure for non-compliant specs.
1436
1550
  */
1437
1551
  function normalizeArrayEnum(schema) {
1438
1552
  const normalizedItems = {
@@ -1450,7 +1564,7 @@ function normalizeArrayEnum(schema) {
1450
1564
  *
1451
1565
  * Returns closures that share mutable state (`resolvingRefs` set for cycle detection).
1452
1566
  * Each converter branch (`convertRef`, `convertAllOf`, etc.) mutually recursively calls `parseSchema`,
1453
- * made possible by hoisting of function declarations.
1567
+ * which works because function declarations hoist.
1454
1568
  *
1455
1569
  * @internal
1456
1570
  */
@@ -1580,7 +1694,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1580
1694
  const { allOf: _allOf, ...schemaWithoutAllOf } = schema;
1581
1695
  allOfMembers.push(parseSchema({ schema: schemaWithoutAllOf }, rawOptions));
1582
1696
  }
1583
- for (const { propertyName, value } of filteredDiscriminantValues) allOfMembers.push(ast.factory.createDiscriminantNode({
1697
+ for (const { propertyName, value } of filteredDiscriminantValues) allOfMembers.push(createDiscriminantNode({
1584
1698
  propertyName,
1585
1699
  value
1586
1700
  }));
@@ -1634,7 +1748,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1634
1748
  }), discriminator.propertyName) : void 0;
1635
1749
  return ast.factory.createSchema({
1636
1750
  type: "intersection",
1637
- members: [memberNode, narrowedDiscriminatorNode ?? ast.factory.createDiscriminantNode({
1751
+ members: [memberNode, narrowedDiscriminatorNode ?? createDiscriminantNode({
1638
1752
  propertyName: discriminator.propertyName,
1639
1753
  value: discriminatorValue
1640
1754
  })]
@@ -2289,84 +2403,6 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2289
2403
  };
2290
2404
  }
2291
2405
  //#endregion
2292
- //#region src/discriminator.ts
2293
- /**
2294
- * Builds a map of child schema names → discriminator patch data by scanning the given
2295
- * top-level AST schema nodes for union schemas that carry a `discriminatorPropertyName`.
2296
- *
2297
- * The streaming path calls this on a small pre-parsed subset of schemas (only the
2298
- * discriminator parents) rather than on all schemas at once.
2299
- */
2300
- function buildDiscriminatorChildMap(schemas) {
2301
- const childMap = /* @__PURE__ */ new Map();
2302
- for (const schema of schemas) {
2303
- let unionNode = ast.narrowSchema(schema, "union");
2304
- if (!unionNode) {
2305
- const intersectionMembers = ast.narrowSchema(schema, "intersection")?.members;
2306
- if (intersectionMembers) for (const m of intersectionMembers) {
2307
- const u = ast.narrowSchema(m, "union");
2308
- if (u) {
2309
- unionNode = u;
2310
- break;
2311
- }
2312
- }
2313
- }
2314
- if (!unionNode?.discriminatorPropertyName || !unionNode.members) continue;
2315
- const { discriminatorPropertyName, members } = unionNode;
2316
- for (const member of members) {
2317
- const intersectionNode = ast.narrowSchema(member, "intersection");
2318
- if (!intersectionNode?.members) continue;
2319
- let refNode = null;
2320
- let objNode = null;
2321
- for (const m of intersectionNode.members) {
2322
- refNode ??= ast.narrowSchema(m, "ref");
2323
- objNode ??= ast.narrowSchema(m, "object");
2324
- }
2325
- if (!refNode?.name || !objNode) continue;
2326
- const prop = objNode.properties.find((p) => p.name === discriminatorPropertyName);
2327
- const enumNode = prop ? ast.narrowSchema(prop.schema, "enum") : null;
2328
- if (!enumNode?.enumValues?.length) continue;
2329
- const enumValues = enumNode.enumValues.filter((v) => v !== null);
2330
- if (!enumValues.length) continue;
2331
- const existing = childMap.get(refNode.name);
2332
- if (!existing) {
2333
- childMap.set(refNode.name, {
2334
- propertyName: discriminatorPropertyName,
2335
- enumValues: [...enumValues]
2336
- });
2337
- continue;
2338
- }
2339
- existing.enumValues.push(...enumValues);
2340
- }
2341
- }
2342
- return childMap;
2343
- }
2344
- /**
2345
- * Patches a single top-level `SchemaNode` with its discriminator entry (adds or replaces
2346
- * the discriminant property). Used by the streaming path to apply patches inline per yield
2347
- * without buffering all schemas.
2348
- */
2349
- function patchDiscriminatorNode(node, entry) {
2350
- const objectNode = ast.narrowSchema(node, "object");
2351
- if (!objectNode) return node;
2352
- const { propertyName, enumValues } = entry;
2353
- const enumSchema = ast.factory.createSchema({
2354
- type: "enum",
2355
- enumValues
2356
- });
2357
- const newProp = ast.factory.createProperty({
2358
- name: propertyName,
2359
- required: true,
2360
- schema: enumSchema
2361
- });
2362
- const existingIdx = objectNode.properties.findIndex((p) => p.name === propertyName);
2363
- const newProperties = existingIdx >= 0 ? objectNode.properties.map((p, i) => i === existingIdx ? newProp : p) : [...objectNode.properties, newProp];
2364
- return {
2365
- ...objectNode,
2366
- properties: newProperties
2367
- };
2368
- }
2369
- //#endregion
2370
2406
  //#region src/schemaDiagnostics.ts
2371
2407
  /**
2372
2408
  * Reports the advisory diagnostics (`KUBB_UNSUPPORTED_FORMAT`, `KUBB_DEPRECATED`) for one
@@ -2429,7 +2465,7 @@ function visit(node, pointer) {
2429
2465
  *
2430
2466
  * Only enums and objects are candidates, and object shapes that reference a circular schema are
2431
2467
  * rejected to avoid hoisting recursive structures. Inline shapes reuse their context-derived
2432
- * name (collision-resolved against existing component names); shapes without a name stay inline.
2468
+ * name (collision-resolved against existing component names). Shapes without a name stay inline.
2433
2469
  */
2434
2470
  function createDedupePlan({ schemaNodes, operationNodes, schemaNames, circularNames }) {
2435
2471
  const circularSchemas = new Set(circularNames);