@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.
- package/dist/{diagnostics-B0ONXReg.d.ts → diagnostics-DhfW8YpT.d.ts} +309 -350
- package/dist/index.cjs +569 -172
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +164 -119
- package/dist/index.js +548 -147
- package/dist/index.js.map +1 -1
- package/dist/{KubbDriver-CckeYpMG.js → memoryStorage-CNQTs-YG.js} +240 -166
- package/dist/memoryStorage-CNQTs-YG.js.map +1 -0
- package/dist/{KubbDriver-CXoKVRxI.cjs → memoryStorage-DHi1d0To.cjs} +255 -205
- package/dist/memoryStorage-DHi1d0To.cjs.map +1 -0
- package/dist/mocks.cjs +58 -5
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.ts +30 -3
- package/dist/mocks.js +57 -6
- package/dist/mocks.js.map +1 -1
- package/package.json +4 -4
- package/src/KubbDriver.ts +24 -74
- package/src/Telemetry.ts +278 -0
- package/src/constants.ts +14 -21
- package/src/createKubb.ts +22 -50
- package/src/createReporter.ts +75 -12
- package/src/defineGenerator.ts +2 -6
- package/src/defineLogger.ts +13 -1
- package/src/defineResolver.ts +3 -4
- package/src/diagnostics.ts +130 -61
- package/src/index.ts +8 -16
- package/src/mocks.ts +80 -4
- package/src/reporters/cliReporter.ts +90 -0
- package/src/reporters/fileReporter.ts +103 -0
- package/src/reporters/jsonReporter.ts +20 -0
- package/src/reporters/report.ts +85 -0
- package/src/types.ts +0 -1
- package/dist/KubbDriver-CXoKVRxI.cjs.map +0 -1
- package/dist/KubbDriver-CckeYpMG.js.map +0 -1
- package/src/devtools.ts +0 -53
|
@@ -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
|
-
*
|
|
668
|
+
* OpenTelemetry ingestion endpoint for anonymous usage telemetry.
|
|
652
669
|
*/
|
|
653
|
-
const
|
|
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 =
|
|
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 =
|
|
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
|
|
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 (
|
|
798
|
+
* if (isProblem(diagnostic)) {
|
|
798
799
|
* console.log(diagnostic.location)
|
|
799
800
|
* }
|
|
800
801
|
* ```
|
|
801
802
|
*/
|
|
802
|
-
const
|
|
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(
|
|
809
|
+
* const timings = diagnostics.filter(isPerformance)
|
|
809
810
|
* ```
|
|
810
811
|
*/
|
|
811
|
-
const
|
|
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 (
|
|
818
|
+
* if (isUpdate(diagnostic)) {
|
|
818
819
|
* console.log(diagnostic.latestVersion)
|
|
819
820
|
* }
|
|
820
821
|
* ```
|
|
821
822
|
*/
|
|
822
|
-
const
|
|
823
|
+
const isUpdate = isKind("update");
|
|
823
824
|
/**
|
|
824
|
-
*
|
|
825
|
-
*
|
|
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
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
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
|
|
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
|
|
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 (
|
|
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 (!
|
|
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 (!
|
|
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 =
|
|
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
|
|
1353
|
-
code:
|
|
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
|
-
*
|
|
2024
|
-
*
|
|
2025
|
-
|
|
2026
|
-
|
|
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.#
|
|
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`
|
|
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.#
|
|
2169
|
+
if (this.inputNode || !this.adapter || !this.#adapterSource) return;
|
|
2112
2170
|
const adapter = this.adapter;
|
|
2113
|
-
const source = this.#
|
|
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.#
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
2770
|
-
code:
|
|
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
|
|
2782
|
-
code:
|
|
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, "
|
|
2912
|
+
Object.defineProperty(exports, "OTLP_ENDPOINT", {
|
|
2851
2913
|
enumerable: true,
|
|
2852
2914
|
get: function() {
|
|
2853
|
-
return
|
|
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, "
|
|
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
|
|
2939
|
+
return camelCase;
|
|
2890
2940
|
}
|
|
2891
2941
|
});
|
|
2892
|
-
Object.defineProperty(exports, "
|
|
2942
|
+
Object.defineProperty(exports, "createStorage", {
|
|
2893
2943
|
enumerable: true,
|
|
2894
2944
|
get: function() {
|
|
2895
|
-
return
|
|
2945
|
+
return createStorage;
|
|
2896
2946
|
}
|
|
2897
2947
|
});
|
|
2898
|
-
Object.defineProperty(exports, "
|
|
2948
|
+
Object.defineProperty(exports, "definePlugin", {
|
|
2899
2949
|
enumerable: true,
|
|
2900
2950
|
get: function() {
|
|
2901
|
-
return
|
|
2951
|
+
return definePlugin;
|
|
2902
2952
|
}
|
|
2903
2953
|
});
|
|
2904
|
-
Object.defineProperty(exports, "
|
|
2954
|
+
Object.defineProperty(exports, "defineResolver", {
|
|
2905
2955
|
enumerable: true,
|
|
2906
2956
|
get: function() {
|
|
2907
|
-
return
|
|
2957
|
+
return defineResolver;
|
|
2908
2958
|
}
|
|
2909
2959
|
});
|
|
2910
|
-
Object.defineProperty(exports, "
|
|
2960
|
+
Object.defineProperty(exports, "formatMs", {
|
|
2911
2961
|
enumerable: true,
|
|
2912
2962
|
get: function() {
|
|
2913
|
-
return
|
|
2963
|
+
return formatMs;
|
|
2914
2964
|
}
|
|
2915
2965
|
});
|
|
2916
|
-
Object.defineProperty(exports, "
|
|
2966
|
+
Object.defineProperty(exports, "getElapsedMs", {
|
|
2917
2967
|
enumerable: true,
|
|
2918
2968
|
get: function() {
|
|
2919
|
-
return
|
|
2969
|
+
return getElapsedMs;
|
|
2920
2970
|
}
|
|
2921
2971
|
});
|
|
2922
|
-
Object.defineProperty(exports, "
|
|
2972
|
+
Object.defineProperty(exports, "memoryStorage", {
|
|
2923
2973
|
enumerable: true,
|
|
2924
2974
|
get: function() {
|
|
2925
|
-
return
|
|
2975
|
+
return memoryStorage;
|
|
2926
2976
|
}
|
|
2927
2977
|
});
|
|
2928
2978
|
|
|
2929
|
-
//# sourceMappingURL=
|
|
2979
|
+
//# sourceMappingURL=memoryStorage-DHi1d0To.cjs.map
|