@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.cjs CHANGED
@@ -114,7 +114,7 @@ const structuralKeys = new Set([
114
114
  *
115
115
  * Only formats whose AST type differs from the OAS `type` field appear here.
116
116
  * Formats that depend on runtime options (`int64`, `date-time`, `date`, `time`) are handled separately
117
- * in the parser. `ipv4` and `ipv6` map to their own dedicated schema types; `hostname` and
117
+ * in the parser. `ipv4` and `ipv6` map to their own dedicated schema types. `hostname` and
118
118
  * `idn-hostname` map to `'url'` as the closest generic string-format type.
119
119
  *
120
120
  * @example
@@ -167,8 +167,8 @@ const formatMap = {
167
167
  */
168
168
  const enumExtensionKeys = ["x-enumNames", "x-enum-varnames"];
169
169
  /**
170
- * Maps `'any' | 'unknown' | 'void'` option strings to their `ScalarSchemaType` constant.
171
- * Replaces a plain object lookup with a `Map` for explicit key membership testing via `.has()`.
170
+ * Maps the `unknownType`/`emptySchemaType` option string to its `ScalarSchemaType` constant.
171
+ * A `Map` (over a plain object) lets callers test key membership with `.has()`.
172
172
  */
173
173
  const typeOptionMap = new Map([
174
174
  ["any", _kubb_core.ast.schemaTypes.any],
@@ -863,6 +863,120 @@ const oasDialect = _kubb_core.ast.defineSchemaDialect({
863
863
  resolveRef
864
864
  });
865
865
  //#endregion
866
+ //#region src/discriminator.ts
867
+ /**
868
+ * Builds a map of child schema names → discriminator patch data by scanning the given
869
+ * top-level AST schema nodes for union schemas that carry a `discriminatorPropertyName`.
870
+ *
871
+ * The streaming path calls this on a small pre-parsed subset of schemas (only the
872
+ * discriminator parents) rather than on all schemas at once.
873
+ */
874
+ function buildDiscriminatorChildMap(schemas) {
875
+ const childMap = /* @__PURE__ */ new Map();
876
+ for (const schema of schemas) {
877
+ let unionNode = _kubb_core.ast.narrowSchema(schema, "union");
878
+ if (!unionNode) {
879
+ const intersectionMembers = _kubb_core.ast.narrowSchema(schema, "intersection")?.members;
880
+ if (intersectionMembers) for (const m of intersectionMembers) {
881
+ const u = _kubb_core.ast.narrowSchema(m, "union");
882
+ if (u) {
883
+ unionNode = u;
884
+ break;
885
+ }
886
+ }
887
+ }
888
+ if (!unionNode?.discriminatorPropertyName || !unionNode.members) continue;
889
+ const { discriminatorPropertyName, members } = unionNode;
890
+ for (const member of members) {
891
+ const intersectionNode = _kubb_core.ast.narrowSchema(member, "intersection");
892
+ if (!intersectionNode?.members) continue;
893
+ let refNode = null;
894
+ let objNode = null;
895
+ for (const m of intersectionNode.members) {
896
+ refNode ??= _kubb_core.ast.narrowSchema(m, "ref");
897
+ objNode ??= _kubb_core.ast.narrowSchema(m, "object");
898
+ }
899
+ if (!refNode?.name || !objNode) continue;
900
+ const prop = objNode.properties.find((p) => p.name === discriminatorPropertyName);
901
+ const enumNode = prop ? _kubb_core.ast.narrowSchema(prop.schema, "enum") : null;
902
+ if (!enumNode?.enumValues?.length) continue;
903
+ const enumValues = enumNode.enumValues.filter((v) => v !== null);
904
+ if (!enumValues.length) continue;
905
+ const existing = childMap.get(refNode.name);
906
+ if (!existing) {
907
+ childMap.set(refNode.name, {
908
+ propertyName: discriminatorPropertyName,
909
+ enumValues: [...enumValues]
910
+ });
911
+ continue;
912
+ }
913
+ existing.enumValues.push(...enumValues);
914
+ }
915
+ }
916
+ return childMap;
917
+ }
918
+ /**
919
+ * Patches a single top-level `SchemaNode` with its discriminator entry (adds or replaces
920
+ * the discriminant property). Used by the streaming path to apply patches inline per yield
921
+ * without buffering all schemas.
922
+ */
923
+ function patchDiscriminatorNode(node, entry) {
924
+ const objectNode = _kubb_core.ast.narrowSchema(node, "object");
925
+ if (!objectNode) return node;
926
+ const { propertyName, enumValues } = entry;
927
+ const enumSchema = _kubb_core.ast.factory.createSchema({
928
+ type: "enum",
929
+ enumValues
930
+ });
931
+ const newProp = _kubb_core.ast.factory.createProperty({
932
+ name: propertyName,
933
+ required: true,
934
+ schema: enumSchema
935
+ });
936
+ const existingIdx = objectNode.properties.findIndex((p) => p.name === propertyName);
937
+ const newProperties = existingIdx >= 0 ? objectNode.properties.map((p, i) => i === existingIdx ? newProp : p) : [...objectNode.properties, newProp];
938
+ return {
939
+ ...objectNode,
940
+ properties: newProperties
941
+ };
942
+ }
943
+ /**
944
+ * Creates a single-property object schema used as a discriminator literal.
945
+ *
946
+ * @example
947
+ * ```ts
948
+ * createDiscriminantNode({ propertyName: 'type', value: 'dog' })
949
+ * // -> { type: 'object', properties: [{ name: 'type', required: true, schema: enum('dog') }] }
950
+ * ```
951
+ */
952
+ function createDiscriminantNode({ propertyName, value }) {
953
+ return _kubb_core.ast.factory.createSchema({
954
+ type: "object",
955
+ primitive: "object",
956
+ properties: [_kubb_core.ast.factory.createProperty({
957
+ name: propertyName,
958
+ schema: _kubb_core.ast.factory.createSchema({
959
+ type: "enum",
960
+ primitive: "string",
961
+ enumValues: [value]
962
+ }),
963
+ required: true
964
+ })]
965
+ });
966
+ }
967
+ /**
968
+ * Returns the discriminator key whose mapping value matches `ref`, or `null` when there is no match.
969
+ *
970
+ * @example
971
+ * ```ts
972
+ * findDiscriminator({ dog: '#/components/schemas/Dog' }, '#/components/schemas/Dog') // 'dog'
973
+ * ```
974
+ */
975
+ function findDiscriminator(mapping, ref) {
976
+ if (!mapping || !ref) return null;
977
+ return Object.entries(mapping).find(([, value]) => value === ref)?.[0] ?? null;
978
+ }
979
+ //#endregion
866
980
  //#region src/mime.ts
867
981
  /**
868
982
  * MIME type fragments that mark a media type as JSON-like.
@@ -1351,7 +1465,7 @@ function getSchemas(document, { contentType }) {
1351
1465
  }
1352
1466
  /**
1353
1467
  * Resolves the AST type descriptor for a date/time format, honoring the `dateType` option.
1354
- * Returns `null` when `dateType: false`, signalling the format should fall through to `string`.
1468
+ * Returns `null` when `dateType: false`, so the format falls through to `string`.
1355
1469
  */
1356
1470
  function getDateType(options, format) {
1357
1471
  if (!options.dateType) return null;
@@ -1453,9 +1567,9 @@ function getResponseBodyContentTypes(document, operation, statusCode) {
1453
1567
  * Normalizes malformed `{ type: 'array', enum: [...] }` schemas by moving enum values into items.
1454
1568
  *
1455
1569
  * This pattern violates the OpenAPI spec but appears in real specs. The fix moves enum values
1456
- * from the array to its items sub-schema, making them valid for downstream processing.
1570
+ * from the array to its items sub-schema, so they are valid for downstream processing.
1457
1571
  *
1458
- * @note This is a defensive measure for robustness with non-compliant specs.
1572
+ * @note A defensive measure for non-compliant specs.
1459
1573
  */
1460
1574
  function normalizeArrayEnum(schema) {
1461
1575
  const normalizedItems = {
@@ -1473,7 +1587,7 @@ function normalizeArrayEnum(schema) {
1473
1587
  *
1474
1588
  * Returns closures that share mutable state (`resolvingRefs` set for cycle detection).
1475
1589
  * Each converter branch (`convertRef`, `convertAllOf`, etc.) mutually recursively calls `parseSchema`,
1476
- * made possible by hoisting of function declarations.
1590
+ * which works because function declarations hoist.
1477
1591
  *
1478
1592
  * @internal
1479
1593
  */
@@ -1565,7 +1679,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1565
1679
  const inOneOf = parentUnion.some((oneOfItem) => dialect.isReference(oneOfItem) && oneOfItem.$ref === childRef);
1566
1680
  const inMapping = Object.values(deref.discriminator.mapping ?? {}).some((v) => v === childRef);
1567
1681
  if (inOneOf || inMapping) {
1568
- const discriminatorValue = (0, _kubb_ast_utils.findDiscriminator)(deref.discriminator.mapping, childRef);
1682
+ const discriminatorValue = findDiscriminator(deref.discriminator.mapping, childRef);
1569
1683
  if (discriminatorValue) filteredDiscriminantValues.push({
1570
1684
  propertyName: deref.discriminator.propertyName,
1571
1685
  value: discriminatorValue
@@ -1603,7 +1717,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1603
1717
  const { allOf: _allOf, ...schemaWithoutAllOf } = schema;
1604
1718
  allOfMembers.push(parseSchema({ schema: schemaWithoutAllOf }, rawOptions));
1605
1719
  }
1606
- for (const { propertyName, value } of filteredDiscriminantValues) allOfMembers.push(_kubb_core.ast.factory.createDiscriminantNode({
1720
+ for (const { propertyName, value } of filteredDiscriminantValues) allOfMembers.push(createDiscriminantNode({
1607
1721
  propertyName,
1608
1722
  value
1609
1723
  }));
@@ -1644,7 +1758,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1644
1758
  if (sharedPropertiesNode || discriminator?.mapping) {
1645
1759
  const members = unionMembers.map((s) => {
1646
1760
  const ref = dialect.isReference(s) ? s.$ref : void 0;
1647
- const discriminatorValue = (0, _kubb_ast_utils.findDiscriminator)(discriminator?.mapping, ref);
1761
+ const discriminatorValue = findDiscriminator(discriminator?.mapping, ref);
1648
1762
  const memberNode = parseSchema({
1649
1763
  schema: s,
1650
1764
  name
@@ -1657,7 +1771,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1657
1771
  }), discriminator.propertyName) : void 0;
1658
1772
  return _kubb_core.ast.factory.createSchema({
1659
1773
  type: "intersection",
1660
- members: [memberNode, narrowedDiscriminatorNode ?? _kubb_core.ast.factory.createDiscriminantNode({
1774
+ members: [memberNode, narrowedDiscriminatorNode ?? createDiscriminantNode({
1661
1775
  propertyName: discriminator.propertyName,
1662
1776
  value: discriminatorValue
1663
1777
  })]
@@ -2312,84 +2426,6 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2312
2426
  };
2313
2427
  }
2314
2428
  //#endregion
2315
- //#region src/discriminator.ts
2316
- /**
2317
- * Builds a map of child schema names → discriminator patch data by scanning the given
2318
- * top-level AST schema nodes for union schemas that carry a `discriminatorPropertyName`.
2319
- *
2320
- * The streaming path calls this on a small pre-parsed subset of schemas (only the
2321
- * discriminator parents) rather than on all schemas at once.
2322
- */
2323
- function buildDiscriminatorChildMap(schemas) {
2324
- const childMap = /* @__PURE__ */ new Map();
2325
- for (const schema of schemas) {
2326
- let unionNode = _kubb_core.ast.narrowSchema(schema, "union");
2327
- if (!unionNode) {
2328
- const intersectionMembers = _kubb_core.ast.narrowSchema(schema, "intersection")?.members;
2329
- if (intersectionMembers) for (const m of intersectionMembers) {
2330
- const u = _kubb_core.ast.narrowSchema(m, "union");
2331
- if (u) {
2332
- unionNode = u;
2333
- break;
2334
- }
2335
- }
2336
- }
2337
- if (!unionNode?.discriminatorPropertyName || !unionNode.members) continue;
2338
- const { discriminatorPropertyName, members } = unionNode;
2339
- for (const member of members) {
2340
- const intersectionNode = _kubb_core.ast.narrowSchema(member, "intersection");
2341
- if (!intersectionNode?.members) continue;
2342
- let refNode = null;
2343
- let objNode = null;
2344
- for (const m of intersectionNode.members) {
2345
- refNode ??= _kubb_core.ast.narrowSchema(m, "ref");
2346
- objNode ??= _kubb_core.ast.narrowSchema(m, "object");
2347
- }
2348
- if (!refNode?.name || !objNode) continue;
2349
- const prop = objNode.properties.find((p) => p.name === discriminatorPropertyName);
2350
- const enumNode = prop ? _kubb_core.ast.narrowSchema(prop.schema, "enum") : null;
2351
- if (!enumNode?.enumValues?.length) continue;
2352
- const enumValues = enumNode.enumValues.filter((v) => v !== null);
2353
- if (!enumValues.length) continue;
2354
- const existing = childMap.get(refNode.name);
2355
- if (!existing) {
2356
- childMap.set(refNode.name, {
2357
- propertyName: discriminatorPropertyName,
2358
- enumValues: [...enumValues]
2359
- });
2360
- continue;
2361
- }
2362
- existing.enumValues.push(...enumValues);
2363
- }
2364
- }
2365
- return childMap;
2366
- }
2367
- /**
2368
- * Patches a single top-level `SchemaNode` with its discriminator entry (adds or replaces
2369
- * the discriminant property). Used by the streaming path to apply patches inline per yield
2370
- * without buffering all schemas.
2371
- */
2372
- function patchDiscriminatorNode(node, entry) {
2373
- const objectNode = _kubb_core.ast.narrowSchema(node, "object");
2374
- if (!objectNode) return node;
2375
- const { propertyName, enumValues } = entry;
2376
- const enumSchema = _kubb_core.ast.factory.createSchema({
2377
- type: "enum",
2378
- enumValues
2379
- });
2380
- const newProp = _kubb_core.ast.factory.createProperty({
2381
- name: propertyName,
2382
- required: true,
2383
- schema: enumSchema
2384
- });
2385
- const existingIdx = objectNode.properties.findIndex((p) => p.name === propertyName);
2386
- const newProperties = existingIdx >= 0 ? objectNode.properties.map((p, i) => i === existingIdx ? newProp : p) : [...objectNode.properties, newProp];
2387
- return {
2388
- ...objectNode,
2389
- properties: newProperties
2390
- };
2391
- }
2392
- //#endregion
2393
2429
  //#region src/schemaDiagnostics.ts
2394
2430
  /**
2395
2431
  * Reports the advisory diagnostics (`KUBB_UNSUPPORTED_FORMAT`, `KUBB_DEPRECATED`) for one
@@ -2452,7 +2488,7 @@ function visit(node, pointer) {
2452
2488
  *
2453
2489
  * Only enums and objects are candidates, and object shapes that reference a circular schema are
2454
2490
  * rejected to avoid hoisting recursive structures. Inline shapes reuse their context-derived
2455
- * name (collision-resolved against existing component names); shapes without a name stay inline.
2491
+ * name (collision-resolved against existing component names). Shapes without a name stay inline.
2456
2492
  */
2457
2493
  function createDedupePlan({ schemaNodes, operationNodes, schemaNames, circularNames }) {
2458
2494
  const circularSchemas = new Set(circularNames);