@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.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_usingCtx = require("./usingCtx-
|
|
2
|
+
const require_usingCtx = require("./usingCtx-BdYw7ICK.cjs");
|
|
3
3
|
let node_async_hooks = require("node:async_hooks");
|
|
4
4
|
let node_util = require("node:util");
|
|
5
5
|
let node_crypto = require("node:crypto");
|
|
@@ -7,6 +7,8 @@ let node_fs_promises = require("node:fs/promises");
|
|
|
7
7
|
let node_path = require("node:path");
|
|
8
8
|
node_path = require_usingCtx.__toESM(node_path, 1);
|
|
9
9
|
let _kubb_ast = require("@kubb/ast");
|
|
10
|
+
let node_fs = require("node:fs");
|
|
11
|
+
let node_os = require("node:os");
|
|
10
12
|
let node_process = require("node:process");
|
|
11
13
|
node_process = require_usingCtx.__toESM(node_process, 1);
|
|
12
14
|
//#region src/createAdapter.ts
|
|
@@ -151,130 +153,11 @@ function randomCliColor(text) {
|
|
|
151
153
|
return (0, node_util.styleText)(color, text);
|
|
152
154
|
}
|
|
153
155
|
//#endregion
|
|
154
|
-
//#region package.json
|
|
155
|
-
var version = "5.0.0-beta.107";
|
|
156
|
-
//#endregion
|
|
157
|
-
//#region src/constants.ts
|
|
158
|
-
/**
|
|
159
|
-
* Plugin `include` filter types that select operations directly. When one of these is set
|
|
160
|
-
* without a `schemaName` include, the generate phase pre-scans operations to compute the set
|
|
161
|
-
* of schemas they reach, so unreachable schemas can be pruned for that plugin.
|
|
162
|
-
*/
|
|
163
|
-
const OPERATION_FILTER_TYPES = /* @__PURE__ */ new Set([
|
|
164
|
-
"tag",
|
|
165
|
-
"operationId",
|
|
166
|
-
"path",
|
|
167
|
-
"method",
|
|
168
|
-
"contentType"
|
|
169
|
-
]);
|
|
170
|
-
/**
|
|
171
|
-
* Stable codes Kubb attaches to a `Diagnostic`. Each maps to a known failure mode
|
|
172
|
-
* and stays stable so it can be referenced in tooling and (later) docs. Reference
|
|
173
|
-
* these instead of inlining the string at a throw site.
|
|
174
|
-
*/
|
|
175
|
-
const diagnosticCode = {
|
|
176
|
-
/**
|
|
177
|
-
* Fallback for an unstructured error with no specific code.
|
|
178
|
-
*/
|
|
179
|
-
unknown: "KUBB_UNKNOWN",
|
|
180
|
-
/**
|
|
181
|
-
* The file or URL set as `input` could not be read.
|
|
182
|
-
*/
|
|
183
|
-
inputNotFound: "KUBB_INPUT_NOT_FOUND",
|
|
184
|
-
/**
|
|
185
|
-
* An adapter was configured without an `input`.
|
|
186
|
-
*/
|
|
187
|
-
inputRequired: "KUBB_INPUT_REQUIRED",
|
|
188
|
-
/**
|
|
189
|
-
* `input` uses the v4 `{ path }` / `{ data }` wrapper, which v5 reads as a parsed
|
|
190
|
-
* document instead of a pointer to one.
|
|
191
|
-
*/
|
|
192
|
-
legacyInput: "KUBB_LEGACY_INPUT",
|
|
193
|
-
/**
|
|
194
|
-
* The parsed `input` carries no `openapi` or `swagger` version, so it is not a
|
|
195
|
-
* document the adapter can read.
|
|
196
|
-
*/
|
|
197
|
-
invalidDocument: "KUBB_INVALID_DOCUMENT",
|
|
198
|
-
/**
|
|
199
|
-
* A `$ref` (or equivalent reference) could not be resolved in the source document.
|
|
200
|
-
*/
|
|
201
|
-
refNotFound: "KUBB_REF_NOT_FOUND",
|
|
202
|
-
/**
|
|
203
|
-
* A server variable value is not allowed by its `enum`.
|
|
204
|
-
*/
|
|
205
|
-
invalidServerVariable: "KUBB_INVALID_SERVER_VARIABLE",
|
|
206
|
-
/**
|
|
207
|
-
* A required plugin is missing from the config.
|
|
208
|
-
*/
|
|
209
|
-
pluginNotFound: "KUBB_PLUGIN_NOT_FOUND",
|
|
210
|
-
/**
|
|
211
|
-
* A plugin threw while generating.
|
|
212
|
-
*/
|
|
213
|
-
pluginFailed: "KUBB_PLUGIN_FAILED",
|
|
214
|
-
/**
|
|
215
|
-
* A plugin reported a non-fatal warning through `ctx.warn`.
|
|
216
|
-
*/
|
|
217
|
-
pluginWarning: "KUBB_PLUGIN_WARNING",
|
|
218
|
-
/**
|
|
219
|
-
* A plugin reported an informational message through `ctx.info`.
|
|
220
|
-
*/
|
|
221
|
-
pluginInfo: "KUBB_PLUGIN_INFO",
|
|
222
|
-
/**
|
|
223
|
-
* A schema uses a `format` Kubb does not map to a specific type. Reserved for
|
|
224
|
-
* adapters to emit as a `warning`.
|
|
225
|
-
*/
|
|
226
|
-
unsupportedFormat: "KUBB_UNSUPPORTED_FORMAT",
|
|
227
|
-
/**
|
|
228
|
-
* A referenced schema or operation is marked `deprecated`. Reserved for adapters
|
|
229
|
-
* to emit as an `info`.
|
|
230
|
-
*/
|
|
231
|
-
deprecated: "KUBB_DEPRECATED",
|
|
232
|
-
/**
|
|
233
|
-
* An adapter is required but the config has none. The build cannot read the input
|
|
234
|
-
* without one.
|
|
235
|
-
*/
|
|
236
|
-
adapterRequired: "KUBB_ADAPTER_REQUIRED",
|
|
237
|
-
/**
|
|
238
|
-
* A resolved output path escapes the output directory, which can stem from a path
|
|
239
|
-
* traversal in the spec or a misconfigured `group.name`.
|
|
240
|
-
*/
|
|
241
|
-
pathTraversal: "KUBB_PATH_TRAVERSAL",
|
|
242
|
-
/**
|
|
243
|
-
* `output.clean` is enabled but `output.path` resolves to the project root or a parent of it,
|
|
244
|
-
* so cleaning would delete kubb.config and every source file.
|
|
245
|
-
*/
|
|
246
|
-
cleanRoot: "KUBB_CLEAN_ROOT",
|
|
247
|
-
/**
|
|
248
|
-
* A plugin's options are invalid, for example `output.mode: 'file'` paired with a `group` option.
|
|
249
|
-
*/
|
|
250
|
-
invalidPluginOptions: "KUBB_INVALID_PLUGIN_OPTIONS",
|
|
251
|
-
/**
|
|
252
|
-
* A post-generate command (`output.postGenerate`) exited with a failure.
|
|
253
|
-
*/
|
|
254
|
-
postGenerateFailed: "KUBB_POST_GENERATE_FAILED",
|
|
255
|
-
/**
|
|
256
|
-
* The formatter pass over the generated files failed.
|
|
257
|
-
*/
|
|
258
|
-
formatFailed: "KUBB_FORMAT_FAILED",
|
|
259
|
-
/**
|
|
260
|
-
* The linter pass over the generated files failed.
|
|
261
|
-
*/
|
|
262
|
-
lintFailed: "KUBB_LINT_FAILED",
|
|
263
|
-
/**
|
|
264
|
-
* Not a failure. Carries a plugin's elapsed time, summed into the run total.
|
|
265
|
-
*/
|
|
266
|
-
performance: "KUBB_PERFORMANCE",
|
|
267
|
-
/**
|
|
268
|
-
* Not a failure. A newer Kubb version is available on npm.
|
|
269
|
-
*/
|
|
270
|
-
updateAvailable: "KUBB_UPDATE_AVAILABLE"
|
|
271
|
-
};
|
|
272
|
-
//#endregion
|
|
273
156
|
//#region src/Diagnostics.ts
|
|
274
157
|
/**
|
|
275
158
|
* Docs major version, derived from the package version so the link tracks the published major.
|
|
276
159
|
*/
|
|
277
|
-
const docsMajor =
|
|
160
|
+
const docsMajor = "5.0.0-beta.109".split(".")[0] ?? "5";
|
|
278
161
|
/**
|
|
279
162
|
* Builds a type guard that narrows a {@link Diagnostic} to the variant for `kind`. A diagnostic
|
|
280
163
|
* with no `kind` is treated as a `problem`.
|
|
@@ -327,112 +210,122 @@ const severityStyle = {
|
|
|
327
210
|
* and `Diagnostics.docsUrl` for the matching kubb.dev page.
|
|
328
211
|
*/
|
|
329
212
|
const diagnosticCatalog = {
|
|
330
|
-
[diagnosticCode.unknown]: {
|
|
213
|
+
[require_usingCtx.diagnosticCode.unknown]: {
|
|
331
214
|
title: "Unknown error",
|
|
332
215
|
cause: "An error was thrown without a stable Kubb code, so it is reported as-is.",
|
|
333
216
|
fix: "Read the underlying message and stack. If it comes from a plugin or adapter, check its configuration; otherwise report it as a possible Kubb bug."
|
|
334
217
|
},
|
|
335
|
-
[diagnosticCode.inputNotFound]: {
|
|
218
|
+
[require_usingCtx.diagnosticCode.inputNotFound]: {
|
|
336
219
|
title: "Input not found",
|
|
337
|
-
cause: "The file
|
|
338
|
-
fix: "Check that the path
|
|
220
|
+
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.",
|
|
221
|
+
fix: "Check that the path exists and is readable, then set it as `input` or pass it on the CLI."
|
|
222
|
+
},
|
|
223
|
+
[require_usingCtx.diagnosticCode.inputRequestFailed]: {
|
|
224
|
+
title: "Input request failed",
|
|
225
|
+
cause: "A URL set as `input` (or reached through a `$ref`) answered with a 4xx or 5xx status instead of the document.",
|
|
226
|
+
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."
|
|
227
|
+
},
|
|
228
|
+
[require_usingCtx.diagnosticCode.inputUnreachable]: {
|
|
229
|
+
title: "Input unreachable",
|
|
230
|
+
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.",
|
|
231
|
+
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`."
|
|
339
232
|
},
|
|
340
|
-
[diagnosticCode.inputRequired]: {
|
|
233
|
+
[require_usingCtx.diagnosticCode.inputRequired]: {
|
|
341
234
|
title: "Input required",
|
|
342
235
|
cause: "An adapter is configured but no `input` was provided.",
|
|
343
236
|
fix: "Set `input` to a file path, a URL, an inline spec (JSON/YAML string), or a parsed object in your Kubb config."
|
|
344
237
|
},
|
|
345
|
-
[diagnosticCode.legacyInput]: {
|
|
238
|
+
[require_usingCtx.diagnosticCode.legacyInput]: {
|
|
346
239
|
title: "Legacy input shape",
|
|
347
240
|
cause: "`input` is a `{ path }` or `{ data }` wrapper, which v4 used to point at a document and v5 reads as the document itself.",
|
|
348
241
|
fix: "Unwrap it: `input: { path: \"./petStore.yaml\" }` becomes `input: \"./petStore.yaml\"`, and `input: { data: spec }` becomes `input: spec`."
|
|
349
242
|
},
|
|
350
|
-
[diagnosticCode.invalidDocument]: {
|
|
243
|
+
[require_usingCtx.diagnosticCode.invalidDocument]: {
|
|
351
244
|
title: "Invalid document",
|
|
352
245
|
cause: "The parsed `input` has no `openapi` or `swagger` version field, so it is not an OpenAPI or Swagger document.",
|
|
353
246
|
fix: "Point `input` at a document that declares `openapi` or `swagger`, and check that a passed object is the spec itself rather than a wrapper around it."
|
|
354
247
|
},
|
|
355
|
-
[diagnosticCode.refNotFound]: {
|
|
248
|
+
[require_usingCtx.diagnosticCode.refNotFound]: {
|
|
356
249
|
title: "Reference not found",
|
|
357
250
|
cause: "A `$ref` could not be resolved in the source document.",
|
|
358
251
|
fix: "Add the missing definition (for example under `components.schemas`) or fix the `$ref`. Run `kubb validate` to check the spec."
|
|
359
252
|
},
|
|
360
|
-
[diagnosticCode.invalidServerVariable]: {
|
|
253
|
+
[require_usingCtx.diagnosticCode.invalidServerVariable]: {
|
|
361
254
|
title: "Invalid server variable",
|
|
362
255
|
cause: "A server variable value is not allowed by its `enum`.",
|
|
363
256
|
fix: "Use one of the values listed in the server variable `enum`, or update the spec."
|
|
364
257
|
},
|
|
365
|
-
[diagnosticCode.pluginNotFound]: {
|
|
258
|
+
[require_usingCtx.diagnosticCode.pluginNotFound]: {
|
|
366
259
|
title: "Plugin not found",
|
|
367
260
|
cause: "A plugin that another plugin depends on is missing from the config.",
|
|
368
261
|
fix: "Add the required plugin to the `plugins` array in kubb.config.ts, or remove the dependency on it."
|
|
369
262
|
},
|
|
370
|
-
[diagnosticCode.pluginFailed]: {
|
|
263
|
+
[require_usingCtx.diagnosticCode.pluginFailed]: {
|
|
371
264
|
title: "Plugin failed",
|
|
372
265
|
cause: "A plugin threw while generating, or reported an error through `ctx.error`.",
|
|
373
266
|
fix: "Read the underlying error and check the plugin options and the schema or operation it failed on."
|
|
374
267
|
},
|
|
375
|
-
[diagnosticCode.pluginWarning]: {
|
|
268
|
+
[require_usingCtx.diagnosticCode.pluginWarning]: {
|
|
376
269
|
title: "Plugin warning",
|
|
377
270
|
cause: "A plugin reported a non-fatal warning through `ctx.warn`.",
|
|
378
271
|
fix: "Review the message. It does not fail the build; adjust the plugin options or input if the warning is unwanted."
|
|
379
272
|
},
|
|
380
|
-
[diagnosticCode.pluginInfo]: {
|
|
273
|
+
[require_usingCtx.diagnosticCode.pluginInfo]: {
|
|
381
274
|
title: "Plugin info",
|
|
382
275
|
cause: "A plugin reported an informational message through `ctx.info`.",
|
|
383
276
|
fix: "Informational only. No action is required."
|
|
384
277
|
},
|
|
385
|
-
[diagnosticCode.unsupportedFormat]: {
|
|
278
|
+
[require_usingCtx.diagnosticCode.unsupportedFormat]: {
|
|
386
279
|
title: "Unsupported format",
|
|
387
280
|
cause: "A schema uses a `format` Kubb does not map to a specific type, so it falls back to the base type.",
|
|
388
281
|
fix: "Use a format Kubb supports, or handle the custom format with a parser or plugin."
|
|
389
282
|
},
|
|
390
|
-
[diagnosticCode.deprecated]: {
|
|
283
|
+
[require_usingCtx.diagnosticCode.deprecated]: {
|
|
391
284
|
title: "Deprecated",
|
|
392
285
|
cause: "A referenced schema or operation is marked `deprecated`.",
|
|
393
286
|
fix: "Migrate off the deprecated definition if the warning is unwanted."
|
|
394
287
|
},
|
|
395
|
-
[diagnosticCode.adapterRequired]: {
|
|
288
|
+
[require_usingCtx.diagnosticCode.adapterRequired]: {
|
|
396
289
|
title: "Adapter required",
|
|
397
290
|
cause: "An action needs an adapter but none is configured.",
|
|
398
291
|
fix: "Set `adapter` in kubb.config.ts, for example `adapterOas()`."
|
|
399
292
|
},
|
|
400
|
-
[diagnosticCode.pathTraversal]: {
|
|
293
|
+
[require_usingCtx.diagnosticCode.pathTraversal]: {
|
|
401
294
|
title: "Path traversal",
|
|
402
295
|
cause: "A resolved output path escaped the output directory, which can stem from a path traversal in the spec or a misconfigured `group.name`.",
|
|
403
296
|
fix: "Keep generated paths within the output directory. Review the `group.name` function and the names coming from the spec."
|
|
404
297
|
},
|
|
405
|
-
[diagnosticCode.cleanRoot]: {
|
|
298
|
+
[require_usingCtx.diagnosticCode.cleanRoot]: {
|
|
406
299
|
title: "Clean targets the project root",
|
|
407
300
|
cause: "`output.clean` is enabled and `output.path` resolves to the project root or a parent of it, so cleaning would delete `kubb.config` and every source file.",
|
|
408
301
|
fix: "Point `output.path` at a subdirectory such as `./src/gen` so clean only removes generated code, or disable `output.clean`."
|
|
409
302
|
},
|
|
410
|
-
[diagnosticCode.invalidPluginOptions]: {
|
|
303
|
+
[require_usingCtx.diagnosticCode.invalidPluginOptions]: {
|
|
411
304
|
title: "Invalid plugin options",
|
|
412
305
|
cause: "A plugin was configured with options that cannot be honored, for example `output.mode: 'file'` paired with a `group` option.",
|
|
413
306
|
fix: "Fix the plugin options. A single-file output has nothing to group, so remove the `group` option or use `output.mode: 'directory'`."
|
|
414
307
|
},
|
|
415
|
-
[diagnosticCode.postGenerateFailed]: {
|
|
308
|
+
[require_usingCtx.diagnosticCode.postGenerateFailed]: {
|
|
416
309
|
title: "Post-generate command failed",
|
|
417
310
|
cause: "A post-generate command (`output.postGenerate`) exited with a non-zero status.",
|
|
418
311
|
fix: "Check the command is installed and correct, and run it manually to see the error."
|
|
419
312
|
},
|
|
420
|
-
[diagnosticCode.formatFailed]: {
|
|
313
|
+
[require_usingCtx.diagnosticCode.formatFailed]: {
|
|
421
314
|
title: "Format failed",
|
|
422
315
|
cause: "The formatter pass over the generated files failed.",
|
|
423
316
|
fix: "Check the formatter (oxfmt, biome, or prettier) is installed and its config is valid, then run it manually on the output."
|
|
424
317
|
},
|
|
425
|
-
[diagnosticCode.lintFailed]: {
|
|
318
|
+
[require_usingCtx.diagnosticCode.lintFailed]: {
|
|
426
319
|
title: "Lint failed",
|
|
427
320
|
cause: "The linter pass over the generated files failed.",
|
|
428
321
|
fix: "Check the linter (oxlint, biome, or eslint) is installed and its config is valid, then run it manually on the output."
|
|
429
322
|
},
|
|
430
|
-
[diagnosticCode.performance]: {
|
|
323
|
+
[require_usingCtx.diagnosticCode.performance]: {
|
|
431
324
|
title: "Performance",
|
|
432
325
|
cause: "Not a failure. Records a plugin’s elapsed time, summed into the run total.",
|
|
433
326
|
fix: "No action. This is an informational metric."
|
|
434
327
|
},
|
|
435
|
-
[diagnosticCode.updateAvailable]: {
|
|
328
|
+
[require_usingCtx.diagnosticCode.updateAvailable]: {
|
|
436
329
|
title: "Update available",
|
|
437
330
|
cause: "A newer Kubb version is published on npm than the one running.",
|
|
438
331
|
fix: "Update the `@kubb/*` packages, for example `npm install -g @kubb/cli`, to get the latest fixes."
|
|
@@ -452,7 +345,7 @@ var Diagnostics = class Diagnostics {
|
|
|
452
345
|
/**
|
|
453
346
|
* The diagnostic code catalog, exposed as `Diagnostics.code` (e.g. `Diagnostics.code.refNotFound`).
|
|
454
347
|
*/
|
|
455
|
-
static code = diagnosticCode;
|
|
348
|
+
static code = require_usingCtx.diagnosticCode;
|
|
456
349
|
/**
|
|
457
350
|
* Type guard for a build {@link ProblemDiagnostic}.
|
|
458
351
|
*/
|
|
@@ -533,7 +426,7 @@ var Diagnostics = class Diagnostics {
|
|
|
533
426
|
current = current.cause;
|
|
534
427
|
}
|
|
535
428
|
return {
|
|
536
|
-
code: diagnosticCode.unknown,
|
|
429
|
+
code: require_usingCtx.diagnosticCode.unknown,
|
|
537
430
|
severity: "error",
|
|
538
431
|
message: root ? root.message : require_usingCtx.getErrorMessage(error),
|
|
539
432
|
cause: root
|
|
@@ -545,7 +438,7 @@ var Diagnostics = class Diagnostics {
|
|
|
545
438
|
static performance({ plugin, duration }) {
|
|
546
439
|
return {
|
|
547
440
|
kind: "performance",
|
|
548
|
-
code: diagnosticCode.performance,
|
|
441
|
+
code: require_usingCtx.diagnosticCode.performance,
|
|
549
442
|
severity: "info",
|
|
550
443
|
message: `${plugin} generated in ${Math.round(duration)}ms`,
|
|
551
444
|
plugin,
|
|
@@ -558,7 +451,7 @@ var Diagnostics = class Diagnostics {
|
|
|
558
451
|
static update({ currentVersion, latestVersion }) {
|
|
559
452
|
return {
|
|
560
453
|
kind: "update",
|
|
561
|
-
code: diagnosticCode.updateAvailable,
|
|
454
|
+
code: require_usingCtx.diagnosticCode.updateAvailable,
|
|
562
455
|
severity: "info",
|
|
563
456
|
message: `Update available: v${currentVersion} → v${latestVersion}. Run \`npm install -g @kubb/cli\` to update.`,
|
|
564
457
|
currentVersion,
|
|
@@ -651,7 +544,7 @@ var Diagnostics = class Diagnostics {
|
|
|
651
544
|
...problem?.location ? { location: problem.location } : {},
|
|
652
545
|
...problem?.help ? { help: problem.help } : {},
|
|
653
546
|
...problem?.plugin ? { plugin: problem.plugin } : {},
|
|
654
|
-
...diagnostic.code === diagnosticCode.unknown ? {} : { docsUrl: Diagnostics.docsUrl(diagnostic.code) }
|
|
547
|
+
...diagnostic.code === require_usingCtx.diagnosticCode.unknown ? {} : { docsUrl: Diagnostics.docsUrl(diagnostic.code) }
|
|
655
548
|
};
|
|
656
549
|
}
|
|
657
550
|
/**
|
|
@@ -671,7 +564,7 @@ var Diagnostics = class Diagnostics {
|
|
|
671
564
|
const details = [];
|
|
672
565
|
if (problem?.location && "pointer" in problem.location) details.push(` ${(0, node_util.styleText)("dim", "at:")} ${(0, node_util.styleText)("cyan", problem.location.pointer)}`);
|
|
673
566
|
if (problem?.help) details.push(` ${(0, node_util.styleText)("cyan", "fix:")} ${problem.help}`);
|
|
674
|
-
if (code !== diagnosticCode.unknown) details.push(` ${(0, node_util.styleText)("dim", "see:")} ${(0, node_util.styleText)("cyan", Diagnostics.docsUrl(code))}`);
|
|
567
|
+
if (code !== require_usingCtx.diagnosticCode.unknown) details.push(` ${(0, node_util.styleText)("dim", "see:")} ${(0, node_util.styleText)("cyan", Diagnostics.docsUrl(code))}`);
|
|
675
568
|
return {
|
|
676
569
|
headline,
|
|
677
570
|
details
|
|
@@ -696,7 +589,7 @@ var Diagnostics = class Diagnostics {
|
|
|
696
589
|
function normalizeOutput({ output, group, pluginName }) {
|
|
697
590
|
const mode = output.mode ?? "file";
|
|
698
591
|
if (mode === "file" && group) throw new Diagnostics.Error({
|
|
699
|
-
code: diagnosticCode.invalidPluginOptions,
|
|
592
|
+
code: require_usingCtx.diagnosticCode.invalidPluginOptions,
|
|
700
593
|
severity: "error",
|
|
701
594
|
message: `Plugin "${pluginName}" sets \`output.mode: 'file'\` but also configures a \`group\` option.`,
|
|
702
595
|
help: "A single-file output has nothing to group. Remove the `group` option, or use `output.mode: 'directory'` to organize files into subdirectories.",
|
|
@@ -1513,22 +1406,25 @@ var KubbDriver = class {
|
|
|
1513
1406
|
async run() {
|
|
1514
1407
|
const { hooks, config, fileManager } = this;
|
|
1515
1408
|
const diagnostics = [];
|
|
1516
|
-
const updateBuffer = [];
|
|
1517
1409
|
const parsersMap = /* @__PURE__ */ new Map();
|
|
1518
1410
|
for (const parser of config.parsers) if (parser.extNames) for (const ext of parser.extNames) parsersMap.set(ext, parser);
|
|
1411
|
+
const updateBuffer = [];
|
|
1519
1412
|
const unhookWrites = fileManager.hooks.addHooks({
|
|
1520
1413
|
start: async (files) => {
|
|
1521
1414
|
await hooks.callHook("kubb:files:processing:start", { files });
|
|
1522
1415
|
},
|
|
1523
|
-
update: (
|
|
1524
|
-
updateBuffer.push(
|
|
1416
|
+
update: ({ file, processed, total, percentage }) => {
|
|
1417
|
+
updateBuffer.push({
|
|
1418
|
+
file,
|
|
1419
|
+
processed,
|
|
1420
|
+
total,
|
|
1421
|
+
percentage,
|
|
1422
|
+
config
|
|
1423
|
+
});
|
|
1525
1424
|
},
|
|
1526
1425
|
end: async (files) => {
|
|
1527
1426
|
updateBuffer.sort((a, b) => a.processed - b.processed);
|
|
1528
|
-
await hooks.callHook("kubb:files:processing:update", { files: updateBuffer
|
|
1529
|
-
...item,
|
|
1530
|
-
config
|
|
1531
|
-
})) });
|
|
1427
|
+
await hooks.callHook("kubb:files:processing:update", { files: updateBuffer });
|
|
1532
1428
|
updateBuffer.length = 0;
|
|
1533
1429
|
await hooks.callHook("kubb:files:processing:end", { files });
|
|
1534
1430
|
}
|
|
@@ -1595,7 +1491,8 @@ var KubbDriver = class {
|
|
|
1595
1491
|
await hooks.callHook("kubb:plugins:end", this.#withFiles({ config }));
|
|
1596
1492
|
await fileManager.write(fileManager.files, {
|
|
1597
1493
|
storage: config.storage,
|
|
1598
|
-
parsers: parsersMap
|
|
1494
|
+
parsers: parsersMap,
|
|
1495
|
+
manifest: this.options.manifest
|
|
1599
1496
|
});
|
|
1600
1497
|
await hooks.callHook("kubb:build:end", {
|
|
1601
1498
|
files: this.fileManager.files,
|
|
@@ -1674,7 +1571,7 @@ var KubbDriver = class {
|
|
|
1674
1571
|
const allowedSchemaNamesByPlugin = /* @__PURE__ */ new Map();
|
|
1675
1572
|
for (const { plugin } of entries) {
|
|
1676
1573
|
const { exclude, include, override } = plugin.options;
|
|
1677
|
-
if (!((include?.some(({ type }) => OPERATION_FILTER_TYPES.has(type)) ?? false) && !(include?.some(({ type }) => type === "schemaName") ?? false))) continue;
|
|
1574
|
+
if (!((include?.some(({ type }) => require_usingCtx.OPERATION_FILTER_TYPES.has(type)) ?? false) && !(include?.some(({ type }) => type === "schemaName") ?? false))) continue;
|
|
1678
1575
|
const resolver = this.getResolver(plugin.name);
|
|
1679
1576
|
const includedOps = operations.filter((operation) => resolver.default.options(operation, {
|
|
1680
1577
|
options: plugin.options,
|
|
@@ -1956,6 +1853,72 @@ var KubbDriver = class {
|
|
|
1956
1853
|
}
|
|
1957
1854
|
};
|
|
1958
1855
|
//#endregion
|
|
1856
|
+
//#region src/outputManifest.ts
|
|
1857
|
+
/**
|
|
1858
|
+
* Bumped when the stored shape changes, so an older cache is discarded instead of misread.
|
|
1859
|
+
*/
|
|
1860
|
+
const VERSION = 1;
|
|
1861
|
+
function hash(value) {
|
|
1862
|
+
return (0, node_crypto.createHash)("sha256").update(value).digest("hex");
|
|
1863
|
+
}
|
|
1864
|
+
const MANIFEST_KEY = "output-manifest.json";
|
|
1865
|
+
async function loadEntries({ cache }) {
|
|
1866
|
+
try {
|
|
1867
|
+
const stored = await cache.readItem(MANIFEST_KEY);
|
|
1868
|
+
if (stored === null) return {};
|
|
1869
|
+
const data = JSON.parse(stored);
|
|
1870
|
+
if (data.version !== VERSION) return {};
|
|
1871
|
+
if (typeof data.entries !== "object" || data.entries === null || Array.isArray(data.entries)) return {};
|
|
1872
|
+
return data.entries;
|
|
1873
|
+
} catch {
|
|
1874
|
+
return {};
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
/**
|
|
1878
|
+
* Loads the stored manifest, starting empty when it is missing, unreadable, or from an older
|
|
1879
|
+
* version. `storage` holds the generated files, `cache` holds the manifest itself.
|
|
1880
|
+
*
|
|
1881
|
+
* @example
|
|
1882
|
+
* ```ts
|
|
1883
|
+
* const manifest = await createOutputManifest({ storage: config.storage, cache: cacheStorage({ root: config.root }) })
|
|
1884
|
+
* ```
|
|
1885
|
+
*/
|
|
1886
|
+
async function createOutputManifest({ storage, cache }) {
|
|
1887
|
+
const entries = await loadEntries({ cache });
|
|
1888
|
+
const tracked = /* @__PURE__ */ new Map();
|
|
1889
|
+
return {
|
|
1890
|
+
isUpToDate({ key, source, disk }) {
|
|
1891
|
+
const entry = entries[key];
|
|
1892
|
+
if (!entry) return false;
|
|
1893
|
+
return entry.source === hash(source) && entry.output === hash(disk);
|
|
1894
|
+
},
|
|
1895
|
+
track({ key, source }) {
|
|
1896
|
+
tracked.set(key, hash(source));
|
|
1897
|
+
},
|
|
1898
|
+
async commit() {
|
|
1899
|
+
try {
|
|
1900
|
+
const next = { ...entries };
|
|
1901
|
+
await require_usingCtx.inParallel({
|
|
1902
|
+
items: [...tracked],
|
|
1903
|
+
limit: 50,
|
|
1904
|
+
run: async ([key, source]) => {
|
|
1905
|
+
const stored = await storage.readItem(key);
|
|
1906
|
+
if (stored === null) return;
|
|
1907
|
+
next[key] = {
|
|
1908
|
+
source,
|
|
1909
|
+
output: hash(stored)
|
|
1910
|
+
};
|
|
1911
|
+
}
|
|
1912
|
+
});
|
|
1913
|
+
await cache.writeItem(MANIFEST_KEY, JSON.stringify({
|
|
1914
|
+
version: VERSION,
|
|
1915
|
+
entries: next
|
|
1916
|
+
}));
|
|
1917
|
+
} catch {}
|
|
1918
|
+
}
|
|
1919
|
+
};
|
|
1920
|
+
}
|
|
1921
|
+
//#endregion
|
|
1959
1922
|
//#region src/createStorage.ts
|
|
1960
1923
|
/**
|
|
1961
1924
|
* Defines a custom storage backend. The builder receives user options and
|
|
@@ -2032,7 +1995,8 @@ function createLimiter(concurrency) {
|
|
|
2032
1995
|
*
|
|
2033
1996
|
* Writes are deduplicated and directory-safe:
|
|
2034
1997
|
* - leading and trailing whitespace is trimmed before writing
|
|
2035
|
-
* - the write is skipped when the file content
|
|
1998
|
+
* - the write is skipped when the file already holds that content, ignoring any trailing newline
|
|
1999
|
+
* a formatter left behind
|
|
2036
2000
|
* - missing parent directories are created automatically
|
|
2037
2001
|
* - Bun's native file API is used when running under Bun
|
|
2038
2002
|
* - concurrent `writeItem` calls are capped at {@link WRITE_CONCURRENCY} in flight, so a caller
|
|
@@ -2093,6 +2057,60 @@ const fsStorage = createStorage(() => {
|
|
|
2093
2057
|
};
|
|
2094
2058
|
});
|
|
2095
2059
|
//#endregion
|
|
2060
|
+
//#region src/storages/cacheStorage.ts
|
|
2061
|
+
/**
|
|
2062
|
+
* Directory Kubb keeps build caches in. A project with a `node_modules` gets
|
|
2063
|
+
* `node_modules/.cache/kubb`, the convention babel and eslint already use, so the cache stays out
|
|
2064
|
+
* of version control. Without one it falls back to the OS temp directory, keyed by root so two
|
|
2065
|
+
* projects sharing that directory keep their own cache.
|
|
2066
|
+
*
|
|
2067
|
+
* @example Inside a project
|
|
2068
|
+
* `resolveCacheDir('/project') // '/project/node_modules/.cache/kubb'`
|
|
2069
|
+
*/
|
|
2070
|
+
function resolveCacheDir(root) {
|
|
2071
|
+
const nodeModules = (0, node_path.join)(root, "node_modules");
|
|
2072
|
+
if ((0, node_fs.existsSync)(nodeModules)) return (0, node_path.join)(nodeModules, ".cache", "kubb");
|
|
2073
|
+
return (0, node_path.join)((0, node_os.tmpdir)(), "kubb", (0, node_crypto.createHash)("sha256").update(root).digest("hex").slice(0, 16));
|
|
2074
|
+
}
|
|
2075
|
+
/**
|
|
2076
|
+
* Filesystem storage for build caches rather than generated code. Keys are plain names resolved
|
|
2077
|
+
* inside {@link resolveCacheDir}, so a caller stores `'x.json'` without knowing where the cache
|
|
2078
|
+
* lives. Kept apart from the configured output storage, which may not be a local disk at all.
|
|
2079
|
+
*
|
|
2080
|
+
* @example
|
|
2081
|
+
* ```ts
|
|
2082
|
+
* const cache = cacheStorage({ root: config.root })
|
|
2083
|
+
* await cache.writeItem('output-manifest.json', JSON.stringify(entries))
|
|
2084
|
+
* ```
|
|
2085
|
+
*/
|
|
2086
|
+
const cacheStorage = createStorage(({ root = process.cwd() }) => {
|
|
2087
|
+
const dir = resolveCacheDir(root);
|
|
2088
|
+
const storage = fsStorage();
|
|
2089
|
+
const toPath = (key) => (0, node_path.join)(dir, key);
|
|
2090
|
+
return {
|
|
2091
|
+
name: "cache",
|
|
2092
|
+
async existsItem(key) {
|
|
2093
|
+
return storage.existsItem(toPath(key));
|
|
2094
|
+
},
|
|
2095
|
+
async readItem(key) {
|
|
2096
|
+
return storage.readItem(toPath(key));
|
|
2097
|
+
},
|
|
2098
|
+
async writeItem(key, value) {
|
|
2099
|
+
return storage.writeItem(toPath(key), value);
|
|
2100
|
+
},
|
|
2101
|
+
async removeItem(key) {
|
|
2102
|
+
return storage.removeItem(toPath(key));
|
|
2103
|
+
},
|
|
2104
|
+
async readKeys(base) {
|
|
2105
|
+
return storage.readKeys(base ? toPath(base) : dir);
|
|
2106
|
+
},
|
|
2107
|
+
async empty(base) {
|
|
2108
|
+
if (!base) return;
|
|
2109
|
+
return storage.empty(toPath(base));
|
|
2110
|
+
}
|
|
2111
|
+
};
|
|
2112
|
+
});
|
|
2113
|
+
//#endregion
|
|
2096
2114
|
//#region src/createKubb.ts
|
|
2097
2115
|
function resolveConfig(userConfig) {
|
|
2098
2116
|
return {
|
|
@@ -2111,6 +2129,13 @@ function resolveConfig(userConfig) {
|
|
|
2111
2129
|
};
|
|
2112
2130
|
}
|
|
2113
2131
|
/**
|
|
2132
|
+
* Whether anything runs over the output directory after the files are written. Only then can the
|
|
2133
|
+
* bytes on disk stop matching what Kubb wrote, which is what the manifest exists to track.
|
|
2134
|
+
*/
|
|
2135
|
+
function hasOutputPasses(output) {
|
|
2136
|
+
return Boolean(output.format || output.lint || output.postGenerate?.length);
|
|
2137
|
+
}
|
|
2138
|
+
/**
|
|
2114
2139
|
* Kubb code-generation instance bound to a single config entry. Resolves the user
|
|
2115
2140
|
* config in the constructor, so `config` is available right away, and shares `hooks`,
|
|
2116
2141
|
* `storage`, and `driver` across the `setup → build` lifecycle.
|
|
@@ -2132,6 +2157,7 @@ var Kubb = class {
|
|
|
2132
2157
|
config;
|
|
2133
2158
|
#driver = null;
|
|
2134
2159
|
#storage = null;
|
|
2160
|
+
#manifest = null;
|
|
2135
2161
|
constructor(userConfig, options = {}) {
|
|
2136
2162
|
this.config = resolveConfig(userConfig);
|
|
2137
2163
|
this.hooks = options.hooks ?? new require_usingCtx.Hookable();
|
|
@@ -2149,7 +2175,14 @@ var Kubb = class {
|
|
|
2149
2175
|
*/
|
|
2150
2176
|
async setup() {
|
|
2151
2177
|
const config = this.config;
|
|
2152
|
-
const
|
|
2178
|
+
const manifest = hasOutputPasses(config.output) ? await createOutputManifest({
|
|
2179
|
+
storage: config.storage,
|
|
2180
|
+
cache: cacheStorage({ root: config.root })
|
|
2181
|
+
}) : void 0;
|
|
2182
|
+
const driver = new KubbDriver(config, {
|
|
2183
|
+
hooks: this.hooks,
|
|
2184
|
+
manifest
|
|
2185
|
+
});
|
|
2153
2186
|
this.hooks.setMaxListeners(Math.max(10, config.plugins.length * 4));
|
|
2154
2187
|
if (config.output.clean) {
|
|
2155
2188
|
const cleanPath = (0, node_path.resolve)(config.root, config.output.path);
|
|
@@ -2165,6 +2198,7 @@ var Kubb = class {
|
|
|
2165
2198
|
await driver.setup();
|
|
2166
2199
|
this.#driver = driver;
|
|
2167
2200
|
this.#storage = config.storage;
|
|
2201
|
+
this.#manifest = manifest ?? null;
|
|
2168
2202
|
}
|
|
2169
2203
|
/**
|
|
2170
2204
|
* Runs the full pipeline and throws on any plugin error.
|
|
@@ -2252,6 +2286,7 @@ var Kubb = class {
|
|
|
2252
2286
|
}) : [];
|
|
2253
2287
|
const finalDiagnostics = [...diagnostics, ...outputDiagnostics];
|
|
2254
2288
|
const failed = Diagnostics.hasError(outputDiagnostics);
|
|
2289
|
+
if (!failed) await this.#manifest?.commit();
|
|
2255
2290
|
await hooks.callHook("kubb:generation:end", {
|
|
2256
2291
|
config,
|
|
2257
2292
|
storage,
|