@kubb/core 4.32.4 → 4.33.1

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.
Files changed (85) hide show
  1. package/dist/hooks.d.ts +1 -1
  2. package/dist/index.cjs +1695 -82
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.ts +150 -20
  5. package/dist/index.js +1673 -65
  6. package/dist/index.js.map +1 -1
  7. package/dist/{types-f_no0d7G.d.ts → types-DfjjJb2r.d.ts} +70 -27
  8. package/package.json +3 -24
  9. package/src/BarrelManager.ts +10 -31
  10. package/src/PackageManager.ts +13 -21
  11. package/src/PluginManager.ts +65 -87
  12. package/src/PromiseManager.ts +3 -5
  13. package/src/build.ts +61 -47
  14. package/src/config.ts +1 -1
  15. package/src/constants.ts +60 -0
  16. package/src/errors.ts +1 -14
  17. package/src/index.ts +6 -3
  18. package/src/types.ts +5 -14
  19. package/src/utils/FunctionParams.ts +7 -8
  20. package/src/utils/TreeNode.ts +12 -23
  21. package/src/utils/executeStrategies.ts +5 -3
  22. package/src/utils/formatters.ts +3 -20
  23. package/src/utils/getBarrelFiles.ts +8 -2
  24. package/src/utils/getConfigs.ts +6 -15
  25. package/src/utils/getPlugins.ts +7 -7
  26. package/src/utils/linters.ts +3 -20
  27. package/dist/fs-D4eqq6bR.cjs +0 -103
  28. package/dist/fs-D4eqq6bR.cjs.map +0 -1
  29. package/dist/fs-TVBCPkE-.js +0 -67
  30. package/dist/fs-TVBCPkE-.js.map +0 -1
  31. package/dist/fs.cjs +0 -8
  32. package/dist/fs.d.ts +0 -23
  33. package/dist/fs.js +0 -2
  34. package/dist/packageManager-_7I0WFQU.d.ts +0 -82
  35. package/dist/packageManager-jzjuEj2U.cjs +0 -1103
  36. package/dist/packageManager-jzjuEj2U.cjs.map +0 -1
  37. package/dist/packageManager-wMCQlgd6.js +0 -1024
  38. package/dist/packageManager-wMCQlgd6.js.map +0 -1
  39. package/dist/transformers-BwSpAhvT.js +0 -267
  40. package/dist/transformers-BwSpAhvT.js.map +0 -1
  41. package/dist/transformers-BweFhqh-.cjs +0 -380
  42. package/dist/transformers-BweFhqh-.cjs.map +0 -1
  43. package/dist/transformers.cjs +0 -24
  44. package/dist/transformers.d.ts +0 -108
  45. package/dist/transformers.js +0 -2
  46. package/dist/utils.cjs +0 -430
  47. package/dist/utils.cjs.map +0 -1
  48. package/dist/utils.d.ts +0 -290
  49. package/dist/utils.js +0 -402
  50. package/dist/utils.js.map +0 -1
  51. package/src/BaseGenerator.ts +0 -34
  52. package/src/fs/clean.ts +0 -5
  53. package/src/fs/exists.ts +0 -16
  54. package/src/fs/index.ts +0 -5
  55. package/src/fs/read.ts +0 -13
  56. package/src/fs/utils.ts +0 -32
  57. package/src/fs/write.ts +0 -46
  58. package/src/transformers/casing.ts +0 -62
  59. package/src/transformers/combineCodes.ts +0 -3
  60. package/src/transformers/createJSDocBlockText.ts +0 -9
  61. package/src/transformers/escape.ts +0 -31
  62. package/src/transformers/indent.ts +0 -3
  63. package/src/transformers/index.ts +0 -46
  64. package/src/transformers/nameSorter.ts +0 -9
  65. package/src/transformers/searchAndReplace.ts +0 -25
  66. package/src/transformers/stringify.ts +0 -25
  67. package/src/transformers/toRegExp.ts +0 -22
  68. package/src/transformers/transformReservedWord.ts +0 -106
  69. package/src/transformers/trim.ts +0 -18
  70. package/src/utils/AsyncEventEmitter.ts +0 -48
  71. package/src/utils/Cache.ts +0 -31
  72. package/src/utils/URLPath.ts +0 -146
  73. package/src/utils/buildJSDoc.ts +0 -34
  74. package/src/utils/checkOnlineStatus.ts +0 -40
  75. package/src/utils/formatHrtime.ts +0 -33
  76. package/src/utils/getNestedAccessor.ts +0 -25
  77. package/src/utils/index.ts +0 -26
  78. package/src/utils/packageManager.ts +0 -58
  79. package/src/utils/promise.ts +0 -13
  80. package/src/utils/renderTemplate.ts +0 -31
  81. package/src/utils/serializePluginOptions.ts +0 -29
  82. package/src/utils/timeout.ts +0 -11
  83. package/src/utils/tokenize.ts +0 -23
  84. package/src/utils/types.ts +0 -1
  85. package/src/utils/uniqueName.ts +0 -20
package/dist/index.cjs CHANGED
@@ -3,12 +3,16 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("./chunk-ByKO4r7w.cjs");
6
- const require_packageManager = require("./packageManager-jzjuEj2U.cjs");
7
- const require_fs = require("./fs-D4eqq6bR.cjs");
8
6
  let node_path = require("node:path");
7
+ node_path = require_chunk.__toESM(node_path);
8
+ let node_events = require("node:events");
9
+ let node_util = require("node:util");
10
+ let node_fs = require("node:fs");
11
+ let node_fs_promises = require("node:fs/promises");
9
12
  let _kubb_react_fabric = require("@kubb/react-fabric");
10
13
  let _kubb_react_fabric_parsers = require("@kubb/react-fabric/parsers");
11
14
  let _kubb_react_fabric_plugins = require("@kubb/react-fabric/plugins");
15
+ let node_perf_hooks = require("node:perf_hooks");
12
16
  let node_process = require("node:process");
13
17
  let node_module = require("node:module");
14
18
  node_module = require_chunk.__toESM(node_module);
@@ -18,30 +22,641 @@ let node_url = require("node:url");
18
22
  let empathic_package = require("empathic/package");
19
23
  empathic_package = require_chunk.__toESM(empathic_package);
20
24
  let semver = require("semver");
21
- //#region src/BaseGenerator.ts
25
+ let remeda = require("remeda");
26
+ let tinyexec = require("tinyexec");
27
+ //#region ../../internals/utils/dist/index.js
28
+ /** Thrown when a plugin's configuration or input fails validation. */
29
+ var ValidationPluginError = class extends Error {};
22
30
  /**
23
- * Abstract class that contains the building blocks for plugins to create their own Generator
24
- * @link idea based on https://github.com/colinhacks/zod/blob/master/src/types.ts#L137
31
+ * Thrown when one or more errors occur during a Kubb build.
32
+ * Carries the full list of underlying errors on `errors`.
25
33
  */
26
- var BaseGenerator = class {
27
- #options = {};
28
- #context = {};
29
- constructor(options, context) {
30
- if (context) this.#context = context;
31
- if (options) this.#options = options;
32
- return this;
34
+ var BuildError = class extends Error {
35
+ errors;
36
+ constructor(message, options) {
37
+ super(message, { cause: options.cause });
38
+ this.name = "BuildError";
39
+ this.errors = options.errors;
40
+ }
41
+ };
42
+ /**
43
+ * Coerces an unknown thrown value to an `Error` instance.
44
+ * When the value is already an `Error` it is returned as-is;
45
+ * otherwise a new `Error` is created whose message is `String(value)`.
46
+ */
47
+ function toError(value) {
48
+ return value instanceof Error ? value : new Error(String(value));
49
+ }
50
+ /**
51
+ * A typed EventEmitter that awaits all async listeners before resolving.
52
+ * Wraps Node's `EventEmitter` with full TypeScript event-map inference.
53
+ */
54
+ var AsyncEventEmitter = class {
55
+ /**
56
+ * `maxListener` controls the 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);
33
61
  }
34
- get options() {
35
- return this.#options;
62
+ #emitter = new node_events.EventEmitter();
63
+ /**
64
+ * Emits an event and awaits all registered listeners in parallel.
65
+ * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.
66
+ */
67
+ async emit(eventName, ...eventArgs) {
68
+ const listeners = this.#emitter.listeners(eventName);
69
+ if (listeners.length === 0) return;
70
+ await Promise.all(listeners.map(async (listener) => {
71
+ try {
72
+ return await listener(...eventArgs);
73
+ } catch (err) {
74
+ let serializedArgs;
75
+ try {
76
+ serializedArgs = JSON.stringify(eventArgs);
77
+ } catch {
78
+ serializedArgs = String(eventArgs);
79
+ }
80
+ throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
81
+ }
82
+ }));
36
83
  }
37
- get context() {
38
- return this.#context;
84
+ /** Registers a persistent listener for the given event. */
85
+ on(eventName, handler) {
86
+ this.#emitter.on(eventName, handler);
39
87
  }
40
- set options(options) {
41
- this.#options = {
42
- ...this.#options,
43
- ...options
88
+ /** Registers a one-shot listener that removes itself after the first invocation. */
89
+ onOnce(eventName, handler) {
90
+ const wrapper = (...args) => {
91
+ this.off(eventName, wrapper);
92
+ return handler(...args);
44
93
  };
94
+ this.on(eventName, wrapper);
95
+ }
96
+ /** Removes a previously registered listener. */
97
+ off(eventName, handler) {
98
+ this.#emitter.off(eventName, handler);
99
+ }
100
+ /** Removes all listeners from every event channel. */
101
+ removeAll() {
102
+ this.#emitter.removeAllListeners();
103
+ }
104
+ };
105
+ /**
106
+ * Shared implementation for camelCase and PascalCase conversion.
107
+ * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
108
+ * and capitalizes each word according to `pascal`.
109
+ *
110
+ * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
111
+ */
112
+ function toCamelOrPascal(text, pascal) {
113
+ 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) => {
114
+ if (word.length > 1 && word === word.toUpperCase()) return word;
115
+ if (i === 0 && !pascal) return word.charAt(0).toLowerCase() + word.slice(1);
116
+ return word.charAt(0).toUpperCase() + word.slice(1);
117
+ }).join("").replace(/[^a-zA-Z0-9]/g, "");
118
+ }
119
+ /**
120
+ * Splits `text` on `.` and applies `transformPart` to each segment.
121
+ * The last segment receives `isLast = true`, all earlier segments receive `false`.
122
+ * Segments are joined with `/` to form a file path.
123
+ */
124
+ function applyToFileParts(text, transformPart) {
125
+ const parts = text.split(".");
126
+ return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join("/");
127
+ }
128
+ /**
129
+ * Converts `text` to camelCase.
130
+ * When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`.
131
+ *
132
+ * @example
133
+ * camelCase('hello-world') // 'helloWorld'
134
+ * camelCase('pet.petId', { isFile: true }) // 'pet/petId'
135
+ */
136
+ function camelCase(text, { isFile, prefix = "", suffix = "" } = {}) {
137
+ if (isFile) return applyToFileParts(text, (part, isLast) => camelCase(part, isLast ? {
138
+ prefix,
139
+ suffix
140
+ } : {}));
141
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
142
+ }
143
+ /** Returns a `CLIAdapter` with type inference. Pass a different adapter to `createCLI` to swap the CLI engine. */
144
+ function defineCLIAdapter(adapter) {
145
+ return adapter;
146
+ }
147
+ /**
148
+ * Serializes `CommandDefinition[]` to a plain, JSON-serializable structure.
149
+ * Use to expose CLI capabilities to AI agents or MCP tools.
150
+ */
151
+ function getCommandSchema(defs) {
152
+ return defs.map(serializeCommand);
153
+ }
154
+ function serializeCommand(def) {
155
+ return {
156
+ name: def.name,
157
+ description: def.description,
158
+ arguments: def.arguments,
159
+ options: serializeOptions(def.options ?? {}),
160
+ subCommands: def.subCommands ? def.subCommands.map(serializeCommand) : []
161
+ };
162
+ }
163
+ function serializeOptions(options) {
164
+ return Object.entries(options).map(([name, opt]) => {
165
+ return {
166
+ name,
167
+ flags: `${opt.short ? `-${opt.short}, ` : ""}--${name}${opt.type === "string" ? ` <${opt.hint ?? name}>` : ""}`,
168
+ type: opt.type,
169
+ description: opt.description,
170
+ ...opt.default !== void 0 ? { default: opt.default } : {},
171
+ ...opt.hint ? { hint: opt.hint } : {},
172
+ ...opt.enum ? { enum: opt.enum } : {},
173
+ ...opt.required ? { required: opt.required } : {}
174
+ };
175
+ });
176
+ }
177
+ /** Prints formatted help output for a command using its `CommandDefinition`. */
178
+ function renderHelp(def, parentName) {
179
+ const schema = getCommandSchema([def])[0];
180
+ const programName = parentName ? `${parentName} ${schema.name}` : schema.name;
181
+ const argsPart = schema.arguments?.length ? ` ${schema.arguments.join(" ")}` : "";
182
+ const subCmdPart = schema.subCommands.length ? " <command>" : "";
183
+ console.log(`\n${(0, node_util.styleText)("bold", "Usage:")} ${programName}${argsPart}${subCmdPart} [options]\n`);
184
+ if (schema.description) console.log(` ${schema.description}\n`);
185
+ if (schema.subCommands.length) {
186
+ console.log((0, node_util.styleText)("bold", "Commands:"));
187
+ for (const sub of schema.subCommands) console.log(` ${(0, node_util.styleText)("cyan", sub.name.padEnd(16))}${sub.description}`);
188
+ console.log();
189
+ }
190
+ const options = [...schema.options, {
191
+ name: "help",
192
+ flags: "-h, --help",
193
+ type: "boolean",
194
+ description: "Show help"
195
+ }];
196
+ console.log((0, node_util.styleText)("bold", "Options:"));
197
+ for (const opt of options) {
198
+ const flags = (0, node_util.styleText)("cyan", opt.flags.padEnd(30));
199
+ const defaultPart = opt.default !== void 0 ? (0, node_util.styleText)("dim", ` (default: ${opt.default})`) : "";
200
+ console.log(` ${flags}${opt.description}${defaultPart}`);
201
+ }
202
+ console.log();
203
+ }
204
+ function buildParseOptions(def) {
205
+ const result = { help: {
206
+ type: "boolean",
207
+ short: "h"
208
+ } };
209
+ for (const [name, opt] of Object.entries(def.options ?? {})) result[name] = {
210
+ type: opt.type,
211
+ ...opt.short ? { short: opt.short } : {},
212
+ ...opt.default !== void 0 ? { default: opt.default } : {}
213
+ };
214
+ return result;
215
+ }
216
+ async function runCommand(def, argv, parentName) {
217
+ const parseOptions = buildParseOptions(def);
218
+ let parsed;
219
+ try {
220
+ const result = (0, node_util.parseArgs)({
221
+ args: argv,
222
+ options: parseOptions,
223
+ allowPositionals: true,
224
+ strict: false
225
+ });
226
+ parsed = {
227
+ values: result.values,
228
+ positionals: result.positionals
229
+ };
230
+ } catch {
231
+ renderHelp(def, parentName);
232
+ process.exit(1);
233
+ }
234
+ if (parsed.values["help"]) {
235
+ renderHelp(def, parentName);
236
+ process.exit(0);
237
+ }
238
+ for (const [name, opt] of Object.entries(def.options ?? {})) if (opt.required && parsed.values[name] === void 0) {
239
+ console.error((0, node_util.styleText)("red", `Error: --${name} is required`));
240
+ renderHelp(def, parentName);
241
+ process.exit(1);
242
+ }
243
+ if (!def.run) {
244
+ renderHelp(def, parentName);
245
+ process.exit(0);
246
+ }
247
+ try {
248
+ await def.run(parsed);
249
+ } catch (err) {
250
+ console.error((0, node_util.styleText)("red", `Error: ${err instanceof Error ? err.message : String(err)}`));
251
+ renderHelp(def, parentName);
252
+ process.exit(1);
253
+ }
254
+ }
255
+ function printRootHelp(programName, version, defs) {
256
+ console.log(`\n${(0, node_util.styleText)("bold", "Usage:")} ${programName} <command> [options]\n`);
257
+ console.log(` Kubb generation — v${version}\n`);
258
+ console.log((0, node_util.styleText)("bold", "Commands:"));
259
+ for (const def of defs) console.log(` ${(0, node_util.styleText)("cyan", def.name.padEnd(16))}${def.description}`);
260
+ console.log();
261
+ console.log((0, node_util.styleText)("bold", "Options:"));
262
+ console.log(` ${(0, node_util.styleText)("cyan", "-v, --version".padEnd(30))}Show version number`);
263
+ console.log(` ${(0, node_util.styleText)("cyan", "-h, --help".padEnd(30))}Show help`);
264
+ console.log();
265
+ console.log(`Run ${(0, node_util.styleText)("cyan", `${programName} <command> --help`)} for command-specific help.\n`);
266
+ }
267
+ defineCLIAdapter({
268
+ renderHelp(def, parentName) {
269
+ renderHelp(def, parentName);
270
+ },
271
+ async run(defs, argv, opts) {
272
+ const { programName, defaultCommandName, version } = opts;
273
+ const args = argv.length >= 2 && argv[0]?.includes("node") ? argv.slice(2) : argv;
274
+ if (args[0] === "--version" || args[0] === "-v") {
275
+ console.log(version);
276
+ process.exit(0);
277
+ }
278
+ if (args[0] === "--help" || args[0] === "-h") {
279
+ printRootHelp(programName, version, defs);
280
+ process.exit(0);
281
+ }
282
+ if (args.length === 0) {
283
+ const defaultDef = defs.find((d) => d.name === defaultCommandName);
284
+ if (defaultDef?.run) await runCommand(defaultDef, [], programName);
285
+ else printRootHelp(programName, version, defs);
286
+ return;
287
+ }
288
+ const [first, ...rest] = args;
289
+ const isKnownSubcommand = defs.some((d) => d.name === first);
290
+ let def;
291
+ let commandArgv;
292
+ let parentName;
293
+ if (isKnownSubcommand) {
294
+ def = defs.find((d) => d.name === first);
295
+ commandArgv = rest;
296
+ parentName = programName;
297
+ } else {
298
+ def = defs.find((d) => d.name === defaultCommandName);
299
+ commandArgv = args;
300
+ parentName = programName;
301
+ }
302
+ if (!def) {
303
+ console.error(`Unknown command: ${first}`);
304
+ printRootHelp(programName, version, defs);
305
+ process.exit(1);
306
+ }
307
+ if (def.subCommands?.length) {
308
+ const [subName, ...subRest] = commandArgv;
309
+ const subDef = def.subCommands.find((s) => s.name === subName);
310
+ if (subName === "--help" || subName === "-h") {
311
+ renderHelp(def, parentName);
312
+ process.exit(0);
313
+ }
314
+ if (!subDef) {
315
+ renderHelp(def, parentName);
316
+ process.exit(subName ? 1 : 0);
317
+ }
318
+ await runCommand(subDef, subRest, `${parentName} ${def.name}`);
319
+ return;
320
+ }
321
+ await runCommand(def, commandArgv, parentName);
322
+ }
323
+ });
324
+ /**
325
+ * Calculates elapsed time in milliseconds from a high-resolution start time.
326
+ * Rounds to 2 decimal places to provide sub-millisecond precision without noise.
327
+ */
328
+ function getElapsedMs(hrStart) {
329
+ const [seconds, nanoseconds] = process.hrtime(hrStart);
330
+ const ms = seconds * 1e3 + nanoseconds / 1e6;
331
+ return Math.round(ms * 100) / 100;
332
+ }
333
+ /**
334
+ * Converts a millisecond duration into a human-readable string.
335
+ * Adjusts units (ms, s, m s) based on the magnitude of the duration.
336
+ */
337
+ function formatMs(ms) {
338
+ if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`;
339
+ if (ms >= 1e3) return `${(ms / 1e3).toFixed(2)}s`;
340
+ return `${Math.round(ms)}ms`;
341
+ }
342
+ /**
343
+ * Parses a CSS hex color string (`#RGB`) into its RGB channels.
344
+ * Falls back to `255` for any channel that cannot be parsed.
345
+ */
346
+ function parseHex(color) {
347
+ const int = Number.parseInt(color.replace("#", ""), 16);
348
+ return Number.isNaN(int) ? {
349
+ r: 255,
350
+ g: 255,
351
+ b: 255
352
+ } : {
353
+ r: int >> 16 & 255,
354
+ g: int >> 8 & 255,
355
+ b: int & 255
356
+ };
357
+ }
358
+ /**
359
+ * Returns a function that wraps a string in a 24-bit ANSI true-color escape sequence
360
+ * for the given hex color.
361
+ */
362
+ function hex(color) {
363
+ const { r, g, b } = parseHex(color);
364
+ return (text) => `\x1b[38;2;${r};${g};${b}m${text}\x1b[0m`;
365
+ }
366
+ hex("#F55A17"), hex("#F5A217"), hex("#F58517"), hex("#B45309"), hex("#FFFFFF"), hex("#adadc6"), hex("#FDA4AF");
367
+ /**
368
+ * Converts all backslashes to forward slashes.
369
+ * Extended-length Windows paths (`\\?\...`) are left unchanged.
370
+ */
371
+ function toSlash(p) {
372
+ if (p.startsWith("\\\\?\\")) return p;
373
+ return p.replaceAll("\\", "/");
374
+ }
375
+ /**
376
+ * Returns the relative path from `rootDir` to `filePath`, always using
377
+ * forward slashes and prefixed with `./` when not already traversing upward.
378
+ */
379
+ function getRelativePath(rootDir, filePath) {
380
+ if (!rootDir || !filePath) throw new Error(`Root and file should be filled in when retrieving the relativePath, ${rootDir || ""} ${filePath || ""}`);
381
+ const relativePath = node_path.posix.relative(toSlash(rootDir), toSlash(filePath));
382
+ return relativePath.startsWith("../") ? relativePath : `./${relativePath}`;
383
+ }
384
+ /**
385
+ * Resolves to `true` when the file or directory at `path` exists.
386
+ * Uses `Bun.file().exists()` when running under Bun, `fs.access` otherwise.
387
+ */
388
+ async function exists(path) {
389
+ if (typeof Bun !== "undefined") return Bun.file(path).exists();
390
+ return (0, node_fs_promises.access)(path).then(() => true, () => false);
391
+ }
392
+ /**
393
+ * Reads the file at `path` as a UTF-8 string.
394
+ * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise.
395
+ */
396
+ async function read(path) {
397
+ if (typeof Bun !== "undefined") return Bun.file(path).text();
398
+ return (0, node_fs_promises.readFile)(path, { encoding: "utf8" });
399
+ }
400
+ /** Synchronous counterpart of `read`. */
401
+ function readSync(path) {
402
+ return (0, node_fs.readFileSync)(path, { encoding: "utf8" });
403
+ }
404
+ /**
405
+ * Writes `data` to `path`, trimming leading/trailing whitespace before saving.
406
+ * Skips the write and returns `undefined` when the trimmed content is empty or
407
+ * identical to what is already on disk.
408
+ * Creates any missing parent directories automatically.
409
+ * When `sanity` is `true`, re-reads the file after writing and throws if the
410
+ * content does not match — useful for catching write failures on unreliable file systems.
411
+ */
412
+ async function write(path, data, options = {}) {
413
+ const trimmed = data.trim();
414
+ if (trimmed === "") return void 0;
415
+ const resolved = (0, node_path.resolve)(path);
416
+ if (typeof Bun !== "undefined") {
417
+ const file = Bun.file(resolved);
418
+ if ((await file.exists() ? await file.text() : null) === trimmed) return void 0;
419
+ await Bun.write(resolved, trimmed);
420
+ return trimmed;
421
+ }
422
+ try {
423
+ if (await (0, node_fs_promises.readFile)(resolved, { encoding: "utf-8" }) === trimmed) return void 0;
424
+ } catch {}
425
+ await (0, node_fs_promises.mkdir)((0, node_path.dirname)(resolved), { recursive: true });
426
+ await (0, node_fs_promises.writeFile)(resolved, trimmed, { encoding: "utf-8" });
427
+ if (options.sanity) {
428
+ const savedData = await (0, node_fs_promises.readFile)(resolved, { encoding: "utf-8" });
429
+ if (savedData !== trimmed) throw new Error(`Sanity check failed for ${path}\n\nData[${data.length}]:\n${data}\n\nSaved[${savedData.length}]:\n${savedData}\n`);
430
+ return savedData;
431
+ }
432
+ return trimmed;
433
+ }
434
+ /** Recursively removes `path`. Silently succeeds when `path` does not exist. */
435
+ async function clean(path) {
436
+ return (0, node_fs_promises.rm)(path, {
437
+ recursive: true,
438
+ force: true
439
+ });
440
+ }
441
+ /**
442
+ * Registers `originalName` in `data` without altering the returned name.
443
+ * Use this when you need to track usage frequency but always emit the original identifier.
444
+ */
445
+ function setUniqueName(originalName, data) {
446
+ let used = data[originalName] || 0;
447
+ if (used) {
448
+ data[originalName] = ++used;
449
+ return originalName;
450
+ }
451
+ data[originalName] = 1;
452
+ return originalName;
453
+ }
454
+ /**
455
+ * JavaScript and Java reserved words.
456
+ * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
457
+ */
458
+ const reservedWords = [
459
+ "abstract",
460
+ "arguments",
461
+ "boolean",
462
+ "break",
463
+ "byte",
464
+ "case",
465
+ "catch",
466
+ "char",
467
+ "class",
468
+ "const",
469
+ "continue",
470
+ "debugger",
471
+ "default",
472
+ "delete",
473
+ "do",
474
+ "double",
475
+ "else",
476
+ "enum",
477
+ "eval",
478
+ "export",
479
+ "extends",
480
+ "false",
481
+ "final",
482
+ "finally",
483
+ "float",
484
+ "for",
485
+ "function",
486
+ "goto",
487
+ "if",
488
+ "implements",
489
+ "import",
490
+ "in",
491
+ "instanceof",
492
+ "int",
493
+ "interface",
494
+ "let",
495
+ "long",
496
+ "native",
497
+ "new",
498
+ "null",
499
+ "package",
500
+ "private",
501
+ "protected",
502
+ "public",
503
+ "return",
504
+ "short",
505
+ "static",
506
+ "super",
507
+ "switch",
508
+ "synchronized",
509
+ "this",
510
+ "throw",
511
+ "throws",
512
+ "transient",
513
+ "true",
514
+ "try",
515
+ "typeof",
516
+ "var",
517
+ "void",
518
+ "volatile",
519
+ "while",
520
+ "with",
521
+ "yield",
522
+ "Array",
523
+ "Date",
524
+ "hasOwnProperty",
525
+ "Infinity",
526
+ "isFinite",
527
+ "isNaN",
528
+ "isPrototypeOf",
529
+ "length",
530
+ "Math",
531
+ "name",
532
+ "NaN",
533
+ "Number",
534
+ "Object",
535
+ "prototype",
536
+ "String",
537
+ "toString",
538
+ "undefined",
539
+ "valueOf"
540
+ ];
541
+ /**
542
+ * Prefixes a word with `_` when it is a reserved JavaScript/Java identifier
543
+ * or starts with a digit.
544
+ */
545
+ function transformReservedWord(word) {
546
+ const firstChar = word.charCodeAt(0);
547
+ if (word && (reservedWords.includes(word) || firstChar >= 48 && firstChar <= 57)) return `_${word}`;
548
+ return word;
549
+ }
550
+ /**
551
+ * Returns `true` when `name` is a syntactically valid JavaScript variable name.
552
+ */
553
+ function isValidVarName(name) {
554
+ try {
555
+ new Function(`var ${name}`);
556
+ } catch {
557
+ return false;
558
+ }
559
+ return true;
560
+ }
561
+ /**
562
+ * Parses and transforms an OpenAPI/Swagger path string into various URL formats.
563
+ *
564
+ * @example
565
+ * const p = new URLPath('/pet/{petId}')
566
+ * p.URL // '/pet/:petId'
567
+ * p.template // '`/pet/${petId}`'
568
+ */
569
+ var URLPath = class {
570
+ /** The raw OpenAPI/Swagger path string, e.g. `/pet/{petId}`. */
571
+ path;
572
+ #options;
573
+ constructor(path, options = {}) {
574
+ this.path = path;
575
+ this.#options = options;
576
+ }
577
+ /** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`. */
578
+ get URL() {
579
+ return this.toURLPath();
580
+ }
581
+ /** Returns `true` when `path` is a fully-qualified URL (e.g. starts with `https://`). */
582
+ get isURL() {
583
+ try {
584
+ return !!new URL(this.path).href;
585
+ } catch {
586
+ return false;
587
+ }
588
+ }
589
+ /**
590
+ * Converts the OpenAPI path to a TypeScript template literal string.
591
+ *
592
+ * @example
593
+ * new URLPath('/pet/{petId}').template // '`/pet/${petId}`'
594
+ * new URLPath('/account/monetary-accountID').template // '`/account/${monetaryAccountId}`'
595
+ */
596
+ get template() {
597
+ return this.toTemplateString();
598
+ }
599
+ /** Returns the path and its extracted params as a structured `URLObject`, or as a stringified expression when `stringify` is set. */
600
+ get object() {
601
+ return this.toObject();
602
+ }
603
+ /** Returns a map of path parameter names, or `undefined` when the path has no parameters. */
604
+ get params() {
605
+ return this.getParams();
606
+ }
607
+ #transformParam(raw) {
608
+ const param = isValidVarName(raw) ? raw : camelCase(raw);
609
+ return this.#options.casing === "camelcase" ? camelCase(param) : param;
610
+ }
611
+ /** Iterates over every `{param}` token in `path`, calling `fn` with the raw token and transformed name. */
612
+ #eachParam(fn) {
613
+ for (const match of this.path.matchAll(/\{([^}]+)\}/g)) {
614
+ const raw = match[1];
615
+ fn(raw, this.#transformParam(raw));
616
+ }
617
+ }
618
+ toObject({ type = "path", replacer, stringify } = {}) {
619
+ const object = {
620
+ url: type === "path" ? this.toURLPath() : this.toTemplateString({ replacer }),
621
+ params: this.getParams()
622
+ };
623
+ if (stringify) {
624
+ if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
625
+ if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`;
626
+ return `{ url: '${object.url}' }`;
627
+ }
628
+ return object;
629
+ }
630
+ /**
631
+ * Converts the OpenAPI path to a TypeScript template literal string.
632
+ * An optional `replacer` can transform each extracted parameter name before interpolation.
633
+ *
634
+ * @example
635
+ * new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`'
636
+ */
637
+ toTemplateString({ prefix = "", replacer } = {}) {
638
+ return `\`${prefix}${this.path.split(/\{([^}]+)\}/).map((part, i) => {
639
+ if (i % 2 === 0) return part;
640
+ const param = this.#transformParam(part);
641
+ return `\${${replacer ? replacer(param) : param}}`;
642
+ }).join("")}\``;
643
+ }
644
+ /**
645
+ * Extracts all `{param}` segments from the path and returns them as a key-value map.
646
+ * An optional `replacer` transforms each parameter name in both key and value positions.
647
+ * Returns `undefined` when no path parameters are found.
648
+ */
649
+ getParams(replacer) {
650
+ const params = {};
651
+ this.#eachParam((_raw, param) => {
652
+ const key = replacer ? replacer(param) : param;
653
+ params[key] = key;
654
+ });
655
+ return Object.keys(params).length > 0 ? params : void 0;
656
+ }
657
+ /** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`. */
658
+ toURLPath() {
659
+ return this.path.replace(/\{([^}]+)\}/g, ":$1");
45
660
  }
46
661
  };
47
662
  //#endregion
@@ -69,9 +684,638 @@ function defineConfig(config) {
69
684
  function isInputPath(config) {
70
685
  return typeof config?.input === "object" && config.input !== null && "path" in config.input;
71
686
  }
687
+ const BARREL_FILENAME = "index.ts";
688
+ const DEFAULT_BANNER = "simple";
689
+ const DEFAULT_EXTENSION = { ".ts": ".ts" };
690
+ const PATH_SEPARATORS = ["/", "\\"];
691
+ const logLevel = {
692
+ silent: Number.NEGATIVE_INFINITY,
693
+ error: 0,
694
+ warn: 1,
695
+ info: 3,
696
+ verbose: 4,
697
+ debug: 5
698
+ };
699
+ const linters = {
700
+ eslint: {
701
+ command: "eslint",
702
+ args: (outputPath) => [outputPath, "--fix"],
703
+ errorMessage: "Eslint not found"
704
+ },
705
+ biome: {
706
+ command: "biome",
707
+ args: (outputPath) => [
708
+ "lint",
709
+ "--fix",
710
+ outputPath
711
+ ],
712
+ errorMessage: "Biome not found"
713
+ },
714
+ oxlint: {
715
+ command: "oxlint",
716
+ args: (outputPath) => ["--fix", outputPath],
717
+ errorMessage: "Oxlint not found"
718
+ }
719
+ };
720
+ const formatters = {
721
+ prettier: {
722
+ command: "prettier",
723
+ args: (outputPath) => [
724
+ "--ignore-unknown",
725
+ "--write",
726
+ outputPath
727
+ ],
728
+ errorMessage: "Prettier not found"
729
+ },
730
+ biome: {
731
+ command: "biome",
732
+ args: (outputPath) => [
733
+ "format",
734
+ "--write",
735
+ outputPath
736
+ ],
737
+ errorMessage: "Biome not found"
738
+ },
739
+ oxfmt: {
740
+ command: "oxfmt",
741
+ args: (outputPath) => [outputPath],
742
+ errorMessage: "Oxfmt not found"
743
+ }
744
+ };
745
+ //#endregion
746
+ //#region ../../node_modules/.pnpm/yocto-queue@1.2.2/node_modules/yocto-queue/index.js
747
+ var Node = class {
748
+ value;
749
+ next;
750
+ constructor(value) {
751
+ this.value = value;
752
+ }
753
+ };
754
+ var Queue = class {
755
+ #head;
756
+ #tail;
757
+ #size;
758
+ constructor() {
759
+ this.clear();
760
+ }
761
+ enqueue(value) {
762
+ const node = new Node(value);
763
+ if (this.#head) {
764
+ this.#tail.next = node;
765
+ this.#tail = node;
766
+ } else {
767
+ this.#head = node;
768
+ this.#tail = node;
769
+ }
770
+ this.#size++;
771
+ }
772
+ dequeue() {
773
+ const current = this.#head;
774
+ if (!current) return;
775
+ this.#head = this.#head.next;
776
+ this.#size--;
777
+ if (!this.#head) this.#tail = void 0;
778
+ return current.value;
779
+ }
780
+ peek() {
781
+ if (!this.#head) return;
782
+ return this.#head.value;
783
+ }
784
+ clear() {
785
+ this.#head = void 0;
786
+ this.#tail = void 0;
787
+ this.#size = 0;
788
+ }
789
+ get size() {
790
+ return this.#size;
791
+ }
792
+ *[Symbol.iterator]() {
793
+ let current = this.#head;
794
+ while (current) {
795
+ yield current.value;
796
+ current = current.next;
797
+ }
798
+ }
799
+ *drain() {
800
+ while (this.#head) yield this.dequeue();
801
+ }
802
+ };
803
+ //#endregion
804
+ //#region ../../node_modules/.pnpm/p-limit@7.3.0/node_modules/p-limit/index.js
805
+ function pLimit(concurrency) {
806
+ let rejectOnClear = false;
807
+ if (typeof concurrency === "object") ({concurrency, rejectOnClear = false} = concurrency);
808
+ validateConcurrency(concurrency);
809
+ if (typeof rejectOnClear !== "boolean") throw new TypeError("Expected `rejectOnClear` to be a boolean");
810
+ const queue = new Queue();
811
+ let activeCount = 0;
812
+ const resumeNext = () => {
813
+ if (activeCount < concurrency && queue.size > 0) {
814
+ activeCount++;
815
+ queue.dequeue().run();
816
+ }
817
+ };
818
+ const next = () => {
819
+ activeCount--;
820
+ resumeNext();
821
+ };
822
+ const run = async (function_, resolve, arguments_) => {
823
+ const result = (async () => function_(...arguments_))();
824
+ resolve(result);
825
+ try {
826
+ await result;
827
+ } catch {}
828
+ next();
829
+ };
830
+ const enqueue = (function_, resolve, reject, arguments_) => {
831
+ const queueItem = { reject };
832
+ new Promise((internalResolve) => {
833
+ queueItem.run = internalResolve;
834
+ queue.enqueue(queueItem);
835
+ }).then(run.bind(void 0, function_, resolve, arguments_));
836
+ if (activeCount < concurrency) resumeNext();
837
+ };
838
+ const generator = (function_, ...arguments_) => new Promise((resolve, reject) => {
839
+ enqueue(function_, resolve, reject, arguments_);
840
+ });
841
+ Object.defineProperties(generator, {
842
+ activeCount: { get: () => activeCount },
843
+ pendingCount: { get: () => queue.size },
844
+ clearQueue: { value() {
845
+ if (!rejectOnClear) {
846
+ queue.clear();
847
+ return;
848
+ }
849
+ const abortError = AbortSignal.abort().reason;
850
+ while (queue.size > 0) queue.dequeue().reject(abortError);
851
+ } },
852
+ concurrency: {
853
+ get: () => concurrency,
854
+ set(newConcurrency) {
855
+ validateConcurrency(newConcurrency);
856
+ concurrency = newConcurrency;
857
+ queueMicrotask(() => {
858
+ while (activeCount < concurrency && queue.size > 0) resumeNext();
859
+ });
860
+ }
861
+ },
862
+ map: { async value(iterable, function_) {
863
+ const promises = Array.from(iterable, (value, index) => this(function_, value, index));
864
+ return Promise.all(promises);
865
+ } }
866
+ });
867
+ return generator;
868
+ }
869
+ function validateConcurrency(concurrency) {
870
+ if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) throw new TypeError("Expected `concurrency` to be a number from 1 and up");
871
+ }
872
+ //#endregion
873
+ //#region src/utils/executeStrategies.ts
874
+ /**
875
+ * Chains promises
876
+ */
877
+ function hookSeq(promises) {
878
+ return promises.filter(Boolean).reduce((promise, func) => {
879
+ if (typeof func !== "function") throw new Error("HookSeq needs a function that returns a promise `() => Promise<unknown>`");
880
+ return promise.then((state) => {
881
+ const calledFunc = func(state);
882
+ if (calledFunc) return calledFunc.then(Array.prototype.concat.bind(state));
883
+ return state;
884
+ });
885
+ }, Promise.resolve([]));
886
+ }
887
+ /**
888
+ * Chains promises, first non-null result stops and returns
889
+ */
890
+ function hookFirst(promises, nullCheck = (state) => state !== null) {
891
+ let promise = Promise.resolve(null);
892
+ for (const func of promises.filter(Boolean)) promise = promise.then((state) => {
893
+ if (nullCheck(state)) return state;
894
+ return func(state);
895
+ });
896
+ return promise;
897
+ }
898
+ /**
899
+ * Runs an array of promise functions with optional concurrency limit.
900
+ */
901
+ function hookParallel(promises, concurrency = Number.POSITIVE_INFINITY) {
902
+ const limit = pLimit(concurrency);
903
+ const tasks = promises.filter(Boolean).map((promise) => limit(() => promise()));
904
+ return Promise.allSettled(tasks);
905
+ }
906
+ //#endregion
907
+ //#region src/PromiseManager.ts
908
+ var PromiseManager = class {
909
+ #options = {};
910
+ constructor(options = {}) {
911
+ this.#options = options;
912
+ }
913
+ run(strategy, promises, { concurrency = Number.POSITIVE_INFINITY } = {}) {
914
+ if (strategy === "seq") return hookSeq(promises);
915
+ if (strategy === "first") return hookFirst(promises, this.#options.nullCheck);
916
+ if (strategy === "parallel") return hookParallel(promises, concurrency);
917
+ throw new Error(`${strategy} not implemented`);
918
+ }
919
+ };
920
+ function isPromiseRejectedResult(result) {
921
+ return result.status === "rejected";
922
+ }
923
+ //#endregion
924
+ //#region src/PluginManager.ts
925
+ function getMode(fileOrFolder) {
926
+ if (!fileOrFolder) return "split";
927
+ return node_path.default.extname(fileOrFolder) ? "single" : "split";
928
+ }
929
+ var PluginManager = class {
930
+ config;
931
+ options;
932
+ #plugins = /* @__PURE__ */ new Set();
933
+ #usedPluginNames = {};
934
+ #promiseManager;
935
+ constructor(config, options) {
936
+ this.config = config;
937
+ this.options = options;
938
+ this.#promiseManager = new PromiseManager({ nullCheck: (state) => !!state?.result });
939
+ [...config.plugins || []].forEach((plugin) => {
940
+ const parsedPlugin = this.#parse(plugin);
941
+ this.#plugins.add(parsedPlugin);
942
+ });
943
+ }
944
+ get events() {
945
+ return this.options.events;
946
+ }
947
+ getContext(plugin) {
948
+ const plugins = [...this.#plugins];
949
+ const baseContext = {
950
+ fabric: this.options.fabric,
951
+ config: this.config,
952
+ plugin,
953
+ events: this.options.events,
954
+ pluginManager: this,
955
+ mode: getMode(node_path.default.resolve(this.config.root, this.config.output.path)),
956
+ addFile: async (...files) => {
957
+ await this.options.fabric.addFile(...files);
958
+ },
959
+ upsertFile: async (...files) => {
960
+ await this.options.fabric.upsertFile(...files);
961
+ }
962
+ };
963
+ const mergedExtras = {};
964
+ for (const p of plugins) if (typeof p.inject === "function") {
965
+ const result = p.inject.call(baseContext, baseContext);
966
+ if (result !== null && typeof result === "object") Object.assign(mergedExtras, result);
967
+ }
968
+ return {
969
+ ...baseContext,
970
+ ...mergedExtras
971
+ };
972
+ }
973
+ get plugins() {
974
+ return this.#getSortedPlugins();
975
+ }
976
+ getFile({ name, mode, extname, pluginKey, options }) {
977
+ const baseName = `${name}${extname}`;
978
+ const path = this.resolvePath({
979
+ baseName,
980
+ mode,
981
+ pluginKey,
982
+ options
983
+ });
984
+ if (!path) throw new Error(`Filepath should be defined for resolvedName "${name}" and pluginKey [${JSON.stringify(pluginKey)}]`);
985
+ return {
986
+ path,
987
+ baseName,
988
+ meta: { pluginKey },
989
+ sources: [],
990
+ imports: [],
991
+ exports: []
992
+ };
993
+ }
994
+ resolvePath = (params) => {
995
+ const root = node_path.default.resolve(this.config.root, this.config.output.path);
996
+ const defaultPath = node_path.default.resolve(root, params.baseName);
997
+ if (params.pluginKey) return this.hookForPluginSync({
998
+ pluginKey: params.pluginKey,
999
+ hookName: "resolvePath",
1000
+ parameters: [
1001
+ params.baseName,
1002
+ params.mode,
1003
+ params.options
1004
+ ]
1005
+ })?.at(0) || defaultPath;
1006
+ return this.hookFirstSync({
1007
+ hookName: "resolvePath",
1008
+ parameters: [
1009
+ params.baseName,
1010
+ params.mode,
1011
+ params.options
1012
+ ]
1013
+ })?.result || defaultPath;
1014
+ };
1015
+ resolveName = (params) => {
1016
+ if (params.pluginKey) {
1017
+ const names = this.hookForPluginSync({
1018
+ pluginKey: params.pluginKey,
1019
+ hookName: "resolveName",
1020
+ parameters: [params.name.trim(), params.type]
1021
+ });
1022
+ return transformReservedWord([...new Set(names)].at(0) || params.name);
1023
+ }
1024
+ const name = this.hookFirstSync({
1025
+ hookName: "resolveName",
1026
+ parameters: [params.name.trim(), params.type]
1027
+ })?.result;
1028
+ return transformReservedWord(name ?? params.name);
1029
+ };
1030
+ /**
1031
+ * Run a specific hookName for plugin x.
1032
+ */
1033
+ async hookForPlugin({ pluginKey, hookName, parameters }) {
1034
+ const plugins = this.getPluginsByKey(hookName, pluginKey);
1035
+ this.events.emit("plugins:hook:progress:start", {
1036
+ hookName,
1037
+ plugins
1038
+ });
1039
+ const items = [];
1040
+ for (const plugin of plugins) {
1041
+ const result = await this.#execute({
1042
+ strategy: "hookFirst",
1043
+ hookName,
1044
+ parameters,
1045
+ plugin
1046
+ });
1047
+ if (result !== void 0 && result !== null) items.push(result);
1048
+ }
1049
+ this.events.emit("plugins:hook:progress:end", { hookName });
1050
+ return items;
1051
+ }
1052
+ /**
1053
+ * Run a specific hookName for plugin x.
1054
+ */
1055
+ hookForPluginSync({ pluginKey, hookName, parameters }) {
1056
+ return this.getPluginsByKey(hookName, pluginKey).map((plugin) => {
1057
+ return this.#executeSync({
1058
+ strategy: "hookFirst",
1059
+ hookName,
1060
+ parameters,
1061
+ plugin
1062
+ });
1063
+ }).filter((x) => x !== null);
1064
+ }
1065
+ /**
1066
+ * Returns the first non-null result.
1067
+ */
1068
+ async hookFirst({ hookName, parameters, skipped }) {
1069
+ const plugins = this.#getSortedPlugins(hookName).filter((plugin) => {
1070
+ return skipped ? !skipped.has(plugin) : true;
1071
+ });
1072
+ this.events.emit("plugins:hook:progress:start", {
1073
+ hookName,
1074
+ plugins
1075
+ });
1076
+ const promises = plugins.map((plugin) => {
1077
+ return async () => {
1078
+ const value = await this.#execute({
1079
+ strategy: "hookFirst",
1080
+ hookName,
1081
+ parameters,
1082
+ plugin
1083
+ });
1084
+ return Promise.resolve({
1085
+ plugin,
1086
+ result: value
1087
+ });
1088
+ };
1089
+ });
1090
+ const result = await this.#promiseManager.run("first", promises);
1091
+ this.events.emit("plugins:hook:progress:end", { hookName });
1092
+ return result;
1093
+ }
1094
+ /**
1095
+ * Returns the first non-null result.
1096
+ */
1097
+ hookFirstSync({ hookName, parameters, skipped }) {
1098
+ let parseResult = null;
1099
+ const plugins = this.#getSortedPlugins(hookName).filter((plugin) => {
1100
+ return skipped ? !skipped.has(plugin) : true;
1101
+ });
1102
+ for (const plugin of plugins) {
1103
+ parseResult = {
1104
+ result: this.#executeSync({
1105
+ strategy: "hookFirst",
1106
+ hookName,
1107
+ parameters,
1108
+ plugin
1109
+ }),
1110
+ plugin
1111
+ };
1112
+ if (parseResult?.result != null) break;
1113
+ }
1114
+ return parseResult;
1115
+ }
1116
+ /**
1117
+ * Runs all plugins in parallel based on `this.plugin` order and `pre`/`post` settings.
1118
+ */
1119
+ async hookParallel({ hookName, parameters }) {
1120
+ const plugins = this.#getSortedPlugins(hookName);
1121
+ this.events.emit("plugins:hook:progress:start", {
1122
+ hookName,
1123
+ plugins
1124
+ });
1125
+ const pluginStartTimes = /* @__PURE__ */ new Map();
1126
+ const promises = plugins.map((plugin) => {
1127
+ return () => {
1128
+ pluginStartTimes.set(plugin, node_perf_hooks.performance.now());
1129
+ return this.#execute({
1130
+ strategy: "hookParallel",
1131
+ hookName,
1132
+ parameters,
1133
+ plugin
1134
+ });
1135
+ };
1136
+ });
1137
+ const results = await this.#promiseManager.run("parallel", promises, { concurrency: this.options.concurrency });
1138
+ results.forEach((result, index) => {
1139
+ if (isPromiseRejectedResult(result)) {
1140
+ const plugin = this.#getSortedPlugins(hookName)[index];
1141
+ if (plugin) {
1142
+ const startTime = pluginStartTimes.get(plugin) ?? node_perf_hooks.performance.now();
1143
+ this.events.emit("error", result.reason, {
1144
+ plugin,
1145
+ hookName,
1146
+ strategy: "hookParallel",
1147
+ duration: Math.round(node_perf_hooks.performance.now() - startTime),
1148
+ parameters
1149
+ });
1150
+ }
1151
+ }
1152
+ });
1153
+ this.events.emit("plugins:hook:progress:end", { hookName });
1154
+ return results.reduce((acc, result) => {
1155
+ if (result.status === "fulfilled") acc.push(result.value);
1156
+ return acc;
1157
+ }, []);
1158
+ }
1159
+ /**
1160
+ * Chains plugins
1161
+ */
1162
+ async hookSeq({ hookName, parameters }) {
1163
+ const plugins = this.#getSortedPlugins(hookName);
1164
+ this.events.emit("plugins:hook:progress:start", {
1165
+ hookName,
1166
+ plugins
1167
+ });
1168
+ const promises = plugins.map((plugin) => {
1169
+ return () => this.#execute({
1170
+ strategy: "hookSeq",
1171
+ hookName,
1172
+ parameters,
1173
+ plugin
1174
+ });
1175
+ });
1176
+ await this.#promiseManager.run("seq", promises);
1177
+ this.events.emit("plugins:hook:progress:end", { hookName });
1178
+ }
1179
+ #getSortedPlugins(hookName) {
1180
+ const plugins = [...this.#plugins];
1181
+ if (hookName) return plugins.filter((plugin) => hookName in plugin);
1182
+ return plugins.map((plugin) => {
1183
+ if (plugin.pre) {
1184
+ const missingPlugins = plugin.pre.filter((pluginName) => !plugins.find((pluginToFind) => pluginToFind.name === pluginName));
1185
+ if (missingPlugins.length > 0) throw new ValidationPluginError(`The plugin '${plugin.name}' has a pre set that references missing plugins for '${missingPlugins.join(", ")}'`);
1186
+ }
1187
+ return plugin;
1188
+ }).sort((a, b) => {
1189
+ if (b.pre?.includes(a.name)) return 1;
1190
+ if (b.post?.includes(a.name)) return -1;
1191
+ return 0;
1192
+ });
1193
+ }
1194
+ getPluginByKey(pluginKey) {
1195
+ const plugins = [...this.#plugins];
1196
+ const [searchPluginName] = pluginKey;
1197
+ return plugins.find((item) => {
1198
+ const [name] = item.key;
1199
+ return name === searchPluginName;
1200
+ });
1201
+ }
1202
+ getPluginsByKey(hookName, pluginKey) {
1203
+ const plugins = [...this.plugins];
1204
+ const [searchPluginName, searchIdentifier] = pluginKey;
1205
+ const pluginByPluginName = plugins.filter((plugin) => hookName in plugin).filter((item) => {
1206
+ const [name, identifier] = item.key;
1207
+ const identifierCheck = identifier?.toString() === searchIdentifier?.toString();
1208
+ const nameCheck = name === searchPluginName;
1209
+ if (searchIdentifier) return identifierCheck && nameCheck;
1210
+ return nameCheck;
1211
+ });
1212
+ if (!pluginByPluginName?.length) {
1213
+ const corePlugin = plugins.find((plugin) => plugin.name === "core" && hookName in plugin);
1214
+ return corePlugin ? [corePlugin] : [];
1215
+ }
1216
+ return pluginByPluginName;
1217
+ }
1218
+ /**
1219
+ * Run an async plugin hook and return the result.
1220
+ * @param hookName Name of the plugin hook. Must be either in `PluginHooks` or `OutputPluginValueHooks`.
1221
+ * @param args Arguments passed to the plugin hook.
1222
+ * @param plugin The actual pluginObject to run.
1223
+ */
1224
+ #emitProcessingEnd({ startTime, output, strategy, hookName, plugin, parameters }) {
1225
+ this.events.emit("plugins:hook:processing:end", {
1226
+ duration: Math.round(node_perf_hooks.performance.now() - startTime),
1227
+ parameters,
1228
+ output,
1229
+ strategy,
1230
+ hookName,
1231
+ plugin
1232
+ });
1233
+ }
1234
+ #execute({ strategy, hookName, parameters, plugin }) {
1235
+ const hook = plugin[hookName];
1236
+ if (!hook) return null;
1237
+ this.events.emit("plugins:hook:processing:start", {
1238
+ strategy,
1239
+ hookName,
1240
+ parameters,
1241
+ plugin
1242
+ });
1243
+ const startTime = node_perf_hooks.performance.now();
1244
+ return (async () => {
1245
+ try {
1246
+ const output = typeof hook === "function" ? await Promise.resolve(hook.apply(this.getContext(plugin), parameters ?? [])) : hook;
1247
+ this.#emitProcessingEnd({
1248
+ startTime,
1249
+ output,
1250
+ strategy,
1251
+ hookName,
1252
+ plugin,
1253
+ parameters
1254
+ });
1255
+ return output;
1256
+ } catch (error) {
1257
+ this.events.emit("error", error, {
1258
+ plugin,
1259
+ hookName,
1260
+ strategy,
1261
+ duration: Math.round(node_perf_hooks.performance.now() - startTime)
1262
+ });
1263
+ return null;
1264
+ }
1265
+ })();
1266
+ }
1267
+ /**
1268
+ * Run a sync plugin hook and return the result.
1269
+ * @param hookName Name of the plugin hook. Must be in `PluginHooks`.
1270
+ * @param args Arguments passed to the plugin hook.
1271
+ * @param plugin The actual plugin
1272
+ */
1273
+ #executeSync({ strategy, hookName, parameters, plugin }) {
1274
+ const hook = plugin[hookName];
1275
+ if (!hook) return null;
1276
+ this.events.emit("plugins:hook:processing:start", {
1277
+ strategy,
1278
+ hookName,
1279
+ parameters,
1280
+ plugin
1281
+ });
1282
+ const startTime = node_perf_hooks.performance.now();
1283
+ try {
1284
+ const output = typeof hook === "function" ? hook.apply(this.getContext(plugin), parameters) : hook;
1285
+ this.#emitProcessingEnd({
1286
+ startTime,
1287
+ output,
1288
+ strategy,
1289
+ hookName,
1290
+ plugin,
1291
+ parameters
1292
+ });
1293
+ return output;
1294
+ } catch (error) {
1295
+ this.events.emit("error", error, {
1296
+ plugin,
1297
+ hookName,
1298
+ strategy,
1299
+ duration: Math.round(node_perf_hooks.performance.now() - startTime)
1300
+ });
1301
+ return null;
1302
+ }
1303
+ }
1304
+ #parse(plugin) {
1305
+ const usedPluginNames = this.#usedPluginNames;
1306
+ setUniqueName(plugin.name, usedPluginNames);
1307
+ const usageCount = usedPluginNames[plugin.name];
1308
+ if (usageCount && usageCount > 1) this.events.emit("warn", `Multiple instances of plugin "${plugin.name}" detected. This behavior is deprecated and will be removed in v5.`, `Plugin key: [${plugin.name}, ${usageCount}]`);
1309
+ return {
1310
+ install() {},
1311
+ ...plugin,
1312
+ key: [plugin.name, usedPluginNames[plugin.name]].filter(Boolean)
1313
+ };
1314
+ }
1315
+ };
72
1316
  //#endregion
73
1317
  //#region package.json
74
- var version = "4.32.4";
1318
+ var version = "4.33.1";
75
1319
  //#endregion
76
1320
  //#region src/utils/diagnostics.ts
77
1321
  /**
@@ -89,7 +1333,7 @@ function getDiagnosticInfo() {
89
1333
  //#endregion
90
1334
  //#region src/build.ts
91
1335
  async function setup(options) {
92
- const { config: userConfig, events = new require_packageManager.AsyncEventEmitter() } = options;
1336
+ const { config: userConfig, events = new AsyncEventEmitter() } = options;
93
1337
  const sources = /* @__PURE__ */ new Map();
94
1338
  const diagnosticInfo = getDiagnosticInfo();
95
1339
  if (Array.isArray(userConfig.input)) await events.emit("warn", "This feature is still under development — use with caution");
@@ -110,8 +1354,8 @@ async function setup(options) {
110
1354
  ]
111
1355
  });
112
1356
  try {
113
- if (isInputPath(userConfig) && !new require_packageManager.URLPath(userConfig.input.path).isURL) {
114
- await require_fs.exists(userConfig.input.path);
1357
+ if (isInputPath(userConfig) && !new URLPath(userConfig.input.path).isURL) {
1358
+ await exists(userConfig.input.path);
115
1359
  await events.emit("debug", {
116
1360
  date: /* @__PURE__ */ new Date(),
117
1361
  logs: [`✓ Input file validated: ${userConfig.input.path}`]
@@ -129,8 +1373,8 @@ async function setup(options) {
129
1373
  output: {
130
1374
  write: true,
131
1375
  barrelType: "named",
132
- extension: { ".ts": ".ts" },
133
- defaultBanner: "simple",
1376
+ extension: DEFAULT_EXTENSION,
1377
+ defaultBanner: DEFAULT_BANNER,
134
1378
  ...userConfig.output
135
1379
  },
136
1380
  plugins: userConfig.plugins
@@ -140,7 +1384,7 @@ async function setup(options) {
140
1384
  date: /* @__PURE__ */ new Date(),
141
1385
  logs: ["Cleaning output directories", ` • Output: ${definedConfig.output.path}`]
142
1386
  });
143
- await require_fs.clean(definedConfig.output.path);
1387
+ await clean(definedConfig.output.path);
144
1388
  }
145
1389
  const fabric = (0, _kubb_react_fabric.createFabric)();
146
1390
  fabric.use(_kubb_react_fabric_plugins.fsPlugin);
@@ -160,7 +1404,7 @@ async function setup(options) {
160
1404
  source
161
1405
  });
162
1406
  if (source) {
163
- if (definedConfig.output.write) await require_fs.write(file.path, source, { sanity: false });
1407
+ if (definedConfig.output.write) await write(file.path, source, { sanity: false });
164
1408
  sources.set(file.path, source);
165
1409
  }
166
1410
  });
@@ -182,7 +1426,7 @@ async function setup(options) {
182
1426
  return {
183
1427
  events,
184
1428
  fabric,
185
- pluginManager: new require_packageManager.PluginManager(definedConfig, {
1429
+ pluginManager: new PluginManager(definedConfig, {
186
1430
  fabric,
187
1431
  events,
188
1432
  concurrency: 15
@@ -195,7 +1439,7 @@ async function build(options, overrides) {
195
1439
  if (error) throw error;
196
1440
  if (failedPlugins.size > 0) {
197
1441
  const errors = [...failedPlugins].map(({ error }) => error);
198
- throw new require_packageManager.BuildError(`Build Error with ${failedPlugins.size} failed plugins`, { errors });
1442
+ throw new BuildError(`Build Error with ${failedPlugins.size} failed plugins`, { errors });
199
1443
  }
200
1444
  return {
201
1445
  failedPlugins,
@@ -225,7 +1469,7 @@ async function safeBuild(options, overrides) {
225
1469
  logs: ["Installing plugin...", ` • Plugin Key: [${plugin.key.join(", ")}]`]
226
1470
  });
227
1471
  await installer(context);
228
- const duration = require_packageManager.getElapsedMs(hrStart);
1472
+ const duration = getElapsedMs(hrStart);
229
1473
  pluginTimings.set(plugin.name, duration);
230
1474
  await events.emit("plugin:end", plugin, {
231
1475
  duration,
@@ -233,12 +1477,12 @@ async function safeBuild(options, overrides) {
233
1477
  });
234
1478
  await events.emit("debug", {
235
1479
  date: /* @__PURE__ */ new Date(),
236
- logs: [`✓ Plugin installed successfully (${require_packageManager.formatMs(duration)})`]
1480
+ logs: [`✓ Plugin installed successfully (${formatMs(duration)})`]
237
1481
  });
238
1482
  } catch (caughtError) {
239
1483
  const error = caughtError;
240
1484
  const errorTimestamp = /* @__PURE__ */ new Date();
241
- const duration = require_packageManager.getElapsedMs(hrStart);
1485
+ const duration = getElapsedMs(hrStart);
242
1486
  await events.emit("plugin:end", plugin, {
243
1487
  duration,
244
1488
  success: false,
@@ -261,7 +1505,8 @@ async function safeBuild(options, overrides) {
261
1505
  }
262
1506
  }
263
1507
  if (config.output.barrelType) {
264
- const rootPath = (0, node_path.resolve)((0, node_path.resolve)(config.root), config.output.path, "index.ts");
1508
+ const rootPath = (0, node_path.resolve)((0, node_path.resolve)(config.root), config.output.path, BARREL_FILENAME);
1509
+ const rootDir = (0, node_path.dirname)(rootPath);
265
1510
  await events.emit("debug", {
266
1511
  date: /* @__PURE__ */ new Date(),
267
1512
  logs: [
@@ -277,25 +1522,17 @@ async function safeBuild(options, overrides) {
277
1522
  date: /* @__PURE__ */ new Date(),
278
1523
  logs: [`Found ${barrelFiles.length} indexable files for barrel export`]
279
1524
  });
280
- const pluginKeyMap = /* @__PURE__ */ new Map();
281
- for (const plugin of pluginManager.plugins) pluginKeyMap.set(JSON.stringify(plugin.key), plugin);
1525
+ const existingBarrel = fabric.files.find((f) => f.path === rootPath);
282
1526
  const rootFile = {
283
1527
  path: rootPath,
284
- baseName: "index.ts",
285
- exports: barrelFiles.flatMap((file) => {
286
- const containsOnlyTypes = file.sources?.every((source) => source.isTypeOnly);
287
- return file.sources?.map((source) => {
288
- if (!file.path || !source.isIndexable) return;
289
- const meta = file.meta;
290
- const pluginOptions = (meta?.pluginKey ? pluginKeyMap.get(JSON.stringify(meta.pluginKey)) : void 0)?.options;
291
- if (!pluginOptions || pluginOptions?.output?.barrelType === false) return;
292
- return {
293
- name: config.output.barrelType === "all" ? void 0 : [source.name],
294
- path: require_fs.getRelativePath(rootPath, file.path),
295
- isTypeOnly: config.output.barrelType === "all" ? containsOnlyTypes : source.isTypeOnly
296
- };
297
- }).filter(Boolean);
298
- }).filter(Boolean),
1528
+ baseName: BARREL_FILENAME,
1529
+ exports: buildBarrelExports({
1530
+ barrelFiles,
1531
+ rootDir,
1532
+ existingExports: new Set(existingBarrel?.exports?.flatMap((e) => Array.isArray(e.name) ? e.name : [e.name]).filter((n) => Boolean(n)) ?? []),
1533
+ config,
1534
+ pluginManager
1535
+ }),
299
1536
  sources: [],
300
1537
  imports: [],
301
1538
  meta: {}
@@ -328,6 +1565,26 @@ async function safeBuild(options, overrides) {
328
1565
  };
329
1566
  }
330
1567
  }
1568
+ function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, pluginManager }) {
1569
+ const pluginKeyMap = /* @__PURE__ */ new Map();
1570
+ for (const plugin of pluginManager.plugins) pluginKeyMap.set(JSON.stringify(plugin.key), plugin);
1571
+ return barrelFiles.flatMap((file) => {
1572
+ const containsOnlyTypes = file.sources?.every((source) => source.isTypeOnly);
1573
+ return (file.sources ?? []).flatMap((source) => {
1574
+ if (!file.path || !source.isIndexable) return [];
1575
+ const meta = file.meta;
1576
+ const pluginOptions = (meta?.pluginKey ? pluginKeyMap.get(JSON.stringify(meta.pluginKey)) : void 0)?.options;
1577
+ if (!pluginOptions || pluginOptions.output?.barrelType === false) return [];
1578
+ const exportName = config.output.barrelType === "all" ? void 0 : source.name ? [source.name] : void 0;
1579
+ if (exportName?.some((n) => existingExports.has(n))) return [];
1580
+ return [{
1581
+ name: exportName,
1582
+ path: getRelativePath(rootDir, file.path),
1583
+ isTypeOnly: config.output.barrelType === "all" ? containsOnlyTypes : source.isTypeOnly
1584
+ }];
1585
+ });
1586
+ });
1587
+ }
331
1588
  //#endregion
332
1589
  //#region src/defineLogger.ts
333
1590
  function defineLogger(logger) {
@@ -346,10 +1603,8 @@ function definePlugin(build) {
346
1603
  var PackageManager = class PackageManager {
347
1604
  static #cache = {};
348
1605
  #cwd;
349
- #SLASHES = new Set(["/", "\\"]);
350
1606
  constructor(workspace) {
351
1607
  if (workspace) this.#cwd = workspace;
352
- return this;
353
1608
  }
354
1609
  set workspace(workspace) {
355
1610
  this.#cwd = workspace;
@@ -359,7 +1614,7 @@ var PackageManager = class PackageManager {
359
1614
  }
360
1615
  normalizeDirectory(directory) {
361
1616
  const lastChar = directory[directory.length - 1];
362
- if (lastChar && !this.#SLASHES.has(lastChar)) return `${directory}/`;
1617
+ if (lastChar && !PATH_SEPARATORS.includes(lastChar)) return `${directory}/`;
363
1618
  return directory;
364
1619
  }
365
1620
  getLocation(path) {
@@ -368,26 +1623,21 @@ var PackageManager = class PackageManager {
368
1623
  return location;
369
1624
  }
370
1625
  async import(path) {
371
- try {
372
- let location = this.getLocation(path);
373
- if (node_os.default.platform() === "win32") location = (0, node_url.pathToFileURL)(location).href;
374
- const module = await import(location);
375
- return module?.default ?? module;
376
- } catch (error) {
377
- console.error(error);
378
- return;
379
- }
1626
+ let location = this.getLocation(path);
1627
+ if (node_os.default.platform() === "win32") location = (0, node_url.pathToFileURL)(location).href;
1628
+ const module = await import(location);
1629
+ return module?.default ?? module;
380
1630
  }
381
1631
  async getPackageJSON() {
382
1632
  const pkgPath = empathic_package.up({ cwd: this.#cwd });
383
1633
  if (!pkgPath) return;
384
- const json = await require_fs.read(pkgPath);
1634
+ const json = await read(pkgPath);
385
1635
  return JSON.parse(json);
386
1636
  }
387
1637
  getPackageJSONSync() {
388
1638
  const pkgPath = empathic_package.up({ cwd: this.#cwd });
389
1639
  if (!pkgPath) return;
390
- const json = require_fs.readSync(pkgPath);
1640
+ const json = readSync(pkgPath);
391
1641
  return JSON.parse(json);
392
1642
  }
393
1643
  static setVersion(dependency, version) {
@@ -395,8 +1645,8 @@ var PackageManager = class PackageManager {
395
1645
  }
396
1646
  #match(packageJSON, dependency) {
397
1647
  const dependencies = {
398
- ...packageJSON["dependencies"] || {},
399
- ...packageJSON["devDependencies"] || {}
1648
+ ...packageJSON.dependencies || {},
1649
+ ...packageJSON.devDependencies || {}
400
1650
  };
401
1651
  if (typeof dependency === "string" && dependencies[dependency]) return dependencies[dependency];
402
1652
  const matchedDependency = Object.keys(dependencies).find((dep) => dep.match(dependency));
@@ -432,30 +1682,393 @@ var PackageManager = class PackageManager {
432
1682
  }
433
1683
  };
434
1684
  //#endregion
435
- //#region src/types.ts
436
- const LogLevel = {
437
- silent: Number.NEGATIVE_INFINITY,
438
- error: 0,
439
- warn: 1,
440
- info: 3,
441
- verbose: 4,
442
- debug: 5
1685
+ //#region src/utils/FunctionParams.ts
1686
+ /**
1687
+ * @deprecated
1688
+ */
1689
+ var FunctionParams = class FunctionParams {
1690
+ #items = [];
1691
+ get items() {
1692
+ return this.#items.flat();
1693
+ }
1694
+ add(item) {
1695
+ if (!item) return this;
1696
+ if (Array.isArray(item)) {
1697
+ item.filter((x) => x !== void 0).forEach((it) => {
1698
+ this.#items.push(it);
1699
+ });
1700
+ return this;
1701
+ }
1702
+ this.#items.push(item);
1703
+ return this;
1704
+ }
1705
+ static #orderItems(items) {
1706
+ return (0, remeda.sortBy)(items.filter(Boolean), [(item) => Array.isArray(item), "desc"], [(item) => !Array.isArray(item) && item.default !== void 0, "asc"], [(item) => Array.isArray(item) || (item.required ?? true), "desc"]);
1707
+ }
1708
+ static #addParams(acc, item) {
1709
+ const { enabled = true, name, type, required = true, ...rest } = item;
1710
+ if (!enabled) return acc;
1711
+ if (!name) {
1712
+ acc.push(`${type}${rest.default ? ` = ${rest.default}` : ""}`);
1713
+ return acc;
1714
+ }
1715
+ const parameterName = name.startsWith("{") ? name : camelCase(name);
1716
+ if (type) if (required) acc.push(`${parameterName}: ${type}${rest.default ? ` = ${rest.default}` : ""}`);
1717
+ else acc.push(`${parameterName}?: ${type}`);
1718
+ else acc.push(`${parameterName}`);
1719
+ return acc;
1720
+ }
1721
+ static toObject(items) {
1722
+ let type = [];
1723
+ let name = [];
1724
+ const enabled = items.every((item) => item.enabled) ? items.at(0)?.enabled : true;
1725
+ const required = items.every((item) => item.required) ?? true;
1726
+ items.forEach((item) => {
1727
+ name = FunctionParams.#addParams(name, {
1728
+ ...item,
1729
+ type: void 0
1730
+ });
1731
+ if (items.some((item) => item.type)) type = FunctionParams.#addParams(type, item);
1732
+ });
1733
+ return {
1734
+ name: `{ ${name.join(", ")} }`,
1735
+ type: type.length ? `{ ${type.join("; ")} }` : void 0,
1736
+ enabled,
1737
+ required
1738
+ };
1739
+ }
1740
+ toObject() {
1741
+ const items = FunctionParams.#orderItems(this.#items).flat();
1742
+ return FunctionParams.toObject(items);
1743
+ }
1744
+ static toString(items) {
1745
+ return FunctionParams.#orderItems(items).reduce((acc, item) => {
1746
+ if (Array.isArray(item)) {
1747
+ if (item.length <= 0) return acc;
1748
+ const subItems = FunctionParams.#orderItems(item);
1749
+ const objectItem = FunctionParams.toObject(subItems);
1750
+ return FunctionParams.#addParams(acc, objectItem);
1751
+ }
1752
+ return FunctionParams.#addParams(acc, item);
1753
+ }, []).join(", ");
1754
+ }
1755
+ toString() {
1756
+ const items = FunctionParams.#orderItems(this.#items);
1757
+ return FunctionParams.toString(items);
1758
+ }
443
1759
  };
444
1760
  //#endregion
445
- exports.BaseGenerator = BaseGenerator;
446
- exports.LogLevel = LogLevel;
1761
+ //#region src/utils/formatters.ts
1762
+ /**
1763
+ * Check if a formatter command is available in the system.
1764
+ *
1765
+ * @param formatter - The formatter to check ('biome', 'prettier', or 'oxfmt')
1766
+ * @returns Promise that resolves to true if the formatter is available, false otherwise
1767
+ *
1768
+ * @remarks
1769
+ * This function checks availability by running `<formatter> --version` command.
1770
+ * All supported formatters (biome, prettier, oxfmt) implement the --version flag.
1771
+ */
1772
+ async function isFormatterAvailable(formatter) {
1773
+ try {
1774
+ await (0, tinyexec.x)(formatter, ["--version"], { nodeOptions: { stdio: "ignore" } });
1775
+ return true;
1776
+ } catch {
1777
+ return false;
1778
+ }
1779
+ }
1780
+ /**
1781
+ * Detect which formatter is available in the system.
1782
+ *
1783
+ * @returns Promise that resolves to the first available formatter or undefined if none are found
1784
+ *
1785
+ * @remarks
1786
+ * Checks in order of preference: biome, oxfmt, prettier.
1787
+ * Uses the `--version` flag to detect if each formatter command is available.
1788
+ * This is a reliable method as all supported formatters implement this flag.
1789
+ *
1790
+ * @example
1791
+ * ```typescript
1792
+ * const formatter = await detectFormatter()
1793
+ * if (formatter) {
1794
+ * console.log(`Using ${formatter} for formatting`)
1795
+ * } else {
1796
+ * console.log('No formatter found')
1797
+ * }
1798
+ * ```
1799
+ */
1800
+ async function detectFormatter() {
1801
+ for (const formatter of [
1802
+ "biome",
1803
+ "oxfmt",
1804
+ "prettier"
1805
+ ]) if (await isFormatterAvailable(formatter)) return formatter;
1806
+ }
1807
+ //#endregion
1808
+ //#region src/utils/TreeNode.ts
1809
+ var TreeNode = class TreeNode {
1810
+ data;
1811
+ parent;
1812
+ children = [];
1813
+ #cachedLeaves = void 0;
1814
+ constructor(data, parent) {
1815
+ this.data = data;
1816
+ this.parent = parent;
1817
+ }
1818
+ addChild(data) {
1819
+ const child = new TreeNode(data, this);
1820
+ if (!this.children) this.children = [];
1821
+ this.children.push(child);
1822
+ return child;
1823
+ }
1824
+ get root() {
1825
+ if (!this.parent) return this;
1826
+ return this.parent.root;
1827
+ }
1828
+ get leaves() {
1829
+ if (!this.children || this.children.length === 0) return [this];
1830
+ if (this.#cachedLeaves) return this.#cachedLeaves;
1831
+ const leaves = [];
1832
+ for (const child of this.children) leaves.push(...child.leaves);
1833
+ this.#cachedLeaves = leaves;
1834
+ return leaves;
1835
+ }
1836
+ forEach(callback) {
1837
+ if (typeof callback !== "function") throw new TypeError("forEach() callback must be a function");
1838
+ callback(this);
1839
+ for (const child of this.children) child.forEach(callback);
1840
+ return this;
1841
+ }
1842
+ findDeep(predicate) {
1843
+ if (typeof predicate !== "function") throw new TypeError("find() predicate must be a function");
1844
+ return this.leaves.find(predicate);
1845
+ }
1846
+ forEachDeep(callback) {
1847
+ if (typeof callback !== "function") throw new TypeError("forEach() callback must be a function");
1848
+ this.leaves.forEach(callback);
1849
+ }
1850
+ filterDeep(callback) {
1851
+ if (typeof callback !== "function") throw new TypeError("filter() callback must be a function");
1852
+ return this.leaves.filter(callback);
1853
+ }
1854
+ mapDeep(callback) {
1855
+ if (typeof callback !== "function") throw new TypeError("map() callback must be a function");
1856
+ return this.leaves.map(callback);
1857
+ }
1858
+ static build(files, root) {
1859
+ try {
1860
+ const filteredTree = buildDirectoryTree(files, root);
1861
+ if (!filteredTree) return null;
1862
+ const treeNode = new TreeNode({
1863
+ name: filteredTree.name,
1864
+ path: filteredTree.path,
1865
+ file: filteredTree.file,
1866
+ type: getMode(filteredTree.path)
1867
+ });
1868
+ const recurse = (node, item) => {
1869
+ const subNode = node.addChild({
1870
+ name: item.name,
1871
+ path: item.path,
1872
+ file: item.file,
1873
+ type: getMode(item.path)
1874
+ });
1875
+ if (item.children?.length) item.children?.forEach((child) => {
1876
+ recurse(subNode, child);
1877
+ });
1878
+ };
1879
+ filteredTree.children?.forEach((child) => {
1880
+ recurse(treeNode, child);
1881
+ });
1882
+ return treeNode;
1883
+ } catch (error) {
1884
+ throw new Error("Something went wrong with creating barrel files with the TreeNode class", { cause: error });
1885
+ }
1886
+ }
1887
+ };
1888
+ const normalizePath = (p) => p.replaceAll("\\", "/");
1889
+ function buildDirectoryTree(files, rootFolder = "") {
1890
+ const normalizedRootFolder = normalizePath(rootFolder);
1891
+ const rootPrefix = normalizedRootFolder.endsWith("/") ? normalizedRootFolder : `${normalizedRootFolder}/`;
1892
+ const filteredFiles = files.filter((file) => {
1893
+ const normalizedFilePath = normalizePath(file.path);
1894
+ return rootFolder ? normalizedFilePath.startsWith(rootPrefix) && !normalizedFilePath.endsWith(".json") : !normalizedFilePath.endsWith(".json");
1895
+ });
1896
+ if (filteredFiles.length === 0) return null;
1897
+ const root = {
1898
+ name: rootFolder || "",
1899
+ path: rootFolder || "",
1900
+ children: []
1901
+ };
1902
+ filteredFiles.forEach((file) => {
1903
+ const parts = file.path.slice(rootFolder.length).split("/").filter(Boolean);
1904
+ let currentLevel = root.children;
1905
+ let currentPath = normalizePath(rootFolder);
1906
+ parts.forEach((part, index) => {
1907
+ currentPath = node_path.default.posix.join(currentPath, part);
1908
+ let existingNode = currentLevel.find((node) => node.name === part);
1909
+ if (!existingNode) {
1910
+ if (index === parts.length - 1) existingNode = {
1911
+ name: part,
1912
+ file,
1913
+ path: currentPath
1914
+ };
1915
+ else existingNode = {
1916
+ name: part,
1917
+ path: currentPath,
1918
+ children: []
1919
+ };
1920
+ currentLevel.push(existingNode);
1921
+ }
1922
+ if (!existingNode.file) currentLevel = existingNode.children;
1923
+ });
1924
+ });
1925
+ return root;
1926
+ }
1927
+ //#endregion
1928
+ //#region src/BarrelManager.ts
1929
+ /** biome-ignore-all lint/suspicious/useIterableCallbackReturn: not needed */
1930
+ var BarrelManager = class {
1931
+ getFiles({ files: generatedFiles, root }) {
1932
+ const cachedFiles = /* @__PURE__ */ new Map();
1933
+ TreeNode.build(generatedFiles, root)?.forEach((treeNode) => {
1934
+ if (!treeNode || !treeNode.children || !treeNode.parent?.data.path) return;
1935
+ const barrelFile = {
1936
+ path: (0, node_path.join)(treeNode.parent?.data.path, "index.ts"),
1937
+ baseName: "index.ts",
1938
+ exports: [],
1939
+ imports: [],
1940
+ sources: []
1941
+ };
1942
+ const previousBarrelFile = cachedFiles.get(barrelFile.path);
1943
+ treeNode.leaves.forEach((item) => {
1944
+ if (!item.data.name) return;
1945
+ (item.data.file?.sources || []).forEach((source) => {
1946
+ if (!item.data.file?.path || !source.isIndexable || !source.name) return;
1947
+ if (previousBarrelFile?.sources.some((item) => item.name === source.name && item.isTypeOnly === source.isTypeOnly)) return;
1948
+ barrelFile.exports.push({
1949
+ name: [source.name],
1950
+ path: getRelativePath(treeNode.parent?.data.path, item.data.path),
1951
+ isTypeOnly: source.isTypeOnly
1952
+ });
1953
+ barrelFile.sources.push({
1954
+ name: source.name,
1955
+ isTypeOnly: source.isTypeOnly,
1956
+ value: "",
1957
+ isExportable: false,
1958
+ isIndexable: false
1959
+ });
1960
+ });
1961
+ });
1962
+ if (previousBarrelFile) {
1963
+ previousBarrelFile.sources.push(...barrelFile.sources);
1964
+ previousBarrelFile.exports?.push(...barrelFile.exports || []);
1965
+ } else cachedFiles.set(barrelFile.path, barrelFile);
1966
+ });
1967
+ return [...cachedFiles.values()];
1968
+ }
1969
+ };
1970
+ //#endregion
1971
+ //#region src/utils/getBarrelFiles.ts
1972
+ function trimExtName(text) {
1973
+ const dotIndex = text.lastIndexOf(".");
1974
+ if (dotIndex > 0 && !text.includes("/", dotIndex)) return text.slice(0, dotIndex);
1975
+ return text;
1976
+ }
1977
+ async function getBarrelFiles(files, { type, meta = {}, root, output }) {
1978
+ if (!type || type === "propagate") return [];
1979
+ const barrelManager = new BarrelManager();
1980
+ const pathToBuildFrom = (0, node_path.join)(root, output.path);
1981
+ if (trimExtName(pathToBuildFrom).endsWith("index")) return [];
1982
+ const barrelFiles = barrelManager.getFiles({
1983
+ files,
1984
+ root: pathToBuildFrom,
1985
+ meta
1986
+ });
1987
+ if (type === "all") return barrelFiles.map((file) => {
1988
+ return {
1989
+ ...file,
1990
+ exports: file.exports?.map((exportItem) => {
1991
+ return {
1992
+ ...exportItem,
1993
+ name: void 0
1994
+ };
1995
+ })
1996
+ };
1997
+ });
1998
+ return barrelFiles.map((indexFile) => {
1999
+ return {
2000
+ ...indexFile,
2001
+ meta
2002
+ };
2003
+ });
2004
+ }
2005
+ //#endregion
2006
+ //#region src/utils/getPlugins.ts
2007
+ function isJSONPlugins(plugins) {
2008
+ return Array.isArray(plugins) && plugins.some((plugin) => Array.isArray(plugin) && typeof plugin[0] === "string");
2009
+ }
2010
+ function isObjectPlugins(plugins) {
2011
+ return plugins instanceof Object && !Array.isArray(plugins);
2012
+ }
2013
+ function getPlugins(plugins) {
2014
+ if (isObjectPlugins(plugins)) throw new Error("Object plugins are not supported anymore, best to use http://kubb.dev/getting-started/configure#json");
2015
+ if (isJSONPlugins(plugins)) throw new Error("JSON plugins are not supported anymore, best to use http://kubb.dev/getting-started/configure#json");
2016
+ return Promise.resolve(plugins);
2017
+ }
2018
+ //#endregion
2019
+ //#region src/utils/getConfigs.ts
2020
+ /**
2021
+ * Converting UserConfig to Config Array without a change in the object beside the JSON convert.
2022
+ */
2023
+ async function getConfigs(config, args) {
2024
+ let userConfigs = await (typeof config === "function" ? Promise.resolve(config(args)) : Promise.resolve(config));
2025
+ if (!Array.isArray(userConfigs)) userConfigs = [userConfigs];
2026
+ const results = [];
2027
+ for (const item of userConfigs) {
2028
+ const plugins = item.plugins ? await getPlugins(item.plugins) : void 0;
2029
+ results.push({
2030
+ ...item,
2031
+ plugins
2032
+ });
2033
+ }
2034
+ return results;
2035
+ }
2036
+ //#endregion
2037
+ //#region src/utils/linters.ts
2038
+ async function isLinterAvailable(linter) {
2039
+ try {
2040
+ await (0, tinyexec.x)(linter, ["--version"], { nodeOptions: { stdio: "ignore" } });
2041
+ return true;
2042
+ } catch {
2043
+ return false;
2044
+ }
2045
+ }
2046
+ async function detectLinter() {
2047
+ for (const linter of [
2048
+ "biome",
2049
+ "oxlint",
2050
+ "eslint"
2051
+ ]) if (await isLinterAvailable(linter)) return linter;
2052
+ }
2053
+ //#endregion
2054
+ exports.FunctionParams = FunctionParams;
447
2055
  exports.PackageManager = PackageManager;
448
- exports.PluginManager = require_packageManager.PluginManager;
449
- exports.PromiseManager = require_packageManager.PromiseManager;
2056
+ exports.PluginManager = PluginManager;
2057
+ exports.PromiseManager = PromiseManager;
450
2058
  exports.build = build;
451
2059
  exports.default = build;
452
2060
  exports.defineConfig = defineConfig;
453
2061
  exports.defineLogger = defineLogger;
454
2062
  exports.definePlugin = definePlugin;
455
- exports.detectPackageManager = require_packageManager.detectPackageManager;
456
- exports.getBarrelFiles = require_packageManager.getBarrelFiles;
457
- exports.getMode = require_packageManager.getMode;
2063
+ exports.detectFormatter = detectFormatter;
2064
+ exports.detectLinter = detectLinter;
2065
+ exports.formatters = formatters;
2066
+ exports.getBarrelFiles = getBarrelFiles;
2067
+ exports.getConfigs = getConfigs;
2068
+ exports.getMode = getMode;
458
2069
  exports.isInputPath = isInputPath;
2070
+ exports.linters = linters;
2071
+ exports.logLevel = logLevel;
459
2072
  exports.safeBuild = safeBuild;
460
2073
  exports.setup = setup;
461
2074