orval 8.17.0 → 8.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { FormDataArrayHandling, GetterPropType, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SupportedFormatter, asyncReduce, buildDynamicScope, collectReferencedComponents, conventionName, createSuccessMessage, dynamicImport, fixCrossDirectoryImports, fixRegularSchemaImports, generateComponentDefinition, generateDependencyImports, generateMutator, generateParameterDefinition, generateSchemasDefinition, generateVerbsOptions, getBaseUrlRuntimeImports, getFileInfo, getFullRoute, getImportExtension, getMockFileExtensionByTypeName, getRefInfo, getRoute, isBoolean, isComponentRef, isFunction, isNullish, isObject, isReference, isString, isUrl, jsDoc, log, logError, logVerbose, logWarning, pascal, removeFilesAndEmptyFolders, resolveInstalledVersions, resolveRef, resolveValue, splitSchemasByType, upath, writeGeneratedFile, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode } from "@orval/core";
|
|
2
|
+
import { DefaultTag, FormDataArrayHandling, GetterPropType, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SupportedFormatter, asyncReduce, buildDynamicScope, buildSchemaTagMap, collectReferencedComponents, conventionName, createSuccessMessage, dynamicImport, fixCrossDirectoryImports, fixRegularSchemaImports, generateComponentDefinition, generateDependencyImports, generateMutator, generateParameterDefinition, generateSchemasDefinition, generateVerbsOptions, getBaseUrlRuntimeImports, getFileInfo, getFullRoute, getImportExtension, getMockFileExtensionByTypeName, getRefInfo, getRoute, isBoolean, isComponentRef, isFunction, isNullish, isObject, isReference, isString, isUrl, jsDoc, kebab, log, logError, logVerbose, logWarning, pascal, removeFilesAndEmptyFolders, resolveInstalledVersions, resolveRef, resolveValue, splitSchemasByType, upath, writeGeneratedFile, writeSchemas, writeSchemasTagsSplit, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode } from "@orval/core";
|
|
3
3
|
import { bundle } from "@scalar/json-magic/bundle";
|
|
4
4
|
import { fetchUrls, parseJson, parseYaml, readFiles } from "@scalar/json-magic/bundle/plugins/node";
|
|
5
5
|
import { upgrade, validate } from "@scalar/openapi-parser";
|
|
@@ -15,7 +15,7 @@ import mcp from "@orval/mcp";
|
|
|
15
15
|
import query from "@orval/query";
|
|
16
16
|
import solidStart from "@orval/solid-start";
|
|
17
17
|
import swr from "@orval/swr";
|
|
18
|
-
import zod, { dereference, generateFormDataZodSchema, generateZodValidationSchemaDefinition,
|
|
18
|
+
import zod, { dereference, generateFormDataZodSchema, generateZodValidationSchemaDefinition, parseZodValidationSchemaDefinition, resolveIsZodV4 } from "@orval/zod";
|
|
19
19
|
import { ExecaError, execa } from "execa";
|
|
20
20
|
import fs from "fs-extra";
|
|
21
21
|
import fs$1, { access } from "node:fs/promises";
|
|
@@ -28,7 +28,7 @@ import fs$2 from "node:fs";
|
|
|
28
28
|
import { createJiti } from "jiti";
|
|
29
29
|
//#region package.json
|
|
30
30
|
var name = "orval";
|
|
31
|
-
var version = "8.
|
|
31
|
+
var version = "8.19.0";
|
|
32
32
|
var description = "A swagger client generator for typescript";
|
|
33
33
|
//#endregion
|
|
34
34
|
//#region src/client.ts
|
|
@@ -77,21 +77,24 @@ const generateClientImports = ({ client, implementation, imports, projectName, h
|
|
|
77
77
|
};
|
|
78
78
|
const generateClientHeader = ({ outputClient = DEFAULT_CLIENT, isRequestOptions, isGlobalMutator, isMutator, provideIn, hasAwaitedType, titles, output, verbOptions, tag, isDefaultTagBucket, clientImplementation }) => {
|
|
79
79
|
const { header } = getGeneratorClient(outputClient, output);
|
|
80
|
+
const rawHeader = header ? header({
|
|
81
|
+
title: titles.implementation,
|
|
82
|
+
isRequestOptions,
|
|
83
|
+
isGlobalMutator,
|
|
84
|
+
isMutator,
|
|
85
|
+
provideIn,
|
|
86
|
+
hasAwaitedType,
|
|
87
|
+
output,
|
|
88
|
+
verbOptions,
|
|
89
|
+
tag,
|
|
90
|
+
isDefaultTagBucket,
|
|
91
|
+
clientImplementation
|
|
92
|
+
}) : "";
|
|
93
|
+
const normalizedHeader = typeof rawHeader === "string" ? { implementation: rawHeader } : rawHeader;
|
|
80
94
|
return {
|
|
81
|
-
implementation:
|
|
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`
|
|
95
|
+
implementation: normalizedHeader.implementation,
|
|
96
|
+
implementationMock: `export const ${titles.implementationMock} = () => [\n`,
|
|
97
|
+
sharedTypes: normalizedHeader.sharedTypes
|
|
95
98
|
};
|
|
96
99
|
};
|
|
97
100
|
const generateClientFooter = ({ outputClient, operationNames, hasMutator, hasAwaitedType, titles, output }) => {
|
|
@@ -173,7 +176,8 @@ const generateOperations = (outputClient = DEFAULT_CLIENT, verbsOptions, options
|
|
|
173
176
|
type: isFunction(entry) ? OutputMockType.MSW : entry.type,
|
|
174
177
|
implementation: generated.implementation,
|
|
175
178
|
imports: generated.imports,
|
|
176
|
-
strictMockSchemaTypeNames: generated.strictMockSchemaTypeNames
|
|
179
|
+
strictMockSchemaTypeNames: generated.strictMockSchemaTypeNames,
|
|
180
|
+
strictMockSchemaKinds: generated.strictMockSchemaKinds
|
|
177
181
|
};
|
|
178
182
|
});
|
|
179
183
|
const hasImplementation = client.implementation.trim().length > 0;
|
|
@@ -883,17 +887,28 @@ function createFormData(workspace, formData) {
|
|
|
883
887
|
function normalizeSchemasOption(schemas, workspace) {
|
|
884
888
|
if (!schemas) return;
|
|
885
889
|
if (isString(schemas)) return normalizePath(schemas, workspace);
|
|
886
|
-
|
|
887
|
-
if (schemas.importPath?.trim() === "") throw new Error(`schemas.importPath must be a non-empty package specifier (e.g. '@acme/models'). Received a whitespace-only string.`);
|
|
888
|
-
if (schemas.importPath && schemas.importPath.trim() !== schemas.importPath) throw new Error(`schemas.importPath must be a non-empty package specifier (e.g. '@acme/models'). Received a value with leading or trailing whitespace: "${schemas.importPath}"`);
|
|
889
|
-
if (schemas.importPath?.startsWith(".")) throw new Error(`schemas.importPath must be a package specifier (e.g. '@acme/models'), not a relative path. Received: "${schemas.importPath}"`);
|
|
890
|
-
if (schemas.importPath && (path.isAbsolute(schemas.importPath) || /^[A-Za-z]:[\\/]/.test(schemas.importPath) || schemas.importPath.startsWith("\\\\"))) throw new Error(`schemas.importPath must be a package specifier (e.g. '@acme/models'), not an absolute path. Received: "${schemas.importPath}"`);
|
|
890
|
+
validatePackageSpecifier(schemas.importPath, "schemas.importPath");
|
|
891
891
|
return {
|
|
892
892
|
path: normalizePath(schemas.path, workspace),
|
|
893
|
-
type: schemas.type,
|
|
894
|
-
importPath: schemas.importPath
|
|
893
|
+
type: schemas.type ?? "typescript",
|
|
894
|
+
importPath: schemas.importPath,
|
|
895
|
+
splitByTags: schemas.splitByTags ?? false
|
|
895
896
|
};
|
|
896
897
|
}
|
|
898
|
+
/**
|
|
899
|
+
* Validates that a config value is a valid package specifier (bare specifier
|
|
900
|
+
* or sub-path import like `@acme/models` / `@acme/models/fakers`). Rejects
|
|
901
|
+
* empty, whitespace-only, relative (`./`, `../`), and absolute paths with a
|
|
902
|
+
* clear, actionable error message. No-op when the value is `undefined`.
|
|
903
|
+
*/
|
|
904
|
+
function validatePackageSpecifier(value, fieldName) {
|
|
905
|
+
if (value === void 0) return;
|
|
906
|
+
if (!value) throw new Error(`\`${fieldName}\` must be a non-empty package specifier (e.g. '@acme/models'). Received an empty string.`);
|
|
907
|
+
if (value.trim() === "") throw new Error(`\`${fieldName}\` must be a non-empty package specifier (e.g. '@acme/models'). Received a whitespace-only string.`);
|
|
908
|
+
if (value.trim() !== value) throw new Error(`\`${fieldName}\` must be a non-empty package specifier (e.g. '@acme/models'). Received a value with leading or trailing whitespace: "${value}"`);
|
|
909
|
+
if (value.startsWith(".")) throw new Error(`\`${fieldName}\` must be a package specifier (e.g. '@acme/models'), not a relative path. Received: "${value}"`);
|
|
910
|
+
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}"`);
|
|
911
|
+
}
|
|
897
912
|
function normalizeEffectOptions(effect) {
|
|
898
913
|
return {
|
|
899
914
|
strict: {
|
|
@@ -955,6 +970,7 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
|
|
|
955
970
|
if (isFunction(entry)) continue;
|
|
956
971
|
if (seenMockTypes.has(entry.type)) throw new Error(`Duplicate mock generator type "${entry.type}". Each type can only appear once in mock.generators.`);
|
|
957
972
|
seenMockTypes.add(entry.type);
|
|
973
|
+
if (entry.type === OutputMockType.FAKER) validatePackageSpecifier(entry.schemasImportPath, "mock.generators[faker].schemasImportPath");
|
|
958
974
|
}
|
|
959
975
|
const defaultFileExtension = ".ts";
|
|
960
976
|
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;
|
|
@@ -973,7 +989,7 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
|
|
|
973
989
|
shouldExportQueryKey: true,
|
|
974
990
|
shouldFilterQueryKey: false,
|
|
975
991
|
shouldSplitQueryKey: false,
|
|
976
|
-
...normalizeQueryOptions(outputOptions.override?.query,
|
|
992
|
+
...normalizeQueryOptions(outputOptions.override?.query, outputWorkspace)
|
|
977
993
|
};
|
|
978
994
|
const normalizedOptions = {
|
|
979
995
|
input: {
|
|
@@ -1005,6 +1021,8 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
|
|
|
1005
1021
|
baseUrl: outputOptions.baseUrl,
|
|
1006
1022
|
unionAddMissingProperties: outputOptions.unionAddMissingProperties ?? false,
|
|
1007
1023
|
factoryMethods,
|
|
1024
|
+
tagsSplitDeduplication: outputOptions.tagsSplitDeduplication ?? false,
|
|
1025
|
+
commonTypesFileName: outputOptions.commonTypesFileName ?? "common-types",
|
|
1008
1026
|
override: {
|
|
1009
1027
|
...outputOptions.override,
|
|
1010
1028
|
mock: {
|
|
@@ -1015,8 +1033,8 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
|
|
|
1015
1033
|
fractionDigits: outputOptions.override?.mock?.fractionDigits ?? 2,
|
|
1016
1034
|
...outputOptions.override?.mock
|
|
1017
1035
|
},
|
|
1018
|
-
operations: normalizeOperationsAndTags(outputOptions.override?.operations ?? {}, outputWorkspace, { query: globalQueryOptions }),
|
|
1019
|
-
tags: normalizeOperationsAndTags(outputOptions.override?.tags ?? {}, outputWorkspace, { query: globalQueryOptions }),
|
|
1036
|
+
operations: normalizeOperationsAndTags(outputOptions.override?.operations ?? {}, outputWorkspace, { query: globalQueryOptions }, "operations"),
|
|
1037
|
+
tags: normalizeOperationsAndTags(outputOptions.override?.tags ?? {}, outputWorkspace, { query: globalQueryOptions }, "tags"),
|
|
1020
1038
|
mutator: normalizeMutator(outputWorkspace, outputOptions.override?.mutator),
|
|
1021
1039
|
formData: createFormData(outputWorkspace, outputOptions.override?.formData),
|
|
1022
1040
|
formUrlEncoded: (isBoolean(outputOptions.override?.formUrlEncoded) ? outputOptions.override.formUrlEncoded : normalizeMutator(outputWorkspace, outputOptions.override?.formUrlEncoded)) ?? true,
|
|
@@ -1071,13 +1089,14 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
|
|
|
1071
1089
|
response: outputOptions.override?.zod?.coerce?.response ?? false
|
|
1072
1090
|
},
|
|
1073
1091
|
preprocess: {
|
|
1074
|
-
...outputOptions.override?.zod?.preprocess?.param ? { param: normalizeMutator(
|
|
1075
|
-
...outputOptions.override?.zod?.preprocess?.query ? { query: normalizeMutator(
|
|
1076
|
-
...outputOptions.override?.zod?.preprocess?.header ? { header: normalizeMutator(
|
|
1077
|
-
...outputOptions.override?.zod?.preprocess?.body ? { body: normalizeMutator(
|
|
1078
|
-
...outputOptions.override?.zod?.preprocess?.response ? { response: normalizeMutator(
|
|
1092
|
+
...outputOptions.override?.zod?.preprocess?.param ? { param: normalizeMutator(outputWorkspace, outputOptions.override.zod.preprocess.param) } : {},
|
|
1093
|
+
...outputOptions.override?.zod?.preprocess?.query ? { query: normalizeMutator(outputWorkspace, outputOptions.override.zod.preprocess.query) } : {},
|
|
1094
|
+
...outputOptions.override?.zod?.preprocess?.header ? { header: normalizeMutator(outputWorkspace, outputOptions.override.zod.preprocess.header) } : {},
|
|
1095
|
+
...outputOptions.override?.zod?.preprocess?.body ? { body: normalizeMutator(outputWorkspace, outputOptions.override.zod.preprocess.body) } : {},
|
|
1096
|
+
...outputOptions.override?.zod?.preprocess?.response ? { response: normalizeMutator(outputWorkspace, outputOptions.override.zod.preprocess.response) } : {}
|
|
1079
1097
|
},
|
|
1080
|
-
...outputOptions.override?.zod?.params ? { params: normalizeMutator(
|
|
1098
|
+
...outputOptions.override?.zod?.params ? { params: normalizeMutator(outputWorkspace, outputOptions.override.zod.params) } : {},
|
|
1099
|
+
version: outputOptions.override?.zod?.version ?? "auto",
|
|
1081
1100
|
generateEachHttpStatus: outputOptions.override?.zod?.generateEachHttpStatus ?? false,
|
|
1082
1101
|
useBrandedTypes: outputOptions.override?.zod?.useBrandedTypes ?? false,
|
|
1083
1102
|
generateReusableSchemas: outputOptions.override?.zod?.generateReusableSchemas ?? false,
|
|
@@ -1101,6 +1120,7 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
|
|
|
1101
1120
|
forceSuccessResponse: outputOptions.override?.fetch?.forceSuccessResponse ?? false,
|
|
1102
1121
|
runtimeValidation: outputOptions.override?.fetch?.runtimeValidation ?? false,
|
|
1103
1122
|
useRuntimeFetcher: outputOptions.override?.fetch?.useRuntimeFetcher ?? false,
|
|
1123
|
+
...outputOptions.override?.fetch?.arrayFormat ? { arrayFormat: outputOptions.override.fetch.arrayFormat } : {},
|
|
1104
1124
|
...outputOptions.override?.fetch,
|
|
1105
1125
|
...outputOptions.override?.fetch?.jsonReviver ? { jsonReviver: normalizeMutator(outputWorkspace, outputOptions.override.fetch.jsonReviver) } : {}
|
|
1106
1126
|
},
|
|
@@ -1121,6 +1141,11 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
|
|
|
1121
1141
|
};
|
|
1122
1142
|
if (!normalizedOptions.input.target) throw new Error(styleText("red", `Config requires an input target.`));
|
|
1123
1143
|
if (!normalizedOptions.output.target && !normalizedOptions.output.schemas) throw new Error(styleText("red", `Config requires an output target or schemas.`));
|
|
1144
|
+
const fakerWithSchemasImportPath = normalizedOptions.output.mock.generators.find((g) => !isFunction(g) && g.type === OutputMockType.FAKER && !!g.schemasImportPath);
|
|
1145
|
+
if (fakerWithSchemasImportPath) {
|
|
1146
|
+
if (fakerWithSchemasImportPath.schemas !== true) throw new Error(styleText("red", `\`mock.generators[faker].schemasImportPath\` requires \`schemas: true\` on the same generator. Schema-level faker factories are only emitted when \`schemas: true\`.`));
|
|
1147
|
+
if (!(isObject(normalizedOptions.output.schemas) && normalizedOptions.output.schemas.importPath)) throw new Error(styleText("red", `\`mock.generators[faker].schemasImportPath\` requires \`schemas.importPath\` to also be set. It overrides the package specifier used for importing schema-level faker factories.`));
|
|
1148
|
+
}
|
|
1124
1149
|
const usesAngularGenerator = normalizedOptions.output.client === OutputClient.ANGULAR || normalizedOptions.output.client === OutputClient.ANGULAR_QUERY && normalizedOptions.output.httpClient === OutputHttpClient.ANGULAR;
|
|
1125
1150
|
if (normalizedOptions.output.override.paramsFilter && !usesAngularGenerator) throw new Error(styleText("red", `\`override.paramsFilter\` is only supported by the Angular generator (the \`angular\` client, or \`angular-query\` with \`httpClient: 'angular'\`). It has no effect for other clients — use \`override.paramsSerializer\` instead.`));
|
|
1126
1151
|
if (!usesAngularGenerator) {
|
|
@@ -1210,8 +1235,19 @@ function normalizePath(path$1, workspace) {
|
|
|
1210
1235
|
if (!isString(path$1)) return path$1;
|
|
1211
1236
|
return path.resolve(workspace, path$1);
|
|
1212
1237
|
}
|
|
1213
|
-
function normalizeOperationsAndTags(operationsOrTags, workspace, global) {
|
|
1238
|
+
function normalizeOperationsAndTags(operationsOrTags, workspace, global, source) {
|
|
1239
|
+
const unsupportedZodKeys = [
|
|
1240
|
+
"version",
|
|
1241
|
+
"dateTimeOptions",
|
|
1242
|
+
"timeOptions",
|
|
1243
|
+
"generateEachHttpStatus",
|
|
1244
|
+
"generateReusableSchemas",
|
|
1245
|
+
"generateMeta"
|
|
1246
|
+
];
|
|
1214
1247
|
return Object.fromEntries(Object.entries(operationsOrTags).map(([key, { transformer, mutator, formData, formUrlEncoded, paramsSerializer, paramsFilter, query, angular, zod, effect, ...rest }]) => {
|
|
1248
|
+
const unsupportedOperationZodKeys = zod && unsupportedZodKeys.filter((unsupportedKey) => zod[unsupportedKey] !== void 0);
|
|
1249
|
+
if (unsupportedOperationZodKeys && unsupportedOperationZodKeys.length) logWarning(`⚠️ override.${source}.${key}.zod only supports strict, generate, coerce, preprocess, params, and useBrandedTypes. Ignoring unsupported ${unsupportedOperationZodKeys.length === 1 ? "field" : "fields"}: ${unsupportedOperationZodKeys.map((unsupportedKey) => `zod.${unsupportedKey}`).join(", ")}.`);
|
|
1250
|
+
const hasSupportedOperationZodConfig = !!zod && (zod.strict !== void 0 || zod.generate !== void 0 || zod.coerce !== void 0 || zod.preprocess !== void 0 || zod.params !== void 0 || zod.useBrandedTypes !== void 0);
|
|
1215
1251
|
return [key, {
|
|
1216
1252
|
...rest,
|
|
1217
1253
|
...angular ? { angular: {
|
|
@@ -1221,7 +1257,7 @@ function normalizeOperationsAndTags(operationsOrTags, workspace, global) {
|
|
|
1221
1257
|
...angular.httpResource ? { httpResource: angular.httpResource } : {}
|
|
1222
1258
|
} } : {},
|
|
1223
1259
|
...query ? { query: normalizeQueryOptions(query, workspace, global.query) } : {},
|
|
1224
|
-
...zod ? { zod: {
|
|
1260
|
+
...hasSupportedOperationZodConfig && zod ? { zod: {
|
|
1225
1261
|
strict: {
|
|
1226
1262
|
param: zod.strict?.param ?? false,
|
|
1227
1263
|
query: zod.strict?.query ?? false,
|
|
@@ -1251,12 +1287,7 @@ function normalizeOperationsAndTags(operationsOrTags, workspace, global) {
|
|
|
1251
1287
|
...zod.preprocess?.response ? { response: normalizeMutator(workspace, zod.preprocess.response) } : {}
|
|
1252
1288
|
},
|
|
1253
1289
|
...zod.params ? { params: normalizeMutator(workspace, zod.params) } : {},
|
|
1254
|
-
|
|
1255
|
-
useBrandedTypes: zod.useBrandedTypes ?? false,
|
|
1256
|
-
generateReusableSchemas: zod.generateReusableSchemas ?? false,
|
|
1257
|
-
generateMeta: zod.generateMeta ?? false,
|
|
1258
|
-
dateTimeOptions: zod.dateTimeOptions ?? { offset: true },
|
|
1259
|
-
timeOptions: zod.timeOptions ?? {}
|
|
1290
|
+
useBrandedTypes: zod.useBrandedTypes ?? false
|
|
1260
1291
|
} } : {},
|
|
1261
1292
|
...effect ? { effect: normalizeEffectOptions(effect) } : {},
|
|
1262
1293
|
...transformer ? { transformer: normalizePath(transformer, workspace) } : {},
|
|
@@ -1591,6 +1622,23 @@ const rewriteReusableSchemas = (entries) => {
|
|
|
1591
1622
|
function buildMutatorImportStatement(mutator) {
|
|
1592
1623
|
return `import ${mutator.default ? mutator.name : `{ ${mutator.name} }`} from '${mutator.path}';`;
|
|
1593
1624
|
}
|
|
1625
|
+
const ROOT_DIR = ".";
|
|
1626
|
+
function getSchemaDir(schemaTagMap, name) {
|
|
1627
|
+
return schemaTagMap?.get(name) ?? ROOT_DIR;
|
|
1628
|
+
}
|
|
1629
|
+
function computeCrossDirImportPath(schemasPath, fromDir, toDir, fileName, importExt) {
|
|
1630
|
+
if (fromDir === toDir) return `./${fileName}${importExt}`;
|
|
1631
|
+
const fromPath = fromDir === ROOT_DIR ? schemasPath : path.join(schemasPath, fromDir);
|
|
1632
|
+
const toPath = toDir === ROOT_DIR ? schemasPath : path.join(schemasPath, toDir);
|
|
1633
|
+
const relDir = upath.relativeSafe(fromPath, toPath);
|
|
1634
|
+
return `${upath.joinSafe(relDir, fileName)}${importExt}`;
|
|
1635
|
+
}
|
|
1636
|
+
function adjustMutatorPathForDir(mutatorPath, tagDir) {
|
|
1637
|
+
if (tagDir === ROOT_DIR) return mutatorPath;
|
|
1638
|
+
if (mutatorPath.startsWith("./")) return `../${mutatorPath.slice(2)}`;
|
|
1639
|
+
if (mutatorPath.startsWith("../")) return `../${mutatorPath}`;
|
|
1640
|
+
return mutatorPath;
|
|
1641
|
+
}
|
|
1594
1642
|
/**
|
|
1595
1643
|
* Whole-word substring check for a resolved mutator alias inside generated
|
|
1596
1644
|
* code. Plain `String.includes` would false-positive when the user names the
|
|
@@ -1660,7 +1708,7 @@ const isValidSchemaIdentifier = (name) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(name);
|
|
|
1660
1708
|
* `resolveValue` producer surfaces aliases here today, so the integration
|
|
1661
1709
|
* tests can't exercise it.
|
|
1662
1710
|
*/
|
|
1663
|
-
function buildSiblingImports({ usedRefs, extraImports, entryName, componentNames, namingConvention, importExt }) {
|
|
1711
|
+
function buildSiblingImports({ usedRefs, extraImports, entryName, componentNames, namingConvention, importExt, schemaTagMap, currentDir, schemasPath }) {
|
|
1664
1712
|
const importsByName = /* @__PURE__ */ new Map();
|
|
1665
1713
|
for (const name of usedRefs) {
|
|
1666
1714
|
if (name === entryName) continue;
|
|
@@ -1672,7 +1720,7 @@ function buildSiblingImports({ usedRefs, extraImports, entryName, componentNames
|
|
|
1672
1720
|
}
|
|
1673
1721
|
return [...importsByName.values()].toSorted((a, b) => a.name.localeCompare(b.name)).map(({ name, alias }) => {
|
|
1674
1722
|
const importedFile = conventionName(name, namingConvention);
|
|
1675
|
-
return `import { ${alias ? `${name} as ${alias}` : name} } from '
|
|
1723
|
+
return `import { ${alias ? `${name} as ${alias}` : name} } from '${schemaTagMap && currentDir && schemasPath ? computeCrossDirImportPath(schemasPath, currentDir, getSchemaDir(schemaTagMap, name), importedFile, importExt) : `./${importedFile}${importExt}`}';`;
|
|
1676
1724
|
}).join("\n");
|
|
1677
1725
|
}
|
|
1678
1726
|
const isPrimitiveSchemaName = (name) => [
|
|
@@ -1698,8 +1746,8 @@ const groupSchemasByFilePath = (schemas) => {
|
|
|
1698
1746
|
}
|
|
1699
1747
|
return [...grouped.values()].map((group) => [...group].toSorted((a, b) => a.filePath.localeCompare(b.filePath, "en", { numeric: true }))).toSorted((a, b) => a[0].filePath.localeCompare(b[0].filePath, "en", { numeric: true }));
|
|
1700
1748
|
};
|
|
1701
|
-
async function writeZodSchemaIndex(schemasPath, fileExtension, header, schemaNames, namingConvention, shouldMergeExisting = false) {
|
|
1702
|
-
const importFileExtension = fileExtension
|
|
1749
|
+
async function writeZodSchemaIndex(schemasPath, fileExtension, header, schemaNames, namingConvention, shouldMergeExisting = false, tsconfig) {
|
|
1750
|
+
const importFileExtension = getImportExtension(fileExtension, tsconfig);
|
|
1703
1751
|
const indexPath = path.join(schemasPath, `index.ts`);
|
|
1704
1752
|
let existingExports = "";
|
|
1705
1753
|
if (shouldMergeExisting && await fs.pathExists(indexPath)) {
|
|
@@ -1715,11 +1763,34 @@ async function writeZodSchemaIndex(schemasPath, fileExtension, header, schemaNam
|
|
|
1715
1763
|
const uniqueExports = [...new Set(allExports.split("\n"))].filter((line) => line.trim()).toSorted().join("\n");
|
|
1716
1764
|
await fs.outputFile(indexPath, `${header}\n${uniqueExports}\n`);
|
|
1717
1765
|
}
|
|
1766
|
+
async function writeZodSchemaTagsSplitBarrel(schemasPath, fileExtension, header, componentDirs, verbDirs, namingConvention, tsconfig) {
|
|
1767
|
+
const importExt = getImportExtension(fileExtension, tsconfig);
|
|
1768
|
+
const indexImportExt = getImportExtension(".ts", tsconfig);
|
|
1769
|
+
const allDirs = /* @__PURE__ */ new Map();
|
|
1770
|
+
for (const [dir, names] of componentDirs) allDirs.set(dir, [...names]);
|
|
1771
|
+
for (const [dir, names] of verbDirs) if (allDirs.has(dir)) allDirs.get(dir).push(...names);
|
|
1772
|
+
else allDirs.set(dir, [...names]);
|
|
1773
|
+
for (const [dir, schemaNames] of allDirs) {
|
|
1774
|
+
if (dir === ROOT_DIR) continue;
|
|
1775
|
+
await writeZodSchemaIndex(path.join(schemasPath, dir), fileExtension, header, schemaNames, namingConvention, false, tsconfig);
|
|
1776
|
+
}
|
|
1777
|
+
const rootSchemas = allDirs.get(ROOT_DIR) ?? [];
|
|
1778
|
+
const rootExports = [...new Set(rootSchemas)].map((name) => {
|
|
1779
|
+
return `export * from './${conventionName(name, namingConvention)}${importExt}';`;
|
|
1780
|
+
}).toSorted();
|
|
1781
|
+
const tagExports = [...allDirs.keys()].filter((dir) => dir !== ROOT_DIR).toSorted((a, b) => a.localeCompare(b, "en", { numeric: true })).map((dir) => {
|
|
1782
|
+
return `export * from '${indexImportExt ? `./${dir}/index${indexImportExt}` : `./${dir}`}';`;
|
|
1783
|
+
});
|
|
1784
|
+
const allExports = [...rootExports, ...tagExports];
|
|
1785
|
+
const rootIndexPath = path.join(schemasPath, "index.ts");
|
|
1786
|
+
const content = `${header}\n${allExports.join("\n")}\n`;
|
|
1787
|
+
await fs.outputFile(rootIndexPath, content);
|
|
1788
|
+
}
|
|
1718
1789
|
function generateZodSchemasInline(builder, output, includeZodImport = true, paramsMutator, includeParamsImport = false) {
|
|
1719
1790
|
if (output.override.zod.generateReusableSchemas === true) return generateZodSchemasInlineReusable(builder, output, includeZodImport, paramsMutator, includeParamsImport);
|
|
1720
1791
|
const schemasWithOpenApiDef = builder.schemas.filter((s) => s.schema);
|
|
1721
1792
|
if (schemasWithOpenApiDef.length === 0) return "";
|
|
1722
|
-
const isZodV4 =
|
|
1793
|
+
const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
|
|
1723
1794
|
const strict = output.override.zod.strict.body;
|
|
1724
1795
|
const coerce = output.override.zod.coerce.body;
|
|
1725
1796
|
const schemas = [];
|
|
@@ -1745,7 +1816,7 @@ function generateZodSchemasInline(builder, output, includeZodImport = true, para
|
|
|
1745
1816
|
return generateZodSchemaFileContent("", schemas, includeZodImport);
|
|
1746
1817
|
}
|
|
1747
1818
|
function generateZodSchemasInlineReusable(builder, output, includeZodImport = true, paramsMutator, includeParamsImport = false) {
|
|
1748
|
-
const isZodV4 =
|
|
1819
|
+
const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
|
|
1749
1820
|
const strict = output.override.zod.strict.body;
|
|
1750
1821
|
const coerce = output.override.zod.coerce.body;
|
|
1751
1822
|
const context = {
|
|
@@ -1769,21 +1840,20 @@ function generateZodSchemasInlineReusable(builder, output, includeZodImport = tr
|
|
|
1769
1840
|
const paramsImport = paramsMutator && includeParamsImport && bodyReferencesMutator(body, paramsMutator) ? `${buildMutatorImportStatement(paramsMutator)}\n` : "";
|
|
1770
1841
|
return `${zodImport || paramsImport ? `${zodImport}${paramsImport}\n` : ""}${body}\n`;
|
|
1771
1842
|
}
|
|
1772
|
-
async function writeZodSchemas(builder, schemasPath, fileExtension, header, output, paramsMutator) {
|
|
1773
|
-
if (output.override.zod.generateReusableSchemas)
|
|
1774
|
-
|
|
1775
|
-
return;
|
|
1776
|
-
}
|
|
1843
|
+
async function writeZodSchemas(builder, schemasPath, fileExtension, header, output, paramsMutator, schemaTagMap) {
|
|
1844
|
+
if (output.override.zod.generateReusableSchemas) return writeZodSchemasReusable(builder, schemasPath, fileExtension, header, output, paramsMutator, schemaTagMap);
|
|
1845
|
+
const isSplit = !!schemaTagMap;
|
|
1777
1846
|
const schemasWithOpenApiDef = builder.schemas.filter((s) => s.schema);
|
|
1778
1847
|
const schemasToWrite = [];
|
|
1779
|
-
const isZodV4 =
|
|
1848
|
+
const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
|
|
1780
1849
|
const strict = output.override.zod.strict.body;
|
|
1781
1850
|
const coerce = output.override.zod.coerce.body;
|
|
1782
1851
|
for (const generatorSchema of schemasWithOpenApiDef) {
|
|
1783
1852
|
const { name, schema: schemaObject } = generatorSchema;
|
|
1784
1853
|
if (!schemaObject) continue;
|
|
1785
1854
|
const fileName = conventionName(name, output.namingConvention);
|
|
1786
|
-
const
|
|
1855
|
+
const tagDir = getSchemaDir(schemaTagMap, name);
|
|
1856
|
+
const filePath = isSplit ? path.join(schemasPath, tagDir, `${fileName}${fileExtension}`) : path.join(schemasPath, `${fileName}${fileExtension}`);
|
|
1787
1857
|
const context = {
|
|
1788
1858
|
spec: builder.spec,
|
|
1789
1859
|
target: builder.target,
|
|
@@ -1806,10 +1876,22 @@ async function writeZodSchemas(builder, schemasPath, fileExtension, header, outp
|
|
|
1806
1876
|
const fileContent = generateZodSchemaFileContent(header, schemaGroup);
|
|
1807
1877
|
await fs.outputFile(schemaGroup[0].filePath, fileContent);
|
|
1808
1878
|
}
|
|
1809
|
-
|
|
1879
|
+
const writtenSchemaNames = groupedSchemasToWrite.map((schemaGroup) => schemaGroup[0].schemaName);
|
|
1880
|
+
if (output.indexFiles && !isSplit) await writeZodSchemaIndex(schemasPath, fileExtension, header, writtenSchemaNames, output.namingConvention, false, output.tsconfig);
|
|
1881
|
+
if (isSplit) {
|
|
1882
|
+
const dirSchemas = /* @__PURE__ */ new Map();
|
|
1883
|
+
for (const name of writtenSchemaNames) {
|
|
1884
|
+
const dir = getSchemaDir(schemaTagMap, name);
|
|
1885
|
+
if (!dirSchemas.has(dir)) dirSchemas.set(dir, []);
|
|
1886
|
+
dirSchemas.get(dir).push(name);
|
|
1887
|
+
}
|
|
1888
|
+
return dirSchemas;
|
|
1889
|
+
}
|
|
1890
|
+
return new Map([[ROOT_DIR, writtenSchemaNames]]);
|
|
1810
1891
|
}
|
|
1811
|
-
async function writeZodSchemasReusable(builder, schemasPath, fileExtension, header, output, paramsMutator) {
|
|
1812
|
-
const
|
|
1892
|
+
async function writeZodSchemasReusable(builder, schemasPath, fileExtension, header, output, paramsMutator, schemaTagMap) {
|
|
1893
|
+
const isSplit = !!schemaTagMap;
|
|
1894
|
+
const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
|
|
1813
1895
|
const strict = output.override.zod.strict.body;
|
|
1814
1896
|
const coerce = output.override.zod.coerce.body;
|
|
1815
1897
|
const context = {
|
|
@@ -1829,11 +1911,11 @@ async function writeZodSchemasReusable(builder, schemasPath, fileExtension, head
|
|
|
1829
1911
|
paramsMutator
|
|
1830
1912
|
}));
|
|
1831
1913
|
const componentNames = new Set(Object.keys(builder.spec.components?.schemas ?? {}).map((schemaName) => resolveSchemaName(`#/components/schemas/${schemaName}`, context)));
|
|
1832
|
-
const paramsMutatorImport = paramsMutator ? buildMutatorImportStatement(paramsMutator) : void 0;
|
|
1833
1914
|
for (const entry of rewritten) {
|
|
1834
1915
|
const fileName = conventionName(entry.name, output.namingConvention);
|
|
1835
|
-
const
|
|
1836
|
-
const
|
|
1916
|
+
const tagDir = getSchemaDir(schemaTagMap, entry.name);
|
|
1917
|
+
const filePath = isSplit ? path.join(schemasPath, tagDir, `${fileName}${fileExtension}`) : path.join(schemasPath, `${fileName}${fileExtension}`);
|
|
1918
|
+
const importExt = getImportExtension(fileExtension, output.tsconfig);
|
|
1837
1919
|
const rendered = renderReusableSchemaEntry(entry, context);
|
|
1838
1920
|
const refImports = buildSiblingImports({
|
|
1839
1921
|
usedRefs: entry.usedRefs,
|
|
@@ -1841,19 +1923,39 @@ async function writeZodSchemasReusable(builder, schemasPath, fileExtension, head
|
|
|
1841
1923
|
entryName: entry.name,
|
|
1842
1924
|
componentNames,
|
|
1843
1925
|
namingConvention: output.namingConvention,
|
|
1844
|
-
importExt
|
|
1926
|
+
importExt,
|
|
1927
|
+
...isSplit ? {
|
|
1928
|
+
schemaTagMap,
|
|
1929
|
+
currentDir: tagDir,
|
|
1930
|
+
schemasPath
|
|
1931
|
+
} : {}
|
|
1845
1932
|
});
|
|
1846
|
-
const
|
|
1933
|
+
const mutatorImportStr = !!paramsMutator && bodyReferencesMutator(entry.zod, paramsMutator) ? buildMutatorImportStatement({
|
|
1934
|
+
...paramsMutator,
|
|
1935
|
+
path: isSplit ? adjustMutatorPathForDir(paramsMutator.path, tagDir) : paramsMutator.path
|
|
1936
|
+
}) : void 0;
|
|
1937
|
+
const imports = [...mutatorImportStr ? [mutatorImportStr] : [], ...refImports ? [refImports] : []].join("\n");
|
|
1847
1938
|
const fileContent = `${header}import { z as zod } from 'zod';\n` + (imports ? `${imports}\n\n` : "\n") + `${rendered.content}\n`;
|
|
1848
1939
|
await fs.outputFile(filePath, fileContent);
|
|
1849
1940
|
}
|
|
1850
|
-
if (output.indexFiles && rewritten.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, rewritten.map((e) => e.name), output.namingConvention, true);
|
|
1941
|
+
if (output.indexFiles && !isSplit && rewritten.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, rewritten.map((e) => e.name), output.namingConvention, true, output.tsconfig);
|
|
1942
|
+
if (isSplit) {
|
|
1943
|
+
const dirSchemas = /* @__PURE__ */ new Map();
|
|
1944
|
+
for (const entry of rewritten) {
|
|
1945
|
+
const dir = getSchemaDir(schemaTagMap, entry.name);
|
|
1946
|
+
if (!dirSchemas.has(dir)) dirSchemas.set(dir, []);
|
|
1947
|
+
dirSchemas.get(dir).push(entry.name);
|
|
1948
|
+
}
|
|
1949
|
+
return dirSchemas;
|
|
1950
|
+
}
|
|
1951
|
+
return new Map([[ROOT_DIR, rewritten.map((e) => e.name)]]);
|
|
1851
1952
|
}
|
|
1852
|
-
async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension, header, output, context) {
|
|
1953
|
+
async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension, header, output, context, schemaTagMap) {
|
|
1954
|
+
const isSplit = !!schemaTagMap;
|
|
1853
1955
|
const zodContext = context;
|
|
1854
1956
|
const verbOptionsArray = Object.values(verbOptions);
|
|
1855
|
-
if (verbOptionsArray.length === 0) return;
|
|
1856
|
-
const isZodV4 =
|
|
1957
|
+
if (verbOptionsArray.length === 0) return /* @__PURE__ */ new Map();
|
|
1958
|
+
const isZodV4 = resolveIsZodV4(output.override.zod.version, output.packageJson);
|
|
1857
1959
|
const strict = output.override.zod.strict.body;
|
|
1858
1960
|
const coerce = output.override.zod.coerce.body;
|
|
1859
1961
|
const useReusableSchemas = output.override.zod.generateReusableSchemas === true;
|
|
@@ -1915,14 +2017,18 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
|
|
|
1915
2017
|
...queryParamsSchemas,
|
|
1916
2018
|
...headerParamsSchemas,
|
|
1917
2019
|
...responseSchemas
|
|
1918
|
-
])
|
|
2020
|
+
]).map((s) => ({
|
|
2021
|
+
...s,
|
|
2022
|
+
verbTagDir: isSplit ? kebab(verbOption.tags?.[0] ?? DefaultTag) : ROOT_DIR
|
|
2023
|
+
}));
|
|
1919
2024
|
}));
|
|
1920
2025
|
const schemasToWrite = [];
|
|
1921
2026
|
for (const entry of uniqueVerbsSchemas) {
|
|
1922
2027
|
if (useReusableSchemas && entry.schema && typeof entry.schema.$ref === "string" && Object.keys(entry.schema).length === 1) continue;
|
|
1923
2028
|
const { name, schema } = entry;
|
|
1924
2029
|
const fileName = conventionName(name, output.namingConvention);
|
|
1925
|
-
const
|
|
2030
|
+
const tagDir = entry.verbTagDir ?? ROOT_DIR;
|
|
2031
|
+
const filePath = isSplit ? path.join(schemasPath, tagDir, `${fileName}${fileExtension}`) : path.join(schemasPath, `${fileName}${fileExtension}`);
|
|
1926
2032
|
const parsedZodDefinition = parseZodValidationSchemaDefinition("bodyContentType" in entry && entry.bodyContentType === "multipart/form-data" ? generateFormDataZodSchema(schema, zodContext, name, strict, isZodV4, "encoding" in entry ? entry.encoding : void 0, useReusableSchemas) : generateZodValidationSchemaDefinition(schema, zodContext, name, strict, isZodV4, {
|
|
1927
2033
|
required: true,
|
|
1928
2034
|
useReusableSchemas
|
|
@@ -1931,9 +2037,10 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
|
|
|
1931
2037
|
let importStatements;
|
|
1932
2038
|
if (useReusableSchemas && parsedZodDefinition.usedRefs.size > 0) {
|
|
1933
2039
|
zodExpression = rewriteSentinelsToDirect(zodExpression);
|
|
1934
|
-
const importExt = fileExtension.
|
|
2040
|
+
const importExt = getImportExtension(fileExtension, output.tsconfig);
|
|
1935
2041
|
importStatements = [...parsedZodDefinition.usedRefs].filter((refName) => refName !== name).toSorted().map((refName) => {
|
|
1936
|
-
|
|
2042
|
+
const importedFile = conventionName(refName, output.namingConvention);
|
|
2043
|
+
return `import { ${refName} } from '${isSplit ? computeCrossDirImportPath(schemasPath, tagDir, getSchemaDir(schemaTagMap, refName), importedFile, importExt) : `./${importedFile}${importExt}`}';`;
|
|
1937
2044
|
});
|
|
1938
2045
|
}
|
|
1939
2046
|
schemasToWrite.push({
|
|
@@ -1949,7 +2056,19 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
|
|
|
1949
2056
|
const fileContent = generateZodSchemaFileContent(header, schemaGroup);
|
|
1950
2057
|
await fs.outputFile(schemaGroup[0].filePath, fileContent);
|
|
1951
2058
|
}
|
|
1952
|
-
|
|
2059
|
+
const writtenSchemaNames = groupedSchemasToWrite.map((schemaGroup) => schemaGroup[0].schemaName);
|
|
2060
|
+
if (output.indexFiles && !isSplit && uniqueVerbsSchemas.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, writtenSchemaNames, output.namingConvention, true, output.tsconfig);
|
|
2061
|
+
if (isSplit) {
|
|
2062
|
+
const dirSchemas = /* @__PURE__ */ new Map();
|
|
2063
|
+
for (const entry of uniqueVerbsSchemas) {
|
|
2064
|
+
if (useReusableSchemas && entry.schema && typeof entry.schema.$ref === "string" && Object.keys(entry.schema).length === 1) continue;
|
|
2065
|
+
const dir = entry.verbTagDir ?? ROOT_DIR;
|
|
2066
|
+
if (!dirSchemas.has(dir)) dirSchemas.set(dir, []);
|
|
2067
|
+
dirSchemas.get(dir).push(entry.name);
|
|
2068
|
+
}
|
|
2069
|
+
return dirSchemas;
|
|
2070
|
+
}
|
|
2071
|
+
return new Map([[ROOT_DIR, writtenSchemaNames]]);
|
|
1953
2072
|
}
|
|
1954
2073
|
//#endregion
|
|
1955
2074
|
//#region src/write-specs.ts
|
|
@@ -1989,6 +2108,10 @@ function getHeader(option, info) {
|
|
|
1989
2108
|
/**
|
|
1990
2109
|
* Add re-export of operation schemas from the main schemas index file.
|
|
1991
2110
|
* Handles the case where the index file doesn't exist (no regular schemas).
|
|
2111
|
+
*
|
|
2112
|
+
* NOTE: `operationSchemasPath` is a directory, so under NodeNext the re-export
|
|
2113
|
+
* would need an `/index.js` suffix rather than a bare `.js`. That directory-
|
|
2114
|
+
* import case is tracked separately and intentionally left as-is here.
|
|
1992
2115
|
*/
|
|
1993
2116
|
async function addOperationSchemasReExport(schemaPath, operationSchemasPath, header) {
|
|
1994
2117
|
const schemaIndexPath = path.join(schemaPath, `index.ts`);
|
|
@@ -2010,13 +2133,13 @@ async function addOperationSchemasReExport(schemaPath, operationSchemasPath, hea
|
|
|
2010
2133
|
* file path so callers can include it in formatter / hook runs, or
|
|
2011
2134
|
* `undefined` if no file was written.
|
|
2012
2135
|
*/
|
|
2013
|
-
async function writeFakerSchemaMocks(builder, options, header) {
|
|
2136
|
+
async function writeFakerSchemaMocks(builder, options, header, schemaTagMap) {
|
|
2014
2137
|
const { output } = options;
|
|
2015
2138
|
const fakerEntry = output.mock.generators.find((g) => !isFunction(g) && g.type === OutputMockType.FAKER && g.schemas === true);
|
|
2016
2139
|
if (!fakerEntry) return;
|
|
2017
2140
|
const schemasWithDef = builder.schemas.filter((s) => !!s.schema);
|
|
2018
2141
|
if (schemasWithDef.length === 0) return;
|
|
2019
|
-
const { implementation, imports, strictMockSchemaTypeNames } = generateFakerForSchemas(schemasWithDef, {
|
|
2142
|
+
const { implementation, imports, strictMockSchemaTypeNames, strictMockSchemaKinds } = generateFakerForSchemas(schemasWithDef, {
|
|
2020
2143
|
spec: builder.spec,
|
|
2021
2144
|
target: builder.target,
|
|
2022
2145
|
workspace: "",
|
|
@@ -2025,7 +2148,8 @@ async function writeFakerSchemaMocks(builder, options, header) {
|
|
|
2025
2148
|
if (!implementation.trim()) return;
|
|
2026
2149
|
const finalizedImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(implementation, {
|
|
2027
2150
|
mockOptions: output.override.mock,
|
|
2028
|
-
strictSchemaTypeNames: strictMockSchemaTypeNames
|
|
2151
|
+
strictSchemaTypeNames: strictMockSchemaTypeNames,
|
|
2152
|
+
strictMockSchemaKinds
|
|
2029
2153
|
}) : implementation;
|
|
2030
2154
|
let filePath;
|
|
2031
2155
|
let schemaImportPath;
|
|
@@ -2040,9 +2164,32 @@ async function writeFakerSchemaMocks(builder, options, header) {
|
|
|
2040
2164
|
filePath = path.join(dir, `schemas.faker${fileExtension}`);
|
|
2041
2165
|
schemaImportPath = targetInfo ? `./${targetInfo.filename}${getImportExtension(fileExtension, output.tsconfig)}` : void 0;
|
|
2042
2166
|
}
|
|
2043
|
-
const
|
|
2044
|
-
|
|
2045
|
-
|
|
2167
|
+
const isZodSchemaOutput = isObject(output.schemas) && output.schemas.type === "zod";
|
|
2168
|
+
const importExtension = getImportExtension(fileExtension, output.tsconfig);
|
|
2169
|
+
const schemaSuffix = isZodSchemaOutput ? ".zod" : "";
|
|
2170
|
+
const perSchemaImportPath = /* @__PURE__ */ new Map();
|
|
2171
|
+
if (schemaImportPath === "." && !output.indexFiles && isObject(output.schemas)) for (const schema of builder.schemas) {
|
|
2172
|
+
const tsName = pascal(schema.name);
|
|
2173
|
+
const fileName = conventionName(schema.name, output.namingConvention);
|
|
2174
|
+
const tagDir = schemaTagMap?.get(schema.name);
|
|
2175
|
+
const tagSegment = tagDir && tagDir !== "." ? `${tagDir}/` : "";
|
|
2176
|
+
perSchemaImportPath.set(tsName, `./${tagSegment}${fileName}${schemaSuffix}${importExtension}`);
|
|
2177
|
+
}
|
|
2178
|
+
const reroutedImports = imports.map((imp) => {
|
|
2179
|
+
if (imp.importPath) return imp;
|
|
2180
|
+
if (imp.schemaFactory) return {
|
|
2181
|
+
...imp,
|
|
2182
|
+
importPath: "."
|
|
2183
|
+
};
|
|
2184
|
+
const resolved = perSchemaImportPath.get(imp.name);
|
|
2185
|
+
if (resolved) return {
|
|
2186
|
+
...imp,
|
|
2187
|
+
importPath: resolved
|
|
2188
|
+
};
|
|
2189
|
+
return {
|
|
2190
|
+
...imp,
|
|
2191
|
+
importPath: schemaImportPath
|
|
2192
|
+
};
|
|
2046
2193
|
});
|
|
2047
2194
|
const grouped = /* @__PURE__ */ new Map();
|
|
2048
2195
|
for (const imp of reroutedImports) {
|
|
@@ -2079,28 +2226,62 @@ function shouldGenerateSchemas(output, hasOperations) {
|
|
|
2079
2226
|
async function writeSpecs(builder, workspace, options, projectName) {
|
|
2080
2227
|
const { info, schemas, target } = builder;
|
|
2081
2228
|
const { output } = options;
|
|
2229
|
+
const shouldSplitSchemasByTags = isObject(output.schemas) && output.schemas.splitByTags;
|
|
2230
|
+
const schemaTagMap = shouldSplitSchemasByTags ? buildSchemaTagMap(Object.values(builder.operations).map((op) => ({
|
|
2231
|
+
imports: op.imports,
|
|
2232
|
+
tags: op.tags
|
|
2233
|
+
})), schemas) : void 0;
|
|
2082
2234
|
const projectTitle = projectName ?? info.title;
|
|
2083
2235
|
const header = getHeader(output.override.header, info);
|
|
2084
2236
|
if (output.schemas) {
|
|
2085
2237
|
const schemasPath = isString(output.schemas) ? output.schemas : output.schemas.path;
|
|
2086
|
-
|
|
2238
|
+
const isZodSchemas = !isString(output.schemas) && output.schemas.type === "zod" || isString(output.schemas) && output.client === "zod" && output.override.zod.generateReusableSchemas;
|
|
2239
|
+
if (shouldSplitSchemasByTags && output.operationSchemas) throw new Error("schemas.splitByTags cannot be used with output.operationSchemas. The tags-split schema mode handles operation type placement within tag directories.");
|
|
2240
|
+
if (isZodSchemas) {
|
|
2087
2241
|
const fileExtension = output.schemaFileExtension;
|
|
2088
|
-
|
|
2242
|
+
const schemasParamsMutator = output.override.zod.params ? await generateMutator({
|
|
2089
2243
|
output: path.join(schemasPath, `__params__${fileExtension}`),
|
|
2090
2244
|
mutator: output.override.zod.params,
|
|
2091
2245
|
name: "zodParams",
|
|
2092
2246
|
workspace,
|
|
2093
2247
|
tsconfig: output.tsconfig
|
|
2094
|
-
}) : void 0
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2248
|
+
}) : void 0;
|
|
2249
|
+
if (shouldSplitSchemasByTags) {
|
|
2250
|
+
const componentDirs = await writeZodSchemas(builder, schemasPath, fileExtension, header, output, schemasParamsMutator, schemaTagMap);
|
|
2251
|
+
const verbDirs = await writeZodSchemasFromVerbs(builder.verbOptions, schemasPath, fileExtension, header, output, {
|
|
2252
|
+
spec: builder.spec,
|
|
2253
|
+
target: builder.target,
|
|
2254
|
+
workspace,
|
|
2255
|
+
output
|
|
2256
|
+
}, schemaTagMap);
|
|
2257
|
+
if (output.indexFiles) await writeZodSchemaTagsSplitBarrel(schemasPath, fileExtension, header, componentDirs, verbDirs, output.namingConvention, output.tsconfig);
|
|
2258
|
+
} else {
|
|
2259
|
+
await writeZodSchemas(builder, schemasPath, fileExtension, header, output, schemasParamsMutator);
|
|
2260
|
+
await writeZodSchemasFromVerbs(builder.verbOptions, schemasPath, fileExtension, header, output, {
|
|
2261
|
+
spec: builder.spec,
|
|
2262
|
+
target: builder.target,
|
|
2263
|
+
workspace,
|
|
2264
|
+
output
|
|
2265
|
+
});
|
|
2266
|
+
}
|
|
2101
2267
|
} else {
|
|
2102
2268
|
const fileExtension = output.fileExtension || ".ts";
|
|
2103
|
-
if (
|
|
2269
|
+
if (shouldSplitSchemasByTags) await writeSchemasTagsSplit({
|
|
2270
|
+
schemaPath: schemasPath,
|
|
2271
|
+
schemas,
|
|
2272
|
+
target,
|
|
2273
|
+
namingConvention: output.namingConvention,
|
|
2274
|
+
fileExtension,
|
|
2275
|
+
header,
|
|
2276
|
+
indexFiles: output.indexFiles,
|
|
2277
|
+
tsconfig: output.tsconfig,
|
|
2278
|
+
factoryOutputDirectory: output.factoryMethods?.outputDirectory,
|
|
2279
|
+
operations: Object.values(builder.operations).map((op) => ({
|
|
2280
|
+
imports: op.imports,
|
|
2281
|
+
tags: op.tags
|
|
2282
|
+
}))
|
|
2283
|
+
});
|
|
2284
|
+
else if (output.operationSchemas) {
|
|
2104
2285
|
const { regularSchemas, operationSchemas: opSchemas } = splitSchemasByType(schemas);
|
|
2105
2286
|
const regularSchemaNames = new Set(regularSchemas.map((s) => s.name));
|
|
2106
2287
|
const operationSchemaNames = new Set(opSchemas.map((s) => s.name));
|
|
@@ -2144,7 +2325,7 @@ async function writeSpecs(builder, workspace, options, projectName) {
|
|
|
2144
2325
|
});
|
|
2145
2326
|
}
|
|
2146
2327
|
}
|
|
2147
|
-
const fakerSchemaPath = await writeFakerSchemaMocks(builder, options, header);
|
|
2328
|
+
const fakerSchemaPath = await writeFakerSchemaMocks(builder, options, header, schemaTagMap);
|
|
2148
2329
|
let implementationPaths = [];
|
|
2149
2330
|
if (output.target) {
|
|
2150
2331
|
const writeMode = getWriteMode(output.mode);
|
|
@@ -2167,6 +2348,7 @@ async function writeSpecs(builder, workspace, options, projectName) {
|
|
|
2167
2348
|
projectName,
|
|
2168
2349
|
header,
|
|
2169
2350
|
needSchema: shouldGenerateSchemas(output, hasOperations),
|
|
2351
|
+
schemaTagMap,
|
|
2170
2352
|
generateSchemasInline: needZodSchemasInline ? () => generateZodSchemasInline(builder, output, includeZodImport, inlineSchemasParamsMutator, includeParamsImport) : void 0
|
|
2171
2353
|
});
|
|
2172
2354
|
}
|
|
@@ -2174,7 +2356,11 @@ async function writeSpecs(builder, workspace, options, projectName) {
|
|
|
2174
2356
|
const workspacePath = output.workspace;
|
|
2175
2357
|
const indexFile = path.join(workspacePath, "index.ts");
|
|
2176
2358
|
const mockExtensions = output.mock.generators.map((g) => getMockFileExtensionByTypeName(g));
|
|
2177
|
-
const
|
|
2359
|
+
const importExtension = getImportExtension(output.fileExtension, output.tsconfig);
|
|
2360
|
+
const imports = implementationPaths.filter((p) => mockExtensions.length === 0 || !mockExtensions.some((ext) => p.endsWith(`.${ext}.ts`))).map((p) => {
|
|
2361
|
+
const relative = upath.getRelativeImportPath(indexFile, p, true);
|
|
2362
|
+
return (relative.endsWith(output.fileExtension) ? relative.slice(0, -output.fileExtension.length) : relative.replace(/\.[^/.]+$/, "")) + importExtension;
|
|
2363
|
+
});
|
|
2178
2364
|
if (output.schemas) {
|
|
2179
2365
|
const schemasPath = isString(output.schemas) ? output.schemas : output.schemas.path;
|
|
2180
2366
|
imports.push(upath.getRelativeImportPath(indexFile, getFileInfo(schemasPath).dirname));
|
|
@@ -2326,4 +2512,4 @@ async function loadConfigFile(configFilePath) {
|
|
|
2326
2512
|
//#endregion
|
|
2327
2513
|
export { defineConfig as a, description as c, startWatcher as i, name as l, loadConfigFile as n, defineTransformer as o, generateSpec as r, normalizeOptions as s, findConfigFile as t, version as u };
|
|
2328
2514
|
|
|
2329
|
-
//# sourceMappingURL=config-
|
|
2515
|
+
//# sourceMappingURL=config-D-TQRn-G.mjs.map
|