tsc-ts 0.0.5 → 0.0.7

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 (203) hide show
  1. package/README.md +1 -1
  2. package/dist/api/compiler/ast.d.ts +67 -27
  3. package/dist/api/compiler/ast.js +156 -55
  4. package/dist/api/compiler/binder-utilities.js +4 -3
  5. package/dist/api/compiler/binder.js +14 -13
  6. package/dist/api/compiler/checker-calls.js +7 -6
  7. package/dist/api/compiler/checker-contextual.js +1 -1
  8. package/dist/api/compiler/checker-declaration-order.js +2 -1
  9. package/dist/api/compiler/checker-declarations.js +14 -14
  10. package/dist/api/compiler/checker-declared-types.d.ts +1 -1
  11. package/dist/api/compiler/checker-declared-types.js +12 -11
  12. package/dist/api/compiler/checker-decorators.js +3 -3
  13. package/dist/api/compiler/checker-deprecation.js +17 -18
  14. package/dist/api/compiler/checker-destructuring.d.ts +1 -1
  15. package/dist/api/compiler/checker-destructuring.js +3 -3
  16. package/dist/api/compiler/checker-elaboration.js +8 -7
  17. package/dist/api/compiler/checker-emit-helpers.d.ts +2 -1
  18. package/dist/api/compiler/checker-emit-helpers.js +5 -4
  19. package/dist/api/compiler/checker-emit-resolver.d.ts +1 -1
  20. package/dist/api/compiler/checker-emit-resolver.js +5 -4
  21. package/dist/api/compiler/checker-grammar.js +23 -9
  22. package/dist/api/compiler/checker-heritage.d.ts +1 -1
  23. package/dist/api/compiler/checker-heritage.js +14 -13
  24. package/dist/api/compiler/checker-inference.d.ts +21 -11
  25. package/dist/api/compiler/checker-inference.js +57 -34
  26. package/dist/api/compiler/checker-javascript.d.ts +1 -1
  27. package/dist/api/compiler/checker-javascript.js +5 -4
  28. package/dist/api/compiler/checker-jsx.d.ts +1 -1
  29. package/dist/api/compiler/checker-jsx.js +4 -4
  30. package/dist/api/compiler/checker-literals.js +2 -2
  31. package/dist/api/compiler/checker-members.d.ts +32 -3
  32. package/dist/api/compiler/checker-members.js +240 -53
  33. package/dist/api/compiler/checker-modules.d.ts +15 -1
  34. package/dist/api/compiler/checker-modules.js +86 -14
  35. package/dist/api/compiler/checker-object-literals.d.ts +1 -1
  36. package/dist/api/compiler/checker-object-literals.js +11 -7
  37. package/dist/api/compiler/checker-overloads.d.ts +1 -1
  38. package/dist/api/compiler/checker-overloads.js +4 -3
  39. package/dist/api/compiler/checker-property-access.d.ts +1 -1
  40. package/dist/api/compiler/checker-property-access.js +2 -2
  41. package/dist/api/compiler/checker-services.js +2 -2
  42. package/dist/api/compiler/checker-signatures.d.ts +1 -1
  43. package/dist/api/compiler/checker-signatures.js +9 -8
  44. package/dist/api/compiler/checker-symbol-types.d.ts +2 -18
  45. package/dist/api/compiler/checker-symbol-types.js +22 -952
  46. package/dist/api/compiler/checker-symbols.d.ts +2 -2
  47. package/dist/api/compiler/checker-symbols.js +29 -27
  48. package/dist/api/compiler/checker-type-factory.d.ts +2 -2
  49. package/dist/api/compiler/checker-type-factory.js +57 -16
  50. package/dist/api/compiler/checker-type-nodes.d.ts +1 -1
  51. package/dist/api/compiler/checker-type-nodes.js +2 -2
  52. package/dist/api/compiler/checker-type-operators.d.ts +1 -1
  53. package/dist/api/compiler/checker-type-operators.js +5 -5
  54. package/dist/api/compiler/checker-types.d.ts +73 -7
  55. package/dist/api/compiler/checker-types.js +220 -43
  56. package/dist/api/compiler/checker-unused.d.ts +1 -1
  57. package/dist/api/compiler/checker-unused.js +3 -3
  58. package/dist/api/compiler/checker.d.ts +45 -8
  59. package/dist/api/compiler/checker.js +46 -9
  60. package/dist/api/compiler/diagnostics.d.ts +2 -8
  61. package/dist/api/compiler/diagnostics.js +13 -45
  62. package/dist/api/compiler/file-include.d.ts +35 -8
  63. package/dist/api/compiler/file-include.js +81 -18
  64. package/dist/api/compiler/file-loader.d.ts +33 -4
  65. package/dist/api/compiler/file-loader.js +90 -24
  66. package/dist/api/compiler/instantiation.d.ts +1 -1
  67. package/dist/api/compiler/instantiation.js +86 -50
  68. package/dist/api/compiler/link-tables.d.ts +69 -0
  69. package/dist/api/compiler/link-tables.js +236 -0
  70. package/dist/api/compiler/name-resolver.js +3 -3
  71. package/dist/api/compiler/node-builder-names.d.ts +1 -1
  72. package/dist/api/compiler/node-builder-names.js +12 -12
  73. package/dist/api/compiler/node-builder-pseudo.d.ts +1 -1
  74. package/dist/api/compiler/node-builder-pseudo.js +2 -1
  75. package/dist/api/compiler/node-builder.d.ts +1 -1
  76. package/dist/api/compiler/node-builder.js +16 -16
  77. package/dist/api/compiler/parallel-parse.d.ts +2 -0
  78. package/dist/api/compiler/parallel-parse.js +7 -1
  79. package/dist/api/compiler/parser.d.ts +33 -16
  80. package/dist/api/compiler/parser.js +127 -98
  81. package/dist/api/compiler/printer/emit-context.d.ts +5 -2
  82. package/dist/api/compiler/printer/emit-context.js +19 -13
  83. package/dist/api/compiler/printer/factory-base.js +8 -8
  84. package/dist/api/compiler/printer/factory.js +4 -4
  85. package/dist/api/compiler/printer/printer.js +6 -6
  86. package/dist/api/compiler/program-checker.d.ts +5 -0
  87. package/dist/api/compiler/program-checker.js +14 -1
  88. package/dist/api/compiler/program.js +9 -1
  89. package/dist/api/compiler/relations.d.ts +1 -1
  90. package/dist/api/compiler/relations.js +18 -13
  91. package/dist/api/compiler/reparser.js +13 -5
  92. package/dist/api/compiler/symbol-accessibility.d.ts +1 -1
  93. package/dist/api/compiler/symbol-accessibility.js +123 -26
  94. package/dist/api/compiler/symbol.d.ts +45 -3
  95. package/dist/api/compiler/symbol.js +121 -10
  96. package/dist/api/compiler/transformers/alias-references.d.ts +1 -1
  97. package/dist/api/compiler/transformers/alias-references.js +2 -1
  98. package/dist/api/compiler/transformers/class-fields.js +3 -3
  99. package/dist/api/compiler/transformers/commonjs-module.js +3 -3
  100. package/dist/api/compiler/transformers/declarations-diagnostics.js +2 -1
  101. package/dist/api/compiler/transformers/declarations-pseudo.js +6 -4
  102. package/dist/api/compiler/transformers/declarations-syntactic.d.ts +1 -1
  103. package/dist/api/compiler/transformers/declarations-syntactic.js +9 -9
  104. package/dist/api/compiler/transformers/declarations-tracker.d.ts +1 -1
  105. package/dist/api/compiler/transformers/declarations-tracker.js +3 -2
  106. package/dist/api/compiler/transformers/declarations.js +6 -5
  107. package/dist/api/compiler/transformers/module.js +2 -2
  108. package/dist/api/compiler/transformers/optional-chain.js +3 -3
  109. package/dist/api/compiler/transformers/reference-resolver.d.ts +2 -1
  110. package/dist/api/compiler/transformers/reference-resolver.js +26 -24
  111. package/dist/api/compiler/transformers/subtree-facts.d.ts +1 -0
  112. package/dist/api/compiler/transformers/subtree-facts.js +9 -7
  113. package/dist/api/compiler/transformers/syntax-facts.d.ts +1 -0
  114. package/dist/api/compiler/transformers/syntax-facts.js +9 -5
  115. package/dist/api/compiler/transformers/tagged-template.js +2 -2
  116. package/dist/api/compiler/transformers/type-eraser.js +2 -2
  117. package/dist/api/compiler/transformers/type-serialization.js +12 -12
  118. package/dist/api/compiler/transformers/visitor-base.js +3 -3
  119. package/dist/api/compiler/tsconfig.js +2 -2
  120. package/package.json +9 -9
  121. package/src/compiler/ast.ts +211 -78
  122. package/src/compiler/binder-utilities.ts +4 -3
  123. package/src/compiler/binder.ts +26 -16
  124. package/src/compiler/checker-calls.ts +8 -6
  125. package/src/compiler/checker-contextual.ts +1 -1
  126. package/src/compiler/checker-declaration-order.ts +2 -2
  127. package/src/compiler/checker-declarations.ts +21 -14
  128. package/src/compiler/checker-declared-types.ts +12 -12
  129. package/src/compiler/checker-decorators.ts +3 -3
  130. package/src/compiler/checker-deprecation.ts +17 -21
  131. package/src/compiler/checker-destructuring.ts +3 -3
  132. package/src/compiler/checker-elaboration.ts +8 -8
  133. package/src/compiler/checker-emit-helpers.ts +5 -4
  134. package/src/compiler/checker-emit-resolver.ts +5 -5
  135. package/src/compiler/checker-grammar.ts +22 -8
  136. package/src/compiler/checker-heritage.ts +21 -14
  137. package/src/compiler/checker-inference.ts +66 -34
  138. package/src/compiler/checker-javascript.ts +5 -5
  139. package/src/compiler/checker-jsx.ts +12 -8
  140. package/src/compiler/checker-literals.ts +2 -2
  141. package/src/compiler/checker-members.ts +255 -47
  142. package/src/compiler/checker-modules.ts +115 -14
  143. package/src/compiler/checker-object-literals.ts +22 -6
  144. package/src/compiler/checker-overloads.ts +6 -6
  145. package/src/compiler/checker-property-access.ts +2 -2
  146. package/src/compiler/checker-services.ts +2 -2
  147. package/src/compiler/checker-signatures.ts +9 -9
  148. package/src/compiler/checker-symbol-types.ts +20 -940
  149. package/src/compiler/checker-symbols.ts +42 -35
  150. package/src/compiler/checker-type-factory.ts +53 -16
  151. package/src/compiler/checker-type-nodes.ts +2 -2
  152. package/src/compiler/checker-type-operators.ts +13 -5
  153. package/src/compiler/checker-types.ts +223 -43
  154. package/src/compiler/checker-unused.ts +3 -3
  155. package/src/compiler/checker.ts +50 -9
  156. package/src/compiler/decoder.ts +5 -4
  157. package/src/compiler/diagnostics.ts +14 -48
  158. package/src/compiler/encoder.ts +10 -5
  159. package/src/compiler/file-include.ts +85 -17
  160. package/src/compiler/file-loader.ts +104 -35
  161. package/src/compiler/incremental.ts +39 -5
  162. package/src/compiler/instantiation.ts +99 -55
  163. package/src/compiler/link-tables.ts +245 -0
  164. package/src/compiler/name-resolver.ts +3 -3
  165. package/src/compiler/node-builder-names.ts +21 -19
  166. package/src/compiler/node-builder-pseudo.ts +2 -2
  167. package/src/compiler/node-builder.ts +24 -16
  168. package/src/compiler/parallel-check.ts +11 -8
  169. package/src/compiler/parallel-parse.ts +8 -1
  170. package/src/compiler/parse-thread.ts +0 -4
  171. package/src/compiler/parser.ts +173 -93
  172. package/src/compiler/printer/emit-context.ts +20 -15
  173. package/src/compiler/printer/factory-base.ts +14 -7
  174. package/src/compiler/printer/factory.ts +5 -3
  175. package/src/compiler/printer/printer.ts +8 -6
  176. package/src/compiler/program-checker.ts +12 -1
  177. package/src/compiler/program.ts +8 -1
  178. package/src/compiler/relations.ts +20 -12
  179. package/src/compiler/reparser.ts +14 -4
  180. package/src/compiler/symbol-accessibility.ts +120 -25
  181. package/src/compiler/symbol.ts +127 -9
  182. package/src/compiler/transformers/alias-references.ts +2 -2
  183. package/src/compiler/transformers/class-fields.ts +12 -2
  184. package/src/compiler/transformers/commonjs-module.ts +3 -2
  185. package/src/compiler/transformers/declarations-diagnostics.ts +2 -1
  186. package/src/compiler/transformers/declarations-pseudo.ts +9 -5
  187. package/src/compiler/transformers/declarations-syntactic.ts +17 -9
  188. package/src/compiler/transformers/declarations-tracker.ts +3 -3
  189. package/src/compiler/transformers/declarations.ts +7 -7
  190. package/src/compiler/transformers/module.ts +2 -1
  191. package/src/compiler/transformers/optional-chain.ts +5 -2
  192. package/src/compiler/transformers/reference-resolver.ts +37 -25
  193. package/src/compiler/transformers/subtree-facts.ts +15 -6
  194. package/src/compiler/transformers/syntax-facts.ts +10 -5
  195. package/src/compiler/transformers/tagged-template.ts +2 -2
  196. package/src/compiler/transformers/type-eraser.ts +2 -1
  197. package/src/compiler/transformers/type-serialization.ts +12 -12
  198. package/src/compiler/transformers/visitor-base.ts +10 -5
  199. package/src/compiler/tsc-build.ts +17 -13
  200. package/src/compiler/tsc-cli.ts +9 -6
  201. package/src/compiler/tsc-compile.ts +16 -7
  202. package/src/compiler/tsc-watch.ts +94 -26
  203. package/src/compiler/tsconfig.ts +2 -1
@@ -2,7 +2,7 @@
2
2
  * Diagnostics: message lookup and localization, the `Diagnostic` type, and tsc's plain and
3
3
  * pretty diagnostic output.
4
4
  */
5
- import { CharacterCodes, isDigit, isUnicodeWhiteSpace, utf8Length } from './character-codes.js';
5
+ import { isDigit, isUnicodeWhiteSpace, utf8Length } from './character-codes.js';
6
6
  import { Locale, translations } from './diagnostic-locales.js';
7
7
  import { Diagnostics, messageCodes, messageFlags, messageKeys, messageTexts } from './diagnostic-messages.js';
8
8
  import { getPathComponentsRelativeTo, getPathFromPathComponents, isRootedDiskPath, pathIsAbsolute } from './path.js';
@@ -146,15 +146,15 @@ function toWellFormed(text: string): string {
146
146
  /**
147
147
  * Where this thread computes the line starts and UTF-8 offsets of files that may be shared with other
148
148
  * threads (`useThreadTextCaches`): a copy of each such file, by file, that computes them in place.
149
- * Files leave the parser with line starts, except declaration files, and without UTF-8 offsets.
149
+ * Files leave the parser without line starts and UTF-8 offsets, except JSON files, which have line
150
+ * starts.
150
151
  */
151
152
  let threadCopies: Map<DiagnosticFile, DiagnosticFile> | undefined = undefined;
152
153
 
153
154
  /**
154
155
  * Makes this thread compute the caches of files that do not have them yet in copies of its own: the
155
- * files may be published (immutable) and shared with other threads. Declaration files leave the
156
- * parser without them (`Parser.parseSourceFile`): they make up most of the text of a typical program,
157
- * and are rarely checked or pointed into by a diagnostic.
156
+ * files may be published (immutable) and shared with other threads. Files leave the parser without
157
+ * them (`Parser.parseSourceFile`): most files are never pointed into by a diagnostic.
158
158
  */
159
159
  export function useThreadTextCaches(): void {
160
160
  if (threadCopies === undefined) threadCopies = new Map<DiagnosticFile, DiagnosticFile>();
@@ -174,21 +174,15 @@ function threadCopyOf(file: DiagnosticFile): DiagnosticFile | undefined {
174
174
  return copy;
175
175
  }
176
176
 
177
- /** The position of the first code unit at or after `pos` that is a CR or below, or not ASCII; or `end`. */
178
- function skipPlainASCII(units: Uint16Array, pos: number, end: number): number {
179
- for (let i = pos | 0; i < end; i = (i + 1) | 0) {
180
- const c = units[i] | 0;
181
- if (c <= CharacterCodes.carriageReturn || c >= 0x80) return i;
182
- }
183
- return end;
184
- }
177
+ /** The empty value of a file's position tables until they are computed. */
178
+ const noNumbers: readonly number[] = [];
185
179
 
186
180
  /** The text of a file diagnostics point into. */
187
181
  export class DiagnosticFile {
188
182
  readonly fileName: string;
189
183
  readonly text: string;
190
184
  // Computed on first use; never empty once computed.
191
- private lineStarts: number[] = [];
185
+ private lineStarts: readonly number[] = noNumbers;
192
186
  /** Whether this is a thread's copy of a possibly shared file (`threadCopyOf`). */
193
187
  isThreadCopy = false;
194
188
 
@@ -206,36 +200,6 @@ export class DiagnosticFile {
206
200
  if (this.lineStarts.length === 0) this.lineStarts = computeLineStarts(this.text);
207
201
  }
208
202
 
209
- /**
210
- * Like `computeCaches`, from the text's UTF-16 code units `units[0, text.length)`, so the text
211
- * itself is neither searched nor copied.
212
- */
213
- computeCachesFromUnits(units: Uint16Array): void {
214
- const text = this.text;
215
- // ASCII texts are searched faster than walked.
216
- if (this.lineStarts.length !== 0 || Buffer.byteLength(text, 'utf8') === text.length) {
217
- this.computeCaches();
218
- return;
219
- }
220
- const length = text.length | 0;
221
- const lineStarts: number[] = [0];
222
- // Visit only the code units that may break a line; `skipPlainASCII` runs over the rest without
223
- // calls, so native builds keep its loop on registers. A CR followed by an LF leaves the line start
224
- // to the LF.
225
- for (let i = skipPlainASCII(units, 0, length); i < length; i = skipPlainASCII(units, (i + 1) | 0, length)) {
226
- const ch = units[i] | 0;
227
- if (
228
- ch === CharacterCodes.lineFeed ||
229
- (ch === CharacterCodes.carriageReturn &&
230
- (i + 1 >= length || (units[(i + 1) | 0] | 0) !== CharacterCodes.lineFeed)) ||
231
- ch === CharacterCodes.lineSeparator ||
232
- ch === CharacterCodes.paragraphSeparator
233
- )
234
- lineStarts.push(i + 1);
235
- }
236
- this.lineStarts = lineStarts;
237
- }
238
-
239
203
  /** Start offsets of each line, split at CR, LF, CRLF, LS and PS. */
240
204
  getLineStarts(): readonly number[] {
241
205
  if (this.lineStarts.length === 0) {
@@ -249,8 +213,8 @@ export class DiagnosticFile {
249
213
  // The non-ASCII characters, in order: their UTF-16 offsets, UTF-8 lengths, and the UTF-8 bytes
250
214
  // beyond one per UTF-16 code unit of the text up to and including each. Unset until first used.
251
215
  private nonASCIIStarts: number[] | undefined = undefined;
252
- private nonASCIILengths: number[] = [];
253
- private extraBytes: number[] = [];
216
+ private nonASCIILengths: readonly number[] = noNumbers;
217
+ private extraBytes: readonly number[] = noNumbers;
254
218
 
255
219
  private getNonASCIIStarts(): number[] {
256
220
  let starts = this.nonASCIIStarts;
@@ -260,8 +224,8 @@ export class DiagnosticFile {
260
224
  if (Buffer.byteLength(text, 'utf8') !== text.length) {
261
225
  // Scanning the UTF-8 encoding is faster than reading each code unit.
262
226
  const bytes = Buffer.from(text, 'utf8');
263
- const lengths = this.nonASCIILengths;
264
- const extraBytes = this.extraBytes;
227
+ const lengths: number[] = [];
228
+ const extraBytes: number[] = [];
265
229
  let extra = 0;
266
230
  for (let i = 0; i < bytes.length; i++) {
267
231
  const b = bytes[i]!;
@@ -274,6 +238,8 @@ export class DiagnosticFile {
274
238
  extraBytes.push(extra);
275
239
  i += length - 1;
276
240
  }
241
+ this.nonASCIILengths = lengths;
242
+ this.extraBytes = extraBytes;
277
243
  }
278
244
  this.nonASCIIStarts = starts;
279
245
  }
@@ -186,6 +186,11 @@ import {
186
186
  YieldExpression,
187
187
  BigIntLiteral,
188
188
  Identifier,
189
+ propertyAssignmentPostfixToken,
190
+ propertyAssignmentType,
191
+ callQuestionDotToken,
192
+ propertyAssignmentModifiers,
193
+ callTypeArguments,
189
194
  } from './ast.js';
190
195
  import { getJSDoc } from './parser.js';
191
196
  import { SyntaxKind } from './syntax-kind.js';
@@ -883,8 +888,8 @@ function childrenPropertyMask(node: Node): number {
883
888
  case SyntaxKind.CallExpression:
884
889
  return node instanceof CallExpression
885
890
  ? ((node as CallExpression).expression !== undefined ? 1 : 0) |
886
- ((node as CallExpression).questionDotToken !== undefined ? 2 : 0) |
887
- ((node as CallExpression).typeArguments !== undefined ? 4 : 0) |
891
+ (callQuestionDotToken(node as CallExpression) !== undefined ? 2 : 0) |
892
+ (callTypeArguments(node as CallExpression) !== undefined ? 4 : 0) |
888
893
  ((node as CallExpression).arguments !== undefined ? 8 : 0)
889
894
  : 0;
890
895
  case SyntaxKind.NewExpression:
@@ -938,10 +943,10 @@ function childrenPropertyMask(node: Node): number {
938
943
  return node instanceof SpreadAssignment ? ((node as SpreadAssignment).expression !== undefined ? 1 : 0) : 0;
939
944
  case SyntaxKind.PropertyAssignment:
940
945
  return node instanceof PropertyAssignment
941
- ? (hasModifiers((node as PropertyAssignment).modifiers) ? 1 : 0) |
946
+ ? (hasModifiers(propertyAssignmentModifiers(node as PropertyAssignment)) ? 1 : 0) |
942
947
  ((node as PropertyAssignment).name !== undefined ? 2 : 0) |
943
- ((node as PropertyAssignment).postfixToken !== undefined ? 4 : 0) |
944
- ((node as PropertyAssignment).type !== undefined ? 8 : 0) |
948
+ (propertyAssignmentPostfixToken(node as PropertyAssignment) !== undefined ? 4 : 0) |
949
+ (propertyAssignmentType(node as PropertyAssignment) !== undefined ? 8 : 0) |
945
950
  ((node as PropertyAssignment).initializer !== undefined ? 16 : 0)
946
951
  : 0;
947
952
  case SyntaxKind.ShorthandPropertyAssignment:
@@ -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
  */