@kubb/core 5.0.0-beta.38 → 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.38".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();
@@ -2708,7 +2762,7 @@ var KubbDriver = class KubbDriver {
2708
2762
  },
2709
2763
  warn(message) {
2710
2764
  report({
2711
- code: diagnosticCode.pluginWarning,
2765
+ code: Diagnostics.code.pluginWarning,
2712
2766
  severity: "warning",
2713
2767
  message
2714
2768
  });
@@ -2716,7 +2770,7 @@ var KubbDriver = class KubbDriver {
2716
2770
  error(error) {
2717
2771
  const cause = typeof error === "string" ? void 0 : error;
2718
2772
  report({
2719
- code: diagnosticCode.pluginFailed,
2773
+ code: Diagnostics.code.pluginFailed,
2720
2774
  severity: "error",
2721
2775
  message: typeof error === "string" ? error : error.message,
2722
2776
  cause
@@ -2724,31 +2778,10 @@ var KubbDriver = class KubbDriver {
2724
2778
  },
2725
2779
  info(message) {
2726
2780
  report({
2727
- code: diagnosticCode.pluginInfo,
2781
+ code: Diagnostics.code.pluginInfo,
2728
2782
  severity: "info",
2729
2783
  message
2730
2784
  });
2731
- },
2732
- async openInStudio(options) {
2733
- if (!driver.config.devtools || driver.#studio.isOpen) return;
2734
- if (typeof driver.config.devtools !== "object") throw new DiagnosticError({
2735
- code: diagnosticCode.devtoolsInvalid,
2736
- severity: "error",
2737
- message: "The `devtools` config must be an object.",
2738
- help: "Set `devtools` to an options object, or remove it to disable Kubb Studio.",
2739
- location: { kind: "config" }
2740
- });
2741
- if (!driver.adapter || !driver.#studio.source) throw new DiagnosticError({
2742
- code: diagnosticCode.adapterRequired,
2743
- severity: "error",
2744
- message: "An adapter is required to open Kubb Studio, but none is configured.",
2745
- help: "Set `adapter` in kubb.config.ts (for example `adapterOas()`).",
2746
- location: { kind: "config" }
2747
- });
2748
- driver.#studio.isOpen = true;
2749
- const studioUrl = driver.config.devtools?.studioUrl ?? "https://kubb.studio";
2750
- driver.#studio.inputNode ??= Promise.resolve(driver.adapter.parse(driver.#studio.source));
2751
- return openInStudio(await driver.#studio.inputNode, studioUrl, options);
2752
2785
  }
2753
2786
  };
2754
2787
  }
@@ -2757,8 +2790,8 @@ var KubbDriver = class KubbDriver {
2757
2790
  }
2758
2791
  requirePlugin(pluginName) {
2759
2792
  const plugin = this.plugins.get(pluginName);
2760
- if (!plugin) throw new DiagnosticError({
2761
- code: diagnosticCode.pluginNotFound,
2793
+ if (!plugin) throw new Diagnostics.Error({
2794
+ code: Diagnostics.code.pluginNotFound,
2762
2795
  severity: "error",
2763
2796
  message: `Plugin "${pluginName}" is required but not found. Make sure it is included in your Kubb config.`,
2764
2797
  help: `Add "${pluginName}" to the \`plugins\` array in kubb.config.ts, or remove the dependency on it.`,
@@ -2769,8 +2802,8 @@ var KubbDriver = class KubbDriver {
2769
2802
  };
2770
2803
  function inputToAdapterSource(config) {
2771
2804
  const input = config.input;
2772
- if (!input) throw new DiagnosticError({
2773
- code: diagnosticCode.inputRequired,
2805
+ if (!input) throw new Diagnostics.Error({
2806
+ code: Diagnostics.code.inputRequired,
2774
2807
  severity: "error",
2775
2808
  message: "An adapter is configured without an input.",
2776
2809
  help: "Provide `input.path` (a file or URL) or `input.data` (an inline spec) in your Kubb config.",
@@ -2790,6 +2823,56 @@ function inputToAdapterSource(config) {
2790
2823
  };
2791
2824
  }
2792
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
2793
2876
  Object.defineProperty(exports, "AsyncEventEmitter", {
2794
2877
  enumerable: true,
2795
2878
  get: function() {
@@ -2802,18 +2885,6 @@ Object.defineProperty(exports, "BuildError", {
2802
2885
  return BuildError;
2803
2886
  }
2804
2887
  });
2805
- Object.defineProperty(exports, "DEFAULT_STUDIO_URL", {
2806
- enumerable: true,
2807
- get: function() {
2808
- return DEFAULT_STUDIO_URL;
2809
- }
2810
- });
2811
- Object.defineProperty(exports, "DiagnosticError", {
2812
- enumerable: true,
2813
- get: function() {
2814
- return DiagnosticError;
2815
- }
2816
- });
2817
2888
  Object.defineProperty(exports, "Diagnostics", {
2818
2889
  enumerable: true,
2819
2890
  get: function() {
@@ -2838,10 +2909,10 @@ Object.defineProperty(exports, "KubbDriver", {
2838
2909
  return KubbDriver;
2839
2910
  }
2840
2911
  });
2841
- Object.defineProperty(exports, "URLPath", {
2912
+ Object.defineProperty(exports, "OTLP_ENDPOINT", {
2842
2913
  enumerable: true,
2843
2914
  get: function() {
2844
- return URLPath;
2915
+ return OTLP_ENDPOINT;
2845
2916
  }
2846
2917
  });
2847
2918
  Object.defineProperty(exports, "__name", {
@@ -2862,59 +2933,47 @@ Object.defineProperty(exports, "_usingCtx", {
2862
2933
  return _usingCtx;
2863
2934
  }
2864
2935
  });
2865
- Object.defineProperty(exports, "definePlugin", {
2866
- enumerable: true,
2867
- get: function() {
2868
- return definePlugin;
2869
- }
2870
- });
2871
- Object.defineProperty(exports, "defineResolver", {
2872
- enumerable: true,
2873
- get: function() {
2874
- return defineResolver;
2875
- }
2876
- });
2877
- Object.defineProperty(exports, "diagnosticCatalog", {
2936
+ Object.defineProperty(exports, "camelCase", {
2878
2937
  enumerable: true,
2879
2938
  get: function() {
2880
- return diagnosticCatalog;
2939
+ return camelCase;
2881
2940
  }
2882
2941
  });
2883
- Object.defineProperty(exports, "diagnosticCode", {
2942
+ Object.defineProperty(exports, "createStorage", {
2884
2943
  enumerable: true,
2885
2944
  get: function() {
2886
- return diagnosticCode;
2945
+ return createStorage;
2887
2946
  }
2888
2947
  });
2889
- Object.defineProperty(exports, "isPerformanceDiagnostic", {
2948
+ Object.defineProperty(exports, "definePlugin", {
2890
2949
  enumerable: true,
2891
2950
  get: function() {
2892
- return isPerformanceDiagnostic;
2951
+ return definePlugin;
2893
2952
  }
2894
2953
  });
2895
- Object.defineProperty(exports, "isProblemDiagnostic", {
2954
+ Object.defineProperty(exports, "defineResolver", {
2896
2955
  enumerable: true,
2897
2956
  get: function() {
2898
- return isProblemDiagnostic;
2957
+ return defineResolver;
2899
2958
  }
2900
2959
  });
2901
- Object.defineProperty(exports, "isUpdateDiagnostic", {
2960
+ Object.defineProperty(exports, "formatMs", {
2902
2961
  enumerable: true,
2903
2962
  get: function() {
2904
- return isUpdateDiagnostic;
2963
+ return formatMs;
2905
2964
  }
2906
2965
  });
2907
- Object.defineProperty(exports, "logLevel", {
2966
+ Object.defineProperty(exports, "getElapsedMs", {
2908
2967
  enumerable: true,
2909
2968
  get: function() {
2910
- return logLevel;
2969
+ return getElapsedMs;
2911
2970
  }
2912
2971
  });
2913
- Object.defineProperty(exports, "narrowDiagnostic", {
2972
+ Object.defineProperty(exports, "memoryStorage", {
2914
2973
  enumerable: true,
2915
2974
  get: function() {
2916
- return narrowDiagnostic;
2975
+ return memoryStorage;
2917
2976
  }
2918
2977
  });
2919
2978
 
2920
- //# sourceMappingURL=KubbDriver-BYBUfOZ8.cjs.map
2979
+ //# sourceMappingURL=memoryStorage-DHi1d0To.cjs.map