tsdown 0.13.3 → 0.13.4

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,4 +1,4 @@
1
- import { LogLevels, createLogger, debounce, generateColor, globalLogger, noop, prettyFormat, prettyName, resolveComma, resolveRegex, slash, toArray } from "./logger-DScmoUke.mjs";
1
+ import { LogLevels, createLogger, debounce, generateColor, globalLogger, noop, prettyFormat, prettyName, resolveComma, resolveRegex, slash, toArray } from "./logger-CGMSjTLn.mjs";
2
2
  import { builtinModules } from "node:module";
3
3
  import path, { dirname, normalize, sep } from "node:path";
4
4
  import process from "node:process";
@@ -17,14 +17,14 @@ import satisfies from "semver/functions/satisfies.js";
17
17
  import { glob } from "tinyglobby";
18
18
  import { RE_CSS, RE_DTS, RE_JS } from "rolldown-plugin-dts/filename";
19
19
  import { createHooks } from "hookable";
20
- import { up } from "empathic/package";
20
+ import minVersion from "semver/ranges/min-version.js";
21
+ import { up } from "empathic/find";
22
+ import { up as up$1 } from "empathic/package";
23
+ import { loadConfig } from "unconfig";
21
24
  import { Buffer } from "node:buffer";
22
25
  import { brotliCompress, gzip } from "node:zlib";
23
26
  import readline from "node:readline";
24
- import minVersion from "semver/ranges/min-version.js";
25
27
  import { globalContext, invalidateContextFile } from "rolldown-plugin-dts/tsc-context";
26
- import { up as up$1 } from "empathic/find";
27
- import { loadConfig } from "unconfig";
28
28
 
29
29
  //#region src/utils/fs.ts
30
30
  function fsExists(path$1) {
@@ -66,7 +66,7 @@ function lowestCommonAncestor(...filepaths) {
66
66
 
67
67
  //#endregion
68
68
  //#region src/features/attw.ts
69
- const debug$7 = debug("tsdown:attw");
69
+ const debug$8 = debug("tsdown:attw");
70
70
  const exec$1 = promisify(child_process.exec);
71
71
  /**
72
72
  * ATTW profiles.
@@ -113,7 +113,7 @@ async function attw(options) {
113
113
  }
114
114
  const { profile = "strict", level = "warn",...attwOptions } = options.attw === true ? {} : options.attw;
115
115
  const t = performance.now();
116
- debug$7("Running attw check");
116
+ debug$8("Running attw check");
117
117
  const tempDir = await mkdtemp(path.join(tmpdir(), "tsdown-attw-"));
118
118
  let attwCore;
119
119
  try {
@@ -147,7 +147,7 @@ async function attw(options) {
147
147
  } else options.logger.success(`No Are the types wrong problems found`, dim`(${Math.round(performance.now() - t)}ms)`);
148
148
  } catch (error) {
149
149
  options.logger.error("ATTW check failed:", error);
150
- debug$7("Found errors, setting exit code to 1");
150
+ debug$8("Found errors, setting exit code to 1");
151
151
  process.exitCode = 1;
152
152
  } finally {
153
153
  await fsRemove(tempDir);
@@ -172,7 +172,7 @@ function warnLegacyCJS(config) {
172
172
 
173
173
  //#endregion
174
174
  //#region src/features/clean.ts
175
- const debug$6 = debug("tsdown:clean");
175
+ const debug$7 = debug("tsdown:clean");
176
176
  const RE_LAST_SLASH = /[/\\]$/;
177
177
  async function cleanOutDir(configs) {
178
178
  const removes = /* @__PURE__ */ new Set();
@@ -192,10 +192,10 @@ async function cleanOutDir(configs) {
192
192
  if (!removes.size) return;
193
193
  globalLogger.info(`Cleaning ${removes.size} files`);
194
194
  await Promise.all([...removes].map(async (file) => {
195
- debug$6("Removing", file);
195
+ debug$7("Removing", file);
196
196
  await fsRemove(file);
197
197
  }));
198
- debug$6("Removed %d files", removes.size);
198
+ debug$7("Removed %d files", removes.size);
199
199
  }
200
200
  function resolveClean(clean, outDir, cwd) {
201
201
  if (clean === true) clean = [slash(outDir)];
@@ -327,50 +327,6 @@ function exportMeta(exports, all) {
327
327
  else exports["./package.json"] = "./package.json";
328
328
  }
329
329
 
330
- //#endregion
331
- //#region src/features/external.ts
332
- const debug$5 = debug("tsdown:external");
333
- function ExternalPlugin(options) {
334
- const deps = options.pkg && Array.from(getProductionDeps(options.pkg));
335
- return {
336
- name: "tsdown:external",
337
- async resolveId(id, importer, extraOptions) {
338
- if (extraOptions.isEntry) return;
339
- if (id === shimFile) return;
340
- const { noExternal } = options;
341
- if (typeof noExternal === "function" && noExternal(id, importer)) return;
342
- if (noExternal) {
343
- const noExternalPatterns = toArray(noExternal);
344
- if (noExternalPatterns.some((pattern) => {
345
- if (pattern instanceof RegExp) {
346
- pattern.lastIndex = 0;
347
- return pattern.test(id);
348
- }
349
- return id === pattern;
350
- })) return;
351
- }
352
- let shouldExternal = false;
353
- if (options.skipNodeModulesBundle) {
354
- const resolved = await this.resolve(id, importer, extraOptions);
355
- if (!resolved) return resolved;
356
- shouldExternal = resolved.external || /[\\/]node_modules[\\/]/.test(resolved.id);
357
- }
358
- if (deps) shouldExternal ||= deps.some((dep) => id === dep || id.startsWith(`${dep}/`));
359
- if (shouldExternal) {
360
- debug$5("External dependency:", id);
361
- return {
362
- id,
363
- external: shouldExternal,
364
- moduleSideEffects: id.startsWith("node:") || builtinModules.includes(id) ? false : void 0
365
- };
366
- }
367
- }
368
- };
369
- }
370
- function getProductionDeps(pkg) {
371
- return new Set([...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})]);
372
- }
373
-
374
330
  //#endregion
375
331
  //#region src/features/hooks.ts
376
332
  async function createHooks$1(options) {
@@ -388,101 +344,146 @@ async function createHooks$1(options) {
388
344
  }
389
345
 
390
346
  //#endregion
391
- //#region src/utils/lightningcss.ts
392
- /**
393
- * Converts esbuild target [^1] (which is also used by Rolldown [^2]) to Lightning CSS targets [^3].
394
- *
395
- * [^1]: https://esbuild.github.io/api/#target
396
- * [^2]: https://github.com/rolldown/rolldown/blob/v1.0.0-beta.8/packages/rolldown/src/binding.d.ts#L1429-L1431
397
- * [^3]: https://lightningcss.dev/transpilation.html
398
- */
399
- function esbuildTargetToLightningCSS(target) {
400
- let targets;
401
- const targetString = target.join(" ").toLowerCase();
402
- const matches = [...targetString.matchAll(TARGET_REGEX)];
403
- for (const match of matches) {
404
- const name = match[1];
405
- const browser = ESBUILD_LIGHTNINGCSS_MAPPING[name];
406
- if (!browser) continue;
407
- const version = match[2];
408
- const versionInt = parseVersion(version);
409
- if (versionInt == null) continue;
410
- targets = targets || {};
411
- targets[browser] = versionInt;
347
+ //#region src/features/publint.ts
348
+ const debug$6 = debug("tsdown:publint");
349
+ async function publint(options) {
350
+ if (!options.publint) return;
351
+ if (!options.pkg) {
352
+ options.logger.warn("publint is enabled but package.json is not found");
353
+ return;
354
+ }
355
+ const t = performance.now();
356
+ debug$6("Running publint");
357
+ const { publint: publint$1 } = await import("publint");
358
+ const { formatMessage } = await import("publint/utils");
359
+ const { messages } = await publint$1(options.publint === true ? {} : options.publint);
360
+ debug$6("Found %d issues", messages.length);
361
+ if (!messages.length) options.logger.success(`No publint issues found`, dim`(${Math.round(performance.now() - t)}ms)`);
362
+ let hasError = false;
363
+ for (const message of messages) {
364
+ hasError ||= message.type === "error";
365
+ const formattedMessage = formatMessage(message, options.pkg);
366
+ const logType = {
367
+ error: "error",
368
+ warning: "warn",
369
+ suggestion: "info"
370
+ }[message.type];
371
+ options.logger[logType](formattedMessage);
372
+ }
373
+ if (hasError) {
374
+ debug$6("Found errors, setting exit code to 1");
375
+ process.exitCode = 1;
412
376
  }
413
- return targets;
414
- }
415
- const TARGET_REGEX = /([a-z]+)(\d+(?:\.\d+)*)/g;
416
- const ESBUILD_LIGHTNINGCSS_MAPPING = {
417
- chrome: "chrome",
418
- edge: "edge",
419
- firefox: "firefox",
420
- ie: "ie",
421
- ios: "ios_saf",
422
- opera: "opera",
423
- safari: "safari"
424
- };
425
- function parseVersion(version) {
426
- const [major, minor = 0, patch = 0] = version.split("-")[0].split(".").map((v) => Number.parseInt(v, 10));
427
- if (Number.isNaN(major) || Number.isNaN(minor) || Number.isNaN(patch)) return null;
428
- return major << 16 | minor << 8 | patch;
429
377
  }
430
378
 
431
379
  //#endregion
432
- //#region src/features/lightningcss.ts
433
- async function LightningCSSPlugin(options) {
434
- const LightningCSS = await import("unplugin-lightningcss/rolldown").catch(() => void 0);
435
- if (!LightningCSS) return;
436
- const targets = options.target && esbuildTargetToLightningCSS(options.target);
437
- if (!targets) return;
438
- return LightningCSS.default({ options: { targets } });
380
+ //#region src/features/entry.ts
381
+ async function resolveEntry(logger, entry, cwd, name) {
382
+ const nameLabel = name ? `[${name}] ` : "";
383
+ if (!entry || Object.keys(entry).length === 0) {
384
+ const defaultEntry = path.resolve(cwd, "src/index.ts");
385
+ if (await fsExists(defaultEntry)) entry = { index: defaultEntry };
386
+ else throw new Error(`${nameLabel}No input files, try "tsdown <your-file>" or create src/index.ts`);
387
+ }
388
+ const entryMap = await toObjectEntry(entry, cwd);
389
+ const entries = Object.values(entryMap);
390
+ if (entries.length === 0) throw new Error(`${nameLabel}Cannot find entry: ${JSON.stringify(entry)}`);
391
+ logger.info(prettyName(name), `entry: ${generateColor(name)(entries.map((entry$1) => path.relative(cwd, entry$1)).join(", "))}`);
392
+ return entryMap;
393
+ }
394
+ async function toObjectEntry(entry, cwd) {
395
+ if (typeof entry === "string") entry = [entry];
396
+ if (!Array.isArray(entry)) return entry;
397
+ const resolvedEntry = (await glob(entry, { cwd })).map((file) => path.resolve(cwd, file));
398
+ const base = lowestCommonAncestor(...resolvedEntry);
399
+ return Object.fromEntries(resolvedEntry.map((file) => {
400
+ const relative = path.relative(base, file);
401
+ return [relative.slice(0, relative.length - path.extname(relative).length), file];
402
+ }));
439
403
  }
440
404
 
441
405
  //#endregion
442
- //#region src/features/node-protocol.ts
443
- /**
444
- * The `node:` protocol was added in Node.js v14.18.0.
445
- * @see https://nodejs.org/api/esm.html#node-imports
446
- */
447
- function NodeProtocolPlugin(nodeProtocolOption) {
448
- if (nodeProtocolOption === "strip") return {
449
- name: "tsdown:node-protocol:strip",
406
+ //#region src/features/target.ts
407
+ function resolveTarget(logger, target, pkg, name) {
408
+ if (target === false) return;
409
+ if (target == null) {
410
+ const pkgTarget = resolvePackageTarget(pkg);
411
+ if (pkgTarget) target = pkgTarget;
412
+ else return;
413
+ }
414
+ const targets = resolveComma(toArray(target));
415
+ if (targets.length) logger.info(prettyName(name), `target${targets.length > 1 ? "s" : ""}: ${generateColor(name)(targets.join(", "))}`);
416
+ return targets;
417
+ }
418
+ function resolvePackageTarget(pkg) {
419
+ const nodeVersion = pkg?.engines?.node;
420
+ if (!nodeVersion) return;
421
+ const nodeMinVersion = minVersion(nodeVersion);
422
+ if (!nodeMinVersion) return;
423
+ if (nodeMinVersion.version === "0.0.0") return;
424
+ return `node${nodeMinVersion.version}`;
425
+ }
426
+ let warned = false;
427
+ function RuntimeHelperCheckPlugin(logger, targets) {
428
+ return {
429
+ name: "tsdown:runtime-helper-check",
450
430
  resolveId: {
451
- order: "pre",
452
- filter: { id: /^node:/ },
453
- handler(id) {
454
- return {
455
- id: id.slice(5),
456
- external: true,
457
- moduleSideEffects: false
431
+ filter: { id: /^@oxc-project\/runtime/ },
432
+ async handler(id, ...args) {
433
+ const EXTERNAL = {
434
+ id,
435
+ external: true
458
436
  };
437
+ if (warned) return EXTERNAL;
438
+ const resolved = await this.resolve(id, ...args);
439
+ if (!resolved) {
440
+ if (!warned) {
441
+ warned = true;
442
+ logger.warn(`The target environment (${targets.join(", ")}) requires runtime helpers from ${blue`@oxc-project/runtime`}. Please install it to ensure all necessary polyfills are included.\nFor more information, visit: https://tsdown.dev/options/target#runtime-helpers`);
443
+ }
444
+ return EXTERNAL;
445
+ }
446
+ return resolved;
459
447
  }
460
448
  }
461
449
  };
462
- const builtinModulesRegex = /* @__PURE__ */ new RegExp(`^(${builtinModules.join("|")})$`);
463
- return {
464
- name: "tsdown:node-protocol:add",
465
- resolveId: {
466
- order: "pre",
467
- filter: { id: builtinModulesRegex },
468
- handler(id) {
469
- return {
470
- id: `node:${id}`,
471
- external: true,
472
- moduleSideEffects: false
473
- };
450
+ }
451
+
452
+ //#endregion
453
+ //#region src/features/tsconfig.ts
454
+ function findTsconfig(cwd, name = "tsconfig.json") {
455
+ return up(name, { cwd }) || false;
456
+ }
457
+ async function resolveTsconfig(logger, tsconfig, cwd, name) {
458
+ const original = tsconfig;
459
+ if (tsconfig !== false) {
460
+ if (tsconfig === true || tsconfig == null) {
461
+ tsconfig = findTsconfig(cwd);
462
+ if (original && !tsconfig) logger.warn(`No tsconfig found in ${blue(cwd)}`);
463
+ } else {
464
+ const tsconfigPath = path.resolve(cwd, tsconfig);
465
+ const stat$1 = await fsStat(tsconfigPath);
466
+ if (stat$1?.isFile()) tsconfig = tsconfigPath;
467
+ else if (stat$1?.isDirectory()) {
468
+ tsconfig = findTsconfig(tsconfigPath);
469
+ if (!tsconfig) logger.warn(`No tsconfig found in ${blue(tsconfigPath)}`);
470
+ } else {
471
+ tsconfig = findTsconfig(cwd, tsconfig);
472
+ if (!tsconfig) logger.warn(`tsconfig ${blue(original)} doesn't exist`);
474
473
  }
475
474
  }
476
- };
475
+ if (tsconfig) logger.info(prettyName(name), `tsconfig: ${generateColor(name)(path.relative(cwd, tsconfig))}`);
476
+ }
477
+ return tsconfig;
477
478
  }
478
479
 
479
480
  //#endregion
480
481
  //#region src/utils/package.ts
481
- const debug$4 = debug("tsdown:package");
482
+ const debug$5 = debug("tsdown:package");
482
483
  async function readPackageJson(dir) {
483
- const packageJsonPath = up({ cwd: dir });
484
+ const packageJsonPath = up$1({ cwd: dir });
484
485
  if (!packageJsonPath) return;
485
- debug$4("Reading package.json:", packageJsonPath);
486
+ debug$5("Reading package.json:", packageJsonPath);
486
487
  const contents = await readFile(packageJsonPath, "utf8");
487
488
  return {
488
489
  ...JSON.parse(contents),
@@ -508,356 +509,6 @@ function normalizeFormat(format) {
508
509
  });
509
510
  }
510
511
 
511
- //#endregion
512
- //#region src/features/output.ts
513
- function resolveJsOutputExtension(packageType, format, fixedExtension) {
514
- switch (format) {
515
- case "es": return !fixedExtension && packageType === "module" ? "js" : "mjs";
516
- case "cjs": return fixedExtension || packageType === "module" ? "cjs" : "js";
517
- default: return "js";
518
- }
519
- }
520
- function resolveChunkFilename({ outExtensions, fixedExtension, pkg, hash }, inputOptions, format) {
521
- const packageType = getPackageType(pkg);
522
- let jsExtension;
523
- let dtsExtension;
524
- if (outExtensions) {
525
- const { js, dts } = outExtensions({
526
- options: inputOptions,
527
- format,
528
- pkgType: packageType
529
- }) || {};
530
- jsExtension = js;
531
- dtsExtension = dts;
532
- }
533
- jsExtension ||= `.${resolveJsOutputExtension(packageType, format, fixedExtension)}`;
534
- const suffix = format === "iife" || format === "umd" ? `.${format}` : "";
535
- return [createChunkFilename(`[name]${suffix}`, jsExtension, dtsExtension), createChunkFilename(`[name]${suffix}${hash ? "-[hash]" : ""}`, jsExtension, dtsExtension)];
536
- }
537
- function createChunkFilename(basename, jsExtension, dtsExtension) {
538
- if (!dtsExtension) return `${basename}${jsExtension}`;
539
- return (chunk) => {
540
- return `${basename}${chunk.name.endsWith(".d") ? dtsExtension : jsExtension}`;
541
- };
542
- }
543
- function resolveChunkAddon(chunkAddon, format) {
544
- if (!chunkAddon) return;
545
- return (chunk) => {
546
- if (typeof chunkAddon === "function") chunkAddon = chunkAddon({ format });
547
- switch (true) {
548
- case RE_JS.test(chunk.fileName): return chunkAddon?.js || "";
549
- case RE_CSS.test(chunk.fileName): return chunkAddon?.css || "";
550
- case RE_DTS.test(chunk.fileName): return chunkAddon?.dts || "";
551
- default: return "";
552
- }
553
- };
554
- }
555
-
556
- //#endregion
557
- //#region src/features/publint.ts
558
- const debug$3 = debug("tsdown:publint");
559
- async function publint(options) {
560
- if (!options.publint) return;
561
- if (!options.pkg) {
562
- options.logger.warn("publint is enabled but package.json is not found");
563
- return;
564
- }
565
- const t = performance.now();
566
- debug$3("Running publint");
567
- const { publint: publint$1 } = await import("publint");
568
- const { formatMessage } = await import("publint/utils");
569
- const { messages } = await publint$1(options.publint === true ? {} : options.publint);
570
- debug$3("Found %d issues", messages.length);
571
- if (!messages.length) options.logger.success(`No publint issues found`, dim`(${Math.round(performance.now() - t)}ms)`);
572
- let hasError = false;
573
- for (const message of messages) {
574
- hasError ||= message.type === "error";
575
- const formattedMessage = formatMessage(message, options.pkg);
576
- const logType = {
577
- error: "error",
578
- warning: "warn",
579
- suggestion: "info"
580
- }[message.type];
581
- options.logger[logType](formattedMessage);
582
- }
583
- if (hasError) {
584
- debug$3("Found errors, setting exit code to 1");
585
- process.exitCode = 1;
586
- }
587
- }
588
-
589
- //#endregion
590
- //#region src/utils/format.ts
591
- function formatBytes(bytes) {
592
- if (bytes === Infinity) return void 0;
593
- return `${(bytes / 1e3).toFixed(2)} kB`;
594
- }
595
-
596
- //#endregion
597
- //#region src/features/report.ts
598
- const debug$2 = debug("tsdown:report");
599
- const brotliCompressAsync = promisify(brotliCompress);
600
- const gzipAsync = promisify(gzip);
601
- function ReportPlugin(options, logger, cwd, cjsDts, name, isMultiFormat) {
602
- return {
603
- name: "tsdown:report",
604
- async writeBundle(outputOptions, bundle) {
605
- const outDir = path.relative(cwd, outputOptions.file ? path.resolve(cwd, outputOptions.file, "..") : path.resolve(cwd, outputOptions.dir));
606
- const sizes = [];
607
- for (const chunk of Object.values(bundle)) {
608
- const size = await calcSize(options, chunk);
609
- sizes.push(size);
610
- }
611
- const filenameLength = Math.max(...sizes.map((size) => size.filename.length));
612
- const rawTextLength = Math.max(...sizes.map((size) => size.rawText.length));
613
- const gzipTextLength = Math.max(...sizes.map((size) => size.gzipText == null ? 0 : size.gzipText.length));
614
- const brotliTextLength = Math.max(...sizes.map((size) => size.brotliText == null ? 0 : size.brotliText.length));
615
- let totalRaw = 0;
616
- for (const size of sizes) {
617
- size.rawText = size.rawText.padStart(rawTextLength);
618
- size.gzipText = size.gzipText?.padStart(gzipTextLength);
619
- size.brotliText = size.brotliText?.padStart(brotliTextLength);
620
- totalRaw += size.raw;
621
- }
622
- sizes.sort((a, b) => {
623
- if (a.dts !== b.dts) return a.dts ? 1 : -1;
624
- if (a.isEntry !== b.isEntry) return a.isEntry ? -1 : 1;
625
- return b.raw - a.raw;
626
- });
627
- const nameLabel = prettyName(name);
628
- const formatLabel = isMultiFormat && prettyFormat(cjsDts ? "cjs" : outputOptions.format);
629
- for (const size of sizes) {
630
- const filenameColor = size.dts ? green : noop;
631
- logger.info(nameLabel, formatLabel, dim(outDir + path.sep) + filenameColor((size.isEntry ? bold : noop)(size.filename)), ` `.repeat(filenameLength - size.filename.length), dim(size.rawText), size.gzipText && dim`│ gzip: ${size.gzipText}`, options.brotli && size.brotliText && dim`│ brotli: ${size.brotliText}`);
632
- }
633
- const totalSizeText = formatBytes(totalRaw);
634
- logger.info(nameLabel, formatLabel, `${sizes.length} files, total: ${totalSizeText}`);
635
- }
636
- };
637
- }
638
- async function calcSize(options, chunk) {
639
- debug$2(`Calculating size for`, chunk.fileName);
640
- const content = chunk.type === "chunk" ? chunk.code : chunk.source;
641
- const raw = Buffer.byteLength(content, "utf8");
642
- debug$2("[size]", chunk.fileName, raw);
643
- let gzip$1 = Infinity;
644
- let brotli = Infinity;
645
- if (raw > (options.maxCompressSize ?? 1e6)) debug$2(chunk.fileName, "file size exceeds limit, skip gzip/brotli");
646
- else {
647
- gzip$1 = (await gzipAsync(content)).length;
648
- debug$2("[gzip]", chunk.fileName, gzip$1);
649
- if (options.brotli) {
650
- brotli = (await brotliCompressAsync(content)).length;
651
- debug$2("[brotli]", chunk.fileName, brotli);
652
- }
653
- }
654
- return {
655
- filename: chunk.fileName,
656
- dts: RE_DTS.test(chunk.fileName),
657
- isEntry: chunk.type === "chunk" && chunk.isEntry,
658
- raw,
659
- rawText: formatBytes(raw),
660
- gzip: gzip$1,
661
- gzipText: formatBytes(gzip$1),
662
- brotli,
663
- brotliText: formatBytes(brotli)
664
- };
665
- }
666
-
667
- //#endregion
668
- //#region src/features/shims.ts
669
- function getShimsInject(format, platform) {
670
- if (format === "es" && platform === "node") return {
671
- __dirname: [shimFile, "__dirname"],
672
- __filename: [shimFile, "__filename"]
673
- };
674
- }
675
-
676
- //#endregion
677
- //#region src/features/shortcuts.ts
678
- function shortcuts(restart) {
679
- let actionRunning = false;
680
- async function onInput(input) {
681
- if (actionRunning) return;
682
- const SHORTCUTS = [
683
- {
684
- key: "r",
685
- description: "reload config and rebuild",
686
- action() {
687
- rl.close();
688
- restart();
689
- }
690
- },
691
- {
692
- key: "c",
693
- description: "clear console",
694
- action() {
695
- console.clear();
696
- }
697
- },
698
- {
699
- key: "q",
700
- description: "quit",
701
- action() {
702
- process.exit(0);
703
- }
704
- }
705
- ];
706
- if (input === "h") {
707
- const loggedKeys = /* @__PURE__ */ new Set();
708
- globalLogger.info(" Shortcuts");
709
- for (const shortcut$1 of SHORTCUTS) {
710
- if (loggedKeys.has(shortcut$1.key)) continue;
711
- loggedKeys.add(shortcut$1.key);
712
- if (shortcut$1.action == null) continue;
713
- globalLogger.info(dim` press ` + bold`${shortcut$1.key} + enter` + dim` to ${shortcut$1.description}`);
714
- }
715
- return;
716
- }
717
- const shortcut = SHORTCUTS.find((shortcut$1) => shortcut$1.key === input);
718
- if (!shortcut) return;
719
- actionRunning = true;
720
- await shortcut.action();
721
- actionRunning = false;
722
- }
723
- const rl = readline.createInterface({ input: process.stdin });
724
- rl.on("line", onInput);
725
- }
726
-
727
- //#endregion
728
- //#region src/features/target.ts
729
- function resolveTarget(logger, target, pkg, name) {
730
- if (target === false) return;
731
- if (target == null) {
732
- const pkgTarget = resolvePackageTarget(pkg);
733
- if (pkgTarget) target = pkgTarget;
734
- else return;
735
- }
736
- const targets = resolveComma(toArray(target));
737
- if (targets.length) logger.info(prettyName(name), `target${targets.length > 1 ? "s" : ""}: ${generateColor(name)(targets.join(", "))}`);
738
- return targets;
739
- }
740
- function resolvePackageTarget(pkg) {
741
- const nodeVersion = pkg?.engines?.node;
742
- if (!nodeVersion) return;
743
- const nodeMinVersion = minVersion(nodeVersion);
744
- if (!nodeMinVersion) return;
745
- if (nodeMinVersion.version === "0.0.0") return;
746
- return `node${nodeMinVersion.version}`;
747
- }
748
- let warned = false;
749
- function RuntimeHelperCheckPlugin(logger, targets) {
750
- return {
751
- name: "tsdown:runtime-helper-check",
752
- resolveId: {
753
- filter: { id: /^@oxc-project\/runtime/ },
754
- async handler(id, ...args) {
755
- const EXTERNAL = {
756
- id,
757
- external: true
758
- };
759
- if (warned) return EXTERNAL;
760
- const resolved = await this.resolve(id, ...args);
761
- if (!resolved) {
762
- if (!warned) {
763
- warned = true;
764
- logger.warn(`The target environment (${targets.join(", ")}) requires runtime helpers from ${blue`@oxc-project/runtime`}. Please install it to ensure all necessary polyfills are included.\nFor more information, visit: https://tsdown.dev/options/target#runtime-helpers`);
765
- }
766
- return EXTERNAL;
767
- }
768
- return resolved;
769
- }
770
- }
771
- };
772
- }
773
-
774
- //#endregion
775
- //#region src/features/watch.ts
776
- const endsWithConfig = /[\\/](?:package\.json|tsdown\.config.*)$/;
777
- async function watchBuild(options, configFiles, rebuild, restart) {
778
- if (typeof options.watch === "boolean" && options.outDir === options.cwd) throw new Error(`Watch is enabled, but output directory is the same as the current working directory.Please specify a different watch directory using ${blue`watch`} option,or set ${blue`outDir`} to a different directory.`);
779
- const files = toArray(typeof options.watch === "boolean" ? options.cwd : options.watch);
780
- options.logger.info(`Watching for changes in ${files.join(", ")}`);
781
- files.push(...configFiles);
782
- const { watch } = await import("chokidar");
783
- const debouncedRebuild = debounce(rebuild, 100);
784
- const watcher = watch(files, {
785
- ignoreInitial: true,
786
- ignorePermissionErrors: true,
787
- ignored: [
788
- /[\\/]\.git[\\/]/,
789
- /[\\/]node_modules[\\/]/,
790
- options.outDir,
791
- ...options.ignoreWatch
792
- ]
793
- });
794
- watcher.on("all", (type, file) => {
795
- if (configFiles.includes(file) || endsWithConfig.test(file)) {
796
- options.logger.info(`Reload config: ${file}`);
797
- restart();
798
- return;
799
- }
800
- options.logger.info(`Change detected: ${type} ${file}`);
801
- invalidateContextFile(globalContext, file);
802
- debouncedRebuild();
803
- });
804
- return watcher;
805
- }
806
-
807
- //#endregion
808
- //#region src/features/entry.ts
809
- async function resolveEntry(logger, entry, cwd, name) {
810
- const nameLabel = name ? `[${name}] ` : "";
811
- if (!entry || Object.keys(entry).length === 0) {
812
- const defaultEntry = path.resolve(cwd, "src/index.ts");
813
- if (await fsExists(defaultEntry)) entry = { index: defaultEntry };
814
- else throw new Error(`${nameLabel}No input files, try "tsdown <your-file>" or create src/index.ts`);
815
- }
816
- const entryMap = await toObjectEntry(entry, cwd);
817
- const entries = Object.values(entryMap);
818
- if (entries.length === 0) throw new Error(`${nameLabel}Cannot find entry: ${JSON.stringify(entry)}`);
819
- logger.info(prettyName(name), `entry: ${generateColor(name)(entries.map((entry$1) => path.relative(cwd, entry$1)).join(", "))}`);
820
- return entryMap;
821
- }
822
- async function toObjectEntry(entry, cwd) {
823
- if (typeof entry === "string") entry = [entry];
824
- if (!Array.isArray(entry)) return entry;
825
- const resolvedEntry = (await glob(entry, { cwd })).map((file) => path.resolve(cwd, file));
826
- const base = lowestCommonAncestor(...resolvedEntry);
827
- return Object.fromEntries(resolvedEntry.map((file) => {
828
- const relative = path.relative(base, file);
829
- return [relative.slice(0, relative.length - path.extname(relative).length), file];
830
- }));
831
- }
832
-
833
- //#endregion
834
- //#region src/features/tsconfig.ts
835
- function findTsconfig(cwd, name = "tsconfig.json") {
836
- return up$1(name, { cwd }) || false;
837
- }
838
- async function resolveTsconfig(logger, tsconfig, cwd, name) {
839
- const original = tsconfig;
840
- if (tsconfig !== false) {
841
- if (tsconfig === true || tsconfig == null) {
842
- tsconfig = findTsconfig(cwd);
843
- if (original && !tsconfig) logger.warn(`No tsconfig found in ${blue(cwd)}`);
844
- } else {
845
- const tsconfigPath = path.resolve(cwd, tsconfig);
846
- const stat$1 = await fsStat(tsconfigPath);
847
- if (stat$1?.isFile()) tsconfig = tsconfigPath;
848
- else if (stat$1?.isDirectory()) {
849
- tsconfig = findTsconfig(tsconfigPath);
850
- if (!tsconfig) logger.warn(`No tsconfig found in ${blue(tsconfigPath)}`);
851
- } else {
852
- tsconfig = findTsconfig(cwd, tsconfig);
853
- if (!tsconfig) logger.warn(`tsconfig ${blue(original)} doesn't exist`);
854
- }
855
- }
856
- if (tsconfig) logger.info(prettyName(name), `tsconfig: ${generateColor(name)(path.relative(cwd, tsconfig))}`);
857
- }
858
- return tsconfig;
859
- }
860
-
861
512
  //#endregion
862
513
  //#region src/options/config.ts
863
514
  async function loadViteConfig(prefix, cwd) {
@@ -948,7 +599,7 @@ async function loadConfigFile(options, workspace) {
948
599
 
949
600
  //#endregion
950
601
  //#region src/options/index.ts
951
- const debug$1 = debug("tsdown:options");
602
+ const debug$4 = debug("tsdown:options");
952
603
  const DEFAULT_EXCLUDE_WORKSPACE = [
953
604
  "**/node_modules/**",
954
605
  "**/dist/**",
@@ -956,21 +607,20 @@ const DEFAULT_EXCLUDE_WORKSPACE = [
956
607
  "**/t?(e)mp/**"
957
608
  ];
958
609
  async function resolveOptions(options) {
959
- const files = [];
960
- debug$1("options %O", options);
961
- debug$1("loading config file: %s", options.config);
610
+ debug$4("options %O", options);
962
611
  const { configs: rootConfigs, file } = await loadConfigFile(options);
612
+ const files = [];
963
613
  if (file) {
964
614
  files.push(file);
965
- debug$1("loaded root config file %s", file);
966
- debug$1("root configs %o", rootConfigs);
967
- } else debug$1("no root config file found");
615
+ debug$4("loaded root config file %s", file);
616
+ debug$4("root configs %O", rootConfigs);
617
+ } else debug$4("no root config file found");
968
618
  const configs = (await Promise.all(rootConfigs.map(async (rootConfig) => {
969
619
  const { configs: workspaceConfigs, files: workspaceFiles } = await resolveWorkspace(rootConfig, options);
970
620
  if (workspaceFiles) files.push(...workspaceFiles);
971
621
  return Promise.all(workspaceConfigs.filter((config) => !config.workspace || config.entry).map((config) => resolveConfig(config)));
972
622
  }))).flat();
973
- debug$1("resolved configs %O", configs);
623
+ debug$4("resolved configs %O", configs);
974
624
  return {
975
625
  configs,
976
626
  files
@@ -1012,16 +662,16 @@ async function resolveWorkspace(config, options) {
1012
662
  }
1013
663
  const files = [];
1014
664
  const configs = (await Promise.all(packages.map(async (cwd) => {
1015
- debug$1("loading workspace config %s", cwd);
665
+ debug$4("loading workspace config %s", cwd);
1016
666
  const { configs: configs$1, file } = await loadConfigFile({
1017
667
  ...options,
1018
668
  config: workspaceConfig,
1019
669
  cwd
1020
670
  }, cwd);
1021
671
  if (file) {
1022
- debug$1("loaded workspace config file %s", file);
672
+ debug$4("loaded workspace config file %s", file);
1023
673
  files.push(file);
1024
- } else debug$1("no workspace config file found in %s", cwd);
674
+ } else debug$4("no workspace config file found in %s", cwd);
1025
675
  return configs$1.map((config$1) => ({
1026
676
  ...normalized,
1027
677
  cwd,
@@ -1034,8 +684,11 @@ async function resolveWorkspace(config, options) {
1034
684
  };
1035
685
  }
1036
686
  async function resolveConfig(userConfig) {
1037
- let { entry, format = ["es"], plugins = [], clean = true, silent = false, logLevel = silent ? "silent" : "info", 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 } = userConfig;
1038
- const logger = createLogger(logLevel, { customLogger });
687
+ 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 } = userConfig;
688
+ const logger = createLogger(logLevel, {
689
+ customLogger,
690
+ failOnWarn
691
+ });
1039
692
  if (typeof bundle === "boolean") logger.warn("`bundle` option is deprecated. Use `unbundle` instead.");
1040
693
  nodeProtocol = nodeProtocol ?? (removeNodeProtocol ? "strip" : false);
1041
694
  outDir = path.resolve(cwd, outDir);
@@ -1100,15 +753,272 @@ async function resolveConfig(userConfig) {
1100
753
  noExternal,
1101
754
  exports,
1102
755
  unbundle,
1103
- nodeProtocol
756
+ nodeProtocol,
757
+ cjsDefault
1104
758
  };
1105
759
  return config;
1106
760
  }
1107
761
  async function mergeUserOptions(defaults, user, args) {
1108
762
  const userOutputOptions = typeof user === "function" ? await user(defaults, ...args) : user;
1109
763
  return {
1110
- ...defaults,
1111
- ...userOutputOptions
764
+ ...defaults,
765
+ ...userOutputOptions
766
+ };
767
+ }
768
+
769
+ //#endregion
770
+ //#region src/features/external.ts
771
+ const debug$3 = debug("tsdown:external");
772
+ function ExternalPlugin(options) {
773
+ const deps = options.pkg && Array.from(getProductionDeps(options.pkg));
774
+ return {
775
+ name: "tsdown:external",
776
+ async resolveId(id, importer, extraOptions) {
777
+ if (extraOptions.isEntry) return;
778
+ if (id === shimFile) return;
779
+ const { noExternal } = options;
780
+ if (typeof noExternal === "function" && noExternal(id, importer)) return;
781
+ if (noExternal) {
782
+ const noExternalPatterns = toArray(noExternal);
783
+ if (noExternalPatterns.some((pattern) => {
784
+ if (pattern instanceof RegExp) {
785
+ pattern.lastIndex = 0;
786
+ return pattern.test(id);
787
+ }
788
+ return id === pattern;
789
+ })) return;
790
+ }
791
+ let shouldExternal = false;
792
+ if (options.skipNodeModulesBundle) {
793
+ const resolved = await this.resolve(id, importer, extraOptions);
794
+ if (!resolved) return resolved;
795
+ shouldExternal = resolved.external || /[\\/]node_modules[\\/]/.test(resolved.id);
796
+ }
797
+ if (deps) shouldExternal ||= deps.some((dep) => id === dep || id.startsWith(`${dep}/`));
798
+ if (shouldExternal) {
799
+ debug$3("External dependency:", id);
800
+ return {
801
+ id,
802
+ external: shouldExternal,
803
+ moduleSideEffects: id.startsWith("node:") || builtinModules.includes(id) ? false : void 0
804
+ };
805
+ }
806
+ }
807
+ };
808
+ }
809
+ function getProductionDeps(pkg) {
810
+ return new Set([...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})]);
811
+ }
812
+
813
+ //#endregion
814
+ //#region src/utils/lightningcss.ts
815
+ /**
816
+ * Converts esbuild target [^1] (which is also used by Rolldown [^2]) to Lightning CSS targets [^3].
817
+ *
818
+ * [^1]: https://esbuild.github.io/api/#target
819
+ * [^2]: https://github.com/rolldown/rolldown/blob/v1.0.0-beta.8/packages/rolldown/src/binding.d.ts#L1429-L1431
820
+ * [^3]: https://lightningcss.dev/transpilation.html
821
+ */
822
+ function esbuildTargetToLightningCSS(target) {
823
+ let targets;
824
+ const targetString = target.join(" ").toLowerCase();
825
+ const matches = [...targetString.matchAll(TARGET_REGEX)];
826
+ for (const match of matches) {
827
+ const name = match[1];
828
+ const browser = ESBUILD_LIGHTNINGCSS_MAPPING[name];
829
+ if (!browser) continue;
830
+ const version = match[2];
831
+ const versionInt = parseVersion(version);
832
+ if (versionInt == null) continue;
833
+ targets = targets || {};
834
+ targets[browser] = versionInt;
835
+ }
836
+ return targets;
837
+ }
838
+ const TARGET_REGEX = /([a-z]+)(\d+(?:\.\d+)*)/g;
839
+ const ESBUILD_LIGHTNINGCSS_MAPPING = {
840
+ chrome: "chrome",
841
+ edge: "edge",
842
+ firefox: "firefox",
843
+ ie: "ie",
844
+ ios: "ios_saf",
845
+ opera: "opera",
846
+ safari: "safari"
847
+ };
848
+ function parseVersion(version) {
849
+ const [major, minor = 0, patch = 0] = version.split("-")[0].split(".").map((v) => Number.parseInt(v, 10));
850
+ if (Number.isNaN(major) || Number.isNaN(minor) || Number.isNaN(patch)) return null;
851
+ return major << 16 | minor << 8 | patch;
852
+ }
853
+
854
+ //#endregion
855
+ //#region src/features/lightningcss.ts
856
+ async function LightningCSSPlugin(options) {
857
+ const LightningCSS = await import("unplugin-lightningcss/rolldown").catch(() => void 0);
858
+ if (!LightningCSS) return;
859
+ const targets = options.target && esbuildTargetToLightningCSS(options.target);
860
+ if (!targets) return;
861
+ return LightningCSS.default({ options: { targets } });
862
+ }
863
+
864
+ //#endregion
865
+ //#region src/features/node-protocol.ts
866
+ /**
867
+ * The `node:` protocol was added in Node.js v14.18.0.
868
+ * @see https://nodejs.org/api/esm.html#node-imports
869
+ */
870
+ function NodeProtocolPlugin(nodeProtocolOption) {
871
+ if (nodeProtocolOption === "strip") return {
872
+ name: "tsdown:node-protocol:strip",
873
+ resolveId: {
874
+ order: "pre",
875
+ filter: { id: /^node:/ },
876
+ handler(id) {
877
+ return {
878
+ id: id.slice(5),
879
+ external: true,
880
+ moduleSideEffects: false
881
+ };
882
+ }
883
+ }
884
+ };
885
+ const builtinModulesRegex = /* @__PURE__ */ new RegExp(`^(${builtinModules.join("|")})$`);
886
+ return {
887
+ name: "tsdown:node-protocol:add",
888
+ resolveId: {
889
+ order: "pre",
890
+ filter: { id: builtinModulesRegex },
891
+ handler(id) {
892
+ return {
893
+ id: `node:${id}`,
894
+ external: true,
895
+ moduleSideEffects: false
896
+ };
897
+ }
898
+ }
899
+ };
900
+ }
901
+
902
+ //#endregion
903
+ //#region src/features/output.ts
904
+ function resolveJsOutputExtension(packageType, format, fixedExtension) {
905
+ switch (format) {
906
+ case "es": return !fixedExtension && packageType === "module" ? "js" : "mjs";
907
+ case "cjs": return fixedExtension || packageType === "module" ? "cjs" : "js";
908
+ default: return "js";
909
+ }
910
+ }
911
+ function resolveChunkFilename({ outExtensions, fixedExtension, pkg, hash }, inputOptions, format) {
912
+ const packageType = getPackageType(pkg);
913
+ let jsExtension;
914
+ let dtsExtension;
915
+ if (outExtensions) {
916
+ const { js, dts } = outExtensions({
917
+ options: inputOptions,
918
+ format,
919
+ pkgType: packageType
920
+ }) || {};
921
+ jsExtension = js;
922
+ dtsExtension = dts;
923
+ }
924
+ jsExtension ||= `.${resolveJsOutputExtension(packageType, format, fixedExtension)}`;
925
+ const suffix = format === "iife" || format === "umd" ? `.${format}` : "";
926
+ return [createChunkFilename(`[name]${suffix}`, jsExtension, dtsExtension), createChunkFilename(`[name]${suffix}${hash ? "-[hash]" : ""}`, jsExtension, dtsExtension)];
927
+ }
928
+ function createChunkFilename(basename, jsExtension, dtsExtension) {
929
+ if (!dtsExtension) return `${basename}${jsExtension}`;
930
+ return (chunk) => {
931
+ return `${basename}${chunk.name.endsWith(".d") ? dtsExtension : jsExtension}`;
932
+ };
933
+ }
934
+ function resolveChunkAddon(chunkAddon, format) {
935
+ if (!chunkAddon) return;
936
+ return (chunk) => {
937
+ if (typeof chunkAddon === "function") chunkAddon = chunkAddon({ format });
938
+ switch (true) {
939
+ case RE_JS.test(chunk.fileName): return chunkAddon?.js || "";
940
+ case RE_CSS.test(chunk.fileName): return chunkAddon?.css || "";
941
+ case RE_DTS.test(chunk.fileName): return chunkAddon?.dts || "";
942
+ default: return "";
943
+ }
944
+ };
945
+ }
946
+
947
+ //#endregion
948
+ //#region src/utils/format.ts
949
+ function formatBytes(bytes) {
950
+ if (bytes === Infinity) return void 0;
951
+ return `${(bytes / 1e3).toFixed(2)} kB`;
952
+ }
953
+
954
+ //#endregion
955
+ //#region src/features/report.ts
956
+ const debug$2 = debug("tsdown:report");
957
+ const brotliCompressAsync = promisify(brotliCompress);
958
+ const gzipAsync = promisify(gzip);
959
+ function ReportPlugin(options, logger, cwd, cjsDts, name, isMultiFormat) {
960
+ return {
961
+ name: "tsdown:report",
962
+ async writeBundle(outputOptions, bundle) {
963
+ const outDir = path.relative(cwd, outputOptions.file ? path.resolve(cwd, outputOptions.file, "..") : path.resolve(cwd, outputOptions.dir));
964
+ const sizes = [];
965
+ for (const chunk of Object.values(bundle)) {
966
+ const size = await calcSize(options, chunk);
967
+ sizes.push(size);
968
+ }
969
+ const filenameLength = Math.max(...sizes.map((size) => size.filename.length));
970
+ const rawTextLength = Math.max(...sizes.map((size) => size.rawText.length));
971
+ const gzipTextLength = Math.max(...sizes.map((size) => size.gzipText == null ? 0 : size.gzipText.length));
972
+ const brotliTextLength = Math.max(...sizes.map((size) => size.brotliText == null ? 0 : size.brotliText.length));
973
+ let totalRaw = 0;
974
+ for (const size of sizes) {
975
+ size.rawText = size.rawText.padStart(rawTextLength);
976
+ size.gzipText = size.gzipText?.padStart(gzipTextLength);
977
+ size.brotliText = size.brotliText?.padStart(brotliTextLength);
978
+ totalRaw += size.raw;
979
+ }
980
+ sizes.sort((a, b) => {
981
+ if (a.dts !== b.dts) return a.dts ? 1 : -1;
982
+ if (a.isEntry !== b.isEntry) return a.isEntry ? -1 : 1;
983
+ return b.raw - a.raw;
984
+ });
985
+ const nameLabel = prettyName(name);
986
+ const formatLabel = isMultiFormat && prettyFormat(cjsDts ? "cjs" : outputOptions.format);
987
+ for (const size of sizes) {
988
+ const filenameColor = size.dts ? green : noop;
989
+ logger.info(nameLabel, formatLabel, dim(outDir + path.sep) + filenameColor((size.isEntry ? bold : noop)(size.filename)), ` `.repeat(filenameLength - size.filename.length), dim(size.rawText), size.gzipText && dim`│ gzip: ${size.gzipText}`, options.brotli && size.brotliText && dim`│ brotli: ${size.brotliText}`);
990
+ }
991
+ const totalSizeText = formatBytes(totalRaw);
992
+ logger.info(nameLabel, formatLabel, `${sizes.length} files, total: ${totalSizeText}`);
993
+ }
994
+ };
995
+ }
996
+ async function calcSize(options, chunk) {
997
+ debug$2(`Calculating size for`, chunk.fileName);
998
+ const content = chunk.type === "chunk" ? chunk.code : chunk.source;
999
+ const raw = Buffer.byteLength(content, "utf8");
1000
+ debug$2("[size]", chunk.fileName, raw);
1001
+ let gzip$1 = Infinity;
1002
+ let brotli = Infinity;
1003
+ if (raw > (options.maxCompressSize ?? 1e6)) debug$2(chunk.fileName, "file size exceeds limit, skip gzip/brotli");
1004
+ else {
1005
+ gzip$1 = (await gzipAsync(content)).length;
1006
+ debug$2("[gzip]", chunk.fileName, gzip$1);
1007
+ if (options.brotli) {
1008
+ brotli = (await brotliCompressAsync(content)).length;
1009
+ debug$2("[brotli]", chunk.fileName, brotli);
1010
+ }
1011
+ }
1012
+ return {
1013
+ filename: chunk.fileName,
1014
+ dts: RE_DTS.test(chunk.fileName),
1015
+ isEntry: chunk.type === "chunk" && chunk.isEntry,
1016
+ raw,
1017
+ rawText: formatBytes(raw),
1018
+ gzip: gzip$1,
1019
+ gzipText: formatBytes(gzip$1),
1020
+ brotli,
1021
+ brotliText: formatBytes(brotli)
1112
1022
  };
1113
1023
  }
1114
1024
 
@@ -1132,6 +1042,190 @@ function ShebangPlugin(logger, cwd, name, isMultiFormat) {
1132
1042
  };
1133
1043
  }
1134
1044
 
1045
+ //#endregion
1046
+ //#region src/features/shims.ts
1047
+ function getShimsInject(format, platform) {
1048
+ if (format === "es" && platform === "node") return {
1049
+ __dirname: [shimFile, "__dirname"],
1050
+ __filename: [shimFile, "__filename"]
1051
+ };
1052
+ }
1053
+
1054
+ //#endregion
1055
+ //#region src/features/rolldown.ts
1056
+ const debug$1 = debug("tsdown:rolldown");
1057
+ async function getBuildOptions(config, format, isMultiFormat, cjsDts = false) {
1058
+ const inputOptions = await resolveInputOptions(config, format, cjsDts, isMultiFormat);
1059
+ const outputOptions = await resolveOutputOptions(inputOptions, config, format, cjsDts);
1060
+ const rolldownConfig = {
1061
+ ...inputOptions,
1062
+ output: outputOptions
1063
+ };
1064
+ debug$1("rolldown config with format \"%s\" %O", cjsDts ? "cjs dts" : format, rolldownConfig);
1065
+ return rolldownConfig;
1066
+ }
1067
+ async function resolveInputOptions(config, format, cjsDts, isMultiFormat) {
1068
+ const { entry, external, plugins: userPlugins, platform, alias, treeshake, dts, unused, target, define, shims, tsconfig, cwd, report, env, nodeProtocol, loader, name, logger, cjsDefault } = config;
1069
+ const plugins = [];
1070
+ if (nodeProtocol) plugins.push(NodeProtocolPlugin(nodeProtocol));
1071
+ if (config.pkg || config.skipNodeModulesBundle) plugins.push(ExternalPlugin(config));
1072
+ if (dts) {
1073
+ const { dts: dtsPlugin } = await import("rolldown-plugin-dts");
1074
+ const options = {
1075
+ tsconfig,
1076
+ ...dts
1077
+ };
1078
+ if (format === "es") plugins.push(dtsPlugin(options));
1079
+ else if (cjsDts) plugins.push(dtsPlugin({
1080
+ ...options,
1081
+ emitDtsOnly: true,
1082
+ cjsDefault
1083
+ }));
1084
+ }
1085
+ if (!cjsDts) {
1086
+ if (unused) {
1087
+ const { Unused } = await import("unplugin-unused");
1088
+ plugins.push(Unused.rolldown(unused === true ? {} : unused));
1089
+ }
1090
+ if (target) plugins.push(RuntimeHelperCheckPlugin(logger, target), await LightningCSSPlugin({ target }));
1091
+ plugins.push(ShebangPlugin(logger, cwd, name, isMultiFormat));
1092
+ }
1093
+ if (report && LogLevels[logger.level] >= 3) plugins.push(ReportPlugin(report, logger, cwd, cjsDts, name, isMultiFormat));
1094
+ if (!cjsDts) plugins.push(userPlugins);
1095
+ const inputOptions = await mergeUserOptions({
1096
+ input: entry,
1097
+ cwd,
1098
+ external,
1099
+ resolve: {
1100
+ alias,
1101
+ tsconfigFilename: tsconfig || void 0
1102
+ },
1103
+ treeshake,
1104
+ platform: cjsDts || format === "cjs" ? "node" : platform,
1105
+ define: {
1106
+ ...define,
1107
+ ...Object.keys(env).reduce((acc, key) => {
1108
+ const value = JSON.stringify(env[key]);
1109
+ acc[`process.env.${key}`] = value;
1110
+ acc[`import.meta.env.${key}`] = value;
1111
+ return acc;
1112
+ }, Object.create(null))
1113
+ },
1114
+ transform: { target },
1115
+ plugins,
1116
+ inject: { ...shims && !cjsDts && getShimsInject(format, platform) },
1117
+ moduleTypes: loader,
1118
+ onLog: cjsDefault ? (level, log, defaultHandler) => {
1119
+ if (log.code === "MIXED_EXPORT") return;
1120
+ defaultHandler(level, log);
1121
+ } : void 0
1122
+ }, config.inputOptions, [format, { cjsDts }]);
1123
+ return inputOptions;
1124
+ }
1125
+ async function resolveOutputOptions(inputOptions, config, format, cjsDts) {
1126
+ const { entry, outDir, sourcemap, minify, unbundle, banner, footer, cjsDefault } = config;
1127
+ const [entryFileNames, chunkFileNames] = resolveChunkFilename(config, inputOptions, format);
1128
+ const outputOptions = await mergeUserOptions({
1129
+ format: cjsDts ? "es" : format,
1130
+ name: config.globalName,
1131
+ sourcemap,
1132
+ dir: outDir,
1133
+ exports: cjsDefault ? "auto" : "named",
1134
+ minify: !cjsDts && minify,
1135
+ entryFileNames,
1136
+ chunkFileNames,
1137
+ preserveModules: unbundle,
1138
+ preserveModulesRoot: unbundle ? lowestCommonAncestor(...Object.values(entry)) : void 0,
1139
+ banner: resolveChunkAddon(banner, format),
1140
+ footer: resolveChunkAddon(footer, format)
1141
+ }, config.outputOptions, [format, { cjsDts }]);
1142
+ return outputOptions;
1143
+ }
1144
+
1145
+ //#endregion
1146
+ //#region src/features/shortcuts.ts
1147
+ function shortcuts(restart) {
1148
+ let actionRunning = false;
1149
+ async function onInput(input) {
1150
+ if (actionRunning) return;
1151
+ const SHORTCUTS = [
1152
+ {
1153
+ key: "r",
1154
+ description: "reload config and rebuild",
1155
+ action() {
1156
+ rl.close();
1157
+ restart();
1158
+ }
1159
+ },
1160
+ {
1161
+ key: "c",
1162
+ description: "clear console",
1163
+ action() {
1164
+ console.clear();
1165
+ }
1166
+ },
1167
+ {
1168
+ key: "q",
1169
+ description: "quit",
1170
+ action() {
1171
+ process.exit(0);
1172
+ }
1173
+ }
1174
+ ];
1175
+ if (input === "h") {
1176
+ const loggedKeys = /* @__PURE__ */ new Set();
1177
+ globalLogger.info(" Shortcuts");
1178
+ for (const shortcut$1 of SHORTCUTS) {
1179
+ if (loggedKeys.has(shortcut$1.key)) continue;
1180
+ loggedKeys.add(shortcut$1.key);
1181
+ if (shortcut$1.action == null) continue;
1182
+ globalLogger.info(dim` press ` + bold`${shortcut$1.key} + enter` + dim` to ${shortcut$1.description}`);
1183
+ }
1184
+ return;
1185
+ }
1186
+ const shortcut = SHORTCUTS.find((shortcut$1) => shortcut$1.key === input);
1187
+ if (!shortcut) return;
1188
+ actionRunning = true;
1189
+ await shortcut.action();
1190
+ actionRunning = false;
1191
+ }
1192
+ const rl = readline.createInterface({ input: process.stdin });
1193
+ rl.on("line", onInput);
1194
+ }
1195
+
1196
+ //#endregion
1197
+ //#region src/features/watch.ts
1198
+ const endsWithConfig = /[\\/](?:package\.json|tsdown\.config.*)$/;
1199
+ async function watchBuild(options, configFiles, rebuild, restart) {
1200
+ if (typeof options.watch === "boolean" && options.outDir === options.cwd) throw new Error(`Watch is enabled, but output directory is the same as the current working directory.Please specify a different watch directory using ${blue`watch`} option,or set ${blue`outDir`} to a different directory.`);
1201
+ const files = toArray(typeof options.watch === "boolean" ? options.cwd : options.watch);
1202
+ options.logger.info(`Watching for changes in ${files.join(", ")}`);
1203
+ files.push(...configFiles);
1204
+ const { watch } = await import("chokidar");
1205
+ const debouncedRebuild = debounce(rebuild, 100);
1206
+ const watcher = watch(files, {
1207
+ ignoreInitial: true,
1208
+ ignorePermissionErrors: true,
1209
+ ignored: [
1210
+ /[\\/]\.git[\\/]/,
1211
+ /[\\/]node_modules[\\/]/,
1212
+ options.outDir,
1213
+ ...options.ignoreWatch
1214
+ ]
1215
+ });
1216
+ watcher.on("all", (type, file) => {
1217
+ if (configFiles.includes(file) || endsWithConfig.test(file)) {
1218
+ options.logger.info(`Reload config: ${file}`);
1219
+ restart();
1220
+ return;
1221
+ }
1222
+ options.logger.info(`Change detected: ${type} ${file}`);
1223
+ invalidateContextFile(globalContext, file);
1224
+ debouncedRebuild();
1225
+ });
1226
+ return watcher;
1227
+ }
1228
+
1135
1229
  //#endregion
1136
1230
  //#region src/index.ts
1137
1231
  /**
@@ -1230,77 +1324,6 @@ async function buildSingle(config, clean) {
1230
1324
  } else await onSuccess?.(config, ab.signal);
1231
1325
  }
1232
1326
  }
1233
- async function getBuildOptions(config, format, isMultiFormat, cjsDts) {
1234
- const { entry, external, plugins: userPlugins, outDir, platform, alias, treeshake, sourcemap, dts, minify, unused, target, define, shims, tsconfig, cwd, report, env, nodeProtocol, loader, name, unbundle, banner, footer, logger } = config;
1235
- const plugins = [];
1236
- if (nodeProtocol) plugins.push(NodeProtocolPlugin(nodeProtocol));
1237
- if (config.pkg || config.skipNodeModulesBundle) plugins.push(ExternalPlugin(config));
1238
- if (dts) {
1239
- const { dts: dtsPlugin } = await import("rolldown-plugin-dts");
1240
- const options = {
1241
- tsconfig,
1242
- ...dts
1243
- };
1244
- if (format === "es") plugins.push(dtsPlugin(options));
1245
- else if (cjsDts) plugins.push(dtsPlugin({
1246
- ...options,
1247
- emitDtsOnly: true
1248
- }));
1249
- }
1250
- if (!cjsDts) {
1251
- if (unused) {
1252
- const { Unused } = await import("unplugin-unused");
1253
- plugins.push(Unused.rolldown(unused === true ? {} : unused));
1254
- }
1255
- if (target) plugins.push(RuntimeHelperCheckPlugin(logger, target), await LightningCSSPlugin({ target }));
1256
- plugins.push(ShebangPlugin(logger, cwd, name, isMultiFormat));
1257
- }
1258
- if (report && LogLevels[logger.level] >= 3) plugins.push(ReportPlugin(report, logger, cwd, cjsDts, name, isMultiFormat));
1259
- if (!cjsDts) plugins.push(userPlugins);
1260
- cjsDts = !!cjsDts;
1261
- const inputOptions = await mergeUserOptions({
1262
- input: entry,
1263
- cwd,
1264
- external,
1265
- resolve: {
1266
- alias,
1267
- tsconfigFilename: tsconfig || void 0
1268
- },
1269
- treeshake,
1270
- platform: cjsDts || format === "cjs" ? "node" : platform,
1271
- define: {
1272
- ...define,
1273
- ...Object.keys(env).reduce((acc, key) => {
1274
- const value = JSON.stringify(env[key]);
1275
- acc[`process.env.${key}`] = value;
1276
- acc[`import.meta.env.${key}`] = value;
1277
- return acc;
1278
- }, Object.create(null))
1279
- },
1280
- transform: { target },
1281
- plugins,
1282
- inject: { ...shims && !cjsDts && getShimsInject(format, platform) },
1283
- moduleTypes: loader
1284
- }, config.inputOptions, [format, { cjsDts }]);
1285
- const [entryFileNames, chunkFileNames] = resolveChunkFilename(config, inputOptions, format);
1286
- const outputOptions = await mergeUserOptions({
1287
- format: cjsDts ? "es" : format,
1288
- name: config.globalName,
1289
- sourcemap,
1290
- dir: outDir,
1291
- minify: !cjsDts && minify,
1292
- entryFileNames,
1293
- chunkFileNames,
1294
- preserveModules: unbundle,
1295
- preserveModulesRoot: unbundle ? lowestCommonAncestor(...Object.values(entry)) : void 0,
1296
- banner: resolveChunkAddon(banner, format),
1297
- footer: resolveChunkAddon(footer, format)
1298
- }, config.outputOptions, [format, { cjsDts }]);
1299
- return {
1300
- ...inputOptions,
1301
- output: outputOptions
1302
- };
1303
- }
1304
1327
 
1305
1328
  //#endregion
1306
1329
  export { ExternalPlugin, NodeProtocolPlugin, ReportPlugin, ShebangPlugin, build$1 as build, buildSingle, shimFile };