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,
|
|
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.
|
|
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:
|
|
82
|
-
|
|
83
|
-
|
|
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))
|
|
1166
|
-
|
|
1167
|
-
|
|
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
|
-
|
|
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)) ?
|
|
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 ? [
|
|
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
|
|
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 '
|
|
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 =
|
|
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 =
|
|
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 ?
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
1864
|
-
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
2066
|
-
|
|
2067
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
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 (
|
|
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
|
|
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, ...
|
|
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-
|
|
2604
|
+
//# sourceMappingURL=config-C8B9Lol2.mjs.map
|