@kubb/cli 5.11.4 → 5.11.6
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/{Telemetry-Be1nltUh.cjs → Telemetry-Be3hIy6_.cjs} +2 -42
- package/dist/Telemetry-Be3hIy6_.cjs.map +1 -0
- package/dist/{Telemetry-CwaVQsvD.js → Telemetry-CfJAUDnh.js} +3 -31
- package/dist/Telemetry-CfJAUDnh.js.map +1 -0
- package/dist/{background-CQPyCSn0.js → background-BBpH2jmk.js} +7 -5
- package/dist/background-BBpH2jmk.js.map +1 -0
- package/dist/{background-mKdZ5HRx.cjs → background-BW-e9FCX.cjs} +5 -4
- package/dist/background-BW-e9FCX.cjs.map +1 -0
- package/dist/{background-aTbwrgui.js → background-DS2zOde-.js} +1 -1
- package/dist/config-Bh00Hwpw.js +132 -0
- package/dist/config-Bh00Hwpw.js.map +1 -0
- package/dist/config-D63Gum4F.cjs +169 -0
- package/dist/config-D63Gum4F.cjs.map +1 -0
- package/dist/config-iVdOcpro.js +1 -0
- package/dist/credentials-CZK6zPLv.js.map +1 -1
- package/dist/credentials-DDaKqtJn.cjs.map +1 -1
- package/dist/errors-Cl69p_vI.cjs +43 -0
- package/dist/errors-Cl69p_vI.cjs.map +1 -0
- package/dist/errors-DmC83ALX.js +32 -0
- package/dist/errors-DmC83ALX.js.map +1 -0
- package/dist/index.cjs +872 -307
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +863 -298
- package/dist/index.js.map +1 -1
- package/dist/registry-BlKLO4ft.cjs +272 -0
- package/dist/registry-BlKLO4ft.cjs.map +1 -0
- package/dist/registry-CgQYxUju.js +200 -0
- package/dist/registry-CgQYxUju.js.map +1 -0
- package/dist/reporters-Dl8lrJZG.js +817 -0
- package/dist/reporters-Dl8lrJZG.js.map +1 -0
- package/dist/reporters-TkCgd4dS.cjs +829 -0
- package/dist/reporters-TkCgd4dS.cjs.map +1 -0
- package/dist/{run-YHth5Afz.js → run-BJn0RSW2.js} +170 -76
- package/dist/run-BJn0RSW2.js.map +1 -0
- package/dist/{run-BWRmQxtE.cjs → run-BszyZwY3.cjs} +176 -82
- package/dist/run-BszyZwY3.cjs.map +1 -0
- package/dist/{run-Bczs5vbI.cjs → run-BtVKUjdK.cjs} +4 -3
- package/dist/{run-Bczs5vbI.cjs.map → run-BtVKUjdK.cjs.map} +1 -1
- package/dist/run-CFf0yxyY.cjs +94 -0
- package/dist/run-CFf0yxyY.cjs.map +1 -0
- package/dist/run-D_dD7xHp.js +93 -0
- package/dist/run-D_dD7xHp.js.map +1 -0
- package/dist/run-DsJJCzQD.js +1 -0
- package/dist/{run-B6VxJ_VM.js → run-KuzAqsjg.js} +3 -2
- package/dist/{run-B6VxJ_VM.js.map → run-KuzAqsjg.js.map} +1 -1
- package/dist/run-TrjCNL8e.cjs +227 -0
- package/dist/run-TrjCNL8e.cjs.map +1 -0
- package/dist/run-wkN1irUo.js +224 -0
- package/dist/run-wkN1irUo.js.map +1 -0
- package/dist/{snapshot-Cilp10vE.js → snapshot-CdGwHH15.js} +49 -62
- package/dist/snapshot-CdGwHH15.js.map +1 -0
- package/dist/{snapshot-D_rXnnMH.cjs → snapshot-u4L8mh4Y.cjs} +51 -64
- package/dist/snapshot-u4L8mh4Y.cjs.map +1 -0
- package/dist/status-DHPeR3bq.js +77 -0
- package/dist/status-DHPeR3bq.js.map +1 -0
- package/dist/status-dpSvxxtN.cjs +78 -0
- package/dist/status-dpSvxxtN.cjs.map +1 -0
- package/dist/studioWorker.js +2 -2
- package/dist/summary-6-rotl2L.cjs +46 -0
- package/dist/summary-6-rotl2L.cjs.map +1 -0
- package/dist/summary-DkSLti6f.js +41 -0
- package/dist/summary-DkSLti6f.js.map +1 -0
- package/dist/text-CMP4M19Z.js +239 -0
- package/dist/text-CMP4M19Z.js.map +1 -0
- package/dist/text-CknhKMvM.cjs +341 -0
- package/dist/text-CknhKMvM.cjs.map +1 -0
- package/dist/utils-CnjEJIdZ.js +612 -0
- package/dist/utils-CnjEJIdZ.js.map +1 -0
- package/dist/utils-DpKrXR2t.cjs +727 -0
- package/dist/utils-DpKrXR2t.cjs.map +1 -0
- package/package.json +7 -7
- package/dist/Telemetry-Be1nltUh.cjs.map +0 -1
- package/dist/Telemetry-CwaVQsvD.js.map +0 -1
- package/dist/background-CQPyCSn0.js.map +0 -1
- package/dist/background-mKdZ5HRx.cjs.map +0 -1
- package/dist/config-B56ZuVhi.js +0 -95
- package/dist/config-B56ZuVhi.js.map +0 -1
- package/dist/config-Cs4N79Fm.cjs +0 -113
- package/dist/config-Cs4N79Fm.cjs.map +0 -1
- package/dist/output-HgzJqkSF.cjs +0 -1076
- package/dist/output-HgzJqkSF.cjs.map +0 -1
- package/dist/output-PhkPtNP7.js +0 -937
- package/dist/output-PhkPtNP7.js.map +0 -1
- package/dist/registry-DYUhC7rH.js +0 -115
- package/dist/registry-DYUhC7rH.js.map +0 -1
- package/dist/registry-tk-v78fd.cjs +0 -157
- package/dist/registry-tk-v78fd.cjs.map +0 -1
- package/dist/run-AfjIBtiL.js +0 -39
- package/dist/run-AfjIBtiL.js.map +0 -1
- package/dist/run-BWRmQxtE.cjs.map +0 -1
- package/dist/run-B_Gr9TJ4.cjs +0 -345
- package/dist/run-B_Gr9TJ4.cjs.map +0 -1
- package/dist/run-CwrI0wRy.js +0 -1
- package/dist/run-DDoJGjWT.cjs +0 -40
- package/dist/run-DDoJGjWT.cjs.map +0 -1
- package/dist/run-SYKj8-Q5.js +0 -343
- package/dist/run-SYKj8-Q5.js.map +0 -1
- package/dist/run-YHth5Afz.js.map +0 -1
- package/dist/snapshot-Cilp10vE.js.map +0 -1
- package/dist/snapshot-D_rXnnMH.cjs.map +0 -1
|
@@ -0,0 +1,817 @@
|
|
|
1
|
+
import "./rolldown-runtime-CRm0XQPb.js";
|
|
2
|
+
import { a as getElapsedMs, i as formatMs } from "./Telemetry-CfJAUDnh.js";
|
|
3
|
+
import { _ as isPathInside, f as formatBar, o as readOutputFiles, p as formatMsWithColor, r as diffOutput, v as read } from "./utils-CnjEJIdZ.js";
|
|
4
|
+
import { n as toPermissionFlag, p as writer, t as pluralize } from "./text-CMP4M19Z.js";
|
|
5
|
+
import { styleText } from "node:util";
|
|
6
|
+
import process from "node:process";
|
|
7
|
+
import { readFile } from "node:fs/promises";
|
|
8
|
+
import { relative, resolve } from "node:path";
|
|
9
|
+
import { Diagnostics, cacheStorage, createCliReporter, createOutputManifest, getInputKind, logLevel } from "@kubb/core";
|
|
10
|
+
//#region src/loggers/features/context.ts
|
|
11
|
+
function createLoggerContext({ hooks, writer, logLevel: logLevel$5 }) {
|
|
12
|
+
const text = (message) => logLevel$5 >= logLevel.verbose ? `${styleText("dim", `[${clock()}]`)} ${message}` : message;
|
|
13
|
+
const ctx = {
|
|
14
|
+
hooks,
|
|
15
|
+
writer,
|
|
16
|
+
logLevel: logLevel$5,
|
|
17
|
+
silent: logLevel$5 <= logLevel.silent,
|
|
18
|
+
human: writer.audience === "human",
|
|
19
|
+
session: false,
|
|
20
|
+
groupOpen: false,
|
|
21
|
+
text,
|
|
22
|
+
line: (symbol, message, info) => text([
|
|
23
|
+
symbol,
|
|
24
|
+
message,
|
|
25
|
+
info && styleText("dim", info)
|
|
26
|
+
].filter(Boolean).join(" ")),
|
|
27
|
+
onRun(name, fn) {
|
|
28
|
+
return hooks.hook(name, (...args) => ctx.session ? void 0 : fn(...args));
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
return ctx;
|
|
32
|
+
}
|
|
33
|
+
/** `HH:MM:SS` in 24-hour time. */
|
|
34
|
+
function clock(date = /* @__PURE__ */ new Date()) {
|
|
35
|
+
return date.toLocaleTimeString("en-US", {
|
|
36
|
+
hour12: false,
|
|
37
|
+
hour: "2-digit",
|
|
38
|
+
minute: "2-digit",
|
|
39
|
+
second: "2-digit"
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** Display path for a config's input: the string form, or its `path` field when the input is an object. */
|
|
43
|
+
function getInputPath(config) {
|
|
44
|
+
const { input } = config;
|
|
45
|
+
if (typeof input === "string") return input;
|
|
46
|
+
return typeof input?.path === "string" ? input.path : void 0;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/loggers/features/generation.ts
|
|
50
|
+
/**
|
|
51
|
+
* One config's run: the group it opens, the state every feature resets at its start, and the
|
|
52
|
+
* closing line, which the lifecycle end draws too for a run that threw before its summary.
|
|
53
|
+
*/
|
|
54
|
+
function createGeneration(ctx, { spinner, progress, walk, phases, problems }) {
|
|
55
|
+
const { writer, silent, human, text, hooks, onRun } = ctx;
|
|
56
|
+
function reset() {
|
|
57
|
+
spinner.reset();
|
|
58
|
+
progress.reset();
|
|
59
|
+
walk.reset();
|
|
60
|
+
phases.reset();
|
|
61
|
+
problems.reset();
|
|
62
|
+
}
|
|
63
|
+
function closeGroup(status) {
|
|
64
|
+
if (!ctx.groupOpen) return;
|
|
65
|
+
ctx.groupOpen = false;
|
|
66
|
+
spinner.stop();
|
|
67
|
+
progress.stop();
|
|
68
|
+
writer.groupEnd(status === "failed" ? styleText("red", problems.failedTitle()) : styleText("green", "✓ Generation succeeded"));
|
|
69
|
+
}
|
|
70
|
+
hooks.hook("kubb:lifecycle:start", () => {
|
|
71
|
+
reset();
|
|
72
|
+
});
|
|
73
|
+
onRun("kubb:generation:start", ({ config }) => {
|
|
74
|
+
closeGroup("failed");
|
|
75
|
+
reset();
|
|
76
|
+
walk.state.totalPlugins = config.plugins?.length ?? 0;
|
|
77
|
+
progress.state.inMemory = config.storage?.name === "memory";
|
|
78
|
+
problems.setSpec(config);
|
|
79
|
+
if (silent) return;
|
|
80
|
+
const input = getInputPath(config);
|
|
81
|
+
writer.group(text([styleText("bold", config.name ?? "kubb"), input ? styleText("dim", input) : void 0].filter(Boolean).join(" ")));
|
|
82
|
+
ctx.groupOpen = true;
|
|
83
|
+
spinner.start("Parsing spec");
|
|
84
|
+
});
|
|
85
|
+
onRun("kubb:generation:end", async ({ diagnostics = [] }) => {
|
|
86
|
+
spinner.stop();
|
|
87
|
+
progress.stop();
|
|
88
|
+
problems.state.diagnostics = diagnostics;
|
|
89
|
+
await problems.flush();
|
|
90
|
+
});
|
|
91
|
+
hooks.hook("kubb:lifecycle:end", async () => {
|
|
92
|
+
await problems.flush();
|
|
93
|
+
closeGroup("failed");
|
|
94
|
+
reset();
|
|
95
|
+
});
|
|
96
|
+
const renderSummary = (lines, { status }) => {
|
|
97
|
+
if (silent || !ctx.groupOpen) return;
|
|
98
|
+
spinner.stop();
|
|
99
|
+
progress.stop();
|
|
100
|
+
if (human) closeGroup(status);
|
|
101
|
+
ctx.groupOpen = false;
|
|
102
|
+
writer.diagnostic([...lines]);
|
|
103
|
+
};
|
|
104
|
+
return { renderSummary };
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/loggers/features/phases.ts
|
|
108
|
+
/**
|
|
109
|
+
* The three output phases, in the order the generate runner runs them.
|
|
110
|
+
*/
|
|
111
|
+
const PHASES = {
|
|
112
|
+
format: {
|
|
113
|
+
running: "Formatting",
|
|
114
|
+
success: "Formatted",
|
|
115
|
+
failure: "Formatting failed"
|
|
116
|
+
},
|
|
117
|
+
lint: {
|
|
118
|
+
running: "Linting",
|
|
119
|
+
success: "Linted",
|
|
120
|
+
failure: "Linting failed"
|
|
121
|
+
},
|
|
122
|
+
hooks: {
|
|
123
|
+
running: "Running post-generate hooks",
|
|
124
|
+
success: "Post-generate hooks completed",
|
|
125
|
+
failure: "Post-generate hooks failed",
|
|
126
|
+
showHookResults: true
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
/** A hook's display name: its `name`, or the command line it runs. */
|
|
130
|
+
function formatHookLabel({ command, name, args }) {
|
|
131
|
+
return name ?? (args?.length ? `${command} ${args.join(" ")}` : command);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Drops the blank lines a subprocess leaves at either end of its output, so its block does not open
|
|
135
|
+
* or close on an empty row.
|
|
136
|
+
*/
|
|
137
|
+
function trimBlankEdges(lines) {
|
|
138
|
+
const start = lines.findIndex((line) => line.trim());
|
|
139
|
+
if (start === -1) return [];
|
|
140
|
+
return lines.slice(start, lines.findLastIndex((line) => line.trim()) + 1);
|
|
141
|
+
}
|
|
142
|
+
/** The format, lint and post-generate phases, and the hooks and messages they buffer while their step owns the line. */
|
|
143
|
+
function createPhases({ writer, silent, logLevel: logLevel$4, text, line, onRun }, spinner) {
|
|
144
|
+
const state = {
|
|
145
|
+
phase: null,
|
|
146
|
+
hooks: /* @__PURE__ */ new Map()
|
|
147
|
+
};
|
|
148
|
+
function startPhase(options) {
|
|
149
|
+
state.phase = {
|
|
150
|
+
...options,
|
|
151
|
+
failed: false,
|
|
152
|
+
hrStart: process.hrtime(),
|
|
153
|
+
lines: [],
|
|
154
|
+
output: []
|
|
155
|
+
};
|
|
156
|
+
spinner.start(options.running);
|
|
157
|
+
}
|
|
158
|
+
function endPhase() {
|
|
159
|
+
const phase = state.phase;
|
|
160
|
+
state.phase = null;
|
|
161
|
+
if (!phase || silent) return;
|
|
162
|
+
const duration = formatMsWithColor(getElapsedMs(phase.hrStart));
|
|
163
|
+
spinner.stop(phase.failed ? `${phase.failure} after ${duration}` : `${phase.success} in ${duration}`, phase.failed ? "failed" : "success");
|
|
164
|
+
if (phase.lines.length) writer.block(phase.lines);
|
|
165
|
+
writeOutput(phase.output);
|
|
166
|
+
}
|
|
167
|
+
function writeOutput(lines) {
|
|
168
|
+
const output = trimBlankEdges(lines);
|
|
169
|
+
if (output.length) writer.raw(output);
|
|
170
|
+
}
|
|
171
|
+
onRun("kubb:format:start", () => startPhase(PHASES.format));
|
|
172
|
+
onRun("kubb:format:end", endPhase);
|
|
173
|
+
onRun("kubb:lint:start", () => startPhase(PHASES.lint));
|
|
174
|
+
onRun("kubb:lint:end", endPhase);
|
|
175
|
+
onRun("kubb:hooks:start", () => startPhase(PHASES.hooks));
|
|
176
|
+
onRun("kubb:hooks:end", endPhase);
|
|
177
|
+
onRun("kubb:hook:end", (ctx) => {
|
|
178
|
+
const { id, command, name, args, success, error } = ctx;
|
|
179
|
+
if (!id) return;
|
|
180
|
+
if (!success && state.phase) state.phase.failed = true;
|
|
181
|
+
if (silent) {
|
|
182
|
+
if (!ctx.success) {
|
|
183
|
+
if (ctx.stdout) console.log(ctx.stdout);
|
|
184
|
+
if (ctx.stderr) console.error(ctx.stderr);
|
|
185
|
+
}
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const active = state.hooks.get(id);
|
|
189
|
+
if (!active) return;
|
|
190
|
+
state.hooks.delete(id);
|
|
191
|
+
const label = styleText("dim", formatHookLabel({
|
|
192
|
+
command,
|
|
193
|
+
name,
|
|
194
|
+
args
|
|
195
|
+
}));
|
|
196
|
+
const reason = error?.message ? ` (${error.message})` : "";
|
|
197
|
+
const result = success ? `${styleText("green", "✓")} ${label} in ${formatMsWithColor(getElapsedMs(active.hrStart))}` : `${styleText("red", "✗")} ${label} failed${reason}`;
|
|
198
|
+
const phase = state.phase;
|
|
199
|
+
if (phase) {
|
|
200
|
+
if (phase.showHookResults || !success) phase.lines.push(result);
|
|
201
|
+
phase.output.push(...active.lines);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
spinner.stop();
|
|
205
|
+
writer.step(text(result));
|
|
206
|
+
writeOutput(active.lines);
|
|
207
|
+
});
|
|
208
|
+
if (!silent) {
|
|
209
|
+
onRun("kubb:info", ({ message, info }) => {
|
|
210
|
+
const formatted = line(styleText("blue", "ℹ"), message, info);
|
|
211
|
+
if (state.phase) {
|
|
212
|
+
state.phase.lines.push(formatted);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (spinner.message(formatted)) return;
|
|
216
|
+
writer.info(formatted);
|
|
217
|
+
});
|
|
218
|
+
onRun("kubb:success", ({ message, info }) => {
|
|
219
|
+
const formatted = line(styleText("green", "✓"), message, logLevel$4 >= logLevel.info ? info : void 0);
|
|
220
|
+
if (spinner.message(formatted)) return;
|
|
221
|
+
writer.success(formatted);
|
|
222
|
+
});
|
|
223
|
+
onRun("kubb:hook:start", ({ id, command, name, args }) => {
|
|
224
|
+
if (!id) return;
|
|
225
|
+
state.hooks.set(id, {
|
|
226
|
+
hrStart: process.hrtime(),
|
|
227
|
+
lines: []
|
|
228
|
+
});
|
|
229
|
+
spinner.message(text(`Running ${styleText("dim", formatHookLabel({
|
|
230
|
+
command,
|
|
231
|
+
name,
|
|
232
|
+
args
|
|
233
|
+
}))}`));
|
|
234
|
+
});
|
|
235
|
+
onRun("kubb:hook:line", ({ id, line }) => {
|
|
236
|
+
const active = state.hooks.get(id);
|
|
237
|
+
if (!active) return;
|
|
238
|
+
if (state.phase) {
|
|
239
|
+
active.lines.push(line);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
writer.raw([line]);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
/** The phase whose step owns the line, so a failure or an info line can wait for it. */
|
|
247
|
+
get phase() {
|
|
248
|
+
return state.phase;
|
|
249
|
+
},
|
|
250
|
+
reset() {
|
|
251
|
+
state.phase = null;
|
|
252
|
+
state.hooks = /* @__PURE__ */ new Map();
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
//#endregion
|
|
257
|
+
//#region src/loggers/specFrame.ts
|
|
258
|
+
/**
|
|
259
|
+
* Where `location` sits in `source` according to its adapter, with a code frame. `undefined` when the adapter cannot place it.
|
|
260
|
+
*/
|
|
261
|
+
function locateInSpec({ adapter, source, location }) {
|
|
262
|
+
const lines = source.split(/\r?\n/);
|
|
263
|
+
try {
|
|
264
|
+
const range = adapter.locate?.(source, location);
|
|
265
|
+
if (!range) return void 0;
|
|
266
|
+
const before = source.slice(0, range.start).split("\n");
|
|
267
|
+
const line = before.length;
|
|
268
|
+
const column = before.at(-1).length + 1;
|
|
269
|
+
const text = lines[line - 1] ?? "";
|
|
270
|
+
const width = String(line).length;
|
|
271
|
+
const gutter = (number) => styleText("dim", `${number === void 0 ? "".padStart(width) : String(number).padStart(width)} │`);
|
|
272
|
+
const carets = "^".repeat(Math.max(1, Math.min(range.end - range.start, text.length - column + 1)));
|
|
273
|
+
return {
|
|
274
|
+
line,
|
|
275
|
+
column,
|
|
276
|
+
frame: [
|
|
277
|
+
...line > 1 ? [`${gutter(line - 1)} ${lines[line - 2]}`] : [],
|
|
278
|
+
`${gutter(line)} ${text}`,
|
|
279
|
+
`${gutter()} ${" ".repeat(column - 1)}${styleText("red", carets)}`
|
|
280
|
+
]
|
|
281
|
+
};
|
|
282
|
+
} catch {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
//#endregion
|
|
287
|
+
//#region src/loggers/features/problems.ts
|
|
288
|
+
/** Warnings, errors and diagnostics: printed as they come, or held back and grouped by plugin once a human's build ends. */
|
|
289
|
+
function createProblems(ctx, spinner, progress, phases) {
|
|
290
|
+
const { writer, silent, human, logLevel: logLevel$3, text, line, hooks } = ctx;
|
|
291
|
+
const { audience } = writer;
|
|
292
|
+
const formatOptions = {
|
|
293
|
+
audience,
|
|
294
|
+
verbose: logLevel$3 >= logLevel.verbose,
|
|
295
|
+
width: Math.min(process.stdout.columns || 80, 100) - (audience === "human" ? 4 : 2)
|
|
296
|
+
};
|
|
297
|
+
const state = {
|
|
298
|
+
/** Problems held back so the human view can print them grouped by plugin once the build ends. */
|
|
299
|
+
problems: [],
|
|
300
|
+
/** The finished config's diagnostics, for the closing verdict. */
|
|
301
|
+
diagnostics: [],
|
|
302
|
+
/** A local-file input, which a located diagnostic points into; `load` parses it once, on the first such diagnostic. */
|
|
303
|
+
spec: void 0
|
|
304
|
+
};
|
|
305
|
+
/** Format options for one problem, with its line and column in a local spec when its pointer resolves there. */
|
|
306
|
+
async function optionsFor(problem) {
|
|
307
|
+
const { location } = problem;
|
|
308
|
+
const { spec } = state;
|
|
309
|
+
if (!location || !spec) return formatOptions;
|
|
310
|
+
const source = await spec.source;
|
|
311
|
+
const position = source && locateInSpec({
|
|
312
|
+
adapter: spec.adapter,
|
|
313
|
+
source,
|
|
314
|
+
location
|
|
315
|
+
});
|
|
316
|
+
if (!position) return formatOptions;
|
|
317
|
+
return {
|
|
318
|
+
...formatOptions,
|
|
319
|
+
position: {
|
|
320
|
+
file: relative(process.cwd(), spec.path),
|
|
321
|
+
...position
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Prints problems grouped under their plugin's name, each with the code aligned at the right.
|
|
327
|
+
*/
|
|
328
|
+
async function writeProblems(problems) {
|
|
329
|
+
if (!problems.length) return;
|
|
330
|
+
const formatted = await Promise.all(problems.map(async (problem) => Diagnostics.format(problem, await optionsFor(problem))));
|
|
331
|
+
if (!human) {
|
|
332
|
+
for (const lines of formatted) writer.diagnostic(lines);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const lines = [...Map.groupBy(problems.map((problem, index) => ({
|
|
336
|
+
plugin: problem.plugin ?? "",
|
|
337
|
+
lines: formatted[index]
|
|
338
|
+
})), ({ plugin }) => plugin)].flatMap(([plugin, group]) => [...plugin ? [` ${styleText("bold", plugin)}`, ""] : [], ...group.flatMap((entry) => [...entry.lines.map((entryLine) => ` ${entryLine}`), ""])]);
|
|
339
|
+
writer.diagnostic(lines.slice(0, -1));
|
|
340
|
+
}
|
|
341
|
+
hooks.hook("kubb:warn", ({ message, info }) => {
|
|
342
|
+
if (logLevel$3 < logLevel.warn) return;
|
|
343
|
+
writer.warn(line(styleText("yellow", "⚠"), message, logLevel$3 >= logLevel.info ? info : void 0));
|
|
344
|
+
});
|
|
345
|
+
hooks.hook("kubb:error", ({ error }) => {
|
|
346
|
+
const phase = phases.phase;
|
|
347
|
+
if (phase) phase.failed = true;
|
|
348
|
+
const message = error.name === "Error" || Diagnostics.isError(error) ? error.message : `${error.name}: ${error.message}`;
|
|
349
|
+
const help = Diagnostics.isError(error) ? error.diagnostic.help : void 0;
|
|
350
|
+
const [headline = "", ...details] = Diagnostics.format({
|
|
351
|
+
code: Diagnostics.code.unknown,
|
|
352
|
+
severity: "error",
|
|
353
|
+
message,
|
|
354
|
+
help,
|
|
355
|
+
cause: error
|
|
356
|
+
}, formatOptions);
|
|
357
|
+
if (!human) {
|
|
358
|
+
spinner.stop();
|
|
359
|
+
progress.stop();
|
|
360
|
+
writer.diagnostic([headline, ...details]);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (spinner.active) spinner.stop(message, "failed");
|
|
364
|
+
else writer.error(text(message));
|
|
365
|
+
if (details.length) writer.block(details.map(text));
|
|
366
|
+
});
|
|
367
|
+
hooks.hook("kubb:diagnostic", async ({ diagnostic }) => {
|
|
368
|
+
if (silent && diagnostic.severity !== "error") return;
|
|
369
|
+
if (ctx.session && !Diagnostics.isUpdate(diagnostic)) return;
|
|
370
|
+
spinner.stop();
|
|
371
|
+
progress.stop();
|
|
372
|
+
if (Diagnostics.isUpdate(diagnostic)) {
|
|
373
|
+
writer.update([`\`v${diagnostic.currentVersion}\` → \`v${diagnostic.latestVersion}\``, "Run `npm install -g @kubb/cli` to update"], "Update available for `Kubb`");
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (human && ctx.groupOpen) {
|
|
377
|
+
state.problems.push(diagnostic);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
await writeProblems([diagnostic]);
|
|
381
|
+
});
|
|
382
|
+
return {
|
|
383
|
+
state,
|
|
384
|
+
/** Points located diagnostics into the config's input when it is a local file. */
|
|
385
|
+
setSpec(config) {
|
|
386
|
+
const input = getInputPath(config);
|
|
387
|
+
if (input && config.adapter?.locate && getInputKind(input) === "file") {
|
|
388
|
+
const path = resolve(config.root, input);
|
|
389
|
+
let source;
|
|
390
|
+
state.spec = {
|
|
391
|
+
path,
|
|
392
|
+
adapter: config.adapter,
|
|
393
|
+
get source() {
|
|
394
|
+
return source ??= read(path).catch(() => void 0);
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
/** Prints the problems held back so far. */
|
|
400
|
+
flush() {
|
|
401
|
+
return writeProblems(state.problems.splice(0));
|
|
402
|
+
},
|
|
403
|
+
/** `✖ Failed 1 error · 1 warning in plugin-ts` once the build ended, or `✗ Generation failed` for a run that stopped early. */
|
|
404
|
+
failedTitle() {
|
|
405
|
+
const { errors, warnings } = Diagnostics.count(state.diagnostics);
|
|
406
|
+
const counts = [errors && pluralize(errors, "error"), warnings && pluralize(warnings, "warning")].filter(Boolean).join(" · ");
|
|
407
|
+
if (!human || !counts) return "✗ Generation failed";
|
|
408
|
+
const plugins = Diagnostics.failedPlugins(state.diagnostics);
|
|
409
|
+
return `✖ Failed ${counts}${plugins.length ? ` in ${plugins.join(", ")}` : ""}`;
|
|
410
|
+
},
|
|
411
|
+
reset() {
|
|
412
|
+
Object.assign(state, {
|
|
413
|
+
problems: [],
|
|
414
|
+
diagnostics: [],
|
|
415
|
+
spec: void 0
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
//#endregion
|
|
421
|
+
//#region src/loggers/features/progress.ts
|
|
422
|
+
/** The progress bar over the file writes, and the counts the summary line shows. */
|
|
423
|
+
function createProgress({ writer, silent, text, onRun }, spinner) {
|
|
424
|
+
const state = {
|
|
425
|
+
progress: null,
|
|
426
|
+
totalFiles: 0,
|
|
427
|
+
processedFiles: 0,
|
|
428
|
+
/** Whether this run keeps its files in memory, as a `kubb studio` run without `--allow-write` does. */
|
|
429
|
+
inMemory: false
|
|
430
|
+
};
|
|
431
|
+
function stop(message) {
|
|
432
|
+
const progress = state.progress;
|
|
433
|
+
if (!progress) return;
|
|
434
|
+
state.progress = null;
|
|
435
|
+
progress.stop(message === void 0 ? "" : text(message));
|
|
436
|
+
}
|
|
437
|
+
if (!silent) {
|
|
438
|
+
onRun("kubb:files:processing:start", ({ files }) => {
|
|
439
|
+
spinner.stop();
|
|
440
|
+
state.totalFiles = files.length;
|
|
441
|
+
state.processedFiles = 0;
|
|
442
|
+
state.progress = writer.progress(files.length);
|
|
443
|
+
state.progress.start(text(`${state.inMemory ? "Generating" : "Writing"} ${pluralize(files.length, "file")}`));
|
|
444
|
+
});
|
|
445
|
+
onRun("kubb:files:processing:update", ({ files }) => {
|
|
446
|
+
for (const { file, config } of files) {
|
|
447
|
+
state.processedFiles++;
|
|
448
|
+
state.progress?.advance(`${state.inMemory ? "Generating" : "Writing"} ${relative(config.root, file.path)}`);
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
onRun("kubb:files:processing:end", ({ files, unchanged }) => {
|
|
452
|
+
const skipped = unchanged.length ? styleText("dim", ` · ${unchanged.length} unchanged`) : "";
|
|
453
|
+
stop(state.inMemory ? `Generated ${pluralize(state.processedFiles, "file")} in memory` : `Wrote ${pluralize(files.length - unchanged.length, "file")}${skipped}`);
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
return {
|
|
457
|
+
state,
|
|
458
|
+
stop,
|
|
459
|
+
reset() {
|
|
460
|
+
stop();
|
|
461
|
+
Object.assign(state, {
|
|
462
|
+
totalFiles: 0,
|
|
463
|
+
processedFiles: 0,
|
|
464
|
+
inMemory: false
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
//#endregion
|
|
470
|
+
//#region src/loggers/features/session.ts
|
|
471
|
+
/** One line of a Studio session's job log: the time, the command, who asked for it, and how it ended. */
|
|
472
|
+
function formatJobLine({ command, result, requestedBy }) {
|
|
473
|
+
const by = requestedBy ? `${styleText("dim", `by ${requestedBy}`.padEnd(16))} ` : "";
|
|
474
|
+
return `${styleText("dim", clock())} ${command.padEnd(10)} ${by}${result}`;
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* A `kubb studio` session. It emits these on the same emitter as its generations, so one logger
|
|
478
|
+
* renders the whole command: the connection, then one job line per command.
|
|
479
|
+
*/
|
|
480
|
+
function createSession(ctx, spinner) {
|
|
481
|
+
const { writer, silent, human, logLevel: logLevel$2, text, hooks } = ctx;
|
|
482
|
+
hooks.hook("studio:disconnected", ({ code, reason }) => {
|
|
483
|
+
if (logLevel$2 < logLevel.warn) return;
|
|
484
|
+
spinner.stop();
|
|
485
|
+
if (code === 4002) {
|
|
486
|
+
writer.warn(text("⚠ Another process connected to Kubb Studio as this agent, so this one stopped"));
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
writer.warn(text(`⚠ Kubb Studio ended the session (${reason || `code ${code}`})`));
|
|
490
|
+
});
|
|
491
|
+
hooks.hook("studio:warn", ({ message, permission }) => {
|
|
492
|
+
if (logLevel$2 < logLevel.warn) return;
|
|
493
|
+
const remedy = permission ? `; pass ${toPermissionFlag(permission)} to allow it` : "";
|
|
494
|
+
const paused = spinner.active;
|
|
495
|
+
spinner.stop();
|
|
496
|
+
writer.warn(text(`⚠ ${message}${remedy}`));
|
|
497
|
+
if (paused) spinner.start("Ready for jobs");
|
|
498
|
+
});
|
|
499
|
+
hooks.hook("studio:error", ({ error }) => {
|
|
500
|
+
if (spinner.active) {
|
|
501
|
+
spinner.stop(error.message, "failed");
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
writer.error(text(error.message));
|
|
505
|
+
});
|
|
506
|
+
if (silent) return;
|
|
507
|
+
let job = null;
|
|
508
|
+
hooks.hook("studio:connected", ({ url, versions: { studio, kubb, agent } }) => {
|
|
509
|
+
ctx.session = human;
|
|
510
|
+
spinner.stop();
|
|
511
|
+
const versions = [
|
|
512
|
+
`v${agent}`,
|
|
513
|
+
kubb !== agent ? `runtime v${kubb}` : void 0,
|
|
514
|
+
`Studio v${studio}`
|
|
515
|
+
].filter(Boolean).join(" · ");
|
|
516
|
+
writer.success(text(`✓ Connected to ${styleText("cyan", url)} ${styleText("dim", `· ${versions}`)}`));
|
|
517
|
+
spinner.start("Ready for jobs");
|
|
518
|
+
});
|
|
519
|
+
hooks.hook("kubb:generation:start", () => {
|
|
520
|
+
if (ctx.session) spinner.message(text("Generating"));
|
|
521
|
+
});
|
|
522
|
+
hooks.hook("kubb:generation:end", ({ diagnostics = [], filesCreated = 0, status, hrStart = process.hrtime() }) => {
|
|
523
|
+
job = {
|
|
524
|
+
fileCount: filesCreated,
|
|
525
|
+
ms: getElapsedMs(hrStart),
|
|
526
|
+
errors: status === "failed" ? Diagnostics.count(diagnostics).errors : 0
|
|
527
|
+
};
|
|
528
|
+
});
|
|
529
|
+
hooks.hook("studio:command", ({ command, info, requestedBy, failed }) => {
|
|
530
|
+
spinner.stop();
|
|
531
|
+
const took = command === "generate" && job ? `${pluralize(job.fileCount, "file")} in ${formatMs(job.ms)} ` : "";
|
|
532
|
+
const result = failed ? `${styleText("red", "✖")} ${job?.errors ? pluralize(job.errors, "error") : "failed"}, see Studio` : `${styleText("green", "✓")} ${took}${styleText("dim", `(${info})`)}`;
|
|
533
|
+
writer.info(formatJobLine({
|
|
534
|
+
command,
|
|
535
|
+
requestedBy,
|
|
536
|
+
result
|
|
537
|
+
}));
|
|
538
|
+
job = null;
|
|
539
|
+
spinner.start("Ready for jobs");
|
|
540
|
+
});
|
|
541
|
+
hooks.hook("studio:reconnecting", ({ delayMs }) => {
|
|
542
|
+
spinner.stop();
|
|
543
|
+
writer.info(text(styleText("dim", `Retrying connection to Kubb Studio in ${formatMs(delayMs)}`)));
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
//#endregion
|
|
547
|
+
//#region src/loggers/features/spinner.ts
|
|
548
|
+
/** The step whose end is not known when it starts: the spec parse, the node walk, a phase, or a Studio session waiting for jobs. */
|
|
549
|
+
function createSpinner({ writer, silent, text }) {
|
|
550
|
+
let spinner = null;
|
|
551
|
+
function stop(message, status = "success") {
|
|
552
|
+
const active = spinner;
|
|
553
|
+
if (!active) return;
|
|
554
|
+
spinner = null;
|
|
555
|
+
if (message === void 0) {
|
|
556
|
+
active.clear();
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (status === "failed") {
|
|
560
|
+
active.error(text(message));
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
active.stop(text(message));
|
|
564
|
+
}
|
|
565
|
+
return {
|
|
566
|
+
/** Whether a spinner is drawing right now. */
|
|
567
|
+
get active() {
|
|
568
|
+
return spinner !== null;
|
|
569
|
+
},
|
|
570
|
+
start(message) {
|
|
571
|
+
if (silent) return;
|
|
572
|
+
spinner = writer.spinner();
|
|
573
|
+
spinner.start(text(message));
|
|
574
|
+
},
|
|
575
|
+
stop,
|
|
576
|
+
/** Redraws the spinner's line. `false` when no spinner is running, so the caller prints the line itself. */
|
|
577
|
+
message(line) {
|
|
578
|
+
if (!spinner) return false;
|
|
579
|
+
spinner.message(line);
|
|
580
|
+
return true;
|
|
581
|
+
},
|
|
582
|
+
reset: () => stop()
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
//#endregion
|
|
586
|
+
//#region src/loggers/features/walk.ts
|
|
587
|
+
/** Milliseconds between redraws of the live generation block, about clack's spinner frame rate. */
|
|
588
|
+
const WALK_REDRAW_MS = 80;
|
|
589
|
+
function createState() {
|
|
590
|
+
return {
|
|
591
|
+
totalPlugins: 0,
|
|
592
|
+
completedPlugins: 0,
|
|
593
|
+
failedPlugins: 0,
|
|
594
|
+
/** `process.hrtime()` snapshot taken at the start of generation, for the elapsed time. */
|
|
595
|
+
hrStart: process.hrtime(),
|
|
596
|
+
/** Plugin results held back while the generation step owns the line. */
|
|
597
|
+
pluginLines: [],
|
|
598
|
+
/** The node walk's live state: the spec's node total, the distinct nodes generated, and each plugin's count and current node. */
|
|
599
|
+
walk: {
|
|
600
|
+
total: 0,
|
|
601
|
+
visited: /* @__PURE__ */ new Set(),
|
|
602
|
+
plugins: /* @__PURE__ */ new Map()
|
|
603
|
+
},
|
|
604
|
+
lastWalkDraw: 0
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
/** The node walk the plugins share: the live generation block, and the plugin results printed once the walk ends. */
|
|
608
|
+
function createWalk({ writer, silent, human, text, onRun }, spinner, progress) {
|
|
609
|
+
const state = createState();
|
|
610
|
+
/** The progress summary line the clack logger shows, `null` when there is nothing to display. */
|
|
611
|
+
function buildProgressLine() {
|
|
612
|
+
const parts = [];
|
|
613
|
+
const duration = formatMs(getElapsedMs(state.hrStart));
|
|
614
|
+
const { totalFiles, processedFiles } = progress.state;
|
|
615
|
+
if (state.totalPlugins > 0) {
|
|
616
|
+
const failed = state.failedPlugins > 0 ? ` ${styleText("red", `(${state.failedPlugins} failed)`)}` : "";
|
|
617
|
+
parts.push(`Plugins ${styleText("green", state.completedPlugins.toString())}/${state.totalPlugins}${failed}`);
|
|
618
|
+
}
|
|
619
|
+
if (totalFiles > 0) parts.push(`Files ${styleText("green", processedFiles.toString())}/${totalFiles}`);
|
|
620
|
+
if (parts.length === 0) return null;
|
|
621
|
+
parts.push(`${styleText("green", duration)} elapsed`);
|
|
622
|
+
return parts.join(styleText("dim", " | "));
|
|
623
|
+
}
|
|
624
|
+
if (!silent) {
|
|
625
|
+
onRun("kubb:build:start", ({ nodeCounts: { schemas, operations } }) => {
|
|
626
|
+
state.walk.total = schemas + operations;
|
|
627
|
+
const details = `${pluralize(schemas, "schema")} · ${pluralize(operations, "operation")} · ${formatMs(getElapsedMs(state.hrStart))}`;
|
|
628
|
+
spinner.stop(`Parsed spec ${styleText("dim", details)}`);
|
|
629
|
+
spinner.start("Generating");
|
|
630
|
+
});
|
|
631
|
+
if (human) {
|
|
632
|
+
const onNode = (key, name, plugin) => {
|
|
633
|
+
const { total, visited, plugins } = state.walk;
|
|
634
|
+
visited.add(key);
|
|
635
|
+
plugins.set(plugin, {
|
|
636
|
+
count: (plugins.get(plugin)?.count ?? 0) + 1,
|
|
637
|
+
current: name
|
|
638
|
+
});
|
|
639
|
+
const now = Date.now();
|
|
640
|
+
if (now - state.lastWalkDraw < WALK_REDRAW_MS) return;
|
|
641
|
+
state.lastWalkDraw = now;
|
|
642
|
+
const elapsed = styleText("dim", formatMs(getElapsedMs(state.hrStart)));
|
|
643
|
+
const head = total ? `Generating ${formatBar(visited.size, total)} ${visited.size}/${total} nodes ${elapsed}` : `Generating ${pluralize(visited.size, "node")} ${elapsed}`;
|
|
644
|
+
const width = Math.max(...[...plugins.keys()].map((pluginName) => pluginName.length));
|
|
645
|
+
const rows = [...plugins].map(([pluginName, row]) => `${styleText("dim", "│")} ${pluginName.padEnd(width)} ${styleText("dim", String(row.count).padStart(4))} ${styleText("cyan", row.current)}`);
|
|
646
|
+
spinner.message(text([head, ...rows].join("\n")));
|
|
647
|
+
};
|
|
648
|
+
onRun("kubb:generate:schema", (node, { plugin }) => onNode(`schema:${node.name}`, node.name ?? "schema", plugin.name));
|
|
649
|
+
onRun("kubb:generate:operation", (node, { plugin }) => onNode(`operation:${node.operationId}`, node.operationId, plugin.name));
|
|
650
|
+
}
|
|
651
|
+
onRun("kubb:plugin:end", ({ plugin, duration, success }) => {
|
|
652
|
+
state[success ? "completedPlugins" : "failedPlugins"]++;
|
|
653
|
+
state.pluginLines.push(text(`${plugin.name} ${success ? "completed" : "failed"} in ${formatMsWithColor(duration)}`));
|
|
654
|
+
});
|
|
655
|
+
onRun("kubb:plugins:end", () => {
|
|
656
|
+
const failed = state.failedPlugins > 0;
|
|
657
|
+
spinner.stop(buildProgressLine() ?? void 0, failed ? "failed" : "success");
|
|
658
|
+
if (state.pluginLines.length) {
|
|
659
|
+
writer.block(state.pluginLines);
|
|
660
|
+
state.pluginLines = [];
|
|
661
|
+
}
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
return {
|
|
665
|
+
state,
|
|
666
|
+
reset() {
|
|
667
|
+
Object.assign(state, createState());
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
//#endregion
|
|
672
|
+
//#region src/loggers/features/index.ts
|
|
673
|
+
/**
|
|
674
|
+
* Wires a {@link LoggerWriter} onto the run's hooks. Each feature registers the hooks for one
|
|
675
|
+
* concern, so every writer reports the same run in the same order: one group per config, a step
|
|
676
|
+
* over the plugin work, a progress bar for the writes, one step per output phase, then the summary.
|
|
677
|
+
* It hands back `renderSummary`, which writes the `cli` reporter's summary inside the group opened
|
|
678
|
+
* for that config and closes the group.
|
|
679
|
+
*/
|
|
680
|
+
function installLogger({ hooks, writer, logLevel }) {
|
|
681
|
+
const ctx = createLoggerContext({
|
|
682
|
+
hooks,
|
|
683
|
+
writer,
|
|
684
|
+
logLevel
|
|
685
|
+
});
|
|
686
|
+
const spinner = createSpinner(ctx);
|
|
687
|
+
const progress = createProgress(ctx, spinner);
|
|
688
|
+
const walk = createWalk(ctx, spinner, progress);
|
|
689
|
+
const phases = createPhases(ctx, spinner);
|
|
690
|
+
const problems = createProblems(ctx, spinner, progress, phases);
|
|
691
|
+
createSession(ctx, spinner);
|
|
692
|
+
return createGeneration(ctx, {
|
|
693
|
+
spinner,
|
|
694
|
+
progress,
|
|
695
|
+
walk,
|
|
696
|
+
phases,
|
|
697
|
+
problems
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
//#endregion
|
|
701
|
+
//#region src/loggers/reporters.ts
|
|
702
|
+
/** Installs the live logger and wires the selected reporters. `cli` renders its summary through the logger, and is skipped when `json` owns stdout. */
|
|
703
|
+
function setupReporters(context, { logLevel: logLevel$1, reporters, writer: writer$1 = writer(), dryRun = false }) {
|
|
704
|
+
const hasJson = reporters.some((reporter) => reporter.name === "json");
|
|
705
|
+
const selected = reporters.flatMap((reporter) => {
|
|
706
|
+
if (reporter.name !== "cli") return [reporter];
|
|
707
|
+
if (hasJson) return [];
|
|
708
|
+
return [createCliReporter({ render: installLogger({
|
|
709
|
+
hooks: context,
|
|
710
|
+
writer: writer$1,
|
|
711
|
+
logLevel: logLevel$1
|
|
712
|
+
}).renderSummary })];
|
|
713
|
+
});
|
|
714
|
+
const ctx = { logLevel: logLevel$1 };
|
|
715
|
+
const pluginFiles = selected.some((reporter) => reporter.needsPluginFiles) ? /* @__PURE__ */ new Map() : void 0;
|
|
716
|
+
const seen = /* @__PURE__ */ new Set();
|
|
717
|
+
if (pluginFiles) context.hook("kubb:plugin:end", ({ plugin, files }) => {
|
|
718
|
+
for (const file of files) {
|
|
719
|
+
if (seen.has(file.path)) continue;
|
|
720
|
+
seen.add(file.path);
|
|
721
|
+
const paths = pluginFiles.get(plugin.name) ?? [];
|
|
722
|
+
paths.push(file.path);
|
|
723
|
+
pluginFiles.set(plugin.name, paths);
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
let filesUnchanged = 0;
|
|
727
|
+
let previous;
|
|
728
|
+
let paths = [];
|
|
729
|
+
let outputPath = "";
|
|
730
|
+
const trackChanges = selected.some((reporter) => reporter.name === "cli") && logLevel$1 > logLevel.silent;
|
|
731
|
+
context.hook("kubb:generation:start", async ({ config }) => {
|
|
732
|
+
pluginFiles?.clear();
|
|
733
|
+
seen.clear();
|
|
734
|
+
filesUnchanged = 0;
|
|
735
|
+
paths = [];
|
|
736
|
+
outputPath = resolve(config.root, config.output.path);
|
|
737
|
+
previous = trackChanges && (dryRun || config.storage?.name === "fs") ? await readOutputFiles(outputPath) : void 0;
|
|
738
|
+
});
|
|
739
|
+
context.hook("kubb:files:processing:start", async ({ files }) => {
|
|
740
|
+
if (!previous) return;
|
|
741
|
+
for (const file of files) {
|
|
742
|
+
if (previous.has(file.path) || isPathInside(outputPath, file.path)) continue;
|
|
743
|
+
const source = await readFile(file.path, "utf8").catch(() => null);
|
|
744
|
+
if (source !== null) previous.set(file.path, source);
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
context.hook("kubb:files:processing:end", ({ files, unchanged }) => {
|
|
748
|
+
filesUnchanged = unchanged.length;
|
|
749
|
+
paths = files.map((file) => file.path);
|
|
750
|
+
});
|
|
751
|
+
context.hook("kubb:generation:end", async ({ config, storage, diagnostics = [], filesCreated = 0, status = "success", hrStart = process.hrtime() }) => {
|
|
752
|
+
const result = {
|
|
753
|
+
config,
|
|
754
|
+
diagnostics,
|
|
755
|
+
filesCreated,
|
|
756
|
+
filesUnchanged,
|
|
757
|
+
dryRun,
|
|
758
|
+
status,
|
|
759
|
+
hrStart
|
|
760
|
+
};
|
|
761
|
+
const cliResult = { ...result };
|
|
762
|
+
if (previous && status !== "failed") {
|
|
763
|
+
const manifest = dryRun ? await createOutputManifest({
|
|
764
|
+
storage,
|
|
765
|
+
cache: cacheStorage({ root: config.root })
|
|
766
|
+
}) : void 0;
|
|
767
|
+
const diff = await diffOutput({
|
|
768
|
+
storage,
|
|
769
|
+
paths,
|
|
770
|
+
clean: Boolean(config.output.clean),
|
|
771
|
+
manifest,
|
|
772
|
+
previousFiles: previous
|
|
773
|
+
});
|
|
774
|
+
const changes = {
|
|
775
|
+
added: 0,
|
|
776
|
+
modified: 0,
|
|
777
|
+
deleted: 0,
|
|
778
|
+
linesAdded: 0,
|
|
779
|
+
linesRemoved: 0
|
|
780
|
+
};
|
|
781
|
+
const counts = {
|
|
782
|
+
A: "added",
|
|
783
|
+
M: "modified",
|
|
784
|
+
D: "deleted"
|
|
785
|
+
};
|
|
786
|
+
for (const file of diff.files) {
|
|
787
|
+
changes[counts[file.status]]++;
|
|
788
|
+
changes.linesAdded += file.added ?? 0;
|
|
789
|
+
changes.linesRemoved += file.removed ?? 0;
|
|
790
|
+
}
|
|
791
|
+
cliResult.filesCreated = changes.added + changes.modified + diff.unchanged;
|
|
792
|
+
cliResult.filesUnchanged = diff.unchanged;
|
|
793
|
+
cliResult.fileChanges = changes;
|
|
794
|
+
}
|
|
795
|
+
for (const reporter of selected) {
|
|
796
|
+
const grouped = reporter.needsPluginFiles && pluginFiles?.size ? [...pluginFiles].map(([plugin, files]) => ({
|
|
797
|
+
plugin,
|
|
798
|
+
files: [...files]
|
|
799
|
+
})) : void 0;
|
|
800
|
+
await reporter.report({
|
|
801
|
+
...reporter.name === "cli" ? cliResult : result,
|
|
802
|
+
pluginFiles: grouped
|
|
803
|
+
}, ctx);
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
context.hook("kubb:lifecycle:end", async () => {
|
|
807
|
+
for (const reporter of selected) await reporter.drain?.(ctx);
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
/** Picks the reporters whose `name` is in `names`, in the given order (the CLI maps `--reporter` to this); duplicates and unknown names are skipped. */
|
|
811
|
+
function selectReporters(reporters, names) {
|
|
812
|
+
return [...new Set(names)].flatMap((name) => reporters.find((reporter) => reporter.name === name) ?? []);
|
|
813
|
+
}
|
|
814
|
+
//#endregion
|
|
815
|
+
export { setupReporters as n, selectReporters as t };
|
|
816
|
+
|
|
817
|
+
//# sourceMappingURL=reporters-Dl8lrJZG.js.map
|