tstyche 7.0.0 → 7.2.0
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 +22 -18
- package/dist/api.d.ts +29 -22
- package/dist/api.js +577 -838
- package/dist/index.cjs +0 -1
- package/dist/index.d.cts +2 -23
- package/dist/index.d.ts +2 -23
- package/dist/index.js +1 -1
- package/package.json +7 -3
- package/schemas/config.json +2 -2
package/dist/api.js
CHANGED
|
@@ -77,46 +77,6 @@ class JsonNode {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
class SourceService {
|
|
81
|
-
static #files = new Map();
|
|
82
|
-
static delete(filePath) {
|
|
83
|
-
SourceService.#files.delete(filePath);
|
|
84
|
-
}
|
|
85
|
-
static get(source) {
|
|
86
|
-
const file = SourceService.#files.get(source.fileName);
|
|
87
|
-
if (file != null) {
|
|
88
|
-
return file;
|
|
89
|
-
}
|
|
90
|
-
return source;
|
|
91
|
-
}
|
|
92
|
-
static set(source) {
|
|
93
|
-
SourceService.#files.set(source.fileName, source);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
class DiagnosticOrigin {
|
|
98
|
-
assertionNode;
|
|
99
|
-
end;
|
|
100
|
-
sourceFile;
|
|
101
|
-
start;
|
|
102
|
-
constructor(start, end, sourceFile, assertionNode) {
|
|
103
|
-
this.start = start;
|
|
104
|
-
this.end = end;
|
|
105
|
-
this.sourceFile = SourceService.get(sourceFile);
|
|
106
|
-
this.assertionNode = assertionNode;
|
|
107
|
-
}
|
|
108
|
-
static fromAssertion(assertionNode) {
|
|
109
|
-
const node = assertionNode.matcherNameNode.name;
|
|
110
|
-
return new DiagnosticOrigin(node.getStart(), node.getEnd(), node.getSourceFile(), assertionNode);
|
|
111
|
-
}
|
|
112
|
-
static fromNode(node, assertionNode) {
|
|
113
|
-
return new DiagnosticOrigin(node.getStart(), node.getEnd(), node.getSourceFile(), assertionNode);
|
|
114
|
-
}
|
|
115
|
-
static fromNodes(nodes, assertionNode) {
|
|
116
|
-
return new DiagnosticOrigin(nodes.pos, nodes.end, nodes[0].getSourceFile(), assertionNode);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
80
|
function diagnosticBelongsToNode(diagnostic, node) {
|
|
121
81
|
return diagnostic.start != null && diagnostic.start >= node.pos && diagnostic.start <= node.end;
|
|
122
82
|
}
|
|
@@ -134,6 +94,16 @@ function getDiagnosticMessageText(diagnostic) {
|
|
|
134
94
|
? diagnostic.messageText
|
|
135
95
|
: diagnosticMessageChainToText(diagnostic.messageText);
|
|
136
96
|
}
|
|
97
|
+
function getOffset(position, offsets) {
|
|
98
|
+
let diff = 0;
|
|
99
|
+
for (const offset of offsets) {
|
|
100
|
+
if (offset.position > position - diff) {
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
diff += offset.diff;
|
|
104
|
+
}
|
|
105
|
+
return diff;
|
|
106
|
+
}
|
|
137
107
|
function getTextSpanEnd(span) {
|
|
138
108
|
return span.start + span.length;
|
|
139
109
|
}
|
|
@@ -141,6 +111,29 @@ function isDiagnosticWithLocation(diagnostic) {
|
|
|
141
111
|
return diagnostic.file != null && diagnostic.start != null && diagnostic.length != null;
|
|
142
112
|
}
|
|
143
113
|
|
|
114
|
+
class DiagnosticOrigin {
|
|
115
|
+
assertionNode;
|
|
116
|
+
end;
|
|
117
|
+
sourceFile;
|
|
118
|
+
start;
|
|
119
|
+
constructor(start, end, sourceFile, assertionNode) {
|
|
120
|
+
this.start = start;
|
|
121
|
+
this.end = end;
|
|
122
|
+
this.sourceFile = sourceFile;
|
|
123
|
+
this.assertionNode = assertionNode;
|
|
124
|
+
}
|
|
125
|
+
static fromAbilityDiagnostic(diagnostic, assertionNode) {
|
|
126
|
+
return new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), diagnostic.file, assertionNode);
|
|
127
|
+
}
|
|
128
|
+
static fromAssertion(assertionNode) {
|
|
129
|
+
const node = assertionNode.matcherNameNode.name;
|
|
130
|
+
return new DiagnosticOrigin(node.getStart(), node.getEnd(), node.getSourceFile(), assertionNode);
|
|
131
|
+
}
|
|
132
|
+
static fromNode(node, assertionNode) {
|
|
133
|
+
return new DiagnosticOrigin(node.getStart(), node.getEnd(), node.getSourceFile(), assertionNode);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
144
137
|
class Diagnostic {
|
|
145
138
|
category;
|
|
146
139
|
code;
|
|
@@ -193,6 +186,37 @@ var DiagnosticCategory;
|
|
|
193
186
|
DiagnosticCategory["Warning"] = "warning";
|
|
194
187
|
})(DiagnosticCategory || (DiagnosticCategory = {}));
|
|
195
188
|
|
|
189
|
+
class MappedDiagnostic {
|
|
190
|
+
category;
|
|
191
|
+
code;
|
|
192
|
+
file;
|
|
193
|
+
length;
|
|
194
|
+
messageText;
|
|
195
|
+
relatedInformation;
|
|
196
|
+
start;
|
|
197
|
+
constructor(sourceFile, diagnostic, offsets = []) {
|
|
198
|
+
this.file = sourceFile;
|
|
199
|
+
if (diagnostic.start != null) {
|
|
200
|
+
this.start = diagnostic.start - getOffset(diagnostic.start, offsets);
|
|
201
|
+
}
|
|
202
|
+
this.category = diagnostic.category;
|
|
203
|
+
this.code = diagnostic.code;
|
|
204
|
+
this.length = diagnostic.length;
|
|
205
|
+
this.messageText = diagnostic.messageText;
|
|
206
|
+
if ("relatedInformation" in diagnostic && Array.isArray(diagnostic.relatedInformation)) {
|
|
207
|
+
this.relatedInformation = [];
|
|
208
|
+
for (const related of diagnostic.relatedInformation) {
|
|
209
|
+
if (related.file?.fileName === sourceFile.fileName) {
|
|
210
|
+
this.relatedInformation.push(new MappedDiagnostic(sourceFile, related, offsets));
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
this.relatedInformation.push(related);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
196
220
|
class JsonScanner {
|
|
197
221
|
#end;
|
|
198
222
|
#position;
|
|
@@ -310,15 +334,20 @@ class JsonSourceFile {
|
|
|
310
334
|
const result = [0];
|
|
311
335
|
let position = 0;
|
|
312
336
|
while (position < this.text.length) {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
337
|
+
const character = this.text.charAt(position);
|
|
338
|
+
switch (character) {
|
|
339
|
+
case "\n":
|
|
340
|
+
result.push(position + 1);
|
|
341
|
+
break;
|
|
342
|
+
case "\r":
|
|
343
|
+
if (this.text.charAt(position + 1) === "\n") {
|
|
344
|
+
result.push(position + 2);
|
|
345
|
+
position++;
|
|
346
|
+
}
|
|
347
|
+
break;
|
|
318
348
|
}
|
|
319
349
|
position++;
|
|
320
350
|
}
|
|
321
|
-
result.push(position);
|
|
322
351
|
return result;
|
|
323
352
|
}
|
|
324
353
|
getLineStarts() {
|
|
@@ -420,15 +449,31 @@ class ConfigDiagnosticText {
|
|
|
420
449
|
class Environment {
|
|
421
450
|
static resolve() {
|
|
422
451
|
return {
|
|
452
|
+
fetchRetries: Environment.#resolveFetchRetries(),
|
|
453
|
+
fetchTimeout: Environment.#resolveFetchTimeout(),
|
|
423
454
|
isCi: Environment.#resolveIsCi(),
|
|
424
455
|
noColor: Environment.#resolveNoColor(),
|
|
425
456
|
noInteractive: Environment.#resolveNoInteractive(),
|
|
426
457
|
npmRegistry: Environment.#resolveNpmRegistry(),
|
|
427
458
|
storePath: Environment.#resolveStorePath(),
|
|
428
|
-
timeout: Environment.#resolveTimeout(),
|
|
429
459
|
typescriptModule: Environment.#resolveTypeScriptModule(),
|
|
430
460
|
};
|
|
431
461
|
}
|
|
462
|
+
static #resolveFetchRetries() {
|
|
463
|
+
if (process.env["TSTYCHE_FETCH_RETRIES"] != null) {
|
|
464
|
+
return Number(process.env["TSTYCHE_FETCH_RETRIES"]);
|
|
465
|
+
}
|
|
466
|
+
return 2;
|
|
467
|
+
}
|
|
468
|
+
static #resolveFetchTimeout() {
|
|
469
|
+
if (process.env["TSTYCHE_FETCH_TIMEOUT"] != null) {
|
|
470
|
+
return Number.parseFloat(process.env["TSTYCHE_FETCH_TIMEOUT"]);
|
|
471
|
+
}
|
|
472
|
+
if (process.env["TSTYCHE_TIMEOUT"] != null) {
|
|
473
|
+
return Number.parseFloat(process.env["TSTYCHE_TIMEOUT"]);
|
|
474
|
+
}
|
|
475
|
+
return 30;
|
|
476
|
+
}
|
|
432
477
|
static #resolveIsCi() {
|
|
433
478
|
if (process.env["CI"] != null) {
|
|
434
479
|
return process.env["CI"] !== "";
|
|
@@ -471,12 +516,6 @@ class Environment {
|
|
|
471
516
|
}
|
|
472
517
|
return Path.resolve(os.homedir(), ".local", "share", "TSTyche");
|
|
473
518
|
}
|
|
474
|
-
static #resolveTimeout() {
|
|
475
|
-
if (process.env["TSTYCHE_TIMEOUT"] != null) {
|
|
476
|
-
return Number.parseFloat(process.env["TSTYCHE_TIMEOUT"]);
|
|
477
|
-
}
|
|
478
|
-
return 30;
|
|
479
|
-
}
|
|
480
519
|
static #resolveTypeScriptModule() {
|
|
481
520
|
let specifier = "typescript";
|
|
482
521
|
if (process.env["TSTYCHE_TYPESCRIPT_MODULE"] != null) {
|
|
@@ -525,6 +564,10 @@ class Version {
|
|
|
525
564
|
}
|
|
526
565
|
}
|
|
527
566
|
|
|
567
|
+
function sleep(delay) {
|
|
568
|
+
return new Promise((resolve) => setTimeout(resolve, delay));
|
|
569
|
+
}
|
|
570
|
+
|
|
528
571
|
class StoreDiagnosticText {
|
|
529
572
|
static cannotAddTypeScriptPackage(tag) {
|
|
530
573
|
return `Cannot add the 'typescript' package for the '${tag}' tag.`;
|
|
@@ -538,13 +581,13 @@ class StoreDiagnosticText {
|
|
|
538
581
|
static failedToUpdateMetadata(registry) {
|
|
539
582
|
return `Failed to update metadata of the 'typescript' package from '${registry}'.`;
|
|
540
583
|
}
|
|
541
|
-
static maybeNetworkConnectionIssue() {
|
|
542
|
-
return "Might be there is an issue with the registry or the network connection.";
|
|
543
|
-
}
|
|
544
584
|
static maybeOutdatedResolution(tag) {
|
|
545
585
|
return `The resolution of the '${tag}' tag may be outdated.`;
|
|
546
586
|
}
|
|
547
|
-
static
|
|
587
|
+
static networkFailure(retries) {
|
|
588
|
+
return `The network connection failed after ${retries + 1} attempts.`;
|
|
589
|
+
}
|
|
590
|
+
static requestFailed(code) {
|
|
548
591
|
return `The request failed with status code ${code}.`;
|
|
549
592
|
}
|
|
550
593
|
static requestTimeoutWasExceeded(timeout) {
|
|
@@ -557,29 +600,48 @@ class StoreDiagnosticText {
|
|
|
557
600
|
|
|
558
601
|
class Fetcher {
|
|
559
602
|
#onDiagnostics;
|
|
603
|
+
#retries;
|
|
560
604
|
#timeout;
|
|
561
|
-
constructor(onDiagnostics, timeout) {
|
|
605
|
+
constructor(onDiagnostics, retries, timeout) {
|
|
562
606
|
this.#onDiagnostics = onDiagnostics;
|
|
607
|
+
this.#retries = retries;
|
|
563
608
|
this.#timeout = timeout;
|
|
564
609
|
}
|
|
565
610
|
async get(request, diagnostic, options) {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
611
|
+
let delay = 3000;
|
|
612
|
+
request.headers.set("User-Agent", `tstyche/${"7.2.0"} ${process.platform} ${process.arch}`);
|
|
613
|
+
for (let attempt = 0; attempt <= this.#retries; attempt++) {
|
|
614
|
+
const isLastAttempt = attempt === this.#retries;
|
|
615
|
+
const suppressErrors = options?.suppressErrors || !isLastAttempt;
|
|
616
|
+
try {
|
|
617
|
+
const response = await fetch(request, { signal: AbortSignal.timeout(this.#timeout) });
|
|
618
|
+
if (response.ok) {
|
|
619
|
+
return response;
|
|
620
|
+
}
|
|
621
|
+
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
|
|
622
|
+
if (options?.suppressErrors) {
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
this.#onDiagnostics(diagnostic().extendWith(StoreDiagnosticText.requestFailed(response.status)));
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
if (!suppressErrors) {
|
|
629
|
+
this.#onDiagnostics(diagnostic().extendWith(StoreDiagnosticText.requestFailed(response.status)));
|
|
630
|
+
}
|
|
572
631
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
632
|
+
catch (error) {
|
|
633
|
+
if (!suppressErrors) {
|
|
634
|
+
if (error instanceof Error && error.name === "TimeoutError") {
|
|
635
|
+
this.#onDiagnostics(diagnostic().extendWith(StoreDiagnosticText.requestTimeoutWasExceeded(this.#timeout)));
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
this.#onDiagnostics(diagnostic().extendWith(StoreDiagnosticText.networkFailure(this.#retries)));
|
|
639
|
+
}
|
|
640
|
+
}
|
|
579
641
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
642
|
+
if (!isLastAttempt) {
|
|
643
|
+
await sleep(delay);
|
|
644
|
+
delay *= 2;
|
|
583
645
|
}
|
|
584
646
|
}
|
|
585
647
|
return;
|
|
@@ -623,17 +685,14 @@ class LockService {
|
|
|
623
685
|
const waitStartTime = Date.now();
|
|
624
686
|
while (isLocked) {
|
|
625
687
|
if (Date.now() - waitStartTime > this.#timeout) {
|
|
626
|
-
this.#onDiagnostics(diagnostic.extendWith(StoreDiagnosticText.lockWaitTimeoutWasExceeded(this.#timeout)));
|
|
688
|
+
this.#onDiagnostics(diagnostic().extendWith(StoreDiagnosticText.lockWaitTimeoutWasExceeded(this.#timeout)));
|
|
627
689
|
break;
|
|
628
690
|
}
|
|
629
|
-
await
|
|
691
|
+
await sleep(1000);
|
|
630
692
|
isLocked = existsSync(lockFilePath);
|
|
631
693
|
}
|
|
632
694
|
return isLocked;
|
|
633
695
|
}
|
|
634
|
-
#sleep(delay) {
|
|
635
|
-
return new Promise((resolve) => setTimeout(resolve, delay));
|
|
636
|
-
}
|
|
637
696
|
}
|
|
638
697
|
|
|
639
698
|
class Manifest {
|
|
@@ -714,7 +773,7 @@ class ManifestService {
|
|
|
714
773
|
return manifest;
|
|
715
774
|
}
|
|
716
775
|
async #load(options) {
|
|
717
|
-
const diagnostic = Diagnostic.error(StoreDiagnosticText.failedToFetchMetadata(this.#npmRegistry));
|
|
776
|
+
const diagnostic = () => Diagnostic.error(StoreDiagnosticText.failedToFetchMetadata(this.#npmRegistry));
|
|
718
777
|
const request = new Request(new URL("typescript", this.#npmRegistry), {
|
|
719
778
|
headers: {
|
|
720
779
|
["Accept"]: "application/vnd.npm.install-v1+json;q=1.0, application/json;q=0.8, */*",
|
|
@@ -776,9 +835,7 @@ class ManifestService {
|
|
|
776
835
|
return manifest;
|
|
777
836
|
}
|
|
778
837
|
async #persist(manifest) {
|
|
779
|
-
|
|
780
|
-
await fs.mkdir(this.#storePath, { recursive: true });
|
|
781
|
-
}
|
|
838
|
+
await fs.mkdir(this.#storePath, { recursive: true });
|
|
782
839
|
await fs.writeFile(this.#manifestFilePath, manifest.stringify());
|
|
783
840
|
}
|
|
784
841
|
async prune() {
|
|
@@ -851,29 +908,9 @@ class PackageService {
|
|
|
851
908
|
this.#fetcher = fetcher;
|
|
852
909
|
this.#lockService = lockService;
|
|
853
910
|
}
|
|
854
|
-
async #add(packagePath, resource, diagnostic) {
|
|
855
|
-
const request = new Request(resource.tarball, { integrity: resource.integrity });
|
|
856
|
-
const response = await this.#fetcher.get(request, diagnostic);
|
|
857
|
-
if (response?.body != null) {
|
|
858
|
-
const targetPath = `${packagePath}-${Math.random().toString(32).slice(2)}`;
|
|
859
|
-
const stream = response.body.pipeThrough(new DecompressionStream("gzip"));
|
|
860
|
-
const tarReader = new TarReader(stream);
|
|
861
|
-
for await (const file of tarReader.extract()) {
|
|
862
|
-
const filePath = Path.join(targetPath, file.name.replace(/^package\//, ""));
|
|
863
|
-
const directoryPath = Path.dirname(filePath);
|
|
864
|
-
if (!existsSync(directoryPath)) {
|
|
865
|
-
await fs.mkdir(directoryPath, { recursive: true });
|
|
866
|
-
}
|
|
867
|
-
await fs.writeFile(filePath, file.content);
|
|
868
|
-
}
|
|
869
|
-
await fs.rename(targetPath, packagePath);
|
|
870
|
-
return packagePath;
|
|
871
|
-
}
|
|
872
|
-
return;
|
|
873
|
-
}
|
|
874
911
|
async ensure(packageVersion, manifest) {
|
|
875
|
-
|
|
876
|
-
const diagnostic = Diagnostic.error(StoreDiagnosticText.failedToFetchPackage(packageVersion));
|
|
912
|
+
const packagePath = Path.join(this.#storePath, `typescript@${packageVersion}`);
|
|
913
|
+
const diagnostic = () => Diagnostic.error(StoreDiagnosticText.failedToFetchPackage(packageVersion));
|
|
877
914
|
if (await this.#lockService.isLocked(packagePath, diagnostic)) {
|
|
878
915
|
return;
|
|
879
916
|
}
|
|
@@ -881,18 +918,29 @@ class PackageService {
|
|
|
881
918
|
return packagePath;
|
|
882
919
|
}
|
|
883
920
|
EventEmitter.dispatch(["store:adds", { packagePath, packageVersion }]);
|
|
884
|
-
const resource = manifest
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
921
|
+
const resource = manifest.packages[packageVersion];
|
|
922
|
+
const lock = this.#lockService.getLock(packagePath);
|
|
923
|
+
try {
|
|
924
|
+
const request = new Request(resource.tarball, { integrity: resource.integrity });
|
|
925
|
+
const response = await this.#fetcher.get(request, diagnostic);
|
|
926
|
+
if (!response?.body) {
|
|
927
|
+
return;
|
|
889
928
|
}
|
|
890
|
-
|
|
891
|
-
|
|
929
|
+
const targetPath = await fs.mkdtemp(`${packagePath}-`);
|
|
930
|
+
const stream = response.body.pipeThrough(new DecompressionStream("gzip"));
|
|
931
|
+
const tarReader = new TarReader(stream);
|
|
932
|
+
for await (const file of tarReader.extract()) {
|
|
933
|
+
const filePath = Path.join(targetPath, file.name.replace(/^package\//, ""));
|
|
934
|
+
const directoryPath = Path.dirname(filePath);
|
|
935
|
+
await fs.mkdir(directoryPath, { recursive: true });
|
|
936
|
+
await fs.writeFile(filePath, file.content);
|
|
892
937
|
}
|
|
938
|
+
await fs.rename(targetPath, packagePath);
|
|
893
939
|
return packagePath;
|
|
894
940
|
}
|
|
895
|
-
|
|
941
|
+
finally {
|
|
942
|
+
lock.release();
|
|
943
|
+
}
|
|
896
944
|
}
|
|
897
945
|
}
|
|
898
946
|
|
|
@@ -903,26 +951,30 @@ class Store {
|
|
|
903
951
|
static #manifestService;
|
|
904
952
|
static #packageService;
|
|
905
953
|
static #npmRegistry = environmentOptions.npmRegistry;
|
|
954
|
+
static #fetchRetries = environmentOptions.fetchRetries;
|
|
955
|
+
static #fetchTimeout = environmentOptions.fetchTimeout * 1000;
|
|
906
956
|
static #storePath = environmentOptions.storePath;
|
|
907
957
|
static #supportedTags;
|
|
908
|
-
static #timeout = environmentOptions.timeout * 1000;
|
|
909
958
|
static {
|
|
910
|
-
Store.#fetcher = new Fetcher(Store.#onDiagnostics, Store.#
|
|
911
|
-
Store.#lockService = new LockService(Store.#onDiagnostics, Store.#
|
|
959
|
+
Store.#fetcher = new Fetcher(Store.#onDiagnostics, Store.#fetchRetries, Store.#fetchTimeout);
|
|
960
|
+
Store.#lockService = new LockService(Store.#onDiagnostics, Store.#fetchTimeout);
|
|
912
961
|
Store.#packageService = new PackageService(Store.#storePath, Store.#fetcher, Store.#lockService);
|
|
913
962
|
Store.#manifestService = new ManifestService(Store.#storePath, Store.#npmRegistry, Store.#fetcher);
|
|
914
963
|
}
|
|
915
|
-
static async
|
|
916
|
-
if (tag === "*" && environmentOptions.typescriptModule != null) {
|
|
917
|
-
return;
|
|
918
|
-
}
|
|
964
|
+
static async #ensure(tag) {
|
|
919
965
|
await Store.open();
|
|
920
966
|
const version = Store.manifest?.resolve(tag);
|
|
921
967
|
if (!version) {
|
|
922
968
|
Store.#onDiagnostics(Diagnostic.error(StoreDiagnosticText.cannotAddTypeScriptPackage(tag)));
|
|
923
969
|
return;
|
|
924
970
|
}
|
|
925
|
-
await Store.#packageService.ensure(version, Store.manifest);
|
|
971
|
+
return await Store.#packageService.ensure(version, Store.manifest);
|
|
972
|
+
}
|
|
973
|
+
static async fetch(tag) {
|
|
974
|
+
if (tag === "*" && environmentOptions.typescriptModule != null) {
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
await Store.#ensure(tag);
|
|
926
978
|
}
|
|
927
979
|
static async load(tag) {
|
|
928
980
|
let resolvedModule;
|
|
@@ -930,13 +982,7 @@ class Store {
|
|
|
930
982
|
resolvedModule = environmentOptions.typescriptModule;
|
|
931
983
|
}
|
|
932
984
|
else {
|
|
933
|
-
await Store
|
|
934
|
-
const version = Store.manifest?.resolve(tag);
|
|
935
|
-
if (!version) {
|
|
936
|
-
Store.#onDiagnostics(Diagnostic.error(StoreDiagnosticText.cannotAddTypeScriptPackage(tag)));
|
|
937
|
-
return;
|
|
938
|
-
}
|
|
939
|
-
const packagePath = await Store.#packageService.ensure(version, Store.manifest);
|
|
985
|
+
const packagePath = await Store.#ensure(tag);
|
|
940
986
|
if (packagePath != null) {
|
|
941
987
|
resolvedModule = pathToFileURL(`${packagePath}/lib/typescript.js`).toString();
|
|
942
988
|
}
|
|
@@ -950,7 +996,9 @@ class Store {
|
|
|
950
996
|
EventEmitter.dispatch(["store:error", { diagnostics: [diagnostic] }]);
|
|
951
997
|
}
|
|
952
998
|
static async open() {
|
|
953
|
-
Store.
|
|
999
|
+
if (Store.manifest != null) {
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
954
1002
|
Store.manifest = await Store.#manifestService.open();
|
|
955
1003
|
if (Store.manifest != null) {
|
|
956
1004
|
Store.#supportedTags = [...Object.keys(Store.manifest.resolutions), ...Store.manifest.versions];
|
|
@@ -1040,7 +1088,7 @@ class Options {
|
|
|
1040
1088
|
},
|
|
1041
1089
|
{
|
|
1042
1090
|
brand: "boolean",
|
|
1043
|
-
description: "Check errors
|
|
1091
|
+
description: "Check errors suppressed by '@ts-expect-error' directives.",
|
|
1044
1092
|
group: 4,
|
|
1045
1093
|
name: "checkSuppressedErrors",
|
|
1046
1094
|
},
|
|
@@ -1092,13 +1140,13 @@ class Options {
|
|
|
1092
1140
|
},
|
|
1093
1141
|
{
|
|
1094
1142
|
brand: "string",
|
|
1095
|
-
description: "Only run tests with matching name.",
|
|
1143
|
+
description: "Only run tests with a matching name.",
|
|
1096
1144
|
group: 2,
|
|
1097
1145
|
name: "only",
|
|
1098
1146
|
},
|
|
1099
1147
|
{
|
|
1100
1148
|
brand: "true",
|
|
1101
|
-
description: "Remove all
|
|
1149
|
+
description: "Remove all fetched versions of the 'typescript' package and exit.",
|
|
1102
1150
|
group: 2,
|
|
1103
1151
|
name: "prune",
|
|
1104
1152
|
},
|
|
@@ -1132,7 +1180,7 @@ class Options {
|
|
|
1132
1180
|
},
|
|
1133
1181
|
{
|
|
1134
1182
|
brand: "string",
|
|
1135
|
-
description: "The path to
|
|
1183
|
+
description: "The path to the root directory of a test project.",
|
|
1136
1184
|
group: 2,
|
|
1137
1185
|
name: "root",
|
|
1138
1186
|
},
|
|
@@ -1144,13 +1192,13 @@ class Options {
|
|
|
1144
1192
|
},
|
|
1145
1193
|
{
|
|
1146
1194
|
brand: "string",
|
|
1147
|
-
description: "Skip tests with matching name.",
|
|
1195
|
+
description: "Skip tests with a matching name.",
|
|
1148
1196
|
group: 2,
|
|
1149
1197
|
name: "skip",
|
|
1150
1198
|
},
|
|
1151
1199
|
{
|
|
1152
1200
|
brand: "range",
|
|
1153
|
-
description: "The range of
|
|
1201
|
+
description: "The TypeScript version or range of versions to test against.",
|
|
1154
1202
|
group: 2 | 4 | 8,
|
|
1155
1203
|
name: "target",
|
|
1156
1204
|
},
|
|
@@ -2270,8 +2318,8 @@ function CodeFrameText({ diagnosticCategory, diagnosticOrigin, options }) {
|
|
|
2270
2318
|
const linesBelow = options?.linesBelow ?? 3;
|
|
2271
2319
|
const showBreadcrumbs = options?.showBreadcrumbs ?? true;
|
|
2272
2320
|
const lineMap = diagnosticOrigin.sourceFile.getLineStarts();
|
|
2273
|
-
const { character:
|
|
2274
|
-
const { character:
|
|
2321
|
+
const { character: firstMarkedCharacter, line: firstMarkedLine } = diagnosticOrigin.sourceFile.getLineAndCharacterOfPosition(diagnosticOrigin.start);
|
|
2322
|
+
const { character: lastMarkedCharacter, line: lastMarkedLine } = diagnosticOrigin.sourceFile.getLineAndCharacterOfPosition(diagnosticOrigin.end);
|
|
2275
2323
|
const firstLine = Math.max(firstMarkedLine - linesAbove, 0);
|
|
2276
2324
|
const lastLine = Math.min(lastMarkedLine + linesBelow, lineMap.length - 1);
|
|
2277
2325
|
const gutterWidth = (lastLine + 1).toString().length + 2;
|
|
@@ -2293,12 +2341,12 @@ function CodeFrameText({ diagnosticCategory, diagnosticOrigin, options }) {
|
|
|
2293
2341
|
codeFrame.push(jsx(CodeLineText, { gutterWidth: gutterWidth, lineNumber: index + 1, lineNumberColor: highlightColor, lineText: lineText }));
|
|
2294
2342
|
if (index === firstMarkedLine) {
|
|
2295
2343
|
const squiggleLength = index === lastMarkedLine
|
|
2296
|
-
?
|
|
2297
|
-
: lineText.length -
|
|
2298
|
-
codeFrame.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, indentWidth:
|
|
2344
|
+
? lastMarkedCharacter - firstMarkedCharacter
|
|
2345
|
+
: lineText.length - firstMarkedCharacter;
|
|
2346
|
+
codeFrame.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, indentWidth: firstMarkedCharacter, squiggleColor: highlightColor, squiggleWidth: squiggleLength }));
|
|
2299
2347
|
}
|
|
2300
2348
|
else if (index === lastMarkedLine) {
|
|
2301
|
-
codeFrame.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, squiggleColor: highlightColor, squiggleWidth:
|
|
2349
|
+
codeFrame.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, squiggleColor: highlightColor, squiggleWidth: lastMarkedCharacter }));
|
|
2302
2350
|
}
|
|
2303
2351
|
else {
|
|
2304
2352
|
codeFrame.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, squiggleColor: highlightColor, squiggleWidth: lineText.length }));
|
|
@@ -2312,7 +2360,7 @@ function CodeFrameText({ diagnosticCategory, diagnosticOrigin, options }) {
|
|
|
2312
2360
|
if (showBreadcrumbs && diagnosticOrigin.assertionNode != null) {
|
|
2313
2361
|
breadcrumbs = jsx(BreadcrumbsText, { ancestor: diagnosticOrigin.assertionNode.parent });
|
|
2314
2362
|
}
|
|
2315
|
-
const location = (jsx(Line, { children: [" ".repeat(gutterWidth + 2), jsx(Text, { color: "90", children: " at " }), jsx(Text, { color: "36", children: Path.relative("", diagnosticOrigin.sourceFile.fileName) }), jsx(Text, { color: "90", children: `:${firstMarkedLine + 1}:${
|
|
2363
|
+
const location = (jsx(Line, { children: [" ".repeat(gutterWidth + 2), jsx(Text, { color: "90", children: " at " }), jsx(Text, { color: "36", children: Path.relative("", diagnosticOrigin.sourceFile.fileName) }), jsx(Text, { color: "90", children: `:${firstMarkedLine + 1}:${firstMarkedCharacter + 1}` }), breadcrumbs] }));
|
|
2316
2364
|
return (jsx(Text, { children: [codeFrame, jsx(Line, {}), location] }));
|
|
2317
2365
|
}
|
|
2318
2366
|
|
|
@@ -3175,7 +3223,7 @@ class Select {
|
|
|
3175
3223
|
if (testFilePaths.length === 0) {
|
|
3176
3224
|
Select.#onDiagnostics(Diagnostic.error(SelectDiagnosticText.noTestFilesWereSelected(resolvedConfig)));
|
|
3177
3225
|
}
|
|
3178
|
-
return testFilePaths.sort();
|
|
3226
|
+
return testFilePaths.sort((a, b) => a.localeCompare(b));
|
|
3179
3227
|
}
|
|
3180
3228
|
static async #visitDirectory(currentPath, testFilePaths, matchPatterns, resolvedConfig) {
|
|
3181
3229
|
const targetPath = Path.join(resolvedConfig.rootPath, currentPath);
|
|
@@ -3305,7 +3353,7 @@ class WatchService {
|
|
|
3305
3353
|
while (!cancellationToken.isCancellationRequested()) {
|
|
3306
3354
|
const testFiles = await debounce.schedule();
|
|
3307
3355
|
if (testFiles.length > 0) {
|
|
3308
|
-
yield testFiles;
|
|
3356
|
+
yield testFiles.sort((a, b) => a.path.localeCompare(b.path));
|
|
3309
3357
|
}
|
|
3310
3358
|
}
|
|
3311
3359
|
}
|
|
@@ -3350,18 +3398,10 @@ class AbilityLayer {
|
|
|
3350
3398
|
this.#editor = editor;
|
|
3351
3399
|
}
|
|
3352
3400
|
#belongsToNode(node, diagnostic) {
|
|
3353
|
-
|
|
3354
|
-
case "expect":
|
|
3355
|
-
return (diagnosticBelongsToNode(diagnostic, node.matcherNode) ||
|
|
3356
|
-
diagnosticBelongsToNode(diagnostic, node.source));
|
|
3357
|
-
case "when":
|
|
3358
|
-
return (diagnosticBelongsToNode(diagnostic, node.actionNode) &&
|
|
3359
|
-
!diagnosticBelongsToNode(diagnostic, node.target));
|
|
3360
|
-
}
|
|
3361
|
-
return false;
|
|
3401
|
+
return diagnosticBelongsToNode(diagnostic, node.matcherNode) || diagnosticBelongsToNode(diagnostic, node.source);
|
|
3362
3402
|
}
|
|
3363
3403
|
close(diagnostics) {
|
|
3364
|
-
if (diagnostics
|
|
3404
|
+
if (diagnostics.length > 0 && this.#nodes.length > 0) {
|
|
3365
3405
|
this.#nodes.reverse();
|
|
3366
3406
|
for (const diagnostic of diagnostics) {
|
|
3367
3407
|
this.#mapToNodes(diagnostic);
|
|
@@ -3384,12 +3424,56 @@ class AbilityLayer {
|
|
|
3384
3424
|
const matcherNameEnd = expect.matcherNameNode.getEnd();
|
|
3385
3425
|
const matcherNodeEnd = expect.matcherNode.getEnd();
|
|
3386
3426
|
switch (expect.matcherNameNode.name.text) {
|
|
3427
|
+
case "toAcceptProps": {
|
|
3428
|
+
this.#nodes.push(expect);
|
|
3429
|
+
const sourceNode = expect.source[0];
|
|
3430
|
+
const targetNode = expect.target?.[0];
|
|
3431
|
+
if (!sourceNode ||
|
|
3432
|
+
!targetNode ||
|
|
3433
|
+
!this.#compiler.isObjectLiteralExpression(targetNode) ||
|
|
3434
|
+
!targetNode.properties.every((property) => (this.#compiler.isPropertyAssignment(property) &&
|
|
3435
|
+
(this.#compiler.isIdentifier(property.name) || this.#compiler.isStringLiteral(property.name))) ||
|
|
3436
|
+
this.#compiler.isSpreadAssignment(property))) {
|
|
3437
|
+
return;
|
|
3438
|
+
}
|
|
3439
|
+
const sourceText = sourceNode.getText();
|
|
3440
|
+
if (nodeBelongsToArgumentList(this.#compiler, sourceNode)) {
|
|
3441
|
+
this.#editor
|
|
3442
|
+
.eraseTrailingComma(expect.source)
|
|
3443
|
+
.erase(expectStart, matcherNodeEnd)
|
|
3444
|
+
.update(expectStart, matcherNameEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? ";" : "")
|
|
3445
|
+
.update(sourceNode.getStart() - 1, sourceNode.getEnd(), `<${sourceText}`);
|
|
3446
|
+
}
|
|
3447
|
+
else {
|
|
3448
|
+
const id = ["SC", expectStart, Date.now().toString(36)].join("_");
|
|
3449
|
+
this.#editor
|
|
3450
|
+
.erase(expectStart, matcherNodeEnd)
|
|
3451
|
+
.update(expectStart, matcherNameEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode)
|
|
3452
|
+
? `;const ${id} = undefined as any as ${sourceText};<${id}`
|
|
3453
|
+
: `const ${id} = undefined as any as ${sourceText};<${id}`);
|
|
3454
|
+
}
|
|
3455
|
+
for (const property of targetNode.properties) {
|
|
3456
|
+
if (this.#compiler.isPropertyAssignment(property)) {
|
|
3457
|
+
this.#editor
|
|
3458
|
+
.update(property.name.getStart(), property.name.getEnd() + 1, this.#compiler.isStringLiteral(property.name)
|
|
3459
|
+
? ` ${property.name.getText().slice(1, -1)} =`
|
|
3460
|
+
: property.name.getText() + "=")
|
|
3461
|
+
.update(property.initializer.getStart(), property.initializer.getStart(), "{")
|
|
3462
|
+
.update(property.initializer.getStart(), property.initializer.getEnd(), property.initializer.getText() + "}");
|
|
3463
|
+
continue;
|
|
3464
|
+
}
|
|
3465
|
+
if (this.#compiler.isSpreadAssignment(property)) {
|
|
3466
|
+
this.#editor
|
|
3467
|
+
.update(property.getStart(), property.getStart(), "{")
|
|
3468
|
+
.update(property.getStart(), property.getEnd(), property.getText() + "}");
|
|
3469
|
+
}
|
|
3470
|
+
}
|
|
3471
|
+
this.#editor.update(matcherNodeEnd, matcherNodeEnd, "/>");
|
|
3472
|
+
break;
|
|
3473
|
+
}
|
|
3387
3474
|
case "toBeApplicable":
|
|
3388
3475
|
this.#nodes.push(expect);
|
|
3389
|
-
this.#editor.
|
|
3390
|
-
[expectStart, expectExpressionEnd],
|
|
3391
|
-
[expectEnd, matcherNameEnd],
|
|
3392
|
-
]);
|
|
3476
|
+
this.#editor.erase(expectStart, expectExpressionEnd).erase(expectEnd, matcherNameEnd);
|
|
3393
3477
|
break;
|
|
3394
3478
|
case "toBeCallableWith": {
|
|
3395
3479
|
this.#nodes.push(expect);
|
|
@@ -3398,27 +3482,16 @@ class AbilityLayer {
|
|
|
3398
3482
|
return;
|
|
3399
3483
|
}
|
|
3400
3484
|
if (nodeBelongsToArgumentList(this.#compiler, sourceNode)) {
|
|
3401
|
-
this.#editor
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
expectExpressionEnd,
|
|
3406
|
-
nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? ";" : "",
|
|
3407
|
-
],
|
|
3408
|
-
[expectEnd, matcherNameEnd],
|
|
3409
|
-
]);
|
|
3485
|
+
this.#editor
|
|
3486
|
+
.eraseTrailingComma(expect.source)
|
|
3487
|
+
.update(expectStart, expectExpressionEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? ";" : "")
|
|
3488
|
+
.erase(expectEnd, matcherNameEnd);
|
|
3410
3489
|
}
|
|
3411
3490
|
else {
|
|
3412
3491
|
const sourceText = sourceNode.getFullText();
|
|
3413
|
-
this.#editor.
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
matcherNameEnd,
|
|
3417
|
-
nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode)
|
|
3418
|
-
? `;(undefined as any as ${sourceText})`
|
|
3419
|
-
: `(undefined as any as ${sourceText})`,
|
|
3420
|
-
],
|
|
3421
|
-
]);
|
|
3492
|
+
this.#editor.update(expectStart, matcherNameEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode)
|
|
3493
|
+
? `;(undefined as any as ${sourceText})`
|
|
3494
|
+
: `(undefined as any as ${sourceText})`);
|
|
3422
3495
|
}
|
|
3423
3496
|
break;
|
|
3424
3497
|
}
|
|
@@ -3429,27 +3502,16 @@ class AbilityLayer {
|
|
|
3429
3502
|
return;
|
|
3430
3503
|
}
|
|
3431
3504
|
if (nodeBelongsToArgumentList(this.#compiler, sourceNode)) {
|
|
3432
|
-
this.#editor
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
expectExpressionEnd,
|
|
3437
|
-
nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? "; new" : "new",
|
|
3438
|
-
],
|
|
3439
|
-
[expectEnd, matcherNameEnd],
|
|
3440
|
-
]);
|
|
3505
|
+
this.#editor
|
|
3506
|
+
.eraseTrailingComma(expect.source)
|
|
3507
|
+
.update(expectStart, expectExpressionEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? "; new" : "new")
|
|
3508
|
+
.erase(expectEnd, matcherNameEnd);
|
|
3441
3509
|
}
|
|
3442
3510
|
else {
|
|
3443
3511
|
const sourceText = sourceNode.getFullText();
|
|
3444
|
-
this.#editor.
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
matcherNameEnd,
|
|
3448
|
-
nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode)
|
|
3449
|
-
? `;new (undefined as any as ${sourceText})`
|
|
3450
|
-
: `new (undefined as any as ${sourceText})`,
|
|
3451
|
-
],
|
|
3452
|
-
]);
|
|
3512
|
+
this.#editor.update(expectStart, matcherNameEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode)
|
|
3513
|
+
? `;new (undefined as any as ${sourceText})`
|
|
3514
|
+
: `new (undefined as any as ${sourceText})`);
|
|
3453
3515
|
}
|
|
3454
3516
|
break;
|
|
3455
3517
|
}
|
|
@@ -3461,39 +3523,26 @@ class AbilityLayer {
|
|
|
3461
3523
|
return;
|
|
3462
3524
|
}
|
|
3463
3525
|
if (nodeBelongsToArgumentList(this.#compiler, sourceNode)) {
|
|
3464
|
-
this.#editor
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
expectExpressionEnd,
|
|
3469
|
-
nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? ";" : "",
|
|
3470
|
-
],
|
|
3471
|
-
[expectEnd, matcherNodeEnd],
|
|
3472
|
-
]);
|
|
3526
|
+
this.#editor
|
|
3527
|
+
.eraseTrailingComma(expect.source)
|
|
3528
|
+
.update(expectStart, expectExpressionEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? ";" : "")
|
|
3529
|
+
.erase(expectEnd, matcherNodeEnd);
|
|
3473
3530
|
if (this.#compiler.isExpressionWithTypeArguments(sourceNode)) {
|
|
3474
|
-
this.#editor.
|
|
3531
|
+
this.#editor.erase(sourceNode.expression.getEnd(), sourceNode.getEnd());
|
|
3475
3532
|
}
|
|
3476
3533
|
}
|
|
3477
3534
|
else {
|
|
3478
3535
|
const sourceText = this.#compiler.isTypeReferenceNode(sourceNode)
|
|
3479
|
-
? sourceNode.typeName.
|
|
3480
|
-
: sourceNode.
|
|
3481
|
-
this.#editor.
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
matcherNodeEnd,
|
|
3485
|
-
nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode)
|
|
3486
|
-
? `;undefined as any as ${sourceText}`
|
|
3487
|
-
: `undefined as any as ${sourceText}`,
|
|
3488
|
-
],
|
|
3489
|
-
]);
|
|
3536
|
+
? sourceNode.typeName.getFullText()
|
|
3537
|
+
: sourceNode.getFullText();
|
|
3538
|
+
this.#editor.update(expectStart, matcherNodeEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode)
|
|
3539
|
+
? `;undefined as any as ${sourceText}`
|
|
3540
|
+
: `undefined as any as ${sourceText}`);
|
|
3490
3541
|
}
|
|
3491
3542
|
if (targetNode != null) {
|
|
3492
3543
|
const targetText = targetNode.getText().slice(1, -1);
|
|
3493
|
-
if (targetText.trim().length >
|
|
3494
|
-
this.#editor.
|
|
3495
|
-
[targetNode.getFullStart(), targetNode.getEnd(), `<${targetText}>`.padStart(targetNode.getFullWidth())],
|
|
3496
|
-
]);
|
|
3544
|
+
if (targetText.trim().length > 0) {
|
|
3545
|
+
this.#editor.update(targetNode.getFullStart(), targetNode.getEnd(), `<${targetText}>`.padStart(targetNode.getFullWidth()));
|
|
3497
3546
|
}
|
|
3498
3547
|
}
|
|
3499
3548
|
break;
|
|
@@ -3505,110 +3554,26 @@ class AbilityLayer {
|
|
|
3505
3554
|
if (!sourceNode || !targetNode) {
|
|
3506
3555
|
return;
|
|
3507
3556
|
}
|
|
3508
|
-
const sourceText = sourceNode.getFullText();
|
|
3509
|
-
const targetText = targetNode.getFullText();
|
|
3510
3557
|
if (nodeBelongsToArgumentList(this.#compiler, sourceNode)) {
|
|
3511
|
-
this.#editor
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
matcherNodeEnd,
|
|
3516
|
-
nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode)
|
|
3517
|
-
? `;(${sourceText})[${targetText}]`
|
|
3518
|
-
: `(${sourceText})[${targetText}]`,
|
|
3519
|
-
],
|
|
3520
|
-
]);
|
|
3558
|
+
this.#editor
|
|
3559
|
+
.eraseTrailingComma(expect.source)
|
|
3560
|
+
.update(expectStart, expectExpressionEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? ";" : "")
|
|
3561
|
+
.erase(expectEnd, matcherNodeEnd);
|
|
3521
3562
|
}
|
|
3522
3563
|
else {
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
]);
|
|
3564
|
+
const sourceText = sourceNode.getFullText();
|
|
3565
|
+
this.#editor.update(expectStart, matcherNodeEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode)
|
|
3566
|
+
? `;(undefined as any as ${sourceText})`
|
|
3567
|
+
: `(undefined as any as ${sourceText})`);
|
|
3568
|
+
}
|
|
3569
|
+
const targetText = targetNode.getText();
|
|
3570
|
+
if (targetText.trim().length > 0) {
|
|
3571
|
+
this.#editor.update(targetNode.getFullStart() - 1, targetNode.getEnd() + 1, `[${targetText}]`.padStart(targetNode.getFullWidth()));
|
|
3532
3572
|
}
|
|
3533
3573
|
break;
|
|
3534
3574
|
}
|
|
3535
3575
|
}
|
|
3536
3576
|
}
|
|
3537
|
-
visitWhen(when) {
|
|
3538
|
-
const whenStart = when.node.getStart();
|
|
3539
|
-
const whenExpressionEnd = when.node.expression.getEnd();
|
|
3540
|
-
const whenEnd = when.node.getEnd();
|
|
3541
|
-
const actionNameEnd = when.actionNameNode.getEnd();
|
|
3542
|
-
switch (when.actionNameNode.name.text) {
|
|
3543
|
-
case "isCalledWith":
|
|
3544
|
-
this.#nodes.push(when);
|
|
3545
|
-
this.#editor.eraseTrailingComma(when.target);
|
|
3546
|
-
this.#editor.replaceRanges([
|
|
3547
|
-
[whenStart, whenExpressionEnd, nodeIsChildOfExpressionStatement(this.#compiler, when.actionNode) ? ";" : ""],
|
|
3548
|
-
[whenEnd, actionNameEnd],
|
|
3549
|
-
]);
|
|
3550
|
-
break;
|
|
3551
|
-
}
|
|
3552
|
-
}
|
|
3553
|
-
}
|
|
3554
|
-
|
|
3555
|
-
class SourceTextEditor {
|
|
3556
|
-
#filePath = "";
|
|
3557
|
-
#sourceFile;
|
|
3558
|
-
#text = "";
|
|
3559
|
-
open(sourceFile) {
|
|
3560
|
-
this.#sourceFile = sourceFile;
|
|
3561
|
-
this.#filePath = sourceFile.fileName;
|
|
3562
|
-
this.#text = sourceFile.text;
|
|
3563
|
-
}
|
|
3564
|
-
close() {
|
|
3565
|
-
if (this.#sourceFile != null) {
|
|
3566
|
-
SourceService.set(this.#sourceFile);
|
|
3567
|
-
this.#sourceFile = undefined;
|
|
3568
|
-
}
|
|
3569
|
-
this.#filePath = "";
|
|
3570
|
-
this.#text = "";
|
|
3571
|
-
}
|
|
3572
|
-
eraseTrailingComma(node) {
|
|
3573
|
-
if (node.hasTrailingComma) {
|
|
3574
|
-
this.replaceRange(node.end - 1, node.end);
|
|
3575
|
-
}
|
|
3576
|
-
}
|
|
3577
|
-
#getErasedRange(start, end) {
|
|
3578
|
-
if (this.#text.indexOf("\n", start) >= end) {
|
|
3579
|
-
return " ".repeat(end - start);
|
|
3580
|
-
}
|
|
3581
|
-
const text = [];
|
|
3582
|
-
for (let index = start; index < end; index++) {
|
|
3583
|
-
const character = this.#text.charAt(index);
|
|
3584
|
-
switch (character) {
|
|
3585
|
-
case "\n":
|
|
3586
|
-
case "\r":
|
|
3587
|
-
text.push(character);
|
|
3588
|
-
break;
|
|
3589
|
-
default:
|
|
3590
|
-
text.push(" ");
|
|
3591
|
-
}
|
|
3592
|
-
}
|
|
3593
|
-
return text.join("");
|
|
3594
|
-
}
|
|
3595
|
-
getFilePath() {
|
|
3596
|
-
return this.#filePath;
|
|
3597
|
-
}
|
|
3598
|
-
getText() {
|
|
3599
|
-
return this.#text;
|
|
3600
|
-
}
|
|
3601
|
-
replaceRange(start, end, replacement) {
|
|
3602
|
-
const rangeText = replacement != null
|
|
3603
|
-
? `${replacement}${this.#getErasedRange(start, end).slice(replacement.length)}`
|
|
3604
|
-
: this.#getErasedRange(start, end);
|
|
3605
|
-
this.#text = `${this.#text.slice(0, start)}${rangeText}${this.#text.slice(end)}`;
|
|
3606
|
-
}
|
|
3607
|
-
replaceRanges(ranges) {
|
|
3608
|
-
for (const [start, end, replacement] of ranges) {
|
|
3609
|
-
this.replaceRange(start, end, replacement);
|
|
3610
|
-
}
|
|
3611
|
-
}
|
|
3612
3577
|
}
|
|
3613
3578
|
|
|
3614
3579
|
class SuppressedLayer {
|
|
@@ -3683,7 +3648,7 @@ class SuppressedLayer {
|
|
|
3683
3648
|
}
|
|
3684
3649
|
for (const suppressedError of suppressedErrors) {
|
|
3685
3650
|
const { start, end } = suppressedError.directive;
|
|
3686
|
-
this.#editor.
|
|
3651
|
+
this.#editor.erase(start, end);
|
|
3687
3652
|
if (this.#suppressedErrorsMap != null) {
|
|
3688
3653
|
const { line } = tree.sourceFile.getLineAndCharacterOfPosition(start);
|
|
3689
3654
|
this.#suppressedErrorsMap.set(line, suppressedError);
|
|
@@ -3692,52 +3657,129 @@ class SuppressedLayer {
|
|
|
3692
3657
|
}
|
|
3693
3658
|
}
|
|
3694
3659
|
|
|
3695
|
-
class
|
|
3696
|
-
#
|
|
3697
|
-
#
|
|
3698
|
-
#
|
|
3699
|
-
#
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
this.#
|
|
3703
|
-
this.#
|
|
3704
|
-
this.#
|
|
3660
|
+
class TextEditor {
|
|
3661
|
+
#filePath = "";
|
|
3662
|
+
#offset = 0;
|
|
3663
|
+
#offsets = [];
|
|
3664
|
+
#text = "";
|
|
3665
|
+
open(sourceFile) {
|
|
3666
|
+
this.#filePath = sourceFile.fileName;
|
|
3667
|
+
this.#text = sourceFile.text;
|
|
3668
|
+
this.#offset = 0;
|
|
3669
|
+
this.#offsets = [];
|
|
3705
3670
|
}
|
|
3706
3671
|
close() {
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
this.#editor.open(tree.sourceFile);
|
|
3719
|
-
this.#suppressedLayer.open(tree);
|
|
3720
|
-
this.#suppressedDiagnostics = this.#projectService.getDiagnostics(this.#editor.getFilePath(), this.#editor.getText());
|
|
3721
|
-
this.#suppressedLayer.close(this.#suppressedDiagnostics);
|
|
3672
|
+
this.#filePath = "";
|
|
3673
|
+
this.#text = "";
|
|
3674
|
+
this.#offset = 0;
|
|
3675
|
+
this.#offsets = [];
|
|
3676
|
+
}
|
|
3677
|
+
erase(start, end) {
|
|
3678
|
+
this.#text =
|
|
3679
|
+
this.#text.slice(0, start + this.#offset) +
|
|
3680
|
+
this.#getErased(start + this.#offset, end + this.#offset) +
|
|
3681
|
+
this.#text.slice(end + this.#offset);
|
|
3682
|
+
return this;
|
|
3722
3683
|
}
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
this.#abilityLayer.visitExpect(node);
|
|
3727
|
-
break;
|
|
3728
|
-
case "when":
|
|
3729
|
-
this.#abilityLayer.visitWhen(node);
|
|
3730
|
-
break;
|
|
3684
|
+
eraseTrailingComma(node) {
|
|
3685
|
+
if (node.hasTrailingComma) {
|
|
3686
|
+
this.erase(node.end - 1, node.end);
|
|
3731
3687
|
}
|
|
3688
|
+
return this;
|
|
3732
3689
|
}
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3690
|
+
#getErased(start, end) {
|
|
3691
|
+
if (this.#text.indexOf("\n", start) >= end) {
|
|
3692
|
+
return " ".repeat(end - start);
|
|
3693
|
+
}
|
|
3694
|
+
const text = [];
|
|
3695
|
+
for (let index = start; index < end; index++) {
|
|
3696
|
+
const character = this.#text.charAt(index);
|
|
3697
|
+
switch (character) {
|
|
3698
|
+
case "\n":
|
|
3699
|
+
case "\r":
|
|
3700
|
+
text.push(character);
|
|
3701
|
+
break;
|
|
3702
|
+
default:
|
|
3703
|
+
text.push(" ");
|
|
3704
|
+
}
|
|
3705
|
+
}
|
|
3706
|
+
return text.join("");
|
|
3707
|
+
}
|
|
3708
|
+
getFilePath() {
|
|
3709
|
+
return this.#filePath;
|
|
3710
|
+
}
|
|
3711
|
+
getOffsets() {
|
|
3712
|
+
return this.#offsets;
|
|
3713
|
+
}
|
|
3714
|
+
getText() {
|
|
3715
|
+
return this.#text;
|
|
3716
|
+
}
|
|
3717
|
+
#setOffset(start, end, text) {
|
|
3718
|
+
const diff = text.length - (end - start);
|
|
3719
|
+
if (diff > 0) {
|
|
3720
|
+
this.#offset += diff;
|
|
3721
|
+
this.#offsets.push({ position: end, diff });
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
update(start, end, text) {
|
|
3725
|
+
this.#text =
|
|
3726
|
+
this.#text.slice(0, start + this.#offset) +
|
|
3727
|
+
text +
|
|
3728
|
+
this.#getErased(start + this.#offset, end + this.#offset).slice(text.length) +
|
|
3729
|
+
this.#text.slice(end + this.#offset);
|
|
3730
|
+
this.#setOffset(start, end, text);
|
|
3731
|
+
return this;
|
|
3732
|
+
}
|
|
3733
|
+
}
|
|
3734
|
+
|
|
3735
|
+
class Layers {
|
|
3736
|
+
#abilityLayer;
|
|
3737
|
+
#editor = new TextEditor();
|
|
3738
|
+
#projectService;
|
|
3739
|
+
#suppressedDiagnostics;
|
|
3740
|
+
#suppressedLayer;
|
|
3741
|
+
constructor(compiler, projectService, resolvedConfig) {
|
|
3742
|
+
this.#projectService = projectService;
|
|
3743
|
+
this.#abilityLayer = new AbilityLayer(compiler, this.#editor);
|
|
3744
|
+
this.#suppressedLayer = new SuppressedLayer(compiler, this.#editor, resolvedConfig);
|
|
3745
|
+
}
|
|
3746
|
+
close(tree) {
|
|
3747
|
+
let seenDiagnostics = [];
|
|
3748
|
+
if (this.#suppressedDiagnostics != null) {
|
|
3749
|
+
seenDiagnostics = this.#suppressedDiagnostics;
|
|
3750
|
+
this.#suppressedDiagnostics = undefined;
|
|
3751
|
+
}
|
|
3752
|
+
const diagnostics = this.#projectService.getDiagnostics(this.#editor.getFilePath(), this.#editor.getText());
|
|
3753
|
+
const offsets = this.#editor.getOffsets();
|
|
3754
|
+
const abilityDiagnostics = [];
|
|
3755
|
+
if (diagnostics != null) {
|
|
3756
|
+
for (const diagnostic of diagnostics) {
|
|
3757
|
+
const mappedDiagnostic = new MappedDiagnostic(tree.sourceFile, diagnostic, offsets);
|
|
3758
|
+
if (!seenDiagnostics.some((seenDiagnostic) => compareDiagnostics(mappedDiagnostic, seenDiagnostic))) {
|
|
3759
|
+
abilityDiagnostics.push(mappedDiagnostic);
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
}
|
|
3763
|
+
this.#abilityLayer.close(abilityDiagnostics);
|
|
3764
|
+
this.#editor.close();
|
|
3765
|
+
}
|
|
3766
|
+
open(tree) {
|
|
3767
|
+
this.#editor.open(tree.sourceFile);
|
|
3768
|
+
this.#suppressedLayer.open(tree);
|
|
3769
|
+
this.#suppressedDiagnostics = this.#projectService.getDiagnostics(this.#editor.getFilePath(), this.#editor.getText());
|
|
3770
|
+
this.#suppressedLayer.close(this.#suppressedDiagnostics?.map((diagnostic) => new MappedDiagnostic(tree.sourceFile, diagnostic)));
|
|
3771
|
+
}
|
|
3772
|
+
visit(node) {
|
|
3773
|
+
this.#abilityLayer.visitExpect(node);
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
|
|
3777
|
+
class CollectDiagnosticText {
|
|
3778
|
+
static cannotBeNestedWithin(source, target) {
|
|
3779
|
+
return `'${source}()' cannot be nested within '${target}()'.`;
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
|
|
3741
3783
|
class TestTreeNode {
|
|
3742
3784
|
brand;
|
|
3743
3785
|
children = [];
|
|
@@ -3880,8 +3922,6 @@ class IdentifierLookup {
|
|
|
3880
3922
|
return { brand: "test", flags };
|
|
3881
3923
|
case "expect":
|
|
3882
3924
|
return { brand: "expect", flags };
|
|
3883
|
-
case "when":
|
|
3884
|
-
return { brand: "when", flags };
|
|
3885
3925
|
}
|
|
3886
3926
|
return;
|
|
3887
3927
|
}
|
|
@@ -3899,25 +3939,6 @@ class TestTree {
|
|
|
3899
3939
|
}
|
|
3900
3940
|
}
|
|
3901
3941
|
|
|
3902
|
-
class WhenNode extends TestTreeNode {
|
|
3903
|
-
actionNode;
|
|
3904
|
-
actionNameNode;
|
|
3905
|
-
abilityDiagnostics = new Set();
|
|
3906
|
-
target;
|
|
3907
|
-
constructor(compiler, brand, node, parent, flags, actionNode, actionNameNode) {
|
|
3908
|
-
super(compiler, brand, node, parent, flags);
|
|
3909
|
-
this.actionNode = actionNode;
|
|
3910
|
-
this.actionNameNode = actionNameNode;
|
|
3911
|
-
this.target = this.node.typeArguments ?? this.node.arguments;
|
|
3912
|
-
for (const diagnostic of parent.diagnostics) {
|
|
3913
|
-
if (diagnosticBelongsToNode(diagnostic, node)) {
|
|
3914
|
-
this.diagnostics.add(diagnostic);
|
|
3915
|
-
parent.diagnostics.delete(diagnostic);
|
|
3916
|
-
}
|
|
3917
|
-
}
|
|
3918
|
-
}
|
|
3919
|
-
}
|
|
3920
|
-
|
|
3921
3942
|
class CollectService {
|
|
3922
3943
|
#layers;
|
|
3923
3944
|
#compiler;
|
|
@@ -3977,38 +3998,6 @@ class CollectService {
|
|
|
3977
3998
|
this.#onNode(expectNode, parent, testTree);
|
|
3978
3999
|
return;
|
|
3979
4000
|
}
|
|
3980
|
-
if (meta.brand === "when") {
|
|
3981
|
-
const actionNameNode = this.#getChainedNode(node);
|
|
3982
|
-
if (!actionNameNode) {
|
|
3983
|
-
const text = "The final element in the chain must be an action.";
|
|
3984
|
-
const origin = DiagnosticOrigin.fromNode(node);
|
|
3985
|
-
this.#onDiagnostics(Diagnostic.error(text, origin));
|
|
3986
|
-
return;
|
|
3987
|
-
}
|
|
3988
|
-
const actionNode = this.#getActionNode(actionNameNode);
|
|
3989
|
-
if (!actionNode) {
|
|
3990
|
-
const text = "The action must be called with an argument.";
|
|
3991
|
-
const origin = DiagnosticOrigin.fromNode(actionNameNode);
|
|
3992
|
-
this.#onDiagnostics(Diagnostic.error(text, origin));
|
|
3993
|
-
return;
|
|
3994
|
-
}
|
|
3995
|
-
this.#compiler.forEachChild(actionNode, (node) => {
|
|
3996
|
-
if (this.#compiler.isCallExpression(node)) {
|
|
3997
|
-
const meta = this.#identifierLookup.resolveTestTreeNodeMeta(node);
|
|
3998
|
-
if (meta?.brand === "describe" ||
|
|
3999
|
-
meta?.brand === "it" ||
|
|
4000
|
-
meta?.brand === "test") {
|
|
4001
|
-
const text = CollectDiagnosticText.cannotBeNestedWithin(meta.brand, "when");
|
|
4002
|
-
const origin = DiagnosticOrigin.fromNode(node);
|
|
4003
|
-
this.#onDiagnostics(Diagnostic.error(text, origin));
|
|
4004
|
-
}
|
|
4005
|
-
}
|
|
4006
|
-
});
|
|
4007
|
-
const whenNode = new WhenNode(this.#compiler, meta.brand, node, parent, meta.flags, actionNode, actionNameNode);
|
|
4008
|
-
this.#layers.visit(whenNode);
|
|
4009
|
-
this.#onNode(whenNode, parent, testTree);
|
|
4010
|
-
return;
|
|
4011
|
-
}
|
|
4012
4001
|
}
|
|
4013
4002
|
}
|
|
4014
4003
|
if (this.#compiler.isImportDeclaration(node)) {
|
|
@@ -4025,7 +4014,7 @@ class CollectService {
|
|
|
4025
4014
|
this.#layers.open(testTree);
|
|
4026
4015
|
this.#identifierLookup.open();
|
|
4027
4016
|
this.#collectTestTreeNodes(sourceFile, testTree, testTree);
|
|
4028
|
-
this.#layers.close();
|
|
4017
|
+
this.#layers.close(testTree);
|
|
4029
4018
|
EventEmitter.dispatch(["collect:end", { tree: testTree }]);
|
|
4030
4019
|
return testTree;
|
|
4031
4020
|
}
|
|
@@ -4050,7 +4039,6 @@ class CollectService {
|
|
|
4050
4039
|
}
|
|
4051
4040
|
break;
|
|
4052
4041
|
case "expect":
|
|
4053
|
-
case "when":
|
|
4054
4042
|
if (parent.brand === "describe") {
|
|
4055
4043
|
return false;
|
|
4056
4044
|
}
|
|
@@ -4079,12 +4067,6 @@ class CollectService {
|
|
|
4079
4067
|
}
|
|
4080
4068
|
return;
|
|
4081
4069
|
}
|
|
4082
|
-
#getActionNode(node) {
|
|
4083
|
-
if (this.#compiler.isCallExpression(node.parent)) {
|
|
4084
|
-
return node.parent;
|
|
4085
|
-
}
|
|
4086
|
-
return;
|
|
4087
|
-
}
|
|
4088
4070
|
#onDiagnostics(diagnostic) {
|
|
4089
4071
|
EventEmitter.dispatch(["collect:error", { diagnostics: [diagnostic] }]);
|
|
4090
4072
|
}
|
|
@@ -4103,7 +4085,6 @@ var TestTreeNodeBrand;
|
|
|
4103
4085
|
TestTreeNodeBrand["Test"] = "test";
|
|
4104
4086
|
TestTreeNodeBrand["It"] = "it";
|
|
4105
4087
|
TestTreeNodeBrand["Expect"] = "expect";
|
|
4106
|
-
TestTreeNodeBrand["When"] = "when";
|
|
4107
4088
|
})(TestTreeNodeBrand || (TestTreeNodeBrand = {}));
|
|
4108
4089
|
|
|
4109
4090
|
var TestTreeNodeFlags;
|
|
@@ -4117,7 +4098,7 @@ var TestTreeNodeFlags;
|
|
|
4117
4098
|
class ProjectService {
|
|
4118
4099
|
#compiler;
|
|
4119
4100
|
#host;
|
|
4120
|
-
#lastSeenProject = "";
|
|
4101
|
+
#lastSeenProject = "none";
|
|
4121
4102
|
#projectConfig;
|
|
4122
4103
|
#resolvedConfig;
|
|
4123
4104
|
#seenProjects = new Set();
|
|
@@ -4167,7 +4148,6 @@ class ProjectService {
|
|
|
4167
4148
|
}
|
|
4168
4149
|
closeFile(filePath) {
|
|
4169
4150
|
this.#service.closeClientFile(filePath);
|
|
4170
|
-
SourceService.delete(filePath);
|
|
4171
4151
|
}
|
|
4172
4152
|
#getDefaultCompilerOptions() {
|
|
4173
4153
|
const defaultCompilerOptions = {
|
|
@@ -4197,14 +4177,10 @@ class ProjectService {
|
|
|
4197
4177
|
}
|
|
4198
4178
|
return project;
|
|
4199
4179
|
}
|
|
4200
|
-
getDiagnostics(filePath, sourceText
|
|
4180
|
+
getDiagnostics(filePath, sourceText) {
|
|
4201
4181
|
this.openFile(filePath, sourceText);
|
|
4202
4182
|
const languageService = this.getLanguageService(filePath);
|
|
4203
|
-
|
|
4204
|
-
if (diagnostics != null && shouldInclude != null) {
|
|
4205
|
-
return diagnostics.filter(shouldInclude);
|
|
4206
|
-
}
|
|
4207
|
-
return diagnostics;
|
|
4183
|
+
return languageService?.getSemanticDiagnostics(filePath);
|
|
4208
4184
|
}
|
|
4209
4185
|
getLanguageService(filePath) {
|
|
4210
4186
|
const project = this.getDefaultProject(filePath);
|
|
@@ -4225,7 +4201,7 @@ class ProjectService {
|
|
|
4225
4201
|
if (Options.isJsonString(specifier)) {
|
|
4226
4202
|
return {
|
|
4227
4203
|
kind: 3,
|
|
4228
|
-
specifier: Path.resolve(this.#resolvedConfig.rootPath, `${
|
|
4204
|
+
specifier: Path.resolve(this.#resolvedConfig.rootPath, `${Date.now().toString(36)}.tsconfig.json`),
|
|
4229
4205
|
};
|
|
4230
4206
|
}
|
|
4231
4207
|
return { kind: 2, specifier };
|
|
@@ -4369,51 +4345,102 @@ class SuppressedService {
|
|
|
4369
4345
|
}
|
|
4370
4346
|
}
|
|
4371
4347
|
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4348
|
+
function capitalize(text) {
|
|
4349
|
+
return text.replace(/^./, text.charAt(0).toUpperCase());
|
|
4350
|
+
}
|
|
4351
|
+
|
|
4352
|
+
class RejectDiagnosticText {
|
|
4353
|
+
static argumentCannotBeOfType(typeText) {
|
|
4354
|
+
return `The argument cannot be of the '${typeText}' type.`;
|
|
4375
4355
|
}
|
|
4376
|
-
static
|
|
4377
|
-
return `
|
|
4356
|
+
static typeArgumentCannotBeOfType(typeText) {
|
|
4357
|
+
return `The type argument cannot be of the '${typeText}' type.`;
|
|
4378
4358
|
}
|
|
4379
|
-
static
|
|
4380
|
-
|
|
4359
|
+
static typeWasRejected(typeText) {
|
|
4360
|
+
const optionNameText = `reject${capitalize(typeText)}Type`;
|
|
4361
|
+
return [
|
|
4362
|
+
`The '${typeText}' type was rejected because the '${optionNameText}' option is enabled.`,
|
|
4363
|
+
`If this check is necessary, pass '${typeText}' as the type argument explicitly.`,
|
|
4364
|
+
];
|
|
4381
4365
|
}
|
|
4382
4366
|
}
|
|
4383
4367
|
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4368
|
+
class Reject {
|
|
4369
|
+
#compiler;
|
|
4370
|
+
#rejectedArgumentTypes = new Set();
|
|
4371
|
+
#typeChecker;
|
|
4372
|
+
constructor(compiler, program, resolvedConfig) {
|
|
4373
|
+
this.#compiler = compiler;
|
|
4374
|
+
this.#typeChecker = program.getTypeChecker();
|
|
4375
|
+
if (resolvedConfig.rejectAnyType) {
|
|
4376
|
+
this.#rejectedArgumentTypes.add("any");
|
|
4377
|
+
}
|
|
4378
|
+
if (resolvedConfig.rejectNeverType) {
|
|
4379
|
+
this.#rejectedArgumentTypes.add("never");
|
|
4380
|
+
}
|
|
4390
4381
|
}
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4382
|
+
argumentType(target, onDiagnostics) {
|
|
4383
|
+
for (const rejectedType of this.#rejectedArgumentTypes) {
|
|
4384
|
+
const allowedKeyword = this.#compiler.SyntaxKind[`${capitalize(rejectedType)}Keyword`];
|
|
4385
|
+
if (target.some((node) => node?.kind === allowedKeyword)) {
|
|
4386
|
+
continue;
|
|
4387
|
+
}
|
|
4388
|
+
for (const node of target) {
|
|
4389
|
+
if (!node) {
|
|
4390
|
+
continue;
|
|
4391
|
+
}
|
|
4392
|
+
if (this.#typeChecker.getTypeAtLocation(node).flags & this.#compiler.TypeFlags[capitalize(rejectedType)]) {
|
|
4393
|
+
const text = [
|
|
4394
|
+
nodeBelongsToArgumentList(this.#compiler, node)
|
|
4395
|
+
? RejectDiagnosticText.argumentCannotBeOfType(rejectedType)
|
|
4396
|
+
: RejectDiagnosticText.typeArgumentCannotBeOfType(rejectedType),
|
|
4397
|
+
...RejectDiagnosticText.typeWasRejected(rejectedType),
|
|
4398
|
+
];
|
|
4399
|
+
const origin = DiagnosticOrigin.fromNode(node);
|
|
4400
|
+
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
4401
|
+
return true;
|
|
4402
|
+
}
|
|
4403
|
+
}
|
|
4404
|
+
}
|
|
4399
4405
|
return false;
|
|
4400
4406
|
}
|
|
4401
|
-
return true;
|
|
4402
4407
|
}
|
|
4403
4408
|
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4409
|
+
class Ensure {
|
|
4410
|
+
#compiler;
|
|
4411
|
+
constructor(compiler) {
|
|
4412
|
+
this.#compiler = compiler;
|
|
4413
|
+
}
|
|
4414
|
+
argument(node, enclosingNode, onDiagnostics) {
|
|
4415
|
+
if (!node || !nodeBelongsToArgumentList(this.#compiler, node)) {
|
|
4416
|
+
this.#emitDiagnostic("An argument must be provided.", enclosingNode, onDiagnostics);
|
|
4417
|
+
return false;
|
|
4418
|
+
}
|
|
4419
|
+
return true;
|
|
4420
|
+
}
|
|
4421
|
+
argumentOrTypeArgument(node, enclosingNode, onDiagnostics) {
|
|
4422
|
+
if (!node) {
|
|
4423
|
+
this.#emitDiagnostic("An argument or type argument must be provided.", enclosingNode, onDiagnostics);
|
|
4424
|
+
return false;
|
|
4425
|
+
}
|
|
4426
|
+
return true;
|
|
4427
|
+
}
|
|
4428
|
+
typeArgument(node, enclosingNode, onDiagnostics) {
|
|
4429
|
+
if (!node || nodeBelongsToArgumentList(this.#compiler, node)) {
|
|
4430
|
+
this.#emitDiagnostic("A type argument must be provided.", enclosingNode, onDiagnostics);
|
|
4431
|
+
return false;
|
|
4432
|
+
}
|
|
4433
|
+
return true;
|
|
4434
|
+
}
|
|
4435
|
+
#emitDiagnostic(text, enclosingNode, onDiagnostics) {
|
|
4407
4436
|
const origin = DiagnosticOrigin.fromNode(enclosingNode);
|
|
4408
4437
|
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
4409
|
-
return false;
|
|
4410
4438
|
}
|
|
4411
|
-
return true;
|
|
4412
4439
|
}
|
|
4413
4440
|
|
|
4414
4441
|
class ExpectDiagnosticText {
|
|
4415
|
-
static argumentMustBe(
|
|
4416
|
-
return `
|
|
4442
|
+
static argumentMustBe(expectedText) {
|
|
4443
|
+
return `The argument must be ${expectedText}.`;
|
|
4417
4444
|
}
|
|
4418
4445
|
static typeArgumentMustBe(expectedText) {
|
|
4419
4446
|
return `The type argument must be ${expectedText}.`;
|
|
@@ -4437,10 +4464,10 @@ class ExpectDiagnosticText {
|
|
|
4437
4464
|
return `${isExpression ? "Expression" : "Type"} is not instantiable ${targetText}.`;
|
|
4438
4465
|
}
|
|
4439
4466
|
static acceptsProps(isExpression) {
|
|
4440
|
-
return `${isExpression ? "Component" : "
|
|
4467
|
+
return `${isExpression ? "Component" : "Type"} accepts props of the given type.`;
|
|
4441
4468
|
}
|
|
4442
4469
|
static doesNotAcceptProps(isExpression) {
|
|
4443
|
-
return `${isExpression ? "Component" : "
|
|
4470
|
+
return `${isExpression ? "Component" : "Type"} does not accept props of the given type.`;
|
|
4444
4471
|
}
|
|
4445
4472
|
static canBeApplied(targetText) {
|
|
4446
4473
|
return `The decorator function can be applied${targetText}.`;
|
|
@@ -4460,9 +4487,6 @@ class ExpectDiagnosticText {
|
|
|
4460
4487
|
static matcherIsNotSupported(matcherNameText) {
|
|
4461
4488
|
return `The '.${matcherNameText}()' matcher is not supported.`;
|
|
4462
4489
|
}
|
|
4463
|
-
static overloadGaveTheFollowingError(index, count, signatureText) {
|
|
4464
|
-
return `Overload ${index} of ${count}, '${signatureText}', gave the following error.`;
|
|
4465
|
-
}
|
|
4466
4490
|
static raisedTypeError(count = 1) {
|
|
4467
4491
|
return `The raised type error${count === 1 ? "" : "s"}:`;
|
|
4468
4492
|
}
|
|
@@ -4500,15 +4524,6 @@ class ExpectDiagnosticText {
|
|
|
4500
4524
|
static isNotTheSame(sourceTypeText, targetTypeText) {
|
|
4501
4525
|
return `Type '${sourceTypeText}' is not the same as type '${targetTypeText}'.`;
|
|
4502
4526
|
}
|
|
4503
|
-
static isNotCompatibleWith(sourceTypeText, targetTypeText) {
|
|
4504
|
-
return `Type '${sourceTypeText}' is not compatible with type '${targetTypeText}'.`;
|
|
4505
|
-
}
|
|
4506
|
-
static requiresProperty(typeText, propertyNameText) {
|
|
4507
|
-
return `Type '${typeText}' requires property '${propertyNameText}'.`;
|
|
4508
|
-
}
|
|
4509
|
-
static typesOfPropertyAreNotCompatible(propertyNameText) {
|
|
4510
|
-
return `Types of property '${propertyNameText}' are not compatible.`;
|
|
4511
|
-
}
|
|
4512
4527
|
}
|
|
4513
4528
|
|
|
4514
4529
|
class MatchWorker {
|
|
@@ -4538,13 +4553,6 @@ class MatchWorker {
|
|
|
4538
4553
|
: { flags: this.#compiler.TypeFlags.NonPrimitive };
|
|
4539
4554
|
return this.typeChecker.isTypeAssignableTo(type, nonPrimitiveType);
|
|
4540
4555
|
}
|
|
4541
|
-
getParameterType(signature, index) {
|
|
4542
|
-
const parameter = signature.getDeclaration().parameters[index];
|
|
4543
|
-
if (!parameter) {
|
|
4544
|
-
return;
|
|
4545
|
-
}
|
|
4546
|
-
return this.getType(parameter);
|
|
4547
|
-
}
|
|
4548
4556
|
getSignatures(node) {
|
|
4549
4557
|
let signatures = this.#signatureCache.get(node);
|
|
4550
4558
|
if (!signatures) {
|
|
@@ -4562,195 +4570,100 @@ class MatchWorker {
|
|
|
4562
4570
|
getType(node) {
|
|
4563
4571
|
return this.typeChecker.getTypeAtLocation(node);
|
|
4564
4572
|
}
|
|
4565
|
-
resolveDiagnosticOrigin(symbol, enclosingNode) {
|
|
4566
|
-
if (symbol.valueDeclaration != null &&
|
|
4567
|
-
(this.#compiler.isPropertySignature(symbol.valueDeclaration) ||
|
|
4568
|
-
this.#compiler.isPropertyAssignment(symbol.valueDeclaration) ||
|
|
4569
|
-
this.#compiler.isShorthandPropertyAssignment(symbol.valueDeclaration)) &&
|
|
4570
|
-
symbol.valueDeclaration.getStart() >= enclosingNode.getStart() &&
|
|
4571
|
-
symbol.valueDeclaration.getEnd() <= enclosingNode.getEnd()) {
|
|
4572
|
-
return DiagnosticOrigin.fromNode(symbol.valueDeclaration.name, this.assertionNode);
|
|
4573
|
-
}
|
|
4574
|
-
return DiagnosticOrigin.fromNode(enclosingNode, this.assertionNode);
|
|
4575
|
-
}
|
|
4576
|
-
}
|
|
4577
|
-
|
|
4578
|
-
function isStringOrNumberLiteralType(compiler, type) {
|
|
4579
|
-
return !!(type.flags & compiler.TypeFlags.StringOrNumberLiteral);
|
|
4580
|
-
}
|
|
4581
|
-
function isUnionType(compiler, type) {
|
|
4582
|
-
return !!(type.flags & compiler.TypeFlags.Union);
|
|
4583
|
-
}
|
|
4584
|
-
function isUniqueSymbolType(compiler, type) {
|
|
4585
|
-
return !!(type.flags & compiler.TypeFlags.UniqueESSymbol);
|
|
4586
4573
|
}
|
|
4587
4574
|
|
|
4588
|
-
class
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
this.#compiler = compiler;
|
|
4593
|
-
this.#typeChecker = program.getTypeChecker();
|
|
4594
|
-
}
|
|
4595
|
-
#explain(matchWorker, sourceNode, targetNode) {
|
|
4596
|
-
const isExpression = nodeBelongsToArgumentList(this.#compiler, sourceNode);
|
|
4597
|
-
const signatures = matchWorker.getSignatures(sourceNode);
|
|
4598
|
-
return signatures.reduce((accumulator, signature, index) => {
|
|
4599
|
-
let diagnostic;
|
|
4600
|
-
const introText = matchWorker.assertionNode.isNot
|
|
4601
|
-
? ExpectDiagnosticText.acceptsProps(isExpression)
|
|
4602
|
-
: ExpectDiagnosticText.doesNotAcceptProps(isExpression);
|
|
4603
|
-
const origin = DiagnosticOrigin.fromNode(targetNode, matchWorker.assertionNode);
|
|
4604
|
-
if (signatures.length > 1) {
|
|
4605
|
-
const signatureText = this.#typeChecker.signatureToString(signature, sourceNode);
|
|
4606
|
-
const overloadText = ExpectDiagnosticText.overloadGaveTheFollowingError(index + 1, signatures.length, signatureText);
|
|
4607
|
-
diagnostic = Diagnostic.error([introText, overloadText], origin);
|
|
4608
|
-
}
|
|
4609
|
-
else {
|
|
4610
|
-
diagnostic = Diagnostic.error([introText], origin);
|
|
4611
|
-
}
|
|
4612
|
-
const { diagnostics, isMatch } = this.#explainProperties(matchWorker, signature, targetNode, diagnostic);
|
|
4613
|
-
if (matchWorker.assertionNode.isNot ? isMatch : !isMatch) {
|
|
4614
|
-
accumulator.push(...diagnostics);
|
|
4615
|
-
}
|
|
4616
|
-
return accumulator;
|
|
4617
|
-
}, []);
|
|
4575
|
+
class AbilityMatcherBase {
|
|
4576
|
+
compiler;
|
|
4577
|
+
constructor(compiler) {
|
|
4578
|
+
this.compiler = compiler;
|
|
4618
4579
|
}
|
|
4619
|
-
|
|
4620
|
-
|
|
4580
|
+
getArgumentCountText(nodes) {
|
|
4581
|
+
if (nodes.length === 0) {
|
|
4582
|
+
return "without arguments";
|
|
4583
|
+
}
|
|
4584
|
+
if (nodes.length === 1 && nodes[0]?.kind === this.compiler.SyntaxKind.SpreadElement) {
|
|
4585
|
+
return "with the given arguments";
|
|
4586
|
+
}
|
|
4587
|
+
return `with the given argument${nodes.length === 1 ? "" : "s"}`;
|
|
4621
4588
|
}
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
const targetPropertyName = targetProperty.getName();
|
|
4626
|
-
const sourceProperty = sourceType?.getProperty(targetPropertyName);
|
|
4627
|
-
if (!sourceProperty) {
|
|
4628
|
-
return false;
|
|
4629
|
-
}
|
|
4630
|
-
const targetPropertyType = this.#typeChecker.getTypeOfSymbol(targetProperty);
|
|
4631
|
-
const sourcePropertyType = this.#typeChecker.getTypeOfSymbol(sourceProperty);
|
|
4632
|
-
if (!this.#typeChecker.isTypeAssignableTo(targetPropertyType, sourcePropertyType)) {
|
|
4633
|
-
return false;
|
|
4634
|
-
}
|
|
4635
|
-
}
|
|
4636
|
-
if (sourceType != null) {
|
|
4637
|
-
const sourceProperties = sourceType.getProperties();
|
|
4638
|
-
for (const sourceProperty of sourceProperties) {
|
|
4639
|
-
const targetProperty = targetType.getProperty(sourceProperty.getName());
|
|
4640
|
-
if (!targetProperty && !this.#isOptionalProperty(sourceProperty)) {
|
|
4641
|
-
return false;
|
|
4642
|
-
}
|
|
4643
|
-
}
|
|
4644
|
-
}
|
|
4645
|
-
return true;
|
|
4646
|
-
};
|
|
4647
|
-
if (sourceType != null && isUnionType(this.#compiler, sourceType)) {
|
|
4648
|
-
return sourceType.types.some((sourceType) => check(sourceType, targetType));
|
|
4589
|
+
getTypeArgumentCountText(targetNode) {
|
|
4590
|
+
if (targetNode.elements.length === 0) {
|
|
4591
|
+
return "without type arguments";
|
|
4649
4592
|
}
|
|
4650
|
-
return
|
|
4593
|
+
return `with the given type argument${targetNode.elements.length === 1 ? "" : "s"}`;
|
|
4651
4594
|
}
|
|
4652
|
-
|
|
4653
|
-
const
|
|
4654
|
-
const
|
|
4655
|
-
const
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
const sourceProperty = sourceType?.getProperty(targetPropertyName);
|
|
4663
|
-
if (!sourceProperty) {
|
|
4664
|
-
const text = [
|
|
4665
|
-
ExpectDiagnosticText.isNotCompatibleWith(sourceTypeText, targetTypeText),
|
|
4666
|
-
ExpectDiagnosticText.doesNotHaveProperty(sourceTypeText, targetPropertyName),
|
|
4667
|
-
];
|
|
4668
|
-
const origin = matchWorker.resolveDiagnosticOrigin(targetProperty, targetNode);
|
|
4669
|
-
diagnostics.push(diagnostic.extendWith(text, origin));
|
|
4670
|
-
continue;
|
|
4595
|
+
explain(matchWorker, sourceNode, targetNode, getArgumentCountText) {
|
|
4596
|
+
const isExpression = nodeBelongsToArgumentList(this.compiler, sourceNode);
|
|
4597
|
+
const argumentCountText = getArgumentCountText?.();
|
|
4598
|
+
const diagnostics = [];
|
|
4599
|
+
if (matchWorker.assertionNode.abilityDiagnostics.size > 0) {
|
|
4600
|
+
for (const diagnostic of matchWorker.assertionNode.abilityDiagnostics) {
|
|
4601
|
+
const text = [this.explainNotText(isExpression, argumentCountText), getDiagnosticMessageText(diagnostic)];
|
|
4602
|
+
let origin;
|
|
4603
|
+
if (isDiagnosticWithLocation(diagnostic) && diagnosticBelongsToNode(diagnostic, targetNode)) {
|
|
4604
|
+
origin = DiagnosticOrigin.fromAbilityDiagnostic(diagnostic, matchWorker.assertionNode);
|
|
4671
4605
|
}
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
if (!this.#typeChecker.isTypeAssignableTo(targetPropertyType, sourcePropertyType)) {
|
|
4675
|
-
const targetPropertyTypeText = this.#typeChecker.typeToString(targetPropertyType);
|
|
4676
|
-
const sourcePropertyTypeText = this.#typeChecker.typeToString(sourcePropertyType);
|
|
4677
|
-
const text = [
|
|
4678
|
-
ExpectDiagnosticText.isNotAssignableFrom(sourceTypeText, targetTypeText),
|
|
4679
|
-
ExpectDiagnosticText.typesOfPropertyAreNotCompatible(targetPropertyName),
|
|
4680
|
-
ExpectDiagnosticText.isNotAssignableFrom(sourcePropertyTypeText, targetPropertyTypeText),
|
|
4681
|
-
];
|
|
4682
|
-
const origin = matchWorker.resolveDiagnosticOrigin(targetProperty, targetNode);
|
|
4683
|
-
diagnostics.push(diagnostic.extendWith(text, origin));
|
|
4606
|
+
else {
|
|
4607
|
+
origin = DiagnosticOrigin.fromAssertion(matchWorker.assertionNode);
|
|
4684
4608
|
}
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
const sourcePropertyName = sourceProperty.getName();
|
|
4689
|
-
const targetProperty = targetType.getProperty(sourcePropertyName);
|
|
4690
|
-
if (!targetProperty && !this.#isOptionalProperty(sourceProperty)) {
|
|
4691
|
-
const text = [
|
|
4692
|
-
ExpectDiagnosticText.isNotAssignableFrom(sourceTypeText, targetTypeText),
|
|
4693
|
-
ExpectDiagnosticText.requiresProperty(sourceTypeText, sourcePropertyName),
|
|
4694
|
-
];
|
|
4695
|
-
diagnostics.push(diagnostic.extendWith(text));
|
|
4696
|
-
}
|
|
4609
|
+
let related;
|
|
4610
|
+
if (diagnostic.relatedInformation != null) {
|
|
4611
|
+
related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
|
|
4697
4612
|
}
|
|
4613
|
+
diagnostics.push(Diagnostic.error(text.flat(), origin).add({ related }));
|
|
4698
4614
|
}
|
|
4699
|
-
if (diagnostics.length === 0) {
|
|
4700
|
-
const text = ExpectDiagnosticText.isAssignableFrom(sourceTypeText, targetTypeText);
|
|
4701
|
-
diagnostics.push(diagnostic.extendWith(text));
|
|
4702
|
-
return { diagnostics, isMatch: true };
|
|
4703
|
-
}
|
|
4704
|
-
return { diagnostics, isMatch: false };
|
|
4705
|
-
};
|
|
4706
|
-
if (sourceType != null && isUnionType(this.#compiler, sourceType)) {
|
|
4707
|
-
let accumulator = [];
|
|
4708
|
-
const isMatch = sourceType.types.some((sourceType) => {
|
|
4709
|
-
const text = matchWorker.assertionNode.isNot
|
|
4710
|
-
? ExpectDiagnosticText.isAssignableFrom(sourceTypeText, targetTypeText)
|
|
4711
|
-
: ExpectDiagnosticText.isNotAssignableFrom(sourceTypeText, targetTypeText);
|
|
4712
|
-
const { diagnostics, isMatch } = explain(sourceType, targetType, diagnostic.extendWith(text));
|
|
4713
|
-
if (isMatch) {
|
|
4714
|
-
accumulator = diagnostics;
|
|
4715
|
-
}
|
|
4716
|
-
else {
|
|
4717
|
-
accumulator.push(...diagnostics);
|
|
4718
|
-
}
|
|
4719
|
-
return isMatch;
|
|
4720
|
-
});
|
|
4721
|
-
return { diagnostics: accumulator, isMatch };
|
|
4722
4615
|
}
|
|
4723
|
-
|
|
4616
|
+
else {
|
|
4617
|
+
const origin = DiagnosticOrigin.fromAssertion(matchWorker.assertionNode);
|
|
4618
|
+
diagnostics.push(Diagnostic.error(this.explainText(isExpression, argumentCountText), origin));
|
|
4619
|
+
}
|
|
4620
|
+
return diagnostics;
|
|
4724
4621
|
}
|
|
4622
|
+
}
|
|
4623
|
+
|
|
4624
|
+
class ToAcceptProps extends AbilityMatcherBase {
|
|
4625
|
+
explainText = ExpectDiagnosticText.acceptsProps;
|
|
4626
|
+
explainNotText = ExpectDiagnosticText.doesNotAcceptProps;
|
|
4725
4627
|
match(matchWorker, sourceNode, targetNode, onDiagnostics) {
|
|
4726
4628
|
const diagnostics = [];
|
|
4727
4629
|
const signatures = matchWorker.getSignatures(sourceNode);
|
|
4728
4630
|
if (signatures.length === 0) {
|
|
4729
4631
|
const expectedText = "of a function or class type";
|
|
4730
|
-
const text = nodeBelongsToArgumentList(this
|
|
4731
|
-
? ExpectDiagnosticText.argumentMustBe(
|
|
4632
|
+
const text = nodeBelongsToArgumentList(this.compiler, sourceNode)
|
|
4633
|
+
? ExpectDiagnosticText.argumentMustBe(expectedText)
|
|
4732
4634
|
: ExpectDiagnosticText.typeArgumentMustBe(expectedText);
|
|
4733
4635
|
const origin = DiagnosticOrigin.fromNode(sourceNode);
|
|
4734
4636
|
diagnostics.push(Diagnostic.error(text, origin));
|
|
4735
4637
|
}
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
const
|
|
4739
|
-
const text = ExpectDiagnosticText.argumentMustBe("props", expectedText);
|
|
4638
|
+
if (!this.compiler.isObjectLiteralExpression(targetNode)) {
|
|
4639
|
+
const expectedText = "an object literal with key-value pairs";
|
|
4640
|
+
const text = ExpectDiagnosticText.argumentMustBe(expectedText);
|
|
4740
4641
|
const origin = DiagnosticOrigin.fromNode(targetNode);
|
|
4741
4642
|
diagnostics.push(Diagnostic.error(text, origin));
|
|
4742
4643
|
}
|
|
4644
|
+
else {
|
|
4645
|
+
for (const property of targetNode.properties) {
|
|
4646
|
+
if (!(this.compiler.isPropertyAssignment(property) || this.compiler.isSpreadAssignment(property))) {
|
|
4647
|
+
const text = "Each property must be a key-value pair or a spread element.";
|
|
4648
|
+
const origin = DiagnosticOrigin.fromNode(property);
|
|
4649
|
+
diagnostics.push(Diagnostic.error(text, origin));
|
|
4650
|
+
continue;
|
|
4651
|
+
}
|
|
4652
|
+
if (this.compiler.isPropertyAssignment(property) &&
|
|
4653
|
+
!(this.compiler.isIdentifier(property.name) || this.compiler.isStringLiteral(property.name))) {
|
|
4654
|
+
const text = "Property keys must be static identifiers or string literals.";
|
|
4655
|
+
const origin = DiagnosticOrigin.fromNode(property.name);
|
|
4656
|
+
diagnostics.push(Diagnostic.error(text, origin));
|
|
4657
|
+
}
|
|
4658
|
+
}
|
|
4659
|
+
}
|
|
4743
4660
|
if (diagnostics.length > 0) {
|
|
4744
4661
|
onDiagnostics(diagnostics);
|
|
4745
4662
|
return;
|
|
4746
4663
|
}
|
|
4747
|
-
const isMatch = signatures.some((signature) => {
|
|
4748
|
-
const sourceType = matchWorker.getParameterType(signature, 0);
|
|
4749
|
-
return this.#checkProperties(sourceType, targetType);
|
|
4750
|
-
});
|
|
4751
4664
|
return {
|
|
4752
|
-
explain: () => this
|
|
4753
|
-
isMatch,
|
|
4665
|
+
explain: () => this.explain(matchWorker, sourceNode, targetNode),
|
|
4666
|
+
isMatch: matchWorker.assertionNode.abilityDiagnostics.size === 0,
|
|
4754
4667
|
};
|
|
4755
4668
|
}
|
|
4756
4669
|
}
|
|
@@ -5351,7 +5264,7 @@ class ToBeApplicable {
|
|
|
5351
5264
|
if (type.getCallSignatures().length === 0) {
|
|
5352
5265
|
const expectedText = "of a function type";
|
|
5353
5266
|
const text = nodeBelongsToArgumentList(this.#compiler, sourceNode)
|
|
5354
|
-
? ExpectDiagnosticText.argumentMustBe(
|
|
5267
|
+
? ExpectDiagnosticText.argumentMustBe(expectedText)
|
|
5355
5268
|
: ExpectDiagnosticText.typeArgumentMustBe(expectedText);
|
|
5356
5269
|
const origin = DiagnosticOrigin.fromNode(sourceNode);
|
|
5357
5270
|
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
@@ -5386,55 +5299,6 @@ class ToBeAssignableTo extends RelationMatcherBase {
|
|
|
5386
5299
|
}
|
|
5387
5300
|
}
|
|
5388
5301
|
|
|
5389
|
-
class AbilityMatcherBase {
|
|
5390
|
-
compiler;
|
|
5391
|
-
constructor(compiler) {
|
|
5392
|
-
this.compiler = compiler;
|
|
5393
|
-
}
|
|
5394
|
-
getArgumentCountText(nodes) {
|
|
5395
|
-
if (nodes.length === 0) {
|
|
5396
|
-
return "without arguments";
|
|
5397
|
-
}
|
|
5398
|
-
if (nodes.length === 1 && nodes[0]?.kind === this.compiler.SyntaxKind.SpreadElement) {
|
|
5399
|
-
return "with the given arguments";
|
|
5400
|
-
}
|
|
5401
|
-
return `with the given argument${nodes.length === 1 ? "" : "s"}`;
|
|
5402
|
-
}
|
|
5403
|
-
getTypeArgumentCountText(targetNode) {
|
|
5404
|
-
if (targetNode.elements.length === 0) {
|
|
5405
|
-
return "without type arguments";
|
|
5406
|
-
}
|
|
5407
|
-
return `with the given type argument${targetNode.elements.length === 1 ? "" : "s"}`;
|
|
5408
|
-
}
|
|
5409
|
-
explain(matchWorker, sourceNode, targetNode, getArgumentCountText) {
|
|
5410
|
-
const isExpression = nodeBelongsToArgumentList(this.compiler, sourceNode);
|
|
5411
|
-
const argumentCountText = getArgumentCountText();
|
|
5412
|
-
const diagnostics = [];
|
|
5413
|
-
if (matchWorker.assertionNode.abilityDiagnostics.size > 0) {
|
|
5414
|
-
for (const diagnostic of matchWorker.assertionNode.abilityDiagnostics) {
|
|
5415
|
-
const text = [this.explainNotText(isExpression, argumentCountText), getDiagnosticMessageText(diagnostic)];
|
|
5416
|
-
let origin;
|
|
5417
|
-
if (isDiagnosticWithLocation(diagnostic) && diagnosticBelongsToNode(diagnostic, targetNode)) {
|
|
5418
|
-
origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), sourceNode.getSourceFile(), matchWorker.assertionNode);
|
|
5419
|
-
}
|
|
5420
|
-
else {
|
|
5421
|
-
origin = DiagnosticOrigin.fromAssertion(matchWorker.assertionNode);
|
|
5422
|
-
}
|
|
5423
|
-
let related;
|
|
5424
|
-
if (diagnostic.relatedInformation != null) {
|
|
5425
|
-
related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
|
|
5426
|
-
}
|
|
5427
|
-
diagnostics.push(Diagnostic.error(text.flat(), origin).add({ related }));
|
|
5428
|
-
}
|
|
5429
|
-
}
|
|
5430
|
-
else {
|
|
5431
|
-
const origin = DiagnosticOrigin.fromAssertion(matchWorker.assertionNode);
|
|
5432
|
-
diagnostics.push(Diagnostic.error(this.explainText(isExpression, argumentCountText), origin));
|
|
5433
|
-
}
|
|
5434
|
-
return diagnostics;
|
|
5435
|
-
}
|
|
5436
|
-
}
|
|
5437
|
-
|
|
5438
5302
|
class ToBeCallableWith extends AbilityMatcherBase {
|
|
5439
5303
|
explainText = ExpectDiagnosticText.isCallable;
|
|
5440
5304
|
explainNotText = ExpectDiagnosticText.isNotCallable;
|
|
@@ -5443,7 +5307,7 @@ class ToBeCallableWith extends AbilityMatcherBase {
|
|
|
5443
5307
|
if (sourceType.getCallSignatures().length === 0) {
|
|
5444
5308
|
const text = [];
|
|
5445
5309
|
if (nodeBelongsToArgumentList(this.compiler, sourceNode)) {
|
|
5446
|
-
text.push(ExpectDiagnosticText.argumentMustBe("
|
|
5310
|
+
text.push(ExpectDiagnosticText.argumentMustBe("a callable expression"));
|
|
5447
5311
|
}
|
|
5448
5312
|
else {
|
|
5449
5313
|
text.push(ExpectDiagnosticText.typeArgumentMustBe("a callable type"));
|
|
@@ -5470,7 +5334,7 @@ class ToBeConstructableWith extends AbilityMatcherBase {
|
|
|
5470
5334
|
if (sourceType.getConstructSignatures().length === 0) {
|
|
5471
5335
|
const text = [];
|
|
5472
5336
|
if (nodeBelongsToArgumentList(this.compiler, sourceNode)) {
|
|
5473
|
-
text.push(ExpectDiagnosticText.argumentMustBe("
|
|
5337
|
+
text.push(ExpectDiagnosticText.argumentMustBe("a constructable expression"));
|
|
5474
5338
|
}
|
|
5475
5339
|
else {
|
|
5476
5340
|
text.push(ExpectDiagnosticText.typeArgumentMustBe("a constructable type"));
|
|
@@ -5499,7 +5363,7 @@ class ToBeInstantiableWith extends AbilityMatcherBase {
|
|
|
5499
5363
|
this.compiler.isExpressionWithTypeArguments(sourceNode))) {
|
|
5500
5364
|
let text;
|
|
5501
5365
|
if (nodeBelongsToArgumentList(this.compiler, sourceNode)) {
|
|
5502
|
-
text = ExpectDiagnosticText.argumentMustBe("
|
|
5366
|
+
text = ExpectDiagnosticText.argumentMustBe("an instantiable expression");
|
|
5503
5367
|
}
|
|
5504
5368
|
else {
|
|
5505
5369
|
text = ExpectDiagnosticText.typeArgumentMustBe("an instantiable type");
|
|
@@ -5530,7 +5394,7 @@ class ToHaveProperty {
|
|
|
5530
5394
|
const sourceTypeText = matchWorker.getTypeText(sourceNode);
|
|
5531
5395
|
const targetType = matchWorker.getType(targetNode);
|
|
5532
5396
|
let propertyNameText;
|
|
5533
|
-
if (
|
|
5397
|
+
if (targetType.flags & (this.#compiler.TypeFlags.StringLiteral | this.#compiler.TypeFlags.NumberLiteral)) {
|
|
5534
5398
|
propertyNameText = targetType.value.toString();
|
|
5535
5399
|
}
|
|
5536
5400
|
else {
|
|
@@ -5548,15 +5412,18 @@ class ToHaveProperty {
|
|
|
5548
5412
|
!matchWorker.extendsObjectType(sourceType)) {
|
|
5549
5413
|
const expectedText = "of an object type";
|
|
5550
5414
|
const text = nodeBelongsToArgumentList(this.#compiler, sourceNode)
|
|
5551
|
-
? ExpectDiagnosticText.argumentMustBe(
|
|
5415
|
+
? ExpectDiagnosticText.argumentMustBe(expectedText)
|
|
5552
5416
|
: ExpectDiagnosticText.typeArgumentMustBe(expectedText);
|
|
5553
5417
|
const origin = DiagnosticOrigin.fromNode(sourceNode);
|
|
5554
5418
|
diagnostics.push(Diagnostic.error(text, origin));
|
|
5555
5419
|
}
|
|
5556
5420
|
const targetType = matchWorker.getType(targetNode);
|
|
5557
|
-
if (!(
|
|
5558
|
-
|
|
5559
|
-
|
|
5421
|
+
if (!(targetType.flags &
|
|
5422
|
+
(this.#compiler.TypeFlags.StringLiteral |
|
|
5423
|
+
this.#compiler.TypeFlags.NumberLiteral |
|
|
5424
|
+
this.#compiler.TypeFlags.UniqueESSymbol))) {
|
|
5425
|
+
const expectedText = "a string, number or symbol";
|
|
5426
|
+
const text = ExpectDiagnosticText.argumentMustBe(expectedText);
|
|
5560
5427
|
const origin = DiagnosticOrigin.fromNode(targetNode);
|
|
5561
5428
|
diagnostics.push(Diagnostic.error(text, origin));
|
|
5562
5429
|
}
|
|
@@ -5615,8 +5482,8 @@ class ToRaiseError {
|
|
|
5615
5482
|
if (!(this.#compiler.isStringLiteralLike(targetNode) ||
|
|
5616
5483
|
this.#compiler.isNumericLiteral(targetNode) ||
|
|
5617
5484
|
this.#compiler.isRegularExpressionLiteral(targetNode))) {
|
|
5618
|
-
const expectedText = "a string, number or regular expression
|
|
5619
|
-
const text = ExpectDiagnosticText.argumentMustBe(
|
|
5485
|
+
const expectedText = "a string, number or regular expression";
|
|
5486
|
+
const text = ExpectDiagnosticText.argumentMustBe(expectedText);
|
|
5620
5487
|
const origin = DiagnosticOrigin.fromNode(targetNode);
|
|
5621
5488
|
diagnostics.push(Diagnostic.error(text, origin));
|
|
5622
5489
|
}
|
|
@@ -5657,6 +5524,7 @@ class ToRaiseError {
|
|
|
5657
5524
|
|
|
5658
5525
|
class ExpectService {
|
|
5659
5526
|
#compiler;
|
|
5527
|
+
#ensure;
|
|
5660
5528
|
#program;
|
|
5661
5529
|
#reject;
|
|
5662
5530
|
toAcceptProps;
|
|
@@ -5669,11 +5537,12 @@ class ExpectService {
|
|
|
5669
5537
|
toBeInstantiableWith;
|
|
5670
5538
|
toHaveProperty;
|
|
5671
5539
|
toRaiseError;
|
|
5672
|
-
constructor(compiler, program,
|
|
5540
|
+
constructor(compiler, program, resolvedConfig) {
|
|
5673
5541
|
this.#compiler = compiler;
|
|
5674
5542
|
this.#program = program;
|
|
5675
|
-
this.#
|
|
5676
|
-
this
|
|
5543
|
+
this.#ensure = new Ensure(compiler);
|
|
5544
|
+
this.#reject = new Reject(compiler, program, resolvedConfig);
|
|
5545
|
+
this.toAcceptProps = new ToAcceptProps(compiler);
|
|
5677
5546
|
this.toBe = new ToBe(compiler, program);
|
|
5678
5547
|
this.toBeApplicable = new ToBeApplicable(compiler);
|
|
5679
5548
|
this.toBeAssignableFrom = new ToBeAssignableFrom();
|
|
@@ -5686,15 +5555,12 @@ class ExpectService {
|
|
|
5686
5555
|
}
|
|
5687
5556
|
match(assertionNode, onDiagnostics) {
|
|
5688
5557
|
const matcherNameText = assertionNode.matcherNameNode.name.text;
|
|
5689
|
-
if (!
|
|
5558
|
+
if (!this.#ensure.argumentOrTypeArgument(assertionNode.source[0], assertionNode.node.expression, onDiagnostics)) {
|
|
5690
5559
|
return;
|
|
5691
5560
|
}
|
|
5692
5561
|
const matchWorker = new MatchWorker(this.#compiler, this.#program, assertionNode);
|
|
5693
5562
|
if (!(matcherNameText === "toBeInstantiableWith" || (matcherNameText === "toRaiseError" && !assertionNode.isNot)) &&
|
|
5694
|
-
this.#reject.argumentType([
|
|
5695
|
-
["source", assertionNode.source[0]],
|
|
5696
|
-
["target", assertionNode.target?.[0]],
|
|
5697
|
-
], onDiagnostics)) {
|
|
5563
|
+
this.#reject.argumentType([assertionNode.source[0], assertionNode.target?.[0]], onDiagnostics)) {
|
|
5698
5564
|
return;
|
|
5699
5565
|
}
|
|
5700
5566
|
switch (matcherNameText) {
|
|
@@ -5702,7 +5568,7 @@ class ExpectService {
|
|
|
5702
5568
|
case "toBe":
|
|
5703
5569
|
case "toBeAssignableFrom":
|
|
5704
5570
|
case "toBeAssignableTo":
|
|
5705
|
-
if (!
|
|
5571
|
+
if (!this.#ensure.argumentOrTypeArgument(assertionNode.target?.[0], assertionNode.matcherNameNode.name, onDiagnostics)) {
|
|
5706
5572
|
return;
|
|
5707
5573
|
}
|
|
5708
5574
|
return this[matcherNameText].match(matchWorker, assertionNode.source[0], assertionNode.target[0], onDiagnostics);
|
|
@@ -5713,13 +5579,13 @@ class ExpectService {
|
|
|
5713
5579
|
case "toRaiseError":
|
|
5714
5580
|
return this[matcherNameText].match(matchWorker, assertionNode.source[0], assertionNode.target, onDiagnostics);
|
|
5715
5581
|
case "toBeInstantiableWith": {
|
|
5716
|
-
if (!
|
|
5582
|
+
if (!this.#ensure.typeArgument(assertionNode.target?.[0], assertionNode.matcherNameNode.name, onDiagnostics)) {
|
|
5717
5583
|
return;
|
|
5718
5584
|
}
|
|
5719
5585
|
return this.toBeInstantiableWith.match(matchWorker, assertionNode.source[0], assertionNode.target[0], onDiagnostics);
|
|
5720
5586
|
}
|
|
5721
5587
|
case "toHaveProperty":
|
|
5722
|
-
if (!
|
|
5588
|
+
if (!this.#ensure.argument(assertionNode.target?.[0], assertionNode.matcherNameNode.name, onDiagnostics)) {
|
|
5723
5589
|
return;
|
|
5724
5590
|
}
|
|
5725
5591
|
return this.toHaveProperty.match(matchWorker, assertionNode.source[0], assertionNode.target[0], onDiagnostics);
|
|
@@ -5735,124 +5601,6 @@ class ExpectService {
|
|
|
5735
5601
|
}
|
|
5736
5602
|
}
|
|
5737
5603
|
|
|
5738
|
-
function capitalize(text) {
|
|
5739
|
-
return text.replace(/^./, text.charAt(0).toUpperCase());
|
|
5740
|
-
}
|
|
5741
|
-
|
|
5742
|
-
class RejectDiagnosticText {
|
|
5743
|
-
static argumentCannotBeOfType(argumentNameText, typeText) {
|
|
5744
|
-
return `An argument for '${argumentNameText}' cannot be of the '${typeText}' type.`;
|
|
5745
|
-
}
|
|
5746
|
-
static typeArgumentCannotBeOfType(argumentNameText, typeText) {
|
|
5747
|
-
return `A type argument for '${argumentNameText}' cannot be of the '${typeText}' type.`;
|
|
5748
|
-
}
|
|
5749
|
-
static typeWasRejected(typeText) {
|
|
5750
|
-
const optionNameText = `reject${capitalize(typeText)}Type`;
|
|
5751
|
-
return [
|
|
5752
|
-
`The '${typeText}' type was rejected because the '${optionNameText}' option is enabled.`,
|
|
5753
|
-
`If this check is necessary, pass '${typeText}' as the type argument explicitly.`,
|
|
5754
|
-
];
|
|
5755
|
-
}
|
|
5756
|
-
}
|
|
5757
|
-
|
|
5758
|
-
class Reject {
|
|
5759
|
-
#compiler;
|
|
5760
|
-
#rejectedArgumentTypes = new Set();
|
|
5761
|
-
#typeChecker;
|
|
5762
|
-
constructor(compiler, program, resolvedConfig) {
|
|
5763
|
-
this.#compiler = compiler;
|
|
5764
|
-
this.#typeChecker = program.getTypeChecker();
|
|
5765
|
-
if (resolvedConfig.rejectAnyType) {
|
|
5766
|
-
this.#rejectedArgumentTypes.add("any");
|
|
5767
|
-
}
|
|
5768
|
-
if (resolvedConfig.rejectNeverType) {
|
|
5769
|
-
this.#rejectedArgumentTypes.add("never");
|
|
5770
|
-
}
|
|
5771
|
-
}
|
|
5772
|
-
argumentType(target, onDiagnostics) {
|
|
5773
|
-
for (const rejectedType of this.#rejectedArgumentTypes) {
|
|
5774
|
-
const allowedKeyword = this.#compiler.SyntaxKind[`${capitalize(rejectedType)}Keyword`];
|
|
5775
|
-
if (target.some(([, node]) => node?.kind === allowedKeyword)) {
|
|
5776
|
-
continue;
|
|
5777
|
-
}
|
|
5778
|
-
for (const [name, node] of target) {
|
|
5779
|
-
if (!node) {
|
|
5780
|
-
continue;
|
|
5781
|
-
}
|
|
5782
|
-
if (this.#typeChecker.getTypeAtLocation(node).flags & this.#compiler.TypeFlags[capitalize(rejectedType)]) {
|
|
5783
|
-
const text = [
|
|
5784
|
-
nodeBelongsToArgumentList(this.#compiler, node)
|
|
5785
|
-
? RejectDiagnosticText.argumentCannotBeOfType(name, rejectedType)
|
|
5786
|
-
: RejectDiagnosticText.typeArgumentCannotBeOfType(capitalize(name), rejectedType),
|
|
5787
|
-
...RejectDiagnosticText.typeWasRejected(rejectedType),
|
|
5788
|
-
];
|
|
5789
|
-
const origin = DiagnosticOrigin.fromNode(node);
|
|
5790
|
-
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
5791
|
-
return true;
|
|
5792
|
-
}
|
|
5793
|
-
}
|
|
5794
|
-
}
|
|
5795
|
-
return false;
|
|
5796
|
-
}
|
|
5797
|
-
}
|
|
5798
|
-
|
|
5799
|
-
class WhenDiagnosticText {
|
|
5800
|
-
static actionIsNotSupported(actionNameText) {
|
|
5801
|
-
return `The '.${actionNameText}()' action is not supported.`;
|
|
5802
|
-
}
|
|
5803
|
-
}
|
|
5804
|
-
|
|
5805
|
-
class WhenService {
|
|
5806
|
-
#compiler;
|
|
5807
|
-
#onDiagnostics;
|
|
5808
|
-
#reject;
|
|
5809
|
-
constructor(compiler, reject, onDiagnostics) {
|
|
5810
|
-
this.#compiler = compiler;
|
|
5811
|
-
this.#reject = reject;
|
|
5812
|
-
this.#onDiagnostics = onDiagnostics;
|
|
5813
|
-
}
|
|
5814
|
-
action(when) {
|
|
5815
|
-
if (!argumentIsProvided(this.#compiler, "target", when.target[0], when.node.expression, this.#onDiagnostics) ||
|
|
5816
|
-
this.#reject.argumentType([["target", when.target[0]]], this.#onDiagnostics)) {
|
|
5817
|
-
return;
|
|
5818
|
-
}
|
|
5819
|
-
const actionNameText = when.actionNameNode.name.getText();
|
|
5820
|
-
switch (actionNameText) {
|
|
5821
|
-
case "isCalledWith":
|
|
5822
|
-
break;
|
|
5823
|
-
default:
|
|
5824
|
-
this.#onActionIsNotSupported(actionNameText, when, this.#onDiagnostics);
|
|
5825
|
-
return;
|
|
5826
|
-
}
|
|
5827
|
-
if (when.abilityDiagnostics.size > 0) {
|
|
5828
|
-
const diagnostics = [];
|
|
5829
|
-
for (const diagnostic of when.abilityDiagnostics) {
|
|
5830
|
-
if (isDiagnosticWithLocation(diagnostic)) {
|
|
5831
|
-
const text = getDiagnosticMessageText(diagnostic);
|
|
5832
|
-
let origin;
|
|
5833
|
-
if (isDiagnosticWithLocation(diagnostic) && diagnosticBelongsToNode(diagnostic, when.node)) {
|
|
5834
|
-
origin = DiagnosticOrigin.fromNodes(when.target);
|
|
5835
|
-
}
|
|
5836
|
-
else {
|
|
5837
|
-
origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), when.node.getSourceFile());
|
|
5838
|
-
}
|
|
5839
|
-
let related;
|
|
5840
|
-
if (diagnostic.relatedInformation != null) {
|
|
5841
|
-
related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
|
|
5842
|
-
}
|
|
5843
|
-
diagnostics.push(Diagnostic.error(text, origin).add({ related }));
|
|
5844
|
-
}
|
|
5845
|
-
}
|
|
5846
|
-
this.#onDiagnostics(diagnostics);
|
|
5847
|
-
}
|
|
5848
|
-
}
|
|
5849
|
-
#onActionIsNotSupported(actionNameText, when, onDiagnostics) {
|
|
5850
|
-
const text = WhenDiagnosticText.actionIsNotSupported(actionNameText);
|
|
5851
|
-
const origin = DiagnosticOrigin.fromNode(when.actionNameNode.name);
|
|
5852
|
-
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
5853
|
-
}
|
|
5854
|
-
}
|
|
5855
|
-
|
|
5856
5604
|
class FixmeDiagnosticText {
|
|
5857
5605
|
static considerRemoving() {
|
|
5858
5606
|
return "Consider removing the '// @tstyche fixme' directive.";
|
|
@@ -5919,7 +5667,6 @@ class TestTreeWalker {
|
|
|
5919
5667
|
#onFileDiagnostics;
|
|
5920
5668
|
#position;
|
|
5921
5669
|
#resolvedConfig;
|
|
5922
|
-
#whenService;
|
|
5923
5670
|
constructor(compiler, program, resolvedConfig, onFileDiagnostics, options) {
|
|
5924
5671
|
this.#compiler = compiler;
|
|
5925
5672
|
this.#resolvedConfig = resolvedConfig;
|
|
@@ -5927,9 +5674,7 @@ class TestTreeWalker {
|
|
|
5927
5674
|
this.#cancellationToken = options.cancellationToken;
|
|
5928
5675
|
this.#hasOnly = options.hasOnly || resolvedConfig.only != null || options.position != null;
|
|
5929
5676
|
this.#position = options.position;
|
|
5930
|
-
|
|
5931
|
-
this.#expectService = new ExpectService(compiler, program, reject);
|
|
5932
|
-
this.#whenService = new WhenService(compiler, reject, onFileDiagnostics);
|
|
5677
|
+
this.#expectService = new ExpectService(compiler, program, resolvedConfig);
|
|
5933
5678
|
}
|
|
5934
5679
|
async #resolveRunMode(flags, node) {
|
|
5935
5680
|
const ifDirective = Directive.getDirectiveRange(this.#compiler, node, "if");
|
|
@@ -5974,9 +5719,6 @@ class TestTreeWalker {
|
|
|
5974
5719
|
case "expect":
|
|
5975
5720
|
await this.#visitExpect(node, runModeFlags, parentResult);
|
|
5976
5721
|
break;
|
|
5977
|
-
case "when":
|
|
5978
|
-
this.#visitWhen(node);
|
|
5979
|
-
break;
|
|
5980
5722
|
}
|
|
5981
5723
|
if (fixmeDirective) {
|
|
5982
5724
|
FixmeService.end(fixmeDirective, node, this.#onFileDiagnostics);
|
|
@@ -6078,9 +5820,6 @@ class TestTreeWalker {
|
|
|
6078
5820
|
EventEmitter.dispatch(["test:fail", { result: testResult }]);
|
|
6079
5821
|
}
|
|
6080
5822
|
}
|
|
6081
|
-
#visitWhen(when) {
|
|
6082
|
-
this.#whenService.action(when);
|
|
6083
|
-
}
|
|
6084
5823
|
}
|
|
6085
5824
|
|
|
6086
5825
|
class FileRunner {
|
|
@@ -6169,7 +5908,7 @@ class FileRunner {
|
|
|
6169
5908
|
class Runner {
|
|
6170
5909
|
#eventEmitter = new EventEmitter();
|
|
6171
5910
|
#resolvedConfig;
|
|
6172
|
-
static version = "7.
|
|
5911
|
+
static version = "7.2.0";
|
|
6173
5912
|
constructor(resolvedConfig) {
|
|
6174
5913
|
this.#resolvedConfig = resolvedConfig;
|
|
6175
5914
|
}
|
|
@@ -6394,4 +6133,4 @@ class Cli {
|
|
|
6394
6133
|
}
|
|
6395
6134
|
}
|
|
6396
6135
|
|
|
6397
|
-
export { BaseReporter, CancellationReason, CancellationToken, Cli, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, Directive, DotReporter, EventEmitter, ExpectResult, FileLocation, FileResult, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, ProjectConfigKind, ProjectResult, Result, ResultStatus, Runner, Scribbler, Select, SelectDiagnosticText, SetupReporter, Store, StreamController, SummaryReporter, SuppressedResult, TargetResult, TestResult, Text, Version, WatchReporter, addsText, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, dotText, environmentOptions, fileStatusText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, prologueText, summaryText, testNameText, usesText, waitingForFileChangesText, watchUsageText };
|
|
6136
|
+
export { BaseReporter, CancellationReason, CancellationToken, Cli, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, Directive, DotReporter, EventEmitter, ExpectResult, FileLocation, FileResult, Line, ListReporter, MappedDiagnostic, OptionBrand, OptionGroup, Options, OutputService, Path, ProjectConfigKind, ProjectResult, Result, ResultStatus, Runner, Scribbler, Select, SelectDiagnosticText, SetupReporter, Store, StreamController, SummaryReporter, SuppressedResult, TargetResult, TestResult, Text, Version, WatchReporter, addsText, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, dotText, environmentOptions, fileStatusText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, prologueText, summaryText, testNameText, usesText, waitingForFileChangesText, watchUsageText };
|