@kubb/core 5.0.0-beta.37 → 5.0.0-beta.39

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.
@@ -25,12 +25,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
  }) : target, mod));
26
26
  //#endregion
27
27
  let node_events = require("node:events");
28
+ let node_util = require("node:util");
28
29
  let node_path = require("node:path");
29
30
  node_path = __toESM(node_path, 1);
30
31
  let _kubb_ast = require("@kubb/ast");
31
32
  let node_async_hooks = require("node:async_hooks");
32
- let fflate = require("fflate");
33
- let tinyexec = require("tinyexec");
34
33
  //#region ../../internals/utils/src/errors.ts
35
34
  /**
36
35
  * Thrown when one or more errors occur during a Kubb build.
@@ -285,6 +284,21 @@ function getElapsedMs(hrStart) {
285
284
  const ms = seconds * 1e3 + nanoseconds / 1e6;
286
285
  return Math.round(ms * 100) / 100;
287
286
  }
287
+ /**
288
+ * Converts a millisecond duration into a human-readable string (`ms`, `s`, or `m s`).
289
+ *
290
+ * @example
291
+ * ```ts
292
+ * formatMs(250) // '250ms'
293
+ * formatMs(1500) // '1.50s'
294
+ * formatMs(90000) // '1m 30.0s'
295
+ * ```
296
+ */
297
+ function formatMs(ms) {
298
+ if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`;
299
+ if (ms >= 1e3) return `${(ms / 1e3).toFixed(2)}s`;
300
+ return `${Math.round(ms)}ms`;
301
+ }
288
302
  //#endregion
289
303
  //#region ../../internals/utils/src/promise.ts
290
304
  function* chunks(arr, size) {
@@ -646,11 +660,14 @@ var URLPath = class {
646
660
  }
647
661
  };
648
662
  //#endregion
663
+ //#region package.json
664
+ var version = "5.0.0-beta.39";
665
+ //#endregion
649
666
  //#region src/constants.ts
650
667
  /**
651
- * Base URL for the Kubb Studio web app.
668
+ * OpenTelemetry ingestion endpoint for anonymous usage telemetry.
652
669
  */
653
- const DEFAULT_STUDIO_URL = "https://kubb.studio";
670
+ const OTLP_ENDPOINT = "https://otlp.kubb.dev";
654
671
  /**
655
672
  * Plugin `include` filter types that select operations directly. When one of these is set
656
673
  * without a `schemaName` include, the generate phase pre-scans operations to compute the set
@@ -664,18 +681,6 @@ const OPERATION_FILTER_TYPES = new Set([
664
681
  "contentType"
665
682
  ]);
666
683
  /**
667
- * Numeric log-level thresholds used internally to compare verbosity.
668
- *
669
- * Higher numbers are more verbose.
670
- */
671
- const logLevel = {
672
- silent: Number.NEGATIVE_INFINITY,
673
- error: 0,
674
- warn: 1,
675
- info: 3,
676
- verbose: 4
677
- };
678
- /**
679
684
  * Stable codes Kubb attaches to a `Diagnostic`. Each maps to a known failure mode
680
685
  * and stays stable so it can be referenced in tooling and (later) docs. Reference
681
686
  * these instead of inlining the string at a throw site.
@@ -733,10 +738,6 @@ const diagnosticCode = {
733
738
  */
734
739
  adapterRequired: "KUBB_ADAPTER_REQUIRED",
735
740
  /**
736
- * The `devtools` config is set to something other than an object.
737
- */
738
- devtoolsInvalid: "KUBB_DEVTOOLS_INVALID",
739
- /**
740
741
  * A resolved output path escapes the output directory, which can stem from a path
741
742
  * traversal in the spec or a misconfigured `group.name`.
742
743
  */
@@ -767,19 +768,19 @@ const diagnosticCode = {
767
768
  /**
768
769
  * Docs major, derived from the package version so the link tracks the published major.
769
770
  */
770
- const docsMajor = "5.0.0-beta.37".split(".")[0] ?? "5";
771
+ const docsMajor = version.split(".")[0] ?? "5";
771
772
  /**
772
773
  * Narrows a {@link Diagnostic} to the variant for `code`, or `null` when it does not match.
773
774
  *
774
775
  * @example
775
776
  * ```ts
776
- * const update = narrowDiagnostic(diagnostic, diagnosticCode.updateAvailable)
777
+ * const update = narrow(diagnostic, diagnosticCode.updateAvailable)
777
778
  * if (update) {
778
779
  * console.log(update.latestVersion)
779
780
  * }
780
781
  * ```
781
782
  */
782
- function narrowDiagnostic(diagnostic, code) {
783
+ function narrow(diagnostic, code) {
783
784
  return diagnostic.code === code ? diagnostic : null;
784
785
  }
785
786
  /**
@@ -794,59 +795,51 @@ function isKind(kind) {
794
795
  *
795
796
  * @example
796
797
  * ```ts
797
- * if (isProblemDiagnostic(diagnostic)) {
798
+ * if (isProblem(diagnostic)) {
798
799
  * console.log(diagnostic.location)
799
800
  * }
800
801
  * ```
801
802
  */
802
- const isProblemDiagnostic = isKind("problem");
803
+ const isProblem = isKind("problem");
803
804
  /**
804
805
  * Returns `true` when the diagnostic is a per-plugin {@link PerformanceDiagnostic}.
805
806
  *
806
807
  * @example
807
808
  * ```ts
808
- * const timings = diagnostics.filter(isPerformanceDiagnostic)
809
+ * const timings = diagnostics.filter(isPerformance)
809
810
  * ```
810
811
  */
811
- const isPerformanceDiagnostic = isKind("performance");
812
+ const isPerformance = isKind("performance");
812
813
  /**
813
814
  * Returns `true` when the diagnostic is a version-update {@link UpdateDiagnostic}.
814
815
  *
815
816
  * @example
816
817
  * ```ts
817
- * if (isUpdateDiagnostic(diagnostic)) {
818
+ * if (isUpdate(diagnostic)) {
818
819
  * console.log(diagnostic.latestVersion)
819
820
  * }
820
821
  * ```
821
822
  */
822
- const isUpdateDiagnostic = isKind("update");
823
+ const isUpdate = isKind("update");
823
824
  /**
824
- * An `Error` that carries a {@link Diagnostic}, so structured problems can flow
825
- * through the existing throw/catch paths while keeping their code and location.
826
- *
827
- * @example
828
- * ```ts
829
- * throw new DiagnosticError({ code: diagnosticCode.refNotFound, severity: 'error', message: `Could not find ${ref}`, location: { kind: 'schema', pointer: ref, ref } })
830
- * ```
825
+ * Glyph and accent color per severity, matching the miette/oxlint convention
826
+ * (`×` error, `⚠` warning, `ℹ` advice).
831
827
  */
832
- var DiagnosticError = class extends Error {
833
- diagnostic;
834
- constructor(diagnostic) {
835
- super(diagnostic.message, { cause: diagnostic.cause });
836
- this.name = "DiagnosticError";
837
- this.diagnostic = diagnostic;
828
+ const severityStyle = {
829
+ error: {
830
+ glyph: "×",
831
+ color: "red"
832
+ },
833
+ warning: {
834
+ glyph: "⚠",
835
+ color: "yellow"
836
+ },
837
+ info: {
838
+ glyph: "ℹ",
839
+ color: "blue"
838
840
  }
839
841
  };
840
842
  /**
841
- * Structural check for a {@link DiagnosticError}, including one thrown from a duplicated
842
- * `@kubb/core` copy where `instanceof` fails. Matches on the `name` and a `diagnostic`
843
- * that carries a `code`.
844
- */
845
- function isDiagnosticError(error) {
846
- if (error instanceof DiagnosticError) return true;
847
- return error instanceof Error && error.name === "DiagnosticError" && "diagnostic" in error && typeof error.diagnostic === "object" && error.diagnostic !== null && typeof error.diagnostic?.code === "string";
848
- }
849
- /**
850
843
  * Explanation for every {@link diagnosticCode}. Use {@link Diagnostics.explain} to look one up
851
844
  * and `Diagnostics.docsUrl` for the matching kubb.dev page.
852
845
  */
@@ -908,14 +901,9 @@ const diagnosticCatalog = {
908
901
  },
909
902
  [diagnosticCode.adapterRequired]: {
910
903
  title: "Adapter required",
911
- cause: "An action needs an adapter (for example opening Kubb Studio) but none is configured.",
904
+ cause: "An action needs an adapter but none is configured.",
912
905
  fix: "Set `adapter` in kubb.config.ts, for example `adapterOas()`."
913
906
  },
914
- [diagnosticCode.devtoolsInvalid]: {
915
- title: "Invalid devtools config",
916
- cause: "The `devtools` config is set to something other than an object.",
917
- fix: "Set `devtools` to an options object, or remove it to disable Kubb Studio."
918
- },
919
907
  [diagnosticCode.pathTraversal]: {
920
908
  title: "Path traversal",
921
909
  cause: "A resolved output path escaped the output directory, which can stem from a path traversal in the spec or a misconfigured `group.name`.",
@@ -959,6 +947,52 @@ const diagnosticCatalog = {
959
947
  var Diagnostics = class Diagnostics {
960
948
  static #reporterStorage = new node_async_hooks.AsyncLocalStorage();
961
949
  /**
950
+ * The diagnostic code catalog, exposed as `Diagnostics.code` (e.g. `Diagnostics.code.refNotFound`).
951
+ */
952
+ static code = diagnosticCode;
953
+ /**
954
+ * Type guard for a build {@link ProblemDiagnostic}.
955
+ */
956
+ static isProblem = isProblem;
957
+ /**
958
+ * Type guard for a version-update {@link UpdateDiagnostic}.
959
+ */
960
+ static isUpdate = isUpdate;
961
+ /**
962
+ * Type guard for a per-plugin {@link PerformanceDiagnostic}.
963
+ */
964
+ static isPerformance = isPerformance;
965
+ /**
966
+ * Narrows a {@link Diagnostic} to the variant for `code`, or `null` when it does not match.
967
+ */
968
+ static narrow = narrow;
969
+ /**
970
+ * An `Error` that carries a {@link Diagnostic}, so structured problems can flow
971
+ * through the existing throw/catch paths while keeping their code and location.
972
+ *
973
+ * @example
974
+ * ```ts
975
+ * throw new Diagnostics.Error({ code: diagnosticCode.refNotFound, severity: 'error', message: `Could not find ${ref}`, location: { kind: 'schema', pointer: ref, ref } })
976
+ * ```
977
+ */
978
+ static Error = class DiagnosticError extends Error {
979
+ diagnostic;
980
+ constructor(diagnostic) {
981
+ super(diagnostic.message, { cause: diagnostic.cause });
982
+ this.name = "DiagnosticError";
983
+ this.diagnostic = diagnostic;
984
+ }
985
+ };
986
+ /**
987
+ * Structural check for a {@link Diagnostics.Error}, including one thrown from a duplicated
988
+ * `@kubb/core` copy where `instanceof` fails. Matches on the `name` and a `diagnostic`
989
+ * that carries a `code`.
990
+ */
991
+ static isError(error) {
992
+ if (error instanceof Diagnostics.Error) return true;
993
+ return error instanceof Error && error.name === "DiagnosticError" && "diagnostic" in error && typeof error.diagnostic === "object" && error.diagnostic !== null && typeof error.diagnostic?.code === "string";
994
+ }
995
+ /**
962
996
  * Runs `fn` with `sink` as the active diagnostic sink for the whole async
963
997
  * subtree, so {@link Diagnostics.report} reaches it from anywhere inside.
964
998
  */
@@ -986,7 +1020,7 @@ var Diagnostics = class Diagnostics {
986
1020
  await hooks.emit("kubb:diagnostic", { diagnostic });
987
1021
  }
988
1022
  /**
989
- * Coerces any thrown value into a {@link ProblemDiagnostic}. A {@link DiagnosticError}
1023
+ * Coerces any thrown value into a {@link ProblemDiagnostic}. A {@link Diagnostics.Error}
990
1024
  * keeps its structured data, and anything else becomes a `KUBB_UNKNOWN` error.
991
1025
  */
992
1026
  static from(error) {
@@ -994,7 +1028,7 @@ var Diagnostics = class Diagnostics {
994
1028
  let current = error;
995
1029
  let root;
996
1030
  while (current instanceof Error && !seen.has(current)) {
997
- if (isDiagnosticError(current)) return current.diagnostic;
1031
+ if (Diagnostics.isError(current)) return current.diagnostic;
998
1032
  seen.add(current);
999
1033
  root = current;
1000
1034
  current = current.cause;
@@ -1057,7 +1091,7 @@ var Diagnostics = class Diagnostics {
1057
1091
  let warnings = 0;
1058
1092
  let infos = 0;
1059
1093
  for (const diagnostic of diagnostics) {
1060
- if (!isProblemDiagnostic(diagnostic)) continue;
1094
+ if (!isProblem(diagnostic)) continue;
1061
1095
  if (diagnostic.severity === "error") errors += 1;
1062
1096
  else if (diagnostic.severity === "warning") warnings += 1;
1063
1097
  else infos += 1;
@@ -1077,7 +1111,7 @@ var Diagnostics = class Diagnostics {
1077
1111
  const seen = /* @__PURE__ */ new Set();
1078
1112
  const result = [];
1079
1113
  for (const diagnostic of diagnostics) {
1080
- if (!isProblemDiagnostic(diagnostic)) {
1114
+ if (!isProblem(diagnostic)) {
1081
1115
  result.push(diagnostic);
1082
1116
  continue;
1083
1117
  }
@@ -1109,7 +1143,7 @@ var Diagnostics = class Diagnostics {
1109
1143
  * fields are omitted rather than set to `undefined`.
1110
1144
  */
1111
1145
  static serialize(diagnostic) {
1112
- const problem = isProblemDiagnostic(diagnostic) ? diagnostic : void 0;
1146
+ const problem = isProblem(diagnostic) ? diagnostic : void 0;
1113
1147
  return {
1114
1148
  code: diagnostic.code,
1115
1149
  severity: diagnostic.severity,
@@ -1120,8 +1154,82 @@ var Diagnostics = class Diagnostics {
1120
1154
  ...diagnostic.code === diagnosticCode.unknown ? {} : { docsUrl: Diagnostics.docsUrl(diagnostic.code) }
1121
1155
  };
1122
1156
  }
1157
+ /**
1158
+ * Renders a {@link Diagnostic} for terminal output as its parts: the colored severity `symbol`
1159
+ * (the gutter glyph), the `plugin(CODE): message` `headline`, and the `details` lines (optional
1160
+ * `at <pointer>`, `help:`, and `docs:`).
1161
+ *
1162
+ * Hosts compose these to fit their gutter: a clack logger passes `symbol` as its own gutter and
1163
+ * `[headline, ...details]` as the message, while plain text outputs use {@link Diagnostics.formatLines}.
1164
+ */
1165
+ static format(diagnostic) {
1166
+ const { code, severity, message } = diagnostic;
1167
+ const { glyph, color } = severityStyle[severity];
1168
+ const problem = isProblem(diagnostic) ? diagnostic : void 0;
1169
+ const rule = (0, node_util.styleText)(color, (0, node_util.styleText)("bold", problem?.plugin ? `${problem.plugin}(${code})` : code));
1170
+ const details = [];
1171
+ if (problem?.location && "pointer" in problem.location) details.push(` ${(0, node_util.styleText)("dim", "at")} ${(0, node_util.styleText)("cyan", problem.location.pointer)}`);
1172
+ if (problem?.help) details.push(` ${(0, node_util.styleText)("cyan", "help:")} ${problem.help}`);
1173
+ if (code !== diagnosticCode.unknown) details.push(` ${(0, node_util.styleText)("dim", "docs:")} ${(0, node_util.styleText)("cyan", Diagnostics.docsUrl(code))}`);
1174
+ return {
1175
+ symbol: (0, node_util.styleText)(color, (0, node_util.styleText)("bold", glyph)),
1176
+ headline: `${rule}: ${message}`,
1177
+ details
1178
+ };
1179
+ }
1180
+ /**
1181
+ * The self-contained block form of {@link Diagnostics.format}: `${symbol} ${headline}` followed by
1182
+ * the detail lines. Used where there is no gutter to own the symbol (plain and file output).
1183
+ */
1184
+ static formatLines(diagnostic) {
1185
+ const { symbol, headline, details } = Diagnostics.format(diagnostic);
1186
+ return [`${symbol} ${headline}`, ...details];
1187
+ }
1123
1188
  };
1124
1189
  //#endregion
1190
+ //#region src/createStorage.ts
1191
+ /**
1192
+ * Defines a custom storage backend. The builder receives user options and
1193
+ * returns a `Storage` implementation. Kubb ships with filesystem and
1194
+ * in-memory storages, reach for this when you need to write generated files
1195
+ * elsewhere (cloud storage, a database, a remote API).
1196
+ *
1197
+ * @example In-memory storage (the built-in implementation)
1198
+ * ```ts
1199
+ * import { createStorage } from '@kubb/core'
1200
+ *
1201
+ * export const memoryStorage = createStorage(() => {
1202
+ * const store = new Map<string, string>()
1203
+ *
1204
+ * return {
1205
+ * name: 'memory',
1206
+ * async hasItem(key) {
1207
+ * return store.has(key)
1208
+ * },
1209
+ * async getItem(key) {
1210
+ * return store.get(key) ?? null
1211
+ * },
1212
+ * async setItem(key, value) {
1213
+ * store.set(key, value)
1214
+ * },
1215
+ * async removeItem(key) {
1216
+ * store.delete(key)
1217
+ * },
1218
+ * async getKeys(base) {
1219
+ * const keys = [...store.keys()]
1220
+ * return base ? keys.filter((k) => k.startsWith(base)) : keys
1221
+ * },
1222
+ * async clear(base) {
1223
+ * if (!base) store.clear()
1224
+ * },
1225
+ * }
1226
+ * })
1227
+ * ```
1228
+ */
1229
+ function createStorage(build) {
1230
+ return (options) => build(options ?? {});
1231
+ }
1232
+ //#endregion
1125
1233
  //#region src/definePlugin.ts
1126
1234
  /**
1127
1235
  * Wraps a plugin factory and returns a function that accepts user options and
@@ -1349,8 +1457,8 @@ function defaultResolvePath({ baseName, pathMode, tag, path: groupPath }, { root
1349
1457
  })();
1350
1458
  const outputDir = node_path.default.resolve(root, output.path);
1351
1459
  const outputDirWithSep = outputDir.endsWith(node_path.default.sep) ? outputDir : `${outputDir}${node_path.default.sep}`;
1352
- if (result !== outputDir && !result.startsWith(outputDirWithSep)) throw new DiagnosticError({
1353
- code: diagnosticCode.pathTraversal,
1460
+ if (result !== outputDir && !result.startsWith(outputDirWithSep)) throw new Diagnostics.Error({
1461
+ code: Diagnostics.code.pathTraversal,
1354
1462
  severity: "error",
1355
1463
  message: `Resolved path "${result}" is outside the output directory "${outputDir}".`,
1356
1464
  help: "This can stem from a path traversal in the OpenAPI specification or a misconfigured `group.name` function. Keep generated paths within the output directory.",
@@ -1574,47 +1682,6 @@ function defineResolver(build) {
1574
1682
  return resolver;
1575
1683
  }
1576
1684
  //#endregion
1577
- //#region src/devtools.ts
1578
- /**
1579
- * Encodes an `InputNode` as a compressed, URL-safe string.
1580
- *
1581
- * The JSON representation is deflate-compressed with {@link deflateSync} before
1582
- * base64url encoding, which typically reduces payload size by 70, 80 % and
1583
- * keeps URLs well within browser and server path-length limits.
1584
- */
1585
- function encodeAst(input) {
1586
- const compressed = (0, fflate.deflateSync)(new TextEncoder().encode(JSON.stringify(input)));
1587
- return Buffer.from(compressed).toString("base64url");
1588
- }
1589
- /**
1590
- * Constructs the Kubb Studio URL for the given `InputNode`.
1591
- * When `options.ast` is `true`, navigates to the AST inspector (`/ast`).
1592
- * The `input` is encoded and attached as the `?root=` query parameter so Studio
1593
- * can decode and render it without a round-trip to any server.
1594
- */
1595
- function getStudioUrl(input, studioUrl, options = {}) {
1596
- return `${studioUrl.replace(/\/$/, "")}${options.ast ? "/ast" : ""}?root=${encodeAst(input)}`;
1597
- }
1598
- /**
1599
- * Opens the Kubb Studio URL for the given `InputNode` in the default browser, *
1600
- * Falls back to printing the URL if the browser cannot be launched.
1601
- */
1602
- async function openInStudio(input, studioUrl, options = {}) {
1603
- const url = getStudioUrl(input, studioUrl, options);
1604
- const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
1605
- const args = process.platform === "win32" ? [
1606
- "/c",
1607
- "start",
1608
- "",
1609
- url
1610
- ] : [url];
1611
- try {
1612
- await (0, tinyexec.x)(cmd, args);
1613
- } catch {
1614
- console.log(`\n ${url}\n`);
1615
- }
1616
- }
1617
- //#endregion
1618
1685
  //#region src/FileManager.ts
1619
1686
  function mergeFile(a, b) {
1620
1687
  return {
@@ -2020,19 +2087,10 @@ var KubbDriver = class KubbDriver {
2020
2087
  inputNode = null;
2021
2088
  adapter = null;
2022
2089
  /**
2023
- * Studio session state, kept together so `dispose()` can reset it atomically.
2024
- *
2025
- * - `source` holds the raw adapter source so `adapter.parse()` can be called lazily.
2026
- * Intentionally outlives the build, cleared by `dispose()`.
2027
- * - `isOpen` prevents opening the studio more than once per build.
2028
- * - `inputNode` caches the parse promise so `adapter.parse()` is called at most once
2029
- * per studio session, even when `openInStudio()` is called multiple times.
2030
- */
2031
- #studio = {
2032
- source: null,
2033
- isOpen: false,
2034
- inputNode: null
2035
- };
2090
+ * Raw adapter source so `adapter.parse()` / `adapter.stream()` can run lazily.
2091
+ * Intentionally outlives the build, cleared by `dispose()`.
2092
+ */
2093
+ #adapterSource = null;
2036
2094
  /**
2037
2095
  * Central file store for all generated files.
2038
2096
  * Plugins should use `this.addFile()` / `this.upsertFile()` (via their context) to
@@ -2077,7 +2135,7 @@ var KubbDriver = class KubbDriver {
2077
2135
  this.plugins.set(plugin.name, plugin);
2078
2136
  }
2079
2137
  if (this.config.middleware) for (const middleware of this.config.middleware) for (const event of Object.keys(middleware.hooks)) this.#registerMiddleware(event, middleware.hooks);
2080
- if (this.config.adapter) this.#studio.source = inputToAdapterSource(this.config);
2138
+ if (this.config.adapter) this.#adapterSource = inputToAdapterSource(this.config);
2081
2139
  }
2082
2140
  get hooks() {
2083
2141
  return this.options.hooks;
@@ -2103,14 +2161,14 @@ var KubbDriver = class KubbDriver {
2103
2161
  }
2104
2162
  /**
2105
2163
  * Parses the adapter source into `this.inputNode`. Idempotent, so repeated calls from
2106
- * `run` or the studio path do not re-parse. Adapters with `stream()` are used directly.
2164
+ * `run` do not re-parse. Adapters with `stream()` are used directly.
2107
2165
  * Adapters with only `parse()` are wrapped via `createStreamInput` so the dispatch loop
2108
2166
  * stays stream-only.
2109
2167
  */
2110
2168
  async #parseInput() {
2111
- if (this.inputNode || !this.adapter || !this.#studio.source) return;
2169
+ if (this.inputNode || !this.adapter || !this.#adapterSource) return;
2112
2170
  const adapter = this.adapter;
2113
- const source = this.#studio.source;
2171
+ const source = this.#adapterSource;
2114
2172
  if (adapter.stream) {
2115
2173
  this.inputNode = await adapter.stream(source);
2116
2174
  return;
@@ -2633,11 +2691,7 @@ var KubbDriver = class KubbDriver {
2633
2691
  this.#defaultResolvers.clear();
2634
2692
  this.fileManager.dispose();
2635
2693
  this.inputNode = null;
2636
- this.#studio = {
2637
- source: null,
2638
- isOpen: false,
2639
- inputNode: null
2640
- };
2694
+ this.#adapterSource = null;
2641
2695
  }
2642
2696
  [Symbol.dispose]() {
2643
2697
  this.dispose();
@@ -2670,15 +2724,6 @@ var KubbDriver = class KubbDriver {
2670
2724
  ...diagnostic,
2671
2725
  plugin: plugin.name
2672
2726
  });
2673
- if (diagnostic.severity === "error") {
2674
- driver.hooks.emit("kubb:error", { error: diagnostic.cause ?? new Error(diagnostic.message) });
2675
- return;
2676
- }
2677
- if (diagnostic.severity === "warning") {
2678
- driver.hooks.emit("kubb:warn", { message: diagnostic.message });
2679
- return;
2680
- }
2681
- driver.hooks.emit("kubb:info", { message: diagnostic.message });
2682
2727
  };
2683
2728
  return {
2684
2729
  config: driver.config,
@@ -2717,7 +2762,7 @@ var KubbDriver = class KubbDriver {
2717
2762
  },
2718
2763
  warn(message) {
2719
2764
  report({
2720
- code: diagnosticCode.pluginWarning,
2765
+ code: Diagnostics.code.pluginWarning,
2721
2766
  severity: "warning",
2722
2767
  message
2723
2768
  });
@@ -2725,7 +2770,7 @@ var KubbDriver = class KubbDriver {
2725
2770
  error(error) {
2726
2771
  const cause = typeof error === "string" ? void 0 : error;
2727
2772
  report({
2728
- code: diagnosticCode.pluginFailed,
2773
+ code: Diagnostics.code.pluginFailed,
2729
2774
  severity: "error",
2730
2775
  message: typeof error === "string" ? error : error.message,
2731
2776
  cause
@@ -2733,31 +2778,10 @@ var KubbDriver = class KubbDriver {
2733
2778
  },
2734
2779
  info(message) {
2735
2780
  report({
2736
- code: diagnosticCode.pluginInfo,
2781
+ code: Diagnostics.code.pluginInfo,
2737
2782
  severity: "info",
2738
2783
  message
2739
2784
  });
2740
- },
2741
- async openInStudio(options) {
2742
- if (!driver.config.devtools || driver.#studio.isOpen) return;
2743
- if (typeof driver.config.devtools !== "object") throw new DiagnosticError({
2744
- code: diagnosticCode.devtoolsInvalid,
2745
- severity: "error",
2746
- message: "The `devtools` config must be an object.",
2747
- help: "Set `devtools` to an options object, or remove it to disable Kubb Studio.",
2748
- location: { kind: "config" }
2749
- });
2750
- if (!driver.adapter || !driver.#studio.source) throw new DiagnosticError({
2751
- code: diagnosticCode.adapterRequired,
2752
- severity: "error",
2753
- message: "An adapter is required to open Kubb Studio, but none is configured.",
2754
- help: "Set `adapter` in kubb.config.ts (for example `adapterOas()`).",
2755
- location: { kind: "config" }
2756
- });
2757
- driver.#studio.isOpen = true;
2758
- const studioUrl = driver.config.devtools?.studioUrl ?? "https://kubb.studio";
2759
- driver.#studio.inputNode ??= Promise.resolve(driver.adapter.parse(driver.#studio.source));
2760
- return openInStudio(await driver.#studio.inputNode, studioUrl, options);
2761
2785
  }
2762
2786
  };
2763
2787
  }
@@ -2766,8 +2790,8 @@ var KubbDriver = class KubbDriver {
2766
2790
  }
2767
2791
  requirePlugin(pluginName) {
2768
2792
  const plugin = this.plugins.get(pluginName);
2769
- if (!plugin) throw new DiagnosticError({
2770
- code: diagnosticCode.pluginNotFound,
2793
+ if (!plugin) throw new Diagnostics.Error({
2794
+ code: Diagnostics.code.pluginNotFound,
2771
2795
  severity: "error",
2772
2796
  message: `Plugin "${pluginName}" is required but not found. Make sure it is included in your Kubb config.`,
2773
2797
  help: `Add "${pluginName}" to the \`plugins\` array in kubb.config.ts, or remove the dependency on it.`,
@@ -2778,8 +2802,8 @@ var KubbDriver = class KubbDriver {
2778
2802
  };
2779
2803
  function inputToAdapterSource(config) {
2780
2804
  const input = config.input;
2781
- if (!input) throw new DiagnosticError({
2782
- code: diagnosticCode.inputRequired,
2805
+ if (!input) throw new Diagnostics.Error({
2806
+ code: Diagnostics.code.inputRequired,
2783
2807
  severity: "error",
2784
2808
  message: "An adapter is configured without an input.",
2785
2809
  help: "Provide `input.path` (a file or URL) or `input.data` (an inline spec) in your Kubb config.",
@@ -2799,6 +2823,56 @@ function inputToAdapterSource(config) {
2799
2823
  };
2800
2824
  }
2801
2825
  //#endregion
2826
+ //#region src/storages/memoryStorage.ts
2827
+ /**
2828
+ * In-memory storage driver. Useful for testing and dry-run scenarios where
2829
+ * generated output should be captured without touching the filesystem.
2830
+ *
2831
+ * All data lives in a `Map` scoped to the storage instance and is discarded
2832
+ * when the instance is garbage-collected.
2833
+ *
2834
+ * @example
2835
+ * ```ts
2836
+ * import { memoryStorage } from '@kubb/core'
2837
+ * import { defineConfig } from 'kubb'
2838
+ *
2839
+ * export default defineConfig({
2840
+ * input: { path: './petStore.yaml' },
2841
+ * output: { path: './src/gen' },
2842
+ * storage: memoryStorage(),
2843
+ * })
2844
+ * ```
2845
+ */
2846
+ const memoryStorage = createStorage(() => {
2847
+ const store = /* @__PURE__ */ new Map();
2848
+ return {
2849
+ name: "memory",
2850
+ async hasItem(key) {
2851
+ return store.has(key);
2852
+ },
2853
+ async getItem(key) {
2854
+ return store.get(key) ?? null;
2855
+ },
2856
+ async setItem(key, value) {
2857
+ store.set(key, value);
2858
+ },
2859
+ async removeItem(key) {
2860
+ store.delete(key);
2861
+ },
2862
+ async getKeys(base) {
2863
+ const keys = [...store.keys()];
2864
+ return base ? keys.filter((k) => k.startsWith(base)) : keys;
2865
+ },
2866
+ async clear(base) {
2867
+ if (!base) {
2868
+ store.clear();
2869
+ return;
2870
+ }
2871
+ for (const key of store.keys()) if (key.startsWith(base)) store.delete(key);
2872
+ }
2873
+ };
2874
+ });
2875
+ //#endregion
2802
2876
  Object.defineProperty(exports, "AsyncEventEmitter", {
2803
2877
  enumerable: true,
2804
2878
  get: function() {
@@ -2811,18 +2885,6 @@ Object.defineProperty(exports, "BuildError", {
2811
2885
  return BuildError;
2812
2886
  }
2813
2887
  });
2814
- Object.defineProperty(exports, "DEFAULT_STUDIO_URL", {
2815
- enumerable: true,
2816
- get: function() {
2817
- return DEFAULT_STUDIO_URL;
2818
- }
2819
- });
2820
- Object.defineProperty(exports, "DiagnosticError", {
2821
- enumerable: true,
2822
- get: function() {
2823
- return DiagnosticError;
2824
- }
2825
- });
2826
2888
  Object.defineProperty(exports, "Diagnostics", {
2827
2889
  enumerable: true,
2828
2890
  get: function() {
@@ -2847,10 +2909,10 @@ Object.defineProperty(exports, "KubbDriver", {
2847
2909
  return KubbDriver;
2848
2910
  }
2849
2911
  });
2850
- Object.defineProperty(exports, "URLPath", {
2912
+ Object.defineProperty(exports, "OTLP_ENDPOINT", {
2851
2913
  enumerable: true,
2852
2914
  get: function() {
2853
- return URLPath;
2915
+ return OTLP_ENDPOINT;
2854
2916
  }
2855
2917
  });
2856
2918
  Object.defineProperty(exports, "__name", {
@@ -2871,59 +2933,47 @@ Object.defineProperty(exports, "_usingCtx", {
2871
2933
  return _usingCtx;
2872
2934
  }
2873
2935
  });
2874
- Object.defineProperty(exports, "definePlugin", {
2875
- enumerable: true,
2876
- get: function() {
2877
- return definePlugin;
2878
- }
2879
- });
2880
- Object.defineProperty(exports, "defineResolver", {
2881
- enumerable: true,
2882
- get: function() {
2883
- return defineResolver;
2884
- }
2885
- });
2886
- Object.defineProperty(exports, "diagnosticCatalog", {
2936
+ Object.defineProperty(exports, "camelCase", {
2887
2937
  enumerable: true,
2888
2938
  get: function() {
2889
- return diagnosticCatalog;
2939
+ return camelCase;
2890
2940
  }
2891
2941
  });
2892
- Object.defineProperty(exports, "diagnosticCode", {
2942
+ Object.defineProperty(exports, "createStorage", {
2893
2943
  enumerable: true,
2894
2944
  get: function() {
2895
- return diagnosticCode;
2945
+ return createStorage;
2896
2946
  }
2897
2947
  });
2898
- Object.defineProperty(exports, "isPerformanceDiagnostic", {
2948
+ Object.defineProperty(exports, "definePlugin", {
2899
2949
  enumerable: true,
2900
2950
  get: function() {
2901
- return isPerformanceDiagnostic;
2951
+ return definePlugin;
2902
2952
  }
2903
2953
  });
2904
- Object.defineProperty(exports, "isProblemDiagnostic", {
2954
+ Object.defineProperty(exports, "defineResolver", {
2905
2955
  enumerable: true,
2906
2956
  get: function() {
2907
- return isProblemDiagnostic;
2957
+ return defineResolver;
2908
2958
  }
2909
2959
  });
2910
- Object.defineProperty(exports, "isUpdateDiagnostic", {
2960
+ Object.defineProperty(exports, "formatMs", {
2911
2961
  enumerable: true,
2912
2962
  get: function() {
2913
- return isUpdateDiagnostic;
2963
+ return formatMs;
2914
2964
  }
2915
2965
  });
2916
- Object.defineProperty(exports, "logLevel", {
2966
+ Object.defineProperty(exports, "getElapsedMs", {
2917
2967
  enumerable: true,
2918
2968
  get: function() {
2919
- return logLevel;
2969
+ return getElapsedMs;
2920
2970
  }
2921
2971
  });
2922
- Object.defineProperty(exports, "narrowDiagnostic", {
2972
+ Object.defineProperty(exports, "memoryStorage", {
2923
2973
  enumerable: true,
2924
2974
  get: function() {
2925
- return narrowDiagnostic;
2975
+ return memoryStorage;
2926
2976
  }
2927
2977
  });
2928
2978
 
2929
- //# sourceMappingURL=KubbDriver-CXoKVRxI.cjs.map
2979
+ //# sourceMappingURL=memoryStorage-DHi1d0To.cjs.map