bunup 0.14.20 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  build,
5
5
  processLoadedConfigs,
6
6
  resolveBuildOptions
7
- } from "../shared/bunup-rqsmf79e.js";
7
+ } from "../shared/bunup-04me8aq6.js";
8
8
  import {
9
9
  BunupCLIError,
10
10
  BunupWatchError,
@@ -20,13 +20,13 @@ import {
20
20
  logTime,
21
21
  logger,
22
22
  parseErrorMessage
23
- } from "../shared/bunup-8meww5p0.js";
23
+ } from "../shared/bunup-wssv441a.js";
24
24
 
25
25
  // packages/bunup/src/cli/index.ts
26
26
  import { loadConfig } from "coffi";
27
27
  import pc4 from "picocolors";
28
28
  // packages/bunup/package.json
29
- var version = "0.14.20";
29
+ var version = "0.15.0";
30
30
 
31
31
  // packages/bunup/src/printer/print-build-report.ts
32
32
  import { promisify } from "util";
@@ -39,13 +39,13 @@ async function printBuildReport(buildOutput) {
39
39
  const showCompression = gzip || brotli;
40
40
  const files = await Promise.all(buildOutput.files.map(async (file) => {
41
41
  const pathRelative = file.pathRelativeToOutdir;
42
- const bunFile = Bun.file(file.fullPath);
43
- const size = bunFile.size;
42
+ const size = file.size;
44
43
  const isDts = file.dts && file.kind === "entry-point";
45
44
  const isJs = isTypeScriptFile(file.fullPath) || isJavascriptFile(file.fullPath);
46
45
  let gzipSize;
47
46
  let brotliSize;
48
47
  if (showCompression) {
48
+ const bunFile = Bun.file(file.fullPath);
49
49
  const uint8 = new Uint8Array(await bunFile.arrayBuffer());
50
50
  const [gzipResult, brotliResult] = await Promise.all([
51
51
  gzip ? Promise.resolve(Bun.gzipSync(uint8)) : Promise.resolve(null),
@@ -208,7 +208,8 @@ async function watch(userOptions, rootDir, configFilePath) {
208
208
  watcher.on("change", (changedPath) => {
209
209
  if (configFilePath && changedPath === configFilePath) {
210
210
  console.log(pc2.yellow(`
211
- Please restart watch mode to apply configuration changes.`));
211
+ Please restart watch mode to apply configuration changes.
212
+ `));
212
213
  cleanup();
213
214
  return;
214
215
  }
@@ -249,8 +250,9 @@ var program = cli().name("bunup").version(version).description("A blazing-fast b
249
250
  entry: z.union(z.string().describe("Single entrypoint for declaration file generation"), z.array(z.string()).describe("Multiple entrypoints for declaration file generation")).optional(),
250
251
  resolve: z.union(z.boolean().describe("Resolve types from dependencies"), z.array(z.string()).describe("Names or patterns of packages from which to resolve types")).optional(),
251
252
  splitting: z.boolean().describe("Enable declaration file splitting").optional(),
252
- minify: z.boolean().describe("Minify generated declaration files").optional()
253
- })).default(true)).option("preferred-tsconfig-path", z.string().describe("Path to preferred tsconfig.json for declaration generation").example("./tsconfig.build.json").optional()).option("sourcemap", z.union(z.boolean().describe("Generate a sourcemap (uses the inline type by default)"), z.string().choices(["none", "linked", "inline", "external"]).describe("Generate a sourcemap with a specific type")).optional()).option("define", z.object(z.string()).describe("Define global constants replaced at build time").example(`--define.PACKAGE_VERSION='"1.0.0"'`).optional()).option("env", z.union(z.string().choices(["inline", "disable"]).describe("inline: inject all, disable: inject none"), z.string().regex(/\*$/, "Environment prefix must end with *").describe("Inject env vars with this prefix").example("MYAPP_*").transform((val) => val), z.object(z.string()).describe("Explicit env var mapping").example('--env.NODE_ENV="production" --env.API_URL="https://api.example.com"')).optional()).option("banner", z.string().describe("Banner text added to the top of bundle files").optional()).option("footer", z.string().describe("Footer text added to the bottom of bundle files").optional()).option("drop", z.array(z.string()).describe("Remove function calls from bundle").example("--drop console,debugger").optional()).option("loader", z.object(z.string().choices([
253
+ minify: z.boolean().describe("Minify generated declaration files").optional(),
254
+ "infer-types": z.boolean().describe("Use typescript native compiler for declarations generation (removes need for explicit type annotations)").optional()
255
+ })).default(true)).option("preferred-tsconfig", z.string().describe("Path to a custom tsconfig.json file used for path resolution during both bundling and TypeScript declaration generation.").example("./tsconfig.build.json").optional()).option("sourcemap", z.union(z.boolean().describe("Generate a sourcemap (uses the inline type by default)"), z.string().choices(["none", "linked", "inline", "external"]).describe("Generate a sourcemap with a specific type")).optional()).option("define", z.object(z.string()).describe("Define global constants replaced at build time").example(`--define.PACKAGE_VERSION='"1.0.0"'`).optional()).option("env", z.union(z.string().choices(["inline", "disable"]).describe("inline: inject all, disable: inject none"), z.string().regex(/\*$/, "Environment prefix must end with *").describe("Inject env vars with this prefix").example("MYAPP_*").transform((val) => val), z.object(z.string()).describe("Explicit env var mapping").example('--env.NODE_ENV="production" --env.API_URL="https://api.example.com"')).optional()).option("banner", z.string().describe("Banner text added to the top of bundle files").optional()).option("footer", z.string().describe("Footer text added to the bottom of bundle files").optional()).option("drop", z.array(z.string()).describe("Remove function calls from bundle").example("--drop console,debugger").optional()).option("loader", z.object(z.string().choices([
254
256
  "js",
255
257
  "jsx",
256
258
  "ts",
@@ -276,9 +278,9 @@ var program = cli().name("bunup").version(version).description("A blazing-fast b
276
278
  "include-package-json": z.boolean().describe('Whether to include "./package.json" in exports field').default(true),
277
279
  all: z.boolean().describe("Whether to add wildcard export for deep imports").optional()
278
280
  })).describe("Configure automatic package.json exports generation").optional()).option("unused", z.union(z.boolean(), z.object({
279
- level: z.string().choices(["warn", "error"]).describe("The level of reporting for unused dependencies").default("warn"),
280
- ignore: z.array(z.string()).describe("Dependencies to ignore when checking for unused dependencies").optional()
281
- })).describe("Detect and report unused dependencies").optional()).option("css", z.object({
281
+ level: z.string().choices(["warn", "error"]).describe("The level of reporting for unused or incorrectly categorized dependencies").default("warn"),
282
+ ignore: z.array(z.string()).describe("Dependencies to ignore when checking").optional()
283
+ })).describe("Detect unused or incorrectly categorized dependencies").optional()).option("css", z.object({
282
284
  "typed-modules": z.boolean().describe("Generate TypeScript definitions for CSS modules").default(true),
283
285
  inject: z.union(z.boolean(), z.object({
284
286
  minify: z.boolean().describe("Whether to minify the styles being injected").optional()
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Arrayable, BuildContext, BuildMeta, BuildOptions, BuildOutput, BuildOutputFile, BunupPlugin, DefineConfigItem, DefineWorkspaceItem, WithOptional } from "./shared/bunup-zqdmwaar";
1
+ import { BuildContext, BuildMeta, BuildOptions, BuildOutput, BuildOutputFile, BunupPlugin, DefineConfigItem, DefineWorkspaceItem, WithOptional, WithRequired } from "./shared/bunup-0wvve78m";
2
2
  declare function build(userOptions: Partial<BuildOptions>, rootDir?: string): Promise<BuildOutput>;
3
- declare function defineConfig(options: Arrayable<DefineConfigItem>): Arrayable<DefineConfigItem>;
3
+ declare function defineConfig(options: DefineConfigItem | WithRequired<DefineConfigItem, "name">[]): DefineConfigItem | WithRequired<DefineConfigItem, "name">[];
4
4
  declare function defineWorkspace(options: WithOptional<DefineWorkspaceItem, "config">[], sharedOptions?: Partial<DefineConfigItem>): DefineWorkspaceItem[];
5
5
  export { defineWorkspace, defineConfig, build, DefineWorkspaceItem, DefineConfigItem, BunupPlugin, BuildOutputFile, BuildOutput, BuildOptions, BuildMeta, BuildContext };
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  // @bun
2
2
  import {
3
3
  build
4
- } from "./shared/bunup-rqsmf79e.js";
5
- import"./shared/bunup-8meww5p0.js";
4
+ } from "./shared/bunup-04me8aq6.js";
5
+ import"./shared/bunup-wssv441a.js";
6
6
  // packages/bunup/src/define.ts
7
7
  function defineConfig(options) {
8
8
  return options;
package/dist/plugins.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { BuildOptions, BunupPlugin, BunupPluginHooks, exports, injectStyles, unused } from "./shared/bunup-zqdmwaar";
1
+ import { BuildOptions, BunupPlugin, BunupPluginHooks, exports, injectStyles, unused } from "./shared/bunup-0wvve78m";
2
2
  type CopyOptions = {
3
3
  /** Whether to follow symbolic links when copying files. */
4
4
  followSymlinks?: boolean;
package/dist/plugins.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  logger,
8
8
  shims,
9
9
  unused
10
- } from "./shared/bunup-8meww5p0.js";
10
+ } from "./shared/bunup-wssv441a.js";
11
11
 
12
12
  // packages/bunup/src/plugins/copy.ts
13
13
  import { basename, extname, join } from "path";
@@ -8,28 +8,25 @@ import {
8
8
  ensureArray,
9
9
  ensureObject,
10
10
  exports,
11
+ formatBunBuildError,
12
+ formatInvalidEntryPointsError,
11
13
  formatListWithAnd,
12
- getDefaultDtsOutputExtention,
13
- getDefaultJsOutputExtension,
14
+ formatNoEntryPointsFoundError,
14
15
  getFilesFromGlobs,
15
- getPackageDeps,
16
16
  getShortFilePath,
17
17
  injectStyles,
18
- invalidEntryPointsError,
19
18
  isJavascriptFile,
20
19
  logger,
21
- noEntryPointsFoundError,
22
20
  parseErrorMessage,
23
- replaceExtension,
24
21
  shims,
25
22
  unused
26
- } from "./bunup-8meww5p0.js";
23
+ } from "./bunup-wssv441a.js";
27
24
 
28
25
  // packages/bunup/src/loaders.ts
29
26
  import path from "path";
30
27
  import { loadConfig } from "coffi";
31
28
  async function processLoadedConfigs(config, cwd, filter) {
32
- return Array.isArray(config) && "root" in config[0] ? config.filter((c) => filter ? filter.includes(c.name) : true).map((c) => ({
29
+ return Array.isArray(config) && config[0] && "root" in config[0] ? config.filter((c) => filter ? filter.includes(c.name) : true).map((c) => ({
33
30
  rootDir: path.resolve(cwd, c.root),
34
31
  options: setOrSuffixField(c.config ?? {}, "name", c.name)
35
32
  })) : [
@@ -116,7 +113,7 @@ async function executeOnSuccess(onSuccess, options, signal) {
116
113
  }
117
114
  }
118
115
 
119
- // packages/bunup/src/plugins/internal/css-typed-modules.ts
116
+ // packages/bunup/src/plugins/css-typed-modules.ts
120
117
  import { transform } from "lightningcss";
121
118
  function cssTypedModulesPlugin() {
122
119
  return {
@@ -160,6 +157,16 @@ export default classes;
160
157
  // packages/bunup/src/plugins/internal/external-option.ts
161
158
  import { isBuiltin } from "module";
162
159
 
160
+ // packages/bunup/src/utils/package.ts
161
+ function getPackageDeps(packageJson) {
162
+ if (!packageJson)
163
+ return [];
164
+ return Array.from(new Set([
165
+ ...Object.keys(packageJson.dependencies || {}),
166
+ ...Object.keys(packageJson.peerDependencies || {})
167
+ ]));
168
+ }
169
+
163
170
  // packages/bunup/src/helpers/external.ts
164
171
  function getPackageDepsPatterns(packageJson) {
165
172
  return getPackageDeps(packageJson).map((dep) => new RegExp(`^${dep}($|\\/|\\\\)`));
@@ -339,6 +346,48 @@ async function runPluginBuildDoneHooks(bunupPlugins, options, output, meta) {
339
346
  }
340
347
  }
341
348
 
349
+ // packages/bunup/src/utils/extension.ts
350
+ function getDefaultJsOutputExtension(format, packageType) {
351
+ switch (format) {
352
+ case "esm":
353
+ return isModulePackage(packageType) ? ".js" : ".mjs";
354
+ case "cjs":
355
+ return isModulePackage(packageType) ? ".cjs" : ".js";
356
+ case "iife":
357
+ return ".global.js";
358
+ }
359
+ }
360
+ function getDefaultDtsOutputExtention(format, packageType, kind) {
361
+ if (kind === "chunk")
362
+ return ".d.ts";
363
+ switch (format) {
364
+ case "esm":
365
+ return isModulePackage(packageType) ? ".d.ts" : ".d.mts";
366
+ case "cjs":
367
+ return isModulePackage(packageType) ? ".d.cts" : ".d.ts";
368
+ case "iife":
369
+ return ".global.d.ts";
370
+ }
371
+ }
372
+ function isModulePackage(packageType) {
373
+ return packageType === "module";
374
+ }
375
+ function replaceExtension(filePath, newExtension) {
376
+ if (!filePath) {
377
+ return filePath;
378
+ }
379
+ const normalizedExtension = newExtension.startsWith(".") ? newExtension : `.${newExtension}`;
380
+ const lastSlashIndex = Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\"));
381
+ const directory = lastSlashIndex >= 0 ? filePath.substring(0, lastSlashIndex + 1) : "";
382
+ const filename = lastSlashIndex >= 0 ? filePath.substring(lastSlashIndex + 1) : filePath;
383
+ const lastDotIndex = filename.lastIndexOf(".");
384
+ if (lastDotIndex === -1) {
385
+ return directory + filename + normalizedExtension;
386
+ }
387
+ const nameWithoutExtension = filename.substring(0, lastDotIndex);
388
+ return directory + nameWithoutExtension + normalizedExtension;
389
+ }
390
+
342
391
  // packages/bunup/src/build.ts
343
392
  var ac = null;
344
393
  async function build(userOptions, rootDir = process.cwd()) {
@@ -375,9 +424,9 @@ async function build(userOptions, rootDir = process.cwd()) {
375
424
  const entrypoints = getFilesFromGlobs(entryArray, rootDir);
376
425
  if (!entrypoints.length) {
377
426
  if (!ensureArray(userOptions.entry).length) {
378
- throw new BunupBuildError(noEntryPointsFoundError(DEFAULT_ENTYPOINTS));
427
+ throw new BunupBuildError(formatNoEntryPointsFoundError(DEFAULT_ENTYPOINTS));
379
428
  }
380
- throw new BunupBuildError(invalidEntryPointsError(entryArray));
429
+ throw new BunupBuildError(formatInvalidEntryPointsError(entryArray));
381
430
  }
382
431
  logger.info(`entry: ${formatListWithAnd(entrypoints)}`, {
383
432
  identifier: options.name,
@@ -414,14 +463,17 @@ async function build(userOptions, rootDir = process.cwd()) {
414
463
  emitDCEAnnotations: options.emitDCEAnnotations,
415
464
  jsx: options.jsx,
416
465
  throw: false,
417
- plugins: bunPlugins
466
+ plugins: bunPlugins,
467
+ tsconfig: options.preferredTsconfig ? path2.resolve(rootDir, options.preferredTsconfig) : undefined
418
468
  });
419
469
  for (const log of result.logs) {
420
470
  if (log.level === "error") {
421
- throw new BunupBuildError(log.message);
471
+ throw new BunupBuildError(formatBunBuildError(log));
422
472
  }
423
473
  if (log.level === "warning")
424
474
  logger.warn(log.message);
475
+ if (log.level === "verbose")
476
+ logger.log(log.message);
425
477
  else if (log.level === "info")
426
478
  logger.info(log.message);
427
479
  }
@@ -440,7 +492,8 @@ async function build(userOptions, rootDir = process.cwd()) {
440
492
  dts: false,
441
493
  format: fmt,
442
494
  kind: file.kind,
443
- entrypoint: file.kind === "entry-point" ? cleanPath(entrypoints[entrypointIndex]) : undefined
495
+ entrypoint: file.kind === "entry-point" ? cleanPath(entrypoints[entrypointIndex] ?? "") : undefined,
496
+ size: file.size
444
497
  });
445
498
  if (file.kind === "entry-point") {
446
499
  entrypointIndex++;
@@ -454,7 +507,7 @@ async function build(userOptions, rootDir = process.cwd()) {
454
507
  const { entry, splitting, ...dtsOptions } = typeof options.dts === "object" ? options.dts : {};
455
508
  const dtsResult = await generateDts(ensureArray(entry ?? entrypoints), {
456
509
  cwd: rootDir,
457
- preferredTsConfigPath: options.preferredTsconfigPath,
510
+ preferredTsconfig: options.preferredTsconfig,
458
511
  splitting: getResolvedDtsSplitting(options.splitting, splitting),
459
512
  naming: {
460
513
  chunk: getDefaultChunkNaming(options.name)
@@ -478,7 +531,8 @@ async function build(userOptions, rootDir = process.cwd()) {
478
531
  dts: true,
479
532
  format: fmt,
480
533
  kind: file.kind,
481
- entrypoint: file.entrypoint ? cleanPath(file.entrypoint) : undefined
534
+ entrypoint: file.entrypoint ? cleanPath(file.entrypoint) : undefined,
535
+ size: file.dts.length
482
536
  });
483
537
  }
484
538
  }
@@ -34,6 +34,8 @@ type BuildOutputFile = {
34
34
  dts: boolean;
35
35
  /** The format of the output file */
36
36
  format: Format;
37
+ /** The size of the file in bytes */
38
+ size: number;
37
39
  };
38
40
  /**
39
41
  * Represents the output of a build operation
@@ -169,18 +171,19 @@ type InjectStylesOptions = {
169
171
  declare function injectStyles(options?: InjectStylesOptions): BunPlugin;
170
172
  interface UnusedOptions {
171
173
  /**
172
- * The level of reporting for unused dependencies
174
+ * The level of reporting for unused or incorrectly categorized dependencies
173
175
  * @default 'warn'
174
176
  */
175
177
  level?: "warn" | "error";
176
178
  /**
177
- * Dependencies to ignore when checking for unused dependencies
179
+ * Dependencies to ignore when checking
178
180
  * @default []
179
181
  */
180
182
  ignore?: string[];
181
183
  }
182
184
  /**
183
- * A plugin that detects and reports unused dependencies.
185
+ * Detects and reports unused or incorrectly categorized dependencies in your project,
186
+ * helping you maintain a clean dependency tree and keep your `package.json` up to date.
184
187
  *
185
188
  * @see https://bunup.dev/docs/extra-options/unused
186
189
  */
@@ -366,20 +369,19 @@ interface BuildOptions {
366
369
  * When set to true, generates declaration files for all entry points
367
370
  * Can also be configured with GenerateDtsOptions for more control
368
371
  */
369
- dts?: boolean | (Pick<GenerateDtsOptions, "resolve" | "splitting" | "minify"> & {
372
+ dts?: boolean | (Pick<GenerateDtsOptions, "resolve" | "splitting" | "minify" | "inferTypes"> & {
370
373
  entry?: string | string[];
371
374
  });
372
375
  /**
373
- * Path to a preferred tsconfig.json file to use for declaration generation
376
+ * Path to a custom tsconfig.json file used for path resolution during
377
+ * both bundling and TypeScript declaration generation.
374
378
  *
375
- * If not specified, the tsconfig.json in the project root will be used.
376
- * This option allows you to use a different TypeScript configuration
377
- * specifically for declaration file generation.
379
+ * If not specified, the nearest tsconfig.json will be used.
378
380
  *
379
381
  * @example
380
- * preferredTsconfigPath: './tsconfig.build.json'
382
+ * preferredTsconfig: './tsconfig.build.json'
381
383
  */
382
- preferredTsconfigPath?: string;
384
+ preferredTsconfig?: string;
383
385
  /**
384
386
  * External packages that should not be bundled
385
387
  * Useful for dependencies that should be kept as external imports
@@ -617,11 +619,9 @@ interface BuildOptions {
617
619
  */
618
620
  exports?: boolean | ExportsOptions;
619
621
  /**
620
- * Detect and report unused dependencies in your project.
621
- *
622
- * When `true`, enables unused dependency detection with default warning level.
623
- * When an object is provided, allows customization of the detection behavior,
624
- * including report level (warn/error) and dependencies to ignore.
622
+ * Detect and report dependencies that are unused or incorrectly categorized.
623
+ * This includes dependencies not used in your build output, as well as dependencies
624
+ * that don't need to be packed with your library.
625
625
  *
626
626
  * @see https://bunup.dev/docs/extra-options/unused
627
627
  */
@@ -632,11 +632,14 @@ type WithOptional<
632
632
  T,
633
633
  K extends keyof T
634
634
  > = Omit<T, K> & Partial<Pick<T, K>>;
635
- type Arrayable<T> = T | T[];
635
+ type WithRequired<
636
+ T,
637
+ K extends keyof T
638
+ > = Omit<T, K> & Required<Pick<T, K>>;
636
639
  type DefineConfigItem = WithOptional<BuildOptions, "outDir" | "format" | "entry">;
637
640
  type DefineWorkspaceItem = {
638
641
  name: string;
639
642
  root: string;
640
- config?: DefineConfigItem | DefineConfigItem[];
643
+ config?: DefineConfigItem | WithRequired<DefineConfigItem, "name">[];
641
644
  };
642
- export { WithOptional, Arrayable, DefineConfigItem, DefineWorkspaceItem, BuildMeta, BuildOutputFile, BuildOutput, BuildContext, BunupPluginHooks, BunupPlugin, exports, injectStyles, unused, BuildOptions };
645
+ export { WithOptional, WithRequired, DefineConfigItem, DefineWorkspaceItem, BuildMeta, BuildOutputFile, BuildOutput, BuildContext, BunupPluginHooks, BunupPlugin, exports, injectStyles, unused, BuildOptions };
@@ -67,12 +67,23 @@ class Logger {
67
67
  identifier,
68
68
  muted = false,
69
69
  tick = false,
70
- type = "info"
70
+ type = "info",
71
+ noIcon = false,
72
+ leftPadding
71
73
  } = options;
72
- const icon = options.icon ?? this.getIcon(type, tick);
74
+ const icon = noIcon ? "" : options.icon ?? this.getIcon(type, tick);
73
75
  const styledMessage = muted ? pc.dim(message) : type === "error" ? pc.red(message) : type === "warn" ? pc.yellow(message) : message;
74
76
  const identifierPart = this.formatIdentifier(identifier);
75
- return `${icon} ${styledMessage}${identifierPart}`;
77
+ const iconPart = icon ? `${icon} ` : "";
78
+ const baseMessage = `${iconPart}${styledMessage}${identifierPart}`;
79
+ const paddingCount = leftPadding === true ? 2 : typeof leftPadding === "number" ? leftPadding : 0;
80
+ if (paddingCount > 0) {
81
+ const padding = " ".repeat(paddingCount);
82
+ return baseMessage.split(`
83
+ `).map((line) => `${padding}${line}`).join(`
84
+ `);
85
+ }
86
+ return baseMessage;
76
87
  }
77
88
  output(message, options = {}, logFn = console.log) {
78
89
  if (this.silent || !this.shouldLog(options)) {
@@ -123,10 +134,14 @@ class Logger {
123
134
  console.log("");
124
135
  }
125
136
  }
126
- log(...args) {
127
- if (!this.silent) {
128
- console.log(...args);
129
- }
137
+ log(message, options = {}) {
138
+ const formattedMessage = this.formatMessage({
139
+ ...options,
140
+ message,
141
+ type: "info",
142
+ noIcon: true
143
+ });
144
+ this.output(formattedMessage, options);
130
145
  }
131
146
  list(items, options) {
132
147
  return items.map((item) => {
@@ -136,6 +151,20 @@ class Logger {
136
151
  }).join(`
137
152
  `);
138
153
  }
154
+ highlight(code) {
155
+ const keywords = /\b(const|let|var|function|return|if|else|for|while|class|import|export|from|async|await|new|try|catch|throw|typeof|interface|type|enum)\b/g;
156
+ const strings = /(["'`])(?:(?=(\\?))\2.)*?\1/g;
157
+ const comments = /(\/\/.*$|\/\*[\s\S]*?\*\/)/gm;
158
+ const numbers = /\b(\d+\.?\d*)\b/g;
159
+ const functions = /\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*(?=\()/g;
160
+ let result = code;
161
+ result = result.replace(comments, (match) => pc.dim(match));
162
+ result = result.replace(strings, (match) => pc.green(match));
163
+ result = result.replace(keywords, (match) => pc.magenta(match));
164
+ result = result.replace(numbers, (match) => pc.yellow(match));
165
+ result = result.replace(functions, (match) => pc.cyan(match));
166
+ return result;
167
+ }
139
168
  }
140
169
  function logTime(ms) {
141
170
  return ms >= 1000 ? pc.green(`${(ms / 1000).toFixed(2)}s`) : pc.green(`${Math.round(ms)}ms`);
@@ -148,8 +177,42 @@ function link(url, label) {
148
177
  }
149
178
  var logger = Logger.getInstance();
150
179
 
180
+ // packages/bunup/src/utils/path.ts
181
+ import { normalize } from "path";
182
+ function getShortFilePath(filePath, maxLength = 3) {
183
+ const fileParts = filePath.split("/");
184
+ const shortPath = fileParts.slice(-maxLength).join("/");
185
+ return shortPath;
186
+ }
187
+ function cleanPath(path) {
188
+ return normalize(path).replace(/\\/g, "/").replace(/^[a-zA-Z]:\//, "").replace(/^\/+/, "").replace(/\/+/g, "/");
189
+ }
190
+
151
191
  // packages/bunup/src/errors.ts
152
192
  import pc2 from "picocolors";
193
+
194
+ // packages/bunup/src/utils/format.ts
195
+ function formatFileSize(bytes) {
196
+ if (bytes === 0)
197
+ return "0 B";
198
+ const units = ["B", "KB", "MB", "GB"];
199
+ const i = Math.floor(Math.log(bytes) / Math.log(1024));
200
+ if (i === 0)
201
+ return `${bytes} ${units[i]}`;
202
+ return `${(bytes / 1024 ** i).toFixed(2)} ${units[i]}`;
203
+ }
204
+ var listFormatter = new Intl.ListFormat("en", {
205
+ style: "long",
206
+ type: "conjunction"
207
+ });
208
+ function formatListWithAnd(arr) {
209
+ return listFormatter.format(arr);
210
+ }
211
+ function stripAnsiSafe(text) {
212
+ return Bun.stripANSI ? Bun.stripANSI(text) : text;
213
+ }
214
+
215
+ // packages/bunup/src/errors.ts
153
216
  class BunupError extends Error {
154
217
  constructor(message) {
155
218
  super(message);
@@ -242,36 +305,32 @@ var handleError = (error, context) => {
242
305
  }
243
306
  const knownError = KNOWN_ERRORS.find((error2) => error2.pattern.test(errorMessage) && (error2.errorType === errorType || !error2.errorType));
244
307
  if (!knownError) {
245
- console.error(`
308
+ logger.error(`
246
309
  ${pc2.bgRed(` ${errorType} `)}
247
310
 
248
- ${contextPrefix}${errorMessage}`.split(`
249
- `).map((line) => ` ${line}`).join(`
250
- `));
311
+ ${contextPrefix}${errorMessage}`, { noIcon: true, leftPadding: true });
251
312
  }
252
313
  if (knownError) {
253
- console.log(`
254
- `);
314
+ logger.space();
255
315
  knownError.logSolution(errorMessage);
256
- console.log(`
257
- `);
316
+ logger.space();
258
317
  } else {
259
318
  const issueUrl = new URL("https://github.com/bunup/bunup/issues/new");
260
- issueUrl.searchParams.set("title", `[${errorType}] Error encountered`);
319
+ issueUrl.searchParams.set("title", `[${errorType}] [give a descriptive title]`);
261
320
  issueUrl.searchParams.set("body", `## Error Details
262
321
 
263
322
  **Error Type:** ${errorType}
264
- **Error Message:** ${errorMessage}
323
+ **Error Message:** ${stripAnsiSafe(errorMessage)}
265
324
 
266
325
  ## Additional Context
267
326
 
268
327
  <!-- Please provide any additional context about what you were trying to do when the error occurred -->`);
269
- console.error(pc2.white(`
328
+ logger.log(pc2.white(`
270
329
  If you think this is a bug, please `) + link(issueUrl.toString(), "open an issue") + ` with details about this error
271
330
  `);
272
331
  }
273
332
  };
274
- var noEntryPointsFoundError = (defaultEntrypoints) => {
333
+ var formatNoEntryPointsFoundError = (defaultEntrypoints) => {
275
334
  return `${pc2.red(pc2.bold("No entry points found"))}
276
335
 
277
336
  ` + `Looked for these default entry points:
@@ -280,7 +339,7 @@ var noEntryPointsFoundError = (defaultEntrypoints) => {
280
339
 
281
340
  You can specify entry points via CLI like ${pc2.green("bunup lib/main.ts")}, ` + `use multiple entries like ${pc2.green("bunup components/button.tsx utils/format.ts")}, or add the entry option in your bunup config.`;
282
341
  };
283
- var invalidEntryPointsError = (userEntrypoints) => {
342
+ var formatInvalidEntryPointsError = (userEntrypoints) => {
284
343
  const entryPointsFormatted = logger.list(userEntrypoints, { dim: true });
285
344
  const isMultiple = userEntrypoints.length > 1;
286
345
  return `${pc2.red(pc2.bold(`Entry ${isMultiple ? "points do not exist" : "point does not exist"}`))}
@@ -289,14 +348,27 @@ ${entryPointsFormatted}
289
348
 
290
349
  Please check that ${isMultiple ? "these paths exist and point" : "this path exists and points"} to ${isMultiple ? "valid files" : "a valid file"}.`;
291
350
  };
351
+ function formatBunBuildError(error) {
352
+ const pos = error.position;
353
+ if (!pos) {
354
+ return error.message;
355
+ }
356
+ const lineNum = String(pos.line);
357
+ const padding = " ".repeat(lineNum.length);
358
+ const caretPos = pos.column;
359
+ return `${pc2.dim(`${lineNum} |`)} ${logger.highlight(pos.lineText)}
360
+ ${pc2.dim(`${padding} |`)} ${" ".repeat(caretPos)}${pc2.red("^")}
361
+
362
+ ${pc2.bold(error.message)}
363
+ ${pc2.dim("at")} ${pc2.cyan(getShortFilePath(pos.file))}${pc2.dim(":")}${pc2.yellow(lineNum)}${pc2.dim(":")}${pc2.yellow(String(pos.column))}`;
364
+ }
292
365
  var handleErrorAndExit = (error, context) => {
293
366
  handleError(error, context);
294
367
  process.exit(1);
295
368
  };
296
369
 
297
- // packages/bunup/src/utils.ts
298
- import fs from "fs/promises";
299
- import path, { normalize } from "path";
370
+ // packages/bunup/src/plugins/exports.ts
371
+ import path2 from "path";
300
372
 
301
373
  // packages/bunup/src/constants/re.ts
302
374
  var JS_RE = /\.(js|jsx|cjs|mjs)$/;
@@ -306,60 +378,9 @@ var JS_TS_RE = new RegExp(`${JS_RE.source}|${TS_RE.source}`);
306
378
  var JS_DTS_RE = new RegExp(`${JS_RE.source}|${DTS_RE.source}`);
307
379
  var CSS_RE = /\.(css)$/;
308
380
 
309
- // packages/bunup/src/utils.ts
310
- function ensureArray(value) {
311
- return Array.isArray(value) ? value : [value].filter(Boolean);
312
- }
313
- function ensureObject(value) {
314
- return typeof value === "object" && value !== null ? value : {};
315
- }
316
- function getDefaultJsOutputExtension(format, packageType) {
317
- switch (format) {
318
- case "esm":
319
- return isModulePackage(packageType) ? ".js" : ".mjs";
320
- case "cjs":
321
- return isModulePackage(packageType) ? ".cjs" : ".js";
322
- case "iife":
323
- return ".global.js";
324
- }
325
- }
326
- function getDefaultDtsOutputExtention(format, packageType, kind) {
327
- if (kind === "chunk")
328
- return ".d.ts";
329
- switch (format) {
330
- case "esm":
331
- return isModulePackage(packageType) ? ".d.ts" : ".d.mts";
332
- case "cjs":
333
- return isModulePackage(packageType) ? ".d.cts" : ".d.ts";
334
- case "iife":
335
- return ".global.d.ts";
336
- }
337
- }
338
- function isModulePackage(packageType) {
339
- return packageType === "module";
340
- }
341
- function getPackageDeps(packageJson) {
342
- if (!packageJson)
343
- return [];
344
- return Array.from(new Set([
345
- ...Object.keys(packageJson.dependencies || {}),
346
- ...Object.keys(packageJson.peerDependencies || {})
347
- ]));
348
- }
349
- function formatFileSize(bytes) {
350
- if (bytes === 0)
351
- return "0 B";
352
- const units = ["B", "KB", "MB", "GB"];
353
- const i = Math.floor(Math.log(bytes) / Math.log(1024));
354
- if (i === 0)
355
- return `${bytes} ${units[i]}`;
356
- return `${(bytes / 1024 ** i).toFixed(2)} ${units[i]}`;
357
- }
358
- function getShortFilePath(filePath, maxLength = 3) {
359
- const fileParts = filePath.split("/");
360
- const shortPath = fileParts.slice(-maxLength).join("/");
361
- return shortPath;
362
- }
381
+ // packages/bunup/src/utils/file.ts
382
+ import fs from "fs/promises";
383
+ import path from "path";
363
384
  async function cleanOutDir(rootDir, outDir) {
364
385
  const normalizedOutDir = path.normalize(outDir);
365
386
  if (["/", ".", "..", "~"].includes(normalizedOutDir) || normalizedOutDir.startsWith("/") || normalizedOutDir.startsWith("~")) {
@@ -376,16 +397,6 @@ async function cleanOutDir(rootDir, outDir) {
376
397
  throw new BunupBuildError(`Failed to manage output directory: ${error}`);
377
398
  }
378
399
  }
379
- function cleanPath(path2) {
380
- return normalize(path2).replace(/\\/g, "/").replace(/^[a-zA-Z]:\//, "").replace(/^\/+/, "").replace(/\/+/g, "/");
381
- }
382
- var listFormatter = new Intl.ListFormat("en", {
383
- style: "long",
384
- type: "conjunction"
385
- });
386
- function formatListWithAnd(arr) {
387
- return listFormatter.format(arr);
388
- }
389
400
  function getFilesFromGlobs(patterns, cwd) {
390
401
  const includePatterns = patterns.filter((p) => !p.startsWith("!"));
391
402
  const excludePatterns = patterns.filter((p) => p.startsWith("!")).map((p) => p.slice(1));
@@ -416,20 +427,8 @@ function isJavascriptFile(path2) {
416
427
  return false;
417
428
  return JS_RE.test(path2);
418
429
  }
419
- function replaceExtension(filePath, newExtension) {
420
- if (!filePath) {
421
- return filePath;
422
- }
423
- const normalizedExtension = newExtension.startsWith(".") ? newExtension : `.${newExtension}`;
424
- const lastSlashIndex = Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\"));
425
- const directory = lastSlashIndex >= 0 ? filePath.substring(0, lastSlashIndex + 1) : "";
426
- const filename = lastSlashIndex >= 0 ? filePath.substring(lastSlashIndex + 1) : filePath;
427
- const lastDotIndex = filename.lastIndexOf(".");
428
- if (lastDotIndex === -1) {
429
- return directory + filename + normalizedExtension;
430
- }
431
- const nameWithoutExtension = filename.substring(0, lastDotIndex);
432
- return directory + nameWithoutExtension + normalizedExtension;
430
+ function isGlobPattern(pattern) {
431
+ return /[*?[\]{}]/.test(pattern);
433
432
  }
434
433
  async function detectFileFormatting(filePath) {
435
434
  try {
@@ -442,10 +441,10 @@ async function detectFileFormatting(filePath) {
442
441
  const match = line.match(/^(\s+)/);
443
442
  if (match) {
444
443
  const indent = match[1];
445
- if (indent.startsWith("\t")) {
444
+ if (indent?.startsWith("\t")) {
446
445
  return { indentation: "\t", hasTrailingNewline };
447
446
  }
448
- return { indentation: indent, hasTrailingNewline };
447
+ return { indentation: indent ?? " ", hasTrailingNewline };
449
448
  }
450
449
  }
451
450
  return { indentation: " ", hasTrailingNewline };
@@ -453,12 +452,8 @@ async function detectFileFormatting(filePath) {
453
452
  return { indentation: " ", hasTrailingNewline: true };
454
453
  }
455
454
  }
456
- function isGlobPattern(pattern) {
457
- return /[*?[\]{}]/.test(pattern);
458
- }
459
455
 
460
456
  // packages/bunup/src/plugins/exports.ts
461
- import path2 from "path";
462
457
  function exports(options = {}) {
463
458
  return {
464
459
  name: "exports",
@@ -678,7 +673,7 @@ function isExcluded(entrypoint, exclude, ctx) {
678
673
  }
679
674
  function getExportKey(pathRelativeToOutdir) {
680
675
  const pathSegments = cleanPath(removeExtension(pathRelativeToOutdir)).split("/");
681
- if (pathSegments.length === 1 && pathSegments[0].startsWith("index")) {
676
+ if (pathSegments.length === 1 && pathSegments[0]?.startsWith("index")) {
682
677
  return ".";
683
678
  }
684
679
  return `./${pathSegments.filter((segment) => !segment.startsWith("index")).join("/")}`;
@@ -853,57 +848,99 @@ function unused(options = {}) {
853
848
  hooks: {
854
849
  onBuildDone: async (ctx) => {
855
850
  const { options: buildOptions, output, meta } = ctx;
856
- if (buildOptions.watch) {
851
+ if (buildOptions.watch)
857
852
  return;
858
- }
859
- const transpiler = new Bun.Transpiler({
860
- loader: "js"
861
- });
862
- const jsFiles = output.files.filter((file) => file.fullPath.endsWith(".js"));
863
- const packageDependencies = typeof meta.packageJson.data?.dependencies === "object" ? meta.packageJson.data.dependencies : {};
864
- const externals = [
865
- ...buildOptions.external ?? [],
866
- ...buildOptions.noExternal ?? []
867
- ];
868
- const allImportPaths = new Set;
869
- for (const file of jsFiles) {
870
- const code = await Bun.file(file.fullPath).text();
871
- const codeWithoutShebang = code.replace(/^#!.*$/m, "");
872
- const importPaths = transpiler.scanImports(codeWithoutShebang).map((imp) => imp.path);
873
- for (const importPath of importPaths) {
874
- if (externals.some((ex) => typeof ex === "string" ? importPath.startsWith(ex) : ex.test(importPath)))
875
- continue;
876
- if (importPath.startsWith("node:") || importPath.startsWith("bun:"))
877
- continue;
878
- allImportPaths.add(importPath);
879
- }
880
- }
881
- const allDependencies = Object.keys(packageDependencies);
882
- const unusedDependencies = allDependencies.filter((dependency) => {
883
- if (ignore.includes(dependency))
884
- return false;
885
- return !Array.from(allImportPaths).some((importPath) => importPath === dependency || importPath.startsWith(`${dependency}/`));
886
- });
887
- if (unusedDependencies.length > 0) {
888
- const count = unusedDependencies.length;
889
- const depText = count === 1 ? "dependency" : "dependencies";
890
- const coloredDeps = formatListWithAnd(unusedDependencies.map((dep) => pc3.yellow(dep)));
891
- const removeCommand = pc3.cyan(`bun remove ${unusedDependencies.join(" ")}`);
892
- const message = [
893
- `
894
- Your project${buildOptions.name ? ` ${buildOptions.name}` : ""} has ${count} unused ${depText}: ${coloredDeps}.`,
895
- `You can remove ${count === 1 ? "it" : "them"} with ${removeCommand}`
896
- ].join(" ");
897
- if (level === "error") {
898
- logger.log(pc3.red(message));
899
- process.exit(1);
900
- } else {
901
- logger.log(message);
902
- }
903
- }
853
+ const usedDeps = await collectUsedDependencies(output.files, buildOptions);
854
+ const pkgDeps = extractPackageDependencies(meta.packageJson.data?.dependencies);
855
+ const unusedDeps = findUnusedDependencies(pkgDeps, usedDeps, ignore);
856
+ const misplacedTypes = findMisplacedTypes(pkgDeps, usedDeps, ignore);
857
+ reportIssues(unusedDeps, misplacedTypes, buildOptions.name, level);
904
858
  }
905
859
  }
906
860
  };
907
861
  }
862
+ async function collectUsedDependencies(files, buildOptions) {
863
+ const transpiler = new Bun.Transpiler({ loader: "ts" });
864
+ const externals = [
865
+ ...buildOptions.external ?? [],
866
+ ...buildOptions.noExternal ?? []
867
+ ];
868
+ const usedDeps = new Set;
869
+ const jsFiles = files.filter((f) => isJavascriptFile(f.fullPath) || isTypeScriptFile(f.fullPath));
870
+ for (const file of jsFiles) {
871
+ const code = (await Bun.file(file.fullPath).text()).replace(/^#!.*$/m, "");
872
+ const imports = transpiler.scanImports(code).map((imp) => imp.path);
873
+ for (const path4 of imports) {
874
+ if (isExternal(path4, externals) || isBuiltin(path4))
875
+ continue;
876
+ usedDeps.add(path4);
877
+ }
878
+ }
879
+ return usedDeps;
880
+ }
881
+ function isExternal(path4, externals) {
882
+ return externals.some((ex) => typeof ex === "string" ? path4.startsWith(ex) : ex.test(path4));
883
+ }
884
+ function isBuiltin(path4) {
885
+ return path4.startsWith("node:") || path4.startsWith("bun:");
886
+ }
887
+ function extractPackageDependencies(deps) {
888
+ return typeof deps === "object" ? Object.keys(deps) : [];
889
+ }
890
+ function findUnusedDependencies(allDeps, usedDeps, ignore) {
891
+ return allDeps.filter((dep) => {
892
+ if (ignore.includes(dep))
893
+ return false;
894
+ return !Array.from(usedDeps).some((used) => used === dep || used.startsWith(`${dep}/`));
895
+ });
896
+ }
897
+ function findMisplacedTypes(allDeps, usedDeps, ignore) {
898
+ return allDeps.filter((dep) => {
899
+ if (!dep.startsWith("@types/"))
900
+ return false;
901
+ if (ignore.includes(dep))
902
+ return false;
903
+ return !Array.from(usedDeps).some((used) => used === dep || used.startsWith(`${dep}/`));
904
+ });
905
+ }
906
+ function reportIssues(unused2, misplaced, projectName, level) {
907
+ reportIssue(unused2, "unused", projectName, level);
908
+ reportIssue(misplaced, "misplaced-types", projectName, level);
909
+ }
910
+ function reportIssue(deps, type, projectName, level) {
911
+ if (deps.length === 0)
912
+ return;
913
+ const count = deps.length;
914
+ const coloredDeps = formatListWithAnd(deps.map((d) => pc3.yellow(d)));
915
+ const project = projectName ? ` ${projectName}` : "";
916
+ const message = buildMessage(type, count, coloredDeps, project, deps);
917
+ if (level === "error") {
918
+ logger.log(pc3.red(message), { leftPadding: true });
919
+ process.exit(1);
920
+ } else {
921
+ logger.log(message, { leftPadding: true });
922
+ }
923
+ }
924
+ function buildMessage(type, count, coloredDeps, project, deps) {
925
+ const plural = count === 1 ? "it" : "them";
926
+ if (type === "unused") {
927
+ const depText2 = count === 1 ? "dependency" : "dependencies";
928
+ const cmd2 = pc3.cyan(`bun remove ${deps.join(" ")}`);
929
+ return `
930
+ Your project${project} has ${count} unused ${depText2}: ${coloredDeps}. You can remove ${plural} with ${cmd2}`;
931
+ }
932
+ const depText = count === 1 ? "package" : "packages";
933
+ const cmd = pc3.cyan(`bun remove ${deps.join(" ")} && bun add --dev ${deps.join(" ")}`);
934
+ return `
935
+ Your project${project} has ${count} type ${depText} that should be in devDependencies: ${coloredDeps}. Move ${plural} to devDependencies with ${cmd}`;
936
+ }
937
+
938
+ // packages/bunup/src/utils/common.ts
939
+ function ensureArray(value) {
940
+ return Array.isArray(value) ? value : [value].filter(Boolean);
941
+ }
942
+ function ensureObject(value) {
943
+ return typeof value === "object" && value !== null ? value : {};
944
+ }
908
945
 
909
- export { __toESM, __require, logTime, logger, BunupBuildError, BunupDTSBuildError, BunupCLIError, BunupWatchError, BunupVersionError, parseErrorMessage, handleError, noEntryPointsFoundError, invalidEntryPointsError, handleErrorAndExit, ensureArray, ensureObject, getDefaultJsOutputExtension, getDefaultDtsOutputExtention, getPackageDeps, formatFileSize, getShortFilePath, cleanOutDir, cleanPath, formatListWithAnd, getFilesFromGlobs, isTypeScriptFile, isJavascriptFile, replaceExtension, isGlobPattern, exports, injectStyles, shims, unused };
946
+ export { __toESM, __require, logTime, logger, formatFileSize, formatListWithAnd, getShortFilePath, cleanPath, BunupBuildError, BunupDTSBuildError, BunupCLIError, BunupWatchError, BunupVersionError, parseErrorMessage, handleError, formatNoEntryPointsFoundError, formatInvalidEntryPointsError, formatBunBuildError, handleErrorAndExit, cleanOutDir, getFilesFromGlobs, isTypeScriptFile, isJavascriptFile, isGlobPattern, exports, injectStyles, shims, unused, ensureArray, ensureObject };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bunup",
3
3
  "description": "⚡ A blazing-fast build tool for your libraries built with Bun.",
4
- "version": "0.14.20",
4
+ "version": "0.15.0",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"
@@ -46,16 +46,19 @@
46
46
  "bin": {
47
47
  "bunup": "dist/cli/index.js"
48
48
  },
49
+ "scripts": {
50
+ "type-check": "tsc --noEmit"
51
+ },
49
52
  "dependencies": {
50
- "@bunup/dts": "0.14.14",
53
+ "@bunup/dts": "^0.14.22",
54
+ "@bunup/shared": "0.14.21",
51
55
  "chokidar": "^4.0.3",
52
56
  "coffi": "^0.1.37",
53
57
  "lightningcss": "^1.30.2",
54
58
  "picocolors": "^1.1.1",
55
59
  "tinyexec": "^1.0.1",
56
60
  "tree-kill": "^1.2.2",
57
- "zlye": "^0.4.4",
58
- "@bunup/shared": "0.14.14"
61
+ "zlye": "^0.4.4"
59
62
  },
60
63
  "peerDependencies": {
61
64
  "typescript": "latest"