@kubb/plugin-faker 5.0.0-beta.42 → 5.0.0-beta.56
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/{Faker-SBhWTdC7.d.ts → Faker-A5UuxwJj.d.ts} +2 -2
- package/dist/{Faker-DBPx_MVh.js → Faker-CHh0JtBG.js} +4 -46
- package/dist/Faker-CHh0JtBG.js.map +1 -0
- package/dist/{Faker-DRL0W5Lt.cjs → Faker-CcGjn5ZM.cjs} +5 -53
- package/dist/Faker-CcGjn5ZM.cjs.map +1 -0
- package/dist/components.cjs +1 -1
- package/dist/components.d.ts +1 -1
- package/dist/components.js +1 -1
- package/dist/{fakerGenerator-DNJ61yLj.js → fakerGenerator-DDNsdbH2.js} +16 -50
- package/dist/fakerGenerator-DDNsdbH2.js.map +1 -0
- package/dist/{fakerGenerator-CVOr0Pwm.cjs → fakerGenerator-DrwGWYwv.cjs} +17 -51
- package/dist/fakerGenerator-DrwGWYwv.cjs.map +1 -0
- package/dist/{fakerGenerator-Duc28_FK.d.ts → fakerGenerator-KKVr-CA2.d.ts} +2 -2
- package/dist/generators.cjs +1 -1
- package/dist/generators.d.ts +1 -1
- package/dist/generators.js +1 -1
- package/dist/index.cjs +45 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +45 -42
- package/dist/index.js.map +1 -1
- package/dist/{printerFaker-DXS861Q0.d.ts → printerFaker-CMCJT3FB.d.ts} +9 -13
- package/package.json +8 -15
- package/src/components/Faker.tsx +1 -1
- package/src/generators/fakerGenerator.tsx +12 -16
- package/src/plugin.ts +2 -2
- package/src/printers/printerFaker.ts +23 -25
- package/src/resolvers/resolverFaker.ts +8 -8
- package/src/types.ts +8 -12
- package/src/utils.ts +1 -1
- package/dist/Faker-DBPx_MVh.js.map +0 -1
- package/dist/Faker-DRL0W5Lt.cjs.map +0 -1
- package/dist/fakerGenerator-CVOr0Pwm.cjs.map +0 -1
- package/dist/fakerGenerator-DNJ61yLj.js.map +0 -1
- package/extension.yaml +0 -819
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "./chunk-C0LytTxp.js";
|
|
2
|
-
import {
|
|
3
|
-
import { t as
|
|
4
|
-
import
|
|
5
|
-
import { KubbDriver, definePlugin, defineResolver } from "@kubb/core";
|
|
2
|
+
import { t as Faker } from "./Faker-CHh0JtBG.js";
|
|
3
|
+
import { n as printerFaker, t as fakerGenerator } from "./fakerGenerator-DDNsdbH2.js";
|
|
4
|
+
import { definePlugin, defineResolver } from "@kubb/core";
|
|
6
5
|
import { pluginTsName } from "@kubb/plugin-ts";
|
|
6
|
+
import path from "node:path";
|
|
7
7
|
import { createHash } from "node:crypto";
|
|
8
8
|
//#region ../../internals/utils/src/casing.ts
|
|
9
9
|
/**
|
|
@@ -16,36 +16,45 @@ import { createHash } from "node:crypto";
|
|
|
16
16
|
function toCamelOrPascal(text, pascal) {
|
|
17
17
|
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) => {
|
|
18
18
|
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
19
|
-
|
|
20
|
-
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
19
|
+
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
21
20
|
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
22
21
|
}
|
|
23
22
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
* Converts `text` to camelCase.
|
|
24
|
+
*
|
|
25
|
+
* @example Word boundaries
|
|
26
|
+
* `camelCase('hello-world') // 'helloWorld'`
|
|
27
27
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
28
|
+
* @example With a prefix
|
|
29
|
+
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
30
30
|
*/
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join("/");
|
|
31
|
+
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
32
|
+
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
34
33
|
}
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region ../../internals/utils/src/fs.ts
|
|
35
36
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
37
|
+
* Builds a nested file path from a dotted name. Splits on dots that precede a letter
|
|
38
|
+
* (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
|
|
39
|
+
* every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
|
|
38
40
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
41
|
+
* Empty segments are dropped before joining. They arise when the name starts with a dot
|
|
42
|
+
* followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
|
|
43
|
+
* an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
|
|
44
|
+
* absolute path, letting generated files escape the configured output directory.
|
|
45
|
+
*
|
|
46
|
+
* @example Nested path from a dotted name
|
|
47
|
+
* `toFilePath('pet.petId') // 'pet/petId'`
|
|
48
|
+
*
|
|
49
|
+
* @example PascalCase the final segment
|
|
50
|
+
* `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
|
|
51
|
+
*
|
|
52
|
+
* @example Suffix applied to the final segment only
|
|
53
|
+
* `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
|
|
42
54
|
*/
|
|
43
|
-
function
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
suffix
|
|
47
|
-
} : {}));
|
|
48
|
-
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
55
|
+
function toFilePath(name, caseLast = camelCase) {
|
|
56
|
+
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
57
|
+
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
|
|
49
58
|
}
|
|
50
59
|
//#endregion
|
|
51
60
|
//#region ../../internals/utils/src/reserved.ts
|
|
@@ -177,26 +186,24 @@ function ensureValidVarName(name) {
|
|
|
177
186
|
* shared default naming so every plugin groups output consistently:
|
|
178
187
|
*
|
|
179
188
|
* - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
|
|
180
|
-
* - other groups use
|
|
189
|
+
* - other groups use the camelCased group (`pet store` → `petStore`).
|
|
181
190
|
*
|
|
182
191
|
* A user-provided `group.name` always wins over the default namer, so callers stay in
|
|
183
192
|
* control of their output folders. Returns `null` when grouping is disabled, matching the
|
|
184
193
|
* per-plugin convention.
|
|
185
194
|
*
|
|
186
195
|
* @param group - The user-supplied group option, or `undefined` to disable grouping.
|
|
187
|
-
* @param options.suffix - Appended to non-`path` group names, e.g. `'Controller'` or `'Requests'`.
|
|
188
196
|
*
|
|
189
197
|
* @example
|
|
190
198
|
* ```ts
|
|
191
|
-
* createGroupConfig(group
|
|
192
|
-
* createGroupConfig(group, { suffix: 'Requests' }) // plugin-cypress, plugin-mcp
|
|
199
|
+
* createGroupConfig(group) // shared across every plugin
|
|
193
200
|
* ```
|
|
194
201
|
*/
|
|
195
|
-
function createGroupConfig(group
|
|
202
|
+
function createGroupConfig(group) {
|
|
196
203
|
if (!group) return null;
|
|
197
204
|
const defaultName = (ctx) => {
|
|
198
205
|
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
199
|
-
return
|
|
206
|
+
return camelCase(ctx.group);
|
|
200
207
|
};
|
|
201
208
|
return {
|
|
202
209
|
...group,
|
|
@@ -222,11 +229,8 @@ const resolverFaker = defineResolver(() => {
|
|
|
222
229
|
name: "default",
|
|
223
230
|
pluginName: "plugin-faker",
|
|
224
231
|
default(name, type) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
prefix: "create"
|
|
228
|
-
});
|
|
229
|
-
return type === "file" ? resolvedName : ensureValidVarName(resolvedName);
|
|
232
|
+
if (type === "file") return toFilePath(name, (part) => camelCase(part, { prefix: "create" }));
|
|
233
|
+
return ensureValidVarName(camelCase(name, { prefix: "create" }));
|
|
230
234
|
},
|
|
231
235
|
resolveName(name, type) {
|
|
232
236
|
return this.default(name, type);
|
|
@@ -235,14 +239,13 @@ const resolverFaker = defineResolver(() => {
|
|
|
235
239
|
return this.default(name, type);
|
|
236
240
|
},
|
|
237
241
|
resolveFile({ name, extname, tag, path: groupPath }, context) {
|
|
238
|
-
const
|
|
239
|
-
const baseName = `${pathMode === "single" ? "" : this.resolveName(name, "file")}${extname}`;
|
|
242
|
+
const inputBaseName = `${context.output.mode === "file" ? "" : this.resolveName(name, "file")}${extname}`;
|
|
240
243
|
const filePath = this.resolvePath({
|
|
241
|
-
baseName,
|
|
242
|
-
pathMode,
|
|
244
|
+
baseName: inputBaseName,
|
|
243
245
|
tag,
|
|
244
246
|
path: groupPath
|
|
245
247
|
}, context);
|
|
248
|
+
const baseName = path.basename(filePath);
|
|
246
249
|
return {
|
|
247
250
|
kind: "File",
|
|
248
251
|
id: createHash("sha256").update(filePath).digest("hex"),
|
|
@@ -316,9 +319,9 @@ const pluginFakerName = "plugin-faker";
|
|
|
316
319
|
const pluginFaker = definePlugin((options) => {
|
|
317
320
|
const { output = {
|
|
318
321
|
path: "mocks",
|
|
319
|
-
|
|
322
|
+
barrel: { type: "named" }
|
|
320
323
|
}, seed, locale = "en", group, exclude = [], include, override = [], mapper = {}, dateParser = "faker", generators: userGenerators = [], regexGenerator = "faker", paramsCasing, printer, resolver: userResolver, transformer: userTransformer } = options;
|
|
321
|
-
const groupConfig = createGroupConfig(group
|
|
324
|
+
const groupConfig = createGroupConfig(group);
|
|
322
325
|
return {
|
|
323
326
|
name: pluginFakerName,
|
|
324
327
|
options,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../internals/utils/src/casing.ts","../../../internals/utils/src/reserved.ts","../../../internals/shared/src/group.ts","../src/resolvers/resolverFaker.ts","../src/plugin.ts"],"sourcesContent":["type Options = {\n /**\n * When `true`, dot-separated segments are split on `.` and joined with `/` after casing.\n */\n isFile?: boolean\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n const normalized = text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n\n const words = normalized.split(/[\\s\\-_./\\\\:]+/).filter(Boolean)\n\n return words\n .map((word, i) => {\n const allUpper = word.length > 1 && word === word.toUpperCase()\n if (allUpper) return word\n if (i === 0 && !pascal) return word.charAt(0).toLowerCase() + word.slice(1)\n return word.charAt(0).toUpperCase() + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Splits `text` on `.` and applies `transformPart` to each segment.\n * The last segment receives `isLast = true`, all earlier segments receive `false`.\n * Segments are joined with `/` to form a file path.\n *\n * Only splits on dots followed by a letter so that version numbers\n * embedded in operationIds (e.g. `v2025.0`) are kept intact.\n */\nfunction applyToFileParts(text: string, transformPart: (part: string, isLast: boolean) => string): string {\n const parts = text.split(/\\.(?=[a-zA-Z])/)\n return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join('/')\n}\n\n/**\n * Converts `text` to camelCase.\n * When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`.\n *\n * @example\n * camelCase('hello-world') // 'helloWorld'\n * camelCase('pet.petId', { isFile: true }) // 'pet/petId'\n */\nexport function camelCase(text: string, { isFile, prefix = '', suffix = '' }: Options = {}): string {\n if (isFile) {\n return applyToFileParts(text, (part, isLast) => camelCase(part, isLast ? { prefix, suffix } : {}))\n }\n\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n * When `isFile` is `true`, the last dot-separated segment is PascalCased and earlier segments are camelCased.\n *\n * @example\n * pascalCase('hello-world') // 'HelloWorld'\n * pascalCase('pet.petId', { isFile: true }) // 'pet/PetId'\n */\nexport function pascalCase(text: string, { isFile, prefix = '', suffix = '' }: Options = {}): string {\n if (isFile) {\n return applyToFileParts(text, (part, isLast) => (isLast ? pascalCase(part, { prefix, suffix }) : camelCase(part)))\n }\n\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n\n/**\n * Converts `text` to snake_case.\n *\n * @example\n * snakeCase('helloWorld') // 'hello_world'\n * snakeCase('Hello-World') // 'hello_world'\n */\nexport function snakeCase(text: string, { prefix = '', suffix = '' }: Omit<Options, 'isFile'> = {}): string {\n const processed = `${prefix} ${text} ${suffix}`.trim()\n return processed\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[\\s\\-.]+/g, '_')\n .replace(/[^a-zA-Z0-9_]/g, '')\n .toLowerCase()\n .split('_')\n .filter(Boolean)\n .join('_')\n}\n\n/**\n * Converts `text` to SCREAMING_SNAKE_CASE.\n *\n * @example\n * screamingSnakeCase('helloWorld') // 'HELLO_WORLD'\n */\nexport function screamingSnakeCase(text: string, { prefix = '', suffix = '' }: Omit<Options, 'isFile'> = {}): string {\n return snakeCase(text, { prefix, suffix }).toUpperCase()\n}\n","/**\n * JavaScript and Java reserved words.\n * @link https://github.com/jonschlinkert/reserved/blob/master/index.js\n */\nconst reservedWords = new Set([\n 'abstract',\n 'arguments',\n 'boolean',\n 'break',\n 'byte',\n 'case',\n 'catch',\n 'char',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'double',\n 'else',\n 'enum',\n 'eval',\n 'export',\n 'extends',\n 'false',\n 'final',\n 'finally',\n 'float',\n 'for',\n 'function',\n 'goto',\n 'if',\n 'implements',\n 'import',\n 'in',\n 'instanceof',\n 'int',\n 'interface',\n 'let',\n 'long',\n 'native',\n 'new',\n 'null',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'return',\n 'short',\n 'static',\n 'super',\n 'switch',\n 'synchronized',\n 'this',\n 'throw',\n 'throws',\n 'transient',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'volatile',\n 'while',\n 'with',\n 'yield',\n 'Array',\n 'Date',\n 'hasOwnProperty',\n 'Infinity',\n 'isFinite',\n 'isNaN',\n 'isPrototypeOf',\n 'length',\n 'Math',\n 'name',\n 'NaN',\n 'Number',\n 'Object',\n 'prototype',\n 'String',\n 'toString',\n 'undefined',\n 'valueOf',\n] as const)\n\n/**\n * Returns `true` when `name` is a syntactically valid JavaScript variable name.\n *\n * @example\n * ```ts\n * isValidVarName('status') // true\n * isValidVarName('class') // false (reserved word)\n * isValidVarName('42foo') // false (starts with digit)\n * ```\n */\nexport function isValidVarName(name: string): boolean {\n if (!name || reservedWords.has(name as 'valueOf')) {\n return false\n }\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)\n}\n\n/**\n * Returns `name` when it's a syntactically valid JavaScript variable name,\n * otherwise prefixes it with `_` so the result is a valid identifier.\n *\n * Useful for sanitizing OpenAPI schema names or operation IDs that start with\n * a digit (e.g. `409`, `504AccountCancel`) before using them as exported\n * variable, type, or function names.\n *\n * @example\n * ```ts\n * ensureValidVarName('409') // '_409'\n * ensureValidVarName('504AccountCancel') // '_504AccountCancel'\n * ensureValidVarName('Pet') // 'Pet'\n * ensureValidVarName('class') // '_class'\n * ```\n */\nexport function ensureValidVarName(name: string): string {\n if (!name || isValidVarName(name)) {\n return name\n }\n return `_${name}`\n}\n","import { camelCase } from '@internals/utils'\nimport type { Group } from '@kubb/core'\n\n/**\n * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the\n * shared default naming so every plugin groups output consistently:\n *\n * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).\n * - other groups use `${camelCase(group)}${suffix}` (e.g. `petController`).\n *\n * A user-provided `group.name` always wins over the default namer, so callers stay in\n * control of their output folders. Returns `null` when grouping is disabled, matching the\n * per-plugin convention.\n *\n * @param group - The user-supplied group option, or `undefined` to disable grouping.\n * @param options.suffix - Appended to non-`path` group names, e.g. `'Controller'` or `'Requests'`.\n *\n * @example\n * ```ts\n * createGroupConfig(group, { suffix: 'Controller' }) // plugin-ts, plugin-client, …\n * createGroupConfig(group, { suffix: 'Requests' }) // plugin-cypress, plugin-mcp\n * ```\n */\nexport function createGroupConfig(group: Group | undefined, options: { suffix: string }): Group | null {\n if (!group) {\n return null\n }\n\n const defaultName = (ctx: { group: string }): string => {\n if (group.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n\n return `${camelCase(ctx.group)}${options.suffix}`\n }\n\n return {\n ...group,\n name: group.name ? group.name : defaultName,\n } satisfies Group\n}\n","import { createHash } from 'node:crypto'\nimport path from 'node:path'\nimport { camelCase, ensureValidVarName } from '@internals/utils'\nimport { defineResolver, KubbDriver } from '@kubb/core'\nimport type { PluginFaker } from '../types.ts'\n\n/**\n * Default resolver used by `@kubb/plugin-faker`. Decides the names and file\n * paths for every generated mock factory. Functions and files are prefixed\n * with `create` so `Pet` becomes `createPet`.\n *\n * @example Resolve a factory name\n * ```ts\n * import { resolverFaker } from '@kubb/plugin-faker'\n *\n * resolverFaker.default('list pets', 'function') // 'createListPets'\n * ```\n */\nexport const resolverFaker = defineResolver<PluginFaker>(() => {\n return {\n name: 'default',\n pluginName: 'plugin-faker',\n default(name, type) {\n const resolvedName = camelCase(name, { isFile: type === 'file', prefix: 'create' })\n return type === 'file' ? resolvedName : ensureValidVarName(resolvedName)\n },\n resolveName(name, type) {\n return this.default(name, type)\n },\n resolvePathName(name, type) {\n return this.default(name, type)\n },\n resolveFile({ name, extname, tag, path: groupPath }, context) {\n const pathMode = KubbDriver.getMode(path.resolve(context.root, context.output.path))\n const baseName = `${pathMode === 'single' ? '' : this.resolveName(name, 'file')}${extname}` as `${string}.${string}`\n const filePath = this.resolvePath(\n {\n baseName,\n pathMode,\n tag,\n path: groupPath,\n },\n context,\n )\n\n return {\n kind: 'File',\n id: createHash('sha256').update(filePath).digest('hex'),\n name: path.basename(filePath, extname),\n path: filePath,\n baseName,\n extname,\n meta: { pluginName: this.pluginName },\n sources: [],\n imports: [],\n exports: [],\n }\n },\n resolveParamName(node, param) {\n return this.resolveName(`${node.operationId} ${param.in} ${param.name}`)\n },\n resolveDataName(node) {\n return this.resolveName(`${node.operationId} Data`)\n },\n resolveResponseStatusName(node, statusCode) {\n return this.resolveName(`${node.operationId} Status ${statusCode}`)\n },\n resolveResponseName(node) {\n return this.resolveName(`${node.operationId} Response`)\n },\n resolveResponsesName(node) {\n return this.resolveName(`${node.operationId} Responses`)\n },\n resolvePathParamsName(node, param) {\n return this.resolveParamName(node, param)\n },\n resolveQueryParamsName(node, param) {\n return this.resolveParamName(node, param)\n },\n resolveHeaderParamsName(node, param) {\n return this.resolveParamName(node, param)\n },\n }\n})\n","import { createGroupConfig } from '@internals/shared'\nimport { definePlugin } from '@kubb/core'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { fakerGenerator } from './generators/fakerGenerator.tsx'\nimport { resolverFaker } from './resolvers/resolverFaker.ts'\nimport type { PluginFaker } from './types.ts'\n\n/**\n * Canonical plugin name for `@kubb/plugin-faker`. Used for driver lookups and\n * cross-plugin dependency references.\n */\nexport const pluginFakerName = 'plugin-faker' satisfies PluginFaker['name']\n\n/**\n * Generates one mock-data factory per OpenAPI schema using Faker.js. Call\n * `createPet()` to get a realistic `Pet` object. Useful for tests, Storybook,\n * and local development without a running backend.\n *\n * @example\n * ```ts\n * import { defineConfig } from 'kubb'\n * import { pluginTs } from '@kubb/plugin-ts'\n * import { pluginFaker } from '@kubb/plugin-faker'\n *\n * export default defineConfig({\n * input: { path: './petStore.yaml' },\n * output: { path: './src/gen' },\n * plugins: [\n * pluginTs(),\n * pluginFaker({\n * output: { path: './mocks' },\n * seed: [100],\n * }),\n * ],\n * })\n * ```\n */\nexport const pluginFaker = definePlugin<PluginFaker>((options) => {\n const {\n output = { path: 'mocks', barrelType: 'named' },\n seed,\n locale = 'en',\n group,\n exclude = [],\n include,\n override = [],\n mapper = {},\n dateParser = 'faker',\n generators: userGenerators = [],\n regexGenerator = 'faker',\n paramsCasing,\n printer,\n resolver: userResolver,\n transformer: userTransformer,\n } = options\n\n const groupConfig = createGroupConfig(group, { suffix: 'Controller' })\n\n return {\n name: pluginFakerName,\n options,\n dependencies: [pluginTsName],\n hooks: {\n 'kubb:plugin:setup'(ctx) {\n ctx.setOptions({\n output,\n seed,\n locale,\n exclude,\n include,\n override,\n group: groupConfig,\n mapper,\n dateParser,\n regexGenerator,\n paramsCasing,\n printer,\n })\n ctx.setResolver(userResolver ? { ...resolverFaker, ...userResolver } : resolverFaker)\n if (userTransformer) {\n ctx.setTransformer(userTransformer)\n }\n ctx.addGenerator(fakerGenerator)\n for (const generator of userGenerators) {\n ctx.addGenerator(generator)\n }\n },\n },\n }\n})\n\nexport default pluginFaker\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../internals/utils/src/casing.ts","../../../internals/utils/src/fs.ts","../../../internals/utils/src/reserved.ts","../../../internals/shared/src/group.ts","../src/resolvers/resolverFaker.ts","../src/plugin.ts"],"sourcesContent":["type Options = {\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n return text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n .split(/[\\s\\-_./\\\\:]+/)\n .filter(Boolean)\n .map((word, i) => {\n if (word.length > 1 && word === word.toUpperCase()) return word\n const head = i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()\n return head + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Converts `text` to camelCase.\n *\n * @example Word boundaries\n * `camelCase('hello-world') // 'helloWorld'`\n *\n * @example With a prefix\n * `camelCase('tag', { prefix: 'create' }) // 'createTag'`\n */\nexport function camelCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n *\n * @example Word boundaries\n * `pascalCase('hello-world') // 'HelloWorld'`\n *\n * @example With a suffix\n * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`\n */\nexport function pascalCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n\n/**\n * Converts `text` to snake_case.\n *\n * @example From camelCase\n * `snakeCase('helloWorld') // 'hello_world'`\n *\n * @example From mixed separators\n * `snakeCase('Hello-World') // 'hello_world'`\n */\nexport function snakeCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n const processed = `${prefix} ${text} ${suffix}`.trim()\n return processed\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[\\s\\-.]+/g, '_')\n .replace(/[^a-zA-Z0-9_]/g, '')\n .toLowerCase()\n .split('_')\n .filter(Boolean)\n .join('_')\n}\n\n/**\n * Converts `text` to SCREAMING_SNAKE_CASE.\n *\n * @example From camelCase\n * `screamingSnakeCase('helloWorld') // 'HELLO_WORLD'`\n */\nexport function screamingSnakeCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return snakeCase(text, { prefix, suffix }).toUpperCase()\n}\n","import { posix } from 'node:path'\nimport { camelCase } from './casing.ts'\n\nfunction toSlash(p: string): string {\n if (p.startsWith('\\\\\\\\?\\\\')) return p\n return p.replaceAll('\\\\', '/')\n}\n\n/**\n * Returns the relative path from `rootDir` to `filePath`, always using forward slashes\n * and prefixed with `./` when not already traversing upward.\n *\n * @example\n * ```ts\n * getRelativePath('/src/components', '/src/components/Button.tsx') // './Button.tsx'\n * getRelativePath('/src/components', '/src/utils/helpers.ts') // '../utils/helpers.ts'\n * ```\n */\nexport function getRelativePath(rootDir?: string | null, filePath?: string | null): string {\n if (!rootDir || !filePath) {\n throw new Error(`Root and file should be filled in when retrieving the relativePath, ${rootDir || ''} ${filePath || ''}`)\n }\n\n const relativePath = posix.relative(toSlash(rootDir), toSlash(filePath))\n\n return relativePath.startsWith('../') ? relativePath : `./${relativePath}`\n}\n\n/**\n * Builds a nested file path from a dotted name. Splits on dots that precede a letter\n * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases\n * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.\n *\n * Empty segments are dropped before joining. They arise when the name starts with a dot\n * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to\n * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an\n * absolute path, letting generated files escape the configured output directory.\n *\n * @example Nested path from a dotted name\n * `toFilePath('pet.petId') // 'pet/petId'`\n *\n * @example PascalCase the final segment\n * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`\n *\n * @example Suffix applied to the final segment only\n * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`\n */\nexport function toFilePath(name: string, caseLast: (part: string) => string = camelCase): string {\n const parts = name.split(/\\.(?=[a-zA-Z])/)\n return parts\n .map((part, i) => (i === parts.length - 1 ? caseLast(part) : camelCase(part)))\n .filter(Boolean)\n .join('/')\n}\n","/**\n * JavaScript and Java reserved words.\n * @link https://github.com/jonschlinkert/reserved/blob/master/index.js\n */\nconst reservedWords = new Set([\n 'abstract',\n 'arguments',\n 'boolean',\n 'break',\n 'byte',\n 'case',\n 'catch',\n 'char',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'double',\n 'else',\n 'enum',\n 'eval',\n 'export',\n 'extends',\n 'false',\n 'final',\n 'finally',\n 'float',\n 'for',\n 'function',\n 'goto',\n 'if',\n 'implements',\n 'import',\n 'in',\n 'instanceof',\n 'int',\n 'interface',\n 'let',\n 'long',\n 'native',\n 'new',\n 'null',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'return',\n 'short',\n 'static',\n 'super',\n 'switch',\n 'synchronized',\n 'this',\n 'throw',\n 'throws',\n 'transient',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'volatile',\n 'while',\n 'with',\n 'yield',\n 'Array',\n 'Date',\n 'hasOwnProperty',\n 'Infinity',\n 'isFinite',\n 'isNaN',\n 'isPrototypeOf',\n 'length',\n 'Math',\n 'name',\n 'NaN',\n 'Number',\n 'Object',\n 'prototype',\n 'String',\n 'toString',\n 'undefined',\n 'valueOf',\n] as const)\n\n/**\n * Returns `true` when `name` is a syntactically valid JavaScript variable name.\n *\n * @example\n * ```ts\n * isValidVarName('status') // true\n * isValidVarName('class') // false (reserved word)\n * isValidVarName('42foo') // false (starts with digit)\n * ```\n */\nexport function isValidVarName(name: string): boolean {\n if (!name || reservedWords.has(name as 'valueOf')) {\n return false\n }\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)\n}\n\n/**\n * Returns `name` when it's a syntactically valid JavaScript variable name,\n * otherwise prefixes it with `_` so the result is a valid identifier.\n *\n * Useful for sanitizing OpenAPI schema names or operation IDs that start with\n * a digit (e.g. `409`, `504AccountCancel`) before using them as exported\n * variable, type, or function names.\n *\n * @example\n * ```ts\n * ensureValidVarName('409') // '_409'\n * ensureValidVarName('504AccountCancel') // '_504AccountCancel'\n * ensureValidVarName('Pet') // 'Pet'\n * ensureValidVarName('class') // '_class'\n * ```\n */\nexport function ensureValidVarName(name: string): string {\n if (!name || isValidVarName(name)) {\n return name\n }\n return `_${name}`\n}\n","import { camelCase } from '@internals/utils'\nimport type { Group } from '@kubb/core'\n\n/**\n * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the\n * shared default naming so every plugin groups output consistently:\n *\n * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).\n * - other groups use the camelCased group (`pet store` → `petStore`).\n *\n * A user-provided `group.name` always wins over the default namer, so callers stay in\n * control of their output folders. Returns `null` when grouping is disabled, matching the\n * per-plugin convention.\n *\n * @param group - The user-supplied group option, or `undefined` to disable grouping.\n *\n * @example\n * ```ts\n * createGroupConfig(group) // shared across every plugin\n * ```\n */\nexport function createGroupConfig(group: Group | undefined): Group | null {\n if (!group) {\n return null\n }\n\n const defaultName = (ctx: { group: string }): string => {\n if (group.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n\n return camelCase(ctx.group)\n }\n\n return {\n ...group,\n name: group.name ? group.name : defaultName,\n } satisfies Group\n}\n","import { createHash } from 'node:crypto'\nimport path from 'node:path'\nimport { camelCase, ensureValidVarName, toFilePath } from '@internals/utils'\nimport { defineResolver } from '@kubb/core'\nimport type { PluginFaker } from '../types.ts'\n\n/**\n * Default resolver used by `@kubb/plugin-faker`. Decides the names and file\n * paths for every generated mock factory. Functions and files are prefixed\n * with `create` so `Pet` becomes `createPet`.\n *\n * @example Resolve a factory name\n * ```ts\n * import { resolverFaker } from '@kubb/plugin-faker'\n *\n * resolverFaker.default('list pets', 'function') // 'createListPets'\n * ```\n */\nexport const resolverFaker = defineResolver<PluginFaker>(() => {\n return {\n name: 'default',\n pluginName: 'plugin-faker',\n default(name, type) {\n if (type === 'file') return toFilePath(name, (part) => camelCase(part, { prefix: 'create' }))\n return ensureValidVarName(camelCase(name, { prefix: 'create' }))\n },\n resolveName(name, type) {\n return this.default(name, type)\n },\n resolvePathName(name, type) {\n return this.default(name, type)\n },\n resolveFile({ name, extname, tag, path: groupPath }, context) {\n const resolvedName = context.output.mode === 'file' ? '' : this.resolveName(name, 'file')\n const inputBaseName = `${resolvedName}${extname}` as `${string}.${string}`\n const filePath = this.resolvePath(\n {\n baseName: inputBaseName,\n tag,\n path: groupPath,\n },\n context,\n )\n const baseName = path.basename(filePath) as `${string}.${string}`\n\n return {\n kind: 'File',\n id: createHash('sha256').update(filePath).digest('hex'),\n name: path.basename(filePath, extname),\n path: filePath,\n baseName,\n extname,\n meta: { pluginName: this.pluginName },\n sources: [],\n imports: [],\n exports: [],\n }\n },\n resolveParamName(node, param) {\n return this.resolveName(`${node.operationId} ${param.in} ${param.name}`)\n },\n resolveDataName(node) {\n return this.resolveName(`${node.operationId} Data`)\n },\n resolveResponseStatusName(node, statusCode) {\n return this.resolveName(`${node.operationId} Status ${statusCode}`)\n },\n resolveResponseName(node) {\n return this.resolveName(`${node.operationId} Response`)\n },\n resolveResponsesName(node) {\n return this.resolveName(`${node.operationId} Responses`)\n },\n resolvePathParamsName(node, param) {\n return this.resolveParamName(node, param)\n },\n resolveQueryParamsName(node, param) {\n return this.resolveParamName(node, param)\n },\n resolveHeaderParamsName(node, param) {\n return this.resolveParamName(node, param)\n },\n }\n})\n","import { createGroupConfig } from '@internals/shared'\nimport { definePlugin } from '@kubb/core'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { fakerGenerator } from './generators/fakerGenerator.tsx'\nimport { resolverFaker } from './resolvers/resolverFaker.ts'\nimport type { PluginFaker } from './types.ts'\n\n/**\n * Canonical plugin name for `@kubb/plugin-faker`. Used for driver lookups and\n * cross-plugin dependency references.\n */\nexport const pluginFakerName = 'plugin-faker' satisfies PluginFaker['name']\n\n/**\n * Generates one mock-data factory per OpenAPI schema using Faker.js. Call\n * `createPet()` to get a realistic `Pet` object. Useful for tests, Storybook,\n * and local development without a running backend.\n *\n * @example\n * ```ts\n * import { defineConfig } from 'kubb'\n * import { pluginTs } from '@kubb/plugin-ts'\n * import { pluginFaker } from '@kubb/plugin-faker'\n *\n * export default defineConfig({\n * input: { path: './petStore.yaml' },\n * output: { path: './src/gen' },\n * plugins: [\n * pluginTs(),\n * pluginFaker({\n * output: { path: './mocks' },\n * seed: [100],\n * }),\n * ],\n * })\n * ```\n */\nexport const pluginFaker = definePlugin<PluginFaker>((options) => {\n const {\n output = { path: 'mocks', barrel: { type: 'named' } },\n seed,\n locale = 'en',\n group,\n exclude = [],\n include,\n override = [],\n mapper = {},\n dateParser = 'faker',\n generators: userGenerators = [],\n regexGenerator = 'faker',\n paramsCasing,\n printer,\n resolver: userResolver,\n transformer: userTransformer,\n } = options\n\n const groupConfig = createGroupConfig(group)\n\n return {\n name: pluginFakerName,\n options,\n dependencies: [pluginTsName],\n hooks: {\n 'kubb:plugin:setup'(ctx) {\n ctx.setOptions({\n output,\n seed,\n locale,\n exclude,\n include,\n override,\n group: groupConfig,\n mapper,\n dateParser,\n regexGenerator,\n paramsCasing,\n printer,\n })\n ctx.setResolver(userResolver ? { ...resolverFaker, ...userResolver } : resolverFaker)\n if (userTransformer) {\n ctx.setTransformer(userTransformer)\n }\n ctx.addGenerator(fakerGenerator)\n for (const generator of userGenerators) {\n ctx.addGenerator(generator)\n }\n },\n },\n }\n})\n\nexport default pluginFaker\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __name } from "./chunk-C0LytTxp.js";
|
|
2
|
-
import { Exclude, Generator, Group, Include, Output, Override, PluginFactoryOptions, Resolver, ast } from "@kubb/core";
|
|
2
|
+
import { Exclude, Generator, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver, ast } from "@kubb/core";
|
|
3
3
|
|
|
4
4
|
//#region src/types.d.ts
|
|
5
5
|
/**
|
|
@@ -70,17 +70,13 @@ type ResolverFaker = Resolver & ast.OperationParamsResolver & {
|
|
|
70
70
|
*/
|
|
71
71
|
resolveHeaderParamsName(this: ResolverFaker, node: ast.OperationNode, param: ast.ParameterNode): string;
|
|
72
72
|
};
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Split generated files into subfolders based on the operation's tag.
|
|
82
|
-
*/
|
|
83
|
-
group?: Group;
|
|
73
|
+
/**
|
|
74
|
+
* Where the generated mock factories are written and how they are exported, plus the optional
|
|
75
|
+
* `group` strategy. The `group` option organizes `output.mode: 'directory'` output into per-tag or per-path subdirectories.
|
|
76
|
+
*
|
|
77
|
+
* @default { path: 'mocks', barrel: { type: 'named' } }
|
|
78
|
+
*/
|
|
79
|
+
type Options = OutputOptions & {
|
|
84
80
|
/**
|
|
85
81
|
* Skip operations matching at least one entry in the list.
|
|
86
82
|
*/
|
|
@@ -240,4 +236,4 @@ type PrinterFakerFactory = ast.PrinterFactoryOptions<'faker', PrinterFakerOption
|
|
|
240
236
|
declare const printerFaker: (options: PrinterFakerOptions) => ast.Printer<PrinterFakerFactory>;
|
|
241
237
|
//#endregion
|
|
242
238
|
export { Options as a, printerFaker as i, PrinterFakerNodes as n, PluginFaker as o, PrinterFakerOptions as r, ResolverFaker as s, PrinterFakerFactory as t };
|
|
243
|
-
//# sourceMappingURL=printerFaker-
|
|
239
|
+
//# sourceMappingURL=printerFaker-CMCJT3FB.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/plugin-faker",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.56",
|
|
4
4
|
"description": "Generate Faker.js mock data factories from your OpenAPI schemas. Produces realistic seed data, test fixtures, and datasets for development and testing.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"code-generation",
|
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
"files": [
|
|
27
27
|
"src",
|
|
28
28
|
"dist",
|
|
29
|
-
"extension.yaml",
|
|
30
29
|
"!/**/**.test.**",
|
|
31
30
|
"!/**/__tests__/**",
|
|
32
31
|
"!/**/__snapshots__/**"
|
|
@@ -66,30 +65,24 @@
|
|
|
66
65
|
"registry": "https://registry.npmjs.org/"
|
|
67
66
|
},
|
|
68
67
|
"dependencies": {
|
|
69
|
-
"@kubb/
|
|
70
|
-
"@kubb/
|
|
71
|
-
"@kubb/
|
|
68
|
+
"@kubb/ast": "5.0.0-beta.55",
|
|
69
|
+
"@kubb/core": "5.0.0-beta.55",
|
|
70
|
+
"@kubb/renderer-jsx": "5.0.0-beta.55",
|
|
71
|
+
"@kubb/plugin-ts": "5.0.0-beta.56"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@internals/shared": "0.0.0",
|
|
75
75
|
"@internals/utils": "0.0.0"
|
|
76
76
|
},
|
|
77
77
|
"peerDependencies": {
|
|
78
|
-
"@kubb/renderer-jsx": "5.0.0-beta.
|
|
78
|
+
"@kubb/renderer-jsx": "5.0.0-beta.55"
|
|
79
79
|
},
|
|
80
|
-
"size-limit": [
|
|
81
|
-
{
|
|
82
|
-
"path": "./dist/*.js",
|
|
83
|
-
"limit": "510 KiB",
|
|
84
|
-
"gzip": true
|
|
85
|
-
}
|
|
86
|
-
],
|
|
87
80
|
"engines": {
|
|
88
81
|
"node": ">=22"
|
|
89
82
|
},
|
|
90
83
|
"scripts": {
|
|
91
|
-
"build": "tsdown
|
|
92
|
-
"clean": "
|
|
84
|
+
"build": "tsdown",
|
|
85
|
+
"clean": "node -e \"require('node:fs').rmSync('./dist', {recursive:true,force:true})\"",
|
|
93
86
|
"lint": "oxlint .",
|
|
94
87
|
"lint:fix": "oxlint --fix .",
|
|
95
88
|
"release": "pnpm publish --no-git-check",
|
package/src/components/Faker.tsx
CHANGED
|
@@ -2,7 +2,7 @@ import { getPerContentTypeName, resolveContentTypeVariants } from '@internals/sh
|
|
|
2
2
|
import { aliasConflictingImports, filterUsedImports, rewriteAliasedImports } from '@internals/utils'
|
|
3
3
|
import { ast, defineGenerator } from '@kubb/core'
|
|
4
4
|
import { pluginTsName } from '@kubb/plugin-ts'
|
|
5
|
-
import { File,
|
|
5
|
+
import { File, jsxRenderer } from '@kubb/renderer-jsx'
|
|
6
6
|
import { Faker } from '../components/Faker.tsx'
|
|
7
7
|
import { printerFaker } from '../printers/printerFaker.ts'
|
|
8
8
|
import type { PluginFaker } from '../types.ts'
|
|
@@ -16,7 +16,7 @@ import { buildResponseUnionSchema, canOverrideSchema, localeToFakerImport, resol
|
|
|
16
16
|
*/
|
|
17
17
|
export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
18
18
|
name: 'faker',
|
|
19
|
-
renderer:
|
|
19
|
+
renderer: jsxRenderer,
|
|
20
20
|
schema(node, ctx) {
|
|
21
21
|
const { adapter, config, resolver, root } = ctx
|
|
22
22
|
const { output, group, dateParser, regexGenerator, mapper, seed, locale, printer } = ctx.options
|
|
@@ -29,14 +29,11 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
29
29
|
const tsResolver = ctx.driver.getResolver(pluginTsName)
|
|
30
30
|
|
|
31
31
|
const schemaName = node.name
|
|
32
|
-
const mode = ctx.getMode(output)
|
|
33
32
|
const isEnumSchema = !!ast.narrowSchema(node, ast.schemaTypes.enum)
|
|
34
|
-
const tsEnumType = pluginTs.options?.
|
|
35
|
-
const tsEnumTypeSuffix = pluginTs.options?.
|
|
33
|
+
const tsEnumType = pluginTs.options?.enum?.type
|
|
34
|
+
const tsEnumTypeSuffix = pluginTs.options?.enum?.typeSuffix ?? 'Key'
|
|
36
35
|
const schemaTypeName =
|
|
37
|
-
isEnumSchema &&
|
|
38
|
-
? tsResolver.resolveEnumKeyName({ name: schemaName }, tsEnumTypeSuffix)
|
|
39
|
-
: tsResolver.resolveTypeName(schemaName)
|
|
36
|
+
isEnumSchema && tsEnumType === 'asConst' ? tsResolver.resolveEnumKeyName({ name: schemaName }, tsEnumTypeSuffix) : tsResolver.resolveTypeName(schemaName)
|
|
40
37
|
const meta = {
|
|
41
38
|
name: resolver.resolveName(schemaName),
|
|
42
39
|
file: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group: group ?? undefined }),
|
|
@@ -68,12 +65,10 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
68
65
|
typeFilePath: meta.typeFile.path,
|
|
69
66
|
})
|
|
70
67
|
|
|
71
|
-
const imports = adapter
|
|
72
|
-
.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}))
|
|
76
|
-
.filter((entry) => entry.path !== meta.file.path)
|
|
68
|
+
const imports = adapter.getImports(node, (schemaName) => ({
|
|
69
|
+
name: resolver.resolveName(schemaName),
|
|
70
|
+
path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group: group ?? undefined }).path,
|
|
71
|
+
}))
|
|
77
72
|
const usedImports = filterUsedImports(imports, fakerText)
|
|
78
73
|
|
|
79
74
|
return (
|
|
@@ -88,8 +83,9 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
88
83
|
{regexGenerator === 'randexp' && <File.Import name={'RandExp'} path={'randexp'} />}
|
|
89
84
|
{dateParser !== 'faker' && <File.Import path={dateParser} name={dateParser} />}
|
|
90
85
|
{typeReference.importPath && <File.Import isTypeOnly root={meta.file.path} path={typeReference.importPath} name={[meta.typeName]} />}
|
|
91
|
-
{
|
|
92
|
-
|
|
86
|
+
{usedImports.map((imp) => (
|
|
87
|
+
<File.Import key={[schemaName, imp.path, imp.name].join('-')} root={meta.file.path} path={imp.path} name={imp.name} />
|
|
88
|
+
))}
|
|
93
89
|
<Faker
|
|
94
90
|
name={meta.name}
|
|
95
91
|
typeName={typeReference.typeName}
|
package/src/plugin.ts
CHANGED
|
@@ -37,7 +37,7 @@ export const pluginFakerName = 'plugin-faker' satisfies PluginFaker['name']
|
|
|
37
37
|
*/
|
|
38
38
|
export const pluginFaker = definePlugin<PluginFaker>((options) => {
|
|
39
39
|
const {
|
|
40
|
-
output = { path: 'mocks',
|
|
40
|
+
output = { path: 'mocks', barrel: { type: 'named' } },
|
|
41
41
|
seed,
|
|
42
42
|
locale = 'en',
|
|
43
43
|
group,
|
|
@@ -54,7 +54,7 @@ export const pluginFaker = definePlugin<PluginFaker>((options) => {
|
|
|
54
54
|
transformer: userTransformer,
|
|
55
55
|
} = options
|
|
56
56
|
|
|
57
|
-
const groupConfig = createGroupConfig(group
|
|
57
|
+
const groupConfig = createGroupConfig(group)
|
|
58
58
|
|
|
59
59
|
return {
|
|
60
60
|
name: pluginFakerName,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { stringify, toRegExpString } from '@
|
|
1
|
+
import { buildObject, extractRefName, objectKey, stringify, toRegExpString } from '@kubb/ast/utils'
|
|
2
2
|
import { ast } from '@kubb/core'
|
|
3
3
|
import type { PluginFaker, ResolverFaker } from '../types.ts'
|
|
4
4
|
|
|
@@ -284,7 +284,7 @@ export const printerFaker: (options: PrinterFakerOptions) => ast.Printer<Printer
|
|
|
284
284
|
// Use the canonical name from the $ref path — node.name may have been overridden
|
|
285
285
|
// (e.g. by single-member allOf flatten using the property-derived child name).
|
|
286
286
|
// Inline refs (without $ref) from faker utils already carry resolved helper names.
|
|
287
|
-
const refName = node.ref ? (
|
|
287
|
+
const refName = node.ref ? (extractRefName(node.ref) ?? node.name ?? node.schema?.name) : (node.name ?? node.schema?.name)
|
|
288
288
|
|
|
289
289
|
if (!refName) {
|
|
290
290
|
throw new Error('Name not defined for ref node')
|
|
@@ -369,32 +369,30 @@ export const printerFaker: (options: PrinterFakerOptions) => ast.Printer<Printer
|
|
|
369
369
|
},
|
|
370
370
|
object(node): string {
|
|
371
371
|
const cyclicSchemas = this.options.cyclicSchemas
|
|
372
|
-
const
|
|
373
|
-
.
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
372
|
+
const entries = (node.properties ?? []).map((property): string => {
|
|
373
|
+
if (this.options.mapper && Object.hasOwn(this.options.mapper, property.name)) {
|
|
374
|
+
return `${objectKey(property.name)}: ${this.options.mapper[property.name]}`
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const value: string =
|
|
378
|
+
printNested(property.schema, {
|
|
379
|
+
typeName: this.options.typeName ? indexedTypeName(this.options.typeName, property.name, this.options.nestedInUnion) : undefined,
|
|
380
|
+
nestedInObject: true,
|
|
381
|
+
}) ?? 'undefined'
|
|
377
382
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
// emit a memoizing lazy getter. On first access it computes the value,
|
|
387
|
-
// replaces itself with a plain data property via Object.defineProperty,
|
|
388
|
-
// and returns the cached value – so every subsequent read is stable.
|
|
389
|
-
if (cyclicSchemas && ast.containsCircularRef(property.schema, { circularSchemas: cyclicSchemas, excludeName: this.options.schemaName })) {
|
|
390
|
-
return `get ${property.name}() { const _value = ${value}; Object.defineProperty(this, ${JSON.stringify(property.name)}, { value: _value, configurable: true, writable: true, enumerable: true }); return _value }`
|
|
391
|
-
}
|
|
383
|
+
// When the property's schema transitively references a schema that is
|
|
384
|
+
// part of a circular dependency (other than the current schema itself),
|
|
385
|
+
// emit a memoizing lazy getter. On first access it computes the value,
|
|
386
|
+
// replaces itself with a plain data property via Object.defineProperty,
|
|
387
|
+
// and returns the cached value – so every subsequent read is stable.
|
|
388
|
+
if (cyclicSchemas && ast.containsCircularRef(property.schema, { circularSchemas: cyclicSchemas, excludeName: this.options.schemaName })) {
|
|
389
|
+
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 }`
|
|
390
|
+
}
|
|
392
391
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
.join(',')
|
|
392
|
+
return `${objectKey(property.name)}: ${value}`
|
|
393
|
+
})
|
|
396
394
|
|
|
397
|
-
return
|
|
395
|
+
return buildObject(entries)
|
|
398
396
|
},
|
|
399
397
|
...options.nodes,
|
|
400
398
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto'
|
|
2
2
|
import path from 'node:path'
|
|
3
|
-
import { camelCase, ensureValidVarName } from '@internals/utils'
|
|
4
|
-
import { defineResolver
|
|
3
|
+
import { camelCase, ensureValidVarName, toFilePath } from '@internals/utils'
|
|
4
|
+
import { defineResolver } from '@kubb/core'
|
|
5
5
|
import type { PluginFaker } from '../types.ts'
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -21,8 +21,8 @@ export const resolverFaker = defineResolver<PluginFaker>(() => {
|
|
|
21
21
|
name: 'default',
|
|
22
22
|
pluginName: 'plugin-faker',
|
|
23
23
|
default(name, type) {
|
|
24
|
-
|
|
25
|
-
return
|
|
24
|
+
if (type === 'file') return toFilePath(name, (part) => camelCase(part, { prefix: 'create' }))
|
|
25
|
+
return ensureValidVarName(camelCase(name, { prefix: 'create' }))
|
|
26
26
|
},
|
|
27
27
|
resolveName(name, type) {
|
|
28
28
|
return this.default(name, type)
|
|
@@ -31,17 +31,17 @@ export const resolverFaker = defineResolver<PluginFaker>(() => {
|
|
|
31
31
|
return this.default(name, type)
|
|
32
32
|
},
|
|
33
33
|
resolveFile({ name, extname, tag, path: groupPath }, context) {
|
|
34
|
-
const
|
|
35
|
-
const
|
|
34
|
+
const resolvedName = context.output.mode === 'file' ? '' : this.resolveName(name, 'file')
|
|
35
|
+
const inputBaseName = `${resolvedName}${extname}` as `${string}.${string}`
|
|
36
36
|
const filePath = this.resolvePath(
|
|
37
37
|
{
|
|
38
|
-
baseName,
|
|
39
|
-
pathMode,
|
|
38
|
+
baseName: inputBaseName,
|
|
40
39
|
tag,
|
|
41
40
|
path: groupPath,
|
|
42
41
|
},
|
|
43
42
|
context,
|
|
44
43
|
)
|
|
44
|
+
const baseName = path.basename(filePath) as `${string}.${string}`
|
|
45
45
|
|
|
46
46
|
return {
|
|
47
47
|
kind: 'File',
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ast, Exclude, Generator, Group, Include, Output, Override, PluginFactoryOptions, Resolver } from '@kubb/core'
|
|
1
|
+
import type { ast, Exclude, Generator, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver } from '@kubb/core'
|
|
2
2
|
import type { PrinterFakerNodes } from './printers/printerFaker.ts'
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -71,17 +71,13 @@ export type ResolverFaker = Resolver &
|
|
|
71
71
|
resolveHeaderParamsName(this: ResolverFaker, node: ast.OperationNode, param: ast.ParameterNode): string
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Split generated files into subfolders based on the operation's tag.
|
|
83
|
-
*/
|
|
84
|
-
group?: Group
|
|
74
|
+
/**
|
|
75
|
+
* Where the generated mock factories are written and how they are exported, plus the optional
|
|
76
|
+
* `group` strategy. The `group` option organizes `output.mode: 'directory'` output into per-tag or per-path subdirectories.
|
|
77
|
+
*
|
|
78
|
+
* @default { path: 'mocks', barrel: { type: 'named' } }
|
|
79
|
+
*/
|
|
80
|
+
export type Options = OutputOptions & {
|
|
85
81
|
/**
|
|
86
82
|
* Skip operations matching at least one entry in the list.
|
|
87
83
|
*/
|
package/src/utils.ts
CHANGED
|
@@ -188,7 +188,7 @@ export function resolveTypeReference({
|
|
|
188
188
|
* Maps a schema node type to its corresponding scalar type representation.
|
|
189
189
|
* Returns the type name for enums or the base type (string, number, etc.) for primitives.
|
|
190
190
|
*/
|
|
191
|
-
|
|
191
|
+
function getScalarType(node: ast.SchemaNode, typeName: string): string {
|
|
192
192
|
switch (node.type) {
|
|
193
193
|
case 'string':
|
|
194
194
|
case 'email':
|