@d1g1tal/tsbuild 1.9.1 → 1.9.2
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 +27 -0
- package/dist/{XTZ3MYA7.js → 237SIAOE.js} +0 -53
- package/dist/{3ZUONNU3.js → HDWN4W6U.js} +2 -1
- package/dist/HQEQHKVJ.js +58 -0
- package/dist/WE3VBWJ5.js +54 -0
- package/dist/tsbuild.js +5 -5
- package/dist/type-script-project.d.ts +1 -76
- package/dist/type-script-project.js +3109 -3
- package/package.json +7 -7
- package/dist/7G6BAIKH.js +0 -3151
|
@@ -1,7 +1,3113 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
BuildError,
|
|
3
|
+
BundleError,
|
|
4
|
+
ConfigurationError,
|
|
5
|
+
TypeCheckError,
|
|
6
|
+
UnsupportedSyntaxError,
|
|
7
|
+
castError
|
|
8
|
+
} from "./WE3VBWJ5.js";
|
|
9
|
+
import {
|
|
10
|
+
BuildMessageType,
|
|
11
|
+
Encoding,
|
|
12
|
+
FileExtension,
|
|
13
|
+
Json,
|
|
14
|
+
Paths,
|
|
15
|
+
Platform,
|
|
16
|
+
buildInfoFile,
|
|
17
|
+
cacheDirectory,
|
|
18
|
+
compilerOptionOverrides,
|
|
19
|
+
dataUnits,
|
|
20
|
+
defaultCleanOptions,
|
|
21
|
+
defaultDirOptions,
|
|
22
|
+
defaultEntryFile,
|
|
23
|
+
defaultEntryPoint,
|
|
24
|
+
defaultOutDirectory,
|
|
25
|
+
defaultSourceDirectory,
|
|
26
|
+
dtsCacheFile,
|
|
27
|
+
dtsCacheVersion,
|
|
28
|
+
format,
|
|
29
|
+
newLine,
|
|
30
|
+
outputManifestFile,
|
|
31
|
+
processEnvExpansionPattern,
|
|
32
|
+
sourceScriptExtensionExpression,
|
|
33
|
+
toEsTarget,
|
|
34
|
+
toJsxRenderingMode,
|
|
35
|
+
typeMatcher
|
|
36
|
+
} from "./237SIAOE.js";
|
|
37
|
+
import {
|
|
38
|
+
__decorateElement,
|
|
39
|
+
__decoratorStart,
|
|
40
|
+
__privateAdd,
|
|
41
|
+
__privateGet,
|
|
42
|
+
__privateMethod,
|
|
43
|
+
__privateSet,
|
|
44
|
+
__runInitializers
|
|
45
|
+
} from "./HQEQHKVJ.js";
|
|
46
|
+
|
|
47
|
+
// src/files.ts
|
|
48
|
+
import { dirname, join } from "node:path";
|
|
49
|
+
import { serialize, deserialize } from "node:v8";
|
|
50
|
+
import { brotliDecompress, brotliCompress } from "node:zlib";
|
|
51
|
+
import { access, constants, mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
52
|
+
var windowsDrivePathRegex = /^[A-Za-z]:[\\/]/;
|
|
53
|
+
var Files = class {
|
|
54
|
+
constructor() {
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Check if a file exists.
|
|
58
|
+
* @param filePath The path to the file.
|
|
59
|
+
*/
|
|
60
|
+
static async exists(filePath) {
|
|
61
|
+
try {
|
|
62
|
+
await access(filePath, constants.F_OK);
|
|
63
|
+
return true;
|
|
64
|
+
} catch (error) {
|
|
65
|
+
if (error.code === "ENOENT") {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Clear a directory by removing all of its entries in parallel.
|
|
73
|
+
* Uses readdir + parallel rm so libuv's threadpool can unlink subtrees concurrently,
|
|
74
|
+
* which is significantly faster than a single recursive `rm` for large output trees.
|
|
75
|
+
* The directory itself is preserved (no mkdir needed afterward).
|
|
76
|
+
* @param directory The path to the directory to clear.
|
|
77
|
+
*/
|
|
78
|
+
static async empty(directory) {
|
|
79
|
+
let entries;
|
|
80
|
+
try {
|
|
81
|
+
entries = await readdir(directory);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
if (error.code === "ENOENT") {
|
|
84
|
+
await mkdir(directory, defaultDirOptions);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
if (entries.length === 0) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const removals = new Array(entries.length);
|
|
93
|
+
for (let i = 0, length = entries.length; i < length; i++) {
|
|
94
|
+
removals[i] = rm(join(directory, entries[i]), defaultCleanOptions);
|
|
95
|
+
}
|
|
96
|
+
await Promise.all(removals);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Write data to a file.
|
|
100
|
+
* Ensures the directory exists before writing.
|
|
101
|
+
* @param filePath The path to the file.
|
|
102
|
+
* @param data The data to write to the file.
|
|
103
|
+
* @param options Optional write file options.
|
|
104
|
+
*/
|
|
105
|
+
static async write(filePath, data, options = { encoding: Encoding.utf8 }) {
|
|
106
|
+
await mkdir(dirname(filePath), defaultDirOptions);
|
|
107
|
+
await writeFile(filePath, data, options);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Load a file and return its contents as a string.
|
|
111
|
+
* @param filePath The path to the file.
|
|
112
|
+
* @param encoding The encoding to use when reading the file. Default is UTF-8.
|
|
113
|
+
* @returns The file contents as a string.
|
|
114
|
+
*/
|
|
115
|
+
static async read(filePath, encoding = Encoding.utf8) {
|
|
116
|
+
return await readFile(this.normalizePath(filePath), { encoding });
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Reads the contents of a directory.
|
|
120
|
+
* @param directoryPath The path to the directory.
|
|
121
|
+
* @returns An array of file and directory names within the specified directory.
|
|
122
|
+
*/
|
|
123
|
+
static async readDirectory(directoryPath) {
|
|
124
|
+
return await readdir(directoryPath);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Normalize a file path to an absolute path.
|
|
128
|
+
* @param path The file path to normalize.
|
|
129
|
+
* @returns The normalized absolute path.
|
|
130
|
+
* @throws {TypeError} if path is relative and not a valid URL
|
|
131
|
+
*/
|
|
132
|
+
static normalizePath(path) {
|
|
133
|
+
if (path.startsWith("/") || path.startsWith("file://") || windowsDrivePathRegex.test(path)) {
|
|
134
|
+
return path;
|
|
135
|
+
}
|
|
136
|
+
if (!path.includes("://")) {
|
|
137
|
+
throw new TypeError(`Files.normalizePath requires an absolute path, got: ${path}`);
|
|
138
|
+
}
|
|
139
|
+
return new URL(path, import.meta.url).pathname;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Decompress a Brotli-compressed buffer.
|
|
143
|
+
* Uses callback-based API wrapped in a Promise for faster performance than streaming.
|
|
144
|
+
* @param buffer The compressed buffer to decompress.
|
|
145
|
+
* @returns The decompressed buffer.
|
|
146
|
+
*/
|
|
147
|
+
static decompressBuffer(buffer) {
|
|
148
|
+
return new Promise((resolve3, reject) => brotliDecompress(buffer, (error, result) => error ? reject(error) : resolve3(result)));
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Compress data using Brotli compression.
|
|
152
|
+
* Uses callback-based API wrapped in a Promise for faster performance than streaming.
|
|
153
|
+
* @param buffer The buffer to compress.
|
|
154
|
+
* @returns The compressed buffer.
|
|
155
|
+
*/
|
|
156
|
+
static compressBuffer(buffer) {
|
|
157
|
+
return new Promise((resolve3, reject) => brotliCompress(buffer, (error, result) => error ? reject(error) : resolve3(result)));
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Load a file and deserialize it using V8 deserialization.
|
|
161
|
+
* Faster than JSON.parse for complex objects.
|
|
162
|
+
* @param path The path to the file.
|
|
163
|
+
* @returns The deserialized object.
|
|
164
|
+
*/
|
|
165
|
+
static async readCompressed(path) {
|
|
166
|
+
return deserialize(await this.decompressBuffer(await readFile(this.normalizePath(path))));
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Serialize an object using V8 serialization and save to a Brotli-compressed file.
|
|
170
|
+
* Faster than JSON.stringify for complex objects.
|
|
171
|
+
* @param path The path to the file.
|
|
172
|
+
* @param data The object to serialize and save.
|
|
173
|
+
*/
|
|
174
|
+
static async writeCompressed(path, data) {
|
|
175
|
+
const normalizedPath = this.normalizePath(path);
|
|
176
|
+
await mkdir(dirname(normalizedPath), defaultDirOptions);
|
|
177
|
+
await writeFile(normalizedPath, await this.compressBuffer(serialize(data)));
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// src/text-formatter.ts
|
|
182
|
+
import { isatty } from "node:tty";
|
|
183
|
+
var { env = {}, platform = "" } = process;
|
|
184
|
+
var isDumbTerminal = env["TERM"] === "dumb";
|
|
185
|
+
var isCompatibleTerminal = isatty(1) && env["TERM"] && !isDumbTerminal;
|
|
186
|
+
var isColorSupported = !("NO_COLOR" in env) && ("FORCE_COLOR" in env || platform === "win32" && !isDumbTerminal || isCompatibleTerminal);
|
|
187
|
+
var replaceClose = (index, string, close, replace, head = string.substring(0, index) + replace, tail = string.substring(index + close.length), next = tail.indexOf(close)) => {
|
|
188
|
+
return head + (next < 0 ? tail : replaceClose(next, tail, close, replace));
|
|
189
|
+
};
|
|
190
|
+
var clearBleed = (index, string, open2, close, replace) => {
|
|
191
|
+
return index < 0 ? `${open2}${string}${close}` : `${open2}${replaceClose(index, string, close, replace)}${close}`;
|
|
192
|
+
};
|
|
193
|
+
var filterEmpty = (open2, close, replace = open2, at = open2.length + 1) => {
|
|
194
|
+
return (text) => text.length ? clearBleed(text.indexOf(close, at), text, open2, close, replace) : "";
|
|
195
|
+
};
|
|
196
|
+
var generateTextFormatter = (open2, close, replace) => filterEmpty(`\x1B[${open2}m`, `\x1B[${close}m`, replace);
|
|
197
|
+
var TextFormat = class {
|
|
198
|
+
static enabled = isColorSupported;
|
|
199
|
+
static reset = generateTextFormatter(0, 0);
|
|
200
|
+
static bold = generateTextFormatter(1, 22, "\x1B[22m\x1B[1m");
|
|
201
|
+
static dim = generateTextFormatter(2, 22, "\x1B[22m\x1B[2m");
|
|
202
|
+
static italic = generateTextFormatter(3, 23);
|
|
203
|
+
static underline = generateTextFormatter(4, 24);
|
|
204
|
+
static inverse = generateTextFormatter(7, 27);
|
|
205
|
+
static hidden = generateTextFormatter(8, 28);
|
|
206
|
+
static strikethrough = generateTextFormatter(9, 29);
|
|
207
|
+
static black = generateTextFormatter(30, 39);
|
|
208
|
+
static red = generateTextFormatter(31, 39);
|
|
209
|
+
static green = generateTextFormatter(32, 39);
|
|
210
|
+
static yellow = generateTextFormatter(33, 39);
|
|
211
|
+
static blue = generateTextFormatter(34, 39);
|
|
212
|
+
static magenta = generateTextFormatter(35, 39);
|
|
213
|
+
static cyan = generateTextFormatter(36, 39);
|
|
214
|
+
static white = generateTextFormatter(37, 39);
|
|
215
|
+
static gray = generateTextFormatter(90, 39);
|
|
216
|
+
static bgBlack = generateTextFormatter(40, 49);
|
|
217
|
+
static bgRed = generateTextFormatter(41, 49);
|
|
218
|
+
static bgGreen = generateTextFormatter(42, 49);
|
|
219
|
+
static bgYellow = generateTextFormatter(43, 49);
|
|
220
|
+
static bgBlue = generateTextFormatter(44, 49);
|
|
221
|
+
static bgMagenta = generateTextFormatter(45, 49);
|
|
222
|
+
static bgCyan = generateTextFormatter(46, 49);
|
|
223
|
+
static bgWhite = generateTextFormatter(47, 49);
|
|
224
|
+
static blackBright = generateTextFormatter(90, 39);
|
|
225
|
+
static redBright = generateTextFormatter(91, 39);
|
|
226
|
+
static greenBright = generateTextFormatter(92, 39);
|
|
227
|
+
static yellowBright = generateTextFormatter(93, 39);
|
|
228
|
+
static blueBright = generateTextFormatter(94, 39);
|
|
229
|
+
static magentaBright = generateTextFormatter(95, 39);
|
|
230
|
+
static cyanBright = generateTextFormatter(96, 39);
|
|
231
|
+
static whiteBright = generateTextFormatter(97, 39);
|
|
232
|
+
static bgBlackBright = generateTextFormatter(100, 49);
|
|
233
|
+
static bgRedBright = generateTextFormatter(101, 49);
|
|
234
|
+
static bgGreenBright = generateTextFormatter(102, 49);
|
|
235
|
+
static bgYellowBright = generateTextFormatter(103, 49);
|
|
236
|
+
static bgBlueBright = generateTextFormatter(104, 49);
|
|
237
|
+
static bgMagentaBright = generateTextFormatter(105, 49);
|
|
238
|
+
static bgCyanBright = generateTextFormatter(106, 49);
|
|
239
|
+
static bgWhiteBright = generateTextFormatter(107, 49);
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// src/logger.ts
|
|
243
|
+
var LOG_1024 = Math.log(1024);
|
|
244
|
+
var ansiEscapePattern = /\x1b\[[0-9;]*m/g;
|
|
245
|
+
var isWrittenFiles = (data) => {
|
|
246
|
+
if (!Array.isArray(data)) {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
return data.every((writtenFile) => {
|
|
250
|
+
return writtenFile !== null && typeof writtenFile === "object" && "path" in writtenFile && "size" in writtenFile;
|
|
251
|
+
});
|
|
252
|
+
};
|
|
253
|
+
var colorize = (type2, data, onlyImportant = false) => {
|
|
254
|
+
if (onlyImportant && (type2 === "info" || type2 === "success")) {
|
|
255
|
+
return data;
|
|
256
|
+
}
|
|
257
|
+
switch (type2) {
|
|
258
|
+
case "info":
|
|
259
|
+
return TextFormat.blue(data);
|
|
260
|
+
case "error":
|
|
261
|
+
return TextFormat.red(data);
|
|
262
|
+
case "warn":
|
|
263
|
+
return TextFormat.yellow(data);
|
|
264
|
+
default:
|
|
265
|
+
return TextFormat.green(data);
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
var prettyBytes = (bytes) => {
|
|
269
|
+
if (bytes === 0) {
|
|
270
|
+
return { value: "0", unit: "B" };
|
|
271
|
+
}
|
|
272
|
+
const exp = ~~(Math.log(bytes) / LOG_1024);
|
|
273
|
+
return { value: (bytes / Math.pow(1024, exp)).toFixed(2), unit: dataUnits[exp] };
|
|
274
|
+
};
|
|
275
|
+
var Logger = class _Logger {
|
|
276
|
+
constructor() {
|
|
277
|
+
}
|
|
278
|
+
static EntryType = {
|
|
279
|
+
Info: "info",
|
|
280
|
+
Success: "success",
|
|
281
|
+
Done: "done",
|
|
282
|
+
Error: "error",
|
|
283
|
+
Warn: "warn"
|
|
284
|
+
};
|
|
285
|
+
/** Clears the console */
|
|
286
|
+
static clear() {
|
|
287
|
+
console.log("\x1Bc");
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Logs a header box with a message.
|
|
291
|
+
* The header is styled with a cyan border and the message is centered inside. ANSI escape codes are stripped from the message when calculating the width to ensure proper formatting.
|
|
292
|
+
* This ensures the header box is sized correctly even when the message contains color codes or other formatting.
|
|
293
|
+
* @param message The message to display in the header.
|
|
294
|
+
*/
|
|
295
|
+
static header(message) {
|
|
296
|
+
const innerWidth = message.replace(ansiEscapePattern, "").length + 2;
|
|
297
|
+
console.log(TextFormat.cyan(`\u256D${"\u2500".repeat(innerWidth)}\u256E${newLine}\u2502 ${message} \u2502${newLine}\u2570${"\u2500".repeat(innerWidth)}\u256F`));
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Logs a separator line.
|
|
301
|
+
* @param width Optional width of the separator (default: 40).
|
|
302
|
+
*/
|
|
303
|
+
static separator(width = 40) {
|
|
304
|
+
console.log(TextFormat.dim("\u2500".repeat(width)));
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Logs a success message with a check mark and optional indentation.
|
|
308
|
+
* @param message The message to log.
|
|
309
|
+
* @param indent Whether to indent the message (tree structure).
|
|
310
|
+
*/
|
|
311
|
+
static step(message, indent = false) {
|
|
312
|
+
const prefix = indent ? " \u2514\u2500" : "\u2713";
|
|
313
|
+
console.log(TextFormat.green(`${prefix} ${message}`));
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Logs sub-step timing entries in a tree format below a parent step.
|
|
317
|
+
* @param steps The sub-steps to log.
|
|
318
|
+
*/
|
|
319
|
+
static subSteps(steps) {
|
|
320
|
+
const visible = steps.filter(({ ms }) => ms >= 5);
|
|
321
|
+
if (visible.length === 0) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
let maxNameLength = 0;
|
|
325
|
+
let maxDurationLength = 0;
|
|
326
|
+
for (let i = 0, length = visible.length; i < length; i++) {
|
|
327
|
+
const { name, duration } = visible[i];
|
|
328
|
+
if (name.length > maxNameLength) {
|
|
329
|
+
maxNameLength = name.length;
|
|
330
|
+
}
|
|
331
|
+
if (duration.length > maxDurationLength) {
|
|
332
|
+
maxDurationLength = duration.length;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
for (let i = 0, length = visible.length; i < length; i++) {
|
|
336
|
+
const { name, duration } = visible[i];
|
|
337
|
+
const prefix = i === length - 1 ? " \u2514\u2500" : " \u251C\u2500";
|
|
338
|
+
console.log(`${TextFormat.dim(prefix)} ${TextFormat.bold(name.padEnd(maxNameLength))} ${TextFormat.cyan(duration.padStart(maxDurationLength))}`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Logs a success message.
|
|
343
|
+
* @param message The message to log.
|
|
344
|
+
* @param args Additional data to log.
|
|
345
|
+
* @returns void
|
|
346
|
+
*/
|
|
347
|
+
static success(message, ...args) {
|
|
348
|
+
return _Logger.log(message, "success", ...args);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Logs an info message.
|
|
352
|
+
* @param message The message to log.
|
|
353
|
+
* @param args Additional data to log.
|
|
354
|
+
* @returns void
|
|
355
|
+
*/
|
|
356
|
+
static info(message, ...args) {
|
|
357
|
+
return _Logger.log(message, "info", ...args);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Logs an error message.
|
|
361
|
+
* @param message The message to log.
|
|
362
|
+
* @param args Additional data to log.
|
|
363
|
+
* @returns void
|
|
364
|
+
*/
|
|
365
|
+
static error(message, ...args) {
|
|
366
|
+
return _Logger.log(message, "error", ...args);
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Logs a warning message.
|
|
370
|
+
* @param message The message to log.
|
|
371
|
+
* @param args Additional data to log.
|
|
372
|
+
* @returns void
|
|
373
|
+
*/
|
|
374
|
+
static warn(message, ...args) {
|
|
375
|
+
return _Logger.log(message, "warn", ...args);
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Logs a done message.
|
|
379
|
+
* @param message The message to log.
|
|
380
|
+
* @param type The type of the log entry.
|
|
381
|
+
* @param data Additional data to log.
|
|
382
|
+
*/
|
|
383
|
+
static log(message, type2, ...data) {
|
|
384
|
+
if (data.length) {
|
|
385
|
+
if (isWrittenFiles(data)) {
|
|
386
|
+
if (message) {
|
|
387
|
+
console.log(colorize(type2, message, true));
|
|
388
|
+
}
|
|
389
|
+
_Logger.#files(data);
|
|
390
|
+
} else {
|
|
391
|
+
console.log(colorize(type2, message, true), ...data);
|
|
392
|
+
}
|
|
393
|
+
} else {
|
|
394
|
+
console.log(colorize(type2, message, true));
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Logs an array of WrittenFile objects in a formatted manner.
|
|
399
|
+
* @param files - The array of WrittenFile objects to log.
|
|
400
|
+
* @internal
|
|
401
|
+
*/
|
|
402
|
+
static #files(files) {
|
|
403
|
+
let maxPathLength = 0;
|
|
404
|
+
let maxValueLength = 0;
|
|
405
|
+
let maxUnitLength = 0;
|
|
406
|
+
const formatted = [];
|
|
407
|
+
for (let i = 0, length = files.length; i < length; i++) {
|
|
408
|
+
const { path, size } = files[i];
|
|
409
|
+
const { value, unit } = prettyBytes(size);
|
|
410
|
+
if (path.length > maxPathLength) {
|
|
411
|
+
maxPathLength = path.length;
|
|
412
|
+
}
|
|
413
|
+
if (value.length > maxValueLength) {
|
|
414
|
+
maxValueLength = value.length;
|
|
415
|
+
}
|
|
416
|
+
if (unit.length > maxUnitLength) {
|
|
417
|
+
maxUnitLength = unit.length;
|
|
418
|
+
}
|
|
419
|
+
formatted.push({ path, value, unit });
|
|
420
|
+
}
|
|
421
|
+
for (let i = 0, length = formatted.length; i < length; i++) {
|
|
422
|
+
const { path, value, unit } = formatted[i];
|
|
423
|
+
const paddedPath = path.padEnd(maxPathLength);
|
|
424
|
+
const paddedValue = value.padStart(maxValueLength);
|
|
425
|
+
const paddedUnit = unit.padEnd(maxUnitLength);
|
|
426
|
+
const prefix = i === length - 1 ? " \u2514\u2500" : " \u251C\u2500";
|
|
427
|
+
console.log(`${TextFormat.dim(prefix)} ${TextFormat.bold(paddedPath)} ${TextFormat.cyan(paddedValue)} ${TextFormat.dim(paddedUnit)}`);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
// src/type-script-project.ts
|
|
433
|
+
import { rm as rm2 } from "node:fs/promises";
|
|
434
|
+
|
|
435
|
+
// src/dts/declaration-bundler.ts
|
|
436
|
+
import MagicString2 from "magic-string";
|
|
437
|
+
import { mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
|
|
438
|
+
import { basename, posix } from "node:path";
|
|
439
|
+
|
|
440
|
+
// src/dts/declaration-processor.ts
|
|
441
|
+
import {
|
|
442
|
+
canHaveModifiers,
|
|
443
|
+
forEachChild,
|
|
444
|
+
isClassDeclaration,
|
|
445
|
+
isEmptyStatement,
|
|
446
|
+
isEnumDeclaration,
|
|
447
|
+
isExportDeclaration,
|
|
448
|
+
isExportSpecifier,
|
|
449
|
+
isFunctionDeclaration,
|
|
450
|
+
isIdentifier,
|
|
451
|
+
isImportDeclaration,
|
|
452
|
+
isImportTypeNode,
|
|
453
|
+
isInterfaceDeclaration,
|
|
454
|
+
isLiteralTypeNode,
|
|
455
|
+
isModuleBlock,
|
|
456
|
+
isModuleDeclaration,
|
|
457
|
+
isNamedExports,
|
|
458
|
+
isNamespaceExport,
|
|
459
|
+
isStringLiteral,
|
|
460
|
+
isTypeAliasDeclaration,
|
|
461
|
+
isVariableStatement,
|
|
462
|
+
ModifierFlags,
|
|
463
|
+
NodeFlags,
|
|
464
|
+
SyntaxKind,
|
|
465
|
+
getCombinedModifierFlags
|
|
466
|
+
} from "typescript";
|
|
467
|
+
import MagicString from "magic-string";
|
|
468
|
+
var commaCharacter = 44;
|
|
469
|
+
var DeclarationProcessor = class _DeclarationProcessor {
|
|
470
|
+
constructor() {
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Pre-processes a declaration file before bundling.
|
|
474
|
+
*
|
|
475
|
+
* The pre-process step has the following goals:
|
|
476
|
+
* - Fixes the "modifiers", removing any `export` modifier and adding any missing `declare` modifier
|
|
477
|
+
* - Splits compound `VariableStatement` into its parts
|
|
478
|
+
* - Moves declarations for the same "name" to be next to each other
|
|
479
|
+
* - Removes any triple-slash directives and records them
|
|
480
|
+
* - Creates a synthetic name for any nameless "export default"
|
|
481
|
+
* - Resolves inline `import()` statements and generates top-level imports for them
|
|
482
|
+
* - Generates a separate `export {}` statement for any item which had its modifiers rewritten
|
|
483
|
+
* - Duplicates the identifiers of a namespace `export`, so that renaming does not break it
|
|
484
|
+
*
|
|
485
|
+
* @param sourceFile The source file to process
|
|
486
|
+
* @returns The pre-processed output, which includes the modified code, type references, and file references
|
|
487
|
+
*/
|
|
488
|
+
static preProcess(sourceFile) {
|
|
489
|
+
const code = new MagicString(sourceFile.getFullText());
|
|
490
|
+
const declaredNames = /* @__PURE__ */ new Set();
|
|
491
|
+
const exportedNames = /* @__PURE__ */ new Set();
|
|
492
|
+
let defaultExport = "";
|
|
493
|
+
const inlineImports = /* @__PURE__ */ new Map();
|
|
494
|
+
const nameRanges = /* @__PURE__ */ new Map();
|
|
495
|
+
function newlineAt(node, pos) {
|
|
496
|
+
return node.getSourceFile().getFullText()[pos] === newLine;
|
|
497
|
+
}
|
|
498
|
+
function getStart(node) {
|
|
499
|
+
const start = node.getFullStart();
|
|
500
|
+
return start + (newlineAt(node, start) ? 1 : 0);
|
|
501
|
+
}
|
|
502
|
+
function getEnd(node) {
|
|
503
|
+
const end = node.getEnd();
|
|
504
|
+
return end + (newlineAt(node, end) ? 1 : 0);
|
|
505
|
+
}
|
|
506
|
+
function parseReferenceDirectives(fileReferences2) {
|
|
507
|
+
const referenceDirectives = /* @__PURE__ */ new Set();
|
|
508
|
+
const lineStarts = sourceFile.getLineStarts();
|
|
509
|
+
for (const { fileName, pos } of fileReferences2) {
|
|
510
|
+
referenceDirectives.add(fileName);
|
|
511
|
+
let end = sourceFile.getLineEndOfPosition(pos);
|
|
512
|
+
if (code.slice(end, end + 1) === newLine) {
|
|
513
|
+
end += 1;
|
|
514
|
+
}
|
|
515
|
+
code.remove(lineStarts[sourceFile.getLineAndCharacterOfPosition(pos).line], end);
|
|
516
|
+
}
|
|
517
|
+
return referenceDirectives;
|
|
518
|
+
}
|
|
519
|
+
function createNameRange(node) {
|
|
520
|
+
return [getStart(node), getEnd(node)];
|
|
521
|
+
}
|
|
522
|
+
function checkInlineImport(node) {
|
|
523
|
+
forEachChild(node, checkInlineImport);
|
|
524
|
+
if (isImportTypeNode(node)) {
|
|
525
|
+
if (!isLiteralTypeNode(node.argument) || !isStringLiteral(node.argument.literal)) {
|
|
526
|
+
throw new UnsupportedSyntaxError(node, "inline imports should have a literal argument");
|
|
527
|
+
}
|
|
528
|
+
const children = node.getChildren();
|
|
529
|
+
const token = children.find(({ kind }) => kind === SyntaxKind.DotToken || kind === SyntaxKind.LessThanToken);
|
|
530
|
+
code.overwrite(children.find(({ kind }) => kind === SyntaxKind.ImportKeyword).getStart(), token === void 0 ? node.getEnd() : token.getStart(), createNamespaceImport(node.argument.literal.text));
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
function createNamespaceImport(fileId) {
|
|
534
|
+
let importName = inlineImports.get(fileId);
|
|
535
|
+
if (importName === void 0) {
|
|
536
|
+
const chars = [];
|
|
537
|
+
for (let i = 0; i < fileId.length; i++) {
|
|
538
|
+
const char = fileId[i];
|
|
539
|
+
const code2 = char.charCodeAt(0);
|
|
540
|
+
chars.push(code2 >= 97 && code2 <= 122 || code2 >= 65 && code2 <= 90 || code2 >= 48 && code2 <= 57 || code2 === 95 || code2 === 36 ? char : "_");
|
|
541
|
+
}
|
|
542
|
+
importName = generateUniqueName(chars.join(""));
|
|
543
|
+
inlineImports.set(fileId, importName);
|
|
544
|
+
}
|
|
545
|
+
return importName;
|
|
546
|
+
}
|
|
547
|
+
function generateUniqueName(hint) {
|
|
548
|
+
while (declaredNames.has(hint)) {
|
|
549
|
+
hint = `_${hint}`;
|
|
550
|
+
}
|
|
551
|
+
declaredNames.add(hint);
|
|
552
|
+
return hint;
|
|
553
|
+
}
|
|
554
|
+
function pushNamedNode(name, range) {
|
|
555
|
+
const nodes = nameRanges.get(name);
|
|
556
|
+
if (nodes === void 0) {
|
|
557
|
+
nameRanges.set(name, [range]);
|
|
558
|
+
} else {
|
|
559
|
+
const last = nodes[nodes.length - 1];
|
|
560
|
+
if (last[1] === range[0]) {
|
|
561
|
+
last[1] = range[1];
|
|
562
|
+
} else {
|
|
563
|
+
nodes.push(range);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
function fixModifiers(node) {
|
|
568
|
+
if (!canHaveModifiers(node)) {
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
let hasDeclare = false;
|
|
572
|
+
for (const modifier of node.modifiers ?? []) {
|
|
573
|
+
if (modifier.kind === SyntaxKind.DefaultKeyword || modifier.kind === SyntaxKind.ExportKeyword) {
|
|
574
|
+
code.remove(modifier.getStart(), modifier.getEnd() + getTrailingWhitespaceLength(modifier.getEnd(), node.getEnd()));
|
|
575
|
+
} else if (modifier.kind === SyntaxKind.DeclareKeyword) {
|
|
576
|
+
hasDeclare = true;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
const needsDeclare = isEnumDeclaration(node) || isClassDeclaration(node) || isFunctionDeclaration(node) || isModuleDeclaration(node) || isVariableStatement(node);
|
|
580
|
+
if (needsDeclare && !hasDeclare) {
|
|
581
|
+
code.appendRight(node.getStart(), "declare ");
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
function duplicateExports(module) {
|
|
585
|
+
if (!module.body || !isModuleBlock(module.body)) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
for (const node of module.body.statements) {
|
|
589
|
+
if (isExportDeclaration(node) && node.exportClause && !isNamespaceExport(node.exportClause)) {
|
|
590
|
+
for (const { name, propertyName } of node.exportClause.elements) {
|
|
591
|
+
if (propertyName === void 0) {
|
|
592
|
+
code.appendLeft(name.getEnd(), ` as ${name.getText()}`);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function getTrailingWhitespaceLength(start, end) {
|
|
599
|
+
let length = 0;
|
|
600
|
+
while (start + length < end) {
|
|
601
|
+
const char = code.original[start + length];
|
|
602
|
+
if (char === " " || char === " " || char === newLine || char === "\r") {
|
|
603
|
+
length++;
|
|
604
|
+
} else {
|
|
605
|
+
break;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
return length;
|
|
609
|
+
}
|
|
610
|
+
for (const node of sourceFile.statements) {
|
|
611
|
+
if (isExportDeclaration(node)) {
|
|
612
|
+
if (node.exportClause && isNamedExports(node.exportClause) && node.exportClause.elements.length === 0 && !node.moduleSpecifier) {
|
|
613
|
+
code.remove(getStart(node), getEnd(node));
|
|
614
|
+
} else if (node.isTypeOnly) {
|
|
615
|
+
const exportKeywordEnd = node.getStart() + "export".length;
|
|
616
|
+
const nextTokenStart = node.exportClause?.getStart() ?? node.moduleSpecifier?.getStart() ?? node.getEnd();
|
|
617
|
+
const typeMatch = code.slice(exportKeywordEnd, nextTokenStart).match(typeMatcher);
|
|
618
|
+
if (typeMatch?.index !== void 0) {
|
|
619
|
+
const typeKeywordStart = exportKeywordEnd + typeMatch.index;
|
|
620
|
+
const typeKeywordEnd = typeKeywordStart + "type".length;
|
|
621
|
+
const afterType = code.slice(typeKeywordEnd, nextTokenStart);
|
|
622
|
+
code.remove(typeKeywordStart, typeKeywordEnd + afterType.length - afterType.trimStart().length);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
} else if (isEnumDeclaration(node) || isFunctionDeclaration(node) || isInterfaceDeclaration(node) || isClassDeclaration(node) || isTypeAliasDeclaration(node) || isModuleDeclaration(node)) {
|
|
626
|
+
if (node.name) {
|
|
627
|
+
const name = node.name.getText();
|
|
628
|
+
declaredNames.add(name);
|
|
629
|
+
if (_DeclarationProcessor.#matchesModifier(node, ModifierFlags.ExportDefault)) {
|
|
630
|
+
defaultExport = name;
|
|
631
|
+
} else if (_DeclarationProcessor.#matchesModifier(node, ModifierFlags.Export)) {
|
|
632
|
+
exportedNames.add(name);
|
|
633
|
+
}
|
|
634
|
+
if (!(node.flags & NodeFlags.GlobalAugmentation)) {
|
|
635
|
+
pushNamedNode(name, createNameRange(node));
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
if (isModuleDeclaration(node)) {
|
|
639
|
+
duplicateExports(node);
|
|
640
|
+
}
|
|
641
|
+
fixModifiers(node);
|
|
642
|
+
} else if (isVariableStatement(node)) {
|
|
643
|
+
for (const { name } of node.declarationList.declarations) {
|
|
644
|
+
if (isIdentifier(name)) {
|
|
645
|
+
const nameText = name.getText();
|
|
646
|
+
declaredNames.add(nameText);
|
|
647
|
+
if (node.modifiers?.some((modifier) => modifier.kind === SyntaxKind.DefaultKeyword)) {
|
|
648
|
+
defaultExport = nameText;
|
|
649
|
+
} else if (node.modifiers?.some((modifier) => modifier.kind === SyntaxKind.ExportKeyword)) {
|
|
650
|
+
exportedNames.add(nameText);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
fixModifiers(node);
|
|
655
|
+
const { declarations } = node.declarationList;
|
|
656
|
+
if (declarations.length === 1) {
|
|
657
|
+
const [{ name }] = declarations;
|
|
658
|
+
if (isIdentifier(name)) {
|
|
659
|
+
pushNamedNode(name.getText(), createNameRange(node));
|
|
660
|
+
}
|
|
661
|
+
} else {
|
|
662
|
+
const decls = declarations.slice();
|
|
663
|
+
const first = decls.shift();
|
|
664
|
+
pushNamedNode(first.name.getText(), [getStart(node), first.getEnd()]);
|
|
665
|
+
for (const declaration of decls) {
|
|
666
|
+
if (isIdentifier(declaration.name)) {
|
|
667
|
+
pushNamedNode(declaration.name.getText(), [declaration.getFullStart(), declaration.getEnd()]);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
const { flags } = node.declarationList;
|
|
672
|
+
const prefix = `declare ${flags & NodeFlags.Let ? "let" : flags & NodeFlags.Const ? "const" : "var"} `;
|
|
673
|
+
const sourceText = sourceFile.text;
|
|
674
|
+
for (let i = 1; i < declarations.length; i++) {
|
|
675
|
+
const prev = declarations[i - 1];
|
|
676
|
+
const curr = declarations[i];
|
|
677
|
+
let commaPos = -1;
|
|
678
|
+
const limit = curr.getStart();
|
|
679
|
+
for (let p = prev.end; p < limit; p++) {
|
|
680
|
+
if (sourceText.charCodeAt(p) === commaCharacter) {
|
|
681
|
+
commaPos = p;
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
if (commaPos === -1) {
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
code.remove(commaPos, commaPos + 1);
|
|
689
|
+
code.appendLeft(commaPos, `;${newLine}`);
|
|
690
|
+
const start = curr.getFullStart();
|
|
691
|
+
const slice = sourceText.substring(start, curr.getStart());
|
|
692
|
+
const whitespace = slice.length - slice.trimStart().length;
|
|
693
|
+
if (whitespace) {
|
|
694
|
+
code.overwrite(start, start + whitespace, prefix);
|
|
695
|
+
} else {
|
|
696
|
+
code.appendLeft(start, prefix);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
for (const node of sourceFile.statements) {
|
|
702
|
+
checkInlineImport(node);
|
|
703
|
+
if ((isFunctionDeclaration(node) || isClassDeclaration(node)) && !node.name) {
|
|
704
|
+
if (defaultExport === "") {
|
|
705
|
+
defaultExport = generateUniqueName("export_default");
|
|
706
|
+
}
|
|
707
|
+
const children = node.getChildren();
|
|
708
|
+
const index = children.findIndex((node2) => node2.kind === SyntaxKind.ClassKeyword || node2.kind === SyntaxKind.FunctionKeyword);
|
|
709
|
+
const token = children[index];
|
|
710
|
+
const nextToken = children[index + 1];
|
|
711
|
+
if (SyntaxKind.FirstPunctuation <= nextToken.kind && nextToken.kind <= SyntaxKind.LastPunctuation) {
|
|
712
|
+
code.appendLeft(nextToken.getStart(), `${code.slice(token.getEnd(), nextToken.getStart()) !== " " ? " " : ""}${defaultExport}`);
|
|
713
|
+
} else {
|
|
714
|
+
code.appendRight(token.getEnd(), ` ${defaultExport}`);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
for (const nameRange of nameRanges.values()) {
|
|
719
|
+
const [start] = nameRange.pop();
|
|
720
|
+
for (const [rangeStart, rangeEnd] of nameRange) {
|
|
721
|
+
code.move(rangeStart, rangeEnd, start);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
if (defaultExport !== "") {
|
|
725
|
+
code.append(`${newLine}export default ${defaultExport};${newLine}`);
|
|
726
|
+
}
|
|
727
|
+
if (exportedNames.size) {
|
|
728
|
+
code.append(`${newLine}export { ${[...exportedNames].join(", ")} };${newLine}`);
|
|
729
|
+
}
|
|
730
|
+
for (const [fileId, importName] of inlineImports.entries()) {
|
|
731
|
+
code.prepend(`import * as ${importName} from "${fileId}";${newLine}`);
|
|
732
|
+
}
|
|
733
|
+
const typeReferences = parseReferenceDirectives(sourceFile.typeReferenceDirectives);
|
|
734
|
+
const fileReferences = parseReferenceDirectives(sourceFile.referencedFiles);
|
|
735
|
+
return { code: code.toString(), typeReferences, fileReferences };
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Check if a TypeScript declaration has specific modifier flags
|
|
739
|
+
* @param node - The TypeScript declaration node
|
|
740
|
+
* @param flags - The modifier flags to check for
|
|
741
|
+
* @returns True if the node has all the specified flags
|
|
742
|
+
*/
|
|
743
|
+
static #matchesModifier = (node, flags) => (getCombinedModifierFlags(node) & flags) === flags;
|
|
744
|
+
/**
|
|
745
|
+
* Post-processes a bundled declaration file to clean up bundling artifacts.
|
|
746
|
+
*
|
|
747
|
+
* @param sourceFile The source file to process
|
|
748
|
+
* @returns The processed source code
|
|
749
|
+
*/
|
|
750
|
+
static postProcess(sourceFile) {
|
|
751
|
+
const magic = new MagicString(sourceFile.getFullText());
|
|
752
|
+
function visitNode(node) {
|
|
753
|
+
if (isEmptyStatement(node)) {
|
|
754
|
+
magic.remove(node.getStart(), node.getEnd());
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
if ((isImportDeclaration(node) || isExportDeclaration(node)) && node.moduleSpecifier && isStringLiteral(node.moduleSpecifier)) {
|
|
758
|
+
const { text } = node.moduleSpecifier;
|
|
759
|
+
if (text.startsWith(".") && text.endsWith(FileExtension.DTS)) {
|
|
760
|
+
const replacement = text.endsWith(".d.tsx") ? text.slice(0, -6) + FileExtension.JS : text.slice(0, -5) + FileExtension.JS;
|
|
761
|
+
magic.overwrite(node.moduleSpecifier.getStart() + 1, node.moduleSpecifier.getEnd() - 1, replacement);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
if (isExportSpecifier(node) && node.propertyName && isIdentifier(node.propertyName) && isIdentifier(node.name) && node.propertyName.text === node.name.text) {
|
|
765
|
+
magic.remove(node.propertyName.getStart(), node.name.getStart());
|
|
766
|
+
}
|
|
767
|
+
forEachChild(node, visitNode);
|
|
768
|
+
}
|
|
769
|
+
visitNode(sourceFile);
|
|
770
|
+
return magic.toString();
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
// src/dts/declaration-bundler.ts
|
|
775
|
+
import {
|
|
776
|
+
sys,
|
|
777
|
+
createSourceFile,
|
|
778
|
+
ScriptTarget,
|
|
779
|
+
isImportDeclaration as isImportDeclaration2,
|
|
780
|
+
isExportDeclaration as isExportDeclaration2,
|
|
781
|
+
isInterfaceDeclaration as isInterfaceDeclaration2,
|
|
782
|
+
isTypeAliasDeclaration as isTypeAliasDeclaration2,
|
|
783
|
+
isEnumDeclaration as isEnumDeclaration2,
|
|
784
|
+
isFunctionDeclaration as isFunctionDeclaration2,
|
|
785
|
+
isClassDeclaration as isClassDeclaration2,
|
|
786
|
+
isVariableStatement as isVariableStatement2,
|
|
787
|
+
isModuleDeclaration as isModuleDeclaration2,
|
|
788
|
+
isModuleBlock as isModuleBlock2,
|
|
789
|
+
isNamedExports as isNamedExports2,
|
|
790
|
+
isNamedImports,
|
|
791
|
+
isIdentifier as isIdentifier2,
|
|
792
|
+
isNamespaceImport,
|
|
793
|
+
isQualifiedName,
|
|
794
|
+
resolveModuleName,
|
|
795
|
+
isExportAssignment,
|
|
796
|
+
forEachChild as forEachChild2
|
|
797
|
+
} from "typescript";
|
|
798
|
+
var nodeModules = "/node_modules/";
|
|
799
|
+
var emptySet = /* @__PURE__ */ new Set();
|
|
800
|
+
function mergeImports(imports) {
|
|
801
|
+
const merged = /* @__PURE__ */ new Map();
|
|
802
|
+
const raw = /* @__PURE__ */ new Set();
|
|
803
|
+
for (const imp of imports) {
|
|
804
|
+
if (imp.kind === "raw") {
|
|
805
|
+
raw.add(imp.text);
|
|
806
|
+
continue;
|
|
807
|
+
}
|
|
808
|
+
const key = `${imp.isType ? "type:" : ""}${imp.specifier}`;
|
|
809
|
+
let entry = merged.get(key);
|
|
810
|
+
if (entry === void 0) {
|
|
811
|
+
entry = { specifier: imp.specifier, isType: imp.isType, names: /* @__PURE__ */ new Set() };
|
|
812
|
+
merged.set(key, entry);
|
|
813
|
+
}
|
|
814
|
+
for (const name of imp.names) {
|
|
815
|
+
entry.names.add(name);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
const result = [];
|
|
819
|
+
for (const { specifier, isType, names } of merged.values()) {
|
|
820
|
+
const sorted = Array.from(names).sort();
|
|
821
|
+
result.push(`${isType ? "import type" : "import"} { ${sorted.join(", ")} } from "${specifier}";`);
|
|
822
|
+
}
|
|
823
|
+
for (const text of raw) {
|
|
824
|
+
result.push(text);
|
|
825
|
+
}
|
|
826
|
+
return result;
|
|
827
|
+
}
|
|
828
|
+
var DeclarationBundler = class _DeclarationBundler {
|
|
829
|
+
/** Project declaration files from in-memory FileManager */
|
|
830
|
+
#declarationFiles = /* @__PURE__ */ new Map();
|
|
831
|
+
/** External declaration files resolved from disk (node_modules) when resolve is enabled */
|
|
832
|
+
#externalDeclarationFiles = /* @__PURE__ */ new Map();
|
|
833
|
+
/** d.ts Bundle Options */
|
|
834
|
+
#options;
|
|
835
|
+
/** WeakMap cache for identifier collection to avoid re-parsing same source files */
|
|
836
|
+
#identifierCache = /* @__PURE__ */ new WeakMap();
|
|
837
|
+
/** SourceFile cache keyed by path — survives across multiple bundle() calls (entry points) */
|
|
838
|
+
#sourceFileCache = /* @__PURE__ */ new Map();
|
|
839
|
+
/** Module resolution cache for this bundler instance */
|
|
840
|
+
#moduleResolutionCache = /* @__PURE__ */ new Map();
|
|
841
|
+
/** Pre-computed set of directory prefixes from declaration file paths for O(1) directoryExists lookups */
|
|
842
|
+
#declarationDirs = /* @__PURE__ */ new Set();
|
|
843
|
+
/** Pre-built matcher for external patterns — O(1) string lookups + cached regex tests */
|
|
844
|
+
#matchExternal;
|
|
845
|
+
/** Pre-built matcher for noExternal patterns — O(1) string lookups + cached regex tests */
|
|
846
|
+
#matchNoExternal;
|
|
847
|
+
// Create a proper module resolution host that supports both in-memory files and disk files
|
|
848
|
+
#moduleResolutionHost = {
|
|
849
|
+
fileExists: (fileName) => {
|
|
850
|
+
return this.#declarationFiles.has(fileName) || this.#externalDeclarationFiles.has(fileName) || this.#options.resolve && sys.fileExists(fileName);
|
|
851
|
+
},
|
|
852
|
+
readFile: (fileName) => {
|
|
853
|
+
const cached = this.#declarationFiles.get(fileName) ?? this.#externalDeclarationFiles.get(fileName);
|
|
854
|
+
if (cached) {
|
|
855
|
+
return cached.code;
|
|
856
|
+
}
|
|
857
|
+
if (!this.#options.resolve) {
|
|
858
|
+
return void 0;
|
|
859
|
+
}
|
|
860
|
+
const rawContent = sys.readFile(fileName, Encoding.utf8);
|
|
861
|
+
if (rawContent !== void 0) {
|
|
862
|
+
const preProcessOutput = DeclarationProcessor.preProcess(createSourceFile(fileName, rawContent, ScriptTarget.Latest, true));
|
|
863
|
+
this.#externalDeclarationFiles.set(fileName, preProcessOutput);
|
|
864
|
+
return preProcessOutput.code;
|
|
865
|
+
}
|
|
866
|
+
return void 0;
|
|
867
|
+
},
|
|
868
|
+
directoryExists: (dirName) => {
|
|
869
|
+
const normalizedDir = dirName.endsWith("/") ? dirName.slice(0, -1) : dirName;
|
|
870
|
+
return this.#declarationDirs.has(normalizedDir) || (this.#options.resolve ? sys.directoryExists(dirName) : false);
|
|
871
|
+
},
|
|
872
|
+
getCurrentDirectory: () => this.#options.currentDirectory,
|
|
873
|
+
/* v8 ignore next */
|
|
874
|
+
getDirectories: () => []
|
|
875
|
+
};
|
|
876
|
+
/**
|
|
877
|
+
* Creates a new DTS bundler instance
|
|
878
|
+
* @param dtsBundleOptions - Options for the DTS bundler
|
|
879
|
+
*/
|
|
880
|
+
constructor(dtsBundleOptions) {
|
|
881
|
+
for (const [filePath, cachedDecl] of dtsBundleOptions.declarationFiles) {
|
|
882
|
+
this.#declarationFiles.set(sys.resolvePath(filePath), cachedDecl);
|
|
883
|
+
}
|
|
884
|
+
for (const filePath of this.#declarationFiles.keys()) {
|
|
885
|
+
let dir = filePath.lastIndexOf("/") !== -1 ? filePath.slice(0, filePath.lastIndexOf("/")) : "";
|
|
886
|
+
while (dir.length > 0) {
|
|
887
|
+
if (this.#declarationDirs.has(dir)) {
|
|
888
|
+
break;
|
|
889
|
+
}
|
|
890
|
+
this.#declarationDirs.add(dir);
|
|
891
|
+
const nextSlash = dir.lastIndexOf("/");
|
|
892
|
+
dir = nextSlash !== -1 ? dir.slice(0, nextSlash) : "";
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
this.#options = dtsBundleOptions;
|
|
896
|
+
this.#matchExternal = _DeclarationBundler.#buildMatcher(dtsBundleOptions.external);
|
|
897
|
+
this.#matchNoExternal = _DeclarationBundler.#buildMatcher(dtsBundleOptions.noExternal);
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Clears external declaration files and module resolution cache to free memory.
|
|
901
|
+
* Called after all entry points have been bundled.
|
|
902
|
+
*/
|
|
903
|
+
clearExternalFiles() {
|
|
904
|
+
this.#externalDeclarationFiles.clear();
|
|
905
|
+
this.#moduleResolutionCache.clear();
|
|
906
|
+
this.#sourceFileCache.clear();
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
909
|
+
* Convert a source file path to its corresponding declaration file path
|
|
910
|
+
* @param sourcePath - Absolute path to a source file (.ts, .tsx)
|
|
911
|
+
* @returns The corresponding .d.ts path, or undefined if not found
|
|
912
|
+
*/
|
|
913
|
+
#sourceToDeclarationPath(sourcePath) {
|
|
914
|
+
const { outDir, rootDir } = this.#options.compilerOptions;
|
|
915
|
+
const sourceWithoutExt = sourcePath.substring(0, sourcePath.lastIndexOf(".") || sourcePath.length);
|
|
916
|
+
if (rootDir) {
|
|
917
|
+
const dtsPath = posix.normalize(Paths.join(outDir, Paths.relative(rootDir, sourceWithoutExt) + FileExtension.DTS));
|
|
918
|
+
return this.#declarationFiles.has(dtsPath) ? dtsPath : sourcePath;
|
|
919
|
+
}
|
|
920
|
+
let bestMatch;
|
|
921
|
+
let bestRelativeLength = Infinity;
|
|
922
|
+
for (const dtsPath of this.#declarationFiles.keys()) {
|
|
923
|
+
if (!dtsPath.endsWith(FileExtension.DTS)) {
|
|
924
|
+
continue;
|
|
925
|
+
}
|
|
926
|
+
const withoutOutDir = dtsPath.startsWith(outDir + "/") ? dtsPath.slice(outDir.length + 1) : dtsPath;
|
|
927
|
+
const relativeDtsPath = withoutOutDir.slice(0, -FileExtension.DTS.length);
|
|
928
|
+
if ((sourceWithoutExt === relativeDtsPath || sourceWithoutExt.endsWith("/" + relativeDtsPath)) && relativeDtsPath.length < bestRelativeLength) {
|
|
929
|
+
bestRelativeLength = relativeDtsPath.length;
|
|
930
|
+
bestMatch = dtsPath;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
return bestMatch ?? sourcePath;
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Builds an O(1) matcher from a mixed Pattern array by splitting into a Set<string> for
|
|
937
|
+
* exact/sub-path checks and a RegExp[] for regex tests. Called once per bundler instance.
|
|
938
|
+
* @param patterns - The array of string and RegExp patterns to match against module specifiers
|
|
939
|
+
* @returns A function that takes a module specifier and returns true if it matches any of the patterns
|
|
940
|
+
*/
|
|
941
|
+
static #buildMatcher(patterns) {
|
|
942
|
+
const exact = /* @__PURE__ */ new Set();
|
|
943
|
+
const prefixes = [];
|
|
944
|
+
const regexps = [];
|
|
945
|
+
for (const p of patterns) {
|
|
946
|
+
if (typeof p === "string") {
|
|
947
|
+
exact.add(p);
|
|
948
|
+
prefixes.push(p + "/");
|
|
949
|
+
} else {
|
|
950
|
+
regexps.push(p);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
if (exact.size === 0 && regexps.length === 0) {
|
|
954
|
+
return () => false;
|
|
955
|
+
}
|
|
956
|
+
return (id) => {
|
|
957
|
+
if (exact.has(id)) {
|
|
958
|
+
return true;
|
|
959
|
+
}
|
|
960
|
+
for (let i = 0; i < prefixes.length; i++) {
|
|
961
|
+
if (id.startsWith(prefixes[i])) {
|
|
962
|
+
return true;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
for (let i = 0; i < regexps.length; i++) {
|
|
966
|
+
if (regexps[i].test(id)) {
|
|
967
|
+
return true;
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
return false;
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Resolve a module import using TypeScript's resolution algorithm with path mapping support
|
|
975
|
+
* For bundles with resolve enabled, also loads declaration files from node_modules
|
|
976
|
+
* @param importPath - The module specifier to resolve
|
|
977
|
+
* @param containingFile - The file containing the import
|
|
978
|
+
* @returns Resolved file path or undefined
|
|
979
|
+
*/
|
|
980
|
+
#resolveModule(importPath, containingFile) {
|
|
981
|
+
const cacheKey = `${importPath}|${containingFile}`;
|
|
982
|
+
if (this.#moduleResolutionCache.has(cacheKey)) {
|
|
983
|
+
return this.#moduleResolutionCache.get(cacheKey);
|
|
984
|
+
}
|
|
985
|
+
const { resolvedModule } = resolveModuleName(importPath, containingFile, this.#options.compilerOptions, this.#moduleResolutionHost);
|
|
986
|
+
if (resolvedModule === void 0) {
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
let resolvedFileName = resolvedModule.resolvedFileName;
|
|
990
|
+
if (this.#options.compilerOptions.paths && resolvedFileName.match(sourceScriptExtensionExpression)) {
|
|
991
|
+
resolvedFileName = this.#sourceToDeclarationPath(resolvedFileName);
|
|
992
|
+
}
|
|
993
|
+
this.#moduleResolutionCache.set(cacheKey, resolvedFileName);
|
|
994
|
+
return resolvedFileName;
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* Build a dependency graph of all modules starting from entry point
|
|
998
|
+
* @param entryPoint - The entry point file path
|
|
999
|
+
* @returns Map of file paths to module information with bundled specifiers tracked
|
|
1000
|
+
*/
|
|
1001
|
+
#buildModuleGraph(entryPoint) {
|
|
1002
|
+
const modules = /* @__PURE__ */ new Map();
|
|
1003
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1004
|
+
const bundledSpecifiers = /* @__PURE__ */ new Map();
|
|
1005
|
+
const visit = (path) => {
|
|
1006
|
+
path = sys.resolvePath(path);
|
|
1007
|
+
if (visited.has(path)) {
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
visited.add(path);
|
|
1011
|
+
const cached = this.#declarationFiles.get(path) ?? this.#externalDeclarationFiles.get(path);
|
|
1012
|
+
if (cached === void 0) {
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
const { code, typeReferences, fileReferences } = cached;
|
|
1016
|
+
let sourceFile = this.#sourceFileCache.get(path);
|
|
1017
|
+
if (sourceFile === void 0) {
|
|
1018
|
+
sourceFile = createSourceFile(path, code, ScriptTarget.Latest, true);
|
|
1019
|
+
this.#sourceFileCache.set(path, sourceFile);
|
|
1020
|
+
}
|
|
1021
|
+
const identifiers = this.#collectIdentifiers(sourceFile.statements, sourceFile);
|
|
1022
|
+
const module = { path, code, imports: /* @__PURE__ */ new Set(), typeReferences: new Set(typeReferences), fileReferences: new Set(fileReferences), sourceFile, identifiers };
|
|
1023
|
+
const bundledSpecs = /* @__PURE__ */ new Set();
|
|
1024
|
+
for (const statement of sourceFile.statements) {
|
|
1025
|
+
if ((isImportDeclaration2(statement) || isExportDeclaration2(statement)) && statement.moduleSpecifier) {
|
|
1026
|
+
const specifier = statement.moduleSpecifier.text;
|
|
1027
|
+
if (this.#matchExternal(specifier)) {
|
|
1028
|
+
continue;
|
|
1029
|
+
}
|
|
1030
|
+
const resolvedPath = this.#resolveModule(specifier, path);
|
|
1031
|
+
if (resolvedPath?.includes(nodeModules) && !this.#matchNoExternal(specifier)) {
|
|
1032
|
+
continue;
|
|
1033
|
+
}
|
|
1034
|
+
if (resolvedPath && (this.#declarationFiles.has(resolvedPath) || this.#externalDeclarationFiles.has(resolvedPath))) {
|
|
1035
|
+
module.imports.add(resolvedPath);
|
|
1036
|
+
bundledSpecs.add(specifier);
|
|
1037
|
+
visit(resolvedPath);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
modules.set(path, module);
|
|
1042
|
+
bundledSpecifiers.set(path, bundledSpecs);
|
|
1043
|
+
};
|
|
1044
|
+
visit(entryPoint);
|
|
1045
|
+
return { modules, bundledSpecifiers };
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Topological sort of modules to ensure dependencies come before dependents
|
|
1049
|
+
* @param modules - Map of all modules
|
|
1050
|
+
* @param entryPoint - Starting point for sorting
|
|
1051
|
+
* @returns Array of modules in dependency order
|
|
1052
|
+
*/
|
|
1053
|
+
#sortModules(modules, entryPoint) {
|
|
1054
|
+
const sorted = [];
|
|
1055
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1056
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
1057
|
+
const visitStack = [];
|
|
1058
|
+
const visit = (path) => {
|
|
1059
|
+
if (visited.has(path)) {
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
if (visiting.has(path)) {
|
|
1063
|
+
const cyclePath = [...visitStack.slice(visitStack.indexOf(path)), path].map((p) => Paths.relative(this.#options.currentDirectory, p)).join(" -> ");
|
|
1064
|
+
Logger.warn(`Circular dependency detected: ${cyclePath}`);
|
|
1065
|
+
visited.add(path);
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
visiting.add(path);
|
|
1069
|
+
visitStack.push(path);
|
|
1070
|
+
const module = modules.get(path);
|
|
1071
|
+
if (!module) {
|
|
1072
|
+
visiting.delete(path);
|
|
1073
|
+
visitStack.pop();
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
for (const importPath of module.imports) {
|
|
1077
|
+
visit(importPath);
|
|
1078
|
+
}
|
|
1079
|
+
visiting.delete(path);
|
|
1080
|
+
visitStack.pop();
|
|
1081
|
+
visited.add(path);
|
|
1082
|
+
sorted.push(module);
|
|
1083
|
+
};
|
|
1084
|
+
visit(entryPoint);
|
|
1085
|
+
return sorted;
|
|
1086
|
+
}
|
|
1087
|
+
/**
|
|
1088
|
+
* Recursively collect type and value identifiers from AST statements
|
|
1089
|
+
* This is more robust and performant than regex matching
|
|
1090
|
+
* @param statements - AST statements to analyze
|
|
1091
|
+
* @param sourceFile - Optional source file for caching results
|
|
1092
|
+
* @returns Sets of type and value identifiers
|
|
1093
|
+
*/
|
|
1094
|
+
#collectIdentifiers(statements, sourceFile) {
|
|
1095
|
+
let result;
|
|
1096
|
+
if (sourceFile) {
|
|
1097
|
+
result = this.#identifierCache.get(sourceFile);
|
|
1098
|
+
if (result) {
|
|
1099
|
+
return result;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
const types = /* @__PURE__ */ new Set();
|
|
1103
|
+
const values = /* @__PURE__ */ new Set();
|
|
1104
|
+
const collectNestedIdentifiers = (subStatements) => {
|
|
1105
|
+
const { types: subTypes, values: subValues } = this.#collectIdentifiers(subStatements);
|
|
1106
|
+
for (const type2 of subTypes) {
|
|
1107
|
+
types.add(type2);
|
|
1108
|
+
}
|
|
1109
|
+
for (const value of subValues) {
|
|
1110
|
+
values.add(value);
|
|
1111
|
+
}
|
|
1112
|
+
};
|
|
1113
|
+
for (const statement of statements) {
|
|
1114
|
+
if (isImportDeclaration2(statement)) {
|
|
1115
|
+
continue;
|
|
1116
|
+
}
|
|
1117
|
+
if (isInterfaceDeclaration2(statement) || isTypeAliasDeclaration2(statement)) {
|
|
1118
|
+
types.add(statement.name.text);
|
|
1119
|
+
} else if (isEnumDeclaration2(statement) || isFunctionDeclaration2(statement) || isClassDeclaration2(statement)) {
|
|
1120
|
+
if (statement.name) {
|
|
1121
|
+
values.add(statement.name.text);
|
|
1122
|
+
}
|
|
1123
|
+
} else if (isVariableStatement2(statement)) {
|
|
1124
|
+
for (const { name } of statement.declarationList.declarations) {
|
|
1125
|
+
if (isIdentifier2(name)) {
|
|
1126
|
+
values.add(name.text);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
} else if (isModuleDeclaration2(statement)) {
|
|
1130
|
+
if (statement.name && isIdentifier2(statement.name)) {
|
|
1131
|
+
values.add(statement.name.text);
|
|
1132
|
+
}
|
|
1133
|
+
const body = statement.body;
|
|
1134
|
+
if (body && isModuleBlock2(body)) {
|
|
1135
|
+
collectNestedIdentifiers(body.statements);
|
|
1136
|
+
} else if (body && isModuleDeclaration2(body)) {
|
|
1137
|
+
collectNestedIdentifiers([body]);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
result = { types, values };
|
|
1142
|
+
if (sourceFile) {
|
|
1143
|
+
this.#identifierCache.set(sourceFile, result);
|
|
1144
|
+
}
|
|
1145
|
+
return result;
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Remove import/export statements from code, but preserve external imports
|
|
1149
|
+
* Fully AST-based approach using magic-string for efficient code manipulation
|
|
1150
|
+
* @param code - Declaration file content
|
|
1151
|
+
* @param sourceFile - Parsed source file AST (required to avoid re-parsing)
|
|
1152
|
+
* @param identifiers - Pre-computed type and value identifiers (to avoid re-computation)
|
|
1153
|
+
* @param bundledImportPaths - Set of resolved file paths that were bundled (to exclude from external imports)
|
|
1154
|
+
* @param renameMap - Map of renamed identifiers (name:path -> newName)
|
|
1155
|
+
* @param modulePath - Path of current module for looking up renames
|
|
1156
|
+
* @returns Object with processed code, collected external imports, and exported names (separated by type/value)
|
|
1157
|
+
*/
|
|
1158
|
+
#stripImportsExports(code, sourceFile, identifiers, bundledImportPaths, renameMap, modulePath) {
|
|
1159
|
+
const externalImports = [];
|
|
1160
|
+
const typeExports = [];
|
|
1161
|
+
const valueExports = [];
|
|
1162
|
+
const { types: typeIdentifiers, values: valueIdentifiers } = identifiers;
|
|
1163
|
+
const magic = new MagicString2(code);
|
|
1164
|
+
const moduleRenames = /* @__PURE__ */ new Map();
|
|
1165
|
+
const exportsMapper = (name) => moduleRenames.get(name) ?? name;
|
|
1166
|
+
for (const name of typeIdentifiers) {
|
|
1167
|
+
const renamed = renameMap.get(`${name}:${modulePath}`);
|
|
1168
|
+
if (renamed) {
|
|
1169
|
+
moduleRenames.set(name, renamed);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
for (const name of valueIdentifiers) {
|
|
1173
|
+
const renamed = renameMap.get(`${name}:${modulePath}`);
|
|
1174
|
+
if (renamed) {
|
|
1175
|
+
moduleRenames.set(name, renamed);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
const bundledNamespaceAliases = /* @__PURE__ */ new Set();
|
|
1179
|
+
for (const statement of sourceFile.statements) {
|
|
1180
|
+
if (isImportDeclaration2(statement)) {
|
|
1181
|
+
const moduleSpecifier = statement.moduleSpecifier.text;
|
|
1182
|
+
if (this.#matchExternal(moduleSpecifier) || !bundledImportPaths.has(moduleSpecifier)) {
|
|
1183
|
+
const importClause = statement.importClause;
|
|
1184
|
+
const isTypeOnly = importClause?.isTypeOnly === true;
|
|
1185
|
+
const namedBindings = importClause?.namedBindings;
|
|
1186
|
+
if (importClause && !importClause.name && namedBindings && isNamedImports(namedBindings)) {
|
|
1187
|
+
const names = [];
|
|
1188
|
+
for (const element of namedBindings.elements) {
|
|
1189
|
+
const local = element.name.text;
|
|
1190
|
+
const original = element.propertyName?.text;
|
|
1191
|
+
const prefix = element.isTypeOnly ? "type " : "";
|
|
1192
|
+
names.push(original ? `${prefix}${original} as ${local}` : `${prefix}${local}`);
|
|
1193
|
+
}
|
|
1194
|
+
externalImports.push({ kind: "named", specifier: moduleSpecifier, isType: isTypeOnly, names });
|
|
1195
|
+
} else {
|
|
1196
|
+
externalImports.push({ kind: "raw", text: code.substring(statement.pos, statement.end).trim() });
|
|
1197
|
+
}
|
|
1198
|
+
} else if (statement.importClause?.namedBindings && isNamespaceImport(statement.importClause.namedBindings)) {
|
|
1199
|
+
bundledNamespaceAliases.add(statement.importClause.namedBindings.name.text);
|
|
1200
|
+
}
|
|
1201
|
+
magic.remove(statement.pos, statement.end);
|
|
1202
|
+
} else if (isExportDeclaration2(statement)) {
|
|
1203
|
+
if (statement.moduleSpecifier) {
|
|
1204
|
+
magic.remove(statement.pos, statement.end);
|
|
1205
|
+
continue;
|
|
1206
|
+
}
|
|
1207
|
+
if (statement.exportClause && isNamedExports2(statement.exportClause)) {
|
|
1208
|
+
if (statement.exportClause.elements.length > 0) {
|
|
1209
|
+
for (const { name, propertyName } of statement.exportClause.elements) {
|
|
1210
|
+
const localName = propertyName?.text ?? name.text;
|
|
1211
|
+
if (valueIdentifiers.has(localName)) {
|
|
1212
|
+
valueExports.push(localName);
|
|
1213
|
+
} else if (typeIdentifiers.has(localName)) {
|
|
1214
|
+
typeExports.push(localName);
|
|
1215
|
+
} else {
|
|
1216
|
+
valueExports.push(localName);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
magic.remove(statement.pos, statement.end);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
} else if (isExportAssignment(statement)) {
|
|
1223
|
+
magic.remove(statement.pos, statement.end);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
const hasRenames = moduleRenames.size > 0;
|
|
1227
|
+
const hasBundledAliases = bundledNamespaceAliases.size > 0;
|
|
1228
|
+
if (hasRenames || hasBundledAliases) {
|
|
1229
|
+
const visit = (node) => {
|
|
1230
|
+
if (hasBundledAliases && isQualifiedName(node) && isIdentifier2(node.left) && bundledNamespaceAliases.has(node.left.text)) {
|
|
1231
|
+
magic.remove(node.left.getStart(), node.right.getStart());
|
|
1232
|
+
} else if (hasRenames && isIdentifier2(node)) {
|
|
1233
|
+
const renamed = moduleRenames.get(node.text);
|
|
1234
|
+
if (renamed) {
|
|
1235
|
+
magic.overwrite(node.getStart(), node.end, renamed);
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
forEachChild2(node, visit);
|
|
1239
|
+
};
|
|
1240
|
+
for (const statement of sourceFile.statements) {
|
|
1241
|
+
if (!isImportDeclaration2(statement) && !isExportDeclaration2(statement) && !isExportAssignment(statement)) {
|
|
1242
|
+
visit(statement);
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
const finalValueExportsSet = /* @__PURE__ */ new Set();
|
|
1247
|
+
for (const name of valueExports) {
|
|
1248
|
+
finalValueExportsSet.add(exportsMapper(name));
|
|
1249
|
+
}
|
|
1250
|
+
const finalTypeExports = [];
|
|
1251
|
+
for (const type2 of typeExports) {
|
|
1252
|
+
const mapped = exportsMapper(type2);
|
|
1253
|
+
if (!finalValueExportsSet.has(mapped)) {
|
|
1254
|
+
finalTypeExports.push(mapped);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
return { code: magic.toString(), externalImports, typeExports: finalTypeExports, valueExports: Array.from(finalValueExportsSet) };
|
|
1258
|
+
}
|
|
1259
|
+
/**
|
|
1260
|
+
* Combine modules into a single output string
|
|
1261
|
+
* @param sortedModules - Modules in dependency order
|
|
1262
|
+
* @param bundledSpecifiers - Map of module paths to their bundled import specifiers
|
|
1263
|
+
* @returns Object containing combined code, all exported identifiers, and all declarations from bundled modules
|
|
1264
|
+
*/
|
|
1265
|
+
#combineModules(sortedModules, bundledSpecifiers) {
|
|
1266
|
+
const typeReferencesSet = /* @__PURE__ */ new Set();
|
|
1267
|
+
const fileReferencesSet = /* @__PURE__ */ new Set();
|
|
1268
|
+
const allExternalImports = [];
|
|
1269
|
+
const valueExportsSet = /* @__PURE__ */ new Set();
|
|
1270
|
+
const typeExportsSeen = /* @__PURE__ */ new Set();
|
|
1271
|
+
const orderedTypeExports = [];
|
|
1272
|
+
const codeBlocks = [];
|
|
1273
|
+
const allDeclarations = /* @__PURE__ */ new Set();
|
|
1274
|
+
const declarationSources = /* @__PURE__ */ new Map();
|
|
1275
|
+
const renameMap = /* @__PURE__ */ new Map();
|
|
1276
|
+
for (const { path, identifiers: { types, values } } of sortedModules) {
|
|
1277
|
+
for (const name of types) {
|
|
1278
|
+
let set = declarationSources.get(name);
|
|
1279
|
+
if (set === void 0) {
|
|
1280
|
+
declarationSources.set(name, set = /* @__PURE__ */ new Set());
|
|
1281
|
+
}
|
|
1282
|
+
set.add(path);
|
|
1283
|
+
}
|
|
1284
|
+
for (const name of values) {
|
|
1285
|
+
let set = declarationSources.get(name);
|
|
1286
|
+
if (set === void 0) {
|
|
1287
|
+
declarationSources.set(name, set = /* @__PURE__ */ new Set());
|
|
1288
|
+
}
|
|
1289
|
+
set.add(path);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
for (const [name, sourcesSet] of declarationSources) {
|
|
1293
|
+
if (sourcesSet.size > 1) {
|
|
1294
|
+
let suffix = 1;
|
|
1295
|
+
const modulePaths = sourcesSet.values();
|
|
1296
|
+
modulePaths.next();
|
|
1297
|
+
for (const modulePath of modulePaths) {
|
|
1298
|
+
let candidate = `${name}$${suffix}`;
|
|
1299
|
+
while (declarationSources.has(candidate)) {
|
|
1300
|
+
candidate = `${name}$${++suffix}`;
|
|
1301
|
+
}
|
|
1302
|
+
renameMap.set(`${name}:${modulePath}`, candidate);
|
|
1303
|
+
suffix++;
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
for (const { path, typeReferences, fileReferences, sourceFile, code, identifiers: { types, values } } of sortedModules) {
|
|
1308
|
+
for (const r of typeReferences) {
|
|
1309
|
+
typeReferencesSet.add(r);
|
|
1310
|
+
}
|
|
1311
|
+
for (const r of fileReferences) {
|
|
1312
|
+
fileReferencesSet.add(r);
|
|
1313
|
+
}
|
|
1314
|
+
const bundledForThisModule = bundledSpecifiers.get(path) ?? emptySet;
|
|
1315
|
+
const { code: strippedCode, externalImports, typeExports, valueExports } = this.#stripImportsExports(code, sourceFile, { types, values }, bundledForThisModule, renameMap, path);
|
|
1316
|
+
for (const imp of externalImports) {
|
|
1317
|
+
allExternalImports.push(imp);
|
|
1318
|
+
}
|
|
1319
|
+
if (!path.includes(nodeModules)) {
|
|
1320
|
+
for (const exp of valueExports) {
|
|
1321
|
+
valueExportsSet.add(exp);
|
|
1322
|
+
}
|
|
1323
|
+
for (const exp of typeExports) {
|
|
1324
|
+
if (!typeExportsSeen.has(exp)) {
|
|
1325
|
+
typeExportsSeen.add(exp);
|
|
1326
|
+
orderedTypeExports.push(exp);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
for (const name of types) {
|
|
1330
|
+
allDeclarations.add(name);
|
|
1331
|
+
}
|
|
1332
|
+
for (const name of values) {
|
|
1333
|
+
allDeclarations.add(name);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
if (strippedCode.trim().length > 0) {
|
|
1337
|
+
codeBlocks.push(strippedCode.trim());
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
const mergedExternalImports = mergeImports(allExternalImports);
|
|
1341
|
+
for (const imp of mergedExternalImports) {
|
|
1342
|
+
if (imp.includes('"node:') || imp.includes("'node:")) {
|
|
1343
|
+
typeReferencesSet.add("node");
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
const finalValueExports = [...valueExportsSet];
|
|
1347
|
+
const finalTypeExports = [];
|
|
1348
|
+
for (const typeExport of orderedTypeExports) {
|
|
1349
|
+
if (!valueExportsSet.has(typeExport)) {
|
|
1350
|
+
finalTypeExports.push(typeExport);
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
const outputParts = [];
|
|
1354
|
+
if (fileReferencesSet.size > 0) {
|
|
1355
|
+
for (const ref of fileReferencesSet) {
|
|
1356
|
+
outputParts.push(`/// <reference path="${ref}" />`);
|
|
1357
|
+
}
|
|
1358
|
+
outputParts.push("");
|
|
1359
|
+
}
|
|
1360
|
+
if (typeReferencesSet.size > 0) {
|
|
1361
|
+
for (const ref of typeReferencesSet) {
|
|
1362
|
+
outputParts.push(`/// <reference types="${ref}" />`);
|
|
1363
|
+
}
|
|
1364
|
+
outputParts.push("");
|
|
1365
|
+
}
|
|
1366
|
+
if (mergedExternalImports.length > 0) {
|
|
1367
|
+
for (const imp of mergedExternalImports) {
|
|
1368
|
+
outputParts.push(imp);
|
|
1369
|
+
}
|
|
1370
|
+
outputParts.push("");
|
|
1371
|
+
}
|
|
1372
|
+
outputParts.push(codeBlocks.join(newLine + newLine));
|
|
1373
|
+
if (finalTypeExports.length > 0 || finalValueExports.length > 0) {
|
|
1374
|
+
outputParts.push("");
|
|
1375
|
+
if (finalValueExports.length > 0) {
|
|
1376
|
+
outputParts.push(`export { ${finalValueExports.sort().join(", ")} };`);
|
|
1377
|
+
}
|
|
1378
|
+
if (finalTypeExports.length > 0) {
|
|
1379
|
+
outputParts.push(`export type { ${finalTypeExports.sort().join(", ")} };`);
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
return { code: outputParts.join(newLine), exports: [...finalTypeExports, ...finalValueExports], allDeclarations };
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Main bundling orchestration method
|
|
1386
|
+
* @param entryPoint - The entry point file path
|
|
1387
|
+
* @returns The bundled declaration file content
|
|
1388
|
+
*/
|
|
1389
|
+
bundle(entryPoint) {
|
|
1390
|
+
const dtsEntryPoint = this.#resolveEntryPoint(entryPoint, this.#options.compilerOptions);
|
|
1391
|
+
if (dtsEntryPoint === void 0) {
|
|
1392
|
+
return "";
|
|
1393
|
+
}
|
|
1394
|
+
const { modules, bundledSpecifiers } = this.#buildModuleGraph(dtsEntryPoint);
|
|
1395
|
+
const { code } = this.#combineModules(this.#sortModules(modules, dtsEntryPoint), bundledSpecifiers);
|
|
1396
|
+
return DeclarationProcessor.postProcess(createSourceFile(dtsEntryPoint, code, ScriptTarget.Latest, true));
|
|
1397
|
+
}
|
|
1398
|
+
/**
|
|
1399
|
+
* Resolve entry point from source path to declaration path
|
|
1400
|
+
* @param entryPoint - The entry point file path
|
|
1401
|
+
* @param compilerOptions - Minimal compiler options with outDir and rootDir
|
|
1402
|
+
* @returns Resolved declaration entry point path
|
|
1403
|
+
*/
|
|
1404
|
+
#resolveEntryPoint(entryPoint, compilerOptions) {
|
|
1405
|
+
const dtsEntryPoint = sys.resolvePath(entryPoint.endsWith(FileExtension.DTS) ? entryPoint : this.#sourceToDeclarationPath(entryPoint));
|
|
1406
|
+
if (this.#declarationFiles.has(dtsEntryPoint)) {
|
|
1407
|
+
return dtsEntryPoint;
|
|
1408
|
+
}
|
|
1409
|
+
if (!entryPoint.endsWith(FileExtension.DTS)) {
|
|
1410
|
+
return void 0;
|
|
1411
|
+
}
|
|
1412
|
+
const availableFiles = Array.from(this.#declarationFiles.keys());
|
|
1413
|
+
const entryPointFilename = basename(entryPoint);
|
|
1414
|
+
const similarFiles = availableFiles.filter((filePath) => filePath.includes(entryPointFilename));
|
|
1415
|
+
throw new BundleError(
|
|
1416
|
+
`Entry point declaration file not found: ${dtsEntryPoint || "unknown"}
|
|
1417
|
+
Original entry: ${entryPoint}
|
|
1418
|
+
Compiler options: outDir=${compilerOptions.outDir || "dist"}, rootDir=${compilerOptions.rootDir || "not set"}
|
|
1419
|
+
Similar files found:
|
|
1420
|
+
${similarFiles.map((f) => ` - ${f}`).join("\n")}
|
|
1421
|
+
Total available files: ${availableFiles.length}`
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
};
|
|
1425
|
+
async function bundleDeclarations(options) {
|
|
1426
|
+
await mkdir2(options.compilerOptions.outDir, defaultDirOptions);
|
|
1427
|
+
const dtsBundler = new DeclarationBundler(options);
|
|
1428
|
+
const bundleTasks = [];
|
|
1429
|
+
const bundleEntryPoint = (entryName, entryPoint) => {
|
|
1430
|
+
const content = dtsBundler.bundle(entryPoint);
|
|
1431
|
+
if (content.length > 0) {
|
|
1432
|
+
const outPath = Paths.join(options.compilerOptions.outDir, `${entryName}${FileExtension.DTS}`);
|
|
1433
|
+
bundleTasks.push(writeFile2(outPath, content, Encoding.utf8).then(() => ({ path: Paths.relative(options.currentDirectory, outPath), size: content.length })));
|
|
1434
|
+
}
|
|
1435
|
+
};
|
|
1436
|
+
if (options.parallelTranspile) {
|
|
1437
|
+
const queueImmediateTask = (resolve3) => void setImmediate(resolve3);
|
|
1438
|
+
for (const [entryName, entryPoint] of Object.entries(options.entryPoints)) {
|
|
1439
|
+
await new Promise(queueImmediateTask);
|
|
1440
|
+
bundleEntryPoint(entryName, entryPoint);
|
|
1441
|
+
}
|
|
1442
|
+
} else {
|
|
1443
|
+
for (const [entryName, entryPoint] of Object.entries(options.entryPoints)) {
|
|
1444
|
+
bundleEntryPoint(entryName, entryPoint);
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
const results = await Promise.all(bundleTasks);
|
|
1448
|
+
dtsBundler.clearExternalFiles();
|
|
1449
|
+
return results;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
// src/plugins/output.ts
|
|
1453
|
+
import { chmod, open } from "node:fs/promises";
|
|
1454
|
+
import { extname } from "node:path";
|
|
1455
|
+
async function setShebangPermissions(filePath) {
|
|
1456
|
+
const handle = await open(filePath, "r");
|
|
1457
|
+
try {
|
|
1458
|
+
const buf = Buffer.alloc(2);
|
|
1459
|
+
await handle.read(buf, 0, 2, 0);
|
|
1460
|
+
if (buf[0] === 35 && buf[1] === 33) {
|
|
1461
|
+
await chmod(filePath, 493);
|
|
1462
|
+
}
|
|
1463
|
+
} finally {
|
|
1464
|
+
await handle.close();
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
var outputPlugin = () => {
|
|
1468
|
+
return {
|
|
1469
|
+
name: "esbuild:output-plugin",
|
|
1470
|
+
/**
|
|
1471
|
+
* Checks JS entry points for shebangs and sets executable permissions.
|
|
1472
|
+
* @param build The esbuild plugin build object.
|
|
1473
|
+
*/
|
|
1474
|
+
setup(build) {
|
|
1475
|
+
build.onEnd(async ({ metafile }) => {
|
|
1476
|
+
if (!metafile) {
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
const tasks = [];
|
|
1480
|
+
for (const [outputPath, { entryPoint }] of Object.entries(metafile.outputs)) {
|
|
1481
|
+
if (entryPoint && extname(outputPath) === FileExtension.JS) {
|
|
1482
|
+
tasks.push(setShebangPermissions(outputPath));
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
if (tasks.length > 0) {
|
|
1486
|
+
await Promise.all(tasks);
|
|
1487
|
+
}
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
};
|
|
1491
|
+
};
|
|
1492
|
+
|
|
1493
|
+
// src/plugins/external-modules.ts
|
|
1494
|
+
function packageName(id) {
|
|
1495
|
+
if (id.charCodeAt(0) === 64) {
|
|
1496
|
+
const first = id.indexOf("/");
|
|
1497
|
+
if (first === -1) {
|
|
1498
|
+
return id;
|
|
1499
|
+
}
|
|
1500
|
+
const second = id.indexOf("/", first + 1);
|
|
1501
|
+
return second === -1 ? id : id.slice(0, second);
|
|
1502
|
+
}
|
|
1503
|
+
const slash = id.indexOf("/");
|
|
1504
|
+
return slash === -1 ? id : id.slice(0, slash);
|
|
1505
|
+
}
|
|
1506
|
+
function buildMatcher(patterns) {
|
|
1507
|
+
const exact = /* @__PURE__ */ new Set();
|
|
1508
|
+
const regexps = [];
|
|
1509
|
+
for (const p of patterns) {
|
|
1510
|
+
if (typeof p === "string") {
|
|
1511
|
+
exact.add(p);
|
|
1512
|
+
} else {
|
|
1513
|
+
regexps.push(p);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
if (exact.size === 0 && regexps.length === 0) {
|
|
1517
|
+
return () => false;
|
|
1518
|
+
}
|
|
1519
|
+
return (id) => {
|
|
1520
|
+
if (exact.has(id)) {
|
|
1521
|
+
return true;
|
|
1522
|
+
}
|
|
1523
|
+
const pkg = packageName(id);
|
|
1524
|
+
if (pkg !== id && exact.has(pkg)) {
|
|
1525
|
+
return true;
|
|
1526
|
+
}
|
|
1527
|
+
return regexps.length > 0 && regexps.some((r) => r.test(id));
|
|
1528
|
+
};
|
|
1529
|
+
}
|
|
1530
|
+
var externalModulesPlugin = ({ dependencies = [], noExternal = [] }) => {
|
|
1531
|
+
return {
|
|
1532
|
+
name: "esbuild:external-modules",
|
|
1533
|
+
/**
|
|
1534
|
+
* Configure the plugin to handle external modules
|
|
1535
|
+
* @param build The esbuild build instance
|
|
1536
|
+
*/
|
|
1537
|
+
setup(build) {
|
|
1538
|
+
const external = true;
|
|
1539
|
+
const matchNoExternal = buildMatcher(noExternal);
|
|
1540
|
+
const matchDependencies = buildMatcher(dependencies);
|
|
1541
|
+
build.onResolve({ filter: /.*/ }, ({ path }) => {
|
|
1542
|
+
switch (true) {
|
|
1543
|
+
case matchNoExternal(path):
|
|
1544
|
+
return;
|
|
1545
|
+
case matchDependencies(path):
|
|
1546
|
+
return { external };
|
|
1547
|
+
case !Paths.isPath(path):
|
|
1548
|
+
return { path, external };
|
|
1549
|
+
default:
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1554
|
+
};
|
|
1555
|
+
};
|
|
1556
|
+
|
|
1557
|
+
// src/plugins/resolve-plugin.ts
|
|
1558
|
+
import { resolve } from "node:path";
|
|
1559
|
+
function isPlugin(value) {
|
|
1560
|
+
if (typeof value !== "object" || value === null) {
|
|
1561
|
+
return false;
|
|
1562
|
+
}
|
|
1563
|
+
return "name" in value && typeof value.name === "string" && "setup" in value && typeof value.setup === "function";
|
|
1564
|
+
}
|
|
1565
|
+
function isFactory(value) {
|
|
1566
|
+
return typeof value === "function";
|
|
1567
|
+
}
|
|
1568
|
+
async function resolveReference(reference, projectDir) {
|
|
1569
|
+
const [specifier, options] = typeof reference === "string" ? [reference, void 0] : reference;
|
|
1570
|
+
const resolved = Paths.isPath(specifier) ? resolve(projectDir, specifier) : specifier;
|
|
1571
|
+
let module;
|
|
1572
|
+
try {
|
|
1573
|
+
module = await import(resolved);
|
|
1574
|
+
} catch (error) {
|
|
1575
|
+
throw new ConfigurationError(`Failed to load plugin "${specifier}": ${error instanceof Error ? error.message : String(error)}`);
|
|
1576
|
+
}
|
|
1577
|
+
const defaultExport = module["default"];
|
|
1578
|
+
if (defaultExport === void 0) {
|
|
1579
|
+
throw new ConfigurationError(`Plugin "${specifier}" has no default export. The module must export a plugin factory function or Plugin object as its default export.`);
|
|
1580
|
+
}
|
|
1581
|
+
if (isFactory(defaultExport)) {
|
|
1582
|
+
const result = defaultExport(options);
|
|
1583
|
+
if (!isPlugin(result)) {
|
|
1584
|
+
throw new ConfigurationError(`Plugin "${specifier}" factory did not return a valid esbuild Plugin (expected { name: string, setup: function }).`);
|
|
1585
|
+
}
|
|
1586
|
+
return result;
|
|
1587
|
+
}
|
|
1588
|
+
if (isPlugin(defaultExport)) {
|
|
1589
|
+
if (options !== void 0) {
|
|
1590
|
+
Logger.warn(`Plugin "${specifier}" is a Plugin object, not a factory function. The provided options will be ignored.`);
|
|
1591
|
+
}
|
|
1592
|
+
return defaultExport;
|
|
1593
|
+
}
|
|
1594
|
+
throw new ConfigurationError(`Plugin "${specifier}" default export is not a function or valid esbuild Plugin object.`);
|
|
1595
|
+
}
|
|
1596
|
+
async function resolvePlugins(plugins, projectDir) {
|
|
1597
|
+
const resolved = [];
|
|
1598
|
+
for (const entry of plugins) {
|
|
1599
|
+
if (isPlugin(entry)) {
|
|
1600
|
+
resolved.push(entry);
|
|
1601
|
+
} else {
|
|
1602
|
+
resolved.push(await resolveReference(entry, projectDir));
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
return resolved;
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
// src/plugins/iife.ts
|
|
1609
|
+
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
1610
|
+
import { basename as basename2, dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
|
|
1611
|
+
var namespace = "iife";
|
|
1612
|
+
var fileExtensionRegex = /\.[^.]+$/;
|
|
1613
|
+
var textDecoder = new TextDecoder();
|
|
1614
|
+
function iifePlugin(options) {
|
|
1615
|
+
const files = [];
|
|
1616
|
+
return {
|
|
1617
|
+
files,
|
|
1618
|
+
plugin: {
|
|
1619
|
+
name: "esbuild:iife",
|
|
1620
|
+
/**
|
|
1621
|
+
* Configures the esbuild build instance to produce IIFE output.
|
|
1622
|
+
* @param build The esbuild plugin build object.
|
|
1623
|
+
*/
|
|
1624
|
+
setup(build) {
|
|
1625
|
+
const outdir = build.initialOptions.outdir;
|
|
1626
|
+
if (!outdir) {
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
build.initialOptions.write = false;
|
|
1630
|
+
const sourcemap = build.initialOptions.sourcemap;
|
|
1631
|
+
const minify = build.initialOptions.minify;
|
|
1632
|
+
const entryPointNames = extractEntryNames(build.initialOptions.entryPoints);
|
|
1633
|
+
build.onEnd(async ({ outputFiles }) => {
|
|
1634
|
+
if (!outputFiles || outputFiles.length === 0 || entryPointNames.length === 0) {
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
files.push(...await buildIife(outputFiles, entryPointNames, outdir, options?.globalName, sourcemap, minify));
|
|
1638
|
+
});
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
};
|
|
1642
|
+
}
|
|
1643
|
+
function extractEntryNames(entryPoints) {
|
|
1644
|
+
if (!entryPoints) {
|
|
1645
|
+
return [];
|
|
1646
|
+
}
|
|
1647
|
+
if (Array.isArray(entryPoints)) {
|
|
1648
|
+
const names = [];
|
|
1649
|
+
for (const entry of entryPoints) {
|
|
1650
|
+
if (typeof entry === "string") {
|
|
1651
|
+
names.push(basename2(entry).replace(fileExtensionRegex, ""));
|
|
1652
|
+
} else {
|
|
1653
|
+
names.push(entry.out ?? basename2(entry.in).replace(fileExtensionRegex, ""));
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
return names;
|
|
1657
|
+
}
|
|
1658
|
+
return Object.keys(entryPoints);
|
|
1659
|
+
}
|
|
1660
|
+
function wrapAsIife(text, globalName) {
|
|
1661
|
+
const exportStart = text.lastIndexOf("export");
|
|
1662
|
+
if (exportStart === -1) {
|
|
1663
|
+
return text;
|
|
1664
|
+
}
|
|
1665
|
+
const openBrace = text.indexOf("{", exportStart + 6);
|
|
1666
|
+
const closeBrace = text.indexOf("}", openBrace + 1);
|
|
1667
|
+
if (openBrace === -1 || closeBrace === -1 || text.slice(exportStart + 6, openBrace).trim() !== "") {
|
|
1668
|
+
return text;
|
|
1669
|
+
}
|
|
1670
|
+
let exportEnd = closeBrace + 1;
|
|
1671
|
+
while (exportEnd < text.length && /[ \t]/.test(text[exportEnd] ?? "")) {
|
|
1672
|
+
exportEnd += 1;
|
|
1673
|
+
}
|
|
1674
|
+
if (text[exportEnd] === ";") {
|
|
1675
|
+
exportEnd += 1;
|
|
1676
|
+
}
|
|
1677
|
+
const properties = [];
|
|
1678
|
+
for (const rawMember of text.slice(openBrace + 1, closeBrace).split(",")) {
|
|
1679
|
+
const member = rawMember.trim();
|
|
1680
|
+
if (!member) {
|
|
1681
|
+
continue;
|
|
1682
|
+
}
|
|
1683
|
+
const asIndex = member.indexOf(" as ");
|
|
1684
|
+
if (asIndex <= 0) {
|
|
1685
|
+
properties.push(member);
|
|
1686
|
+
continue;
|
|
1687
|
+
}
|
|
1688
|
+
const localName = member.slice(0, asIndex).trim();
|
|
1689
|
+
const exportName = member.slice(asIndex + 4).trim();
|
|
1690
|
+
properties.push(localName && exportName ? `${exportName}: ${localName}` : member);
|
|
1691
|
+
}
|
|
1692
|
+
if (properties.length === 0) {
|
|
1693
|
+
return text;
|
|
1694
|
+
}
|
|
1695
|
+
const exportedObject = properties.join(", ");
|
|
1696
|
+
const assignment = globalName ? `globalThis.${globalName} = { ${exportedObject} };` : `Object.assign(globalThis, { ${exportedObject} });`;
|
|
1697
|
+
return `(() => {
|
|
1698
|
+
${text.slice(0, exportStart)}
|
|
1699
|
+
${assignment}
|
|
1700
|
+
})();${text.slice(exportEnd)}`;
|
|
1701
|
+
}
|
|
1702
|
+
async function buildIife(primaryOutputs, entryPointNames, outdir, globalName, sourcemap, minify) {
|
|
1703
|
+
const { build: esbuild } = await import("esbuild");
|
|
1704
|
+
const fileContents = /* @__PURE__ */ new Map();
|
|
1705
|
+
const primaryWrites = [];
|
|
1706
|
+
const ensuredDirs = /* @__PURE__ */ new Map();
|
|
1707
|
+
for (const file of primaryOutputs) {
|
|
1708
|
+
const absolute = resolve2(file.path);
|
|
1709
|
+
if (absolute.endsWith(FileExtension.JS)) {
|
|
1710
|
+
fileContents.set(absolute, file.text);
|
|
1711
|
+
}
|
|
1712
|
+
const dir = dirname2(absolute);
|
|
1713
|
+
let dirReady = ensuredDirs.get(dir);
|
|
1714
|
+
if (dirReady === void 0) {
|
|
1715
|
+
dirReady = mkdir3(dir, { recursive: true });
|
|
1716
|
+
ensuredDirs.set(dir, dirReady);
|
|
1717
|
+
}
|
|
1718
|
+
primaryWrites.push(dirReady.then(() => writeFile3(absolute, file.contents)));
|
|
1719
|
+
}
|
|
1720
|
+
const validEntries = [];
|
|
1721
|
+
for (const name of entryPointNames) {
|
|
1722
|
+
const path = Paths.absolute(outdir, name + FileExtension.JS);
|
|
1723
|
+
if (fileContents.has(path)) {
|
|
1724
|
+
validEntries.push({ name, path });
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
if (validEntries.length === 0) {
|
|
1728
|
+
await Promise.all(primaryWrites);
|
|
1729
|
+
return [];
|
|
1730
|
+
}
|
|
1731
|
+
const sourcemapValue = sourcemap !== void 0 && sourcemap !== false ? "external" : false;
|
|
1732
|
+
const plugins = [virtualLoaderPlugin(fileContents)];
|
|
1733
|
+
const iifeOutdir = join2(outdir, namespace);
|
|
1734
|
+
await mkdir3(iifeOutdir, { recursive: true });
|
|
1735
|
+
const results = await Promise.all(validEntries.map(({ name, path }) => {
|
|
1736
|
+
return esbuild({
|
|
1737
|
+
entryPoints: { [name]: path },
|
|
1738
|
+
bundle: true,
|
|
1739
|
+
format,
|
|
1740
|
+
splitting: false,
|
|
1741
|
+
outdir: iifeOutdir,
|
|
1742
|
+
sourcemap: sourcemapValue,
|
|
1743
|
+
minify,
|
|
1744
|
+
write: false,
|
|
1745
|
+
logLevel: "warning",
|
|
1746
|
+
plugins
|
|
1747
|
+
});
|
|
1748
|
+
}));
|
|
1749
|
+
const written = [];
|
|
1750
|
+
const writes = [];
|
|
1751
|
+
const cwd = process.cwd();
|
|
1752
|
+
for (const { outputFiles } of results) {
|
|
1753
|
+
const outputFilePaths = new Set(outputFiles.map(({ path }) => path));
|
|
1754
|
+
for (const { path, contents } of outputFiles) {
|
|
1755
|
+
let text, size = contents.byteLength;
|
|
1756
|
+
if (path.endsWith(FileExtension.JS)) {
|
|
1757
|
+
text = wrapAsIife(textDecoder.decode(contents), globalName);
|
|
1758
|
+
if (outputFilePaths.has(`${path}.map`)) {
|
|
1759
|
+
text += `
|
|
1760
|
+
//# sourceMappingURL=${basename2(path)}.map`;
|
|
1761
|
+
size = Buffer.byteLength(text);
|
|
1762
|
+
}
|
|
1763
|
+
} else {
|
|
1764
|
+
text = contents;
|
|
1765
|
+
}
|
|
1766
|
+
writes.push(writeFile3(path, text));
|
|
1767
|
+
written.push({ path: Paths.relative(cwd, path), size });
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
await Promise.all([...writes, ...primaryWrites]);
|
|
1771
|
+
return written;
|
|
1772
|
+
}
|
|
1773
|
+
function virtualLoaderPlugin(fileContents) {
|
|
1774
|
+
return {
|
|
1775
|
+
name: "iife:virtual-loader",
|
|
1776
|
+
/**
|
|
1777
|
+
* Registers onResolve and onLoad hooks for virtual file loading
|
|
1778
|
+
* @param build The esbuild build instance
|
|
1779
|
+
*/
|
|
1780
|
+
setup(build) {
|
|
1781
|
+
build.onResolve({ filter: /.*/ }, (args) => {
|
|
1782
|
+
if (args.kind === "entry-point") {
|
|
1783
|
+
return { path: args.path, namespace };
|
|
1784
|
+
}
|
|
1785
|
+
if (!args.path.startsWith(".") && !args.path.startsWith("/")) {
|
|
1786
|
+
return { external: true };
|
|
1787
|
+
}
|
|
1788
|
+
const resolved = resolve2(args.resolveDir, args.path);
|
|
1789
|
+
return fileContents.has(resolved) ? { path: resolved, namespace } : { external: true };
|
|
1790
|
+
});
|
|
1791
|
+
build.onLoad({ filter: /.*/, namespace }, (args) => {
|
|
1792
|
+
const contents = fileContents.get(args.path);
|
|
1793
|
+
return contents === void 0 ? null : { contents, loader: "js", resolveDir: dirname2(args.path) };
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1796
|
+
};
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
// src/process-manager.ts
|
|
1800
|
+
var ProcessEvent = {
|
|
1801
|
+
exit: "exit",
|
|
1802
|
+
sigint: "SIGINT",
|
|
1803
|
+
uncaughtException: "uncaughtException"
|
|
1804
|
+
};
|
|
1805
|
+
var ProcessManager = class {
|
|
1806
|
+
#hasHandledExit = false;
|
|
1807
|
+
#closeableClasses = [];
|
|
1808
|
+
constructor() {
|
|
1809
|
+
process.addListener(ProcessEvent.exit, this.#handleExit);
|
|
1810
|
+
process.addListener(ProcessEvent.sigint, this.#consoleExit);
|
|
1811
|
+
process.addListener(ProcessEvent.uncaughtException, this.#handleUncaughtException);
|
|
1812
|
+
}
|
|
1813
|
+
/**
|
|
1814
|
+
* Adds a closeable class to be closed on exit.
|
|
1815
|
+
* @param closeable The closeable class to add.
|
|
1816
|
+
*/
|
|
1817
|
+
addCloseable(closeable) {
|
|
1818
|
+
this.#closeableClasses.push(closeable);
|
|
1819
|
+
}
|
|
1820
|
+
/** Closes the process manager and removes all listeners */
|
|
1821
|
+
close() {
|
|
1822
|
+
this.#closeableClasses.length = 0;
|
|
1823
|
+
process.removeListener(ProcessEvent.exit, this.#handleExit);
|
|
1824
|
+
process.removeListener(ProcessEvent.sigint, this.#consoleExit);
|
|
1825
|
+
process.removeListener(ProcessEvent.uncaughtException, this.#handleUncaughtException);
|
|
1826
|
+
}
|
|
1827
|
+
/** Handles normal process exit */
|
|
1828
|
+
#handleExit = () => {
|
|
1829
|
+
if (this.#hasHandledExit) {
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
for (const closeable of this.#closeableClasses) {
|
|
1833
|
+
closeable.close();
|
|
1834
|
+
}
|
|
1835
|
+
this.close();
|
|
1836
|
+
};
|
|
1837
|
+
/** Handles SIGINT (ctrl+c) */
|
|
1838
|
+
#consoleExit = () => {
|
|
1839
|
+
Logger.warn("\nProcess terminated by user");
|
|
1840
|
+
this.#hasHandledExit = true;
|
|
1841
|
+
for (const closeable of this.#closeableClasses) {
|
|
1842
|
+
closeable.close();
|
|
1843
|
+
}
|
|
1844
|
+
this.close();
|
|
1845
|
+
process.exit(130);
|
|
1846
|
+
};
|
|
1847
|
+
/**
|
|
1848
|
+
* Handles uncaught exceptions and exits the process.
|
|
1849
|
+
* @param e The error that was uncaught.
|
|
1850
|
+
*/
|
|
1851
|
+
#handleUncaughtException = (e) => {
|
|
1852
|
+
Logger.error("Uncaught Exception...", e.stack);
|
|
1853
|
+
process.exit(99);
|
|
1854
|
+
};
|
|
1855
|
+
};
|
|
1856
|
+
var processManager = new ProcessManager();
|
|
1857
|
+
|
|
1858
|
+
// src/decorators/close-on-exit.ts
|
|
1859
|
+
function closeOnExit(value, _context) {
|
|
1860
|
+
return class extends value {
|
|
1861
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1862
|
+
constructor(...args) {
|
|
1863
|
+
super(...args);
|
|
1864
|
+
processManager.addCloseable(this);
|
|
1865
|
+
}
|
|
1866
|
+
};
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
// src/decorators/performance-logger.ts
|
|
1870
|
+
import { PerformanceObserver, performance } from "perf_hooks";
|
|
1871
|
+
var type = "measure";
|
|
1872
|
+
var pendingSteps = [];
|
|
1873
|
+
var _PerformanceLogger_decorators, _init;
|
|
1874
|
+
_PerformanceLogger_decorators = [closeOnExit];
|
|
1875
|
+
var _PerformanceLogger = class _PerformanceLogger {
|
|
1876
|
+
#performanceObserver;
|
|
1877
|
+
constructor() {
|
|
1878
|
+
this.#performanceObserver = new PerformanceObserver((list) => {
|
|
1879
|
+
for (const { name, duration, detail: { message, result = [], steps } } of list.getEntriesByType(type).reverse()) {
|
|
1880
|
+
if (message === "Build") {
|
|
1881
|
+
Logger.separator();
|
|
1882
|
+
if (process.exitCode) {
|
|
1883
|
+
Logger.error(`\u2717 Build failed in ${TextFormat.cyan(_PerformanceLogger.#formatDuration(duration))}
|
|
1884
|
+
`);
|
|
1885
|
+
} else {
|
|
1886
|
+
Logger.step(`Completed in ${TextFormat.cyan(_PerformanceLogger.#formatDuration(duration))}
|
|
1887
|
+
`);
|
|
1888
|
+
}
|
|
1889
|
+
} else {
|
|
1890
|
+
Logger.step(`${message} ${TextFormat.dim(`(${_PerformanceLogger.#formatDuration(duration)})`)}`);
|
|
1891
|
+
if (steps?.length) {
|
|
1892
|
+
Logger.subSteps(steps);
|
|
1893
|
+
}
|
|
1894
|
+
if (result.length > 0) {
|
|
1895
|
+
Logger.success("", ...result);
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
performance.clearResourceTimings(name);
|
|
1899
|
+
}
|
|
1900
|
+
});
|
|
1901
|
+
this.#performanceObserver.observe({ type });
|
|
1902
|
+
}
|
|
1903
|
+
/**
|
|
1904
|
+
* Measures the performance of a method and logs the result.
|
|
1905
|
+
* @param message - The message to log with the performance measurement
|
|
1906
|
+
* @param logResult - Whether to include the method return value in the log output
|
|
1907
|
+
* @returns A Stage 3 method decorator that measures execution time of the decorated method
|
|
1908
|
+
*/
|
|
1909
|
+
measure(message, logResult = false) {
|
|
1910
|
+
const _measure = (propertyKey, result, options) => {
|
|
1911
|
+
if (logResult) {
|
|
1912
|
+
options.detail.result = result;
|
|
1913
|
+
}
|
|
1914
|
+
if (pendingSteps.length > 0) {
|
|
1915
|
+
options.detail.steps = pendingSteps.splice(0);
|
|
1916
|
+
}
|
|
1917
|
+
({ startTime: options.end } = performance.mark(propertyKey));
|
|
1918
|
+
performance.measure(propertyKey, options);
|
|
1919
|
+
return result;
|
|
1920
|
+
};
|
|
1921
|
+
return function(targetMethod, context) {
|
|
1922
|
+
const propertyKey = String(context.name);
|
|
1923
|
+
return function(...args) {
|
|
1924
|
+
const options = { start: performance.mark(propertyKey).startTime, detail: { message } };
|
|
1925
|
+
const result = targetMethod.apply(this, args);
|
|
1926
|
+
return result instanceof Promise ? result.then((r) => _measure(propertyKey, r, options)) : _measure(propertyKey, result, options);
|
|
1927
|
+
};
|
|
1928
|
+
};
|
|
1929
|
+
}
|
|
1930
|
+
/**
|
|
1931
|
+
* Closes the performance logger.
|
|
1932
|
+
*/
|
|
1933
|
+
close() {
|
|
1934
|
+
this.#performanceObserver.disconnect();
|
|
1935
|
+
}
|
|
1936
|
+
/**
|
|
1937
|
+
* Formats the duration into a human-readable string.
|
|
1938
|
+
* @param duration - The duration to format.
|
|
1939
|
+
* @returns The formatted duration string.
|
|
1940
|
+
*/
|
|
1941
|
+
static #formatDuration(duration) {
|
|
1942
|
+
const minutes = ~~(duration / 6e4) % 60;
|
|
1943
|
+
const seconds = ~~(duration / 1e3) % 60;
|
|
1944
|
+
const ms = ~~duration % 1e3;
|
|
1945
|
+
if (minutes > 0) {
|
|
1946
|
+
return `${minutes}m${seconds}s${ms}ms`;
|
|
1947
|
+
}
|
|
1948
|
+
if (seconds > 0) {
|
|
1949
|
+
return `${seconds}s${ms}ms`;
|
|
1950
|
+
}
|
|
1951
|
+
return `${ms}ms`;
|
|
1952
|
+
}
|
|
1953
|
+
};
|
|
1954
|
+
_init = __decoratorStart(null);
|
|
1955
|
+
_PerformanceLogger = __decorateElement(_init, 0, "PerformanceLogger", _PerformanceLogger_decorators, _PerformanceLogger);
|
|
1956
|
+
__runInitializers(_init, 1, _PerformanceLogger);
|
|
1957
|
+
var PerformanceLogger = _PerformanceLogger;
|
|
1958
|
+
var measure = new PerformanceLogger().measure;
|
|
1959
|
+
|
|
1960
|
+
// src/decorators/debounce.ts
|
|
1961
|
+
var _DebounceManager_decorators, _init2;
|
|
1962
|
+
_DebounceManager_decorators = [closeOnExit];
|
|
1963
|
+
var _DebounceManager = class _DebounceManager {
|
|
1964
|
+
static #timers = /* @__PURE__ */ new Set();
|
|
1965
|
+
/**
|
|
1966
|
+
* Creates a debounced version of a function.
|
|
1967
|
+
* @param func - The function to debounce.
|
|
1968
|
+
* @param wait - The number of milliseconds to wait before invoking the function.
|
|
1969
|
+
* @returns A debounced version of the function that returns a Promise.
|
|
1970
|
+
*/
|
|
1971
|
+
debounce(func, wait) {
|
|
1972
|
+
let timeoutId;
|
|
1973
|
+
let pendingResolve;
|
|
1974
|
+
return function(...args) {
|
|
1975
|
+
return new Promise((resolve3, reject) => {
|
|
1976
|
+
if (timeoutId) {
|
|
1977
|
+
clearTimeout(timeoutId);
|
|
1978
|
+
_DebounceManager.#timers.delete(timeoutId);
|
|
1979
|
+
}
|
|
1980
|
+
if (pendingResolve) {
|
|
1981
|
+
pendingResolve(void 0);
|
|
1982
|
+
}
|
|
1983
|
+
pendingResolve = resolve3;
|
|
1984
|
+
timeoutId = setTimeout(() => {
|
|
1985
|
+
if (timeoutId) {
|
|
1986
|
+
_DebounceManager.#timers.delete(timeoutId);
|
|
1987
|
+
}
|
|
1988
|
+
try {
|
|
1989
|
+
resolve3(func.apply(this, args));
|
|
1990
|
+
} catch (error) {
|
|
1991
|
+
reject(castError(error));
|
|
1992
|
+
} finally {
|
|
1993
|
+
pendingResolve = void 0;
|
|
1994
|
+
timeoutId = void 0;
|
|
1995
|
+
}
|
|
1996
|
+
}, wait);
|
|
1997
|
+
_DebounceManager.#timers.add(timeoutId);
|
|
1998
|
+
});
|
|
1999
|
+
};
|
|
2000
|
+
}
|
|
2001
|
+
/** Closes the manager by clearing all active timers. */
|
|
2002
|
+
close() {
|
|
2003
|
+
for (const timer of _DebounceManager.#timers) {
|
|
2004
|
+
clearTimeout(timer);
|
|
2005
|
+
}
|
|
2006
|
+
_DebounceManager.#timers.clear();
|
|
2007
|
+
}
|
|
2008
|
+
};
|
|
2009
|
+
_init2 = __decoratorStart(null);
|
|
2010
|
+
_DebounceManager = __decorateElement(_init2, 0, "DebounceManager", _DebounceManager_decorators, _DebounceManager);
|
|
2011
|
+
__runInitializers(_init2, 1, _DebounceManager);
|
|
2012
|
+
var DebounceManager = _DebounceManager;
|
|
2013
|
+
var debounceManager = new DebounceManager();
|
|
2014
|
+
function debounce(wait) {
|
|
2015
|
+
if (wait < 0) {
|
|
2016
|
+
throw new Error("\u{1F6A8} wait must be non-negative.");
|
|
2017
|
+
}
|
|
2018
|
+
return function(targetMethod, context) {
|
|
2019
|
+
context.addInitializer(function() {
|
|
2020
|
+
Object.defineProperty(this, context.name, { writable: true, configurable: true, value: debounceManager.debounce(targetMethod.bind(this), wait) });
|
|
2021
|
+
});
|
|
2022
|
+
return targetMethod;
|
|
2023
|
+
};
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
// src/file-manager.ts
|
|
2027
|
+
import { createSourceFile as createSourceFile2, ScriptTarget as ScriptTarget2 } from "typescript";
|
|
2028
|
+
var localFileIdentifier = /\.[a-z]+$/i;
|
|
2029
|
+
var relativeSpecifierPattern = /(from\s*['"])(\.\.?\/[^'"]*?)(['"])/g;
|
|
2030
|
+
function rewriteRelativeSpecifiers(code) {
|
|
2031
|
+
return code.replace(relativeSpecifierPattern, (_, before, path, after) => localFileIdentifier.test(path) ? before + path + after : `${before}${path}.js${after}`);
|
|
2032
|
+
}
|
|
2033
|
+
var FileManager = class {
|
|
2034
|
+
#hasEmittedFiles = false;
|
|
2035
|
+
#declarationFiles = /* @__PURE__ */ new Map();
|
|
2036
|
+
#cache;
|
|
2037
|
+
/** Raw declaration text captured during emit, pending pre-processing */
|
|
2038
|
+
#pendingFiles = [];
|
|
2039
|
+
/** Buffered .tsbuildinfo content for async write (avoids sync I/O during emit) */
|
|
2040
|
+
#pendingBuildInfo;
|
|
2041
|
+
/** Background cache save promise — awaited in initialize() and close() */
|
|
2042
|
+
#pendingSave;
|
|
2043
|
+
/**
|
|
2044
|
+
* Creates a new file manager.
|
|
2045
|
+
* @param buildCache - Optional build cache for incremental builds
|
|
2046
|
+
*/
|
|
2047
|
+
constructor(buildCache) {
|
|
2048
|
+
this.#cache = buildCache;
|
|
2049
|
+
}
|
|
2050
|
+
/**
|
|
2051
|
+
* Prepares the manager for a new TypeScript emit operation.
|
|
2052
|
+
* For incremental builds, restores cached (pre-processed) declarations before emit.
|
|
2053
|
+
* For non-incremental builds, clears all stored files.
|
|
2054
|
+
*
|
|
2055
|
+
* @example
|
|
2056
|
+
* ```typescript
|
|
2057
|
+
* await manager.initialize();
|
|
2058
|
+
* program.emit(undefined, manager.fileWriter, undefined, true);
|
|
2059
|
+
* await manager.finalize();
|
|
2060
|
+
* ```
|
|
2061
|
+
*/
|
|
2062
|
+
async initialize() {
|
|
2063
|
+
if (this.#pendingSave) {
|
|
2064
|
+
await this.#pendingSave;
|
|
2065
|
+
this.#pendingSave = void 0;
|
|
2066
|
+
}
|
|
2067
|
+
this.#hasEmittedFiles = false;
|
|
2068
|
+
this.#pendingFiles.length = 0;
|
|
2069
|
+
this.#pendingBuildInfo = void 0;
|
|
2070
|
+
if (this.#cache) {
|
|
2071
|
+
await this.#cache.restore(this.#declarationFiles);
|
|
2072
|
+
} else {
|
|
2073
|
+
this.#declarationFiles.clear();
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
/**
|
|
2077
|
+
* Finalizes the emit operation by saving the cache if files were emitted.
|
|
2078
|
+
* Must be called after program.emit() to ensure cache is properly saved.
|
|
2079
|
+
*
|
|
2080
|
+
* @returns True if files were emitted (or non-incremental build), false if no changes detected
|
|
2081
|
+
* @example
|
|
2082
|
+
* ```typescript
|
|
2083
|
+
* await manager.initialize();
|
|
2084
|
+
* program.emit(undefined, manager.fileWriter, undefined, true);
|
|
2085
|
+
* const hasEmitted = manager.finalize();
|
|
2086
|
+
* if (hasEmitted) { // Continue with build }
|
|
2087
|
+
* ```
|
|
2088
|
+
*/
|
|
2089
|
+
finalize() {
|
|
2090
|
+
this.#processEmittedFiles();
|
|
2091
|
+
return this.#cache === void 0 || this.#hasEmittedFiles;
|
|
2092
|
+
}
|
|
2093
|
+
/**
|
|
2094
|
+
* Persists the .tsbuildinfo file and the dts cache to disk in the background. Call this
|
|
2095
|
+
* AFTER the build's parallel phases (transpile + dts bundling) have completed so the writes
|
|
2096
|
+
* (and Brotli compression for the dts cache) don't compete with esbuild for libuv threadpool slots.
|
|
2097
|
+
* @param fingerprint Build configuration fingerprint for cache invalidation on config change
|
|
2098
|
+
* @param configChanged True when the build configuration fingerprint changed — forces the new
|
|
2099
|
+
* fingerprint to be saved even when TypeScript did not re-emit any files, preventing the
|
|
2100
|
+
* mismatch from triggering unnecessary forced rebuilds on every subsequent build.
|
|
2101
|
+
*/
|
|
2102
|
+
persistCache(fingerprint, configChanged = false) {
|
|
2103
|
+
const tasks = [];
|
|
2104
|
+
if (this.#pendingBuildInfo) {
|
|
2105
|
+
tasks.push(Files.write(this.#pendingBuildInfo.path, this.#pendingBuildInfo.text));
|
|
2106
|
+
this.#pendingBuildInfo = void 0;
|
|
2107
|
+
}
|
|
2108
|
+
if (this.#cache !== void 0 && (this.#hasEmittedFiles || configChanged)) {
|
|
2109
|
+
tasks.push(this.#cache.save(this.#declarationFiles, fingerprint));
|
|
2110
|
+
}
|
|
2111
|
+
if (tasks.length === 0) {
|
|
2112
|
+
return;
|
|
2113
|
+
}
|
|
2114
|
+
const save = tasks.length === 1 ? tasks[0].then(() => {
|
|
2115
|
+
}, () => {
|
|
2116
|
+
}) : Promise.all(tasks).then(() => {
|
|
2117
|
+
}, () => {
|
|
2118
|
+
});
|
|
2119
|
+
this.#pendingSave = this.#pendingSave === void 0 ? save : Promise.all([this.#pendingSave, save]).then(() => {
|
|
2120
|
+
}, () => {
|
|
2121
|
+
});
|
|
2122
|
+
}
|
|
2123
|
+
/**
|
|
2124
|
+
* Retrieves all stored declaration files.
|
|
2125
|
+
* Files are already pre-processed and ready for bundling or writing to disk.
|
|
2126
|
+
* This is a pure getter with no side effects.
|
|
2127
|
+
*
|
|
2128
|
+
* @returns A read-only map of file paths to their pre-processed content with extracted references
|
|
2129
|
+
*/
|
|
2130
|
+
getDeclarationFiles() {
|
|
2131
|
+
return this.#declarationFiles;
|
|
2132
|
+
}
|
|
2133
|
+
/**
|
|
2134
|
+
* Writes all stored declaration files to disk.
|
|
2135
|
+
* Files are already pre-processed, so this just writes them directly.
|
|
2136
|
+
*
|
|
2137
|
+
* @param projectDirectory - Project root for calculating relative paths
|
|
2138
|
+
* @returns Array of written file metadata
|
|
2139
|
+
*/
|
|
2140
|
+
async writeFiles(projectDirectory) {
|
|
2141
|
+
if (this.#declarationFiles.size === 0) {
|
|
2142
|
+
return [];
|
|
2143
|
+
}
|
|
2144
|
+
const writeTasks = [];
|
|
2145
|
+
for (const [filePath, { code }] of this.#declarationFiles) {
|
|
2146
|
+
if (code.length > 0) {
|
|
2147
|
+
writeTasks.push(this.#writeFile(projectDirectory, filePath, code));
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
return Promise.all(writeTasks);
|
|
2151
|
+
}
|
|
2152
|
+
/**
|
|
2153
|
+
* Resolves entry points for declaration bundling.
|
|
2154
|
+
* This is a utility method that filters project entry points based on DTS configuration.
|
|
2155
|
+
*
|
|
2156
|
+
* @param projectEntryPoints - All entry points from project configuration
|
|
2157
|
+
* @param dtsEntryPoints - Optional list of entry point names to include for DTS bundling
|
|
2158
|
+
* @returns Filtered entry points for declaration bundling
|
|
2159
|
+
*/
|
|
2160
|
+
resolveEntryPoints(projectEntryPoints, dtsEntryPoints) {
|
|
2161
|
+
if (!dtsEntryPoints) {
|
|
2162
|
+
return defaultEntryPoint in projectEntryPoints ? { [defaultEntryPoint]: projectEntryPoints[defaultEntryPoint] } : projectEntryPoints;
|
|
2163
|
+
}
|
|
2164
|
+
const result = {};
|
|
2165
|
+
const allowedEntryPoints = new Set(dtsEntryPoints);
|
|
2166
|
+
for (const [name, path] of Object.entries(projectEntryPoints)) {
|
|
2167
|
+
if (allowedEntryPoints.has(name)) {
|
|
2168
|
+
result[name] = path;
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
return result;
|
|
2172
|
+
}
|
|
2173
|
+
/**
|
|
2174
|
+
* Closes the file manager and releases resources.
|
|
2175
|
+
* Clears all stored declaration files.
|
|
2176
|
+
*/
|
|
2177
|
+
close() {
|
|
2178
|
+
this.#pendingSave?.then(() => {
|
|
2179
|
+
}, () => {
|
|
2180
|
+
});
|
|
2181
|
+
this.#pendingSave = void 0;
|
|
2182
|
+
this.#pendingFiles.length = 0;
|
|
2183
|
+
this.#pendingBuildInfo = void 0;
|
|
2184
|
+
this.#declarationFiles.clear();
|
|
2185
|
+
}
|
|
2186
|
+
/**
|
|
2187
|
+
* Awaits any in-flight background I/O (cache save, .tsbuildinfo write).
|
|
2188
|
+
* Call this when you need to guarantee all pending writes have completed,
|
|
2189
|
+
* e.g., before reading the cache file from a different instance.
|
|
2190
|
+
*/
|
|
2191
|
+
async flush() {
|
|
2192
|
+
if (this.#pendingSave) {
|
|
2193
|
+
await this.#pendingSave;
|
|
2194
|
+
this.#pendingSave = void 0;
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
/**
|
|
2198
|
+
* Writes a single declaration file to disk.
|
|
2199
|
+
* @param projectDirectory - Project root for calculating relative paths
|
|
2200
|
+
* @param filePath - The full path of the declaration file to write
|
|
2201
|
+
* @param content - The pre-processed content of the declaration file
|
|
2202
|
+
* @returns Metadata of the written file
|
|
2203
|
+
*/
|
|
2204
|
+
async #writeFile(projectDirectory, filePath, content) {
|
|
2205
|
+
const rewritten = rewriteRelativeSpecifiers(content);
|
|
2206
|
+
await Files.write(filePath, rewritten);
|
|
2207
|
+
return { path: Paths.relative(projectDirectory, filePath), size: rewritten.length };
|
|
2208
|
+
}
|
|
2209
|
+
/**
|
|
2210
|
+
* Function that intercepts file writes during TypeScript emit.
|
|
2211
|
+
* Captures raw text for deferred pre-processing and buffers .tsbuildinfo for async I/O.
|
|
2212
|
+
* Designed to be as fast as possible since it runs inside TypeScript's synchronous emit() call.
|
|
2213
|
+
* @param filePath - The path of the file being written
|
|
2214
|
+
* @param text - The content of the file being written
|
|
2215
|
+
*/
|
|
2216
|
+
fileWriter = (filePath, text) => {
|
|
2217
|
+
if (this.#cache?.isBuildInfoFile(filePath)) {
|
|
2218
|
+
this.#pendingBuildInfo = { path: filePath, text };
|
|
2219
|
+
} else {
|
|
2220
|
+
this.#pendingFiles.push({ path: filePath, text });
|
|
2221
|
+
if (!this.#hasEmittedFiles) {
|
|
2222
|
+
this.#hasEmittedFiles = true;
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
};
|
|
2226
|
+
/**
|
|
2227
|
+
* Pre-processes all declaration files captured during emit.
|
|
2228
|
+
* Runs createSourceFile + DeclarationProcessor.preProcess for each pending file,
|
|
2229
|
+
* then clears the pending queue.
|
|
2230
|
+
*/
|
|
2231
|
+
#processEmittedFiles() {
|
|
2232
|
+
for (const { path, text } of this.#pendingFiles) {
|
|
2233
|
+
const result = DeclarationProcessor.preProcess(createSourceFile2(path, text, ScriptTarget2.Latest, true));
|
|
2234
|
+
if (result.code.length > 0) {
|
|
2235
|
+
this.#declarationFiles.set(path, result);
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
this.#pendingFiles.length = 0;
|
|
2239
|
+
}
|
|
2240
|
+
/**
|
|
2241
|
+
* Custom inspection method for better type representation.
|
|
2242
|
+
* @returns The string 'FileManager'
|
|
2243
|
+
*/
|
|
2244
|
+
get [Symbol.toStringTag]() {
|
|
2245
|
+
return "FileManager";
|
|
2246
|
+
}
|
|
2247
|
+
};
|
|
2248
|
+
|
|
2249
|
+
// src/incremental-build-cache.ts
|
|
2250
|
+
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
2251
|
+
import { mkdir as mkdir4, writeFile as writeFile4 } from "node:fs/promises";
|
|
2252
|
+
var IncrementalBuildCache = class _IncrementalBuildCache {
|
|
2253
|
+
#buildInfoPath;
|
|
2254
|
+
#cacheDirectoryPath;
|
|
2255
|
+
#cacheFilePath;
|
|
2256
|
+
#outputsManifestPath;
|
|
2257
|
+
/** Pre-loading promise started in constructor for async cache restoration */
|
|
2258
|
+
#cacheLoaded;
|
|
2259
|
+
/**
|
|
2260
|
+
* Manifest snapshot captured synchronously at construction. Held in memory so it survives
|
|
2261
|
+
* `invalidate()` (which deletes the on-disk manifest as part of clearing `.tsbuild`) and so
|
|
2262
|
+
* subsequent in-process reads are race-free.
|
|
2263
|
+
*/
|
|
2264
|
+
#outputsSnapshot;
|
|
2265
|
+
/** Set to true when invalidate() is called to prevent stale cache from being restored */
|
|
2266
|
+
#invalidated = false;
|
|
2267
|
+
/** Updated synchronously in save() so fingerprintMatches() sees fresh data without re-reading from disk. */
|
|
2268
|
+
#savedFingerprint;
|
|
2269
|
+
/**
|
|
2270
|
+
* Creates a new build cache instance and begins pre-loading the cache asynchronously.
|
|
2271
|
+
* @param projectRoot - Root directory of the project
|
|
2272
|
+
* @param tsBuildInfoFile - Path to the TypeScript build info file
|
|
2273
|
+
*/
|
|
2274
|
+
constructor(projectRoot, tsBuildInfoFile) {
|
|
2275
|
+
this.#buildInfoPath = Paths.join(projectRoot, tsBuildInfoFile);
|
|
2276
|
+
this.#cacheDirectoryPath = Paths.join(projectRoot, cacheDirectory);
|
|
2277
|
+
this.#cacheFilePath = Paths.join(this.#cacheDirectoryPath, dtsCacheFile);
|
|
2278
|
+
this.#outputsManifestPath = Paths.join(this.#cacheDirectoryPath, outputManifestFile);
|
|
2279
|
+
this.#cacheLoaded = this.#loadCache();
|
|
2280
|
+
this.#outputsSnapshot = _IncrementalBuildCache.#loadOutputsSync(this.#outputsManifestPath);
|
|
2281
|
+
}
|
|
2282
|
+
/**
|
|
2283
|
+
* Loads the cache file asynchronously using V8 deserialization.
|
|
2284
|
+
* @returns The cache or undefined if cache doesn't exist, is corrupted, or has incompatible version.
|
|
2285
|
+
*/
|
|
2286
|
+
async #loadCache() {
|
|
2287
|
+
try {
|
|
2288
|
+
const cache = await Files.readCompressed(this.#cacheFilePath);
|
|
2289
|
+
if (cache.version !== dtsCacheVersion) {
|
|
2290
|
+
return void 0;
|
|
2291
|
+
}
|
|
2292
|
+
return cache;
|
|
2293
|
+
} catch {
|
|
2294
|
+
return void 0;
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
/**
|
|
2298
|
+
* Restores cached declaration files into the provided map.
|
|
2299
|
+
* Waits for the pre-load promise started in constructor to complete.
|
|
2300
|
+
* TypeScript's incremental compilation handles staleness - it re-emits only changed files,
|
|
2301
|
+
* which overwrite cached entries. Unchanged files remain valid and skip re-emission.
|
|
2302
|
+
* @param target - The map to populate with cached declarations
|
|
2303
|
+
*/
|
|
2304
|
+
async restore(target) {
|
|
2305
|
+
if (this.#invalidated) {
|
|
2306
|
+
return;
|
|
2307
|
+
}
|
|
2308
|
+
const cache = await this.#cacheLoaded;
|
|
2309
|
+
if (cache === void 0) {
|
|
2310
|
+
return;
|
|
2311
|
+
}
|
|
2312
|
+
for (const [fileName, content] of cache.files) {
|
|
2313
|
+
target.set(fileName, content);
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
/**
|
|
2317
|
+
* Saves declaration files to the compressed cache file with version and fingerprint information.
|
|
2318
|
+
* Uses V8 serialization for faster read performance on subsequent builds.
|
|
2319
|
+
* @param source - The declaration files to cache
|
|
2320
|
+
* @param fingerprint - Deterministic hash of build configuration for cache invalidation on config change
|
|
2321
|
+
*/
|
|
2322
|
+
async save(source, fingerprint) {
|
|
2323
|
+
this.#savedFingerprint = fingerprint;
|
|
2324
|
+
await Files.writeCompressed(this.#cacheFilePath, { version: dtsCacheVersion, files: source, fingerprint });
|
|
2325
|
+
}
|
|
2326
|
+
/**
|
|
2327
|
+
* Checks whether the build configuration has changed since the cache was last saved.
|
|
2328
|
+
* Returns true if the cache is valid and fingerprints match, false if config changed or cache is invalid.
|
|
2329
|
+
* @param currentFingerprint - The fingerprint of the current build configuration
|
|
2330
|
+
* @returns True if the cached configuration matches the current configuration
|
|
2331
|
+
*/
|
|
2332
|
+
async fingerprintMatches(currentFingerprint) {
|
|
2333
|
+
if (this.#invalidated) {
|
|
2334
|
+
return false;
|
|
2335
|
+
}
|
|
2336
|
+
if (!this.hasPersistedState()) {
|
|
2337
|
+
return false;
|
|
2338
|
+
}
|
|
2339
|
+
if (this.#savedFingerprint !== void 0) {
|
|
2340
|
+
return this.#savedFingerprint === currentFingerprint;
|
|
2341
|
+
}
|
|
2342
|
+
const cache = await this.#cacheLoaded;
|
|
2343
|
+
return cache?.fingerprint === currentFingerprint;
|
|
2344
|
+
}
|
|
2345
|
+
/**
|
|
2346
|
+
* Loads the previous build's output manifest synchronously.
|
|
2347
|
+
* @param manifestPath - Absolute path to the manifest file
|
|
2348
|
+
* @returns The recorded outputs, or undefined when missing/unreadable/malformed.
|
|
2349
|
+
*/
|
|
2350
|
+
static #loadOutputsSync(manifestPath) {
|
|
2351
|
+
try {
|
|
2352
|
+
const parsed = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
2353
|
+
return Array.isArray(parsed) ? parsed : void 0;
|
|
2354
|
+
} catch {
|
|
2355
|
+
return void 0;
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
/**
|
|
2359
|
+
* Returns the project-relative output paths recorded by the previous build, or undefined if none.
|
|
2360
|
+
* The snapshot is captured at construction time and survives `invalidate()`.
|
|
2361
|
+
* @returns The recorded outputs from the prior build, or undefined when unavailable.
|
|
2362
|
+
*/
|
|
2363
|
+
getPreviousOutputs() {
|
|
2364
|
+
return this.#outputsSnapshot;
|
|
2365
|
+
}
|
|
2366
|
+
/**
|
|
2367
|
+
* Persists the project-relative output paths produced by the current build.
|
|
2368
|
+
* Updates the in-memory snapshot immediately so subsequent getPreviousOutputs() calls
|
|
2369
|
+
* (in watch mode) return the freshly written list without re-reading disk.
|
|
2370
|
+
* @param outputs - Project-relative output paths
|
|
2371
|
+
*/
|
|
2372
|
+
async saveOutputs(outputs) {
|
|
2373
|
+
this.#outputsSnapshot = outputs.slice();
|
|
2374
|
+
await mkdir4(this.#cacheDirectoryPath, defaultDirOptions);
|
|
2375
|
+
await writeFile4(this.#outputsManifestPath, JSON.stringify(this.#outputsSnapshot), "utf8");
|
|
2376
|
+
}
|
|
2377
|
+
/**
|
|
2378
|
+
* Checks if the cache is valid (not invalidated).
|
|
2379
|
+
* @returns True if the cache is valid, false if it has been invalidated
|
|
2380
|
+
*/
|
|
2381
|
+
isValid() {
|
|
2382
|
+
return !this.#invalidated;
|
|
2383
|
+
}
|
|
2384
|
+
/** Invalidates the build cache by removing the cache directory. */
|
|
2385
|
+
invalidate() {
|
|
2386
|
+
this.#invalidated = true;
|
|
2387
|
+
try {
|
|
2388
|
+
rmSync(this.#cacheDirectoryPath, defaultCleanOptions);
|
|
2389
|
+
} catch {
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
/**
|
|
2393
|
+
* Checks if a file path is the TypeScript build info file.
|
|
2394
|
+
* @param filePath - The file path to check
|
|
2395
|
+
* @returns True if the path matches the build info file
|
|
2396
|
+
*/
|
|
2397
|
+
isBuildInfoFile(filePath) {
|
|
2398
|
+
return filePath === this.#buildInfoPath;
|
|
2399
|
+
}
|
|
2400
|
+
/**
|
|
2401
|
+
* Synchronously checks whether persisted incremental state exists on disk.
|
|
2402
|
+
* When the .tsbuildinfo file is missing, the next typecheck will perform a full emit,
|
|
2403
|
+
* making it safe to clean the output directory eagerly in parallel with type checking.
|
|
2404
|
+
* @returns True when the .tsbuildinfo file is present and the cache hasn't been invalidated.
|
|
2405
|
+
*/
|
|
2406
|
+
hasPersistedState() {
|
|
2407
|
+
return !this.#invalidated && existsSync(this.#buildInfoPath);
|
|
2408
|
+
}
|
|
2409
|
+
/**
|
|
2410
|
+
* Synchronously checks whether a manifest snapshot from a prior build is available.
|
|
2411
|
+
* Survives `invalidate()` so the manifest-driven cleanup path can be used on
|
|
2412
|
+
* `--clearCache` and `--force` runs as well.
|
|
2413
|
+
* @returns True when an output manifest snapshot is held in memory.
|
|
2414
|
+
*/
|
|
2415
|
+
hasPersistedManifest() {
|
|
2416
|
+
return this.#outputsSnapshot !== void 0;
|
|
2417
|
+
}
|
|
2418
|
+
/**
|
|
2419
|
+
* Custom inspection tag for type.
|
|
2420
|
+
* @returns The string 'IncrementalBuildCache'
|
|
2421
|
+
*/
|
|
2422
|
+
get [Symbol.toStringTag]() {
|
|
2423
|
+
return "IncrementalBuildCache";
|
|
2424
|
+
}
|
|
2425
|
+
};
|
|
2426
|
+
|
|
2427
|
+
// src/entry-points.ts
|
|
2428
|
+
var importConditions = ["import", "node", "module", "default"];
|
|
2429
|
+
function stemOf(filePath) {
|
|
2430
|
+
const base = filePath.split("/").at(-1) ?? "";
|
|
2431
|
+
const dot = base.indexOf(".");
|
|
2432
|
+
return dot === -1 ? base : base.slice(0, dot);
|
|
2433
|
+
}
|
|
2434
|
+
var outputToSourceExtension = /* @__PURE__ */ new Map([
|
|
2435
|
+
[".js", ".ts"],
|
|
2436
|
+
[".jsx", ".tsx"],
|
|
2437
|
+
[".d.ts", ".ts"]
|
|
2438
|
+
]);
|
|
2439
|
+
function unscope(name) {
|
|
2440
|
+
const slash = name.indexOf("/");
|
|
2441
|
+
return slash === -1 ? name : name.slice(slash + 1);
|
|
2442
|
+
}
|
|
2443
|
+
function outputToSourcePath(outputPath, outDir, sourceDir) {
|
|
2444
|
+
const normalizedOutput = outputPath.replace(/^\.\//, "");
|
|
2445
|
+
const normalizedOutDir = outDir.replace(/^\.\//, "").replace(/\/$/, "");
|
|
2446
|
+
if (!normalizedOutput.startsWith(normalizedOutDir + "/") && normalizedOutput !== normalizedOutDir) {
|
|
2447
|
+
return void 0;
|
|
2448
|
+
}
|
|
2449
|
+
const relativePortion = normalizedOutput.slice(normalizedOutDir.length + 1);
|
|
2450
|
+
for (const [outExt, srcExt] of outputToSourceExtension) {
|
|
2451
|
+
if (relativePortion.endsWith(outExt)) {
|
|
2452
|
+
return `./${sourceDir}/${relativePortion.slice(0, -outExt.length)}${srcExt}`;
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
return void 0;
|
|
2456
|
+
}
|
|
2457
|
+
function resolveConditionalExport(exportValue) {
|
|
2458
|
+
if (typeof exportValue === "string") {
|
|
2459
|
+
return exportValue;
|
|
2460
|
+
}
|
|
2461
|
+
for (const condition of importConditions) {
|
|
2462
|
+
const value = exportValue[condition];
|
|
2463
|
+
if (value === void 0) {
|
|
2464
|
+
continue;
|
|
2465
|
+
}
|
|
2466
|
+
const resolved = resolveConditionalExport(value);
|
|
2467
|
+
if (resolved !== void 0) {
|
|
2468
|
+
return resolved;
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
return void 0;
|
|
2472
|
+
}
|
|
2473
|
+
function subpathToEntryName(subpath, packageName2) {
|
|
2474
|
+
if (subpath === ".") {
|
|
2475
|
+
return packageName2 !== void 0 ? unscope(packageName2) : "index";
|
|
2476
|
+
}
|
|
2477
|
+
const withoutPrefix = subpath.replace(/^\.\//, "");
|
|
2478
|
+
const lastSegment = withoutPrefix.lastIndexOf("/");
|
|
2479
|
+
return lastSegment === -1 ? withoutPrefix : withoutPrefix.slice(lastSegment + 1);
|
|
2480
|
+
}
|
|
2481
|
+
function inferEntryPoints(packageJson, outDir, sourceDir = "src") {
|
|
2482
|
+
const entryPoints = {};
|
|
2483
|
+
if (packageJson.exports !== void 0) {
|
|
2484
|
+
if (typeof packageJson.exports === "string") {
|
|
2485
|
+
const sourcePath = outputToSourcePath(packageJson.exports, outDir, sourceDir);
|
|
2486
|
+
if (sourcePath) {
|
|
2487
|
+
entryPoints[stemOf(sourcePath)] = sourcePath;
|
|
2488
|
+
}
|
|
2489
|
+
} else {
|
|
2490
|
+
for (const [subpath, exportValue] of Object.entries(packageJson.exports)) {
|
|
2491
|
+
if (subpath.includes("*")) {
|
|
2492
|
+
continue;
|
|
2493
|
+
}
|
|
2494
|
+
const outputPath = resolveConditionalExport(exportValue);
|
|
2495
|
+
if (outputPath === void 0) {
|
|
2496
|
+
continue;
|
|
2497
|
+
}
|
|
2498
|
+
const sourcePath = outputToSourcePath(outputPath, outDir, sourceDir);
|
|
2499
|
+
if (sourcePath) {
|
|
2500
|
+
entryPoints[subpath === "." ? stemOf(sourcePath) : subpathToEntryName(subpath, packageJson.name)] = sourcePath;
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
if (packageJson.bin !== void 0) {
|
|
2506
|
+
const binEntries = typeof packageJson.bin === "string" ? { [packageJson.name ?? "cli"]: packageJson.bin } : packageJson.bin;
|
|
2507
|
+
for (const [name, outputPath] of Object.entries(binEntries)) {
|
|
2508
|
+
if (entryPoints[name] === void 0) {
|
|
2509
|
+
const sourcePath = outputToSourcePath(outputPath, outDir, sourceDir);
|
|
2510
|
+
if (sourcePath) {
|
|
2511
|
+
entryPoints[name] = sourcePath;
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2516
|
+
let hasEntries = false;
|
|
2517
|
+
for (const _ in entryPoints) {
|
|
2518
|
+
hasEntries = true;
|
|
2519
|
+
break;
|
|
2520
|
+
}
|
|
2521
|
+
if (!hasEntries) {
|
|
2522
|
+
const legacyPath = packageJson.module ?? packageJson.main;
|
|
2523
|
+
if (legacyPath !== void 0) {
|
|
2524
|
+
const sourcePath = outputToSourcePath(legacyPath, outDir, sourceDir);
|
|
2525
|
+
if (sourcePath) {
|
|
2526
|
+
entryPoints["index"] = sourcePath;
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
for (const _ in entryPoints) {
|
|
2531
|
+
return entryPoints;
|
|
2532
|
+
}
|
|
2533
|
+
return void 0;
|
|
2534
|
+
}
|
|
2535
|
+
|
|
2536
|
+
// src/type-script-project.ts
|
|
2537
|
+
import { performance as performance2 } from "node:perf_hooks";
|
|
2538
|
+
import { sys as sys2, createIncrementalProgram, formatDiagnostics, formatDiagnosticsWithColorAndContext, parseJsonConfigFileContent, readConfigFile, findConfigFile } from "typescript";
|
|
2539
|
+
var globCharacters = /[*?\\[\]!].*$/;
|
|
2540
|
+
var domPredicate = (lib) => lib.toUpperCase() === "DOM";
|
|
2541
|
+
var tsLogo = TextFormat.bgBlue(TextFormat.bold(TextFormat.whiteBright(" TS ")));
|
|
2542
|
+
var diagnosticsHost = { getNewLine: () => sys2.newLine, getCurrentDirectory: sys2.getCurrentDirectory, getCanonicalFileName: (fileName) => fileName };
|
|
2543
|
+
var serializePattern = (p) => p instanceof RegExp ? `/${p.source}/${p.flags}` : p;
|
|
2544
|
+
function buildFingerprint(buildConfig, compilerOptions) {
|
|
2545
|
+
return JSON.stringify({
|
|
2546
|
+
minify: buildConfig.minify,
|
|
2547
|
+
iife: buildConfig.iife,
|
|
2548
|
+
declaration: compilerOptions.declaration,
|
|
2549
|
+
emitDeclarationOnly: compilerOptions.emitDeclarationOnly,
|
|
2550
|
+
emitDecoratorMetadata: compilerOptions.emitDecoratorMetadata,
|
|
2551
|
+
bundle: buildConfig.bundle,
|
|
2552
|
+
splitting: buildConfig.splitting,
|
|
2553
|
+
format,
|
|
2554
|
+
target: buildConfig.target,
|
|
2555
|
+
platform: buildConfig.platform,
|
|
2556
|
+
sourceMap: buildConfig.sourceMap,
|
|
2557
|
+
banner: buildConfig.banner,
|
|
2558
|
+
footer: buildConfig.footer,
|
|
2559
|
+
noExternal: buildConfig.noExternal.map(serializePattern),
|
|
2560
|
+
dtsResolve: buildConfig.dts.resolve,
|
|
2561
|
+
dtsEntryPoints: buildConfig.dts.entryPoints,
|
|
2562
|
+
env: buildConfig.env
|
|
2563
|
+
});
|
|
2564
|
+
}
|
|
2565
|
+
var _triggerRebuild_dec, _processDeclarations_dec, _transpile_dec, _typeCheck_dec, _build_dec, _TypeScriptProject_decorators, _fileWatcher, _builderProgram, _directory, _configuration, _fileManager, _buildConfiguration, _pendingChanges, _buildDependencies, _pendingStaleOutputsCleanup, _buildDependenciesProgram, _dependencyPaths, _TypeScriptProject_instances, cleanupStaleOutputs_fn, _init3, typeCheck_fn, transpile_fn, watch_fn, processDeclarations_fn, triggerRebuild_fn, _TypeScriptProject_static, resolveConfiguration_fn, getEntryPoints_fn, handleBuildError_fn, handleTypeErrors_fn;
|
|
2566
|
+
_TypeScriptProject_decorators = [closeOnExit], _build_dec = [measure("Build")], _typeCheck_dec = [measure("Type-checking/Emit", true)], _transpile_dec = [measure("Transpile", true)], _processDeclarations_dec = [measure("Bundle Declarations", true)], _triggerRebuild_dec = [debounce(100)];
|
|
2567
|
+
var _TypeScriptProject = class _TypeScriptProject {
|
|
2568
|
+
/**
|
|
2569
|
+
* Creates a TypeScript project and prepares it for building/bundling.
|
|
2570
|
+
* @param directory - Project root directory (defaults to current working directory)
|
|
2571
|
+
* @param options - Project options to merge with tsconfig.json
|
|
2572
|
+
*/
|
|
2573
|
+
constructor(directory = sys2.getCurrentDirectory(), options = {}) {
|
|
2574
|
+
__runInitializers(_init3, 5, this);
|
|
2575
|
+
__privateAdd(this, _TypeScriptProject_instances);
|
|
2576
|
+
__privateAdd(this, _fileWatcher);
|
|
2577
|
+
__privateAdd(this, _builderProgram);
|
|
2578
|
+
__privateAdd(this, _directory);
|
|
2579
|
+
__privateAdd(this, _configuration);
|
|
2580
|
+
__privateAdd(this, _fileManager);
|
|
2581
|
+
__privateAdd(this, _buildConfiguration);
|
|
2582
|
+
__privateAdd(this, _pendingChanges, []);
|
|
2583
|
+
__privateAdd(this, _buildDependencies, /* @__PURE__ */ new Set());
|
|
2584
|
+
__privateAdd(this, _pendingStaleOutputsCleanup);
|
|
2585
|
+
/** Identity of the Program that populated buildDependencies — skip re-walking when unchanged */
|
|
2586
|
+
__privateAdd(this, _buildDependenciesProgram);
|
|
2587
|
+
__privateAdd(this, _dependencyPaths);
|
|
2588
|
+
var _a;
|
|
2589
|
+
__privateSet(this, _directory, Paths.absolute(directory));
|
|
2590
|
+
__privateSet(this, _configuration, __privateMethod(_a = _TypeScriptProject, _TypeScriptProject_static, resolveConfiguration_fn).call(_a, __privateGet(this, _directory), options));
|
|
2591
|
+
const { buildCache, rootNames, projectReferences, configFileParsingDiagnostics, tsbuild: { entryPoints, ...tsbuildOptions }, compilerOptions: { target, outDir } } = __privateGet(this, _configuration);
|
|
2592
|
+
if (buildCache !== void 0 && options.clearCache) {
|
|
2593
|
+
buildCache.invalidate();
|
|
2594
|
+
}
|
|
2595
|
+
__privateSet(this, _fileManager, new FileManager(buildCache));
|
|
2596
|
+
__privateSet(this, _builderProgram, createIncrementalProgram({ rootNames, options: __privateGet(this, _configuration).compilerOptions, projectReferences, configFileParsingDiagnostics }));
|
|
2597
|
+
__privateSet(this, _buildConfiguration, { entryPoints: __privateMethod(this, _TypeScriptProject_instances, getEntryPoints_fn).call(this, entryPoints), target: toEsTarget(target), outDir, ...tsbuildOptions });
|
|
2598
|
+
__privateSet(this, _dependencyPaths, Files.read(Paths.absolute(__privateGet(this, _directory), "package.json")).then((content) => {
|
|
2599
|
+
const { dependencies = {}, peerDependencies = {} } = Json.parse(content);
|
|
2600
|
+
const dependencySet = /* @__PURE__ */ new Set();
|
|
2601
|
+
for (const key of Object.keys(dependencies)) {
|
|
2602
|
+
dependencySet.add(key);
|
|
2603
|
+
}
|
|
2604
|
+
for (const key of Object.keys(peerDependencies)) {
|
|
2605
|
+
dependencySet.add(key);
|
|
2606
|
+
}
|
|
2607
|
+
return Array.from(dependencySet);
|
|
2608
|
+
}).catch(() => []));
|
|
2609
|
+
}
|
|
2610
|
+
/**
|
|
2611
|
+
* Cleans the output directory
|
|
2612
|
+
* @returns A promise that resolves when the cleaning is complete.
|
|
2613
|
+
*/
|
|
2614
|
+
async clean() {
|
|
2615
|
+
return Files.empty(__privateGet(this, _buildConfiguration).outDir);
|
|
2616
|
+
}
|
|
2617
|
+
async build() {
|
|
2618
|
+
Logger.header(`${tsLogo} tsbuild v${"1.9.2"}${__privateGet(this, _configuration).compilerOptions.incremental && __privateGet(this, _configuration).buildCache?.isValid() ? " [incremental]" : ""}`);
|
|
2619
|
+
try {
|
|
2620
|
+
const processes = [];
|
|
2621
|
+
const buildCache = __privateGet(this, _configuration).buildCache;
|
|
2622
|
+
const currentFingerprint = buildFingerprint(__privateGet(this, _buildConfiguration), __privateGet(this, _configuration).compilerOptions);
|
|
2623
|
+
const fingerprintMatched = buildCache !== void 0 && await buildCache.fingerprintMatches(currentFingerprint);
|
|
2624
|
+
const force = __privateGet(this, _configuration).tsbuild.force || !fingerprintMatched;
|
|
2625
|
+
const cleanEnabled = __privateGet(this, _configuration).clean && !__privateGet(this, _configuration).compilerOptions.noEmit;
|
|
2626
|
+
const useManifest = cleanEnabled && buildCache !== void 0 && buildCache.hasPersistedManifest();
|
|
2627
|
+
const previousOutputs = useManifest ? buildCache.getPreviousOutputs() : void 0;
|
|
2628
|
+
const willEmit = force || buildCache?.hasPersistedState() !== true;
|
|
2629
|
+
const eagerCleanPromise = cleanEnabled && willEmit && !useManifest ? this.clean() : void 0;
|
|
2630
|
+
const filesWereEmitted = await __privateMethod(this, _TypeScriptProject_instances, typeCheck_fn).call(this);
|
|
2631
|
+
if ((filesWereEmitted || force) && !__privateGet(this, _configuration).compilerOptions.noEmit) {
|
|
2632
|
+
if (eagerCleanPromise !== void 0) {
|
|
2633
|
+
await eagerCleanPromise;
|
|
2634
|
+
} else if (cleanEnabled && !useManifest) {
|
|
2635
|
+
await this.clean();
|
|
2636
|
+
}
|
|
2637
|
+
if (__privateGet(this, _configuration).compilerOptions.declaration) {
|
|
2638
|
+
processes.push(__privateMethod(this, _TypeScriptProject_instances, processDeclarations_fn).call(this));
|
|
2639
|
+
}
|
|
2640
|
+
if (!__privateGet(this, _configuration).compilerOptions.emitDeclarationOnly) {
|
|
2641
|
+
processes.push(__privateMethod(this, _TypeScriptProject_instances, transpile_fn).call(this));
|
|
2642
|
+
}
|
|
2643
|
+
} else if (eagerCleanPromise !== void 0) {
|
|
2644
|
+
await eagerCleanPromise;
|
|
2645
|
+
}
|
|
2646
|
+
const settled = await Promise.allSettled(processes);
|
|
2647
|
+
const newOutputs = [];
|
|
2648
|
+
for (const result of settled) {
|
|
2649
|
+
if (result.status === "rejected") {
|
|
2650
|
+
__privateMethod(this, _TypeScriptProject_instances, handleBuildError_fn).call(this, result.reason);
|
|
2651
|
+
continue;
|
|
2652
|
+
}
|
|
2653
|
+
for (const { path } of result.value) {
|
|
2654
|
+
newOutputs.push(path);
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
__privateGet(this, _fileManager).persistCache(currentFingerprint, !fingerprintMatched);
|
|
2658
|
+
if (buildCache !== void 0 && newOutputs.length > 0) {
|
|
2659
|
+
if (previousOutputs !== void 0) {
|
|
2660
|
+
__privateMethod(this, _TypeScriptProject_instances, cleanupStaleOutputs_fn).call(this, previousOutputs, newOutputs);
|
|
2661
|
+
}
|
|
2662
|
+
void buildCache.saveOutputs(newOutputs).catch(() => {
|
|
2663
|
+
});
|
|
2664
|
+
}
|
|
2665
|
+
} catch (error) {
|
|
2666
|
+
__privateMethod(this, _TypeScriptProject_instances, handleBuildError_fn).call(this, error);
|
|
2667
|
+
} finally {
|
|
2668
|
+
if (__privateGet(this, _buildConfiguration).watch.enabled) {
|
|
2669
|
+
const program = __privateGet(this, _builderProgram).getProgram();
|
|
2670
|
+
if (__privateGet(this, _buildDependenciesProgram) !== program) {
|
|
2671
|
+
__privateSet(this, _buildDependenciesProgram, program);
|
|
2672
|
+
__privateGet(this, _buildDependencies).clear();
|
|
2673
|
+
const dirWithSlash = __privateGet(this, _directory) + "/";
|
|
2674
|
+
for (const { isDeclarationFile, fileName } of program.getSourceFiles()) {
|
|
2675
|
+
if (!isDeclarationFile && fileName.startsWith(dirWithSlash)) {
|
|
2676
|
+
__privateGet(this, _buildDependencies).add(Paths.relative(__privateGet(this, _directory), fileName));
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
if (__privateGet(this, _fileWatcher) === void 0 || __privateGet(this, _fileWatcher).isClosed()) {
|
|
2681
|
+
setImmediate(() => void __privateMethod(this, _TypeScriptProject_instances, watch_fn).call(this));
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
/** Closes the project and cleans up resources. */
|
|
2687
|
+
close() {
|
|
2688
|
+
__privateGet(this, _fileWatcher)?.close();
|
|
2689
|
+
__privateGet(this, _fileManager).close();
|
|
2690
|
+
__privateSet(this, _pendingStaleOutputsCleanup, void 0);
|
|
2691
|
+
__privateGet(this, _buildDependencies).clear();
|
|
2692
|
+
__privateSet(this, _buildDependenciesProgram, void 0);
|
|
2693
|
+
__privateGet(this, _pendingChanges).length = 0;
|
|
2694
|
+
}
|
|
2695
|
+
};
|
|
2696
|
+
_init3 = __decoratorStart(null);
|
|
2697
|
+
_fileWatcher = new WeakMap();
|
|
2698
|
+
_builderProgram = new WeakMap();
|
|
2699
|
+
_directory = new WeakMap();
|
|
2700
|
+
_configuration = new WeakMap();
|
|
2701
|
+
_fileManager = new WeakMap();
|
|
2702
|
+
_buildConfiguration = new WeakMap();
|
|
2703
|
+
_pendingChanges = new WeakMap();
|
|
2704
|
+
_buildDependencies = new WeakMap();
|
|
2705
|
+
_pendingStaleOutputsCleanup = new WeakMap();
|
|
2706
|
+
_buildDependenciesProgram = new WeakMap();
|
|
2707
|
+
_dependencyPaths = new WeakMap();
|
|
2708
|
+
_TypeScriptProject_instances = new WeakSet();
|
|
2709
|
+
/**
|
|
2710
|
+
* Removes outputs that the previous build wrote but the current build did not — e.g. renamed
|
|
2711
|
+
* entry points or content-hashed chunks whose hash changed. Restricted to files under outDir
|
|
2712
|
+
* for safety. Fire-and-forget: scheduled after build completion so it never inflates timings.
|
|
2713
|
+
* @param previous - Project-relative paths recorded by the previous build (or undefined)
|
|
2714
|
+
* @param current - Project-relative paths produced by the current build
|
|
2715
|
+
*/
|
|
2716
|
+
cleanupStaleOutputs_fn = function(previous, current) {
|
|
2717
|
+
if (previous === void 0 || previous.length === 0) {
|
|
2718
|
+
return;
|
|
2719
|
+
}
|
|
2720
|
+
const currentSet = new Set(current);
|
|
2721
|
+
const outDirRel = Paths.relative(__privateGet(this, _directory), __privateGet(this, _buildConfiguration).outDir);
|
|
2722
|
+
const prefix = `${outDirRel}/`;
|
|
2723
|
+
const stale = [];
|
|
2724
|
+
for (const path of previous) {
|
|
2725
|
+
if (currentSet.has(path)) {
|
|
2726
|
+
continue;
|
|
2727
|
+
}
|
|
2728
|
+
if (path !== outDirRel && !path.startsWith(prefix)) {
|
|
2729
|
+
continue;
|
|
2730
|
+
}
|
|
2731
|
+
stale.push(Paths.absolute(__privateGet(this, _directory), path));
|
|
2732
|
+
}
|
|
2733
|
+
if (stale.length === 0) {
|
|
2734
|
+
return;
|
|
2735
|
+
}
|
|
2736
|
+
const removals = new Array(stale.length);
|
|
2737
|
+
for (let i = 0, length = stale.length; i < length; i++) {
|
|
2738
|
+
removals[i] = rm2(stale[i], { force: true });
|
|
2739
|
+
}
|
|
2740
|
+
const cleanup = Promise.all(removals).then(() => void 0).catch(() => void 0).finally(() => {
|
|
2741
|
+
if (__privateGet(this, _pendingStaleOutputsCleanup) === cleanup) {
|
|
2742
|
+
__privateSet(this, _pendingStaleOutputsCleanup, void 0);
|
|
2743
|
+
}
|
|
2744
|
+
});
|
|
2745
|
+
__privateSet(this, _pendingStaleOutputsCleanup, cleanup);
|
|
2746
|
+
};
|
|
2747
|
+
typeCheck_fn = async function() {
|
|
2748
|
+
var _a;
|
|
2749
|
+
await __privateGet(this, _fileManager).initialize();
|
|
2750
|
+
let allDiagnostics;
|
|
2751
|
+
if (__privateGet(this, _configuration).compilerOptions.noEmit) {
|
|
2752
|
+
performance2.mark("diagnostics:start");
|
|
2753
|
+
allDiagnostics = [
|
|
2754
|
+
...__privateGet(this, _builderProgram).getConfigFileParsingDiagnostics(),
|
|
2755
|
+
...__privateGet(this, _builderProgram).getOptionsDiagnostics(),
|
|
2756
|
+
...__privateGet(this, _builderProgram).getSyntacticDiagnostics(),
|
|
2757
|
+
...__privateGet(this, _builderProgram).getGlobalDiagnostics(),
|
|
2758
|
+
...__privateGet(this, _builderProgram).getSemanticDiagnostics(),
|
|
2759
|
+
...__privateGet(this, _configuration).compilerOptions.declaration ? __privateGet(this, _builderProgram).getDeclarationDiagnostics() : []
|
|
2760
|
+
];
|
|
2761
|
+
__privateGet(this, _builderProgram).emit(void 0, __privateGet(this, _fileManager).fileWriter, void 0, true);
|
|
2762
|
+
} else {
|
|
2763
|
+
const { diagnostics } = __privateGet(this, _builderProgram).emit(void 0, __privateGet(this, _fileManager).fileWriter, void 0, true);
|
|
2764
|
+
allDiagnostics = [...__privateGet(this, _builderProgram).getSemanticDiagnostics(), ...diagnostics];
|
|
2765
|
+
}
|
|
2766
|
+
if (allDiagnostics.length > 0) {
|
|
2767
|
+
const unique = /* @__PURE__ */ new Map();
|
|
2768
|
+
for (const diagnostic of allDiagnostics) {
|
|
2769
|
+
const key = `${diagnostic.file?.fileName ?? ""}:${diagnostic.start ?? -1}:${diagnostic.code}`;
|
|
2770
|
+
if (!unique.has(key)) {
|
|
2771
|
+
unique.set(key, diagnostic);
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
__privateMethod(_a = _TypeScriptProject, _TypeScriptProject_static, handleTypeErrors_fn).call(_a, "Type-checking failed", Array.from(unique.values()), __privateGet(this, _directory));
|
|
2775
|
+
}
|
|
2776
|
+
return __privateGet(this, _fileManager).finalize() || !__privateGet(this, _configuration).compilerOptions.declaration;
|
|
2777
|
+
};
|
|
2778
|
+
transpile_fn = async function() {
|
|
2779
|
+
const { build: esbuild, formatMessages } = await import("esbuild");
|
|
2780
|
+
const plugins = [];
|
|
2781
|
+
let iife;
|
|
2782
|
+
if (__privateGet(this, _buildConfiguration).iife) {
|
|
2783
|
+
iife = iifePlugin(__privateGet(this, _buildConfiguration).iife === true ? void 0 : __privateGet(this, _buildConfiguration).iife);
|
|
2784
|
+
plugins.push(iife.plugin);
|
|
2785
|
+
}
|
|
2786
|
+
plugins.push(outputPlugin());
|
|
2787
|
+
if (__privateGet(this, _buildConfiguration).noExternal.length > 0) {
|
|
2788
|
+
plugins.push(externalModulesPlugin({ dependencies: await __privateGet(this, _dependencyPaths), noExternal: __privateGet(this, _buildConfiguration).noExternal }));
|
|
2789
|
+
}
|
|
2790
|
+
if (__privateGet(this, _configuration).compilerOptions.emitDecoratorMetadata) {
|
|
2791
|
+
try {
|
|
2792
|
+
const { swcDecoratorMetadataPlugin } = await import("./HDWN4W6U.js");
|
|
2793
|
+
plugins.push(swcDecoratorMetadataPlugin);
|
|
2794
|
+
} catch {
|
|
2795
|
+
throw new ConfigurationError("emitDecoratorMetadata is enabled but @swc/core is not installed. Install it with: pnpm add -D @swc/core");
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
if (__privateGet(this, _buildConfiguration).plugins?.length) {
|
|
2799
|
+
plugins.push(...await resolvePlugins(__privateGet(this, _buildConfiguration).plugins, __privateGet(this, _directory)));
|
|
2800
|
+
}
|
|
2801
|
+
const define = {};
|
|
2802
|
+
if (__privateGet(this, _buildConfiguration).env !== void 0) {
|
|
2803
|
+
const envExpansion = new RegExp(processEnvExpansionPattern, "g");
|
|
2804
|
+
for (const [key, value] of Object.entries(__privateGet(this, _buildConfiguration).env)) {
|
|
2805
|
+
define[`import.meta.env.${key}`] = Json.serialize(value.replace(envExpansion, (_, envVar) => process.env[envVar] ?? ""));
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
try {
|
|
2809
|
+
const { warnings, errors, metafile: { outputs } } = await esbuild({
|
|
2810
|
+
format,
|
|
2811
|
+
plugins,
|
|
2812
|
+
define,
|
|
2813
|
+
write: true,
|
|
2814
|
+
metafile: true,
|
|
2815
|
+
treeShaking: true,
|
|
2816
|
+
logLevel: "warning",
|
|
2817
|
+
tsconfigRaw: {
|
|
2818
|
+
compilerOptions: {
|
|
2819
|
+
alwaysStrict: __privateGet(this, _configuration).compilerOptions.alwaysStrict,
|
|
2820
|
+
experimentalDecorators: __privateGet(this, _configuration).compilerOptions.experimentalDecorators,
|
|
2821
|
+
jsx: toJsxRenderingMode(__privateGet(this, _configuration).compilerOptions.jsx),
|
|
2822
|
+
jsxFactory: __privateGet(this, _configuration).compilerOptions.jsxFactory,
|
|
2823
|
+
jsxFragmentFactory: __privateGet(this, _configuration).compilerOptions.jsxFragmentFactory,
|
|
2824
|
+
jsxImportSource: __privateGet(this, _configuration).compilerOptions.jsxImportSource,
|
|
2825
|
+
paths: __privateGet(this, _configuration).compilerOptions.paths,
|
|
2826
|
+
strict: __privateGet(this, _configuration).compilerOptions.strict,
|
|
2827
|
+
target: __privateGet(this, _buildConfiguration).target,
|
|
2828
|
+
useDefineForClassFields: __privateGet(this, _configuration).compilerOptions.useDefineForClassFields,
|
|
2829
|
+
verbatimModuleSyntax: __privateGet(this, _configuration).compilerOptions.verbatimModuleSyntax
|
|
2830
|
+
}
|
|
2831
|
+
},
|
|
2832
|
+
entryPoints: await __privateGet(this, _buildConfiguration).entryPoints,
|
|
2833
|
+
bundle: __privateGet(this, _buildConfiguration).bundle,
|
|
2834
|
+
packages: __privateGet(this, _buildConfiguration).packages,
|
|
2835
|
+
platform: __privateGet(this, _buildConfiguration).platform,
|
|
2836
|
+
sourcemap: __privateGet(this, _buildConfiguration).sourceMap,
|
|
2837
|
+
target: __privateGet(this, _buildConfiguration).target,
|
|
2838
|
+
banner: __privateGet(this, _buildConfiguration).banner,
|
|
2839
|
+
footer: __privateGet(this, _buildConfiguration).footer,
|
|
2840
|
+
outdir: __privateGet(this, _buildConfiguration).outDir,
|
|
2841
|
+
splitting: __privateGet(this, _buildConfiguration).splitting,
|
|
2842
|
+
chunkNames: "[hash]",
|
|
2843
|
+
minify: __privateGet(this, _buildConfiguration).minify,
|
|
2844
|
+
// Force decorator transformation even with ESNext target since Node.js doesn't support decorators yet
|
|
2845
|
+
supported: { decorators: false }
|
|
2846
|
+
});
|
|
2847
|
+
for (const [kind, logEntryType, messages] of [[BuildMessageType.WARNING, Logger.EntryType.Warn, warnings], [BuildMessageType.ERROR, Logger.EntryType.Error, errors]]) {
|
|
2848
|
+
if (messages.length > 0) {
|
|
2849
|
+
for (const message of await formatMessages(messages, { kind, color: true })) {
|
|
2850
|
+
Logger.log(message, logEntryType);
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
if (kind === BuildMessageType.ERROR && errors.length > 0) {
|
|
2854
|
+
return [];
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
const writtenFiles = [];
|
|
2858
|
+
for (const outputPath in outputs) {
|
|
2859
|
+
writtenFiles.push({ path: outputPath, size: outputs[outputPath].bytes });
|
|
2860
|
+
}
|
|
2861
|
+
if (iife) {
|
|
2862
|
+
writtenFiles.push(...iife.files);
|
|
2863
|
+
}
|
|
2864
|
+
return writtenFiles;
|
|
2865
|
+
} catch (error) {
|
|
2866
|
+
Logger.error("Transpile failed", error);
|
|
2867
|
+
throw error;
|
|
2868
|
+
}
|
|
2869
|
+
};
|
|
2870
|
+
watch_fn = async function() {
|
|
2871
|
+
const { Watchr } = await import("@d1g1tal/watchr");
|
|
2872
|
+
const targets = [];
|
|
2873
|
+
for (const path of __privateGet(this, _configuration).include ?? [defaultSourceDirectory]) {
|
|
2874
|
+
targets.push(Paths.absolute(__privateGet(this, _directory), path.replace(globCharacters, "")));
|
|
2875
|
+
}
|
|
2876
|
+
const rebuild = (event, stats, path, nextPath) => {
|
|
2877
|
+
if (stats?.size === 0 && (event === Watchr.FileEvent.add || event === Watchr.FileEvent.unlink)) {
|
|
2878
|
+
return;
|
|
2879
|
+
}
|
|
2880
|
+
if (__privateGet(this, _configuration).compilerOptions.noEmit || __privateGet(this, _buildDependencies).has(Paths.relative(__privateGet(this, _directory), path))) {
|
|
2881
|
+
__privateGet(this, _pendingChanges).push({ event, path, nextPath });
|
|
2882
|
+
void __privateMethod(this, _TypeScriptProject_instances, triggerRebuild_fn).call(this);
|
|
2883
|
+
}
|
|
2884
|
+
};
|
|
2885
|
+
const pathsToIgnore = [...__privateGet(this, _configuration).exclude ?? [], ...__privateGet(this, _buildConfiguration).watch.ignore ?? []];
|
|
2886
|
+
__privateSet(this, _fileWatcher, new Watchr(targets, { ...__privateGet(this, _buildConfiguration).watch, ignore: (path) => pathsToIgnore.some((p) => path.includes(`/${p}/`) || path.endsWith(`/${p}`)) }, rebuild));
|
|
2887
|
+
Logger.info(`Watching for changes in: ${targets.join(", ")}`);
|
|
2888
|
+
};
|
|
2889
|
+
processDeclarations_fn = async function() {
|
|
2890
|
+
if (!__privateGet(this, _buildConfiguration).bundle) {
|
|
2891
|
+
return __privateGet(this, _fileManager).writeFiles(__privateGet(this, _directory));
|
|
2892
|
+
}
|
|
2893
|
+
return bundleDeclarations({
|
|
2894
|
+
currentDirectory: __privateGet(this, _directory),
|
|
2895
|
+
declarationFiles: __privateGet(this, _fileManager).getDeclarationFiles(),
|
|
2896
|
+
entryPoints: __privateGet(this, _fileManager).resolveEntryPoints(await __privateGet(this, _buildConfiguration).entryPoints, __privateGet(this, _buildConfiguration).dts.entryPoints),
|
|
2897
|
+
resolve: __privateGet(this, _buildConfiguration).dts.resolve,
|
|
2898
|
+
external: __privateGet(this, _buildConfiguration).external ?? [],
|
|
2899
|
+
noExternal: __privateGet(this, _buildConfiguration).noExternal,
|
|
2900
|
+
// Extract only the minimal compiler options needed for DTS bundling from configuration
|
|
2901
|
+
// All these properties are guaranteed to exist in TypeScriptConfiguration
|
|
2902
|
+
compilerOptions: {
|
|
2903
|
+
paths: __privateGet(this, _configuration).compilerOptions.paths,
|
|
2904
|
+
rootDir: __privateGet(this, _configuration).compilerOptions.rootDir,
|
|
2905
|
+
outDir: __privateGet(this, _configuration).compilerOptions.outDir,
|
|
2906
|
+
moduleResolution: __privateGet(this, _configuration).compilerOptions.moduleResolution
|
|
2907
|
+
},
|
|
2908
|
+
// Only yield to event loop if transpile is running in parallel
|
|
2909
|
+
parallelTranspile: !__privateGet(this, _configuration).compilerOptions.emitDeclarationOnly
|
|
2910
|
+
});
|
|
2911
|
+
};
|
|
2912
|
+
triggerRebuild_fn = async function() {
|
|
2913
|
+
if (__privateGet(this, _pendingChanges).length === 0) {
|
|
2914
|
+
return;
|
|
2915
|
+
}
|
|
2916
|
+
Logger.clear();
|
|
2917
|
+
Logger.info(`Rebuilding project: ${__privateGet(this, _pendingChanges).length} file changes detected.`);
|
|
2918
|
+
const rootNames = [...__privateGet(this, _builderProgram).getProgram().getRootFileNames()];
|
|
2919
|
+
for (const { event, path, nextPath } of __privateGet(this, _pendingChanges)) {
|
|
2920
|
+
if (nextPath !== void 0 && (event === "rename" || event === "renameDir")) {
|
|
2921
|
+
__privateGet(this, _buildDependencies).delete(Paths.relative(__privateGet(this, _directory), path));
|
|
2922
|
+
__privateGet(this, _buildDependencies).add(Paths.relative(__privateGet(this, _directory), nextPath));
|
|
2923
|
+
const index = rootNames.indexOf(path);
|
|
2924
|
+
if (index !== -1) {
|
|
2925
|
+
rootNames.splice(index, 1, nextPath);
|
|
2926
|
+
}
|
|
2927
|
+
} else {
|
|
2928
|
+
const index = rootNames.indexOf(path);
|
|
2929
|
+
if (event === "unlink" && index !== -1) {
|
|
2930
|
+
rootNames.splice(index, 1);
|
|
2931
|
+
} else if (event === "add" && index === -1) {
|
|
2932
|
+
rootNames.push(path);
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2936
|
+
__privateGet(this, _pendingChanges).length = 0;
|
|
2937
|
+
await __privateGet(this, _fileManager).flush();
|
|
2938
|
+
__privateSet(this, _builderProgram, createIncrementalProgram({ rootNames, options: __privateGet(this, _configuration).compilerOptions, projectReferences: __privateGet(this, _configuration).projectReferences, configFileParsingDiagnostics: __privateGet(this, _configuration).configFileParsingDiagnostics }));
|
|
2939
|
+
await this.build();
|
|
2940
|
+
};
|
|
2941
|
+
_TypeScriptProject_static = new WeakSet();
|
|
2942
|
+
resolveConfiguration_fn = function(directory, typeScriptOptions) {
|
|
2943
|
+
const configResult = readConfigFile(findConfigFile(directory, sys2.fileExists) ?? "./tsconfig.json", sys2.readFile);
|
|
2944
|
+
if (configResult.error !== void 0) {
|
|
2945
|
+
throw new ConfigurationError(formatDiagnostics([configResult.error], diagnosticsHost));
|
|
2946
|
+
}
|
|
2947
|
+
const bundle = typeScriptOptions.tsbuild?.bundle ?? configResult.config.tsbuild?.bundle ?? true;
|
|
2948
|
+
const platform2 = configResult.config.compilerOptions?.lib?.some(domPredicate) ? Platform.BROWSER : Platform.NODE;
|
|
2949
|
+
const noExternal = typeScriptOptions.tsbuild?.noExternal ?? configResult.config.tsbuild?.noExternal ?? [];
|
|
2950
|
+
const hasExplicitEntryPoints = typeScriptOptions.tsbuild?.entryPoints !== void 0 || configResult.config.tsbuild?.entryPoints !== void 0;
|
|
2951
|
+
let inferredEntryPoints;
|
|
2952
|
+
if (!hasExplicitEntryPoints && bundle) {
|
|
2953
|
+
const packageJsonContent = sys2.readFile(Paths.join(directory, "package.json"));
|
|
2954
|
+
if (packageJsonContent) {
|
|
2955
|
+
try {
|
|
2956
|
+
const pkgJson = JSON.parse(packageJsonContent);
|
|
2957
|
+
const outDir = typeScriptOptions.compilerOptions?.outDir ?? configResult.config.compilerOptions?.outDir ?? defaultOutDirectory;
|
|
2958
|
+
const hasExportFields = pkgJson.exports !== void 0 || pkgJson.bin !== void 0 || pkgJson.main !== void 0 || pkgJson.module !== void 0;
|
|
2959
|
+
inferredEntryPoints = inferEntryPoints(pkgJson, outDir);
|
|
2960
|
+
if (hasExportFields && inferredEntryPoints === void 0) {
|
|
2961
|
+
Logger.warn(`Could not infer entry points from package.json exports (output paths do not match outDir "${outDir}"). Add explicit entryPoints to your tsconfig.json tsbuild configuration.`);
|
|
2962
|
+
}
|
|
2963
|
+
} catch {
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
const defaultTsbuildConfig = {
|
|
2968
|
+
splitting: bundle,
|
|
2969
|
+
minify: false,
|
|
2970
|
+
force: false,
|
|
2971
|
+
bundle,
|
|
2972
|
+
sourceMap: typeScriptOptions.compilerOptions?.sourceMap ?? configResult.config.compilerOptions?.sourceMap ?? false,
|
|
2973
|
+
noExternal,
|
|
2974
|
+
packages: noExternal.length > 0 ? void 0 : platform2 === Platform.BROWSER ? "bundle" : "external",
|
|
2975
|
+
platform: platform2,
|
|
2976
|
+
dts: { resolve: platform2 !== Platform.NODE, entryPoints: bundle ? void 0 : [] },
|
|
2977
|
+
watch: { enabled: false, recursive: true, ignoreInitial: true, persistent: true },
|
|
2978
|
+
entryPoints: inferredEntryPoints ?? (bundle ? { [defaultEntryPoint]: defaultEntryFile } : { src: defaultSourceDirectory })
|
|
2979
|
+
};
|
|
2980
|
+
const baseConfig = {
|
|
2981
|
+
...configResult.config,
|
|
2982
|
+
clean: typeScriptOptions.tsbuild?.clean ?? configResult.config.tsbuild?.clean ?? true,
|
|
2983
|
+
tsbuild: {
|
|
2984
|
+
...defaultTsbuildConfig,
|
|
2985
|
+
...configResult.config.tsbuild,
|
|
2986
|
+
...typeScriptOptions.tsbuild,
|
|
2987
|
+
dts: { ...defaultTsbuildConfig.dts, ...configResult.config.tsbuild?.dts, ...typeScriptOptions.tsbuild?.dts },
|
|
2988
|
+
watch: { ...defaultTsbuildConfig.watch, ...configResult.config.tsbuild?.watch, ...typeScriptOptions.tsbuild?.watch }
|
|
2989
|
+
},
|
|
2990
|
+
compilerOptions: {
|
|
2991
|
+
...{ outDir: defaultOutDirectory, noEmit: false, sourceMap: false, incremental: true, tsBuildInfoFile: Paths.join(cacheDirectory, buildInfoFile), lib: [] },
|
|
2992
|
+
...configResult.config.compilerOptions,
|
|
2993
|
+
...typeScriptOptions.compilerOptions,
|
|
2994
|
+
// Auto-inject 'node' only on Node platform — browser/neutral builds shouldn't pay the
|
|
2995
|
+
// cost of loading @types/node (~3 MB of declarations). Users can still opt in by
|
|
2996
|
+
// listing 'node' explicitly in their tsconfig types array.
|
|
2997
|
+
types: (() => {
|
|
2998
|
+
const typesSet = /* @__PURE__ */ new Set();
|
|
2999
|
+
if (platform2 === Platform.NODE) {
|
|
3000
|
+
typesSet.add("node");
|
|
3001
|
+
}
|
|
3002
|
+
for (const t of configResult.config.compilerOptions?.types ?? []) {
|
|
3003
|
+
typesSet.add(t);
|
|
3004
|
+
}
|
|
3005
|
+
for (const t of typeScriptOptions.compilerOptions?.types ?? []) {
|
|
3006
|
+
typesSet.add(t);
|
|
3007
|
+
}
|
|
3008
|
+
return Array.from(typesSet);
|
|
3009
|
+
})()
|
|
3010
|
+
}
|
|
3011
|
+
};
|
|
3012
|
+
const { options, fileNames, errors } = parseJsonConfigFileContent(baseConfig, sys2, directory);
|
|
3013
|
+
return {
|
|
3014
|
+
...baseConfig,
|
|
3015
|
+
compilerOptions: {
|
|
3016
|
+
...baseConfig.compilerOptions,
|
|
3017
|
+
...options,
|
|
3018
|
+
...compilerOptionOverrides
|
|
3019
|
+
},
|
|
3020
|
+
directory,
|
|
3021
|
+
rootNames: fileNames,
|
|
3022
|
+
configFileParsingDiagnostics: errors,
|
|
3023
|
+
buildCache: baseConfig.compilerOptions.incremental ? new IncrementalBuildCache(directory, baseConfig.compilerOptions.tsBuildInfoFile) : void 0
|
|
3024
|
+
};
|
|
3025
|
+
};
|
|
3026
|
+
getEntryPoints_fn = async function(entryPoints) {
|
|
3027
|
+
const expandedEntryPoints = {};
|
|
3028
|
+
for (const [name, entryPoint] of Object.entries(entryPoints)) {
|
|
3029
|
+
const resolvedPath = Paths.absolute(__privateGet(this, _directory), entryPoint);
|
|
3030
|
+
if (await Paths.isDirectory(resolvedPath)) {
|
|
3031
|
+
for (const file of await Files.readDirectory(resolvedPath)) {
|
|
3032
|
+
const filePath = Paths.join(resolvedPath, file);
|
|
3033
|
+
if (await Paths.isFile(filePath)) {
|
|
3034
|
+
expandedEntryPoints[Paths.parse(file).name] = filePath;
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
} else if (await Paths.isFile(resolvedPath)) {
|
|
3038
|
+
expandedEntryPoints[name] = resolvedPath;
|
|
3039
|
+
} else {
|
|
3040
|
+
throw new ConfigurationError(`Entry point does not exist: ${entryPoint}. Add explicit entryPoints to your tsconfig.json tsbuild configuration.`);
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
return expandedEntryPoints;
|
|
3044
|
+
};
|
|
3045
|
+
/**
|
|
3046
|
+
* Handles build errors by logging unexpected errors and setting appropriate exit codes.
|
|
3047
|
+
* Expected build failures (TypeCheckError, BundleError) are already logged when they occur,
|
|
3048
|
+
* so this method only logs unexpected errors to avoid duplicate output.
|
|
3049
|
+
* @param error - The error to handle
|
|
3050
|
+
*/
|
|
3051
|
+
handleBuildError_fn = function(error) {
|
|
3052
|
+
if (error instanceof ConfigurationError) {
|
|
3053
|
+
Logger.error(error.message);
|
|
3054
|
+
if (!__privateGet(this, _buildConfiguration).watch.enabled) {
|
|
3055
|
+
process.exitCode = error.code;
|
|
3056
|
+
}
|
|
3057
|
+
return;
|
|
3058
|
+
}
|
|
3059
|
+
if (error instanceof BuildError) {
|
|
3060
|
+
if (!__privateGet(this, _buildConfiguration).watch.enabled) {
|
|
3061
|
+
process.exitCode = error.code;
|
|
3062
|
+
}
|
|
3063
|
+
return;
|
|
3064
|
+
}
|
|
3065
|
+
Logger.error("Build failed", error);
|
|
3066
|
+
if (!__privateGet(this, _buildConfiguration).watch.enabled) {
|
|
3067
|
+
process.exitCode = 1;
|
|
3068
|
+
}
|
|
3069
|
+
};
|
|
3070
|
+
handleTypeErrors_fn = function(message, diagnostics, projectDirectory) {
|
|
3071
|
+
Logger.error(formatDiagnosticsWithColorAndContext(diagnostics, diagnosticsHost));
|
|
3072
|
+
const filesWithErrors = /* @__PURE__ */ new Map();
|
|
3073
|
+
for (const { file, start } of diagnostics) {
|
|
3074
|
+
if (file !== void 0) {
|
|
3075
|
+
const { line } = file.getLineAndCharacterOfPosition(start ?? 0);
|
|
3076
|
+
const existing = filesWithErrors.get(file.fileName);
|
|
3077
|
+
if (existing !== void 0) {
|
|
3078
|
+
existing.count++;
|
|
3079
|
+
existing.line = Math.min(existing.line, line);
|
|
3080
|
+
} else {
|
|
3081
|
+
filesWithErrors.set(file.fileName, { count: 1, line });
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
const errorCount = diagnostics.length;
|
|
3086
|
+
const fileCount = filesWithErrors.size;
|
|
3087
|
+
const [[firstFileName, { line: firstLine }] = ["", { line: 0 }]] = filesWithErrors;
|
|
3088
|
+
const relativeFirstFileName = Paths.relative(projectDirectory, firstFileName);
|
|
3089
|
+
if (errorCount === 1) {
|
|
3090
|
+
Logger.error(`Found 1 error in ${relativeFirstFileName}:${firstLine + 1}${sys2.newLine}`);
|
|
3091
|
+
} else if (fileCount === 1) {
|
|
3092
|
+
Logger.error(`Found ${errorCount} errors in the same file, starting at: ${relativeFirstFileName}:${firstLine + 1}${sys2.newLine}`);
|
|
3093
|
+
} else {
|
|
3094
|
+
Logger.error(`Found ${errorCount} errors in ${fileCount} files.${sys2.newLine}`);
|
|
3095
|
+
Logger.error("Errors Files");
|
|
3096
|
+
for (const [fileName, { count, line }] of filesWithErrors) {
|
|
3097
|
+
Logger.error(` ${count} ${fileName}:${line + 1}`);
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
throw new TypeCheckError(message, formatDiagnostics(diagnostics, diagnosticsHost));
|
|
3101
|
+
};
|
|
3102
|
+
__decorateElement(_init3, 1, "build", _build_dec, _TypeScriptProject);
|
|
3103
|
+
typeCheck_fn = __decorateElement(_init3, 17, "#typeCheck", _typeCheck_dec, _TypeScriptProject_instances, typeCheck_fn);
|
|
3104
|
+
transpile_fn = __decorateElement(_init3, 17, "#transpile", _transpile_dec, _TypeScriptProject_instances, transpile_fn);
|
|
3105
|
+
processDeclarations_fn = __decorateElement(_init3, 17, "#processDeclarations", _processDeclarations_dec, _TypeScriptProject_instances, processDeclarations_fn);
|
|
3106
|
+
triggerRebuild_fn = __decorateElement(_init3, 17, "#triggerRebuild", _triggerRebuild_dec, _TypeScriptProject_instances, triggerRebuild_fn);
|
|
3107
|
+
__privateAdd(_TypeScriptProject, _TypeScriptProject_static);
|
|
3108
|
+
_TypeScriptProject = __decorateElement(_init3, 0, "TypeScriptProject", _TypeScriptProject_decorators, _TypeScriptProject);
|
|
3109
|
+
__runInitializers(_init3, 1, _TypeScriptProject);
|
|
3110
|
+
var TypeScriptProject = _TypeScriptProject;
|
|
5
3111
|
export {
|
|
6
3112
|
TypeScriptProject
|
|
7
3113
|
};
|