@d1g1tal/tsbuild 1.8.1 → 1.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ ## [1.8.3](https://github.com/D1g1talEntr0py/tsbuild/compare/v1.8.2...v1.8.3) (2026-04-11)
2
+
3
+ ### Performance Improvements
4
+
5
+ * **core:** optimize build performance and decrease startup time (5cc35a8e0c6acc45dff38f6186e9f5b8f59ee8bf)
6
+ - use sets instead of arrays for faster lookups
7
+ - replace string concatenation with array joins
8
+ - replace object.keys with for-in loops
9
+ - cache regex patterns and avoid repeated compilations
10
+ - dynamically import esbuild and watchr to reduce startup time
11
+ - replace map/reduce chains with single loops for better performance
12
+
13
+
14
+ ### Miscellaneous Chores
15
+
16
+ * **deps:** update dependency @types/node to ^25.6.0 (a99b720acf5c2d3ed4116605e66fbd0f0174259f)
17
+
18
+ ## [1.8.2](https://github.com/D1g1talEntr0py/tsbuild/compare/v1.8.1...v1.8.2) (2026-04-09)
19
+
20
+ ### Bug Fixes
21
+
22
+ * **build:** add handling for modules where the export uses 'as' (d96f626e7329188e702cd32bd8ba028810647d06)
23
+
1
24
  ## [1.8.1](https://github.com/D1g1talEntr0py/tsbuild/compare/v1.8.0...v1.8.1) (2026-04-09)
2
25
 
3
26
  ### Bug Fixes
@@ -139,9 +139,6 @@ var Files = class _Files {
139
139
  }
140
140
  };
141
141
 
142
- // src/type-script-project.ts
143
- import { Watchr } from "@d1g1tal/watchr";
144
-
145
142
  // src/text-formatter.ts
146
143
  import { isatty } from "node:tty";
147
144
  var { env = {}, platform = "" } = process;
@@ -204,6 +201,8 @@ var TextFormat = class {
204
201
  };
205
202
 
206
203
  // src/logger.ts
204
+ var LOG_1024 = Math.log(1024);
205
+ var ansiEscapePattern = /\x1b\[[0-9;]*m/g;
207
206
  var isWrittenFiles = (data) => {
208
207
  if (!Array.isArray(data)) {
209
208
  return false;
@@ -231,7 +230,7 @@ var prettyBytes = (bytes) => {
231
230
  if (bytes === 0) {
232
231
  return { value: "0", unit: "B" };
233
232
  }
234
- const exp = ~~(Math.log(bytes) / Math.log(1024));
233
+ const exp = ~~(Math.log(bytes) / LOG_1024);
235
234
  return { value: (bytes / Math.pow(1024, exp)).toFixed(2), unit: dataUnits[exp] };
236
235
  };
237
236
  var Logger = class _Logger {
@@ -255,7 +254,7 @@ var Logger = class _Logger {
255
254
  * @param message The message to display in the header.
256
255
  */
257
256
  static header(message) {
258
- const innerWidth = message.replace(new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g"), "").length + 2;
257
+ const innerWidth = message.replace(ansiEscapePattern, "").length + 2;
259
258
  console.log(TextFormat.cyan(`\u256D${"\u2500".repeat(innerWidth)}\u256E${newLine}\u2502 ${message} \u2502${newLine}\u2570${"\u2500".repeat(innerWidth)}\u256F`));
260
259
  }
261
260
  /**
@@ -283,8 +282,17 @@ var Logger = class _Logger {
283
282
  if (visible.length === 0) {
284
283
  return;
285
284
  }
286
- const maxNameLength = visible.reduce((max, { name }) => Math.max(max, name.length), 0);
287
- const maxDurationLength = visible.reduce((max, { duration }) => Math.max(max, duration.length), 0);
285
+ let maxNameLength = 0;
286
+ let maxDurationLength = 0;
287
+ for (let i = 0, length = visible.length; i < length; i++) {
288
+ const { name, duration } = visible[i];
289
+ if (name.length > maxNameLength) {
290
+ maxNameLength = name.length;
291
+ }
292
+ if (duration.length > maxDurationLength) {
293
+ maxDurationLength = duration.length;
294
+ }
295
+ }
288
296
  for (let i = 0, length = visible.length; i < length; i++) {
289
297
  const { name, duration } = visible[i];
290
298
  const prefix = i === length - 1 ? " \u2514\u2500" : " \u251C\u2500";
@@ -353,10 +361,24 @@ var Logger = class _Logger {
353
361
  * @internal
354
362
  */
355
363
  static files(files) {
356
- const maxPathLength = files.reduce((max, { path }) => Math.max(max, path.length), 0);
357
- const formatted = files.map(({ path, size }) => ({ path, ...prettyBytes(size) }));
358
- const maxValueLength = formatted.reduce((max, { value }) => Math.max(max, value.length), 0);
359
- const maxUnitLength = formatted.reduce((max, { unit }) => Math.max(max, unit.length), 0);
364
+ let maxPathLength = 0;
365
+ let maxValueLength = 0;
366
+ let maxUnitLength = 0;
367
+ const formatted = [];
368
+ for (let i = 0, length = files.length; i < length; i++) {
369
+ const { path, size } = files[i];
370
+ const { value, unit } = prettyBytes(size);
371
+ if (path.length > maxPathLength) {
372
+ maxPathLength = path.length;
373
+ }
374
+ if (value.length > maxValueLength) {
375
+ maxValueLength = value.length;
376
+ }
377
+ if (unit.length > maxUnitLength) {
378
+ maxUnitLength = unit.length;
379
+ }
380
+ formatted.push({ path, value, unit });
381
+ }
360
382
  for (let i = 0, length = formatted.length; i < length; i++) {
361
383
  const { path, value, unit } = formatted[i];
362
384
  const paddedPath = path.padEnd(maxPathLength);
@@ -536,17 +558,13 @@ var DeclarationProcessor = class _DeclarationProcessor {
536
558
  function createNamespaceImport(fileId) {
537
559
  let importName = inlineImports.get(fileId);
538
560
  if (importName === void 0) {
539
- let sanitized = "";
561
+ const chars = [];
540
562
  for (let i = 0; i < fileId.length; i++) {
541
563
  const char = fileId[i];
542
564
  const code2 = char.charCodeAt(0);
543
- if (code2 >= 97 && code2 <= 122 || code2 >= 65 && code2 <= 90 || code2 >= 48 && code2 <= 57 || code2 === 95 || code2 === 36) {
544
- sanitized += char;
545
- } else {
546
- sanitized += "_";
547
- }
565
+ chars.push(code2 >= 97 && code2 <= 122 || code2 >= 65 && code2 <= 90 || code2 >= 48 && code2 <= 57 || code2 === 95 || code2 === 36 ? char : "_");
548
566
  }
549
- importName = generateUniqueName(sanitized);
567
+ importName = generateUniqueName(chars.join(""));
550
568
  inlineImports.set(fileId, importName);
551
569
  }
552
570
  return importName;
@@ -1206,8 +1224,9 @@ var DeclarationBundler = class {
1206
1224
  };
1207
1225
  forEachChild2(sourceFile, visitQualified);
1208
1226
  }
1209
- const finalValueExports = [...new Set(valueExports.map(exportsMapper))];
1210
- const finalTypeExports = [...new Set(typeExports.map(exportsMapper).filter((t) => !new Set(finalValueExports).has(t)))];
1227
+ const finalValueExportsSet = new Set(valueExports.map(exportsMapper));
1228
+ const finalValueExports = [...finalValueExportsSet];
1229
+ const finalTypeExports = [...new Set(typeExports.map(exportsMapper).filter((t) => !finalValueExportsSet.has(t)))];
1211
1230
  return { code: magic.toString(), externalImports, typeExports: finalTypeExports, valueExports: finalValueExports };
1212
1231
  }
1213
1232
  /**
@@ -1282,8 +1301,8 @@ var DeclarationBundler = class {
1282
1301
  }
1283
1302
  }
1284
1303
  const uniqueTypeReferences = [...typeReferencesSet];
1285
- const finalValueExports = [...new Set(allValueExports)];
1286
- const finalValueExportsSet = new Set(finalValueExports);
1304
+ const finalValueExportsSet = new Set(allValueExports);
1305
+ const finalValueExports = [...finalValueExportsSet];
1287
1306
  const finalTypeExports = [...new Set(allTypeExports.filter((typeExport) => !finalValueExportsSet.has(typeExport)))];
1288
1307
  const outputParts = [];
1289
1308
  if (uniqueFileReferences.length > 0) {
@@ -1519,9 +1538,8 @@ async function resolvePlugins(plugins, projectDir) {
1519
1538
  }
1520
1539
 
1521
1540
  // src/plugins/iife.ts
1522
- import { basename as basename2, dirname as dirname2, join, relative, resolve as resolve2 } from "node:path";
1523
1541
  import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
1524
- import { build as esbuild } from "esbuild";
1542
+ import { basename as basename2, dirname as dirname2, join, resolve as resolve2 } from "node:path";
1525
1543
  var textDecoder2 = new TextDecoder();
1526
1544
  var jsExtension = ".js";
1527
1545
  function iifePlugin(options) {
@@ -1570,32 +1588,44 @@ function extractEntryNames(entryPoints) {
1570
1588
  }
1571
1589
  return Object.keys(entryPoints);
1572
1590
  }
1573
- var exportBlockStart = "\nexport {";
1574
- var exportBlockEnd = "\n};";
1591
+ var exportRegex = /export\s*\{([^}]*)\};?/g;
1592
+ var exportAliasRegex = /^(\w+)\s+as\s+(\w+)$/;
1575
1593
  function wrapAsIife(text, globalName) {
1576
- const start = text.lastIndexOf(exportBlockStart);
1577
- if (start === -1) {
1594
+ const exportIndex = text.lastIndexOf("export");
1595
+ if (exportIndex === -1) {
1578
1596
  return text;
1579
1597
  }
1580
- const end = text.indexOf(exportBlockEnd, start) + exportBlockEnd.length;
1581
- const block = text.slice(start + 1, end);
1582
- const names = [...block.matchAll(/^\s+(\w+)/gm)].map((m) => m[1]);
1583
- if (names.length === 0) {
1598
+ exportRegex.lastIndex = exportIndex;
1599
+ const last = exportRegex.exec(text);
1600
+ if (!last) {
1601
+ return text;
1602
+ }
1603
+ const props = [];
1604
+ for (const raw of last[1].split(",")) {
1605
+ const trimmed = raw.trim();
1606
+ if (!trimmed) {
1607
+ continue;
1608
+ }
1609
+ const m = exportAliasRegex.exec(trimmed);
1610
+ props.push(m ? `${m[2]}: ${m[1]}` : trimmed);
1611
+ }
1612
+ if (props.length === 0) {
1584
1613
  return text;
1585
1614
  }
1586
- const assignment = globalName ? `globalThis.${globalName} = { ${names.join(", ")} };` : `Object.assign(globalThis, { ${names.join(", ")} });`;
1587
- const body = text.slice(0, start);
1588
- const after = text.slice(end);
1615
+ const assignment = globalName ? `globalThis.${globalName} = { ${props.join(", ")} };` : `Object.assign(globalThis, { ${props.join(", ")} });`;
1616
+ const body = text.slice(0, last.index);
1617
+ const after = text.slice(last.index + last[0].length);
1589
1618
  return `(() => {
1590
1619
  ${body}
1591
1620
  ${assignment}
1592
1621
  })();${after}`;
1593
1622
  }
1594
1623
  async function buildIife(outputFiles, entryPointNames, outdir, globalName, sourcemap) {
1624
+ const { build: esbuild } = await import("esbuild");
1595
1625
  const fileContents = /* @__PURE__ */ new Map();
1596
- for (const file of outputFiles) {
1597
- if (file.path.endsWith(jsExtension)) {
1598
- fileContents.set(file.path, textDecoder2.decode(file.contents));
1626
+ for (const { path, contents } of outputFiles) {
1627
+ if (path.endsWith(jsExtension)) {
1628
+ fileContents.set(path, textDecoder2.decode(contents));
1599
1629
  }
1600
1630
  }
1601
1631
  const validEntries = [];
@@ -1627,15 +1657,16 @@ async function buildIife(outputFiles, entryPointNames, outdir, globalName, sourc
1627
1657
  ));
1628
1658
  const written = [];
1629
1659
  const writes = [];
1660
+ const cwd = process.cwd();
1630
1661
  for (const { outputFiles: iifeFiles } of results) {
1631
- for (const file of iifeFiles) {
1632
- if (file.path.endsWith(jsExtension)) {
1633
- const text = wrapAsIife(textDecoder2.decode(file.contents), globalName);
1634
- writes.push(writeFile3(file.path, text));
1635
- written.push({ path: relative(process.cwd(), file.path), size: Buffer.byteLength(text) });
1662
+ for (const { path, contents } of iifeFiles) {
1663
+ if (path.endsWith(jsExtension)) {
1664
+ const text = wrapAsIife(textDecoder2.decode(contents), globalName);
1665
+ writes.push(writeFile3(path, text));
1666
+ written.push({ path: Paths.relative(cwd, path), size: Buffer.byteLength(text) });
1636
1667
  } else {
1637
- writes.push(writeFile3(file.path, file.contents));
1638
- written.push({ path: relative(process.cwd(), file.path), size: file.contents.byteLength });
1668
+ writes.push(writeFile3(path, contents));
1669
+ written.push({ path: Paths.relative(cwd, path), size: contents.byteLength });
1639
1670
  }
1640
1671
  }
1641
1672
  }
@@ -2022,8 +2053,9 @@ var FileManager = class {
2022
2053
  return defaultEntryPoint in projectEntryPoints ? { [defaultEntryPoint]: projectEntryPoints[defaultEntryPoint] } : projectEntryPoints;
2023
2054
  }
2024
2055
  const result = {};
2056
+ const allowedEntryPoints = new Set(dtsEntryPoints);
2025
2057
  for (const [name, path] of Object.entries(projectEntryPoints)) {
2026
- if (dtsEntryPoints.includes(name)) {
2058
+ if (allowedEntryPoints.has(name)) {
2027
2059
  result[name] = path;
2028
2060
  }
2029
2061
  }
@@ -2287,7 +2319,12 @@ function inferEntryPoints(packageJson, outDir, sourceDir = "src") {
2287
2319
  }
2288
2320
  }
2289
2321
  }
2290
- if (Object.keys(entryPoints).length === 0) {
2322
+ let hasEntries = false;
2323
+ for (const _ in entryPoints) {
2324
+ hasEntries = true;
2325
+ break;
2326
+ }
2327
+ if (!hasEntries) {
2291
2328
  const legacyPath = packageJson.module ?? packageJson.main;
2292
2329
  if (legacyPath !== void 0) {
2293
2330
  const sourcePath = outputToSourcePath(legacyPath, outDir, sourceDir);
@@ -2296,11 +2333,13 @@ function inferEntryPoints(packageJson, outDir, sourceDir = "src") {
2296
2333
  }
2297
2334
  }
2298
2335
  }
2299
- return Object.keys(entryPoints).length > 0 ? entryPoints : void 0;
2336
+ for (const _ in entryPoints) {
2337
+ return entryPoints;
2338
+ }
2339
+ return void 0;
2300
2340
  }
2301
2341
 
2302
2342
  // src/type-script-project.ts
2303
- import { build as esbuild2, formatMessages } from "esbuild";
2304
2343
  import { performance as performance2 } from "node:perf_hooks";
2305
2344
  import { sys as sys2, createIncrementalProgram, formatDiagnostics, formatDiagnosticsWithColorAndContext, parseJsonConfigFileContent, readConfigFile, findConfigFile } from "typescript";
2306
2345
  var globCharacters = /[*?\\[\]!].*$/;
@@ -2344,7 +2383,7 @@ var _TypeScriptProject = class _TypeScriptProject {
2344
2383
  return Files.empty(this.buildConfiguration.outDir);
2345
2384
  }
2346
2385
  async build() {
2347
- Logger.header(`${tsLogo} tsbuild v${"1.8.1"}${this.configuration.compilerOptions.incremental && this.configuration.buildCache?.isValid() ? " [incremental]" : ""}`);
2386
+ Logger.header(`${tsLogo} tsbuild v${"1.8.3"}${this.configuration.compilerOptions.incremental && this.configuration.buildCache?.isValid() ? " [incremental]" : ""}`);
2348
2387
  try {
2349
2388
  const processes = [];
2350
2389
  const filesWereEmitted = await this.typeCheck();
@@ -2375,7 +2414,7 @@ var _TypeScriptProject = class _TypeScriptProject {
2375
2414
  }
2376
2415
  }
2377
2416
  if (this.fileWatcher === void 0 || this.fileWatcher.isClosed()) {
2378
- setImmediate(() => this.watch());
2417
+ setImmediate(() => void this.watch());
2379
2418
  }
2380
2419
  }
2381
2420
  }
@@ -2414,6 +2453,7 @@ var _TypeScriptProject = class _TypeScriptProject {
2414
2453
  return emitted || !this.configuration.compilerOptions.declaration;
2415
2454
  }
2416
2455
  async transpile() {
2456
+ const { build: esbuild, formatMessages } = await import("esbuild");
2417
2457
  const plugins = [outputPlugin()];
2418
2458
  if (this.buildConfiguration.noExternal.length > 0) {
2419
2459
  plugins.push(externalModulesPlugin({ dependencies: await this.getProjectDependencyPaths(), noExternal: this.buildConfiguration.noExternal }));
@@ -2442,7 +2482,7 @@ var _TypeScriptProject = class _TypeScriptProject {
2442
2482
  }
2443
2483
  }
2444
2484
  try {
2445
- const { warnings, errors, metafile: { outputs } } = await esbuild2({
2485
+ const { warnings, errors, metafile: { outputs } } = await esbuild({
2446
2486
  format,
2447
2487
  plugins,
2448
2488
  define,
@@ -2506,7 +2546,8 @@ var _TypeScriptProject = class _TypeScriptProject {
2506
2546
  /**
2507
2547
  * Watches for changes in the project files and rebuilds the project when changes are detected.
2508
2548
  */
2509
- watch() {
2549
+ async watch() {
2550
+ const { Watchr } = await import("@d1g1tal/watchr");
2510
2551
  const targets = [];
2511
2552
  for (const path of this.configuration.include ?? [defaultSourceDirectory]) {
2512
2553
  targets.push(Paths.absolute(this.directory, path.replace(globCharacters, "")));
@@ -2560,7 +2601,7 @@ var _TypeScriptProject = class _TypeScriptProject {
2560
2601
  Logger.info(`Rebuilding project: ${this.pendingChanges.length} file changes detected.`);
2561
2602
  const rootNames = [...this.builderProgram.getProgram().getRootFileNames()];
2562
2603
  for (const { event, path, nextPath } of this.pendingChanges) {
2563
- if (nextPath !== void 0 && (event === Watchr.FileEvent.rename || event === Watchr.DirectoryEvent.rename)) {
2604
+ if (nextPath !== void 0 && (event === "rename" || event === "renameDir")) {
2564
2605
  this.buildDependencies.delete(Paths.relative(this.directory, path));
2565
2606
  this.buildDependencies.add(Paths.relative(this.directory, nextPath));
2566
2607
  const index = rootNames.indexOf(path);
@@ -2569,9 +2610,9 @@ var _TypeScriptProject = class _TypeScriptProject {
2569
2610
  }
2570
2611
  } else {
2571
2612
  const index = rootNames.indexOf(path);
2572
- if (event === Watchr.FileEvent.unlink && index !== -1) {
2613
+ if (event === "unlink" && index !== -1) {
2573
2614
  rootNames.splice(index, 1);
2574
- } else if (event === Watchr.FileEvent.add && index === -1) {
2615
+ } else if (event === "add" && index === -1) {
2575
2616
  rootNames.push(path);
2576
2617
  }
2577
2618
  }
package/dist/tsbuild.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  BuildError,
4
4
  TypeScriptProject
5
- } from "./GWNROQXR.js";
5
+ } from "./UM2SFHAT.js";
6
6
  import "./JKGYA2AW.js";
7
7
 
8
8
  // src/tsbuild.ts
@@ -30,7 +30,7 @@ if (help) {
30
30
  process.exit(0);
31
31
  }
32
32
  if (version) {
33
- console.log("1.8.1");
33
+ console.log("1.8.3");
34
34
  process.exit(0);
35
35
  }
36
36
  var typeScriptOptions = {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TypeScriptProject
3
- } from "./GWNROQXR.js";
3
+ } from "./UM2SFHAT.js";
4
4
  import "./JKGYA2AW.js";
5
5
  export {
6
6
  TypeScriptProject
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@d1g1tal/tsbuild",
3
3
  "author": "D1g1talEntr0py",
4
- "version": "1.8.1",
4
+ "version": "1.8.3",
5
5
  "license": "MIT",
6
6
  "description": "A fast, ESM-only TypeScript build tool combining the TypeScript API for type checking and declaration generation, esbuild for bundling, and SWC for decorator metadata.",
7
7
  "homepage": "https://github.com/D1g1talEntr0py/tsbuild#readme",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "devDependencies": {
52
52
  "@eslint/js": "^10.0.1",
53
- "@types/node": "^25.5.2",
53
+ "@types/node": "^25.6.0",
54
54
  "@typescript-eslint/eslint-plugin": "^8.58.1",
55
55
  "@typescript-eslint/parser": "^8.58.1",
56
56
  "@vitest/coverage-v8": "^4.1.4",