@kubb/core 5.0.0-beta.41 → 5.0.0-beta.43

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/src/createKubb.ts CHANGED
@@ -5,6 +5,7 @@ import type { FileNode, InputMeta, OperationNode, SchemaNode } from '@kubb/ast'
5
5
  import { HOOK_LISTENERS_PER_PLUGIN } from './constants.ts'
6
6
  import type { Adapter } from './createAdapter.ts'
7
7
  import { type Diagnostic, Diagnostics, type ProblemDiagnostic, type UpdateDiagnostic } from './diagnostics.ts'
8
+ import type { Cache } from './createCache.ts'
8
9
  import { createStorage, type Storage } from './createStorage.ts'
9
10
  import type { GeneratorContext } from './defineGenerator.ts'
10
11
  import type { Middleware } from './defineMiddleware.ts'
@@ -233,6 +234,26 @@ export type Config<TInput = Input> = {
233
234
  * @see {@link Storage} interface for implementing custom backends.
234
235
  */
235
236
  storage: Storage
237
+ /**
238
+ * Incremental build cache. Kubb fingerprints the inputs (spec content, config, plugin options,
239
+ * versions) and, on an unchanged "hot" run, restores the previously generated output instead of
240
+ * regenerating it. Same idea as Nx's computation cache.
241
+ *
242
+ * `defineConfig` enables `fsCache()` (local disk under `node_modules/.cache/kubb`) by default.
243
+ * Pass another backend to change where snapshots live, or `false` to turn caching off. A bare
244
+ * `createKubb` leaves it off unless a cache is provided.
245
+ *
246
+ * @example
247
+ * ```ts
248
+ * import { fsCache } from '@kubb/core'
249
+ *
250
+ * cache: fsCache({ dir: '.kubb-cache' })
251
+ * cache: false
252
+ * ```
253
+ *
254
+ * @see {@link Cache} interface for implementing custom backends.
255
+ */
256
+ cache?: Cache
236
257
  /**
237
258
  * Plugins that run during the build to generate code and transform the AST. Each one processes
238
259
  * the adapter's AST and can emit files for a different target (TypeScript, Zod, Faker). A plugin
@@ -336,7 +357,12 @@ export type Config<TInput = Input> = {
336
357
  * })
337
358
  * ```
338
359
  */
339
- export type UserConfig<TInput = Input> = Omit<Config<TInput>, 'root' | 'plugins' | 'parsers' | 'adapter' | 'storage' | 'reporters'> & {
360
+ export type UserConfig<TInput = Input> = Omit<Config<TInput>, 'root' | 'plugins' | 'parsers' | 'adapter' | 'storage' | 'reporters' | 'cache'> & {
361
+ /**
362
+ * Incremental build cache. Defaults to `fsCache()` (local disk). Pass another {@link Cache}
363
+ * backend, or `false` to turn caching off.
364
+ */
365
+ cache?: Cache | false
340
366
  /**
341
367
  * Project root directory, absolute or relative to the config file location.
342
368
  * @default process.cwd()
@@ -658,7 +684,7 @@ export type KubbDiagnosticContext = {
658
684
 
659
685
  export type KubbFilesProcessingStartContext = {
660
686
  /**
661
- * Files about to be serialised and written.
687
+ * Files about to be serialized and written.
662
688
  */
663
689
  files: Array<FileNode>
664
690
  }
@@ -677,7 +703,7 @@ export type KubbFileProcessingUpdate = {
677
703
  */
678
704
  percentage: number
679
705
  /**
680
- * Serialised file content, or `undefined` when the file produced no output.
706
+ * Serialized file content, or `undefined` when the file produced no output.
681
707
  */
682
708
  source?: string
683
709
  /**
@@ -699,7 +725,7 @@ export type KubbFilesProcessingUpdateContext = {
699
725
 
700
726
  export type KubbFilesProcessingEndContext = {
701
727
  /**
702
- * All files that were serialised in this batch.
728
+ * All files that were serialized in this batch.
703
729
  */
704
730
  files: Array<FileNode>
705
731
  }
@@ -887,6 +913,9 @@ function resolveConfig(userConfig: UserConfig): Config {
887
913
  ...userConfig.output,
888
914
  },
889
915
  storage: userConfig.storage ?? fsStorage(),
916
+ // Resolve `false` to "no cache". The default `fsCache()` is applied by `defineConfig`, not here,
917
+ // so a raw `createKubb` stays deterministic (no surprise on-disk cache) unless a cache is passed.
918
+ cache: userConfig.cache === false ? undefined : userConfig.cache,
890
919
  reporters: userConfig.reporters ?? [],
891
920
  plugins: userConfig.plugins ?? [],
892
921
  }
@@ -14,15 +14,6 @@ export type Renderer<TElement = unknown> = {
14
14
  * Called once per render cycle. Must resolve before {@link files} is read.
15
15
  */
16
16
  render(element: TElement): Promise<void>
17
- /**
18
- * Tears down the renderer and releases any held resources.
19
- * Pass an `Error` to signal a failure, a number for an exit code, or omit for a clean shutdown.
20
- */
21
- unmount(error?: Error | number | null): void
22
- /**
23
- * Releases any held resources. `[Symbol.dispose]` delegates here.
24
- */
25
- dispose(): void
26
17
  /**
27
18
  * Accumulated {@link FileNode} results produced by the last {@link render} call.
28
19
  * Not populated when {@link stream} is implemented.
@@ -35,7 +26,7 @@ export type Renderer<TElement = unknown> = {
35
26
  stream?(element: TElement): Iterable<FileNode>
36
27
  /**
37
28
  * Disposer hook so renderers participate in `using` blocks: `using r = rendererFactory()`
38
- * guarantees {@link dispose} runs on every exit path, including thrown errors.
29
+ * runs cleanup on every exit path, including thrown errors.
39
30
  */
40
31
  [Symbol.dispose](): void
41
32
  }
@@ -70,14 +61,8 @@ export type RendererFactory<TElement = unknown> = () => Renderer<TElement>
70
61
  * get files() {
71
62
  * return runtime.files
72
63
  * },
73
- * dispose() {
74
- * runtime.dispose()
75
- * },
76
- * unmount(error) {
77
- * runtime.dispose(error)
78
- * },
79
64
  * [Symbol.dispose]() {
80
- * this.dispose()
65
+ * runtime.dispose()
81
66
  * },
82
67
  * }
83
68
  * })
@@ -23,7 +23,7 @@ export type Parser<TMeta extends object = object, TNode = unknown> = {
23
23
  */
24
24
  extNames: Array<FileNode['extname']> | undefined
25
25
  /**
26
- * Serialise the file's AST into source code.
26
+ * Serialize the file's AST into source code.
27
27
  */
28
28
  parse(file: FileNode<TMeta>, options?: PrintOptions): string
29
29
  /**
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { AsyncEventEmitter, URLPath } from '@internals/utils'
2
2
  export * as ast from '@kubb/ast'
3
3
  export { createAdapter } from './createAdapter.ts'
4
+ export { createCache } from './createCache.ts'
4
5
  export { Diagnostics } from './diagnostics.ts'
5
6
  export { createKubb } from './createKubb.ts'
6
7
  export { createReporter, selectReporters } from './createReporter.ts'
@@ -17,6 +18,7 @@ export { defineParser } from './defineParser.ts'
17
18
  export { definePlugin } from './definePlugin.ts'
18
19
  export { defineResolver } from './defineResolver.ts'
19
20
  export { KubbDriver } from './KubbDriver.ts'
21
+ export { fsCache } from './caches/fsCache.ts'
20
22
  export { fsStorage } from './storages/fsStorage.ts'
21
23
  export { memoryStorage } from './storages/memoryStorage.ts'
22
24
  export * from './types.ts'
@@ -1,7 +1,6 @@
1
- import type { Dirent } from 'node:fs'
2
- import { access, readdir, readFile, rm } from 'node:fs/promises'
3
- import { join, resolve } from 'node:path'
4
- import { clean, write } from '@internals/utils'
1
+ import { access, glob, readFile, rm } from 'node:fs/promises'
2
+ import { join, relative, resolve } from 'node:path'
3
+ import { clean, isBun, toPosixPath, write } from '@internals/utils'
5
4
  import { createStorage } from '../createStorage.ts'
6
5
 
7
6
  /**
@@ -55,29 +54,22 @@ export const fsStorage = createStorage(() => ({
55
54
  async getKeys(base?: string) {
56
55
  const resolvedBase = resolve(base ?? process.cwd())
57
56
 
58
- async function* walk(dir: string, prefix: string): AsyncGenerator<string, void, undefined> {
59
- let entries: Array<Dirent>
60
- try {
61
- entries = (await readdir(dir, {
62
- withFileTypes: true,
63
- })) as Array<Dirent>
64
- } catch (_error) {
65
- return
66
- }
67
- for (const entry of entries) {
68
- const rel = prefix ? `${prefix}/${entry.name}` : entry.name
69
- if (entry.isDirectory()) {
70
- yield* walk(join(dir, entry.name), rel)
71
- } else {
72
- yield rel
73
- }
74
- }
57
+ if (isBun()) {
58
+ const bunGlob = new Bun.Glob('**/*')
59
+ return Array.fromAsync(bunGlob.scan({ cwd: resolvedBase, onlyFiles: true, dot: true }))
75
60
  }
76
61
 
77
62
  const keys: Array<string> = []
78
- for await (const key of walk(resolvedBase, '')) {
79
- keys.push(key)
63
+ try {
64
+ for await (const entry of glob('**/*', { cwd: resolvedBase, withFileTypes: true })) {
65
+ if (entry.isFile()) {
66
+ keys.push(toPosixPath(relative(resolvedBase, join(entry.parentPath, entry.name))))
67
+ }
68
+ }
69
+ } catch (_error) {
70
+ // base directory does not exist yet
80
71
  }
72
+
81
73
  return keys
82
74
  },
83
75
  async clear(base?: string) {
package/src/types.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export type { Adapter, AdapterFactoryOptions, AdapterSource } from './createAdapter.ts'
2
+ export type { Cache, CachedSnapshot } from './createCache.ts'
3
+ export type { FsCacheOptions } from './caches/fsCache.ts'
2
4
  export type {
3
5
  Diagnostic,
4
6
  DiagnosticByCode,