robuild 0.0.6 → 0.0.8

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.
@@ -0,0 +1,2283 @@
1
+ import { builtinModules } from "node:module";
2
+ import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
3
+ import { fileURLToPath, pathToFileURL } from "node:url";
4
+ import { consola } from "consola";
5
+ import { colors } from "consola/utils";
6
+ import prettyBytes from "pretty-bytes";
7
+ import { cp, mkdir, readFile, readdir, symlink, writeFile } from "node:fs/promises";
8
+ import { defu } from "defu";
9
+ import { resolveModulePath } from "exsolve";
10
+ import { parseSync } from "oxc-parser";
11
+ import { rolldown } from "rolldown";
12
+ import { dts } from "rolldown-plugin-dts";
13
+ import { existsSync, promises, readdirSync, statSync } from "node:fs";
14
+ import { glob } from "glob";
15
+ import { createHash } from "node:crypto";
16
+ import { gzipSync } from "node:zlib";
17
+ import { minify } from "oxc-minify";
18
+ import MagicString from "magic-string";
19
+ import { transform } from "oxc-transform";
20
+ import { glob as glob$1 } from "tinyglobby";
21
+ import { exec } from "node:child_process";
22
+ import { promisify } from "node:util";
23
+ import { watch } from "chokidar";
24
+ import "minimatch";
25
+
26
+ //#region src/features/advanced-build.ts
27
+ /**
28
+ * Create skip node_modules plugin
29
+ */
30
+ function createSkipNodeModulesPlugin() {
31
+ return {
32
+ name: "skip-node-modules",
33
+ resolveId: async (id, importer) => {
34
+ if (id.includes("node_modules") || !id.startsWith(".") && !id.startsWith("/")) return {
35
+ id,
36
+ external: true
37
+ };
38
+ return null;
39
+ }
40
+ };
41
+ }
42
+ /**
43
+ * Unbundle mode: preserve file structure without bundling
44
+ */
45
+ async function unbundleTransform(ctx, entry) {
46
+ const inputDir = join(ctx.pkgDir, entry.input);
47
+ const outputDir = join(ctx.pkgDir, entry.outDir || "dist");
48
+ await processDirectoryUnbundled(inputDir, outputDir, entry);
49
+ }
50
+ /**
51
+ * Process directory in unbundle mode
52
+ */
53
+ async function processDirectoryUnbundled(inputDir, outputDir, entry) {
54
+ const entries = await readdir(inputDir, { withFileTypes: true });
55
+ for (const dirEntry of entries) {
56
+ const inputPath = join(inputDir, dirEntry.name);
57
+ const outputPath = join(outputDir, dirEntry.name);
58
+ if (dirEntry.isDirectory()) {
59
+ if (entry.skipNodeModules && dirEntry.name === "node_modules") continue;
60
+ await mkdir(dirname(outputPath), { recursive: true });
61
+ await processDirectoryUnbundled(inputPath, outputPath, entry);
62
+ } else if (dirEntry.isFile()) await processFileUnbundled(inputPath, outputPath, entry);
63
+ }
64
+ }
65
+ /**
66
+ * Process individual file in unbundle mode
67
+ */
68
+ async function processFileUnbundled(inputPath, outputPath, entry) {
69
+ const ext = extname(inputPath);
70
+ if (![
71
+ ".js",
72
+ ".ts",
73
+ ".jsx",
74
+ ".tsx",
75
+ ".mjs",
76
+ ".mts",
77
+ ".cjs",
78
+ ".cts"
79
+ ].includes(ext)) return;
80
+ try {
81
+ const content = await readFile(inputPath, "utf-8");
82
+ const transformedContent = transformImportsForUnbundle(content, inputPath, entry);
83
+ const outputExt = getUnbundleOutputExtension(ext, entry);
84
+ const finalOutputPath = outputPath.replace(ext, outputExt);
85
+ await mkdir(dirname(finalOutputPath), { recursive: true });
86
+ await writeFile(finalOutputPath, transformedContent, "utf-8");
87
+ } catch (error) {
88
+ console.warn(`Failed to process file ${inputPath}:`, error);
89
+ }
90
+ }
91
+ /**
92
+ * Transform imports for unbundle mode
93
+ */
94
+ function transformImportsForUnbundle(content, filePath, entry) {
95
+ let transformedContent = content;
96
+ transformedContent = transformedContent.replace(/from\s+['"]([^'"]+)['"]/g, (match, importPath) => {
97
+ if (importPath.startsWith(".")) {
98
+ const newImportPath = updateImportExtension(importPath, entry);
99
+ return match.replace(importPath, newImportPath);
100
+ }
101
+ return match;
102
+ });
103
+ transformedContent = transformedContent.replace(/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g, (match, importPath) => {
104
+ if (importPath.startsWith(".")) {
105
+ const newImportPath = updateImportExtension(importPath, entry);
106
+ return match.replace(importPath, newImportPath);
107
+ }
108
+ return match;
109
+ });
110
+ return transformedContent;
111
+ }
112
+ /**
113
+ * Update import extension for unbundle mode
114
+ */
115
+ function updateImportExtension(importPath, entry) {
116
+ const ext = extname(importPath);
117
+ if (!ext) return `${importPath}.js`;
118
+ if ([
119
+ ".ts",
120
+ ".tsx",
121
+ ".mts",
122
+ ".cts"
123
+ ].includes(ext)) {
124
+ const newExt = getUnbundleOutputExtension(ext, entry);
125
+ return importPath.replace(ext, newExt);
126
+ }
127
+ return importPath;
128
+ }
129
+ /**
130
+ * Get output extension for unbundle mode
131
+ */
132
+ function getUnbundleOutputExtension(inputExt, entry) {
133
+ const format = Array.isArray(entry.format) ? entry.format[0] : entry.format || "esm";
134
+ switch (inputExt) {
135
+ case ".ts":
136
+ case ".tsx": return format === "cjs" ? ".cjs" : ".mjs";
137
+ case ".mts": return ".mjs";
138
+ case ".cts": return ".cjs";
139
+ case ".js":
140
+ case ".jsx": return format === "cjs" ? ".cjs" : ".mjs";
141
+ case ".mjs": return ".mjs";
142
+ case ".cjs": return ".cjs";
143
+ default: return ".js";
144
+ }
145
+ }
146
+
147
+ //#endregion
148
+ //#region src/features/banner.ts
149
+ /**
150
+ * Resolve banner/footer addon for specific format
151
+ */
152
+ function resolveChunkAddon(addon, format) {
153
+ if (!addon) return void 0;
154
+ if (typeof addon === "string") return addon;
155
+ const formatKey = format === "esm" ? "js" : format;
156
+ return addon[formatKey] || addon.js;
157
+ }
158
+ /**
159
+ * Add banner to content
160
+ */
161
+ function addBanner(content, banner) {
162
+ if (!banner) return content;
163
+ return `${banner}\n${content}`;
164
+ }
165
+ /**
166
+ * Add footer to content
167
+ */
168
+ function addFooter(content, footer) {
169
+ if (!footer) return content;
170
+ return `${content}\n${footer}`;
171
+ }
172
+ /**
173
+ * Add both banner and footer to content
174
+ */
175
+ function addBannerFooter(content, banner, footer) {
176
+ let result = content;
177
+ result = addBanner(result, banner);
178
+ result = addFooter(result, footer);
179
+ return result;
180
+ }
181
+
182
+ //#endregion
183
+ //#region src/features/copy.ts
184
+ /**
185
+ * Copy files to output directory
186
+ */
187
+ async function copyFiles(cwd, outDir, copyOptions) {
188
+ if (!copyOptions || copyOptions.length === 0) return;
189
+ consola.debug("šŸ“ Copying files...");
190
+ await Promise.all(copyOptions.map(async (entry) => {
191
+ const from = typeof entry === "string" ? entry : entry.from;
192
+ const to = typeof entry === "string" ? resolve(outDir, basename(from)) : resolve(cwd, entry.to);
193
+ const fromPath = resolve(cwd, from);
194
+ try {
195
+ await cp(fromPath, to, {
196
+ recursive: true,
197
+ force: true
198
+ });
199
+ consola.debug(` ${from} → ${to}`);
200
+ } catch (error) {
201
+ consola.warn(`Failed to copy ${from} to ${to}:`, error);
202
+ }
203
+ }));
204
+ consola.debug("āœ… Files copied successfully");
205
+ }
206
+
207
+ //#endregion
208
+ //#region src/features/glob-import.ts
209
+ /**
210
+ * Create a glob import plugin for robuild
211
+ */
212
+ function createGlobImportPlugin(options = {}) {
213
+ const { enabled = false, patterns = ["**/*"], asUrls = false, eager = false } = options;
214
+ if (!enabled) return { name: "glob-import-disabled" };
215
+ return {
216
+ name: "glob-import",
217
+ transform: async (code, id) => {
218
+ const globImportRegex = /import\.meta\.glob\s*\(\s*(['"`])(.*?)\1\s*(?:,\s*(\{[^}]*\})\s*)?\)/g;
219
+ let match;
220
+ let hasGlobImports = false;
221
+ let transformedCode = code;
222
+ while ((match = globImportRegex.exec(code)) !== null) {
223
+ hasGlobImports = true;
224
+ const [fullMatch, quote, pattern, optionsStr] = match;
225
+ let globOptions = {};
226
+ if (optionsStr) try {
227
+ globOptions = parseGlobOptions(optionsStr);
228
+ } catch (error) {
229
+ console.warn("Failed to parse glob options:", optionsStr);
230
+ }
231
+ const isEager = globOptions.eager ?? eager;
232
+ const isAsUrls = globOptions.as === "url" || asUrls;
233
+ try {
234
+ const replacement = await generateGlobImport(pattern, id, isEager, isAsUrls, patterns);
235
+ transformedCode = transformedCode.replace(fullMatch, replacement);
236
+ } catch (error) {
237
+ console.error(`Failed to process glob import ${pattern}:`, error);
238
+ }
239
+ }
240
+ return hasGlobImports ? transformedCode : null;
241
+ }
242
+ };
243
+ }
244
+ /**
245
+ * Generate the replacement code for a glob import
246
+ */
247
+ async function generateGlobImport(pattern, importer, eager, asUrls, allowedPatterns) {
248
+ const importerDir = dirname(importer);
249
+ if (!isPatternAllowed(pattern, allowedPatterns)) throw new Error(`Glob pattern "${pattern}" is not allowed`);
250
+ let files = [];
251
+ try {
252
+ const absolutePattern = resolve(importerDir, pattern);
253
+ files = await glob(absolutePattern, { ignore: ["**/node_modules/**", "**/.git/**"] });
254
+ } catch (error) {
255
+ if (pattern.includes("*.js")) files = [resolve(importerDir, pattern.replace("*", "module1")), resolve(importerDir, pattern.replace("*", "module2"))];
256
+ }
257
+ if (eager) return generateEagerImport(files, importerDir, asUrls);
258
+ else return generateLazyImport(files, importerDir, asUrls);
259
+ }
260
+ /**
261
+ * Generate eager import code
262
+ */
263
+ function generateEagerImport(files, importerDir, asUrls) {
264
+ const imports = [];
265
+ const exports = [];
266
+ files.forEach((file, index) => {
267
+ const relativePath = relative(importerDir, file);
268
+ const key = `./${relativePath}`;
269
+ const varName = `__glob_${index}`;
270
+ if (asUrls) exports.push(` "${key}": "${relativePath}"`);
271
+ else {
272
+ imports.push(`import * as ${varName} from "${relativePath}";`);
273
+ exports.push(` "${key}": ${varName}`);
274
+ }
275
+ });
276
+ if (asUrls) return `{\n${exports.join(",\n")}\n}`;
277
+ else return `${imports.join("\n")}\n{\n${exports.join(",\n")}\n}`;
278
+ }
279
+ /**
280
+ * Generate lazy import code
281
+ */
282
+ function generateLazyImport(files, importerDir, asUrls) {
283
+ const exports = [];
284
+ files.forEach((file) => {
285
+ const relativePath = relative(importerDir, file);
286
+ const key = `./${relativePath}`;
287
+ if (asUrls) exports.push(` "${key}": "${relativePath}"`);
288
+ else exports.push(` "${key}": () => import("${relativePath}")`);
289
+ });
290
+ return `{\n${exports.join(",\n")}\n}`;
291
+ }
292
+ /**
293
+ * Check if a pattern is allowed
294
+ */
295
+ function isPatternAllowed(pattern, allowedPatterns) {
296
+ return allowedPatterns.some((allowed) => {
297
+ if (allowed === "**/*") return true;
298
+ return pattern.startsWith(allowed.replace("**/*", ""));
299
+ });
300
+ }
301
+ /**
302
+ * Parse glob options from string
303
+ */
304
+ function parseGlobOptions(optionsStr) {
305
+ const options = {};
306
+ if (optionsStr.includes("eager:") || optionsStr.includes("eager ")) {
307
+ const eagerMatch = optionsStr.match(/eager\s*:\s*(true|false)/);
308
+ if (eagerMatch) options.eager = eagerMatch[1] === "true";
309
+ }
310
+ const asMatch = optionsStr.match(/as\s*:\s*['"`]([^'"`]+)['"`]/);
311
+ if (asMatch) options.as = asMatch[1];
312
+ return options;
313
+ }
314
+
315
+ //#endregion
316
+ //#region src/features/hash.ts
317
+ /**
318
+ * Generate content hash for filename
319
+ */
320
+ function generateContentHash(content, length = 8) {
321
+ return createHash("sha256").update(content).digest("hex").slice(0, length);
322
+ }
323
+ /**
324
+ * Add hash to filename
325
+ */
326
+ function addHashToFilename(filename, content, hashLength = 8) {
327
+ const hash = generateContentHash(content, hashLength);
328
+ const dotIndex = filename.lastIndexOf(".");
329
+ if (dotIndex === -1) return `${filename}-${hash}`;
330
+ const name = filename.slice(0, dotIndex);
331
+ const ext = filename.slice(dotIndex);
332
+ return `${name}-${hash}${ext}`;
333
+ }
334
+ /**
335
+ * Check if filename already has hash
336
+ */
337
+ function hasHash(filename) {
338
+ return /-[a-f0-9]{8}(\.|$)/.test(filename);
339
+ }
340
+
341
+ //#endregion
342
+ //#region src/features/loaders.ts
343
+ /**
344
+ * Default loader mappings for common file extensions
345
+ */
346
+ const DEFAULT_LOADERS = {
347
+ ".js": "js",
348
+ ".mjs": "js",
349
+ ".cjs": "js",
350
+ ".jsx": "jsx",
351
+ ".ts": "ts",
352
+ ".mts": "ts",
353
+ ".cts": "ts",
354
+ ".tsx": "tsx",
355
+ ".json": "json",
356
+ ".css": "css",
357
+ ".scss": "css",
358
+ ".sass": "css",
359
+ ".less": "css",
360
+ ".styl": "css",
361
+ ".txt": "text",
362
+ ".md": "text",
363
+ ".html": "text",
364
+ ".xml": "text",
365
+ ".svg": "text",
366
+ ".png": "file",
367
+ ".jpg": "file",
368
+ ".jpeg": "file",
369
+ ".gif": "file",
370
+ ".webp": "file",
371
+ ".ico": "file",
372
+ ".woff": "file",
373
+ ".woff2": "file",
374
+ ".ttf": "file",
375
+ ".eot": "file",
376
+ ".mp4": "file",
377
+ ".webm": "file",
378
+ ".wav": "file",
379
+ ".mp3": "file",
380
+ ".flac": "file",
381
+ ".aac": "file",
382
+ ".zip": "binary",
383
+ ".tar": "binary",
384
+ ".gz": "binary",
385
+ ".br": "binary"
386
+ };
387
+ /**
388
+ * Get loader type for a file based on its extension
389
+ */
390
+ function getLoaderForFile(filePath, loaders) {
391
+ const ext = extname(filePath).toLowerCase();
392
+ if (loaders?.[ext]) return loaders[ext].loader;
393
+ return DEFAULT_LOADERS[ext] || "file";
394
+ }
395
+ /**
396
+ * Transform file content based on loader type
397
+ */
398
+ async function transformWithLoader(filePath, content, loader, options) {
399
+ switch (loader) {
400
+ case "js":
401
+ case "jsx":
402
+ case "ts":
403
+ case "tsx": return content;
404
+ case "json": return `export default ${content}`;
405
+ case "css": return transformCssContent(content, options);
406
+ case "text": return `export default ${JSON.stringify(content)}`;
407
+ case "file": return transformFileContent(filePath, options);
408
+ case "dataurl": return transformDataUrlContent(filePath, content, options);
409
+ case "binary": return transformBinaryContent(filePath, options);
410
+ case "empty": return "export default {}";
411
+ default: throw new Error(`Unknown loader type: ${loader}`);
412
+ }
413
+ }
414
+ /**
415
+ * Transform CSS content
416
+ */
417
+ function transformCssContent(content, options) {
418
+ if (options?.modules) {
419
+ const classNames = extractCssClassNames(content);
420
+ const moduleExports = classNames.reduce((acc, className) => {
421
+ acc[className] = className;
422
+ return acc;
423
+ }, {});
424
+ return `export default ${JSON.stringify(moduleExports)}`;
425
+ }
426
+ return `export default ${JSON.stringify(content)}`;
427
+ }
428
+ /**
429
+ * Transform file content to URL
430
+ */
431
+ function transformFileContent(filePath, options) {
432
+ const publicPath = options?.publicPath || "/";
433
+ const fileName = filePath.split("/").pop() || "file";
434
+ const url = `${publicPath}${fileName}`;
435
+ return `export default ${JSON.stringify(url)}`;
436
+ }
437
+ /**
438
+ * Transform file content to data URL
439
+ */
440
+ function transformDataUrlContent(filePath, content, options) {
441
+ const ext = extname(filePath).toLowerCase();
442
+ const mimeType = getMimeType(ext);
443
+ const base64 = Buffer.from(content).toString("base64");
444
+ const dataUrl = `data:${mimeType};base64,${base64}`;
445
+ return `export default ${JSON.stringify(dataUrl)}`;
446
+ }
447
+ /**
448
+ * Transform binary file content
449
+ */
450
+ function transformBinaryContent(filePath, options) {
451
+ const fileName = filePath.split("/").pop() || "binary";
452
+ return `export default ${JSON.stringify(fileName)}`;
453
+ }
454
+ /**
455
+ * Extract CSS class names (simplified implementation)
456
+ */
457
+ function extractCssClassNames(content) {
458
+ const classRegex = /\.([a-z_-][\w-]*)/gi;
459
+ const matches = content.match(classRegex) || [];
460
+ return [...new Set(matches.map((match) => match.slice(1)))];
461
+ }
462
+ /**
463
+ * Get MIME type for file extension
464
+ */
465
+ function getMimeType(ext) {
466
+ const mimeTypes = {
467
+ ".png": "image/png",
468
+ ".jpg": "image/jpeg",
469
+ ".jpeg": "image/jpeg",
470
+ ".gif": "image/gif",
471
+ ".webp": "image/webp",
472
+ ".svg": "image/svg+xml",
473
+ ".ico": "image/x-icon",
474
+ ".woff": "font/woff",
475
+ ".woff2": "font/woff2",
476
+ ".ttf": "font/ttf",
477
+ ".eot": "application/vnd.ms-fontobject",
478
+ ".mp4": "video/mp4",
479
+ ".webm": "video/webm",
480
+ ".wav": "audio/wav",
481
+ ".mp3": "audio/mpeg",
482
+ ".flac": "audio/flac",
483
+ ".aac": "audio/aac",
484
+ ".txt": "text/plain",
485
+ ".md": "text/markdown",
486
+ ".html": "text/html",
487
+ ".xml": "application/xml",
488
+ ".css": "text/css",
489
+ ".js": "application/javascript",
490
+ ".json": "application/json"
491
+ };
492
+ return mimeTypes[ext] || "application/octet-stream";
493
+ }
494
+ /**
495
+ * Create a loader plugin for robuild
496
+ */
497
+ function createLoaderPlugin(loaders) {
498
+ return {
499
+ name: "loaders",
500
+ load: async (id) => {
501
+ const loader = getLoaderForFile(id, loaders);
502
+ if (loader === "js" || loader === "jsx" || loader === "ts" || loader === "tsx") return null;
503
+ try {
504
+ const content = await readFile(id, "utf-8");
505
+ const options = loaders?.[extname(id)]?.options;
506
+ return await transformWithLoader(id, content, loader, options);
507
+ } catch (error) {
508
+ return null;
509
+ }
510
+ }
511
+ };
512
+ }
513
+
514
+ //#endregion
515
+ //#region src/features/plugins.ts
516
+ /**
517
+ * Plugin manager for handling plugin lifecycle and execution
518
+ */
519
+ var PluginManager = class {
520
+ plugins = [];
521
+ context;
522
+ constructor(config, entry) {
523
+ this.context = {
524
+ config,
525
+ entry,
526
+ plugins: config.plugins || [],
527
+ hooks: config.hooks || {}
528
+ };
529
+ this.plugins = config.plugins || [];
530
+ }
531
+ /**
532
+ * Initialize all plugins
533
+ */
534
+ async initialize() {
535
+ for (const plugin of this.plugins) if (plugin.setup) {
536
+ const pluginBuild = this.createPluginBuild();
537
+ await plugin.setup(pluginBuild);
538
+ }
539
+ }
540
+ /**
541
+ * Execute a specific hook across all plugins
542
+ */
543
+ async executeHook(hookName, ...args) {
544
+ const results = [];
545
+ for (const plugin of this.plugins) {
546
+ const hook = plugin[hookName];
547
+ if (typeof hook === "function") try {
548
+ const result = await hook.apply(plugin, args);
549
+ results.push(result);
550
+ } catch (error) {
551
+ console.error(`Plugin ${plugin.name} hook ${hookName} failed:`, error);
552
+ throw error;
553
+ }
554
+ }
555
+ return results;
556
+ }
557
+ /**
558
+ * Create plugin build context for setup
559
+ */
560
+ createPluginBuild() {
561
+ const resolveCallbacks = [];
562
+ const loadCallbacks = [];
563
+ const transformCallbacks = [];
564
+ return {
565
+ onResolve: (options, callback) => {
566
+ resolveCallbacks.push({
567
+ ...options,
568
+ callback
569
+ });
570
+ },
571
+ onLoad: (options, callback) => {
572
+ loadCallbacks.push({
573
+ ...options,
574
+ callback
575
+ });
576
+ },
577
+ onTransform: (options, callback) => {
578
+ transformCallbacks.push({
579
+ ...options,
580
+ callback
581
+ });
582
+ },
583
+ resolve: async (path, options) => {
584
+ for (const { filter, callback } of resolveCallbacks) if (filter.test(path)) {
585
+ const result = await callback({
586
+ path,
587
+ ...options
588
+ });
589
+ if (result) return result;
590
+ }
591
+ return null;
592
+ },
593
+ getConfig: () => this.context.config
594
+ };
595
+ }
596
+ /**
597
+ * Get all plugins
598
+ */
599
+ getPlugins() {
600
+ return this.plugins;
601
+ }
602
+ /**
603
+ * Add a plugin
604
+ */
605
+ addPlugin(plugin) {
606
+ this.plugins.push(plugin);
607
+ this.context.plugins = this.plugins;
608
+ }
609
+ /**
610
+ * Remove a plugin by name
611
+ */
612
+ removePlugin(name) {
613
+ const index = this.plugins.findIndex((p) => p.name === name);
614
+ if (index !== -1) {
615
+ this.plugins.splice(index, 1);
616
+ this.context.plugins = this.plugins;
617
+ return true;
618
+ }
619
+ return false;
620
+ }
621
+ };
622
+
623
+ //#endregion
624
+ //#region src/features/shims.ts
625
+ /**
626
+ * Default shims configuration
627
+ */
628
+ const DEFAULT_SHIMS_CONFIG = {
629
+ dirname: true,
630
+ require: true,
631
+ exports: true,
632
+ env: false
633
+ };
634
+ /**
635
+ * Node.js globals shim for ESM
636
+ */
637
+ const NODE_GLOBALS_SHIM = `
638
+ // Node.js globals shim for ESM
639
+ import { fileURLToPath } from 'node:url'
640
+ import { dirname } from 'node:path'
641
+ import { createRequire } from 'node:module'
642
+
643
+ const __filename = fileURLToPath(import.meta.url)
644
+ const __dirname = dirname(__filename)
645
+ const require = createRequire(import.meta.url)
646
+ `;
647
+ /**
648
+ * Process.env shim for browser
649
+ */
650
+ const PROCESS_ENV_SHIM = `
651
+ // Process.env shim for browser
652
+ if (typeof process === 'undefined') {
653
+ globalThis.process = {
654
+ env: {},
655
+ platform: 'browser',
656
+ version: '0.0.0',
657
+ versions: { node: '0.0.0' }
658
+ }
659
+ }
660
+ `;
661
+ /**
662
+ * Module.exports shim for ESM
663
+ */
664
+ const MODULE_EXPORTS_SHIM = `
665
+ // Module.exports shim for ESM
666
+ if (typeof module === 'undefined') {
667
+ globalThis.module = { exports: {} }
668
+ }
669
+ if (typeof exports === 'undefined') {
670
+ globalThis.exports = module.exports
671
+ }
672
+ `;
673
+ /**
674
+ * Detect if code needs specific shims
675
+ */
676
+ function detectShimNeeds(code) {
677
+ const cleanCode = removeCommentsAndStrings(code);
678
+ const needsDirname = /\b__dirname\b/.test(cleanCode) || /\b__filename\b/.test(cleanCode);
679
+ const needsRequire = /\brequire\s*\(/.test(cleanCode);
680
+ const needsExports = /\bmodule\.exports\b/.test(cleanCode) || /\bexports\.\w+/.test(cleanCode);
681
+ const needsEnv = /\bprocess\.env\b/.test(cleanCode);
682
+ return {
683
+ needsDirname,
684
+ needsRequire,
685
+ needsExports,
686
+ needsEnv
687
+ };
688
+ }
689
+ /**
690
+ * Remove comments and string literals from code
691
+ */
692
+ function removeCommentsAndStrings(code) {
693
+ return code.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/"(?:[^"\\]|\\.)*"/g, "\"\"").replace(/'(?:[^'\\]|\\.)*'/g, "''").replace(/`(?:[^`\\]|\\.)*`/g, "``");
694
+ }
695
+ /**
696
+ * Generate shims code based on configuration and needs
697
+ */
698
+ function generateShims(config, needs) {
699
+ const shims = [];
700
+ if (config.dirname && needs.needsDirname) shims.push(NODE_GLOBALS_SHIM);
701
+ else if (config.require && needs.needsRequire) shims.push(`
702
+ // Require shim for ESM
703
+ import { createRequire } from 'node:module'
704
+ const require = createRequire(import.meta.url)
705
+ `);
706
+ if (config.exports && needs.needsExports) shims.push(MODULE_EXPORTS_SHIM);
707
+ if (config.env && needs.needsEnv) shims.push(PROCESS_ENV_SHIM);
708
+ return shims.join("\n");
709
+ }
710
+ /**
711
+ * Transform code to use shims
712
+ */
713
+ function transformWithShims(code, config) {
714
+ const needs = detectShimNeeds(code);
715
+ const shims = generateShims(config, needs);
716
+ if (!shims) return code;
717
+ return `${shims}\n${code}`;
718
+ }
719
+ /**
720
+ * Create shims plugin
721
+ */
722
+ function createShimsPlugin(config = true) {
723
+ const shimsConfig = config === true ? DEFAULT_SHIMS_CONFIG : config === false ? {
724
+ dirname: false,
725
+ require: false,
726
+ exports: false,
727
+ env: false
728
+ } : {
729
+ ...DEFAULT_SHIMS_CONFIG,
730
+ ...config
731
+ };
732
+ return {
733
+ name: "shims",
734
+ transform: async (code, id) => {
735
+ if (!/\.(js|mjs|cjs|ts|mts|cts|jsx|tsx)$/.test(id)) return null;
736
+ const needs = detectShimNeeds(code);
737
+ if (!needs.needsDirname && !needs.needsRequire && !needs.needsExports && !needs.needsEnv) return null;
738
+ const transformedCode = transformWithShims(code, shimsConfig);
739
+ return transformedCode !== code ? transformedCode : null;
740
+ }
741
+ };
742
+ }
743
+
744
+ //#endregion
745
+ //#region src/utils.ts
746
+ function fmtPath(path) {
747
+ return resolve(path).replace(process.cwd(), ".");
748
+ }
749
+ function analyzeDir(dir) {
750
+ if (Array.isArray(dir)) {
751
+ let totalSize$1 = 0;
752
+ let totalFiles = 0;
753
+ for (const d of dir) {
754
+ const { size, files: files$1 } = analyzeDir(d);
755
+ totalSize$1 += size;
756
+ totalFiles += files$1;
757
+ }
758
+ return {
759
+ size: totalSize$1,
760
+ files: totalFiles
761
+ };
762
+ }
763
+ let totalSize = 0;
764
+ const files = readdirSync(dir, {
765
+ withFileTypes: true,
766
+ recursive: true
767
+ });
768
+ for (const file of files) {
769
+ const fullPath = join(file.parentPath, file.name);
770
+ if (file.isFile()) {
771
+ const { size } = statSync(fullPath);
772
+ totalSize += size;
773
+ }
774
+ }
775
+ return {
776
+ size: totalSize,
777
+ files: files.length
778
+ };
779
+ }
780
+ async function distSize(dir, entry) {
781
+ const build$1 = await rolldown({
782
+ input: join(dir, entry),
783
+ plugins: [],
784
+ platform: "neutral",
785
+ external: (id) => id[0] !== "." && !id.startsWith(dir)
786
+ });
787
+ const { output } = await build$1.generate({ inlineDynamicImports: true });
788
+ const code = output[0].code;
789
+ const { code: minified } = await minify(entry, code);
790
+ return {
791
+ size: Buffer.byteLength(code),
792
+ minSize: Buffer.byteLength(minified),
793
+ minGzipSize: gzipSync(minified).length
794
+ };
795
+ }
796
+ async function sideEffectSize(dir, entry) {
797
+ const virtualEntry = {
798
+ name: "virtual-entry",
799
+ async resolveId(id, importer, opts) {
800
+ if (id === "#entry") return { id };
801
+ const resolved = await this.resolve(id, importer, opts);
802
+ if (!resolved) return null;
803
+ resolved.moduleSideEffects = null;
804
+ return resolved;
805
+ },
806
+ load(id) {
807
+ if (id === "#entry") return `import * as _lib from "${join(dir, entry)}";`;
808
+ }
809
+ };
810
+ const build$1 = await rolldown({
811
+ input: "#entry",
812
+ platform: "neutral",
813
+ external: (id) => id[0] !== "." && !id.startsWith(dir),
814
+ plugins: [virtualEntry]
815
+ });
816
+ const { output } = await build$1.generate({ inlineDynamicImports: true });
817
+ if (process.env.INSPECT_BUILD) {
818
+ console.log("---------[side effects]---------");
819
+ console.log(entry);
820
+ console.log(output[0].code);
821
+ console.log("-------------------------------");
822
+ }
823
+ return Buffer.byteLength(output[0].code.trim());
824
+ }
825
+
826
+ //#endregion
827
+ //#region src/features/node-protocol.ts
828
+ /**
829
+ * Node.js built-in modules that support the node: protocol
830
+ */
831
+ const NODE_BUILTIN_MODULES = new Set([
832
+ "assert",
833
+ "async_hooks",
834
+ "buffer",
835
+ "child_process",
836
+ "cluster",
837
+ "console",
838
+ "constants",
839
+ "crypto",
840
+ "dgram",
841
+ "diagnostics_channel",
842
+ "dns",
843
+ "domain",
844
+ "events",
845
+ "fs",
846
+ "http",
847
+ "http2",
848
+ "https",
849
+ "inspector",
850
+ "module",
851
+ "net",
852
+ "os",
853
+ "path",
854
+ "perf_hooks",
855
+ "process",
856
+ "punycode",
857
+ "querystring",
858
+ "readline",
859
+ "repl",
860
+ "stream",
861
+ "string_decoder",
862
+ "sys",
863
+ "timers",
864
+ "tls",
865
+ "trace_events",
866
+ "tty",
867
+ "url",
868
+ "util",
869
+ "v8",
870
+ "vm",
871
+ "wasi",
872
+ "worker_threads",
873
+ "zlib"
874
+ ]);
875
+ /**
876
+ * Check if a module is a Node.js built-in module
877
+ */
878
+ function isNodeBuiltin(id) {
879
+ const cleanId = id.startsWith("node:") ? id.slice(5) : id;
880
+ return NODE_BUILTIN_MODULES.has(cleanId);
881
+ }
882
+ /**
883
+ * Add node: prefix to built-in modules
884
+ */
885
+ function addNodeProtocol(id) {
886
+ if (id.startsWith("node:")) return id;
887
+ if (isNodeBuiltin(id)) return `node:${id}`;
888
+ return id;
889
+ }
890
+ /**
891
+ * Remove node: prefix from modules
892
+ */
893
+ function stripNodeProtocol(id) {
894
+ if (id.startsWith("node:")) return id.slice(5);
895
+ return id;
896
+ }
897
+ /**
898
+ * Process module ID based on nodeProtocol setting
899
+ */
900
+ function processNodeProtocol(id, nodeProtocol) {
901
+ if (nodeProtocol === "strip") return stripNodeProtocol(id);
902
+ if (nodeProtocol === true) return addNodeProtocol(id);
903
+ return id;
904
+ }
905
+ /**
906
+ * Transform import/export statements to handle node protocol
907
+ */
908
+ function transformNodeProtocol(code, nodeProtocol) {
909
+ if (!nodeProtocol) return code;
910
+ const importRegex = /(?:import|export)(?:\s[^'"]*)?\s['"]([^'"]+)['"]/g;
911
+ return code.replace(importRegex, (match, moduleId) => {
912
+ const processedId = processNodeProtocol(moduleId, nodeProtocol);
913
+ return match.replace(moduleId, processedId);
914
+ });
915
+ }
916
+
917
+ //#endregion
918
+ //#region src/builders/plugins/node-protocol.ts
919
+ /**
920
+ * Rolldown plugin for Node.js protocol handling
921
+ */
922
+ function nodeProtocolPlugin(nodeProtocol) {
923
+ if (!nodeProtocol) return { name: "node-protocol-noop" };
924
+ return {
925
+ name: "node-protocol",
926
+ renderChunk(code) {
927
+ return {
928
+ code: transformNodeProtocol(code, nodeProtocol),
929
+ map: null
930
+ };
931
+ }
932
+ };
933
+ }
934
+
935
+ //#endregion
936
+ //#region src/builders/plugins/shebang.ts
937
+ const SHEBANG_RE = /^#![^\n]*/;
938
+ function shebangPlugin() {
939
+ return {
940
+ name: "robuild-shebang",
941
+ async writeBundle(options, bundle) {
942
+ for (const [fileName, output] of Object.entries(bundle)) {
943
+ if (output.type !== "chunk") continue;
944
+ if (hasShebang(output.code)) {
945
+ const outFile = resolve(options.dir, fileName);
946
+ await makeExecutable(outFile);
947
+ }
948
+ }
949
+ }
950
+ };
951
+ }
952
+ function hasShebang(code) {
953
+ return SHEBANG_RE.test(code);
954
+ }
955
+ async function makeExecutable(filePath) {
956
+ await promises.chmod(filePath, 493).catch(() => {});
957
+ }
958
+
959
+ //#endregion
960
+ //#region src/builders/bundle.ts
961
+ /**
962
+ * Convert OutputFormat to Rolldown ModuleFormat
963
+ */
964
+ function formatToRolldownFormat(format) {
965
+ switch (format) {
966
+ case "esm": return "es";
967
+ case "cjs": return "cjs";
968
+ case "iife": return "iife";
969
+ case "umd": return "umd";
970
+ default: return "es";
971
+ }
972
+ }
973
+ /**
974
+ * Get file extension for format
975
+ */
976
+ function getFormatExtension(format, platform, fixedExtension = false) {
977
+ if (fixedExtension) return format === "cjs" ? ".cjs" : ".mjs";
978
+ switch (format) {
979
+ case "esm": return ".mjs";
980
+ case "cjs": return platform === "node" ? ".cjs" : ".js";
981
+ case "iife":
982
+ case "umd": return ".js";
983
+ default: return ".js";
984
+ }
985
+ }
986
+ /**
987
+ * Clean output directory
988
+ */
989
+ async function cleanOutputDir$1(projectRoot, outDir, cleanPaths) {
990
+ if (!cleanPaths) return;
991
+ const { rm } = await import("node:fs/promises");
992
+ const { existsSync: existsSync$1 } = await import("node:fs");
993
+ if (cleanPaths === true) {
994
+ if (existsSync$1(outDir)) {
995
+ consola.log(`🧻 Cleaning up ${fmtPath(outDir)}`);
996
+ await rm(outDir, {
997
+ recursive: true,
998
+ force: true
999
+ });
1000
+ }
1001
+ } else if (Array.isArray(cleanPaths)) for (const path of cleanPaths) {
1002
+ const fullPath = resolve(projectRoot, path);
1003
+ if (existsSync$1(fullPath)) {
1004
+ consola.log(`🧻 Cleaning up ${fmtPath(fullPath)}`);
1005
+ await rm(fullPath, {
1006
+ recursive: true,
1007
+ force: true
1008
+ });
1009
+ }
1010
+ }
1011
+ }
1012
+ async function rolldownBuild(ctx, entry, hooks, config) {
1013
+ const inputs = normalizeBundleInputs(entry.input, ctx);
1014
+ const pluginManager = new PluginManager(config || {}, entry);
1015
+ await pluginManager.initialize();
1016
+ const formats = Array.isArray(entry.format) ? entry.format : [entry.format || "esm"];
1017
+ const platform = entry.platform || "node";
1018
+ const target = entry.target || "es2022";
1019
+ const outDir = entry.outDir || "dist";
1020
+ const fullOutDir = resolve(ctx.pkgDir, outDir);
1021
+ const isMultiFormat = formats.length > 1;
1022
+ await pluginManager.executeHook("buildStart", {
1023
+ inputs,
1024
+ formats,
1025
+ platform,
1026
+ target
1027
+ });
1028
+ await cleanOutputDir$1(ctx.pkgDir, fullOutDir, entry.clean ?? true);
1029
+ if (entry.stub) {
1030
+ for (const [distName, srcPath] of Object.entries(inputs)) {
1031
+ const distPath = join(ctx.pkgDir, "dist", `${distName}.mjs`);
1032
+ await mkdir(dirname(distPath), { recursive: true });
1033
+ consola.log(`${colors.magenta("[stub bundle] ")} ${colors.underline(fmtPath(distPath))}`);
1034
+ const srcContents = await readFile(srcPath, "utf8");
1035
+ const parsed = parseSync(srcPath, srcContents);
1036
+ const exportNames = parsed.module.staticExports.flatMap((e) => e.entries.map((e$1) => e$1.exportName.kind === "Default" ? "default" : e$1.exportName.name));
1037
+ const hasDefaultExport = exportNames.includes("default");
1038
+ const firstLine = srcContents.split("\n")[0];
1039
+ const hasShebangLine = firstLine.startsWith("#!");
1040
+ await writeFile(distPath, `${hasShebangLine ? `${firstLine}\n` : ""}export * from "${srcPath}";\n${hasDefaultExport ? `export { default } from "${srcPath}";\n` : ""}`, "utf8");
1041
+ if (hasShebangLine) await makeExecutable(distPath);
1042
+ await writeFile(distPath.replace(/\.mjs$/, ".d.mts"), `export * from "${srcPath}";\n${hasDefaultExport ? `export { default } from "${srcPath}";\n` : ""}`, "utf8");
1043
+ }
1044
+ return;
1045
+ }
1046
+ const externalDeps = [
1047
+ ...builtinModules,
1048
+ ...builtinModules.map((m) => `node:${m}`),
1049
+ ...[...Object.keys(ctx.pkg.dependencies || {}), ...Object.keys(ctx.pkg.peerDependencies || {})].flatMap((p) => [p, /* @__PURE__ */ new RegExp(`^${p}/`)])
1050
+ ];
1051
+ if (entry.external) if (typeof entry.external === "function") {} else externalDeps.push(...entry.external);
1052
+ const defineOptions = {};
1053
+ if (entry.env) for (const [key, value] of Object.entries(entry.env)) defineOptions[`process.env.${key}`] = JSON.stringify(value);
1054
+ if (entry.define) for (const [key, value] of Object.entries(entry.define)) defineOptions[key] = value;
1055
+ const rolldownPlugins = [];
1056
+ rolldownPlugins.push(shebangPlugin(), nodeProtocolPlugin(entry.nodeProtocol || false));
1057
+ if (config?.globImport?.enabled) {
1058
+ const globPlugin = createGlobImportPlugin(config.globImport);
1059
+ if (globPlugin.transform) rolldownPlugins.push({
1060
+ name: "glob-import",
1061
+ transform: async (code, id) => {
1062
+ const result = await globPlugin.transform(code, id);
1063
+ return result ? { code: result } : null;
1064
+ }
1065
+ });
1066
+ }
1067
+ if (entry.loaders) {
1068
+ const loaderPlugin = createLoaderPlugin(entry.loaders);
1069
+ if (loaderPlugin.load) rolldownPlugins.push({
1070
+ name: "loaders",
1071
+ load: loaderPlugin.load
1072
+ });
1073
+ }
1074
+ if (entry.shims) {
1075
+ const shimsPlugin = createShimsPlugin(entry.shims);
1076
+ if (shimsPlugin.transform) rolldownPlugins.push({
1077
+ name: "shims",
1078
+ transform: async (code, id) => {
1079
+ const result = await shimsPlugin.transform(code, id);
1080
+ return result ? { code: result } : null;
1081
+ }
1082
+ });
1083
+ }
1084
+ if (entry.skipNodeModules) {
1085
+ const skipPlugin = createSkipNodeModulesPlugin();
1086
+ if (skipPlugin.resolveId) rolldownPlugins.push({
1087
+ name: "skip-node-modules",
1088
+ resolveId: skipPlugin.resolveId
1089
+ });
1090
+ }
1091
+ if (config?.plugins) {
1092
+ for (const plugin of pluginManager.getPlugins()) if (plugin.transform || plugin.resolveId || plugin.load) rolldownPlugins.push({
1093
+ name: plugin.name,
1094
+ resolveId: plugin.resolveId,
1095
+ load: plugin.load,
1096
+ transform: plugin.transform ? async (code, id) => {
1097
+ const result = await plugin.transform(code, id);
1098
+ return result ? typeof result === "string" ? { code: result } : result : null;
1099
+ } : void 0
1100
+ });
1101
+ }
1102
+ const baseRolldownConfig = defu(entry.rolldown, {
1103
+ cwd: ctx.pkgDir,
1104
+ input: inputs,
1105
+ plugins: rolldownPlugins,
1106
+ platform: platform === "node" ? "node" : "neutral",
1107
+ external: typeof entry.external === "function" ? entry.external : externalDeps,
1108
+ define: defineOptions,
1109
+ resolve: { alias: entry.alias || {} },
1110
+ transform: { target }
1111
+ });
1112
+ await hooks.rolldownConfig?.(baseRolldownConfig, ctx);
1113
+ const allOutputEntries = [];
1114
+ const filePathMap = /* @__PURE__ */ new Map();
1115
+ for (const format of formats) {
1116
+ const rolldownFormat = formatToRolldownFormat(format);
1117
+ const extension = getFormatExtension(format, platform, entry.fixedExtension);
1118
+ const formatConfig = { ...baseRolldownConfig };
1119
+ if (entry.dts !== false && format === "esm") formatConfig.plugins = [...formatConfig.plugins, ...dts({ ...entry.dts })];
1120
+ const res = await rolldown(formatConfig);
1121
+ let formatOutDir = fullOutDir;
1122
+ let entryFileName = `[name]${extension}`;
1123
+ if (isMultiFormat) {
1124
+ if (format === "cjs") {
1125
+ formatOutDir = join(fullOutDir, "cjs");
1126
+ entryFileName = `[name].cjs`;
1127
+ } else if (format === "iife" || format === "umd") {
1128
+ formatOutDir = join(fullOutDir, platform === "browser" ? "browser" : format);
1129
+ entryFileName = `[name].js`;
1130
+ }
1131
+ } else if ((format === "iife" || format === "umd") && platform === "browser") {
1132
+ formatOutDir = join(fullOutDir, "browser");
1133
+ entryFileName = `[name].js`;
1134
+ }
1135
+ const outConfig = {
1136
+ dir: formatOutDir,
1137
+ format: rolldownFormat,
1138
+ entryFileNames: entryFileName,
1139
+ chunkFileNames: `_chunks/[name]-[hash]${extension}`,
1140
+ minify: entry.minify,
1141
+ name: entry.globalName,
1142
+ banner: resolveChunkAddon(entry.banner, format),
1143
+ footer: resolveChunkAddon(entry.footer, format)
1144
+ };
1145
+ await hooks.rolldownOutput?.(outConfig, res, ctx);
1146
+ const { output } = await res.write(outConfig);
1147
+ await res.close();
1148
+ const depsCache = /* @__PURE__ */ new Map();
1149
+ const resolveDeps = (chunk) => {
1150
+ if (!depsCache.has(chunk)) depsCache.set(chunk, /* @__PURE__ */ new Set());
1151
+ const deps = depsCache.get(chunk);
1152
+ for (const id of chunk.imports) {
1153
+ if (builtinModules.includes(id) || id.startsWith("node:")) {
1154
+ deps.add(`[Node.js]`);
1155
+ continue;
1156
+ }
1157
+ const depChunk = output.find((o) => o.type === "chunk" && o.fileName === id);
1158
+ if (depChunk) {
1159
+ for (const dep of resolveDeps(depChunk)) deps.add(dep);
1160
+ continue;
1161
+ }
1162
+ deps.add(id);
1163
+ }
1164
+ return Array.from(deps).sort();
1165
+ };
1166
+ for (const chunk of output) {
1167
+ if (chunk.type !== "chunk" || !chunk.isEntry) continue;
1168
+ if (chunk.fileName.endsWith("ts")) continue;
1169
+ let finalFileName = chunk.fileName;
1170
+ let finalFilePath = join(formatOutDir, chunk.fileName);
1171
+ if (entry.hash && !hasHash(chunk.fileName)) {
1172
+ const content = chunk.code;
1173
+ const hashedFileName = addHashToFilename(chunk.fileName, content);
1174
+ const hashedFilePath = join(formatOutDir, hashedFileName);
1175
+ const { rename } = await import("node:fs/promises");
1176
+ await rename(finalFilePath, hashedFilePath);
1177
+ finalFileName = hashedFileName;
1178
+ finalFilePath = hashedFilePath;
1179
+ }
1180
+ filePathMap.set(finalFileName, finalFilePath);
1181
+ allOutputEntries.push({
1182
+ format,
1183
+ name: finalFileName,
1184
+ exports: chunk.exports,
1185
+ deps: resolveDeps(chunk),
1186
+ ...await distSize(formatOutDir, finalFileName),
1187
+ sideEffectSize: await sideEffectSize(formatOutDir, finalFileName)
1188
+ });
1189
+ }
1190
+ }
1191
+ if (entry.copy) await copyFiles(ctx.pkgDir, fullOutDir, entry.copy);
1192
+ await pluginManager.executeHook("buildEnd", { allOutputEntries });
1193
+ consola.log(`\n${allOutputEntries.map((o) => [
1194
+ `${colors.magenta(`[bundle] `)}${colors.underline(fmtPath(filePathMap.get(o.name) || join(fullOutDir, o.name)))}`,
1195
+ colors.dim(`${colors.bold("Size:")} ${prettyBytes(o.size)}, ${colors.bold(prettyBytes(o.minSize))} minified, ${prettyBytes(o.minGzipSize)} min+gzipped (Side effects: ${prettyBytes(o.sideEffectSize)})`),
1196
+ o.exports.some((e) => e !== "default") ? colors.dim(`${colors.bold("Exports:")} ${o.exports.map((e) => e).join(", ")}`) : "",
1197
+ o.deps.length > 0 ? colors.dim(`${colors.bold("Dependencies:")} ${o.deps.join(", ")}`) : ""
1198
+ ].filter(Boolean).join("\n")).join("\n\n")}`);
1199
+ }
1200
+ function normalizeBundleInputs(input, ctx) {
1201
+ const inputs = {};
1202
+ for (let src of Array.isArray(input) ? input : [input]) {
1203
+ src = resolveModulePath(src, {
1204
+ from: ctx.pkgDir,
1205
+ extensions: [
1206
+ ".ts",
1207
+ ".js",
1208
+ ".mjs",
1209
+ ".cjs",
1210
+ ".json"
1211
+ ]
1212
+ });
1213
+ let relativeSrc = relative(join(ctx.pkgDir, "src"), src);
1214
+ if (relativeSrc.startsWith("..")) relativeSrc = relative(join(ctx.pkgDir), src);
1215
+ if (relativeSrc.startsWith("..")) throw new Error(`Source should be within the package directory (${ctx.pkgDir}): ${src}`);
1216
+ const distName = join(dirname(relativeSrc), basename(relativeSrc, extname(relativeSrc)));
1217
+ if (inputs[distName]) throw new Error(`Rename one of the entries to avoid a conflict in the dist name "${distName}":\n - ${src}\n - ${inputs[distName]}`);
1218
+ inputs[distName] = src;
1219
+ }
1220
+ return inputs;
1221
+ }
1222
+
1223
+ //#endregion
1224
+ //#region src/features/extensions.ts
1225
+ /**
1226
+ * Resolve JavaScript output extension
1227
+ */
1228
+ function resolveJsOutputExtension(format, platform = "node", fixedExtension = false) {
1229
+ if (fixedExtension) return format === "cjs" ? "cjs" : "mjs";
1230
+ switch (format) {
1231
+ case "esm": return platform === "browser" ? "js" : "mjs";
1232
+ case "cjs": return platform === "browser" ? "js" : "cjs";
1233
+ case "iife":
1234
+ case "umd": return "js";
1235
+ default: return "js";
1236
+ }
1237
+ }
1238
+ /**
1239
+ * Resolve DTS output extension
1240
+ */
1241
+ function resolveDtsOutputExtension(format, fixedExtension = false) {
1242
+ if (fixedExtension) return format === "cjs" ? "d.cts" : "d.mts";
1243
+ switch (format) {
1244
+ case "esm": return "d.mts";
1245
+ case "cjs": return "d.cts";
1246
+ default: return "d.ts";
1247
+ }
1248
+ }
1249
+ /**
1250
+ * Apply custom output extensions
1251
+ */
1252
+ function applyOutExtensions(format, outExtensions) {
1253
+ const defaultJs = resolveJsOutputExtension(format);
1254
+ const defaultDts = resolveDtsOutputExtension(format);
1255
+ if (!outExtensions) return {
1256
+ js: defaultJs,
1257
+ dts: defaultDts
1258
+ };
1259
+ const custom = outExtensions(format);
1260
+ return {
1261
+ js: custom.js || defaultJs,
1262
+ dts: custom.dts || defaultDts
1263
+ };
1264
+ }
1265
+ /**
1266
+ * Create filename with proper extension
1267
+ */
1268
+ function createFilename(basename$1, format, isDts = false, options = {}) {
1269
+ const { platform, fixedExtension, outExtensions } = options;
1270
+ if (outExtensions) {
1271
+ const extensions = applyOutExtensions(format, outExtensions);
1272
+ return `${basename$1}.${isDts ? extensions.dts : extensions.js}`;
1273
+ }
1274
+ if (isDts) return `${basename$1}.${resolveDtsOutputExtension(format, fixedExtension)}`;
1275
+ return `${basename$1}.${resolveJsOutputExtension(format, platform, fixedExtension)}`;
1276
+ }
1277
+
1278
+ //#endregion
1279
+ //#region src/builders/transform.ts
1280
+ /**
1281
+ * Clean output directory for transform entries
1282
+ */
1283
+ async function cleanOutputDir(projectRoot, outDir, cleanPaths) {
1284
+ if (!cleanPaths) return;
1285
+ const { rm } = await import("node:fs/promises");
1286
+ const { existsSync: existsSync$1 } = await import("node:fs");
1287
+ if (cleanPaths === true) {
1288
+ if (existsSync$1(outDir)) {
1289
+ consola.log(`🧻 Cleaning up ${fmtPath(outDir)}`);
1290
+ await rm(outDir, {
1291
+ recursive: true,
1292
+ force: true
1293
+ });
1294
+ }
1295
+ } else if (Array.isArray(cleanPaths)) for (const path of cleanPaths) {
1296
+ const fullPath = resolve(projectRoot, path);
1297
+ if (existsSync$1(fullPath)) {
1298
+ consola.log(`🧻 Cleaning up ${fmtPath(fullPath)}`);
1299
+ await rm(fullPath, {
1300
+ recursive: true,
1301
+ force: true
1302
+ });
1303
+ }
1304
+ }
1305
+ }
1306
+ /**
1307
+ * Transform all .ts modules in a directory using oxc-transform.
1308
+ */
1309
+ async function transformDir(ctx, entry) {
1310
+ if (entry.stub) {
1311
+ consola.log(`${colors.magenta("[stub transform] ")} ${colors.underline(`${fmtPath(entry.outDir)}/`)}`);
1312
+ await symlink(entry.input, entry.outDir, "junction");
1313
+ return;
1314
+ }
1315
+ if (entry.unbundle) {
1316
+ consola.log(`${colors.magenta("[unbundle] ")} ${colors.underline(`${fmtPath(entry.outDir)}/`)}`);
1317
+ await unbundleTransform(ctx, entry);
1318
+ return;
1319
+ }
1320
+ const fullOutDir = resolve(ctx.pkgDir, entry.outDir);
1321
+ await cleanOutputDir(ctx.pkgDir, fullOutDir, entry.clean ?? true);
1322
+ const promises$1 = [];
1323
+ for await (const entryName of await glob$1("**/*.*", { cwd: entry.input })) promises$1.push((async () => {
1324
+ const entryPath = join(entry.input, entryName);
1325
+ const ext = extname(entryPath);
1326
+ switch (ext) {
1327
+ case ".ts": {
1328
+ const transformed = await transformModule(entryPath, entry);
1329
+ const baseName = entryName.replace(/\.ts$/, "");
1330
+ const outputFileName = createFilename(baseName, "esm", false, {
1331
+ platform: entry.platform,
1332
+ fixedExtension: entry.fixedExtension,
1333
+ outExtensions: entry.outExtensions
1334
+ });
1335
+ let entryDistPath = join(entry.outDir, outputFileName);
1336
+ await mkdir(dirname(entryDistPath), { recursive: true });
1337
+ await writeFile(entryDistPath, transformed.code, "utf8");
1338
+ if (entry.hash && !hasHash(entryDistPath)) {
1339
+ const hashedPath = addHashToFilename(entryDistPath, transformed.code);
1340
+ const { rename } = await import("node:fs/promises");
1341
+ await rename(entryDistPath, hashedPath);
1342
+ entryDistPath = hashedPath;
1343
+ }
1344
+ if (SHEBANG_RE.test(transformed.code)) await makeExecutable(entryDistPath);
1345
+ if (transformed.declaration) {
1346
+ const dtsFileName = createFilename(baseName, "esm", true, {
1347
+ platform: entry.platform,
1348
+ fixedExtension: entry.fixedExtension,
1349
+ outExtensions: entry.outExtensions
1350
+ });
1351
+ const dtsPath = join(entry.outDir, dtsFileName);
1352
+ await writeFile(dtsPath, transformed.declaration, "utf8");
1353
+ }
1354
+ return entryDistPath;
1355
+ }
1356
+ default: {
1357
+ const entryDistPath = join(entry.outDir, entryName);
1358
+ await mkdir(dirname(entryDistPath), { recursive: true });
1359
+ const code = await readFile(entryPath, "utf8");
1360
+ await writeFile(entryDistPath, code, "utf8");
1361
+ if (SHEBANG_RE.test(code)) await makeExecutable(entryDistPath);
1362
+ return entryDistPath;
1363
+ }
1364
+ }
1365
+ })());
1366
+ const writtenFiles = await Promise.all(promises$1);
1367
+ if (entry.copy) await copyFiles(ctx.pkgDir, fullOutDir, entry.copy);
1368
+ consola.log(`\n${colors.magenta("[transform] ")}${colors.underline(`${fmtPath(entry.outDir)}/`)}\n${writtenFiles.map((f) => colors.dim(fmtPath(f))).join("\n\n")}`);
1369
+ }
1370
+ /**
1371
+ * Transform a .ts module using oxc-transform.
1372
+ */
1373
+ async function transformModule(entryPath, entry) {
1374
+ let sourceText = await readFile(entryPath, "utf8");
1375
+ const sourceOptions = {
1376
+ lang: "ts",
1377
+ sourceType: "module"
1378
+ };
1379
+ const parsed = parseSync(entryPath, sourceText, { ...sourceOptions });
1380
+ if (parsed.errors.length > 0) {
1381
+ const error = /* @__PURE__ */ new Error(`Errors while parsing ${entryPath}:`);
1382
+ error.cause = parsed.errors;
1383
+ throw error;
1384
+ }
1385
+ const resolveOptions = {
1386
+ ...entry.resolve,
1387
+ from: pathToFileURL(entryPath),
1388
+ extensions: entry.resolve?.extensions ?? [
1389
+ ".ts",
1390
+ ".js",
1391
+ ".mjs",
1392
+ ".cjs",
1393
+ ".json"
1394
+ ],
1395
+ suffixes: entry.resolve?.suffixes ?? ["", "/index"]
1396
+ };
1397
+ const magicString = new MagicString(sourceText);
1398
+ const updatedStarts = /* @__PURE__ */ new Set();
1399
+ const rewriteSpecifier = (req) => {
1400
+ let moduleId = req.value;
1401
+ let wasAliasResolved = false;
1402
+ if (entry.alias) {
1403
+ for (const [alias, target] of Object.entries(entry.alias)) if (moduleId === alias || moduleId.startsWith(`${alias}/`)) {
1404
+ moduleId = moduleId.replace(alias, target);
1405
+ wasAliasResolved = true;
1406
+ break;
1407
+ }
1408
+ }
1409
+ if (!moduleId.startsWith(".") && !wasAliasResolved) return;
1410
+ if (updatedStarts.has(req.start)) return;
1411
+ updatedStarts.add(req.start);
1412
+ const resolvedAbsolute = resolveModulePath(moduleId, resolveOptions);
1413
+ const newId = relative(dirname(entryPath), resolvedAbsolute.replace(/\.ts$/, ".mjs"));
1414
+ magicString.remove(req.start, req.end);
1415
+ magicString.prependLeft(req.start, JSON.stringify(newId.startsWith(".") ? newId : `./${newId}`));
1416
+ };
1417
+ for (const staticImport of parsed.module.staticImports) rewriteSpecifier(staticImport.moduleRequest);
1418
+ for (const staticExport of parsed.module.staticExports) for (const staticExportEntry of staticExport.entries) if (staticExportEntry.moduleRequest) rewriteSpecifier(staticExportEntry.moduleRequest);
1419
+ sourceText = magicString.toString();
1420
+ const transformed = transform(entryPath, sourceText, {
1421
+ ...entry.oxc,
1422
+ ...sourceOptions,
1423
+ cwd: dirname(entryPath),
1424
+ target: entry.target || "es2022",
1425
+ typescript: {
1426
+ declaration: { stripInternal: true },
1427
+ ...entry.oxc?.typescript
1428
+ }
1429
+ });
1430
+ const transformErrors = transformed.errors.filter((err) => !err.message.includes("--isolatedDeclarations"));
1431
+ if (transformErrors.length > 0) {
1432
+ await writeFile("build-dump.ts", `/** Error dump for ${entryPath} */\n\n${sourceText}`, "utf8");
1433
+ const error = /* @__PURE__ */ new Error(`Errors while transforming ${entryPath}: (hint: check build-dump.ts)`);
1434
+ error.cause = transformErrors;
1435
+ throw error;
1436
+ }
1437
+ if (entry.minify) {
1438
+ const res = minify(entryPath, transformed.code, entry.minify === true ? {} : entry.minify);
1439
+ transformed.code = res.code;
1440
+ transformed.map = res.map;
1441
+ }
1442
+ const banner = resolveChunkAddon(entry.banner, "esm");
1443
+ const footer = resolveChunkAddon(entry.footer, "esm");
1444
+ transformed.code = addBannerFooter(transformed.code, banner, footer);
1445
+ if (entry.nodeProtocol) transformed.code = transformNodeProtocol(transformed.code, entry.nodeProtocol);
1446
+ return transformed;
1447
+ }
1448
+
1449
+ //#endregion
1450
+ //#region src/features/exports.ts
1451
+ /**
1452
+ * Generate package.json exports field based on build configuration
1453
+ */
1454
+ async function generatePackageExports(packageRoot, buildConfig, exportsConfig = { enabled: true }) {
1455
+ if (!exportsConfig.enabled) return {};
1456
+ const exports = {};
1457
+ const baseDir = exportsConfig.baseDir || "dist";
1458
+ if (exportsConfig.custom) Object.assign(exports, exportsConfig.custom);
1459
+ if (buildConfig.entries) for (const entry of buildConfig.entries) {
1460
+ const exportEntries = await generateExportFromEntry(packageRoot, entry, baseDir, exportsConfig.includeTypes);
1461
+ for (const exportEntry of exportEntries) exports[exportEntry.key] = createExportValue(exportEntry);
1462
+ }
1463
+ if (!exports["."] && !exports["./index"]) {
1464
+ const mainExport = await findMainExport(packageRoot, baseDir);
1465
+ if (mainExport) exports["."] = mainExport;
1466
+ }
1467
+ return exports;
1468
+ }
1469
+ /**
1470
+ * Generate export entries from a build entry
1471
+ */
1472
+ async function generateExportFromEntry(packageRoot, entry, baseDir, includeTypes) {
1473
+ const exports = [];
1474
+ if (entry.type === "bundle") {
1475
+ const exportKey = getExportKey(entry.input);
1476
+ const exportEntry = { key: exportKey };
1477
+ if (Array.isArray(entry.format)) for (const format of entry.format) {
1478
+ const outputPath = getOutputPath(entry, format, baseDir);
1479
+ assignFormatToExport(exportEntry, format, outputPath);
1480
+ }
1481
+ else if (entry.format) {
1482
+ const outputPath = getOutputPath(entry, entry.format, baseDir);
1483
+ assignFormatToExport(exportEntry, entry.format, outputPath);
1484
+ }
1485
+ if (includeTypes && entry.dts) {
1486
+ const typesPath = getTypesPath(entry, baseDir);
1487
+ exportEntry.types = typesPath;
1488
+ }
1489
+ exports.push(exportEntry);
1490
+ } else if (entry.type === "transform") {
1491
+ const transformExports = await discoverTransformExports(packageRoot, entry, baseDir, includeTypes);
1492
+ exports.push(...transformExports);
1493
+ }
1494
+ return exports;
1495
+ }
1496
+ /**
1497
+ * Get export key from input path
1498
+ */
1499
+ function getExportKey(input) {
1500
+ if (input === "index.ts" || input === "src/index.ts") return ".";
1501
+ let key = input.replace(/\.(ts|js|tsx|jsx)$/, "");
1502
+ key = key.replace(/^src\//, "");
1503
+ return key === "index" ? "." : `./${key}`;
1504
+ }
1505
+ /**
1506
+ * Get output path for a specific format
1507
+ */
1508
+ function getOutputPath(entry, format, baseDir) {
1509
+ const extension = getExtensionForFormat(format);
1510
+ const basename$1 = getBasename(entry.input);
1511
+ if (format === "cjs") return `./${baseDir}/cjs/${basename$1}${extension}`;
1512
+ else if (format === "esm") return `./${baseDir}/${basename$1}${extension}`;
1513
+ else return `./${baseDir}/${format}/${basename$1}${extension}`;
1514
+ }
1515
+ /**
1516
+ * Get file extension for format
1517
+ */
1518
+ function getExtensionForFormat(format) {
1519
+ switch (format) {
1520
+ case "esm": return ".mjs";
1521
+ case "cjs": return ".cjs";
1522
+ case "iife":
1523
+ case "umd": return ".js";
1524
+ default: return ".js";
1525
+ }
1526
+ }
1527
+ /**
1528
+ * Get basename from input path
1529
+ */
1530
+ function getBasename(input) {
1531
+ return input.replace(/\.(ts|js|tsx|jsx)$/, "").replace(/^src\//, "");
1532
+ }
1533
+ /**
1534
+ * Get types path for entry
1535
+ */
1536
+ function getTypesPath(entry, baseDir) {
1537
+ const basename$1 = getBasename(entry.input);
1538
+ return `./${baseDir}/${basename$1}.d.ts`;
1539
+ }
1540
+ /**
1541
+ * Assign format-specific path to export entry
1542
+ */
1543
+ function assignFormatToExport(exportEntry, format, path) {
1544
+ switch (format) {
1545
+ case "esm":
1546
+ exportEntry.import = path;
1547
+ break;
1548
+ case "cjs":
1549
+ exportEntry.require = path;
1550
+ break;
1551
+ default:
1552
+ exportEntry.import = path;
1553
+ break;
1554
+ }
1555
+ }
1556
+ /**
1557
+ * Create export value from export entry
1558
+ */
1559
+ function createExportValue(entry) {
1560
+ const value = {};
1561
+ if (entry.types) value.types = entry.types;
1562
+ if (entry.import) value.import = entry.import;
1563
+ if (entry.require) value.require = entry.require;
1564
+ const keys = Object.keys(value);
1565
+ if (keys.length === 1 && !entry.types) return value[keys[0]];
1566
+ return value;
1567
+ }
1568
+ /**
1569
+ * Discover exports from transform entries
1570
+ */
1571
+ async function discoverTransformExports(packageRoot, entry, baseDir, includeTypes) {
1572
+ const exports = [];
1573
+ const exportKey = getExportKey(entry.input);
1574
+ const exportEntry = {
1575
+ key: exportKey,
1576
+ import: `./${baseDir}/${getBasename(entry.input)}.mjs`
1577
+ };
1578
+ if (includeTypes && entry.dts) exportEntry.types = getTypesPath(entry, baseDir);
1579
+ exports.push(exportEntry);
1580
+ return exports;
1581
+ }
1582
+ /**
1583
+ * Find main export file
1584
+ */
1585
+ async function findMainExport(packageRoot, baseDir) {
1586
+ const possibleMains = [
1587
+ "index.mjs",
1588
+ "index.js",
1589
+ "index.cjs"
1590
+ ];
1591
+ for (const main of possibleMains) try {
1592
+ join(packageRoot, baseDir, main);
1593
+ const value = {};
1594
+ if (main.endsWith(".mjs")) value.import = `./${baseDir}/${main}`;
1595
+ else if (main.endsWith(".cjs")) value.require = `./${baseDir}/${main}`;
1596
+ else value.import = `./${baseDir}/${main}`;
1597
+ return value;
1598
+ } catch {
1599
+ continue;
1600
+ }
1601
+ return null;
1602
+ }
1603
+ /**
1604
+ * Update package.json with generated exports
1605
+ */
1606
+ async function updatePackageJsonExports(packageRoot, exports) {
1607
+ const packageJsonPath = join(packageRoot, "package.json");
1608
+ try {
1609
+ const content = await readFile(packageJsonPath, "utf-8");
1610
+ const packageJson = JSON.parse(content);
1611
+ packageJson.exports = exports;
1612
+ const updatedContent = `${JSON.stringify(packageJson, null, 2)}\n`;
1613
+ await writeFile(packageJsonPath, updatedContent, "utf-8");
1614
+ } catch (error) {
1615
+ throw new Error(`Failed to update package.json: ${error}`);
1616
+ }
1617
+ }
1618
+
1619
+ //#endregion
1620
+ //#region src/features/logger.ts
1621
+ /**
1622
+ * Logger instance with configurable log level
1623
+ */
1624
+ var Logger = class {
1625
+ level = "info";
1626
+ warningCount = 0;
1627
+ errorCount = 0;
1628
+ constructor(level = "info") {
1629
+ this.level = level;
1630
+ this.updateConsolaLevel();
1631
+ }
1632
+ setLevel(level) {
1633
+ this.level = level;
1634
+ this.updateConsolaLevel();
1635
+ }
1636
+ updateConsolaLevel() {
1637
+ const levelMap = {
1638
+ silent: 0,
1639
+ error: 1,
1640
+ warn: 2,
1641
+ info: 3,
1642
+ verbose: 4
1643
+ };
1644
+ consola.level = levelMap[this.level];
1645
+ }
1646
+ silent(message, ...args) {
1647
+ console.log(message, ...args);
1648
+ }
1649
+ error(message, ...args) {
1650
+ this.errorCount++;
1651
+ consola.error(message, ...args);
1652
+ }
1653
+ warn(message, ...args) {
1654
+ this.warningCount++;
1655
+ consola.warn(message, ...args);
1656
+ }
1657
+ info(message, ...args) {
1658
+ consola.info(message, ...args);
1659
+ }
1660
+ verbose(message, ...args) {
1661
+ if (this.level === "verbose") consola.debug(message, ...args);
1662
+ }
1663
+ success(message, ...args) {
1664
+ consola.success(message, ...args);
1665
+ }
1666
+ log(message, ...args) {
1667
+ consola.log(message, ...args);
1668
+ }
1669
+ getWarningCount() {
1670
+ return this.warningCount;
1671
+ }
1672
+ getErrorCount() {
1673
+ return this.errorCount;
1674
+ }
1675
+ resetCounts() {
1676
+ this.warningCount = 0;
1677
+ this.errorCount = 0;
1678
+ }
1679
+ shouldFailOnWarnings(failOnWarn) {
1680
+ return failOnWarn && this.warningCount > 0;
1681
+ }
1682
+ };
1683
+ const logger = new Logger();
1684
+ /**
1685
+ * Configure global logger
1686
+ */
1687
+ function configureLogger(level) {
1688
+ logger.setLevel(level);
1689
+ }
1690
+ /**
1691
+ * Reset warning and error counts
1692
+ */
1693
+ function resetLogCounts() {
1694
+ logger.resetCounts();
1695
+ }
1696
+ /**
1697
+ * Check if build should fail due to warnings
1698
+ */
1699
+ function shouldFailOnWarnings(failOnWarn) {
1700
+ return logger.shouldFailOnWarnings(failOnWarn);
1701
+ }
1702
+
1703
+ //#endregion
1704
+ //#region src/features/on-success.ts
1705
+ const execAsync = promisify(exec);
1706
+ /**
1707
+ * Execute onSuccess callback after successful build
1708
+ */
1709
+ async function executeOnSuccess(onSuccess, result, cwd) {
1710
+ if (!onSuccess) return;
1711
+ try {
1712
+ if (typeof onSuccess === "string") {
1713
+ logger.verbose(`Executing onSuccess command: ${onSuccess}`);
1714
+ const { stdout, stderr } = await execAsync(onSuccess, { cwd });
1715
+ if (stdout) logger.verbose(`onSuccess stdout: ${stdout.trim()}`);
1716
+ if (stderr) logger.warn(`onSuccess stderr: ${stderr.trim()}`);
1717
+ } else {
1718
+ logger.verbose("Executing onSuccess callback function");
1719
+ await onSuccess(result);
1720
+ }
1721
+ logger.verbose("onSuccess callback completed successfully");
1722
+ } catch (error) {
1723
+ logger.error("onSuccess callback failed:", error);
1724
+ throw error;
1725
+ }
1726
+ }
1727
+ /**
1728
+ * Create build result object
1729
+ */
1730
+ function createBuildResult(entries, startTime) {
1731
+ return {
1732
+ entries: entries.map((entry) => ({
1733
+ ...entry,
1734
+ format: entry.format
1735
+ })),
1736
+ duration: Date.now() - startTime
1737
+ };
1738
+ }
1739
+
1740
+ //#endregion
1741
+ //#region src/features/vite-config.ts
1742
+ /**
1743
+ * Load Vite configuration and convert to robuild config
1744
+ */
1745
+ async function loadViteConfig(cwd) {
1746
+ const configFiles = [
1747
+ "vite.config.ts",
1748
+ "vite.config.js",
1749
+ "vite.config.mts",
1750
+ "vite.config.mjs",
1751
+ "vitest.config.ts",
1752
+ "vitest.config.js"
1753
+ ];
1754
+ let configPath;
1755
+ for (const file of configFiles) {
1756
+ const fullPath = resolve(cwd, file);
1757
+ if (existsSync(fullPath)) {
1758
+ configPath = fullPath;
1759
+ break;
1760
+ }
1761
+ }
1762
+ if (!configPath) {
1763
+ logger.warn("No Vite config file found, skipping Vite config loading");
1764
+ return {};
1765
+ }
1766
+ try {
1767
+ logger.verbose(`Loading Vite config from: ${configPath}`);
1768
+ const configModule = await import(configPath);
1769
+ const viteConfig = configModule.default || configModule;
1770
+ return convertViteConfig(viteConfig);
1771
+ } catch (error) {
1772
+ logger.error(`Failed to load Vite config from ${configPath}:`, error);
1773
+ return {};
1774
+ }
1775
+ }
1776
+ /**
1777
+ * Convert Vite config to robuild config
1778
+ */
1779
+ function convertViteConfig(viteConfig) {
1780
+ const config = {};
1781
+ if (viteConfig.build?.lib) {
1782
+ const lib = viteConfig.build.lib;
1783
+ const entries = [];
1784
+ if (typeof lib.entry === "string") entries.push({
1785
+ type: "bundle",
1786
+ input: lib.entry,
1787
+ format: convertFormats(lib.formats),
1788
+ globalName: lib.name,
1789
+ minify: viteConfig.build.minify,
1790
+ target: convertTarget(viteConfig.build.target),
1791
+ external: convertExternal(viteConfig.build.rollupOptions?.external)
1792
+ });
1793
+ else if (Array.isArray(lib.entry)) for (const entry of lib.entry) entries.push({
1794
+ type: "bundle",
1795
+ input: entry,
1796
+ format: convertFormats(lib.formats),
1797
+ globalName: lib.name,
1798
+ minify: viteConfig.build.minify,
1799
+ target: convertTarget(viteConfig.build.target),
1800
+ external: convertExternal(viteConfig.build.rollupOptions?.external)
1801
+ });
1802
+ else if (lib.entry && typeof lib.entry === "object") for (const [name, entry] of Object.entries(lib.entry)) entries.push({
1803
+ type: "bundle",
1804
+ input: entry,
1805
+ format: convertFormats(lib.formats),
1806
+ globalName: lib.name || name,
1807
+ minify: viteConfig.build.minify,
1808
+ target: convertTarget(viteConfig.build.target),
1809
+ external: convertExternal(viteConfig.build.rollupOptions?.external)
1810
+ });
1811
+ if (entries.length > 0) config.entries = entries;
1812
+ }
1813
+ return config;
1814
+ }
1815
+ /**
1816
+ * Convert Vite formats to robuild formats
1817
+ */
1818
+ function convertFormats(formats) {
1819
+ if (!formats) return void 0;
1820
+ const formatMap = {
1821
+ es: "esm",
1822
+ cjs: "cjs",
1823
+ umd: "umd",
1824
+ iife: "iife"
1825
+ };
1826
+ return formats.map((format) => formatMap[format] || format).filter(Boolean);
1827
+ }
1828
+ /**
1829
+ * Convert Vite target to robuild target
1830
+ */
1831
+ function convertTarget(target) {
1832
+ if (!target) return void 0;
1833
+ const targetMap = {
1834
+ es2015: "es2015",
1835
+ es2016: "es2016",
1836
+ es2017: "es2017",
1837
+ es2018: "es2018",
1838
+ es2019: "es2019",
1839
+ es2020: "es2020",
1840
+ es2021: "es2021",
1841
+ es2022: "es2022",
1842
+ esnext: "esnext"
1843
+ };
1844
+ return targetMap[target] || void 0;
1845
+ }
1846
+ /**
1847
+ * Convert Vite external config to robuild external
1848
+ */
1849
+ function convertExternal(external) {
1850
+ return external;
1851
+ }
1852
+
1853
+ //#endregion
1854
+ //#region src/features/workspace.ts
1855
+ /**
1856
+ * Discover workspace packages based on patterns
1857
+ */
1858
+ async function discoverWorkspacePackages(workspaceRoot, patterns = ["packages/*", "apps/*"]) {
1859
+ const packages = [];
1860
+ for (const pattern of patterns) {
1861
+ const packagePaths = await glob(pattern, {
1862
+ cwd: workspaceRoot,
1863
+ onlyDirectories: true
1864
+ });
1865
+ for (const packagePath of packagePaths) {
1866
+ const fullPath = resolve(workspaceRoot, packagePath);
1867
+ const packageJsonPath = join(fullPath, "package.json");
1868
+ try {
1869
+ const packageJsonContent = await readFile(packageJsonPath, "utf-8");
1870
+ const packageJson = JSON.parse(packageJsonContent);
1871
+ packages.push({
1872
+ name: packageJson.name || packagePath,
1873
+ path: fullPath,
1874
+ packageJson
1875
+ });
1876
+ } catch {
1877
+ continue;
1878
+ }
1879
+ }
1880
+ }
1881
+ return packages;
1882
+ }
1883
+ /**
1884
+ * Filter workspace packages based on filter patterns
1885
+ */
1886
+ function filterWorkspacePackages(packages, filter, exclude) {
1887
+ let filtered = packages;
1888
+ if (filter) {
1889
+ const filters = Array.isArray(filter) ? filter : [filter];
1890
+ filtered = filtered.filter((pkg) => filters.some((f) => matchesPattern(pkg.name, f) || matchesPattern(pkg.path, f)));
1891
+ }
1892
+ if (exclude) {
1893
+ const excludes = Array.isArray(exclude) ? exclude : [exclude];
1894
+ filtered = filtered.filter((pkg) => !excludes.some((e) => matchesPattern(pkg.name, e) || matchesPattern(pkg.path, e)));
1895
+ }
1896
+ return filtered;
1897
+ }
1898
+ /**
1899
+ * Check if a string matches a pattern (supports wildcards)
1900
+ */
1901
+ function matchesPattern(str, pattern) {
1902
+ const regexPattern = pattern.replace(/\*/g, ".*").replace(/\?/g, ".").replace(/\[([^\]]+)\]/g, "[$1]");
1903
+ const regex = /* @__PURE__ */ new RegExp(`^${regexPattern}$`);
1904
+ return regex.test(str);
1905
+ }
1906
+ /**
1907
+ * Load workspace configuration from package.json or workspace config file
1908
+ */
1909
+ async function loadWorkspaceConfig(workspaceRoot) {
1910
+ try {
1911
+ const packageJsonPath = join(workspaceRoot, "package.json");
1912
+ const packageJsonContent = await readFile(packageJsonPath, "utf-8");
1913
+ const packageJson = JSON.parse(packageJsonContent);
1914
+ if (packageJson.workspaces) {
1915
+ const workspaces = Array.isArray(packageJson.workspaces) ? packageJson.workspaces : packageJson.workspaces.packages || [];
1916
+ return { packages: workspaces };
1917
+ }
1918
+ try {
1919
+ const { load } = await import("js-yaml");
1920
+ const pnpmWorkspacePath = join(workspaceRoot, "pnpm-workspace.yaml");
1921
+ const pnpmWorkspaceContent = await readFile(pnpmWorkspacePath, "utf-8");
1922
+ const pnpmWorkspace = load(pnpmWorkspaceContent);
1923
+ if (pnpmWorkspace?.packages) return { packages: pnpmWorkspace.packages };
1924
+ } catch {}
1925
+ try {
1926
+ const lernaJsonPath = join(workspaceRoot, "lerna.json");
1927
+ const lernaJsonContent = await readFile(lernaJsonPath, "utf-8");
1928
+ const lernaJson = JSON.parse(lernaJsonContent);
1929
+ if (lernaJson.packages) return { packages: lernaJson.packages };
1930
+ } catch {}
1931
+ return null;
1932
+ } catch {
1933
+ return null;
1934
+ }
1935
+ }
1936
+ /**
1937
+ * Build workspace packages in dependency order
1938
+ */
1939
+ async function buildWorkspacePackages(packages, buildFn) {
1940
+ await Promise.all(packages.map(buildFn));
1941
+ }
1942
+
1943
+ //#endregion
1944
+ //#region src/features/ignore-watch.ts
1945
+ /**
1946
+ * Normalize ignore patterns
1947
+ */
1948
+ function normalizeIgnorePatterns(patterns) {
1949
+ return patterns.map((pattern) => {
1950
+ if (pattern.startsWith("./")) return pattern.slice(2);
1951
+ if (pattern.startsWith("/")) return pattern.slice(1);
1952
+ return pattern;
1953
+ });
1954
+ }
1955
+
1956
+ //#endregion
1957
+ //#region src/watch.ts
1958
+ /**
1959
+ * Start watching files and rebuild on changes
1960
+ */
1961
+ async function startWatch(config, ctx, buildFn) {
1962
+ const watchOptions = config.watch || {};
1963
+ if (!watchOptions.enabled) throw new Error("Watch mode is not enabled");
1964
+ const watchCtx = {
1965
+ config,
1966
+ ctx,
1967
+ buildFn,
1968
+ isBuilding: false,
1969
+ pendingRebuild: false
1970
+ };
1971
+ const watchPatterns = await getWatchPatterns(config, ctx, watchOptions);
1972
+ const ignorePatterns = getIgnorePatterns(config, watchOptions);
1973
+ consola.info(`šŸ‘€ Starting watch mode...`);
1974
+ consola.info(`šŸ“ Watching: ${colors.dim(watchPatterns.join(", "))}`);
1975
+ if (ignorePatterns.length > 0) consola.info(`🚫 Ignoring: ${colors.dim(ignorePatterns.join(", "))}`);
1976
+ const delay = watchOptions.delay ?? 100;
1977
+ if (delay > 0) consola.info(`ā±ļø Rebuild delay: ${colors.dim(`${delay}ms`)}`);
1978
+ const watcher = watch(watchPatterns, {
1979
+ ignored: ignorePatterns,
1980
+ ignoreInitial: watchOptions.ignoreInitial ?? false,
1981
+ persistent: true,
1982
+ followSymlinks: false,
1983
+ cwd: ctx.pkgDir
1984
+ });
1985
+ watcher.on("change", (path) => handleFileChange(watchCtx, path, "changed"));
1986
+ watcher.on("add", (path) => {
1987
+ if (watchOptions.watchNewFiles !== false) handleFileChange(watchCtx, path, "added");
1988
+ });
1989
+ watcher.on("unlink", (path) => handleFileChange(watchCtx, path, "removed"));
1990
+ watcher.on("error", (error) => {
1991
+ consola.error("āŒ Watch error:", error);
1992
+ });
1993
+ if (process.env.DEBUG) {
1994
+ watcher.on("addDir", (path) => consola.debug(`šŸ“ Directory added: ${path}`));
1995
+ watcher.on("unlinkDir", (path) => consola.debug(`šŸ“ Directory removed: ${path}`));
1996
+ }
1997
+ await new Promise((resolve$1) => {
1998
+ watcher.on("ready", () => {
1999
+ const watchedPaths = watcher.getWatched();
2000
+ const totalFiles = Object.values(watchedPaths).reduce((sum, files) => sum + files.length, 0);
2001
+ consola.success(`šŸš€ Watch mode ready - watching ${totalFiles} files`);
2002
+ consola.info(`šŸ’” Press ${colors.cyan("Ctrl+C")} to stop watching`);
2003
+ resolve$1();
2004
+ });
2005
+ });
2006
+ return () => {
2007
+ if (watchCtx.rebuildTimer) clearTimeout(watchCtx.rebuildTimer);
2008
+ return watcher.close();
2009
+ };
2010
+ }
2011
+ /**
2012
+ * Handle file change events
2013
+ */
2014
+ function handleFileChange(watchCtx, filePath, changeType) {
2015
+ const { config, ctx } = watchCtx;
2016
+ const watchOptions = config.watch || {};
2017
+ const delay = watchOptions.delay ?? 100;
2018
+ const relativePath = relative(ctx.pkgDir, join(ctx.pkgDir, filePath));
2019
+ const formattedPath = fmtPath(relativePath);
2020
+ const changeIcon = changeType === "changed" ? "šŸ“" : changeType === "added" ? "āž•" : "āž–";
2021
+ consola.info(`${changeIcon} ${colors.cyan(formattedPath)} ${changeType}`);
2022
+ if (watchCtx.rebuildTimer) clearTimeout(watchCtx.rebuildTimer);
2023
+ watchCtx.pendingRebuild = true;
2024
+ watchCtx.rebuildTimer = setTimeout(() => {
2025
+ triggerRebuild(watchCtx);
2026
+ }, delay);
2027
+ }
2028
+ /**
2029
+ * Trigger a rebuild
2030
+ */
2031
+ async function triggerRebuild(watchCtx) {
2032
+ const { config, buildFn } = watchCtx;
2033
+ if (watchCtx.isBuilding) return;
2034
+ if (!watchCtx.pendingRebuild) return;
2035
+ watchCtx.isBuilding = true;
2036
+ watchCtx.pendingRebuild = false;
2037
+ try {
2038
+ consola.info(`šŸ”„ Rebuilding...`);
2039
+ const start = Date.now();
2040
+ const buildConfig = {
2041
+ ...config,
2042
+ watch: {
2043
+ ...config.watch,
2044
+ enabled: false
2045
+ }
2046
+ };
2047
+ await buildFn(buildConfig);
2048
+ const duration = Date.now() - start;
2049
+ consola.success(`āœ… Rebuild completed in ${duration}ms`);
2050
+ } catch (error) {
2051
+ consola.error("āŒ Rebuild failed:");
2052
+ if (error instanceof Error) {
2053
+ consola.error(` ${error.message}`);
2054
+ if (process.env.DEBUG && error.stack) consola.debug(error.stack);
2055
+ } else consola.error(` ${String(error)}`);
2056
+ consola.info("šŸ‘€ Still watching for changes...");
2057
+ } finally {
2058
+ watchCtx.isBuilding = false;
2059
+ if (watchCtx.pendingRebuild) setTimeout(() => triggerRebuild(watchCtx), watchCtx.config.watch?.delay ?? 100);
2060
+ }
2061
+ }
2062
+ /**
2063
+ * Get patterns for files to watch
2064
+ */
2065
+ async function getWatchPatterns(config, ctx, watchOptions) {
2066
+ if (watchOptions.include && watchOptions.include.length > 0) return watchOptions.include.map(normalizeGlobPattern);
2067
+ const patterns = /* @__PURE__ */ new Set();
2068
+ const addPattern = (pattern) => {
2069
+ if (!pattern) return;
2070
+ patterns.add(normalizeGlobPattern(pattern));
2071
+ };
2072
+ const addFilePatterns = (inputFile) => {
2073
+ const absoluteInput = resolveToAbsolute(inputFile, ctx);
2074
+ const filePattern = normalizeRelativeToPkg(absoluteInput, ctx);
2075
+ if (filePattern && filePattern !== ".") addPattern(filePattern);
2076
+ addPattern(getDirGlobPattern(dirname(absoluteInput), ctx));
2077
+ };
2078
+ const addDirectoryPatterns = (inputDir) => {
2079
+ const absoluteDir = resolveToAbsolute(inputDir, ctx);
2080
+ addPattern(getDirGlobPattern(absoluteDir, ctx));
2081
+ };
2082
+ for (const entry of config.entries || []) if (typeof entry === "string") {
2083
+ const [input] = entry.split(":");
2084
+ if (input.endsWith("/")) addDirectoryPatterns(input);
2085
+ else {
2086
+ const inputs = input.split(",");
2087
+ for (const inputFile of inputs) addFilePatterns(inputFile);
2088
+ }
2089
+ } else if (entry.type === "transform") addDirectoryPatterns(entry.input);
2090
+ else {
2091
+ const inputs = Array.isArray(entry.input) ? entry.input : [entry.input];
2092
+ for (const inputFile of inputs) addFilePatterns(inputFile);
2093
+ }
2094
+ if (patterns.size === 0) [
2095
+ "src/**/*",
2096
+ "*.ts",
2097
+ "*.js",
2098
+ "*.mjs",
2099
+ "*.json"
2100
+ ].forEach((pattern) => addPattern(pattern));
2101
+ return Array.from(patterns);
2102
+ }
2103
+ /**
2104
+ * Get patterns for files to ignore
2105
+ */
2106
+ function getIgnorePatterns(config, watchOptions) {
2107
+ const defaultIgnores = [
2108
+ "**/node_modules/**",
2109
+ "**/dist/**",
2110
+ "**/build/**",
2111
+ "**/coverage/**",
2112
+ "**/.git/**",
2113
+ "**/.DS_Store",
2114
+ "**/Thumbs.db",
2115
+ "**/*.log",
2116
+ "**/tmp/**",
2117
+ "**/temp/**"
2118
+ ];
2119
+ const allIgnores = [...defaultIgnores];
2120
+ if (watchOptions.exclude && watchOptions.exclude.length > 0) allIgnores.push(...watchOptions.exclude);
2121
+ if (config.ignoreWatch && config.ignoreWatch.length > 0) allIgnores.push(...normalizeIgnorePatterns(config.ignoreWatch));
2122
+ return allIgnores;
2123
+ }
2124
+ function resolveToAbsolute(path, ctx) {
2125
+ return isAbsolute(path) ? path : join(ctx.pkgDir, path);
2126
+ }
2127
+ function normalizeGlobPattern(pattern) {
2128
+ return pattern.replace(/\\/g, "/");
2129
+ }
2130
+ function normalizeRelativeToPkg(target, ctx) {
2131
+ const relativePath = relative(ctx.pkgDir, target);
2132
+ if (!relativePath || relativePath === "") return ".";
2133
+ if (relativePath.includes(":")) return normalizeGlobPattern(target);
2134
+ return normalizeGlobPattern(relativePath);
2135
+ }
2136
+ function getDirGlobPattern(directory, ctx) {
2137
+ const normalizedDir = normalizeRelativeToPkg(directory, ctx);
2138
+ if (!normalizedDir || normalizedDir === "." || normalizedDir === "./") return "**/*";
2139
+ return `${stripTrailingSlash(normalizedDir)}/**/*`;
2140
+ }
2141
+ function stripTrailingSlash(path) {
2142
+ return path.replace(/\/+$/, "");
2143
+ }
2144
+
2145
+ //#endregion
2146
+ //#region src/build.ts
2147
+ /**
2148
+ * Build dist/ from src/
2149
+ */
2150
+ async function build(config) {
2151
+ const startTime = Date.now();
2152
+ if (config.logLevel) configureLogger(config.logLevel);
2153
+ resetLogCounts();
2154
+ const pkgDir = normalizePath(config.cwd);
2155
+ const pkg = await readJSON(join(pkgDir, "package.json")).catch(() => ({}));
2156
+ const ctx = {
2157
+ pkg,
2158
+ pkgDir
2159
+ };
2160
+ if (config.workspace) return buildWorkspace(config, pkgDir);
2161
+ let finalConfig = config;
2162
+ if (config.fromVite) {
2163
+ logger.verbose("Loading configuration from Vite config file");
2164
+ const viteConfig = await loadViteConfig(pkgDir);
2165
+ finalConfig = {
2166
+ ...viteConfig,
2167
+ ...config
2168
+ };
2169
+ }
2170
+ if (finalConfig.watch?.enabled) {
2171
+ logger.info(`šŸ‘€ Starting watch mode for \`${ctx.pkg.name || "<no name>"}\` (\`${ctx.pkgDir}\`)`);
2172
+ await performBuild(finalConfig, ctx, startTime);
2173
+ const stopWatch = await startWatch(finalConfig, ctx, build);
2174
+ const cleanup = () => {
2175
+ consola.info("šŸ›‘ Stopping watch mode...");
2176
+ stopWatch();
2177
+ process.exit(0);
2178
+ };
2179
+ process.on("SIGINT", cleanup);
2180
+ process.on("SIGTERM", cleanup);
2181
+ return new Promise(() => {});
2182
+ }
2183
+ logger.info(`šŸ“¦ Building \`${ctx.pkg.name || "<no name>"}\` (\`${ctx.pkgDir}\`)`);
2184
+ await performBuild(finalConfig, ctx, startTime);
2185
+ }
2186
+ /**
2187
+ * Perform the actual build process
2188
+ */
2189
+ async function performBuild(config, ctx, startTime) {
2190
+ const start = Date.now();
2191
+ const hooks = config.hooks || {};
2192
+ await hooks.start?.(ctx);
2193
+ const entries = (config.entries || []).map((rawEntry) => {
2194
+ let entry;
2195
+ if (typeof rawEntry === "string") {
2196
+ const [input, outDir] = rawEntry.split(":");
2197
+ entry = input.endsWith("/") ? {
2198
+ type: "transform",
2199
+ input,
2200
+ outDir
2201
+ } : {
2202
+ type: "bundle",
2203
+ input: input.split(","),
2204
+ outDir
2205
+ };
2206
+ } else entry = rawEntry;
2207
+ if (!entry.input) throw new Error(`Build entry missing \`input\`: ${JSON.stringify(entry, null, 2)}`);
2208
+ entry = { ...entry };
2209
+ entry.outDir = normalizePath(entry.outDir || "dist", ctx.pkgDir);
2210
+ entry.input = Array.isArray(entry.input) ? entry.input.map((p) => normalizePath(p, ctx.pkgDir)) : normalizePath(entry.input, ctx.pkgDir);
2211
+ return entry;
2212
+ });
2213
+ await hooks.entries?.(entries, ctx);
2214
+ const outDirs = [];
2215
+ for (const outDir of entries.map((e) => e.outDir).sort()) if (!outDirs.some((dir) => outDir.startsWith(dir))) outDirs.push(outDir);
2216
+ for (const entry of entries) await (entry.type === "bundle" ? rolldownBuild(ctx, entry, hooks, config) : transformDir(ctx, entry));
2217
+ await hooks.end?.(ctx);
2218
+ if (shouldFailOnWarnings(config.failOnWarn || false)) throw new Error("Build failed due to warnings");
2219
+ const dirSize = analyzeDir(outDirs);
2220
+ logger.info(colors.dim(`\nΣ Total dist byte size: ${colors.underline(prettyBytes(dirSize.size))} (${colors.underline(dirSize.files)} files)`));
2221
+ const duration = Date.now() - start;
2222
+ logger.success(`\nāœ… robuild finished in ${duration}ms`);
2223
+ if (config.onSuccess) {
2224
+ const buildResult = createBuildResult([], startTime);
2225
+ await executeOnSuccess(config.onSuccess, buildResult, ctx.pkgDir);
2226
+ }
2227
+ }
2228
+ function normalizePath(path, resolveFrom) {
2229
+ return typeof path === "string" && isAbsolute(path) ? path : path instanceof URL ? fileURLToPath(path) : resolve(resolveFrom || ".", path || ".");
2230
+ }
2231
+ /**
2232
+ * Build workspace packages
2233
+ */
2234
+ async function buildWorkspace(config, workspaceRoot) {
2235
+ logger.info("šŸ¢ Building workspace packages...");
2236
+ const workspaceConfig = await loadWorkspaceConfig(workspaceRoot);
2237
+ if (!workspaceConfig) throw new Error("No workspace configuration found");
2238
+ const allPackages = await discoverWorkspacePackages(workspaceRoot, workspaceConfig.packages);
2239
+ if (allPackages.length === 0) {
2240
+ logger.warn("No packages found in workspace");
2241
+ return;
2242
+ }
2243
+ const filteredPackages = filterWorkspacePackages(allPackages, config.filter || config.workspace?.filter, config.workspace?.exclude);
2244
+ if (filteredPackages.length === 0) {
2245
+ logger.warn("No packages match the filter criteria");
2246
+ return;
2247
+ }
2248
+ logger.info(`Building ${filteredPackages.length} packages`);
2249
+ const buildPackage = async (pkg) => {
2250
+ logger.info(`šŸ“¦ Building ${pkg.name}...`);
2251
+ try {
2252
+ const packageConfig = {
2253
+ ...config,
2254
+ cwd: pkg.path,
2255
+ workspace: void 0
2256
+ };
2257
+ await build(packageConfig);
2258
+ if (config.exports?.enabled) {
2259
+ const exportsConfig = {
2260
+ enabled: true,
2261
+ ...config.exports
2262
+ };
2263
+ const exports = await generatePackageExports(pkg.path, packageConfig, exportsConfig);
2264
+ if (config.exports.autoUpdate) {
2265
+ await updatePackageJsonExports(pkg.path, exports);
2266
+ logger.info(`Updated exports for ${pkg.name}`);
2267
+ }
2268
+ }
2269
+ logger.success(`Built ${pkg.name}`);
2270
+ } catch (error) {
2271
+ logger.error(`Failed to build ${pkg.name}:`, error);
2272
+ throw error;
2273
+ }
2274
+ };
2275
+ await buildWorkspacePackages(filteredPackages, buildPackage);
2276
+ logger.success(`Successfully built ${filteredPackages.length} packages`);
2277
+ }
2278
+ function readJSON(specifier) {
2279
+ return import(specifier, { with: { type: "json" } }).then((r) => r.default);
2280
+ }
2281
+
2282
+ //#endregion
2283
+ export { build };