@kubb/core 5.0.0-beta.85 → 5.0.0-beta.86

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.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_usingCtx = require("./usingCtx-fxRpJw0P.cjs");
2
+ const require_usingCtx = require("./usingCtx-BN2OKJRx.cjs");
3
3
  let node_async_hooks = require("node:async_hooks");
4
4
  let node_util = require("node:util");
5
5
  let node_crypto = require("node:crypto");
@@ -172,7 +172,7 @@ function memoize(store, factory) {
172
172
  }
173
173
  //#endregion
174
174
  //#region package.json
175
- var version = "5.0.0-beta.85";
175
+ var version = "5.0.0-beta.86";
176
176
  //#endregion
177
177
  //#region src/constants.ts
178
178
  /**
@@ -519,12 +519,12 @@ var Diagnostics = class Diagnostics {
519
519
  return true;
520
520
  }
521
521
  /**
522
- * Emits a diagnostic on the run's `kubb:diagnostic` event so the loggers render it live.
523
- * Use it instead of calling `hooks.emit('kubb:diagnostic', ...)` directly. To collect a
522
+ * Emits a diagnostic on the run's `kubb:diagnostic` hook so the loggers render it live.
523
+ * Use it instead of calling `hooks.callHook('kubb:diagnostic', ...)` directly. To collect a
524
524
  * diagnostic into the build result from deep in a run, use {@link Diagnostics.report} instead.
525
525
  */
526
526
  static async emit(hooks, diagnostic) {
527
- await hooks.emit("kubb:diagnostic", { diagnostic });
527
+ await hooks.callHook("kubb:diagnostic", { diagnostic });
528
528
  }
529
529
  /**
530
530
  * Coerces any thrown value into a {@link ProblemDiagnostic}. A {@link Diagnostics.Error}
@@ -742,7 +742,7 @@ function definePlugin(factory) {
742
742
  return (options) => factory(options ?? {});
743
743
  }
744
744
  //#endregion
745
- //#region src/createResolver.ts
745
+ //#region src/Resolver.ts
746
746
  function isNamespace(value) {
747
747
  return typeof value === "object" && value !== null && !Array.isArray(value);
748
748
  }
@@ -806,7 +806,7 @@ var Resolver = class Resolver {
806
806
  */
807
807
  static merge(base, override) {
808
808
  const patch = override instanceof Resolver ? override.#options : override;
809
- return createResolver({
809
+ return new Resolver({
810
810
  ...base.#options,
811
811
  ...patch
812
812
  });
@@ -998,6 +998,8 @@ var Resolver = class Resolver {
998
998
  return Resolver.#resolveUserText(output?.footer, meta, file) ?? null;
999
999
  }
1000
1000
  };
1001
+ //#endregion
1002
+ //#region src/createResolver.ts
1001
1003
  /**
1002
1004
  * Defines a plugin resolver, the object that decides what every generated symbol and file
1003
1005
  * path is called. Override the top-level `name` and `file` to set the plugin's conventions,
@@ -1103,35 +1105,7 @@ const ENFORCE_ORDER = {
1103
1105
  pre: -1,
1104
1106
  post: 1
1105
1107
  };
1106
- /**
1107
- * Orders plugins so every dependency runs before its dependents (Kahn's algorithm), with
1108
- * `enforce` (`'pre'` before normal before `'post'`) and declaration order as tiebreaks.
1109
- * A pairwise `Array.sort` comparator cannot do this: dependency relations are not transitive
1110
- * at the comparator level, so a chain where A depends on B and B depends on C could come out
1111
- * wrong when A and C are never compared directly. Dependencies on plugins missing from the
1112
- * config are ignored here and surface later through `requirePlugin`.
1113
- */
1114
- function sortPlugins(plugins) {
1115
- const queue = [...plugins].sort((a, b) => (a.enforce ? ENFORCE_ORDER[a.enforce] : 0) - (b.enforce ? ENFORCE_ORDER[b.enforce] : 0));
1116
- const names = new Set(queue.map((plugin) => plugin.name));
1117
- const blockedBy = new Map(queue.map((plugin) => [plugin.name, new Set(plugin.dependencies?.filter((name) => names.has(name) && name !== plugin.name))]));
1118
- const sorted = [];
1119
- while (queue.length > 0) {
1120
- const index = queue.findIndex((plugin) => blockedBy.get(plugin.name)?.size === 0);
1121
- if (index === -1) throw new Diagnostics.Error({
1122
- code: Diagnostics.code.invalidPluginOptions,
1123
- severity: "error",
1124
- message: `Plugin dependencies form a cycle: ${queue.map((plugin) => plugin.name).join(" → ")}.`,
1125
- help: "Remove one of the `dependencies` entries so the plugins can be ordered.",
1126
- location: { kind: "config" }
1127
- });
1128
- const [plugin] = queue.splice(index, 1);
1129
- if (!plugin) break;
1130
- sorted.push(plugin);
1131
- for (const blockers of blockedBy.values()) blockers.delete(plugin.name);
1132
- }
1133
- return sorted;
1134
- }
1108
+ const enforceWeight = (plugin) => plugin.enforce ? ENFORCE_ORDER[plugin.enforce] : 0;
1135
1109
  var KubbDriver = class {
1136
1110
  config;
1137
1111
  options;
@@ -1153,17 +1127,17 @@ var KubbDriver = class {
1153
1127
  fileManager = new require_usingCtx.FileManager();
1154
1128
  plugins = /* @__PURE__ */ new Map();
1155
1129
  /**
1156
- * Tracks which plugins have generators registered via `addGenerator()` (event-based path).
1157
- * Used by the build loop to decide whether to emit generator events for a given plugin.
1130
+ * Tracks which plugins have generators registered via `addGenerator()` (hook-based path).
1131
+ * Used by the build loop to decide whether to emit generator hooks for a given plugin.
1158
1132
  */
1159
- #eventGeneratorPlugins = /* @__PURE__ */ new Set();
1133
+ #hookGeneratorPlugins = /* @__PURE__ */ new Set();
1160
1134
  #resolvers = /* @__PURE__ */ new Map();
1161
1135
  #defaultResolvers = /* @__PURE__ */ new Map();
1162
1136
  /**
1163
- * Tracks every listener the driver added (plugin, generator) so `dispose()` can remove them
1164
- * in one pass. External `hooks.on(...)` listeners are not tracked.
1137
+ * Removers for every listener the driver added (plugin, generator) so `dispose()` can detach
1138
+ * them in one pass. External `hooks.hook(...)` listeners are not tracked.
1165
1139
  */
1166
- #listeners = [];
1140
+ #unhooks = [];
1167
1141
  /**
1168
1142
  * Transform registry. Plugins populate it during `kubb:plugin:setup` via `addMacro`/`setMacros`,
1169
1143
  * and `#runGenerators` reads it once per `(plugin, node)` pair through `applyTo`.
@@ -1175,52 +1149,67 @@ var KubbDriver = class {
1175
1149
  this.adapter = config.adapter ?? null;
1176
1150
  }
1177
1151
  /**
1178
- * Attaches a listener to the shared emitter and tracks it so `dispose()` can remove it later.
1179
- * Listeners attached directly via `hooks.on(...)` are not tracked and survive disposal.
1180
- */
1181
- #trackListener(event, handler) {
1182
- this.hooks.on(event, handler);
1183
- this.#listeners.push([event, handler]);
1184
- }
1185
- /**
1186
1152
  * Normalizes every configured plugin, orders them, and registers their lifecycle handlers.
1187
1153
  * A plugin that another lists as a dependency runs first, then `enforce: 'pre'` before
1188
1154
  * `'post'`. When the config has an adapter, the adapter source is resolved from the input
1189
1155
  * so `run` can parse it later.
1190
1156
  */
1191
1157
  async setup() {
1192
- const normalized = sortPlugins(this.config.plugins.map((rawPlugin) => this.#normalizePlugin(rawPlugin)));
1158
+ const normalized = this.#sortPlugins(this.config.plugins.map((rawPlugin) => {
1159
+ return {
1160
+ name: rawPlugin.name,
1161
+ dependencies: rawPlugin.dependencies,
1162
+ enforce: rawPlugin.enforce,
1163
+ hooks: rawPlugin.hooks,
1164
+ options: rawPlugin.options ?? {
1165
+ output: {
1166
+ path: ".",
1167
+ mode: "directory"
1168
+ },
1169
+ exclude: [],
1170
+ override: []
1171
+ }
1172
+ };
1173
+ }));
1193
1174
  for (const plugin of normalized) {
1194
1175
  this.#registerPlugin(plugin);
1195
1176
  this.plugins.set(plugin.name, plugin);
1196
1177
  }
1197
1178
  if (this.config.adapter) this.#adapterSource = inputToAdapterSource(this.config);
1198
1179
  }
1180
+ /**
1181
+ * Orders plugins so every dependency runs before its dependents (Kahn's algorithm), with
1182
+ * `enforce` (`'pre'` before normal before `'post'`) and declaration order as tiebreaks.
1183
+ * A pairwise `Array.sort` comparator cannot do this: dependency relations are not transitive
1184
+ * at the comparator level, so a chain where A depends on B and B depends on C could come out
1185
+ * wrong when A and C are never compared directly. Dependencies on plugins missing from the
1186
+ * config are ignored here and surface later through `requirePlugin`.
1187
+ */
1188
+ #sortPlugins(plugins) {
1189
+ const queue = [...plugins].sort((a, b) => enforceWeight(a) - enforceWeight(b));
1190
+ const names = new Set(queue.map((plugin) => plugin.name));
1191
+ const blockedBy = new Map(queue.map((plugin) => [plugin.name, new Set(plugin.dependencies?.filter((name) => names.has(name) && name !== plugin.name))]));
1192
+ const sorted = [];
1193
+ for (const _ of plugins) {
1194
+ const index = queue.findIndex((plugin) => blockedBy.get(plugin.name)?.size === 0);
1195
+ if (index === -1) throw new Diagnostics.Error({
1196
+ code: Diagnostics.code.invalidPluginOptions,
1197
+ severity: "error",
1198
+ message: `Plugin dependencies form a cycle: ${queue.map((plugin) => plugin.name).join(" → ")}.`,
1199
+ help: "Remove one of the `dependencies` entries so the plugins can be ordered.",
1200
+ location: { kind: "config" }
1201
+ });
1202
+ const [plugin] = queue.splice(index, 1);
1203
+ if (!plugin) break;
1204
+ sorted.push(plugin);
1205
+ for (const blockers of blockedBy.values()) blockers.delete(plugin.name);
1206
+ }
1207
+ return sorted;
1208
+ }
1199
1209
  get hooks() {
1200
1210
  return this.options.hooks;
1201
1211
  }
1202
1212
  /**
1203
- * Builds a `NormalizedPlugin` from a hook-style plugin, filling in default
1204
- * options. Registering its lifecycle handlers on the `AsyncEventEmitter` is
1205
- * done separately by `#registerPlugin`.
1206
- */
1207
- #normalizePlugin(plugin) {
1208
- return {
1209
- name: plugin.name,
1210
- dependencies: plugin.dependencies,
1211
- enforce: plugin.enforce,
1212
- hooks: plugin.hooks,
1213
- options: plugin.options ?? {
1214
- output: {
1215
- path: ".",
1216
- mode: "directory"
1217
- },
1218
- exclude: [],
1219
- override: []
1220
- }
1221
- };
1222
- }
1223
- /**
1224
1213
  * Parses the adapter source into `this.inputNode`. Idempotent, so repeated calls from
1225
1214
  * `run` do not re-parse.
1226
1215
  */
@@ -1229,86 +1218,68 @@ var KubbDriver = class {
1229
1218
  this.inputNode = await this.adapter.parse(this.#adapterSource);
1230
1219
  }
1231
1220
  /**
1232
- * Registers a hook-style plugin's lifecycle handlers on the shared `AsyncEventEmitter`.
1233
- *
1234
- * The `kubb:plugin:setup` listener wraps the global context in a plugin-specific one so
1235
- * `addGenerator`, `setResolver`, and `setMacros` target the right `normalizedPlugin`.
1236
- * Every other `KubbHooks` event registers as a pass-through listener that external tooling
1237
- * can observe via `hooks.on(...)`.
1221
+ * Registers a plugin's lifecycle hooks on the shared `Hookable` as pass-through listeners that
1222
+ * external tooling can observe via `hooks.hook(...)`. The returned remover is tracked for
1223
+ * `dispose`. `kubb:plugin:setup` is skipped here; `setupHooks` invokes it directly with a
1224
+ * plugin-scoped context.
1238
1225
  *
1239
1226
  * @internal
1240
1227
  */
1241
1228
  #registerPlugin(plugin) {
1242
1229
  const { hooks } = plugin;
1243
1230
  if (!hooks) return;
1244
- if (hooks["kubb:plugin:setup"]) {
1245
- const setupHandler = (globalCtx) => {
1246
- const pluginCtx = {
1247
- ...globalCtx,
1248
- options: plugin.options ?? {},
1249
- addGenerator: (...generators) => {
1250
- for (const generator of generators.flat()) this.registerGenerator(plugin.name, generator);
1251
- },
1252
- setResolver: (resolver) => {
1253
- this.setPluginResolver(plugin.name, resolver);
1254
- },
1255
- addMacro: (macro) => {
1256
- this.#transforms.add(plugin.name, macro);
1257
- },
1258
- setMacros: (macros) => {
1259
- this.#transforms.set(plugin.name, macros);
1260
- },
1261
- setOptions: (opts) => {
1262
- plugin.options = {
1263
- ...plugin.options,
1264
- ...opts
1265
- };
1266
- if (plugin.options.output) {
1267
- const group = "group" in plugin.options ? plugin.options.group : void 0;
1268
- plugin.options.output = normalizeOutput({
1269
- output: plugin.options.output,
1270
- group,
1271
- pluginName: plugin.name
1272
- });
1273
- }
1274
- },
1275
- injectFile: (userFileNode) => {
1276
- this.fileManager.add(_kubb_ast.ast.factory.createFile(userFileNode));
1277
- }
1278
- };
1279
- return hooks["kubb:plugin:setup"](pluginCtx);
1280
- };
1281
- this.#trackListener("kubb:plugin:setup", setupHandler);
1282
- }
1283
- for (const event of Object.keys(hooks)) {
1284
- if (event === "kubb:plugin:setup") continue;
1285
- const handler = hooks[event];
1286
- if (!handler) continue;
1287
- this.#trackListener(event, handler);
1288
- }
1231
+ const { "kubb:plugin:setup": _setup, ...configHooks } = hooks;
1232
+ this.#unhooks.push(this.hooks.addHooks(configHooks));
1289
1233
  }
1290
1234
  /**
1291
- * Emits the `kubb:plugin:setup` event so that all registered hook-style plugin listeners
1292
- * can configure generators, resolvers, macros and renderers before `buildStart` runs.
1293
- *
1294
- * Called once from `run` before the plugin execution loop begins.
1235
+ * Runs each plugin's `kubb:plugin:setup` handler, in plugin order, with a context scoped to that
1236
+ * plugin so `addGenerator`, `setResolver`, `addMacro`, `setMacros`, and `setOptions` target its
1237
+ * `NormalizedPlugin` entry. Called once from `run` before the plugin execution loop begins, so
1238
+ * plugins can configure generators, resolvers, macros, and options before `buildStart`.
1295
1239
  */
1296
- async emitSetupHooks() {
1240
+ async setupHooks() {
1297
1241
  const noop = () => {};
1298
- await this.hooks.emit("kubb:plugin:setup", {
1299
- config: this.config,
1300
- options: {},
1301
- addGenerator: noop,
1302
- setResolver: noop,
1303
- addMacro: noop,
1304
- setMacros: noop,
1305
- setOptions: noop,
1306
- injectFile: noop,
1307
- updateConfig: noop
1308
- });
1242
+ for (const plugin of this.plugins.values()) {
1243
+ const setup = plugin.hooks?.["kubb:plugin:setup"];
1244
+ if (!setup) continue;
1245
+ await setup({
1246
+ config: this.config,
1247
+ options: plugin.options ?? {},
1248
+ updateConfig: noop,
1249
+ addGenerator: (...generators) => {
1250
+ for (const generator of generators) this.registerGenerator(plugin.name, generator);
1251
+ },
1252
+ setResolver: (resolver) => {
1253
+ this.setPluginResolver(plugin.name, resolver);
1254
+ },
1255
+ addMacro: (macro) => {
1256
+ this.#transforms.add(plugin.name, macro);
1257
+ },
1258
+ setMacros: (macros) => {
1259
+ this.#transforms.set(plugin.name, macros);
1260
+ },
1261
+ setOptions: (opts) => {
1262
+ plugin.options = {
1263
+ ...plugin.options,
1264
+ ...opts
1265
+ };
1266
+ if (plugin.options.output) {
1267
+ const group = "group" in plugin.options ? plugin.options.group : void 0;
1268
+ plugin.options.output = normalizeOutput({
1269
+ output: plugin.options.output,
1270
+ group,
1271
+ pluginName: plugin.name
1272
+ });
1273
+ }
1274
+ },
1275
+ injectFile: (userFileNode) => {
1276
+ this.fileManager.add(_kubb_ast.ast.factory.createFile(userFileNode));
1277
+ }
1278
+ });
1279
+ }
1309
1280
  }
1310
1281
  /**
1311
- * Registers a generator for the given plugin on the shared event emitter.
1282
+ * Registers a generator for the given plugin on the shared hook emitter.
1312
1283
  *
1313
1284
  * The generator's `schema`, `operation`, and `operations` methods are registered as
1314
1285
  * listeners on `kubb:generate:schema`, `kubb:generate:operation`, and `kubb:generate:operations`
@@ -1321,9 +1292,9 @@ var KubbDriver = class {
1321
1292
  * Call this method inside `addGenerator()` (in `kubb:plugin:setup`) to wire up a generator.
1322
1293
  */
1323
1294
  registerGenerator(pluginName, generator) {
1324
- const register = (event, method) => {
1325
- if (!method) return;
1326
- const handler = async (node, ctx) => {
1295
+ const wrap = (method) => {
1296
+ if (!method) return void 0;
1297
+ return async (node, ctx) => {
1327
1298
  if (ctx.plugin.name !== pluginName) return;
1328
1299
  const result = await method(node, ctx);
1329
1300
  await this.dispatch({
@@ -1331,22 +1302,23 @@ var KubbDriver = class {
1331
1302
  renderer: generator.renderer
1332
1303
  });
1333
1304
  };
1334
- this.#trackListener(event, handler);
1335
1305
  };
1336
- register("kubb:generate:schema", generator.schema);
1337
- register("kubb:generate:operation", generator.operation);
1338
- register("kubb:generate:operations", generator.operations);
1339
- this.#eventGeneratorPlugins.add(pluginName);
1306
+ this.#unhooks.push(this.hooks.addHooks({
1307
+ "kubb:generate:schema": wrap(generator.schema),
1308
+ "kubb:generate:operation": wrap(generator.operation),
1309
+ "kubb:generate:operations": wrap(generator.operations)
1310
+ }));
1311
+ this.#hookGeneratorPlugins.add(pluginName);
1340
1312
  }
1341
1313
  /**
1342
1314
  * Returns `true` when at least one generator was registered for the given plugin
1343
1315
  * via `addGenerator()` in `kubb:plugin:setup`.
1344
1316
  *
1345
- * Used by the build loop to decide whether to walk the AST and emit generator events
1317
+ * Used by the build loop to decide whether to walk the AST and emit generator hooks
1346
1318
  * for a plugin.
1347
1319
  */
1348
- hasEventGenerators(pluginName) {
1349
- return this.#eventGeneratorPlugins.has(pluginName);
1320
+ hasHookGenerators(pluginName) {
1321
+ return this.#hookGeneratorPlugins.has(pluginName);
1350
1322
  }
1351
1323
  /**
1352
1324
  * Runs the full plugin pipeline. Returns the diagnostics collected so far even
@@ -1360,29 +1332,31 @@ var KubbDriver = class {
1360
1332
  const parsersMap = /* @__PURE__ */ new Map();
1361
1333
  for (const parser of config.parsers) if (parser.extNames) for (const ext of parser.extNames) parsersMap.set(ext, parser);
1362
1334
  const onWriteStart = async (files) => {
1363
- await hooks.emit("kubb:files:processing:start", { files });
1335
+ await hooks.callHook("kubb:files:processing:start", { files });
1364
1336
  };
1365
1337
  const updateBuffer = [];
1366
1338
  const onWriteUpdate = (item) => {
1367
1339
  updateBuffer.push(item);
1368
1340
  };
1369
1341
  const onWriteEnd = async (files) => {
1370
- await hooks.emit("kubb:files:processing:update", { files: updateBuffer.map((item) => ({
1342
+ await hooks.callHook("kubb:files:processing:update", { files: updateBuffer.map((item) => ({
1371
1343
  ...item,
1372
1344
  config
1373
1345
  })) });
1374
1346
  updateBuffer.length = 0;
1375
- await hooks.emit("kubb:files:processing:end", { files });
1347
+ await hooks.callHook("kubb:files:processing:end", { files });
1376
1348
  };
1377
- fileManager.hooks.on("start", onWriteStart);
1378
- fileManager.hooks.on("update", onWriteUpdate);
1379
- fileManager.hooks.on("end", onWriteEnd);
1349
+ const unhookWrites = fileManager.hooks.addHooks({
1350
+ start: onWriteStart,
1351
+ update: onWriteUpdate,
1352
+ end: onWriteEnd
1353
+ });
1380
1354
  return Diagnostics.scope((diagnostic) => diagnostics.push(diagnostic), async () => {
1381
1355
  try {
1382
1356
  const outputRoot = (0, node_path.resolve)(config.root, config.output.path);
1383
1357
  await this.#parseInput();
1384
- await this.emitSetupHooks();
1385
- if (this.adapter && this.inputNode) await hooks.emit("kubb:build:start", Object.assign({
1358
+ await this.setupHooks();
1359
+ if (this.adapter && this.inputNode) await hooks.callHook("kubb:build:start", Object.assign({
1386
1360
  config,
1387
1361
  adapter: this.adapter,
1388
1362
  meta: this.inputNode.meta,
@@ -1393,9 +1367,9 @@ var KubbDriver = class {
1393
1367
  const context = this.getContext(plugin);
1394
1368
  const hrStart = process.hrtime();
1395
1369
  try {
1396
- await hooks.emit("kubb:plugin:start", { plugin });
1370
+ await hooks.callHook("kubb:plugin:start", { plugin });
1397
1371
  } catch (caughtError) {
1398
- const error = caughtError;
1372
+ const error = require_usingCtx.toError(caughtError);
1399
1373
  const duration = getElapsedMs(hrStart);
1400
1374
  await this.#emitPluginEnd({
1401
1375
  plugin,
@@ -1412,7 +1386,7 @@ var KubbDriver = class {
1412
1386
  }));
1413
1387
  continue;
1414
1388
  }
1415
- if (this.hasEventGenerators(plugin.name)) {
1389
+ if (this.hasHookGenerators(plugin.name)) {
1416
1390
  generatorPlugins.push({
1417
1391
  plugin,
1418
1392
  context,
@@ -1432,13 +1406,13 @@ var KubbDriver = class {
1432
1406
  });
1433
1407
  }
1434
1408
  diagnostics.push(...await this.#runGenerators(generatorPlugins));
1435
- await hooks.emit("kubb:plugins:end", Object.assign({ config }, this.#filesPayload()));
1409
+ await hooks.callHook("kubb:plugins:end", Object.assign({ config }, this.#filesPayload()));
1436
1410
  await fileManager.write(fileManager.files, {
1437
1411
  storage,
1438
1412
  parsers: parsersMap,
1439
1413
  extension: config.output.extension
1440
1414
  });
1441
- await hooks.emit("kubb:build:end", {
1415
+ await hooks.callHook("kubb:build:end", {
1442
1416
  files: this.fileManager.files,
1443
1417
  config,
1444
1418
  outputDir: outputRoot
@@ -1448,9 +1422,7 @@ var KubbDriver = class {
1448
1422
  diagnostics.push(Diagnostics.from(caughtError));
1449
1423
  return { diagnostics: Diagnostics.dedupe(diagnostics) };
1450
1424
  } finally {
1451
- fileManager.hooks.off("start", onWriteStart);
1452
- fileManager.hooks.off("update", onWriteUpdate);
1453
- fileManager.hooks.off("end", onWriteEnd);
1425
+ unhookWrites();
1454
1426
  }
1455
1427
  });
1456
1428
  }
@@ -1464,7 +1436,7 @@ var KubbDriver = class {
1464
1436
  };
1465
1437
  }
1466
1438
  #emitPluginEnd({ plugin, duration, success, error }) {
1467
- return this.hooks.emit("kubb:plugin:end", Object.assign({
1439
+ return this.hooks.callHook("kubb:plugin:end", Object.assign({
1468
1440
  plugin,
1469
1441
  duration,
1470
1442
  success,
@@ -1557,12 +1529,12 @@ var KubbDriver = class {
1557
1529
  if (!resolved) continue;
1558
1530
  const { transformedNode, options } = resolved;
1559
1531
  if (allowedSchemaNames !== null && transformedNode.name && !allowedSchemaNames.has(transformedNode.name)) continue;
1560
- await this.hooks.emit("kubb:generate:schema", transformedNode, {
1532
+ await this.hooks.callHook("kubb:generate:schema", transformedNode, {
1561
1533
  ...generatorContext,
1562
1534
  options
1563
1535
  });
1564
1536
  } catch (caughtError) {
1565
- error = caughtError;
1537
+ error = require_usingCtx.toError(caughtError);
1566
1538
  }
1567
1539
  }
1568
1540
  if (emitsOperationHook) for (const node of operations) {
@@ -1570,12 +1542,12 @@ var KubbDriver = class {
1570
1542
  try {
1571
1543
  const resolved = resolveForPlugin(node);
1572
1544
  if (!resolved) continue;
1573
- await this.hooks.emit("kubb:generate:operation", resolved.transformedNode, {
1545
+ await this.hooks.callHook("kubb:generate:operation", resolved.transformedNode, {
1574
1546
  ...generatorContext,
1575
1547
  options: resolved.options
1576
1548
  });
1577
1549
  } catch (caughtError) {
1578
- error = caughtError;
1550
+ error = require_usingCtx.toError(caughtError);
1579
1551
  }
1580
1552
  }
1581
1553
  if (!error && emitsOperationsHook) try {
@@ -1588,9 +1560,9 @@ var KubbDriver = class {
1588
1560
  if (resolved) acc.push(resolved.transformedNode);
1589
1561
  return acc;
1590
1562
  }, []);
1591
- await this.hooks.emit("kubb:generate:operations", pluginOperations, ctx);
1563
+ await this.hooks.callHook("kubb:generate:operations", pluginOperations, ctx);
1592
1564
  } catch (caughtError) {
1593
- error = caughtError;
1565
+ error = require_usingCtx.toError(caughtError);
1594
1566
  }
1595
1567
  const duration = getElapsedMs(hrStart);
1596
1568
  await this.#emitPluginEnd({
@@ -1647,9 +1619,9 @@ var KubbDriver = class {
1647
1619
  * @internal
1648
1620
  */
1649
1621
  dispose() {
1650
- for (const [event, handler] of this.#listeners) this.hooks.off(event, handler);
1651
- this.#listeners.length = 0;
1652
- this.#eventGeneratorPlugins.clear();
1622
+ for (const unhook of this.#unhooks) unhook();
1623
+ this.#unhooks.length = 0;
1624
+ this.#hookGeneratorPlugins.clear();
1653
1625
  this.#transforms.dispose();
1654
1626
  this.#resolvers.clear();
1655
1627
  this.#defaultResolvers.clear();
@@ -1742,18 +1714,18 @@ var KubbDriver = class {
1742
1714
  return this.plugins.get(pluginName);
1743
1715
  }
1744
1716
  requirePlugin(pluginName, context) {
1745
- const plugin = this.plugins.get(pluginName);
1746
- if (!plugin) {
1747
- const requiredBy = context?.requiredBy;
1748
- throw new Diagnostics.Error({
1749
- code: Diagnostics.code.pluginNotFound,
1750
- severity: "error",
1751
- message: requiredBy ? `Plugin "${pluginName}" is required by "${requiredBy}" but not found. Make sure it is included in your Kubb config.` : `Plugin "${pluginName}" is required but not found. Make sure it is included in your Kubb config.`,
1752
- help: requiredBy ? `Add "${pluginName}" to the \`plugins\` array in kubb.config.ts (required by "${requiredBy}"), or remove the dependency on it.` : `Add "${pluginName}" to the \`plugins\` array in kubb.config.ts, or remove the dependency on it.`,
1753
- location: { kind: "config" }
1754
- });
1755
- }
1756
- return plugin;
1717
+ const plugin = this.getPlugin(pluginName);
1718
+ if (plugin) return plugin;
1719
+ const requiredBy = context?.requiredBy;
1720
+ const by = requiredBy ? ` by "${requiredBy}"` : "";
1721
+ const help = requiredBy ? ` (required by "${requiredBy}")` : "";
1722
+ throw new Diagnostics.Error({
1723
+ code: Diagnostics.code.pluginNotFound,
1724
+ severity: "error",
1725
+ message: `Plugin "${pluginName}" is required${by} but not found. Make sure it is included in your Kubb config.`,
1726
+ help: `Add "${pluginName}" to the \`plugins\` array in kubb.config.ts${help}, or remove the dependency on it.`,
1727
+ location: { kind: "config" }
1728
+ });
1757
1729
  }
1758
1730
  };
1759
1731
  function inputToAdapterSource(config) {
@@ -1942,12 +1914,12 @@ function resolveConfig(userConfig) {
1942
1914
  * `createKubb` takes a plain config object (the shape `defineConfig` produces),
1943
1915
  * not a fluent builder.
1944
1916
  *
1945
- * Attach event listeners to `.hooks` before calling `setup()` or `build()`.
1917
+ * Attach hook listeners to `.hooks` before calling `setup()` or `build()`.
1946
1918
  *
1947
1919
  * @example
1948
1920
  * ```ts
1949
1921
  * const kubb = createKubb(userConfig)
1950
- * kubb.hooks.on('kubb:plugin:end', ({ plugin, duration }) => console.log(plugin.name, duration))
1922
+ * kubb.hooks.hook('kubb:plugin:end', ({ plugin, duration }) => console.log(plugin.name, duration))
1951
1923
  * const { files, diagnostics } = await kubb.safeBuild()
1952
1924
  * ```
1953
1925
  */
@@ -1958,7 +1930,7 @@ var Kubb = class {
1958
1930
  #storage = null;
1959
1931
  constructor(userConfig, options = {}) {
1960
1932
  this.config = resolveConfig(userConfig);
1961
- this.hooks = options.hooks ?? new require_usingCtx.AsyncEventEmitter();
1933
+ this.hooks = options.hooks ?? new require_usingCtx.Hookable();
1962
1934
  }
1963
1935
  get storage() {
1964
1936
  if (!this.#storage) throw new Error("[kubb] setup() must be called before accessing storage");
@@ -2001,9 +1973,9 @@ var Kubb = class {
2001
1973
  try {
2002
1974
  var _usingCtx$1 = require_usingCtx._usingCtx();
2003
1975
  if (!this.#driver) await this.setup();
2004
- const cleanup = _usingCtx$1.u(this);
2005
- const driver = cleanup.driver;
2006
- const storage = cleanup.storage;
1976
+ const self = _usingCtx$1.u(this);
1977
+ const driver = self.driver;
1978
+ const storage = self.storage;
2007
1979
  const { diagnostics } = await driver.run({ storage });
2008
1980
  return {
2009
1981
  diagnostics,
@@ -2064,7 +2036,7 @@ const logLevel = {
2064
2036
  /**
2065
2037
  * Defines a reporter. When the definition has a `drain`, the returned reporter buffers each value
2066
2038
  * `report` returns and hands the array to `drain` once, then clears it. Without a `drain`, nothing
2067
- * is buffered. Wiring the reporter onto the run's events is the host's job, so the reporter only
2039
+ * is buffered. Wiring the reporter onto the run's hooks is the host's job, so the reporter only
2068
2040
  * ever deals with a {@link GenerationResult}.
2069
2041
  *
2070
2042
  * @example
@@ -2248,7 +2220,7 @@ function buildTimingSection(report) {
2248
2220
  * `## Timings` section. Selected with `--reporter file` (or `reporters: ['file']`).
2249
2221
  *
2250
2222
  * @note It captures the collected diagnostics once a config finishes, not the live
2251
- * `kubb:info`/`kubb:plugin` event stream. Color is stripped so the file stays plain text even when
2223
+ * `kubb:info`/`kubb:plugin` hook stream. Color is stripped so the file stays plain text even when
2252
2224
  * the run is attached to a TTY.
2253
2225
  */
2254
2226
  const fileReporter = createReporter({
@@ -2436,8 +2408,8 @@ const memoryStorage = createStorage(() => {
2436
2408
  };
2437
2409
  });
2438
2410
  //#endregion
2439
- exports.AsyncEventEmitter = require_usingCtx.AsyncEventEmitter;
2440
2411
  exports.Diagnostics = Diagnostics;
2412
+ exports.Hookable = require_usingCtx.Hookable;
2441
2413
  exports.KubbDriver = KubbDriver;
2442
2414
  exports.Resolver = Resolver;
2443
2415
  exports.cliReporter = cliReporter;