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

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/dist/mocks.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_memoryStorage = require("./memoryStorage-Dkxnid2K.cjs");
2
+ const require_memoryStorage = require("./memoryStorage-DZqlEW7H.cjs");
3
3
  let node_path = require("node:path");
4
4
  node_path = require_memoryStorage.__toESM(node_path, 1);
5
5
  let _kubb_ast = require("@kubb/ast");
package/dist/mocks.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as __name } from "./chunk-C0LytTxp.js";
2
- import { It as Adapter, Lt as AdapterFactoryOptions, V as Generator, W as KubbDriver, Z as NormalizedPlugin, gt as Parser, h as Config, tt as PluginFactoryOptions } from "./diagnostics-DhfW8YpT.js";
2
+ import { G as KubbDriver, H as Generator, Lt as Adapter, Q as NormalizedPlugin, Rt as AdapterFactoryOptions, _t as Parser, h as Config, nt as PluginFactoryOptions } from "./diagnostics-Ba-FcsPo.js";
3
3
  import { FileNode, InputMeta, OperationNode, SchemaNode, Visitor } from "@kubb/ast";
4
4
 
5
5
  //#region src/mocks.d.ts
package/dist/mocks.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "./chunk-C0LytTxp.js";
2
- import { a as FileManager, i as FileProcessor, m as camelCase, n as KubbDriver, r as _usingCtx, t as memoryStorage } from "./memoryStorage-DTv1Kub1.js";
2
+ import { a as FileManager, i as FileProcessor, m as camelCase, n as KubbDriver, r as _usingCtx, t as memoryStorage } from "./memoryStorage-DA1bnMte.js";
3
3
  import path, { resolve } from "node:path";
4
4
  import { transform } from "@kubb/ast";
5
5
  import { expect } from "vitest";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/core",
3
- "version": "5.0.0-beta.40",
3
+ "version": "5.0.0-beta.41",
4
4
  "description": "Core engine for Kubb's plugin-based code generation system. Provides the plugin driver, file manager, defineConfig, and build orchestration used by every Kubb plugin.",
5
5
  "keywords": [
6
6
  "code-generator",
@@ -58,14 +58,14 @@
58
58
  "dependencies": {
59
59
  "fflate": "^0.8.3",
60
60
  "tinyexec": "~1.1.2",
61
- "@kubb/ast": "5.0.0-beta.40"
61
+ "@kubb/ast": "5.0.0-beta.41"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@internals/utils": "0.0.0",
65
- "@kubb/renderer-jsx": "5.0.0-beta.40"
65
+ "@kubb/renderer-jsx": "5.0.0-beta.41"
66
66
  },
67
67
  "peerDependencies": {
68
- "@kubb/renderer-jsx": "5.0.0-beta.40"
68
+ "@kubb/renderer-jsx": "5.0.0-beta.41"
69
69
  },
70
70
  "size-limit": [
71
71
  {
package/src/KubbDriver.ts CHANGED
@@ -473,6 +473,11 @@ export class KubbDriver {
473
473
  * A failing plugin contributes an error diagnostic so the rest of the build continues.
474
474
  * Every plugin also contributes a `timing` diagnostic.
475
475
  *
476
+ * Plugins run sequentially so `kubb:plugin:end` fires as each plugin completes, instead
477
+ * of all at once after every plugin has marched through the parallel batches together.
478
+ * That ordering is what drives the CLI's `Plugins N/M` counter; without it the bar would
479
+ * sit at the initial value until the very end of the run.
480
+ *
476
481
  * When `entries` is empty or `this.inputNode` is `null`, every entry still gets a
477
482
  * `kubb:plugin:end` so middleware listeners (the barrel writer and friends) complete.
478
483
  */
@@ -526,22 +531,27 @@ export class KubbDriver {
526
531
 
527
532
  const emitsSchemaHook = this.hooks.listenerCount('kubb:generate:schema') > 0
528
533
  const emitsOperationHook = this.hooks.listenerCount('kubb:generate:operation') > 0
534
+ const emitsOperationsHook = this.hooks.listenerCount('kubb:generate:operations') > 0
535
+
536
+ // Buffer the streaming adapter's nodes once. Each plugin reads the same buffer
537
+ // instead of re-parsing the document per pass, and the pruning pre-scan below
538
+ // shares it too (previously it iterated its own copies).
539
+ const schemasBuffer: Array<SchemaNode> = []
540
+ for await (const schema of schemas) schemasBuffer.push(schema)
541
+ const operationsBuffer: Array<OperationNode> = []
542
+ for await (const operation of operations) operationsBuffer.push(operation)
529
543
 
530
544
  // Pre-scan: plugins with operation-based includes (but no schemaName include) need
531
545
  // the reachable schema set. This requires the full schema graph in memory at once,
532
- // since transitive reachability can't be derived from a single node. `allSchemas` is
533
- // released as soon as the pre-scan returns, so the main passes get fresh iterators.
546
+ // since transitive reachability can't be derived from a single node.
534
547
  const pruningStates = states.filter(({ plugin }) => {
535
548
  const { include } = plugin.options
536
549
  return (include?.some(({ type }) => OPERATION_FILTER_TYPES.has(type)) ?? false) && !(include?.some(({ type }) => type === 'schemaName') ?? false)
537
550
  })
538
551
 
539
552
  if (pruningStates.length > 0) {
540
- const allSchemas: Array<SchemaNode> = []
541
- for await (const schema of schemas) allSchemas.push(schema)
542
-
543
553
  const includedOpsByState = new Map<PluginState, Array<OperationNode>>(pruningStates.map((state) => [state, []]))
544
- for await (const operation of operations) {
554
+ for (const operation of operationsBuffer) {
545
555
  for (const state of pruningStates) {
546
556
  const { exclude, include, override } = state.plugin.options
547
557
  const options = state.generatorContext.resolver.resolveOptions(operation, { options: state.plugin.options, exclude, include, override })
@@ -550,7 +560,7 @@ export class KubbDriver {
550
560
  }
551
561
 
552
562
  for (const state of pruningStates) {
553
- state.allowedSchemaNames = collectUsedSchemaNames(includedOpsByState.get(state) ?? [], allSchemas)
563
+ state.allowedSchemaNames = collectUsedSchemaNames(includedOpsByState.get(state) ?? [], schemasBuffer)
554
564
  includedOpsByState.delete(state)
555
565
  }
556
566
  }
@@ -628,30 +638,29 @@ export class KubbDriver {
628
638
  emit: emitsOperationHook ? (node: OperationNode, ctx: GeneratorContext) => this.hooks.emit('kubb:generate:operation', node, ctx) : null,
629
639
  } as const
630
640
 
631
- // Skip building the aggregated operations array when nothing consumes it. Saves an
632
- // N-sized allocation on the common path where plugins only define per-node `gen.operation`.
633
- const needsCollectedOperations =
634
- this.hooks.listenerCount('kubb:generate:operations') > 0 || states.some((state) => state.generators.some((gen) => !!gen.operations))
635
- const collectedOperations: Array<OperationNode> | undefined = needsCollectedOperations ? [] : undefined
636
-
637
- // Run schemas before operations: the two passes share `flushPending` and the
638
- // FileProcessor's event emitter, so running them concurrently would interleave
639
- // `kubb:files:processing:start|end` events and race on the shared dirty list.
640
- await forBatches(schemas, (nodes) => Promise.all(nodes.flatMap((node) => states.map((state) => dispatchNode(state, node, schemaDispatch)))), {
641
- concurrency: SCHEMA_PARALLEL,
642
- flush: flushPending,
643
- })
641
+ for (const state of states) {
642
+ // Skip building the aggregated operations array when this plugin doesn't consume it.
643
+ // Saves an N-sized allocation when the plugin only defines per-node `gen.operation`.
644
+ const needsCollectedOperations = emitsOperationsHook || state.generators.some((gen) => !!gen.operations)
645
+ const collectedOperations: Array<OperationNode> | undefined = needsCollectedOperations ? [] : undefined
646
+
647
+ // Run schemas before operations: the two passes share `flushPending` and the
648
+ // FileProcessor's event emitter, so running them concurrently would interleave
649
+ // `kubb:files:processing:start|end` events and race on the shared dirty list.
650
+ await forBatches(schemasBuffer, (nodes) => Promise.all(nodes.map((node) => dispatchNode(state, node, schemaDispatch))), {
651
+ concurrency: SCHEMA_PARALLEL,
652
+ flush: flushPending,
653
+ })
644
654
 
645
- await forBatches(
646
- operations,
647
- (nodes) => {
648
- if (needsCollectedOperations) collectedOperations?.push(...nodes)
649
- return Promise.all(nodes.flatMap((node) => states.map((state) => dispatchNode(state, node, operationDispatch))))
650
- },
651
- { concurrency: SCHEMA_PARALLEL, flush: flushPending },
652
- )
655
+ await forBatches(
656
+ operationsBuffer,
657
+ (nodes) => {
658
+ if (needsCollectedOperations) collectedOperations?.push(...nodes)
659
+ return Promise.all(nodes.map((node) => dispatchNode(state, node, operationDispatch)))
660
+ },
661
+ { concurrency: SCHEMA_PARALLEL, flush: flushPending },
662
+ )
653
663
 
654
- for (const state of states) {
655
664
  if (!state.failed && needsCollectedOperations) {
656
665
  try {
657
666
  const { plugin, generatorContext, generators } = state
package/src/createKubb.ts CHANGED
@@ -464,6 +464,7 @@ export interface KubbHooks {
464
464
  'kubb:hooks:start': []
465
465
  'kubb:hooks:end': []
466
466
  'kubb:hook:start': [ctx: KubbHookStartContext]
467
+ 'kubb:hook:line': [ctx: KubbHookLineContext]
467
468
  'kubb:hook:end': [ctx: KubbHookEndContext]
468
469
  'kubb:info': [ctx: KubbInfoContext]
469
470
  'kubb:error': [ctx: KubbErrorContext]
@@ -718,6 +719,21 @@ export type KubbHookStartContext = {
718
719
  args?: ReadonlyArray<string>
719
720
  }
720
721
 
722
+ /**
723
+ * Emitted for each line streamed from a hook's stdout while it runs.
724
+ * A logger correlates the line to its active UI element via `id`.
725
+ */
726
+ export type KubbHookLineContext = {
727
+ /**
728
+ * Identifier matching the corresponding `kubb:hook:start` event.
729
+ */
730
+ id: string
731
+ /**
732
+ * A single streamed stdout line, without its trailing newline.
733
+ */
734
+ line: string
735
+ }
736
+
721
737
  export type KubbHookEndContext = {
722
738
  /**
723
739
  * Optional identifier matching the corresponding `kubb:hook:start` event.
@@ -739,6 +755,14 @@ export type KubbHookEndContext = {
739
755
  * Error thrown by the command, or `null` on success.
740
756
  */
741
757
  error: Error | null
758
+ /**
759
+ * Captured stdout from the process, populated when it exits non-zero.
760
+ */
761
+ stdout?: string
762
+ /**
763
+ * Captured stderr from the process, populated when it exits non-zero.
764
+ */
765
+ stderr?: string
742
766
  }
743
767
 
744
768
  /**
@@ -34,29 +34,27 @@ export type LoggerContext = AsyncEventEmitter<KubbHooks>
34
34
  /**
35
35
  * Logger contract. A logger receives the build's event emitter and subscribes
36
36
  * to whichever lifecycle events it wants to forward to its destination
37
- * (console, file, remote sink).
37
+ * (console, file, remote service).
38
38
  */
39
- export type Logger<TOptions extends LoggerOptions = LoggerOptions, TInstallReturn = void> = {
39
+ export type Logger<TOptions extends LoggerOptions = LoggerOptions> = {
40
40
  /**
41
41
  * Display name used in diagnostics.
42
42
  */
43
43
  name: string
44
44
  /**
45
- * Called once per build with the shared event emitter. Subscribe to events
46
- * here. The return value (if any) is forwarded to whoever installed the
47
- * logger, which is handy for sink factories.
45
+ * Called once per build with the shared event emitter. Subscribe to the
46
+ * lifecycle events the logger wants to forward to its destination.
48
47
  */
49
- install: (context: LoggerContext, options?: TOptions) => TInstallReturn | Promise<TInstallReturn>
48
+ install: (context: LoggerContext, options?: TOptions) => void | Promise<void>
50
49
  }
51
50
 
52
- export type UserLogger<TOptions extends LoggerOptions = LoggerOptions, TInstallReturn = void> = Logger<TOptions, TInstallReturn>
51
+ export type UserLogger<TOptions extends LoggerOptions = LoggerOptions> = Logger<TOptions>
53
52
 
54
53
  /**
55
- * Defines a typed logger. Use the second type parameter to declare a return
56
- * value from `install`, which is handy when the logger exposes a sink factory
57
- * or cleanup callback to the caller.
54
+ * Defines a typed logger. The `install` method subscribes to lifecycle events
55
+ * on the shared emitter and forwards them to the logger's destination.
58
56
  *
59
- * @example Basic logger
57
+ * @example
60
58
  * ```ts
61
59
  * import { defineLogger } from '@kubb/core'
62
60
  *
@@ -68,23 +66,7 @@ export type UserLogger<TOptions extends LoggerOptions = LoggerOptions, TInstallR
68
66
  * },
69
67
  * })
70
68
  * ```
71
- *
72
- * @example Logger that returns a hook sink factory
73
- * ```ts
74
- * import { defineLogger, type LoggerOptions } from '@kubb/core'
75
- * import type { HookSinkFactory } from './sinks'
76
- *
77
- * export const myLogger = defineLogger<LoggerOptions, HookSinkFactory>({
78
- * name: 'my-logger',
79
- * install(context) {
80
- * // … register event handlers …
81
- * return () => ({ onStdout: console.log })
82
- * },
83
- * })
84
- * ```
85
69
  */
86
- export function defineLogger<Options extends LoggerOptions = LoggerOptions, TInstallReturn = void>(
87
- logger: UserLogger<Options, TInstallReturn>,
88
- ): Logger<Options, TInstallReturn> {
70
+ export function defineLogger<Options extends LoggerOptions = LoggerOptions>(logger: UserLogger<Options>): Logger<Options> {
89
71
  return logger
90
72
  }
package/src/types.ts CHANGED
@@ -31,6 +31,7 @@ export type {
31
31
  KubbGenerationEndContext,
32
32
  KubbGenerationStartContext,
33
33
  KubbHookEndContext,
34
+ KubbHookLineContext,
34
35
  KubbHookStartContext,
35
36
  KubbHooks,
36
37
  KubbInfoContext,