@kubb/core 5.0.0-beta.100 → 5.0.0-beta.102

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/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
2
- import { $ as definePlugin, A as Generator, At as DiagnosticSeverity, B as Include, Bt as AdapterSource, C as KubbWarnContext, Ct as UserReporter, D as CreateKubbOptions, Dt as DiagnosticDoc, E as UserConfig, Et as Diagnostic, F as Parser, Ft as SerializedDiagnostic, G as Output, H as KubbPluginSetupContext, I as defineParser, It as UpdateDiagnostic, J as Override, K as OutputMode, L as Exclude, Lt as Hookable, M as defineGenerator, Mt as PerformanceDiagnostic, N as KubbDriver, Nt as ProblemCode, O as Kubb, Ot as DiagnosticKind, P as FileManagerHooks, Pt as ProblemDiagnostic, Q as ResolvePluginOptions, R as Filter, Rt as Adapter, S as KubbSuccessContext, St as ReporterName, T as PostGenerateCommand, Tt as logLevel, U as KubbPluginStartContext, V as KubbPluginEndContext, Vt as createAdapter, W as NormalizedPlugin, X as PluginFactoryOptions, Y as Plugin, Z as PluginName, _ as KubbHookStartContext, _t as Storage, a as KubbBuildEndContext, at as ResolveOptionsContext, b as KubbLifecycleStartContext, bt as Reporter, c as KubbErrorContext, ct as ResolverDefault, d as KubbFilesProcessingStartContext, dt as ResolverFilePathParams, et as BannerMeta, f as KubbFilesProcessingUpdateContext, ft as ResolverPatch, g as KubbHookLineContext, gt as createRenderer, h as KubbHookEndContext, ht as RendererFactory, i as Input, it as ResolveImportsOptions, j as GeneratorContext, jt as Diagnostics, k as createKubb, kt as DiagnosticLocation, l as KubbFileProcessingUpdate, lt as ResolverFile, m as KubbGenerationStartContext, mt as Renderer, n as CLIOptions, nt as ResolveBannerFile, o as KubbBuildStartContext, ot as ResolvePathOptions, p as KubbGenerationEndContext, pt as ResolverPathParams, q as OutputOptions, r as Config, rt as ResolveFileOptions, s as KubbDiagnosticContext, st as Resolver, t as BuildOutput, tt as ResolveBannerContext, u as KubbFilesProcessingEndContext, ut as ResolverFileParams, v as KubbHooks, vt as createStorage, w as PossibleConfig, wt as createReporter, x as KubbPluginsEndContext, xt as ReporterContext, y as KubbInfoContext, yt as GenerationResult, z as Group, zt as AdapterFactoryOptions } from "./types-DM7-MGjZ.js";
2
+ import { $ as PluginName, A as Kubb, At as DiagnosticKind, B as Filter, Bt as Adapter, C as KubbWarnContext, Ct as ReporterContext, D as CreateKubbOptions, Dt as logLevel, E as UserConfig, Et as createReporter, F as KubbDriver, Ft as ProblemCode, G as KubbPluginStartContext, H as Include, Ht as AdapterSource, I as FileManagerHooks, It as ProblemDiagnostic, J as OutputMode, K as NormalizedPlugin, L as Parser, Lt as SerializedDiagnostic, M as Generator, Mt as DiagnosticSeverity, N as GeneratorContext, Nt as Diagnostics, O as GenerateOptions, Ot as Diagnostic, P as defineGenerator, Pt as PerformanceDiagnostic, Q as PluginFactoryOptions, R as defineParser, Rt as UpdateDiagnostic, S as KubbSuccessContext, St as Reporter, T as PostGenerateCommand, Tt as UserReporter, U as KubbPluginEndContext, Ut as createAdapter, V as Group, Vt as AdapterFactoryOptions, W as KubbPluginSetupContext, X as Override, Y as OutputOptions, Z as Plugin, _ as KubbHookStartContext, _t as RendererFactory, a as KubbBuildEndContext, at as ResolveFileOptions, b as KubbLifecycleStartContext, bt as createStorage, c as KubbErrorContext, ct as ResolvePathOptions, d as KubbFilesProcessingStartContext, dt as ResolverFile, et as ResolvePluginOptions, f as KubbFilesProcessingUpdateContext, ft as ResolverFileParams, g as KubbHookLineContext, gt as Renderer, h as KubbHookEndContext, ht as ResolverPathParams, i as Input, it as ResolveBannerFile, j as createKubb, jt as DiagnosticLocation, k as GenerateResult, kt as DiagnosticDoc, l as KubbFileProcessingUpdate, lt as Resolver, m as KubbGenerationStartContext, mt as ResolverPatch, n as CLIOptions, nt as BannerMeta, o as KubbBuildStartContext, ot as ResolveImportsOptions, p as KubbGenerationEndContext, pt as ResolverFilePathParams, q as Output, r as Config, rt as ResolveBannerContext, s as KubbDiagnosticContext, st as ResolveOptionsContext, t as BuildOutput, tt as definePlugin, u as KubbFilesProcessingEndContext, ut as ResolverDefault, v as KubbHooks, vt as createRenderer, w as PossibleConfig, wt as ReporterName, x as KubbPluginsEndContext, xt as GenerationResult, y as KubbInfoContext, yt as Storage, z as Exclude, zt as Hookable } from "./types-B14Ba9P7.js";
3
3
  //#region src/applyConfigDefaults.d.ts
4
4
  type ApplyConfigDefaultsOptions<TOutput> = {
5
5
  defaultAdapter: Adapter;
@@ -183,5 +183,5 @@ declare const fsStorage: (options?: Record<string, never> | undefined) => Storag
183
183
  */
184
184
  declare const memoryStorage: (options?: Record<string, never> | undefined) => Storage;
185
185
  //#endregion
186
- export { type Adapter, type AdapterFactoryOptions, type AdapterSource, type BannerMeta, BuildOutput, CLIOptions, Config, type CreateKubbOptions, type Diagnostic, type DiagnosticDoc, type DiagnosticKind, type DiagnosticLocation, type DiagnosticSeverity, Diagnostics, type Exclude, type FileManagerHooks, type Filter, type GenerationResult, type Generator, type GeneratorContext, type Group, Hookable, type Include, Input, type InputKind, type Kubb, KubbBuildEndContext, KubbBuildStartContext, KubbDiagnosticContext, KubbDriver, KubbErrorContext, KubbFileProcessingUpdate, KubbFilesProcessingEndContext, KubbFilesProcessingStartContext, KubbFilesProcessingUpdateContext, KubbGenerationEndContext, KubbGenerationStartContext, KubbHookEndContext, KubbHookLineContext, KubbHookStartContext, KubbHooks, KubbInfoContext, KubbLifecycleStartContext, type KubbPluginEndContext, type KubbPluginSetupContext, type KubbPluginStartContext, KubbPluginsEndContext, KubbSuccessContext, KubbWarnContext, type NormalizedPlugin, type Output, type OutputMode, type OutputOptions, type Override, type Parser, type PerformanceDiagnostic, type Plugin, type PluginFactoryOptions, type PluginName, PossibleConfig, PostGenerateCommand, type ProblemCode, type ProblemDiagnostic, type Renderer, type RendererFactory, type Reporter, type ReporterContext, type ReporterName, type ResolveBannerContext, type ResolveBannerFile, type ResolveFileOptions, type ResolveImportsOptions, type ResolveOptionsContext, type ResolvePathOptions, type ResolvePluginOptions, Resolver, type ResolverDefault, type ResolverFile, type ResolverFileParams, type ResolverFilePathParams, type ResolverPatch, type ResolverPathParams, type SerializedDiagnostic, type Storage, type UpdateDiagnostic, UserConfig, type UserReporter, applyConfigDefaults, cliReporter, createAdapter, createKubb, createRenderer, createReporter, createResolver, createStorage, defineGenerator, defineParser, definePlugin, fileReporter, fsStorage, getInputKind, jsonReporter, logLevel, memoryStorage };
186
+ export { type Adapter, type AdapterFactoryOptions, type AdapterSource, type BannerMeta, BuildOutput, CLIOptions, Config, type CreateKubbOptions, type Diagnostic, type DiagnosticDoc, type DiagnosticKind, type DiagnosticLocation, type DiagnosticSeverity, Diagnostics, type Exclude, type FileManagerHooks, type Filter, type GenerateOptions, type GenerateResult, type GenerationResult, type Generator, type GeneratorContext, type Group, Hookable, type Include, Input, type InputKind, type Kubb, KubbBuildEndContext, KubbBuildStartContext, KubbDiagnosticContext, KubbDriver, KubbErrorContext, KubbFileProcessingUpdate, KubbFilesProcessingEndContext, KubbFilesProcessingStartContext, KubbFilesProcessingUpdateContext, KubbGenerationEndContext, KubbGenerationStartContext, KubbHookEndContext, KubbHookLineContext, KubbHookStartContext, KubbHooks, KubbInfoContext, KubbLifecycleStartContext, type KubbPluginEndContext, type KubbPluginSetupContext, type KubbPluginStartContext, KubbPluginsEndContext, KubbSuccessContext, KubbWarnContext, type NormalizedPlugin, type Output, type OutputMode, type OutputOptions, type Override, type Parser, type PerformanceDiagnostic, type Plugin, type PluginFactoryOptions, type PluginName, PossibleConfig, PostGenerateCommand, type ProblemCode, type ProblemDiagnostic, type Renderer, type RendererFactory, type Reporter, type ReporterContext, type ReporterName, type ResolveBannerContext, type ResolveBannerFile, type ResolveFileOptions, type ResolveImportsOptions, type ResolveOptionsContext, type ResolvePathOptions, type ResolvePluginOptions, Resolver, type ResolverDefault, type ResolverFile, type ResolverFileParams, type ResolverFilePathParams, type ResolverPatch, type ResolverPathParams, type SerializedDiagnostic, type Storage, type UpdateDiagnostic, UserConfig, type UserReporter, applyConfigDefaults, cliReporter, createAdapter, createKubb, createRenderer, createReporter, createResolver, createStorage, defineGenerator, defineParser, definePlugin, fileReporter, fsStorage, getInputKind, jsonReporter, logLevel, memoryStorage };
187
187
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -148,48 +148,8 @@ function randomCliColor(text) {
148
148
  return styleText(randomColors[index] ?? "white", text);
149
149
  }
150
150
  //#endregion
151
- //#region ../../internals/utils/src/promise.ts
152
- /**
153
- * Wraps `factory` with a keyed cache backed by the provided store.
154
- *
155
- * Pass a `WeakMap` for object keys (results are GC-eligible when the key is
156
- * collected) or a `Map` for primitive keys. For multi-argument functions,
157
- * nest two `memoize` calls — the outer keyed by the first argument, the
158
- * inner (created once per outer miss) keyed by the second.
159
- *
160
- * Because the cache is owned by the caller, it can be shared, inspected, or
161
- * cleared independently of the memoized function.
162
- *
163
- * @example Single WeakMap key
164
- * ```ts
165
- * const cache = new WeakMap<SchemaNode, Set<string>>()
166
- * const getRefs = memoize(cache, (node) => collectRefs(node))
167
- * ```
168
- *
169
- * @example Single Map key (primitive)
170
- * ```ts
171
- * const cache = new Map<string, Resolver>()
172
- * const getResolver = memoize(cache, (name) => buildResolver(name))
173
- * ```
174
- *
175
- * @example Two-level (object + primitive)
176
- * ```ts
177
- * const outer = new WeakMap<Params[], Map<string, Params[]>>()
178
- * const fn = memoize(outer, (params) => memoize(new Map(), (key) => transform(params, key)))
179
- * fn(params)('camelcase')
180
- * ```
181
- */
182
- function memoize(store, factory) {
183
- return (key) => {
184
- if (store.has(key)) return store.get(key);
185
- const value = factory(key);
186
- store.set(key, value);
187
- return value;
188
- };
189
- }
190
- //#endregion
191
151
  //#region package.json
192
- var version = "5.0.0-beta.100";
152
+ var version = "5.0.0-beta.102";
193
153
  //#endregion
194
154
  //#region src/constants.ts
195
155
  /**
@@ -1286,6 +1246,38 @@ const ENFORCE_ORDER = {
1286
1246
  post: 1
1287
1247
  };
1288
1248
  const enforceWeight = (plugin) => plugin.enforce ? ENFORCE_ORDER[plugin.enforce] : 0;
1249
+ /**
1250
+ * The options bag a `NormalizedPlugin` starts with before a plugin refines it: a directory output
1251
+ * at the plugin root and empty filter lists.
1252
+ */
1253
+ function defaultPluginOptions() {
1254
+ return {
1255
+ output: {
1256
+ path: ".",
1257
+ mode: "directory"
1258
+ },
1259
+ exclude: [],
1260
+ override: []
1261
+ };
1262
+ }
1263
+ /**
1264
+ * Fills in the `output`, `exclude`, and `override` a `NormalizedPlugin` needs from a plugin's raw
1265
+ * options, running `output` through `normalizeOutput`. Idempotent, so the driver can apply it after
1266
+ * `setOptions` has already run without disturbing an already-normalized bag.
1267
+ */
1268
+ function normalizePluginOptions(rawOptions, pluginName) {
1269
+ const options = {
1270
+ ...defaultPluginOptions(),
1271
+ ...rawOptions ?? {}
1272
+ };
1273
+ const group = "group" in options ? options.group : void 0;
1274
+ options.output = normalizeOutput({
1275
+ output: options.output,
1276
+ group,
1277
+ pluginName
1278
+ });
1279
+ return options;
1280
+ }
1289
1281
  var KubbDriver = class {
1290
1282
  config;
1291
1283
  options;
@@ -1307,13 +1299,6 @@ var KubbDriver = class {
1307
1299
  fileManager = new FileManager();
1308
1300
  plugins = /* @__PURE__ */ new Map();
1309
1301
  /**
1310
- * Tracks which plugins have generators registered via `addGenerator()` (hook-based path).
1311
- * Used by the build loop to decide whether to emit generator hooks for a given plugin.
1312
- */
1313
- #hookGeneratorPlugins = /* @__PURE__ */ new Set();
1314
- #resolvers = /* @__PURE__ */ new Map();
1315
- #defaultResolvers = /* @__PURE__ */ new Map();
1316
- /**
1317
1302
  * Removers for every listener the driver added (plugin, generator) so `dispose()` can detach
1318
1303
  * them in one pass. External `hooks.hook(...)` listeners are not tracked.
1319
1304
  */
@@ -1341,15 +1326,8 @@ var KubbDriver = class {
1341
1326
  dependencies: rawPlugin.dependencies,
1342
1327
  enforce: rawPlugin.enforce,
1343
1328
  hooks: rawPlugin.hooks,
1344
- options: rawPlugin.options ?? {
1345
- output: {
1346
- path: ".",
1347
- mode: "directory"
1348
- },
1349
- exclude: [],
1350
- override: []
1351
- },
1352
- resolver: this.#getDefaultResolver(rawPlugin.name)
1329
+ options: rawPlugin.options ?? defaultPluginOptions(),
1330
+ resolver: createResolver({ pluginName: rawPlugin.name })
1353
1331
  };
1354
1332
  }));
1355
1333
  for (const plugin of normalized) {
@@ -1458,46 +1436,30 @@ var KubbDriver = class {
1458
1436
  }
1459
1437
  }
1460
1438
  /**
1461
- * Registers a generator for the given plugin on the shared hook emitter.
1439
+ * Appends a generator to its owning plugin so the generate loop can call it directly.
1462
1440
  *
1463
- * The generator's `schema`, `operation`, and `operations` methods are registered as
1464
- * listeners on `kubb:generate:schema`, `kubb:generate:operation`, and `kubb:generate:operations`
1465
- * respectively. Each listener is scoped to the owning plugin via a `ctx.plugin.name` check
1466
- * so that generators from different plugins do not cross-fire.
1467
- *
1468
- * The renderer comes from `generator.renderer`. Set `generator.renderer = null` (or leave it
1469
- * unset) to opt out of rendering.
1441
+ * The generator's `schema`, `operation`, and `operations` methods run per node during the AST
1442
+ * walk in `#runGenerators`, and their result is routed through `dispatch`. Because a generator is
1443
+ * bound to a plugin, generators from different plugins never cross-fire without a name check. The
1444
+ * renderer comes from `generator.renderer`; set it to `null` (or leave it unset) to opt out of
1445
+ * rendering.
1470
1446
  *
1471
1447
  * Call this method inside `addGenerator()` (in `kubb:plugin:setup`) to wire up a generator.
1472
1448
  */
1473
1449
  registerGenerator(pluginName, generator) {
1474
- const wrap = (method) => {
1475
- if (!method) return void 0;
1476
- return async (node, ctx) => {
1477
- if (ctx.plugin.name !== pluginName) return;
1478
- const result = await method(node, ctx);
1479
- await this.dispatch({
1480
- result,
1481
- renderer: generator.renderer
1482
- });
1483
- };
1484
- };
1485
- this.#unhooks.push(this.hooks.addHooks({
1486
- "kubb:generate:schema": wrap(generator.schema),
1487
- "kubb:generate:operation": wrap(generator.operation),
1488
- "kubb:generate:operations": wrap(generator.operations)
1489
- }));
1490
- this.#hookGeneratorPlugins.add(pluginName);
1450
+ const plugin = this.plugins.get(pluginName);
1451
+ if (!plugin) return;
1452
+ plugin.generators = plugin.generators ? [...plugin.generators, generator] : [generator];
1491
1453
  }
1492
1454
  /**
1493
1455
  * Returns `true` when at least one generator was registered for the given plugin
1494
1456
  * via `addGenerator()` in `kubb:plugin:setup`.
1495
1457
  *
1496
- * Used by the build loop to decide whether to walk the AST and emit generator hooks
1458
+ * Used by the build loop to decide whether to walk the AST and run the generators
1497
1459
  * for a plugin.
1498
1460
  */
1499
1461
  hasHookGenerators(pluginName) {
1500
- return this.#hookGeneratorPlugins.has(pluginName);
1462
+ return (this.plugins.get(pluginName)?.generators?.length ?? 0) > 0;
1501
1463
  }
1502
1464
  /**
1503
1465
  * Runs the full plugin pipeline. Returns the diagnostics collected so far even
@@ -1532,12 +1494,16 @@ var KubbDriver = class {
1532
1494
  const outputRoot = resolve(config.root, config.output.path);
1533
1495
  await this.#parseInput();
1534
1496
  await this.setupHooks();
1535
- if (this.adapter && this.inputNode) await hooks.callHook("kubb:build:start", Object.assign({
1536
- config,
1537
- adapter: this.adapter,
1538
- meta: this.inputNode.meta,
1539
- getPlugin: this.getPlugin.bind(this)
1540
- }, this.#filesPayload()));
1497
+ for (const plugin of this.plugins.values()) plugin.options = normalizePluginOptions(plugin.options, plugin.name);
1498
+ if (this.adapter && this.inputNode) {
1499
+ const buildStartContext = this.#withFiles({
1500
+ config,
1501
+ adapter: this.adapter,
1502
+ meta: this.inputNode.meta,
1503
+ getPlugin: this.getPlugin.bind(this)
1504
+ });
1505
+ await hooks.callHook("kubb:build:start", buildStartContext);
1506
+ }
1541
1507
  const generatorPlugins = [];
1542
1508
  for (const plugin of this.plugins.values()) {
1543
1509
  const context = this.getContext(plugin);
@@ -1582,7 +1548,7 @@ var KubbDriver = class {
1582
1548
  });
1583
1549
  }
1584
1550
  diagnostics.push(...await this.#runGenerators(generatorPlugins));
1585
- await hooks.callHook("kubb:plugins:end", Object.assign({ config }, this.#filesPayload()));
1551
+ await hooks.callHook("kubb:plugins:end", this.#withFiles({ config }));
1586
1552
  await fileManager.write(fileManager.files, {
1587
1553
  storage: config.storage,
1588
1554
  parsers: parsersMap
@@ -1601,23 +1567,26 @@ var KubbDriver = class {
1601
1567
  }
1602
1568
  });
1603
1569
  }
1604
- #filesPayload() {
1605
- const driver = this;
1570
+ /**
1571
+ * Widens `extra` with the files present at emit time and a bound `upsertFile`, the shape every
1572
+ * file-carrying hook context shares. Building it here in one place keeps the `files` and
1573
+ * `upsertFile` keys from being dropped by a stray spread at the call site.
1574
+ */
1575
+ #withFiles(extra) {
1606
1576
  return {
1607
- get files() {
1608
- return driver.fileManager.files;
1609
- },
1610
- upsertFile: (...files) => driver.fileManager.upsert(...files)
1577
+ ...extra,
1578
+ files: this.fileManager.files,
1579
+ upsertFile: (...files) => this.fileManager.upsert(...files)
1611
1580
  };
1612
1581
  }
1613
1582
  #emitPluginEnd({ plugin, duration, success, error }) {
1614
- return this.hooks.callHook("kubb:plugin:end", Object.assign({
1583
+ return this.hooks.callHook("kubb:plugin:end", this.#withFiles({
1615
1584
  plugin,
1616
1585
  duration,
1617
1586
  success,
1618
1587
  ...error ? { error } : {},
1619
1588
  config: this.config
1620
- }, this.#filesPayload()));
1589
+ }));
1621
1590
  }
1622
1591
  /**
1623
1592
  * Runs schemas and operations through every plugin's generators. Each node is run
@@ -1654,9 +1623,6 @@ var KubbDriver = class {
1654
1623
  }
1655
1624
  const transforms = this.#transforms;
1656
1625
  const { schemas, operations } = this.inputNode;
1657
- const emitsSchemaHook = this.hooks.listenerCount("kubb:generate:schema") > 0;
1658
- const emitsOperationHook = this.hooks.listenerCount("kubb:generate:operation") > 0;
1659
- const emitsOperationsHook = this.hooks.listenerCount("kubb:generate:operations") > 0;
1660
1626
  const allowedSchemaNamesByPlugin = /* @__PURE__ */ new Map();
1661
1627
  for (const { plugin } of entries) {
1662
1628
  const { exclude, include, override } = plugin.options;
@@ -1678,6 +1644,10 @@ var KubbDriver = class {
1678
1644
  const { exclude, include, override } = plugin.options;
1679
1645
  const optionsAreStatic = !exclude?.length && !include?.length && !override?.length;
1680
1646
  const allowedSchemaNames = allowedSchemaNamesByPlugin.get(plugin.name) ?? null;
1647
+ const generators = plugin.generators ?? [];
1648
+ const schemaGenerators = generators.filter((generator) => generator.schema);
1649
+ const operationGenerators = generators.filter((generator) => generator.operation);
1650
+ const operationsGenerators = generators.filter((generator) => generator.operations);
1681
1651
  let error = null;
1682
1652
  const resolveForPlugin = (node) => {
1683
1653
  const transformedNode = transforms.applyTo(plugin.name, node);
@@ -1697,44 +1667,57 @@ var KubbDriver = class {
1697
1667
  options
1698
1668
  };
1699
1669
  };
1700
- if (emitsSchemaHook) for (const node of schemas) {
1670
+ if (schemaGenerators.length) for (const node of schemas) {
1701
1671
  if (error) break;
1702
1672
  try {
1703
1673
  const resolved = resolveForPlugin(node);
1704
1674
  if (!resolved) continue;
1705
1675
  const { transformedNode, options } = resolved;
1706
1676
  if (allowedSchemaNames !== null && transformedNode.name && !allowedSchemaNames.has(transformedNode.name)) continue;
1707
- await this.hooks.callHook("kubb:generate:schema", transformedNode, {
1677
+ const ctx = {
1708
1678
  ...generatorContext,
1709
1679
  options
1680
+ };
1681
+ for (const generator of schemaGenerators) await this.dispatch({
1682
+ result: await generator.schema(transformedNode, ctx),
1683
+ renderer: generator.renderer
1710
1684
  });
1685
+ await this.hooks.callHook("kubb:generate:schema", transformedNode, ctx);
1711
1686
  } catch (caughtError) {
1712
1687
  error = toError(caughtError);
1713
1688
  }
1714
1689
  }
1715
- if (emitsOperationHook) for (const node of operations) {
1690
+ const pluginOperations = [];
1691
+ if (operationGenerators.length || operationsGenerators.length) for (const node of operations) {
1716
1692
  if (error) break;
1717
1693
  try {
1718
1694
  const resolved = resolveForPlugin(node);
1719
1695
  if (!resolved) continue;
1720
- await this.hooks.callHook("kubb:generate:operation", resolved.transformedNode, {
1721
- ...generatorContext,
1722
- options: resolved.options
1723
- });
1696
+ pluginOperations.push(resolved.transformedNode);
1697
+ if (operationGenerators.length) {
1698
+ const ctx = {
1699
+ ...generatorContext,
1700
+ options: resolved.options
1701
+ };
1702
+ for (const generator of operationGenerators) await this.dispatch({
1703
+ result: await generator.operation(resolved.transformedNode, ctx),
1704
+ renderer: generator.renderer
1705
+ });
1706
+ await this.hooks.callHook("kubb:generate:operation", resolved.transformedNode, ctx);
1707
+ }
1724
1708
  } catch (caughtError) {
1725
1709
  error = toError(caughtError);
1726
1710
  }
1727
1711
  }
1728
- if (!error && emitsOperationsHook) try {
1712
+ if (!error && operationsGenerators.length) try {
1729
1713
  const ctx = {
1730
1714
  ...generatorContext,
1731
1715
  options: plugin.options
1732
1716
  };
1733
- const pluginOperations = operations.reduce((acc, node) => {
1734
- const resolved = resolveForPlugin(node);
1735
- if (resolved) acc.push(resolved.transformedNode);
1736
- return acc;
1737
- }, []);
1717
+ for (const generator of operationsGenerators) await this.dispatch({
1718
+ result: await generator.operations(pluginOperations, ctx),
1719
+ renderer: generator.renderer
1720
+ });
1738
1721
  await this.hooks.callHook("kubb:generate:operations", pluginOperations, ctx);
1739
1722
  } catch (caughtError) {
1740
1723
  error = toError(caughtError);
@@ -1796,10 +1779,7 @@ var KubbDriver = class {
1796
1779
  dispose() {
1797
1780
  for (const unhook of this.#unhooks) unhook();
1798
1781
  this.#unhooks.length = 0;
1799
- this.#hookGeneratorPlugins.clear();
1800
1782
  this.#transforms.dispose();
1801
- this.#resolvers.clear();
1802
- this.#defaultResolvers.clear();
1803
1783
  this.fileManager.dispose();
1804
1784
  this.inputNode = null;
1805
1785
  this.#adapterSource = null;
@@ -1807,21 +1787,17 @@ var KubbDriver = class {
1807
1787
  [Symbol.dispose]() {
1808
1788
  this.dispose();
1809
1789
  }
1810
- #getDefaultResolver = memoize(this.#defaultResolvers, (pluginName) => createResolver({ pluginName }));
1811
1790
  /**
1812
- * Merges `partial` with the plugin's default resolver and stores the result.
1813
- * Also mirrors it onto `plugin.resolver` so callers using `getPlugin(name).resolver`
1814
- * get the up-to-date resolver without going through `getResolver()`.
1791
+ * Merges `partial` onto a fresh default resolver and stores the result on `plugin.resolver`,
1792
+ * which is the single source `getResolver` and `getPlugin(name).resolver` both read.
1815
1793
  */
1816
1794
  setPluginResolver(pluginName, partial) {
1817
- const defaultResolver = this.#getDefaultResolver(pluginName);
1818
- const merged = Resolver.merge(defaultResolver, partial);
1819
- this.#resolvers.set(pluginName, merged);
1820
1795
  const plugin = this.plugins.get(pluginName);
1821
- if (plugin) plugin.resolver = merged;
1796
+ if (!plugin) return;
1797
+ plugin.resolver = Resolver.merge(createResolver({ pluginName }), partial);
1822
1798
  }
1823
1799
  getResolver(pluginName) {
1824
- return this.#resolvers.get(pluginName) ?? this.#getDefaultResolver(pluginName);
1800
+ return this.plugins.get(pluginName)?.resolver ?? createResolver({ pluginName });
1825
1801
  }
1826
1802
  getContext(plugin) {
1827
1803
  const driver = this;
@@ -2151,6 +2127,69 @@ var Kubb = class {
2151
2127
  _usingCtx$1.d();
2152
2128
  }
2153
2129
  }
2130
+ /**
2131
+ * Run one build and its output passes end to end, emitting the surrounding `kubb:generation:*`
2132
+ * hooks. Never throws on a build error: the outcome comes back in {@link GenerateResult} so the
2133
+ * host decides how failures surface. Telemetry and progress narration stay with the host, which
2134
+ * reads the result and subscribes to the `kubb:*` hooks.
2135
+ *
2136
+ * @example
2137
+ * ```ts
2138
+ * const result = await createKubb(config, { hooks }).generate()
2139
+ * if (!result.success) process.exitCode = 1
2140
+ * ```
2141
+ */
2142
+ async generate(options = {}) {
2143
+ const { hooks, config } = this;
2144
+ const hrStart = process.hrtime();
2145
+ await hooks.callHook("kubb:generation:start", { config });
2146
+ await hooks.callHook("kubb:setup:start");
2147
+ await this.setup();
2148
+ await hooks.callHook("kubb:setup:end");
2149
+ const { files, diagnostics, storage } = await this.safeBuild();
2150
+ for (const diagnostic of diagnostics) {
2151
+ if (!Diagnostics.isProblem(diagnostic)) continue;
2152
+ if (diagnostic.code === Diagnostics.code.unknown) {
2153
+ await hooks.callHook("kubb:error", { error: diagnostic.cause ?? new Error(diagnostic.message) });
2154
+ continue;
2155
+ }
2156
+ await Diagnostics.emit(hooks, diagnostic);
2157
+ }
2158
+ if (Diagnostics.hasError(diagnostics)) {
2159
+ await hooks.callHook("kubb:generation:end", {
2160
+ config,
2161
+ storage,
2162
+ diagnostics,
2163
+ filesCreated: files.length,
2164
+ status: "failed",
2165
+ hrStart
2166
+ });
2167
+ return {
2168
+ success: false,
2169
+ files,
2170
+ diagnostics
2171
+ };
2172
+ }
2173
+ const outputDiagnostics = options.processOutput ? await options.processOutput({
2174
+ config,
2175
+ outputPath: resolve(config.root, config.output.path)
2176
+ }) : [];
2177
+ const finalDiagnostics = [...diagnostics, ...outputDiagnostics];
2178
+ const failed = Diagnostics.hasError(outputDiagnostics);
2179
+ await hooks.callHook("kubb:generation:end", {
2180
+ config,
2181
+ storage,
2182
+ diagnostics: finalDiagnostics,
2183
+ filesCreated: files.length,
2184
+ status: failed ? "failed" : "success",
2185
+ hrStart
2186
+ });
2187
+ return {
2188
+ success: !failed,
2189
+ files,
2190
+ diagnostics: finalDiagnostics
2191
+ };
2192
+ }
2154
2193
  dispose() {
2155
2194
  this.#driver?.dispose();
2156
2195
  }