@kubb/core 5.0.0-alpha.9 → 5.0.0-beta.10

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 (62) hide show
  1. package/README.md +13 -40
  2. package/dist/PluginDriver-Cu1Kj9S-.cjs +1075 -0
  3. package/dist/PluginDriver-Cu1Kj9S-.cjs.map +1 -0
  4. package/dist/PluginDriver-D8Z0Htid.js +978 -0
  5. package/dist/PluginDriver-D8Z0Htid.js.map +1 -0
  6. package/dist/createKubb-ALdb8lmq.d.ts +2082 -0
  7. package/dist/index.cjs +747 -1667
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.ts +175 -269
  10. package/dist/index.js +734 -1638
  11. package/dist/index.js.map +1 -1
  12. package/dist/mocks.cjs +145 -0
  13. package/dist/mocks.cjs.map +1 -0
  14. package/dist/mocks.d.ts +80 -0
  15. package/dist/mocks.js +140 -0
  16. package/dist/mocks.js.map +1 -0
  17. package/package.json +47 -60
  18. package/src/FileManager.ts +115 -0
  19. package/src/FileProcessor.ts +86 -0
  20. package/src/PluginDriver.ts +355 -561
  21. package/src/constants.ts +21 -48
  22. package/src/createAdapter.ts +88 -5
  23. package/src/createKubb.ts +1266 -0
  24. package/src/createRenderer.ts +57 -0
  25. package/src/createStorage.ts +13 -1
  26. package/src/defineGenerator.ts +160 -119
  27. package/src/defineLogger.ts +46 -5
  28. package/src/defineMiddleware.ts +62 -0
  29. package/src/defineParser.ts +44 -0
  30. package/src/definePlugin.ts +379 -0
  31. package/src/defineResolver.ts +548 -25
  32. package/src/devtools.ts +22 -15
  33. package/src/index.ts +13 -15
  34. package/src/mocks.ts +177 -0
  35. package/src/storages/fsStorage.ts +13 -8
  36. package/src/storages/memoryStorage.ts +4 -2
  37. package/src/types.ts +40 -547
  38. package/dist/PluginDriver-BkFepPdm.d.ts +0 -1054
  39. package/dist/chunk-ByKO4r7w.cjs +0 -38
  40. package/dist/hooks.cjs +0 -103
  41. package/dist/hooks.cjs.map +0 -1
  42. package/dist/hooks.d.ts +0 -77
  43. package/dist/hooks.js +0 -98
  44. package/dist/hooks.js.map +0 -1
  45. package/src/Kubb.ts +0 -224
  46. package/src/build.ts +0 -418
  47. package/src/config.ts +0 -56
  48. package/src/createPlugin.ts +0 -28
  49. package/src/hooks/index.ts +0 -4
  50. package/src/hooks/useKubb.ts +0 -143
  51. package/src/hooks/useMode.ts +0 -11
  52. package/src/hooks/usePlugin.ts +0 -11
  53. package/src/hooks/usePluginDriver.ts +0 -11
  54. package/src/utils/FunctionParams.ts +0 -155
  55. package/src/utils/TreeNode.ts +0 -215
  56. package/src/utils/diagnostics.ts +0 -15
  57. package/src/utils/executeStrategies.ts +0 -81
  58. package/src/utils/formatters.ts +0 -56
  59. package/src/utils/getBarrelFiles.ts +0 -141
  60. package/src/utils/getConfigs.ts +0 -12
  61. package/src/utils/linters.ts +0 -25
  62. package/src/utils/packageJSON.ts +0 -61
package/src/devtools.ts CHANGED
@@ -1,10 +1,17 @@
1
- import type { RootNode } from '@kubb/ast/types'
1
+ import type { InputNode } from '@kubb/ast'
2
2
  import { deflateSync, inflateSync } from 'fflate'
3
3
  import { x } from 'tinyexec'
4
- import type { DevtoolsOptions } from './types.ts'
4
+
5
+ export type DevtoolsOptions = {
6
+ /**
7
+ * Open the AST inspector in Kubb Studio (`/ast`). Defaults to the main Studio page.
8
+ * @default false
9
+ */
10
+ ast?: boolean
11
+ }
5
12
 
6
13
  /**
7
- * Encodes a `RootNode` as a compressed, URL-safe string.
14
+ * Encodes an `InputNode` as a compressed, URL-safe string.
8
15
  *
9
16
  * The JSON representation is deflate-compressed with {@link deflateSync} before
10
17
  * base64url encoding, which typically reduces payload size by 70–80 % and
@@ -12,41 +19,41 @@ import type { DevtoolsOptions } from './types.ts'
12
19
  *
13
20
  * Use {@link decodeAst} to reverse.
14
21
  */
15
- export function encodeAst(root: RootNode): string {
16
- const compressed = deflateSync(new TextEncoder().encode(JSON.stringify(root)))
22
+ export function encodeAst(input: InputNode): string {
23
+ const compressed = deflateSync(new TextEncoder().encode(JSON.stringify(input)))
17
24
  return Buffer.from(compressed).toString('base64url')
18
25
  }
19
26
 
20
27
  /**
21
- * Decodes a `RootNode` from a string produced by {@link encodeAst}.
28
+ * Decodes an `InputNode` from a string produced by {@link encodeAst}.
22
29
  *
23
30
  * Works in both Node.js and the browser — no streaming APIs required.
24
31
  */
25
- export function decodeAst(encoded: string): RootNode {
32
+ export function decodeAst(encoded: string): InputNode {
26
33
  const bytes = Buffer.from(encoded, 'base64url')
27
- return JSON.parse(new TextDecoder().decode(inflateSync(bytes))) as RootNode
34
+ return JSON.parse(new TextDecoder().decode(inflateSync(bytes))) as InputNode
28
35
  }
29
36
 
30
37
  /**
31
- * Constructs the Kubb Studio URL for the given `RootNode`.
38
+ * Constructs the Kubb Studio URL for the given `InputNode`.
32
39
  * When `options.ast` is `true`, navigates to the AST inspector (`/ast`).
33
- * The `root` is encoded and attached as the `?root=` query parameter so Studio
40
+ * The `input` is encoded and attached as the `?root=` query parameter so Studio
34
41
  * can decode and render it without a round-trip to any server.
35
42
  */
36
- export function getStudioUrl(root: RootNode, studioUrl: string, options: DevtoolsOptions = {}): string {
43
+ export function getStudioUrl(input: InputNode, studioUrl: string, options: DevtoolsOptions = {}): string {
37
44
  const baseUrl = studioUrl.replace(/\/$/, '')
38
45
  const path = options.ast ? '/ast' : ''
39
46
 
40
- return `${baseUrl}${path}?root=${encodeAst(root)}`
47
+ return `${baseUrl}${path}?root=${encodeAst(input)}`
41
48
  }
42
49
 
43
50
  /**
44
- * Opens the Kubb Studio URL for the given `RootNode` in the default browser —
51
+ * Opens the Kubb Studio URL for the given `InputNode` in the default browser —
45
52
  *
46
53
  * Falls back to printing the URL if the browser cannot be launched.
47
54
  */
48
- export async function openInStudio(root: RootNode, studioUrl: string, options: DevtoolsOptions = {}): Promise<void> {
49
- const url = getStudioUrl(root, studioUrl, options)
55
+ export async function openInStudio(input: InputNode, studioUrl: string, options: DevtoolsOptions = {}): Promise<void> {
56
+ const url = getStudioUrl(input, studioUrl, options)
50
57
 
51
58
  const cmd = process.platform === 'win32' ? 'cmd' : process.platform === 'darwin' ? 'open' : 'xdg-open'
52
59
  const args = process.platform === 'win32' ? ['/c', 'start', '', url] : [url]
package/src/index.ts CHANGED
@@ -1,22 +1,20 @@
1
- export { definePrinter } from '@kubb/ast'
2
- export { build, build as default, safeBuild, setup } from './build.ts'
3
- export { type CLIOptions, type ConfigInput, defineConfig, isInputPath } from './config.ts'
4
- export { formatters, linters, logLevel } from './constants.ts'
1
+ export { AsyncEventEmitter, URLPath } from '@internals/utils'
2
+ export * as ast from '@kubb/ast'
3
+ export { logLevel } from './constants.ts'
5
4
  export { createAdapter } from './createAdapter.ts'
6
- export { createPlugin } from './createPlugin.ts'
5
+ export { createKubb } from './createKubb.ts'
6
+ export { createRenderer } from './createRenderer.ts'
7
7
  export { createStorage } from './createStorage.ts'
8
8
  export { defineGenerator } from './defineGenerator.ts'
9
9
  export { defineLogger } from './defineLogger.ts'
10
- export { defaultResolveOptions, defineResolver } from './defineResolver.ts'
11
- export { getMode, PluginDriver } from './PluginDriver.ts'
10
+ export { defineMiddleware } from './defineMiddleware.ts'
11
+ export { defineParser } from './defineParser.ts'
12
+ export { definePlugin } from './definePlugin.ts'
13
+ export { defineResolver } from './defineResolver.ts'
14
+ export { FileManager } from './FileManager.ts'
15
+ export { FileProcessor } from './FileProcessor.ts'
16
+ export { PluginDriver } from './PluginDriver.ts'
12
17
  export { fsStorage } from './storages/fsStorage.ts'
13
18
  export { memoryStorage } from './storages/memoryStorage.ts'
14
19
  export * from './types.ts'
15
- export type { FunctionParamsAST } from './utils/FunctionParams.ts'
16
- export { FunctionParams } from './utils/FunctionParams.ts'
17
- export { detectFormatter } from './utils/formatters.ts'
18
- export type { FileMetaBase } from './utils/getBarrelFiles.ts'
19
- export { getBarrelFiles } from './utils/getBarrelFiles.ts'
20
- export { getConfigs } from './utils/getConfigs.ts'
21
- export { detectLinter } from './utils/linters.ts'
22
- export { satisfiesDependency } from './utils/packageJSON.ts'
20
+ export { isInputPath } from './createKubb.ts'
package/src/mocks.ts ADDED
@@ -0,0 +1,177 @@
1
+ import { resolve } from 'node:path'
2
+ import type { FileNode, OperationNode, SchemaNode, Visitor } from '@kubb/ast'
3
+ import { transform } from '@kubb/ast'
4
+ import { FileManager } from './FileManager.ts'
5
+ import { applyHookResult, PluginDriver } from './PluginDriver.ts'
6
+ import type { Adapter, AdapterFactoryOptions, Config, Generator, GeneratorContext, NormalizedPlugin, PluginFactoryOptions } from './types.ts'
7
+
8
+ /**
9
+
10
+ * Creates a minimal `PluginDriver` mock for unit tests.
11
+ */
12
+ export function createMockedPluginDriver(options: { name?: string; plugin?: NormalizedPlugin; config?: Config } = {}): PluginDriver {
13
+ return {
14
+ config: options?.config ?? {
15
+ root: '.',
16
+ output: {
17
+ path: './path',
18
+ },
19
+ },
20
+ getPlugin(_pluginName: string): NormalizedPlugin | undefined {
21
+ return options?.plugin
22
+ },
23
+ getResolver: (_pluginName: string) => options?.plugin?.resolver,
24
+ fileManager: new FileManager(),
25
+ } as unknown as PluginDriver
26
+ }
27
+
28
+ /**
29
+ * Creates a minimal `Adapter` mock for unit tests.
30
+ * `parse` returns an empty `InputNode` by default; override via `options.parse`.
31
+ * `getImports` returns `[]` by default.
32
+ */
33
+ export function createMockedAdapter<TOptions extends AdapterFactoryOptions = AdapterFactoryOptions>(
34
+ options: {
35
+ name?: TOptions['name']
36
+ resolvedOptions?: TOptions['resolvedOptions']
37
+ inputNode?: Adapter<TOptions>['inputNode']
38
+ parse?: Adapter<TOptions>['parse']
39
+ getImports?: Adapter<TOptions>['getImports']
40
+ } = {},
41
+ ): Adapter<TOptions> {
42
+ const inputNode = options.inputNode ?? null
43
+ return {
44
+ name: (options.name ?? 'oas') as TOptions['name'],
45
+ options: (options.resolvedOptions ?? {}) as TOptions['resolvedOptions'],
46
+ inputNode,
47
+ parse: options.parse ?? (async () => ({ kind: 'Input' as const, schemas: [], operations: [] })),
48
+ getImports: options.getImports ?? ((_node: SchemaNode, _resolve: (schemaName: string) => { name: string; path: string }) => []),
49
+ } as Adapter<TOptions>
50
+ }
51
+
52
+ /**
53
+ * Creates a minimal plugin mock for unit tests.
54
+ *
55
+ * @example
56
+ * `const plugin = createMockedPlugin<PluginTs>({ name: '@kubb/plugin-ts', options })`
57
+ */
58
+ export function createMockedPlugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions>(params: {
59
+ name: TOptions['name']
60
+ options: TOptions['resolvedOptions']
61
+ resolver?: TOptions['resolver']
62
+ transformer?: Visitor
63
+ dependencies?: Array<string>
64
+ }): NormalizedPlugin<TOptions> {
65
+ return {
66
+ name: params.name,
67
+ options: params.options,
68
+ resolver: params.resolver,
69
+ transformer: params.transformer,
70
+ dependencies: params.dependencies,
71
+ hooks: {},
72
+ } as unknown as NormalizedPlugin<TOptions>
73
+ }
74
+
75
+ type RenderGeneratorOptions<TOptions extends PluginFactoryOptions> = {
76
+ config: Config
77
+ adapter: Adapter
78
+ driver: PluginDriver
79
+ plugin: NormalizedPlugin<TOptions>
80
+ options: TOptions['resolvedOptions']
81
+ resolver: TOptions['resolver']
82
+ }
83
+
84
+ function createMockedPluginContext<TOptions extends PluginFactoryOptions>(opts: RenderGeneratorOptions<TOptions>): Omit<GeneratorContext<TOptions>, 'options'> {
85
+ const root = resolve(opts.config.root, opts.config.output.path)
86
+
87
+ return {
88
+ config: opts.config,
89
+ root,
90
+ getMode: (output: { path: string }) => PluginDriver.getMode(resolve(root, output.path)),
91
+ adapter: opts.adapter,
92
+ resolver: opts.resolver,
93
+ plugin: opts.plugin,
94
+ driver: opts.driver,
95
+ getResolver: (name: string) => opts.driver.getResolver(name),
96
+ inputNode: { kind: 'Input', schemas: [], operations: [] },
97
+ addFile: async (...files: Array<FileNode>) => opts.driver.fileManager.add(...files),
98
+ upsertFile: async (...files: Array<FileNode>) => opts.driver.fileManager.upsert(...files),
99
+ hooks: opts.driver.hooks ?? ({} as never),
100
+ warn: (msg: string) => console.warn(msg),
101
+ error: (msg: string) => console.error(msg),
102
+ info: (msg: string) => console.info(msg),
103
+ openInStudio: async () => {},
104
+ } as unknown as Omit<GeneratorContext<TOptions>, 'options'>
105
+ }
106
+
107
+ /**
108
+ * Renders a generator's `schema` method in a test context.
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * await renderGeneratorSchema(typeGenerator, node, { config, adapter, driver, plugin, options, resolver })
113
+ * await matchFiles(driver.fileManager.files)
114
+ * ```
115
+ */
116
+ export async function renderGeneratorSchema<TOptions extends PluginFactoryOptions>(
117
+ generator: Generator<TOptions>,
118
+ node: SchemaNode,
119
+ opts: RenderGeneratorOptions<TOptions>,
120
+ ): Promise<void> {
121
+ if (!generator.schema) return
122
+ const context = createMockedPluginContext(opts)
123
+ const transformedNode = opts.plugin.transformer ? transform(node, opts.plugin.transformer) : node
124
+ const result = await generator.schema(transformedNode, {
125
+ ...context,
126
+ options: opts.options,
127
+ })
128
+ await applyHookResult(result, opts.driver, generator.renderer ?? undefined)
129
+ }
130
+
131
+ /**
132
+ * Renders a generator's `operation` method in a test context.
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * await renderGeneratorOperation(typeGenerator, node, { config, adapter, driver, plugin, options, resolver })
137
+ * await matchFiles(driver.fileManager.files)
138
+ * ```
139
+ */
140
+ export async function renderGeneratorOperation<TOptions extends PluginFactoryOptions>(
141
+ generator: Generator<TOptions>,
142
+ node: OperationNode,
143
+ opts: RenderGeneratorOptions<TOptions>,
144
+ ): Promise<void> {
145
+ if (!generator.operation) return
146
+ const context = createMockedPluginContext(opts)
147
+ const transformedNode = opts.plugin.transformer ? transform(node, opts.plugin.transformer) : node
148
+ const result = await generator.operation(transformedNode, {
149
+ ...context,
150
+ options: opts.options,
151
+ })
152
+ await applyHookResult(result, opts.driver, generator.renderer ?? undefined)
153
+ }
154
+
155
+ /**
156
+ * Renders a generator's `operations` method in a test context.
157
+ *
158
+ * @example
159
+ * ```ts
160
+ * await renderGeneratorOperations(classClientGenerator, nodes, { config, adapter, driver, plugin, options, resolver })
161
+ * await matchFiles(driver.fileManager.files)
162
+ * ```
163
+ */
164
+ export async function renderGeneratorOperations<TOptions extends PluginFactoryOptions>(
165
+ generator: Generator<TOptions>,
166
+ nodes: Array<OperationNode>,
167
+ opts: RenderGeneratorOptions<TOptions>,
168
+ ): Promise<void> {
169
+ if (!generator.operations) return
170
+ const context = createMockedPluginContext(opts)
171
+ const transformedNodes = opts.plugin.transformer ? nodes.map((n) => transform(n, opts.plugin.transformer!)) : nodes
172
+ const result = await generator.operations(transformedNodes, {
173
+ ...context,
174
+ options: opts.options,
175
+ })
176
+ await applyHookResult(result, opts.driver, generator.renderer ?? undefined)
177
+ }
@@ -7,7 +7,7 @@ import { createStorage } from '../createStorage.ts'
7
7
  /**
8
8
  * Built-in filesystem storage driver.
9
9
  *
10
- * This is the default storage when no `storage` option is configured in `output`.
10
+ * This is the default storage when no `storage` option is configured in the root config.
11
11
  * Keys are resolved against `process.cwd()`, so root-relative paths such as
12
12
  * `src/gen/api/getPets.ts` are written to the correct location without extra configuration.
13
13
  *
@@ -19,11 +19,13 @@ import { createStorage } from '../createStorage.ts'
19
19
  *
20
20
  * @example
21
21
  * ```ts
22
- * import { defineConfig, fsStorage } from '@kubb/core'
22
+ * import { fsStorage } from '@kubb/core'
23
+ * import { defineConfig } from 'kubb'
23
24
  *
24
25
  * export default defineConfig({
25
26
  * input: { path: './petStore.yaml' },
26
- * output: { path: './src/gen', storage: fsStorage() },
27
+ * output: { path: './src/gen' },
28
+ * storage: fsStorage(),
27
29
  * })
28
30
  * ```
29
31
  */
@@ -33,14 +35,14 @@ export const fsStorage = createStorage(() => ({
33
35
  try {
34
36
  await access(resolve(key))
35
37
  return true
36
- } catch {
38
+ } catch (_error) {
37
39
  return false
38
40
  }
39
41
  },
40
42
  async getItem(key: string) {
41
43
  try {
42
44
  return await readFile(resolve(key), 'utf8')
43
- } catch {
45
+ } catch (_error) {
44
46
  return null
45
47
  }
46
48
  },
@@ -52,12 +54,15 @@ export const fsStorage = createStorage(() => ({
52
54
  },
53
55
  async getKeys(base?: string) {
54
56
  const keys: Array<string> = []
57
+ const resolvedBase = resolve(base ?? process.cwd())
55
58
 
56
59
  async function walk(dir: string, prefix: string): Promise<void> {
57
60
  let entries: Array<Dirent>
58
61
  try {
59
- entries = (await readdir(dir, { withFileTypes: true })) as Array<Dirent>
60
- } catch {
62
+ entries = (await readdir(dir, {
63
+ withFileTypes: true,
64
+ })) as Array<Dirent>
65
+ } catch (_error) {
61
66
  return
62
67
  }
63
68
  for (const entry of entries) {
@@ -70,7 +75,7 @@ export const fsStorage = createStorage(() => ({
70
75
  }
71
76
  }
72
77
 
73
- await walk(resolve(base ?? process.cwd()), '')
78
+ await walk(resolvedBase, '')
74
79
 
75
80
  return keys
76
81
  },
@@ -9,11 +9,13 @@ import { createStorage } from '../createStorage.ts'
9
9
  *
10
10
  * @example
11
11
  * ```ts
12
- * import { defineConfig, memoryStorage } from '@kubb/core'
12
+ * import { memoryStorage } from '@kubb/core'
13
+ * import { defineConfig } from 'kubb'
13
14
  *
14
15
  * export default defineConfig({
15
16
  * input: { path: './petStore.yaml' },
16
- * output: { path: './src/gen', storage: memoryStorage() },
17
+ * output: { path: './src/gen' },
18
+ * storage: memoryStorage(),
17
19
  * })
18
20
  * ```
19
21
  */