@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 +90 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +13 -0
- package/dist/index.js +90 -13
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/adapter.ts +13 -4
- package/src/parser.ts +16 -0
- package/src/stream.ts +105 -4
- package/src/types.ts +13 -0
package/dist/index.d.ts
CHANGED
|
@@ -476,6 +476,18 @@ type AdapterOasOptions = {
|
|
|
476
476
|
* @default 'strict'
|
|
477
477
|
*/
|
|
478
478
|
discriminator?: 'strict' | 'inherit';
|
|
479
|
+
/**
|
|
480
|
+
* Collapse structurally identical schemas and enums into a single shared definition.
|
|
481
|
+
*
|
|
482
|
+
* Duplicated inline shapes (especially enums repeated across many properties) are hoisted
|
|
483
|
+
* into one named schema; every other occurrence — and any structurally identical top-level
|
|
484
|
+
* component — becomes a `ref` to it. Equality is shape-only: documentation such as
|
|
485
|
+
* `description` and `example` is ignored. Enabled by default; set to `false` to keep every
|
|
486
|
+
* occurrence inline and produce byte-for-byte identical output to earlier versions.
|
|
487
|
+
*
|
|
488
|
+
* @default true
|
|
489
|
+
*/
|
|
490
|
+
dedupe?: boolean;
|
|
479
491
|
} & Partial<ast.ParserOptions>;
|
|
480
492
|
/**
|
|
481
493
|
* Adapter options after defaults have been applied and schema name collisions resolved.
|
|
@@ -486,6 +498,7 @@ type AdapterOasResolvedOptions = {
|
|
|
486
498
|
serverIndex: AdapterOasOptions['serverIndex'];
|
|
487
499
|
serverVariables: AdapterOasOptions['serverVariables'];
|
|
488
500
|
discriminator: NonNullable<AdapterOasOptions['discriminator']>;
|
|
501
|
+
dedupe: NonNullable<AdapterOasOptions['dedupe']>;
|
|
489
502
|
dateType: NonNullable<AdapterOasOptions['dateType']>;
|
|
490
503
|
integerType: NonNullable<AdapterOasOptions['integerType']>;
|
|
491
504
|
unknownType: NonNullable<AdapterOasOptions['unknownType']>;
|
package/dist/index.js
CHANGED
|
@@ -1484,6 +1484,15 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1484
1484
|
}, rawOptions);
|
|
1485
1485
|
const nullInEnum = schema.enum.includes(null);
|
|
1486
1486
|
const filteredValues = nullInEnum ? schema.enum.filter((v) => v !== null) : schema.enum;
|
|
1487
|
+
if (nullInEnum && filteredValues.length === 0) return ast.createSchema({
|
|
1488
|
+
type: "null",
|
|
1489
|
+
primitive: "null",
|
|
1490
|
+
name,
|
|
1491
|
+
title: schema.title,
|
|
1492
|
+
description: schema.description,
|
|
1493
|
+
deprecated: schema.deprecated,
|
|
1494
|
+
format: schema.format
|
|
1495
|
+
});
|
|
1487
1496
|
const enumNullable = nullable || nullInEnum || void 0;
|
|
1488
1497
|
const enumDefault = schema.default === null && enumNullable ? void 0 : schema.default;
|
|
1489
1498
|
const enumPrimitive = getPrimitiveType(type);
|
|
@@ -2065,6 +2074,36 @@ function patchDiscriminatorNode(node, entry) {
|
|
|
2065
2074
|
//#endregion
|
|
2066
2075
|
//#region src/stream.ts
|
|
2067
2076
|
/**
|
|
2077
|
+
* Builds the deduplication plan from the already-parsed top-level schema nodes plus a
|
|
2078
|
+
* single extra parse pass over operations (so duplicates in request/response bodies are seen).
|
|
2079
|
+
*
|
|
2080
|
+
* Only enums and objects are candidates, and object shapes that reference a circular schema are
|
|
2081
|
+
* rejected to avoid hoisting recursive structures. Inline shapes reuse their context-derived
|
|
2082
|
+
* name (collision-resolved against existing component names); shapes without a name stay inline.
|
|
2083
|
+
*/
|
|
2084
|
+
function createDedupePlan({ schemaNodes, operationNodes, schemaNames, circularNames }) {
|
|
2085
|
+
const circularSchemas = new Set(circularNames);
|
|
2086
|
+
const usedNames = new Set(schemaNames);
|
|
2087
|
+
return ast.buildDedupePlan([...schemaNodes, ...operationNodes], {
|
|
2088
|
+
isCandidate: (node) => {
|
|
2089
|
+
if (node.type === "enum") return true;
|
|
2090
|
+
if (node.type !== "object") return false;
|
|
2091
|
+
if (node.name && circularSchemas.has(node.name)) return false;
|
|
2092
|
+
return !ast.containsCircularRef(node, { circularSchemas });
|
|
2093
|
+
},
|
|
2094
|
+
nameFor: (node) => {
|
|
2095
|
+
const base = node.name;
|
|
2096
|
+
if (!base) return null;
|
|
2097
|
+
let name = base;
|
|
2098
|
+
let counter = 2;
|
|
2099
|
+
while (usedNames.has(name)) name = `${base}${counter++}`;
|
|
2100
|
+
usedNames.add(name);
|
|
2101
|
+
return name;
|
|
2102
|
+
},
|
|
2103
|
+
refFor: (name) => `${SCHEMA_REF_PREFIX}${name}`
|
|
2104
|
+
});
|
|
2105
|
+
}
|
|
2106
|
+
/**
|
|
2068
2107
|
* Reads the server URL from the document's `servers` array at `serverIndex`,
|
|
2069
2108
|
* interpolating any `serverVariables` into the URL template.
|
|
2070
2109
|
*
|
|
@@ -2105,7 +2144,7 @@ function resolveBaseUrl({ document, serverIndex, serverVariables }) {
|
|
|
2105
2144
|
* })
|
|
2106
2145
|
* ```
|
|
2107
2146
|
*/
|
|
2108
|
-
function preScan({ schemas, parseSchema, parserOptions, discriminator }) {
|
|
2147
|
+
function preScan({ schemas, parseSchema, parseOperation, baseOas, parserOptions, discriminator, dedupe }) {
|
|
2109
2148
|
const allNodes = [];
|
|
2110
2149
|
const refAliasMap = /* @__PURE__ */ new Map();
|
|
2111
2150
|
const enumNames = [];
|
|
@@ -2120,11 +2159,30 @@ function preScan({ schemas, parseSchema, parserOptions, discriminator }) {
|
|
|
2120
2159
|
if (ast.narrowSchema(node, ast.schemaTypes.enum) && node.name) enumNames.push(node.name);
|
|
2121
2160
|
if (discriminator === "inherit" && (schema.oneOf ?? schema.anyOf) && schema.discriminator?.propertyName) discriminatorParentNodes.push(node);
|
|
2122
2161
|
}
|
|
2162
|
+
const circularNames = [...ast.findCircularSchemas(allNodes)];
|
|
2163
|
+
const discriminatorChildMap = discriminatorParentNodes.length > 0 ? buildDiscriminatorChildMap(discriminatorParentNodes) : null;
|
|
2164
|
+
let dedupePlan = null;
|
|
2165
|
+
if (dedupe) {
|
|
2166
|
+
const operationNodes = [];
|
|
2167
|
+
for (const methods of Object.values(baseOas.getPaths())) for (const operation of Object.values(methods)) {
|
|
2168
|
+
if (!operation) continue;
|
|
2169
|
+
const operationNode = parseOperation(parserOptions, operation);
|
|
2170
|
+
if (operationNode) operationNodes.push(operationNode);
|
|
2171
|
+
}
|
|
2172
|
+
dedupePlan = createDedupePlan({
|
|
2173
|
+
schemaNodes: allNodes,
|
|
2174
|
+
operationNodes,
|
|
2175
|
+
schemaNames: Object.keys(schemas),
|
|
2176
|
+
circularNames
|
|
2177
|
+
});
|
|
2178
|
+
for (const definition of dedupePlan.hoisted) if (definition.type === "enum" && definition.name) enumNames.push(definition.name);
|
|
2179
|
+
}
|
|
2123
2180
|
return {
|
|
2124
2181
|
refAliasMap,
|
|
2125
2182
|
enumNames,
|
|
2126
|
-
circularNames
|
|
2127
|
-
discriminatorChildMap
|
|
2183
|
+
circularNames,
|
|
2184
|
+
discriminatorChildMap,
|
|
2185
|
+
dedupePlan
|
|
2128
2186
|
};
|
|
2129
2187
|
}
|
|
2130
2188
|
/**
|
|
@@ -2145,26 +2203,39 @@ function preScan({ schemas, parseSchema, parserOptions, discriminator }) {
|
|
|
2145
2203
|
* }
|
|
2146
2204
|
* ```
|
|
2147
2205
|
*/
|
|
2148
|
-
function createInputStream({ schemas, parseSchema, parseOperation, baseOas, parserOptions, refAliasMap, discriminatorChildMap, meta }) {
|
|
2206
|
+
function createInputStream({ schemas, parseSchema, parseOperation, baseOas, parserOptions, refAliasMap, discriminatorChildMap, dedupePlan, meta }) {
|
|
2207
|
+
const rewriteTopLevelSchema = (node) => {
|
|
2208
|
+
if (!dedupePlan) return node;
|
|
2209
|
+
const canonical = dedupePlan.canonicalBySignature.get(ast.schemaSignature(node));
|
|
2210
|
+
if (canonical && canonical.name !== node.name) return ast.createSchema({
|
|
2211
|
+
type: "ref",
|
|
2212
|
+
name: node.name ?? null,
|
|
2213
|
+
ref: canonical.ref,
|
|
2214
|
+
description: node.description,
|
|
2215
|
+
deprecated: node.deprecated
|
|
2216
|
+
});
|
|
2217
|
+
return ast.applyDedupe(node, dedupePlan.canonicalBySignature, true);
|
|
2218
|
+
};
|
|
2149
2219
|
const schemasIterable = { [Symbol.asyncIterator]() {
|
|
2150
2220
|
return (async function* () {
|
|
2221
|
+
if (dedupePlan) for (const definition of dedupePlan.hoisted) yield definition;
|
|
2151
2222
|
for (const [name, schema] of Object.entries(schemas)) {
|
|
2152
2223
|
const alias = refAliasMap.get(name);
|
|
2153
2224
|
if (alias?.name && schemas[alias.name]) {
|
|
2154
|
-
yield {
|
|
2225
|
+
yield rewriteTopLevelSchema({
|
|
2155
2226
|
...parseSchema({
|
|
2156
2227
|
schema: schemas[alias.name],
|
|
2157
2228
|
name: alias.name
|
|
2158
2229
|
}, parserOptions),
|
|
2159
2230
|
name
|
|
2160
|
-
};
|
|
2231
|
+
});
|
|
2161
2232
|
continue;
|
|
2162
2233
|
}
|
|
2163
2234
|
const parsed = parseSchema({
|
|
2164
2235
|
schema,
|
|
2165
2236
|
name
|
|
2166
2237
|
}, parserOptions);
|
|
2167
|
-
yield discriminatorChildMap?.get(name) ? patchDiscriminatorNode(parsed, discriminatorChildMap.get(name)) : parsed;
|
|
2238
|
+
yield rewriteTopLevelSchema(discriminatorChildMap?.get(name) ? patchDiscriminatorNode(parsed, discriminatorChildMap.get(name)) : parsed);
|
|
2168
2239
|
}
|
|
2169
2240
|
})();
|
|
2170
2241
|
} };
|
|
@@ -2173,7 +2244,7 @@ function createInputStream({ schemas, parseSchema, parseOperation, baseOas, pars
|
|
|
2173
2244
|
for (const methods of Object.values(baseOas.getPaths())) for (const operation of Object.values(methods)) {
|
|
2174
2245
|
if (!operation) continue;
|
|
2175
2246
|
const node = parseOperation(parserOptions, operation);
|
|
2176
|
-
if (node) yield node;
|
|
2247
|
+
if (node) yield dedupePlan ? ast.applyDedupe(node, dedupePlan.canonicalBySignature) : node;
|
|
2177
2248
|
}
|
|
2178
2249
|
})();
|
|
2179
2250
|
} };
|
|
@@ -2213,7 +2284,7 @@ const adapterOasName = "oas";
|
|
|
2213
2284
|
* ```
|
|
2214
2285
|
*/
|
|
2215
2286
|
const adapterOas = createAdapter((options) => {
|
|
2216
|
-
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;
|
|
2287
|
+
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;
|
|
2217
2288
|
const parserOptions = {
|
|
2218
2289
|
...DEFAULT_PARSER_OPTIONS,
|
|
2219
2290
|
dateType,
|
|
@@ -2240,25 +2311,30 @@ const adapterOas = createAdapter((options) => {
|
|
|
2240
2311
|
document,
|
|
2241
2312
|
contentType
|
|
2242
2313
|
}));
|
|
2243
|
-
const ensurePreScan = once((schemas, parseSchema) => preScan({
|
|
2314
|
+
const ensurePreScan = once((schemas, parseSchema, parseOperation, baseOas) => preScan({
|
|
2244
2315
|
schemas,
|
|
2245
2316
|
parseSchema,
|
|
2317
|
+
parseOperation,
|
|
2318
|
+
baseOas,
|
|
2246
2319
|
parserOptions,
|
|
2247
|
-
discriminator
|
|
2320
|
+
discriminator,
|
|
2321
|
+
dedupe
|
|
2248
2322
|
}));
|
|
2249
2323
|
async function createStream(source) {
|
|
2250
2324
|
const document = await ensureDocument(source);
|
|
2251
2325
|
const schemas = await ensureSchemas(document);
|
|
2252
2326
|
const { parseSchema, parseOperation } = ensureSchemaParser(document);
|
|
2253
|
-
const
|
|
2327
|
+
const baseOas = ensureBaseOas(document);
|
|
2328
|
+
const { refAliasMap, enumNames, circularNames, discriminatorChildMap, dedupePlan } = ensurePreScan(schemas, parseSchema, parseOperation, baseOas);
|
|
2254
2329
|
return createInputStream({
|
|
2255
2330
|
schemas,
|
|
2256
2331
|
parseSchema,
|
|
2257
2332
|
parseOperation,
|
|
2258
|
-
baseOas
|
|
2333
|
+
baseOas,
|
|
2259
2334
|
parserOptions,
|
|
2260
2335
|
refAliasMap,
|
|
2261
2336
|
discriminatorChildMap,
|
|
2337
|
+
dedupePlan,
|
|
2262
2338
|
meta: {
|
|
2263
2339
|
title: document.info?.title,
|
|
2264
2340
|
description: document.info?.description,
|
|
@@ -2282,6 +2358,7 @@ const adapterOas = createAdapter((options) => {
|
|
|
2282
2358
|
serverIndex,
|
|
2283
2359
|
serverVariables,
|
|
2284
2360
|
discriminator,
|
|
2361
|
+
dedupe,
|
|
2285
2362
|
dateType,
|
|
2286
2363
|
integerType,
|
|
2287
2364
|
unknownType,
|