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
package/README.md CHANGED
@@ -31,7 +31,7 @@ npx tsc-ts -p tsconfig.json
31
31
  npx tsc-ts --noEmit src/index.ts
32
32
  ```
33
33
 
34
- `tsc-ts --api` serves the TypeScript API over stdin and stdout, like `tsc --api`. On Windows, `--api --pipe \\.\pipe\<name>` serves it over a named pipe it creates, as `tsc --api --pipe` does, for clients that connect to the pipe (such as scriptc under Node.js); only the native executable supports `--pipe`.
34
+ `tsc-ts --api` serves the TypeScript API over stdin and stdout, like `tsc --api`. On Windows, `--api --pipe \\.\pipe\<name>` serves it over a named pipe it creates, as `tsc --api --pipe` does, for clients that connect to the pipe (such as scriptc under Node.js); only the native executable supports `--pipe`. On macOS and Linux, `--api --listen <path>` serves it on a Unix socket it creates, with mode 0600, to one client of the same user at a time, each until the client closes its end. Each client gets the answers a new `tsc-ts --api` process would give, except that symbol ids continue from earlier clients, and the server reads every file through the client again, but it keeps parsed files between clients and reuses those whose text is unchanged, along with the encoding `getSourceFile` sends for each, so a client that opens the same project again loads it faster. The server exits when no client connects for 60 seconds (`--idle-exit <seconds>` sets the time), or after a client when its resident memory is above 2.5 times what it held after its first client (`TSC_TS_LISTEN_MEMORY` sets the limit in megabytes). To stop, it removes the socket file, serves the clients that had connected, and exits. It replaces a socket file that no server answers on, such as one left by a server that was killed. Only the native executable supports `--listen`. With `--default-libraries-from-disk`, the server reads the files in its default library directory (`TSC_TS_LIB_DIR`, or the executable's directory) from the disk itself, even when the client handles file system calls (`--callbacks`), which saves a round trip to the client for each library file.
35
35
 
36
36
  `--checkers N` checks the program on N threads. Unless `--checkers` or `--singleThreaded` is given, the native executable uses one checker per CPU it may run on (up to 16), and at least tsgo's four; it uses fewer than the CPUs, but never fewer than four, when the estimated peak memory of more checkers would not fit 85% of the machine's memory (`TSC_TS_CHECKERS=fixed` keeps tsgo's four), and checkers beyond the fourth stop taking files, one at a time, when the process's memory reaches that share; it shares one program between its threads and also parses and binds the program's files on them. Unless `--singleThreaded` is given, the program's files are parsed and bound on threads also with `--checkers 1`, as tsgo does. Files that share costly declarations, such as a large generated schema and the few files importing it, are checked together on one checker. Under Node.js, where every thread builds its own copy of the program, tsc-ts checks on one thread unless `--checkers` is given. `--incremental`, `--watch` and `--build` always check on one thread. The diagnostics are the same as with one checker.
37
37
 
@@ -2281,6 +2281,8 @@ export declare class SourceFile extends Node {
2281
2281
  identifierCount: number;
2282
2282
  nodeCount: number;
2283
2283
  textCount: number;
2284
+ /** The API's binary encoding of this file, when an API server keeps it (`keptEncodingOf`). */
2285
+ apiEncoding: Uint8Array | undefined;
2284
2286
  /** Module specifiers of imports, exports, `require` calls and `import()` types, in source order. */
2285
2287
  imports: Node[];
2286
2288
  /** Names of `declare module "x"` augmentations and `declare global` blocks in modules. */
@@ -6641,6 +6641,8 @@ export class SourceFile extends Node {
6641
6641
  identifierCount;
6642
6642
  nodeCount;
6643
6643
  textCount;
6644
+ /** The API's binary encoding of this file, when an API server keeps it (`keptEncodingOf`). */
6645
+ apiEncoding;
6644
6646
  /** Module specifiers of imports, exports, `require` calls and `import()` types, in source order. */
6645
6647
  imports;
6646
6648
  /** Names of `declare module "x"` augmentations and `declare global` blocks in modules. */
@@ -6699,6 +6701,7 @@ export class SourceFile extends Node {
6699
6701
  this.identifierCount = 0;
6700
6702
  this.nodeCount = 0;
6701
6703
  this.textCount = 0;
6704
+ this.apiEncoding = undefined;
6702
6705
  this.imports = [];
6703
6706
  this.moduleAugmentations = emptyNodes;
6704
6707
  this.ambientModuleNames = emptyStrings;
@@ -709,7 +709,11 @@ export function reorderCandidates(c, signatures, callChainFlags) {
709
709
  spliceIndex = index;
710
710
  if (callChainFlags !== 0)
711
711
  signature = getOptionalCallSignature(c, signature, callChainFlags);
712
- result.splice(spliceIndex, 0, signature);
712
+ // Most signatures go at the end, where a push is cheaper than an inserting splice.
713
+ if (spliceIndex === result.length)
714
+ result.push(signature);
715
+ else
716
+ result.splice(spliceIndex, 0, signature);
713
717
  }
714
718
  return result;
715
719
  }
@@ -2255,7 +2255,8 @@ function getEmitSyntaxOfImportOrExport(g) {
2255
2255
  return ModuleKind.None;
2256
2256
  }
2257
2257
  function checkGrammarObjectLiteralExpression(g, node, inDestructuring) {
2258
- const seen = new Map();
2258
+ // An object literal with one property can't repeat a name, so it needs no table of names.
2259
+ const seen = node.properties.nodes.length > 1 ? new Map() : undefined;
2259
2260
  for (const property of node.properties.nodes) {
2260
2261
  if (property.kind === 305 /* SyntaxKind.SpreadAssignment */) {
2261
2262
  if (inDestructuring) {
@@ -2313,7 +2314,7 @@ function checkGrammarObjectLiteralExpression(g, node, inDestructuring) {
2313
2314
  if (inDestructuring)
2314
2315
  continue;
2315
2316
  const effectiveName = getEffectivePropertyNameForPropertyNameNode(g.c, name);
2316
- if (effectiveName === undefined)
2317
+ if (effectiveName === undefined || seen === undefined)
2317
2318
  continue;
2318
2319
  const existingKind = seen.get(effectiveName);
2319
2320
  if (existingKind === undefined) {
@@ -450,8 +450,14 @@ class InferenceState {
450
450
  index = 0;
451
451
  while (index < inference.candidateDepths.length && inference.candidateDepths[index] >= this.depth)
452
452
  index++;
453
- inference.candidates.splice(index, 0, candidate);
454
- inference.candidateDepths.splice(index, 0, this.depth);
453
+ if (index === inference.candidates.length) {
454
+ inference.candidates.push(candidate);
455
+ inference.candidateDepths.push(this.depth);
456
+ }
457
+ else {
458
+ inference.candidates.splice(index, 0, candidate);
459
+ inference.candidateDepths.splice(index, 0, this.depth);
460
+ }
455
461
  clearCachedInferences(this.inferences);
456
462
  }
457
463
  }
@@ -702,8 +702,12 @@ export function resolveDeclaredMembers(c, t) {
702
702
  const members = getMembersOfSymbol(c, t.symbol);
703
703
  declared.declaredMembersResolved = true;
704
704
  declared.declaredMembers = members;
705
- declared.declaredCallSignatures = getSignaturesOfSymbol(c, members.get("\uFFFEcall" /* InternalSymbolName.Call */));
706
- declared.declaredConstructSignatures = getSignaturesOfSymbol(c, members.get("\uFFFEnew" /* InternalSymbolName.New */));
705
+ // Most interfaces declare neither, and share one empty list.
706
+ const call = members.get("\uFFFEcall" /* InternalSymbolName.Call */);
707
+ const construct = members.get("\uFFFEnew" /* InternalSymbolName.New */);
708
+ declared.declaredCallSignatures = call !== undefined ? getSignaturesOfSymbol(c, call) : emptySignatures;
709
+ declared.declaredConstructSignatures =
710
+ construct !== undefined ? getSignaturesOfSymbol(c, construct) : emptySignatures;
707
711
  declared.declaredIndexInfos = getIndexInfosOfSymbol(c, t.symbol);
708
712
  }
709
713
  return declared;
@@ -1264,7 +1268,8 @@ export function getPropertyOfTypeEx(c, t, name, skipObjectFunctionPropertyAugmen
1264
1268
  if (!isOwnReducedApparentType(t))
1265
1269
  t = getReducedApparentTypeWorker(c, t);
1266
1270
  if ((t.flags & 1048576 /* TypeFlags.Object */) !== 0) {
1267
- const resolved = resolveStructuredTypeMembers(c, t);
1271
+ // The first test of resolveStructuredTypeMembers, here where most lookups find the members resolved.
1272
+ const resolved = (t.objectFlags & 2097152 /* ObjectFlags.MembersResolved */) !== 0 ? t : resolveStructuredTypeMembers(c, t);
1268
1273
  const symbol = getResolvedMember(resolved, name);
1269
1274
  if (symbol !== undefined && includeTypeOnlyMembers)
1270
1275
  return symbol;
@@ -5,6 +5,18 @@ import type { Checker } from './checker.js';
5
5
  * identifiers, which need the whole file checked first.
6
6
  */
7
7
  export declare function checkSourceFile(c: Checker, file: SourceFile, checkUnused?: boolean): void;
8
+ /**
9
+ * Checks the statements `start` to `end` of the declaration file `file`, one of the ranges that several
10
+ * checkers check it in (parallel-check.ts), and returns whether the checker then has diagnostics in the
11
+ * file. The range ending the file also runs the checks of the whole file. The file is not marked checked.
12
+ *
13
+ * When no range finds a diagnostic in the file, checking it whole would find none either: each statement
14
+ * is checked by the checker of its range. Otherwise the file is checked whole (`startParallelCheck`): the
15
+ * diagnostics of the ranges can differ from the file's, where they depend on the order the file's
16
+ * declarations are resolved in. A union type prints its members in the order the checker created them,
17
+ * and a check that a symbol's first declaration runs reports on all its declarations.
18
+ */
19
+ export declare function checkSourceFileRange(c: Checker, file: SourceFile, start: number, end: number): boolean;
8
20
  /** Checks a statement, declaration, class member or type node. */
9
21
  export declare function checkSourceElement(c: Checker, node: Node | undefined): void;
10
22
  /** Resolves the `@link` names of a node's JSDoc, which marks what they name referenced. */
@@ -81,6 +81,41 @@ function checkSourceFileWorker(c, file) {
81
81
  links.typeChecked = true;
82
82
  links.deferredNodes = undefined;
83
83
  }
84
+ /**
85
+ * Checks the statements `start` to `end` of the declaration file `file`, one of the ranges that several
86
+ * checkers check it in (parallel-check.ts), and returns whether the checker then has diagnostics in the
87
+ * file. The range ending the file also runs the checks of the whole file. The file is not marked checked.
88
+ *
89
+ * When no range finds a diagnostic in the file, checking it whole would find none either: each statement
90
+ * is checked by the checker of its range. Otherwise the file is checked whole (`startParallelCheck`): the
91
+ * diagnostics of the ranges can differ from the file's, where they depend on the order the file's
92
+ * declarations are resolved in. A union type prints its members in the order the checker created them,
93
+ * and a check that a symbol's first declaration runs reports on all its declarations.
94
+ */
95
+ export function checkSourceFileRange(c, file, start, end) {
96
+ const statements = getStatements(file).nodes;
97
+ c.fileBeingChecked = file;
98
+ c.saveDeferredDiagnostics = true;
99
+ for (let i = start; i < end; i++)
100
+ checkSourceElement(c, statements[i]);
101
+ checkDeferredNodes(c, file);
102
+ const whole = end === statements.length;
103
+ if (whole && isExternalOrCommonJSModule(file))
104
+ checkExternalModuleExports(c, file);
105
+ c.renamedBindingElementsInTypes.length = 0;
106
+ if (whole) {
107
+ checkGrammarSourceFile(c, file);
108
+ checkDeferredNodes(c, file);
109
+ checkPendingExternalEmitHelpers(c, file);
110
+ }
111
+ c.fileBeingChecked = undefined;
112
+ c.saveDeferredDiagnostics = false;
113
+ produceDeferredIterationErrors(c);
114
+ produceDeferredCollisionChecks(c);
115
+ // Deferred nodes of a later range are queued again (checkNodeDeferred).
116
+ c.nodeLinks(file).deferredNodes = undefined;
117
+ return c.diagnostics.forFile(file.fileName).length > 0;
118
+ }
84
119
  /** Checks a statement, declaration, class member or type node. */
85
120
  export function checkSourceElement(c, node) {
86
121
  if (node === undefined)
@@ -697,6 +697,7 @@ function setMergedSymbol(c, id, target) {
697
697
  c.mergedSymbolChanges.set(c.mergedSymbols, id, target);
698
698
  else
699
699
  c.mergedSymbols.set(id, target);
700
+ c.mergedSymbolIds.add(id);
700
701
  }
701
702
  /** Merges script locals into globals; ambient modules and augmentations wait for global types. */
702
703
  export function initializeGlobals(c) {
@@ -1033,7 +1034,7 @@ function recordMergedSymbol(c, target, source) {
1033
1034
  }
1034
1035
  export function getMergedSymbol(c, symbol) {
1035
1036
  const id = symbol.id;
1036
- if (id !== 0) {
1037
+ if (id !== 0 && c.mergedSymbolIds.has(id)) {
1037
1038
  const merged = c.mergedSymbols.get(id);
1038
1039
  if (merged !== undefined)
1039
1040
  return merged;
@@ -989,7 +989,10 @@ export function insertType(c, types, t) {
989
989
  const index = binarySearchTypes(c, types, t);
990
990
  if (index >= 0)
991
991
  return false;
992
- types.splice(~index, 0, t);
992
+ if (~index === types.length)
993
+ types.push(t);
994
+ else
995
+ types.splice(~index, 0, t);
993
996
  return true;
994
997
  }
995
998
  // ---- Iterating unions
@@ -1198,7 +1201,10 @@ function insertTypeNearLast(c, set, t) {
1198
1201
  else
1199
1202
  high = middle - 1;
1200
1203
  }
1201
- types.splice(low, 0, t);
1204
+ if (low === types.length)
1205
+ types.push(t);
1206
+ else
1207
+ types.splice(low, 0, t);
1202
1208
  set.last = low;
1203
1209
  }
1204
1210
  function getUnionTypeWorker(c, types, unionReduction, alias, origin) {
@@ -1,7 +1,7 @@
1
1
  import type { DeferredCollisionCheck } from './checker-generated-code.js';
2
2
  import type { EmitHelperFileLinks } from './checker-emit-helpers.js';
3
3
  import type { Node, PatternAmbientModule, SourceFile } from './ast.js';
4
- import { CompactSymbolLinkTable, IntLinkTable, LinkTable, SparseLinkTable } from './link-tables.js';
4
+ import { CompactSymbolLinkTable, IntLinkTable, LinkTable, PagedIdSet, SparseLinkTable } from './link-tables.js';
5
5
  import { Diagnostic, type DiagnosticMessage, Diagnostics } from './diagnostics.js';
6
6
  import { type CompilerOptions, ModuleKind, ScriptTarget } from './options.js';
7
7
  import { CheckFlags, Symbol, SymbolFlags, type SymbolTable } from './symbol.js';
@@ -71,6 +71,10 @@ declare class DiagnosticCollection {
71
71
  /** An already reported diagnostic equal to `diagnostic`, if any. */
72
72
  lookup(diagnostic: Diagnostic): Diagnostic | undefined;
73
73
  globals(): Diagnostic[];
74
+ /** The global diagnostics `withoutNewGlobals` removed. */
75
+ removedGlobals: number;
76
+ /** Runs `run`, then removes the global diagnostics it added. */
77
+ withoutNewGlobals<T>(run: () => T): T;
74
78
  /** Records the diagnostics added from now on. */
75
79
  startLog(): void;
76
80
  /** The diagnostics added since `startLog`, in order; stops recording. */
@@ -204,6 +208,11 @@ export declare class Checker implements TypeChecking {
204
208
  readonly resolvedSignatures: SparseLinkTable<Signature>;
205
209
  /** Merged symbols, indexed by the id of the symbol merged into them. */
206
210
  readonly mergedSymbols: Map<number, Symbol>;
211
+ /**
212
+ * The ids that `mergedSymbols` has, or had: most symbols are merged into none, and `getMergedSymbol`
213
+ * finds that here without probing the map.
214
+ */
215
+ readonly mergedSymbolIds: PagedIdSet;
207
216
  /** Globals merged from the default libraries, shared with other checkers. */
208
217
  libGlobals: LibGlobals | undefined;
209
218
  /** The program's globals and module augmentations as another checker merged them, shared with it. */
@@ -486,6 +495,13 @@ export declare class Checker implements TypeChecking {
486
495
  getSuggestionDiagnostics(file: SourceFile): Diagnostic[];
487
496
  /** Diagnostics without a file, such as missing global types. */
488
497
  getGlobalDiagnostics(): Diagnostic[];
498
+ /**
499
+ * Runs `run` (such as emitting declarations), then forgets the global diagnostics it reported:
500
+ * the program collects global diagnostics before it emits.
501
+ */
502
+ withoutGlobalDiagnostics<T>(run: () => T): T;
503
+ /** The global diagnostics `withoutGlobalDiagnostics` forgot so far. */
504
+ forgottenGlobalDiagnostics(): number;
489
505
  /** The rarely used links of `symbol`, created on first use. */
490
506
  symbolLinks(symbol: Symbol): SymbolLinks;
491
507
  /** The links of `symbol` if it has any, without creating them. */
@@ -1,5 +1,5 @@
1
1
  import { sideOf } from './side-state.js';
2
- import { CompactSymbolLinkTable, IntLinkTable, LinkTable, SparseLinkTable } from './link-tables.js';
2
+ import { CompactSymbolLinkTable, IntLinkTable, LinkTable, PagedIdSet, SparseLinkTable } from './link-tables.js';
3
3
  import { getErrorRangeForNode, getSourceFileOfNode } from './binder-utilities.js';
4
4
  import { Diagnostic, compareDiagnostics } from './diagnostics.js';
5
5
  import { ModuleKind, ScriptTarget, getEmitScriptTarget, getIsolatedModules, getStrictOptionValue, shouldPreserveConstEnums, } from './options.js';
@@ -137,6 +137,35 @@ class DiagnosticCollection {
137
137
  }
138
138
  return this.global.slice();
139
139
  }
140
+ /** The global diagnostics `withoutNewGlobals` removed. */
141
+ removedGlobals = 0;
142
+ /** Runs `run`, then removes the global diagnostics it added. */
143
+ withoutNewGlobals(run) {
144
+ const outer = this.log;
145
+ const added = [];
146
+ this.log = added;
147
+ try {
148
+ return run();
149
+ }
150
+ finally {
151
+ this.log = outer;
152
+ if (outer !== undefined)
153
+ for (const d of added)
154
+ outer.push(d);
155
+ const globals = new Set();
156
+ for (const d of added)
157
+ if (d.file === undefined)
158
+ globals.add(d);
159
+ if (globals.size > 0) {
160
+ this.removedGlobals += globals.size;
161
+ let kept = 0;
162
+ for (const d of this.global)
163
+ if (!globals.has(d))
164
+ this.global[kept++] = d;
165
+ this.global.length = kept;
166
+ }
167
+ }
168
+ }
140
169
  /** Records the diagnostics added from now on. */
141
170
  startLog() {
142
171
  this.log = [];
@@ -284,6 +313,11 @@ export class Checker {
284
313
  resolvedSignatures = new SparseLinkTable();
285
314
  /** Merged symbols, indexed by the id of the symbol merged into them. */
286
315
  mergedSymbols;
316
+ /**
317
+ * The ids that `mergedSymbols` has, or had: most symbols are merged into none, and `getMergedSymbol`
318
+ * finds that here without probing the map.
319
+ */
320
+ mergedSymbolIds = new PagedIdSet();
287
321
  /** Globals merged from the default libraries, shared with other checkers. */
288
322
  libGlobals;
289
323
  /** The program's globals and module augmentations as another checker merged them, shared with it. */
@@ -616,6 +650,8 @@ export class Checker {
616
650
  this.globals = libs.copyGlobals();
617
651
  this.mergedSymbols = libs.copyMergedSymbols();
618
652
  }
653
+ for (const id of this.mergedSymbols.keys())
654
+ this.mergedSymbolIds.add(id);
619
655
  this.globalThisSymbol = this.newSymbol(1536 /* SymbolFlags.Module */, 'globalThis');
620
656
  this.globalThisSymbol.checkFlags = 8 /* CheckFlags.Readonly */;
621
657
  this.globalThisSymbol.exports = this.globals;
@@ -773,6 +809,17 @@ export class Checker {
773
809
  getGlobalDiagnostics() {
774
810
  return this.diagnostics.globals();
775
811
  }
812
+ /**
813
+ * Runs `run` (such as emitting declarations), then forgets the global diagnostics it reported:
814
+ * the program collects global diagnostics before it emits.
815
+ */
816
+ withoutGlobalDiagnostics(run) {
817
+ return this.diagnostics.withoutNewGlobals(run);
818
+ }
819
+ /** The global diagnostics `withoutGlobalDiagnostics` forgot so far. */
820
+ forgottenGlobalDiagnostics() {
821
+ return this.diagnostics.removedGlobals;
822
+ }
776
823
  // ---- Links
777
824
  /** The rarely used links of `symbol`, created on first use. */
778
825
  symbolLinks(symbol) {
@@ -890,6 +937,7 @@ export function disposeChecker(c) {
890
937
  c.mergedSymbols.clear();
891
938
  c.globals.clear();
892
939
  }
940
+ c.mergedSymbolIds.clear();
893
941
  c.sharedSymbolCopies.clear();
894
942
  c.memberPositionsInLists.clear();
895
943
  c.memberNamesOfLists.clear();
@@ -61,6 +61,28 @@ export declare class EmitIndexes {
61
61
  readonly declarations: DeclarationGlobals | undefined;
62
62
  constructor(program: Program);
63
63
  }
64
+ /**
65
+ * The JavaScript emit of a program's files without a checker, for emit threads (parallel-emit.ts).
66
+ * JavaScript emit asks the checker only how decorator metadata serializes a type
67
+ * (`CheckerEmitResolver`): with `kinds`, the answers the main thread's checker gave
68
+ * (`recordMetadataKinds`), else files with decorator metadata are emitted by a `ProgramEmitter`.
69
+ */
70
+ export declare class JavaScriptEmitter {
71
+ private readonly host;
72
+ private readonly recorded;
73
+ constructor(program: Program, kinds?: readonly number[]);
74
+ /**
75
+ * Emits `file`, or returns undefined if its decorator metadata asked for a kind that wasn't recorded: what
76
+ * was written is then not the file's emit, and it must be emitted with the checker.
77
+ */
78
+ emit(file: SourceFile, writer: OutputWriter): EmitResult | undefined;
79
+ }
80
+ /**
81
+ * The serialization kinds of decorator metadata that the checker of `checked` gives the type references of
82
+ * `files`, in the order JavaScript emit asks for them: the type name's node id, the location's node id (-1 for
83
+ * none) and the kind, for each. Only the decorator metadata transform runs, as the first transform of emit.
84
+ */
85
+ export declare function recordMetadataKinds(checked: CheckedProgram, files: readonly SourceFile[]): number[];
64
86
  /** A checked program and the emit of its files. */
65
87
  export declare class ProgramEmitter {
66
88
  readonly checked: CheckedProgram;
@@ -110,9 +132,11 @@ export declare class PlainProgram extends CompilerProgram {
110
132
  export declare function handleNoEmitOnError(program: CompilerProgram): EmitResult | undefined;
111
133
  /**
112
134
  * Config and syntax errors; without syntax errors, program, global and semantic errors too, and
113
- * declaration errors under `noEmit` (or `withDeclarationDiagnostics`).
135
+ * declaration errors under `noEmit` (or `withDeclarationDiagnostics`). With `declarationsLater`, the
136
+ * declaration errors are left to `program.emit`, which reports them under `noEmit` (without
137
+ * `noEmitOnError`) whether or not other errors were found.
114
138
  */
115
- export declare function getDiagnosticsOfProgram(program: CompilerProgram, withDeclarationDiagnostics: boolean): Diagnostic[];
139
+ export declare function getDiagnosticsOfProgram(program: CompilerProgram, withDeclarationDiagnostics: boolean, declarationsLater?: boolean): Diagnostic[];
116
140
  /** Combines emit results in order. */
117
141
  export declare function combineEmitResults(results: readonly EmitResult[]): EmitResult;
118
142
  export { CheckedProgram };
@@ -6,6 +6,10 @@ import { CheckerDeclarationEmitResolver, CheckerEmitResolver } from './checker-e
6
6
  import { getEmitModuleFormatOfFile } from './program-utilities.js';
7
7
  import { DeclarationGlobals, SyntacticDeclarationEmitResolver } from './transformers/declarations-syntactic.js';
8
8
  import { mark } from './timeline.js';
9
+ import { DecoratorMetadata } from './transformers/decorator-metadata.js';
10
+ import { SyntaxFacts } from './transformers/syntax-facts.js';
11
+ import { EmitContext } from './printer/emit-context.js';
12
+ import { SyntacticEmitResolver } from './transformers/emit-resolver.js';
9
13
  import { ModuleFormatHost } from './transformers/module.js';
10
14
  import { ModuleLookup, ReferenceResolver } from './transformers/reference-resolver.js';
11
15
  /** Where emit writes files. */
@@ -165,6 +169,82 @@ export class EmitIndexes {
165
169
  : undefined;
166
170
  }
167
171
  }
172
+ /**
173
+ * The JavaScript emit of a program's files without a checker, for emit threads (parallel-emit.ts).
174
+ * JavaScript emit asks the checker only how decorator metadata serializes a type
175
+ * (`CheckerEmitResolver`): with `kinds`, the answers the main thread's checker gave
176
+ * (`recordMetadataKinds`), else files with decorator metadata are emitted by a `ProgramEmitter`.
177
+ */
178
+ export class JavaScriptEmitter {
179
+ host;
180
+ recorded;
181
+ constructor(program, kinds = []) {
182
+ const options = program.options;
183
+ const indexes = program.emitIndexes;
184
+ const references = new ReferenceResolver(options, program.getSourceFiles(), new ProgramModules(program), indexes !== undefined ? indexes.globals : undefined);
185
+ this.recorded = kinds.length > 0 ? new RecordedKindsEmitResolver(options, references, kinds) : undefined;
186
+ this.host = new ProgramEmitHost(program, this.recorded ?? new SyntacticEmitResolver(options, references));
187
+ }
188
+ /**
189
+ * Emits `file`, or returns undefined if its decorator metadata asked for a kind that wasn't recorded: what
190
+ * was written is then not the file's emit, and it must be emitted with the checker.
191
+ */
192
+ emit(file, writer) {
193
+ const host = this.host;
194
+ const recorded = this.recorded;
195
+ if (recorded !== undefined)
196
+ recorded.missed = false;
197
+ host.writer = writer;
198
+ const result = emitFiles(host, [file], 1 /* EmitOnly.Js */);
199
+ host.writer = undefined;
200
+ return recorded !== undefined && recorded.missed ? undefined : result;
201
+ }
202
+ }
203
+ /**
204
+ * The serialization kinds of decorator metadata that the checker of `checked` gives the type references of
205
+ * `files`, in the order JavaScript emit asks for them: the type name's node id, the location's node id (-1 for
206
+ * none) and the kind, for each. Only the decorator metadata transform runs, as the first transform of emit.
207
+ */
208
+ export function recordMetadataKinds(checked, files) {
209
+ const program = checked.program;
210
+ const options = program.options;
211
+ const indexes = program.emitIndexes;
212
+ const references = new ReferenceResolver(options, program.getSourceFiles(), new ProgramModules(program), indexes !== undefined ? indexes.globals : undefined);
213
+ const resolver = new RecordingEmitResolver(options, references, checked.checker);
214
+ for (const file of files)
215
+ new DecoratorMetadata(new EmitContext(), options, resolver, new SyntaxFacts()).transformSourceFile(file);
216
+ return resolver.kinds;
217
+ }
218
+ /** A `CheckerEmitResolver` that records the serialization kinds it gives (`recordMetadataKinds`). */
219
+ class RecordingEmitResolver extends CheckerEmitResolver {
220
+ kinds = [];
221
+ getTypeReferenceSerializationKind(typeName, location) {
222
+ const kind = super.getTypeReferenceSerializationKind(typeName, location);
223
+ this.kinds.push(typeName.id, location === undefined ? -1 : location.id, kind);
224
+ return kind;
225
+ }
226
+ }
227
+ /** Answers serialization kinds from those recorded on the main thread; `missed` once one wasn't. */
228
+ class RecordedKindsEmitResolver extends SyntacticEmitResolver {
229
+ kinds;
230
+ /** The kind and location of each type name, by the type name's node id. */
231
+ byName = new Map();
232
+ missed = false;
233
+ constructor(options, referenceResolver, kinds) {
234
+ super(options, referenceResolver);
235
+ this.kinds = kinds;
236
+ for (let i = 0; i < kinds.length; i += 3)
237
+ if (!this.byName.has(kinds[i]))
238
+ this.byName.set(kinds[i], i);
239
+ }
240
+ getTypeReferenceSerializationKind(typeName, location) {
241
+ const at = this.byName.get(typeName.id);
242
+ if (at !== undefined && this.kinds[at + 1] === (location === undefined ? -1 : location.id))
243
+ return this.kinds[at + 2];
244
+ this.missed = true;
245
+ return super.getTypeReferenceSerializationKind(typeName, location);
246
+ }
247
+ }
168
248
  /** A checked program and the emit of its files. */
169
249
  export class ProgramEmitter {
170
250
  checked;
@@ -291,14 +371,24 @@ export class PlainProgram extends CompilerProgram {
291
371
  const program = this.program;
292
372
  const files = program.getSourceFiles();
293
373
  const parallel = this.checked.emittedInParallel;
294
- // Checker threads emitted the files they checked (parallel-check.ts); the others are emitted here, in order.
374
+ // Checker threads emitted the files they checked (parallel-check.ts), or emit threads their JavaScript
375
+ // (parallel-emit.ts); the rest is emitted here, in order.
295
376
  const result = parallel === undefined
296
377
  ? this.emitter.emit(files, 0 /* EmitOnly.All */, writer)
297
378
  : combineEmitResults(files.map((file, i) => {
298
379
  const emitted = parallel[i];
299
- return emitted !== undefined
300
- ? writeHeldOutputs(emitted, writer)
301
- : this.emitter.emit([file], 0 /* EmitOnly.All */, writer);
380
+ // The declaration thread emitted the declarations of the files it could (parallel-emit.ts).
381
+ const ahead = this.checked.declarationsEmittedAhead;
382
+ const declarations = () => ahead?.[i] ?? this.emitter.emit([file], 2 /* EmitOnly.Dts */, writer);
383
+ if (emitted === undefined)
384
+ return ahead !== undefined
385
+ ? combineEmitResults([this.emitter.emit([file], 1 /* EmitOnly.Js */, writer), declarations()])
386
+ : this.emitter.emit([file], 0 /* EmitOnly.All */, writer);
387
+ const written = writeHeldOutputs(emitted, writer);
388
+ // Emit threads emit JavaScript only.
389
+ if (!this.checked.javaScriptEmittedOnThreads || !getEmitDeclarations(options))
390
+ return written;
391
+ return combineEmitResults([written, declarations()]);
302
392
  }));
303
393
  if (options.noEmit === true) {
304
394
  // Emit is skipped only for files that would have been emitted.
@@ -326,9 +416,11 @@ export function handleNoEmitOnError(program) {
326
416
  }
327
417
  /**
328
418
  * Config and syntax errors; without syntax errors, program, global and semantic errors too, and
329
- * declaration errors under `noEmit` (or `withDeclarationDiagnostics`).
419
+ * declaration errors under `noEmit` (or `withDeclarationDiagnostics`). With `declarationsLater`, the
420
+ * declaration errors are left to `program.emit`, which reports them under `noEmit` (without
421
+ * `noEmitOnError`) whether or not other errors were found.
330
422
  */
331
- export function getDiagnosticsOfProgram(program, withDeclarationDiagnostics) {
423
+ export function getDiagnosticsOfProgram(program, withDeclarationDiagnostics, declarationsLater = false) {
332
424
  const result = [...program.getConfigFileParsingDiagnostics()];
333
425
  const configCount = result.length;
334
426
  for (const d of program.getSyntacticDiagnostics())
@@ -356,7 +448,8 @@ export function getDiagnosticsOfProgram(program, withDeclarationDiagnostics) {
356
448
  result.push(d);
357
449
  mark('semantic diagnostics');
358
450
  }
359
- if ((withDeclarationDiagnostics || options.noEmit === true) &&
451
+ if (!declarationsLater &&
452
+ (withDeclarationDiagnostics || options.noEmit === true) &&
360
453
  getEmitDeclarations(options) &&
361
454
  result.length === configCount) {
362
455
  for (const d of program.getDeclarationDiagnostics())
@@ -109,6 +109,11 @@ export declare class Diagnostic {
109
109
  readonly reportsDeprecated: boolean;
110
110
  skippedOnNoEmit: boolean;
111
111
  repopulateInfo: RepopulateInfo | undefined;
112
+ /**
113
+ * What `formatDiagnostic` gives for this diagnostic in `formattedReports.format`, where the checker
114
+ * thread that found it formatted it (`packResult`); `''` otherwise.
115
+ */
116
+ formatted: string;
112
117
  constructor(file: DiagnosticFile | undefined, pos: number, end: number, message: DiagnosticMessage, args?: readonly string[]);
113
118
  localize(locale: Locale): string;
114
119
  addMessageChain(chain: Diagnostic | undefined): Diagnostic;
@@ -132,6 +137,14 @@ export declare function chainDiagnostic(chain: Diagnostic | undefined, message:
132
137
  export declare function compareCodePoints(a: string, b: string): number;
133
138
  /** The order tsc reports diagnostics in: by file, position, code, arguments, then elaboration. */
134
139
  export declare function compareDiagnostics(a: Diagnostic, b: Diagnostic): number;
140
+ /**
141
+ * `diagnostics` in the order of `compareDiagnostics`, equal ones in their order in `diagnostics`. File
142
+ * names are compared once per pair of files rather than once per pair of diagnostics: the distinct
143
+ * files are sorted by name, and each diagnostic sorts by its file's place in that order, then by the
144
+ * rest of `compareDiagnostics`. A program's diagnostics come a file at a time, so the files are found
145
+ * from the runs of one file.
146
+ */
147
+ export declare function sortDiagnostics(diagnostics: readonly Diagnostic[]): Diagnostic[];
135
148
  /** Whether two diagnostics report the same thing, ignoring related information. */
136
149
  export declare function equalDiagnosticsNoRelatedInfo(a: Diagnostic, b: Diagnostic): boolean;
137
150
  export declare function equalDiagnostics(a: Diagnostic, b: Diagnostic): boolean;
@@ -145,6 +158,15 @@ export interface DiagnosticFormatOptions {
145
158
  export declare function flattenDiagnosticMessage(diagnostic: Diagnostic, newLine: string, locale: Locale): string;
146
159
  /** `file(line,col): error TS1005: message`, as tsc prints without `--pretty`. */
147
160
  export declare function formatDiagnostic(diagnostic: Diagnostic, options: DiagnosticFormatOptions): string;
161
+ /**
162
+ * The plain format the main thread reports a compilation's diagnostics in (`DiagnosticReporter.plainFormat`),
163
+ * which its checker threads receive a copy of and format the diagnostics they send back in
164
+ * (`Diagnostic.formatted`). Unset where diagnostics are reported with color and context, or not at all.
165
+ */
166
+ export declare class FormattedReports {
167
+ format: DiagnosticFormatOptions | undefined;
168
+ }
169
+ export declare const formattedReports: FormattedReports;
148
170
  /** `formatDiagnostic` of each diagnostic. */
149
171
  export declare function formatDiagnostics(diagnostics: readonly Diagnostic[], options: DiagnosticFormatOptions): string;
150
172
  /** The colored form with source snippets, as tsc prints with `--pretty`. */