tsc-ts 0.0.9 → 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 +2 -1
- package/dist/api/compiler/checker-type-factory.js +8 -2
- package/dist/api/compiler/checker.d.ts +11 -0
- package/dist/api/compiler/checker.js +40 -0
- 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 +11 -1
- package/dist/api/compiler/file-loader.js +63 -7
- package/dist/api/compiler/parallel-parse.d.ts +3 -2
- package/dist/api/compiler/parallel-parse.js +17 -5
- 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 +4 -0
- package/dist/api/compiler/program-checker.js +4 -0
- 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/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 +3 -1
- package/src/compiler/checker-type-factory.ts +4 -2
- package/src/compiler/checker.ts +37 -0
- package/src/compiler/compile-program.ts +121 -7
- package/src/compiler/diagnostics.ts +84 -3
- package/src/compiler/file-loader.ts +58 -6
- package/src/compiler/incremental.ts +80 -13
- package/src/compiler/parallel-check.ts +129 -44
- 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/printer/emit-context.ts +5 -0
- package/src/compiler/printer/printer.ts +231 -16
- package/src/compiler/program-checker.ts +4 -0
- 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 +45 -2
- 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/README.md
CHANGED
|
@@ -31,7 +31,7 @@ npx tsc-ts -p tsconfig.json
|
|
|
31
31
|
npx tsc-ts --noEmit src/index.ts
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
`tsc-ts --api` serves the TypeScript API over stdin and stdout, like `tsc --api`. On Windows, `--api --pipe \\.\pipe\<name>` serves it over a named pipe it creates, as `tsc --api --pipe` does, for clients that connect to the pipe (such as scriptc under Node.js); only the native executable supports `--pipe`.
|
|
34
|
+
`tsc-ts --api` serves the TypeScript API over stdin and stdout, like `tsc --api`. On Windows, `--api --pipe \\.\pipe\<name>` serves it over a named pipe it creates, as `tsc --api --pipe` does, for clients that connect to the pipe (such as scriptc under Node.js); only the native executable supports `--pipe`. On macOS and Linux, `--api --listen <path>` serves it on a Unix socket it creates, with mode 0600, to one client of the same user at a time, each until the client closes its end. Each client gets the answers a new `tsc-ts --api` process would give, except that symbol ids continue from earlier clients, and the server reads every file through the client again, but it keeps parsed files between clients and reuses those whose text is unchanged, along with the encoding `getSourceFile` sends for each, so a client that opens the same project again loads it faster. The server exits when no client connects for 60 seconds (`--idle-exit <seconds>` sets the time), or after a client when its resident memory is above 2.5 times what it held after its first client (`TSC_TS_LISTEN_MEMORY` sets the limit in megabytes). To stop, it removes the socket file, serves the clients that had connected, and exits. It replaces a socket file that no server answers on, such as one left by a server that was killed. Only the native executable supports `--listen`. With `--default-libraries-from-disk`, the server reads the files in its default library directory (`TSC_TS_LIB_DIR`, or the executable's directory) from the disk itself, even when the client handles file system calls (`--callbacks`), which saves a round trip to the client for each library file.
|
|
35
35
|
|
|
36
36
|
`--checkers N` checks the program on N threads. Unless `--checkers` or `--singleThreaded` is given, the native executable uses one checker per CPU it may run on (up to 16), and at least tsgo's four; it uses fewer than the CPUs, but never fewer than four, when the estimated peak memory of more checkers would not fit 85% of the machine's memory (`TSC_TS_CHECKERS=fixed` keeps tsgo's four), and checkers beyond the fourth stop taking files, one at a time, when the process's memory reaches that share; it shares one program between its threads and also parses and binds the program's files on them. Unless `--singleThreaded` is given, the program's files are parsed and bound on threads also with `--checkers 1`, as tsgo does. Files that share costly declarations, such as a large generated schema and the few files importing it, are checked together on one checker. Under Node.js, where every thread builds its own copy of the program, tsc-ts checks on one thread unless `--checkers` is given. `--incremental`, `--watch` and `--build` always check on one thread. The diagnostics are the same as with one checker.
|
|
37
37
|
|
|
@@ -2281,6 +2281,8 @@ export declare class SourceFile extends Node {
|
|
|
2281
2281
|
identifierCount: number;
|
|
2282
2282
|
nodeCount: number;
|
|
2283
2283
|
textCount: number;
|
|
2284
|
+
/** The API's binary encoding of this file, when an API server keeps it (`keptEncodingOf`). */
|
|
2285
|
+
apiEncoding: Uint8Array | undefined;
|
|
2284
2286
|
/** Module specifiers of imports, exports, `require` calls and `import()` types, in source order. */
|
|
2285
2287
|
imports: Node[];
|
|
2286
2288
|
/** Names of `declare module "x"` augmentations and `declare global` blocks in modules. */
|
package/dist/api/compiler/ast.js
CHANGED
|
@@ -6641,6 +6641,8 @@ export class SourceFile extends Node {
|
|
|
6641
6641
|
identifierCount;
|
|
6642
6642
|
nodeCount;
|
|
6643
6643
|
textCount;
|
|
6644
|
+
/** The API's binary encoding of this file, when an API server keeps it (`keptEncodingOf`). */
|
|
6645
|
+
apiEncoding;
|
|
6644
6646
|
/** Module specifiers of imports, exports, `require` calls and `import()` types, in source order. */
|
|
6645
6647
|
imports;
|
|
6646
6648
|
/** Names of `declare module "x"` augmentations and `declare global` blocks in modules. */
|
|
@@ -6699,6 +6701,7 @@ export class SourceFile extends Node {
|
|
|
6699
6701
|
this.identifierCount = 0;
|
|
6700
6702
|
this.nodeCount = 0;
|
|
6701
6703
|
this.textCount = 0;
|
|
6704
|
+
this.apiEncoding = undefined;
|
|
6702
6705
|
this.imports = [];
|
|
6703
6706
|
this.moduleAugmentations = emptyNodes;
|
|
6704
6707
|
this.ambientModuleNames = emptyStrings;
|
|
@@ -709,7 +709,11 @@ export function reorderCandidates(c, signatures, callChainFlags) {
|
|
|
709
709
|
spliceIndex = index;
|
|
710
710
|
if (callChainFlags !== 0)
|
|
711
711
|
signature = getOptionalCallSignature(c, signature, callChainFlags);
|
|
712
|
-
|
|
712
|
+
// Most signatures go at the end, where a push is cheaper than an inserting splice.
|
|
713
|
+
if (spliceIndex === result.length)
|
|
714
|
+
result.push(signature);
|
|
715
|
+
else
|
|
716
|
+
result.splice(spliceIndex, 0, signature);
|
|
713
717
|
}
|
|
714
718
|
return result;
|
|
715
719
|
}
|
|
@@ -2255,7 +2255,8 @@ function getEmitSyntaxOfImportOrExport(g) {
|
|
|
2255
2255
|
return ModuleKind.None;
|
|
2256
2256
|
}
|
|
2257
2257
|
function checkGrammarObjectLiteralExpression(g, node, inDestructuring) {
|
|
2258
|
-
|
|
2258
|
+
// An object literal with one property can't repeat a name, so it needs no table of names.
|
|
2259
|
+
const seen = node.properties.nodes.length > 1 ? new Map() : undefined;
|
|
2259
2260
|
for (const property of node.properties.nodes) {
|
|
2260
2261
|
if (property.kind === 305 /* SyntaxKind.SpreadAssignment */) {
|
|
2261
2262
|
if (inDestructuring) {
|
|
@@ -2313,7 +2314,7 @@ function checkGrammarObjectLiteralExpression(g, node, inDestructuring) {
|
|
|
2313
2314
|
if (inDestructuring)
|
|
2314
2315
|
continue;
|
|
2315
2316
|
const effectiveName = getEffectivePropertyNameForPropertyNameNode(g.c, name);
|
|
2316
|
-
if (effectiveName === undefined)
|
|
2317
|
+
if (effectiveName === undefined || seen === undefined)
|
|
2317
2318
|
continue;
|
|
2318
2319
|
const existingKind = seen.get(effectiveName);
|
|
2319
2320
|
if (existingKind === undefined) {
|
|
@@ -450,8 +450,14 @@ class InferenceState {
|
|
|
450
450
|
index = 0;
|
|
451
451
|
while (index < inference.candidateDepths.length && inference.candidateDepths[index] >= this.depth)
|
|
452
452
|
index++;
|
|
453
|
-
inference.candidates.
|
|
454
|
-
|
|
453
|
+
if (index === inference.candidates.length) {
|
|
454
|
+
inference.candidates.push(candidate);
|
|
455
|
+
inference.candidateDepths.push(this.depth);
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
inference.candidates.splice(index, 0, candidate);
|
|
459
|
+
inference.candidateDepths.splice(index, 0, this.depth);
|
|
460
|
+
}
|
|
455
461
|
clearCachedInferences(this.inferences);
|
|
456
462
|
}
|
|
457
463
|
}
|
|
@@ -1268,7 +1268,8 @@ export function getPropertyOfTypeEx(c, t, name, skipObjectFunctionPropertyAugmen
|
|
|
1268
1268
|
if (!isOwnReducedApparentType(t))
|
|
1269
1269
|
t = getReducedApparentTypeWorker(c, t);
|
|
1270
1270
|
if ((t.flags & 1048576 /* TypeFlags.Object */) !== 0) {
|
|
1271
|
-
|
|
1271
|
+
// The first test of resolveStructuredTypeMembers, here where most lookups find the members resolved.
|
|
1272
|
+
const resolved = (t.objectFlags & 2097152 /* ObjectFlags.MembersResolved */) !== 0 ? t : resolveStructuredTypeMembers(c, t);
|
|
1272
1273
|
const symbol = getResolvedMember(resolved, name);
|
|
1273
1274
|
if (symbol !== undefined && includeTypeOnlyMembers)
|
|
1274
1275
|
return symbol;
|
|
@@ -989,7 +989,10 @@ export function insertType(c, types, t) {
|
|
|
989
989
|
const index = binarySearchTypes(c, types, t);
|
|
990
990
|
if (index >= 0)
|
|
991
991
|
return false;
|
|
992
|
-
|
|
992
|
+
if (~index === types.length)
|
|
993
|
+
types.push(t);
|
|
994
|
+
else
|
|
995
|
+
types.splice(~index, 0, t);
|
|
993
996
|
return true;
|
|
994
997
|
}
|
|
995
998
|
// ---- Iterating unions
|
|
@@ -1198,7 +1201,10 @@ function insertTypeNearLast(c, set, t) {
|
|
|
1198
1201
|
else
|
|
1199
1202
|
high = middle - 1;
|
|
1200
1203
|
}
|
|
1201
|
-
|
|
1204
|
+
if (low === types.length)
|
|
1205
|
+
types.push(t);
|
|
1206
|
+
else
|
|
1207
|
+
types.splice(low, 0, t);
|
|
1202
1208
|
set.last = low;
|
|
1203
1209
|
}
|
|
1204
1210
|
function getUnionTypeWorker(c, types, unionReduction, alias, origin) {
|
|
@@ -71,6 +71,10 @@ declare class DiagnosticCollection {
|
|
|
71
71
|
/** An already reported diagnostic equal to `diagnostic`, if any. */
|
|
72
72
|
lookup(diagnostic: Diagnostic): Diagnostic | undefined;
|
|
73
73
|
globals(): Diagnostic[];
|
|
74
|
+
/** The global diagnostics `withoutNewGlobals` removed. */
|
|
75
|
+
removedGlobals: number;
|
|
76
|
+
/** Runs `run`, then removes the global diagnostics it added. */
|
|
77
|
+
withoutNewGlobals<T>(run: () => T): T;
|
|
74
78
|
/** Records the diagnostics added from now on. */
|
|
75
79
|
startLog(): void;
|
|
76
80
|
/** The diagnostics added since `startLog`, in order; stops recording. */
|
|
@@ -491,6 +495,13 @@ export declare class Checker implements TypeChecking {
|
|
|
491
495
|
getSuggestionDiagnostics(file: SourceFile): Diagnostic[];
|
|
492
496
|
/** Diagnostics without a file, such as missing global types. */
|
|
493
497
|
getGlobalDiagnostics(): Diagnostic[];
|
|
498
|
+
/**
|
|
499
|
+
* Runs `run` (such as emitting declarations), then forgets the global diagnostics it reported:
|
|
500
|
+
* the program collects global diagnostics before it emits.
|
|
501
|
+
*/
|
|
502
|
+
withoutGlobalDiagnostics<T>(run: () => T): T;
|
|
503
|
+
/** The global diagnostics `withoutGlobalDiagnostics` forgot so far. */
|
|
504
|
+
forgottenGlobalDiagnostics(): number;
|
|
494
505
|
/** The rarely used links of `symbol`, created on first use. */
|
|
495
506
|
symbolLinks(symbol: Symbol): SymbolLinks;
|
|
496
507
|
/** The links of `symbol` if it has any, without creating them. */
|
|
@@ -137,6 +137,35 @@ class DiagnosticCollection {
|
|
|
137
137
|
}
|
|
138
138
|
return this.global.slice();
|
|
139
139
|
}
|
|
140
|
+
/** The global diagnostics `withoutNewGlobals` removed. */
|
|
141
|
+
removedGlobals = 0;
|
|
142
|
+
/** Runs `run`, then removes the global diagnostics it added. */
|
|
143
|
+
withoutNewGlobals(run) {
|
|
144
|
+
const outer = this.log;
|
|
145
|
+
const added = [];
|
|
146
|
+
this.log = added;
|
|
147
|
+
try {
|
|
148
|
+
return run();
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
this.log = outer;
|
|
152
|
+
if (outer !== undefined)
|
|
153
|
+
for (const d of added)
|
|
154
|
+
outer.push(d);
|
|
155
|
+
const globals = new Set();
|
|
156
|
+
for (const d of added)
|
|
157
|
+
if (d.file === undefined)
|
|
158
|
+
globals.add(d);
|
|
159
|
+
if (globals.size > 0) {
|
|
160
|
+
this.removedGlobals += globals.size;
|
|
161
|
+
let kept = 0;
|
|
162
|
+
for (const d of this.global)
|
|
163
|
+
if (!globals.has(d))
|
|
164
|
+
this.global[kept++] = d;
|
|
165
|
+
this.global.length = kept;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
140
169
|
/** Records the diagnostics added from now on. */
|
|
141
170
|
startLog() {
|
|
142
171
|
this.log = [];
|
|
@@ -780,6 +809,17 @@ export class Checker {
|
|
|
780
809
|
getGlobalDiagnostics() {
|
|
781
810
|
return this.diagnostics.globals();
|
|
782
811
|
}
|
|
812
|
+
/**
|
|
813
|
+
* Runs `run` (such as emitting declarations), then forgets the global diagnostics it reported:
|
|
814
|
+
* the program collects global diagnostics before it emits.
|
|
815
|
+
*/
|
|
816
|
+
withoutGlobalDiagnostics(run) {
|
|
817
|
+
return this.diagnostics.withoutNewGlobals(run);
|
|
818
|
+
}
|
|
819
|
+
/** The global diagnostics `withoutGlobalDiagnostics` forgot so far. */
|
|
820
|
+
forgottenGlobalDiagnostics() {
|
|
821
|
+
return this.diagnostics.removedGlobals;
|
|
822
|
+
}
|
|
783
823
|
// ---- Links
|
|
784
824
|
/** The rarely used links of `symbol`, created on first use. */
|
|
785
825
|
symbolLinks(symbol) {
|
|
@@ -61,6 +61,28 @@ export declare class EmitIndexes {
|
|
|
61
61
|
readonly declarations: DeclarationGlobals | undefined;
|
|
62
62
|
constructor(program: Program);
|
|
63
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* The JavaScript emit of a program's files without a checker, for emit threads (parallel-emit.ts).
|
|
66
|
+
* JavaScript emit asks the checker only how decorator metadata serializes a type
|
|
67
|
+
* (`CheckerEmitResolver`): with `kinds`, the answers the main thread's checker gave
|
|
68
|
+
* (`recordMetadataKinds`), else files with decorator metadata are emitted by a `ProgramEmitter`.
|
|
69
|
+
*/
|
|
70
|
+
export declare class JavaScriptEmitter {
|
|
71
|
+
private readonly host;
|
|
72
|
+
private readonly recorded;
|
|
73
|
+
constructor(program: Program, kinds?: readonly number[]);
|
|
74
|
+
/**
|
|
75
|
+
* Emits `file`, or returns undefined if its decorator metadata asked for a kind that wasn't recorded: what
|
|
76
|
+
* was written is then not the file's emit, and it must be emitted with the checker.
|
|
77
|
+
*/
|
|
78
|
+
emit(file: SourceFile, writer: OutputWriter): EmitResult | undefined;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The serialization kinds of decorator metadata that the checker of `checked` gives the type references of
|
|
82
|
+
* `files`, in the order JavaScript emit asks for them: the type name's node id, the location's node id (-1 for
|
|
83
|
+
* none) and the kind, for each. Only the decorator metadata transform runs, as the first transform of emit.
|
|
84
|
+
*/
|
|
85
|
+
export declare function recordMetadataKinds(checked: CheckedProgram, files: readonly SourceFile[]): number[];
|
|
64
86
|
/** A checked program and the emit of its files. */
|
|
65
87
|
export declare class ProgramEmitter {
|
|
66
88
|
readonly checked: CheckedProgram;
|
|
@@ -110,9 +132,11 @@ export declare class PlainProgram extends CompilerProgram {
|
|
|
110
132
|
export declare function handleNoEmitOnError(program: CompilerProgram): EmitResult | undefined;
|
|
111
133
|
/**
|
|
112
134
|
* Config and syntax errors; without syntax errors, program, global and semantic errors too, and
|
|
113
|
-
* declaration errors under `noEmit` (or `withDeclarationDiagnostics`).
|
|
135
|
+
* declaration errors under `noEmit` (or `withDeclarationDiagnostics`). With `declarationsLater`, the
|
|
136
|
+
* declaration errors are left to `program.emit`, which reports them under `noEmit` (without
|
|
137
|
+
* `noEmitOnError`) whether or not other errors were found.
|
|
114
138
|
*/
|
|
115
|
-
export declare function getDiagnosticsOfProgram(program: CompilerProgram, withDeclarationDiagnostics: boolean): Diagnostic[];
|
|
139
|
+
export declare function getDiagnosticsOfProgram(program: CompilerProgram, withDeclarationDiagnostics: boolean, declarationsLater?: boolean): Diagnostic[];
|
|
116
140
|
/** Combines emit results in order. */
|
|
117
141
|
export declare function combineEmitResults(results: readonly EmitResult[]): EmitResult;
|
|
118
142
|
export { CheckedProgram };
|
|
@@ -6,6 +6,10 @@ import { CheckerDeclarationEmitResolver, CheckerEmitResolver } from './checker-e
|
|
|
6
6
|
import { getEmitModuleFormatOfFile } from './program-utilities.js';
|
|
7
7
|
import { DeclarationGlobals, SyntacticDeclarationEmitResolver } from './transformers/declarations-syntactic.js';
|
|
8
8
|
import { mark } from './timeline.js';
|
|
9
|
+
import { DecoratorMetadata } from './transformers/decorator-metadata.js';
|
|
10
|
+
import { SyntaxFacts } from './transformers/syntax-facts.js';
|
|
11
|
+
import { EmitContext } from './printer/emit-context.js';
|
|
12
|
+
import { SyntacticEmitResolver } from './transformers/emit-resolver.js';
|
|
9
13
|
import { ModuleFormatHost } from './transformers/module.js';
|
|
10
14
|
import { ModuleLookup, ReferenceResolver } from './transformers/reference-resolver.js';
|
|
11
15
|
/** Where emit writes files. */
|
|
@@ -165,6 +169,82 @@ export class EmitIndexes {
|
|
|
165
169
|
: undefined;
|
|
166
170
|
}
|
|
167
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* The JavaScript emit of a program's files without a checker, for emit threads (parallel-emit.ts).
|
|
174
|
+
* JavaScript emit asks the checker only how decorator metadata serializes a type
|
|
175
|
+
* (`CheckerEmitResolver`): with `kinds`, the answers the main thread's checker gave
|
|
176
|
+
* (`recordMetadataKinds`), else files with decorator metadata are emitted by a `ProgramEmitter`.
|
|
177
|
+
*/
|
|
178
|
+
export class JavaScriptEmitter {
|
|
179
|
+
host;
|
|
180
|
+
recorded;
|
|
181
|
+
constructor(program, kinds = []) {
|
|
182
|
+
const options = program.options;
|
|
183
|
+
const indexes = program.emitIndexes;
|
|
184
|
+
const references = new ReferenceResolver(options, program.getSourceFiles(), new ProgramModules(program), indexes !== undefined ? indexes.globals : undefined);
|
|
185
|
+
this.recorded = kinds.length > 0 ? new RecordedKindsEmitResolver(options, references, kinds) : undefined;
|
|
186
|
+
this.host = new ProgramEmitHost(program, this.recorded ?? new SyntacticEmitResolver(options, references));
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Emits `file`, or returns undefined if its decorator metadata asked for a kind that wasn't recorded: what
|
|
190
|
+
* was written is then not the file's emit, and it must be emitted with the checker.
|
|
191
|
+
*/
|
|
192
|
+
emit(file, writer) {
|
|
193
|
+
const host = this.host;
|
|
194
|
+
const recorded = this.recorded;
|
|
195
|
+
if (recorded !== undefined)
|
|
196
|
+
recorded.missed = false;
|
|
197
|
+
host.writer = writer;
|
|
198
|
+
const result = emitFiles(host, [file], 1 /* EmitOnly.Js */);
|
|
199
|
+
host.writer = undefined;
|
|
200
|
+
return recorded !== undefined && recorded.missed ? undefined : result;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* The serialization kinds of decorator metadata that the checker of `checked` gives the type references of
|
|
205
|
+
* `files`, in the order JavaScript emit asks for them: the type name's node id, the location's node id (-1 for
|
|
206
|
+
* none) and the kind, for each. Only the decorator metadata transform runs, as the first transform of emit.
|
|
207
|
+
*/
|
|
208
|
+
export function recordMetadataKinds(checked, files) {
|
|
209
|
+
const program = checked.program;
|
|
210
|
+
const options = program.options;
|
|
211
|
+
const indexes = program.emitIndexes;
|
|
212
|
+
const references = new ReferenceResolver(options, program.getSourceFiles(), new ProgramModules(program), indexes !== undefined ? indexes.globals : undefined);
|
|
213
|
+
const resolver = new RecordingEmitResolver(options, references, checked.checker);
|
|
214
|
+
for (const file of files)
|
|
215
|
+
new DecoratorMetadata(new EmitContext(), options, resolver, new SyntaxFacts()).transformSourceFile(file);
|
|
216
|
+
return resolver.kinds;
|
|
217
|
+
}
|
|
218
|
+
/** A `CheckerEmitResolver` that records the serialization kinds it gives (`recordMetadataKinds`). */
|
|
219
|
+
class RecordingEmitResolver extends CheckerEmitResolver {
|
|
220
|
+
kinds = [];
|
|
221
|
+
getTypeReferenceSerializationKind(typeName, location) {
|
|
222
|
+
const kind = super.getTypeReferenceSerializationKind(typeName, location);
|
|
223
|
+
this.kinds.push(typeName.id, location === undefined ? -1 : location.id, kind);
|
|
224
|
+
return kind;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/** Answers serialization kinds from those recorded on the main thread; `missed` once one wasn't. */
|
|
228
|
+
class RecordedKindsEmitResolver extends SyntacticEmitResolver {
|
|
229
|
+
kinds;
|
|
230
|
+
/** The kind and location of each type name, by the type name's node id. */
|
|
231
|
+
byName = new Map();
|
|
232
|
+
missed = false;
|
|
233
|
+
constructor(options, referenceResolver, kinds) {
|
|
234
|
+
super(options, referenceResolver);
|
|
235
|
+
this.kinds = kinds;
|
|
236
|
+
for (let i = 0; i < kinds.length; i += 3)
|
|
237
|
+
if (!this.byName.has(kinds[i]))
|
|
238
|
+
this.byName.set(kinds[i], i);
|
|
239
|
+
}
|
|
240
|
+
getTypeReferenceSerializationKind(typeName, location) {
|
|
241
|
+
const at = this.byName.get(typeName.id);
|
|
242
|
+
if (at !== undefined && this.kinds[at + 1] === (location === undefined ? -1 : location.id))
|
|
243
|
+
return this.kinds[at + 2];
|
|
244
|
+
this.missed = true;
|
|
245
|
+
return super.getTypeReferenceSerializationKind(typeName, location);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
168
248
|
/** A checked program and the emit of its files. */
|
|
169
249
|
export class ProgramEmitter {
|
|
170
250
|
checked;
|
|
@@ -291,14 +371,24 @@ export class PlainProgram extends CompilerProgram {
|
|
|
291
371
|
const program = this.program;
|
|
292
372
|
const files = program.getSourceFiles();
|
|
293
373
|
const parallel = this.checked.emittedInParallel;
|
|
294
|
-
// Checker threads emitted the files they checked (parallel-check.ts)
|
|
374
|
+
// Checker threads emitted the files they checked (parallel-check.ts), or emit threads their JavaScript
|
|
375
|
+
// (parallel-emit.ts); the rest is emitted here, in order.
|
|
295
376
|
const result = parallel === undefined
|
|
296
377
|
? this.emitter.emit(files, 0 /* EmitOnly.All */, writer)
|
|
297
378
|
: combineEmitResults(files.map((file, i) => {
|
|
298
379
|
const emitted = parallel[i];
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
380
|
+
// The declaration thread emitted the declarations of the files it could (parallel-emit.ts).
|
|
381
|
+
const ahead = this.checked.declarationsEmittedAhead;
|
|
382
|
+
const declarations = () => ahead?.[i] ?? this.emitter.emit([file], 2 /* EmitOnly.Dts */, writer);
|
|
383
|
+
if (emitted === undefined)
|
|
384
|
+
return ahead !== undefined
|
|
385
|
+
? combineEmitResults([this.emitter.emit([file], 1 /* EmitOnly.Js */, writer), declarations()])
|
|
386
|
+
: this.emitter.emit([file], 0 /* EmitOnly.All */, writer);
|
|
387
|
+
const written = writeHeldOutputs(emitted, writer);
|
|
388
|
+
// Emit threads emit JavaScript only.
|
|
389
|
+
if (!this.checked.javaScriptEmittedOnThreads || !getEmitDeclarations(options))
|
|
390
|
+
return written;
|
|
391
|
+
return combineEmitResults([written, declarations()]);
|
|
302
392
|
}));
|
|
303
393
|
if (options.noEmit === true) {
|
|
304
394
|
// Emit is skipped only for files that would have been emitted.
|
|
@@ -326,9 +416,11 @@ export function handleNoEmitOnError(program) {
|
|
|
326
416
|
}
|
|
327
417
|
/**
|
|
328
418
|
* Config and syntax errors; without syntax errors, program, global and semantic errors too, and
|
|
329
|
-
* declaration errors under `noEmit` (or `withDeclarationDiagnostics`).
|
|
419
|
+
* declaration errors under `noEmit` (or `withDeclarationDiagnostics`). With `declarationsLater`, the
|
|
420
|
+
* declaration errors are left to `program.emit`, which reports them under `noEmit` (without
|
|
421
|
+
* `noEmitOnError`) whether or not other errors were found.
|
|
330
422
|
*/
|
|
331
|
-
export function getDiagnosticsOfProgram(program, withDeclarationDiagnostics) {
|
|
423
|
+
export function getDiagnosticsOfProgram(program, withDeclarationDiagnostics, declarationsLater = false) {
|
|
332
424
|
const result = [...program.getConfigFileParsingDiagnostics()];
|
|
333
425
|
const configCount = result.length;
|
|
334
426
|
for (const d of program.getSyntacticDiagnostics())
|
|
@@ -356,7 +448,8 @@ export function getDiagnosticsOfProgram(program, withDeclarationDiagnostics) {
|
|
|
356
448
|
result.push(d);
|
|
357
449
|
mark('semantic diagnostics');
|
|
358
450
|
}
|
|
359
|
-
if (
|
|
451
|
+
if (!declarationsLater &&
|
|
452
|
+
(withDeclarationDiagnostics || options.noEmit === true) &&
|
|
360
453
|
getEmitDeclarations(options) &&
|
|
361
454
|
result.length === configCount) {
|
|
362
455
|
for (const d of program.getDeclarationDiagnostics())
|
|
@@ -109,6 +109,11 @@ export declare class Diagnostic {
|
|
|
109
109
|
readonly reportsDeprecated: boolean;
|
|
110
110
|
skippedOnNoEmit: boolean;
|
|
111
111
|
repopulateInfo: RepopulateInfo | undefined;
|
|
112
|
+
/**
|
|
113
|
+
* What `formatDiagnostic` gives for this diagnostic in `formattedReports.format`, where the checker
|
|
114
|
+
* thread that found it formatted it (`packResult`); `''` otherwise.
|
|
115
|
+
*/
|
|
116
|
+
formatted: string;
|
|
112
117
|
constructor(file: DiagnosticFile | undefined, pos: number, end: number, message: DiagnosticMessage, args?: readonly string[]);
|
|
113
118
|
localize(locale: Locale): string;
|
|
114
119
|
addMessageChain(chain: Diagnostic | undefined): Diagnostic;
|
|
@@ -132,6 +137,14 @@ export declare function chainDiagnostic(chain: Diagnostic | undefined, message:
|
|
|
132
137
|
export declare function compareCodePoints(a: string, b: string): number;
|
|
133
138
|
/** The order tsc reports diagnostics in: by file, position, code, arguments, then elaboration. */
|
|
134
139
|
export declare function compareDiagnostics(a: Diagnostic, b: Diagnostic): number;
|
|
140
|
+
/**
|
|
141
|
+
* `diagnostics` in the order of `compareDiagnostics`, equal ones in their order in `diagnostics`. File
|
|
142
|
+
* names are compared once per pair of files rather than once per pair of diagnostics: the distinct
|
|
143
|
+
* files are sorted by name, and each diagnostic sorts by its file's place in that order, then by the
|
|
144
|
+
* rest of `compareDiagnostics`. A program's diagnostics come a file at a time, so the files are found
|
|
145
|
+
* from the runs of one file.
|
|
146
|
+
*/
|
|
147
|
+
export declare function sortDiagnostics(diagnostics: readonly Diagnostic[]): Diagnostic[];
|
|
135
148
|
/** Whether two diagnostics report the same thing, ignoring related information. */
|
|
136
149
|
export declare function equalDiagnosticsNoRelatedInfo(a: Diagnostic, b: Diagnostic): boolean;
|
|
137
150
|
export declare function equalDiagnostics(a: Diagnostic, b: Diagnostic): boolean;
|
|
@@ -145,6 +158,15 @@ export interface DiagnosticFormatOptions {
|
|
|
145
158
|
export declare function flattenDiagnosticMessage(diagnostic: Diagnostic, newLine: string, locale: Locale): string;
|
|
146
159
|
/** `file(line,col): error TS1005: message`, as tsc prints without `--pretty`. */
|
|
147
160
|
export declare function formatDiagnostic(diagnostic: Diagnostic, options: DiagnosticFormatOptions): string;
|
|
161
|
+
/**
|
|
162
|
+
* The plain format the main thread reports a compilation's diagnostics in (`DiagnosticReporter.plainFormat`),
|
|
163
|
+
* which its checker threads receive a copy of and format the diagnostics they send back in
|
|
164
|
+
* (`Diagnostic.formatted`). Unset where diagnostics are reported with color and context, or not at all.
|
|
165
|
+
*/
|
|
166
|
+
export declare class FormattedReports {
|
|
167
|
+
format: DiagnosticFormatOptions | undefined;
|
|
168
|
+
}
|
|
169
|
+
export declare const formattedReports: FormattedReports;
|
|
148
170
|
/** `formatDiagnostic` of each diagnostic. */
|
|
149
171
|
export declare function formatDiagnostics(diagnostics: readonly Diagnostic[], options: DiagnosticFormatOptions): string;
|
|
150
172
|
/** The colored form with source snippets, as tsc prints with `--pretty`. */
|
|
@@ -326,6 +326,11 @@ export class Diagnostic {
|
|
|
326
326
|
reportsDeprecated;
|
|
327
327
|
skippedOnNoEmit = false;
|
|
328
328
|
repopulateInfo = undefined;
|
|
329
|
+
/**
|
|
330
|
+
* What `formatDiagnostic` gives for this diagnostic in `formattedReports.format`, where the checker
|
|
331
|
+
* thread that found it formatted it (`packResult`); `''` otherwise.
|
|
332
|
+
*/
|
|
333
|
+
formatted = '';
|
|
329
334
|
constructor(file, pos, end, message, args = []) {
|
|
330
335
|
this.file = file;
|
|
331
336
|
this.pos = pos;
|
|
@@ -358,6 +363,7 @@ export class Diagnostic {
|
|
|
358
363
|
result.relatedInformation = this.relatedInformation;
|
|
359
364
|
result.skippedOnNoEmit = this.skippedOnNoEmit;
|
|
360
365
|
result.repopulateInfo = this.repopulateInfo;
|
|
366
|
+
result.formatted = this.formatted;
|
|
361
367
|
return result;
|
|
362
368
|
}
|
|
363
369
|
}
|
|
@@ -463,10 +469,12 @@ function compareRelatedInfo(a, b) {
|
|
|
463
469
|
export function compareDiagnostics(a, b) {
|
|
464
470
|
if (a === b)
|
|
465
471
|
return 0;
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
472
|
+
const c = compareCodePoints(fileNameOf(a), fileNameOf(b));
|
|
473
|
+
return c !== 0 ? c : compareDiagnosticsInFile(a, b);
|
|
474
|
+
}
|
|
475
|
+
/** `compareDiagnostics` of two diagnostics whose files have the same name. */
|
|
476
|
+
function compareDiagnosticsInFile(a, b) {
|
|
477
|
+
let c = a.pos - b.pos;
|
|
470
478
|
if (c !== 0)
|
|
471
479
|
return c;
|
|
472
480
|
c = a.end - b.end;
|
|
@@ -486,6 +494,66 @@ export function compareDiagnostics(a, b) {
|
|
|
486
494
|
return c;
|
|
487
495
|
return compareRelatedInfo(a.relatedInformation, b.relatedInformation);
|
|
488
496
|
}
|
|
497
|
+
/**
|
|
498
|
+
* `diagnostics` in the order of `compareDiagnostics`, equal ones in their order in `diagnostics`. File
|
|
499
|
+
* names are compared once per pair of files rather than once per pair of diagnostics: the distinct
|
|
500
|
+
* files are sorted by name, and each diagnostic sorts by its file's place in that order, then by the
|
|
501
|
+
* rest of `compareDiagnostics`. A program's diagnostics come a file at a time, so the files are found
|
|
502
|
+
* from the runs of one file.
|
|
503
|
+
*/
|
|
504
|
+
export function sortDiagnostics(diagnostics) {
|
|
505
|
+
const n = diagnostics.length;
|
|
506
|
+
if (n < 2)
|
|
507
|
+
return diagnostics.slice();
|
|
508
|
+
const fileIndices = new Map();
|
|
509
|
+
const files = [];
|
|
510
|
+
const fileOf = [];
|
|
511
|
+
let last = undefined;
|
|
512
|
+
let lastIndex = -1;
|
|
513
|
+
for (let i = 0; i < n; i++) {
|
|
514
|
+
const file = diagnostics[i].file;
|
|
515
|
+
if (lastIndex < 0 || file !== last) {
|
|
516
|
+
let k = fileIndices.get(file);
|
|
517
|
+
if (k === undefined) {
|
|
518
|
+
k = files.length;
|
|
519
|
+
fileIndices.set(file, k);
|
|
520
|
+
files.push(file);
|
|
521
|
+
}
|
|
522
|
+
last = file;
|
|
523
|
+
lastIndex = k;
|
|
524
|
+
}
|
|
525
|
+
fileOf.push(lastIndex);
|
|
526
|
+
}
|
|
527
|
+
// Files with the same name share a rank, as they compare equal.
|
|
528
|
+
const nameOf = (k) => {
|
|
529
|
+
const file = files[k];
|
|
530
|
+
return file === undefined ? '' : file.fileName;
|
|
531
|
+
};
|
|
532
|
+
const byName = [];
|
|
533
|
+
for (let k = 0; k < files.length; k++)
|
|
534
|
+
byName.push(k);
|
|
535
|
+
byName.sort((x, y) => compareCodePoints(nameOf(x), nameOf(y)));
|
|
536
|
+
const rank = [];
|
|
537
|
+
for (let k = 0; k < files.length; k++)
|
|
538
|
+
rank.push(0);
|
|
539
|
+
for (let k = 1; k < byName.length; k++)
|
|
540
|
+
rank[byName[k]] = rank[byName[k - 1]] + (nameOf(byName[k]) === nameOf(byName[k - 1]) ? 0 : 1);
|
|
541
|
+
const order = [];
|
|
542
|
+
for (let i = 0; i < n; i++)
|
|
543
|
+
order.push(i);
|
|
544
|
+
order.sort((x, y) => {
|
|
545
|
+
const c = rank[fileOf[x]] - rank[fileOf[y]];
|
|
546
|
+
if (c !== 0)
|
|
547
|
+
return c;
|
|
548
|
+
const a = diagnostics[x];
|
|
549
|
+
const b = diagnostics[y];
|
|
550
|
+
return a === b ? 0 : compareDiagnosticsInFile(a, b);
|
|
551
|
+
});
|
|
552
|
+
const sorted = [];
|
|
553
|
+
for (const i of order)
|
|
554
|
+
sorted.push(diagnostics[i]);
|
|
555
|
+
return sorted;
|
|
556
|
+
}
|
|
489
557
|
function equalChain(a, b) {
|
|
490
558
|
if (a.length !== b.length)
|
|
491
559
|
return false;
|
|
@@ -567,13 +635,27 @@ function formatDiagnosticIn(diagnostic, fileName, options) {
|
|
|
567
635
|
result += `${categoryName(diagnostic.category)} TS${diagnostic.code}: `;
|
|
568
636
|
return result + flattenDiagnosticMessage(diagnostic, options.newLine, options.locale) + options.newLine;
|
|
569
637
|
}
|
|
638
|
+
/**
|
|
639
|
+
* The plain format the main thread reports a compilation's diagnostics in (`DiagnosticReporter.plainFormat`),
|
|
640
|
+
* which its checker threads receive a copy of and format the diagnostics they send back in
|
|
641
|
+
* (`Diagnostic.formatted`). Unset where diagnostics are reported with color and context, or not at all.
|
|
642
|
+
*/
|
|
643
|
+
export class FormattedReports {
|
|
644
|
+
format = undefined;
|
|
645
|
+
}
|
|
646
|
+
export const formattedReports = new FormattedReports();
|
|
570
647
|
/** `formatDiagnostic` of each diagnostic. */
|
|
571
648
|
export function formatDiagnostics(diagnostics, options) {
|
|
572
649
|
let result = '';
|
|
650
|
+
const formatted = options === formattedReports.format;
|
|
573
651
|
// Sorted diagnostics come a file at a time: the relative name of the last file is kept.
|
|
574
652
|
let lastFile = undefined;
|
|
575
653
|
let lastName = '';
|
|
576
654
|
for (const diagnostic of diagnostics) {
|
|
655
|
+
if (formatted && diagnostic.formatted !== '') {
|
|
656
|
+
result += diagnostic.formatted;
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
577
659
|
const file = diagnostic.file;
|
|
578
660
|
if (file !== undefined && file !== lastFile) {
|
|
579
661
|
lastFile = file;
|
|
@@ -147,6 +147,11 @@ export declare class ProcessedFiles {
|
|
|
147
147
|
* threads (`preparedPackageJsonLookups`); `undefined` where they may miss some.
|
|
148
148
|
*/
|
|
149
149
|
readonly preparedPackageJsons: readonly PackageJsonLookup[] | undefined;
|
|
150
|
+
/**
|
|
151
|
+
* The files each file's imports and type reference directives added to the program, by index into
|
|
152
|
+
* `files`, without the file itself.
|
|
153
|
+
*/
|
|
154
|
+
readonly addedFiles: readonly (readonly number[])[];
|
|
150
155
|
constructor(resolver: Resolver,
|
|
151
156
|
/** Libraries first, sorted, then other files in load order. */
|
|
152
157
|
files: readonly SourceFile[], filesByPath: ReadonlyMap<string, SourceFile>, missingFiles: readonly string[], resolvedModules: ReadonlyMap<string, ModeAwareCache<ResolvedModule> | undefined>, typeResolutionsInFile: ReadonlyMap<string, ModeAwareCache<ResolvedTypeReferenceDirective> | undefined>, sourceFileMetadata: ReadonlyMap<string, SourceFileMetadata>, jsxRuntimeImports: ReadonlyMap<string, JsxRuntimeImport>, importHelpersImportSpecifiers: ReadonlyMap<string, StringLiteral>, libFiles: ReadonlyMap<string, LibFile>,
|
|
@@ -158,7 +163,12 @@ export declare class ProcessedFiles {
|
|
|
158
163
|
* The `package.json` lookups made resolving the files whose resolutions were taken from parse
|
|
159
164
|
* threads (`preparedPackageJsonLookups`); `undefined` where they may miss some.
|
|
160
165
|
*/
|
|
161
|
-
preparedPackageJsons: readonly PackageJsonLookup[] | undefined
|
|
166
|
+
preparedPackageJsons: readonly PackageJsonLookup[] | undefined,
|
|
167
|
+
/**
|
|
168
|
+
* The files each file's imports and type reference directives added to the program, by index into
|
|
169
|
+
* `files`, without the file itself.
|
|
170
|
+
*/
|
|
171
|
+
addedFiles: readonly (readonly number[])[]);
|
|
162
172
|
}
|
|
163
173
|
/** The files of `processed` with `file` in place of the file at its path, for `Program.updateFile`. */
|
|
164
174
|
export declare function withReplacedFile(processed: ProcessedFiles, file: SourceFile): ProcessedFiles;
|