@kubb/adapter-oas 5.0.0-alpha.10 → 5.0.0-alpha.11
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 +201 -147
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +34 -26
- package/dist/index.js +201 -147
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/adapter.ts +9 -6
- package/src/constants.ts +11 -5
- package/src/parser.ts +102 -77
- package/src/types.ts +35 -19
package/dist/index.d.ts
CHANGED
|
@@ -100,6 +100,31 @@ declare class Oas extends BaseOas {
|
|
|
100
100
|
}
|
|
101
101
|
//#endregion
|
|
102
102
|
//#region src/types.d.ts
|
|
103
|
+
/**
|
|
104
|
+
* Controls how various OAS constructs are mapped to Kubb AST nodes.
|
|
105
|
+
*/
|
|
106
|
+
type ParserOptions = {
|
|
107
|
+
/**
|
|
108
|
+
* How `format: 'date-time'` schemas are represented. `false` falls through to a plain string.
|
|
109
|
+
*/
|
|
110
|
+
dateType: false | 'string' | 'stringOffset' | 'stringLocal' | 'date';
|
|
111
|
+
/**
|
|
112
|
+
* Whether `type: 'integer'` and `format: 'int64'` produce `number` or `bigint` nodes.
|
|
113
|
+
*/
|
|
114
|
+
integerType?: 'number' | 'bigint';
|
|
115
|
+
/**
|
|
116
|
+
* AST type used when no schema type can be inferred.
|
|
117
|
+
*/
|
|
118
|
+
unknownType: 'any' | 'unknown' | 'void';
|
|
119
|
+
/**
|
|
120
|
+
* AST type used for completely empty schemas (`{}`).
|
|
121
|
+
*/
|
|
122
|
+
emptySchemaType: 'any' | 'unknown' | 'void';
|
|
123
|
+
/**
|
|
124
|
+
* Suffix appended to derived enum names when building property schema names.
|
|
125
|
+
*/
|
|
126
|
+
enumSuffix: 'enum' | (string & {});
|
|
127
|
+
};
|
|
103
128
|
type OasAdapterOptions = {
|
|
104
129
|
/**
|
|
105
130
|
* Validate the OpenAPI spec before parsing.
|
|
@@ -139,34 +164,16 @@ type OasAdapterOptions = {
|
|
|
139
164
|
*/
|
|
140
165
|
discriminator?: 'strict' | 'inherit';
|
|
141
166
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
167
|
+
* Enable collision detection for inline enum and schema type names.
|
|
168
|
+
* When `true` (default), full-path names are used and name collisions
|
|
169
|
+
* across schema components are automatically resolved (e.g. `OrderParamsStatusEnum`).
|
|
170
|
+
* When `false`, enum names use only the immediate property context
|
|
171
|
+
* (e.g. `ParamsStatusEnum`) matching the v4 naming conventions, with numeric
|
|
172
|
+
* suffixes for deduplication (e.g. `ParamsStatusEnum2`).
|
|
173
|
+
* @default true
|
|
144
174
|
*/
|
|
145
175
|
collisionDetection?: boolean;
|
|
146
|
-
|
|
147
|
-
* How `format: 'date-time'` schemas are represented in the AST.
|
|
148
|
-
* - `'string'` maps to a `datetime` string node.
|
|
149
|
-
* - `'date'` maps to a JavaScript `Date` node.
|
|
150
|
-
* - `false` falls through to a plain `string` node.
|
|
151
|
-
* @default 'string'
|
|
152
|
-
*/
|
|
153
|
-
dateType?: false | 'string' | 'stringOffset' | 'stringLocal' | 'date';
|
|
154
|
-
/**
|
|
155
|
-
* Whether `type: 'integer'` / `format: 'int64'` produces `number` or `bigint` nodes.
|
|
156
|
-
* @default 'number'
|
|
157
|
-
*/
|
|
158
|
-
integerType?: 'number' | 'bigint';
|
|
159
|
-
/**
|
|
160
|
-
* AST type used when no schema type can be inferred.
|
|
161
|
-
* @default 'any'
|
|
162
|
-
*/
|
|
163
|
-
unknownType?: 'any' | 'unknown' | 'void';
|
|
164
|
-
/**
|
|
165
|
-
* AST type used for completely empty schemas (`{}`).
|
|
166
|
-
* @default `unknownType`
|
|
167
|
-
*/
|
|
168
|
-
emptySchemaType?: 'any' | 'unknown' | 'void';
|
|
169
|
-
};
|
|
176
|
+
} & Partial<ParserOptions>;
|
|
170
177
|
type OasAdapterResolvedOptions = {
|
|
171
178
|
validate: boolean;
|
|
172
179
|
oasClass: OasAdapterOptions['oasClass'];
|
|
@@ -179,6 +186,7 @@ type OasAdapterResolvedOptions = {
|
|
|
179
186
|
integerType: NonNullable<OasAdapterOptions['integerType']>;
|
|
180
187
|
unknownType: NonNullable<OasAdapterOptions['unknownType']>;
|
|
181
188
|
emptySchemaType: NonNullable<OasAdapterOptions['emptySchemaType']>;
|
|
189
|
+
enumSuffix: OasAdapterOptions['enumSuffix'];
|
|
182
190
|
/**
|
|
183
191
|
* Map from original `$ref` paths to their collision-resolved schema names.
|
|
184
192
|
* Populated by the adapter after each `parse()` call.
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,110 @@ import swagger2openapi from "swagger2openapi";
|
|
|
11
11
|
import jsonpointer from "jsonpointer";
|
|
12
12
|
import BaseOas from "oas";
|
|
13
13
|
import { matchesMimeType } from "oas/utils";
|
|
14
|
+
//#region src/constants.ts
|
|
15
|
+
/**
|
|
16
|
+
* Default values for all `Options` fields.
|
|
17
|
+
*/
|
|
18
|
+
const DEFAULT_PARSER_OPTIONS = {
|
|
19
|
+
dateType: "string",
|
|
20
|
+
integerType: "number",
|
|
21
|
+
unknownType: "any",
|
|
22
|
+
emptySchemaType: "any",
|
|
23
|
+
enumSuffix: "enum"
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* OpenAPI version string written into merged document stubs.
|
|
27
|
+
*/
|
|
28
|
+
const MERGE_OPENAPI_VERSION = "3.0.0";
|
|
29
|
+
/**
|
|
30
|
+
* Fallback `info.title` used when merging multiple API documents.
|
|
31
|
+
*/
|
|
32
|
+
const MERGE_DEFAULT_TITLE = "Merged API";
|
|
33
|
+
/**
|
|
34
|
+
* Fallback `info.version` used when merging multiple API documents.
|
|
35
|
+
*/
|
|
36
|
+
const MERGE_DEFAULT_VERSION = "1.0.0";
|
|
37
|
+
/**
|
|
38
|
+
* JSON Schema keywords that indicate structural composition.
|
|
39
|
+
* A schema fragment containing any of these keys must not be inlined into its
|
|
40
|
+
* parent during `allOf` flattening — it carries semantic meaning of its own.
|
|
41
|
+
*/
|
|
42
|
+
const structuralKeys = new Set([
|
|
43
|
+
"properties",
|
|
44
|
+
"items",
|
|
45
|
+
"additionalProperties",
|
|
46
|
+
"oneOf",
|
|
47
|
+
"anyOf",
|
|
48
|
+
"allOf",
|
|
49
|
+
"not"
|
|
50
|
+
]);
|
|
51
|
+
/**
|
|
52
|
+
* Maps OAS/JSON Schema `format` strings to their Kubb `SchemaType` equivalents.
|
|
53
|
+
*
|
|
54
|
+
* Only formats that need a type different from the raw OAS `type` are listed.
|
|
55
|
+
* `int64`, `date-time`, `date`, and `time` are handled separately because their
|
|
56
|
+
* mapping depends on runtime parser options.
|
|
57
|
+
*
|
|
58
|
+
* Note: `ipv4`, `ipv6`, and `hostname` map to `'url'` — the closest supported
|
|
59
|
+
* scalar type in the Kubb AST, even though these are not strictly URLs.
|
|
60
|
+
*/
|
|
61
|
+
const formatMap = {
|
|
62
|
+
uuid: "uuid",
|
|
63
|
+
email: "email",
|
|
64
|
+
"idn-email": "email",
|
|
65
|
+
uri: "url",
|
|
66
|
+
"uri-reference": "url",
|
|
67
|
+
url: "url",
|
|
68
|
+
ipv4: "url",
|
|
69
|
+
ipv6: "url",
|
|
70
|
+
hostname: "url",
|
|
71
|
+
"idn-hostname": "url",
|
|
72
|
+
binary: "blob",
|
|
73
|
+
byte: "blob",
|
|
74
|
+
int32: "integer",
|
|
75
|
+
float: "number",
|
|
76
|
+
double: "number"
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Exhaustive list of media types that Kubb recognizes.
|
|
80
|
+
*/
|
|
81
|
+
const knownMediaTypes = new Set([
|
|
82
|
+
"application/json",
|
|
83
|
+
"application/xml",
|
|
84
|
+
"application/x-www-form-urlencoded",
|
|
85
|
+
"application/octet-stream",
|
|
86
|
+
"application/pdf",
|
|
87
|
+
"application/zip",
|
|
88
|
+
"application/graphql",
|
|
89
|
+
"multipart/form-data",
|
|
90
|
+
"text/plain",
|
|
91
|
+
"text/html",
|
|
92
|
+
"text/csv",
|
|
93
|
+
"text/xml",
|
|
94
|
+
"image/png",
|
|
95
|
+
"image/jpeg",
|
|
96
|
+
"image/gif",
|
|
97
|
+
"image/webp",
|
|
98
|
+
"image/svg+xml",
|
|
99
|
+
"audio/mpeg",
|
|
100
|
+
"video/mp4"
|
|
101
|
+
]);
|
|
102
|
+
/**
|
|
103
|
+
* Vendor extension keys used to attach human-readable labels to enum values.
|
|
104
|
+
* Checked in priority order: the first key found wins.
|
|
105
|
+
*/
|
|
106
|
+
const enumExtensionKeys = ["x-enumNames", "x-enum-varnames"];
|
|
107
|
+
/**
|
|
108
|
+
* Scalar primitive schema types used for union member simplification.
|
|
109
|
+
*/
|
|
110
|
+
const SCALAR_PRIMITIVE_TYPES = new Set([
|
|
111
|
+
"string",
|
|
112
|
+
"number",
|
|
113
|
+
"integer",
|
|
114
|
+
"bigint",
|
|
115
|
+
"boolean"
|
|
116
|
+
]);
|
|
117
|
+
//#endregion
|
|
14
118
|
//#region src/oas/resolveServerUrl.ts
|
|
15
119
|
/**
|
|
16
120
|
* Resolves an OpenAPI server URL by substituting `{variable}` placeholders.
|
|
@@ -89,6 +193,27 @@ function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
|
|
|
89
193
|
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
90
194
|
}
|
|
91
195
|
//#endregion
|
|
196
|
+
//#region ../../internals/utils/src/names.ts
|
|
197
|
+
/**
|
|
198
|
+
* Returns a unique name by appending an incrementing numeric suffix when the name has already been used.
|
|
199
|
+
* Mutates `data` in-place as a usage counter so subsequent calls remain consistent.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* const seen: Record<string, number> = {}
|
|
203
|
+
* getUniqueName('Foo', seen) // 'Foo'
|
|
204
|
+
* getUniqueName('Foo', seen) // 'Foo2'
|
|
205
|
+
* getUniqueName('Foo', seen) // 'Foo3'
|
|
206
|
+
*/
|
|
207
|
+
function getUniqueName(originalName, data) {
|
|
208
|
+
let used = data[originalName] || 0;
|
|
209
|
+
if (used) {
|
|
210
|
+
data[originalName] = ++used;
|
|
211
|
+
originalName += used;
|
|
212
|
+
}
|
|
213
|
+
data[originalName] = 1;
|
|
214
|
+
return originalName;
|
|
215
|
+
}
|
|
216
|
+
//#endregion
|
|
92
217
|
//#region ../../internals/utils/src/reserved.ts
|
|
93
218
|
/**
|
|
94
219
|
* Returns `true` when `name` is a syntactically valid JavaScript variable name.
|
|
@@ -205,100 +330,6 @@ var URLPath = class {
|
|
|
205
330
|
}
|
|
206
331
|
};
|
|
207
332
|
//#endregion
|
|
208
|
-
//#region src/constants.ts
|
|
209
|
-
/**
|
|
210
|
-
* OpenAPI version string written into merged document stubs.
|
|
211
|
-
*/
|
|
212
|
-
const MERGE_OPENAPI_VERSION = "3.0.0";
|
|
213
|
-
/**
|
|
214
|
-
* Fallback `info.title` used when merging multiple API documents.
|
|
215
|
-
*/
|
|
216
|
-
const MERGE_DEFAULT_TITLE = "Merged API";
|
|
217
|
-
/**
|
|
218
|
-
* Fallback `info.version` used when merging multiple API documents.
|
|
219
|
-
*/
|
|
220
|
-
const MERGE_DEFAULT_VERSION = "1.0.0";
|
|
221
|
-
/**
|
|
222
|
-
* JSON Schema keywords that indicate structural composition.
|
|
223
|
-
* A schema fragment containing any of these keys must not be inlined into its
|
|
224
|
-
* parent during `allOf` flattening — it carries semantic meaning of its own.
|
|
225
|
-
*/
|
|
226
|
-
const structuralKeys = new Set([
|
|
227
|
-
"properties",
|
|
228
|
-
"items",
|
|
229
|
-
"additionalProperties",
|
|
230
|
-
"oneOf",
|
|
231
|
-
"anyOf",
|
|
232
|
-
"allOf",
|
|
233
|
-
"not"
|
|
234
|
-
]);
|
|
235
|
-
/**
|
|
236
|
-
* Maps OAS/JSON Schema `format` strings to their Kubb `SchemaType` equivalents.
|
|
237
|
-
*
|
|
238
|
-
* Only formats that need a type different from the raw OAS `type` are listed.
|
|
239
|
-
* `int64`, `date-time`, `date`, and `time` are handled separately because their
|
|
240
|
-
* mapping depends on runtime parser options.
|
|
241
|
-
*
|
|
242
|
-
* Note: `ipv4`, `ipv6`, and `hostname` map to `'url'` — the closest supported
|
|
243
|
-
* scalar type in the Kubb AST, even though these are not strictly URLs.
|
|
244
|
-
*/
|
|
245
|
-
const formatMap = {
|
|
246
|
-
uuid: "uuid",
|
|
247
|
-
email: "email",
|
|
248
|
-
"idn-email": "email",
|
|
249
|
-
uri: "url",
|
|
250
|
-
"uri-reference": "url",
|
|
251
|
-
url: "url",
|
|
252
|
-
ipv4: "url",
|
|
253
|
-
ipv6: "url",
|
|
254
|
-
hostname: "url",
|
|
255
|
-
"idn-hostname": "url",
|
|
256
|
-
binary: "blob",
|
|
257
|
-
byte: "blob",
|
|
258
|
-
int32: "integer",
|
|
259
|
-
float: "number",
|
|
260
|
-
double: "number"
|
|
261
|
-
};
|
|
262
|
-
/**
|
|
263
|
-
* Exhaustive list of media types that Kubb recognizes.
|
|
264
|
-
*/
|
|
265
|
-
const knownMediaTypes = new Set([
|
|
266
|
-
"application/json",
|
|
267
|
-
"application/xml",
|
|
268
|
-
"application/x-www-form-urlencoded",
|
|
269
|
-
"application/octet-stream",
|
|
270
|
-
"application/pdf",
|
|
271
|
-
"application/zip",
|
|
272
|
-
"application/graphql",
|
|
273
|
-
"multipart/form-data",
|
|
274
|
-
"text/plain",
|
|
275
|
-
"text/html",
|
|
276
|
-
"text/csv",
|
|
277
|
-
"text/xml",
|
|
278
|
-
"image/png",
|
|
279
|
-
"image/jpeg",
|
|
280
|
-
"image/gif",
|
|
281
|
-
"image/webp",
|
|
282
|
-
"image/svg+xml",
|
|
283
|
-
"audio/mpeg",
|
|
284
|
-
"video/mp4"
|
|
285
|
-
]);
|
|
286
|
-
/**
|
|
287
|
-
* Vendor extension keys used to attach human-readable labels to enum values.
|
|
288
|
-
* Checked in priority order: the first key found wins.
|
|
289
|
-
*/
|
|
290
|
-
const enumExtensionKeys = ["x-enumNames", "x-enum-varnames"];
|
|
291
|
-
/**
|
|
292
|
-
* Scalar primitive schema types used for union member simplification.
|
|
293
|
-
*/
|
|
294
|
-
const SCALAR_PRIMITIVE_TYPES = new Set([
|
|
295
|
-
"string",
|
|
296
|
-
"number",
|
|
297
|
-
"integer",
|
|
298
|
-
"bigint",
|
|
299
|
-
"boolean"
|
|
300
|
-
]);
|
|
301
|
-
//#endregion
|
|
302
333
|
//#region src/oas/Oas.ts
|
|
303
334
|
/**
|
|
304
335
|
* Prefix used to create synthetic `$ref` values for anonymous (inline) discriminator schemas.
|
|
@@ -1052,16 +1083,6 @@ function getImports({ node, nameMapping, resolve }) {
|
|
|
1052
1083
|
//#endregion
|
|
1053
1084
|
//#region src/parser.ts
|
|
1054
1085
|
/**
|
|
1055
|
-
* Default values for all `Options` fields.
|
|
1056
|
-
*/
|
|
1057
|
-
const DEFAULT_OPTIONS = {
|
|
1058
|
-
dateType: "string",
|
|
1059
|
-
integerType: "number",
|
|
1060
|
-
unknownType: "any",
|
|
1061
|
-
emptySchemaType: "any",
|
|
1062
|
-
enumSuffix: "enum"
|
|
1063
|
-
};
|
|
1064
|
-
/**
|
|
1065
1086
|
* Looks up the Kubb `SchemaType` for a given OAS `format` string.
|
|
1066
1087
|
* Returns `undefined` for formats not in `formatMap` (e.g. `int64`, `date-time`),
|
|
1067
1088
|
* which are handled separately because their output depends on parser options.
|
|
@@ -1110,6 +1131,8 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1110
1131
|
contentType,
|
|
1111
1132
|
collisionDetection
|
|
1112
1133
|
});
|
|
1134
|
+
const usedEnumNames = {};
|
|
1135
|
+
const isLegacyNaming = collisionDetection === false;
|
|
1113
1136
|
/**
|
|
1114
1137
|
* Maps an `'any' | 'unknown' | 'void'` option string to the corresponding `SchemaType` constant.
|
|
1115
1138
|
* Used for both `unknownType` (unannotated schemas) and `emptySchemaType` (empty `{}` schemas).
|
|
@@ -1156,7 +1179,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1156
1179
|
* Shared metadata fields included in every `createSchema` call.
|
|
1157
1180
|
* Centralizes the common properties so sub-handlers don't repeat them.
|
|
1158
1181
|
*/
|
|
1159
|
-
function
|
|
1182
|
+
function renderSchemaBase(schema, name, nullable, defaultValue) {
|
|
1160
1183
|
return {
|
|
1161
1184
|
name,
|
|
1162
1185
|
nullable,
|
|
@@ -1264,7 +1287,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1264
1287
|
return createSchema({
|
|
1265
1288
|
type: "intersection",
|
|
1266
1289
|
members: [...allOfMembers.slice(0, syntheticStart), ...mergeAdjacentAnonymousObjects(allOfMembers.slice(syntheticStart))],
|
|
1267
|
-
...
|
|
1290
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1268
1291
|
});
|
|
1269
1292
|
}
|
|
1270
1293
|
/**
|
|
@@ -1278,23 +1301,23 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1278
1301
|
function convertUnion({ schema, name, nullable, defaultValue, options }) {
|
|
1279
1302
|
const unionMembers = [...schema.oneOf ?? [], ...schema.anyOf ?? []];
|
|
1280
1303
|
const unionBase = {
|
|
1281
|
-
...
|
|
1304
|
+
...renderSchemaBase(schema, name, nullable, defaultValue),
|
|
1282
1305
|
discriminatorPropertyName: isDiscriminator(schema) ? schema.discriminator.propertyName : void 0
|
|
1283
1306
|
};
|
|
1284
1307
|
if (schema.properties) {
|
|
1285
1308
|
const { oneOf: _oneOf, anyOf: _anyOf, ...schemaWithoutUnion } = schema;
|
|
1286
1309
|
const discriminator = isDiscriminator(schema) ? schema.discriminator : void 0;
|
|
1287
|
-
const
|
|
1310
|
+
const sharedPropertiesNode = convertSchema({
|
|
1311
|
+
schema: discriminator ? Object.fromEntries(Object.entries(schemaWithoutUnion).filter(([key]) => key !== "discriminator")) : schemaWithoutUnion,
|
|
1312
|
+
name: isLegacyNaming ? void 0 : name
|
|
1313
|
+
}, options);
|
|
1288
1314
|
return createSchema({
|
|
1289
1315
|
type: "union",
|
|
1290
1316
|
...unionBase,
|
|
1291
1317
|
members: unionMembers.map((s) => {
|
|
1292
1318
|
const ref = isReference(s) ? s.$ref : void 0;
|
|
1293
1319
|
const discriminatorValue = discriminator?.mapping && ref ? Object.entries(discriminator.mapping).find(([, v]) => v === ref)?.[0] : void 0;
|
|
1294
|
-
let propertiesNode =
|
|
1295
|
-
schema: memberBaseSchema,
|
|
1296
|
-
name
|
|
1297
|
-
}, options);
|
|
1320
|
+
let propertiesNode = sharedPropertiesNode;
|
|
1298
1321
|
if (discriminatorValue && discriminator) propertiesNode = applyDiscriminatorEnum({
|
|
1299
1322
|
node: propertiesNode,
|
|
1300
1323
|
propertyName: discriminator.propertyName,
|
|
@@ -1333,7 +1356,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1333
1356
|
type: "enum",
|
|
1334
1357
|
primitive: getPrimitiveType(typeof constValue === "number" ? "number" : typeof constValue === "boolean" ? "boolean" : "string"),
|
|
1335
1358
|
enumValues: [constValue],
|
|
1336
|
-
...
|
|
1359
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1337
1360
|
});
|
|
1338
1361
|
}
|
|
1339
1362
|
/**
|
|
@@ -1342,7 +1365,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1342
1365
|
* (i.e. `format: 'date-time'` with `dateType: false`).
|
|
1343
1366
|
*/
|
|
1344
1367
|
function convertFormat({ schema, name, nullable, defaultValue, mergedOptions }) {
|
|
1345
|
-
const base =
|
|
1368
|
+
const base = renderSchemaBase(schema, name, nullable, defaultValue);
|
|
1346
1369
|
if (schema.format === "int64") return createSchema({
|
|
1347
1370
|
type: mergedOptions.integerType === "bigint" ? "bigint" : "integer",
|
|
1348
1371
|
primitive: "integer",
|
|
@@ -1480,29 +1503,62 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1480
1503
|
* - not required + not nullable → `optional: true`
|
|
1481
1504
|
* - not required + nullable → `nullish: true`
|
|
1482
1505
|
*/
|
|
1506
|
+
/**
|
|
1507
|
+
* Builds the propagation name for a child property during recursive schema conversion.
|
|
1508
|
+
*
|
|
1509
|
+
* - **Legacy naming** (`isLegacyNaming`): only the immediate property key is used
|
|
1510
|
+
* (e.g. `Params` for property `params`), keeping nested names short.
|
|
1511
|
+
* - **Default naming**: the parent name is prepended so the full path is encoded
|
|
1512
|
+
* (e.g. `OrderParams` when parent is `Order`).
|
|
1513
|
+
*/
|
|
1514
|
+
function resolveChildName(parentName, propName) {
|
|
1515
|
+
if (isLegacyNaming) return pascalCase(propName);
|
|
1516
|
+
return parentName ? pascalCase([parentName, propName].join(" ")) : void 0;
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* Derives the final name for an enum property schema node.
|
|
1520
|
+
*
|
|
1521
|
+
* The raw name always includes the enum suffix (e.g. `StatusEnum`).
|
|
1522
|
+
* In legacy mode an additional deduplication step appends a numeric suffix
|
|
1523
|
+
* when the same name has already been used (e.g. `ParamsStatusEnum2`).
|
|
1524
|
+
*/
|
|
1525
|
+
function resolveEnumPropName(parentName, propName, enumSuffix) {
|
|
1526
|
+
const raw = pascalCase([
|
|
1527
|
+
parentName,
|
|
1528
|
+
propName,
|
|
1529
|
+
enumSuffix
|
|
1530
|
+
].filter(Boolean).join(" "));
|
|
1531
|
+
return isLegacyNaming ? getUniqueName(raw, usedEnumNames) : raw;
|
|
1532
|
+
}
|
|
1533
|
+
/**
|
|
1534
|
+
* Given a freshly-converted property schema, returns the node with a correct
|
|
1535
|
+
* `name` attached — or stripped — depending on whether the node is a named
|
|
1536
|
+
* enum, a boolean const-enum (always inlined), or a regular schema.
|
|
1537
|
+
*/
|
|
1538
|
+
function applyEnumName(propNode, parentName, propName, enumSuffix) {
|
|
1539
|
+
const enumNode = narrowSchema(propNode, "enum");
|
|
1540
|
+
if (enumNode?.primitive === "boolean") return {
|
|
1541
|
+
...propNode,
|
|
1542
|
+
name: void 0
|
|
1543
|
+
};
|
|
1544
|
+
if (enumNode) return {
|
|
1545
|
+
...propNode,
|
|
1546
|
+
name: resolveEnumPropName(parentName, propName, enumSuffix)
|
|
1547
|
+
};
|
|
1548
|
+
return propNode;
|
|
1549
|
+
}
|
|
1483
1550
|
function convertObject({ schema, name, nullable, defaultValue, options, mergedOptions }) {
|
|
1484
1551
|
const properties = schema.properties ? Object.entries(schema.properties).map(([propName, propSchema]) => {
|
|
1485
1552
|
const required = Array.isArray(schema.required) ? schema.required.includes(propName) : !!schema.required;
|
|
1486
1553
|
const resolvedPropSchema = propSchema;
|
|
1487
1554
|
const propNullable = isNullable(resolvedPropSchema);
|
|
1488
|
-
const basePropName = name ? pascalCase([name, propName].join(" ")) : void 0;
|
|
1489
|
-
const propNode = convertSchema({
|
|
1490
|
-
schema: resolvedPropSchema,
|
|
1491
|
-
name: basePropName
|
|
1492
|
-
}, options);
|
|
1493
|
-
const isEnumNode = !!narrowSchema(propNode, "enum");
|
|
1494
|
-
const derivedPropName = isEnumNode && name ? pascalCase([
|
|
1495
|
-
name,
|
|
1496
|
-
propName,
|
|
1497
|
-
mergedOptions.enumSuffix
|
|
1498
|
-
].filter(Boolean).join(" ")) : basePropName;
|
|
1499
1555
|
return createProperty({
|
|
1500
1556
|
name: propName,
|
|
1501
1557
|
schema: {
|
|
1502
|
-
...
|
|
1503
|
-
|
|
1504
|
-
name:
|
|
1505
|
-
}
|
|
1558
|
+
...applyEnumName(convertSchema({
|
|
1559
|
+
schema: resolvedPropSchema,
|
|
1560
|
+
name: resolveChildName(name, propName)
|
|
1561
|
+
}, options), name, propName, mergedOptions.enumSuffix),
|
|
1506
1562
|
nullable: propNullable || void 0,
|
|
1507
1563
|
optional: !required && !propNullable ? true : void 0,
|
|
1508
1564
|
nullish: !required && propNullable ? true : void 0
|
|
@@ -1524,7 +1580,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1524
1580
|
properties,
|
|
1525
1581
|
additionalProperties: additionalPropertiesNode,
|
|
1526
1582
|
patternProperties,
|
|
1527
|
-
...
|
|
1583
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1528
1584
|
});
|
|
1529
1585
|
if (isDiscriminator(schema) && schema.discriminator.mapping) {
|
|
1530
1586
|
const discPropName = schema.discriminator.propertyName;
|
|
@@ -1532,11 +1588,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1532
1588
|
node: objectNode,
|
|
1533
1589
|
propertyName: discPropName,
|
|
1534
1590
|
values: Object.keys(schema.discriminator.mapping),
|
|
1535
|
-
enumName: name ?
|
|
1536
|
-
name,
|
|
1537
|
-
discPropName,
|
|
1538
|
-
mergedOptions.enumSuffix
|
|
1539
|
-
].filter(Boolean).join(" ")) : void 0
|
|
1591
|
+
enumName: name ? resolveEnumPropName(name, discPropName, mergedOptions.enumSuffix) : void 0
|
|
1540
1592
|
});
|
|
1541
1593
|
}
|
|
1542
1594
|
return objectNode;
|
|
@@ -1555,7 +1607,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1555
1607
|
rest: schema.items ? convertSchema({ schema: schema.items }, options) : void 0,
|
|
1556
1608
|
min: schema.minItems,
|
|
1557
1609
|
max: schema.maxItems,
|
|
1558
|
-
...
|
|
1610
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1559
1611
|
});
|
|
1560
1612
|
}
|
|
1561
1613
|
/**
|
|
@@ -1566,7 +1618,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1566
1618
|
*/
|
|
1567
1619
|
function convertArray({ schema, name, nullable, defaultValue, options, mergedOptions }) {
|
|
1568
1620
|
const rawItems = schema.items;
|
|
1569
|
-
const itemName = rawItems?.enum?.length && name ?
|
|
1621
|
+
const itemName = rawItems?.enum?.length && name ? resolveEnumPropName(void 0, name, mergedOptions.enumSuffix) : void 0;
|
|
1570
1622
|
return createSchema({
|
|
1571
1623
|
type: "array",
|
|
1572
1624
|
primitive: "array",
|
|
@@ -1577,7 +1629,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1577
1629
|
min: schema.minItems,
|
|
1578
1630
|
max: schema.maxItems,
|
|
1579
1631
|
unique: schema.uniqueItems ?? void 0,
|
|
1580
|
-
...
|
|
1632
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1581
1633
|
});
|
|
1582
1634
|
}
|
|
1583
1635
|
/**
|
|
@@ -1590,7 +1642,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1590
1642
|
min: schema.minLength,
|
|
1591
1643
|
max: schema.maxLength,
|
|
1592
1644
|
pattern: schema.pattern,
|
|
1593
|
-
...
|
|
1645
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1594
1646
|
});
|
|
1595
1647
|
}
|
|
1596
1648
|
/**
|
|
@@ -1604,7 +1656,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1604
1656
|
max: schema.maximum,
|
|
1605
1657
|
exclusiveMinimum: typeof schema.exclusiveMinimum === "number" ? schema.exclusiveMinimum : void 0,
|
|
1606
1658
|
exclusiveMaximum: typeof schema.exclusiveMaximum === "number" ? schema.exclusiveMaximum : void 0,
|
|
1607
|
-
...
|
|
1659
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1608
1660
|
});
|
|
1609
1661
|
}
|
|
1610
1662
|
/**
|
|
@@ -1614,7 +1666,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1614
1666
|
return createSchema({
|
|
1615
1667
|
type: "boolean",
|
|
1616
1668
|
primitive: "boolean",
|
|
1617
|
-
...
|
|
1669
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1618
1670
|
});
|
|
1619
1671
|
}
|
|
1620
1672
|
/**
|
|
@@ -1649,7 +1701,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1649
1701
|
*/
|
|
1650
1702
|
function convertSchema({ schema, name }, options) {
|
|
1651
1703
|
const mergedOptions = {
|
|
1652
|
-
...
|
|
1704
|
+
...DEFAULT_PARSER_OPTIONS,
|
|
1653
1705
|
...options
|
|
1654
1706
|
};
|
|
1655
1707
|
const flattenedSchema = flattenSchema(schema);
|
|
@@ -1680,7 +1732,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1680
1732
|
if (schema.type === "string" && schema.contentMediaType === "application/octet-stream") return createSchema({
|
|
1681
1733
|
type: "blob",
|
|
1682
1734
|
primitive: "string",
|
|
1683
|
-
...
|
|
1735
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1684
1736
|
});
|
|
1685
1737
|
if (Array.isArray(schema.type) && schema.type.length > 1) {
|
|
1686
1738
|
const nonNullTypes = schema.type.filter((t) => t !== "null");
|
|
@@ -1694,7 +1746,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1694
1746
|
},
|
|
1695
1747
|
name
|
|
1696
1748
|
}, options)),
|
|
1697
|
-
...
|
|
1749
|
+
...renderSchemaBase(schema, name, arrayNullable, defaultValue)
|
|
1698
1750
|
});
|
|
1699
1751
|
}
|
|
1700
1752
|
if (!type) {
|
|
@@ -1775,7 +1827,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1775
1827
|
*/
|
|
1776
1828
|
function parse(options) {
|
|
1777
1829
|
const mergedOptions = {
|
|
1778
|
-
...
|
|
1830
|
+
...DEFAULT_PARSER_OPTIONS,
|
|
1779
1831
|
...options
|
|
1780
1832
|
};
|
|
1781
1833
|
const schemas = Object.entries(schemaObjects).map(([name, schemaObject]) => convertSchema({
|
|
@@ -1845,7 +1897,7 @@ const adapterOasName = "oas";
|
|
|
1845
1897
|
* ```
|
|
1846
1898
|
*/
|
|
1847
1899
|
const adapterOas = createAdapter((options) => {
|
|
1848
|
-
const { validate = true, oasClass, contentType, serverIndex, serverVariables, discriminator = "strict", collisionDetection =
|
|
1900
|
+
const { validate = true, oasClass, contentType, serverIndex, serverVariables, discriminator = "strict", collisionDetection = 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;
|
|
1849
1901
|
const nameMapping = /* @__PURE__ */ new Map();
|
|
1850
1902
|
return {
|
|
1851
1903
|
name: "oas",
|
|
@@ -1861,6 +1913,7 @@ const adapterOas = createAdapter((options) => {
|
|
|
1861
1913
|
integerType,
|
|
1862
1914
|
unknownType,
|
|
1863
1915
|
emptySchemaType,
|
|
1916
|
+
enumSuffix,
|
|
1864
1917
|
nameMapping
|
|
1865
1918
|
},
|
|
1866
1919
|
getImports(node, resolve) {
|
|
@@ -1893,7 +1946,8 @@ const adapterOas = createAdapter((options) => {
|
|
|
1893
1946
|
dateType,
|
|
1894
1947
|
integerType,
|
|
1895
1948
|
unknownType,
|
|
1896
|
-
emptySchemaType
|
|
1949
|
+
emptySchemaType,
|
|
1950
|
+
enumSuffix
|
|
1897
1951
|
}),
|
|
1898
1952
|
meta: {
|
|
1899
1953
|
title: oas.api.info?.title,
|