@orval/core 8.17.0 → 8.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import { t as __exportAll } from "./chunk-8H4AJuhK.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { entries, groupBy, isArray, isBoolean, isBoolean as isBoolean$1, isEmptyish, isFunction, isFunction as isFunction$1, 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 nodePath from "node:path";
5
+ import path from "node:path";
6
6
  import { compare } from "compare-versions";
7
7
  import debug from "debug";
8
8
  import { pathToFileURL } from "node:url";
@@ -168,7 +168,7 @@ function isDynamicReference(obj) {
168
168
  * @param pathValue - Path string to inspect.
169
169
  */
170
170
  function isDirectory(pathValue) {
171
- return !nodePath.extname(pathValue);
171
+ return !path.extname(pathValue);
172
172
  }
173
173
  /**
174
174
  * Type guard for plain objects created with `{}` or `new Object()`.
@@ -560,8 +560,8 @@ async function dynamicImport(toImport, from = process.cwd(), takeDefault = true)
560
560
  if (!toImport) return toImport;
561
561
  try {
562
562
  if (isString(toImport)) {
563
- const filePath = nodePath.resolve(from, toImport);
564
- const extension = nodePath.extname(filePath);
563
+ const filePath = path.resolve(from, toImport);
564
+ const extension = path.extname(filePath);
565
565
  if (TS_MODULE_EXTENSIONS.has(extension)) {
566
566
  const data = await createJiti(from, { interopDefault: true }).import(filePath);
567
567
  if (takeDefault && (isObject(data) || isModule(data)) && data.default) return data.default;
@@ -586,14 +586,14 @@ function getExtension(path) {
586
586
  //#region src/utils/file.ts
587
587
  function getFileInfo(target = "", { backupFilename = "filename", extension = ".ts" } = {}) {
588
588
  const isDir = isDirectory(target);
589
- const filePath = isDir ? nodePath.join(target, backupFilename + extension) : target;
589
+ const filePath = isDir ? path.join(target, backupFilename + extension) : target;
590
590
  return {
591
591
  path: filePath,
592
592
  pathWithoutExtension: filePath.replace(/\.[^/.]+$/, ""),
593
593
  extension,
594
594
  isDirectory: isDir,
595
- dirname: nodePath.dirname(filePath),
596
- filename: nodePath.basename(filePath, extension.startsWith(".") ? extension : `.${extension}`)
595
+ dirname: path.dirname(filePath),
596
+ filename: path.basename(filePath, extension.startsWith(".") ? extension : `.${extension}`)
597
597
  };
598
598
  }
599
599
  async function removeFilesAndEmptyFolders(patterns, dir) {
@@ -804,10 +804,10 @@ var path_exports = /* @__PURE__ */ __exportAll({
804
804
  toUnix: () => toUnix
805
805
  });
806
806
  function isAbsolute(value) {
807
- return nodePath.isAbsolute(value);
807
+ return path.isAbsolute(value);
808
808
  }
809
809
  function resolve(...args) {
810
- return toUnix(nodePath.resolve(...args));
810
+ return toUnix(path.resolve(...args));
811
811
  }
812
812
  function toUnix(value) {
813
813
  value = value.replaceAll("\\", "/");
@@ -815,13 +815,13 @@ function toUnix(value) {
815
815
  return value;
816
816
  }
817
817
  function join(...args) {
818
- return toUnix(nodePath.join(...args.map((a) => toUnix(a))));
818
+ return toUnix(path.join(...args.map((a) => toUnix(a))));
819
819
  }
820
820
  /**
821
821
  * Behaves exactly like `path.relative(from, to)`, but keeps the first meaningful "./"
822
822
  */
823
823
  function relativeSafe(from, to) {
824
- return normalizeSafe(`./${toUnix(nodePath.relative(toUnix(from), toUnix(to)))}`);
824
+ return normalizeSafe(`./${toUnix(path.relative(toUnix(from), toUnix(to)))}`);
825
825
  }
826
826
  function getSchemaFileName(path) {
827
827
  return path.replace(`.${getExtension(path)}`, "").slice(path.lastIndexOf("/") + 1);
@@ -829,13 +829,13 @@ function getSchemaFileName(path) {
829
829
  function normalizeSafe(value) {
830
830
  let result;
831
831
  value = toUnix(value);
832
- result = toUnix(nodePath.normalize(value));
832
+ result = toUnix(path.normalize(value));
833
833
  if (value.startsWith("./") && !result.startsWith("./") && !result.startsWith("..")) result = "./" + result;
834
834
  else if (value.startsWith("//") && !result.startsWith("//")) result = value.startsWith("//./") ? "//." + result : "/" + result;
835
835
  return result;
836
836
  }
837
837
  function joinSafe(...values) {
838
- let result = toUnix(nodePath.join(...values.map((v) => toUnix(v))));
838
+ let result = toUnix(path.join(...values.map((v) => toUnix(v))));
839
839
  if (values.length > 0) {
840
840
  const firstValue = toUnix(values[0]);
841
841
  if (firstValue.startsWith("./") && !result.startsWith("./") && !result.startsWith("..")) result = "./" + result;
@@ -866,14 +866,14 @@ function joinSafe(...values) {
866
866
  * @returns The relative import path string.
867
867
  */
868
868
  function getRelativeImportPath(importerFilePath, exporterFilePath, includeFileExtension = false) {
869
- if (!nodePath.isAbsolute(importerFilePath)) throw new Error(`'importerFilePath' is not an absolute path. "${importerFilePath}"`);
870
- if (!nodePath.isAbsolute(exporterFilePath)) throw new Error(`'exporterFilePath' is not an absolute path. "${exporterFilePath}"`);
871
- const importerDir = nodePath.dirname(importerFilePath);
872
- const relativePath = nodePath.relative(importerDir, exporterFilePath);
873
- let posixPath = nodePath.posix.join(...relativePath.split(nodePath.sep));
869
+ if (!path.isAbsolute(importerFilePath)) throw new Error(`'importerFilePath' is not an absolute path. "${importerFilePath}"`);
870
+ if (!path.isAbsolute(exporterFilePath)) throw new Error(`'exporterFilePath' is not an absolute path. "${exporterFilePath}"`);
871
+ const importerDir = path.dirname(importerFilePath);
872
+ const relativePath = path.relative(importerDir, exporterFilePath);
873
+ let posixPath = path.posix.join(...relativePath.split(path.sep));
874
874
  if (!posixPath.startsWith("./") && !posixPath.startsWith("../")) posixPath = `./${posixPath}`;
875
875
  if (!includeFileExtension) {
876
- const ext = nodePath.extname(posixPath);
876
+ const ext = path.extname(posixPath);
877
877
  if (ext && posixPath.endsWith(ext)) posixPath = posixPath.slice(0, -ext.length);
878
878
  }
879
879
  return posixPath;
@@ -882,20 +882,20 @@ function getRelativeImportPath(importerFilePath, exporterFilePath, includeFileEx
882
882
  //#region src/utils/resolve-version.ts
883
883
  function resolveInstalledVersion(packageName, fromDir) {
884
884
  try {
885
- const require = createRequire(nodePath.join(fromDir, "noop.js"));
885
+ const require = createRequire(path.join(fromDir, "noop.js"));
886
886
  try {
887
887
  return require(`${packageName}/package.json`).version;
888
888
  } catch (directError) {
889
889
  if (directError instanceof Error && "code" in directError && directError.code === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
890
890
  const entryPath = require.resolve(packageName);
891
- let dir = nodePath.dirname(entryPath);
892
- while (dir !== nodePath.parse(dir).root) {
893
- const pkgPath = nodePath.join(dir, "package.json");
891
+ let dir = path.dirname(entryPath);
892
+ while (dir !== path.parse(dir).root) {
893
+ const pkgPath = path.join(dir, "package.json");
894
894
  if (existsSync(pkgPath)) {
895
895
  const pkgData = JSON.parse(readFileSync(pkgPath, "utf8"));
896
896
  if (pkgData.name === packageName) return pkgData.version;
897
897
  }
898
- dir = nodePath.dirname(dir);
898
+ dir = path.dirname(dir);
899
899
  }
900
900
  return;
901
901
  }
@@ -955,17 +955,18 @@ const sortByPriority = (arr) => arr.toSorted((a, b) => {
955
955
  function stringify(data) {
956
956
  if (data === void 0) return;
957
957
  if (data === null) return "null";
958
- if (isString(data)) return `'${data.replaceAll("'", String.raw`\'`)}'`;
958
+ if (isString(data)) return `'${jsStringLiteralEscape(data)}'`;
959
959
  if (isNumber(data) || isBoolean(data) || isFunction(data)) return String(data);
960
960
  if (Array.isArray(data)) return `[${data.map((item) => stringify(item)).join(", ")}]`;
961
961
  const entries = Object.entries(data);
962
962
  let result = "";
963
963
  for (const [index, [key, value]] of entries.entries()) {
964
964
  const strValue = stringify(value);
965
- if (entries.length === 1) result = `{ ${key}: ${strValue}, }`;
966
- else if (!index) result = `{ ${key}: ${strValue}, `;
967
- else if (entries.length - 1 === index) result += `${key}: ${strValue}, }`;
968
- else result += `${key}: ${strValue}, `;
965
+ const safeKey = key === "__proto__" ? `['${jsStringLiteralEscape(key)}']` : keyword.isIdentifierNameES5(key) ? key : `'${jsStringLiteralEscape(key)}'`;
966
+ if (entries.length === 1) result = `{ ${safeKey}: ${strValue}, }`;
967
+ else if (!index) result = `{ ${safeKey}: ${strValue}, `;
968
+ else if (entries.length - 1 === index) result += `${safeKey}: ${strValue}, }`;
969
+ else result += `${safeKey}: ${strValue}, `;
969
970
  }
970
971
  return result;
971
972
  }
@@ -1158,6 +1159,55 @@ function dedupeUnionType(unionType) {
1158
1159
  return [...new Set(parts)].join(" | ");
1159
1160
  }
1160
1161
  //#endregion
1162
+ //#region src/utils/tags.ts
1163
+ /**
1164
+ * Canonical bucket key for a single OpenAPI tag.
1165
+ *
1166
+ * In `tags` / `tags-split` mode operations are routed into files by their first
1167
+ * tag. This function is the **single source of truth** for turning a tag (or a
1168
+ * missing tag) into the key that identifies that file bucket. Every place that
1169
+ * groups operations by tag, derives a per-tag file/directory name, or checks
1170
+ * whether an operation belongs to a tag MUST go through here so that the
1171
+ * "build the key" side and the "look the key up" side can never disagree.
1172
+ *
1173
+ * The result is `kebab`-cased. `kebab` is idempotent
1174
+ * (`kebab(kebab(x)) === kebab(x)`), so it is always safe to call this on a value
1175
+ * that is already a canonical key. Other case functions (`camel`, `pascal`) are
1176
+ * NOT safe here: they do not round-trip through the bucket key for tags
1177
+ * containing acronyms or spaces (e.g. `"AB Widget"`), which is exactly the class
1178
+ * of bug this module exists to prevent.
1179
+ *
1180
+ * Missing or empty tags map to the implicit {@link DefaultTag} bucket.
1181
+ */
1182
+ function getTagKey(tag) {
1183
+ const normalizedTag = tag?.trim();
1184
+ return kebab(normalizedTag ? normalizedTag : DefaultTag);
1185
+ }
1186
+ /**
1187
+ * Canonical bucket key for an operation, derived from its primary (first) tag.
1188
+ *
1189
+ * Untagged operations resolve to the {@link DefaultTag} bucket.
1190
+ */
1191
+ function getOperationTagKey(operation) {
1192
+ return getTagKey(operation.tags[0]);
1193
+ }
1194
+ /**
1195
+ * Whether an operation belongs to the given tag bucket.
1196
+ *
1197
+ * Both sides are normalised through {@link getTagKey}, so the comparison is
1198
+ * correct regardless of how `tagKey` was spelled or cased by the caller. An
1199
+ * absent (`undefined`) `tagKey` matches every operation (the "no tag filter"
1200
+ * case); an empty/whitespace `tagKey` is normalised to the {@link DefaultTag}
1201
+ * bucket like any other tag.
1202
+ *
1203
+ * Prefer this over hand-rolling `operation.tags[0] === tagKey`: a raw tag
1204
+ * compared against a canonical key silently fails for multi-word/acronym tags.
1205
+ */
1206
+ function isOperationInTagBucket(operation, tagKey) {
1207
+ if (tagKey == null) return true;
1208
+ return getOperationTagKey(operation) === getTagKey(tagKey);
1209
+ }
1210
+ //#endregion
1161
1211
  //#region src/utils/tsconfig.ts
1162
1212
  function isSyntheticDefaultImportsAllow(config) {
1163
1213
  if (!config) return true;
@@ -2485,6 +2535,52 @@ function buildDynamicScope(schemaName, schema, context) {
2485
2535
  return scope;
2486
2536
  }
2487
2537
  /**
2538
+ * Build dynamic scope entries for an **anonymous inline** subschema that declares
2539
+ * `$dynamicAnchor` without a `$ref` (e.g. inside `allOf`, `items`, nested props).
2540
+ *
2541
+ * Unlike {@link buildDynamicScope}, entries carry the concrete `inlineSchema` so
2542
+ * that a descendant `$dynamicRef` resolves to the inline override rather than the
2543
+ * outer/global component. Used when `dereference` enters a subschema without a
2544
+ * named component `$ref`.
2545
+ *
2546
+ * Scope of handling (deliberate, see #3492):
2547
+ * - Direct `$dynamicAnchor` on the subschema → inline entry.
2548
+ * - `$defs` `$dynamicAnchor` *without* a `$ref` → inline entry. Note this
2549
+ * differs from `buildDynamicScope`, which treats unbound `$defs` anchors as
2550
+ * generic parameters (`isParameter`); inline subschemas are concrete
2551
+ * instances, so the anchor resolves to the inline schema object itself.
2552
+ * - `$defs` `$dynamicAnchor` *with* a `$ref` → intentionally NOT collected
2553
+ * here. Such anchors rely on `resolveDynamicRef`'s global fallback (which
2554
+ * finds them when the `$ref` target declares the same anchor). Fully
2555
+ * resolving them would duplicate `buildDynamicScope`'s `$defs` logic.
2556
+ */
2557
+ function buildInlineDynamicScope(schema) {
2558
+ const scope = {};
2559
+ const schemaRecord = schema;
2560
+ if (typeof schemaRecord.$dynamicAnchor === "string") {
2561
+ const anchor = schemaRecord.$dynamicAnchor;
2562
+ scope[anchor] = {
2563
+ name: anchor,
2564
+ schemaName: anchor,
2565
+ inlineSchema: schema
2566
+ };
2567
+ }
2568
+ const defs = schemaRecord.$defs;
2569
+ if (defs && typeof defs === "object") for (const defSchema of Object.values(defs)) {
2570
+ if (!defSchema || typeof defSchema !== "object") continue;
2571
+ const defRecord = defSchema;
2572
+ if (typeof defRecord.$dynamicAnchor === "string" && !defSchema.$ref) {
2573
+ const anchor = defRecord.$dynamicAnchor;
2574
+ scope[anchor] = {
2575
+ name: anchor,
2576
+ schemaName: anchor,
2577
+ inlineSchema: defSchema
2578
+ };
2579
+ }
2580
+ }
2581
+ return scope;
2582
+ }
2583
+ /**
2488
2584
  * Resolve a `$dynamicRef` anchor to its concrete type using the current dynamic scope.
2489
2585
  * Returns `{ schema: {}, resolvedTypeName: 'unknown' }` when no scope override exists.
2490
2586
  */
@@ -2520,6 +2616,12 @@ function resolveDynamicRef(anchorName, context, imports = []) {
2520
2616
  resolvedTypeName: scopeEntry.name,
2521
2617
  schemaName: void 0
2522
2618
  };
2619
+ if (scopeEntry.inlineSchema) return {
2620
+ schema: scopeEntry.inlineSchema,
2621
+ imports,
2622
+ resolvedTypeName: scopeEntry.name,
2623
+ schemaName: void 0
2624
+ };
2523
2625
  const resolvedTypeName = scopeEntry.name;
2524
2626
  const schemaRef = `#/components/schemas/${encodeJsonPointerSegment(scopeEntry.schemaName)}`;
2525
2627
  try {
@@ -2712,7 +2814,7 @@ function resolveValue({ schema, name, context, formDataContext }) {
2712
2814
  const refName = resolvedImport.name;
2713
2815
  let effectiveContext = context;
2714
2816
  const refAnchor = schemaObject.$dynamicAnchor;
2715
- if (typeof refAnchor === "string" && context.dynamicScope?.[refAnchor] && context.dynamicScope[refAnchor].name !== refName && !context.dynamicScope[refAnchor].isParameter) {
2817
+ if (typeof refAnchor === "string" && context.dynamicScope?.[refAnchor] && context.dynamicScope[refAnchor].name !== refName && !context.dynamicScope[refAnchor].isParameter && !context.dynamicScope[refAnchor].inlineSchema) {
2716
2818
  const scopeEntry = context.dynamicScope[refAnchor];
2717
2819
  const allOf = ((context.spec.components?.schemas)?.[scopeEntry.schemaName])?.allOf;
2718
2820
  if (!(Array.isArray(allOf) && allOf.some((el) => {
@@ -4618,9 +4720,10 @@ function parseFunction(ast, funcName) {
4618
4720
  //#endregion
4619
4721
  //#region src/generators/mutator.ts
4620
4722
  const BODY_TYPE_NAME = "BodyType";
4621
- const getImport = (output, mutator) => {
4723
+ const getImport = (output, mutator, tsconfig) => {
4622
4724
  const outputFile = getFileInfo(output).path;
4623
- return `${getRelativeImportPath(outputFile, mutator.path)}${mutator.extension ?? ""}`;
4725
+ const ext = mutator.extension ?? getImportExtension(path.extname(mutator.path), tsconfig);
4726
+ return `${getRelativeImportPath(outputFile, mutator.path)}${ext}`;
4624
4727
  };
4625
4728
  async function generateMutator({ output, mutator, name, workspace, tsconfig }) {
4626
4729
  if (!mutator || !output) return;
@@ -4643,7 +4746,7 @@ async function generateMutator({ output, mutator, name, workspace, tsconfig }) {
4643
4746
  tsconfig
4644
4747
  });
4645
4748
  if (!mutatorInfo) throw new Error(styleText("red", `Your mutator file doesn't have the ${mutatorInfoName} exported function`));
4646
- const importStatementPath = getImport(output, mutator);
4749
+ const importStatementPath = getImport(output, mutator, tsconfig);
4647
4750
  const isHook = mutator.name ? mutator.name.startsWith("use") && !mutatorInfo.numberOfParams : !mutatorInfo.numberOfParams;
4648
4751
  return {
4649
4752
  name: mutator.name || !isHook ? importName : `use${pascal(importName)}`,
@@ -4685,11 +4788,19 @@ const getAngularFilteredParamsExpression = (paramsExpression, requiredNullablePa
4685
4788
  continue;
4686
4789
  }
4687
4790
  ` : "";
4688
- const preserveNullableBranch = preserveRequiredNullables ? ` } else if (value === null && requiredNullableParamKeys.has(key)) {
4791
+ let preserveNullableBranch;
4792
+ let requiredNullableParamKeysBranch;
4793
+ if (preserveRequiredNullables) {
4794
+ preserveNullableBranch = ` } else if (value === null && requiredNullableParamKeys.has(key)) {
4689
4795
  filteredParams[key] = null;
4690
- ` : "";
4796
+ `;
4797
+ requiredNullableParamKeysBranch = `const requiredNullableParamKeys = new Set<string>(${JSON.stringify(requiredNullableParamKeys)});`;
4798
+ } else {
4799
+ preserveNullableBranch = "";
4800
+ requiredNullableParamKeysBranch = "";
4801
+ }
4691
4802
  return `(() => {
4692
- ${hasPassthrough ? ` const passthroughKeys = new Set<string>(${JSON.stringify(nonPrimitiveKeys)});\n` : ""} const requiredNullableParamKeys = new Set<string>(${JSON.stringify(requiredNullableParamKeys)});
4803
+ ${hasPassthrough ? ` const passthroughKeys = new Set<string>(${JSON.stringify(nonPrimitiveKeys)});\n` : ""} ${requiredNullableParamKeysBranch}
4693
4804
  const filteredParams: Record<string, ${filteredParamValueType}> = {};
4694
4805
  for (const [key, value] of Object.entries(${paramsExpression})) {
4695
4806
  ${passthroughBranch} if (Array.isArray(value)) {
@@ -4811,7 +4922,7 @@ function generateBodyOptions(body, isFormData, isFormUrlEncoded) {
4811
4922
  if (isFormUrlEncoded && body.formUrlEncoded) return "formUrlEncoded";
4812
4923
  if (body.implementation) return body.implementation;
4813
4924
  }
4814
- function generateAxiosOptions({ response, isExactOptionalPropertyTypes, angularObserve, angularParamsRef, requiredNullableQueryParamKeys, nonPrimitiveQueryParamKeys, queryParams, headers, requestOptions, hasSignal, hasSignalParam = false, isVue, isAngular, paramsSerializer, paramsSerializerOptions, paramsFilter }) {
4925
+ function generateAxiosOptions({ response, isExactOptionalPropertyTypes, angularObserve, angularParamsRef, requiredNullableQueryParamKeys, nonPrimitiveQueryParamKeys, queryParams, headers, requestOptions, hasSignal, hasSignalParam = false, isAngular, paramsSerializer, paramsSerializerOptions, paramsFilter }) {
4815
4926
  const isRequestOptions = requestOptions !== false;
4816
4927
  const angularPassthroughQueryParamKeys = paramsSerializer ? nonPrimitiveQueryParamKeys : [];
4817
4928
  const signalVar = hasSignalParam ? "querySignal" : "signal";
@@ -4848,8 +4959,7 @@ function generateAxiosOptions({ response, isExactOptionalPropertyTypes, angularO
4848
4959
  if (isRequestOptions) {
4849
4960
  value += isAngular ? "\n ...(options as Omit<NonNullable<typeof options>, 'observe'>)," : "\n ...options,";
4850
4961
  if (isAngular && angularObserve) value += `\n observe: '${angularObserve}',`;
4851
- if (queryParams) if (isVue) value += "\n params: {...unref(params), ...options?.params},";
4852
- else if (isAngular && angularParamsRef) value += `\n params: ${angularParamsRef},`;
4962
+ if (queryParams) if (isAngular && angularParamsRef) value += `\n params: ${angularParamsRef},`;
4853
4963
  else if (isAngular && paramsSerializer) {
4854
4964
  const callExpr = buildAngularParamsFilterExpression({
4855
4965
  paramsExpression: "{...params, ...options?.params}",
@@ -4878,7 +4988,7 @@ function generateAxiosOptions({ response, isExactOptionalPropertyTypes, angularO
4878
4988
  }
4879
4989
  return value;
4880
4990
  }
4881
- function generateOptions({ route, body, angularObserve, angularParamsRef, headers, queryParams, response, verb, requestOptions, isFormData, isFormUrlEncoded, isAngular, isExactOptionalPropertyTypes, hasSignal, hasSignalParam, isVue, paramsSerializer, paramsSerializerOptions, paramsFilter }) {
4991
+ function generateOptions({ route, body, angularObserve, angularParamsRef, headers, queryParams, response, verb, requestOptions, isFormData, isFormUrlEncoded, isAngular, isExactOptionalPropertyTypes, hasSignal, hasSignalParam, paramsSerializer, paramsSerializerOptions, paramsFilter }) {
4882
4992
  const bodyIdentifier = getIsBodyVerb(verb) ? generateBodyOptions(body, isFormData, isFormUrlEncoded) : void 0;
4883
4993
  const axiosOptions = generateAxiosOptions({
4884
4994
  response,
@@ -4892,7 +5002,6 @@ function generateOptions({ route, body, angularObserve, angularParamsRef, header
4892
5002
  isExactOptionalPropertyTypes,
4893
5003
  hasSignal,
4894
5004
  hasSignalParam,
4895
- isVue: isVue ?? false,
4896
5005
  isAngular: isAngular ?? false,
4897
5006
  paramsSerializer,
4898
5007
  paramsSerializerOptions,
@@ -4915,11 +5024,10 @@ function generateBodyMutatorConfig(body, isFormData, isFormUrlEncoded) {
4915
5024
  if (body.implementation) return `,\n data: ${body.implementation}`;
4916
5025
  return "";
4917
5026
  }
4918
- function generateQueryParamsAxiosConfig(response, isVue, isAngular, requiredNullableQueryParamKeys, queryParams, paramsFilter) {
5027
+ function generateQueryParamsAxiosConfig(response, isAngular, requiredNullableQueryParamKeys, queryParams, paramsFilter) {
4919
5028
  if (!queryParams && !response.isBlob) return "";
4920
5029
  let value = "";
4921
- if (queryParams) if (isVue) value += ",\n params: unref(params)";
4922
- else if (isAngular) {
5030
+ if (queryParams) if (isAngular) {
4923
5031
  const paramsExpr = buildAngularParamsFilterExpression({
4924
5032
  paramsExpression: "params ?? {}",
4925
5033
  requiredNullableParamKeys: requiredNullableQueryParamKeys,
@@ -4932,9 +5040,9 @@ function generateQueryParamsAxiosConfig(response, isVue, isAngular, requiredNull
4932
5040
  if (response.isBlob) value += `,\n responseType: 'blob'`;
4933
5041
  return value;
4934
5042
  }
4935
- function generateMutatorConfig({ route, body, headers, queryParams, response, verb, isFormData, isFormUrlEncoded, hasSignal, hasSignalParam = false, isExactOptionalPropertyTypes, isVue, isAngular, paramsFilter }) {
5043
+ function generateMutatorConfig({ route, body, headers, queryParams, response, verb, isFormData, isFormUrlEncoded, hasSignal, hasSignalParam = false, isExactOptionalPropertyTypes, isAngular, paramsFilter }) {
4936
5044
  const bodyOptions = getIsBodyVerb(verb) ? generateBodyMutatorConfig(body, isFormData, isFormUrlEncoded) : "";
4937
- const queryParamsOptions = generateQueryParamsAxiosConfig(response, isVue ?? false, isAngular ?? false, queryParams?.requiredNullableKeys, queryParams, paramsFilter);
5045
+ const queryParamsOptions = generateQueryParamsAxiosConfig(response, isAngular ?? false, queryParams?.requiredNullableKeys, queryParams, paramsFilter);
4938
5046
  const ignoreContentTypes = isAngular ? ["multipart/form-data"] : [];
4939
5047
  const headerOptions = body.contentType && !ignoreContentTypes.includes(body.contentType) ? `,\n headers: {'Content-Type': '${body.contentType}', ${headers ? "...headers" : ""}}` : headers ? ",\n headers" : "";
4940
5048
  const signalVar = hasSignalParam ? "querySignal" : "signal";
@@ -5469,6 +5577,50 @@ async function writeGeneratedFile(filePath, content) {
5469
5577
  await fs$1.outputFile(filePath, content.replaceAll(TRAILING_WHITESPACE_RE, ""));
5470
5578
  }
5471
5579
  //#endregion
5580
+ //#region src/writers/schema-tag-mapper.ts
5581
+ const SHARED_DIR = ".";
5582
+ function buildSchemaTagMap(operations, schemas) {
5583
+ const schemaNames = new Set(schemas.map((s) => s.name));
5584
+ const schemaToTags = /* @__PURE__ */ new Map();
5585
+ for (const schema of schemas) if (!schemaToTags.has(schema.name)) schemaToTags.set(schema.name, /* @__PURE__ */ new Set());
5586
+ for (const operation of operations) {
5587
+ const tag = kebab(operation.tags[0] ?? "default");
5588
+ for (const imp of operation.imports) if (!imp.importPath && schemaNames.has(imp.name)) addTag(schemaToTags, imp.name, tag);
5589
+ }
5590
+ propagateTransitiveTags(schemaToTags, new Map(schemas.map((s) => [s.name, s])));
5591
+ const result = /* @__PURE__ */ new Map();
5592
+ for (const [name, tags] of schemaToTags) if (tags.size === 0 || tags.size > 1) result.set(name, ".");
5593
+ else result.set(name, [...tags][0]);
5594
+ return result;
5595
+ }
5596
+ function addTag(schemaToTags, schemaName, tag) {
5597
+ if (!schemaToTags.has(schemaName)) schemaToTags.set(schemaName, /* @__PURE__ */ new Set());
5598
+ schemaToTags.get(schemaName).add(tag);
5599
+ }
5600
+ function propagateTransitiveTags(schemaToTags, schemaByName) {
5601
+ let changed = true;
5602
+ while (changed) {
5603
+ changed = false;
5604
+ for (const [name, tags] of schemaToTags) {
5605
+ const schema = schemaByName.get(name);
5606
+ if (!schema) continue;
5607
+ for (const imp of schema.imports) {
5608
+ if (!isSchemaImport(imp)) continue;
5609
+ if (!schemaByName.has(imp.name)) continue;
5610
+ const targetTags = schemaToTags.get(imp.name);
5611
+ if (!targetTags) continue;
5612
+ for (const tag of tags) if (!targetTags.has(tag)) {
5613
+ targetTags.add(tag);
5614
+ changed = true;
5615
+ }
5616
+ }
5617
+ }
5618
+ }
5619
+ }
5620
+ function isSchemaImport(imp) {
5621
+ return !imp.importPath;
5622
+ }
5623
+ //#endregion
5472
5624
  //#region src/writers/schemas.ts
5473
5625
  /**
5474
5626
  * Patterns to detect operation-derived types (params, bodies, responses).
@@ -5621,8 +5773,8 @@ function getSchema({ schema: { imports, model }, header, namingConvention = Nami
5621
5773
  file += model;
5622
5774
  return file;
5623
5775
  }
5624
- function getPath(path, name, fileExtension) {
5625
- return nodePath.join(path, `${name}${fileExtension}`);
5776
+ function getPath(path$1, name, fileExtension) {
5777
+ return path.join(path$1, `${name}${fileExtension}`);
5626
5778
  }
5627
5779
  function writeModelInline(acc, model) {
5628
5780
  return acc + `${model}\n`;
@@ -5715,14 +5867,14 @@ async function writeSchemas({ schemaPath, schemas, target, namingConvention, fil
5715
5867
  await writeGeneratedFile(getPath(factoryDir, factoryFileName, fileExtension), factoryFile);
5716
5868
  }
5717
5869
  if (indexFiles) {
5718
- const schemaFilePath = nodePath.join(schemaPath, `index.ts`);
5870
+ const schemaFilePath = path.join(schemaPath, `index.ts`);
5719
5871
  await fs$1.ensureFile(schemaFilePath);
5720
5872
  const ext = getImportExtension(fileExtension, tsconfig);
5721
5873
  const conventionNamesSet = new Set(Object.values(schemaGroups).map((group) => conventionName(group[0].name, namingConvention)));
5722
5874
  try {
5723
5875
  const currentExports = [...conventionNamesSet].map((schemaName) => `export * from './${schemaName}${ext}';`);
5724
5876
  if (factoryOutputDirectory && normalizeSafe(factoryOutputDirectory) !== normalizeSafe(schemaPath) && (isCombined.value || separateFactoryNames.length > 0)) {
5725
- const factoryIndexFilePath = nodePath.join(factoryOutputDirectory, `index.ts`);
5877
+ const factoryIndexFilePath = path.join(factoryOutputDirectory, `index.ts`);
5726
5878
  await fs$1.ensureFile(factoryIndexFilePath);
5727
5879
  const factoryExports = [];
5728
5880
  if (isCombined.value) {
@@ -5745,24 +5897,93 @@ async function writeSchemas({ schemaPath, schemas, target, namingConvention, fil
5745
5897
  }
5746
5898
  }
5747
5899
  //#endregion
5900
+ //#region src/writers/schemas-tags-split.ts
5901
+ async function writeSchemasTagsSplit({ schemaPath, schemas, target, namingConvention, fileExtension, header, indexFiles, tsconfig, factoryOutputDirectory, operations }) {
5902
+ const schemaTagMap = buildSchemaTagMap(operations, schemas);
5903
+ const importExtension = getImportExtension(fileExtension, tsconfig);
5904
+ const groups = /* @__PURE__ */ new Map();
5905
+ for (const schema of schemas) {
5906
+ const group = schemaTagMap.get(schema.name) ?? ".";
5907
+ if (!groups.has(group)) groups.set(group, []);
5908
+ groups.get(group).push(schema);
5909
+ }
5910
+ for (const [groupDir, groupSchemas] of groups) {
5911
+ const isRoot = groupDir === ".";
5912
+ const groupPath = isRoot ? schemaPath : path.join(schemaPath, groupDir);
5913
+ fixCrossTagImports(groupSchemas, schemaTagMap, schemaPath, groupDir, namingConvention, importExtension);
5914
+ const groupFactoryDir = factoryOutputDirectory ? isRoot ? factoryOutputDirectory : path.join(factoryOutputDirectory, groupDir) : void 0;
5915
+ await writeSchemas({
5916
+ schemaPath: groupPath,
5917
+ schemas: groupSchemas,
5918
+ target,
5919
+ namingConvention,
5920
+ fileExtension,
5921
+ header,
5922
+ indexFiles: !isRoot && indexFiles,
5923
+ tsconfig,
5924
+ factoryOutputDirectory: groupFactoryDir
5925
+ });
5926
+ }
5927
+ if (indexFiles && groups.size > 0) {
5928
+ const rootIndexPath = path.join(schemaPath, "index.ts");
5929
+ const rootExports = (groups.get(".") ?? []).map((s) => {
5930
+ return `export * from './${conventionName(s.name, namingConvention)}${importExtension}';`;
5931
+ });
5932
+ const tagExports = [...groups.keys()].filter((dir) => dir !== ".").toSorted((a, b) => a.localeCompare(b, "en", { numeric: true })).map((dir) => {
5933
+ return `export * from '${importExtension ? `./${dir}/index${importExtension}` : `./${dir}`}';`;
5934
+ });
5935
+ await writeGeneratedFile(rootIndexPath, `${header}\n${[...rootExports, ...tagExports].join("\n")}\n`);
5936
+ }
5937
+ }
5938
+ function fixCrossTagImports(schemas, schemaTagMap, schemaPath, currentGroupDir, namingConvention, importExtension) {
5939
+ const fromPath = currentGroupDir === "." ? schemaPath : path.join(schemaPath, currentGroupDir);
5940
+ for (const schema of schemas) {
5941
+ const fixImports = (imports) => imports.map((imp) => {
5942
+ const targetGroup = schemaTagMap.get(imp.name);
5943
+ if (targetGroup === void 0 || targetGroup === currentGroupDir) return imp;
5944
+ const importPath = joinSafe(relativeSafe(fromPath, targetGroup === "." ? schemaPath : path.join(schemaPath, targetGroup)), conventionName(imp.name, namingConvention)) + importExtension;
5945
+ return {
5946
+ ...imp,
5947
+ importPath
5948
+ };
5949
+ });
5950
+ schema.imports = fixImports(schema.imports);
5951
+ if (schema.factoryImports) schema.factoryImports = fixImports(schema.factoryImports);
5952
+ }
5953
+ }
5954
+ //#endregion
5748
5955
  //#region src/writers/finalize-mock-implementation.ts
5749
5956
  function getFinalizeMockImplementationOptions(output, mockOutputs) {
5750
- const strictSchemaTypeNames = [...new Set((Array.isArray(mockOutputs) ? mockOutputs : [mockOutputs]).flatMap((mockOutput) => mockOutput.strictMockSchemaTypeNames ?? []))];
5957
+ const outputs = Array.isArray(mockOutputs) ? mockOutputs : [mockOutputs];
5958
+ const strictSchemaTypeNames = [...new Set(outputs.flatMap((mockOutput) => mockOutput.strictMockSchemaTypeNames ?? []))];
5959
+ const strictMockSchemaKinds = outputs.reduce((acc, mockOutput) => {
5960
+ if (!mockOutput.strictMockSchemaKinds) return acc;
5961
+ for (const [name, kind] of Object.entries(mockOutput.strictMockSchemaKinds)) acc[name] ??= kind;
5962
+ return acc;
5963
+ }, {});
5751
5964
  return {
5752
5965
  mockOptions: output.override.mock,
5753
- strictSchemaTypeNames: strictSchemaTypeNames.length > 0 ? strictSchemaTypeNames : void 0
5966
+ strictSchemaTypeNames: strictSchemaTypeNames.length > 0 ? strictSchemaTypeNames : void 0,
5967
+ strictMockSchemaKinds: Object.keys(strictMockSchemaKinds).length > 0 ? strictMockSchemaKinds : void 0
5754
5968
  };
5755
5969
  }
5970
+ /** Drop schema-factory `{Schema}Mock` type imports that are declared locally. */
5971
+ function filterLocalStrictMockTypeImports(imports, strictSchemaTypeNames) {
5972
+ if (!strictSchemaTypeNames?.length) return [...imports];
5973
+ const localMockTypeNames = new Set(strictSchemaTypeNames.map((name) => `${name}Mock`));
5974
+ return imports.filter((imp) => !(imp.schemaFactory && !imp.values && localMockTypeNames.has(imp.name)));
5975
+ }
5756
5976
  //#endregion
5757
5977
  //#region src/writers/generate-imports-for-builder.ts
5758
- function generateImportsForBuilder(output, imports, relativeSchemasPath) {
5978
+ function generateImportsForBuilder(output, imports, relativeSchemasPath, schemaTagMap) {
5759
5979
  const isPackageImport = isObject(output.schemas) && !!output.schemas.importPath;
5760
5980
  const isZodSchemaOutput = isObject(output.schemas) && output.schemas.type === "zod";
5761
5981
  const schemaFactoryImports = imports.filter((i) => i.schemaFactory);
5762
5982
  const schemaFactoryImportExtension = isPackageImport ? "" : getImportExtension(output.fileExtension, output.tsconfig);
5983
+ const schemaFactoryDependency = getFakerSchemasImportPath(output.mock) ?? joinSafe(relativeSchemasPath, `index.faker${schemaFactoryImportExtension}`);
5763
5984
  const schemaFactoryDeps = schemaFactoryImports.length > 0 ? [{
5764
5985
  exports: uniqueBy(schemaFactoryImports, (entry) => `${entry.name}|${entry.alias ?? ""}`),
5765
- dependency: joinSafe(relativeSchemasPath, `index.faker${schemaFactoryImportExtension}`)
5986
+ dependency: schemaFactoryDependency
5766
5987
  }] : [];
5767
5988
  imports = imports.filter((i) => !i.schemaFactory);
5768
5989
  let schemaImports;
@@ -5776,7 +5997,11 @@ function generateImportsForBuilder(output, imports, relativeSchemasPath) {
5776
5997
  else {
5777
5998
  const importsByDependency = /* @__PURE__ */ new Map();
5778
5999
  for (const schemaImport of imports.filter((i) => !i.importPath)) {
5779
- const dependency = joinSafe(relativeSchemasPath, `${conventionName(isZodSchemaOutput ? schemaImport.name : schemaImport.schemaName ?? schemaImport.name, output.namingConvention)}${isZodSchemaOutput ? ".zod" : ""}${isPackageImport ? "" : getImportExtension(output.fileExtension, output.tsconfig)}`);
6000
+ const normalizedName = conventionName(isZodSchemaOutput ? schemaImport.name : schemaImport.schemaName ?? schemaImport.name, output.namingConvention);
6001
+ const suffix = isZodSchemaOutput ? ".zod" : "";
6002
+ const importExtension = isPackageImport ? "" : getImportExtension(output.fileExtension, output.tsconfig);
6003
+ const tagDir = schemaTagMap?.get(schemaImport.name);
6004
+ const dependency = joinSafe(relativeSchemasPath, `${tagDir && tagDir !== "." ? `${tagDir}/` : ""}${normalizedName}${suffix}${importExtension}`);
5780
6005
  if (!importsByDependency.has(dependency)) importsByDependency.set(dependency, []);
5781
6006
  importsByDependency.get(dependency)?.push(schemaImport);
5782
6007
  }
@@ -5797,6 +6022,88 @@ function generateImportsForBuilder(output, imports, relativeSchemasPath) {
5797
6022
  ...otherImports
5798
6023
  ];
5799
6024
  }
6025
+ /**
6026
+ * Extracts the faker generator's `schemasImportPath` from the normalized mock
6027
+ * config, if one is configured. Returns `undefined` when there is no faker
6028
+ * generator with schema factories enabled, or when `schemasImportPath` is not
6029
+ * set.
6030
+ */
6031
+ function getFakerSchemasImportPath(mock) {
6032
+ if (!mock) return;
6033
+ return mock.generators.find((g) => !isFunction(g) && g.type === OutputMockType.FAKER && g.schemas === true)?.schemasImportPath;
6034
+ }
6035
+ //#endregion
6036
+ //#region src/writers/mock-imports.ts
6037
+ /** Maps `components/schemas` names to consolidated index.faker import symbols. */
6038
+ function buildKnownSchemaFactoryImportSets(schemaNames) {
6039
+ const factoryNames = /* @__PURE__ */ new Set();
6040
+ const typeNames = /* @__PURE__ */ new Set();
6041
+ for (const name of schemaNames) {
6042
+ const typeName = pascal(name);
6043
+ factoryNames.add(`get${typeName}Mock`);
6044
+ typeNames.add(`${typeName}Mock`);
6045
+ }
6046
+ return {
6047
+ factoryNames,
6048
+ typeNames
6049
+ };
6050
+ }
6051
+ /**
6052
+ * Recover schema-factory imports referenced in generated mock bodies but
6053
+ * missing from the collected import list (e.g. after shared-array import
6054
+ * aggregation on large specs). Scans for `get<Schema>Mock()` calls and
6055
+ * `as <Schema>Mock` casts emitted by strict schema delegation (#3590).
6056
+ *
6057
+ * When `knownSets` is provided, only symbols that exist in the consolidated
6058
+ * schemas faker file are recovered — this avoids importing one-off split
6059
+ * response helper factories that live in the tag file itself.
6060
+ */
6061
+ function collectSchemaFactoryImportsFromImplementation(implementation, knownSets) {
6062
+ const imports = [];
6063
+ const seen = /* @__PURE__ */ new Set();
6064
+ for (const match of implementation.matchAll(/\b(get[A-Za-z0-9]+Mock)\(\)/g)) {
6065
+ const factoryName = match[1];
6066
+ if (knownSets && !knownSets.factoryNames.has(factoryName)) continue;
6067
+ const key = `value::${factoryName}`;
6068
+ if (seen.has(key)) continue;
6069
+ seen.add(key);
6070
+ imports.push({
6071
+ name: factoryName,
6072
+ values: true,
6073
+ schemaFactory: true
6074
+ });
6075
+ }
6076
+ for (const match of implementation.matchAll(/\bas ([A-Za-z0-9]+Mock)\b/g)) {
6077
+ const typeName = match[1];
6078
+ if (knownSets && !knownSets.typeNames.has(typeName)) continue;
6079
+ const key = `type::${typeName}`;
6080
+ if (seen.has(key)) continue;
6081
+ seen.add(key);
6082
+ imports.push({
6083
+ name: typeName,
6084
+ values: false,
6085
+ schemaFactory: true
6086
+ });
6087
+ }
6088
+ return imports;
6089
+ }
6090
+ function mergeGeneratorImports(...groups) {
6091
+ const merged = /* @__PURE__ */ new Map();
6092
+ for (const group of groups) for (const imp of group) {
6093
+ const key = `${imp.name}::${imp.alias ?? ""}`;
6094
+ const existing = merged.get(key);
6095
+ if (!existing) {
6096
+ merged.set(key, imp);
6097
+ continue;
6098
+ }
6099
+ if (!existing.values && imp.values) merged.set(key, imp);
6100
+ }
6101
+ return [...merged.values()];
6102
+ }
6103
+ /** Recover missing index.faker imports when `schemas: true` is enabled. */
6104
+ function collectRecoveredSchemaFactoryImports(implementation, componentSchemaNames) {
6105
+ return collectSchemaFactoryImportsFromImplementation(implementation, buildKnownSchemaFactoryImportSets(componentSchemaNames));
6106
+ }
5800
6107
  //#endregion
5801
6108
  //#region src/writers/mock-outputs.ts
5802
6109
  /**
@@ -5822,8 +6129,8 @@ function hasAnyMockPath(mockConfig) {
5822
6129
  return mockConfig.generators.some((g) => !isFunction(g) && !!g.path);
5823
6130
  }
5824
6131
  function resolveMockSchemasPath(mockFilePath, schemasTarget) {
5825
- const ext = nodePath.extname(mockFilePath);
5826
- const targetExt = nodePath.extname(schemasTarget);
6132
+ const ext = path.extname(mockFilePath);
6133
+ const targetExt = path.extname(schemasTarget);
5827
6134
  return getRelativeImportPath(mockFilePath, targetExt === ".schemas" ? schemasTarget + ext : targetExt ? schemasTarget : schemasTarget + ext);
5828
6135
  }
5829
6136
  //#endregion
@@ -5844,7 +6151,8 @@ function flattenMockOutput$1(full) {
5844
6151
  type: full.type,
5845
6152
  implementation: full.implementation.function + full.implementation.handler,
5846
6153
  imports: full.imports,
5847
- strictMockSchemaTypeNames: full.strictMockSchemaTypeNames
6154
+ strictMockSchemaTypeNames: full.strictMockSchemaTypeNames,
6155
+ strictMockSchemaKinds: full.strictMockSchemaKinds
5848
6156
  };
5849
6157
  }
5850
6158
  function generateTarget(builder, options) {
@@ -5866,7 +6174,8 @@ function generateTarget(builder, options) {
5866
6174
  formUrlEncoded: [],
5867
6175
  paramsSerializer: [],
5868
6176
  paramsFilter: [],
5869
- fetchReviver: []
6177
+ fetchReviver: [],
6178
+ sharedTypes: []
5870
6179
  };
5871
6180
  const operations = Object.values(builder.operations);
5872
6181
  for (const [index, operation] of operations.entries()) {
@@ -5880,6 +6189,10 @@ function generateTarget(builder, options) {
5880
6189
  }
5881
6190
  acc.imports.push(...opMock.imports);
5882
6191
  if (opMock.strictMockSchemaTypeNames?.length) acc.strictMockSchemaTypeNames = [...new Set([...acc.strictMockSchemaTypeNames ?? [], ...opMock.strictMockSchemaTypeNames])];
6192
+ if (opMock.strictMockSchemaKinds) acc.strictMockSchemaKinds = {
6193
+ ...acc.strictMockSchemaKinds,
6194
+ ...opMock.strictMockSchemaKinds
6195
+ };
5883
6196
  acc.implementation.function += opMock.implementation.function;
5884
6197
  acc.implementation.handler += opMock.implementation.handler;
5885
6198
  if (opMock.implementation.handlerName) {
@@ -5909,7 +6222,7 @@ function generateTarget(builder, options) {
5909
6222
  verbOptions: builder.verbOptions,
5910
6223
  clientImplementation: target.implementation
5911
6224
  });
5912
- target.implementation = header.implementation + target.implementation;
6225
+ target.implementation = (header.sharedTypes && header.sharedTypes.length > 0 ? header.sharedTypes.map((t) => `${t.exported ? "export " : ""}${t.code}`).join("\n") + "\n\n" : "") + header.implementation + target.implementation;
5913
6226
  const footer = builder.footer({
5914
6227
  outputClient: options.client,
5915
6228
  operationNames,
@@ -5975,7 +6288,7 @@ interface TypedResponse<T> extends Response {
5975
6288
  }
5976
6289
  //#endregion
5977
6290
  //#region src/writers/single-mode.ts
5978
- async function writeSingleMode({ builder, output, projectName, header, needSchema, generateSchemasInline }) {
6291
+ async function writeSingleMode({ builder, output, projectName, header, needSchema, generateSchemasInline, schemaTagMap }) {
5979
6292
  try {
5980
6293
  const { path: targetPath, filename, dirname, extension } = getFileInfo(output.target, {
5981
6294
  backupFilename: conventionName(builder.info.title ?? "filename", output.namingConvention),
@@ -6003,7 +6316,7 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
6003
6316
  }
6004
6317
  }
6005
6318
  let data = header;
6006
- const importsForBuilder = schemasPath ? generateImportsForBuilder(output, normalizedImports, relativeSchemasPath) : generateImportsForBuilder(output, normalizedImports.filter((imp) => !!imp.importPath), ".");
6319
+ const importsForBuilder = schemasPath ? generateImportsForBuilder(output, normalizedImports, relativeSchemasPath, schemaTagMap) : generateImportsForBuilder(output, normalizedImports.filter((imp) => !!imp.importPath), ".");
6007
6320
  data += builder.imports({
6008
6321
  client: output.client,
6009
6322
  implementation,
@@ -6019,10 +6332,13 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
6019
6332
  });
6020
6333
  if (!shouldDeinlineMocks) for (const mockOutput of collapsedMockOutputs) {
6021
6334
  const entry = output.mock.generators.find((g) => !isFunction(g) && g.type === mockOutput.type);
6022
- const filteredMockImports = mockOutput.imports.filter((impMock) => !normalizedImports.some((imp) => imp.name === impMock.name && (imp.alias ?? "") === (impMock.alias ?? "")));
6023
- const importsMockForBuilder = schemasPath ? generateImportsForBuilder(output, filteredMockImports, relativeSchemasPath) : generateImportsForBuilder(output, filteredMockImports.filter((imp) => !!imp.importPath), ".");
6335
+ const finalizeMockOptions = getFinalizeMockImplementationOptions(output, mockOutput);
6336
+ const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, finalizeMockOptions) : mockOutput.implementation;
6337
+ const recoveredSchemaFactoryImports = !!entry && !isFunction(entry) && entry.type === OutputMockType.FAKER && entry.schemas === true && output.schemas ? collectRecoveredSchemaFactoryImports(finalizedMockImplementation, builder.schemas.filter((s) => s.schema).map((s) => s.name)) : [];
6338
+ const filteredMockImports = filterLocalStrictMockTypeImports(mergeGeneratorImports(mockOutput.imports, recoveredSchemaFactoryImports).filter((impMock) => !normalizedImports.some((imp) => imp.name === impMock.name && (imp.alias ?? "") === (impMock.alias ?? ""))), finalizeMockOptions.strictSchemaTypeNames);
6339
+ const importsMockForBuilder = schemasPath ? generateImportsForBuilder(output, filteredMockImports, relativeSchemasPath, schemaTagMap) : generateImportsForBuilder(output, filteredMockImports.filter((imp) => !!imp.importPath), ".");
6024
6340
  data += builder.importsMock({
6025
- implementation: mockOutput.implementation,
6341
+ implementation: finalizedMockImplementation,
6026
6342
  imports: importsMockForBuilder,
6027
6343
  projectName,
6028
6344
  hasSchemaDir: !!output.schemas,
@@ -6071,11 +6387,13 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
6071
6387
  if (!rawEntry) continue;
6072
6388
  const mockExtension = isFunction(rawEntry) ? OutputMockType.MSW : getMockFileExtensionByTypeName(rawEntry);
6073
6389
  const mockDir = getMockDir(rawEntry, output.mock) ?? dirname;
6074
- const mockFilePath = nodePath.join(mockDir, filename + "." + mockExtension + extension);
6390
+ const mockFilePath = path.join(mockDir, filename + "." + mockExtension + extension);
6075
6391
  const mockRelativeSchemasPath = schemaCustomImportPath ?? resolveMockSchemasPath(mockFilePath, schemasTarget);
6076
- const importsMockForBuilder = schemasPath || mockDir !== dirname ? generateImportsForBuilder(output, mockOutput.imports, mockRelativeSchemasPath) : generateImportsForBuilder(output, mockOutput.imports.filter((imp) => !!imp.importPath), ".");
6392
+ const finalizeMockOptions = getFinalizeMockImplementationOptions(output, mockOutput);
6393
+ const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, finalizeMockOptions) : mockOutput.implementation;
6394
+ const recoveredSchemaFactoryImports = !isFunction(rawEntry) && rawEntry.type === OutputMockType.FAKER && rawEntry.schemas === true && output.schemas ? collectRecoveredSchemaFactoryImports(finalizedMockImplementation, builder.schemas.filter((s) => s.schema).map((s) => s.name)) : [];
6395
+ const importsMockForBuilder = schemasPath || mockDir !== dirname ? generateImportsForBuilder(output, filterLocalStrictMockTypeImports(mergeGeneratorImports(mockOutput.imports, recoveredSchemaFactoryImports), finalizeMockOptions.strictSchemaTypeNames), mockRelativeSchemasPath, schemaTagMap) : generateImportsForBuilder(output, filterLocalStrictMockTypeImports(mergeGeneratorImports(mockOutput.imports, recoveredSchemaFactoryImports), finalizeMockOptions.strictSchemaTypeNames).filter((imp) => !!imp.importPath), ".");
6077
6396
  let mockData = header;
6078
- const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, getFinalizeMockImplementationOptions(output, mockOutput)) : mockOutput.implementation;
6079
6397
  mockData += builder.importsMock({
6080
6398
  implementation: finalizedMockImplementation,
6081
6399
  imports: importsMockForBuilder,
@@ -6099,7 +6417,7 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
6099
6417
  if (output.mock.indexMockFiles) {
6100
6418
  const importExtension = getImportExtension(output.fileExtension, output.tsconfig);
6101
6419
  for (const { extension: mockExt, mockDir } of writtenMockEntries) {
6102
- const indexMockPath = nodePath.join(mockDir, `index.${mockExt}${extension}`);
6420
+ const indexMockPath = path.join(mockDir, `index.${mockExt}${extension}`);
6103
6421
  await writeGeneratedFile(indexMockPath, `export * from './${filename}.${mockExt}${importExtension}'\n`);
6104
6422
  extraPaths.push(indexMockPath);
6105
6423
  }
@@ -6113,7 +6431,7 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
6113
6431
  }
6114
6432
  //#endregion
6115
6433
  //#region src/writers/split-mode.ts
6116
- async function writeSplitMode({ builder, output, projectName, header, needSchema, generateSchemasInline }) {
6434
+ async function writeSplitMode({ builder, output, projectName, header, needSchema, generateSchemasInline, schemaTagMap }) {
6117
6435
  try {
6118
6436
  const { path: targetPath, filename, dirname, extension } = getFileInfo(output.target, {
6119
6437
  backupFilename: conventionName(builder.info.title ?? "filename", output.namingConvention),
@@ -6122,10 +6440,10 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
6122
6440
  const { imports, implementation, mockOutputs, mutators, clientMutators, formData, formUrlEncoded, paramsSerializer, paramsFilter, fetchReviver } = generateTarget(builder, output);
6123
6441
  let implementationData = header;
6124
6442
  const schemaCustomImportPath = getSchemasImportPath(output.schemas);
6125
- const relativeSchemasPath = output.schemas ? schemaCustomImportPath ?? getRelativeImportPath(targetPath, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "./" + filename + ".schemas" + extension.replace(/\.ts$/, "");
6126
- const schemasTarget = output.schemas ? getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname : nodePath.join(dirname, filename + ".schemas" + extension.replace(/\.ts$/, ""));
6443
+ const relativeSchemasPath = output.schemas ? schemaCustomImportPath ?? getRelativeImportPath(targetPath, isString(output.schemas) ? output.schemas : output.schemas.path, true) : "./" + filename + ".schemas" + getImportExtension(extension, output.tsconfig);
6444
+ const schemasTarget = output.schemas ? isString(output.schemas) ? output.schemas : output.schemas.path : path.join(dirname, filename + ".schemas" + getImportExtension(extension, output.tsconfig));
6127
6445
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
6128
- const importsForBuilder = generateImportsForBuilder(output, imports, relativeSchemasPath);
6446
+ const importsForBuilder = generateImportsForBuilder(output, imports, relativeSchemasPath, schemaTagMap);
6129
6447
  implementationData += builder.imports({
6130
6448
  client: output.client,
6131
6449
  implementation,
@@ -6139,7 +6457,7 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
6139
6457
  packageJson: output.packageJson,
6140
6458
  output
6141
6459
  });
6142
- const schemasPath = !output.schemas && needSchema ? nodePath.join(dirname, filename + ".schemas" + extension) : void 0;
6460
+ const schemasPath = !output.schemas && needSchema ? path.join(dirname, filename + ".schemas" + extension) : void 0;
6143
6461
  if (schemasPath) await writeGeneratedFile(schemasPath, generateSchemasInline ? header + generateSchemasInline() : header + generateModelsInline(builder.schemas));
6144
6462
  if (mutators) implementationData += generateMutatorImports({
6145
6463
  mutators,
@@ -6161,7 +6479,7 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
6161
6479
  }
6162
6480
  implementationData += `\n${implementation}`;
6163
6481
  const implementationFilename = filename + (OutputClient.ANGULAR === output.client ? ".service" : "") + extension;
6164
- const implementationPath = nodePath.join(dirname, implementationFilename);
6482
+ const implementationPath = path.join(dirname, implementationFilename);
6165
6483
  await writeGeneratedFile(implementationPath, implementationData);
6166
6484
  const mockPaths = [];
6167
6485
  const seenMockIndexKeys = /* @__PURE__ */ new Set();
@@ -6174,11 +6492,13 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
6174
6492
  if (!rawEntry) continue;
6175
6493
  const mockExtension = isFunction(rawEntry) ? OutputMockType.MSW : getMockFileExtensionByTypeName(rawEntry);
6176
6494
  const mockDir = getMockDir(rawEntry, output.mock) ?? dirname;
6177
- const mockFilePath = nodePath.join(mockDir, filename + "." + mockExtension + extension);
6495
+ const mockFilePath = path.join(mockDir, filename + "." + mockExtension + extension);
6178
6496
  const mockRelativeSchemasPath = schemaCustomImportPath ?? resolveMockSchemasPath(mockFilePath, schemasTarget);
6179
- const importsMockForBuilder = generateImportsForBuilder(output, mockOutput.imports, mockRelativeSchemasPath);
6497
+ const finalizeMockOptions = getFinalizeMockImplementationOptions(output, mockOutput);
6498
+ const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, finalizeMockOptions) : mockOutput.implementation;
6499
+ const recoveredSchemaFactoryImports = !isFunction(rawEntry) && rawEntry.type === OutputMockType.FAKER && rawEntry.schemas === true && output.schemas ? collectRecoveredSchemaFactoryImports(finalizedMockImplementation, builder.schemas.filter((s) => s.schema).map((s) => s.name)) : [];
6500
+ const importsMockForBuilder = generateImportsForBuilder(output, filterLocalStrictMockTypeImports(mergeGeneratorImports(mockOutput.imports, recoveredSchemaFactoryImports), finalizeMockOptions.strictSchemaTypeNames), mockRelativeSchemasPath, schemaTagMap);
6180
6501
  let mockData = header;
6181
- const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, getFinalizeMockImplementationOptions(output, mockOutput)) : mockOutput.implementation;
6182
6502
  mockData += builder.importsMock({
6183
6503
  implementation: finalizedMockImplementation,
6184
6504
  imports: importsMockForBuilder,
@@ -6203,7 +6523,7 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
6203
6523
  if (output.mock.indexMockFiles) {
6204
6524
  const importExtension = getImportExtension(output.fileExtension, output.tsconfig);
6205
6525
  for (const { extension: mockExt, mockDir } of writtenMockEntries) {
6206
- const indexMockPath = nodePath.join(mockDir, `index.${mockExt}${extension}`);
6526
+ const indexMockPath = path.join(mockDir, `index.${mockExt}${extension}`);
6207
6527
  await writeGeneratedFile(indexMockPath, `export * from './${filename}.${mockExt}${importExtension}'\n`);
6208
6528
  indexMockPaths.push(indexMockPath);
6209
6529
  }
@@ -6248,7 +6568,8 @@ function flattenMockOutput(full) {
6248
6568
  type: full.type,
6249
6569
  implementation: full.implementation.function + full.implementation.handler,
6250
6570
  imports: full.imports,
6251
- strictMockSchemaTypeNames: full.strictMockSchemaTypeNames
6571
+ strictMockSchemaTypeNames: full.strictMockSchemaTypeNames,
6572
+ strictMockSchemaKinds: full.strictMockSchemaKinds
6252
6573
  };
6253
6574
  }
6254
6575
  function mergeOperationMockOutputs(accMockOutputs, opMockOutputs) {
@@ -6256,7 +6577,8 @@ function mergeOperationMockOutputs(accMockOutputs, opMockOutputs) {
6256
6577
  type: m.type,
6257
6578
  implementation: { ...m.implementation },
6258
6579
  imports: [...m.imports],
6259
- strictMockSchemaTypeNames: m.strictMockSchemaTypeNames ? [...m.strictMockSchemaTypeNames] : void 0
6580
+ strictMockSchemaTypeNames: m.strictMockSchemaTypeNames ? [...m.strictMockSchemaTypeNames] : void 0,
6581
+ strictMockSchemaKinds: m.strictMockSchemaKinds ? { ...m.strictMockSchemaKinds } : void 0
6260
6582
  }));
6261
6583
  for (const op of opMockOutputs) {
6262
6584
  let acc = result.find((m) => m.type === op.type);
@@ -6266,6 +6588,10 @@ function mergeOperationMockOutputs(accMockOutputs, opMockOutputs) {
6266
6588
  }
6267
6589
  acc.imports.push(...op.imports);
6268
6590
  if (op.strictMockSchemaTypeNames?.length) acc.strictMockSchemaTypeNames = [...new Set([...acc.strictMockSchemaTypeNames ?? [], ...op.strictMockSchemaTypeNames])];
6591
+ if (op.strictMockSchemaKinds) acc.strictMockSchemaKinds = {
6592
+ ...acc.strictMockSchemaKinds,
6593
+ ...op.strictMockSchemaKinds
6594
+ };
6269
6595
  acc.implementation.function += op.implementation.function;
6270
6596
  acc.implementation.handler += op.implementation.handler;
6271
6597
  if (op.implementation.handlerName) {
@@ -6284,11 +6610,12 @@ function initialMockOutputsForOperation(op) {
6284
6610
  handlerName: m.implementation.handlerName ? " " + m.implementation.handlerName + "()" : ""
6285
6611
  },
6286
6612
  imports: [...m.imports],
6287
- strictMockSchemaTypeNames: m.strictMockSchemaTypeNames ? [...m.strictMockSchemaTypeNames] : void 0
6613
+ strictMockSchemaTypeNames: m.strictMockSchemaTypeNames ? [...m.strictMockSchemaTypeNames] : void 0,
6614
+ strictMockSchemaKinds: m.strictMockSchemaKinds ? { ...m.strictMockSchemaKinds } : void 0
6288
6615
  }));
6289
6616
  }
6290
6617
  function generateTargetTags(currentAcc, operation) {
6291
- const tag = kebab(operation.tags[0]);
6618
+ const tag = getOperationTagKey(operation);
6292
6619
  if (!(tag in currentAcc)) {
6293
6620
  currentAcc[tag] = {
6294
6621
  imports: operation.imports,
@@ -6329,7 +6656,7 @@ function generateTargetForTags(builder, options) {
6329
6656
  const transformed = {};
6330
6657
  for (const [tag, target] of Object.entries(allTargetTags)) {
6331
6658
  const isMutator = !!target.mutators?.some((mutator) => isAngularClient ? mutator.hasThirdArg : mutator.hasSecondArg);
6332
- const operationNames = Object.values(builder.operations).filter(({ tags }) => tags.map((tag) => kebab(tag)).indexOf(kebab(tag)) === 0).map(({ operationName }) => operationName);
6659
+ const operationNames = operations.filter((operation) => isOperationInTagBucket(operation, tag)).map(({ operationName }) => operationName);
6333
6660
  const hasAwaitedType = compareVersions(options.packageJson?.dependencies?.typescript ?? options.packageJson?.devDependencies?.typescript ?? "4.4.0", "4.5.0");
6334
6661
  const titles = builder.title({
6335
6662
  outputClient: options.client,
@@ -6359,6 +6686,9 @@ function generateTargetForTags(builder, options) {
6359
6686
  isDefaultTagBucket: tag === "default" && Object.values(builder.operations).some((operation) => operation.tags.length === 0),
6360
6687
  clientImplementation: target.implementation
6361
6688
  });
6689
+ const sharedTypes = header.sharedTypes;
6690
+ const deduplicationActive = options.tagsSplitDeduplication && !options.workspace;
6691
+ const inlinedSharedTypes = !deduplicationActive && sharedTypes && sharedTypes.length > 0 ? sharedTypes.map((t) => `${t.exported ? "export " : ""}${t.code}`).join("\n") + "\n\n" : "";
6362
6692
  const wrappedMockOutputs = target.mockOutputs.map((m) => ({
6363
6693
  type: m.type,
6364
6694
  implementation: {
@@ -6367,10 +6697,11 @@ function generateTargetForTags(builder, options) {
6367
6697
  handlerName: m.implementation.handlerName
6368
6698
  },
6369
6699
  imports: m.imports,
6370
- strictMockSchemaTypeNames: m.strictMockSchemaTypeNames
6700
+ strictMockSchemaTypeNames: m.strictMockSchemaTypeNames,
6701
+ strictMockSchemaKinds: m.strictMockSchemaKinds
6371
6702
  }));
6372
6703
  transformed[tag] = {
6373
- implementation: header.implementation + target.implementation + footer.implementation,
6704
+ implementation: inlinedSharedTypes + header.implementation + target.implementation + footer.implementation,
6374
6705
  mockOutputs: wrappedMockOutputs,
6375
6706
  imports: target.imports,
6376
6707
  mutators: target.mutators,
@@ -6379,7 +6710,8 @@ function generateTargetForTags(builder, options) {
6379
6710
  formUrlEncoded: target.formUrlEncoded,
6380
6711
  paramsSerializer: target.paramsSerializer,
6381
6712
  paramsFilter: target.paramsFilter,
6382
- fetchReviver: target.fetchReviver
6713
+ fetchReviver: target.fetchReviver,
6714
+ sharedTypes: deduplicationActive ? sharedTypes : void 0
6383
6715
  };
6384
6716
  }
6385
6717
  allTargetTags = transformed;
@@ -6394,7 +6726,7 @@ function generateTargetForTags(builder, options) {
6394
6726
  }
6395
6727
  //#endregion
6396
6728
  //#region src/writers/split-tags-mode.ts
6397
- async function writeSplitTagsMode({ builder, output, projectName, header, needSchema, generateSchemasInline }) {
6729
+ async function writeSplitTagsMode({ builder, output, projectName, header, needSchema, generateSchemasInline, schemaTagMap }) {
6398
6730
  const { filename, dirname, extension } = getFileInfo(output.target, {
6399
6731
  backupFilename: conventionName(builder.info.title ?? "filename", output.namingConvention),
6400
6732
  extension: output.fileExtension
@@ -6403,33 +6735,51 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
6403
6735
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
6404
6736
  const mockIndexEntries = [];
6405
6737
  const seenMockIndexKeys = /* @__PURE__ */ new Set();
6406
- const schemasTarget = output.schemas ? getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname : nodePath.join(dirname, filename + ".schemas" + extension.replace(/\.ts$/, ""));
6738
+ const schemasTarget = output.schemas ? isString(output.schemas) ? output.schemas : output.schemas.path : path.join(dirname, filename + ".schemas" + getImportExtension(extension, output.tsconfig));
6407
6739
  const tagEntries = Object.entries(target).toSorted(([a], [b]) => a.localeCompare(b));
6740
+ const deduplicationEnabled = output.tagsSplitDeduplication && !output.workspace;
6741
+ const collectedSharedTypes = [];
6742
+ const seenSharedTypeNames = /* @__PURE__ */ new Set();
6743
+ for (const [, target] of tagEntries) {
6744
+ if (!target.sharedTypes) continue;
6745
+ for (const t of target.sharedTypes) if (!seenSharedTypeNames.has(t.name)) {
6746
+ seenSharedTypeNames.add(t.name);
6747
+ collectedSharedTypes.push(t);
6748
+ }
6749
+ }
6750
+ const commonTypesImportExtension = getImportExtension(extension, output.tsconfig);
6751
+ const commonTypesBasename = output.commonTypesFileName;
6752
+ const commonTypesPath = path.join(dirname, commonTypesBasename + extension);
6753
+ const commonTypesRelativeImport = "../" + commonTypesBasename + (deduplicationEnabled ? commonTypesImportExtension : "");
6408
6754
  const generatedFilePathsArray = await Promise.all(tagEntries.map(async ([tag, target]) => {
6409
6755
  try {
6410
6756
  const { imports, implementation, mockOutputs, mutators, clientMutators, formData, fetchReviver, formUrlEncoded, paramsSerializer, paramsFilter } = target;
6411
6757
  let implementationData = header;
6412
- const importerPath = nodePath.join(dirname, tag, tag + extension);
6758
+ if (deduplicationEnabled && target.sharedTypes && target.sharedTypes.length > 0) {
6759
+ const typeNames = target.sharedTypes.map((t) => t.name).join(", ");
6760
+ implementationData += `import type { ${typeNames} } from '${commonTypesRelativeImport}';\n`;
6761
+ }
6762
+ const importerPath = path.join(dirname, tag, tag + extension);
6413
6763
  const schemaCustomImportPath = getSchemasImportPath(output.schemas);
6414
- const relativeSchemasPath = output.schemas ? schemaCustomImportPath ?? getRelativeImportPath(importerPath, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "../" + filename + ".schemas" + extension.replace(/\.ts$/, "");
6764
+ const relativeSchemasPath = output.schemas ? schemaCustomImportPath ?? getRelativeImportPath(importerPath, isString(output.schemas) ? output.schemas : output.schemas.path, true) : "../" + filename + ".schemas" + getImportExtension(extension, output.tsconfig);
6415
6765
  const tagNames = new Set(tagEntries.map(([t]) => t));
6416
6766
  const serviceSuffix = OutputClient.ANGULAR === output.client ? ".service" : "";
6417
6767
  const importsForBuilder = generateImportsForBuilder(output, imports.map((imp) => {
6418
6768
  if (!imp.importPath) return imp;
6419
6769
  if (!imp.importPath.startsWith(".")) return imp;
6420
- const resolvedPath = nodePath.resolve(dirname, imp.importPath);
6421
- const targetBasename = nodePath.basename(resolvedPath);
6770
+ const resolvedPath = path.resolve(dirname, imp.importPath);
6771
+ const targetBasename = path.basename(resolvedPath);
6422
6772
  let targetFile;
6423
6773
  if (tagNames.has(targetBasename)) {
6424
6774
  const tagFilename = targetBasename + serviceSuffix + extension;
6425
- targetFile = nodePath.join(resolvedPath, tagFilename);
6775
+ targetFile = path.join(resolvedPath, tagFilename);
6426
6776
  } else targetFile = resolvedPath + extension;
6427
6777
  const adjustedPath = getRelativeImportPath(importerPath, targetFile);
6428
6778
  return {
6429
6779
  ...imp,
6430
6780
  importPath: adjustedPath
6431
6781
  };
6432
- }), relativeSchemasPath);
6782
+ }), relativeSchemasPath, schemaTagMap);
6433
6783
  implementationData += builder.imports({
6434
6784
  client: output.client,
6435
6785
  implementation,
@@ -6443,7 +6793,7 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
6443
6793
  packageJson: output.packageJson,
6444
6794
  output
6445
6795
  });
6446
- const schemasPath = !output.schemas && needSchema ? nodePath.join(dirname, filename + ".schemas" + extension) : void 0;
6796
+ const schemasPath = !output.schemas && needSchema ? path.join(dirname, filename + ".schemas" + extension) : void 0;
6447
6797
  if (schemasPath) await writeGeneratedFile(schemasPath, generateSchemasInline ? header + generateSchemasInline() : header + generateModelsInline(builder.schemas));
6448
6798
  if (mutators) implementationData += generateMutatorImports({
6449
6799
  mutators,
@@ -6484,7 +6834,7 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
6484
6834
  }
6485
6835
  implementationData += `\n${implementation}`;
6486
6836
  const implementationFilename = tag + (OutputClient.ANGULAR === output.client ? ".service" : "") + extension;
6487
- const implementationPath = nodePath.join(dirname, tag, implementationFilename);
6837
+ const implementationPath = path.join(dirname, tag, implementationFilename);
6488
6838
  await writeGeneratedFile(implementationPath, implementationData);
6489
6839
  const mockPaths = [];
6490
6840
  for (const mockOutput of mockOutputs) {
@@ -6495,10 +6845,12 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
6495
6845
  if (!rawEntry) continue;
6496
6846
  const mockExtension = isFunction(rawEntry) ? OutputMockType.MSW : getMockFileExtensionByTypeName(rawEntry);
6497
6847
  const mockDir = getMockDir(rawEntry, output.mock) ?? dirname;
6498
- const mockFilePath = nodePath.join(mockDir, tag, tag + "." + mockExtension + extension);
6848
+ const mockFilePath = path.join(mockDir, tag, tag + "." + mockExtension + extension);
6499
6849
  const mockRelativeSchemasPath = schemaCustomImportPath ?? resolveMockSchemasPath(mockFilePath, schemasTarget);
6500
- const importsMockForBuilder = generateImportsForBuilder(output, mockOutput.imports, mockRelativeSchemasPath);
6501
- const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, getFinalizeMockImplementationOptions(output, mockOutput)) : mockOutput.implementation;
6850
+ const finalizeMockOptions = getFinalizeMockImplementationOptions(output, mockOutput);
6851
+ const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, finalizeMockOptions) : mockOutput.implementation;
6852
+ const recoveredSchemaFactoryImports = !isFunction(rawEntry) && rawEntry.type === OutputMockType.FAKER && rawEntry.schemas === true && output.schemas ? collectRecoveredSchemaFactoryImports(finalizedMockImplementation, builder.schemas.filter((s) => s.schema).map((s) => s.name)) : [];
6853
+ const importsMockForBuilder = generateImportsForBuilder(output, filterLocalStrictMockTypeImports(mergeGeneratorImports(mockOutput.imports, recoveredSchemaFactoryImports), finalizeMockOptions.strictSchemaTypeNames), mockRelativeSchemasPath, schemaTagMap);
6502
6854
  let mockData = header;
6503
6855
  mockData += builder.importsMock({
6504
6856
  implementation: finalizedMockImplementation,
@@ -6533,15 +6885,40 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
6533
6885
  throw new Error(`Oups... 🍻. An Error occurred while splitting tag ${tag} => ${String(error)}`, { cause: error });
6534
6886
  }
6535
6887
  }));
6536
- if (output.mock.indexMockFiles) for (const { ext, mockDir, tags } of mockIndexEntries) await writeGeneratedFile(nodePath.join(mockDir, `index.${ext}${extension}`), tags.toSorted((a, b) => a.localeCompare(b)).map((tag) => {
6537
- const localMockPath = joinSafe("./", tag, tag + "." + ext);
6538
- return ext === OutputMockType.MSW ? `export { get${pascal(tag)}Mock } from '${localMockPath}'\n` : `export * from '${localMockPath}'\n`;
6539
- }).join(""));
6540
- return [...new Set([...output.mock.indexMockFiles ? mockIndexEntries.map(({ mockDir, ext }) => nodePath.join(mockDir, `index.${ext}${extension}`)) : [], ...generatedFilePathsArray.flat()])];
6888
+ if (output.mock.indexMockFiles) {
6889
+ const mockImportExtension = getImportExtension(extension, output.tsconfig);
6890
+ for (const { ext, mockDir, tags } of mockIndexEntries) await writeGeneratedFile(path.join(mockDir, `index.${ext}${extension}`), tags.toSorted((a, b) => a.localeCompare(b)).map((tag) => {
6891
+ const localMockPath = joinSafe("./", tag, tag + "." + ext + mockImportExtension);
6892
+ return ext === OutputMockType.MSW ? `export { get${pascal(tag)}Mock } from '${localMockPath}'\n` : `export * from '${localMockPath}'\n`;
6893
+ }).join(""));
6894
+ }
6895
+ let commonTypesFilePath;
6896
+ if (deduplicationEnabled && collectedSharedTypes.length > 0) {
6897
+ const commonTypesContent = collectedSharedTypes.map((t) => `export ${t.code}`).join("\n") + "\n";
6898
+ commonTypesFilePath = commonTypesPath;
6899
+ await writeGeneratedFile(commonTypesPath, commonTypesContent);
6900
+ }
6901
+ let indexFilePath;
6902
+ if (output.indexFiles && deduplicationEnabled && tagEntries.length > 0) {
6903
+ const importExtension = getImportExtension(output.fileExtension, output.tsconfig);
6904
+ const serviceSuffix = OutputClient.ANGULAR === output.client ? ".service" : "";
6905
+ const publicSharedTypeNames = collectedSharedTypes.filter((t) => t.exported).map((t) => t.name);
6906
+ const indexContent = (publicSharedTypeNames.length > 0 ? `export type { ${publicSharedTypeNames.join(", ")} } from './${commonTypesBasename}${importExtension}';\n` : "") + tagEntries.map(([tag]) => {
6907
+ return `export * from '${joinSafe("./", tag, tag + serviceSuffix + importExtension)}';\n`;
6908
+ }).join("");
6909
+ indexFilePath = path.join(dirname, `index${extension}`);
6910
+ await writeGeneratedFile(indexFilePath, indexContent);
6911
+ }
6912
+ return [...new Set([
6913
+ ...output.mock.indexMockFiles ? mockIndexEntries.map(({ mockDir, ext }) => path.join(mockDir, `index.${ext}${extension}`)) : [],
6914
+ ...commonTypesFilePath ? [commonTypesFilePath] : [],
6915
+ ...indexFilePath ? [indexFilePath] : [],
6916
+ ...generatedFilePathsArray.flat()
6917
+ ])];
6541
6918
  }
6542
6919
  //#endregion
6543
6920
  //#region src/writers/tags-mode.ts
6544
- async function writeTagsMode({ builder, output, projectName, header, needSchema, generateSchemasInline }) {
6921
+ async function writeTagsMode({ builder, output, projectName, header, needSchema, generateSchemasInline, schemaTagMap }) {
6545
6922
  const { path: targetPath, filename, dirname, extension } = getFileInfo(output.target, {
6546
6923
  backupFilename: conventionName(builder.info.title ?? "filename", output.namingConvention),
6547
6924
  extension: output.fileExtension
@@ -6552,8 +6929,8 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema,
6552
6929
  const mockIndexEntries = [];
6553
6930
  const seenMockIndexKeys = /* @__PURE__ */ new Set();
6554
6931
  const schemaCustomImportPath = getSchemasImportPath(output.schemas);
6555
- const schemasPathRelative = output.schemas ? schemaCustomImportPath ?? getRelativeImportPath(targetPath, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "./" + filename + ".schemas" + extension.replace(/\.ts$/, "");
6556
- const schemasTarget = output.schemas ? getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname : nodePath.join(dirname, filename + ".schemas" + extension.replace(/\.ts$/, ""));
6932
+ const schemasPathRelative = output.schemas ? schemaCustomImportPath ?? getRelativeImportPath(targetPath, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "./" + filename + ".schemas" + getImportExtension(extension, output.tsconfig);
6933
+ const schemasTarget = output.schemas ? getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname : path.join(dirname, filename + ".schemas" + getImportExtension(extension, output.tsconfig));
6557
6934
  const tagEntries = Object.entries(target).toSorted(([a], [b]) => a.localeCompare(b));
6558
6935
  const generatedFilePathsArray = await Promise.all(tagEntries.map(async ([tag, target]) => {
6559
6936
  try {
@@ -6573,7 +6950,7 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema,
6573
6950
  if (!!mockImport.values || !!mockImport.isConstant || !!mockImport.default || !!mockImport.namespaceImport || !!mockImport.syntheticDefaultImport) matchingImport.values = true;
6574
6951
  }
6575
6952
  }
6576
- const importsForBuilder = generateImportsForBuilder(output, normalizedImports, schemasPathRelative);
6953
+ const importsForBuilder = generateImportsForBuilder(output, normalizedImports, schemasPathRelative, schemaTagMap);
6577
6954
  data += builder.imports({
6578
6955
  client: output.client,
6579
6956
  implementation,
@@ -6589,7 +6966,7 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema,
6589
6966
  });
6590
6967
  if (!shouldDeinlineMocks) for (const mockOutput of collapsedMockOutputs) {
6591
6968
  const entry = output.mock.generators.find((g) => !isFunction(g) && g.type === mockOutput.type);
6592
- const importsMockForBuilder = generateImportsForBuilder(output, mockOutput.imports.filter((impMock) => !normalizedImports.some((imp) => imp.name === impMock.name && (imp.alias ?? "") === (impMock.alias ?? ""))), schemasPathRelative);
6969
+ const importsMockForBuilder = generateImportsForBuilder(output, mockOutput.imports.filter((impMock) => !normalizedImports.some((imp) => imp.name === impMock.name && (imp.alias ?? "") === (impMock.alias ?? ""))), schemasPathRelative, schemaTagMap);
6593
6970
  data += builder.importsMock({
6594
6971
  implementation: mockOutput.implementation,
6595
6972
  imports: importsMockForBuilder,
@@ -6599,7 +6976,7 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema,
6599
6976
  options: entry && !isFunction(entry) ? entry : void 0
6600
6977
  });
6601
6978
  }
6602
- const schemasPath = !output.schemas && needSchema ? nodePath.join(dirname, filename + ".schemas" + extension) : void 0;
6979
+ const schemasPath = !output.schemas && needSchema ? path.join(dirname, filename + ".schemas" + extension) : void 0;
6603
6980
  if (schemasPath) await writeGeneratedFile(schemasPath, generateSchemasInline ? header + generateSchemasInline() : header + generateModelsInline(builder.schemas));
6604
6981
  if (mutators) data += generateMutatorImports({
6605
6982
  mutators,
@@ -6630,7 +7007,7 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema,
6630
7007
  }
6631
7008
  }
6632
7009
  const kebabTag = kebab(tag);
6633
- const implementationPath = nodePath.join(dirname, `${kebabTag}${extension}`);
7010
+ const implementationPath = path.join(dirname, `${kebabTag}${extension}`);
6634
7011
  await writeGeneratedFile(implementationPath, data);
6635
7012
  const extraPaths = [];
6636
7013
  if (shouldDeinlineMocks) for (const mockOutput of rawMockOutputs) {
@@ -6641,11 +7018,13 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema,
6641
7018
  if (!rawEntry) continue;
6642
7019
  const mockExtension = isFunction(rawEntry) ? OutputMockType.MSW : getMockFileExtensionByTypeName(rawEntry);
6643
7020
  const mockDir = getMockDir(rawEntry, output.mock) ?? dirname;
6644
- const mockFilePath = nodePath.join(mockDir, kebabTag, kebabTag + "." + mockExtension + extension);
7021
+ const mockFilePath = path.join(mockDir, kebabTag, kebabTag + "." + mockExtension + extension);
6645
7022
  const mockRelativeSchemasPath = schemaCustomImportPath ?? resolveMockSchemasPath(mockFilePath, schemasTarget);
6646
- const importsMockForBuilder = generateImportsForBuilder(output, mockOutput.imports, mockRelativeSchemasPath);
7023
+ const finalizeMockOptions = getFinalizeMockImplementationOptions(output, mockOutput);
7024
+ const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, finalizeMockOptions) : mockOutput.implementation;
7025
+ const recoveredSchemaFactoryImports = !isFunction(rawEntry) && rawEntry.type === OutputMockType.FAKER && rawEntry.schemas === true && output.schemas ? collectRecoveredSchemaFactoryImports(finalizedMockImplementation, builder.schemas.filter((s) => s.schema).map((s) => s.name)) : [];
7026
+ const importsMockForBuilder = generateImportsForBuilder(output, filterLocalStrictMockTypeImports(mergeGeneratorImports(mockOutput.imports, recoveredSchemaFactoryImports), finalizeMockOptions.strictSchemaTypeNames), mockRelativeSchemasPath, schemaTagMap);
6647
7027
  let mockData = header;
6648
- const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, getFinalizeMockImplementationOptions(output, mockOutput)) : mockOutput.implementation;
6649
7028
  mockData += builder.importsMock({
6650
7029
  implementation: finalizedMockImplementation,
6651
7030
  imports: importsMockForBuilder,
@@ -6679,17 +7058,20 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema,
6679
7058
  throw new Error(`Oups... 🍻. An Error occurred while writing tag ${tag} => ${String(error)}`, { cause: error });
6680
7059
  }
6681
7060
  }));
6682
- if (shouldDeinlineMocks && output.mock.indexMockFiles) for (const { ext, mockDir, tags } of mockIndexEntries) {
6683
- const indexPath = nodePath.join(mockDir, `index.${ext}${extension}`);
6684
- await writeGeneratedFile(indexPath, tags.toSorted((a, b) => a.localeCompare(b)).map((kebabTag) => {
6685
- const localMockPath = joinSafe("./", kebabTag, kebabTag + "." + ext);
6686
- return ext === OutputMockType.MSW ? `export { get${pascal(kebabTag)}Mock } from '${localMockPath}'\n` : `export * from '${localMockPath}'\n`;
6687
- }).join(""));
6688
- generatedFilePathsArray.push([indexPath]);
7061
+ if (shouldDeinlineMocks && output.mock.indexMockFiles) {
7062
+ const mockImportExtension = getImportExtension(extension, output.tsconfig);
7063
+ for (const { ext, mockDir, tags } of mockIndexEntries) {
7064
+ const indexPath = path.join(mockDir, `index.${ext}${extension}`);
7065
+ await writeGeneratedFile(indexPath, tags.toSorted((a, b) => a.localeCompare(b)).map((kebabTag) => {
7066
+ const localMockPath = joinSafe("./", kebabTag, kebabTag + "." + ext + mockImportExtension);
7067
+ return ext === OutputMockType.MSW ? `export { get${pascal(kebabTag)}Mock } from '${localMockPath}'\n` : `export * from '${localMockPath}'\n`;
7068
+ }).join(""));
7069
+ generatedFilePathsArray.push([indexPath]);
7070
+ }
6689
7071
  }
6690
7072
  return generatedFilePathsArray.flat();
6691
7073
  }
6692
7074
  //#endregion
6693
- export { BODY_TYPE_NAME, DefaultTag, EnumGeneration, ErrorWithTag, FormDataArrayHandling, GetterPropType, LogLevels, NAMED_COMPONENT_SECTIONS, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SchemaType, SupportedFormatter, TEMPLATE_TAG_REGEX, URL_REGEX, VERBS_WITH_BODY, Verbs, addDependency, asyncReduce, buildAngularParamsFilterExpression, buildDynamicScope, camel, collectReferencedComponents, combineSchemas, compareVersions, conventionName, count, createDebugger, createLogger, createSuccessMessage, createTypeAliasIfNeeded, dedupeUnionType, dynamicAnchorToParamName, dynamicAnchorsToUniqueParamNames, dynamicImport, escape, escapeRegExp, extractBoundAliasInfo, filterByContentType, filteredVerbs, fixCrossDirectoryImports, fixRegularSchemaImports, generalJSTypes, generalJSTypesWithArray, generateAxiosOptions, generateBodyMutatorConfig, generateBodyOptions, generateComponentDefinition, generateDependencyImports, generateFactory, generateFormDataAndUrlEncodedFunction, generateImports, generateModelInline, generateModelsInline, generateMutator, generateMutatorConfig, generateMutatorImports, generateMutatorRequestOptions, generateOptions, generateParameterDefinition, generateQueryParamsAxiosConfig, generateSchemasDefinition, generateTarget, generateTargetForTags, generateVerbImports, generateVerbOptions, generateVerbsOptions, getAngularFilteredParamsCallExpression, getAngularFilteredParamsExpression, getAngularFilteredParamsHelperBody, getArray, getBaseUrlRuntimeImports, getBodiesByContentType, getBody, getCombinedEnumValue, getDefaultContentType, getDynamicAnchorName, getEnum, getEnumDescriptions, getEnumImplementation, getEnumNames, getEnumUnionFromSchema, getExtension, getFileInfo, getFormDataFieldFileType, getFullRoute, getImportExtension, getIsBodyVerb, getKey, getMockFileExtensionByTypeName, getNumberWord, getObject, getOperationId, getOrvalGeneratedTypes, getParameters, getParams, getParamsInPath, getPropertySafe, getProps, getQueryParams, getRefInfo, getResReqTypes, getResponse, getResponseTypeCategory, getRoute, getRouteAsArray, getScalar, getSchemasImportPath, getSuccessResponseType, getTypedResponse, getWarningCount, isBinaryContentType, isBinaryScalarSchema, isBoolean, isComponentRef, isDirectory, isDynamicReference, isFakerMock, isFunction, isModule, isMswMock, isNullish, isNumber, isNumeric, isObject, isReference, isSchema, isString, isStringLike, isSyntheticDefaultImportsAllow, isUrl, isVerb, isVerbose, jsDoc, jsStringEscape, jsStringLiteralEscape, kebab, keyValuePairsToJsDoc, log, logError, logVerbose, logWarning, makeRouteSafe, mergeDeep, mismatchArgsMessage, pascal, removeFilesAndEmptyFolders, resetWarnings, resolveDiscriminators, resolveDynamicRef, resolveExampleRefs, resolveInstalledVersion, resolveInstalledVersions, resolveObject, resolveRef, resolveValue, sanitize, setVerbose, snake, sortByPriority, splitSchemasByType, startMessage, stringify, toObjectString, path_exports as upath, upper, wrapRouteParameters, writeGeneratedFile, writeModelInline, writeModelsInline, writeSchema, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode };
7075
+ export { BODY_TYPE_NAME, DefaultTag, EnumGeneration, ErrorWithTag, FormDataArrayHandling, GetterPropType, LogLevels, NAMED_COMPONENT_SECTIONS, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SHARED_DIR, SchemaType, SupportedFormatter, TEMPLATE_TAG_REGEX, URL_REGEX, VERBS_WITH_BODY, Verbs, addDependency, asyncReduce, buildAngularParamsFilterExpression, buildDynamicScope, buildInlineDynamicScope, buildSchemaTagMap, camel, collectReferencedComponents, combineSchemas, compareVersions, conventionName, count, createDebugger, createLogger, createSuccessMessage, createTypeAliasIfNeeded, dedupeUnionType, dynamicAnchorToParamName, dynamicAnchorsToUniqueParamNames, dynamicImport, escape, escapeRegExp, extractBoundAliasInfo, filterByContentType, filteredVerbs, fixCrossDirectoryImports, fixRegularSchemaImports, generalJSTypes, generalJSTypesWithArray, generateAxiosOptions, generateBodyMutatorConfig, generateBodyOptions, generateComponentDefinition, generateDependencyImports, generateFactory, generateFormDataAndUrlEncodedFunction, generateImports, generateModelInline, generateModelsInline, generateMutator, generateMutatorConfig, generateMutatorImports, generateMutatorRequestOptions, generateOptions, generateParameterDefinition, generateQueryParamsAxiosConfig, generateSchemasDefinition, generateTarget, generateTargetForTags, generateVerbImports, generateVerbOptions, generateVerbsOptions, getAngularFilteredParamsCallExpression, getAngularFilteredParamsExpression, getAngularFilteredParamsHelperBody, getArray, getBaseUrlRuntimeImports, getBodiesByContentType, getBody, getCombinedEnumValue, getDefaultContentType, getDynamicAnchorName, getEnum, getEnumDescriptions, getEnumImplementation, getEnumNames, getEnumUnionFromSchema, getExtension, getFileInfo, getFormDataFieldFileType, getFullRoute, getImportExtension, getIsBodyVerb, getKey, getMockFileExtensionByTypeName, getNumberWord, getObject, getOperationId, getOperationTagKey, getOrvalGeneratedTypes, getParameters, getParams, getParamsInPath, getPropertySafe, getProps, getQueryParams, getRefInfo, getResReqTypes, getResponse, getResponseTypeCategory, getRoute, getRouteAsArray, getScalar, getSchemasImportPath, getSuccessResponseType, getTagKey, getTypedResponse, getWarningCount, isBinaryContentType, isBinaryScalarSchema, isBoolean, isComponentRef, isDirectory, isDynamicReference, isFakerMock, isFunction, isModule, isMswMock, isNullish, isNumber, isNumeric, isObject, isOperationInTagBucket, isReference, isSchema, isString, isStringLike, isSyntheticDefaultImportsAllow, isUrl, isVerb, isVerbose, jsDoc, jsStringEscape, jsStringLiteralEscape, kebab, keyValuePairsToJsDoc, log, logError, logVerbose, logWarning, makeRouteSafe, mergeDeep, mismatchArgsMessage, pascal, removeFilesAndEmptyFolders, resetWarnings, resolveDiscriminators, resolveDynamicRef, resolveExampleRefs, resolveInstalledVersion, resolveInstalledVersions, resolveObject, resolveRef, resolveValue, sanitize, setVerbose, snake, sortByPriority, splitSchemasByType, startMessage, stringify, toObjectString, path_exports as upath, upper, wrapRouteParameters, writeGeneratedFile, writeModelInline, writeModelsInline, writeSchema, writeSchemas, writeSchemasTagsSplit, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode };
6694
7076
 
6695
7077
  //# sourceMappingURL=index.mjs.map