@orval/core 8.16.0 → 8.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -395,27 +395,31 @@ interface CommonMockOptions {
395
395
  generateEachHttpStatus?: boolean;
396
396
  locale?: keyof typeof allLocales;
397
397
  preferredContentType?: string;
398
+ arrayItems?: boolean;
398
399
  }
399
400
  interface MswMockOptions extends CommonMockOptions {
400
401
  type: typeof OutputMockType.MSW;
401
402
  baseUrl?: string;
402
403
  delay?: false | number | (() => number);
403
404
  delayFunctionLazyExecute?: boolean;
405
+ path?: string;
404
406
  }
405
407
  interface FakerMockOptions extends CommonMockOptions {
406
408
  type: typeof OutputMockType.FAKER;
407
409
  schemas?: boolean;
408
410
  operationResponses?: boolean;
409
- arrayItems?: boolean;
411
+ path?: string;
410
412
  }
411
413
  type GlobalMockOptions = MswMockOptions | FakerMockOptions;
412
414
  interface OutputMocksConfig {
413
415
  indexMockFiles?: boolean;
416
+ path?: string;
414
417
  generators: (GlobalMockOptions | ClientMockBuilder)[];
415
418
  }
416
419
  type OutputMocksOption = boolean | OutputMocksConfig | ClientMockBuilder;
417
420
  interface NormalizedMocksConfig {
418
421
  indexMockFiles: boolean;
422
+ path?: string;
419
423
  generators: (GlobalMockOptions | ClientMockBuilder)[];
420
424
  }
421
425
  type OverrideMockOptions = Partial<GlobalMockOptions> & {
@@ -953,9 +957,16 @@ interface ContextSpec {
953
957
  * Tracks array-item mock factory names already emitted per output file scope.
954
958
  * Populated by `@orval/mock` when `arrayItems: true` so shared `$ref` item
955
959
  * factories are not re-declared within the same file (single/split) or tag
956
- * bucket (tags/tags-split).
960
+ * bucket (tags/tags-split). Scope keys include the active mock generator
961
+ * type so separate `.msw.ts` / `.faker.ts` files each get their own copy.
957
962
  */
958
963
  arrayItemMockFactories?: Map<string, Set<string>>;
964
+ /**
965
+ * Set by `@orval/mock` while generating per-operation mock output so
966
+ * file-scoped helpers (e.g. array-item factory dedup) can distinguish
967
+ * separate mock generator files.
968
+ */
969
+ activeMockOutputType?: OutputMockType;
959
970
  }
960
971
  /**
961
972
  * Maps a `$dynamicAnchor` name to its resolution target.
package/dist/index.mjs CHANGED
@@ -1320,7 +1320,7 @@ const getUnion = (value, enumName) => {
1320
1320
  };
1321
1321
  function getEnumUnionFromSchema(schema) {
1322
1322
  if (!schema?.enum) return "";
1323
- return schema.enum.filter((val) => val !== null).map((val) => isString(val) ? `'${escape(val)}'` : String(val)).join(" | ");
1323
+ return schema.enum.filter((val) => val !== null).map((val) => isString(val) ? `'${jsStringLiteralEscape(val)}'` : String(val)).join(" | ");
1324
1324
  }
1325
1325
  const stripNullUnion = (value) => value.replaceAll(/\s*\|\s*null/g, "").trim();
1326
1326
  const isSpreadableEnumRef = (schema, refName) => {
@@ -1707,13 +1707,13 @@ function getPropertyNamesEnumKeyType(item) {
1707
1707
  if (Array.isArray(propertyNames.enum)) {
1708
1708
  const enumValues = propertyNames.enum.filter((val) => isString(val));
1709
1709
  if (enumValues.length > 0) return {
1710
- value: enumValues.map((val) => `'${escape(val)}'`).join(" | "),
1710
+ value: enumValues.map((val) => `'${jsStringLiteralEscape(val)}'`).join(" | "),
1711
1711
  imports: [],
1712
1712
  dependencies: []
1713
1713
  };
1714
1714
  }
1715
1715
  if (isString(propertyNames.const)) return {
1716
- value: `'${escape(propertyNames.const)}'`,
1716
+ value: `'${jsStringLiteralEscape(propertyNames.const)}'`,
1717
1717
  imports: [],
1718
1718
  dependencies: []
1719
1719
  };
@@ -1878,7 +1878,7 @@ function getObject({ item, name, context, nullable, formDataContext }) {
1878
1878
  const hasConst = constValue !== void 0;
1879
1879
  let constLiteral;
1880
1880
  if (!hasConst) constLiteral = void 0;
1881
- else if (isString(constValue)) constLiteral = `'${escape(constValue)}'`;
1881
+ else if (isString(constValue)) constLiteral = `'${jsStringLiteralEscape(constValue)}'`;
1882
1882
  else constLiteral = JSON.stringify(constValue);
1883
1883
  const needsValueImport = hasConst && (resolvedValue.isEnum || resolvedValue.type === "enum");
1884
1884
  const usedResolvedValue = !hasConst || needsValueImport;
@@ -2011,7 +2011,7 @@ function getObject({ item, name, context, nullable, formDataContext }) {
2011
2011
  else if (typeof constValue === "boolean") type = "boolean";
2012
2012
  else type = "object";
2013
2013
  return {
2014
- value: typeof constValue === "string" ? `'${escape(constValue)}'` : JSON.stringify(constValue),
2014
+ value: typeof constValue === "string" ? `'${jsStringLiteralEscape(constValue)}'` : JSON.stringify(constValue),
2015
2015
  imports: [],
2016
2016
  schemas: [],
2017
2017
  isEnum: false,
@@ -2152,7 +2152,7 @@ function getScalar({ item, name, context, formDataContext }) {
2152
2152
  let value = "string";
2153
2153
  let isEnum = false;
2154
2154
  if (enumItems) {
2155
- value = enumItems.map((enumItem) => isString(enumItem) ? `'${escape(enumItem)}'` : `${enumItem}`).filter(Boolean).join(` | `);
2155
+ value = enumItems.map((enumItem) => isString(enumItem) ? `'${jsStringLiteralEscape(enumItem)}'` : `${enumItem}`).filter(Boolean).join(` | `);
2156
2156
  isEnum = true;
2157
2157
  }
2158
2158
  if (!formDataContext?.urlEncoded) {
@@ -2164,7 +2164,7 @@ function getScalar({ item, name, context, formDataContext }) {
2164
2164
  }
2165
2165
  if (context.output.override.useDates && (schemaFormat === "date" || schemaFormat === "date-time")) value = "Date";
2166
2166
  value += nullable;
2167
- if (schemaConst) value = `'${schemaConst}'`;
2167
+ if (schemaConst) value = `'${jsStringLiteralEscape(schemaConst)}'`;
2168
2168
  return {
2169
2169
  value,
2170
2170
  isEnum,
@@ -2214,7 +2214,7 @@ function getScalar({ item, name, context, formDataContext }) {
2214
2214
  nullable
2215
2215
  });
2216
2216
  if (enumItems) return {
2217
- value: enumItems.map((enumItem) => isString(enumItem) ? `'${escape(enumItem)}'` : String(enumItem)).filter(Boolean).join(` | `) + nullable,
2217
+ value: enumItems.map((enumItem) => isString(enumItem) ? `'${jsStringLiteralEscape(enumItem)}'` : String(enumItem)).filter(Boolean).join(` | `) + nullable,
2218
2218
  isEnum: true,
2219
2219
  type: "string",
2220
2220
  imports: [],
@@ -4457,8 +4457,9 @@ function findRefs(value) {
4457
4457
  if (!value || typeof value !== "object") return [];
4458
4458
  if (Array.isArray(value)) return value.flatMap((item) => findRefs(item));
4459
4459
  const obj = value;
4460
- if (typeof obj.$ref === "string") return [obj.$ref];
4461
- return Object.values(obj).flatMap((val) => findRefs(val));
4460
+ const refs = [];
4461
+ if (typeof obj.$ref === "string") refs.push(obj.$ref);
4462
+ return refs.concat(Object.values(obj).flatMap((val) => findRefs(val)));
4462
4463
  }
4463
4464
  function parseComponentRef(ref) {
4464
4465
  const parts = ref.split("/");
@@ -5811,6 +5812,21 @@ function collapseInlineMockOutputs(mockOutputs) {
5811
5812
  return mockOutputs.filter((m) => m.type !== OutputMockType.FAKER);
5812
5813
  }
5813
5814
  //#endregion
5815
+ //#region src/writers/mock-utils.ts
5816
+ function getMockDir(entry, mockConfig) {
5817
+ if (!isFunction(entry) && entry.path) return entry.path;
5818
+ return mockConfig.path;
5819
+ }
5820
+ function hasAnyMockPath(mockConfig) {
5821
+ if (mockConfig.path) return true;
5822
+ return mockConfig.generators.some((g) => !isFunction(g) && !!g.path);
5823
+ }
5824
+ function resolveMockSchemasPath(mockFilePath, schemasTarget) {
5825
+ const ext = nodePath.extname(mockFilePath);
5826
+ const targetExt = nodePath.extname(schemasTarget);
5827
+ return getRelativeImportPath(mockFilePath, targetExt === ".schemas" ? schemasTarget + ext : targetExt ? schemasTarget : schemasTarget + ext);
5828
+ }
5829
+ //#endregion
5814
5830
  //#region src/writers/target.ts
5815
5831
  function emptyMockOutputFull$1(type) {
5816
5832
  return {
@@ -5961,30 +5977,33 @@ interface TypedResponse<T> extends Response {
5961
5977
  //#region src/writers/single-mode.ts
5962
5978
  async function writeSingleMode({ builder, output, projectName, header, needSchema, generateSchemasInline }) {
5963
5979
  try {
5964
- const { path } = getFileInfo(output.target, {
5980
+ const { path: targetPath, filename, dirname, extension } = getFileInfo(output.target, {
5965
5981
  backupFilename: conventionName(builder.info.title ?? "filename", output.namingConvention),
5966
5982
  extension: output.fileExtension
5967
5983
  });
5968
5984
  const { imports, mockOutputs: rawMockOutputs, implementation, mutators, clientMutators, formData, formUrlEncoded, paramsSerializer, paramsFilter, fetchReviver } = generateTarget(builder, output);
5969
- const mockOutputs = collapseInlineMockOutputs(rawMockOutputs);
5970
- const implementationMock = mockOutputs.map((m) => m.implementation).join("\n\n");
5971
- const finalizedImplementationMock = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(implementationMock, getFinalizeMockImplementationOptions(output, mockOutputs)) : implementationMock;
5972
- const importsMock = mockOutputs.flatMap((m) => m.imports);
5973
- let data = header;
5974
- const schemaCustomImportPath = getSchemasImportPath(output.schemas);
5975
- const schemasPath = output.schemas ? schemaCustomImportPath ?? getRelativeImportPath(path, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : void 0;
5976
5985
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
5986
+ const shouldDeinlineMocks = hasAnyMockPath(output.mock);
5987
+ const schemaCustomImportPath = getSchemasImportPath(output.schemas);
5988
+ const schemasPath = output.schemas ? schemaCustomImportPath ?? getRelativeImportPath(targetPath, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : void 0;
5989
+ const relativeSchemasPath = schemasPath ?? "./" + filename + ".schemas" + extension.replace(/\.ts$/, "");
5990
+ const schemasTarget = output.schemas ? getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname : targetPath;
5977
5991
  const normalizedImports = imports.filter((imp) => {
5978
5992
  const searchWords = [imp.alias, imp.name].filter((part) => Boolean(part?.length)).map((part) => escapeRegExp(part)).join("|");
5979
5993
  if (!searchWords) return false;
5980
5994
  return new RegExp(String.raw`\b(${searchWords})\b`, "g").test(implementation);
5981
5995
  }).map((imp) => ({ ...imp }));
5982
- for (const mockImport of importsMock) {
5983
- const matchingImport = normalizedImports.find((imp) => imp.name === mockImport.name && (imp.alias ?? "") === (mockImport.alias ?? ""));
5984
- if (!matchingImport) continue;
5985
- if (!!mockImport.values || !!mockImport.isConstant || !!mockImport.default || !!mockImport.namespaceImport || !!mockImport.syntheticDefaultImport) matchingImport.values = true;
5996
+ const collapsedMockOutputs = shouldDeinlineMocks ? [] : collapseInlineMockOutputs(rawMockOutputs);
5997
+ if (!shouldDeinlineMocks) {
5998
+ const importsMock = collapsedMockOutputs.flatMap((m) => m.imports);
5999
+ for (const mockImport of importsMock) {
6000
+ const matchingImport = normalizedImports.find((imp) => imp.name === mockImport.name && (imp.alias ?? "") === (mockImport.alias ?? ""));
6001
+ if (!matchingImport) continue;
6002
+ if (!!mockImport.values || !!mockImport.isConstant || !!mockImport.default || !!mockImport.namespaceImport || !!mockImport.syntheticDefaultImport) matchingImport.values = true;
6003
+ }
5986
6004
  }
5987
- const importsForBuilder = schemasPath ? generateImportsForBuilder(output, normalizedImports, schemasPath) : generateImportsForBuilder(output, normalizedImports.filter((imp) => !!imp.importPath), ".");
6005
+ let data = header;
6006
+ const importsForBuilder = schemasPath ? generateImportsForBuilder(output, normalizedImports, relativeSchemasPath) : generateImportsForBuilder(output, normalizedImports.filter((imp) => !!imp.importPath), ".");
5988
6007
  data += builder.imports({
5989
6008
  client: output.client,
5990
6009
  implementation,
@@ -5998,10 +6017,10 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
5998
6017
  packageJson: output.packageJson,
5999
6018
  output
6000
6019
  });
6001
- for (const mockOutput of mockOutputs) {
6020
+ if (!shouldDeinlineMocks) for (const mockOutput of collapsedMockOutputs) {
6002
6021
  const entry = output.mock.generators.find((g) => !isFunction(g) && g.type === mockOutput.type);
6003
6022
  const filteredMockImports = mockOutput.imports.filter((impMock) => !normalizedImports.some((imp) => imp.name === impMock.name && (imp.alias ?? "") === (impMock.alias ?? "")));
6004
- const importsMockForBuilder = schemasPath ? generateImportsForBuilder(output, filteredMockImports, schemasPath) : generateImportsForBuilder(output, filteredMockImports.filter((imp) => !!imp.importPath), ".");
6023
+ const importsMockForBuilder = schemasPath ? generateImportsForBuilder(output, filteredMockImports, relativeSchemasPath) : generateImportsForBuilder(output, filteredMockImports.filter((imp) => !!imp.importPath), ".");
6005
6024
  data += builder.importsMock({
6006
6025
  implementation: mockOutput.implementation,
6007
6026
  imports: importsMockForBuilder,
@@ -6031,12 +6050,62 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
6031
6050
  }
6032
6051
  if (!output.schemas && needSchema) data += generateSchemasInline ? generateSchemasInline() : generateModelsInline(builder.schemas);
6033
6052
  data += `${implementation.trim()}\n`;
6034
- if (mockOutputs.length > 0) {
6035
- data += "\n\n";
6036
- data += finalizedImplementationMock;
6053
+ if (!shouldDeinlineMocks) {
6054
+ const implementationMock = collapsedMockOutputs.map((m) => m.implementation).join("\n\n");
6055
+ const finalizedImplementationMock = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(implementationMock, getFinalizeMockImplementationOptions(output, collapsedMockOutputs)) : implementationMock;
6056
+ if (collapsedMockOutputs.length > 0) {
6057
+ data += "\n\n";
6058
+ data += finalizedImplementationMock;
6059
+ }
6060
+ }
6061
+ await writeGeneratedFile(targetPath, data);
6062
+ const extraPaths = [];
6063
+ if (shouldDeinlineMocks) {
6064
+ const seenMockIndexKeys = /* @__PURE__ */ new Set();
6065
+ const writtenMockEntries = [];
6066
+ for (const mockOutput of rawMockOutputs) {
6067
+ const rawEntry = output.mock.generators.find((g) => {
6068
+ if (isFunction(g)) return mockOutput.type === OutputMockType.MSW;
6069
+ return g.type === mockOutput.type;
6070
+ });
6071
+ if (!rawEntry) continue;
6072
+ const mockExtension = isFunction(rawEntry) ? OutputMockType.MSW : getMockFileExtensionByTypeName(rawEntry);
6073
+ const mockDir = getMockDir(rawEntry, output.mock) ?? dirname;
6074
+ const mockFilePath = nodePath.join(mockDir, filename + "." + mockExtension + extension);
6075
+ 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), ".");
6077
+ let mockData = header;
6078
+ const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, getFinalizeMockImplementationOptions(output, mockOutput)) : mockOutput.implementation;
6079
+ mockData += builder.importsMock({
6080
+ implementation: finalizedMockImplementation,
6081
+ imports: importsMockForBuilder,
6082
+ projectName,
6083
+ hasSchemaDir: !!output.schemas,
6084
+ isAllowSyntheticDefaultImports,
6085
+ options: isFunction(rawEntry) ? void 0 : rawEntry
6086
+ });
6087
+ mockData += `\n${finalizedMockImplementation}`;
6088
+ await writeGeneratedFile(mockFilePath, mockData);
6089
+ extraPaths.push(mockFilePath);
6090
+ const indexKey = `${mockExtension}::${mockDir}`;
6091
+ if (!seenMockIndexKeys.has(indexKey)) {
6092
+ seenMockIndexKeys.add(indexKey);
6093
+ writtenMockEntries.push({
6094
+ extension: mockExtension,
6095
+ mockDir
6096
+ });
6097
+ }
6098
+ }
6099
+ if (output.mock.indexMockFiles) {
6100
+ const importExtension = getImportExtension(output.fileExtension, output.tsconfig);
6101
+ for (const { extension: mockExt, mockDir } of writtenMockEntries) {
6102
+ const indexMockPath = nodePath.join(mockDir, `index.${mockExt}${extension}`);
6103
+ await writeGeneratedFile(indexMockPath, `export * from './${filename}.${mockExt}${importExtension}'\n`);
6104
+ extraPaths.push(indexMockPath);
6105
+ }
6106
+ }
6037
6107
  }
6038
- await writeGeneratedFile(path, data);
6039
- return [path];
6108
+ return [targetPath, ...extraPaths];
6040
6109
  } catch (error) {
6041
6110
  const errorMsg = error instanceof Error ? error.message : "unknown error";
6042
6111
  throw new Error(`Oups... 🍻. An Error occurred while writing file => ${errorMsg}`, { cause: error });
@@ -6054,6 +6123,7 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
6054
6123
  let implementationData = header;
6055
6124
  const schemaCustomImportPath = getSchemasImportPath(output.schemas);
6056
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$/, ""));
6057
6127
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
6058
6128
  const importsForBuilder = generateImportsForBuilder(output, imports, relativeSchemasPath);
6059
6129
  implementationData += builder.imports({
@@ -6094,11 +6164,19 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
6094
6164
  const implementationPath = nodePath.join(dirname, implementationFilename);
6095
6165
  await writeGeneratedFile(implementationPath, implementationData);
6096
6166
  const mockPaths = [];
6097
- const writtenMockExtensions = /* @__PURE__ */ new Set();
6167
+ const seenMockIndexKeys = /* @__PURE__ */ new Set();
6168
+ const writtenMockEntries = [];
6098
6169
  for (const mockOutput of mockOutputs) {
6099
- const entry = output.mock.generators.find((g) => !isFunction(g) && g.type === mockOutput.type);
6100
- if (!entry) continue;
6101
- const importsMockForBuilder = generateImportsForBuilder(output, mockOutput.imports, relativeSchemasPath);
6170
+ const rawEntry = output.mock.generators.find((g) => {
6171
+ if (isFunction(g)) return mockOutput.type === OutputMockType.MSW;
6172
+ return g.type === mockOutput.type;
6173
+ });
6174
+ if (!rawEntry) continue;
6175
+ const mockExtension = isFunction(rawEntry) ? OutputMockType.MSW : getMockFileExtensionByTypeName(rawEntry);
6176
+ const mockDir = getMockDir(rawEntry, output.mock) ?? dirname;
6177
+ const mockFilePath = nodePath.join(mockDir, filename + "." + mockExtension + extension);
6178
+ const mockRelativeSchemasPath = schemaCustomImportPath ?? resolveMockSchemasPath(mockFilePath, schemasTarget);
6179
+ const importsMockForBuilder = generateImportsForBuilder(output, mockOutput.imports, mockRelativeSchemasPath);
6102
6180
  let mockData = header;
6103
6181
  const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, getFinalizeMockImplementationOptions(output, mockOutput)) : mockOutput.implementation;
6104
6182
  mockData += builder.importsMock({
@@ -6107,21 +6185,26 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
6107
6185
  projectName,
6108
6186
  hasSchemaDir: !!output.schemas,
6109
6187
  isAllowSyntheticDefaultImports,
6110
- options: entry
6188
+ options: isFunction(rawEntry) ? void 0 : rawEntry
6111
6189
  });
6112
6190
  mockData += `\n${finalizedMockImplementation}`;
6113
- const mockExtension = getMockFileExtensionByTypeName(entry);
6114
- const mockPath = nodePath.join(dirname, filename + "." + mockExtension + extension);
6115
- await writeGeneratedFile(mockPath, mockData);
6116
- mockPaths.push(mockPath);
6117
- writtenMockExtensions.add(mockExtension);
6191
+ await writeGeneratedFile(mockFilePath, mockData);
6192
+ mockPaths.push(mockFilePath);
6193
+ const indexKey = `${mockExtension}::${mockDir}`;
6194
+ if (!seenMockIndexKeys.has(indexKey)) {
6195
+ seenMockIndexKeys.add(indexKey);
6196
+ writtenMockEntries.push({
6197
+ extension: mockExtension,
6198
+ mockDir
6199
+ });
6200
+ }
6118
6201
  }
6119
6202
  const indexMockPaths = [];
6120
6203
  if (output.mock.indexMockFiles) {
6121
6204
  const importExtension = getImportExtension(output.fileExtension, output.tsconfig);
6122
- for (const mockExtension of writtenMockExtensions) {
6123
- const indexMockPath = nodePath.join(dirname, `index.${mockExtension}${extension}`);
6124
- await writeGeneratedFile(indexMockPath, `export * from './${filename}.${mockExtension}${importExtension}'\n`);
6205
+ for (const { extension: mockExt, mockDir } of writtenMockEntries) {
6206
+ const indexMockPath = nodePath.join(mockDir, `index.${mockExt}${extension}`);
6207
+ await writeGeneratedFile(indexMockPath, `export * from './${filename}.${mockExt}${importExtension}'\n`);
6125
6208
  indexMockPaths.push(indexMockPath);
6126
6209
  }
6127
6210
  }
@@ -6172,7 +6255,8 @@ function mergeOperationMockOutputs(accMockOutputs, opMockOutputs) {
6172
6255
  const result = accMockOutputs.map((m) => ({
6173
6256
  type: m.type,
6174
6257
  implementation: { ...m.implementation },
6175
- imports: [...m.imports]
6258
+ imports: [...m.imports],
6259
+ strictMockSchemaTypeNames: m.strictMockSchemaTypeNames ? [...m.strictMockSchemaTypeNames] : void 0
6176
6260
  }));
6177
6261
  for (const op of opMockOutputs) {
6178
6262
  let acc = result.find((m) => m.type === op.type);
@@ -6199,7 +6283,8 @@ function initialMockOutputsForOperation(op) {
6199
6283
  handler: m.implementation.handler,
6200
6284
  handlerName: m.implementation.handlerName ? " " + m.implementation.handlerName + "()" : ""
6201
6285
  },
6202
- imports: [...m.imports]
6286
+ imports: [...m.imports],
6287
+ strictMockSchemaTypeNames: m.strictMockSchemaTypeNames ? [...m.strictMockSchemaTypeNames] : void 0
6203
6288
  }));
6204
6289
  }
6205
6290
  function generateTargetTags(currentAcc, operation) {
@@ -6281,7 +6366,8 @@ function generateTargetForTags(builder, options) {
6281
6366
  handler: m.implementation.handlerName ? m.implementation.handler + header.implementationMock + m.implementation.handlerName + footer.implementationMock : m.implementation.handler,
6282
6367
  handlerName: m.implementation.handlerName
6283
6368
  },
6284
- imports: m.imports
6369
+ imports: m.imports,
6370
+ strictMockSchemaTypeNames: m.strictMockSchemaTypeNames
6285
6371
  }));
6286
6372
  transformed[tag] = {
6287
6373
  implementation: header.implementation + target.implementation + footer.implementation,
@@ -6315,16 +6401,10 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
6315
6401
  });
6316
6402
  const target = generateTargetForTags(builder, output);
6317
6403
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
6318
- if (output.mock.generators.some((g) => isFunction(g))) throw new Error("Function mock generators (ClientMockBuilder) are not supported in tags-split mode. Use typed generators ({ type: \"msw\" } or { type: \"faker\" }).");
6319
- const generatorEntries = output.mock.generators.filter((g) => !isFunction(g));
6320
- const indexFilePathsByType = /* @__PURE__ */ new Map();
6321
- if (output.mock.indexMockFiles) for (const entry of generatorEntries) {
6322
- const ext = getMockFileExtensionByTypeName(entry);
6323
- const indexPath = nodePath.join(dirname, `index.${ext}${extension}`);
6324
- indexFilePathsByType.set(ext, indexPath);
6325
- await fs$1.outputFile(indexPath, "");
6326
- }
6327
- const tagEntries = Object.entries(target);
6404
+ const mockIndexEntries = [];
6405
+ 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$/, ""));
6407
+ const tagEntries = Object.entries(target).toSorted(([a], [b]) => a.localeCompare(b));
6328
6408
  const generatedFilePathsArray = await Promise.all(tagEntries.map(async ([tag, target]) => {
6329
6409
  try {
6330
6410
  const { imports, implementation, mockOutputs, mutators, clientMutators, formData, fetchReviver, formUrlEncoded, paramsSerializer, paramsFilter } = target;
@@ -6408,9 +6488,16 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
6408
6488
  await writeGeneratedFile(implementationPath, implementationData);
6409
6489
  const mockPaths = [];
6410
6490
  for (const mockOutput of mockOutputs) {
6411
- const entry = output.mock.generators.find((g) => !isFunction(g) && g.type === mockOutput.type);
6412
- if (!entry) continue;
6413
- const importsMockForBuilder = generateImportsForBuilder(output, mockOutput.imports, relativeSchemasPath);
6491
+ const rawEntry = output.mock.generators.find((g) => {
6492
+ if (isFunction(g)) return mockOutput.type === OutputMockType.MSW;
6493
+ return g.type === mockOutput.type;
6494
+ });
6495
+ if (!rawEntry) continue;
6496
+ const mockExtension = isFunction(rawEntry) ? OutputMockType.MSW : getMockFileExtensionByTypeName(rawEntry);
6497
+ const mockDir = getMockDir(rawEntry, output.mock) ?? dirname;
6498
+ const mockFilePath = nodePath.join(mockDir, tag, tag + "." + mockExtension + extension);
6499
+ const mockRelativeSchemasPath = schemaCustomImportPath ?? resolveMockSchemasPath(mockFilePath, schemasTarget);
6500
+ const importsMockForBuilder = generateImportsForBuilder(output, mockOutput.imports, mockRelativeSchemasPath);
6414
6501
  const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, getFinalizeMockImplementationOptions(output, mockOutput)) : mockOutput.implementation;
6415
6502
  let mockData = header;
6416
6503
  mockData += builder.importsMock({
@@ -6419,12 +6506,23 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
6419
6506
  projectName,
6420
6507
  hasSchemaDir: !!output.schemas,
6421
6508
  isAllowSyntheticDefaultImports,
6422
- options: entry
6509
+ options: isFunction(rawEntry) ? void 0 : rawEntry
6423
6510
  });
6424
6511
  mockData += `\n${finalizedMockImplementation}`;
6425
- const mockPath = nodePath.join(dirname, tag, tag + "." + getMockFileExtensionByTypeName(entry) + extension);
6426
- await writeGeneratedFile(mockPath, mockData);
6427
- mockPaths.push(mockPath);
6512
+ await writeGeneratedFile(mockFilePath, mockData);
6513
+ mockPaths.push(mockFilePath);
6514
+ const indexKey = `${mockExtension}::${mockDir}`;
6515
+ let indexEntry = mockIndexEntries.find((e) => e.ext === mockExtension && e.mockDir === mockDir);
6516
+ if (!indexEntry) {
6517
+ indexEntry = {
6518
+ ext: mockExtension,
6519
+ mockDir,
6520
+ tags: []
6521
+ };
6522
+ mockIndexEntries.push(indexEntry);
6523
+ seenMockIndexKeys.add(indexKey);
6524
+ }
6525
+ if (!indexEntry.tags.includes(tag)) indexEntry.tags.push(tag);
6428
6526
  }
6429
6527
  return [
6430
6528
  implementationPath,
@@ -6435,17 +6533,11 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
6435
6533
  throw new Error(`Oups... 🍻. An Error occurred while splitting tag ${tag} => ${String(error)}`, { cause: error });
6436
6534
  }
6437
6535
  }));
6438
- if (output.mock.indexMockFiles) for (const entry of generatorEntries) {
6439
- const ext = getMockFileExtensionByTypeName(entry);
6440
- const indexFilePath = indexFilePathsByType.get(ext);
6441
- if (!indexFilePath) continue;
6442
- const indexContent = tagEntries.map(([tag]) => {
6443
- const localMockPath = joinSafe("./", tag, tag + "." + ext);
6444
- return ext === OutputMockType.MSW ? `export { get${pascal(tag)}Mock } from '${localMockPath}'\n` : `export * from '${localMockPath}'\n`;
6445
- }).join("");
6446
- await fs$1.appendFile(indexFilePath, indexContent);
6447
- }
6448
- return [...new Set([...indexFilePathsByType.values(), ...generatedFilePathsArray.flat()])];
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()])];
6449
6541
  }
6450
6542
  //#endregion
6451
6543
  //#region src/writers/tags-mode.ts
@@ -6456,25 +6548,30 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema,
6456
6548
  });
6457
6549
  const target = generateTargetForTags(builder, output);
6458
6550
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
6459
- return (await Promise.all(Object.entries(target).map(async ([tag, target]) => {
6551
+ const shouldDeinlineMocks = hasAnyMockPath(output.mock);
6552
+ const mockIndexEntries = [];
6553
+ const seenMockIndexKeys = /* @__PURE__ */ new Set();
6554
+ 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$/, ""));
6557
+ const tagEntries = Object.entries(target).toSorted(([a], [b]) => a.localeCompare(b));
6558
+ const generatedFilePathsArray = await Promise.all(tagEntries.map(async ([tag, target]) => {
6460
6559
  try {
6461
6560
  const { imports, implementation, mockOutputs: rawMockOutputs, mutators, clientMutators, formData, formUrlEncoded, fetchReviver, paramsSerializer, paramsFilter } = target;
6462
- const mockOutputs = collapseInlineMockOutputs(rawMockOutputs);
6463
- const importsMock = mockOutputs.flatMap((m) => m.imports);
6464
- const implementationMock = mockOutputs.map((m) => m.implementation).join("\n\n");
6465
- const finalizedImplementationMock = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(implementationMock, getFinalizeMockImplementationOptions(output, mockOutputs)) : implementationMock;
6466
- let data = header;
6467
- const schemaCustomImportPath = getSchemasImportPath(output.schemas);
6468
- 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$/, "");
6469
6561
  const normalizedImports = imports.filter((imp) => {
6470
6562
  const searchWords = [imp.alias, imp.name].filter((part) => Boolean(part?.length)).map((part) => escapeRegExp(part)).join("|");
6471
6563
  if (!searchWords) return false;
6472
6564
  return new RegExp(String.raw`\b(${searchWords})\b`, "g").test(implementation);
6473
6565
  }).map((imp) => ({ ...imp }));
6474
- for (const mockImport of importsMock) {
6475
- const matchingImport = normalizedImports.find((imp) => imp.name === mockImport.name && (imp.alias ?? "") === (mockImport.alias ?? ""));
6476
- if (!matchingImport) continue;
6477
- if (!!mockImport.values || !!mockImport.isConstant || !!mockImport.default || !!mockImport.namespaceImport || !!mockImport.syntheticDefaultImport) matchingImport.values = true;
6566
+ const collapsedMockOutputs = shouldDeinlineMocks ? [] : collapseInlineMockOutputs(rawMockOutputs);
6567
+ let data = header;
6568
+ if (!shouldDeinlineMocks) {
6569
+ const importsMock = collapsedMockOutputs.flatMap((m) => m.imports);
6570
+ for (const mockImport of importsMock) {
6571
+ const matchingImport = normalizedImports.find((imp) => imp.name === mockImport.name && (imp.alias ?? "") === (mockImport.alias ?? ""));
6572
+ if (!matchingImport) continue;
6573
+ if (!!mockImport.values || !!mockImport.isConstant || !!mockImport.default || !!mockImport.namespaceImport || !!mockImport.syntheticDefaultImport) matchingImport.values = true;
6574
+ }
6478
6575
  }
6479
6576
  const importsForBuilder = generateImportsForBuilder(output, normalizedImports, schemasPathRelative);
6480
6577
  data += builder.imports({
@@ -6490,7 +6587,7 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema,
6490
6587
  packageJson: output.packageJson,
6491
6588
  output
6492
6589
  });
6493
- for (const mockOutput of mockOutputs) {
6590
+ if (!shouldDeinlineMocks) for (const mockOutput of collapsedMockOutputs) {
6494
6591
  const entry = output.mock.generators.find((g) => !isFunction(g) && g.type === mockOutput.type);
6495
6592
  const importsMockForBuilder = generateImportsForBuilder(output, mockOutput.imports.filter((impMock) => !normalizedImports.some((imp) => imp.name === impMock.name && (imp.alias ?? "") === (impMock.alias ?? ""))), schemasPathRelative);
6496
6593
  data += builder.importsMock({
@@ -6524,17 +6621,73 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema,
6524
6621
  data += "\n";
6525
6622
  }
6526
6623
  data += implementation;
6527
- if (mockOutputs.length > 0) {
6528
- data += "\n\n";
6529
- data += finalizedImplementationMock;
6624
+ if (!shouldDeinlineMocks) {
6625
+ const implementationMock = collapsedMockOutputs.map((m) => m.implementation).join("\n\n");
6626
+ const finalizedImplementationMock = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(implementationMock, getFinalizeMockImplementationOptions(output, collapsedMockOutputs)) : implementationMock;
6627
+ if (collapsedMockOutputs.length > 0) {
6628
+ data += "\n\n";
6629
+ data += finalizedImplementationMock;
6630
+ }
6530
6631
  }
6531
- const implementationPath = nodePath.join(dirname, `${kebab(tag)}${extension}`);
6632
+ const kebabTag = kebab(tag);
6633
+ const implementationPath = nodePath.join(dirname, `${kebabTag}${extension}`);
6532
6634
  await writeGeneratedFile(implementationPath, data);
6533
- return [implementationPath, ...schemasPath ? [schemasPath] : []];
6635
+ const extraPaths = [];
6636
+ if (shouldDeinlineMocks) for (const mockOutput of rawMockOutputs) {
6637
+ const rawEntry = output.mock.generators.find((g) => {
6638
+ if (isFunction(g)) return mockOutput.type === OutputMockType.MSW;
6639
+ return g.type === mockOutput.type;
6640
+ });
6641
+ if (!rawEntry) continue;
6642
+ const mockExtension = isFunction(rawEntry) ? OutputMockType.MSW : getMockFileExtensionByTypeName(rawEntry);
6643
+ const mockDir = getMockDir(rawEntry, output.mock) ?? dirname;
6644
+ const mockFilePath = nodePath.join(mockDir, kebabTag, kebabTag + "." + mockExtension + extension);
6645
+ const mockRelativeSchemasPath = schemaCustomImportPath ?? resolveMockSchemasPath(mockFilePath, schemasTarget);
6646
+ const importsMockForBuilder = generateImportsForBuilder(output, mockOutput.imports, mockRelativeSchemasPath);
6647
+ let mockData = header;
6648
+ const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, getFinalizeMockImplementationOptions(output, mockOutput)) : mockOutput.implementation;
6649
+ mockData += builder.importsMock({
6650
+ implementation: finalizedMockImplementation,
6651
+ imports: importsMockForBuilder,
6652
+ projectName,
6653
+ hasSchemaDir: !!output.schemas,
6654
+ isAllowSyntheticDefaultImports,
6655
+ options: isFunction(rawEntry) ? void 0 : rawEntry
6656
+ });
6657
+ mockData += `\n${finalizedMockImplementation}`;
6658
+ await writeGeneratedFile(mockFilePath, mockData);
6659
+ extraPaths.push(mockFilePath);
6660
+ const indexKey = `${mockExtension}::${mockDir}`;
6661
+ let indexEntry = mockIndexEntries.find((e) => e.ext === mockExtension && e.mockDir === mockDir);
6662
+ if (!indexEntry) {
6663
+ indexEntry = {
6664
+ ext: mockExtension,
6665
+ mockDir,
6666
+ tags: []
6667
+ };
6668
+ mockIndexEntries.push(indexEntry);
6669
+ seenMockIndexKeys.add(indexKey);
6670
+ }
6671
+ if (!indexEntry.tags.includes(kebabTag)) indexEntry.tags.push(kebabTag);
6672
+ }
6673
+ return [
6674
+ implementationPath,
6675
+ ...schemasPath ? [schemasPath] : [],
6676
+ ...extraPaths
6677
+ ];
6534
6678
  } catch (error) {
6535
6679
  throw new Error(`Oups... 🍻. An Error occurred while writing tag ${tag} => ${String(error)}`, { cause: error });
6536
6680
  }
6537
- }))).flat();
6681
+ }));
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]);
6689
+ }
6690
+ return generatedFilePathsArray.flat();
6538
6691
  }
6539
6692
  //#endregion
6540
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 };