tsc-ts 0.0.8 → 0.0.10

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 (68) hide show
  1. package/README.md +1 -1
  2. package/dist/api/compiler/ast.d.ts +2 -0
  3. package/dist/api/compiler/ast.js +3 -0
  4. package/dist/api/compiler/checker-calls.js +5 -1
  5. package/dist/api/compiler/checker-grammar.js +3 -2
  6. package/dist/api/compiler/checker-inference.js +8 -2
  7. package/dist/api/compiler/checker-members.js +8 -3
  8. package/dist/api/compiler/checker-source-file.d.ts +12 -0
  9. package/dist/api/compiler/checker-source-file.js +35 -0
  10. package/dist/api/compiler/checker-symbols.js +2 -1
  11. package/dist/api/compiler/checker-type-factory.js +8 -2
  12. package/dist/api/compiler/checker.d.ts +17 -1
  13. package/dist/api/compiler/checker.js +49 -1
  14. package/dist/api/compiler/compile-program.d.ts +26 -2
  15. package/dist/api/compiler/compile-program.js +100 -7
  16. package/dist/api/compiler/diagnostics.d.ts +22 -0
  17. package/dist/api/compiler/diagnostics.js +86 -4
  18. package/dist/api/compiler/file-loader.d.ts +13 -3
  19. package/dist/api/compiler/file-loader.js +106 -30
  20. package/dist/api/compiler/link-tables.d.ts +7 -0
  21. package/dist/api/compiler/link-tables.js +22 -0
  22. package/dist/api/compiler/parallel-parse.d.ts +3 -2
  23. package/dist/api/compiler/parallel-parse.js +17 -5
  24. package/dist/api/compiler/parser.js +15 -14
  25. package/dist/api/compiler/printer/emit-context.d.ts +2 -0
  26. package/dist/api/compiler/printer/emit-context.js +4 -0
  27. package/dist/api/compiler/printer/printer.d.ts +48 -2
  28. package/dist/api/compiler/printer/printer.js +238 -14
  29. package/dist/api/compiler/program-checker.d.ts +22 -0
  30. package/dist/api/compiler/program-checker.js +39 -2
  31. package/dist/api/compiler/program.d.ts +2 -6
  32. package/dist/api/compiler/program.js +5 -30
  33. package/dist/api/compiler/relations.js +10 -0
  34. package/dist/api/compiler/symbol.d.ts +1 -1
  35. package/dist/api/compiler/symbol.js +8 -10
  36. package/dist/api/library/diagnostics.d.ts +10 -0
  37. package/dist/api/library/diagnostics.js +20 -0
  38. package/package.json +9 -9
  39. package/src/compiler/ast.ts +3 -0
  40. package/src/compiler/checker-calls.ts +3 -1
  41. package/src/compiler/checker-grammar.ts +3 -2
  42. package/src/compiler/checker-inference.ts +7 -2
  43. package/src/compiler/checker-members.ts +9 -3
  44. package/src/compiler/checker-source-file.ts +34 -0
  45. package/src/compiler/checker-symbols.ts +2 -1
  46. package/src/compiler/checker-type-factory.ts +4 -2
  47. package/src/compiler/checker.ts +45 -1
  48. package/src/compiler/compile-program.ts +121 -7
  49. package/src/compiler/diagnostics.ts +84 -3
  50. package/src/compiler/file-loader.ts +106 -29
  51. package/src/compiler/incremental.ts +80 -13
  52. package/src/compiler/link-tables.ts +32 -0
  53. package/src/compiler/parallel-check.ts +326 -62
  54. package/src/compiler/parallel-emit.ts +320 -0
  55. package/src/compiler/parallel-parse.ts +16 -5
  56. package/src/compiler/parse-thread.ts +3 -0
  57. package/src/compiler/parser.ts +15 -16
  58. package/src/compiler/printer/emit-context.ts +5 -0
  59. package/src/compiler/printer/printer.ts +231 -16
  60. package/src/compiler/program-checker.ts +40 -2
  61. package/src/compiler/program.ts +5 -25
  62. package/src/compiler/relations.ts +7 -0
  63. package/src/compiler/symbol.ts +15 -10
  64. package/src/compiler/thread-entry.ts +61 -3
  65. package/src/compiler/tsc-build.ts +63 -9
  66. package/src/compiler/tsc-cli.ts +5 -0
  67. package/src/compiler/tsc-compile.ts +278 -3
  68. package/src/library/diagnostics.ts +23 -0
@@ -326,6 +326,11 @@ export class Diagnostic {
326
326
  reportsDeprecated;
327
327
  skippedOnNoEmit = false;
328
328
  repopulateInfo = undefined;
329
+ /**
330
+ * What `formatDiagnostic` gives for this diagnostic in `formattedReports.format`, where the checker
331
+ * thread that found it formatted it (`packResult`); `''` otherwise.
332
+ */
333
+ formatted = '';
329
334
  constructor(file, pos, end, message, args = []) {
330
335
  this.file = file;
331
336
  this.pos = pos;
@@ -358,6 +363,7 @@ export class Diagnostic {
358
363
  result.relatedInformation = this.relatedInformation;
359
364
  result.skippedOnNoEmit = this.skippedOnNoEmit;
360
365
  result.repopulateInfo = this.repopulateInfo;
366
+ result.formatted = this.formatted;
361
367
  return result;
362
368
  }
363
369
  }
@@ -463,10 +469,12 @@ function compareRelatedInfo(a, b) {
463
469
  export function compareDiagnostics(a, b) {
464
470
  if (a === b)
465
471
  return 0;
466
- let c = compareCodePoints(fileNameOf(a), fileNameOf(b));
467
- if (c !== 0)
468
- return c;
469
- c = a.pos - b.pos;
472
+ const c = compareCodePoints(fileNameOf(a), fileNameOf(b));
473
+ return c !== 0 ? c : compareDiagnosticsInFile(a, b);
474
+ }
475
+ /** `compareDiagnostics` of two diagnostics whose files have the same name. */
476
+ function compareDiagnosticsInFile(a, b) {
477
+ let c = a.pos - b.pos;
470
478
  if (c !== 0)
471
479
  return c;
472
480
  c = a.end - b.end;
@@ -486,6 +494,66 @@ export function compareDiagnostics(a, b) {
486
494
  return c;
487
495
  return compareRelatedInfo(a.relatedInformation, b.relatedInformation);
488
496
  }
497
+ /**
498
+ * `diagnostics` in the order of `compareDiagnostics`, equal ones in their order in `diagnostics`. File
499
+ * names are compared once per pair of files rather than once per pair of diagnostics: the distinct
500
+ * files are sorted by name, and each diagnostic sorts by its file's place in that order, then by the
501
+ * rest of `compareDiagnostics`. A program's diagnostics come a file at a time, so the files are found
502
+ * from the runs of one file.
503
+ */
504
+ export function sortDiagnostics(diagnostics) {
505
+ const n = diagnostics.length;
506
+ if (n < 2)
507
+ return diagnostics.slice();
508
+ const fileIndices = new Map();
509
+ const files = [];
510
+ const fileOf = [];
511
+ let last = undefined;
512
+ let lastIndex = -1;
513
+ for (let i = 0; i < n; i++) {
514
+ const file = diagnostics[i].file;
515
+ if (lastIndex < 0 || file !== last) {
516
+ let k = fileIndices.get(file);
517
+ if (k === undefined) {
518
+ k = files.length;
519
+ fileIndices.set(file, k);
520
+ files.push(file);
521
+ }
522
+ last = file;
523
+ lastIndex = k;
524
+ }
525
+ fileOf.push(lastIndex);
526
+ }
527
+ // Files with the same name share a rank, as they compare equal.
528
+ const nameOf = (k) => {
529
+ const file = files[k];
530
+ return file === undefined ? '' : file.fileName;
531
+ };
532
+ const byName = [];
533
+ for (let k = 0; k < files.length; k++)
534
+ byName.push(k);
535
+ byName.sort((x, y) => compareCodePoints(nameOf(x), nameOf(y)));
536
+ const rank = [];
537
+ for (let k = 0; k < files.length; k++)
538
+ rank.push(0);
539
+ for (let k = 1; k < byName.length; k++)
540
+ rank[byName[k]] = rank[byName[k - 1]] + (nameOf(byName[k]) === nameOf(byName[k - 1]) ? 0 : 1);
541
+ const order = [];
542
+ for (let i = 0; i < n; i++)
543
+ order.push(i);
544
+ order.sort((x, y) => {
545
+ const c = rank[fileOf[x]] - rank[fileOf[y]];
546
+ if (c !== 0)
547
+ return c;
548
+ const a = diagnostics[x];
549
+ const b = diagnostics[y];
550
+ return a === b ? 0 : compareDiagnosticsInFile(a, b);
551
+ });
552
+ const sorted = [];
553
+ for (const i of order)
554
+ sorted.push(diagnostics[i]);
555
+ return sorted;
556
+ }
489
557
  function equalChain(a, b) {
490
558
  if (a.length !== b.length)
491
559
  return false;
@@ -567,13 +635,27 @@ function formatDiagnosticIn(diagnostic, fileName, options) {
567
635
  result += `${categoryName(diagnostic.category)} TS${diagnostic.code}: `;
568
636
  return result + flattenDiagnosticMessage(diagnostic, options.newLine, options.locale) + options.newLine;
569
637
  }
638
+ /**
639
+ * The plain format the main thread reports a compilation's diagnostics in (`DiagnosticReporter.plainFormat`),
640
+ * which its checker threads receive a copy of and format the diagnostics they send back in
641
+ * (`Diagnostic.formatted`). Unset where diagnostics are reported with color and context, or not at all.
642
+ */
643
+ export class FormattedReports {
644
+ format = undefined;
645
+ }
646
+ export const formattedReports = new FormattedReports();
570
647
  /** `formatDiagnostic` of each diagnostic. */
571
648
  export function formatDiagnostics(diagnostics, options) {
572
649
  let result = '';
650
+ const formatted = options === formattedReports.format;
573
651
  // Sorted diagnostics come a file at a time: the relative name of the last file is kept.
574
652
  let lastFile = undefined;
575
653
  let lastName = '';
576
654
  for (const diagnostic of diagnostics) {
655
+ if (formatted && diagnostic.formatted !== '') {
656
+ result += diagnostic.formatted;
657
+ continue;
658
+ }
577
659
  const file = diagnostic.file;
578
660
  if (file !== undefined && file !== lastFile) {
579
661
  lastFile = file;
@@ -95,10 +95,10 @@ export declare class LoadedFile {
95
95
  readonly references: LoadedReference[];
96
96
  readonly resolutionsInFile: ModeAwareCache<ResolvedModule> | undefined;
97
97
  readonly typeResolutionsInFile: ModeAwareCache<ResolvedTypeReferenceDirective> | undefined;
98
- readonly processingDiagnostics: ProcessingDiagnostic[];
98
+ readonly processingDiagnostics: readonly ProcessingDiagnostic[];
99
99
  readonly importHelpersImportSpecifier: StringLiteral | undefined;
100
100
  readonly jsxRuntimeImport: JsxRuntimeImport | undefined;
101
- constructor(file: SourceFile, isLibFile: boolean, metadata: SourceFileMetadata, references: LoadedReference[], resolutionsInFile: ModeAwareCache<ResolvedModule> | undefined, typeResolutionsInFile: ModeAwareCache<ResolvedTypeReferenceDirective> | undefined, processingDiagnostics: ProcessingDiagnostic[], importHelpersImportSpecifier: StringLiteral | undefined, jsxRuntimeImport: JsxRuntimeImport | undefined);
101
+ constructor(file: SourceFile, isLibFile: boolean, metadata: SourceFileMetadata, references: LoadedReference[], resolutionsInFile: ModeAwareCache<ResolvedModule> | undefined, typeResolutionsInFile: ModeAwareCache<ResolvedTypeReferenceDirective> | undefined, processingDiagnostics: readonly ProcessingDiagnostic[], importHelpersImportSpecifier: StringLiteral | undefined, jsxRuntimeImport: JsxRuntimeImport | undefined);
102
102
  }
103
103
  /** Referenced projects, and how their sources map to declaration outputs. */
104
104
  export declare class ProjectReferenceMapper {
@@ -147,6 +147,11 @@ export declare class ProcessedFiles {
147
147
  * threads (`preparedPackageJsonLookups`); `undefined` where they may miss some.
148
148
  */
149
149
  readonly preparedPackageJsons: readonly PackageJsonLookup[] | undefined;
150
+ /**
151
+ * The files each file's imports and type reference directives added to the program, by index into
152
+ * `files`, without the file itself.
153
+ */
154
+ readonly addedFiles: readonly (readonly number[])[];
150
155
  constructor(resolver: Resolver,
151
156
  /** Libraries first, sorted, then other files in load order. */
152
157
  files: readonly SourceFile[], filesByPath: ReadonlyMap<string, SourceFile>, missingFiles: readonly string[], resolvedModules: ReadonlyMap<string, ModeAwareCache<ResolvedModule> | undefined>, typeResolutionsInFile: ReadonlyMap<string, ModeAwareCache<ResolvedTypeReferenceDirective> | undefined>, sourceFileMetadata: ReadonlyMap<string, SourceFileMetadata>, jsxRuntimeImports: ReadonlyMap<string, JsxRuntimeImport>, importHelpersImportSpecifiers: ReadonlyMap<string, StringLiteral>, libFiles: ReadonlyMap<string, LibFile>,
@@ -158,7 +163,12 @@ export declare class ProcessedFiles {
158
163
  * The `package.json` lookups made resolving the files whose resolutions were taken from parse
159
164
  * threads (`preparedPackageJsonLookups`); `undefined` where they may miss some.
160
165
  */
161
- preparedPackageJsons: readonly PackageJsonLookup[] | undefined);
166
+ preparedPackageJsons: readonly PackageJsonLookup[] | undefined,
167
+ /**
168
+ * The files each file's imports and type reference directives added to the program, by index into
169
+ * `files`, without the file itself.
170
+ */
171
+ addedFiles: readonly (readonly number[])[]);
162
172
  }
163
173
  /** The files of `processed` with `file` in place of the file at its path, for `Program.updateFile`. */
164
174
  export declare function withReplacedFile(processed: ProcessedFiles, file: SourceFile): ProcessedFiles;
@@ -165,6 +165,14 @@ class SubTasksAhead {
165
165
  this.subTasks = subTasks;
166
166
  }
167
167
  }
168
+ /** Read in place of a task's lists it has not created. */
169
+ const noParseTasks = [];
170
+ const noTraces = [];
171
+ const noProcessingDiagnostics = [];
172
+ /**
173
+ * A file to load. Its lists are created on first use: most tasks never get sub-tasks, traces or processing
174
+ * diagnostics, and large programs create hundreds of thousands of tasks.
175
+ */
168
176
  class ParseTask {
169
177
  normalizedFilePath;
170
178
  libFile;
@@ -176,19 +184,21 @@ class ParseTask {
176
184
  path = '';
177
185
  file = undefined;
178
186
  redirectedParseTask = undefined;
179
- subTasks = [];
187
+ subTasks = undefined;
180
188
  loaded = false;
181
189
  startedSubTasks = false;
182
190
  metadata = libFileMetadata;
183
191
  resolutionsInFile = undefined;
184
- resolutionsTrace = [];
192
+ resolutionsTrace = undefined;
185
193
  typeResolutionsInFile = undefined;
186
- typeResolutionsTrace = [];
187
- processingDiagnostics = [];
194
+ typeResolutionsTrace = undefined;
195
+ processingDiagnostics = undefined;
188
196
  importHelpersImportSpecifier = undefined;
189
197
  jsxRuntimeImport = undefined;
190
198
  /** The task of the same file name that was loaded instead of this one. */
191
199
  loadedTask = undefined;
200
+ /** Whether an import or a type reference directive adds the file (`ProcessedFiles.addedFiles`). */
201
+ byImport;
192
202
  constructor(normalizedFilePath, libFile, includeReason, isForAutomaticTypeDirective, increaseDepth,
193
203
  /** A JavaScript file found in `node_modules`, loaded only within `maxNodeModuleJsDepth`. */
194
204
  elideOnDepth, packageId) {
@@ -199,17 +209,37 @@ class ParseTask {
199
209
  this.increaseDepth = increaseDepth;
200
210
  this.elideOnDepth = elideOnDepth;
201
211
  this.packageId = packageId;
212
+ const kind = includeReason !== undefined ? includeReason.kind : -1;
213
+ this.byImport = kind === 0 /* FileIncludeKind.Import */ || kind === 2 /* FileIncludeKind.TypeReferenceDirective */;
202
214
  }
203
215
  addSubTask(fileName, libFile, reason, increaseDepth, elideOnDepth, packageId) {
204
- this.subTasks.push(new ParseTask(normalizePath(fileName), libFile, reason, false, increaseDepth, elideOnDepth, packageId));
216
+ (this.subTasks ??= []).push(new ParseTask(normalizePath(fileName), libFile, reason, false, increaseDepth, elideOnDepth, packageId));
217
+ }
218
+ addProcessingDiagnostic(diagnostic) {
219
+ (this.processingDiagnostics ??= []).push(diagnostic);
220
+ }
221
+ /** Where module resolution traces go under `--traceResolution`; undefined without it. */
222
+ moduleTraces(trace) {
223
+ return trace ? (this.resolutionsTrace ??= []) : undefined;
224
+ }
225
+ /** Where type reference resolution traces go under `--traceResolution`; undefined without it. */
226
+ typeTraces(trace) {
227
+ return trace ? (this.typeResolutionsTrace ??= []) : undefined;
205
228
  }
206
229
  }
230
+ const noData = [];
207
231
  /** The tasks of one path, by file name casing. */
208
232
  class ParseTaskData {
209
233
  tasks = new Map();
210
234
  lowestDepth = Number.MAX_SAFE_INTEGER;
211
235
  startedSubTasks = false;
212
236
  packageId = undefined;
237
+ /** The index of this path's file in the program's files, once collected; -1 for none. */
238
+ index = -1;
239
+ /** For a deduplicated package's path, the tasks of the copy kept (`collect`). */
240
+ keptCopy = undefined;
241
+ /** The paths the file's imports and type reference directives add, once collected. */
242
+ added = noData;
213
243
  constructor(task) {
214
244
  this.tasks.set(task.normalizedFilePath, task);
215
245
  }
@@ -321,6 +351,7 @@ export class ProcessedFiles {
321
351
  redirectFilesByPath;
322
352
  projectReferenceMapper;
323
353
  preparedPackageJsons;
354
+ addedFiles;
324
355
  constructor(resolver,
325
356
  /** Libraries first, sorted, then other files in load order. */
326
357
  files, filesByPath, missingFiles, resolvedModules, typeResolutionsInFile, sourceFileMetadata, jsxRuntimeImports, importHelpersImportSpecifiers, libFiles,
@@ -332,7 +363,12 @@ export class ProcessedFiles {
332
363
  * The `package.json` lookups made resolving the files whose resolutions were taken from parse
333
364
  * threads (`preparedPackageJsonLookups`); `undefined` where they may miss some.
334
365
  */
335
- preparedPackageJsons) {
366
+ preparedPackageJsons,
367
+ /**
368
+ * The files each file's imports and type reference directives added to the program, by index into
369
+ * `files`, without the file itself.
370
+ */
371
+ addedFiles) {
336
372
  this.resolver = resolver;
337
373
  this.files = files;
338
374
  this.filesByPath = filesByPath;
@@ -350,6 +386,7 @@ export class ProcessedFiles {
350
386
  this.redirectFilesByPath = redirectFilesByPath;
351
387
  this.projectReferenceMapper = projectReferenceMapper;
352
388
  this.preparedPackageJsons = preparedPackageJsons;
389
+ this.addedFiles = addedFiles;
353
390
  }
354
391
  }
355
392
  /** The files of `processed` with `file` in place of the file at its path, for `Program.updateFile`. */
@@ -358,7 +395,9 @@ export function withReplacedFile(processed, file) {
358
395
  files[files.findIndex((f) => f.path === file.path)] = file;
359
396
  const filesByPath = new Map(processed.filesByPath);
360
397
  filesByPath.set(file.path, file);
361
- return new ProcessedFiles(processed.resolver, files, filesByPath, processed.missingFiles, processed.resolvedModules, processed.typeResolutionsInFile, processed.sourceFileMetadata, processed.jsxRuntimeImports, processed.importHelpersImportSpecifiers, processed.libFiles, processed.sourceFilesFoundSearchingNodeModules, processed.includeProcessor.copy(file.path), processed.outputFileToProjectReferenceSource, processed.redirectTargets, processed.redirectFilesByPath, processed.projectReferenceMapper, processed.preparedPackageJsons);
398
+ return new ProcessedFiles(processed.resolver, files, filesByPath, processed.missingFiles, processed.resolvedModules, processed.typeResolutionsInFile, processed.sourceFileMetadata, processed.jsxRuntimeImports, processed.importHelpersImportSpecifiers, processed.libFiles, processed.sourceFilesFoundSearchingNodeModules, processed.includeProcessor.copy(file.path), processed.outputFileToProjectReferenceSource, processed.redirectTargets, processed.redirectFilesByPath, processed.projectReferenceMapper, processed.preparedPackageJsons,
399
+ // The file has the same references (`canReplaceFile`), and keeps its index.
400
+ processed.addedFiles);
362
401
  }
363
402
  /** Whether `file` imports the `importHelpers` module (tslib) under `options`. */
364
403
  export function needsImportHelpersImportSpecifier(file, options) {
@@ -640,7 +679,7 @@ export class FileLoader {
640
679
  return undefined;
641
680
  }
642
681
  const references = [];
643
- for (const sub of task.subTasks) {
682
+ for (const sub of task.subTasks ?? noParseTasks) {
644
683
  references.push(new LoadedReference(sub.normalizedFilePath, sub.libFile !== undefined ? sub.libFile.name : '', sub.includeReason, sub.increaseDepth, sub.elideOnDepth, sub.packageId));
645
684
  const subDepth = sub.increaseDepth ? depth + 1 : depth;
646
685
  // `run` skips these.
@@ -655,7 +694,7 @@ export class FileLoader {
655
694
  // Traces are reported in the program's order: such programs resolve on their own.
656
695
  if (file === undefined || this.options.traceResolution === true)
657
696
  return undefined;
658
- return new LoadedFile(file, task.libFile !== undefined, task.metadata, references, task.resolutionsInFile, task.typeResolutionsInFile, task.processingDiagnostics, task.importHelpersImportSpecifier, task.jsxRuntimeImport);
697
+ return new LoadedFile(file, task.libFile !== undefined, task.metadata, references, task.resolutionsInFile, task.typeResolutionsInFile, task.processingDiagnostics ?? noProcessingDiagnostics, task.importHelpersImportSpecifier, task.jsxRuntimeImport);
659
698
  }
660
699
  // ---- Project references
661
700
  loadProjectReferences() {
@@ -737,7 +776,7 @@ export class FileLoader {
737
776
  return;
738
777
  }
739
778
  const task = new ParseTask(absolute, undefined, reason, false, false, false, undefined);
740
- task.processingDiagnostics.push(ProcessingDiagnostic.explainingFileInclude('', reason, resolved.message, resolved.args));
779
+ task.addProcessingDiagnostic(ProcessingDiagnostic.explainingFileInclude('', reason, resolved.message, resolved.args));
741
780
  this.rootTasks.push(task);
742
781
  }
743
782
  isSupportedExtension(canonicalFileName) {
@@ -888,7 +927,8 @@ export class FileLoader {
888
927
  }
889
928
  if (!taskByFileName.startedSubTasks && loadSubTasks) {
890
929
  taskByFileName.startedSubTasks = true;
891
- this.start(taskByFileName.subTasks, data.lowestDepth);
930
+ if (taskByFileName.subTasks !== undefined)
931
+ this.start(taskByFileName.subTasks, data.lowestDepth);
892
932
  }
893
933
  }
894
934
  }
@@ -921,7 +961,7 @@ export class FileLoader {
921
961
  if (hasExtension(task.normalizedFilePath) && this.options.allowNonTsExtensions !== true) {
922
962
  const canonicalFileName = getCanonicalFileName(task.normalizedFilePath, fs.useCaseSensitiveFileNames);
923
963
  if (!this.isSupportedExtension(canonicalFileName)) {
924
- task.processingDiagnostics.push(hasJSFileExtension(canonicalFileName)
964
+ task.addProcessingDiagnostic(hasJSFileExtension(canonicalFileName)
925
965
  ? ProcessingDiagnostic.explainingFileInclude('', task.includeReason, 1519 /* Diagnostics.File_0_is_a_JavaScript_file_Did_you_mean_to_enable_the_allowJs_option */, [task.normalizedFilePath])
926
966
  : ProcessingDiagnostic.explainingFileInclude('', task.includeReason, 1230 /* Diagnostics.File_0_has_an_unsupported_extension_The_only_supported_extensions_are_1 */, [task.normalizedFilePath, this.supportedExtensionsList()]));
927
967
  return;
@@ -955,7 +995,7 @@ export class FileLoader {
955
995
  const reason = FileIncludeReason.reference(3 /* FileIncludeKind.LibReferenceDirective */, task.path, i, undefined);
956
996
  const name = getLibFileName(file.libReferenceDirectives[i].fileName);
957
997
  if (name === '') {
958
- task.processingDiagnostics.push(ProcessingDiagnostic.unknownReference(reason));
998
+ task.addProcessingDiagnostic(ProcessingDiagnostic.unknownReference(reason));
959
999
  continue;
960
1000
  }
961
1001
  const libFile = this.pathForLibFile(name);
@@ -975,7 +1015,7 @@ export class FileLoader {
975
1015
  else
976
1016
  task.subTasks = this.subTasksOf(loaded);
977
1017
  for (const diagnostic of loaded.processingDiagnostics)
978
- task.processingDiagnostics.push(diagnostic.copy());
1018
+ task.addProcessingDiagnostic(diagnostic.copy());
979
1019
  task.resolutionsInFile = loaded.resolutionsInFile;
980
1020
  task.typeResolutionsInFile = loaded.typeResolutionsInFile;
981
1021
  task.importHelpersImportSpecifier = loaded.importHelpersImportSpecifier;
@@ -1002,7 +1042,7 @@ export class FileLoader {
1002
1042
  const reason = FileIncludeReason.reference(1 /* FileIncludeKind.ReferenceFile */, this.toPath(containingFile), index, undefined);
1003
1043
  const resolved = this.getSourceFileFromReference(normalizePath(referencedFileName), moduleName, containingFile, reason);
1004
1044
  if (typeof resolved !== 'string') {
1005
- task.processingDiagnostics.push(ProcessingDiagnostic.explainingFileInclude('', reason, resolved.message, resolved.args));
1045
+ task.addProcessingDiagnostic(ProcessingDiagnostic.explainingFileInclude('', reason, resolved.message, resolved.args));
1006
1046
  return;
1007
1047
  }
1008
1048
  task.addSubTask(resolved, undefined, reason, false, false, undefined);
@@ -1020,14 +1060,14 @@ export class FileLoader {
1020
1060
  const mode = reference.resolutionMode !== ModuleKind.None
1021
1061
  ? reference.resolutionMode
1022
1062
  : getDefaultResolutionModeForFile(file.fileName, task.metadata, options);
1023
- const resolved = this.resolver.resolveTypeReferenceDirective(reference.fileName, containingFile, mode, redirect?.resolved, task.typeResolutionsTrace);
1063
+ const resolved = this.resolver.resolveTypeReferenceDirective(reference.fileName, containingFile, mode, redirect?.resolved, task.typeTraces(this.options.traceResolution === true));
1024
1064
  resolutions.set(modeAwareKey(reference.fileName, mode), resolved);
1025
1065
  const reason = FileIncludeReason.reference(2 /* FileIncludeKind.TypeReferenceDirective */, task.path, i, undefined);
1026
1066
  if (resolved.resolvedFileName !== '') {
1027
1067
  task.addSubTask(resolved.resolvedFileName, undefined, reason, resolved.isExternalLibraryImport, false, resolved.packageId);
1028
1068
  }
1029
1069
  else {
1030
- task.processingDiagnostics.push(ProcessingDiagnostic.unknownReference(reason));
1070
+ task.addProcessingDiagnostic(ProcessingDiagnostic.unknownReference(reason));
1031
1071
  }
1032
1072
  }
1033
1073
  task.typeResolutionsInFile = resolutions;
@@ -1039,13 +1079,13 @@ export class FileLoader {
1039
1079
  const resolutions = new Map();
1040
1080
  for (const name of names) {
1041
1081
  // Resolved without a mode: CommonJS under node16/nodenext, `import` conditions under bundler.
1042
- const resolved = this.resolver.resolveTypeReferenceDirective(name, task.normalizedFilePath, ModuleKind.None, undefined, task.typeResolutionsTrace);
1082
+ const resolved = this.resolver.resolveTypeReferenceDirective(name, task.normalizedFilePath, ModuleKind.None, undefined, task.typeTraces(this.options.traceResolution === true));
1043
1083
  resolutions.set(modeAwareKey(name, ModuleKind.None), resolved);
1044
1084
  if (resolved.resolvedFileName !== '') {
1045
1085
  task.addSubTask(resolved.resolvedFileName, undefined, FileIncludeReason.automaticTypeDirective(name, resolved.packageId), resolved.isExternalLibraryImport, false, resolved.packageId);
1046
1086
  }
1047
1087
  else {
1048
- task.processingDiagnostics.push(ProcessingDiagnostic.explainingFileInclude('', FileIncludeReason.automaticTypeDirective(name, undefined), 821 /* Diagnostics.Cannot_find_type_definition_file_for_0 */, [name]));
1088
+ task.addProcessingDiagnostic(ProcessingDiagnostic.explainingFileInclude('', FileIncludeReason.automaticTypeDirective(name, undefined), 821 /* Diagnostics.Cannot_find_type_definition_file_for_0 */, [name]));
1049
1089
  }
1050
1090
  }
1051
1091
  task.typeResolutionsInFile = resolutions;
@@ -1083,7 +1123,7 @@ export class FileLoader {
1083
1123
  if (moduleName === '')
1084
1124
  continue;
1085
1125
  const mode = getModeForUsageLocation(file.fileName, task.metadata, entry, options);
1086
- const resolved = this.resolver.resolveModuleName(moduleName, containingFile, mode, redirect?.resolved, task.resolutionsTrace);
1126
+ const resolved = this.resolver.resolveModuleName(moduleName, containingFile, mode, redirect?.resolved, task.moduleTraces(this.options.traceResolution === true));
1087
1127
  resolutions.set(modeAwareKey(moduleName, mode), resolved);
1088
1128
  const resolvedFileName = resolved.resolvedFileName;
1089
1129
  if (resolvedFileName === '')
@@ -1134,9 +1174,16 @@ export class FileLoader {
1134
1174
  const packageIdToSourceFile = new Map();
1135
1175
  const checkCasing = this.options.forceConsistentCasingInFileNames !== false;
1136
1176
  const seen = new Map();
1137
- const collectFiles = (tasks) => {
1177
+ // The paths each file's imports and type reference directives add (the tasks of each path), for
1178
+ // `ProcessedFiles.addedFiles`: recorded while collecting visits them, as their files are only known
1179
+ // once every file is collected.
1180
+ const fileData = [];
1181
+ const libData = new Map();
1182
+ const packageIdToData = new Map();
1183
+ const collectFiles = (tasks, added) => {
1138
1184
  for (let task of tasks) {
1139
1185
  const includeReason = task.includeReason;
1186
+ const byImport = task.byImport;
1140
1187
  // Automatic type directive tasks are an implementation detail, not a reason.
1141
1188
  if (task.redirectedParseTask === undefined && !task.isForAutomaticTypeDirective) {
1142
1189
  if (task.loadedTask !== undefined)
@@ -1145,6 +1192,8 @@ export class FileLoader {
1145
1192
  addIncludeReason(includeProcessor, task, includeReason);
1146
1193
  }
1147
1194
  const data = this.taskDataByPath.get(task.path);
1195
+ if (added !== undefined && data !== undefined && byImport)
1196
+ added.push(data);
1148
1197
  if (!task.loaded || data === undefined)
1149
1198
  continue;
1150
1199
  const checkedName = seen.get(data);
@@ -1169,9 +1218,9 @@ export class FileLoader {
1169
1218
  tasksSeenByNameIgnoreCase.set(lowerCasePath, task);
1170
1219
  }
1171
1220
  }
1172
- for (const trace of task.typeResolutionsTrace)
1221
+ for (const trace of task.typeResolutionsTrace ?? noTraces)
1173
1222
  host.trace(trace);
1174
- for (const trace of task.resolutionsTrace)
1223
+ for (const trace of task.resolutionsTrace ?? noTraces)
1175
1224
  host.trace(trace);
1176
1225
  const file = task.file;
1177
1226
  const packageId = data.packageId;
@@ -1186,15 +1235,19 @@ export class FileLoader {
1186
1235
  targets.push(task.normalizedFilePath);
1187
1236
  redirectFilesByPath.set(task.path, new RedirectFile(files.length + redirectFilesByPath.size, task.normalizedFilePath, task.path, packageIdFile.path));
1188
1237
  filesByPath.set(task.path, packageIdFile);
1238
+ data.keptCopy = packageIdToData.get(key);
1189
1239
  if (data.lowestDepth > 0)
1190
1240
  sourceFilesFoundSearchingNodeModules.add(task.path);
1191
1241
  continue;
1192
1242
  }
1193
- if (file !== undefined)
1243
+ if (file !== undefined) {
1194
1244
  packageIdToSourceFile.set(key, file);
1245
+ packageIdToData.set(key, data);
1246
+ }
1195
1247
  }
1196
- if (task.subTasks.length > 0)
1197
- collectFiles(task.subTasks);
1248
+ let own = undefined;
1249
+ if (task.subTasks !== undefined && task.subTasks.length > 0)
1250
+ collectFiles(task.subTasks, (own = []));
1198
1251
  const redirected = task.redirectedParseTask;
1199
1252
  if (redirected !== undefined) {
1200
1253
  outputFileToProjectReferenceSource.set(redirected.path, task.normalizedFilePath);
@@ -1202,12 +1255,12 @@ export class FileLoader {
1202
1255
  }
1203
1256
  if (task.isForAutomaticTypeDirective) {
1204
1257
  typeResolutionsInFile.set(task.path, task.typeResolutionsInFile);
1205
- for (const diagnostic of task.processingDiagnostics)
1258
+ for (const diagnostic of task.processingDiagnostics ?? noProcessingDiagnostics)
1206
1259
  includeProcessor.addProcessingDiagnostic(diagnostic);
1207
1260
  continue;
1208
1261
  }
1209
1262
  const path = task.path;
1210
- for (const diagnostic of task.processingDiagnostics)
1263
+ for (const diagnostic of task.processingDiagnostics ?? noProcessingDiagnostics)
1211
1264
  includeProcessor.addProcessingDiagnostic(diagnostic);
1212
1265
  if (file === undefined) {
1213
1266
  missingFiles.push(task.normalizedFilePath);
@@ -1215,11 +1268,15 @@ export class FileLoader {
1215
1268
  }
1216
1269
  if (task.libFile !== undefined) {
1217
1270
  libFiles.push(file);
1271
+ libData.set(file, data);
1218
1272
  libFilesByPath.set(path, task.libFile);
1219
1273
  }
1220
1274
  else {
1221
1275
  files.push(file);
1276
+ fileData.push(data);
1222
1277
  }
1278
+ if (own !== undefined)
1279
+ data.added = own;
1223
1280
  filesByPath.set(path, file);
1224
1281
  resolvedModules.set(path, task.resolutionsInFile);
1225
1282
  typeResolutionsInFile.set(path, task.typeResolutionsInFile);
@@ -1233,7 +1290,7 @@ export class FileLoader {
1233
1290
  sourceFilesFoundSearchingNodeModules.add(path);
1234
1291
  }
1235
1292
  };
1236
- collectFiles(this.rootTasks);
1293
+ collectFiles(this.rootTasks, undefined);
1237
1294
  const priorities = new Map();
1238
1295
  for (const file of libFiles)
1239
1296
  priorities.set(file, this.libFilePriority(file));
@@ -1241,6 +1298,25 @@ export class FileLoader {
1241
1298
  const allFiles = [...libFiles, ...files];
1242
1299
  for (const redirect of redirectFilesByPath.values())
1243
1300
  redirect.index += libFiles.length;
1301
+ // The files a file adds, without reading its resolutions again or looking up their paths.
1302
+ const dataOfFiles = [];
1303
+ for (const file of libFiles)
1304
+ dataOfFiles.push(libData.get(file));
1305
+ for (const data of fileData)
1306
+ dataOfFiles.push(data);
1307
+ for (let i = 0; i < dataOfFiles.length; i++)
1308
+ dataOfFiles[i].index = i;
1309
+ const addedFiles = [];
1310
+ for (let i = 0; i < dataOfFiles.length; i++) {
1311
+ const added = [];
1312
+ for (const data of dataOfFiles[i].added) {
1313
+ const kept = data.keptCopy;
1314
+ const k = kept !== undefined ? kept.index : data.index;
1315
+ if (k >= 0 && k !== i)
1316
+ added.push(k);
1317
+ }
1318
+ addedFiles.push(added);
1319
+ }
1244
1320
  const keys = [...this.libResolutions.keys()].sort();
1245
1321
  for (const key of keys) {
1246
1322
  const resolution = this.libResolutions.get(key);
@@ -1252,7 +1328,7 @@ export class FileLoader {
1252
1328
  for (const trace of resolution.trace)
1253
1329
  host.trace(trace);
1254
1330
  }
1255
- return new ProcessedFiles(this.resolver, allFiles, filesByPath, missingFiles, resolvedModules, typeResolutionsInFile, sourceFileMetadata, jsxRuntimeImports, importHelpersImportSpecifiers, libFilesByPath, sourceFilesFoundSearchingNodeModules, includeProcessor, outputFileToProjectReferenceSource, redirectTargets, redirectFilesByPath, this.mapper, this.tookPreparedResolutions ? preparedPackageJsonLookups() : noPackageJsonLookups);
1331
+ return new ProcessedFiles(this.resolver, allFiles, filesByPath, missingFiles, resolvedModules, typeResolutionsInFile, sourceFileMetadata, jsxRuntimeImports, importHelpersImportSpecifiers, libFilesByPath, sourceFilesFoundSearchingNodeModules, includeProcessor, outputFileToProjectReferenceSource, redirectTargets, redirectFilesByPath, this.mapper, this.tookPreparedResolutions ? preparedPackageJsonLookups() : noPackageJsonLookups, addedFiles);
1256
1332
  }
1257
1333
  }
1258
1334
  const noPackageJsonLookups = [];
@@ -58,6 +58,13 @@ export declare class ClusteredIntLinkTable {
58
58
  set(id: number, value: number): void;
59
59
  private pageOf;
60
60
  }
61
+ /** Ids in pages of `IdSetPaging.Ids` ids, one bit each; a page is created by the first id added to it. */
62
+ export declare class PagedIdSet {
63
+ readonly pages: (Int32Array | undefined)[];
64
+ has(id: number): boolean;
65
+ add(id: number): void;
66
+ clear(): void;
67
+ }
61
68
  /**
62
69
  * A page of a `CompactSymbolLinkTable`: one bit per id of the page in eight 32-id words, the number
63
70
  * of symbols stored before each word, and the symbols in id order. The words are fields, so a
@@ -146,6 +146,28 @@ export class ClusteredIntLinkTable {
146
146
  return this.lastPage;
147
147
  }
148
148
  }
149
+ /** Ids in pages of `IdSetPaging.Ids` ids, one bit each; a page is created by the first id added to it. */
150
+ export class PagedIdSet {
151
+ pages = [];
152
+ has(id) {
153
+ const page = this.pages[id >> 13 /* IdSetPaging.Bits */];
154
+ return page !== undefined && (page[(id >> 5) & 255 /* IdSetPaging.WordMask */] & (1 << (id & 31))) !== 0;
155
+ }
156
+ add(id) {
157
+ const index = id >> 13 /* IdSetPaging.Bits */;
158
+ let page = this.pages[index];
159
+ if (page === undefined) {
160
+ while (this.pages.length <= index)
161
+ this.pages.push(undefined);
162
+ page = new Int32Array(256 /* IdSetPaging.Words */);
163
+ this.pages[index] = page;
164
+ }
165
+ page[(id >> 5) & 255 /* IdSetPaging.WordMask */] |= 1 << (id & 31);
166
+ }
167
+ clear() {
168
+ this.pages.length = 0;
169
+ }
170
+ }
149
171
  /** The number of set bits of a 32-bit value. */
150
172
  function bitCount(x) {
151
173
  x = x - ((x >>> 1) & 0x55555555);
@@ -128,7 +128,7 @@ export declare function fileSize(fileName: string): number;
128
128
  * Then, for the same reason, large files, one per chunk: root files (TypeScript's 3 MB `checker.ts`,
129
129
  * which in a chunk of root files kept one thread busy after the others were done) and the files the
130
130
  * parse threads found (`csstype`'s 0.9 MB of declarations, found through React's). The other files go
131
- * out in program order, in chunks of up to `maxChunk`.
131
+ * out in program order, in chunks of up to `maxChunk` files and about `maxChunkBytes` of text.
132
132
  */
133
133
  export declare class ParseQueue {
134
134
  private readonly libraries;
@@ -148,7 +148,8 @@ export declare class ParseQueue {
148
148
  left(): number;
149
149
  /**
150
150
  * The next chunk for one of `threads` parse threads, or `undefined` when nothing is left. With
151
- * `full`, other files only go out `maxChunk` at a time, and stay queued until there are as many.
151
+ * `full`, other files only go out in full chunks, `maxChunk` files or `maxChunkBytes` of text, and stay
152
+ * queued until there are as many.
152
153
  */
153
154
  next(threads: number, full?: boolean): LoadMessage | undefined;
154
155
  }
@@ -187,6 +187,12 @@ export function fileSize(fileName) {
187
187
  const maxChunk = 16;
188
188
  /** Files from this size (bytes) on take a parse thread 25 ms or more, and go out ahead of others. */
189
189
  const largeFile = 256 * 1024;
190
+ /**
191
+ * The most text (bytes) a chunk of other files holds, about one large file's: a chunk ends with the file
192
+ * that reaches it. Sixteen of tsc-ts's own compiler sources, 50-200 KB each, made one chunk that kept its
193
+ * thread busy for 30-45 ms after the others were done.
194
+ */
195
+ const maxChunkBytes = largeFile;
190
196
  /**
191
197
  * The files to hand out to parse threads, each queued once. Library files go out first, one per
192
198
  * chunk, also those found later through `/// <reference lib>`: a large one (`lib.dom.d.ts`) takes a
@@ -194,7 +200,7 @@ const largeFile = 256 * 1024;
194
200
  * Then, for the same reason, large files, one per chunk: root files (TypeScript's 3 MB `checker.ts`,
195
201
  * which in a chunk of root files kept one thread busy after the others were done) and the files the
196
202
  * parse threads found (`csstype`'s 0.9 MB of declarations, found through React's). The other files go
197
- * out in program order, in chunks of up to `maxChunk`.
203
+ * out in program order, in chunks of up to `maxChunk` files and about `maxChunkBytes` of text.
198
204
  */
199
205
  export class ParseQueue {
200
206
  libraries = new LoadJobs();
@@ -238,7 +244,8 @@ export class ParseQueue {
238
244
  }
239
245
  /**
240
246
  * The next chunk for one of `threads` parse threads, or `undefined` when nothing is left. With
241
- * `full`, other files only go out `maxChunk` at a time, and stay queued until there are as many.
247
+ * `full`, other files only go out in full chunks, `maxChunk` files or `maxChunkBytes` of text, and stay
248
+ * queued until there are as many.
242
249
  */
243
250
  next(threads, full = false) {
244
251
  const libraries = this.libraries;
@@ -263,11 +270,16 @@ export class ParseQueue {
263
270
  }
264
271
  const queue = this.others;
265
272
  const left = queue.names.length - this.head;
266
- if (left <= 0 || (full && left < maxChunk))
273
+ if (left <= 0)
267
274
  return undefined;
268
- const size = full ? maxChunk : Math.min(maxChunk, Math.max(1, Math.floor(left / threads)));
275
+ const most = full ? maxChunk : Math.min(maxChunk, Math.max(1, Math.floor(left / threads)));
269
276
  const start = this.head;
270
- const end = start + size;
277
+ let end = start;
278
+ let bytes = 0;
279
+ while (end < queue.names.length && end - start < most && bytes < maxChunkBytes)
280
+ bytes += queue.sizes[end++];
281
+ if (full && end - start < maxChunk && bytes < maxChunkBytes)
282
+ return undefined;
271
283
  this.head = end;
272
284
  return {
273
285
  stop: false,