@orval/core 8.0.0-rc.5 → 8.0.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/README.md CHANGED
@@ -11,12 +11,10 @@
11
11
 
12
12
  ### Code Generation
13
13
 
14
- `orval` is able to generate client with appropriate type-signatures (TypeScript) from any valid OpenAPI v3 or Swagger v2 specification, either in `yaml` or `json` formats.
14
+ `orval` generates type-safe JS clients (TypeScript) from any valid OpenAPI v3 or Swagger v2 specification, either in `yaml` or `json` formats.
15
15
 
16
16
  `Generate`, `valid`, `cache` and `mock` in your React, Vue, Svelte and Angular applications all with your OpenAPI specification.
17
17
 
18
- ### Samples
19
-
20
18
  You can find below some samples
21
19
 
22
20
  - [react app](https://github.com/orval-labs/orval/tree/master/samples/react-app)
package/dist/index.d.mts CHANGED
@@ -104,6 +104,7 @@ type NormalizedMutator = {
104
104
  name?: string;
105
105
  default: boolean;
106
106
  alias?: Record<string, string>;
107
+ external?: string[];
107
108
  extension?: string;
108
109
  };
109
110
  type NormalizedOperationOptions = {
@@ -224,6 +225,8 @@ declare const OutputClient: {
224
225
  readonly AXIOS: "axios";
225
226
  readonly AXIOS_FUNCTIONS: "axios-functions";
226
227
  readonly REACT_QUERY: "react-query";
228
+ readonly SOLID_START: "solid-start";
229
+ readonly SOLID_QUERY: "solid-query";
227
230
  readonly SVELTE_QUERY: "svelte-query";
228
231
  readonly VUE_QUERY: "vue-query";
229
232
  readonly SWR: "swr";
@@ -299,6 +302,7 @@ type MutatorObject = {
299
302
  name?: string;
300
303
  default?: boolean;
301
304
  alias?: Record<string, string>;
305
+ external?: string[];
302
306
  extension?: string;
303
307
  };
304
308
  type Mutator = string | MutatorObject;
@@ -473,6 +477,15 @@ type NormalizedZodOptions = {
473
477
  dateTimeOptions: ZodDateTimeOptions;
474
478
  timeOptions: ZodTimeOptions;
475
479
  };
480
+ type InvalidateTarget = string | {
481
+ query: string;
482
+ params: string[] | Record<string, string>;
483
+ };
484
+ type MutationInvalidatesRule = {
485
+ onMutations: string[];
486
+ invalidates: InvalidateTarget[];
487
+ };
488
+ type MutationInvalidatesConfig = MutationInvalidatesRule[];
476
489
  type HonoOptions = {
477
490
  handlers?: string;
478
491
  compositeRoute?: string;
@@ -499,6 +512,7 @@ type NormalizedQueryOptions = {
499
512
  useOperationIdAsQueryKey?: boolean;
500
513
  signal?: boolean;
501
514
  version?: 3 | 4 | 5;
515
+ mutationInvalidates?: MutationInvalidatesConfig;
502
516
  };
503
517
  type QueryOptions = {
504
518
  useQuery?: boolean;
@@ -520,6 +534,7 @@ type QueryOptions = {
520
534
  useOperationIdAsQueryKey?: boolean;
521
535
  signal?: boolean;
522
536
  version?: 3 | 4 | 5;
537
+ mutationInvalidates?: MutationInvalidatesConfig;
523
538
  };
524
539
  type AngularOptions = {
525
540
  provideIn?: 'root' | 'any' | boolean;
@@ -527,6 +542,8 @@ type AngularOptions = {
527
542
  type SwrOptions = {
528
543
  useInfinite?: boolean;
529
544
  useSWRMutationForGet?: boolean;
545
+ useSuspense?: boolean;
546
+ generateErrorTypes?: boolean;
530
547
  swrOptions?: unknown;
531
548
  swrMutationOptions?: unknown;
532
549
  swrInfiniteOptions?: unknown;
@@ -648,6 +665,7 @@ type GeneratorImport = {
648
665
  values?: boolean;
649
666
  syntheticDefaultImport?: boolean;
650
667
  namespaceImport?: boolean;
668
+ importPath?: string;
651
669
  };
652
670
  type GeneratorDependency = {
653
671
  exports: GeneratorImport[];
@@ -1729,7 +1747,38 @@ declare const sortByPriority: <T>(arr: (T & {
1729
1747
  })[];
1730
1748
  //#endregion
1731
1749
  //#region src/utils/string.d.ts
1750
+ /**
1751
+ * Converts data to a string representation suitable for code generation.
1752
+ * Handles strings, numbers, booleans, functions, arrays, and objects.
1753
+ *
1754
+ * @param data - The data to stringify. Can be a string, array, object, number, boolean, function, null, or undefined.
1755
+ * @returns A string representation of the data, or undefined if data is null or undefined.
1756
+ * @example
1757
+ * stringify('hello') // returns "'hello'"
1758
+ * stringify(42) // returns "42"
1759
+ * stringify([1, 2, 3]) // returns "[1, 2, 3]"
1760
+ * stringify({ a: 1, b: 'test' }) // returns "{ a: 1, b: 'test', }"
1761
+ */
1732
1762
  declare function stringify(data?: string | any[] | Record<string, any>): string | undefined;
1763
+ /**
1764
+ * Sanitizes a string value by removing or replacing special characters and ensuring
1765
+ * it conforms to JavaScript identifier naming rules if needed.
1766
+ *
1767
+ * @param value - The string value to sanitize.
1768
+ * @param options - Configuration options for sanitization:
1769
+ * - `whitespace` - Replacement string for whitespace characters, or `true` to keep them.
1770
+ * - `underscore` - Replacement string for underscores, or `true` to keep them.
1771
+ * - `dot` - Replacement string for dots, or `true` to keep them.
1772
+ * - `dash` - Replacement string for dashes, or `true` to keep them.
1773
+ * - `es5keyword` - If true, prefixes the value with underscore if it's an ES5 keyword.
1774
+ * - `es5IdentifierName` - If true, ensures the value is a valid ES5 identifier name.
1775
+ * - `special` - If true, preserves special characters that would otherwise be removed.
1776
+ * @returns The sanitized string value.
1777
+ * @example
1778
+ * sanitize('hello-world', { dash: '_' }) // returns "hello_world"
1779
+ * sanitize('class', { es5keyword: true }) // returns "_class"
1780
+ * sanitize('123abc', { es5IdentifierName: true }) // returns "N123abc"
1781
+ */
1733
1782
  declare function sanitize(value: string, options?: {
1734
1783
  whitespace?: string | true;
1735
1784
  underscore?: string | true;
@@ -1739,8 +1788,40 @@ declare function sanitize(value: string, options?: {
1739
1788
  es5IdentifierName?: boolean;
1740
1789
  special?: boolean;
1741
1790
  }): string;
1791
+ /**
1792
+ * Converts an array of objects to a comma-separated string representation.
1793
+ * Optionally extracts a nested property from each object using a dot-notation path.
1794
+ *
1795
+ * @param props - Array of objects to convert to string.
1796
+ * @param path - Optional dot-notation path to extract a property from each object (e.g., "user.name").
1797
+ * @returns A comma-separated string of values, with each value on a new line indented.
1798
+ * @example
1799
+ * toObjectString([{ name: 'John' }, { name: 'Jane' }], 'name')
1800
+ * // returns "John,\n Jane,"
1801
+ * toObjectString(['a', 'b', 'c'])
1802
+ * // returns "a,\n b,\n c,"
1803
+ */
1742
1804
  declare function toObjectString<T>(props: T[], path?: keyof T): string;
1805
+ /**
1806
+ * Converts a number to its word representation by translating each digit to its word form.
1807
+ *
1808
+ * @param num - The number to convert to words.
1809
+ * @returns A string containing the word representation of each digit concatenated together.
1810
+ * @example
1811
+ * getNumberWord(123) // returns "onetwothree"
1812
+ * getNumberWord(42) // returns "fourtwo"
1813
+ */
1743
1814
  declare function getNumberWord(num: number): string;
1815
+ /**
1816
+ * Escapes a specific character in a string by prefixing it with a backslash.
1817
+ *
1818
+ * @param str - The string to escape, or null.
1819
+ * @param char - The character to escape. Defaults to single quote (').
1820
+ * @returns The escaped string, or null if the input is null.
1821
+ * @example
1822
+ * escape("don't") // returns "don\'t"
1823
+ * escape('say "hello"', '"') // returns 'say \\"hello\\"'
1824
+ */
1744
1825
  declare function escape(str: string | null, char?: string): string | undefined;
1745
1826
  /**
1746
1827
  * Escape all characters not included in SingleStringCharacters and
@@ -1840,5 +1921,5 @@ declare function generateTargetForTags(builder: WriteSpecBuilder, options: Norma
1840
1921
  declare function getOrvalGeneratedTypes(): string;
1841
1922
  declare function getTypedResponse(): string;
1842
1923
  //#endregion
1843
- export { AngularOptions, BODY_TYPE_NAME, BaseUrlFromConstant, BaseUrlFromSpec, ClientBuilder, ClientDependenciesBuilder, ClientExtraFilesBuilder, ClientFileBuilder, ClientFooterBuilder, ClientGeneratorsBuilder, ClientHeaderBuilder, ClientMockBuilder, ClientMockGeneratorBuilder, ClientMockGeneratorImplementation, ClientTitleBuilder, Config, ConfigExternal, ConfigFn, ContextSpec, DeepNonNullable, EnumGeneration, ErrorWithTag, FetchOptions, FormDataArrayHandling, FormDataType, GenerateMockImports, GenerateVerbOptionsParams, GenerateVerbsOptionsParams, GeneratorApiBuilder, GeneratorApiOperations, GeneratorApiResponse, GeneratorClient, GeneratorClientExtra, GeneratorClientFooter, GeneratorClientHeader, GeneratorClientImports, GeneratorClientTitle, GeneratorClients, GeneratorDependency, GeneratorImport, GeneratorMutator, GeneratorMutatorParsingInfo, GeneratorOperation, GeneratorOperations, GeneratorOptions, GeneratorSchema, GeneratorTarget, GeneratorTargetFull, GeneratorVerbOptions, GeneratorVerbsOptions, GetterBody, GetterParam, GetterParameters, GetterParams, GetterProp, GetterPropType, GetterProps, GetterQueryParam, GetterResponse, GlobalMockOptions, GlobalOptions, HonoOptions, Hook, HookCommand, HookFunction, HookOption, HooksOptions, ImportOpenApi, InputFiltersOptions, InputOptions, InputTransformerFn, JsDocOptions, LogLevel, LogLevels, LogOptions, LogType, Logger, LoggerOptions, MockData, MockDataArray, MockDataArrayFn, MockDataObject, MockDataObjectFn, MockOptions, MockProperties, MockPropertiesObject, MockPropertiesObjectFn, Mutator, MutatorObject, NamingConvention, NormalizedConfig, NormalizedFetchOptions, NormalizedFormDataType, NormalizedHonoOptions, NormalizedHookCommand, NormalizedHookOptions, NormalizedInputOptions, NormalizedJsDocOptions, NormalizedMutator, NormalizedOperationOptions, NormalizedOptions, NormalizedOutputOptions, NormalizedOverrideOutput, NormalizedParamsSerializerOptions, NormalizedQueryOptions, NormalizedSchemaOptions, NormalizedZodOptions, OpenApiComponentsObject, OpenApiDocument, OpenApiEncodingObject, OpenApiExampleObject, OpenApiInfoObject, OpenApiMediaTypeObject, OpenApiOperationObject, OpenApiParameterObject, OpenApiPathItemObject, OpenApiPathsObject, OpenApiReferenceObject, OpenApiRequestBodyObject, OpenApiResponseObject, OpenApiResponsesObject, OpenApiSchemaObject, OpenApiSchemaObjectType, OpenApiSchemasObject, OpenApiServerObject, OperationOptions, Options, OptionsExport, OptionsFn, OutputClient, OutputClientFunc, OutputDocsOptions, OutputHttpClient, OutputMockType, OutputMode, OutputOptions, OverrideInput, OverrideMockOptions, OverrideOutput, OverrideOutputContentType, PackageJson, ParamsSerializerOptions, PropertySortOrder, QueryOptions, RefComponentSuffix, RefInfo, ResReqTypesValue, ResolverValue, ResponseTypeCategory, ScalarValue, SchemaGenerationType, SchemaOptions, SchemaType, SwrOptions, TEMPLATE_TAG_REGEX, TsConfigTarget, Tsconfig, URL_REGEX, VERBS_WITH_BODY, Verbs, WriteModeProps, WriteSpecBuilder, ZodCoerceType, ZodDateTimeOptions, ZodOptions, ZodTimeOptions, _filteredVerbs, addDependency, asyncReduce, camel, combineSchemas, compareVersions, conventionName, count, createDebugger, createLogger, createSuccessMessage, dynamicImport, escape, 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, getDefaultContentType, getEnum, getEnumDescriptions, getEnumImplementation, getEnumNames, 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, startMessage, stringify, toObjectString, path_d_exports as upath, upper, writeModelInline, writeModelsInline, writeSchema, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode };
1924
+ export { AngularOptions, BODY_TYPE_NAME, BaseUrlFromConstant, BaseUrlFromSpec, ClientBuilder, ClientDependenciesBuilder, ClientExtraFilesBuilder, ClientFileBuilder, ClientFooterBuilder, ClientGeneratorsBuilder, ClientHeaderBuilder, ClientMockBuilder, ClientMockGeneratorBuilder, ClientMockGeneratorImplementation, ClientTitleBuilder, Config, ConfigExternal, ConfigFn, ContextSpec, DeepNonNullable, EnumGeneration, ErrorWithTag, FetchOptions, FormDataArrayHandling, FormDataType, GenerateMockImports, GenerateVerbOptionsParams, GenerateVerbsOptionsParams, GeneratorApiBuilder, GeneratorApiOperations, GeneratorApiResponse, GeneratorClient, GeneratorClientExtra, GeneratorClientFooter, GeneratorClientHeader, GeneratorClientImports, GeneratorClientTitle, GeneratorClients, GeneratorDependency, GeneratorImport, GeneratorMutator, GeneratorMutatorParsingInfo, GeneratorOperation, GeneratorOperations, GeneratorOptions, GeneratorSchema, GeneratorTarget, GeneratorTargetFull, GeneratorVerbOptions, GeneratorVerbsOptions, GetterBody, GetterParam, GetterParameters, GetterParams, GetterProp, GetterPropType, GetterProps, GetterQueryParam, GetterResponse, GlobalMockOptions, GlobalOptions, HonoOptions, Hook, HookCommand, HookFunction, HookOption, HooksOptions, ImportOpenApi, InputFiltersOptions, InputOptions, InputTransformerFn, InvalidateTarget, JsDocOptions, LogLevel, LogLevels, LogOptions, LogType, Logger, LoggerOptions, MockData, MockDataArray, MockDataArrayFn, MockDataObject, MockDataObjectFn, MockOptions, MockProperties, MockPropertiesObject, MockPropertiesObjectFn, MutationInvalidatesConfig, MutationInvalidatesRule, Mutator, MutatorObject, NamingConvention, NormalizedConfig, NormalizedFetchOptions, NormalizedFormDataType, NormalizedHonoOptions, NormalizedHookCommand, NormalizedHookOptions, NormalizedInputOptions, NormalizedJsDocOptions, NormalizedMutator, NormalizedOperationOptions, NormalizedOptions, NormalizedOutputOptions, NormalizedOverrideOutput, NormalizedParamsSerializerOptions, NormalizedQueryOptions, NormalizedSchemaOptions, NormalizedZodOptions, OpenApiComponentsObject, OpenApiDocument, OpenApiEncodingObject, OpenApiExampleObject, OpenApiInfoObject, OpenApiMediaTypeObject, OpenApiOperationObject, OpenApiParameterObject, OpenApiPathItemObject, OpenApiPathsObject, OpenApiReferenceObject, OpenApiRequestBodyObject, OpenApiResponseObject, OpenApiResponsesObject, OpenApiSchemaObject, OpenApiSchemaObjectType, OpenApiSchemasObject, OpenApiServerObject, OperationOptions, Options, OptionsExport, OptionsFn, OutputClient, OutputClientFunc, OutputDocsOptions, OutputHttpClient, OutputMockType, OutputMode, OutputOptions, OverrideInput, OverrideMockOptions, OverrideOutput, OverrideOutputContentType, PackageJson, ParamsSerializerOptions, PropertySortOrder, QueryOptions, RefComponentSuffix, RefInfo, ResReqTypesValue, ResolverValue, ResponseTypeCategory, ScalarValue, SchemaGenerationType, SchemaOptions, SchemaType, SwrOptions, TEMPLATE_TAG_REGEX, TsConfigTarget, Tsconfig, URL_REGEX, VERBS_WITH_BODY, Verbs, WriteModeProps, WriteSpecBuilder, ZodCoerceType, ZodDateTimeOptions, ZodOptions, ZodTimeOptions, _filteredVerbs, addDependency, asyncReduce, camel, combineSchemas, compareVersions, conventionName, count, createDebugger, createLogger, createSuccessMessage, dynamicImport, escape, 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, getDefaultContentType, getEnum, getEnumDescriptions, getEnumImplementation, getEnumNames, 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, startMessage, stringify, toObjectString, path_d_exports as upath, upper, writeModelInline, writeModelsInline, writeSchema, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode };
1844
1925
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as __export } from "./chunk-C6wwvPpM.mjs";
2
- import { entries, isArray, isEmptyish, prop, unique, uniqueBy, uniqueWith } from "remeda";
2
+ import { entries, groupBy, isArray, isEmptyish, prop, unique, uniqueBy, uniqueWith } from "remeda";
3
3
  import { keyword } from "esutils";
4
4
  import path from "node:path";
5
5
  import fs from "node:fs";
@@ -36,6 +36,8 @@ const OutputClient = {
36
36
  AXIOS: "axios",
37
37
  AXIOS_FUNCTIONS: "axios-functions",
38
38
  REACT_QUERY: "react-query",
39
+ SOLID_START: "solid-start",
40
+ SOLID_QUERY: "solid-query",
39
41
  SVELTE_QUERY: "svelte-query",
40
42
  VUE_QUERY: "vue-query",
41
43
  SWR: "swr",
@@ -674,6 +676,18 @@ const sortByPriority = (arr) => arr.sort((a, b) => {
674
676
 
675
677
  //#endregion
676
678
  //#region src/utils/string.ts
679
+ /**
680
+ * Converts data to a string representation suitable for code generation.
681
+ * Handles strings, numbers, booleans, functions, arrays, and objects.
682
+ *
683
+ * @param data - The data to stringify. Can be a string, array, object, number, boolean, function, null, or undefined.
684
+ * @returns A string representation of the data, or undefined if data is null or undefined.
685
+ * @example
686
+ * stringify('hello') // returns "'hello'"
687
+ * stringify(42) // returns "42"
688
+ * stringify([1, 2, 3]) // returns "[1, 2, 3]"
689
+ * stringify({ a: 1, b: 'test' }) // returns "{ a: 1, b: 'test', }"
690
+ */
677
691
  function stringify(data) {
678
692
  if (isUndefined(data) || isNull(data)) return;
679
693
  if (isString(data)) return `'${data.replaceAll("'", String.raw`\'`)}'`;
@@ -687,6 +701,25 @@ function stringify(data) {
687
701
  return acc + `${key}: ${strValue}, `;
688
702
  }, "");
689
703
  }
704
+ /**
705
+ * Sanitizes a string value by removing or replacing special characters and ensuring
706
+ * it conforms to JavaScript identifier naming rules if needed.
707
+ *
708
+ * @param value - The string value to sanitize.
709
+ * @param options - Configuration options for sanitization:
710
+ * - `whitespace` - Replacement string for whitespace characters, or `true` to keep them.
711
+ * - `underscore` - Replacement string for underscores, or `true` to keep them.
712
+ * - `dot` - Replacement string for dots, or `true` to keep them.
713
+ * - `dash` - Replacement string for dashes, or `true` to keep them.
714
+ * - `es5keyword` - If true, prefixes the value with underscore if it's an ES5 keyword.
715
+ * - `es5IdentifierName` - If true, ensures the value is a valid ES5 identifier name.
716
+ * - `special` - If true, preserves special characters that would otherwise be removed.
717
+ * @returns The sanitized string value.
718
+ * @example
719
+ * sanitize('hello-world', { dash: '_' }) // returns "hello_world"
720
+ * sanitize('class', { es5keyword: true }) // returns "_class"
721
+ * sanitize('123abc', { es5IdentifierName: true }) // returns "N123abc"
722
+ */
690
723
  function sanitize(value, options) {
691
724
  const { whitespace = "", underscore = "", dot = "", dash = "", es5keyword = false, es5IdentifierName = false, special = false } = options ?? {};
692
725
  let newValue = value;
@@ -700,6 +733,19 @@ function sanitize(value, options) {
700
733
  else newValue = keyword.isIdentifierNameES5(newValue) ? newValue : `_${newValue}`;
701
734
  return newValue;
702
735
  }
736
+ /**
737
+ * Converts an array of objects to a comma-separated string representation.
738
+ * Optionally extracts a nested property from each object using a dot-notation path.
739
+ *
740
+ * @param props - Array of objects to convert to string.
741
+ * @param path - Optional dot-notation path to extract a property from each object (e.g., "user.name").
742
+ * @returns A comma-separated string of values, with each value on a new line indented.
743
+ * @example
744
+ * toObjectString([{ name: 'John' }, { name: 'Jane' }], 'name')
745
+ * // returns "John,\n Jane,"
746
+ * toObjectString(['a', 'b', 'c'])
747
+ * // returns "a,\n b,\n c,"
748
+ */
703
749
  function toObjectString(props, path$2) {
704
750
  if (props.length === 0) return "";
705
751
  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 ") + ",";
@@ -716,9 +762,28 @@ const NUMBERS = {
716
762
  "8": "eight",
717
763
  "9": "nine"
718
764
  };
765
+ /**
766
+ * Converts a number to its word representation by translating each digit to its word form.
767
+ *
768
+ * @param num - The number to convert to words.
769
+ * @returns A string containing the word representation of each digit concatenated together.
770
+ * @example
771
+ * getNumberWord(123) // returns "onetwothree"
772
+ * getNumberWord(42) // returns "fourtwo"
773
+ */
719
774
  function getNumberWord(num) {
720
775
  return num.toString().split("").reduce((acc, n) => acc + NUMBERS[n], "");
721
776
  }
777
+ /**
778
+ * Escapes a specific character in a string by prefixing it with a backslash.
779
+ *
780
+ * @param str - The string to escape, or null.
781
+ * @param char - The character to escape. Defaults to single quote (').
782
+ * @returns The escaped string, or null if the input is null.
783
+ * @example
784
+ * escape("don't") // returns "don\'t"
785
+ * escape('say "hello"', '"') // returns 'say \\"hello\\"'
786
+ */
722
787
  function escape(str, char = "'") {
723
788
  return str?.replace(char, `\\${char}`);
724
789
  }
@@ -776,7 +841,6 @@ const getTypeConstEnum = (value, enumName, names, descriptions, enumNamingConven
776
841
  enumValue += ";\n";
777
842
  const implementation = getEnumImplementation(value, names, descriptions, enumNamingConvention);
778
843
  enumValue += "\n\n";
779
- enumValue += "// eslint-disable-next-line @typescript-eslint/no-redeclare\n";
780
844
  enumValue += `export const ${enumName} = {\n${implementation}} as const;\n`;
781
845
  return enumValue;
782
846
  };
@@ -944,12 +1008,13 @@ function resolveValue({ schema, name, context }) {
944
1008
  const { schema: schemaObject, imports } = resolveRef(schema, context);
945
1009
  const resolvedImport = imports[0];
946
1010
  let hasReadonlyProps = false;
947
- if (!name || !context.parents?.includes(name)) hasReadonlyProps = getScalar({
1011
+ const refName = resolvedImport.name;
1012
+ if (!context.parents?.includes(refName)) hasReadonlyProps = getScalar({
948
1013
  item: schemaObject,
949
- name: resolvedImport.name,
1014
+ name: refName,
950
1015
  context: {
951
1016
  ...context,
952
- ...name ? { parents: [...context.parents ?? [], name] } : {}
1017
+ parents: [...context.parents ?? [], refName]
953
1018
  }
954
1019
  }).hasReadonlyProps;
955
1020
  const nullable = Array.isArray(schemaObject.type) && schemaObject.type.includes("null") ? " | null" : "";
@@ -1014,7 +1079,8 @@ function resolveObjectOriginal({ schema, propName, combined = false, context })
1014
1079
  };
1015
1080
  }
1016
1081
  if (propName && resolvedValue.isEnum && !combined && !resolvedValue.isRef) {
1017
- const enumValue = getEnum(resolvedValue.value, propName, getEnumNames(resolvedValue.originalSchema), context.output.override.enumGenerationType, getEnumDescriptions(resolvedValue.originalSchema), context.output.override.namingConvention?.enum);
1082
+ const enumGenerationType = context.output.override.enumGenerationType;
1083
+ const enumValue = getEnum(resolvedValue.value, propName, getEnumNames(resolvedValue.originalSchema), enumGenerationType, getEnumDescriptions(resolvedValue.originalSchema), context.output.override.namingConvention?.enum);
1018
1084
  return {
1019
1085
  value: propName,
1020
1086
  imports: [{ name: propName }],
@@ -1029,7 +1095,7 @@ function resolveObjectOriginal({ schema, propName, combined = false, context })
1029
1095
  originalSchema: resolvedValue.originalSchema,
1030
1096
  isRef: resolvedValue.isRef,
1031
1097
  hasReadonlyProps: resolvedValue.hasReadonlyProps,
1032
- dependencies: resolvedValue.dependencies
1098
+ dependencies: [...resolvedValue.dependencies, propName]
1033
1099
  };
1034
1100
  }
1035
1101
  return resolvedValue;
@@ -1375,7 +1441,7 @@ function combineSchemas({ name, schema, separator: separator$1, context, nullabl
1375
1441
  requiredProperties: separator$1 === "allOf" ? schema.required ?? [] : []
1376
1442
  });
1377
1443
  if (resolvedData.isEnum.every(Boolean) && name && items.length > 1 && separator$1 !== "oneOf") {
1378
- const newEnum = `// eslint-disable-next-line @typescript-eslint/no-redeclare\nexport const ${pascal(name)} = ${getCombineEnumValue(resolvedData)}`;
1444
+ const newEnum = `export const ${pascal(name)} = ${getCombineEnumValue(resolvedData)}`;
1379
1445
  return {
1380
1446
  value: `typeof ${pascal(name)}[keyof typeof ${pascal(name)}] ${nullable}`,
1381
1447
  imports: [{ name: pascal(name) }],
@@ -1516,17 +1582,28 @@ function getObject({ item, name, context, nullable, propertyOverrides }) {
1516
1582
  if (!index) acc.value += "{";
1517
1583
  const doc = jsDoc(schema, true, context);
1518
1584
  acc.hasReadonlyProps ||= isReadOnly || false;
1519
- const aliasedImports = getAliasedImports({
1585
+ const constValue = "const" in schema ? schema.const : void 0;
1586
+ const hasConst = constValue !== void 0;
1587
+ let constLiteral;
1588
+ if (!hasConst) constLiteral = void 0;
1589
+ else if (typeof constValue === "string") constLiteral = `'${escape(constValue)}'`;
1590
+ else constLiteral = JSON.stringify(constValue);
1591
+ const needsValueImport = hasConst && (resolvedValue.isEnum || resolvedValue.type === "enum");
1592
+ const aliasedImports = needsValueImport ? resolvedValue.imports.map((imp) => ({
1593
+ ...imp,
1594
+ isConstant: true
1595
+ })) : hasConst ? [] : getAliasedImports({
1520
1596
  name,
1521
1597
  context,
1522
1598
  resolvedValue
1523
1599
  });
1524
- acc.imports.push(...aliasedImports);
1525
- const propValue = getImportAliasForRefOrValue({
1600
+ if (aliasedImports.length > 0) acc.imports.push(...aliasedImports);
1601
+ const alias = getImportAliasForRefOrValue({
1526
1602
  context,
1527
1603
  resolvedValue,
1528
1604
  imports: aliasedImports
1529
1605
  });
1606
+ const propValue = needsValueImport ? alias : constLiteral ?? alias;
1530
1607
  acc.value += `\n ${doc ? `${doc} ` : ""}${isReadOnly && !context.output.override.suppressReadonlyModifier ? "readonly " : ""}${getKey(key)}${isRequired ? "" : "?"}: ${propValue};`;
1531
1608
  acc.schemas.push(...resolvedValue.schemas);
1532
1609
  acc.dependencies.push(...resolvedValue.dependencies);
@@ -1657,9 +1734,9 @@ function getResReqTypes(responsesOrRequests, name, context, defaultType = "unkno
1657
1734
  isEnum: false,
1658
1735
  isRef: true,
1659
1736
  hasReadonlyProps: false,
1660
- originalSchema: mediaType.schema,
1661
- example: mediaType.example,
1662
- examples: resolveExampleRefs(mediaType.examples, context),
1737
+ originalSchema: mediaType?.schema,
1738
+ example: mediaType?.example,
1739
+ examples: resolveExampleRefs(mediaType?.examples, context),
1663
1740
  key,
1664
1741
  contentType
1665
1742
  }];
@@ -2472,9 +2549,15 @@ function generateComponentDefinition(responses = {}, context, suffix) {
2472
2549
  //#region src/generators/imports.ts
2473
2550
  function generateImports({ imports, namingConvention = NamingConvention.CAMEL_CASE }) {
2474
2551
  if (imports.length === 0) return "";
2475
- return uniqueWith(imports, (a, b) => a.name === b.name && a.default === b.default).toSorted().map(({ name, values, alias, isConstant }) => {
2476
- const fileName = conventionName(name, namingConvention);
2477
- return `import ${!values && !isConstant ? "type " : ""}{ ${name}${alias ? ` as ${alias}` : ""} } from './${fileName}';`;
2552
+ const grouped = groupBy(uniqueWith(imports, (a, b) => a.name === b.name && a.default === b.default).map((imp) => ({
2553
+ ...imp,
2554
+ importPath: imp.importPath ?? `./${conventionName(imp.name, namingConvention)}`
2555
+ })), (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)}`);
2556
+ return Object.entries(grouped).toSorted(([a], [b]) => a.localeCompare(b)).map(([, group]) => {
2557
+ const sample = group[0];
2558
+ if (!sample.default && !sample.namespaceImport && !sample.syntheticDefaultImport && !sample.values && !sample.isConstant) return `import type { ${[...new Set(group.map(({ name: name$1, alias: alias$1 }) => `${name$1}${alias$1 ? ` as ${alias$1}` : ""}`))].toSorted().join(", ")} } from '${sample.importPath}';`;
2559
+ const { name, values, alias, isConstant, importPath } = sample;
2560
+ return `import ${!values && !isConstant ? "type " : ""}{ ${name}${alias ? ` as ${alias}` : ""} } from '${importPath}';`;
2478
2561
  }).join("\n");
2479
2562
  }
2480
2563
  function generateMutatorImports({ mutators, implementation, oneMore }) {
@@ -2604,10 +2687,10 @@ function generateModelsInline(obj) {
2604
2687
  //#endregion
2605
2688
  //#region src/generators/mutator-info.ts
2606
2689
  async function getMutatorInfo(filePath, options) {
2607
- const { root = process.cwd(), namedExport = "default", alias, tsconfig } = options ?? {};
2608
- return parseFile(await bundleFile(root, path.resolve(filePath), alias, tsconfig?.compilerOptions), namedExport, getEcmaVersion(tsconfig?.compilerOptions?.target));
2690
+ const { root = process.cwd(), namedExport = "default", alias, external, tsconfig } = options ?? {};
2691
+ return parseFile(await bundleFile(root, path.resolve(filePath), alias, external, tsconfig?.compilerOptions), namedExport, getEcmaVersion(tsconfig?.compilerOptions?.target));
2609
2692
  }
2610
- async function bundleFile(root, fileName, alias, compilerOptions) {
2693
+ async function bundleFile(root, fileName, alias, external, compilerOptions) {
2611
2694
  const { text } = (await build({
2612
2695
  absWorkingDir: root,
2613
2696
  entryPoints: [fileName],
@@ -2623,7 +2706,8 @@ async function bundleFile(root, fileName, alias, compilerOptions) {
2623
2706
  minifyWhitespace: false,
2624
2707
  treeShaking: false,
2625
2708
  keepNames: false,
2626
- alias
2709
+ alias,
2710
+ external: external || ["*"]
2627
2711
  })).outputFiles[0];
2628
2712
  return text;
2629
2713
  }
@@ -2723,6 +2807,7 @@ async function generateMutator({ output, mutator, name, workspace, tsconfig }) {
2723
2807
  root: path.resolve(workspace),
2724
2808
  namedExport: mutatorInfoName,
2725
2809
  alias: mutator.alias,
2810
+ external: mutator.external,
2726
2811
  tsconfig
2727
2812
  });
2728
2813
  if (!mutatorInfo) throw new Error(chalk.red(`Your mutator file doesn't have the ${mutatorInfoName} exported function`));
@@ -3195,6 +3280,54 @@ function _filteredVerbs(verbs, filters) {
3195
3280
 
3196
3281
  //#endregion
3197
3282
  //#region src/writers/schemas.ts
3283
+ function getSchemaKey(schemaPath, schemaName, namingConvention, fileExtension) {
3284
+ return getPath(schemaPath, conventionName(schemaName, namingConvention), fileExtension).toLowerCase().replaceAll("\\", "/");
3285
+ }
3286
+ function getSchemaGroups(schemaPath, schemas, namingConvention, fileExtension) {
3287
+ return groupBy(schemas, (schema) => getSchemaKey(schemaPath, schema.name, namingConvention, fileExtension));
3288
+ }
3289
+ function getCanonicalMap(schemaGroups, schemaPath, namingConvention, fileExtension) {
3290
+ const canonicalPathMap = /* @__PURE__ */ new Map();
3291
+ for (const [key, groupSchemas] of Object.entries(schemaGroups)) {
3292
+ const canonicalPath = getPath(schemaPath, conventionName(groupSchemas[0].name, namingConvention), fileExtension);
3293
+ canonicalPathMap.set(key, {
3294
+ importPath: canonicalPath,
3295
+ name: groupSchemas[0].name
3296
+ });
3297
+ }
3298
+ return canonicalPathMap;
3299
+ }
3300
+ function normalizeCanonicalImportPaths(schemas, canonicalPathMap, schemaPath, namingConvention, fileExtension) {
3301
+ for (const schema of schemas) schema.imports = schema.imports.map((imp) => {
3302
+ const resolvedImportKey = resolveImportKey(schemaPath, imp.importPath ?? `./${conventionName(imp.name, namingConvention)}`, fileExtension);
3303
+ const canonical = canonicalPathMap.get(resolvedImportKey);
3304
+ if (!canonical?.importPath) return imp;
3305
+ const importPath = removeFileExtension(relativeSafe(schemaPath, canonical.importPath.replaceAll("\\", "/")), fileExtension);
3306
+ return {
3307
+ ...imp,
3308
+ importPath
3309
+ };
3310
+ });
3311
+ }
3312
+ function mergeSchemaGroup(schemas) {
3313
+ const baseSchemaName = schemas[0].name;
3314
+ const baseSchema = schemas[0].schema;
3315
+ const mergedImports = [...new Map(schemas.flatMap((schema) => schema.imports).map((imp) => [JSON.stringify(imp), imp])).values()];
3316
+ const mergedDependencies = [...new Set(schemas.flatMap((schema) => schema.dependencies ?? []))];
3317
+ return {
3318
+ name: baseSchemaName,
3319
+ schema: baseSchema,
3320
+ model: schemas.map((schema) => schema.model).join("\n"),
3321
+ imports: mergedImports,
3322
+ dependencies: mergedDependencies
3323
+ };
3324
+ }
3325
+ function resolveImportKey(schemaPath, importPath, fileExtension) {
3326
+ return join(schemaPath, `${importPath}${fileExtension}`).toLowerCase().replaceAll("\\", "/");
3327
+ }
3328
+ function removeFileExtension(path$2, fileExtension) {
3329
+ return path$2.endsWith(fileExtension) ? path$2.slice(0, path$2.length - fileExtension.length) : path$2;
3330
+ }
3198
3331
  function getSchema({ schema: { imports, model }, target, header, namingConvention = NamingConvention.CAMEL_CASE }) {
3199
3332
  let file = header;
3200
3333
  file += generateImports({
@@ -3206,7 +3339,9 @@ function getSchema({ schema: { imports, model }, target, header, namingConventio
3206
3339
  file += model;
3207
3340
  return file;
3208
3341
  }
3209
- const getPath = (path$2, name, fileExtension) => join(path$2, `/${name}${fileExtension}`);
3342
+ function getPath(path$2, name, fileExtension) {
3343
+ return join(path$2, `/${name}${fileExtension}`);
3344
+ }
3210
3345
  function writeModelInline(acc, model) {
3211
3346
  return acc + `${model}\n`;
3212
3347
  }
@@ -3229,28 +3364,34 @@ async function writeSchema({ path: path$2, schema, target, namingConvention, fil
3229
3364
  }
3230
3365
  }
3231
3366
  async function writeSchemas({ schemaPath, schemas, target, namingConvention, fileExtension, header, indexFiles }) {
3232
- await Promise.all(schemas.map(async (schema) => {
3367
+ const schemaGroups = getSchemaGroups(schemaPath, schemas, namingConvention, fileExtension);
3368
+ normalizeCanonicalImportPaths(schemas, getCanonicalMap(schemaGroups, schemaPath, namingConvention, fileExtension), schemaPath, namingConvention, fileExtension);
3369
+ for (const groupSchemas of Object.values(schemaGroups)) {
3370
+ if (groupSchemas.length === 1) {
3371
+ await writeSchema({
3372
+ path: schemaPath,
3373
+ schema: groupSchemas[0],
3374
+ target,
3375
+ namingConvention,
3376
+ fileExtension,
3377
+ header
3378
+ });
3379
+ continue;
3380
+ }
3233
3381
  await writeSchema({
3234
3382
  path: schemaPath,
3235
- schema,
3383
+ schema: mergeSchemaGroup(groupSchemas),
3236
3384
  target,
3237
3385
  namingConvention,
3238
3386
  fileExtension,
3239
3387
  header
3240
3388
  });
3241
- }));
3389
+ }
3242
3390
  if (indexFiles) {
3243
3391
  const schemaFilePath = join(schemaPath, `/index${fileExtension}`);
3244
3392
  await fs$1.ensureFile(schemaFilePath);
3245
3393
  const ext = fileExtension.endsWith(".ts") ? fileExtension.slice(0, -3) : fileExtension;
3246
- const conventionNamesSet = /* @__PURE__ */ new Set();
3247
- const duplicateNamesMap = /* @__PURE__ */ new Map();
3248
- for (const schema of schemas) {
3249
- const conventionNameValue = conventionName(schema.name, namingConvention);
3250
- if (conventionNamesSet.has(conventionNameValue)) duplicateNamesMap.set(conventionNameValue, (duplicateNamesMap.get(conventionNameValue) ?? 0) + 1);
3251
- else conventionNamesSet.add(conventionNameValue);
3252
- }
3253
- if (duplicateNamesMap.size > 0) throw new Error("Duplicate schema names detected (after naming convention):\n" + [...duplicateNamesMap].map((duplicate) => ` ${duplicate[1] + 1}x ${duplicate[0]}`).join("\n"));
3394
+ const conventionNamesSet = new Set(Object.values(schemaGroups).map((group) => conventionName(group[0].name, namingConvention)));
3254
3395
  try {
3255
3396
  const fileContent = `${header}\n${[...conventionNamesSet].map((schemaName) => `export * from './${schemaName}${ext}';`).toSorted((a, b) => a.localeCompare(b)).join("\n")}`;
3256
3397
  await fs$1.writeFile(schemaFilePath, fileContent, { encoding: "utf8" });