@kubb/adapter-oas 5.0.0-beta.30 → 5.0.0-beta.31

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
@@ -1510,6 +1510,15 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1510
1510
  }, rawOptions);
1511
1511
  const nullInEnum = schema.enum.includes(null);
1512
1512
  const filteredValues = nullInEnum ? schema.enum.filter((v) => v !== null) : schema.enum;
1513
+ if (nullInEnum && filteredValues.length === 0) return _kubb_core.ast.createSchema({
1514
+ type: "null",
1515
+ primitive: "null",
1516
+ name,
1517
+ title: schema.title,
1518
+ description: schema.description,
1519
+ deprecated: schema.deprecated,
1520
+ format: schema.format
1521
+ });
1513
1522
  const enumNullable = nullable || nullInEnum || void 0;
1514
1523
  const enumDefault = schema.default === null && enumNullable ? void 0 : schema.default;
1515
1524
  const enumPrimitive = getPrimitiveType(type);
@@ -2091,6 +2100,36 @@ function patchDiscriminatorNode(node, entry) {
2091
2100
  //#endregion
2092
2101
  //#region src/stream.ts
2093
2102
  /**
2103
+ * Builds the deduplication plan from the already-parsed top-level schema nodes plus a
2104
+ * single extra parse pass over operations (so duplicates in request/response bodies are seen).
2105
+ *
2106
+ * Only enums and objects are candidates, and object shapes that reference a circular schema are
2107
+ * rejected to avoid hoisting recursive structures. Inline shapes reuse their context-derived
2108
+ * name (collision-resolved against existing component names); shapes without a name stay inline.
2109
+ */
2110
+ function createDedupePlan({ schemaNodes, operationNodes, schemaNames, circularNames }) {
2111
+ const circularSchemas = new Set(circularNames);
2112
+ const usedNames = new Set(schemaNames);
2113
+ return _kubb_core.ast.buildDedupePlan([...schemaNodes, ...operationNodes], {
2114
+ isCandidate: (node) => {
2115
+ if (node.type === "enum") return true;
2116
+ if (node.type !== "object") return false;
2117
+ if (node.name && circularSchemas.has(node.name)) return false;
2118
+ return !_kubb_core.ast.containsCircularRef(node, { circularSchemas });
2119
+ },
2120
+ nameFor: (node) => {
2121
+ const base = node.name;
2122
+ if (!base) return null;
2123
+ let name = base;
2124
+ let counter = 2;
2125
+ while (usedNames.has(name)) name = `${base}${counter++}`;
2126
+ usedNames.add(name);
2127
+ return name;
2128
+ },
2129
+ refFor: (name) => `${SCHEMA_REF_PREFIX}${name}`
2130
+ });
2131
+ }
2132
+ /**
2094
2133
  * Reads the server URL from the document's `servers` array at `serverIndex`,
2095
2134
  * interpolating any `serverVariables` into the URL template.
2096
2135
  *
@@ -2131,7 +2170,7 @@ function resolveBaseUrl({ document, serverIndex, serverVariables }) {
2131
2170
  * })
2132
2171
  * ```
2133
2172
  */
2134
- function preScan({ schemas, parseSchema, parserOptions, discriminator }) {
2173
+ function preScan({ schemas, parseSchema, parseOperation, baseOas, parserOptions, discriminator, dedupe }) {
2135
2174
  const allNodes = [];
2136
2175
  const refAliasMap = /* @__PURE__ */ new Map();
2137
2176
  const enumNames = [];
@@ -2146,11 +2185,30 @@ function preScan({ schemas, parseSchema, parserOptions, discriminator }) {
2146
2185
  if (_kubb_core.ast.narrowSchema(node, _kubb_core.ast.schemaTypes.enum) && node.name) enumNames.push(node.name);
2147
2186
  if (discriminator === "inherit" && (schema.oneOf ?? schema.anyOf) && schema.discriminator?.propertyName) discriminatorParentNodes.push(node);
2148
2187
  }
2188
+ const circularNames = [..._kubb_core.ast.findCircularSchemas(allNodes)];
2189
+ const discriminatorChildMap = discriminatorParentNodes.length > 0 ? buildDiscriminatorChildMap(discriminatorParentNodes) : null;
2190
+ let dedupePlan = null;
2191
+ if (dedupe) {
2192
+ const operationNodes = [];
2193
+ for (const methods of Object.values(baseOas.getPaths())) for (const operation of Object.values(methods)) {
2194
+ if (!operation) continue;
2195
+ const operationNode = parseOperation(parserOptions, operation);
2196
+ if (operationNode) operationNodes.push(operationNode);
2197
+ }
2198
+ dedupePlan = createDedupePlan({
2199
+ schemaNodes: allNodes,
2200
+ operationNodes,
2201
+ schemaNames: Object.keys(schemas),
2202
+ circularNames
2203
+ });
2204
+ for (const definition of dedupePlan.hoisted) if (definition.type === "enum" && definition.name) enumNames.push(definition.name);
2205
+ }
2149
2206
  return {
2150
2207
  refAliasMap,
2151
2208
  enumNames,
2152
- circularNames: [..._kubb_core.ast.findCircularSchemas(allNodes)],
2153
- discriminatorChildMap: discriminatorParentNodes.length > 0 ? buildDiscriminatorChildMap(discriminatorParentNodes) : null
2209
+ circularNames,
2210
+ discriminatorChildMap,
2211
+ dedupePlan
2154
2212
  };
2155
2213
  }
2156
2214
  /**
@@ -2171,26 +2229,39 @@ function preScan({ schemas, parseSchema, parserOptions, discriminator }) {
2171
2229
  * }
2172
2230
  * ```
2173
2231
  */
2174
- function createInputStream({ schemas, parseSchema, parseOperation, baseOas, parserOptions, refAliasMap, discriminatorChildMap, meta }) {
2232
+ function createInputStream({ schemas, parseSchema, parseOperation, baseOas, parserOptions, refAliasMap, discriminatorChildMap, dedupePlan, meta }) {
2233
+ const rewriteTopLevelSchema = (node) => {
2234
+ if (!dedupePlan) return node;
2235
+ const canonical = dedupePlan.canonicalBySignature.get(_kubb_core.ast.schemaSignature(node));
2236
+ if (canonical && canonical.name !== node.name) return _kubb_core.ast.createSchema({
2237
+ type: "ref",
2238
+ name: node.name ?? null,
2239
+ ref: canonical.ref,
2240
+ description: node.description,
2241
+ deprecated: node.deprecated
2242
+ });
2243
+ return _kubb_core.ast.applyDedupe(node, dedupePlan.canonicalBySignature, true);
2244
+ };
2175
2245
  const schemasIterable = { [Symbol.asyncIterator]() {
2176
2246
  return (async function* () {
2247
+ if (dedupePlan) for (const definition of dedupePlan.hoisted) yield definition;
2177
2248
  for (const [name, schema] of Object.entries(schemas)) {
2178
2249
  const alias = refAliasMap.get(name);
2179
2250
  if (alias?.name && schemas[alias.name]) {
2180
- yield {
2251
+ yield rewriteTopLevelSchema({
2181
2252
  ...parseSchema({
2182
2253
  schema: schemas[alias.name],
2183
2254
  name: alias.name
2184
2255
  }, parserOptions),
2185
2256
  name
2186
- };
2257
+ });
2187
2258
  continue;
2188
2259
  }
2189
2260
  const parsed = parseSchema({
2190
2261
  schema,
2191
2262
  name
2192
2263
  }, parserOptions);
2193
- yield discriminatorChildMap?.get(name) ? patchDiscriminatorNode(parsed, discriminatorChildMap.get(name)) : parsed;
2264
+ yield rewriteTopLevelSchema(discriminatorChildMap?.get(name) ? patchDiscriminatorNode(parsed, discriminatorChildMap.get(name)) : parsed);
2194
2265
  }
2195
2266
  })();
2196
2267
  } };
@@ -2199,7 +2270,7 @@ function createInputStream({ schemas, parseSchema, parseOperation, baseOas, pars
2199
2270
  for (const methods of Object.values(baseOas.getPaths())) for (const operation of Object.values(methods)) {
2200
2271
  if (!operation) continue;
2201
2272
  const node = parseOperation(parserOptions, operation);
2202
- if (node) yield node;
2273
+ if (node) yield dedupePlan ? _kubb_core.ast.applyDedupe(node, dedupePlan.canonicalBySignature) : node;
2203
2274
  }
2204
2275
  })();
2205
2276
  } };
@@ -2239,7 +2310,7 @@ const adapterOasName = "oas";
2239
2310
  * ```
2240
2311
  */
2241
2312
  const adapterOas = (0, _kubb_core.createAdapter)((options) => {
2242
- const { validate = true, contentType, serverIndex, serverVariables, discriminator = "strict", dateType = DEFAULT_PARSER_OPTIONS.dateType, integerType = DEFAULT_PARSER_OPTIONS.integerType, unknownType = DEFAULT_PARSER_OPTIONS.unknownType, enumSuffix = DEFAULT_PARSER_OPTIONS.enumSuffix, emptySchemaType = unknownType || DEFAULT_PARSER_OPTIONS.emptySchemaType } = options;
2313
+ const { validate = true, contentType, serverIndex, serverVariables, discriminator = "strict", dedupe = true, dateType = DEFAULT_PARSER_OPTIONS.dateType, integerType = DEFAULT_PARSER_OPTIONS.integerType, unknownType = DEFAULT_PARSER_OPTIONS.unknownType, enumSuffix = DEFAULT_PARSER_OPTIONS.enumSuffix, emptySchemaType = unknownType || DEFAULT_PARSER_OPTIONS.emptySchemaType } = options;
2243
2314
  const parserOptions = {
2244
2315
  ...DEFAULT_PARSER_OPTIONS,
2245
2316
  dateType,
@@ -2266,25 +2337,30 @@ const adapterOas = (0, _kubb_core.createAdapter)((options) => {
2266
2337
  document,
2267
2338
  contentType
2268
2339
  }));
2269
- const ensurePreScan = once((schemas, parseSchema) => preScan({
2340
+ const ensurePreScan = once((schemas, parseSchema, parseOperation, baseOas) => preScan({
2270
2341
  schemas,
2271
2342
  parseSchema,
2343
+ parseOperation,
2344
+ baseOas,
2272
2345
  parserOptions,
2273
- discriminator
2346
+ discriminator,
2347
+ dedupe
2274
2348
  }));
2275
2349
  async function createStream(source) {
2276
2350
  const document = await ensureDocument(source);
2277
2351
  const schemas = await ensureSchemas(document);
2278
2352
  const { parseSchema, parseOperation } = ensureSchemaParser(document);
2279
- const { refAliasMap, enumNames, circularNames, discriminatorChildMap } = ensurePreScan(schemas, parseSchema);
2353
+ const baseOas = ensureBaseOas(document);
2354
+ const { refAliasMap, enumNames, circularNames, discriminatorChildMap, dedupePlan } = ensurePreScan(schemas, parseSchema, parseOperation, baseOas);
2280
2355
  return createInputStream({
2281
2356
  schemas,
2282
2357
  parseSchema,
2283
2358
  parseOperation,
2284
- baseOas: ensureBaseOas(document),
2359
+ baseOas,
2285
2360
  parserOptions,
2286
2361
  refAliasMap,
2287
2362
  discriminatorChildMap,
2363
+ dedupePlan,
2288
2364
  meta: {
2289
2365
  title: document.info?.title,
2290
2366
  description: document.info?.description,
@@ -2308,6 +2384,7 @@ const adapterOas = (0, _kubb_core.createAdapter)((options) => {
2308
2384
  serverIndex,
2309
2385
  serverVariables,
2310
2386
  discriminator,
2387
+ dedupe,
2311
2388
  dateType,
2312
2389
  integerType,
2313
2390
  unknownType,