@kubb/core 5.0.0-beta.107 → 5.0.0-beta.109
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/index.cjs +198 -163
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +171 -135
- package/dist/index.js.map +1 -1
- package/dist/mocks.cjs +1 -1
- package/dist/mocks.d.ts +1 -1
- package/dist/mocks.js +1 -1
- package/dist/{types-Dtisidv5.d.ts → types-TqpVzVtY.d.ts} +60 -7
- package/dist/{usingCtx-lve4tKsy.cjs → usingCtx-BdYw7ICK.cjs} +234 -21
- package/dist/usingCtx-BdYw7ICK.cjs.map +1 -0
- package/dist/{usingCtx-D9_Ee6kn.js → usingCtx-njZUKKsY.js} +217 -22
- package/dist/usingCtx-njZUKKsY.js.map +1 -0
- package/package.json +2 -2
- package/dist/usingCtx-D9_Ee6kn.js.map +0 -1
- package/dist/usingCtx-lve4tKsy.cjs.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
|
|
2
|
-
import { $ as PluginFactoryOptions, A as Kubb, At as DiagnosticDoc, B as Exclude, Bt as Hookable, C as KubbWarnContext, Ct as Reporter, D as CreateKubbOptions, Dt as createReporter, E as UserConfig, Et as UserReporter, F as NodeCache, Ft as PerformanceDiagnostic, G as KubbPluginSetupContext, H as Group, Ht as AdapterFactoryOptions, I as KubbDriver, It as ProblemCode, J as Output, K as KubbPluginStartContext, L as FileManagerHooks, Lt as ProblemDiagnostic, M as Generator, Mt as DiagnosticLocation, N as GeneratorContext, Nt as DiagnosticSeverity, O as GenerateOptions, Ot as logLevel, P as defineGenerator, Pt as Diagnostics, Q as Plugin, R as Parser, Rt as SerializedDiagnostic, S as KubbSuccessContext, St as GenerationResult, T as PostGenerateCommand, Tt as ReporterName, U as Include, Ut as AdapterSource, V as Filter, Vt as Adapter, W as KubbPluginEndContext, Wt as createAdapter, X as OutputOptions, Y as OutputMode, Z as Override, _ as KubbHookStartContext, _t as Renderer, a as KubbBuildEndContext, at as ResolveBannerFile, b as KubbLifecycleStartContext, bt as Storage, c as KubbErrorContext, ct as ResolveOptionsContext, d as KubbFilesProcessingStartContext, dt as ResolverDefault, et as PluginName, f as KubbFilesProcessingUpdateContext, ft as ResolverFile, g as KubbHookLineContext, gt as ResolverPathParams, h as KubbHookEndContext, ht as ResolverPatch, i as Input, it as ResolveBannerContext, j as createKubb, jt as DiagnosticKind, k as GenerateResult, kt as Diagnostic, l as KubbFileProcessingUpdate, lt as ResolvePathOptions, m as KubbGenerationStartContext, mt as ResolverFilePathParams, n as CLIOptions, nt as definePlugin, o as KubbBuildStartContext, ot as ResolveFileOptions, p as KubbGenerationEndContext, pt as ResolverFileParams, q as NormalizedPlugin, r as Config, rt as BannerMeta, s as KubbDiagnosticContext, st as ResolveImportsOptions, t as BuildOutput, tt as ResolvePluginOptions, u as KubbFilesProcessingEndContext, ut as Resolver, v as KubbHooks, vt as RendererFactory, w as PossibleConfig, wt as ReporterContext, x as KubbPluginsEndContext, xt as createStorage, y as KubbInfoContext, yt as createRenderer, z as defineParser, zt as UpdateDiagnostic } from "./types-
|
|
2
|
+
import { $ as PluginFactoryOptions, A as Kubb, At as DiagnosticDoc, B as Exclude, Bt as Hookable, C as KubbWarnContext, Ct as Reporter, D as CreateKubbOptions, Dt as createReporter, E as UserConfig, Et as UserReporter, F as NodeCache, Ft as PerformanceDiagnostic, G as KubbPluginSetupContext, H as Group, Ht as AdapterFactoryOptions, I as KubbDriver, It as ProblemCode, J as Output, K as KubbPluginStartContext, L as FileManagerHooks, Lt as ProblemDiagnostic, M as Generator, Mt as DiagnosticLocation, N as GeneratorContext, Nt as DiagnosticSeverity, O as GenerateOptions, Ot as logLevel, P as defineGenerator, Pt as Diagnostics, Q as Plugin, R as Parser, Rt as SerializedDiagnostic, S as KubbSuccessContext, St as GenerationResult, T as PostGenerateCommand, Tt as ReporterName, U as Include, Ut as AdapterSource, V as Filter, Vt as Adapter, W as KubbPluginEndContext, Wt as createAdapter, X as OutputOptions, Y as OutputMode, Z as Override, _ as KubbHookStartContext, _t as Renderer, a as KubbBuildEndContext, at as ResolveBannerFile, b as KubbLifecycleStartContext, bt as Storage, c as KubbErrorContext, ct as ResolveOptionsContext, d as KubbFilesProcessingStartContext, dt as ResolverDefault, et as PluginName, f as KubbFilesProcessingUpdateContext, ft as ResolverFile, g as KubbHookLineContext, gt as ResolverPathParams, h as KubbHookEndContext, ht as ResolverPatch, i as Input, it as ResolveBannerContext, j as createKubb, jt as DiagnosticKind, k as GenerateResult, kt as Diagnostic, l as KubbFileProcessingUpdate, lt as ResolvePathOptions, m as KubbGenerationStartContext, mt as ResolverFilePathParams, n as CLIOptions, nt as definePlugin, o as KubbBuildStartContext, ot as ResolveFileOptions, p as KubbGenerationEndContext, pt as ResolverFileParams, q as NormalizedPlugin, r as Config, rt as BannerMeta, s as KubbDiagnosticContext, st as ResolveImportsOptions, t as BuildOutput, tt as ResolvePluginOptions, u as KubbFilesProcessingEndContext, ut as Resolver, v as KubbHooks, vt as RendererFactory, w as PossibleConfig, wt as ReporterContext, x as KubbPluginsEndContext, xt as createStorage, y as KubbInfoContext, yt as createRenderer, z as defineParser, zt as UpdateDiagnostic } from "./types-TqpVzVtY.js";
|
|
3
3
|
//#region src/applyConfigDefaults.d.ts
|
|
4
4
|
type ApplyConfigDefaultsOptions<TOutput> = {
|
|
5
5
|
defaultAdapter: Adapter;
|
|
@@ -141,7 +141,8 @@ declare function getInputKind(input: NonNullable<Input>): InputKind;
|
|
|
141
141
|
*
|
|
142
142
|
* Writes are deduplicated and directory-safe:
|
|
143
143
|
* - leading and trailing whitespace is trimmed before writing
|
|
144
|
-
* - the write is skipped when the file content
|
|
144
|
+
* - the write is skipped when the file already holds that content, ignoring any trailing newline
|
|
145
|
+
* a formatter left behind
|
|
145
146
|
* - missing parent directories are created automatically
|
|
146
147
|
* - Bun's native file API is used when running under Bun
|
|
147
148
|
* - concurrent `writeItem` calls are capped at {@link WRITE_CONCURRENCY} in flight, so a caller
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import "./rolldown-runtime-C0LytTxp.js";
|
|
2
|
-
import { a as
|
|
1
|
+
import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
|
|
2
|
+
import { a as OPERATION_FILTER_TYPES, c as clean, d as toPosixPath, f as write, g as camelCase, h as toError, i as Hookable, l as isPathInside, m as getErrorMessage, n as createNodeCache, o as diagnosticCode, p as BuildError, r as FileManager, s as inParallel, t as _usingCtx, u as toFilePath } from "./usingCtx-njZUKKsY.js";
|
|
3
3
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
4
|
import { stripVTControlCharacters, styleText } from "node:util";
|
|
5
|
-
import { hash } from "node:crypto";
|
|
5
|
+
import { createHash, hash } from "node:crypto";
|
|
6
6
|
import { access, glob, readFile, rm } from "node:fs/promises";
|
|
7
7
|
import path, { join, relative, resolve } from "node:path";
|
|
8
8
|
import { ast, collectImportedRefNames, collectUsedSchemaNames, composeMacros, operationDef, schemaDef, transform } from "@kubb/ast";
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { tmpdir } from "node:os";
|
|
9
11
|
import process$1 from "node:process";
|
|
10
12
|
//#region src/createAdapter.ts
|
|
11
13
|
/**
|
|
@@ -149,130 +151,11 @@ function randomCliColor(text) {
|
|
|
149
151
|
return styleText(color, text);
|
|
150
152
|
}
|
|
151
153
|
//#endregion
|
|
152
|
-
//#region package.json
|
|
153
|
-
var version = "5.0.0-beta.107";
|
|
154
|
-
//#endregion
|
|
155
|
-
//#region src/constants.ts
|
|
156
|
-
/**
|
|
157
|
-
* Plugin `include` filter types that select operations directly. When one of these is set
|
|
158
|
-
* without a `schemaName` include, the generate phase pre-scans operations to compute the set
|
|
159
|
-
* of schemas they reach, so unreachable schemas can be pruned for that plugin.
|
|
160
|
-
*/
|
|
161
|
-
const OPERATION_FILTER_TYPES = /* @__PURE__ */ new Set([
|
|
162
|
-
"tag",
|
|
163
|
-
"operationId",
|
|
164
|
-
"path",
|
|
165
|
-
"method",
|
|
166
|
-
"contentType"
|
|
167
|
-
]);
|
|
168
|
-
/**
|
|
169
|
-
* Stable codes Kubb attaches to a `Diagnostic`. Each maps to a known failure mode
|
|
170
|
-
* and stays stable so it can be referenced in tooling and (later) docs. Reference
|
|
171
|
-
* these instead of inlining the string at a throw site.
|
|
172
|
-
*/
|
|
173
|
-
const diagnosticCode = {
|
|
174
|
-
/**
|
|
175
|
-
* Fallback for an unstructured error with no specific code.
|
|
176
|
-
*/
|
|
177
|
-
unknown: "KUBB_UNKNOWN",
|
|
178
|
-
/**
|
|
179
|
-
* The file or URL set as `input` could not be read.
|
|
180
|
-
*/
|
|
181
|
-
inputNotFound: "KUBB_INPUT_NOT_FOUND",
|
|
182
|
-
/**
|
|
183
|
-
* An adapter was configured without an `input`.
|
|
184
|
-
*/
|
|
185
|
-
inputRequired: "KUBB_INPUT_REQUIRED",
|
|
186
|
-
/**
|
|
187
|
-
* `input` uses the v4 `{ path }` / `{ data }` wrapper, which v5 reads as a parsed
|
|
188
|
-
* document instead of a pointer to one.
|
|
189
|
-
*/
|
|
190
|
-
legacyInput: "KUBB_LEGACY_INPUT",
|
|
191
|
-
/**
|
|
192
|
-
* The parsed `input` carries no `openapi` or `swagger` version, so it is not a
|
|
193
|
-
* document the adapter can read.
|
|
194
|
-
*/
|
|
195
|
-
invalidDocument: "KUBB_INVALID_DOCUMENT",
|
|
196
|
-
/**
|
|
197
|
-
* A `$ref` (or equivalent reference) could not be resolved in the source document.
|
|
198
|
-
*/
|
|
199
|
-
refNotFound: "KUBB_REF_NOT_FOUND",
|
|
200
|
-
/**
|
|
201
|
-
* A server variable value is not allowed by its `enum`.
|
|
202
|
-
*/
|
|
203
|
-
invalidServerVariable: "KUBB_INVALID_SERVER_VARIABLE",
|
|
204
|
-
/**
|
|
205
|
-
* A required plugin is missing from the config.
|
|
206
|
-
*/
|
|
207
|
-
pluginNotFound: "KUBB_PLUGIN_NOT_FOUND",
|
|
208
|
-
/**
|
|
209
|
-
* A plugin threw while generating.
|
|
210
|
-
*/
|
|
211
|
-
pluginFailed: "KUBB_PLUGIN_FAILED",
|
|
212
|
-
/**
|
|
213
|
-
* A plugin reported a non-fatal warning through `ctx.warn`.
|
|
214
|
-
*/
|
|
215
|
-
pluginWarning: "KUBB_PLUGIN_WARNING",
|
|
216
|
-
/**
|
|
217
|
-
* A plugin reported an informational message through `ctx.info`.
|
|
218
|
-
*/
|
|
219
|
-
pluginInfo: "KUBB_PLUGIN_INFO",
|
|
220
|
-
/**
|
|
221
|
-
* A schema uses a `format` Kubb does not map to a specific type. Reserved for
|
|
222
|
-
* adapters to emit as a `warning`.
|
|
223
|
-
*/
|
|
224
|
-
unsupportedFormat: "KUBB_UNSUPPORTED_FORMAT",
|
|
225
|
-
/**
|
|
226
|
-
* A referenced schema or operation is marked `deprecated`. Reserved for adapters
|
|
227
|
-
* to emit as an `info`.
|
|
228
|
-
*/
|
|
229
|
-
deprecated: "KUBB_DEPRECATED",
|
|
230
|
-
/**
|
|
231
|
-
* An adapter is required but the config has none. The build cannot read the input
|
|
232
|
-
* without one.
|
|
233
|
-
*/
|
|
234
|
-
adapterRequired: "KUBB_ADAPTER_REQUIRED",
|
|
235
|
-
/**
|
|
236
|
-
* A resolved output path escapes the output directory, which can stem from a path
|
|
237
|
-
* traversal in the spec or a misconfigured `group.name`.
|
|
238
|
-
*/
|
|
239
|
-
pathTraversal: "KUBB_PATH_TRAVERSAL",
|
|
240
|
-
/**
|
|
241
|
-
* `output.clean` is enabled but `output.path` resolves to the project root or a parent of it,
|
|
242
|
-
* so cleaning would delete kubb.config and every source file.
|
|
243
|
-
*/
|
|
244
|
-
cleanRoot: "KUBB_CLEAN_ROOT",
|
|
245
|
-
/**
|
|
246
|
-
* A plugin's options are invalid, for example `output.mode: 'file'` paired with a `group` option.
|
|
247
|
-
*/
|
|
248
|
-
invalidPluginOptions: "KUBB_INVALID_PLUGIN_OPTIONS",
|
|
249
|
-
/**
|
|
250
|
-
* A post-generate command (`output.postGenerate`) exited with a failure.
|
|
251
|
-
*/
|
|
252
|
-
postGenerateFailed: "KUBB_POST_GENERATE_FAILED",
|
|
253
|
-
/**
|
|
254
|
-
* The formatter pass over the generated files failed.
|
|
255
|
-
*/
|
|
256
|
-
formatFailed: "KUBB_FORMAT_FAILED",
|
|
257
|
-
/**
|
|
258
|
-
* The linter pass over the generated files failed.
|
|
259
|
-
*/
|
|
260
|
-
lintFailed: "KUBB_LINT_FAILED",
|
|
261
|
-
/**
|
|
262
|
-
* Not a failure. Carries a plugin's elapsed time, summed into the run total.
|
|
263
|
-
*/
|
|
264
|
-
performance: "KUBB_PERFORMANCE",
|
|
265
|
-
/**
|
|
266
|
-
* Not a failure. A newer Kubb version is available on npm.
|
|
267
|
-
*/
|
|
268
|
-
updateAvailable: "KUBB_UPDATE_AVAILABLE"
|
|
269
|
-
};
|
|
270
|
-
//#endregion
|
|
271
154
|
//#region src/Diagnostics.ts
|
|
272
155
|
/**
|
|
273
156
|
* Docs major version, derived from the package version so the link tracks the published major.
|
|
274
157
|
*/
|
|
275
|
-
const docsMajor =
|
|
158
|
+
const docsMajor = "5.0.0-beta.109".split(".")[0] ?? "5";
|
|
276
159
|
/**
|
|
277
160
|
* Builds a type guard that narrows a {@link Diagnostic} to the variant for `kind`. A diagnostic
|
|
278
161
|
* with no `kind` is treated as a `problem`.
|
|
@@ -332,8 +215,18 @@ const diagnosticCatalog = {
|
|
|
332
215
|
},
|
|
333
216
|
[diagnosticCode.inputNotFound]: {
|
|
334
217
|
title: "Input not found",
|
|
335
|
-
cause: "The file
|
|
336
|
-
fix: "Check that the path
|
|
218
|
+
cause: "The file set as `input` (or passed as `kubb generate PATH`) could not be read. A URL reports `KUBB_INPUT_REQUEST_FAILED` or `KUBB_INPUT_UNREACHABLE` instead.",
|
|
219
|
+
fix: "Check that the path exists and is readable, then set it as `input` or pass it on the CLI."
|
|
220
|
+
},
|
|
221
|
+
[diagnosticCode.inputRequestFailed]: {
|
|
222
|
+
title: "Input request failed",
|
|
223
|
+
cause: "A URL set as `input` (or reached through a `$ref`) answered with a 4xx or 5xx status instead of the document.",
|
|
224
|
+
fix: "Open the URL to see what the server returns. A 401 or 403 needs credentials Kubb does not send, so download the document and point `input` at the local file. A 404 means the path is wrong, and a 5xx means the server itself failed."
|
|
225
|
+
},
|
|
226
|
+
[diagnosticCode.inputUnreachable]: {
|
|
227
|
+
title: "Input unreachable",
|
|
228
|
+
cause: "A URL set as `input` (or reached through a `$ref`) never answered, so the request failed before a status came back. A refused connection, an unknown host, an expired certificate, and a timeout all land here.",
|
|
229
|
+
fix: "Check that the host is running and reachable from this machine. For a local server, start it and confirm the port matches the one in `input`."
|
|
337
230
|
},
|
|
338
231
|
[diagnosticCode.inputRequired]: {
|
|
339
232
|
title: "Input required",
|
|
@@ -1511,22 +1404,25 @@ var KubbDriver = class {
|
|
|
1511
1404
|
async run() {
|
|
1512
1405
|
const { hooks, config, fileManager } = this;
|
|
1513
1406
|
const diagnostics = [];
|
|
1514
|
-
const updateBuffer = [];
|
|
1515
1407
|
const parsersMap = /* @__PURE__ */ new Map();
|
|
1516
1408
|
for (const parser of config.parsers) if (parser.extNames) for (const ext of parser.extNames) parsersMap.set(ext, parser);
|
|
1409
|
+
const updateBuffer = [];
|
|
1517
1410
|
const unhookWrites = fileManager.hooks.addHooks({
|
|
1518
1411
|
start: async (files) => {
|
|
1519
1412
|
await hooks.callHook("kubb:files:processing:start", { files });
|
|
1520
1413
|
},
|
|
1521
|
-
update: (
|
|
1522
|
-
updateBuffer.push(
|
|
1414
|
+
update: ({ file, processed, total, percentage }) => {
|
|
1415
|
+
updateBuffer.push({
|
|
1416
|
+
file,
|
|
1417
|
+
processed,
|
|
1418
|
+
total,
|
|
1419
|
+
percentage,
|
|
1420
|
+
config
|
|
1421
|
+
});
|
|
1523
1422
|
},
|
|
1524
1423
|
end: async (files) => {
|
|
1525
1424
|
updateBuffer.sort((a, b) => a.processed - b.processed);
|
|
1526
|
-
await hooks.callHook("kubb:files:processing:update", { files: updateBuffer
|
|
1527
|
-
...item,
|
|
1528
|
-
config
|
|
1529
|
-
})) });
|
|
1425
|
+
await hooks.callHook("kubb:files:processing:update", { files: updateBuffer });
|
|
1530
1426
|
updateBuffer.length = 0;
|
|
1531
1427
|
await hooks.callHook("kubb:files:processing:end", { files });
|
|
1532
1428
|
}
|
|
@@ -1593,7 +1489,8 @@ var KubbDriver = class {
|
|
|
1593
1489
|
await hooks.callHook("kubb:plugins:end", this.#withFiles({ config }));
|
|
1594
1490
|
await fileManager.write(fileManager.files, {
|
|
1595
1491
|
storage: config.storage,
|
|
1596
|
-
parsers: parsersMap
|
|
1492
|
+
parsers: parsersMap,
|
|
1493
|
+
manifest: this.options.manifest
|
|
1597
1494
|
});
|
|
1598
1495
|
await hooks.callHook("kubb:build:end", {
|
|
1599
1496
|
files: this.fileManager.files,
|
|
@@ -1954,6 +1851,73 @@ var KubbDriver = class {
|
|
|
1954
1851
|
}
|
|
1955
1852
|
};
|
|
1956
1853
|
//#endregion
|
|
1854
|
+
//#region src/outputManifest.ts
|
|
1855
|
+
/**
|
|
1856
|
+
* Bumped when the stored shape changes, so an older cache is discarded instead of misread.
|
|
1857
|
+
*/
|
|
1858
|
+
const VERSION = 1;
|
|
1859
|
+
function hash$1(value) {
|
|
1860
|
+
return createHash("sha256").update(value).digest("hex");
|
|
1861
|
+
}
|
|
1862
|
+
__name(hash$1, "hash");
|
|
1863
|
+
const MANIFEST_KEY = "output-manifest.json";
|
|
1864
|
+
async function loadEntries({ cache }) {
|
|
1865
|
+
try {
|
|
1866
|
+
const stored = await cache.readItem(MANIFEST_KEY);
|
|
1867
|
+
if (stored === null) return {};
|
|
1868
|
+
const data = JSON.parse(stored);
|
|
1869
|
+
if (data.version !== VERSION) return {};
|
|
1870
|
+
if (typeof data.entries !== "object" || data.entries === null || Array.isArray(data.entries)) return {};
|
|
1871
|
+
return data.entries;
|
|
1872
|
+
} catch {
|
|
1873
|
+
return {};
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
/**
|
|
1877
|
+
* Loads the stored manifest, starting empty when it is missing, unreadable, or from an older
|
|
1878
|
+
* version. `storage` holds the generated files, `cache` holds the manifest itself.
|
|
1879
|
+
*
|
|
1880
|
+
* @example
|
|
1881
|
+
* ```ts
|
|
1882
|
+
* const manifest = await createOutputManifest({ storage: config.storage, cache: cacheStorage({ root: config.root }) })
|
|
1883
|
+
* ```
|
|
1884
|
+
*/
|
|
1885
|
+
async function createOutputManifest({ storage, cache }) {
|
|
1886
|
+
const entries = await loadEntries({ cache });
|
|
1887
|
+
const tracked = /* @__PURE__ */ new Map();
|
|
1888
|
+
return {
|
|
1889
|
+
isUpToDate({ key, source, disk }) {
|
|
1890
|
+
const entry = entries[key];
|
|
1891
|
+
if (!entry) return false;
|
|
1892
|
+
return entry.source === hash$1(source) && entry.output === hash$1(disk);
|
|
1893
|
+
},
|
|
1894
|
+
track({ key, source }) {
|
|
1895
|
+
tracked.set(key, hash$1(source));
|
|
1896
|
+
},
|
|
1897
|
+
async commit() {
|
|
1898
|
+
try {
|
|
1899
|
+
const next = { ...entries };
|
|
1900
|
+
await inParallel({
|
|
1901
|
+
items: [...tracked],
|
|
1902
|
+
limit: 50,
|
|
1903
|
+
run: async ([key, source]) => {
|
|
1904
|
+
const stored = await storage.readItem(key);
|
|
1905
|
+
if (stored === null) return;
|
|
1906
|
+
next[key] = {
|
|
1907
|
+
source,
|
|
1908
|
+
output: hash$1(stored)
|
|
1909
|
+
};
|
|
1910
|
+
}
|
|
1911
|
+
});
|
|
1912
|
+
await cache.writeItem(MANIFEST_KEY, JSON.stringify({
|
|
1913
|
+
version: VERSION,
|
|
1914
|
+
entries: next
|
|
1915
|
+
}));
|
|
1916
|
+
} catch {}
|
|
1917
|
+
}
|
|
1918
|
+
};
|
|
1919
|
+
}
|
|
1920
|
+
//#endregion
|
|
1957
1921
|
//#region src/createStorage.ts
|
|
1958
1922
|
/**
|
|
1959
1923
|
* Defines a custom storage backend. The builder receives user options and
|
|
@@ -2030,7 +1994,8 @@ function createLimiter(concurrency) {
|
|
|
2030
1994
|
*
|
|
2031
1995
|
* Writes are deduplicated and directory-safe:
|
|
2032
1996
|
* - leading and trailing whitespace is trimmed before writing
|
|
2033
|
-
* - the write is skipped when the file content
|
|
1997
|
+
* - the write is skipped when the file already holds that content, ignoring any trailing newline
|
|
1998
|
+
* a formatter left behind
|
|
2034
1999
|
* - missing parent directories are created automatically
|
|
2035
2000
|
* - Bun's native file API is used when running under Bun
|
|
2036
2001
|
* - concurrent `writeItem` calls are capped at {@link WRITE_CONCURRENCY} in flight, so a caller
|
|
@@ -2091,6 +2056,60 @@ const fsStorage = createStorage(() => {
|
|
|
2091
2056
|
};
|
|
2092
2057
|
});
|
|
2093
2058
|
//#endregion
|
|
2059
|
+
//#region src/storages/cacheStorage.ts
|
|
2060
|
+
/**
|
|
2061
|
+
* Directory Kubb keeps build caches in. A project with a `node_modules` gets
|
|
2062
|
+
* `node_modules/.cache/kubb`, the convention babel and eslint already use, so the cache stays out
|
|
2063
|
+
* of version control. Without one it falls back to the OS temp directory, keyed by root so two
|
|
2064
|
+
* projects sharing that directory keep their own cache.
|
|
2065
|
+
*
|
|
2066
|
+
* @example Inside a project
|
|
2067
|
+
* `resolveCacheDir('/project') // '/project/node_modules/.cache/kubb'`
|
|
2068
|
+
*/
|
|
2069
|
+
function resolveCacheDir(root) {
|
|
2070
|
+
const nodeModules = join(root, "node_modules");
|
|
2071
|
+
if (existsSync(nodeModules)) return join(nodeModules, ".cache", "kubb");
|
|
2072
|
+
return join(tmpdir(), "kubb", createHash("sha256").update(root).digest("hex").slice(0, 16));
|
|
2073
|
+
}
|
|
2074
|
+
/**
|
|
2075
|
+
* Filesystem storage for build caches rather than generated code. Keys are plain names resolved
|
|
2076
|
+
* inside {@link resolveCacheDir}, so a caller stores `'x.json'` without knowing where the cache
|
|
2077
|
+
* lives. Kept apart from the configured output storage, which may not be a local disk at all.
|
|
2078
|
+
*
|
|
2079
|
+
* @example
|
|
2080
|
+
* ```ts
|
|
2081
|
+
* const cache = cacheStorage({ root: config.root })
|
|
2082
|
+
* await cache.writeItem('output-manifest.json', JSON.stringify(entries))
|
|
2083
|
+
* ```
|
|
2084
|
+
*/
|
|
2085
|
+
const cacheStorage = createStorage(({ root = process.cwd() }) => {
|
|
2086
|
+
const dir = resolveCacheDir(root);
|
|
2087
|
+
const storage = fsStorage();
|
|
2088
|
+
const toPath = (key) => join(dir, key);
|
|
2089
|
+
return {
|
|
2090
|
+
name: "cache",
|
|
2091
|
+
async existsItem(key) {
|
|
2092
|
+
return storage.existsItem(toPath(key));
|
|
2093
|
+
},
|
|
2094
|
+
async readItem(key) {
|
|
2095
|
+
return storage.readItem(toPath(key));
|
|
2096
|
+
},
|
|
2097
|
+
async writeItem(key, value) {
|
|
2098
|
+
return storage.writeItem(toPath(key), value);
|
|
2099
|
+
},
|
|
2100
|
+
async removeItem(key) {
|
|
2101
|
+
return storage.removeItem(toPath(key));
|
|
2102
|
+
},
|
|
2103
|
+
async readKeys(base) {
|
|
2104
|
+
return storage.readKeys(base ? toPath(base) : dir);
|
|
2105
|
+
},
|
|
2106
|
+
async empty(base) {
|
|
2107
|
+
if (!base) return;
|
|
2108
|
+
return storage.empty(toPath(base));
|
|
2109
|
+
}
|
|
2110
|
+
};
|
|
2111
|
+
});
|
|
2112
|
+
//#endregion
|
|
2094
2113
|
//#region src/createKubb.ts
|
|
2095
2114
|
function resolveConfig(userConfig) {
|
|
2096
2115
|
return {
|
|
@@ -2109,6 +2128,13 @@ function resolveConfig(userConfig) {
|
|
|
2109
2128
|
};
|
|
2110
2129
|
}
|
|
2111
2130
|
/**
|
|
2131
|
+
* Whether anything runs over the output directory after the files are written. Only then can the
|
|
2132
|
+
* bytes on disk stop matching what Kubb wrote, which is what the manifest exists to track.
|
|
2133
|
+
*/
|
|
2134
|
+
function hasOutputPasses(output) {
|
|
2135
|
+
return Boolean(output.format || output.lint || output.postGenerate?.length);
|
|
2136
|
+
}
|
|
2137
|
+
/**
|
|
2112
2138
|
* Kubb code-generation instance bound to a single config entry. Resolves the user
|
|
2113
2139
|
* config in the constructor, so `config` is available right away, and shares `hooks`,
|
|
2114
2140
|
* `storage`, and `driver` across the `setup → build` lifecycle.
|
|
@@ -2130,6 +2156,7 @@ var Kubb = class {
|
|
|
2130
2156
|
config;
|
|
2131
2157
|
#driver = null;
|
|
2132
2158
|
#storage = null;
|
|
2159
|
+
#manifest = null;
|
|
2133
2160
|
constructor(userConfig, options = {}) {
|
|
2134
2161
|
this.config = resolveConfig(userConfig);
|
|
2135
2162
|
this.hooks = options.hooks ?? new Hookable();
|
|
@@ -2147,7 +2174,14 @@ var Kubb = class {
|
|
|
2147
2174
|
*/
|
|
2148
2175
|
async setup() {
|
|
2149
2176
|
const config = this.config;
|
|
2150
|
-
const
|
|
2177
|
+
const manifest = hasOutputPasses(config.output) ? await createOutputManifest({
|
|
2178
|
+
storage: config.storage,
|
|
2179
|
+
cache: cacheStorage({ root: config.root })
|
|
2180
|
+
}) : void 0;
|
|
2181
|
+
const driver = new KubbDriver(config, {
|
|
2182
|
+
hooks: this.hooks,
|
|
2183
|
+
manifest
|
|
2184
|
+
});
|
|
2151
2185
|
this.hooks.setMaxListeners(Math.max(10, config.plugins.length * 4));
|
|
2152
2186
|
if (config.output.clean) {
|
|
2153
2187
|
const cleanPath = resolve(config.root, config.output.path);
|
|
@@ -2163,6 +2197,7 @@ var Kubb = class {
|
|
|
2163
2197
|
await driver.setup();
|
|
2164
2198
|
this.#driver = driver;
|
|
2165
2199
|
this.#storage = config.storage;
|
|
2200
|
+
this.#manifest = manifest ?? null;
|
|
2166
2201
|
}
|
|
2167
2202
|
/**
|
|
2168
2203
|
* Runs the full pipeline and throws on any plugin error.
|
|
@@ -2250,6 +2285,7 @@ var Kubb = class {
|
|
|
2250
2285
|
}) : [];
|
|
2251
2286
|
const finalDiagnostics = [...diagnostics, ...outputDiagnostics];
|
|
2252
2287
|
const failed = Diagnostics.hasError(outputDiagnostics);
|
|
2288
|
+
if (!failed) await this.#manifest?.commit();
|
|
2253
2289
|
await hooks.callHook("kubb:generation:end", {
|
|
2254
2290
|
config,
|
|
2255
2291
|
storage,
|