@d1g1tal/tsbuild 1.8.2 → 1.8.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.
- package/CHANGELOG.md +44 -0
- package/dist/{ALZQNZZK.js → 23A5VAYC.js} +199 -125
- package/dist/tsbuild.js +2 -2
- package/dist/type-script-project.js +1 -1
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
## [1.8.4](https://github.com/D1g1talEntr0py/tsbuild/compare/v1.8.3...v1.8.4) (2026-04-12)
|
|
2
|
+
|
|
3
|
+
### Performance Improvements
|
|
4
|
+
|
|
5
|
+
* **build:** delegate file writing to esbuild (84a64e212a9dc7f309bb2dcbe74ffa990c06065b)
|
|
6
|
+
- Enables esbuild write option for direct-to-disk transpilation output
|
|
7
|
+
- Moves relative module specifier rewriting logic to FileManager
|
|
8
|
+
- Simplifies output plugin to only manage shebang executable permissions via chmod
|
|
9
|
+
- Adapts IIFE plugin to process metafile outputs instead of in-memory files
|
|
10
|
+
- Updates tests and mock helpers to align with file writing capabilities
|
|
11
|
+
|
|
12
|
+
* **dts:** optimize declaration bundler module resolution and graph traversal (59606c0ccfe54ac74068fe6ab8f6d26d7edd97b6)
|
|
13
|
+
- Optimizes module pattern matching by using Sets and RegEx arrays instead of iteration
|
|
14
|
+
- Refactors bundled specifiers state to use ReadonlySet for O(1) lookups
|
|
15
|
+
- Simplifies deduplication of non-mergeable imports using Sets
|
|
16
|
+
- Yields the event loop before cpu-intensive declaration bundling to prevent I/O blocking
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Miscellaneous Chores
|
|
20
|
+
|
|
21
|
+
* **perf:** add performance baseline documentation and benchmark script (3e897aaa7a35022b8d9ec1d4222448973eb57a2b)
|
|
22
|
+
- Adds documentation detailing performance baselines and architectures
|
|
23
|
+
- Introduces performance measurements log
|
|
24
|
+
- Adds quick reference for performance monitoring
|
|
25
|
+
- Introduces new benchmark script for running automated metrics collection
|
|
26
|
+
- Registers bench script in package.json
|
|
27
|
+
|
|
28
|
+
## [1.8.3](https://github.com/D1g1talEntr0py/tsbuild/compare/v1.8.2...v1.8.3) (2026-04-11)
|
|
29
|
+
|
|
30
|
+
### Performance Improvements
|
|
31
|
+
|
|
32
|
+
* **core:** optimize build performance and decrease startup time (5cc35a8e0c6acc45dff38f6186e9f5b8f59ee8bf)
|
|
33
|
+
- use sets instead of arrays for faster lookups
|
|
34
|
+
- replace string concatenation with array joins
|
|
35
|
+
- replace object.keys with for-in loops
|
|
36
|
+
- cache regex patterns and avoid repeated compilations
|
|
37
|
+
- dynamically import esbuild and watchr to reduce startup time
|
|
38
|
+
- replace map/reduce chains with single loops for better performance
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### Miscellaneous Chores
|
|
42
|
+
|
|
43
|
+
* **deps:** update dependency @types/node to ^25.6.0 (a99b720acf5c2d3ed4116605e66fbd0f0174259f)
|
|
44
|
+
|
|
1
45
|
## [1.8.2](https://github.com/D1g1talEntr0py/tsbuild/compare/v1.8.1...v1.8.2) (2026-04-09)
|
|
2
46
|
|
|
3
47
|
### 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;
|
|
@@ -151,13 +148,13 @@ var isColorSupported = !("NO_COLOR" in env) && ("FORCE_COLOR" in env || platform
|
|
|
151
148
|
var replaceClose = (index, string, close, replace, head = string.substring(0, index) + replace, tail = string.substring(index + close.length), next = tail.indexOf(close)) => {
|
|
152
149
|
return head + (next < 0 ? tail : replaceClose(next, tail, close, replace));
|
|
153
150
|
};
|
|
154
|
-
var clearBleed = (index, string,
|
|
155
|
-
return index < 0 ? `${
|
|
151
|
+
var clearBleed = (index, string, open2, close, replace) => {
|
|
152
|
+
return index < 0 ? `${open2}${string}${close}` : `${open2}${replaceClose(index, string, close, replace)}${close}`;
|
|
156
153
|
};
|
|
157
|
-
var filterEmpty = (
|
|
158
|
-
return (text) => text.length ? clearBleed(text.indexOf(close, at), text,
|
|
154
|
+
var filterEmpty = (open2, close, replace = open2, at = open2.length + 1) => {
|
|
155
|
+
return (text) => text.length ? clearBleed(text.indexOf(close, at), text, open2, close, replace) : "";
|
|
159
156
|
};
|
|
160
|
-
var generateTextFormatter = (
|
|
157
|
+
var generateTextFormatter = (open2, close, replace) => filterEmpty(`\x1B[${open2}m`, `\x1B[${close}m`, replace);
|
|
161
158
|
var TextFormat = class {
|
|
162
159
|
static enabled = isColorSupported;
|
|
163
160
|
static reset = generateTextFormatter(0, 0);
|
|
@@ -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) /
|
|
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(
|
|
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
|
-
|
|
287
|
-
|
|
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
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
567
|
+
importName = generateUniqueName(chars.join(""));
|
|
550
568
|
inlineImports.set(fileId, importName);
|
|
551
569
|
}
|
|
552
570
|
return importName;
|
|
@@ -799,36 +817,40 @@ import {
|
|
|
799
817
|
forEachChild as forEachChild2
|
|
800
818
|
} from "typescript";
|
|
801
819
|
var nodeModules = "/node_modules/";
|
|
820
|
+
var emptySet = /* @__PURE__ */ new Set();
|
|
802
821
|
var importPattern = /^import\s*(?:type\s*)?\{\s*([^}]+)\s*\}\s*from\s*['"]([^'"]+)['"]\s*;?\s*$/;
|
|
803
822
|
var typePrefixPattern = /^type:/;
|
|
804
823
|
function mergeImports(imports) {
|
|
805
824
|
const moduleImports = /* @__PURE__ */ new Map();
|
|
806
|
-
const nonMergeableImports =
|
|
825
|
+
const nonMergeableImports = /* @__PURE__ */ new Set();
|
|
807
826
|
for (const importStatement of imports) {
|
|
808
827
|
const match = importPattern.exec(importStatement);
|
|
809
828
|
if (match) {
|
|
810
829
|
const [, namesString, moduleSpecifier] = match;
|
|
811
830
|
const isType = importStatement.includes("import type");
|
|
812
831
|
const key = `${isType ? "type:" : ""}${moduleSpecifier}`;
|
|
813
|
-
|
|
814
|
-
|
|
832
|
+
let entry = moduleImports.get(key);
|
|
833
|
+
if (entry === void 0) {
|
|
834
|
+
entry = { names: /* @__PURE__ */ new Set(), isType };
|
|
835
|
+
moduleImports.set(key, entry);
|
|
815
836
|
}
|
|
816
|
-
const entry = moduleImports.get(key);
|
|
817
837
|
for (const name of namesString.split(",")) {
|
|
818
838
|
entry.names.add(name.trim());
|
|
819
839
|
}
|
|
820
840
|
} else {
|
|
821
|
-
nonMergeableImports.
|
|
841
|
+
nonMergeableImports.add(importStatement);
|
|
822
842
|
}
|
|
823
843
|
}
|
|
824
844
|
const result = [];
|
|
825
845
|
for (const [key, { names, isType }] of moduleImports) {
|
|
826
846
|
result.push(`${isType ? "import type" : "import"} { ${[...names].sort().join(", ")} } from "${key.replace(typePrefixPattern, "")}";`);
|
|
827
847
|
}
|
|
828
|
-
|
|
848
|
+
for (const imp of nonMergeableImports) {
|
|
849
|
+
result.push(imp);
|
|
850
|
+
}
|
|
829
851
|
return result;
|
|
830
852
|
}
|
|
831
|
-
var DeclarationBundler = class {
|
|
853
|
+
var DeclarationBundler = class _DeclarationBundler {
|
|
832
854
|
/** Project declaration files from in-memory FileManager */
|
|
833
855
|
declarationFiles = /* @__PURE__ */ new Map();
|
|
834
856
|
/** External declaration files resolved from disk (node_modules) when resolve is enabled */
|
|
@@ -841,6 +863,10 @@ var DeclarationBundler = class {
|
|
|
841
863
|
moduleResolutionCache = /* @__PURE__ */ new Map();
|
|
842
864
|
/** Pre-computed set of directory prefixes from declaration file paths for O(1) directoryExists lookups */
|
|
843
865
|
declarationDirs = /* @__PURE__ */ new Set();
|
|
866
|
+
/** Pre-built matcher for external patterns — O(1) string lookups + cached regex tests */
|
|
867
|
+
matchExternal;
|
|
868
|
+
/** Pre-built matcher for noExternal patterns — O(1) string lookups + cached regex tests */
|
|
869
|
+
matchNoExternal;
|
|
844
870
|
// Create a proper module resolution host that supports both in-memory files and disk files
|
|
845
871
|
moduleResolutionHost = {
|
|
846
872
|
fileExists: (fileName) => {
|
|
@@ -890,6 +916,8 @@ var DeclarationBundler = class {
|
|
|
890
916
|
}
|
|
891
917
|
}
|
|
892
918
|
this.options = dtsBundleOptions;
|
|
919
|
+
this.matchExternal = _DeclarationBundler.buildMatcher(dtsBundleOptions.external);
|
|
920
|
+
this.matchNoExternal = _DeclarationBundler.buildMatcher(dtsBundleOptions.noExternal);
|
|
893
921
|
}
|
|
894
922
|
/**
|
|
895
923
|
* Clears external declaration files and module resolution cache to free memory.
|
|
@@ -942,23 +970,42 @@ var DeclarationBundler = class {
|
|
|
942
970
|
return imports;
|
|
943
971
|
}
|
|
944
972
|
/**
|
|
945
|
-
*
|
|
946
|
-
*
|
|
947
|
-
* @param patterns -
|
|
948
|
-
* @returns
|
|
973
|
+
* Builds an O(1) matcher from a mixed Pattern array by splitting into a Set<string> for
|
|
974
|
+
* exact/sub-path checks and a RegExp[] for regex tests. Called once per bundler instance.
|
|
975
|
+
* @param patterns - The array of string and RegExp patterns to match against module specifiers
|
|
976
|
+
* @returns A function that takes a module specifier and returns true if it matches any of the patterns
|
|
949
977
|
*/
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
978
|
+
static buildMatcher(patterns) {
|
|
979
|
+
const exact = /* @__PURE__ */ new Set();
|
|
980
|
+
const prefixes = [];
|
|
981
|
+
const regexps = [];
|
|
982
|
+
for (const p of patterns) {
|
|
983
|
+
if (typeof p === "string") {
|
|
984
|
+
exact.add(p);
|
|
985
|
+
prefixes.push(p + "/");
|
|
986
|
+
} else {
|
|
987
|
+
regexps.push(p);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
if (exact.size === 0 && regexps.length === 0) {
|
|
991
|
+
return () => false;
|
|
992
|
+
}
|
|
993
|
+
return (id) => {
|
|
994
|
+
if (exact.has(id)) {
|
|
995
|
+
return true;
|
|
996
|
+
}
|
|
997
|
+
for (let i = 0; i < prefixes.length; i++) {
|
|
998
|
+
if (id.startsWith(prefixes[i])) {
|
|
999
|
+
return true;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
for (let i = 0; i < regexps.length; i++) {
|
|
1003
|
+
if (regexps[i].test(id)) {
|
|
1004
|
+
return true;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
return false;
|
|
1008
|
+
};
|
|
962
1009
|
}
|
|
963
1010
|
/**
|
|
964
1011
|
* Resolve a module import using TypeScript's resolution algorithm with path mapping support
|
|
@@ -1006,18 +1053,18 @@ var DeclarationBundler = class {
|
|
|
1006
1053
|
const sourceFile = createSourceFile(path, code, ScriptTarget.Latest, true);
|
|
1007
1054
|
const identifiers = this.collectIdentifiers(sourceFile.statements, sourceFile);
|
|
1008
1055
|
const module = { path, code, imports: /* @__PURE__ */ new Set(), typeReferences: new Set(typeReferences), fileReferences: new Set(fileReferences), sourceFile, identifiers };
|
|
1009
|
-
const bundledSpecs =
|
|
1056
|
+
const bundledSpecs = /* @__PURE__ */ new Set();
|
|
1010
1057
|
for (const specifier of this.extractImports(sourceFile)) {
|
|
1011
|
-
if (this.
|
|
1058
|
+
if (this.matchExternal(specifier)) {
|
|
1012
1059
|
continue;
|
|
1013
1060
|
}
|
|
1014
1061
|
const resolvedPath = this.resolveModule(specifier, path);
|
|
1015
|
-
if (resolvedPath?.includes(nodeModules) && !this.
|
|
1062
|
+
if (resolvedPath?.includes(nodeModules) && !this.matchNoExternal(specifier)) {
|
|
1016
1063
|
continue;
|
|
1017
1064
|
}
|
|
1018
1065
|
if (resolvedPath && (this.declarationFiles.has(resolvedPath) || this.externalDeclarationFiles.has(resolvedPath))) {
|
|
1019
1066
|
module.imports.add(resolvedPath);
|
|
1020
|
-
bundledSpecs.
|
|
1067
|
+
bundledSpecs.add(specifier);
|
|
1021
1068
|
visit(resolvedPath);
|
|
1022
1069
|
}
|
|
1023
1070
|
}
|
|
@@ -1128,7 +1175,7 @@ var DeclarationBundler = class {
|
|
|
1128
1175
|
* @param code - Declaration file content
|
|
1129
1176
|
* @param sourceFile - Parsed source file AST (required to avoid re-parsing)
|
|
1130
1177
|
* @param identifiers - Pre-computed type and value identifiers (to avoid re-computation)
|
|
1131
|
-
* @param bundledImportPaths -
|
|
1178
|
+
* @param bundledImportPaths - Set of resolved file paths that were bundled (to exclude from external imports)
|
|
1132
1179
|
* @param renameMap - Map of renamed identifiers (name:path -> newName)
|
|
1133
1180
|
* @param modulePath - Path of current module for looking up renames
|
|
1134
1181
|
* @returns Object with processed code, collected external imports, and exported names (separated by type/value)
|
|
@@ -1151,7 +1198,7 @@ var DeclarationBundler = class {
|
|
|
1151
1198
|
for (const statement of sourceFile.statements) {
|
|
1152
1199
|
if (isImportDeclaration2(statement)) {
|
|
1153
1200
|
const moduleSpecifier = statement.moduleSpecifier.text;
|
|
1154
|
-
if (this.
|
|
1201
|
+
if (this.matchExternal(moduleSpecifier) || !bundledImportPaths.has(moduleSpecifier)) {
|
|
1155
1202
|
externalImports.push(code.substring(statement.pos, statement.end).trim());
|
|
1156
1203
|
} else if (statement.importClause?.namedBindings && isNamespaceImport(statement.importClause.namedBindings)) {
|
|
1157
1204
|
bundledNamespaceAliases.add(statement.importClause.namedBindings.name.text);
|
|
@@ -1206,8 +1253,9 @@ var DeclarationBundler = class {
|
|
|
1206
1253
|
};
|
|
1207
1254
|
forEachChild2(sourceFile, visitQualified);
|
|
1208
1255
|
}
|
|
1209
|
-
const
|
|
1210
|
-
const
|
|
1256
|
+
const finalValueExportsSet = new Set(valueExports.map(exportsMapper));
|
|
1257
|
+
const finalValueExports = [...finalValueExportsSet];
|
|
1258
|
+
const finalTypeExports = [...new Set(typeExports.map(exportsMapper).filter((t) => !finalValueExportsSet.has(t)))];
|
|
1211
1259
|
return { code: magic.toString(), externalImports, typeExports: finalTypeExports, valueExports: finalValueExports };
|
|
1212
1260
|
}
|
|
1213
1261
|
/**
|
|
@@ -1243,7 +1291,9 @@ var DeclarationBundler = class {
|
|
|
1243
1291
|
for (const [name, sourcesSet] of declarationSources) {
|
|
1244
1292
|
if (sourcesSet.size > 1) {
|
|
1245
1293
|
let suffix = 1;
|
|
1246
|
-
|
|
1294
|
+
const modulePaths = sourcesSet.values();
|
|
1295
|
+
modulePaths.next();
|
|
1296
|
+
for (const modulePath of modulePaths) {
|
|
1247
1297
|
let candidate = `${name}$${suffix}`;
|
|
1248
1298
|
while (declarationSources.has(candidate)) {
|
|
1249
1299
|
candidate = `${name}$${++suffix}`;
|
|
@@ -1256,7 +1306,7 @@ var DeclarationBundler = class {
|
|
|
1256
1306
|
for (const { path, typeReferences, fileReferences, sourceFile, code, identifiers } of sortedModules) {
|
|
1257
1307
|
allTypeReferences.push(...typeReferences);
|
|
1258
1308
|
allFileReferences.push(...fileReferences);
|
|
1259
|
-
const bundledForThisModule = bundledSpecifiers.get(path)
|
|
1309
|
+
const bundledForThisModule = bundledSpecifiers.get(path) ?? emptySet;
|
|
1260
1310
|
const { code: strippedCode, externalImports, typeExports, valueExports } = this.stripImportsExports(code, sourceFile, identifiers, bundledForThisModule, renameMap, path);
|
|
1261
1311
|
allExternalImports.push(...externalImports);
|
|
1262
1312
|
if (!path.includes(nodeModules)) {
|
|
@@ -1282,8 +1332,8 @@ var DeclarationBundler = class {
|
|
|
1282
1332
|
}
|
|
1283
1333
|
}
|
|
1284
1334
|
const uniqueTypeReferences = [...typeReferencesSet];
|
|
1285
|
-
const
|
|
1286
|
-
const
|
|
1335
|
+
const finalValueExportsSet = new Set(allValueExports);
|
|
1336
|
+
const finalValueExports = [...finalValueExportsSet];
|
|
1287
1337
|
const finalTypeExports = [...new Set(allTypeExports.filter((typeExport) => !finalValueExportsSet.has(typeExport)))];
|
|
1288
1338
|
const outputParts = [];
|
|
1289
1339
|
if (uniqueFileReferences.length > 0) {
|
|
@@ -1353,11 +1403,12 @@ async function bundleDeclarations(options) {
|
|
|
1353
1403
|
await mkdir2(options.compilerOptions.outDir, defaultDirOptions);
|
|
1354
1404
|
}
|
|
1355
1405
|
const dtsBundler = new DeclarationBundler(options);
|
|
1406
|
+
await new Promise((resolve3) => void setImmediate(resolve3));
|
|
1356
1407
|
const bundleTasks = [];
|
|
1357
1408
|
for (const [entryName, entryPoint] of Object.entries(options.entryPoints)) {
|
|
1358
1409
|
const content = dtsBundler.bundle(entryPoint);
|
|
1359
1410
|
if (content.length > 0) {
|
|
1360
|
-
const outPath = Paths.join(options.compilerOptions.outDir, `${entryName}.
|
|
1411
|
+
const outPath = Paths.join(options.compilerOptions.outDir, `${entryName}${FileExtension.DTS}`);
|
|
1361
1412
|
bundleTasks.push(writeFile2(outPath, content, Encoding.utf8).then(() => ({ path: Paths.relative(options.currentDirectory, outPath), size: content.length })));
|
|
1362
1413
|
}
|
|
1363
1414
|
}
|
|
@@ -1367,38 +1418,42 @@ async function bundleDeclarations(options) {
|
|
|
1367
1418
|
}
|
|
1368
1419
|
|
|
1369
1420
|
// src/plugins/output.ts
|
|
1421
|
+
import { chmod, open } from "node:fs/promises";
|
|
1370
1422
|
import { extname } from "node:path";
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
}
|
|
1379
|
-
async function fileMapper({ path, contents }) {
|
|
1380
|
-
if (extname(path) !== FileExtension.JS) {
|
|
1381
|
-
return Files.write(path, contents, { mode: FileMode.READ_WRITE });
|
|
1382
|
-
}
|
|
1383
|
-
let rewritten = false;
|
|
1384
|
-
const result = textDecoder.decode(contents).replace(relativeSpecifierPattern, (_, before, specPath, after) => {
|
|
1385
|
-
if (localFileIdentifier.test(specPath)) {
|
|
1386
|
-
return before + specPath + after;
|
|
1423
|
+
async function setShebangPermissions(filePath) {
|
|
1424
|
+
const handle = await open(filePath, "r");
|
|
1425
|
+
try {
|
|
1426
|
+
const buf = Buffer.alloc(2);
|
|
1427
|
+
await handle.read(buf, 0, 2, 0);
|
|
1428
|
+
if (buf[0] === 35 && buf[1] === 33) {
|
|
1429
|
+
await chmod(filePath, 493);
|
|
1387
1430
|
}
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
}
|
|
1391
|
-
return Files.write(path, rewritten ? textEncoder.encode(result) : contents, { mode: contents[0] === 35 && contents[1] === 33 ? FileMode.READ_WRITE_EXECUTE : FileMode.READ_WRITE });
|
|
1431
|
+
} finally {
|
|
1432
|
+
await handle.close();
|
|
1433
|
+
}
|
|
1392
1434
|
}
|
|
1393
1435
|
var outputPlugin = () => {
|
|
1394
1436
|
return {
|
|
1395
1437
|
name: "esbuild:output-plugin",
|
|
1396
1438
|
/**
|
|
1397
|
-
*
|
|
1439
|
+
* Checks JS entry points for shebangs and sets executable permissions
|
|
1398
1440
|
* @param build The esbuild build instance
|
|
1399
1441
|
*/
|
|
1400
1442
|
setup(build) {
|
|
1401
|
-
build.onEnd(async ({
|
|
1443
|
+
build.onEnd(async ({ metafile }) => {
|
|
1444
|
+
if (!metafile) {
|
|
1445
|
+
return;
|
|
1446
|
+
}
|
|
1447
|
+
const tasks = [];
|
|
1448
|
+
for (const [outputPath, { entryPoint }] of Object.entries(metafile.outputs)) {
|
|
1449
|
+
if (entryPoint && extname(outputPath) === FileExtension.JS) {
|
|
1450
|
+
tasks.push(setShebangPermissions(outputPath));
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
if (tasks.length > 0) {
|
|
1454
|
+
await Promise.all(tasks);
|
|
1455
|
+
}
|
|
1456
|
+
});
|
|
1402
1457
|
}
|
|
1403
1458
|
};
|
|
1404
1459
|
};
|
|
@@ -1519,10 +1574,9 @@ async function resolvePlugins(plugins, projectDir) {
|
|
|
1519
1574
|
}
|
|
1520
1575
|
|
|
1521
1576
|
// src/plugins/iife.ts
|
|
1522
|
-
import {
|
|
1523
|
-
import {
|
|
1524
|
-
|
|
1525
|
-
var textDecoder2 = new TextDecoder();
|
|
1577
|
+
import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile3 } from "node:fs/promises";
|
|
1578
|
+
import { basename as basename2, dirname as dirname2, join, resolve as resolve2 } from "node:path";
|
|
1579
|
+
var textDecoder = new TextDecoder();
|
|
1526
1580
|
var jsExtension = ".js";
|
|
1527
1581
|
function iifePlugin(options) {
|
|
1528
1582
|
const globalName = options?.globalName;
|
|
@@ -1542,11 +1596,11 @@ function iifePlugin(options) {
|
|
|
1542
1596
|
}
|
|
1543
1597
|
const sourcemap = build.initialOptions.sourcemap;
|
|
1544
1598
|
const entryPointNames = extractEntryNames(build.initialOptions.entryPoints);
|
|
1545
|
-
build.onEnd(async ({
|
|
1546
|
-
if (!
|
|
1599
|
+
build.onEnd(async ({ metafile }) => {
|
|
1600
|
+
if (!metafile || entryPointNames.length === 0) {
|
|
1547
1601
|
return;
|
|
1548
1602
|
}
|
|
1549
|
-
const written = await buildIife(
|
|
1603
|
+
const written = await buildIife(metafile.outputs, entryPointNames, outdir, globalName, sourcemap);
|
|
1550
1604
|
files.push(...written);
|
|
1551
1605
|
});
|
|
1552
1606
|
}
|
|
@@ -1570,15 +1624,15 @@ function extractEntryNames(entryPoints) {
|
|
|
1570
1624
|
}
|
|
1571
1625
|
return Object.keys(entryPoints);
|
|
1572
1626
|
}
|
|
1573
|
-
var
|
|
1574
|
-
var
|
|
1627
|
+
var exportRegex = /export\s*\{([^}]*)\};?/g;
|
|
1628
|
+
var exportAliasRegex = /^(\w+)\s+as\s+(\w+)$/;
|
|
1575
1629
|
function wrapAsIife(text, globalName) {
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
while ((match = exportRe.exec(text)) !== null) {
|
|
1580
|
-
last = match;
|
|
1630
|
+
const exportIndex = text.lastIndexOf("export");
|
|
1631
|
+
if (exportIndex === -1) {
|
|
1632
|
+
return text;
|
|
1581
1633
|
}
|
|
1634
|
+
exportRegex.lastIndex = exportIndex;
|
|
1635
|
+
const last = exportRegex.exec(text);
|
|
1582
1636
|
if (!last) {
|
|
1583
1637
|
return text;
|
|
1584
1638
|
}
|
|
@@ -1588,7 +1642,7 @@ function wrapAsIife(text, globalName) {
|
|
|
1588
1642
|
if (!trimmed) {
|
|
1589
1643
|
continue;
|
|
1590
1644
|
}
|
|
1591
|
-
const m =
|
|
1645
|
+
const m = exportAliasRegex.exec(trimmed);
|
|
1592
1646
|
props.push(m ? `${m[2]}: ${m[1]}` : trimmed);
|
|
1593
1647
|
}
|
|
1594
1648
|
if (props.length === 0) {
|
|
@@ -1602,11 +1656,12 @@ ${body}
|
|
|
1602
1656
|
${assignment}
|
|
1603
1657
|
})();${after}`;
|
|
1604
1658
|
}
|
|
1605
|
-
async function buildIife(
|
|
1659
|
+
async function buildIife(outputs, entryPointNames, outdir, globalName, sourcemap) {
|
|
1660
|
+
const { build: esbuild } = await import("esbuild");
|
|
1606
1661
|
const fileContents = /* @__PURE__ */ new Map();
|
|
1607
|
-
for (const
|
|
1608
|
-
if (
|
|
1609
|
-
fileContents.set(
|
|
1662
|
+
for (const outputPath of Object.keys(outputs)) {
|
|
1663
|
+
if (outputPath.endsWith(jsExtension)) {
|
|
1664
|
+
fileContents.set(outputPath, await readFile2(outputPath, "utf8"));
|
|
1610
1665
|
}
|
|
1611
1666
|
}
|
|
1612
1667
|
const validEntries = [];
|
|
@@ -1638,15 +1693,16 @@ async function buildIife(outputFiles, entryPointNames, outdir, globalName, sourc
|
|
|
1638
1693
|
));
|
|
1639
1694
|
const written = [];
|
|
1640
1695
|
const writes = [];
|
|
1696
|
+
const cwd = process.cwd();
|
|
1641
1697
|
for (const { outputFiles: iifeFiles } of results) {
|
|
1642
|
-
for (const
|
|
1643
|
-
if (
|
|
1644
|
-
const text = wrapAsIife(
|
|
1645
|
-
writes.push(writeFile3(
|
|
1646
|
-
written.push({ path: relative(
|
|
1698
|
+
for (const { path, contents } of iifeFiles) {
|
|
1699
|
+
if (path.endsWith(jsExtension)) {
|
|
1700
|
+
const text = wrapAsIife(textDecoder.decode(contents), globalName);
|
|
1701
|
+
writes.push(writeFile3(path, text));
|
|
1702
|
+
written.push({ path: Paths.relative(cwd, path), size: Buffer.byteLength(text) });
|
|
1647
1703
|
} else {
|
|
1648
|
-
writes.push(writeFile3(
|
|
1649
|
-
written.push({ path: relative(
|
|
1704
|
+
writes.push(writeFile3(path, contents));
|
|
1705
|
+
written.push({ path: Paths.relative(cwd, path), size: contents.byteLength });
|
|
1650
1706
|
}
|
|
1651
1707
|
}
|
|
1652
1708
|
}
|
|
@@ -1921,6 +1977,11 @@ function debounce(wait) {
|
|
|
1921
1977
|
|
|
1922
1978
|
// src/file-manager.ts
|
|
1923
1979
|
import { createSourceFile as createSourceFile2, ScriptTarget as ScriptTarget2 } from "typescript";
|
|
1980
|
+
var localFileIdentifier = /\.[a-z]+$/i;
|
|
1981
|
+
var relativeSpecifierPattern = /(from\s*['"])(\.\.?\/[^'"]*?)(['"])/g;
|
|
1982
|
+
function rewriteRelativeSpecifiers(code) {
|
|
1983
|
+
return code.replace(relativeSpecifierPattern, (_, before, path, after) => localFileIdentifier.test(path) ? before + path + after : `${before}${path}.js${after}`);
|
|
1984
|
+
}
|
|
1924
1985
|
var FileManager = class {
|
|
1925
1986
|
hasEmittedFiles = false;
|
|
1926
1987
|
declarationFiles = /* @__PURE__ */ new Map();
|
|
@@ -1979,14 +2040,17 @@ var FileManager = class {
|
|
|
1979
2040
|
*/
|
|
1980
2041
|
finalize() {
|
|
1981
2042
|
this.processEmittedFiles();
|
|
1982
|
-
const
|
|
2043
|
+
const tasks = [];
|
|
2044
|
+
if (this.pendingBuildInfo) {
|
|
2045
|
+
tasks.push(Files.write(this.pendingBuildInfo.path, this.pendingBuildInfo.text));
|
|
2046
|
+
}
|
|
1983
2047
|
this.pendingBuildInfo = void 0;
|
|
1984
2048
|
if (this.cache && this.hasEmittedFiles) {
|
|
1985
|
-
|
|
1986
|
-
});
|
|
1987
|
-
} else if (buildInfoWrite) {
|
|
1988
|
-
this.pendingSave = buildInfoWrite;
|
|
2049
|
+
tasks.push(this.cache.save(this.declarationFiles));
|
|
1989
2050
|
}
|
|
2051
|
+
this.pendingSave = Promise.all(tasks).then(() => {
|
|
2052
|
+
}, () => {
|
|
2053
|
+
});
|
|
1990
2054
|
this.pendingSave?.catch(() => {
|
|
1991
2055
|
});
|
|
1992
2056
|
return this.cache === void 0 || this.hasEmittedFiles;
|
|
@@ -2018,7 +2082,7 @@ var FileManager = class {
|
|
|
2018
2082
|
writeTasks.push(this.writeFile(projectDirectory, filePath, code));
|
|
2019
2083
|
}
|
|
2020
2084
|
}
|
|
2021
|
-
return
|
|
2085
|
+
return Promise.all(writeTasks);
|
|
2022
2086
|
}
|
|
2023
2087
|
/**
|
|
2024
2088
|
* Resolves entry points for declaration bundling.
|
|
@@ -2033,8 +2097,9 @@ var FileManager = class {
|
|
|
2033
2097
|
return defaultEntryPoint in projectEntryPoints ? { [defaultEntryPoint]: projectEntryPoints[defaultEntryPoint] } : projectEntryPoints;
|
|
2034
2098
|
}
|
|
2035
2099
|
const result = {};
|
|
2100
|
+
const allowedEntryPoints = new Set(dtsEntryPoints);
|
|
2036
2101
|
for (const [name, path] of Object.entries(projectEntryPoints)) {
|
|
2037
|
-
if (
|
|
2102
|
+
if (allowedEntryPoints.has(name)) {
|
|
2038
2103
|
result[name] = path;
|
|
2039
2104
|
}
|
|
2040
2105
|
}
|
|
@@ -2298,7 +2363,12 @@ function inferEntryPoints(packageJson, outDir, sourceDir = "src") {
|
|
|
2298
2363
|
}
|
|
2299
2364
|
}
|
|
2300
2365
|
}
|
|
2301
|
-
|
|
2366
|
+
let hasEntries = false;
|
|
2367
|
+
for (const _ in entryPoints) {
|
|
2368
|
+
hasEntries = true;
|
|
2369
|
+
break;
|
|
2370
|
+
}
|
|
2371
|
+
if (!hasEntries) {
|
|
2302
2372
|
const legacyPath = packageJson.module ?? packageJson.main;
|
|
2303
2373
|
if (legacyPath !== void 0) {
|
|
2304
2374
|
const sourcePath = outputToSourcePath(legacyPath, outDir, sourceDir);
|
|
@@ -2307,11 +2377,13 @@ function inferEntryPoints(packageJson, outDir, sourceDir = "src") {
|
|
|
2307
2377
|
}
|
|
2308
2378
|
}
|
|
2309
2379
|
}
|
|
2310
|
-
|
|
2380
|
+
for (const _ in entryPoints) {
|
|
2381
|
+
return entryPoints;
|
|
2382
|
+
}
|
|
2383
|
+
return void 0;
|
|
2311
2384
|
}
|
|
2312
2385
|
|
|
2313
2386
|
// src/type-script-project.ts
|
|
2314
|
-
import { build as esbuild2, formatMessages } from "esbuild";
|
|
2315
2387
|
import { performance as performance2 } from "node:perf_hooks";
|
|
2316
2388
|
import { sys as sys2, createIncrementalProgram, formatDiagnostics, formatDiagnosticsWithColorAndContext, parseJsonConfigFileContent, readConfigFile, findConfigFile } from "typescript";
|
|
2317
2389
|
var globCharacters = /[*?\\[\]!].*$/;
|
|
@@ -2355,7 +2427,7 @@ var _TypeScriptProject = class _TypeScriptProject {
|
|
|
2355
2427
|
return Files.empty(this.buildConfiguration.outDir);
|
|
2356
2428
|
}
|
|
2357
2429
|
async build() {
|
|
2358
|
-
Logger.header(`${tsLogo} tsbuild v${"1.8.
|
|
2430
|
+
Logger.header(`${tsLogo} tsbuild v${"1.8.4"}${this.configuration.compilerOptions.incremental && this.configuration.buildCache?.isValid() ? " [incremental]" : ""}`);
|
|
2359
2431
|
try {
|
|
2360
2432
|
const processes = [];
|
|
2361
2433
|
const filesWereEmitted = await this.typeCheck();
|
|
@@ -2386,7 +2458,7 @@ var _TypeScriptProject = class _TypeScriptProject {
|
|
|
2386
2458
|
}
|
|
2387
2459
|
}
|
|
2388
2460
|
if (this.fileWatcher === void 0 || this.fileWatcher.isClosed()) {
|
|
2389
|
-
setImmediate(() => this.watch());
|
|
2461
|
+
setImmediate(() => void this.watch());
|
|
2390
2462
|
}
|
|
2391
2463
|
}
|
|
2392
2464
|
}
|
|
@@ -2425,6 +2497,7 @@ var _TypeScriptProject = class _TypeScriptProject {
|
|
|
2425
2497
|
return emitted || !this.configuration.compilerOptions.declaration;
|
|
2426
2498
|
}
|
|
2427
2499
|
async transpile() {
|
|
2500
|
+
const { build: esbuild, formatMessages } = await import("esbuild");
|
|
2428
2501
|
const plugins = [outputPlugin()];
|
|
2429
2502
|
if (this.buildConfiguration.noExternal.length > 0) {
|
|
2430
2503
|
plugins.push(externalModulesPlugin({ dependencies: await this.getProjectDependencyPaths(), noExternal: this.buildConfiguration.noExternal }));
|
|
@@ -2453,11 +2526,11 @@ var _TypeScriptProject = class _TypeScriptProject {
|
|
|
2453
2526
|
}
|
|
2454
2527
|
}
|
|
2455
2528
|
try {
|
|
2456
|
-
const { warnings, errors, metafile: { outputs } } = await
|
|
2529
|
+
const { warnings, errors, metafile: { outputs } } = await esbuild({
|
|
2457
2530
|
format,
|
|
2458
2531
|
plugins,
|
|
2459
2532
|
define,
|
|
2460
|
-
write:
|
|
2533
|
+
write: true,
|
|
2461
2534
|
metafile: true,
|
|
2462
2535
|
treeShaking: true,
|
|
2463
2536
|
logLevel: "warning",
|
|
@@ -2517,7 +2590,8 @@ var _TypeScriptProject = class _TypeScriptProject {
|
|
|
2517
2590
|
/**
|
|
2518
2591
|
* Watches for changes in the project files and rebuilds the project when changes are detected.
|
|
2519
2592
|
*/
|
|
2520
|
-
watch() {
|
|
2593
|
+
async watch() {
|
|
2594
|
+
const { Watchr } = await import("@d1g1tal/watchr");
|
|
2521
2595
|
const targets = [];
|
|
2522
2596
|
for (const path of this.configuration.include ?? [defaultSourceDirectory]) {
|
|
2523
2597
|
targets.push(Paths.absolute(this.directory, path.replace(globCharacters, "")));
|
|
@@ -2571,7 +2645,7 @@ var _TypeScriptProject = class _TypeScriptProject {
|
|
|
2571
2645
|
Logger.info(`Rebuilding project: ${this.pendingChanges.length} file changes detected.`);
|
|
2572
2646
|
const rootNames = [...this.builderProgram.getProgram().getRootFileNames()];
|
|
2573
2647
|
for (const { event, path, nextPath } of this.pendingChanges) {
|
|
2574
|
-
if (nextPath !== void 0 && (event ===
|
|
2648
|
+
if (nextPath !== void 0 && (event === "rename" || event === "renameDir")) {
|
|
2575
2649
|
this.buildDependencies.delete(Paths.relative(this.directory, path));
|
|
2576
2650
|
this.buildDependencies.add(Paths.relative(this.directory, nextPath));
|
|
2577
2651
|
const index = rootNames.indexOf(path);
|
|
@@ -2580,9 +2654,9 @@ var _TypeScriptProject = class _TypeScriptProject {
|
|
|
2580
2654
|
}
|
|
2581
2655
|
} else {
|
|
2582
2656
|
const index = rootNames.indexOf(path);
|
|
2583
|
-
if (event ===
|
|
2657
|
+
if (event === "unlink" && index !== -1) {
|
|
2584
2658
|
rootNames.splice(index, 1);
|
|
2585
|
-
} else if (event ===
|
|
2659
|
+
} else if (event === "add" && index === -1) {
|
|
2586
2660
|
rootNames.push(path);
|
|
2587
2661
|
}
|
|
2588
2662
|
}
|
package/dist/tsbuild.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
BuildError,
|
|
4
4
|
TypeScriptProject
|
|
5
|
-
} from "./
|
|
5
|
+
} from "./23A5VAYC.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.
|
|
33
|
+
console.log("1.8.4");
|
|
34
34
|
process.exit(0);
|
|
35
35
|
}
|
|
36
36
|
var typeScriptOptions = {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@d1g1tal/tsbuild",
|
|
3
3
|
"author": "D1g1talEntr0py",
|
|
4
|
-
"version": "1.8.
|
|
4
|
+
"version": "1.8.4",
|
|
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.
|
|
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",
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
"scripts": {
|
|
82
82
|
"build": "tsx ./src/tsbuild.ts",
|
|
83
83
|
"build:watch": "tsx ./src/tsbuild.ts --watch",
|
|
84
|
+
"bench": "tsx ./scripts/benchmark.ts",
|
|
84
85
|
"type-check": "tsx ./src/tsbuild.ts --noEmit",
|
|
85
86
|
"lint": "eslint ./src",
|
|
86
87
|
"test": "vitest run",
|