tsdown 0.15.12 → 0.16.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.
@@ -1,6 +1,6 @@
1
1
  import { createRequire as __cjs_createRequire } from "node:module";
2
2
  const __cjs_require = __cjs_createRequire(import.meta.url);
3
- import { a as globalLogger, c as debounce, d as resolveComma, f as resolveRegex, i as generateColor, l as matchPattern, m as toArray, n as LogLevels, o as prettyFormat, p as slash, r as createLogger, s as prettyName, t as version, u as noop } from "./package-qYegZAPv.mjs";
3
+ import { a as globalLogger, c as debounce, d as noop, f as pkgExists, g as toArray, h as slash, i as generateColor, l as importWithError, m as resolveRegex, n as LogLevels, o as prettyFormat, p as resolveComma, r as createLogger, s as prettyName, t as version, u as matchPattern } from "./package-BEpC3UYZ.mjs";
4
4
  import { builtinModules, isBuiltin } from "node:module";
5
5
  import path, { dirname, join, normalize, sep } from "node:path";
6
6
  import process from "node:process";
@@ -9,21 +9,20 @@ import { blue, bold, dim, green, underline } from "ansis";
9
9
  import { VERSION, build } from "rolldown";
10
10
  import { exec } from "tinyexec";
11
11
  const treeKill = __cjs_require("tree-kill");
12
- import child_process from "node:child_process";
13
12
  import { access, chmod, cp, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
14
- import { tmpdir } from "node:os";
15
- import util, { promisify } from "node:util";
16
13
  const Debug = __cjs_require("debug");
17
- const coerce = __cjs_require("semver/functions/coerce.js");
18
- const satisfies = __cjs_require("semver/functions/satisfies.js");
14
+ import { createConfigCoreLoader } from "unconfig-core";
19
15
  import { glob } from "tinyglobby";
20
16
  import { RE_CSS, RE_DTS, RE_JS, RE_NODE_MODULES } from "rolldown-plugin-dts/filename";
21
- import { createHooks } from "hookable";
22
- import { importGlobPlugin } from "rolldown/experimental";
23
17
  const minVersion = __cjs_require("semver/ranges/min-version.js");
24
18
  import { up } from "empathic/find";
25
19
  import { up as up$1 } from "empathic/package";
26
- import { loadConfig } from "unconfig";
20
+ import { tmpdir } from "node:os";
21
+ const coerce = __cjs_require("semver/functions/coerce.js");
22
+ const satisfies = __cjs_require("semver/functions/satisfies.js");
23
+ import { createHooks } from "hookable";
24
+ import util, { promisify } from "node:util";
25
+ import { importGlobPlugin } from "rolldown/experimental";
27
26
  import { Buffer } from "node:buffer";
28
27
  import { brotliCompress, gzip } from "node:zlib";
29
28
  import readline from "node:readline";
@@ -68,114 +67,143 @@ function lowestCommonAncestor(...filepaths) {
68
67
  }
69
68
 
70
69
  //#endregion
71
- //#region src/features/attw.ts
72
- const debug$7 = Debug("tsdown:attw");
73
- const exec$1 = promisify(child_process.exec);
74
- /**
75
- * ATTW profiles.
76
- * Defines the resolution modes to ignore for each profile.
77
- *
78
- * @see https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/packages/cli/README.md#profiles
79
- */
80
- const profiles = {
81
- strict: [],
82
- node16: ["node10"],
83
- esmOnly: ["node10", "node16-cjs"]
84
- };
85
- /**
86
- * Format an ATTW problem for display
87
- */
88
- function formatProblem(problem) {
89
- const resolutionKind = "resolutionKind" in problem ? ` (${problem.resolutionKind})` : "";
90
- const entrypoint = "entrypoint" in problem ? ` at ${problem.entrypoint}` : "";
91
- switch (problem.kind) {
92
- case "NoResolution": return ` ❌ No resolution${resolutionKind}${entrypoint}`;
93
- case "UntypedResolution": return ` ⚠️ Untyped resolution${resolutionKind}${entrypoint}`;
94
- case "FalseESM": return ` 🔄 False ESM: Types indicate ESM (${problem.typesModuleKind}) but implementation is CJS (${problem.implementationModuleKind})\n Types: ${problem.typesFileName} | Implementation: ${problem.implementationFileName}`;
95
- case "FalseCJS": return ` 🔄 False CJS: Types indicate CJS (${problem.typesModuleKind}) but implementation is ESM (${problem.implementationModuleKind})\n Types: ${problem.typesFileName} | Implementation: ${problem.implementationFileName}`;
96
- case "CJSResolvesToESM": return ` CJS resolves to ESM${resolutionKind}${entrypoint}`;
97
- case "NamedExports": {
98
- const missingExports = problem.missing?.length > 0 ? ` Missing: ${problem.missing.join(", ")}` : "";
99
- return ` 📤 Named exports problem${problem.isMissingAllNamed ? " (all named exports missing)" : ""}${missingExports}\n Types: ${problem.typesFileName} | Implementation: ${problem.implementationFileName}`;
100
- }
101
- case "FallbackCondition": return ` 🎯 Fallback condition used${resolutionKind}${entrypoint}`;
102
- case "FalseExportDefault": return ` 🎭 False export default\n Types: ${problem.typesFileName} | Implementation: ${problem.implementationFileName}`;
103
- case "MissingExportEquals": return ` 📝 Missing export equals\n Types: ${problem.typesFileName} | Implementation: ${problem.implementationFileName}`;
104
- case "InternalResolutionError": return ` 💥 Internal resolution error in ${problem.fileName} (${problem.resolutionOption})\n Module: ${problem.moduleSpecifier} | Mode: ${problem.resolutionMode}`;
105
- case "UnexpectedModuleSyntax": return ` 📋 Unexpected module syntax in ${problem.fileName}\n Expected: ${problem.moduleKind} | Found: ${problem.syntax === 99 ? "ESM" : "CJS"}`;
106
- case "CJSOnlyExportsDefault": return ` 🏷️ CJS only exports default in ${problem.fileName}`;
107
- default: return ` ❓ Unknown problem: ${JSON.stringify(problem)}`;
108
- }
70
+ //#region src/config/config.ts
71
+ const debug$8 = Debug("tsdown:config");
72
+ async function loadViteConfig(prefix, cwd, configLoader) {
73
+ const loader = resolveConfigLoader(configLoader);
74
+ debug$8("Loading Vite config via loader: ", loader);
75
+ const parser = createParser(loader);
76
+ const [result] = await createConfigCoreLoader({
77
+ sources: [{
78
+ files: [`${prefix}.config`],
79
+ extensions: [
80
+ "ts",
81
+ "mts",
82
+ "cts",
83
+ "js",
84
+ "mjs",
85
+ "cjs",
86
+ "json",
87
+ ""
88
+ ],
89
+ parser
90
+ }],
91
+ cwd
92
+ }).load();
93
+ if (!result) return;
94
+ const { config, source } = result;
95
+ globalLogger.info(`Using Vite config: ${underline(source)}`);
96
+ const resolved = await config;
97
+ if (typeof resolved === "function") return resolved({
98
+ command: "build",
99
+ mode: "production"
100
+ });
101
+ return resolved;
109
102
  }
110
- async function attw(options) {
111
- if (!options.attw) return;
112
- if (!options.pkg) {
113
- options.logger.warn("attw is enabled but package.json is not found");
114
- return;
115
- }
116
- const { profile = "strict", level = "warn",...attwOptions } = options.attw === true ? {} : options.attw;
117
- const t = performance.now();
118
- debug$7("Running attw check");
119
- const tempDir = await mkdtemp(path.join(tmpdir(), "tsdown-attw-"));
120
- let attwCore;
121
- try {
122
- attwCore = await import("@arethetypeswrong/core");
123
- } catch {
124
- options.logger.error(`ATTW check requires ${blue`@arethetypeswrong/core`} to be installed.`);
125
- return;
103
+ const configPrefix = "tsdown.config";
104
+ let isWatch = false;
105
+ function setWatch() {
106
+ isWatch = true;
107
+ }
108
+ async function loadConfigFile(inlineConfig, workspace) {
109
+ let cwd = inlineConfig.cwd || process.cwd();
110
+ let overrideConfig = false;
111
+ let { config: filePath } = inlineConfig;
112
+ if (filePath === false) return { configs: [{}] };
113
+ if (typeof filePath === "string") {
114
+ const stats = await fsStat(filePath);
115
+ if (stats) {
116
+ const resolved = path.resolve(filePath);
117
+ if (stats.isFile()) {
118
+ overrideConfig = true;
119
+ filePath = resolved;
120
+ cwd = path.dirname(filePath);
121
+ } else if (stats.isDirectory()) cwd = resolved;
122
+ }
126
123
  }
127
- try {
128
- const { stdout: tarballInfo } = await exec$1(`npm pack --json ----pack-destination ${tempDir}`, {
129
- encoding: "utf8",
130
- cwd: options.cwd
131
- });
132
- const parsed = JSON.parse(tarballInfo);
133
- if (!Array.isArray(parsed) || !parsed[0]?.filename) throw new Error("Invalid npm pack output format");
134
- const tarball = await readFile(path.join(tempDir, parsed[0].filename));
135
- const pkg = attwCore.createPackageFromTarballData(tarball);
136
- const checkResult = await attwCore.checkPackage(pkg, attwOptions);
137
- if (checkResult.types !== false && checkResult.problems.length) {
138
- const problems = checkResult.problems.filter((problem) => {
139
- if ("resolutionKind" in problem) return !profiles[profile]?.includes(problem.resolutionKind);
140
- return true;
141
- });
142
- if (problems.length) {
143
- const problemMessage = `Are the types wrong problems found:\n${problems.map(formatProblem).join("\n")}`;
144
- if (level === "error") throw new Error(problemMessage);
145
- options.logger.warn(problemMessage);
146
- }
147
- } else options.logger.success(`No Are the types wrong problems found`, dim`(${Math.round(performance.now() - t)}ms)`);
148
- } catch (error) {
149
- options.logger.error("ATTW check failed:", error);
150
- debug$7("Found errors, setting exit code to 1");
151
- process.exitCode = 1;
152
- } finally {
153
- await fsRemove(tempDir);
124
+ const loader = resolveConfigLoader(inlineConfig.configLoader);
125
+ debug$8("Using config loader:", loader);
126
+ const parser = createParser(loader);
127
+ const [result] = await createConfigCoreLoader({
128
+ sources: overrideConfig ? [{
129
+ files: [filePath],
130
+ extensions: [],
131
+ parser
132
+ }] : [{
133
+ files: [configPrefix],
134
+ extensions: [
135
+ "ts",
136
+ "mts",
137
+ "cts",
138
+ "js",
139
+ "mjs",
140
+ "cjs",
141
+ "json",
142
+ ""
143
+ ],
144
+ parser
145
+ }, {
146
+ files: ["package.json"],
147
+ parser
148
+ }],
149
+ cwd,
150
+ stopAt: workspace && path.dirname(workspace)
151
+ }).load(isWatch);
152
+ let exported = [];
153
+ let file;
154
+ if (result) {
155
+ ({config: exported, source: file} = result);
156
+ globalLogger.info(`Using tsdown config: ${underline(file)}`);
157
+ exported = await exported;
158
+ if (typeof exported === "function") exported = await exported(inlineConfig);
154
159
  }
160
+ exported = toArray(exported);
161
+ if (exported.length === 0) exported.push({});
162
+ return {
163
+ configs: exported,
164
+ file
165
+ };
155
166
  }
156
-
157
- //#endregion
158
- //#region src/features/cjs.ts
159
- /**
160
- * If the config includes the `cjs` format and
161
- * one of its target >= node 23.0.0 / 22.12.0,
162
- * warn the user about the deprecation of CommonJS.
163
- */
164
- function warnLegacyCJS(config) {
165
- if (!config.format.includes("cjs") || !config.target) return;
166
- if (config.target.some((t) => {
167
- const version$1 = coerce(t.split("node")[1]);
168
- return version$1 && satisfies(version$1, ">=23.0.0 || >=22.12.0");
169
- })) config.logger.warnOnce("We recommend using the ESM format instead of CommonJS.\nThe ESM format is compatible with modern platforms and runtimes, and most new libraries are now distributed only in ESM format.\nLearn more at https://nodejs.org/en/learn/modules/publishing-a-package#how-did-we-get-here");
167
+ function resolveConfigLoader(configLoader = "auto") {
168
+ if (isWatch) return "unrun";
169
+ else if (configLoader === "auto") return !!(process.features.typescript || process.versions.bun || process.versions.deno) ? "native" : "unrun";
170
+ else return configLoader === "native" ? "native" : "unrun";
171
+ }
172
+ function createParser(loader) {
173
+ return async (filepath) => {
174
+ const basename = path.basename(filepath);
175
+ const isPkgJson = basename === "package.json";
176
+ if (basename === configPrefix || isPkgJson || basename.endsWith(".json")) {
177
+ const contents = await readFile(filepath, "utf8");
178
+ const parsed = JSON.parse(contents);
179
+ if (isPkgJson) return parsed?.tsdown;
180
+ return parsed;
181
+ }
182
+ if (loader === "native") return nativeImport(filepath);
183
+ return unrunImport(filepath);
184
+ };
185
+ }
186
+ async function nativeImport(id) {
187
+ const mod = await import(pathToFileURL(id).href).catch((error) => {
188
+ if (error?.message?.includes?.("Cannot find module")) throw new Error(`Failed to load the config file. Try setting the --config-loader CLI flag to \`unrun\`.\n\n${error.message}`, { cause: error });
189
+ else throw error;
190
+ });
191
+ return mod.default || mod;
192
+ }
193
+ async function unrunImport(id) {
194
+ const { unrun } = await import("unrun");
195
+ const { module: module$1 } = await unrun({ path: pathToFileURL(id).href });
196
+ return module$1;
170
197
  }
171
198
 
172
199
  //#endregion
173
200
  //#region src/features/clean.ts
174
- const debug$6 = Debug("tsdown:clean");
201
+ const debug$7 = Debug("tsdown:clean");
175
202
  const RE_LAST_SLASH = /[/\\]$/;
176
203
  async function cleanOutDir(configs) {
177
204
  const removes = /* @__PURE__ */ new Set();
178
205
  for (const config of configs) {
206
+ if (config.debug && (config.debug.clean ?? true)) config.clean.push(".rolldown");
179
207
  if (!config.clean.length) continue;
180
208
  const files = await glob(config.clean, {
181
209
  cwd: config.cwd,
@@ -188,10 +216,10 @@ async function cleanOutDir(configs) {
188
216
  if (!removes.size) return;
189
217
  globalLogger.info(`Cleaning ${removes.size} files`);
190
218
  await Promise.all([...removes].map(async (file) => {
191
- debug$6("Removing", file);
219
+ debug$7("Removing", file);
192
220
  await fsRemove(file);
193
221
  }));
194
- debug$6("Removed %d files", removes.size);
222
+ debug$7("Removed %d files", removes.size);
195
223
  }
196
224
  function resolveClean(clean, outDir, cwd) {
197
225
  if (clean === true) clean = [slash(outDir)];
@@ -201,18 +229,32 @@ function resolveClean(clean, outDir, cwd) {
201
229
  }
202
230
 
203
231
  //#endregion
204
- //#region src/features/copy.ts
205
- async function copy(options) {
206
- if (!options.copy) return;
207
- const copy$1 = typeof options.copy === "function" ? await options.copy(options) : options.copy;
208
- await Promise.all(toArray(copy$1).map((dir) => {
209
- const from = typeof dir === "string" ? dir : dir.from;
210
- const to = typeof dir === "string" ? path.resolve(options.outDir, path.basename(from)) : dir.to;
211
- return cp$1(options.cwd, from, to);
212
- }));
232
+ //#region src/features/entry.ts
233
+ async function resolveEntry(logger, entry, cwd, name) {
234
+ const nameLabel = name ? `[${name}] ` : "";
235
+ if (!entry || Object.keys(entry).length === 0) {
236
+ const defaultEntry = path.resolve(cwd, "src/index.ts");
237
+ if (await fsExists(defaultEntry)) entry = { index: defaultEntry };
238
+ else throw new Error(`${nameLabel}No input files, try "tsdown <your-file>" or create src/index.ts`);
239
+ }
240
+ const entryMap = await toObjectEntry(entry, cwd);
241
+ const entries = Object.values(entryMap);
242
+ if (entries.length === 0) throw new Error(`${nameLabel}Cannot find entry: ${JSON.stringify(entry)}`);
243
+ logger.info(prettyName(name), `entry: ${generateColor(name)(entries.map((entry$1) => path.relative(cwd, entry$1)).join(", "))}`);
244
+ return entryMap;
213
245
  }
214
- function cp$1(cwd, from, to) {
215
- return fsCopy(path.resolve(cwd, from), path.resolve(cwd, to));
246
+ async function toObjectEntry(entry, cwd) {
247
+ if (typeof entry === "string") entry = [entry];
248
+ if (!Array.isArray(entry)) return entry;
249
+ const resolvedEntry = (await glob(entry, {
250
+ cwd,
251
+ expandDirectories: false
252
+ })).map((file) => path.resolve(cwd, file));
253
+ const base = lowestCommonAncestor(...resolvedEntry);
254
+ return Object.fromEntries(resolvedEntry.map((file) => {
255
+ const relative = path.relative(base, file);
256
+ return [relative.slice(0, relative.length - path.extname(relative).length), file];
257
+ }));
216
258
  }
217
259
 
218
260
  //#endregion
@@ -334,86 +376,6 @@ function hasExportsTypes(pkg) {
334
376
  return false;
335
377
  }
336
378
 
337
- //#endregion
338
- //#region src/features/hooks.ts
339
- async function createHooks$1(options) {
340
- const hooks = createHooks();
341
- if (typeof options.hooks === "object") hooks.addHooks(options.hooks);
342
- else if (typeof options.hooks === "function") await options.hooks(hooks);
343
- return {
344
- hooks,
345
- context: {
346
- options,
347
- hooks
348
- }
349
- };
350
- }
351
-
352
- //#endregion
353
- //#region src/features/publint.ts
354
- const debug$5 = Debug("tsdown:publint");
355
- async function publint(options) {
356
- if (!options.publint) return;
357
- if (!options.pkg) {
358
- options.logger.warn(prettyName(options.name), "publint is enabled but package.json is not found");
359
- return;
360
- }
361
- const t = performance.now();
362
- debug$5("Running publint");
363
- const { publint: publint$1 } = await import("publint");
364
- const { formatMessage } = await import("publint/utils");
365
- const { messages } = await publint$1({
366
- ...options.publint === true ? {} : options.publint,
367
- pkgDir: path.dirname(options.pkg.packageJsonPath)
368
- });
369
- debug$5("Found %d issues", messages.length);
370
- if (!messages.length) options.logger.success(prettyName(options.name), `No publint issues found`, dim`(${Math.round(performance.now() - t)}ms)`);
371
- let hasError = false;
372
- for (const message of messages) {
373
- hasError ||= message.type === "error";
374
- const formattedMessage = formatMessage(message, options.pkg);
375
- const logType = {
376
- error: "error",
377
- warning: "warn",
378
- suggestion: "info"
379
- }[message.type];
380
- options.logger[logType](prettyName(options.name), formattedMessage);
381
- }
382
- if (hasError) {
383
- debug$5("Found errors, setting exit code to 1");
384
- process.exitCode = 1;
385
- }
386
- }
387
-
388
- //#endregion
389
- //#region src/features/entry.ts
390
- async function resolveEntry(logger, entry, cwd, name) {
391
- const nameLabel = name ? `[${name}] ` : "";
392
- if (!entry || Object.keys(entry).length === 0) {
393
- const defaultEntry = path.resolve(cwd, "src/index.ts");
394
- if (await fsExists(defaultEntry)) entry = { index: defaultEntry };
395
- else throw new Error(`${nameLabel}No input files, try "tsdown <your-file>" or create src/index.ts`);
396
- }
397
- const entryMap = await toObjectEntry(entry, cwd);
398
- const entries = Object.values(entryMap);
399
- if (entries.length === 0) throw new Error(`${nameLabel}Cannot find entry: ${JSON.stringify(entry)}`);
400
- logger.info(prettyName(name), `entry: ${generateColor(name)(entries.map((entry$1) => path.relative(cwd, entry$1)).join(", "))}`);
401
- return entryMap;
402
- }
403
- async function toObjectEntry(entry, cwd) {
404
- if (typeof entry === "string") entry = [entry];
405
- if (!Array.isArray(entry)) return entry;
406
- const resolvedEntry = (await glob(entry, {
407
- cwd,
408
- expandDirectories: false
409
- })).map((file) => path.resolve(cwd, file));
410
- const base = lowestCommonAncestor(...resolvedEntry);
411
- return Object.fromEntries(resolvedEntry.map((file) => {
412
- const relative = path.relative(base, file);
413
- return [relative.slice(0, relative.length - path.extname(relative).length), file];
414
- }));
415
- }
416
-
417
379
  //#endregion
418
380
  //#region src/features/target.ts
419
381
  function resolveTarget(logger, target, pkg, name) {
@@ -467,11 +429,11 @@ async function resolveTsconfig(logger, tsconfig, cwd, name) {
467
429
 
468
430
  //#endregion
469
431
  //#region src/utils/package.ts
470
- const debug$4 = Debug("tsdown:package");
432
+ const debug$6 = Debug("tsdown:package");
471
433
  async function readPackageJson(dir) {
472
434
  const packageJsonPath = up$1({ cwd: dir });
473
435
  if (!packageJsonPath) return;
474
- debug$4("Reading package.json:", packageJsonPath);
436
+ debug$6("Reading package.json:", packageJsonPath);
475
437
  const contents = await readFile(packageJsonPath, "utf8");
476
438
  return {
477
439
  ...JSON.parse(contents),
@@ -498,147 +460,38 @@ function normalizeFormat(format) {
498
460
  }
499
461
 
500
462
  //#endregion
501
- //#region src/options/config.ts
502
- async function loadViteConfig(prefix, cwd) {
503
- const { config, sources: [source] } = await loadConfig({
504
- sources: [{
505
- files: `${prefix}.config`,
506
- extensions: [
507
- "ts",
508
- "mts",
509
- "cts",
510
- "js",
511
- "mjs",
512
- "cjs",
513
- "json",
514
- ""
515
- ]
516
- }],
517
- cwd,
518
- defaults: {}
519
- });
520
- if (!source) return;
521
- globalLogger.info(`Using Vite config: ${underline(source)}`);
522
- const resolved = await config;
523
- if (typeof resolved === "function") return resolved({
524
- command: "build",
525
- mode: "production"
526
- });
527
- return resolved;
528
- }
529
- let loaded = false;
530
- async function loadConfigFile(options, workspace) {
531
- let cwd = options.cwd || process.cwd();
532
- let overrideConfig = false;
533
- let { config: filePath } = options;
534
- if (filePath === false) return { configs: [{}] };
535
- if (typeof filePath === "string") {
536
- const stats = await fsStat(filePath);
537
- if (stats) {
538
- const resolved = path.resolve(filePath);
539
- if (stats.isFile()) {
540
- overrideConfig = true;
541
- filePath = resolved;
542
- cwd = path.dirname(filePath);
543
- } else if (stats.isDirectory()) cwd = resolved;
544
- }
545
- }
546
- let isNative = false;
547
- if (!loaded) {
548
- if (!options.configLoader || options.configLoader === "auto") isNative = !!(process.features.typescript || process.versions.bun || process.versions.deno);
549
- else if (options.configLoader === "native") isNative = true;
550
- }
551
- let { config, sources } = await loadConfig.async({
552
- sources: overrideConfig ? [{
553
- files: filePath,
554
- extensions: []
555
- }] : [{
556
- files: "tsdown.config",
557
- extensions: [
558
- "ts",
559
- "mts",
560
- "cts",
561
- "js",
562
- "mjs",
563
- "cjs",
564
- "json",
565
- ""
566
- ],
567
- parser: options.configLoader === "unrun" ? unrunImport : isNative ? nativeImport : "auto"
568
- }, {
569
- files: "package.json",
570
- extensions: [],
571
- rewrite: (config$1) => config$1?.tsdown
572
- }],
573
- cwd,
574
- stopAt: workspace && path.dirname(workspace),
575
- defaults: {}
576
- }).finally(() => loaded = true);
577
- if (typeof config === "function") config = await config(options);
578
- config = toArray(config);
579
- if (config.length === 0) config.push({});
580
- const file = sources[0];
581
- if (file) globalLogger.info(`Using tsdown config: ${underline(file)}`);
582
- return {
583
- configs: config,
584
- file
585
- };
586
- }
587
- async function nativeImport(id) {
588
- const mod = await import(pathToFileURL(id).href).catch((error) => {
589
- if (error?.message?.includes?.("Cannot find module")) {
590
- const configError = /* @__PURE__ */ new Error(`Failed to load the config file. Try setting the --config-loader CLI flag to \`unconfig\`.\n\n${error.message}`);
591
- configError.cause = error;
592
- throw configError;
593
- } else throw error;
594
- });
595
- return mod.default || mod;
596
- }
597
- async function unrunImport(id) {
598
- const { unrun } = await import("unrun");
599
- const { module: module$1 } = await unrun({ path: pathToFileURL(id).href }).catch((error) => {
600
- if (error?.message?.includes?.("Cannot find module")) {
601
- const configError = /* @__PURE__ */ new Error(`Failed to load the config file. \`unrun\` is experimental; try setting the --config-loader CLI flag to \`unconfig\` instead.\n\n${error.message}`);
602
- configError.cause = error;
603
- throw configError;
604
- } else throw error;
605
- });
606
- return module$1;
607
- }
608
-
609
- //#endregion
610
- //#region src/options/index.ts
611
- const debug$3 = Debug("tsdown:options");
463
+ //#region src/config/index.ts
464
+ const debug$5 = Debug("tsdown:options");
612
465
  const DEFAULT_EXCLUDE_WORKSPACE = [
613
466
  "**/node_modules/**",
614
467
  "**/dist/**",
615
468
  "**/test?(s)/**",
616
469
  "**/t?(e)mp/**"
617
470
  ];
618
- async function resolveOptions(options) {
619
- debug$3("options %O", options);
620
- const { configs: rootConfigs, file } = await loadConfigFile(options);
471
+ async function resolveConfig(inlineConfig) {
472
+ debug$5("inline config %O", inlineConfig);
473
+ const { configs: rootConfigs, file } = await loadConfigFile(inlineConfig);
621
474
  const files = [];
622
475
  if (file) {
623
476
  files.push(file);
624
- debug$3("loaded root config file %s", file);
625
- debug$3("root configs %O", rootConfigs);
626
- } else debug$3("no root config file found");
477
+ debug$5("loaded root user config file %s", file);
478
+ debug$5("root user configs %O", rootConfigs);
479
+ } else debug$5("no root user config file found");
627
480
  const configs = (await Promise.all(rootConfigs.map(async (rootConfig) => {
628
- const { configs: workspaceConfigs, files: workspaceFiles } = await resolveWorkspace(rootConfig, options);
481
+ const { configs: workspaceConfigs, files: workspaceFiles } = await resolveWorkspace(rootConfig, inlineConfig);
629
482
  if (workspaceFiles) files.push(...workspaceFiles);
630
- return Promise.all(workspaceConfigs.filter((config) => !config.workspace || config.entry).map((config) => resolveConfig(config)));
483
+ return Promise.all(workspaceConfigs.filter((config) => !config.workspace || config.entry).map((config) => resolveUserConfig(config, inlineConfig)));
631
484
  }))).flat();
632
- debug$3("resolved configs %O", configs);
485
+ debug$5("resolved configs %O", configs);
633
486
  return {
634
487
  configs,
635
488
  files
636
489
  };
637
490
  }
638
- async function resolveWorkspace(config, options) {
491
+ async function resolveWorkspace(config, inlineConfig) {
639
492
  const normalized = {
640
493
  ...config,
641
- ...options
494
+ ...inlineConfig
642
495
  };
643
496
  const rootCwd = normalized.cwd || process.cwd();
644
497
  let { workspace } = normalized;
@@ -662,26 +515,26 @@ async function resolveWorkspace(config, options) {
662
515
  expandDirectories: false
663
516
  })).map((file) => slash(path.resolve(file)));
664
517
  if (packages.length === 0) throw new Error("No workspace packages found, please check your config");
665
- if (options.filter) {
666
- options.filter = resolveRegex(options.filter);
518
+ if (inlineConfig.filter) {
519
+ inlineConfig.filter = resolveRegex(inlineConfig.filter);
667
520
  packages = packages.filter((path$1) => {
668
- return typeof options.filter === "string" ? path$1.includes(options.filter) : Array.isArray(options.filter) ? options.filter.some((filter) => path$1.includes(filter)) : options.filter.test(path$1);
521
+ return typeof inlineConfig.filter === "string" ? path$1.includes(inlineConfig.filter) : Array.isArray(inlineConfig.filter) ? inlineConfig.filter.some((filter) => path$1.includes(filter)) : inlineConfig.filter.test(path$1);
669
522
  });
670
523
  if (packages.length === 0) throw new Error("No packages matched the filters");
671
524
  }
672
525
  const files = [];
673
526
  return {
674
527
  configs: (await Promise.all(packages.map(async (cwd) => {
675
- debug$3("loading workspace config %s", cwd);
528
+ debug$5("loading workspace config %s", cwd);
676
529
  const { configs, file } = await loadConfigFile({
677
- ...options,
530
+ ...inlineConfig,
678
531
  config: workspaceConfig,
679
532
  cwd
680
533
  }, cwd);
681
534
  if (file) {
682
- debug$3("loaded workspace config file %s", file);
535
+ debug$5("loaded workspace config file %s", file);
683
536
  files.push(file);
684
- } else debug$3("no workspace config file found in %s", cwd);
537
+ } else debug$5("no workspace config file found in %s", cwd);
685
538
  return configs.map((config$1) => ({
686
539
  ...normalized,
687
540
  cwd,
@@ -691,8 +544,8 @@ async function resolveWorkspace(config, options) {
691
544
  files
692
545
  };
693
546
  }
694
- async function resolveConfig(userConfig) {
695
- let { entry, format = ["es"], plugins = [], clean = true, silent = false, logLevel = silent ? "silent" : "info", failOnWarn = false, customLogger, treeshake = true, platform = "node", outDir = "dist", sourcemap = false, dts, unused = false, watch = false, ignoreWatch, shims = false, skipNodeModulesBundle = false, publint: publint$1 = false, attw: attw$1 = false, fromVite, alias, tsconfig, report = true, target, env = {}, copy: copy$1, publicDir, hash, cwd = process.cwd(), name, workspace, external, noExternal, exports = false, bundle, unbundle = typeof bundle === "boolean" ? !bundle : false, removeNodeProtocol, nodeProtocol, cjsDefault = true, globImport = true, inlineOnly } = userConfig;
547
+ async function resolveUserConfig(userConfig, inlineConfig) {
548
+ let { entry, format = ["es"], plugins = [], clean = true, silent = false, logLevel = silent ? "silent" : "info", failOnWarn = false, customLogger, treeshake = true, platform = "node", outDir = "dist", sourcemap = false, dts, unused = false, watch = false, ignoreWatch, shims = false, skipNodeModulesBundle = false, publint: publint$1 = false, attw: attw$1 = false, fromVite, alias, tsconfig, report = true, target, env = {}, copy: copy$1, publicDir, hash, cwd = process.cwd(), name, workspace, external, noExternal, exports = false, bundle, unbundle = typeof bundle === "boolean" ? !bundle : false, removeNodeProtocol, nodeProtocol, cjsDefault = true, globImport = true, inlineOnly, fixedExtension = platform === "node", debug: debug$9 = false } = userConfig;
696
549
  const logger = createLogger(logLevel, {
697
550
  customLogger,
698
551
  failOnWarn
@@ -716,7 +569,7 @@ async function resolveConfig(userConfig) {
716
569
  if (publicDir) if (copy$1) throw new TypeError("`publicDir` is deprecated. Cannot be used with `copy`");
717
570
  else logger.warn(`${blue`publicDir`} is deprecated. Use ${blue`copy`} instead.`);
718
571
  if (fromVite) {
719
- const viteUserConfig = await loadViteConfig(fromVite === true ? "vite" : fromVite, cwd);
572
+ const viteUserConfig = await loadViteConfig(fromVite === true ? "vite" : fromVite, cwd, inlineConfig.configLoader);
720
573
  if (viteUserConfig) {
721
574
  const viteAlias = viteUserConfig.resolve?.alias;
722
575
  if (Array.isArray(viteAlias)) throw new TypeError("Unsupported resolve.alias in Vite config. Use object instead of array");
@@ -737,6 +590,10 @@ async function resolveConfig(userConfig) {
737
590
  noExternal = (id) => matchPattern(id, noExternalPatterns);
738
591
  }
739
592
  if (inlineOnly != null) inlineOnly = toArray(inlineOnly);
593
+ if (debug$9) {
594
+ if (debug$9 === true) debug$9 = {};
595
+ debug$9.devtools ??= !!pkgExists("@vitejs/devtools/cli");
596
+ }
740
597
  return {
741
598
  ...userConfig,
742
599
  entry,
@@ -773,7 +630,9 @@ async function resolveConfig(userConfig) {
773
630
  nodeProtocol,
774
631
  cjsDefault,
775
632
  globImport,
776
- inlineOnly
633
+ inlineOnly,
634
+ fixedExtension,
635
+ debug: debug$9
777
636
  };
778
637
  }
779
638
  async function mergeUserOptions(defaults, user, args) {
@@ -784,6 +643,172 @@ async function mergeUserOptions(defaults, user, args) {
784
643
  };
785
644
  }
786
645
 
646
+ //#endregion
647
+ //#region src/features/attw.ts
648
+ const debug$4 = Debug("tsdown:attw");
649
+ /**
650
+ * ATTW profiles.
651
+ * Defines the resolution modes to ignore for each profile.
652
+ *
653
+ * @see https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/packages/cli/README.md#profiles
654
+ */
655
+ const profiles = {
656
+ strict: [],
657
+ node16: ["node10"],
658
+ esmOnly: ["node10", "node16-cjs"]
659
+ };
660
+ /**
661
+ * Format an ATTW problem for display
662
+ */
663
+ function formatProblem(problem) {
664
+ const resolutionKind = "resolutionKind" in problem ? ` (${problem.resolutionKind})` : "";
665
+ const entrypoint = "entrypoint" in problem ? ` at ${problem.entrypoint}` : "";
666
+ switch (problem.kind) {
667
+ case "NoResolution": return ` ❌ No resolution${resolutionKind}${entrypoint}`;
668
+ case "UntypedResolution": return ` ⚠️ Untyped resolution${resolutionKind}${entrypoint}`;
669
+ case "FalseESM": return ` 🔄 False ESM: Types indicate ESM (${problem.typesModuleKind}) but implementation is CJS (${problem.implementationModuleKind})\n Types: ${problem.typesFileName} | Implementation: ${problem.implementationFileName}`;
670
+ case "FalseCJS": return ` 🔄 False CJS: Types indicate CJS (${problem.typesModuleKind}) but implementation is ESM (${problem.implementationModuleKind})\n Types: ${problem.typesFileName} | Implementation: ${problem.implementationFileName}`;
671
+ case "CJSResolvesToESM": return ` ⚡ CJS resolves to ESM${resolutionKind}${entrypoint}`;
672
+ case "NamedExports": {
673
+ const missingExports = problem.missing?.length > 0 ? ` Missing: ${problem.missing.join(", ")}` : "";
674
+ return ` 📤 Named exports problem${problem.isMissingAllNamed ? " (all named exports missing)" : ""}${missingExports}\n Types: ${problem.typesFileName} | Implementation: ${problem.implementationFileName}`;
675
+ }
676
+ case "FallbackCondition": return ` 🎯 Fallback condition used${resolutionKind}${entrypoint}`;
677
+ case "FalseExportDefault": return ` 🎭 False export default\n Types: ${problem.typesFileName} | Implementation: ${problem.implementationFileName}`;
678
+ case "MissingExportEquals": return ` 📝 Missing export equals\n Types: ${problem.typesFileName} | Implementation: ${problem.implementationFileName}`;
679
+ case "InternalResolutionError": return ` 💥 Internal resolution error in ${problem.fileName} (${problem.resolutionOption})\n Module: ${problem.moduleSpecifier} | Mode: ${problem.resolutionMode}`;
680
+ case "UnexpectedModuleSyntax": return ` 📋 Unexpected module syntax in ${problem.fileName}\n Expected: ${problem.moduleKind} | Found: ${problem.syntax === 99 ? "ESM" : "CJS"}`;
681
+ case "CJSOnlyExportsDefault": return ` 🏷️ CJS only exports default in ${problem.fileName}`;
682
+ default: return ` ❓ Unknown problem: ${JSON.stringify(problem)}`;
683
+ }
684
+ }
685
+ async function attw(options) {
686
+ if (!options.attw) return;
687
+ if (!options.pkg) {
688
+ options.logger.warn("attw is enabled but package.json is not found");
689
+ return;
690
+ }
691
+ const { profile = "strict", level = "warn",...attwOptions } = options.attw === true ? {} : options.attw;
692
+ const t = performance.now();
693
+ debug$4("Running attw check");
694
+ const tempDir = await mkdtemp(path.join(tmpdir(), "tsdown-attw-"));
695
+ const attwCore = await importWithError("@arethetypeswrong/core");
696
+ try {
697
+ const { stdout: tarballInfo } = await exec("npm", [
698
+ "pack",
699
+ "--json",
700
+ "--pack-destination",
701
+ tempDir
702
+ ], { nodeOptions: { cwd: options.cwd } });
703
+ const parsed = JSON.parse(tarballInfo);
704
+ if (!Array.isArray(parsed) || !parsed[0]?.filename) throw new Error("Invalid npm pack output format");
705
+ const tarball = await readFile(path.join(tempDir, parsed[0].filename));
706
+ const pkg = attwCore.createPackageFromTarballData(tarball);
707
+ const checkResult = await attwCore.checkPackage(pkg, attwOptions);
708
+ if (checkResult.types !== false && checkResult.problems.length) {
709
+ const problems = checkResult.problems.filter((problem) => {
710
+ if ("resolutionKind" in problem) return !profiles[profile]?.includes(problem.resolutionKind);
711
+ return true;
712
+ });
713
+ if (problems.length) {
714
+ const problemMessage = `Are the types wrong problems found:\n${problems.map(formatProblem).join("\n")}`;
715
+ if (level === "error") throw new Error(problemMessage);
716
+ options.logger.warn(prettyName(options.name), problemMessage);
717
+ }
718
+ } else options.logger.success(prettyName(options.name), `No Are the types wrong problems found`, dim`(${Math.round(performance.now() - t)}ms)`);
719
+ } catch (error) {
720
+ options.logger.error("ATTW check failed:", error);
721
+ debug$4("Found errors, setting exit code to 1");
722
+ process.exitCode = 1;
723
+ } finally {
724
+ await fsRemove(tempDir);
725
+ }
726
+ }
727
+
728
+ //#endregion
729
+ //#region src/features/cjs.ts
730
+ /**
731
+ * If the config includes the `cjs` format and
732
+ * one of its target >= node 23.0.0 / 22.12.0,
733
+ * warn the user about the deprecation of CommonJS.
734
+ */
735
+ function warnLegacyCJS(config) {
736
+ if (!config.format.includes("cjs") || !config.target) return;
737
+ if (config.target.some((t) => {
738
+ const version$1 = coerce(t.split("node")[1]);
739
+ return version$1 && satisfies(version$1, ">=23.0.0 || >=22.12.0");
740
+ })) config.logger.warnOnce("We recommend using the ESM format instead of CommonJS.\nThe ESM format is compatible with modern platforms and runtimes, and most new libraries are now distributed only in ESM format.\nLearn more at https://nodejs.org/en/learn/modules/publishing-a-package#how-did-we-get-here");
741
+ }
742
+
743
+ //#endregion
744
+ //#region src/features/copy.ts
745
+ async function copy(options) {
746
+ if (!options.copy) return;
747
+ const copy$1 = typeof options.copy === "function" ? await options.copy(options) : options.copy;
748
+ await Promise.all(toArray(copy$1).map((dir) => {
749
+ const from = typeof dir === "string" ? dir : dir.from;
750
+ const to = typeof dir === "string" ? path.resolve(options.outDir, path.basename(from)) : dir.to;
751
+ return cp$1(options.cwd, from, to);
752
+ }));
753
+ }
754
+ function cp$1(cwd, from, to) {
755
+ return fsCopy(path.resolve(cwd, from), path.resolve(cwd, to));
756
+ }
757
+
758
+ //#endregion
759
+ //#region src/features/hooks.ts
760
+ async function createHooks$1(options) {
761
+ const hooks = createHooks();
762
+ if (typeof options.hooks === "object") hooks.addHooks(options.hooks);
763
+ else if (typeof options.hooks === "function") await options.hooks(hooks);
764
+ return {
765
+ hooks,
766
+ context: {
767
+ options,
768
+ hooks
769
+ }
770
+ };
771
+ }
772
+
773
+ //#endregion
774
+ //#region src/features/publint.ts
775
+ const debug$3 = Debug("tsdown:publint");
776
+ async function publint(options) {
777
+ if (!options.publint) return;
778
+ if (!options.pkg) {
779
+ options.logger.warn(prettyName(options.name), "publint is enabled but package.json is not found");
780
+ return;
781
+ }
782
+ const t = performance.now();
783
+ debug$3("Running publint");
784
+ const { publint: publint$1 } = await importWithError("publint");
785
+ const { formatMessage } = await import("publint/utils");
786
+ const { messages } = await publint$1({
787
+ ...options.publint === true ? {} : options.publint,
788
+ pkgDir: path.dirname(options.pkg.packageJsonPath)
789
+ });
790
+ debug$3("Found %d issues", messages.length);
791
+ if (!messages.length) {
792
+ options.logger.success(prettyName(options.name), `No publint issues found`, dim`(${Math.round(performance.now() - t)}ms)`);
793
+ return;
794
+ }
795
+ let hasError = false;
796
+ for (const message of messages) {
797
+ hasError ||= message.type === "error";
798
+ const formattedMessage = formatMessage(message, options.pkg);
799
+ const logType = {
800
+ error: "error",
801
+ warning: "warn",
802
+ suggestion: "info"
803
+ }[message.type];
804
+ options.logger[logType](prettyName(options.name), formattedMessage);
805
+ }
806
+ if (hasError) {
807
+ debug$3("Found errors, setting exit code to 1");
808
+ process.exitCode = 1;
809
+ }
810
+ }
811
+
787
812
  //#endregion
788
813
  //#region src/features/external.ts
789
814
  const debug$2 = Debug("tsdown:external");
@@ -1104,7 +1129,7 @@ async function getBuildOptions(config, format, isMultiFormat, cjsDts = false) {
1104
1129
  return rolldownConfig;
1105
1130
  }
1106
1131
  async function resolveInputOptions(config, format, cjsDts, isMultiFormat) {
1107
- const { entry, external, plugins: userPlugins, platform, alias, treeshake, dts, unused, target, shims, tsconfig, cwd, report, env, nodeProtocol, loader, name, logger, cjsDefault, banner, footer, globImport } = config;
1132
+ const { entry, external, plugins: userPlugins, platform, alias, treeshake, dts, unused, target, shims, tsconfig, cwd, report, env, nodeProtocol, loader, name, logger, cjsDefault, banner, footer, globImport, debug: debug$9 } = config;
1108
1133
  const plugins = [];
1109
1134
  if (nodeProtocol) plugins.push(NodeProtocolPlugin(nodeProtocol));
1110
1135
  if (config.pkg || config.skipNodeModulesBundle) plugins.push(ExternalPlugin(config));
@@ -1125,8 +1150,11 @@ async function resolveInputOptions(config, format, cjsDts, isMultiFormat) {
1125
1150
  }
1126
1151
  if (!cjsDts) {
1127
1152
  if (unused) {
1128
- const { Unused } = await import("unplugin-unused");
1129
- plugins.push(Unused.rolldown(unused === true ? {} : unused));
1153
+ const { Unused } = await importWithError("unplugin-unused");
1154
+ plugins.push(Unused.rolldown({
1155
+ root: cwd,
1156
+ ...unused === true ? {} : unused
1157
+ }));
1130
1158
  }
1131
1159
  if (target) plugins.push(await LightningCSSPlugin({ target }));
1132
1160
  plugins.push(ShebangPlugin(logger, cwd, name, isMultiFormat));
@@ -1163,7 +1191,8 @@ async function resolveInputOptions(config, format, cjsDts, isMultiFormat) {
1163
1191
  onLog: cjsDefault ? (level, log, defaultHandler) => {
1164
1192
  if (log.code === "MIXED_EXPORT") return;
1165
1193
  defaultHandler(level, log);
1166
- } : void 0
1194
+ } : void 0,
1195
+ debug: debug$9 || void 0
1167
1196
  }, config.inputOptions, [format, { cjsDts }]);
1168
1197
  }
1169
1198
  async function resolveOutputOptions(inputOptions, config, format, cjsDts) {
@@ -1319,7 +1348,7 @@ async function watchBuild(options, configFiles, rebuild, restart) {
1319
1348
  */
1320
1349
  async function build$1(userOptions = {}) {
1321
1350
  globalLogger.level = userOptions.logLevel || (userOptions.silent ? "error" : "info");
1322
- const { configs, files: configFiles } = await resolveOptions(userOptions);
1351
+ const { configs, files: configFiles } = await resolveConfig(userOptions);
1323
1352
  let cleanPromise;
1324
1353
  const clean = () => {
1325
1354
  if (cleanPromise) return cleanPromise;
@@ -1331,9 +1360,24 @@ async function build$1(userOptions = {}) {
1331
1360
  for (const [i, config] of configs.entries()) {
1332
1361
  const rebuild = rebuilds[i];
1333
1362
  if (!rebuild) continue;
1363
+ setWatch();
1334
1364
  const watcher = await watchBuild(config, configFiles, rebuild, restart);
1335
1365
  disposeCbs.push(() => watcher.close());
1336
1366
  }
1367
+ let firstDevtoolsConfig = configs.find((config) => config.debug && config.debug.devtools);
1368
+ if (disposeCbs.length && firstDevtoolsConfig) {
1369
+ globalLogger.warn("Devtools is not supported in watch mode, disabling it.");
1370
+ firstDevtoolsConfig = void 0;
1371
+ }
1372
+ if (firstDevtoolsConfig) {
1373
+ const { start } = await importWithError("@vitejs/devtools/cli-commands");
1374
+ const devtoolsOptions = firstDevtoolsConfig.debug.devtools;
1375
+ await start({
1376
+ host: "127.0.0.1",
1377
+ open: true,
1378
+ ...typeof devtoolsOptions === "object" ? devtoolsOptions : {}
1379
+ });
1380
+ }
1337
1381
  if (disposeCbs.length) disposeCbs.push(shortcuts(restart));
1338
1382
  async function restart() {
1339
1383
  for (const dispose of disposeCbs) await dispose();