@kubb/plugin-faker 5.2.1 → 5.2.3
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.cjs +176 -119
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -13
- package/dist/index.d.ts +2 -13
- package/dist/index.js +173 -116
- package/dist/index.js.map +1 -1
- package/docs/options.md +2 -0
- package/kubb-extension.json +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,48 +1,9 @@
|
|
|
1
1
|
import { posix } from "node:path";
|
|
2
|
-
import { Diagnostics, Resolver, addGenerator, ast, containsCircularRef, createResolver, defineExtension, defineGenerator, setMacros, setResolver } from "kubb/kit";
|
|
2
|
+
import { Diagnostics, Resolver, addGenerator, ast, camelCase, containsCircularRef, createResolver, defineExtension, defineGenerator, setMacros, setResolver, syncSchemaRef } from "kubb/kit";
|
|
3
3
|
import { File, Function, jsxRenderer } from "kubb/jsx";
|
|
4
4
|
import { Fragment, jsx, jsxs } from "kubb/jsx/jsx-runtime";
|
|
5
5
|
import { buildParams, enumTypeName, pluginTsName } from "@kubb/plugin-ts";
|
|
6
|
-
|
|
7
|
-
//#region ../../internals/utils/src/casing.ts
|
|
8
|
-
/**
|
|
9
|
-
* Shared implementation for camelCase and PascalCase conversion.
|
|
10
|
-
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
11
|
-
* and capitalizes each word according to `pascal`.
|
|
12
|
-
*
|
|
13
|
-
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
14
|
-
*/
|
|
15
|
-
function convert(text, pascal) {
|
|
16
|
-
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
|
|
17
|
-
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
18
|
-
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
19
|
-
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
20
|
-
}
|
|
21
|
-
const cache = /* @__PURE__ */ new Map();
|
|
22
|
-
const cacheLimit = 1e4;
|
|
23
|
-
function toCamelOrPascal(text, pascal) {
|
|
24
|
-
const key = `${pascal ? "P" : "c"}${text}`;
|
|
25
|
-
const cached = cache.get(key);
|
|
26
|
-
if (cached !== void 0) return cached;
|
|
27
|
-
const result = convert(text, pascal);
|
|
28
|
-
if (cache.size >= cacheLimit) cache.clear();
|
|
29
|
-
cache.set(key, result);
|
|
30
|
-
return result;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Converts `text` to camelCase.
|
|
34
|
-
*
|
|
35
|
-
* @example Word boundaries
|
|
36
|
-
* `camelCase('hello-world') // 'helloWorld'`
|
|
37
|
-
*
|
|
38
|
-
* @example With a prefix
|
|
39
|
-
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
40
|
-
*/
|
|
41
|
-
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
42
|
-
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
43
|
-
}
|
|
44
|
-
//#endregion
|
|
45
|
-
//#region ../../internals/utils/src/reserved.ts
|
|
6
|
+
// ../../internals/utils/src/reserved.ts
|
|
46
7
|
/**
|
|
47
8
|
* JavaScript and Java reserved words.
|
|
48
9
|
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
@@ -50,6 +11,7 @@ function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
|
50
11
|
const reservedWords = /* @__PURE__ */ new Set([
|
|
51
12
|
"abstract",
|
|
52
13
|
"arguments",
|
|
14
|
+
"await",
|
|
53
15
|
"boolean",
|
|
54
16
|
"break",
|
|
55
17
|
"byte",
|
|
@@ -180,8 +142,7 @@ function ensureValidVarName(name) {
|
|
|
180
142
|
function isIdentifier(name) {
|
|
181
143
|
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
182
144
|
}
|
|
183
|
-
|
|
184
|
-
//#region ../../internals/utils/src/strings.ts
|
|
145
|
+
// ../../internals/utils/src/strings.ts
|
|
185
146
|
/**
|
|
186
147
|
* Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping
|
|
187
148
|
* any backslash or single quote in the content.
|
|
@@ -242,6 +203,34 @@ function stringify(value) {
|
|
|
242
203
|
function jsDocEscape(input) {
|
|
243
204
|
return `${input}`.replace(/^(\s*)@/gm, "$1\\@");
|
|
244
205
|
}
|
|
206
|
+
const NEEDS_UNICODE = /(?<!\\)(?:\\\\)*\\[pPu]\{|[\u{10000}-\u{10FFFF}]/u;
|
|
207
|
+
const KEPT_ESCAPE = /[A-Za-z0-9^$\\.*+?()[\]{}|/]/;
|
|
208
|
+
/**
|
|
209
|
+
* Drops the backslash from escapes that the `u` flag rejects: an escaped punctuation character that is
|
|
210
|
+
* not a syntax character, and `\-` outside a class. Both match the same character without the backslash.
|
|
211
|
+
*/
|
|
212
|
+
function dropIdentityEscapes(pattern) {
|
|
213
|
+
let inClass = false;
|
|
214
|
+
return pattern.replace(/\\(.)|[[\]]/gs, (match, escaped) => {
|
|
215
|
+
if (escaped === void 0) {
|
|
216
|
+
inClass = match === "[";
|
|
217
|
+
return match;
|
|
218
|
+
}
|
|
219
|
+
return KEPT_ESCAPE.test(escaped) || escaped === "-" && inClass ? match : escaped;
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Builds the `RegExp` for a pattern, adding the `u` flag when it uses `\p{...}`, `\P{...}` or `\u{...}`, or
|
|
224
|
+
* holds a character outside the BMP. A pattern that is not valid under `u` keeps the flags it came with.
|
|
225
|
+
*/
|
|
226
|
+
function toRegExp(pattern, flags) {
|
|
227
|
+
if (flags?.includes("u") || !NEEDS_UNICODE.test(pattern)) return new RegExp(pattern, flags);
|
|
228
|
+
try {
|
|
229
|
+
return new RegExp(dropIdentityEscapes(pattern), `${flags ?? ""}u`);
|
|
230
|
+
} catch {
|
|
231
|
+
return new RegExp(pattern, flags);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
245
234
|
/**
|
|
246
235
|
* Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
|
|
247
236
|
* Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.
|
|
@@ -258,13 +247,11 @@ function toRegExpString(text, func = "RegExp") {
|
|
|
258
247
|
const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
|
|
259
248
|
const replacementTarget = match?.[1] ?? "";
|
|
260
249
|
const matchedFlags = match?.[2];
|
|
261
|
-
const
|
|
262
|
-
const { source, flags } = new RegExp(cleaned, matchedFlags);
|
|
250
|
+
const { source, flags } = toRegExp(raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, ""), matchedFlags);
|
|
263
251
|
if (func === null) return `/${source}/${flags}`;
|
|
264
252
|
return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
|
|
265
253
|
}
|
|
266
|
-
|
|
267
|
-
//#region ../../internals/utils/src/codegen.ts
|
|
254
|
+
// ../../internals/utils/src/codegen.ts
|
|
268
255
|
const INDENT = " ";
|
|
269
256
|
/**
|
|
270
257
|
* Indents every non-empty line of `text` by one indent level, leaving blank lines empty.
|
|
@@ -301,8 +288,7 @@ function buildObject(entries) {
|
|
|
301
288
|
if (entries.length === 0) return "{}";
|
|
302
289
|
return `{\n${entries.map((entry) => `${indentLines(entry)},`).join("\n")}\n}`;
|
|
303
290
|
}
|
|
304
|
-
|
|
305
|
-
//#region ../../internals/utils/src/fs.ts
|
|
291
|
+
// ../../internals/utils/src/fs.ts
|
|
306
292
|
function toSlash(p) {
|
|
307
293
|
if (p.startsWith("\\\\?\\")) return p;
|
|
308
294
|
return p.replaceAll("\\", "/");
|
|
@@ -344,8 +330,7 @@ function toFilePath(name, caseLast = camelCase) {
|
|
|
344
330
|
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
345
331
|
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
|
|
346
332
|
}
|
|
347
|
-
|
|
348
|
-
//#region src/utils.ts
|
|
333
|
+
// src/utils.ts
|
|
349
334
|
/**
|
|
350
335
|
* Returns the `@faker-js/faker` named export for a locale code.
|
|
351
336
|
*
|
|
@@ -396,6 +381,18 @@ const NON_INLINABLE_RESPONSE_TYPES = /* @__PURE__ */ new Set([
|
|
|
396
381
|
function canOverrideSchema(node) {
|
|
397
382
|
return !NON_OVERRIDABLE_TYPES.has(node.type);
|
|
398
383
|
}
|
|
384
|
+
/**
|
|
385
|
+
* Whether a schema can supply object properties when merging faker values.
|
|
386
|
+
*/
|
|
387
|
+
function isObjectSchema(node, seen = /* @__PURE__ */ new Set()) {
|
|
388
|
+
const resolved = ast.resolveRef(node);
|
|
389
|
+
if (seen.has(resolved)) return false;
|
|
390
|
+
seen.add(resolved);
|
|
391
|
+
if (ast.narrowSchema(resolved, ast.schemaTypes.object) || ast.narrowSchema(resolved, ast.schemaTypes.ref)) return true;
|
|
392
|
+
const composition = ast.narrowSchema(resolved, ast.schemaTypes.intersection) ?? ast.narrowSchema(resolved, ast.schemaTypes.union);
|
|
393
|
+
if (!composition) return false;
|
|
394
|
+
return composition.type === ast.schemaTypes.intersection && !composition.members?.length || (composition.members ?? []).some((member) => isObjectSchema(member, seen));
|
|
395
|
+
}
|
|
399
396
|
function shouldInlineSingleResponseSchema(schema) {
|
|
400
397
|
return !NON_INLINABLE_RESPONSE_TYPES.has(schema.type);
|
|
401
398
|
}
|
|
@@ -407,11 +404,16 @@ function buildResponseUnionSchema(node, resolver) {
|
|
|
407
404
|
const responses = node.responses.filter((response) => response.content?.[0]?.schema);
|
|
408
405
|
if (!responses.length) return null;
|
|
409
406
|
if (responses.length === 1) {
|
|
410
|
-
const
|
|
407
|
+
const schemas = responses[0].content?.flatMap((content) => content.schema ? [content.schema] : []) ?? [];
|
|
408
|
+
const schema = schemas.length > 1 ? ast.factory.createSchema({
|
|
409
|
+
type: "union",
|
|
410
|
+
members: schemas
|
|
411
|
+
}) : schemas[0];
|
|
411
412
|
if (schema && shouldInlineSingleResponseSchema(schema)) return schema;
|
|
412
413
|
return ast.factory.createSchema({
|
|
413
414
|
type: "ref",
|
|
414
|
-
name: resolver.response.status(node, responses[0].statusCode)
|
|
415
|
+
name: resolver.response.status(node, responses[0].statusCode),
|
|
416
|
+
schema: responses[0].content?.length === 1 ? schema : void 0
|
|
415
417
|
});
|
|
416
418
|
}
|
|
417
419
|
return ast.factory.createSchema({
|
|
@@ -480,7 +482,8 @@ function getScalarType(node, typeName) {
|
|
|
480
482
|
* Determines the data type, return type, and whether it uses the type name.
|
|
481
483
|
*/
|
|
482
484
|
function resolveFakerTypeUsage(node, typeName, canOverride) {
|
|
483
|
-
const
|
|
485
|
+
const resolvedNode = ast.resolveRef(node);
|
|
486
|
+
const scalarType = SCALAR_TYPES.has(resolvedNode.type) ? `${getScalarType(resolvedNode, typeName)}${node.nullable || resolvedNode.nullable ? " | null" : ""}` : void 0;
|
|
484
487
|
const dataType = scalarType ?? `Partial<${typeName}>`;
|
|
485
488
|
const returnType = scalarType ?? (canOverride ? typeName : null);
|
|
486
489
|
return {
|
|
@@ -489,28 +492,27 @@ function resolveFakerTypeUsage(node, typeName, canOverride) {
|
|
|
489
492
|
usesTypeName: canOverride && dataType.includes(typeName) || Boolean(returnType?.includes(typeName))
|
|
490
493
|
};
|
|
491
494
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
const OBJECT_TYPES = /* @__PURE__ */ new Set(["object", "intersection"]);
|
|
495
|
-
function Faker({ node, description, name, typeName, printer, canOverride, typeMode = "inferred" }) {
|
|
495
|
+
// src/components/Faker.tsx
|
|
496
|
+
function Faker({ node, description, name, typeName, printer, canOverride, typeMode = "inferred", keysToOmit }) {
|
|
496
497
|
const fakerText = printer.print(node) ?? "undefined";
|
|
497
498
|
const isArray = node.type === "array";
|
|
498
|
-
const isObject =
|
|
499
|
+
const isObject = !!ast.narrowSchema(node, ast.schemaTypes.object) || node.type === ast.schemaTypes.intersection && isObjectSchema(node);
|
|
500
|
+
const isValueIntersection = node.type === ast.schemaTypes.intersection && !isObject;
|
|
499
501
|
const isTuple = node.type === "tuple";
|
|
500
502
|
const isScalar = SCALAR_TYPES.has(node.type);
|
|
501
503
|
const isUnion = node.type === "union";
|
|
502
|
-
const useObjectOverride = canOverride && isObject;
|
|
504
|
+
const useObjectOverride = canOverride && (isObject || !!keysToOmit?.length);
|
|
503
505
|
const fakerTextWithOverride = (() => {
|
|
504
506
|
if (canOverride && node.type === "tuple") return `data && data.length === ${node.items?.length ?? 0} && !data.includes(undefined) ? data : ${fakerText}`;
|
|
505
507
|
if (canOverride && isArray) return `[\n ...${fakerText},\n ...(data || []).filter((item) => item !== undefined),\n]`;
|
|
506
|
-
if (canOverride && (isScalar || isUnion)) return node.nullable ? `data !== undefined ? data : ${fakerText}` : `data ?? ${fakerText}`;
|
|
508
|
+
if (canOverride && (isScalar || isUnion || isValueIntersection)) return node.nullable ? `data !== undefined ? data : ${fakerText}` : `data ?? ${fakerText}`;
|
|
507
509
|
return fakerText;
|
|
508
510
|
})();
|
|
509
511
|
const { dataType, returnType: resolvedReturnType } = resolveFakerTypeUsage(node, typeName, canOverride);
|
|
510
512
|
if (!useObjectOverride) {
|
|
511
513
|
const paramsSignature = `${/\bdata\b/.test(fakerTextWithOverride) ? "data" : "_data"}?: ${dataType}`;
|
|
512
514
|
const returnType = resolvedReturnType;
|
|
513
|
-
const returnExpression = canOverride && !!returnType && (node.type === "ref" || isArray || isTuple || isUnion) ? `${isTuple || isUnion ? `(${fakerTextWithOverride})` : fakerTextWithOverride} as ${returnType}` : fakerTextWithOverride;
|
|
515
|
+
const returnExpression = canOverride && !!returnType && (node.type === "ref" && !SCALAR_TYPES.has(ast.resolveRef(node).type) || isArray || isTuple || isUnion) ? `${isTuple || isUnion ? `(${fakerTextWithOverride})` : fakerTextWithOverride} as ${returnType}` : fakerTextWithOverride;
|
|
514
516
|
return /* @__PURE__ */ jsx(File.Source, {
|
|
515
517
|
name,
|
|
516
518
|
isExportable: true,
|
|
@@ -525,18 +527,21 @@ function Faker({ node, description, name, typeName, printer, canOverride, typeMo
|
|
|
525
527
|
})
|
|
526
528
|
});
|
|
527
529
|
}
|
|
528
|
-
const returnType = typeMode === "schema" ? typeName : "Omit<typeof defaultFakeData, keyof NoInfer<TData>> & NoInfer<TData>";
|
|
529
530
|
const { cyclicSchemas, schemaName } = printer.options;
|
|
530
|
-
const
|
|
531
|
+
const isCyclic = !!schemaName && !!cyclicSchemas?.has(schemaName);
|
|
532
|
+
const returnType = typeMode === "schema" ? typeName : `Omit<${isCyclic ? typeName : "typeof defaultFakeData"}, keyof NoInfer<TData>> & NoInfer<TData>`;
|
|
533
|
+
const hasGetters = node.type === "object" && !!cyclicSchemas && (node.properties ?? []).some((p) => containsCircularRef(p.schema, {
|
|
531
534
|
circularSchemas: cyclicSchemas,
|
|
532
535
|
excludeName: schemaName
|
|
533
|
-
}))
|
|
536
|
+
}));
|
|
537
|
+
const declaration = `const ${keysToOmit?.length ? `{ ${keysToOmit.map((key, index) => `${objectKey(key)}: _omit${index}`).join(", ")}, ...defaultFakeData }` : "defaultFakeData"} = ${fakerText}`;
|
|
538
|
+
const functionBody = hasGetters ? `${declaration}
|
|
534
539
|
if (data) {
|
|
535
540
|
for (const [key, value] of Object.entries(data)) {
|
|
536
541
|
Object.defineProperty(defaultFakeData, key, { value, configurable: true, writable: true, enumerable: true })
|
|
537
542
|
}
|
|
538
543
|
}
|
|
539
|
-
return defaultFakeData as ${returnType}` :
|
|
544
|
+
return defaultFakeData as ${returnType}` : `${declaration}
|
|
540
545
|
return {
|
|
541
546
|
...defaultFakeData,
|
|
542
547
|
...(data || {}),
|
|
@@ -551,13 +556,12 @@ return {
|
|
|
551
556
|
JSDoc: { comments: description ? [`@description ${jsDocEscape(description)}`] : [] },
|
|
552
557
|
generics: typeMode === "schema" ? void 0 : `TData extends Partial<${typeName}> = object`,
|
|
553
558
|
params: typeMode === "schema" ? `data?: Partial<${typeName}>` : "data?: TData",
|
|
554
|
-
returnType: typeMode === "schema" ?
|
|
559
|
+
returnType: typeMode === "schema" || isCyclic ? returnType : void 0,
|
|
555
560
|
children: functionBody
|
|
556
561
|
})
|
|
557
562
|
});
|
|
558
563
|
}
|
|
559
|
-
|
|
560
|
-
//#region ../../internals/shared/src/operation.ts
|
|
564
|
+
// ../../internals/shared/src/operation.ts
|
|
561
565
|
/**
|
|
562
566
|
* Builds the `ResolverFileParams` every operation generator passes to
|
|
563
567
|
* `resolver.file`: a file named `name`, tagged by the operation's first
|
|
@@ -672,17 +676,24 @@ function getOperationParameters(node) {
|
|
|
672
676
|
operationParameterGroupsByNode.set(node, groups);
|
|
673
677
|
return groups;
|
|
674
678
|
}
|
|
675
|
-
|
|
676
|
-
//#region ../../internals/shared/src/resolver.ts
|
|
679
|
+
// ../../internals/shared/src/resolver.ts
|
|
677
680
|
/**
|
|
678
|
-
*
|
|
679
|
-
*
|
|
681
|
+
* Builds the allocation key for a declaration an operation owns. `scope` names which declaration
|
|
682
|
+
* it is, so two of them never share an allocation even when a custom resolver gives both the same
|
|
683
|
+
* name. Leave `scope` empty for the operation's own declaration.
|
|
680
684
|
*
|
|
681
685
|
* @example
|
|
682
|
-
*
|
|
686
|
+
* ```ts
|
|
687
|
+
* resolver.resolveName({ key: operationKey(node, 'response', 'status', 404), name })
|
|
688
|
+
* ```
|
|
683
689
|
*/
|
|
684
|
-
function
|
|
685
|
-
return
|
|
690
|
+
function operationKey(node, ...scope) {
|
|
691
|
+
return [
|
|
692
|
+
"operation",
|
|
693
|
+
node.method,
|
|
694
|
+
node.path,
|
|
695
|
+
...scope.map(String)
|
|
696
|
+
];
|
|
686
697
|
}
|
|
687
698
|
/**
|
|
688
699
|
* Builds the shared `param` namespace. Spread the result into `createResolver`
|
|
@@ -695,15 +706,33 @@ function operationParamName(node, param) {
|
|
|
695
706
|
*/
|
|
696
707
|
function createOperationParamResolver() {
|
|
697
708
|
return {
|
|
698
|
-
name
|
|
709
|
+
name(node, param) {
|
|
710
|
+
const name = this.name(`${node.operationId} ${param.in} ${param.name}`);
|
|
711
|
+
return this.resolveName({
|
|
712
|
+
key: operationKey(node, "param", "name", param.in, param.name),
|
|
713
|
+
name
|
|
714
|
+
});
|
|
715
|
+
},
|
|
699
716
|
path(node) {
|
|
700
|
-
|
|
717
|
+
const name = this.name(`${node.operationId} Path`);
|
|
718
|
+
return this.resolveName({
|
|
719
|
+
key: operationKey(node, "param", "path"),
|
|
720
|
+
name
|
|
721
|
+
});
|
|
701
722
|
},
|
|
702
723
|
query(node) {
|
|
703
|
-
|
|
724
|
+
const name = this.name(`${node.operationId} Query`);
|
|
725
|
+
return this.resolveName({
|
|
726
|
+
key: operationKey(node, "param", "query"),
|
|
727
|
+
name
|
|
728
|
+
});
|
|
704
729
|
},
|
|
705
730
|
headers(node) {
|
|
706
|
-
|
|
731
|
+
const name = this.name(`${node.operationId} Headers`);
|
|
732
|
+
return this.resolveName({
|
|
733
|
+
key: operationKey(node, "param", "headers"),
|
|
734
|
+
name
|
|
735
|
+
});
|
|
707
736
|
}
|
|
708
737
|
};
|
|
709
738
|
}
|
|
@@ -720,16 +749,32 @@ function createOperationParamResolver() {
|
|
|
720
749
|
function createOperationResponseResolver() {
|
|
721
750
|
return {
|
|
722
751
|
status(node, statusCode) {
|
|
723
|
-
|
|
752
|
+
const name = this.name(`${node.operationId} Status ${statusCode}`);
|
|
753
|
+
return this.resolveName({
|
|
754
|
+
key: operationKey(node, "response", "status", statusCode),
|
|
755
|
+
name
|
|
756
|
+
});
|
|
724
757
|
},
|
|
725
758
|
body(node) {
|
|
726
|
-
|
|
759
|
+
const name = this.name(`${node.operationId} Body`);
|
|
760
|
+
return this.resolveName({
|
|
761
|
+
key: operationKey(node, "response", "body"),
|
|
762
|
+
name
|
|
763
|
+
});
|
|
727
764
|
},
|
|
728
765
|
responses(node) {
|
|
729
|
-
|
|
766
|
+
const name = this.name(`${node.operationId} Responses`);
|
|
767
|
+
return this.resolveName({
|
|
768
|
+
key: operationKey(node, "response", "responses"),
|
|
769
|
+
name
|
|
770
|
+
});
|
|
730
771
|
},
|
|
731
772
|
response(node) {
|
|
732
|
-
|
|
773
|
+
const name = this.name(`${node.operationId} Response`);
|
|
774
|
+
return this.resolveName({
|
|
775
|
+
key: operationKey(node, "response", "response"),
|
|
776
|
+
name
|
|
777
|
+
});
|
|
733
778
|
}
|
|
734
779
|
};
|
|
735
780
|
}
|
|
@@ -744,11 +789,10 @@ function createOperationResponseResolver() {
|
|
|
744
789
|
*/
|
|
745
790
|
function createCasedFile(caseLast) {
|
|
746
791
|
return { baseName({ name, extname }) {
|
|
747
|
-
return `${toFilePath(name, caseLast)}${extname}
|
|
792
|
+
return this.memo(`file:${name}\0${extname}`, () => `${toFilePath(name, caseLast)}${extname}`);
|
|
748
793
|
} };
|
|
749
794
|
}
|
|
750
|
-
|
|
751
|
-
//#region ../../internals/shared/src/group.ts
|
|
795
|
+
// ../../internals/shared/src/group.ts
|
|
752
796
|
/**
|
|
753
797
|
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
754
798
|
* shared default naming so every plugin groups output consistently:
|
|
@@ -778,8 +822,7 @@ function createGroupConfig(group) {
|
|
|
778
822
|
name: group.name ? group.name : defaultName
|
|
779
823
|
};
|
|
780
824
|
}
|
|
781
|
-
|
|
782
|
-
//#region ../../internals/shared/src/schemaTraversal.ts
|
|
825
|
+
// ../../internals/shared/src/schemaTraversal.ts
|
|
783
826
|
/**
|
|
784
827
|
* Maps each member of a union or intersection schema to its transformed output, pairing every
|
|
785
828
|
* result with the original member.
|
|
@@ -800,8 +843,7 @@ function mapSchemaItems(node, transform) {
|
|
|
800
843
|
output: transform(schema)
|
|
801
844
|
}));
|
|
802
845
|
}
|
|
803
|
-
|
|
804
|
-
//#region src/utils/imports.ts
|
|
846
|
+
// src/utils/imports.ts
|
|
805
847
|
function escapeRegExp(value) {
|
|
806
848
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
807
849
|
}
|
|
@@ -849,8 +891,7 @@ function aliasConflictingImports(imports, reservedNames) {
|
|
|
849
891
|
function rewriteAliasedImports(text, aliases) {
|
|
850
892
|
return Array.from(aliases).reduce((acc, [name, alias]) => acc.replace(new RegExp(`\\b${escapeRegExp(name)}\\b`, "g"), alias), text);
|
|
851
893
|
}
|
|
852
|
-
|
|
853
|
-
//#region src/printers/printerFaker.ts
|
|
894
|
+
// src/printers/printerFaker.ts
|
|
854
895
|
/**
|
|
855
896
|
* Formats that put a whole number inside a `type: 'string'` schema, the way ProtoJSON encodes
|
|
856
897
|
* 64-bit integers, so the mock has to be digits rather than letters.
|
|
@@ -986,7 +1027,9 @@ const printerFaker = ast.createPrinter((options) => {
|
|
|
986
1027
|
},
|
|
987
1028
|
enum(node) {
|
|
988
1029
|
const { typeName } = this.options;
|
|
989
|
-
|
|
1030
|
+
const values = ast.getSchemaLiteralValues(node);
|
|
1031
|
+
if (values.length === 1 && values[0] !== null && typeof values[0] === "object") return JSON.stringify(values[0]);
|
|
1032
|
+
return `faker.helpers.arrayElement${typeName ? `<${typeName}>` : ""}([${values.map(parseEnumValue).join(", ")}])`;
|
|
990
1033
|
},
|
|
991
1034
|
union(node) {
|
|
992
1035
|
const { discriminatorPropertyName } = node;
|
|
@@ -1010,9 +1053,14 @@ const printerFaker = ast.createPrinter((options) => {
|
|
|
1010
1053
|
}).map(({ output }) => output).filter((item) => Boolean(item)).join(", ")}])`;
|
|
1011
1054
|
},
|
|
1012
1055
|
intersection(node) {
|
|
1013
|
-
const
|
|
1056
|
+
const objectMembers = (node.members ?? []).filter((member) => isObjectSchema(member));
|
|
1057
|
+
const members = objectMembers.length ? objectMembers : node.members;
|
|
1058
|
+
const items = mapSchemaMembers({
|
|
1059
|
+
...node,
|
|
1060
|
+
members
|
|
1061
|
+
}, (member) => printNested(member, { nestedInObject: true })).map(({ output }) => output).filter((item) => Boolean(item) && item !== "undefined");
|
|
1014
1062
|
if (items.length === 0) return "{}";
|
|
1015
|
-
return items.length === 1 ? items
|
|
1063
|
+
return !objectMembers.length || items.length === 1 ? items.at(-1) : `{...${items.join(", ...")}}`;
|
|
1016
1064
|
},
|
|
1017
1065
|
array(node) {
|
|
1018
1066
|
const items = mapSchemaItems(node, (member) => printNested(member, {
|
|
@@ -1035,7 +1083,13 @@ const printerFaker = ast.createPrinter((options) => {
|
|
|
1035
1083
|
},
|
|
1036
1084
|
object(node) {
|
|
1037
1085
|
const cyclicSchemas = this.options.cyclicSchemas;
|
|
1038
|
-
|
|
1086
|
+
const keySchema = node.propertyNames && syncSchemaRef(node.propertyNames);
|
|
1087
|
+
const valueSchema = node.additionalProperties;
|
|
1088
|
+
const recordProperties = keySchema?.type === "enum" && typeof valueSchema === "object" ? ast.getSchemaLiteralValues(keySchema).filter((key) => typeof key === "string" && !node.properties.some((property) => property.name === key)).map((name) => ast.factory.createProperty({
|
|
1089
|
+
name,
|
|
1090
|
+
schema: valueSchema
|
|
1091
|
+
})) : [];
|
|
1092
|
+
return buildObject([...node.properties, ...recordProperties].map((property) => {
|
|
1039
1093
|
const value = printNested(property.schema, {
|
|
1040
1094
|
typeName: this.options.typeName ? indexedTypeName(this.options.typeName, property.name, this.options.nestedInUnion) : void 0,
|
|
1041
1095
|
nestedInObject: true
|
|
@@ -1051,8 +1105,7 @@ const printerFaker = ast.createPrinter((options) => {
|
|
|
1051
1105
|
overrides: options.nodes
|
|
1052
1106
|
};
|
|
1053
1107
|
});
|
|
1054
|
-
|
|
1055
|
-
//#region src/generators/fakerGenerator.tsx
|
|
1108
|
+
// src/generators/fakerGenerator.tsx
|
|
1056
1109
|
/**
|
|
1057
1110
|
* Built-in generator for `@kubb/plugin-faker`. Emits one `createX` factory
|
|
1058
1111
|
* per schema in the spec plus per-operation request/response factories. Each
|
|
@@ -1224,7 +1277,7 @@ const fakerGenerator = defineGenerator({
|
|
|
1224
1277
|
name: baseName,
|
|
1225
1278
|
typeName: tsBaseName,
|
|
1226
1279
|
description,
|
|
1227
|
-
|
|
1280
|
+
keysToOmit: primary.keysToOmit
|
|
1228
1281
|
}];
|
|
1229
1282
|
}
|
|
1230
1283
|
const variants = resolveContentTypeVariants(entries, baseName);
|
|
@@ -1241,7 +1294,7 @@ const fakerGenerator = defineGenerator({
|
|
|
1241
1294
|
name: variant.name,
|
|
1242
1295
|
typeName: getPerContentTypeName(tsBaseName, variant.suffix),
|
|
1243
1296
|
description,
|
|
1244
|
-
|
|
1297
|
+
keysToOmit: variant.keysToOmit
|
|
1245
1298
|
})), {
|
|
1246
1299
|
schema: unionSchema,
|
|
1247
1300
|
name: baseName,
|
|
@@ -1291,8 +1344,15 @@ const fakerGenerator = defineGenerator({
|
|
|
1291
1344
|
group: group ?? void 0
|
|
1292
1345
|
}).filter((entry) => entry.path !== meta.file.path);
|
|
1293
1346
|
}
|
|
1294
|
-
function renderEntry({ schema, name, typeName, description, skipImportNames = [] }) {
|
|
1347
|
+
function renderEntry({ schema, name, typeName, description, keysToOmit, skipImportNames = [] }) {
|
|
1295
1348
|
if (!schema) return null;
|
|
1349
|
+
if (schema.type === ast.schemaTypes.object && keysToOmit?.length) {
|
|
1350
|
+
schema = {
|
|
1351
|
+
...schema,
|
|
1352
|
+
properties: schema.properties.filter((property) => !keysToOmit?.includes(property.name))
|
|
1353
|
+
};
|
|
1354
|
+
keysToOmit = void 0;
|
|
1355
|
+
}
|
|
1296
1356
|
const canOverride = canOverrideSchema(schema);
|
|
1297
1357
|
const printerInstance = printerFaker({
|
|
1298
1358
|
resolver,
|
|
@@ -1301,7 +1361,8 @@ const fakerGenerator = defineGenerator({
|
|
|
1301
1361
|
dateParser,
|
|
1302
1362
|
regexGenerator,
|
|
1303
1363
|
nodes: printer?.nodes,
|
|
1304
|
-
cyclicSchemas
|
|
1364
|
+
cyclicSchemas,
|
|
1365
|
+
nestedInObject: !!keysToOmit?.length
|
|
1305
1366
|
});
|
|
1306
1367
|
const fakerText = printerInstance.print(schema) ?? "undefined";
|
|
1307
1368
|
const { imports, aliases } = aliasConflictingImports(filterUsedImports(resolveMockImports(schema), fakerText, skipImportNames), localHelperNames);
|
|
@@ -1340,7 +1401,8 @@ const fakerGenerator = defineGenerator({
|
|
|
1340
1401
|
print: () => rewrittenFakerText
|
|
1341
1402
|
},
|
|
1342
1403
|
canOverride,
|
|
1343
|
-
typeMode
|
|
1404
|
+
typeMode,
|
|
1405
|
+
keysToOmit
|
|
1344
1406
|
})
|
|
1345
1407
|
] });
|
|
1346
1408
|
}
|
|
@@ -1397,17 +1459,14 @@ const fakerGenerator = defineGenerator({
|
|
|
1397
1459
|
});
|
|
1398
1460
|
}
|
|
1399
1461
|
});
|
|
1400
|
-
|
|
1401
|
-
//#region kubb-extension.json
|
|
1462
|
+
// kubb-extension.json
|
|
1402
1463
|
var compatibility = {
|
|
1403
|
-
"kubb": ">=5.
|
|
1464
|
+
"kubb": ">=5.14.6",
|
|
1404
1465
|
"node": ">=22.22"
|
|
1405
1466
|
};
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
//#endregion
|
|
1410
|
-
//#region src/resolvers/resolverFaker.ts
|
|
1467
|
+
// package.json
|
|
1468
|
+
var version = "5.2.3";
|
|
1469
|
+
// src/resolvers/resolverFaker.ts
|
|
1411
1470
|
/**
|
|
1412
1471
|
* Default resolver used by `@kubb/plugin-faker`. Decides the names and file
|
|
1413
1472
|
* paths for every generated mock factory. Functions and files are prefixed
|
|
@@ -1423,14 +1482,13 @@ var version = "5.2.1";
|
|
|
1423
1482
|
const resolverFaker = createResolver({
|
|
1424
1483
|
pluginName: "plugin-faker",
|
|
1425
1484
|
name(name) {
|
|
1426
|
-
return ensureValidVarName(camelCase(name, { prefix: "create" }));
|
|
1485
|
+
return this.memo(`name:${name}`, () => ensureValidVarName(camelCase(name, { prefix: "create" })));
|
|
1427
1486
|
},
|
|
1428
1487
|
file: createCasedFile((part) => camelCase(part, { prefix: "create" })),
|
|
1429
1488
|
param: createOperationParamResolver(),
|
|
1430
1489
|
response: createOperationResponseResolver()
|
|
1431
1490
|
});
|
|
1432
|
-
|
|
1433
|
-
//#region src/plugin.ts
|
|
1491
|
+
// src/plugin.ts
|
|
1434
1492
|
/**
|
|
1435
1493
|
* Canonical plugin name for `@kubb/plugin-faker`. Used for driver lookups and
|
|
1436
1494
|
* cross-plugin dependency references.
|
|
@@ -1491,7 +1549,6 @@ const pluginFaker = defineExtension({
|
|
|
1491
1549
|
};
|
|
1492
1550
|
}
|
|
1493
1551
|
});
|
|
1494
|
-
//#endregion
|
|
1495
1552
|
export { Faker, pluginFaker as default, pluginFaker, fakerGenerator, pluginFakerName, printerFaker, resolverFaker };
|
|
1496
1553
|
|
|
1497
1554
|
//# sourceMappingURL=index.js.map
|