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.
- package/README.md +1 -1
- package/dist/api/compiler/ast.d.ts +2 -0
- package/dist/api/compiler/ast.js +3 -0
- package/dist/api/compiler/checker-calls.js +5 -1
- package/dist/api/compiler/checker-grammar.js +3 -2
- package/dist/api/compiler/checker-inference.js +8 -2
- package/dist/api/compiler/checker-members.js +8 -3
- package/dist/api/compiler/checker-source-file.d.ts +12 -0
- package/dist/api/compiler/checker-source-file.js +35 -0
- package/dist/api/compiler/checker-symbols.js +2 -1
- package/dist/api/compiler/checker-type-factory.js +8 -2
- package/dist/api/compiler/checker.d.ts +17 -1
- package/dist/api/compiler/checker.js +49 -1
- package/dist/api/compiler/compile-program.d.ts +26 -2
- package/dist/api/compiler/compile-program.js +100 -7
- package/dist/api/compiler/diagnostics.d.ts +22 -0
- package/dist/api/compiler/diagnostics.js +86 -4
- package/dist/api/compiler/file-loader.d.ts +13 -3
- package/dist/api/compiler/file-loader.js +106 -30
- package/dist/api/compiler/link-tables.d.ts +7 -0
- package/dist/api/compiler/link-tables.js +22 -0
- package/dist/api/compiler/parallel-parse.d.ts +3 -2
- package/dist/api/compiler/parallel-parse.js +17 -5
- package/dist/api/compiler/parser.js +15 -14
- package/dist/api/compiler/printer/emit-context.d.ts +2 -0
- package/dist/api/compiler/printer/emit-context.js +4 -0
- package/dist/api/compiler/printer/printer.d.ts +48 -2
- package/dist/api/compiler/printer/printer.js +238 -14
- package/dist/api/compiler/program-checker.d.ts +22 -0
- package/dist/api/compiler/program-checker.js +39 -2
- package/dist/api/compiler/program.d.ts +2 -6
- package/dist/api/compiler/program.js +5 -30
- package/dist/api/compiler/relations.js +10 -0
- package/dist/api/compiler/symbol.d.ts +1 -1
- package/dist/api/compiler/symbol.js +8 -10
- package/dist/api/library/diagnostics.d.ts +10 -0
- package/dist/api/library/diagnostics.js +20 -0
- package/package.json +9 -9
- package/src/compiler/ast.ts +3 -0
- package/src/compiler/checker-calls.ts +3 -1
- package/src/compiler/checker-grammar.ts +3 -2
- package/src/compiler/checker-inference.ts +7 -2
- package/src/compiler/checker-members.ts +9 -3
- package/src/compiler/checker-source-file.ts +34 -0
- package/src/compiler/checker-symbols.ts +2 -1
- package/src/compiler/checker-type-factory.ts +4 -2
- package/src/compiler/checker.ts +45 -1
- package/src/compiler/compile-program.ts +121 -7
- package/src/compiler/diagnostics.ts +84 -3
- package/src/compiler/file-loader.ts +106 -29
- package/src/compiler/incremental.ts +80 -13
- package/src/compiler/link-tables.ts +32 -0
- package/src/compiler/parallel-check.ts +326 -62
- package/src/compiler/parallel-emit.ts +320 -0
- package/src/compiler/parallel-parse.ts +16 -5
- package/src/compiler/parse-thread.ts +3 -0
- package/src/compiler/parser.ts +15 -16
- package/src/compiler/printer/emit-context.ts +5 -0
- package/src/compiler/printer/printer.ts +231 -16
- package/src/compiler/program-checker.ts +40 -2
- package/src/compiler/program.ts +5 -25
- package/src/compiler/relations.ts +7 -0
- package/src/compiler/symbol.ts +15 -10
- package/src/compiler/thread-entry.ts +61 -3
- package/src/compiler/tsc-build.ts +63 -9
- package/src/compiler/tsc-cli.ts +5 -0
- package/src/compiler/tsc-compile.ts +278 -3
- 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
|
-
|
|
3014
|
-
|
|
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
|
-
|
|
3018
|
-
|
|
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
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
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
|
-
/**
|
|
118
|
-
|
|
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
|
-
/**
|
|
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
|
-
|
|
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.
|
|
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 =
|
|
3772
|
-
|
|
3773
|
-
const
|
|
3774
|
-
const
|
|
3775
|
-
const
|
|
3776
|
-
const
|
|
3777
|
-
const
|
|
3778
|
-
|
|
3779
|
-
|
|
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
|
-
|
|
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
|
|
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;
|