@kubb/cli 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.
Files changed (82) hide show
  1. package/dist/{agent-CfZ_Uqde.js → agent-CLspGfSn.js} +4 -4
  2. package/dist/{agent-CfZ_Uqde.js.map → agent-CLspGfSn.js.map} +1 -1
  3. package/dist/{agent-Bl8JwjMa.cjs → agent-RdNQgRXD.cjs} +4 -4
  4. package/dist/{agent-Bl8JwjMa.cjs.map → agent-RdNQgRXD.cjs.map} +1 -1
  5. package/dist/{constants-CYxk4aNm.js → constants-84a47qA-.js} +2 -6
  6. package/dist/constants-84a47qA-.js.map +1 -0
  7. package/dist/{constants-CAKUpLcQ.cjs → constants-BtmponZ3.cjs} +1 -11
  8. package/dist/constants-BtmponZ3.cjs.map +1 -0
  9. package/dist/{generate-Bgds6Zx3.cjs → generate-DK1pLJMi.cjs} +2 -2
  10. package/dist/{generate-Bgds6Zx3.cjs.map → generate-DK1pLJMi.cjs.map} +1 -1
  11. package/dist/{generate-CfxFqNeb.js → generate-Db0pJmbG.js} +2 -2
  12. package/dist/{generate-CfxFqNeb.js.map → generate-Db0pJmbG.js.map} +1 -1
  13. package/dist/index.cjs +9 -9
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.js +9 -9
  16. package/dist/index.js.map +1 -1
  17. package/dist/{init-TIec3Dym.js → init-DKMwmbmx.js} +2 -2
  18. package/dist/{init-TIec3Dym.js.map → init-DKMwmbmx.js.map} +1 -1
  19. package/dist/{init-C5wnuzeK.cjs → init-D_MQBDVz.cjs} +2 -2
  20. package/dist/{init-C5wnuzeK.cjs.map → init-D_MQBDVz.cjs.map} +1 -1
  21. package/dist/{mcp-Damue5Mq.js → mcp-DqNyN0cN.js} +3 -3
  22. package/dist/{mcp-Damue5Mq.js.map → mcp-DqNyN0cN.js.map} +1 -1
  23. package/dist/{mcp-Cr753GW1.cjs → mcp-DvEeDWlW.cjs} +3 -3
  24. package/dist/{mcp-Cr753GW1.cjs.map → mcp-DvEeDWlW.cjs.map} +1 -1
  25. package/dist/package-C8u_WvqI.js +6 -0
  26. package/dist/package-C8u_WvqI.js.map +1 -0
  27. package/dist/{package-guApEHiW.cjs → package-CusjBrSS.cjs} +2 -2
  28. package/dist/package-CusjBrSS.cjs.map +1 -0
  29. package/dist/{run-DJxYClJV.js → run-BQ3Qj0xB.js} +4 -4
  30. package/dist/run-BQ3Qj0xB.js.map +1 -0
  31. package/dist/{run-BvXxelGR.js → run-BQzoaxjR.js} +3 -3
  32. package/dist/run-BQzoaxjR.js.map +1 -0
  33. package/dist/{run-C752fag9.js → run-BabEDDqN.js} +128 -369
  34. package/dist/run-BabEDDqN.js.map +1 -0
  35. package/dist/{run-BFEK9md9.js → run-CGf0KEts.js} +3 -3
  36. package/dist/run-CGf0KEts.js.map +1 -0
  37. package/dist/{run-BFZtWpcW.cjs → run-CJUmJcbC.cjs} +128 -369
  38. package/dist/run-CJUmJcbC.cjs.map +1 -0
  39. package/dist/{run-Bz9IFMWg.cjs → run-CkTpemme.cjs} +3 -3
  40. package/dist/run-CkTpemme.cjs.map +1 -0
  41. package/dist/{run-BQZyg7If.cjs → run-Cl4SrSob.cjs} +3 -3
  42. package/dist/run-Cl4SrSob.cjs.map +1 -0
  43. package/dist/{run-BFv6avA_.cjs → run-D-s2LdlW.cjs} +5 -5
  44. package/dist/run-D-s2LdlW.cjs.map +1 -0
  45. package/dist/{validate-DMzjP-hd.cjs → validate-CkW_AKZp.cjs} +3 -3
  46. package/dist/{validate-DMzjP-hd.cjs.map → validate-CkW_AKZp.cjs.map} +1 -1
  47. package/dist/{validate-CYTKdezO.js → validate-jRewvR0c.js} +3 -3
  48. package/dist/{validate-CYTKdezO.js.map → validate-jRewvR0c.js.map} +1 -1
  49. package/package.json +7 -7
  50. package/src/constants.ts +0 -15
  51. package/src/index.ts +2 -2
  52. package/src/loggers/clackLogger.ts +4 -6
  53. package/src/loggers/githubActionsLogger.ts +3 -3
  54. package/src/loggers/plainLogger.ts +2 -3
  55. package/src/loggers/utils.ts +27 -32
  56. package/src/runners/agent/run.ts +2 -2
  57. package/src/runners/generate/run.ts +21 -17
  58. package/src/runners/mcp/run.ts +2 -2
  59. package/src/runners/validate/run.ts +2 -2
  60. package/dist/constants-CAKUpLcQ.cjs.map +0 -1
  61. package/dist/constants-CYxk4aNm.js.map +0 -1
  62. package/dist/package-Cnt1K03J.js +0 -6
  63. package/dist/package-Cnt1K03J.js.map +0 -1
  64. package/dist/package-guApEHiW.cjs.map +0 -1
  65. package/dist/run-BFEK9md9.js.map +0 -1
  66. package/dist/run-BFZtWpcW.cjs.map +0 -1
  67. package/dist/run-BFv6avA_.cjs.map +0 -1
  68. package/dist/run-BQZyg7If.cjs.map +0 -1
  69. package/dist/run-BvXxelGR.js.map +0 -1
  70. package/dist/run-Bz9IFMWg.cjs.map +0 -1
  71. package/dist/run-C752fag9.js.map +0 -1
  72. package/dist/run-DJxYClJV.js.map +0 -1
  73. package/dist/telemetry-B80oJfxR.cjs +0 -280
  74. package/dist/telemetry-B80oJfxR.cjs.map +0 -1
  75. package/dist/telemetry-ueaMzs_c.js +0 -243
  76. package/dist/telemetry-ueaMzs_c.js.map +0 -1
  77. package/src/loggers/diagnostics.ts +0 -77
  78. package/src/reporters/cliReporter.ts +0 -89
  79. package/src/reporters/fileReporter.ts +0 -103
  80. package/src/reporters/jsonReporter.ts +0 -20
  81. package/src/reporters/report.ts +0 -84
  82. package/src/telemetry.ts +0 -280
@@ -1,22 +1,21 @@
1
1
  const require_chunk = require("./chunk-Bx3C2hgW.cjs");
2
2
  const require_errors = require("./errors-DykI11xo.cjs");
3
- const require_telemetry = require("./telemetry-B80oJfxR.cjs");
4
3
  const require_shell = require("./shell-Lh-vLWwH.cjs");
5
- const require_package = require("./package-guApEHiW.cjs");
6
- const require_constants = require("./constants-CAKUpLcQ.cjs");
4
+ const require_package = require("./package-CusjBrSS.cjs");
5
+ const require_constants = require("./constants-BtmponZ3.cjs");
7
6
  let node_util = require("node:util");
8
7
  let node_events = require("node:events");
9
8
  let node_crypto = require("node:crypto");
10
9
  let node_child_process = require("node:child_process");
11
10
  let node_fs = require("node:fs");
12
- let node_fs_promises = require("node:fs/promises");
13
11
  let node_path = require("node:path");
14
12
  node_path = require_chunk.__toESM(node_path, 1);
13
+ let node_dns = require("node:dns");
14
+ let _kubb_core = require("@kubb/core");
15
15
  let node_process = require("node:process");
16
16
  node_process = require_chunk.__toESM(node_process, 1);
17
17
  let _clack_prompts = require("@clack/prompts");
18
18
  _clack_prompts = require_chunk.__toESM(_clack_prompts, 1);
19
- let _kubb_core = require("@kubb/core");
20
19
  let cosmiconfig = require("cosmiconfig");
21
20
  let jiti = require("jiti");
22
21
  let tinyexec = require("tinyexec");
@@ -288,32 +287,6 @@ function getIntro({ title, description, version, areEyesOpen }) {
288
287
  `;
289
288
  }
290
289
  /**
291
- * ANSI color names used by {@link randomCliColor} for deterministic terminal coloring.
292
- */
293
- const randomColors = [
294
- "black",
295
- "red",
296
- "green",
297
- "yellow",
298
- "blue",
299
- "white",
300
- "magenta",
301
- "cyan",
302
- "gray"
303
- ];
304
- /**
305
- * Wraps `text` in a deterministic ANSI color derived from the text's SHA-256 hash.
306
- *
307
- * @example
308
- * ```ts
309
- * randomCliColor('petstore') // '\x1b[33m' + 'petstore' + '\x1b[39m' (always the same color for 'petstore')
310
- * ```
311
- */
312
- function randomCliColor(text) {
313
- if (!text) return "";
314
- return (0, node_util.styleText)(randomColors[(0, node_crypto.createHash)("sha256").update(text).digest().readUInt32BE(0) % randomColors.length] ?? "white", text);
315
- }
316
- /**
317
290
  * Formats a millisecond duration with a threshold-based ANSI color.
318
291
  * `≤ 500 ms` → green · `≤ 1 000 ms` → yellow · `> 1 000 ms` → red.
319
292
  *
@@ -331,6 +304,55 @@ function formatMsWithColor(ms) {
331
304
  return (0, node_util.styleText)("red", formatted);
332
305
  }
333
306
  //#endregion
307
+ //#region ../../internals/utils/src/env.ts
308
+ /**
309
+ * Returns `true` when running inside a GitHub Actions workflow.
310
+ *
311
+ * @example
312
+ * ```ts
313
+ * if (isGitHubActions()) {
314
+ * core.setOutput('result', 'ok')
315
+ * }
316
+ * ```
317
+ */
318
+ function isGitHubActions() {
319
+ return !!process.env.GITHUB_ACTIONS;
320
+ }
321
+ /**
322
+ * Returns `true` when the process is running in a CI environment.
323
+ * Covers GitHub Actions, GitLab CI, CircleCI, Travis CI, Jenkins, Bitbucket,
324
+ * TeamCity, Buildkite, and Azure Pipelines.
325
+ *
326
+ * @example
327
+ * ```ts
328
+ * if (isCIEnvironment()) {
329
+ * logger.level = 'error'
330
+ * }
331
+ * ```
332
+ */
333
+ function isCIEnvironment() {
334
+ return !!(process.env.CI || process.env.GITHUB_ACTIONS || process.env.GITLAB_CI || process.env.BITBUCKET_BUILD_NUMBER || process.env.JENKINS_URL || process.env.CIRCLECI || process.env.TRAVIS || process.env.TEAMCITY_VERSION || process.env.BUILDKITE || process.env.TF_BUILD);
335
+ }
336
+ /**
337
+ * Returns `true` when the process has an interactive TTY with a valid terminal
338
+ * width and is not running in CI.
339
+ *
340
+ * Some IDE-embedded terminals report `isTTY = true` but set `columns` to `0`,
341
+ * which breaks clack's box-drawing helpers (they call `String.prototype.repeat`
342
+ * with a negative count and throw a `RangeError`). We therefore require a
343
+ * positive column count before declaring the TTY usable.
344
+ *
345
+ * @example
346
+ * ```ts
347
+ * if (canUseTTY()) {
348
+ * renderProgressBar()
349
+ * }
350
+ * ```
351
+ */
352
+ function canUseTTY() {
353
+ return !!process.stdout.isTTY && (process.stdout.columns ?? 0) > 0 && !isCIEnvironment();
354
+ }
355
+ //#endregion
334
356
  //#region ../../internals/utils/src/formatters.ts
335
357
  /**
336
358
  * CLI command descriptors for each supported code formatter.
@@ -395,62 +417,8 @@ async function detectFormatter() {
395
417
  return null;
396
418
  }
397
419
  //#endregion
398
- //#region ../../internals/utils/src/fs.ts
399
- /**
400
- * Writes `data` to `path`, trimming leading/trailing whitespace before saving.
401
- * Skips the write when the trimmed content is empty or identical to what is already on disk.
402
- * Creates any missing parent directories automatically.
403
- * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match.
404
- *
405
- * @example
406
- * ```ts
407
- * await write('./src/Pet.ts', source) // writes and returns trimmed content
408
- * await write('./src/Pet.ts', source) // null — file unchanged
409
- * await write('./src/Pet.ts', ' ') // null — empty content skipped
410
- * ```
411
- */
412
- async function write(path, data, options = {}) {
413
- const trimmed = data.trim();
414
- if (trimmed === "") return null;
415
- const resolved = (0, node_path.resolve)(path);
416
- if (typeof Bun !== "undefined") {
417
- const file = Bun.file(resolved);
418
- if ((await file.exists() ? await file.text() : null) === trimmed) return null;
419
- await Bun.write(resolved, trimmed);
420
- return trimmed;
421
- }
422
- try {
423
- if (await (0, node_fs_promises.readFile)(resolved, { encoding: "utf-8" }) === trimmed) return null;
424
- } catch {}
425
- await (0, node_fs_promises.mkdir)((0, node_path.dirname)(resolved), { recursive: true });
426
- await (0, node_fs_promises.writeFile)(resolved, trimmed, { encoding: "utf-8" });
427
- if (options.sanity) {
428
- const savedData = await (0, node_fs_promises.readFile)(resolved, { encoding: "utf-8" });
429
- if (savedData !== trimmed) throw new Error(`Sanity check failed for ${path}\n\nData[${data.length}]:\n${data}\n\nSaved[${savedData.length}]:\n${savedData}\n`);
430
- return savedData;
431
- }
432
- return trimmed;
433
- }
434
- //#endregion
435
420
  //#region ../../internals/utils/src/linters.ts
436
421
  /**
437
- * Collects all files under `dir` recursively using Node's built-in fs APIs.
438
- *
439
- * Passing explicit file paths to oxlint (instead of a directory) bypasses
440
- * oxlint's `.gitignore`-aware directory traversal, which would otherwise skip
441
- * files that are listed in `.gitignore` (e.g. generated output directories).
442
- */
443
- function findLintableFiles(dir) {
444
- try {
445
- return (0, node_fs.readdirSync)(dir, {
446
- withFileTypes: true,
447
- recursive: true
448
- }).filter((d) => d.isFile()).map((d) => `${d.parentPath}/${d.name}`);
449
- } catch {
450
- return [];
451
- }
452
- }
453
- /**
454
422
  * CLI command descriptors for each supported linter.
455
423
  *
456
424
  * Each entry contains the executable `command`, an `args` factory that maps an
@@ -474,7 +442,11 @@ const linters = {
474
442
  },
475
443
  oxlint: {
476
444
  command: "oxlint",
477
- args: (outputPath) => ["--fix", ...findLintableFiles(outputPath)],
445
+ args: (outputPath) => [
446
+ "--fix",
447
+ "--no-ignore",
448
+ outputPath
449
+ ],
478
450
  errorMessage: "Oxlint not found"
479
451
  }
480
452
  };
@@ -509,266 +481,50 @@ async function detectLinter() {
509
481
  return null;
510
482
  }
511
483
  //#endregion
512
- //#region src/reporters/report.ts
513
- /**
514
- * Builds the normalized {@link Report} for one config from its {@link GenerationResult}. Splits the
515
- * diagnostics into problems and per-plugin timings (slowest first) and derives the plugin and issue
516
- * counts, so every reporter renders the same data.
517
- */
518
- function buildReport(result) {
519
- const { config, diagnostics, filesCreated, status, hrStart } = result;
520
- const failed = _kubb_core.Diagnostics.failedPlugins(diagnostics);
521
- const total = config.plugins?.length ?? 0;
522
- const counts = _kubb_core.Diagnostics.count(diagnostics);
523
- const problems = diagnostics.filter(_kubb_core.isProblemDiagnostic);
524
- const timings = diagnostics.filter(_kubb_core.isPerformanceDiagnostic).sort((a, b) => b.duration - a.duration).map((diagnostic) => ({
525
- plugin: diagnostic.plugin,
526
- durationMs: diagnostic.duration
527
- }));
528
- return {
529
- name: config.name ?? "",
530
- status,
531
- plugins: {
532
- passed: total - failed.length,
533
- failed,
534
- total
535
- },
536
- counts,
537
- filesCreated,
538
- durationMs: getElapsedMs(hrStart),
539
- output: (0, node_path.resolve)(config.root, config.output.path),
540
- timings,
541
- diagnostics: problems.map((diagnostic) => _kubb_core.Diagnostics.serialize(diagnostic))
542
- };
543
- }
544
- //#endregion
545
- //#region src/reporters/cliReporter.ts
546
- /**
547
- * Builds the vitest/jest-style summary for one {@link Report}: right-aligned dim labels with
548
- * `N passed (total)` counts, and a per-plugin `Timings` section when `showTimings`.
549
- */
550
- function buildSummaryLines(report, { showTimings }) {
551
- const { status, plugins, counts, filesCreated, durationMs, output, timings } = report;
552
- const rows = [];
553
- rows.push(["Plugins", status === "success" ? `${(0, node_util.styleText)("green", `${plugins.passed} passed`)} (${plugins.total})` : `${(0, node_util.styleText)("green", `${plugins.passed} passed`)} | ${(0, node_util.styleText)("red", `${plugins.failed.length} failed`)} (${plugins.total})`]);
554
- if (status === "failed" && plugins.failed.length > 0) rows.push(["Failed", plugins.failed.map((name) => randomCliColor(name)).join(", ")]);
555
- if (counts.errors > 0 || counts.warnings > 0) {
556
- const issues = [counts.errors > 0 ? (0, node_util.styleText)("red", `${counts.errors} ${counts.errors === 1 ? "error" : "errors"}`) : void 0, counts.warnings > 0 ? (0, node_util.styleText)("yellow", `${counts.warnings} ${counts.warnings === 1 ? "warning" : "warnings"}`) : void 0].filter(Boolean).join(" | ");
557
- rows.push(["Issues", issues]);
558
- }
559
- rows.push(["Files", `${(0, node_util.styleText)("green", String(filesCreated))} generated`]);
560
- rows.push(["Duration", (0, node_util.styleText)("green", formatMs(durationMs))]);
561
- rows.push(["Output", output]);
562
- const labelWidth = Math.max(...rows.map(([label]) => label.length), timings.length > 0 ? 7 : 0);
563
- const lines = rows.map(([label, value]) => `${(0, node_util.styleText)("dim", label.padStart(labelWidth))} ${value}`);
564
- if (showTimings && timings.length > 0) {
565
- const nameWidth = Math.max(0, ...timings.map((timing) => timing.plugin.length));
566
- const indent = " ".repeat(labelWidth + 2);
567
- lines.push((0, node_util.styleText)("dim", "Timings".padStart(labelWidth)));
568
- for (const timing of timings) {
569
- const timeStr = formatMs(timing.durationMs);
570
- const barLength = Math.min(Math.ceil(timing.durationMs / 100), 10);
571
- const bar = (0, node_util.styleText)("dim", "█".repeat(barLength));
572
- lines.push(`${indent}${(0, node_util.styleText)("dim", "•")} ${timing.plugin.padEnd(nameWidth)} ${bar} ${timeStr}`);
573
- }
574
- }
575
- return lines;
576
- }
577
- /**
578
- * Renders the summary as plain `console.log` lines so it works in every CLI (no clack/TTY
579
- * dependency): a blank line, the config name colored by status, then the summary rows.
580
- */
581
- function renderSummary(lines, { title, status }) {
582
- console.log("");
583
- if (title) console.log((0, node_util.styleText)(status === "failed" ? "red" : "green", title));
584
- for (const line of lines) console.log(line);
585
- }
586
- /**
587
- * The default `cli` reporter. Renders the {@link Report} for each config as it finishes, independent
588
- * of the live logger view. Suppressed at `silent`; the `verbose` level adds the per-plugin timings.
589
- */
590
- const cliReporter = (0, _kubb_core.createReporter)({
591
- name: "cli",
592
- report(result, { logLevel }) {
593
- if (logLevel <= _kubb_core.logLevel.silent) return;
594
- const report = buildReport(result);
595
- renderSummary(buildSummaryLines(report, { showTimings: logLevel >= _kubb_core.logLevel.verbose }), {
596
- title: report.name,
597
- status: report.status
598
- });
599
- }
600
- });
601
- //#endregion
602
- //#region src/loggers/diagnostics.ts
603
- /**
604
- * Glyph and accent color per severity, matching the miette/oxlint convention
605
- * (`×` error, `⚠` warning, `ℹ` advice).
606
- */
607
- const severityStyle = {
608
- error: {
609
- glyph: "×",
610
- color: "red"
611
- },
612
- warning: {
613
- glyph: "⚠",
614
- color: "yellow"
615
- },
616
- info: {
617
- glyph: "ℹ",
618
- color: "blue"
619
- }
620
- };
621
- /**
622
- * The colored, bold severity glyph (`×`, `⚠`, `ℹ`) on its own. Pass it as clack's
623
- * `symbol` so clack owns the gutter and adds the bar to the continuation lines,
624
- * instead of baking the glyph into the message text.
625
- */
626
- function diagnosticSymbol(severity) {
627
- const { glyph, color } = severityStyle[severity];
628
- return (0, node_util.styleText)(color, (0, node_util.styleText)("bold", glyph));
629
- }
484
+ //#region ../../internals/utils/src/network.ts
630
485
  /**
631
- * The `plugin(CODE): message` headline, without the leading severity glyph.
486
+ * Well-known stable domains used as DNS probes to check internet connectivity.
632
487
  */
633
- function diagnosticHeadline(diagnostic) {
634
- const { code, severity, message } = diagnostic;
635
- const plugin = (0, _kubb_core.isProblemDiagnostic)(diagnostic) ? diagnostic.plugin : void 0;
636
- const { color } = severityStyle[severity];
637
- return `${(0, node_util.styleText)(color, (0, node_util.styleText)("bold", plugin ? `${plugin}(${code})` : code))}: ${message}`;
638
- }
639
- /**
640
- * The detail lines below the headline: optional `at <pointer>`, `help:`, and
641
- * `docs:`. OpenAPI has no line/column, so the location is the JSON pointer the
642
- * adapter built. Each line keeps a two-space indent so it sits under the headline.
643
- */
644
- function diagnosticDetails(diagnostic) {
645
- const { code } = diagnostic;
646
- const problem = (0, _kubb_core.isProblemDiagnostic)(diagnostic) ? diagnostic : void 0;
647
- const location = problem?.location;
648
- const help = problem?.help;
649
- const lines = [];
650
- if (location && "pointer" in location) lines.push(` ${(0, node_util.styleText)("dim", "at")} ${(0, node_util.styleText)("cyan", location.pointer)}`);
651
- if (help) lines.push(` ${(0, node_util.styleText)("cyan", "help:")} ${help}`);
652
- if (code !== _kubb_core.diagnosticCode.unknown) lines.push(` ${(0, node_util.styleText)("dim", "docs:")} ${(0, node_util.styleText)("cyan", _kubb_core.Diagnostics.docsUrl(code))}`);
653
- return lines;
654
- }
488
+ const TEST_DOMAINS = [
489
+ "dns.google.com",
490
+ "cloudflare.com",
491
+ "one.one.one.one"
492
+ ];
655
493
  /**
656
- * Renders a {@link Diagnostic} in the oxlint style as a self-contained block: a
657
- * plugin(CODE): message` header followed by the {@link diagnosticDetails}.
658
- * Use this where clack's gutter is not available (plain, file output); clack
659
- * loggers pass {@link diagnosticSymbol}, {@link diagnosticHeadline}, and
660
- * {@link diagnosticDetails} to `clack.log.message` instead.
494
+ * Returns `true` when the system has internet connectivity.
495
+ * Probes DNS resolution against well-known stable domains.
661
496
  *
662
497
  * @example
663
498
  * ```ts
664
- * formatDiagnostic({ code: 'KUBB_REF_NOT_FOUND', severity: 'error', message: 'Could not find Pet', help: 'Add Pet under components.schemas.', plugin: '@kubb/plugin-zod', location: { kind: 'schema', pointer: '#/components/schemas/Pet' } })
499
+ * if (await isOnline()) {
500
+ * await fetchLatestVersion()
501
+ * }
665
502
  * ```
666
503
  */
667
- function formatDiagnostic(diagnostic) {
668
- return [`${diagnosticSymbol(diagnostic.severity)} ${diagnosticHeadline(diagnostic)}`, ...diagnosticDetails(diagnostic)];
669
- }
670
- //#endregion
671
- //#region src/reporters/fileReporter.ts
672
- /**
673
- * Builds the `## Summary` section: the same counts the cli and json reporters expose, as a list of
674
- * `label value` rows with the labels padded to a common width.
675
- */
676
- function buildSummarySection(report) {
677
- const { status, plugins, counts, filesCreated, durationMs, output } = report;
678
- const rows = [["Status", status], ["Plugins", status === "success" ? `${plugins.passed} passed (${plugins.total})` : `${plugins.passed} passed | ${plugins.failed.length} failed (${plugins.total})`]];
679
- if (plugins.failed.length > 0) rows.push(["Failed", plugins.failed.join(", ")]);
680
- rows.push(["Issues", `${counts.errors} errors | ${counts.warnings} warnings | ${counts.infos} infos`]);
681
- rows.push(["Files", `${filesCreated} generated`]);
682
- rows.push(["Duration", formatMs(durationMs)]);
683
- rows.push(["Output", output]);
684
- const labelWidth = Math.max(...rows.map(([label]) => label.length));
685
- return [
686
- "## Summary",
687
- "",
688
- ...rows.map(([label, value]) => ` ${label.padEnd(labelWidth)} ${value}`)
689
- ];
690
- }
691
- /**
692
- * Builds the `## Problems` section: each problem rendered in the miette block format, blocks
693
- * separated by a blank line. Returns an empty array when there are no problems, so the caller
694
- * can drop the heading.
695
- */
696
- function buildProblemSection(diagnostics) {
697
- const problems = diagnostics.filter(_kubb_core.isProblemDiagnostic);
698
- if (problems.length === 0) return [];
699
- return [
700
- "## Problems",
701
- "",
702
- problems.map((diagnostic) => formatDiagnostic(diagnostic).join("\n")).join("\n\n")
703
- ];
704
- }
705
- /**
706
- * Builds the `## Timings` section from a {@link Report}: one `plugin duration` row per record,
707
- * slowest first with the plugin names left-aligned and the durations right-aligned. Returns an
708
- * empty array when there are no timings.
709
- */
710
- function buildTimingSection(report) {
711
- const { timings } = report;
712
- if (timings.length === 0) return [];
713
- const nameWidth = Math.max(...timings.map((timing) => timing.plugin.length));
714
- const durations = timings.map((timing) => formatMs(timing.durationMs));
715
- const durationWidth = Math.max(...durations.map((duration) => duration.length));
716
- return [
717
- "## Timings",
718
- "",
719
- ...timings.map((timing, index) => ` ${timing.plugin.padEnd(nameWidth)} ${durations[index].padStart(durationWidth)}`)
720
- ];
504
+ async function isOnline() {
505
+ for (const domain of TEST_DOMAINS) try {
506
+ await node_dns.promises.resolve(domain);
507
+ return true;
508
+ } catch {}
509
+ return false;
721
510
  }
722
511
  /**
723
- * The `file` reporter. Writes a config's {@link Report} to `.kubb/kubb-<name>-<timestamp>.log` as a
724
- * plain-text document: a `# <name> — <timestamp>` header, a `## Summary` with the same counts the
725
- * cli and json reporters expose, a `## Problems` section in the miette block format, and a
726
- * `## Timings` section. Selected with `--reporter file` (or `reporters: ['file']`), replacing the
727
- * old `--debug` flag.
512
+ * Executes `fn` only when the system is online. Returns `null` when offline or on error.
728
513
  *
729
- * @note Unlike the streaming logger it replaced, it captures the collected diagnostics once a
730
- * config finishes, not the live `kubb:info`/`kubb:plugin` event stream. Color is stripped so the
731
- * file stays plain text even when the run is attached to a TTY.
732
- */
733
- const fileReporter = (0, _kubb_core.createReporter)({
734
- name: "file",
735
- async report(result) {
736
- const { diagnostics, config } = result;
737
- if (diagnostics.length === 0) return;
738
- const report = buildReport(result);
739
- const content = (0, node_util.stripVTControlCharacters)([config.name ? `# ${config.name} — ${(/* @__PURE__ */ new Date()).toISOString()}` : `# ${(/* @__PURE__ */ new Date()).toISOString()}`, ...[
740
- buildSummarySection(report),
741
- buildProblemSection(diagnostics),
742
- buildTimingSection(report)
743
- ].filter((section) => section.length > 0).map((section) => section.join("\n"))].join("\n\n"));
744
- const baseName = `${[
745
- "kubb",
746
- config.name,
747
- Date.now()
748
- ].filter(Boolean).join("-")}.log`;
749
- const pathName = (0, node_path.resolve)(node_process.default.cwd(), ".kubb", baseName);
750
- await write(pathName, `${content}\n`);
751
- console.error(`Debug log written to ${(0, node_path.relative)(node_process.default.cwd(), pathName)}`);
752
- }
753
- });
754
- //#endregion
755
- //#region src/reporters/jsonReporter.ts
756
- /**
757
- * The `json` reporter. `report` returns one config's {@link Report}, which {@link createReporter}
758
- * buffers, and `flush` writes them as a single pretty-printed JSON array on `kubb:lifecycle:end`.
759
- * Buffering keeps a multi-config run one valid JSON document on stdout instead of concatenated
760
- * objects that would break `jq .`. The terminal reporter is suppressed while `json` is active so
761
- * stdout stays valid JSON.
514
+ * @example
515
+ * ```ts
516
+ * const version = await executeIfOnline(() => fetchLatestVersion('kubb'))
517
+ * // null when offline
518
+ * ```
762
519
  */
763
- const jsonReporter = (0, _kubb_core.createReporter)({
764
- name: "json",
765
- report(result) {
766
- return buildReport(result);
767
- },
768
- flush(_context, reports) {
769
- node_process.default.stdout.write(`${JSON.stringify(reports, null, 2)}\n`);
520
+ async function executeIfOnline(fn) {
521
+ if (!await isOnline()) return null;
522
+ try {
523
+ return await fn();
524
+ } catch {
525
+ return null;
770
526
  }
771
- });
527
+ }
772
528
  //#endregion
773
529
  //#region src/loggers/clackLogger.ts
774
530
  /**
@@ -885,7 +641,7 @@ const clackLogger = (0, _kubb_core.defineLogger)({
885
641
  if (logLevel <= _kubb_core.logLevel.silent && diagnostic.severity !== "error") return;
886
642
  stopSpinner();
887
643
  stopActiveProgress();
888
- if ((0, _kubb_core.isUpdateDiagnostic)(diagnostic)) {
644
+ if (_kubb_core.Diagnostics.isUpdate(diagnostic)) {
889
645
  _clack_prompts.box(`\`v${diagnostic.currentVersion}\` → \`v${diagnostic.latestVersion}\`
890
646
  Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
891
647
  width: "auto",
@@ -897,7 +653,8 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
897
653
  });
898
654
  return;
899
655
  }
900
- _clack_prompts.log.message([diagnosticHeadline(diagnostic), ...diagnosticDetails(diagnostic)], { symbol: diagnosticSymbol(diagnostic.severity) });
656
+ const { symbol, headline, details } = _kubb_core.Diagnostics.format(diagnostic);
657
+ _clack_prompts.log.message([headline, ...details], { symbol });
901
658
  });
902
659
  context.on("kubb:lifecycle:start", async ({ version }) => {
903
660
  console.log(`\n${getIntro({
@@ -1144,7 +901,7 @@ const githubActionsLogger = (0, _kubb_core.defineLogger)({
1144
901
  context.on("kubb:diagnostic", ({ diagnostic }) => {
1145
902
  closeAllGroups();
1146
903
  if (logLevel <= _kubb_core.logLevel.silent && diagnostic.severity !== "error") return;
1147
- if (!(0, _kubb_core.isProblemDiagnostic)(diagnostic)) {
904
+ if (!_kubb_core.Diagnostics.isProblem(diagnostic)) {
1148
905
  console.log(`::notice::${diagnostic.message}`);
1149
906
  return;
1150
907
  }
@@ -1152,7 +909,7 @@ const githubActionsLogger = (0, _kubb_core.defineLogger)({
1152
909
  if (diagnostic.location && "pointer" in diagnostic.location) parts.push(`(at ${diagnostic.location.pointer})`);
1153
910
  if (diagnostic.plugin) parts.push(`[plugin: ${diagnostic.plugin}]`);
1154
911
  if (diagnostic.help) parts.push(`help: ${diagnostic.help}`);
1155
- if (diagnostic.code !== _kubb_core.diagnosticCode.unknown) parts.push(`docs: ${_kubb_core.Diagnostics.docsUrl(diagnostic.code)}`);
912
+ if (diagnostic.code !== _kubb_core.Diagnostics.code.unknown) parts.push(`docs: ${_kubb_core.Diagnostics.docsUrl(diagnostic.code)}`);
1156
913
  console.error(`::error::${parts.join(" ")}`);
1157
914
  });
1158
915
  context.on("kubb:lifecycle:start", ({ version }) => {
@@ -1316,7 +1073,7 @@ const plainLogger = (0, _kubb_core.defineLogger)({
1316
1073
  });
1317
1074
  context.on("kubb:diagnostic", ({ diagnostic }) => {
1318
1075
  if (logLevel <= _kubb_core.logLevel.silent && diagnostic.severity !== "error") return;
1319
- console.log(getMessage(formatDiagnostic(diagnostic).join("\n")));
1076
+ console.log(getMessage(_kubb_core.Diagnostics.formatLines(diagnostic).join("\n")));
1320
1077
  });
1321
1078
  context.on("kubb:lifecycle:start", ({ version }) => {
1322
1079
  console.log(`Kubb CLI v${version}`);
@@ -1475,8 +1232,8 @@ function formatCommandWithArgs(command, args) {
1475
1232
  return args?.length ? `${command} ${args.join(" ")}` : command;
1476
1233
  }
1477
1234
  function detectLogger() {
1478
- if (require_telemetry.isGitHubActions()) return "github-actions";
1479
- if (require_telemetry.canUseTTY()) return "clack";
1235
+ if (isGitHubActions()) return "github-actions";
1236
+ if (canUseTTY()) return "clack";
1480
1237
  return "plain";
1481
1238
  }
1482
1239
  const logMapper = {
@@ -1498,31 +1255,32 @@ function installReporter(context, reporter, ctx) {
1498
1255
  hrStart
1499
1256
  }, ctx);
1500
1257
  });
1501
- if (reporter.flush) context.on("kubb:lifecycle:end", () => reporter.flush?.(ctx));
1258
+ if (reporter.drain) context.on("kubb:lifecycle:end", () => reporter.drain?.(ctx));
1502
1259
  }
1503
1260
  /**
1504
- * Installs the live logger (the TUI view) and the selected reporters (the output), returning the
1505
- * terminal logger's hook sink when one was installed. Loggers and reporters are independent: the
1506
- * `cli` selection activates the env logger plus the {@link cliReporter} summary.
1261
+ * Installs the live logger (the TUI view) and the given reporters (the output), returning the
1262
+ * terminal logger's hook sink when one was installed. The reporters are already selected by the
1263
+ * caller (the CLI maps `--reporter` to names via `selectReporters`); this only wires them.
1507
1264
  *
1508
- * The `json` reporter owns stdout, so the terminal logger and `cli` summary are suppressed whenever
1509
- * `json` is selected, even if `cli` is also listed.
1265
+ * Loggers and reporters are independent: the `cli` reporter also activates the env logger summary.
1266
+ * The `json` reporter owns stdout, so the live logger and the `cli` summary are suppressed whenever
1267
+ * `json` is among the reporters, even if `cli` is also listed.
1510
1268
  */
1511
1269
  async function setupReporters(context, { logLevel, reporters }) {
1512
- const unique = new Set(reporters.length ? reporters : ["cli"]);
1513
- const hasJson = unique.has("json");
1270
+ const hasJson = reporters.some((reporter) => reporter.name === "json");
1514
1271
  const ctx = { logLevel };
1515
1272
  let makeSink = null;
1516
- if (unique.has("cli") && !hasJson) {
1517
- const type = detectLogger();
1518
- const logger = logMapper[type];
1519
- if (!logger) throw new Error(`Unknown adapter type: ${type}`);
1520
- const sink = await logger.install(context, { logLevel });
1521
- makeSink = typeof sink === "function" ? sink : null;
1522
- installReporter(context, cliReporter, ctx);
1273
+ for (const reporter of reporters) {
1274
+ if (reporter.name === "cli") {
1275
+ if (hasJson) continue;
1276
+ const type = detectLogger();
1277
+ const logger = logMapper[type];
1278
+ if (!logger) throw new Error(`Unknown adapter type: ${type}`);
1279
+ const sink = await logger.install(context, { logLevel });
1280
+ makeSink = typeof sink === "function" ? sink : null;
1281
+ }
1282
+ installReporter(context, reporter, ctx);
1523
1283
  }
1524
- if (hasJson) installReporter(context, jsonReporter, ctx);
1525
- if (unique.has("file")) installReporter(context, fileReporter, ctx);
1526
1284
  return makeSink;
1527
1285
  }
1528
1286
  //#endregion
@@ -1721,7 +1479,7 @@ async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefi
1721
1479
  }
1722
1480
  }
1723
1481
  let toolError;
1724
- if (resolvedTool && resolvedTool !== "auto" && resolvedTool in toolMap) {
1482
+ if (resolvedTool && resolvedTool !== "auto" && resolvedTool in toolMap && (0, node_fs.existsSync)(outputPath)) {
1725
1483
  const toolConfig = toolMap[resolvedTool];
1726
1484
  const hookId = (0, node_crypto.createHash)("sha256").update([configName, resolvedTool].filter(Boolean).join("-")).digest("hex");
1727
1485
  const successMessage = [
@@ -1789,7 +1547,7 @@ async function generate(options) {
1789
1547
  name: p.name,
1790
1548
  options: p.options
1791
1549
  }));
1792
- const reportTelemetry = (status) => require_telemetry.sendTelemetry(require_telemetry.buildTelemetryEvent({
1550
+ const reportTelemetry = (status) => _kubb_core.Telemetry.send(_kubb_core.Telemetry.build({
1793
1551
  command: "generate",
1794
1552
  kubbVersion: require_package.version,
1795
1553
  plugins: telemetryPlugins,
@@ -1798,8 +1556,8 @@ async function generate(options) {
1798
1556
  status
1799
1557
  }));
1800
1558
  for (const diagnostic of diagnostics) {
1801
- if (!(0, _kubb_core.isProblemDiagnostic)(diagnostic)) continue;
1802
- const unknown = (0, _kubb_core.narrowDiagnostic)(diagnostic, _kubb_core.diagnosticCode.unknown);
1559
+ if (!_kubb_core.Diagnostics.isProblem(diagnostic)) continue;
1560
+ const unknown = _kubb_core.Diagnostics.narrow(diagnostic, _kubb_core.Diagnostics.code.unknown);
1803
1561
  if (unknown) await hooks.emit("kubb:error", { error: unknown.cause ?? new Error(unknown.message) });
1804
1562
  else await _kubb_core.Diagnostics.emit(hooks, diagnostic);
1805
1563
  }
@@ -1818,7 +1576,7 @@ async function generate(options) {
1818
1576
  const outputPath = node_path.default.resolve(config.root, config.output.path);
1819
1577
  const outputDiagnostics = [];
1820
1578
  const toolPasses = [config.output.format && {
1821
- code: _kubb_core.diagnosticCode.formatFailed,
1579
+ code: _kubb_core.Diagnostics.code.formatFailed,
1822
1580
  toolValue: config.output.format,
1823
1581
  detect: detectFormatter,
1824
1582
  toolMap: formatters,
@@ -1828,7 +1586,7 @@ async function generate(options) {
1828
1586
  onStart: () => hooks.emit("kubb:format:start"),
1829
1587
  onEnd: () => hooks.emit("kubb:format:end")
1830
1588
  }, config.output.lint && {
1831
- code: _kubb_core.diagnosticCode.lintFailed,
1589
+ code: _kubb_core.Diagnostics.code.lintFailed,
1832
1590
  toolValue: config.output.lint,
1833
1591
  detect: detectLinter,
1834
1592
  toolMap: linters,
@@ -1869,7 +1627,7 @@ async function generate(options) {
1869
1627
  hooks.off("kubb:hook:end", onHookEnd);
1870
1628
  }
1871
1629
  for (const error of hookFailures) {
1872
- const diagnostic = outputDiagnostic(_kubb_core.diagnosticCode.hookFailed, "Post-generate hook", error);
1630
+ const diagnostic = outputDiagnostic(_kubb_core.Diagnostics.code.hookFailed, "Post-generate hook", error);
1873
1631
  outputDiagnostics.push(diagnostic);
1874
1632
  await _kubb_core.Diagnostics.emit(hooks, diagnostic);
1875
1633
  }
@@ -1907,7 +1665,7 @@ function outputDiagnostic(code, label, caughtError) {
1907
1665
  };
1908
1666
  }
1909
1667
  async function checkForUpdate(hooks) {
1910
- await require_telemetry.executeIfOnline(async () => {
1668
+ await executeIfOnline(async () => {
1911
1669
  try {
1912
1670
  const data = await (await fetch(require_constants.KUBB_NPM_PACKAGE_URL)).json();
1913
1671
  if (data.version && require_package.version < data.version) await _kubb_core.Diagnostics.emit(hooks, _kubb_core.Diagnostics.update({
@@ -1939,14 +1697,15 @@ async function run({ input, configPath, logLevel: logLevelKey, watch, reporters:
1939
1697
  } catch (error) {
1940
1698
  await setupReporters(hooks, {
1941
1699
  logLevel,
1942
- reporters: ["cli"]
1700
+ reporters: [_kubb_core.cliReporter]
1943
1701
  });
1944
1702
  await hooks.emit("kubb:error", { error: require_errors.toError(error) });
1945
1703
  node_process.default.exit(1);
1946
1704
  }
1705
+ const requestedNames = cliReporters?.length ? cliReporters : ["cli"];
1947
1706
  const makeSink = await setupReporters(hooks, {
1948
1707
  logLevel,
1949
- reporters: cliReporters?.length ? cliReporters : configs[0]?.reporters ?? ["cli"]
1708
+ reporters: (0, _kubb_core.selectReporters)(configs[0]?.reporters ?? [], requestedNames)
1950
1709
  });
1951
1710
  await hooks.emit("kubb:lifecycle:start", { version: require_package.version });
1952
1711
  await checkForUpdate(hooks);
@@ -1963,7 +1722,7 @@ async function run({ input, configPath, logLevel: logLevelKey, watch, reporters:
1963
1722
  });
1964
1723
  await hooks.emit("kubb:config:end", { configs });
1965
1724
  let anyFailed = false;
1966
- for (const config of configs) if ((0, _kubb_core.isInputPath)(config) && watch) await startWatcher([input || config.input.path], async (paths) => {
1725
+ for (const config of configs) if (config.input && "path" in config.input && watch) await startWatcher([input || config.input.path], async (paths) => {
1967
1726
  await generate({
1968
1727
  input,
1969
1728
  config,
@@ -1998,4 +1757,4 @@ async function run({ input, configPath, logLevel: logLevelKey, watch, reporters:
1998
1757
  //#endregion
1999
1758
  exports.run = run;
2000
1759
 
2001
- //# sourceMappingURL=run-BFZtWpcW.cjs.map
1760
+ //# sourceMappingURL=run-CJUmJcbC.cjs.map