tsdown 0.9.0 → 0.9.2

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/LICENSE CHANGED
@@ -1,6 +1,7 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2024-present VoidZero Inc. & Contributors
3
+ Copyright (c) 2025-present VoidZero Inc. & Contributors
4
+ Copyright (c) 2024 三咲智子 Kevin Deng (https://github.com/sxzz)
4
5
 
5
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
7
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,32 +1,24 @@
1
- <img src="./assets/header-illustration.svg" alt="tsdown" width="100%" /><br>
1
+ <img src="./docs/public/og-image.svg" alt="tsdown" width="100%" /><br>
2
2
 
3
3
  # tsdown [![npm](https://img.shields.io/npm/v/tsdown.svg)](https://npmjs.com/package/tsdown) [![Unit Test](https://github.com/rolldown/tsdown/actions/workflows/tests.yml/badge.svg)](https://github.com/rolldown/tsdown/actions/workflows/tests.yml) [![JSR](https://jsr.io/badges/@sxzz/tsdown)](https://jsr.io/@sxzz/tsdown)
4
4
 
5
- ⚡️ Smooth and fast library bundler powered by Rolldown [Rolldown](https://github.com/rolldown/rolldown).
5
+ The elegant bundler for libraries powered by [Rolldown](https://github.com/rolldown/rolldown).
6
6
 
7
7
  ## Features
8
8
 
9
- - 🚀 **Blazing fast**: Build and generate `.d.ts` powered by Oxc and Rolldown, incredibly fast!
10
- - ♻️ **Powerful ecosystem**: Support Rollup / Rolldown / unplugin plugins, and some Vite plugins.
11
- - 📦 **Out-of-box**: Support reusing configurations from Vite or Vitest.
9
+ - 🚀 **Blazing fast**: Build and generate declaration files powered by Oxc and Rolldown, incredibly fast!
10
+ - ♻️ **Powerful ecosystem**: Support Rollup, Rolldown, unplugin plugins, and some Vite plugins.
11
+ - ️🛠️ **Easy to use**: tsdown preconfigures everything you need to get started, so you can focus on writing code.
12
12
  - 🔄 **Seamless migration**: Compatible with tsup's main options and features, ensuring a smooth transition.
13
13
 
14
- ## Install
15
-
16
- ```bash
17
- npm i tsdown
18
- ```
14
+ ## Documentation
19
15
 
20
- ## Configuration
16
+ For full documentation, visit [tsdown.dev](https://tsdown.dev).
21
17
 
22
- ```ts
23
- // tsdown.config.ts
24
- import { defineConfig } from 'tsdown'
18
+ ## Install
25
19
 
26
- export default defineConfig({
27
- entry: ['./src'],
28
- // ...
29
- })
20
+ ```bash
21
+ npm i -D tsdown
30
22
  ```
31
23
 
32
24
  ## Usage
@@ -41,11 +33,11 @@ npx tsdown
41
33
  npx tsdown migrate
42
34
  ```
43
35
 
44
- Please make sure to commit your changes before migrating.
36
+ Please make sure to commit your changes before migrating. For more details, see the [Migration Guide](https://tsdown.dev/guide/migrate-from-tsup).
45
37
 
46
38
  ## Credits
47
39
 
48
- This project also partially contains code derived or copied from [tsup](https://github.com/egoist/tsup).
40
+ This project also partially contains code derived or copied from the following projects:
49
41
 
50
42
  - [tsup](https://github.com/egoist/tsup)
51
43
  - [pkgroll](https://github.com/privatenumber/pkgroll)
@@ -1,5 +1,7 @@
1
-
2
1
  //#region src/config.ts
2
+ /**
3
+ * Defines the configuration for tsdown.
4
+ */
3
5
  function defineConfig(options) {
4
6
  return options;
5
7
  }
@@ -1,9 +1,12 @@
1
- import { UserConfig } from "./options.d-BUmkLb5_.js";
1
+ import { UserConfig } from "./options.d-DxODs1UG.js";
2
2
 
3
3
  //#region src/config.d.ts
4
4
  /**
5
5
  * Defines the configuration for tsdown.
6
6
  */
7
+ /**
8
+ * Defines the configuration for tsdown.
9
+ */
7
10
  declare function defineConfig(options: UserConfig): UserConfig;
8
11
 
9
12
  //#endregion
package/dist/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import "./options.d-BUmkLb5_.js";
2
- import { defineConfig$1 as defineConfig } from "./config.d-CIuApN_q.js";
1
+ import "./options.d-DxODs1UG.js";
2
+ import { defineConfig$1 as defineConfig } from "./config.d-BrQCtlF9.js";
3
3
 
4
4
  export { defineConfig };
package/dist/config.js CHANGED
@@ -1,3 +1,3 @@
1
- import { defineConfig } from "./config-0LDjKwZ7.js";
1
+ import { defineConfig } from "./config-yiJy1jd0.js";
2
2
 
3
3
  export { defineConfig };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Options, ResolvedOptions, UserConfig } from "./options.d-BUmkLb5_.js";
2
- import { defineConfig$1 as defineConfig } from "./config.d-CIuApN_q.js";
1
+ import { Options, ResolvedOptions, UserConfig } from "./options.d-DxODs1UG.js";
2
+ import { defineConfig$1 as defineConfig } from "./config.d-BrQCtlF9.js";
3
3
  import Debug from "debug";
4
4
  import { ConsolaInstance } from "consola";
5
5
 
@@ -7,6 +7,9 @@ import { ConsolaInstance } from "consola";
7
7
  /**
8
8
  * Logger instance
9
9
  */
10
+ /**
11
+ * Logger instance
12
+ */
10
13
  declare const logger: ConsolaInstance;
11
14
 
12
15
  //#endregion
@@ -14,6 +17,9 @@ declare const logger: ConsolaInstance;
14
17
  /**
15
18
  * Build with tsdown.
16
19
  */
20
+ /**
21
+ * Build with tsdown.
22
+ */
17
23
  declare function build(userOptions?: Options): Promise<void>;
18
24
  declare const pkgRoot: string;
19
25
  /**
@@ -21,6 +27,11 @@ declare const pkgRoot: string;
21
27
  *
22
28
  * @param config Resolved options
23
29
  */
30
+ /**
31
+ * Build a single configuration, without watch and shortcuts features.
32
+ *
33
+ * @param config Resolved options
34
+ */
24
35
  declare function buildSingle(config: ResolvedOptions): Promise<(() => Promise<void>) | undefined>;
25
36
 
26
37
  //#endregion
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
- import { defineConfig } from "./config-0LDjKwZ7.js";
2
- import { debug, logger, setSilent } from "./logger-4bmpqibt.js";
3
- import { ExternalPlugin, debounce, toArray } from "./external-DvQ4QDcG.js";
4
- import path, { dirname, normalize, sep } from "node:path";
1
+ import { defineConfig } from "./config-yiJy1jd0.js";
2
+ import { ExternalPlugin, ShebangPlugin, debounce, fsExists, fsRemove, lowestCommonAncestor, toArray } from "./plugins-CATHxFm7.js";
3
+ import { debug, logger, setSilent } from "./logger-Dt3D6T-U.js";
4
+ import path from "node:path";
5
5
  import process from "node:process";
6
6
  import { fileURLToPath, pathToFileURL } from "node:url";
7
7
  import { build as build$1 } from "rolldown";
8
8
  import { transformPlugin } from "rolldown/experimental";
9
9
  import { exec } from "tinyexec";
10
- import { access, readFile, readdir, rm, stat } from "node:fs/promises";
10
+ import { readFile, readdir, stat } from "node:fs/promises";
11
11
  import Debug from "debug";
12
12
  import { glob } from "tinyglobby";
13
13
  import { findUp } from "find-up-simple";
@@ -15,36 +15,6 @@ import readline from "node:readline";
15
15
  import { blue, bold, dim, underline } from "ansis";
16
16
  import { loadConfig } from "unconfig";
17
17
 
18
- //#region src/utils/fs.ts
19
- function fsExists(path$1) {
20
- return access(path$1).then(() => true, () => false);
21
- }
22
- function fsRemove(path$1) {
23
- return rm(path$1, {
24
- force: true,
25
- recursive: true
26
- }).catch(() => {});
27
- }
28
- function lowestCommonAncestor(...filepaths) {
29
- if (filepaths.length === 0) return "";
30
- if (filepaths.length === 1) return dirname(filepaths[0]);
31
- filepaths = filepaths.map(normalize);
32
- const [first, ...rest] = filepaths;
33
- let ancestor = first.split(sep);
34
- for (const filepath of rest) {
35
- const directories = filepath.split(sep, ancestor.length);
36
- let index = 0;
37
- for (const directory of directories) if (directory === ancestor[index]) index += 1;
38
- else {
39
- ancestor = ancestor.slice(0, index);
40
- break;
41
- }
42
- ancestor = ancestor.slice(0, index);
43
- }
44
- return ancestor.length <= 1 && ancestor[0] === "" ? sep + ancestor[0] : ancestor.join(sep);
45
- }
46
-
47
- //#endregion
48
18
  //#region src/features/clean.ts
49
19
  const debug$2 = Debug("tsdown:clean");
50
20
  async function cleanOutDir(cwd, patterns) {
@@ -75,7 +45,6 @@ function getPackageType(pkg) {
75
45
  if (!["module", "commonjs"].includes(pkg.type)) throw new Error(`Invalid package.json type: ${pkg.type}`);
76
46
  return pkg.type;
77
47
  }
78
- return "commonjs";
79
48
  }
80
49
  function normalizeFormat(format) {
81
50
  return toArray(format, "es").map((format$1) => {
@@ -92,7 +61,7 @@ function normalizeFormat(format) {
92
61
 
93
62
  //#endregion
94
63
  //#region src/features/output.ts
95
- function resolveOutputExtension(packageType, format, fixedExtension) {
64
+ function resolveJsOutputExtension(packageType, format, fixedExtension) {
96
65
  switch (format) {
97
66
  case "es": return !fixedExtension && packageType === "module" ? "js" : "mjs";
98
67
  case "cjs": return fixedExtension || packageType === "module" ? "cjs" : "js";
@@ -112,7 +81,7 @@ function resolveChunkFilename(pkg, inputOptions, format, { outExtensions, fixedE
112
81
  jsExtension = js;
113
82
  dtsExtension = dts;
114
83
  }
115
- jsExtension ||= `.${resolveOutputExtension(packageType, format, fixedExtension)}`;
84
+ jsExtension ||= `.${resolveJsOutputExtension(packageType, format, fixedExtension)}`;
116
85
  return [createChunkFilename("[name]", jsExtension, dtsExtension), createChunkFilename(`[name]-[hash]`, jsExtension, dtsExtension)];
117
86
  }
118
87
  function createChunkFilename(basename, jsExtension, dtsExtension) {
@@ -244,18 +213,18 @@ async function watchBuild(options, configFile, rebuild, restart) {
244
213
 
245
214
  //#endregion
246
215
  //#region src/features/entry.ts
247
- async function resolveEntry(entry) {
216
+ async function resolveEntry(entry, cwd) {
248
217
  if (!entry || Object.keys(entry).length === 0) throw new Error(`No input files, try "tsdown <your-file>" instead`);
249
- const objectEntry = await toObjectEntry(entry);
218
+ const objectEntry = await toObjectEntry(entry, cwd);
250
219
  const entries = Object.values(objectEntry);
251
220
  if (entries.length === 0) throw new Error(`Cannot find entry: ${JSON.stringify(entry)}`);
252
221
  logger.info(`entry: ${blue(entries.join(", "))}`);
253
222
  return objectEntry;
254
223
  }
255
- async function toObjectEntry(entry) {
224
+ async function toObjectEntry(entry, cwd) {
256
225
  if (typeof entry === "string") entry = [entry];
257
226
  if (!Array.isArray(entry)) return entry;
258
- const resolvedEntry = await glob(entry);
227
+ const resolvedEntry = await glob(entry, { cwd });
259
228
  const base = lowestCommonAncestor(...resolvedEntry);
260
229
  return Object.fromEntries(resolvedEntry.map((file) => {
261
230
  const relative = path.relative(base, file);
@@ -280,7 +249,7 @@ async function resolveOptions(options) {
280
249
  ...options
281
250
  };
282
251
  let { entry, format = ["es"], plugins = [], clean = false, silent = false, treeshake = true, platform = "node", outDir = "dist", sourcemap = false, dts = false, unused = false, watch = false, shims = false, skipNodeModulesBundle = false, publint: publint$1 = false, fromVite, alias, tsconfig } = subOptions;
283
- entry = await resolveEntry(entry);
252
+ entry = await resolveEntry(entry, cwd);
284
253
  if (clean === true) clean = [];
285
254
  if (publint$1 === true) publint$1 = {};
286
255
  if (tsconfig !== false) {
@@ -299,7 +268,7 @@ async function resolveOptions(options) {
299
268
  if (!tsconfig) logger.warn(`No \`${tsconfig}\` found in \`${cwd}\``);
300
269
  }
301
270
  }
302
- if (tsconfig) logger.info(`Using tsconfig: ${underline(tsconfig)}`);
271
+ if (tsconfig) logger.info(`Using tsconfig: ${underline(path.relative(cwd, tsconfig))}`);
303
272
  }
304
273
  if (fromVite) {
305
274
  const viteUserConfig = await loadViteConfig(fromVite === true ? "vite" : fromVite, cwd);
@@ -328,7 +297,8 @@ async function resolveOptions(options) {
328
297
  skipNodeModulesBundle,
329
298
  publint: publint$1,
330
299
  alias,
331
- tsconfig
300
+ tsconfig,
301
+ cwd
332
302
  };
333
303
  return config;
334
304
  }));
@@ -432,6 +402,9 @@ async function mergeUserOptions(defaults, user, args) {
432
402
 
433
403
  //#endregion
434
404
  //#region src/index.ts
405
+ /**
406
+ * Build with tsdown.
407
+ */
435
408
  async function build(userOptions = {}) {
436
409
  if (typeof userOptions.silent === "boolean") setSilent(userOptions.silent);
437
410
  debug("Loading config");
@@ -454,6 +427,11 @@ async function build(userOptions = {}) {
454
427
  }
455
428
  const dirname$1 = path.dirname(fileURLToPath(import.meta.url));
456
429
  const pkgRoot = path.resolve(dirname$1, "..");
430
+ /**
431
+ * Build a single configuration, without watch and shortcuts features.
432
+ *
433
+ * @param config Resolved options
434
+ */
457
435
  async function buildSingle(config) {
458
436
  const { outDir, format: formats, clean, dts, watch, onSuccess } = config;
459
437
  let onSuccessCleanup;
@@ -495,13 +473,9 @@ async function buildSingle(config) {
495
473
  }
496
474
  }
497
475
  async function getBuildOptions(config, pkg, format, cjsDts) {
498
- const { entry, external, plugins: userPlugins, outDir, platform, alias, treeshake, sourcemap, dts, minify, unused, target, define, shims, tsconfig } = config;
476
+ const { entry, external, plugins: userPlugins, outDir, platform, alias, treeshake, sourcemap, dts, minify, unused, target, define, shims, tsconfig, cwd } = config;
499
477
  const plugins = [];
500
478
  if (pkg || config.skipNodeModulesBundle) plugins.push(ExternalPlugin(config, pkg));
501
- if (unused && !cjsDts) {
502
- const { Unused } = await import("unplugin-unused");
503
- plugins.push(Unused.rolldown(unused === true ? {} : unused));
504
- }
505
479
  if (dts) {
506
480
  const { dts: dtsPlugin } = await import("rolldown-plugin-dts");
507
481
  const options = {
@@ -514,13 +488,22 @@ async function getBuildOptions(config, pkg, format, cjsDts) {
514
488
  emitDtsOnly: true
515
489
  }));
516
490
  }
517
- if (target && !cjsDts) plugins.push(transformPlugin({
518
- target: target && (typeof target === "string" ? target : target.join(",")),
519
- exclude: /\.d\.[cm]?ts$/
520
- }));
491
+ if (!cjsDts) {
492
+ if (unused) {
493
+ const { Unused } = await import("unplugin-unused");
494
+ plugins.push(Unused.rolldown(unused === true ? {} : unused));
495
+ }
496
+ if (target) plugins.push(transformPlugin({
497
+ include: /\.[cm]?[jt]sx?$/,
498
+ exclude: /\.d\.[cm]?ts$/,
499
+ transformOptions: { target }
500
+ }));
501
+ plugins.push(ShebangPlugin(cwd));
502
+ }
521
503
  plugins.push(userPlugins);
522
504
  const inputOptions = await mergeUserOptions({
523
505
  input: entry,
506
+ cwd,
524
507
  external,
525
508
  resolve: {
526
509
  alias,
@@ -1,9 +1,12 @@
1
1
  import process from "node:process";
2
2
  import Debug from "debug";
3
- import { consola as consola$1 } from "consola";
3
+ import { consola } from "consola";
4
4
 
5
5
  //#region src/utils/logger.ts
6
- const logger = consola$1.withTag("tsdown");
6
+ /**
7
+ * Logger instance
8
+ */
9
+ const logger = consola.withTag("tsdown");
7
10
  const debug = Debug("tsdown");
8
11
  function setSilent(silent) {
9
12
  if (!("CONSOLA_LEVEL" in process.env)) logger.level = silent ? 0 : 3;
@@ -1,16 +1,16 @@
1
- import { version } from "./package-BnNFONow.js";
1
+ import { version } from "./package-DTByKj86.js";
2
2
  import process from "node:process";
3
3
  import { readFile, unlink, writeFile } from "node:fs/promises";
4
- import consola from "consola";
4
+ import consola$1 from "consola";
5
5
  import { existsSync } from "node:fs";
6
6
 
7
7
  //#region src/migrate.ts
8
8
  async function migrate({ cwd, dryRun }) {
9
- if (dryRun) consola.info("Dry run enabled. No changes were made.");
9
+ if (dryRun) consola$1.info("Dry run enabled. No changes were made.");
10
10
  else {
11
- const confirm = await consola.prompt("Please make sure to commit your changes before migrating. Continue?", { type: "confirm" });
11
+ const confirm = await consola$1.prompt("Please make sure to commit your changes before migrating. Continue?", { type: "confirm" });
12
12
  if (!confirm) {
13
- consola.error("Migration cancelled.");
13
+ consola$1.error("Migration cancelled.");
14
14
  process.exitCode = 1;
15
15
  return;
16
16
  }
@@ -18,15 +18,15 @@ async function migrate({ cwd, dryRun }) {
18
18
  if (cwd) process.chdir(cwd);
19
19
  let migrated = await migratePackageJson(dryRun);
20
20
  if (await migrateTsupConfig(dryRun)) migrated = true;
21
- if (migrated) consola.success("Migration completed. Remember to run install command with your package manager.");
21
+ if (migrated) consola$1.success("Migration completed. Remember to run install command with your package manager.");
22
22
  else {
23
- consola.error("No migration performed.");
23
+ consola$1.error("No migration performed.");
24
24
  process.exitCode = 1;
25
25
  }
26
26
  }
27
27
  async function migratePackageJson(dryRun) {
28
28
  if (!existsSync("package.json")) {
29
- consola.error("No package.json found");
29
+ consola$1.error("No package.json found");
30
30
  return false;
31
31
  }
32
32
  const pkgRaw = await readFile("package.json", "utf-8");
@@ -34,44 +34,44 @@ async function migratePackageJson(dryRun) {
34
34
  const semver = `^${version}`;
35
35
  let found = false;
36
36
  if (pkg.dependencies?.tsup) {
37
- consola.info("Migrating `dependencies` to tsdown.");
37
+ consola$1.info("Migrating `dependencies` to tsdown.");
38
38
  found = true;
39
39
  pkg.dependencies = renameKey(pkg.dependencies, "tsup", "tsdown", semver);
40
40
  }
41
41
  if (pkg.devDependencies?.tsup) {
42
- consola.info("Migrating `devDependencies` to tsdown.");
42
+ consola$1.info("Migrating `devDependencies` to tsdown.");
43
43
  found = true;
44
44
  pkg.devDependencies = renameKey(pkg.devDependencies, "tsup", "tsdown", semver);
45
45
  }
46
46
  if (pkg.peerDependencies?.tsup) {
47
- consola.info("Migrating `peerDependencies` to tsdown.");
47
+ consola$1.info("Migrating `peerDependencies` to tsdown.");
48
48
  found = true;
49
49
  pkg.peerDependencies = renameKey(pkg.peerDependencies, "tsup", "tsdown", "*");
50
50
  }
51
51
  if (pkg.scripts) {
52
52
  for (const key of Object.keys(pkg.scripts)) if (pkg.scripts[key].includes("tsup")) {
53
- consola.info(`Migrating \`${key}\` script to tsdown`);
53
+ consola$1.info(`Migrating \`${key}\` script to tsdown`);
54
54
  found = true;
55
55
  pkg.scripts[key] = pkg.scripts[key].replaceAll(/tsup(?:-node)?/g, "tsdown");
56
56
  }
57
57
  }
58
58
  if (pkg.tsup) {
59
- consola.info("Migrating `tsup` field in package.json to `tsdown`.");
59
+ consola$1.info("Migrating `tsup` field in package.json to `tsdown`.");
60
60
  found = true;
61
61
  pkg = renameKey(pkg, "tsup", "tsdown");
62
62
  }
63
63
  if (!found) {
64
- consola.warn("No tsup-related fields found in package.json");
64
+ consola$1.warn("No tsup-related fields found in package.json");
65
65
  return false;
66
66
  }
67
67
  const pkgStr = `${JSON.stringify(pkg, null, 2)}\n`;
68
68
  if (dryRun) {
69
69
  const { createPatch } = await import("diff");
70
- consola.info("[dry-run] package.json:");
70
+ consola$1.info("[dry-run] package.json:");
71
71
  console.info(createPatch("package.json", pkgRaw, pkgStr));
72
72
  } else {
73
73
  await writeFile("package.json", pkgStr);
74
- consola.success("Migrated `package.json`");
74
+ consola$1.success("Migrated `package.json`");
75
75
  }
76
76
  return true;
77
77
  }
@@ -88,22 +88,22 @@ async function migrateTsupConfig(dryRun) {
88
88
  let found = false;
89
89
  for (const file of TSUP_FILES) {
90
90
  if (!existsSync(file)) continue;
91
- consola.info(`Found \`${file}\``);
91
+ consola$1.info(`Found \`${file}\``);
92
92
  found = true;
93
93
  const tsupConfigRaw = await readFile(file, "utf-8");
94
94
  const tsupConfig = tsupConfigRaw.replaceAll(/\btsup\b/g, "tsdown").replaceAll(/\bTSUP\b/g, "TSDOWN");
95
95
  const renamed = file.replaceAll("tsup", "tsdown");
96
96
  if (dryRun) {
97
97
  const { createTwoFilesPatch } = await import("diff");
98
- consola.info(`[dry-run] ${file} -> ${renamed}:`);
98
+ consola$1.info(`[dry-run] ${file} -> ${renamed}:`);
99
99
  console.info(createTwoFilesPatch(file, renamed, tsupConfigRaw, tsupConfig));
100
100
  } else {
101
101
  await writeFile(renamed, tsupConfig, "utf8");
102
102
  await unlink(file);
103
- consola.success(`Migrated \`${file}\` to \`${renamed}\``);
103
+ consola$1.success(`Migrated \`${file}\` to \`${renamed}\``);
104
104
  }
105
105
  }
106
- if (!found) consola.warn("No tsup config found");
106
+ if (!found) consola$1.warn("No tsup config found");
107
107
  return found;
108
108
  }
109
109
  function renameKey(obj, oldKey, newKey, newValue) {
@@ -1,11 +1,25 @@
1
- import { ExternalOption, InputOptions, InternalModuleFormat, ModuleFormat, OutputOptions } from "rolldown";
1
+ import { ExternalOption, InputOption, InputOptions, InternalModuleFormat, ModuleFormat, OutputOptions } from "rolldown";
2
2
  import { Options } from "publint";
3
3
  import { Options as Options$1 } from "rolldown-plugin-dts";
4
4
  import { Options as Options$2 } from "unplugin-unused";
5
5
  import { PackageJson } from "pkg-types";
6
6
 
7
7
  //#region src/utils/package.d.ts
8
- type PackageType = "module" | "commonjs";
8
+ type PackageType = "module" | "commonjs" | undefined;
9
+
10
+ //#endregion
11
+ //#region src/features/output.d.ts
12
+ interface OutExtensionContext {
13
+ options: InputOptions;
14
+ format: NormalizedFormat;
15
+ /** "type" field in project's package.json */
16
+ pkgType?: PackageType;
17
+ }
18
+ interface OutExtensionObject {
19
+ js?: string;
20
+ dts?: string;
21
+ }
22
+ type OutExtensionFactory = (ctx: OutExtensionContext) => OutExtensionObject;
9
23
 
10
24
  //#endregion
11
25
  //#region src/utils/types.d.ts
@@ -23,22 +37,14 @@ type Arrayable<T> = T | T[];
23
37
  //#endregion
24
38
  //#region src/options.d.ts
25
39
  type Sourcemap = boolean | "inline" | "hidden";
26
- interface OutExtensionContext {
27
- options: InputOptions;
28
- format: NormalizedFormat;
29
- /** "type" field in project's package.json */
30
- pkgType: PackageType;
31
- }
32
- interface OutExtensionObject {
33
- js?: string;
34
- dts?: string;
35
- }
36
- type OutExtensionFactory = (ctx: OutExtensionContext) => OutExtensionObject;
40
+ /**
41
+ * Options for tsdown.
42
+ */
37
43
  /**
38
44
  * Options for tsdown.
39
45
  */
40
46
  interface Options$3 {
41
- entry?: InputOptions["input"];
47
+ entry?: InputOption;
42
48
  external?: ExternalOption;
43
49
  noExternal?: Arrayable<string | RegExp> | ((id: string, importer: string | undefined) => boolean | null | undefined | void);
44
50
  alias?: Record<string, string>;
@@ -46,8 +52,10 @@ interface Options$3 {
46
52
  /** @default 'node' */
47
53
  platform?: "node" | "neutral" | "browser";
48
54
  inputOptions?: InputOptions | ((options: InputOptions, format: NormalizedFormat) => Awaitable<InputOptions | void | null>);
55
+ /** @default 'es' */
49
56
  format?: ModuleFormat | ModuleFormat[];
50
57
  globalName?: string;
58
+ /** @default 'dist' */
51
59
  outDir?: string;
52
60
  sourcemap?: Sourcemap;
53
61
  clean?: boolean | string[];
@@ -55,13 +63,28 @@ interface Options$3 {
55
63
  minify?: boolean;
56
64
  target?: string | string[];
57
65
  define?: Record<string, string>;
66
+ /** @default false */
58
67
  shims?: boolean;
68
+ /**
69
+ * Use a fixed extension for output files.
70
+ * The extension will always be `.cjs` or `.mjs`.
71
+ * Otherwise, it will depend on the package type.
72
+ * @default false
73
+ */
74
+ fixedExtension?: boolean;
75
+ /**
76
+ * Custom extensions for output files.
77
+ * `fixedExtension` will be overridden by this option.
78
+ */
59
79
  outExtensions?: OutExtensionFactory;
60
80
  outputOptions?: OutputOptions | ((options: OutputOptions, format: NormalizedFormat) => Awaitable<OutputOptions | void | null>);
61
81
  /** @default true */
62
82
  treeshake?: boolean;
63
83
  plugins?: InputOptions["plugins"];
64
84
  silent?: boolean;
85
+ /**
86
+ * Config file path
87
+ */
65
88
  config?: boolean | string;
66
89
  watch?: boolean | string | string[];
67
90
  /**
@@ -73,19 +96,12 @@ interface Options$3 {
73
96
  */
74
97
  skipNodeModulesBundle?: boolean;
75
98
  /**
76
- * Use a fixed extension for output files.
77
- * The extension will always be `.cjs` or `.mjs`.
78
- * Otherwise, it will depend on the package type.
79
- * @default false
80
- */
81
- fixedExtension?: boolean;
82
- /**
83
99
  * Reuse config from Vite or Vitest (experimental)
84
100
  * @default false
85
101
  */
86
102
  fromVite?: boolean | "vitest";
87
103
  /**
88
- * Enable dts generation with `isolatedDeclarations` (experimental)
104
+ * Emit declaration files
89
105
  */
90
106
  dts?: boolean | Options$1;
91
107
  /**
@@ -102,6 +118,9 @@ interface Options$3 {
102
118
  /**
103
119
  * Options without specifying config file path.
104
120
  */
121
+ /**
122
+ * Options without specifying config file path.
123
+ */
105
124
  type UserConfig = Arrayable<Omit<Options$3, "config">>;
106
125
  type NormalizedFormat = Exclude<InternalModuleFormat, "app"> | "experimental-app";
107
126
  type ResolvedOptions = Omit<Overwrite<MarkPartial<Options$3, "globalName" | "inputOptions" | "outputOptions" | "minify" | "target" | "define" | "alias" | "external" | "noExternal" | "onSuccess" | "dts" | "fixedExtension" | "outExtensions">, {
@@ -109,6 +128,7 @@ type ResolvedOptions = Omit<Overwrite<MarkPartial<Options$3, "globalName" | "inp
109
128
  clean: string[] | false
110
129
  dts: false | Options$1
111
130
  tsconfig: string | false
131
+ cwd: string
112
132
  }>, "config" | "fromVite">;
113
133
 
114
134
  //#endregion
@@ -0,0 +1,5 @@
1
+ //#region package.json
2
+ var version = "0.9.2";
3
+
4
+ //#endregion
5
+ export { version };
@@ -0,0 +1,117 @@
1
+ import { logger } from "./logger-Dt3D6T-U.js";
2
+ import path, { dirname, normalize, sep } from "node:path";
3
+ import { access, chmod, rm } from "node:fs/promises";
4
+ import Debug from "debug";
5
+ import { underline } from "ansis";
6
+
7
+ //#region src/utils/fs.ts
8
+ function fsExists(path$1) {
9
+ return access(path$1).then(() => true, () => false);
10
+ }
11
+ function fsRemove(path$1) {
12
+ return rm(path$1, {
13
+ force: true,
14
+ recursive: true
15
+ }).catch(() => {});
16
+ }
17
+ function lowestCommonAncestor(...filepaths) {
18
+ if (filepaths.length === 0) return "";
19
+ if (filepaths.length === 1) return dirname(filepaths[0]);
20
+ filepaths = filepaths.map(normalize);
21
+ const [first, ...rest] = filepaths;
22
+ let ancestor = first.split(sep);
23
+ for (const filepath of rest) {
24
+ const directories = filepath.split(sep, ancestor.length);
25
+ let index = 0;
26
+ for (const directory of directories) if (directory === ancestor[index]) index += 1;
27
+ else {
28
+ ancestor = ancestor.slice(0, index);
29
+ break;
30
+ }
31
+ ancestor = ancestor.slice(0, index);
32
+ }
33
+ return ancestor.length <= 1 && ancestor[0] === "" ? sep + ancestor[0] : ancestor.join(sep);
34
+ }
35
+
36
+ //#endregion
37
+ //#region src/utils/general.ts
38
+ function toArray(val, defaultValue) {
39
+ if (Array.isArray(val)) return val;
40
+ else if (val == null) {
41
+ if (defaultValue) return [defaultValue];
42
+ return [];
43
+ } else return [val];
44
+ }
45
+ function debounce(fn, wait) {
46
+ let timeout;
47
+ return function(...args) {
48
+ if (timeout) clearTimeout(timeout);
49
+ timeout = setTimeout(() => {
50
+ timeout = void 0;
51
+ fn.apply(this, args);
52
+ }, wait);
53
+ };
54
+ }
55
+
56
+ //#endregion
57
+ //#region src/features/external.ts
58
+ const debug = Debug("tsdown:external");
59
+ const RE_DTS = /\.d\.[cm]?ts$/;
60
+ function ExternalPlugin(options, pkg) {
61
+ const deps = pkg && Array.from(getProductionDeps(pkg));
62
+ return {
63
+ name: "tsdown:external",
64
+ async resolveId(id, importer, { isEntry }) {
65
+ if (isEntry) return;
66
+ if (importer && RE_DTS.test(importer)) return;
67
+ const { noExternal } = options;
68
+ if (typeof noExternal === "function" && noExternal(id, importer)) return;
69
+ if (noExternal) {
70
+ const noExternalPatterns = toArray(noExternal);
71
+ if (noExternalPatterns.some((pattern) => {
72
+ return pattern instanceof RegExp ? pattern.test(id) : id === pattern;
73
+ })) return;
74
+ }
75
+ let shouldExternal = false;
76
+ if (options.skipNodeModulesBundle) {
77
+ const resolved = await this.resolve(id);
78
+ if (!resolved) return;
79
+ shouldExternal = resolved.external || /[\\/]node_modules[\\/]/.test(resolved.id);
80
+ }
81
+ if (deps) shouldExternal ||= deps.some((dep) => id === dep || id.startsWith(`${dep}/`));
82
+ if (shouldExternal) {
83
+ debug("External dependency:", id);
84
+ return {
85
+ id,
86
+ external: shouldExternal
87
+ };
88
+ }
89
+ }
90
+ };
91
+ }
92
+ function getProductionDeps(pkg) {
93
+ return new Set([...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})]);
94
+ }
95
+
96
+ //#endregion
97
+ //#region src/features/shebang.ts
98
+ const RE_SHEBANG = /^#!.*/;
99
+ function ShebangPlugin(cwd) {
100
+ return {
101
+ name: "tsdown:shebang",
102
+ async writeBundle(options, bundle) {
103
+ for (const chunk of Object.values(bundle)) {
104
+ if (chunk.type !== "chunk" || !chunk.isEntry) continue;
105
+ if (!RE_SHEBANG.test(chunk.code)) continue;
106
+ const filepath = path.resolve(cwd, options.file || path.join(options.dir, chunk.fileName));
107
+ if (await fsExists(filepath)) {
108
+ logger.info(`Granting execute permission to ${underline(path.relative(cwd, filepath))}`);
109
+ await chmod(filepath, 493);
110
+ }
111
+ }
112
+ }
113
+ };
114
+ }
115
+
116
+ //#endregion
117
+ export { ExternalPlugin, ShebangPlugin, debounce, fsExists, fsRemove, lowestCommonAncestor, toArray };
package/dist/plugins.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ResolvedOptions } from "./options.d-BUmkLb5_.js";
1
+ import { ResolvedOptions } from "./options.d-DxODs1UG.js";
2
2
  import { Plugin } from "rolldown";
3
3
  import { PackageJson } from "pkg-types";
4
4
 
@@ -6,4 +6,8 @@ import { PackageJson } from "pkg-types";
6
6
  declare function ExternalPlugin(options: ResolvedOptions, pkg?: PackageJson): Plugin;
7
7
 
8
8
  //#endregion
9
- export { ExternalPlugin };
9
+ //#region src/features/shebang.d.ts
10
+ declare function ShebangPlugin(cwd: string): Plugin;
11
+
12
+ //#endregion
13
+ export { ExternalPlugin, ShebangPlugin };
package/dist/plugins.js CHANGED
@@ -1,3 +1,4 @@
1
- import { ExternalPlugin } from "./external-DvQ4QDcG.js";
1
+ import { ExternalPlugin, ShebangPlugin } from "./plugins-CATHxFm7.js";
2
+ import "./logger-Dt3D6T-U.js";
2
3
 
3
- export { ExternalPlugin };
4
+ export { ExternalPlugin, ShebangPlugin };
package/dist/run.js CHANGED
@@ -1,5 +1,6 @@
1
- import { logger, setSilent } from "./logger-4bmpqibt.js";
2
- import { version } from "./package-BnNFONow.js";
1
+ #!/usr/bin/env node
2
+ import { logger, setSilent } from "./logger-Dt3D6T-U.js";
3
+ import { version } from "./package-DTByKj86.js";
3
4
  import process from "node:process";
4
5
  import { VERSION } from "rolldown";
5
6
  import { dim } from "ansis";
@@ -16,7 +17,7 @@ cli.command("[...files]", "Bundle files", { ignoreOptionDefaultValue: true }).op
16
17
  await build$1(flags);
17
18
  });
18
19
  cli.command("migrate", "Migrate from tsup to tsdown").option("-c, --cwd <dir>", "Working directory").option("-d, --dry-run", "Dry run").action(async (args) => {
19
- const { migrate } = await import("./migrate-D8koNtWX.js");
20
+ const { migrate } = await import("./migrate-M59yd0BY.js");
20
21
  await migrate(args);
21
22
  });
22
23
  async function runCLI() {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tsdown",
3
- "version": "0.9.0",
4
- "description": "Smooth and fast library bundler powered by Rolldown.",
3
+ "version": "0.9.2",
4
+ "description": "The Elegant Bundler for Libraries",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/rolldown/tsdown#readme",
@@ -36,7 +36,7 @@
36
36
  }
37
37
  },
38
38
  "bin": {
39
- "tsdown": "./bin/tsdown.js"
39
+ "tsdown": "./dist/run.js"
40
40
  },
41
41
  "publishConfig": {
42
42
  "access": "public"
@@ -61,19 +61,20 @@
61
61
  "debug": "^4.4.0",
62
62
  "diff": "^7.0.0",
63
63
  "find-up-simple": "^1.0.1",
64
- "rolldown": "^1.0.0-beta.7",
64
+ "rolldown": "1.0.0-beta.7-commit.c2596d3",
65
65
  "rolldown-plugin-dts": "^0.8.0",
66
66
  "tinyexec": "^1.0.1",
67
67
  "tinyglobby": "^0.2.12",
68
68
  "unconfig": "^7.3.1"
69
69
  },
70
70
  "devDependencies": {
71
- "@sxzz/eslint-config": "^6.1.1",
71
+ "@sxzz/eslint-config": "^6.1.2",
72
72
  "@sxzz/prettier-config": "^2.2.1",
73
73
  "@sxzz/test-utils": "^0.5.5",
74
74
  "@types/debug": "^4.1.12",
75
75
  "@types/diff": "^7.0.2",
76
76
  "@types/node": "^22.14.1",
77
+ "@unocss/eslint-plugin": "^66.1.0-beta.12",
77
78
  "bumpp": "^10.1.0",
78
79
  "eslint": "^9.25.0",
79
80
  "pkg-types": "^2.1.0",
@@ -81,11 +82,17 @@
81
82
  "publint": "^0.3.12",
82
83
  "tsup": "^8.4.0",
83
84
  "tsx": "^4.19.3",
85
+ "typedoc": "^0.28.2",
86
+ "typedoc-plugin-markdown": "^4.6.2",
84
87
  "typescript": "~5.8.3",
85
- "unplugin-ast": "^0.14.6",
88
+ "unocss": "^66.1.0-beta.12",
86
89
  "unplugin-unused": "^0.4.4",
87
90
  "vite": "^6.3.2",
88
- "vitest": "^3.1.1"
91
+ "vitepress": "^1.6.3",
92
+ "vitepress-plugin-group-icons": "^1.5.2",
93
+ "vitepress-plugin-llms": "^1.1.0",
94
+ "vitest": "^3.1.1",
95
+ "vue": "^3.5.13"
89
96
  },
90
97
  "engines": {
91
98
  "node": ">=18.0.0"
@@ -99,6 +106,10 @@
99
106
  "test": "vitest",
100
107
  "typecheck": "tsc --noEmit",
101
108
  "format": "prettier --cache --write .",
102
- "release": "bumpp && pnpm publish"
109
+ "release": "bumpp && pnpm publish",
110
+ "docs:dev": "vitepress dev docs",
111
+ "docs:build": "vitepress build docs",
112
+ "docs:preview": "vitepress preview docs",
113
+ "docs:generate": "./docs/.vitepress/scripts/docs-generate.sh"
103
114
  }
104
115
  }
package/bin/tsdown.js DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import '../dist/run.js'
@@ -1,63 +0,0 @@
1
- import Debug from "debug";
2
-
3
- //#region src/utils/general.ts
4
- function toArray(val, defaultValue) {
5
- if (Array.isArray(val)) return val;
6
- else if (val == null) {
7
- if (defaultValue) return [defaultValue];
8
- return [];
9
- } else return [val];
10
- }
11
- function debounce(fn, wait) {
12
- let timeout;
13
- return function(...args) {
14
- if (timeout) clearTimeout(timeout);
15
- timeout = setTimeout(() => {
16
- timeout = void 0;
17
- fn.apply(this, args);
18
- }, wait);
19
- };
20
- }
21
-
22
- //#endregion
23
- //#region src/features/external.ts
24
- const debug = Debug("tsdown:external");
25
- const RE_DTS = /\.d\.[cm]?ts$/;
26
- function ExternalPlugin(options, pkg) {
27
- const deps = pkg && Array.from(getProductionDeps(pkg));
28
- return {
29
- name: "tsdown:external",
30
- async resolveId(id, importer, { isEntry }) {
31
- if (isEntry) return;
32
- if (importer && RE_DTS.test(importer)) return;
33
- const { noExternal } = options;
34
- if (typeof noExternal === "function" && noExternal(id, importer)) return;
35
- if (noExternal) {
36
- const noExternalPatterns = toArray(noExternal);
37
- if (noExternalPatterns.some((pattern) => {
38
- return pattern instanceof RegExp ? pattern.test(id) : id === pattern;
39
- })) return;
40
- }
41
- let shouldExternal = false;
42
- if (options.skipNodeModulesBundle) {
43
- const resolved = await this.resolve(id);
44
- if (!resolved) return;
45
- shouldExternal = resolved.external || /[\\/]node_modules[\\/]/.test(resolved.id);
46
- }
47
- if (deps) shouldExternal ||= deps.some((dep) => id === dep || id.startsWith(`${dep}/`));
48
- if (shouldExternal) {
49
- debug("External dependency:", id);
50
- return {
51
- id,
52
- external: shouldExternal
53
- };
54
- }
55
- }
56
- };
57
- }
58
- function getProductionDeps(pkg) {
59
- return new Set([...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})]);
60
- }
61
-
62
- //#endregion
63
- export { ExternalPlugin, debounce, toArray };
@@ -1,6 +0,0 @@
1
-
2
- //#region package.json
3
- var version = "0.9.0";
4
-
5
- //#endregion
6
- export { version };