@kubb/adapter-oas 5.0.0-alpha.10 → 5.0.0-alpha.12

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.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
- * Automatically resolve name collisions across schema components.
143
- * @default false
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.
@@ -53,9 +157,12 @@ function toCamelOrPascal(text, pascal) {
53
157
  * Splits `text` on `.` and applies `transformPart` to each segment.
54
158
  * The last segment receives `isLast = true`, all earlier segments receive `false`.
55
159
  * Segments are joined with `/` to form a file path.
160
+ *
161
+ * Only splits on dots followed by a letter so that version numbers
162
+ * embedded in operationIds (e.g. `v2025.0`) are kept intact.
56
163
  */
57
164
  function applyToFileParts(text, transformPart) {
58
- const parts = text.split(".");
165
+ const parts = text.split(/\.(?=[a-zA-Z])/);
59
166
  return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join("/");
60
167
  }
61
168
  /**
@@ -89,6 +196,27 @@ function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
89
196
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
90
197
  }
91
198
  //#endregion
199
+ //#region ../../internals/utils/src/names.ts
200
+ /**
201
+ * Returns a unique name by appending an incrementing numeric suffix when the name has already been used.
202
+ * Mutates `data` in-place as a usage counter so subsequent calls remain consistent.
203
+ *
204
+ * @example
205
+ * const seen: Record<string, number> = {}
206
+ * getUniqueName('Foo', seen) // 'Foo'
207
+ * getUniqueName('Foo', seen) // 'Foo2'
208
+ * getUniqueName('Foo', seen) // 'Foo3'
209
+ */
210
+ function getUniqueName(originalName, data) {
211
+ let used = data[originalName] || 0;
212
+ if (used) {
213
+ data[originalName] = ++used;
214
+ originalName += used;
215
+ }
216
+ data[originalName] = 1;
217
+ return originalName;
218
+ }
219
+ //#endregion
92
220
  //#region ../../internals/utils/src/reserved.ts
93
221
  /**
94
222
  * Returns `true` when `name` is a syntactically valid JavaScript variable name.
@@ -205,100 +333,6 @@ var URLPath = class {
205
333
  }
206
334
  };
207
335
  //#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
336
  //#region src/oas/Oas.ts
303
337
  /**
304
338
  * Prefix used to create synthetic `$ref` values for anonymous (inline) discriminator schemas.
@@ -1052,16 +1086,6 @@ function getImports({ node, nameMapping, resolve }) {
1052
1086
  //#endregion
1053
1087
  //#region src/parser.ts
1054
1088
  /**
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
1089
  * Looks up the Kubb `SchemaType` for a given OAS `format` string.
1066
1090
  * Returns `undefined` for formats not in `formatMap` (e.g. `int64`, `date-time`),
1067
1091
  * which are handled separately because their output depends on parser options.
@@ -1110,6 +1134,8 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1110
1134
  contentType,
1111
1135
  collisionDetection
1112
1136
  });
1137
+ const usedEnumNames = {};
1138
+ const isLegacyNaming = collisionDetection === false;
1113
1139
  /**
1114
1140
  * Maps an `'any' | 'unknown' | 'void'` option string to the corresponding `SchemaType` constant.
1115
1141
  * Used for both `unknownType` (unannotated schemas) and `emptySchemaType` (empty `{}` schemas).
@@ -1156,7 +1182,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1156
1182
  * Shared metadata fields included in every `createSchema` call.
1157
1183
  * Centralizes the common properties so sub-handlers don't repeat them.
1158
1184
  */
1159
- function buildSchemaBase(schema, name, nullable, defaultValue) {
1185
+ function renderSchemaBase(schema, name, nullable, defaultValue) {
1160
1186
  return {
1161
1187
  name,
1162
1188
  nullable,
@@ -1264,7 +1290,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1264
1290
  return createSchema({
1265
1291
  type: "intersection",
1266
1292
  members: [...allOfMembers.slice(0, syntheticStart), ...mergeAdjacentAnonymousObjects(allOfMembers.slice(syntheticStart))],
1267
- ...buildSchemaBase(schema, name, nullable, defaultValue)
1293
+ ...renderSchemaBase(schema, name, nullable, defaultValue)
1268
1294
  });
1269
1295
  }
1270
1296
  /**
@@ -1278,23 +1304,23 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1278
1304
  function convertUnion({ schema, name, nullable, defaultValue, options }) {
1279
1305
  const unionMembers = [...schema.oneOf ?? [], ...schema.anyOf ?? []];
1280
1306
  const unionBase = {
1281
- ...buildSchemaBase(schema, name, nullable, defaultValue),
1307
+ ...renderSchemaBase(schema, name, nullable, defaultValue),
1282
1308
  discriminatorPropertyName: isDiscriminator(schema) ? schema.discriminator.propertyName : void 0
1283
1309
  };
1284
1310
  if (schema.properties) {
1285
1311
  const { oneOf: _oneOf, anyOf: _anyOf, ...schemaWithoutUnion } = schema;
1286
1312
  const discriminator = isDiscriminator(schema) ? schema.discriminator : void 0;
1287
- const memberBaseSchema = discriminator ? Object.fromEntries(Object.entries(schemaWithoutUnion).filter(([key]) => key !== "discriminator")) : schemaWithoutUnion;
1313
+ const sharedPropertiesNode = convertSchema({
1314
+ schema: discriminator ? Object.fromEntries(Object.entries(schemaWithoutUnion).filter(([key]) => key !== "discriminator")) : schemaWithoutUnion,
1315
+ name: isLegacyNaming ? void 0 : name
1316
+ }, options);
1288
1317
  return createSchema({
1289
1318
  type: "union",
1290
1319
  ...unionBase,
1291
1320
  members: unionMembers.map((s) => {
1292
1321
  const ref = isReference(s) ? s.$ref : void 0;
1293
1322
  const discriminatorValue = discriminator?.mapping && ref ? Object.entries(discriminator.mapping).find(([, v]) => v === ref)?.[0] : void 0;
1294
- let propertiesNode = convertSchema({
1295
- schema: memberBaseSchema,
1296
- name
1297
- }, options);
1323
+ let propertiesNode = sharedPropertiesNode;
1298
1324
  if (discriminatorValue && discriminator) propertiesNode = applyDiscriminatorEnum({
1299
1325
  node: propertiesNode,
1300
1326
  propertyName: discriminator.propertyName,
@@ -1333,7 +1359,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1333
1359
  type: "enum",
1334
1360
  primitive: getPrimitiveType(typeof constValue === "number" ? "number" : typeof constValue === "boolean" ? "boolean" : "string"),
1335
1361
  enumValues: [constValue],
1336
- ...buildSchemaBase(schema, name, nullable, defaultValue)
1362
+ ...renderSchemaBase(schema, name, nullable, defaultValue)
1337
1363
  });
1338
1364
  }
1339
1365
  /**
@@ -1342,7 +1368,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1342
1368
  * (i.e. `format: 'date-time'` with `dateType: false`).
1343
1369
  */
1344
1370
  function convertFormat({ schema, name, nullable, defaultValue, mergedOptions }) {
1345
- const base = buildSchemaBase(schema, name, nullable, defaultValue);
1371
+ const base = renderSchemaBase(schema, name, nullable, defaultValue);
1346
1372
  if (schema.format === "int64") return createSchema({
1347
1373
  type: mergedOptions.integerType === "bigint" ? "bigint" : "integer",
1348
1374
  primitive: "integer",
@@ -1480,29 +1506,62 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1480
1506
  * - not required + not nullable → `optional: true`
1481
1507
  * - not required + nullable → `nullish: true`
1482
1508
  */
1509
+ /**
1510
+ * Builds the propagation name for a child property during recursive schema conversion.
1511
+ *
1512
+ * - **Legacy naming** (`isLegacyNaming`): only the immediate property key is used
1513
+ * (e.g. `Params` for property `params`), keeping nested names short.
1514
+ * - **Default naming**: the parent name is prepended so the full path is encoded
1515
+ * (e.g. `OrderParams` when parent is `Order`).
1516
+ */
1517
+ function resolveChildName(parentName, propName) {
1518
+ if (isLegacyNaming) return pascalCase(propName);
1519
+ return parentName ? pascalCase([parentName, propName].join(" ")) : void 0;
1520
+ }
1521
+ /**
1522
+ * Derives the final name for an enum property schema node.
1523
+ *
1524
+ * The raw name always includes the enum suffix (e.g. `StatusEnum`).
1525
+ * In legacy mode an additional deduplication step appends a numeric suffix
1526
+ * when the same name has already been used (e.g. `ParamsStatusEnum2`).
1527
+ */
1528
+ function resolveEnumPropName(parentName, propName, enumSuffix) {
1529
+ const raw = pascalCase([
1530
+ parentName,
1531
+ propName,
1532
+ enumSuffix
1533
+ ].filter(Boolean).join(" "));
1534
+ return isLegacyNaming ? getUniqueName(raw, usedEnumNames) : raw;
1535
+ }
1536
+ /**
1537
+ * Given a freshly-converted property schema, returns the node with a correct
1538
+ * `name` attached — or stripped — depending on whether the node is a named
1539
+ * enum, a boolean const-enum (always inlined), or a regular schema.
1540
+ */
1541
+ function applyEnumName(propNode, parentName, propName, enumSuffix) {
1542
+ const enumNode = narrowSchema(propNode, "enum");
1543
+ if (enumNode?.primitive === "boolean") return {
1544
+ ...propNode,
1545
+ name: void 0
1546
+ };
1547
+ if (enumNode) return {
1548
+ ...propNode,
1549
+ name: resolveEnumPropName(parentName, propName, enumSuffix)
1550
+ };
1551
+ return propNode;
1552
+ }
1483
1553
  function convertObject({ schema, name, nullable, defaultValue, options, mergedOptions }) {
1484
1554
  const properties = schema.properties ? Object.entries(schema.properties).map(([propName, propSchema]) => {
1485
1555
  const required = Array.isArray(schema.required) ? schema.required.includes(propName) : !!schema.required;
1486
1556
  const resolvedPropSchema = propSchema;
1487
1557
  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
1558
  return createProperty({
1500
1559
  name: propName,
1501
1560
  schema: {
1502
- ...isEnumNode && derivedPropName !== basePropName ? {
1503
- ...propNode,
1504
- name: derivedPropName
1505
- } : propNode,
1561
+ ...applyEnumName(convertSchema({
1562
+ schema: resolvedPropSchema,
1563
+ name: resolveChildName(name, propName)
1564
+ }, options), name, propName, mergedOptions.enumSuffix),
1506
1565
  nullable: propNullable || void 0,
1507
1566
  optional: !required && !propNullable ? true : void 0,
1508
1567
  nullish: !required && propNullable ? true : void 0
@@ -1524,7 +1583,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1524
1583
  properties,
1525
1584
  additionalProperties: additionalPropertiesNode,
1526
1585
  patternProperties,
1527
- ...buildSchemaBase(schema, name, nullable, defaultValue)
1586
+ ...renderSchemaBase(schema, name, nullable, defaultValue)
1528
1587
  });
1529
1588
  if (isDiscriminator(schema) && schema.discriminator.mapping) {
1530
1589
  const discPropName = schema.discriminator.propertyName;
@@ -1532,11 +1591,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1532
1591
  node: objectNode,
1533
1592
  propertyName: discPropName,
1534
1593
  values: Object.keys(schema.discriminator.mapping),
1535
- enumName: name ? pascalCase([
1536
- name,
1537
- discPropName,
1538
- mergedOptions.enumSuffix
1539
- ].filter(Boolean).join(" ")) : void 0
1594
+ enumName: name ? resolveEnumPropName(name, discPropName, mergedOptions.enumSuffix) : void 0
1540
1595
  });
1541
1596
  }
1542
1597
  return objectNode;
@@ -1555,7 +1610,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1555
1610
  rest: schema.items ? convertSchema({ schema: schema.items }, options) : void 0,
1556
1611
  min: schema.minItems,
1557
1612
  max: schema.maxItems,
1558
- ...buildSchemaBase(schema, name, nullable, defaultValue)
1613
+ ...renderSchemaBase(schema, name, nullable, defaultValue)
1559
1614
  });
1560
1615
  }
1561
1616
  /**
@@ -1566,7 +1621,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1566
1621
  */
1567
1622
  function convertArray({ schema, name, nullable, defaultValue, options, mergedOptions }) {
1568
1623
  const rawItems = schema.items;
1569
- const itemName = rawItems?.enum?.length && name ? pascalCase([name, mergedOptions.enumSuffix].join(" ")) : void 0;
1624
+ const itemName = rawItems?.enum?.length && name ? resolveEnumPropName(void 0, name, mergedOptions.enumSuffix) : void 0;
1570
1625
  return createSchema({
1571
1626
  type: "array",
1572
1627
  primitive: "array",
@@ -1577,7 +1632,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1577
1632
  min: schema.minItems,
1578
1633
  max: schema.maxItems,
1579
1634
  unique: schema.uniqueItems ?? void 0,
1580
- ...buildSchemaBase(schema, name, nullable, defaultValue)
1635
+ ...renderSchemaBase(schema, name, nullable, defaultValue)
1581
1636
  });
1582
1637
  }
1583
1638
  /**
@@ -1590,7 +1645,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1590
1645
  min: schema.minLength,
1591
1646
  max: schema.maxLength,
1592
1647
  pattern: schema.pattern,
1593
- ...buildSchemaBase(schema, name, nullable, defaultValue)
1648
+ ...renderSchemaBase(schema, name, nullable, defaultValue)
1594
1649
  });
1595
1650
  }
1596
1651
  /**
@@ -1604,7 +1659,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1604
1659
  max: schema.maximum,
1605
1660
  exclusiveMinimum: typeof schema.exclusiveMinimum === "number" ? schema.exclusiveMinimum : void 0,
1606
1661
  exclusiveMaximum: typeof schema.exclusiveMaximum === "number" ? schema.exclusiveMaximum : void 0,
1607
- ...buildSchemaBase(schema, name, nullable, defaultValue)
1662
+ ...renderSchemaBase(schema, name, nullable, defaultValue)
1608
1663
  });
1609
1664
  }
1610
1665
  /**
@@ -1614,7 +1669,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1614
1669
  return createSchema({
1615
1670
  type: "boolean",
1616
1671
  primitive: "boolean",
1617
- ...buildSchemaBase(schema, name, nullable, defaultValue)
1672
+ ...renderSchemaBase(schema, name, nullable, defaultValue)
1618
1673
  });
1619
1674
  }
1620
1675
  /**
@@ -1649,7 +1704,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1649
1704
  */
1650
1705
  function convertSchema({ schema, name }, options) {
1651
1706
  const mergedOptions = {
1652
- ...DEFAULT_OPTIONS,
1707
+ ...DEFAULT_PARSER_OPTIONS,
1653
1708
  ...options
1654
1709
  };
1655
1710
  const flattenedSchema = flattenSchema(schema);
@@ -1680,7 +1735,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1680
1735
  if (schema.type === "string" && schema.contentMediaType === "application/octet-stream") return createSchema({
1681
1736
  type: "blob",
1682
1737
  primitive: "string",
1683
- ...buildSchemaBase(schema, name, nullable, defaultValue)
1738
+ ...renderSchemaBase(schema, name, nullable, defaultValue)
1684
1739
  });
1685
1740
  if (Array.isArray(schema.type) && schema.type.length > 1) {
1686
1741
  const nonNullTypes = schema.type.filter((t) => t !== "null");
@@ -1694,7 +1749,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1694
1749
  },
1695
1750
  name
1696
1751
  }, options)),
1697
- ...buildSchemaBase(schema, name, arrayNullable, defaultValue)
1752
+ ...renderSchemaBase(schema, name, arrayNullable, defaultValue)
1698
1753
  });
1699
1754
  }
1700
1755
  if (!type) {
@@ -1742,18 +1797,26 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1742
1797
  function parseOperation(options, oas, operation) {
1743
1798
  const parameters = oas.getParameters(operation).map((param) => parseParameter(options, param));
1744
1799
  const requestBodySchema = oas.getRequestSchema(operation);
1745
- const requestBody = requestBodySchema ? convertSchema({ schema: requestBodySchema }, options) : void 0;
1800
+ const requestBodySchemaNode = requestBodySchema ? convertSchema({ schema: requestBodySchema }, options) : void 0;
1801
+ const requestBodyKeysToOmit = requestBodySchema?.properties ? Object.entries(requestBodySchema.properties).filter(([, prop]) => !isReference(prop) && prop.readOnly).map(([key]) => key) : void 0;
1802
+ const requestBody = requestBodySchemaNode ? {
1803
+ schema: requestBodySchemaNode,
1804
+ keysToOmit: requestBodyKeysToOmit?.length ? requestBodyKeysToOmit : void 0
1805
+ } : void 0;
1746
1806
  const responses = operation.getResponseStatusCodes().map((statusCode) => {
1747
1807
  const responseObj = operation.getResponseByStatusCode(statusCode);
1748
1808
  const responseSchema = oas.getResponseSchema(operation, statusCode);
1749
1809
  const schema = responseSchema && Object.keys(responseSchema).length > 0 ? convertSchema({ schema: responseSchema }, options) : createSchema({ type: resolveTypeOption(options.emptySchemaType) });
1750
1810
  const description = typeof responseObj === "object" && responseObj !== null && !Array.isArray(responseObj) ? responseObj.description : void 0;
1751
1811
  const rawContent = typeof responseObj === "object" && responseObj !== null && !Array.isArray(responseObj) ? responseObj.content : void 0;
1812
+ const mediaType = rawContent ? toMediaType(Object.keys(rawContent)[0] ?? "") : toMediaType(operation.contentType ?? "");
1813
+ const keysToOmit = responseSchema?.properties ? Object.entries(responseSchema.properties).filter(([, prop]) => !isReference(prop) && prop.writeOnly).map(([key]) => key) : void 0;
1752
1814
  return createResponse({
1753
1815
  statusCode,
1754
1816
  description,
1755
1817
  schema,
1756
- mediaType: rawContent ? toMediaType(Object.keys(rawContent)[0] ?? "") : toMediaType(operation.contentType ?? "")
1818
+ mediaType,
1819
+ keysToOmit: keysToOmit?.length ? keysToOmit : void 0
1757
1820
  });
1758
1821
  });
1759
1822
  return createOperation({
@@ -1775,7 +1838,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
1775
1838
  */
1776
1839
  function parse(options) {
1777
1840
  const mergedOptions = {
1778
- ...DEFAULT_OPTIONS,
1841
+ ...DEFAULT_PARSER_OPTIONS,
1779
1842
  ...options
1780
1843
  };
1781
1844
  const schemas = Object.entries(schemaObjects).map(([name, schemaObject]) => convertSchema({
@@ -1845,7 +1908,7 @@ const adapterOasName = "oas";
1845
1908
  * ```
1846
1909
  */
1847
1910
  const adapterOas = createAdapter((options) => {
1848
- const { validate = true, oasClass, contentType, serverIndex, serverVariables, discriminator = "strict", collisionDetection = false, dateType = "string", integerType = "number", unknownType = "any", emptySchemaType = unknownType } = options;
1911
+ 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
1912
  const nameMapping = /* @__PURE__ */ new Map();
1850
1913
  return {
1851
1914
  name: "oas",
@@ -1861,6 +1924,7 @@ const adapterOas = createAdapter((options) => {
1861
1924
  integerType,
1862
1925
  unknownType,
1863
1926
  emptySchemaType,
1927
+ enumSuffix,
1864
1928
  nameMapping
1865
1929
  },
1866
1930
  getImports(node, resolve) {
@@ -1893,7 +1957,8 @@ const adapterOas = createAdapter((options) => {
1893
1957
  dateType,
1894
1958
  integerType,
1895
1959
  unknownType,
1896
- emptySchemaType
1960
+ emptySchemaType,
1961
+ enumSuffix
1897
1962
  }),
1898
1963
  meta: {
1899
1964
  title: oas.api.info?.title,