@kubb/plugin-faker 5.0.0-beta.64 → 5.0.0-beta.74
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/README.md +2 -2
- package/dist/index.cjs +968 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +302 -5
- package/dist/index.js +944 -9
- package/dist/index.js.map +1 -1
- package/package.json +8 -17
- package/dist/Faker-BA4l8DTe.d.ts +0 -27
- package/dist/Faker-DUx7jvCo.js +0 -277
- package/dist/Faker-DUx7jvCo.js.map +0 -1
- package/dist/Faker-Ds2xP2-k.cjs +0 -349
- package/dist/Faker-Ds2xP2-k.cjs.map +0 -1
- package/dist/components.cjs +0 -3
- package/dist/components.d.ts +0 -2
- package/dist/components.js +0 -2
- package/dist/fakerGenerator-BNysC6rh.d.ts +0 -14
- package/dist/fakerGenerator-BeKRKYuy.cjs +0 -669
- package/dist/fakerGenerator-BeKRKYuy.cjs.map +0 -1
- package/dist/fakerGenerator-D5Bcy5WY.js +0 -659
- package/dist/fakerGenerator-D5Bcy5WY.js.map +0 -1
- package/dist/generators.cjs +0 -3
- package/dist/generators.d.ts +0 -2
- package/dist/generators.js +0 -2
- package/dist/printerFaker-BzEB43Jz.d.ts +0 -239
- /package/dist/{chunk-C0LytTxp.js → rolldown-runtime-C0LytTxp.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,10 +1,277 @@
|
|
|
1
|
-
import "./
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
1
|
+
import "./rolldown-runtime-C0LytTxp.js";
|
|
2
|
+
import { buildObject, containsCircularRef, extractRefName, jsStringEscape, mapSchemaItems, mapSchemaMembers, objectKey, stringify, toRegExpString } from "@kubb/ast/utils";
|
|
3
|
+
import { createFunctionParameter, createFunctionParameters, functionPrinter, pluginTsName } from "@kubb/plugin-ts";
|
|
4
|
+
import { File, Function, jsxRenderer } from "@kubb/renderer-jsx";
|
|
5
|
+
import path, { posix } from "node:path";
|
|
6
|
+
import { ast, defineGenerator, definePlugin, defineResolver } from "@kubb/core";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
|
|
7
8
|
import { createHash } from "node:crypto";
|
|
9
|
+
//#region src/utils.ts
|
|
10
|
+
/**
|
|
11
|
+
* Returns the `@faker-js/faker` named export for a locale code.
|
|
12
|
+
*
|
|
13
|
+
* Without a locale, returns `'faker'` for the default English instance.
|
|
14
|
+
* With a locale, the language code is converted to upper case and joined with any region suffix.
|
|
15
|
+
*
|
|
16
|
+
* @example Default
|
|
17
|
+
* `localeToFakerImport() // 'faker'`
|
|
18
|
+
*
|
|
19
|
+
* @example Simple locale
|
|
20
|
+
* `localeToFakerImport('de') // 'fakerDE'`
|
|
21
|
+
*
|
|
22
|
+
* @example Compound locale
|
|
23
|
+
* `localeToFakerImport('de_AT') // 'fakerDE_AT'`
|
|
24
|
+
*/
|
|
25
|
+
function localeToFakerImport(locale) {
|
|
26
|
+
if (!locale) return "faker";
|
|
27
|
+
const parts = locale.split("_");
|
|
28
|
+
parts[0] = parts[0].toUpperCase();
|
|
29
|
+
return `faker${parts.join("_")}`;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Determines if a schema node can be overridden during faker generation.
|
|
33
|
+
*/
|
|
34
|
+
function canOverrideSchema(node) {
|
|
35
|
+
return new Set([
|
|
36
|
+
"array",
|
|
37
|
+
"tuple",
|
|
38
|
+
"object",
|
|
39
|
+
"intersection",
|
|
40
|
+
"union",
|
|
41
|
+
"enum",
|
|
42
|
+
"ref",
|
|
43
|
+
"string",
|
|
44
|
+
"email",
|
|
45
|
+
"url",
|
|
46
|
+
"uuid",
|
|
47
|
+
"number",
|
|
48
|
+
"integer",
|
|
49
|
+
"bigint",
|
|
50
|
+
"boolean",
|
|
51
|
+
"date",
|
|
52
|
+
"time",
|
|
53
|
+
"datetime",
|
|
54
|
+
"blob"
|
|
55
|
+
]).has(node.type);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolves a parameter name based on its location (path, query, header, etc.) using the provided resolver.
|
|
59
|
+
*/
|
|
60
|
+
function resolveParamNameByLocation(resolver, node, param) {
|
|
61
|
+
switch (param.in) {
|
|
62
|
+
case "path": return resolver.resolvePathParamsName(node, param);
|
|
63
|
+
case "query": return resolver.resolveQueryParamsName(node, param);
|
|
64
|
+
case "header": return resolver.resolveHeaderParamsName(node, param);
|
|
65
|
+
default: return resolver.resolveParamName(node, param);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function shouldInlineSingleResponseSchema(schema) {
|
|
69
|
+
return new Set([
|
|
70
|
+
"any",
|
|
71
|
+
"unknown",
|
|
72
|
+
"void",
|
|
73
|
+
"null",
|
|
74
|
+
"array",
|
|
75
|
+
"tuple",
|
|
76
|
+
"string",
|
|
77
|
+
"email",
|
|
78
|
+
"url",
|
|
79
|
+
"uuid",
|
|
80
|
+
"number",
|
|
81
|
+
"integer",
|
|
82
|
+
"bigint",
|
|
83
|
+
"boolean",
|
|
84
|
+
"date",
|
|
85
|
+
"time",
|
|
86
|
+
"datetime",
|
|
87
|
+
"blob",
|
|
88
|
+
"enum",
|
|
89
|
+
"union"
|
|
90
|
+
]).has(schema.type);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Builds a response schema as a union of all response statuses.
|
|
94
|
+
* Returns null if no responses are provided, or embeds single simple responses inline.
|
|
95
|
+
*/
|
|
96
|
+
function buildResponseUnionSchema(node, resolver) {
|
|
97
|
+
const responses = node.responses.filter((response) => response.content?.[0]?.schema);
|
|
98
|
+
if (!responses.length) return null;
|
|
99
|
+
if (responses.length === 1) {
|
|
100
|
+
const schema = responses[0].content?.[0]?.schema;
|
|
101
|
+
if (schema && shouldInlineSingleResponseSchema(schema)) return schema;
|
|
102
|
+
return ast.factory.createSchema({
|
|
103
|
+
type: "ref",
|
|
104
|
+
name: resolver.resolveResponseStatusName(node, responses[0].statusCode)
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return ast.factory.createSchema({
|
|
108
|
+
type: "union",
|
|
109
|
+
members: responses.map((response) => ast.factory.createSchema({
|
|
110
|
+
type: "ref",
|
|
111
|
+
name: resolver.resolveResponseStatusName(node, response.statusCode)
|
|
112
|
+
}))
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
const SCALAR_TYPES$1 = new Set([
|
|
116
|
+
"string",
|
|
117
|
+
"email",
|
|
118
|
+
"url",
|
|
119
|
+
"uuid",
|
|
120
|
+
"number",
|
|
121
|
+
"integer",
|
|
122
|
+
"bigint",
|
|
123
|
+
"boolean",
|
|
124
|
+
"date",
|
|
125
|
+
"time",
|
|
126
|
+
"datetime",
|
|
127
|
+
"blob",
|
|
128
|
+
"enum"
|
|
129
|
+
]);
|
|
130
|
+
const ARRAY_TYPES$1 = new Set(["array"]);
|
|
131
|
+
function toRelativeImportPath(from, to) {
|
|
132
|
+
const relativePath = posix.relative(posix.dirname(from), to);
|
|
133
|
+
return relativePath.startsWith("../") ? relativePath : `./${relativePath}`;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Resolves a type reference, determining if it needs an import statement or inline type reference.
|
|
137
|
+
* Takes into account whether the type can be overridden and the file paths.
|
|
138
|
+
*/
|
|
139
|
+
function resolveTypeReference({ node, canOverride, name, typeName, filePath, typeFilePath }) {
|
|
140
|
+
const { usesTypeName } = resolveFakerTypeUsage(node, typeName, canOverride);
|
|
141
|
+
if (!usesTypeName) return { typeName };
|
|
142
|
+
if (name === typeName) return { typeName: `import('${toRelativeImportPath(filePath, typeFilePath)}').${typeName}` };
|
|
143
|
+
return {
|
|
144
|
+
importPath: typeFilePath,
|
|
145
|
+
typeName
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Maps a schema node type to its corresponding scalar type representation.
|
|
150
|
+
* Returns the type name for enums or the base type (string, number, etc.) for primitives.
|
|
151
|
+
*/
|
|
152
|
+
function getScalarType(node, typeName) {
|
|
153
|
+
switch (node.type) {
|
|
154
|
+
case "string":
|
|
155
|
+
case "email":
|
|
156
|
+
case "url":
|
|
157
|
+
case "uuid": return "string";
|
|
158
|
+
case "number":
|
|
159
|
+
case "integer": return "number";
|
|
160
|
+
case "bigint": return "bigint";
|
|
161
|
+
case "boolean": return "boolean";
|
|
162
|
+
case "date":
|
|
163
|
+
case "time": return node.representation === "date" ? "Date" : "string";
|
|
164
|
+
case "datetime": return "string";
|
|
165
|
+
case "blob": return "Blob";
|
|
166
|
+
case "enum": return typeName;
|
|
167
|
+
default: return typeName;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Resolves faker type usage information for a schema.
|
|
172
|
+
* Determines the data type, return type, and whether it uses the type name.
|
|
173
|
+
*/
|
|
174
|
+
function resolveFakerTypeUsage(node, typeName, canOverride) {
|
|
175
|
+
const isArray = ARRAY_TYPES$1.has(node.type);
|
|
176
|
+
const isTuple = node.type === "tuple";
|
|
177
|
+
const isScalar = SCALAR_TYPES$1.has(node.type);
|
|
178
|
+
let dataType = `Partial<${typeName}>`;
|
|
179
|
+
if (isArray || isTuple || node.type === "union" || node.type === "enum") dataType = typeName;
|
|
180
|
+
if (isScalar) dataType = getScalarType(node, typeName);
|
|
181
|
+
let returnType = canOverride ? typeName : null;
|
|
182
|
+
if (isScalar) returnType = getScalarType(node, typeName);
|
|
183
|
+
return {
|
|
184
|
+
dataType,
|
|
185
|
+
returnType,
|
|
186
|
+
usesTypeName: dataType.includes(typeName) || Boolean(returnType?.includes(typeName))
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region src/components/Faker.tsx
|
|
191
|
+
const OBJECT_TYPES = new Set(["object", "intersection"]);
|
|
192
|
+
const ARRAY_TYPES = new Set(["array"]);
|
|
193
|
+
const SCALAR_TYPES = new Set([
|
|
194
|
+
"string",
|
|
195
|
+
"email",
|
|
196
|
+
"url",
|
|
197
|
+
"uuid",
|
|
198
|
+
"number",
|
|
199
|
+
"integer",
|
|
200
|
+
"bigint",
|
|
201
|
+
"boolean",
|
|
202
|
+
"date",
|
|
203
|
+
"time",
|
|
204
|
+
"datetime",
|
|
205
|
+
"blob",
|
|
206
|
+
"enum"
|
|
207
|
+
]);
|
|
208
|
+
const declarationPrinter = functionPrinter({ mode: "declaration" });
|
|
209
|
+
function Faker({ node, description, name, typeName, printer, seed, canOverride }) {
|
|
210
|
+
const fakerText = printer.print(node) ?? "undefined";
|
|
211
|
+
const isArray = ARRAY_TYPES.has(node.type);
|
|
212
|
+
const isObject = OBJECT_TYPES.has(node.type);
|
|
213
|
+
const isTuple = node.type === "tuple";
|
|
214
|
+
const isScalar = SCALAR_TYPES.has(node.type);
|
|
215
|
+
const useGenericOverride = canOverride && isObject;
|
|
216
|
+
const fakerTextWithOverride = (() => {
|
|
217
|
+
if (canOverride && isTuple) return `data || ${fakerText}`;
|
|
218
|
+
if (canOverride && isArray) return `[\n ...${fakerText},\n ...(data || [])\n]`;
|
|
219
|
+
if (canOverride && isScalar) return `data ?? ${fakerText}`;
|
|
220
|
+
return fakerText;
|
|
221
|
+
})();
|
|
222
|
+
const { dataType, returnType: resolvedReturnType } = resolveFakerTypeUsage(node, typeName, canOverride);
|
|
223
|
+
if (!useGenericOverride) {
|
|
224
|
+
const params = createFunctionParameters({ params: [createFunctionParameter({
|
|
225
|
+
name: /\bdata\b/.test(fakerTextWithOverride) ? "data" : "_data",
|
|
226
|
+
type: dataType,
|
|
227
|
+
optional: true
|
|
228
|
+
})] });
|
|
229
|
+
const paramsSignature = declarationPrinter.print(params) ?? "";
|
|
230
|
+
const returnType = resolvedReturnType;
|
|
231
|
+
const returnExpression = node.type === "ref" && canOverride && returnType ? `${fakerTextWithOverride} as ${returnType}` : fakerTextWithOverride;
|
|
232
|
+
return /* @__PURE__ */ jsx(File.Source, {
|
|
233
|
+
name,
|
|
234
|
+
isExportable: true,
|
|
235
|
+
isIndexable: true,
|
|
236
|
+
children: /* @__PURE__ */ jsxs(Function, {
|
|
237
|
+
export: true,
|
|
238
|
+
name,
|
|
239
|
+
JSDoc: { comments: description ? [`@description ${jsStringEscape(description)}`] : [] },
|
|
240
|
+
params: canOverride ? paramsSignature : void 0,
|
|
241
|
+
returnType: returnType ?? void 0,
|
|
242
|
+
children: [seed ? /* @__PURE__ */ jsxs(Fragment, { children: [`faker.seed(${JSON.stringify(seed)})`, /* @__PURE__ */ jsx("br", {})] }) : void 0, `return ${returnExpression}`]
|
|
243
|
+
})
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
const functionSignature = `${description ? `/**\n * @description ${jsStringEscape(description)}\n */\n ` : ""}export function ${name}<TData extends Partial<${typeName}> = object>(data?: TData)`;
|
|
247
|
+
const seedCode = seed ? `faker.seed(${JSON.stringify(seed)})\n ` : "";
|
|
248
|
+
const { cyclicSchemas, schemaName } = printer.options;
|
|
249
|
+
const functionBody = node.type === "object" && !!cyclicSchemas && (node.properties ?? []).some((p) => containsCircularRef(p.schema, {
|
|
250
|
+
circularSchemas: cyclicSchemas,
|
|
251
|
+
excludeName: schemaName
|
|
252
|
+
})) ? `{
|
|
253
|
+
${seedCode}const defaultFakeData = ${fakerText}
|
|
254
|
+
if (data) {
|
|
255
|
+
for (const [key, value] of Object.entries(data)) {
|
|
256
|
+
Object.defineProperty(defaultFakeData, key, { value, configurable: true, writable: true, enumerable: true })
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return defaultFakeData as Omit<typeof defaultFakeData, keyof TData> & TData
|
|
260
|
+
}` : `{
|
|
261
|
+
${seedCode}const defaultFakeData = ${fakerText}
|
|
262
|
+
return {
|
|
263
|
+
...defaultFakeData,
|
|
264
|
+
...(data || {}),
|
|
265
|
+
} as Omit<typeof defaultFakeData, keyof TData> & TData
|
|
266
|
+
}`;
|
|
267
|
+
return /* @__PURE__ */ jsxs(File.Source, {
|
|
268
|
+
name,
|
|
269
|
+
isExportable: true,
|
|
270
|
+
isIndexable: true,
|
|
271
|
+
children: [functionSignature, functionBody]
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
//#endregion
|
|
8
275
|
//#region ../../internals/utils/src/casing.ts
|
|
9
276
|
/**
|
|
10
277
|
* Shared implementation for camelCase and PascalCase conversion.
|
|
@@ -57,6 +324,51 @@ function toFilePath(name, caseLast = camelCase) {
|
|
|
57
324
|
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
|
|
58
325
|
}
|
|
59
326
|
//#endregion
|
|
327
|
+
//#region ../../internals/utils/src/imports.ts
|
|
328
|
+
function escapeRegExp(value) {
|
|
329
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
330
|
+
}
|
|
331
|
+
function getImportNames(entry) {
|
|
332
|
+
return (Array.isArray(entry.name) ? entry.name : [entry.name]).map((name) => {
|
|
333
|
+
if (typeof name === "string") return name;
|
|
334
|
+
return name.name ?? name.propertyName;
|
|
335
|
+
}).filter((name) => Boolean(name));
|
|
336
|
+
}
|
|
337
|
+
function filterUsedImports(imports, text, skipImportNames = []) {
|
|
338
|
+
const skip = new Set(skipImportNames);
|
|
339
|
+
return imports.filter((entry) => {
|
|
340
|
+
return getImportNames(entry).some((name) => {
|
|
341
|
+
if (skip.has(name)) return false;
|
|
342
|
+
return new RegExp(`\\b${escapeRegExp(name)}\\b(?=\\s*\\()`).test(text);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
function aliasConflictingImports(imports, reservedNames) {
|
|
347
|
+
const reservedNameSet = new Set(reservedNames);
|
|
348
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
349
|
+
return {
|
|
350
|
+
imports: imports.map((entry) => {
|
|
351
|
+
const aliasedNames = (Array.isArray(entry.name) ? entry.name : [entry.name]).map((item) => {
|
|
352
|
+
if (typeof item !== "string" || !reservedNameSet.has(item)) return item;
|
|
353
|
+
const alias = `${item}Schema`;
|
|
354
|
+
aliases.set(item, alias);
|
|
355
|
+
return {
|
|
356
|
+
propertyName: item,
|
|
357
|
+
name: alias
|
|
358
|
+
};
|
|
359
|
+
});
|
|
360
|
+
return aliasedNames.some((item) => typeof item === "object" && item.name) ? {
|
|
361
|
+
...entry,
|
|
362
|
+
name: aliasedNames
|
|
363
|
+
} : entry;
|
|
364
|
+
}),
|
|
365
|
+
aliases
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
function rewriteAliasedImports(text, aliases) {
|
|
369
|
+
return Array.from(aliases).reduce((acc, [name, alias]) => acc.replace(new RegExp(`\\b${escapeRegExp(name)}\\b`, "g"), alias), text);
|
|
370
|
+
}
|
|
371
|
+
//#endregion
|
|
60
372
|
//#region ../../internals/utils/src/reserved.ts
|
|
61
373
|
/**
|
|
62
374
|
* JavaScript and Java reserved words.
|
|
@@ -180,6 +492,77 @@ function ensureValidVarName(name) {
|
|
|
180
492
|
return `_${name}`;
|
|
181
493
|
}
|
|
182
494
|
//#endregion
|
|
495
|
+
//#region ../../internals/shared/src/params.ts
|
|
496
|
+
const caseParamsCache = /* @__PURE__ */ new WeakMap();
|
|
497
|
+
/**
|
|
498
|
+
* Applies camelCase to parameter names and returns a new array without mutating the input.
|
|
499
|
+
*
|
|
500
|
+
* Run it before handing parameters to schema builders so output property keys get the right casing
|
|
501
|
+
* while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
|
|
502
|
+
* original array is returned unchanged. Results are cached per input array.
|
|
503
|
+
*/
|
|
504
|
+
function caseParams(params, casing) {
|
|
505
|
+
if (!casing) return params;
|
|
506
|
+
const cached = caseParamsCache.get(params);
|
|
507
|
+
if (cached) return cached;
|
|
508
|
+
const result = params.map((param) => ({
|
|
509
|
+
...param,
|
|
510
|
+
name: camelCase(param.name)
|
|
511
|
+
}));
|
|
512
|
+
caseParamsCache.set(params, result);
|
|
513
|
+
return result;
|
|
514
|
+
}
|
|
515
|
+
//#endregion
|
|
516
|
+
//#region ../../internals/shared/src/operation.ts
|
|
517
|
+
/**
|
|
518
|
+
* Maps a content type to the PascalCase suffix used to name per-content-type variants
|
|
519
|
+
* (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).
|
|
520
|
+
*/
|
|
521
|
+
function getContentTypeSuffix(contentType) {
|
|
522
|
+
const baseType = contentType.split(";")[0].trim();
|
|
523
|
+
if (baseType === "application/json") return "Json";
|
|
524
|
+
if (baseType === "multipart/form-data") return "FormData";
|
|
525
|
+
if (baseType === "application/x-www-form-urlencoded") return "FormUrlEncoded";
|
|
526
|
+
const parts = (baseType.split("/").pop() ?? baseType).split(/[^a-zA-Z0-9]+/).filter(Boolean);
|
|
527
|
+
if (parts.length === 0) return "Unknown";
|
|
528
|
+
return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Appends a content-type suffix to a base name, keeping a trailing `Data` segment last
|
|
532
|
+
* (e.g. `AddPetData` + `Json` → `AddPetJsonData`, `AddPetStatus200` + `Xml` → `AddPetStatus200Xml`).
|
|
533
|
+
*/
|
|
534
|
+
function getPerContentTypeName(baseName, suffix) {
|
|
535
|
+
if (baseName.endsWith("Data")) return suffix.endsWith("Data") ? baseName.slice(0, -4) + suffix : `${baseName.slice(0, -4)}${suffix}Data`;
|
|
536
|
+
return baseName + suffix;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Resolves per-content-type variant names for a set of content entries, deduplicating suffix
|
|
540
|
+
* collisions with a numeric counter. Entries without a schema are skipped. The returned `suffix` is
|
|
541
|
+
* the final (possibly counter-augmented) value, so callers can derive parallel names in another
|
|
542
|
+
* namespace (e.g. plugin-faker deriving the matching plugin-ts type name).
|
|
543
|
+
*/
|
|
544
|
+
function resolveContentTypeVariants(entries, baseName) {
|
|
545
|
+
const usedNames = /* @__PURE__ */ new Set();
|
|
546
|
+
return entries.filter((entry) => entry.schema).map((entry) => {
|
|
547
|
+
const baseSuffix = getContentTypeSuffix(entry.contentType);
|
|
548
|
+
let suffix = baseSuffix;
|
|
549
|
+
let name = getPerContentTypeName(baseName, suffix);
|
|
550
|
+
let counter = 2;
|
|
551
|
+
while (usedNames.has(name)) {
|
|
552
|
+
suffix = `${baseSuffix}${counter++}`;
|
|
553
|
+
name = getPerContentTypeName(baseName, suffix);
|
|
554
|
+
}
|
|
555
|
+
usedNames.add(name);
|
|
556
|
+
return {
|
|
557
|
+
name,
|
|
558
|
+
suffix,
|
|
559
|
+
schema: entry.schema,
|
|
560
|
+
keysToOmit: entry.keysToOmit,
|
|
561
|
+
contentType: entry.contentType
|
|
562
|
+
};
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
//#endregion
|
|
183
566
|
//#region ../../internals/shared/src/group.ts
|
|
184
567
|
/**
|
|
185
568
|
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
@@ -211,6 +594,560 @@ function createGroupConfig(group) {
|
|
|
211
594
|
};
|
|
212
595
|
}
|
|
213
596
|
//#endregion
|
|
597
|
+
//#region src/printers/printerFaker.ts
|
|
598
|
+
const fakerKeywordMapper = {
|
|
599
|
+
any: () => "undefined",
|
|
600
|
+
unknown: () => "undefined",
|
|
601
|
+
void: () => "undefined",
|
|
602
|
+
number: (min, max) => {
|
|
603
|
+
if (max !== void 0 && min !== void 0) return `faker.number.float({ min: ${min}, max: ${max} })`;
|
|
604
|
+
if (max !== void 0) return `faker.number.float({ max: ${max} })`;
|
|
605
|
+
if (min !== void 0) return `faker.number.float({ min: ${min} })`;
|
|
606
|
+
return "faker.number.float()";
|
|
607
|
+
},
|
|
608
|
+
integer: (min, max) => {
|
|
609
|
+
if (max !== void 0 && min !== void 0) return `faker.number.int({ min: ${min}, max: ${max} })`;
|
|
610
|
+
if (max !== void 0) return `faker.number.int({ max: ${max} })`;
|
|
611
|
+
if (min !== void 0) return `faker.number.int({ min: ${min} })`;
|
|
612
|
+
return "faker.number.int()";
|
|
613
|
+
},
|
|
614
|
+
bigint: () => "faker.number.bigInt()",
|
|
615
|
+
string: (min, max) => {
|
|
616
|
+
if (max !== void 0 && min !== void 0) return `faker.string.alpha({ length: { min: ${min}, max: ${max} } })`;
|
|
617
|
+
if (max !== void 0) return `faker.string.alpha({ length: ${max} })`;
|
|
618
|
+
if (min !== void 0) return `faker.string.alpha({ length: ${min} })`;
|
|
619
|
+
return "faker.string.alpha()";
|
|
620
|
+
},
|
|
621
|
+
boolean: () => "faker.datatype.boolean()",
|
|
622
|
+
null: () => "null",
|
|
623
|
+
array: (items = [], min, max) => {
|
|
624
|
+
if (items.length > 1) return `faker.helpers.arrayElements([${items.join(", ")}])`;
|
|
625
|
+
const item = items.at(0);
|
|
626
|
+
if (min !== void 0 && max !== void 0) return `faker.helpers.multiple(() => (${item}), { count: { min: ${min}, max: ${max} }})`;
|
|
627
|
+
if (min !== void 0) return `faker.helpers.multiple(() => (${item}), { count: ${min} })`;
|
|
628
|
+
if (max !== void 0) return `faker.helpers.multiple(() => (${item}), { count: { min: 0, max: ${max} }})`;
|
|
629
|
+
return `faker.helpers.multiple(() => (${item}))`;
|
|
630
|
+
},
|
|
631
|
+
tuple: (items = []) => `[${items.join(", ")}]`,
|
|
632
|
+
enum: (items = [], type = "any") => `faker.helpers.arrayElement<${type}>([${items.join(", ")}])`,
|
|
633
|
+
union: (items = []) => `faker.helpers.arrayElement<any>([${items.join(", ")}])`,
|
|
634
|
+
datetime: () => "faker.date.anytime().toISOString()",
|
|
635
|
+
date: (representation = "string", parser = "faker") => {
|
|
636
|
+
if (representation === "string") {
|
|
637
|
+
if (parser !== "faker") return `${parser}(faker.date.anytime()).format("YYYY-MM-DD")`;
|
|
638
|
+
return "faker.date.anytime().toISOString().substring(0, 10)";
|
|
639
|
+
}
|
|
640
|
+
if (parser !== "faker") throw new Error(`type '${representation}' and parser '${parser}' can not work together`);
|
|
641
|
+
return "faker.date.anytime()";
|
|
642
|
+
},
|
|
643
|
+
time: (representation = "string", parser = "faker") => {
|
|
644
|
+
if (representation === "string") {
|
|
645
|
+
if (parser !== "faker") return `${parser}(faker.date.anytime()).format("HH:mm:ss")`;
|
|
646
|
+
return "faker.date.anytime().toISOString().substring(11, 19)";
|
|
647
|
+
}
|
|
648
|
+
if (parser !== "faker") throw new Error(`type '${representation}' and parser '${parser}' can not work together`);
|
|
649
|
+
return "faker.date.anytime()";
|
|
650
|
+
},
|
|
651
|
+
uuid: () => "faker.string.uuid()",
|
|
652
|
+
url: () => "faker.internet.url()",
|
|
653
|
+
and: (items = []) => {
|
|
654
|
+
if (items.length === 0) return "{}";
|
|
655
|
+
if (items.length === 1) return items[0] ?? "{}";
|
|
656
|
+
return `{...${items.join(", ...")}}`;
|
|
657
|
+
},
|
|
658
|
+
matches: (value = "", regexGenerator = "faker") => {
|
|
659
|
+
if (regexGenerator === "randexp") return `${toRegExpString(value, "RandExp")}.gen()`;
|
|
660
|
+
return `faker.helpers.fromRegExp("${value}")`;
|
|
661
|
+
},
|
|
662
|
+
email: () => "faker.internet.email()",
|
|
663
|
+
blob: () => "faker.image.url() as unknown as Blob"
|
|
664
|
+
};
|
|
665
|
+
function getEnumValues(node) {
|
|
666
|
+
if (node.namedEnumValues?.length) return node.namedEnumValues.map((item) => item.value);
|
|
667
|
+
return node.enumValues ?? [];
|
|
668
|
+
}
|
|
669
|
+
function parseEnumValue(value) {
|
|
670
|
+
if (typeof value === "string") return stringify(value);
|
|
671
|
+
return value;
|
|
672
|
+
}
|
|
673
|
+
/** Reads the discriminator literal off a variant, or `undefined` when it can't be determined. */
|
|
674
|
+
function getDiscriminatorValue(member, discriminatorPropertyName) {
|
|
675
|
+
const prop = ast.narrowSchema(member, "object")?.properties?.find((p) => p.name === discriminatorPropertyName);
|
|
676
|
+
const enumNode = prop ? ast.narrowSchema(prop.schema, "enum") : null;
|
|
677
|
+
return enumNode ? getEnumValues(enumNode)[0] : void 0;
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Type expression for an object property's value, indexed off the parent `typeName`.
|
|
681
|
+
*
|
|
682
|
+
* In a union (`oneOf`), a key that only some branches declare turns a plain `NonNullable<T>[K]`
|
|
683
|
+
* into a TS2339 error, so union members guard the access. The breakdown is below.
|
|
684
|
+
*/
|
|
685
|
+
function indexedTypeName(typeName, propertyName, nestedInUnion) {
|
|
686
|
+
const key = JSON.stringify(propertyName);
|
|
687
|
+
return nestedInUnion ? `(NonNullable<${typeName}> & Record<${key}, unknown>)[${key}]` : `NonNullable<${typeName}>[${key}]`;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Creates a Faker printer that generates mock data generation code from schema nodes.
|
|
691
|
+
* Handles circular references gracefully by emitting memoizing getters for cyclic properties.
|
|
692
|
+
*/
|
|
693
|
+
const printerFaker = ast.createPrinter((options) => {
|
|
694
|
+
const printNested = (node, overrideOptions = {}) => {
|
|
695
|
+
return printerFaker({
|
|
696
|
+
...options,
|
|
697
|
+
...overrideOptions,
|
|
698
|
+
nodes: options.nodes
|
|
699
|
+
}).print(node) ?? "undefined";
|
|
700
|
+
};
|
|
701
|
+
return {
|
|
702
|
+
name: "faker",
|
|
703
|
+
options,
|
|
704
|
+
nodes: {
|
|
705
|
+
any: () => fakerKeywordMapper.any(),
|
|
706
|
+
unknown: () => fakerKeywordMapper.unknown(),
|
|
707
|
+
void: () => fakerKeywordMapper.void(),
|
|
708
|
+
boolean: () => fakerKeywordMapper.boolean(),
|
|
709
|
+
null: () => fakerKeywordMapper.null(),
|
|
710
|
+
string(node) {
|
|
711
|
+
if (node.pattern) return fakerKeywordMapper.matches(node.pattern, this.options.regexGenerator);
|
|
712
|
+
return fakerKeywordMapper.string(node.min, node.max);
|
|
713
|
+
},
|
|
714
|
+
email: () => fakerKeywordMapper.email(),
|
|
715
|
+
url: () => fakerKeywordMapper.url(),
|
|
716
|
+
uuid: () => fakerKeywordMapper.uuid(),
|
|
717
|
+
number(node) {
|
|
718
|
+
return fakerKeywordMapper.number(node.min, node.max);
|
|
719
|
+
},
|
|
720
|
+
integer(node) {
|
|
721
|
+
return fakerKeywordMapper.integer(node.min, node.max);
|
|
722
|
+
},
|
|
723
|
+
bigint: () => fakerKeywordMapper.bigint(),
|
|
724
|
+
blob: () => fakerKeywordMapper.blob(),
|
|
725
|
+
datetime: () => fakerKeywordMapper.datetime(),
|
|
726
|
+
date(node) {
|
|
727
|
+
return fakerKeywordMapper.date(node.representation ?? "string", this.options.dateParser);
|
|
728
|
+
},
|
|
729
|
+
time(node) {
|
|
730
|
+
return fakerKeywordMapper.time(node.representation ?? "string", this.options.dateParser);
|
|
731
|
+
},
|
|
732
|
+
ref(node) {
|
|
733
|
+
const refName = node.ref ? extractRefName(node.ref) ?? node.name ?? node.schema?.name : node.name ?? node.schema?.name;
|
|
734
|
+
if (!refName) throw new Error("Name not defined for ref node");
|
|
735
|
+
if (this.options.schemaName && refName === this.options.schemaName) return "undefined as any";
|
|
736
|
+
const resolvedName = node.ref ? this.options.resolver.resolveName(refName) : refName;
|
|
737
|
+
if (!this.options.nestedInObject) return `${resolvedName}(data)`;
|
|
738
|
+
return `${resolvedName}()`;
|
|
739
|
+
},
|
|
740
|
+
enum(node) {
|
|
741
|
+
return fakerKeywordMapper.enum(getEnumValues(node).map(parseEnumValue), this.options.typeName);
|
|
742
|
+
},
|
|
743
|
+
union(node) {
|
|
744
|
+
const { discriminatorPropertyName } = node;
|
|
745
|
+
const baseTypeName = this.options.typeName;
|
|
746
|
+
const items = mapSchemaMembers(node, (member) => {
|
|
747
|
+
const value = discriminatorPropertyName ? getDiscriminatorValue(member, discriminatorPropertyName) : void 0;
|
|
748
|
+
if (baseTypeName && value !== void 0) return printNested(member, {
|
|
749
|
+
typeName: `Extract<NonNullable<${baseTypeName}>, { ${JSON.stringify(discriminatorPropertyName)}: ${parseEnumValue(value)} }>`,
|
|
750
|
+
nestedInObject: true
|
|
751
|
+
});
|
|
752
|
+
return printNested(member, {
|
|
753
|
+
typeName: baseTypeName,
|
|
754
|
+
nestedInObject: true,
|
|
755
|
+
nestedInUnion: true
|
|
756
|
+
});
|
|
757
|
+
}).map(({ output }) => output).filter((item) => Boolean(item));
|
|
758
|
+
return fakerKeywordMapper.union(items);
|
|
759
|
+
},
|
|
760
|
+
intersection(node) {
|
|
761
|
+
const items = mapSchemaMembers(node, (member) => printNested(member, { nestedInObject: true })).map(({ output }) => output).filter((item) => Boolean(item) && item !== "undefined");
|
|
762
|
+
return fakerKeywordMapper.and(items);
|
|
763
|
+
},
|
|
764
|
+
array(node) {
|
|
765
|
+
const items = mapSchemaItems(node, (member) => printNested(member, {
|
|
766
|
+
typeName: this.options.typeName ? `NonNullable<${this.options.typeName}>[number]` : void 0,
|
|
767
|
+
nestedInObject: true
|
|
768
|
+
})).map(({ output }) => output).filter((item) => Boolean(item));
|
|
769
|
+
return fakerKeywordMapper.array(items, node.min, node.max);
|
|
770
|
+
},
|
|
771
|
+
tuple(node) {
|
|
772
|
+
const items = (node.items ?? []).map((member, index) => printNested(member, {
|
|
773
|
+
typeName: this.options.typeName ? `NonNullable<${this.options.typeName}>[${index}]` : void 0,
|
|
774
|
+
nestedInObject: true
|
|
775
|
+
})).filter((item) => Boolean(item));
|
|
776
|
+
return fakerKeywordMapper.tuple(items);
|
|
777
|
+
},
|
|
778
|
+
object(node) {
|
|
779
|
+
const cyclicSchemas = this.options.cyclicSchemas;
|
|
780
|
+
return buildObject((node.properties ?? []).map((property) => {
|
|
781
|
+
if (this.options.mapper && Object.hasOwn(this.options.mapper, property.name)) return `${objectKey(property.name)}: ${this.options.mapper[property.name]}`;
|
|
782
|
+
const value = printNested(property.schema, {
|
|
783
|
+
typeName: this.options.typeName ? indexedTypeName(this.options.typeName, property.name, this.options.nestedInUnion) : void 0,
|
|
784
|
+
nestedInObject: true
|
|
785
|
+
}) ?? "undefined";
|
|
786
|
+
if (cyclicSchemas && containsCircularRef(property.schema, {
|
|
787
|
+
circularSchemas: cyclicSchemas,
|
|
788
|
+
excludeName: this.options.schemaName
|
|
789
|
+
})) return `get ${objectKey(property.name)}() { const _value = ${value}; Object.defineProperty(this, ${JSON.stringify(property.name)}, { value: _value, configurable: true, writable: true, enumerable: true }); return _value }`;
|
|
790
|
+
return `${objectKey(property.name)}: ${value}`;
|
|
791
|
+
}));
|
|
792
|
+
},
|
|
793
|
+
...options.nodes
|
|
794
|
+
},
|
|
795
|
+
print(node) {
|
|
796
|
+
return this.transform(node) ?? null;
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
});
|
|
800
|
+
//#endregion
|
|
801
|
+
//#region src/generators/fakerGenerator.tsx
|
|
802
|
+
/**
|
|
803
|
+
* Built-in generator for `@kubb/plugin-faker`. Emits one `createX` factory
|
|
804
|
+
* per schema in the spec plus per-operation request/response factories. Each
|
|
805
|
+
* factory returns a value matching the corresponding TypeScript type from
|
|
806
|
+
* `@kubb/plugin-ts`.
|
|
807
|
+
*/
|
|
808
|
+
const fakerGenerator = defineGenerator({
|
|
809
|
+
name: "faker",
|
|
810
|
+
renderer: jsxRenderer,
|
|
811
|
+
schema(node, ctx) {
|
|
812
|
+
const { adapter, config, resolver, root } = ctx;
|
|
813
|
+
const { output, group, dateParser, regexGenerator, mapper, seed, locale, printer } = ctx.options;
|
|
814
|
+
const pluginTs = ctx.driver.getPlugin(pluginTsName);
|
|
815
|
+
if (!node.name || !pluginTs) return;
|
|
816
|
+
const tsResolver = ctx.driver.getResolver(pluginTsName);
|
|
817
|
+
const schemaName = node.name;
|
|
818
|
+
const isEnumSchema = !!ast.narrowSchema(node, ast.schemaTypes.enum);
|
|
819
|
+
const tsEnumType = pluginTs.options?.enum?.type;
|
|
820
|
+
const tsEnumTypeSuffix = pluginTs.options?.enum?.typeSuffix ?? "Key";
|
|
821
|
+
const schemaTypeName = isEnumSchema && tsEnumType === "asConst" ? tsResolver.resolveEnumKeyName({ name: schemaName }, tsEnumTypeSuffix) : tsResolver.resolveTypeName(schemaName);
|
|
822
|
+
const meta = {
|
|
823
|
+
name: resolver.resolveName(schemaName),
|
|
824
|
+
file: resolver.resolveFile({
|
|
825
|
+
name: schemaName,
|
|
826
|
+
extname: ".ts"
|
|
827
|
+
}, {
|
|
828
|
+
root,
|
|
829
|
+
output,
|
|
830
|
+
group: group ?? void 0
|
|
831
|
+
}),
|
|
832
|
+
typeName: schemaTypeName,
|
|
833
|
+
typeFile: tsResolver.resolveFile({
|
|
834
|
+
name: schemaName,
|
|
835
|
+
extname: ".ts"
|
|
836
|
+
}, {
|
|
837
|
+
root,
|
|
838
|
+
output: pluginTs.options?.output ?? output,
|
|
839
|
+
group: pluginTs.options?.group ?? void 0
|
|
840
|
+
})
|
|
841
|
+
};
|
|
842
|
+
const canOverride = canOverrideSchema(node);
|
|
843
|
+
const cyclicSchemas = new Set(ctx.meta.circularNames);
|
|
844
|
+
const printerInstance = printerFaker({
|
|
845
|
+
resolver,
|
|
846
|
+
schemaName,
|
|
847
|
+
typeName: meta.typeName,
|
|
848
|
+
dateParser,
|
|
849
|
+
regexGenerator,
|
|
850
|
+
mapper,
|
|
851
|
+
nodes: printer?.nodes,
|
|
852
|
+
cyclicSchemas
|
|
853
|
+
});
|
|
854
|
+
const fakerText = printerInstance.print(node) ?? "undefined";
|
|
855
|
+
const typeReference = resolveTypeReference({
|
|
856
|
+
node,
|
|
857
|
+
canOverride,
|
|
858
|
+
name: meta.name,
|
|
859
|
+
typeName: meta.typeName,
|
|
860
|
+
filePath: meta.file.path,
|
|
861
|
+
typeFilePath: meta.typeFile.path
|
|
862
|
+
});
|
|
863
|
+
const usedImports = filterUsedImports(adapter.getImports(node, (schemaName) => ({
|
|
864
|
+
name: resolver.resolveName(schemaName),
|
|
865
|
+
path: resolver.resolveFile({
|
|
866
|
+
name: schemaName,
|
|
867
|
+
extname: ".ts"
|
|
868
|
+
}, {
|
|
869
|
+
root,
|
|
870
|
+
output,
|
|
871
|
+
group: group ?? void 0
|
|
872
|
+
}).path
|
|
873
|
+
})), fakerText);
|
|
874
|
+
return /* @__PURE__ */ jsxs(File, {
|
|
875
|
+
baseName: meta.file.baseName,
|
|
876
|
+
path: meta.file.path,
|
|
877
|
+
meta: meta.file.meta,
|
|
878
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
879
|
+
output,
|
|
880
|
+
config,
|
|
881
|
+
file: {
|
|
882
|
+
path: meta.file.path,
|
|
883
|
+
baseName: meta.file.baseName
|
|
884
|
+
}
|
|
885
|
+
}),
|
|
886
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
887
|
+
output,
|
|
888
|
+
config,
|
|
889
|
+
file: {
|
|
890
|
+
path: meta.file.path,
|
|
891
|
+
baseName: meta.file.baseName
|
|
892
|
+
}
|
|
893
|
+
}),
|
|
894
|
+
children: [
|
|
895
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
896
|
+
name: locale ? [{
|
|
897
|
+
propertyName: localeToFakerImport(locale),
|
|
898
|
+
name: "faker"
|
|
899
|
+
}] : ["faker"],
|
|
900
|
+
path: "@faker-js/faker"
|
|
901
|
+
}),
|
|
902
|
+
regexGenerator === "randexp" && /* @__PURE__ */ jsx(File.Import, {
|
|
903
|
+
name: "RandExp",
|
|
904
|
+
path: "randexp"
|
|
905
|
+
}),
|
|
906
|
+
dateParser !== "faker" && /* @__PURE__ */ jsx(File.Import, {
|
|
907
|
+
path: dateParser,
|
|
908
|
+
name: dateParser
|
|
909
|
+
}),
|
|
910
|
+
typeReference.importPath && /* @__PURE__ */ jsx(File.Import, {
|
|
911
|
+
isTypeOnly: true,
|
|
912
|
+
root: meta.file.path,
|
|
913
|
+
path: typeReference.importPath,
|
|
914
|
+
name: [meta.typeName]
|
|
915
|
+
}),
|
|
916
|
+
usedImports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
|
|
917
|
+
root: meta.file.path,
|
|
918
|
+
path: imp.path,
|
|
919
|
+
name: imp.name
|
|
920
|
+
}, [
|
|
921
|
+
schemaName,
|
|
922
|
+
imp.path,
|
|
923
|
+
imp.name
|
|
924
|
+
].join("-"))),
|
|
925
|
+
/* @__PURE__ */ jsx(Faker, {
|
|
926
|
+
name: meta.name,
|
|
927
|
+
typeName: typeReference.typeName,
|
|
928
|
+
description: node.description,
|
|
929
|
+
node,
|
|
930
|
+
printer: printerInstance,
|
|
931
|
+
seed,
|
|
932
|
+
canOverride
|
|
933
|
+
})
|
|
934
|
+
]
|
|
935
|
+
});
|
|
936
|
+
},
|
|
937
|
+
operation(node, ctx) {
|
|
938
|
+
const { adapter, config, resolver, root } = ctx;
|
|
939
|
+
const { output, group, dateParser, regexGenerator, mapper, seed, locale, printer } = ctx.options;
|
|
940
|
+
const pluginTs = ctx.driver.getPlugin(pluginTsName);
|
|
941
|
+
if (!pluginTs) return;
|
|
942
|
+
const tsResolver = ctx.driver.getResolver(pluginTsName);
|
|
943
|
+
const paramEntries = caseParams(node.parameters, "camelcase").map((param) => ({
|
|
944
|
+
param,
|
|
945
|
+
name: resolveParamNameByLocation(resolver, node, param),
|
|
946
|
+
typeName: resolveParamNameByLocation(tsResolver, node, param)
|
|
947
|
+
}));
|
|
948
|
+
function expandContentUnits(entries, baseName, tsBaseName, description, decorate) {
|
|
949
|
+
const withSchema = entries.filter((entry) => entry.schema);
|
|
950
|
+
if (withSchema.length <= 1) {
|
|
951
|
+
const primary = withSchema[0] ?? entries[0];
|
|
952
|
+
if (!primary?.schema) return [];
|
|
953
|
+
return [{
|
|
954
|
+
schema: decorate ? decorate(primary.schema) : primary.schema,
|
|
955
|
+
name: baseName,
|
|
956
|
+
typeName: tsBaseName,
|
|
957
|
+
description,
|
|
958
|
+
skipImportNames: []
|
|
959
|
+
}];
|
|
960
|
+
}
|
|
961
|
+
const variants = resolveContentTypeVariants(entries, baseName);
|
|
962
|
+
const unionSchema = ast.factory.createSchema({
|
|
963
|
+
type: "union",
|
|
964
|
+
members: variants.map((variant) => ast.factory.createSchema({
|
|
965
|
+
type: "ref",
|
|
966
|
+
name: variant.name
|
|
967
|
+
}))
|
|
968
|
+
});
|
|
969
|
+
return [...variants.map((variant) => ({
|
|
970
|
+
schema: decorate ? decorate(variant.schema) : variant.schema,
|
|
971
|
+
name: variant.name,
|
|
972
|
+
typeName: getPerContentTypeName(tsBaseName, variant.suffix),
|
|
973
|
+
description,
|
|
974
|
+
skipImportNames: []
|
|
975
|
+
})), {
|
|
976
|
+
schema: unionSchema,
|
|
977
|
+
name: baseName,
|
|
978
|
+
typeName: tsBaseName,
|
|
979
|
+
description,
|
|
980
|
+
skipImportNames: variants.map((variant) => variant.name)
|
|
981
|
+
}];
|
|
982
|
+
}
|
|
983
|
+
const responseUnits = node.responses.flatMap((response) => expandContentUnits(response.content ?? [], resolver.resolveResponseStatusName(node, response.statusCode), tsResolver.resolveResponseStatusName(node, response.statusCode), response.description));
|
|
984
|
+
const dataUnits = expandContentUnits(node.requestBody?.content ?? [], resolver.resolveDataName(node), tsResolver.resolveDataName(node), node.requestBody?.description, (schema) => ({
|
|
985
|
+
...schema,
|
|
986
|
+
description: node.requestBody?.description ?? schema.description
|
|
987
|
+
}));
|
|
988
|
+
const responseName = resolver.resolveResponseName(node);
|
|
989
|
+
const localHelperNames = new Set([
|
|
990
|
+
...paramEntries.map((entry) => entry.name),
|
|
991
|
+
...responseUnits.map((unit) => unit.name),
|
|
992
|
+
...dataUnits.map((unit) => unit.name),
|
|
993
|
+
responseName
|
|
994
|
+
]);
|
|
995
|
+
const cyclicSchemas = new Set(ctx.meta.circularNames);
|
|
996
|
+
const meta = {
|
|
997
|
+
file: resolver.resolveFile({
|
|
998
|
+
name: node.operationId,
|
|
999
|
+
extname: ".ts",
|
|
1000
|
+
tag: node.tags[0] ?? "default",
|
|
1001
|
+
path: node.path
|
|
1002
|
+
}, {
|
|
1003
|
+
root,
|
|
1004
|
+
output,
|
|
1005
|
+
group: group ?? void 0
|
|
1006
|
+
}),
|
|
1007
|
+
typeFile: tsResolver.resolveFile({
|
|
1008
|
+
name: node.operationId,
|
|
1009
|
+
extname: ".ts",
|
|
1010
|
+
tag: node.tags[0] ?? "default",
|
|
1011
|
+
path: node.path
|
|
1012
|
+
}, {
|
|
1013
|
+
root,
|
|
1014
|
+
output: pluginTs.options?.output ?? output,
|
|
1015
|
+
group: pluginTs.options?.group ?? void 0
|
|
1016
|
+
})
|
|
1017
|
+
};
|
|
1018
|
+
function resolveMockImports(schema) {
|
|
1019
|
+
return adapter.getImports(schema, (schemaName) => ({
|
|
1020
|
+
name: resolver.resolveName(schemaName),
|
|
1021
|
+
path: resolver.resolveFile({
|
|
1022
|
+
name: schemaName,
|
|
1023
|
+
extname: ".ts"
|
|
1024
|
+
}, {
|
|
1025
|
+
root,
|
|
1026
|
+
output,
|
|
1027
|
+
group: group ?? void 0
|
|
1028
|
+
}).path
|
|
1029
|
+
})).filter((entry) => entry.path !== meta.file.path);
|
|
1030
|
+
}
|
|
1031
|
+
function renderEntry({ schema, name, typeName, description, skipImportNames = [] }) {
|
|
1032
|
+
if (!schema) return null;
|
|
1033
|
+
const canOverride = canOverrideSchema(schema);
|
|
1034
|
+
const printerInstance = printerFaker({
|
|
1035
|
+
resolver,
|
|
1036
|
+
schemaName: name,
|
|
1037
|
+
typeName,
|
|
1038
|
+
dateParser,
|
|
1039
|
+
regexGenerator,
|
|
1040
|
+
mapper,
|
|
1041
|
+
nodes: printer?.nodes,
|
|
1042
|
+
cyclicSchemas
|
|
1043
|
+
});
|
|
1044
|
+
const fakerText = printerInstance.print(schema) ?? "undefined";
|
|
1045
|
+
const { imports, aliases } = aliasConflictingImports(filterUsedImports(resolveMockImports(schema), fakerText, skipImportNames), localHelperNames);
|
|
1046
|
+
const rewrittenFakerText = rewriteAliasedImports(fakerText, aliases);
|
|
1047
|
+
const typeReference = resolveTypeReference({
|
|
1048
|
+
node: schema,
|
|
1049
|
+
canOverride,
|
|
1050
|
+
name,
|
|
1051
|
+
typeName,
|
|
1052
|
+
filePath: meta.file.path,
|
|
1053
|
+
typeFilePath: meta.typeFile.path
|
|
1054
|
+
});
|
|
1055
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1056
|
+
typeReference.importPath && /* @__PURE__ */ jsx(File.Import, {
|
|
1057
|
+
isTypeOnly: true,
|
|
1058
|
+
root: meta.file.path,
|
|
1059
|
+
path: typeReference.importPath,
|
|
1060
|
+
name: [typeName]
|
|
1061
|
+
}),
|
|
1062
|
+
imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
|
|
1063
|
+
root: meta.file.path,
|
|
1064
|
+
path: imp.path,
|
|
1065
|
+
name: imp.name
|
|
1066
|
+
}, [
|
|
1067
|
+
name,
|
|
1068
|
+
imp.path,
|
|
1069
|
+
imp.name
|
|
1070
|
+
].join("-"))),
|
|
1071
|
+
/* @__PURE__ */ jsx(Faker, {
|
|
1072
|
+
name,
|
|
1073
|
+
typeName: typeReference.typeName,
|
|
1074
|
+
description,
|
|
1075
|
+
node: schema,
|
|
1076
|
+
printer: {
|
|
1077
|
+
...printerInstance,
|
|
1078
|
+
print: () => rewrittenFakerText
|
|
1079
|
+
},
|
|
1080
|
+
seed,
|
|
1081
|
+
canOverride
|
|
1082
|
+
})
|
|
1083
|
+
] });
|
|
1084
|
+
}
|
|
1085
|
+
return /* @__PURE__ */ jsxs(File, {
|
|
1086
|
+
baseName: meta.file.baseName,
|
|
1087
|
+
path: meta.file.path,
|
|
1088
|
+
meta: meta.file.meta,
|
|
1089
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
1090
|
+
output,
|
|
1091
|
+
config,
|
|
1092
|
+
file: {
|
|
1093
|
+
path: meta.file.path,
|
|
1094
|
+
baseName: meta.file.baseName
|
|
1095
|
+
}
|
|
1096
|
+
}),
|
|
1097
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
1098
|
+
output,
|
|
1099
|
+
config,
|
|
1100
|
+
file: {
|
|
1101
|
+
path: meta.file.path,
|
|
1102
|
+
baseName: meta.file.baseName
|
|
1103
|
+
}
|
|
1104
|
+
}),
|
|
1105
|
+
children: [
|
|
1106
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
1107
|
+
name: locale ? [{
|
|
1108
|
+
propertyName: localeToFakerImport(locale),
|
|
1109
|
+
name: "faker"
|
|
1110
|
+
}] : ["faker"],
|
|
1111
|
+
path: "@faker-js/faker"
|
|
1112
|
+
}),
|
|
1113
|
+
regexGenerator === "randexp" && /* @__PURE__ */ jsx(File.Import, {
|
|
1114
|
+
name: "RandExp",
|
|
1115
|
+
path: "randexp"
|
|
1116
|
+
}),
|
|
1117
|
+
dateParser !== "faker" && /* @__PURE__ */ jsx(File.Import, {
|
|
1118
|
+
path: dateParser,
|
|
1119
|
+
name: dateParser
|
|
1120
|
+
}),
|
|
1121
|
+
paramEntries.map(({ param, name, typeName }) => renderEntry({
|
|
1122
|
+
schema: param.schema,
|
|
1123
|
+
name,
|
|
1124
|
+
typeName
|
|
1125
|
+
})),
|
|
1126
|
+
responseUnits.map((unit) => renderEntry({
|
|
1127
|
+
schema: unit.schema,
|
|
1128
|
+
name: unit.name,
|
|
1129
|
+
typeName: unit.typeName,
|
|
1130
|
+
description: unit.description,
|
|
1131
|
+
skipImportNames: unit.skipImportNames
|
|
1132
|
+
})),
|
|
1133
|
+
dataUnits.map((unit) => renderEntry({
|
|
1134
|
+
schema: unit.schema,
|
|
1135
|
+
name: unit.name,
|
|
1136
|
+
typeName: unit.typeName,
|
|
1137
|
+
description: unit.description,
|
|
1138
|
+
skipImportNames: unit.skipImportNames
|
|
1139
|
+
})),
|
|
1140
|
+
renderEntry({
|
|
1141
|
+
schema: buildResponseUnionSchema(node, resolver),
|
|
1142
|
+
name: responseName,
|
|
1143
|
+
typeName: tsResolver.resolveResponseName(node),
|
|
1144
|
+
skipImportNames: responseUnits.map((unit) => unit.name)
|
|
1145
|
+
})
|
|
1146
|
+
]
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1150
|
+
//#endregion
|
|
214
1151
|
//#region src/resolvers/resolverFaker.ts
|
|
215
1152
|
/**
|
|
216
1153
|
* Default resolver used by `@kubb/plugin-faker`. Decides the names and file
|
|
@@ -320,7 +1257,7 @@ const pluginFaker = definePlugin((options) => {
|
|
|
320
1257
|
const { output = {
|
|
321
1258
|
path: "mocks",
|
|
322
1259
|
barrel: { type: "named" }
|
|
323
|
-
}, seed, locale = "en", group, exclude = [], include, override = [], mapper = {}, dateParser = "faker",
|
|
1260
|
+
}, seed, locale = "en", group, exclude = [], include, override = [], mapper = {}, dateParser = "faker", regexGenerator = "faker", printer, resolver: userResolver, macros: userMacros } = options;
|
|
324
1261
|
const groupConfig = createGroupConfig(group);
|
|
325
1262
|
return {
|
|
326
1263
|
name: pluginFakerName,
|
|
@@ -338,7 +1275,6 @@ const pluginFaker = definePlugin((options) => {
|
|
|
338
1275
|
mapper,
|
|
339
1276
|
dateParser,
|
|
340
1277
|
regexGenerator,
|
|
341
|
-
paramsCasing,
|
|
342
1278
|
printer
|
|
343
1279
|
});
|
|
344
1280
|
ctx.setResolver(userResolver ? {
|
|
@@ -347,7 +1283,6 @@ const pluginFaker = definePlugin((options) => {
|
|
|
347
1283
|
} : resolverFaker);
|
|
348
1284
|
if (userMacros?.length) ctx.setMacros(userMacros);
|
|
349
1285
|
ctx.addGenerator(fakerGenerator);
|
|
350
|
-
for (const generator of userGenerators) ctx.addGenerator(generator);
|
|
351
1286
|
} }
|
|
352
1287
|
};
|
|
353
1288
|
});
|