orval 8.18.0 → 8.20.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,6 @@
1
+ import { createRequire } from "node:module";
1
2
  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";
3
+ 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
4
  import { bundle } from "@scalar/json-magic/bundle";
4
5
  import { fetchUrls, parseJson, parseYaml, readFiles } from "@scalar/json-magic/bundle/plugins/node";
5
6
  import { upgrade, validate } from "@scalar/openapi-parser";
@@ -15,20 +16,20 @@ import mcp from "@orval/mcp";
15
16
  import query from "@orval/query";
16
17
  import solidStart from "@orval/solid-start";
17
18
  import swr from "@orval/swr";
18
- import zod, { dereference, generateFormDataZodSchema, generateZodValidationSchemaDefinition, isZodVersionV4, parseZodValidationSchemaDefinition } from "@orval/zod";
19
+ import zod, { assertZodTarget, dereference, generateFormDataZodSchema, generateZodValidationSchemaDefinition, getZodImportSource, getZodTypeName, parseZodValidationSchemaDefinition, resolveIsZodV4 } from "@orval/zod";
19
20
  import { ExecaError, execa } from "execa";
20
21
  import fs from "fs-extra";
21
22
  import fs$1, { access } from "node:fs/promises";
22
23
  import { styleText } from "node:util";
23
24
  import { parseArgsStringToArgv } from "string-argv";
25
+ import fs$2, { existsSync } from "node:fs";
24
26
  import { findUp, findUpMultiple } from "find-up";
25
27
  import yaml from "js-yaml";
26
28
  import { parseTsconfig } from "get-tsconfig";
27
- import fs$2 from "node:fs";
28
29
  import { createJiti } from "jiti";
29
30
  //#region package.json
30
31
  var name = "orval";
31
- var version = "8.18.0";
32
+ var version = "8.20.0";
32
33
  var description = "A swagger client generator for typescript";
33
34
  //#endregion
34
35
  //#region src/client.ts
@@ -77,21 +78,24 @@ const generateClientImports = ({ client, implementation, imports, projectName, h
77
78
  };
78
79
  const generateClientHeader = ({ outputClient = DEFAULT_CLIENT, isRequestOptions, isGlobalMutator, isMutator, provideIn, hasAwaitedType, titles, output, verbOptions, tag, isDefaultTagBucket, clientImplementation }) => {
79
80
  const { header } = getGeneratorClient(outputClient, output);
81
+ const rawHeader = 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
+ const normalizedHeader = typeof rawHeader === "string" ? { implementation: rawHeader } : rawHeader;
80
95
  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`
96
+ implementation: normalizedHeader.implementation,
97
+ implementationMock: `export const ${titles.implementationMock} = () => [\n`,
98
+ sharedTypes: normalizedHeader.sharedTypes
95
99
  };
96
100
  };
97
101
  const generateClientFooter = ({ outputClient, operationNames, hasMutator, hasAwaitedType, titles, output }) => {
@@ -888,7 +892,8 @@ function normalizeSchemasOption(schemas, workspace) {
888
892
  return {
889
893
  path: normalizePath(schemas.path, workspace),
890
894
  type: schemas.type ?? "typescript",
891
- importPath: schemas.importPath
895
+ importPath: schemas.importPath,
896
+ splitByTags: schemas.splitByTags ?? false
892
897
  };
893
898
  }
894
899
  /**
@@ -905,6 +910,29 @@ function validatePackageSpecifier(value, fieldName) {
905
910
  if (value.startsWith(".")) throw new Error(`\`${fieldName}\` must be a package specifier (e.g. '@acme/models'), not a relative path. Received: "${value}"`);
906
911
  if (path.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\")) throw new Error(`\`${fieldName}\` must be a package specifier (e.g. '@acme/models'), not an absolute path. Received: "${value}"`);
907
912
  }
913
+ function looksLikePackageSpecifier(value) {
914
+ return !!value && value.trim() === value && !value.startsWith(".") && !path.isAbsolute(value) && !/^[A-Za-z]:[\\/]/.test(value) && !value.startsWith("\\\\");
915
+ }
916
+ function resolvePackageSpecifier(workspace, value) {
917
+ try {
918
+ return createRequire(path.join(workspace, "package.json")).resolve(value);
919
+ } catch {
920
+ return;
921
+ }
922
+ }
923
+ function isPackageSpecifierCandidate(workspace, value) {
924
+ if (!looksLikePackageSpecifier(value)) return false;
925
+ if (existsSync(path.resolve(workspace, value))) return false;
926
+ if (value.startsWith("@")) return true;
927
+ const [packageName] = value.split("/");
928
+ if (!value.includes("/")) return true;
929
+ for (let dir = workspace;;) {
930
+ if (existsSync(path.join(dir, "node_modules", packageName))) return true;
931
+ const parent = path.dirname(dir);
932
+ if (parent === dir) return false;
933
+ dir = parent;
934
+ }
935
+ }
908
936
  function normalizeEffectOptions(effect) {
909
937
  return {
910
938
  strict: {
@@ -1017,6 +1045,8 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
1017
1045
  baseUrl: outputOptions.baseUrl,
1018
1046
  unionAddMissingProperties: outputOptions.unionAddMissingProperties ?? false,
1019
1047
  factoryMethods,
1048
+ tagsSplitDeduplication: outputOptions.tagsSplitDeduplication ?? false,
1049
+ commonTypesFileName: outputOptions.commonTypesFileName ?? "common-types",
1020
1050
  override: {
1021
1051
  ...outputOptions.override,
1022
1052
  mock: {
@@ -1027,8 +1057,8 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
1027
1057
  fractionDigits: outputOptions.override?.mock?.fractionDigits ?? 2,
1028
1058
  ...outputOptions.override?.mock
1029
1059
  },
1030
- operations: normalizeOperationsAndTags(outputOptions.override?.operations ?? {}, outputWorkspace, { query: globalQueryOptions }),
1031
- tags: normalizeOperationsAndTags(outputOptions.override?.tags ?? {}, outputWorkspace, { query: globalQueryOptions }),
1060
+ operations: normalizeOperationsAndTags(outputOptions.override?.operations ?? {}, outputWorkspace, { query: globalQueryOptions }, "operations"),
1061
+ tags: normalizeOperationsAndTags(outputOptions.override?.tags ?? {}, outputWorkspace, { query: globalQueryOptions }, "tags"),
1032
1062
  mutator: normalizeMutator(outputWorkspace, outputOptions.override?.mutator),
1033
1063
  formData: createFormData(outputWorkspace, outputOptions.override?.formData),
1034
1064
  formUrlEncoded: (isBoolean(outputOptions.override?.formUrlEncoded) ? outputOptions.override.formUrlEncoded : normalizeMutator(outputWorkspace, outputOptions.override?.formUrlEncoded)) ?? true,
@@ -1090,6 +1120,8 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
1090
1120
  ...outputOptions.override?.zod?.preprocess?.response ? { response: normalizeMutator(outputWorkspace, outputOptions.override.zod.preprocess.response) } : {}
1091
1121
  },
1092
1122
  ...outputOptions.override?.zod?.params ? { params: normalizeMutator(outputWorkspace, outputOptions.override.zod.params) } : {},
1123
+ variant: outputOptions.override?.zod?.variant ?? "classic",
1124
+ version: outputOptions.override?.zod?.version ?? "auto",
1093
1125
  generateEachHttpStatus: outputOptions.override?.zod?.generateEachHttpStatus ?? false,
1094
1126
  useBrandedTypes: outputOptions.override?.zod?.useBrandedTypes ?? false,
1095
1127
  generateReusableSchemas: outputOptions.override?.zod?.generateReusableSchemas ?? false,
@@ -1113,6 +1145,7 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
1113
1145
  forceSuccessResponse: outputOptions.override?.fetch?.forceSuccessResponse ?? false,
1114
1146
  runtimeValidation: outputOptions.override?.fetch?.runtimeValidation ?? false,
1115
1147
  useRuntimeFetcher: outputOptions.override?.fetch?.useRuntimeFetcher ?? false,
1148
+ ...outputOptions.override?.fetch?.arrayFormat ? { arrayFormat: outputOptions.override.fetch.arrayFormat } : {},
1116
1149
  ...outputOptions.override?.fetch,
1117
1150
  ...outputOptions.override?.fetch?.jsonReviver ? { jsonReviver: normalizeMutator(outputWorkspace, outputOptions.override.fetch.jsonReviver) } : {}
1118
1151
  },
@@ -1153,8 +1186,10 @@ function normalizeMutator(workspace, mutator) {
1153
1186
  if (isObject(mutator)) {
1154
1187
  const m = mutator;
1155
1188
  if (!m.path) throw new Error(styleText("red", `Mutator requires a path.`));
1189
+ const resolvedPath = looksLikePackageSpecifier(m.path) ? resolvePackageSpecifier(workspace, m.path) : void 0;
1156
1190
  return {
1157
- path: path.resolve(workspace, m.path),
1191
+ path: !!resolvedPath || isPackageSpecifierCandidate(workspace, m.path) ? m.path : path.resolve(workspace, m.path),
1192
+ ...resolvedPath ? { resolvedPath } : {},
1158
1193
  name: m.name,
1159
1194
  default: m.default ?? !m.name,
1160
1195
  alias: m.alias,
@@ -1162,10 +1197,14 @@ function normalizeMutator(workspace, mutator) {
1162
1197
  extension: m.extension
1163
1198
  };
1164
1199
  }
1165
- if (isString(mutator)) return {
1166
- path: path.resolve(workspace, mutator),
1167
- default: true
1168
- };
1200
+ if (isString(mutator)) {
1201
+ const resolvedPath = looksLikePackageSpecifier(mutator) ? resolvePackageSpecifier(workspace, mutator) : void 0;
1202
+ return {
1203
+ path: !!resolvedPath || isPackageSpecifierCandidate(workspace, mutator) ? mutator : path.resolve(workspace, mutator),
1204
+ ...resolvedPath ? { resolvedPath } : {},
1205
+ default: true
1206
+ };
1207
+ }
1169
1208
  }
1170
1209
  async function resolveFirstValidTarget(targets, workspace, parserOptions) {
1171
1210
  for (const target of targets) {
@@ -1227,8 +1266,20 @@ function normalizePath(path$1, workspace) {
1227
1266
  if (!isString(path$1)) return path$1;
1228
1267
  return path.resolve(workspace, path$1);
1229
1268
  }
1230
- function normalizeOperationsAndTags(operationsOrTags, workspace, global) {
1269
+ function normalizeOperationsAndTags(operationsOrTags, workspace, global, source) {
1270
+ const unsupportedZodKeys = [
1271
+ "version",
1272
+ "variant",
1273
+ "dateTimeOptions",
1274
+ "timeOptions",
1275
+ "generateEachHttpStatus",
1276
+ "generateReusableSchemas",
1277
+ "generateMeta"
1278
+ ];
1231
1279
  return Object.fromEntries(Object.entries(operationsOrTags).map(([key, { transformer, mutator, formData, formUrlEncoded, paramsSerializer, paramsFilter, query, angular, zod, effect, ...rest }]) => {
1280
+ const unsupportedOperationZodKeys = zod && unsupportedZodKeys.filter((unsupportedKey) => zod[unsupportedKey] !== void 0);
1281
+ 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(", ")}.`);
1282
+ 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
1283
  return [key, {
1233
1284
  ...rest,
1234
1285
  ...angular ? { angular: {
@@ -1238,7 +1289,7 @@ function normalizeOperationsAndTags(operationsOrTags, workspace, global) {
1238
1289
  ...angular.httpResource ? { httpResource: angular.httpResource } : {}
1239
1290
  } } : {},
1240
1291
  ...query ? { query: normalizeQueryOptions(query, workspace, global.query) } : {},
1241
- ...zod ? { zod: {
1292
+ ...hasSupportedOperationZodConfig && zod ? { zod: {
1242
1293
  strict: {
1243
1294
  param: zod.strict?.param ?? false,
1244
1295
  query: zod.strict?.query ?? false,
@@ -1268,12 +1319,7 @@ function normalizeOperationsAndTags(operationsOrTags, workspace, global) {
1268
1319
  ...zod.preprocess?.response ? { response: normalizeMutator(workspace, zod.preprocess.response) } : {}
1269
1320
  },
1270
1321
  ...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 ?? {}
1322
+ useBrandedTypes: zod.useBrandedTypes ?? false
1277
1323
  } } : {},
1278
1324
  ...effect ? { effect: normalizeEffectOptions(effect) } : {},
1279
1325
  ...transformer ? { transformer: normalizePath(transformer, workspace) } : {},
@@ -1480,13 +1526,14 @@ const generateReusableSchemaSet = (refs, context, options) => {
1480
1526
  operationId: "",
1481
1527
  location: "schema",
1482
1528
  schemaName: name
1483
- } : void 0);
1529
+ } : void 0, options.variant);
1484
1530
  entries.push({
1485
1531
  ref,
1486
1532
  name,
1487
1533
  zod: parsed.zod,
1488
1534
  consts: parsed.consts,
1489
- usedRefs: parsed.usedRefs
1535
+ usedRefs: parsed.usedRefs,
1536
+ variant: options.variant
1490
1537
  });
1491
1538
  for (const usedName of parsed.usedRefs) {
1492
1539
  const usedRef = nameToRef.get(usedName);
@@ -1582,7 +1629,7 @@ const rewriteReusableSchemas = (entries) => {
1582
1629
  else if (lazyEdges.has(edgeKey(scc[0], scc[0]))) recursiveNames.add(scc[0]);
1583
1630
  const rewritten = new Map(entries.map((entry) => {
1584
1631
  const newZod = entry.zod.replaceAll(SENTINEL_PATTERN, (_match, refName) => {
1585
- return lazyEdges.has(edgeKey(entry.name, refName)) ? `zod.lazy(() => ${refName})` : refName;
1632
+ return lazyEdges.has(edgeKey(entry.name, refName)) ? `${entry.variant === "mini" ? "/*#__PURE__*/ " : ""}zod.lazy(() => ${refName})` : refName;
1586
1633
  });
1587
1634
  return [entry.name, {
1588
1635
  ...entry,
@@ -1599,6 +1646,7 @@ const rewriteReusableSchemas = (entries) => {
1599
1646
  };
1600
1647
  //#endregion
1601
1648
  //#region src/write-zod-specs.ts
1649
+ const getZodSchemaImportStatement = (variant) => variant === "mini" ? `import * as zod from '${getZodImportSource(variant)}';` : `import { z as zod } from '${getZodImportSource(variant)}';`;
1602
1650
  /**
1603
1651
  * Render the `import { ... } from '...'` line for a resolved
1604
1652
  * `GeneratorMutator`. Mirrors the format produced by
@@ -1608,6 +1656,23 @@ const rewriteReusableSchemas = (entries) => {
1608
1656
  function buildMutatorImportStatement(mutator) {
1609
1657
  return `import ${mutator.default ? mutator.name : `{ ${mutator.name} }`} from '${mutator.path}';`;
1610
1658
  }
1659
+ const ROOT_DIR = ".";
1660
+ function getSchemaDir(schemaTagMap, name) {
1661
+ return schemaTagMap?.get(name) ?? ROOT_DIR;
1662
+ }
1663
+ function computeCrossDirImportPath(schemasPath, fromDir, toDir, fileName, importExt) {
1664
+ if (fromDir === toDir) return `./${fileName}${importExt}`;
1665
+ const fromPath = fromDir === ROOT_DIR ? schemasPath : path.join(schemasPath, fromDir);
1666
+ const toPath = toDir === ROOT_DIR ? schemasPath : path.join(schemasPath, toDir);
1667
+ const relDir = upath.relativeSafe(fromPath, toPath);
1668
+ return `${upath.joinSafe(relDir, fileName)}${importExt}`;
1669
+ }
1670
+ function adjustMutatorPathForDir(mutatorPath, tagDir) {
1671
+ if (tagDir === ROOT_DIR) return mutatorPath;
1672
+ if (mutatorPath.startsWith("./")) return `../${mutatorPath.slice(2)}`;
1673
+ if (mutatorPath.startsWith("../")) return `../${mutatorPath}`;
1674
+ return mutatorPath;
1675
+ }
1611
1676
  /**
1612
1677
  * Whole-word substring check for a resolved mutator alias inside generated
1613
1678
  * code. Plain `String.includes` would false-positive when the user names the
@@ -1616,9 +1681,9 @@ function buildMutatorImportStatement(mutator) {
1616
1681
  function bodyReferencesMutator(body, mutator) {
1617
1682
  return new RegExp(String.raw`\b${mutator.name}\b`).test(body);
1618
1683
  }
1619
- function generateZodSchemaFileContent(header, schemas, includeZodImport = true) {
1684
+ function generateZodSchemaFileContent(header, schemas, zodVariant, includeZodImport = true) {
1620
1685
  const refImports = [...new Set(schemas.flatMap((s) => s.importStatements ?? []))].toSorted();
1621
- const importBlock = [...includeZodImport ? [`import { z as zod } from 'zod';`] : [], ...refImports].join("\n");
1686
+ const importBlock = [...includeZodImport ? [getZodSchemaImportStatement(zodVariant)] : [], ...refImports].join("\n");
1622
1687
  const schemaContent = schemas.map(({ schemaName, consts, zodExpression }) => {
1623
1688
  return `${consts ? `${consts}\n` : ""}export const ${schemaName} = ${zodExpression}
1624
1689
 
@@ -1627,7 +1692,7 @@ export type ${schemaName}Output = zod.output<typeof ${schemaName}>;`;
1627
1692
  }).join("\n\n");
1628
1693
  return `${header}${importBlock ? `${importBlock}\n\n` : ""}${schemaContent}\n`;
1629
1694
  }
1630
- function renderReusableSchemaEntry(entry, context) {
1695
+ function renderReusableSchemaEntry(entry, context, zodVariant) {
1631
1696
  const consts = entry.consts ? `${entry.consts}\n\n` : "";
1632
1697
  if (entry.isRecursive) {
1633
1698
  const rawName = isComponentRef(entry.ref) ? getRefInfo(entry.ref, context).originalName : void 0;
@@ -1638,10 +1703,18 @@ function renderReusableSchemaEntry(entry, context) {
1638
1703
  context
1639
1704
  }) : void 0;
1640
1705
  const typeBody = resolved ? resolved.value : "unknown";
1706
+ const seenSubModels = /* @__PURE__ */ new Set();
1707
+ const subModels = (resolved?.schemas ?? []).filter((s) => {
1708
+ if (seenSubModels.has(s.name)) return false;
1709
+ seenSubModels.add(s.name);
1710
+ return true;
1711
+ });
1712
+ const subModelBlock = subModels.length ? `${subModels.map((s) => s.model.trimEnd()).join("\n")}\n\n` : "";
1713
+ const localNames = new Set(subModels.map((s) => s.name));
1641
1714
  const seen = /* @__PURE__ */ new Set();
1642
1715
  const extraImports = [];
1643
1716
  for (const imp of resolved?.imports ?? []) {
1644
- if (!imp.name || imp.name === entry.name) continue;
1717
+ if (!imp.name || imp.name === entry.name || localNames.has(imp.name)) continue;
1645
1718
  const bindingKey = imp.alias ?? imp.name;
1646
1719
  if (seen.has(bindingKey)) continue;
1647
1720
  seen.add(bindingKey);
@@ -1651,7 +1724,7 @@ function renderReusableSchemaEntry(entry, context) {
1651
1724
  });
1652
1725
  }
1653
1726
  return {
1654
- content: `${consts}export type ${entry.name} = ${typeBody};\n\nexport const ${entry.name}: zod.ZodType<${entry.name}> = ${entry.zod};\n\nexport type ${entry.name}Output = zod.output<typeof ${entry.name}>;`,
1727
+ content: `${consts}${subModelBlock}export type ${entry.name} = ${typeBody};\n\nexport const ${entry.name}: zod.${getZodTypeName(zodVariant)}<${entry.name}> = ${entry.zod};\n\nexport type ${entry.name}Output = zod.output<typeof ${entry.name}>;`,
1655
1728
  extraImports
1656
1729
  };
1657
1730
  }
@@ -1677,7 +1750,7 @@ const isValidSchemaIdentifier = (name) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(name);
1677
1750
  * `resolveValue` producer surfaces aliases here today, so the integration
1678
1751
  * tests can't exercise it.
1679
1752
  */
1680
- function buildSiblingImports({ usedRefs, extraImports, entryName, componentNames, namingConvention, importExt }) {
1753
+ function buildSiblingImports({ usedRefs, extraImports, entryName, componentNames, namingConvention, importExt, schemaTagMap, currentDir, schemasPath }) {
1681
1754
  const importsByName = /* @__PURE__ */ new Map();
1682
1755
  for (const name of usedRefs) {
1683
1756
  if (name === entryName) continue;
@@ -1689,7 +1762,7 @@ function buildSiblingImports({ usedRefs, extraImports, entryName, componentNames
1689
1762
  }
1690
1763
  return [...importsByName.values()].toSorted((a, b) => a.name.localeCompare(b.name)).map(({ name, alias }) => {
1691
1764
  const importedFile = conventionName(name, namingConvention);
1692
- return `import { ${alias ? `${name} as ${alias}` : name} } from './${importedFile}${importExt}';`;
1765
+ return `import { ${alias ? `${name} as ${alias}` : name} } from '${schemaTagMap && currentDir && schemasPath ? computeCrossDirImportPath(schemasPath, currentDir, getSchemaDir(schemaTagMap, name), importedFile, importExt) : `./${importedFile}${importExt}`}';`;
1693
1766
  }).join("\n");
1694
1767
  }
1695
1768
  const isPrimitiveSchemaName = (name) => [
@@ -1732,11 +1805,38 @@ async function writeZodSchemaIndex(schemasPath, fileExtension, header, schemaNam
1732
1805
  const uniqueExports = [...new Set(allExports.split("\n"))].filter((line) => line.trim()).toSorted().join("\n");
1733
1806
  await fs.outputFile(indexPath, `${header}\n${uniqueExports}\n`);
1734
1807
  }
1808
+ async function writeZodSchemaTagsSplitBarrel(schemasPath, fileExtension, header, componentDirs, verbDirs, namingConvention, tsconfig) {
1809
+ const importExt = getImportExtension(fileExtension, tsconfig);
1810
+ const indexImportExt = getImportExtension(".ts", tsconfig);
1811
+ const allDirs = /* @__PURE__ */ new Map();
1812
+ for (const [dir, names] of componentDirs) allDirs.set(dir, [...names]);
1813
+ for (const [dir, names] of verbDirs) if (allDirs.has(dir)) allDirs.get(dir).push(...names);
1814
+ else allDirs.set(dir, [...names]);
1815
+ for (const [dir, schemaNames] of allDirs) {
1816
+ if (dir === ROOT_DIR) continue;
1817
+ await writeZodSchemaIndex(path.join(schemasPath, dir), fileExtension, header, schemaNames, namingConvention, false, tsconfig);
1818
+ }
1819
+ const rootSchemas = allDirs.get(ROOT_DIR) ?? [];
1820
+ const rootExports = [...new Set(rootSchemas)].map((name) => {
1821
+ return `export * from './${conventionName(name, namingConvention)}${importExt}';`;
1822
+ }).toSorted();
1823
+ const tagExports = [...allDirs.keys()].filter((dir) => dir !== ROOT_DIR).toSorted((a, b) => a.localeCompare(b, "en", { numeric: true })).map((dir) => {
1824
+ return `export * from '${indexImportExt ? `./${dir}/index${indexImportExt}` : `./${dir}`}';`;
1825
+ });
1826
+ const allExports = [...rootExports, ...tagExports];
1827
+ const rootIndexPath = path.join(schemasPath, "index.ts");
1828
+ const content = `${header}\n${allExports.join("\n")}\n`;
1829
+ await fs.outputFile(rootIndexPath, content);
1830
+ }
1735
1831
  function generateZodSchemasInline(builder, output, includeZodImport = true, paramsMutator, includeParamsImport = false) {
1736
1832
  if (output.override.zod.generateReusableSchemas === true) return generateZodSchemasInlineReusable(builder, output, includeZodImport, paramsMutator, includeParamsImport);
1737
1833
  const schemasWithOpenApiDef = builder.schemas.filter((s) => s.schema);
1738
1834
  if (schemasWithOpenApiDef.length === 0) return "";
1739
- const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1835
+ const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
1836
+ assertZodTarget({
1837
+ variant: output.override.zod.variant,
1838
+ isZodV4
1839
+ });
1740
1840
  const strict = output.override.zod.strict.body;
1741
1841
  const coerce = output.override.zod.coerce.body;
1742
1842
  const schemas = [];
@@ -1751,7 +1851,7 @@ function generateZodSchemasInline(builder, output, includeZodImport = true, para
1751
1851
  const parsedZodDefinition = parseZodValidationSchemaDefinition(generateZodValidationSchemaDefinition(dereference(schemaObject, context), context, name, strict, isZodV4, {
1752
1852
  required: true,
1753
1853
  emitMeta: output.override.zod.generateMeta
1754
- }), context, coerce, strict, isZodV4);
1854
+ }), context, coerce, strict, isZodV4, void 0, void 0, output.override.zod.variant);
1755
1855
  schemas.push({
1756
1856
  schemaName: name,
1757
1857
  consts: parsedZodDefinition.consts,
@@ -1759,10 +1859,14 @@ function generateZodSchemasInline(builder, output, includeZodImport = true, para
1759
1859
  });
1760
1860
  }
1761
1861
  if (schemas.length === 0) return "";
1762
- return generateZodSchemaFileContent("", schemas, includeZodImport);
1862
+ return generateZodSchemaFileContent("", schemas, output.override.zod.variant, includeZodImport);
1763
1863
  }
1764
1864
  function generateZodSchemasInlineReusable(builder, output, includeZodImport = true, paramsMutator, includeParamsImport = false) {
1765
- const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1865
+ const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
1866
+ assertZodTarget({
1867
+ variant: output.override.zod.variant,
1868
+ isZodV4
1869
+ });
1766
1870
  const strict = output.override.zod.strict.body;
1767
1871
  const coerce = output.override.zod.coerce.body;
1768
1872
  const context = {
@@ -1779,28 +1883,32 @@ function generateZodSchemasInlineReusable(builder, output, includeZodImport = tr
1779
1883
  strict,
1780
1884
  isZodV4,
1781
1885
  coerce,
1886
+ variant: output.override.zod.variant,
1782
1887
  generateMeta: output.override.zod.generateMeta,
1783
1888
  paramsMutator
1784
- })).map((entry) => renderReusableSchemaEntry(entry, context).content).join("\n\n");
1785
- const zodImport = includeZodImport ? `import { z as zod } from 'zod';\n` : "";
1889
+ })).map((entry) => renderReusableSchemaEntry(entry, context, output.override.zod.variant).content).join("\n\n");
1890
+ const zodImport = includeZodImport ? `${getZodSchemaImportStatement(output.override.zod.variant)}\n` : "";
1786
1891
  const paramsImport = paramsMutator && includeParamsImport && bodyReferencesMutator(body, paramsMutator) ? `${buildMutatorImportStatement(paramsMutator)}\n` : "";
1787
1892
  return `${zodImport || paramsImport ? `${zodImport}${paramsImport}\n` : ""}${body}\n`;
1788
1893
  }
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
- }
1894
+ async function writeZodSchemas(builder, schemasPath, fileExtension, header, output, paramsMutator, schemaTagMap) {
1895
+ if (output.override.zod.generateReusableSchemas) return writeZodSchemasReusable(builder, schemasPath, fileExtension, header, output, paramsMutator, schemaTagMap);
1896
+ const isSplit = !!schemaTagMap;
1794
1897
  const schemasWithOpenApiDef = builder.schemas.filter((s) => s.schema);
1795
1898
  const schemasToWrite = [];
1796
- const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1899
+ const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
1900
+ assertZodTarget({
1901
+ variant: output.override.zod.variant,
1902
+ isZodV4
1903
+ });
1797
1904
  const strict = output.override.zod.strict.body;
1798
1905
  const coerce = output.override.zod.coerce.body;
1799
1906
  for (const generatorSchema of schemasWithOpenApiDef) {
1800
1907
  const { name, schema: schemaObject } = generatorSchema;
1801
1908
  if (!schemaObject) continue;
1802
1909
  const fileName = conventionName(name, output.namingConvention);
1803
- const filePath = path.join(schemasPath, `${fileName}${fileExtension}`);
1910
+ const tagDir = getSchemaDir(schemaTagMap, name);
1911
+ const filePath = isSplit ? path.join(schemasPath, tagDir, `${fileName}${fileExtension}`) : path.join(schemasPath, `${fileName}${fileExtension}`);
1804
1912
  const context = {
1805
1913
  spec: builder.spec,
1806
1914
  target: builder.target,
@@ -1810,7 +1918,7 @@ async function writeZodSchemas(builder, schemasPath, fileExtension, header, outp
1810
1918
  const parsedZodDefinition = parseZodValidationSchemaDefinition(generateZodValidationSchemaDefinition(dereference(schemaObject, context), context, name, strict, isZodV4, {
1811
1919
  required: true,
1812
1920
  emitMeta: output.override.zod.generateMeta
1813
- }), context, coerce, strict, isZodV4);
1921
+ }), context, coerce, strict, isZodV4, void 0, void 0, output.override.zod.variant);
1814
1922
  schemasToWrite.push({
1815
1923
  schemaName: name,
1816
1924
  filePath,
@@ -1820,13 +1928,29 @@ async function writeZodSchemas(builder, schemasPath, fileExtension, header, outp
1820
1928
  }
1821
1929
  const groupedSchemasToWrite = groupSchemasByFilePath(schemasToWrite);
1822
1930
  for (const schemaGroup of groupedSchemasToWrite) {
1823
- const fileContent = generateZodSchemaFileContent(header, schemaGroup);
1931
+ const fileContent = generateZodSchemaFileContent(header, schemaGroup, output.override.zod.variant);
1824
1932
  await fs.outputFile(schemaGroup[0].filePath, fileContent);
1825
1933
  }
1826
- if (output.indexFiles) await writeZodSchemaIndex(schemasPath, fileExtension, header, groupedSchemasToWrite.map((schemaGroup) => schemaGroup[0].schemaName), output.namingConvention, false, output.tsconfig);
1934
+ const writtenSchemaNames = groupedSchemasToWrite.map((schemaGroup) => schemaGroup[0].schemaName);
1935
+ if (output.indexFiles && !isSplit) await writeZodSchemaIndex(schemasPath, fileExtension, header, writtenSchemaNames, output.namingConvention, false, output.tsconfig);
1936
+ if (isSplit) {
1937
+ const dirSchemas = /* @__PURE__ */ new Map();
1938
+ for (const name of writtenSchemaNames) {
1939
+ const dir = getSchemaDir(schemaTagMap, name);
1940
+ if (!dirSchemas.has(dir)) dirSchemas.set(dir, []);
1941
+ dirSchemas.get(dir).push(name);
1942
+ }
1943
+ return dirSchemas;
1944
+ }
1945
+ return new Map([[ROOT_DIR, writtenSchemaNames]]);
1827
1946
  }
1828
- async function writeZodSchemasReusable(builder, schemasPath, fileExtension, header, output, paramsMutator) {
1829
- const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1947
+ async function writeZodSchemasReusable(builder, schemasPath, fileExtension, header, output, paramsMutator, schemaTagMap) {
1948
+ const isSplit = !!schemaTagMap;
1949
+ const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
1950
+ assertZodTarget({
1951
+ variant: output.override.zod.variant,
1952
+ isZodV4
1953
+ });
1830
1954
  const strict = output.override.zod.strict.body;
1831
1955
  const coerce = output.override.zod.coerce.body;
1832
1956
  const context = {
@@ -1842,35 +1966,60 @@ async function writeZodSchemasReusable(builder, schemasPath, fileExtension, head
1842
1966
  strict,
1843
1967
  isZodV4,
1844
1968
  coerce,
1969
+ variant: output.override.zod.variant,
1845
1970
  generateMeta: output.override.zod.generateMeta,
1846
1971
  paramsMutator
1847
1972
  }));
1848
1973
  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
1974
  for (const entry of rewritten) {
1851
1975
  const fileName = conventionName(entry.name, output.namingConvention);
1852
- const filePath = path.join(schemasPath, `${fileName}${fileExtension}`);
1976
+ const tagDir = getSchemaDir(schemaTagMap, entry.name);
1977
+ const filePath = isSplit ? path.join(schemasPath, tagDir, `${fileName}${fileExtension}`) : path.join(schemasPath, `${fileName}${fileExtension}`);
1853
1978
  const importExt = getImportExtension(fileExtension, output.tsconfig);
1854
- const rendered = renderReusableSchemaEntry(entry, context);
1979
+ const rendered = renderReusableSchemaEntry(entry, context, output.override.zod.variant);
1855
1980
  const refImports = buildSiblingImports({
1856
1981
  usedRefs: entry.usedRefs,
1857
1982
  extraImports: rendered.extraImports,
1858
1983
  entryName: entry.name,
1859
1984
  componentNames,
1860
1985
  namingConvention: output.namingConvention,
1861
- importExt
1986
+ importExt,
1987
+ ...isSplit ? {
1988
+ schemaTagMap,
1989
+ currentDir: tagDir,
1990
+ schemasPath
1991
+ } : {}
1862
1992
  });
1863
- const imports = [...!!paramsMutator && bodyReferencesMutator(entry.zod, paramsMutator) && paramsMutatorImport ? [paramsMutatorImport] : [], ...refImports ? [refImports] : []].join("\n");
1864
- const fileContent = `${header}import { z as zod } from 'zod';\n` + (imports ? `${imports}\n\n` : "\n") + `${rendered.content}\n`;
1993
+ const mutatorImportStr = !!paramsMutator && bodyReferencesMutator(entry.zod, paramsMutator) ? buildMutatorImportStatement({
1994
+ ...paramsMutator,
1995
+ path: isSplit ? adjustMutatorPathForDir(paramsMutator.path, tagDir) : paramsMutator.path
1996
+ }) : void 0;
1997
+ const imports = [...mutatorImportStr ? [mutatorImportStr] : [], ...refImports ? [refImports] : []].join("\n");
1998
+ const fileContent = `${header}${getZodSchemaImportStatement(output.override.zod.variant)}\n` + (imports ? `${imports}\n\n` : "\n") + `${rendered.content}\n`;
1865
1999
  await fs.outputFile(filePath, fileContent);
1866
2000
  }
1867
- if (output.indexFiles && rewritten.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, rewritten.map((e) => e.name), output.namingConvention, true, output.tsconfig);
2001
+ if (output.indexFiles && !isSplit && rewritten.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, rewritten.map((e) => e.name), output.namingConvention, true, output.tsconfig);
2002
+ if (isSplit) {
2003
+ const dirSchemas = /* @__PURE__ */ new Map();
2004
+ for (const entry of rewritten) {
2005
+ const dir = getSchemaDir(schemaTagMap, entry.name);
2006
+ if (!dirSchemas.has(dir)) dirSchemas.set(dir, []);
2007
+ dirSchemas.get(dir).push(entry.name);
2008
+ }
2009
+ return dirSchemas;
2010
+ }
2011
+ return new Map([[ROOT_DIR, rewritten.map((e) => e.name)]]);
1868
2012
  }
1869
- async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension, header, output, context) {
2013
+ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension, header, output, context, schemaTagMap) {
2014
+ const isSplit = !!schemaTagMap;
1870
2015
  const zodContext = context;
1871
2016
  const verbOptionsArray = Object.values(verbOptions);
1872
- if (verbOptionsArray.length === 0) return;
1873
- const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
2017
+ if (verbOptionsArray.length === 0) return /* @__PURE__ */ new Map();
2018
+ const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
2019
+ assertZodTarget({
2020
+ variant: output.override.zod.variant,
2021
+ isZodV4
2022
+ });
1874
2023
  const strict = output.override.zod.strict.body;
1875
2024
  const coerce = output.override.zod.coerce.body;
1876
2025
  const useReusableSchemas = output.override.zod.generateReusableSchemas === true;
@@ -1932,25 +2081,30 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1932
2081
  ...queryParamsSchemas,
1933
2082
  ...headerParamsSchemas,
1934
2083
  ...responseSchemas
1935
- ]);
2084
+ ]).map((s) => ({
2085
+ ...s,
2086
+ verbTagDir: isSplit ? kebab(verbOption.tags?.[0] ?? DefaultTag) : ROOT_DIR
2087
+ }));
1936
2088
  }));
1937
2089
  const schemasToWrite = [];
1938
2090
  for (const entry of uniqueVerbsSchemas) {
1939
2091
  if (useReusableSchemas && entry.schema && typeof entry.schema.$ref === "string" && Object.keys(entry.schema).length === 1) continue;
1940
2092
  const { name, schema } = entry;
1941
2093
  const fileName = conventionName(name, output.namingConvention);
1942
- const filePath = path.join(schemasPath, `${fileName}${fileExtension}`);
2094
+ const tagDir = entry.verbTagDir ?? ROOT_DIR;
2095
+ const filePath = isSplit ? path.join(schemasPath, tagDir, `${fileName}${fileExtension}`) : path.join(schemasPath, `${fileName}${fileExtension}`);
1943
2096
  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
2097
  required: true,
1945
2098
  useReusableSchemas
1946
- }), zodContext, coerce, strict, isZodV4);
2099
+ }), zodContext, coerce, strict, isZodV4, void 0, void 0, output.override.zod.variant);
1947
2100
  let zodExpression = parsedZodDefinition.zod;
1948
2101
  let importStatements;
1949
2102
  if (useReusableSchemas && parsedZodDefinition.usedRefs.size > 0) {
1950
2103
  zodExpression = rewriteSentinelsToDirect(zodExpression);
1951
2104
  const importExt = getImportExtension(fileExtension, output.tsconfig);
1952
2105
  importStatements = [...parsedZodDefinition.usedRefs].filter((refName) => refName !== name).toSorted().map((refName) => {
1953
- return `import { ${refName} } from './${conventionName(refName, output.namingConvention)}${importExt}';`;
2106
+ const importedFile = conventionName(refName, output.namingConvention);
2107
+ return `import { ${refName} } from '${isSplit ? computeCrossDirImportPath(schemasPath, tagDir, getSchemaDir(schemaTagMap, refName), importedFile, importExt) : `./${importedFile}${importExt}`}';`;
1954
2108
  });
1955
2109
  }
1956
2110
  schemasToWrite.push({
@@ -1963,10 +2117,22 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1963
2117
  }
1964
2118
  const groupedSchemasToWrite = groupSchemasByFilePath(schemasToWrite);
1965
2119
  for (const schemaGroup of groupedSchemasToWrite) {
1966
- const fileContent = generateZodSchemaFileContent(header, schemaGroup);
2120
+ const fileContent = generateZodSchemaFileContent(header, schemaGroup, output.override.zod.variant);
1967
2121
  await fs.outputFile(schemaGroup[0].filePath, fileContent);
1968
2122
  }
1969
- if (output.indexFiles && uniqueVerbsSchemas.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, groupedSchemasToWrite.map((schemaGroup) => schemaGroup[0].schemaName), output.namingConvention, true, output.tsconfig);
2123
+ const writtenSchemaNames = groupedSchemasToWrite.map((schemaGroup) => schemaGroup[0].schemaName);
2124
+ if (output.indexFiles && !isSplit && uniqueVerbsSchemas.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, writtenSchemaNames, output.namingConvention, true, output.tsconfig);
2125
+ if (isSplit) {
2126
+ const dirSchemas = /* @__PURE__ */ new Map();
2127
+ for (const entry of uniqueVerbsSchemas) {
2128
+ if (useReusableSchemas && entry.schema && typeof entry.schema.$ref === "string" && Object.keys(entry.schema).length === 1) continue;
2129
+ const dir = entry.verbTagDir ?? ROOT_DIR;
2130
+ if (!dirSchemas.has(dir)) dirSchemas.set(dir, []);
2131
+ dirSchemas.get(dir).push(entry.name);
2132
+ }
2133
+ return dirSchemas;
2134
+ }
2135
+ return new Map([[ROOT_DIR, writtenSchemaNames]]);
1970
2136
  }
1971
2137
  //#endregion
1972
2138
  //#region src/write-specs.ts
@@ -1998,6 +2164,23 @@ async function runFormatter(formatter, paths, projectTitle) {
1998
2164
  break;
1999
2165
  }
2000
2166
  }
2167
+ function getComparableFilePath(filePath) {
2168
+ const resolvedPath = path.resolve(filePath);
2169
+ let comparablePath = resolvedPath;
2170
+ try {
2171
+ comparablePath = fs.realpathSync(resolvedPath);
2172
+ } catch (error) {
2173
+ if (error.code !== "ENOENT") throw error;
2174
+ }
2175
+ return process.platform === "win32" || process.platform === "darwin" ? comparablePath.toLowerCase() : comparablePath;
2176
+ }
2177
+ function excludeFilePath(filePaths, filePathToExclude) {
2178
+ const comparablePathToExclude = getComparableFilePath(filePathToExclude);
2179
+ return filePaths.map((filePath) => ({
2180
+ filePath,
2181
+ comparablePath: getComparableFilePath(filePath)
2182
+ })).filter(({ comparablePath }) => comparablePath !== comparablePathToExclude).map(({ filePath }) => filePath);
2183
+ }
2001
2184
  function getHeader(option, info) {
2002
2185
  if (!option) return "";
2003
2186
  const header = option(info);
@@ -2031,7 +2214,7 @@ async function addOperationSchemasReExport(schemaPath, operationSchemasPath, hea
2031
2214
  * file path so callers can include it in formatter / hook runs, or
2032
2215
  * `undefined` if no file was written.
2033
2216
  */
2034
- async function writeFakerSchemaMocks(builder, options, header) {
2217
+ async function writeFakerSchemaMocks(builder, options, header, schemaTagMap) {
2035
2218
  const { output } = options;
2036
2219
  const fakerEntry = output.mock.generators.find((g) => !isFunction(g) && g.type === OutputMockType.FAKER && g.schemas === true);
2037
2220
  if (!fakerEntry) return;
@@ -2062,9 +2245,32 @@ async function writeFakerSchemaMocks(builder, options, header) {
2062
2245
  filePath = path.join(dir, `schemas.faker${fileExtension}`);
2063
2246
  schemaImportPath = targetInfo ? `./${targetInfo.filename}${getImportExtension(fileExtension, output.tsconfig)}` : void 0;
2064
2247
  }
2065
- const reroutedImports = imports.map((imp) => imp.importPath ? imp : {
2066
- ...imp,
2067
- importPath: schemaImportPath
2248
+ const isZodSchemaOutput = isObject(output.schemas) && output.schemas.type === "zod";
2249
+ const importExtension = getImportExtension(fileExtension, output.tsconfig);
2250
+ const schemaSuffix = isZodSchemaOutput ? ".zod" : "";
2251
+ const perSchemaImportPath = /* @__PURE__ */ new Map();
2252
+ if (schemaImportPath === "." && !output.indexFiles && isObject(output.schemas)) for (const schema of builder.schemas) {
2253
+ const tsName = pascal(schema.name);
2254
+ const fileName = conventionName(schema.name, output.namingConvention);
2255
+ const tagDir = schemaTagMap?.get(schema.name);
2256
+ const tagSegment = tagDir && tagDir !== "." ? `${tagDir}/` : "";
2257
+ perSchemaImportPath.set(tsName, `./${tagSegment}${fileName}${schemaSuffix}${importExtension}`);
2258
+ }
2259
+ const reroutedImports = imports.map((imp) => {
2260
+ if (imp.importPath) return imp;
2261
+ if (imp.schemaFactory) return {
2262
+ ...imp,
2263
+ importPath: "."
2264
+ };
2265
+ const resolved = perSchemaImportPath.get(imp.name);
2266
+ if (resolved) return {
2267
+ ...imp,
2268
+ importPath: resolved
2269
+ };
2270
+ return {
2271
+ ...imp,
2272
+ importPath: schemaImportPath
2273
+ };
2068
2274
  });
2069
2275
  const grouped = /* @__PURE__ */ new Map();
2070
2276
  for (const imp of reroutedImports) {
@@ -2098,31 +2304,72 @@ function shouldGenerateZodSchemasInline(output, hasOperations) {
2098
2304
  function shouldGenerateSchemas(output, hasOperations) {
2099
2305
  return !output.schemas && !isSchemaValidatorClient(output.client) || shouldGenerateZodSchemasInline(output, hasOperations);
2100
2306
  }
2307
+ function getImplementationPathsForIndex(output, implementationPaths, indexFile) {
2308
+ const shouldExcludeSelf = output.indexFiles;
2309
+ const paths = shouldExcludeSelf ? excludeFilePath(implementationPaths, indexFile) : implementationPaths;
2310
+ if (!(shouldExcludeSelf && output.mode === OutputMode.SPLIT && getComparableFilePath(output.target) === getComparableFilePath(indexFile))) return paths;
2311
+ const targetInfo = getFileInfo(output.target, { extension: output.fileExtension });
2312
+ return excludeFilePath(paths, path.join(targetInfo.dirname, `${targetInfo.filename}.schemas${output.fileExtension}`));
2313
+ }
2101
2314
  async function writeSpecs(builder, workspace, options, projectName) {
2102
2315
  const { info, schemas, target } = builder;
2103
2316
  const { output } = options;
2317
+ const shouldSplitSchemasByTags = isObject(output.schemas) && output.schemas.splitByTags;
2318
+ const schemaTagMap = shouldSplitSchemasByTags ? buildSchemaTagMap(Object.values(builder.operations).map((op) => ({
2319
+ imports: op.imports,
2320
+ tags: op.tags
2321
+ })), schemas) : void 0;
2104
2322
  const projectTitle = projectName ?? info.title;
2105
2323
  const header = getHeader(output.override.header, info);
2106
2324
  if (output.schemas) {
2107
2325
  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) {
2326
+ const isZodSchemas = !isString(output.schemas) && output.schemas.type === "zod" || isString(output.schemas) && output.client === "zod" && output.override.zod.generateReusableSchemas;
2327
+ 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.");
2328
+ if (isZodSchemas) {
2109
2329
  const fileExtension = output.schemaFileExtension;
2110
- await writeZodSchemas(builder, schemasPath, fileExtension, header, output, output.override.zod.params ? await generateMutator({
2330
+ const schemasParamsMutator = output.override.zod.params ? await generateMutator({
2111
2331
  output: path.join(schemasPath, `__params__${fileExtension}`),
2112
2332
  mutator: output.override.zod.params,
2113
2333
  name: "zodParams",
2114
2334
  workspace,
2115
2335
  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
- });
2336
+ }) : void 0;
2337
+ if (shouldSplitSchemasByTags) {
2338
+ const componentDirs = await writeZodSchemas(builder, schemasPath, fileExtension, header, output, schemasParamsMutator, schemaTagMap);
2339
+ const verbDirs = await writeZodSchemasFromVerbs(builder.verbOptions, schemasPath, fileExtension, header, output, {
2340
+ spec: builder.spec,
2341
+ target: builder.target,
2342
+ workspace,
2343
+ output
2344
+ }, schemaTagMap);
2345
+ if (output.indexFiles) await writeZodSchemaTagsSplitBarrel(schemasPath, fileExtension, header, componentDirs, verbDirs, output.namingConvention, output.tsconfig);
2346
+ } else {
2347
+ await writeZodSchemas(builder, schemasPath, fileExtension, header, output, schemasParamsMutator);
2348
+ await writeZodSchemasFromVerbs(builder.verbOptions, schemasPath, fileExtension, header, output, {
2349
+ spec: builder.spec,
2350
+ target: builder.target,
2351
+ workspace,
2352
+ output
2353
+ });
2354
+ }
2123
2355
  } else {
2124
2356
  const fileExtension = output.fileExtension || ".ts";
2125
- if (output.operationSchemas) {
2357
+ if (shouldSplitSchemasByTags) await writeSchemasTagsSplit({
2358
+ schemaPath: schemasPath,
2359
+ schemas,
2360
+ target,
2361
+ namingConvention: output.namingConvention,
2362
+ fileExtension,
2363
+ header,
2364
+ indexFiles: output.indexFiles,
2365
+ tsconfig: output.tsconfig,
2366
+ factoryOutputDirectory: output.factoryMethods?.outputDirectory,
2367
+ operations: Object.values(builder.operations).map((op) => ({
2368
+ imports: op.imports,
2369
+ tags: op.tags
2370
+ }))
2371
+ });
2372
+ else if (output.operationSchemas) {
2126
2373
  const { regularSchemas, operationSchemas: opSchemas } = splitSchemasByType(schemas);
2127
2374
  const regularSchemaNames = new Set(regularSchemas.map((s) => s.name));
2128
2375
  const operationSchemaNames = new Set(opSchemas.map((s) => s.name));
@@ -2166,7 +2413,7 @@ async function writeSpecs(builder, workspace, options, projectName) {
2166
2413
  });
2167
2414
  }
2168
2415
  }
2169
- const fakerSchemaPath = await writeFakerSchemaMocks(builder, options, header);
2416
+ const fakerSchemaPath = await writeFakerSchemaMocks(builder, options, header, schemaTagMap);
2170
2417
  let implementationPaths = [];
2171
2418
  if (output.target) {
2172
2419
  const writeMode = getWriteMode(output.mode);
@@ -2189,6 +2436,7 @@ async function writeSpecs(builder, workspace, options, projectName) {
2189
2436
  projectName,
2190
2437
  header,
2191
2438
  needSchema: shouldGenerateSchemas(output, hasOperations),
2439
+ schemaTagMap,
2192
2440
  generateSchemasInline: needZodSchemasInline ? () => generateZodSchemasInline(builder, output, includeZodImport, inlineSchemasParamsMutator, includeParamsImport) : void 0
2193
2441
  });
2194
2442
  }
@@ -2197,7 +2445,8 @@ async function writeSpecs(builder, workspace, options, projectName) {
2197
2445
  const indexFile = path.join(workspacePath, "index.ts");
2198
2446
  const mockExtensions = output.mock.generators.map((g) => getMockFileExtensionByTypeName(g));
2199
2447
  const importExtension = getImportExtension(output.fileExtension, output.tsconfig);
2200
- const imports = implementationPaths.filter((p) => mockExtensions.length === 0 || !mockExtensions.some((ext) => p.endsWith(`.${ext}.ts`))).map((p) => {
2448
+ const implementationPathsForIndex = getImplementationPathsForIndex(output, implementationPaths, indexFile);
2449
+ const imports = implementationPathsForIndex.filter((p) => mockExtensions.length === 0 || !mockExtensions.some((ext) => p.endsWith(`.${ext}.ts`))).map((p) => {
2201
2450
  const relative = upath.getRelativeImportPath(indexFile, p, true);
2202
2451
  return (relative.endsWith(output.fileExtension) ? relative.slice(0, -output.fileExtension.length) : relative.replace(/\.[^/.]+$/, "")) + importExtension;
2203
2452
  });
@@ -2209,10 +2458,10 @@ async function writeSpecs(builder, workspace, options, projectName) {
2209
2458
  if (output.indexFiles) {
2210
2459
  if (await fs.pathExists(indexFile)) {
2211
2460
  const data = await fs.readFile(indexFile, "utf8");
2212
- const importsNotDeclared = imports.filter((imp) => !data.includes(imp));
2461
+ const importsNotDeclared = imports.filter((imp) => !data.includes(`export * from '${imp}'`));
2213
2462
  await fs.appendFile(indexFile, unique(importsNotDeclared).map((imp) => `export * from '${imp}';\n`).join(""));
2214
2463
  } else await fs.outputFile(indexFile, unique(imports).map((imp) => `export * from '${imp}';`).join("\n") + "\n");
2215
- implementationPaths = [indexFile, ...implementationPaths];
2464
+ implementationPaths = [indexFile, ...implementationPathsForIndex];
2216
2465
  }
2217
2466
  }
2218
2467
  if (builder.extraFiles.length > 0) {
@@ -2352,4 +2601,4 @@ async function loadConfigFile(configFilePath) {
2352
2601
  //#endregion
2353
2602
  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
2603
 
2355
- //# sourceMappingURL=config-CXPetEiJ.mjs.map
2604
+ //# sourceMappingURL=config-C8B9Lol2.mjs.map