@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.
- package/dist/{diagnostics-CYfKPtbU.d.ts → diagnostics-DhfW8YpT.d.ts} +289 -347
- package/dist/index.cjs +553 -174
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +164 -119
- package/dist/index.js +532 -149
- package/dist/index.js.map +1 -1
- package/dist/{KubbDriver-CyNF-NIb.js → memoryStorage-CNQTs-YG.js} +240 -157
- package/dist/memoryStorage-CNQTs-YG.js.map +1 -0
- package/dist/{KubbDriver-BYBUfOZ8.cjs → memoryStorage-DHi1d0To.cjs} +255 -196
- package/dist/memoryStorage-DHi1d0To.cjs.map +1 -0
- package/dist/mocks.cjs +36 -6
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.ts +30 -3
- package/dist/mocks.js +33 -5
- package/dist/mocks.js.map +1 -1
- package/package.json +4 -4
- package/src/KubbDriver.ts +21 -65
- package/src/Telemetry.ts +278 -0
- package/src/constants.ts +14 -21
- package/src/createKubb.ts +22 -50
- package/src/createReporter.ts +43 -13
- 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 +57 -2
- 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-BYBUfOZ8.cjs.map +0 -1
- package/dist/KubbDriver-CyNF-NIb.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();
|
|
@@ -2708,7 +2762,7 @@ var KubbDriver = class KubbDriver {
|
|
|
2708
2762
|
},
|
|
2709
2763
|
warn(message) {
|
|
2710
2764
|
report({
|
|
2711
|
-
code:
|
|
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:
|
|
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:
|
|
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
|
|
2761
|
-
code:
|
|
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
|
|
2773
|
-
code:
|
|
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, "
|
|
2912
|
+
Object.defineProperty(exports, "OTLP_ENDPOINT", {
|
|
2842
2913
|
enumerable: true,
|
|
2843
2914
|
get: function() {
|
|
2844
|
-
return
|
|
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, "
|
|
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
|
|
2939
|
+
return camelCase;
|
|
2881
2940
|
}
|
|
2882
2941
|
});
|
|
2883
|
-
Object.defineProperty(exports, "
|
|
2942
|
+
Object.defineProperty(exports, "createStorage", {
|
|
2884
2943
|
enumerable: true,
|
|
2885
2944
|
get: function() {
|
|
2886
|
-
return
|
|
2945
|
+
return createStorage;
|
|
2887
2946
|
}
|
|
2888
2947
|
});
|
|
2889
|
-
Object.defineProperty(exports, "
|
|
2948
|
+
Object.defineProperty(exports, "definePlugin", {
|
|
2890
2949
|
enumerable: true,
|
|
2891
2950
|
get: function() {
|
|
2892
|
-
return
|
|
2951
|
+
return definePlugin;
|
|
2893
2952
|
}
|
|
2894
2953
|
});
|
|
2895
|
-
Object.defineProperty(exports, "
|
|
2954
|
+
Object.defineProperty(exports, "defineResolver", {
|
|
2896
2955
|
enumerable: true,
|
|
2897
2956
|
get: function() {
|
|
2898
|
-
return
|
|
2957
|
+
return defineResolver;
|
|
2899
2958
|
}
|
|
2900
2959
|
});
|
|
2901
|
-
Object.defineProperty(exports, "
|
|
2960
|
+
Object.defineProperty(exports, "formatMs", {
|
|
2902
2961
|
enumerable: true,
|
|
2903
2962
|
get: function() {
|
|
2904
|
-
return
|
|
2963
|
+
return formatMs;
|
|
2905
2964
|
}
|
|
2906
2965
|
});
|
|
2907
|
-
Object.defineProperty(exports, "
|
|
2966
|
+
Object.defineProperty(exports, "getElapsedMs", {
|
|
2908
2967
|
enumerable: true,
|
|
2909
2968
|
get: function() {
|
|
2910
|
-
return
|
|
2969
|
+
return getElapsedMs;
|
|
2911
2970
|
}
|
|
2912
2971
|
});
|
|
2913
|
-
Object.defineProperty(exports, "
|
|
2972
|
+
Object.defineProperty(exports, "memoryStorage", {
|
|
2914
2973
|
enumerable: true,
|
|
2915
2974
|
get: function() {
|
|
2916
|
-
return
|
|
2975
|
+
return memoryStorage;
|
|
2917
2976
|
}
|
|
2918
2977
|
});
|
|
2919
2978
|
|
|
2920
|
-
//# sourceMappingURL=
|
|
2979
|
+
//# sourceMappingURL=memoryStorage-DHi1d0To.cjs.map
|