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
|
@@ -174,7 +174,7 @@ import { SyntaxKind } from '../syntax-kind.js';
|
|
|
174
174
|
import { type CommentRange, TokenFlags } from '../types.js';
|
|
175
175
|
import { ScriptTarget } from '../options.js';
|
|
176
176
|
import { fileExtensionIs } from '../path.js';
|
|
177
|
-
import { isWhiteSpaceLike } from '../character-codes.js';
|
|
177
|
+
import { CharacterCodes, isWhiteSpaceLike } from '../character-codes.js';
|
|
178
178
|
import type { SourceMapGenerator } from '../sourcemap.js';
|
|
179
179
|
import { EmitContext, compareEmitHelpers, type SynthesizedComment } from './emit-context.js';
|
|
180
180
|
import { EmitFlags, GeneratedIdentifierFlags } from './emit-flags.js';
|
|
@@ -399,6 +399,9 @@ const enum State {
|
|
|
399
399
|
SourceMaps = 1 << 1,
|
|
400
400
|
}
|
|
401
401
|
|
|
402
|
+
/** The saved emit flags of a node whose comments were not looked for (`Printer.inCommentFreeRange`). */
|
|
403
|
+
const commentFreeNode = -1;
|
|
404
|
+
|
|
402
405
|
export class Printer extends NameGeneratorHost {
|
|
403
406
|
readonly options: PrinterOptions;
|
|
404
407
|
readonly context: EmitContext;
|
|
@@ -410,6 +413,13 @@ export class Printer extends NameGeneratorHost {
|
|
|
410
413
|
currentSourceFile: SourceFile | undefined;
|
|
411
414
|
private sourceText: string;
|
|
412
415
|
private lineStarts: readonly number[];
|
|
416
|
+
/**
|
|
417
|
+
* The line of the last `lineOf` lookup, `lookupLine`, and the positions it spans, `[lookupLineStart, lookupLineEnd)`,
|
|
418
|
+
* with `lookupLineEnd` -1 after the last line: printing reads positions mostly in order, so most lookups fall on that line.
|
|
419
|
+
*/
|
|
420
|
+
private lookupLine: number;
|
|
421
|
+
private lookupLineStart: number;
|
|
422
|
+
private lookupLineEnd: number;
|
|
413
423
|
private writer: TextWriter;
|
|
414
424
|
private ownWriter: TextWriter | undefined;
|
|
415
425
|
private uniqueHelperNames: Map<string, Identifier> | undefined;
|
|
@@ -423,8 +433,25 @@ export class Printer extends NameGeneratorHost {
|
|
|
423
433
|
private commentsDisabled: boolean;
|
|
424
434
|
/** Emitting the `extends` clause of a conditional or infer type. */
|
|
425
435
|
private inExtends: boolean;
|
|
426
|
-
/**
|
|
427
|
-
|
|
436
|
+
/**
|
|
437
|
+
* Saved comment state, 32-bit values: emit flags, comment pos, comment end, container pos, container end,
|
|
438
|
+
* declaration list end.
|
|
439
|
+
* Flags are `commentFreeNode` for a node that `emitCommentsBeforeNode` handled in a comment-free range.
|
|
440
|
+
*/
|
|
441
|
+
private commentStack: Int32Array;
|
|
442
|
+
/** The used length of `commentStack`: entries are written in place and kept for reuse once popped. */
|
|
443
|
+
private commentDepth: number;
|
|
444
|
+
/** Start positions of `//` and `/*` in `sourceText`, ascending; made on first use for each file. */
|
|
445
|
+
private commentStarts: Int32Array | undefined;
|
|
446
|
+
/**
|
|
447
|
+
* A range of `sourceText`, `[freeStart, freeEnd)`, where no comment starts and the last character is not trivia,
|
|
448
|
+
* so no comment is found from any position in it; -1 when there is none. `freeOwner` is the node it was made for.
|
|
449
|
+
*/
|
|
450
|
+
private freeStart: number;
|
|
451
|
+
private freeEnd: number;
|
|
452
|
+
/** Whether no trailing comment follows `freeEnd`. */
|
|
453
|
+
private freeEndTrailingNone: boolean;
|
|
454
|
+
private freeOwner: Node | undefined;
|
|
428
455
|
/** Saved source map state: emit flags, pos, end, has token range. */
|
|
429
456
|
private readonly sourceMapStack: number[];
|
|
430
457
|
/** The token position after `enterToken` skipped trivia. */
|
|
@@ -457,6 +484,9 @@ export class Printer extends NameGeneratorHost {
|
|
|
457
484
|
this.currentSourceFile = undefined;
|
|
458
485
|
this.sourceText = '';
|
|
459
486
|
this.lineStarts = [];
|
|
487
|
+
this.lookupLine = -1;
|
|
488
|
+
this.lookupLineStart = 0;
|
|
489
|
+
this.lookupLineEnd = 0;
|
|
460
490
|
this.writer = new TextWriter(options.newLine, 4);
|
|
461
491
|
this.ownWriter = undefined;
|
|
462
492
|
this.uniqueHelperNames = undefined;
|
|
@@ -468,7 +498,13 @@ export class Printer extends NameGeneratorHost {
|
|
|
468
498
|
this.detachedComments = [];
|
|
469
499
|
this.commentsDisabled = options.removeComments;
|
|
470
500
|
this.inExtends = false;
|
|
471
|
-
this.commentStack =
|
|
501
|
+
this.commentStack = new Int32Array(96);
|
|
502
|
+
this.commentDepth = 0;
|
|
503
|
+
this.commentStarts = undefined;
|
|
504
|
+
this.freeStart = -1;
|
|
505
|
+
this.freeEnd = -1;
|
|
506
|
+
this.freeEndTrailingNone = false;
|
|
507
|
+
this.freeOwner = undefined;
|
|
472
508
|
this.sourceMapStack = [];
|
|
473
509
|
this.tokenPos = 0;
|
|
474
510
|
this.sourceMapsDisabled = true;
|
|
@@ -518,6 +554,11 @@ export class Printer extends NameGeneratorHost {
|
|
|
518
554
|
this.currentSourceFile = sourceFile;
|
|
519
555
|
this.sourceText = sourceFile === undefined ? '' : sourceFile.text;
|
|
520
556
|
this.lineStarts = sourceFile === undefined ? [] : sourceFile.lineStarts();
|
|
557
|
+
this.lookupLine = -1;
|
|
558
|
+
this.lookupLineStart = 0;
|
|
559
|
+
this.lookupLineEnd = 0;
|
|
560
|
+
this.commentStarts = undefined;
|
|
561
|
+
this.endCommentFreeRange();
|
|
521
562
|
return true;
|
|
522
563
|
}
|
|
523
564
|
|
|
@@ -615,6 +656,8 @@ export class Printer extends NameGeneratorHost {
|
|
|
615
656
|
case SyntaxKind.Identifier:
|
|
616
657
|
case SyntaxKind.PrivateIdentifier:
|
|
617
658
|
case SyntaxKind.JsxNamespacedName:
|
|
659
|
+
// Its text either way: the source text, or the text of a node from elsewhere.
|
|
660
|
+
if (this.textIsSourceText(node)) return (node as Identifier | PrivateIdentifier).text;
|
|
618
661
|
if (!canUseSourceFile || !this.isInCurrentSourceFile(node)) {
|
|
619
662
|
if (node instanceof Identifier) return node.text;
|
|
620
663
|
if (node instanceof PrivateIdentifier) return node.text;
|
|
@@ -635,6 +678,38 @@ export class Printer extends NameGeneratorHost {
|
|
|
635
678
|
return getSourceTextOfNode(this.sourceText, node);
|
|
636
679
|
}
|
|
637
680
|
|
|
681
|
+
/**
|
|
682
|
+
* Whether the source text of an identifier or private identifier of the current file, from the end of its leading
|
|
683
|
+
* trivia to its end, is its text: the text ends the node, and the character before it is not part of the token, as
|
|
684
|
+
* it would be in an identifier written with escapes. Nodes from JSDoc may span other text, so they are left to the
|
|
685
|
+
* general path.
|
|
686
|
+
*/
|
|
687
|
+
private textIsSourceText(node: Node): boolean {
|
|
688
|
+
if (!(node instanceof Identifier) && !(node instanceof PrivateIdentifier)) return false;
|
|
689
|
+
if ((node.flags & (NodeFlags.Reparsed | NodeFlags.JSDoc | NodeFlags.ReparserTransformedLiteral)) !== 0)
|
|
690
|
+
return false;
|
|
691
|
+
const text = node.text;
|
|
692
|
+
const source = this.sourceText;
|
|
693
|
+
const end = node.end;
|
|
694
|
+
const start = end - text.length;
|
|
695
|
+
if (text.length === 0 || start < node.pos || end > source.length) return false;
|
|
696
|
+
if (!source.startsWith(text, start)) return false;
|
|
697
|
+
if (start === node.pos) return true;
|
|
698
|
+
const before = source.charCodeAt(start - 1);
|
|
699
|
+
return !(
|
|
700
|
+
(before >= CharacterCodes.a && before <= CharacterCodes.z) ||
|
|
701
|
+
(before >= CharacterCodes.A && before <= CharacterCodes.Z) ||
|
|
702
|
+
(before >= CharacterCodes._0 && before <= CharacterCodes._9) ||
|
|
703
|
+
before === CharacterCodes._ ||
|
|
704
|
+
before === CharacterCodes.$ ||
|
|
705
|
+
before === CharacterCodes.backslash ||
|
|
706
|
+
before === CharacterCodes.openBrace ||
|
|
707
|
+
before === CharacterCodes.closeBrace ||
|
|
708
|
+
before === CharacterCodes.hash ||
|
|
709
|
+
before > CharacterCodes.maxAsciiCharacter
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
|
|
638
713
|
private isInCurrentSourceFile(node: Node): boolean {
|
|
639
714
|
const file = this.currentSourceFile;
|
|
640
715
|
if (file === undefined) return false;
|
|
@@ -717,7 +792,28 @@ export class Printer extends NameGeneratorHost {
|
|
|
717
792
|
// Lines between nodes
|
|
718
793
|
|
|
719
794
|
private positionsAreOnSameLine(pos1: number, pos2: number): boolean {
|
|
720
|
-
|
|
795
|
+
if (pos1 === pos2) return true;
|
|
796
|
+
const lower = pos1 < pos2 ? pos1 : pos2;
|
|
797
|
+
const upper = pos1 < pos2 ? pos2 : pos1;
|
|
798
|
+
// What getLinesBetweenPositions finds: no line starts in (lower, upper].
|
|
799
|
+
if (lower < 0) {
|
|
800
|
+
const first = this.lineStarts.length > 0 ? this.lineStarts[0] | 0 : -1;
|
|
801
|
+
return first < 0 || upper < first;
|
|
802
|
+
}
|
|
803
|
+
this.lineOf(lower);
|
|
804
|
+
return this.lookupLineEnd < 0 || upper < this.lookupLineEnd;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/** The zero-based line of `pos` (-1 before the first line), which becomes the line of the last lookup. */
|
|
808
|
+
private lineOf(pos: number): number {
|
|
809
|
+
if (pos >= this.lookupLineStart && (pos < this.lookupLineEnd || this.lookupLineEnd < 0) && this.lookupLine >= 0)
|
|
810
|
+
return this.lookupLine;
|
|
811
|
+
const starts = this.lineStarts;
|
|
812
|
+
const line = computeLineOfPosition(starts, pos);
|
|
813
|
+
this.lookupLine = line;
|
|
814
|
+
this.lookupLineStart = line >= 0 ? starts[line] | 0 : 0;
|
|
815
|
+
this.lookupLineEnd = line + 1 < starts.length ? starts[line + 1] | 0 : -1;
|
|
816
|
+
return line;
|
|
721
817
|
}
|
|
722
818
|
|
|
723
819
|
private rangeStart(pos: number): number {
|
|
@@ -1049,8 +1145,13 @@ export class Printer extends NameGeneratorHost {
|
|
|
1049
1145
|
|
|
1050
1146
|
// Names
|
|
1051
1147
|
|
|
1052
|
-
// Source text of names reparsed from JSDoc can span lines.
|
|
1148
|
+
// Source text of names reparsed from JSDoc can span lines; an identifier's own source text has no line breaks.
|
|
1053
1149
|
private emitIdentifierText(node: Identifier): boolean {
|
|
1150
|
+
if (!this.context.autoGenerate.has(node) && this.textIsSourceText(node)) {
|
|
1151
|
+
// writeText's answer for text without line breaks.
|
|
1152
|
+
this.writer.write(node.text);
|
|
1153
|
+
return false;
|
|
1154
|
+
}
|
|
1054
1155
|
return this.writer.writeText(this.getTextOfNode(node));
|
|
1055
1156
|
}
|
|
1056
1157
|
|
|
@@ -4350,10 +4451,18 @@ export class Printer extends NameGeneratorHost {
|
|
|
4350
4451
|
|
|
4351
4452
|
private emitCommentsBeforeNode(node: Node): boolean {
|
|
4352
4453
|
if (!this.shouldEmitComments(node)) return false;
|
|
4454
|
+
if (this.inCommentFreeRange(node)) {
|
|
4455
|
+
// What the general path does for a node without emit data and without comments.
|
|
4456
|
+
this.pushCommentState(commentFreeNode, node.pos, node.end);
|
|
4457
|
+
this.containerPos = node.pos;
|
|
4458
|
+
this.containerEnd = node.end;
|
|
4459
|
+
if (node.kind === SyntaxKind.VariableDeclarationList) this.declarationListContainerEnd = node.end;
|
|
4460
|
+
return true;
|
|
4461
|
+
}
|
|
4353
4462
|
const flags = this.context.getEmitFlags(node);
|
|
4354
4463
|
const pos = this.context.commentPos(node);
|
|
4355
4464
|
const end = this.context.commentEnd(node);
|
|
4356
|
-
this.
|
|
4465
|
+
this.pushCommentState(flags, pos, end);
|
|
4357
4466
|
this.emitLeadingCommentsOfNode(node, flags, pos, end);
|
|
4358
4467
|
if ((flags & EmitFlags.NoLeadingComments) === 0) {
|
|
4359
4468
|
const synthesized = this.context.getSyntheticLeadingComments(node);
|
|
@@ -4363,17 +4472,43 @@ export class Printer extends NameGeneratorHost {
|
|
|
4363
4472
|
return true;
|
|
4364
4473
|
}
|
|
4365
4474
|
|
|
4475
|
+
/** Saves the comment state of a node: its emit flags (or `commentFreeNode`), comment range and the containers. */
|
|
4476
|
+
private pushCommentState(flags: number, pos: number, end: number): boolean {
|
|
4477
|
+
let stack = this.commentStack;
|
|
4478
|
+
const at = this.commentDepth;
|
|
4479
|
+
if (at + 6 > stack.length) {
|
|
4480
|
+
const grown = new Int32Array(stack.length * 2);
|
|
4481
|
+
grown.set(stack);
|
|
4482
|
+
this.commentStack = grown;
|
|
4483
|
+
stack = grown;
|
|
4484
|
+
}
|
|
4485
|
+
stack[at] = flags;
|
|
4486
|
+
stack[at + 1] = pos;
|
|
4487
|
+
stack[at + 2] = end;
|
|
4488
|
+
stack[at + 3] = this.containerPos;
|
|
4489
|
+
stack[at + 4] = this.containerEnd;
|
|
4490
|
+
stack[at + 5] = this.declarationListContainerEnd;
|
|
4491
|
+
this.commentDepth = at + 6;
|
|
4492
|
+
return true;
|
|
4493
|
+
}
|
|
4494
|
+
|
|
4366
4495
|
private emitCommentsAfterNode(node: Node): boolean {
|
|
4367
4496
|
const stack = this.commentStack;
|
|
4368
|
-
const base =
|
|
4369
|
-
|
|
4370
|
-
const
|
|
4371
|
-
const
|
|
4372
|
-
const
|
|
4373
|
-
const
|
|
4374
|
-
const
|
|
4375
|
-
|
|
4376
|
-
|
|
4497
|
+
const base = this.commentDepth - 6;
|
|
4498
|
+
const flags = stack[base]!;
|
|
4499
|
+
const pos = stack[base + 1]!;
|
|
4500
|
+
const end = stack[base + 2]!;
|
|
4501
|
+
const containerPos = stack[base + 3]!;
|
|
4502
|
+
const containerEnd = stack[base + 4]!;
|
|
4503
|
+
const declarationListContainerEnd = stack[base + 5]!;
|
|
4504
|
+
this.commentDepth = base;
|
|
4505
|
+
if (node === this.freeOwner) this.endCommentFreeRange();
|
|
4506
|
+
if (flags === commentFreeNode) {
|
|
4507
|
+
this.containerPos = containerPos;
|
|
4508
|
+
this.containerEnd = containerEnd;
|
|
4509
|
+
this.declarationListContainerEnd = declarationListContainerEnd;
|
|
4510
|
+
return true;
|
|
4511
|
+
}
|
|
4377
4512
|
if ((flags & EmitFlags.NoNestedComments) !== 0) this.commentsDisabled = false;
|
|
4378
4513
|
if ((flags & EmitFlags.NoTrailingComments) === 0) {
|
|
4379
4514
|
const synthesized = this.context.getSyntheticTrailingComments(node);
|
|
@@ -4395,6 +4530,83 @@ export class Printer extends NameGeneratorHost {
|
|
|
4395
4530
|
return true;
|
|
4396
4531
|
}
|
|
4397
4532
|
|
|
4533
|
+
/**
|
|
4534
|
+
* Whether `node` has no emit data and lies in a range of the source text where no comment is found, so that its
|
|
4535
|
+
* comments need not be looked for. Outside such a range, a node whose own range is one starts it (`freeOwner`).
|
|
4536
|
+
*/
|
|
4537
|
+
private inCommentFreeRange(node: Node): boolean {
|
|
4538
|
+
const pos = node.pos;
|
|
4539
|
+
const end = node.end;
|
|
4540
|
+
if (pos < 0 || end <= pos || node.kind === SyntaxKind.JsxText || node.kind === SyntaxKind.NotEmittedStatement)
|
|
4541
|
+
return false;
|
|
4542
|
+
if (this.freeEnd < 0) {
|
|
4543
|
+
if (!this.startCommentFreeRange(pos, end)) return false;
|
|
4544
|
+
this.freeOwner = node;
|
|
4545
|
+
} else if (pos < this.freeStart) return false;
|
|
4546
|
+
if (this.context.hasEmitNode(node)) return false;
|
|
4547
|
+
return end < this.freeEnd || (end === this.freeEnd && this.freeEndTrailingNone);
|
|
4548
|
+
}
|
|
4549
|
+
|
|
4550
|
+
private endCommentFreeRange(): boolean {
|
|
4551
|
+
this.freeStart = -1;
|
|
4552
|
+
this.freeEnd = -1;
|
|
4553
|
+
this.freeEndTrailingNone = false;
|
|
4554
|
+
this.freeOwner = undefined;
|
|
4555
|
+
return true;
|
|
4556
|
+
}
|
|
4557
|
+
|
|
4558
|
+
/** Whether the comment-free range shows that no trailing comment follows `pos`. */
|
|
4559
|
+
private noCommentsAfter(pos: number): boolean {
|
|
4560
|
+
return pos >= this.freeStart && (pos < this.freeEnd || (pos === this.freeEnd && this.freeEndTrailingNone));
|
|
4561
|
+
}
|
|
4562
|
+
|
|
4563
|
+
/** Makes `[pos, end)` the comment-free range if no comment starts in it and its last character is not trivia. */
|
|
4564
|
+
private startCommentFreeRange(pos: number, end: number): boolean {
|
|
4565
|
+
const text = this.sourceText;
|
|
4566
|
+
if (end > text.length) return false;
|
|
4567
|
+
const last = text.charCodeAt(end - 1);
|
|
4568
|
+
if (
|
|
4569
|
+
last === CharacterCodes.space ||
|
|
4570
|
+
last === CharacterCodes.tab ||
|
|
4571
|
+
last === CharacterCodes.lineFeed ||
|
|
4572
|
+
last === CharacterCodes.carriageReturn ||
|
|
4573
|
+
last === CharacterCodes.verticalTab ||
|
|
4574
|
+
last === CharacterCodes.formFeed ||
|
|
4575
|
+
last > CharacterCodes.maxAsciiCharacter
|
|
4576
|
+
)
|
|
4577
|
+
return false;
|
|
4578
|
+
const starts = this.commentStartsOfFile();
|
|
4579
|
+
// The first comment start at or after `pos`.
|
|
4580
|
+
let low = 0;
|
|
4581
|
+
let high = starts.length;
|
|
4582
|
+
while (low < high) {
|
|
4583
|
+
const middle = (low + high) >>> 1;
|
|
4584
|
+
if (starts[middle]! < pos) low = middle + 1;
|
|
4585
|
+
else high = middle;
|
|
4586
|
+
}
|
|
4587
|
+
if (low < starts.length && starts[low]! < end) return false;
|
|
4588
|
+
this.freeStart = pos;
|
|
4589
|
+
this.freeEnd = end;
|
|
4590
|
+
this.freeEndTrailingNone = getTrailingCommentRanges(text, end) === undefined;
|
|
4591
|
+
return true;
|
|
4592
|
+
}
|
|
4593
|
+
|
|
4594
|
+
private commentStartsOfFile(): Int32Array {
|
|
4595
|
+
const cached = this.commentStarts;
|
|
4596
|
+
if (cached !== undefined) return cached;
|
|
4597
|
+
const text = this.sourceText;
|
|
4598
|
+
const length = text.length;
|
|
4599
|
+
const list: number[] = [];
|
|
4600
|
+
for (let i = text.indexOf('/'); i >= 0 && i + 1 < length; i = text.indexOf('/', i + 1)) {
|
|
4601
|
+
const next = text.charCodeAt(i + 1);
|
|
4602
|
+
if (next === CharacterCodes.slash || next === CharacterCodes.asterisk) list.push(i);
|
|
4603
|
+
}
|
|
4604
|
+
const starts = new Int32Array(list.length);
|
|
4605
|
+
for (let i = 0; i < list.length; i++) starts[i] = list[i]!;
|
|
4606
|
+
this.commentStarts = starts;
|
|
4607
|
+
return starts;
|
|
4608
|
+
}
|
|
4609
|
+
|
|
4398
4610
|
/** Emits comments before a token; returns whether `emitCommentsAfterToken` applies, with the token's position in `tokenPos`. */
|
|
4399
4611
|
private emitCommentsBeforeToken(pos: number, contextNode: Node, flags: TokenEmitFlags): boolean {
|
|
4400
4612
|
if ((flags & TokenEmitFlags.NoComments) !== 0 || this.commentsDisabled) {
|
|
@@ -4505,6 +4717,7 @@ export class Printer extends NameGeneratorHost {
|
|
|
4505
4717
|
private emitLeadingComments(pos: number, elided: boolean): boolean {
|
|
4506
4718
|
if (this.commentsDisabled || this.currentSourceFile === undefined || pos < 0 || pos === this.containerPos)
|
|
4507
4719
|
return false;
|
|
4720
|
+
if (pos >= this.freeStart && pos < this.freeEnd) return false;
|
|
4508
4721
|
// 1: only triple-slash comments, 2: all but triple-slash comments, 0: all.
|
|
4509
4722
|
let tripleSlash = 0;
|
|
4510
4723
|
if (!elided) {
|
|
@@ -4552,6 +4765,7 @@ export class Printer extends NameGeneratorHost {
|
|
|
4552
4765
|
(this.containerEnd !== -1 && (pos === this.containerEnd || pos === this.declarationListContainerEnd))
|
|
4553
4766
|
)
|
|
4554
4767
|
return false;
|
|
4768
|
+
if (this.noCommentsAfter(pos)) return false;
|
|
4555
4769
|
const ranges = getTrailingCommentRanges(this.sourceText, pos);
|
|
4556
4770
|
if (ranges === undefined) return false;
|
|
4557
4771
|
let comments: CommentRange[] | undefined = undefined;
|
|
@@ -4567,6 +4781,7 @@ export class Printer extends NameGeneratorHost {
|
|
|
4567
4781
|
if (this.commentsDisabled || this.currentSourceFile === undefined) return false;
|
|
4568
4782
|
if (this.containerEnd !== -1 && (pos === this.containerEnd || pos === this.declarationListContainerEnd))
|
|
4569
4783
|
return false;
|
|
4784
|
+
if (this.noCommentsAfter(pos)) return false;
|
|
4570
4785
|
const comments = getTrailingCommentRanges(this.sourceText, pos);
|
|
4571
4786
|
if (comments === undefined) return false;
|
|
4572
4787
|
for (const comment of comments) {
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
type SourceFileMetadata,
|
|
27
27
|
} from './program-utilities.js';
|
|
28
28
|
import { bindSourceFile } from './binder.js';
|
|
29
|
+
import { checkSourceFileRange } from './checker-source-file.js';
|
|
29
30
|
import { computeLineOfPosition } from './scanner.js';
|
|
30
31
|
import { CommentDirectiveKind } from './types.js';
|
|
31
32
|
|
|
@@ -275,6 +276,10 @@ export class CheckedProgram {
|
|
|
275
276
|
* emit. Set once every file is checked, when checker threads emit (parallel-check.ts).
|
|
276
277
|
*/
|
|
277
278
|
emittedInParallel: (EmitResult | undefined)[] | undefined = undefined;
|
|
279
|
+
/** Emit threads emitted only the JavaScript of `emittedInParallel`: declarations are emitted here. */
|
|
280
|
+
javaScriptEmittedOnThreads = false;
|
|
281
|
+
/** The declaration emit of each file on the declaration thread (parallel-emit.ts); undefined for one it didn't emit. */
|
|
282
|
+
declarationsEmittedAhead: (EmitResult | undefined)[] | undefined = undefined;
|
|
278
283
|
/**
|
|
279
284
|
* The global diagnostics of this thread's checker before it emitted files while checker threads
|
|
280
285
|
* checked (`emitUncheckedFiles`), reported instead of its current ones.
|
|
@@ -313,6 +318,38 @@ export class CheckedProgram {
|
|
|
313
318
|
return result;
|
|
314
319
|
}
|
|
315
320
|
|
|
321
|
+
/**
|
|
322
|
+
* Checks the statements `start` to `end` of the declaration file `file` with this checker, one of the
|
|
323
|
+
* ranges that several checkers check it in (`checkSourceFileRange`, parallel-check.ts), and returns
|
|
324
|
+
* whether the checker then has diagnostics in the file.
|
|
325
|
+
*/
|
|
326
|
+
checkRange(file: SourceFile, start: number, end: number): boolean {
|
|
327
|
+
return checkSourceFileRange(this.checker, file, start, end);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* The diagnostics of `file`, as `unfilteredDiagnosticsOfFile` gives them, where checkers checked it in
|
|
332
|
+
* ranges and found no diagnostics in it (`checkRange`).
|
|
333
|
+
*/
|
|
334
|
+
unfilteredDiagnosticsOfCleanRanges(file: SourceFile): Diagnostic[] {
|
|
335
|
+
const result = this.getBindAndCheckDiagnostics(file, []);
|
|
336
|
+
for (const d of this.getIncludeProcessorDiagnostics(file)) result.push(d);
|
|
337
|
+
return result;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* The diagnostics of `file`, as `unfilteredDiagnosticsOfFile` gives them, from a new checker that checks it
|
|
342
|
+
* whole: for a file checked in ranges that found diagnostics in it (parallel-check.ts), part of which this
|
|
343
|
+
* thread's checker may have checked.
|
|
344
|
+
*/
|
|
345
|
+
unfilteredDiagnosticsOfFileOnNewChecker(file: SourceFile): Diagnostic[] {
|
|
346
|
+
const checker = this.createChecker();
|
|
347
|
+
const result = this.getBindAndCheckDiagnostics(file, checker.getDiagnostics(file));
|
|
348
|
+
disposeChecker(checker);
|
|
349
|
+
for (const d of this.getIncludeProcessorDiagnostics(file)) result.push(d);
|
|
350
|
+
return result;
|
|
351
|
+
}
|
|
352
|
+
|
|
316
353
|
/**
|
|
317
354
|
* The bind and check diagnostics of `file` before `noEmit` filtering and without include errors.
|
|
318
355
|
* Once checker threads checked the program, they come from the threads' diagnostics of the file,
|
|
@@ -395,10 +432,11 @@ export class CheckedProgram {
|
|
|
395
432
|
return sortAndDeduplicateDiagnostics(result);
|
|
396
433
|
}
|
|
397
434
|
|
|
398
|
-
|
|
435
|
+
/** `checks` are the checker's diagnostics of `file`. */
|
|
436
|
+
private getBindAndCheckDiagnostics(file: SourceFile, checks?: readonly Diagnostic[]): Diagnostic[] {
|
|
399
437
|
const options = this.program.options;
|
|
400
438
|
const diagnostics = file.bindDiagnostics.slice();
|
|
401
|
-
for (const d of this.checker.getDiagnostics(file)) diagnostics.push(d);
|
|
439
|
+
for (const d of checks ?? this.checker.getDiagnostics(file)) diagnostics.push(d);
|
|
402
440
|
if (isPlainJSFile(file, options)) {
|
|
403
441
|
const result: Diagnostic[] = [];
|
|
404
442
|
for (const d of diagnostics) if (plainJSErrors.has(d.code)) result.push(d);
|
package/src/compiler/program.ts
CHANGED
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
equalDiagnosticsNoRelatedInfo,
|
|
28
28
|
type DiagnosticMessage,
|
|
29
29
|
type Locale,
|
|
30
|
+
sortDiagnostics,
|
|
30
31
|
useThreadTextCaches,
|
|
31
32
|
} from './diagnostics.js';
|
|
32
33
|
import {
|
|
@@ -455,30 +456,9 @@ export class Program implements OutputPathsHost {
|
|
|
455
456
|
return this.processed.resolvedModules.get(file.path)?.get(modeAwareKey(moduleName, mode));
|
|
456
457
|
}
|
|
457
458
|
|
|
458
|
-
/** The
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
* files by file name, finds a file without computing its path when it is resolved by that name.
|
|
462
|
-
*/
|
|
463
|
-
getResolvedFilesOf(file: SourceFile, byFileName?: ReadonlyMap<string, SourceFile>): SourceFile[] {
|
|
464
|
-
const result: SourceFile[] = [];
|
|
465
|
-
const modules = this.processed.resolvedModules.get(file.path);
|
|
466
|
-
if (modules !== undefined)
|
|
467
|
-
for (const resolved of modules.values()) {
|
|
468
|
-
const name = resolved.resolvedFileName;
|
|
469
|
-
if (name === '') continue;
|
|
470
|
-
const target = byFileName?.get(name) ?? this.getSourceFileForResolvedModule(name);
|
|
471
|
-
if (target !== undefined) result.push(target);
|
|
472
|
-
}
|
|
473
|
-
const types = this.processed.typeResolutionsInFile.get(file.path);
|
|
474
|
-
if (types !== undefined)
|
|
475
|
-
for (const resolved of types.values()) {
|
|
476
|
-
const name = resolved.resolvedFileName;
|
|
477
|
-
if (name === '') continue;
|
|
478
|
-
const target = byFileName?.get(name) ?? this.getSourceFile(name);
|
|
479
|
-
if (target !== undefined) result.push(target);
|
|
480
|
-
}
|
|
481
|
-
return result;
|
|
459
|
+
/** The files each file added to the program (`ProcessedFiles.addedFiles`), as indices of `getSourceFiles`. */
|
|
460
|
+
addedFiles(): readonly (readonly number[])[] {
|
|
461
|
+
return this.processed.addedFiles;
|
|
482
462
|
}
|
|
483
463
|
|
|
484
464
|
/** The specifier of the implicit JSX runtime import of `file`, if any. */
|
|
@@ -1398,7 +1378,7 @@ class NodeCollector extends NodeVisitor {
|
|
|
1398
1378
|
|
|
1399
1379
|
/** Sorts diagnostics and merges duplicates, combining their related information. */
|
|
1400
1380
|
export function sortAndDeduplicateDiagnostics(diagnostics: readonly Diagnostic[]): Diagnostic[] {
|
|
1401
|
-
const sorted =
|
|
1381
|
+
const sorted = sortDiagnostics(diagnostics);
|
|
1402
1382
|
if (sorted.length < 2) return sorted;
|
|
1403
1383
|
const result: Diagnostic[] = [];
|
|
1404
1384
|
let i = 0;
|
|
@@ -517,6 +517,13 @@ export function isTypeRelatedTo(c: Checker, source: Type, target: Type, relation
|
|
|
517
517
|
// Types that can't simplify must have identical flags.
|
|
518
518
|
if (source.flags !== target.flags) return false;
|
|
519
519
|
if ((source.flags & TypeFlags.Singleton) !== 0) return true;
|
|
520
|
+
} else {
|
|
521
|
+
// What the relater decides first for types that may simplify (Relater.isRelatedToEx): their normal forms are
|
|
522
|
+
// one type, or can be identical only with identical flags.
|
|
523
|
+
const s = getNormalizedType(c, source, false);
|
|
524
|
+
const t = getNormalizedType(c, target, true);
|
|
525
|
+
if (s === t) return true;
|
|
526
|
+
if (s.flags !== t.flags) return false;
|
|
520
527
|
}
|
|
521
528
|
if ((source.flags & TypeFlags.Object) !== 0 && (target.flags & TypeFlags.Object) !== 0) {
|
|
522
529
|
const related = relation.get(
|
package/src/compiler/symbol.ts
CHANGED
|
@@ -156,12 +156,17 @@ export class SymbolRareFields implements ProgramLifetime {
|
|
|
156
156
|
valueDeclaration: Node | undefined = undefined;
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
/**
|
|
160
|
-
|
|
159
|
+
/**
|
|
160
|
+
* In `Symbol.bits`, above the check flags: the value declaration is the first declaration. A const enum
|
|
161
|
+
* member, so that native builds read it as a constant rather than as a module variable.
|
|
162
|
+
*/
|
|
163
|
+
const enum SymbolBits {
|
|
164
|
+
ValueDeclarationIsFirst = 1 << 30,
|
|
165
|
+
}
|
|
161
166
|
|
|
162
167
|
export class Symbol implements ProgramLifetime {
|
|
163
168
|
flags: SymbolFlags;
|
|
164
|
-
/** The check flags, and `
|
|
169
|
+
/** The check flags, and `SymbolBits.ValueDeclarationIsFirst`. */
|
|
165
170
|
private bits: number;
|
|
166
171
|
readonly name: string;
|
|
167
172
|
/**
|
|
@@ -186,19 +191,19 @@ export class Symbol implements ProgramLifetime {
|
|
|
186
191
|
}
|
|
187
192
|
|
|
188
193
|
get checkFlags(): CheckFlags {
|
|
189
|
-
return (this.bits & ~
|
|
194
|
+
return (this.bits & ~SymbolBits.ValueDeclarationIsFirst) as CheckFlags;
|
|
190
195
|
}
|
|
191
196
|
|
|
192
197
|
set checkFlags(flags: CheckFlags) {
|
|
193
|
-
this.bits = (this.bits &
|
|
198
|
+
this.bits = (this.bits & SymbolBits.ValueDeclarationIsFirst) | flags;
|
|
194
199
|
}
|
|
195
200
|
|
|
196
201
|
/** Makes `node` the first declaration, keeping the value declaration. */
|
|
197
202
|
setFirst(node: Node | undefined): void {
|
|
198
|
-
if ((this.bits &
|
|
203
|
+
if ((this.bits & SymbolBits.ValueDeclarationIsFirst) !== 0 && node !== this.declaration) {
|
|
199
204
|
// The value declaration stays what it was.
|
|
200
205
|
this.rareFieldsOrNew().valueDeclaration = this.declaration;
|
|
201
|
-
this.bits &= ~
|
|
206
|
+
this.bits &= ~SymbolBits.ValueDeclarationIsFirst;
|
|
202
207
|
}
|
|
203
208
|
this.declaration = node;
|
|
204
209
|
}
|
|
@@ -208,7 +213,7 @@ export class Symbol implements ProgramLifetime {
|
|
|
208
213
|
* says; any other is kept in the rare fields.
|
|
209
214
|
*/
|
|
210
215
|
get valueDeclaration(): Node | undefined {
|
|
211
|
-
if ((this.bits &
|
|
216
|
+
if ((this.bits & SymbolBits.ValueDeclarationIsFirst) !== 0) return this.declaration;
|
|
212
217
|
const group = this.rareFields;
|
|
213
218
|
return group === undefined ? undefined : group.valueDeclaration;
|
|
214
219
|
}
|
|
@@ -216,11 +221,11 @@ export class Symbol implements ProgramLifetime {
|
|
|
216
221
|
set valueDeclaration(node: Node | undefined) {
|
|
217
222
|
const group = this.rareFields;
|
|
218
223
|
if (node !== undefined && node === this.declaration) {
|
|
219
|
-
this.bits |=
|
|
224
|
+
this.bits |= SymbolBits.ValueDeclarationIsFirst;
|
|
220
225
|
if (group !== undefined) group.valueDeclaration = undefined;
|
|
221
226
|
return;
|
|
222
227
|
}
|
|
223
|
-
this.bits &= ~
|
|
228
|
+
this.bits &= ~SymbolBits.ValueDeclarationIsFirst;
|
|
224
229
|
if (node !== undefined || group !== undefined) this.rareFieldsOrNew().valueDeclaration = node;
|
|
225
230
|
}
|
|
226
231
|
|