@kubb/core 5.11.3 → 5.11.5
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/{Hookable-Ce-Xu-KB.js → Hookable-7Kv_oj72.js} +139 -82
- package/dist/Hookable-7Kv_oj72.js.map +1 -0
- package/dist/{createAdapter-D6osJ_0O.d.ts → createAdapter-DtX_MKL-.d.ts} +77 -14
- package/dist/index.cjs +194 -120
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +77 -16
- package/dist/index.d.ts +3 -5
- package/dist/index.js +65 -47
- package/dist/index.js.map +1 -1
- package/dist/mocks.d.ts +1 -1
- package/dist/mocks.js +1 -1
- package/package.json +2 -2
- package/dist/Hookable-Ce-Xu-KB.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -29,10 +29,10 @@ let tinyexec = require("tinyexec");
|
|
|
29
29
|
let node_fs_promises = require("node:fs/promises");
|
|
30
30
|
let node_path = require("node:path");
|
|
31
31
|
node_path = __toESM(node_path, 1);
|
|
32
|
+
let node_fs = require("node:fs");
|
|
32
33
|
let node_util = require("node:util");
|
|
33
34
|
let _kubb_ast = require("@kubb/ast");
|
|
34
35
|
let node_crypto = require("node:crypto");
|
|
35
|
-
let node_fs = require("node:fs");
|
|
36
36
|
let node_os = require("node:os");
|
|
37
37
|
let node_readline = require("node:readline");
|
|
38
38
|
let unstorage = require("unstorage");
|
|
@@ -41,7 +41,7 @@ unstorage_drivers_fs = __toESM(unstorage_drivers_fs, 1);
|
|
|
41
41
|
let node_url = require("node:url");
|
|
42
42
|
let node_module = require("node:module");
|
|
43
43
|
//#region package.json
|
|
44
|
-
var version = "5.11.
|
|
44
|
+
var version = "5.11.5";
|
|
45
45
|
//#endregion
|
|
46
46
|
//#region ../../internals/utils/src/casing.ts
|
|
47
47
|
/**
|
|
@@ -247,9 +247,26 @@ async function write(path, data, options = {}) {
|
|
|
247
247
|
stored: stored ?? "",
|
|
248
248
|
source: trimmed
|
|
249
249
|
})) return null;
|
|
250
|
+
await writeRaw(resolved, content);
|
|
251
|
+
if (options.sanity) {
|
|
252
|
+
const savedData = await read(resolved);
|
|
253
|
+
if (savedData !== content) throw new Error(`Sanity check failed for ${path}\n\nData[${data.length}]:\n${data}\n\nSaved[${savedData.length}]:\n${savedData}\n`);
|
|
254
|
+
return savedData;
|
|
255
|
+
}
|
|
256
|
+
return content;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Writes UTF-8 content verbatim, including empty files and surrounding whitespace.
|
|
260
|
+
* Uses Bun.write under Bun and creates missing parent directories under either runtime.
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* await writeRaw('./cache/output.ts', ' // keep these bytes\n\n')
|
|
264
|
+
*/
|
|
265
|
+
async function writeRaw(path, content) {
|
|
266
|
+
const resolved = (0, node_path.resolve)(path);
|
|
250
267
|
if (runtime.isBun) {
|
|
251
268
|
await Bun.write(resolved, content);
|
|
252
|
-
return
|
|
269
|
+
return;
|
|
253
270
|
}
|
|
254
271
|
try {
|
|
255
272
|
await (0, node_fs_promises.writeFile)(resolved, content, { encoding: "utf-8" });
|
|
@@ -258,12 +275,29 @@ async function write(path, data, options = {}) {
|
|
|
258
275
|
await (0, node_fs_promises.mkdir)((0, node_path.dirname)(resolved), { recursive: true });
|
|
259
276
|
await (0, node_fs_promises.writeFile)(resolved, content, { encoding: "utf-8" });
|
|
260
277
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Lists non-hidden regular files below `directory` as relative POSIX paths, excluding directories and symlinks.
|
|
281
|
+
* Uses Bun.Glob under Bun because its Node glob compatibility API lacks directory-entry support.
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* for await (const path of listFiles('./src')) console.log(path)
|
|
285
|
+
*/
|
|
286
|
+
async function* listFiles(directory) {
|
|
287
|
+
const cwd = (0, node_path.resolve)(directory);
|
|
288
|
+
if (runtime.isBun) {
|
|
289
|
+
yield* new Bun.Glob("**/*").scan({
|
|
290
|
+
cwd,
|
|
291
|
+
dot: false,
|
|
292
|
+
onlyFiles: true,
|
|
293
|
+
followSymlinks: false
|
|
294
|
+
});
|
|
295
|
+
return;
|
|
265
296
|
}
|
|
266
|
-
|
|
297
|
+
for await (const entry of (0, node_fs_promises.glob)("**/*", {
|
|
298
|
+
cwd,
|
|
299
|
+
withFileTypes: true
|
|
300
|
+
})) if (entry.isFile()) yield toPosixPath((0, node_path.relative)(cwd, (0, node_path.join)(entry.parentPath, entry.name)));
|
|
267
301
|
}
|
|
268
302
|
/**
|
|
269
303
|
* Converts a filesystem path to use POSIX (`/`) separators.
|
|
@@ -745,13 +779,15 @@ function serialize(diagnostic) {
|
|
|
745
779
|
* with `at`, `fix`, the first cause, and `Learn more` for an error, and one row for a warning.
|
|
746
780
|
* `verbose` adds the full stack.
|
|
747
781
|
*/
|
|
748
|
-
function format(diagnostic, { audience = "agent", verbose = false, width = 0 } = {}) {
|
|
782
|
+
function format(diagnostic, { audience = "agent", verbose = false, width = 0, position } = {}) {
|
|
749
783
|
const { code, severity, message } = diagnostic;
|
|
750
784
|
const problem = Diagnostics.isProblem(diagnostic) ? diagnostic : void 0;
|
|
751
785
|
const human = audience === "human";
|
|
752
786
|
const paint = human ? node_util.styleText : (_format, text) => text;
|
|
753
787
|
const [firstLine = "", ...rest] = message.split("\n");
|
|
754
788
|
const pointer = problem?.location && "pointer" in problem.location ? problem.location.pointer : void 0;
|
|
789
|
+
const at = position ? `${position.file}:${position.line}:${position.column}` : void 0;
|
|
790
|
+
const where = at ?? pointer;
|
|
755
791
|
const help = problem ? getHelp(problem) : void 0;
|
|
756
792
|
const causes = problem ? getCauses(problem) : [];
|
|
757
793
|
const crash = problem ? crashCodes.has(problem.code) : false;
|
|
@@ -761,7 +797,7 @@ function format(diagnostic, { audience = "agent", verbose = false, width = 0 } =
|
|
|
761
797
|
const row = (label, value) => {
|
|
762
798
|
if (value) details.push(` ${label}: ${value}`);
|
|
763
799
|
};
|
|
764
|
-
row("at", pointer);
|
|
800
|
+
row("at", at && pointer ? `${at} (${pointer})` : pointer);
|
|
765
801
|
if (problem && severity !== "info") row("why", Diagnostics.explain(problem.code).cause);
|
|
766
802
|
row("fix", help);
|
|
767
803
|
for (const cause of causes) row("caused by", cause);
|
|
@@ -771,24 +807,25 @@ function format(diagnostic, { audience = "agent", verbose = false, width = 0 } =
|
|
|
771
807
|
return [`${severity} ${code}${problem?.plugin ? ` [${problem.plugin}]` : ""}: ${firstLine}`, ...details];
|
|
772
808
|
}
|
|
773
809
|
const left = `${paint(severityStyle[severity], severityIcon[severity])} ${paint("bold", firstLine)}`;
|
|
774
|
-
const gap =
|
|
775
|
-
const headline = `${left}${" ".repeat(gap)}${paint("dim", code)}
|
|
810
|
+
const gap = width - (0, node_util.stripVTControlCharacters)(left).length - code.length;
|
|
811
|
+
const headline = width && gap < 2 ? [left, `${" ".repeat(Math.max(0, width - code.length))}${paint("dim", code)}`] : [`${left}${" ".repeat(Math.max(2, gap))}${paint("dim", code)}`];
|
|
776
812
|
const frame = rest.filter((line) => line.trim()).map((line) => ` ${paint("dim", line)}`);
|
|
777
813
|
const label = (name) => paint("dim", name.length < 4 ? name.padEnd(4) : `${name} `);
|
|
778
|
-
const rows = [["at",
|
|
814
|
+
const rows = [["at", where && paint("cyan", where)], ["fix", help]];
|
|
779
815
|
if (severity !== "error") {
|
|
780
816
|
const first = rows.find(([, value]) => value);
|
|
781
817
|
return [
|
|
782
|
-
headline,
|
|
818
|
+
...headline,
|
|
783
819
|
...frame,
|
|
784
820
|
...first ? [` ${label(first[0])} ${first[1]}`] : []
|
|
785
821
|
];
|
|
786
822
|
}
|
|
787
823
|
rows.push(["caused by", causes[0]], ["report", problem?.issues && paint("cyan", problem.issues)]);
|
|
788
|
-
const
|
|
824
|
+
const codeFrame = (position?.frame ?? []).map((line) => ` ${line}`);
|
|
825
|
+
const details = [...frame, ...rows.flatMap(([name, value]) => value ? [` ${label(name)} ${value}`, ...name === "at" ? codeFrame : []] : [])];
|
|
789
826
|
if (frames?.length) details.push(` ${paint("dim", "stack")}`, ...frames);
|
|
790
827
|
if (code !== diagnosticCode.unknown) details.push(` ${paint("dim", "↳ Learn more")} ${paint("cyan", Diagnostics.docsUrl(code).replace(/^https:\/\//, ""))}`);
|
|
791
|
-
return [headline, ...details];
|
|
828
|
+
return [...headline, ...details];
|
|
792
829
|
}
|
|
793
830
|
//#endregion
|
|
794
831
|
//#region src/Diagnostics.ts
|
|
@@ -840,6 +877,7 @@ const failedCode = {
|
|
|
840
877
|
parser: diagnosticCode.parserFailed
|
|
841
878
|
};
|
|
842
879
|
const docsByCode = new Map(Object.values(diagnosticCatalog).map((doc) => [doc.code, doc]));
|
|
880
|
+
const reporterKey = Symbol.for("kubb.diagnostics.reporter");
|
|
843
881
|
const countKey = {
|
|
844
882
|
error: "errors",
|
|
845
883
|
warning: "warnings",
|
|
@@ -849,13 +887,13 @@ const countKey = {
|
|
|
849
887
|
* Static helpers for working with {@link Diagnostic}s, plus the run-scoped sink
|
|
850
888
|
* that lets deep code report a diagnostic without threading a callback.
|
|
851
889
|
*
|
|
852
|
-
* The sink lives in a single `AsyncLocalStorage`
|
|
890
|
+
* The sink lives in a single `AsyncLocalStorage` on `globalThis`, shared by every copy of `@kubb/core`.
|
|
853
891
|
* `Diagnostics.scope` activates it for a run, so anything inside that run (the
|
|
854
892
|
* adapter parse, a generator) reports through `Diagnostics.report` and lands
|
|
855
893
|
* in the same run.
|
|
856
894
|
*/
|
|
857
895
|
var Diagnostics = class Diagnostics {
|
|
858
|
-
static #reporterStorage = new node_async_hooks.AsyncLocalStorage();
|
|
896
|
+
static #reporterStorage = globalThis[reporterKey] ??= new node_async_hooks.AsyncLocalStorage();
|
|
859
897
|
/**
|
|
860
898
|
* The diagnostic code catalog, exposed as `Diagnostics.code` (e.g. `Diagnostics.code.refNotFound`).
|
|
861
899
|
*/
|
|
@@ -1198,7 +1236,7 @@ function defineExtension(definition) {
|
|
|
1198
1236
|
return Object.assign(build(options), {
|
|
1199
1237
|
name: meta.name,
|
|
1200
1238
|
meta,
|
|
1201
|
-
options
|
|
1239
|
+
options: raw
|
|
1202
1240
|
});
|
|
1203
1241
|
}
|
|
1204
1242
|
});
|
|
@@ -1711,7 +1749,8 @@ var Resolver = class Resolver {
|
|
|
1711
1749
|
#resolvePath({ baseName, tag, path: groupPath, root, output, group }) {
|
|
1712
1750
|
if (output.mode !== "directory") return node_path.default.resolve(root, output.path);
|
|
1713
1751
|
const outputDir = node_path.default.resolve(root, output.path);
|
|
1714
|
-
const
|
|
1752
|
+
const groupValue = group?.type === "path" ? groupPath : tag;
|
|
1753
|
+
const result = group && groupValue ? node_path.default.resolve(outputDir, Resolver.#resolveGroupDir(group, groupValue), baseName) : node_path.default.resolve(outputDir, baseName);
|
|
1715
1754
|
assertInside({
|
|
1716
1755
|
target: result,
|
|
1717
1756
|
parent: outputDir,
|
|
@@ -1952,10 +1991,7 @@ function runParser(parser, print) {
|
|
|
1952
1991
|
* Reads a `copy` file and prints it through the parser's `copy` hook, or verbatim with `banner`/`footer` when there is none.
|
|
1953
1992
|
*/
|
|
1954
1993
|
async function parseCopy(file, parser) {
|
|
1955
|
-
|
|
1956
|
-
try {
|
|
1957
|
-
content = await (0, node_fs_promises.readFile)(file.copy, "utf8");
|
|
1958
|
-
} catch (err) {
|
|
1994
|
+
const content = await (0, node_fs_promises.readFile)(file.copy, "utf8").catch((err) => {
|
|
1959
1995
|
throw new Diagnostics.Error({
|
|
1960
1996
|
code: Diagnostics.code.pluginFailed,
|
|
1961
1997
|
severity: "error",
|
|
@@ -1963,7 +1999,7 @@ async function parseCopy(file, parser) {
|
|
|
1963
1999
|
help: "Check that the file a plugin copies into the output exists and is readable.",
|
|
1964
2000
|
cause: toError(err)
|
|
1965
2001
|
});
|
|
1966
|
-
}
|
|
2002
|
+
});
|
|
1967
2003
|
if (parser?.copy) return runParser(parser, () => parser.parse(_kubb_ast.ast.factory.createFile(parser.copy(file, content))));
|
|
1968
2004
|
return [
|
|
1969
2005
|
file.banner,
|
|
@@ -1977,9 +2013,9 @@ function mergeFile(a, b) {
|
|
|
1977
2013
|
banner: b.banner,
|
|
1978
2014
|
footer: b.footer,
|
|
1979
2015
|
copy: b.copy ?? a.copy,
|
|
1980
|
-
sources:
|
|
1981
|
-
imports:
|
|
1982
|
-
exports:
|
|
2016
|
+
sources: [...a.sources, ...b.sources],
|
|
2017
|
+
imports: [...a.imports, ...b.imports],
|
|
2018
|
+
exports: [...a.exports, ...b.exports]
|
|
1983
2019
|
};
|
|
1984
2020
|
}
|
|
1985
2021
|
function isIndexPath(path) {
|
|
@@ -1988,17 +2024,49 @@ function isIndexPath(path) {
|
|
|
1988
2024
|
function compareFiles(a, b) {
|
|
1989
2025
|
return a.path.length - b.path.length || Number(isIndexPath(a.path)) - Number(isIndexPath(b.path));
|
|
1990
2026
|
}
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
2027
|
+
/**
|
|
2028
|
+
* Writes `source` to `file.path` unless the storage already holds it, either verbatim or, per the
|
|
2029
|
+
* manifest, as what the output passes make of it. Checking here rather than in a driver gives a
|
|
2030
|
+
* storage writing to S3 or a database the same guarantee `fsStorage` has. `false` when skipped.
|
|
2031
|
+
*/
|
|
2032
|
+
async function writeChanged({ storage, manifest, file, source, signal }) {
|
|
2033
|
+
signal?.throwIfAborted();
|
|
2034
|
+
const stored = await storage.readItem(file.path);
|
|
2035
|
+
if (stored !== null && (matchesStored({
|
|
1994
2036
|
stored,
|
|
1995
2037
|
source
|
|
1996
|
-
})
|
|
1997
|
-
|
|
1998
|
-
key,
|
|
2038
|
+
}) || manifest?.isUpToDate({
|
|
2039
|
+
key: file.path,
|
|
1999
2040
|
source,
|
|
2000
2041
|
disk: stored
|
|
2001
|
-
})
|
|
2042
|
+
}))) return false;
|
|
2043
|
+
signal?.throwIfAborted();
|
|
2044
|
+
await storage.writeItem(file.path, source, { stored });
|
|
2045
|
+
manifest?.track({
|
|
2046
|
+
key: file.path,
|
|
2047
|
+
source
|
|
2048
|
+
});
|
|
2049
|
+
return true;
|
|
2050
|
+
}
|
|
2051
|
+
/** Reports finished files in input order: each finished file flushes the run of finished files ahead of it as one update. */
|
|
2052
|
+
function createProgress(files, config, hooks) {
|
|
2053
|
+
const finished = [];
|
|
2054
|
+
let flushed = 0;
|
|
2055
|
+
return async (index) => {
|
|
2056
|
+
finished[index] = true;
|
|
2057
|
+
const updates = [];
|
|
2058
|
+
while (finished[flushed]) {
|
|
2059
|
+
flushed++;
|
|
2060
|
+
updates.push({
|
|
2061
|
+
file: files[flushed - 1],
|
|
2062
|
+
processed: flushed,
|
|
2063
|
+
total: files.length,
|
|
2064
|
+
percentage: flushed / files.length * 100,
|
|
2065
|
+
config
|
|
2066
|
+
});
|
|
2067
|
+
}
|
|
2068
|
+
if (updates.length) await hooks.callHook("kubb:files:processing:update", { files: updates });
|
|
2069
|
+
};
|
|
2002
2070
|
}
|
|
2003
2071
|
/**
|
|
2004
2072
|
* In-memory file store for generated files, and the writer that turns them into source
|
|
@@ -2043,25 +2111,17 @@ var FileManager = class {
|
|
|
2043
2111
|
}
|
|
2044
2112
|
}
|
|
2045
2113
|
#store(files, mergeExisting) {
|
|
2046
|
-
const batch =
|
|
2047
|
-
const resolved =
|
|
2048
|
-
for (const file of batch) {
|
|
2114
|
+
const batch = /* @__PURE__ */ new Set();
|
|
2115
|
+
const resolved = files.map((file) => {
|
|
2049
2116
|
const existing = this.#cache.get(file.path);
|
|
2050
|
-
const merged = existing && mergeExisting
|
|
2117
|
+
const merged = _kubb_ast.ast.factory.createFile(existing && (mergeExisting || batch.has(file.path)) ? mergeFile(existing, file) : file);
|
|
2051
2118
|
this.#cache.set(merged.path, merged);
|
|
2052
|
-
|
|
2053
|
-
|
|
2119
|
+
batch.add(merged.path);
|
|
2120
|
+
return merged;
|
|
2121
|
+
});
|
|
2054
2122
|
if (resolved.length > 0) this.#sorted = null;
|
|
2055
2123
|
return resolved;
|
|
2056
2124
|
}
|
|
2057
|
-
#dedupe(files) {
|
|
2058
|
-
const seen = /* @__PURE__ */ new Map();
|
|
2059
|
-
for (const file of files) {
|
|
2060
|
-
const prev = seen.get(file.path);
|
|
2061
|
-
seen.set(file.path, prev ? mergeFile(prev, file) : file);
|
|
2062
|
-
}
|
|
2063
|
-
return [...seen.values()];
|
|
2064
|
-
}
|
|
2065
2125
|
/**
|
|
2066
2126
|
* Releases all stored files. Called by the core after `kubb:build:end`.
|
|
2067
2127
|
*/
|
|
@@ -2089,50 +2149,38 @@ var FileManager = class {
|
|
|
2089
2149
|
* Parses and writes every file through a bounded pool of workers. A small spec runs all its files
|
|
2090
2150
|
* at once; a spec with thousands of files keeps at most {@link FILE_CONCURRENCY} parsed sources in
|
|
2091
2151
|
* memory rather than holding every source, while still overlapping each file's write with the
|
|
2092
|
-
* next file's parse. Files finish in whatever order they parse, so
|
|
2093
|
-
*
|
|
2152
|
+
* next file's parse. Files finish in whatever order they parse, so each finished file flushes the
|
|
2153
|
+
* run of finished files ahead of it as one `kubb:files:processing:update`, keeping rows in input order.
|
|
2094
2154
|
*
|
|
2095
2155
|
* A file the storage already holds is skipped, so a rebuild that generates identical output
|
|
2096
|
-
* writes nothing and leaves every mtime where it was.
|
|
2156
|
+
* writes nothing and leaves every mtime where it was. `kubb:files:processing:end` lists the
|
|
2157
|
+
* skipped paths as `unchanged`.
|
|
2097
2158
|
*/
|
|
2098
2159
|
async write(files, { storage, parsers, manifest, signal, hooks, config }) {
|
|
2099
2160
|
if (files.length === 0) return;
|
|
2100
2161
|
await hooks?.callHook("kubb:files:processing:start", { files });
|
|
2101
|
-
const
|
|
2102
|
-
const
|
|
2162
|
+
const unchanged = [];
|
|
2163
|
+
const progress = hooks && config ? createProgress(files, config, hooks) : void 0;
|
|
2103
2164
|
await inParallel({
|
|
2104
2165
|
items: files,
|
|
2105
2166
|
limit: 50,
|
|
2106
2167
|
run: async (file, index) => {
|
|
2107
2168
|
signal?.throwIfAborted();
|
|
2108
2169
|
const source = await this.parse(file, { parsers });
|
|
2109
|
-
if (
|
|
2170
|
+
if (source && !await writeChanged({
|
|
2171
|
+
storage,
|
|
2172
|
+
manifest,
|
|
2110
2173
|
file,
|
|
2111
|
-
processed: index + 1,
|
|
2112
|
-
total,
|
|
2113
|
-
percentage: (index + 1) / total * 100,
|
|
2114
|
-
config
|
|
2115
|
-
});
|
|
2116
|
-
if (!source) return;
|
|
2117
|
-
signal?.throwIfAborted();
|
|
2118
|
-
const stored = await storage.readItem(file.path);
|
|
2119
|
-
if (isUnchanged({
|
|
2120
|
-
stored,
|
|
2121
2174
|
source,
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
signal?.throwIfAborted();
|
|
2126
|
-
await storage.writeItem(file.path, source, { stored });
|
|
2127
|
-
manifest?.track({
|
|
2128
|
-
key: file.path,
|
|
2129
|
-
source
|
|
2130
|
-
});
|
|
2175
|
+
signal
|
|
2176
|
+
})) unchanged.push(file.path);
|
|
2177
|
+
await progress?.(index);
|
|
2131
2178
|
}
|
|
2132
2179
|
});
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2180
|
+
await hooks?.callHook("kubb:files:processing:end", {
|
|
2181
|
+
files,
|
|
2182
|
+
unchanged
|
|
2183
|
+
});
|
|
2136
2184
|
}
|
|
2137
2185
|
};
|
|
2138
2186
|
//#endregion
|
|
@@ -2460,10 +2508,15 @@ var KubbDriver = class {
|
|
|
2460
2508
|
plugin.options = normalizePluginOptions(plugin.options, plugin.name);
|
|
2461
2509
|
}
|
|
2462
2510
|
if (this.adapter && this.inputNode) {
|
|
2511
|
+
const { meta, schemas, operations } = this.inputNode;
|
|
2463
2512
|
const buildStartContext = this.#withFiles({
|
|
2464
2513
|
config,
|
|
2465
2514
|
adapter: this.adapter,
|
|
2466
|
-
meta
|
|
2515
|
+
meta,
|
|
2516
|
+
nodeCounts: {
|
|
2517
|
+
schemas: schemas.length,
|
|
2518
|
+
operations: operations.length
|
|
2519
|
+
},
|
|
2467
2520
|
getPlugin: this.getPlugin.bind(this)
|
|
2468
2521
|
});
|
|
2469
2522
|
await hooks.callHook("kubb:build:start", buildStartContext);
|
|
@@ -2748,7 +2801,10 @@ var KubbDriver = class {
|
|
|
2748
2801
|
}
|
|
2749
2802
|
return diagnostics;
|
|
2750
2803
|
}
|
|
2751
|
-
/**
|
|
2804
|
+
/**
|
|
2805
|
+
* Runs `node` through the generators whose `match` accepts it; `generate` picks the method for the
|
|
2806
|
+
* node kind.
|
|
2807
|
+
*/
|
|
2752
2808
|
async #dispatchNode({ generators, node, ctx, generate }) {
|
|
2753
2809
|
for (const generator of generators) {
|
|
2754
2810
|
if (!(generator.match ? await generator.match(node, ctx) : true)) continue;
|
|
@@ -3008,7 +3064,7 @@ const fsStorage = createStorage(() => ({
|
|
|
3008
3064
|
name: "fs",
|
|
3009
3065
|
async readItem(key) {
|
|
3010
3066
|
try {
|
|
3011
|
-
return await (
|
|
3067
|
+
return await read((0, node_path.resolve)(key));
|
|
3012
3068
|
} catch (_error) {
|
|
3013
3069
|
return null;
|
|
3014
3070
|
}
|
|
@@ -3026,10 +3082,7 @@ const fsStorage = createStorage(() => ({
|
|
|
3026
3082
|
const resolvedBase = (0, node_path.resolve)(base ?? process.cwd());
|
|
3027
3083
|
const keys = [];
|
|
3028
3084
|
try {
|
|
3029
|
-
for await (const
|
|
3030
|
-
cwd: resolvedBase,
|
|
3031
|
-
withFileTypes: true
|
|
3032
|
-
})) if (entry.isFile()) keys.push(toPosixPath((0, node_path.relative)(resolvedBase, (0, node_path.join)(entry.parentPath, entry.name))));
|
|
3085
|
+
for await (const path of listFiles(resolvedBase)) keys.push(path);
|
|
3033
3086
|
} catch (_error) {}
|
|
3034
3087
|
return keys;
|
|
3035
3088
|
},
|
|
@@ -3075,7 +3128,9 @@ const cacheStorage = createStorage(({ root = process.cwd() }) => {
|
|
|
3075
3128
|
return {
|
|
3076
3129
|
name: "cache",
|
|
3077
3130
|
readItem: (key) => fs.readItem(toPath(key)),
|
|
3078
|
-
writeItem
|
|
3131
|
+
async writeItem(key, value) {
|
|
3132
|
+
await writeRaw(toPath(key), value);
|
|
3133
|
+
},
|
|
3079
3134
|
removeItem: (key) => fs.removeItem(toPath(key)),
|
|
3080
3135
|
readKeys: (base) => fs.readKeys(base ? toPath(base) : dir),
|
|
3081
3136
|
empty: async (base) => base ? fs.empty(toPath(base)) : void 0
|
|
@@ -3659,17 +3714,23 @@ const logLevel = {
|
|
|
3659
3714
|
* ```
|
|
3660
3715
|
*/
|
|
3661
3716
|
function createReporter(reporter) {
|
|
3717
|
+
const { name, needsPluginFiles, drain } = reporter;
|
|
3718
|
+
if (!drain) return {
|
|
3719
|
+
name,
|
|
3720
|
+
needsPluginFiles,
|
|
3721
|
+
async report(result, context) {
|
|
3722
|
+
await reporter.report(result, context);
|
|
3723
|
+
}
|
|
3724
|
+
};
|
|
3662
3725
|
const reports = [];
|
|
3663
3726
|
return {
|
|
3664
|
-
name
|
|
3665
|
-
needsPluginFiles
|
|
3727
|
+
name,
|
|
3728
|
+
needsPluginFiles,
|
|
3666
3729
|
async report(result, context) {
|
|
3667
|
-
|
|
3668
|
-
if (reporter.drain) reports.push(report);
|
|
3730
|
+
reports.push(await reporter.report(result, context));
|
|
3669
3731
|
},
|
|
3670
3732
|
async drain(context) {
|
|
3671
|
-
await
|
|
3672
|
-
reports.length = 0;
|
|
3733
|
+
await drain(context, reports.splice(0));
|
|
3673
3734
|
}
|
|
3674
3735
|
};
|
|
3675
3736
|
}
|
|
@@ -3681,7 +3742,7 @@ function createReporter(reporter) {
|
|
|
3681
3742
|
* counts, so every reporter renders the same data.
|
|
3682
3743
|
*/
|
|
3683
3744
|
function buildReport(result) {
|
|
3684
|
-
const { config, diagnostics, filesCreated, status, hrStart } = result;
|
|
3745
|
+
const { config, diagnostics, filesCreated, filesUnchanged = 0, status, hrStart } = result;
|
|
3685
3746
|
const failed = Diagnostics.failedPlugins(diagnostics);
|
|
3686
3747
|
const total = config.plugins?.length ?? 0;
|
|
3687
3748
|
const counts = Diagnostics.count(diagnostics);
|
|
@@ -3700,6 +3761,9 @@ function buildReport(result) {
|
|
|
3700
3761
|
},
|
|
3701
3762
|
counts,
|
|
3702
3763
|
filesCreated,
|
|
3764
|
+
filesUnchanged,
|
|
3765
|
+
fileChanges: result.fileChanges,
|
|
3766
|
+
dryRun: result.dryRun,
|
|
3703
3767
|
durationMs: getElapsedMs(hrStart),
|
|
3704
3768
|
output: (0, node_path.resolve)(config.root, config.output.path),
|
|
3705
3769
|
timings,
|
|
@@ -3709,39 +3773,48 @@ function buildReport(result) {
|
|
|
3709
3773
|
//#endregion
|
|
3710
3774
|
//#region src/reporters/summary.ts
|
|
3711
3775
|
/**
|
|
3712
|
-
*
|
|
3713
|
-
*
|
|
3714
|
-
* can render the same lines through whatever output it already owns.
|
|
3776
|
+
* Puts the outcome first, followed by file counts, labeled plugin results, and the output path.
|
|
3777
|
+
* Hosts that collect file changes get a compact diff section. Verbose output adds plugin timings.
|
|
3715
3778
|
*/
|
|
3716
3779
|
function formatSummary(report, { showTimings }) {
|
|
3717
|
-
const { status, plugins, counts, filesCreated, durationMs, output, timings } = report;
|
|
3718
|
-
const
|
|
3780
|
+
const { status, plugins, counts, filesCreated, filesUnchanged, fileChanges, dryRun, durationMs, output, timings } = report;
|
|
3781
|
+
const failed = status === "failed";
|
|
3782
|
+
const successTone = counts.warnings ? "yellow" : "green";
|
|
3783
|
+
const tone = failed ? "red" : successTone;
|
|
3784
|
+
const title = (() => {
|
|
3785
|
+
if (failed) return "✗ Generation failed";
|
|
3786
|
+
if (dryRun) return "◇ Dry run complete";
|
|
3787
|
+
if (counts.warnings) return "✓ Generation complete with warnings";
|
|
3788
|
+
if (filesCreated > 0 && filesCreated === filesUnchanged) return "✓ Already up to date";
|
|
3789
|
+
return "✓ Generation complete";
|
|
3790
|
+
})();
|
|
3791
|
+
const separator = (0, node_util.styleText)("dim", " · ");
|
|
3792
|
+
const generated = Math.max(0, filesCreated - filesUnchanged);
|
|
3793
|
+
const fileLabel = `${generated} ${generated === 1 ? "file" : "files"} ${dryRun ? "planned" : "generated"}`;
|
|
3794
|
+
const lines = [
|
|
3795
|
+
`${(0, node_util.styleText)(tone, title)} ${(0, node_util.styleText)("dim", formatMs(durationMs))}`,
|
|
3796
|
+
"",
|
|
3797
|
+
` ${(0, node_util.styleText)(generated ? "bold" : "dim", fileLabel)}${filesUnchanged ? separator + (0, node_util.styleText)("dim", `${filesUnchanged} unchanged`) : ""}`
|
|
3798
|
+
];
|
|
3719
3799
|
const notRun = plugins.total - plugins.passed - plugins.failed.length;
|
|
3720
|
-
|
|
3721
|
-
(0, node_util.styleText)("green", `${plugins.passed} passed`),
|
|
3722
|
-
(0, node_util.styleText)("red", `${plugins.failed.length} failed`),
|
|
3800
|
+
const pluginCounts = [
|
|
3801
|
+
plugins.passed > 0 ? (0, node_util.styleText)("green", `${plugins.passed} passed`) : void 0,
|
|
3802
|
+
plugins.failed.length > 0 ? (0, node_util.styleText)("red", `${plugins.failed.length} failed`) : void 0,
|
|
3723
3803
|
notRun > 0 ? (0, node_util.styleText)("dim", `${notRun} not run`) : void 0
|
|
3724
|
-
].filter(Boolean)
|
|
3725
|
-
|
|
3726
|
-
if (
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
const lines = rows.map(([label, value]) => `${(0, node_util.styleText)("dim", label.padStart(labelWidth))} ${value}`);
|
|
3804
|
+
].filter(Boolean);
|
|
3805
|
+
lines.push(` ${(0, node_util.styleText)("dim", "Plugins")} ${pluginCounts.join(separator) || (0, node_util.styleText)("dim", "none configured")}`);
|
|
3806
|
+
if (plugins.failed.length) lines.push(` ${(0, node_util.styleText)("dim", "Failed plugins")} ${(0, node_util.styleText)("red", plugins.failed.join(", "))}`);
|
|
3807
|
+
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);
|
|
3808
|
+
if (issues.length) lines.push(` ${(0, node_util.styleText)("dim", "Issues")} ${issues.join(separator)}`);
|
|
3809
|
+
const destination = (0, node_path.relative)(process.cwd(), output);
|
|
3810
|
+
const displayPath = destination.startsWith("..") || (0, node_path.isAbsolute)(destination) ? output : `./${destination}`;
|
|
3811
|
+
lines.push(` ${(0, node_util.styleText)("dim", failed || dryRun ? "Target" : "Output")} ${(0, node_util.styleText)(failed ? "dim" : "cyan", displayPath)}`);
|
|
3812
|
+
if (dryRun) lines.push(` ${(0, node_util.styleText)("dim", "Nothing was written.")}`);
|
|
3813
|
+
if (fileChanges) lines.push("", (0, node_util.styleText)("bold", dryRun ? "Planned file changes" : "File changes"), ` ${(0, node_util.styleText)(fileChanges.added ? "green" : "dim", `${fileChanges.added} added`)}${separator}${(0, node_util.styleText)(fileChanges.modified ? "yellow" : "dim", `${fileChanges.modified} modified`)}${separator}${(0, node_util.styleText)(fileChanges.deleted ? "red" : "dim", `${fileChanges.deleted} deleted`)}`, ` ${(0, node_util.styleText)("dim", "Lines")} ${(0, node_util.styleText)(fileChanges.linesAdded ? "green" : "dim", `+${fileChanges.linesAdded}`)} ${(0, node_util.styleText)(fileChanges.linesRemoved ? "red" : "dim", `−${fileChanges.linesRemoved}`)}`);
|
|
3735
3814
|
if (showTimings && timings.length > 0) {
|
|
3736
|
-
const nameWidth = Math.max(
|
|
3737
|
-
|
|
3738
|
-
lines.push((0, node_util.styleText)("dim",
|
|
3739
|
-
for (const timing of timings) {
|
|
3740
|
-
const timeStr = formatMs(timing.durationMs);
|
|
3741
|
-
const barLength = Math.min(Math.ceil(timing.durationMs / 100), 10);
|
|
3742
|
-
const bar = (0, node_util.styleText)("dim", "█".repeat(barLength));
|
|
3743
|
-
lines.push(`${indent}${(0, node_util.styleText)("dim", "•")} ${timing.plugin.padEnd(nameWidth)} ${bar} ${timeStr}`);
|
|
3744
|
-
}
|
|
3815
|
+
const nameWidth = Math.max(...timings.map((timing) => timing.plugin.length));
|
|
3816
|
+
lines.push("", (0, node_util.styleText)("dim", "Plugin timings"));
|
|
3817
|
+
for (const timing of timings) lines.push(` ${timing.plugin.padEnd(nameWidth)} ${(0, node_util.styleText)("dim", formatMs(timing.durationMs))}`);
|
|
3745
3818
|
}
|
|
3746
3819
|
return lines;
|
|
3747
3820
|
}
|
|
@@ -4193,6 +4266,7 @@ exports.cliReporter = cliReporter;
|
|
|
4193
4266
|
exports.createAdapter = createAdapter;
|
|
4194
4267
|
exports.createCliReporter = createCliReporter;
|
|
4195
4268
|
exports.createKubb = createKubb;
|
|
4269
|
+
exports.createOutputManifest = createOutputManifest;
|
|
4196
4270
|
exports.createRenderer = createRenderer;
|
|
4197
4271
|
exports.createReporter = createReporter;
|
|
4198
4272
|
exports.createResolver = createResolver;
|