tsc-ts 0.0.5 → 0.0.6

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.
Files changed (171) hide show
  1. package/README.md +1 -1
  2. package/dist/api/compiler/ast.d.ts +10 -9
  3. package/dist/api/compiler/ast.js +22 -16
  4. package/dist/api/compiler/binder-utilities.js +2 -1
  5. package/dist/api/compiler/binder.js +9 -8
  6. package/dist/api/compiler/checker-calls.js +3 -2
  7. package/dist/api/compiler/checker-declaration-order.js +2 -1
  8. package/dist/api/compiler/checker-declarations.js +14 -14
  9. package/dist/api/compiler/checker-declared-types.d.ts +1 -1
  10. package/dist/api/compiler/checker-declared-types.js +12 -11
  11. package/dist/api/compiler/checker-decorators.js +3 -3
  12. package/dist/api/compiler/checker-deprecation.js +17 -18
  13. package/dist/api/compiler/checker-destructuring.d.ts +1 -1
  14. package/dist/api/compiler/checker-destructuring.js +3 -3
  15. package/dist/api/compiler/checker-elaboration.js +8 -7
  16. package/dist/api/compiler/checker-emit-resolver.d.ts +1 -1
  17. package/dist/api/compiler/checker-emit-resolver.js +5 -4
  18. package/dist/api/compiler/checker-grammar.js +18 -4
  19. package/dist/api/compiler/checker-heritage.d.ts +1 -1
  20. package/dist/api/compiler/checker-heritage.js +14 -13
  21. package/dist/api/compiler/checker-inference.d.ts +1 -1
  22. package/dist/api/compiler/checker-inference.js +9 -9
  23. package/dist/api/compiler/checker-javascript.d.ts +1 -1
  24. package/dist/api/compiler/checker-javascript.js +5 -4
  25. package/dist/api/compiler/checker-jsx.d.ts +1 -1
  26. package/dist/api/compiler/checker-jsx.js +4 -4
  27. package/dist/api/compiler/checker-literals.js +2 -2
  28. package/dist/api/compiler/checker-members.d.ts +5 -3
  29. package/dist/api/compiler/checker-members.js +75 -53
  30. package/dist/api/compiler/checker-modules.d.ts +1 -1
  31. package/dist/api/compiler/checker-modules.js +13 -13
  32. package/dist/api/compiler/checker-object-literals.d.ts +1 -1
  33. package/dist/api/compiler/checker-object-literals.js +11 -7
  34. package/dist/api/compiler/checker-overloads.d.ts +1 -1
  35. package/dist/api/compiler/checker-overloads.js +4 -3
  36. package/dist/api/compiler/checker-property-access.d.ts +1 -1
  37. package/dist/api/compiler/checker-property-access.js +2 -2
  38. package/dist/api/compiler/checker-services.js +2 -2
  39. package/dist/api/compiler/checker-signatures.d.ts +1 -1
  40. package/dist/api/compiler/checker-signatures.js +9 -8
  41. package/dist/api/compiler/checker-symbol-types.d.ts +2 -18
  42. package/dist/api/compiler/checker-symbol-types.js +22 -952
  43. package/dist/api/compiler/checker-symbols.d.ts +2 -2
  44. package/dist/api/compiler/checker-symbols.js +29 -27
  45. package/dist/api/compiler/checker-type-factory.d.ts +2 -2
  46. package/dist/api/compiler/checker-type-factory.js +57 -16
  47. package/dist/api/compiler/checker-type-nodes.d.ts +1 -1
  48. package/dist/api/compiler/checker-type-nodes.js +2 -2
  49. package/dist/api/compiler/checker-type-operators.d.ts +1 -1
  50. package/dist/api/compiler/checker-type-operators.js +5 -5
  51. package/dist/api/compiler/checker-types.d.ts +73 -7
  52. package/dist/api/compiler/checker-types.js +220 -43
  53. package/dist/api/compiler/checker-unused.d.ts +1 -1
  54. package/dist/api/compiler/checker-unused.js +3 -3
  55. package/dist/api/compiler/checker.d.ts +29 -8
  56. package/dist/api/compiler/checker.js +29 -9
  57. package/dist/api/compiler/diagnostics.d.ts +2 -8
  58. package/dist/api/compiler/diagnostics.js +4 -40
  59. package/dist/api/compiler/file-include.d.ts +35 -8
  60. package/dist/api/compiler/file-include.js +81 -18
  61. package/dist/api/compiler/file-loader.d.ts +33 -4
  62. package/dist/api/compiler/file-loader.js +90 -24
  63. package/dist/api/compiler/instantiation.d.ts +1 -1
  64. package/dist/api/compiler/instantiation.js +86 -50
  65. package/dist/api/compiler/link-tables.d.ts +69 -0
  66. package/dist/api/compiler/link-tables.js +236 -0
  67. package/dist/api/compiler/name-resolver.js +3 -3
  68. package/dist/api/compiler/node-builder-names.d.ts +1 -1
  69. package/dist/api/compiler/node-builder-names.js +12 -12
  70. package/dist/api/compiler/node-builder-pseudo.d.ts +1 -1
  71. package/dist/api/compiler/node-builder-pseudo.js +2 -1
  72. package/dist/api/compiler/node-builder.d.ts +1 -1
  73. package/dist/api/compiler/node-builder.js +16 -16
  74. package/dist/api/compiler/parallel-parse.d.ts +2 -0
  75. package/dist/api/compiler/parallel-parse.js +4 -0
  76. package/dist/api/compiler/parser.d.ts +33 -16
  77. package/dist/api/compiler/parser.js +95 -76
  78. package/dist/api/compiler/printer/emit-context.d.ts +5 -2
  79. package/dist/api/compiler/printer/emit-context.js +19 -13
  80. package/dist/api/compiler/program-checker.js +3 -0
  81. package/dist/api/compiler/program.js +9 -1
  82. package/dist/api/compiler/relations.d.ts +1 -1
  83. package/dist/api/compiler/relations.js +10 -10
  84. package/dist/api/compiler/symbol-accessibility.d.ts +1 -1
  85. package/dist/api/compiler/symbol-accessibility.js +123 -26
  86. package/dist/api/compiler/symbol.d.ts +45 -3
  87. package/dist/api/compiler/symbol.js +121 -10
  88. package/dist/api/compiler/transformers/alias-references.d.ts +1 -1
  89. package/dist/api/compiler/transformers/alias-references.js +2 -1
  90. package/dist/api/compiler/transformers/declarations-diagnostics.js +2 -1
  91. package/dist/api/compiler/transformers/declarations-pseudo.js +4 -2
  92. package/dist/api/compiler/transformers/declarations-syntactic.d.ts +1 -1
  93. package/dist/api/compiler/transformers/declarations-syntactic.js +9 -9
  94. package/dist/api/compiler/transformers/declarations-tracker.d.ts +1 -1
  95. package/dist/api/compiler/transformers/declarations-tracker.js +3 -2
  96. package/dist/api/compiler/transformers/declarations.js +6 -5
  97. package/dist/api/compiler/transformers/reference-resolver.d.ts +2 -1
  98. package/dist/api/compiler/transformers/reference-resolver.js +26 -24
  99. package/dist/api/compiler/transformers/subtree-facts.d.ts +1 -0
  100. package/dist/api/compiler/transformers/subtree-facts.js +7 -5
  101. package/dist/api/compiler/transformers/syntax-facts.d.ts +1 -0
  102. package/dist/api/compiler/transformers/syntax-facts.js +9 -5
  103. package/dist/api/compiler/transformers/type-serialization.js +12 -12
  104. package/package.json +9 -9
  105. package/src/compiler/ast.ts +27 -19
  106. package/src/compiler/binder-utilities.ts +2 -2
  107. package/src/compiler/binder.ts +15 -11
  108. package/src/compiler/checker-calls.ts +3 -3
  109. package/src/compiler/checker-declaration-order.ts +2 -2
  110. package/src/compiler/checker-declarations.ts +21 -14
  111. package/src/compiler/checker-declared-types.ts +12 -12
  112. package/src/compiler/checker-decorators.ts +3 -3
  113. package/src/compiler/checker-deprecation.ts +17 -21
  114. package/src/compiler/checker-destructuring.ts +3 -3
  115. package/src/compiler/checker-elaboration.ts +8 -8
  116. package/src/compiler/checker-emit-resolver.ts +5 -5
  117. package/src/compiler/checker-grammar.ts +17 -5
  118. package/src/compiler/checker-heritage.ts +21 -14
  119. package/src/compiler/checker-inference.ts +17 -9
  120. package/src/compiler/checker-javascript.ts +5 -5
  121. package/src/compiler/checker-jsx.ts +12 -8
  122. package/src/compiler/checker-literals.ts +2 -2
  123. package/src/compiler/checker-members.ts +91 -47
  124. package/src/compiler/checker-modules.ts +23 -13
  125. package/src/compiler/checker-object-literals.ts +22 -6
  126. package/src/compiler/checker-overloads.ts +6 -6
  127. package/src/compiler/checker-property-access.ts +2 -2
  128. package/src/compiler/checker-services.ts +2 -2
  129. package/src/compiler/checker-signatures.ts +9 -9
  130. package/src/compiler/checker-symbol-types.ts +20 -940
  131. package/src/compiler/checker-symbols.ts +42 -35
  132. package/src/compiler/checker-type-factory.ts +53 -16
  133. package/src/compiler/checker-type-nodes.ts +2 -2
  134. package/src/compiler/checker-type-operators.ts +13 -5
  135. package/src/compiler/checker-types.ts +223 -43
  136. package/src/compiler/checker-unused.ts +3 -3
  137. package/src/compiler/checker.ts +31 -9
  138. package/src/compiler/diagnostics.ts +5 -44
  139. package/src/compiler/file-include.ts +85 -17
  140. package/src/compiler/file-loader.ts +104 -35
  141. package/src/compiler/incremental.ts +39 -5
  142. package/src/compiler/instantiation.ts +99 -55
  143. package/src/compiler/link-tables.ts +245 -0
  144. package/src/compiler/name-resolver.ts +3 -3
  145. package/src/compiler/node-builder-names.ts +21 -19
  146. package/src/compiler/node-builder-pseudo.ts +2 -2
  147. package/src/compiler/node-builder.ts +24 -16
  148. package/src/compiler/parallel-check.ts +11 -8
  149. package/src/compiler/parallel-parse.ts +5 -0
  150. package/src/compiler/parse-thread.ts +0 -4
  151. package/src/compiler/parser.ts +120 -70
  152. package/src/compiler/printer/emit-context.ts +20 -15
  153. package/src/compiler/program-checker.ts +2 -0
  154. package/src/compiler/program.ts +8 -1
  155. package/src/compiler/relations.ts +10 -10
  156. package/src/compiler/symbol-accessibility.ts +120 -25
  157. package/src/compiler/symbol.ts +127 -9
  158. package/src/compiler/transformers/alias-references.ts +2 -2
  159. package/src/compiler/transformers/declarations-diagnostics.ts +2 -1
  160. package/src/compiler/transformers/declarations-pseudo.ts +7 -4
  161. package/src/compiler/transformers/declarations-syntactic.ts +17 -9
  162. package/src/compiler/transformers/declarations-tracker.ts +3 -3
  163. package/src/compiler/transformers/declarations.ts +6 -6
  164. package/src/compiler/transformers/reference-resolver.ts +37 -25
  165. package/src/compiler/transformers/subtree-facts.ts +13 -5
  166. package/src/compiler/transformers/syntax-facts.ts +10 -5
  167. package/src/compiler/transformers/type-serialization.ts +12 -12
  168. package/src/compiler/tsc-build.ts +17 -13
  169. package/src/compiler/tsc-cli.ts +9 -6
  170. package/src/compiler/tsc-compile.ts +16 -7
  171. package/src/compiler/tsc-watch.ts +94 -26
@@ -30,13 +30,12 @@ export const enum FileIncludeKind {
30
30
  AutomaticTypeDirectiveFile,
31
31
  }
32
32
 
33
- /** One reason a file is in the program. */
33
+ /**
34
+ * One reason a file is in the program. Reasons are immutable, so the program's loader takes the
35
+ * reasons a parse thread found as they are; what they compute for a program is kept by its
36
+ * IncludeProcessor (`ReasonCache`).
37
+ */
34
38
  export class FileIncludeReason {
35
- private relativeDiagnostic: Diagnostic | undefined = undefined;
36
- private absoluteDiagnostic: Diagnostic | undefined = undefined;
37
- private location: ReferenceFileLocation | undefined = undefined;
38
- private relatedInfo: Diagnostic | null | undefined = undefined;
39
-
40
39
  private constructor(
41
40
  readonly kind: FileIncludeKind,
42
41
  /** The referencing file's path, for references from a file. */
@@ -80,7 +79,7 @@ export class FileIncludeReason {
80
79
  return new FileIncludeReason(kind, file, index, synthetic, '', undefined);
81
80
  }
82
81
 
83
- /** The same reason without what it has computed (a parse thread's reasons are immutable). */
82
+ /** The same reason as a new object (`IncludeProcessor.copy`). */
84
83
  copy(): FileIncludeReason {
85
84
  return new FileIncludeReason(this.kind, this.file, this.index, this.synthetic, this.typeReference, this.packageId);
86
85
  }
@@ -90,7 +89,8 @@ export class FileIncludeReason {
90
89
  }
91
90
 
92
91
  getReferencedLocation(program: Program): ReferenceFileLocation {
93
- if (this.location !== undefined) return this.location;
92
+ const cache = program.includeProcessor.cacheOf(this);
93
+ if (cache !== undefined && cache.location !== undefined) return cache.location;
94
94
  const file = program.getSourceFileByPath(this.file);
95
95
  if (file === undefined) throw new Error('referencing file is not in the program');
96
96
  let location: ReferenceFileLocation;
@@ -142,18 +142,20 @@ export class FileIncludeReason {
142
142
  false,
143
143
  );
144
144
  }
145
- if (!program.isShared()) this.location = location;
145
+ if (!program.isShared()) program.includeProcessor.newCacheOf(this).location = location;
146
146
  return location;
147
147
  }
148
148
 
149
149
  /** The reason as a message, with file names relative to the current directory if `relative`. */
150
150
  toDiagnostic(program: Program, relative: boolean): Diagnostic {
151
- const cached = relative ? this.relativeDiagnostic : this.absoluteDiagnostic;
151
+ const cache = program.includeProcessor.cacheOf(this);
152
+ const cached = cache === undefined ? undefined : relative ? cache.relativeDiagnostic : cache.absoluteDiagnostic;
152
153
  if (cached !== undefined) return cached;
153
154
  const diagnostic = this.computeDiagnostic(program, relative);
154
155
  if (program.isShared()) return diagnostic;
155
- if (relative) this.relativeDiagnostic = diagnostic;
156
- else this.absoluteDiagnostic = diagnostic;
156
+ const own = program.includeProcessor.newCacheOf(this);
157
+ if (relative) own.relativeDiagnostic = diagnostic;
158
+ else own.absoluteDiagnostic = diagnostic;
157
159
  return diagnostic;
158
160
  }
159
161
 
@@ -286,9 +288,10 @@ export class FileIncludeReason {
286
288
 
287
289
  /** Where in the config or a file this reason is written, as related information; `undefined` if nowhere. */
288
290
  toRelatedInfo(program: Program): Diagnostic | undefined {
289
- if (this.relatedInfo !== undefined) return this.relatedInfo ?? undefined;
291
+ const cache = program.includeProcessor.cacheOf(this);
292
+ if (cache !== undefined && cache.relatedInfo !== undefined) return cache.relatedInfo ?? undefined;
290
293
  const info = this.computeRelatedInfo(program);
291
- if (!program.isShared()) this.relatedInfo = info ?? null;
294
+ if (!program.isShared()) program.includeProcessor.newCacheOf(this).relatedInfo = info ?? null;
292
295
  return info;
293
296
  }
294
297
 
@@ -425,6 +428,14 @@ export class ProcessingDiagnostic {
425
428
  return new ProcessingDiagnostic(this.kind, this.file, this.reason?.copy(), this.message, this.args);
426
429
  }
427
430
 
431
+ /** This diagnostic with `renew(reason)` for its reason; itself when that is its reason. */
432
+ withReason(renew: (reason: FileIncludeReason) => FileIncludeReason): ProcessingDiagnostic {
433
+ const reason = this.reason === undefined ? undefined : renew(this.reason);
434
+ return reason === this.reason
435
+ ? this
436
+ : new ProcessingDiagnostic(this.kind, this.file, reason, this.message, this.args);
437
+ }
438
+
428
439
  toDiagnostic(program: Program): Diagnostic {
429
440
  const reason = this.reason;
430
441
  if (this.kind === ProcessingDiagnosticKind.UnknownReference && reason !== undefined) {
@@ -509,20 +520,77 @@ function stripLibAffixes(name: string): string {
509
520
  }
510
521
 
511
522
  /** Include reasons of every file and the diagnostics found while loading them. */
523
+ /** What a reason computed for the program of an IncludeProcessor. */
524
+ class ReasonCache {
525
+ relativeDiagnostic: Diagnostic | undefined = undefined;
526
+ absoluteDiagnostic: Diagnostic | undefined = undefined;
527
+ location: ReferenceFileLocation | undefined = undefined;
528
+ relatedInfo: Diagnostic | null | undefined = undefined;
529
+ }
530
+
512
531
  export class IncludeProcessor {
513
532
  private computed: Diagnostic[] | undefined = undefined;
533
+ /** What each reason computed for this processor's program, once it computed something. */
534
+ private readonly reasonCaches = new Map<FileIncludeReason, ReasonCache>();
514
535
  private compilerOptionsObject: ObjectLiteralExpression | undefined = undefined;
515
536
  private compilerOptionsComputed = false;
516
537
  private readonly redirectAndFileFormat = new Map<string, readonly Diagnostic[]>();
538
+ /** The number of processing diagnostics when the program was created (`noteProgramCreated`). */
539
+ private createdCount: number | undefined = undefined;
517
540
 
518
541
  constructor(
519
542
  readonly fileIncludeReasons = new Map<string, FileIncludeReason[]>(),
520
543
  readonly processingDiagnostics: ProcessingDiagnostic[] = [],
521
544
  ) {}
522
545
 
523
- /** A processor with these reasons and processing diagnostics, whose diagnostics are computed for another program. */
524
- copy(): IncludeProcessor {
525
- return new IncludeProcessor(this.fileIncludeReasons, this.processingDiagnostics);
546
+ /** What `reason` computed for this processor's program, if anything. */
547
+ cacheOf(reason: FileIncludeReason): ReasonCache | undefined {
548
+ return this.reasonCaches.get(reason);
549
+ }
550
+
551
+ /** The cache of `reason`, created if needed. */
552
+ newCacheOf(reason: FileIncludeReason): ReasonCache {
553
+ let cache = this.reasonCaches.get(reason);
554
+ if (cache === undefined) {
555
+ cache = new ReasonCache();
556
+ this.reasonCaches.set(reason, cache);
557
+ }
558
+ return cache;
559
+ }
560
+
561
+ /**
562
+ * A processor with these reasons and the processing diagnostics its program was created with, whose diagnostics are
563
+ * computed for another program. Computing the common source directory later adds diagnostics that the program
564
+ * does not report (`Program.commonSourceDirectory`), and those of a program shared with checker threads are
565
+ * immutable, so the copy has its own list. The reasons written in `replaced`, the path of the file
566
+ * `Program.updateFile` swaps in, are new: a reason keeps where its file writes it, which the new text may move. Each
567
+ * is copied once, so a diagnostic and the file's reasons still share it.
568
+ */
569
+ copy(replaced?: string): IncludeProcessor {
570
+ const created = this.processingDiagnostics.slice(0, this.createdCount ?? this.processingDiagnostics.length);
571
+ if (replaced === undefined) return new IncludeProcessor(this.fileIncludeReasons, created);
572
+ const copies = new Map<FileIncludeReason, FileIncludeReason>();
573
+ const renew = (reason: FileIncludeReason): FileIncludeReason => {
574
+ if (reason.file !== replaced) return reason;
575
+ let copy = copies.get(reason);
576
+ if (copy === undefined) {
577
+ copy = reason.copy();
578
+ copies.set(reason, copy);
579
+ }
580
+ return copy;
581
+ };
582
+ const reasons = new Map<string, FileIncludeReason[]>();
583
+ for (const [path, list] of this.fileIncludeReasons)
584
+ reasons.set(path, list.some((reason) => reason.file === replaced) ? list.map(renew) : list);
585
+ return new IncludeProcessor(
586
+ reasons,
587
+ created.map((diagnostic) => diagnostic.withReason(renew)),
588
+ );
589
+ }
590
+
591
+ /** The program is created: the processing diagnostics so far are those a copy takes. */
592
+ noteProgramCreated(): void {
593
+ this.createdCount = this.processingDiagnostics.length;
526
594
  }
527
595
 
528
596
  reasonsOf(path: string): readonly FileIncludeReason[] {
@@ -36,6 +36,7 @@ import {
36
36
  LoadKind,
37
37
  type LoadJobs,
38
38
  type PreparedFile,
39
+ isPrepared,
39
40
  preparedLoad,
40
41
  preparedPackageJsonLookups,
41
42
  takePreparedFile,
@@ -205,7 +206,7 @@ export class LoadedReference {
205
206
  * What a parse thread's FileLoader found loading a file it prepared (parallel-parse.ts): the same
206
207
  * as the program's FileLoader finds, since both load with the same options and file system. The
207
208
  * program's FileLoader takes it instead of resolving the file's references, imports and type
208
- * directives again. Published with the file, so the reasons are copied when taken.
209
+ * directives again, and takes its reasons as they are (they are immutable).
209
210
  */
210
211
  export class LoadedFile {
211
212
  constructor(
@@ -416,7 +417,7 @@ export function withReplacedFile(processed: ProcessedFiles, file: SourceFile): P
416
417
  processed.importHelpersImportSpecifiers,
417
418
  processed.libFiles,
418
419
  processed.sourceFilesFoundSearchingNodeModules,
419
- processed.includeProcessor.copy(),
420
+ processed.includeProcessor.copy(file.path),
420
421
  processed.outputFileToProjectReferenceSource,
421
422
  processed.redirectTargets,
422
423
  processed.redirectFilesByPath,
@@ -527,6 +528,10 @@ export class FileLoader {
527
528
  private rootFilesAdded = 0;
528
529
  /** The sub-tasks of prepared files, by file name, built ahead by `takeAhead`. */
529
530
  private readonly subTasksAhead = new Map<string, SubTasksAhead>();
531
+ /** Whether the work of the root tasks is queued (`startRootTasks`). */
532
+ private rootTasksStarted = false;
533
+ /** Set while `walkAhead` runs: the walk stops at work that would parse a file not prepared yet. */
534
+ private walkingAhead = false;
530
535
  /**
531
536
  * Whether a file that parse threads prepared is loaded from what its thread found (its metadata
532
537
  * and resolutions). If not, only the parsed and bound file is taken, and this loader looks up the
@@ -573,11 +578,8 @@ export class FileLoader {
573
578
  return end === rootFiles.length;
574
579
  }
575
580
 
576
- /**
577
- * Builds ahead what loading takes from each of `files` (`takeLoadedFile`): the main thread does
578
- * this while parse threads load more files (parallel-parse.ts).
579
- */
580
- takeAhead(files: readonly PreparedFile[]): void {
581
+ /** Builds ahead what loading takes from each of `files` (`takeLoadedFile`). */
582
+ private takeAhead(files: readonly PreparedFile[]): void {
581
583
  for (const prepared of files) {
582
584
  const loaded = prepared.loaded;
583
585
  if (loaded === undefined) continue;
@@ -587,10 +589,39 @@ export class FileLoader {
587
589
  }
588
590
  }
589
591
 
592
+ /**
593
+ * Loads what it can while parse threads load more files (parallel-parse.ts), the main thread's work
594
+ * for each batch they return: builds ahead what loading takes from its `files` (`takeAhead`), and once
595
+ * every root file's task is added, runs the walk `load` would run, in the same order, up to work that
596
+ * would parse a file the threads have not prepared yet. A later batch, or `load`, goes on from there.
597
+ * The order decides the program where a file is reached at several depths (the depth it is first
598
+ * loaded at decides the depths of the files it adds), so the walk keeps it.
599
+ */
600
+ walkAhead(files: readonly PreparedFile[]): void {
601
+ this.takeAhead(files);
602
+ if (!this.rootTasksStarted && this.rootFilesAdded < this.config.fileNames.length) return;
603
+ this.startRootTasks();
604
+ this.walkingAhead = true;
605
+ this.walk();
606
+ this.walkingAhead = false;
607
+ }
608
+
590
609
  load(): ProcessedFiles {
591
- const rootFiles = this.config.fileNames;
592
- this.addRootFiles(rootFiles.length);
593
- if (rootFiles.length > 0 && this.options.noLib !== true) {
610
+ this.addRootFiles(this.config.fileNames.length);
611
+ this.startRootTasks();
612
+ mark('loader roots added');
613
+ this.walk();
614
+ mark('loader walked');
615
+ const result = this.collect();
616
+ mark('loader collected');
617
+ this.mapper.loader = undefined;
618
+ return result;
619
+ }
620
+
621
+ /** Adds the tasks of the libraries and of the automatic type directives, after those of the root files. */
622
+ private addLastRootTasks(): void {
623
+ if (this.config.fileNames.length === 0) return;
624
+ if (this.options.noLib !== true) {
594
625
  const lib = this.options.lib;
595
626
  if (lib === undefined) {
596
627
  const libFile = this.pathForLibFile(getDefaultLibFileName(this.options));
@@ -604,32 +635,54 @@ export class FileLoader {
604
635
  }
605
636
  }
606
637
  }
607
- if (rootFiles.length > 0) {
608
- const containingDirectory =
609
- this.options.configFilePath !== undefined
610
- ? getDirectoryPath(this.options.configFilePath)
611
- : this.host.currentDirectory;
612
- this.rootTasks.push(
613
- new ParseTask(
614
- combinePaths(containingDirectory, inferredTypesContainingFile),
615
- undefined,
616
- undefined,
617
- true,
618
- false,
619
- false,
620
- undefined,
621
- ),
622
- );
623
- }
638
+ const containingDirectory =
639
+ this.options.configFilePath !== undefined
640
+ ? getDirectoryPath(this.options.configFilePath)
641
+ : this.host.currentDirectory;
642
+ this.rootTasks.push(
643
+ new ParseTask(
644
+ combinePaths(containingDirectory, inferredTypesContainingFile),
645
+ undefined,
646
+ undefined,
647
+ true,
648
+ false,
649
+ false,
650
+ undefined,
651
+ ),
652
+ );
653
+ }
624
654
 
625
- mark('loader roots added');
655
+ /** Adds the last root tasks and queues the work of every root task, once every root file's task is added. */
656
+ private startRootTasks(): void {
657
+ if (this.rootTasksStarted) return;
658
+ this.rootTasksStarted = true;
659
+ this.addLastRootTasks();
626
660
  this.start(this.rootTasks, 0);
627
- for (let work = this.work.pop(); work !== undefined; work = this.work.pop()) this.run(work);
628
- mark('loader walked');
629
- const result = this.collect();
630
- mark('loader collected');
631
- this.mapper.loader = undefined;
632
- return result;
661
+ }
662
+
663
+ private walk(): void {
664
+ for (let work = this.work.pop(); work !== undefined; work = this.work.pop()) {
665
+ if (this.walkingAhead && this.parsesUnprepared(work.tasks[work.index], work.data)) {
666
+ this.work.push(work);
667
+ return;
668
+ }
669
+ this.run(work);
670
+ }
671
+ }
672
+
673
+ /**
674
+ * Drops the tasks once the program has its files, so that whatever holds the loader after loading
675
+ * (a parse session's callbacks) no longer keeps every file's task, sub-task list and resolution
676
+ * traces. Freeing them takes a while on large programs, so the drivers call this once checking
677
+ * has started (`releaseLater`).
678
+ */
679
+ release(): void {
680
+ this.rootTasks.length = 0;
681
+ this.taskDataByPath.clear();
682
+ this.work.length = 0;
683
+ this.subTasksAhead.clear();
684
+ this.referenceTasks.clear();
685
+ this.paths.clear();
633
686
  }
634
687
 
635
688
  /**
@@ -983,6 +1036,17 @@ export class FileLoader {
983
1036
  }
984
1037
  }
985
1038
 
1039
+ /**
1040
+ * Whether running the work of `task` (of `data`'s path) may parse a file that parse threads have not
1041
+ * prepared yet: a task of the path not loaded yet, or `task`, a new casing.
1042
+ */
1043
+ private parsesUnprepared(task: ParseTask, data: ParseTaskData): boolean {
1044
+ if (!data.tasks.has(task.normalizedFilePath) && !isPrepared(task.normalizedFilePath)) return true;
1045
+ for (const other of data.tasks.values())
1046
+ if (!other.loaded && !other.isForAutomaticTypeDirective && !isPrepared(other.normalizedFilePath)) return true;
1047
+ return false;
1048
+ }
1049
+
986
1050
  private loadTask(task: ParseTask): void {
987
1051
  task.loaded = true;
988
1052
  if (task.isForAutomaticTypeDirective) {
@@ -1092,7 +1156,7 @@ export class FileLoader {
1092
1156
  new ParseTask(
1093
1157
  reference.normalizedFilePath,
1094
1158
  libFile,
1095
- reference.reason.copy(),
1159
+ reference.reason,
1096
1160
  false,
1097
1161
  reference.increaseDepth,
1098
1162
  reference.elideOnDepth,
@@ -1453,6 +1517,11 @@ export class FileLoader {
1453
1517
 
1454
1518
  const noPackageJsonLookups: readonly PackageJsonLookup[] = [];
1455
1519
 
1520
+ /** Releases `loader` (`FileLoader.release`) on a later turn of the event loop, while checking runs. */
1521
+ export function releaseLater(loader: FileLoader): void {
1522
+ setImmediate(() => loader.release());
1523
+ }
1524
+
1456
1525
  function addIncludeReason(processor: IncludeProcessor, task: ParseTask, reason: FileIncludeReason): void {
1457
1526
  const redirected = task.redirectedParseTask;
1458
1527
  if (redirected !== undefined) addIncludeReason(processor, redirected, reason);
@@ -89,10 +89,10 @@ import {
89
89
  isDeclarationFileName,
90
90
  toPath,
91
91
  } from './path.js';
92
- import { lastSymbolIdValue, SymbolFlags, type Symbol } from './symbol.js';
93
92
  import type { ParsedCommandLine } from './tsconfig.js';
94
93
  import { hash128String, toHex } from './xxh3.js';
95
94
  import { preparedVersion } from './parallel-parse.js';
95
+ import { getDeclarations, lastSymbolIdValue, type Symbol, SymbolFlags } from './symbol.js';
96
96
 
97
97
  /** The hash of file text that build info records as a version or signature. */
98
98
  export function computeHash(text: string): string {
@@ -1191,7 +1191,7 @@ function isModuleWithStringLiteralName(node: Node): boolean {
1191
1191
 
1192
1192
  function addReferencedFilesFromSymbol(file: SourceFile, referenced: Set<string>, symbol: Symbol | undefined): void {
1193
1193
  if (symbol === undefined) return;
1194
- for (const declaration of symbol.declarations) {
1194
+ for (const declaration of getDeclarations(symbol)) {
1195
1195
  const declarationFile = getSourceFileOfNode(declaration);
1196
1196
  if (declarationFile !== file) referenced.add(declarationFile.path);
1197
1197
  }
@@ -1259,7 +1259,7 @@ function getAmbientModuleFiles(checked: CheckedProgram): string[] {
1259
1259
  const result = new Set<string>();
1260
1260
  for (const [name, symbol] of checked.checker.globals) {
1261
1261
  if (name.length >= 2 && name.charCodeAt(0) === 0x22 && name.charCodeAt(name.length - 1) === 0x22) {
1262
- for (const declaration of symbol.declarations) result.add(getSourceFileOfNode(declaration).path);
1262
+ for (const declaration of getDeclarations(symbol)) result.add(getSourceFileOfNode(declaration).path);
1263
1263
  }
1264
1264
  }
1265
1265
  return [...result];
@@ -1620,7 +1620,7 @@ class AffectedFilesHandler {
1620
1620
  const aliased = resolveAlias(checker, exported);
1621
1621
  if (aliased === exported) continue;
1622
1622
  if ((aliased.flags & SymbolFlags.ConstEnum) !== 0) {
1623
- if (aliased.declarations.some((d) => getSourceFileOfNode(d) === affectedFile)) {
1623
+ if (getDeclarations(aliased).some((d) => getSourceFileOfNode(d) === affectedFile)) {
1624
1624
  invalidateJsFiles = true;
1625
1625
  break;
1626
1626
  }
@@ -2529,7 +2529,41 @@ export class IncrementalProgram extends CompilerProgram {
2529
2529
  }
2530
2530
 
2531
2531
  /**
2532
- * For checker threads that check `files` (from `filesToCheck`) and emit them, what the emit of each
2532
+ * The files checker threads take in a rebuild: those `filesToCheck` returns, then the files whose
2533
+ * semantic diagnostics the build info holds but whose outputs are pending (after a change of the
2534
+ * options that select outputs, or where an earlier build did not write them). Emitting a file asks
2535
+ * the checker about it, so threads that check and emit it spare this thread that work; the
2536
+ * diagnostics reported for it are still those of the build info. Where no file needs checking
2537
+ * (`checksOnCheckers` false), the threads only emit, and emit checks what it needs.
2538
+ */
2539
+ filesForCheckers(): SourceFile[] {
2540
+ const result = this.filesToCheck();
2541
+ this.checksOnCheckers = result.length > 0;
2542
+ const snapshot = this.snapshot;
2543
+ if (snapshot.options.noEmit === true || snapshot.affectedFilesPendingEmit.size === 0) return result;
2544
+ const program = this.program;
2545
+ const taken = new Set(result);
2546
+ for (const [path, emitKind] of snapshot.affectedFilesPendingEmit) {
2547
+ if (getPendingEmitKind(emitKind, 0) === 0) continue;
2548
+ const file = program.getSourceFileByPath(path);
2549
+ if (
2550
+ file === undefined ||
2551
+ taken.has(file) ||
2552
+ this.checked.skipTypeChecking(file) ||
2553
+ !program.sourceFileMayBeEmitted(file, false)
2554
+ )
2555
+ continue;
2556
+ taken.add(file);
2557
+ result.push(file);
2558
+ }
2559
+ return result;
2560
+ }
2561
+
2562
+ /** Whether the files `filesForCheckers` returned last include files to check, not only files to emit. */
2563
+ checksOnCheckers = true;
2564
+
2565
+ /**
2566
+ * For checker threads that check `files` (from `filesForCheckers`) and emit them, what the emit of each
2533
2567
  * file includes, by file index: its pending emit (`EmitFilesHandler.emitFilesIncremental`), or -1.
2534
2568
  * The incremental program's emit then takes what the threads emitted.
2535
2569
  */