@kubb/core 5.0.0-beta.20 → 5.0.0-beta.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{KubbDriver-BXSnJ3qM.cjs → KubbDriver-DLha_xyo.cjs} +759 -108
- package/dist/KubbDriver-DLha_xyo.cjs.map +1 -0
- package/dist/{KubbDriver-Cxii_rBp.js → KubbDriver-l31wllgN.js} +737 -92
- package/dist/KubbDriver-l31wllgN.js.map +1 -0
- package/dist/{createKubb-Dcmtjqds.d.ts → createKubb-CYrw_xaR.d.ts} +91 -89
- package/dist/index.cjs +138 -762
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +136 -761
- package/dist/index.js.map +1 -1
- package/dist/mocks.cjs +4 -4
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.ts +1 -1
- package/dist/mocks.js +4 -4
- package/dist/mocks.js.map +1 -1
- package/package.json +4 -4
- package/src/FileManager.ts +65 -60
- package/src/FileProcessor.ts +11 -0
- package/src/KubbDriver.ts +368 -28
- package/src/createKubb.ts +144 -646
- package/src/createRenderer.ts +10 -0
- package/src/defineResolver.ts +7 -7
- package/src/mocks.ts +3 -3
- package/src/types.ts +2 -1
- package/dist/KubbDriver-BXSnJ3qM.cjs.map +0 -1
- package/dist/KubbDriver-Cxii_rBp.js.map +0 -1
|
@@ -1,8 +1,152 @@
|
|
|
1
1
|
import "./chunk--u3MIqq1.js";
|
|
2
|
+
import { EventEmitter } from "node:events";
|
|
2
3
|
import path, { extname, resolve } from "node:path";
|
|
3
|
-
import { createFile, createStreamInput, isOperationNode, isSchemaNode } from "@kubb/ast";
|
|
4
|
+
import { collectUsedSchemaNames, createFile, createStreamInput, extractStringsFromNodes, isOperationNode, isSchemaNode, transform } from "@kubb/ast";
|
|
4
5
|
import { deflateSync } from "fflate";
|
|
5
6
|
import { x } from "tinyexec";
|
|
7
|
+
//#region ../../internals/utils/src/errors.ts
|
|
8
|
+
/**
|
|
9
|
+
* Thrown when one or more errors occur during a Kubb build.
|
|
10
|
+
* Carries the full list of underlying errors on `errors`.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* throw new BuildError('Build failed', { errors: [err1, err2] })
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
var BuildError = class extends Error {
|
|
18
|
+
errors;
|
|
19
|
+
constructor(message, options) {
|
|
20
|
+
super(message, { cause: options.cause });
|
|
21
|
+
this.name = "BuildError";
|
|
22
|
+
this.errors = options.errors;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Coerces an unknown thrown value to an `Error` instance.
|
|
27
|
+
* Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* try { ... } catch(err) {
|
|
32
|
+
* throw new BuildError('Build failed', { cause: toError(err), errors: [] })
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
function toError(value) {
|
|
37
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region ../../internals/utils/src/asyncEventEmitter.ts
|
|
41
|
+
/**
|
|
42
|
+
* Typed `EventEmitter` that awaits all async listeners before resolving.
|
|
43
|
+
* Wraps Node's `EventEmitter` with full TypeScript event-map inference.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const emitter = new AsyncEventEmitter<{ build: [name: string] }>()
|
|
48
|
+
* emitter.on('build', async (name) => { console.log(name) })
|
|
49
|
+
* await emitter.emit('build', 'petstore') // all listeners awaited
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
var AsyncEventEmitter = class {
|
|
53
|
+
/**
|
|
54
|
+
* Maximum number of listeners per event before Node emits a memory-leak warning.
|
|
55
|
+
* @default 10
|
|
56
|
+
*/
|
|
57
|
+
constructor(maxListener = 10) {
|
|
58
|
+
this.#emitter.setMaxListeners(maxListener);
|
|
59
|
+
}
|
|
60
|
+
#emitter = new EventEmitter();
|
|
61
|
+
/**
|
|
62
|
+
* Emits `eventName` and awaits all registered listeners sequentially.
|
|
63
|
+
* Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* await emitter.emit('build', 'petstore')
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
emit(eventName, ...eventArgs) {
|
|
71
|
+
const listeners = this.#emitter.listeners(eventName);
|
|
72
|
+
if (listeners.length === 0) return;
|
|
73
|
+
return this.#emitAll(eventName, listeners, eventArgs);
|
|
74
|
+
}
|
|
75
|
+
async #emitAll(eventName, listeners, eventArgs) {
|
|
76
|
+
for (const listener of listeners) try {
|
|
77
|
+
await listener(...eventArgs);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
let serializedArgs;
|
|
80
|
+
try {
|
|
81
|
+
serializedArgs = JSON.stringify(eventArgs);
|
|
82
|
+
} catch {
|
|
83
|
+
serializedArgs = String(eventArgs);
|
|
84
|
+
}
|
|
85
|
+
throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Registers a persistent listener for `eventName`.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* emitter.on('build', async (name) => { console.log(name) })
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
on(eventName, handler) {
|
|
97
|
+
this.#emitter.on(eventName, handler);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Registers a one-shot listener that removes itself after the first invocation.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* emitter.onOnce('build', async (name) => { console.log(name) })
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
onOnce(eventName, handler) {
|
|
108
|
+
const wrapper = (...args) => {
|
|
109
|
+
this.off(eventName, wrapper);
|
|
110
|
+
return handler(...args);
|
|
111
|
+
};
|
|
112
|
+
this.on(eventName, wrapper);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Removes a previously registered listener.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* emitter.off('build', handler)
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
off(eventName, handler) {
|
|
123
|
+
this.#emitter.off(eventName, handler);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Returns the number of listeners registered for `eventName`.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* emitter.on('build', handler)
|
|
131
|
+
* emitter.listenerCount('build') // 1
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
listenerCount(eventName) {
|
|
135
|
+
return this.#emitter.listenerCount(eventName);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Removes all listeners from every event channel.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* emitter.removeAll()
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
removeAll() {
|
|
146
|
+
this.#emitter.removeAllListeners();
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
//#endregion
|
|
6
150
|
//#region ../../internals/utils/src/casing.ts
|
|
7
151
|
/**
|
|
8
152
|
* Shared implementation for camelCase and PascalCase conversion.
|
|
@@ -67,6 +211,39 @@ function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
|
|
|
67
211
|
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
68
212
|
}
|
|
69
213
|
//#endregion
|
|
214
|
+
//#region ../../internals/utils/src/time.ts
|
|
215
|
+
/**
|
|
216
|
+
* Calculates elapsed time in milliseconds from a high-resolution `process.hrtime` start time.
|
|
217
|
+
* Rounds to 2 decimal places for sub-millisecond precision without noise.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```ts
|
|
221
|
+
* const start = process.hrtime()
|
|
222
|
+
* doWork()
|
|
223
|
+
* getElapsedMs(start) // 42.35
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
function getElapsedMs(hrStart) {
|
|
227
|
+
const [seconds, nanoseconds] = process.hrtime(hrStart);
|
|
228
|
+
const ms = seconds * 1e3 + nanoseconds / 1e6;
|
|
229
|
+
return Math.round(ms * 100) / 100;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Converts a millisecond duration into a human-readable string (`ms`, `s`, or `m s`).
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* formatMs(250) // '250ms'
|
|
237
|
+
* formatMs(1500) // '1.50s'
|
|
238
|
+
* formatMs(90000) // '1m 30.0s'
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
241
|
+
function formatMs(ms) {
|
|
242
|
+
if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`;
|
|
243
|
+
if (ms >= 1e3) return `${(ms / 1e3).toFixed(2)}s`;
|
|
244
|
+
return `${Math.round(ms)}ms`;
|
|
245
|
+
}
|
|
246
|
+
//#endregion
|
|
70
247
|
//#region ../../internals/utils/src/promise.ts
|
|
71
248
|
function* chunks(arr, size) {
|
|
72
249
|
for (let i = 0; i < arr.length; i += size) yield arr.slice(i, i + size);
|
|
@@ -109,22 +286,6 @@ async function forBatches(source, process, options) {
|
|
|
109
286
|
if (flush) await flush();
|
|
110
287
|
}
|
|
111
288
|
}
|
|
112
|
-
/**
|
|
113
|
-
* Runs `work`, passing `flush` as its periodic-flush callback, then calls
|
|
114
|
-
* `flush` once more to drain any items that did not cross a flush boundary.
|
|
115
|
-
*
|
|
116
|
-
* @example
|
|
117
|
-
* ```ts
|
|
118
|
-
* await withDrain(
|
|
119
|
-
* (flush) => processItems(items, { flush }),
|
|
120
|
-
* () => writeRemainingFiles(),
|
|
121
|
-
* )
|
|
122
|
-
* ```
|
|
123
|
-
*/
|
|
124
|
-
async function withDrain(work, flush) {
|
|
125
|
-
await work(flush);
|
|
126
|
-
await flush();
|
|
127
|
-
}
|
|
128
289
|
/** Returns `true` when `result` is a thenable `Promise`.
|
|
129
290
|
*
|
|
130
291
|
* @example
|
|
@@ -404,12 +565,13 @@ var URLPath = class {
|
|
|
404
565
|
* @example
|
|
405
566
|
* new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`'
|
|
406
567
|
*/
|
|
407
|
-
toTemplateString({ prefix
|
|
408
|
-
|
|
568
|
+
toTemplateString({ prefix, replacer } = {}) {
|
|
569
|
+
const result = this.path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
409
570
|
if (i % 2 === 0) return part;
|
|
410
571
|
const param = this.#transformParam(part);
|
|
411
572
|
return `\${${replacer ? replacer(param) : param}}`;
|
|
412
|
-
}).join("")
|
|
573
|
+
}).join("");
|
|
574
|
+
return `\`${prefix ?? ""}${result}\``;
|
|
413
575
|
}
|
|
414
576
|
/**
|
|
415
577
|
* Extracts all `{param}` segments from the path and returns them as a key-value map.
|
|
@@ -787,13 +949,13 @@ function buildDefaultBanner({ title, description, version, config }) {
|
|
|
787
949
|
* @example Disabled default banner
|
|
788
950
|
* ```ts
|
|
789
951
|
* defaultResolveBanner(undefined, { config: { output: { defaultBanner: false }, ...config } })
|
|
790
|
-
* // →
|
|
952
|
+
* // → null
|
|
791
953
|
* ```
|
|
792
954
|
*/
|
|
793
955
|
function defaultResolveBanner(meta, { output, config }) {
|
|
794
956
|
if (typeof output?.banner === "function") return output.banner(meta);
|
|
795
957
|
if (typeof output?.banner === "string") return output.banner;
|
|
796
|
-
if (config.output.defaultBanner === false) return;
|
|
958
|
+
if (config.output.defaultBanner === false) return null;
|
|
797
959
|
return buildDefaultBanner({
|
|
798
960
|
title: meta?.title,
|
|
799
961
|
version: meta?.version,
|
|
@@ -822,6 +984,7 @@ function defaultResolveBanner(meta, { output, config }) {
|
|
|
822
984
|
function defaultResolveFooter(meta, { output }) {
|
|
823
985
|
if (typeof output?.footer === "function") return output.footer(meta);
|
|
824
986
|
if (typeof output?.footer === "string") return output.footer;
|
|
987
|
+
return null;
|
|
825
988
|
}
|
|
826
989
|
/**
|
|
827
990
|
* Defines a resolver for a plugin, injecting built-in defaults for name casing,
|
|
@@ -932,111 +1095,241 @@ function mergeFile(a, b) {
|
|
|
932
1095
|
...a,
|
|
933
1096
|
banner: b.banner,
|
|
934
1097
|
footer: b.footer,
|
|
935
|
-
sources:
|
|
936
|
-
imports:
|
|
937
|
-
exports:
|
|
1098
|
+
sources: a.sources.length ? b.sources.length ? [...a.sources, ...b.sources] : a.sources : b.sources,
|
|
1099
|
+
imports: a.imports.length ? b.imports.length ? [...a.imports, ...b.imports] : a.imports : b.imports,
|
|
1100
|
+
exports: a.exports.length ? b.exports.length ? [...a.exports, ...b.exports] : a.exports : b.exports
|
|
938
1101
|
};
|
|
939
1102
|
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
return
|
|
1103
|
+
function isIndexPath(path) {
|
|
1104
|
+
return path.endsWith("/index.ts") || path === "index.ts";
|
|
1105
|
+
}
|
|
1106
|
+
function compareFiles(a, b) {
|
|
1107
|
+
const lenDiff = a.path.length - b.path.length;
|
|
1108
|
+
if (lenDiff !== 0) return lenDiff;
|
|
1109
|
+
const aIsIndex = isIndexPath(a.path);
|
|
1110
|
+
const bIsIndex = isIndexPath(b.path);
|
|
1111
|
+
if (aIsIndex && !bIsIndex) return 1;
|
|
1112
|
+
if (!aIsIndex && bIsIndex) return -1;
|
|
1113
|
+
return 0;
|
|
951
1114
|
}
|
|
952
1115
|
/**
|
|
953
|
-
* In-memory file store for generated files.
|
|
954
|
-
*
|
|
955
|
-
*
|
|
956
|
-
* The `files` getter returns all stored files sorted by path length (shortest first).
|
|
1116
|
+
* In-memory file store for generated files. Files sharing a `path` are merged
|
|
1117
|
+
* (sources/imports/exports concatenated). The `files` getter is sorted by
|
|
1118
|
+
* path length (barrel `index.ts` last within a bucket).
|
|
957
1119
|
*
|
|
958
1120
|
* @example
|
|
959
1121
|
* ```ts
|
|
960
|
-
* import { FileManager } from '@kubb/core'
|
|
961
|
-
*
|
|
962
1122
|
* const manager = new FileManager()
|
|
963
1123
|
* manager.upsert(myFile)
|
|
964
|
-
*
|
|
1124
|
+
* manager.files // sorted view
|
|
965
1125
|
* ```
|
|
966
1126
|
*/
|
|
967
1127
|
var FileManager = class {
|
|
968
1128
|
#cache = /* @__PURE__ */ new Map();
|
|
969
|
-
#
|
|
1129
|
+
#sorted = null;
|
|
1130
|
+
#onUpsert = null;
|
|
970
1131
|
/**
|
|
971
|
-
*
|
|
972
|
-
*
|
|
973
|
-
*
|
|
1132
|
+
* Registers a callback invoked with the resolved {@link FileNode} on every
|
|
1133
|
+
* `add` / `upsert`. Used by the build loop to track newly written files
|
|
1134
|
+
* without keeping its own scan-based diff. Single subscriber by design —
|
|
1135
|
+
* setting again replaces the previous callback. Pass `null` to detach.
|
|
974
1136
|
*/
|
|
1137
|
+
setOnUpsert(callback) {
|
|
1138
|
+
this.#onUpsert = callback;
|
|
1139
|
+
}
|
|
975
1140
|
add(...files) {
|
|
976
1141
|
return this.#store(files, false);
|
|
977
1142
|
}
|
|
978
|
-
/**
|
|
979
|
-
* Adds or merges one or more files.
|
|
980
|
-
* If a file with the same path already exists in the cache, its
|
|
981
|
-
* sources/imports/exports are merged into the incoming file.
|
|
982
|
-
*/
|
|
983
1143
|
upsert(...files) {
|
|
984
1144
|
return this.#store(files, true);
|
|
985
1145
|
}
|
|
986
1146
|
#store(files, mergeExisting) {
|
|
987
|
-
const
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
const
|
|
991
|
-
|
|
992
|
-
|
|
1147
|
+
const batch = files.length > 1 ? this.#dedupe(files) : files;
|
|
1148
|
+
const resolved = [];
|
|
1149
|
+
for (const file of batch) {
|
|
1150
|
+
const existing = this.#cache.get(file.path);
|
|
1151
|
+
const merged = existing && mergeExisting ? createFile(mergeFile(existing, file)) : createFile(file);
|
|
1152
|
+
this.#cache.set(merged.path, merged);
|
|
1153
|
+
resolved.push(merged);
|
|
1154
|
+
this.#onUpsert?.(merged);
|
|
1155
|
+
}
|
|
1156
|
+
if (resolved.length > 0) this.#sorted = null;
|
|
1157
|
+
return resolved;
|
|
1158
|
+
}
|
|
1159
|
+
#dedupe(files) {
|
|
1160
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1161
|
+
for (const file of files) {
|
|
1162
|
+
const prev = seen.get(file.path);
|
|
1163
|
+
seen.set(file.path, prev ? mergeFile(prev, file) : file);
|
|
993
1164
|
}
|
|
994
|
-
|
|
995
|
-
return resolvedFiles;
|
|
1165
|
+
return [...seen.values()];
|
|
996
1166
|
}
|
|
997
1167
|
getByPath(path) {
|
|
998
1168
|
return this.#cache.get(path) ?? null;
|
|
999
1169
|
}
|
|
1000
1170
|
deleteByPath(path) {
|
|
1001
|
-
this.#cache.delete(path);
|
|
1002
|
-
this.#
|
|
1171
|
+
if (!this.#cache.delete(path)) return;
|
|
1172
|
+
this.#sorted = null;
|
|
1003
1173
|
}
|
|
1004
1174
|
clear() {
|
|
1005
1175
|
this.#cache.clear();
|
|
1006
|
-
this.#
|
|
1176
|
+
this.#sorted = null;
|
|
1007
1177
|
}
|
|
1008
1178
|
/**
|
|
1009
|
-
* Releases all stored files. Called by the core after `kubb:build:end
|
|
1010
|
-
* free the per-plugin FileNode caches for the rest of the process lifetime.
|
|
1179
|
+
* Releases all stored files. Called by the core after `kubb:build:end`.
|
|
1011
1180
|
*/
|
|
1012
1181
|
dispose() {
|
|
1013
1182
|
this.clear();
|
|
1183
|
+
this.#onUpsert = null;
|
|
1014
1184
|
}
|
|
1015
1185
|
[Symbol.dispose]() {
|
|
1016
1186
|
this.dispose();
|
|
1017
1187
|
}
|
|
1018
1188
|
/**
|
|
1019
|
-
* All stored files
|
|
1189
|
+
* All stored files in stable sort order (shortest path first, barrel files
|
|
1190
|
+
* last within a length bucket). Returns a cached view — do not mutate.
|
|
1020
1191
|
*/
|
|
1021
1192
|
get files() {
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1193
|
+
return this.#sorted ??= [...this.#cache.values()].sort(compareFiles);
|
|
1194
|
+
}
|
|
1195
|
+
};
|
|
1196
|
+
//#endregion
|
|
1197
|
+
//#region src/FileProcessor.ts
|
|
1198
|
+
function joinSources(file) {
|
|
1199
|
+
const sources = file.sources;
|
|
1200
|
+
if (sources.length === 0) return "";
|
|
1201
|
+
const parts = [];
|
|
1202
|
+
for (const source of sources) {
|
|
1203
|
+
const s = extractStringsFromNodes(source.nodes);
|
|
1204
|
+
if (s) parts.push(s);
|
|
1205
|
+
}
|
|
1206
|
+
return parts.join("\n\n");
|
|
1207
|
+
}
|
|
1208
|
+
/**
|
|
1209
|
+
* Converts a single file to a string using the registered parsers.
|
|
1210
|
+
* Falls back to joining source values when no matching parser is found.
|
|
1211
|
+
*
|
|
1212
|
+
* @internal
|
|
1213
|
+
*/
|
|
1214
|
+
var FileProcessor = class {
|
|
1215
|
+
events = new AsyncEventEmitter();
|
|
1216
|
+
parse(file, { parsers, extension } = {}) {
|
|
1217
|
+
const parseExtName = extension?.[file.extname] || void 0;
|
|
1218
|
+
if (!parsers || !file.extname) return joinSources(file);
|
|
1219
|
+
const parser = parsers.get(file.extname);
|
|
1220
|
+
if (!parser) return joinSources(file);
|
|
1221
|
+
return parser.parse(file, { extname: parseExtName });
|
|
1222
|
+
}
|
|
1223
|
+
*stream(files, options = {}) {
|
|
1224
|
+
const total = files.length;
|
|
1225
|
+
if (total === 0) return;
|
|
1226
|
+
let processed = 0;
|
|
1227
|
+
for (const file of files) {
|
|
1228
|
+
const source = this.parse(file, options);
|
|
1229
|
+
processed++;
|
|
1230
|
+
yield {
|
|
1231
|
+
file,
|
|
1232
|
+
source,
|
|
1233
|
+
processed,
|
|
1234
|
+
total,
|
|
1235
|
+
percentage: processed / total * 100
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
async run(files, options = {}) {
|
|
1240
|
+
await this.events.emit("start", files);
|
|
1241
|
+
for (const { file, source, processed, total, percentage } of this.stream(files, options)) await this.events.emit("update", {
|
|
1242
|
+
file,
|
|
1243
|
+
source,
|
|
1244
|
+
processed,
|
|
1245
|
+
percentage,
|
|
1246
|
+
total
|
|
1031
1247
|
});
|
|
1032
|
-
|
|
1248
|
+
await this.events.emit("end", files);
|
|
1249
|
+
return files;
|
|
1250
|
+
}
|
|
1251
|
+
/**
|
|
1252
|
+
* Clears all registered event listeners.
|
|
1253
|
+
*/
|
|
1254
|
+
dispose() {
|
|
1255
|
+
this.events.removeAll();
|
|
1256
|
+
}
|
|
1257
|
+
[Symbol.dispose]() {
|
|
1258
|
+
this.dispose();
|
|
1033
1259
|
}
|
|
1034
1260
|
};
|
|
1035
1261
|
//#endregion
|
|
1262
|
+
//#region \0@oxc-project+runtime@0.129.0/helpers/usingCtx.js
|
|
1263
|
+
function _usingCtx() {
|
|
1264
|
+
var r = "function" == typeof SuppressedError ? SuppressedError : function(r, e) {
|
|
1265
|
+
var n = Error();
|
|
1266
|
+
return n.name = "SuppressedError", n.error = r, n.suppressed = e, n;
|
|
1267
|
+
};
|
|
1268
|
+
var e = {};
|
|
1269
|
+
var n = [];
|
|
1270
|
+
function using(r, e) {
|
|
1271
|
+
if (null != e) {
|
|
1272
|
+
if (Object(e) !== e) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");
|
|
1273
|
+
if (r) var o = e[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")];
|
|
1274
|
+
if (void 0 === o && (o = e[Symbol.dispose || Symbol["for"]("Symbol.dispose")], r)) var t = o;
|
|
1275
|
+
if ("function" != typeof o) throw new TypeError("Object is not disposable.");
|
|
1276
|
+
t && (o = function o() {
|
|
1277
|
+
try {
|
|
1278
|
+
t.call(e);
|
|
1279
|
+
} catch (r) {
|
|
1280
|
+
return Promise.reject(r);
|
|
1281
|
+
}
|
|
1282
|
+
}), n.push({
|
|
1283
|
+
v: e,
|
|
1284
|
+
d: o,
|
|
1285
|
+
a: r
|
|
1286
|
+
});
|
|
1287
|
+
} else r && n.push({
|
|
1288
|
+
d: e,
|
|
1289
|
+
a: r
|
|
1290
|
+
});
|
|
1291
|
+
return e;
|
|
1292
|
+
}
|
|
1293
|
+
return {
|
|
1294
|
+
e,
|
|
1295
|
+
u: using.bind(null, !1),
|
|
1296
|
+
a: using.bind(null, !0),
|
|
1297
|
+
d: function d() {
|
|
1298
|
+
var o;
|
|
1299
|
+
var t = this.e;
|
|
1300
|
+
var s = 0;
|
|
1301
|
+
function next() {
|
|
1302
|
+
for (; o = n.pop();) try {
|
|
1303
|
+
if (!o.a && 1 === s) return s = 0, n.push(o), Promise.resolve().then(next);
|
|
1304
|
+
if (o.d) {
|
|
1305
|
+
var r = o.d.call(o.v);
|
|
1306
|
+
if (o.a) return s |= 2, Promise.resolve(r).then(next, err);
|
|
1307
|
+
} else s |= 1;
|
|
1308
|
+
} catch (r) {
|
|
1309
|
+
return err(r);
|
|
1310
|
+
}
|
|
1311
|
+
if (1 === s) return t !== e ? Promise.reject(t) : Promise.resolve();
|
|
1312
|
+
if (t !== e) throw t;
|
|
1313
|
+
}
|
|
1314
|
+
function err(n) {
|
|
1315
|
+
return t = t !== e ? new r(n, t) : n, next();
|
|
1316
|
+
}
|
|
1317
|
+
return next();
|
|
1318
|
+
}
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
//#endregion
|
|
1036
1322
|
//#region src/KubbDriver.ts
|
|
1037
1323
|
function enforceOrder(enforce) {
|
|
1038
1324
|
return enforce === "pre" ? -1 : enforce === "post" ? 1 : 0;
|
|
1039
1325
|
}
|
|
1326
|
+
const OPERATION_FILTER_TYPES = new Set([
|
|
1327
|
+
"tag",
|
|
1328
|
+
"operationId",
|
|
1329
|
+
"path",
|
|
1330
|
+
"method",
|
|
1331
|
+
"contentType"
|
|
1332
|
+
]);
|
|
1040
1333
|
var KubbDriver = class KubbDriver {
|
|
1041
1334
|
config;
|
|
1042
1335
|
options;
|
|
@@ -1056,8 +1349,8 @@ var KubbDriver = class KubbDriver {
|
|
|
1056
1349
|
* The streaming `InputStreamNode` produced by the adapter.
|
|
1057
1350
|
* Always set after adapter setup — parse-only adapters are wrapped automatically.
|
|
1058
1351
|
*/
|
|
1059
|
-
inputNode =
|
|
1060
|
-
adapter =
|
|
1352
|
+
inputNode = null;
|
|
1353
|
+
adapter = null;
|
|
1061
1354
|
/**
|
|
1062
1355
|
* Studio session state, kept together so `dispose()` can reset it atomically.
|
|
1063
1356
|
*
|
|
@@ -1068,9 +1361,9 @@ var KubbDriver = class KubbDriver {
|
|
|
1068
1361
|
* per studio session, even when `openInStudio()` is called multiple times.
|
|
1069
1362
|
*/
|
|
1070
1363
|
#studio = {
|
|
1071
|
-
source:
|
|
1364
|
+
source: null,
|
|
1072
1365
|
isOpen: false,
|
|
1073
|
-
inputNode:
|
|
1366
|
+
inputNode: null
|
|
1074
1367
|
};
|
|
1075
1368
|
#middlewareListeners = [];
|
|
1076
1369
|
/**
|
|
@@ -1079,6 +1372,7 @@ var KubbDriver = class KubbDriver {
|
|
|
1079
1372
|
* add files; this property gives direct read/write access when needed.
|
|
1080
1373
|
*/
|
|
1081
1374
|
fileManager = new FileManager();
|
|
1375
|
+
#fileProcessor = new FileProcessor();
|
|
1082
1376
|
plugins = /* @__PURE__ */ new Map();
|
|
1083
1377
|
/**
|
|
1084
1378
|
* Tracks which plugins have generators registered via `addGenerator()` (event-based path).
|
|
@@ -1091,7 +1385,7 @@ var KubbDriver = class KubbDriver {
|
|
|
1091
1385
|
constructor(config, options) {
|
|
1092
1386
|
this.config = config;
|
|
1093
1387
|
this.options = options;
|
|
1094
|
-
this.adapter = config.adapter;
|
|
1388
|
+
this.adapter = config.adapter ?? null;
|
|
1095
1389
|
}
|
|
1096
1390
|
async setup() {
|
|
1097
1391
|
const normalized = this.config.plugins.map((rawPlugin) => this.#normalizePlugin(rawPlugin));
|
|
@@ -1302,6 +1596,344 @@ var KubbDriver = class KubbDriver {
|
|
|
1302
1596
|
return this.#eventGeneratorPlugins.has(pluginName);
|
|
1303
1597
|
}
|
|
1304
1598
|
/**
|
|
1599
|
+
* Runs the full plugin pipeline. Returns timings/failures collected so far even
|
|
1600
|
+
* when an outer hook throws — the orchestrator preserves partial state by capturing
|
|
1601
|
+
* the error into `error` instead of propagating.
|
|
1602
|
+
*/
|
|
1603
|
+
async run({ storage }) {
|
|
1604
|
+
const hooks = this.hooks;
|
|
1605
|
+
const config = this.config;
|
|
1606
|
+
const failedPlugins = /* @__PURE__ */ new Set();
|
|
1607
|
+
const pluginTimings = /* @__PURE__ */ new Map();
|
|
1608
|
+
const parsersMap = /* @__PURE__ */ new Map();
|
|
1609
|
+
for (const parser of config.parsers) if (parser.extNames) for (const ext of parser.extNames) parsersMap.set(ext, parser);
|
|
1610
|
+
const pendingFiles = /* @__PURE__ */ new Map();
|
|
1611
|
+
this.fileManager.setOnUpsert((file) => {
|
|
1612
|
+
pendingFiles.set(file.path, file);
|
|
1613
|
+
});
|
|
1614
|
+
try {
|
|
1615
|
+
const flushPending = async () => {
|
|
1616
|
+
if (pendingFiles.size === 0) return;
|
|
1617
|
+
const files = [...pendingFiles.values()];
|
|
1618
|
+
pendingFiles.clear();
|
|
1619
|
+
await hooks.emit("kubb:debug", {
|
|
1620
|
+
date: /* @__PURE__ */ new Date(),
|
|
1621
|
+
logs: [`Writing ${files.length} files...`]
|
|
1622
|
+
});
|
|
1623
|
+
await hooks.emit("kubb:files:processing:start", { files });
|
|
1624
|
+
const items = [...this.#fileProcessor.stream(files, {
|
|
1625
|
+
parsers: parsersMap,
|
|
1626
|
+
extension: config.output.extension
|
|
1627
|
+
})];
|
|
1628
|
+
await hooks.emit("kubb:files:processing:update", { files: items.map(({ file, source, processed, total, percentage }) => ({
|
|
1629
|
+
file,
|
|
1630
|
+
source,
|
|
1631
|
+
processed,
|
|
1632
|
+
total,
|
|
1633
|
+
percentage,
|
|
1634
|
+
config
|
|
1635
|
+
})) });
|
|
1636
|
+
const queue = [];
|
|
1637
|
+
for (const { file, source } of items) if (source) {
|
|
1638
|
+
queue.push(storage.setItem(file.path, source));
|
|
1639
|
+
if (queue.length >= 50) await Promise.all(queue.splice(0));
|
|
1640
|
+
}
|
|
1641
|
+
await Promise.all(queue);
|
|
1642
|
+
await hooks.emit("kubb:files:processing:end", { files });
|
|
1643
|
+
await hooks.emit("kubb:debug", {
|
|
1644
|
+
date: /* @__PURE__ */ new Date(),
|
|
1645
|
+
logs: [`✓ File write process completed for ${files.length} files`]
|
|
1646
|
+
});
|
|
1647
|
+
};
|
|
1648
|
+
await this.emitSetupHooks();
|
|
1649
|
+
if (this.adapter && this.inputNode) await hooks.emit("kubb:build:start", Object.assign({
|
|
1650
|
+
config,
|
|
1651
|
+
adapter: this.adapter,
|
|
1652
|
+
meta: this.inputNode.meta,
|
|
1653
|
+
getPlugin: this.getPlugin.bind(this)
|
|
1654
|
+
}, this.#filesPayload()));
|
|
1655
|
+
const generatorPlugins = [];
|
|
1656
|
+
for (const plugin of this.plugins.values()) {
|
|
1657
|
+
const context = this.getContext(plugin);
|
|
1658
|
+
const hrStart = process.hrtime();
|
|
1659
|
+
try {
|
|
1660
|
+
await hooks.emit("kubb:plugin:start", { plugin });
|
|
1661
|
+
await hooks.emit("kubb:debug", {
|
|
1662
|
+
date: /* @__PURE__ */ new Date(),
|
|
1663
|
+
logs: ["Starting plugin...", ` • Plugin Name: ${plugin.name}`]
|
|
1664
|
+
});
|
|
1665
|
+
} catch (caughtError) {
|
|
1666
|
+
const error = caughtError;
|
|
1667
|
+
const duration = getElapsedMs(hrStart);
|
|
1668
|
+
pluginTimings.set(plugin.name, duration);
|
|
1669
|
+
await this.#emitPluginEnd({
|
|
1670
|
+
plugin,
|
|
1671
|
+
duration,
|
|
1672
|
+
success: false,
|
|
1673
|
+
error
|
|
1674
|
+
});
|
|
1675
|
+
failedPlugins.add({
|
|
1676
|
+
plugin,
|
|
1677
|
+
error
|
|
1678
|
+
});
|
|
1679
|
+
continue;
|
|
1680
|
+
}
|
|
1681
|
+
if (plugin.generators?.length || this.hasEventGenerators(plugin.name)) {
|
|
1682
|
+
generatorPlugins.push({
|
|
1683
|
+
plugin,
|
|
1684
|
+
context,
|
|
1685
|
+
hrStart
|
|
1686
|
+
});
|
|
1687
|
+
continue;
|
|
1688
|
+
}
|
|
1689
|
+
const duration = getElapsedMs(hrStart);
|
|
1690
|
+
pluginTimings.set(plugin.name, duration);
|
|
1691
|
+
await this.#emitPluginEnd({
|
|
1692
|
+
plugin,
|
|
1693
|
+
duration,
|
|
1694
|
+
success: true
|
|
1695
|
+
});
|
|
1696
|
+
await hooks.emit("kubb:debug", {
|
|
1697
|
+
date: /* @__PURE__ */ new Date(),
|
|
1698
|
+
logs: [`✓ Plugin started successfully (${formatMs(duration)})`]
|
|
1699
|
+
});
|
|
1700
|
+
}
|
|
1701
|
+
if (generatorPlugins.length > 0) if (this.inputNode) {
|
|
1702
|
+
const { timings, failed } = await this.#runGenerators(generatorPlugins, flushPending);
|
|
1703
|
+
await flushPending();
|
|
1704
|
+
for (const [name, duration] of timings) pluginTimings.set(name, duration);
|
|
1705
|
+
for (const entry of failed) failedPlugins.add(entry);
|
|
1706
|
+
} else for (const { plugin, hrStart } of generatorPlugins) {
|
|
1707
|
+
const duration = getElapsedMs(hrStart);
|
|
1708
|
+
pluginTimings.set(plugin.name, duration);
|
|
1709
|
+
await this.#emitPluginEnd({
|
|
1710
|
+
plugin,
|
|
1711
|
+
duration,
|
|
1712
|
+
success: true
|
|
1713
|
+
});
|
|
1714
|
+
}
|
|
1715
|
+
await hooks.emit("kubb:plugins:end", Object.assign({ config }, this.#filesPayload()));
|
|
1716
|
+
await flushPending();
|
|
1717
|
+
const files = this.fileManager.files;
|
|
1718
|
+
await hooks.emit("kubb:build:end", {
|
|
1719
|
+
files,
|
|
1720
|
+
config,
|
|
1721
|
+
outputDir: resolve(config.root, config.output.path)
|
|
1722
|
+
});
|
|
1723
|
+
return {
|
|
1724
|
+
failedPlugins,
|
|
1725
|
+
pluginTimings
|
|
1726
|
+
};
|
|
1727
|
+
} catch (caughtError) {
|
|
1728
|
+
return {
|
|
1729
|
+
failedPlugins,
|
|
1730
|
+
pluginTimings,
|
|
1731
|
+
error: caughtError
|
|
1732
|
+
};
|
|
1733
|
+
} finally {
|
|
1734
|
+
this.fileManager.setOnUpsert(null);
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
#filesPayload() {
|
|
1738
|
+
const driver = this;
|
|
1739
|
+
return {
|
|
1740
|
+
get files() {
|
|
1741
|
+
return driver.fileManager.files;
|
|
1742
|
+
},
|
|
1743
|
+
upsertFile: (...files) => driver.fileManager.upsert(...files)
|
|
1744
|
+
};
|
|
1745
|
+
}
|
|
1746
|
+
#emitPluginEnd({ plugin, duration, success, error }) {
|
|
1747
|
+
return this.hooks.emit("kubb:plugin:end", Object.assign({
|
|
1748
|
+
plugin,
|
|
1749
|
+
duration,
|
|
1750
|
+
success,
|
|
1751
|
+
...error ? { error } : {},
|
|
1752
|
+
config: this.config
|
|
1753
|
+
}, this.#filesPayload()));
|
|
1754
|
+
}
|
|
1755
|
+
async #runGenerators(entries, flushPending) {
|
|
1756
|
+
const timings = /* @__PURE__ */ new Map();
|
|
1757
|
+
const failed = /* @__PURE__ */ new Set();
|
|
1758
|
+
const driver = this;
|
|
1759
|
+
const { schemas, operations } = this.inputNode;
|
|
1760
|
+
const states = entries.map(({ plugin, context, hrStart }) => {
|
|
1761
|
+
const { exclude, include, override } = plugin.options;
|
|
1762
|
+
const hasExclude = Array.isArray(exclude) && exclude.length > 0;
|
|
1763
|
+
const hasInclude = Array.isArray(include) && include.length > 0;
|
|
1764
|
+
const hasOverride = Array.isArray(override) && override.length > 0;
|
|
1765
|
+
return {
|
|
1766
|
+
plugin,
|
|
1767
|
+
generatorContext: {
|
|
1768
|
+
...context,
|
|
1769
|
+
resolver: this.getResolver(plugin.name)
|
|
1770
|
+
},
|
|
1771
|
+
generators: plugin.generators ?? [],
|
|
1772
|
+
hrStart,
|
|
1773
|
+
failed: false,
|
|
1774
|
+
error: null,
|
|
1775
|
+
optionsAreStatic: !hasExclude && !hasInclude && !hasOverride,
|
|
1776
|
+
allowedSchemaNames: null
|
|
1777
|
+
};
|
|
1778
|
+
});
|
|
1779
|
+
const emitsSchemaHook = this.hooks.listenerCount("kubb:generate:schema") > 0;
|
|
1780
|
+
const emitsOperationHook = this.hooks.listenerCount("kubb:generate:operation") > 0;
|
|
1781
|
+
const pruningStates = states.filter(({ plugin }) => {
|
|
1782
|
+
const { include } = plugin.options;
|
|
1783
|
+
return (include?.some(({ type }) => OPERATION_FILTER_TYPES.has(type)) ?? false) && !(include?.some(({ type }) => type === "schemaName") ?? false);
|
|
1784
|
+
});
|
|
1785
|
+
if (pruningStates.length > 0) {
|
|
1786
|
+
const allSchemas = [];
|
|
1787
|
+
for await (const schema of schemas) allSchemas.push(schema);
|
|
1788
|
+
const includedOpsByState = new Map(pruningStates.map((s) => [s, []]));
|
|
1789
|
+
for await (const operation of operations) for (const state of pruningStates) {
|
|
1790
|
+
const { exclude, include, override } = state.plugin.options;
|
|
1791
|
+
if (state.generatorContext.resolver.resolveOptions(operation, {
|
|
1792
|
+
options: state.plugin.options,
|
|
1793
|
+
exclude,
|
|
1794
|
+
include,
|
|
1795
|
+
override
|
|
1796
|
+
}) !== null) includedOpsByState.get(state)?.push(operation);
|
|
1797
|
+
}
|
|
1798
|
+
for (const state of pruningStates) {
|
|
1799
|
+
state.allowedSchemaNames = collectUsedSchemaNames(includedOpsByState.get(state) ?? [], allSchemas);
|
|
1800
|
+
includedOpsByState.delete(state);
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
const resolveRendererFor = (gen, state) => gen.renderer === null ? void 0 : gen.renderer ?? state.plugin.renderer ?? state.generatorContext.config.renderer;
|
|
1804
|
+
const dispatchSchema = async (state, node) => {
|
|
1805
|
+
if (state.failed) return;
|
|
1806
|
+
try {
|
|
1807
|
+
const { plugin, generatorContext, generators } = state;
|
|
1808
|
+
const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node;
|
|
1809
|
+
if (state.allowedSchemaNames !== null && transformedNode.name && !state.allowedSchemaNames.has(transformedNode.name)) return;
|
|
1810
|
+
const { exclude, include, override } = plugin.options;
|
|
1811
|
+
const options = state.optionsAreStatic ? plugin.options : generatorContext.resolver.resolveOptions(transformedNode, {
|
|
1812
|
+
options: plugin.options,
|
|
1813
|
+
exclude,
|
|
1814
|
+
include,
|
|
1815
|
+
override
|
|
1816
|
+
});
|
|
1817
|
+
if (options === null) return;
|
|
1818
|
+
const ctx = {
|
|
1819
|
+
...generatorContext,
|
|
1820
|
+
options
|
|
1821
|
+
};
|
|
1822
|
+
for (const gen of generators) {
|
|
1823
|
+
if (!gen.schema) continue;
|
|
1824
|
+
const raw = gen.schema(transformedNode, ctx);
|
|
1825
|
+
const applied = applyHookResult({
|
|
1826
|
+
result: isPromise(raw) ? await raw : raw,
|
|
1827
|
+
driver,
|
|
1828
|
+
rendererFactory: resolveRendererFor(gen, state)
|
|
1829
|
+
});
|
|
1830
|
+
if (isPromise(applied)) await applied;
|
|
1831
|
+
}
|
|
1832
|
+
if (emitsSchemaHook) await this.hooks.emit("kubb:generate:schema", transformedNode, ctx);
|
|
1833
|
+
} catch (caughtError) {
|
|
1834
|
+
state.failed = true;
|
|
1835
|
+
state.error = caughtError;
|
|
1836
|
+
}
|
|
1837
|
+
};
|
|
1838
|
+
const dispatchOperation = async (state, node) => {
|
|
1839
|
+
if (state.failed) return;
|
|
1840
|
+
try {
|
|
1841
|
+
const { plugin, generatorContext, generators } = state;
|
|
1842
|
+
const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node;
|
|
1843
|
+
const { exclude, include, override } = plugin.options;
|
|
1844
|
+
const options = state.optionsAreStatic ? plugin.options : generatorContext.resolver.resolveOptions(transformedNode, {
|
|
1845
|
+
options: plugin.options,
|
|
1846
|
+
exclude,
|
|
1847
|
+
include,
|
|
1848
|
+
override
|
|
1849
|
+
});
|
|
1850
|
+
if (options === null) return;
|
|
1851
|
+
const ctx = {
|
|
1852
|
+
...generatorContext,
|
|
1853
|
+
options
|
|
1854
|
+
};
|
|
1855
|
+
for (const gen of generators) {
|
|
1856
|
+
if (!gen.operation) continue;
|
|
1857
|
+
const raw = gen.operation(transformedNode, ctx);
|
|
1858
|
+
const applied = applyHookResult({
|
|
1859
|
+
result: isPromise(raw) ? await raw : raw,
|
|
1860
|
+
driver,
|
|
1861
|
+
rendererFactory: resolveRendererFor(gen, state)
|
|
1862
|
+
});
|
|
1863
|
+
if (isPromise(applied)) await applied;
|
|
1864
|
+
}
|
|
1865
|
+
if (emitsOperationHook) await this.hooks.emit("kubb:generate:operation", transformedNode, ctx);
|
|
1866
|
+
} catch (caughtError) {
|
|
1867
|
+
state.failed = true;
|
|
1868
|
+
state.error = caughtError;
|
|
1869
|
+
}
|
|
1870
|
+
};
|
|
1871
|
+
const needsCollectedOperations = this.hooks.listenerCount("kubb:generate:operations") > 0 || states.some((s) => s.generators.some((g) => !!g.operations));
|
|
1872
|
+
const collectedOperations = needsCollectedOperations ? [] : void 0;
|
|
1873
|
+
await forBatches(schemas, (nodes) => Promise.all(nodes.flatMap((n) => states.map((state) => dispatchSchema(state, n)))), {
|
|
1874
|
+
concurrency: 8,
|
|
1875
|
+
flush: flushPending
|
|
1876
|
+
});
|
|
1877
|
+
await forBatches(operations, (nodes) => {
|
|
1878
|
+
if (needsCollectedOperations) collectedOperations.push(...nodes);
|
|
1879
|
+
return Promise.all(nodes.flatMap((n) => states.map((state) => dispatchOperation(state, n))));
|
|
1880
|
+
}, {
|
|
1881
|
+
concurrency: 8,
|
|
1882
|
+
flush: flushPending
|
|
1883
|
+
});
|
|
1884
|
+
for (const state of states) {
|
|
1885
|
+
if (!state.failed && needsCollectedOperations) try {
|
|
1886
|
+
const { plugin, generatorContext, generators } = state;
|
|
1887
|
+
const ctx = {
|
|
1888
|
+
...generatorContext,
|
|
1889
|
+
options: plugin.options
|
|
1890
|
+
};
|
|
1891
|
+
const pluginOperations = state.optionsAreStatic ? collectedOperations : collectedOperations.filter((node) => {
|
|
1892
|
+
const transformed = plugin.transformer ? transform(node, plugin.transformer) : node;
|
|
1893
|
+
const { exclude, include, override } = plugin.options;
|
|
1894
|
+
return generatorContext.resolver.resolveOptions(transformed, {
|
|
1895
|
+
options: plugin.options,
|
|
1896
|
+
exclude,
|
|
1897
|
+
include,
|
|
1898
|
+
override
|
|
1899
|
+
}) !== null;
|
|
1900
|
+
});
|
|
1901
|
+
for (const gen of generators) {
|
|
1902
|
+
if (!gen.operations) continue;
|
|
1903
|
+
await applyHookResult({
|
|
1904
|
+
result: await gen.operations(pluginOperations, ctx),
|
|
1905
|
+
driver,
|
|
1906
|
+
rendererFactory: resolveRendererFor(gen, state)
|
|
1907
|
+
});
|
|
1908
|
+
}
|
|
1909
|
+
await this.hooks.emit("kubb:generate:operations", pluginOperations, ctx);
|
|
1910
|
+
} catch (caughtError) {
|
|
1911
|
+
state.failed = true;
|
|
1912
|
+
state.error = caughtError;
|
|
1913
|
+
}
|
|
1914
|
+
const duration = getElapsedMs(state.hrStart);
|
|
1915
|
+
timings.set(state.plugin.name, duration);
|
|
1916
|
+
await this.#emitPluginEnd({
|
|
1917
|
+
plugin: state.plugin,
|
|
1918
|
+
duration,
|
|
1919
|
+
success: !state.failed,
|
|
1920
|
+
error: state.failed && state.error ? state.error : void 0
|
|
1921
|
+
});
|
|
1922
|
+
if (state.failed && state.error) failed.add({
|
|
1923
|
+
plugin: state.plugin,
|
|
1924
|
+
error: state.error
|
|
1925
|
+
});
|
|
1926
|
+
await this.hooks.emit("kubb:debug", {
|
|
1927
|
+
date: /* @__PURE__ */ new Date(),
|
|
1928
|
+
logs: [state.failed ? "✗ Plugin start failed" : `✓ Plugin started successfully (${formatMs(duration)})`]
|
|
1929
|
+
});
|
|
1930
|
+
}
|
|
1931
|
+
return {
|
|
1932
|
+
timings,
|
|
1933
|
+
failed
|
|
1934
|
+
};
|
|
1935
|
+
}
|
|
1936
|
+
/**
|
|
1305
1937
|
* Unregisters all plugin lifecycle listeners from the shared event emitter.
|
|
1306
1938
|
* Called at the end of a build to prevent listener leaks across repeated builds.
|
|
1307
1939
|
*
|
|
@@ -1314,11 +1946,12 @@ var KubbDriver = class KubbDriver {
|
|
|
1314
1946
|
this.#resolvers.clear();
|
|
1315
1947
|
this.#defaultResolvers.clear();
|
|
1316
1948
|
this.fileManager.dispose();
|
|
1317
|
-
this.
|
|
1949
|
+
this.#fileProcessor.dispose();
|
|
1950
|
+
this.inputNode = null;
|
|
1318
1951
|
this.#studio = {
|
|
1319
|
-
source:
|
|
1952
|
+
source: null,
|
|
1320
1953
|
isOpen: false,
|
|
1321
|
-
inputNode:
|
|
1954
|
+
inputNode: null
|
|
1322
1955
|
};
|
|
1323
1956
|
for (const [event, handler] of this.#middlewareListeners) this.hooks.off(event, handler);
|
|
1324
1957
|
}
|
|
@@ -1438,10 +2071,15 @@ function applyHookResult({ result, driver, rendererFactory }) {
|
|
|
1438
2071
|
}
|
|
1439
2072
|
if (!rendererFactory) return;
|
|
1440
2073
|
const renderer = rendererFactory();
|
|
1441
|
-
if (renderer.stream) {
|
|
1442
|
-
|
|
1443
|
-
|
|
2074
|
+
if (renderer.stream) try {
|
|
2075
|
+
var _usingCtx$1 = _usingCtx();
|
|
2076
|
+
const r = _usingCtx$1.u(renderer);
|
|
2077
|
+
for (const file of r.stream(result)) driver.fileManager.upsert(file);
|
|
1444
2078
|
return;
|
|
2079
|
+
} catch (_) {
|
|
2080
|
+
_usingCtx$1.e = _;
|
|
2081
|
+
} finally {
|
|
2082
|
+
_usingCtx$1.d();
|
|
1445
2083
|
}
|
|
1446
2084
|
return applyAsyncRender({
|
|
1447
2085
|
renderer,
|
|
@@ -1450,9 +2088,16 @@ function applyHookResult({ result, driver, rendererFactory }) {
|
|
|
1450
2088
|
});
|
|
1451
2089
|
}
|
|
1452
2090
|
async function applyAsyncRender({ renderer, result, driver }) {
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
2091
|
+
try {
|
|
2092
|
+
var _usingCtx3 = _usingCtx();
|
|
2093
|
+
const r = _usingCtx3.u(renderer);
|
|
2094
|
+
await r.render(result);
|
|
2095
|
+
driver.fileManager.upsert(...r.files);
|
|
2096
|
+
} catch (_) {
|
|
2097
|
+
_usingCtx3.e = _;
|
|
2098
|
+
} finally {
|
|
2099
|
+
_usingCtx3.d();
|
|
2100
|
+
}
|
|
1456
2101
|
}
|
|
1457
2102
|
function inputToAdapterSource(config) {
|
|
1458
2103
|
const input = config.input;
|
|
@@ -1471,6 +2116,6 @@ function inputToAdapterSource(config) {
|
|
|
1471
2116
|
};
|
|
1472
2117
|
}
|
|
1473
2118
|
//#endregion
|
|
1474
|
-
export {
|
|
2119
|
+
export { FileManager as a, DEFAULT_BANNER as c, logLevel as d, URLPath as f, FileProcessor as i, DEFAULT_EXTENSION as l, BuildError as m, applyHookResult as n, defineResolver as o, AsyncEventEmitter as p, _usingCtx as r, definePlugin as s, KubbDriver as t, DEFAULT_STUDIO_URL as u };
|
|
1475
2120
|
|
|
1476
|
-
//# sourceMappingURL=KubbDriver-
|
|
2121
|
+
//# sourceMappingURL=KubbDriver-l31wllgN.js.map
|