@orval/mock 8.17.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 +389 -56
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -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";
|
|
25
35
|
}
|
|
26
|
-
function
|
|
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};`;
|
|
51
|
+
}
|
|
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;
|
|
@@ -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:
|
|
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
|
|
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)
|
|
301
|
-
value: `{}`,
|
|
302
|
-
|
|
303
|
-
|
|
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)))
|
|
307
|
-
value: `{}`,
|
|
308
|
-
|
|
309
|
-
|
|
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
|
-
|
|
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
|
};
|
|
@@ -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
|
|
@@ -497,7 +787,7 @@ function getMockScalar({ item, imports, mockOptions, operationId, tags, combine,
|
|
|
497
787
|
if (context.output.override.mock?.useExamples || safeMockOptions.useExamples) {
|
|
498
788
|
const propertyExample = item.example === void 0 ? Array.isArray(item.examples) && item.examples.length > 0 ? item.examples[0] : void 0 : item.example;
|
|
499
789
|
if (propertyExample !== void 0) return {
|
|
500
|
-
value:
|
|
790
|
+
value: formatSchemaExampleValue(propertyExample, item, context),
|
|
501
791
|
imports: [],
|
|
502
792
|
name: item.name,
|
|
503
793
|
overrided: true
|
|
@@ -878,19 +1168,28 @@ function resolveMockValue({ schema, mockOptions, operationId, tags, combine, con
|
|
|
878
1168
|
const newSeparator = newSchema.allOf ? "allOf" : newSchema.oneOf ? "oneOf" : "anyOf";
|
|
879
1169
|
if (shouldDelegateToSchemaFactories(context) && isComponentsSchemaRef(refPaths) && !hasOverrideTouchingSchema(schemaRef?.properties, mockOptions, operationId, tags, schemaReference.path)) {
|
|
880
1170
|
const factoryName = `get${pascal(name)}Mock`;
|
|
881
|
-
|
|
1171
|
+
const factoryImport = {
|
|
882
1172
|
name: factoryName,
|
|
883
1173
|
values: true,
|
|
884
1174
|
schemaFactory: true
|
|
885
|
-
}
|
|
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}` : "";
|
|
886
1184
|
return {
|
|
887
|
-
value: getNullable(
|
|
888
|
-
imports,
|
|
1185
|
+
value: getNullable(isObjectLike ? `{ ...${factoryName}()${strictObjectCast} }` : `${factoryName}()`, Boolean(newSchema.nullable), mockOptions?.nonNullable),
|
|
1186
|
+
imports: strictMockTypeImport ? [factoryImport, strictMockTypeImport] : [factoryImport],
|
|
889
1187
|
name: newSchema.name,
|
|
890
1188
|
type: getType(newSchema),
|
|
891
1189
|
nullWrapped: Boolean(newSchema.nullable) && !mockOptions?.nonNullable
|
|
892
1190
|
};
|
|
893
1191
|
}
|
|
1192
|
+
const importsBefore = imports.length;
|
|
894
1193
|
const scalar = getMockScalar({
|
|
895
1194
|
item: newSchema,
|
|
896
1195
|
mockOptions,
|
|
@@ -921,27 +1220,36 @@ function resolveMockValue({ schema, mockOptions, operationId, tags, combine, con
|
|
|
921
1220
|
splitMockImplementations.push(func);
|
|
922
1221
|
}
|
|
923
1222
|
scalar.value = newSchema.nullable ? `${funcName}()` : `{...${funcName}()}`;
|
|
924
|
-
|
|
1223
|
+
const typeImport = {
|
|
1224
|
+
name: newSchema.name,
|
|
1225
|
+
values: false
|
|
1226
|
+
};
|
|
1227
|
+
scalar.imports.push(typeImport);
|
|
1228
|
+
if (scalar.imports !== imports) imports.push(typeImport);
|
|
925
1229
|
}
|
|
1230
|
+
mergeReturnedMockImports(imports, importsBefore, scalar.imports);
|
|
926
1231
|
return {
|
|
927
1232
|
...scalar,
|
|
928
1233
|
type: getType(newSchema)
|
|
929
1234
|
};
|
|
930
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);
|
|
931
1251
|
return {
|
|
932
|
-
...
|
|
933
|
-
item: schema,
|
|
934
|
-
mockOptions,
|
|
935
|
-
operationId,
|
|
936
|
-
tags,
|
|
937
|
-
combine,
|
|
938
|
-
context,
|
|
939
|
-
imports,
|
|
940
|
-
existingReferencedProperties,
|
|
941
|
-
existingReferencedAllOfRefs,
|
|
942
|
-
splitMockImplementations,
|
|
943
|
-
allowOverride
|
|
944
|
-
}),
|
|
1252
|
+
...scalar,
|
|
945
1253
|
type: getType(schema)
|
|
946
1254
|
};
|
|
947
1255
|
}
|
|
@@ -1201,7 +1509,8 @@ function getResponsesMockDefinition({ operationId, tags, returnType, responses,
|
|
|
1201
1509
|
if (context.output.override.mock?.useExamples || mockOptions?.useExamples) {
|
|
1202
1510
|
const exampleValue = unwrapExampleValue(example ?? originalSchema?.example ?? getExampleEntries(examples)[0] ?? getExampleEntries(originalSchema?.examples)[0]);
|
|
1203
1511
|
if (exampleValue !== void 0) {
|
|
1204
|
-
|
|
1512
|
+
const formatted = formatSchemaExampleValue(exampleValue, originalSchema, context);
|
|
1513
|
+
result.definitions.push(transformer ? transformer(formatted, returnType) : formatted);
|
|
1205
1514
|
continue;
|
|
1206
1515
|
}
|
|
1207
1516
|
}
|
|
@@ -1216,13 +1525,15 @@ function getResponsesMockDefinition({ operationId, tags, returnType, responses,
|
|
|
1216
1525
|
};
|
|
1217
1526
|
else if (!originalSchema) continue;
|
|
1218
1527
|
const resolvedSchema = resolveRef(originalSchema, context).schema;
|
|
1528
|
+
const responseImports = imports ?? [];
|
|
1529
|
+
const importsBefore = responseImports.length;
|
|
1219
1530
|
const scalar = getMockScalar({
|
|
1220
1531
|
item: {
|
|
1221
1532
|
...resolvedSchema,
|
|
1222
1533
|
name: definition,
|
|
1223
1534
|
...context.output.override.enumGenerationType === "enum" && isRef ? { isRef: true } : {}
|
|
1224
1535
|
},
|
|
1225
|
-
imports,
|
|
1536
|
+
imports: responseImports,
|
|
1226
1537
|
mockOptions: mockOptionsWithoutFunc,
|
|
1227
1538
|
operationId,
|
|
1228
1539
|
tags,
|
|
@@ -1231,9 +1542,11 @@ function getResponsesMockDefinition({ operationId, tags, returnType, responses,
|
|
|
1231
1542
|
splitMockImplementations,
|
|
1232
1543
|
allowOverride: true
|
|
1233
1544
|
});
|
|
1234
|
-
result.imports
|
|
1545
|
+
appendImportsDelta(result.imports, responseImports, importsBefore);
|
|
1546
|
+
if (scalar.imports !== responseImports) appendImportsDelta(result.imports, scalar.imports, 0);
|
|
1235
1547
|
result.definitions.push(transformer ? transformer(scalar.value, returnType) : scalar.value);
|
|
1236
1548
|
}
|
|
1549
|
+
appendImportsDelta(result.imports, collectSplitMockTypeImports(splitMockImplementations), 0);
|
|
1237
1550
|
return result;
|
|
1238
1551
|
}
|
|
1239
1552
|
function getMockDefinition({ operationId, tags, returnType, responses, override, transformer, context, mockOptions, splitMockImplementations }) {
|
|
@@ -1437,7 +1750,8 @@ export const ${handlerName} = (overrideResponse?: ${mockReturnType} | ((${infoPa
|
|
|
1437
1750
|
handler: handlerImplementation
|
|
1438
1751
|
},
|
|
1439
1752
|
imports: includeResponseImports,
|
|
1440
|
-
strictMockSchemaTypeNames: strictMock ? mergeStrictMockSchemaTypeNames(schemaTypeNames, collectStrictMockSchemaTypeNamesFromImplementation(mockImplementation)) : void 0
|
|
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
|
|
1441
1755
|
};
|
|
1442
1756
|
}
|
|
1443
1757
|
function generateMSW(generatorVerbOptions, generatorOptions) {
|
|
@@ -1454,12 +1768,14 @@ function generateMSW(generatorVerbOptions, generatorOptions) {
|
|
|
1454
1768
|
const handlerImplementations = [baseDefinition.implementation.handler];
|
|
1455
1769
|
const imports = [...baseDefinition.imports];
|
|
1456
1770
|
const strictMockSchemaTypeNames = new Set(baseDefinition.strictMockSchemaTypeNames);
|
|
1771
|
+
const strictMockSchemaKinds = { ...baseDefinition.strictMockSchemaKinds };
|
|
1457
1772
|
if (generatorOptions.mock && isObject(generatorOptions.mock) && generatorOptions.mock.generateEachHttpStatus) for (const statusResponse of [...response.types.success, ...response.types.errors]) {
|
|
1458
1773
|
const definition = generateDefinition(statusResponse.key, route, getResponseMockFunctionName, handlerName, generatorVerbOptions, generatorOptions, statusResponse.value, statusResponse.key, response.imports, [statusResponse], [statusResponse.contentType], splitMockImplementations);
|
|
1459
1774
|
mockImplementations.push(definition.implementation.function);
|
|
1460
1775
|
handlerImplementations.push(definition.implementation.handler);
|
|
1461
1776
|
imports.push(...definition.imports);
|
|
1462
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;
|
|
1463
1779
|
}
|
|
1464
1780
|
const aggregatedStrictNames = [...strictMockSchemaTypeNames];
|
|
1465
1781
|
return {
|
|
@@ -1469,7 +1785,8 @@ function generateMSW(generatorVerbOptions, generatorOptions) {
|
|
|
1469
1785
|
handler: handlerImplementations.join("\n")
|
|
1470
1786
|
},
|
|
1471
1787
|
imports,
|
|
1472
|
-
strictMockSchemaTypeNames: aggregatedStrictNames.length > 0 ? aggregatedStrictNames : void 0
|
|
1788
|
+
strictMockSchemaTypeNames: aggregatedStrictNames.length > 0 ? aggregatedStrictNames : void 0,
|
|
1789
|
+
strictMockSchemaKinds: mergeStrictMockSchemaKinds(strictMockSchemaKinds)
|
|
1473
1790
|
};
|
|
1474
1791
|
}
|
|
1475
1792
|
//#endregion
|
|
@@ -1507,7 +1824,8 @@ function generateFaker(generatorVerbOptions, generatorOptions) {
|
|
|
1507
1824
|
handlerName: ""
|
|
1508
1825
|
},
|
|
1509
1826
|
imports: result.imports,
|
|
1510
|
-
strictMockSchemaTypeNames: result.strictMockSchemaTypeNames
|
|
1827
|
+
strictMockSchemaTypeNames: result.strictMockSchemaTypeNames,
|
|
1828
|
+
strictMockSchemaKinds: result.strictMockSchemaKinds
|
|
1511
1829
|
};
|
|
1512
1830
|
}
|
|
1513
1831
|
/**
|
|
@@ -1522,38 +1840,47 @@ function generateFaker(generatorVerbOptions, generatorOptions) {
|
|
|
1522
1840
|
function generateFakerForSchemas(schemas, context, options) {
|
|
1523
1841
|
const factories = [];
|
|
1524
1842
|
const strictMockTypeNames = /* @__PURE__ */ new Set();
|
|
1843
|
+
const strictMockSchemaKinds = {};
|
|
1525
1844
|
const allImports = [];
|
|
1526
1845
|
const splitMockImplementations = [];
|
|
1527
1846
|
const localFactoryNames = new Set(schemas.filter((s) => !!s.schema).map((s) => `get${pascal(s.name)}Mock`));
|
|
1847
|
+
const localMockTypeNames = new Set(schemas.filter((s) => !!s.schema).map((s) => getStrictMockTypeName(pascal(s.name))));
|
|
1528
1848
|
const mockOptions = getMockWithoutFunc(context.spec, context.output.override);
|
|
1529
1849
|
for (const generatorSchema of schemas) {
|
|
1530
1850
|
const { name, schema } = generatorSchema;
|
|
1531
1851
|
if (!schema) continue;
|
|
1532
1852
|
const factoryName = `get${pascal(name)}Mock`;
|
|
1533
1853
|
const factoryImports = [];
|
|
1854
|
+
const factoryImportsBefore = factoryImports.length;
|
|
1855
|
+
const schemaName = pascal(name);
|
|
1534
1856
|
const result = getMockScalar({
|
|
1535
1857
|
item: {
|
|
1536
1858
|
...schema,
|
|
1537
|
-
name
|
|
1859
|
+
name: schemaName
|
|
1538
1860
|
},
|
|
1539
1861
|
imports: factoryImports,
|
|
1540
1862
|
mockOptions,
|
|
1541
1863
|
operationId: name,
|
|
1542
1864
|
tags: [],
|
|
1543
1865
|
context,
|
|
1544
|
-
existingReferencedProperties: [],
|
|
1866
|
+
existingReferencedProperties: [schemaName],
|
|
1867
|
+
existingReferencedAllOfRefs: [schemaName],
|
|
1545
1868
|
splitMockImplementations,
|
|
1546
1869
|
allowOverride: true,
|
|
1547
1870
|
isRef: false
|
|
1548
1871
|
});
|
|
1549
|
-
allImports
|
|
1872
|
+
appendImportsDelta(allImports, factoryImports, factoryImportsBefore);
|
|
1873
|
+
if (result.imports !== factoryImports) appendImportsDelta(allImports, result.imports, 0);
|
|
1550
1874
|
const typeName = pascal(name);
|
|
1551
1875
|
const { param, returnType, returnCast } = getMockFactorySignatureParts(typeName, mockOptions, {
|
|
1552
1876
|
isOverridable: result.value.includes("overrideResponse"),
|
|
1553
1877
|
overrideType: `Partial<${typeName}>`
|
|
1554
1878
|
});
|
|
1555
1879
|
const factory = formatMockFactoryDeclaration(factoryName, param, returnType, result.value, returnCast);
|
|
1556
|
-
if (isStrictMock(mockOptions))
|
|
1880
|
+
if (isStrictMock(mockOptions)) {
|
|
1881
|
+
strictMockTypeNames.add(typeName);
|
|
1882
|
+
strictMockSchemaKinds[typeName] = classifyStrictMockSchemaType(schema);
|
|
1883
|
+
}
|
|
1557
1884
|
factories.push(factory);
|
|
1558
1885
|
allImports.push({
|
|
1559
1886
|
name: pascal(name),
|
|
@@ -1563,6 +1890,7 @@ function generateFakerForSchemas(schemas, context, options) {
|
|
|
1563
1890
|
const mergedImports = /* @__PURE__ */ new Map();
|
|
1564
1891
|
for (const imp of allImports) {
|
|
1565
1892
|
if (imp.schemaFactory && localFactoryNames.has(imp.name)) continue;
|
|
1893
|
+
if (imp.schemaFactory && !imp.values && localMockTypeNames.has(imp.name)) continue;
|
|
1566
1894
|
const key = `${imp.name}::${imp.alias ?? ""}`;
|
|
1567
1895
|
const existing = mergedImports.get(key);
|
|
1568
1896
|
if (!existing) {
|
|
@@ -1573,11 +1901,16 @@ function generateFakerForSchemas(schemas, context, options) {
|
|
|
1573
1901
|
}
|
|
1574
1902
|
const uniqueImports = [...mergedImports.values()];
|
|
1575
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
|
+
}
|
|
1576
1908
|
const aggregatedStrictNames = [...strictMockTypeNames];
|
|
1577
1909
|
return {
|
|
1578
1910
|
implementation,
|
|
1579
1911
|
imports: uniqueImports,
|
|
1580
|
-
strictMockSchemaTypeNames: aggregatedStrictNames.length > 0 ? aggregatedStrictNames : void 0
|
|
1912
|
+
strictMockSchemaTypeNames: aggregatedStrictNames.length > 0 ? aggregatedStrictNames : void 0,
|
|
1913
|
+
strictMockSchemaKinds: mergeStrictMockSchemaKinds(strictMockSchemaKinds)
|
|
1581
1914
|
};
|
|
1582
1915
|
}
|
|
1583
1916
|
//#endregion
|