@orval/core 8.5.2 → 8.6.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.
- package/dist/index.d.mts +247 -154
- package/dist/index.mjs +361 -210
- package/dist/index.mjs.map +1 -1
- package/package.json +21 -10
package/dist/index.mjs
CHANGED
|
@@ -2,10 +2,11 @@ import { t as __exportAll } from "./chunk-C7Uep-_p.mjs";
|
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { entries, groupBy, isArray, isBoolean, isBoolean as isBoolean$1, isEmptyish, isFunction, isNullish, isNullish as isNullish$1, isNumber, isString, isString as isString$1, prop, unique, uniqueBy, uniqueWith } from "remeda";
|
|
4
4
|
import { keyword } from "esutils";
|
|
5
|
-
import
|
|
5
|
+
import nodePath from "node:path";
|
|
6
6
|
import { compare } from "compare-versions";
|
|
7
7
|
import debug from "debug";
|
|
8
8
|
import { pathToFileURL } from "node:url";
|
|
9
|
+
import { createJiti } from "jiti";
|
|
9
10
|
import fs, { existsSync, readFileSync } from "node:fs";
|
|
10
11
|
import { globby } from "globby";
|
|
11
12
|
import readline from "node:readline";
|
|
@@ -134,7 +135,7 @@ function isReference(obj) {
|
|
|
134
135
|
return !isNullish$1(obj) && Object.hasOwn(obj, "$ref");
|
|
135
136
|
}
|
|
136
137
|
function isDirectory(pathValue) {
|
|
137
|
-
return !
|
|
138
|
+
return !nodePath.extname(pathValue);
|
|
138
139
|
}
|
|
139
140
|
function isObject(x) {
|
|
140
141
|
return Object.prototype.toString.call(x) === "[object Object]";
|
|
@@ -245,10 +246,10 @@ function camel(s = "") {
|
|
|
245
246
|
const camelString = decap(pascal(s), isStartWithUnderscore ? 1 : 0);
|
|
246
247
|
return isStartWithUnderscore ? `_${camelString}` : camelString;
|
|
247
248
|
}
|
|
248
|
-
function snake(s) {
|
|
249
|
+
function snake(s = "") {
|
|
249
250
|
return lower(s, "_", true);
|
|
250
251
|
}
|
|
251
|
-
function kebab(s) {
|
|
252
|
+
function kebab(s = "") {
|
|
252
253
|
return lower(s, "-", true);
|
|
253
254
|
}
|
|
254
255
|
function upper(s, fillWith, isDeapostrophe) {
|
|
@@ -457,18 +458,32 @@ function keyValuePairsToJsDoc(keyValues) {
|
|
|
457
458
|
|
|
458
459
|
//#endregion
|
|
459
460
|
//#region src/utils/dynamic-import.ts
|
|
461
|
+
const TS_MODULE_EXTENSIONS = new Set([
|
|
462
|
+
".ts",
|
|
463
|
+
".mts",
|
|
464
|
+
".cts",
|
|
465
|
+
".tsx",
|
|
466
|
+
".jsx"
|
|
467
|
+
]);
|
|
460
468
|
async function dynamicImport(toImport, from = process.cwd(), takeDefault = true) {
|
|
461
469
|
if (!toImport) return toImport;
|
|
462
470
|
try {
|
|
463
471
|
if (isString(toImport)) {
|
|
464
|
-
const
|
|
465
|
-
const
|
|
472
|
+
const filePath = nodePath.resolve(from, toImport);
|
|
473
|
+
const extension = nodePath.extname(filePath);
|
|
474
|
+
if (TS_MODULE_EXTENSIONS.has(extension)) {
|
|
475
|
+
const data = await createJiti(from, { interopDefault: true }).import(filePath);
|
|
476
|
+
if (takeDefault && (isObject(data) || isModule(data)) && data.default) return data.default;
|
|
477
|
+
return data;
|
|
478
|
+
}
|
|
479
|
+
const fileUrl = pathToFileURL(filePath);
|
|
480
|
+
const data = extension === ".json" ? await import(fileUrl.href, { with: { type: "json" } }) : await import(fileUrl.href);
|
|
466
481
|
if (takeDefault && (isObject(data) || isModule(data)) && data.default) return data.default;
|
|
467
482
|
return data;
|
|
468
483
|
}
|
|
469
484
|
return toImport;
|
|
470
485
|
} catch (error) {
|
|
471
|
-
throw new Error(`Oups... 🍻. Path: ${String(toImport)} => ${String(error)}
|
|
486
|
+
throw new Error(`Oups... 🍻. Path: ${String(toImport)} => ${String(error)}`, { cause: error });
|
|
472
487
|
}
|
|
473
488
|
}
|
|
474
489
|
|
|
@@ -482,14 +497,14 @@ function getExtension(path) {
|
|
|
482
497
|
//#region src/utils/file.ts
|
|
483
498
|
function getFileInfo(target = "", { backupFilename = "filename", extension = ".ts" } = {}) {
|
|
484
499
|
const isDir = isDirectory(target);
|
|
485
|
-
const filePath = isDir ?
|
|
500
|
+
const filePath = isDir ? nodePath.join(target, backupFilename + extension) : target;
|
|
486
501
|
return {
|
|
487
502
|
path: filePath,
|
|
488
503
|
pathWithoutExtension: filePath.replace(/\.[^/.]+$/, ""),
|
|
489
504
|
extension,
|
|
490
505
|
isDirectory: isDir,
|
|
491
|
-
dirname:
|
|
492
|
-
filename:
|
|
506
|
+
dirname: nodePath.dirname(filePath),
|
|
507
|
+
filename: nodePath.basename(filePath, extension.startsWith(".") ? extension : `.${extension}`)
|
|
493
508
|
};
|
|
494
509
|
}
|
|
495
510
|
async function removeFilesAndEmptyFolders(patterns, dir) {
|
|
@@ -565,7 +580,7 @@ function startMessage({ name, version, description }) {
|
|
|
565
580
|
return `🍻 ${styleText(["cyan", "bold"], name)} ${styleText("green", `v${version}`)}${description ? ` - ${description}` : ""}`;
|
|
566
581
|
}
|
|
567
582
|
function logError(err, tag) {
|
|
568
|
-
let message
|
|
583
|
+
let message;
|
|
569
584
|
if (err instanceof Error) {
|
|
570
585
|
message = (err.message || err.stack) ?? "Unknown error";
|
|
571
586
|
if (err.cause) {
|
|
@@ -693,13 +708,13 @@ function toUnix(value) {
|
|
|
693
708
|
return value;
|
|
694
709
|
}
|
|
695
710
|
function join(...args) {
|
|
696
|
-
return toUnix(
|
|
711
|
+
return toUnix(nodePath.join(...args.map((a) => toUnix(a))));
|
|
697
712
|
}
|
|
698
713
|
/**
|
|
699
714
|
* Behaves exactly like `path.relative(from, to)`, but keeps the first meaningful "./"
|
|
700
715
|
*/
|
|
701
716
|
function relativeSafe(from, to) {
|
|
702
|
-
return normalizeSafe(`.${separator}${toUnix(
|
|
717
|
+
return normalizeSafe(`.${separator}${toUnix(nodePath.relative(toUnix(from), toUnix(to)))}`);
|
|
703
718
|
}
|
|
704
719
|
function getSchemaFileName(path) {
|
|
705
720
|
return path.replace(`.${getExtension(path)}`, "").slice(path.lastIndexOf("/") + 1);
|
|
@@ -708,13 +723,13 @@ const separator = "/";
|
|
|
708
723
|
function normalizeSafe(value) {
|
|
709
724
|
let result;
|
|
710
725
|
value = toUnix(value);
|
|
711
|
-
result = toUnix(
|
|
726
|
+
result = toUnix(nodePath.normalize(value));
|
|
712
727
|
if (value.startsWith("./") && !result.startsWith("./") && !result.startsWith("..")) result = "./" + result;
|
|
713
728
|
else if (value.startsWith("//") && !result.startsWith("//")) result = value.startsWith("//./") ? "//." + result : "/" + result;
|
|
714
729
|
return result;
|
|
715
730
|
}
|
|
716
731
|
function joinSafe(...values) {
|
|
717
|
-
let result = toUnix(
|
|
732
|
+
let result = toUnix(nodePath.join(...values.map((v) => toUnix(v))));
|
|
718
733
|
if (values.length > 0) {
|
|
719
734
|
const firstValue = toUnix(values[0]);
|
|
720
735
|
if (firstValue.startsWith("./") && !result.startsWith("./") && !result.startsWith("..")) result = "./" + result;
|
|
@@ -745,14 +760,14 @@ function joinSafe(...values) {
|
|
|
745
760
|
* @returns The relative import path string.
|
|
746
761
|
*/
|
|
747
762
|
function getRelativeImportPath(importerFilePath, exporterFilePath, includeFileExtension = false) {
|
|
748
|
-
if (!
|
|
749
|
-
if (!
|
|
750
|
-
const importerDir =
|
|
751
|
-
const relativePath =
|
|
752
|
-
let posixPath =
|
|
763
|
+
if (!nodePath.isAbsolute(importerFilePath)) throw new Error(`'importerFilePath' is not an absolute path. "${importerFilePath}"`);
|
|
764
|
+
if (!nodePath.isAbsolute(exporterFilePath)) throw new Error(`'exporterFilePath' is not an absolute path. "${exporterFilePath}"`);
|
|
765
|
+
const importerDir = nodePath.dirname(importerFilePath);
|
|
766
|
+
const relativePath = nodePath.relative(importerDir, exporterFilePath);
|
|
767
|
+
let posixPath = nodePath.posix.join(...relativePath.split(nodePath.sep));
|
|
753
768
|
if (!posixPath.startsWith("./") && !posixPath.startsWith("../")) posixPath = `./${posixPath}`;
|
|
754
769
|
if (!includeFileExtension) {
|
|
755
|
-
const ext =
|
|
770
|
+
const ext = nodePath.extname(posixPath);
|
|
756
771
|
if (ext && posixPath.endsWith(ext)) posixPath = posixPath.slice(0, -ext.length);
|
|
757
772
|
}
|
|
758
773
|
return posixPath;
|
|
@@ -762,20 +777,20 @@ function getRelativeImportPath(importerFilePath, exporterFilePath, includeFileEx
|
|
|
762
777
|
//#region src/utils/resolve-version.ts
|
|
763
778
|
function resolveInstalledVersion(packageName, fromDir) {
|
|
764
779
|
try {
|
|
765
|
-
const require = createRequire(
|
|
780
|
+
const require = createRequire(nodePath.join(fromDir, "noop.js"));
|
|
766
781
|
try {
|
|
767
782
|
return require(`${packageName}/package.json`).version;
|
|
768
783
|
} catch (directError) {
|
|
769
784
|
if (directError instanceof Error && "code" in directError && directError.code === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
|
|
770
785
|
const entryPath = require.resolve(packageName);
|
|
771
|
-
let dir =
|
|
772
|
-
while (dir !==
|
|
773
|
-
const pkgPath =
|
|
786
|
+
let dir = nodePath.dirname(entryPath);
|
|
787
|
+
while (dir !== nodePath.parse(dir).root) {
|
|
788
|
+
const pkgPath = nodePath.join(dir, "package.json");
|
|
774
789
|
if (existsSync(pkgPath)) {
|
|
775
790
|
const pkgData = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
776
791
|
if (pkgData.name === packageName) return pkgData.version;
|
|
777
792
|
}
|
|
778
|
-
dir =
|
|
793
|
+
dir = nodePath.dirname(dir);
|
|
779
794
|
}
|
|
780
795
|
return;
|
|
781
796
|
}
|
|
@@ -817,7 +832,7 @@ const sortByPriority = (arr) => arr.toSorted((a, b) => {
|
|
|
817
832
|
* Handles strings, numbers, booleans, functions, arrays, and objects.
|
|
818
833
|
*
|
|
819
834
|
* @param data - The data to stringify. Can be a string, array, object, number, boolean, function, null, or undefined.
|
|
820
|
-
* @returns A string representation of the data, or undefined if data is
|
|
835
|
+
* @returns A string representation of the data, `null` for null, or undefined if data is undefined.
|
|
821
836
|
* @example
|
|
822
837
|
* stringify('hello') // returns "'hello'"
|
|
823
838
|
* stringify(42) // returns "42"
|
|
@@ -825,7 +840,8 @@ const sortByPriority = (arr) => arr.toSorted((a, b) => {
|
|
|
825
840
|
* stringify({ a: 1, b: 'test' }) // returns "{ a: 1, b: 'test', }"
|
|
826
841
|
*/
|
|
827
842
|
function stringify(data) {
|
|
828
|
-
if (
|
|
843
|
+
if (data === void 0) return;
|
|
844
|
+
if (data === null) return "null";
|
|
829
845
|
if (isString(data)) return `'${data.replaceAll("'", String.raw`\'`)}'`;
|
|
830
846
|
if (isNumber(data) || isBoolean(data) || isFunction(data)) return String(data);
|
|
831
847
|
if (Array.isArray(data)) return `[${data.map((item) => stringify(item)).join(", ")}]`;
|
|
@@ -918,17 +934,31 @@ function getNumberWord(num) {
|
|
|
918
934
|
return [...num.toString()].reduce((acc, n) => acc + NUMBERS[n], "");
|
|
919
935
|
}
|
|
920
936
|
/**
|
|
921
|
-
* Escapes a specific character in a string by prefixing
|
|
937
|
+
* Escapes a specific character in a string by prefixing all of its occurrences with a backslash.
|
|
922
938
|
*
|
|
923
939
|
* @param str - The string to escape, or null.
|
|
924
940
|
* @param char - The character to escape. Defaults to single quote (').
|
|
925
941
|
* @returns The escaped string, or null if the input is null.
|
|
926
942
|
* @example
|
|
927
943
|
* escape("don't") // returns "don\'t"
|
|
944
|
+
* escape("it's John's") // returns "it\'s John\'s"
|
|
928
945
|
* escape('say "hello"', '"') // returns 'say \\"hello\\"'
|
|
946
|
+
* escape("a'''b", "'") // returns "a\'\'\'b"
|
|
929
947
|
*/
|
|
930
948
|
function escape(str, char = "'") {
|
|
931
|
-
return str?.
|
|
949
|
+
return str?.replaceAll(char, `\\${char}`);
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Escapes regular expression metacharacters in a string so it can be safely
|
|
953
|
+
* embedded inside a RegExp pattern.
|
|
954
|
+
*
|
|
955
|
+
* @param value - The raw string value to escape for regex usage.
|
|
956
|
+
* @returns The escaped string.
|
|
957
|
+
* @example
|
|
958
|
+
* escapeRegExp('foo$bar') // returns 'foo\\$bar'
|
|
959
|
+
*/
|
|
960
|
+
function escapeRegExp(value) {
|
|
961
|
+
return value.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
|
|
932
962
|
}
|
|
933
963
|
/**
|
|
934
964
|
* Escape all characters not included in SingleStringCharacters and
|
|
@@ -996,6 +1026,38 @@ function isSyntheticDefaultImportsAllow(config) {
|
|
|
996
1026
|
|
|
997
1027
|
//#endregion
|
|
998
1028
|
//#region src/getters/enum.ts
|
|
1029
|
+
/**
|
|
1030
|
+
* Map of special characters to semantic word replacements.
|
|
1031
|
+
*
|
|
1032
|
+
* Applied before naming convention transforms (PascalCase, camelCase, …) so
|
|
1033
|
+
* that characters which would otherwise be stripped still contribute a unique
|
|
1034
|
+
* segment to the generated key. Without this, values like "created_at" and
|
|
1035
|
+
* "-created_at" both PascalCase to "CreatedAt", silently overwriting one
|
|
1036
|
+
* another in the generated const/enum object.
|
|
1037
|
+
*
|
|
1038
|
+
* Only characters that appear as leading/trailing modifiers in real-world
|
|
1039
|
+
* OpenAPI enums are mapped — the list is intentionally conservative to avoid
|
|
1040
|
+
* changing output for schemas that don't hit collisions.
|
|
1041
|
+
*/
|
|
1042
|
+
const ENUM_SPECIAL_CHARACTER_MAP = {
|
|
1043
|
+
"-": "minus",
|
|
1044
|
+
"+": "plus"
|
|
1045
|
+
};
|
|
1046
|
+
/**
|
|
1047
|
+
* Replace special characters with semantic words (plus an underscore separator)
|
|
1048
|
+
* so that naming convention transforms (PascalCase, etc.) produce unique keys.
|
|
1049
|
+
*
|
|
1050
|
+
* The trailing underscore acts as a word boundary so that PascalCase treats the
|
|
1051
|
+
* replacement as a separate word: "-created_at" → "minus_created_at" → "MinusCreatedAt".
|
|
1052
|
+
*/
|
|
1053
|
+
function replaceSpecialCharacters(key) {
|
|
1054
|
+
let result = "";
|
|
1055
|
+
for (const char of key) {
|
|
1056
|
+
const replacement = ENUM_SPECIAL_CHARACTER_MAP[char];
|
|
1057
|
+
result += replacement ? replacement + "_" : char;
|
|
1058
|
+
}
|
|
1059
|
+
return result;
|
|
1060
|
+
}
|
|
999
1061
|
function getEnumNames(schemaObject) {
|
|
1000
1062
|
const names = schemaObject?.["x-enumNames"] ?? schemaObject?.["x-enumnames"] ?? schemaObject?.["x-enum-varnames"];
|
|
1001
1063
|
if (!names) return;
|
|
@@ -1023,9 +1085,33 @@ const getTypeConstEnum = (value, enumName, names, descriptions, enumNamingConven
|
|
|
1023
1085
|
enumValue += `export const ${enumName} = {\n${implementation}} as const;\n`;
|
|
1024
1086
|
return enumValue;
|
|
1025
1087
|
};
|
|
1088
|
+
/**
|
|
1089
|
+
* Derive the object/enum key for a single enum value.
|
|
1090
|
+
*
|
|
1091
|
+
* Handles numeric prefixes, sanitization, and optional naming convention
|
|
1092
|
+
* transforms. When `disambiguate` is true, special characters (-/+) are
|
|
1093
|
+
* replaced with semantic words before the convention transform to prevent
|
|
1094
|
+
* key collisions.
|
|
1095
|
+
*/
|
|
1096
|
+
function deriveEnumKey(val, enumNamingConvention, disambiguate = false) {
|
|
1097
|
+
let key = val.startsWith("'") ? val.slice(1, -1) : val;
|
|
1098
|
+
if (isNumeric(key)) key = toNumberKey(key);
|
|
1099
|
+
if (key.length > 1) key = sanitize(key, {
|
|
1100
|
+
whitespace: "_",
|
|
1101
|
+
underscore: true,
|
|
1102
|
+
dash: true,
|
|
1103
|
+
special: true
|
|
1104
|
+
});
|
|
1105
|
+
if (enumNamingConvention) {
|
|
1106
|
+
if (disambiguate) key = replaceSpecialCharacters(key);
|
|
1107
|
+
key = conventionName(key, enumNamingConvention);
|
|
1108
|
+
}
|
|
1109
|
+
return key;
|
|
1110
|
+
}
|
|
1026
1111
|
function getEnumImplementation(value, names, descriptions, enumNamingConvention) {
|
|
1027
1112
|
if (value === "") return "";
|
|
1028
1113
|
const uniqueValues = [...new Set(value.split(" | "))];
|
|
1114
|
+
const disambiguate = !!enumNamingConvention && new Set(uniqueValues.map((v) => deriveEnumKey(v, enumNamingConvention))).size < uniqueValues.length;
|
|
1029
1115
|
let result = "";
|
|
1030
1116
|
for (const [index, val] of uniqueValues.entries()) {
|
|
1031
1117
|
const name = names?.[index];
|
|
@@ -1035,15 +1121,7 @@ function getEnumImplementation(value, names, descriptions, enumNamingConvention)
|
|
|
1035
1121
|
result += comment + ` ${keyword.isIdentifierNameES5(name) ? name : `'${name}'`}: ${val},\n`;
|
|
1036
1122
|
continue;
|
|
1037
1123
|
}
|
|
1038
|
-
|
|
1039
|
-
if (isNumeric(key)) key = toNumberKey(key);
|
|
1040
|
-
if (key.length > 1) key = sanitize(key, {
|
|
1041
|
-
whitespace: "_",
|
|
1042
|
-
underscore: true,
|
|
1043
|
-
dash: true,
|
|
1044
|
-
special: true
|
|
1045
|
-
});
|
|
1046
|
-
if (enumNamingConvention) key = conventionName(key, enumNamingConvention);
|
|
1124
|
+
const key = deriveEnumKey(val, enumNamingConvention, disambiguate);
|
|
1047
1125
|
result += comment + ` ${keyword.isIdentifierNameES5(key) ? key : `'${key}'`}: ${val},\n`;
|
|
1048
1126
|
}
|
|
1049
1127
|
return result;
|
|
@@ -1054,6 +1132,7 @@ const getNativeEnum = (value, enumName, names, enumNamingConvention) => {
|
|
|
1054
1132
|
const getNativeEnumItems = (value, names, enumNamingConvention) => {
|
|
1055
1133
|
if (value === "") return "";
|
|
1056
1134
|
const uniqueValues = [...new Set(value.split(" | "))];
|
|
1135
|
+
const disambiguate = !!enumNamingConvention && new Set(uniqueValues.map((v) => deriveEnumKey(v, enumNamingConvention))).size < uniqueValues.length;
|
|
1057
1136
|
let result = "";
|
|
1058
1137
|
for (const [index, val] of uniqueValues.entries()) {
|
|
1059
1138
|
const name = names?.[index];
|
|
@@ -1061,15 +1140,7 @@ const getNativeEnumItems = (value, names, enumNamingConvention) => {
|
|
|
1061
1140
|
result += ` ${keyword.isIdentifierNameES5(name) ? name : `'${name}'`}= ${val},\n`;
|
|
1062
1141
|
continue;
|
|
1063
1142
|
}
|
|
1064
|
-
|
|
1065
|
-
if (isNumeric(key)) key = toNumberKey(key);
|
|
1066
|
-
if (key.length > 1) key = sanitize(key, {
|
|
1067
|
-
whitespace: "_",
|
|
1068
|
-
underscore: true,
|
|
1069
|
-
dash: true,
|
|
1070
|
-
special: true
|
|
1071
|
-
});
|
|
1072
|
-
if (enumNamingConvention) key = conventionName(key, enumNamingConvention);
|
|
1143
|
+
const key = deriveEnumKey(val, enumNamingConvention, disambiguate);
|
|
1073
1144
|
result += ` ${keyword.isIdentifierNameES5(key) ? key : `'${key}'`}= ${val},\n`;
|
|
1074
1145
|
}
|
|
1075
1146
|
return result;
|
|
@@ -1176,7 +1247,7 @@ function getRefInfo($ref, context) {
|
|
|
1176
1247
|
return firstLevel[paths[1]]?.suffix ?? "";
|
|
1177
1248
|
};
|
|
1178
1249
|
const suffix = getOverrideSuffix(context.output.override, refPaths);
|
|
1179
|
-
const originalName = ref ? refPaths
|
|
1250
|
+
const originalName = ref ? refPaths.at(-1) ?? "" : getSchemaFileName(pathname);
|
|
1180
1251
|
if (!pathname) return {
|
|
1181
1252
|
name: sanitize(pascal(originalName) + suffix, {
|
|
1182
1253
|
es5keyword: true,
|
|
@@ -1263,10 +1334,9 @@ function getSchema$1(schema, context) {
|
|
|
1263
1334
|
if (!schema.$ref) throw new Error(`${REF_NOT_FOUND_PREFIX}: missing $ref`);
|
|
1264
1335
|
const refInfo = getRefInfo(schema.$ref, context);
|
|
1265
1336
|
const { refPaths } = refInfo;
|
|
1266
|
-
|
|
1267
|
-
schemaByRefPaths
|
|
1268
|
-
|
|
1269
|
-
let currentSchema = schemaByRefPaths || context.spec;
|
|
1337
|
+
const schemaByRefPaths = Array.isArray(refPaths) ? prop(context.spec, ...refPaths) : void 0;
|
|
1338
|
+
if (isObject(schemaByRefPaths) && isReference(schemaByRefPaths)) return getSchema$1(schemaByRefPaths, context);
|
|
1339
|
+
let currentSchema = schemaByRefPaths;
|
|
1270
1340
|
if (isObject(currentSchema) && "nullable" in schema) {
|
|
1271
1341
|
const nullable = schema.nullable;
|
|
1272
1342
|
currentSchema = {
|
|
@@ -1503,7 +1573,7 @@ function getArray({ schema, name, context, formDataContext }) {
|
|
|
1503
1573
|
example: schemaExample,
|
|
1504
1574
|
examples: resolveExampleRefs(schemaExamples, context)
|
|
1505
1575
|
};
|
|
1506
|
-
} else if (compareVersions(context.spec.openapi, "3.1", ">=")) return {
|
|
1576
|
+
} else if (compareVersions(context.spec.openapi ?? "3.0.0", "3.1", ">=")) return {
|
|
1507
1577
|
value: "unknown[]",
|
|
1508
1578
|
imports: [],
|
|
1509
1579
|
schemas: [],
|
|
@@ -1561,11 +1631,12 @@ function getResReqTypes(responsesOrRequests, name, context, defaultType = "unkno
|
|
|
1561
1631
|
isEnum: false,
|
|
1562
1632
|
isRef: true,
|
|
1563
1633
|
hasReadonlyProps: false,
|
|
1634
|
+
dependencies: [name],
|
|
1564
1635
|
originalSchema: void 0,
|
|
1565
1636
|
example: void 0,
|
|
1566
1637
|
examples: void 0,
|
|
1567
1638
|
key,
|
|
1568
|
-
contentType:
|
|
1639
|
+
contentType: ""
|
|
1569
1640
|
}];
|
|
1570
1641
|
const [contentType, mediaType] = firstEntry;
|
|
1571
1642
|
const isFormData = formDataContentTypes.has(contentType);
|
|
@@ -1581,6 +1652,7 @@ function getResReqTypes(responsesOrRequests, name, context, defaultType = "unkno
|
|
|
1581
1652
|
isEnum: false,
|
|
1582
1653
|
isRef: true,
|
|
1583
1654
|
hasReadonlyProps: false,
|
|
1655
|
+
dependencies: [name],
|
|
1584
1656
|
originalSchema: mediaType.schema,
|
|
1585
1657
|
example: mediaType.example,
|
|
1586
1658
|
examples: resolveExampleRefs(mediaType.examples, context),
|
|
@@ -1618,6 +1690,7 @@ function getResReqTypes(responsesOrRequests, name, context, defaultType = "unkno
|
|
|
1618
1690
|
type: "unknown",
|
|
1619
1691
|
isEnum: false,
|
|
1620
1692
|
hasReadonlyProps: false,
|
|
1693
|
+
dependencies: [name],
|
|
1621
1694
|
formData,
|
|
1622
1695
|
formUrlEncoded,
|
|
1623
1696
|
isRef: true,
|
|
@@ -1662,6 +1735,7 @@ function getResReqTypes(responsesOrRequests, name, context, defaultType = "unkno
|
|
|
1662
1735
|
if (!isFormData && !isFormUrlEncoded || !effectivePropName || !mediaType.schema) return {
|
|
1663
1736
|
...resolvedValue,
|
|
1664
1737
|
imports: resolvedValue.imports,
|
|
1738
|
+
dependencies: resolvedValue.dependencies,
|
|
1665
1739
|
contentType,
|
|
1666
1740
|
example: mediaType.example,
|
|
1667
1741
|
examples: resolveExampleRefs(mediaType.examples, context)
|
|
@@ -1716,6 +1790,7 @@ function getResReqTypes(responsesOrRequests, name, context, defaultType = "unkno
|
|
|
1716
1790
|
schemas: [],
|
|
1717
1791
|
type: defaultType,
|
|
1718
1792
|
isEnum: false,
|
|
1793
|
+
dependencies: [],
|
|
1719
1794
|
key,
|
|
1720
1795
|
isRef: false,
|
|
1721
1796
|
hasReadonlyProps: false,
|
|
@@ -1927,7 +2002,7 @@ function getBody({ requestBody, operationName, context, contentType }) {
|
|
|
1927
2002
|
const imports = filteredBodyTypes.flatMap(({ imports }) => imports);
|
|
1928
2003
|
const schemas = filteredBodyTypes.flatMap(({ schemas }) => schemas);
|
|
1929
2004
|
const definition = filteredBodyTypes.map(({ value }) => value).join(" | ");
|
|
1930
|
-
const nonReadonlyDefinition = filteredBodyTypes.some((x) => x.hasReadonlyProps) && definition ? `NonReadonly<${definition}>` : definition;
|
|
2005
|
+
const nonReadonlyDefinition = filteredBodyTypes.some((x) => x.hasReadonlyProps) && definition && context.output.override.preserveReadonlyRequestBodies !== "preserve" ? `NonReadonly<${definition}>` : definition;
|
|
1931
2006
|
let implementation = generalJSTypesWithArray.includes(definition.toLowerCase()) || filteredBodyTypes.length > 1 ? camel(operationName) + context.output.override.components.requestBodies.suffix : camel(definition);
|
|
1932
2007
|
let isOptional = false;
|
|
1933
2008
|
if (implementation) {
|
|
@@ -2037,17 +2112,22 @@ function getObject({ item, name, context, nullable, formDataContext }) {
|
|
|
2037
2112
|
examples: resolveExampleRefs(item.examples, context)
|
|
2038
2113
|
};
|
|
2039
2114
|
}
|
|
2040
|
-
|
|
2041
|
-
|
|
2115
|
+
const schemaItem = item;
|
|
2116
|
+
const itemAllOf = schemaItem.allOf;
|
|
2117
|
+
const itemOneOf = schemaItem.oneOf;
|
|
2118
|
+
const itemAnyOf = schemaItem.anyOf;
|
|
2119
|
+
const itemType = schemaItem.type;
|
|
2120
|
+
if (itemAllOf || itemOneOf || itemAnyOf) return combineSchemas({
|
|
2121
|
+
schema: schemaItem,
|
|
2042
2122
|
name,
|
|
2043
|
-
separator:
|
|
2123
|
+
separator: itemAllOf ? "allOf" : itemOneOf ? "oneOf" : "anyOf",
|
|
2044
2124
|
context,
|
|
2045
2125
|
nullable,
|
|
2046
2126
|
formDataContext
|
|
2047
2127
|
});
|
|
2048
|
-
if (Array.isArray(
|
|
2049
|
-
const typeArray =
|
|
2050
|
-
const baseItem =
|
|
2128
|
+
if (Array.isArray(itemType)) {
|
|
2129
|
+
const typeArray = itemType;
|
|
2130
|
+
const baseItem = schemaItem;
|
|
2051
2131
|
return combineSchemas({
|
|
2052
2132
|
schema: { anyOf: typeArray.map((type) => ({
|
|
2053
2133
|
...baseItem,
|
|
@@ -2059,7 +2139,7 @@ function getObject({ item, name, context, nullable, formDataContext }) {
|
|
|
2059
2139
|
nullable
|
|
2060
2140
|
});
|
|
2061
2141
|
}
|
|
2062
|
-
const itemProperties =
|
|
2142
|
+
const itemProperties = schemaItem.properties;
|
|
2063
2143
|
if (itemProperties && Object.entries(itemProperties).length > 0) {
|
|
2064
2144
|
const entries = Object.entries(itemProperties);
|
|
2065
2145
|
if (context.output.propertySortOrder === PropertySortOrder.ALPHABETICAL) entries.sort((a, b) => {
|
|
@@ -2072,14 +2152,13 @@ function getObject({ item, name, context, nullable, formDataContext }) {
|
|
|
2072
2152
|
isEnum: false,
|
|
2073
2153
|
type: "object",
|
|
2074
2154
|
isRef: false,
|
|
2075
|
-
schema: {},
|
|
2076
2155
|
hasReadonlyProps: false,
|
|
2077
2156
|
useTypeAlias: false,
|
|
2078
2157
|
dependencies: [],
|
|
2079
|
-
example:
|
|
2080
|
-
examples: resolveExampleRefs(
|
|
2158
|
+
example: schemaItem.example,
|
|
2159
|
+
examples: resolveExampleRefs(schemaItem.examples, context)
|
|
2081
2160
|
};
|
|
2082
|
-
const itemRequired =
|
|
2161
|
+
const itemRequired = schemaItem.required;
|
|
2083
2162
|
for (const [index, [key, schema]] of entries.entries()) {
|
|
2084
2163
|
const isRequired = (Array.isArray(itemRequired) ? itemRequired : []).includes(key);
|
|
2085
2164
|
let propName = "";
|
|
@@ -2099,10 +2178,11 @@ function getObject({ item, name, context, nullable, formDataContext }) {
|
|
|
2099
2178
|
context,
|
|
2100
2179
|
formDataContext: propertyFormDataContext
|
|
2101
2180
|
});
|
|
2102
|
-
const isReadOnly =
|
|
2181
|
+
const isReadOnly = Boolean(schemaItem.readOnly) || Boolean(schema.readOnly);
|
|
2103
2182
|
if (!index) acc.value += "{";
|
|
2104
2183
|
const doc = jsDoc(schema, true, context);
|
|
2105
|
-
|
|
2184
|
+
const propertyDoc = doc ? `${doc.trimEnd().split("\n").map((line) => ` ${line}`).join("\n")}\n` : "";
|
|
2185
|
+
if (isReadOnly) acc.hasReadonlyProps = true;
|
|
2106
2186
|
const constValue = "const" in schema ? schema.const : void 0;
|
|
2107
2187
|
const hasConst = constValue !== void 0;
|
|
2108
2188
|
let constLiteral;
|
|
@@ -2110,6 +2190,7 @@ function getObject({ item, name, context, nullable, formDataContext }) {
|
|
|
2110
2190
|
else if (isString(constValue)) constLiteral = `'${escape(constValue)}'`;
|
|
2111
2191
|
else constLiteral = JSON.stringify(constValue);
|
|
2112
2192
|
const needsValueImport = hasConst && (resolvedValue.isEnum || resolvedValue.type === "enum");
|
|
2193
|
+
const usedResolvedValue = !hasConst || needsValueImport;
|
|
2113
2194
|
const aliasedImports = needsValueImport ? resolvedValue.imports.map((imp) => ({
|
|
2114
2195
|
...imp,
|
|
2115
2196
|
isConstant: true
|
|
@@ -2126,19 +2207,21 @@ function getObject({ item, name, context, nullable, formDataContext }) {
|
|
|
2126
2207
|
});
|
|
2127
2208
|
const propValue = needsValueImport ? alias : constLiteral ?? alias;
|
|
2128
2209
|
const finalPropValue = isRequired ? propValue : context.output.override.useNullForOptional === true ? `${propValue} | null` : propValue;
|
|
2129
|
-
acc.value += `\n
|
|
2130
|
-
|
|
2131
|
-
|
|
2210
|
+
acc.value += `\n${propertyDoc}${isReadOnly && !context.output.override.suppressReadonlyModifier ? " readonly " : " "}${getKey(key)}${isRequired ? "" : "?"}: ${finalPropValue};`;
|
|
2211
|
+
if (usedResolvedValue) {
|
|
2212
|
+
acc.schemas.push(...resolvedValue.schemas);
|
|
2213
|
+
acc.dependencies.push(...resolvedValue.dependencies);
|
|
2214
|
+
}
|
|
2132
2215
|
if (entries.length - 1 === index) {
|
|
2133
|
-
const additionalProps =
|
|
2134
|
-
if (additionalProps) if (
|
|
2135
|
-
const recordType = getPropertyNamesRecordType(
|
|
2216
|
+
const additionalProps = schemaItem.additionalProperties;
|
|
2217
|
+
if (additionalProps) if (additionalProps === true) {
|
|
2218
|
+
const recordType = getPropertyNamesRecordType(schemaItem, "unknown");
|
|
2136
2219
|
if (recordType) {
|
|
2137
2220
|
acc.value += "\n}";
|
|
2138
2221
|
acc.value += ` & ${recordType}`;
|
|
2139
2222
|
acc.useTypeAlias = true;
|
|
2140
2223
|
} else {
|
|
2141
|
-
const keyType = getIndexSignatureKey(
|
|
2224
|
+
const keyType = getIndexSignatureKey(schemaItem);
|
|
2142
2225
|
acc.value += `\n [key: ${keyType}]: unknown;\n }`;
|
|
2143
2226
|
}
|
|
2144
2227
|
} else {
|
|
@@ -2147,13 +2230,13 @@ function getObject({ item, name, context, nullable, formDataContext }) {
|
|
|
2147
2230
|
name,
|
|
2148
2231
|
context
|
|
2149
2232
|
});
|
|
2150
|
-
const recordType = getPropertyNamesRecordType(
|
|
2233
|
+
const recordType = getPropertyNamesRecordType(schemaItem, resolvedValue.value);
|
|
2151
2234
|
if (recordType) {
|
|
2152
2235
|
acc.value += "\n}";
|
|
2153
2236
|
acc.value += ` & ${recordType}`;
|
|
2154
2237
|
acc.useTypeAlias = true;
|
|
2155
2238
|
} else {
|
|
2156
|
-
const keyType = getIndexSignatureKey(
|
|
2239
|
+
const keyType = getIndexSignatureKey(schemaItem);
|
|
2157
2240
|
acc.value += `\n [key: ${keyType}]: ${resolvedValue.value};\n}`;
|
|
2158
2241
|
}
|
|
2159
2242
|
acc.dependencies.push(...resolvedValue.dependencies);
|
|
@@ -2164,11 +2247,11 @@ function getObject({ item, name, context, nullable, formDataContext }) {
|
|
|
2164
2247
|
}
|
|
2165
2248
|
return acc;
|
|
2166
2249
|
}
|
|
2167
|
-
const outerAdditionalProps =
|
|
2168
|
-
const readOnlyFlag =
|
|
2250
|
+
const outerAdditionalProps = schemaItem.additionalProperties;
|
|
2251
|
+
const readOnlyFlag = schemaItem.readOnly;
|
|
2169
2252
|
if (outerAdditionalProps) {
|
|
2170
|
-
if (
|
|
2171
|
-
const recordType = getPropertyNamesRecordType(
|
|
2253
|
+
if (outerAdditionalProps === true) {
|
|
2254
|
+
const recordType = getPropertyNamesRecordType(schemaItem, "unknown");
|
|
2172
2255
|
if (recordType) return {
|
|
2173
2256
|
value: recordType + nullable,
|
|
2174
2257
|
imports: [],
|
|
@@ -2181,7 +2264,7 @@ function getObject({ item, name, context, nullable, formDataContext }) {
|
|
|
2181
2264
|
dependencies: []
|
|
2182
2265
|
};
|
|
2183
2266
|
return {
|
|
2184
|
-
value: `{ [key: ${getIndexSignatureKey(
|
|
2267
|
+
value: `{ [key: ${getIndexSignatureKey(schemaItem)}]: unknown }` + nullable,
|
|
2185
2268
|
imports: [],
|
|
2186
2269
|
schemas: [],
|
|
2187
2270
|
isEnum: false,
|
|
@@ -2197,7 +2280,7 @@ function getObject({ item, name, context, nullable, formDataContext }) {
|
|
|
2197
2280
|
name,
|
|
2198
2281
|
context
|
|
2199
2282
|
});
|
|
2200
|
-
const recordType = getPropertyNamesRecordType(
|
|
2283
|
+
const recordType = getPropertyNamesRecordType(schemaItem, resolvedValue.value);
|
|
2201
2284
|
if (recordType) return {
|
|
2202
2285
|
value: recordType + nullable,
|
|
2203
2286
|
imports: resolvedValue.imports,
|
|
@@ -2210,7 +2293,7 @@ function getObject({ item, name, context, nullable, formDataContext }) {
|
|
|
2210
2293
|
dependencies: resolvedValue.dependencies
|
|
2211
2294
|
};
|
|
2212
2295
|
return {
|
|
2213
|
-
value: `{[key: ${getIndexSignatureKey(
|
|
2296
|
+
value: `{[key: ${getIndexSignatureKey(schemaItem)}]: ${resolvedValue.value}}` + nullable,
|
|
2214
2297
|
imports: resolvedValue.imports,
|
|
2215
2298
|
schemas: resolvedValue.schemas,
|
|
2216
2299
|
isEnum: false,
|
|
@@ -2221,20 +2304,29 @@ function getObject({ item, name, context, nullable, formDataContext }) {
|
|
|
2221
2304
|
dependencies: resolvedValue.dependencies
|
|
2222
2305
|
};
|
|
2223
2306
|
}
|
|
2224
|
-
const constValue =
|
|
2225
|
-
if (constValue)
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
type
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2307
|
+
const constValue = schemaItem.const;
|
|
2308
|
+
if (constValue !== void 0) {
|
|
2309
|
+
let type;
|
|
2310
|
+
if (Array.isArray(constValue)) type = "array";
|
|
2311
|
+
else if (constValue === null) type = "null";
|
|
2312
|
+
else if (typeof constValue === "string") type = "string";
|
|
2313
|
+
else if (typeof constValue === "number") type = "number";
|
|
2314
|
+
else if (typeof constValue === "boolean") type = "boolean";
|
|
2315
|
+
else type = "object";
|
|
2316
|
+
return {
|
|
2317
|
+
value: typeof constValue === "string" ? `'${escape(constValue)}'` : JSON.stringify(constValue),
|
|
2318
|
+
imports: [],
|
|
2319
|
+
schemas: [],
|
|
2320
|
+
isEnum: false,
|
|
2321
|
+
type,
|
|
2322
|
+
isRef: false,
|
|
2323
|
+
hasReadonlyProps: readOnlyFlag ?? false,
|
|
2324
|
+
dependencies: []
|
|
2325
|
+
};
|
|
2326
|
+
}
|
|
2327
|
+
const keyType = itemType === "object" ? getIndexSignatureKey(schemaItem) : "string";
|
|
2328
|
+
const recordType = getPropertyNamesRecordType(schemaItem, "unknown");
|
|
2329
|
+
if (itemType === "object" && recordType) return {
|
|
2238
2330
|
value: recordType + nullable,
|
|
2239
2331
|
imports: [],
|
|
2240
2332
|
schemas: [],
|
|
@@ -2246,7 +2338,7 @@ function getObject({ item, name, context, nullable, formDataContext }) {
|
|
|
2246
2338
|
dependencies: []
|
|
2247
2339
|
};
|
|
2248
2340
|
return {
|
|
2249
|
-
value: (
|
|
2341
|
+
value: (itemType === "object" ? `{ [key: ${keyType}]: unknown }` : "unknown") + nullable,
|
|
2250
2342
|
imports: [],
|
|
2251
2343
|
schemas: [],
|
|
2252
2344
|
isEnum: false,
|
|
@@ -2434,7 +2526,7 @@ function normalizeAllOfSchema(schema) {
|
|
|
2434
2526
|
let didMerge = false;
|
|
2435
2527
|
const schemaProperties = schema.properties;
|
|
2436
2528
|
const schemaRequired = schema.required;
|
|
2437
|
-
const mergedProperties = { ...schemaProperties };
|
|
2529
|
+
const mergedProperties = schemaProperties ? { ...schemaProperties } : {};
|
|
2438
2530
|
const mergedRequired = new Set(schemaRequired);
|
|
2439
2531
|
const remainingAllOf = [];
|
|
2440
2532
|
for (const subSchema of schemaAllOf) {
|
|
@@ -2581,15 +2673,18 @@ function combineSchemas({ name, schema, separator, context, nullable, formDataCo
|
|
|
2581
2673
|
};
|
|
2582
2674
|
}
|
|
2583
2675
|
let resolvedValue;
|
|
2584
|
-
|
|
2676
|
+
const normalizedProperties = normalizedSchema.properties;
|
|
2677
|
+
const schemaOneOf = schema.oneOf;
|
|
2678
|
+
const schemaAnyOf = schema.anyOf;
|
|
2679
|
+
if (normalizedProperties) resolvedValue = getScalar({
|
|
2585
2680
|
item: Object.fromEntries(Object.entries(normalizedSchema).filter(([key]) => key !== separator)),
|
|
2586
2681
|
name,
|
|
2587
2682
|
context,
|
|
2588
2683
|
formDataContext
|
|
2589
2684
|
});
|
|
2590
|
-
else if (separator === "allOf" && (
|
|
2591
|
-
const siblingCombiner =
|
|
2592
|
-
const siblingSchemas =
|
|
2685
|
+
else if (separator === "allOf" && (schemaOneOf || schemaAnyOf)) {
|
|
2686
|
+
const siblingCombiner = schemaOneOf ? "oneOf" : "anyOf";
|
|
2687
|
+
const siblingSchemas = schemaOneOf ?? schemaAnyOf;
|
|
2593
2688
|
resolvedValue = combineSchemas({
|
|
2594
2689
|
schema: { [siblingCombiner]: siblingSchemas },
|
|
2595
2690
|
name,
|
|
@@ -2783,8 +2878,8 @@ function getProps({ body, queryParams, params, operationName, headers, context }
|
|
|
2783
2878
|
const parameterTypeName = `${pascal(operationName)}PathParameters`;
|
|
2784
2879
|
const name = "pathParams";
|
|
2785
2880
|
const namedParametersTypeDefinition = `export type ${parameterTypeName} = {\n ${params.map((property) => property.definition).join(",\n ")},\n }`;
|
|
2786
|
-
const isOptional = context.output.optionsParamRequired || params.every((param) => param.default);
|
|
2787
|
-
const implementation = `{ ${params.map((property) => property.default ? `${property.name} = ${property.default}`
|
|
2881
|
+
const isOptional = context.output.optionsParamRequired || params.every((param) => param.default !== void 0);
|
|
2882
|
+
const implementation = `{ ${params.map((property) => property.default === void 0 ? property.name : `${property.name} = ${stringify(property.default)}`).join(", ")} }: ${parameterTypeName}${isOptional ? " = {}" : ""}`;
|
|
2788
2883
|
const destructured = `{ ${params.map((property) => property.name).join(", ")} }`;
|
|
2789
2884
|
paramGetterProps = [{
|
|
2790
2885
|
type: GetterPropType.NAMED_PATH_PARAMS,
|
|
@@ -2949,13 +3044,15 @@ const getRoutePath = (path) => {
|
|
|
2949
3044
|
const matches = /([^{]*){?([\w*_-]*)}?(.*)/.exec(path);
|
|
2950
3045
|
if (!matches?.length) return path;
|
|
2951
3046
|
const prev = matches[1];
|
|
2952
|
-
const
|
|
3047
|
+
const rawParam = matches[2];
|
|
3048
|
+
const rest = matches[3];
|
|
3049
|
+
const param = sanitize(camel(rawParam), {
|
|
2953
3050
|
es5keyword: true,
|
|
2954
3051
|
underscore: true,
|
|
2955
3052
|
dash: true,
|
|
2956
3053
|
dot: true
|
|
2957
3054
|
});
|
|
2958
|
-
const next = hasParam(
|
|
3055
|
+
const next = hasParam(rest) ? getRoutePath(rest) : rest;
|
|
2959
3056
|
return hasParam(path) ? `${prev}\${${param}}${next}` : `${prev}${param}${next}`;
|
|
2960
3057
|
};
|
|
2961
3058
|
function getRoute(route) {
|
|
@@ -2975,13 +3072,14 @@ function getFullRoute(route, servers, baseUrl) {
|
|
|
2975
3072
|
if (!servers) throw new Error("Orval is configured to use baseUrl from the specifications 'servers' field, but there exist no servers in the specification.");
|
|
2976
3073
|
const server = servers.at(Math.min(baseUrl.index ?? 0, servers.length - 1));
|
|
2977
3074
|
if (!server) return "";
|
|
2978
|
-
|
|
2979
|
-
|
|
3075
|
+
const serverUrl = server.url ?? "";
|
|
3076
|
+
if (!server.variables) return serverUrl;
|
|
3077
|
+
let url = serverUrl;
|
|
2980
3078
|
const variables = baseUrl.variables;
|
|
2981
3079
|
for (const variableKey of Object.keys(server.variables)) {
|
|
2982
3080
|
const variable = server.variables[variableKey];
|
|
2983
3081
|
if (variables?.[variableKey]) {
|
|
2984
|
-
if (variable.enum && !variable.enum.some((e) => e == variables[variableKey])) throw new Error(`Invalid variable value '${variables[variableKey]}' for variable '${variableKey}' when resolving ${
|
|
3082
|
+
if (variable.enum && !variable.enum.some((e) => e == variables[variableKey])) throw new Error(`Invalid variable value '${variables[variableKey]}' for variable '${variableKey}' when resolving ${serverUrl}. Valid values are: ${variable.enum.join(", ")}.`);
|
|
2985
3083
|
url = url.replaceAll(`{${variableKey}}`, variables[variableKey]);
|
|
2986
3084
|
} else url = url.replaceAll(`{${variableKey}}`, String(variable.default));
|
|
2987
3085
|
}
|
|
@@ -3081,7 +3179,8 @@ function generateDependency({ deps, isAllowSyntheticDefaultImports, dependency,
|
|
|
3081
3179
|
}
|
|
3082
3180
|
function addDependency({ implementation, exports, dependency, projectName, isAllowSyntheticDefaultImports }) {
|
|
3083
3181
|
const toAdds = exports.filter((e) => {
|
|
3084
|
-
const searchWords = [e.alias, e.name].filter((p) => p?.length).join("|");
|
|
3182
|
+
const searchWords = [e.alias, e.name].filter((p) => Boolean(p?.length)).map((part) => escapeRegExp(part)).join("|");
|
|
3183
|
+
if (!searchWords) return false;
|
|
3085
3184
|
const pattern = new RegExp(String.raw`\b(${searchWords})\b`, "g");
|
|
3086
3185
|
return implementation.match(pattern);
|
|
3087
3186
|
});
|
|
@@ -3124,8 +3223,7 @@ function addDependency({ implementation, exports, dependency, projectName, isAll
|
|
|
3124
3223
|
}).join("\n") + "\n";
|
|
3125
3224
|
}
|
|
3126
3225
|
function getLibName(code) {
|
|
3127
|
-
|
|
3128
|
-
return splitString[splitString.length - 1].split(";")[0].trim();
|
|
3226
|
+
return (code.split(" from ").at(-1) ?? "").split(";")[0].trim();
|
|
3129
3227
|
}
|
|
3130
3228
|
function generateDependencyImports(implementation, imports, projectName, hasSchemaDir, isAllowSyntheticDefaultImports) {
|
|
3131
3229
|
const dependencies = imports.map((dep) => addDependency({
|
|
@@ -3170,7 +3268,7 @@ function generateModelInline(acc, model) {
|
|
|
3170
3268
|
return acc + `${model}\n`;
|
|
3171
3269
|
}
|
|
3172
3270
|
function generateModelsInline(obj) {
|
|
3173
|
-
const schemas = Object.values(obj).flat();
|
|
3271
|
+
const schemas = Array.isArray(obj) ? obj : Object.values(obj).flat();
|
|
3174
3272
|
let result = "";
|
|
3175
3273
|
for (const { model } of schemas) result = generateModelInline(result, model);
|
|
3176
3274
|
return result;
|
|
@@ -3334,9 +3432,14 @@ function removeComments(file) {
|
|
|
3334
3432
|
* (e.g. observe-mode branches), prefer getAngularFilteredParamsCallExpression +
|
|
3335
3433
|
* getAngularFilteredParamsHelperBody instead.
|
|
3336
3434
|
*/
|
|
3337
|
-
const getAngularFilteredParamsExpression = (paramsExpression, requiredNullableParamKeys = []
|
|
3435
|
+
const getAngularFilteredParamsExpression = (paramsExpression, requiredNullableParamKeys = [], preserveRequiredNullables = false) => {
|
|
3436
|
+
const filteredParamValueType = `string | number | boolean${preserveRequiredNullables ? " | null" : ""} | Array<string | number | boolean>`;
|
|
3437
|
+
const preserveNullableBranch = preserveRequiredNullables ? ` } else if (value === null && requiredNullableParamKeys.has(key)) {
|
|
3438
|
+
filteredParams[key] = value;
|
|
3439
|
+
` : "";
|
|
3440
|
+
return `(() => {
|
|
3338
3441
|
const requiredNullableParamKeys = new Set<string>(${JSON.stringify(requiredNullableParamKeys)});
|
|
3339
|
-
const filteredParams
|
|
3442
|
+
const filteredParams: Record<string, ${filteredParamValueType}> = {};
|
|
3340
3443
|
for (const [key, value] of Object.entries(${paramsExpression})) {
|
|
3341
3444
|
if (Array.isArray(value)) {
|
|
3342
3445
|
const filtered = value.filter(
|
|
@@ -3345,33 +3448,46 @@ const getAngularFilteredParamsExpression = (paramsExpression, requiredNullablePa
|
|
|
3345
3448
|
(typeof item === 'string' ||
|
|
3346
3449
|
typeof item === 'number' ||
|
|
3347
3450
|
typeof item === 'boolean'),
|
|
3348
|
-
|
|
3451
|
+
) as Array<string | number | boolean>;
|
|
3349
3452
|
if (filtered.length) {
|
|
3350
3453
|
filteredParams[key] = filtered;
|
|
3351
3454
|
}
|
|
3352
|
-
} else if (
|
|
3353
|
-
filteredParams[key] = value;
|
|
3354
|
-
} else if (
|
|
3455
|
+
${preserveNullableBranch} } else if (
|
|
3355
3456
|
value != null &&
|
|
3356
3457
|
(typeof value === 'string' ||
|
|
3357
3458
|
typeof value === 'number' ||
|
|
3358
3459
|
typeof value === 'boolean')
|
|
3359
3460
|
) {
|
|
3360
|
-
filteredParams[key] = value
|
|
3461
|
+
filteredParams[key] = value;
|
|
3361
3462
|
}
|
|
3362
3463
|
}
|
|
3363
|
-
return filteredParams
|
|
3464
|
+
return filteredParams;
|
|
3364
3465
|
})()`;
|
|
3466
|
+
};
|
|
3365
3467
|
/**
|
|
3366
3468
|
* Returns the body of a standalone `filterParams` helper function
|
|
3367
3469
|
* to be emitted once in the generated file header, replacing the
|
|
3368
3470
|
* inline IIFE that was previously duplicated in every method.
|
|
3369
3471
|
*/
|
|
3370
|
-
const getAngularFilteredParamsHelperBody = () => `
|
|
3472
|
+
const getAngularFilteredParamsHelperBody = () => `type AngularHttpParamValue = string | number | boolean | Array<string | number | boolean>;
|
|
3473
|
+
type AngularHttpParamValueWithNullable = AngularHttpParamValue | null;
|
|
3474
|
+
|
|
3475
|
+
function filterParams(
|
|
3476
|
+
params: Record<string, unknown>,
|
|
3477
|
+
requiredNullableKeys?: ReadonlySet<string>,
|
|
3478
|
+
preserveRequiredNullables?: false,
|
|
3479
|
+
): Record<string, AngularHttpParamValue>;
|
|
3480
|
+
function filterParams(
|
|
3371
3481
|
params: Record<string, unknown>,
|
|
3372
|
-
requiredNullableKeys:
|
|
3373
|
-
|
|
3374
|
-
|
|
3482
|
+
requiredNullableKeys: ReadonlySet<string> | undefined,
|
|
3483
|
+
preserveRequiredNullables: true,
|
|
3484
|
+
): Record<string, AngularHttpParamValueWithNullable>;
|
|
3485
|
+
function filterParams(
|
|
3486
|
+
params: Record<string, unknown>,
|
|
3487
|
+
requiredNullableKeys: ReadonlySet<string> = new Set(),
|
|
3488
|
+
preserveRequiredNullables = false,
|
|
3489
|
+
): Record<string, AngularHttpParamValueWithNullable> {
|
|
3490
|
+
const filteredParams: Record<string, AngularHttpParamValueWithNullable> = {};
|
|
3375
3491
|
for (const [key, value] of Object.entries(params)) {
|
|
3376
3492
|
if (Array.isArray(value)) {
|
|
3377
3493
|
const filtered = value.filter(
|
|
@@ -3384,7 +3500,11 @@ const getAngularFilteredParamsHelperBody = () => `function filterParams(
|
|
|
3384
3500
|
if (filtered.length) {
|
|
3385
3501
|
filteredParams[key] = filtered;
|
|
3386
3502
|
}
|
|
3387
|
-
} else if (
|
|
3503
|
+
} else if (
|
|
3504
|
+
preserveRequiredNullables &&
|
|
3505
|
+
value === null &&
|
|
3506
|
+
requiredNullableKeys.has(key)
|
|
3507
|
+
) {
|
|
3388
3508
|
filteredParams[key] = value;
|
|
3389
3509
|
} else if (
|
|
3390
3510
|
value != null &&
|
|
@@ -3392,15 +3512,15 @@ const getAngularFilteredParamsHelperBody = () => `function filterParams(
|
|
|
3392
3512
|
typeof value === 'number' ||
|
|
3393
3513
|
typeof value === 'boolean')
|
|
3394
3514
|
) {
|
|
3395
|
-
filteredParams[key] = value
|
|
3515
|
+
filteredParams[key] = value;
|
|
3396
3516
|
}
|
|
3397
3517
|
}
|
|
3398
|
-
return filteredParams
|
|
3518
|
+
return filteredParams;
|
|
3399
3519
|
}`;
|
|
3400
3520
|
/**
|
|
3401
3521
|
* Returns a call expression to the `filterParams` helper function.
|
|
3402
3522
|
*/
|
|
3403
|
-
const getAngularFilteredParamsCallExpression = (paramsExpression, requiredNullableParamKeys = []) => `filterParams(${paramsExpression}, new Set<string>(${JSON.stringify(requiredNullableParamKeys)}))`;
|
|
3523
|
+
const getAngularFilteredParamsCallExpression = (paramsExpression, requiredNullableParamKeys = [], preserveRequiredNullables = false) => `filterParams(${paramsExpression}, new Set<string>(${JSON.stringify(requiredNullableParamKeys)})${preserveRequiredNullables ? ", true" : ""})`;
|
|
3404
3524
|
function generateBodyOptions(body, isFormData, isFormUrlEncoded) {
|
|
3405
3525
|
if (isFormData && body.formData) return "\n formData,";
|
|
3406
3526
|
if (isFormUrlEncoded && body.formUrlEncoded) return "\n formUrlEncoded,";
|
|
@@ -3422,7 +3542,7 @@ function generateAxiosOptions({ response, isExactOptionalPropertyTypes, angularO
|
|
|
3422
3542
|
let value = "";
|
|
3423
3543
|
if (!isRequestOptions) {
|
|
3424
3544
|
if (queryParams) if (isAngular) {
|
|
3425
|
-
const iifeExpr = getAngularFilteredParamsExpression("params ?? {}", requiredNullableQueryParamKeys);
|
|
3545
|
+
const iifeExpr = getAngularFilteredParamsExpression("params ?? {}", requiredNullableQueryParamKeys, !!paramsSerializer);
|
|
3426
3546
|
value += paramsSerializer ? `\n params: ${paramsSerializer.name}(${iifeExpr}),` : `\n params: ${iifeExpr},`;
|
|
3427
3547
|
} else value += "\n params,";
|
|
3428
3548
|
if (headers) value += "\n headers,";
|
|
@@ -3439,7 +3559,7 @@ function generateAxiosOptions({ response, isExactOptionalPropertyTypes, angularO
|
|
|
3439
3559
|
if (queryParams) if (isVue) value += "\n params: {...unref(params), ...options?.params},";
|
|
3440
3560
|
else if (isAngular && angularParamsRef) value += `\n params: ${angularParamsRef},`;
|
|
3441
3561
|
else if (isAngular && paramsSerializer) {
|
|
3442
|
-
const callExpr = getAngularFilteredParamsCallExpression("{...params, ...options?.params}", requiredNullableQueryParamKeys);
|
|
3562
|
+
const callExpr = getAngularFilteredParamsCallExpression("{...params, ...options?.params}", requiredNullableQueryParamKeys, true);
|
|
3443
3563
|
value += `\n params: ${paramsSerializer.name}(${callExpr}),`;
|
|
3444
3564
|
} else if (isAngular) value += `\n params: ${getAngularFilteredParamsCallExpression("{...params, ...options?.params}", requiredNullableQueryParamKeys)},`;
|
|
3445
3565
|
else value += "\n params: {...params, ...options?.params},";
|
|
@@ -3887,6 +4007,20 @@ function _filteredVerbs(verbs, filters) {
|
|
|
3887
4007
|
});
|
|
3888
4008
|
}
|
|
3889
4009
|
|
|
4010
|
+
//#endregion
|
|
4011
|
+
//#region src/writers/file.ts
|
|
4012
|
+
const TRAILING_WHITESPACE_RE = /[^\S\r\n]+$/gm;
|
|
4013
|
+
/**
|
|
4014
|
+
* Write generated code to a file, stripping trailing whitespace from each line.
|
|
4015
|
+
*
|
|
4016
|
+
* Template literals in code generators can produce lines with only whitespace
|
|
4017
|
+
* when conditional expressions evaluate to empty strings. This function
|
|
4018
|
+
* ensures the output is always clean regardless of generator implementation.
|
|
4019
|
+
*/
|
|
4020
|
+
async function writeGeneratedFile(filePath, content) {
|
|
4021
|
+
await fs$1.outputFile(filePath, content.replaceAll(TRAILING_WHITESPACE_RE, ""));
|
|
4022
|
+
}
|
|
4023
|
+
|
|
3890
4024
|
//#endregion
|
|
3891
4025
|
//#region src/writers/schemas.ts
|
|
3892
4026
|
/**
|
|
@@ -3969,19 +4103,26 @@ function getSchemaGroups(schemaPath, schemas, namingConvention, fileExtension) {
|
|
|
3969
4103
|
}
|
|
3970
4104
|
function getCanonicalMap(schemaGroups, schemaPath, namingConvention, fileExtension) {
|
|
3971
4105
|
const canonicalPathMap = /* @__PURE__ */ new Map();
|
|
4106
|
+
const canonicalNameMap = /* @__PURE__ */ new Map();
|
|
3972
4107
|
for (const [key, groupSchemas] of Object.entries(schemaGroups)) {
|
|
3973
|
-
const
|
|
3974
|
-
|
|
3975
|
-
importPath: canonicalPath,
|
|
4108
|
+
const canonicalInfo = {
|
|
4109
|
+
importPath: getPath(schemaPath, conventionName(groupSchemas[0].name, namingConvention), fileExtension),
|
|
3976
4110
|
name: groupSchemas[0].name
|
|
3977
|
-
}
|
|
4111
|
+
};
|
|
4112
|
+
canonicalPathMap.set(key, canonicalInfo);
|
|
4113
|
+
for (const schema of groupSchemas) canonicalNameMap.set(schema.name, canonicalInfo);
|
|
3978
4114
|
}
|
|
3979
|
-
return
|
|
4115
|
+
return {
|
|
4116
|
+
canonicalPathMap,
|
|
4117
|
+
canonicalNameMap
|
|
4118
|
+
};
|
|
3980
4119
|
}
|
|
3981
|
-
function normalizeCanonicalImportPaths(schemas, canonicalPathMap, schemaPath, namingConvention, fileExtension) {
|
|
4120
|
+
function normalizeCanonicalImportPaths(schemas, canonicalPathMap, canonicalNameMap, schemaPath, namingConvention, fileExtension) {
|
|
3982
4121
|
for (const schema of schemas) schema.imports = schema.imports.map((imp) => {
|
|
4122
|
+
const canonicalByName = canonicalNameMap.get(imp.name);
|
|
3983
4123
|
const resolvedImportKey = resolveImportKey(schemaPath, imp.importPath ?? `./${conventionName(imp.name, namingConvention)}`, fileExtension);
|
|
3984
|
-
const
|
|
4124
|
+
const canonicalByPath = canonicalPathMap.get(resolvedImportKey);
|
|
4125
|
+
const canonical = canonicalByName ?? canonicalByPath;
|
|
3985
4126
|
if (!canonical?.importPath) return imp;
|
|
3986
4127
|
const importPath = removeFileExtension(relativeSafe(schemaPath, canonical.importPath.replaceAll("\\", "/")), fileExtension);
|
|
3987
4128
|
return {
|
|
@@ -4009,19 +4150,18 @@ function resolveImportKey(schemaPath, importPath, fileExtension) {
|
|
|
4009
4150
|
function removeFileExtension(path, fileExtension) {
|
|
4010
4151
|
return path.endsWith(fileExtension) ? path.slice(0, path.length - fileExtension.length) : path;
|
|
4011
4152
|
}
|
|
4012
|
-
function getSchema({ schema: { imports, model },
|
|
4153
|
+
function getSchema({ schema: { imports, model }, header, namingConvention = NamingConvention.CAMEL_CASE }) {
|
|
4013
4154
|
let file = header;
|
|
4014
4155
|
file += generateImports({
|
|
4015
4156
|
imports: imports.filter((imp) => !model.includes(`type ${imp.alias ?? imp.name} =`) && !model.includes(`interface ${imp.alias ?? imp.name} {`)),
|
|
4016
|
-
target,
|
|
4017
4157
|
namingConvention
|
|
4018
4158
|
});
|
|
4019
4159
|
file += imports.length > 0 ? "\n\n" : "\n";
|
|
4020
4160
|
file += model;
|
|
4021
4161
|
return file;
|
|
4022
4162
|
}
|
|
4023
|
-
function getPath(path
|
|
4024
|
-
return
|
|
4163
|
+
function getPath(path, name, fileExtension) {
|
|
4164
|
+
return nodePath.join(path, `${name}${fileExtension}`);
|
|
4025
4165
|
}
|
|
4026
4166
|
function writeModelInline(acc, model) {
|
|
4027
4167
|
return acc + `${model}\n`;
|
|
@@ -4034,19 +4174,20 @@ function writeModelsInline(array) {
|
|
|
4034
4174
|
async function writeSchema({ path, schema, target, namingConvention, fileExtension, header }) {
|
|
4035
4175
|
const name = conventionName(schema.name, namingConvention);
|
|
4036
4176
|
try {
|
|
4037
|
-
await
|
|
4177
|
+
await writeGeneratedFile(getPath(path, name, fileExtension), getSchema({
|
|
4038
4178
|
schema,
|
|
4039
4179
|
target,
|
|
4040
4180
|
header,
|
|
4041
4181
|
namingConvention
|
|
4042
4182
|
}));
|
|
4043
4183
|
} catch (error) {
|
|
4044
|
-
throw new Error(`Oups... 🍻. An Error occurred while writing schema ${name} => ${String(error)}
|
|
4184
|
+
throw new Error(`Oups... 🍻. An Error occurred while writing schema ${name} => ${String(error)}`, { cause: error });
|
|
4045
4185
|
}
|
|
4046
4186
|
}
|
|
4047
4187
|
async function writeSchemas({ schemaPath, schemas, target, namingConvention, fileExtension, header, indexFiles }) {
|
|
4048
4188
|
const schemaGroups = getSchemaGroups(schemaPath, schemas, namingConvention, fileExtension);
|
|
4049
|
-
|
|
4189
|
+
const { canonicalPathMap, canonicalNameMap } = getCanonicalMap(schemaGroups, schemaPath, namingConvention, fileExtension);
|
|
4190
|
+
normalizeCanonicalImportPaths(schemas, canonicalPathMap, canonicalNameMap, schemaPath, namingConvention, fileExtension);
|
|
4050
4191
|
for (const groupSchemas of Object.values(schemaGroups)) {
|
|
4051
4192
|
if (groupSchemas.length === 1) {
|
|
4052
4193
|
await writeSchema({
|
|
@@ -4069,21 +4210,14 @@ async function writeSchemas({ schemaPath, schemas, target, namingConvention, fil
|
|
|
4069
4210
|
});
|
|
4070
4211
|
}
|
|
4071
4212
|
if (indexFiles) {
|
|
4072
|
-
const schemaFilePath =
|
|
4213
|
+
const schemaFilePath = nodePath.join(schemaPath, `index${fileExtension}`);
|
|
4073
4214
|
await fs$1.ensureFile(schemaFilePath);
|
|
4074
4215
|
const ext = fileExtension.endsWith(".ts") ? fileExtension.slice(0, -3) : fileExtension;
|
|
4075
4216
|
const conventionNamesSet = new Set(Object.values(schemaGroups).map((group) => conventionName(group[0].name, namingConvention)));
|
|
4076
4217
|
try {
|
|
4077
|
-
|
|
4078
|
-
const existingExports = (await fs$1.readFile(schemaFilePath, "utf8")).match(/export\s+\*\s+from\s+['"][^'"]+['"]/g)?.map((statement) => {
|
|
4079
|
-
const match = /export\s+\*\s+from\s+['"]([^'"]+)['"]/.exec(statement);
|
|
4080
|
-
if (!match) return;
|
|
4081
|
-
return `export * from '${match[1]}';`;
|
|
4082
|
-
}).filter(Boolean) ?? [];
|
|
4083
|
-
const fileContent = `${header}\n${[...new Set([...existingExports, ...currentExports])].toSorted((a, b) => a.localeCompare(b)).join("\n")}`;
|
|
4084
|
-
await fs$1.writeFile(schemaFilePath, fileContent, { encoding: "utf8" });
|
|
4218
|
+
await writeGeneratedFile(schemaFilePath, `${header}\n${[...conventionNamesSet].map((schemaName) => `export * from './${schemaName}${ext}';`).toSorted((a, b) => a.localeCompare(b)).join("\n")}\n`);
|
|
4085
4219
|
} catch (error) {
|
|
4086
|
-
throw new Error(`Oups... 🍻. An Error occurred while writing schema index file ${schemaFilePath} => ${String(error)}
|
|
4220
|
+
throw new Error(`Oups... 🍻. An Error occurred while writing schema index file ${schemaFilePath} => ${String(error)}`, { cause: error });
|
|
4087
4221
|
}
|
|
4088
4222
|
}
|
|
4089
4223
|
}
|
|
@@ -4092,7 +4226,7 @@ async function writeSchemas({ schemaPath, schemas, target, namingConvention, fil
|
|
|
4092
4226
|
//#region src/writers/generate-imports-for-builder.ts
|
|
4093
4227
|
function generateImportsForBuilder(output, imports, relativeSchemasPath) {
|
|
4094
4228
|
const isZodSchemaOutput = isObject(output.schemas) && output.schemas.type === "zod";
|
|
4095
|
-
let schemaImports
|
|
4229
|
+
let schemaImports;
|
|
4096
4230
|
if (output.indexFiles) schemaImports = isZodSchemaOutput ? [{
|
|
4097
4231
|
exports: imports.filter((i) => !i.importPath),
|
|
4098
4232
|
dependency: joinSafe(relativeSchemasPath, "index.zod")
|
|
@@ -4100,15 +4234,21 @@ function generateImportsForBuilder(output, imports, relativeSchemasPath) {
|
|
|
4100
4234
|
exports: imports.filter((i) => !i.importPath),
|
|
4101
4235
|
dependency: relativeSchemasPath
|
|
4102
4236
|
}];
|
|
4103
|
-
else
|
|
4104
|
-
const
|
|
4105
|
-
const
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
dependency
|
|
4110
|
-
|
|
4111
|
-
|
|
4237
|
+
else {
|
|
4238
|
+
const importsByDependency = /* @__PURE__ */ new Map();
|
|
4239
|
+
for (const schemaImport of imports.filter((i) => !i.importPath)) {
|
|
4240
|
+
const normalizedName = conventionName(isZodSchemaOutput ? schemaImport.name : schemaImport.schemaName ?? schemaImport.name, output.namingConvention);
|
|
4241
|
+
const suffix = isZodSchemaOutput ? ".zod" : "";
|
|
4242
|
+
const importExtension = output.fileExtension.replace(/\.ts$/, "") || "";
|
|
4243
|
+
const dependency = joinSafe(relativeSchemasPath, `${normalizedName}${suffix}${importExtension}`);
|
|
4244
|
+
if (!importsByDependency.has(dependency)) importsByDependency.set(dependency, []);
|
|
4245
|
+
importsByDependency.get(dependency)?.push(schemaImport);
|
|
4246
|
+
}
|
|
4247
|
+
schemaImports = [...importsByDependency.entries()].map(([dependency, dependencyImports]) => ({
|
|
4248
|
+
dependency,
|
|
4249
|
+
exports: uniqueBy(dependencyImports, (entry) => `${entry.name}|${entry.alias ?? ""}|${String(entry.values)}|${String(entry.default)}`)
|
|
4250
|
+
}));
|
|
4251
|
+
}
|
|
4112
4252
|
const otherImports = uniqueBy(imports.filter((i) => !!i.importPath), (x) => x.name + x.importPath).map((i) => {
|
|
4113
4253
|
return {
|
|
4114
4254
|
exports: [i],
|
|
@@ -4239,14 +4379,24 @@ interface TypedResponse<T> extends Response {
|
|
|
4239
4379
|
async function writeSingleMode({ builder, output, projectName, header, needSchema }) {
|
|
4240
4380
|
try {
|
|
4241
4381
|
const { path } = getFileInfo(output.target, {
|
|
4242
|
-
backupFilename: conventionName(builder.info.title, output.namingConvention),
|
|
4382
|
+
backupFilename: conventionName(builder.info.title ?? "filename", output.namingConvention),
|
|
4243
4383
|
extension: output.fileExtension
|
|
4244
4384
|
});
|
|
4245
4385
|
const { imports, importsMock, implementation, implementationMock, mutators, clientMutators, formData, formUrlEncoded, paramsSerializer, fetchReviver } = generateTarget(builder, output);
|
|
4246
4386
|
let data = header;
|
|
4247
4387
|
const schemasPath = output.schemas ? getRelativeImportPath(path, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : void 0;
|
|
4248
4388
|
const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
|
|
4249
|
-
const
|
|
4389
|
+
const normalizedImports = imports.filter((imp) => {
|
|
4390
|
+
const searchWords = [imp.alias, imp.name].filter((part) => Boolean(part?.length)).map((part) => escapeRegExp(part)).join("|");
|
|
4391
|
+
if (!searchWords) return false;
|
|
4392
|
+
return new RegExp(String.raw`\b(${searchWords})\b`, "g").test(implementation);
|
|
4393
|
+
}).map((imp) => ({ ...imp }));
|
|
4394
|
+
for (const mockImport of importsMock) {
|
|
4395
|
+
const matchingImport = normalizedImports.find((imp) => imp.name === mockImport.name && (imp.alias ?? "") === (mockImport.alias ?? ""));
|
|
4396
|
+
if (!matchingImport) continue;
|
|
4397
|
+
if (!!mockImport.values || !!mockImport.isConstant || !!mockImport.default || !!mockImport.namespaceImport || !!mockImport.syntheticDefaultImport) matchingImport.values = true;
|
|
4398
|
+
}
|
|
4399
|
+
const importsForBuilder = schemasPath ? generateImportsForBuilder(output, normalizedImports, schemasPath) : [];
|
|
4250
4400
|
data += builder.imports({
|
|
4251
4401
|
client: output.client,
|
|
4252
4402
|
implementation,
|
|
@@ -4261,7 +4411,7 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
|
|
|
4261
4411
|
output
|
|
4262
4412
|
});
|
|
4263
4413
|
if (output.mock) {
|
|
4264
|
-
const importsMockForBuilder = schemasPath ? generateImportsForBuilder(output, importsMock, schemasPath) : [];
|
|
4414
|
+
const importsMockForBuilder = schemasPath ? generateImportsForBuilder(output, importsMock.filter((impMock) => !normalizedImports.some((imp) => imp.name === impMock.name && (imp.alias ?? "") === (impMock.alias ?? ""))), schemasPath) : [];
|
|
4265
4415
|
data += builder.importsMock({
|
|
4266
4416
|
implementation: implementationMock,
|
|
4267
4417
|
imports: importsMockForBuilder,
|
|
@@ -4294,11 +4444,11 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
|
|
|
4294
4444
|
data += "\n\n";
|
|
4295
4445
|
data += implementationMock;
|
|
4296
4446
|
}
|
|
4297
|
-
await
|
|
4447
|
+
await writeGeneratedFile(path, data);
|
|
4298
4448
|
return [path];
|
|
4299
4449
|
} catch (error) {
|
|
4300
4450
|
const errorMsg = error instanceof Error ? error.message : "unknown error";
|
|
4301
|
-
throw new Error(`Oups... 🍻. An Error occurred while writing file => ${errorMsg}
|
|
4451
|
+
throw new Error(`Oups... 🍻. An Error occurred while writing file => ${errorMsg}`, { cause: error });
|
|
4302
4452
|
}
|
|
4303
4453
|
}
|
|
4304
4454
|
|
|
@@ -4307,7 +4457,7 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
|
|
|
4307
4457
|
async function writeSplitMode({ builder, output, projectName, header, needSchema }) {
|
|
4308
4458
|
try {
|
|
4309
4459
|
const { path: targetPath, filename, dirname, extension } = getFileInfo(output.target, {
|
|
4310
|
-
backupFilename: conventionName(builder.info.title, output.namingConvention),
|
|
4460
|
+
backupFilename: conventionName(builder.info.title ?? "filename", output.namingConvention),
|
|
4311
4461
|
extension: output.fileExtension
|
|
4312
4462
|
});
|
|
4313
4463
|
const { imports, implementation, implementationMock, importsMock, mutators, clientMutators, formData, formUrlEncoded, paramsSerializer, fetchReviver } = generateTarget(builder, output);
|
|
@@ -4338,11 +4488,8 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
|
|
|
4338
4488
|
isAllowSyntheticDefaultImports,
|
|
4339
4489
|
options: isFunction(output.mock) ? void 0 : output.mock
|
|
4340
4490
|
});
|
|
4341
|
-
const schemasPath = output.schemas ? void 0 :
|
|
4342
|
-
if (schemasPath && needSchema)
|
|
4343
|
-
const schemasData = header + generateModelsInline(builder.schemas);
|
|
4344
|
-
await fs$1.outputFile(schemasPath, schemasData);
|
|
4345
|
-
}
|
|
4491
|
+
const schemasPath = output.schemas ? void 0 : nodePath.join(dirname, filename + ".schemas" + extension);
|
|
4492
|
+
if (schemasPath && needSchema) await writeGeneratedFile(schemasPath, header + generateModelsInline(builder.schemas));
|
|
4346
4493
|
if (mutators) implementationData += generateMutatorImports({
|
|
4347
4494
|
mutators,
|
|
4348
4495
|
implementation
|
|
@@ -4363,17 +4510,17 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
|
|
|
4363
4510
|
implementationData += `\n${implementation}`;
|
|
4364
4511
|
mockData += `\n${implementationMock}`;
|
|
4365
4512
|
const implementationFilename = filename + (OutputClient.ANGULAR === output.client ? ".service" : "") + extension;
|
|
4366
|
-
const implementationPath =
|
|
4367
|
-
await
|
|
4368
|
-
const mockPath = output.mock ?
|
|
4369
|
-
if (mockPath) await
|
|
4513
|
+
const implementationPath = nodePath.join(dirname, implementationFilename);
|
|
4514
|
+
await writeGeneratedFile(implementationPath, implementationData);
|
|
4515
|
+
const mockPath = output.mock ? nodePath.join(dirname, filename + "." + getMockFileExtensionByTypeName(output.mock) + extension) : void 0;
|
|
4516
|
+
if (mockPath) await writeGeneratedFile(mockPath, mockData);
|
|
4370
4517
|
return [
|
|
4371
4518
|
implementationPath,
|
|
4372
4519
|
...schemasPath ? [schemasPath] : [],
|
|
4373
4520
|
...mockPath ? [mockPath] : []
|
|
4374
4521
|
];
|
|
4375
4522
|
} catch (error) {
|
|
4376
|
-
throw new Error(`Oups... 🍻. An Error occurred while splitting => ${String(error)}
|
|
4523
|
+
throw new Error(`Oups... 🍻. An Error occurred while splitting => ${String(error)}`, { cause: error });
|
|
4377
4524
|
}
|
|
4378
4525
|
}
|
|
4379
4526
|
|
|
@@ -4496,13 +4643,13 @@ function generateTargetForTags(builder, options) {
|
|
|
4496
4643
|
//#region src/writers/split-tags-mode.ts
|
|
4497
4644
|
async function writeSplitTagsMode({ builder, output, projectName, header, needSchema }) {
|
|
4498
4645
|
const { filename, dirname, extension } = getFileInfo(output.target, {
|
|
4499
|
-
backupFilename: conventionName(builder.info.title, output.namingConvention),
|
|
4646
|
+
backupFilename: conventionName(builder.info.title ?? "filename", output.namingConvention),
|
|
4500
4647
|
extension: output.fileExtension
|
|
4501
4648
|
});
|
|
4502
4649
|
const target = generateTargetForTags(builder, output);
|
|
4503
4650
|
const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
|
|
4504
4651
|
const mockOption = output.mock && !isFunction(output.mock) ? output.mock : void 0;
|
|
4505
|
-
const indexFilePath = mockOption?.indexMockFiles ?
|
|
4652
|
+
const indexFilePath = mockOption?.indexMockFiles ? nodePath.join(dirname, "index." + getMockFileExtensionByTypeName(mockOption) + extension) : void 0;
|
|
4506
4653
|
if (indexFilePath) await fs$1.outputFile(indexFilePath, "");
|
|
4507
4654
|
const tagEntries = Object.entries(target);
|
|
4508
4655
|
const generatedFilePathsArray = await Promise.all(tagEntries.map(async ([tag, target]) => {
|
|
@@ -4510,7 +4657,7 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
|
|
|
4510
4657
|
const { imports, implementation, implementationMock, importsMock, mutators, clientMutators, formData, fetchReviver, formUrlEncoded, paramsSerializer } = target;
|
|
4511
4658
|
let implementationData = header;
|
|
4512
4659
|
let mockData = header;
|
|
4513
|
-
const importerPath =
|
|
4660
|
+
const importerPath = nodePath.join(dirname, tag, tag + extension);
|
|
4514
4661
|
const relativeSchemasPath = output.schemas ? getRelativeImportPath(importerPath, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "../" + filename + ".schemas";
|
|
4515
4662
|
const importsForBuilder = generateImportsForBuilder(output, imports, relativeSchemasPath);
|
|
4516
4663
|
implementationData += builder.imports({
|
|
@@ -4535,11 +4682,8 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
|
|
|
4535
4682
|
isAllowSyntheticDefaultImports,
|
|
4536
4683
|
options: isFunction(output.mock) ? void 0 : output.mock
|
|
4537
4684
|
});
|
|
4538
|
-
const schemasPath = output.schemas ? void 0 :
|
|
4539
|
-
if (schemasPath && needSchema)
|
|
4540
|
-
const schemasData = header + generateModelsInline(builder.schemas);
|
|
4541
|
-
await fs$1.outputFile(schemasPath, schemasData);
|
|
4542
|
-
}
|
|
4685
|
+
const schemasPath = output.schemas ? void 0 : nodePath.join(dirname, filename + ".schemas" + extension);
|
|
4686
|
+
if (schemasPath && needSchema) await writeGeneratedFile(schemasPath, header + generateModelsInline(builder.schemas));
|
|
4543
4687
|
if (mutators) implementationData += generateMutatorImports({
|
|
4544
4688
|
mutators,
|
|
4545
4689
|
implementation,
|
|
@@ -4576,17 +4720,17 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
|
|
|
4576
4720
|
implementationData += `\n${implementation}`;
|
|
4577
4721
|
mockData += `\n${implementationMock}`;
|
|
4578
4722
|
const implementationFilename = tag + (OutputClient.ANGULAR === output.client ? ".service" : "") + extension;
|
|
4579
|
-
const implementationPath =
|
|
4580
|
-
await
|
|
4581
|
-
const mockPath = output.mock ?
|
|
4582
|
-
if (mockPath) await
|
|
4723
|
+
const implementationPath = nodePath.join(dirname, tag, implementationFilename);
|
|
4724
|
+
await writeGeneratedFile(implementationPath, implementationData);
|
|
4725
|
+
const mockPath = output.mock ? nodePath.join(dirname, tag, tag + "." + getMockFileExtensionByTypeName(output.mock) + extension) : void 0;
|
|
4726
|
+
if (mockPath) await writeGeneratedFile(mockPath, mockData);
|
|
4583
4727
|
return [
|
|
4584
4728
|
implementationPath,
|
|
4585
4729
|
...schemasPath ? [schemasPath] : [],
|
|
4586
4730
|
...mockPath ? [mockPath] : []
|
|
4587
4731
|
];
|
|
4588
4732
|
} catch (error) {
|
|
4589
|
-
throw new Error(`Oups... 🍻. An Error occurred while splitting tag ${tag} => ${String(error)}
|
|
4733
|
+
throw new Error(`Oups... 🍻. An Error occurred while splitting tag ${tag} => ${String(error)}`, { cause: error });
|
|
4590
4734
|
}
|
|
4591
4735
|
}));
|
|
4592
4736
|
if (indexFilePath && mockOption) {
|
|
@@ -4596,14 +4740,14 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
|
|
|
4596
4740
|
}).join("");
|
|
4597
4741
|
await fs$1.appendFile(indexFilePath, indexContent);
|
|
4598
4742
|
}
|
|
4599
|
-
return [...indexFilePath ? [indexFilePath] : [], ...generatedFilePathsArray.flat()];
|
|
4743
|
+
return [...new Set([...indexFilePath ? [indexFilePath] : [], ...generatedFilePathsArray.flat()])];
|
|
4600
4744
|
}
|
|
4601
4745
|
|
|
4602
4746
|
//#endregion
|
|
4603
4747
|
//#region src/writers/tags-mode.ts
|
|
4604
4748
|
async function writeTagsMode({ builder, output, projectName, header, needSchema }) {
|
|
4605
4749
|
const { path: targetPath, filename, dirname, extension } = getFileInfo(output.target, {
|
|
4606
|
-
backupFilename: conventionName(builder.info.title, output.namingConvention),
|
|
4750
|
+
backupFilename: conventionName(builder.info.title ?? "filename", output.namingConvention),
|
|
4607
4751
|
extension: output.fileExtension
|
|
4608
4752
|
});
|
|
4609
4753
|
const target = generateTargetForTags(builder, output);
|
|
@@ -4613,7 +4757,17 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema
|
|
|
4613
4757
|
const { imports, implementation, implementationMock, importsMock, mutators, clientMutators, formData, formUrlEncoded, fetchReviver, paramsSerializer } = target;
|
|
4614
4758
|
let data = header;
|
|
4615
4759
|
const schemasPathRelative = output.schemas ? getRelativeImportPath(targetPath, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "./" + filename + ".schemas";
|
|
4616
|
-
const
|
|
4760
|
+
const normalizedImports = imports.filter((imp) => {
|
|
4761
|
+
const searchWords = [imp.alias, imp.name].filter((part) => Boolean(part?.length)).map((part) => escapeRegExp(part)).join("|");
|
|
4762
|
+
if (!searchWords) return false;
|
|
4763
|
+
return new RegExp(String.raw`\b(${searchWords})\b`, "g").test(implementation);
|
|
4764
|
+
}).map((imp) => ({ ...imp }));
|
|
4765
|
+
for (const mockImport of importsMock) {
|
|
4766
|
+
const matchingImport = normalizedImports.find((imp) => imp.name === mockImport.name && (imp.alias ?? "") === (mockImport.alias ?? ""));
|
|
4767
|
+
if (!matchingImport) continue;
|
|
4768
|
+
if (!!mockImport.values || !!mockImport.isConstant || !!mockImport.default || !!mockImport.namespaceImport || !!mockImport.syntheticDefaultImport) matchingImport.values = true;
|
|
4769
|
+
}
|
|
4770
|
+
const importsForBuilder = generateImportsForBuilder(output, normalizedImports, schemasPathRelative);
|
|
4617
4771
|
data += builder.imports({
|
|
4618
4772
|
client: output.client,
|
|
4619
4773
|
implementation,
|
|
@@ -4628,7 +4782,7 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema
|
|
|
4628
4782
|
output
|
|
4629
4783
|
});
|
|
4630
4784
|
if (output.mock) {
|
|
4631
|
-
const importsMockForBuilder = generateImportsForBuilder(output, importsMock, schemasPathRelative);
|
|
4785
|
+
const importsMockForBuilder = generateImportsForBuilder(output, importsMock.filter((impMock) => !normalizedImports.some((imp) => imp.name === impMock.name && (imp.alias ?? "") === (impMock.alias ?? ""))), schemasPathRelative);
|
|
4632
4786
|
data += builder.importsMock({
|
|
4633
4787
|
implementation: implementationMock,
|
|
4634
4788
|
imports: importsMockForBuilder,
|
|
@@ -4638,11 +4792,8 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema
|
|
|
4638
4792
|
options: isFunction(output.mock) ? void 0 : output.mock
|
|
4639
4793
|
});
|
|
4640
4794
|
}
|
|
4641
|
-
const schemasPath = output.schemas ? void 0 :
|
|
4642
|
-
if (schemasPath && needSchema)
|
|
4643
|
-
const schemasData = header + generateModelsInline(builder.schemas);
|
|
4644
|
-
await fs$1.outputFile(schemasPath, schemasData);
|
|
4645
|
-
}
|
|
4795
|
+
const schemasPath = output.schemas ? void 0 : nodePath.join(dirname, filename + ".schemas" + extension);
|
|
4796
|
+
if (schemasPath && needSchema) await writeGeneratedFile(schemasPath, header + generateModelsInline(builder.schemas));
|
|
4646
4797
|
if (mutators) data += generateMutatorImports({
|
|
4647
4798
|
mutators,
|
|
4648
4799
|
implementation
|
|
@@ -4666,15 +4817,15 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema
|
|
|
4666
4817
|
data += "\n\n";
|
|
4667
4818
|
data += implementationMock;
|
|
4668
4819
|
}
|
|
4669
|
-
const implementationPath =
|
|
4670
|
-
await
|
|
4820
|
+
const implementationPath = nodePath.join(dirname, `${kebab(tag)}${extension}`);
|
|
4821
|
+
await writeGeneratedFile(implementationPath, data);
|
|
4671
4822
|
return [implementationPath, ...schemasPath ? [schemasPath] : []];
|
|
4672
4823
|
} catch (error) {
|
|
4673
|
-
throw new Error(`Oups... 🍻. An Error occurred while writing tag ${tag} => ${String(error)}
|
|
4824
|
+
throw new Error(`Oups... 🍻. An Error occurred while writing tag ${tag} => ${String(error)}`, { cause: error });
|
|
4674
4825
|
}
|
|
4675
4826
|
}))).flat();
|
|
4676
4827
|
}
|
|
4677
4828
|
|
|
4678
4829
|
//#endregion
|
|
4679
|
-
export { BODY_TYPE_NAME, EnumGeneration, ErrorWithTag, FormDataArrayHandling, GetterPropType, LogLevels, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SchemaType, TEMPLATE_TAG_REGEX, URL_REGEX, VERBS_WITH_BODY, Verbs, _filteredVerbs, addDependency, asyncReduce, camel, combineSchemas, compareVersions, conventionName, count, createDebugger, createLogger, createSuccessMessage, createTypeAliasIfNeeded, dedupeUnionType, dynamicImport, escape, filterByContentType, fixCrossDirectoryImports, fixRegularSchemaImports, generalJSTypes, generalJSTypesWithArray, generateAxiosOptions, generateBodyMutatorConfig, generateBodyOptions, generateComponentDefinition, generateDependencyImports, generateFormDataAndUrlEncodedFunction, generateImports, generateModelInline, generateModelsInline, generateMutator, generateMutatorConfig, generateMutatorImports, generateMutatorRequestOptions, generateOptions, generateParameterDefinition, generateQueryParamsAxiosConfig, generateSchemasDefinition, generateTarget, generateTargetForTags, generateVerbImports, generateVerbOptions, generateVerbsOptions, getAngularFilteredParamsCallExpression, getAngularFilteredParamsExpression, getAngularFilteredParamsHelperBody, getArray, getBody, getCombinedEnumValue, getDefaultContentType, getEnum, getEnumDescriptions, getEnumImplementation, getEnumNames, getEnumUnionFromSchema, getExtension, getFileInfo, getFormDataFieldFileType, getFullRoute, getIsBodyVerb, getKey, getMockFileExtensionByTypeName, getNumberWord, getObject, getOperationId, getOrvalGeneratedTypes, getParameters, getParams, getParamsInPath, getPropertySafe, getProps, getQueryParams, getRefInfo, getResReqTypes, getResponse, getResponseTypeCategory, getRoute, getRouteAsArray, getScalar, getSuccessResponseType, getTypedResponse, isBinaryContentType, isBoolean, isDirectory, isFunction, isModule, isNullish, isNumber, isNumeric, isObject, isReference, isSchema, isString, isStringLike, isSyntheticDefaultImportsAllow, isUrl, isVerb, isVerbose, jsDoc, jsStringEscape, kebab, keyValuePairsToJsDoc, log, logError, logVerbose, mergeDeep, mismatchArgsMessage, pascal, removeFilesAndEmptyFolders, resolveDiscriminators, resolveExampleRefs, resolveInstalledVersion, resolveInstalledVersions, resolveObject, resolveRef, resolveValue, sanitize, setVerbose, snake, sortByPriority, splitSchemasByType, startMessage, stringify, toObjectString, path_exports as upath, upper, writeModelInline, writeModelsInline, writeSchema, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode };
|
|
4830
|
+
export { BODY_TYPE_NAME, EnumGeneration, ErrorWithTag, FormDataArrayHandling, GetterPropType, LogLevels, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SchemaType, TEMPLATE_TAG_REGEX, URL_REGEX, VERBS_WITH_BODY, Verbs, _filteredVerbs, addDependency, asyncReduce, camel, combineSchemas, compareVersions, conventionName, count, createDebugger, createLogger, createSuccessMessage, createTypeAliasIfNeeded, dedupeUnionType, dynamicImport, escape, escapeRegExp, filterByContentType, fixCrossDirectoryImports, fixRegularSchemaImports, generalJSTypes, generalJSTypesWithArray, generateAxiosOptions, generateBodyMutatorConfig, generateBodyOptions, generateComponentDefinition, generateDependencyImports, generateFormDataAndUrlEncodedFunction, generateImports, generateModelInline, generateModelsInline, generateMutator, generateMutatorConfig, generateMutatorImports, generateMutatorRequestOptions, generateOptions, generateParameterDefinition, generateQueryParamsAxiosConfig, generateSchemasDefinition, generateTarget, generateTargetForTags, generateVerbImports, generateVerbOptions, generateVerbsOptions, getAngularFilteredParamsCallExpression, getAngularFilteredParamsExpression, getAngularFilteredParamsHelperBody, getArray, getBody, getCombinedEnumValue, getDefaultContentType, getEnum, getEnumDescriptions, getEnumImplementation, getEnumNames, getEnumUnionFromSchema, getExtension, getFileInfo, getFormDataFieldFileType, getFullRoute, getIsBodyVerb, getKey, getMockFileExtensionByTypeName, getNumberWord, getObject, getOperationId, getOrvalGeneratedTypes, getParameters, getParams, getParamsInPath, getPropertySafe, getProps, getQueryParams, getRefInfo, getResReqTypes, getResponse, getResponseTypeCategory, getRoute, getRouteAsArray, getScalar, getSuccessResponseType, getTypedResponse, isBinaryContentType, isBoolean, isDirectory, isFunction, isModule, isNullish, isNumber, isNumeric, isObject, isReference, isSchema, isString, isStringLike, isSyntheticDefaultImportsAllow, isUrl, isVerb, isVerbose, jsDoc, jsStringEscape, kebab, keyValuePairsToJsDoc, log, logError, logVerbose, mergeDeep, mismatchArgsMessage, pascal, removeFilesAndEmptyFolders, resolveDiscriminators, resolveExampleRefs, resolveInstalledVersion, resolveInstalledVersions, resolveObject, resolveRef, resolveValue, sanitize, setVerbose, snake, sortByPriority, splitSchemasByType, startMessage, stringify, toObjectString, path_exports as upath, upper, writeModelInline, writeModelsInline, writeSchema, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode };
|
|
4680
4831
|
//# sourceMappingURL=index.mjs.map
|