@d1g1tal/tsbuild 1.8.2 → 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,20 @@
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
+
1
18
  ## [1.8.2](https://github.com/D1g1talEntr0py/tsbuild/compare/v1.8.1...v1.8.2) (2026-04-09)
2
19
 
3
20
  ### 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,15 +1588,15 @@ function extractEntryNames(entryPoints) {
1570
1588
  }
1571
1589
  return Object.keys(entryPoints);
1572
1590
  }
1573
- var exportRe = /export\s*\{([^}]*)\};?/g;
1574
- var asRe = /^(\w+)\s+as\s+(\w+)$/;
1591
+ var exportRegex = /export\s*\{([^}]*)\};?/g;
1592
+ var exportAliasRegex = /^(\w+)\s+as\s+(\w+)$/;
1575
1593
  function wrapAsIife(text, globalName) {
1576
- let last = null;
1577
- let match;
1578
- exportRe.lastIndex = 0;
1579
- while ((match = exportRe.exec(text)) !== null) {
1580
- last = match;
1594
+ const exportIndex = text.lastIndexOf("export");
1595
+ if (exportIndex === -1) {
1596
+ return text;
1581
1597
  }
1598
+ exportRegex.lastIndex = exportIndex;
1599
+ const last = exportRegex.exec(text);
1582
1600
  if (!last) {
1583
1601
  return text;
1584
1602
  }
@@ -1588,7 +1606,7 @@ function wrapAsIife(text, globalName) {
1588
1606
  if (!trimmed) {
1589
1607
  continue;
1590
1608
  }
1591
- const m = asRe.exec(trimmed);
1609
+ const m = exportAliasRegex.exec(trimmed);
1592
1610
  props.push(m ? `${m[2]}: ${m[1]}` : trimmed);
1593
1611
  }
1594
1612
  if (props.length === 0) {
@@ -1603,10 +1621,11 @@ ${body}
1603
1621
  })();${after}`;
1604
1622
  }
1605
1623
  async function buildIife(outputFiles, entryPointNames, outdir, globalName, sourcemap) {
1624
+ const { build: esbuild } = await import("esbuild");
1606
1625
  const fileContents = /* @__PURE__ */ new Map();
1607
- for (const file of outputFiles) {
1608
- if (file.path.endsWith(jsExtension)) {
1609
- 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));
1610
1629
  }
1611
1630
  }
1612
1631
  const validEntries = [];
@@ -1638,15 +1657,16 @@ async function buildIife(outputFiles, entryPointNames, outdir, globalName, sourc
1638
1657
  ));
1639
1658
  const written = [];
1640
1659
  const writes = [];
1660
+ const cwd = process.cwd();
1641
1661
  for (const { outputFiles: iifeFiles } of results) {
1642
- for (const file of iifeFiles) {
1643
- if (file.path.endsWith(jsExtension)) {
1644
- const text = wrapAsIife(textDecoder2.decode(file.contents), globalName);
1645
- writes.push(writeFile3(file.path, text));
1646
- 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) });
1647
1667
  } else {
1648
- writes.push(writeFile3(file.path, file.contents));
1649
- 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 });
1650
1670
  }
1651
1671
  }
1652
1672
  }
@@ -2033,8 +2053,9 @@ var FileManager = class {
2033
2053
  return defaultEntryPoint in projectEntryPoints ? { [defaultEntryPoint]: projectEntryPoints[defaultEntryPoint] } : projectEntryPoints;
2034
2054
  }
2035
2055
  const result = {};
2056
+ const allowedEntryPoints = new Set(dtsEntryPoints);
2036
2057
  for (const [name, path] of Object.entries(projectEntryPoints)) {
2037
- if (dtsEntryPoints.includes(name)) {
2058
+ if (allowedEntryPoints.has(name)) {
2038
2059
  result[name] = path;
2039
2060
  }
2040
2061
  }
@@ -2298,7 +2319,12 @@ function inferEntryPoints(packageJson, outDir, sourceDir = "src") {
2298
2319
  }
2299
2320
  }
2300
2321
  }
2301
- if (Object.keys(entryPoints).length === 0) {
2322
+ let hasEntries = false;
2323
+ for (const _ in entryPoints) {
2324
+ hasEntries = true;
2325
+ break;
2326
+ }
2327
+ if (!hasEntries) {
2302
2328
  const legacyPath = packageJson.module ?? packageJson.main;
2303
2329
  if (legacyPath !== void 0) {
2304
2330
  const sourcePath = outputToSourcePath(legacyPath, outDir, sourceDir);
@@ -2307,11 +2333,13 @@ function inferEntryPoints(packageJson, outDir, sourceDir = "src") {
2307
2333
  }
2308
2334
  }
2309
2335
  }
2310
- return Object.keys(entryPoints).length > 0 ? entryPoints : void 0;
2336
+ for (const _ in entryPoints) {
2337
+ return entryPoints;
2338
+ }
2339
+ return void 0;
2311
2340
  }
2312
2341
 
2313
2342
  // src/type-script-project.ts
2314
- import { build as esbuild2, formatMessages } from "esbuild";
2315
2343
  import { performance as performance2 } from "node:perf_hooks";
2316
2344
  import { sys as sys2, createIncrementalProgram, formatDiagnostics, formatDiagnosticsWithColorAndContext, parseJsonConfigFileContent, readConfigFile, findConfigFile } from "typescript";
2317
2345
  var globCharacters = /[*?\\[\]!].*$/;
@@ -2355,7 +2383,7 @@ var _TypeScriptProject = class _TypeScriptProject {
2355
2383
  return Files.empty(this.buildConfiguration.outDir);
2356
2384
  }
2357
2385
  async build() {
2358
- Logger.header(`${tsLogo} tsbuild v${"1.8.2"}${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]" : ""}`);
2359
2387
  try {
2360
2388
  const processes = [];
2361
2389
  const filesWereEmitted = await this.typeCheck();
@@ -2386,7 +2414,7 @@ var _TypeScriptProject = class _TypeScriptProject {
2386
2414
  }
2387
2415
  }
2388
2416
  if (this.fileWatcher === void 0 || this.fileWatcher.isClosed()) {
2389
- setImmediate(() => this.watch());
2417
+ setImmediate(() => void this.watch());
2390
2418
  }
2391
2419
  }
2392
2420
  }
@@ -2425,6 +2453,7 @@ var _TypeScriptProject = class _TypeScriptProject {
2425
2453
  return emitted || !this.configuration.compilerOptions.declaration;
2426
2454
  }
2427
2455
  async transpile() {
2456
+ const { build: esbuild, formatMessages } = await import("esbuild");
2428
2457
  const plugins = [outputPlugin()];
2429
2458
  if (this.buildConfiguration.noExternal.length > 0) {
2430
2459
  plugins.push(externalModulesPlugin({ dependencies: await this.getProjectDependencyPaths(), noExternal: this.buildConfiguration.noExternal }));
@@ -2453,7 +2482,7 @@ var _TypeScriptProject = class _TypeScriptProject {
2453
2482
  }
2454
2483
  }
2455
2484
  try {
2456
- const { warnings, errors, metafile: { outputs } } = await esbuild2({
2485
+ const { warnings, errors, metafile: { outputs } } = await esbuild({
2457
2486
  format,
2458
2487
  plugins,
2459
2488
  define,
@@ -2517,7 +2546,8 @@ var _TypeScriptProject = class _TypeScriptProject {
2517
2546
  /**
2518
2547
  * Watches for changes in the project files and rebuilds the project when changes are detected.
2519
2548
  */
2520
- watch() {
2549
+ async watch() {
2550
+ const { Watchr } = await import("@d1g1tal/watchr");
2521
2551
  const targets = [];
2522
2552
  for (const path of this.configuration.include ?? [defaultSourceDirectory]) {
2523
2553
  targets.push(Paths.absolute(this.directory, path.replace(globCharacters, "")));
@@ -2571,7 +2601,7 @@ var _TypeScriptProject = class _TypeScriptProject {
2571
2601
  Logger.info(`Rebuilding project: ${this.pendingChanges.length} file changes detected.`);
2572
2602
  const rootNames = [...this.builderProgram.getProgram().getRootFileNames()];
2573
2603
  for (const { event, path, nextPath } of this.pendingChanges) {
2574
- if (nextPath !== void 0 && (event === Watchr.FileEvent.rename || event === Watchr.DirectoryEvent.rename)) {
2604
+ if (nextPath !== void 0 && (event === "rename" || event === "renameDir")) {
2575
2605
  this.buildDependencies.delete(Paths.relative(this.directory, path));
2576
2606
  this.buildDependencies.add(Paths.relative(this.directory, nextPath));
2577
2607
  const index = rootNames.indexOf(path);
@@ -2580,9 +2610,9 @@ var _TypeScriptProject = class _TypeScriptProject {
2580
2610
  }
2581
2611
  } else {
2582
2612
  const index = rootNames.indexOf(path);
2583
- if (event === Watchr.FileEvent.unlink && index !== -1) {
2613
+ if (event === "unlink" && index !== -1) {
2584
2614
  rootNames.splice(index, 1);
2585
- } else if (event === Watchr.FileEvent.add && index === -1) {
2615
+ } else if (event === "add" && index === -1) {
2586
2616
  rootNames.push(path);
2587
2617
  }
2588
2618
  }
package/dist/tsbuild.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  BuildError,
4
4
  TypeScriptProject
5
- } from "./ALZQNZZK.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.2");
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 "./ALZQNZZK.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.2",
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",