@orval/mock 8.37.0 → 8.38.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 +231 -196
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -3
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { EnumGeneration, OutputMockType, OutputMode, PropertySortOrder, camelPathParamName, compareNatural, compareVersions, escapeRegExp, generalJSTypesWithArray, generateDependencyImports, getKey, getOperationTagKey, getRefInfo, getRequiredKeys, getStringLiteralType, isBoolean, isFunction, isMswMock, isNumber, isObject,
|
|
2
|
-
import { prop } from "remeda";
|
|
1
|
+
import { EnumGeneration, OutputMockType, OutputMode, PropertySortOrder, camelPathParamName, compareNatural, compareVersions, escapeRegExp, generalJSTypesWithArray, generateDependencyImports, getAtPath, getKey, getOperationTagKey, getRefInfo, getRequiredKeys, getStringLiteralType, isBoolean, isFunction, isInlineSchema, isMswMock, isNullOnlyEnum, isNumber, isObject, isSchemaNullable, isString, jsStringLiteralEscape, mergeDeep, pascal, resolveRef, safeNumericConstraint, stringify, toColonRoutePath, toJsLiteral, toObjectSchema } from "@orval/core";
|
|
3
2
|
//#region src/mock-types.ts
|
|
3
|
+
function asObjectSchema(schema) {
|
|
4
|
+
if (!schema || typeof schema !== "object") return;
|
|
5
|
+
return schema;
|
|
6
|
+
}
|
|
4
7
|
function isStrictMock(mockOptions) {
|
|
5
8
|
return Boolean(mockOptions && mockOptions.required && mockOptions.nonNullable);
|
|
6
9
|
}
|
|
@@ -21,23 +24,25 @@ export type MockWithNullableOverrides<
|
|
|
21
24
|
};`;
|
|
22
25
|
}
|
|
23
26
|
function classifyStrictMockSchemaType(schema, context) {
|
|
24
|
-
|
|
25
|
-
if (
|
|
26
|
-
if (
|
|
27
|
+
const objectSchema = asObjectSchema(schema);
|
|
28
|
+
if (!objectSchema) return "object";
|
|
29
|
+
if (objectSchema.format === "binary" || objectSchema.contentMediaType === "application/octet-stream" && !objectSchema.contentEncoding) return "binary";
|
|
30
|
+
if (typeof objectSchema.$ref === "string") {
|
|
27
31
|
if (context) {
|
|
28
|
-
const { schema: resolved } = resolveRef(
|
|
32
|
+
const { schema: resolved } = resolveRef(objectSchema, context);
|
|
29
33
|
return classifyStrictMockSchemaType(resolved, context);
|
|
30
34
|
}
|
|
31
35
|
return "object";
|
|
32
36
|
}
|
|
33
|
-
if (
|
|
37
|
+
if (objectSchema.type === "object" || objectSchema.properties || isComposedObjectSchema(objectSchema)) return "object";
|
|
34
38
|
return "alias";
|
|
35
39
|
}
|
|
36
40
|
function isComposedObjectSchema(schema) {
|
|
37
41
|
const branches = schema.oneOf ?? schema.anyOf ?? schema.allOf;
|
|
38
42
|
if (!branches?.length) return false;
|
|
39
43
|
return branches.some((branch) => {
|
|
40
|
-
const item = branch;
|
|
44
|
+
const item = asObjectSchema(branch);
|
|
45
|
+
if (!item) return false;
|
|
41
46
|
if (typeof item.$ref === "string" || item.type === "object" || item.properties) return true;
|
|
42
47
|
return isComposedObjectSchema(item);
|
|
43
48
|
});
|
|
@@ -62,23 +67,24 @@ function strictMockResolvedImportMatches(typeName, resolvedImport, importBareNam
|
|
|
62
67
|
return importBareName !== void 0 && importBareName === resolvedName;
|
|
63
68
|
}
|
|
64
69
|
function resolveStrictMockSchemaForTypeName(typeName, originalSchema, context, importBareName) {
|
|
65
|
-
|
|
66
|
-
if (!
|
|
67
|
-
|
|
70
|
+
const objectSchema = asObjectSchema(originalSchema);
|
|
71
|
+
if (!objectSchema) return;
|
|
72
|
+
if (!context) return objectSchema;
|
|
73
|
+
const branches = objectSchema.oneOf ?? objectSchema.anyOf ?? objectSchema.allOf;
|
|
68
74
|
if (branches?.length) {
|
|
69
75
|
for (const branch of branches) {
|
|
70
|
-
if (typeof branch.$ref !== "string") continue;
|
|
76
|
+
if (typeof branch !== "object" || branch === null || !("$ref" in branch) || typeof branch.$ref !== "string") continue;
|
|
71
77
|
const resolved = resolveRef(branch, context);
|
|
72
78
|
if (strictMockResolvedImportMatches(typeName, resolved.imports[0], importBareName)) return resolved.schema;
|
|
73
79
|
}
|
|
74
80
|
return;
|
|
75
81
|
}
|
|
76
|
-
if (typeof
|
|
77
|
-
const resolved = resolveRef(
|
|
82
|
+
if (typeof objectSchema.$ref === "string") {
|
|
83
|
+
const resolved = resolveRef(objectSchema, context);
|
|
78
84
|
if (strictMockResolvedImportMatches(typeName, resolved.imports[0], importBareName)) return resolved.schema;
|
|
79
85
|
return;
|
|
80
86
|
}
|
|
81
|
-
return
|
|
87
|
+
return objectSchema;
|
|
82
88
|
}
|
|
83
89
|
function getMockFactoryReturnType(typeName, mockOptions) {
|
|
84
90
|
return isStrictMock(mockOptions) ? getStrictMockTypeName(typeName) : typeName;
|
|
@@ -140,10 +146,9 @@ function getStrictMockSchemaKindsFromResponses(responses, context) {
|
|
|
140
146
|
if (!value || !response.originalSchema) continue;
|
|
141
147
|
const baseType = value.endsWith("[]") ? value.slice(0, -2) : value;
|
|
142
148
|
if (!/^[A-Z]\w*$/.test(baseType)) continue;
|
|
143
|
-
const schema = response.originalSchema;
|
|
144
|
-
if (value.endsWith("[]") && schema
|
|
145
|
-
|
|
146
|
-
kinds[baseType] = classifyStrictMockSchemaType(items, context);
|
|
149
|
+
const schema = asObjectSchema(response.originalSchema);
|
|
150
|
+
if (value.endsWith("[]") && schema?.type === "array" && schema.items && typeof schema.items === "object") {
|
|
151
|
+
kinds[baseType] = classifyStrictMockSchemaType(schema.items, context);
|
|
147
152
|
continue;
|
|
148
153
|
}
|
|
149
154
|
kinds[baseType] = classifyStrictMockSchemaType(resolveStrictMockSchemaForTypeName(baseType, response.originalSchema, context) ?? response.originalSchema, context);
|
|
@@ -214,46 +219,6 @@ function mergeStrictMockSchemaKinds(...groups) {
|
|
|
214
219
|
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
215
220
|
}
|
|
216
221
|
//#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
|
-
}
|
|
256
|
-
//#endregion
|
|
257
222
|
//#region src/delay.ts
|
|
258
223
|
const getDelay = (override, options) => {
|
|
259
224
|
const mswOptions = options && isMswMock(options) ? options : void 0;
|
|
@@ -268,12 +233,12 @@ const getDelay = (override, options) => {
|
|
|
268
233
|
//#region src/faker/getters/all-of-required.ts
|
|
269
234
|
function derefAllOfMember(member, context, seen) {
|
|
270
235
|
let current = member;
|
|
271
|
-
while (current && typeof current === "object" &&
|
|
236
|
+
while (current && typeof current === "object" && "$ref" in current && typeof current.$ref === "string") {
|
|
272
237
|
const ref = current.$ref;
|
|
273
|
-
if (
|
|
238
|
+
if (seen.has(ref)) return;
|
|
274
239
|
seen.add(ref);
|
|
275
240
|
const { refPaths } = getRefInfo(ref, context);
|
|
276
|
-
current = Array.isArray(refPaths) ?
|
|
241
|
+
current = Array.isArray(refPaths) ? getAtPath(context.spec, refPaths) : void 0;
|
|
277
242
|
}
|
|
278
243
|
return current && typeof current === "object" ? current : void 0;
|
|
279
244
|
}
|
|
@@ -340,6 +305,161 @@ const DEFAULT_FORMAT_MOCK = {
|
|
|
340
305
|
};
|
|
341
306
|
const DEFAULT_OBJECT_KEY_MOCK = "faker.string.alphanumeric(5)";
|
|
342
307
|
//#endregion
|
|
308
|
+
//#region src/faker/format-example-value.ts
|
|
309
|
+
const DATE_FORMATS = /* @__PURE__ */ new Set(["date", "date-time"]);
|
|
310
|
+
function isDateFormat(format) {
|
|
311
|
+
return format !== void 0 && DATE_FORMATS.has(format);
|
|
312
|
+
}
|
|
313
|
+
function isSchemaObject(schema) {
|
|
314
|
+
return typeof schema === "object" && schema !== null && !Array.isArray(schema);
|
|
315
|
+
}
|
|
316
|
+
function resolveSchema(schema, context) {
|
|
317
|
+
if (!schema || typeof schema !== "object") return;
|
|
318
|
+
if (typeof schema.$ref === "string") {
|
|
319
|
+
const resolved = resolveRef(schema, context).schema;
|
|
320
|
+
return resolved && typeof resolved === "object" ? resolved : void 0;
|
|
321
|
+
}
|
|
322
|
+
return schema;
|
|
323
|
+
}
|
|
324
|
+
function mergePropertySchemas(...schemas) {
|
|
325
|
+
const merged = {};
|
|
326
|
+
for (const schema of schemas) {
|
|
327
|
+
if (!schema?.properties) continue;
|
|
328
|
+
for (const [key, prop] of Object.entries(schema.properties)) if (isSchemaObject(prop)) merged[key] = prop;
|
|
329
|
+
}
|
|
330
|
+
return merged;
|
|
331
|
+
}
|
|
332
|
+
function getEffectiveScalarFormat(resolved, context) {
|
|
333
|
+
if (!resolved) return;
|
|
334
|
+
if (isDateFormat(resolved.format)) return resolved.format;
|
|
335
|
+
const oneOf = resolved.oneOf;
|
|
336
|
+
const anyOf = resolved.anyOf;
|
|
337
|
+
for (const variant of [...oneOf ?? [], ...anyOf ?? []]) {
|
|
338
|
+
const resolvedVariant = resolveSchema(isSchemaObject(variant) ? variant : void 0, context);
|
|
339
|
+
if (isDateFormat(resolvedVariant?.format)) return resolvedVariant.format;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Resolves compositional schemas (allOf / oneOf / anyOf) so example formatting
|
|
344
|
+
* can see property formats on nested and referenced types.
|
|
345
|
+
*/
|
|
346
|
+
function resolveExampleSchema(schema, context, seenRefs = /* @__PURE__ */ new Set()) {
|
|
347
|
+
if (!schema || typeof schema !== "object") return;
|
|
348
|
+
if (typeof schema.$ref === "string") {
|
|
349
|
+
const ref = schema.$ref;
|
|
350
|
+
if (seenRefs.has(ref)) {
|
|
351
|
+
const resolved = resolveRef(schema, context).schema;
|
|
352
|
+
return resolved && typeof resolved === "object" ? resolved : void 0;
|
|
353
|
+
}
|
|
354
|
+
seenRefs = new Set(seenRefs).add(ref);
|
|
355
|
+
}
|
|
356
|
+
const resolved = resolveSchema(schema, context);
|
|
357
|
+
if (!resolved) return;
|
|
358
|
+
const allOf = resolved.allOf;
|
|
359
|
+
const oneOf = resolved.oneOf;
|
|
360
|
+
const anyOf = resolved.anyOf;
|
|
361
|
+
const compositors = [
|
|
362
|
+
...allOf ?? [],
|
|
363
|
+
...oneOf ?? [],
|
|
364
|
+
...anyOf ?? []
|
|
365
|
+
];
|
|
366
|
+
const properties = mergePropertySchemas(resolved, ...compositors.map((sub) => resolveExampleSchema(sub, context, seenRefs)));
|
|
367
|
+
const baseResolved = resolved;
|
|
368
|
+
if (resolved.type === "array" && isSchemaObject(resolved.items)) {
|
|
369
|
+
const items = resolveExampleSchema(resolved.items, context, seenRefs);
|
|
370
|
+
const itemProperties = items?.properties;
|
|
371
|
+
const normalizedItems = itemProperties && Object.keys(itemProperties).length > 0 ? {
|
|
372
|
+
type: "object",
|
|
373
|
+
properties: itemProperties
|
|
374
|
+
} : items;
|
|
375
|
+
return {
|
|
376
|
+
...baseResolved,
|
|
377
|
+
...Object.keys(properties).length > 0 ? { properties } : {},
|
|
378
|
+
items: normalizedItems ?? resolved.items
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
if (Object.keys(properties).length > 0) return {
|
|
382
|
+
...baseResolved,
|
|
383
|
+
properties
|
|
384
|
+
};
|
|
385
|
+
if (compositors.length > 0 && (oneOf ?? anyOf)) {
|
|
386
|
+
const variantProperties = mergePropertySchemas(...compositors.map((sub) => resolveExampleSchema(sub, context, seenRefs)));
|
|
387
|
+
if (Object.keys(variantProperties).length > 0) return {
|
|
388
|
+
type: "object",
|
|
389
|
+
properties: variantProperties
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
const scalarFormat = getEffectiveScalarFormat(resolved, context);
|
|
393
|
+
if (scalarFormat) return {
|
|
394
|
+
...baseResolved,
|
|
395
|
+
format: scalarFormat
|
|
396
|
+
};
|
|
397
|
+
return resolved;
|
|
398
|
+
}
|
|
399
|
+
function formatLiteralValue(example, schema, context) {
|
|
400
|
+
if (example === null) return "null";
|
|
401
|
+
if (example === void 0) return "undefined";
|
|
402
|
+
const resolved = resolveExampleSchema(schema, context);
|
|
403
|
+
if (Array.isArray(example)) {
|
|
404
|
+
const itemsSchema = resolved?.type === "array" && isSchemaObject(resolved.items) ? resolveExampleSchema(resolved.items, context) : resolved;
|
|
405
|
+
return `[${example.map((item) => formatLiteralValue(item, itemsSchema, context)).join(", ")}]`;
|
|
406
|
+
}
|
|
407
|
+
if (typeof example === "object") {
|
|
408
|
+
const properties = resolved?.properties ?? {};
|
|
409
|
+
return `{ ${Object.entries(example).map(([key, value]) => {
|
|
410
|
+
const propSchema = properties[key];
|
|
411
|
+
const resolvedProp = isSchemaObject(propSchema) ? resolveExampleSchema(propSchema, context) : void 0;
|
|
412
|
+
return `${/^[a-zA-Z_$][\w$]*$/.test(key) ? key : JSON.stringify(key)}: ${formatLiteralValue(value, resolvedProp, context)}`;
|
|
413
|
+
}).join(", ")} }`;
|
|
414
|
+
}
|
|
415
|
+
if (context.output.override.useDates && typeof example === "string" && isDateFormat(getEffectiveScalarFormat(resolved, context))) return `new Date(${JSON.stringify(example)})`;
|
|
416
|
+
return JSON.stringify(example);
|
|
417
|
+
}
|
|
418
|
+
function formatSchemaExampleValue(example, schema, context) {
|
|
419
|
+
if (!context.output.override.useDates || schema === void 0) return JSON.stringify(example);
|
|
420
|
+
return formatLiteralValue(example, schema, context);
|
|
421
|
+
}
|
|
422
|
+
//#endregion
|
|
423
|
+
//#region src/faker/imports.ts
|
|
424
|
+
/**
|
|
425
|
+
* Appends entries added to `source` since `sinceIndex`. Uses indexed push
|
|
426
|
+
* instead of spread so large import batches (common with `schemas: true`
|
|
427
|
+
* delegation on wide objects) do not overflow the call stack.
|
|
428
|
+
*/
|
|
429
|
+
function appendImportsDelta(target, source, sinceIndex) {
|
|
430
|
+
for (let i = sinceIndex; i < source.length; i++) target.push(source[i]);
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Merge imports returned from mock resolution when the shared imports array
|
|
434
|
+
* was not mutated in place. Enum mocks and nested object factories return
|
|
435
|
+
* their imports separately; schema-factory delegation mutates `sharedImports`
|
|
436
|
+
* directly and must not be merged again from `resolvedImports`.
|
|
437
|
+
*/
|
|
438
|
+
function mergeReturnedMockImports(sharedImports, sharedBefore, resolvedImports) {
|
|
439
|
+
if (sharedImports.length === sharedBefore) appendImportsDelta(sharedImports, resolvedImports, 0);
|
|
440
|
+
}
|
|
441
|
+
/** Recover type imports referenced by nested oneOf split mock helpers. */
|
|
442
|
+
function collectSplitMockTypeImports(implementations) {
|
|
443
|
+
const seen = /* @__PURE__ */ new Set();
|
|
444
|
+
const imports = [];
|
|
445
|
+
const addType = (name) => {
|
|
446
|
+
if (!name || seen.has(name)) return;
|
|
447
|
+
seen.add(name);
|
|
448
|
+
imports.push({
|
|
449
|
+
name,
|
|
450
|
+
values: false
|
|
451
|
+
});
|
|
452
|
+
};
|
|
453
|
+
for (const impl of implementations) {
|
|
454
|
+
for (const match of impl.matchAll(/export const get\w+Mock = \(\s*overrideResponse: Partial<(\w+)[^)]*\):\s*(\w+)\s*=>/g)) {
|
|
455
|
+
addType(match[1]);
|
|
456
|
+
addType(match[2]);
|
|
457
|
+
}
|
|
458
|
+
for (const match of impl.matchAll(/export const get\w+Mock[\s\S]*?MockWithNullableOverrides<(?:Extract<(\w+),[^>]+>|(\w+)),/g)) addType(match[1] ?? match[2]);
|
|
459
|
+
}
|
|
460
|
+
return imports;
|
|
461
|
+
}
|
|
462
|
+
//#endregion
|
|
343
463
|
//#region src/faker/getters/object.ts
|
|
344
464
|
const overrideVarName = "overrideResponse";
|
|
345
465
|
function wrapRootNullableObjectValue(value, schemaItem, mockOptions, combine) {
|
|
@@ -362,13 +482,13 @@ function reExpansionWouldCollapse(ref, context, existingReferencedProperties, no
|
|
|
362
482
|
const targetRequired = target?.required;
|
|
363
483
|
if (!targetProperties || !Array.isArray(targetRequired)) return false;
|
|
364
484
|
return Object.entries(targetProperties).some(([key, property]) => {
|
|
365
|
-
if (!targetRequired.includes(key) ||
|
|
485
|
+
if (!targetRequired.includes(key) || isInlineSchema(property)) return false;
|
|
366
486
|
if (!existingReferencedProperties.includes(getReferenceName$1(property.$ref, context))) return false;
|
|
367
487
|
return nonNullable || !isNullableRefTarget(property.$ref, context);
|
|
368
488
|
});
|
|
369
489
|
}
|
|
370
490
|
function getMockObject({ item, mockOptions, operationId, tags, combine, context, imports, existingReferencedProperties, existingReferencedAllOfRefs = [], splitMockImplementations, allowOverride = false }) {
|
|
371
|
-
if (
|
|
491
|
+
if (typeof item.$ref === "string") return resolveMockValue({
|
|
372
492
|
schema: {
|
|
373
493
|
...item,
|
|
374
494
|
name: item.name,
|
|
@@ -476,14 +596,14 @@ function getMockObject({ item, mockOptions, operationId, tags, combine, context,
|
|
|
476
596
|
const propertyScalars = entries.map(([key, prop]) => {
|
|
477
597
|
if (combine?.includedProperties.includes(key)) return;
|
|
478
598
|
const isRequired = mockOptions?.required ?? (Array.isArray(itemRequired) ? itemRequired : []).includes(key);
|
|
479
|
-
const hasNullable =
|
|
480
|
-
const refName =
|
|
599
|
+
const hasNullable = isInlineSchema(prop) && isSchemaNullable(prop);
|
|
600
|
+
const refName = !isInlineSchema(prop) ? getReferenceName$1(prop.$ref, context) : "";
|
|
481
601
|
const isRecursiveRef = !!refName && existingReferencedProperties.includes(refName);
|
|
482
602
|
if (isRecursiveRef) {
|
|
483
603
|
if (!isRequired) return;
|
|
484
604
|
const keyDefinition = getKey(key);
|
|
485
|
-
if (!mockOptions?.nonNullable && (hasNullable ||
|
|
486
|
-
if (new Set(existingReferencedProperties).size !== existingReferencedProperties.length ||
|
|
605
|
+
if (!mockOptions?.nonNullable && (hasNullable || !isInlineSchema(prop) && isNullableRefTarget(prop.$ref, context))) return `${keyDefinition}: null`;
|
|
606
|
+
if (new Set(existingReferencedProperties).size !== existingReferencedProperties.length || !isInlineSchema(prop) && reExpansionWouldCollapse(prop.$ref, context, existingReferencedProperties, mockOptions?.nonNullable)) {
|
|
487
607
|
imports.push({ name: refName });
|
|
488
608
|
return `${keyDefinition}: {} as unknown as ${refName}`;
|
|
489
609
|
}
|
|
@@ -516,14 +636,14 @@ function getMockObject({ item, mockOptions, operationId, tags, combine, context,
|
|
|
516
636
|
imports.push({ name: refName });
|
|
517
637
|
return `${keyDefinition}: {} as unknown as ${refName}`;
|
|
518
638
|
}
|
|
519
|
-
const hasDefault = "default" in prop && prop.default !== void 0;
|
|
639
|
+
const hasDefault = typeof prop === "object" && prop !== null && "default" in prop && prop.default !== void 0;
|
|
520
640
|
if (!isRequired && !resolvedValue.overrided && !hasDefault) {
|
|
521
641
|
if (resolvedValue.nullWrapped) return `${keyDefinition}: ${resolvedValue.value}`;
|
|
522
642
|
const omitValue = mockOptions?.nonNullable || !hasNullable ? "undefined" : "null";
|
|
523
643
|
if (omitValue === "undefined" && mockOptions?.exactOptional) return `...(faker.datatype.boolean() ? {${keyDefinition}: ${resolvedValue.value}} : {})`;
|
|
524
644
|
return `${keyDefinition}: faker.helpers.arrayElement([${resolvedValue.value}, ${omitValue}])`;
|
|
525
645
|
}
|
|
526
|
-
if (Array.isArray(prop.type) && prop.type.includes("null") && !resolvedValue.nullWrapped && !resolvedValue.overrided && !mockOptions?.nonNullable) return `${keyDefinition}: faker.helpers.arrayElement([${resolvedValue.value}, null])`;
|
|
646
|
+
if (typeof prop === "object" && prop !== null && "type" in prop && Array.isArray(prop.type) && prop.type.includes("null") && !resolvedValue.nullWrapped && !resolvedValue.overrided && !mockOptions?.nonNullable) return `${keyDefinition}: faker.helpers.arrayElement([${resolvedValue.value}, null])`;
|
|
527
647
|
return `${keyDefinition}: ${resolvedValue.value}`;
|
|
528
648
|
}).filter(Boolean);
|
|
529
649
|
if (allowOverride) propertyScalars.push(`...${overrideVarName}`);
|
|
@@ -549,7 +669,7 @@ function getMockObject({ item, mockOptions, operationId, tags, combine, context,
|
|
|
549
669
|
};
|
|
550
670
|
}
|
|
551
671
|
const additionalProperties = itemAdditionalProperties;
|
|
552
|
-
if (
|
|
672
|
+
if (!isInlineSchema(additionalProperties) && existingReferencedProperties.includes(getReferenceName$1(additionalProperties.$ref, context))) {
|
|
553
673
|
const { value: finalValue, nullWrapped } = wrapRootNullableObjectValue(`{}`, schemaItem, mockOptions, combine);
|
|
554
674
|
return {
|
|
555
675
|
value: finalValue,
|
|
@@ -662,11 +782,12 @@ function shouldExtractArrayItem(items, context, operationId, parentName) {
|
|
|
662
782
|
const itemsRef = extractItemsRef(items);
|
|
663
783
|
if (itemsRef) try {
|
|
664
784
|
const { schema } = resolveRef({ $ref: itemsRef }, context);
|
|
785
|
+
if (typeof schema !== "object" || schema === null) return false;
|
|
665
786
|
return isResolvedSchemaObjectLike(schema);
|
|
666
787
|
} catch {
|
|
667
788
|
return false;
|
|
668
789
|
}
|
|
669
|
-
if (
|
|
790
|
+
if (!isInlineSchema(items)) return false;
|
|
670
791
|
const schema = items;
|
|
671
792
|
if (isNullableArrayItem(schema)) return false;
|
|
672
793
|
if (schema.oneOf || schema.anyOf) return false;
|
|
@@ -747,115 +868,6 @@ function extractArrayItemMock({ items, propertyName, parentName, operationId, ta
|
|
|
747
868
|
return `{...${factoryName}()${isStrictMock(mockOptions) ? ` as ${getStrictMockTypeName(typeName)}` : ""}}`;
|
|
748
869
|
}
|
|
749
870
|
//#endregion
|
|
750
|
-
//#region src/faker/format-example-value.ts
|
|
751
|
-
const DATE_FORMATS = /* @__PURE__ */ new Set(["date", "date-time"]);
|
|
752
|
-
function isDateFormat(format) {
|
|
753
|
-
return format !== void 0 && DATE_FORMATS.has(format);
|
|
754
|
-
}
|
|
755
|
-
function isSchemaObject(schema) {
|
|
756
|
-
return typeof schema === "object" && schema !== null && !Array.isArray(schema);
|
|
757
|
-
}
|
|
758
|
-
function resolveSchema(schema, context) {
|
|
759
|
-
if (!schema) return;
|
|
760
|
-
if (isReference(schema)) return resolveRef(schema, context).schema;
|
|
761
|
-
return schema;
|
|
762
|
-
}
|
|
763
|
-
function mergePropertySchemas(...schemas) {
|
|
764
|
-
const merged = {};
|
|
765
|
-
for (const schema of schemas) {
|
|
766
|
-
if (!schema?.properties) continue;
|
|
767
|
-
for (const [key, prop] of Object.entries(schema.properties)) if (isSchemaObject(prop)) merged[key] = prop;
|
|
768
|
-
}
|
|
769
|
-
return merged;
|
|
770
|
-
}
|
|
771
|
-
function getEffectiveScalarFormat(resolved, context) {
|
|
772
|
-
if (!resolved) return;
|
|
773
|
-
if (isDateFormat(resolved.format)) return resolved.format;
|
|
774
|
-
const oneOf = resolved.oneOf;
|
|
775
|
-
const anyOf = resolved.anyOf;
|
|
776
|
-
for (const variant of [...oneOf ?? [], ...anyOf ?? []]) {
|
|
777
|
-
const resolvedVariant = resolveSchema(isReference(variant) || isSchemaObject(variant) ? variant : void 0, context);
|
|
778
|
-
if (isDateFormat(resolvedVariant?.format)) return resolvedVariant.format;
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
/**
|
|
782
|
-
* Resolves compositional schemas (allOf / oneOf / anyOf) so example formatting
|
|
783
|
-
* can see property formats on nested and referenced types.
|
|
784
|
-
*/
|
|
785
|
-
function resolveExampleSchema(schema, context, seenRefs = /* @__PURE__ */ new Set()) {
|
|
786
|
-
if (!schema) return;
|
|
787
|
-
if (isReference(schema)) {
|
|
788
|
-
const ref = schema.$ref;
|
|
789
|
-
if (ref && seenRefs.has(ref)) return resolveRef(schema, context).schema;
|
|
790
|
-
if (ref) seenRefs = new Set(seenRefs).add(ref);
|
|
791
|
-
}
|
|
792
|
-
const resolved = resolveSchema(schema, context);
|
|
793
|
-
if (!resolved) return;
|
|
794
|
-
const allOf = resolved.allOf;
|
|
795
|
-
const oneOf = resolved.oneOf;
|
|
796
|
-
const anyOf = resolved.anyOf;
|
|
797
|
-
const compositors = [
|
|
798
|
-
...allOf ?? [],
|
|
799
|
-
...oneOf ?? [],
|
|
800
|
-
...anyOf ?? []
|
|
801
|
-
];
|
|
802
|
-
const properties = mergePropertySchemas(resolved, ...compositors.map((sub) => resolveExampleSchema(sub, context, seenRefs)));
|
|
803
|
-
const baseResolved = resolved;
|
|
804
|
-
if (resolved.type === "array" && isSchemaObject(resolved.items)) {
|
|
805
|
-
const items = resolveExampleSchema(resolved.items, context, seenRefs);
|
|
806
|
-
const itemProperties = items?.properties;
|
|
807
|
-
const normalizedItems = itemProperties && Object.keys(itemProperties).length > 0 ? {
|
|
808
|
-
type: "object",
|
|
809
|
-
properties: itemProperties
|
|
810
|
-
} : items;
|
|
811
|
-
return {
|
|
812
|
-
...baseResolved,
|
|
813
|
-
...Object.keys(properties).length > 0 ? { properties } : {},
|
|
814
|
-
items: normalizedItems ?? resolved.items
|
|
815
|
-
};
|
|
816
|
-
}
|
|
817
|
-
if (Object.keys(properties).length > 0) return {
|
|
818
|
-
...baseResolved,
|
|
819
|
-
properties
|
|
820
|
-
};
|
|
821
|
-
if (compositors.length > 0 && (oneOf ?? anyOf)) {
|
|
822
|
-
const variantProperties = mergePropertySchemas(...compositors.map((sub) => resolveExampleSchema(sub, context, seenRefs)));
|
|
823
|
-
if (Object.keys(variantProperties).length > 0) return {
|
|
824
|
-
type: "object",
|
|
825
|
-
properties: variantProperties
|
|
826
|
-
};
|
|
827
|
-
}
|
|
828
|
-
const scalarFormat = getEffectiveScalarFormat(resolved, context);
|
|
829
|
-
if (scalarFormat) return {
|
|
830
|
-
...baseResolved,
|
|
831
|
-
format: scalarFormat
|
|
832
|
-
};
|
|
833
|
-
return resolved;
|
|
834
|
-
}
|
|
835
|
-
function formatLiteralValue(example, schema, context) {
|
|
836
|
-
if (example === null) return "null";
|
|
837
|
-
if (example === void 0) return "undefined";
|
|
838
|
-
const resolved = resolveExampleSchema(schema, context);
|
|
839
|
-
if (Array.isArray(example)) {
|
|
840
|
-
const itemsSchema = resolved?.type === "array" && isSchemaObject(resolved.items) ? resolveExampleSchema(resolved.items, context) : resolved;
|
|
841
|
-
return `[${example.map((item) => formatLiteralValue(item, itemsSchema, context)).join(", ")}]`;
|
|
842
|
-
}
|
|
843
|
-
if (typeof example === "object") {
|
|
844
|
-
const properties = resolved?.properties ?? {};
|
|
845
|
-
return `{ ${Object.entries(example).map(([key, value]) => {
|
|
846
|
-
const propSchema = properties[key];
|
|
847
|
-
const resolvedProp = isSchemaObject(propSchema) ? resolveExampleSchema(propSchema, context) : void 0;
|
|
848
|
-
return `${/^[a-zA-Z_$][\w$]*$/.test(key) ? key : JSON.stringify(key)}: ${formatLiteralValue(value, resolvedProp, context)}`;
|
|
849
|
-
}).join(", ")} }`;
|
|
850
|
-
}
|
|
851
|
-
if (context.output.override.useDates && typeof example === "string" && isDateFormat(getEffectiveScalarFormat(resolved, context))) return `new Date(${JSON.stringify(example)})`;
|
|
852
|
-
return JSON.stringify(example);
|
|
853
|
-
}
|
|
854
|
-
function formatSchemaExampleValue(example, schema, context) {
|
|
855
|
-
if (!context.output.override.useDates || schema === void 0) return JSON.stringify(example);
|
|
856
|
-
return formatLiteralValue(example, schema, context);
|
|
857
|
-
}
|
|
858
|
-
//#endregion
|
|
859
871
|
//#region src/faker/getters/scalar.ts
|
|
860
872
|
function getMockScalar({ item, imports, mockOptions, operationId, tags, combine, context, existingReferencedProperties, existingReferencedAllOfRefs = [], splitMockImplementations, allowOverride = false }) {
|
|
861
873
|
const safeMockOptions = mockOptions ?? {};
|
|
@@ -885,6 +897,18 @@ function getMockScalar({ item, imports, mockOptions, operationId, tags, combine,
|
|
|
885
897
|
overrided: true
|
|
886
898
|
};
|
|
887
899
|
}
|
|
900
|
+
if (isNullOnlyEnum(item)) return {
|
|
901
|
+
value: "null",
|
|
902
|
+
imports: [],
|
|
903
|
+
name: item.name,
|
|
904
|
+
nullWrapped: true
|
|
905
|
+
};
|
|
906
|
+
if ("const" in item && item.type === void 0) return {
|
|
907
|
+
value: toJsLiteral(item.const),
|
|
908
|
+
imports: [],
|
|
909
|
+
name: item.name,
|
|
910
|
+
nullWrapped: item.const === null
|
|
911
|
+
};
|
|
888
912
|
const formatOverrides = safeMockOptions.format ?? {};
|
|
889
913
|
const ALL_FORMAT = {
|
|
890
914
|
...DEFAULT_FORMAT_MOCK,
|
|
@@ -993,18 +1017,19 @@ function getMockScalar({ item, imports, mockOptions, operationId, tags, combine,
|
|
|
993
1017
|
name: item.name
|
|
994
1018
|
};
|
|
995
1019
|
}
|
|
996
|
-
if (!item.items) return {
|
|
1020
|
+
if (!item.items || typeof item.items !== "object") return {
|
|
997
1021
|
value: "[]",
|
|
998
1022
|
imports: [],
|
|
999
1023
|
name: item.name
|
|
1000
1024
|
};
|
|
1001
|
-
const
|
|
1025
|
+
const itemsSchema = item.items;
|
|
1026
|
+
const itemsRef = extractItemsRef(itemsSchema);
|
|
1002
1027
|
if (itemsRef && existingReferencedProperties.includes(getRefInfo(itemsRef, context).name)) return {
|
|
1003
1028
|
value: "[]",
|
|
1004
1029
|
imports: [],
|
|
1005
1030
|
name: item.name
|
|
1006
1031
|
};
|
|
1007
|
-
const resolvedItems = itemsRef && !("$ref" in
|
|
1032
|
+
const resolvedItems = itemsRef && !("$ref" in itemsSchema) ? { $ref: itemsRef } : itemsSchema;
|
|
1008
1033
|
const { value, enums, imports: resolvedImports } = resolveMockValue({
|
|
1009
1034
|
schema: {
|
|
1010
1035
|
...resolvedItems,
|
|
@@ -1132,14 +1157,14 @@ function getMockScalar({ item, imports, mockOptions, operationId, tags, combine,
|
|
|
1132
1157
|
}
|
|
1133
1158
|
}
|
|
1134
1159
|
function extractItemsRef(items) {
|
|
1135
|
-
if (
|
|
1160
|
+
if (!isInlineSchema(items)) return items.$ref;
|
|
1136
1161
|
for (const key of [
|
|
1137
1162
|
"allOf",
|
|
1138
1163
|
"oneOf",
|
|
1139
1164
|
"anyOf"
|
|
1140
1165
|
]) {
|
|
1141
1166
|
const composed = items[key];
|
|
1142
|
-
if (Array.isArray(composed) && composed.length === 1 &&
|
|
1167
|
+
if (Array.isArray(composed) && composed.length === 1 && !isInlineSchema(composed[0])) return composed[0].$ref;
|
|
1143
1168
|
}
|
|
1144
1169
|
}
|
|
1145
1170
|
function getItemType(item) {
|
|
@@ -1258,7 +1283,7 @@ function resolveRefTarget(ref, context) {
|
|
|
1258
1283
|
if (!fragment) return void 0;
|
|
1259
1284
|
const { refPaths } = getRefInfo(ref, context);
|
|
1260
1285
|
if (!Array.isArray(refPaths)) return void 0;
|
|
1261
|
-
return
|
|
1286
|
+
return getAtPath(context.spec, refPaths);
|
|
1262
1287
|
}
|
|
1263
1288
|
/**
|
|
1264
1289
|
* Whether a schema accepts `null`, in any of the spellings orval sees.
|
|
@@ -1334,7 +1359,7 @@ function hasOverrideTouchingSchema(schemaProperties, mockOptions, operationId, t
|
|
|
1334
1359
|
});
|
|
1335
1360
|
}
|
|
1336
1361
|
function resolveMockValue({ schema, mockOptions, operationId, tags, combine, context, imports, existingReferencedProperties, existingReferencedAllOfRefs = [], splitMockImplementations, allowOverride }) {
|
|
1337
|
-
if (
|
|
1362
|
+
if (!isInlineSchema(schema)) {
|
|
1338
1363
|
const schemaReference = schema;
|
|
1339
1364
|
const schemaRefPath = typeof schema.$ref === "string" ? schema.$ref : "";
|
|
1340
1365
|
const { name, refPaths } = getRefInfo(schemaRefPath, context);
|
|
@@ -1345,7 +1370,7 @@ function resolveMockValue({ schema, mockOptions, operationId, tags, combine, con
|
|
|
1345
1370
|
path: schemaReference.path,
|
|
1346
1371
|
isRef: true,
|
|
1347
1372
|
required: [...schemaRef?.required ?? [], ...getRequiredKeys(schemaReference, name)],
|
|
1348
|
-
...Array.isArray(schemaReference.type) ? { type: schemaReference.type } : {}
|
|
1373
|
+
..."type" in schemaReference && Array.isArray(schemaReference.type) ? { type: schemaReference.type } : {}
|
|
1349
1374
|
};
|
|
1350
1375
|
if (combine?.separator === "allOf" && newSchema.discriminator && newSchema.oneOf) {
|
|
1351
1376
|
const parentDiscriminator = newSchema.discriminator;
|
|
@@ -1462,12 +1487,12 @@ function resolveMockValue({ schema, mockOptions, operationId, tags, combine, con
|
|
|
1462
1487
|
};
|
|
1463
1488
|
}
|
|
1464
1489
|
function getType(schema) {
|
|
1465
|
-
if (
|
|
1490
|
+
if (!isInlineSchema(schema)) return;
|
|
1466
1491
|
return schema.type ?? (schema.properties ? "object" : schema.items ? "array" : void 0);
|
|
1467
1492
|
}
|
|
1468
1493
|
function resolvesToObjectLike(schema, context, seen = /* @__PURE__ */ new Set()) {
|
|
1469
1494
|
let resolved;
|
|
1470
|
-
if (
|
|
1495
|
+
if (!isInlineSchema(schema)) {
|
|
1471
1496
|
if (typeof schema.$ref !== "string" || seen.has(schema.$ref)) return false;
|
|
1472
1497
|
seen = new Set(seen).add(schema.$ref);
|
|
1473
1498
|
resolved = resolveRefTarget(schema.$ref, context);
|
|
@@ -1489,7 +1514,7 @@ function combineSchemasMock({ item, separator, mockOptions, operationId, tags, c
|
|
|
1489
1514
|
const includedProperties = [...combine?.includedProperties ?? []];
|
|
1490
1515
|
const separatorItems = item[separator] ?? [];
|
|
1491
1516
|
const itemRequired = item.required;
|
|
1492
|
-
const isRefAndNotExisting =
|
|
1517
|
+
const isRefAndNotExisting = typeof item.$ref === "string" && !existingReferencedProperties.includes(item.name);
|
|
1493
1518
|
const discriminator = item.discriminator;
|
|
1494
1519
|
const itemProperties = item.properties;
|
|
1495
1520
|
const discriminatorPropertyName = separator === "oneOf" && discriminator?.mapping && discriminator.propertyName && itemProperties && discriminator.propertyName in itemProperties ? discriminator.propertyName : void 0;
|
|
@@ -1537,9 +1562,10 @@ function combineSchemasMock({ item, separator, mockOptions, operationId, tags, c
|
|
|
1537
1562
|
includedProperties.push(...itemResolvedValue?.includedProperties ?? []);
|
|
1538
1563
|
combineImports.push(...itemResolvedValue?.imports ?? []);
|
|
1539
1564
|
let containsOnlyPrimitiveValues = true;
|
|
1565
|
+
let hasNullMember = false;
|
|
1540
1566
|
let value = separator === "allOf" ? "" : "faker.helpers.arrayElement([";
|
|
1541
1567
|
for (const val of separatorItems) {
|
|
1542
|
-
const refName =
|
|
1568
|
+
const refName = isInlineSchema(val) ? "" : getReferenceName(val.$ref, context);
|
|
1543
1569
|
if (separator === "allOf" ? refName && (refName === item.name || existingReferencedProperties.includes(refName) && !item.isRef || existingReferencedAllOfRefs.includes(refName)) : refName && existingReferencedProperties.includes(refName)) {
|
|
1544
1570
|
if (separatorItems.length === 1) value = "undefined";
|
|
1545
1571
|
continue;
|
|
@@ -1591,6 +1617,10 @@ function combineSchemasMock({ item, separator, mockOptions, operationId, tags, c
|
|
|
1591
1617
|
continue;
|
|
1592
1618
|
}
|
|
1593
1619
|
}
|
|
1620
|
+
if (separator !== "allOf" && resolvedValue.value === "null") {
|
|
1621
|
+
if (hasNullMember) continue;
|
|
1622
|
+
hasNullMember = true;
|
|
1623
|
+
}
|
|
1594
1624
|
value += `${resolvedValue.value},`;
|
|
1595
1625
|
}
|
|
1596
1626
|
let finalValue = value === "undefined" || separator !== "allOf" && value === "faker.helpers.arrayElement([" ? "undefined" : `${separator === "allOf" && !containsOnlyPrimitiveValues ? "{" : ""}${value}${separator === "allOf" ? containsOnlyPrimitiveValues ? "" : "}" : "])"}`;
|
|
@@ -1706,8 +1736,9 @@ function getResponsesMockDefinition({ operationId, tags, returnType, responses,
|
|
|
1706
1736
|
for (const response of responses) {
|
|
1707
1737
|
const { value: definition, example, examples, imports, isRef } = response;
|
|
1708
1738
|
let { originalSchema } = response;
|
|
1739
|
+
const schemaObject = originalSchema && typeof originalSchema === "object" ? originalSchema : void 0;
|
|
1709
1740
|
if (context.output.override.mock?.useExamples || mockOptions?.useExamples) {
|
|
1710
|
-
const exampleValue = unwrapExampleValue(example ??
|
|
1741
|
+
const exampleValue = unwrapExampleValue(example ?? schemaObject?.example ?? getExampleEntries(examples)[0] ?? getExampleEntries(schemaObject?.examples)[0]);
|
|
1711
1742
|
if (exampleValue !== void 0) {
|
|
1712
1743
|
const formatted = formatSchemaExampleValue(exampleValue, originalSchema, context);
|
|
1713
1744
|
result.definitions.push(transformer ? transformer(formatted, returnType) : formatted);
|
|
@@ -1724,7 +1755,7 @@ function getResponsesMockDefinition({ operationId, tags, returnType, responses,
|
|
|
1724
1755
|
format: "binary"
|
|
1725
1756
|
};
|
|
1726
1757
|
else if (!originalSchema) continue;
|
|
1727
|
-
const resolvedSchema = resolveRef(originalSchema, context).schema;
|
|
1758
|
+
const resolvedSchema = toObjectSchema(resolveRef(originalSchema, context).schema);
|
|
1728
1759
|
const responseImports = imports ? [...imports] : [];
|
|
1729
1760
|
const importsBefore = responseImports.length;
|
|
1730
1761
|
const scalar = getMockScalar({
|
|
@@ -1857,7 +1888,11 @@ function generateDefinition(name, route, getResponseMockFunctionNameBase, handle
|
|
|
1857
1888
|
const hasTextLikeContentType = contentTypes.some((ct) => isTextLikeContentType(ct));
|
|
1858
1889
|
const isExactlyStringReturnType = isTypeExactlyString(returnType);
|
|
1859
1890
|
const isTextResponse = isExactlyStringReturnType && hasTextLikeContentType || contentTypesByPreference.some((ct) => isTextLikeContentType(ct));
|
|
1860
|
-
const isSchemaBinary = (r) =>
|
|
1891
|
+
const isSchemaBinary = (r) => {
|
|
1892
|
+
const schema = r.originalSchema;
|
|
1893
|
+
if (!schema || typeof schema !== "object") return false;
|
|
1894
|
+
return schema.format === "binary" || schema.contentMediaType === "application/octet-stream" && !schema.contentEncoding;
|
|
1895
|
+
};
|
|
1861
1896
|
const isBinaryResponse = preferredContentTypeMatch ? responsesByPreference.some((r) => isSchemaBinary(r)) : contentTypesByPreference.some((ct) => isBinaryLikeContentType(ct)) || responsesByPreference.some((r) => isSchemaBinary(r));
|
|
1862
1897
|
const isReturnHttpResponse = value && value !== "undefined";
|
|
1863
1898
|
const getResponseMockFunctionName = `${getResponseMockFunctionNameBase}${pascal(name)}`;
|