@orval/core 8.3.0 → 8.4.1

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,11 +1,12 @@
1
- import { t as __export } from "./chunk-C6wwvPpM.mjs";
1
+ import { t as __export } from "./chunk-1-as6MWF.mjs";
2
+ import { createRequire } from "node:module";
2
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
6
  import { compare } from "compare-versions";
6
7
  import debug from "debug";
7
8
  import { pathToFileURL } from "node:url";
8
- import fs from "node:fs";
9
+ import fs, { existsSync, readFileSync } from "node:fs";
9
10
  import { globby } from "globby";
10
11
  import readline from "node:readline";
11
12
  import chalk from "chalk";
@@ -550,6 +551,16 @@ function getIsBodyVerb(verb) {
550
551
  //#endregion
551
552
  //#region src/utils/logger.ts
552
553
  const log = console.log;
554
+ let _verbose = false;
555
+ function setVerbose(v) {
556
+ _verbose = v;
557
+ }
558
+ function isVerbose() {
559
+ return _verbose;
560
+ }
561
+ const logVerbose = (...args) => {
562
+ if (_verbose) log(...args);
563
+ };
553
564
  function startMessage({ name, version, description }) {
554
565
  return `🍻 ${chalk.cyan.bold(name)} ${chalk.green(`v${version}`)}${description ? ` - ${description}` : ""}`;
555
566
  }
@@ -720,6 +731,47 @@ function joinSafe(...values) {
720
731
  return result;
721
732
  }
722
733
 
734
+ //#endregion
735
+ //#region src/utils/resolve-version.ts
736
+ function resolveInstalledVersion(packageName, fromDir) {
737
+ try {
738
+ const require = createRequire(path.join(fromDir, "noop.js"));
739
+ try {
740
+ return require(`${packageName}/package.json`).version;
741
+ } catch (directError) {
742
+ if (directError instanceof Error && "code" in directError && directError.code === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
743
+ const entryPath = require.resolve(packageName);
744
+ let dir = path.dirname(entryPath);
745
+ while (dir !== path.parse(dir).root) {
746
+ const pkgPath = path.join(dir, "package.json");
747
+ if (existsSync(pkgPath)) {
748
+ const pkgData = JSON.parse(readFileSync(pkgPath, "utf8"));
749
+ if (pkgData.name === packageName) return pkgData.version;
750
+ }
751
+ dir = path.dirname(dir);
752
+ }
753
+ return;
754
+ }
755
+ throw directError;
756
+ }
757
+ } catch {
758
+ return;
759
+ }
760
+ }
761
+ function resolveInstalledVersions(packageJson, fromDir) {
762
+ const resolved = {};
763
+ const allDeps = new Set([
764
+ ...Object.keys(packageJson.dependencies ?? {}),
765
+ ...Object.keys(packageJson.devDependencies ?? {}),
766
+ ...Object.keys(packageJson.peerDependencies ?? {})
767
+ ]);
768
+ for (const pkgName of allDeps) {
769
+ const version = resolveInstalledVersion(pkgName, fromDir);
770
+ if (version) resolved[pkgName] = version;
771
+ }
772
+ return resolved;
773
+ }
774
+
723
775
  //#endregion
724
776
  //#region src/utils/sort.ts
725
777
  const sortByPriority = (arr) => arr.toSorted((a, b) => {
@@ -1437,7 +1489,25 @@ function getResReqTypes(responsesOrRequests, name, context, defaultType = "unkno
1437
1489
  return uniqueBy(responsesOrRequests.filter(([, res]) => Boolean(res)).map(([key, res]) => {
1438
1490
  if (isReference(res)) {
1439
1491
  const { schema: bodySchema, imports: [{ name: name$1, schemaName }] } = resolveRef(res, context);
1440
- const [contentType, mediaType] = Object.entries(bodySchema.content ?? {})[0] ?? [];
1492
+ const firstEntry = Object.entries(bodySchema.content ?? {}).at(0);
1493
+ if (!firstEntry) return [{
1494
+ value: name$1,
1495
+ imports: [{
1496
+ name: name$1,
1497
+ schemaName
1498
+ }],
1499
+ schemas: [],
1500
+ type: "unknown",
1501
+ isEnum: false,
1502
+ isRef: true,
1503
+ hasReadonlyProps: false,
1504
+ originalSchema: void 0,
1505
+ example: void 0,
1506
+ examples: void 0,
1507
+ key,
1508
+ contentType: void 0
1509
+ }];
1510
+ const [contentType, mediaType] = firstEntry;
1441
1511
  const isFormData = formDataContentTypes.has(contentType);
1442
1512
  const isFormUrlEncoded = formUrlEncodedContentTypes.has(contentType);
1443
1513
  if (!isFormData && !isFormUrlEncoded || !mediaType.schema) return [{
@@ -1594,6 +1664,17 @@ function getResReqTypes(responsesOrRequests, name, context, defaultType = "unkno
1594
1664
  }).flat(), uniqueKey);
1595
1665
  }
1596
1666
  /**
1667
+ * Determine the responseType option based on success content types only.
1668
+ * This avoids error-response content types influencing the responseType.
1669
+ */
1670
+ function getSuccessResponseType(response) {
1671
+ const successContentTypes = response.types.success.map((t) => t.contentType).filter(Boolean);
1672
+ if (response.isBlob) return "blob";
1673
+ const hasJsonResponse = successContentTypes.some((contentType) => contentType.includes("json") || contentType.includes("+json"));
1674
+ const hasTextResponse = successContentTypes.some((contentType) => contentType.startsWith("text/") || contentType.includes("xml"));
1675
+ if (!hasJsonResponse && hasTextResponse) return "text";
1676
+ }
1677
+ /**
1597
1678
  * Determine the response type category for a given content type.
1598
1679
  * Used to set the correct responseType option in HTTP clients.
1599
1680
  *
@@ -1781,14 +1862,6 @@ function resolveSchemaPropertiesToFormData({ schema, variableName, propName, con
1781
1862
 
1782
1863
  //#endregion
1783
1864
  //#region src/getters/body.ts
1784
- /**
1785
- * Extract all content types from a requestBody (#2812)
1786
- */
1787
- function getRequestBodyContentTypes(requestBody, context) {
1788
- if (!requestBody) return [];
1789
- const content = (isReference(requestBody) ? resolveRef(requestBody, context).schema : requestBody).content;
1790
- return content ? Object.keys(content) : [];
1791
- }
1792
1865
  function getBody({ requestBody, operationName, context, contentType }) {
1793
1866
  const filteredBodyTypes = filterByContentType(getResReqTypes([[context.output.override.components.requestBodies.suffix, requestBody]], operationName, context), contentType);
1794
1867
  const imports = filteredBodyTypes.flatMap(({ imports: imports$1 }) => imports$1);
@@ -2677,13 +2750,27 @@ function getProps({ body, queryParams, params, operationName, headers, context }
2677
2750
  ]);
2678
2751
  }
2679
2752
  function getQueryParamDefinition(queryParams, context) {
2680
- let paramType = queryParams?.schema.name;
2681
- if (OutputClient.ANGULAR === context.output.client) paramType = `DeepNonNullable<${paramType}>`;
2753
+ const paramType = queryParams?.schema.name;
2682
2754
  return `params${(queryParams?.isOptional || context.output.allParamsOptional) && !context.output.optionsParamRequired ? "?" : ""}: ${paramType}`;
2683
2755
  }
2684
2756
 
2685
2757
  //#endregion
2686
2758
  //#region src/getters/query-params.ts
2759
+ const isOpenApiSchemaObject = (value) => {
2760
+ if (!value || typeof value !== "object") return false;
2761
+ return !("$ref" in value);
2762
+ };
2763
+ const isSchemaNullable = (schema) => {
2764
+ if (schema.nullable === true) return true;
2765
+ if (schema.type === "null") return true;
2766
+ if (Array.isArray(schema.type) && schema.type.includes("null")) return true;
2767
+ const oneOfVariants = Array.isArray(schema.oneOf) ? schema.oneOf : [];
2768
+ const anyOfVariants = Array.isArray(schema.anyOf) ? schema.anyOf : [];
2769
+ return [...oneOfVariants, ...anyOfVariants].some((variant) => {
2770
+ if (!isOpenApiSchemaObject(variant)) return false;
2771
+ return isSchemaNullable(variant);
2772
+ });
2773
+ };
2687
2774
  function getQueryParamsTypes(queryParams, operationName, context) {
2688
2775
  return queryParams.map(({ parameter, imports: parameterImports }) => {
2689
2776
  const { name, required, schema: schemaParam, content } = parameter;
@@ -2708,6 +2795,8 @@ function getQueryParamsTypes(queryParams, operationName, context) {
2708
2795
  ...schemaForDoc
2709
2796
  }, void 0, context);
2710
2797
  if (parameterImports.length > 0) return {
2798
+ name,
2799
+ required,
2711
2800
  definition: `${doc}${key}${!required || schema.default ? "?" : ""}: ${parameterImports[0].name};`,
2712
2801
  imports: parameterImports,
2713
2802
  schemas: [],
@@ -2717,6 +2806,8 @@ function getQueryParamsTypes(queryParams, operationName, context) {
2717
2806
  const enumName = queryName;
2718
2807
  const enumValue = getEnum(resolvedValue.value, enumName, getEnumNames(resolvedValue.originalSchema), context.output.override.enumGenerationType, getEnumDescriptions(resolvedValue.originalSchema), context.output.override.namingConvention.enum);
2719
2808
  return {
2809
+ name,
2810
+ required,
2720
2811
  definition: `${doc}${key}${!required || schema.default ? "?" : ""}: ${enumName};`,
2721
2812
  imports: [{ name: enumName }],
2722
2813
  schemas: [...resolvedValue.schemas, {
@@ -2728,6 +2819,8 @@ function getQueryParamsTypes(queryParams, operationName, context) {
2728
2819
  };
2729
2820
  }
2730
2821
  return {
2822
+ name,
2823
+ required,
2731
2824
  definition: `${doc}${key}${!required || schema.default ? "?" : ""}: ${resolvedValue.value};`,
2732
2825
  imports: resolvedValue.imports,
2733
2826
  schemas: resolvedValue.schemas,
@@ -2743,6 +2836,7 @@ function getQueryParams({ queryParams, operationName, context, suffix = "params"
2743
2836
  const name = `${pascal(operationName)}${pascal(suffix)}`;
2744
2837
  const type = types.map(({ definition }) => definition).join("\n");
2745
2838
  const allOptional = queryParams.every(({ parameter }) => !parameter.required);
2839
+ const requiredNullableKeys = types.filter(({ required, originalSchema }) => required && isSchemaNullable(originalSchema)).map(({ name: name$1 }) => name$1);
2746
2840
  return {
2747
2841
  schema: {
2748
2842
  name,
@@ -2750,14 +2844,15 @@ function getQueryParams({ queryParams, operationName, context, suffix = "params"
2750
2844
  imports
2751
2845
  },
2752
2846
  deps: schemas,
2753
- isOptional: allOptional
2847
+ isOptional: allOptional,
2848
+ requiredNullableKeys
2754
2849
  };
2755
2850
  }
2756
2851
 
2757
2852
  //#endregion
2758
2853
  //#region src/getters/response.ts
2759
2854
  function getResponse({ responses, operationName, context, contentType }) {
2760
- const filteredTypes = filterByContentType(getResReqTypes(Object.entries(responses), operationName, context, "void", (type) => `${type.key}-${type.value}`), contentType);
2855
+ const filteredTypes = filterByContentType(getResReqTypes(Object.entries(responses), operationName, context, "void", (type) => `${type.key}-${type.value}-${type.contentType}`), contentType);
2761
2856
  const imports = filteredTypes.flatMap(({ imports: imports$1 }) => imports$1);
2762
2857
  const schemas = filteredTypes.flatMap(({ schemas: schemas$1 }) => schemas$1);
2763
2858
  const contentTypes = [...new Set(filteredTypes.map(({ contentType: contentType$1 }) => contentType$1))];
@@ -2876,7 +2971,7 @@ function generateComponentDefinition(responses = {}, context, suffix) {
2876
2971
  //#region src/generators/imports.ts
2877
2972
  function generateImports({ imports, namingConvention = NamingConvention.CAMEL_CASE }) {
2878
2973
  if (imports.length === 0) return "";
2879
- const grouped = groupBy(uniqueWith(imports, (a, b) => a.name === b.name && a.default === b.default).map((imp) => ({
2974
+ 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) => ({
2880
2975
  ...imp,
2881
2976
  importPath: imp.importPath ?? `./${conventionName(imp.name, namingConvention)}`
2882
2977
  })), (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)}`);
@@ -2951,7 +3046,7 @@ function addDependency({ implementation, exports, dependency, projectName, isAll
2951
3046
  if (types.length > 0) {
2952
3047
  let uniqueTypes = types;
2953
3048
  if (values.length > 0) {
2954
- uniqueTypes = types.filter((t) => !values.some((v) => v.name === t.name));
3049
+ uniqueTypes = types.filter((t) => !values.some((v) => v.name === t.name && (v.alias ?? "") === (t.alias ?? "")));
2955
3050
  dep += "\n";
2956
3051
  }
2957
3052
  dep += generateDependency({
@@ -2994,7 +3089,17 @@ function generateVerbImports({ response, body, queryParams, props, headers, para
2994
3089
  ...queryParams ? [{ name: queryParams.schema.name }] : [],
2995
3090
  ...headers ? [{ name: headers.schema.name }] : [],
2996
3091
  ...params.flatMap(({ imports }) => imports)
2997
- ];
3092
+ ].flatMap((imp) => {
3093
+ if (imp.name !== "Error" || !imp.values || imp.alias) return [imp];
3094
+ return [{
3095
+ ...imp,
3096
+ values: void 0
3097
+ }, {
3098
+ ...imp,
3099
+ alias: "ErrorSchema",
3100
+ values: true
3101
+ }];
3102
+ });
2998
3103
  }
2999
3104
 
3000
3105
  //#endregion
@@ -3156,46 +3261,143 @@ function removeComments(file) {
3156
3261
 
3157
3262
  //#endregion
3158
3263
  //#region src/generators/options.ts
3264
+ /**
3265
+ * Filters query params for Angular's HttpClient.
3266
+ *
3267
+ * Why: Angular's HttpParams / HttpClient `params` type does not accept `null` or
3268
+ * `undefined` values, and arrays must only contain string/number/boolean.
3269
+ * Orval models often include nullable query params, so we remove nullish values
3270
+ * (including nulls inside arrays) before passing params to HttpClient or a
3271
+ * paramsSerializer to avoid runtime and type issues.
3272
+ *
3273
+ * Returns an inline IIFE expression. For paths that benefit from a shared helper
3274
+ * (e.g. observe-mode branches), prefer getAngularFilteredParamsCallExpression +
3275
+ * getAngularFilteredParamsHelperBody instead.
3276
+ */
3277
+ const getAngularFilteredParamsExpression = (paramsExpression, requiredNullableParamKeys = []) => `(() => {
3278
+ const requiredNullableParamKeys = new Set<string>(${JSON.stringify(requiredNullableParamKeys)});
3279
+ const filteredParams = {} as Record<string, string | number | boolean | null | Array<string | number | boolean>>;
3280
+ for (const [key, value] of Object.entries(${paramsExpression})) {
3281
+ if (Array.isArray(value)) {
3282
+ const filtered = value.filter(
3283
+ (item) =>
3284
+ item != null &&
3285
+ (typeof item === 'string' ||
3286
+ typeof item === 'number' ||
3287
+ typeof item === 'boolean'),
3288
+ ) as Array<string | number | boolean>;
3289
+ if (filtered.length) {
3290
+ filteredParams[key] = filtered;
3291
+ }
3292
+ } else if (value === null && requiredNullableParamKeys.has(key)) {
3293
+ filteredParams[key] = value;
3294
+ } else if (
3295
+ value != null &&
3296
+ (typeof value === 'string' ||
3297
+ typeof value === 'number' ||
3298
+ typeof value === 'boolean')
3299
+ ) {
3300
+ filteredParams[key] = value as string | number | boolean;
3301
+ }
3302
+ }
3303
+ return filteredParams as unknown as Record<string, string | number | boolean | Array<string | number | boolean>>;
3304
+ })()`;
3305
+ /**
3306
+ * Returns the body of a standalone `filterParams` helper function
3307
+ * to be emitted once in the generated file header, replacing the
3308
+ * inline IIFE that was previously duplicated in every method.
3309
+ */
3310
+ const getAngularFilteredParamsHelperBody = () => `function filterParams(
3311
+ params: Record<string, unknown>,
3312
+ requiredNullableKeys: Set<string> = new Set(),
3313
+ ): Record<string, string | number | boolean | Array<string | number | boolean>> {
3314
+ const filteredParams: Record<string, string | number | boolean | null | Array<string | number | boolean>> = {};
3315
+ for (const [key, value] of Object.entries(params)) {
3316
+ if (Array.isArray(value)) {
3317
+ const filtered = value.filter(
3318
+ (item) =>
3319
+ item != null &&
3320
+ (typeof item === 'string' ||
3321
+ typeof item === 'number' ||
3322
+ typeof item === 'boolean'),
3323
+ ) as Array<string | number | boolean>;
3324
+ if (filtered.length) {
3325
+ filteredParams[key] = filtered;
3326
+ }
3327
+ } else if (value === null && requiredNullableKeys.has(key)) {
3328
+ filteredParams[key] = value;
3329
+ } else if (
3330
+ value != null &&
3331
+ (typeof value === 'string' ||
3332
+ typeof value === 'number' ||
3333
+ typeof value === 'boolean')
3334
+ ) {
3335
+ filteredParams[key] = value as string | number | boolean;
3336
+ }
3337
+ }
3338
+ return filteredParams as Record<string, string | number | boolean | Array<string | number | boolean>>;
3339
+ }`;
3340
+ /**
3341
+ * Returns a call expression to the `filterParams` helper function.
3342
+ */
3343
+ const getAngularFilteredParamsCallExpression = (paramsExpression, requiredNullableParamKeys = []) => `filterParams(${paramsExpression}, new Set<string>(${JSON.stringify(requiredNullableParamKeys)}))`;
3159
3344
  function generateBodyOptions(body, isFormData, isFormUrlEncoded) {
3160
3345
  if (isFormData && body.formData) return "\n formData,";
3161
3346
  if (isFormUrlEncoded && body.formUrlEncoded) return "\n formUrlEncoded,";
3162
3347
  if (body.implementation) return `\n ${body.implementation},`;
3163
3348
  return "";
3164
3349
  }
3165
- function generateAxiosOptions({ response, isExactOptionalPropertyTypes, queryParams, headers, requestOptions, hasSignal, hasSignalParam = false, isVue, isAngular, paramsSerializer, paramsSerializerOptions }) {
3350
+ function generateAxiosOptions({ response, isExactOptionalPropertyTypes, angularObserve, angularParamsRef, requiredNullableQueryParamKeys, queryParams, headers, requestOptions, hasSignal, hasSignalParam = false, isVue, isAngular, paramsSerializer, paramsSerializerOptions }) {
3166
3351
  const isRequestOptions = requestOptions !== false;
3167
3352
  const signalVar = hasSignalParam ? "querySignal" : "signal";
3168
3353
  const signalProp = hasSignalParam ? `signal: ${signalVar}` : "signal";
3169
3354
  if (!queryParams && !headers && !response.isBlob && response.definition.success !== "string") {
3170
- if (isRequestOptions) return "options";
3355
+ if (isRequestOptions) return isAngular ? angularObserve ? `{
3356
+ ...(options as Omit<NonNullable<typeof options>, 'observe'>),
3357
+ observe: '${angularObserve}',
3358
+ }` : "(options as Omit<NonNullable<typeof options>, 'observe'>)" : "options";
3171
3359
  if (hasSignal) return isExactOptionalPropertyTypes ? `...(${signalVar} ? { ${signalProp} } : {})` : signalProp;
3172
3360
  return "";
3173
3361
  }
3174
3362
  let value = "";
3175
3363
  if (!isRequestOptions) {
3176
- if (queryParams) value += "\n params,";
3364
+ if (queryParams) if (isAngular) {
3365
+ const iifeExpr = getAngularFilteredParamsExpression("params ?? {}", requiredNullableQueryParamKeys);
3366
+ value += paramsSerializer ? `\n params: ${paramsSerializer.name}(${iifeExpr}),` : `\n params: ${iifeExpr},`;
3367
+ } else value += "\n params,";
3177
3368
  if (headers) value += "\n headers,";
3178
3369
  if (hasSignal) value += isExactOptionalPropertyTypes ? `\n ...(${signalVar} ? { ${signalProp} } : {}),` : `\n ${signalProp},`;
3179
3370
  }
3180
3371
  if (!isObject(requestOptions) || !Object.hasOwn(requestOptions, "responseType")) {
3181
- if (response.isBlob) value += `\n responseType: 'blob',`;
3182
- else if (response.contentTypes.at(0) === "text/plain") value += `\n responseType: 'text',`;
3372
+ const successResponseType = getSuccessResponseType(response);
3373
+ if (successResponseType) value += `\n responseType: '${successResponseType}',`;
3183
3374
  }
3184
3375
  if (isObject(requestOptions)) value += `\n ${stringify(requestOptions)?.slice(1, -1)}`;
3185
3376
  if (isRequestOptions) {
3186
- value += "\n ...options,";
3377
+ value += isAngular ? "\n ...(options as Omit<NonNullable<typeof options>, 'observe'>)," : "\n ...options,";
3378
+ if (isAngular && angularObserve) value += `\n observe: '${angularObserve}',`;
3187
3379
  if (queryParams) if (isVue) value += "\n params: {...unref(params), ...options?.params},";
3188
- else if (isAngular && paramsSerializer) value += `\n params: ${paramsSerializer.name}({...params, ...options?.params}),`;
3380
+ else if (isAngular && angularParamsRef) value += `\n params: ${angularParamsRef},`;
3381
+ else if (isAngular && paramsSerializer) {
3382
+ const callExpr = getAngularFilteredParamsCallExpression("{...params, ...options?.params}", requiredNullableQueryParamKeys);
3383
+ value += `\n params: ${paramsSerializer.name}(${callExpr}),`;
3384
+ } else if (isAngular) value += `\n params: ${getAngularFilteredParamsCallExpression("{...params, ...options?.params}", requiredNullableQueryParamKeys)},`;
3189
3385
  else value += "\n params: {...params, ...options?.params},";
3190
3386
  if (headers) value += "\n headers: {...headers, ...options?.headers},";
3191
3387
  }
3192
- if (!isAngular && queryParams && (paramsSerializer || paramsSerializerOptions?.qs)) value += paramsSerializer ? `\n paramsSerializer: ${paramsSerializer.name},` : `\n paramsSerializer: (params) => qs.stringify(params, ${JSON.stringify(paramsSerializerOptions?.qs)}),`;
3388
+ if (!isAngular && queryParams && (paramsSerializer || paramsSerializerOptions?.qs)) {
3389
+ const qsOptions = paramsSerializerOptions?.qs;
3390
+ value += paramsSerializer ? `\n paramsSerializer: ${paramsSerializer.name},` : `\n paramsSerializer: (params) => qs.stringify(params, ${JSON.stringify(qsOptions)}),`;
3391
+ }
3193
3392
  return value;
3194
3393
  }
3195
- function generateOptions({ route, body, headers, queryParams, response, verb, requestOptions, isFormData, isFormUrlEncoded, isAngular, isExactOptionalPropertyTypes, hasSignal, hasSignalParam, isVue, paramsSerializer, paramsSerializerOptions }) {
3394
+ function generateOptions({ route, body, angularObserve, angularParamsRef, headers, queryParams, response, verb, requestOptions, isFormData, isFormUrlEncoded, isAngular, isExactOptionalPropertyTypes, hasSignal, hasSignalParam, isVue, paramsSerializer, paramsSerializerOptions }) {
3196
3395
  const bodyOptions = getIsBodyVerb(verb) ? generateBodyOptions(body, isFormData, isFormUrlEncoded) : "";
3197
3396
  const axiosOptions = generateAxiosOptions({
3198
3397
  response,
3398
+ angularObserve,
3399
+ angularParamsRef,
3400
+ requiredNullableQueryParamKeys: queryParams?.requiredNullableKeys,
3199
3401
  queryParams: queryParams?.schema,
3200
3402
  headers: headers?.schema,
3201
3403
  requestOptions,
@@ -3207,12 +3409,16 @@ function generateOptions({ route, body, headers, queryParams, response, verb, re
3207
3409
  paramsSerializer,
3208
3410
  paramsSerializerOptions
3209
3411
  });
3210
- const options = axiosOptions ? `{${axiosOptions}}` : "";
3412
+ const trimmedAxiosOptions = axiosOptions.trim();
3413
+ const isRawOptionsArgument = trimmedAxiosOptions === "options" || trimmedAxiosOptions.startsWith("(") && trimmedAxiosOptions.endsWith(")") || trimmedAxiosOptions.startsWith("{") && trimmedAxiosOptions.endsWith("}");
3414
+ const optionsArgument = axiosOptions ? isRawOptionsArgument ? axiosOptions : `{${axiosOptions}}` : "";
3211
3415
  if (verb === Verbs.DELETE) {
3212
- if (!bodyOptions) return `\n \`${route}\`,${axiosOptions === "options" ? axiosOptions : options}\n `;
3213
- return `\n \`${route}\`,{${isAngular ? "body" : "data"}:${bodyOptions} ${axiosOptions === "options" ? `...${axiosOptions}` : axiosOptions}}\n `;
3416
+ if (!bodyOptions) return `\n \`${route}\`${optionsArgument ? `,${optionsArgument}` : ""}\n `;
3417
+ const deleteBodyOptions = isRawOptionsArgument ? `...${optionsArgument}` : axiosOptions;
3418
+ return `\n \`${route}\`,{${isAngular ? "body" : "data"}:${bodyOptions} ${axiosOptions ? deleteBodyOptions : ""}}\n `;
3214
3419
  }
3215
- return `\n \`${route}\`,${getIsBodyVerb(verb) ? bodyOptions || "undefined," : ""}${axiosOptions === "options" ? axiosOptions : options}\n `;
3420
+ const bodyOrOptions = getIsBodyVerb(verb) ? bodyOptions || "undefined," : "";
3421
+ return `\n \`${route}\`${bodyOrOptions || optionsArgument ? "," : ""}${bodyOrOptions}${optionsArgument}\n `;
3216
3422
  }
3217
3423
  function generateBodyMutatorConfig(body, isFormData, isFormUrlEncoded) {
3218
3424
  if (isFormData && body.formData) return ",\n data: formData";
@@ -3220,16 +3426,18 @@ function generateBodyMutatorConfig(body, isFormData, isFormUrlEncoded) {
3220
3426
  if (body.implementation) return `,\n data: ${body.implementation}`;
3221
3427
  return "";
3222
3428
  }
3223
- function generateQueryParamsAxiosConfig(response, isVue, queryParams) {
3429
+ function generateQueryParamsAxiosConfig(response, isVue, isAngular, requiredNullableQueryParamKeys, queryParams) {
3224
3430
  if (!queryParams && !response.isBlob) return "";
3225
3431
  let value = "";
3226
- if (queryParams) value += isVue ? ",\n params: unref(params)" : ",\n params";
3432
+ if (queryParams) if (isVue) value += ",\n params: unref(params)";
3433
+ else if (isAngular) value += `,\n params: ${getAngularFilteredParamsExpression("params ?? {}", requiredNullableQueryParamKeys)}`;
3434
+ else value += ",\n params";
3227
3435
  if (response.isBlob) value += `,\n responseType: 'blob'`;
3228
3436
  return value;
3229
3437
  }
3230
- function generateMutatorConfig({ route, body, headers, queryParams, response, verb, isFormData, isFormUrlEncoded, hasSignal, hasSignalParam = false, isExactOptionalPropertyTypes, isVue }) {
3438
+ function generateMutatorConfig({ route, body, headers, queryParams, response, verb, isFormData, isFormUrlEncoded, hasSignal, hasSignalParam = false, isExactOptionalPropertyTypes, isVue, isAngular }) {
3231
3439
  const bodyOptions = getIsBodyVerb(verb) ? generateBodyMutatorConfig(body, isFormData, isFormUrlEncoded) : "";
3232
- const queryParamsOptions = generateQueryParamsAxiosConfig(response, isVue ?? false, queryParams);
3440
+ const queryParamsOptions = generateQueryParamsAxiosConfig(response, isVue ?? false, isAngular ?? false, queryParams?.requiredNullableKeys, queryParams);
3233
3441
  const headerOptions = body.contentType && !["multipart/form-data"].includes(body.contentType) ? `,\n headers: {'Content-Type': '${body.contentType}', ${headers ? "...headers" : ""}}` : headers ? ",\n headers" : "";
3234
3442
  const signalVar = hasSignalParam ? "querySignal" : "signal";
3235
3443
  const signalProp = hasSignalParam ? `signal: ${signalVar}` : "signal";
@@ -3467,19 +3675,7 @@ function generateSchemaDefinitions(schemaName, schema, context, suffix) {
3467
3675
 
3468
3676
  //#endregion
3469
3677
  //#region src/generators/verbs-options.ts
3470
- /**
3471
- * Get a content-type specific suffix for operation names (#2812)
3472
- */
3473
- function getContentTypeSuffix(contentType) {
3474
- return {
3475
- "application/json": "Json",
3476
- "multipart/form-data": "FormData",
3477
- "application/x-www-form-urlencoded": "UrlEncoded",
3478
- "application/xml": "Xml",
3479
- "text/plain": "Text"
3480
- }[contentType] || pascal(contentType.replaceAll(/[^a-zA-Z0-9]/g, "_"));
3481
- }
3482
- async function generateVerbOptions({ verb, output, operation, route, pathRoute, verbParameters = [], context, contentType }) {
3678
+ async function generateVerbOptions({ verb, output, operation, route, pathRoute, verbParameters = [], context }) {
3483
3679
  const { responses, requestBody, parameters: operationParameters, tags: rawTags, deprecated: rawDeprecated, description: rawDescription, summary: rawSummary } = operation;
3484
3680
  const tags = rawTags ?? [];
3485
3681
  const deprecated = rawDeprecated;
@@ -3490,22 +3686,19 @@ async function generateVerbOptions({ verb, output, operation, route, pathRoute,
3490
3686
  let overrideTag = {};
3491
3687
  for (const [tag, options] of Object.entries(output.override.tags)) if (tags.includes(tag) && options) overrideTag = mergeDeep(overrideTag, options);
3492
3688
  const override = mergeDeep(mergeDeep(output.override, overrideTag), overrideOperation ?? {});
3493
- const originalContentTypeFilter = override.contentType;
3494
- const requestBodyContentTypeFilter = contentType ? { include: [contentType] } : override.contentType;
3495
3689
  const overrideOperationName = overrideOperation?.operationName ?? output.override.operationName;
3496
- let operationName = overrideOperationName ? overrideOperationName(operation, route, verb) : sanitize(camel(operationId), { es5keyword: true });
3497
- if (contentType) operationName = operationName + "With" + getContentTypeSuffix(contentType);
3690
+ const operationName = overrideOperationName ? overrideOperationName(operation, route, verb) : sanitize(camel(operationId), { es5keyword: true });
3498
3691
  const response = getResponse({
3499
3692
  responses: responses ?? {},
3500
3693
  operationName,
3501
3694
  context,
3502
- contentType: originalContentTypeFilter
3695
+ contentType: override.contentType
3503
3696
  });
3504
3697
  const body = requestBody ? getBody({
3505
3698
  requestBody,
3506
3699
  operationName,
3507
3700
  context,
3508
- contentType: requestBodyContentTypeFilter
3701
+ contentType: override.contentType
3509
3702
  }) : {
3510
3703
  originalSchema: {},
3511
3704
  definition: "",
@@ -3539,54 +3732,6 @@ async function generateVerbOptions({ verb, output, operation, route, pathRoute,
3539
3732
  context,
3540
3733
  output
3541
3734
  });
3542
- const props = getProps({
3543
- body,
3544
- queryParams,
3545
- params,
3546
- headers,
3547
- operationName,
3548
- context
3549
- });
3550
- const mutator = await generateMutator({
3551
- output: output.target,
3552
- name: operationName,
3553
- mutator: override.mutator,
3554
- workspace: context.workspace,
3555
- tsconfig: context.output.tsconfig
3556
- });
3557
- const formData = !override.formData.disabled && body.formData ? await generateMutator({
3558
- output: output.target,
3559
- name: operationName,
3560
- mutator: override.formData.mutator,
3561
- workspace: context.workspace,
3562
- tsconfig: context.output.tsconfig
3563
- }) : void 0;
3564
- const formUrlEncoded = isString(override.formUrlEncoded) || isObject(override.formUrlEncoded) ? await generateMutator({
3565
- output: output.target,
3566
- name: operationName,
3567
- mutator: override.formUrlEncoded,
3568
- workspace: context.workspace,
3569
- tsconfig: context.output.tsconfig
3570
- }) : void 0;
3571
- const paramsSerializer = isString(override.paramsSerializer) || isObject(override.paramsSerializer) ? await generateMutator({
3572
- output: output.target,
3573
- name: "paramsSerializer",
3574
- mutator: override.paramsSerializer,
3575
- workspace: context.workspace,
3576
- tsconfig: context.output.tsconfig
3577
- }) : void 0;
3578
- const fetchReviver = isString(override.fetch.jsonReviver) || isObject(override.fetch.jsonReviver) ? await generateMutator({
3579
- output: output.target,
3580
- name: "fetchReviver",
3581
- mutator: override.fetch.jsonReviver,
3582
- workspace: context.workspace,
3583
- tsconfig: context.output.tsconfig
3584
- }) : void 0;
3585
- const doc = jsDoc({
3586
- description,
3587
- deprecated,
3588
- summary
3589
- });
3590
3735
  const verbOption = {
3591
3736
  verb,
3592
3737
  tags,
@@ -3600,14 +3745,55 @@ async function generateVerbOptions({ verb, output, operation, route, pathRoute,
3600
3745
  headers,
3601
3746
  queryParams,
3602
3747
  params,
3603
- props,
3604
- mutator,
3605
- formData,
3606
- formUrlEncoded,
3607
- paramsSerializer,
3608
- fetchReviver,
3748
+ props: getProps({
3749
+ body,
3750
+ queryParams,
3751
+ params,
3752
+ headers,
3753
+ operationName,
3754
+ context
3755
+ }),
3756
+ mutator: await generateMutator({
3757
+ output: output.target,
3758
+ name: operationName,
3759
+ mutator: override.mutator,
3760
+ workspace: context.workspace,
3761
+ tsconfig: context.output.tsconfig
3762
+ }),
3763
+ formData: !override.formData.disabled && body.formData ? await generateMutator({
3764
+ output: output.target,
3765
+ name: operationName,
3766
+ mutator: override.formData.mutator,
3767
+ workspace: context.workspace,
3768
+ tsconfig: context.output.tsconfig
3769
+ }) : void 0,
3770
+ formUrlEncoded: isString(override.formUrlEncoded) || isObject(override.formUrlEncoded) ? await generateMutator({
3771
+ output: output.target,
3772
+ name: operationName,
3773
+ mutator: override.formUrlEncoded,
3774
+ workspace: context.workspace,
3775
+ tsconfig: context.output.tsconfig
3776
+ }) : void 0,
3777
+ paramsSerializer: isString(override.paramsSerializer) || isObject(override.paramsSerializer) ? await generateMutator({
3778
+ output: output.target,
3779
+ name: "paramsSerializer",
3780
+ mutator: override.paramsSerializer,
3781
+ workspace: context.workspace,
3782
+ tsconfig: context.output.tsconfig
3783
+ }) : void 0,
3784
+ fetchReviver: isString(override.fetch.jsonReviver) || isObject(override.fetch.jsonReviver) ? await generateMutator({
3785
+ output: output.target,
3786
+ name: "fetchReviver",
3787
+ mutator: override.fetch.jsonReviver,
3788
+ workspace: context.workspace,
3789
+ tsconfig: context.output.tsconfig
3790
+ }) : void 0,
3609
3791
  override,
3610
- doc,
3792
+ doc: jsDoc({
3793
+ description,
3794
+ deprecated,
3795
+ summary
3796
+ }),
3611
3797
  deprecated,
3612
3798
  originalOperation: operation
3613
3799
  };
@@ -3617,32 +3803,16 @@ async function generateVerbOptions({ verb, output, operation, route, pathRoute,
3617
3803
  function generateVerbsOptions({ verbs, input, output, route, pathRoute, context }) {
3618
3804
  return asyncReduce(_filteredVerbs(verbs, input.filters), async (acc, [verb, operation]) => {
3619
3805
  if (isVerb(verb)) {
3620
- const contentTypes = getRequestBodyContentTypes(operation.requestBody, context);
3621
- if (contentTypes.length > 1) for (const contentType of contentTypes) {
3622
- const verbOptions = await generateVerbOptions({
3623
- verb,
3624
- output,
3625
- verbParameters: verbs.parameters,
3626
- route,
3627
- pathRoute,
3628
- operation,
3629
- context,
3630
- contentType
3631
- });
3632
- acc.push(verbOptions);
3633
- }
3634
- else {
3635
- const verbOptions = await generateVerbOptions({
3636
- verb,
3637
- output,
3638
- verbParameters: verbs.parameters,
3639
- route,
3640
- pathRoute,
3641
- operation,
3642
- context
3643
- });
3644
- acc.push(verbOptions);
3645
- }
3806
+ const verbOptions = await generateVerbOptions({
3807
+ verb,
3808
+ output,
3809
+ verbParameters: verbs.parameters,
3810
+ route,
3811
+ pathRoute,
3812
+ operation,
3813
+ context
3814
+ });
3815
+ acc.push(verbOptions);
3646
3816
  }
3647
3817
  return acc;
3648
3818
  }, []);
@@ -3862,28 +4032,30 @@ async function writeSchemas({ schemaPath, schemas, target, namingConvention, fil
3862
4032
  //#region src/writers/generate-imports-for-builder.ts
3863
4033
  function generateImportsForBuilder(output, imports, relativeSchemasPath) {
3864
4034
  const isZodSchemaOutput = isObject(output.schemas) && output.schemas.type === "zod";
3865
- if (output.indexFiles) return isZodSchemaOutput ? [{
3866
- exports: imports.map((i) => ({
3867
- ...i,
3868
- values: true
3869
- })),
4035
+ let schemaImports = [];
4036
+ if (output.indexFiles) schemaImports = isZodSchemaOutput ? [{
4037
+ exports: imports.filter((i) => !i.importPath),
3870
4038
  dependency: joinSafe(relativeSchemasPath, "index.zod")
3871
4039
  }] : [{
3872
- exports: imports,
4040
+ exports: imports.filter((i) => !i.importPath),
3873
4041
  dependency: relativeSchemasPath
3874
4042
  }];
3875
- else return uniqueBy(imports, (x) => x.name).map((i) => {
4043
+ else schemaImports = uniqueBy(imports.filter((i) => !i.importPath), (x) => x.name).map((i) => {
3876
4044
  const name = conventionName(i.schemaName ?? i.name, output.namingConvention);
3877
4045
  const suffix = isZodSchemaOutput ? ".zod" : "";
3878
4046
  const importExtension = output.fileExtension.replace(/\.ts$/, "") || "";
3879
4047
  return {
3880
- exports: isZodSchemaOutput ? [{
3881
- ...i,
3882
- values: true
3883
- }] : [i],
4048
+ exports: [i],
3884
4049
  dependency: joinSafe(relativeSchemasPath, `${name}${suffix}${importExtension}`)
3885
4050
  };
3886
4051
  });
4052
+ const otherImports = uniqueBy(imports.filter((i) => !!i.importPath), (x) => x.name + (x.importPath ?? "")).map((i) => {
4053
+ return {
4054
+ exports: [i],
4055
+ dependency: i.importPath
4056
+ };
4057
+ });
4058
+ return [...schemaImports, ...otherImports];
3887
4059
  }
3888
4060
 
3889
4061
  //#endregion
@@ -4272,7 +4444,7 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
4272
4444
  const mockOption = output.mock && !isFunction(output.mock) ? output.mock : void 0;
4273
4445
  const indexFilePath = mockOption?.indexMockFiles ? join(dirname$1, "index." + getMockFileExtensionByTypeName(mockOption) + extension) : void 0;
4274
4446
  if (indexFilePath) await fs$1.outputFile(indexFilePath, "");
4275
- return (await Promise.all(Object.entries(target).map(async ([tag, target$1]) => {
4447
+ const generatedFilePathsArray = await Promise.all(Object.entries(target).map(async ([tag, target$1]) => {
4276
4448
  try {
4277
4449
  const { imports, implementation, implementationMock, importsMock, mutators, clientMutators, formData, fetchReviver, formUrlEncoded, paramsSerializer } = target$1;
4278
4450
  let implementationData = header;
@@ -4360,7 +4532,8 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
4360
4532
  } catch (error) {
4361
4533
  throw new Error(`Oups... 🍻. An Error occurred while splitting tag ${tag} => ${String(error)}`);
4362
4534
  }
4363
- }))).flat();
4535
+ }));
4536
+ return [...indexFilePath ? [indexFilePath] : [], ...generatedFilePathsArray.flat()];
4364
4537
  }
4365
4538
 
4366
4539
  //#endregion
@@ -4440,5 +4613,5 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema
4440
4613
  }
4441
4614
 
4442
4615
  //#endregion
4443
- 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, 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, 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, resolveObject, resolveRef, resolveValue, sanitize, snake, sortByPriority, splitSchemasByType, startMessage, stringify, toObjectString, path_exports as upath, upper, writeModelInline, writeModelsInline, writeSchema, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode };
4616
+ 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, getResReqTypes, getResponse, getResponseTypeCategory, getRoute, getRouteAsArray, getScalar, getSuccessResponseType, getTypedResponse, isBinaryContentType, isBoolean, isDirectory, isFunction, isModule, isNullish, isNumber, isNumeric, isObject, isReference, isSchema, isString, isStringLike, isSyntheticDefaultImportsAllow, isUrl, isVerb, isVerbose, jsDoc, jsStringEscape, kebab, keyValuePairsToJsDoc, log, logError, logVerbose, mergeDeep, mismatchArgsMessage, pascal, removeFilesAndEmptyFolders, resolveDiscriminators, resolveExampleRefs, resolveInstalledVersion, resolveInstalledVersions, resolveObject, resolveRef, resolveValue, sanitize, setVerbose, snake, sortByPriority, splitSchemasByType, startMessage, stringify, toObjectString, path_exports as upath, upper, writeModelInline, writeModelsInline, writeSchema, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode };
4444
4617
  //# sourceMappingURL=index.mjs.map