orval 8.12.3 → 8.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { c as description, i as startWatcher, l as name, n as loadConfigFile, r as generateSpec, s as normalizeOptions, t as findConfigFile, u as version } from "../config-DDQgHurQ.mjs";
2
+ import { c as description, i as startWatcher, l as name, n as loadConfigFile, r as generateSpec, s as normalizeOptions, t as findConfigFile, u as version } from "../config-Cyybmy9c.mjs";
3
3
  import path from "node:path";
4
4
  import { Option, program } from "@commander-js/extra-typings";
5
5
  import { ErrorWithTag, OutputClient, OutputMode, SupportedFormatter, getWarningCount, isString, log, logError, resetWarnings, setVerbose, startMessage } from "@orval/core";
@@ -1,11 +1,11 @@
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, generateParameterDefinition, generateSchemasDefinition, generateVerbsOptions, getBaseUrlRuntimeImports, getFileInfo, getFullRoute, getImportExtension, getMockFileExtensionByTypeName, getRoute, isBoolean, isFunction, isNullish, isObject, isReference, isString, isUrl, jsDoc, log, logError, logVerbose, logWarning, pascal, removeFilesAndEmptyFolders, resolveInstalledVersions, resolveRef, 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
11
  import fetchClient from "@orval/fetch";
@@ -28,7 +28,7 @@ import { createJiti } from "jiti";
28
28
  //#region package.json
29
29
  var name = "orval";
30
30
  var description = "A swagger client generator for typescript";
31
- var version = "8.12.3";
31
+ var version = "8.13.0";
32
32
  //#endregion
33
33
  //#region src/client.ts
34
34
  const DEFAULT_CLIENT = OutputClient.AXIOS;
@@ -162,7 +162,10 @@ const generateOperations = (outputClient = DEFAULT_CLIENT, verbsOptions, options
162
162
  const { client: generatorClient } = getGeneratorClient(outputClient, output);
163
163
  const client = await generatorClient(verbOption, options, outputClient, output);
164
164
  if (!client.implementation) return acc;
165
- const mockOutputs = output.mock.generators.map((entry) => {
165
+ const mockOutputs = output.mock.generators.filter((entry) => {
166
+ if (!isFunction(entry) && entry.type === OutputMockType.FAKER && entry.operationResponses === false) return false;
167
+ return true;
168
+ }).map((entry) => {
166
169
  const generated = invokeMockGenerator(verbOption, options, entry);
167
170
  return {
168
171
  type: isFunction(entry) ? OutputMockType.MSW : entry.type,
@@ -891,6 +894,15 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
891
894
  seenMockTypes.add(entry.type);
892
895
  }
893
896
  const defaultFileExtension = ".ts";
897
+ 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;
898
+ const factoryMethodsConfig = outputOptions.factoryMethods;
899
+ let factoryMethods = void 0;
900
+ if (factoryMethodsConfig) factoryMethods = {
901
+ functionNamePrefix: factoryMethodsConfig.functionNamePrefix ?? "create",
902
+ mode: factoryMethodsConfig.mode ?? "split",
903
+ outputDirectory: factoryMethodsConfig.outputDirectory ? normalizePath(factoryMethodsConfig.outputDirectory, outputWorkspace) : outputOptions.schemas ? normalizePath(isString(outputOptions.schemas) ? outputOptions.schemas : outputOptions.schemas.path, outputWorkspace) : normalizePath(outputWorkspace, outputWorkspace),
904
+ includeOptionalProperty: factoryMethodsConfig.includeOptionalProperty ?? true
905
+ };
894
906
  const globalQueryOptions = {
895
907
  signal: true,
896
908
  shouldExportMutatorHooks: true,
@@ -913,6 +925,7 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
913
925
  operationSchemas: outputOptions.operationSchemas ? normalizePath(outputOptions.operationSchemas, outputWorkspace) : void 0,
914
926
  namingConvention: outputOptions.namingConvention ?? NamingConvention.CAMEL_CASE,
915
927
  fileExtension: outputOptions.fileExtension ?? defaultFileExtension,
928
+ schemaFileExtension: outputOptions.schemaFileExtension ?? outputOptions.fileExtension ?? defaultSchemaFileExtension,
916
929
  workspace: outputOptions.workspace ? outputWorkspace : void 0,
917
930
  client: outputOptions.client ?? client ?? OutputClient.AXIOS_FUNCTIONS,
918
931
  httpClient: outputOptions.httpClient ?? httpClient ?? ((outputOptions.client ?? client) === OutputClient.ANGULAR_QUERY ? OutputHttpClient.ANGULAR : OutputHttpClient.FETCH),
@@ -927,6 +940,7 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
927
940
  indexFiles: outputOptions.indexFiles ?? true,
928
941
  baseUrl: outputOptions.baseUrl,
929
942
  unionAddMissingProperties: outputOptions.unionAddMissingProperties ?? false,
943
+ factoryMethods,
930
944
  override: {
931
945
  ...outputOptions.override,
932
946
  mock: {
@@ -1001,6 +1015,7 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
1001
1015
  },
1002
1016
  generateEachHttpStatus: outputOptions.override?.zod?.generateEachHttpStatus ?? false,
1003
1017
  useBrandedTypes: outputOptions.override?.zod?.useBrandedTypes ?? false,
1018
+ generateReusableSchemas: outputOptions.override?.zod?.generateReusableSchemas ?? false,
1004
1019
  dateTimeOptions: outputOptions.override?.zod?.dateTimeOptions ?? { offset: true },
1005
1020
  timeOptions: outputOptions.override?.zod?.timeOptions ?? {}
1006
1021
  },
@@ -1170,6 +1185,7 @@ function normalizeOperationsAndTags(operationsOrTags, workspace, global) {
1170
1185
  },
1171
1186
  generateEachHttpStatus: zod.generateEachHttpStatus ?? false,
1172
1187
  useBrandedTypes: zod.useBrandedTypes ?? false,
1188
+ generateReusableSchemas: zod.generateReusableSchemas ?? false,
1173
1189
  dateTimeOptions: zod.dateTimeOptions ?? { offset: true },
1174
1190
  timeOptions: zod.timeOptions ?? {}
1175
1191
  } } : {},
@@ -1308,6 +1324,158 @@ async function startWatcher(watchOptions, watchFn, defaultTarget = ".") {
1308
1324
  });
1309
1325
  }
1310
1326
  //#endregion
1327
+ //#region src/reusable-schemas.ts
1328
+ const lastRefSegment = (ref) => {
1329
+ const raw = ref.split("/").pop() ?? "";
1330
+ return decodeURIComponent(raw).replaceAll("~1", "/").replaceAll("~0", "~");
1331
+ };
1332
+ /**
1333
+ * Convert a single `#/components/schemas/X` ref into the export name we will
1334
+ * emit for it: the last `$ref` segment with `namingConvention` applied.
1335
+ */
1336
+ const resolveSchemaName = (ref, namingConvention) => conventionName(lastRefSegment(ref), namingConvention);
1337
+ const JS_IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
1338
+ /**
1339
+ * Resolve names for a set of refs, throwing on conflicts or on names that
1340
+ * aren't valid JS identifiers (e.g. `kebab-case` produces dashes). The mapping
1341
+ * is the single source of truth for cross-schema references — the generator,
1342
+ * the orchestrator's graph, and the sentinel rewriter all consult it.
1343
+ */
1344
+ const resolveSchemaNames = (refs, namingConvention) => {
1345
+ const resolved = /* @__PURE__ */ new Map();
1346
+ const reverse = /* @__PURE__ */ new Map();
1347
+ for (const ref of refs) {
1348
+ const name = resolveSchemaName(ref, namingConvention);
1349
+ if (!JS_IDENTIFIER_PATTERN.test(name)) throw new Error(`[orval/zod] generateReusableSchemas: ref ${ref} converts to "${name}" under namingConvention=${namingConvention}, which is not a valid JS identifier. Use camelCase, PascalCase, or snake_case for the project's namingConvention when this flag is enabled.`);
1350
+ const previous = reverse.get(name);
1351
+ if (previous !== void 0 && previous !== ref) throw new Error(`[orval/zod] generateReusableSchemas: refs ${previous} and ${ref} both convert to "${name}" under namingConvention=${namingConvention}. Rename one in the OpenAPI source or change the convention.`);
1352
+ resolved.set(ref, name);
1353
+ reverse.set(name, ref);
1354
+ }
1355
+ return resolved;
1356
+ };
1357
+ /**
1358
+ * For each component-schema ref, run the Zod generator + parser with
1359
+ * `useReusableSchemas: true`. The resulting `zod` strings contain
1360
+ * `__REF_<name>__` sentinels at every site that references another schema;
1361
+ * the SCC step (Task 10) decides whether each sentinel becomes a direct
1362
+ * identifier or a `z.lazy(() => Name)` wrapper.
1363
+ */
1364
+ const generateReusableSchemaSet = (refs, context, options) => {
1365
+ const componentSchemas = context.spec.components?.schemas ?? {};
1366
+ const nameToRef = /* @__PURE__ */ new Map();
1367
+ for (const schemaName of Object.keys(componentSchemas)) {
1368
+ const ref = `#/components/schemas/${schemaName}`;
1369
+ nameToRef.set(resolveSchemaName(ref, context.output.namingConvention), ref);
1370
+ }
1371
+ const queue = [...refs];
1372
+ const seen = new Set(refs);
1373
+ const entries = [];
1374
+ for (const ref of queue) {
1375
+ const schema = componentSchemas[ref.slice(21)];
1376
+ if (!schema) continue;
1377
+ const name = resolveSchemaName(ref, context.output.namingConvention);
1378
+ const parsed = parseZodValidationSchemaDefinition(generateZodValidationSchemaDefinition(schema, context, name, options.strict, options.isZodV4, {
1379
+ required: true,
1380
+ useReusableSchemas: true
1381
+ }), context, options.coerce ?? false, options.strict, options.isZodV4);
1382
+ entries.push({
1383
+ ref,
1384
+ name,
1385
+ zod: parsed.zod,
1386
+ consts: parsed.consts,
1387
+ usedRefs: parsed.usedRefs
1388
+ });
1389
+ for (const usedName of parsed.usedRefs) {
1390
+ const usedRef = nameToRef.get(usedName);
1391
+ if (usedRef !== void 0 && !seen.has(usedRef)) {
1392
+ seen.add(usedRef);
1393
+ queue.push(usedRef);
1394
+ }
1395
+ }
1396
+ }
1397
+ return entries;
1398
+ };
1399
+ const edgeKey = (from, to) => `${from}->${to}`;
1400
+ const tarjan = (graph) => {
1401
+ let index = 0;
1402
+ const stack = [];
1403
+ const onStack = /* @__PURE__ */ new Set();
1404
+ const indices = /* @__PURE__ */ new Map();
1405
+ const lowlinks = /* @__PURE__ */ new Map();
1406
+ const sccs = [];
1407
+ const lazyEdges = /* @__PURE__ */ new Set();
1408
+ const strongconnect = (v) => {
1409
+ indices.set(v, index);
1410
+ lowlinks.set(v, index);
1411
+ index += 1;
1412
+ stack.push(v);
1413
+ onStack.add(v);
1414
+ const neighbors = graph.get(v) ?? /* @__PURE__ */ new Set();
1415
+ for (const w of neighbors) {
1416
+ if (v === w) {
1417
+ lazyEdges.add(edgeKey(v, w));
1418
+ continue;
1419
+ }
1420
+ if (!indices.has(w)) {
1421
+ strongconnect(w);
1422
+ lowlinks.set(v, Math.min(lowlinks.get(v) ?? -1, lowlinks.get(w) ?? -1));
1423
+ } else if (onStack.has(w)) {
1424
+ lazyEdges.add(edgeKey(v, w));
1425
+ lowlinks.set(v, Math.min(lowlinks.get(v) ?? -1, indices.get(w) ?? -1));
1426
+ }
1427
+ }
1428
+ if (lowlinks.get(v) === indices.get(v)) {
1429
+ const scc = [];
1430
+ let w;
1431
+ do {
1432
+ w = stack.pop();
1433
+ if (w === void 0) break;
1434
+ onStack.delete(w);
1435
+ scc.push(w);
1436
+ } while (w !== v);
1437
+ sccs.push(scc);
1438
+ }
1439
+ };
1440
+ for (const node of graph.keys()) if (!indices.has(node)) strongconnect(node);
1441
+ return {
1442
+ sccs,
1443
+ lazyEdges
1444
+ };
1445
+ };
1446
+ const SENTINEL_PATTERN = /__REF_([A-Za-z_$][A-Za-z0-9_$]*)__/g;
1447
+ /**
1448
+ * Replace every `__REF_<name>__` sentinel with either the bare identifier or
1449
+ * `zod.lazy(() => <name>)` based on whether the edge closes a cycle, then
1450
+ * reorder entries so that every non-lazy reference is emitted AFTER its
1451
+ * target. This avoids TDZ errors at module load.
1452
+ *
1453
+ * Both the lazy classification and the emit order come from a single Tarjan
1454
+ * run, guaranteeing they agree: a non-lazy edge u→v means v is visited (and
1455
+ * popped) before u in DFS, so v appears earlier in the SCC array → emitted
1456
+ * before u → safe.
1457
+ */
1458
+ const rewriteReusableSchemas = (entries) => {
1459
+ const graph = new Map(entries.map((e) => [e.name, new Set(e.usedRefs)]));
1460
+ for (const e of entries) for (const ref of e.usedRefs) if (!graph.has(ref)) graph.set(ref, /* @__PURE__ */ new Set());
1461
+ const { sccs, lazyEdges } = tarjan(graph);
1462
+ const rewritten = new Map(entries.map((entry) => {
1463
+ const newZod = entry.zod.replaceAll(SENTINEL_PATTERN, (_match, refName) => {
1464
+ return lazyEdges.has(edgeKey(entry.name, refName)) ? `zod.lazy(() => ${refName})` : refName;
1465
+ });
1466
+ return [entry.name, {
1467
+ ...entry,
1468
+ zod: newZod
1469
+ }];
1470
+ }));
1471
+ const out = [];
1472
+ for (const scc of sccs) for (const name of scc) {
1473
+ const entry = rewritten.get(name);
1474
+ if (entry !== void 0) out.push(entry);
1475
+ }
1476
+ return out;
1477
+ };
1478
+ //#endregion
1311
1479
  //#region src/write-zod-specs.ts
1312
1480
  function generateZodSchemaFileContent(header, schemas) {
1313
1481
  return `${header}import { z as zod } from 'zod';
@@ -1362,6 +1530,7 @@ async function writeZodSchemaIndex(schemasPath, fileExtension, header, schemaNam
1362
1530
  await fs.outputFile(indexPath, `${header}\n${uniqueExports}\n`);
1363
1531
  }
1364
1532
  function generateZodSchemasInline(builder, output) {
1533
+ if (output.override.zod.generateReusableSchemas === true) return generateZodSchemasInlineReusable(builder, output);
1365
1534
  const schemasWithOpenApiDef = builder.schemas.filter((s) => s.schema);
1366
1535
  if (schemasWithOpenApiDef.length === 0) return "";
1367
1536
  const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
@@ -1386,7 +1555,33 @@ function generateZodSchemasInline(builder, output) {
1386
1555
  if (schemas.length === 0) return "";
1387
1556
  return generateZodSchemaFileContent("", schemas);
1388
1557
  }
1558
+ function generateZodSchemasInlineReusable(builder, output) {
1559
+ const schemasWithOpenApiDef = builder.schemas.filter((s) => s.schema);
1560
+ if (schemasWithOpenApiDef.length === 0) return "";
1561
+ const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1562
+ const strict = output.override.zod.strict.body;
1563
+ const coerce = output.override.zod.coerce.body;
1564
+ const context = {
1565
+ spec: builder.spec,
1566
+ target: builder.target,
1567
+ workspace: "",
1568
+ output
1569
+ };
1570
+ const refs = schemasWithOpenApiDef.map(({ name }) => `#/components/schemas/${name}`);
1571
+ resolveSchemaNames(refs, output.namingConvention);
1572
+ return `import { z as zod } from 'zod';\n\n${rewriteReusableSchemas(generateReusableSchemaSet(refs, context, {
1573
+ strict,
1574
+ isZodV4,
1575
+ coerce
1576
+ })).map((entry) => {
1577
+ return `${entry.consts ? `${entry.consts}\n\n` : ""}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}>;`;
1578
+ }).join("\n\n")}\n`;
1579
+ }
1389
1580
  async function writeZodSchemas(builder, schemasPath, fileExtension, header, output) {
1581
+ if (output.override.zod.generateReusableSchemas) {
1582
+ await writeZodSchemasReusable(builder, schemasPath, fileExtension, header, output);
1583
+ return;
1584
+ }
1390
1585
  const schemasWithOpenApiDef = builder.schemas.filter((s) => s.schema);
1391
1586
  const schemasToWrite = [];
1392
1587
  const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
@@ -1418,6 +1613,39 @@ async function writeZodSchemas(builder, schemasPath, fileExtension, header, outp
1418
1613
  }
1419
1614
  if (output.indexFiles) await writeZodSchemaIndex(schemasPath, fileExtension, header, groupedSchemasToWrite.map((schemaGroup) => schemaGroup[0].schemaName), output.namingConvention, false);
1420
1615
  }
1616
+ async function writeZodSchemasReusable(builder, schemasPath, fileExtension, header, output) {
1617
+ const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1618
+ const strict = output.override.zod.strict.body;
1619
+ const coerce = output.override.zod.coerce.body;
1620
+ const context = {
1621
+ spec: builder.spec,
1622
+ target: builder.target,
1623
+ workspace: "",
1624
+ output
1625
+ };
1626
+ const refs = builder.schemas.map(({ name }) => `#/components/schemas/${name}`).filter((ref) => {
1627
+ const schemaName = ref.slice(21);
1628
+ return (builder.spec.components?.schemas ?? {})[schemaName] !== void 0;
1629
+ });
1630
+ resolveSchemaNames(refs, output.namingConvention);
1631
+ const rewritten = rewriteReusableSchemas(generateReusableSchemaSet(refs, context, {
1632
+ strict,
1633
+ isZodV4,
1634
+ coerce
1635
+ }));
1636
+ for (const entry of rewritten) {
1637
+ const fileName = conventionName(entry.name, output.namingConvention);
1638
+ const filePath = path.join(schemasPath, `${fileName}${fileExtension}`);
1639
+ const importExt = fileExtension.replace(/\.ts$/, "");
1640
+ const imports = [...entry.usedRefs].filter((r) => r !== entry.name).toSorted().map((r) => {
1641
+ return `import { ${r} } from './${conventionName(r, output.namingConvention)}${importExt}';`;
1642
+ }).join("\n");
1643
+ const consts = entry.consts ? `${entry.consts}\n\n` : "";
1644
+ const fileContent = `${header}import { z as zod } from 'zod';\n` + (imports ? `${imports}\n\n` : "\n") + `${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}>;\n`;
1645
+ await fs.outputFile(filePath, fileContent);
1646
+ }
1647
+ if (output.indexFiles && rewritten.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, rewritten.map((e) => e.name), output.namingConvention, true);
1648
+ }
1421
1649
  async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension, header, output, context) {
1422
1650
  const zodContext = context;
1423
1651
  const verbOptionsArray = Object.values(verbOptions);
@@ -1425,6 +1653,7 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1425
1653
  const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
1426
1654
  const strict = output.override.zod.strict.body;
1427
1655
  const coerce = output.override.zod.coerce.body;
1656
+ const useReusableSchemas = output.override.zod.generateReusableSchemas === true;
1428
1657
  const uniqueVerbsSchemas = dedupeSchemasByName(verbOptionsArray.flatMap((verbOption) => {
1429
1658
  const operation = verbOption.originalOperation;
1430
1659
  const shouldGenerate = {
@@ -1440,7 +1669,7 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1440
1669
  const bodySchema = bodyMedia?.schema;
1441
1670
  const bodySchemas = shouldGenerate.body && bodySchema ? [{
1442
1671
  name: `${pascal(verbOption.operationName)}Body`,
1443
- schema: dereference(bodySchema, zodContext),
1672
+ schema: useReusableSchemas ? bodySchema : dereference(bodySchema, zodContext),
1444
1673
  bodyContentType,
1445
1674
  encoding: bodyMedia?.encoding
1446
1675
  }] : [];
@@ -1450,7 +1679,7 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1450
1679
  name: `${pascal(verbOption.operationName)}Params`,
1451
1680
  schema: {
1452
1681
  type: "object",
1453
- properties: Object.fromEntries(queryParams.filter((p) => "schema" in p && p.schema).map((p) => [p.name, dereference(p.schema, zodContext)])),
1682
+ properties: Object.fromEntries(queryParams.filter((p) => "schema" in p && p.schema).map((p) => [p.name, useReusableSchemas ? p.schema : dereference(p.schema, zodContext)])),
1454
1683
  required: queryParams.filter((p) => p.required).map((p) => p.name).filter((name) => name !== void 0)
1455
1684
  }
1456
1685
  }] : [];
@@ -1459,13 +1688,13 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1459
1688
  name: `${pascal(verbOption.operationName)}Headers`,
1460
1689
  schema: {
1461
1690
  type: "object",
1462
- properties: Object.fromEntries(headerParams.filter((p) => "schema" in p && p.schema).map((p) => [p.name, dereference(p.schema, zodContext)])),
1691
+ properties: Object.fromEntries(headerParams.filter((p) => "schema" in p && p.schema).map((p) => [p.name, useReusableSchemas ? p.schema : dereference(p.schema, zodContext)])),
1463
1692
  required: headerParams.filter((p) => p.required).map((p) => p.name).filter((name) => name !== void 0)
1464
1693
  }
1465
1694
  }] : [];
1466
1695
  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
1696
  name: responseType.value,
1468
- schema: dereference(responseType.originalSchema, zodContext)
1697
+ schema: useReusableSchemas ? responseType.originalSchema : dereference(responseType.originalSchema, zodContext)
1469
1698
  })) : [];
1470
1699
  return dedupeSchemasByName([
1471
1700
  ...bodySchemas,
@@ -1476,10 +1705,14 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
1476
1705
  }));
1477
1706
  const schemasToWrite = [];
1478
1707
  for (const entry of uniqueVerbsSchemas) {
1708
+ if (useReusableSchemas && entry.schema && typeof entry.schema.$ref === "string" && Object.keys(entry.schema).length === 1) continue;
1479
1709
  const { name, schema } = entry;
1480
1710
  const fileName = conventionName(name, output.namingConvention);
1481
1711
  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);
1712
+ 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, {
1713
+ required: true,
1714
+ useReusableSchemas
1715
+ }), zodContext, coerce, strict, isZodV4);
1483
1716
  schemasToWrite.push({
1484
1717
  schemaName: name,
1485
1718
  filePath,
@@ -1545,104 +1778,128 @@ async function addOperationSchemasReExport(schemaPath, operationSchemasPath, hea
1545
1778
  await fs.outputFile(schemaIndexPath, content);
1546
1779
  }
1547
1780
  }
1781
+ /**
1782
+ * Emit `<schemas-dir>/index.faker.ts` (or `<output-root>/schemas.faker.ts`
1783
+ * when `output.schemas` is not configured) when a faker generator entry has
1784
+ * `schemas: true`. Each `components/schemas` entry becomes a
1785
+ * `get<SchemaName>Mock(overrides)` factory in the file. Returns the written
1786
+ * file path so callers can include it in formatter / hook runs, or
1787
+ * `undefined` if no file was written.
1788
+ */
1789
+ async function writeFakerSchemaMocks(builder, options, header) {
1790
+ const { output } = options;
1791
+ const fakerEntry = output.mock.generators.find((g) => !isFunction(g) && g.type === OutputMockType.FAKER && g.schemas === true);
1792
+ if (!fakerEntry) return;
1793
+ const schemasWithDef = builder.schemas.filter((s) => !!s.schema);
1794
+ if (schemasWithDef.length === 0) return;
1795
+ const { implementation, imports } = generateFakerForSchemas(schemasWithDef, {
1796
+ spec: builder.spec,
1797
+ target: builder.target,
1798
+ workspace: "",
1799
+ output
1800
+ }, fakerEntry);
1801
+ if (!implementation.trim()) return;
1802
+ let filePath;
1803
+ let schemaImportPath;
1804
+ const fileExtension = output.fileExtension || ".ts";
1805
+ if (output.schemas) {
1806
+ const schemasDir = isString(output.schemas) ? output.schemas : output.schemas.path;
1807
+ filePath = path.join(schemasDir, `index.faker${fileExtension}`);
1808
+ schemaImportPath = ".";
1809
+ } else {
1810
+ const targetInfo = output.target ? getFileInfo(output.target, { extension: fileExtension }) : void 0;
1811
+ const dir = targetInfo?.dirname ?? process.cwd();
1812
+ filePath = path.join(dir, `schemas.faker${fileExtension}`);
1813
+ schemaImportPath = targetInfo ? `./${targetInfo.filename}${getImportExtension(fileExtension, output.tsconfig)}` : void 0;
1814
+ }
1815
+ const reroutedImports = imports.map((imp) => imp.importPath ? imp : {
1816
+ ...imp,
1817
+ importPath: schemaImportPath
1818
+ });
1819
+ const grouped = /* @__PURE__ */ new Map();
1820
+ for (const imp of reroutedImports) {
1821
+ const key = imp.importPath ?? "";
1822
+ if (!key) continue;
1823
+ const bucket = grouped.get(key) ?? [];
1824
+ bucket.push(imp);
1825
+ grouped.set(key, bucket);
1826
+ }
1827
+ const content = `${header}${generateDependencyImports(implementation, [{
1828
+ exports: [{
1829
+ name: "faker",
1830
+ values: true
1831
+ }],
1832
+ dependency: fakerEntry.locale ? `@faker-js/faker/locale/${fakerEntry.locale}` : "@faker-js/faker"
1833
+ }, ...[...grouped.entries()].map(([dependency, exports]) => ({
1834
+ exports,
1835
+ dependency
1836
+ }))], void 0, !!output.schemas, false)}\n\n${implementation}`;
1837
+ await writeGeneratedFile(filePath, content);
1838
+ return filePath;
1839
+ }
1548
1840
  async function writeSpecs(builder, workspace, options, projectName) {
1549
1841
  const { info, schemas, target } = builder;
1550
1842
  const { output } = options;
1551
1843
  const projectTitle = projectName ?? info.title;
1552
1844
  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,
1570
- tsconfig: output.tsconfig
1845
+ if (output.schemas) {
1846
+ const schemasPath = isString(output.schemas) ? output.schemas : output.schemas.path;
1847
+ if (!isString(output.schemas) && output.schemas.type === "zod" || isString(output.schemas) && output.client === "zod" && output.override.zod.generateReusableSchemas) {
1848
+ const fileExtension = output.schemaFileExtension;
1849
+ await writeZodSchemas(builder, schemasPath, fileExtension, header, output);
1850
+ await writeZodSchemasFromVerbs(builder.verbOptions, schemasPath, fileExtension, header, output, {
1851
+ spec: builder.spec,
1852
+ target: builder.target,
1853
+ workspace,
1854
+ output
1571
1855
  });
1572
- if (opSchemas.length > 0) {
1573
- await writeSchemas({
1574
- schemaPath: output.operationSchemas,
1575
- schemas: opSchemas,
1856
+ } else {
1857
+ const fileExtension = output.fileExtension || ".ts";
1858
+ if (output.operationSchemas) {
1859
+ const { regularSchemas, operationSchemas: opSchemas } = splitSchemasByType(schemas);
1860
+ const regularSchemaNames = new Set(regularSchemas.map((s) => s.name));
1861
+ const operationSchemaNames = new Set(opSchemas.map((s) => s.name));
1862
+ fixCrossDirectoryImports(opSchemas, regularSchemaNames, schemasPath, output.operationSchemas, output.namingConvention, fileExtension, output.tsconfig);
1863
+ fixRegularSchemaImports(regularSchemas, operationSchemaNames, schemasPath, output.operationSchemas, output.namingConvention, fileExtension, output.tsconfig);
1864
+ if (regularSchemas.length > 0) await writeSchemas({
1865
+ schemaPath: schemasPath,
1866
+ schemas: regularSchemas,
1576
1867
  target,
1577
1868
  namingConvention: output.namingConvention,
1578
1869
  fileExtension,
1579
1870
  header,
1580
1871
  indexFiles: output.indexFiles,
1581
- tsconfig: output.tsconfig
1872
+ tsconfig: output.tsconfig,
1873
+ factoryOutputDirectory: output.factoryMethods?.outputDirectory
1582
1874
  });
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,
1875
+ if (opSchemas.length > 0) {
1876
+ await writeSchemas({
1877
+ schemaPath: output.operationSchemas,
1878
+ schemas: opSchemas,
1879
+ target,
1880
+ namingConvention: output.namingConvention,
1881
+ fileExtension,
1882
+ header,
1883
+ indexFiles: output.indexFiles,
1884
+ tsconfig: output.tsconfig,
1885
+ factoryOutputDirectory: output.factoryMethods?.outputDirectory
1886
+ });
1887
+ if (output.indexFiles) await addOperationSchemasReExport(schemasPath, output.operationSchemas, header);
1888
+ }
1889
+ } else await writeSchemas({
1890
+ schemaPath: schemasPath,
1891
+ schemas,
1606
1892
  target,
1607
1893
  namingConvention: output.namingConvention,
1608
1894
  fileExtension,
1609
1895
  header,
1610
1896
  indexFiles: output.indexFiles,
1611
- tsconfig: output.tsconfig
1897
+ tsconfig: output.tsconfig,
1898
+ factoryOutputDirectory: output.factoryMethods?.outputDirectory
1612
1899
  });
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
- });
1900
+ }
1645
1901
  }
1902
+ const fakerSchemaPath = await writeFakerSchemaMocks(builder, options, header);
1646
1903
  let implementationPaths = [];
1647
1904
  if (output.target) {
1648
1905
  const writeMode = getWriteMode(output.mode);
@@ -1684,6 +1941,7 @@ async function writeSpecs(builder, workspace, options, projectName) {
1684
1941
  }
1685
1942
  const paths = [
1686
1943
  ...output.schemas ? [getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path).dirname] : [],
1944
+ ...fakerSchemaPath ? [fakerSchemaPath] : [],
1687
1945
  ...output.operationSchemas ? [getFileInfo(output.operationSchemas).dirname] : [],
1688
1946
  ...implementationPaths
1689
1947
  ];
@@ -1814,4 +2072,4 @@ async function loadConfigFile(configFilePath) {
1814
2072
  //#endregion
1815
2073
  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
2074
 
1817
- //# sourceMappingURL=config-DDQgHurQ.mjs.map
2075
+ //# sourceMappingURL=config-Cyybmy9c.mjs.map