orval 8.18.0 → 8.19.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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { c as description, i as startWatcher, l as name, n as loadConfigFile, r as generateSpec, s as normalizeOptions, t as findConfigFile, u as version } from "../config-CXPetEiJ.mjs";
2
+ import { c as description, i as startWatcher, l as name, n as loadConfigFile, r as generateSpec, s as normalizeOptions, t as findConfigFile, u as version } from "../config-D-TQRn-G.mjs";
3
3
  import path from "node:path";
4
4
  import { Option, program } from "@commander-js/extra-typings";
5
5
  import { ErrorWithTag, OutputClient, OutputMode, SupportedFormatter, getWarningCount, isString, log, logError, resetWarnings, setVerbose, startMessage } from "@orval/core";
@@ -1,5 +1,5 @@
1
1
  import path from "node:path";
2
- import { FormDataArrayHandling, GetterPropType, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SupportedFormatter, asyncReduce, buildDynamicScope, collectReferencedComponents, conventionName, createSuccessMessage, dynamicImport, fixCrossDirectoryImports, fixRegularSchemaImports, generateComponentDefinition, generateDependencyImports, generateMutator, generateParameterDefinition, generateSchemasDefinition, generateVerbsOptions, getBaseUrlRuntimeImports, getFileInfo, getFullRoute, getImportExtension, getMockFileExtensionByTypeName, getRefInfo, getRoute, isBoolean, isComponentRef, isFunction, isNullish, isObject, isReference, isString, isUrl, jsDoc, log, logError, logVerbose, logWarning, pascal, removeFilesAndEmptyFolders, resolveInstalledVersions, resolveRef, resolveValue, splitSchemasByType, upath, writeGeneratedFile, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode } from "@orval/core";
2
+ import { DefaultTag, FormDataArrayHandling, GetterPropType, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SupportedFormatter, asyncReduce, buildDynamicScope, buildSchemaTagMap, collectReferencedComponents, conventionName, createSuccessMessage, dynamicImport, fixCrossDirectoryImports, fixRegularSchemaImports, generateComponentDefinition, generateDependencyImports, generateMutator, generateParameterDefinition, generateSchemasDefinition, generateVerbsOptions, getBaseUrlRuntimeImports, getFileInfo, getFullRoute, getImportExtension, getMockFileExtensionByTypeName, getRefInfo, getRoute, isBoolean, isComponentRef, isFunction, isNullish, isObject, isReference, isString, isUrl, jsDoc, kebab, log, logError, logVerbose, logWarning, pascal, removeFilesAndEmptyFolders, resolveInstalledVersions, resolveRef, resolveValue, splitSchemasByType, upath, writeGeneratedFile, writeSchemas, writeSchemasTagsSplit, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode } from "@orval/core";
3
3
  import { bundle } from "@scalar/json-magic/bundle";
4
4
  import { fetchUrls, parseJson, parseYaml, readFiles } from "@scalar/json-magic/bundle/plugins/node";
5
5
  import { upgrade, validate } from "@scalar/openapi-parser";
@@ -15,7 +15,7 @@ import mcp from "@orval/mcp";
15
15
  import query from "@orval/query";
16
16
  import solidStart from "@orval/solid-start";
17
17
  import swr from "@orval/swr";
18
- import zod, { dereference, generateFormDataZodSchema, generateZodValidationSchemaDefinition, isZodVersionV4, parseZodValidationSchemaDefinition } from "@orval/zod";
18
+ import zod, { dereference, generateFormDataZodSchema, generateZodValidationSchemaDefinition, parseZodValidationSchemaDefinition, resolveIsZodV4 } from "@orval/zod";
19
19
  import { ExecaError, execa } from "execa";
20
20
  import fs from "fs-extra";
21
21
  import fs$1, { access } from "node:fs/promises";
@@ -28,7 +28,7 @@ import fs$2 from "node:fs";
28
28
  import { createJiti } from "jiti";
29
29
  //#region package.json
30
30
  var name = "orval";
31
- var version = "8.18.0";
31
+ var version = "8.19.0";
32
32
  var description = "A swagger client generator for typescript";
33
33
  //#endregion
34
34
  //#region src/client.ts
@@ -77,21 +77,24 @@ const generateClientImports = ({ client, implementation, imports, projectName, h
77
77
  };
78
78
  const generateClientHeader = ({ outputClient = DEFAULT_CLIENT, isRequestOptions, isGlobalMutator, isMutator, provideIn, hasAwaitedType, titles, output, verbOptions, tag, isDefaultTagBucket, clientImplementation }) => {
79
79
  const { header } = getGeneratorClient(outputClient, output);
80
+ const rawHeader = header ? header({
81
+ title: titles.implementation,
82
+ isRequestOptions,
83
+ isGlobalMutator,
84
+ isMutator,
85
+ provideIn,
86
+ hasAwaitedType,
87
+ output,
88
+ verbOptions,
89
+ tag,
90
+ isDefaultTagBucket,
91
+ clientImplementation
92
+ }) : "";
93
+ const normalizedHeader = typeof rawHeader === "string" ? { implementation: rawHeader } : rawHeader;
80
94
  return {
81
- implementation: header ? header({
82
- title: titles.implementation,
83
- isRequestOptions,
84
- isGlobalMutator,
85
- isMutator,
86
- provideIn,
87
- hasAwaitedType,
88
- output,
89
- verbOptions,
90
- tag,
91
- isDefaultTagBucket,
92
- clientImplementation
93
- }) : "",
94
- implementationMock: `export const ${titles.implementationMock} = () => [\n`
95
+ implementation: normalizedHeader.implementation,
96
+ implementationMock: `export const ${titles.implementationMock} = () => [\n`,
97
+ sharedTypes: normalizedHeader.sharedTypes
95
98
  };
96
99
  };
97
100
  const generateClientFooter = ({ outputClient, operationNames, hasMutator, hasAwaitedType, titles, output }) => {
@@ -888,7 +891,8 @@ function normalizeSchemasOption(schemas, workspace) {
888
891
  return {
889
892
  path: normalizePath(schemas.path, workspace),
890
893
  type: schemas.type ?? "typescript",
891
- importPath: schemas.importPath
894
+ importPath: schemas.importPath,
895
+ splitByTags: schemas.splitByTags ?? false
892
896
  };
893
897
  }
894
898
  /**
@@ -1017,6 +1021,8 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
1017
1021
  baseUrl: outputOptions.baseUrl,
1018
1022
  unionAddMissingProperties: outputOptions.unionAddMissingProperties ?? false,
1019
1023
  factoryMethods,
1024
+ tagsSplitDeduplication: outputOptions.tagsSplitDeduplication ?? false,
1025
+ commonTypesFileName: outputOptions.commonTypesFileName ?? "common-types",
1020
1026
  override: {
1021
1027
  ...outputOptions.override,
1022
1028
  mock: {
@@ -1027,8 +1033,8 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
1027
1033
  fractionDigits: outputOptions.override?.mock?.fractionDigits ?? 2,
1028
1034
  ...outputOptions.override?.mock
1029
1035
  },
1030
- operations: normalizeOperationsAndTags(outputOptions.override?.operations ?? {}, outputWorkspace, { query: globalQueryOptions }),
1031
- tags: normalizeOperationsAndTags(outputOptions.override?.tags ?? {}, outputWorkspace, { query: globalQueryOptions }),
1036
+ operations: normalizeOperationsAndTags(outputOptions.override?.operations ?? {}, outputWorkspace, { query: globalQueryOptions }, "operations"),
1037
+ tags: normalizeOperationsAndTags(outputOptions.override?.tags ?? {}, outputWorkspace, { query: globalQueryOptions }, "tags"),
1032
1038
  mutator: normalizeMutator(outputWorkspace, outputOptions.override?.mutator),
1033
1039
  formData: createFormData(outputWorkspace, outputOptions.override?.formData),
1034
1040
  formUrlEncoded: (isBoolean(outputOptions.override?.formUrlEncoded) ? outputOptions.override.formUrlEncoded : normalizeMutator(outputWorkspace, outputOptions.override?.formUrlEncoded)) ?? true,
@@ -1090,6 +1096,7 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
1090
1096
  ...outputOptions.override?.zod?.preprocess?.response ? { response: normalizeMutator(outputWorkspace, outputOptions.override.zod.preprocess.response) } : {}
1091
1097
  },
1092
1098
  ...outputOptions.override?.zod?.params ? { params: normalizeMutator(outputWorkspace, outputOptions.override.zod.params) } : {},
1099
+ version: outputOptions.override?.zod?.version ?? "auto",
1093
1100
  generateEachHttpStatus: outputOptions.override?.zod?.generateEachHttpStatus ?? false,
1094
1101
  useBrandedTypes: outputOptions.override?.zod?.useBrandedTypes ?? false,
1095
1102
  generateReusableSchemas: outputOptions.override?.zod?.generateReusableSchemas ?? false,
@@ -1113,6 +1120,7 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
1113
1120
  forceSuccessResponse: outputOptions.override?.fetch?.forceSuccessResponse ?? false,
1114
1121
  runtimeValidation: outputOptions.override?.fetch?.runtimeValidation ?? false,
1115
1122
  useRuntimeFetcher: outputOptions.override?.fetch?.useRuntimeFetcher ?? false,
1123
+ ...outputOptions.override?.fetch?.arrayFormat ? { arrayFormat: outputOptions.override.fetch.arrayFormat } : {},
1116
1124
  ...outputOptions.override?.fetch,
1117
1125
  ...outputOptions.override?.fetch?.jsonReviver ? { jsonReviver: normalizeMutator(outputWorkspace, outputOptions.override.fetch.jsonReviver) } : {}
1118
1126
  },
@@ -1227,8 +1235,19 @@ function normalizePath(path$1, workspace) {
1227
1235
  if (!isString(path$1)) return path$1;
1228
1236
  return path.resolve(workspace, path$1);
1229
1237
  }
1230
- function normalizeOperationsAndTags(operationsOrTags, workspace, global) {
1238
+ function normalizeOperationsAndTags(operationsOrTags, workspace, global, source) {
1239
+ const unsupportedZodKeys = [
1240
+ "version",
1241
+ "dateTimeOptions",
1242
+ "timeOptions",
1243
+ "generateEachHttpStatus",
1244
+ "generateReusableSchemas",
1245
+ "generateMeta"
1246
+ ];
1231
1247
  return Object.fromEntries(Object.entries(operationsOrTags).map(([key, { transformer, mutator, formData, formUrlEncoded, paramsSerializer, paramsFilter, query, angular, zod, effect, ...rest }]) => {
1248
+ const unsupportedOperationZodKeys = zod && unsupportedZodKeys.filter((unsupportedKey) => zod[unsupportedKey] !== void 0);
1249
+ if (unsupportedOperationZodKeys && unsupportedOperationZodKeys.length) logWarning(`⚠️ override.${source}.${key}.zod only supports strict, generate, coerce, preprocess, params, and useBrandedTypes. Ignoring unsupported ${unsupportedOperationZodKeys.length === 1 ? "field" : "fields"}: ${unsupportedOperationZodKeys.map((unsupportedKey) => `zod.${unsupportedKey}`).join(", ")}.`);
1250
+ const hasSupportedOperationZodConfig = !!zod && (zod.strict !== void 0 || zod.generate !== void 0 || zod.coerce !== void 0 || zod.preprocess !== void 0 || zod.params !== void 0 || zod.useBrandedTypes !== void 0);
1232
1251
  return [key, {
1233
1252
  ...rest,
1234
1253
  ...angular ? { angular: {
@@ -1238,7 +1257,7 @@ function normalizeOperationsAndTags(operationsOrTags, workspace, global) {
1238
1257
  ...angular.httpResource ? { httpResource: angular.httpResource } : {}
1239
1258
  } } : {},
1240
1259
  ...query ? { query: normalizeQueryOptions(query, workspace, global.query) } : {},
1241
- ...zod ? { zod: {
1260
+ ...hasSupportedOperationZodConfig && zod ? { zod: {
1242
1261
  strict: {
1243
1262
  param: zod.strict?.param ?? false,
1244
1263
  query: zod.strict?.query ?? false,
@@ -1268,12 +1287,7 @@ function normalizeOperationsAndTags(operationsOrTags, workspace, global) {
1268
1287
  ...zod.preprocess?.response ? { response: normalizeMutator(workspace, zod.preprocess.response) } : {}
1269
1288
  },
1270
1289
  ...zod.params ? { params: normalizeMutator(workspace, zod.params) } : {},
1271
- generateEachHttpStatus: zod.generateEachHttpStatus ?? false,
1272
- useBrandedTypes: zod.useBrandedTypes ?? false,
1273
- generateReusableSchemas: zod.generateReusableSchemas ?? false,
1274
- generateMeta: zod.generateMeta ?? false,
1275
- dateTimeOptions: zod.dateTimeOptions ?? { offset: true },
1276
- timeOptions: zod.timeOptions ?? {}
1290
+ useBrandedTypes: zod.useBrandedTypes ?? false
1277
1291
  } } : {},
1278
1292
  ...effect ? { effect: normalizeEffectOptions(effect) } : {},
1279
1293
  ...transformer ? { transformer: normalizePath(transformer, workspace) } : {},
@@ -1608,6 +1622,23 @@ const rewriteReusableSchemas = (entries) => {
1608
1622
  function buildMutatorImportStatement(mutator) {
1609
1623
  return `import ${mutator.default ? mutator.name : `{ ${mutator.name} }`} from '${mutator.path}';`;
1610
1624
  }
1625
+ const ROOT_DIR = ".";
1626
+ function getSchemaDir(schemaTagMap, name) {
1627
+ return schemaTagMap?.get(name) ?? ROOT_DIR;
1628
+ }
1629
+ function computeCrossDirImportPath(schemasPath, fromDir, toDir, fileName, importExt) {
1630
+ if (fromDir === toDir) return `./${fileName}${importExt}`;
1631
+ const fromPath = fromDir === ROOT_DIR ? schemasPath : path.join(schemasPath, fromDir);
1632
+ const toPath = toDir === ROOT_DIR ? schemasPath : path.join(schemasPath, toDir);
1633
+ const relDir = upath.relativeSafe(fromPath, toPath);
1634
+ return `${upath.joinSafe(relDir, fileName)}${importExt}`;
1635
+ }
1636
+ function adjustMutatorPathForDir(mutatorPath, tagDir) {
1637
+ if (tagDir === ROOT_DIR) return mutatorPath;
1638
+ if (mutatorPath.startsWith("./")) return `../${mutatorPath.slice(2)}`;
1639
+ if (mutatorPath.startsWith("../")) return `../${mutatorPath}`;
1640
+ return mutatorPath;
1641
+ }
1611
1642
  /**
1612
1643
  * Whole-word substring check for a resolved mutator alias inside generated
1613
1644
  * code. Plain `String.includes` would false-positive when the user names the
@@ -1677,7 +1708,7 @@ const isValidSchemaIdentifier = (name) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(name);
1677
1708
  * `resolveValue` producer surfaces aliases here today, so the integration
1678
1709
  * tests can't exercise it.
1679
1710
  */
1680
- function buildSiblingImports({ usedRefs, extraImports, entryName, componentNames, namingConvention, importExt }) {
1711
+ function buildSiblingImports({ usedRefs, extraImports, entryName, componentNames, namingConvention, importExt, schemaTagMap, currentDir, schemasPath }) {
1681
1712
  const importsByName = /* @__PURE__ */ new Map();
1682
1713
  for (const name of usedRefs) {
1683
1714
  if (name === entryName) continue;
@@ -1689,7 +1720,7 @@ function buildSiblingImports({ usedRefs, extraImports, entryName, componentNames
1689
1720
  }
1690
1721
  return [...importsByName.values()].toSorted((a, b) => a.name.localeCompare(b.name)).map(({ name, alias }) => {
1691
1722
  const importedFile = conventionName(name, namingConvention);
1692
- return `import { ${alias ? `${name} as ${alias}` : name} } from './${importedFile}${importExt}';`;
1723
+ return `import { ${alias ? `${name} as ${alias}` : name} } from '${schemaTagMap && currentDir && schemasPath ? computeCrossDirImportPath(schemasPath, currentDir, getSchemaDir(schemaTagMap, name), importedFile, importExt) : `./${importedFile}${importExt}`}';`;
1693
1724
  }).join("\n");
1694
1725
  }
1695
1726
  const isPrimitiveSchemaName = (name) => [
@@ -1732,11 +1763,34 @@ async function writeZodSchemaIndex(schemasPath, fileExtension, header, schemaNam
1732
1763
  const uniqueExports = [...new Set(allExports.split("\n"))].filter((line) => line.trim()).toSorted().join("\n");
1733
1764
  await fs.outputFile(indexPath, `${header}\n${uniqueExports}\n`);
1734
1765
  }
1766
+ async function writeZodSchemaTagsSplitBarrel(schemasPath, fileExtension, header, componentDirs, verbDirs, namingConvention, tsconfig) {
1767
+ const importExt = getImportExtension(fileExtension, tsconfig);
1768
+ const indexImportExt = getImportExtension(".ts", tsconfig);
1769
+ const allDirs = /* @__PURE__ */ new Map();
1770
+ for (const [dir, names] of componentDirs) allDirs.set(dir, [...names]);
1771
+ for (const [dir, names] of verbDirs) if (allDirs.has(dir)) allDirs.get(dir).push(...names);
1772
+ else allDirs.set(dir, [...names]);
1773
+ for (const [dir, schemaNames] of allDirs) {
1774
+ if (dir === ROOT_DIR) continue;
1775
+ await writeZodSchemaIndex(path.join(schemasPath, dir), fileExtension, header, schemaNames, namingConvention, false, tsconfig);
1776
+ }
1777
+ const rootSchemas = allDirs.get(ROOT_DIR) ?? [];
1778
+ const rootExports = [...new Set(rootSchemas)].map((name) => {
1779
+ return `export * from './${conventionName(name, namingConvention)}${importExt}';`;
1780
+ }).toSorted();
1781
+ const tagExports = [...allDirs.keys()].filter((dir) => dir !== ROOT_DIR).toSorted((a, b) => a.localeCompare(b, "en", { numeric: true })).map((dir) => {
1782
+ return `export * from '${indexImportExt ? `./${dir}/index${indexImportExt}` : `./${dir}`}';`;
1783
+ });
1784
+ const allExports = [...rootExports, ...tagExports];
1785
+ const rootIndexPath = path.join(schemasPath, "index.ts");
1786
+ const content = `${header}\n${allExports.join("\n")}\n`;
1787
+ await fs.outputFile(rootIndexPath, content);
1788
+ }
1735
1789
  function generateZodSchemasInline(builder, output, includeZodImport = true, paramsMutator, includeParamsImport = false) {
1736
1790
  if (output.override.zod.generateReusableSchemas === true) return generateZodSchemasInlineReusable(builder, output, includeZodImport, paramsMutator, includeParamsImport);
1737
1791
  const schemasWithOpenApiDef = builder.schemas.filter((s) => s.schema);
1738
1792
  if (schemasWithOpenApiDef.length === 0) return "";
1739
- const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1793
+ const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
1740
1794
  const strict = output.override.zod.strict.body;
1741
1795
  const coerce = output.override.zod.coerce.body;
1742
1796
  const schemas = [];
@@ -1762,7 +1816,7 @@ function generateZodSchemasInline(builder, output, includeZodImport = true, para
1762
1816
  return generateZodSchemaFileContent("", schemas, includeZodImport);
1763
1817
  }
1764
1818
  function generateZodSchemasInlineReusable(builder, output, includeZodImport = true, paramsMutator, includeParamsImport = false) {
1765
- const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1819
+ const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
1766
1820
  const strict = output.override.zod.strict.body;
1767
1821
  const coerce = output.override.zod.coerce.body;
1768
1822
  const context = {
@@ -1786,21 +1840,20 @@ function generateZodSchemasInlineReusable(builder, output, includeZodImport = tr
1786
1840
  const paramsImport = paramsMutator && includeParamsImport && bodyReferencesMutator(body, paramsMutator) ? `${buildMutatorImportStatement(paramsMutator)}\n` : "";
1787
1841
  return `${zodImport || paramsImport ? `${zodImport}${paramsImport}\n` : ""}${body}\n`;
1788
1842
  }
1789
- async function writeZodSchemas(builder, schemasPath, fileExtension, header, output, paramsMutator) {
1790
- if (output.override.zod.generateReusableSchemas) {
1791
- await writeZodSchemasReusable(builder, schemasPath, fileExtension, header, output, paramsMutator);
1792
- return;
1793
- }
1843
+ async function writeZodSchemas(builder, schemasPath, fileExtension, header, output, paramsMutator, schemaTagMap) {
1844
+ if (output.override.zod.generateReusableSchemas) return writeZodSchemasReusable(builder, schemasPath, fileExtension, header, output, paramsMutator, schemaTagMap);
1845
+ const isSplit = !!schemaTagMap;
1794
1846
  const schemasWithOpenApiDef = builder.schemas.filter((s) => s.schema);
1795
1847
  const schemasToWrite = [];
1796
- const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1848
+ const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
1797
1849
  const strict = output.override.zod.strict.body;
1798
1850
  const coerce = output.override.zod.coerce.body;
1799
1851
  for (const generatorSchema of schemasWithOpenApiDef) {
1800
1852
  const { name, schema: schemaObject } = generatorSchema;
1801
1853
  if (!schemaObject) continue;
1802
1854
  const fileName = conventionName(name, output.namingConvention);
1803
- const filePath = path.join(schemasPath, `${fileName}${fileExtension}`);
1855
+ const tagDir = getSchemaDir(schemaTagMap, name);
1856
+ const filePath = isSplit ? path.join(schemasPath, tagDir, `${fileName}${fileExtension}`) : path.join(schemasPath, `${fileName}${fileExtension}`);
1804
1857
  const context = {
1805
1858
  spec: builder.spec,
1806
1859
  target: builder.target,
@@ -1823,10 +1876,22 @@ async function writeZodSchemas(builder, schemasPath, fileExtension, header, outp
1823
1876
  const fileContent = generateZodSchemaFileContent(header, schemaGroup);
1824
1877
  await fs.outputFile(schemaGroup[0].filePath, fileContent);
1825
1878
  }
1826
- if (output.indexFiles) await writeZodSchemaIndex(schemasPath, fileExtension, header, groupedSchemasToWrite.map((schemaGroup) => schemaGroup[0].schemaName), output.namingConvention, false, output.tsconfig);
1879
+ const writtenSchemaNames = groupedSchemasToWrite.map((schemaGroup) => schemaGroup[0].schemaName);
1880
+ if (output.indexFiles && !isSplit) await writeZodSchemaIndex(schemasPath, fileExtension, header, writtenSchemaNames, output.namingConvention, false, output.tsconfig);
1881
+ if (isSplit) {
1882
+ const dirSchemas = /* @__PURE__ */ new Map();
1883
+ for (const name of writtenSchemaNames) {
1884
+ const dir = getSchemaDir(schemaTagMap, name);
1885
+ if (!dirSchemas.has(dir)) dirSchemas.set(dir, []);
1886
+ dirSchemas.get(dir).push(name);
1887
+ }
1888
+ return dirSchemas;
1889
+ }
1890
+ return new Map([[ROOT_DIR, writtenSchemaNames]]);
1827
1891
  }
1828
- async function writeZodSchemasReusable(builder, schemasPath, fileExtension, header, output, paramsMutator) {
1829
- const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1892
+ async function writeZodSchemasReusable(builder, schemasPath, fileExtension, header, output, paramsMutator, schemaTagMap) {
1893
+ const isSplit = !!schemaTagMap;
1894
+ const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
1830
1895
  const strict = output.override.zod.strict.body;
1831
1896
  const coerce = output.override.zod.coerce.body;
1832
1897
  const context = {
@@ -1846,10 +1911,10 @@ async function writeZodSchemasReusable(builder, schemasPath, fileExtension, head
1846
1911
  paramsMutator
1847
1912
  }));
1848
1913
  const componentNames = new Set(Object.keys(builder.spec.components?.schemas ?? {}).map((schemaName) => resolveSchemaName(`#/components/schemas/${schemaName}`, context)));
1849
- const paramsMutatorImport = paramsMutator ? buildMutatorImportStatement(paramsMutator) : void 0;
1850
1914
  for (const entry of rewritten) {
1851
1915
  const fileName = conventionName(entry.name, output.namingConvention);
1852
- const filePath = path.join(schemasPath, `${fileName}${fileExtension}`);
1916
+ const tagDir = getSchemaDir(schemaTagMap, entry.name);
1917
+ const filePath = isSplit ? path.join(schemasPath, tagDir, `${fileName}${fileExtension}`) : path.join(schemasPath, `${fileName}${fileExtension}`);
1853
1918
  const importExt = getImportExtension(fileExtension, output.tsconfig);
1854
1919
  const rendered = renderReusableSchemaEntry(entry, context);
1855
1920
  const refImports = buildSiblingImports({
@@ -1858,19 +1923,39 @@ async function writeZodSchemasReusable(builder, schemasPath, fileExtension, head
1858
1923
  entryName: entry.name,
1859
1924
  componentNames,
1860
1925
  namingConvention: output.namingConvention,
1861
- importExt
1926
+ importExt,
1927
+ ...isSplit ? {
1928
+ schemaTagMap,
1929
+ currentDir: tagDir,
1930
+ schemasPath
1931
+ } : {}
1862
1932
  });
1863
- const imports = [...!!paramsMutator && bodyReferencesMutator(entry.zod, paramsMutator) && paramsMutatorImport ? [paramsMutatorImport] : [], ...refImports ? [refImports] : []].join("\n");
1933
+ const mutatorImportStr = !!paramsMutator && bodyReferencesMutator(entry.zod, paramsMutator) ? buildMutatorImportStatement({
1934
+ ...paramsMutator,
1935
+ path: isSplit ? adjustMutatorPathForDir(paramsMutator.path, tagDir) : paramsMutator.path
1936
+ }) : void 0;
1937
+ const imports = [...mutatorImportStr ? [mutatorImportStr] : [], ...refImports ? [refImports] : []].join("\n");
1864
1938
  const fileContent = `${header}import { z as zod } from 'zod';\n` + (imports ? `${imports}\n\n` : "\n") + `${rendered.content}\n`;
1865
1939
  await fs.outputFile(filePath, fileContent);
1866
1940
  }
1867
- if (output.indexFiles && rewritten.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, rewritten.map((e) => e.name), output.namingConvention, true, output.tsconfig);
1941
+ if (output.indexFiles && !isSplit && rewritten.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, rewritten.map((e) => e.name), output.namingConvention, true, output.tsconfig);
1942
+ if (isSplit) {
1943
+ const dirSchemas = /* @__PURE__ */ new Map();
1944
+ for (const entry of rewritten) {
1945
+ const dir = getSchemaDir(schemaTagMap, entry.name);
1946
+ if (!dirSchemas.has(dir)) dirSchemas.set(dir, []);
1947
+ dirSchemas.get(dir).push(entry.name);
1948
+ }
1949
+ return dirSchemas;
1950
+ }
1951
+ return new Map([[ROOT_DIR, rewritten.map((e) => e.name)]]);
1868
1952
  }
1869
- async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension, header, output, context) {
1953
+ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension, header, output, context, schemaTagMap) {
1954
+ const isSplit = !!schemaTagMap;
1870
1955
  const zodContext = context;
1871
1956
  const verbOptionsArray = Object.values(verbOptions);
1872
- if (verbOptionsArray.length === 0) return;
1873
- const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1957
+ if (verbOptionsArray.length === 0) return /* @__PURE__ */ new Map();
1958
+ const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
1874
1959
  const strict = output.override.zod.strict.body;
1875
1960
  const coerce = output.override.zod.coerce.body;
1876
1961
  const useReusableSchemas = output.override.zod.generateReusableSchemas === true;
@@ -1932,14 +2017,18 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1932
2017
  ...queryParamsSchemas,
1933
2018
  ...headerParamsSchemas,
1934
2019
  ...responseSchemas
1935
- ]);
2020
+ ]).map((s) => ({
2021
+ ...s,
2022
+ verbTagDir: isSplit ? kebab(verbOption.tags?.[0] ?? DefaultTag) : ROOT_DIR
2023
+ }));
1936
2024
  }));
1937
2025
  const schemasToWrite = [];
1938
2026
  for (const entry of uniqueVerbsSchemas) {
1939
2027
  if (useReusableSchemas && entry.schema && typeof entry.schema.$ref === "string" && Object.keys(entry.schema).length === 1) continue;
1940
2028
  const { name, schema } = entry;
1941
2029
  const fileName = conventionName(name, output.namingConvention);
1942
- const filePath = path.join(schemasPath, `${fileName}${fileExtension}`);
2030
+ const tagDir = entry.verbTagDir ?? ROOT_DIR;
2031
+ const filePath = isSplit ? path.join(schemasPath, tagDir, `${fileName}${fileExtension}`) : path.join(schemasPath, `${fileName}${fileExtension}`);
1943
2032
  const parsedZodDefinition = parseZodValidationSchemaDefinition("bodyContentType" in entry && entry.bodyContentType === "multipart/form-data" ? generateFormDataZodSchema(schema, zodContext, name, strict, isZodV4, "encoding" in entry ? entry.encoding : void 0, useReusableSchemas) : generateZodValidationSchemaDefinition(schema, zodContext, name, strict, isZodV4, {
1944
2033
  required: true,
1945
2034
  useReusableSchemas
@@ -1950,7 +2039,8 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1950
2039
  zodExpression = rewriteSentinelsToDirect(zodExpression);
1951
2040
  const importExt = getImportExtension(fileExtension, output.tsconfig);
1952
2041
  importStatements = [...parsedZodDefinition.usedRefs].filter((refName) => refName !== name).toSorted().map((refName) => {
1953
- return `import { ${refName} } from './${conventionName(refName, output.namingConvention)}${importExt}';`;
2042
+ const importedFile = conventionName(refName, output.namingConvention);
2043
+ return `import { ${refName} } from '${isSplit ? computeCrossDirImportPath(schemasPath, tagDir, getSchemaDir(schemaTagMap, refName), importedFile, importExt) : `./${importedFile}${importExt}`}';`;
1954
2044
  });
1955
2045
  }
1956
2046
  schemasToWrite.push({
@@ -1966,7 +2056,19 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1966
2056
  const fileContent = generateZodSchemaFileContent(header, schemaGroup);
1967
2057
  await fs.outputFile(schemaGroup[0].filePath, fileContent);
1968
2058
  }
1969
- if (output.indexFiles && uniqueVerbsSchemas.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, groupedSchemasToWrite.map((schemaGroup) => schemaGroup[0].schemaName), output.namingConvention, true, output.tsconfig);
2059
+ const writtenSchemaNames = groupedSchemasToWrite.map((schemaGroup) => schemaGroup[0].schemaName);
2060
+ if (output.indexFiles && !isSplit && uniqueVerbsSchemas.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, writtenSchemaNames, output.namingConvention, true, output.tsconfig);
2061
+ if (isSplit) {
2062
+ const dirSchemas = /* @__PURE__ */ new Map();
2063
+ for (const entry of uniqueVerbsSchemas) {
2064
+ if (useReusableSchemas && entry.schema && typeof entry.schema.$ref === "string" && Object.keys(entry.schema).length === 1) continue;
2065
+ const dir = entry.verbTagDir ?? ROOT_DIR;
2066
+ if (!dirSchemas.has(dir)) dirSchemas.set(dir, []);
2067
+ dirSchemas.get(dir).push(entry.name);
2068
+ }
2069
+ return dirSchemas;
2070
+ }
2071
+ return new Map([[ROOT_DIR, writtenSchemaNames]]);
1970
2072
  }
1971
2073
  //#endregion
1972
2074
  //#region src/write-specs.ts
@@ -2031,7 +2133,7 @@ async function addOperationSchemasReExport(schemaPath, operationSchemasPath, hea
2031
2133
  * file path so callers can include it in formatter / hook runs, or
2032
2134
  * `undefined` if no file was written.
2033
2135
  */
2034
- async function writeFakerSchemaMocks(builder, options, header) {
2136
+ async function writeFakerSchemaMocks(builder, options, header, schemaTagMap) {
2035
2137
  const { output } = options;
2036
2138
  const fakerEntry = output.mock.generators.find((g) => !isFunction(g) && g.type === OutputMockType.FAKER && g.schemas === true);
2037
2139
  if (!fakerEntry) return;
@@ -2062,9 +2164,32 @@ async function writeFakerSchemaMocks(builder, options, header) {
2062
2164
  filePath = path.join(dir, `schemas.faker${fileExtension}`);
2063
2165
  schemaImportPath = targetInfo ? `./${targetInfo.filename}${getImportExtension(fileExtension, output.tsconfig)}` : void 0;
2064
2166
  }
2065
- const reroutedImports = imports.map((imp) => imp.importPath ? imp : {
2066
- ...imp,
2067
- importPath: schemaImportPath
2167
+ const isZodSchemaOutput = isObject(output.schemas) && output.schemas.type === "zod";
2168
+ const importExtension = getImportExtension(fileExtension, output.tsconfig);
2169
+ const schemaSuffix = isZodSchemaOutput ? ".zod" : "";
2170
+ const perSchemaImportPath = /* @__PURE__ */ new Map();
2171
+ if (schemaImportPath === "." && !output.indexFiles && isObject(output.schemas)) for (const schema of builder.schemas) {
2172
+ const tsName = pascal(schema.name);
2173
+ const fileName = conventionName(schema.name, output.namingConvention);
2174
+ const tagDir = schemaTagMap?.get(schema.name);
2175
+ const tagSegment = tagDir && tagDir !== "." ? `${tagDir}/` : "";
2176
+ perSchemaImportPath.set(tsName, `./${tagSegment}${fileName}${schemaSuffix}${importExtension}`);
2177
+ }
2178
+ const reroutedImports = imports.map((imp) => {
2179
+ if (imp.importPath) return imp;
2180
+ if (imp.schemaFactory) return {
2181
+ ...imp,
2182
+ importPath: "."
2183
+ };
2184
+ const resolved = perSchemaImportPath.get(imp.name);
2185
+ if (resolved) return {
2186
+ ...imp,
2187
+ importPath: resolved
2188
+ };
2189
+ return {
2190
+ ...imp,
2191
+ importPath: schemaImportPath
2192
+ };
2068
2193
  });
2069
2194
  const grouped = /* @__PURE__ */ new Map();
2070
2195
  for (const imp of reroutedImports) {
@@ -2101,28 +2226,62 @@ function shouldGenerateSchemas(output, hasOperations) {
2101
2226
  async function writeSpecs(builder, workspace, options, projectName) {
2102
2227
  const { info, schemas, target } = builder;
2103
2228
  const { output } = options;
2229
+ const shouldSplitSchemasByTags = isObject(output.schemas) && output.schemas.splitByTags;
2230
+ const schemaTagMap = shouldSplitSchemasByTags ? buildSchemaTagMap(Object.values(builder.operations).map((op) => ({
2231
+ imports: op.imports,
2232
+ tags: op.tags
2233
+ })), schemas) : void 0;
2104
2234
  const projectTitle = projectName ?? info.title;
2105
2235
  const header = getHeader(output.override.header, info);
2106
2236
  if (output.schemas) {
2107
2237
  const schemasPath = isString(output.schemas) ? output.schemas : output.schemas.path;
2108
- if (!isString(output.schemas) && output.schemas.type === "zod" || isString(output.schemas) && output.client === "zod" && output.override.zod.generateReusableSchemas) {
2238
+ const isZodSchemas = !isString(output.schemas) && output.schemas.type === "zod" || isString(output.schemas) && output.client === "zod" && output.override.zod.generateReusableSchemas;
2239
+ if (shouldSplitSchemasByTags && output.operationSchemas) throw new Error("schemas.splitByTags cannot be used with output.operationSchemas. The tags-split schema mode handles operation type placement within tag directories.");
2240
+ if (isZodSchemas) {
2109
2241
  const fileExtension = output.schemaFileExtension;
2110
- await writeZodSchemas(builder, schemasPath, fileExtension, header, output, output.override.zod.params ? await generateMutator({
2242
+ const schemasParamsMutator = output.override.zod.params ? await generateMutator({
2111
2243
  output: path.join(schemasPath, `__params__${fileExtension}`),
2112
2244
  mutator: output.override.zod.params,
2113
2245
  name: "zodParams",
2114
2246
  workspace,
2115
2247
  tsconfig: output.tsconfig
2116
- }) : void 0);
2117
- await writeZodSchemasFromVerbs(builder.verbOptions, schemasPath, fileExtension, header, output, {
2118
- spec: builder.spec,
2119
- target: builder.target,
2120
- workspace,
2121
- output
2122
- });
2248
+ }) : void 0;
2249
+ if (shouldSplitSchemasByTags) {
2250
+ const componentDirs = await writeZodSchemas(builder, schemasPath, fileExtension, header, output, schemasParamsMutator, schemaTagMap);
2251
+ const verbDirs = await writeZodSchemasFromVerbs(builder.verbOptions, schemasPath, fileExtension, header, output, {
2252
+ spec: builder.spec,
2253
+ target: builder.target,
2254
+ workspace,
2255
+ output
2256
+ }, schemaTagMap);
2257
+ if (output.indexFiles) await writeZodSchemaTagsSplitBarrel(schemasPath, fileExtension, header, componentDirs, verbDirs, output.namingConvention, output.tsconfig);
2258
+ } else {
2259
+ await writeZodSchemas(builder, schemasPath, fileExtension, header, output, schemasParamsMutator);
2260
+ await writeZodSchemasFromVerbs(builder.verbOptions, schemasPath, fileExtension, header, output, {
2261
+ spec: builder.spec,
2262
+ target: builder.target,
2263
+ workspace,
2264
+ output
2265
+ });
2266
+ }
2123
2267
  } else {
2124
2268
  const fileExtension = output.fileExtension || ".ts";
2125
- if (output.operationSchemas) {
2269
+ if (shouldSplitSchemasByTags) await writeSchemasTagsSplit({
2270
+ schemaPath: schemasPath,
2271
+ schemas,
2272
+ target,
2273
+ namingConvention: output.namingConvention,
2274
+ fileExtension,
2275
+ header,
2276
+ indexFiles: output.indexFiles,
2277
+ tsconfig: output.tsconfig,
2278
+ factoryOutputDirectory: output.factoryMethods?.outputDirectory,
2279
+ operations: Object.values(builder.operations).map((op) => ({
2280
+ imports: op.imports,
2281
+ tags: op.tags
2282
+ }))
2283
+ });
2284
+ else if (output.operationSchemas) {
2126
2285
  const { regularSchemas, operationSchemas: opSchemas } = splitSchemasByType(schemas);
2127
2286
  const regularSchemaNames = new Set(regularSchemas.map((s) => s.name));
2128
2287
  const operationSchemaNames = new Set(opSchemas.map((s) => s.name));
@@ -2166,7 +2325,7 @@ async function writeSpecs(builder, workspace, options, projectName) {
2166
2325
  });
2167
2326
  }
2168
2327
  }
2169
- const fakerSchemaPath = await writeFakerSchemaMocks(builder, options, header);
2328
+ const fakerSchemaPath = await writeFakerSchemaMocks(builder, options, header, schemaTagMap);
2170
2329
  let implementationPaths = [];
2171
2330
  if (output.target) {
2172
2331
  const writeMode = getWriteMode(output.mode);
@@ -2189,6 +2348,7 @@ async function writeSpecs(builder, workspace, options, projectName) {
2189
2348
  projectName,
2190
2349
  header,
2191
2350
  needSchema: shouldGenerateSchemas(output, hasOperations),
2351
+ schemaTagMap,
2192
2352
  generateSchemasInline: needZodSchemasInline ? () => generateZodSchemasInline(builder, output, includeZodImport, inlineSchemasParamsMutator, includeParamsImport) : void 0
2193
2353
  });
2194
2354
  }
@@ -2352,4 +2512,4 @@ async function loadConfigFile(configFilePath) {
2352
2512
  //#endregion
2353
2513
  export { defineConfig as a, description as c, startWatcher as i, name as l, loadConfigFile as n, defineTransformer as o, generateSpec as r, normalizeOptions as s, findConfigFile as t, version as u };
2354
2514
 
2355
- //# sourceMappingURL=config-CXPetEiJ.mjs.map
2515
+ //# sourceMappingURL=config-D-TQRn-G.mjs.map