orval 8.12.3 → 8.14.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,13 +1,14 @@
1
1
  import path from "node:path";
2
- import { FormDataArrayHandling, GetterPropType, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SupportedFormatter, asyncReduce, collectReferencedComponents, conventionName, createSuccessMessage, dynamicImport, fixCrossDirectoryImports, fixRegularSchemaImports, generateComponentDefinition, generateDependencyImports, generateParameterDefinition, generateSchemasDefinition, generateVerbsOptions, getBaseUrlRuntimeImports, getFileInfo, getFullRoute, getMockFileExtensionByTypeName, getRoute, isBoolean, isFunction, isNullish, isObject, isReference, isString, isUrl, jsDoc, log, logError, logVerbose, logWarning, pascal, removeFilesAndEmptyFolders, resolveInstalledVersions, resolveRef, splitSchemasByType, upath, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode } from "@orval/core";
2
+ import { FormDataArrayHandling, GetterPropType, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SupportedFormatter, asyncReduce, 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
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";
6
6
  import { isNullish as isNullish$1, pick, unique } from "remeda";
7
7
  import * as mock from "@orval/mock";
8
- import { generateMockImports, getDefaultMockOptionsForType } from "@orval/mock";
8
+ import { generateFakerForSchemas, generateMockImports, getDefaultMockOptionsForType } from "@orval/mock";
9
9
  import angular from "@orval/angular";
10
10
  import axios from "@orval/axios";
11
+ import effect from "@orval/effect";
11
12
  import fetchClient from "@orval/fetch";
12
13
  import hono from "@orval/hono";
13
14
  import mcp from "@orval/mcp";
@@ -28,7 +29,7 @@ import { createJiti } from "jiti";
28
29
  //#region package.json
29
30
  var name = "orval";
30
31
  var description = "A swagger client generator for typescript";
31
- var version = "8.12.3";
32
+ var version = "8.14.0";
32
33
  //#endregion
33
34
  //#region src/client.ts
34
35
  const DEFAULT_CLIENT = OutputClient.AXIOS;
@@ -61,6 +62,7 @@ const getGeneratorClient = (outputClient, output) => {
61
62
  })(),
62
63
  swr: swr()(),
63
64
  zod: zod()(),
65
+ effect: effect()(),
64
66
  hono: hono()(),
65
67
  fetch: fetchClient()(),
66
68
  mcp: mcp()()
@@ -162,7 +164,10 @@ const generateOperations = (outputClient = DEFAULT_CLIENT, verbsOptions, options
162
164
  const { client: generatorClient } = getGeneratorClient(outputClient, output);
163
165
  const client = await generatorClient(verbOption, options, outputClient, output);
164
166
  if (!client.implementation) return acc;
165
- const mockOutputs = output.mock.generators.map((entry) => {
167
+ const mockOutputs = output.mock.generators.filter((entry) => {
168
+ if (!isFunction(entry) && entry.type === OutputMockType.FAKER && entry.operationResponses === false) return false;
169
+ return true;
170
+ }).map((entry) => {
166
171
  const generated = invokeMockGenerator(verbOption, options, entry);
167
172
  return {
168
173
  type: isFunction(entry) ? OutputMockType.MSW : entry.type,
@@ -851,6 +856,26 @@ function normalizeSchemasOption(schemas, workspace) {
851
856
  type: schemas.type
852
857
  };
853
858
  }
859
+ function normalizeEffectOptions(effect) {
860
+ return {
861
+ strict: {
862
+ param: effect?.strict?.param ?? false,
863
+ query: effect?.strict?.query ?? false,
864
+ header: effect?.strict?.header ?? false,
865
+ body: effect?.strict?.body ?? false,
866
+ response: effect?.strict?.response ?? false
867
+ },
868
+ generate: {
869
+ param: effect?.generate?.param ?? true,
870
+ query: effect?.generate?.query ?? true,
871
+ header: effect?.generate?.header ?? true,
872
+ body: effect?.generate?.body ?? true,
873
+ response: effect?.generate?.response ?? true
874
+ },
875
+ generateEachHttpStatus: effect?.generateEachHttpStatus ?? false,
876
+ useBrandedTypes: effect?.useBrandedTypes ?? false
877
+ };
878
+ }
854
879
  async function normalizeOptions(optionsExport, workspace = process.cwd(), globalOptions = {}) {
855
880
  const options = await (isFunction(optionsExport) ? optionsExport() : optionsExport);
856
881
  if (!options.input) throw new Error(styleText("red", `Config requires an input.`));
@@ -891,11 +916,21 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
891
916
  seenMockTypes.add(entry.type);
892
917
  }
893
918
  const defaultFileExtension = ".ts";
919
+ const defaultSchemaFileExtension = !!outputOptions.schemas && (!isString(outputOptions.schemas) && outputOptions.schemas.type === "zod" || isString(outputOptions.schemas) && (outputOptions.client ?? client) === "zod" && outputOptions.override?.zod?.generateReusableSchemas === true) ? ".zod.ts" : defaultFileExtension;
920
+ const factoryMethodsConfig = outputOptions.factoryMethods;
921
+ let factoryMethods = void 0;
922
+ if (factoryMethodsConfig) factoryMethods = {
923
+ functionNamePrefix: factoryMethodsConfig.functionNamePrefix ?? "create",
924
+ mode: factoryMethodsConfig.mode ?? "split",
925
+ outputDirectory: factoryMethodsConfig.outputDirectory ? normalizePath(factoryMethodsConfig.outputDirectory, outputWorkspace) : outputOptions.schemas ? normalizePath(isString(outputOptions.schemas) ? outputOptions.schemas : outputOptions.schemas.path, outputWorkspace) : normalizePath(outputWorkspace, outputWorkspace),
926
+ includeOptionalProperty: factoryMethodsConfig.includeOptionalProperty ?? true
927
+ };
894
928
  const globalQueryOptions = {
895
929
  signal: true,
896
930
  shouldExportMutatorHooks: true,
897
931
  shouldExportHttpClient: true,
898
932
  shouldExportQueryKey: true,
933
+ shouldFilterQueryKey: false,
899
934
  shouldSplitQueryKey: false,
900
935
  ...normalizeQueryOptions(outputOptions.override?.query, workspace)
901
936
  };
@@ -913,6 +948,7 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
913
948
  operationSchemas: outputOptions.operationSchemas ? normalizePath(outputOptions.operationSchemas, outputWorkspace) : void 0,
914
949
  namingConvention: outputOptions.namingConvention ?? NamingConvention.CAMEL_CASE,
915
950
  fileExtension: outputOptions.fileExtension ?? defaultFileExtension,
951
+ schemaFileExtension: outputOptions.schemaFileExtension ?? outputOptions.fileExtension ?? defaultSchemaFileExtension,
916
952
  workspace: outputOptions.workspace ? outputWorkspace : void 0,
917
953
  client: outputOptions.client ?? client ?? OutputClient.AXIOS_FUNCTIONS,
918
954
  httpClient: outputOptions.httpClient ?? httpClient ?? ((outputOptions.client ?? client) === OutputClient.ANGULAR_QUERY ? OutputHttpClient.ANGULAR : OutputHttpClient.FETCH),
@@ -927,6 +963,7 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
927
963
  indexFiles: outputOptions.indexFiles ?? true,
928
964
  baseUrl: outputOptions.baseUrl,
929
965
  unionAddMissingProperties: outputOptions.unionAddMissingProperties ?? false,
966
+ factoryMethods,
930
967
  override: {
931
968
  ...outputOptions.override,
932
969
  mock: {
@@ -999,11 +1036,15 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
999
1036
  ...outputOptions.override?.zod?.preprocess?.body ? { body: normalizeMutator(workspace, outputOptions.override.zod.preprocess.body) } : {},
1000
1037
  ...outputOptions.override?.zod?.preprocess?.response ? { response: normalizeMutator(workspace, outputOptions.override.zod.preprocess.response) } : {}
1001
1038
  },
1039
+ ...outputOptions.override?.zod?.params ? { params: normalizeMutator(workspace, outputOptions.override.zod.params) } : {},
1002
1040
  generateEachHttpStatus: outputOptions.override?.zod?.generateEachHttpStatus ?? false,
1003
1041
  useBrandedTypes: outputOptions.override?.zod?.useBrandedTypes ?? false,
1042
+ generateReusableSchemas: outputOptions.override?.zod?.generateReusableSchemas ?? false,
1043
+ generateMeta: outputOptions.override?.zod?.generateMeta ?? false,
1004
1044
  dateTimeOptions: outputOptions.override?.zod?.dateTimeOptions ?? { offset: true },
1005
1045
  timeOptions: outputOptions.override?.zod?.timeOptions ?? {}
1006
1046
  },
1047
+ effect: normalizeEffectOptions(outputOptions.override?.effect),
1007
1048
  swr: {
1008
1049
  generateErrorTypes: false,
1009
1050
  ...outputOptions.override?.swr
@@ -1129,7 +1170,7 @@ function normalizePath(path$1, workspace) {
1129
1170
  return path.resolve(workspace, path$1);
1130
1171
  }
1131
1172
  function normalizeOperationsAndTags(operationsOrTags, workspace, global) {
1132
- return Object.fromEntries(Object.entries(operationsOrTags).map(([key, { transformer, mutator, formData, formUrlEncoded, paramsSerializer, paramsFilter, query, angular, zod, ...rest }]) => {
1173
+ return Object.fromEntries(Object.entries(operationsOrTags).map(([key, { transformer, mutator, formData, formUrlEncoded, paramsSerializer, paramsFilter, query, angular, zod, effect, ...rest }]) => {
1133
1174
  return [key, {
1134
1175
  ...rest,
1135
1176
  ...angular ? { angular: {
@@ -1168,11 +1209,15 @@ function normalizeOperationsAndTags(operationsOrTags, workspace, global) {
1168
1209
  ...zod.preprocess?.body ? { body: normalizeMutator(workspace, zod.preprocess.body) } : {},
1169
1210
  ...zod.preprocess?.response ? { response: normalizeMutator(workspace, zod.preprocess.response) } : {}
1170
1211
  },
1212
+ ...zod.params ? { params: normalizeMutator(workspace, zod.params) } : {},
1171
1213
  generateEachHttpStatus: zod.generateEachHttpStatus ?? false,
1172
1214
  useBrandedTypes: zod.useBrandedTypes ?? false,
1215
+ generateReusableSchemas: zod.generateReusableSchemas ?? false,
1216
+ generateMeta: zod.generateMeta ?? false,
1173
1217
  dateTimeOptions: zod.dateTimeOptions ?? { offset: true },
1174
1218
  timeOptions: zod.timeOptions ?? {}
1175
1219
  } } : {},
1220
+ ...effect ? { effect: normalizeEffectOptions(effect) } : {},
1176
1221
  ...transformer ? { transformer: normalizePath(transformer, workspace) } : {},
1177
1222
  ...mutator ? { mutator: normalizeMutator(workspace, mutator) } : {},
1178
1223
  ...formData === void 0 ? {} : { formData: createFormData(workspace, formData) },
@@ -1242,6 +1287,8 @@ function normalizeQueryOptions(queryOptions = {}, outputWorkspace, globalOptions
1242
1287
  ...queryOptions.mutationOptions ? { mutationOptions: normalizeMutator(outputWorkspace, queryOptions.mutationOptions) } : {},
1243
1288
  ...isNullish(globalOptions.shouldExportQueryKey) ? {} : { shouldExportQueryKey: globalOptions.shouldExportQueryKey },
1244
1289
  ...isNullish(queryOptions.shouldExportQueryKey) ? {} : { shouldExportQueryKey: queryOptions.shouldExportQueryKey },
1290
+ ...isNullish(globalOptions.shouldFilterQueryKey) ? {} : { shouldFilterQueryKey: globalOptions.shouldFilterQueryKey },
1291
+ ...isNullish(queryOptions.shouldFilterQueryKey) ? {} : { shouldFilterQueryKey: queryOptions.shouldFilterQueryKey },
1245
1292
  ...isNullish(globalOptions.shouldExportHttpClient) ? {} : { shouldExportHttpClient: globalOptions.shouldExportHttpClient },
1246
1293
  ...isNullish(queryOptions.shouldExportHttpClient) ? {} : { shouldExportHttpClient: queryOptions.shouldExportHttpClient },
1247
1294
  ...isNullish(globalOptions.shouldExportMutatorHooks) ? {} : { shouldExportMutatorHooks: globalOptions.shouldExportMutatorHooks },
@@ -1308,19 +1355,277 @@ async function startWatcher(watchOptions, watchFn, defaultTarget = ".") {
1308
1355
  });
1309
1356
  }
1310
1357
  //#endregion
1358
+ //#region src/reusable-schemas.ts
1359
+ /**
1360
+ * Resolve the export identifier for a `#/components/schemas/X` ref. We reuse
1361
+ * `@orval/core`'s `getRefInfo(...).name` (`pascal` + sanitize + component
1362
+ * suffix) so reusable zod schema exports match the operation wrappers and the
1363
+ * TS model types exactly. `namingConvention` deliberately does NOT influence
1364
+ * the identifier — it governs file names only, consistent with the rest of
1365
+ * orval. The same call powers the generator's `namedRef` emission, so the
1366
+ * definition name and every reference stay in sync.
1367
+ */
1368
+ const resolveSchemaName = (ref, context) => getRefInfo(ref, context).name;
1369
+ /**
1370
+ * Resolve names for a set of refs, throwing on conflicts (two distinct refs
1371
+ * collapsing to the same identifier). The mapping is the single source of
1372
+ * truth for cross-schema references — the generator, the orchestrator's graph,
1373
+ * and the sentinel rewriter all consult it.
1374
+ */
1375
+ const resolveSchemaNames = (refs, context) => {
1376
+ const resolved = /* @__PURE__ */ new Map();
1377
+ const reverse = /* @__PURE__ */ new Map();
1378
+ for (const ref of refs) {
1379
+ const name = resolveSchemaName(ref, context);
1380
+ const previous = reverse.get(name);
1381
+ if (previous !== void 0 && previous !== ref) throw new Error(`[orval/zod] generateReusableSchemas: refs ${previous} and ${ref} both resolve to the export name "${name}". Rename one in the OpenAPI source.`);
1382
+ resolved.set(ref, name);
1383
+ reverse.set(name, ref);
1384
+ }
1385
+ return resolved;
1386
+ };
1387
+ /**
1388
+ * For each component-schema ref, run the Zod generator + parser with
1389
+ * `useReusableSchemas: true`. The resulting `zod` strings contain
1390
+ * `__REF_<name>__` sentinels at every site that references another schema;
1391
+ * the SCC step (Task 10) decides whether each sentinel becomes a direct
1392
+ * identifier or a `z.lazy(() => Name)` wrapper.
1393
+ */
1394
+ const generateReusableSchemaSet = (refs, context, options) => {
1395
+ const componentSchemas = context.spec.components?.schemas ?? {};
1396
+ const nameToRef = /* @__PURE__ */ new Map();
1397
+ for (const schemaName of Object.keys(componentSchemas)) {
1398
+ const ref = `#/components/schemas/${schemaName}`;
1399
+ nameToRef.set(resolveSchemaName(ref, context), ref);
1400
+ }
1401
+ const queue = [...refs];
1402
+ const seen = new Set(refs);
1403
+ const entries = [];
1404
+ for (const ref of queue) {
1405
+ const schema = componentSchemas[ref.slice(21)];
1406
+ if (!schema) continue;
1407
+ const name = resolveSchemaName(ref, context);
1408
+ const parsed = parseZodValidationSchemaDefinition(generateZodValidationSchemaDefinition(schema, context, name, options.strict, options.isZodV4, {
1409
+ required: true,
1410
+ useReusableSchemas: true,
1411
+ emitMeta: options.generateMeta
1412
+ }), context, options.coerce ?? false, options.strict, options.isZodV4, void 0, options.paramsMutator ? {
1413
+ mutator: options.paramsMutator,
1414
+ operationId: "",
1415
+ location: "schema",
1416
+ schemaName: name
1417
+ } : void 0);
1418
+ entries.push({
1419
+ ref,
1420
+ name,
1421
+ zod: parsed.zod,
1422
+ consts: parsed.consts,
1423
+ usedRefs: parsed.usedRefs
1424
+ });
1425
+ for (const usedName of parsed.usedRefs) {
1426
+ const usedRef = nameToRef.get(usedName);
1427
+ if (usedRef !== void 0 && !seen.has(usedRef)) {
1428
+ seen.add(usedRef);
1429
+ queue.push(usedRef);
1430
+ }
1431
+ }
1432
+ }
1433
+ return entries;
1434
+ };
1435
+ const edgeKey = (from, to) => `${from}->${to}`;
1436
+ const tarjan = (graph) => {
1437
+ let index = 0;
1438
+ const stack = [];
1439
+ const onStack = /* @__PURE__ */ new Set();
1440
+ const indices = /* @__PURE__ */ new Map();
1441
+ const lowlinks = /* @__PURE__ */ new Map();
1442
+ const sccs = [];
1443
+ const lazyEdges = /* @__PURE__ */ new Set();
1444
+ const strongconnect = (v) => {
1445
+ indices.set(v, index);
1446
+ lowlinks.set(v, index);
1447
+ index += 1;
1448
+ stack.push(v);
1449
+ onStack.add(v);
1450
+ const neighbors = graph.get(v) ?? /* @__PURE__ */ new Set();
1451
+ for (const w of neighbors) {
1452
+ if (v === w) {
1453
+ lazyEdges.add(edgeKey(v, w));
1454
+ continue;
1455
+ }
1456
+ if (!indices.has(w)) {
1457
+ strongconnect(w);
1458
+ lowlinks.set(v, Math.min(lowlinks.get(v) ?? -1, lowlinks.get(w) ?? -1));
1459
+ } else if (onStack.has(w)) {
1460
+ lazyEdges.add(edgeKey(v, w));
1461
+ lowlinks.set(v, Math.min(lowlinks.get(v) ?? -1, indices.get(w) ?? -1));
1462
+ }
1463
+ }
1464
+ if (lowlinks.get(v) === indices.get(v)) {
1465
+ const scc = [];
1466
+ let w;
1467
+ do {
1468
+ w = stack.pop();
1469
+ if (w === void 0) break;
1470
+ onStack.delete(w);
1471
+ scc.push(w);
1472
+ } while (w !== v);
1473
+ sccs.push(scc);
1474
+ }
1475
+ };
1476
+ for (const node of graph.keys()) if (!indices.has(node)) strongconnect(node);
1477
+ return {
1478
+ sccs,
1479
+ lazyEdges
1480
+ };
1481
+ };
1482
+ const SENTINEL_PATTERN = /__REF_([A-Za-z_$][A-Za-z0-9_$]*)__/g;
1483
+ /**
1484
+ * Replace every `__REF_<name>__` sentinel with the bare identifier. Use this
1485
+ * for schemas that sit at the top of the dependency graph (operation params,
1486
+ * bodies, responses) — they can never participate in a cycle with the
1487
+ * component schemas they reference, so every ref is a direct (non-lazy) one.
1488
+ */
1489
+ const rewriteSentinelsToDirect = (zod) => zod.replaceAll(SENTINEL_PATTERN, (_match, refName) => refName);
1490
+ /**
1491
+ * Replace every `__REF_<name>__` sentinel with either the bare identifier or
1492
+ * `zod.lazy(() => <name>)` based on whether the edge closes a cycle, then
1493
+ * reorder entries so that every non-lazy reference is emitted AFTER its
1494
+ * target. This avoids TDZ errors at module load.
1495
+ *
1496
+ * Entries that sit in a cycle (SCC of size > 1, or a self-loop) are flagged
1497
+ * `isRecursive`. Their generated `const` reads its own binding inside the
1498
+ * initializer (through the `zod.lazy` wrapper), which TypeScript rejects with
1499
+ * TS7022 ("'X' implicitly has type 'any' ... referenced directly or indirectly
1500
+ * in its own initializer") unless the `const` carries an explicit type
1501
+ * annotation. The writer (`write-zod-specs`) supplies that annotation —
1502
+ * `const X: zod.ZodType<X>` — backed by a generated TS type, which both
1503
+ * silences TS7022 and preserves full `z.infer` typing through the recursion.
1504
+ *
1505
+ * Both the lazy classification and the emit order come from a single Tarjan
1506
+ * run, guaranteeing they agree: a non-lazy edge u→v means v is visited (and
1507
+ * popped) before u in DFS, so v appears earlier in the SCC array → emitted
1508
+ * before u → safe.
1509
+ */
1510
+ const rewriteReusableSchemas = (entries) => {
1511
+ const graph = new Map(entries.map((e) => [e.name, new Set(e.usedRefs)]));
1512
+ for (const e of entries) for (const ref of e.usedRefs) if (!graph.has(ref)) graph.set(ref, /* @__PURE__ */ new Set());
1513
+ const { sccs, lazyEdges } = tarjan(graph);
1514
+ const recursiveNames = /* @__PURE__ */ new Set();
1515
+ for (const scc of sccs) if (scc.length > 1) for (const name of scc) recursiveNames.add(name);
1516
+ else if (lazyEdges.has(edgeKey(scc[0], scc[0]))) recursiveNames.add(scc[0]);
1517
+ const rewritten = new Map(entries.map((entry) => {
1518
+ const newZod = entry.zod.replaceAll(SENTINEL_PATTERN, (_match, refName) => {
1519
+ return lazyEdges.has(edgeKey(entry.name, refName)) ? `zod.lazy(() => ${refName})` : refName;
1520
+ });
1521
+ return [entry.name, {
1522
+ ...entry,
1523
+ zod: newZod,
1524
+ isRecursive: recursiveNames.has(entry.name)
1525
+ }];
1526
+ }));
1527
+ const out = [];
1528
+ for (const scc of sccs) for (const name of scc) {
1529
+ const entry = rewritten.get(name);
1530
+ if (entry !== void 0) out.push(entry);
1531
+ }
1532
+ return out;
1533
+ };
1534
+ //#endregion
1311
1535
  //#region src/write-zod-specs.ts
1312
- function generateZodSchemaFileContent(header, schemas) {
1313
- return `${header}import { z as zod } from 'zod';
1314
-
1315
- ${schemas.map(({ schemaName, consts, zodExpression }) => {
1536
+ /**
1537
+ * Render the `import { ... } from '...'` line for a resolved
1538
+ * `GeneratorMutator`. Mirrors the format produced by
1539
+ * `generateMutatorImports` in `@orval/core` but inlined to avoid pulling in
1540
+ * its full surface area for a single statement.
1541
+ */
1542
+ function buildMutatorImportStatement(mutator) {
1543
+ return `import ${mutator.default ? mutator.name : `{ ${mutator.name} }`} from '${mutator.path}';`;
1544
+ }
1545
+ /**
1546
+ * Whole-word substring check for a resolved mutator alias inside generated
1547
+ * code. Plain `String.includes` would false-positive when the user names the
1548
+ * mutator something like `min` against `.min(1)`.
1549
+ */
1550
+ function bodyReferencesMutator(body, mutator) {
1551
+ return new RegExp(String.raw`\b${mutator.name}\b`).test(body);
1552
+ }
1553
+ function generateZodSchemaFileContent(header, schemas, includeZodImport = true) {
1554
+ const refImports = [...new Set(schemas.flatMap((s) => s.importStatements ?? []))].toSorted();
1555
+ const importBlock = [...includeZodImport ? [`import { z as zod } from 'zod';`] : [], ...refImports].join("\n");
1556
+ const schemaContent = schemas.map(({ schemaName, consts, zodExpression }) => {
1316
1557
  return `${consts ? `${consts}\n` : ""}export const ${schemaName} = ${zodExpression}
1317
1558
 
1318
1559
  export type ${schemaName} = zod.input<typeof ${schemaName}>;
1319
1560
  export type ${schemaName}Output = zod.output<typeof ${schemaName}>;`;
1320
- }).join("\n\n")}
1321
- `;
1561
+ }).join("\n\n");
1562
+ return `${header}${importBlock ? `${importBlock}\n\n` : ""}${schemaContent}\n`;
1563
+ }
1564
+ function renderReusableSchemaEntry(entry, context) {
1565
+ const consts = entry.consts ? `${entry.consts}\n\n` : "";
1566
+ if (entry.isRecursive) {
1567
+ const rawName = isComponentRef(entry.ref) ? getRefInfo(entry.ref, context).originalName : void 0;
1568
+ const schema = rawName ? context.spec.components?.schemas?.[rawName] : void 0;
1569
+ const resolved = schema ? resolveValue({
1570
+ schema,
1571
+ name: entry.name,
1572
+ context
1573
+ }) : void 0;
1574
+ const typeBody = resolved ? resolved.value : "unknown";
1575
+ const seen = /* @__PURE__ */ new Set();
1576
+ const extraImports = [];
1577
+ for (const imp of resolved?.imports ?? []) {
1578
+ if (!imp.name || imp.name === entry.name) continue;
1579
+ const bindingKey = imp.alias ?? imp.name;
1580
+ if (seen.has(bindingKey)) continue;
1581
+ seen.add(bindingKey);
1582
+ extraImports.push({
1583
+ name: imp.name,
1584
+ ...imp.alias ? { alias: imp.alias } : {}
1585
+ });
1586
+ }
1587
+ return {
1588
+ 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}>;`,
1589
+ extraImports
1590
+ };
1591
+ }
1592
+ return {
1593
+ content: `${consts}export const ${entry.name} = ${entry.zod};\n\nexport type ${entry.name} = zod.input<typeof ${entry.name}>;\nexport type ${entry.name}Output = zod.output<typeof ${entry.name}>;`,
1594
+ extraImports: []
1595
+ };
1322
1596
  }
1323
1597
  const isValidSchemaIdentifier = (name) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(name);
1598
+ /**
1599
+ * Build the sibling-file `import { … } from './…'` block for one reusable
1600
+ * schema file. Two sources feed in:
1601
+ * - `usedRefs` — names from the zod runtime expression. Sourced from the
1602
+ * sentinel parser, so always unaliased.
1603
+ * - `extraImports` — names the recursive TS body needs that the zod runtime
1604
+ * collapsed (`propertyNames` $refs, etc.). May carry `alias`.
1605
+ * Keyed by export name (`name`) so an aliased `extraImports` entry overrides
1606
+ * a bare `usedRefs` entry — the recursive TS body uses the local binding, so
1607
+ * the aliased form has to win for the file to compile. Self-refs and
1608
+ * non-component identifiers are filtered out.
1609
+ *
1610
+ * Exported for unit-test coverage of the alias-propagation path; no
1611
+ * `resolveValue` producer surfaces aliases here today, so the integration
1612
+ * tests can't exercise it.
1613
+ */
1614
+ function buildSiblingImports({ usedRefs, extraImports, entryName, componentNames, namingConvention, importExt }) {
1615
+ const importsByName = /* @__PURE__ */ new Map();
1616
+ for (const name of usedRefs) {
1617
+ if (name === entryName) continue;
1618
+ importsByName.set(name, { name });
1619
+ }
1620
+ for (const imp of extraImports) {
1621
+ if (imp.name === entryName || !componentNames.has(imp.name)) continue;
1622
+ importsByName.set(imp.name, imp);
1623
+ }
1624
+ return [...importsByName.values()].toSorted((a, b) => a.name.localeCompare(b.name)).map(({ name, alias }) => {
1625
+ const importedFile = conventionName(name, namingConvention);
1626
+ return `import { ${alias ? `${name} as ${alias}` : name} } from './${importedFile}${importExt}';`;
1627
+ }).join("\n");
1628
+ }
1324
1629
  const isPrimitiveSchemaName = (name) => [
1325
1630
  "string",
1326
1631
  "number",
@@ -1361,7 +1666,8 @@ async function writeZodSchemaIndex(schemasPath, fileExtension, header, schemaNam
1361
1666
  const uniqueExports = [...new Set(allExports.split("\n"))].filter((line) => line.trim()).toSorted().join("\n");
1362
1667
  await fs.outputFile(indexPath, `${header}\n${uniqueExports}\n`);
1363
1668
  }
1364
- function generateZodSchemasInline(builder, output) {
1669
+ function generateZodSchemasInline(builder, output, includeZodImport = true, paramsMutator, includeParamsImport = false) {
1670
+ if (output.override.zod.generateReusableSchemas === true) return generateZodSchemasInlineReusable(builder, output, includeZodImport, paramsMutator, includeParamsImport);
1365
1671
  const schemasWithOpenApiDef = builder.schemas.filter((s) => s.schema);
1366
1672
  if (schemasWithOpenApiDef.length === 0) return "";
1367
1673
  const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
@@ -1376,7 +1682,10 @@ function generateZodSchemasInline(builder, output) {
1376
1682
  workspace: "",
1377
1683
  output
1378
1684
  };
1379
- const parsedZodDefinition = parseZodValidationSchemaDefinition(generateZodValidationSchemaDefinition(dereference(schemaObject, context), context, name, strict, isZodV4, { required: true }), context, coerce, strict, isZodV4);
1685
+ const parsedZodDefinition = parseZodValidationSchemaDefinition(generateZodValidationSchemaDefinition(dereference(schemaObject, context), context, name, strict, isZodV4, {
1686
+ required: true,
1687
+ emitMeta: output.override.zod.generateMeta
1688
+ }), context, coerce, strict, isZodV4);
1380
1689
  schemas.push({
1381
1690
  schemaName: name,
1382
1691
  consts: parsedZodDefinition.consts,
@@ -1384,9 +1693,38 @@ function generateZodSchemasInline(builder, output) {
1384
1693
  });
1385
1694
  }
1386
1695
  if (schemas.length === 0) return "";
1387
- return generateZodSchemaFileContent("", schemas);
1696
+ return generateZodSchemaFileContent("", schemas, includeZodImport);
1697
+ }
1698
+ function generateZodSchemasInlineReusable(builder, output, includeZodImport = true, paramsMutator, includeParamsImport = false) {
1699
+ const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1700
+ const strict = output.override.zod.strict.body;
1701
+ const coerce = output.override.zod.coerce.body;
1702
+ const context = {
1703
+ spec: builder.spec,
1704
+ target: builder.target,
1705
+ workspace: "",
1706
+ output
1707
+ };
1708
+ const componentSchemas = builder.spec.components?.schemas ?? {};
1709
+ const refs = Object.keys(componentSchemas).map((schemaName) => `#/components/schemas/${schemaName}`);
1710
+ if (refs.length === 0) return "";
1711
+ resolveSchemaNames(refs, context);
1712
+ const body = rewriteReusableSchemas(generateReusableSchemaSet(refs, context, {
1713
+ strict,
1714
+ isZodV4,
1715
+ coerce,
1716
+ generateMeta: output.override.zod.generateMeta,
1717
+ paramsMutator
1718
+ })).map((entry) => renderReusableSchemaEntry(entry, context).content).join("\n\n");
1719
+ const zodImport = includeZodImport ? `import { z as zod } from 'zod';\n` : "";
1720
+ const paramsImport = paramsMutator && includeParamsImport && bodyReferencesMutator(body, paramsMutator) ? `${buildMutatorImportStatement(paramsMutator)}\n` : "";
1721
+ return `${zodImport || paramsImport ? `${zodImport}${paramsImport}\n` : ""}${body}\n`;
1388
1722
  }
1389
- async function writeZodSchemas(builder, schemasPath, fileExtension, header, output) {
1723
+ async function writeZodSchemas(builder, schemasPath, fileExtension, header, output, paramsMutator) {
1724
+ if (output.override.zod.generateReusableSchemas) {
1725
+ await writeZodSchemasReusable(builder, schemasPath, fileExtension, header, output, paramsMutator);
1726
+ return;
1727
+ }
1390
1728
  const schemasWithOpenApiDef = builder.schemas.filter((s) => s.schema);
1391
1729
  const schemasToWrite = [];
1392
1730
  const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
@@ -1403,7 +1741,10 @@ async function writeZodSchemas(builder, schemasPath, fileExtension, header, outp
1403
1741
  workspace: "",
1404
1742
  output
1405
1743
  };
1406
- const parsedZodDefinition = parseZodValidationSchemaDefinition(generateZodValidationSchemaDefinition(dereference(schemaObject, context), context, name, strict, isZodV4, { required: true }), context, coerce, strict, isZodV4);
1744
+ const parsedZodDefinition = parseZodValidationSchemaDefinition(generateZodValidationSchemaDefinition(dereference(schemaObject, context), context, name, strict, isZodV4, {
1745
+ required: true,
1746
+ emitMeta: output.override.zod.generateMeta
1747
+ }), context, coerce, strict, isZodV4);
1407
1748
  schemasToWrite.push({
1408
1749
  schemaName: name,
1409
1750
  filePath,
@@ -1418,6 +1759,47 @@ async function writeZodSchemas(builder, schemasPath, fileExtension, header, outp
1418
1759
  }
1419
1760
  if (output.indexFiles) await writeZodSchemaIndex(schemasPath, fileExtension, header, groupedSchemasToWrite.map((schemaGroup) => schemaGroup[0].schemaName), output.namingConvention, false);
1420
1761
  }
1762
+ async function writeZodSchemasReusable(builder, schemasPath, fileExtension, header, output, paramsMutator) {
1763
+ const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1764
+ const strict = output.override.zod.strict.body;
1765
+ const coerce = output.override.zod.coerce.body;
1766
+ const context = {
1767
+ spec: builder.spec,
1768
+ target: builder.target,
1769
+ workspace: "",
1770
+ output
1771
+ };
1772
+ const componentSchemas = builder.spec.components?.schemas ?? {};
1773
+ const refs = Object.keys(componentSchemas).map((schemaName) => `#/components/schemas/${schemaName}`);
1774
+ resolveSchemaNames(refs, context);
1775
+ const rewritten = rewriteReusableSchemas(generateReusableSchemaSet(refs, context, {
1776
+ strict,
1777
+ isZodV4,
1778
+ coerce,
1779
+ generateMeta: output.override.zod.generateMeta,
1780
+ paramsMutator
1781
+ }));
1782
+ const componentNames = new Set(Object.keys(builder.spec.components?.schemas ?? {}).map((schemaName) => resolveSchemaName(`#/components/schemas/${schemaName}`, context)));
1783
+ const paramsMutatorImport = paramsMutator ? buildMutatorImportStatement(paramsMutator) : void 0;
1784
+ for (const entry of rewritten) {
1785
+ const fileName = conventionName(entry.name, output.namingConvention);
1786
+ const filePath = path.join(schemasPath, `${fileName}${fileExtension}`);
1787
+ const importExt = fileExtension.replace(/\.ts$/, "");
1788
+ const rendered = renderReusableSchemaEntry(entry, context);
1789
+ const refImports = buildSiblingImports({
1790
+ usedRefs: entry.usedRefs,
1791
+ extraImports: rendered.extraImports,
1792
+ entryName: entry.name,
1793
+ componentNames,
1794
+ namingConvention: output.namingConvention,
1795
+ importExt
1796
+ });
1797
+ const imports = [...!!paramsMutator && bodyReferencesMutator(entry.zod, paramsMutator) && paramsMutatorImport ? [paramsMutatorImport] : [], ...refImports ? [refImports] : []].join("\n");
1798
+ const fileContent = `${header}import { z as zod } from 'zod';\n` + (imports ? `${imports}\n\n` : "\n") + `${rendered.content}\n`;
1799
+ await fs.outputFile(filePath, fileContent);
1800
+ }
1801
+ if (output.indexFiles && rewritten.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, rewritten.map((e) => e.name), output.namingConvention, true);
1802
+ }
1421
1803
  async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension, header, output, context) {
1422
1804
  const zodContext = context;
1423
1805
  const verbOptionsArray = Object.values(verbOptions);
@@ -1425,6 +1807,7 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1425
1807
  const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1426
1808
  const strict = output.override.zod.strict.body;
1427
1809
  const coerce = output.override.zod.coerce.body;
1810
+ const useReusableSchemas = output.override.zod.generateReusableSchemas === true;
1428
1811
  const uniqueVerbsSchemas = dedupeSchemasByName(verbOptionsArray.flatMap((verbOption) => {
1429
1812
  const operation = verbOption.originalOperation;
1430
1813
  const shouldGenerate = {
@@ -1440,7 +1823,7 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1440
1823
  const bodySchema = bodyMedia?.schema;
1441
1824
  const bodySchemas = shouldGenerate.body && bodySchema ? [{
1442
1825
  name: `${pascal(verbOption.operationName)}Body`,
1443
- schema: dereference(bodySchema, zodContext),
1826
+ schema: useReusableSchemas ? bodySchema : dereference(bodySchema, zodContext),
1444
1827
  bodyContentType,
1445
1828
  encoding: bodyMedia?.encoding
1446
1829
  }] : [];
@@ -1450,7 +1833,7 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1450
1833
  name: `${pascal(verbOption.operationName)}Params`,
1451
1834
  schema: {
1452
1835
  type: "object",
1453
- properties: Object.fromEntries(queryParams.filter((p) => "schema" in p && p.schema).map((p) => [p.name, dereference(p.schema, zodContext)])),
1836
+ properties: Object.fromEntries(queryParams.filter((p) => "schema" in p && p.schema).map((p) => [p.name, useReusableSchemas ? p.schema : dereference(p.schema, zodContext)])),
1454
1837
  required: queryParams.filter((p) => p.required).map((p) => p.name).filter((name) => name !== void 0)
1455
1838
  }
1456
1839
  }] : [];
@@ -1459,13 +1842,13 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1459
1842
  name: `${pascal(verbOption.operationName)}Headers`,
1460
1843
  schema: {
1461
1844
  type: "object",
1462
- properties: Object.fromEntries(headerParams.filter((p) => "schema" in p && p.schema).map((p) => [p.name, dereference(p.schema, zodContext)])),
1845
+ properties: Object.fromEntries(headerParams.filter((p) => "schema" in p && p.schema).map((p) => [p.name, useReusableSchemas ? p.schema : dereference(p.schema, zodContext)])),
1463
1846
  required: headerParams.filter((p) => p.required).map((p) => p.name).filter((name) => name !== void 0)
1464
1847
  }
1465
1848
  }] : [];
1466
1849
  const responseSchemas = shouldGenerate.response ? [...verbOption.response.types.success, ...verbOption.response.types.errors].filter((responseType) => !!responseType.originalSchema && !responseType.isRef && isValidSchemaIdentifier(responseType.value) && !isPrimitiveSchemaName(responseType.value)).map((responseType) => ({
1467
1850
  name: responseType.value,
1468
- schema: dereference(responseType.originalSchema, zodContext)
1851
+ schema: useReusableSchemas ? responseType.originalSchema : dereference(responseType.originalSchema, zodContext)
1469
1852
  })) : [];
1470
1853
  return dedupeSchemasByName([
1471
1854
  ...bodySchemas,
@@ -1476,15 +1859,29 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1476
1859
  }));
1477
1860
  const schemasToWrite = [];
1478
1861
  for (const entry of uniqueVerbsSchemas) {
1862
+ if (useReusableSchemas && entry.schema && typeof entry.schema.$ref === "string" && Object.keys(entry.schema).length === 1) continue;
1479
1863
  const { name, schema } = entry;
1480
1864
  const fileName = conventionName(name, output.namingConvention);
1481
1865
  const filePath = path.join(schemasPath, `${fileName}${fileExtension}`);
1482
- const parsedZodDefinition = parseZodValidationSchemaDefinition("bodyContentType" in entry && entry.bodyContentType === "multipart/form-data" ? generateFormDataZodSchema(schema, zodContext, name, strict, isZodV4, "encoding" in entry ? entry.encoding : void 0) : generateZodValidationSchemaDefinition(schema, zodContext, name, strict, isZodV4, { required: true }), zodContext, coerce, strict, isZodV4);
1866
+ 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, {
1867
+ required: true,
1868
+ useReusableSchemas
1869
+ }), zodContext, coerce, strict, isZodV4);
1870
+ let zodExpression = parsedZodDefinition.zod;
1871
+ let importStatements;
1872
+ if (useReusableSchemas && parsedZodDefinition.usedRefs.size > 0) {
1873
+ zodExpression = rewriteSentinelsToDirect(zodExpression);
1874
+ const importExt = fileExtension.replace(/\.ts$/, "");
1875
+ importStatements = [...parsedZodDefinition.usedRefs].filter((refName) => refName !== name).toSorted().map((refName) => {
1876
+ return `import { ${refName} } from './${conventionName(refName, output.namingConvention)}${importExt}';`;
1877
+ });
1878
+ }
1483
1879
  schemasToWrite.push({
1484
1880
  schemaName: name,
1485
1881
  filePath,
1486
1882
  consts: parsedZodDefinition.consts,
1487
- zodExpression: parsedZodDefinition.zod
1883
+ zodExpression,
1884
+ importStatements
1488
1885
  });
1489
1886
  }
1490
1887
  const groupedSchemasToWrite = groupSchemasByFilePath(schemasToWrite);
@@ -1545,118 +1942,168 @@ async function addOperationSchemasReExport(schemaPath, operationSchemasPath, hea
1545
1942
  await fs.outputFile(schemaIndexPath, content);
1546
1943
  }
1547
1944
  }
1945
+ /**
1946
+ * Emit `<schemas-dir>/index.faker.ts` (or `<output-root>/schemas.faker.ts`
1947
+ * when `output.schemas` is not configured) when a faker generator entry has
1948
+ * `schemas: true`. Each `components/schemas` entry becomes a
1949
+ * `get<SchemaName>Mock(overrides)` factory in the file. Returns the written
1950
+ * file path so callers can include it in formatter / hook runs, or
1951
+ * `undefined` if no file was written.
1952
+ */
1953
+ async function writeFakerSchemaMocks(builder, options, header) {
1954
+ const { output } = options;
1955
+ const fakerEntry = output.mock.generators.find((g) => !isFunction(g) && g.type === OutputMockType.FAKER && g.schemas === true);
1956
+ if (!fakerEntry) return;
1957
+ const schemasWithDef = builder.schemas.filter((s) => !!s.schema);
1958
+ if (schemasWithDef.length === 0) return;
1959
+ const { implementation, imports } = generateFakerForSchemas(schemasWithDef, {
1960
+ spec: builder.spec,
1961
+ target: builder.target,
1962
+ workspace: "",
1963
+ output
1964
+ }, fakerEntry);
1965
+ if (!implementation.trim()) return;
1966
+ let filePath;
1967
+ let schemaImportPath;
1968
+ const fileExtension = output.fileExtension || ".ts";
1969
+ if (output.schemas) {
1970
+ const schemasDir = isString(output.schemas) ? output.schemas : output.schemas.path;
1971
+ filePath = path.join(schemasDir, `index.faker${fileExtension}`);
1972
+ schemaImportPath = ".";
1973
+ } else {
1974
+ const targetInfo = output.target ? getFileInfo(output.target, { extension: fileExtension }) : void 0;
1975
+ const dir = targetInfo?.dirname ?? process.cwd();
1976
+ filePath = path.join(dir, `schemas.faker${fileExtension}`);
1977
+ schemaImportPath = targetInfo ? `./${targetInfo.filename}${getImportExtension(fileExtension, output.tsconfig)}` : void 0;
1978
+ }
1979
+ const reroutedImports = imports.map((imp) => imp.importPath ? imp : {
1980
+ ...imp,
1981
+ importPath: schemaImportPath
1982
+ });
1983
+ const grouped = /* @__PURE__ */ new Map();
1984
+ for (const imp of reroutedImports) {
1985
+ const key = imp.importPath ?? "";
1986
+ if (!key) continue;
1987
+ const bucket = grouped.get(key) ?? [];
1988
+ bucket.push(imp);
1989
+ grouped.set(key, bucket);
1990
+ }
1991
+ const content = `${header}${generateDependencyImports(implementation, [{
1992
+ exports: [{
1993
+ name: "faker",
1994
+ values: true
1995
+ }],
1996
+ dependency: fakerEntry.locale ? `@faker-js/faker/locale/${fakerEntry.locale}` : "@faker-js/faker"
1997
+ }, ...[...grouped.entries()].map(([dependency, exports]) => ({
1998
+ exports,
1999
+ dependency
2000
+ }))], void 0, !!output.schemas, false)}\n\n${implementation}`;
2001
+ await writeGeneratedFile(filePath, content);
2002
+ return filePath;
2003
+ }
2004
+ function isSchemaValidatorClient(client) {
2005
+ return client === "zod" || client === "effect";
2006
+ }
2007
+ function shouldGenerateZodSchemasInline(output, hasOperations) {
2008
+ if (output.client !== "zod" || output.schemas) return false;
2009
+ if (output.override.zod.generateReusableSchemas) return true;
2010
+ return !hasOperations;
2011
+ }
2012
+ function shouldGenerateSchemas(output, hasOperations) {
2013
+ return !output.schemas && !isSchemaValidatorClient(output.client) || shouldGenerateZodSchemasInline(output, hasOperations);
2014
+ }
1548
2015
  async function writeSpecs(builder, workspace, options, projectName) {
1549
2016
  const { info, schemas, target } = builder;
1550
2017
  const { output } = options;
1551
2018
  const projectTitle = projectName ?? info.title;
1552
2019
  const header = getHeader(output.override.header, info);
1553
- if (output.schemas) if (isString(output.schemas)) {
1554
- const fileExtension = output.fileExtension || ".ts";
1555
- const schemaPath = output.schemas;
1556
- if (output.operationSchemas) {
1557
- const { regularSchemas, operationSchemas: opSchemas } = splitSchemasByType(schemas);
1558
- const regularSchemaNames = new Set(regularSchemas.map((s) => s.name));
1559
- const operationSchemaNames = new Set(opSchemas.map((s) => s.name));
1560
- fixCrossDirectoryImports(opSchemas, regularSchemaNames, schemaPath, output.operationSchemas, output.namingConvention, fileExtension, output.tsconfig);
1561
- fixRegularSchemaImports(regularSchemas, operationSchemaNames, schemaPath, output.operationSchemas, output.namingConvention, fileExtension, output.tsconfig);
1562
- if (regularSchemas.length > 0) await writeSchemas({
1563
- schemaPath,
1564
- schemas: regularSchemas,
1565
- target,
1566
- namingConvention: output.namingConvention,
1567
- fileExtension,
1568
- header,
1569
- indexFiles: output.indexFiles,
2020
+ if (output.schemas) {
2021
+ const schemasPath = isString(output.schemas) ? output.schemas : output.schemas.path;
2022
+ if (!isString(output.schemas) && output.schemas.type === "zod" || isString(output.schemas) && output.client === "zod" && output.override.zod.generateReusableSchemas) {
2023
+ const fileExtension = output.schemaFileExtension;
2024
+ await writeZodSchemas(builder, schemasPath, fileExtension, header, output, output.override.zod.params ? await generateMutator({
2025
+ output: path.join(schemasPath, `__params__${fileExtension}`),
2026
+ mutator: output.override.zod.params,
2027
+ name: "zodParams",
2028
+ workspace,
1570
2029
  tsconfig: output.tsconfig
2030
+ }) : void 0);
2031
+ await writeZodSchemasFromVerbs(builder.verbOptions, schemasPath, fileExtension, header, output, {
2032
+ spec: builder.spec,
2033
+ target: builder.target,
2034
+ workspace,
2035
+ output
1571
2036
  });
1572
- if (opSchemas.length > 0) {
1573
- await writeSchemas({
1574
- schemaPath: output.operationSchemas,
1575
- schemas: opSchemas,
2037
+ } else {
2038
+ const fileExtension = output.fileExtension || ".ts";
2039
+ if (output.operationSchemas) {
2040
+ const { regularSchemas, operationSchemas: opSchemas } = splitSchemasByType(schemas);
2041
+ const regularSchemaNames = new Set(regularSchemas.map((s) => s.name));
2042
+ const operationSchemaNames = new Set(opSchemas.map((s) => s.name));
2043
+ fixCrossDirectoryImports(opSchemas, regularSchemaNames, schemasPath, output.operationSchemas, output.namingConvention, fileExtension, output.tsconfig);
2044
+ fixRegularSchemaImports(regularSchemas, operationSchemaNames, schemasPath, output.operationSchemas, output.namingConvention, fileExtension, output.tsconfig);
2045
+ if (regularSchemas.length > 0) await writeSchemas({
2046
+ schemaPath: schemasPath,
2047
+ schemas: regularSchemas,
1576
2048
  target,
1577
2049
  namingConvention: output.namingConvention,
1578
2050
  fileExtension,
1579
2051
  header,
1580
2052
  indexFiles: output.indexFiles,
1581
- tsconfig: output.tsconfig
2053
+ tsconfig: output.tsconfig,
2054
+ factoryOutputDirectory: output.factoryMethods?.outputDirectory
1582
2055
  });
1583
- if (output.indexFiles) await addOperationSchemasReExport(schemaPath, output.operationSchemas, header);
1584
- }
1585
- } else await writeSchemas({
1586
- schemaPath,
1587
- schemas,
1588
- target,
1589
- namingConvention: output.namingConvention,
1590
- fileExtension,
1591
- header,
1592
- indexFiles: output.indexFiles,
1593
- tsconfig: output.tsconfig
1594
- });
1595
- } else if (output.schemas.type === "typescript") {
1596
- const fileExtension = output.fileExtension || ".ts";
1597
- if (output.operationSchemas) {
1598
- const { regularSchemas, operationSchemas: opSchemas } = splitSchemasByType(schemas);
1599
- const regularSchemaNames = new Set(regularSchemas.map((s) => s.name));
1600
- const operationSchemaNames = new Set(opSchemas.map((s) => s.name));
1601
- fixCrossDirectoryImports(opSchemas, regularSchemaNames, output.schemas.path, output.operationSchemas, output.namingConvention, fileExtension, output.tsconfig);
1602
- fixRegularSchemaImports(regularSchemas, operationSchemaNames, output.schemas.path, output.operationSchemas, output.namingConvention, fileExtension, output.tsconfig);
1603
- if (regularSchemas.length > 0) await writeSchemas({
1604
- schemaPath: output.schemas.path,
1605
- schemas: regularSchemas,
2056
+ if (opSchemas.length > 0) {
2057
+ await writeSchemas({
2058
+ schemaPath: output.operationSchemas,
2059
+ schemas: opSchemas,
2060
+ target,
2061
+ namingConvention: output.namingConvention,
2062
+ fileExtension,
2063
+ header,
2064
+ indexFiles: output.indexFiles,
2065
+ tsconfig: output.tsconfig,
2066
+ factoryOutputDirectory: output.factoryMethods?.outputDirectory
2067
+ });
2068
+ if (output.indexFiles) await addOperationSchemasReExport(schemasPath, output.operationSchemas, header);
2069
+ }
2070
+ } else await writeSchemas({
2071
+ schemaPath: schemasPath,
2072
+ schemas,
1606
2073
  target,
1607
2074
  namingConvention: output.namingConvention,
1608
2075
  fileExtension,
1609
2076
  header,
1610
2077
  indexFiles: output.indexFiles,
1611
- tsconfig: output.tsconfig
2078
+ tsconfig: output.tsconfig,
2079
+ factoryOutputDirectory: output.factoryMethods?.outputDirectory
1612
2080
  });
1613
- if (opSchemas.length > 0) {
1614
- await writeSchemas({
1615
- schemaPath: output.operationSchemas,
1616
- schemas: opSchemas,
1617
- target,
1618
- namingConvention: output.namingConvention,
1619
- fileExtension,
1620
- header,
1621
- indexFiles: output.indexFiles,
1622
- tsconfig: output.tsconfig
1623
- });
1624
- if (output.indexFiles) await addOperationSchemasReExport(output.schemas.path, output.operationSchemas, header);
1625
- }
1626
- } else await writeSchemas({
1627
- schemaPath: output.schemas.path,
1628
- schemas,
1629
- target,
1630
- namingConvention: output.namingConvention,
1631
- fileExtension,
1632
- header,
1633
- indexFiles: output.indexFiles,
1634
- tsconfig: output.tsconfig
1635
- });
1636
- } else {
1637
- const fileExtension = ".zod.ts";
1638
- await writeZodSchemas(builder, output.schemas.path, fileExtension, header, output);
1639
- await writeZodSchemasFromVerbs(builder.verbOptions, output.schemas.path, fileExtension, header, output, {
1640
- spec: builder.spec,
1641
- target: builder.target,
1642
- workspace,
1643
- output
1644
- });
2081
+ }
1645
2082
  }
2083
+ const fakerSchemaPath = await writeFakerSchemaMocks(builder, options, header);
1646
2084
  let implementationPaths = [];
1647
2085
  if (output.target) {
1648
2086
  const writeMode = getWriteMode(output.mode);
1649
- const isZodClient = output.client === "zod";
1650
2087
  const hasOperations = Object.keys(builder.operations).length > 0;
1651
- const needZodSchemasInline = isZodClient && !output.schemas && !hasOperations;
2088
+ const needZodSchemasInline = shouldGenerateZodSchemasInline(output, hasOperations);
2089
+ const includeZodImport = !Object.values(builder.operations).some((operation) => /\bzod\b/.test(operation.implementation));
2090
+ const inlineSchemasParamsMutator = needZodSchemasInline && output.override.zod.params ? await generateMutator({
2091
+ output: output.target,
2092
+ mutator: output.override.zod.params,
2093
+ name: "zodParams",
2094
+ workspace,
2095
+ tsconfig: output.tsconfig
2096
+ }) : void 0;
2097
+ const isSchemasInSeparateFile = output.mode !== OutputMode.SINGLE;
2098
+ const includeParamsImport = !hasOperations || isSchemasInSeparateFile;
1652
2099
  implementationPaths = await writeMode({
1653
2100
  builder,
1654
2101
  workspace,
1655
2102
  output,
1656
2103
  projectName,
1657
2104
  header,
1658
- needSchema: !output.schemas && !isZodClient || needZodSchemasInline,
1659
- generateSchemasInline: needZodSchemasInline ? () => generateZodSchemasInline(builder, output) : void 0
2105
+ needSchema: shouldGenerateSchemas(output, hasOperations),
2106
+ generateSchemasInline: needZodSchemasInline ? () => generateZodSchemasInline(builder, output, includeZodImport, inlineSchemasParamsMutator, includeParamsImport) : void 0
1660
2107
  });
1661
2108
  }
1662
2109
  if (output.workspace) {
@@ -1684,6 +2131,7 @@ async function writeSpecs(builder, workspace, options, projectName) {
1684
2131
  }
1685
2132
  const paths = [
1686
2133
  ...output.schemas ? [getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path).dirname] : [],
2134
+ ...fakerSchemaPath ? [fakerSchemaPath] : [],
1687
2135
  ...output.operationSchemas ? [getFileInfo(output.operationSchemas).dirname] : [],
1688
2136
  ...implementationPaths
1689
2137
  ];
@@ -1814,4 +2262,4 @@ async function loadConfigFile(configFilePath) {
1814
2262
  //#endregion
1815
2263
  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 };
1816
2264
 
1817
- //# sourceMappingURL=config-DDQgHurQ.mjs.map
2265
+ //# sourceMappingURL=config-yIkhToq8.mjs.map