@kubb/plugin-faker 5.0.0-alpha.9 → 5.0.0-beta.4

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.
Files changed (44) hide show
  1. package/LICENSE +17 -10
  2. package/README.md +1 -4
  3. package/dist/Faker-BgleOzVN.cjs +486 -0
  4. package/dist/Faker-BgleOzVN.cjs.map +1 -0
  5. package/dist/Faker-CdyPfOPg.d.ts +27 -0
  6. package/dist/Faker-fcQEB9i5.js +384 -0
  7. package/dist/Faker-fcQEB9i5.js.map +1 -0
  8. package/dist/components.cjs +2 -2
  9. package/dist/components.d.ts +2 -31
  10. package/dist/components.js +1 -1
  11. package/dist/fakerGenerator-C3Ho3BaI.d.ts +9 -0
  12. package/dist/fakerGenerator-D7daHCh6.js +516 -0
  13. package/dist/fakerGenerator-D7daHCh6.js.map +1 -0
  14. package/dist/fakerGenerator-VJEVzLjc.cjs +526 -0
  15. package/dist/fakerGenerator-VJEVzLjc.cjs.map +1 -0
  16. package/dist/generators.cjs +1 -1
  17. package/dist/generators.d.ts +2 -505
  18. package/dist/generators.js +1 -1
  19. package/dist/index.cjs +136 -84
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.ts +28 -4
  22. package/dist/index.js +128 -83
  23. package/dist/index.js.map +1 -1
  24. package/dist/printerFaker-CJiwzoto.d.ts +206 -0
  25. package/extension.yaml +364 -0
  26. package/package.json +52 -50
  27. package/src/components/Faker.tsx +124 -78
  28. package/src/generators/fakerGenerator.tsx +235 -134
  29. package/src/index.ts +7 -2
  30. package/src/plugin.ts +60 -121
  31. package/src/printers/printerFaker.ts +341 -0
  32. package/src/resolvers/resolverFaker.ts +92 -0
  33. package/src/types.ts +127 -81
  34. package/src/utils.ts +356 -0
  35. package/dist/components-BkBIov4R.js +0 -419
  36. package/dist/components-BkBIov4R.js.map +0 -1
  37. package/dist/components-IdP8GXXX.cjs +0 -461
  38. package/dist/components-IdP8GXXX.cjs.map +0 -1
  39. package/dist/fakerGenerator-CYUCNH3Q.cjs +0 -204
  40. package/dist/fakerGenerator-CYUCNH3Q.cjs.map +0 -1
  41. package/dist/fakerGenerator-M5oCrPmy.js +0 -200
  42. package/dist/fakerGenerator-M5oCrPmy.js.map +0 -1
  43. package/dist/types-r7BubMLO.d.ts +0 -132
  44. package/src/parser.ts +0 -453
package/package.json CHANGED
@@ -1,35 +1,56 @@
1
1
  {
2
2
  "name": "@kubb/plugin-faker",
3
- "version": "5.0.0-alpha.9",
3
+ "version": "5.0.0-beta.4",
4
4
  "description": "Faker.js data generator plugin for Kubb, creating realistic mock data from OpenAPI specifications for development and testing.",
5
5
  "keywords": [
6
+ "code-generator",
7
+ "codegen",
8
+ "data-generation",
9
+ "development",
6
10
  "faker",
7
11
  "faker.js",
8
12
  "fakerjs",
13
+ "fixtures",
14
+ "kubb",
9
15
  "mock-data",
10
16
  "mocks",
11
- "data-generation",
12
- "fixtures",
13
- "testing",
14
- "development",
15
- "typescript",
16
- "openapi",
17
- "swagger",
18
17
  "oas",
19
- "code-generator",
20
- "codegen",
18
+ "openapi",
21
19
  "plugins",
22
- "kubb"
20
+ "swagger",
21
+ "testing",
22
+ "typescript"
23
23
  ],
24
+ "license": "MIT",
25
+ "author": "stijnvanhulle",
24
26
  "repository": {
25
27
  "type": "git",
26
- "url": "git+https://github.com/kubb-labs/kubb.git",
28
+ "url": "git+https://github.com/kubb-labs/plugins.git",
27
29
  "directory": "packages/plugin-faker"
28
30
  },
29
- "license": "MIT",
30
- "author": "stijnvanhulle",
31
- "sideEffects": false,
31
+ "files": [
32
+ "src",
33
+ "dist",
34
+ "extension.yaml",
35
+ "!/**/**.test.**",
36
+ "!/**/__tests__/**",
37
+ "!/**/__snapshots__/**"
38
+ ],
32
39
  "type": "module",
40
+ "sideEffects": false,
41
+ "main": "./dist/index.cjs",
42
+ "module": "./dist/index.js",
43
+ "types": "./dist/index.d.ts",
44
+ "typesVersions": {
45
+ "*": {
46
+ "components": [
47
+ "./dist/components.d.ts"
48
+ ],
49
+ "generators": [
50
+ "./dist/generators.d.ts"
51
+ ]
52
+ }
53
+ },
33
54
  "exports": {
34
55
  ".": {
35
56
  "import": "./dist/index.js",
@@ -45,24 +66,21 @@
45
66
  },
46
67
  "./package.json": "./package.json"
47
68
  },
48
- "types": "./dist/index.d.ts",
49
- "typesVersions": {
50
- "*": {
51
- "components": [
52
- "./dist/components.d.ts"
53
- ],
54
- "generators": [
55
- "./dist/generators.d.ts"
56
- ]
57
- }
69
+ "publishConfig": {
70
+ "access": "public",
71
+ "registry": "https://registry.npmjs.org/"
72
+ },
73
+ "dependencies": {
74
+ "@kubb/core": "5.0.0-beta.4",
75
+ "@kubb/renderer-jsx": "5.0.0-beta.4",
76
+ "@kubb/plugin-ts": "5.0.0-beta.4"
77
+ },
78
+ "devDependencies": {
79
+ "@internals/utils": "0.0.0"
80
+ },
81
+ "peerDependencies": {
82
+ "@kubb/renderer-jsx": "5.0.0-beta.4"
58
83
  },
59
- "files": [
60
- "src",
61
- "dist",
62
- "!/**/**.test.**",
63
- "!/**/__tests__/**",
64
- "!/**/__snapshots__/**"
65
- ],
66
84
  "size-limit": [
67
85
  {
68
86
  "path": "./dist/*.js",
@@ -70,30 +88,14 @@
70
88
  "gzip": true
71
89
  }
72
90
  ],
73
- "dependencies": {
74
- "@kubb/react-fabric": "0.14.0",
75
- "@kubb/oas": "5.0.0-alpha.9",
76
- "@kubb/core": "5.0.0-alpha.9",
77
- "@kubb/plugin-oas": "5.0.0-alpha.9",
78
- "@kubb/plugin-ts": "5.0.0-alpha.9"
79
- },
80
91
  "engines": {
81
92
  "node": ">=22"
82
93
  },
83
- "publishConfig": {
84
- "access": "public",
85
- "registry": "https://registry.npmjs.org/"
86
- },
87
- "main": "./dist/index.cjs",
88
- "module": "./dist/index.js",
89
- "devDependencies": {
90
- "@internals/utils": "0.0.0"
91
- },
92
94
  "scripts": {
93
95
  "build": "tsdown && size-limit",
94
96
  "clean": "npx rimraf ./dist",
95
- "lint": "bun biome lint .",
96
- "lint:fix": "bun biome lint --fix --unsafe .",
97
+ "lint": "oxlint .",
98
+ "lint:fix": "oxlint --fix .",
97
99
  "release": "pnpm publish --no-git-check",
98
100
  "release:canary": "bash ../../.github/canary.sh && node ../../scripts/build.js canary && pnpm publish --no-git-check",
99
101
  "start": "tsdown --watch",
@@ -1,107 +1,153 @@
1
1
  import { jsStringEscape } from '@internals/utils'
2
- import type { Schema } from '@kubb/plugin-oas'
3
- import { isKeyword, schemaKeywords } from '@kubb/plugin-oas'
4
- import { File, Function, FunctionParams } from '@kubb/react-fabric'
5
- import type { FabricReactNode } from '@kubb/react-fabric/types'
6
- import * as parserFaker from '../parser.ts'
2
+ import { ast } from '@kubb/core'
3
+ import { functionPrinter } from '@kubb/plugin-ts'
4
+ import { File, Function } from '@kubb/renderer-jsx'
5
+ import type { KubbReactNode } from '@kubb/renderer-jsx/types'
6
+ import type { PrinterFakerFactory } from '../printers/printerFaker.ts'
7
7
  import type { PluginFaker } from '../types.ts'
8
+ import { resolveFakerTypeUsage } from '../utils.ts'
8
9
 
9
10
  type Props = {
10
11
  name: string
11
12
  typeName: string
12
- tree: Array<Schema>
13
+ node: ast.SchemaNode
14
+ printer: ast.Printer<PrinterFakerFactory>
13
15
  seed?: PluginFaker['options']['seed']
14
16
  description?: string
15
- regexGenerator?: PluginFaker['options']['regexGenerator']
16
- mapper?: PluginFaker['options']['mapper']
17
- dateParser?: PluginFaker['options']['dateParser']
18
17
  canOverride: boolean
19
18
  }
20
19
 
21
- export function Faker({ tree, description, name, typeName, seed, regexGenerator, canOverride, mapper, dateParser }: Props): FabricReactNode {
22
- const fakerText = parserFaker.joinItems(
23
- tree
24
- .map((schema, _index, siblings) =>
25
- parserFaker.parse(
26
- { name, schema, parent: undefined, current: schema, siblings },
27
- {
28
- typeName,
29
- rootTypeName: name,
30
- regexGenerator,
31
- mapper,
32
- canOverride,
33
- dateParser,
34
- },
35
- ),
36
- )
37
- .filter((x): x is string => Boolean(x)),
38
- )
39
-
40
- const isArray = fakerText.startsWith('faker.helpers.arrayElements') || fakerText.startsWith('faker.helpers.multiple')
41
- const isRefToArray = tree.some((s) => isKeyword(s, schemaKeywords.schema) && s.args.type === 'array')
42
- const isObject = fakerText.startsWith('{')
43
- const isTuple = fakerText.startsWith('faker.helpers.arrayElement')
44
-
45
- const isSimpleString = name === 'string'
46
- const isSimpleInt = name === 'integer'
47
- const isSimpleFloat = name === 'float'
20
+ const OBJECT_TYPES = new Set<ast.SchemaNode['type']>(['object', 'intersection'])
21
+ const ARRAY_TYPES = new Set<ast.SchemaNode['type']>(['array'])
22
+ const SCALAR_TYPES = new Set<ast.SchemaNode['type']>([
23
+ 'string',
24
+ 'email',
25
+ 'url',
26
+ 'uuid',
27
+ 'number',
28
+ 'integer',
29
+ 'bigint',
30
+ 'boolean',
31
+ 'date',
32
+ 'time',
33
+ 'datetime',
34
+ 'blob',
35
+ 'enum',
36
+ ])
37
+ const declarationPrinter = functionPrinter({ mode: 'declaration' })
38
+
39
+ export function Faker({ node, description, name, typeName, printer, seed, canOverride }: Props): KubbReactNode {
40
+ const fakerText = printer.print(node) ?? 'undefined'
41
+
42
+ const isArray = ARRAY_TYPES.has(node.type)
43
+ const isObject = OBJECT_TYPES.has(node.type)
44
+ const isTuple = node.type === 'tuple'
45
+ const isScalar = SCALAR_TYPES.has(node.type)
48
46
 
49
47
  let fakerTextWithOverride = fakerText
48
+ let useGenericOverride = false
50
49
 
51
50
  if (canOverride && isObject) {
52
- fakerTextWithOverride = `{
53
- ...${fakerText},
54
- ...data || {}
55
- }`
51
+ useGenericOverride = true
56
52
  }
57
53
 
58
- if (canOverride && isTuple) fakerTextWithOverride = `data || ${fakerText}`
54
+ if (canOverride && isTuple) {
55
+ fakerTextWithOverride = `data || ${fakerText}`
56
+ }
59
57
 
60
58
  if (canOverride && isArray) {
61
59
  fakerTextWithOverride = `[
62
- ...${fakerText},
63
- ...data || []
64
- ]`
60
+ ...${fakerText},
61
+ ...(data || [])
62
+ ]`
65
63
  }
66
64
 
67
- if (canOverride && isSimpleString) fakerTextWithOverride = 'data ?? faker.string.alpha()'
68
-
69
- if (canOverride && isSimpleInt) fakerTextWithOverride = 'data ?? faker.number.int()'
70
-
71
- if (canOverride && isSimpleFloat) fakerTextWithOverride = 'data ?? faker.number.float()'
72
-
73
- let type = `Partial<${typeName}>`
74
-
75
- if (isArray) type = typeName
76
- if (isRefToArray) type = typeName
77
- if (isSimpleString) type = name
78
- if (isSimpleInt || isSimpleFloat) type = 'number'
79
-
80
- const params = FunctionParams.factory({
81
- data: {
82
- // making a partial out of an array does not make sense
83
- type,
84
- optional: true,
85
- },
86
- })
87
-
88
- let returnType = canOverride ? typeName : undefined
65
+ if (canOverride && isScalar) {
66
+ fakerTextWithOverride = `data ?? ${fakerText}`
67
+ }
89
68
 
90
- if (isSimpleString || isSimpleInt || isSimpleFloat) returnType = type
69
+ const { dataType, returnType: resolvedReturnType } = resolveFakerTypeUsage(node, typeName, canOverride)
70
+
71
+ let functionSignature = ''
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 {
112
+ const usesData = /\bdata\b/.test(fakerTextWithOverride)
113
+ const dataParamName = usesData ? 'data' : '_data'
114
+ const params = ast.createFunctionParameters({
115
+ params: [
116
+ ast.createFunctionParameter({
117
+ name: dataParamName,
118
+ type: ast.createParamsType({ variant: 'reference', name: dataType }),
119
+ optional: true,
120
+ }),
121
+ ],
122
+ })
123
+ const paramsSignature = declarationPrinter.print(params) ?? ''
124
+ const returnType = resolvedReturnType
125
+
126
+ return (
127
+ <File.Source name={name} isExportable isIndexable>
128
+ <Function
129
+ export
130
+ name={name}
131
+ JSDoc={{ comments: description ? [`@description ${jsStringEscape(description)}`] : [] }}
132
+ params={canOverride ? paramsSignature : undefined}
133
+ returnType={returnType}
134
+ >
135
+ {seed ? (
136
+ <>
137
+ {`faker.seed(${JSON.stringify(seed)})`}
138
+ <br />
139
+ </>
140
+ ) : undefined}
141
+ {`return ${fakerTextWithOverride}`}
142
+ </Function>
143
+ </File.Source>
144
+ )
145
+ }
91
146
 
92
147
  return (
93
148
  <File.Source name={name} isExportable isIndexable>
94
- <Function
95
- export
96
- name={name}
97
- JSDoc={{ comments: [description ? `@description ${jsStringEscape(description)}` : undefined].filter(Boolean) }}
98
- params={canOverride ? params.toConstructor() : undefined}
99
- returnType={returnType}
100
- >
101
- {seed ? `faker.seed(${JSON.stringify(seed)})` : undefined}
102
- <br />
103
- {`return ${fakerTextWithOverride}`}
104
- </Function>
149
+ {functionSignature}
150
+ {functionBody}
105
151
  </File.Source>
106
152
  )
107
153
  }