@kubb/plugin-faker 5.0.0-beta.3 → 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/README.md +26 -5
- package/dist/{Faker-CdyPfOPg.d.ts → Faker-BaLJxPyl.d.ts} +2 -2
- package/dist/{Faker-fcQEB9i5.js → Faker-DwIc_lta.js} +38 -100
- package/dist/Faker-DwIc_lta.js.map +1 -0
- package/dist/{Faker-BgleOzVN.cjs → Faker-XuyEQflW.cjs} +37 -123
- package/dist/Faker-XuyEQflW.cjs.map +1 -0
- package/dist/components.cjs +1 -1
- package/dist/components.d.ts +1 -1
- package/dist/components.js +1 -1
- package/dist/{fakerGenerator-VJEVzLjc.cjs → fakerGenerator-BBr2WsG8.cjs} +236 -60
- package/dist/fakerGenerator-BBr2WsG8.cjs.map +1 -0
- package/dist/{fakerGenerator-D7daHCh6.js → fakerGenerator-BDNxA7KY.js} +235 -59
- package/dist/fakerGenerator-BDNxA7KY.js.map +1 -0
- package/dist/fakerGenerator-DSvAJTq3.d.ts +15 -0
- package/dist/generators.cjs +1 -1
- package/dist/generators.d.ts +1 -1
- package/dist/generators.js +1 -1
- package/dist/index.cjs +213 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +33 -12
- package/dist/index.js +214 -43
- package/dist/index.js.map +1 -1
- package/dist/{printerFaker-CJiwzoto.d.ts → printerFaker-Bhwq62d1.d.ts} +63 -26
- package/extension.yaml +817 -0
- package/package.json +9 -13
- package/src/components/Faker.tsx +50 -64
- package/src/generators/fakerGenerator.tsx +107 -67
- package/src/plugin.ts +25 -21
- package/src/printers/printerFaker.ts +80 -16
- package/src/resolvers/resolverFaker.ts +29 -37
- package/src/types.ts +36 -23
- package/src/utils.ts +6 -105
- package/dist/Faker-BgleOzVN.cjs.map +0 -1
- package/dist/Faker-fcQEB9i5.js.map +0 -1
- package/dist/fakerGenerator-C3Ho3BaI.d.ts +0 -9
- package/dist/fakerGenerator-D7daHCh6.js.map +0 -1
- package/dist/fakerGenerator-VJEVzLjc.cjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/plugin-faker",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
4
|
-
"description": "Faker.js data
|
|
3
|
+
"version": "5.0.0-beta.31",
|
|
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
|
-
"code-
|
|
6
|
+
"code-generation",
|
|
7
7
|
"codegen",
|
|
8
|
-
"data-generation",
|
|
9
|
-
"development",
|
|
10
8
|
"faker",
|
|
11
9
|
"faker.js",
|
|
12
10
|
"fakerjs",
|
|
@@ -14,11 +12,8 @@
|
|
|
14
12
|
"kubb",
|
|
15
13
|
"mock-data",
|
|
16
14
|
"mocks",
|
|
17
|
-
"oas",
|
|
18
15
|
"openapi",
|
|
19
|
-
"plugins",
|
|
20
16
|
"swagger",
|
|
21
|
-
"testing",
|
|
22
17
|
"typescript"
|
|
23
18
|
],
|
|
24
19
|
"license": "MIT",
|
|
@@ -31,7 +26,7 @@
|
|
|
31
26
|
"files": [
|
|
32
27
|
"src",
|
|
33
28
|
"dist",
|
|
34
|
-
"
|
|
29
|
+
"extension.yaml",
|
|
35
30
|
"!/**/**.test.**",
|
|
36
31
|
"!/**/__tests__/**",
|
|
37
32
|
"!/**/__snapshots__/**"
|
|
@@ -71,15 +66,16 @@
|
|
|
71
66
|
"registry": "https://registry.npmjs.org/"
|
|
72
67
|
},
|
|
73
68
|
"dependencies": {
|
|
74
|
-
"@kubb/core": "5.0.0-beta.
|
|
75
|
-
"@kubb/renderer-jsx": "5.0.0-beta.
|
|
76
|
-
"@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"
|
|
77
72
|
},
|
|
78
73
|
"devDependencies": {
|
|
74
|
+
"@internals/shared": "0.0.0",
|
|
79
75
|
"@internals/utils": "0.0.0"
|
|
80
76
|
},
|
|
81
77
|
"peerDependencies": {
|
|
82
|
-
"@kubb/renderer-jsx": "5.0.0-beta.
|
|
78
|
+
"@kubb/renderer-jsx": "5.0.0-beta.31"
|
|
83
79
|
},
|
|
84
80
|
"size-limit": [
|
|
85
81
|
{
|
package/src/components/Faker.tsx
CHANGED
|
@@ -44,71 +44,17 @@ export function Faker({ node, description, name, typeName, printer, seed, canOve
|
|
|
44
44
|
const isTuple = node.type === 'tuple'
|
|
45
45
|
const isScalar = SCALAR_TYPES.has(node.type)
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (canOverride && isTuple) {
|
|
55
|
-
fakerTextWithOverride = `data || ${fakerText}`
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (canOverride && isArray) {
|
|
59
|
-
fakerTextWithOverride = `[
|
|
60
|
-
...${fakerText},
|
|
61
|
-
...(data || [])
|
|
62
|
-
]`
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (canOverride && isScalar) {
|
|
66
|
-
fakerTextWithOverride = `data ?? ${fakerText}`
|
|
67
|
-
}
|
|
47
|
+
const useGenericOverride = canOverride && isObject
|
|
48
|
+
const fakerTextWithOverride = (() => {
|
|
49
|
+
if (canOverride && isTuple) return `data || ${fakerText}`
|
|
50
|
+
if (canOverride && isArray) return `[\n ...${fakerText},\n ...(data || [])\n]`
|
|
51
|
+
if (canOverride && isScalar) return `data ?? ${fakerText}`
|
|
52
|
+
return fakerText
|
|
53
|
+
})()
|
|
68
54
|
|
|
69
55
|
const { dataType, returnType: resolvedReturnType } = resolveFakerTypeUsage(node, typeName, canOverride)
|
|
70
56
|
|
|
71
|
-
|
|
72
|
-
let functionBody = ''
|
|
73
|
-
|
|
74
|
-
if (useGenericOverride) {
|
|
75
|
-
// Generate function with defaultFakeData structure
|
|
76
|
-
const jsdoc = description ? `/**\n * @description ${jsStringEscape(description)}\n */\n ` : ''
|
|
77
|
-
functionSignature = `${jsdoc}export function ${name}(data?: Partial<${typeName}>): Required<${typeName}>`
|
|
78
|
-
|
|
79
|
-
const seedCode = seed ? `faker.seed(${JSON.stringify(seed)})\n ` : ''
|
|
80
|
-
|
|
81
|
-
// When the object node has properties that transitively reference a cyclic schema,
|
|
82
|
-
// the printer emits memoizing getters for those properties. Spreading the object
|
|
83
|
-
// literal would immediately invoke those getters, triggering recursive faker calls
|
|
84
|
-
// and causing a stack overflow. Detect this upfront via ast helpers so we can
|
|
85
|
-
// use Object.defineProperty-based merging instead of spread.
|
|
86
|
-
const { cyclicSchemas, schemaName } = printer.options
|
|
87
|
-
const hasGetters =
|
|
88
|
-
node.type === 'object' &&
|
|
89
|
-
!!cyclicSchemas &&
|
|
90
|
-
(node.properties ?? []).some((p) => ast.containsCircularRef(p.schema, { circularSchemas: cyclicSchemas, excludeName: schemaName }))
|
|
91
|
-
|
|
92
|
-
if (hasGetters) {
|
|
93
|
-
functionBody = `{
|
|
94
|
-
${seedCode}const defaultFakeData = ${fakerText}
|
|
95
|
-
if (data) {
|
|
96
|
-
for (const [key, value] of Object.entries(data)) {
|
|
97
|
-
Object.defineProperty(defaultFakeData, key, { value, configurable: true, writable: true, enumerable: true })
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return defaultFakeData as Required<${typeName}>
|
|
101
|
-
}`
|
|
102
|
-
} else {
|
|
103
|
-
functionBody = `{
|
|
104
|
-
${seedCode}const defaultFakeData = ${fakerText}
|
|
105
|
-
return {
|
|
106
|
-
...defaultFakeData,
|
|
107
|
-
...(data || {}),
|
|
108
|
-
} as Required<${typeName}>
|
|
109
|
-
}`
|
|
110
|
-
}
|
|
111
|
-
} else {
|
|
57
|
+
if (!useGenericOverride) {
|
|
112
58
|
const usesData = /\bdata\b/.test(fakerTextWithOverride)
|
|
113
59
|
const dataParamName = usesData ? 'data' : '_data'
|
|
114
60
|
const params = ast.createFunctionParameters({
|
|
@@ -123,6 +69,11 @@ export function Faker({ node, description, name, typeName, printer, seed, canOve
|
|
|
123
69
|
const paramsSignature = declarationPrinter.print(params) ?? ''
|
|
124
70
|
const returnType = resolvedReturnType
|
|
125
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
|
+
|
|
126
77
|
return (
|
|
127
78
|
<File.Source name={name} isExportable isIndexable>
|
|
128
79
|
<Function
|
|
@@ -130,7 +81,7 @@ export function Faker({ node, description, name, typeName, printer, seed, canOve
|
|
|
130
81
|
name={name}
|
|
131
82
|
JSDoc={{ comments: description ? [`@description ${jsStringEscape(description)}`] : [] }}
|
|
132
83
|
params={canOverride ? paramsSignature : undefined}
|
|
133
|
-
returnType={returnType}
|
|
84
|
+
returnType={returnType ?? undefined}
|
|
134
85
|
>
|
|
135
86
|
{seed ? (
|
|
136
87
|
<>
|
|
@@ -138,12 +89,47 @@ export function Faker({ node, description, name, typeName, printer, seed, canOve
|
|
|
138
89
|
<br />
|
|
139
90
|
</>
|
|
140
91
|
) : undefined}
|
|
141
|
-
{`return ${
|
|
92
|
+
{`return ${returnExpression}`}
|
|
142
93
|
</Function>
|
|
143
94
|
</File.Source>
|
|
144
95
|
)
|
|
145
96
|
}
|
|
146
97
|
|
|
98
|
+
// Generate function with defaultFakeData structure
|
|
99
|
+
const jsdoc = description ? `/**\n * @description ${jsStringEscape(description)}\n */\n ` : ''
|
|
100
|
+
const functionSignature = `${jsdoc}export function ${name}<TData extends Partial<${typeName}> = object>(data?: TData)`
|
|
101
|
+
|
|
102
|
+
const seedCode = seed ? `faker.seed(${JSON.stringify(seed)})\n ` : ''
|
|
103
|
+
|
|
104
|
+
// When the object node has properties that transitively reference a cyclic schema,
|
|
105
|
+
// the printer emits memoizing getters for those properties. Spreading the object
|
|
106
|
+
// literal would immediately invoke those getters, triggering recursive faker calls
|
|
107
|
+
// and causing a stack overflow. Detect this upfront via ast helpers so we can
|
|
108
|
+
// use Object.defineProperty-based merging instead of spread.
|
|
109
|
+
const { cyclicSchemas, schemaName } = printer.options
|
|
110
|
+
const hasGetters =
|
|
111
|
+
node.type === 'object' &&
|
|
112
|
+
!!cyclicSchemas &&
|
|
113
|
+
(node.properties ?? []).some((p) => ast.containsCircularRef(p.schema, { circularSchemas: cyclicSchemas, excludeName: schemaName }))
|
|
114
|
+
|
|
115
|
+
const functionBody = hasGetters
|
|
116
|
+
? `{
|
|
117
|
+
${seedCode}const defaultFakeData = ${fakerText}
|
|
118
|
+
if (data) {
|
|
119
|
+
for (const [key, value] of Object.entries(data)) {
|
|
120
|
+
Object.defineProperty(defaultFakeData, key, { value, configurable: true, writable: true, enumerable: true })
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return defaultFakeData as Omit<typeof defaultFakeData, keyof TData> & TData
|
|
124
|
+
}`
|
|
125
|
+
: `{
|
|
126
|
+
${seedCode}const defaultFakeData = ${fakerText}
|
|
127
|
+
return {
|
|
128
|
+
...defaultFakeData,
|
|
129
|
+
...(data || {}),
|
|
130
|
+
} as Omit<typeof defaultFakeData, keyof TData> & TData
|
|
131
|
+
}`
|
|
132
|
+
|
|
147
133
|
return (
|
|
148
134
|
<File.Source name={name} isExportable isIndexable>
|
|
149
135
|
{functionSignature}
|
|
@@ -1,49 +1,53 @@
|
|
|
1
|
+
import { getPerContentTypeName, resolveContentTypeVariants } from '@internals/shared'
|
|
2
|
+
import { aliasConflictingImports, filterUsedImports, rewriteAliasedImports } from '@internals/utils'
|
|
1
3
|
import { ast, defineGenerator } from '@kubb/core'
|
|
2
4
|
import { pluginTsName } from '@kubb/plugin-ts'
|
|
3
|
-
import { File,
|
|
5
|
+
import { File, jsxRendererSync } from '@kubb/renderer-jsx'
|
|
4
6
|
import { Faker } from '../components/Faker.tsx'
|
|
5
7
|
import { printerFaker } from '../printers/printerFaker.ts'
|
|
6
8
|
import type { PluginFaker } from '../types.ts'
|
|
7
|
-
import {
|
|
8
|
-
aliasConflictingImports,
|
|
9
|
-
buildResponseUnionSchema,
|
|
10
|
-
canOverrideSchema,
|
|
11
|
-
filterUsedImports,
|
|
12
|
-
localeToFakerImport,
|
|
13
|
-
resolveParamNameByLocation,
|
|
14
|
-
resolveSchemaRef,
|
|
15
|
-
resolveTypeReference,
|
|
16
|
-
rewriteAliasedImports,
|
|
17
|
-
} from '../utils.ts'
|
|
9
|
+
import { buildResponseUnionSchema, canOverrideSchema, localeToFakerImport, resolveParamNameByLocation, resolveTypeReference } from '../utils.ts'
|
|
18
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Built-in generator for `@kubb/plugin-faker`. Emits one `createX` factory
|
|
13
|
+
* per schema in the spec plus per-operation request/response factories. Each
|
|
14
|
+
* factory returns a value matching the corresponding TypeScript type from
|
|
15
|
+
* `@kubb/plugin-ts`.
|
|
16
|
+
*/
|
|
19
17
|
export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
20
18
|
name: 'faker',
|
|
21
|
-
renderer:
|
|
19
|
+
renderer: jsxRendererSync,
|
|
22
20
|
schema(node, ctx) {
|
|
23
21
|
const { adapter, config, resolver, root } = ctx
|
|
24
22
|
const { output, group, dateParser, regexGenerator, mapper, seed, locale, printer } = ctx.options
|
|
25
23
|
const pluginTs = ctx.driver.getPlugin(pluginTsName)
|
|
26
24
|
|
|
27
|
-
if (!node.name || !pluginTs
|
|
25
|
+
if (!node.name || !pluginTs) {
|
|
28
26
|
return
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
const tsResolver = ctx.driver.getResolver(pluginTsName)
|
|
32
30
|
|
|
33
|
-
const
|
|
34
|
-
const schemaName = schemaNode.name ?? node.name
|
|
31
|
+
const schemaName = node.name
|
|
35
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)
|
|
36
40
|
const meta = {
|
|
37
41
|
name: resolver.resolveName(schemaName),
|
|
38
|
-
file: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }),
|
|
39
|
-
typeName:
|
|
42
|
+
file: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group: group ?? undefined }),
|
|
43
|
+
typeName: schemaTypeName,
|
|
40
44
|
typeFile: tsResolver.resolveFile(
|
|
41
45
|
{ name: schemaName, extname: '.ts' },
|
|
42
|
-
{ root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group },
|
|
46
|
+
{ root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group ?? undefined },
|
|
43
47
|
),
|
|
44
48
|
} as const
|
|
45
|
-
const canOverride = canOverrideSchema(
|
|
46
|
-
const cyclicSchemas =
|
|
49
|
+
const canOverride = canOverrideSchema(node)
|
|
50
|
+
const cyclicSchemas = new Set<string>(ctx.meta.circularNames)
|
|
47
51
|
const printerInstance = printerFaker({
|
|
48
52
|
resolver,
|
|
49
53
|
schemaName,
|
|
@@ -54,9 +58,9 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
54
58
|
nodes: printer?.nodes,
|
|
55
59
|
cyclicSchemas,
|
|
56
60
|
})
|
|
57
|
-
const fakerText = printerInstance.print(
|
|
61
|
+
const fakerText = printerInstance.print(node) ?? 'undefined'
|
|
58
62
|
const typeReference = resolveTypeReference({
|
|
59
|
-
node
|
|
63
|
+
node,
|
|
60
64
|
canOverride,
|
|
61
65
|
name: meta.name,
|
|
62
66
|
typeName: meta.typeName,
|
|
@@ -65,9 +69,9 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
65
69
|
})
|
|
66
70
|
|
|
67
71
|
const imports = adapter
|
|
68
|
-
.getImports(
|
|
72
|
+
.getImports(node, (schemaName) => ({
|
|
69
73
|
name: resolver.resolveName(schemaName),
|
|
70
|
-
path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }).path,
|
|
74
|
+
path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group: group ?? undefined }).path,
|
|
71
75
|
}))
|
|
72
76
|
.filter((entry) => entry.path !== meta.file.path)
|
|
73
77
|
const usedImports = filterUsedImports(imports, fakerText)
|
|
@@ -77,8 +81,8 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
77
81
|
baseName={meta.file.baseName}
|
|
78
82
|
path={meta.file.path}
|
|
79
83
|
meta={meta.file.meta}
|
|
80
|
-
banner={resolver.resolveBanner(
|
|
81
|
-
footer={resolver.resolveFooter(
|
|
84
|
+
banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
|
|
85
|
+
footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
|
|
82
86
|
>
|
|
83
87
|
<File.Import name={locale ? [{ propertyName: localeToFakerImport(locale), name: 'faker' }] : ['faker']} path="@faker-js/faker" />
|
|
84
88
|
{regexGenerator === 'randexp' && <File.Import name={'RandExp'} path={'randexp'} />}
|
|
@@ -89,8 +93,8 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
89
93
|
<Faker
|
|
90
94
|
name={meta.name}
|
|
91
95
|
typeName={typeReference.typeName}
|
|
92
|
-
description={
|
|
93
|
-
node={
|
|
96
|
+
description={node.description}
|
|
97
|
+
node={node}
|
|
94
98
|
printer={printerInstance}
|
|
95
99
|
seed={seed}
|
|
96
100
|
canOverride={canOverride}
|
|
@@ -115,31 +119,66 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
115
119
|
name: resolveParamNameByLocation(resolver, node, param),
|
|
116
120
|
typeName: resolveParamNameByLocation(tsResolver, node, param),
|
|
117
121
|
}))
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
+
)
|
|
134
168
|
const responseName = resolver.resolveResponseName(node)
|
|
135
169
|
const localHelperNames = new Set([
|
|
136
170
|
...paramEntries.map((entry) => entry.name),
|
|
137
|
-
...
|
|
138
|
-
...(
|
|
171
|
+
...responseUnits.map((unit) => unit.name),
|
|
172
|
+
...dataUnits.map((unit) => unit.name),
|
|
139
173
|
responseName,
|
|
140
174
|
])
|
|
175
|
+
const cyclicSchemas = new Set<string>(ctx.meta.circularNames)
|
|
176
|
+
|
|
141
177
|
const meta = {
|
|
142
|
-
file: resolver.resolveFile(
|
|
178
|
+
file: resolver.resolveFile(
|
|
179
|
+
{ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
|
|
180
|
+
{ root, output, group: group ?? undefined },
|
|
181
|
+
),
|
|
143
182
|
typeFile: tsResolver.resolveFile(
|
|
144
183
|
{
|
|
145
184
|
name: node.operationId,
|
|
@@ -150,7 +189,7 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
150
189
|
{
|
|
151
190
|
root,
|
|
152
191
|
output: pluginTs.options?.output ?? output,
|
|
153
|
-
group: pluginTs.options?.group,
|
|
192
|
+
group: pluginTs.options?.group ?? undefined,
|
|
154
193
|
},
|
|
155
194
|
),
|
|
156
195
|
} as const
|
|
@@ -159,7 +198,7 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
159
198
|
return adapter
|
|
160
199
|
.getImports(schema, (schemaName) => ({
|
|
161
200
|
name: resolver.resolveName(schemaName),
|
|
162
|
-
path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }).path,
|
|
201
|
+
path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group: group ?? undefined }).path,
|
|
163
202
|
}))
|
|
164
203
|
.filter((entry) => entry.path !== meta.file.path)
|
|
165
204
|
}
|
|
@@ -182,7 +221,6 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
182
221
|
}
|
|
183
222
|
|
|
184
223
|
const canOverride = canOverrideSchema(schema)
|
|
185
|
-
const cyclicSchemas = adapter.inputNode ? ast.findCircularSchemas(adapter.inputNode.schemas) : undefined
|
|
186
224
|
const printerInstance = printerFaker({
|
|
187
225
|
resolver,
|
|
188
226
|
schemaName: name,
|
|
@@ -230,8 +268,8 @@ export const fakerGenerator = defineGenerator<PluginFaker>({
|
|
|
230
268
|
baseName={meta.file.baseName}
|
|
231
269
|
path={meta.file.path}
|
|
232
270
|
meta={meta.file.meta}
|
|
233
|
-
banner={resolver.resolveBanner(
|
|
234
|
-
footer={resolver.resolveFooter(
|
|
271
|
+
banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
|
|
272
|
+
footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
|
|
235
273
|
>
|
|
236
274
|
<File.Import name={locale ? [{ propertyName: localeToFakerImport(locale), name: 'faker' }] : ['faker']} path="@faker-js/faker" />
|
|
237
275
|
{regexGenerator === 'randexp' && <File.Import name={'RandExp'} path={'randexp'} />}
|
|
@@ -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,22 +1,39 @@
|
|
|
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'
|
|
6
6
|
import type { PluginFaker } from './types.ts'
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Canonical plugin name for `@kubb/plugin-faker
|
|
9
|
+
* Canonical plugin name for `@kubb/plugin-faker`. Used for driver lookups and
|
|
10
|
+
* cross-plugin dependency references.
|
|
10
11
|
*/
|
|
11
12
|
export const pluginFakerName = 'plugin-faker' satisfies PluginFaker['name']
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
|
-
* Generates
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* Generates one mock-data factory per OpenAPI schema using Faker.js. Call
|
|
16
|
+
* `createPet()` to get a realistic `Pet` object. Useful for tests, Storybook,
|
|
17
|
+
* and local development without a running backend.
|
|
17
18
|
*
|
|
18
19
|
* @example
|
|
19
|
-
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { defineConfig } from 'kubb'
|
|
22
|
+
* import { pluginTs } from '@kubb/plugin-ts'
|
|
23
|
+
* import { pluginFaker } from '@kubb/plugin-faker'
|
|
24
|
+
*
|
|
25
|
+
* export default defineConfig({
|
|
26
|
+
* input: { path: './petStore.yaml' },
|
|
27
|
+
* output: { path: './src/gen' },
|
|
28
|
+
* plugins: [
|
|
29
|
+
* pluginTs(),
|
|
30
|
+
* pluginFaker({
|
|
31
|
+
* output: { path: './mocks' },
|
|
32
|
+
* seed: [100],
|
|
33
|
+
* }),
|
|
34
|
+
* ],
|
|
35
|
+
* })
|
|
36
|
+
* ```
|
|
20
37
|
*/
|
|
21
38
|
export const pluginFaker = definePlugin<PluginFaker>((options) => {
|
|
22
39
|
const {
|
|
@@ -37,20 +54,7 @@ export const pluginFaker = definePlugin<PluginFaker>((options) => {
|
|
|
37
54
|
transformer: userTransformer,
|
|
38
55
|
} = options
|
|
39
56
|
|
|
40
|
-
const groupConfig = group
|
|
41
|
-
? ({
|
|
42
|
-
...group,
|
|
43
|
-
name: group.name
|
|
44
|
-
? group.name
|
|
45
|
-
: (ctx: { group: string }) => {
|
|
46
|
-
if (group.type === 'path') {
|
|
47
|
-
return `${ctx.group.split('/')[1]}`
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return `${camelCase(ctx.group)}Controller`
|
|
51
|
-
},
|
|
52
|
-
} satisfies Group)
|
|
53
|
-
: undefined
|
|
57
|
+
const groupConfig = createGroupConfig(group, { suffix: 'Controller', honorName: true })
|
|
54
58
|
|
|
55
59
|
return {
|
|
56
60
|
name: pluginFakerName,
|