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
@@ -3010,17 +3010,12 @@ export class Parser extends ScannerErrorReporter {
3010
3010
  return false;
3011
3011
  }
3012
3012
  parseTypeOrTypePredicate() {
3013
- if (this.isIdentifier()) {
3014
- const state = this.beginSpeculation();
3013
+ // `x is T`: the identifier is parsed only once `is` is known to follow it.
3014
+ if (this.isIdentifier() && this.lookAhead(nextTokenIsIsKeywordOnSameLine)) {
3015
3015
  const pos = this.nodePos();
3016
3016
  const id = this.parseIdentifier(1 /* IdentifierUse.Name */);
3017
- if (this.token() === 142 /* SyntaxKind.IsKeyword */ && !this.hasPrecedingLineBreak()) {
3018
- this.endSpeculation(state);
3019
- this.nextToken();
3020
- return this.finishNode(new TypePredicateNode(undefined, id, this.parseType()), pos);
3021
- }
3022
- this.rewind(state);
3023
- this.endSpeculation(state);
3017
+ this.nextToken();
3018
+ return this.finishNode(new TypePredicateNode(undefined, id, this.parseType()), pos);
3024
3019
  }
3025
3020
  return this.parseType();
3026
3021
  }
@@ -5982,6 +5977,9 @@ function nextTokenCanFollowExportModifier(p) {
5982
5977
  function nextTokenIsClassKeywordOnSameLine(p) {
5983
5978
  return p.nextToken() === 85 /* SyntaxKind.ClassKeyword */ && !p.hasPrecedingLineBreak();
5984
5979
  }
5980
+ function nextTokenIsIsKeywordOnSameLine(p) {
5981
+ return p.nextToken() === 142 /* SyntaxKind.IsKeyword */ && !p.hasPrecedingLineBreak();
5982
+ }
5985
5983
  function nextTokenIsFunctionKeywordOnSameLine(p) {
5986
5984
  return p.nextToken() === 99 /* SyntaxKind.FunctionKeyword */ && !p.hasPrecedingLineBreak();
5987
5985
  }
@@ -6034,11 +6032,14 @@ function nextIsUnParenthesizedAsyncArrowFunction(p) {
6034
6032
  // `async =>` is a simple arrow function with a parameter named `async`.
6035
6033
  if (p.hasPrecedingLineBreak() || p.token() === 38 /* SyntaxKind.EqualsGreaterThanToken */)
6036
6034
  return false;
6037
- const expr = p.parseBinaryExpressionOrHigher(0 /* OperatorPrecedence.Lowest */);
6038
- if (!p.hasPrecedingLineBreak() &&
6039
- expr.kind === 79 /* SyntaxKind.Identifier */ &&
6040
- p.token() === 38 /* SyntaxKind.EqualsGreaterThanToken */)
6041
- return true;
6035
+ // The binary expression after `async` is a lone identifier followed by `=>` only when an identifier
6036
+ // token is followed by `=>`. Any other first token starts another kind of expression or none, and any
6037
+ // other token after the identifier continues the expression or ends it before `=>`. Checking the
6038
+ // tokens gives the same answer as parsing the expression, whose nodes would be discarded.
6039
+ if (!p.isIdentifier())
6040
+ return false;
6041
+ p.nextToken();
6042
+ return !p.hasPrecedingLineBreak() && p.token() === 38 /* SyntaxKind.EqualsGreaterThanToken */;
6042
6043
  }
6043
6044
  return false;
6044
6045
  }
@@ -91,6 +91,8 @@ export declare class EmitContext extends NodeFactory {
91
91
  getAutoGenerateInfo(node: Node): AutoGenerateInfo | undefined;
92
92
  /** The node a generated name is based on, following clones of generated names. */
93
93
  getNodeForGeneratedName(name: Node): Node;
94
+ /** Whether `node` has emit data: flags, ranges, helpers or synthesized comments. */
95
+ hasEmitNode(node: Node): boolean;
94
96
  getEmitFlags(node: Node): EmitFlags;
95
97
  setEmitFlags(node: Node, flags: EmitFlags): Node;
96
98
  addEmitFlags(node: Node, flags: EmitFlags): Node;
@@ -228,6 +228,10 @@ export class EmitContext extends NodeFactory {
228
228
  return node;
229
229
  }
230
230
  // Emit data
231
+ /** Whether `node` has emit data: flags, ranges, helpers or synthesized comments. */
232
+ hasEmitNode(node) {
233
+ return this.lookup(node) !== undefined;
234
+ }
231
235
  getEmitFlags(node) {
232
236
  const emitNode = this.lookup(node);
233
237
  return emitNode === undefined ? 0 /* EmitFlags.None */ : emitNode.emitFlags;
@@ -101,6 +101,13 @@ export declare class Printer extends NameGeneratorHost {
101
101
  currentSourceFile: SourceFile | undefined;
102
102
  private sourceText;
103
103
  private lineStarts;
104
+ /**
105
+ * The line of the last `lineOf` lookup, `lookupLine`, and the positions it spans, `[lookupLineStart, lookupLineEnd)`,
106
+ * with `lookupLineEnd` -1 after the last line: printing reads positions mostly in order, so most lookups fall on that line.
107
+ */
108
+ private lookupLine;
109
+ private lookupLineStart;
110
+ private lookupLineEnd;
104
111
  private writer;
105
112
  private ownWriter;
106
113
  private uniqueHelperNames;
@@ -114,8 +121,25 @@ export declare class Printer extends NameGeneratorHost {
114
121
  private commentsDisabled;
115
122
  /** Emitting the `extends` clause of a conditional or infer type. */
116
123
  private inExtends;
117
- /** Saved comment state: emit flags, comment pos, comment end, container pos, container end, declaration list end. */
118
- private readonly commentStack;
124
+ /**
125
+ * Saved comment state, 32-bit values: emit flags, comment pos, comment end, container pos, container end,
126
+ * declaration list end.
127
+ * Flags are `commentFreeNode` for a node that `emitCommentsBeforeNode` handled in a comment-free range.
128
+ */
129
+ private commentStack;
130
+ /** The used length of `commentStack`: entries are written in place and kept for reuse once popped. */
131
+ private commentDepth;
132
+ /** Start positions of `//` and `/*` in `sourceText`, ascending; made on first use for each file. */
133
+ private commentStarts;
134
+ /**
135
+ * A range of `sourceText`, `[freeStart, freeEnd)`, where no comment starts and the last character is not trivia,
136
+ * so no comment is found from any position in it; -1 when there is none. `freeOwner` is the node it was made for.
137
+ */
138
+ private freeStart;
139
+ private freeEnd;
140
+ /** Whether no trailing comment follows `freeEnd`. */
141
+ private freeEndTrailingNone;
142
+ private freeOwner;
119
143
  /** Saved source map state: emit flags, pos, end, has token range. */
120
144
  private readonly sourceMapStack;
121
145
  /** The token position after `enterToken` skipped trivia. */
@@ -143,6 +167,13 @@ export declare class Printer extends NameGeneratorHost {
143
167
  private getLiteralTextOfNode;
144
168
  /** The text of an identifier, private identifier, literal or JSX namespaced name as printed. */
145
169
  getTextOfNode(node: Node): string;
170
+ /**
171
+ * Whether the source text of an identifier or private identifier of the current file, from the end of its leading
172
+ * trivia to its end, is its text: the text ends the node, and the character before it is not part of the token, as
173
+ * it would be in an identifier written with escapes. Nodes from JSDoc may span other text, so they are left to the
174
+ * general path.
175
+ */
176
+ private textIsSourceText;
146
177
  private isInCurrentSourceFile;
147
178
  private write1;
148
179
  private space;
@@ -155,6 +186,8 @@ export declare class Printer extends NameGeneratorHost {
155
186
  private writeLineSeparatorsAndIndentBefore;
156
187
  private writeLineSeparatorsAfter;
157
188
  private positionsAreOnSameLine;
189
+ /** The zero-based line of `pos` (-1 before the first line), which becomes the line of the last lookup. */
190
+ private lineOf;
158
191
  private rangeStart;
159
192
  private rangeIsOnSingleLine;
160
193
  private rangeEndIsOnSameLineAsRangeStart;
@@ -363,7 +396,20 @@ export declare class Printer extends NameGeneratorHost {
363
396
  private emitListItems;
364
397
  private emitAnyNode;
365
398
  private emitCommentsBeforeNode;
399
+ /** Saves the comment state of a node: its emit flags (or `commentFreeNode`), comment range and the containers. */
400
+ private pushCommentState;
366
401
  private emitCommentsAfterNode;
402
+ /**
403
+ * Whether `node` has no emit data and lies in a range of the source text where no comment is found, so that its
404
+ * comments need not be looked for. Outside such a range, a node whose own range is one starts it (`freeOwner`).
405
+ */
406
+ private inCommentFreeRange;
407
+ private endCommentFreeRange;
408
+ /** Whether the comment-free range shows that no trailing comment follows `pos`. */
409
+ private noCommentsAfter;
410
+ /** Makes `[pos, end)` the comment-free range if no comment starts in it and its last character is not trivia. */
411
+ private startCommentFreeRange;
412
+ private commentStartsOfFile;
367
413
  /** Emits comments before a token; returns whether `emitCommentsAfterToken` applies, with the token's position in `tokenPos`. */
368
414
  private emitCommentsBeforeToken;
369
415
  private emitCommentsAfterToken;
@@ -39,6 +39,8 @@ export class PrinterOptions {
39
39
  this.terminateUnterminatedLiterals = false;
40
40
  }
41
41
  }
42
+ /** The saved emit flags of a node whose comments were not looked for (`Printer.inCommentFreeRange`). */
43
+ const commentFreeNode = -1;
42
44
  export class Printer extends NameGeneratorHost {
43
45
  options;
44
46
  context;
@@ -50,6 +52,13 @@ export class Printer extends NameGeneratorHost {
50
52
  currentSourceFile;
51
53
  sourceText;
52
54
  lineStarts;
55
+ /**
56
+ * The line of the last `lineOf` lookup, `lookupLine`, and the positions it spans, `[lookupLineStart, lookupLineEnd)`,
57
+ * with `lookupLineEnd` -1 after the last line: printing reads positions mostly in order, so most lookups fall on that line.
58
+ */
59
+ lookupLine;
60
+ lookupLineStart;
61
+ lookupLineEnd;
53
62
  writer;
54
63
  ownWriter;
55
64
  uniqueHelperNames;
@@ -63,8 +72,25 @@ export class Printer extends NameGeneratorHost {
63
72
  commentsDisabled;
64
73
  /** Emitting the `extends` clause of a conditional or infer type. */
65
74
  inExtends;
66
- /** Saved comment state: emit flags, comment pos, comment end, container pos, container end, declaration list end. */
75
+ /**
76
+ * Saved comment state, 32-bit values: emit flags, comment pos, comment end, container pos, container end,
77
+ * declaration list end.
78
+ * Flags are `commentFreeNode` for a node that `emitCommentsBeforeNode` handled in a comment-free range.
79
+ */
67
80
  commentStack;
81
+ /** The used length of `commentStack`: entries are written in place and kept for reuse once popped. */
82
+ commentDepth;
83
+ /** Start positions of `//` and `/*` in `sourceText`, ascending; made on first use for each file. */
84
+ commentStarts;
85
+ /**
86
+ * A range of `sourceText`, `[freeStart, freeEnd)`, where no comment starts and the last character is not trivia,
87
+ * so no comment is found from any position in it; -1 when there is none. `freeOwner` is the node it was made for.
88
+ */
89
+ freeStart;
90
+ freeEnd;
91
+ /** Whether no trailing comment follows `freeEnd`. */
92
+ freeEndTrailingNone;
93
+ freeOwner;
68
94
  /** Saved source map state: emit flags, pos, end, has token range. */
69
95
  sourceMapStack;
70
96
  /** The token position after `enterToken` skipped trivia. */
@@ -94,6 +120,9 @@ export class Printer extends NameGeneratorHost {
94
120
  this.currentSourceFile = undefined;
95
121
  this.sourceText = '';
96
122
  this.lineStarts = [];
123
+ this.lookupLine = -1;
124
+ this.lookupLineStart = 0;
125
+ this.lookupLineEnd = 0;
97
126
  this.writer = new TextWriter(options.newLine, 4);
98
127
  this.ownWriter = undefined;
99
128
  this.uniqueHelperNames = undefined;
@@ -105,7 +134,13 @@ export class Printer extends NameGeneratorHost {
105
134
  this.detachedComments = [];
106
135
  this.commentsDisabled = options.removeComments;
107
136
  this.inExtends = false;
108
- this.commentStack = [];
137
+ this.commentStack = new Int32Array(96);
138
+ this.commentDepth = 0;
139
+ this.commentStarts = undefined;
140
+ this.freeStart = -1;
141
+ this.freeEnd = -1;
142
+ this.freeEndTrailingNone = false;
143
+ this.freeOwner = undefined;
109
144
  this.sourceMapStack = [];
110
145
  this.tokenPos = 0;
111
146
  this.sourceMapsDisabled = true;
@@ -150,6 +185,11 @@ export class Printer extends NameGeneratorHost {
150
185
  this.currentSourceFile = sourceFile;
151
186
  this.sourceText = sourceFile === undefined ? '' : sourceFile.text;
152
187
  this.lineStarts = sourceFile === undefined ? [] : sourceFile.lineStarts();
188
+ this.lookupLine = -1;
189
+ this.lookupLineStart = 0;
190
+ this.lookupLineEnd = 0;
191
+ this.commentStarts = undefined;
192
+ this.endCommentFreeRange();
153
193
  return true;
154
194
  }
155
195
  /** Prints `node` into `writer`, adding mappings to `sourceMapGenerator` if given. */
@@ -234,6 +274,9 @@ export class Printer extends NameGeneratorHost {
234
274
  case 79 /* SyntaxKind.Identifier */:
235
275
  case 80 /* SyntaxKind.PrivateIdentifier */:
236
276
  case 296 /* SyntaxKind.JsxNamespacedName */:
277
+ // Its text either way: the source text, or the text of a node from elsewhere.
278
+ if (this.textIsSourceText(node))
279
+ return node.text;
237
280
  if (!canUseSourceFile || !this.isInCurrentSourceFile(node)) {
238
281
  if (node instanceof Identifier)
239
282
  return node.text;
@@ -256,6 +299,39 @@ export class Printer extends NameGeneratorHost {
256
299
  }
257
300
  return getSourceTextOfNode(this.sourceText, node);
258
301
  }
302
+ /**
303
+ * Whether the source text of an identifier or private identifier of the current file, from the end of its leading
304
+ * trivia to its end, is its text: the text ends the node, and the character before it is not part of the token, as
305
+ * it would be in an identifier written with escapes. Nodes from JSDoc may span other text, so they are left to the
306
+ * general path.
307
+ */
308
+ textIsSourceText(node) {
309
+ if (!(node instanceof Identifier) && !(node instanceof PrivateIdentifier))
310
+ return false;
311
+ if ((node.flags & (8 /* NodeFlags.Reparsed */ | 4194304 /* NodeFlags.JSDoc */ | 268435456 /* NodeFlags.ReparserTransformedLiteral */)) !== 0)
312
+ return false;
313
+ const text = node.text;
314
+ const source = this.sourceText;
315
+ const end = node.end;
316
+ const start = end - text.length;
317
+ if (text.length === 0 || start < node.pos || end > source.length)
318
+ return false;
319
+ if (!source.startsWith(text, start))
320
+ return false;
321
+ if (start === node.pos)
322
+ return true;
323
+ const before = source.charCodeAt(start - 1);
324
+ return !((before >= 97 /* CharacterCodes.a */ && before <= 122 /* CharacterCodes.z */) ||
325
+ (before >= 65 /* CharacterCodes.A */ && before <= 90 /* CharacterCodes.Z */) ||
326
+ (before >= 48 /* CharacterCodes._0 */ && before <= 57 /* CharacterCodes._9 */) ||
327
+ before === 95 /* CharacterCodes._ */ ||
328
+ before === 36 /* CharacterCodes.$ */ ||
329
+ before === 92 /* CharacterCodes.backslash */ ||
330
+ before === 123 /* CharacterCodes.openBrace */ ||
331
+ before === 125 /* CharacterCodes.closeBrace */ ||
332
+ before === 35 /* CharacterCodes.hash */ ||
333
+ before > 127 /* CharacterCodes.maxAsciiCharacter */);
334
+ }
259
335
  isInCurrentSourceFile(node) {
260
336
  const file = this.currentSourceFile;
261
337
  if (file === undefined)
@@ -331,7 +407,28 @@ export class Printer extends NameGeneratorHost {
331
407
  }
332
408
  // Lines between nodes
333
409
  positionsAreOnSameLine(pos1, pos2) {
334
- return getLinesBetweenPositions(this.lineStarts, pos1, pos2) === 0;
410
+ if (pos1 === pos2)
411
+ return true;
412
+ const lower = pos1 < pos2 ? pos1 : pos2;
413
+ const upper = pos1 < pos2 ? pos2 : pos1;
414
+ // What getLinesBetweenPositions finds: no line starts in (lower, upper].
415
+ if (lower < 0) {
416
+ const first = this.lineStarts.length > 0 ? this.lineStarts[0] | 0 : -1;
417
+ return first < 0 || upper < first;
418
+ }
419
+ this.lineOf(lower);
420
+ return this.lookupLineEnd < 0 || upper < this.lookupLineEnd;
421
+ }
422
+ /** The zero-based line of `pos` (-1 before the first line), which becomes the line of the last lookup. */
423
+ lineOf(pos) {
424
+ if (pos >= this.lookupLineStart && (pos < this.lookupLineEnd || this.lookupLineEnd < 0) && this.lookupLine >= 0)
425
+ return this.lookupLine;
426
+ const starts = this.lineStarts;
427
+ const line = computeLineOfPosition(starts, pos);
428
+ this.lookupLine = line;
429
+ this.lookupLineStart = line >= 0 ? starts[line] | 0 : 0;
430
+ this.lookupLineEnd = line + 1 < starts.length ? starts[line + 1] | 0 : -1;
431
+ return line;
335
432
  }
336
433
  rangeStart(pos) {
337
434
  return getStartPositionOfRange(this.sourceText, pos, false);
@@ -617,8 +714,13 @@ export class Printer extends NameGeneratorHost {
617
714
  return true;
618
715
  }
619
716
  // Names
620
- // Source text of names reparsed from JSDoc can span lines.
717
+ // Source text of names reparsed from JSDoc can span lines; an identifier's own source text has no line breaks.
621
718
  emitIdentifierText(node) {
719
+ if (!this.context.autoGenerate.has(node) && this.textIsSourceText(node)) {
720
+ // writeText's answer for text without line breaks.
721
+ this.writer.write(node.text);
722
+ return false;
723
+ }
622
724
  return this.writer.writeText(this.getTextOfNode(node));
623
725
  }
624
726
  emitIdentifierName(node) {
@@ -3751,10 +3853,19 @@ export class Printer extends NameGeneratorHost {
3751
3853
  emitCommentsBeforeNode(node) {
3752
3854
  if (!this.shouldEmitComments(node))
3753
3855
  return false;
3856
+ if (this.inCommentFreeRange(node)) {
3857
+ // What the general path does for a node without emit data and without comments.
3858
+ this.pushCommentState(commentFreeNode, node.pos, node.end);
3859
+ this.containerPos = node.pos;
3860
+ this.containerEnd = node.end;
3861
+ if (node.kind === 262 /* SyntaxKind.VariableDeclarationList */)
3862
+ this.declarationListContainerEnd = node.end;
3863
+ return true;
3864
+ }
3754
3865
  const flags = this.context.getEmitFlags(node);
3755
3866
  const pos = this.context.commentPos(node);
3756
3867
  const end = this.context.commentEnd(node);
3757
- this.commentStack.push(flags, pos, end, this.containerPos, this.containerEnd, this.declarationListContainerEnd);
3868
+ this.pushCommentState(flags, pos, end);
3758
3869
  this.emitLeadingCommentsOfNode(node, flags, pos, end);
3759
3870
  if ((flags & 128 /* EmitFlags.NoLeadingComments */) === 0) {
3760
3871
  const synthesized = this.context.getSyntheticLeadingComments(node);
@@ -3766,17 +3877,43 @@ export class Printer extends NameGeneratorHost {
3766
3877
  this.commentsDisabled = true;
3767
3878
  return true;
3768
3879
  }
3880
+ /** Saves the comment state of a node: its emit flags (or `commentFreeNode`), comment range and the containers. */
3881
+ pushCommentState(flags, pos, end) {
3882
+ let stack = this.commentStack;
3883
+ const at = this.commentDepth;
3884
+ if (at + 6 > stack.length) {
3885
+ const grown = new Int32Array(stack.length * 2);
3886
+ grown.set(stack);
3887
+ this.commentStack = grown;
3888
+ stack = grown;
3889
+ }
3890
+ stack[at] = flags;
3891
+ stack[at + 1] = pos;
3892
+ stack[at + 2] = end;
3893
+ stack[at + 3] = this.containerPos;
3894
+ stack[at + 4] = this.containerEnd;
3895
+ stack[at + 5] = this.declarationListContainerEnd;
3896
+ this.commentDepth = at + 6;
3897
+ return true;
3898
+ }
3769
3899
  emitCommentsAfterNode(node) {
3770
3900
  const stack = this.commentStack;
3771
- const base = stack.length - 6;
3772
- // `| 0` keeps scriptc from typing array reads as possibly undefined.
3773
- const flags = stack[base] | 0;
3774
- const pos = stack[base + 1] | 0;
3775
- const end = stack[base + 2] | 0;
3776
- const containerPos = stack[base + 3] | 0;
3777
- const containerEnd = stack[base + 4] | 0;
3778
- const declarationListContainerEnd = stack[base + 5] | 0;
3779
- stack.length = base;
3901
+ const base = this.commentDepth - 6;
3902
+ const flags = stack[base];
3903
+ const pos = stack[base + 1];
3904
+ const end = stack[base + 2];
3905
+ const containerPos = stack[base + 3];
3906
+ const containerEnd = stack[base + 4];
3907
+ const declarationListContainerEnd = stack[base + 5];
3908
+ this.commentDepth = base;
3909
+ if (node === this.freeOwner)
3910
+ this.endCommentFreeRange();
3911
+ if (flags === commentFreeNode) {
3912
+ this.containerPos = containerPos;
3913
+ this.containerEnd = containerEnd;
3914
+ this.declarationListContainerEnd = declarationListContainerEnd;
3915
+ return true;
3916
+ }
3780
3917
  if ((flags & 512 /* EmitFlags.NoNestedComments */) !== 0)
3781
3918
  this.commentsDisabled = false;
3782
3919
  if ((flags & 256 /* EmitFlags.NoTrailingComments */) === 0) {
@@ -3792,6 +3929,87 @@ export class Printer extends NameGeneratorHost {
3792
3929
  this.emitTrailingCommentsOfNode(node, flags, typeNode.pos, typeNode.end, containerPos, containerEnd, declarationListContainerEnd);
3793
3930
  return true;
3794
3931
  }
3932
+ /**
3933
+ * Whether `node` has no emit data and lies in a range of the source text where no comment is found, so that its
3934
+ * comments need not be looked for. Outside such a range, a node whose own range is one starts it (`freeOwner`).
3935
+ */
3936
+ inCommentFreeRange(node) {
3937
+ const pos = node.pos;
3938
+ const end = node.end;
3939
+ if (pos < 0 || end <= pos || node.kind === 11 /* SyntaxKind.JsxText */ || node.kind === 347 /* SyntaxKind.NotEmittedStatement */)
3940
+ return false;
3941
+ if (this.freeEnd < 0) {
3942
+ if (!this.startCommentFreeRange(pos, end))
3943
+ return false;
3944
+ this.freeOwner = node;
3945
+ }
3946
+ else if (pos < this.freeStart)
3947
+ return false;
3948
+ if (this.context.hasEmitNode(node))
3949
+ return false;
3950
+ return end < this.freeEnd || (end === this.freeEnd && this.freeEndTrailingNone);
3951
+ }
3952
+ endCommentFreeRange() {
3953
+ this.freeStart = -1;
3954
+ this.freeEnd = -1;
3955
+ this.freeEndTrailingNone = false;
3956
+ this.freeOwner = undefined;
3957
+ return true;
3958
+ }
3959
+ /** Whether the comment-free range shows that no trailing comment follows `pos`. */
3960
+ noCommentsAfter(pos) {
3961
+ return pos >= this.freeStart && (pos < this.freeEnd || (pos === this.freeEnd && this.freeEndTrailingNone));
3962
+ }
3963
+ /** Makes `[pos, end)` the comment-free range if no comment starts in it and its last character is not trivia. */
3964
+ startCommentFreeRange(pos, end) {
3965
+ const text = this.sourceText;
3966
+ if (end > text.length)
3967
+ return false;
3968
+ const last = text.charCodeAt(end - 1);
3969
+ if (last === 32 /* CharacterCodes.space */ ||
3970
+ last === 9 /* CharacterCodes.tab */ ||
3971
+ last === 10 /* CharacterCodes.lineFeed */ ||
3972
+ last === 13 /* CharacterCodes.carriageReturn */ ||
3973
+ last === 11 /* CharacterCodes.verticalTab */ ||
3974
+ last === 12 /* CharacterCodes.formFeed */ ||
3975
+ last > 127 /* CharacterCodes.maxAsciiCharacter */)
3976
+ return false;
3977
+ const starts = this.commentStartsOfFile();
3978
+ // The first comment start at or after `pos`.
3979
+ let low = 0;
3980
+ let high = starts.length;
3981
+ while (low < high) {
3982
+ const middle = (low + high) >>> 1;
3983
+ if (starts[middle] < pos)
3984
+ low = middle + 1;
3985
+ else
3986
+ high = middle;
3987
+ }
3988
+ if (low < starts.length && starts[low] < end)
3989
+ return false;
3990
+ this.freeStart = pos;
3991
+ this.freeEnd = end;
3992
+ this.freeEndTrailingNone = getTrailingCommentRanges(text, end) === undefined;
3993
+ return true;
3994
+ }
3995
+ commentStartsOfFile() {
3996
+ const cached = this.commentStarts;
3997
+ if (cached !== undefined)
3998
+ return cached;
3999
+ const text = this.sourceText;
4000
+ const length = text.length;
4001
+ const list = [];
4002
+ for (let i = text.indexOf('/'); i >= 0 && i + 1 < length; i = text.indexOf('/', i + 1)) {
4003
+ const next = text.charCodeAt(i + 1);
4004
+ if (next === 47 /* CharacterCodes.slash */ || next === 42 /* CharacterCodes.asterisk */)
4005
+ list.push(i);
4006
+ }
4007
+ const starts = new Int32Array(list.length);
4008
+ for (let i = 0; i < list.length; i++)
4009
+ starts[i] = list[i];
4010
+ this.commentStarts = starts;
4011
+ return starts;
4012
+ }
3795
4013
  /** Emits comments before a token; returns whether `emitCommentsAfterToken` applies, with the token's position in `tokenPos`. */
3796
4014
  emitCommentsBeforeToken(pos, contextNode, flags) {
3797
4015
  if ((flags & 1 /* TokenEmitFlags.NoComments */) !== 0 || this.commentsDisabled) {
@@ -3897,6 +4115,8 @@ export class Printer extends NameGeneratorHost {
3897
4115
  emitLeadingComments(pos, elided) {
3898
4116
  if (this.commentsDisabled || this.currentSourceFile === undefined || pos < 0 || pos === this.containerPos)
3899
4117
  return false;
4118
+ if (pos >= this.freeStart && pos < this.freeEnd)
4119
+ return false;
3900
4120
  // 1: only triple-slash comments, 2: all but triple-slash comments, 0: all.
3901
4121
  let tripleSlash = 0;
3902
4122
  if (!elided) {
@@ -3947,6 +4167,8 @@ export class Printer extends NameGeneratorHost {
3947
4167
  this.currentSourceFile === undefined ||
3948
4168
  (this.containerEnd !== -1 && (pos === this.containerEnd || pos === this.declarationListContainerEnd)))
3949
4169
  return false;
4170
+ if (this.noCommentsAfter(pos))
4171
+ return false;
3950
4172
  const ranges = getTrailingCommentRanges(this.sourceText, pos);
3951
4173
  if (ranges === undefined)
3952
4174
  return false;
@@ -3965,6 +4187,8 @@ export class Printer extends NameGeneratorHost {
3965
4187
  return false;
3966
4188
  if (this.containerEnd !== -1 && (pos === this.containerEnd || pos === this.declarationListContainerEnd))
3967
4189
  return false;
4190
+ if (this.noCommentsAfter(pos))
4191
+ return false;
3968
4192
  const comments = getTrailingCommentRanges(this.sourceText, pos);
3969
4193
  if (comments === undefined)
3970
4194
  return false;
@@ -120,6 +120,10 @@ export declare class CheckedProgram {
120
120
  * emit. Set once every file is checked, when checker threads emit (parallel-check.ts).
121
121
  */
122
122
  emittedInParallel: (EmitResult | undefined)[] | undefined;
123
+ /** Emit threads emitted only the JavaScript of `emittedInParallel`: declarations are emitted here. */
124
+ javaScriptEmittedOnThreads: boolean;
125
+ /** The declaration emit of each file on the declaration thread (parallel-emit.ts); undefined for one it didn't emit. */
126
+ declarationsEmittedAhead: (EmitResult | undefined)[] | undefined;
123
127
  /**
124
128
  * The global diagnostics of this thread's checker before it emitted files while checker threads
125
129
  * checked (`emitUncheckedFiles`), reported instead of its current ones.
@@ -134,6 +138,23 @@ export declare class CheckedProgram {
134
138
  * incremental program keeps them unfiltered under `noEmit` too.
135
139
  */
136
140
  unfilteredDiagnosticsOfFile(file: SourceFile): Diagnostic[];
141
+ /**
142
+ * Checks the statements `start` to `end` of the declaration file `file` with this checker, one of the
143
+ * ranges that several checkers check it in (`checkSourceFileRange`, parallel-check.ts), and returns
144
+ * whether the checker then has diagnostics in the file.
145
+ */
146
+ checkRange(file: SourceFile, start: number, end: number): boolean;
147
+ /**
148
+ * The diagnostics of `file`, as `unfilteredDiagnosticsOfFile` gives them, where checkers checked it in
149
+ * ranges and found no diagnostics in it (`checkRange`).
150
+ */
151
+ unfilteredDiagnosticsOfCleanRanges(file: SourceFile): Diagnostic[];
152
+ /**
153
+ * The diagnostics of `file`, as `unfilteredDiagnosticsOfFile` gives them, from a new checker that checks it
154
+ * whole: for a file checked in ranges that found diagnostics in it (parallel-check.ts), part of which this
155
+ * thread's checker may have checked.
156
+ */
157
+ unfilteredDiagnosticsOfFileOnNewChecker(file: SourceFile): Diagnostic[];
137
158
  /**
138
159
  * The bind and check diagnostics of `file` before `noEmit` filtering and without include errors.
139
160
  * Once checker threads checked the program, they come from the threads' diagnostics of the file,
@@ -156,6 +177,7 @@ export declare class CheckedProgram {
156
177
  skipTypeChecking(file: SourceFile): boolean;
157
178
  private collect;
158
179
  private collectChecked;
180
+ /** `checks` are the checker's diagnostics of `file`. */
159
181
  private getBindAndCheckDiagnostics;
160
182
  getIncludeProcessorDiagnostics(file: SourceFile): Diagnostic[];
161
183
  }
@@ -4,6 +4,7 @@ import { ModuleSpecifierHost } from './module-specifiers.js';
4
4
  import { sortAndDeduplicateDiagnostics } from './program.js';
5
5
  import { getEmitModuleFormatOfFile, getEmitSyntaxForUsageLocation, isCheckJsEnabledForFile, } from './program-utilities.js';
6
6
  import { bindSourceFile } from './binder.js';
7
+ import { checkSourceFileRange } from './checker-source-file.js';
7
8
  import { computeLineOfPosition } from './scanner.js';
8
9
  /** What the checker needs, answered by a program. */
9
10
  export class ProgramCheckerHost extends CheckerHost {
@@ -209,6 +210,10 @@ export class CheckedProgram {
209
210
  * emit. Set once every file is checked, when checker threads emit (parallel-check.ts).
210
211
  */
211
212
  emittedInParallel = undefined;
213
+ /** Emit threads emitted only the JavaScript of `emittedInParallel`: declarations are emitted here. */
214
+ javaScriptEmittedOnThreads = false;
215
+ /** The declaration emit of each file on the declaration thread (parallel-emit.ts); undefined for one it didn't emit. */
216
+ declarationsEmittedAhead = undefined;
212
217
  /**
213
218
  * The global diagnostics of this thread's checker before it emitted files while checker threads
214
219
  * checked (`emitUncheckedFiles`), reported instead of its current ones.
@@ -250,6 +255,37 @@ export class CheckedProgram {
250
255
  result.push(d);
251
256
  return result;
252
257
  }
258
+ /**
259
+ * Checks the statements `start` to `end` of the declaration file `file` with this checker, one of the
260
+ * ranges that several checkers check it in (`checkSourceFileRange`, parallel-check.ts), and returns
261
+ * whether the checker then has diagnostics in the file.
262
+ */
263
+ checkRange(file, start, end) {
264
+ return checkSourceFileRange(this.checker, file, start, end);
265
+ }
266
+ /**
267
+ * The diagnostics of `file`, as `unfilteredDiagnosticsOfFile` gives them, where checkers checked it in
268
+ * ranges and found no diagnostics in it (`checkRange`).
269
+ */
270
+ unfilteredDiagnosticsOfCleanRanges(file) {
271
+ const result = this.getBindAndCheckDiagnostics(file, []);
272
+ for (const d of this.getIncludeProcessorDiagnostics(file))
273
+ result.push(d);
274
+ return result;
275
+ }
276
+ /**
277
+ * The diagnostics of `file`, as `unfilteredDiagnosticsOfFile` gives them, from a new checker that checks it
278
+ * whole: for a file checked in ranges that found diagnostics in it (parallel-check.ts), part of which this
279
+ * thread's checker may have checked.
280
+ */
281
+ unfilteredDiagnosticsOfFileOnNewChecker(file) {
282
+ const checker = this.createChecker();
283
+ const result = this.getBindAndCheckDiagnostics(file, checker.getDiagnostics(file));
284
+ disposeChecker(checker);
285
+ for (const d of this.getIncludeProcessorDiagnostics(file))
286
+ result.push(d);
287
+ return result;
288
+ }
253
289
  /**
254
290
  * The bind and check diagnostics of `file` before `noEmit` filtering and without include errors.
255
291
  * Once checker threads checked the program, they come from the threads' diagnostics of the file,
@@ -331,10 +367,11 @@ export class CheckedProgram {
331
367
  }
332
368
  return sortAndDeduplicateDiagnostics(result);
333
369
  }
334
- getBindAndCheckDiagnostics(file) {
370
+ /** `checks` are the checker's diagnostics of `file`. */
371
+ getBindAndCheckDiagnostics(file, checks) {
335
372
  const options = this.program.options;
336
373
  const diagnostics = file.bindDiagnostics.slice();
337
- for (const d of this.checker.getDiagnostics(file))
374
+ for (const d of checks ?? this.checker.getDiagnostics(file))
338
375
  diagnostics.push(d);
339
376
  if (isPlainJSFile(file, options)) {
340
377
  const result = [];
@@ -111,12 +111,8 @@ export declare class Program implements OutputPathsHost {
111
111
  /** Packages that modules resolved into, by name: whether any resolution into them was a declaration file. */
112
112
  getPackagesMap(): ReadonlyMap<string, boolean>;
113
113
  getResolvedModule(file: SourceFile, moduleName: string, mode: ModuleKind): ResolvedModule | undefined;
114
- /** The program files that the imports and type reference directives of `file` resolved to. */
115
- /**
116
- * The files `file` imports and references through type directives. `byFileName`, the program's
117
- * files by file name, finds a file without computing its path when it is resolved by that name.
118
- */
119
- getResolvedFilesOf(file: SourceFile, byFileName?: ReadonlyMap<string, SourceFile>): SourceFile[];
114
+ /** The files each file added to the program (`ProcessedFiles.addedFiles`), as indices of `getSourceFiles`. */
115
+ addedFiles(): readonly (readonly number[])[];
120
116
  /** The specifier of the implicit JSX runtime import of `file`, if any. */
121
117
  jsxRuntimeImportSpecifier(path: string): Node | undefined;
122
118
  getResolvedModuleFromModuleSpecifier(file: SourceFile, specifier: Node): ResolvedModule | undefined;