@orval/mock 8.17.0 → 8.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { DefaultTag, EnumGeneration, OutputMockType, OutputMode, PropertySortOrder, camel, compareVersions, escapeRegExp, generalJSTypesWithArray, generateDependencyImports, getKey, getRefInfo, isBoolean, isFunction, isMswMock, isNumber, isObject, isReference, isSchema, isString, jsStringLiteralEscape, kebab, mergeDeep, pascal, resolveRef, sanitize, stringify } from "@orval/core";
1
+ import { EnumGeneration, OutputMockType, OutputMode, PropertySortOrder, camel, compareVersions, escapeRegExp, generalJSTypesWithArray, generateDependencyImports, getKey, getOperationTagKey, getRefInfo, isBoolean, isFunction, isMswMock, isNumber, isObject, isReference, isSchema, isString, jsStringLiteralEscape, mergeDeep, pascal, resolveRef, sanitize, stringify } from "@orval/core";
2
2
  import { prop } from "remeda";
3
3
  //#region src/mock-types.ts
4
4
  function isStrictMock(mockOptions) {
@@ -20,13 +20,65 @@ export type MockWithNullableOverrides<
20
20
  [K in Extract<KeysWithNull<O>, keyof T>]: M[K] | null;
21
21
  };`;
22
22
  }
23
- function getStrictMockTypeDeclaration(typeName) {
24
- return `export type ${getStrictMockTypeName(typeName)} = {\n [K in keyof Required<${typeName}>]: NonNullable<Required<${typeName}>[K]>;\n};`;
23
+ function classifyStrictMockSchemaType(schema, context) {
24
+ if (!schema) return "object";
25
+ if (schema.format === "binary" || schema.contentMediaType === "application/octet-stream" && !schema.contentEncoding) return "binary";
26
+ if (typeof schema.$ref === "string") {
27
+ if (context) {
28
+ const { schema: resolved } = resolveRef(schema, context);
29
+ return classifyStrictMockSchemaType(resolved, context);
30
+ }
31
+ return "object";
32
+ }
33
+ if (schema.type === "object" || schema.properties || isComposedObjectSchema(schema)) return "object";
34
+ return "alias";
35
+ }
36
+ function isComposedObjectSchema(schema) {
37
+ const branches = schema.oneOf ?? schema.anyOf ?? schema.allOf;
38
+ if (!branches?.length) return false;
39
+ return branches.some((branch) => {
40
+ const item = branch;
41
+ if (typeof item.$ref === "string" || item.type === "object" || item.properties) return true;
42
+ return isComposedObjectSchema(item);
43
+ });
44
+ }
45
+ function getStrictMockTypeDeclaration(typeName, kind = "object", options) {
46
+ const mockTypeName = getStrictMockTypeName(typeName);
47
+ if (kind === "alias") return `export type ${mockTypeName} = ${typeName};`;
48
+ if (kind === "binary") return `export type ${mockTypeName} = ArrayBuffer;`;
49
+ const mappedType = `{\n [K in keyof Required<NonNullable<${typeName}>>]: NonNullable<Required<NonNullable<${typeName}>>[K]>;\n}`;
50
+ return `export type ${mockTypeName} = ${options?.schemaNullableAtRoot ? `${mappedType} | null` : mappedType};`;
25
51
  }
26
- function getStrictMockTypeDeclarations(typeNames) {
52
+ function getStrictMockTypeDeclarations(typeNames, kinds, nullableAtRoot) {
27
53
  const unique = [...new Set(typeNames)];
28
54
  if (unique.length === 0) return "";
29
- return unique.map((typeName) => getStrictMockTypeDeclaration(typeName)).join("\n\n");
55
+ return unique.map((typeName) => getStrictMockTypeDeclaration(typeName, kinds?.[typeName] ?? "object", { schemaNullableAtRoot: nullableAtRoot?.[typeName] })).join("\n\n");
56
+ }
57
+ function strictMockResolvedImportMatches(typeName, resolvedImport, importBareName) {
58
+ const resolvedName = resolvedImport?.name;
59
+ if (!resolvedName) return false;
60
+ if (typeName === resolvedName) return true;
61
+ if (resolvedImport.alias && typeName === resolvedImport.alias) return true;
62
+ return importBareName !== void 0 && importBareName === resolvedName;
63
+ }
64
+ function resolveStrictMockSchemaForTypeName(typeName, originalSchema, context, importBareName) {
65
+ if (!originalSchema) return;
66
+ if (!context) return originalSchema;
67
+ const branches = originalSchema.oneOf ?? originalSchema.anyOf ?? originalSchema.allOf;
68
+ if (branches?.length) {
69
+ for (const branch of branches) {
70
+ if (typeof branch.$ref !== "string") continue;
71
+ const resolved = resolveRef(branch, context);
72
+ if (strictMockResolvedImportMatches(typeName, resolved.imports[0], importBareName)) return resolved.schema;
73
+ }
74
+ return;
75
+ }
76
+ if (typeof originalSchema.$ref === "string") {
77
+ const resolved = resolveRef(originalSchema, context);
78
+ if (strictMockResolvedImportMatches(typeName, resolved.imports[0], importBareName)) return resolved.schema;
79
+ return;
80
+ }
81
+ return originalSchema;
30
82
  }
31
83
  function getMockFactoryReturnType(typeName, mockOptions) {
32
84
  return isStrictMock(mockOptions) ? getStrictMockTypeName(typeName) : typeName;
@@ -73,8 +125,33 @@ function getSchemaTypeNamesFromResponses(responses) {
73
125
  }
74
126
  return [...names];
75
127
  }
76
- function buildStrictMockTypeFileHeader(schemaTypeNames) {
77
- const schemaBlock = getStrictMockTypeDeclarations([...new Set(schemaTypeNames)]);
128
+ function getStrictMockSchemaKindsFromResponses(responses, context) {
129
+ const kinds = {};
130
+ for (const response of responses) {
131
+ for (const imp of response.imports) {
132
+ if (imp.values || imp.schemaFactory) continue;
133
+ const importName = imp.alias ?? imp.name;
134
+ if (!/^[A-Z]\w*$/.test(importName)) continue;
135
+ const schemaForImport = resolveStrictMockSchemaForTypeName(importName, response.originalSchema, context, imp.name);
136
+ if (!schemaForImport) continue;
137
+ kinds[importName] = classifyStrictMockSchemaType(schemaForImport, context);
138
+ }
139
+ const { value } = response;
140
+ if (!value || !response.originalSchema) continue;
141
+ const baseType = value.endsWith("[]") ? value.slice(0, -2) : value;
142
+ if (!/^[A-Z]\w*$/.test(baseType)) continue;
143
+ const schema = response.originalSchema;
144
+ if (value.endsWith("[]") && schema.type === "array" && schema.items) {
145
+ const items = schema.items;
146
+ kinds[baseType] = classifyStrictMockSchemaType(items, context);
147
+ continue;
148
+ }
149
+ kinds[baseType] = classifyStrictMockSchemaType(resolveStrictMockSchemaForTypeName(baseType, response.originalSchema, context) ?? response.originalSchema, context);
150
+ }
151
+ return kinds;
152
+ }
153
+ function buildStrictMockTypeFileHeader(schemaTypeNames, kinds) {
154
+ const schemaBlock = getStrictMockTypeDeclarations([...new Set(schemaTypeNames)], kinds);
78
155
  return [getStrictMockHelperTypeDeclarations(), schemaBlock].filter(Boolean).join("\n\n");
79
156
  }
80
157
  /**
@@ -88,7 +165,7 @@ function dedupeStrictMockTypeDeclarations(implementation, options = {}) {
88
165
  if (!isStrictMock(options.mockOptions)) return implementation;
89
166
  const schemaTypeNames = options.strictSchemaTypeNames ? [...new Set(options.strictSchemaTypeNames)] : [];
90
167
  if (schemaTypeNames.length === 0) return implementation;
91
- return `${buildStrictMockTypeFileHeader(schemaTypeNames)}\n\n${implementation.trimStart()}`;
168
+ return `${buildStrictMockTypeFileHeader(schemaTypeNames, options.strictMockSchemaKinds)}\n\n${implementation.trimStart()}`;
92
169
  }
93
170
  function applyStrictMockReturnType(returnType, schemaTypeNames) {
94
171
  if (schemaTypeNames.length === 0) return returnType;
@@ -128,6 +205,54 @@ function mergeStrictMockSchemaTypeNames(...groups) {
128
205
  }
129
206
  return names.size > 0 ? [...names] : void 0;
130
207
  }
208
+ function mergeStrictMockSchemaKinds(...groups) {
209
+ const merged = {};
210
+ for (const group of groups) {
211
+ if (!group) continue;
212
+ for (const [name, kind] of Object.entries(group)) merged[name] ??= kind;
213
+ }
214
+ return Object.keys(merged).length > 0 ? merged : void 0;
215
+ }
216
+ //#endregion
217
+ //#region src/faker/imports.ts
218
+ /**
219
+ * Appends entries added to `source` since `sinceIndex`. Uses indexed push
220
+ * instead of spread so large import batches (common with `schemas: true`
221
+ * delegation on wide objects) do not overflow the call stack.
222
+ */
223
+ function appendImportsDelta(target, source, sinceIndex) {
224
+ for (let i = sinceIndex; i < source.length; i++) target.push(source[i]);
225
+ }
226
+ /**
227
+ * Merge imports returned from mock resolution when the shared imports array
228
+ * was not mutated in place. Enum mocks and nested object factories return
229
+ * their imports separately; schema-factory delegation mutates `sharedImports`
230
+ * directly and must not be merged again from `resolvedImports`.
231
+ */
232
+ function mergeReturnedMockImports(sharedImports, sharedBefore, resolvedImports) {
233
+ if (sharedImports.length === sharedBefore) appendImportsDelta(sharedImports, resolvedImports, 0);
234
+ }
235
+ /** Recover type imports referenced by nested oneOf split mock helpers. */
236
+ function collectSplitMockTypeImports(implementations) {
237
+ const seen = /* @__PURE__ */ new Set();
238
+ const imports = [];
239
+ const addType = (name) => {
240
+ if (!name || seen.has(name)) return;
241
+ seen.add(name);
242
+ imports.push({
243
+ name,
244
+ values: false
245
+ });
246
+ };
247
+ for (const impl of implementations) {
248
+ for (const match of impl.matchAll(/export const get\w+Mock = \(\s*overrideResponse: Partial<(\w+)[^)]*\):\s*(\w+)\s*=>/g)) {
249
+ addType(match[1]);
250
+ addType(match[2]);
251
+ }
252
+ for (const match of impl.matchAll(/export const get\w+Mock[\s\S]*?MockWithNullableOverrides<(?:Extract<(\w+),[^>]+>|(\w+)),/g)) addType(match[1] ?? match[2]);
253
+ }
254
+ return imports;
255
+ }
131
256
  //#endregion
132
257
  //#region src/delay.ts
133
258
  const getDelay = (override, options) => {
@@ -180,6 +305,13 @@ const DEFAULT_OBJECT_KEY_MOCK = "faker.string.alphanumeric(5)";
180
305
  //#endregion
181
306
  //#region src/faker/getters/object.ts
182
307
  const overrideVarName = "overrideResponse";
308
+ function wrapRootNullableObjectValue(value, schemaItem, mockOptions, combine) {
309
+ const nullableAtRoot = !combine && isNullableSchema(schemaItem) && !mockOptions?.nonNullable;
310
+ return {
311
+ value: nullableAtRoot ? getNullable(value, true) : value,
312
+ nullWrapped: nullableAtRoot
313
+ };
314
+ }
183
315
  function getReferenceName$1(ref, context) {
184
316
  if (!ref) return "";
185
317
  return getRefInfo(ref, context).name;
@@ -222,10 +354,44 @@ function getMockObject({ item, mockOptions, operationId, tags, combine, context,
222
354
  splitMockImplementations
223
355
  });
224
356
  if (Array.isArray(itemType)) {
357
+ const nonNullTypes = mockOptions?.nonNullable ? itemType.filter((type) => type !== "null") : itemType;
358
+ if (nonNullTypes.length === 0) return {
359
+ value: "null",
360
+ imports: [],
361
+ name: schemaItem.name
362
+ };
363
+ if (nonNullTypes.length === 1) return getMockObject({
364
+ item: {
365
+ ...schemaItem,
366
+ type: nonNullTypes[0]
367
+ },
368
+ mockOptions,
369
+ operationId,
370
+ tags,
371
+ combine,
372
+ context,
373
+ imports,
374
+ existingReferencedProperties,
375
+ existingReferencedAllOfRefs,
376
+ splitMockImplementations,
377
+ allowOverride
378
+ });
379
+ if (!itemProperties && (!itemRequired || itemRequired.length === 0) && !itemAdditionalProperties && nonNullTypes.includes("object") && nonNullTypes.includes("null") && nonNullTypes.every((type) => type === "object" || type === "null")) {
380
+ if (mockOptions?.nonNullable) return {
381
+ value: "{}",
382
+ imports: [],
383
+ name: schemaItem.name
384
+ };
385
+ return {
386
+ value: "faker.helpers.arrayElement([{}, null])",
387
+ imports: [],
388
+ name: schemaItem.name
389
+ };
390
+ }
225
391
  const baseItem = schemaItem;
226
392
  return combineSchemasMock({
227
393
  item: {
228
- anyOf: itemType.map((type) => ({
394
+ anyOf: nonNullTypes.map((type) => ({
229
395
  ...baseItem,
230
396
  type
231
397
  })),
@@ -259,6 +425,7 @@ function getMockObject({ item, mockOptions, operationId, tags, combine, context,
259
425
  if (isRequired) return `${getKey(key)}: null`;
260
426
  return;
261
427
  }
428
+ const importsBefore = imports.length;
262
429
  const resolvedValue = resolveMockValue({
263
430
  schema: {
264
431
  ...prop,
@@ -275,7 +442,7 @@ function getMockObject({ item, mockOptions, operationId, tags, combine, context,
275
442
  existingReferencedAllOfRefs: [],
276
443
  splitMockImplementations
277
444
  });
278
- imports.push(...resolvedValue.imports);
445
+ mergeReturnedMockImports(imports, importsBefore, resolvedValue.imports);
279
446
  includedProperties.push(key);
280
447
  const keyDefinition = getKey(key);
281
448
  const hasDefault = "default" in prop && prop.default !== void 0;
@@ -289,25 +456,35 @@ function getMockObject({ item, mockOptions, operationId, tags, combine, context,
289
456
  if (allowOverride) propertyScalars.push(`...${overrideVarName}`);
290
457
  value += propertyScalars.join(", ");
291
458
  value += !combine || combine.separator === "oneOf" || combine.separator === "anyOf" ? "}" : "";
459
+ const { value: finalValue, nullWrapped } = wrapRootNullableObjectValue(value, schemaItem, mockOptions, combine);
292
460
  return {
293
- value,
461
+ value: finalValue,
462
+ nullWrapped,
294
463
  imports,
295
464
  name: schemaItem.name,
296
465
  includedProperties
297
466
  };
298
467
  }
299
468
  if (itemAdditionalProperties) {
300
- if (itemAdditionalProperties === true) return {
301
- value: `{}`,
302
- imports: [],
303
- name: schemaItem.name
304
- };
469
+ if (itemAdditionalProperties === true) {
470
+ const { value: finalValue, nullWrapped } = wrapRootNullableObjectValue(`{}`, schemaItem, mockOptions, combine);
471
+ return {
472
+ value: finalValue,
473
+ nullWrapped,
474
+ imports: [],
475
+ name: schemaItem.name
476
+ };
477
+ }
305
478
  const additionalProperties = itemAdditionalProperties;
306
- if (isReference(additionalProperties) && existingReferencedProperties.includes(getReferenceName$1(additionalProperties.$ref, context))) return {
307
- value: `{}`,
308
- imports: [],
309
- name: schemaItem.name
310
- };
479
+ if (isReference(additionalProperties) && existingReferencedProperties.includes(getReferenceName$1(additionalProperties.$ref, context))) {
480
+ const { value: finalValue, nullWrapped } = wrapRootNullableObjectValue(`{}`, schemaItem, mockOptions, combine);
481
+ return {
482
+ value: finalValue,
483
+ nullWrapped,
484
+ imports: [],
485
+ name: schemaItem.name
486
+ };
487
+ }
311
488
  const resolvedValue = resolveMockValue({
312
489
  schema: {
313
490
  ...additionalProperties,
@@ -323,15 +500,19 @@ function getMockObject({ item, mockOptions, operationId, tags, combine, context,
323
500
  existingReferencedAllOfRefs: [],
324
501
  splitMockImplementations
325
502
  });
503
+ const { value: finalValue, nullWrapped } = wrapRootNullableObjectValue(`{
504
+ [${DEFAULT_OBJECT_KEY_MOCK}]: ${resolvedValue.value}
505
+ }`, schemaItem, mockOptions, combine);
326
506
  return {
327
507
  ...resolvedValue,
328
- value: `{
329
- [${DEFAULT_OBJECT_KEY_MOCK}]: ${resolvedValue.value}
330
- }`
508
+ value: finalValue,
509
+ nullWrapped
331
510
  };
332
511
  }
512
+ const { value: finalValue, nullWrapped } = wrapRootNullableObjectValue("{}", schemaItem, mockOptions, combine);
333
513
  return {
334
- value: "{}",
514
+ value: finalValue,
515
+ nullWrapped,
335
516
  imports: [],
336
517
  name: schemaItem.name
337
518
  };
@@ -347,7 +528,7 @@ function getArrayItemMockFileScope(context, tags) {
347
528
  const mode = context.output.mode;
348
529
  const mockType = context.activeMockOutputType ?? OutputMockType.MSW;
349
530
  let base;
350
- if (mode === OutputMode.TAGS || mode === OutputMode.TAGS_SPLIT) base = `tag:${kebab(tags.length > 0 ? tags[0] : DefaultTag)}`;
531
+ if (mode === OutputMode.TAGS || mode === OutputMode.TAGS_SPLIT) base = `tag:${getOperationTagKey({ tags })}`;
351
532
  else if (mode === OutputMode.SPLIT) base = "split";
352
533
  else base = "single";
353
534
  return `${base}:${mockType}`;
@@ -463,8 +644,8 @@ function extractArrayItemMock({ items, propertyName, parentName, operationId, ta
463
644
  if (!names) return;
464
645
  const { factoryName, typeName } = names;
465
646
  const fileLevelFactories = getFileLevelExtractedFactories(context, getArrayItemMockFileScope(context, tags));
647
+ const mockOptions = context.output.override.mock;
466
648
  if (!(fileLevelFactories.has(factoryName) || splitMockImplementations.some((f) => f.includes(`export const ${factoryName}`)))) {
467
- const mockOptions = context.output.override.mock;
468
649
  const { param, returnType, returnCast } = getMockFactorySignatureParts(typeName, mockOptions, {
469
650
  isOverridable: true,
470
651
  overrideType: `Partial<${typeName}>`
@@ -474,7 +655,116 @@ function extractArrayItemMock({ items, propertyName, parentName, operationId, ta
474
655
  fileLevelFactories.add(factoryName);
475
656
  }
476
657
  imports.push({ name: typeName });
477
- return `{...${factoryName}()}`;
658
+ return `{...${factoryName}()${isStrictMock(mockOptions) ? ` as ${getStrictMockTypeName(typeName)}` : ""}}`;
659
+ }
660
+ //#endregion
661
+ //#region src/faker/format-example-value.ts
662
+ const DATE_FORMATS = new Set(["date", "date-time"]);
663
+ function isDateFormat(format) {
664
+ return format !== void 0 && DATE_FORMATS.has(format);
665
+ }
666
+ function isSchemaObject(schema) {
667
+ return typeof schema === "object" && schema !== null && !Array.isArray(schema);
668
+ }
669
+ function resolveSchema(schema, context) {
670
+ if (!schema) return;
671
+ if (isReference(schema)) return resolveRef(schema, context).schema;
672
+ return schema;
673
+ }
674
+ function mergePropertySchemas(...schemas) {
675
+ const merged = {};
676
+ for (const schema of schemas) {
677
+ if (!schema?.properties) continue;
678
+ for (const [key, prop] of Object.entries(schema.properties)) if (isSchemaObject(prop)) merged[key] = prop;
679
+ }
680
+ return merged;
681
+ }
682
+ function getEffectiveScalarFormat(resolved, context) {
683
+ if (!resolved) return;
684
+ if (isDateFormat(resolved.format)) return resolved.format;
685
+ const oneOf = resolved.oneOf;
686
+ const anyOf = resolved.anyOf;
687
+ for (const variant of [...oneOf ?? [], ...anyOf ?? []]) {
688
+ const resolvedVariant = resolveSchema(isReference(variant) || isSchemaObject(variant) ? variant : void 0, context);
689
+ if (isDateFormat(resolvedVariant?.format)) return resolvedVariant.format;
690
+ }
691
+ }
692
+ /**
693
+ * Resolves compositional schemas (allOf / oneOf / anyOf) so example formatting
694
+ * can see property formats on nested and referenced types.
695
+ */
696
+ function resolveExampleSchema(schema, context, seenRefs = /* @__PURE__ */ new Set()) {
697
+ if (!schema) return;
698
+ if (isReference(schema)) {
699
+ const ref = schema.$ref;
700
+ if (ref && seenRefs.has(ref)) return resolveRef(schema, context).schema;
701
+ if (ref) seenRefs = new Set(seenRefs).add(ref);
702
+ }
703
+ const resolved = resolveSchema(schema, context);
704
+ if (!resolved) return;
705
+ const allOf = resolved.allOf;
706
+ const oneOf = resolved.oneOf;
707
+ const anyOf = resolved.anyOf;
708
+ const compositors = [
709
+ ...allOf ?? [],
710
+ ...oneOf ?? [],
711
+ ...anyOf ?? []
712
+ ];
713
+ const properties = mergePropertySchemas(resolved, ...compositors.map((sub) => resolveExampleSchema(sub, context, seenRefs)));
714
+ const baseResolved = resolved;
715
+ if (resolved.type === "array" && isSchemaObject(resolved.items)) {
716
+ const items = resolveExampleSchema(resolved.items, context, seenRefs);
717
+ const itemProperties = items?.properties;
718
+ const normalizedItems = itemProperties && Object.keys(itemProperties).length > 0 ? {
719
+ type: "object",
720
+ properties: itemProperties
721
+ } : items;
722
+ return {
723
+ ...baseResolved,
724
+ ...Object.keys(properties).length > 0 ? { properties } : {},
725
+ items: normalizedItems ?? resolved.items
726
+ };
727
+ }
728
+ if (Object.keys(properties).length > 0) return {
729
+ ...baseResolved,
730
+ properties
731
+ };
732
+ if (compositors.length > 0 && (oneOf ?? anyOf)) {
733
+ const variantProperties = mergePropertySchemas(...compositors.map((sub) => resolveExampleSchema(sub, context, seenRefs)));
734
+ if (Object.keys(variantProperties).length > 0) return {
735
+ type: "object",
736
+ properties: variantProperties
737
+ };
738
+ }
739
+ const scalarFormat = getEffectiveScalarFormat(resolved, context);
740
+ if (scalarFormat) return {
741
+ ...baseResolved,
742
+ format: scalarFormat
743
+ };
744
+ return resolved;
745
+ }
746
+ function formatLiteralValue(example, schema, context) {
747
+ if (example === null) return "null";
748
+ if (example === void 0) return "undefined";
749
+ const resolved = resolveExampleSchema(schema, context);
750
+ if (Array.isArray(example)) {
751
+ const itemsSchema = resolved?.type === "array" && isSchemaObject(resolved.items) ? resolveExampleSchema(resolved.items, context) : resolved;
752
+ return `[${example.map((item) => formatLiteralValue(item, itemsSchema, context)).join(", ")}]`;
753
+ }
754
+ if (typeof example === "object") {
755
+ const properties = resolved?.properties ?? {};
756
+ return `{ ${Object.entries(example).map(([key, value]) => {
757
+ const propSchema = properties[key];
758
+ const resolvedProp = isSchemaObject(propSchema) ? resolveExampleSchema(propSchema, context) : void 0;
759
+ return `${/^[a-zA-Z_$][\w$]*$/.test(key) ? key : JSON.stringify(key)}: ${formatLiteralValue(value, resolvedProp, context)}`;
760
+ }).join(", ")} }`;
761
+ }
762
+ if (context.output.override.useDates && typeof example === "string" && isDateFormat(getEffectiveScalarFormat(resolved, context))) return `new Date(${JSON.stringify(example)})`;
763
+ return JSON.stringify(example);
764
+ }
765
+ function formatSchemaExampleValue(example, schema, context) {
766
+ if (!context.output.override.useDates || schema === void 0) return JSON.stringify(example);
767
+ return formatLiteralValue(example, schema, context);
478
768
  }
479
769
  //#endregion
480
770
  //#region src/faker/getters/scalar.ts
@@ -492,12 +782,15 @@ function getMockScalar({ item, imports, mockOptions, operationId, tags, combine,
492
782
  }
493
783
  const tagProperty = resolveMockOverride(overrideTag.properties, item, nonNullableOption);
494
784
  if (tagProperty) return tagProperty;
785
+ const schemaName = item.parentName;
786
+ const schemaProperty = schemaName ? resolveMockOverride(safeMockOptions.schemas?.[schemaName]?.properties, item, nonNullableOption) : void 0;
787
+ if (schemaProperty) return schemaProperty;
495
788
  const property = resolveMockOverride(safeMockOptions.properties, item, nonNullableOption);
496
789
  if (property) return property;
497
790
  if (context.output.override.mock?.useExamples || safeMockOptions.useExamples) {
498
791
  const propertyExample = item.example === void 0 ? Array.isArray(item.examples) && item.examples.length > 0 ? item.examples[0] : void 0 : item.example;
499
792
  if (propertyExample !== void 0) return {
500
- value: JSON.stringify(propertyExample),
793
+ value: formatSchemaExampleValue(propertyExample, item, context),
501
794
  imports: [],
502
795
  name: item.name,
503
796
  overrided: true
@@ -820,6 +1113,11 @@ function isComponentsSchemaRef(refPaths) {
820
1113
  * the schema body so the override actually applies; the shared
821
1114
  * `get<X>Mock` factory has no knowledge of operation-scoped overrides.
822
1115
  *
1116
+ * Schema-scoped overrides (`override.mock.schemas`) need no special handling
1117
+ * here: they target a schema's *own* properties, so the schema's `get<X>Mock`
1118
+ * factory — built with the same mock options — already bakes them in, and
1119
+ * delegating to it preserves the override.
1120
+ *
823
1121
  * Reuses `resolveMockOverride` so the same matching rules apply as for
824
1122
  * regular property mocks — bare name, regex (`/.../`), and exact-path
825
1123
  * (`#.foo.bar`). The parent's `path` (where the `$ref` appears in the
@@ -878,19 +1176,28 @@ function resolveMockValue({ schema, mockOptions, operationId, tags, combine, con
878
1176
  const newSeparator = newSchema.allOf ? "allOf" : newSchema.oneOf ? "oneOf" : "anyOf";
879
1177
  if (shouldDelegateToSchemaFactories(context) && isComponentsSchemaRef(refPaths) && !hasOverrideTouchingSchema(schemaRef?.properties, mockOptions, operationId, tags, schemaReference.path)) {
880
1178
  const factoryName = `get${pascal(name)}Mock`;
881
- imports.push({
1179
+ const factoryImport = {
882
1180
  name: factoryName,
883
1181
  values: true,
884
1182
  schemaFactory: true
885
- });
1183
+ };
1184
+ const isObjectLike = newSchema.type === "object" || !!newSchema.allOf || resolvesToObjectLike(newSchema, context);
1185
+ const mockTypeName = getStrictMockTypeName(pascal(name));
1186
+ const strictMockTypeImport = isStrictMock(mockOptions) && isObjectLike ? {
1187
+ name: mockTypeName,
1188
+ values: false,
1189
+ schemaFactory: true
1190
+ } : void 0;
1191
+ const strictObjectCast = isStrictMock(mockOptions) && isObjectLike ? ` as ${mockTypeName}` : "";
886
1192
  return {
887
- value: getNullable(newSchema.type === "object" || !!newSchema.allOf || resolvesToObjectLike(newSchema, context) ? `{ ...${factoryName}() }` : `${factoryName}()`, Boolean(newSchema.nullable), mockOptions?.nonNullable),
888
- imports,
1193
+ value: getNullable(isObjectLike ? `{ ...${factoryName}()${strictObjectCast} }` : `${factoryName}()`, Boolean(newSchema.nullable), mockOptions?.nonNullable),
1194
+ imports: strictMockTypeImport ? [factoryImport, strictMockTypeImport] : [factoryImport],
889
1195
  name: newSchema.name,
890
1196
  type: getType(newSchema),
891
1197
  nullWrapped: Boolean(newSchema.nullable) && !mockOptions?.nonNullable
892
1198
  };
893
1199
  }
1200
+ const importsBefore = imports.length;
894
1201
  const scalar = getMockScalar({
895
1202
  item: newSchema,
896
1203
  mockOptions,
@@ -921,27 +1228,36 @@ function resolveMockValue({ schema, mockOptions, operationId, tags, combine, con
921
1228
  splitMockImplementations.push(func);
922
1229
  }
923
1230
  scalar.value = newSchema.nullable ? `${funcName}()` : `{...${funcName}()}`;
924
- scalar.imports.push({ name: newSchema.name });
1231
+ const typeImport = {
1232
+ name: newSchema.name,
1233
+ values: false
1234
+ };
1235
+ scalar.imports.push(typeImport);
1236
+ if (scalar.imports !== imports) imports.push(typeImport);
925
1237
  }
1238
+ mergeReturnedMockImports(imports, importsBefore, scalar.imports);
926
1239
  return {
927
1240
  ...scalar,
928
1241
  type: getType(newSchema)
929
1242
  };
930
1243
  }
1244
+ const importsBefore = imports.length;
1245
+ const scalar = getMockScalar({
1246
+ item: schema,
1247
+ mockOptions,
1248
+ operationId,
1249
+ tags,
1250
+ combine,
1251
+ context,
1252
+ imports,
1253
+ existingReferencedProperties,
1254
+ existingReferencedAllOfRefs,
1255
+ splitMockImplementations,
1256
+ allowOverride
1257
+ });
1258
+ mergeReturnedMockImports(imports, importsBefore, scalar.imports);
931
1259
  return {
932
- ...getMockScalar({
933
- item: schema,
934
- mockOptions,
935
- operationId,
936
- tags,
937
- combine,
938
- context,
939
- imports,
940
- existingReferencedProperties,
941
- existingReferencedAllOfRefs,
942
- splitMockImplementations,
943
- allowOverride
944
- }),
1260
+ ...scalar,
945
1261
  type: getType(schema)
946
1262
  };
947
1263
  }
@@ -1138,6 +1454,14 @@ function getMockWithoutFunc(spec, override) {
1138
1454
  }
1139
1455
  return tagMocks;
1140
1456
  })() : void 0;
1457
+ const schemas = override?.mock?.schemas ? (() => {
1458
+ const schemaMocks = {};
1459
+ for (const [key, value] of Object.entries(override.mock.schemas)) {
1460
+ if (!value?.properties) continue;
1461
+ schemaMocks[key] = { properties: getMockPropertiesWithoutFunc(value.properties, spec) };
1462
+ }
1463
+ return schemaMocks;
1464
+ })() : void 0;
1141
1465
  return {
1142
1466
  arrayMin: override?.mock?.arrayMin,
1143
1467
  arrayMax: override?.mock?.arrayMax,
@@ -1151,7 +1475,8 @@ function getMockWithoutFunc(spec, override) {
1151
1475
  ...override?.mock?.properties ? { properties: getMockPropertiesWithoutFunc(override.mock.properties, spec) } : {},
1152
1476
  ...override?.mock?.format ? { format: getMockPropertiesWithoutFunc(override.mock.format, spec) } : {},
1153
1477
  ...operations ? { operations } : {},
1154
- ...tags ? { tags } : {}
1478
+ ...tags ? { tags } : {},
1479
+ ...schemas ? { schemas } : {}
1155
1480
  };
1156
1481
  }
1157
1482
  function getMockNumberOption(mockOptionsWithoutFunc, key) {
@@ -1201,7 +1526,8 @@ function getResponsesMockDefinition({ operationId, tags, returnType, responses,
1201
1526
  if (context.output.override.mock?.useExamples || mockOptions?.useExamples) {
1202
1527
  const exampleValue = unwrapExampleValue(example ?? originalSchema?.example ?? getExampleEntries(examples)[0] ?? getExampleEntries(originalSchema?.examples)[0]);
1203
1528
  if (exampleValue !== void 0) {
1204
- result.definitions.push(transformer ? transformer(exampleValue, returnType) : JSON.stringify(exampleValue));
1529
+ const formatted = formatSchemaExampleValue(exampleValue, originalSchema, context);
1530
+ result.definitions.push(transformer ? transformer(formatted, returnType) : formatted);
1205
1531
  continue;
1206
1532
  }
1207
1533
  }
@@ -1216,13 +1542,15 @@ function getResponsesMockDefinition({ operationId, tags, returnType, responses,
1216
1542
  };
1217
1543
  else if (!originalSchema) continue;
1218
1544
  const resolvedSchema = resolveRef(originalSchema, context).schema;
1545
+ const responseImports = imports ?? [];
1546
+ const importsBefore = responseImports.length;
1219
1547
  const scalar = getMockScalar({
1220
1548
  item: {
1221
1549
  ...resolvedSchema,
1222
1550
  name: definition,
1223
1551
  ...context.output.override.enumGenerationType === "enum" && isRef ? { isRef: true } : {}
1224
1552
  },
1225
- imports,
1553
+ imports: responseImports,
1226
1554
  mockOptions: mockOptionsWithoutFunc,
1227
1555
  operationId,
1228
1556
  tags,
@@ -1231,9 +1559,11 @@ function getResponsesMockDefinition({ operationId, tags, returnType, responses,
1231
1559
  splitMockImplementations,
1232
1560
  allowOverride: true
1233
1561
  });
1234
- result.imports.push(...scalar.imports);
1562
+ appendImportsDelta(result.imports, responseImports, importsBefore);
1563
+ if (scalar.imports !== responseImports) appendImportsDelta(result.imports, scalar.imports, 0);
1235
1564
  result.definitions.push(transformer ? transformer(scalar.value, returnType) : scalar.value);
1236
1565
  }
1566
+ appendImportsDelta(result.imports, collectSplitMockTypeImports(splitMockImplementations), 0);
1237
1567
  return result;
1238
1568
  }
1239
1569
  function getMockDefinition({ operationId, tags, returnType, responses, override, transformer, context, mockOptions, splitMockImplementations }) {
@@ -1437,7 +1767,8 @@ export const ${handlerName} = (overrideResponse?: ${mockReturnType} | ((${infoPa
1437
1767
  handler: handlerImplementation
1438
1768
  },
1439
1769
  imports: includeResponseImports,
1440
- strictMockSchemaTypeNames: strictMock ? mergeStrictMockSchemaTypeNames(schemaTypeNames, collectStrictMockSchemaTypeNamesFromImplementation(mockImplementation)) : void 0
1770
+ strictMockSchemaTypeNames: strictMock ? mergeStrictMockSchemaTypeNames(schemaTypeNames, collectStrictMockSchemaTypeNamesFromImplementation(mockImplementation)) : void 0,
1771
+ strictMockSchemaKinds: strictMock ? mergeStrictMockSchemaKinds(getStrictMockSchemaKindsFromResponses(responses, context), Object.fromEntries((collectStrictMockSchemaTypeNamesFromImplementation(mockImplementation) ?? []).map((name) => [name, "object"]))) : void 0
1441
1772
  };
1442
1773
  }
1443
1774
  function generateMSW(generatorVerbOptions, generatorOptions) {
@@ -1454,12 +1785,14 @@ function generateMSW(generatorVerbOptions, generatorOptions) {
1454
1785
  const handlerImplementations = [baseDefinition.implementation.handler];
1455
1786
  const imports = [...baseDefinition.imports];
1456
1787
  const strictMockSchemaTypeNames = new Set(baseDefinition.strictMockSchemaTypeNames);
1788
+ const strictMockSchemaKinds = { ...baseDefinition.strictMockSchemaKinds };
1457
1789
  if (generatorOptions.mock && isObject(generatorOptions.mock) && generatorOptions.mock.generateEachHttpStatus) for (const statusResponse of [...response.types.success, ...response.types.errors]) {
1458
1790
  const definition = generateDefinition(statusResponse.key, route, getResponseMockFunctionName, handlerName, generatorVerbOptions, generatorOptions, statusResponse.value, statusResponse.key, response.imports, [statusResponse], [statusResponse.contentType], splitMockImplementations);
1459
1791
  mockImplementations.push(definition.implementation.function);
1460
1792
  handlerImplementations.push(definition.implementation.handler);
1461
1793
  imports.push(...definition.imports);
1462
1794
  for (const name of definition.strictMockSchemaTypeNames ?? []) strictMockSchemaTypeNames.add(name);
1795
+ if (definition.strictMockSchemaKinds) for (const [name, kind] of Object.entries(definition.strictMockSchemaKinds)) strictMockSchemaKinds[name] ??= kind;
1463
1796
  }
1464
1797
  const aggregatedStrictNames = [...strictMockSchemaTypeNames];
1465
1798
  return {
@@ -1469,7 +1802,8 @@ function generateMSW(generatorVerbOptions, generatorOptions) {
1469
1802
  handler: handlerImplementations.join("\n")
1470
1803
  },
1471
1804
  imports,
1472
- strictMockSchemaTypeNames: aggregatedStrictNames.length > 0 ? aggregatedStrictNames : void 0
1805
+ strictMockSchemaTypeNames: aggregatedStrictNames.length > 0 ? aggregatedStrictNames : void 0,
1806
+ strictMockSchemaKinds: mergeStrictMockSchemaKinds(strictMockSchemaKinds)
1473
1807
  };
1474
1808
  }
1475
1809
  //#endregion
@@ -1507,7 +1841,8 @@ function generateFaker(generatorVerbOptions, generatorOptions) {
1507
1841
  handlerName: ""
1508
1842
  },
1509
1843
  imports: result.imports,
1510
- strictMockSchemaTypeNames: result.strictMockSchemaTypeNames
1844
+ strictMockSchemaTypeNames: result.strictMockSchemaTypeNames,
1845
+ strictMockSchemaKinds: result.strictMockSchemaKinds
1511
1846
  };
1512
1847
  }
1513
1848
  /**
@@ -1522,38 +1857,47 @@ function generateFaker(generatorVerbOptions, generatorOptions) {
1522
1857
  function generateFakerForSchemas(schemas, context, options) {
1523
1858
  const factories = [];
1524
1859
  const strictMockTypeNames = /* @__PURE__ */ new Set();
1860
+ const strictMockSchemaKinds = {};
1525
1861
  const allImports = [];
1526
1862
  const splitMockImplementations = [];
1527
1863
  const localFactoryNames = new Set(schemas.filter((s) => !!s.schema).map((s) => `get${pascal(s.name)}Mock`));
1864
+ const localMockTypeNames = new Set(schemas.filter((s) => !!s.schema).map((s) => getStrictMockTypeName(pascal(s.name))));
1528
1865
  const mockOptions = getMockWithoutFunc(context.spec, context.output.override);
1529
1866
  for (const generatorSchema of schemas) {
1530
1867
  const { name, schema } = generatorSchema;
1531
1868
  if (!schema) continue;
1532
1869
  const factoryName = `get${pascal(name)}Mock`;
1533
1870
  const factoryImports = [];
1871
+ const factoryImportsBefore = factoryImports.length;
1872
+ const schemaName = pascal(name);
1534
1873
  const result = getMockScalar({
1535
1874
  item: {
1536
1875
  ...schema,
1537
- name
1876
+ name: schemaName
1538
1877
  },
1539
1878
  imports: factoryImports,
1540
1879
  mockOptions,
1541
1880
  operationId: name,
1542
1881
  tags: [],
1543
1882
  context,
1544
- existingReferencedProperties: [],
1883
+ existingReferencedProperties: [schemaName],
1884
+ existingReferencedAllOfRefs: [schemaName],
1545
1885
  splitMockImplementations,
1546
1886
  allowOverride: true,
1547
1887
  isRef: false
1548
1888
  });
1549
- allImports.push(...result.imports, ...factoryImports);
1889
+ appendImportsDelta(allImports, factoryImports, factoryImportsBefore);
1890
+ if (result.imports !== factoryImports) appendImportsDelta(allImports, result.imports, 0);
1550
1891
  const typeName = pascal(name);
1551
1892
  const { param, returnType, returnCast } = getMockFactorySignatureParts(typeName, mockOptions, {
1552
1893
  isOverridable: result.value.includes("overrideResponse"),
1553
1894
  overrideType: `Partial<${typeName}>`
1554
1895
  });
1555
1896
  const factory = formatMockFactoryDeclaration(factoryName, param, returnType, result.value, returnCast);
1556
- if (isStrictMock(mockOptions)) strictMockTypeNames.add(typeName);
1897
+ if (isStrictMock(mockOptions)) {
1898
+ strictMockTypeNames.add(typeName);
1899
+ strictMockSchemaKinds[typeName] = classifyStrictMockSchemaType(schema);
1900
+ }
1557
1901
  factories.push(factory);
1558
1902
  allImports.push({
1559
1903
  name: pascal(name),
@@ -1563,6 +1907,7 @@ function generateFakerForSchemas(schemas, context, options) {
1563
1907
  const mergedImports = /* @__PURE__ */ new Map();
1564
1908
  for (const imp of allImports) {
1565
1909
  if (imp.schemaFactory && localFactoryNames.has(imp.name)) continue;
1910
+ if (imp.schemaFactory && !imp.values && localMockTypeNames.has(imp.name)) continue;
1566
1911
  const key = `${imp.name}::${imp.alias ?? ""}`;
1567
1912
  const existing = mergedImports.get(key);
1568
1913
  if (!existing) {
@@ -1573,11 +1918,16 @@ function generateFakerForSchemas(schemas, context, options) {
1573
1918
  }
1574
1919
  const uniqueImports = [...mergedImports.values()];
1575
1920
  const implementation = [...splitMockImplementations, ...factories].filter(Boolean).join("\n\n");
1921
+ for (const name of collectStrictMockSchemaTypeNamesFromImplementation(implementation)) {
1922
+ strictMockTypeNames.add(name);
1923
+ strictMockSchemaKinds[name] ??= "object";
1924
+ }
1576
1925
  const aggregatedStrictNames = [...strictMockTypeNames];
1577
1926
  return {
1578
1927
  implementation,
1579
1928
  imports: uniqueImports,
1580
- strictMockSchemaTypeNames: aggregatedStrictNames.length > 0 ? aggregatedStrictNames : void 0
1929
+ strictMockSchemaTypeNames: aggregatedStrictNames.length > 0 ? aggregatedStrictNames : void 0,
1930
+ strictMockSchemaKinds: mergeStrictMockSchemaKinds(strictMockSchemaKinds)
1581
1931
  };
1582
1932
  }
1583
1933
  //#endregion