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