@kubb/adapter-oas 5.0.0-beta.67 → 5.0.0-beta.69
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 +80 -203
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +38 -33
- package/dist/index.js +81 -204
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.d.ts
CHANGED
|
@@ -1162,6 +1162,22 @@ type ResponseObject$1 = OpenAPIV3_1.ResponseObject;
|
|
|
1162
1162
|
* OpenAPI media type object that maps a content-type string to its schema.
|
|
1163
1163
|
*/
|
|
1164
1164
|
type MediaTypeObject$1 = OpenAPIV3_1.MediaTypeObject;
|
|
1165
|
+
/**
|
|
1166
|
+
* Selects which entry in the spec's `servers` array becomes the base URL and
|
|
1167
|
+
* supplies values for its `{variable}` placeholders.
|
|
1168
|
+
*/
|
|
1169
|
+
type ServerOptions = {
|
|
1170
|
+
/**
|
|
1171
|
+
* Index into the `servers` array from your OpenAPI spec. Most projects pick
|
|
1172
|
+
* `0` for the primary server. Omit to leave `baseURL` undefined.
|
|
1173
|
+
*/
|
|
1174
|
+
index?: number;
|
|
1175
|
+
/**
|
|
1176
|
+
* Override values for `{variable}` placeholders in the selected server URL.
|
|
1177
|
+
* Variables you do not provide use their `default` value from the spec.
|
|
1178
|
+
*/
|
|
1179
|
+
variables?: Record<string, string>;
|
|
1180
|
+
};
|
|
1165
1181
|
/**
|
|
1166
1182
|
* Configuration for the OpenAPI adapter: spec validation, content-type selection,
|
|
1167
1183
|
* server URL resolution, and how schema types are derived.
|
|
@@ -1171,8 +1187,7 @@ type MediaTypeObject$1 = OpenAPIV3_1.MediaTypeObject;
|
|
|
1171
1187
|
* adapterOas({
|
|
1172
1188
|
* validate: false,
|
|
1173
1189
|
* dateType: 'date',
|
|
1174
|
-
*
|
|
1175
|
-
* serverVariables: { env: 'prod' },
|
|
1190
|
+
* server: { index: 0, variables: { env: 'prod' } },
|
|
1176
1191
|
* })
|
|
1177
1192
|
* ```
|
|
1178
1193
|
*/
|
|
@@ -1191,47 +1206,38 @@ type AdapterOasOptions = {
|
|
|
1191
1206
|
*/
|
|
1192
1207
|
contentType?: ContentType;
|
|
1193
1208
|
/**
|
|
1194
|
-
*
|
|
1195
|
-
*
|
|
1196
|
-
*
|
|
1197
|
-
*/
|
|
1198
|
-
serverIndex?: number;
|
|
1199
|
-
/**
|
|
1200
|
-
* Override values for `{variable}` placeholders in the selected server URL.
|
|
1201
|
-
* Only used when `serverIndex` is set. Variables you do not provide use
|
|
1202
|
-
* their `default` value from the spec.
|
|
1209
|
+
* Selects the server entry used to compute the base URL for plugins that need
|
|
1210
|
+
* it, and overrides its `{variable}` placeholders. Omit to leave `baseURL`
|
|
1211
|
+
* undefined.
|
|
1203
1212
|
*
|
|
1204
1213
|
* @example
|
|
1205
1214
|
* ```ts
|
|
1206
1215
|
* // spec server: "https://api.{env}.example.com"
|
|
1207
|
-
*
|
|
1216
|
+
* server: { index: 0, variables: { env: 'prod' } }
|
|
1208
1217
|
* // → baseURL: "https://api.prod.example.com"
|
|
1209
1218
|
* ```
|
|
1210
1219
|
*/
|
|
1211
|
-
|
|
1220
|
+
server?: ServerOptions;
|
|
1212
1221
|
/**
|
|
1213
1222
|
* How the `discriminator` field on `oneOf`/`anyOf` schemas is interpreted.
|
|
1214
|
-
* - `'
|
|
1223
|
+
* - `'preserve'` child schemas stay exactly as written. The discriminator
|
|
1215
1224
|
* narrows types at the call site but child shapes are not modified.
|
|
1216
|
-
* - `'
|
|
1217
|
-
*
|
|
1218
|
-
*
|
|
1225
|
+
* - `'propagate'` Kubb pushes the discriminator property as a literal value
|
|
1226
|
+
* into each child schema, so each branch's discriminator field is precisely
|
|
1227
|
+
* typed.
|
|
1219
1228
|
*
|
|
1220
|
-
* @default '
|
|
1229
|
+
* @default 'preserve'
|
|
1221
1230
|
*/
|
|
1222
|
-
discriminator?: '
|
|
1231
|
+
discriminator?: 'preserve' | 'propagate';
|
|
1223
1232
|
/**
|
|
1224
|
-
*
|
|
1225
|
-
*
|
|
1226
|
-
*
|
|
1227
|
-
*
|
|
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
|
+
* Where inline enums live.
|
|
1234
|
+
* - `'inline'` keeps each enum inline on the property that declares it.
|
|
1235
|
+
* - `'root'` lifts every inline enum to a reusable top-level schema named after its context
|
|
1236
|
+
* (e.g. `PetStatusEnum`) and references it everywhere it appears.
|
|
1231
1237
|
*
|
|
1232
|
-
* @default
|
|
1238
|
+
* @default 'inline'
|
|
1233
1239
|
*/
|
|
1234
|
-
|
|
1240
|
+
enums?: 'inline' | 'root';
|
|
1235
1241
|
} & Partial<ast.ParserOptions>;
|
|
1236
1242
|
/**
|
|
1237
1243
|
* Adapter options after defaults have been applied and schema name collisions resolved.
|
|
@@ -1239,10 +1245,9 @@ type AdapterOasOptions = {
|
|
|
1239
1245
|
type AdapterOasResolvedOptions = {
|
|
1240
1246
|
validate: boolean;
|
|
1241
1247
|
contentType: AdapterOasOptions['contentType'];
|
|
1242
|
-
|
|
1243
|
-
serverVariables: AdapterOasOptions['serverVariables'];
|
|
1248
|
+
server: AdapterOasOptions['server'];
|
|
1244
1249
|
discriminator: NonNullable<AdapterOasOptions['discriminator']>;
|
|
1245
|
-
|
|
1250
|
+
enums: NonNullable<AdapterOasOptions['enums']>;
|
|
1246
1251
|
dateType: NonNullable<AdapterOasOptions['dateType']>;
|
|
1247
1252
|
integerType: NonNullable<AdapterOasOptions['integerType']>;
|
|
1248
1253
|
unknownType: NonNullable<AdapterOasOptions['unknownType']>;
|
|
@@ -1289,8 +1294,8 @@ declare const adapterOasName = "oas";
|
|
|
1289
1294
|
* input: { path: './petStore.yaml' },
|
|
1290
1295
|
* output: { path: './src/gen' },
|
|
1291
1296
|
* adapter: adapterOas({
|
|
1292
|
-
*
|
|
1293
|
-
* discriminator: '
|
|
1297
|
+
* server: { index: 0 },
|
|
1298
|
+
* discriminator: 'propagate',
|
|
1294
1299
|
* dateType: 'date',
|
|
1295
1300
|
* }),
|
|
1296
1301
|
* plugins: [pluginTs()],
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { upgrade } from "@scalar/openapi-upgrader";
|
|
|
7
7
|
import { parse } from "yaml";
|
|
8
8
|
import { bundle } from "api-ref-bundler";
|
|
9
9
|
import { macroDiscriminatorEnum, macroEnumName, macroSimplifyUnion } from "@kubb/ast/macros";
|
|
10
|
-
import { childName,
|
|
10
|
+
import { childName, enumPropName, extractRefName, findCircularSchemas, mergeAdjacentObjectsLazy } from "@kubb/ast/utils";
|
|
11
11
|
import { collect, narrowSchema } from "@kubb/ast";
|
|
12
12
|
//#region src/constants.ts
|
|
13
13
|
/**
|
|
@@ -589,168 +589,6 @@ async function validateDocument(document, { throwOnError = false } = {}) {
|
|
|
589
589
|
}
|
|
590
590
|
}
|
|
591
591
|
//#endregion
|
|
592
|
-
//#region src/dedupe.ts
|
|
593
|
-
/**
|
|
594
|
-
* Minimum occurrences before a shape is deduplicated.
|
|
595
|
-
*/
|
|
596
|
-
const MIN_OCCURRENCES = 2;
|
|
597
|
-
/**
|
|
598
|
-
* Builds the shared `ref` replacement for a duplicate occurrence, carrying the
|
|
599
|
-
* usage-slot and documentation fields that are not part of the shared type.
|
|
600
|
-
*/
|
|
601
|
-
function createRefNode(node, target) {
|
|
602
|
-
return ast.factory.createSchema({
|
|
603
|
-
type: "ref",
|
|
604
|
-
name: target.name,
|
|
605
|
-
ref: target.ref,
|
|
606
|
-
optional: node.optional,
|
|
607
|
-
nullish: node.nullish,
|
|
608
|
-
readOnly: node.readOnly,
|
|
609
|
-
writeOnly: node.writeOnly,
|
|
610
|
-
deprecated: node.deprecated,
|
|
611
|
-
description: node.description,
|
|
612
|
-
default: node.default,
|
|
613
|
-
examples: node.examples
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
/**
|
|
617
|
-
* Strips usage-slot flags from an extracted definition and applies its name.
|
|
618
|
-
* A standalone definition is never optional, so `optional`/`nullish` are cleared.
|
|
619
|
-
*/
|
|
620
|
-
function cleanDefinition(node, name) {
|
|
621
|
-
return {
|
|
622
|
-
...node,
|
|
623
|
-
name,
|
|
624
|
-
optional: void 0,
|
|
625
|
-
nullish: void 0
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
/**
|
|
629
|
-
* Returns `true` when a node is eligible for deduplication. Only enums and objects qualify, and
|
|
630
|
-
* object shapes that take part in a circular chain are rejected so recursive structures are not
|
|
631
|
-
* extracted (which would break the cycle).
|
|
632
|
-
*/
|
|
633
|
-
function isCandidate(node, circularSchemas) {
|
|
634
|
-
if (node.type === "enum") return true;
|
|
635
|
-
if (node.type !== "object") return false;
|
|
636
|
-
if (node.name && circularSchemas.has(node.name)) return false;
|
|
637
|
-
return !containsCircularRef(node, { circularSchemas });
|
|
638
|
-
}
|
|
639
|
-
/**
|
|
640
|
-
* Produces the name for an inline shape with no existing named component, resolving
|
|
641
|
-
* collisions against `usedNames`. Returns `null` for an unnamed shape, which stays inline.
|
|
642
|
-
*/
|
|
643
|
-
function nameFor(node, usedNames) {
|
|
644
|
-
const base = node.name;
|
|
645
|
-
if (!base) return null;
|
|
646
|
-
let name = base;
|
|
647
|
-
let counter = 2;
|
|
648
|
-
while (usedNames.has(name)) name = `${base}${counter++}`;
|
|
649
|
-
usedNames.add(name);
|
|
650
|
-
return name;
|
|
651
|
-
}
|
|
652
|
-
/**
|
|
653
|
-
* Scans a forest of schema and operation nodes and produces a {@link Plan}.
|
|
654
|
-
*
|
|
655
|
-
* A shape that occurs at least {@link MIN_OCCURRENCES} times is deduplicated: if any occurrence is
|
|
656
|
-
* a named top-level schema, the first one becomes the target (so other top-level duplicates and
|
|
657
|
-
* inline copies turn into references to it). Other top-level names with the same content are
|
|
658
|
-
* recorded as aliases. Otherwise a new definition is extracted using {@link nameFor}. The returned
|
|
659
|
-
* plan rewrites nodes against those decisions.
|
|
660
|
-
*
|
|
661
|
-
* @example
|
|
662
|
-
* ```ts
|
|
663
|
-
* const dedupePlan = plan([...schemaNodes, ...operationNodes], { circularSchemas, usedNames })
|
|
664
|
-
* ```
|
|
665
|
-
*/
|
|
666
|
-
function plan(roots, context) {
|
|
667
|
-
const { circularSchemas, usedNames } = context;
|
|
668
|
-
const topLevelNodes = /* @__PURE__ */ new Set();
|
|
669
|
-
const groups = /* @__PURE__ */ new Map();
|
|
670
|
-
for (const root of roots) {
|
|
671
|
-
if (root.kind === "Schema") topLevelNodes.add(root);
|
|
672
|
-
for (const schemaNode of ast.collect(root, { schema: (node) => node })) {
|
|
673
|
-
if (!isCandidate(schemaNode, circularSchemas)) continue;
|
|
674
|
-
const signature = ast.signatureOf(schemaNode);
|
|
675
|
-
const isTopLevel = topLevelNodes.has(schemaNode) && !!schemaNode.name;
|
|
676
|
-
const group = groups.get(signature);
|
|
677
|
-
if (group) {
|
|
678
|
-
group.count++;
|
|
679
|
-
if (isTopLevel) group.topLevelNames.push(schemaNode.name);
|
|
680
|
-
} else groups.set(signature, {
|
|
681
|
-
count: 1,
|
|
682
|
-
representative: schemaNode,
|
|
683
|
-
topLevelNames: isTopLevel ? [schemaNode.name] : []
|
|
684
|
-
});
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
const bySignature = /* @__PURE__ */ new Map();
|
|
688
|
-
const byName = /* @__PURE__ */ new Map();
|
|
689
|
-
const pendingExtractions = [];
|
|
690
|
-
for (const [signature, group] of groups) {
|
|
691
|
-
if (group.count < MIN_OCCURRENCES) continue;
|
|
692
|
-
const [firstName, ...duplicateNames] = group.topLevelNames;
|
|
693
|
-
if (firstName) {
|
|
694
|
-
const target = {
|
|
695
|
-
name: firstName,
|
|
696
|
-
ref: `${SCHEMA_REF_PREFIX}${firstName}`
|
|
697
|
-
};
|
|
698
|
-
bySignature.set(signature, target);
|
|
699
|
-
for (const duplicate of duplicateNames) byName.set(duplicate, target);
|
|
700
|
-
continue;
|
|
701
|
-
}
|
|
702
|
-
const name = nameFor(group.representative, usedNames);
|
|
703
|
-
if (!name) continue;
|
|
704
|
-
bySignature.set(signature, {
|
|
705
|
-
name,
|
|
706
|
-
ref: `${SCHEMA_REF_PREFIX}${name}`
|
|
707
|
-
});
|
|
708
|
-
pendingExtractions.push({
|
|
709
|
-
name,
|
|
710
|
-
representative: group.representative
|
|
711
|
-
});
|
|
712
|
-
}
|
|
713
|
-
function rewrite(node, skipRootMatch) {
|
|
714
|
-
if (bySignature.size === 0 && byName.size === 0) return node;
|
|
715
|
-
const root = node;
|
|
716
|
-
return ast.transform(node, { schema(schemaNode) {
|
|
717
|
-
if (schemaNode.type === "ref") {
|
|
718
|
-
const refName = schemaNode.ref ? extractRefName(schemaNode.ref) : schemaNode.name;
|
|
719
|
-
const target = refName ? byName.get(refName) : void 0;
|
|
720
|
-
return target ? {
|
|
721
|
-
...schemaNode,
|
|
722
|
-
name: target.name,
|
|
723
|
-
ref: target.ref
|
|
724
|
-
} : void 0;
|
|
725
|
-
}
|
|
726
|
-
if (skipRootMatch && schemaNode === root) return void 0;
|
|
727
|
-
const target = bySignature.get(ast.signatureOf(schemaNode));
|
|
728
|
-
if (!target) return void 0;
|
|
729
|
-
return createRefNode(schemaNode, target);
|
|
730
|
-
} });
|
|
731
|
-
}
|
|
732
|
-
return {
|
|
733
|
-
extracted: pendingExtractions.map(({ name, representative }) => cleanDefinition(rewrite(representative, true), name)),
|
|
734
|
-
apply(node) {
|
|
735
|
-
return rewrite(node, false);
|
|
736
|
-
},
|
|
737
|
-
applyTopLevel(node) {
|
|
738
|
-
const target = bySignature.get(ast.signatureOf(node));
|
|
739
|
-
if (target && target.name !== node.name) return ast.factory.createSchema({
|
|
740
|
-
type: "ref",
|
|
741
|
-
name: node.name ?? null,
|
|
742
|
-
ref: target.ref,
|
|
743
|
-
description: node.description,
|
|
744
|
-
deprecated: node.deprecated
|
|
745
|
-
});
|
|
746
|
-
return rewrite(node, true);
|
|
747
|
-
},
|
|
748
|
-
isAlias(name) {
|
|
749
|
-
return byName.has(name);
|
|
750
|
-
}
|
|
751
|
-
};
|
|
752
|
-
}
|
|
753
|
-
//#endregion
|
|
754
592
|
//#region src/guards.ts
|
|
755
593
|
/**
|
|
756
594
|
* Returns `true` when a schema should be treated as nullable.
|
|
@@ -892,8 +730,7 @@ const oasDialect = ast.defineDialect({
|
|
|
892
730
|
isDiscriminator,
|
|
893
731
|
isBinary: (schema) => schema.type === "string" && schema.contentMediaType === "application/octet-stream",
|
|
894
732
|
resolveRef
|
|
895
|
-
}
|
|
896
|
-
dedupe: { plan }
|
|
733
|
+
}
|
|
897
734
|
});
|
|
898
735
|
//#endregion
|
|
899
736
|
//#region src/discriminator.ts
|
|
@@ -2475,6 +2312,53 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2475
2312
|
};
|
|
2476
2313
|
}
|
|
2477
2314
|
//#endregion
|
|
2315
|
+
//#region src/promoteEnums.ts
|
|
2316
|
+
/**
|
|
2317
|
+
* Collects inline enums to lift to the top level, keyed by the name the parser derived for them
|
|
2318
|
+
* (e.g. `PetStatusEnum`). An enum already defined as a top-level component is left as-is, and a
|
|
2319
|
+
* name that recurs maps to the first definition so each name yields one shared type.
|
|
2320
|
+
*/
|
|
2321
|
+
function collectInlineEnums(roots, topLevelNames) {
|
|
2322
|
+
const promoted = /* @__PURE__ */ new Map();
|
|
2323
|
+
for (const root of roots) {
|
|
2324
|
+
const isSchemaRoot = root.kind === "Schema";
|
|
2325
|
+
for (const node of ast.collect(root, { schema: (schemaNode) => schemaNode })) {
|
|
2326
|
+
if (node.type !== "enum" || !node.name) continue;
|
|
2327
|
+
if (isSchemaRoot && node === root) continue;
|
|
2328
|
+
if (topLevelNames.has(node.name)) continue;
|
|
2329
|
+
if (!promoted.has(node.name)) promoted.set(node.name, {
|
|
2330
|
+
...node,
|
|
2331
|
+
optional: void 0,
|
|
2332
|
+
nullish: void 0
|
|
2333
|
+
});
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
return promoted;
|
|
2337
|
+
}
|
|
2338
|
+
/**
|
|
2339
|
+
* Replaces every promoted inline enum in `node` with a `ref` to its lifted definition, keeping the
|
|
2340
|
+
* occurrence's usage-slot and documentation fields.
|
|
2341
|
+
*/
|
|
2342
|
+
function refPromotedEnums(node, promoted) {
|
|
2343
|
+
if (promoted.size === 0) return node;
|
|
2344
|
+
return ast.transform(node, { schema(schemaNode) {
|
|
2345
|
+
if (schemaNode.type !== "enum" || !schemaNode.name || !promoted.has(schemaNode.name)) return void 0;
|
|
2346
|
+
return ast.factory.createSchema({
|
|
2347
|
+
type: "ref",
|
|
2348
|
+
name: schemaNode.name,
|
|
2349
|
+
ref: `${SCHEMA_REF_PREFIX}${schemaNode.name}`,
|
|
2350
|
+
optional: schemaNode.optional,
|
|
2351
|
+
nullish: schemaNode.nullish,
|
|
2352
|
+
readOnly: schemaNode.readOnly,
|
|
2353
|
+
writeOnly: schemaNode.writeOnly,
|
|
2354
|
+
deprecated: schemaNode.deprecated,
|
|
2355
|
+
description: schemaNode.description,
|
|
2356
|
+
default: schemaNode.default,
|
|
2357
|
+
examples: schemaNode.examples
|
|
2358
|
+
});
|
|
2359
|
+
} });
|
|
2360
|
+
}
|
|
2361
|
+
//#endregion
|
|
2478
2362
|
//#region src/schemaDiagnostics.ts
|
|
2479
2363
|
/**
|
|
2480
2364
|
* Reports the advisory diagnostics (`KUBB_UNSUPPORTED_FORMAT`, `KUBB_DEPRECATED`) for one
|
|
@@ -2532,20 +2416,21 @@ function visit(node, pointer) {
|
|
|
2532
2416
|
//#endregion
|
|
2533
2417
|
//#region src/stream.ts
|
|
2534
2418
|
/**
|
|
2535
|
-
* Reads the server URL from the document's `servers` array at `
|
|
2536
|
-
* interpolating any `
|
|
2419
|
+
* Reads the server URL from the document's `servers` array at `server.index`,
|
|
2420
|
+
* interpolating any `server.variables` into the URL template.
|
|
2537
2421
|
*
|
|
2538
|
-
* Returns `null` when `
|
|
2422
|
+
* Returns `null` when `server.index` is omitted or out of range.
|
|
2539
2423
|
*
|
|
2540
2424
|
* @example Resolve the first server
|
|
2541
|
-
* `resolveBaseUrl({ document,
|
|
2425
|
+
* `resolveBaseUrl({ document, server: { index: 0 } })`
|
|
2542
2426
|
*
|
|
2543
2427
|
* @example Override a path variable
|
|
2544
|
-
* `resolveBaseUrl({ document,
|
|
2428
|
+
* `resolveBaseUrl({ document, server: { index: 0, variables: { version: 'v2' } } })`
|
|
2545
2429
|
*/
|
|
2546
|
-
function resolveBaseUrl({ document,
|
|
2547
|
-
const
|
|
2548
|
-
|
|
2430
|
+
function resolveBaseUrl({ document, server }) {
|
|
2431
|
+
const index = server?.index;
|
|
2432
|
+
const entry = index !== void 0 ? document.servers?.at(index) : void 0;
|
|
2433
|
+
return entry?.url ? resolveServerUrl(entry, server?.variables) : null;
|
|
2549
2434
|
}
|
|
2550
2435
|
/**
|
|
2551
2436
|
* Parses every schema once to build the lookup structures that streaming needs upfront.
|
|
@@ -2568,11 +2453,11 @@ function resolveBaseUrl({ document, serverIndex, serverVariables }) {
|
|
|
2568
2453
|
* schemas,
|
|
2569
2454
|
* parseSchema,
|
|
2570
2455
|
* parserOptions,
|
|
2571
|
-
* discriminator: '
|
|
2456
|
+
* discriminator: 'preserve',
|
|
2572
2457
|
* })
|
|
2573
2458
|
* ```
|
|
2574
2459
|
*/
|
|
2575
|
-
function preScan({ schemas, parseSchema, parseOperation, document, parserOptions, discriminator,
|
|
2460
|
+
function preScan({ schemas, parseSchema, parseOperation, document, parserOptions, discriminator, enums = "inline" }) {
|
|
2576
2461
|
const allNodes = [];
|
|
2577
2462
|
const refAliasMap = /* @__PURE__ */ new Map();
|
|
2578
2463
|
const enumNames = [];
|
|
@@ -2589,31 +2474,26 @@ function preScan({ schemas, parseSchema, parseOperation, document, parserOptions
|
|
|
2589
2474
|
});
|
|
2590
2475
|
if (node.type === "ref" && node.name && node.name !== name) refAliasMap.set(name, node);
|
|
2591
2476
|
if (ast.narrowSchema(node, ast.schemaTypes.enum) && node.name) enumNames.push(node.name);
|
|
2592
|
-
if (discriminator === "
|
|
2477
|
+
if (discriminator === "propagate" && (schema.oneOf ?? schema.anyOf) && schema.discriminator?.propertyName) discriminatorParentNodes.push(node);
|
|
2593
2478
|
}
|
|
2594
2479
|
const circularNames = [...findCircularSchemas(allNodes)];
|
|
2595
2480
|
const discriminatorChildMap = discriminatorParentNodes.length > 0 ? buildDiscriminatorChildMap(discriminatorParentNodes) : null;
|
|
2596
|
-
let
|
|
2597
|
-
if (
|
|
2481
|
+
let promotedEnums = null;
|
|
2482
|
+
if (enums === "root" && document && parseOperation) {
|
|
2598
2483
|
const operationNodes = [];
|
|
2599
2484
|
for (const operation of getOperations(document)) {
|
|
2600
2485
|
const operationNode = parseOperation(parserOptions, operation);
|
|
2601
2486
|
if (operationNode) operationNodes.push(operationNode);
|
|
2602
2487
|
}
|
|
2603
|
-
|
|
2604
|
-
const
|
|
2605
|
-
dedupePlan = oasDialect.dedupe.plan([...allNodes, ...operationNodes], {
|
|
2606
|
-
circularSchemas,
|
|
2607
|
-
usedNames
|
|
2608
|
-
});
|
|
2609
|
-
for (const definition of dedupePlan.extracted) if (definition.type === "enum" && definition.name) enumNames.push(definition.name);
|
|
2488
|
+
promotedEnums = collectInlineEnums([...allNodes, ...operationNodes], new Set(Object.keys(schemas)));
|
|
2489
|
+
for (const name of promotedEnums.keys()) enumNames.push(name);
|
|
2610
2490
|
}
|
|
2611
2491
|
return {
|
|
2612
2492
|
refAliasMap,
|
|
2613
|
-
enumNames
|
|
2493
|
+
enumNames,
|
|
2614
2494
|
circularNames,
|
|
2615
2495
|
discriminatorChildMap,
|
|
2616
|
-
|
|
2496
|
+
promotedEnums
|
|
2617
2497
|
};
|
|
2618
2498
|
}
|
|
2619
2499
|
/**
|
|
@@ -2634,12 +2514,11 @@ function preScan({ schemas, parseSchema, parseOperation, document, parserOptions
|
|
|
2634
2514
|
* }
|
|
2635
2515
|
* ```
|
|
2636
2516
|
*/
|
|
2637
|
-
function createInputStream({ schemas, parseSchema, parseOperation, document, parserOptions, refAliasMap, discriminatorChildMap,
|
|
2517
|
+
function createInputStream({ schemas, parseSchema, parseOperation, document, parserOptions, refAliasMap, discriminatorChildMap, promotedEnums, meta }) {
|
|
2638
2518
|
const schemasIterable = { [Symbol.asyncIterator]() {
|
|
2639
2519
|
return (async function* () {
|
|
2640
|
-
if (
|
|
2520
|
+
if (promotedEnums) for (const definition of promotedEnums.values()) yield definition;
|
|
2641
2521
|
for (const [name, schema] of Object.entries(schemas)) {
|
|
2642
|
-
if (dedupePlan?.isAlias(name)) continue;
|
|
2643
2522
|
const alias = refAliasMap.get(name);
|
|
2644
2523
|
if (alias?.name && schemas[alias.name]) {
|
|
2645
2524
|
const aliasNode = {
|
|
@@ -2649,7 +2528,7 @@ function createInputStream({ schemas, parseSchema, parseOperation, document, par
|
|
|
2649
2528
|
}, parserOptions),
|
|
2650
2529
|
name
|
|
2651
2530
|
};
|
|
2652
|
-
yield
|
|
2531
|
+
yield promotedEnums ? refPromotedEnums(aliasNode, promotedEnums) : aliasNode;
|
|
2653
2532
|
continue;
|
|
2654
2533
|
}
|
|
2655
2534
|
const parsed = parseSchema({
|
|
@@ -2657,7 +2536,7 @@ function createInputStream({ schemas, parseSchema, parseOperation, document, par
|
|
|
2657
2536
|
name
|
|
2658
2537
|
}, parserOptions);
|
|
2659
2538
|
const node = discriminatorChildMap?.get(name) ? patchDiscriminatorNode(parsed, discriminatorChildMap.get(name)) : parsed;
|
|
2660
|
-
yield
|
|
2539
|
+
yield promotedEnums ? refPromotedEnums(node, promotedEnums) : node;
|
|
2661
2540
|
}
|
|
2662
2541
|
})();
|
|
2663
2542
|
} };
|
|
@@ -2665,7 +2544,7 @@ function createInputStream({ schemas, parseSchema, parseOperation, document, par
|
|
|
2665
2544
|
return (async function* () {
|
|
2666
2545
|
for (const operation of getOperations(document)) {
|
|
2667
2546
|
const node = parseOperation(parserOptions, operation);
|
|
2668
|
-
if (node) yield
|
|
2547
|
+
if (node) yield promotedEnums ? refPromotedEnums(node, promotedEnums) : node;
|
|
2669
2548
|
}
|
|
2670
2549
|
})();
|
|
2671
2550
|
} };
|
|
@@ -2701,8 +2580,8 @@ const adapterOasName = "oas";
|
|
|
2701
2580
|
* input: { path: './petStore.yaml' },
|
|
2702
2581
|
* output: { path: './src/gen' },
|
|
2703
2582
|
* adapter: adapterOas({
|
|
2704
|
-
*
|
|
2705
|
-
* discriminator: '
|
|
2583
|
+
* server: { index: 0 },
|
|
2584
|
+
* discriminator: 'propagate',
|
|
2706
2585
|
* dateType: 'date',
|
|
2707
2586
|
* }),
|
|
2708
2587
|
* plugins: [pluginTs()],
|
|
@@ -2710,7 +2589,7 @@ const adapterOasName = "oas";
|
|
|
2710
2589
|
* ```
|
|
2711
2590
|
*/
|
|
2712
2591
|
const adapterOas = createAdapter((options) => {
|
|
2713
|
-
const { validate = true, contentType,
|
|
2592
|
+
const { validate = true, contentType, server, discriminator = "preserve", enums = "inline", 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;
|
|
2714
2593
|
const parserOptions = {
|
|
2715
2594
|
...DEFAULT_PARSER_OPTIONS,
|
|
2716
2595
|
dateType,
|
|
@@ -2768,7 +2647,7 @@ const adapterOas = createAdapter((options) => {
|
|
|
2768
2647
|
document,
|
|
2769
2648
|
parserOptions,
|
|
2770
2649
|
discriminator,
|
|
2771
|
-
|
|
2650
|
+
enums
|
|
2772
2651
|
});
|
|
2773
2652
|
preScanCache.set(document, result);
|
|
2774
2653
|
return result;
|
|
@@ -2777,7 +2656,7 @@ const adapterOas = createAdapter((options) => {
|
|
|
2777
2656
|
const document = await ensureDocument(source);
|
|
2778
2657
|
const schemas = await ensureSchemas(document);
|
|
2779
2658
|
const { parseSchema, parseOperation } = ensureSchemaParser(document);
|
|
2780
|
-
const { refAliasMap, enumNames, circularNames, discriminatorChildMap,
|
|
2659
|
+
const { refAliasMap, enumNames, circularNames, discriminatorChildMap, promotedEnums } = ensurePreScan(document, schemas, parseSchema, parseOperation);
|
|
2781
2660
|
return createInputStream({
|
|
2782
2661
|
schemas,
|
|
2783
2662
|
parseSchema,
|
|
@@ -2786,15 +2665,14 @@ const adapterOas = createAdapter((options) => {
|
|
|
2786
2665
|
parserOptions,
|
|
2787
2666
|
refAliasMap,
|
|
2788
2667
|
discriminatorChildMap,
|
|
2789
|
-
|
|
2668
|
+
promotedEnums,
|
|
2790
2669
|
meta: {
|
|
2791
2670
|
title: document.info?.title,
|
|
2792
2671
|
description: document.info?.description,
|
|
2793
2672
|
version: document.info?.version,
|
|
2794
2673
|
baseURL: resolveBaseUrl({
|
|
2795
2674
|
document,
|
|
2796
|
-
|
|
2797
|
-
serverVariables
|
|
2675
|
+
server
|
|
2798
2676
|
}),
|
|
2799
2677
|
circularNames,
|
|
2800
2678
|
enumNames
|
|
@@ -2807,10 +2685,9 @@ const adapterOas = createAdapter((options) => {
|
|
|
2807
2685
|
return {
|
|
2808
2686
|
validate,
|
|
2809
2687
|
contentType,
|
|
2810
|
-
|
|
2811
|
-
serverVariables,
|
|
2688
|
+
server,
|
|
2812
2689
|
discriminator,
|
|
2813
|
-
|
|
2690
|
+
enums,
|
|
2814
2691
|
dateType,
|
|
2815
2692
|
integerType,
|
|
2816
2693
|
unknownType,
|