@orval/mock 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.d.mts +3 -2
- package/dist/index.mjs +442 -68
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DefaultTag, EnumGeneration, OutputMockType, OutputMode, PropertySortOrder, camel, compareVersions,
|
|
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";
|
|
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
|
|
24
|
-
|
|
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
|
|
77
|
-
const
|
|
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;
|
|
@@ -97,6 +174,85 @@ function applyStrictMockReturnType(returnType, schemaTypeNames) {
|
|
|
97
174
|
for (const name of sorted) result = result.replaceAll(new RegExp(String.raw`\b${escapeRegExp(name)}\b`, "g"), getStrictMockTypeName(name));
|
|
98
175
|
return result;
|
|
99
176
|
}
|
|
177
|
+
const STRICT_MOCK_SCHEMA_TYPE_FROM_OVERRIDES = /MockWithNullableOverrides<([A-Z]\w*),/g;
|
|
178
|
+
const STRICT_MOCK_SCHEMA_TYPE_FROM_OVERRIDE_ALIAS = /MockWithNullableOverrides<[^,]+,\s*[^,]+,\s*([A-Z]\w*Mock)>/g;
|
|
179
|
+
const STRICT_MOCK_SCHEMA_TYPE_FROM_MOCK_ALIAS_RETURN = /\): ([A-Z]\w*Mock)(?:\[\]|;)/g;
|
|
180
|
+
/** Inverse of {@link getStrictMockTypeName}: `PetMock` → `Pet`, `WidgetMockMock` → `WidgetMock`. */
|
|
181
|
+
function getSchemaTypeNameFromStrictMockAlias(alias) {
|
|
182
|
+
return alias.endsWith("Mock") ? alias.slice(0, -4) : alias;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Collect schema type names referenced by strict mock factories in generated
|
|
186
|
+
* implementation text (nested split factories, array item helpers, etc.).
|
|
187
|
+
*
|
|
188
|
+
* This reverse-parses emitted factory syntax and is therefore coupled to the
|
|
189
|
+
* current `formatMockFactoryDeclaration` / `getMockFactorySignatureParts`
|
|
190
|
+
* shape. The structurally robust alternative is to record each nested item's
|
|
191
|
+
* schema name where split factories are generated (array-item / faker getters,
|
|
192
|
+
* where the `$ref` name is known) and thread it into `strictMockSchemaTypeNames`.
|
|
193
|
+
*/
|
|
194
|
+
function collectStrictMockSchemaTypeNamesFromImplementation(implementation) {
|
|
195
|
+
const names = /* @__PURE__ */ new Set();
|
|
196
|
+
for (const match of implementation.matchAll(STRICT_MOCK_SCHEMA_TYPE_FROM_OVERRIDES)) names.add(match[1]);
|
|
197
|
+
for (const pattern of [STRICT_MOCK_SCHEMA_TYPE_FROM_OVERRIDE_ALIAS, STRICT_MOCK_SCHEMA_TYPE_FROM_MOCK_ALIAS_RETURN]) for (const match of implementation.matchAll(pattern)) names.add(getSchemaTypeNameFromStrictMockAlias(match[1]));
|
|
198
|
+
return [...names];
|
|
199
|
+
}
|
|
200
|
+
function mergeStrictMockSchemaTypeNames(...groups) {
|
|
201
|
+
const names = /* @__PURE__ */ new Set();
|
|
202
|
+
for (const group of groups) {
|
|
203
|
+
if (!group) continue;
|
|
204
|
+
for (const name of group) names.add(name);
|
|
205
|
+
}
|
|
206
|
+
return names.size > 0 ? [...names] : void 0;
|
|
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
|
+
}
|
|
100
256
|
//#endregion
|
|
101
257
|
//#region src/delay.ts
|
|
102
258
|
const getDelay = (override, options) => {
|
|
@@ -149,6 +305,13 @@ const DEFAULT_OBJECT_KEY_MOCK = "faker.string.alphanumeric(5)";
|
|
|
149
305
|
//#endregion
|
|
150
306
|
//#region src/faker/getters/object.ts
|
|
151
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
|
+
}
|
|
152
315
|
function getReferenceName$1(ref, context) {
|
|
153
316
|
if (!ref) return "";
|
|
154
317
|
return getRefInfo(ref, context).name;
|
|
@@ -191,10 +354,44 @@ function getMockObject({ item, mockOptions, operationId, tags, combine, context,
|
|
|
191
354
|
splitMockImplementations
|
|
192
355
|
});
|
|
193
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
|
+
}
|
|
194
391
|
const baseItem = schemaItem;
|
|
195
392
|
return combineSchemasMock({
|
|
196
393
|
item: {
|
|
197
|
-
anyOf:
|
|
394
|
+
anyOf: nonNullTypes.map((type) => ({
|
|
198
395
|
...baseItem,
|
|
199
396
|
type
|
|
200
397
|
})),
|
|
@@ -228,6 +425,7 @@ function getMockObject({ item, mockOptions, operationId, tags, combine, context,
|
|
|
228
425
|
if (isRequired) return `${getKey(key)}: null`;
|
|
229
426
|
return;
|
|
230
427
|
}
|
|
428
|
+
const importsBefore = imports.length;
|
|
231
429
|
const resolvedValue = resolveMockValue({
|
|
232
430
|
schema: {
|
|
233
431
|
...prop,
|
|
@@ -244,7 +442,7 @@ function getMockObject({ item, mockOptions, operationId, tags, combine, context,
|
|
|
244
442
|
existingReferencedAllOfRefs: [],
|
|
245
443
|
splitMockImplementations
|
|
246
444
|
});
|
|
247
|
-
imports
|
|
445
|
+
mergeReturnedMockImports(imports, importsBefore, resolvedValue.imports);
|
|
248
446
|
includedProperties.push(key);
|
|
249
447
|
const keyDefinition = getKey(key);
|
|
250
448
|
const hasDefault = "default" in prop && prop.default !== void 0;
|
|
@@ -258,25 +456,35 @@ function getMockObject({ item, mockOptions, operationId, tags, combine, context,
|
|
|
258
456
|
if (allowOverride) propertyScalars.push(`...${overrideVarName}`);
|
|
259
457
|
value += propertyScalars.join(", ");
|
|
260
458
|
value += !combine || combine.separator === "oneOf" || combine.separator === "anyOf" ? "}" : "";
|
|
459
|
+
const { value: finalValue, nullWrapped } = wrapRootNullableObjectValue(value, schemaItem, mockOptions, combine);
|
|
261
460
|
return {
|
|
262
|
-
value,
|
|
461
|
+
value: finalValue,
|
|
462
|
+
nullWrapped,
|
|
263
463
|
imports,
|
|
264
464
|
name: schemaItem.name,
|
|
265
465
|
includedProperties
|
|
266
466
|
};
|
|
267
467
|
}
|
|
268
468
|
if (itemAdditionalProperties) {
|
|
269
|
-
if (itemAdditionalProperties === true)
|
|
270
|
-
value: `{}`,
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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
|
+
}
|
|
274
478
|
const additionalProperties = itemAdditionalProperties;
|
|
275
|
-
if (isReference(additionalProperties) && existingReferencedProperties.includes(getReferenceName$1(additionalProperties.$ref, context)))
|
|
276
|
-
value: `{}`,
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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
|
+
}
|
|
280
488
|
const resolvedValue = resolveMockValue({
|
|
281
489
|
schema: {
|
|
282
490
|
...additionalProperties,
|
|
@@ -292,15 +500,19 @@ function getMockObject({ item, mockOptions, operationId, tags, combine, context,
|
|
|
292
500
|
existingReferencedAllOfRefs: [],
|
|
293
501
|
splitMockImplementations
|
|
294
502
|
});
|
|
503
|
+
const { value: finalValue, nullWrapped } = wrapRootNullableObjectValue(`{
|
|
504
|
+
[${DEFAULT_OBJECT_KEY_MOCK}]: ${resolvedValue.value}
|
|
505
|
+
}`, schemaItem, mockOptions, combine);
|
|
295
506
|
return {
|
|
296
507
|
...resolvedValue,
|
|
297
|
-
value:
|
|
298
|
-
|
|
299
|
-
}`
|
|
508
|
+
value: finalValue,
|
|
509
|
+
nullWrapped
|
|
300
510
|
};
|
|
301
511
|
}
|
|
512
|
+
const { value: finalValue, nullWrapped } = wrapRootNullableObjectValue("{}", schemaItem, mockOptions, combine);
|
|
302
513
|
return {
|
|
303
|
-
value:
|
|
514
|
+
value: finalValue,
|
|
515
|
+
nullWrapped,
|
|
304
516
|
imports: [],
|
|
305
517
|
name: schemaItem.name
|
|
306
518
|
};
|
|
@@ -314,9 +526,12 @@ function getMockObject({ item, mockOptions, operationId, tags, combine, context,
|
|
|
314
526
|
*/
|
|
315
527
|
function getArrayItemMockFileScope(context, tags) {
|
|
316
528
|
const mode = context.output.mode;
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
529
|
+
const mockType = context.activeMockOutputType ?? OutputMockType.MSW;
|
|
530
|
+
let base;
|
|
531
|
+
if (mode === OutputMode.TAGS || mode === OutputMode.TAGS_SPLIT) base = `tag:${kebab(tags.length > 0 ? tags[0] : DefaultTag)}`;
|
|
532
|
+
else if (mode === OutputMode.SPLIT) base = "split";
|
|
533
|
+
else base = "single";
|
|
534
|
+
return `${base}:${mockType}`;
|
|
320
535
|
}
|
|
321
536
|
function getFileLevelExtractedFactories(context, scope) {
|
|
322
537
|
context.arrayItemMockFactories ??= /* @__PURE__ */ new Map();
|
|
@@ -327,11 +542,11 @@ function getFileLevelExtractedFactories(context, scope) {
|
|
|
327
542
|
return factories;
|
|
328
543
|
}
|
|
329
544
|
/**
|
|
330
|
-
* True when
|
|
331
|
-
*
|
|
545
|
+
* True when any mock generator entry opts into reusable array-item mock
|
|
546
|
+
* factories for object-like array item schemas in operation responses.
|
|
332
547
|
*/
|
|
333
548
|
function shouldExtractArrayItemFactories(context) {
|
|
334
|
-
return
|
|
549
|
+
return context.output.mock.generators.some((g) => !isFunction(g) && g.arrayItems === true);
|
|
335
550
|
}
|
|
336
551
|
/**
|
|
337
552
|
* True when `schemas: true` already emits a consolidated factory for this
|
|
@@ -429,8 +644,8 @@ function extractArrayItemMock({ items, propertyName, parentName, operationId, ta
|
|
|
429
644
|
if (!names) return;
|
|
430
645
|
const { factoryName, typeName } = names;
|
|
431
646
|
const fileLevelFactories = getFileLevelExtractedFactories(context, getArrayItemMockFileScope(context, tags));
|
|
647
|
+
const mockOptions = context.output.override.mock;
|
|
432
648
|
if (!(fileLevelFactories.has(factoryName) || splitMockImplementations.some((f) => f.includes(`export const ${factoryName}`)))) {
|
|
433
|
-
const mockOptions = context.output.override.mock;
|
|
434
649
|
const { param, returnType, returnCast } = getMockFactorySignatureParts(typeName, mockOptions, {
|
|
435
650
|
isOverridable: true,
|
|
436
651
|
overrideType: `Partial<${typeName}>`
|
|
@@ -440,7 +655,116 @@ function extractArrayItemMock({ items, propertyName, parentName, operationId, ta
|
|
|
440
655
|
fileLevelFactories.add(factoryName);
|
|
441
656
|
}
|
|
442
657
|
imports.push({ name: typeName });
|
|
443
|
-
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);
|
|
444
768
|
}
|
|
445
769
|
//#endregion
|
|
446
770
|
//#region src/faker/getters/scalar.ts
|
|
@@ -463,7 +787,7 @@ function getMockScalar({ item, imports, mockOptions, operationId, tags, combine,
|
|
|
463
787
|
if (context.output.override.mock?.useExamples || safeMockOptions.useExamples) {
|
|
464
788
|
const propertyExample = item.example === void 0 ? Array.isArray(item.examples) && item.examples.length > 0 ? item.examples[0] : void 0 : item.example;
|
|
465
789
|
if (propertyExample !== void 0) return {
|
|
466
|
-
value:
|
|
790
|
+
value: formatSchemaExampleValue(propertyExample, item, context),
|
|
467
791
|
imports: [],
|
|
468
792
|
name: item.name,
|
|
469
793
|
overrided: true
|
|
@@ -700,7 +1024,7 @@ function getItemType(item) {
|
|
|
700
1024
|
}
|
|
701
1025
|
function getEnum(item, imports, context, existingReferencedProperties, type) {
|
|
702
1026
|
if (!item.enum) return "";
|
|
703
|
-
let enumValue = `[${item.enum.filter((e) => e !== null).map((e) => type === "string" || type === void 0 && isString(e) ? `'${
|
|
1027
|
+
let enumValue = `[${item.enum.filter((e) => e !== null).map((e) => type === "string" || type === void 0 && isString(e) ? `'${jsStringLiteralEscape(e)}'` : e).join(",")}]`;
|
|
704
1028
|
if (context.output.override.enumGenerationType === EnumGeneration.ENUM) if (item.isRef || existingReferencedProperties.length === 0) {
|
|
705
1029
|
enumValue += ` as ${item.name}${item.name.endsWith("[]") ? "" : "[]"}`;
|
|
706
1030
|
imports.push({ name: item.name });
|
|
@@ -844,19 +1168,28 @@ function resolveMockValue({ schema, mockOptions, operationId, tags, combine, con
|
|
|
844
1168
|
const newSeparator = newSchema.allOf ? "allOf" : newSchema.oneOf ? "oneOf" : "anyOf";
|
|
845
1169
|
if (shouldDelegateToSchemaFactories(context) && isComponentsSchemaRef(refPaths) && !hasOverrideTouchingSchema(schemaRef?.properties, mockOptions, operationId, tags, schemaReference.path)) {
|
|
846
1170
|
const factoryName = `get${pascal(name)}Mock`;
|
|
847
|
-
|
|
1171
|
+
const factoryImport = {
|
|
848
1172
|
name: factoryName,
|
|
849
1173
|
values: true,
|
|
850
1174
|
schemaFactory: true
|
|
851
|
-
}
|
|
1175
|
+
};
|
|
1176
|
+
const isObjectLike = newSchema.type === "object" || !!newSchema.allOf || resolvesToObjectLike(newSchema, context);
|
|
1177
|
+
const mockTypeName = getStrictMockTypeName(pascal(name));
|
|
1178
|
+
const strictMockTypeImport = isStrictMock(mockOptions) && isObjectLike ? {
|
|
1179
|
+
name: mockTypeName,
|
|
1180
|
+
values: false,
|
|
1181
|
+
schemaFactory: true
|
|
1182
|
+
} : void 0;
|
|
1183
|
+
const strictObjectCast = isStrictMock(mockOptions) && isObjectLike ? ` as ${mockTypeName}` : "";
|
|
852
1184
|
return {
|
|
853
|
-
value: getNullable(
|
|
854
|
-
imports,
|
|
1185
|
+
value: getNullable(isObjectLike ? `{ ...${factoryName}()${strictObjectCast} }` : `${factoryName}()`, Boolean(newSchema.nullable), mockOptions?.nonNullable),
|
|
1186
|
+
imports: strictMockTypeImport ? [factoryImport, strictMockTypeImport] : [factoryImport],
|
|
855
1187
|
name: newSchema.name,
|
|
856
1188
|
type: getType(newSchema),
|
|
857
1189
|
nullWrapped: Boolean(newSchema.nullable) && !mockOptions?.nonNullable
|
|
858
1190
|
};
|
|
859
1191
|
}
|
|
1192
|
+
const importsBefore = imports.length;
|
|
860
1193
|
const scalar = getMockScalar({
|
|
861
1194
|
item: newSchema,
|
|
862
1195
|
mockOptions,
|
|
@@ -887,27 +1220,36 @@ function resolveMockValue({ schema, mockOptions, operationId, tags, combine, con
|
|
|
887
1220
|
splitMockImplementations.push(func);
|
|
888
1221
|
}
|
|
889
1222
|
scalar.value = newSchema.nullable ? `${funcName}()` : `{...${funcName}()}`;
|
|
890
|
-
|
|
1223
|
+
const typeImport = {
|
|
1224
|
+
name: newSchema.name,
|
|
1225
|
+
values: false
|
|
1226
|
+
};
|
|
1227
|
+
scalar.imports.push(typeImport);
|
|
1228
|
+
if (scalar.imports !== imports) imports.push(typeImport);
|
|
891
1229
|
}
|
|
1230
|
+
mergeReturnedMockImports(imports, importsBefore, scalar.imports);
|
|
892
1231
|
return {
|
|
893
1232
|
...scalar,
|
|
894
1233
|
type: getType(newSchema)
|
|
895
1234
|
};
|
|
896
1235
|
}
|
|
1236
|
+
const importsBefore = imports.length;
|
|
1237
|
+
const scalar = getMockScalar({
|
|
1238
|
+
item: schema,
|
|
1239
|
+
mockOptions,
|
|
1240
|
+
operationId,
|
|
1241
|
+
tags,
|
|
1242
|
+
combine,
|
|
1243
|
+
context,
|
|
1244
|
+
imports,
|
|
1245
|
+
existingReferencedProperties,
|
|
1246
|
+
existingReferencedAllOfRefs,
|
|
1247
|
+
splitMockImplementations,
|
|
1248
|
+
allowOverride
|
|
1249
|
+
});
|
|
1250
|
+
mergeReturnedMockImports(imports, importsBefore, scalar.imports);
|
|
897
1251
|
return {
|
|
898
|
-
...
|
|
899
|
-
item: schema,
|
|
900
|
-
mockOptions,
|
|
901
|
-
operationId,
|
|
902
|
-
tags,
|
|
903
|
-
combine,
|
|
904
|
-
context,
|
|
905
|
-
imports,
|
|
906
|
-
existingReferencedProperties,
|
|
907
|
-
existingReferencedAllOfRefs,
|
|
908
|
-
splitMockImplementations,
|
|
909
|
-
allowOverride
|
|
910
|
-
}),
|
|
1252
|
+
...scalar,
|
|
911
1253
|
type: getType(schema)
|
|
912
1254
|
};
|
|
913
1255
|
}
|
|
@@ -1167,7 +1509,8 @@ function getResponsesMockDefinition({ operationId, tags, returnType, responses,
|
|
|
1167
1509
|
if (context.output.override.mock?.useExamples || mockOptions?.useExamples) {
|
|
1168
1510
|
const exampleValue = unwrapExampleValue(example ?? originalSchema?.example ?? getExampleEntries(examples)[0] ?? getExampleEntries(originalSchema?.examples)[0]);
|
|
1169
1511
|
if (exampleValue !== void 0) {
|
|
1170
|
-
|
|
1512
|
+
const formatted = formatSchemaExampleValue(exampleValue, originalSchema, context);
|
|
1513
|
+
result.definitions.push(transformer ? transformer(formatted, returnType) : formatted);
|
|
1171
1514
|
continue;
|
|
1172
1515
|
}
|
|
1173
1516
|
}
|
|
@@ -1182,13 +1525,15 @@ function getResponsesMockDefinition({ operationId, tags, returnType, responses,
|
|
|
1182
1525
|
};
|
|
1183
1526
|
else if (!originalSchema) continue;
|
|
1184
1527
|
const resolvedSchema = resolveRef(originalSchema, context).schema;
|
|
1528
|
+
const responseImports = imports ?? [];
|
|
1529
|
+
const importsBefore = responseImports.length;
|
|
1185
1530
|
const scalar = getMockScalar({
|
|
1186
1531
|
item: {
|
|
1187
1532
|
...resolvedSchema,
|
|
1188
1533
|
name: definition,
|
|
1189
1534
|
...context.output.override.enumGenerationType === "enum" && isRef ? { isRef: true } : {}
|
|
1190
1535
|
},
|
|
1191
|
-
imports,
|
|
1536
|
+
imports: responseImports,
|
|
1192
1537
|
mockOptions: mockOptionsWithoutFunc,
|
|
1193
1538
|
operationId,
|
|
1194
1539
|
tags,
|
|
@@ -1197,9 +1542,11 @@ function getResponsesMockDefinition({ operationId, tags, returnType, responses,
|
|
|
1197
1542
|
splitMockImplementations,
|
|
1198
1543
|
allowOverride: true
|
|
1199
1544
|
});
|
|
1200
|
-
result.imports
|
|
1545
|
+
appendImportsDelta(result.imports, responseImports, importsBefore);
|
|
1546
|
+
if (scalar.imports !== responseImports) appendImportsDelta(result.imports, scalar.imports, 0);
|
|
1201
1547
|
result.definitions.push(transformer ? transformer(scalar.value, returnType) : scalar.value);
|
|
1202
1548
|
}
|
|
1549
|
+
appendImportsDelta(result.imports, collectSplitMockTypeImports(splitMockImplementations), 0);
|
|
1203
1550
|
return result;
|
|
1204
1551
|
}
|
|
1205
1552
|
function getMockDefinition({ operationId, tags, returnType, responses, override, transformer, context, mockOptions, splitMockImplementations }) {
|
|
@@ -1403,7 +1750,8 @@ export const ${handlerName} = (overrideResponse?: ${mockReturnType} | ((${infoPa
|
|
|
1403
1750
|
handler: handlerImplementation
|
|
1404
1751
|
},
|
|
1405
1752
|
imports: includeResponseImports,
|
|
1406
|
-
strictMockSchemaTypeNames: strictMock
|
|
1753
|
+
strictMockSchemaTypeNames: strictMock ? mergeStrictMockSchemaTypeNames(schemaTypeNames, collectStrictMockSchemaTypeNamesFromImplementation(mockImplementation)) : void 0,
|
|
1754
|
+
strictMockSchemaKinds: strictMock ? mergeStrictMockSchemaKinds(getStrictMockSchemaKindsFromResponses(responses, context), Object.fromEntries((collectStrictMockSchemaTypeNamesFromImplementation(mockImplementation) ?? []).map((name) => [name, "object"]))) : void 0
|
|
1407
1755
|
};
|
|
1408
1756
|
}
|
|
1409
1757
|
function generateMSW(generatorVerbOptions, generatorOptions) {
|
|
@@ -1420,12 +1768,14 @@ function generateMSW(generatorVerbOptions, generatorOptions) {
|
|
|
1420
1768
|
const handlerImplementations = [baseDefinition.implementation.handler];
|
|
1421
1769
|
const imports = [...baseDefinition.imports];
|
|
1422
1770
|
const strictMockSchemaTypeNames = new Set(baseDefinition.strictMockSchemaTypeNames);
|
|
1771
|
+
const strictMockSchemaKinds = { ...baseDefinition.strictMockSchemaKinds };
|
|
1423
1772
|
if (generatorOptions.mock && isObject(generatorOptions.mock) && generatorOptions.mock.generateEachHttpStatus) for (const statusResponse of [...response.types.success, ...response.types.errors]) {
|
|
1424
1773
|
const definition = generateDefinition(statusResponse.key, route, getResponseMockFunctionName, handlerName, generatorVerbOptions, generatorOptions, statusResponse.value, statusResponse.key, response.imports, [statusResponse], [statusResponse.contentType], splitMockImplementations);
|
|
1425
1774
|
mockImplementations.push(definition.implementation.function);
|
|
1426
1775
|
handlerImplementations.push(definition.implementation.handler);
|
|
1427
1776
|
imports.push(...definition.imports);
|
|
1428
1777
|
for (const name of definition.strictMockSchemaTypeNames ?? []) strictMockSchemaTypeNames.add(name);
|
|
1778
|
+
if (definition.strictMockSchemaKinds) for (const [name, kind] of Object.entries(definition.strictMockSchemaKinds)) strictMockSchemaKinds[name] ??= kind;
|
|
1429
1779
|
}
|
|
1430
1780
|
const aggregatedStrictNames = [...strictMockSchemaTypeNames];
|
|
1431
1781
|
return {
|
|
@@ -1435,7 +1785,8 @@ function generateMSW(generatorVerbOptions, generatorOptions) {
|
|
|
1435
1785
|
handler: handlerImplementations.join("\n")
|
|
1436
1786
|
},
|
|
1437
1787
|
imports,
|
|
1438
|
-
strictMockSchemaTypeNames: aggregatedStrictNames.length > 0 ? aggregatedStrictNames : void 0
|
|
1788
|
+
strictMockSchemaTypeNames: aggregatedStrictNames.length > 0 ? aggregatedStrictNames : void 0,
|
|
1789
|
+
strictMockSchemaKinds: mergeStrictMockSchemaKinds(strictMockSchemaKinds)
|
|
1439
1790
|
};
|
|
1440
1791
|
}
|
|
1441
1792
|
//#endregion
|
|
@@ -1473,7 +1824,8 @@ function generateFaker(generatorVerbOptions, generatorOptions) {
|
|
|
1473
1824
|
handlerName: ""
|
|
1474
1825
|
},
|
|
1475
1826
|
imports: result.imports,
|
|
1476
|
-
strictMockSchemaTypeNames: result.strictMockSchemaTypeNames
|
|
1827
|
+
strictMockSchemaTypeNames: result.strictMockSchemaTypeNames,
|
|
1828
|
+
strictMockSchemaKinds: result.strictMockSchemaKinds
|
|
1477
1829
|
};
|
|
1478
1830
|
}
|
|
1479
1831
|
/**
|
|
@@ -1488,38 +1840,47 @@ function generateFaker(generatorVerbOptions, generatorOptions) {
|
|
|
1488
1840
|
function generateFakerForSchemas(schemas, context, options) {
|
|
1489
1841
|
const factories = [];
|
|
1490
1842
|
const strictMockTypeNames = /* @__PURE__ */ new Set();
|
|
1843
|
+
const strictMockSchemaKinds = {};
|
|
1491
1844
|
const allImports = [];
|
|
1492
1845
|
const splitMockImplementations = [];
|
|
1493
1846
|
const localFactoryNames = new Set(schemas.filter((s) => !!s.schema).map((s) => `get${pascal(s.name)}Mock`));
|
|
1494
|
-
const
|
|
1847
|
+
const localMockTypeNames = new Set(schemas.filter((s) => !!s.schema).map((s) => getStrictMockTypeName(pascal(s.name))));
|
|
1848
|
+
const mockOptions = getMockWithoutFunc(context.spec, context.output.override);
|
|
1495
1849
|
for (const generatorSchema of schemas) {
|
|
1496
1850
|
const { name, schema } = generatorSchema;
|
|
1497
1851
|
if (!schema) continue;
|
|
1498
1852
|
const factoryName = `get${pascal(name)}Mock`;
|
|
1499
1853
|
const factoryImports = [];
|
|
1854
|
+
const factoryImportsBefore = factoryImports.length;
|
|
1855
|
+
const schemaName = pascal(name);
|
|
1500
1856
|
const result = getMockScalar({
|
|
1501
1857
|
item: {
|
|
1502
1858
|
...schema,
|
|
1503
|
-
name
|
|
1859
|
+
name: schemaName
|
|
1504
1860
|
},
|
|
1505
1861
|
imports: factoryImports,
|
|
1506
1862
|
mockOptions,
|
|
1507
1863
|
operationId: name,
|
|
1508
1864
|
tags: [],
|
|
1509
1865
|
context,
|
|
1510
|
-
existingReferencedProperties: [],
|
|
1866
|
+
existingReferencedProperties: [schemaName],
|
|
1867
|
+
existingReferencedAllOfRefs: [schemaName],
|
|
1511
1868
|
splitMockImplementations,
|
|
1512
1869
|
allowOverride: true,
|
|
1513
1870
|
isRef: false
|
|
1514
1871
|
});
|
|
1515
|
-
allImports
|
|
1872
|
+
appendImportsDelta(allImports, factoryImports, factoryImportsBefore);
|
|
1873
|
+
if (result.imports !== factoryImports) appendImportsDelta(allImports, result.imports, 0);
|
|
1516
1874
|
const typeName = pascal(name);
|
|
1517
1875
|
const { param, returnType, returnCast } = getMockFactorySignatureParts(typeName, mockOptions, {
|
|
1518
1876
|
isOverridable: result.value.includes("overrideResponse"),
|
|
1519
1877
|
overrideType: `Partial<${typeName}>`
|
|
1520
1878
|
});
|
|
1521
1879
|
const factory = formatMockFactoryDeclaration(factoryName, param, returnType, result.value, returnCast);
|
|
1522
|
-
if (isStrictMock(mockOptions))
|
|
1880
|
+
if (isStrictMock(mockOptions)) {
|
|
1881
|
+
strictMockTypeNames.add(typeName);
|
|
1882
|
+
strictMockSchemaKinds[typeName] = classifyStrictMockSchemaType(schema);
|
|
1883
|
+
}
|
|
1523
1884
|
factories.push(factory);
|
|
1524
1885
|
allImports.push({
|
|
1525
1886
|
name: pascal(name),
|
|
@@ -1529,6 +1890,7 @@ function generateFakerForSchemas(schemas, context, options) {
|
|
|
1529
1890
|
const mergedImports = /* @__PURE__ */ new Map();
|
|
1530
1891
|
for (const imp of allImports) {
|
|
1531
1892
|
if (imp.schemaFactory && localFactoryNames.has(imp.name)) continue;
|
|
1893
|
+
if (imp.schemaFactory && !imp.values && localMockTypeNames.has(imp.name)) continue;
|
|
1532
1894
|
const key = `${imp.name}::${imp.alias ?? ""}`;
|
|
1533
1895
|
const existing = mergedImports.get(key);
|
|
1534
1896
|
if (!existing) {
|
|
@@ -1539,11 +1901,16 @@ function generateFakerForSchemas(schemas, context, options) {
|
|
|
1539
1901
|
}
|
|
1540
1902
|
const uniqueImports = [...mergedImports.values()];
|
|
1541
1903
|
const implementation = [...splitMockImplementations, ...factories].filter(Boolean).join("\n\n");
|
|
1904
|
+
for (const name of collectStrictMockSchemaTypeNamesFromImplementation(implementation)) {
|
|
1905
|
+
strictMockTypeNames.add(name);
|
|
1906
|
+
strictMockSchemaKinds[name] ??= "object";
|
|
1907
|
+
}
|
|
1542
1908
|
const aggregatedStrictNames = [...strictMockTypeNames];
|
|
1543
1909
|
return {
|
|
1544
1910
|
implementation,
|
|
1545
1911
|
imports: uniqueImports,
|
|
1546
|
-
strictMockSchemaTypeNames: aggregatedStrictNames.length > 0 ? aggregatedStrictNames : void 0
|
|
1912
|
+
strictMockSchemaTypeNames: aggregatedStrictNames.length > 0 ? aggregatedStrictNames : void 0,
|
|
1913
|
+
strictMockSchemaKinds: mergeStrictMockSchemaKinds(strictMockSchemaKinds)
|
|
1547
1914
|
};
|
|
1548
1915
|
}
|
|
1549
1916
|
//#endregion
|
|
@@ -1585,9 +1952,16 @@ const generateMockImports = (importOptions) => {
|
|
|
1585
1952
|
* `output.mock.generators` is dispatched here individually.
|
|
1586
1953
|
*/
|
|
1587
1954
|
function generateMock(generatorVerbOptions, generatorOptions) {
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1955
|
+
const { context } = generatorOptions;
|
|
1956
|
+
const previousActiveMockOutputType = context.activeMockOutputType;
|
|
1957
|
+
context.activeMockOutputType = generatorOptions.mock.type;
|
|
1958
|
+
try {
|
|
1959
|
+
switch (generatorOptions.mock.type) {
|
|
1960
|
+
case OutputMockType.FAKER: return generateFaker(generatorVerbOptions, generatorOptions);
|
|
1961
|
+
default: return generateMSW(generatorVerbOptions, generatorOptions);
|
|
1962
|
+
}
|
|
1963
|
+
} finally {
|
|
1964
|
+
context.activeMockOutputType = previousActiveMockOutputType;
|
|
1591
1965
|
}
|
|
1592
1966
|
}
|
|
1593
1967
|
//#endregion
|