@kubb/core 5.0.0-beta.6 → 5.0.0-beta.61
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/LICENSE +17 -10
- package/README.md +25 -158
- package/dist/diagnostics-DiaUv_iK.d.ts +2904 -0
- package/dist/index.cjs +2523 -1071
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +80 -273
- package/dist/index.js +2513 -1067
- package/dist/index.js.map +1 -1
- package/dist/memoryStorage-CUj1hrxa.cjs +823 -0
- package/dist/memoryStorage-CUj1hrxa.cjs.map +1 -0
- package/dist/memoryStorage-CWFzAz4o.js +714 -0
- package/dist/memoryStorage-CWFzAz4o.js.map +1 -0
- package/dist/mocks.cjs +83 -23
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.ts +36 -10
- package/dist/mocks.js +85 -27
- package/dist/mocks.js.map +1 -1
- package/package.json +8 -28
- package/src/FileManager.ts +86 -64
- package/src/FileProcessor.ts +170 -44
- package/src/KubbDriver.ts +909 -0
- package/src/Transform.ts +105 -0
- package/src/constants.ts +111 -20
- package/src/createAdapter.ts +112 -17
- package/src/createKubb.ts +140 -517
- package/src/createRenderer.ts +43 -28
- package/src/createReporter.ts +134 -0
- package/src/createStorage.ts +36 -23
- package/src/defineGenerator.ts +140 -17
- package/src/defineParser.ts +30 -12
- package/src/definePlugin.ts +375 -21
- package/src/defineResolver.ts +402 -212
- package/src/diagnostics.ts +662 -0
- package/src/index.ts +8 -8
- package/src/mocks.ts +97 -26
- package/src/reporters/cliReporter.ts +89 -0
- package/src/reporters/fileReporter.ts +103 -0
- package/src/reporters/jsonReporter.ts +20 -0
- package/src/reporters/report.ts +85 -0
- package/src/storages/fsStorage.ts +23 -55
- package/src/types.ts +411 -887
- package/dist/PluginDriver-BkTRD2H2.js +0 -946
- package/dist/PluginDriver-BkTRD2H2.js.map +0 -1
- package/dist/PluginDriver-Cadu4ORh.cjs +0 -1037
- package/dist/PluginDriver-Cadu4ORh.cjs.map +0 -1
- package/dist/types-DVPKmzw_.d.ts +0 -2159
- package/src/Kubb.ts +0 -300
- package/src/PluginDriver.ts +0 -426
- package/src/defineLogger.ts +0 -19
- package/src/defineMiddleware.ts +0 -62
- package/src/devtools.ts +0 -59
- 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/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
|
@@ -0,0 +1,823 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __name = (target, value) => __defProp(target, "name", {
|
|
5
|
+
value,
|
|
6
|
+
configurable: true
|
|
7
|
+
});
|
|
8
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
9
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
10
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
11
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
14
|
+
key = keys[i];
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
16
|
+
get: ((k) => from[k]).bind(null, key),
|
|
17
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
//#endregion
|
|
27
|
+
let node_events = require("node:events");
|
|
28
|
+
let _kubb_ast_factory = require("@kubb/ast/factory");
|
|
29
|
+
_kubb_ast_factory = __toESM(_kubb_ast_factory, 1);
|
|
30
|
+
let _kubb_ast_utils = require("@kubb/ast/utils");
|
|
31
|
+
//#region ../../internals/utils/src/errors.ts
|
|
32
|
+
/**
|
|
33
|
+
* Thrown when one or more errors occur during a Kubb build.
|
|
34
|
+
* Carries the full list of underlying errors on `errors`.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* throw new BuildError('Build failed', { errors: [err1, err2] })
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
var BuildError = class extends Error {
|
|
42
|
+
errors;
|
|
43
|
+
constructor(message, options) {
|
|
44
|
+
super(message, { cause: options.cause });
|
|
45
|
+
this.name = "BuildError";
|
|
46
|
+
this.errors = options.errors;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Coerces an unknown thrown value to an `Error` instance.
|
|
51
|
+
* Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* try { ... } catch(err) {
|
|
56
|
+
* throw new BuildError('Build failed', { cause: toError(err), errors: [] })
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
function toError(value) {
|
|
61
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Extracts a human-readable message from any thrown value.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* getErrorMessage(new Error('oops')) // 'oops'
|
|
69
|
+
* getErrorMessage('plain string') // 'plain string'
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
function getErrorMessage(value) {
|
|
73
|
+
return value instanceof Error ? value.message : String(value);
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region ../../internals/utils/src/asyncEventEmitter.ts
|
|
77
|
+
/**
|
|
78
|
+
* Typed `EventEmitter` that awaits all async listeners before resolving.
|
|
79
|
+
* Wraps Node's `EventEmitter` with full TypeScript event-map inference.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* const emitter = new AsyncEventEmitter<{ build: [name: string] }>()
|
|
84
|
+
* emitter.on('build', async (name) => { console.log(name) })
|
|
85
|
+
* await emitter.emit('build', 'petstore') // all listeners awaited
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
var AsyncEventEmitter = class {
|
|
89
|
+
/**
|
|
90
|
+
* Maximum number of listeners per event before Node emits a memory-leak warning.
|
|
91
|
+
* @default 10
|
|
92
|
+
*/
|
|
93
|
+
constructor(maxListener = 10) {
|
|
94
|
+
this.#emitter.setMaxListeners(maxListener);
|
|
95
|
+
}
|
|
96
|
+
#emitter = new node_events.EventEmitter();
|
|
97
|
+
/**
|
|
98
|
+
* Emits `eventName` and awaits all registered listeners sequentially.
|
|
99
|
+
* Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* await emitter.emit('build', 'petstore')
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
emit(eventName, ...eventArgs) {
|
|
107
|
+
const listeners = this.#emitter.listeners(eventName);
|
|
108
|
+
if (listeners.length === 0) return;
|
|
109
|
+
return this.#emitAll(eventName, listeners, eventArgs);
|
|
110
|
+
}
|
|
111
|
+
async #emitAll(eventName, listeners, eventArgs) {
|
|
112
|
+
for (const listener of listeners) try {
|
|
113
|
+
await listener(...eventArgs);
|
|
114
|
+
} catch (err) {
|
|
115
|
+
let serializedArgs;
|
|
116
|
+
try {
|
|
117
|
+
serializedArgs = JSON.stringify(eventArgs);
|
|
118
|
+
} catch {
|
|
119
|
+
serializedArgs = String(eventArgs);
|
|
120
|
+
}
|
|
121
|
+
throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Registers a persistent listener for `eventName`.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```ts
|
|
129
|
+
* emitter.on('build', async (name) => { console.log(name) })
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
on(eventName, handler) {
|
|
133
|
+
this.#emitter.on(eventName, handler);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Registers a one-shot listener that removes itself after the first invocation.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* emitter.onOnce('build', async (name) => { console.log(name) })
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
onOnce(eventName, handler) {
|
|
144
|
+
const wrapper = (...args) => {
|
|
145
|
+
this.off(eventName, wrapper);
|
|
146
|
+
return handler(...args);
|
|
147
|
+
};
|
|
148
|
+
this.on(eventName, wrapper);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Removes a previously registered listener.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```ts
|
|
155
|
+
* emitter.off('build', handler)
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
off(eventName, handler) {
|
|
159
|
+
this.#emitter.off(eventName, handler);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Returns the number of listeners registered for `eventName`.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* emitter.on('build', handler)
|
|
167
|
+
* emitter.listenerCount('build') // 1
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
listenerCount(eventName) {
|
|
171
|
+
return this.#emitter.listenerCount(eventName);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Raises or lowers the per-event listener ceiling before Node warns about a memory leak.
|
|
175
|
+
* Set this above the expected listener count when many listeners attach by design.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* emitter.setMaxListeners(40)
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
setMaxListeners(max) {
|
|
183
|
+
this.#emitter.setMaxListeners(max);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Returns the current per-event listener ceiling.
|
|
187
|
+
*/
|
|
188
|
+
getMaxListeners() {
|
|
189
|
+
return this.#emitter.getMaxListeners();
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Removes all listeners from every event channel.
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```ts
|
|
196
|
+
* emitter.removeAll()
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
removeAll() {
|
|
200
|
+
this.#emitter.removeAllListeners();
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
//#endregion
|
|
204
|
+
//#region ../../internals/utils/src/casing.ts
|
|
205
|
+
/**
|
|
206
|
+
* Shared implementation for camelCase and PascalCase conversion.
|
|
207
|
+
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
208
|
+
* and capitalizes each word according to `pascal`.
|
|
209
|
+
*
|
|
210
|
+
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
211
|
+
*/
|
|
212
|
+
function toCamelOrPascal(text, pascal) {
|
|
213
|
+
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
|
|
214
|
+
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
215
|
+
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
216
|
+
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Converts `text` to camelCase.
|
|
220
|
+
*
|
|
221
|
+
* @example Word boundaries
|
|
222
|
+
* `camelCase('hello-world') // 'helloWorld'`
|
|
223
|
+
*
|
|
224
|
+
* @example With a prefix
|
|
225
|
+
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
226
|
+
*/
|
|
227
|
+
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
228
|
+
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Converts `text` to PascalCase.
|
|
232
|
+
*
|
|
233
|
+
* @example Word boundaries
|
|
234
|
+
* `pascalCase('hello-world') // 'HelloWorld'`
|
|
235
|
+
*
|
|
236
|
+
* @example With a suffix
|
|
237
|
+
* `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
|
|
238
|
+
*/
|
|
239
|
+
function pascalCase(text, { prefix = "", suffix = "" } = {}) {
|
|
240
|
+
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
241
|
+
}
|
|
242
|
+
//#endregion
|
|
243
|
+
//#region src/constants.ts
|
|
244
|
+
/**
|
|
245
|
+
* Plugin `include` filter types that select operations directly. When one of these is set
|
|
246
|
+
* without a `schemaName` include, the generate phase pre-scans operations to compute the set
|
|
247
|
+
* of schemas they reach, so unreachable schemas can be pruned for that plugin.
|
|
248
|
+
*/
|
|
249
|
+
const OPERATION_FILTER_TYPES = new Set([
|
|
250
|
+
"tag",
|
|
251
|
+
"operationId",
|
|
252
|
+
"path",
|
|
253
|
+
"method",
|
|
254
|
+
"contentType"
|
|
255
|
+
]);
|
|
256
|
+
/**
|
|
257
|
+
* Stable codes Kubb attaches to a `Diagnostic`. Each maps to a known failure mode
|
|
258
|
+
* and stays stable so it can be referenced in tooling and (later) docs. Reference
|
|
259
|
+
* these instead of inlining the string at a throw site.
|
|
260
|
+
*/
|
|
261
|
+
const diagnosticCode = {
|
|
262
|
+
/**
|
|
263
|
+
* Fallback for an unstructured error with no specific code.
|
|
264
|
+
*/
|
|
265
|
+
unknown: "KUBB_UNKNOWN",
|
|
266
|
+
/**
|
|
267
|
+
* The `input.path` file or URL could not be read.
|
|
268
|
+
*/
|
|
269
|
+
inputNotFound: "KUBB_INPUT_NOT_FOUND",
|
|
270
|
+
/**
|
|
271
|
+
* An adapter was configured without an `input`.
|
|
272
|
+
*/
|
|
273
|
+
inputRequired: "KUBB_INPUT_REQUIRED",
|
|
274
|
+
/**
|
|
275
|
+
* A `$ref` (or equivalent reference) could not be resolved in the source document.
|
|
276
|
+
*/
|
|
277
|
+
refNotFound: "KUBB_REF_NOT_FOUND",
|
|
278
|
+
/**
|
|
279
|
+
* A server variable value is not allowed by its `enum`.
|
|
280
|
+
*/
|
|
281
|
+
invalidServerVariable: "KUBB_INVALID_SERVER_VARIABLE",
|
|
282
|
+
/**
|
|
283
|
+
* A required plugin is missing from the config.
|
|
284
|
+
*/
|
|
285
|
+
pluginNotFound: "KUBB_PLUGIN_NOT_FOUND",
|
|
286
|
+
/**
|
|
287
|
+
* A plugin threw while generating.
|
|
288
|
+
*/
|
|
289
|
+
pluginFailed: "KUBB_PLUGIN_FAILED",
|
|
290
|
+
/**
|
|
291
|
+
* A plugin reported a non-fatal warning through `ctx.warn`.
|
|
292
|
+
*/
|
|
293
|
+
pluginWarning: "KUBB_PLUGIN_WARNING",
|
|
294
|
+
/**
|
|
295
|
+
* A plugin reported an informational message through `ctx.info`.
|
|
296
|
+
*/
|
|
297
|
+
pluginInfo: "KUBB_PLUGIN_INFO",
|
|
298
|
+
/**
|
|
299
|
+
* A schema uses a `format` Kubb does not map to a specific type. Reserved for
|
|
300
|
+
* adapters to emit as a `warning`.
|
|
301
|
+
*/
|
|
302
|
+
unsupportedFormat: "KUBB_UNSUPPORTED_FORMAT",
|
|
303
|
+
/**
|
|
304
|
+
* A referenced schema or operation is marked `deprecated`. Reserved for adapters
|
|
305
|
+
* to emit as an `info`.
|
|
306
|
+
*/
|
|
307
|
+
deprecated: "KUBB_DEPRECATED",
|
|
308
|
+
/**
|
|
309
|
+
* An adapter is required but the config has none. The build cannot read the input
|
|
310
|
+
* without one.
|
|
311
|
+
*/
|
|
312
|
+
adapterRequired: "KUBB_ADAPTER_REQUIRED",
|
|
313
|
+
/**
|
|
314
|
+
* A resolved output path escapes the output directory, which can stem from a path
|
|
315
|
+
* traversal in the spec or a misconfigured `group.name`.
|
|
316
|
+
*/
|
|
317
|
+
pathTraversal: "KUBB_PATH_TRAVERSAL",
|
|
318
|
+
/**
|
|
319
|
+
* A plugin's options are invalid, for example `output.mode: 'file'` paired with a `group` option.
|
|
320
|
+
*/
|
|
321
|
+
invalidPluginOptions: "KUBB_INVALID_PLUGIN_OPTIONS",
|
|
322
|
+
/**
|
|
323
|
+
* A post-generate shell hook (`hooks.done`) exited with a failure.
|
|
324
|
+
*/
|
|
325
|
+
hookFailed: "KUBB_HOOK_FAILED",
|
|
326
|
+
/**
|
|
327
|
+
* The formatter pass over the generated files failed.
|
|
328
|
+
*/
|
|
329
|
+
formatFailed: "KUBB_FORMAT_FAILED",
|
|
330
|
+
/**
|
|
331
|
+
* The linter pass over the generated files failed.
|
|
332
|
+
*/
|
|
333
|
+
lintFailed: "KUBB_LINT_FAILED",
|
|
334
|
+
/**
|
|
335
|
+
* Not a failure. Carries a plugin's elapsed time, summed into the run total.
|
|
336
|
+
*/
|
|
337
|
+
performance: "KUBB_PERFORMANCE",
|
|
338
|
+
/**
|
|
339
|
+
* Not a failure. A newer Kubb version is available on npm.
|
|
340
|
+
*/
|
|
341
|
+
updateAvailable: "KUBB_UPDATE_AVAILABLE"
|
|
342
|
+
};
|
|
343
|
+
//#endregion
|
|
344
|
+
//#region src/createStorage.ts
|
|
345
|
+
/**
|
|
346
|
+
* Defines a custom storage backend. The builder receives user options and
|
|
347
|
+
* returns a `Storage` implementation. Kubb ships with filesystem and in-memory
|
|
348
|
+
* storages. A custom backend writes generated files elsewhere, such as cloud
|
|
349
|
+
* storage or a database.
|
|
350
|
+
*
|
|
351
|
+
* @example In-memory storage (the built-in implementation)
|
|
352
|
+
* ```ts
|
|
353
|
+
* import { createStorage } from '@kubb/core'
|
|
354
|
+
*
|
|
355
|
+
* export const memoryStorage = createStorage(() => {
|
|
356
|
+
* const store = new Map<string, string>()
|
|
357
|
+
*
|
|
358
|
+
* return {
|
|
359
|
+
* name: 'memory',
|
|
360
|
+
* async hasItem(key) {
|
|
361
|
+
* return store.has(key)
|
|
362
|
+
* },
|
|
363
|
+
* async getItem(key) {
|
|
364
|
+
* return store.get(key) ?? null
|
|
365
|
+
* },
|
|
366
|
+
* async setItem(key, value) {
|
|
367
|
+
* store.set(key, value)
|
|
368
|
+
* },
|
|
369
|
+
* async removeItem(key) {
|
|
370
|
+
* store.delete(key)
|
|
371
|
+
* },
|
|
372
|
+
* async getKeys(base) {
|
|
373
|
+
* const keys = [...store.keys()]
|
|
374
|
+
* return base ? keys.filter((k) => k.startsWith(base)) : keys
|
|
375
|
+
* },
|
|
376
|
+
* async clear(base) {
|
|
377
|
+
* if (!base) store.clear()
|
|
378
|
+
* },
|
|
379
|
+
* }
|
|
380
|
+
* })
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
function createStorage(build) {
|
|
384
|
+
return (options) => build(options ?? {});
|
|
385
|
+
}
|
|
386
|
+
//#endregion
|
|
387
|
+
//#region src/FileManager.ts
|
|
388
|
+
function mergeFile(a, b) {
|
|
389
|
+
return {
|
|
390
|
+
...a,
|
|
391
|
+
banner: b.banner,
|
|
392
|
+
footer: b.footer,
|
|
393
|
+
sources: a.sources.length ? b.sources.length ? [...a.sources, ...b.sources] : a.sources : b.sources,
|
|
394
|
+
imports: a.imports.length ? b.imports.length ? [...a.imports, ...b.imports] : a.imports : b.imports,
|
|
395
|
+
exports: a.exports.length ? b.exports.length ? [...a.exports, ...b.exports] : a.exports : b.exports
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
function isIndexPath(path) {
|
|
399
|
+
return path.endsWith("/index.ts") || path === "index.ts";
|
|
400
|
+
}
|
|
401
|
+
function compareFiles(a, b) {
|
|
402
|
+
const lenDiff = a.path.length - b.path.length;
|
|
403
|
+
if (lenDiff !== 0) return lenDiff;
|
|
404
|
+
const aIsIndex = isIndexPath(a.path);
|
|
405
|
+
const bIsIndex = isIndexPath(b.path);
|
|
406
|
+
if (aIsIndex && !bIsIndex) return 1;
|
|
407
|
+
if (!aIsIndex && bIsIndex) return -1;
|
|
408
|
+
return 0;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* In-memory file store for generated files. Files sharing a `path` are merged
|
|
412
|
+
* (sources/imports/exports concatenated). The `files` getter is sorted by
|
|
413
|
+
* path length (barrel `index.ts` last within a bucket).
|
|
414
|
+
*
|
|
415
|
+
* @example
|
|
416
|
+
* ```ts
|
|
417
|
+
* const manager = new FileManager()
|
|
418
|
+
* manager.upsert(myFile)
|
|
419
|
+
* manager.files // sorted view
|
|
420
|
+
* ```
|
|
421
|
+
*/
|
|
422
|
+
var FileManager = class {
|
|
423
|
+
/**
|
|
424
|
+
* Subscribe to file-store changes. Listeners on `upsert` see each resolved file as it lands
|
|
425
|
+
* through `add` or `upsert`.
|
|
426
|
+
*/
|
|
427
|
+
hooks = new AsyncEventEmitter();
|
|
428
|
+
#cache = /* @__PURE__ */ new Map();
|
|
429
|
+
#sorted = null;
|
|
430
|
+
add(...files) {
|
|
431
|
+
return this.#store(files, false);
|
|
432
|
+
}
|
|
433
|
+
upsert(...files) {
|
|
434
|
+
return this.#store(files, true);
|
|
435
|
+
}
|
|
436
|
+
#store(files, mergeExisting) {
|
|
437
|
+
const batch = files.length > 1 ? this.#dedupe(files) : files;
|
|
438
|
+
const resolved = [];
|
|
439
|
+
for (const file of batch) {
|
|
440
|
+
const existing = this.#cache.get(file.path);
|
|
441
|
+
const merged = existing && mergeExisting ? _kubb_ast_factory.createFile(mergeFile(existing, file)) : _kubb_ast_factory.createFile(file);
|
|
442
|
+
this.#cache.set(merged.path, merged);
|
|
443
|
+
resolved.push(merged);
|
|
444
|
+
this.hooks.emit("upsert", merged);
|
|
445
|
+
}
|
|
446
|
+
if (resolved.length > 0) this.#sorted = null;
|
|
447
|
+
return resolved;
|
|
448
|
+
}
|
|
449
|
+
#dedupe(files) {
|
|
450
|
+
const seen = /* @__PURE__ */ new Map();
|
|
451
|
+
for (const file of files) {
|
|
452
|
+
const prev = seen.get(file.path);
|
|
453
|
+
seen.set(file.path, prev ? mergeFile(prev, file) : file);
|
|
454
|
+
}
|
|
455
|
+
return [...seen.values()];
|
|
456
|
+
}
|
|
457
|
+
getByPath(path) {
|
|
458
|
+
return this.#cache.get(path) ?? null;
|
|
459
|
+
}
|
|
460
|
+
deleteByPath(path) {
|
|
461
|
+
if (!this.#cache.delete(path)) return;
|
|
462
|
+
this.#sorted = null;
|
|
463
|
+
}
|
|
464
|
+
clear() {
|
|
465
|
+
this.#cache.clear();
|
|
466
|
+
this.#sorted = null;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Releases all stored files and clears every `hooks` listener. Called by the core after
|
|
470
|
+
* `kubb:build:end`.
|
|
471
|
+
*/
|
|
472
|
+
dispose() {
|
|
473
|
+
this.clear();
|
|
474
|
+
this.hooks.removeAll();
|
|
475
|
+
}
|
|
476
|
+
[Symbol.dispose]() {
|
|
477
|
+
this.dispose();
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* All stored files in stable sort order (shortest path first, barrel files
|
|
481
|
+
* last within a length bucket). Returns a cached view, do not mutate.
|
|
482
|
+
*/
|
|
483
|
+
get files() {
|
|
484
|
+
return this.#sorted ??= [...this.#cache.values()].sort(compareFiles);
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
//#endregion
|
|
488
|
+
//#region src/FileProcessor.ts
|
|
489
|
+
function joinSources(file) {
|
|
490
|
+
const sources = file.sources;
|
|
491
|
+
if (sources.length === 0) return "";
|
|
492
|
+
const parts = [];
|
|
493
|
+
for (const source of sources) {
|
|
494
|
+
const text = (0, _kubb_ast_utils.extractStringsFromNodes)(source.nodes);
|
|
495
|
+
if (text) parts.push(text);
|
|
496
|
+
}
|
|
497
|
+
return parts.join("\n\n");
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Turns `FileNode`s into source strings and writes them to storage.
|
|
501
|
+
*
|
|
502
|
+
* Two modes share the same instance. Stateless mode (`parse`, `stream`, `run`) just runs the
|
|
503
|
+
* conversion. Queue mode (`enqueue`, `flush`, `drain`) buffers files deduped by path and
|
|
504
|
+
* writes each batch through storage with up to `STREAM_FLUSH_EVERY` requests in flight.
|
|
505
|
+
*
|
|
506
|
+
* `flush` does not wait for its batch to finish, so dispatch can overlap with IO. The next
|
|
507
|
+
* `flush` or `drain` picks the in-flight batch up. `drain` blocks until everything has been
|
|
508
|
+
* written and is meant for the end of a build.
|
|
509
|
+
*
|
|
510
|
+
* To surface build-level hook signals (`kubb:files:processing:*` and friends) subscribe to
|
|
511
|
+
* `hooks` and re-emit on the kubb bus.
|
|
512
|
+
*/
|
|
513
|
+
var FileProcessor = class {
|
|
514
|
+
hooks = new AsyncEventEmitter();
|
|
515
|
+
#parsers;
|
|
516
|
+
#storage;
|
|
517
|
+
#extension;
|
|
518
|
+
#pending = /* @__PURE__ */ new Map();
|
|
519
|
+
#runningFlush = null;
|
|
520
|
+
constructor(options) {
|
|
521
|
+
this.#parsers = options.parsers ?? null;
|
|
522
|
+
this.#storage = options.storage;
|
|
523
|
+
this.#extension = options.extension ?? null;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Files waiting in the queue.
|
|
527
|
+
*/
|
|
528
|
+
get size() {
|
|
529
|
+
return this.#pending.size;
|
|
530
|
+
}
|
|
531
|
+
parse(file) {
|
|
532
|
+
const parsers = this.#parsers;
|
|
533
|
+
const parseExtName = this.#extension?.[file.extname] || void 0;
|
|
534
|
+
if (!parsers || !file.extname) return joinSources(file);
|
|
535
|
+
const parser = parsers.get(file.extname);
|
|
536
|
+
if (!parser) return joinSources(file);
|
|
537
|
+
return parser.parse(file, { extname: parseExtName });
|
|
538
|
+
}
|
|
539
|
+
*stream(files) {
|
|
540
|
+
const total = files.length;
|
|
541
|
+
if (total === 0) return;
|
|
542
|
+
let processed = 0;
|
|
543
|
+
for (const file of files) {
|
|
544
|
+
const source = this.parse(file);
|
|
545
|
+
processed++;
|
|
546
|
+
yield {
|
|
547
|
+
file,
|
|
548
|
+
source,
|
|
549
|
+
processed,
|
|
550
|
+
total,
|
|
551
|
+
percentage: processed / total * 100
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
async run(files) {
|
|
556
|
+
await this.hooks.emit("start", files);
|
|
557
|
+
for (const { file, source, processed, total, percentage } of this.stream(files)) await this.hooks.emit("update", {
|
|
558
|
+
file,
|
|
559
|
+
source,
|
|
560
|
+
processed,
|
|
561
|
+
percentage,
|
|
562
|
+
total
|
|
563
|
+
});
|
|
564
|
+
await this.hooks.emit("end", files);
|
|
565
|
+
return files;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Adds a file to the next flush. A later `enqueue` for the same path replaces the previous
|
|
569
|
+
* entry, matching `FileManager.upsert`. Fires the `enqueue` event.
|
|
570
|
+
*/
|
|
571
|
+
enqueue(file) {
|
|
572
|
+
this.#pending.set(file.path, file);
|
|
573
|
+
this.hooks.emit("enqueue", file);
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Starts processing the queued files. Waits for any previous flush to finish (so two
|
|
577
|
+
* batches never run together) and then returns without waiting for the new one. The next
|
|
578
|
+
* `flush` or `drain` picks up the in-flight task.
|
|
579
|
+
*/
|
|
580
|
+
async flush() {
|
|
581
|
+
if (this.#runningFlush) await this.#runningFlush;
|
|
582
|
+
if (this.#pending.size === 0) return;
|
|
583
|
+
const batch = [...this.#pending.values()];
|
|
584
|
+
this.#pending.clear();
|
|
585
|
+
this.#runningFlush = this.#processAndWrite(batch).finally(() => {
|
|
586
|
+
this.#runningFlush = null;
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Waits for the in-flight flush and writes any files still queued. Fires the `drain` event
|
|
591
|
+
* when both are done.
|
|
592
|
+
*/
|
|
593
|
+
async drain() {
|
|
594
|
+
if (this.#runningFlush) await this.#runningFlush;
|
|
595
|
+
if (this.#pending.size > 0) {
|
|
596
|
+
const batch = [...this.#pending.values()];
|
|
597
|
+
this.#pending.clear();
|
|
598
|
+
await this.#processAndWrite(batch);
|
|
599
|
+
}
|
|
600
|
+
await this.hooks.emit("drain");
|
|
601
|
+
}
|
|
602
|
+
async #processAndWrite(files) {
|
|
603
|
+
const storage = this.#storage;
|
|
604
|
+
await this.hooks.emit("start", files);
|
|
605
|
+
const queue = [];
|
|
606
|
+
for (const item of this.stream(files)) {
|
|
607
|
+
await this.hooks.emit("update", item);
|
|
608
|
+
if (item.source) {
|
|
609
|
+
queue.push(storage.setItem(item.file.path, item.source));
|
|
610
|
+
if (queue.length >= 50) await Promise.all(queue.splice(0));
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
await Promise.all(queue);
|
|
614
|
+
await this.hooks.emit("end", files);
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Clears every listener and the pending queue.
|
|
618
|
+
*/
|
|
619
|
+
dispose() {
|
|
620
|
+
this.hooks.removeAll();
|
|
621
|
+
this.#pending.clear();
|
|
622
|
+
}
|
|
623
|
+
[Symbol.dispose]() {
|
|
624
|
+
this.dispose();
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
//#endregion
|
|
628
|
+
//#region \0@oxc-project+runtime@0.134.0/helpers/esm/usingCtx.js
|
|
629
|
+
function _usingCtx() {
|
|
630
|
+
var r = "function" == typeof SuppressedError ? SuppressedError : function(r, e) {
|
|
631
|
+
var n = Error();
|
|
632
|
+
return n.name = "SuppressedError", n.error = r, n.suppressed = e, n;
|
|
633
|
+
};
|
|
634
|
+
var e = {};
|
|
635
|
+
var n = [];
|
|
636
|
+
function using(r, e) {
|
|
637
|
+
if (null != e) {
|
|
638
|
+
if (Object(e) !== e) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");
|
|
639
|
+
if (r) var o = e[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")];
|
|
640
|
+
if (void 0 === o && (o = e[Symbol.dispose || Symbol["for"]("Symbol.dispose")], r)) var t = o;
|
|
641
|
+
if ("function" != typeof o) throw new TypeError("Object is not disposable.");
|
|
642
|
+
t && (o = function o() {
|
|
643
|
+
try {
|
|
644
|
+
t.call(e);
|
|
645
|
+
} catch (r) {
|
|
646
|
+
return Promise.reject(r);
|
|
647
|
+
}
|
|
648
|
+
}), n.push({
|
|
649
|
+
v: e,
|
|
650
|
+
d: o,
|
|
651
|
+
a: r
|
|
652
|
+
});
|
|
653
|
+
} else r && n.push({
|
|
654
|
+
d: e,
|
|
655
|
+
a: r
|
|
656
|
+
});
|
|
657
|
+
return e;
|
|
658
|
+
}
|
|
659
|
+
return {
|
|
660
|
+
e,
|
|
661
|
+
u: using.bind(null, !1),
|
|
662
|
+
a: using.bind(null, !0),
|
|
663
|
+
d: function d() {
|
|
664
|
+
var o;
|
|
665
|
+
var t = this.e;
|
|
666
|
+
var s = 0;
|
|
667
|
+
function next() {
|
|
668
|
+
for (; o = n.pop();) try {
|
|
669
|
+
if (!o.a && 1 === s) return s = 0, n.push(o), Promise.resolve().then(next);
|
|
670
|
+
if (o.d) {
|
|
671
|
+
var r = o.d.call(o.v);
|
|
672
|
+
if (o.a) return s |= 2, Promise.resolve(r).then(next, err);
|
|
673
|
+
} else s |= 1;
|
|
674
|
+
} catch (r) {
|
|
675
|
+
return err(r);
|
|
676
|
+
}
|
|
677
|
+
if (1 === s) return t !== e ? Promise.reject(t) : Promise.resolve();
|
|
678
|
+
if (t !== e) throw t;
|
|
679
|
+
}
|
|
680
|
+
function err(n) {
|
|
681
|
+
return t = t !== e ? new r(n, t) : n, next();
|
|
682
|
+
}
|
|
683
|
+
return next();
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
//#endregion
|
|
688
|
+
//#region src/storages/memoryStorage.ts
|
|
689
|
+
/**
|
|
690
|
+
* In-memory storage driver. Useful for testing and dry-run scenarios where
|
|
691
|
+
* generated output should be captured without touching the filesystem.
|
|
692
|
+
*
|
|
693
|
+
* All data lives in a `Map` scoped to the storage instance and is discarded
|
|
694
|
+
* when the instance is garbage-collected.
|
|
695
|
+
*
|
|
696
|
+
* @example
|
|
697
|
+
* ```ts
|
|
698
|
+
* import { memoryStorage } from '@kubb/core'
|
|
699
|
+
* import { defineConfig } from 'kubb'
|
|
700
|
+
*
|
|
701
|
+
* export default defineConfig({
|
|
702
|
+
* input: { path: './petStore.yaml' },
|
|
703
|
+
* output: { path: './src/gen' },
|
|
704
|
+
* storage: memoryStorage(),
|
|
705
|
+
* })
|
|
706
|
+
* ```
|
|
707
|
+
*/
|
|
708
|
+
const memoryStorage = createStorage(() => {
|
|
709
|
+
const store = /* @__PURE__ */ new Map();
|
|
710
|
+
return {
|
|
711
|
+
name: "memory",
|
|
712
|
+
async hasItem(key) {
|
|
713
|
+
return store.has(key);
|
|
714
|
+
},
|
|
715
|
+
async getItem(key) {
|
|
716
|
+
return store.get(key) ?? null;
|
|
717
|
+
},
|
|
718
|
+
async setItem(key, value) {
|
|
719
|
+
store.set(key, value);
|
|
720
|
+
},
|
|
721
|
+
async removeItem(key) {
|
|
722
|
+
store.delete(key);
|
|
723
|
+
},
|
|
724
|
+
async getKeys(base) {
|
|
725
|
+
const keys = [...store.keys()];
|
|
726
|
+
return base ? keys.filter((k) => k.startsWith(base)) : keys;
|
|
727
|
+
},
|
|
728
|
+
async clear(base) {
|
|
729
|
+
if (!base) {
|
|
730
|
+
store.clear();
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
for (const key of store.keys()) if (key.startsWith(base)) store.delete(key);
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
});
|
|
737
|
+
//#endregion
|
|
738
|
+
Object.defineProperty(exports, "AsyncEventEmitter", {
|
|
739
|
+
enumerable: true,
|
|
740
|
+
get: function() {
|
|
741
|
+
return AsyncEventEmitter;
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
Object.defineProperty(exports, "BuildError", {
|
|
745
|
+
enumerable: true,
|
|
746
|
+
get: function() {
|
|
747
|
+
return BuildError;
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
Object.defineProperty(exports, "FileManager", {
|
|
751
|
+
enumerable: true,
|
|
752
|
+
get: function() {
|
|
753
|
+
return FileManager;
|
|
754
|
+
}
|
|
755
|
+
});
|
|
756
|
+
Object.defineProperty(exports, "FileProcessor", {
|
|
757
|
+
enumerable: true,
|
|
758
|
+
get: function() {
|
|
759
|
+
return FileProcessor;
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
Object.defineProperty(exports, "OPERATION_FILTER_TYPES", {
|
|
763
|
+
enumerable: true,
|
|
764
|
+
get: function() {
|
|
765
|
+
return OPERATION_FILTER_TYPES;
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
Object.defineProperty(exports, "__name", {
|
|
769
|
+
enumerable: true,
|
|
770
|
+
get: function() {
|
|
771
|
+
return __name;
|
|
772
|
+
}
|
|
773
|
+
});
|
|
774
|
+
Object.defineProperty(exports, "__toESM", {
|
|
775
|
+
enumerable: true,
|
|
776
|
+
get: function() {
|
|
777
|
+
return __toESM;
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
Object.defineProperty(exports, "_usingCtx", {
|
|
781
|
+
enumerable: true,
|
|
782
|
+
get: function() {
|
|
783
|
+
return _usingCtx;
|
|
784
|
+
}
|
|
785
|
+
});
|
|
786
|
+
Object.defineProperty(exports, "camelCase", {
|
|
787
|
+
enumerable: true,
|
|
788
|
+
get: function() {
|
|
789
|
+
return camelCase;
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
Object.defineProperty(exports, "createStorage", {
|
|
793
|
+
enumerable: true,
|
|
794
|
+
get: function() {
|
|
795
|
+
return createStorage;
|
|
796
|
+
}
|
|
797
|
+
});
|
|
798
|
+
Object.defineProperty(exports, "diagnosticCode", {
|
|
799
|
+
enumerable: true,
|
|
800
|
+
get: function() {
|
|
801
|
+
return diagnosticCode;
|
|
802
|
+
}
|
|
803
|
+
});
|
|
804
|
+
Object.defineProperty(exports, "getErrorMessage", {
|
|
805
|
+
enumerable: true,
|
|
806
|
+
get: function() {
|
|
807
|
+
return getErrorMessage;
|
|
808
|
+
}
|
|
809
|
+
});
|
|
810
|
+
Object.defineProperty(exports, "memoryStorage", {
|
|
811
|
+
enumerable: true,
|
|
812
|
+
get: function() {
|
|
813
|
+
return memoryStorage;
|
|
814
|
+
}
|
|
815
|
+
});
|
|
816
|
+
Object.defineProperty(exports, "pascalCase", {
|
|
817
|
+
enumerable: true,
|
|
818
|
+
get: function() {
|
|
819
|
+
return pascalCase;
|
|
820
|
+
}
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
//# sourceMappingURL=memoryStorage-CUj1hrxa.cjs.map
|