@kubb/plugin-faker 5.0.0-alpha.9 → 5.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +17 -10
- package/README.md +1 -4
- package/dist/Faker-BgleOzVN.cjs +486 -0
- package/dist/Faker-BgleOzVN.cjs.map +1 -0
- package/dist/Faker-CdyPfOPg.d.ts +27 -0
- package/dist/Faker-fcQEB9i5.js +384 -0
- package/dist/Faker-fcQEB9i5.js.map +1 -0
- package/dist/components.cjs +2 -2
- package/dist/components.d.ts +2 -31
- package/dist/components.js +1 -1
- package/dist/fakerGenerator-C3Ho3BaI.d.ts +9 -0
- package/dist/fakerGenerator-D7daHCh6.js +516 -0
- package/dist/fakerGenerator-D7daHCh6.js.map +1 -0
- package/dist/fakerGenerator-VJEVzLjc.cjs +526 -0
- package/dist/fakerGenerator-VJEVzLjc.cjs.map +1 -0
- package/dist/generators.cjs +1 -1
- package/dist/generators.d.ts +2 -505
- package/dist/generators.js +1 -1
- package/dist/index.cjs +136 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +28 -4
- package/dist/index.js +128 -83
- package/dist/index.js.map +1 -1
- package/dist/printerFaker-CJiwzoto.d.ts +206 -0
- package/package.json +52 -50
- package/src/components/Faker.tsx +124 -78
- package/src/generators/fakerGenerator.tsx +235 -134
- package/src/index.ts +7 -2
- package/src/plugin.ts +60 -121
- package/src/printers/printerFaker.ts +341 -0
- package/src/resolvers/resolverFaker.ts +92 -0
- package/src/types.ts +127 -81
- package/src/utils.ts +356 -0
- package/dist/components-BkBIov4R.js +0 -419
- package/dist/components-BkBIov4R.js.map +0 -1
- package/dist/components-IdP8GXXX.cjs +0 -461
- package/dist/components-IdP8GXXX.cjs.map +0 -1
- package/dist/fakerGenerator-CYUCNH3Q.cjs +0 -204
- package/dist/fakerGenerator-CYUCNH3Q.cjs.map +0 -1
- package/dist/fakerGenerator-M5oCrPmy.js +0 -200
- package/dist/fakerGenerator-M5oCrPmy.js.map +0 -1
- package/dist/types-r7BubMLO.d.ts +0 -132
- package/src/parser.ts +0 -453
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { stringify, toRegExpString } from '@internals/utils'
|
|
2
|
+
import { ast } from '@kubb/core'
|
|
3
|
+
import type { PluginFaker, ResolverFaker } from '../types.ts'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Partial printer nodes for Faker generation, mapping schema types to output strings.
|
|
7
|
+
*/
|
|
8
|
+
export type PrinterFakerNodes = ast.PrinterPartial<string, PrinterFakerOptions>
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Configuration options for the Faker printer, including resolvers, mappers, and cyclic schema tracking.
|
|
12
|
+
*/
|
|
13
|
+
export type PrinterFakerOptions = {
|
|
14
|
+
dateParser?: PluginFaker['resolvedOptions']['dateParser']
|
|
15
|
+
regexGenerator?: PluginFaker['resolvedOptions']['regexGenerator']
|
|
16
|
+
mapper?: PluginFaker['resolvedOptions']['mapper']
|
|
17
|
+
resolver: ResolverFaker
|
|
18
|
+
typeName?: string
|
|
19
|
+
schemaName?: string
|
|
20
|
+
nestedInObject?: boolean
|
|
21
|
+
nodes?: PrinterFakerNodes
|
|
22
|
+
/**
|
|
23
|
+
* Names of schemas that participate in a circular dependency chain.
|
|
24
|
+
* Properties whose schema transitively references one of these are emitted
|
|
25
|
+
* as lazy getters so that user overrides via the `data` parameter prevent
|
|
26
|
+
* the recursive faker call from ever executing (avoiding stack overflow).
|
|
27
|
+
*/
|
|
28
|
+
cyclicSchemas?: ReadonlySet<string>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Factory options for the Faker printer, defining input/output types and configuration.
|
|
33
|
+
*/
|
|
34
|
+
export type PrinterFakerFactory = ast.PrinterFactoryOptions<'faker', PrinterFakerOptions, string, string>
|
|
35
|
+
|
|
36
|
+
const fakerKeywordMapper = {
|
|
37
|
+
any: () => 'undefined',
|
|
38
|
+
unknown: () => 'undefined',
|
|
39
|
+
void: () => 'undefined',
|
|
40
|
+
number: (min?: number, max?: number) => {
|
|
41
|
+
if (max !== undefined && min !== undefined) {
|
|
42
|
+
return `faker.number.float({ min: ${min}, max: ${max} })`
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (max !== undefined) {
|
|
46
|
+
return `faker.number.float({ max: ${max} })`
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (min !== undefined) {
|
|
50
|
+
return `faker.number.float({ min: ${min} })`
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return 'faker.number.float()'
|
|
54
|
+
},
|
|
55
|
+
integer: (min?: number, max?: number) => {
|
|
56
|
+
if (max !== undefined && min !== undefined) {
|
|
57
|
+
return `faker.number.int({ min: ${min}, max: ${max} })`
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (max !== undefined) {
|
|
61
|
+
return `faker.number.int({ max: ${max} })`
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (min !== undefined) {
|
|
65
|
+
return `faker.number.int({ min: ${min} })`
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return 'faker.number.int()'
|
|
69
|
+
},
|
|
70
|
+
bigint: () => 'faker.number.bigInt()',
|
|
71
|
+
string: (min?: number, max?: number) => {
|
|
72
|
+
if (max !== undefined && min !== undefined) {
|
|
73
|
+
return `faker.string.alpha({ length: { min: ${min}, max: ${max} } })`
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (max !== undefined) {
|
|
77
|
+
return `faker.string.alpha({ length: ${max} })`
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (min !== undefined) {
|
|
81
|
+
return `faker.string.alpha({ length: ${min} })`
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return 'faker.string.alpha()'
|
|
85
|
+
},
|
|
86
|
+
boolean: () => 'faker.datatype.boolean()',
|
|
87
|
+
null: () => 'null',
|
|
88
|
+
array: (items: string[] = [], min?: number, max?: number) => {
|
|
89
|
+
if (items.length > 1) {
|
|
90
|
+
return `faker.helpers.arrayElements([${items.join(', ')}])`
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const item = items.at(0)
|
|
94
|
+
|
|
95
|
+
if (min !== undefined && max !== undefined) {
|
|
96
|
+
return `faker.helpers.multiple(() => (${item}), { count: { min: ${min}, max: ${max} }})`
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (min !== undefined) {
|
|
100
|
+
return `faker.helpers.multiple(() => (${item}), { count: ${min} })`
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (max !== undefined) {
|
|
104
|
+
return `faker.helpers.multiple(() => (${item}), { count: { min: 0, max: ${max} }})`
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return `faker.helpers.multiple(() => (${item}))`
|
|
108
|
+
},
|
|
109
|
+
tuple: (items: string[] = []) => `[${items.join(', ')}]`,
|
|
110
|
+
enum: (items: Array<string | number | boolean | undefined> = [], type = 'any') => `faker.helpers.arrayElement<${type}>([${items.join(', ')}])`,
|
|
111
|
+
union: (items: string[] = []) => `faker.helpers.arrayElement<any>([${items.join(', ')}])`,
|
|
112
|
+
datetime: () => 'faker.date.anytime().toISOString()',
|
|
113
|
+
date: (representation: 'date' | 'string' = 'string', parser: PluginFaker['resolvedOptions']['dateParser'] = 'faker') => {
|
|
114
|
+
if (representation === 'string') {
|
|
115
|
+
if (parser !== 'faker') {
|
|
116
|
+
return `${parser}(faker.date.anytime()).format("YYYY-MM-DD")`
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return 'faker.date.anytime().toISOString().substring(0, 10)'
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (parser !== 'faker') {
|
|
123
|
+
throw new Error(`type '${representation}' and parser '${parser}' can not work together`)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return 'faker.date.anytime()'
|
|
127
|
+
},
|
|
128
|
+
time: (representation: 'date' | 'string' = 'string', parser: PluginFaker['resolvedOptions']['dateParser'] = 'faker') => {
|
|
129
|
+
if (representation === 'string') {
|
|
130
|
+
if (parser !== 'faker') {
|
|
131
|
+
return `${parser}(faker.date.anytime()).format("HH:mm:ss")`
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return 'faker.date.anytime().toISOString().substring(11, 19)'
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (parser !== 'faker') {
|
|
138
|
+
throw new Error(`type '${representation}' and parser '${parser}' can not work together`)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return 'faker.date.anytime()'
|
|
142
|
+
},
|
|
143
|
+
uuid: () => 'faker.string.uuid()',
|
|
144
|
+
url: () => 'faker.internet.url()',
|
|
145
|
+
and: (items: string[] = []) => {
|
|
146
|
+
if (items.length === 0) {
|
|
147
|
+
return '{}'
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (items.length === 1) {
|
|
151
|
+
return items[0] ?? '{}'
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return `{...${items.join(', ...')}}`
|
|
155
|
+
},
|
|
156
|
+
matches: (value = '', regexGenerator: 'faker' | 'randexp' = 'faker') => {
|
|
157
|
+
if (regexGenerator === 'randexp') {
|
|
158
|
+
return `${toRegExpString(value, 'RandExp')}.gen()`
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return `faker.helpers.fromRegExp("${value}")`
|
|
162
|
+
},
|
|
163
|
+
email: () => 'faker.internet.email()',
|
|
164
|
+
blob: () => 'faker.image.url() as unknown as Blob',
|
|
165
|
+
} as const
|
|
166
|
+
|
|
167
|
+
function getEnumValues(node: ast.EnumSchemaNode): Array<string | number | boolean | undefined> {
|
|
168
|
+
if (node.namedEnumValues?.length) {
|
|
169
|
+
return node.namedEnumValues.map((item) => item.value as string | number | boolean | undefined)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return (node.enumValues ?? []) as Array<string | number | boolean | undefined>
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function parseEnumValue(value: string | number | boolean | undefined) {
|
|
176
|
+
if (typeof value === 'string') {
|
|
177
|
+
return stringify(value)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return value
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Creates a Faker printer that generates mock data generation code from schema nodes.
|
|
185
|
+
* Handles circular references gracefully by emitting memoizing getters for cyclic properties.
|
|
186
|
+
*/
|
|
187
|
+
export const printerFaker: (options: PrinterFakerOptions) => ast.Printer<PrinterFakerFactory> = ast.definePrinter<PrinterFakerFactory>((options) => {
|
|
188
|
+
const printNested = (node: ast.SchemaNode, overrideOptions: Partial<PrinterFakerOptions> = {}): string => {
|
|
189
|
+
return (
|
|
190
|
+
printerFaker({
|
|
191
|
+
...options,
|
|
192
|
+
...overrideOptions,
|
|
193
|
+
nodes: options.nodes,
|
|
194
|
+
}).print(node) ?? 'undefined'
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
name: 'faker',
|
|
200
|
+
options,
|
|
201
|
+
nodes: {
|
|
202
|
+
any: () => fakerKeywordMapper.any(),
|
|
203
|
+
unknown: () => fakerKeywordMapper.unknown(),
|
|
204
|
+
void: () => fakerKeywordMapper.void(),
|
|
205
|
+
boolean: () => fakerKeywordMapper.boolean(),
|
|
206
|
+
null: () => fakerKeywordMapper.null(),
|
|
207
|
+
string(node) {
|
|
208
|
+
if (node.pattern) {
|
|
209
|
+
return fakerKeywordMapper.matches(node.pattern, this.options.regexGenerator)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return fakerKeywordMapper.string(node.min, node.max)
|
|
213
|
+
},
|
|
214
|
+
email: () => fakerKeywordMapper.email(),
|
|
215
|
+
url: () => fakerKeywordMapper.url(),
|
|
216
|
+
uuid: () => fakerKeywordMapper.uuid(),
|
|
217
|
+
number(node) {
|
|
218
|
+
return fakerKeywordMapper.number(node.min, node.max)
|
|
219
|
+
},
|
|
220
|
+
integer(node) {
|
|
221
|
+
return fakerKeywordMapper.integer(node.min, node.max)
|
|
222
|
+
},
|
|
223
|
+
bigint: () => fakerKeywordMapper.bigint(),
|
|
224
|
+
blob: () => fakerKeywordMapper.blob(),
|
|
225
|
+
datetime: () => fakerKeywordMapper.datetime(),
|
|
226
|
+
date(node) {
|
|
227
|
+
return fakerKeywordMapper.date(node.representation ?? 'string', this.options.dateParser)
|
|
228
|
+
},
|
|
229
|
+
time(node) {
|
|
230
|
+
return fakerKeywordMapper.time(node.representation ?? 'string', this.options.dateParser)
|
|
231
|
+
},
|
|
232
|
+
ref(node) {
|
|
233
|
+
// Parser-generated refs (with $ref) carry raw schema names that need resolving.
|
|
234
|
+
// Use the canonical name from the $ref path — node.name may have been overridden
|
|
235
|
+
// (e.g. by single-member allOf flatten using the property-derived child name).
|
|
236
|
+
// Inline refs (without $ref) from faker utils already carry resolved helper names.
|
|
237
|
+
const refName = node.ref ? (ast.extractRefName(node.ref) ?? node.name ?? node.schema?.name) : (node.name ?? node.schema?.name)
|
|
238
|
+
|
|
239
|
+
if (!refName) {
|
|
240
|
+
throw new Error('Name not defined for ref node')
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (this.options.schemaName && refName === this.options.schemaName) {
|
|
244
|
+
return 'undefined as any'
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Internal helper refs (for generated response/data helpers) are already
|
|
248
|
+
// emitted with resolver output and should not be transformed twice.
|
|
249
|
+
const resolvedName = node.ref ? this.options.resolver.resolveName(refName) : refName
|
|
250
|
+
|
|
251
|
+
if (!this.options.nestedInObject) {
|
|
252
|
+
return `${resolvedName}(data)`
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return `${resolvedName}()`
|
|
256
|
+
},
|
|
257
|
+
enum(node) {
|
|
258
|
+
return fakerKeywordMapper.enum(getEnumValues(node).map(parseEnumValue), this.options.typeName)
|
|
259
|
+
},
|
|
260
|
+
union(node): string {
|
|
261
|
+
const items: string[] = (node.members ?? [])
|
|
262
|
+
.map((member) =>
|
|
263
|
+
printNested(member, {
|
|
264
|
+
nestedInObject: true,
|
|
265
|
+
}),
|
|
266
|
+
)
|
|
267
|
+
.filter((item): item is string => Boolean(item))
|
|
268
|
+
|
|
269
|
+
return fakerKeywordMapper.union(items)
|
|
270
|
+
},
|
|
271
|
+
intersection(node): string {
|
|
272
|
+
const items: string[] = (node.members ?? [])
|
|
273
|
+
.map((member) =>
|
|
274
|
+
printNested(member, {
|
|
275
|
+
nestedInObject: true,
|
|
276
|
+
}),
|
|
277
|
+
)
|
|
278
|
+
.filter((item): item is string => Boolean(item))
|
|
279
|
+
|
|
280
|
+
return fakerKeywordMapper.and(items)
|
|
281
|
+
},
|
|
282
|
+
array(node): string {
|
|
283
|
+
const items: string[] = (node.items ?? [])
|
|
284
|
+
.map((member) =>
|
|
285
|
+
printNested(member, {
|
|
286
|
+
typeName: this.options.typeName ? `NonNullable<${this.options.typeName}>[number]` : undefined,
|
|
287
|
+
nestedInObject: true,
|
|
288
|
+
}),
|
|
289
|
+
)
|
|
290
|
+
.filter((item): item is string => Boolean(item))
|
|
291
|
+
|
|
292
|
+
return fakerKeywordMapper.array(items, node.min, node.max)
|
|
293
|
+
},
|
|
294
|
+
tuple(node): string {
|
|
295
|
+
const items: string[] = (node.items ?? [])
|
|
296
|
+
.map((member, index) =>
|
|
297
|
+
printNested(member, {
|
|
298
|
+
typeName: this.options.typeName ? `NonNullable<${this.options.typeName}>[${index}]` : undefined,
|
|
299
|
+
nestedInObject: true,
|
|
300
|
+
}),
|
|
301
|
+
)
|
|
302
|
+
.filter((item): item is string => Boolean(item))
|
|
303
|
+
|
|
304
|
+
return fakerKeywordMapper.tuple(items)
|
|
305
|
+
},
|
|
306
|
+
object(node): string {
|
|
307
|
+
const cyclicSchemas = this.options.cyclicSchemas
|
|
308
|
+
const properties = (node.properties ?? [])
|
|
309
|
+
.map((property): string => {
|
|
310
|
+
if (this.options.mapper && Object.hasOwn(this.options.mapper, property.name)) {
|
|
311
|
+
return `"${property.name}": ${this.options.mapper[property.name]}`
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const value: string =
|
|
315
|
+
printNested(property.schema, {
|
|
316
|
+
typeName: this.options.typeName ? `NonNullable<${this.options.typeName}>[${JSON.stringify(property.name)}]` : undefined,
|
|
317
|
+
nestedInObject: true,
|
|
318
|
+
}) ?? 'undefined'
|
|
319
|
+
|
|
320
|
+
// When the property's schema transitively references a schema that is
|
|
321
|
+
// part of a circular dependency (other than the current schema itself),
|
|
322
|
+
// emit a memoizing lazy getter. On first access it computes the value,
|
|
323
|
+
// replaces itself with a plain data property via Object.defineProperty,
|
|
324
|
+
// and returns the cached value – so every subsequent read is stable.
|
|
325
|
+
if (cyclicSchemas && ast.containsCircularRef(property.schema, { circularSchemas: cyclicSchemas, excludeName: this.options.schemaName })) {
|
|
326
|
+
return `get ${property.name}() { const _value = ${value}; Object.defineProperty(this, ${JSON.stringify(property.name)}, { value: _value, configurable: true, writable: true, enumerable: true }); return _value }`
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return `"${property.name}": ${value}`
|
|
330
|
+
})
|
|
331
|
+
.join(',')
|
|
332
|
+
|
|
333
|
+
return `{${properties}}`
|
|
334
|
+
},
|
|
335
|
+
...options.nodes,
|
|
336
|
+
},
|
|
337
|
+
print(node) {
|
|
338
|
+
return this.transform(node) ?? null
|
|
339
|
+
},
|
|
340
|
+
}
|
|
341
|
+
})
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { camelCase } from '@internals/utils'
|
|
4
|
+
import { defineResolver, PluginDriver } from '@kubb/core'
|
|
5
|
+
import type { PluginFaker } from '../types.ts'
|
|
6
|
+
|
|
7
|
+
function isValidStrictIdentifier(name: string): boolean {
|
|
8
|
+
try {
|
|
9
|
+
new Function(`"use strict"; const ${name} = 1;`)
|
|
10
|
+
} catch {
|
|
11
|
+
return false
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return true
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Naming convention resolver for Faker plugin.
|
|
19
|
+
*
|
|
20
|
+
* Provides default naming helpers using camelCase. Prefixes invalid identifiers with `_`.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* `resolverFaker.default('list pets', 'function') // → 'listPets'`
|
|
24
|
+
*/
|
|
25
|
+
export const resolverFaker = defineResolver<PluginFaker>((ctx) => {
|
|
26
|
+
return {
|
|
27
|
+
name: 'default',
|
|
28
|
+
pluginName: 'plugin-faker',
|
|
29
|
+
default(name, type) {
|
|
30
|
+
const resolvedName = camelCase(name, { isFile: type === 'file' })
|
|
31
|
+
|
|
32
|
+
if (type === 'file' || isValidStrictIdentifier(resolvedName)) {
|
|
33
|
+
return resolvedName
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return `_${resolvedName}`
|
|
37
|
+
},
|
|
38
|
+
resolveName(name, type) {
|
|
39
|
+
return ctx.default(name, type)
|
|
40
|
+
},
|
|
41
|
+
resolvePathName(name, type) {
|
|
42
|
+
return ctx.default(name, type)
|
|
43
|
+
},
|
|
44
|
+
resolveFile({ name, extname, tag, path: groupPath }, context) {
|
|
45
|
+
const pathMode = PluginDriver.getMode(path.resolve(context.root, context.output.path))
|
|
46
|
+
const baseName = `${pathMode === 'single' ? '' : ctx.resolveName(name, 'file')}${extname}` as `${string}.${string}`
|
|
47
|
+
const filePath = ctx.resolvePath(
|
|
48
|
+
{
|
|
49
|
+
baseName,
|
|
50
|
+
pathMode,
|
|
51
|
+
tag,
|
|
52
|
+
path: groupPath,
|
|
53
|
+
},
|
|
54
|
+
context,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
kind: 'File',
|
|
59
|
+
id: createHash('sha256').update(filePath).digest('hex'),
|
|
60
|
+
name: path.basename(filePath, extname),
|
|
61
|
+
path: filePath,
|
|
62
|
+
baseName,
|
|
63
|
+
extname,
|
|
64
|
+
meta: { pluginName: ctx.pluginName },
|
|
65
|
+
sources: [],
|
|
66
|
+
imports: [],
|
|
67
|
+
exports: [],
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
resolveParamName(node, param) {
|
|
71
|
+
return ctx.resolveName(`${node.operationId} ${param.in} ${param.name}`)
|
|
72
|
+
},
|
|
73
|
+
resolveDataName(node) {
|
|
74
|
+
return ctx.resolveName(`${node.operationId} Data`)
|
|
75
|
+
},
|
|
76
|
+
resolveResponseStatusName(node, statusCode) {
|
|
77
|
+
return ctx.resolveName(`${node.operationId} Status ${statusCode}`)
|
|
78
|
+
},
|
|
79
|
+
resolveResponseName(node) {
|
|
80
|
+
return ctx.resolveName(`${node.operationId} Response`)
|
|
81
|
+
},
|
|
82
|
+
resolvePathParamsName(node, param) {
|
|
83
|
+
return ctx.resolveParamName(node, param)
|
|
84
|
+
},
|
|
85
|
+
resolveQueryParamsName(node, param) {
|
|
86
|
+
return ctx.resolveParamName(node, param)
|
|
87
|
+
},
|
|
88
|
+
resolveHeaderParamsName(node, param) {
|
|
89
|
+
return ctx.resolveParamName(node, param)
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
})
|
package/src/types.ts
CHANGED
|
@@ -1,126 +1,172 @@
|
|
|
1
|
-
import type { Group, Output, PluginFactoryOptions,
|
|
1
|
+
import type { ast, Exclude, Generator, Group, Include, Output, Override, PluginFactoryOptions, Resolver } from '@kubb/core'
|
|
2
|
+
import type { PrinterFakerNodes } from './printers/printerFaker.ts'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Resolver for Faker that provides naming methods for mock functions.
|
|
6
|
+
*/
|
|
7
|
+
export type ResolverFaker = Resolver &
|
|
8
|
+
ast.OperationParamsResolver & {
|
|
9
|
+
/**
|
|
10
|
+
* Resolves the faker function name for a schema.
|
|
11
|
+
*
|
|
12
|
+
* @example Resolving faker function names
|
|
13
|
+
* `resolver.resolveName('show pet by id') // -> 'showPetById'`
|
|
14
|
+
*/
|
|
15
|
+
resolveName(this: ResolverFaker, name: string, type?: 'file' | 'function' | 'type' | 'const'): string
|
|
16
|
+
/**
|
|
17
|
+
* Resolves the output file name for a faker module.
|
|
18
|
+
*
|
|
19
|
+
* @example Resolving faker file names
|
|
20
|
+
* `resolver.resolvePathName('show pet by id', 'file') // -> 'showPetById'`
|
|
21
|
+
*/
|
|
22
|
+
resolvePathName(this: ResolverFaker, name: string, type?: 'file' | 'function' | 'type' | 'const'): string
|
|
23
|
+
/**
|
|
24
|
+
* Resolves the faker function name for a request body.
|
|
25
|
+
*
|
|
26
|
+
* @example Resolving data function names
|
|
27
|
+
* `resolver.resolveDataName(node) // -> 'createPetsData'`
|
|
28
|
+
*/
|
|
29
|
+
resolveDataName(this: ResolverFaker, node: ast.OperationNode): string
|
|
30
|
+
/**
|
|
31
|
+
* Resolves the faker function name for a response by status code.
|
|
32
|
+
*
|
|
33
|
+
* @example Response status names
|
|
34
|
+
* `resolver.resolveResponseStatusName(node, 200) // -> 'listPetsStatus200'`
|
|
35
|
+
*/
|
|
36
|
+
resolveResponseStatusName(this: ResolverFaker, node: ast.OperationNode, statusCode: ast.StatusCode): string
|
|
37
|
+
/**
|
|
38
|
+
* Resolves the faker function name for the response union.
|
|
39
|
+
*
|
|
40
|
+
* @example Response union names
|
|
41
|
+
* `resolver.resolveResponseName(node) // -> 'listPetsResponse'`
|
|
42
|
+
*/
|
|
43
|
+
resolveResponseName(this: ResolverFaker, node: ast.OperationNode): string
|
|
44
|
+
/**
|
|
45
|
+
* Resolves the faker function name for path parameters.
|
|
46
|
+
*
|
|
47
|
+
* @example Path parameters names
|
|
48
|
+
* `resolver.resolvePathParamsName(node, param) // -> 'showPetByIdPathPetId'`
|
|
49
|
+
*/
|
|
50
|
+
resolvePathParamsName(this: ResolverFaker, node: ast.OperationNode, param: ast.ParameterNode): string
|
|
51
|
+
/**
|
|
52
|
+
* Resolves the faker function name for query parameters.
|
|
53
|
+
*
|
|
54
|
+
* @example Query parameters names
|
|
55
|
+
* `resolver.resolveQueryParamsName(node, param) // -> 'listPetsQueryLimit'`
|
|
56
|
+
*/
|
|
57
|
+
resolveQueryParamsName(this: ResolverFaker, node: ast.OperationNode, param: ast.ParameterNode): string
|
|
58
|
+
/**
|
|
59
|
+
* Resolves the faker function name for header parameters.
|
|
60
|
+
*
|
|
61
|
+
* @example Header parameters names
|
|
62
|
+
* `resolver.resolveHeaderParamsName(node, param) // -> 'deletePetHeaderApiKey'`
|
|
63
|
+
*/
|
|
64
|
+
resolveHeaderParamsName(this: ResolverFaker, node: ast.OperationNode, param: ast.ParameterNode): string
|
|
65
|
+
}
|
|
6
66
|
|
|
7
67
|
export type Options = {
|
|
8
68
|
/**
|
|
9
|
-
* Specify the export location for the files and define the behavior of the output
|
|
10
|
-
* @default { path: '
|
|
11
|
-
*/
|
|
12
|
-
output?: Output<Oas>
|
|
13
|
-
/**
|
|
14
|
-
* Define which contentType should be used.
|
|
15
|
-
* By default, the first JSON valid mediaType is used
|
|
69
|
+
* Specify the export location for the files and define the behavior of the output.
|
|
70
|
+
* @default { path: 'mocks', barrelType: 'named' }
|
|
16
71
|
*/
|
|
17
|
-
|
|
72
|
+
output?: Output
|
|
18
73
|
/**
|
|
19
74
|
* Group the Faker mocks based on the provided name.
|
|
20
75
|
*/
|
|
21
76
|
group?: Group
|
|
22
77
|
/**
|
|
23
|
-
*
|
|
78
|
+
* Tags, operations, or paths to exclude from generation.
|
|
24
79
|
*/
|
|
25
80
|
exclude?: Array<Exclude>
|
|
26
81
|
/**
|
|
27
|
-
*
|
|
82
|
+
* Tags, operations, or paths to include in generation.
|
|
28
83
|
*/
|
|
29
84
|
include?: Array<Include>
|
|
30
85
|
/**
|
|
31
|
-
*
|
|
86
|
+
* Override options for specific tags, operations, or paths.
|
|
32
87
|
*/
|
|
33
88
|
override?: Array<Override<ResolvedOptions>>
|
|
34
89
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* - 'date' represents dates as JavaScript Date objects.
|
|
38
|
-
* @default 'string'
|
|
39
|
-
*/
|
|
40
|
-
dateType?: 'string' | 'date'
|
|
41
|
-
/**
|
|
42
|
-
* Choose to use `number` or `bigint` for integer fields with `int64` format.
|
|
43
|
-
* - 'number' uses the JavaScript `number` type (matches JSON.parse() runtime behavior).
|
|
44
|
-
* - 'bigint' uses the JavaScript `bigint` type (accurate for values exceeding Number.MAX_SAFE_INTEGER).
|
|
45
|
-
* @note in v5 of Kubb 'bigint' will become the default to better align with OpenAPI's int64 specification.
|
|
46
|
-
* @default 'number'
|
|
47
|
-
*/
|
|
48
|
-
integerType?: 'number' | 'bigint'
|
|
49
|
-
/**
|
|
50
|
-
* Which parser should be used when dateType is set to string.
|
|
51
|
-
* - 'faker' uses faker's built-in date formatting methods.
|
|
52
|
-
* - 'dayjs' uses dayjs for date formatting with custom patterns.
|
|
53
|
-
* - 'moment' uses moment for date formatting with custom patterns.
|
|
90
|
+
* Parser to use when formatting date/time values as strings.
|
|
91
|
+
*
|
|
54
92
|
* @default 'faker'
|
|
55
93
|
*/
|
|
56
94
|
dateParser?: 'faker' | 'dayjs' | 'moment' | (string & {})
|
|
57
95
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* - 'void' represents no value.
|
|
62
|
-
* @default 'any'
|
|
96
|
+
* Generator to use for RegExp patterns.
|
|
97
|
+
*
|
|
98
|
+
* @default 'faker'
|
|
63
99
|
*/
|
|
64
|
-
|
|
100
|
+
regexGenerator?: 'faker' | 'randexp'
|
|
65
101
|
/**
|
|
66
|
-
*
|
|
67
|
-
* - 'any' allows any value.
|
|
68
|
-
* - 'unknown' requires type narrowing before use.
|
|
69
|
-
* - 'void' represents no value.
|
|
70
|
-
* @default `unknownType`
|
|
102
|
+
* Provide per-property faker expressions keyed by property name.
|
|
71
103
|
*/
|
|
72
|
-
|
|
104
|
+
mapper?: Record<string, string>
|
|
73
105
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
106
|
+
* Locale for generating mock data.
|
|
107
|
+
* Imports the matching localized `@faker-js/faker` instance so names, addresses,
|
|
108
|
+
* and phone numbers reflect the target region.
|
|
109
|
+
*
|
|
110
|
+
* @default 'en'
|
|
111
|
+
*
|
|
112
|
+
* @example German
|
|
113
|
+
* `locale: 'de'`
|
|
114
|
+
*
|
|
115
|
+
* @example Austrian German
|
|
116
|
+
* `locale: 'de_AT'`
|
|
117
|
+
*
|
|
118
|
+
* @see https://fakerjs.dev/api/localization.html
|
|
78
119
|
*/
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
mapper?: Record<string, string>
|
|
120
|
+
locale?: string
|
|
82
121
|
/**
|
|
83
|
-
*
|
|
122
|
+
* Seed faker for deterministic output.
|
|
84
123
|
*/
|
|
85
124
|
seed?: number | number[]
|
|
86
125
|
/**
|
|
87
|
-
*
|
|
88
|
-
* When set to 'camelcase', parameter names in path, query, and header params will be transformed to camelCase.
|
|
89
|
-
* This should match the paramsCasing setting used in @kubb/plugin-ts.
|
|
90
|
-
* @default undefined
|
|
126
|
+
* Apply casing to parameter names to match your configuration.
|
|
91
127
|
*/
|
|
92
128
|
paramsCasing?: 'camelcase'
|
|
93
|
-
transformers?: {
|
|
94
|
-
/**
|
|
95
|
-
* Customize the names based on the type that is provided by the plugin.
|
|
96
|
-
*/
|
|
97
|
-
name?: (name: ResolveNameParams['name'], type?: ResolveNameParams['type']) => string
|
|
98
|
-
/**
|
|
99
|
-
* Receive schema and baseName(propertyName) and return FakerMeta array
|
|
100
|
-
* TODO TODO add docs
|
|
101
|
-
* @beta
|
|
102
|
-
*/
|
|
103
|
-
schema?: (props: { schema: SchemaObject | null; name: string | null; parentName: string | null }, defaultSchemas: Schema[]) => Schema[] | undefined
|
|
104
|
-
}
|
|
105
129
|
/**
|
|
106
|
-
*
|
|
130
|
+
* Additional generators alongside the default generators.
|
|
107
131
|
*/
|
|
108
132
|
generators?: Array<Generator<PluginFaker>>
|
|
133
|
+
/**
|
|
134
|
+
* Override naming conventions for function names and types.
|
|
135
|
+
*/
|
|
136
|
+
resolver?: Partial<ResolverFaker> & ThisType<ResolverFaker>
|
|
137
|
+
/**
|
|
138
|
+
* AST visitor to transform generated nodes.
|
|
139
|
+
*/
|
|
140
|
+
transformer?: ast.Visitor
|
|
141
|
+
/**
|
|
142
|
+
* Override individual faker printer node handlers.
|
|
143
|
+
*/
|
|
144
|
+
printer?: {
|
|
145
|
+
nodes?: PrinterFakerNodes
|
|
146
|
+
}
|
|
109
147
|
}
|
|
110
148
|
|
|
111
149
|
type ResolvedOptions = {
|
|
112
|
-
output: Output
|
|
113
|
-
group:
|
|
150
|
+
output: Output
|
|
151
|
+
group: Group | undefined
|
|
152
|
+
exclude: NonNullable<Options['exclude']>
|
|
153
|
+
include: Options['include']
|
|
114
154
|
override: NonNullable<Options['override']>
|
|
115
|
-
dateType: NonNullable<Options['dateType']>
|
|
116
|
-
integerType: NonNullable<Options['integerType']>
|
|
117
155
|
dateParser: NonNullable<Options['dateParser']>
|
|
118
|
-
unknownType: NonNullable<Options['unknownType']>
|
|
119
|
-
emptySchemaType: NonNullable<Options['emptySchemaType']>
|
|
120
|
-
transformers: NonNullable<Options['transformers']>
|
|
121
|
-
seed: NonNullable<Options['seed']> | undefined
|
|
122
|
-
mapper: NonNullable<Options['mapper']>
|
|
123
156
|
regexGenerator: NonNullable<Options['regexGenerator']>
|
|
157
|
+
mapper: NonNullable<Options['mapper']>
|
|
158
|
+
seed: NonNullable<Options['seed']> | undefined
|
|
159
|
+
locale: Options['locale']
|
|
124
160
|
paramsCasing: Options['paramsCasing']
|
|
161
|
+
printer: Options['printer']
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export type PluginFaker = PluginFactoryOptions<'plugin-faker', Options, ResolvedOptions, ResolverFaker>
|
|
165
|
+
|
|
166
|
+
declare global {
|
|
167
|
+
namespace Kubb {
|
|
168
|
+
interface PluginRegistry {
|
|
169
|
+
'plugin-faker': PluginFaker
|
|
170
|
+
}
|
|
171
|
+
}
|
|
125
172
|
}
|
|
126
|
-
export type PluginFaker = PluginFactoryOptions<'plugin-faker', Options, ResolvedOptions, never, ResolvePathOptions>
|