@kubb/plugin-faker 5.0.0-beta.30 → 5.0.0-beta.31
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-CXZVQQ7e.js → Faker-DwIc_lta.js} +6 -5
- package/dist/{Faker-CXZVQQ7e.js.map → Faker-DwIc_lta.js.map} +1 -1
- package/dist/{Faker-CkJccVKI.cjs → Faker-XuyEQflW.cjs} +6 -5
- package/dist/{Faker-CkJccVKI.cjs.map → Faker-XuyEQflW.cjs.map} +1 -1
- package/dist/components.cjs +1 -1
- package/dist/components.js +1 -1
- package/dist/{fakerGenerator-DhNV9xBw.cjs → fakerGenerator-BBr2WsG8.cjs} +112 -30
- package/dist/fakerGenerator-BBr2WsG8.cjs.map +1 -0
- package/dist/{fakerGenerator-BvMBDgwp.js → fakerGenerator-BDNxA7KY.js} +112 -30
- package/dist/fakerGenerator-BDNxA7KY.js.map +1 -0
- package/dist/generators.cjs +1 -1
- package/dist/generators.js +1 -1
- package/dist/index.cjs +39 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +39 -9
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
- package/src/components/Faker.tsx +9 -4
- package/src/generators/fakerGenerator.tsx +73 -33
- package/src/plugin.ts +3 -16
- package/dist/fakerGenerator-BvMBDgwp.js.map +0 -1
- package/dist/fakerGenerator-DhNV9xBw.cjs.map +0 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["KubbDriver","path","pluginTsName","fakerGenerator"],"sources":["../../../internals/utils/src/casing.ts","../../../internals/utils/src/reserved.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 { 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 { camelCase } from '@internals/utils'\nimport { definePlugin, type Group } 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,\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 = group\n ? ({\n ...group,\n name: group.name\n ? group.name\n : (ctx: { group: string }) => {\n if (group.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n\n return `${camelCase(ctx.group)}Controller`\n },\n } satisfies Group)\n : null\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.cjs","names":["KubbDriver","path","pluginTsName","fakerGenerator"],"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 * Returns `null` when grouping is disabled, matching the 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 * @param options.honorName - When `true`, a user-provided `group.name` overrides the default namer.\n *\n * @example\n * ```ts\n * createGroupConfig(group, { suffix: 'Controller' }) // plugin-ts, plugin-zod\n * createGroupConfig(group, { suffix: 'Controller', honorName: true }) // plugin-faker, plugin-client, …\n * createGroupConfig(group, { suffix: 'Requests', honorName: true }) // plugin-cypress, plugin-mcp\n * ```\n */\nexport function createGroupConfig(group: Group | undefined, options: { suffix: string; honorName?: boolean }): 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: options.honorName && 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,\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', honorName: true })\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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"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./chunk--u3MIqq1.js";
|
|
2
|
-
import { n as printerFaker, t as fakerGenerator } from "./fakerGenerator-
|
|
3
|
-
import { t as Faker } from "./Faker-
|
|
2
|
+
import { n as printerFaker, t as fakerGenerator } from "./fakerGenerator-BDNxA7KY.js";
|
|
3
|
+
import { t as Faker } from "./Faker-DwIc_lta.js";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { KubbDriver, definePlugin, defineResolver } from "@kubb/core";
|
|
6
6
|
import { pluginTsName } from "@kubb/plugin-ts";
|
|
@@ -171,6 +171,39 @@ function ensureValidVarName(name) {
|
|
|
171
171
|
return `_${name}`;
|
|
172
172
|
}
|
|
173
173
|
//#endregion
|
|
174
|
+
//#region ../../internals/shared/src/group.ts
|
|
175
|
+
/**
|
|
176
|
+
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
177
|
+
* shared default naming so every plugin groups output consistently:
|
|
178
|
+
*
|
|
179
|
+
* - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
|
|
180
|
+
* - other groups use `${camelCase(group)}${suffix}` (e.g. `petController`).
|
|
181
|
+
*
|
|
182
|
+
* Returns `null` when grouping is disabled, matching the per-plugin convention.
|
|
183
|
+
*
|
|
184
|
+
* @param group - The user-supplied group option, or `undefined` to disable grouping.
|
|
185
|
+
* @param options.suffix - Appended to non-`path` group names, e.g. `'Controller'` or `'Requests'`.
|
|
186
|
+
* @param options.honorName - When `true`, a user-provided `group.name` overrides the default namer.
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* ```ts
|
|
190
|
+
* createGroupConfig(group, { suffix: 'Controller' }) // plugin-ts, plugin-zod
|
|
191
|
+
* createGroupConfig(group, { suffix: 'Controller', honorName: true }) // plugin-faker, plugin-client, …
|
|
192
|
+
* createGroupConfig(group, { suffix: 'Requests', honorName: true }) // plugin-cypress, plugin-mcp
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
function createGroupConfig(group, options) {
|
|
196
|
+
if (!group) return null;
|
|
197
|
+
const defaultName = (ctx) => {
|
|
198
|
+
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
199
|
+
return `${camelCase(ctx.group)}${options.suffix}`;
|
|
200
|
+
};
|
|
201
|
+
return {
|
|
202
|
+
...group,
|
|
203
|
+
name: options.honorName && group.name ? group.name : defaultName
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
//#endregion
|
|
174
207
|
//#region src/resolvers/resolverFaker.ts
|
|
175
208
|
/**
|
|
176
209
|
* Default resolver used by `@kubb/plugin-faker`. Decides the names and file
|
|
@@ -285,13 +318,10 @@ const pluginFaker = definePlugin((options) => {
|
|
|
285
318
|
path: "mocks",
|
|
286
319
|
barrelType: "named"
|
|
287
320
|
}, seed, locale, group, exclude = [], include, override = [], mapper = {}, dateParser = "faker", generators: userGenerators = [], regexGenerator = "faker", paramsCasing, printer, resolver: userResolver, transformer: userTransformer } = options;
|
|
288
|
-
const groupConfig = group
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
return `${camelCase(ctx.group)}Controller`;
|
|
293
|
-
}
|
|
294
|
-
} : null;
|
|
321
|
+
const groupConfig = createGroupConfig(group, {
|
|
322
|
+
suffix: "Controller",
|
|
323
|
+
honorName: true
|
|
324
|
+
});
|
|
295
325
|
return {
|
|
296
326
|
name: pluginFakerName,
|
|
297
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","../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 { 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 { camelCase } from '@internals/utils'\nimport { definePlugin, type Group } 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,\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 = group\n ? ({\n ...group,\n name: group.name\n ? group.name\n : (ctx: { group: string }) => {\n if (group.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n\n return `${camelCase(ctx.group)}Controller`\n },\n } satisfies Group)\n : null\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/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 * Returns `null` when grouping is disabled, matching the 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 * @param options.honorName - When `true`, a user-provided `group.name` overrides the default namer.\n *\n * @example\n * ```ts\n * createGroupConfig(group, { suffix: 'Controller' }) // plugin-ts, plugin-zod\n * createGroupConfig(group, { suffix: 'Controller', honorName: true }) // plugin-faker, plugin-client, …\n * createGroupConfig(group, { suffix: 'Requests', honorName: true }) // plugin-cypress, plugin-mcp\n * ```\n */\nexport function createGroupConfig(group: Group | undefined, options: { suffix: string; honorName?: boolean }): 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: options.honorName && 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,\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', honorName: true })\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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"}
|
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.31",
|
|
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",
|
|
@@ -66,15 +66,16 @@
|
|
|
66
66
|
"registry": "https://registry.npmjs.org/"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"@kubb/core": "5.0.0-beta.
|
|
70
|
-
"@kubb/renderer-jsx": "5.0.0-beta.
|
|
71
|
-
"@kubb/plugin-ts": "5.0.0-beta.
|
|
69
|
+
"@kubb/core": "5.0.0-beta.31",
|
|
70
|
+
"@kubb/renderer-jsx": "5.0.0-beta.31",
|
|
71
|
+
"@kubb/plugin-ts": "5.0.0-beta.31"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
+
"@internals/shared": "0.0.0",
|
|
74
75
|
"@internals/utils": "0.0.0"
|
|
75
76
|
},
|
|
76
77
|
"peerDependencies": {
|
|
77
|
-
"@kubb/renderer-jsx": "5.0.0-beta.
|
|
78
|
+
"@kubb/renderer-jsx": "5.0.0-beta.31"
|
|
78
79
|
},
|
|
79
80
|
"size-limit": [
|
|
80
81
|
{
|
package/src/components/Faker.tsx
CHANGED
|
@@ -69,6 +69,11 @@ export function Faker({ node, description, name, typeName, printer, seed, canOve
|
|
|
69
69
|
const paramsSignature = declarationPrinter.print(params) ?? ''
|
|
70
70
|
const returnType = resolvedReturnType
|
|
71
71
|
|
|
72
|
+
// A `ref` wrapper delegates to another faker. Object fakers are now generic and
|
|
73
|
+
// widen to `Partial<T>` when called with a `Partial<T>`-typed argument, so cast
|
|
74
|
+
// back to the wrapper's declared return type to keep it assignable.
|
|
75
|
+
const returnExpression = node.type === 'ref' && canOverride && returnType ? `${fakerTextWithOverride} as ${returnType}` : fakerTextWithOverride
|
|
76
|
+
|
|
72
77
|
return (
|
|
73
78
|
<File.Source name={name} isExportable isIndexable>
|
|
74
79
|
<Function
|
|
@@ -84,7 +89,7 @@ export function Faker({ node, description, name, typeName, printer, seed, canOve
|
|
|
84
89
|
<br />
|
|
85
90
|
</>
|
|
86
91
|
) : undefined}
|
|
87
|
-
{`return ${
|
|
92
|
+
{`return ${returnExpression}`}
|
|
88
93
|
</Function>
|
|
89
94
|
</File.Source>
|
|
90
95
|
)
|
|
@@ -92,7 +97,7 @@ export function Faker({ node, description, name, typeName, printer, seed, canOve
|
|
|
92
97
|
|
|
93
98
|
// Generate function with defaultFakeData structure
|
|
94
99
|
const jsdoc = description ? `/**\n * @description ${jsStringEscape(description)}\n */\n ` : ''
|
|
95
|
-
const functionSignature = `${jsdoc}export function ${name}
|
|
100
|
+
const functionSignature = `${jsdoc}export function ${name}<TData extends Partial<${typeName}> = object>(data?: TData)`
|
|
96
101
|
|
|
97
102
|
const seedCode = seed ? `faker.seed(${JSON.stringify(seed)})\n ` : ''
|
|
98
103
|
|
|
@@ -115,14 +120,14 @@ export function Faker({ node, description, name, typeName, printer, seed, canOve
|
|
|
115
120
|
Object.defineProperty(defaultFakeData, key, { value, configurable: true, writable: true, enumerable: true })
|
|
116
121
|
}
|
|
117
122
|
}
|
|
118
|
-
return defaultFakeData as
|
|
123
|
+
return defaultFakeData as Omit<typeof defaultFakeData, keyof TData> & TData
|
|
119
124
|
}`
|
|
120
125
|
: `{
|
|
121
126
|
${seedCode}const defaultFakeData = ${fakerText}
|
|
122
127
|
return {
|
|
123
128
|
...defaultFakeData,
|
|
124
129
|
...(data || {}),
|
|
125
|
-
} as
|
|
130
|
+
} as Omit<typeof defaultFakeData, keyof TData> & TData
|
|
126
131
|
}`
|
|
127
132
|
|
|
128
133
|
return (
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getPerContentTypeName, resolveContentTypeVariants } from '@internals/shared'
|
|
1
2
|
import { aliasConflictingImports, filterUsedImports, rewriteAliasedImports } from '@internals/utils'
|
|
2
3
|
import { ast, defineGenerator } from '@kubb/core'
|
|
3
4
|
import { pluginTsName } from '@kubb/plugin-ts'
|
|
@@ -29,10 +30,17 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
29
30
|
|
|
30
31
|
const schemaName = node.name
|
|
31
32
|
const mode = ctx.getMode(output)
|
|
33
|
+
const isEnumSchema = !!ast.narrowSchema(node, ast.schemaTypes.enum)
|
|
34
|
+
const tsEnumType = pluginTs.options?.enumType
|
|
35
|
+
const tsEnumTypeSuffix = pluginTs.options?.enumTypeSuffix ?? 'Key'
|
|
36
|
+
const schemaTypeName =
|
|
37
|
+
isEnumSchema && (tsEnumType === 'asConst' || tsEnumType === 'asPascalConst')
|
|
38
|
+
? tsResolver.resolveEnumKeyName({ name: schemaName }, tsEnumTypeSuffix)
|
|
39
|
+
: tsResolver.resolveTypeName(schemaName)
|
|
32
40
|
const meta = {
|
|
33
41
|
name: resolver.resolveName(schemaName),
|
|
34
42
|
file: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group: group ?? undefined }),
|
|
35
|
-
typeName:
|
|
43
|
+
typeName: schemaTypeName,
|
|
36
44
|
typeFile: tsResolver.resolveFile(
|
|
37
45
|
{ name: schemaName, extname: '.ts' },
|
|
38
46
|
{ root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group ?? undefined },
|
|
@@ -111,27 +119,57 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
111
119
|
name: resolveParamNameByLocation(resolver, node, param),
|
|
112
120
|
typeName: resolveParamNameByLocation(tsResolver, node, param),
|
|
113
121
|
}))
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
122
|
+
type RenderUnit = { schema: ast.SchemaNode | null; name: string; typeName: string; description?: string; skipImportNames: Array<string> }
|
|
123
|
+
|
|
124
|
+
// Expands a content array into render units: one faker per content type plus a union faker
|
|
125
|
+
// (named `baseName`) when more than one content type carries a schema, else a single faker.
|
|
126
|
+
function expandContentUnits(
|
|
127
|
+
entries: Array<{ contentType: string; schema?: ast.SchemaNode | null }>,
|
|
128
|
+
baseName: string,
|
|
129
|
+
tsBaseName: string,
|
|
130
|
+
description: string | undefined,
|
|
131
|
+
decorate?: (schema: ast.SchemaNode) => ast.SchemaNode,
|
|
132
|
+
): Array<RenderUnit> {
|
|
133
|
+
const withSchema = entries.filter((entry) => entry.schema)
|
|
134
|
+
if (withSchema.length <= 1) {
|
|
135
|
+
const primary = withSchema[0] ?? entries[0]
|
|
136
|
+
if (!primary?.schema) return []
|
|
137
|
+
return [{ schema: decorate ? decorate(primary.schema) : primary.schema, name: baseName, typeName: tsBaseName, description, skipImportNames: [] }]
|
|
138
|
+
}
|
|
139
|
+
const variants = resolveContentTypeVariants(entries, baseName)
|
|
140
|
+
const unionSchema = ast.createSchema({ type: 'union', members: variants.map((variant) => ast.createSchema({ type: 'ref', name: variant.name })) })
|
|
141
|
+
return [
|
|
142
|
+
...variants.map((variant) => ({
|
|
143
|
+
schema: decorate ? decorate(variant.schema) : variant.schema,
|
|
144
|
+
name: variant.name,
|
|
145
|
+
typeName: getPerContentTypeName(tsBaseName, variant.suffix),
|
|
146
|
+
description,
|
|
147
|
+
skipImportNames: [],
|
|
148
|
+
})),
|
|
149
|
+
{ schema: unionSchema, name: baseName, typeName: tsBaseName, description, skipImportNames: variants.map((variant) => variant.name) },
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const responseUnits = node.responses.flatMap((response) =>
|
|
154
|
+
expandContentUnits(
|
|
155
|
+
response.content ?? [],
|
|
156
|
+
resolver.resolveResponseStatusName(node, response.statusCode),
|
|
157
|
+
tsResolver.resolveResponseStatusName(node, response.statusCode),
|
|
158
|
+
response.description,
|
|
159
|
+
),
|
|
160
|
+
)
|
|
161
|
+
const dataUnits = expandContentUnits(
|
|
162
|
+
node.requestBody?.content ?? [],
|
|
163
|
+
resolver.resolveDataName(node),
|
|
164
|
+
tsResolver.resolveDataName(node),
|
|
165
|
+
node.requestBody?.description,
|
|
166
|
+
(schema) => ({ ...schema, description: node.requestBody?.description ?? schema.description }),
|
|
167
|
+
)
|
|
130
168
|
const responseName = resolver.resolveResponseName(node)
|
|
131
169
|
const localHelperNames = new Set([
|
|
132
170
|
...paramEntries.map((entry) => entry.name),
|
|
133
|
-
...
|
|
134
|
-
...(
|
|
171
|
+
...responseUnits.map((unit) => unit.name),
|
|
172
|
+
...dataUnits.map((unit) => unit.name),
|
|
135
173
|
responseName,
|
|
136
174
|
])
|
|
137
175
|
const cyclicSchemas = new Set<string>(ctx.meta.circularNames)
|
|
@@ -243,27 +281,29 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
243
281
|
typeName,
|
|
244
282
|
}),
|
|
245
283
|
)}
|
|
246
|
-
{
|
|
284
|
+
{responseUnits.map((unit) =>
|
|
247
285
|
renderEntry({
|
|
248
|
-
schema:
|
|
249
|
-
name,
|
|
250
|
-
typeName,
|
|
251
|
-
description:
|
|
286
|
+
schema: unit.schema,
|
|
287
|
+
name: unit.name,
|
|
288
|
+
typeName: unit.typeName,
|
|
289
|
+
description: unit.description,
|
|
290
|
+
skipImportNames: unit.skipImportNames,
|
|
291
|
+
}),
|
|
292
|
+
)}
|
|
293
|
+
{dataUnits.map((unit) =>
|
|
294
|
+
renderEntry({
|
|
295
|
+
schema: unit.schema,
|
|
296
|
+
name: unit.name,
|
|
297
|
+
typeName: unit.typeName,
|
|
298
|
+
description: unit.description,
|
|
299
|
+
skipImportNames: unit.skipImportNames,
|
|
252
300
|
}),
|
|
253
301
|
)}
|
|
254
|
-
{dataEntry
|
|
255
|
-
? renderEntry({
|
|
256
|
-
schema: dataEntry.schema,
|
|
257
|
-
name: dataEntry.name,
|
|
258
|
-
typeName: dataEntry.typeName,
|
|
259
|
-
description: dataEntry.description,
|
|
260
|
-
})
|
|
261
|
-
: null}
|
|
262
302
|
{renderEntry({
|
|
263
303
|
schema: buildResponseUnionSchema(node, resolver),
|
|
264
304
|
name: responseName,
|
|
265
305
|
typeName: tsResolver.resolveResponseName(node),
|
|
266
|
-
skipImportNames:
|
|
306
|
+
skipImportNames: responseUnits.map((unit) => unit.name),
|
|
267
307
|
})}
|
|
268
308
|
</File>
|
|
269
309
|
)
|
package/src/plugin.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { definePlugin
|
|
1
|
+
import { createGroupConfig } from '@internals/shared'
|
|
2
|
+
import { definePlugin } from '@kubb/core'
|
|
3
3
|
import { pluginTsName } from '@kubb/plugin-ts'
|
|
4
4
|
import { fakerGenerator } from './generators/fakerGenerator.tsx'
|
|
5
5
|
import { resolverFaker } from './resolvers/resolverFaker.ts'
|
|
@@ -54,20 +54,7 @@ export const pluginFaker = definePlugin<PluginFaker>((options) => {
|
|
|
54
54
|
transformer: userTransformer,
|
|
55
55
|
} = options
|
|
56
56
|
|
|
57
|
-
const groupConfig = group
|
|
58
|
-
? ({
|
|
59
|
-
...group,
|
|
60
|
-
name: group.name
|
|
61
|
-
? group.name
|
|
62
|
-
: (ctx: { group: string }) => {
|
|
63
|
-
if (group.type === 'path') {
|
|
64
|
-
return `${ctx.group.split('/')[1]}`
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return `${camelCase(ctx.group)}Controller`
|
|
68
|
-
},
|
|
69
|
-
} satisfies Group)
|
|
70
|
-
: null
|
|
57
|
+
const groupConfig = createGroupConfig(group, { suffix: 'Controller', honorName: true })
|
|
71
58
|
|
|
72
59
|
return {
|
|
73
60
|
name: pluginFakerName,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fakerGenerator-BvMBDgwp.js","names":[],"sources":["../../../internals/utils/src/imports.ts","../../../internals/utils/src/object.ts","../../../internals/utils/src/regexp.ts","../src/printers/printerFaker.ts","../src/generators/fakerGenerator.tsx"],"sourcesContent":["export type ImportName = string | { propertyName: string; name?: string }\n\nexport type ImportEntry = {\n name: string | Array<ImportName>\n path: string\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nfunction getImportNames(entry: ImportEntry): Array<string> {\n return (Array.isArray(entry.name) ? entry.name : [entry.name])\n .map((name) => {\n if (typeof name === 'string') {\n return name\n }\n\n return name.name ?? name.propertyName\n })\n .filter((name): name is string => Boolean(name))\n}\n\nexport function filterUsedImports(imports: Array<ImportEntry>, text: string, skipImportNames: Array<string> = []): Array<ImportEntry> {\n return imports.filter((entry) => {\n const names = getImportNames(entry)\n\n return names.some((name) => {\n if (skipImportNames.includes(name)) {\n return false\n }\n\n return new RegExp(`\\\\b${escapeRegExp(name)}\\\\b(?=\\\\s*\\\\()`).test(text)\n })\n })\n}\n\nexport function aliasConflictingImports(\n imports: Array<ImportEntry>,\n reservedNames: Iterable<string>,\n): { imports: Array<ImportEntry>; aliases: Map<string, string> } {\n const reservedNameSet = new Set(reservedNames)\n const aliases = new Map<string, string>()\n\n const aliasedImports = imports.map((entry) => {\n const names = Array.isArray(entry.name) ? entry.name : [entry.name]\n const aliasedNames = names.map((item): ImportName => {\n if (typeof item !== 'string' || !reservedNameSet.has(item)) {\n return item\n }\n\n const alias = `${item}Schema`\n aliases.set(item, alias)\n\n return { propertyName: item, name: alias }\n })\n\n return aliasedNames.some((item) => typeof item === 'object' && item.name)\n ? {\n ...entry,\n name: aliasedNames,\n }\n : entry\n })\n\n return {\n imports: aliasedImports,\n aliases,\n }\n}\n\nexport function rewriteAliasedImports(text: string, aliases: ReadonlyMap<string, string>): string {\n return Array.from(aliases).reduce((acc, [name, alias]) => acc.replace(new RegExp(`\\\\b${escapeRegExp(name)}\\\\b`, 'g'), alias), text)\n}\n","import { trimQuotes } from './string.ts'\n\n/**\n * Serializes a primitive value to a JSON string literal, stripping any surrounding quote characters first.\n *\n * @example\n * stringify('hello') // '\"hello\"'\n * stringify('\"hello\"') // '\"hello\"'\n */\nexport function stringify(value: string | number | boolean | undefined): string {\n if (value === undefined || value === null) return '\"\"'\n return JSON.stringify(trimQuotes(value.toString()))\n}\n\n/**\n * Converts a plain object into a multiline key-value string suitable for embedding in generated code.\n * Nested objects are recursively stringified with indentation.\n *\n * @example\n * stringifyObject({ foo: 'bar', nested: { a: 1 } })\n * // 'foo: bar,\\nnested: {\\n a: 1\\n }'\n */\nexport function stringifyObject(value: Record<string, unknown>): string {\n const items = Object.entries(value)\n .map(([key, val]) => {\n if (val !== null && typeof val === 'object') {\n return `${key}: {\\n ${stringifyObject(val as Record<string, unknown>)}\\n }`\n }\n return `${key}: ${val}`\n })\n .filter(Boolean)\n return items.join(',\\n')\n}\n\n/**\n * Converts a dot-notation path or string array into an optional-chaining accessor expression.\n *\n * @example\n * getNestedAccessor('pagination.next.id', 'lastPage')\n * // → \"lastPage?.['pagination']?.['next']?.['id']\"\n */\nexport function getNestedAccessor(param: string | string[], accessor: string): string | null {\n const parts = Array.isArray(param) ? param : param.split('.')\n if (parts.length === 0 || (parts.length === 1 && parts[0] === '')) return null\n return `${accessor}?.['${`${parts.join(\"']?.['\")}']`}`\n}\n","import { trimQuotes } from './string.ts'\n\n/**\n * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.\n * Inline flags expressed as `^(?im)` prefixes are extracted and applied to the resulting expression.\n * Pass `null` as the second argument to emit a `/pattern/flags` literal instead.\n *\n * @example\n * toRegExpString('^(?im)foo') // → 'new RegExp(\"foo\", \"im\")'\n * toRegExpString('^(?im)foo', null) // → '/foo/im'\n */\nexport function toRegExpString(text: string, func: string | null = 'RegExp'): string {\n const raw = trimQuotes(text)\n\n const match = raw.match(/^\\^(\\(\\?([igmsuy]+)\\))/i)\n const replacementTarget = match?.[1] ?? ''\n const matchedFlags = match?.[2]\n const cleaned = raw\n .replace(/^\\\\?\\//, '')\n .replace(/\\\\?\\/$/, '')\n .replace(replacementTarget, '')\n\n const { source, flags } = new RegExp(cleaned, matchedFlags)\n\n if (func === null) return `/${source}/${flags}`\n\n return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ''})`\n}\n","import { stringify, toRegExpString } from '@internals/utils'\nimport { ast } from '@kubb/core'\nimport type { PluginFaker, ResolverFaker } from '../types.ts'\n\n/**\n * Partial map of node-type overrides for the Faker printer. Each key is a\n * `SchemaType` (`'string'`, `'date'`, ...) and each handler returns the\n * Faker expression for that schema as a string. Use `this.transform` to\n * recurse into nested schema nodes and `this.options` to read printer options.\n *\n * @example Override the integer handler\n * ```ts\n * pluginFaker({\n * printer: {\n * nodes: {\n * integer() {\n * return 'faker.number.float()'\n * },\n * },\n * },\n * })\n * ```\n */\nexport type PrinterFakerNodes = ast.PrinterPartial<string, PrinterFakerOptions>\n\n/**\n * Options passed to the Faker printer at instantiation: the parser library\n * for date strings, the regex generator, the user-supplied schema-name\n * mapper, and the resolver used to compute identifiers.\n */\nexport type PrinterFakerOptions = {\n dateParser?: PluginFaker['resolvedOptions']['dateParser']\n regexGenerator?: PluginFaker['resolvedOptions']['regexGenerator']\n mapper?: PluginFaker['resolvedOptions']['mapper']\n resolver: ResolverFaker\n typeName?: string\n schemaName?: string\n nestedInObject?: boolean\n /**\n * Set while printing the members of a union (`oneOf`). Object properties then index their\n * type as `(NonNullable<T> & Record<K, unknown>)[K]` instead of `NonNullable<T>[K]`, so a key\n * carried by only some branches stays valid (a plain index would be a TS2339).\n */\n nestedInUnion?: boolean\n nodes?: PrinterFakerNodes\n /**\n * Names of schemas that participate in a circular dependency chain.\n * Properties whose schema transitively references one of these are emitted\n * as lazy getters so that user overrides via the `data` parameter prevent\n * the recursive faker call from ever executing (avoiding stack overflow).\n */\n cyclicSchemas?: ReadonlySet<string>\n}\n\n/**\n * Factory options for the Faker printer, defining input/output types and configuration.\n */\nexport type PrinterFakerFactory = ast.PrinterFactoryOptions<'faker', PrinterFakerOptions, string, string>\n\nconst fakerKeywordMapper = {\n any: () => 'undefined',\n unknown: () => 'undefined',\n void: () => 'undefined',\n number: (min?: number, max?: number) => {\n if (max !== undefined && min !== undefined) {\n return `faker.number.float({ min: ${min}, max: ${max} })`\n }\n\n if (max !== undefined) {\n return `faker.number.float({ max: ${max} })`\n }\n\n if (min !== undefined) {\n return `faker.number.float({ min: ${min} })`\n }\n\n return 'faker.number.float()'\n },\n integer: (min?: number, max?: number) => {\n if (max !== undefined && min !== undefined) {\n return `faker.number.int({ min: ${min}, max: ${max} })`\n }\n\n if (max !== undefined) {\n return `faker.number.int({ max: ${max} })`\n }\n\n if (min !== undefined) {\n return `faker.number.int({ min: ${min} })`\n }\n\n return 'faker.number.int()'\n },\n bigint: () => 'faker.number.bigInt()',\n string: (min?: number, max?: number) => {\n if (max !== undefined && min !== undefined) {\n return `faker.string.alpha({ length: { min: ${min}, max: ${max} } })`\n }\n\n if (max !== undefined) {\n return `faker.string.alpha({ length: ${max} })`\n }\n\n if (min !== undefined) {\n return `faker.string.alpha({ length: ${min} })`\n }\n\n return 'faker.string.alpha()'\n },\n boolean: () => 'faker.datatype.boolean()',\n null: () => 'null',\n array: (items: Array<string> = [], min?: number, max?: number) => {\n if (items.length > 1) {\n return `faker.helpers.arrayElements([${items.join(', ')}])`\n }\n\n const item = items.at(0)\n\n if (min !== undefined && max !== undefined) {\n return `faker.helpers.multiple(() => (${item}), { count: { min: ${min}, max: ${max} }})`\n }\n\n if (min !== undefined) {\n return `faker.helpers.multiple(() => (${item}), { count: ${min} })`\n }\n\n if (max !== undefined) {\n return `faker.helpers.multiple(() => (${item}), { count: { min: 0, max: ${max} }})`\n }\n\n return `faker.helpers.multiple(() => (${item}))`\n },\n tuple: (items: Array<string> = []) => `[${items.join(', ')}]`,\n enum: (items: Array<string | number | boolean | undefined> = [], type = 'any') => `faker.helpers.arrayElement<${type}>([${items.join(', ')}])`,\n union: (items: Array<string> = []) => `faker.helpers.arrayElement<any>([${items.join(', ')}])`,\n datetime: () => 'faker.date.anytime().toISOString()',\n date: (representation: 'date' | 'string' = 'string', parser: PluginFaker['resolvedOptions']['dateParser'] = 'faker') => {\n if (representation === 'string') {\n if (parser !== 'faker') {\n return `${parser}(faker.date.anytime()).format(\"YYYY-MM-DD\")`\n }\n\n return 'faker.date.anytime().toISOString().substring(0, 10)'\n }\n\n if (parser !== 'faker') {\n throw new Error(`type '${representation}' and parser '${parser}' can not work together`)\n }\n\n return 'faker.date.anytime()'\n },\n time: (representation: 'date' | 'string' = 'string', parser: PluginFaker['resolvedOptions']['dateParser'] = 'faker') => {\n if (representation === 'string') {\n if (parser !== 'faker') {\n return `${parser}(faker.date.anytime()).format(\"HH:mm:ss\")`\n }\n\n return 'faker.date.anytime().toISOString().substring(11, 19)'\n }\n\n if (parser !== 'faker') {\n throw new Error(`type '${representation}' and parser '${parser}' can not work together`)\n }\n\n return 'faker.date.anytime()'\n },\n uuid: () => 'faker.string.uuid()',\n url: () => 'faker.internet.url()',\n and: (items: Array<string> = []) => {\n if (items.length === 0) {\n return '{}'\n }\n\n if (items.length === 1) {\n return items[0] ?? '{}'\n }\n\n return `{...${items.join(', ...')}}`\n },\n matches: (value = '', regexGenerator: 'faker' | 'randexp' = 'faker') => {\n if (regexGenerator === 'randexp') {\n return `${toRegExpString(value, 'RandExp')}.gen()`\n }\n\n return `faker.helpers.fromRegExp(\"${value}\")`\n },\n email: () => 'faker.internet.email()',\n blob: () => 'faker.image.url() as unknown as Blob',\n} as const\n\nfunction getEnumValues(node: ast.EnumSchemaNode): Array<string | number | boolean | undefined> {\n if (node.namedEnumValues?.length) {\n return node.namedEnumValues.map((item) => item.value as string | number | boolean | undefined)\n }\n\n return (node.enumValues ?? []) as Array<string | number | boolean | undefined>\n}\n\nfunction parseEnumValue(value: string | number | boolean | undefined) {\n if (typeof value === 'string') {\n return stringify(value)\n }\n\n return value\n}\n\n/** Reads the discriminator literal off a variant, or `undefined` when it can't be determined. */\nfunction getDiscriminatorValue(member: ast.SchemaNode, discriminatorPropertyName: string) {\n const prop = ast.narrowSchema(member, 'object')?.properties?.find((p) => p.name === discriminatorPropertyName)\n const enumNode = prop ? ast.narrowSchema(prop.schema, 'enum') : null\n\n return enumNode ? getEnumValues(enumNode)[0] : undefined\n}\n\n/**\n * Type expression for an object property's value, indexed off the parent `typeName`.\n *\n * In a union (`oneOf`), a key that only some branches declare turns a plain `NonNullable<T>[K]`\n * into a TS2339 error, so union members guard the access. The breakdown is below.\n */\nfunction indexedTypeName(typeName: string, propertyName: string, nestedInUnion?: boolean): string {\n const key = JSON.stringify(propertyName)\n\n // `(NonNullable<T> & Record<K, unknown>)[K]`, read inside-out:\n // NonNullable<T> strips null and undefined from the parent type T.\n // & Record<K, unknown> forces every branch to have key K. A branch that already declares K\n // keeps it (`T[K] & unknown` is `T[K]`); a branch missing K gains it as `unknown`.\n // [K] reads the key, which is now always present, so it never hits TS2339.\n // For a single object T the intersection does nothing, leaving `T[K]`.\n return nestedInUnion ? `(NonNullable<${typeName}> & Record<${key}, unknown>)[${key}]` : `NonNullable<${typeName}>[${key}]`\n}\n\n/**\n * Creates a Faker printer that generates mock data generation code from schema nodes.\n * Handles circular references gracefully by emitting memoizing getters for cyclic properties.\n */\nexport const printerFaker: (options: PrinterFakerOptions) => ast.Printer<PrinterFakerFactory> = ast.definePrinter<PrinterFakerFactory>((options) => {\n const printNested = (node: ast.SchemaNode, overrideOptions: Partial<PrinterFakerOptions> = {}): string => {\n return (\n printerFaker({\n ...options,\n ...overrideOptions,\n nodes: options.nodes,\n }).print(node) ?? 'undefined'\n )\n }\n\n return {\n name: 'faker',\n options,\n nodes: {\n any: () => fakerKeywordMapper.any(),\n unknown: () => fakerKeywordMapper.unknown(),\n void: () => fakerKeywordMapper.void(),\n boolean: () => fakerKeywordMapper.boolean(),\n null: () => fakerKeywordMapper.null(),\n string(node) {\n if (node.pattern) {\n return fakerKeywordMapper.matches(node.pattern, this.options.regexGenerator)\n }\n\n return fakerKeywordMapper.string(node.min, node.max)\n },\n email: () => fakerKeywordMapper.email(),\n url: () => fakerKeywordMapper.url(),\n uuid: () => fakerKeywordMapper.uuid(),\n number(node) {\n return fakerKeywordMapper.number(node.min, node.max)\n },\n integer(node) {\n return fakerKeywordMapper.integer(node.min, node.max)\n },\n bigint: () => fakerKeywordMapper.bigint(),\n blob: () => fakerKeywordMapper.blob(),\n datetime: () => fakerKeywordMapper.datetime(),\n date(node) {\n return fakerKeywordMapper.date(node.representation ?? 'string', this.options.dateParser)\n },\n time(node) {\n return fakerKeywordMapper.time(node.representation ?? 'string', this.options.dateParser)\n },\n ref(node) {\n // Parser-generated refs (with $ref) carry raw schema names that need resolving.\n // Use the canonical name from the $ref path — node.name may have been overridden\n // (e.g. by single-member allOf flatten using the property-derived child name).\n // Inline refs (without $ref) from faker utils already carry resolved helper names.\n const refName = node.ref ? (ast.extractRefName(node.ref) ?? node.name ?? node.schema?.name) : (node.name ?? node.schema?.name)\n\n if (!refName) {\n throw new Error('Name not defined for ref node')\n }\n\n if (this.options.schemaName && refName === this.options.schemaName) {\n return 'undefined as any'\n }\n\n // Internal helper refs (for generated response/data helpers) are already\n // emitted with resolver output and should not be transformed twice.\n const resolvedName = node.ref ? this.options.resolver.resolveName(refName) : refName\n\n if (!this.options.nestedInObject) {\n return `${resolvedName}(data)`\n }\n\n return `${resolvedName}()`\n },\n enum(node) {\n return fakerKeywordMapper.enum(getEnumValues(node).map(parseEnumValue), this.options.typeName)\n },\n union(node): string {\n const { discriminatorPropertyName } = node\n const baseTypeName = this.options.typeName\n\n const items: Array<string> = (node.members ?? [])\n .map((member) => {\n // For a discriminated union, narrow each variant to its own branch so nested\n // `NonNullable<T>[K]` indexes resolve against that branch instead of the whole union.\n const value = discriminatorPropertyName ? getDiscriminatorValue(member, discriminatorPropertyName) : undefined\n\n if (baseTypeName && value !== undefined) {\n const typeName = `Extract<NonNullable<${baseTypeName}>, { ${JSON.stringify(discriminatorPropertyName)}: ${parseEnumValue(value)} }>`\n\n return printNested(member, { typeName, nestedInObject: true })\n }\n\n // Without a discriminator, keep the union type but guard each indexed access (see\n // `indexedTypeName`) so a key carried by only some branches resolves to `unknown`\n // rather than erroring with TS2339.\n return printNested(member, { typeName: baseTypeName, nestedInObject: true, nestedInUnion: true })\n })\n .filter((item): item is string => Boolean(item))\n\n return fakerKeywordMapper.union(items)\n },\n intersection(node): string {\n const items: Array<string> = (node.members ?? [])\n .map((member) =>\n printNested(member, {\n nestedInObject: true,\n }),\n )\n .filter((item): item is string => Boolean(item))\n\n return fakerKeywordMapper.and(items)\n },\n array(node): string {\n const items: Array<string> = (node.items ?? [])\n .map((member) =>\n printNested(member, {\n typeName: this.options.typeName ? `NonNullable<${this.options.typeName}>[number]` : undefined,\n nestedInObject: true,\n }),\n )\n .filter((item): item is string => Boolean(item))\n\n return fakerKeywordMapper.array(items, node.min, node.max)\n },\n tuple(node): string {\n const items: Array<string> = (node.items ?? [])\n .map((member, index) =>\n printNested(member, {\n typeName: this.options.typeName ? `NonNullable<${this.options.typeName}>[${index}]` : undefined,\n nestedInObject: true,\n }),\n )\n .filter((item): item is string => Boolean(item))\n\n return fakerKeywordMapper.tuple(items)\n },\n object(node): string {\n const cyclicSchemas = this.options.cyclicSchemas\n const properties = (node.properties ?? [])\n .map((property): string => {\n if (this.options.mapper && Object.hasOwn(this.options.mapper, property.name)) {\n return `\"${property.name}\": ${this.options.mapper[property.name]}`\n }\n\n const value: string =\n printNested(property.schema, {\n typeName: this.options.typeName ? indexedTypeName(this.options.typeName, property.name, this.options.nestedInUnion) : undefined,\n nestedInObject: true,\n }) ?? 'undefined'\n\n // When the property's schema transitively references a schema that is\n // part of a circular dependency (other than the current schema itself),\n // emit a memoizing lazy getter. On first access it computes the value,\n // replaces itself with a plain data property via Object.defineProperty,\n // and returns the cached value – so every subsequent read is stable.\n if (cyclicSchemas && ast.containsCircularRef(property.schema, { circularSchemas: cyclicSchemas, excludeName: this.options.schemaName })) {\n return `get ${property.name}() { const _value = ${value}; Object.defineProperty(this, ${JSON.stringify(property.name)}, { value: _value, configurable: true, writable: true, enumerable: true }); return _value }`\n }\n\n return `\"${property.name}\": ${value}`\n })\n .join(',')\n\n return `{${properties}}`\n },\n ...options.nodes,\n },\n print(node) {\n return this.transform(node) ?? null\n },\n }\n})\n","import { aliasConflictingImports, filterUsedImports, rewriteAliasedImports } from '@internals/utils'\nimport { ast, defineGenerator } from '@kubb/core'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { File, jsxRendererSync } from '@kubb/renderer-jsx'\nimport { Faker } from '../components/Faker.tsx'\nimport { printerFaker } from '../printers/printerFaker.ts'\nimport type { PluginFaker } from '../types.ts'\nimport { buildResponseUnionSchema, canOverrideSchema, localeToFakerImport, resolveParamNameByLocation, resolveTypeReference } from '../utils.ts'\n\n/**\n * Built-in generator for `@kubb/plugin-faker`. Emits one `createX` factory\n * per schema in the spec plus per-operation request/response factories. Each\n * factory returns a value matching the corresponding TypeScript type from\n * `@kubb/plugin-ts`.\n */\nexport const fakerGenerator = defineGenerator<PluginFaker>({\n name: 'faker',\n renderer: jsxRendererSync,\n schema(node, ctx) {\n const { adapter, config, resolver, root } = ctx\n const { output, group, dateParser, regexGenerator, mapper, seed, locale, printer } = ctx.options\n const pluginTs = ctx.driver.getPlugin(pluginTsName)\n\n if (!node.name || !pluginTs) {\n return\n }\n\n const tsResolver = ctx.driver.getResolver(pluginTsName)\n\n const schemaName = node.name\n const mode = ctx.getMode(output)\n const meta = {\n name: resolver.resolveName(schemaName),\n file: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group: group ?? undefined }),\n typeName: tsResolver.resolveTypeName(schemaName),\n typeFile: tsResolver.resolveFile(\n { name: schemaName, extname: '.ts' },\n { root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group ?? undefined },\n ),\n } as const\n const canOverride = canOverrideSchema(node)\n const cyclicSchemas = new Set<string>(ctx.meta.circularNames)\n const printerInstance = printerFaker({\n resolver,\n schemaName,\n typeName: meta.typeName,\n dateParser,\n regexGenerator,\n mapper,\n nodes: printer?.nodes,\n cyclicSchemas,\n })\n const fakerText = printerInstance.print(node) ?? 'undefined'\n const typeReference = resolveTypeReference({\n node,\n canOverride,\n name: meta.name,\n typeName: meta.typeName,\n filePath: meta.file.path,\n typeFilePath: meta.typeFile.path,\n })\n\n const imports = adapter\n .getImports(node, (schemaName) => ({\n name: resolver.resolveName(schemaName),\n path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group: group ?? undefined }).path,\n }))\n .filter((entry) => entry.path !== meta.file.path)\n const usedImports = filterUsedImports(imports, fakerText)\n\n return (\n <File\n baseName={meta.file.baseName}\n path={meta.file.path}\n meta={meta.file.meta}\n banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}\n footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}\n >\n <File.Import name={locale ? [{ propertyName: localeToFakerImport(locale), name: 'faker' }] : ['faker']} path=\"@faker-js/faker\" />\n {regexGenerator === 'randexp' && <File.Import name={'RandExp'} path={'randexp'} />}\n {dateParser !== 'faker' && <File.Import path={dateParser} name={dateParser} />}\n {typeReference.importPath && <File.Import isTypeOnly root={meta.file.path} path={typeReference.importPath} name={[meta.typeName]} />}\n {mode === 'split' &&\n usedImports.map((imp) => <File.Import key={[schemaName, imp.path, imp.name].join('-')} root={meta.file.path} path={imp.path} name={imp.name} />)}\n <Faker\n name={meta.name}\n typeName={typeReference.typeName}\n description={node.description}\n node={node}\n printer={printerInstance}\n seed={seed}\n canOverride={canOverride}\n />\n </File>\n )\n },\n operation(node, ctx) {\n const { adapter, config, resolver, root } = ctx\n const { output, group, paramsCasing, dateParser, regexGenerator, mapper, seed, locale, printer } = ctx.options\n const pluginTs = ctx.driver.getPlugin(pluginTsName)\n\n if (!pluginTs) {\n return\n }\n\n const tsResolver = ctx.driver.getResolver(pluginTsName)\n\n const params = ast.caseParams(node.parameters, paramsCasing)\n const paramEntries = params.map((param) => ({\n param,\n name: resolveParamNameByLocation(resolver, node, param),\n typeName: resolveParamNameByLocation(tsResolver, node, param),\n }))\n const responseEntries = node.responses.map((response) => ({\n response,\n name: resolver.resolveResponseStatusName(node, response.statusCode),\n typeName: tsResolver.resolveResponseStatusName(node, response.statusCode),\n }))\n const dataEntry = node.requestBody?.content?.[0]?.schema\n ? {\n schema: {\n ...node.requestBody.content![0]!.schema!,\n description: node.requestBody.description ?? node.requestBody.content![0]!.schema!.description,\n },\n name: resolver.resolveDataName(node),\n typeName: tsResolver.resolveDataName(node),\n description: node.requestBody.description ?? node.requestBody.content![0]!.schema!.description,\n }\n : null\n const responseName = resolver.resolveResponseName(node)\n const localHelperNames = new Set([\n ...paramEntries.map((entry) => entry.name),\n ...responseEntries.map((entry) => entry.name),\n ...(dataEntry ? [dataEntry.name] : []),\n responseName,\n ])\n const cyclicSchemas = new Set<string>(ctx.meta.circularNames)\n\n const meta = {\n file: resolver.resolveFile(\n { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },\n { root, output, group: group ?? undefined },\n ),\n typeFile: tsResolver.resolveFile(\n {\n name: node.operationId,\n extname: '.ts',\n tag: node.tags[0] ?? 'default',\n path: node.path,\n },\n {\n root,\n output: pluginTs.options?.output ?? output,\n group: pluginTs.options?.group ?? undefined,\n },\n ),\n } as const\n\n function resolveMockImports(schema: ast.SchemaNode) {\n return adapter\n .getImports(schema, (schemaName) => ({\n name: resolver.resolveName(schemaName),\n path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group: group ?? undefined }).path,\n }))\n .filter((entry) => entry.path !== meta.file.path)\n }\n\n function renderEntry({\n schema,\n name,\n typeName,\n description,\n skipImportNames = [],\n }: {\n schema: ast.SchemaNode | null\n name: string\n typeName: string\n description?: string\n skipImportNames?: Array<string>\n }) {\n if (!schema) {\n return null\n }\n\n const canOverride = canOverrideSchema(schema)\n const printerInstance = printerFaker({\n resolver,\n schemaName: name,\n typeName,\n dateParser,\n regexGenerator,\n mapper,\n nodes: printer?.nodes,\n cyclicSchemas,\n })\n const fakerText = printerInstance.print(schema) ?? 'undefined'\n const usedImports = filterUsedImports(resolveMockImports(schema), fakerText, skipImportNames)\n const { imports, aliases } = aliasConflictingImports(usedImports, localHelperNames)\n const rewrittenFakerText = rewriteAliasedImports(fakerText, aliases)\n const typeReference = resolveTypeReference({\n node: schema,\n canOverride,\n name,\n typeName,\n filePath: meta.file.path,\n typeFilePath: meta.typeFile.path,\n })\n\n return (\n <>\n {typeReference.importPath && <File.Import isTypeOnly root={meta.file.path} path={typeReference.importPath} name={[typeName]} />}\n {imports.map((imp) => (\n <File.Import key={[name, imp.path, imp.name].join('-')} root={meta.file.path} path={imp.path} name={imp.name} />\n ))}\n <Faker\n name={name}\n typeName={typeReference.typeName}\n description={description}\n node={schema}\n printer={{ ...printerInstance, print: () => rewrittenFakerText }}\n seed={seed}\n canOverride={canOverride}\n />\n </>\n )\n }\n\n return (\n <File\n baseName={meta.file.baseName}\n path={meta.file.path}\n meta={meta.file.meta}\n banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}\n footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}\n >\n <File.Import name={locale ? [{ propertyName: localeToFakerImport(locale), name: 'faker' }] : ['faker']} path=\"@faker-js/faker\" />\n {regexGenerator === 'randexp' && <File.Import name={'RandExp'} path={'randexp'} />}\n {dateParser !== 'faker' && <File.Import path={dateParser} name={dateParser} />}\n {paramEntries.map(({ param, name, typeName }) =>\n renderEntry({\n schema: param.schema,\n name,\n typeName,\n }),\n )}\n {responseEntries.map(({ response, name, typeName }) =>\n renderEntry({\n schema: response.content?.[0]?.schema ?? null,\n name,\n typeName,\n description: response.description,\n }),\n )}\n {dataEntry\n ? renderEntry({\n schema: dataEntry.schema,\n name: dataEntry.name,\n typeName: dataEntry.typeName,\n description: dataEntry.description,\n })\n : null}\n {renderEntry({\n schema: buildResponseUnionSchema(node, resolver),\n name: responseName,\n typeName: tsResolver.resolveResponseName(node),\n skipImportNames: responseEntries.map(({ name }) => name),\n })}\n </File>\n )\n },\n})\n"],"mappings":"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"}
|