@orval/core 8.2.0 → 8.4.0

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.mjs CHANGED
@@ -1,12 +1,13 @@
1
- import { t as __export } from "./chunk-C6wwvPpM.mjs";
2
- import { entries, groupBy, isArray, isEmptyish, prop, unique, uniqueBy, uniqueWith } from "remeda";
1
+ import { t as __export } from "./chunk-1-as6MWF.mjs";
2
+ import { createRequire } from "node:module";
3
+ import { entries, groupBy, isArray, isBoolean, isBoolean as isBoolean$1, isEmptyish, isFunction, isNullish, isNullish as isNullish$1, isNumber, isString, isString as isString$1, prop, unique, uniqueBy, uniqueWith } from "remeda";
3
4
  import { keyword } from "esutils";
4
5
  import path from "node:path";
5
- import fs from "node:fs";
6
- import { globby } from "globby";
7
6
  import { compare } from "compare-versions";
8
7
  import debug from "debug";
9
8
  import { pathToFileURL } from "node:url";
9
+ import fs, { existsSync, readFileSync } from "node:fs";
10
+ import { globby } from "globby";
10
11
  import readline from "node:readline";
11
12
  import chalk from "chalk";
12
13
  import { isDereferenced } from "@scalar/openapi-types/helpers";
@@ -108,124 +109,20 @@ const generalJSTypes = [
108
109
  "object",
109
110
  "blob"
110
111
  ];
111
- const generalJSTypesWithArray = generalJSTypes.reduce((acc, type) => {
112
- acc.push(type, `Array<${type}>`, `${type}[]`);
113
- return acc;
114
- }, []);
112
+ const generalJSTypesWithArray = generalJSTypes.flatMap((type) => [
113
+ type,
114
+ `Array<${type}>`,
115
+ `${type}[]`
116
+ ]);
115
117
  const VERBS_WITH_BODY = [
116
118
  Verbs.POST,
117
119
  Verbs.PUT,
118
120
  Verbs.PATCH,
119
121
  Verbs.DELETE
120
122
  ];
121
- const URL_REGEX = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$/;
123
+ const URL_REGEX = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!$&'()*+,;=.]+$/;
122
124
  const TEMPLATE_TAG_REGEX = /\${(.+?)}/g;
123
125
 
124
- //#endregion
125
- //#region src/utils/extension.ts
126
- function getExtension(path$2) {
127
- return path$2.toLowerCase().includes(".yaml") || path$2.toLowerCase().includes(".yml") ? "yaml" : "json";
128
- }
129
-
130
- //#endregion
131
- //#region src/utils/file.ts
132
- function getFileInfo(target = "", { backupFilename = "filename", extension = ".ts" } = {}) {
133
- const isDir = isDirectory(target);
134
- const filePath = isDir ? path.join(target, backupFilename + extension) : target;
135
- return {
136
- path: filePath,
137
- pathWithoutExtension: filePath.replace(/\.[^/.]+$/, ""),
138
- extension,
139
- isDirectory: isDir,
140
- dirname: path.dirname(filePath),
141
- filename: path.basename(filePath, extension.startsWith(".") ? extension : `.${extension}`)
142
- };
143
- }
144
- async function removeFilesAndEmptyFolders(patterns, dir) {
145
- const files = await globby(patterns, {
146
- cwd: dir,
147
- absolute: true
148
- });
149
- await Promise.all(files.map((file) => fs.promises.unlink(file)));
150
- const sortedDirectories = (await globby(["**/*"], {
151
- cwd: dir,
152
- absolute: true,
153
- onlyDirectories: true
154
- })).toSorted((a, b) => {
155
- const depthA = a.split("/").length;
156
- return b.split("/").length - depthA;
157
- });
158
- for (const directory of sortedDirectories) try {
159
- if ((await fs.promises.readdir(directory)).length === 0) await fs.promises.rmdir(directory);
160
- } catch {}
161
- }
162
-
163
- //#endregion
164
- //#region src/utils/path.ts
165
- var path_exports = /* @__PURE__ */ __export({
166
- basename: () => basename,
167
- dirname: () => dirname,
168
- extname: () => extname,
169
- getSchemaFileName: () => getSchemaFileName,
170
- isAbsolute: () => isAbsolute,
171
- join: () => join,
172
- joinSafe: () => joinSafe,
173
- normalizeSafe: () => normalizeSafe,
174
- relativeSafe: () => relativeSafe,
175
- resolve: () => resolve,
176
- separator: () => separator
177
- });
178
- const path$1 = {};
179
- const isFunction$1 = (val) => typeof val == "function";
180
- const isString$1 = (val) => {
181
- if (typeof val === "string") return true;
182
- if (typeof val === "object" && val !== null) return Object.toString.call(val) == "[object String]";
183
- return false;
184
- };
185
- for (const [propName, propValue] of Object.entries(path)) if (isFunction$1(propValue)) path$1[propName] = ((propName$1) => {
186
- return (...args) => {
187
- args = args.map((p) => {
188
- return isString$1(p) ? toUnix(p) : p;
189
- });
190
- const result = path[propName$1](...args);
191
- return isString$1(result) ? toUnix(result) : result;
192
- };
193
- })(propName);
194
- else path$1[propName] = propValue;
195
- const { join, resolve, extname, dirname, basename, isAbsolute } = path$1;
196
- /**
197
- * Behaves exactly like `path.relative(from, to)`, but keeps the first meaningful "./"
198
- */
199
- function relativeSafe(from, to) {
200
- return normalizeSafe(`.${separator}${path$1.relative(from, to)}`);
201
- }
202
- function getSchemaFileName(path$2) {
203
- return path$2.replace(`.${getExtension(path$2)}`, "").slice(path$2.lastIndexOf("/") + 1);
204
- }
205
- const separator = "/";
206
- const toUnix = function(value) {
207
- value = value.replaceAll("\\", "/");
208
- value = value.replaceAll(/(?<!^)\/+/g, "/");
209
- return value;
210
- };
211
- function normalizeSafe(value) {
212
- let result;
213
- value = toUnix(value);
214
- result = path$1.normalize(value);
215
- if (value.startsWith("./") && !result.startsWith("./") && !result.startsWith("..")) result = "./" + result;
216
- else if (value.startsWith("//") && !result.startsWith("//")) result = value.startsWith("//./") ? "//." + result : "/" + result;
217
- return result;
218
- }
219
- function joinSafe(...values) {
220
- let result = path$1.join(...values);
221
- if (values.length > 0) {
222
- const firstValue = toUnix(values[0]);
223
- if (firstValue.startsWith("./") && !result.startsWith("./") && !result.startsWith("..")) result = "./" + result;
224
- else if (firstValue.startsWith("//") && !result.startsWith("//")) result = firstValue.startsWith("//./") ? "//." + result : "/" + result;
225
- }
226
- return result;
227
- }
228
-
229
126
  //#endregion
230
127
  //#region src/utils/assertion.ts
231
128
  /**
@@ -234,42 +131,29 @@ function joinSafe(...values) {
234
131
  * @param property
235
132
  */
236
133
  function isReference(obj) {
237
- return !isNull(obj) && Object.hasOwn(obj, "$ref");
134
+ return !isNullish$1(obj) && Object.hasOwn(obj, "$ref");
238
135
  }
239
- function isDirectory(path$2) {
240
- return !extname(path$2);
136
+ function isDirectory(pathValue) {
137
+ return !path.extname(pathValue);
241
138
  }
242
139
  function isObject(x) {
243
140
  return Object.prototype.toString.call(x) === "[object Object]";
244
141
  }
142
+ function isStringLike(val) {
143
+ if (isString$1(val)) return true;
144
+ return Object.prototype.toString.call(val) === "[object String]";
145
+ }
245
146
  function isModule(x) {
246
147
  return Object.prototype.toString.call(x) === "[object Module]";
247
148
  }
248
- function isString(x) {
249
- return typeof x === "string";
250
- }
251
- function isNumber(x) {
252
- return typeof x === "number";
253
- }
254
149
  function isNumeric(x) {
255
- return /^-?\d+$/.test(x);
256
- }
257
- function isBoolean(x) {
258
- return typeof x === "boolean";
259
- }
260
- function isFunction(x) {
261
- return typeof x === "function";
262
- }
263
- function isUndefined(x) {
264
- return x === void 0;
265
- }
266
- function isNull(x) {
267
- return x === null;
150
+ if (typeof x === "number") return Number.isInteger(x);
151
+ return isString$1(x) && /^-?\d+$/.test(x);
268
152
  }
269
153
  function isSchema(x) {
270
154
  if (!isObject(x)) return false;
271
- if (isString(x.type) && Object.values(SchemaType).includes(x.type)) return true;
272
- const combine = x.allOf || x.anyOf || x.oneOf;
155
+ if (isString$1(x.type) && Object.values(SchemaType).includes(x.type)) return true;
156
+ const combine = x.allOf ?? x.anyOf ?? x.oneOf;
273
157
  if (Array.isArray(combine)) return true;
274
158
  if (isObject(x.properties)) return true;
275
159
  return false;
@@ -278,27 +162,26 @@ function isVerb(verb) {
278
162
  return Object.values(Verbs).includes(verb);
279
163
  }
280
164
  function isUrl(str) {
281
- let givenURL;
165
+ if (!str.trim()) return false;
282
166
  try {
283
- givenURL = new URL(str);
167
+ const url = new URL(str);
168
+ return ["http:", "https:"].includes(url.protocol);
284
169
  } catch {
285
170
  return false;
286
171
  }
287
- return givenURL.protocol === "http:" || givenURL.protocol === "https:";
288
172
  }
289
173
 
290
174
  //#endregion
291
175
  //#region src/utils/async-reduce.ts
292
176
  async function asyncReduce(array, reducer, initValue) {
293
- let accumulate = typeof initValue === "object" ? Object.create(initValue) : initValue;
177
+ let accumulate = initValue === null || initValue === Object(initValue) && !isFunction(initValue) ? Object.create(initValue) : initValue;
294
178
  for (const item of array) accumulate = await reducer(accumulate, item);
295
179
  return accumulate;
296
180
  }
297
181
 
298
182
  //#endregion
299
183
  //#region src/utils/case.ts
300
- const unicodes = function(s, prefix) {
301
- prefix = prefix || "";
184
+ const unicodes = function(s, prefix = "") {
302
185
  return s.replaceAll(/(^|-)/g, String.raw`$1\u` + prefix).replaceAll(",", String.raw`\u` + prefix);
303
186
  };
304
187
  const symbols = unicodes("20-26,28-2F,3A-40,5B-60,7B-7E,A0-BF,D7,F7", "00");
@@ -320,8 +203,8 @@ const regexps = {
320
203
  const deapostrophe = (s) => {
321
204
  return s.replace(regexps.apostrophe, "");
322
205
  };
323
- const up = String.prototype.toUpperCase;
324
- const low = String.prototype.toLowerCase;
206
+ const up = (s) => s.toUpperCase();
207
+ const low = (s) => s.toLowerCase();
325
208
  const fill = (s, fillWith, isDeapostrophe = false) => {
326
209
  s = s.replace(regexps.fill, function(m, next) {
327
210
  return next ? fillWith + next : "";
@@ -330,14 +213,13 @@ const fill = (s, fillWith, isDeapostrophe = false) => {
330
213
  return s;
331
214
  };
332
215
  const decap = (s, char = 0) => {
333
- return low.call(s.charAt(char)) + s.slice(char + 1);
216
+ return low(s.charAt(char)) + s.slice(char + 1);
334
217
  };
335
218
  const relax = (m, before, acronym, caps) => {
336
219
  return before + " " + (acronym ? acronym + " " : "") + caps;
337
220
  };
338
221
  const prep = (s, isFill = false, isPascal = false, isUpper = false) => {
339
- s = s == void 0 ? "" : s + "";
340
- if (!isUpper && regexps.upper.test(s)) s = low.call(s);
222
+ if (!isUpper && regexps.upper.test(s)) s = low(s);
341
223
  if (!isFill && !regexps.hole.test(s)) {
342
224
  var holey = fill(s, " ");
343
225
  if (regexps.hole.test(holey)) s = holey;
@@ -346,20 +228,20 @@ const prep = (s, isFill = false, isPascal = false, isUpper = false) => {
346
228
  return s;
347
229
  };
348
230
  const lower = (s, fillWith, isDeapostrophe) => {
349
- return fill(low.call(prep(s, !!fillWith)), fillWith, isDeapostrophe);
231
+ return fill(low(prep(s, !!fillWith)), fillWith, isDeapostrophe);
350
232
  };
351
233
  const pascalMemory = {};
352
- function pascal(s) {
234
+ function pascal(s = "") {
353
235
  if (pascalMemory[s]) return pascalMemory[s];
354
- const isStartWithUnderscore = s?.startsWith("_");
355
- if (regexps.upper.test(s)) s = low.call(s);
356
- const pascalString = (s?.match(/[a-zA-Z0-9\u00C0-\u017F]+/g) || []).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
236
+ const isStartWithUnderscore = s.startsWith("_");
237
+ if (regexps.upper.test(s)) s = low(s);
238
+ const pascalString = (s.match(/[a-zA-Z0-9\u00C0-\u017F]+/g) ?? []).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
357
239
  const pascalWithUnderscore = isStartWithUnderscore ? `_${pascalString}` : pascalString;
358
240
  pascalMemory[s] = pascalWithUnderscore;
359
241
  return pascalWithUnderscore;
360
242
  }
361
- function camel(s) {
362
- const isStartWithUnderscore = s?.startsWith("_");
243
+ function camel(s = "") {
244
+ const isStartWithUnderscore = s.startsWith("_");
363
245
  const camelString = decap(pascal(s), isStartWithUnderscore ? 1 : 0);
364
246
  return isStartWithUnderscore ? `_${camelString}` : camelString;
365
247
  }
@@ -370,7 +252,7 @@ function kebab(s) {
370
252
  return lower(s, "-", true);
371
253
  }
372
254
  function upper(s, fillWith, isDeapostrophe) {
373
- return fill(up.call(prep(s, !!fillWith, false, true)), fillWith, isDeapostrophe);
255
+ return fill(up(prep(s, !!fillWith, false, true)), fillWith, isDeapostrophe);
374
256
  }
375
257
  function conventionName(name, convention) {
376
258
  let nameConventionTransform = camel;
@@ -388,6 +270,14 @@ function conventionName(name, convention) {
388
270
  return nameConventionTransform(name);
389
271
  }
390
272
 
273
+ //#endregion
274
+ //#region src/utils/compare-version.ts
275
+ function compareVersions(firstVersion, secondVersions, operator = ">=") {
276
+ if (firstVersion === "latest" || firstVersion === "*") return true;
277
+ if (firstVersion.startsWith("catalog:")) return true;
278
+ return compare(firstVersion.replace(/(\s(.*))/, ""), secondVersions, operator);
279
+ }
280
+
391
281
  //#endregion
392
282
  //#region src/utils/content-type.ts
393
283
  /**
@@ -435,16 +325,38 @@ function isBinaryContentType(contentType) {
435
325
  function getFormDataFieldFileType(resolvedSchema, partContentType) {
436
326
  if (resolvedSchema.type !== "string") return;
437
327
  if (resolvedSchema.contentEncoding) return;
438
- const effectiveContentType = partContentType ?? resolvedSchema.contentMediaType;
328
+ const contentMediaType = resolvedSchema.contentMediaType;
329
+ const effectiveContentType = partContentType ?? contentMediaType;
439
330
  if (effectiveContentType) return isBinaryContentType(effectiveContentType) ? "binary" : "text";
440
331
  }
441
-
442
- //#endregion
443
- //#region src/utils/compare-version.ts
444
- function compareVersions(firstVersion, secondVersions, operator = ">=") {
445
- if (firstVersion === "latest" || firstVersion === "*") return true;
446
- if (firstVersion.startsWith("catalog:")) return true;
447
- return compare(firstVersion.replace(/(\s(.*))/, ""), secondVersions, operator);
332
+ /**
333
+ * Filters items by content type based on include/exclude rules
334
+ *
335
+ * @param items - Array of items with contentType property
336
+ * @param filter - Optional filter configuration
337
+ * @returns Filtered array
338
+ *
339
+ * @example
340
+ * ```ts
341
+ * const types = [
342
+ * { contentType: 'application/json', value: '...' },
343
+ * { contentType: 'text/xml', value: '...' }
344
+ * ];
345
+ *
346
+ * // Include only JSON
347
+ * filterByContentType(types, { include: ['application/json'] });
348
+ *
349
+ * // Exclude XML
350
+ * filterByContentType(types, { exclude: ['text/xml'] });
351
+ * ```
352
+ */
353
+ function filterByContentType(items, filter$1) {
354
+ if (!filter$1) return items;
355
+ return items.filter((item) => {
356
+ const shouldInclude = !filter$1.include || filter$1.include.includes(item.contentType);
357
+ const shouldExclude = filter$1.exclude?.includes(item.contentType) ?? false;
358
+ return shouldInclude && !shouldExclude;
359
+ });
448
360
  }
449
361
 
450
362
  //#endregion
@@ -454,7 +366,7 @@ const DEBUG = process.env.DEBUG;
454
366
  function createDebugger(ns, options = {}) {
455
367
  const log$1 = debug(ns);
456
368
  const { onlyWhenFocused } = options;
457
- const focus = typeof onlyWhenFocused === "string" ? onlyWhenFocused : ns;
369
+ const focus = isString(onlyWhenFocused) ? onlyWhenFocused : ns;
458
370
  return (msg, ...args) => {
459
371
  if (filter && !msg.includes(filter)) return;
460
372
  if (onlyWhenFocused && !DEBUG?.includes(focus)) return;
@@ -468,13 +380,13 @@ const search = String.raw`\*/`;
468
380
  const replacement = String.raw`*\/`;
469
381
  const regex$1 = new RegExp(search, "g");
470
382
  function jsDoc(schema, tryOneLine = false, context) {
471
- if (context?.output?.override?.jsDoc) {
383
+ if (context?.output.override.jsDoc) {
472
384
  const { filter: filter$1 } = context.output.override.jsDoc;
473
385
  if (filter$1) return keyValuePairsToJsDoc(filter$1(schema));
474
386
  }
475
387
  const { description, deprecated, summary, minLength, maxLength, minimum, maximum, exclusiveMinimum, exclusiveMaximum, minItems, maxItems, pattern } = schema;
476
388
  const isNullable = schema.type === "null" || Array.isArray(schema.type) && schema.type.includes("null");
477
- const lines = (Array.isArray(description) ? description.filter((d) => !d.includes("eslint-disable")) : [description || ""]).map((line) => line.replaceAll(regex$1, replacement));
389
+ const lines = (Array.isArray(description) ? description.filter((d) => !d.includes("eslint-disable")) : [description ?? ""]).map((line) => line.replaceAll(regex$1, replacement));
478
390
  const count$1 = [
479
391
  description,
480
392
  deprecated,
@@ -489,7 +401,7 @@ function jsDoc(schema, tryOneLine = false, context) {
489
401
  maxItems?.toString(),
490
402
  isNullable ? "null" : "",
491
403
  pattern
492
- ].reduce((acc, it) => it ? acc + 1 : acc, 0);
404
+ ].filter(Boolean).length;
493
405
  if (!count$1) return "";
494
406
  const oneLine = count$1 === 1 && tryOneLine;
495
407
  const eslintDisable = Array.isArray(description) ? description.find((d) => d.includes("eslint-disable"))?.replaceAll(regex$1, replacement) : void 0;
@@ -556,10 +468,49 @@ async function dynamicImport(toImport, from = process.cwd(), takeDefault = true)
556
468
  }
557
469
  return toImport;
558
470
  } catch (error) {
559
- throw new Error(`Oups... 🍻. Path: ${toImport} => ${error}`);
471
+ throw new Error(`Oups... 🍻. Path: ${String(toImport)} => ${String(error)}`);
560
472
  }
561
473
  }
562
474
 
475
+ //#endregion
476
+ //#region src/utils/extension.ts
477
+ function getExtension(path$2) {
478
+ return path$2.toLowerCase().includes(".yaml") || path$2.toLowerCase().includes(".yml") ? "yaml" : "json";
479
+ }
480
+
481
+ //#endregion
482
+ //#region src/utils/file.ts
483
+ function getFileInfo(target = "", { backupFilename = "filename", extension = ".ts" } = {}) {
484
+ const isDir = isDirectory(target);
485
+ const filePath = isDir ? path.join(target, backupFilename + extension) : target;
486
+ return {
487
+ path: filePath,
488
+ pathWithoutExtension: filePath.replace(/\.[^/.]+$/, ""),
489
+ extension,
490
+ isDirectory: isDir,
491
+ dirname: path.dirname(filePath),
492
+ filename: path.basename(filePath, extension.startsWith(".") ? extension : `.${extension}`)
493
+ };
494
+ }
495
+ async function removeFilesAndEmptyFolders(patterns, dir) {
496
+ const files = await globby(patterns, {
497
+ cwd: dir,
498
+ absolute: true
499
+ });
500
+ await Promise.all(files.map((file) => fs.promises.unlink(file)));
501
+ const sortedDirectories = (await globby(["**/*"], {
502
+ cwd: dir,
503
+ absolute: true,
504
+ onlyDirectories: true
505
+ })).toSorted((a, b) => {
506
+ const depthA = a.split("/").length;
507
+ return b.split("/").length - depthA;
508
+ });
509
+ for (const directory of sortedDirectories) try {
510
+ if ((await fs.promises.readdir(directory)).length === 0) await fs.promises.rmdir(directory);
511
+ } catch {}
512
+ }
513
+
563
514
  //#endregion
564
515
  //#region src/utils/file-extensions.ts
565
516
  function getMockFileExtensionByTypeName(mock) {
@@ -608,7 +559,7 @@ function logError(err, tag) {
608
559
  if (err instanceof Error) {
609
560
  message = (err.message || err.stack) ?? "Unknown error";
610
561
  if (err.cause) {
611
- const causeMsg = err.cause instanceof Error ? err.cause.message : typeof err.cause === "string" ? err.cause : JSON.stringify(err.cause, void 0, 2);
562
+ const causeMsg = err.cause instanceof Error ? err.cause.message : isString(err.cause) ? err.cause : JSON.stringify(err.cause, void 0, 2);
612
563
  message += `\n Cause: ${causeMsg}`;
613
564
  }
614
565
  } else message = String(err);
@@ -695,16 +646,16 @@ function createLogger(level = "info", options = {}) {
695
646
 
696
647
  //#endregion
697
648
  //#region src/utils/merge-deep.ts
698
- const isObject$1 = (obj) => obj && typeof obj === "object";
699
649
  function mergeDeep(source, target) {
700
- if (!isObject$1(target) || !isObject$1(source)) return source;
701
- return Object.entries(target).reduce((acc, [key, value]) => {
650
+ if (!isObject(target) || !isObject(source)) return source;
651
+ const acc = Object.assign({}, source);
652
+ for (const [key, value] of Object.entries(target)) {
702
653
  const sourceValue = acc[key];
703
654
  if (Array.isArray(sourceValue) && Array.isArray(value)) acc[key] = [...sourceValue, ...value];
704
- else if (isObject$1(sourceValue) && isObject$1(value)) acc[key] = mergeDeep(sourceValue, value);
655
+ else if (isObject(sourceValue) && isObject(value)) acc[key] = mergeDeep(sourceValue, value);
705
656
  else acc[key] = value;
706
- return acc;
707
- }, Object.assign({}, source));
657
+ }
658
+ return acc;
708
659
  }
709
660
 
710
661
  //#endregion
@@ -714,9 +665,106 @@ function count(str = "", key) {
714
665
  return (str.match(new RegExp(key, "g")) ?? []).length;
715
666
  }
716
667
 
668
+ //#endregion
669
+ //#region src/utils/path.ts
670
+ var path_exports = /* @__PURE__ */ __export({
671
+ basename: () => basename,
672
+ dirname: () => dirname,
673
+ extname: () => extname,
674
+ getSchemaFileName: () => getSchemaFileName,
675
+ isAbsolute: () => isAbsolute,
676
+ join: () => join,
677
+ joinSafe: () => joinSafe,
678
+ normalizeSafe: () => normalizeSafe,
679
+ relativeSafe: () => relativeSafe,
680
+ resolve: () => resolve,
681
+ separator: () => separator
682
+ });
683
+ function wrapPathFn(fn) {
684
+ return (...args) => {
685
+ const result = fn(...args.map((p) => isStringLike(p) ? toUnix(p) : p));
686
+ return isStringLike(result) ? toUnix(result) : result;
687
+ };
688
+ }
689
+ const path$1 = Object.fromEntries(Object.entries(path).map(([key, value]) => [key, isFunction(value) ? wrapPathFn(value) : value]));
690
+ const { join, resolve, extname, dirname, basename, isAbsolute } = path$1;
691
+ /**
692
+ * Behaves exactly like `path.relative(from, to)`, but keeps the first meaningful "./"
693
+ */
694
+ function relativeSafe(from, to) {
695
+ return normalizeSafe(`.${separator}${path$1.relative(from, to)}`);
696
+ }
697
+ function getSchemaFileName(path$2) {
698
+ return path$2.replace(`.${getExtension(path$2)}`, "").slice(path$2.lastIndexOf("/") + 1);
699
+ }
700
+ const separator = "/";
701
+ const toUnix = function(value) {
702
+ value = value.replaceAll("\\", "/");
703
+ value = value.replaceAll(/(?<!^)\/+/g, "/");
704
+ return value;
705
+ };
706
+ function normalizeSafe(value) {
707
+ let result;
708
+ value = toUnix(value);
709
+ result = path$1.normalize(value);
710
+ if (value.startsWith("./") && !result.startsWith("./") && !result.startsWith("..")) result = "./" + result;
711
+ else if (value.startsWith("//") && !result.startsWith("//")) result = value.startsWith("//./") ? "//." + result : "/" + result;
712
+ return result;
713
+ }
714
+ function joinSafe(...values) {
715
+ let result = path$1.join(...values);
716
+ if (values.length > 0) {
717
+ const firstValue = toUnix(values[0]);
718
+ if (firstValue.startsWith("./") && !result.startsWith("./") && !result.startsWith("..")) result = "./" + result;
719
+ else if (firstValue.startsWith("//") && !result.startsWith("//")) result = firstValue.startsWith("//./") ? "//." + result : "/" + result;
720
+ }
721
+ return result;
722
+ }
723
+
724
+ //#endregion
725
+ //#region src/utils/resolve-version.ts
726
+ function resolveInstalledVersion(packageName, fromDir) {
727
+ try {
728
+ const require = createRequire(path.join(fromDir, "noop.js"));
729
+ try {
730
+ return require(`${packageName}/package.json`).version;
731
+ } catch (directError) {
732
+ if (directError instanceof Error && "code" in directError && directError.code === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
733
+ const entryPath = require.resolve(packageName);
734
+ let dir = path.dirname(entryPath);
735
+ while (dir !== path.parse(dir).root) {
736
+ const pkgPath = path.join(dir, "package.json");
737
+ if (existsSync(pkgPath)) {
738
+ const pkgData = JSON.parse(readFileSync(pkgPath, "utf8"));
739
+ if (pkgData.name === packageName) return pkgData.version;
740
+ }
741
+ dir = path.dirname(dir);
742
+ }
743
+ return;
744
+ }
745
+ throw directError;
746
+ }
747
+ } catch {
748
+ return;
749
+ }
750
+ }
751
+ function resolveInstalledVersions(packageJson, fromDir) {
752
+ const resolved = {};
753
+ const allDeps = new Set([
754
+ ...Object.keys(packageJson.dependencies ?? {}),
755
+ ...Object.keys(packageJson.devDependencies ?? {}),
756
+ ...Object.keys(packageJson.peerDependencies ?? {})
757
+ ]);
758
+ for (const pkgName of allDeps) {
759
+ const version = resolveInstalledVersion(pkgName, fromDir);
760
+ if (version) resolved[pkgName] = version;
761
+ }
762
+ return resolved;
763
+ }
764
+
717
765
  //#endregion
718
766
  //#region src/utils/sort.ts
719
- const sortByPriority = (arr) => arr.sort((a, b) => {
767
+ const sortByPriority = (arr) => arr.toSorted((a, b) => {
720
768
  if (a.default) return 1;
721
769
  if (b.default) return -1;
722
770
  if (a.required && b.required) return 0;
@@ -740,17 +788,20 @@ const sortByPriority = (arr) => arr.sort((a, b) => {
740
788
  * stringify({ a: 1, b: 'test' }) // returns "{ a: 1, b: 'test', }"
741
789
  */
742
790
  function stringify(data) {
743
- if (isUndefined(data) || isNull(data)) return;
791
+ if (isNullish$1(data)) return;
744
792
  if (isString(data)) return `'${data.replaceAll("'", String.raw`\'`)}'`;
745
- if (isNumber(data) || isBoolean(data) || isFunction(data)) return `${data}`;
746
- if (Array.isArray(data)) return `[${data.map(stringify).join(", ")}]`;
747
- return Object.entries(data).reduce((acc, [key, value], index, arr) => {
793
+ if (isNumber(data) || isBoolean(data) || isFunction(data)) return String(data);
794
+ if (Array.isArray(data)) return `[${data.map((item) => stringify(item)).join(", ")}]`;
795
+ const entries$1 = Object.entries(data);
796
+ let result = "";
797
+ for (const [index, [key, value]] of entries$1.entries()) {
748
798
  const strValue = stringify(value);
749
- if (arr.length === 1) return `{ ${key}: ${strValue}, }`;
750
- if (!index) return `{ ${key}: ${strValue}, `;
751
- if (arr.length - 1 === index) return acc + `${key}: ${strValue}, }`;
752
- return acc + `${key}: ${strValue}, `;
753
- }, "");
799
+ if (entries$1.length === 1) result = `{ ${key}: ${strValue}, }`;
800
+ else if (!index) result = `{ ${key}: ${strValue}, `;
801
+ else if (entries$1.length - 1 === index) result += `${key}: ${strValue}, }`;
802
+ else result += `${key}: ${strValue}, `;
803
+ }
804
+ return result;
754
805
  }
755
806
  /**
756
807
  * Sanitizes a string value by removing or replacing special characters and ensuring
@@ -774,7 +825,7 @@ function stringify(data) {
774
825
  function sanitize(value, options) {
775
826
  const { whitespace = "", underscore = "", dot = "", dash = "", es5keyword = false, es5IdentifierName = false, special = false } = options ?? {};
776
827
  let newValue = value;
777
- if (!special) newValue = newValue.replaceAll(/[!"`'#%&,:;<>=@{}~\$\(\)\*\+\/\\\?\[\]\^\|]/g, "");
828
+ if (!special) newValue = newValue.replaceAll(/[!"`'#%&,:;<>=@{}~$()*+/\\?[\]^|]/g, "");
778
829
  if (whitespace !== true) newValue = newValue.replaceAll(/[\s]/g, whitespace);
779
830
  if (underscore !== true) newValue = newValue.replaceAll(/['_']/g, underscore);
780
831
  if (dot !== true) newValue = newValue.replaceAll(/[.]/g, dot);
@@ -799,7 +850,11 @@ function sanitize(value, options) {
799
850
  */
800
851
  function toObjectString(props, path$2) {
801
852
  if (props.length === 0) return "";
802
- return (typeof path$2 === "string" ? props.map((prop$1) => path$2.split(".").reduce((obj, key) => obj && typeof obj === "object" ? obj[key] : void 0, prop$1)) : props).join(",\n ") + ",";
853
+ return (isString(path$2) ? props.map((prop$1) => {
854
+ let obj = prop$1;
855
+ for (const key of path$2.split(".")) obj = obj && (isObject(obj) || Array.isArray(obj)) ? obj[key] : void 0;
856
+ return obj;
857
+ }) : props).join(",\n ") + ",";
803
858
  }
804
859
  const NUMBERS = {
805
860
  "0": "zero",
@@ -823,7 +878,7 @@ const NUMBERS = {
823
878
  * getNumberWord(42) // returns "fourtwo"
824
879
  */
825
880
  function getNumberWord(num) {
826
- return num.toString().split("").reduce((acc, n) => acc + NUMBERS[n], "");
881
+ return [...num.toString()].reduce((acc, n) => acc + NUMBERS[n], "");
827
882
  }
828
883
  /**
829
884
  * Escapes a specific character in a string by prefixing it with a backslash.
@@ -917,8 +972,7 @@ function getEnumDescriptions(schemaObject) {
917
972
  function getEnum(value, enumName, names, enumGenerationType, descriptions, enumNamingConvention) {
918
973
  if (enumGenerationType === EnumGeneration.CONST) return getTypeConstEnum(value, enumName, names, descriptions, enumNamingConvention);
919
974
  if (enumGenerationType === EnumGeneration.ENUM) return getNativeEnum(value, enumName, names, enumNamingConvention);
920
- if (enumGenerationType === EnumGeneration.UNION) return getUnion(value, enumName);
921
- throw new Error(`Invalid enumGenerationType: ${enumGenerationType}`);
975
+ return getUnion(value, enumName);
922
976
  }
923
977
  const getTypeConstEnum = (value, enumName, names, descriptions, enumNamingConvention) => {
924
978
  let enumValue = `export type ${enumName} = typeof ${enumName}[keyof typeof ${enumName}]`;
@@ -934,11 +988,16 @@ const getTypeConstEnum = (value, enumName, names, descriptions, enumNamingConven
934
988
  };
935
989
  function getEnumImplementation(value, names, descriptions, enumNamingConvention) {
936
990
  if (value === "") return "";
937
- return [...new Set(value.split(" | "))].reduce((acc, val, index) => {
991
+ const uniqueValues = [...new Set(value.split(" | "))];
992
+ let result = "";
993
+ for (const [index, val] of uniqueValues.entries()) {
938
994
  const name = names?.[index];
939
995
  const description = descriptions?.[index];
940
996
  const comment = description ? ` /** ${description} */\n` : "";
941
- if (name) return acc + comment + ` ${keyword.isIdentifierNameES5(name) ? name : `'${name}'`}: ${val},\n`;
997
+ if (name) {
998
+ result += comment + ` ${keyword.isIdentifierNameES5(name) ? name : `'${name}'`}: ${val},\n`;
999
+ continue;
1000
+ }
942
1001
  let key = val.startsWith("'") ? val.slice(1, -1) : val;
943
1002
  if (isNumeric(key)) key = toNumberKey(key);
944
1003
  if (key.length > 1) key = sanitize(key, {
@@ -948,17 +1007,23 @@ function getEnumImplementation(value, names, descriptions, enumNamingConvention)
948
1007
  special: true
949
1008
  });
950
1009
  if (enumNamingConvention) key = conventionName(key, enumNamingConvention);
951
- return acc + comment + ` ${keyword.isIdentifierNameES5(key) ? key : `'${key}'`}: ${val},\n`;
952
- }, "");
1010
+ result += comment + ` ${keyword.isIdentifierNameES5(key) ? key : `'${key}'`}: ${val},\n`;
1011
+ }
1012
+ return result;
953
1013
  }
954
1014
  const getNativeEnum = (value, enumName, names, enumNamingConvention) => {
955
1015
  return `export enum ${enumName} {\n${getNativeEnumItems(value, names, enumNamingConvention)}\n}`;
956
1016
  };
957
1017
  const getNativeEnumItems = (value, names, enumNamingConvention) => {
958
1018
  if (value === "") return "";
959
- return [...new Set(value.split(" | "))].reduce((acc, val, index) => {
1019
+ const uniqueValues = [...new Set(value.split(" | "))];
1020
+ let result = "";
1021
+ for (const [index, val] of uniqueValues.entries()) {
960
1022
  const name = names?.[index];
961
- if (name) return acc + ` ${keyword.isIdentifierNameES5(name) ? name : `'${name}'`}= ${val},\n`;
1023
+ if (name) {
1024
+ result += ` ${keyword.isIdentifierNameES5(name) ? name : `'${name}'`}= ${val},\n`;
1025
+ continue;
1026
+ }
962
1027
  let key = val.startsWith("'") ? val.slice(1, -1) : val;
963
1028
  if (isNumeric(key)) key = toNumberKey(key);
964
1029
  if (key.length > 1) key = sanitize(key, {
@@ -968,8 +1033,9 @@ const getNativeEnumItems = (value, names, enumNamingConvention) => {
968
1033
  special: true
969
1034
  });
970
1035
  if (enumNamingConvention) key = conventionName(key, enumNamingConvention);
971
- return acc + ` ${keyword.isIdentifierNameES5(key) ? key : `'${key}'`}= ${val},\n`;
972
- }, "");
1036
+ result += ` ${keyword.isIdentifierNameES5(key) ? key : `'${key}'`}= ${val},\n`;
1037
+ }
1038
+ return result;
973
1039
  };
974
1040
  const toNumberKey = (value) => {
975
1041
  if (value.startsWith("-")) return `NUMBER_MINUS_${value.slice(1)}`;
@@ -981,9 +1047,9 @@ const getUnion = (value, enumName) => {
981
1047
  };
982
1048
  function getEnumUnionFromSchema(schema) {
983
1049
  if (!schema?.enum) return "";
984
- return schema.enum.filter((val) => val !== null).map((val) => isString(val) ? `'${escape(val)}'` : `${val}`).join(" | ");
1050
+ return schema.enum.filter((val) => val !== null).map((val) => isString(val) ? `'${escape(val)}'` : String(val)).join(" | ");
985
1051
  }
986
- const stripNullUnion = (value) => value.replace(/\s*\|\s*null/g, "").trim();
1052
+ const stripNullUnion = (value) => value.replaceAll(/\s*\|\s*null/g, "").trim();
987
1053
  const isSpreadableEnumRef = (schema, refName) => {
988
1054
  if (!schema?.enum || !refName) return false;
989
1055
  if (!getEnumUnionFromSchema(schema)) return false;
@@ -1129,17 +1195,23 @@ function getSchema$1(schema, context) {
1129
1195
  const refInfo = getRefInfo(schema.$ref, context);
1130
1196
  const { refPaths } = refInfo;
1131
1197
  let schemaByRefPaths = Array.isArray(refPaths) ? prop(context.spec, ...refPaths) : void 0;
1132
- if (!schemaByRefPaths) schemaByRefPaths = context.spec;
1198
+ schemaByRefPaths ??= context.spec;
1133
1199
  if (isReference(schemaByRefPaths)) return getSchema$1(schemaByRefPaths, context);
1134
- let currentSchema = schemaByRefPaths ? schemaByRefPaths : context.spec;
1135
- if ("nullable" in schema) currentSchema = {
1136
- ...currentSchema,
1137
- nullable: schema.nullable
1138
- };
1139
- if ("type" in schema && Array.isArray(schema.type)) currentSchema = {
1140
- ...currentSchema,
1141
- type: schema.type
1142
- };
1200
+ let currentSchema = schemaByRefPaths || context.spec;
1201
+ if ("nullable" in schema) {
1202
+ const nullable = schema.nullable;
1203
+ currentSchema = {
1204
+ ...currentSchema,
1205
+ nullable
1206
+ };
1207
+ }
1208
+ if ("type" in schema && Array.isArray(schema.type)) {
1209
+ const type = schema.type;
1210
+ currentSchema = {
1211
+ ...currentSchema,
1212
+ type
1213
+ };
1214
+ }
1143
1215
  return {
1144
1216
  currentSchema,
1145
1217
  refInfo
@@ -1153,14 +1225,11 @@ function resolveExampleRefs(examples, context) {
1153
1225
  return schema.value;
1154
1226
  }
1155
1227
  return example;
1156
- }) : Object.entries(examples).reduce((acc, [key, example]) => {
1157
- let schema = example;
1158
- if (isReference(example)) schema = resolveRef(example, context).schema.value;
1159
- return {
1160
- ...acc,
1161
- [key]: schema
1162
- };
1163
- }, {});
1228
+ }) : (() => {
1229
+ const result = {};
1230
+ for (const [key, example] of Object.entries(examples)) result[key] = isReference(example) ? resolveRef(example, context).schema.value : example;
1231
+ return result;
1232
+ })();
1164
1233
  }
1165
1234
 
1166
1235
  //#endregion
@@ -1179,7 +1248,8 @@ function resolveValue({ schema, name, context, formDataContext }) {
1179
1248
  parents: [...context.parents ?? [], refName]
1180
1249
  }
1181
1250
  }).hasReadonlyProps;
1182
- const nullable = Array.isArray(schemaObject.type) && schemaObject.type.includes("null") || schemaObject.nullable === true ? " | null" : "";
1251
+ const isAnyOfNullable = schemaObject.anyOf?.some((anyOfItem) => !isReference(anyOfItem) && (anyOfItem.type === "null" || Array.isArray(anyOfItem.type) && anyOfItem.type.includes("null")));
1252
+ const nullable = Array.isArray(schemaObject.type) && schemaObject.type.includes("null") || schemaObject.nullable === true || isAnyOfNullable ? " | null" : "";
1183
1253
  return {
1184
1254
  value: resolvedImport.name + nullable,
1185
1255
  imports: [{
@@ -1216,7 +1286,7 @@ function resolveValue({ schema, name, context, formDataContext }) {
1216
1286
  function createTypeAliasIfNeeded({ resolvedValue, propName, context }) {
1217
1287
  if (!propName) return;
1218
1288
  if (resolvedValue.isEnum || resolvedValue.type !== "object") return;
1219
- const aliasPattern = context.output.override.aliasCombinedTypes ? "{|&|\\|" : "{";
1289
+ const aliasPattern = context.output.override.aliasCombinedTypes ? String.raw`{|&|\|` : "{";
1220
1290
  if (!new RegExp(aliasPattern).test(resolvedValue.value)) return;
1221
1291
  const { originalSchema } = resolvedValue;
1222
1292
  const doc = jsDoc(originalSchema);
@@ -1259,8 +1329,8 @@ function resolveObjectOriginal({ schema, propName, combined = false, context, fo
1259
1329
  originalSchema: resolvedValue.originalSchema
1260
1330
  };
1261
1331
  if (propName && resolvedValue.isEnum && !combined && !resolvedValue.isRef) {
1262
- const doc = jsDoc(resolvedValue.originalSchema ?? {});
1263
- const enumValue = getEnum(resolvedValue.value, propName, getEnumNames(resolvedValue.originalSchema), context.output.override.enumGenerationType, getEnumDescriptions(resolvedValue.originalSchema), context.output.override.namingConvention?.enum);
1332
+ const doc = jsDoc(resolvedValue.originalSchema);
1333
+ const enumValue = getEnum(resolvedValue.value, propName, getEnumNames(resolvedValue.originalSchema), context.output.override.enumGenerationType, getEnumDescriptions(resolvedValue.originalSchema), context.output.override.namingConvention.enum);
1264
1334
  return {
1265
1335
  value: propName,
1266
1336
  imports: [{ name: propName }],
@@ -1309,17 +1379,20 @@ function resolveObject({ schema, propName, combined = false, context, formDataCo
1309
1379
  * @param item item with type === "array"
1310
1380
  */
1311
1381
  function getArray({ schema, name, context, formDataContext }) {
1312
- const schema31 = schema;
1382
+ const schemaPrefixItems = schema.prefixItems;
1383
+ const schemaItems = schema.items;
1384
+ const schemaExample = schema.example;
1385
+ const schemaExamples = schema.examples;
1313
1386
  const itemSuffix = context.output.override.components.schemas.itemSuffix;
1314
- if (schema31.prefixItems) {
1315
- const resolvedObjects = schema31.prefixItems.map((item, index) => resolveObject({
1387
+ if (schemaPrefixItems) {
1388
+ const resolvedObjects = schemaPrefixItems.map((item, index) => resolveObject({
1316
1389
  schema: item,
1317
- propName: name ? name + itemSuffix + index : void 0,
1390
+ propName: name ? name + itemSuffix + String(index) : void 0,
1318
1391
  context
1319
1392
  }));
1320
- if (schema31.items) {
1393
+ if (schemaItems) {
1321
1394
  const additional = resolveObject({
1322
- schema: schema31.items,
1395
+ schema: schemaItems,
1323
1396
  propName: name ? name + itemSuffix + "Additional" : void 0,
1324
1397
  context
1325
1398
  });
@@ -1337,13 +1410,13 @@ function getArray({ schema, name, context, formDataContext }) {
1337
1410
  schemas: resolvedObjects.flatMap((o) => o.schemas),
1338
1411
  dependencies: resolvedObjects.flatMap((o) => o.dependencies),
1339
1412
  hasReadonlyProps: resolvedObjects.some((o) => o.hasReadonlyProps),
1340
- example: schema.example,
1341
- examples: resolveExampleRefs(schema.examples, context)
1413
+ example: schemaExample,
1414
+ examples: resolveExampleRefs(schemaExamples, context)
1342
1415
  };
1343
1416
  }
1344
- if (schema.items) {
1417
+ if (schemaItems) {
1345
1418
  const resolvedObject = resolveObject({
1346
- schema: schema.items,
1419
+ schema: schemaItems,
1347
1420
  propName: name ? name + itemSuffix : void 0,
1348
1421
  context,
1349
1422
  formDataContext
@@ -1357,8 +1430,8 @@ function getArray({ schema, name, context, formDataContext }) {
1357
1430
  type: "array",
1358
1431
  isRef: false,
1359
1432
  hasReadonlyProps: resolvedObject.hasReadonlyProps,
1360
- example: schema.example,
1361
- examples: resolveExampleRefs(schema.examples, context)
1433
+ example: schemaExample,
1434
+ examples: resolveExampleRefs(schemaExamples, context)
1362
1435
  };
1363
1436
  } else if (compareVersions(context.spec.openapi, "3.1", ">=")) return {
1364
1437
  value: "unknown[]",
@@ -1375,6 +1448,13 @@ function getArray({ schema, name, context, formDataContext }) {
1375
1448
 
1376
1449
  //#endregion
1377
1450
  //#region src/getters/res-req-types.ts
1451
+ const getSchemaType = (s) => s.type;
1452
+ const getSchemaCombined = (s) => s.oneOf ?? s.anyOf ?? s.allOf;
1453
+ const getSchemaOneOf = (s) => s.oneOf;
1454
+ const getSchemaAnyOf = (s) => s.anyOf;
1455
+ const getSchemaItems = (s) => s.items;
1456
+ const getSchemaRequired = (s) => s.required;
1457
+ const getSchemaProperties = (s) => s.properties;
1378
1458
  const formDataContentTypes = new Set(["multipart/form-data"]);
1379
1459
  const formUrlEncodedContentTypes = new Set(["application/x-www-form-urlencoded"]);
1380
1460
  function getResReqContentTypes({ mediaType, propName, context, isFormData, contentType }) {
@@ -1396,10 +1476,28 @@ function getResReqContentTypes({ mediaType, propName, context, isFormData, conte
1396
1476
  return resolvedObject;
1397
1477
  }
1398
1478
  function getResReqTypes(responsesOrRequests, name, context, defaultType = "unknown", uniqueKey = (item) => item.value) {
1399
- return uniqueBy(responsesOrRequests.filter(([_, res]) => Boolean(res)).map(([key, res]) => {
1479
+ return uniqueBy(responsesOrRequests.filter(([, res]) => Boolean(res)).map(([key, res]) => {
1400
1480
  if (isReference(res)) {
1401
1481
  const { schema: bodySchema, imports: [{ name: name$1, schemaName }] } = resolveRef(res, context);
1402
- const [contentType, mediaType] = Object.entries(bodySchema.content ?? {})[0] ?? [];
1482
+ const firstEntry = Object.entries(bodySchema.content ?? {}).at(0);
1483
+ if (!firstEntry) return [{
1484
+ value: name$1,
1485
+ imports: [{
1486
+ name: name$1,
1487
+ schemaName
1488
+ }],
1489
+ schemas: [],
1490
+ type: "unknown",
1491
+ isEnum: false,
1492
+ isRef: true,
1493
+ hasReadonlyProps: false,
1494
+ originalSchema: void 0,
1495
+ example: void 0,
1496
+ examples: void 0,
1497
+ key,
1498
+ contentType: void 0
1499
+ }];
1500
+ const [contentType, mediaType] = firstEntry;
1403
1501
  const isFormData = formDataContentTypes.has(contentType);
1404
1502
  const isFormUrlEncoded = formUrlEncodedContentTypes.has(contentType);
1405
1503
  if (!isFormData && !isFormUrlEncoded || !mediaType.schema) return [{
@@ -1413,9 +1511,9 @@ function getResReqTypes(responsesOrRequests, name, context, defaultType = "unkno
1413
1511
  isEnum: false,
1414
1512
  isRef: true,
1415
1513
  hasReadonlyProps: false,
1416
- originalSchema: mediaType?.schema,
1417
- example: mediaType?.example,
1418
- examples: resolveExampleRefs(mediaType?.examples, context),
1514
+ originalSchema: mediaType.schema,
1515
+ example: mediaType.example,
1516
+ examples: resolveExampleRefs(mediaType.examples, context),
1419
1517
  key,
1420
1518
  contentType
1421
1519
  }];
@@ -1491,7 +1589,7 @@ function getResReqTypes(responsesOrRequests, name, context, defaultType = "unkno
1491
1589
  return;
1492
1590
  }
1493
1591
  const isFormUrlEncoded = formUrlEncodedContentTypes.has(contentType);
1494
- if (!isFormData && !isFormUrlEncoded || !effectivePropName) return {
1592
+ if (!isFormData && !isFormUrlEncoded || !effectivePropName || !mediaType.schema) return {
1495
1593
  ...resolvedValue,
1496
1594
  imports: resolvedValue.imports,
1497
1595
  contentType,
@@ -1556,6 +1654,17 @@ function getResReqTypes(responsesOrRequests, name, context, defaultType = "unkno
1556
1654
  }).flat(), uniqueKey);
1557
1655
  }
1558
1656
  /**
1657
+ * Determine the responseType option based on success content types only.
1658
+ * This avoids error-response content types influencing the responseType.
1659
+ */
1660
+ function getSuccessResponseType(response) {
1661
+ const successContentTypes = response.types.success.map((t) => t.contentType).filter(Boolean);
1662
+ if (response.isBlob) return "blob";
1663
+ const hasJsonResponse = successContentTypes.some((contentType) => contentType.includes("json") || contentType.includes("+json"));
1664
+ const hasTextResponse = successContentTypes.some((contentType) => contentType.startsWith("text/") || contentType.includes("xml"));
1665
+ if (!hasJsonResponse && hasTextResponse) return "text";
1666
+ }
1667
+ /**
1559
1668
  * Determine the response type category for a given content type.
1560
1669
  * Used to set the correct responseType option in HTTP clients.
1561
1670
  *
@@ -1584,9 +1693,9 @@ function getDefaultContentType(contentTypes) {
1584
1693
  function getFormDataAdditionalImports({ schemaObject, context }) {
1585
1694
  const { schema } = resolveRef(schemaObject, context);
1586
1695
  if (schema.type !== "object") return [];
1587
- const combinedSchemas = schema.oneOf || schema.anyOf;
1696
+ const combinedSchemas = getSchemaOneOf(schema) ?? getSchemaAnyOf(schema);
1588
1697
  if (!combinedSchemas) return [];
1589
- return combinedSchemas.map((schema$1) => resolveRef(schema$1, context).imports[0]).filter(Boolean);
1698
+ return combinedSchemas.map((subSchema) => resolveRef(subSchema, context).imports[0]).filter(Boolean);
1590
1699
  }
1591
1700
  function getSchemaFormDataAndUrlEncoded({ name, schemaObject, context, isRequestBodyOptional, isUrlEncoded, isRef, encoding }) {
1592
1701
  const { schema, imports } = resolveRef(schemaObject, context);
@@ -1594,12 +1703,12 @@ function getSchemaFormDataAndUrlEncoded({ name, schemaObject, context, isRequest
1594
1703
  const additionalImports = [];
1595
1704
  const variableName = isUrlEncoded ? "formUrlEncoded" : "formData";
1596
1705
  let form = isUrlEncoded ? `const ${variableName} = new URLSearchParams();\n` : `const ${variableName} = new FormData();\n`;
1597
- const combinedSchemas = schema.oneOf || schema.anyOf || schema.allOf;
1706
+ const combinedSchemas = getSchemaCombined(schema);
1598
1707
  if (schema.type === "object" || schema.type === void 0 && combinedSchemas) {
1599
1708
  if (combinedSchemas) {
1600
- const shouldCast = !!schema.oneOf || !!schema.anyOf;
1601
- const combinedSchemasFormData = combinedSchemas.map((schema$1) => {
1602
- const { schema: combinedSchema, imports: imports$1 } = resolveRef(schema$1, context);
1709
+ const shouldCast = !!getSchemaOneOf(schema) || !!getSchemaAnyOf(schema);
1710
+ const combinedSchemasFormData = combinedSchemas.map((subSchema) => {
1711
+ const { schema: combinedSchema, imports: imports$1 } = resolveRef(subSchema, context);
1603
1712
  let newPropName = propName;
1604
1713
  let newPropDefinition = "";
1605
1714
  if (shouldCast && imports$1[0]) {
@@ -1633,8 +1742,9 @@ function getSchemaFormDataAndUrlEncoded({ name, schemaObject, context, isRequest
1633
1742
  }
1634
1743
  if (schema.type === "array") {
1635
1744
  let valueStr = "value";
1636
- if (schema.items) {
1637
- const { schema: itemSchema } = resolveRef(schema.items, context);
1745
+ const schemaItems = getSchemaItems(schema);
1746
+ if (schemaItems) {
1747
+ const { schema: itemSchema } = resolveRef(schemaItems, context);
1638
1748
  if (itemSchema.type === "object" || itemSchema.type === "array") valueStr = "JSON.stringify(value)";
1639
1749
  else if (itemSchema.type === "number" || itemSchema.type === "integer" || itemSchema.type === "boolean") valueStr = "value.toString()";
1640
1750
  }
@@ -1644,9 +1754,11 @@ function getSchemaFormDataAndUrlEncoded({ name, schemaObject, context, isRequest
1644
1754
  return `${form}${variableName}.append('data', ${propName})\n`;
1645
1755
  }
1646
1756
  function resolveSchemaPropertiesToFormData({ schema, variableName, propName, context, isRequestBodyOptional, keyPrefix = "", depth = 0, encoding }) {
1647
- return Object.entries(schema.properties ?? {}).reduce((acc, [key, value]) => {
1757
+ let formDataValues = "";
1758
+ const schemaProps = getSchemaProperties(schema) ?? {};
1759
+ for (const [key, value] of Object.entries(schemaProps)) {
1648
1760
  const { schema: property } = resolveRef(value, context);
1649
- if (property.readOnly) return acc;
1761
+ if (property.readOnly) continue;
1650
1762
  let formDataValue = "";
1651
1763
  const partContentType = (depth === 0 ? encoding?.[key] : void 0)?.contentType;
1652
1764
  const formattedKeyPrefix = isRequestBodyOptional ? keyword.isIdentifierNameES5(key) ? "?" : "?." : "";
@@ -1670,8 +1782,9 @@ function resolveSchemaPropertiesToFormData({ schema, variableName, propName, con
1670
1782
  else if (property.type === "array") {
1671
1783
  let valueStr = "value";
1672
1784
  let hasNonPrimitiveChild = false;
1673
- if (property.items) {
1674
- const { schema: itemSchema } = resolveRef(property.items, context);
1785
+ const propertyItems = getSchemaItems(property);
1786
+ if (propertyItems) {
1787
+ const { schema: itemSchema } = resolveRef(propertyItems, context);
1675
1788
  if (itemSchema.type === "object" || itemSchema.type === "array") if (context.output.override.formData.arrayHandling === FormDataArrayHandling.EXPLODE) {
1676
1789
  hasNonPrimitiveChild = true;
1677
1790
  const resolvedValue = resolveSchemaPropertiesToFormData({
@@ -1686,52 +1799,69 @@ function resolveSchemaPropertiesToFormData({ schema, variableName, propName, con
1686
1799
  formDataValue = `${valueKey}.forEach((value, index${depth > 0 ? depth : ""}) => {
1687
1800
  ${resolvedValue}});\n`;
1688
1801
  } else valueStr = "JSON.stringify(value)";
1689
- else if (itemSchema.type === "number" || itemSchema.type?.includes("number") || itemSchema.type === "integer" || itemSchema.type?.includes("integer") || itemSchema.type === "boolean" || itemSchema.type?.includes("boolean")) valueStr = "value.toString()";
1802
+ else {
1803
+ const itemType = getSchemaType(itemSchema);
1804
+ if (itemType === "number" || Array.isArray(itemType) && itemType.includes("number") || itemType === "integer" || Array.isArray(itemType) && itemType.includes("integer") || itemType === "boolean" || Array.isArray(itemType) && itemType.includes("boolean")) valueStr = "value.toString()";
1805
+ }
1690
1806
  }
1691
1807
  if (context.output.override.formData.arrayHandling === FormDataArrayHandling.EXPLODE) {
1692
1808
  if (!hasNonPrimitiveChild) formDataValue = `${valueKey}.forEach((value, index${depth > 0 ? depth : ""}) => ${variableName}.append(\`${keyPrefix}${key}[\${index${depth > 0 ? depth : ""}}]\`, ${valueStr}));\n`;
1693
1809
  } else formDataValue = `${valueKey}.forEach(value => ${variableName}.append(\`${keyPrefix}${key}${context.output.override.formData.arrayHandling === FormDataArrayHandling.SERIALIZE_WITH_BRACKETS ? "[]" : ""}\`, ${valueStr}));\n`;
1694
- } else if (property.type === "number" || property.type?.includes("number") || property.type === "integer" || property.type?.includes("integer") || property.type === "boolean" || property.type?.includes("boolean")) formDataValue = `${variableName}.append(\`${keyPrefix}${key}\`, ${nonOptionalValueKey}.toString())\n`;
1810
+ } else if ((() => {
1811
+ const propType$1 = getSchemaType(property);
1812
+ return propType$1 === "number" || Array.isArray(propType$1) && propType$1.includes("number") || propType$1 === "integer" || Array.isArray(propType$1) && propType$1.includes("integer") || propType$1 === "boolean" || Array.isArray(propType$1) && propType$1.includes("boolean");
1813
+ })()) formDataValue = `${variableName}.append(\`${keyPrefix}${key}\`, ${nonOptionalValueKey}.toString())\n`;
1695
1814
  else formDataValue = `${variableName}.append(\`${keyPrefix}${key}\`, ${nonOptionalValueKey});\n`;
1696
1815
  let existSubSchemaNullable = false;
1697
- if (property.allOf || property.anyOf || property.oneOf) {
1698
- const subSchemas = (property.allOf || property.anyOf || property.oneOf)?.map((c) => resolveObject({
1816
+ const combine = getSchemaCombined(property);
1817
+ if (combine) {
1818
+ const subSchemas = combine.map((c) => resolveObject({
1699
1819
  schema: c,
1700
1820
  combined: true,
1701
1821
  context
1702
1822
  }));
1703
- if (subSchemas?.some((subSchema) => {
1823
+ if (subSchemas.some((subSchema) => {
1704
1824
  return [
1705
1825
  "number",
1706
1826
  "integer",
1707
1827
  "boolean"
1708
1828
  ].includes(subSchema.type);
1709
1829
  })) formDataValue = `${variableName}.append(\`${key}\`, ${nonOptionalValueKey}.toString())\n`;
1710
- if (subSchemas?.some((subSchema) => {
1830
+ if (subSchemas.some((subSchema) => {
1711
1831
  return subSchema.type === "null";
1712
1832
  })) existSubSchemaNullable = true;
1713
1833
  }
1714
- const isRequired = schema.required?.includes(key) && !isRequestBodyOptional;
1715
- if (property.nullable || property.type?.includes("null") || existSubSchemaNullable) {
1716
- if (isRequired) return acc + `if(${valueKey} !== null) {\n ${formDataValue} }\n`;
1717
- return acc + `if(${valueKey} !== undefined && ${nonOptionalValueKey} !== null) {\n ${formDataValue} }\n`;
1834
+ const isRequired = getSchemaRequired(schema)?.includes(key) && !isRequestBodyOptional;
1835
+ const propType = getSchemaType(property);
1836
+ if (property.nullable || Array.isArray(propType) && propType.includes("null") || existSubSchemaNullable) {
1837
+ if (isRequired) {
1838
+ formDataValues += `if(${valueKey} !== null) {\n ${formDataValue} }\n`;
1839
+ continue;
1840
+ }
1841
+ formDataValues += `if(${valueKey} !== undefined && ${nonOptionalValueKey} !== null) {\n ${formDataValue} }\n`;
1842
+ continue;
1843
+ }
1844
+ if (isRequired) {
1845
+ formDataValues += formDataValue;
1846
+ continue;
1718
1847
  }
1719
- if (isRequired) return acc + formDataValue;
1720
- return acc + `if(${valueKey} !== undefined) {\n ${formDataValue} }\n`;
1721
- }, "");
1848
+ formDataValues += `if(${valueKey} !== undefined) {\n ${formDataValue} }\n`;
1849
+ }
1850
+ return formDataValues;
1722
1851
  }
1723
1852
 
1724
1853
  //#endregion
1725
1854
  //#region src/getters/body.ts
1855
+ /**
1856
+ * Extract all content types from a requestBody (#2812)
1857
+ */
1858
+ function getRequestBodyContentTypes(requestBody, context) {
1859
+ if (!requestBody) return [];
1860
+ const content = (isReference(requestBody) ? resolveRef(requestBody, context).schema : requestBody).content;
1861
+ return content ? Object.keys(content) : [];
1862
+ }
1726
1863
  function getBody({ requestBody, operationName, context, contentType }) {
1727
- const allBodyTypes = getResReqTypes([[context.output.override.components.requestBodies.suffix, requestBody]], operationName, context);
1728
- const filteredBodyTypes = contentType ? allBodyTypes.filter((type) => {
1729
- let include = true;
1730
- let exclude = false;
1731
- if (contentType.include) include = contentType.include.includes(type.contentType);
1732
- if (contentType.exclude) exclude = contentType.exclude.includes(type.contentType);
1733
- return include && !exclude;
1734
- }) : allBodyTypes;
1864
+ const filteredBodyTypes = filterByContentType(getResReqTypes([[context.output.override.components.requestBodies.suffix, requestBody]], operationName, context), contentType);
1735
1865
  const imports = filteredBodyTypes.flatMap(({ imports: imports$1 }) => imports$1);
1736
1866
  const schemas = filteredBodyTypes.flatMap(({ schemas: schemas$1 }) => schemas$1);
1737
1867
  const definition = filteredBodyTypes.map(({ value }) => value).join(" | ");
@@ -1805,7 +1935,10 @@ function getKey(key) {
1805
1935
  * Returns undefined if propertyNames doesn't have an enum
1806
1936
  */
1807
1937
  function getPropertyNamesEnum(item) {
1808
- if ("propertyNames" in item && item.propertyNames && "enum" in item.propertyNames && Array.isArray(item.propertyNames.enum)) return item.propertyNames.enum.filter((val) => typeof val === "string");
1938
+ if ("propertyNames" in item && item.propertyNames && "enum" in item.propertyNames) {
1939
+ const propertyNames = item.propertyNames;
1940
+ if (Array.isArray(propertyNames.enum)) return propertyNames.enum.filter((val) => isString(val));
1941
+ }
1809
1942
  }
1810
1943
  /**
1811
1944
  * Generate index signature key type based on propertyNames enum
@@ -1850,23 +1983,43 @@ function getObject({ item, name, context, nullable, formDataContext }) {
1850
1983
  nullable,
1851
1984
  formDataContext
1852
1985
  });
1853
- if (Array.isArray(item.type)) return combineSchemas({
1854
- schema: { anyOf: item.type.map((type) => ({
1855
- ...item,
1856
- type
1857
- })) },
1858
- name,
1859
- separator: "anyOf",
1860
- context,
1861
- nullable
1862
- });
1863
- if (item.properties && Object.entries(item.properties).length > 0) {
1864
- const entries$1 = Object.entries(item.properties);
1986
+ if (Array.isArray(item.type)) {
1987
+ const typeArray = item.type;
1988
+ const baseItem = item;
1989
+ return combineSchemas({
1990
+ schema: { anyOf: typeArray.map((type) => ({
1991
+ ...baseItem,
1992
+ type
1993
+ })) },
1994
+ name,
1995
+ separator: "anyOf",
1996
+ context,
1997
+ nullable
1998
+ });
1999
+ }
2000
+ const itemProperties = item.properties;
2001
+ if (itemProperties && Object.entries(itemProperties).length > 0) {
2002
+ const entries$1 = Object.entries(itemProperties);
1865
2003
  if (context.output.propertySortOrder === PropertySortOrder.ALPHABETICAL) entries$1.sort((a, b) => {
1866
2004
  return a[0].localeCompare(b[0]);
1867
2005
  });
1868
- return entries$1.reduce((acc, [key, schema], index, arr) => {
1869
- const isRequired = (Array.isArray(item.required) ? item.required : []).includes(key);
2006
+ const acc = {
2007
+ imports: [],
2008
+ schemas: [],
2009
+ value: "",
2010
+ isEnum: false,
2011
+ type: "object",
2012
+ isRef: false,
2013
+ schema: {},
2014
+ hasReadonlyProps: false,
2015
+ useTypeAlias: false,
2016
+ dependencies: [],
2017
+ example: item.example,
2018
+ examples: resolveExampleRefs(item.examples, context)
2019
+ };
2020
+ const itemRequired = item.required;
2021
+ for (const [index, [key, schema]] of entries$1.entries()) {
2022
+ const isRequired = (Array.isArray(itemRequired) ? itemRequired : []).includes(key);
1870
2023
  let propName = "";
1871
2024
  if (name) {
1872
2025
  const isKeyStartWithUnderscore = key.startsWith("_");
@@ -1884,16 +2037,16 @@ function getObject({ item, name, context, nullable, formDataContext }) {
1884
2037
  context,
1885
2038
  formDataContext: propertyFormDataContext
1886
2039
  });
1887
- const isReadOnly = item.readOnly || schema.readOnly;
2040
+ const isReadOnly = item.readOnly ?? schema.readOnly;
1888
2041
  if (!index) acc.value += "{";
1889
2042
  const doc = jsDoc(schema, true, context);
1890
- acc.hasReadonlyProps ||= isReadOnly || false;
1891
- const constValue = "const" in schema ? schema.const : void 0;
1892
- const hasConst = constValue !== void 0;
2043
+ if (isReadOnly ?? false) acc.hasReadonlyProps = true;
2044
+ const constValue$1 = "const" in schema ? schema.const : void 0;
2045
+ const hasConst = constValue$1 !== void 0;
1893
2046
  let constLiteral;
1894
2047
  if (!hasConst) constLiteral = void 0;
1895
- else if (typeof constValue === "string") constLiteral = `'${escape(constValue)}'`;
1896
- else constLiteral = JSON.stringify(constValue);
2048
+ else if (isString(constValue$1)) constLiteral = `'${escape(constValue$1)}'`;
2049
+ else constLiteral = JSON.stringify(constValue$1);
1897
2050
  const needsValueImport = hasConst && (resolvedValue.isEnum || resolvedValue.type === "enum");
1898
2051
  const aliasedImports = needsValueImport ? resolvedValue.imports.map((imp) => ({
1899
2052
  ...imp,
@@ -1914,8 +2067,9 @@ function getObject({ item, name, context, nullable, formDataContext }) {
1914
2067
  acc.value += `\n ${doc ? `${doc} ` : ""}${isReadOnly && !context.output.override.suppressReadonlyModifier ? "readonly " : ""}${getKey(key)}${isRequired ? "" : "?"}: ${finalPropValue};`;
1915
2068
  acc.schemas.push(...resolvedValue.schemas);
1916
2069
  acc.dependencies.push(...resolvedValue.dependencies);
1917
- if (arr.length - 1 === index) {
1918
- if (item.additionalProperties) if (isBoolean(item.additionalProperties)) {
2070
+ if (entries$1.length - 1 === index) {
2071
+ const additionalProps = item.additionalProperties;
2072
+ if (additionalProps) if (isBoolean(additionalProps)) {
1919
2073
  const recordType$1 = getPropertyNamesRecordType(item, "unknown");
1920
2074
  if (recordType$1) {
1921
2075
  acc.value += "\n}";
@@ -1927,7 +2081,7 @@ function getObject({ item, name, context, nullable, formDataContext }) {
1927
2081
  }
1928
2082
  } else {
1929
2083
  const resolvedValue$1 = resolveValue({
1930
- schema: item.additionalProperties,
2084
+ schema: additionalProps,
1931
2085
  name,
1932
2086
  context
1933
2087
  });
@@ -1945,24 +2099,13 @@ function getObject({ item, name, context, nullable, formDataContext }) {
1945
2099
  else acc.value += "\n}";
1946
2100
  acc.value += nullable;
1947
2101
  }
1948
- return acc;
1949
- }, {
1950
- imports: [],
1951
- schemas: [],
1952
- value: "",
1953
- isEnum: false,
1954
- type: "object",
1955
- isRef: false,
1956
- schema: {},
1957
- hasReadonlyProps: false,
1958
- useTypeAlias: false,
1959
- dependencies: [],
1960
- example: item.example,
1961
- examples: resolveExampleRefs(item.examples, context)
1962
- });
2102
+ }
2103
+ return acc;
1963
2104
  }
1964
- if (item.additionalProperties) {
1965
- if (isBoolean(item.additionalProperties)) {
2105
+ const outerAdditionalProps = item.additionalProperties;
2106
+ const readOnlyFlag = item.readOnly;
2107
+ if (outerAdditionalProps) {
2108
+ if (isBoolean(outerAdditionalProps)) {
1966
2109
  const recordType$2 = getPropertyNamesRecordType(item, "unknown");
1967
2110
  if (recordType$2) return {
1968
2111
  value: recordType$2 + nullable,
@@ -1971,7 +2114,7 @@ function getObject({ item, name, context, nullable, formDataContext }) {
1971
2114
  isEnum: false,
1972
2115
  type: "object",
1973
2116
  isRef: false,
1974
- hasReadonlyProps: item.readOnly || false,
2117
+ hasReadonlyProps: readOnlyFlag ?? false,
1975
2118
  useTypeAlias: true,
1976
2119
  dependencies: []
1977
2120
  };
@@ -1982,21 +2125,21 @@ function getObject({ item, name, context, nullable, formDataContext }) {
1982
2125
  isEnum: false,
1983
2126
  type: "object",
1984
2127
  isRef: false,
1985
- hasReadonlyProps: item.readOnly || false,
2128
+ hasReadonlyProps: readOnlyFlag ?? false,
1986
2129
  useTypeAlias: false,
1987
2130
  dependencies: []
1988
2131
  };
1989
2132
  }
1990
2133
  const resolvedValue = resolveValue({
1991
- schema: item.additionalProperties,
2134
+ schema: outerAdditionalProps,
1992
2135
  name,
1993
2136
  context
1994
2137
  });
1995
2138
  const recordType$1 = getPropertyNamesRecordType(item, resolvedValue.value);
1996
2139
  if (recordType$1) return {
1997
2140
  value: recordType$1 + nullable,
1998
- imports: resolvedValue.imports ?? [],
1999
- schemas: resolvedValue.schemas ?? [],
2141
+ imports: resolvedValue.imports,
2142
+ schemas: resolvedValue.schemas,
2000
2143
  isEnum: false,
2001
2144
  type: "object",
2002
2145
  isRef: false,
@@ -2006,8 +2149,8 @@ function getObject({ item, name, context, nullable, formDataContext }) {
2006
2149
  };
2007
2150
  return {
2008
2151
  value: `{[key: ${getIndexSignatureKey(item)}]: ${resolvedValue.value}}` + nullable,
2009
- imports: resolvedValue.imports ?? [],
2010
- schemas: resolvedValue.schemas ?? [],
2152
+ imports: resolvedValue.imports,
2153
+ schemas: resolvedValue.schemas,
2011
2154
  isEnum: false,
2012
2155
  type: "object",
2013
2156
  isRef: false,
@@ -2016,15 +2159,15 @@ function getObject({ item, name, context, nullable, formDataContext }) {
2016
2159
  dependencies: resolvedValue.dependencies
2017
2160
  };
2018
2161
  }
2019
- const itemWithConst = item;
2020
- if (itemWithConst.const) return {
2021
- value: `'${itemWithConst.const}'`,
2162
+ const constValue = item.const;
2163
+ if (constValue) return {
2164
+ value: `'${constValue}'`,
2022
2165
  imports: [],
2023
2166
  schemas: [],
2024
2167
  isEnum: false,
2025
2168
  type: "string",
2026
2169
  isRef: false,
2027
- hasReadonlyProps: item.readOnly || false,
2170
+ hasReadonlyProps: readOnlyFlag ?? false,
2028
2171
  dependencies: []
2029
2172
  };
2030
2173
  const keyType = item.type === "object" ? getIndexSignatureKey(item) : "string";
@@ -2036,7 +2179,7 @@ function getObject({ item, name, context, nullable, formDataContext }) {
2036
2179
  isEnum: false,
2037
2180
  type: "object",
2038
2181
  isRef: false,
2039
- hasReadonlyProps: item.readOnly || false,
2182
+ hasReadonlyProps: readOnlyFlag ?? false,
2040
2183
  useTypeAlias: true,
2041
2184
  dependencies: []
2042
2185
  };
@@ -2047,7 +2190,7 @@ function getObject({ item, name, context, nullable, formDataContext }) {
2047
2190
  isEnum: false,
2048
2191
  type: "object",
2049
2192
  isRef: false,
2050
- hasReadonlyProps: item.readOnly || false,
2193
+ hasReadonlyProps: readOnlyFlag ?? false,
2051
2194
  useTypeAlias: false,
2052
2195
  dependencies: []
2053
2196
  };
@@ -2062,29 +2205,36 @@ function getObject({ item, name, context, nullable, formDataContext }) {
2062
2205
  * @ref https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.1.md#data-types
2063
2206
  */
2064
2207
  function getScalar({ item, name, context, formDataContext }) {
2065
- const nullable = isArray(item.type) && item.type.includes("null") || item.nullable === true ? " | null" : "";
2066
- const enumItems = item.enum?.filter((enumItem) => enumItem !== null);
2067
- let itemType = item.type;
2208
+ const schemaEnum = item.enum;
2209
+ const schemaType = item.type;
2210
+ const schemaReadOnly = item.readOnly;
2211
+ const schemaExample = item.example;
2212
+ const schemaExamples = item.examples;
2213
+ const schemaConst = item.const;
2214
+ const schemaFormat = item.format;
2215
+ const schemaNullable = item.nullable;
2216
+ const nullable = isArray(schemaType) && schemaType.includes("null") || schemaNullable === true ? " | null" : "";
2217
+ const enumItems = schemaEnum?.filter((enumItem) => enumItem !== null);
2218
+ let itemType = schemaType;
2068
2219
  if (!itemType && item.items) {
2069
2220
  item.type = "array";
2070
2221
  itemType = "array";
2071
2222
  }
2072
- if (isArray(item.type) && item.type.includes("null")) {
2073
- const typesWithoutNull = item.type.filter((x) => x !== "null");
2223
+ if (isArray(schemaType) && schemaType.includes("null")) {
2224
+ const typesWithoutNull = schemaType.filter((x) => x !== "null");
2074
2225
  itemType = typesWithoutNull.length === 1 ? typesWithoutNull[0] : typesWithoutNull;
2075
2226
  }
2076
2227
  switch (itemType) {
2077
2228
  case "number":
2078
2229
  case "integer": {
2079
- let value = context.output.override.useBigInt && (item.format === "int64" || item.format === "uint64") ? "bigint" : "number";
2230
+ let value = context.output.override.useBigInt && (schemaFormat === "int64" || schemaFormat === "uint64") ? "bigint" : "number";
2080
2231
  let isEnum = false;
2081
2232
  if (enumItems) {
2082
2233
  value = enumItems.map((enumItem) => `${enumItem}`).join(" | ");
2083
2234
  isEnum = true;
2084
2235
  }
2085
2236
  value += nullable;
2086
- const itemWithConst = item;
2087
- if (itemWithConst.const !== void 0) value = itemWithConst.const;
2237
+ if (schemaConst !== void 0) value = schemaConst;
2088
2238
  return {
2089
2239
  value,
2090
2240
  isEnum,
@@ -2092,16 +2242,15 @@ function getScalar({ item, name, context, formDataContext }) {
2092
2242
  schemas: [],
2093
2243
  imports: [],
2094
2244
  isRef: false,
2095
- hasReadonlyProps: item.readOnly || false,
2245
+ hasReadonlyProps: schemaReadOnly ?? false,
2096
2246
  dependencies: [],
2097
- example: item.example,
2098
- examples: resolveExampleRefs(item.examples, context)
2247
+ example: schemaExample,
2248
+ examples: resolveExampleRefs(schemaExamples, context)
2099
2249
  };
2100
2250
  }
2101
2251
  case "boolean": {
2102
2252
  let value = "boolean" + nullable;
2103
- const itemWithConst = item;
2104
- if (itemWithConst.const !== void 0) value = itemWithConst.const;
2253
+ if (schemaConst !== void 0) value = schemaConst;
2105
2254
  return {
2106
2255
  value,
2107
2256
  type: "boolean",
@@ -2109,10 +2258,10 @@ function getScalar({ item, name, context, formDataContext }) {
2109
2258
  schemas: [],
2110
2259
  imports: [],
2111
2260
  isRef: false,
2112
- hasReadonlyProps: item.readOnly || false,
2261
+ hasReadonlyProps: schemaReadOnly ?? false,
2113
2262
  dependencies: [],
2114
- example: item.example,
2115
- examples: resolveExampleRefs(item.examples, context)
2263
+ example: schemaExample,
2264
+ examples: resolveExampleRefs(schemaExamples, context)
2116
2265
  };
2117
2266
  }
2118
2267
  case "array": {
@@ -2125,7 +2274,7 @@ function getScalar({ item, name, context, formDataContext }) {
2125
2274
  return {
2126
2275
  value: value + nullable,
2127
2276
  ...rest,
2128
- dependencies: rest.dependencies ?? []
2277
+ dependencies: rest.dependencies
2129
2278
  };
2130
2279
  }
2131
2280
  case "string": {
@@ -2135,15 +2284,14 @@ function getScalar({ item, name, context, formDataContext }) {
2135
2284
  value = enumItems.map((enumItem) => isString(enumItem) ? `'${escape(enumItem)}'` : `${enumItem}`).filter(Boolean).join(` | `);
2136
2285
  isEnum = true;
2137
2286
  }
2138
- if (item.format === "binary") value = "Blob";
2287
+ if (schemaFormat === "binary") value = "Blob";
2139
2288
  else if (formDataContext?.atPart) {
2140
2289
  const fileType = getFormDataFieldFileType(item, formDataContext.partContentType);
2141
2290
  if (fileType) value = fileType === "binary" ? "Blob" : "Blob | string";
2142
2291
  }
2143
- if (context.output.override.useDates && (item.format === "date" || item.format === "date-time")) value = "Date";
2292
+ if (context.output.override.useDates && (schemaFormat === "date" || schemaFormat === "date-time")) value = "Date";
2144
2293
  value += nullable;
2145
- const itemWithConst = item;
2146
- if (itemWithConst.const) value = `'${itemWithConst.const}'`;
2294
+ if (schemaConst) value = `'${schemaConst}'`;
2147
2295
  return {
2148
2296
  value,
2149
2297
  isEnum,
@@ -2151,10 +2299,10 @@ function getScalar({ item, name, context, formDataContext }) {
2151
2299
  imports: [],
2152
2300
  schemas: [],
2153
2301
  isRef: false,
2154
- hasReadonlyProps: item.readOnly || false,
2302
+ hasReadonlyProps: schemaReadOnly ?? false,
2155
2303
  dependencies: [],
2156
- example: item.example,
2157
- examples: resolveExampleRefs(item.examples, context)
2304
+ example: schemaExample,
2305
+ examples: resolveExampleRefs(schemaExamples, context)
2158
2306
  };
2159
2307
  }
2160
2308
  case "null": return {
@@ -2164,34 +2312,30 @@ function getScalar({ item, name, context, formDataContext }) {
2164
2312
  imports: [],
2165
2313
  schemas: [],
2166
2314
  isRef: false,
2167
- hasReadonlyProps: item.readOnly || false,
2315
+ hasReadonlyProps: schemaReadOnly ?? false,
2168
2316
  dependencies: []
2169
2317
  };
2170
- case "object":
2171
2318
  default: {
2172
2319
  if (isArray(itemType)) return combineSchemas({
2173
- schema: { anyOf: itemType.map((type) => ({
2174
- ...item,
2175
- type
2176
- })) },
2320
+ schema: { anyOf: itemType.map((type) => Object.assign({}, item, { type })) },
2177
2321
  name,
2178
2322
  separator: "anyOf",
2179
2323
  context,
2180
2324
  nullable
2181
2325
  });
2182
2326
  if (enumItems) return {
2183
- value: enumItems.map((enumItem) => isString(enumItem) ? `'${escape(enumItem)}'` : `${enumItem}`).filter(Boolean).join(` | `) + nullable,
2327
+ value: enumItems.map((enumItem) => isString(enumItem) ? `'${escape(enumItem)}'` : String(enumItem)).filter(Boolean).join(` | `) + nullable,
2184
2328
  isEnum: true,
2185
2329
  type: "string",
2186
2330
  imports: [],
2187
2331
  schemas: [],
2188
2332
  isRef: false,
2189
- hasReadonlyProps: item.readOnly || false,
2333
+ hasReadonlyProps: schemaReadOnly ?? false,
2190
2334
  dependencies: [],
2191
- example: item.example,
2192
- examples: resolveExampleRefs(item.examples, context)
2335
+ example: schemaExample,
2336
+ examples: resolveExampleRefs(schemaExamples, context)
2193
2337
  };
2194
- const hasCombiners = item.allOf || item.anyOf || item.oneOf;
2338
+ const hasCombiners = item.allOf ?? item.anyOf ?? item.oneOf;
2195
2339
  const { value, ...rest } = getObject({
2196
2340
  item,
2197
2341
  name,
@@ -2209,17 +2353,66 @@ function getScalar({ item, name, context, formDataContext }) {
2209
2353
 
2210
2354
  //#endregion
2211
2355
  //#region src/getters/combine.ts
2212
- function combineValues({ resolvedData, resolvedValue, separator: separator$1, context }) {
2356
+ const mergeableAllOfKeys = new Set([
2357
+ "type",
2358
+ "properties",
2359
+ "required"
2360
+ ]);
2361
+ function isMergeableAllOfObject(schema) {
2362
+ if (isNullish$1(schema.properties)) return false;
2363
+ if (schema.allOf || schema.anyOf || schema.oneOf) return false;
2364
+ if (!isNullish$1(schema.type) && schema.type !== "object") return false;
2365
+ return Object.keys(schema).every((key) => mergeableAllOfKeys.has(key));
2366
+ }
2367
+ function normalizeAllOfSchema(schema) {
2368
+ const schemaAllOf = schema.allOf;
2369
+ if (!schemaAllOf) return schema;
2370
+ let didMerge = false;
2371
+ const schemaProperties = schema.properties;
2372
+ const schemaRequired = schema.required;
2373
+ const mergedProperties = { ...schemaProperties };
2374
+ const mergedRequired = new Set(schemaRequired);
2375
+ const remainingAllOf = [];
2376
+ for (const subSchema of schemaAllOf) {
2377
+ if (isSchema(subSchema) && isMergeableAllOfObject(subSchema)) {
2378
+ didMerge = true;
2379
+ if (subSchema.properties) Object.assign(mergedProperties, subSchema.properties);
2380
+ const subRequired = subSchema.required;
2381
+ if (subRequired) for (const prop$1 of subRequired) mergedRequired.add(prop$1);
2382
+ continue;
2383
+ }
2384
+ remainingAllOf.push(subSchema);
2385
+ }
2386
+ if (!didMerge || remainingAllOf.length === 0) return schema;
2387
+ return {
2388
+ ...schema,
2389
+ ...Object.keys(mergedProperties).length > 0 && { properties: mergedProperties },
2390
+ ...mergedRequired.size > 0 && { required: [...mergedRequired] },
2391
+ ...remainingAllOf.length > 0 && { allOf: remainingAllOf }
2392
+ };
2393
+ }
2394
+ function combineValues({ resolvedData, resolvedValue, separator: separator$1, context, parentSchema }) {
2213
2395
  if (resolvedData.isEnum.every(Boolean)) return `${resolvedData.values.join(` | `)}${resolvedValue ? ` | ${resolvedValue.value}` : ""}`;
2214
2396
  if (separator$1 === "allOf") {
2215
2397
  let resolvedDataValue = resolvedData.values.map((v) => v.includes(" | ") ? `(${v})` : v).join(` & `);
2216
2398
  if (resolvedData.originalSchema.length > 0 && resolvedValue) {
2217
- const discriminatedPropertySchemas = resolvedData.originalSchema.filter((s) => s?.discriminator && resolvedValue.value.includes(` ${s.discriminator.propertyName}:`));
2399
+ const discriminatedPropertySchemas = resolvedData.originalSchema.filter((s) => {
2400
+ const disc = s?.discriminator;
2401
+ return disc && resolvedValue.value.includes(` ${disc.propertyName}:`);
2402
+ });
2218
2403
  if (discriminatedPropertySchemas.length > 0) resolvedDataValue = `Omit<${resolvedDataValue}, '${discriminatedPropertySchemas.map((s) => s.discriminator?.propertyName).join("' | '")}'>`;
2219
2404
  }
2220
2405
  const resolvedValueStr = resolvedValue?.value.includes(" | ") ? `(${resolvedValue.value})` : resolvedValue?.value;
2221
2406
  const joined = `${resolvedDataValue}${resolvedValue ? ` & ${resolvedValueStr}` : ""}`;
2222
- const overrideRequiredProperties = resolvedData.requiredProperties.filter((prop$1) => !resolvedData.originalSchema.some((schema) => schema?.properties?.[prop$1] && schema.required?.includes(prop$1)));
2407
+ const overrideRequiredProperties = resolvedData.requiredProperties.filter((prop$1) => !resolvedData.originalSchema.some((schema) => {
2408
+ const props = schema?.properties;
2409
+ const req = schema?.required;
2410
+ return props?.[prop$1] && req?.includes(prop$1);
2411
+ }) && !(() => {
2412
+ const parentProps = parentSchema?.properties;
2413
+ const parentReq = parentSchema?.required;
2414
+ return !!(parentProps?.[prop$1] && parentReq?.includes(prop$1));
2415
+ })());
2223
2416
  if (overrideRequiredProperties.length > 0) return `${joined} & Required<Pick<${joined}, '${overrideRequiredProperties.join("' | '")}'>>`;
2224
2417
  return joined;
2225
2418
  }
@@ -2228,11 +2421,12 @@ function combineValues({ resolvedData, resolvedValue, separator: separator$1, co
2228
2421
  values = [];
2229
2422
  for (let i = 0; i < resolvedData.values.length; i += 1) {
2230
2423
  const subSchema = resolvedData.originalSchema[i];
2231
- if (subSchema?.type !== "object") {
2424
+ if (subSchema?.type !== "object" || !subSchema.properties) {
2232
2425
  values.push(resolvedData.values[i]);
2233
2426
  continue;
2234
2427
  }
2235
- const missingProperties = unique(resolvedData.allProperties.filter((p) => !Object.keys(subSchema.properties).includes(p)));
2428
+ const subSchemaProps = subSchema.properties;
2429
+ const missingProperties = unique(resolvedData.allProperties.filter((p) => !Object.keys(subSchemaProps).includes(p)));
2236
2430
  values.push(`${resolvedData.values[i]}${missingProperties.length > 0 ? ` & {${missingProperties.map((p) => `${p}?: never`).join("; ")}}` : ""}`);
2237
2431
  }
2238
2432
  }
@@ -2240,14 +2434,30 @@ function combineValues({ resolvedData, resolvedValue, separator: separator$1, co
2240
2434
  return values.join(" | ");
2241
2435
  }
2242
2436
  function combineSchemas({ name, schema, separator: separator$1, context, nullable, formDataContext }) {
2243
- const items = schema[separator$1] ?? [];
2244
- const resolvedData = items.reduce((acc, subSchema) => {
2437
+ const normalizedSchema = separator$1 === "allOf" && !context.output.override.aliasCombinedTypes && !schema.oneOf && !schema.anyOf ? normalizeAllOfSchema(schema) : schema;
2438
+ const items = normalizedSchema[separator$1] ?? [];
2439
+ const resolvedData = {
2440
+ values: [],
2441
+ imports: [],
2442
+ schemas: [],
2443
+ isEnum: [],
2444
+ isRef: [],
2445
+ types: [],
2446
+ dependencies: [],
2447
+ originalSchema: [],
2448
+ allProperties: [],
2449
+ hasReadonlyProps: false,
2450
+ example: schema.example,
2451
+ examples: resolveExampleRefs(schema.examples, context),
2452
+ requiredProperties: separator$1 === "allOf" ? schema.required ?? [] : []
2453
+ };
2454
+ for (const subSchema of items) {
2245
2455
  let propName;
2246
2456
  if (context.output.override.aliasCombinedTypes) {
2247
2457
  propName = name ? name + pascal(separator$1) : void 0;
2248
- if (propName && acc.schemas.length > 0) propName = propName + pascal(getNumberWord(acc.schemas.length + 1));
2458
+ if (propName && resolvedData.schemas.length > 0) propName = propName + pascal(getNumberWord(resolvedData.schemas.length + 1));
2249
2459
  }
2250
- if (separator$1 === "allOf" && isSchema(subSchema) && subSchema.required) acc.requiredProperties.push(...subSchema.required);
2460
+ if (separator$1 === "allOf" && isSchema(subSchema) && subSchema.required) resolvedData.requiredProperties.push(...subSchema.required);
2251
2461
  const resolvedValue$1 = resolveObject({
2252
2462
  schema: subSchema,
2253
2463
  propName,
@@ -2265,32 +2475,18 @@ function combineSchemas({ name, schema, separator: separator$1, context, nullabl
2265
2475
  resolvedValue: resolvedValue$1,
2266
2476
  imports: aliasedImports
2267
2477
  });
2268
- acc.values.push(value);
2269
- acc.imports.push(...aliasedImports);
2270
- acc.schemas.push(...resolvedValue$1.schemas);
2271
- acc.dependencies.push(...resolvedValue$1.dependencies);
2272
- acc.isEnum.push(resolvedValue$1.isEnum);
2273
- acc.types.push(resolvedValue$1.type);
2274
- acc.isRef.push(resolvedValue$1.isRef);
2275
- acc.originalSchema.push(resolvedValue$1.originalSchema);
2276
- acc.hasReadonlyProps ||= resolvedValue$1.hasReadonlyProps;
2277
- if (resolvedValue$1.type === "object" && resolvedValue$1.originalSchema.properties) acc.allProperties.push(...Object.keys(resolvedValue$1.originalSchema.properties));
2278
- return acc;
2279
- }, {
2280
- values: [],
2281
- imports: [],
2282
- schemas: [],
2283
- isEnum: [],
2284
- isRef: [],
2285
- types: [],
2286
- dependencies: [],
2287
- originalSchema: [],
2288
- allProperties: [],
2289
- hasReadonlyProps: false,
2290
- example: schema.example,
2291
- examples: resolveExampleRefs(schema.examples, context),
2292
- requiredProperties: separator$1 === "allOf" ? schema.required ?? [] : []
2293
- });
2478
+ resolvedData.values.push(value);
2479
+ resolvedData.imports.push(...aliasedImports);
2480
+ resolvedData.schemas.push(...resolvedValue$1.schemas);
2481
+ resolvedData.dependencies.push(...resolvedValue$1.dependencies);
2482
+ resolvedData.isEnum.push(resolvedValue$1.isEnum);
2483
+ resolvedData.types.push(resolvedValue$1.type);
2484
+ resolvedData.isRef.push(resolvedValue$1.isRef);
2485
+ resolvedData.originalSchema.push(resolvedValue$1.originalSchema);
2486
+ if (resolvedValue$1.hasReadonlyProps) resolvedData.hasReadonlyProps = true;
2487
+ const originalProps = resolvedValue$1.originalSchema.properties;
2488
+ if (resolvedValue$1.type === "object" && originalProps) resolvedData.allProperties.push(...Object.keys(originalProps));
2489
+ }
2294
2490
  if (resolvedData.isEnum.every(Boolean) && name && items.length > 1 && context.output.override.enumGenerationType !== EnumGeneration.UNION) {
2295
2491
  const { value: combinedEnumValue, valueImports, hasNull } = getCombinedEnumValue(resolvedData.values.map((value, index) => ({
2296
2492
  value,
@@ -2321,15 +2517,17 @@ function combineSchemas({ name, schema, separator: separator$1, context, nullabl
2321
2517
  };
2322
2518
  }
2323
2519
  let resolvedValue;
2324
- if (schema.properties) resolvedValue = getScalar({
2325
- item: Object.fromEntries(Object.entries(schema).filter(([key]) => key !== separator$1)),
2520
+ if (normalizedSchema.properties) resolvedValue = getScalar({
2521
+ item: Object.fromEntries(Object.entries(normalizedSchema).filter(([key]) => key !== separator$1)),
2326
2522
  name,
2327
- context
2523
+ context,
2524
+ formDataContext
2328
2525
  });
2329
2526
  else if (separator$1 === "allOf" && (schema.oneOf || schema.anyOf)) {
2330
2527
  const siblingCombiner = schema.oneOf ? "oneOf" : "anyOf";
2528
+ const siblingSchemas = schema[siblingCombiner];
2331
2529
  resolvedValue = combineSchemas({
2332
- schema: { [siblingCombiner]: schema[siblingCombiner] },
2530
+ schema: { [siblingCombiner]: siblingSchemas },
2333
2531
  name,
2334
2532
  separator: siblingCombiner,
2335
2533
  context,
@@ -2341,7 +2539,8 @@ function combineSchemas({ name, schema, separator: separator$1, context, nullabl
2341
2539
  resolvedData,
2342
2540
  separator: separator$1,
2343
2541
  resolvedValue,
2344
- context
2542
+ context,
2543
+ parentSchema: normalizedSchema
2345
2544
  }) + nullable),
2346
2545
  imports: resolvedValue ? [...resolvedData.imports, ...resolvedValue.imports] : resolvedData.imports,
2347
2546
  schemas: resolvedValue ? [...resolvedData.schemas, ...resolvedValue.schemas] : resolvedData.schemas,
@@ -2349,7 +2548,7 @@ function combineSchemas({ name, schema, separator: separator$1, context, nullabl
2349
2548
  isEnum: false,
2350
2549
  type: "object",
2351
2550
  isRef: false,
2352
- hasReadonlyProps: resolvedData?.hasReadonlyProps || resolvedValue?.hasReadonlyProps || false,
2551
+ hasReadonlyProps: resolvedData.hasReadonlyProps || (resolvedValue?.hasReadonlyProps ?? false),
2353
2552
  example: schema.example,
2354
2553
  examples: resolveExampleRefs(schema.examples, context)
2355
2554
  };
@@ -2360,7 +2559,9 @@ function combineSchemas({ name, schema, separator: separator$1, context, nullabl
2360
2559
  function resolveDiscriminators(schemas, context) {
2361
2560
  const transformedSchemas = schemas;
2362
2561
  for (const schema of Object.values(transformedSchemas)) {
2363
- if (typeof schema === "boolean") continue;
2562
+ if (isBoolean$1(schema)) continue;
2563
+ const discriminator = schema.discriminator;
2564
+ if (!schema.oneOf && isArray(discriminator?.oneOf)) schema.oneOf = discriminator.oneOf;
2364
2565
  if (schema.discriminator?.mapping) {
2365
2566
  const { mapping, propertyName } = schema.discriminator;
2366
2567
  for (const [mappingKey, mappingValue] of Object.entries(mapping)) {
@@ -2371,17 +2572,25 @@ function resolveDiscriminators(schemas, context) {
2371
2572
  } catch {
2372
2573
  subTypeSchema = transformedSchemas[mappingValue];
2373
2574
  }
2374
- if (typeof subTypeSchema === "boolean" || propertyName === void 0) continue;
2575
+ if (isBoolean$1(subTypeSchema) || propertyName === void 0) continue;
2375
2576
  const property = subTypeSchema.properties?.[propertyName];
2376
- if (typeof property === "boolean" || property === void 0) continue;
2577
+ if (isBoolean$1(property)) continue;
2578
+ const schemaProperty = property && !isReference(property) ? property : void 0;
2579
+ const enumProperty = schemaProperty ? getPropertySafe(schemaProperty, "enum") : {
2580
+ hasProperty: false,
2581
+ value: void 0
2582
+ };
2583
+ const mergedEnumValues = [...((enumProperty.hasProperty && Array.isArray(enumProperty.value) ? enumProperty.value : void 0) ?? []).filter((value) => value !== mappingKey), mappingKey];
2584
+ const mergedProperty = {
2585
+ ...schemaProperty,
2586
+ type: "string",
2587
+ enum: mergedEnumValues
2588
+ };
2377
2589
  subTypeSchema.properties = {
2378
2590
  ...subTypeSchema.properties,
2379
- [propertyName]: {
2380
- type: "string",
2381
- enum: [...property?.enum?.filter((value) => value !== mappingKey) ?? [], mappingKey]
2382
- }
2591
+ [propertyName]: mergedProperty
2383
2592
  };
2384
- subTypeSchema.required = [...subTypeSchema.required ?? [], propertyName];
2593
+ subTypeSchema.required = [...new Set([...subTypeSchema.required ?? [], propertyName])];
2385
2594
  }
2386
2595
  }
2387
2596
  }
@@ -2403,23 +2612,22 @@ function getOperationId(operation, route, verb) {
2403
2612
  //#endregion
2404
2613
  //#region src/getters/parameters.ts
2405
2614
  function getParameters({ parameters, context }) {
2406
- return parameters.reduce((acc, p) => {
2407
- if (isReference(p)) {
2408
- const { schema: parameter, imports } = resolveRef(p, context);
2409
- if (parameter.in === "path" || parameter.in === "query" || parameter.in === "header") acc[parameter.in].push({
2410
- parameter,
2411
- imports
2412
- });
2413
- } else if (p.in === "query" || p.in === "path" || p.in === "header") acc[p.in].push({
2414
- parameter: p,
2415
- imports: []
2416
- });
2417
- return acc;
2418
- }, {
2615
+ const result = {
2419
2616
  path: [],
2420
2617
  query: [],
2421
2618
  header: []
2619
+ };
2620
+ for (const p of parameters) if (isReference(p)) {
2621
+ const { schema: parameter, imports } = resolveRef(p, context);
2622
+ if (parameter.in === "path" || parameter.in === "query" || parameter.in === "header") result[parameter.in].push({
2623
+ parameter,
2624
+ imports
2625
+ });
2626
+ } else if (p.in === "query" || p.in === "path" || p.in === "header") result[p.in].push({
2627
+ parameter: p,
2628
+ imports: []
2422
2629
  });
2630
+ return result;
2423
2631
  }
2424
2632
 
2425
2633
  //#endregion
@@ -2463,16 +2671,18 @@ function getParams({ route, pathParams = [], operationId, context, output }) {
2463
2671
  schema,
2464
2672
  context
2465
2673
  });
2674
+ const originalSchema = resolvedValue.originalSchema;
2675
+ const schemaDefault = originalSchema.default;
2466
2676
  let paramType = resolvedValue.value;
2467
2677
  if (output.allParamsOptional) paramType = `${paramType} | undefined | null`;
2468
2678
  return {
2469
2679
  name,
2470
- definition: `${name}${!required || resolvedValue.originalSchema.default ? "?" : ""}: ${paramType}`,
2471
- implementation: `${name}${!required && !resolvedValue.originalSchema.default ? "?" : ""}${resolvedValue.originalSchema.default ? `: ${paramType} = ${stringify(resolvedValue.originalSchema.default)}` : `: ${paramType}`}`,
2472
- default: resolvedValue.originalSchema.default,
2680
+ definition: `${name}${!required || schemaDefault ? "?" : ""}: ${paramType}`,
2681
+ implementation: `${name}${!required && !schemaDefault ? "?" : ""}${schemaDefault ? `: ${paramType} = ${stringify(schemaDefault)}` : `: ${paramType}`}`,
2682
+ default: schemaDefault,
2473
2683
  required,
2474
2684
  imports: resolvedValue.imports,
2475
- originalSchema: resolvedValue.originalSchema
2685
+ originalSchema
2476
2686
  };
2477
2687
  });
2478
2688
  }
@@ -2493,7 +2703,7 @@ function getProps({ body, queryParams, params, operationName, headers, context }
2493
2703
  definition: getQueryParamDefinition(queryParams, context),
2494
2704
  implementation: getQueryParamDefinition(queryParams, context),
2495
2705
  default: false,
2496
- required: isUndefined(queryParams?.isOptional) ? !context.output.allParamsOptional || context.output.optionsParamRequired : !queryParams?.isOptional && !context.output.allParamsOptional || context.output.optionsParamRequired,
2706
+ required: isNullish(queryParams?.isOptional) ? !context.output.allParamsOptional || context.output.optionsParamRequired : !queryParams.isOptional && !context.output.allParamsOptional || context.output.optionsParamRequired,
2497
2707
  type: GetterPropType.QUERY_PARAM
2498
2708
  };
2499
2709
  const headersProp = {
@@ -2501,7 +2711,7 @@ function getProps({ body, queryParams, params, operationName, headers, context }
2501
2711
  definition: `headers${headers?.isOptional && !context.output.optionsParamRequired ? "?" : ""}: ${headers?.schema.name}`,
2502
2712
  implementation: `headers${headers?.isOptional && !context.output.optionsParamRequired ? "?" : ""}: ${headers?.schema.name}`,
2503
2713
  default: false,
2504
- required: isUndefined(headers?.isOptional) ? false : !headers?.isOptional || context.output.optionsParamRequired,
2714
+ required: isNullish(headers?.isOptional) ? false : !headers.isOptional || context.output.optionsParamRequired,
2505
2715
  type: GetterPropType.HEADER
2506
2716
  };
2507
2717
  let paramGetterProps;
@@ -2538,13 +2748,27 @@ function getProps({ body, queryParams, params, operationName, headers, context }
2538
2748
  ]);
2539
2749
  }
2540
2750
  function getQueryParamDefinition(queryParams, context) {
2541
- let paramType = queryParams?.schema.name;
2542
- if (OutputClient.ANGULAR === context.output.client) paramType = `DeepNonNullable<${paramType}>`;
2751
+ const paramType = queryParams?.schema.name;
2543
2752
  return `params${(queryParams?.isOptional || context.output.allParamsOptional) && !context.output.optionsParamRequired ? "?" : ""}: ${paramType}`;
2544
2753
  }
2545
2754
 
2546
2755
  //#endregion
2547
2756
  //#region src/getters/query-params.ts
2757
+ const isOpenApiSchemaObject = (value) => {
2758
+ if (!value || typeof value !== "object") return false;
2759
+ return !("$ref" in value);
2760
+ };
2761
+ const isSchemaNullable = (schema) => {
2762
+ if (schema.nullable === true) return true;
2763
+ if (schema.type === "null") return true;
2764
+ if (Array.isArray(schema.type) && schema.type.includes("null")) return true;
2765
+ const oneOfVariants = Array.isArray(schema.oneOf) ? schema.oneOf : [];
2766
+ const anyOfVariants = Array.isArray(schema.anyOf) ? schema.anyOf : [];
2767
+ return [...oneOfVariants, ...anyOfVariants].some((variant) => {
2768
+ if (!isOpenApiSchemaObject(variant)) return false;
2769
+ return isSchemaNullable(variant);
2770
+ });
2771
+ };
2548
2772
  function getQueryParamsTypes(queryParams, operationName, context) {
2549
2773
  return queryParams.map(({ parameter, imports: parameterImports }) => {
2550
2774
  const { name, required, schema: schemaParam, content } = parameter;
@@ -2555,18 +2779,22 @@ function getQueryParamsTypes(queryParams, operationName, context) {
2555
2779
  es5keyword: true,
2556
2780
  es5IdentifierName: true
2557
2781
  });
2558
- const schema = schemaParam || content["application/json"].schema;
2782
+ const schema = schemaParam ?? content?.["application/json"]?.schema;
2783
+ if (!schema) throw new Error(`Query parameter "${name}" has no schema or content definition`);
2559
2784
  const resolvedValue = resolveValue({
2560
2785
  schema,
2561
2786
  context,
2562
2787
  name: queryName
2563
2788
  });
2564
2789
  const key = getKey(name);
2790
+ const schemaForDoc = schema;
2565
2791
  const doc = jsDoc({
2566
2792
  description: parameter.description,
2567
- ...schema
2793
+ ...schemaForDoc
2568
2794
  }, void 0, context);
2569
2795
  if (parameterImports.length > 0) return {
2796
+ name,
2797
+ required,
2570
2798
  definition: `${doc}${key}${!required || schema.default ? "?" : ""}: ${parameterImports[0].name};`,
2571
2799
  imports: parameterImports,
2572
2800
  schemas: [],
@@ -2574,8 +2802,10 @@ function getQueryParamsTypes(queryParams, operationName, context) {
2574
2802
  };
2575
2803
  if (resolvedValue.isEnum && !resolvedValue.isRef) {
2576
2804
  const enumName = queryName;
2577
- const enumValue = getEnum(resolvedValue.value, enumName, getEnumNames(resolvedValue.originalSchema), context.output.override.enumGenerationType, getEnumDescriptions(resolvedValue.originalSchema), context.output.override.namingConvention?.enum);
2805
+ const enumValue = getEnum(resolvedValue.value, enumName, getEnumNames(resolvedValue.originalSchema), context.output.override.enumGenerationType, getEnumDescriptions(resolvedValue.originalSchema), context.output.override.namingConvention.enum);
2578
2806
  return {
2807
+ name,
2808
+ required,
2579
2809
  definition: `${doc}${key}${!required || schema.default ? "?" : ""}: ${enumName};`,
2580
2810
  imports: [{ name: enumName }],
2581
2811
  schemas: [...resolvedValue.schemas, {
@@ -2587,6 +2817,8 @@ function getQueryParamsTypes(queryParams, operationName, context) {
2587
2817
  };
2588
2818
  }
2589
2819
  return {
2820
+ name,
2821
+ required,
2590
2822
  definition: `${doc}${key}${!required || schema.default ? "?" : ""}: ${resolvedValue.value};`,
2591
2823
  imports: resolvedValue.imports,
2592
2824
  schemas: resolvedValue.schemas,
@@ -2602,6 +2834,7 @@ function getQueryParams({ queryParams, operationName, context, suffix = "params"
2602
2834
  const name = `${pascal(operationName)}${pascal(suffix)}`;
2603
2835
  const type = types.map(({ definition }) => definition).join("\n");
2604
2836
  const allOptional = queryParams.every(({ parameter }) => !parameter.required);
2837
+ const requiredNullableKeys = types.filter(({ required, originalSchema }) => required && isSchemaNullable(originalSchema)).map(({ name: name$1 }) => name$1);
2605
2838
  return {
2606
2839
  schema: {
2607
2840
  name,
@@ -2609,46 +2842,24 @@ function getQueryParams({ queryParams, operationName, context, suffix = "params"
2609
2842
  imports
2610
2843
  },
2611
2844
  deps: schemas,
2612
- isOptional: allOptional
2845
+ isOptional: allOptional,
2846
+ requiredNullableKeys
2613
2847
  };
2614
2848
  }
2615
2849
 
2616
2850
  //#endregion
2617
2851
  //#region src/getters/response.ts
2618
2852
  function getResponse({ responses, operationName, context, contentType }) {
2619
- if (!responses) return {
2620
- imports: [],
2621
- definition: {
2622
- success: "",
2623
- errors: ""
2624
- },
2625
- isBlob: false,
2626
- types: {
2627
- success: [],
2628
- errors: []
2629
- },
2630
- schemas: [],
2631
- contentTypes: []
2632
- };
2633
- const types = getResReqTypes(Object.entries(responses), operationName, context, "void", (type) => `${type.key}-${type.value}`);
2634
- const filteredTypes = contentType ? types.filter((type) => {
2635
- let include = true;
2636
- let exclude = false;
2637
- if (contentType.include) include = contentType.include.includes(type.contentType);
2638
- if (contentType.exclude) exclude = contentType.exclude.includes(type.contentType);
2639
- return include && !exclude;
2640
- }) : types;
2853
+ const filteredTypes = filterByContentType(getResReqTypes(Object.entries(responses), operationName, context, "void", (type) => `${type.key}-${type.value}-${type.contentType}`), contentType);
2641
2854
  const imports = filteredTypes.flatMap(({ imports: imports$1 }) => imports$1);
2642
2855
  const schemas = filteredTypes.flatMap(({ schemas: schemas$1 }) => schemas$1);
2643
2856
  const contentTypes = [...new Set(filteredTypes.map(({ contentType: contentType$1 }) => contentType$1))];
2644
- const groupedByStatus = filteredTypes.reduce((acc, type) => {
2645
- if (type.key.startsWith("2")) acc.success.push(type);
2646
- else acc.errors.push(type);
2647
- return acc;
2648
- }, {
2857
+ const groupedByStatus = {
2649
2858
  success: [],
2650
2859
  errors: []
2651
- });
2860
+ };
2861
+ for (const type of filteredTypes) if (type.key.startsWith("2")) groupedByStatus.success.push(type);
2862
+ else groupedByStatus.errors.push(type);
2652
2863
  const success = dedupeUnionType(groupedByStatus.success.map(({ value, formData }) => formData ? "Blob" : value).join(" | "));
2653
2864
  const errors = dedupeUnionType(groupedByStatus.errors.map(({ value }) => value).join(" | "));
2654
2865
  const defaultType = filteredTypes.find(({ key }) => key === "default")?.value;
@@ -2684,16 +2895,18 @@ const getRoutePath = (path$2) => {
2684
2895
  return hasParam(path$2) ? `${prev}\${${param}}${next}` : `${prev}${param}${next}`;
2685
2896
  };
2686
2897
  function getRoute(route) {
2687
- return route.split("/").reduce((acc, path$2, i) => {
2688
- if (!path$2 && !i) return acc;
2689
- if (!path$2.includes("{")) return `${acc}/${path$2}`;
2690
- return `${acc}/${getRoutePath(path$2)}`;
2691
- }, "");
2898
+ const splittedRoute = route.split("/");
2899
+ let result = "";
2900
+ for (const [i, path$2] of splittedRoute.entries()) {
2901
+ if (!path$2 && !i) continue;
2902
+ result += path$2.includes("{") ? `/${getRoutePath(path$2)}` : `/${path$2}`;
2903
+ }
2904
+ return result;
2692
2905
  }
2693
2906
  function getFullRoute(route, servers, baseUrl) {
2694
2907
  const getBaseUrl = () => {
2695
2908
  if (!baseUrl) return "";
2696
- if (typeof baseUrl === "string") return baseUrl;
2909
+ if (isString(baseUrl)) return baseUrl;
2697
2910
  if (baseUrl.getBaseUrlFromSpecification) {
2698
2911
  if (!servers) throw new Error("Orval is configured to use baseUrl from the specifications 'servers' field, but there exist no servers in the specification.");
2699
2912
  const server = servers.at(Math.min(baseUrl.index ?? 0, servers.length - 1));
@@ -2756,7 +2969,7 @@ function generateComponentDefinition(responses = {}, context, suffix) {
2756
2969
  //#region src/generators/imports.ts
2757
2970
  function generateImports({ imports, namingConvention = NamingConvention.CAMEL_CASE }) {
2758
2971
  if (imports.length === 0) return "";
2759
- const grouped = groupBy(uniqueWith(imports, (a, b) => a.name === b.name && a.default === b.default).map((imp) => ({
2972
+ const grouped = groupBy(uniqueWith(imports, (a, b) => a.name === b.name && a.default === b.default && a.alias === b.alias && a.values === b.values && a.isConstant === b.isConstant && a.namespaceImport === b.namespaceImport && a.syntheticDefaultImport === b.syntheticDefaultImport && a.importPath === b.importPath).map((imp) => ({
2760
2973
  ...imp,
2761
2974
  importPath: imp.importPath ?? `./${conventionName(imp.name, namingConvention)}`
2762
2975
  })), (imp) => !imp.default && !imp.namespaceImport && !imp.syntheticDefaultImport && !imp.values && !imp.isConstant ? `aggregate|${imp.importPath}` : `single|${imp.importPath}|${imp.name}|${imp.alias ?? ""}|${String(imp.default)}|${String(imp.namespaceImport)}|${String(imp.syntheticDefaultImport)}|${String(imp.values)}|${String(imp.isConstant)}`);
@@ -2768,25 +2981,26 @@ function generateImports({ imports, namingConvention = NamingConvention.CAMEL_CA
2768
2981
  }).join("\n");
2769
2982
  }
2770
2983
  function generateMutatorImports({ mutators, implementation, oneMore }) {
2771
- return uniqueWith(mutators, (a, b) => a.name === b.name && a.default === b.default).reduce((acc, mutator) => {
2984
+ let imports = "";
2985
+ for (const mutator of uniqueWith(mutators, (a, b) => a.name === b.name && a.default === b.default)) {
2772
2986
  const path$2 = `${oneMore ? "../" : ""}${mutator.path}`;
2773
2987
  const importDefault = mutator.default ? mutator.name : `{ ${mutator.name} }`;
2774
- acc += `import ${importDefault} from '${path$2}';`;
2775
- acc += "\n";
2988
+ imports += `import ${importDefault} from '${path$2}';`;
2989
+ imports += "\n";
2776
2990
  if (implementation && (mutator.hasErrorType || mutator.bodyTypeName)) {
2777
2991
  let errorImportName = "";
2778
2992
  const targetErrorImportName = mutator.default ? `ErrorType as ${mutator.errorTypeName}` : mutator.errorTypeName;
2779
- if (mutator.hasErrorType && implementation.includes(mutator.errorTypeName) && !acc.includes(`{ ${targetErrorImportName} `)) errorImportName = targetErrorImportName;
2993
+ if (mutator.hasErrorType && implementation.includes(mutator.errorTypeName) && !imports.includes(`{ ${targetErrorImportName} `)) errorImportName = targetErrorImportName;
2780
2994
  let bodyImportName = "";
2781
2995
  const targetBodyImportName = mutator.default ? `BodyType as ${mutator.bodyTypeName}` : mutator.bodyTypeName;
2782
- if (mutator.bodyTypeName && implementation.includes(mutator.bodyTypeName) && !acc.includes(` ${targetBodyImportName} }`)) bodyImportName = targetBodyImportName;
2996
+ if (mutator.bodyTypeName && implementation.includes(mutator.bodyTypeName) && !imports.includes(` ${targetBodyImportName} }`)) bodyImportName = targetBodyImportName ?? "";
2783
2997
  if (bodyImportName || errorImportName) {
2784
- acc += `import type { ${errorImportName}${errorImportName && bodyImportName ? " , " : ""}${bodyImportName} } from '${path$2}';`;
2785
- acc += "\n";
2998
+ imports += `import type { ${errorImportName}${errorImportName && bodyImportName ? " , " : ""}${bodyImportName} } from '${path$2}';`;
2999
+ imports += "\n";
2786
3000
  }
2787
3001
  }
2788
- return acc;
2789
- }, "");
3002
+ }
3003
+ return imports;
2790
3004
  }
2791
3005
  function generateDependency({ deps, isAllowSyntheticDefaultImports, dependency, projectName, key, onlyTypes }) {
2792
3006
  const defaultDep = deps.find((e) => e.default && (isAllowSyntheticDefaultImports || !e.syntheticDefaultImport));
@@ -2801,31 +3015,25 @@ function generateDependency({ deps, isAllowSyntheticDefaultImports, dependency,
2801
3015
  importString += `import ${onlyTypes ? "type " : ""}${defaultDep ? `${defaultDep.name}${depsString ? "," : ""}` : ""}${depsString ? `{\n ${depsString}\n}` : ""} from '${dependency}${key !== "default" && projectName ? `/${projectName}` : ""}';`;
2802
3016
  return importString;
2803
3017
  }
2804
- function addDependency({ implementation, exports, dependency, projectName, hasSchemaDir, isAllowSyntheticDefaultImports }) {
3018
+ function addDependency({ implementation, exports, dependency, projectName, isAllowSyntheticDefaultImports }) {
2805
3019
  const toAdds = exports.filter((e) => {
2806
3020
  const searchWords = [e.alias, e.name].filter((p) => p?.length).join("|");
2807
3021
  const pattern = new RegExp(String.raw`\b(${searchWords})\b`, "g");
2808
3022
  return implementation.match(pattern);
2809
3023
  });
2810
3024
  if (toAdds.length === 0) return;
2811
- const groupedBySpecKey = toAdds.reduce((acc, dep) => {
3025
+ const groupedBySpecKey = { default: {
3026
+ types: [],
3027
+ values: []
3028
+ } };
3029
+ for (const dep of toAdds) {
2812
3030
  const key = "default";
2813
- if (dep.values && (isAllowSyntheticDefaultImports || !dep.syntheticDefaultImport)) {
2814
- acc[key] = {
2815
- ...acc[key],
2816
- values: [...acc[key]?.values ?? [], dep]
2817
- };
2818
- return acc;
2819
- }
2820
- acc[key] = {
2821
- ...acc[key],
2822
- types: [...acc[key]?.types ?? [], dep]
2823
- };
2824
- return acc;
2825
- }, {});
3031
+ if (dep.values && (isAllowSyntheticDefaultImports || !dep.syntheticDefaultImport)) groupedBySpecKey[key].values.push(dep);
3032
+ else groupedBySpecKey[key].types.push(dep);
3033
+ }
2826
3034
  return Object.entries(groupedBySpecKey).map(([key, { values, types }]) => {
2827
3035
  let dep = "";
2828
- if (values) dep += generateDependency({
3036
+ if (values.length > 0) dep += generateDependency({
2829
3037
  deps: values,
2830
3038
  isAllowSyntheticDefaultImports,
2831
3039
  dependency,
@@ -2833,10 +3041,10 @@ function addDependency({ implementation, exports, dependency, projectName, hasSc
2833
3041
  key,
2834
3042
  onlyTypes: false
2835
3043
  });
2836
- if (types) {
3044
+ if (types.length > 0) {
2837
3045
  let uniqueTypes = types;
2838
- if (values) {
2839
- uniqueTypes = types.filter((t) => !values.some((v) => v.name === t.name));
3046
+ if (values.length > 0) {
3047
+ uniqueTypes = types.filter((t) => !values.some((v) => v.name === t.name && (v.alias ?? "") === (t.alias ?? "")));
2840
3048
  dep += "\n";
2841
3049
  }
2842
3050
  dep += generateDependency({
@@ -2862,7 +3070,7 @@ function generateDependencyImports(implementation, imports, projectName, hasSche
2862
3070
  projectName,
2863
3071
  hasSchemaDir,
2864
3072
  isAllowSyntheticDefaultImports
2865
- })).filter(Boolean).sort((a, b) => {
3073
+ })).filter((x) => Boolean(x)).toSorted((a, b) => {
2866
3074
  const aLib = getLibName(a);
2867
3075
  const bLib = getLibName(b);
2868
3076
  if (aLib === bLib) return 0;
@@ -2879,7 +3087,17 @@ function generateVerbImports({ response, body, queryParams, props, headers, para
2879
3087
  ...queryParams ? [{ name: queryParams.schema.name }] : [],
2880
3088
  ...headers ? [{ name: headers.schema.name }] : [],
2881
3089
  ...params.flatMap(({ imports }) => imports)
2882
- ];
3090
+ ].flatMap((imp) => {
3091
+ if (imp.name !== "Error" || !imp.values || imp.alias) return [imp];
3092
+ return [{
3093
+ ...imp,
3094
+ values: void 0
3095
+ }, {
3096
+ ...imp,
3097
+ alias: "ErrorSchema",
3098
+ values: true
3099
+ }];
3100
+ });
2883
3101
  }
2884
3102
 
2885
3103
  //#endregion
@@ -2888,7 +3106,10 @@ function generateModelInline(acc, model) {
2888
3106
  return acc + `${model}\n`;
2889
3107
  }
2890
3108
  function generateModelsInline(obj) {
2891
- return Object.values(obj).flat().reduce((acc, { model }) => generateModelInline(acc, model), "");
3109
+ const schemas = Object.values(obj).flat();
3110
+ let result = "";
3111
+ for (const { model } of schemas) result = generateModelInline(result, model);
3112
+ return result;
2892
3113
  }
2893
3114
 
2894
3115
  //#endregion
@@ -2914,7 +3135,7 @@ async function bundleFile(root, fileName, alias, external, compilerOptions) {
2914
3135
  treeShaking: false,
2915
3136
  keepNames: false,
2916
3137
  alias,
2917
- external: external || ["*"]
3138
+ external: external ?? ["*"]
2918
3139
  })).outputFiles[0];
2919
3140
  return text;
2920
3141
  }
@@ -3038,46 +3259,143 @@ function removeComments(file) {
3038
3259
 
3039
3260
  //#endregion
3040
3261
  //#region src/generators/options.ts
3262
+ /**
3263
+ * Filters query params for Angular's HttpClient.
3264
+ *
3265
+ * Why: Angular's HttpParams / HttpClient `params` type does not accept `null` or
3266
+ * `undefined` values, and arrays must only contain string/number/boolean.
3267
+ * Orval models often include nullable query params, so we remove nullish values
3268
+ * (including nulls inside arrays) before passing params to HttpClient or a
3269
+ * paramsSerializer to avoid runtime and type issues.
3270
+ *
3271
+ * Returns an inline IIFE expression. For paths that benefit from a shared helper
3272
+ * (e.g. observe-mode branches), prefer getAngularFilteredParamsCallExpression +
3273
+ * getAngularFilteredParamsHelperBody instead.
3274
+ */
3275
+ const getAngularFilteredParamsExpression = (paramsExpression, requiredNullableParamKeys = []) => `(() => {
3276
+ const requiredNullableParamKeys = new Set<string>(${JSON.stringify(requiredNullableParamKeys)});
3277
+ const filteredParams = {} as Record<string, string | number | boolean | null | Array<string | number | boolean>>;
3278
+ for (const [key, value] of Object.entries(${paramsExpression})) {
3279
+ if (Array.isArray(value)) {
3280
+ const filtered = value.filter(
3281
+ (item) =>
3282
+ item != null &&
3283
+ (typeof item === 'string' ||
3284
+ typeof item === 'number' ||
3285
+ typeof item === 'boolean'),
3286
+ ) as Array<string | number | boolean>;
3287
+ if (filtered.length) {
3288
+ filteredParams[key] = filtered;
3289
+ }
3290
+ } else if (value === null && requiredNullableParamKeys.has(key)) {
3291
+ filteredParams[key] = value;
3292
+ } else if (
3293
+ value != null &&
3294
+ (typeof value === 'string' ||
3295
+ typeof value === 'number' ||
3296
+ typeof value === 'boolean')
3297
+ ) {
3298
+ filteredParams[key] = value as string | number | boolean;
3299
+ }
3300
+ }
3301
+ return filteredParams as unknown as Record<string, string | number | boolean | Array<string | number | boolean>>;
3302
+ })()`;
3303
+ /**
3304
+ * Returns the body of a standalone `filterParams` helper function
3305
+ * to be emitted once in the generated file header, replacing the
3306
+ * inline IIFE that was previously duplicated in every method.
3307
+ */
3308
+ const getAngularFilteredParamsHelperBody = () => `function filterParams(
3309
+ params: Record<string, unknown>,
3310
+ requiredNullableKeys: Set<string> = new Set(),
3311
+ ): Record<string, string | number | boolean | Array<string | number | boolean>> {
3312
+ const filteredParams: Record<string, string | number | boolean | null | Array<string | number | boolean>> = {};
3313
+ for (const [key, value] of Object.entries(params)) {
3314
+ if (Array.isArray(value)) {
3315
+ const filtered = value.filter(
3316
+ (item) =>
3317
+ item != null &&
3318
+ (typeof item === 'string' ||
3319
+ typeof item === 'number' ||
3320
+ typeof item === 'boolean'),
3321
+ ) as Array<string | number | boolean>;
3322
+ if (filtered.length) {
3323
+ filteredParams[key] = filtered;
3324
+ }
3325
+ } else if (value === null && requiredNullableKeys.has(key)) {
3326
+ filteredParams[key] = value;
3327
+ } else if (
3328
+ value != null &&
3329
+ (typeof value === 'string' ||
3330
+ typeof value === 'number' ||
3331
+ typeof value === 'boolean')
3332
+ ) {
3333
+ filteredParams[key] = value as string | number | boolean;
3334
+ }
3335
+ }
3336
+ return filteredParams as Record<string, string | number | boolean | Array<string | number | boolean>>;
3337
+ }`;
3338
+ /**
3339
+ * Returns a call expression to the `filterParams` helper function.
3340
+ */
3341
+ const getAngularFilteredParamsCallExpression = (paramsExpression, requiredNullableParamKeys = []) => `filterParams(${paramsExpression}, new Set<string>(${JSON.stringify(requiredNullableParamKeys)}))`;
3041
3342
  function generateBodyOptions(body, isFormData, isFormUrlEncoded) {
3042
3343
  if (isFormData && body.formData) return "\n formData,";
3043
3344
  if (isFormUrlEncoded && body.formUrlEncoded) return "\n formUrlEncoded,";
3044
3345
  if (body.implementation) return `\n ${body.implementation},`;
3045
3346
  return "";
3046
3347
  }
3047
- function generateAxiosOptions({ response, isExactOptionalPropertyTypes, queryParams, headers, requestOptions, hasSignal, hasSignalParam = false, isVue, isAngular, paramsSerializer, paramsSerializerOptions }) {
3348
+ function generateAxiosOptions({ response, isExactOptionalPropertyTypes, angularObserve, angularParamsRef, requiredNullableQueryParamKeys, queryParams, headers, requestOptions, hasSignal, hasSignalParam = false, isVue, isAngular, paramsSerializer, paramsSerializerOptions }) {
3048
3349
  const isRequestOptions = requestOptions !== false;
3049
3350
  const signalVar = hasSignalParam ? "querySignal" : "signal";
3050
3351
  const signalProp = hasSignalParam ? `signal: ${signalVar}` : "signal";
3051
3352
  if (!queryParams && !headers && !response.isBlob && response.definition.success !== "string") {
3052
- if (isRequestOptions) return "options";
3353
+ if (isRequestOptions) return isAngular ? angularObserve ? `{
3354
+ ...(options as Omit<NonNullable<typeof options>, 'observe'>),
3355
+ observe: '${angularObserve}',
3356
+ }` : "(options as Omit<NonNullable<typeof options>, 'observe'>)" : "options";
3053
3357
  if (hasSignal) return isExactOptionalPropertyTypes ? `...(${signalVar} ? { ${signalProp} } : {})` : signalProp;
3054
3358
  return "";
3055
3359
  }
3056
3360
  let value = "";
3057
3361
  if (!isRequestOptions) {
3058
- if (queryParams) value += "\n params,";
3362
+ if (queryParams) if (isAngular) {
3363
+ const iifeExpr = getAngularFilteredParamsExpression("params ?? {}", requiredNullableQueryParamKeys);
3364
+ value += paramsSerializer ? `\n params: ${paramsSerializer.name}(${iifeExpr}),` : `\n params: ${iifeExpr},`;
3365
+ } else value += "\n params,";
3059
3366
  if (headers) value += "\n headers,";
3060
3367
  if (hasSignal) value += isExactOptionalPropertyTypes ? `\n ...(${signalVar} ? { ${signalProp} } : {}),` : `\n ${signalProp},`;
3061
3368
  }
3062
- if (!isObject(requestOptions) || !requestOptions.hasOwnProperty("responseType")) {
3063
- if (response.isBlob) value += `\n responseType: 'blob',`;
3064
- else if (response.contentTypes.at(0) === "text/plain") value += `\n responseType: 'text',`;
3369
+ if (!isObject(requestOptions) || !Object.hasOwn(requestOptions, "responseType")) {
3370
+ const successResponseType = getSuccessResponseType(response);
3371
+ if (successResponseType) value += `\n responseType: '${successResponseType}',`;
3065
3372
  }
3066
3373
  if (isObject(requestOptions)) value += `\n ${stringify(requestOptions)?.slice(1, -1)}`;
3067
3374
  if (isRequestOptions) {
3068
- value += "\n ...options,";
3375
+ value += isAngular ? "\n ...(options as Omit<NonNullable<typeof options>, 'observe'>)," : "\n ...options,";
3376
+ if (isAngular && angularObserve) value += `\n observe: '${angularObserve}',`;
3069
3377
  if (queryParams) if (isVue) value += "\n params: {...unref(params), ...options?.params},";
3070
- else if (isAngular && paramsSerializer) value += `\n params: ${paramsSerializer.name}({...params, ...options?.params}),`;
3378
+ else if (isAngular && angularParamsRef) value += `\n params: ${angularParamsRef},`;
3379
+ else if (isAngular && paramsSerializer) {
3380
+ const callExpr = getAngularFilteredParamsCallExpression("{...params, ...options?.params}", requiredNullableQueryParamKeys);
3381
+ value += `\n params: ${paramsSerializer.name}(${callExpr}),`;
3382
+ } else if (isAngular) value += `\n params: ${getAngularFilteredParamsCallExpression("{...params, ...options?.params}", requiredNullableQueryParamKeys)},`;
3071
3383
  else value += "\n params: {...params, ...options?.params},";
3072
3384
  if (headers) value += "\n headers: {...headers, ...options?.headers},";
3073
3385
  }
3074
- if (!isAngular && queryParams && (paramsSerializer || paramsSerializerOptions?.qs)) value += paramsSerializer ? `\n paramsSerializer: ${paramsSerializer.name},` : `\n paramsSerializer: (params) => qs.stringify(params, ${JSON.stringify(paramsSerializerOptions.qs)}),`;
3386
+ if (!isAngular && queryParams && (paramsSerializer || paramsSerializerOptions?.qs)) {
3387
+ const qsOptions = paramsSerializerOptions?.qs;
3388
+ value += paramsSerializer ? `\n paramsSerializer: ${paramsSerializer.name},` : `\n paramsSerializer: (params) => qs.stringify(params, ${JSON.stringify(qsOptions)}),`;
3389
+ }
3075
3390
  return value;
3076
3391
  }
3077
- function generateOptions({ route, body, headers, queryParams, response, verb, requestOptions, isFormData, isFormUrlEncoded, isAngular, isExactOptionalPropertyTypes, hasSignal, hasSignalParam, isVue, paramsSerializer, paramsSerializerOptions }) {
3392
+ function generateOptions({ route, body, angularObserve, angularParamsRef, headers, queryParams, response, verb, requestOptions, isFormData, isFormUrlEncoded, isAngular, isExactOptionalPropertyTypes, hasSignal, hasSignalParam, isVue, paramsSerializer, paramsSerializerOptions }) {
3078
3393
  const bodyOptions = getIsBodyVerb(verb) ? generateBodyOptions(body, isFormData, isFormUrlEncoded) : "";
3079
3394
  const axiosOptions = generateAxiosOptions({
3080
3395
  response,
3396
+ angularObserve,
3397
+ angularParamsRef,
3398
+ requiredNullableQueryParamKeys: queryParams?.requiredNullableKeys,
3081
3399
  queryParams: queryParams?.schema,
3082
3400
  headers: headers?.schema,
3083
3401
  requestOptions,
@@ -3089,12 +3407,15 @@ function generateOptions({ route, body, headers, queryParams, response, verb, re
3089
3407
  paramsSerializer,
3090
3408
  paramsSerializerOptions
3091
3409
  });
3092
- const options = axiosOptions ? `{${axiosOptions}}` : "";
3410
+ const isRawOptionsArgument = axiosOptions === "options" || axiosOptions.startsWith("(") && axiosOptions.endsWith(")");
3411
+ const optionsArgument = axiosOptions ? isRawOptionsArgument ? axiosOptions : `{${axiosOptions}}` : "";
3093
3412
  if (verb === Verbs.DELETE) {
3094
- if (!bodyOptions) return `\n \`${route}\`,${axiosOptions === "options" ? axiosOptions : options}\n `;
3095
- return `\n \`${route}\`,{${isAngular ? "body" : "data"}:${bodyOptions} ${axiosOptions === "options" ? `...${axiosOptions}` : axiosOptions}}\n `;
3413
+ if (!bodyOptions) return `\n \`${route}\`${optionsArgument ? `,${optionsArgument}` : ""}\n `;
3414
+ const deleteBodyOptions = isRawOptionsArgument ? `...${optionsArgument}` : axiosOptions;
3415
+ return `\n \`${route}\`,{${isAngular ? "body" : "data"}:${bodyOptions} ${axiosOptions ? deleteBodyOptions : ""}}\n `;
3096
3416
  }
3097
- return `\n \`${route}\`,${getIsBodyVerb(verb) ? bodyOptions || "undefined," : ""}${axiosOptions === "options" ? axiosOptions : options}\n `;
3417
+ const bodyOrOptions = getIsBodyVerb(verb) ? bodyOptions || "undefined," : "";
3418
+ return `\n \`${route}\`${bodyOrOptions || optionsArgument ? "," : ""}${bodyOrOptions}${optionsArgument}\n `;
3098
3419
  }
3099
3420
  function generateBodyMutatorConfig(body, isFormData, isFormUrlEncoded) {
3100
3421
  if (isFormData && body.formData) return ",\n data: formData";
@@ -3102,17 +3423,19 @@ function generateBodyMutatorConfig(body, isFormData, isFormUrlEncoded) {
3102
3423
  if (body.implementation) return `,\n data: ${body.implementation}`;
3103
3424
  return "";
3104
3425
  }
3105
- function generateQueryParamsAxiosConfig(response, isVue, queryParams) {
3426
+ function generateQueryParamsAxiosConfig(response, isVue, isAngular, requiredNullableQueryParamKeys, queryParams) {
3106
3427
  if (!queryParams && !response.isBlob) return "";
3107
3428
  let value = "";
3108
- if (queryParams) value += isVue ? ",\n params: unref(params)" : ",\n params";
3429
+ if (queryParams) if (isVue) value += ",\n params: unref(params)";
3430
+ else if (isAngular) value += `,\n params: ${getAngularFilteredParamsExpression("params ?? {}", requiredNullableQueryParamKeys)}`;
3431
+ else value += ",\n params";
3109
3432
  if (response.isBlob) value += `,\n responseType: 'blob'`;
3110
3433
  return value;
3111
3434
  }
3112
- function generateMutatorConfig({ route, body, headers, queryParams, response, verb, isFormData, isFormUrlEncoded, hasSignal, hasSignalParam = false, isExactOptionalPropertyTypes, isVue }) {
3435
+ function generateMutatorConfig({ route, body, headers, queryParams, response, verb, isFormData, isFormUrlEncoded, hasSignal, hasSignalParam = false, isExactOptionalPropertyTypes, isVue, isAngular }) {
3113
3436
  const bodyOptions = getIsBodyVerb(verb) ? generateBodyMutatorConfig(body, isFormData, isFormUrlEncoded) : "";
3114
- const queryParamsOptions = generateQueryParamsAxiosConfig(response, isVue ?? false, queryParams);
3115
- const headerOptions = body.contentType ? `,\n headers: {'Content-Type': '${body.contentType}', ${headers ? "...headers" : ""}}` : headers ? ",\n headers" : "";
3437
+ const queryParamsOptions = generateQueryParamsAxiosConfig(response, isVue ?? false, isAngular ?? false, queryParams?.requiredNullableKeys, queryParams);
3438
+ const headerOptions = body.contentType && !["multipart/form-data"].includes(body.contentType) ? `,\n headers: {'Content-Type': '${body.contentType}', ${headers ? "...headers" : ""}}` : headers ? ",\n headers" : "";
3116
3439
  const signalVar = hasSignalParam ? "querySignal" : "signal";
3117
3440
  const signalProp = hasSignalParam ? `signal: ${signalVar}` : "signal";
3118
3441
  return `{url: \`${route}\`, method: '${verb.toUpperCase()}'${headerOptions}${bodyOptions}${queryParamsOptions}${hasSignal ? `, ${isExactOptionalPropertyTypes ? `...(${signalVar} ? { ${signalProp} }: {})` : signalProp}` : ""}\n }`;
@@ -3194,18 +3517,20 @@ function generateInterface({ name, schema, context }) {
3194
3517
  context
3195
3518
  });
3196
3519
  const isEmptyObject = scalar.value === "{}";
3197
- const shouldUseTypeAlias = context?.output.override?.useTypeOverInterfaces || scalar.useTypeAlias;
3520
+ const shouldUseTypeAlias = context.output.override.useTypeOverInterfaces ?? scalar.useTypeAlias;
3198
3521
  let model = "";
3199
3522
  model += jsDoc(schema);
3200
3523
  if (isEmptyObject) model += "// eslint-disable-next-line @typescript-eslint/no-empty-interface\n";
3201
- if (scalar.type === "object" && !shouldUseTypeAlias) if (scalar.type === "object" && schema.properties && Object.values(schema.properties).length > 0 && Object.values(schema.properties).every((item) => "const" in item)) {
3202
- const mappedScalarValue = scalar.value.replaceAll(";", ",").replaceAll("?:", ":");
3203
- model += `export const ${name}Value = ${mappedScalarValue} as const;\nexport type ${name} = typeof ${name}Value;\n`;
3204
- } else {
3205
- const blankInterfaceValue = scalar.value === "unknown" ? "{}" : scalar.value;
3206
- model += `export interface ${name} ${blankInterfaceValue}\n`;
3207
- }
3208
- else model += `export type ${name} = ${scalar.value};\n`;
3524
+ if (scalar.type === "object" && !shouldUseTypeAlias) {
3525
+ const properties = schema.properties;
3526
+ if (properties && Object.values(properties).length > 0 && Object.values(properties).every((item) => "const" in item)) {
3527
+ const mappedScalarValue = scalar.value.replaceAll(";", ",").replaceAll("?:", ":");
3528
+ model += `export const ${name}Value = ${mappedScalarValue} as const;\nexport type ${name} = typeof ${name}Value;\n`;
3529
+ } else {
3530
+ const blankInterfaceValue = scalar.value === "unknown" ? "{}" : scalar.value;
3531
+ model += `export interface ${name} ${blankInterfaceValue}\n`;
3532
+ }
3533
+ } else model += `export type ${name} = ${scalar.value};\n`;
3209
3534
  const externalModulesImportsOnly = scalar.imports.filter((importName) => importName.alias ? importName.alias !== name : importName.name !== name);
3210
3535
  return [...scalar.schemas, {
3211
3536
  name,
@@ -3255,7 +3580,7 @@ function sortSchemasByDependencies(schemas) {
3255
3580
  for (const dependencyName of schema.dependencies) if (dependencyName && schemaNames.has(dependencyName)) dependencies.add(dependencyName);
3256
3581
  }
3257
3582
  for (const imp of schema.imports) {
3258
- const dependencyName = imp.alias || imp.name;
3583
+ const dependencyName = imp.alias ?? imp.name;
3259
3584
  if (dependencyName && schemaNames.has(dependencyName)) dependencies.add(dependencyName);
3260
3585
  }
3261
3586
  dependencyMap.set(schema.name, dependencies);
@@ -3292,7 +3617,7 @@ function generateSchemaDefinitions(schemaName, schema, context, suffix) {
3292
3617
  es5keyword: true,
3293
3618
  es5IdentifierName: true
3294
3619
  });
3295
- if (typeof schema === "boolean") return [{
3620
+ if (isBoolean(schema)) return [{
3296
3621
  name: sanitizedSchemaName,
3297
3622
  model: `export type ${sanitizedSchemaName} = ${schema ? "any" : "never"};\n`,
3298
3623
  imports: [],
@@ -3311,7 +3636,7 @@ function generateSchemaDefinitions(schemaName, schema, context, suffix) {
3311
3636
  let output = "";
3312
3637
  let imports = resolvedValue.imports;
3313
3638
  output += jsDoc(schema);
3314
- if (resolvedValue.isEnum && !resolvedValue.isRef) output += getEnum(resolvedValue.value, sanitizedSchemaName, getEnumNames(resolvedValue.originalSchema), context.output.override.enumGenerationType, getEnumDescriptions(resolvedValue.originalSchema), context.output.override.namingConvention?.enum);
3639
+ if (resolvedValue.isEnum && !resolvedValue.isRef) output += getEnum(resolvedValue.value, sanitizedSchemaName, getEnumNames(resolvedValue.originalSchema), context.output.override.enumGenerationType, getEnumDescriptions(resolvedValue.originalSchema), context.output.override.namingConvention.enum);
3315
3640
  else if (sanitizedSchemaName === resolvedValue.value && resolvedValue.isRef) {
3316
3641
  const { schema: referredSchema } = resolveRef(schema, context);
3317
3642
  if (!shouldCreateInterface(referredSchema)) {
@@ -3330,7 +3655,7 @@ function generateSchemaDefinitions(schemaName, schema, context, suffix) {
3330
3655
  resolvedValue.schemas = resolvedValue.schemas.filter((schema$1) => {
3331
3656
  if (schema$1.name !== sanitizedSchemaName) return true;
3332
3657
  output += `${schema$1.model}\n`;
3333
- imports = imports.concat(schema$1.imports);
3658
+ imports = [...imports, ...schema$1.imports];
3334
3659
  resolvedValue.dependencies.push(...schema$1.dependencies ?? []);
3335
3660
  return false;
3336
3661
  });
@@ -3347,26 +3672,56 @@ function generateSchemaDefinitions(schemaName, schema, context, suffix) {
3347
3672
 
3348
3673
  //#endregion
3349
3674
  //#region src/generators/verbs-options.ts
3350
- async function generateVerbOptions({ verb, output, operation, route, pathRoute, verbParameters = [], context }) {
3351
- const { responses, requestBody, parameters: operationParameters, tags = [], deprecated, description, summary } = operation;
3675
+ /**
3676
+ * Get a content-type specific suffix for operation names (#2812)
3677
+ */
3678
+ function getContentTypeSuffix(contentType) {
3679
+ return {
3680
+ "application/json": "Json",
3681
+ "multipart/form-data": "FormData",
3682
+ "application/x-www-form-urlencoded": "UrlEncoded",
3683
+ "application/xml": "Xml",
3684
+ "text/plain": "Text"
3685
+ }[contentType] || pascal(contentType.replaceAll(/[^a-zA-Z0-9]/g, "_"));
3686
+ }
3687
+ async function generateVerbOptions({ verb, output, operation, route, pathRoute, verbParameters = [], context, contentType }) {
3688
+ const { responses, requestBody, parameters: operationParameters, tags: rawTags, deprecated: rawDeprecated, description: rawDescription, summary: rawSummary } = operation;
3689
+ const tags = rawTags ?? [];
3690
+ const deprecated = rawDeprecated;
3691
+ const description = rawDescription;
3692
+ const summary = rawSummary;
3352
3693
  const operationId = getOperationId(operation, route, verb);
3353
3694
  const overrideOperation = output.override.operations[operationId];
3354
- const overrideTag = Object.entries(output.override.tags).reduce((acc, [tag, options]) => tags.includes(tag) && options ? mergeDeep(acc, options) : acc, {});
3355
- const override = mergeDeep(mergeDeep(output.override, overrideTag), overrideOperation);
3695
+ let overrideTag = {};
3696
+ for (const [tag, options] of Object.entries(output.override.tags)) if (tags.includes(tag) && options) overrideTag = mergeDeep(overrideTag, options);
3697
+ const override = mergeDeep(mergeDeep(output.override, overrideTag), overrideOperation ?? {});
3698
+ const originalContentTypeFilter = override.contentType;
3699
+ const requestBodyContentTypeFilter = contentType ? { include: [contentType] } : override.contentType;
3356
3700
  const overrideOperationName = overrideOperation?.operationName ?? output.override.operationName;
3357
- const operationName = overrideOperationName ? overrideOperationName(operation, route, verb) : sanitize(camel(operationId), { es5keyword: true });
3701
+ let operationName = overrideOperationName ? overrideOperationName(operation, route, verb) : sanitize(camel(operationId), { es5keyword: true });
3702
+ if (contentType) operationName = operationName + "With" + getContentTypeSuffix(contentType);
3358
3703
  const response = getResponse({
3359
- responses,
3704
+ responses: responses ?? {},
3360
3705
  operationName,
3361
3706
  context,
3362
- contentType: override.contentType
3707
+ contentType: originalContentTypeFilter
3363
3708
  });
3364
- const body = getBody({
3709
+ const body = requestBody ? getBody({
3365
3710
  requestBody,
3366
3711
  operationName,
3367
3712
  context,
3368
- contentType: override.contentType
3369
- });
3713
+ contentType: requestBodyContentTypeFilter
3714
+ }) : {
3715
+ originalSchema: {},
3716
+ definition: "",
3717
+ implementation: "",
3718
+ imports: [],
3719
+ schemas: [],
3720
+ formData: "",
3721
+ formUrlEncoded: "",
3722
+ contentType: "",
3723
+ isOptional: false
3724
+ };
3370
3725
  const parameters = getParameters({
3371
3726
  parameters: [...verbParameters, ...operationParameters ?? []],
3372
3727
  context
@@ -3442,7 +3797,7 @@ async function generateVerbOptions({ verb, output, operation, route, pathRoute,
3442
3797
  tags,
3443
3798
  route,
3444
3799
  pathRoute,
3445
- summary: operation.summary,
3800
+ summary,
3446
3801
  operationId,
3447
3802
  operationName,
3448
3803
  response,
@@ -3467,23 +3822,39 @@ async function generateVerbOptions({ verb, output, operation, route, pathRoute,
3467
3822
  function generateVerbsOptions({ verbs, input, output, route, pathRoute, context }) {
3468
3823
  return asyncReduce(_filteredVerbs(verbs, input.filters), async (acc, [verb, operation]) => {
3469
3824
  if (isVerb(verb)) {
3470
- const verbOptions = await generateVerbOptions({
3471
- verb,
3472
- output,
3473
- verbParameters: verbs.parameters,
3474
- route,
3475
- pathRoute,
3476
- operation,
3477
- context
3478
- });
3479
- acc.push(verbOptions);
3825
+ const contentTypes = getRequestBodyContentTypes(operation.requestBody, context);
3826
+ if (contentTypes.length > 1) for (const contentType of contentTypes) {
3827
+ const verbOptions = await generateVerbOptions({
3828
+ verb,
3829
+ output,
3830
+ verbParameters: verbs.parameters,
3831
+ route,
3832
+ pathRoute,
3833
+ operation,
3834
+ context,
3835
+ contentType
3836
+ });
3837
+ acc.push(verbOptions);
3838
+ }
3839
+ else {
3840
+ const verbOptions = await generateVerbOptions({
3841
+ verb,
3842
+ output,
3843
+ verbParameters: verbs.parameters,
3844
+ route,
3845
+ pathRoute,
3846
+ operation,
3847
+ context
3848
+ });
3849
+ acc.push(verbOptions);
3850
+ }
3480
3851
  }
3481
3852
  return acc;
3482
3853
  }, []);
3483
3854
  }
3484
3855
  function _filteredVerbs(verbs, filters) {
3485
3856
  if (filters?.tags === void 0) return Object.entries(verbs);
3486
- const filterTags = filters.tags || [];
3857
+ const filterTags = filters.tags;
3487
3858
  const filterMode = filters.mode ?? "include";
3488
3859
  return Object.entries(verbs).filter(([, operation]) => {
3489
3860
  const isMatch = (operation.tags ?? []).some((tag) => filterTags.some((filterTag) => filterTag instanceof RegExp ? filterTag.test(tag) : filterTag === tag));
@@ -3529,17 +3900,25 @@ function splitSchemasByType(schemas) {
3529
3900
  };
3530
3901
  }
3531
3902
  /**
3903
+ * Get the import extension from a file extension.
3904
+ * Removes `.ts` suffix since TypeScript doesn't need it in imports.
3905
+ */
3906
+ function getImportExtension(fileExtension) {
3907
+ return fileExtension.replace(/\.ts$/, "") || "";
3908
+ }
3909
+ /**
3532
3910
  * Fix cross-directory imports when schemas reference other schemas in a different directory.
3533
3911
  * Updates import paths to use correct relative paths between directories.
3534
3912
  */
3535
- function fixSchemaImports(schemas, targetSchemaNames, fromPath, toPath, namingConvention) {
3913
+ function fixSchemaImports(schemas, targetSchemaNames, fromPath, toPath, namingConvention, fileExtension) {
3536
3914
  const relativePath = relativeSafe(fromPath, toPath);
3915
+ const importExtension = getImportExtension(fileExtension);
3537
3916
  for (const schema of schemas) schema.imports = schema.imports.map((imp) => {
3538
3917
  if (targetSchemaNames.has(imp.name)) {
3539
3918
  const fileName = conventionName(imp.name, namingConvention);
3540
3919
  return {
3541
3920
  ...imp,
3542
- importPath: joinSafe(relativePath, fileName)
3921
+ importPath: joinSafe(relativePath, fileName) + importExtension
3543
3922
  };
3544
3923
  }
3545
3924
  return imp;
@@ -3548,14 +3927,14 @@ function fixSchemaImports(schemas, targetSchemaNames, fromPath, toPath, namingCo
3548
3927
  /**
3549
3928
  * Fix imports in operation schemas that reference regular schemas.
3550
3929
  */
3551
- function fixCrossDirectoryImports(operationSchemas, regularSchemaNames, schemaPath, operationSchemaPath, namingConvention) {
3552
- fixSchemaImports(operationSchemas, regularSchemaNames, operationSchemaPath, schemaPath, namingConvention);
3930
+ function fixCrossDirectoryImports(operationSchemas, regularSchemaNames, schemaPath, operationSchemaPath, namingConvention, fileExtension) {
3931
+ fixSchemaImports(operationSchemas, regularSchemaNames, operationSchemaPath, schemaPath, namingConvention, fileExtension);
3553
3932
  }
3554
3933
  /**
3555
3934
  * Fix imports in regular schemas that reference operation schemas.
3556
3935
  */
3557
- function fixRegularSchemaImports(regularSchemas, operationSchemaNames, schemaPath, operationSchemaPath, namingConvention) {
3558
- fixSchemaImports(regularSchemas, operationSchemaNames, schemaPath, operationSchemaPath, namingConvention);
3936
+ function fixRegularSchemaImports(regularSchemas, operationSchemaNames, schemaPath, operationSchemaPath, namingConvention, fileExtension) {
3937
+ fixSchemaImports(regularSchemas, operationSchemaNames, schemaPath, operationSchemaPath, namingConvention, fileExtension);
3559
3938
  }
3560
3939
  function getSchemaKey(schemaPath, schemaName, namingConvention, fileExtension) {
3561
3940
  return getPath(schemaPath, conventionName(schemaName, namingConvention), fileExtension).toLowerCase().replaceAll("\\", "/");
@@ -3608,7 +3987,7 @@ function removeFileExtension(path$2, fileExtension) {
3608
3987
  function getSchema({ schema: { imports, model }, target, header, namingConvention = NamingConvention.CAMEL_CASE }) {
3609
3988
  let file = header;
3610
3989
  file += generateImports({
3611
- imports: imports.filter((imp) => !model.includes(`type ${imp.alias || imp.name} =`) && !model.includes(`interface ${imp.alias || imp.name} {`)),
3990
+ imports: imports.filter((imp) => !model.includes(`type ${imp.alias ?? imp.name} =`) && !model.includes(`interface ${imp.alias ?? imp.name} {`)),
3612
3991
  target,
3613
3992
  namingConvention
3614
3993
  });
@@ -3637,7 +4016,7 @@ async function writeSchema({ path: path$2, schema, target, namingConvention, fil
3637
4016
  namingConvention
3638
4017
  }));
3639
4018
  } catch (error) {
3640
- throw new Error(`Oups... 🍻. An Error occurred while writing schema ${name} => ${error}`);
4019
+ throw new Error(`Oups... 🍻. An Error occurred while writing schema ${name} => ${String(error)}`);
3641
4020
  }
3642
4021
  }
3643
4022
  async function writeSchemas({ schemaPath, schemas, target, namingConvention, fileExtension, header, indexFiles }) {
@@ -3672,14 +4051,14 @@ async function writeSchemas({ schemaPath, schemas, target, namingConvention, fil
3672
4051
  try {
3673
4052
  const currentExports = [...conventionNamesSet].map((schemaName) => `export * from './${schemaName}${ext}';`).toSorted((a, b) => a.localeCompare(b));
3674
4053
  const existingExports = (await fs$1.readFile(schemaFilePath, "utf8")).match(/export\s+\*\s+from\s+['"][^'"]+['"]/g)?.map((statement) => {
3675
- const match = statement.match(/export\s+\*\s+from\s+['"]([^'"]+)['"]/);
3676
- if (!match) return void 0;
4054
+ const match = /export\s+\*\s+from\s+['"]([^'"]+)['"]/.exec(statement);
4055
+ if (!match) return;
3677
4056
  return `export * from '${match[1]}';`;
3678
- }).filter((statement) => Boolean(statement)) ?? [];
4057
+ }).filter(Boolean) ?? [];
3679
4058
  const fileContent = `${header}\n${[...new Set([...existingExports, ...currentExports])].toSorted((a, b) => a.localeCompare(b)).join("\n")}`;
3680
4059
  await fs$1.writeFile(schemaFilePath, fileContent, { encoding: "utf8" });
3681
4060
  } catch (error) {
3682
- throw new Error(`Oups... 🍻. An Error occurred while writing schema index file ${schemaFilePath} => ${error}`);
4061
+ throw new Error(`Oups... 🍻. An Error occurred while writing schema index file ${schemaFilePath} => ${String(error)}`);
3683
4062
  }
3684
4063
  }
3685
4064
  }
@@ -3688,58 +4067,76 @@ async function writeSchemas({ schemaPath, schemas, target, namingConvention, fil
3688
4067
  //#region src/writers/generate-imports-for-builder.ts
3689
4068
  function generateImportsForBuilder(output, imports, relativeSchemasPath) {
3690
4069
  const isZodSchemaOutput = isObject(output.schemas) && output.schemas.type === "zod";
3691
- if (!output.indexFiles) return uniqueBy(imports, (x) => x.name).map((i) => {
3692
- const name = conventionName(i.schemaName || i.name, output.namingConvention);
4070
+ let schemaImports = [];
4071
+ if (output.indexFiles) schemaImports = isZodSchemaOutput ? [{
4072
+ exports: imports.filter((i) => !i.importPath),
4073
+ dependency: joinSafe(relativeSchemasPath, "index.zod")
4074
+ }] : [{
4075
+ exports: imports.filter((i) => !i.importPath),
4076
+ dependency: relativeSchemasPath
4077
+ }];
4078
+ else schemaImports = uniqueBy(imports.filter((i) => !i.importPath), (x) => x.name).map((i) => {
4079
+ const name = conventionName(i.schemaName ?? i.name, output.namingConvention);
3693
4080
  const suffix = isZodSchemaOutput ? ".zod" : "";
3694
- const importExtension = output.fileExtension?.replace(/\.ts$/, "") || "";
4081
+ const importExtension = output.fileExtension.replace(/\.ts$/, "") || "";
3695
4082
  return {
3696
- exports: isZodSchemaOutput ? [{
3697
- ...i,
3698
- values: true
3699
- }] : [i],
4083
+ exports: [i],
3700
4084
  dependency: joinSafe(relativeSchemasPath, `${name}${suffix}${importExtension}`)
3701
4085
  };
3702
4086
  });
3703
- else if (isZodSchemaOutput) return [{
3704
- exports: imports.map((i) => ({
3705
- ...i,
3706
- values: true
3707
- })),
3708
- dependency: joinSafe(relativeSchemasPath, "index.zod")
3709
- }];
3710
- else return [{
3711
- exports: imports,
3712
- dependency: relativeSchemasPath
3713
- }];
4087
+ const otherImports = uniqueBy(imports.filter((i) => !!i.importPath), (x) => x.name + (x.importPath ?? "")).map((i) => {
4088
+ return {
4089
+ exports: [i],
4090
+ dependency: i.importPath
4091
+ };
4092
+ });
4093
+ return [...schemaImports, ...otherImports];
3714
4094
  }
3715
4095
 
3716
4096
  //#endregion
3717
4097
  //#region src/writers/target.ts
3718
4098
  function generateTarget(builder, options) {
3719
4099
  const operationNames = Object.values(builder.operations).map(({ operationName }) => operationName);
3720
- const isAngularClient = options?.client === OutputClient.ANGULAR;
4100
+ const isAngularClient = options.client === OutputClient.ANGULAR;
3721
4101
  const titles = builder.title({
3722
4102
  outputClient: options.client,
3723
4103
  title: pascal(builder.info.title),
3724
4104
  customTitleFunc: options.override.title,
3725
4105
  output: options
3726
4106
  });
3727
- const target = Object.values(builder.operations).reduce((acc, operation, index, arr) => {
3728
- acc.imports.push(...operation.imports);
3729
- acc.importsMock.push(...operation.importsMock);
3730
- acc.implementation += operation.implementation + "\n";
3731
- acc.implementationMock.function += operation.implementationMock.function;
3732
- acc.implementationMock.handler += operation.implementationMock.handler;
3733
- const handlerNameSeparator = acc.implementationMock.handlerName.length > 0 ? ",\n " : " ";
3734
- acc.implementationMock.handlerName += handlerNameSeparator + operation.implementationMock.handlerName + "()";
3735
- if (operation.mutator) acc.mutators.push(operation.mutator);
3736
- if (operation.formData) acc.formData.push(operation.formData);
3737
- if (operation.formUrlEncoded) acc.formUrlEncoded.push(operation.formUrlEncoded);
3738
- if (operation.paramsSerializer) acc.paramsSerializer.push(operation.paramsSerializer);
3739
- if (operation.clientMutators) acc.clientMutators.push(...operation.clientMutators);
3740
- if (operation.fetchReviver) acc.fetchReviver.push(operation.fetchReviver);
3741
- if (index === arr.length - 1) {
3742
- const isMutator = acc.mutators.some((mutator) => isAngularClient ? mutator.hasThirdArg : mutator.hasSecondArg);
4107
+ const target = {
4108
+ imports: [],
4109
+ implementation: "",
4110
+ implementationMock: {
4111
+ function: "",
4112
+ handler: "",
4113
+ handlerName: ""
4114
+ },
4115
+ importsMock: [],
4116
+ mutators: [],
4117
+ clientMutators: [],
4118
+ formData: [],
4119
+ formUrlEncoded: [],
4120
+ paramsSerializer: [],
4121
+ fetchReviver: []
4122
+ };
4123
+ const operations = Object.values(builder.operations);
4124
+ for (const [index, operation] of operations.entries()) {
4125
+ target.imports.push(...operation.imports);
4126
+ target.importsMock.push(...operation.importsMock);
4127
+ target.implementation += operation.implementation + "\n";
4128
+ target.implementationMock.function += operation.implementationMock.function;
4129
+ target.implementationMock.handler += operation.implementationMock.handler;
4130
+ const handlerNameSeparator = target.implementationMock.handlerName.length > 0 ? ",\n " : " ";
4131
+ target.implementationMock.handlerName += handlerNameSeparator + operation.implementationMock.handlerName + "()";
4132
+ if (operation.mutator) target.mutators.push(operation.mutator);
4133
+ if (operation.formData) target.formData.push(operation.formData);
4134
+ if (operation.formUrlEncoded) target.formUrlEncoded.push(operation.formUrlEncoded);
4135
+ if (operation.paramsSerializer) target.paramsSerializer.push(operation.paramsSerializer);
4136
+ if (operation.clientMutators) target.clientMutators.push(...operation.clientMutators);
4137
+ if (operation.fetchReviver) target.fetchReviver.push(operation.fetchReviver);
4138
+ if (index === operations.length - 1) {
4139
+ const isMutator = target.mutators.some((mutator) => isAngularClient ? mutator.hasThirdArg : mutator.hasSecondArg);
3743
4140
  const hasAwaitedType = compareVersions(options.packageJson?.dependencies?.typescript ?? options.packageJson?.devDependencies?.typescript ?? "4.4.0", "4.5.0");
3744
4141
  const header = builder.header({
3745
4142
  outputClient: options.client,
@@ -3751,38 +4148,22 @@ function generateTarget(builder, options) {
3751
4148
  titles,
3752
4149
  output: options,
3753
4150
  verbOptions: builder.verbOptions,
3754
- clientImplementation: acc.implementation
4151
+ clientImplementation: target.implementation
3755
4152
  });
3756
- acc.implementation = header.implementation + acc.implementation;
3757
- acc.implementationMock.handler = acc.implementationMock.handler + header.implementationMock + acc.implementationMock.handlerName;
4153
+ target.implementation = header.implementation + target.implementation;
4154
+ target.implementationMock.handler = target.implementationMock.handler + header.implementationMock + target.implementationMock.handlerName;
3758
4155
  const footer = builder.footer({
3759
- outputClient: options?.client,
4156
+ outputClient: options.client,
3760
4157
  operationNames,
3761
- hasMutator: acc.mutators.length > 0,
4158
+ hasMutator: target.mutators.length > 0,
3762
4159
  hasAwaitedType,
3763
4160
  titles,
3764
4161
  output: options
3765
4162
  });
3766
- acc.implementation += footer.implementation;
3767
- acc.implementationMock.handler += footer.implementationMock;
4163
+ target.implementation += footer.implementation;
4164
+ target.implementationMock.handler += footer.implementationMock;
3768
4165
  }
3769
- return acc;
3770
- }, {
3771
- imports: [],
3772
- implementation: "",
3773
- implementationMock: {
3774
- function: "",
3775
- handler: "",
3776
- handlerName: ""
3777
- },
3778
- importsMock: [],
3779
- mutators: [],
3780
- clientMutators: [],
3781
- formData: [],
3782
- formUrlEncoded: [],
3783
- paramsSerializer: [],
3784
- fetchReviver: []
3785
- });
4166
+ }
3786
4167
  return {
3787
4168
  ...target,
3788
4169
  implementationMock: target.implementationMock.function + target.implementationMock.handler
@@ -3838,7 +4219,7 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
3838
4219
  });
3839
4220
  const { imports, importsMock, implementation, implementationMock, mutators, clientMutators, formData, formUrlEncoded, paramsSerializer, fetchReviver } = generateTarget(builder, output);
3840
4221
  let data = header;
3841
- const schemasPath = output.schemas ? relativeSafe(dirname$1, getFileInfo(typeof output.schemas === "string" ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : void 0;
4222
+ const schemasPath = output.schemas ? relativeSafe(dirname$1, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : void 0;
3842
4223
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
3843
4224
  const importsForBuilder = schemasPath ? generateImportsForBuilder(output, imports.filter((imp) => !importsMock.some((impMock) => imp.name === impMock.name)), schemasPath) : [];
3844
4225
  data += builder.imports({
@@ -3907,7 +4288,7 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
3907
4288
  const { imports, implementation, implementationMock, importsMock, mutators, clientMutators, formData, formUrlEncoded, paramsSerializer, fetchReviver } = generateTarget(builder, output);
3908
4289
  let implementationData = header;
3909
4290
  let mockData = header;
3910
- const relativeSchemasPath = output.schemas ? relativeSafe(dirname$1, getFileInfo(typeof output.schemas === "string" ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "./" + filename + ".schemas";
4291
+ const relativeSchemasPath = output.schemas ? relativeSafe(dirname$1, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "./" + filename + ".schemas";
3911
4292
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
3912
4293
  const importsForBuilder = generateImportsForBuilder(output, imports, relativeSchemasPath);
3913
4294
  implementationData += builder.imports({
@@ -3967,7 +4348,7 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
3967
4348
  ...mockPath ? [mockPath] : []
3968
4349
  ];
3969
4350
  } catch (error) {
3970
- throw new Error(`Oups... 🍻. An Error occurred while splitting => ${error}`);
4351
+ throw new Error(`Oups... 🍻. An Error occurred while splitting => ${String(error)}`);
3971
4352
  }
3972
4353
  }
3973
4354
 
@@ -3981,8 +4362,7 @@ function addDefaultTagIfEmpty(operation) {
3981
4362
  }
3982
4363
  function generateTargetTags(currentAcc, operation) {
3983
4364
  const tag = kebab(operation.tags[0]);
3984
- const currentOperation = currentAcc[tag];
3985
- if (!currentOperation) {
4365
+ if (!(tag in currentAcc)) {
3986
4366
  currentAcc[tag] = {
3987
4367
  imports: operation.imports,
3988
4368
  importsMock: operation.importsMock,
@@ -4001,6 +4381,7 @@ function generateTargetTags(currentAcc, operation) {
4001
4381
  };
4002
4382
  return currentAcc;
4003
4383
  }
4384
+ const currentOperation = currentAcc[tag];
4004
4385
  currentAcc[tag] = {
4005
4386
  implementation: currentOperation.implementation + operation.implementation,
4006
4387
  imports: [...currentOperation.imports, ...operation.imports],
@@ -4021,66 +4402,69 @@ function generateTargetTags(currentAcc, operation) {
4021
4402
  }
4022
4403
  function generateTargetForTags(builder, options) {
4023
4404
  const isAngularClient = options.client === OutputClient.ANGULAR;
4024
- const allTargetTags = Object.values(builder.operations).map((operation) => addDefaultTagIfEmpty(operation)).reduce((acc, operation, index, arr) => {
4025
- const targetTags = generateTargetTags(acc, operation);
4026
- if (index === arr.length - 1) return Object.entries(targetTags).reduce((acc$1, [tag, target]) => {
4027
- const isMutator = !!target.mutators?.some((mutator) => isAngularClient ? mutator.hasThirdArg : mutator.hasSecondArg);
4028
- const operationNames = Object.values(builder.operations).filter(({ tags }) => tags.map((tag$1) => kebab(tag$1)).indexOf(kebab(tag)) === 0).map(({ operationName }) => operationName);
4029
- const hasAwaitedType = compareVersions(options.packageJson?.dependencies?.typescript ?? options.packageJson?.devDependencies?.typescript ?? "4.4.0", "4.5.0");
4030
- const titles = builder.title({
4031
- outputClient: options.client,
4032
- title: pascal(tag),
4033
- customTitleFunc: options.override.title,
4034
- output: options
4035
- });
4036
- const footer = builder.footer({
4037
- outputClient: options?.client,
4038
- operationNames,
4039
- hasMutator: !!target.mutators?.length,
4040
- hasAwaitedType,
4041
- titles,
4042
- output: options
4043
- });
4044
- const header = builder.header({
4045
- outputClient: options.client,
4046
- isRequestOptions: options.override.requestOptions !== false,
4047
- isMutator,
4048
- isGlobalMutator: !!options.override.mutator,
4049
- provideIn: options.override.angular.provideIn,
4050
- hasAwaitedType,
4051
- titles,
4052
- output: options,
4053
- verbOptions: builder.verbOptions,
4054
- tag,
4055
- clientImplementation: target.implementation
4056
- });
4057
- acc$1[tag] = {
4058
- implementation: header.implementation + target.implementation + footer.implementation,
4059
- implementationMock: {
4060
- function: target.implementationMock.function,
4061
- handler: target.implementationMock.handler + header.implementationMock + target.implementationMock.handlerName + footer.implementationMock,
4062
- handlerName: target.implementationMock.handlerName
4063
- },
4064
- imports: target.imports,
4065
- importsMock: target.importsMock,
4066
- mutators: target.mutators,
4067
- clientMutators: target.clientMutators,
4068
- formData: target.formData,
4069
- formUrlEncoded: target.formUrlEncoded,
4070
- paramsSerializer: target.paramsSerializer,
4071
- fetchReviver: target.fetchReviver
4072
- };
4073
- return acc$1;
4074
- }, {});
4075
- return targetTags;
4076
- }, {});
4077
- return Object.entries(allTargetTags).reduce((acc, [tag, target]) => {
4078
- acc[tag] = {
4079
- ...target,
4080
- implementationMock: target.implementationMock.function + target.implementationMock.handler
4081
- };
4082
- return acc;
4083
- }, {});
4405
+ const operations = Object.values(builder.operations).map((operation) => addDefaultTagIfEmpty(operation));
4406
+ let allTargetTags = {};
4407
+ for (const [index, operation] of operations.entries()) {
4408
+ allTargetTags = generateTargetTags(allTargetTags, operation);
4409
+ if (index === operations.length - 1) {
4410
+ const transformed = {};
4411
+ for (const [tag, target] of Object.entries(allTargetTags)) {
4412
+ const isMutator = !!target.mutators?.some((mutator) => isAngularClient ? mutator.hasThirdArg : mutator.hasSecondArg);
4413
+ const operationNames = Object.values(builder.operations).filter(({ tags }) => tags.map((tag$1) => kebab(tag$1)).indexOf(kebab(tag)) === 0).map(({ operationName }) => operationName);
4414
+ const hasAwaitedType = compareVersions(options.packageJson?.dependencies?.typescript ?? options.packageJson?.devDependencies?.typescript ?? "4.4.0", "4.5.0");
4415
+ const titles = builder.title({
4416
+ outputClient: options.client,
4417
+ title: pascal(tag),
4418
+ customTitleFunc: options.override.title,
4419
+ output: options
4420
+ });
4421
+ const footer = builder.footer({
4422
+ outputClient: options.client,
4423
+ operationNames,
4424
+ hasMutator: !!target.mutators?.length,
4425
+ hasAwaitedType,
4426
+ titles,
4427
+ output: options
4428
+ });
4429
+ const header = builder.header({
4430
+ outputClient: options.client,
4431
+ isRequestOptions: options.override.requestOptions !== false,
4432
+ isMutator,
4433
+ isGlobalMutator: !!options.override.mutator,
4434
+ provideIn: options.override.angular.provideIn,
4435
+ hasAwaitedType,
4436
+ titles,
4437
+ output: options,
4438
+ verbOptions: builder.verbOptions,
4439
+ tag,
4440
+ clientImplementation: target.implementation
4441
+ });
4442
+ transformed[tag] = {
4443
+ implementation: header.implementation + target.implementation + footer.implementation,
4444
+ implementationMock: {
4445
+ function: target.implementationMock.function,
4446
+ handler: target.implementationMock.handler + header.implementationMock + target.implementationMock.handlerName + footer.implementationMock,
4447
+ handlerName: target.implementationMock.handlerName
4448
+ },
4449
+ imports: target.imports,
4450
+ importsMock: target.importsMock,
4451
+ mutators: target.mutators,
4452
+ clientMutators: target.clientMutators,
4453
+ formData: target.formData,
4454
+ formUrlEncoded: target.formUrlEncoded,
4455
+ paramsSerializer: target.paramsSerializer,
4456
+ fetchReviver: target.fetchReviver
4457
+ };
4458
+ }
4459
+ allTargetTags = transformed;
4460
+ }
4461
+ }
4462
+ const result = {};
4463
+ for (const [tag, target] of Object.entries(allTargetTags)) result[tag] = {
4464
+ ...target,
4465
+ implementationMock: target.implementationMock.function + target.implementationMock.handler
4466
+ };
4467
+ return result;
4084
4468
  }
4085
4469
 
4086
4470
  //#endregion
@@ -4092,14 +4476,15 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
4092
4476
  });
4093
4477
  const target = generateTargetForTags(builder, output);
4094
4478
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
4095
- const indexFilePath = output.mock && !isFunction(output.mock) && output.mock.indexMockFiles ? join(dirname$1, "index." + getMockFileExtensionByTypeName(output.mock) + extension) : void 0;
4479
+ const mockOption = output.mock && !isFunction(output.mock) ? output.mock : void 0;
4480
+ const indexFilePath = mockOption?.indexMockFiles ? join(dirname$1, "index." + getMockFileExtensionByTypeName(mockOption) + extension) : void 0;
4096
4481
  if (indexFilePath) await fs$1.outputFile(indexFilePath, "");
4097
4482
  return (await Promise.all(Object.entries(target).map(async ([tag, target$1]) => {
4098
4483
  try {
4099
4484
  const { imports, implementation, implementationMock, importsMock, mutators, clientMutators, formData, fetchReviver, formUrlEncoded, paramsSerializer } = target$1;
4100
4485
  let implementationData = header;
4101
4486
  let mockData = header;
4102
- const relativeSchemasPath = output.schemas ? "../" + relativeSafe(dirname$1, getFileInfo(typeof output.schemas === "string" ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "../" + filename + ".schemas";
4487
+ const relativeSchemasPath = output.schemas ? "../" + relativeSafe(dirname$1, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "../" + filename + ".schemas";
4103
4488
  const importsForBuilder = generateImportsForBuilder(output, imports, relativeSchemasPath);
4104
4489
  implementationData += builder.imports({
4105
4490
  client: output.client,
@@ -4169,9 +4554,9 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
4169
4554
  const mockPath = output.mock ? join(dirname$1, tag, tag + "." + getMockFileExtensionByTypeName(output.mock) + extension) : void 0;
4170
4555
  if (mockPath) {
4171
4556
  await fs$1.outputFile(mockPath, mockData);
4172
- if (indexFilePath) {
4173
- const localMockPath = joinSafe("./", tag, tag + "." + getMockFileExtensionByTypeName(output.mock));
4174
- fs$1.appendFile(indexFilePath, `export { get${pascal(tag)}Mock } from '${localMockPath}'\n`);
4557
+ if (indexFilePath && mockOption) {
4558
+ const localMockPath = joinSafe("./", tag, tag + "." + getMockFileExtensionByTypeName(mockOption));
4559
+ await fs$1.appendFile(indexFilePath, `export { get${pascal(tag)}Mock } from '${localMockPath}'\n`);
4175
4560
  }
4176
4561
  }
4177
4562
  return [
@@ -4180,7 +4565,7 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
4180
4565
  ...mockPath ? [mockPath] : []
4181
4566
  ];
4182
4567
  } catch (error) {
4183
- throw new Error(`Oups... 🍻. An Error occurred while splitting tag ${tag} => ${error}`);
4568
+ throw new Error(`Oups... 🍻. An Error occurred while splitting tag ${tag} => ${String(error)}`);
4184
4569
  }
4185
4570
  }))).flat();
4186
4571
  }
@@ -4198,7 +4583,7 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema
4198
4583
  try {
4199
4584
  const { imports, implementation, implementationMock, importsMock, mutators, clientMutators, formData, formUrlEncoded, fetchReviver, paramsSerializer } = target$1;
4200
4585
  let data = header;
4201
- const schemasPathRelative = output.schemas ? relativeSafe(dirname$1, getFileInfo(typeof output.schemas === "string" ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "./" + filename + ".schemas";
4586
+ const schemasPathRelative = output.schemas ? relativeSafe(dirname$1, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "./" + filename + ".schemas";
4202
4587
  const importsForBuilder = generateImportsForBuilder(output, imports.filter((imp) => !importsMock.some((impMock) => imp.name === impMock.name)), schemasPathRelative);
4203
4588
  data += builder.imports({
4204
4589
  client: output.client,
@@ -4256,11 +4641,11 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema
4256
4641
  await fs$1.outputFile(implementationPath, data);
4257
4642
  return [implementationPath, ...schemasPath ? [schemasPath] : []];
4258
4643
  } catch (error) {
4259
- throw new Error(`Oups... 🍻. An Error occurred while writing tag ${tag} => ${error}`);
4644
+ throw new Error(`Oups... 🍻. An Error occurred while writing tag ${tag} => ${String(error)}`);
4260
4645
  }
4261
4646
  }))).flat();
4262
4647
  }
4263
4648
 
4264
4649
  //#endregion
4265
- export { BODY_TYPE_NAME, EnumGeneration, ErrorWithTag, FormDataArrayHandling, GetterPropType, LogLevels, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SchemaType, TEMPLATE_TAG_REGEX, URL_REGEX, VERBS_WITH_BODY, Verbs, _filteredVerbs, addDependency, asyncReduce, camel, combineSchemas, compareVersions, conventionName, count, createDebugger, createLogger, createSuccessMessage, createTypeAliasIfNeeded, dedupeUnionType, dynamicImport, escape, fixCrossDirectoryImports, fixRegularSchemaImports, generalJSTypes, generalJSTypesWithArray, generateAxiosOptions, generateBodyMutatorConfig, generateBodyOptions, generateComponentDefinition, generateDependencyImports, generateFormDataAndUrlEncodedFunction, generateImports, generateModelInline, generateModelsInline, generateMutator, generateMutatorConfig, generateMutatorImports, generateMutatorRequestOptions, generateOptions, generateParameterDefinition, generateQueryParamsAxiosConfig, generateSchemasDefinition, generateTarget, generateTargetForTags, generateVerbImports, generateVerbOptions, generateVerbsOptions, getArray, getBody, getCombinedEnumValue, getDefaultContentType, getEnum, getEnumDescriptions, getEnumImplementation, getEnumNames, getEnumUnionFromSchema, getExtension, getFileInfo, getFormDataFieldFileType, getFullRoute, getIsBodyVerb, getKey, getMockFileExtensionByTypeName, getNumberWord, getObject, getOperationId, getOrvalGeneratedTypes, getParameters, getParams, getParamsInPath, getPropertySafe, getProps, getQueryParams, getRefInfo, getResReqTypes, getResponse, getResponseTypeCategory, getRoute, getRouteAsArray, getScalar, getTypedResponse, isBinaryContentType, isBoolean, isDirectory, isFunction, isModule, isNull, isNumber, isNumeric, isObject, isReference, isSchema, isString, isSyntheticDefaultImportsAllow, isUndefined, isUrl, isVerb, jsDoc, jsStringEscape, kebab, keyValuePairsToJsDoc, log, logError, mergeDeep, mismatchArgsMessage, pascal, removeFilesAndEmptyFolders, resolveDiscriminators, resolveExampleRefs, resolveObject, resolveRef, resolveValue, sanitize, snake, sortByPriority, splitSchemasByType, startMessage, stringify, toObjectString, path_exports as upath, upper, writeModelInline, writeModelsInline, writeSchema, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode };
4650
+ export { BODY_TYPE_NAME, EnumGeneration, ErrorWithTag, FormDataArrayHandling, GetterPropType, LogLevels, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SchemaType, TEMPLATE_TAG_REGEX, URL_REGEX, VERBS_WITH_BODY, Verbs, _filteredVerbs, addDependency, asyncReduce, camel, combineSchemas, compareVersions, conventionName, count, createDebugger, createLogger, createSuccessMessage, createTypeAliasIfNeeded, dedupeUnionType, dynamicImport, escape, filterByContentType, fixCrossDirectoryImports, fixRegularSchemaImports, generalJSTypes, generalJSTypesWithArray, generateAxiosOptions, generateBodyMutatorConfig, generateBodyOptions, generateComponentDefinition, generateDependencyImports, generateFormDataAndUrlEncodedFunction, generateImports, generateModelInline, generateModelsInline, generateMutator, generateMutatorConfig, generateMutatorImports, generateMutatorRequestOptions, generateOptions, generateParameterDefinition, generateQueryParamsAxiosConfig, generateSchemasDefinition, generateTarget, generateTargetForTags, generateVerbImports, generateVerbOptions, generateVerbsOptions, getAngularFilteredParamsCallExpression, getAngularFilteredParamsExpression, getAngularFilteredParamsHelperBody, getArray, getBody, getCombinedEnumValue, getDefaultContentType, getEnum, getEnumDescriptions, getEnumImplementation, getEnumNames, getEnumUnionFromSchema, getExtension, getFileInfo, getFormDataFieldFileType, getFullRoute, getIsBodyVerb, getKey, getMockFileExtensionByTypeName, getNumberWord, getObject, getOperationId, getOrvalGeneratedTypes, getParameters, getParams, getParamsInPath, getPropertySafe, getProps, getQueryParams, getRefInfo, getRequestBodyContentTypes, getResReqTypes, getResponse, getResponseTypeCategory, getRoute, getRouteAsArray, getScalar, getSuccessResponseType, getTypedResponse, isBinaryContentType, isBoolean, isDirectory, isFunction, isModule, isNullish, isNumber, isNumeric, isObject, isReference, isSchema, isString, isStringLike, isSyntheticDefaultImportsAllow, isUrl, isVerb, jsDoc, jsStringEscape, kebab, keyValuePairsToJsDoc, log, logError, mergeDeep, mismatchArgsMessage, pascal, removeFilesAndEmptyFolders, resolveDiscriminators, resolveExampleRefs, resolveInstalledVersion, resolveInstalledVersions, resolveObject, resolveRef, resolveValue, sanitize, snake, sortByPriority, splitSchemasByType, startMessage, stringify, toObjectString, path_exports as upath, upper, writeModelInline, writeModelsInline, writeSchema, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode };
4266
4651
  //# sourceMappingURL=index.mjs.map