@orval/core 8.16.0 → 8.18.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
@@ -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
  }
@@ -1320,7 +1321,7 @@ const getUnion = (value, enumName) => {
1320
1321
  };
1321
1322
  function getEnumUnionFromSchema(schema) {
1322
1323
  if (!schema?.enum) return "";
1323
- return schema.enum.filter((val) => val !== null).map((val) => isString(val) ? `'${escape(val)}'` : String(val)).join(" | ");
1324
+ return schema.enum.filter((val) => val !== null).map((val) => isString(val) ? `'${jsStringLiteralEscape(val)}'` : String(val)).join(" | ");
1324
1325
  }
1325
1326
  const stripNullUnion = (value) => value.replaceAll(/\s*\|\s*null/g, "").trim();
1326
1327
  const isSpreadableEnumRef = (schema, refName) => {
@@ -1707,13 +1708,13 @@ function getPropertyNamesEnumKeyType(item) {
1707
1708
  if (Array.isArray(propertyNames.enum)) {
1708
1709
  const enumValues = propertyNames.enum.filter((val) => isString(val));
1709
1710
  if (enumValues.length > 0) return {
1710
- value: enumValues.map((val) => `'${escape(val)}'`).join(" | "),
1711
+ value: enumValues.map((val) => `'${jsStringLiteralEscape(val)}'`).join(" | "),
1711
1712
  imports: [],
1712
1713
  dependencies: []
1713
1714
  };
1714
1715
  }
1715
1716
  if (isString(propertyNames.const)) return {
1716
- value: `'${escape(propertyNames.const)}'`,
1717
+ value: `'${jsStringLiteralEscape(propertyNames.const)}'`,
1717
1718
  imports: [],
1718
1719
  dependencies: []
1719
1720
  };
@@ -1878,7 +1879,7 @@ function getObject({ item, name, context, nullable, formDataContext }) {
1878
1879
  const hasConst = constValue !== void 0;
1879
1880
  let constLiteral;
1880
1881
  if (!hasConst) constLiteral = void 0;
1881
- else if (isString(constValue)) constLiteral = `'${escape(constValue)}'`;
1882
+ else if (isString(constValue)) constLiteral = `'${jsStringLiteralEscape(constValue)}'`;
1882
1883
  else constLiteral = JSON.stringify(constValue);
1883
1884
  const needsValueImport = hasConst && (resolvedValue.isEnum || resolvedValue.type === "enum");
1884
1885
  const usedResolvedValue = !hasConst || needsValueImport;
@@ -2011,7 +2012,7 @@ function getObject({ item, name, context, nullable, formDataContext }) {
2011
2012
  else if (typeof constValue === "boolean") type = "boolean";
2012
2013
  else type = "object";
2013
2014
  return {
2014
- value: typeof constValue === "string" ? `'${escape(constValue)}'` : JSON.stringify(constValue),
2015
+ value: typeof constValue === "string" ? `'${jsStringLiteralEscape(constValue)}'` : JSON.stringify(constValue),
2015
2016
  imports: [],
2016
2017
  schemas: [],
2017
2018
  isEnum: false,
@@ -2152,7 +2153,7 @@ function getScalar({ item, name, context, formDataContext }) {
2152
2153
  let value = "string";
2153
2154
  let isEnum = false;
2154
2155
  if (enumItems) {
2155
- value = enumItems.map((enumItem) => isString(enumItem) ? `'${escape(enumItem)}'` : `${enumItem}`).filter(Boolean).join(` | `);
2156
+ value = enumItems.map((enumItem) => isString(enumItem) ? `'${jsStringLiteralEscape(enumItem)}'` : `${enumItem}`).filter(Boolean).join(` | `);
2156
2157
  isEnum = true;
2157
2158
  }
2158
2159
  if (!formDataContext?.urlEncoded) {
@@ -2164,7 +2165,7 @@ function getScalar({ item, name, context, formDataContext }) {
2164
2165
  }
2165
2166
  if (context.output.override.useDates && (schemaFormat === "date" || schemaFormat === "date-time")) value = "Date";
2166
2167
  value += nullable;
2167
- if (schemaConst) value = `'${schemaConst}'`;
2168
+ if (schemaConst) value = `'${jsStringLiteralEscape(schemaConst)}'`;
2168
2169
  return {
2169
2170
  value,
2170
2171
  isEnum,
@@ -2214,7 +2215,7 @@ function getScalar({ item, name, context, formDataContext }) {
2214
2215
  nullable
2215
2216
  });
2216
2217
  if (enumItems) return {
2217
- value: enumItems.map((enumItem) => isString(enumItem) ? `'${escape(enumItem)}'` : String(enumItem)).filter(Boolean).join(` | `) + nullable,
2218
+ value: enumItems.map((enumItem) => isString(enumItem) ? `'${jsStringLiteralEscape(enumItem)}'` : String(enumItem)).filter(Boolean).join(` | `) + nullable,
2218
2219
  isEnum: true,
2219
2220
  type: "string",
2220
2221
  imports: [],
@@ -4457,8 +4458,9 @@ function findRefs(value) {
4457
4458
  if (!value || typeof value !== "object") return [];
4458
4459
  if (Array.isArray(value)) return value.flatMap((item) => findRefs(item));
4459
4460
  const obj = value;
4460
- if (typeof obj.$ref === "string") return [obj.$ref];
4461
- return Object.values(obj).flatMap((val) => findRefs(val));
4461
+ const refs = [];
4462
+ if (typeof obj.$ref === "string") refs.push(obj.$ref);
4463
+ return refs.concat(Object.values(obj).flatMap((val) => findRefs(val)));
4462
4464
  }
4463
4465
  function parseComponentRef(ref) {
4464
4466
  const parts = ref.split("/");
@@ -4617,9 +4619,10 @@ function parseFunction(ast, funcName) {
4617
4619
  //#endregion
4618
4620
  //#region src/generators/mutator.ts
4619
4621
  const BODY_TYPE_NAME = "BodyType";
4620
- const getImport = (output, mutator) => {
4622
+ const getImport = (output, mutator, tsconfig) => {
4621
4623
  const outputFile = getFileInfo(output).path;
4622
- return `${getRelativeImportPath(outputFile, mutator.path)}${mutator.extension ?? ""}`;
4624
+ const ext = mutator.extension ?? getImportExtension(nodePath.extname(mutator.path), tsconfig);
4625
+ return `${getRelativeImportPath(outputFile, mutator.path)}${ext}`;
4623
4626
  };
4624
4627
  async function generateMutator({ output, mutator, name, workspace, tsconfig }) {
4625
4628
  if (!mutator || !output) return;
@@ -4642,7 +4645,7 @@ async function generateMutator({ output, mutator, name, workspace, tsconfig }) {
4642
4645
  tsconfig
4643
4646
  });
4644
4647
  if (!mutatorInfo) throw new Error(styleText("red", `Your mutator file doesn't have the ${mutatorInfoName} exported function`));
4645
- const importStatementPath = getImport(output, mutator);
4648
+ const importStatementPath = getImport(output, mutator, tsconfig);
4646
4649
  const isHook = mutator.name ? mutator.name.startsWith("use") && !mutatorInfo.numberOfParams : !mutatorInfo.numberOfParams;
4647
4650
  return {
4648
4651
  name: mutator.name || !isHook ? importName : `use${pascal(importName)}`,
@@ -4684,11 +4687,19 @@ const getAngularFilteredParamsExpression = (paramsExpression, requiredNullablePa
4684
4687
  continue;
4685
4688
  }
4686
4689
  ` : "";
4687
- const preserveNullableBranch = preserveRequiredNullables ? ` } else if (value === null && requiredNullableParamKeys.has(key)) {
4690
+ let preserveNullableBranch;
4691
+ let requiredNullableParamKeysBranch;
4692
+ if (preserveRequiredNullables) {
4693
+ preserveNullableBranch = ` } else if (value === null && requiredNullableParamKeys.has(key)) {
4688
4694
  filteredParams[key] = null;
4689
- ` : "";
4695
+ `;
4696
+ requiredNullableParamKeysBranch = `const requiredNullableParamKeys = new Set<string>(${JSON.stringify(requiredNullableParamKeys)});`;
4697
+ } else {
4698
+ preserveNullableBranch = "";
4699
+ requiredNullableParamKeysBranch = "";
4700
+ }
4690
4701
  return `(() => {
4691
- ${hasPassthrough ? ` const passthroughKeys = new Set<string>(${JSON.stringify(nonPrimitiveKeys)});\n` : ""} const requiredNullableParamKeys = new Set<string>(${JSON.stringify(requiredNullableParamKeys)});
4702
+ ${hasPassthrough ? ` const passthroughKeys = new Set<string>(${JSON.stringify(nonPrimitiveKeys)});\n` : ""} ${requiredNullableParamKeysBranch}
4692
4703
  const filteredParams: Record<string, ${filteredParamValueType}> = {};
4693
4704
  for (const [key, value] of Object.entries(${paramsExpression})) {
4694
4705
  ${passthroughBranch} if (Array.isArray(value)) {
@@ -5746,12 +5757,25 @@ async function writeSchemas({ schemaPath, schemas, target, namingConvention, fil
5746
5757
  //#endregion
5747
5758
  //#region src/writers/finalize-mock-implementation.ts
5748
5759
  function getFinalizeMockImplementationOptions(output, mockOutputs) {
5749
- const strictSchemaTypeNames = [...new Set((Array.isArray(mockOutputs) ? mockOutputs : [mockOutputs]).flatMap((mockOutput) => mockOutput.strictMockSchemaTypeNames ?? []))];
5760
+ const outputs = Array.isArray(mockOutputs) ? mockOutputs : [mockOutputs];
5761
+ const strictSchemaTypeNames = [...new Set(outputs.flatMap((mockOutput) => mockOutput.strictMockSchemaTypeNames ?? []))];
5762
+ const strictMockSchemaKinds = outputs.reduce((acc, mockOutput) => {
5763
+ if (!mockOutput.strictMockSchemaKinds) return acc;
5764
+ for (const [name, kind] of Object.entries(mockOutput.strictMockSchemaKinds)) acc[name] ??= kind;
5765
+ return acc;
5766
+ }, {});
5750
5767
  return {
5751
5768
  mockOptions: output.override.mock,
5752
- strictSchemaTypeNames: strictSchemaTypeNames.length > 0 ? strictSchemaTypeNames : void 0
5769
+ strictSchemaTypeNames: strictSchemaTypeNames.length > 0 ? strictSchemaTypeNames : void 0,
5770
+ strictMockSchemaKinds: Object.keys(strictMockSchemaKinds).length > 0 ? strictMockSchemaKinds : void 0
5753
5771
  };
5754
5772
  }
5773
+ /** Drop schema-factory `{Schema}Mock` type imports that are declared locally. */
5774
+ function filterLocalStrictMockTypeImports(imports, strictSchemaTypeNames) {
5775
+ if (!strictSchemaTypeNames?.length) return [...imports];
5776
+ const localMockTypeNames = new Set(strictSchemaTypeNames.map((name) => `${name}Mock`));
5777
+ return imports.filter((imp) => !(imp.schemaFactory && !imp.values && localMockTypeNames.has(imp.name)));
5778
+ }
5755
5779
  //#endregion
5756
5780
  //#region src/writers/generate-imports-for-builder.ts
5757
5781
  function generateImportsForBuilder(output, imports, relativeSchemasPath) {
@@ -5759,9 +5783,10 @@ function generateImportsForBuilder(output, imports, relativeSchemasPath) {
5759
5783
  const isZodSchemaOutput = isObject(output.schemas) && output.schemas.type === "zod";
5760
5784
  const schemaFactoryImports = imports.filter((i) => i.schemaFactory);
5761
5785
  const schemaFactoryImportExtension = isPackageImport ? "" : getImportExtension(output.fileExtension, output.tsconfig);
5786
+ const schemaFactoryDependency = getFakerSchemasImportPath(output.mock) ?? joinSafe(relativeSchemasPath, `index.faker${schemaFactoryImportExtension}`);
5762
5787
  const schemaFactoryDeps = schemaFactoryImports.length > 0 ? [{
5763
5788
  exports: uniqueBy(schemaFactoryImports, (entry) => `${entry.name}|${entry.alias ?? ""}`),
5764
- dependency: joinSafe(relativeSchemasPath, `index.faker${schemaFactoryImportExtension}`)
5789
+ dependency: schemaFactoryDependency
5765
5790
  }] : [];
5766
5791
  imports = imports.filter((i) => !i.schemaFactory);
5767
5792
  let schemaImports;
@@ -5796,6 +5821,16 @@ function generateImportsForBuilder(output, imports, relativeSchemasPath) {
5796
5821
  ...otherImports
5797
5822
  ];
5798
5823
  }
5824
+ /**
5825
+ * Extracts the faker generator's `schemasImportPath` from the normalized mock
5826
+ * config, if one is configured. Returns `undefined` when there is no faker
5827
+ * generator with schema factories enabled, or when `schemasImportPath` is not
5828
+ * set.
5829
+ */
5830
+ function getFakerSchemasImportPath(mock) {
5831
+ if (!mock) return;
5832
+ return mock.generators.find((g) => !isFunction(g) && g.type === OutputMockType.FAKER && g.schemas === true)?.schemasImportPath;
5833
+ }
5799
5834
  //#endregion
5800
5835
  //#region src/writers/mock-outputs.ts
5801
5836
  /**
@@ -5811,6 +5846,21 @@ function collapseInlineMockOutputs(mockOutputs) {
5811
5846
  return mockOutputs.filter((m) => m.type !== OutputMockType.FAKER);
5812
5847
  }
5813
5848
  //#endregion
5849
+ //#region src/writers/mock-utils.ts
5850
+ function getMockDir(entry, mockConfig) {
5851
+ if (!isFunction(entry) && entry.path) return entry.path;
5852
+ return mockConfig.path;
5853
+ }
5854
+ function hasAnyMockPath(mockConfig) {
5855
+ if (mockConfig.path) return true;
5856
+ return mockConfig.generators.some((g) => !isFunction(g) && !!g.path);
5857
+ }
5858
+ function resolveMockSchemasPath(mockFilePath, schemasTarget) {
5859
+ const ext = nodePath.extname(mockFilePath);
5860
+ const targetExt = nodePath.extname(schemasTarget);
5861
+ return getRelativeImportPath(mockFilePath, targetExt === ".schemas" ? schemasTarget + ext : targetExt ? schemasTarget : schemasTarget + ext);
5862
+ }
5863
+ //#endregion
5814
5864
  //#region src/writers/target.ts
5815
5865
  function emptyMockOutputFull$1(type) {
5816
5866
  return {
@@ -5828,7 +5878,8 @@ function flattenMockOutput$1(full) {
5828
5878
  type: full.type,
5829
5879
  implementation: full.implementation.function + full.implementation.handler,
5830
5880
  imports: full.imports,
5831
- strictMockSchemaTypeNames: full.strictMockSchemaTypeNames
5881
+ strictMockSchemaTypeNames: full.strictMockSchemaTypeNames,
5882
+ strictMockSchemaKinds: full.strictMockSchemaKinds
5832
5883
  };
5833
5884
  }
5834
5885
  function generateTarget(builder, options) {
@@ -5864,6 +5915,10 @@ function generateTarget(builder, options) {
5864
5915
  }
5865
5916
  acc.imports.push(...opMock.imports);
5866
5917
  if (opMock.strictMockSchemaTypeNames?.length) acc.strictMockSchemaTypeNames = [...new Set([...acc.strictMockSchemaTypeNames ?? [], ...opMock.strictMockSchemaTypeNames])];
5918
+ if (opMock.strictMockSchemaKinds) acc.strictMockSchemaKinds = {
5919
+ ...acc.strictMockSchemaKinds,
5920
+ ...opMock.strictMockSchemaKinds
5921
+ };
5867
5922
  acc.implementation.function += opMock.implementation.function;
5868
5923
  acc.implementation.handler += opMock.implementation.handler;
5869
5924
  if (opMock.implementation.handlerName) {
@@ -5961,30 +6016,33 @@ interface TypedResponse<T> extends Response {
5961
6016
  //#region src/writers/single-mode.ts
5962
6017
  async function writeSingleMode({ builder, output, projectName, header, needSchema, generateSchemasInline }) {
5963
6018
  try {
5964
- const { path } = getFileInfo(output.target, {
6019
+ const { path: targetPath, filename, dirname, extension } = getFileInfo(output.target, {
5965
6020
  backupFilename: conventionName(builder.info.title ?? "filename", output.namingConvention),
5966
6021
  extension: output.fileExtension
5967
6022
  });
5968
6023
  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
6024
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
6025
+ const shouldDeinlineMocks = hasAnyMockPath(output.mock);
6026
+ const schemaCustomImportPath = getSchemasImportPath(output.schemas);
6027
+ const schemasPath = output.schemas ? schemaCustomImportPath ?? getRelativeImportPath(targetPath, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : void 0;
6028
+ const relativeSchemasPath = schemasPath ?? "./" + filename + ".schemas" + extension.replace(/\.ts$/, "");
6029
+ const schemasTarget = output.schemas ? getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname : targetPath;
5977
6030
  const normalizedImports = imports.filter((imp) => {
5978
6031
  const searchWords = [imp.alias, imp.name].filter((part) => Boolean(part?.length)).map((part) => escapeRegExp(part)).join("|");
5979
6032
  if (!searchWords) return false;
5980
6033
  return new RegExp(String.raw`\b(${searchWords})\b`, "g").test(implementation);
5981
6034
  }).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;
6035
+ const collapsedMockOutputs = shouldDeinlineMocks ? [] : collapseInlineMockOutputs(rawMockOutputs);
6036
+ if (!shouldDeinlineMocks) {
6037
+ const importsMock = collapsedMockOutputs.flatMap((m) => m.imports);
6038
+ for (const mockImport of importsMock) {
6039
+ const matchingImport = normalizedImports.find((imp) => imp.name === mockImport.name && (imp.alias ?? "") === (mockImport.alias ?? ""));
6040
+ if (!matchingImport) continue;
6041
+ if (!!mockImport.values || !!mockImport.isConstant || !!mockImport.default || !!mockImport.namespaceImport || !!mockImport.syntheticDefaultImport) matchingImport.values = true;
6042
+ }
5986
6043
  }
5987
- const importsForBuilder = schemasPath ? generateImportsForBuilder(output, normalizedImports, schemasPath) : generateImportsForBuilder(output, normalizedImports.filter((imp) => !!imp.importPath), ".");
6044
+ let data = header;
6045
+ const importsForBuilder = schemasPath ? generateImportsForBuilder(output, normalizedImports, relativeSchemasPath) : generateImportsForBuilder(output, normalizedImports.filter((imp) => !!imp.importPath), ".");
5988
6046
  data += builder.imports({
5989
6047
  client: output.client,
5990
6048
  implementation,
@@ -5998,10 +6056,11 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
5998
6056
  packageJson: output.packageJson,
5999
6057
  output
6000
6058
  });
6001
- for (const mockOutput of mockOutputs) {
6059
+ if (!shouldDeinlineMocks) for (const mockOutput of collapsedMockOutputs) {
6002
6060
  const entry = output.mock.generators.find((g) => !isFunction(g) && g.type === mockOutput.type);
6003
- 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), ".");
6061
+ const finalizeMockOptions = getFinalizeMockImplementationOptions(output, mockOutput);
6062
+ const filteredMockImports = filterLocalStrictMockTypeImports(mockOutput.imports.filter((impMock) => !normalizedImports.some((imp) => imp.name === impMock.name && (imp.alias ?? "") === (impMock.alias ?? ""))), finalizeMockOptions.strictSchemaTypeNames);
6063
+ const importsMockForBuilder = schemasPath ? generateImportsForBuilder(output, filteredMockImports, relativeSchemasPath) : generateImportsForBuilder(output, filteredMockImports.filter((imp) => !!imp.importPath), ".");
6005
6064
  data += builder.importsMock({
6006
6065
  implementation: mockOutput.implementation,
6007
6066
  imports: importsMockForBuilder,
@@ -6031,18 +6090,140 @@ async function writeSingleMode({ builder, output, projectName, header, needSchem
6031
6090
  }
6032
6091
  if (!output.schemas && needSchema) data += generateSchemasInline ? generateSchemasInline() : generateModelsInline(builder.schemas);
6033
6092
  data += `${implementation.trim()}\n`;
6034
- if (mockOutputs.length > 0) {
6035
- data += "\n\n";
6036
- data += finalizedImplementationMock;
6093
+ if (!shouldDeinlineMocks) {
6094
+ const implementationMock = collapsedMockOutputs.map((m) => m.implementation).join("\n\n");
6095
+ const finalizedImplementationMock = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(implementationMock, getFinalizeMockImplementationOptions(output, collapsedMockOutputs)) : implementationMock;
6096
+ if (collapsedMockOutputs.length > 0) {
6097
+ data += "\n\n";
6098
+ data += finalizedImplementationMock;
6099
+ }
6037
6100
  }
6038
- await writeGeneratedFile(path, data);
6039
- return [path];
6101
+ await writeGeneratedFile(targetPath, data);
6102
+ const extraPaths = [];
6103
+ if (shouldDeinlineMocks) {
6104
+ const seenMockIndexKeys = /* @__PURE__ */ new Set();
6105
+ const writtenMockEntries = [];
6106
+ for (const mockOutput of rawMockOutputs) {
6107
+ const rawEntry = output.mock.generators.find((g) => {
6108
+ if (isFunction(g)) return mockOutput.type === OutputMockType.MSW;
6109
+ return g.type === mockOutput.type;
6110
+ });
6111
+ if (!rawEntry) continue;
6112
+ const mockExtension = isFunction(rawEntry) ? OutputMockType.MSW : getMockFileExtensionByTypeName(rawEntry);
6113
+ const mockDir = getMockDir(rawEntry, output.mock) ?? dirname;
6114
+ const mockFilePath = nodePath.join(mockDir, filename + "." + mockExtension + extension);
6115
+ const mockRelativeSchemasPath = schemaCustomImportPath ?? resolveMockSchemasPath(mockFilePath, schemasTarget);
6116
+ const importsMockForBuilder = schemasPath || mockDir !== dirname ? generateImportsForBuilder(output, mockOutput.imports, mockRelativeSchemasPath) : generateImportsForBuilder(output, mockOutput.imports.filter((imp) => !!imp.importPath), ".");
6117
+ let mockData = header;
6118
+ const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, getFinalizeMockImplementationOptions(output, mockOutput)) : mockOutput.implementation;
6119
+ mockData += builder.importsMock({
6120
+ implementation: finalizedMockImplementation,
6121
+ imports: importsMockForBuilder,
6122
+ projectName,
6123
+ hasSchemaDir: !!output.schemas,
6124
+ isAllowSyntheticDefaultImports,
6125
+ options: isFunction(rawEntry) ? void 0 : rawEntry
6126
+ });
6127
+ mockData += `\n${finalizedMockImplementation}`;
6128
+ await writeGeneratedFile(mockFilePath, mockData);
6129
+ extraPaths.push(mockFilePath);
6130
+ const indexKey = `${mockExtension}::${mockDir}`;
6131
+ if (!seenMockIndexKeys.has(indexKey)) {
6132
+ seenMockIndexKeys.add(indexKey);
6133
+ writtenMockEntries.push({
6134
+ extension: mockExtension,
6135
+ mockDir
6136
+ });
6137
+ }
6138
+ }
6139
+ if (output.mock.indexMockFiles) {
6140
+ const importExtension = getImportExtension(output.fileExtension, output.tsconfig);
6141
+ for (const { extension: mockExt, mockDir } of writtenMockEntries) {
6142
+ const indexMockPath = nodePath.join(mockDir, `index.${mockExt}${extension}`);
6143
+ await writeGeneratedFile(indexMockPath, `export * from './${filename}.${mockExt}${importExtension}'\n`);
6144
+ extraPaths.push(indexMockPath);
6145
+ }
6146
+ }
6147
+ }
6148
+ return [targetPath, ...extraPaths];
6040
6149
  } catch (error) {
6041
6150
  const errorMsg = error instanceof Error ? error.message : "unknown error";
6042
6151
  throw new Error(`Oups... 🍻. An Error occurred while writing file => ${errorMsg}`, { cause: error });
6043
6152
  }
6044
6153
  }
6045
6154
  //#endregion
6155
+ //#region src/writers/mock-imports.ts
6156
+ /** Maps `components/schemas` names to consolidated index.faker import symbols. */
6157
+ function buildKnownSchemaFactoryImportSets(schemaNames) {
6158
+ const factoryNames = /* @__PURE__ */ new Set();
6159
+ const typeNames = /* @__PURE__ */ new Set();
6160
+ for (const name of schemaNames) {
6161
+ const typeName = pascal(name);
6162
+ factoryNames.add(`get${typeName}Mock`);
6163
+ typeNames.add(`${typeName}Mock`);
6164
+ }
6165
+ return {
6166
+ factoryNames,
6167
+ typeNames
6168
+ };
6169
+ }
6170
+ /**
6171
+ * Recover schema-factory imports referenced in generated mock bodies but
6172
+ * missing from the collected import list (e.g. after shared-array import
6173
+ * aggregation on large specs). Scans for `get<Schema>Mock()` calls and
6174
+ * `as <Schema>Mock` casts emitted by strict schema delegation (#3590).
6175
+ *
6176
+ * When `knownSets` is provided, only symbols that exist in the consolidated
6177
+ * schemas faker file are recovered — this avoids importing one-off split
6178
+ * response helper factories that live in the tag file itself.
6179
+ */
6180
+ function collectSchemaFactoryImportsFromImplementation(implementation, knownSets) {
6181
+ const imports = [];
6182
+ const seen = /* @__PURE__ */ new Set();
6183
+ for (const match of implementation.matchAll(/\b(get[A-Za-z0-9]+Mock)\(\)/g)) {
6184
+ const factoryName = match[1];
6185
+ if (knownSets && !knownSets.factoryNames.has(factoryName)) continue;
6186
+ const key = `value::${factoryName}`;
6187
+ if (seen.has(key)) continue;
6188
+ seen.add(key);
6189
+ imports.push({
6190
+ name: factoryName,
6191
+ values: true,
6192
+ schemaFactory: true
6193
+ });
6194
+ }
6195
+ for (const match of implementation.matchAll(/\bas ([A-Za-z0-9]+Mock)\b/g)) {
6196
+ const typeName = match[1];
6197
+ if (knownSets && !knownSets.typeNames.has(typeName)) continue;
6198
+ const key = `type::${typeName}`;
6199
+ if (seen.has(key)) continue;
6200
+ seen.add(key);
6201
+ imports.push({
6202
+ name: typeName,
6203
+ values: false,
6204
+ schemaFactory: true
6205
+ });
6206
+ }
6207
+ return imports;
6208
+ }
6209
+ function mergeGeneratorImports(...groups) {
6210
+ const merged = /* @__PURE__ */ new Map();
6211
+ for (const group of groups) for (const imp of group) {
6212
+ const key = `${imp.name}::${imp.alias ?? ""}`;
6213
+ const existing = merged.get(key);
6214
+ if (!existing) {
6215
+ merged.set(key, imp);
6216
+ continue;
6217
+ }
6218
+ if (!existing.values && imp.values) merged.set(key, imp);
6219
+ }
6220
+ return [...merged.values()];
6221
+ }
6222
+ /** Recover missing index.faker imports when `schemas: true` is enabled. */
6223
+ function collectRecoveredSchemaFactoryImports(implementation, componentSchemaNames) {
6224
+ return collectSchemaFactoryImportsFromImplementation(implementation, buildKnownSchemaFactoryImportSets(componentSchemaNames));
6225
+ }
6226
+ //#endregion
6046
6227
  //#region src/writers/split-mode.ts
6047
6228
  async function writeSplitMode({ builder, output, projectName, header, needSchema, generateSchemasInline }) {
6048
6229
  try {
@@ -6053,7 +6234,8 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
6053
6234
  const { imports, implementation, mockOutputs, mutators, clientMutators, formData, formUrlEncoded, paramsSerializer, paramsFilter, fetchReviver } = generateTarget(builder, output);
6054
6235
  let implementationData = header;
6055
6236
  const schemaCustomImportPath = getSchemasImportPath(output.schemas);
6056
- 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$/, "");
6237
+ const relativeSchemasPath = output.schemas ? schemaCustomImportPath ?? getRelativeImportPath(targetPath, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "./" + filename + ".schemas" + getImportExtension(extension, output.tsconfig);
6238
+ const schemasTarget = output.schemas ? getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname : nodePath.join(dirname, filename + ".schemas" + getImportExtension(extension, output.tsconfig));
6057
6239
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
6058
6240
  const importsForBuilder = generateImportsForBuilder(output, imports, relativeSchemasPath);
6059
6241
  implementationData += builder.imports({
@@ -6094,34 +6276,49 @@ async function writeSplitMode({ builder, output, projectName, header, needSchema
6094
6276
  const implementationPath = nodePath.join(dirname, implementationFilename);
6095
6277
  await writeGeneratedFile(implementationPath, implementationData);
6096
6278
  const mockPaths = [];
6097
- const writtenMockExtensions = /* @__PURE__ */ new Set();
6279
+ const seenMockIndexKeys = /* @__PURE__ */ new Set();
6280
+ const writtenMockEntries = [];
6098
6281
  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);
6282
+ const rawEntry = output.mock.generators.find((g) => {
6283
+ if (isFunction(g)) return mockOutput.type === OutputMockType.MSW;
6284
+ return g.type === mockOutput.type;
6285
+ });
6286
+ if (!rawEntry) continue;
6287
+ const mockExtension = isFunction(rawEntry) ? OutputMockType.MSW : getMockFileExtensionByTypeName(rawEntry);
6288
+ const mockDir = getMockDir(rawEntry, output.mock) ?? dirname;
6289
+ const mockFilePath = nodePath.join(mockDir, filename + "." + mockExtension + extension);
6290
+ const mockRelativeSchemasPath = schemaCustomImportPath ?? resolveMockSchemasPath(mockFilePath, schemasTarget);
6291
+ const finalizeMockOptions = getFinalizeMockImplementationOptions(output, mockOutput);
6292
+ const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, finalizeMockOptions) : mockOutput.implementation;
6293
+ 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)) : [];
6294
+ const importsMockForBuilder = generateImportsForBuilder(output, filterLocalStrictMockTypeImports(mergeGeneratorImports(mockOutput.imports, recoveredSchemaFactoryImports), finalizeMockOptions.strictSchemaTypeNames), mockRelativeSchemasPath);
6102
6295
  let mockData = header;
6103
- const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, getFinalizeMockImplementationOptions(output, mockOutput)) : mockOutput.implementation;
6104
6296
  mockData += builder.importsMock({
6105
6297
  implementation: finalizedMockImplementation,
6106
6298
  imports: importsMockForBuilder,
6107
6299
  projectName,
6108
6300
  hasSchemaDir: !!output.schemas,
6109
6301
  isAllowSyntheticDefaultImports,
6110
- options: entry
6302
+ options: isFunction(rawEntry) ? void 0 : rawEntry
6111
6303
  });
6112
6304
  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);
6305
+ await writeGeneratedFile(mockFilePath, mockData);
6306
+ mockPaths.push(mockFilePath);
6307
+ const indexKey = `${mockExtension}::${mockDir}`;
6308
+ if (!seenMockIndexKeys.has(indexKey)) {
6309
+ seenMockIndexKeys.add(indexKey);
6310
+ writtenMockEntries.push({
6311
+ extension: mockExtension,
6312
+ mockDir
6313
+ });
6314
+ }
6118
6315
  }
6119
6316
  const indexMockPaths = [];
6120
6317
  if (output.mock.indexMockFiles) {
6121
6318
  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`);
6319
+ for (const { extension: mockExt, mockDir } of writtenMockEntries) {
6320
+ const indexMockPath = nodePath.join(mockDir, `index.${mockExt}${extension}`);
6321
+ await writeGeneratedFile(indexMockPath, `export * from './${filename}.${mockExt}${importExtension}'\n`);
6125
6322
  indexMockPaths.push(indexMockPath);
6126
6323
  }
6127
6324
  }
@@ -6165,14 +6362,17 @@ function flattenMockOutput(full) {
6165
6362
  type: full.type,
6166
6363
  implementation: full.implementation.function + full.implementation.handler,
6167
6364
  imports: full.imports,
6168
- strictMockSchemaTypeNames: full.strictMockSchemaTypeNames
6365
+ strictMockSchemaTypeNames: full.strictMockSchemaTypeNames,
6366
+ strictMockSchemaKinds: full.strictMockSchemaKinds
6169
6367
  };
6170
6368
  }
6171
6369
  function mergeOperationMockOutputs(accMockOutputs, opMockOutputs) {
6172
6370
  const result = accMockOutputs.map((m) => ({
6173
6371
  type: m.type,
6174
6372
  implementation: { ...m.implementation },
6175
- imports: [...m.imports]
6373
+ imports: [...m.imports],
6374
+ strictMockSchemaTypeNames: m.strictMockSchemaTypeNames ? [...m.strictMockSchemaTypeNames] : void 0,
6375
+ strictMockSchemaKinds: m.strictMockSchemaKinds ? { ...m.strictMockSchemaKinds } : void 0
6176
6376
  }));
6177
6377
  for (const op of opMockOutputs) {
6178
6378
  let acc = result.find((m) => m.type === op.type);
@@ -6182,6 +6382,10 @@ function mergeOperationMockOutputs(accMockOutputs, opMockOutputs) {
6182
6382
  }
6183
6383
  acc.imports.push(...op.imports);
6184
6384
  if (op.strictMockSchemaTypeNames?.length) acc.strictMockSchemaTypeNames = [...new Set([...acc.strictMockSchemaTypeNames ?? [], ...op.strictMockSchemaTypeNames])];
6385
+ if (op.strictMockSchemaKinds) acc.strictMockSchemaKinds = {
6386
+ ...acc.strictMockSchemaKinds,
6387
+ ...op.strictMockSchemaKinds
6388
+ };
6185
6389
  acc.implementation.function += op.implementation.function;
6186
6390
  acc.implementation.handler += op.implementation.handler;
6187
6391
  if (op.implementation.handlerName) {
@@ -6199,7 +6403,9 @@ function initialMockOutputsForOperation(op) {
6199
6403
  handler: m.implementation.handler,
6200
6404
  handlerName: m.implementation.handlerName ? " " + m.implementation.handlerName + "()" : ""
6201
6405
  },
6202
- imports: [...m.imports]
6406
+ imports: [...m.imports],
6407
+ strictMockSchemaTypeNames: m.strictMockSchemaTypeNames ? [...m.strictMockSchemaTypeNames] : void 0,
6408
+ strictMockSchemaKinds: m.strictMockSchemaKinds ? { ...m.strictMockSchemaKinds } : void 0
6203
6409
  }));
6204
6410
  }
6205
6411
  function generateTargetTags(currentAcc, operation) {
@@ -6281,7 +6487,9 @@ function generateTargetForTags(builder, options) {
6281
6487
  handler: m.implementation.handlerName ? m.implementation.handler + header.implementationMock + m.implementation.handlerName + footer.implementationMock : m.implementation.handler,
6282
6488
  handlerName: m.implementation.handlerName
6283
6489
  },
6284
- imports: m.imports
6490
+ imports: m.imports,
6491
+ strictMockSchemaTypeNames: m.strictMockSchemaTypeNames,
6492
+ strictMockSchemaKinds: m.strictMockSchemaKinds
6285
6493
  }));
6286
6494
  transformed[tag] = {
6287
6495
  implementation: header.implementation + target.implementation + footer.implementation,
@@ -6315,23 +6523,17 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
6315
6523
  });
6316
6524
  const target = generateTargetForTags(builder, output);
6317
6525
  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);
6526
+ const mockIndexEntries = [];
6527
+ const seenMockIndexKeys = /* @__PURE__ */ new Set();
6528
+ const schemasTarget = output.schemas ? getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname : nodePath.join(dirname, filename + ".schemas" + getImportExtension(extension, output.tsconfig));
6529
+ const tagEntries = Object.entries(target).toSorted(([a], [b]) => a.localeCompare(b));
6328
6530
  const generatedFilePathsArray = await Promise.all(tagEntries.map(async ([tag, target]) => {
6329
6531
  try {
6330
6532
  const { imports, implementation, mockOutputs, mutators, clientMutators, formData, fetchReviver, formUrlEncoded, paramsSerializer, paramsFilter } = target;
6331
6533
  let implementationData = header;
6332
6534
  const importerPath = nodePath.join(dirname, tag, tag + extension);
6333
6535
  const schemaCustomImportPath = getSchemasImportPath(output.schemas);
6334
- 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$/, "");
6536
+ const relativeSchemasPath = output.schemas ? schemaCustomImportPath ?? getRelativeImportPath(importerPath, getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname) : "../" + filename + ".schemas" + getImportExtension(extension, output.tsconfig);
6335
6537
  const tagNames = new Set(tagEntries.map(([t]) => t));
6336
6538
  const serviceSuffix = OutputClient.ANGULAR === output.client ? ".service" : "";
6337
6539
  const importsForBuilder = generateImportsForBuilder(output, imports.map((imp) => {
@@ -6408,10 +6610,19 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
6408
6610
  await writeGeneratedFile(implementationPath, implementationData);
6409
6611
  const mockPaths = [];
6410
6612
  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);
6414
- const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, getFinalizeMockImplementationOptions(output, mockOutput)) : mockOutput.implementation;
6613
+ const rawEntry = output.mock.generators.find((g) => {
6614
+ if (isFunction(g)) return mockOutput.type === OutputMockType.MSW;
6615
+ return g.type === mockOutput.type;
6616
+ });
6617
+ if (!rawEntry) continue;
6618
+ const mockExtension = isFunction(rawEntry) ? OutputMockType.MSW : getMockFileExtensionByTypeName(rawEntry);
6619
+ const mockDir = getMockDir(rawEntry, output.mock) ?? dirname;
6620
+ const mockFilePath = nodePath.join(mockDir, tag, tag + "." + mockExtension + extension);
6621
+ const mockRelativeSchemasPath = schemaCustomImportPath ?? resolveMockSchemasPath(mockFilePath, schemasTarget);
6622
+ const finalizeMockOptions = getFinalizeMockImplementationOptions(output, mockOutput);
6623
+ const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, finalizeMockOptions) : mockOutput.implementation;
6624
+ 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)) : [];
6625
+ const importsMockForBuilder = generateImportsForBuilder(output, filterLocalStrictMockTypeImports(mergeGeneratorImports(mockOutput.imports, recoveredSchemaFactoryImports), finalizeMockOptions.strictSchemaTypeNames), mockRelativeSchemasPath);
6415
6626
  let mockData = header;
6416
6627
  mockData += builder.importsMock({
6417
6628
  implementation: finalizedMockImplementation,
@@ -6419,12 +6630,23 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
6419
6630
  projectName,
6420
6631
  hasSchemaDir: !!output.schemas,
6421
6632
  isAllowSyntheticDefaultImports,
6422
- options: entry
6633
+ options: isFunction(rawEntry) ? void 0 : rawEntry
6423
6634
  });
6424
6635
  mockData += `\n${finalizedMockImplementation}`;
6425
- const mockPath = nodePath.join(dirname, tag, tag + "." + getMockFileExtensionByTypeName(entry) + extension);
6426
- await writeGeneratedFile(mockPath, mockData);
6427
- mockPaths.push(mockPath);
6636
+ await writeGeneratedFile(mockFilePath, mockData);
6637
+ mockPaths.push(mockFilePath);
6638
+ const indexKey = `${mockExtension}::${mockDir}`;
6639
+ let indexEntry = mockIndexEntries.find((e) => e.ext === mockExtension && e.mockDir === mockDir);
6640
+ if (!indexEntry) {
6641
+ indexEntry = {
6642
+ ext: mockExtension,
6643
+ mockDir,
6644
+ tags: []
6645
+ };
6646
+ mockIndexEntries.push(indexEntry);
6647
+ seenMockIndexKeys.add(indexKey);
6648
+ }
6649
+ if (!indexEntry.tags.includes(tag)) indexEntry.tags.push(tag);
6428
6650
  }
6429
6651
  return [
6430
6652
  implementationPath,
@@ -6435,17 +6657,14 @@ async function writeSplitTagsMode({ builder, output, projectName, header, needSc
6435
6657
  throw new Error(`Oups... 🍻. An Error occurred while splitting tag ${tag} => ${String(error)}`, { cause: error });
6436
6658
  }
6437
6659
  }));
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);
6660
+ if (output.mock.indexMockFiles) {
6661
+ const mockImportExtension = getImportExtension(extension, output.tsconfig);
6662
+ for (const { ext, mockDir, tags } of mockIndexEntries) await writeGeneratedFile(nodePath.join(mockDir, `index.${ext}${extension}`), tags.toSorted((a, b) => a.localeCompare(b)).map((tag) => {
6663
+ const localMockPath = joinSafe("./", tag, tag + "." + ext + mockImportExtension);
6444
6664
  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);
6665
+ }).join(""));
6447
6666
  }
6448
- return [...new Set([...indexFilePathsByType.values(), ...generatedFilePathsArray.flat()])];
6667
+ return [...new Set([...output.mock.indexMockFiles ? mockIndexEntries.map(({ mockDir, ext }) => nodePath.join(mockDir, `index.${ext}${extension}`)) : [], ...generatedFilePathsArray.flat()])];
6449
6668
  }
6450
6669
  //#endregion
6451
6670
  //#region src/writers/tags-mode.ts
@@ -6456,25 +6675,30 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema,
6456
6675
  });
6457
6676
  const target = generateTargetForTags(builder, output);
6458
6677
  const isAllowSyntheticDefaultImports = isSyntheticDefaultImportsAllow(output.tsconfig);
6459
- return (await Promise.all(Object.entries(target).map(async ([tag, target]) => {
6678
+ const shouldDeinlineMocks = hasAnyMockPath(output.mock);
6679
+ const mockIndexEntries = [];
6680
+ const seenMockIndexKeys = /* @__PURE__ */ new Set();
6681
+ const schemaCustomImportPath = getSchemasImportPath(output.schemas);
6682
+ 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);
6683
+ const schemasTarget = output.schemas ? getFileInfo(isString(output.schemas) ? output.schemas : output.schemas.path, { extension: output.fileExtension }).dirname : nodePath.join(dirname, filename + ".schemas" + getImportExtension(extension, output.tsconfig));
6684
+ const tagEntries = Object.entries(target).toSorted(([a], [b]) => a.localeCompare(b));
6685
+ const generatedFilePathsArray = await Promise.all(tagEntries.map(async ([tag, target]) => {
6460
6686
  try {
6461
6687
  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
6688
  const normalizedImports = imports.filter((imp) => {
6470
6689
  const searchWords = [imp.alias, imp.name].filter((part) => Boolean(part?.length)).map((part) => escapeRegExp(part)).join("|");
6471
6690
  if (!searchWords) return false;
6472
6691
  return new RegExp(String.raw`\b(${searchWords})\b`, "g").test(implementation);
6473
6692
  }).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;
6693
+ const collapsedMockOutputs = shouldDeinlineMocks ? [] : collapseInlineMockOutputs(rawMockOutputs);
6694
+ let data = header;
6695
+ if (!shouldDeinlineMocks) {
6696
+ const importsMock = collapsedMockOutputs.flatMap((m) => m.imports);
6697
+ for (const mockImport of importsMock) {
6698
+ const matchingImport = normalizedImports.find((imp) => imp.name === mockImport.name && (imp.alias ?? "") === (mockImport.alias ?? ""));
6699
+ if (!matchingImport) continue;
6700
+ if (!!mockImport.values || !!mockImport.isConstant || !!mockImport.default || !!mockImport.namespaceImport || !!mockImport.syntheticDefaultImport) matchingImport.values = true;
6701
+ }
6478
6702
  }
6479
6703
  const importsForBuilder = generateImportsForBuilder(output, normalizedImports, schemasPathRelative);
6480
6704
  data += builder.imports({
@@ -6490,7 +6714,7 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema,
6490
6714
  packageJson: output.packageJson,
6491
6715
  output
6492
6716
  });
6493
- for (const mockOutput of mockOutputs) {
6717
+ if (!shouldDeinlineMocks) for (const mockOutput of collapsedMockOutputs) {
6494
6718
  const entry = output.mock.generators.find((g) => !isFunction(g) && g.type === mockOutput.type);
6495
6719
  const importsMockForBuilder = generateImportsForBuilder(output, mockOutput.imports.filter((impMock) => !normalizedImports.some((imp) => imp.name === impMock.name && (imp.alias ?? "") === (impMock.alias ?? ""))), schemasPathRelative);
6496
6720
  data += builder.importsMock({
@@ -6524,17 +6748,78 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema,
6524
6748
  data += "\n";
6525
6749
  }
6526
6750
  data += implementation;
6527
- if (mockOutputs.length > 0) {
6528
- data += "\n\n";
6529
- data += finalizedImplementationMock;
6751
+ if (!shouldDeinlineMocks) {
6752
+ const implementationMock = collapsedMockOutputs.map((m) => m.implementation).join("\n\n");
6753
+ const finalizedImplementationMock = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(implementationMock, getFinalizeMockImplementationOptions(output, collapsedMockOutputs)) : implementationMock;
6754
+ if (collapsedMockOutputs.length > 0) {
6755
+ data += "\n\n";
6756
+ data += finalizedImplementationMock;
6757
+ }
6530
6758
  }
6531
- const implementationPath = nodePath.join(dirname, `${kebab(tag)}${extension}`);
6759
+ const kebabTag = kebab(tag);
6760
+ const implementationPath = nodePath.join(dirname, `${kebabTag}${extension}`);
6532
6761
  await writeGeneratedFile(implementationPath, data);
6533
- return [implementationPath, ...schemasPath ? [schemasPath] : []];
6762
+ const extraPaths = [];
6763
+ if (shouldDeinlineMocks) for (const mockOutput of rawMockOutputs) {
6764
+ const rawEntry = output.mock.generators.find((g) => {
6765
+ if (isFunction(g)) return mockOutput.type === OutputMockType.MSW;
6766
+ return g.type === mockOutput.type;
6767
+ });
6768
+ if (!rawEntry) continue;
6769
+ const mockExtension = isFunction(rawEntry) ? OutputMockType.MSW : getMockFileExtensionByTypeName(rawEntry);
6770
+ const mockDir = getMockDir(rawEntry, output.mock) ?? dirname;
6771
+ const mockFilePath = nodePath.join(mockDir, kebabTag, kebabTag + "." + mockExtension + extension);
6772
+ const mockRelativeSchemasPath = schemaCustomImportPath ?? resolveMockSchemasPath(mockFilePath, schemasTarget);
6773
+ const finalizeMockOptions = getFinalizeMockImplementationOptions(output, mockOutput);
6774
+ const finalizedMockImplementation = builder.finalizeMockImplementation ? builder.finalizeMockImplementation(mockOutput.implementation, finalizeMockOptions) : mockOutput.implementation;
6775
+ 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)) : [];
6776
+ const importsMockForBuilder = generateImportsForBuilder(output, filterLocalStrictMockTypeImports(mergeGeneratorImports(mockOutput.imports, recoveredSchemaFactoryImports), finalizeMockOptions.strictSchemaTypeNames), mockRelativeSchemasPath);
6777
+ let mockData = header;
6778
+ mockData += builder.importsMock({
6779
+ implementation: finalizedMockImplementation,
6780
+ imports: importsMockForBuilder,
6781
+ projectName,
6782
+ hasSchemaDir: !!output.schemas,
6783
+ isAllowSyntheticDefaultImports,
6784
+ options: isFunction(rawEntry) ? void 0 : rawEntry
6785
+ });
6786
+ mockData += `\n${finalizedMockImplementation}`;
6787
+ await writeGeneratedFile(mockFilePath, mockData);
6788
+ extraPaths.push(mockFilePath);
6789
+ const indexKey = `${mockExtension}::${mockDir}`;
6790
+ let indexEntry = mockIndexEntries.find((e) => e.ext === mockExtension && e.mockDir === mockDir);
6791
+ if (!indexEntry) {
6792
+ indexEntry = {
6793
+ ext: mockExtension,
6794
+ mockDir,
6795
+ tags: []
6796
+ };
6797
+ mockIndexEntries.push(indexEntry);
6798
+ seenMockIndexKeys.add(indexKey);
6799
+ }
6800
+ if (!indexEntry.tags.includes(kebabTag)) indexEntry.tags.push(kebabTag);
6801
+ }
6802
+ return [
6803
+ implementationPath,
6804
+ ...schemasPath ? [schemasPath] : [],
6805
+ ...extraPaths
6806
+ ];
6534
6807
  } catch (error) {
6535
6808
  throw new Error(`Oups... 🍻. An Error occurred while writing tag ${tag} => ${String(error)}`, { cause: error });
6536
6809
  }
6537
- }))).flat();
6810
+ }));
6811
+ if (shouldDeinlineMocks && output.mock.indexMockFiles) {
6812
+ const mockImportExtension = getImportExtension(extension, output.tsconfig);
6813
+ for (const { ext, mockDir, tags } of mockIndexEntries) {
6814
+ const indexPath = nodePath.join(mockDir, `index.${ext}${extension}`);
6815
+ await writeGeneratedFile(indexPath, tags.toSorted((a, b) => a.localeCompare(b)).map((kebabTag) => {
6816
+ const localMockPath = joinSafe("./", kebabTag, kebabTag + "." + ext + mockImportExtension);
6817
+ return ext === OutputMockType.MSW ? `export { get${pascal(kebabTag)}Mock } from '${localMockPath}'\n` : `export * from '${localMockPath}'\n`;
6818
+ }).join(""));
6819
+ generatedFilePathsArray.push([indexPath]);
6820
+ }
6821
+ }
6822
+ return generatedFilePathsArray.flat();
6538
6823
  }
6539
6824
  //#endregion
6540
6825
  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 };