@kubb/core 5.0.0-beta.3 → 5.0.0-beta.30
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/README.md +8 -38
- package/dist/KubbDriver-CFx2DdhF.js +2131 -0
- package/dist/KubbDriver-CFx2DdhF.js.map +1 -0
- package/dist/KubbDriver-vyD7F0Ip.cjs +2252 -0
- package/dist/KubbDriver-vyD7F0Ip.cjs.map +1 -0
- package/dist/{types-CC09VtBt.d.ts → createKubb-6zii1jo-.d.ts} +1610 -1257
- package/dist/index.cjs +351 -1125
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -186
- package/dist/index.js +341 -1119
- package/dist/index.js.map +1 -1
- package/dist/mocks.cjs +30 -21
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.ts +5 -5
- package/dist/mocks.js +29 -20
- package/dist/mocks.js.map +1 -1
- package/package.json +6 -18
- package/src/FileManager.ts +78 -61
- package/src/FileProcessor.ts +48 -38
- package/src/KubbDriver.ts +930 -0
- package/src/constants.ts +11 -6
- package/src/createAdapter.ts +113 -17
- package/src/createKubb.ts +1039 -478
- package/src/createRenderer.ts +58 -27
- package/src/createStorage.ts +36 -23
- package/src/defineGenerator.ts +127 -15
- package/src/defineLogger.ts +66 -7
- package/src/defineMiddleware.ts +19 -17
- package/src/defineParser.ts +30 -13
- package/src/definePlugin.ts +329 -14
- package/src/defineResolver.ts +365 -167
- package/src/devtools.ts +8 -1
- package/src/index.ts +2 -2
- package/src/mocks.ts +11 -14
- package/src/storages/fsStorage.ts +13 -37
- package/src/types.ts +48 -1292
- package/dist/PluginDriver-BXibeQk-.cjs +0 -1036
- package/dist/PluginDriver-BXibeQk-.cjs.map +0 -1
- package/dist/PluginDriver-DV3p2Hky.js +0 -945
- package/dist/PluginDriver-DV3p2Hky.js.map +0 -1
- package/src/Kubb.ts +0 -300
- package/src/PluginDriver.ts +0 -424
- package/src/renderNode.ts +0 -35
- package/src/utils/diagnostics.ts +0 -18
- package/src/utils/isInputPath.ts +0 -10
- package/src/utils/packageJSON.ts +0 -99
package/dist/index.cjs
CHANGED
|
@@ -1,184 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const
|
|
3
|
-
let node_events = require("node:events");
|
|
2
|
+
const require_KubbDriver = require("./KubbDriver-vyD7F0Ip.cjs");
|
|
4
3
|
let node_fs_promises = require("node:fs/promises");
|
|
5
4
|
let node_path = require("node:path");
|
|
6
5
|
let _kubb_ast = require("@kubb/ast");
|
|
7
|
-
_kubb_ast =
|
|
6
|
+
_kubb_ast = require_KubbDriver.__toESM(_kubb_ast, 1);
|
|
8
7
|
let node_process = require("node:process");
|
|
9
|
-
//#region ../../internals/utils/src/errors.ts
|
|
10
|
-
/**
|
|
11
|
-
* Thrown when one or more errors occur during a Kubb build.
|
|
12
|
-
* Carries the full list of underlying errors on `errors`.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```ts
|
|
16
|
-
* throw new BuildError('Build failed', { errors: [err1, err2] })
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
var BuildError = class extends Error {
|
|
20
|
-
errors;
|
|
21
|
-
constructor(message, options) {
|
|
22
|
-
super(message, { cause: options.cause });
|
|
23
|
-
this.name = "BuildError";
|
|
24
|
-
this.errors = options.errors;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
/**
|
|
28
|
-
* Coerces an unknown thrown value to an `Error` instance.
|
|
29
|
-
* Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`.
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```ts
|
|
33
|
-
* try { ... } catch(err) {
|
|
34
|
-
* throw new BuildError('Build failed', { cause: toError(err), errors: [] })
|
|
35
|
-
* }
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
function toError(value) {
|
|
39
|
-
return value instanceof Error ? value : new Error(String(value));
|
|
40
|
-
}
|
|
41
|
-
//#endregion
|
|
42
|
-
//#region ../../internals/utils/src/asyncEventEmitter.ts
|
|
43
|
-
/**
|
|
44
|
-
* Typed `EventEmitter` that awaits all async listeners before resolving.
|
|
45
|
-
* Wraps Node's `EventEmitter` with full TypeScript event-map inference.
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
* ```ts
|
|
49
|
-
* const emitter = new AsyncEventEmitter<{ build: [name: string] }>()
|
|
50
|
-
* emitter.on('build', async (name) => { console.log(name) })
|
|
51
|
-
* await emitter.emit('build', 'petstore') // all listeners awaited
|
|
52
|
-
* ```
|
|
53
|
-
*/
|
|
54
|
-
var AsyncEventEmitter = class {
|
|
55
|
-
/**
|
|
56
|
-
* Maximum number of listeners per event before Node emits a memory-leak warning.
|
|
57
|
-
* @default 10
|
|
58
|
-
*/
|
|
59
|
-
constructor(maxListener = 10) {
|
|
60
|
-
this.#emitter.setMaxListeners(maxListener);
|
|
61
|
-
}
|
|
62
|
-
#emitter = new node_events.EventEmitter();
|
|
63
|
-
/**
|
|
64
|
-
* Emits `eventName` and awaits all registered listeners sequentially.
|
|
65
|
-
* Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.
|
|
66
|
-
*
|
|
67
|
-
* @example
|
|
68
|
-
* ```ts
|
|
69
|
-
* await emitter.emit('build', 'petstore')
|
|
70
|
-
* ```
|
|
71
|
-
*/
|
|
72
|
-
async emit(eventName, ...eventArgs) {
|
|
73
|
-
const listeners = this.#emitter.listeners(eventName);
|
|
74
|
-
if (listeners.length === 0) return;
|
|
75
|
-
for (const listener of listeners) try {
|
|
76
|
-
await listener(...eventArgs);
|
|
77
|
-
} catch (err) {
|
|
78
|
-
let serializedArgs;
|
|
79
|
-
try {
|
|
80
|
-
serializedArgs = JSON.stringify(eventArgs);
|
|
81
|
-
} catch {
|
|
82
|
-
serializedArgs = String(eventArgs);
|
|
83
|
-
}
|
|
84
|
-
throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Registers a persistent listener for `eventName`.
|
|
89
|
-
*
|
|
90
|
-
* @example
|
|
91
|
-
* ```ts
|
|
92
|
-
* emitter.on('build', async (name) => { console.log(name) })
|
|
93
|
-
* ```
|
|
94
|
-
*/
|
|
95
|
-
on(eventName, handler) {
|
|
96
|
-
this.#emitter.on(eventName, handler);
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Registers a one-shot listener that removes itself after the first invocation.
|
|
100
|
-
*
|
|
101
|
-
* @example
|
|
102
|
-
* ```ts
|
|
103
|
-
* emitter.onOnce('build', async (name) => { console.log(name) })
|
|
104
|
-
* ```
|
|
105
|
-
*/
|
|
106
|
-
onOnce(eventName, handler) {
|
|
107
|
-
const wrapper = (...args) => {
|
|
108
|
-
this.off(eventName, wrapper);
|
|
109
|
-
return handler(...args);
|
|
110
|
-
};
|
|
111
|
-
this.on(eventName, wrapper);
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Removes a previously registered listener.
|
|
115
|
-
*
|
|
116
|
-
* @example
|
|
117
|
-
* ```ts
|
|
118
|
-
* emitter.off('build', handler)
|
|
119
|
-
* ```
|
|
120
|
-
*/
|
|
121
|
-
off(eventName, handler) {
|
|
122
|
-
this.#emitter.off(eventName, handler);
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Returns the number of listeners registered for `eventName`.
|
|
126
|
-
*
|
|
127
|
-
* @example
|
|
128
|
-
* ```ts
|
|
129
|
-
* emitter.on('build', handler)
|
|
130
|
-
* emitter.listenerCount('build') // 1
|
|
131
|
-
* ```
|
|
132
|
-
*/
|
|
133
|
-
listenerCount(eventName) {
|
|
134
|
-
return this.#emitter.listenerCount(eventName);
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Removes all listeners from every event channel.
|
|
138
|
-
*
|
|
139
|
-
* @example
|
|
140
|
-
* ```ts
|
|
141
|
-
* emitter.removeAll()
|
|
142
|
-
* ```
|
|
143
|
-
*/
|
|
144
|
-
removeAll() {
|
|
145
|
-
this.#emitter.removeAllListeners();
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
//#endregion
|
|
149
|
-
//#region ../../internals/utils/src/time.ts
|
|
150
|
-
/**
|
|
151
|
-
* Calculates elapsed time in milliseconds from a high-resolution `process.hrtime` start time.
|
|
152
|
-
* Rounds to 2 decimal places for sub-millisecond precision without noise.
|
|
153
|
-
*
|
|
154
|
-
* @example
|
|
155
|
-
* ```ts
|
|
156
|
-
* const start = process.hrtime()
|
|
157
|
-
* doWork()
|
|
158
|
-
* getElapsedMs(start) // 42.35
|
|
159
|
-
* ```
|
|
160
|
-
*/
|
|
161
|
-
function getElapsedMs(hrStart) {
|
|
162
|
-
const [seconds, nanoseconds] = process.hrtime(hrStart);
|
|
163
|
-
const ms = seconds * 1e3 + nanoseconds / 1e6;
|
|
164
|
-
return Math.round(ms * 100) / 100;
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Converts a millisecond duration into a human-readable string (`ms`, `s`, or `m s`).
|
|
168
|
-
*
|
|
169
|
-
* @example
|
|
170
|
-
* ```ts
|
|
171
|
-
* formatMs(250) // '250ms'
|
|
172
|
-
* formatMs(1500) // '1.50s'
|
|
173
|
-
* formatMs(90000) // '1m 30.0s'
|
|
174
|
-
* ```
|
|
175
|
-
*/
|
|
176
|
-
function formatMs(ms) {
|
|
177
|
-
if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`;
|
|
178
|
-
if (ms >= 1e3) return `${(ms / 1e3).toFixed(2)}s`;
|
|
179
|
-
return `${Math.round(ms)}ms`;
|
|
180
|
-
}
|
|
181
|
-
//#endregion
|
|
182
8
|
//#region ../../internals/utils/src/fs.ts
|
|
183
9
|
/**
|
|
184
10
|
* Resolves to `true` when the file or directory at `path` exists.
|
|
@@ -245,488 +71,81 @@ async function clean(path) {
|
|
|
245
71
|
});
|
|
246
72
|
}
|
|
247
73
|
//#endregion
|
|
248
|
-
//#region ../../internals/utils/src/reserved.ts
|
|
249
|
-
/**
|
|
250
|
-
* JavaScript and Java reserved words.
|
|
251
|
-
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
252
|
-
*/
|
|
253
|
-
const reservedWords = new Set([
|
|
254
|
-
"abstract",
|
|
255
|
-
"arguments",
|
|
256
|
-
"boolean",
|
|
257
|
-
"break",
|
|
258
|
-
"byte",
|
|
259
|
-
"case",
|
|
260
|
-
"catch",
|
|
261
|
-
"char",
|
|
262
|
-
"class",
|
|
263
|
-
"const",
|
|
264
|
-
"continue",
|
|
265
|
-
"debugger",
|
|
266
|
-
"default",
|
|
267
|
-
"delete",
|
|
268
|
-
"do",
|
|
269
|
-
"double",
|
|
270
|
-
"else",
|
|
271
|
-
"enum",
|
|
272
|
-
"eval",
|
|
273
|
-
"export",
|
|
274
|
-
"extends",
|
|
275
|
-
"false",
|
|
276
|
-
"final",
|
|
277
|
-
"finally",
|
|
278
|
-
"float",
|
|
279
|
-
"for",
|
|
280
|
-
"function",
|
|
281
|
-
"goto",
|
|
282
|
-
"if",
|
|
283
|
-
"implements",
|
|
284
|
-
"import",
|
|
285
|
-
"in",
|
|
286
|
-
"instanceof",
|
|
287
|
-
"int",
|
|
288
|
-
"interface",
|
|
289
|
-
"let",
|
|
290
|
-
"long",
|
|
291
|
-
"native",
|
|
292
|
-
"new",
|
|
293
|
-
"null",
|
|
294
|
-
"package",
|
|
295
|
-
"private",
|
|
296
|
-
"protected",
|
|
297
|
-
"public",
|
|
298
|
-
"return",
|
|
299
|
-
"short",
|
|
300
|
-
"static",
|
|
301
|
-
"super",
|
|
302
|
-
"switch",
|
|
303
|
-
"synchronized",
|
|
304
|
-
"this",
|
|
305
|
-
"throw",
|
|
306
|
-
"throws",
|
|
307
|
-
"transient",
|
|
308
|
-
"true",
|
|
309
|
-
"try",
|
|
310
|
-
"typeof",
|
|
311
|
-
"var",
|
|
312
|
-
"void",
|
|
313
|
-
"volatile",
|
|
314
|
-
"while",
|
|
315
|
-
"with",
|
|
316
|
-
"yield",
|
|
317
|
-
"Array",
|
|
318
|
-
"Date",
|
|
319
|
-
"hasOwnProperty",
|
|
320
|
-
"Infinity",
|
|
321
|
-
"isFinite",
|
|
322
|
-
"isNaN",
|
|
323
|
-
"isPrototypeOf",
|
|
324
|
-
"length",
|
|
325
|
-
"Math",
|
|
326
|
-
"name",
|
|
327
|
-
"NaN",
|
|
328
|
-
"Number",
|
|
329
|
-
"Object",
|
|
330
|
-
"prototype",
|
|
331
|
-
"String",
|
|
332
|
-
"toString",
|
|
333
|
-
"undefined",
|
|
334
|
-
"valueOf"
|
|
335
|
-
]);
|
|
336
|
-
/**
|
|
337
|
-
* Returns `true` when `name` is a syntactically valid JavaScript variable name.
|
|
338
|
-
*
|
|
339
|
-
* @example
|
|
340
|
-
* ```ts
|
|
341
|
-
* isValidVarName('status') // true
|
|
342
|
-
* isValidVarName('class') // false (reserved word)
|
|
343
|
-
* isValidVarName('42foo') // false (starts with digit)
|
|
344
|
-
* ```
|
|
345
|
-
*/
|
|
346
|
-
function isValidVarName(name) {
|
|
347
|
-
if (!name || reservedWords.has(name)) return false;
|
|
348
|
-
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
349
|
-
}
|
|
350
|
-
//#endregion
|
|
351
|
-
//#region ../../internals/utils/src/urlPath.ts
|
|
352
|
-
/**
|
|
353
|
-
* Parses and transforms an OpenAPI/Swagger path string into various URL formats.
|
|
354
|
-
*
|
|
355
|
-
* @example
|
|
356
|
-
* const p = new URLPath('/pet/{petId}')
|
|
357
|
-
* p.URL // '/pet/:petId'
|
|
358
|
-
* p.template // '`/pet/${petId}`'
|
|
359
|
-
*/
|
|
360
|
-
var URLPath = class {
|
|
361
|
-
/**
|
|
362
|
-
* The raw OpenAPI/Swagger path string, e.g. `/pet/{petId}`.
|
|
363
|
-
*/
|
|
364
|
-
path;
|
|
365
|
-
#options;
|
|
366
|
-
constructor(path, options = {}) {
|
|
367
|
-
this.path = path;
|
|
368
|
-
this.#options = options;
|
|
369
|
-
}
|
|
370
|
-
/** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`.
|
|
371
|
-
*
|
|
372
|
-
* @example
|
|
373
|
-
* ```ts
|
|
374
|
-
* new URLPath('/pet/{petId}').URL // '/pet/:petId'
|
|
375
|
-
* ```
|
|
376
|
-
*/
|
|
377
|
-
get URL() {
|
|
378
|
-
return this.toURLPath();
|
|
379
|
-
}
|
|
380
|
-
/** Returns `true` when `path` is a fully-qualified URL (e.g. starts with `https://`).
|
|
381
|
-
*
|
|
382
|
-
* @example
|
|
383
|
-
* ```ts
|
|
384
|
-
* new URLPath('https://petstore.swagger.io/v2/pet').isURL // true
|
|
385
|
-
* new URLPath('/pet/{petId}').isURL // false
|
|
386
|
-
* ```
|
|
387
|
-
*/
|
|
388
|
-
get isURL() {
|
|
389
|
-
try {
|
|
390
|
-
return !!new URL(this.path).href;
|
|
391
|
-
} catch {
|
|
392
|
-
return false;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
/**
|
|
396
|
-
* Converts the OpenAPI path to a TypeScript template literal string.
|
|
397
|
-
*
|
|
398
|
-
* @example
|
|
399
|
-
* new URLPath('/pet/{petId}').template // '`/pet/${petId}`'
|
|
400
|
-
* new URLPath('/account/monetary-accountID').template // '`/account/${monetaryAccountId}`'
|
|
401
|
-
*/
|
|
402
|
-
get template() {
|
|
403
|
-
return this.toTemplateString();
|
|
404
|
-
}
|
|
405
|
-
/** Returns the path and its extracted params as a structured `URLObject`, or as a stringified expression when `stringify` is set.
|
|
406
|
-
*
|
|
407
|
-
* @example
|
|
408
|
-
* ```ts
|
|
409
|
-
* new URLPath('/pet/{petId}').object
|
|
410
|
-
* // { url: '/pet/:petId', params: { petId: 'petId' } }
|
|
411
|
-
* ```
|
|
412
|
-
*/
|
|
413
|
-
get object() {
|
|
414
|
-
return this.toObject();
|
|
415
|
-
}
|
|
416
|
-
/** Returns a map of path parameter names, or `undefined` when the path has no parameters.
|
|
417
|
-
*
|
|
418
|
-
* @example
|
|
419
|
-
* ```ts
|
|
420
|
-
* new URLPath('/pet/{petId}').params // { petId: 'petId' }
|
|
421
|
-
* new URLPath('/pet').params // undefined
|
|
422
|
-
* ```
|
|
423
|
-
*/
|
|
424
|
-
get params() {
|
|
425
|
-
return this.getParams();
|
|
426
|
-
}
|
|
427
|
-
#transformParam(raw) {
|
|
428
|
-
const param = isValidVarName(raw) ? raw : require_PluginDriver.camelCase(raw);
|
|
429
|
-
return this.#options.casing === "camelcase" ? require_PluginDriver.camelCase(param) : param;
|
|
430
|
-
}
|
|
431
|
-
/**
|
|
432
|
-
* Iterates over every `{param}` token in `path`, calling `fn` with the raw token and transformed name.
|
|
433
|
-
*/
|
|
434
|
-
#eachParam(fn) {
|
|
435
|
-
for (const match of this.path.matchAll(/\{([^}]+)\}/g)) {
|
|
436
|
-
const raw = match[1];
|
|
437
|
-
fn(raw, this.#transformParam(raw));
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
toObject({ type = "path", replacer, stringify } = {}) {
|
|
441
|
-
const object = {
|
|
442
|
-
url: type === "path" ? this.toURLPath() : this.toTemplateString({ replacer }),
|
|
443
|
-
params: this.getParams()
|
|
444
|
-
};
|
|
445
|
-
if (stringify) {
|
|
446
|
-
if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
|
|
447
|
-
if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`;
|
|
448
|
-
return `{ url: '${object.url}' }`;
|
|
449
|
-
}
|
|
450
|
-
return object;
|
|
451
|
-
}
|
|
452
|
-
/**
|
|
453
|
-
* Converts the OpenAPI path to a TypeScript template literal string.
|
|
454
|
-
* An optional `replacer` can transform each extracted parameter name before interpolation.
|
|
455
|
-
*
|
|
456
|
-
* @example
|
|
457
|
-
* new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`'
|
|
458
|
-
*/
|
|
459
|
-
toTemplateString({ prefix = "", replacer } = {}) {
|
|
460
|
-
return `\`${prefix}${this.path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
461
|
-
if (i % 2 === 0) return part;
|
|
462
|
-
const param = this.#transformParam(part);
|
|
463
|
-
return `\${${replacer ? replacer(param) : param}}`;
|
|
464
|
-
}).join("")}\``;
|
|
465
|
-
}
|
|
466
|
-
/**
|
|
467
|
-
* Extracts all `{param}` segments from the path and returns them as a key-value map.
|
|
468
|
-
* An optional `replacer` transforms each parameter name in both key and value positions.
|
|
469
|
-
* Returns `undefined` when no path parameters are found.
|
|
470
|
-
*
|
|
471
|
-
* @example
|
|
472
|
-
* ```ts
|
|
473
|
-
* new URLPath('/pet/{petId}/tag/{tagId}').getParams()
|
|
474
|
-
* // { petId: 'petId', tagId: 'tagId' }
|
|
475
|
-
* ```
|
|
476
|
-
*/
|
|
477
|
-
getParams(replacer) {
|
|
478
|
-
const params = {};
|
|
479
|
-
this.#eachParam((_raw, param) => {
|
|
480
|
-
const key = replacer ? replacer(param) : param;
|
|
481
|
-
params[key] = key;
|
|
482
|
-
});
|
|
483
|
-
return Object.keys(params).length > 0 ? params : void 0;
|
|
484
|
-
}
|
|
485
|
-
/** Converts the OpenAPI path to Express-style colon syntax.
|
|
486
|
-
*
|
|
487
|
-
* @example
|
|
488
|
-
* ```ts
|
|
489
|
-
* new URLPath('/pet/{petId}').toURLPath() // '/pet/:petId'
|
|
490
|
-
* ```
|
|
491
|
-
*/
|
|
492
|
-
toURLPath() {
|
|
493
|
-
return this.path.replace(/\{([^}]+)\}/g, ":$1");
|
|
494
|
-
}
|
|
495
|
-
};
|
|
496
|
-
//#endregion
|
|
497
74
|
//#region src/createAdapter.ts
|
|
498
75
|
/**
|
|
499
|
-
*
|
|
76
|
+
* Defines a custom adapter that translates a spec format into Kubb's universal
|
|
77
|
+
* AST. Use this when you need to consume GraphQL, gRPC, AsyncAPI, or another
|
|
78
|
+
* domain-specific schema. Built-in adapters: `@kubb/adapter-oas` for
|
|
79
|
+
* OpenAPI/Swagger documents.
|
|
500
80
|
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
*
|
|
504
|
-
* @note Adapters must parse their input format to Kubb's `InputNode` structure.
|
|
81
|
+
* Adapters must return an `InputNode` from `parse`. That node is what every
|
|
82
|
+
* plugin in the build consumes.
|
|
505
83
|
*
|
|
506
84
|
* @example
|
|
507
85
|
* ```ts
|
|
508
|
-
*
|
|
509
|
-
*
|
|
510
|
-
*
|
|
511
|
-
* options,
|
|
512
|
-
* async parse(source) {
|
|
513
|
-
* // Transform source format to InputNode
|
|
514
|
-
* return { ... }
|
|
515
|
-
* },
|
|
516
|
-
* }
|
|
517
|
-
* })
|
|
86
|
+
* import { createAdapter, ast, type AdapterFactoryOptions } from '@kubb/core'
|
|
87
|
+
*
|
|
88
|
+
* type MyAdapter = AdapterFactoryOptions<'my-adapter', { validate?: boolean }>
|
|
518
89
|
*
|
|
519
|
-
*
|
|
520
|
-
*
|
|
90
|
+
* export const myAdapter = createAdapter<MyAdapter>((options) => ({
|
|
91
|
+
* name: 'my-adapter',
|
|
92
|
+
* options,
|
|
93
|
+
* document: null,
|
|
94
|
+
* async parse(_source) {
|
|
95
|
+
* // Convert `source` (path or inline data) into an InputNode.
|
|
96
|
+
* return ast.createInput()
|
|
97
|
+
* },
|
|
98
|
+
* getImports: () => [],
|
|
99
|
+
* async validate() {
|
|
100
|
+
* // Throw or call ctx.error here when the spec is invalid.
|
|
101
|
+
* },
|
|
102
|
+
* }))
|
|
521
103
|
* ```
|
|
522
104
|
*/
|
|
523
105
|
function createAdapter(build) {
|
|
524
106
|
return (options) => build(options ?? {});
|
|
525
107
|
}
|
|
526
108
|
//#endregion
|
|
527
|
-
//#region
|
|
528
|
-
var
|
|
529
|
-
value;
|
|
530
|
-
next;
|
|
531
|
-
constructor(value) {
|
|
532
|
-
this.value = value;
|
|
533
|
-
}
|
|
534
|
-
};
|
|
535
|
-
var Queue = class {
|
|
536
|
-
#head;
|
|
537
|
-
#tail;
|
|
538
|
-
#size;
|
|
539
|
-
constructor() {
|
|
540
|
-
this.clear();
|
|
541
|
-
}
|
|
542
|
-
enqueue(value) {
|
|
543
|
-
const node = new Node(value);
|
|
544
|
-
if (this.#head) {
|
|
545
|
-
this.#tail.next = node;
|
|
546
|
-
this.#tail = node;
|
|
547
|
-
} else {
|
|
548
|
-
this.#head = node;
|
|
549
|
-
this.#tail = node;
|
|
550
|
-
}
|
|
551
|
-
this.#size++;
|
|
552
|
-
}
|
|
553
|
-
dequeue() {
|
|
554
|
-
const current = this.#head;
|
|
555
|
-
if (!current) return;
|
|
556
|
-
this.#head = this.#head.next;
|
|
557
|
-
this.#size--;
|
|
558
|
-
if (!this.#head) this.#tail = void 0;
|
|
559
|
-
return current.value;
|
|
560
|
-
}
|
|
561
|
-
peek() {
|
|
562
|
-
if (!this.#head) return;
|
|
563
|
-
return this.#head.value;
|
|
564
|
-
}
|
|
565
|
-
clear() {
|
|
566
|
-
this.#head = void 0;
|
|
567
|
-
this.#tail = void 0;
|
|
568
|
-
this.#size = 0;
|
|
569
|
-
}
|
|
570
|
-
get size() {
|
|
571
|
-
return this.#size;
|
|
572
|
-
}
|
|
573
|
-
*[Symbol.iterator]() {
|
|
574
|
-
let current = this.#head;
|
|
575
|
-
while (current) {
|
|
576
|
-
yield current.value;
|
|
577
|
-
current = current.next;
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
*drain() {
|
|
581
|
-
while (this.#head) yield this.dequeue();
|
|
582
|
-
}
|
|
583
|
-
};
|
|
584
|
-
//#endregion
|
|
585
|
-
//#region ../../node_modules/.pnpm/p-limit@7.3.0/node_modules/p-limit/index.js
|
|
586
|
-
function pLimit(concurrency) {
|
|
587
|
-
let rejectOnClear = false;
|
|
588
|
-
if (typeof concurrency === "object") ({concurrency, rejectOnClear = false} = concurrency);
|
|
589
|
-
validateConcurrency(concurrency);
|
|
590
|
-
if (typeof rejectOnClear !== "boolean") throw new TypeError("Expected `rejectOnClear` to be a boolean");
|
|
591
|
-
const queue = new Queue();
|
|
592
|
-
let activeCount = 0;
|
|
593
|
-
const resumeNext = () => {
|
|
594
|
-
if (activeCount < concurrency && queue.size > 0) {
|
|
595
|
-
activeCount++;
|
|
596
|
-
queue.dequeue().run();
|
|
597
|
-
}
|
|
598
|
-
};
|
|
599
|
-
const next = () => {
|
|
600
|
-
activeCount--;
|
|
601
|
-
resumeNext();
|
|
602
|
-
};
|
|
603
|
-
const run = async (function_, resolve, arguments_) => {
|
|
604
|
-
const result = (async () => function_(...arguments_))();
|
|
605
|
-
resolve(result);
|
|
606
|
-
try {
|
|
607
|
-
await result;
|
|
608
|
-
} catch {}
|
|
609
|
-
next();
|
|
610
|
-
};
|
|
611
|
-
const enqueue = (function_, resolve, reject, arguments_) => {
|
|
612
|
-
const queueItem = { reject };
|
|
613
|
-
new Promise((internalResolve) => {
|
|
614
|
-
queueItem.run = internalResolve;
|
|
615
|
-
queue.enqueue(queueItem);
|
|
616
|
-
}).then(run.bind(void 0, function_, resolve, arguments_));
|
|
617
|
-
if (activeCount < concurrency) resumeNext();
|
|
618
|
-
};
|
|
619
|
-
const generator = (function_, ...arguments_) => new Promise((resolve, reject) => {
|
|
620
|
-
enqueue(function_, resolve, reject, arguments_);
|
|
621
|
-
});
|
|
622
|
-
Object.defineProperties(generator, {
|
|
623
|
-
activeCount: { get: () => activeCount },
|
|
624
|
-
pendingCount: { get: () => queue.size },
|
|
625
|
-
clearQueue: { value() {
|
|
626
|
-
if (!rejectOnClear) {
|
|
627
|
-
queue.clear();
|
|
628
|
-
return;
|
|
629
|
-
}
|
|
630
|
-
const abortError = AbortSignal.abort().reason;
|
|
631
|
-
while (queue.size > 0) queue.dequeue().reject(abortError);
|
|
632
|
-
} },
|
|
633
|
-
concurrency: {
|
|
634
|
-
get: () => concurrency,
|
|
635
|
-
set(newConcurrency) {
|
|
636
|
-
validateConcurrency(newConcurrency);
|
|
637
|
-
concurrency = newConcurrency;
|
|
638
|
-
queueMicrotask(() => {
|
|
639
|
-
while (activeCount < concurrency && queue.size > 0) resumeNext();
|
|
640
|
-
});
|
|
641
|
-
}
|
|
642
|
-
},
|
|
643
|
-
map: { async value(iterable, function_) {
|
|
644
|
-
const promises = Array.from(iterable, (value, index) => this(function_, value, index));
|
|
645
|
-
return Promise.all(promises);
|
|
646
|
-
} }
|
|
647
|
-
});
|
|
648
|
-
return generator;
|
|
649
|
-
}
|
|
650
|
-
function validateConcurrency(concurrency) {
|
|
651
|
-
if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) throw new TypeError("Expected `concurrency` to be a number from 1 and up");
|
|
652
|
-
}
|
|
653
|
-
//#endregion
|
|
654
|
-
//#region src/FileProcessor.ts
|
|
655
|
-
function joinSources(file) {
|
|
656
|
-
return file.sources.map((item) => (0, _kubb_ast.extractStringsFromNodes)(item.nodes)).filter(Boolean).join("\n\n");
|
|
657
|
-
}
|
|
658
|
-
/**
|
|
659
|
-
* Converts a single file to a string using the registered parsers.
|
|
660
|
-
* Falls back to joining source values when no matching parser is found.
|
|
661
|
-
*
|
|
662
|
-
* @internal
|
|
663
|
-
*/
|
|
664
|
-
var FileProcessor = class {
|
|
665
|
-
#limit = pLimit(100);
|
|
666
|
-
async parse(file, { parsers, extension } = {}) {
|
|
667
|
-
const parseExtName = extension?.[file.extname] || void 0;
|
|
668
|
-
if (!parsers || !file.extname) return joinSources(file);
|
|
669
|
-
const parser = parsers.get(file.extname);
|
|
670
|
-
if (!parser) return joinSources(file);
|
|
671
|
-
return parser.parse(file, { extname: parseExtName });
|
|
672
|
-
}
|
|
673
|
-
async run(files, { parsers, mode = "sequential", extension, onStart, onEnd, onUpdate } = {}) {
|
|
674
|
-
await onStart?.(files);
|
|
675
|
-
const total = files.length;
|
|
676
|
-
let processed = 0;
|
|
677
|
-
const processOne = async (file) => {
|
|
678
|
-
const source = await this.parse(file, {
|
|
679
|
-
extension,
|
|
680
|
-
parsers
|
|
681
|
-
});
|
|
682
|
-
const currentProcessed = ++processed;
|
|
683
|
-
const percentage = currentProcessed / total * 100;
|
|
684
|
-
await onUpdate?.({
|
|
685
|
-
file,
|
|
686
|
-
source,
|
|
687
|
-
processed: currentProcessed,
|
|
688
|
-
percentage,
|
|
689
|
-
total
|
|
690
|
-
});
|
|
691
|
-
};
|
|
692
|
-
if (mode === "sequential") for (const file of files) await processOne(file);
|
|
693
|
-
else await Promise.all(files.map((file) => this.#limit(() => processOne(file))));
|
|
694
|
-
await onEnd?.(files);
|
|
695
|
-
return files;
|
|
696
|
-
}
|
|
697
|
-
};
|
|
109
|
+
//#region package.json
|
|
110
|
+
var version = "5.0.0-beta.30";
|
|
698
111
|
//#endregion
|
|
699
112
|
//#region src/createStorage.ts
|
|
700
113
|
/**
|
|
701
|
-
*
|
|
702
|
-
*
|
|
703
|
-
*
|
|
704
|
-
*
|
|
705
|
-
*
|
|
706
|
-
* @note Call the returned factory with optional options to instantiate the storage adapter.
|
|
114
|
+
* Defines a custom storage backend. The builder receives user options and
|
|
115
|
+
* returns a `Storage` implementation. Kubb ships with filesystem and
|
|
116
|
+
* in-memory storages — reach for this when you need to write generated files
|
|
117
|
+
* elsewhere (cloud storage, a database, a remote API).
|
|
707
118
|
*
|
|
708
|
-
* @example
|
|
119
|
+
* @example In-memory storage (the built-in implementation)
|
|
709
120
|
* ```ts
|
|
710
121
|
* import { createStorage } from '@kubb/core'
|
|
711
122
|
*
|
|
712
123
|
* export const memoryStorage = createStorage(() => {
|
|
713
124
|
* const store = new Map<string, string>()
|
|
125
|
+
*
|
|
714
126
|
* return {
|
|
715
127
|
* name: 'memory',
|
|
716
|
-
* async hasItem(key) {
|
|
717
|
-
*
|
|
718
|
-
*
|
|
719
|
-
* async
|
|
128
|
+
* async hasItem(key) {
|
|
129
|
+
* return store.has(key)
|
|
130
|
+
* },
|
|
131
|
+
* async getItem(key) {
|
|
132
|
+
* return store.get(key) ?? null
|
|
133
|
+
* },
|
|
134
|
+
* async setItem(key, value) {
|
|
135
|
+
* store.set(key, value)
|
|
136
|
+
* },
|
|
137
|
+
* async removeItem(key) {
|
|
138
|
+
* store.delete(key)
|
|
139
|
+
* },
|
|
720
140
|
* async getKeys(base) {
|
|
721
141
|
* const keys = [...store.keys()]
|
|
722
142
|
* return base ? keys.filter((k) => k.startsWith(base)) : keys
|
|
723
143
|
* },
|
|
724
|
-
* async clear(base) {
|
|
144
|
+
* async clear(base) {
|
|
145
|
+
* if (!base) store.clear()
|
|
146
|
+
* },
|
|
725
147
|
* }
|
|
726
148
|
* })
|
|
727
|
-
*
|
|
728
|
-
* // Instantiate:
|
|
729
|
-
* const storage = memoryStorage()
|
|
730
149
|
* ```
|
|
731
150
|
*/
|
|
732
151
|
function createStorage(build) {
|
|
@@ -735,12 +154,6 @@ function createStorage(build) {
|
|
|
735
154
|
//#endregion
|
|
736
155
|
//#region src/storages/fsStorage.ts
|
|
737
156
|
/**
|
|
738
|
-
* Detects the filesystem error used to indicate that a path does not exist.
|
|
739
|
-
*/
|
|
740
|
-
function isMissingPathError(error) {
|
|
741
|
-
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
742
|
-
}
|
|
743
|
-
/**
|
|
744
157
|
* Built-in filesystem storage driver.
|
|
745
158
|
*
|
|
746
159
|
* This is the default storage when no `storage` option is configured in the root config.
|
|
@@ -771,17 +184,15 @@ const fsStorage = createStorage(() => ({
|
|
|
771
184
|
try {
|
|
772
185
|
await (0, node_fs_promises.access)((0, node_path.resolve)(key));
|
|
773
186
|
return true;
|
|
774
|
-
} catch (
|
|
775
|
-
|
|
776
|
-
throw new Error(`Failed to access storage item "${key}"`, { cause: error });
|
|
187
|
+
} catch (_error) {
|
|
188
|
+
return false;
|
|
777
189
|
}
|
|
778
190
|
},
|
|
779
191
|
async getItem(key) {
|
|
780
192
|
try {
|
|
781
193
|
return await (0, node_fs_promises.readFile)((0, node_path.resolve)(key), "utf8");
|
|
782
|
-
} catch (
|
|
783
|
-
|
|
784
|
-
throw new Error(`Failed to read storage item "${key}"`, { cause: error });
|
|
194
|
+
} catch (_error) {
|
|
195
|
+
return null;
|
|
785
196
|
}
|
|
786
197
|
},
|
|
787
198
|
async setItem(key, value) {
|
|
@@ -791,23 +202,22 @@ const fsStorage = createStorage(() => ({
|
|
|
791
202
|
await (0, node_fs_promises.rm)((0, node_path.resolve)(key), { force: true });
|
|
792
203
|
},
|
|
793
204
|
async getKeys(base) {
|
|
794
|
-
const keys = [];
|
|
795
205
|
const resolvedBase = (0, node_path.resolve)(base ?? process.cwd());
|
|
796
|
-
async function walk(dir, prefix) {
|
|
206
|
+
async function* walk(dir, prefix) {
|
|
797
207
|
let entries;
|
|
798
208
|
try {
|
|
799
209
|
entries = await (0, node_fs_promises.readdir)(dir, { withFileTypes: true });
|
|
800
|
-
} catch (
|
|
801
|
-
|
|
802
|
-
throw new Error(`Failed to list storage keys under "${resolvedBase}"`, { cause: error });
|
|
210
|
+
} catch (_error) {
|
|
211
|
+
return;
|
|
803
212
|
}
|
|
804
213
|
for (const entry of entries) {
|
|
805
214
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
806
|
-
if (entry.isDirectory())
|
|
807
|
-
else
|
|
215
|
+
if (entry.isDirectory()) yield* walk((0, node_path.join)(dir, entry.name), rel);
|
|
216
|
+
else yield rel;
|
|
808
217
|
}
|
|
809
218
|
}
|
|
810
|
-
|
|
219
|
+
const keys = [];
|
|
220
|
+
for await (const key of walk(resolvedBase, "")) keys.push(key);
|
|
811
221
|
return keys;
|
|
812
222
|
},
|
|
813
223
|
async clear(base) {
|
|
@@ -816,475 +226,272 @@ const fsStorage = createStorage(() => ({
|
|
|
816
226
|
}
|
|
817
227
|
}));
|
|
818
228
|
//#endregion
|
|
819
|
-
//#region
|
|
820
|
-
var version = "5.0.0-beta.3";
|
|
821
|
-
//#endregion
|
|
822
|
-
//#region src/utils/diagnostics.ts
|
|
229
|
+
//#region src/createKubb.ts
|
|
823
230
|
/**
|
|
824
|
-
*
|
|
825
|
-
*
|
|
826
|
-
*
|
|
827
|
-
*
|
|
231
|
+
* Builds a `Storage` view scoped to the file paths produced by the current build.
|
|
232
|
+
* Reads delegate to the underlying `storage` so source bytes stay where they were
|
|
233
|
+
* written; writes register the key so subsequent reads and `getKeys` are scoped
|
|
234
|
+
* to this build's output.
|
|
828
235
|
*/
|
|
829
|
-
function
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
` • Output: ${userConfig.output?.path || "not specified"}`,
|
|
857
|
-
` • Plugins: ${userConfig.plugins?.length || 0}`,
|
|
858
|
-
"Output Settings:",
|
|
859
|
-
` • Storage: ${userConfig.storage ? `custom(${userConfig.storage.name})` : userConfig.output?.write === false ? "disabled" : "filesystem (default)"}`,
|
|
860
|
-
` • Formatter: ${userConfig.output?.format || "none"}`,
|
|
861
|
-
` • Linter: ${userConfig.output?.lint || "none"}`,
|
|
862
|
-
"Environment:",
|
|
863
|
-
Object.entries(diagnosticInfo).map(([key, value]) => ` • ${key}: ${value}`).join("\n")
|
|
864
|
-
]
|
|
865
|
-
});
|
|
866
|
-
try {
|
|
867
|
-
if (isInputPath(userConfig) && !new URLPath(userConfig.input.path).isURL) {
|
|
868
|
-
await exists(userConfig.input.path);
|
|
869
|
-
await hooks.emit("kubb:debug", {
|
|
870
|
-
date: /* @__PURE__ */ new Date(),
|
|
871
|
-
logs: [`✓ Input file validated: ${userConfig.input.path}`]
|
|
872
|
-
});
|
|
873
|
-
}
|
|
874
|
-
} catch (caughtError) {
|
|
875
|
-
if (isInputPath(userConfig)) {
|
|
876
|
-
const error = caughtError;
|
|
877
|
-
throw new Error(`Cannot read file/URL defined in \`input.path\` or set with \`kubb generate PATH\` in the CLI of your Kubb config ${userConfig.input.path}`, { cause: error });
|
|
236
|
+
function createSourcesView(storage) {
|
|
237
|
+
const paths = /* @__PURE__ */ new Set();
|
|
238
|
+
return createStorage(() => ({
|
|
239
|
+
name: `${storage.name}:sources`,
|
|
240
|
+
async hasItem(key) {
|
|
241
|
+
return paths.has(key) && await storage.hasItem(key);
|
|
242
|
+
},
|
|
243
|
+
async getItem(key) {
|
|
244
|
+
return paths.has(key) ? storage.getItem(key) : null;
|
|
245
|
+
},
|
|
246
|
+
async setItem(key, value) {
|
|
247
|
+
paths.add(key);
|
|
248
|
+
await storage.setItem(key, value);
|
|
249
|
+
},
|
|
250
|
+
async removeItem(key) {
|
|
251
|
+
paths.delete(key);
|
|
252
|
+
await storage.removeItem(key);
|
|
253
|
+
},
|
|
254
|
+
async getKeys(base) {
|
|
255
|
+
if (!base) return [...paths];
|
|
256
|
+
const result = [];
|
|
257
|
+
for (const key of paths) if (key.startsWith(base)) result.push(key);
|
|
258
|
+
return result;
|
|
259
|
+
},
|
|
260
|
+
async clear() {
|
|
261
|
+
paths.clear();
|
|
262
|
+
await storage.clear();
|
|
878
263
|
}
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
|
|
264
|
+
}))();
|
|
265
|
+
}
|
|
266
|
+
function resolveConfig(userConfig) {
|
|
267
|
+
return {
|
|
882
268
|
...userConfig,
|
|
883
269
|
root: userConfig.root || process.cwd(),
|
|
884
270
|
parsers: userConfig.parsers ?? [],
|
|
885
|
-
adapter: userConfig.adapter,
|
|
886
271
|
output: {
|
|
887
272
|
format: false,
|
|
888
273
|
lint: false,
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
defaultBanner: require_PluginDriver.DEFAULT_BANNER,
|
|
274
|
+
extension: require_KubbDriver.DEFAULT_EXTENSION,
|
|
275
|
+
defaultBanner: require_KubbDriver.DEFAULT_BANNER,
|
|
892
276
|
...userConfig.output
|
|
893
277
|
},
|
|
278
|
+
storage: userConfig.storage ?? fsStorage(),
|
|
894
279
|
devtools: userConfig.devtools ? {
|
|
895
|
-
studioUrl:
|
|
280
|
+
studioUrl: require_KubbDriver.DEFAULT_STUDIO_URL,
|
|
896
281
|
...typeof userConfig.devtools === "boolean" ? {} : userConfig.devtools
|
|
897
282
|
} : void 0,
|
|
898
|
-
plugins: userConfig.plugins
|
|
283
|
+
plugins: userConfig.plugins ?? []
|
|
899
284
|
};
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
const driver = new require_PluginDriver.PluginDriver(config, { hooks });
|
|
909
|
-
function registerMiddlewareHook(event, middlewareHooks) {
|
|
910
|
-
const handler = middlewareHooks[event];
|
|
911
|
-
if (handler) hooks.on(event, handler);
|
|
912
|
-
}
|
|
913
|
-
for (const middleware of config.middleware ?? []) for (const event of Object.keys(middleware.hooks)) registerMiddlewareHook(event, middleware.hooks);
|
|
914
|
-
const adapter = config.adapter;
|
|
915
|
-
if (!adapter) throw new Error("No adapter configured. Please provide an adapter in your kubb.config.ts.");
|
|
916
|
-
const source = inputToAdapterSource(config);
|
|
917
|
-
await hooks.emit("kubb:debug", {
|
|
918
|
-
date: /* @__PURE__ */ new Date(),
|
|
919
|
-
logs: [`Running adapter: ${adapter.name}`]
|
|
920
|
-
});
|
|
921
|
-
driver.adapter = adapter;
|
|
922
|
-
driver.inputNode = await adapter.parse(source);
|
|
923
|
-
await hooks.emit("kubb:debug", {
|
|
924
|
-
date: /* @__PURE__ */ new Date(),
|
|
925
|
-
logs: [
|
|
926
|
-
`✓ Adapter '${adapter.name}' resolved InputNode`,
|
|
927
|
-
` • Schemas: ${driver.inputNode.schemas.length}`,
|
|
928
|
-
` • Operations: ${driver.inputNode.operations.length}`
|
|
929
|
-
]
|
|
930
|
-
});
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Returns a snapshot of the current runtime environment.
|
|
288
|
+
*
|
|
289
|
+
* Useful for attaching context to debug logs and error reports so that
|
|
290
|
+
* issues can be reproduced without manual information gathering.
|
|
291
|
+
*/
|
|
292
|
+
function getDiagnosticInfo() {
|
|
931
293
|
return {
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
294
|
+
nodeVersion: node_process.version,
|
|
295
|
+
KubbVersion: version,
|
|
296
|
+
platform: process.platform,
|
|
297
|
+
arch: process.arch,
|
|
298
|
+
cwd: process.cwd()
|
|
937
299
|
};
|
|
938
300
|
}
|
|
301
|
+
function isInputPath(config) {
|
|
302
|
+
return typeof config?.input === "object" && config.input !== null && "path" in config.input;
|
|
303
|
+
}
|
|
939
304
|
/**
|
|
940
|
-
*
|
|
941
|
-
* (`
|
|
305
|
+
* Kubb code-generation instance bound to a single config entry. Resolves the user
|
|
306
|
+
* config during `setup()` and shares `hooks`, `storage`, `driver`, and `config` across
|
|
307
|
+
* the `setup → build` lifecycle.
|
|
308
|
+
*
|
|
309
|
+
* Attach event listeners to `.hooks` before calling `setup()` or `build()`.
|
|
942
310
|
*
|
|
943
|
-
*
|
|
944
|
-
*
|
|
945
|
-
*
|
|
946
|
-
*
|
|
947
|
-
*
|
|
311
|
+
* @example
|
|
312
|
+
* ```ts
|
|
313
|
+
* const kubb = createKubb(userConfig)
|
|
314
|
+
* kubb.hooks.on('kubb:plugin:end', ({ plugin, duration }) => console.log(plugin.name, duration))
|
|
315
|
+
* const { files, failedPlugins } = await kubb.safeBuild()
|
|
316
|
+
* ```
|
|
948
317
|
*/
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
318
|
+
var Kubb = class {
|
|
319
|
+
hooks;
|
|
320
|
+
#userConfig;
|
|
321
|
+
#config = null;
|
|
322
|
+
#driver = null;
|
|
323
|
+
#storage = null;
|
|
324
|
+
constructor(userConfig, options = {}) {
|
|
325
|
+
this.#userConfig = userConfig;
|
|
326
|
+
this.hooks = options.hooks ?? new require_KubbDriver.AsyncEventEmitter();
|
|
327
|
+
}
|
|
328
|
+
get storage() {
|
|
329
|
+
if (!this.#storage) throw new Error("[kubb] setup() must be called before accessing storage");
|
|
330
|
+
return this.#storage;
|
|
331
|
+
}
|
|
332
|
+
get driver() {
|
|
333
|
+
if (!this.#driver) throw new Error("[kubb] setup() must be called before accessing driver");
|
|
334
|
+
return this.#driver;
|
|
335
|
+
}
|
|
336
|
+
get config() {
|
|
337
|
+
if (!this.#config) throw new Error("[kubb] setup() must be called before accessing config");
|
|
338
|
+
return this.#config;
|
|
955
339
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
"
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
if (hasOperationBasedIncludes && !hasSchemaNameIncludes) allowedSchemaNames = (0, _kubb_ast.collectUsedSchemaNames)(inputNode.operations.filter((op) => resolver.resolveOptions(op, {
|
|
973
|
-
options: plugin.options,
|
|
974
|
-
exclude,
|
|
975
|
-
include,
|
|
976
|
-
override
|
|
977
|
-
}) !== null), inputNode.schemas);
|
|
978
|
-
await (0, _kubb_ast.walk)(inputNode, {
|
|
979
|
-
depth: "shallow",
|
|
980
|
-
async schema(node) {
|
|
981
|
-
const transformedNode = plugin.transformer ? (0, _kubb_ast.transform)(node, plugin.transformer) : node;
|
|
982
|
-
if (allowedSchemaNames !== void 0 && transformedNode.name && !allowedSchemaNames.has(transformedNode.name)) return;
|
|
983
|
-
const options = resolver.resolveOptions(transformedNode, {
|
|
984
|
-
options: plugin.options,
|
|
985
|
-
exclude,
|
|
986
|
-
include,
|
|
987
|
-
override
|
|
340
|
+
/**
|
|
341
|
+
* Resolves config and initializes the driver. `build()` calls this automatically.
|
|
342
|
+
*/
|
|
343
|
+
async setup() {
|
|
344
|
+
const config = resolveConfig(this.#userConfig);
|
|
345
|
+
const driver = new require_KubbDriver.KubbDriver(config, { hooks: this.hooks });
|
|
346
|
+
const storage = createSourcesView(config.storage);
|
|
347
|
+
await this.hooks.emit("kubb:debug", {
|
|
348
|
+
date: /* @__PURE__ */ new Date(),
|
|
349
|
+
logs: this.#configLogs(config)
|
|
350
|
+
});
|
|
351
|
+
if (isInputPath(this.#userConfig) && !new require_KubbDriver.URLPath(this.#userConfig.input.path).isURL) try {
|
|
352
|
+
await exists(this.#userConfig.input.path);
|
|
353
|
+
await this.hooks.emit("kubb:debug", {
|
|
354
|
+
date: /* @__PURE__ */ new Date(),
|
|
355
|
+
logs: [`✓ Input file validated: ${this.#userConfig.input.path}`]
|
|
988
356
|
});
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
await require_PluginDriver.applyHookResult(await gen.schema(transformedNode, ctx), driver, resolveRenderer(gen));
|
|
997
|
-
}
|
|
998
|
-
await driver.hooks.emit("kubb:generate:schema", transformedNode, ctx);
|
|
999
|
-
},
|
|
1000
|
-
async operation(node) {
|
|
1001
|
-
const transformedNode = plugin.transformer ? (0, _kubb_ast.transform)(node, plugin.transformer) : node;
|
|
1002
|
-
const options = resolver.resolveOptions(transformedNode, {
|
|
1003
|
-
options: plugin.options,
|
|
1004
|
-
exclude,
|
|
1005
|
-
include,
|
|
1006
|
-
override
|
|
357
|
+
} catch (caughtError) {
|
|
358
|
+
throw new Error(`Cannot read file/URL defined in \`input.path\` or set with \`kubb generate PATH\` in the CLI of your Kubb config ${this.#userConfig.input.path}`, { cause: caughtError });
|
|
359
|
+
}
|
|
360
|
+
if (config.output.clean) {
|
|
361
|
+
await this.hooks.emit("kubb:debug", {
|
|
362
|
+
date: /* @__PURE__ */ new Date(),
|
|
363
|
+
logs: ["Cleaning output directories", ` • Output: ${config.output.path}`]
|
|
1007
364
|
});
|
|
1008
|
-
|
|
1009
|
-
collectedOperations.push(transformedNode);
|
|
1010
|
-
const ctx = {
|
|
1011
|
-
...generatorContext,
|
|
1012
|
-
options
|
|
1013
|
-
};
|
|
1014
|
-
for (const gen of generators) {
|
|
1015
|
-
if (!gen.operation) continue;
|
|
1016
|
-
await require_PluginDriver.applyHookResult(await gen.operation(transformedNode, ctx), driver, resolveRenderer(gen));
|
|
1017
|
-
}
|
|
1018
|
-
await driver.hooks.emit("kubb:generate:operation", transformedNode, ctx);
|
|
1019
|
-
}
|
|
365
|
+
await config.storage.clear((0, node_path.resolve)(config.root, config.output.path));
|
|
1020
366
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
367
|
+
await driver.setup();
|
|
368
|
+
this.#config = config;
|
|
369
|
+
this.#driver = driver;
|
|
370
|
+
this.#storage = storage;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Runs the full pipeline and throws on any plugin error.
|
|
374
|
+
* Automatically calls `setup()` if needed.
|
|
375
|
+
*/
|
|
376
|
+
async build() {
|
|
377
|
+
const out = await this.safeBuild();
|
|
378
|
+
if (out.error) throw out.error;
|
|
379
|
+
if (out.failedPlugins.size > 0) {
|
|
380
|
+
const errors = [...out.failedPlugins].map(({ error }) => error);
|
|
381
|
+
throw new require_KubbDriver.BuildError(`Build Error with ${out.failedPlugins.size} failed plugins`, { errors });
|
|
1030
382
|
}
|
|
1031
|
-
|
|
383
|
+
return out;
|
|
1032
384
|
}
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
await hooks.emit("kubb:debug", {
|
|
1058
|
-
date: timestamp,
|
|
1059
|
-
logs: ["Starting plugin...", ` • Plugin Name: ${plugin.name}`]
|
|
1060
|
-
});
|
|
1061
|
-
if (plugin.generators?.length || driver.hasRegisteredGenerators(plugin.name)) await runPluginAstHooks(plugin, context);
|
|
1062
|
-
const duration = getElapsedMs(hrStart);
|
|
1063
|
-
pluginTimings.set(plugin.name, duration);
|
|
1064
|
-
await hooks.emit("kubb:plugin:end", {
|
|
1065
|
-
plugin,
|
|
1066
|
-
duration,
|
|
1067
|
-
success: true,
|
|
1068
|
-
config,
|
|
1069
|
-
get files() {
|
|
1070
|
-
return driver.fileManager.files;
|
|
1071
|
-
},
|
|
1072
|
-
upsertFile: (...files) => driver.fileManager.upsert(...files)
|
|
1073
|
-
});
|
|
1074
|
-
await hooks.emit("kubb:debug", {
|
|
1075
|
-
date: /* @__PURE__ */ new Date(),
|
|
1076
|
-
logs: [`✓ Plugin started successfully (${formatMs(duration)})`]
|
|
1077
|
-
});
|
|
1078
|
-
} catch (caughtError) {
|
|
1079
|
-
const error = caughtError;
|
|
1080
|
-
const errorTimestamp = /* @__PURE__ */ new Date();
|
|
1081
|
-
const duration = getElapsedMs(hrStart);
|
|
1082
|
-
await hooks.emit("kubb:plugin:end", {
|
|
1083
|
-
plugin,
|
|
1084
|
-
duration,
|
|
1085
|
-
success: false,
|
|
1086
|
-
error,
|
|
1087
|
-
config,
|
|
1088
|
-
get files() {
|
|
1089
|
-
return driver.fileManager.files;
|
|
1090
|
-
},
|
|
1091
|
-
upsertFile: (...files) => driver.fileManager.upsert(...files)
|
|
1092
|
-
});
|
|
1093
|
-
await hooks.emit("kubb:debug", {
|
|
1094
|
-
date: errorTimestamp,
|
|
1095
|
-
logs: [
|
|
1096
|
-
"✗ Plugin start failed",
|
|
1097
|
-
` • Plugin Name: ${plugin.name}`,
|
|
1098
|
-
` • Error: ${error.constructor.name} - ${error.message}`,
|
|
1099
|
-
" • Stack Trace:",
|
|
1100
|
-
error.stack || "No stack trace available"
|
|
1101
|
-
]
|
|
1102
|
-
});
|
|
1103
|
-
failedPlugins.add({
|
|
1104
|
-
plugin,
|
|
1105
|
-
error
|
|
1106
|
-
});
|
|
1107
|
-
}
|
|
385
|
+
/**
|
|
386
|
+
* Runs the full pipeline and captures errors in `BuildOutput` instead of throwing.
|
|
387
|
+
* Automatically calls `setup()` if needed.
|
|
388
|
+
*/
|
|
389
|
+
async safeBuild() {
|
|
390
|
+
try {
|
|
391
|
+
var _usingCtx$1 = require_KubbDriver._usingCtx();
|
|
392
|
+
if (!this.#driver) await this.setup();
|
|
393
|
+
const cleanup = _usingCtx$1.u(this);
|
|
394
|
+
const driver = cleanup.driver;
|
|
395
|
+
const storage = cleanup.storage;
|
|
396
|
+
const { failedPlugins, pluginTimings, error } = await driver.run({ storage });
|
|
397
|
+
return {
|
|
398
|
+
failedPlugins,
|
|
399
|
+
files: driver.fileManager.files,
|
|
400
|
+
driver,
|
|
401
|
+
pluginTimings,
|
|
402
|
+
storage,
|
|
403
|
+
...error ? { error } : {}
|
|
404
|
+
};
|
|
405
|
+
} catch (_) {
|
|
406
|
+
_usingCtx$1.e = _;
|
|
407
|
+
} finally {
|
|
408
|
+
_usingCtx$1.d();
|
|
1108
409
|
}
|
|
1109
|
-
await hooks.emit("kubb:plugins:end", {
|
|
1110
|
-
config,
|
|
1111
|
-
get files() {
|
|
1112
|
-
return driver.fileManager.files;
|
|
1113
|
-
},
|
|
1114
|
-
upsertFile: (...files) => driver.fileManager.upsert(...files)
|
|
1115
|
-
});
|
|
1116
|
-
const files = driver.fileManager.files;
|
|
1117
|
-
const parsersMap = /* @__PURE__ */ new Map();
|
|
1118
|
-
for (const parser of config.parsers) if (parser.extNames) for (const extname of parser.extNames) parsersMap.set(extname, parser);
|
|
1119
|
-
const fileProcessor = new FileProcessor();
|
|
1120
|
-
await hooks.emit("kubb:debug", {
|
|
1121
|
-
date: /* @__PURE__ */ new Date(),
|
|
1122
|
-
logs: [`Writing ${files.length} files...`]
|
|
1123
|
-
});
|
|
1124
|
-
await fileProcessor.run(files, {
|
|
1125
|
-
parsers: parsersMap,
|
|
1126
|
-
extension: config.output.extension,
|
|
1127
|
-
onStart: async (processingFiles) => {
|
|
1128
|
-
await hooks.emit("kubb:files:processing:start", { files: processingFiles });
|
|
1129
|
-
},
|
|
1130
|
-
onUpdate: async ({ file, source, processed, total, percentage }) => {
|
|
1131
|
-
await hooks.emit("kubb:file:processing:update", {
|
|
1132
|
-
file,
|
|
1133
|
-
source,
|
|
1134
|
-
processed,
|
|
1135
|
-
total,
|
|
1136
|
-
percentage,
|
|
1137
|
-
config
|
|
1138
|
-
});
|
|
1139
|
-
if (source) {
|
|
1140
|
-
await storage?.setItem(file.path, source);
|
|
1141
|
-
sources.set(file.path, source);
|
|
1142
|
-
}
|
|
1143
|
-
},
|
|
1144
|
-
onEnd: async (processedFiles) => {
|
|
1145
|
-
await hooks.emit("kubb:files:processing:end", { files: processedFiles });
|
|
1146
|
-
await hooks.emit("kubb:debug", {
|
|
1147
|
-
date: /* @__PURE__ */ new Date(),
|
|
1148
|
-
logs: [`✓ File write process completed for ${processedFiles.length} files`]
|
|
1149
|
-
});
|
|
1150
|
-
}
|
|
1151
|
-
});
|
|
1152
|
-
await hooks.emit("kubb:build:end", {
|
|
1153
|
-
files,
|
|
1154
|
-
config,
|
|
1155
|
-
outputDir: (0, node_path.resolve)(config.root, config.output.path)
|
|
1156
|
-
});
|
|
1157
|
-
return {
|
|
1158
|
-
failedPlugins,
|
|
1159
|
-
files,
|
|
1160
|
-
driver,
|
|
1161
|
-
pluginTimings,
|
|
1162
|
-
sources
|
|
1163
|
-
};
|
|
1164
|
-
} catch (error) {
|
|
1165
|
-
return {
|
|
1166
|
-
failedPlugins,
|
|
1167
|
-
files: [],
|
|
1168
|
-
driver,
|
|
1169
|
-
pluginTimings,
|
|
1170
|
-
error,
|
|
1171
|
-
sources
|
|
1172
|
-
};
|
|
1173
|
-
} finally {
|
|
1174
|
-
driver.dispose();
|
|
1175
410
|
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
const { files, driver, failedPlugins, pluginTimings, error, sources } = await safeBuild(setupResult);
|
|
1179
|
-
if (error) throw error;
|
|
1180
|
-
if (failedPlugins.size > 0) {
|
|
1181
|
-
const errors = [...failedPlugins].map(({ error }) => error);
|
|
1182
|
-
throw new BuildError(`Build Error with ${failedPlugins.size} failed plugins`, { errors });
|
|
411
|
+
dispose() {
|
|
412
|
+
this.#driver?.dispose();
|
|
1183
413
|
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
return {
|
|
1207
|
-
type: "path",
|
|
1208
|
-
path: (0, node_path.resolve)(config.root, config.input.path)
|
|
1209
|
-
};
|
|
1210
|
-
}
|
|
414
|
+
[Symbol.dispose]() {
|
|
415
|
+
this.dispose();
|
|
416
|
+
}
|
|
417
|
+
#configLogs(config) {
|
|
418
|
+
const u = this.#userConfig;
|
|
419
|
+
const diag = getDiagnosticInfo();
|
|
420
|
+
return [
|
|
421
|
+
"Configuration:",
|
|
422
|
+
` • Name: ${u.name || "unnamed"}`,
|
|
423
|
+
` • Root: ${u.root || process.cwd()}`,
|
|
424
|
+
` • Output: ${u.output?.path || "not specified"}`,
|
|
425
|
+
` • Plugins: ${u.plugins?.length || 0}`,
|
|
426
|
+
"Output Settings:",
|
|
427
|
+
` • Storage: ${config.storage.name}`,
|
|
428
|
+
` • Formatter: ${u.output?.format || "none"}`,
|
|
429
|
+
` • Linter: ${u.output?.lint || "none"}`,
|
|
430
|
+
`Running adapter: ${config.adapter?.name || "none"}`,
|
|
431
|
+
"Environment:",
|
|
432
|
+
Object.entries(diag).map(([key, value]) => ` • ${key}: ${value}`).join("\n")
|
|
433
|
+
];
|
|
434
|
+
}
|
|
435
|
+
};
|
|
1211
436
|
/**
|
|
1212
|
-
*
|
|
1213
|
-
*
|
|
1214
|
-
* Accepts a user-facing config shape and resolves it to a full {@link Config} during
|
|
1215
|
-
* `setup()`. The instance then holds shared state (`hooks`, `sources`, `driver`, `config`)
|
|
1216
|
-
* across the `setup → build` lifecycle. Attach event listeners to `kubb.hooks` before
|
|
1217
|
-
* calling `setup()` or `build()`.
|
|
437
|
+
* Constructs a {@link Kubb} build orchestrator from a user config. Equivalent
|
|
438
|
+
* to `new Kubb(userConfig, options)` and the canonical public entry point.
|
|
1218
439
|
*
|
|
1219
440
|
* @example
|
|
1220
441
|
* ```ts
|
|
1221
|
-
*
|
|
442
|
+
* import { createKubb } from '@kubb/core'
|
|
443
|
+
* import { adapterOas } from '@kubb/adapter-oas'
|
|
444
|
+
* import { pluginTs } from '@kubb/plugin-ts'
|
|
1222
445
|
*
|
|
1223
|
-
* kubb
|
|
1224
|
-
*
|
|
446
|
+
* const kubb = createKubb({
|
|
447
|
+
* input: { path: './petStore.yaml' },
|
|
448
|
+
* output: { path: './src/gen' },
|
|
449
|
+
* adapter: adapterOas(),
|
|
450
|
+
* plugins: [pluginTs()],
|
|
1225
451
|
* })
|
|
1226
452
|
*
|
|
1227
|
-
*
|
|
453
|
+
* await kubb.build()
|
|
1228
454
|
* ```
|
|
1229
455
|
*/
|
|
1230
456
|
function createKubb(userConfig, options = {}) {
|
|
1231
|
-
|
|
1232
|
-
let setupResult;
|
|
1233
|
-
const instance = {
|
|
1234
|
-
get hooks() {
|
|
1235
|
-
return hooks;
|
|
1236
|
-
},
|
|
1237
|
-
get sources() {
|
|
1238
|
-
return setupResult?.sources ?? /* @__PURE__ */ new Map();
|
|
1239
|
-
},
|
|
1240
|
-
get driver() {
|
|
1241
|
-
return setupResult?.driver;
|
|
1242
|
-
},
|
|
1243
|
-
get config() {
|
|
1244
|
-
return setupResult?.config;
|
|
1245
|
-
},
|
|
1246
|
-
async setup() {
|
|
1247
|
-
setupResult = await setup(userConfig, { hooks });
|
|
1248
|
-
},
|
|
1249
|
-
async build() {
|
|
1250
|
-
if (!setupResult) await instance.setup();
|
|
1251
|
-
return build(setupResult);
|
|
1252
|
-
},
|
|
1253
|
-
async safeBuild() {
|
|
1254
|
-
if (!setupResult) await instance.setup();
|
|
1255
|
-
return safeBuild(setupResult);
|
|
1256
|
-
}
|
|
1257
|
-
};
|
|
1258
|
-
return instance;
|
|
457
|
+
return new Kubb(userConfig, options);
|
|
1259
458
|
}
|
|
1260
459
|
//#endregion
|
|
1261
460
|
//#region src/createRenderer.ts
|
|
1262
461
|
/**
|
|
1263
|
-
*
|
|
462
|
+
* Defines a renderer factory. Renderers turn the generator's return value
|
|
463
|
+
* (JSX, a template string, a tree of any shape) into `FileNode`s that get
|
|
464
|
+
* written to disk.
|
|
1264
465
|
*
|
|
1265
|
-
*
|
|
1266
|
-
* renderer
|
|
1267
|
-
* to
|
|
466
|
+
* Use this to support output formats beyond JSX — for instance, a Handlebars
|
|
467
|
+
* renderer, a string-template renderer, or a renderer that writes binary
|
|
468
|
+
* files. Plugins and generators pick the renderer to use via the `renderer`
|
|
469
|
+
* field on `defineGenerator`.
|
|
1268
470
|
*
|
|
1269
|
-
* @example
|
|
471
|
+
* @example A minimal renderer that wraps a custom runtime
|
|
1270
472
|
* ```ts
|
|
1271
|
-
*
|
|
1272
|
-
*
|
|
1273
|
-
*
|
|
473
|
+
* import { createRenderer } from '@kubb/core'
|
|
474
|
+
*
|
|
475
|
+
* export const myRenderer = createRenderer(() => {
|
|
476
|
+
* const runtime = new MyRuntime()
|
|
1274
477
|
* return {
|
|
1275
|
-
* async render(element) {
|
|
1276
|
-
*
|
|
1277
|
-
*
|
|
478
|
+
* async render(element) {
|
|
479
|
+
* await runtime.render(element)
|
|
480
|
+
* },
|
|
481
|
+
* get files() {
|
|
482
|
+
* return runtime.files
|
|
483
|
+
* },
|
|
484
|
+
* dispose() {
|
|
485
|
+
* runtime.dispose()
|
|
486
|
+
* },
|
|
487
|
+
* unmount(error) {
|
|
488
|
+
* runtime.dispose(error)
|
|
489
|
+
* },
|
|
490
|
+
* [Symbol.dispose]() {
|
|
491
|
+
* this.dispose()
|
|
492
|
+
* },
|
|
1278
493
|
* }
|
|
1279
494
|
* })
|
|
1280
|
-
*
|
|
1281
|
-
* // packages/plugin-zod/src/generators/zodGenerator.tsx
|
|
1282
|
-
* import { jsxRenderer } from '@kubb/renderer-jsx'
|
|
1283
|
-
* export const zodGenerator = defineGenerator<PluginZod>({
|
|
1284
|
-
* name: 'zod',
|
|
1285
|
-
* renderer: jsxRenderer,
|
|
1286
|
-
* schema(node, options) { return <File ...>...</File> },
|
|
1287
|
-
* })
|
|
1288
495
|
* ```
|
|
1289
496
|
*/
|
|
1290
497
|
function createRenderer(factory) {
|
|
@@ -1293,9 +500,32 @@ function createRenderer(factory) {
|
|
|
1293
500
|
//#endregion
|
|
1294
501
|
//#region src/defineGenerator.ts
|
|
1295
502
|
/**
|
|
1296
|
-
* Defines a generator
|
|
1297
|
-
*
|
|
1298
|
-
*
|
|
503
|
+
* Defines a generator: a unit of work that runs during the plugin's AST walk
|
|
504
|
+
* and produces files. Plugins register generators via `ctx.addGenerator()`
|
|
505
|
+
* inside `kubb:plugin:setup`.
|
|
506
|
+
*
|
|
507
|
+
* The returned object is the input as-is, but with `this` types preserved so
|
|
508
|
+
* `schema`/`operation`/`operations` methods are correctly typed against the
|
|
509
|
+
* plugin's `PluginFactoryOptions`. Renderer elements and `FileNode[]` returns
|
|
510
|
+
* are both handled by the runtime — pick whichever style fits.
|
|
511
|
+
*
|
|
512
|
+
* @example JSX-based schema generator
|
|
513
|
+
* ```tsx
|
|
514
|
+
* import { defineGenerator } from '@kubb/core'
|
|
515
|
+
* import { jsxRenderer } from '@kubb/renderer-jsx'
|
|
516
|
+
*
|
|
517
|
+
* export const typeGenerator = defineGenerator({
|
|
518
|
+
* name: 'typescript',
|
|
519
|
+
* renderer: jsxRenderer,
|
|
520
|
+
* schema(node, ctx) {
|
|
521
|
+
* return (
|
|
522
|
+
* <File path={`${ctx.root}/${node.name}.ts`}>
|
|
523
|
+
* <Type node={node} resolver={ctx.resolver} />
|
|
524
|
+
* </File>
|
|
525
|
+
* )
|
|
526
|
+
* },
|
|
527
|
+
* })
|
|
528
|
+
* ```
|
|
1299
529
|
*/
|
|
1300
530
|
function defineGenerator(generator) {
|
|
1301
531
|
return generator;
|
|
@@ -1303,15 +533,33 @@ function defineGenerator(generator) {
|
|
|
1303
533
|
//#endregion
|
|
1304
534
|
//#region src/defineLogger.ts
|
|
1305
535
|
/**
|
|
1306
|
-
*
|
|
536
|
+
* Defines a typed logger. Use the second type parameter to declare a return
|
|
537
|
+
* value from `install`, which is handy when the logger exposes a sink factory
|
|
538
|
+
* or cleanup callback to the caller.
|
|
1307
539
|
*
|
|
1308
|
-
* @example
|
|
540
|
+
* @example Basic logger
|
|
1309
541
|
* ```ts
|
|
542
|
+
* import { defineLogger } from '@kubb/core'
|
|
543
|
+
*
|
|
1310
544
|
* export const myLogger = defineLogger({
|
|
1311
545
|
* name: 'my-logger',
|
|
1312
|
-
* install(context
|
|
1313
|
-
* context.on('kubb:info', (message) => console.log('ℹ', message))
|
|
1314
|
-
* context.on('kubb:error', (error) => console.error('✗', error.message))
|
|
546
|
+
* install(context) {
|
|
547
|
+
* context.on('kubb:info', ({ message }) => console.log('ℹ', message))
|
|
548
|
+
* context.on('kubb:error', ({ error }) => console.error('✗', error.message))
|
|
549
|
+
* },
|
|
550
|
+
* })
|
|
551
|
+
* ```
|
|
552
|
+
*
|
|
553
|
+
* @example Logger that returns a hook sink factory
|
|
554
|
+
* ```ts
|
|
555
|
+
* import { defineLogger, type LoggerOptions } from '@kubb/core'
|
|
556
|
+
* import type { HookSinkFactory } from './sinks'
|
|
557
|
+
*
|
|
558
|
+
* export const myLogger = defineLogger<LoggerOptions, HookSinkFactory>({
|
|
559
|
+
* name: 'my-logger',
|
|
560
|
+
* install(context) {
|
|
561
|
+
* // … register event handlers …
|
|
562
|
+
* return () => ({ onStdout: console.log })
|
|
1315
563
|
* },
|
|
1316
564
|
* })
|
|
1317
565
|
* ```
|
|
@@ -1322,18 +570,17 @@ function defineLogger(logger) {
|
|
|
1322
570
|
//#endregion
|
|
1323
571
|
//#region src/defineMiddleware.ts
|
|
1324
572
|
/**
|
|
1325
|
-
* Creates a middleware factory
|
|
573
|
+
* Creates a middleware factory. Middleware fires after every plugin handler
|
|
574
|
+
* for the same event, which makes it the natural place for post-processing
|
|
575
|
+
* (barrel files, lint runs, audit logs).
|
|
1326
576
|
*
|
|
1327
|
-
*
|
|
1328
|
-
*
|
|
577
|
+
* Per-build state belongs inside the factory closure so each `createKubb`
|
|
578
|
+
* invocation gets its own isolated instance.
|
|
1329
579
|
*
|
|
1330
|
-
* @
|
|
1331
|
-
*
|
|
1332
|
-
* @example
|
|
580
|
+
* @example Stateless middleware
|
|
1333
581
|
* ```ts
|
|
1334
582
|
* import { defineMiddleware } from '@kubb/core'
|
|
1335
583
|
*
|
|
1336
|
-
* // Stateless middleware
|
|
1337
584
|
* export const logMiddleware = defineMiddleware(() => ({
|
|
1338
585
|
* name: 'log-middleware',
|
|
1339
586
|
* hooks: {
|
|
@@ -1342,8 +589,12 @@ function defineLogger(logger) {
|
|
|
1342
589
|
* },
|
|
1343
590
|
* },
|
|
1344
591
|
* }))
|
|
592
|
+
* ```
|
|
593
|
+
*
|
|
594
|
+
* @example Middleware with options and per-build state
|
|
595
|
+
* ```ts
|
|
596
|
+
* import { defineMiddleware } from '@kubb/core'
|
|
1345
597
|
*
|
|
1346
|
-
* // Middleware with options and per-build state
|
|
1347
598
|
* export const prefixMiddleware = defineMiddleware((options: { prefix: string } = { prefix: '' }) => {
|
|
1348
599
|
* const seen = new Set<string>()
|
|
1349
600
|
* return {
|
|
@@ -1363,20 +614,23 @@ function defineMiddleware(factory) {
|
|
|
1363
614
|
//#endregion
|
|
1364
615
|
//#region src/defineParser.ts
|
|
1365
616
|
/**
|
|
1366
|
-
* Defines a parser with type
|
|
1367
|
-
*
|
|
1368
|
-
* @note Call the returned factory with optional options to instantiate the parser.
|
|
617
|
+
* Defines a parser with type-safe `this`. Used to register handlers for new
|
|
618
|
+
* file extensions or to plug a non-TypeScript output into the build.
|
|
1369
619
|
*
|
|
1370
620
|
* @example
|
|
1371
621
|
* ```ts
|
|
1372
|
-
* import { defineParser } from '@kubb/core'
|
|
622
|
+
* import { defineParser, ast } from '@kubb/core'
|
|
1373
623
|
*
|
|
1374
624
|
* export const jsonParser = defineParser({
|
|
1375
625
|
* name: 'json',
|
|
1376
626
|
* extNames: ['.json'],
|
|
1377
627
|
* parse(file) {
|
|
1378
|
-
*
|
|
1379
|
-
*
|
|
628
|
+
* return file.sources
|
|
629
|
+
* .map((source) => ast.extractStringsFromNodes(source.nodes ?? []))
|
|
630
|
+
* .join('\n')
|
|
631
|
+
* },
|
|
632
|
+
* print(...nodes) {
|
|
633
|
+
* return nodes.map(String).join('\n')
|
|
1380
634
|
* },
|
|
1381
635
|
* })
|
|
1382
636
|
* ```
|
|
@@ -1385,34 +639,6 @@ function defineParser(parser) {
|
|
|
1385
639
|
return parser;
|
|
1386
640
|
}
|
|
1387
641
|
//#endregion
|
|
1388
|
-
//#region src/definePlugin.ts
|
|
1389
|
-
/**
|
|
1390
|
-
* Wraps a factory function and returns a typed `Plugin` with lifecycle handlers grouped under `hooks`.
|
|
1391
|
-
*
|
|
1392
|
-
* Handlers live in a single `hooks` object (inspired by Astro integrations).
|
|
1393
|
-
* All lifecycle events from `KubbHooks` are available for subscription.
|
|
1394
|
-
*
|
|
1395
|
-
* @note For real plugins, use a `PluginFactoryOptions` type parameter to get type-safe context in `kubb:plugin:setup`.
|
|
1396
|
-
* Plugin names should follow the convention `plugin-<feature>` (e.g., `plugin-react-query`, `plugin-zod`).
|
|
1397
|
-
*
|
|
1398
|
-
* @example
|
|
1399
|
-
* ```ts
|
|
1400
|
-
* import { definePlugin } from '@kubb/core'
|
|
1401
|
-
*
|
|
1402
|
-
* export const pluginTs = definePlugin((options: { prefix?: string } = {}) => ({
|
|
1403
|
-
* name: 'plugin-ts',
|
|
1404
|
-
* hooks: {
|
|
1405
|
-
* 'kubb:plugin:setup'(ctx) {
|
|
1406
|
-
* ctx.setResolver(resolverTs)
|
|
1407
|
-
* },
|
|
1408
|
-
* },
|
|
1409
|
-
* }))
|
|
1410
|
-
* ```
|
|
1411
|
-
*/
|
|
1412
|
-
function definePlugin(factory) {
|
|
1413
|
-
return (options) => factory(options ?? {});
|
|
1414
|
-
}
|
|
1415
|
-
//#endregion
|
|
1416
642
|
//#region src/storages/memoryStorage.ts
|
|
1417
643
|
/**
|
|
1418
644
|
* In-memory storage driver. Useful for testing and dry-run scenarios where
|
|
@@ -1463,11 +689,11 @@ const memoryStorage = createStorage(() => {
|
|
|
1463
689
|
};
|
|
1464
690
|
});
|
|
1465
691
|
//#endregion
|
|
1466
|
-
exports.AsyncEventEmitter = AsyncEventEmitter;
|
|
1467
|
-
exports.FileManager =
|
|
1468
|
-
exports.FileProcessor = FileProcessor;
|
|
1469
|
-
exports.
|
|
1470
|
-
exports.URLPath = URLPath;
|
|
692
|
+
exports.AsyncEventEmitter = require_KubbDriver.AsyncEventEmitter;
|
|
693
|
+
exports.FileManager = require_KubbDriver.FileManager;
|
|
694
|
+
exports.FileProcessor = require_KubbDriver.FileProcessor;
|
|
695
|
+
exports.KubbDriver = require_KubbDriver.KubbDriver;
|
|
696
|
+
exports.URLPath = require_KubbDriver.URLPath;
|
|
1471
697
|
Object.defineProperty(exports, "ast", {
|
|
1472
698
|
enumerable: true,
|
|
1473
699
|
get: function() {
|
|
@@ -1482,11 +708,11 @@ exports.defineGenerator = defineGenerator;
|
|
|
1482
708
|
exports.defineLogger = defineLogger;
|
|
1483
709
|
exports.defineMiddleware = defineMiddleware;
|
|
1484
710
|
exports.defineParser = defineParser;
|
|
1485
|
-
exports.definePlugin = definePlugin;
|
|
1486
|
-
exports.defineResolver =
|
|
711
|
+
exports.definePlugin = require_KubbDriver.definePlugin;
|
|
712
|
+
exports.defineResolver = require_KubbDriver.defineResolver;
|
|
1487
713
|
exports.fsStorage = fsStorage;
|
|
1488
714
|
exports.isInputPath = isInputPath;
|
|
1489
|
-
exports.logLevel =
|
|
715
|
+
exports.logLevel = require_KubbDriver.logLevel;
|
|
1490
716
|
exports.memoryStorage = memoryStorage;
|
|
1491
717
|
|
|
1492
718
|
//# sourceMappingURL=index.cjs.map
|