@orval/core 8.5.1 → 8.5.3

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.mjs CHANGED
@@ -2,7 +2,7 @@ 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 path from "node:path";
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";
@@ -134,7 +134,7 @@ function isReference(obj) {
134
134
  return !isNullish$1(obj) && Object.hasOwn(obj, "$ref");
135
135
  }
136
136
  function isDirectory(pathValue) {
137
- return !path.extname(pathValue);
137
+ return !nodePath.extname(pathValue);
138
138
  }
139
139
  function isObject(x) {
140
140
  return Object.prototype.toString.call(x) === "[object Object]";
@@ -461,14 +461,14 @@ async function dynamicImport(toImport, from = process.cwd(), takeDefault = true)
461
461
  if (!toImport) return toImport;
462
462
  try {
463
463
  if (isString(toImport)) {
464
- const fileUrl = pathToFileURL(path.resolve(from, toImport));
465
- const data = path.extname(fileUrl.href) === ".json" ? await import(fileUrl.href, { with: { type: "json" } }) : await import(fileUrl.href);
464
+ const fileUrl = pathToFileURL(nodePath.resolve(from, toImport));
465
+ const data = nodePath.extname(fileUrl.href) === ".json" ? await import(fileUrl.href, { with: { type: "json" } }) : await import(fileUrl.href);
466
466
  if (takeDefault && (isObject(data) || isModule(data)) && data.default) return data.default;
467
467
  return data;
468
468
  }
469
469
  return toImport;
470
470
  } catch (error) {
471
- throw new Error(`Oups... 🍻. Path: ${String(toImport)} => ${String(error)}`);
471
+ throw new Error(`Oups... 🍻. Path: ${String(toImport)} => ${String(error)}`, { cause: error });
472
472
  }
473
473
  }
474
474
 
@@ -482,14 +482,14 @@ function getExtension(path) {
482
482
  //#region src/utils/file.ts
483
483
  function getFileInfo(target = "", { backupFilename = "filename", extension = ".ts" } = {}) {
484
484
  const isDir = isDirectory(target);
485
- const filePath = isDir ? path.join(target, backupFilename + extension) : target;
485
+ const filePath = isDir ? nodePath.join(target, backupFilename + extension) : target;
486
486
  return {
487
487
  path: filePath,
488
488
  pathWithoutExtension: filePath.replace(/\.[^/.]+$/, ""),
489
489
  extension,
490
490
  isDirectory: isDir,
491
- dirname: path.dirname(filePath),
492
- filename: path.basename(filePath, extension.startsWith(".") ? extension : `.${extension}`)
491
+ dirname: nodePath.dirname(filePath),
492
+ filename: nodePath.basename(filePath, extension.startsWith(".") ? extension : `.${extension}`)
493
493
  };
494
494
  }
495
495
  async function removeFilesAndEmptyFolders(patterns, dir) {
@@ -565,7 +565,7 @@ function startMessage({ name, version, description }) {
565
565
  return `🍻 ${styleText(["cyan", "bold"], name)} ${styleText("green", `v${version}`)}${description ? ` - ${description}` : ""}`;
566
566
  }
567
567
  function logError(err, tag) {
568
- let message = "";
568
+ let message;
569
569
  if (err instanceof Error) {
570
570
  message = (err.message || err.stack) ?? "Unknown error";
571
571
  if (err.cause) {
@@ -678,51 +678,43 @@ function count(str = "", key) {
678
678
  //#endregion
679
679
  //#region src/utils/path.ts
680
680
  var path_exports = /* @__PURE__ */ __exportAll({
681
- basename: () => basename,
682
- dirname: () => dirname,
683
- extname: () => extname,
681
+ getRelativeImportPath: () => getRelativeImportPath,
684
682
  getSchemaFileName: () => getSchemaFileName,
685
- isAbsolute: () => isAbsolute,
686
683
  join: () => join,
687
684
  joinSafe: () => joinSafe,
688
685
  normalizeSafe: () => normalizeSafe,
689
686
  relativeSafe: () => relativeSafe,
690
- resolve: () => resolve,
691
- separator: () => separator
687
+ separator: () => separator,
688
+ toUnix: () => toUnix
692
689
  });
693
- function wrapPathFn(fn) {
694
- return (...args) => {
695
- const result = fn(...args.map((p) => isStringLike(p) ? toUnix(p) : p));
696
- return isStringLike(result) ? toUnix(result) : result;
697
- };
690
+ function toUnix(value) {
691
+ value = value.replaceAll("\\", "/");
692
+ value = value.replaceAll(/(?<!^)\/+/g, "/");
693
+ return value;
694
+ }
695
+ function join(...args) {
696
+ return toUnix(nodePath.join(...args.map((a) => toUnix(a))));
698
697
  }
699
- const path$1 = Object.fromEntries(Object.entries(path).map(([key, value]) => [key, isFunction(value) ? wrapPathFn(value) : value]));
700
- const { join, resolve, extname, dirname, basename, isAbsolute } = path$1;
701
698
  /**
702
699
  * Behaves exactly like `path.relative(from, to)`, but keeps the first meaningful "./"
703
700
  */
704
701
  function relativeSafe(from, to) {
705
- return normalizeSafe(`.${separator}${path$1.relative(from, to)}`);
702
+ return normalizeSafe(`.${separator}${toUnix(nodePath.relative(toUnix(from), toUnix(to)))}`);
706
703
  }
707
704
  function getSchemaFileName(path) {
708
705
  return path.replace(`.${getExtension(path)}`, "").slice(path.lastIndexOf("/") + 1);
709
706
  }
710
707
  const separator = "/";
711
- const toUnix = function(value) {
712
- value = value.replaceAll("\\", "/");
713
- value = value.replaceAll(/(?<!^)\/+/g, "/");
714
- return value;
715
- };
716
708
  function normalizeSafe(value) {
717
709
  let result;
718
710
  value = toUnix(value);
719
- result = path$1.normalize(value);
711
+ result = toUnix(nodePath.normalize(value));
720
712
  if (value.startsWith("./") && !result.startsWith("./") && !result.startsWith("..")) result = "./" + result;
721
713
  else if (value.startsWith("//") && !result.startsWith("//")) result = value.startsWith("//./") ? "//." + result : "/" + result;
722
714
  return result;
723
715
  }
724
716
  function joinSafe(...values) {
725
- let result = path$1.join(...values);
717
+ let result = toUnix(nodePath.join(...values.map((v) => toUnix(v))));
726
718
  if (values.length > 0) {
727
719
  const firstValue = toUnix(values[0]);
728
720
  if (firstValue.startsWith("./") && !result.startsWith("./") && !result.startsWith("..")) result = "./" + result;
@@ -730,25 +722,60 @@ function joinSafe(...values) {
730
722
  }
731
723
  return result;
732
724
  }
725
+ /**
726
+ * Given two absolute file paths, generates a valid ESM relative import path
727
+ * from the 'importer' file to the 'exporter' file.
728
+ *
729
+ * @example
730
+ * ```ts
731
+ * getRelativeImportPath('/path/to/importer.ts', '/path/to/exporter.ts')
732
+ * // => './exporter'
733
+ * getRelativeImportPath('/path/to/importer.ts', '/path/to/sub/exporter.ts')
734
+ * // => './sub/exporter'
735
+ * getRelativeImportPath('/path/to/importer.ts', '/path/sibling/exporter.ts')
736
+ * // => '../sibling/exporter'
737
+ * ```
738
+ *
739
+ * This function handles path normalization, cross-platform separators, and
740
+ * ensures the path is a valid ESM relative specifier (e.g., starts with './').
741
+ *
742
+ * @param importerFilePath - The absolute path of the file that will contain the import statement.
743
+ * @param exporterFilePath - The absolute path of the file being imported.
744
+ * @param [includeFileExtension=false] - Whether the import path should include the file extension, defaults to false.
745
+ * @returns The relative import path string.
746
+ */
747
+ function getRelativeImportPath(importerFilePath, exporterFilePath, includeFileExtension = false) {
748
+ if (!nodePath.isAbsolute(importerFilePath)) throw new Error(`'importerFilePath' is not an absolute path. "${importerFilePath}"`);
749
+ if (!nodePath.isAbsolute(exporterFilePath)) throw new Error(`'exporterFilePath' is not an absolute path. "${exporterFilePath}"`);
750
+ const importerDir = nodePath.dirname(importerFilePath);
751
+ const relativePath = nodePath.relative(importerDir, exporterFilePath);
752
+ let posixPath = nodePath.posix.join(...relativePath.split(nodePath.sep));
753
+ if (!posixPath.startsWith("./") && !posixPath.startsWith("../")) posixPath = `./${posixPath}`;
754
+ if (!includeFileExtension) {
755
+ const ext = nodePath.extname(posixPath);
756
+ if (ext && posixPath.endsWith(ext)) posixPath = posixPath.slice(0, -ext.length);
757
+ }
758
+ return posixPath;
759
+ }
733
760
 
734
761
  //#endregion
735
762
  //#region src/utils/resolve-version.ts
736
763
  function resolveInstalledVersion(packageName, fromDir) {
737
764
  try {
738
- const require = createRequire(path.join(fromDir, "noop.js"));
765
+ const require = createRequire(nodePath.join(fromDir, "noop.js"));
739
766
  try {
740
767
  return require(`${packageName}/package.json`).version;
741
768
  } catch (directError) {
742
769
  if (directError instanceof Error && "code" in directError && directError.code === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
743
770
  const entryPath = require.resolve(packageName);
744
- let dir = path.dirname(entryPath);
745
- while (dir !== path.parse(dir).root) {
746
- const pkgPath = path.join(dir, "package.json");
771
+ let dir = nodePath.dirname(entryPath);
772
+ while (dir !== nodePath.parse(dir).root) {
773
+ const pkgPath = nodePath.join(dir, "package.json");
747
774
  if (existsSync(pkgPath)) {
748
775
  const pkgData = JSON.parse(readFileSync(pkgPath, "utf8"));
749
776
  if (pkgData.name === packageName) return pkgData.version;
750
777
  }
751
- dir = path.dirname(dir);
778
+ dir = nodePath.dirname(dir);
752
779
  }
753
780
  return;
754
781
  }
@@ -891,17 +918,19 @@ function getNumberWord(num) {
891
918
  return [...num.toString()].reduce((acc, n) => acc + NUMBERS[n], "");
892
919
  }
893
920
  /**
894
- * Escapes a specific character in a string by prefixing it with a backslash.
921
+ * Escapes a specific character in a string by prefixing all of its occurrences with a backslash.
895
922
  *
896
923
  * @param str - The string to escape, or null.
897
924
  * @param char - The character to escape. Defaults to single quote (').
898
925
  * @returns The escaped string, or null if the input is null.
899
926
  * @example
900
927
  * escape("don't") // returns "don\'t"
928
+ * escape("it's John's") // returns "it\'s John\'s"
901
929
  * escape('say "hello"', '"') // returns 'say \\"hello\\"'
930
+ * escape("a'''b", "'") // returns "a\'\'\'b"
902
931
  */
903
932
  function escape(str, char = "'") {
904
- return str?.replace(char, `\\${char}`);
933
+ return str?.replaceAll(char, `\\${char}`);
905
934
  }
906
935
  /**
907
936
  * Escape all characters not included in SingleStringCharacters and
@@ -1174,48 +1203,80 @@ function getRefInfo($ref, context) {
1174
1203
 
1175
1204
  //#endregion
1176
1205
  //#region src/resolvers/ref.ts
1206
+ const REF_NOT_FOUND_PREFIX = "Oops... 🍻. Ref not found";
1207
+ /**
1208
+ * Recursively resolves a `$ref` in an OpenAPI document, following
1209
+ * nested schema refs and collecting imports along the way.
1210
+ *
1211
+ * Handles OpenAPI 3.0 `nullable` and 3.1 type-array hints on direct refs.
1212
+ *
1213
+ * @see https://spec.openapis.org/oas/v3.0.3#reference-object
1214
+ * @see https://spec.openapis.org/oas/v3.1.0#reference-object
1215
+ */
1177
1216
  function resolveRef(schema, context, imports = []) {
1178
- if ("schema" in schema && schema.schema?.$ref) {
1179
- const resolvedRef = resolveRef(schema.schema, context, imports);
1180
- if ("examples" in schema) schema.examples = resolveExampleRefs(schema.examples, context);
1181
- if ("examples" in resolvedRef.schema) resolvedRef.schema.examples = resolveExampleRefs(resolvedRef.schema.examples, context);
1217
+ const refPath = "$ref" in schema ? schema.$ref : void 0;
1218
+ const nestedSchema = "schema" in schema ? schema.schema : void 0;
1219
+ if (isObject(nestedSchema) && isReference(nestedSchema) && typeof nestedSchema.$ref === "string") {
1220
+ const resolvedRef = resolveRef(nestedSchema, context, imports);
1221
+ if ("examples" in schema) {
1222
+ const schemaWithExamples = schema;
1223
+ schemaWithExamples.examples = resolveExampleRefs(schemaWithExamples.examples, context);
1224
+ }
1225
+ if ("examples" in resolvedRef.schema) {
1226
+ const resolvedWithExamples = resolvedRef.schema;
1227
+ resolvedWithExamples.examples = resolveExampleRefs(resolvedWithExamples.examples, context);
1228
+ }
1182
1229
  return {
1183
1230
  schema: {
1184
1231
  ...schema,
1185
1232
  schema: resolvedRef.schema
1186
1233
  },
1187
- imports
1234
+ imports: resolvedRef.imports
1188
1235
  };
1189
1236
  }
1190
1237
  if (isDereferenced(schema)) {
1191
- if ("examples" in schema) schema.examples = resolveExampleRefs(schema.examples, context);
1238
+ if ("examples" in schema) {
1239
+ const schemaWithExamples = schema;
1240
+ schemaWithExamples.examples = resolveExampleRefs(schemaWithExamples.examples, context);
1241
+ }
1192
1242
  return {
1193
1243
  schema,
1194
1244
  imports
1195
1245
  };
1196
1246
  }
1247
+ if (!refPath) throw new Error(`${REF_NOT_FOUND_PREFIX}: missing $ref`);
1197
1248
  const { currentSchema, refInfo: { name, originalName } } = getSchema$1(schema, context);
1198
- if (!currentSchema) throw new Error(`Oops... 🍻. Ref not found: ${schema.$ref}`);
1249
+ if (!currentSchema) throw new Error(`${REF_NOT_FOUND_PREFIX}: ${refPath}`);
1199
1250
  return resolveRef(currentSchema, { ...context }, [...imports, {
1200
1251
  name,
1201
1252
  schemaName: originalName
1202
1253
  }]);
1203
1254
  }
1255
+ /**
1256
+ * Looks up a schema by its `$ref` path in the spec, applying suffix resolution.
1257
+ *
1258
+ * Preserves OpenAPI 3.0 `nullable` and 3.1 type-array (`["object", "null"]`)
1259
+ * hints from the referencing schema onto the resolved target.
1260
+ *
1261
+ * @see https://spec.openapis.org/oas/v3.0.3#fixed-fields-18 (nullable)
1262
+ * @see https://spec.openapis.org/oas/v3.1.0#schema-object (type as array)
1263
+ */
1204
1264
  function getSchema$1(schema, context) {
1265
+ if (!schema.$ref) throw new Error(`${REF_NOT_FOUND_PREFIX}: missing $ref`);
1205
1266
  const refInfo = getRefInfo(schema.$ref, context);
1206
1267
  const { refPaths } = refInfo;
1207
1268
  let schemaByRefPaths = Array.isArray(refPaths) ? prop(context.spec, ...refPaths) : void 0;
1208
1269
  schemaByRefPaths ??= context.spec;
1209
1270
  if (isReference(schemaByRefPaths)) return getSchema$1(schemaByRefPaths, context);
1210
1271
  let currentSchema = schemaByRefPaths || context.spec;
1211
- if ("nullable" in schema) {
1272
+ if (isObject(currentSchema) && "nullable" in schema) {
1212
1273
  const nullable = schema.nullable;
1213
1274
  currentSchema = {
1214
1275
  ...currentSchema,
1215
1276
  nullable
1216
1277
  };
1217
1278
  }
1218
- if ("type" in schema && Array.isArray(schema.type)) {
1279
+ if (isObject(currentSchema) && "type" in schema && Array.isArray(schema.type)) {
1219
1280
  const type = schema.type;
1220
1281
  currentSchema = {
1221
1282
  ...currentSchema,
@@ -1227,17 +1288,18 @@ function getSchema$1(schema, context) {
1227
1288
  refInfo
1228
1289
  };
1229
1290
  }
1291
+ /** Recursively resolves `$ref` entries in an examples array or record. */
1230
1292
  function resolveExampleRefs(examples, context) {
1231
1293
  if (!examples) return;
1232
1294
  return Array.isArray(examples) ? examples.map((example) => {
1233
- if (isReference(example)) {
1295
+ if (isObject(example) && isReference(example)) {
1234
1296
  const { schema } = resolveRef(example, context);
1235
1297
  return schema.value;
1236
1298
  }
1237
1299
  return example;
1238
1300
  }) : (() => {
1239
1301
  const result = {};
1240
- for (const [key, example] of Object.entries(examples)) result[key] = isReference(example) ? resolveRef(example, context).schema.value : example;
1302
+ for (const [key, example] of Object.entries(examples)) result[key] = isObject(example) && isReference(example) ? resolveRef(example, context).schema.value : example;
1241
1303
  return result;
1242
1304
  })();
1243
1305
  }
@@ -3120,7 +3182,7 @@ function generateModelsInline(obj) {
3120
3182
  //#region src/generators/mutator-info.ts
3121
3183
  async function getMutatorInfo(filePath, options) {
3122
3184
  const { root = process.cwd(), namedExport = "default", alias, external, tsconfig } = options ?? {};
3123
- return parseFile(await bundleFile(root, path.resolve(filePath), alias, external, tsconfig?.compilerOptions), namedExport, getEcmaVersion(tsconfig?.compilerOptions?.target));
3185
+ return parseFile(await bundleFile(root, filePath, alias, external, tsconfig?.compilerOptions), namedExport, getEcmaVersion(tsconfig?.compilerOptions?.target));
3124
3186
  }
3125
3187
  async function bundleFile(root, fileName, alias, external, compilerOptions) {
3126
3188
  const { text } = (await build({
@@ -3217,10 +3279,8 @@ function getEcmaVersion(target) {
3217
3279
  //#region src/generators/mutator.ts
3218
3280
  const BODY_TYPE_NAME = "BodyType";
3219
3281
  const getImport = (output, mutator) => {
3220
- const outputFileInfo = getFileInfo(output);
3221
- const mutatorFileInfo = getFileInfo(mutator.path);
3222
- const { pathWithoutExtension } = getFileInfo(relativeSafe(outputFileInfo.dirname, mutatorFileInfo.path));
3223
- return `${pathWithoutExtension}${mutator.extension ?? ""}`;
3282
+ const outputFile = getFileInfo(output).path;
3283
+ return `${getRelativeImportPath(outputFile, mutator.path)}${mutator.extension ?? ""}`;
3224
3284
  };
3225
3285
  async function generateMutator({ output, mutator, name, workspace, tsconfig }) {
3226
3286
  if (!mutator || !output) return;
@@ -3236,7 +3296,7 @@ async function generateMutator({ output, mutator, name, workspace, tsconfig }) {
3236
3296
  const errorTypeName = mutator.default ? `${pascal(name)}ErrorType` : "ErrorType";
3237
3297
  const bodyTypeName = mutator.default ? `${pascal(name)}${BODY_TYPE_NAME}` : BODY_TYPE_NAME;
3238
3298
  const mutatorInfo = await getMutatorInfo(importPath, {
3239
- root: path.resolve(workspace),
3299
+ root: workspace,
3240
3300
  namedExport: mutatorInfoName,
3241
3301
  alias: mutator.alias,
3242
3302
  external: mutator.external,
@@ -3911,19 +3971,26 @@ function getSchemaGroups(schemaPath, schemas, namingConvention, fileExtension) {
3911
3971
  }
3912
3972
  function getCanonicalMap(schemaGroups, schemaPath, namingConvention, fileExtension) {
3913
3973
  const canonicalPathMap = /* @__PURE__ */ new Map();
3974
+ const canonicalNameMap = /* @__PURE__ */ new Map();
3914
3975
  for (const [key, groupSchemas] of Object.entries(schemaGroups)) {
3915
- const canonicalPath = getPath(schemaPath, conventionName(groupSchemas[0].name, namingConvention), fileExtension);
3916
- canonicalPathMap.set(key, {
3917
- importPath: canonicalPath,
3976
+ const canonicalInfo = {
3977
+ importPath: getPath(schemaPath, conventionName(groupSchemas[0].name, namingConvention), fileExtension),
3918
3978
  name: groupSchemas[0].name
3919
- });
3979
+ };
3980
+ canonicalPathMap.set(key, canonicalInfo);
3981
+ for (const schema of groupSchemas) canonicalNameMap.set(schema.name, canonicalInfo);
3920
3982
  }
3921
- return canonicalPathMap;
3983
+ return {
3984
+ canonicalPathMap,
3985
+ canonicalNameMap
3986
+ };
3922
3987
  }
3923
- function normalizeCanonicalImportPaths(schemas, canonicalPathMap, schemaPath, namingConvention, fileExtension) {
3988
+ function normalizeCanonicalImportPaths(schemas, canonicalPathMap, canonicalNameMap, schemaPath, namingConvention, fileExtension) {
3924
3989
  for (const schema of schemas) schema.imports = schema.imports.map((imp) => {
3990
+ const canonicalByName = canonicalNameMap.get(imp.name);
3925
3991
  const resolvedImportKey = resolveImportKey(schemaPath, imp.importPath ?? `./${conventionName(imp.name, namingConvention)}`, fileExtension);
3926
- const canonical = canonicalPathMap.get(resolvedImportKey);
3992
+ const canonicalByPath = canonicalPathMap.get(resolvedImportKey);
3993
+ const canonical = canonicalByName ?? canonicalByPath;
3927
3994
  if (!canonical?.importPath) return imp;
3928
3995
  const importPath = removeFileExtension(relativeSafe(schemaPath, canonical.importPath.replaceAll("\\", "/")), fileExtension);
3929
3996
  return {
@@ -3963,7 +4030,7 @@ function getSchema({ schema: { imports, model }, target, header, namingConventio
3963
4030
  return file;
3964
4031
  }
3965
4032
  function getPath(path, name, fileExtension) {
3966
- return join(path, `/${name}${fileExtension}`);
4033
+ return nodePath.join(path, `${name}${fileExtension}`);
3967
4034
  }
3968
4035
  function writeModelInline(acc, model) {
3969
4036
  return acc + `${model}\n`;
@@ -3983,12 +4050,13 @@ async function writeSchema({ path, schema, target, namingConvention, fileExtensi
3983
4050
  namingConvention
3984
4051
  }));
3985
4052
  } catch (error) {
3986
- throw new Error(`Oups... 🍻. An Error occurred while writing schema ${name} => ${String(error)}`);
4053
+ throw new Error(`Oups... 🍻. An Error occurred while writing schema ${name} => ${String(error)}`, { cause: error });
3987
4054
  }
3988
4055
  }
3989
4056
  async function writeSchemas({ schemaPath, schemas, target, namingConvention, fileExtension, header, indexFiles }) {
3990
4057
  const schemaGroups = getSchemaGroups(schemaPath, schemas, namingConvention, fileExtension);
3991
- normalizeCanonicalImportPaths(schemas, getCanonicalMap(schemaGroups, schemaPath, namingConvention, fileExtension), schemaPath, namingConvention, fileExtension);
4058
+ const { canonicalPathMap, canonicalNameMap } = getCanonicalMap(schemaGroups, schemaPath, namingConvention, fileExtension);
4059
+ normalizeCanonicalImportPaths(schemas, canonicalPathMap, canonicalNameMap, schemaPath, namingConvention, fileExtension);
3992
4060
  for (const groupSchemas of Object.values(schemaGroups)) {
3993
4061
  if (groupSchemas.length === 1) {
3994
4062
  await writeSchema({
@@ -4011,7 +4079,7 @@ async function writeSchemas({ schemaPath, schemas, target, namingConvention, fil
4011
4079
  });
4012
4080
  }
4013
4081
  if (indexFiles) {
4014
- const schemaFilePath = join(schemaPath, `/index${fileExtension}`);
4082
+ const schemaFilePath = nodePath.join(schemaPath, `index${fileExtension}`);
4015
4083
  await fs$1.ensureFile(schemaFilePath);
4016
4084
  const ext = fileExtension.endsWith(".ts") ? fileExtension.slice(0, -3) : fileExtension;
4017
4085
  const conventionNamesSet = new Set(Object.values(schemaGroups).map((group) => conventionName(group[0].name, namingConvention)));
@@ -4025,7 +4093,7 @@ async function writeSchemas({ schemaPath, schemas, target, namingConvention, fil
4025
4093
  const fileContent = `${header}\n${[...new Set([...existingExports, ...currentExports])].toSorted((a, b) => a.localeCompare(b)).join("\n")}`;
4026
4094
  await fs$1.writeFile(schemaFilePath, fileContent, { encoding: "utf8" });
4027
4095
  } catch (error) {
4028
- throw new Error(`Oups... 🍻. An Error occurred while writing schema index file ${schemaFilePath} => ${String(error)}`);
4096
+ throw new Error(`Oups... 🍻. An Error occurred while writing schema index file ${schemaFilePath} => ${String(error)}`, { cause: error });
4029
4097
  }
4030
4098
  }
4031
4099
  }
@@ -4034,7 +4102,7 @@ async function writeSchemas({ schemaPath, schemas, target, namingConvention, fil
4034
4102
  //#region src/writers/generate-imports-for-builder.ts
4035
4103
  function generateImportsForBuilder(output, imports, relativeSchemasPath) {
4036
4104
  const isZodSchemaOutput = isObject(output.schemas) && output.schemas.type === "zod";
4037
- let schemaImports = [];
4105
+ let schemaImports;
4038
4106
  if (output.indexFiles) schemaImports = isZodSchemaOutput ? [{
4039
4107
  exports: imports.filter((i) => !i.importPath),
4040
4108
  dependency: joinSafe(relativeSchemasPath, "index.zod")
@@ -4043,7 +4111,7 @@ function generateImportsForBuilder(output, imports, relativeSchemasPath) {
4043
4111
  dependency: relativeSchemasPath
4044
4112
  }];
4045
4113
  else schemaImports = uniqueBy(imports.filter((i) => !i.importPath), (x) => x.name).map((i) => {
4046
- const name = conventionName(i.schemaName ?? i.name, output.namingConvention);
4114
+ const name = conventionName(isZodSchemaOutput ? i.name : i.schemaName ?? i.name, output.namingConvention);
4047
4115
  const suffix = isZodSchemaOutput ? ".zod" : "";
4048
4116
  const importExtension = output.fileExtension.replace(/\.ts$/, "") || "";
4049
4117
  return {
@@ -4051,7 +4119,7 @@ function generateImportsForBuilder(output, imports, relativeSchemasPath) {
4051
4119
  dependency: joinSafe(relativeSchemasPath, `${name}${suffix}${importExtension}`)
4052
4120
  };
4053
4121
  });
4054
- const otherImports = uniqueBy(imports.filter((i) => !!i.importPath), (x) => x.name + (x.importPath ?? "")).map((i) => {
4122
+ const otherImports = uniqueBy(imports.filter((i) => !!i.importPath), (x) => x.name + x.importPath).map((i) => {
4055
4123
  return {
4056
4124
  exports: [i],
4057
4125
  dependency: i.importPath
@@ -4180,13 +4248,13 @@ interface TypedResponse<T> extends Response {
4180
4248
  //#region src/writers/single-mode.ts
4181
4249
  async function writeSingleMode({ builder, output, projectName, header, needSchema }) {
4182
4250
  try {
4183
- const { path, dirname } = getFileInfo(output.target, {
4251
+ const { path } = getFileInfo(output.target, {
4184
4252
  backupFilename: conventionName(builder.info.title, output.namingConvention),
4185
4253
  extension: output.fileExtension
4186
4254
  });
4187
4255
  const { imports, importsMock, implementation, implementationMock, mutators, clientMutators, formData, formUrlEncoded, paramsSerializer, fetchReviver } = generateTarget(builder, output);
4188
4256
  let data = header;
4189
- const schemasPath = output.schemas ? relativeSafe(dirname, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : void 0;
4257
+ const schemasPath = output.schemas ? getRelativeImportPath(path, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : void 0;
4190
4258
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
4191
4259
  const importsForBuilder = schemasPath ? generateImportsForBuilder(output, imports.filter((imp) => !importsMock.some((impMock) => imp.name === impMock.name)), schemasPath) : [];
4192
4260
  data += builder.imports({
@@ -4240,7 +4308,7 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
4240
4308
  return [path];
4241
4309
  } catch (error) {
4242
4310
  const errorMsg = error instanceof Error ? error.message : "unknown error";
4243
- throw new Error(`Oups... 🍻. An Error occurred while writing file => ${errorMsg}`);
4311
+ throw new Error(`Oups... 🍻. An Error occurred while writing file => ${errorMsg}`, { cause: error });
4244
4312
  }
4245
4313
  }
4246
4314
 
@@ -4248,14 +4316,14 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
4248
4316
  //#region src/writers/split-mode.ts
4249
4317
  async function writeSplitMode({ builder, output, projectName, header, needSchema }) {
4250
4318
  try {
4251
- const { filename, dirname, extension } = getFileInfo(output.target, {
4319
+ const { path: targetPath, filename, dirname, extension } = getFileInfo(output.target, {
4252
4320
  backupFilename: conventionName(builder.info.title, output.namingConvention),
4253
4321
  extension: output.fileExtension
4254
4322
  });
4255
4323
  const { imports, implementation, implementationMock, importsMock, mutators, clientMutators, formData, formUrlEncoded, paramsSerializer, fetchReviver } = generateTarget(builder, output);
4256
4324
  let implementationData = header;
4257
4325
  let mockData = header;
4258
- const relativeSchemasPath = output.schemas ? relativeSafe(dirname, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "./" + filename + ".schemas";
4326
+ const relativeSchemasPath = output.schemas ? getRelativeImportPath(targetPath, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "./" + filename + ".schemas";
4259
4327
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
4260
4328
  const importsForBuilder = generateImportsForBuilder(output, imports, relativeSchemasPath);
4261
4329
  implementationData += builder.imports({
@@ -4280,10 +4348,10 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
4280
4348
  isAllowSyntheticDefaultImports,
4281
4349
  options: isFunction(output.mock) ? void 0 : output.mock
4282
4350
  });
4283
- const schemasPath = output.schemas ? void 0 : join(dirname, filename + ".schemas" + extension);
4351
+ const schemasPath = output.schemas ? void 0 : nodePath.join(dirname, filename + ".schemas" + extension);
4284
4352
  if (schemasPath && needSchema) {
4285
4353
  const schemasData = header + generateModelsInline(builder.schemas);
4286
- await fs$1.outputFile(join(dirname, filename + ".schemas" + extension), schemasData);
4354
+ await fs$1.outputFile(schemasPath, schemasData);
4287
4355
  }
4288
4356
  if (mutators) implementationData += generateMutatorImports({
4289
4357
  mutators,
@@ -4305,9 +4373,9 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
4305
4373
  implementationData += `\n${implementation}`;
4306
4374
  mockData += `\n${implementationMock}`;
4307
4375
  const implementationFilename = filename + (OutputClient.ANGULAR === output.client ? ".service" : "") + extension;
4308
- const implementationPath = join(dirname, implementationFilename);
4309
- await fs$1.outputFile(join(dirname, implementationFilename), implementationData);
4310
- const mockPath = output.mock ? join(dirname, filename + "." + getMockFileExtensionByTypeName(output.mock) + extension) : void 0;
4376
+ const implementationPath = nodePath.join(dirname, implementationFilename);
4377
+ await fs$1.outputFile(implementationPath, implementationData);
4378
+ const mockPath = output.mock ? nodePath.join(dirname, filename + "." + getMockFileExtensionByTypeName(output.mock) + extension) : void 0;
4311
4379
  if (mockPath) await fs$1.outputFile(mockPath, mockData);
4312
4380
  return [
4313
4381
  implementationPath,
@@ -4315,7 +4383,7 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
4315
4383
  ...mockPath ? [mockPath] : []
4316
4384
  ];
4317
4385
  } catch (error) {
4318
- throw new Error(`Oups... 🍻. An Error occurred while splitting => ${String(error)}`);
4386
+ throw new Error(`Oups... 🍻. An Error occurred while splitting => ${String(error)}`, { cause: error });
4319
4387
  }
4320
4388
  }
4321
4389
 
@@ -4444,7 +4512,7 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
4444
4512
  const target = generateTargetForTags(builder, output);
4445
4513
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
4446
4514
  const mockOption = output.mock && !isFunction(output.mock) ? output.mock : void 0;
4447
- const indexFilePath = mockOption?.indexMockFiles ? join(dirname, "index." + getMockFileExtensionByTypeName(mockOption) + extension) : void 0;
4515
+ const indexFilePath = mockOption?.indexMockFiles ? nodePath.join(dirname, "index." + getMockFileExtensionByTypeName(mockOption) + extension) : void 0;
4448
4516
  if (indexFilePath) await fs$1.outputFile(indexFilePath, "");
4449
4517
  const tagEntries = Object.entries(target);
4450
4518
  const generatedFilePathsArray = await Promise.all(tagEntries.map(async ([tag, target]) => {
@@ -4452,7 +4520,8 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
4452
4520
  const { imports, implementation, implementationMock, importsMock, mutators, clientMutators, formData, fetchReviver, formUrlEncoded, paramsSerializer } = target;
4453
4521
  let implementationData = header;
4454
4522
  let mockData = header;
4455
- const relativeSchemasPath = output.schemas ? "../" + relativeSafe(dirname, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "../" + filename + ".schemas";
4523
+ const importerPath = nodePath.join(dirname, tag, tag + extension);
4524
+ const relativeSchemasPath = output.schemas ? getRelativeImportPath(importerPath, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "../" + filename + ".schemas";
4456
4525
  const importsForBuilder = generateImportsForBuilder(output, imports, relativeSchemasPath);
4457
4526
  implementationData += builder.imports({
4458
4527
  client: output.client,
@@ -4476,7 +4545,7 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
4476
4545
  isAllowSyntheticDefaultImports,
4477
4546
  options: isFunction(output.mock) ? void 0 : output.mock
4478
4547
  });
4479
- const schemasPath = output.schemas ? void 0 : join(dirname, filename + ".schemas" + extension);
4548
+ const schemasPath = output.schemas ? void 0 : nodePath.join(dirname, filename + ".schemas" + extension);
4480
4549
  if (schemasPath && needSchema) {
4481
4550
  const schemasData = header + generateModelsInline(builder.schemas);
4482
4551
  await fs$1.outputFile(schemasPath, schemasData);
@@ -4517,9 +4586,9 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
4517
4586
  implementationData += `\n${implementation}`;
4518
4587
  mockData += `\n${implementationMock}`;
4519
4588
  const implementationFilename = tag + (OutputClient.ANGULAR === output.client ? ".service" : "") + extension;
4520
- const implementationPath = join(dirname, tag, implementationFilename);
4589
+ const implementationPath = nodePath.join(dirname, tag, implementationFilename);
4521
4590
  await fs$1.outputFile(implementationPath, implementationData);
4522
- const mockPath = output.mock ? join(dirname, tag, tag + "." + getMockFileExtensionByTypeName(output.mock) + extension) : void 0;
4591
+ const mockPath = output.mock ? nodePath.join(dirname, tag, tag + "." + getMockFileExtensionByTypeName(output.mock) + extension) : void 0;
4523
4592
  if (mockPath) await fs$1.outputFile(mockPath, mockData);
4524
4593
  return [
4525
4594
  implementationPath,
@@ -4527,7 +4596,7 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
4527
4596
  ...mockPath ? [mockPath] : []
4528
4597
  ];
4529
4598
  } catch (error) {
4530
- throw new Error(`Oups... 🍻. An Error occurred while splitting tag ${tag} => ${String(error)}`);
4599
+ throw new Error(`Oups... 🍻. An Error occurred while splitting tag ${tag} => ${String(error)}`, { cause: error });
4531
4600
  }
4532
4601
  }));
4533
4602
  if (indexFilePath && mockOption) {
@@ -4543,7 +4612,7 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
4543
4612
  //#endregion
4544
4613
  //#region src/writers/tags-mode.ts
4545
4614
  async function writeTagsMode({ builder, output, projectName, header, needSchema }) {
4546
- const { filename, dirname, extension } = getFileInfo(output.target, {
4615
+ const { path: targetPath, filename, dirname, extension } = getFileInfo(output.target, {
4547
4616
  backupFilename: conventionName(builder.info.title, output.namingConvention),
4548
4617
  extension: output.fileExtension
4549
4618
  });
@@ -4553,7 +4622,7 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema
4553
4622
  try {
4554
4623
  const { imports, implementation, implementationMock, importsMock, mutators, clientMutators, formData, formUrlEncoded, fetchReviver, paramsSerializer } = target;
4555
4624
  let data = header;
4556
- const schemasPathRelative = output.schemas ? relativeSafe(dirname, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "./" + filename + ".schemas";
4625
+ const schemasPathRelative = output.schemas ? getRelativeImportPath(targetPath, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "./" + filename + ".schemas";
4557
4626
  const importsForBuilder = generateImportsForBuilder(output, imports.filter((imp) => !importsMock.some((impMock) => imp.name === impMock.name)), schemasPathRelative);
4558
4627
  data += builder.imports({
4559
4628
  client: output.client,
@@ -4579,7 +4648,7 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema
4579
4648
  options: isFunction(output.mock) ? void 0 : output.mock
4580
4649
  });
4581
4650
  }
4582
- const schemasPath = output.schemas ? void 0 : join(dirname, filename + ".schemas" + extension);
4651
+ const schemasPath = output.schemas ? void 0 : nodePath.join(dirname, filename + ".schemas" + extension);
4583
4652
  if (schemasPath && needSchema) {
4584
4653
  const schemasData = header + generateModelsInline(builder.schemas);
4585
4654
  await fs$1.outputFile(schemasPath, schemasData);
@@ -4607,11 +4676,11 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema
4607
4676
  data += "\n\n";
4608
4677
  data += implementationMock;
4609
4678
  }
4610
- const implementationPath = join(dirname, `${kebab(tag)}${extension}`);
4679
+ const implementationPath = nodePath.join(dirname, `${kebab(tag)}${extension}`);
4611
4680
  await fs$1.outputFile(implementationPath, data);
4612
4681
  return [implementationPath, ...schemasPath ? [schemasPath] : []];
4613
4682
  } catch (error) {
4614
- throw new Error(`Oups... 🍻. An Error occurred while writing tag ${tag} => ${String(error)}`);
4683
+ throw new Error(`Oups... 🍻. An Error occurred while writing tag ${tag} => ${String(error)}`, { cause: error });
4615
4684
  }
4616
4685
  }))).flat();
4617
4686
  }