@adddog/build-configs 0.0.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.
@@ -0,0 +1,832 @@
1
+ #!/usr/bin/env node
2
+ import { cac } from 'cac';
3
+ import { consola } from 'consola';
4
+ import pc from 'picocolors';
5
+ import { execa } from 'execa';
6
+ import { existsSync, writeFileSync } from 'node:fs';
7
+ import { join, resolve } from 'node:path';
8
+ import { readFile, writeFile } from 'node:fs/promises';
9
+ import { createJiti } from 'jiti';
10
+ import { defu } from 'defu';
11
+ import { getPreset, listPresets } from '../presets/index.mjs';
12
+ import { makeTsupConfig } from '../tsup.config.mjs';
13
+ import { makeUnbuildConfig } from '../unbuild.config.mjs';
14
+ import * as p from '@clack/prompts';
15
+ import { z } from 'zod';
16
+ import 'tsup';
17
+ import 'unbuild';
18
+
19
+ const version = "0.0.1";
20
+
21
+ const logger = consola.create({
22
+ formatOptions: {
23
+ colors: true,
24
+ compact: false,
25
+ date: false
26
+ }
27
+ });
28
+ const colors = {
29
+ primary: pc.cyan,
30
+ success: pc.green,
31
+ warning: pc.yellow,
32
+ error: pc.red,
33
+ info: pc.blue,
34
+ dim: pc.dim,
35
+ bold: pc.bold,
36
+ bundler: pc.magenta,
37
+ file: pc.yellow,
38
+ command: pc.green
39
+ };
40
+ function logSuccess(message) {
41
+ logger.success(colors.success(message));
42
+ }
43
+ function logError(message, error) {
44
+ logger.error(colors.error(message));
45
+ if (error) {
46
+ logger.error(colors.dim(error.message));
47
+ if (error.stack) {
48
+ logger.error(colors.dim(error.stack));
49
+ }
50
+ }
51
+ }
52
+ function logBundler(bundler) {
53
+ logger.info(`Using bundler: ${colors.bundler(bundler)}`);
54
+ }
55
+ function logBox(title, content) {
56
+ const maxLength = Math.max(
57
+ title.length,
58
+ ...content.map((line) => line.length)
59
+ );
60
+ const border = "\u2500".repeat(maxLength + 4);
61
+ console.log(colors.primary(`\u250C${border}\u2510`));
62
+ console.log(
63
+ colors.primary(`\u2502 ${colors.bold(title.padEnd(maxLength))} \u2502`)
64
+ );
65
+ console.log(colors.primary(`\u251C${border}\u2524`));
66
+ content.forEach((line) => {
67
+ console.log(colors.primary(`\u2502 ${line.padEnd(maxLength)} \u2502`));
68
+ });
69
+ console.log(colors.primary(`\u2514${border}\u2518`));
70
+ }
71
+
72
+ const CONFIG_FILES = [
73
+ "build.config.ts",
74
+ "build.config.js",
75
+ "build.config.mjs",
76
+ "build.config.cjs",
77
+ "tsup.config.ts",
78
+ "tsup.config.js",
79
+ "tsup.config.mjs",
80
+ ".radbuildrc.ts",
81
+ ".radbuildrc.js",
82
+ ".radbuildrc.json"
83
+ ];
84
+ async function detectBundler(cwd = process.cwd()) {
85
+ for (const file of ["tsup.config.ts", "tsup.config.js", "tsup.config.mjs"]) {
86
+ if (existsSync(join(cwd, file))) {
87
+ return "tsup";
88
+ }
89
+ }
90
+ for (const file of [
91
+ "build.config.ts",
92
+ "build.config.js",
93
+ "build.config.mjs"
94
+ ]) {
95
+ if (existsSync(join(cwd, file))) {
96
+ const configPath = join(cwd, file);
97
+ try {
98
+ const jiti = createJiti(cwd, {
99
+ interopDefault: true
100
+ });
101
+ const config = await jiti.import(configPath);
102
+ if (config.entries || config.rollup || config[0] && config[0].entries) {
103
+ return "unbuild";
104
+ }
105
+ } catch {
106
+ }
107
+ }
108
+ }
109
+ try {
110
+ const pkgPath = join(cwd, "package.json");
111
+ if (existsSync(pkgPath)) {
112
+ const pkg = JSON.parse(await readFile(pkgPath, "utf-8"));
113
+ if (pkg.scripts?.build) {
114
+ if (pkg.scripts.build.includes("tsup")) return "tsup";
115
+ if (pkg.scripts.build.includes("unbuild")) return "unbuild";
116
+ }
117
+ }
118
+ } catch {
119
+ }
120
+ return null;
121
+ }
122
+ async function discoverConfigFile(cwd = process.cwd(), customPath) {
123
+ if (customPath) {
124
+ const fullPath = resolve(cwd, customPath);
125
+ if (existsSync(fullPath)) {
126
+ return fullPath;
127
+ }
128
+ logger.warn(`Custom config file not found: ${customPath}`);
129
+ return null;
130
+ }
131
+ for (const file of CONFIG_FILES) {
132
+ const fullPath = join(cwd, file);
133
+ if (existsSync(fullPath)) {
134
+ return fullPath;
135
+ }
136
+ }
137
+ const pkgPath = join(cwd, "package.json");
138
+ if (existsSync(pkgPath)) {
139
+ try {
140
+ const pkg = JSON.parse(await readFile(pkgPath, "utf-8"));
141
+ if (pkg.radbuild) {
142
+ return pkgPath;
143
+ }
144
+ } catch {
145
+ }
146
+ }
147
+ return null;
148
+ }
149
+ async function loadConfigFile(configPath, cwd = process.cwd()) {
150
+ try {
151
+ if (configPath.endsWith("package.json")) {
152
+ const pkg = JSON.parse(await readFile(configPath, "utf-8"));
153
+ return pkg.radbuild || null;
154
+ }
155
+ if (configPath.endsWith(".json")) {
156
+ return JSON.parse(await readFile(configPath, "utf-8"));
157
+ }
158
+ const jiti = createJiti(cwd, {
159
+ interopDefault: true
160
+ });
161
+ const config = await jiti.import(configPath);
162
+ return config;
163
+ } catch (error) {
164
+ logger.error(
165
+ `Failed to load config from ${configPath}`,
166
+ error
167
+ );
168
+ return null;
169
+ }
170
+ }
171
+ async function loadConfig(options) {
172
+ const cwd = options.cwd ?? process.cwd();
173
+ let bundler = options.bundler === "auto" ? null : options.bundler;
174
+ if (!bundler) {
175
+ bundler = await detectBundler(cwd) ?? "unbuild";
176
+ }
177
+ let presetConfig = {};
178
+ if (options.preset) {
179
+ const preset = getPreset(options.preset);
180
+ if (preset) {
181
+ presetConfig = bundler === "tsup" ? preset.tsup ?? {} : preset.unbuild ?? {};
182
+ logger.info(`Using preset: ${preset.name}`);
183
+ } else {
184
+ logger.warn(`Preset not found: ${options.preset}`);
185
+ }
186
+ }
187
+ const configPath = await discoverConfigFile(cwd, options.configPath);
188
+ let projectConfig = {};
189
+ if (configPath) {
190
+ const loaded = await loadConfigFile(configPath, cwd);
191
+ if (loaded) {
192
+ projectConfig = loaded;
193
+ logger.info(`Loaded config from: ${configPath}`);
194
+ }
195
+ }
196
+ const config = defu(
197
+ options.cliFlags ?? {},
198
+ projectConfig,
199
+ presetConfig,
200
+ {}
201
+ // Default config is applied in the makers
202
+ );
203
+ return {
204
+ config,
205
+ bundler,
206
+ configPath
207
+ };
208
+ }
209
+ async function getPackageJson(cwd = process.cwd()) {
210
+ try {
211
+ const pkgPath = join(cwd, "package.json");
212
+ if (!existsSync(pkgPath)) return null;
213
+ return JSON.parse(await readFile(pkgPath, "utf-8"));
214
+ } catch {
215
+ return null;
216
+ }
217
+ }
218
+ async function updatePackageJson(updates, cwd = process.cwd()) {
219
+ const { writeFile } = await import('node:fs/promises');
220
+ const pkgPath = join(cwd, "package.json");
221
+ const pkg = await getPackageJson(cwd) ?? {};
222
+ const updated = defu(updates, pkg);
223
+ await writeFile(pkgPath, JSON.stringify(updated, null, 2) + "\n");
224
+ }
225
+
226
+ async function buildCommand(entries, options) {
227
+ try {
228
+ logger.start("Building project...");
229
+ const cliFlags = {};
230
+ if (options.format) {
231
+ cliFlags.format = options.format.split(",");
232
+ }
233
+ if (options.minify !== void 0) {
234
+ cliFlags.minify = options.minify;
235
+ }
236
+ if (options.sourcemap !== void 0) {
237
+ cliFlags.sourcemap = options.sourcemap;
238
+ }
239
+ if (options.dts !== void 0) {
240
+ cliFlags.dts = options.dts;
241
+ cliFlags.declaration = options.dts;
242
+ }
243
+ if (options.clean !== void 0) {
244
+ cliFlags.clean = options.clean;
245
+ }
246
+ if (entries.length > 0) {
247
+ cliFlags.entry = entries;
248
+ cliFlags.entries = entries;
249
+ }
250
+ const { config, bundler, configPath } = await loadConfig({
251
+ ...options.config && { configPath: options.config },
252
+ ...options.preset && { preset: options.preset },
253
+ bundler: options.bundler ?? "auto",
254
+ cliFlags
255
+ });
256
+ logBundler(bundler);
257
+ const tempConfigPath = join(
258
+ process.cwd(),
259
+ `.rad-build-temp.${bundler === "tsup" ? "tsup" : "build"}.config.js`
260
+ );
261
+ try {
262
+ const finalConfig = bundler === "tsup" ? makeTsupConfig(config) : makeUnbuildConfig(config);
263
+ const configContent = `export default ${JSON.stringify(finalConfig, null, 2)}`;
264
+ writeFileSync(tempConfigPath, configContent);
265
+ if (bundler === "tsup") {
266
+ await execa(
267
+ "tsup",
268
+ [
269
+ "--config",
270
+ tempConfigPath,
271
+ ...options.watch ? ["--watch"] : []
272
+ ],
273
+ {
274
+ stdio: "inherit",
275
+ cwd: process.cwd()
276
+ }
277
+ );
278
+ } else {
279
+ await execa(
280
+ "unbuild",
281
+ [
282
+ ...options.watch ? ["--watch"] : [],
283
+ ...configPath ? [] : ["--config", tempConfigPath]
284
+ ],
285
+ {
286
+ stdio: "inherit",
287
+ cwd: process.cwd()
288
+ }
289
+ );
290
+ }
291
+ logSuccess("Build completed successfully!");
292
+ } finally {
293
+ if (existsSync(tempConfigPath)) {
294
+ try {
295
+ const { unlinkSync } = await import('node:fs');
296
+ unlinkSync(tempConfigPath);
297
+ } catch {
298
+ }
299
+ }
300
+ }
301
+ } catch (error) {
302
+ logError("Build failed", error);
303
+ process.exit(1);
304
+ }
305
+ }
306
+
307
+ function generateTsupConfig(options = {}) {
308
+ const config = {
309
+ entry: options.entry ?? ["src/index.ts"],
310
+ format: options.format ?? ["esm", "cjs"],
311
+ dts: options.dts ?? true,
312
+ sourcemap: options.sourcemap ?? true,
313
+ clean: options.clean ?? true,
314
+ ...options
315
+ };
316
+ return `import { makeTsupConfig } from "@adddog/build-configs/tsup";
317
+
318
+ export default makeTsupConfig(${JSON.stringify(config, null, 2)});
319
+ `;
320
+ }
321
+ function generateUnbuildConfig(options = {}) {
322
+ const config = {
323
+ entries: options.entries ?? ["src/index"],
324
+ declaration: options.declaration ?? true,
325
+ rollup: {
326
+ emitCJS: options.rollup?.emitCJS ?? false,
327
+ ...options.rollup
328
+ },
329
+ ...options
330
+ };
331
+ return `import { makeUnbuildConfig } from "@adddog/build-configs/unbuild";
332
+
333
+ export default makeUnbuildConfig(${JSON.stringify(config, null, 2)});
334
+ `;
335
+ }
336
+ function generatePackageJsonScripts(bundler) {
337
+ const buildCommand = bundler === "tsup" ? "tsup" : "unbuild";
338
+ const watchCommand = bundler === "tsup" ? "tsup --watch" : "unbuild --watch";
339
+ return {
340
+ build: buildCommand,
341
+ "build:watch": watchCommand,
342
+ prepublishOnly: "pnpm build"
343
+ };
344
+ }
345
+ function generatePackageJsonExports(_bundler, formats) {
346
+ const hasESM = formats.includes("esm");
347
+ const hasCJS = formats.includes("cjs");
348
+ if (hasESM && hasCJS) {
349
+ return {
350
+ ".": {
351
+ types: "./dist/index.d.ts",
352
+ import: "./dist/index.mjs",
353
+ require: "./dist/index.cjs"
354
+ }
355
+ };
356
+ } else if (hasESM) {
357
+ return {
358
+ ".": {
359
+ types: "./dist/index.d.ts",
360
+ import: "./dist/index.mjs"
361
+ }
362
+ };
363
+ } else {
364
+ return {
365
+ ".": {
366
+ types: "./dist/index.d.ts",
367
+ require: "./dist/index.cjs"
368
+ }
369
+ };
370
+ }
371
+ }
372
+
373
+ async function initCommand(options) {
374
+ try {
375
+ p.intro(colors.bold("Welcome to @adddog/build-configs!"));
376
+ const tsupConfigExists = existsSync("tsup.config.ts");
377
+ const buildConfigExists = existsSync("build.config.ts");
378
+ if ((tsupConfigExists || buildConfigExists) && !options.force) {
379
+ const shouldOverwrite = await p.confirm({
380
+ message: "Config file already exists. Overwrite?",
381
+ initialValue: false
382
+ });
383
+ if (p.isCancel(shouldOverwrite) || !shouldOverwrite) {
384
+ p.cancel("Operation cancelled");
385
+ process.exit(0);
386
+ }
387
+ }
388
+ const bundler = options.bundler ?? await p.select({
389
+ message: "Which bundler do you prefer?",
390
+ options: [
391
+ {
392
+ value: "unbuild",
393
+ label: "unbuild",
394
+ hint: "Preserves file structure, better for libraries"
395
+ },
396
+ {
397
+ value: "tsup",
398
+ label: "tsup",
399
+ hint: "Faster builds, bundles everything"
400
+ }
401
+ ]
402
+ });
403
+ if (p.isCancel(bundler)) {
404
+ p.cancel("Operation cancelled");
405
+ process.exit(0);
406
+ }
407
+ const usePreset = await p.select({
408
+ message: "Start with a preset or custom config?",
409
+ options: [
410
+ { value: "preset", label: "Use a preset" },
411
+ { value: "custom", label: "Custom configuration" }
412
+ ]
413
+ });
414
+ if (p.isCancel(usePreset)) {
415
+ p.cancel("Operation cancelled");
416
+ process.exit(0);
417
+ }
418
+ let selectedPreset;
419
+ let finalConfig = {};
420
+ if (usePreset === "preset") {
421
+ const availablePresets = listPresets().filter((name) => {
422
+ const preset2 = getPreset(name);
423
+ return preset2 && (preset2.bundler === bundler || preset2.bundler === "both");
424
+ });
425
+ const presetChoice = await p.select({
426
+ message: "Select a preset:",
427
+ options: availablePresets.map((name) => {
428
+ const preset2 = getPreset(name);
429
+ return {
430
+ value: name,
431
+ label: name,
432
+ hint: preset2.description
433
+ };
434
+ })
435
+ });
436
+ selectedPreset = String(presetChoice);
437
+ if (p.isCancel(selectedPreset)) {
438
+ p.cancel("Operation cancelled");
439
+ process.exit(0);
440
+ }
441
+ const preset = getPreset(selectedPreset);
442
+ if (preset) {
443
+ finalConfig = bundler === "tsup" ? preset.tsup ?? {} : preset.unbuild ?? {};
444
+ }
445
+ } else {
446
+ const formats = await p.multiselect({
447
+ message: "Output formats?",
448
+ options: [
449
+ { value: "esm", label: "ESM (modern)" },
450
+ { value: "cjs", label: "CommonJS (compatibility)" },
451
+ ...bundler === "tsup" ? [{ value: "iife", label: "IIFE (browser global)" }] : []
452
+ ],
453
+ initialValues: ["esm"],
454
+ required: true
455
+ });
456
+ if (p.isCancel(formats)) {
457
+ p.cancel("Operation cancelled");
458
+ process.exit(0);
459
+ }
460
+ const features = await p.multiselect({
461
+ message: "Additional features?",
462
+ options: [
463
+ { value: "sourcemaps", label: "Generate sourcemaps" },
464
+ { value: "minify", label: "Minify output" },
465
+ { value: "declarations", label: "TypeScript declarations" }
466
+ ],
467
+ initialValues: ["sourcemaps", "declarations"]
468
+ });
469
+ if (p.isCancel(features)) {
470
+ p.cancel("Operation cancelled");
471
+ process.exit(0);
472
+ }
473
+ finalConfig = {
474
+ format: formats,
475
+ sourcemap: features.includes("sourcemaps"),
476
+ minify: features.includes("minify")
477
+ };
478
+ if (bundler === "tsup") {
479
+ finalConfig.dts = features.includes("declarations");
480
+ } else {
481
+ finalConfig.declaration = features.includes(
482
+ "declarations"
483
+ );
484
+ finalConfig.rollup = {
485
+ emitCJS: formats.includes("cjs")
486
+ };
487
+ }
488
+ }
489
+ const spinner = p.spinner();
490
+ spinner.start("Creating configuration files...");
491
+ try {
492
+ const configFileName = bundler === "tsup" ? "tsup.config.ts" : "build.config.ts";
493
+ const configContent = bundler === "tsup" ? generateTsupConfig(finalConfig) : generateUnbuildConfig(finalConfig);
494
+ await writeFile(join(process.cwd(), configFileName), configContent);
495
+ const pkg = await getPackageJson();
496
+ if (pkg) {
497
+ const scripts = generatePackageJsonScripts(bundler);
498
+ const exports = generatePackageJsonExports(
499
+ bundler,
500
+ finalConfig.format ?? ["esm", "cjs"]
501
+ );
502
+ await updatePackageJson({
503
+ scripts: { ...pkg.scripts, ...scripts },
504
+ exports,
505
+ main: finalConfig.format?.includes("cjs") || finalConfig.rollup?.emitCJS ? "./dist/index.cjs" : void 0,
506
+ module: "./dist/index.mjs",
507
+ types: "./dist/index.d.ts",
508
+ files: ["dist"]
509
+ });
510
+ }
511
+ spinner.stop("Configuration created successfully!");
512
+ p.outro(
513
+ colors.success(`
514
+ Next steps:
515
+ 1. ${colors.command("pnpm install")} - Install dependencies
516
+ 2. ${colors.command("pnpm build")} - Build your project
517
+ 3. Edit ${colors.file(configFileName)} to customize
518
+
519
+ ${selectedPreset ? `Using preset: ${colors.primary(selectedPreset)}` : ""}
520
+
521
+ Happy building! \u{1F680}
522
+ `)
523
+ );
524
+ } catch (error) {
525
+ spinner.stop("Failed to create configuration");
526
+ throw error;
527
+ }
528
+ } catch (error) {
529
+ logError("Initialization failed", error);
530
+ process.exit(1);
531
+ }
532
+ }
533
+
534
+ const TsupFormatSchema = z.enum(["cjs", "esm", "iife"]);
535
+ const TsupPlatformSchema = z.enum(["node", "browser", "neutral"]);
536
+ const TsupDtsSchema = z.union([
537
+ z.boolean(),
538
+ z.string(),
539
+ z.object({
540
+ entry: z.any().optional(),
541
+ resolve: z.union([z.boolean(), z.array(z.union([z.string(), z.instanceof(RegExp)]))]).optional(),
542
+ only: z.boolean().optional(),
543
+ banner: z.string().optional(),
544
+ footer: z.string().optional(),
545
+ compilerOptions: z.any().optional()
546
+ })
547
+ ]);
548
+ const TsupEntrySchema = z.union([
549
+ z.array(z.string()),
550
+ z.record(z.string(), z.string())
551
+ ]);
552
+ const TsupConfigSchema = z.object({
553
+ name: z.string().optional(),
554
+ entry: TsupEntrySchema.optional(),
555
+ entryPoints: TsupEntrySchema.optional(),
556
+ format: z.union([TsupFormatSchema, z.array(TsupFormatSchema)]).optional(),
557
+ outDir: z.string().optional(),
558
+ target: z.union([z.string(), z.array(z.string())]).optional(),
559
+ platform: TsupPlatformSchema.optional(),
560
+ dts: TsupDtsSchema.optional(),
561
+ experimentalDts: z.union([
562
+ z.boolean(),
563
+ z.string(),
564
+ z.object({
565
+ entry: z.any().optional(),
566
+ compilerOptions: z.any().optional()
567
+ })
568
+ ]).optional(),
569
+ sourcemap: z.union([z.boolean(), z.literal("inline")]).optional(),
570
+ minify: z.union([z.boolean(), z.literal("terser")]).optional(),
571
+ bundle: z.boolean().optional(),
572
+ splitting: z.boolean().optional(),
573
+ clean: z.union([z.boolean(), z.array(z.string())]).optional(),
574
+ treeshake: z.any().optional(),
575
+ external: z.array(z.union([z.string(), z.instanceof(RegExp)])).optional(),
576
+ noExternal: z.array(z.union([z.string(), z.instanceof(RegExp)])).optional(),
577
+ skipNodeModulesBundle: z.boolean().optional(),
578
+ keepNames: z.boolean().optional(),
579
+ watch: z.union([z.boolean(), z.string(), z.array(z.union([z.string(), z.boolean()]))]).optional(),
580
+ ignoreWatch: z.union([z.array(z.string()), z.string()]).optional(),
581
+ tsconfig: z.string().optional(),
582
+ shims: z.boolean().optional(),
583
+ cjsInterop: z.boolean().optional(),
584
+ removeNodeProtocol: z.boolean().optional()
585
+ });
586
+ const UnbuildBuilderSchema = z.enum(["rollup", "mkdist", "copy", "untyped"]);
587
+ const UnbuildDeclarationSchema = z.union([
588
+ z.boolean(),
589
+ z.literal("compatible"),
590
+ z.literal("node16")
591
+ ]);
592
+ const UnbuildEntrySchema = z.union([
593
+ z.string(),
594
+ z.object({
595
+ builder: UnbuildBuilderSchema.optional(),
596
+ input: z.string(),
597
+ name: z.string().optional(),
598
+ outDir: z.string().optional(),
599
+ declaration: UnbuildDeclarationSchema.optional(),
600
+ format: z.enum(["esm", "cjs"]).optional(),
601
+ ext: z.string().optional()
602
+ })
603
+ ]);
604
+ const UnbuildConfigSchema = z.object({
605
+ name: z.string().optional(),
606
+ rootDir: z.string().optional(),
607
+ entries: z.array(UnbuildEntrySchema).optional(),
608
+ outDir: z.string().optional(),
609
+ clean: z.boolean().optional(),
610
+ declaration: UnbuildDeclarationSchema.optional(),
611
+ sourcemap: z.boolean().optional(),
612
+ stub: z.boolean().optional(),
613
+ watch: z.boolean().optional(),
614
+ parallel: z.boolean().optional(),
615
+ externals: z.array(z.union([z.string(), z.instanceof(RegExp)])).optional(),
616
+ alias: z.record(z.string(), z.string()).optional(),
617
+ replace: z.record(z.string(), z.string()).optional(),
618
+ failOnWarn: z.boolean().optional(),
619
+ rollup: z.object({
620
+ emitCJS: z.boolean().optional(),
621
+ cjsBridge: z.boolean().optional(),
622
+ preserveDynamicImports: z.boolean().optional(),
623
+ inlineDependencies: z.union([z.boolean(), z.array(z.union([z.string(), z.instanceof(RegExp)]))]).optional()
624
+ }).optional()
625
+ });
626
+ function validateTsupConfig(config) {
627
+ return TsupConfigSchema.safeParse(config);
628
+ }
629
+ function validateUnbuildConfig(config) {
630
+ return UnbuildConfigSchema.safeParse(config);
631
+ }
632
+ function validateConfig(config, bundler) {
633
+ if (bundler === "tsup") {
634
+ return validateTsupConfig(config);
635
+ }
636
+ return validateUnbuildConfig(config);
637
+ }
638
+
639
+ async function validateCommand(options) {
640
+ try {
641
+ logger.start("Validating configuration...");
642
+ const configPath = await discoverConfigFile(
643
+ process.cwd(),
644
+ options.config
645
+ );
646
+ if (!configPath) {
647
+ logError("No configuration file found");
648
+ logger.info("Run 'rad-build init' to create a configuration file");
649
+ process.exit(1);
650
+ }
651
+ logger.info(`Found config: ${colors.file(configPath)}`);
652
+ const { config, bundler } = await loadConfig({
653
+ ...options.config && { configPath: options.config },
654
+ bundler: options.bundler ?? "auto"
655
+ });
656
+ logger.info(`Detected bundler: ${colors.bundler(bundler)}`);
657
+ const result = validateConfig(config, bundler);
658
+ if (result.success) {
659
+ logSuccess("\u2713 Configuration is valid!");
660
+ logger.info("\nConfiguration summary:");
661
+ if (bundler === "tsup") {
662
+ const tsupConfig = config;
663
+ logger.info(` Entry: ${JSON.stringify(tsupConfig.entry ?? ["src/index.ts"])}`);
664
+ logger.info(` Format: ${JSON.stringify(tsupConfig.format ?? ["esm", "cjs"])}`);
665
+ logger.info(` DTS: ${tsupConfig.dts !== false ? "enabled" : "disabled"}`);
666
+ logger.info(
667
+ ` Sourcemap: ${tsupConfig.sourcemap !== false ? "enabled" : "disabled"}`
668
+ );
669
+ } else {
670
+ const unbuildConfig = config;
671
+ logger.info(
672
+ ` Entries: ${JSON.stringify(unbuildConfig.entries ?? ["src/index"])}`
673
+ );
674
+ logger.info(
675
+ ` Declaration: ${unbuildConfig.declaration !== false ? "enabled" : "disabled"}`
676
+ );
677
+ logger.info(
678
+ ` CJS: ${unbuildConfig.rollup?.emitCJS ? "enabled" : "disabled"}`
679
+ );
680
+ }
681
+ } else {
682
+ logError("\u2717 Configuration validation failed");
683
+ if (result.error) {
684
+ logger.error("\nValidation errors:");
685
+ result.error.errors.forEach((err) => {
686
+ logger.error(` ${colors.error("\u2022")} ${err.path.join(".")}: ${err.message}`);
687
+ });
688
+ }
689
+ process.exit(1);
690
+ }
691
+ } catch (error) {
692
+ logError("Validation failed", error);
693
+ process.exit(1);
694
+ }
695
+ }
696
+
697
+ async function infoCommand(options) {
698
+ try {
699
+ logger.start("Gathering project information...\n");
700
+ const pkg = await getPackageJson();
701
+ const projectName = pkg?.name ?? "unknown";
702
+ const projectVersion = pkg?.version ?? "0.0.0";
703
+ const configPath = await discoverConfigFile(
704
+ process.cwd(),
705
+ options.config
706
+ );
707
+ let bundler = "none";
708
+ let config = {};
709
+ if (configPath) {
710
+ const loaded = await loadConfig({
711
+ ...options.config && { configPath: options.config },
712
+ bundler: "auto"
713
+ });
714
+ bundler = loaded.bundler;
715
+ config = loaded.config;
716
+ }
717
+ logBox("Project Information", [
718
+ `Name: ${colors.primary(projectName)}`,
719
+ `Version: ${colors.primary(projectVersion)}`,
720
+ `Config: ${configPath ? colors.file(configPath) : colors.dim("not found")}`,
721
+ `Bundler: ${bundler !== "none" ? colors.bundler(bundler) : colors.dim("not configured")}`
722
+ ]);
723
+ if (bundler !== "none") {
724
+ console.log("\n" + colors.bold("Build Configuration:"));
725
+ if (bundler === "tsup") {
726
+ const tsupConfig = config;
727
+ console.log(colors.dim("\u251C\u2500") + " Entry: " + JSON.stringify(tsupConfig.entry ?? ["src/index.ts"]));
728
+ console.log(colors.dim("\u251C\u2500") + " Format: " + JSON.stringify(tsupConfig.format ?? ["esm", "cjs"]));
729
+ console.log(
730
+ colors.dim("\u251C\u2500") + " Target: " + (tsupConfig.target ?? "node18")
731
+ );
732
+ console.log(
733
+ colors.dim("\u251C\u2500") + " Platform: " + (tsupConfig.platform ?? "node")
734
+ );
735
+ console.log(
736
+ colors.dim("\u251C\u2500") + " DTS: " + (tsupConfig.dts !== false ? colors.success("\u2713") : colors.dim("\u2717"))
737
+ );
738
+ console.log(
739
+ colors.dim("\u251C\u2500") + " Sourcemap: " + (tsupConfig.sourcemap !== false ? colors.success("\u2713") : colors.dim("\u2717"))
740
+ );
741
+ console.log(
742
+ colors.dim("\u251C\u2500") + " Minify: " + (tsupConfig.minify ? colors.success("\u2713") : colors.dim("\u2717"))
743
+ );
744
+ console.log(
745
+ colors.dim("\u2514\u2500") + " Clean: " + (tsupConfig.clean !== false ? colors.success("\u2713") : colors.dim("\u2717"))
746
+ );
747
+ } else {
748
+ const unbuildConfig = config;
749
+ console.log(
750
+ colors.dim("\u251C\u2500") + " Entries: " + JSON.stringify(unbuildConfig.entries ?? ["src/index"])
751
+ );
752
+ console.log(
753
+ colors.dim("\u251C\u2500") + " Out Dir: " + (unbuildConfig.outDir ?? "dist")
754
+ );
755
+ console.log(
756
+ colors.dim("\u251C\u2500") + " Declaration: " + (unbuildConfig.declaration !== false ? colors.success("\u2713") : colors.dim("\u2717"))
757
+ );
758
+ console.log(
759
+ colors.dim("\u251C\u2500") + " Emit CJS: " + (unbuildConfig.rollup?.emitCJS ? colors.success("\u2713") : colors.dim("\u2717"))
760
+ );
761
+ console.log(
762
+ colors.dim("\u251C\u2500") + " Sourcemap: " + (unbuildConfig.sourcemap ? colors.success("\u2713") : colors.dim("\u2717"))
763
+ );
764
+ console.log(
765
+ colors.dim("\u251C\u2500") + " Parallel: " + (unbuildConfig.parallel !== false ? colors.success("\u2713") : colors.dim("\u2717"))
766
+ );
767
+ console.log(
768
+ colors.dim("\u2514\u2500") + " Clean: " + (unbuildConfig.clean !== false ? colors.success("\u2713") : colors.dim("\u2717"))
769
+ );
770
+ }
771
+ }
772
+ if (pkg?.exports) {
773
+ console.log("\n" + colors.bold("Package Exports:"));
774
+ console.log(JSON.stringify(pkg.exports, null, 2));
775
+ }
776
+ if (pkg?.scripts) {
777
+ const buildScripts = Object.entries(pkg.scripts).filter(
778
+ ([key]) => key.includes("build") || key.includes("watch")
779
+ );
780
+ if (buildScripts.length > 0) {
781
+ console.log("\n" + colors.bold("Build Scripts:"));
782
+ buildScripts.forEach(([name, script]) => {
783
+ console.log(` ${colors.command(name.padEnd(20))} ${colors.dim(script)}`);
784
+ });
785
+ }
786
+ }
787
+ if (bundler === "none") {
788
+ console.log("\n" + colors.warning("\u26A0 No build configuration found"));
789
+ console.log(
790
+ colors.info("\nRun ") + colors.command("rad-build init") + colors.info(" to set up your project")
791
+ );
792
+ }
793
+ } catch (error) {
794
+ logger.error("Failed to gather information", error);
795
+ process.exit(1);
796
+ }
797
+ }
798
+
799
+ async function watchCommand(options) {
800
+ logger.info("Starting watch mode...");
801
+ await buildCommand([], {
802
+ ...options,
803
+ watch: true
804
+ });
805
+ }
806
+
807
+ const cli = cac("rad-build");
808
+ cli.version(version).help();
809
+ cli.command("[...entries]", "Build your project").option("--config <path>", "Path to config file").option("--preset <name>", "Use a preset configuration").option("--bundler <bundler>", "Specify bundler: tsup or unbuild").option("--format <formats>", "Output formats (comma-separated)").option("--minify", "Minify output").option("--watch", "Watch mode").option("--sourcemap", "Generate sourcemaps").option("--dts", "Generate TypeScript declarations").option("--clean", "Clean output directory before build").action(buildCommand);
810
+ cli.command("init", "Initialize build configuration").option("--bundler <bundler>", "Specify bundler: tsup or unbuild").option("--preset <name>", "Use a preset configuration").option("--force", "Overwrite existing config").action(initCommand);
811
+ cli.command("validate", "Validate build configuration").option("--config <path>", "Path to config file").option("--bundler <bundler>", "Specify bundler: tsup or unbuild").action(validateCommand);
812
+ cli.command("info", "Show build configuration and environment info").option("--config <path>", "Path to config file").action(infoCommand);
813
+ cli.command("watch", "Watch and rebuild on file changes").option("--config <path>", "Path to config file").option("--preset <name>", "Use a preset configuration").option("--bundler <bundler>", "Specify bundler: tsup or unbuild").action(watchCommand);
814
+ cli.command("list-presets", "List all available presets").action(async () => {
815
+ const { presetCategories } = await import('../presets/index.mjs');
816
+ logBox("Available Presets", [
817
+ "",
818
+ ...Object.entries(presetCategories).flatMap(([category, presets]) => [
819
+ colors.bold(category.toUpperCase()),
820
+ ...Object.entries(presets).map(
821
+ ([name, preset]) => ` ${colors.primary(name.padEnd(25))} - ${colors.dim(preset.description)}`
822
+ ),
823
+ ""
824
+ ])
825
+ ]);
826
+ });
827
+ cli.parse();
828
+ process.on("unhandledRejection", (error) => {
829
+ logger.error("Unhandled error:", error);
830
+ process.exit(1);
831
+ });
832
+ //# sourceMappingURL=index.mjs.map