@kubb/core 5.0.0-beta.41 → 5.0.0-beta.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{diagnostics-Ba-FcsPo.d.ts → diagnostics-DZGgDzSv.d.ts} +150 -7
- package/dist/index.cjs +267 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +16 -2
- package/dist/index.js +268 -19
- package/dist/index.js.map +1 -1
- package/dist/{memoryStorage-DA1bnMte.js → memoryStorage-BOnaknb7.js} +149 -10
- package/dist/memoryStorage-BOnaknb7.js.map +1 -0
- package/dist/{memoryStorage-DZqlEW7H.cjs → memoryStorage-Dldu8sRT.cjs} +148 -9
- package/dist/memoryStorage-Dldu8sRT.cjs.map +1 -0
- package/dist/mocks.cjs +1 -1
- package/dist/mocks.d.ts +1 -1
- package/dist/mocks.js +1 -1
- package/package.json +4 -4
- package/src/Fingerprint.ts +98 -0
- package/src/KubbDriver.ts +68 -8
- package/src/Manifest.ts +85 -0
- package/src/Telemetry.ts +13 -1
- package/src/caches/fsCache.ts +103 -0
- package/src/createCache.ts +74 -0
- package/src/createKubb.ts +33 -4
- package/src/defineParser.ts +1 -1
- package/src/index.ts +2 -0
- package/src/storages/fsStorage.ts +15 -23
- package/src/types.ts +2 -0
- package/dist/memoryStorage-DA1bnMte.js.map +0 -1
- package/dist/memoryStorage-DZqlEW7H.cjs.map +0 -1
|
@@ -26,6 +26,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
//#endregion
|
|
27
27
|
let node_events = require("node:events");
|
|
28
28
|
let node_util = require("node:util");
|
|
29
|
+
let node_crypto = require("node:crypto");
|
|
30
|
+
let node_fs_promises = require("node:fs/promises");
|
|
29
31
|
let node_path = require("node:path");
|
|
30
32
|
node_path = __toESM(node_path, 1);
|
|
31
33
|
let _kubb_ast = require("@kubb/ast");
|
|
@@ -661,7 +663,7 @@ var URLPath = class {
|
|
|
661
663
|
};
|
|
662
664
|
//#endregion
|
|
663
665
|
//#region package.json
|
|
664
|
-
var version = "5.0.0-beta.
|
|
666
|
+
var version = "5.0.0-beta.42";
|
|
665
667
|
//#endregion
|
|
666
668
|
//#region src/constants.ts
|
|
667
669
|
/**
|
|
@@ -1230,6 +1232,89 @@ function createStorage(build) {
|
|
|
1230
1232
|
return (options) => build(options ?? {});
|
|
1231
1233
|
}
|
|
1232
1234
|
//#endregion
|
|
1235
|
+
//#region src/Fingerprint.ts
|
|
1236
|
+
/**
|
|
1237
|
+
* Computes the cache key for an incremental build. All methods are static, so call them as
|
|
1238
|
+
* `Fingerprint.compute(...)` and `Fingerprint.stringify(...)`. The key holds no absolute
|
|
1239
|
+
* paths or modification times, so it never depends on where the project lives on disk.
|
|
1240
|
+
*/
|
|
1241
|
+
var Fingerprint = class Fingerprint {
|
|
1242
|
+
/**
|
|
1243
|
+
* Bumped when the snapshot format or fingerprint inputs change in an incompatible way, so stale
|
|
1244
|
+
* cache entries from older Kubb builds are never reused.
|
|
1245
|
+
*/
|
|
1246
|
+
static version = 1;
|
|
1247
|
+
/**
|
|
1248
|
+
* Deterministically serializes a value to JSON: object keys are sorted recursively and
|
|
1249
|
+
* `undefined` values and functions are dropped. Two structurally equal configs produce the same
|
|
1250
|
+
* string regardless of key order, which keeps the fingerprint stable across machines.
|
|
1251
|
+
*/
|
|
1252
|
+
static stringify(value) {
|
|
1253
|
+
return JSON.stringify(Fingerprint.#normalize(value));
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Computes a cache key from everything that affects the generated output: the spec content, the
|
|
1257
|
+
* output-shaping config, each plugin's name and options, the middleware names, the running
|
|
1258
|
+
* `@kubb/core` version, and the cache format version. Returns `null` when the input can't be
|
|
1259
|
+
* fingerprinted (remote URL or no adapter source), which disables caching for that build.
|
|
1260
|
+
*/
|
|
1261
|
+
static async compute({ config, adapterSource, version }) {
|
|
1262
|
+
if (!adapterSource) return null;
|
|
1263
|
+
const spec = await Fingerprint.#readSpec(adapterSource, config.root);
|
|
1264
|
+
if (spec === null) return null;
|
|
1265
|
+
const input = {
|
|
1266
|
+
cacheVersion: Fingerprint.version,
|
|
1267
|
+
version,
|
|
1268
|
+
spec,
|
|
1269
|
+
name: config.name,
|
|
1270
|
+
output: config.output,
|
|
1271
|
+
adapter: config.adapter?.name,
|
|
1272
|
+
parsers: config.parsers.map((parser) => parser.name),
|
|
1273
|
+
plugins: config.plugins.map((plugin) => ({
|
|
1274
|
+
name: plugin.name,
|
|
1275
|
+
options: plugin.options
|
|
1276
|
+
})),
|
|
1277
|
+
middleware: (config.middleware ?? []).map((middleware) => middleware.name)
|
|
1278
|
+
};
|
|
1279
|
+
return (0, node_crypto.createHash)("sha256").update(Fingerprint.stringify(input)).digest("hex");
|
|
1280
|
+
}
|
|
1281
|
+
static #normalize(value) {
|
|
1282
|
+
if (value === null || typeof value !== "object") return typeof value === "function" ? void 0 : value;
|
|
1283
|
+
if (Array.isArray(value)) return value.map((item) => Fingerprint.#normalize(item));
|
|
1284
|
+
const source = value;
|
|
1285
|
+
const result = {};
|
|
1286
|
+
for (const key of Object.keys(source).sort()) {
|
|
1287
|
+
const normalized = Fingerprint.#normalize(source[key]);
|
|
1288
|
+
if (normalized !== void 0) result[key] = normalized;
|
|
1289
|
+
}
|
|
1290
|
+
return result;
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* Reads the spec content that feeds the fingerprint. Returns `null` for a remote URL source
|
|
1294
|
+
* (hashing remote content would mean fetching it on every run) or when a file can't be read, so a
|
|
1295
|
+
* missing or virtual spec disables caching instead of failing the build.
|
|
1296
|
+
*/
|
|
1297
|
+
static async #readSpec(source, root) {
|
|
1298
|
+
if (source.type === "data") return {
|
|
1299
|
+
kind: "data",
|
|
1300
|
+
data: typeof source.data === "string" ? source.data : Fingerprint.stringify(source.data)
|
|
1301
|
+
};
|
|
1302
|
+
const paths = source.type === "paths" ? source.paths : [source.path];
|
|
1303
|
+
if (paths.some((path) => new URLPath(path).isURL)) return null;
|
|
1304
|
+
try {
|
|
1305
|
+
return {
|
|
1306
|
+
kind: "path",
|
|
1307
|
+
contents: await Promise.all(paths.map(async (path) => ({
|
|
1308
|
+
path: (0, node_path.relative)(root, path),
|
|
1309
|
+
content: await (0, node_fs_promises.readFile)(path, "utf8")
|
|
1310
|
+
})))
|
|
1311
|
+
};
|
|
1312
|
+
} catch {
|
|
1313
|
+
return null;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
};
|
|
1317
|
+
//#endregion
|
|
1233
1318
|
//#region src/definePlugin.ts
|
|
1234
1319
|
/**
|
|
1235
1320
|
* Wraps a plugin factory and returns a function that accepts user options and
|
|
@@ -2124,9 +2209,10 @@ var KubbDriver = class KubbDriver {
|
|
|
2124
2209
|
}
|
|
2125
2210
|
async setup() {
|
|
2126
2211
|
const normalized = this.config.plugins.map((rawPlugin) => this.#normalizePlugin(rawPlugin));
|
|
2212
|
+
const dependenciesByName = new Map(normalized.map((plugin) => [plugin.name, new Set(plugin.dependencies ?? [])]));
|
|
2127
2213
|
normalized.sort((a, b) => {
|
|
2128
|
-
if (b.
|
|
2129
|
-
if (a.
|
|
2214
|
+
if (dependenciesByName.get(b.name)?.has(a.name)) return -1;
|
|
2215
|
+
if (dependenciesByName.get(a.name)?.has(b.name)) return 1;
|
|
2130
2216
|
return enforceOrder(a.enforce) - enforceOrder(b.enforce);
|
|
2131
2217
|
});
|
|
2132
2218
|
for (const plugin of normalized) {
|
|
@@ -2351,8 +2437,10 @@ var KubbDriver = class KubbDriver {
|
|
|
2351
2437
|
await hooks.emit("kubb:files:processing:start", { files });
|
|
2352
2438
|
});
|
|
2353
2439
|
const updateBuffer = [];
|
|
2440
|
+
const snapshotSources = /* @__PURE__ */ new Map();
|
|
2354
2441
|
processor.hooks.on("update", (item) => {
|
|
2355
2442
|
updateBuffer.push(item);
|
|
2443
|
+
if (item.source !== void 0) snapshotSources.set(item.file.path, item.source);
|
|
2356
2444
|
});
|
|
2357
2445
|
processor.hooks.on("end", async (files) => {
|
|
2358
2446
|
await hooks.emit("kubb:files:processing:update", { files: updateBuffer.map((item) => ({
|
|
@@ -2368,6 +2456,19 @@ var KubbDriver = class KubbDriver {
|
|
|
2368
2456
|
this.fileManager.hooks.on("upsert", onFileUpsert);
|
|
2369
2457
|
return Diagnostics.scope((diagnostic) => diagnostics.push(diagnostic), async () => {
|
|
2370
2458
|
try {
|
|
2459
|
+
const cache = config.cache;
|
|
2460
|
+
const outputRoot = (0, node_path.resolve)(config.root, config.output.path);
|
|
2461
|
+
const cacheKey = cache ? await Fingerprint.compute({
|
|
2462
|
+
config,
|
|
2463
|
+
adapterSource: this.#adapterSource,
|
|
2464
|
+
version
|
|
2465
|
+
}) : null;
|
|
2466
|
+
if (cache && cacheKey && await this.#restoreSnapshot({
|
|
2467
|
+
cache,
|
|
2468
|
+
cacheKey,
|
|
2469
|
+
outputRoot,
|
|
2470
|
+
storage
|
|
2471
|
+
})) return { diagnostics: Diagnostics.dedupe(diagnostics) };
|
|
2371
2472
|
await this.#parseInput();
|
|
2372
2473
|
await this.emitSetupHooks();
|
|
2373
2474
|
if (this.adapter && this.inputNode) await hooks.emit("kubb:build:start", Object.assign({
|
|
@@ -2426,7 +2527,13 @@ var KubbDriver = class KubbDriver {
|
|
|
2426
2527
|
await hooks.emit("kubb:build:end", {
|
|
2427
2528
|
files: this.fileManager.files,
|
|
2428
2529
|
config,
|
|
2429
|
-
outputDir:
|
|
2530
|
+
outputDir: outputRoot
|
|
2531
|
+
});
|
|
2532
|
+
if (cache && cacheKey && !Diagnostics.hasError(diagnostics)) await this.#persistSnapshot({
|
|
2533
|
+
cache,
|
|
2534
|
+
cacheKey,
|
|
2535
|
+
outputRoot,
|
|
2536
|
+
sources: snapshotSources
|
|
2430
2537
|
});
|
|
2431
2538
|
return { diagnostics: Diagnostics.dedupe(diagnostics) };
|
|
2432
2539
|
} catch (caughtError) {
|
|
@@ -2437,6 +2544,40 @@ var KubbDriver = class KubbDriver {
|
|
|
2437
2544
|
}
|
|
2438
2545
|
});
|
|
2439
2546
|
}
|
|
2547
|
+
/**
|
|
2548
|
+
* Writes a restored snapshot straight to storage and emits `kubb:build:end`. Returns `true` on a
|
|
2549
|
+
* hit (the build is done), `false` on a miss so the caller falls through to a full build.
|
|
2550
|
+
*/
|
|
2551
|
+
async #restoreSnapshot({ cache, cacheKey, outputRoot, storage }) {
|
|
2552
|
+
const snapshot = await cache.restore({ key: cacheKey });
|
|
2553
|
+
if (!snapshot) return false;
|
|
2554
|
+
for (const [relativePath, source] of Object.entries(snapshot.files)) {
|
|
2555
|
+
const absolutePath = (0, node_path.join)(outputRoot, relativePath);
|
|
2556
|
+
this.fileManager.upsert((0, _kubb_ast.createFile)({
|
|
2557
|
+
path: absolutePath,
|
|
2558
|
+
baseName: (0, node_path.basename)(relativePath)
|
|
2559
|
+
}));
|
|
2560
|
+
await storage.setItem(absolutePath, source);
|
|
2561
|
+
}
|
|
2562
|
+
await this.hooks.emit("kubb:build:end", {
|
|
2563
|
+
files: this.fileManager.files,
|
|
2564
|
+
config: this.config,
|
|
2565
|
+
outputDir: outputRoot
|
|
2566
|
+
});
|
|
2567
|
+
return true;
|
|
2568
|
+
}
|
|
2569
|
+
/**
|
|
2570
|
+
* Stores this run's rendered output, keyed by the input fingerprint, so the next unchanged build
|
|
2571
|
+
* restores it instead of regenerating. `sources` is keyed by absolute path and relativized here.
|
|
2572
|
+
*/
|
|
2573
|
+
async #persistSnapshot({ cache, cacheKey, outputRoot, sources }) {
|
|
2574
|
+
const files = {};
|
|
2575
|
+
for (const [absolutePath, source] of sources) files[(0, node_path.relative)(outputRoot, absolutePath)] = source;
|
|
2576
|
+
await cache.persist({
|
|
2577
|
+
key: cacheKey,
|
|
2578
|
+
snapshot: { files }
|
|
2579
|
+
});
|
|
2580
|
+
}
|
|
2440
2581
|
#filesPayload() {
|
|
2441
2582
|
const driver = this;
|
|
2442
2583
|
return {
|
|
@@ -2513,10 +2654,8 @@ var KubbDriver = class KubbDriver {
|
|
|
2513
2654
|
const emitsSchemaHook = this.hooks.listenerCount("kubb:generate:schema") > 0;
|
|
2514
2655
|
const emitsOperationHook = this.hooks.listenerCount("kubb:generate:operation") > 0;
|
|
2515
2656
|
const emitsOperationsHook = this.hooks.listenerCount("kubb:generate:operations") > 0;
|
|
2516
|
-
const schemasBuffer =
|
|
2517
|
-
|
|
2518
|
-
const operationsBuffer = [];
|
|
2519
|
-
for await (const operation of operations) operationsBuffer.push(operation);
|
|
2657
|
+
const schemasBuffer = await Array.fromAsync(schemas);
|
|
2658
|
+
const operationsBuffer = await Array.fromAsync(operations);
|
|
2520
2659
|
const pruningStates = states.filter(({ plugin }) => {
|
|
2521
2660
|
const { include } = plugin.options;
|
|
2522
2661
|
return (include?.some(({ type }) => OPERATION_FILTER_TYPES.has(type)) ?? false) && !(include?.some(({ type }) => type === "schemaName") ?? false);
|
|
@@ -2990,4 +3129,4 @@ Object.defineProperty(exports, "memoryStorage", {
|
|
|
2990
3129
|
}
|
|
2991
3130
|
});
|
|
2992
3131
|
|
|
2993
|
-
//# sourceMappingURL=memoryStorage-
|
|
3132
|
+
//# sourceMappingURL=memoryStorage-Dldu8sRT.cjs.map
|