tstyche 7.1.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/dist/api.d.ts +22 -5
- package/dist/api.js +509 -599
- package/package.json +7 -3
package/dist/api.js
CHANGED
|
@@ -77,43 +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
|
-
}
|
|
116
|
-
|
|
117
80
|
function diagnosticBelongsToNode(diagnostic, node) {
|
|
118
81
|
return diagnostic.start != null && diagnostic.start >= node.pos && diagnostic.start <= node.end;
|
|
119
82
|
}
|
|
@@ -131,6 +94,16 @@ function getDiagnosticMessageText(diagnostic) {
|
|
|
131
94
|
? diagnostic.messageText
|
|
132
95
|
: diagnosticMessageChainToText(diagnostic.messageText);
|
|
133
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
|
+
}
|
|
134
107
|
function getTextSpanEnd(span) {
|
|
135
108
|
return span.start + span.length;
|
|
136
109
|
}
|
|
@@ -138,6 +111,29 @@ function isDiagnosticWithLocation(diagnostic) {
|
|
|
138
111
|
return diagnostic.file != null && diagnostic.start != null && diagnostic.length != null;
|
|
139
112
|
}
|
|
140
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
|
+
|
|
141
137
|
class Diagnostic {
|
|
142
138
|
category;
|
|
143
139
|
code;
|
|
@@ -190,6 +186,37 @@ var DiagnosticCategory;
|
|
|
190
186
|
DiagnosticCategory["Warning"] = "warning";
|
|
191
187
|
})(DiagnosticCategory || (DiagnosticCategory = {}));
|
|
192
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
|
+
|
|
193
220
|
class JsonScanner {
|
|
194
221
|
#end;
|
|
195
222
|
#position;
|
|
@@ -307,15 +334,20 @@ class JsonSourceFile {
|
|
|
307
334
|
const result = [0];
|
|
308
335
|
let position = 0;
|
|
309
336
|
while (position < this.text.length) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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;
|
|
315
348
|
}
|
|
316
349
|
position++;
|
|
317
350
|
}
|
|
318
|
-
result.push(position);
|
|
319
351
|
return result;
|
|
320
352
|
}
|
|
321
353
|
getLineStarts() {
|
|
@@ -417,15 +449,31 @@ class ConfigDiagnosticText {
|
|
|
417
449
|
class Environment {
|
|
418
450
|
static resolve() {
|
|
419
451
|
return {
|
|
452
|
+
fetchRetries: Environment.#resolveFetchRetries(),
|
|
453
|
+
fetchTimeout: Environment.#resolveFetchTimeout(),
|
|
420
454
|
isCi: Environment.#resolveIsCi(),
|
|
421
455
|
noColor: Environment.#resolveNoColor(),
|
|
422
456
|
noInteractive: Environment.#resolveNoInteractive(),
|
|
423
457
|
npmRegistry: Environment.#resolveNpmRegistry(),
|
|
424
458
|
storePath: Environment.#resolveStorePath(),
|
|
425
|
-
timeout: Environment.#resolveTimeout(),
|
|
426
459
|
typescriptModule: Environment.#resolveTypeScriptModule(),
|
|
427
460
|
};
|
|
428
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
|
+
}
|
|
429
477
|
static #resolveIsCi() {
|
|
430
478
|
if (process.env["CI"] != null) {
|
|
431
479
|
return process.env["CI"] !== "";
|
|
@@ -468,12 +516,6 @@ class Environment {
|
|
|
468
516
|
}
|
|
469
517
|
return Path.resolve(os.homedir(), ".local", "share", "TSTyche");
|
|
470
518
|
}
|
|
471
|
-
static #resolveTimeout() {
|
|
472
|
-
if (process.env["TSTYCHE_TIMEOUT"] != null) {
|
|
473
|
-
return Number.parseFloat(process.env["TSTYCHE_TIMEOUT"]);
|
|
474
|
-
}
|
|
475
|
-
return 30;
|
|
476
|
-
}
|
|
477
519
|
static #resolveTypeScriptModule() {
|
|
478
520
|
let specifier = "typescript";
|
|
479
521
|
if (process.env["TSTYCHE_TYPESCRIPT_MODULE"] != null) {
|
|
@@ -522,6 +564,10 @@ class Version {
|
|
|
522
564
|
}
|
|
523
565
|
}
|
|
524
566
|
|
|
567
|
+
function sleep(delay) {
|
|
568
|
+
return new Promise((resolve) => setTimeout(resolve, delay));
|
|
569
|
+
}
|
|
570
|
+
|
|
525
571
|
class StoreDiagnosticText {
|
|
526
572
|
static cannotAddTypeScriptPackage(tag) {
|
|
527
573
|
return `Cannot add the 'typescript' package for the '${tag}' tag.`;
|
|
@@ -535,13 +581,13 @@ class StoreDiagnosticText {
|
|
|
535
581
|
static failedToUpdateMetadata(registry) {
|
|
536
582
|
return `Failed to update metadata of the 'typescript' package from '${registry}'.`;
|
|
537
583
|
}
|
|
538
|
-
static maybeNetworkConnectionIssue() {
|
|
539
|
-
return "Might be there is an issue with the registry or the network connection.";
|
|
540
|
-
}
|
|
541
584
|
static maybeOutdatedResolution(tag) {
|
|
542
585
|
return `The resolution of the '${tag}' tag may be outdated.`;
|
|
543
586
|
}
|
|
544
|
-
static
|
|
587
|
+
static networkFailure(retries) {
|
|
588
|
+
return `The network connection failed after ${retries + 1} attempts.`;
|
|
589
|
+
}
|
|
590
|
+
static requestFailed(code) {
|
|
545
591
|
return `The request failed with status code ${code}.`;
|
|
546
592
|
}
|
|
547
593
|
static requestTimeoutWasExceeded(timeout) {
|
|
@@ -554,29 +600,48 @@ class StoreDiagnosticText {
|
|
|
554
600
|
|
|
555
601
|
class Fetcher {
|
|
556
602
|
#onDiagnostics;
|
|
603
|
+
#retries;
|
|
557
604
|
#timeout;
|
|
558
|
-
constructor(onDiagnostics, timeout) {
|
|
605
|
+
constructor(onDiagnostics, retries, timeout) {
|
|
559
606
|
this.#onDiagnostics = onDiagnostics;
|
|
607
|
+
this.#retries = retries;
|
|
560
608
|
this.#timeout = timeout;
|
|
561
609
|
}
|
|
562
610
|
async get(request, diagnostic, options) {
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
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
|
+
}
|
|
569
631
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
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
|
+
}
|
|
576
641
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
642
|
+
if (!isLastAttempt) {
|
|
643
|
+
await sleep(delay);
|
|
644
|
+
delay *= 2;
|
|
580
645
|
}
|
|
581
646
|
}
|
|
582
647
|
return;
|
|
@@ -620,17 +685,14 @@ class LockService {
|
|
|
620
685
|
const waitStartTime = Date.now();
|
|
621
686
|
while (isLocked) {
|
|
622
687
|
if (Date.now() - waitStartTime > this.#timeout) {
|
|
623
|
-
this.#onDiagnostics(diagnostic.extendWith(StoreDiagnosticText.lockWaitTimeoutWasExceeded(this.#timeout)));
|
|
688
|
+
this.#onDiagnostics(diagnostic().extendWith(StoreDiagnosticText.lockWaitTimeoutWasExceeded(this.#timeout)));
|
|
624
689
|
break;
|
|
625
690
|
}
|
|
626
|
-
await
|
|
691
|
+
await sleep(1000);
|
|
627
692
|
isLocked = existsSync(lockFilePath);
|
|
628
693
|
}
|
|
629
694
|
return isLocked;
|
|
630
695
|
}
|
|
631
|
-
#sleep(delay) {
|
|
632
|
-
return new Promise((resolve) => setTimeout(resolve, delay));
|
|
633
|
-
}
|
|
634
696
|
}
|
|
635
697
|
|
|
636
698
|
class Manifest {
|
|
@@ -711,7 +773,7 @@ class ManifestService {
|
|
|
711
773
|
return manifest;
|
|
712
774
|
}
|
|
713
775
|
async #load(options) {
|
|
714
|
-
const diagnostic = Diagnostic.error(StoreDiagnosticText.failedToFetchMetadata(this.#npmRegistry));
|
|
776
|
+
const diagnostic = () => Diagnostic.error(StoreDiagnosticText.failedToFetchMetadata(this.#npmRegistry));
|
|
715
777
|
const request = new Request(new URL("typescript", this.#npmRegistry), {
|
|
716
778
|
headers: {
|
|
717
779
|
["Accept"]: "application/vnd.npm.install-v1+json;q=1.0, application/json;q=0.8, */*",
|
|
@@ -848,7 +910,7 @@ class PackageService {
|
|
|
848
910
|
}
|
|
849
911
|
async ensure(packageVersion, manifest) {
|
|
850
912
|
const packagePath = Path.join(this.#storePath, `typescript@${packageVersion}`);
|
|
851
|
-
const diagnostic = Diagnostic.error(StoreDiagnosticText.failedToFetchPackage(packageVersion));
|
|
913
|
+
const diagnostic = () => Diagnostic.error(StoreDiagnosticText.failedToFetchPackage(packageVersion));
|
|
852
914
|
if (await this.#lockService.isLocked(packagePath, diagnostic)) {
|
|
853
915
|
return;
|
|
854
916
|
}
|
|
@@ -889,12 +951,13 @@ class Store {
|
|
|
889
951
|
static #manifestService;
|
|
890
952
|
static #packageService;
|
|
891
953
|
static #npmRegistry = environmentOptions.npmRegistry;
|
|
954
|
+
static #fetchRetries = environmentOptions.fetchRetries;
|
|
955
|
+
static #fetchTimeout = environmentOptions.fetchTimeout * 1000;
|
|
892
956
|
static #storePath = environmentOptions.storePath;
|
|
893
957
|
static #supportedTags;
|
|
894
|
-
static #timeout = environmentOptions.timeout * 1000;
|
|
895
958
|
static {
|
|
896
|
-
Store.#fetcher = new Fetcher(Store.#onDiagnostics, Store.#
|
|
897
|
-
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);
|
|
898
961
|
Store.#packageService = new PackageService(Store.#storePath, Store.#fetcher, Store.#lockService);
|
|
899
962
|
Store.#manifestService = new ManifestService(Store.#storePath, Store.#npmRegistry, Store.#fetcher);
|
|
900
963
|
}
|
|
@@ -2255,8 +2318,8 @@ function CodeFrameText({ diagnosticCategory, diagnosticOrigin, options }) {
|
|
|
2255
2318
|
const linesBelow = options?.linesBelow ?? 3;
|
|
2256
2319
|
const showBreadcrumbs = options?.showBreadcrumbs ?? true;
|
|
2257
2320
|
const lineMap = diagnosticOrigin.sourceFile.getLineStarts();
|
|
2258
|
-
const { character:
|
|
2259
|
-
const { character:
|
|
2321
|
+
const { character: firstMarkedCharacter, line: firstMarkedLine } = diagnosticOrigin.sourceFile.getLineAndCharacterOfPosition(diagnosticOrigin.start);
|
|
2322
|
+
const { character: lastMarkedCharacter, line: lastMarkedLine } = diagnosticOrigin.sourceFile.getLineAndCharacterOfPosition(diagnosticOrigin.end);
|
|
2260
2323
|
const firstLine = Math.max(firstMarkedLine - linesAbove, 0);
|
|
2261
2324
|
const lastLine = Math.min(lastMarkedLine + linesBelow, lineMap.length - 1);
|
|
2262
2325
|
const gutterWidth = (lastLine + 1).toString().length + 2;
|
|
@@ -2278,12 +2341,12 @@ function CodeFrameText({ diagnosticCategory, diagnosticOrigin, options }) {
|
|
|
2278
2341
|
codeFrame.push(jsx(CodeLineText, { gutterWidth: gutterWidth, lineNumber: index + 1, lineNumberColor: highlightColor, lineText: lineText }));
|
|
2279
2342
|
if (index === firstMarkedLine) {
|
|
2280
2343
|
const squiggleLength = index === lastMarkedLine
|
|
2281
|
-
?
|
|
2282
|
-
: lineText.length -
|
|
2283
|
-
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 }));
|
|
2284
2347
|
}
|
|
2285
2348
|
else if (index === lastMarkedLine) {
|
|
2286
|
-
codeFrame.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, squiggleColor: highlightColor, squiggleWidth:
|
|
2349
|
+
codeFrame.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, squiggleColor: highlightColor, squiggleWidth: lastMarkedCharacter }));
|
|
2287
2350
|
}
|
|
2288
2351
|
else {
|
|
2289
2352
|
codeFrame.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, squiggleColor: highlightColor, squiggleWidth: lineText.length }));
|
|
@@ -2297,7 +2360,7 @@ function CodeFrameText({ diagnosticCategory, diagnosticOrigin, options }) {
|
|
|
2297
2360
|
if (showBreadcrumbs && diagnosticOrigin.assertionNode != null) {
|
|
2298
2361
|
breadcrumbs = jsx(BreadcrumbsText, { ancestor: diagnosticOrigin.assertionNode.parent });
|
|
2299
2362
|
}
|
|
2300
|
-
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] }));
|
|
2301
2364
|
return (jsx(Text, { children: [codeFrame, jsx(Line, {}), location] }));
|
|
2302
2365
|
}
|
|
2303
2366
|
|
|
@@ -3160,7 +3223,7 @@ class Select {
|
|
|
3160
3223
|
if (testFilePaths.length === 0) {
|
|
3161
3224
|
Select.#onDiagnostics(Diagnostic.error(SelectDiagnosticText.noTestFilesWereSelected(resolvedConfig)));
|
|
3162
3225
|
}
|
|
3163
|
-
return testFilePaths.sort();
|
|
3226
|
+
return testFilePaths.sort((a, b) => a.localeCompare(b));
|
|
3164
3227
|
}
|
|
3165
3228
|
static async #visitDirectory(currentPath, testFilePaths, matchPatterns, resolvedConfig) {
|
|
3166
3229
|
const targetPath = Path.join(resolvedConfig.rootPath, currentPath);
|
|
@@ -3290,7 +3353,7 @@ class WatchService {
|
|
|
3290
3353
|
while (!cancellationToken.isCancellationRequested()) {
|
|
3291
3354
|
const testFiles = await debounce.schedule();
|
|
3292
3355
|
if (testFiles.length > 0) {
|
|
3293
|
-
yield testFiles;
|
|
3356
|
+
yield testFiles.sort((a, b) => a.path.localeCompare(b.path));
|
|
3294
3357
|
}
|
|
3295
3358
|
}
|
|
3296
3359
|
}
|
|
@@ -3335,11 +3398,10 @@ class AbilityLayer {
|
|
|
3335
3398
|
this.#editor = editor;
|
|
3336
3399
|
}
|
|
3337
3400
|
#belongsToNode(node, diagnostic) {
|
|
3338
|
-
return
|
|
3339
|
-
diagnosticBelongsToNode(diagnostic, node.source));
|
|
3401
|
+
return diagnosticBelongsToNode(diagnostic, node.matcherNode) || diagnosticBelongsToNode(diagnostic, node.source);
|
|
3340
3402
|
}
|
|
3341
3403
|
close(diagnostics) {
|
|
3342
|
-
if (diagnostics
|
|
3404
|
+
if (diagnostics.length > 0 && this.#nodes.length > 0) {
|
|
3343
3405
|
this.#nodes.reverse();
|
|
3344
3406
|
for (const diagnostic of diagnostics) {
|
|
3345
3407
|
this.#mapToNodes(diagnostic);
|
|
@@ -3362,12 +3424,56 @@ class AbilityLayer {
|
|
|
3362
3424
|
const matcherNameEnd = expect.matcherNameNode.getEnd();
|
|
3363
3425
|
const matcherNodeEnd = expect.matcherNode.getEnd();
|
|
3364
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
|
+
}
|
|
3365
3474
|
case "toBeApplicable":
|
|
3366
3475
|
this.#nodes.push(expect);
|
|
3367
|
-
this.#editor.
|
|
3368
|
-
[expectStart, expectExpressionEnd],
|
|
3369
|
-
[expectEnd, matcherNameEnd],
|
|
3370
|
-
]);
|
|
3476
|
+
this.#editor.erase(expectStart, expectExpressionEnd).erase(expectEnd, matcherNameEnd);
|
|
3371
3477
|
break;
|
|
3372
3478
|
case "toBeCallableWith": {
|
|
3373
3479
|
this.#nodes.push(expect);
|
|
@@ -3376,27 +3482,16 @@ class AbilityLayer {
|
|
|
3376
3482
|
return;
|
|
3377
3483
|
}
|
|
3378
3484
|
if (nodeBelongsToArgumentList(this.#compiler, sourceNode)) {
|
|
3379
|
-
this.#editor
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
expectExpressionEnd,
|
|
3384
|
-
nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? ";" : "",
|
|
3385
|
-
],
|
|
3386
|
-
[expectEnd, matcherNameEnd],
|
|
3387
|
-
]);
|
|
3485
|
+
this.#editor
|
|
3486
|
+
.eraseTrailingComma(expect.source)
|
|
3487
|
+
.update(expectStart, expectExpressionEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? ";" : "")
|
|
3488
|
+
.erase(expectEnd, matcherNameEnd);
|
|
3388
3489
|
}
|
|
3389
3490
|
else {
|
|
3390
3491
|
const sourceText = sourceNode.getFullText();
|
|
3391
|
-
this.#editor.
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
matcherNameEnd,
|
|
3395
|
-
nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode)
|
|
3396
|
-
? `;(undefined as any as ${sourceText})`
|
|
3397
|
-
: `(undefined as any as ${sourceText})`,
|
|
3398
|
-
],
|
|
3399
|
-
]);
|
|
3492
|
+
this.#editor.update(expectStart, matcherNameEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode)
|
|
3493
|
+
? `;(undefined as any as ${sourceText})`
|
|
3494
|
+
: `(undefined as any as ${sourceText})`);
|
|
3400
3495
|
}
|
|
3401
3496
|
break;
|
|
3402
3497
|
}
|
|
@@ -3407,27 +3502,16 @@ class AbilityLayer {
|
|
|
3407
3502
|
return;
|
|
3408
3503
|
}
|
|
3409
3504
|
if (nodeBelongsToArgumentList(this.#compiler, sourceNode)) {
|
|
3410
|
-
this.#editor
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
expectExpressionEnd,
|
|
3415
|
-
nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? "; new" : "new",
|
|
3416
|
-
],
|
|
3417
|
-
[expectEnd, matcherNameEnd],
|
|
3418
|
-
]);
|
|
3505
|
+
this.#editor
|
|
3506
|
+
.eraseTrailingComma(expect.source)
|
|
3507
|
+
.update(expectStart, expectExpressionEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? "; new" : "new")
|
|
3508
|
+
.erase(expectEnd, matcherNameEnd);
|
|
3419
3509
|
}
|
|
3420
3510
|
else {
|
|
3421
3511
|
const sourceText = sourceNode.getFullText();
|
|
3422
|
-
this.#editor.
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
matcherNameEnd,
|
|
3426
|
-
nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode)
|
|
3427
|
-
? `;new (undefined as any as ${sourceText})`
|
|
3428
|
-
: `new (undefined as any as ${sourceText})`,
|
|
3429
|
-
],
|
|
3430
|
-
]);
|
|
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})`);
|
|
3431
3515
|
}
|
|
3432
3516
|
break;
|
|
3433
3517
|
}
|
|
@@ -3439,39 +3523,26 @@ class AbilityLayer {
|
|
|
3439
3523
|
return;
|
|
3440
3524
|
}
|
|
3441
3525
|
if (nodeBelongsToArgumentList(this.#compiler, sourceNode)) {
|
|
3442
|
-
this.#editor
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
expectExpressionEnd,
|
|
3447
|
-
nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? ";" : "",
|
|
3448
|
-
],
|
|
3449
|
-
[expectEnd, matcherNodeEnd],
|
|
3450
|
-
]);
|
|
3526
|
+
this.#editor
|
|
3527
|
+
.eraseTrailingComma(expect.source)
|
|
3528
|
+
.update(expectStart, expectExpressionEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? ";" : "")
|
|
3529
|
+
.erase(expectEnd, matcherNodeEnd);
|
|
3451
3530
|
if (this.#compiler.isExpressionWithTypeArguments(sourceNode)) {
|
|
3452
|
-
this.#editor.
|
|
3531
|
+
this.#editor.erase(sourceNode.expression.getEnd(), sourceNode.getEnd());
|
|
3453
3532
|
}
|
|
3454
3533
|
}
|
|
3455
3534
|
else {
|
|
3456
3535
|
const sourceText = this.#compiler.isTypeReferenceNode(sourceNode)
|
|
3457
|
-
? sourceNode.typeName.
|
|
3458
|
-
: sourceNode.
|
|
3459
|
-
this.#editor.
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
matcherNodeEnd,
|
|
3463
|
-
nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode)
|
|
3464
|
-
? `;undefined as any as ${sourceText}`
|
|
3465
|
-
: `undefined as any as ${sourceText}`,
|
|
3466
|
-
],
|
|
3467
|
-
]);
|
|
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}`);
|
|
3468
3541
|
}
|
|
3469
3542
|
if (targetNode != null) {
|
|
3470
3543
|
const targetText = targetNode.getText().slice(1, -1);
|
|
3471
|
-
if (targetText.trim().length >
|
|
3472
|
-
this.#editor.
|
|
3473
|
-
[targetNode.getFullStart(), targetNode.getEnd(), `<${targetText}>`.padStart(targetNode.getFullWidth())],
|
|
3474
|
-
]);
|
|
3544
|
+
if (targetText.trim().length > 0) {
|
|
3545
|
+
this.#editor.update(targetNode.getFullStart(), targetNode.getEnd(), `<${targetText}>`.padStart(targetNode.getFullWidth()));
|
|
3475
3546
|
}
|
|
3476
3547
|
}
|
|
3477
3548
|
break;
|
|
@@ -3483,30 +3554,21 @@ class AbilityLayer {
|
|
|
3483
3554
|
if (!sourceNode || !targetNode) {
|
|
3484
3555
|
return;
|
|
3485
3556
|
}
|
|
3486
|
-
const sourceText = sourceNode.getFullText();
|
|
3487
|
-
const targetText = targetNode.getFullText();
|
|
3488
3557
|
if (nodeBelongsToArgumentList(this.#compiler, sourceNode)) {
|
|
3489
|
-
this.#editor
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
matcherNodeEnd,
|
|
3494
|
-
nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode)
|
|
3495
|
-
? `;(${sourceText})[${targetText}]`
|
|
3496
|
-
: `(${sourceText})[${targetText}]`,
|
|
3497
|
-
],
|
|
3498
|
-
]);
|
|
3558
|
+
this.#editor
|
|
3559
|
+
.eraseTrailingComma(expect.source)
|
|
3560
|
+
.update(expectStart, expectExpressionEnd, nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? ";" : "")
|
|
3561
|
+
.erase(expectEnd, matcherNodeEnd);
|
|
3499
3562
|
}
|
|
3500
3563
|
else {
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
]);
|
|
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()));
|
|
3510
3572
|
}
|
|
3511
3573
|
break;
|
|
3512
3574
|
}
|
|
@@ -3514,65 +3576,6 @@ class AbilityLayer {
|
|
|
3514
3576
|
}
|
|
3515
3577
|
}
|
|
3516
3578
|
|
|
3517
|
-
class SourceTextEditor {
|
|
3518
|
-
#filePath = "";
|
|
3519
|
-
#sourceFile;
|
|
3520
|
-
#text = "";
|
|
3521
|
-
open(sourceFile) {
|
|
3522
|
-
this.#sourceFile = sourceFile;
|
|
3523
|
-
this.#filePath = sourceFile.fileName;
|
|
3524
|
-
this.#text = sourceFile.text;
|
|
3525
|
-
}
|
|
3526
|
-
close() {
|
|
3527
|
-
if (this.#sourceFile != null) {
|
|
3528
|
-
SourceService.set(this.#sourceFile);
|
|
3529
|
-
this.#sourceFile = undefined;
|
|
3530
|
-
}
|
|
3531
|
-
this.#filePath = "";
|
|
3532
|
-
this.#text = "";
|
|
3533
|
-
}
|
|
3534
|
-
eraseTrailingComma(node) {
|
|
3535
|
-
if (node.hasTrailingComma) {
|
|
3536
|
-
this.replaceRange(node.end - 1, node.end);
|
|
3537
|
-
}
|
|
3538
|
-
}
|
|
3539
|
-
#getErasedRange(start, end) {
|
|
3540
|
-
if (this.#text.indexOf("\n", start) >= end) {
|
|
3541
|
-
return " ".repeat(end - start);
|
|
3542
|
-
}
|
|
3543
|
-
const text = [];
|
|
3544
|
-
for (let index = start; index < end; index++) {
|
|
3545
|
-
const character = this.#text.charAt(index);
|
|
3546
|
-
switch (character) {
|
|
3547
|
-
case "\n":
|
|
3548
|
-
case "\r":
|
|
3549
|
-
text.push(character);
|
|
3550
|
-
break;
|
|
3551
|
-
default:
|
|
3552
|
-
text.push(" ");
|
|
3553
|
-
}
|
|
3554
|
-
}
|
|
3555
|
-
return text.join("");
|
|
3556
|
-
}
|
|
3557
|
-
getFilePath() {
|
|
3558
|
-
return this.#filePath;
|
|
3559
|
-
}
|
|
3560
|
-
getText() {
|
|
3561
|
-
return this.#text;
|
|
3562
|
-
}
|
|
3563
|
-
replaceRange(start, end, replacement) {
|
|
3564
|
-
const rangeText = replacement != null
|
|
3565
|
-
? `${replacement}${this.#getErasedRange(start, end).slice(replacement.length)}`
|
|
3566
|
-
: this.#getErasedRange(start, end);
|
|
3567
|
-
this.#text = `${this.#text.slice(0, start)}${rangeText}${this.#text.slice(end)}`;
|
|
3568
|
-
}
|
|
3569
|
-
replaceRanges(ranges) {
|
|
3570
|
-
for (const [start, end, replacement] of ranges) {
|
|
3571
|
-
this.replaceRange(start, end, replacement);
|
|
3572
|
-
}
|
|
3573
|
-
}
|
|
3574
|
-
}
|
|
3575
|
-
|
|
3576
3579
|
class SuppressedLayer {
|
|
3577
3580
|
#compiler;
|
|
3578
3581
|
#editor;
|
|
@@ -3645,7 +3648,7 @@ class SuppressedLayer {
|
|
|
3645
3648
|
}
|
|
3646
3649
|
for (const suppressedError of suppressedErrors) {
|
|
3647
3650
|
const { start, end } = suppressedError.directive;
|
|
3648
|
-
this.#editor.
|
|
3651
|
+
this.#editor.erase(start, end);
|
|
3649
3652
|
if (this.#suppressedErrorsMap != null) {
|
|
3650
3653
|
const { line } = tree.sourceFile.getLineAndCharacterOfPosition(start);
|
|
3651
3654
|
this.#suppressedErrorsMap.set(line, suppressedError);
|
|
@@ -3654,9 +3657,84 @@ class SuppressedLayer {
|
|
|
3654
3657
|
}
|
|
3655
3658
|
}
|
|
3656
3659
|
|
|
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 = [];
|
|
3670
|
+
}
|
|
3671
|
+
close() {
|
|
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;
|
|
3683
|
+
}
|
|
3684
|
+
eraseTrailingComma(node) {
|
|
3685
|
+
if (node.hasTrailingComma) {
|
|
3686
|
+
this.erase(node.end - 1, node.end);
|
|
3687
|
+
}
|
|
3688
|
+
return this;
|
|
3689
|
+
}
|
|
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
|
+
|
|
3657
3735
|
class Layers {
|
|
3658
3736
|
#abilityLayer;
|
|
3659
|
-
#editor = new
|
|
3737
|
+
#editor = new TextEditor();
|
|
3660
3738
|
#projectService;
|
|
3661
3739
|
#suppressedDiagnostics;
|
|
3662
3740
|
#suppressedLayer;
|
|
@@ -3665,14 +3743,23 @@ class Layers {
|
|
|
3665
3743
|
this.#abilityLayer = new AbilityLayer(compiler, this.#editor);
|
|
3666
3744
|
this.#suppressedLayer = new SuppressedLayer(compiler, this.#editor, resolvedConfig);
|
|
3667
3745
|
}
|
|
3668
|
-
close() {
|
|
3669
|
-
let
|
|
3746
|
+
close(tree) {
|
|
3747
|
+
let seenDiagnostics = [];
|
|
3670
3748
|
if (this.#suppressedDiagnostics != null) {
|
|
3671
|
-
|
|
3749
|
+
seenDiagnostics = this.#suppressedDiagnostics;
|
|
3672
3750
|
this.#suppressedDiagnostics = undefined;
|
|
3673
|
-
isSeenDiagnostic = (diagnostic) => !seenDiagnostics.some((seenDiagnostic) => compareDiagnostics(diagnostic, seenDiagnostic));
|
|
3674
3751
|
}
|
|
3675
|
-
const
|
|
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
|
+
}
|
|
3676
3763
|
this.#abilityLayer.close(abilityDiagnostics);
|
|
3677
3764
|
this.#editor.close();
|
|
3678
3765
|
}
|
|
@@ -3680,7 +3767,7 @@ class Layers {
|
|
|
3680
3767
|
this.#editor.open(tree.sourceFile);
|
|
3681
3768
|
this.#suppressedLayer.open(tree);
|
|
3682
3769
|
this.#suppressedDiagnostics = this.#projectService.getDiagnostics(this.#editor.getFilePath(), this.#editor.getText());
|
|
3683
|
-
this.#suppressedLayer.close(this.#suppressedDiagnostics);
|
|
3770
|
+
this.#suppressedLayer.close(this.#suppressedDiagnostics?.map((diagnostic) => new MappedDiagnostic(tree.sourceFile, diagnostic)));
|
|
3684
3771
|
}
|
|
3685
3772
|
visit(node) {
|
|
3686
3773
|
this.#abilityLayer.visitExpect(node);
|
|
@@ -3927,7 +4014,7 @@ class CollectService {
|
|
|
3927
4014
|
this.#layers.open(testTree);
|
|
3928
4015
|
this.#identifierLookup.open();
|
|
3929
4016
|
this.#collectTestTreeNodes(sourceFile, testTree, testTree);
|
|
3930
|
-
this.#layers.close();
|
|
4017
|
+
this.#layers.close(testTree);
|
|
3931
4018
|
EventEmitter.dispatch(["collect:end", { tree: testTree }]);
|
|
3932
4019
|
return testTree;
|
|
3933
4020
|
}
|
|
@@ -4061,7 +4148,6 @@ class ProjectService {
|
|
|
4061
4148
|
}
|
|
4062
4149
|
closeFile(filePath) {
|
|
4063
4150
|
this.#service.closeClientFile(filePath);
|
|
4064
|
-
SourceService.delete(filePath);
|
|
4065
4151
|
}
|
|
4066
4152
|
#getDefaultCompilerOptions() {
|
|
4067
4153
|
const defaultCompilerOptions = {
|
|
@@ -4091,14 +4177,10 @@ class ProjectService {
|
|
|
4091
4177
|
}
|
|
4092
4178
|
return project;
|
|
4093
4179
|
}
|
|
4094
|
-
getDiagnostics(filePath, sourceText
|
|
4180
|
+
getDiagnostics(filePath, sourceText) {
|
|
4095
4181
|
this.openFile(filePath, sourceText);
|
|
4096
4182
|
const languageService = this.getLanguageService(filePath);
|
|
4097
|
-
|
|
4098
|
-
if (diagnostics != null && shouldInclude != null) {
|
|
4099
|
-
return diagnostics.filter(shouldInclude);
|
|
4100
|
-
}
|
|
4101
|
-
return diagnostics;
|
|
4183
|
+
return languageService?.getSemanticDiagnostics(filePath);
|
|
4102
4184
|
}
|
|
4103
4185
|
getLanguageService(filePath) {
|
|
4104
4186
|
const project = this.getDefaultProject(filePath);
|
|
@@ -4263,51 +4345,102 @@ class SuppressedService {
|
|
|
4263
4345
|
}
|
|
4264
4346
|
}
|
|
4265
4347
|
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
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.`;
|
|
4269
4355
|
}
|
|
4270
|
-
static
|
|
4271
|
-
return `
|
|
4356
|
+
static typeArgumentCannotBeOfType(typeText) {
|
|
4357
|
+
return `The type argument cannot be of the '${typeText}' type.`;
|
|
4272
4358
|
}
|
|
4273
|
-
static
|
|
4274
|
-
|
|
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
|
+
];
|
|
4275
4365
|
}
|
|
4276
4366
|
}
|
|
4277
4367
|
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
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
|
+
}
|
|
4284
4381
|
}
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
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
|
+
}
|
|
4293
4405
|
return false;
|
|
4294
4406
|
}
|
|
4295
|
-
return true;
|
|
4296
4407
|
}
|
|
4297
4408
|
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
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) {
|
|
4301
4436
|
const origin = DiagnosticOrigin.fromNode(enclosingNode);
|
|
4302
4437
|
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
4303
|
-
return false;
|
|
4304
4438
|
}
|
|
4305
|
-
return true;
|
|
4306
4439
|
}
|
|
4307
4440
|
|
|
4308
4441
|
class ExpectDiagnosticText {
|
|
4309
|
-
static argumentMustBe(
|
|
4310
|
-
return `
|
|
4442
|
+
static argumentMustBe(expectedText) {
|
|
4443
|
+
return `The argument must be ${expectedText}.`;
|
|
4311
4444
|
}
|
|
4312
4445
|
static typeArgumentMustBe(expectedText) {
|
|
4313
4446
|
return `The type argument must be ${expectedText}.`;
|
|
@@ -4331,10 +4464,10 @@ class ExpectDiagnosticText {
|
|
|
4331
4464
|
return `${isExpression ? "Expression" : "Type"} is not instantiable ${targetText}.`;
|
|
4332
4465
|
}
|
|
4333
4466
|
static acceptsProps(isExpression) {
|
|
4334
|
-
return `${isExpression ? "Component" : "
|
|
4467
|
+
return `${isExpression ? "Component" : "Type"} accepts props of the given type.`;
|
|
4335
4468
|
}
|
|
4336
4469
|
static doesNotAcceptProps(isExpression) {
|
|
4337
|
-
return `${isExpression ? "Component" : "
|
|
4470
|
+
return `${isExpression ? "Component" : "Type"} does not accept props of the given type.`;
|
|
4338
4471
|
}
|
|
4339
4472
|
static canBeApplied(targetText) {
|
|
4340
4473
|
return `The decorator function can be applied${targetText}.`;
|
|
@@ -4354,9 +4487,6 @@ class ExpectDiagnosticText {
|
|
|
4354
4487
|
static matcherIsNotSupported(matcherNameText) {
|
|
4355
4488
|
return `The '.${matcherNameText}()' matcher is not supported.`;
|
|
4356
4489
|
}
|
|
4357
|
-
static overloadGaveTheFollowingError(index, count, signatureText) {
|
|
4358
|
-
return `Overload ${index} of ${count}, '${signatureText}', gave the following error.`;
|
|
4359
|
-
}
|
|
4360
4490
|
static raisedTypeError(count = 1) {
|
|
4361
4491
|
return `The raised type error${count === 1 ? "" : "s"}:`;
|
|
4362
4492
|
}
|
|
@@ -4394,15 +4524,6 @@ class ExpectDiagnosticText {
|
|
|
4394
4524
|
static isNotTheSame(sourceTypeText, targetTypeText) {
|
|
4395
4525
|
return `Type '${sourceTypeText}' is not the same as type '${targetTypeText}'.`;
|
|
4396
4526
|
}
|
|
4397
|
-
static isNotCompatibleWith(sourceTypeText, targetTypeText) {
|
|
4398
|
-
return `Type '${sourceTypeText}' is not compatible with type '${targetTypeText}'.`;
|
|
4399
|
-
}
|
|
4400
|
-
static requiresProperty(typeText, propertyNameText) {
|
|
4401
|
-
return `Type '${typeText}' requires property '${propertyNameText}'.`;
|
|
4402
|
-
}
|
|
4403
|
-
static typesOfPropertyAreNotCompatible(propertyNameText) {
|
|
4404
|
-
return `Types of property '${propertyNameText}' are not compatible.`;
|
|
4405
|
-
}
|
|
4406
4527
|
}
|
|
4407
4528
|
|
|
4408
4529
|
class MatchWorker {
|
|
@@ -4432,13 +4553,6 @@ class MatchWorker {
|
|
|
4432
4553
|
: { flags: this.#compiler.TypeFlags.NonPrimitive };
|
|
4433
4554
|
return this.typeChecker.isTypeAssignableTo(type, nonPrimitiveType);
|
|
4434
4555
|
}
|
|
4435
|
-
getParameterType(signature, index) {
|
|
4436
|
-
const parameter = signature.getDeclaration().parameters[index];
|
|
4437
|
-
if (!parameter) {
|
|
4438
|
-
return;
|
|
4439
|
-
}
|
|
4440
|
-
return this.getType(parameter);
|
|
4441
|
-
}
|
|
4442
4556
|
getSignatures(node) {
|
|
4443
4557
|
let signatures = this.#signatureCache.get(node);
|
|
4444
4558
|
if (!signatures) {
|
|
@@ -4456,195 +4570,100 @@ class MatchWorker {
|
|
|
4456
4570
|
getType(node) {
|
|
4457
4571
|
return this.typeChecker.getTypeAtLocation(node);
|
|
4458
4572
|
}
|
|
4459
|
-
resolveDiagnosticOrigin(symbol, enclosingNode) {
|
|
4460
|
-
if (symbol.valueDeclaration != null &&
|
|
4461
|
-
(this.#compiler.isPropertySignature(symbol.valueDeclaration) ||
|
|
4462
|
-
this.#compiler.isPropertyAssignment(symbol.valueDeclaration) ||
|
|
4463
|
-
this.#compiler.isShorthandPropertyAssignment(symbol.valueDeclaration)) &&
|
|
4464
|
-
symbol.valueDeclaration.getStart() >= enclosingNode.getStart() &&
|
|
4465
|
-
symbol.valueDeclaration.getEnd() <= enclosingNode.getEnd()) {
|
|
4466
|
-
return DiagnosticOrigin.fromNode(symbol.valueDeclaration.name, this.assertionNode);
|
|
4467
|
-
}
|
|
4468
|
-
return DiagnosticOrigin.fromNode(enclosingNode, this.assertionNode);
|
|
4469
|
-
}
|
|
4470
|
-
}
|
|
4471
|
-
|
|
4472
|
-
function isStringOrNumberLiteralType(compiler, type) {
|
|
4473
|
-
return !!(type.flags & compiler.TypeFlags.StringOrNumberLiteral);
|
|
4474
|
-
}
|
|
4475
|
-
function isUnionType(compiler, type) {
|
|
4476
|
-
return !!(type.flags & compiler.TypeFlags.Union);
|
|
4477
|
-
}
|
|
4478
|
-
function isUniqueSymbolType(compiler, type) {
|
|
4479
|
-
return !!(type.flags & compiler.TypeFlags.UniqueESSymbol);
|
|
4480
4573
|
}
|
|
4481
4574
|
|
|
4482
|
-
class
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
this.#compiler = compiler;
|
|
4487
|
-
this.#typeChecker = program.getTypeChecker();
|
|
4488
|
-
}
|
|
4489
|
-
#explain(matchWorker, sourceNode, targetNode) {
|
|
4490
|
-
const isExpression = nodeBelongsToArgumentList(this.#compiler, sourceNode);
|
|
4491
|
-
const signatures = matchWorker.getSignatures(sourceNode);
|
|
4492
|
-
return signatures.reduce((accumulator, signature, index) => {
|
|
4493
|
-
let diagnostic;
|
|
4494
|
-
const introText = matchWorker.assertionNode.isNot
|
|
4495
|
-
? ExpectDiagnosticText.acceptsProps(isExpression)
|
|
4496
|
-
: ExpectDiagnosticText.doesNotAcceptProps(isExpression);
|
|
4497
|
-
const origin = DiagnosticOrigin.fromNode(targetNode, matchWorker.assertionNode);
|
|
4498
|
-
if (signatures.length > 1) {
|
|
4499
|
-
const signatureText = this.#typeChecker.signatureToString(signature, sourceNode);
|
|
4500
|
-
const overloadText = ExpectDiagnosticText.overloadGaveTheFollowingError(index + 1, signatures.length, signatureText);
|
|
4501
|
-
diagnostic = Diagnostic.error([introText, overloadText], origin);
|
|
4502
|
-
}
|
|
4503
|
-
else {
|
|
4504
|
-
diagnostic = Diagnostic.error([introText], origin);
|
|
4505
|
-
}
|
|
4506
|
-
const { diagnostics, isMatch } = this.#explainProperties(matchWorker, signature, targetNode, diagnostic);
|
|
4507
|
-
if (matchWorker.assertionNode.isNot ? isMatch : !isMatch) {
|
|
4508
|
-
accumulator.push(...diagnostics);
|
|
4509
|
-
}
|
|
4510
|
-
return accumulator;
|
|
4511
|
-
}, []);
|
|
4575
|
+
class AbilityMatcherBase {
|
|
4576
|
+
compiler;
|
|
4577
|
+
constructor(compiler) {
|
|
4578
|
+
this.compiler = compiler;
|
|
4512
4579
|
}
|
|
4513
|
-
|
|
4514
|
-
|
|
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"}`;
|
|
4515
4588
|
}
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
const targetPropertyName = targetProperty.getName();
|
|
4520
|
-
const sourceProperty = sourceType?.getProperty(targetPropertyName);
|
|
4521
|
-
if (!sourceProperty) {
|
|
4522
|
-
return false;
|
|
4523
|
-
}
|
|
4524
|
-
const targetPropertyType = this.#typeChecker.getTypeOfSymbol(targetProperty);
|
|
4525
|
-
const sourcePropertyType = this.#typeChecker.getTypeOfSymbol(sourceProperty);
|
|
4526
|
-
if (!this.#typeChecker.isTypeAssignableTo(targetPropertyType, sourcePropertyType)) {
|
|
4527
|
-
return false;
|
|
4528
|
-
}
|
|
4529
|
-
}
|
|
4530
|
-
if (sourceType != null) {
|
|
4531
|
-
const sourceProperties = sourceType.getProperties();
|
|
4532
|
-
for (const sourceProperty of sourceProperties) {
|
|
4533
|
-
const targetProperty = targetType.getProperty(sourceProperty.getName());
|
|
4534
|
-
if (!targetProperty && !this.#isOptionalProperty(sourceProperty)) {
|
|
4535
|
-
return false;
|
|
4536
|
-
}
|
|
4537
|
-
}
|
|
4538
|
-
}
|
|
4539
|
-
return true;
|
|
4540
|
-
};
|
|
4541
|
-
if (sourceType != null && isUnionType(this.#compiler, sourceType)) {
|
|
4542
|
-
return sourceType.types.some((sourceType) => check(sourceType, targetType));
|
|
4589
|
+
getTypeArgumentCountText(targetNode) {
|
|
4590
|
+
if (targetNode.elements.length === 0) {
|
|
4591
|
+
return "without type arguments";
|
|
4543
4592
|
}
|
|
4544
|
-
return
|
|
4593
|
+
return `with the given type argument${targetNode.elements.length === 1 ? "" : "s"}`;
|
|
4545
4594
|
}
|
|
4546
|
-
|
|
4547
|
-
const
|
|
4548
|
-
const
|
|
4549
|
-
const
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
const sourceProperty = sourceType?.getProperty(targetPropertyName);
|
|
4557
|
-
if (!sourceProperty) {
|
|
4558
|
-
const text = [
|
|
4559
|
-
ExpectDiagnosticText.isNotCompatibleWith(sourceTypeText, targetTypeText),
|
|
4560
|
-
ExpectDiagnosticText.doesNotHaveProperty(sourceTypeText, targetPropertyName),
|
|
4561
|
-
];
|
|
4562
|
-
const origin = matchWorker.resolveDiagnosticOrigin(targetProperty, targetNode);
|
|
4563
|
-
diagnostics.push(diagnostic.extendWith(text, origin));
|
|
4564
|
-
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);
|
|
4565
4605
|
}
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
if (!this.#typeChecker.isTypeAssignableTo(targetPropertyType, sourcePropertyType)) {
|
|
4569
|
-
const targetPropertyTypeText = this.#typeChecker.typeToString(targetPropertyType);
|
|
4570
|
-
const sourcePropertyTypeText = this.#typeChecker.typeToString(sourcePropertyType);
|
|
4571
|
-
const text = [
|
|
4572
|
-
ExpectDiagnosticText.isNotAssignableFrom(sourceTypeText, targetTypeText),
|
|
4573
|
-
ExpectDiagnosticText.typesOfPropertyAreNotCompatible(targetPropertyName),
|
|
4574
|
-
ExpectDiagnosticText.isNotAssignableFrom(sourcePropertyTypeText, targetPropertyTypeText),
|
|
4575
|
-
];
|
|
4576
|
-
const origin = matchWorker.resolveDiagnosticOrigin(targetProperty, targetNode);
|
|
4577
|
-
diagnostics.push(diagnostic.extendWith(text, origin));
|
|
4606
|
+
else {
|
|
4607
|
+
origin = DiagnosticOrigin.fromAssertion(matchWorker.assertionNode);
|
|
4578
4608
|
}
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
const sourcePropertyName = sourceProperty.getName();
|
|
4583
|
-
const targetProperty = targetType.getProperty(sourcePropertyName);
|
|
4584
|
-
if (!targetProperty && !this.#isOptionalProperty(sourceProperty)) {
|
|
4585
|
-
const text = [
|
|
4586
|
-
ExpectDiagnosticText.isNotAssignableFrom(sourceTypeText, targetTypeText),
|
|
4587
|
-
ExpectDiagnosticText.requiresProperty(sourceTypeText, sourcePropertyName),
|
|
4588
|
-
];
|
|
4589
|
-
diagnostics.push(diagnostic.extendWith(text));
|
|
4590
|
-
}
|
|
4609
|
+
let related;
|
|
4610
|
+
if (diagnostic.relatedInformation != null) {
|
|
4611
|
+
related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
|
|
4591
4612
|
}
|
|
4613
|
+
diagnostics.push(Diagnostic.error(text.flat(), origin).add({ related }));
|
|
4592
4614
|
}
|
|
4593
|
-
if (diagnostics.length === 0) {
|
|
4594
|
-
const text = ExpectDiagnosticText.isAssignableFrom(sourceTypeText, targetTypeText);
|
|
4595
|
-
diagnostics.push(diagnostic.extendWith(text));
|
|
4596
|
-
return { diagnostics, isMatch: true };
|
|
4597
|
-
}
|
|
4598
|
-
return { diagnostics, isMatch: false };
|
|
4599
|
-
};
|
|
4600
|
-
if (sourceType != null && isUnionType(this.#compiler, sourceType)) {
|
|
4601
|
-
let accumulator = [];
|
|
4602
|
-
const isMatch = sourceType.types.some((sourceType) => {
|
|
4603
|
-
const text = matchWorker.assertionNode.isNot
|
|
4604
|
-
? ExpectDiagnosticText.isAssignableFrom(sourceTypeText, targetTypeText)
|
|
4605
|
-
: ExpectDiagnosticText.isNotAssignableFrom(sourceTypeText, targetTypeText);
|
|
4606
|
-
const { diagnostics, isMatch } = explain(sourceType, targetType, diagnostic.extendWith(text));
|
|
4607
|
-
if (isMatch) {
|
|
4608
|
-
accumulator = diagnostics;
|
|
4609
|
-
}
|
|
4610
|
-
else {
|
|
4611
|
-
accumulator.push(...diagnostics);
|
|
4612
|
-
}
|
|
4613
|
-
return isMatch;
|
|
4614
|
-
});
|
|
4615
|
-
return { diagnostics: accumulator, isMatch };
|
|
4616
4615
|
}
|
|
4617
|
-
|
|
4616
|
+
else {
|
|
4617
|
+
const origin = DiagnosticOrigin.fromAssertion(matchWorker.assertionNode);
|
|
4618
|
+
diagnostics.push(Diagnostic.error(this.explainText(isExpression, argumentCountText), origin));
|
|
4619
|
+
}
|
|
4620
|
+
return diagnostics;
|
|
4618
4621
|
}
|
|
4622
|
+
}
|
|
4623
|
+
|
|
4624
|
+
class ToAcceptProps extends AbilityMatcherBase {
|
|
4625
|
+
explainText = ExpectDiagnosticText.acceptsProps;
|
|
4626
|
+
explainNotText = ExpectDiagnosticText.doesNotAcceptProps;
|
|
4619
4627
|
match(matchWorker, sourceNode, targetNode, onDiagnostics) {
|
|
4620
4628
|
const diagnostics = [];
|
|
4621
4629
|
const signatures = matchWorker.getSignatures(sourceNode);
|
|
4622
4630
|
if (signatures.length === 0) {
|
|
4623
4631
|
const expectedText = "of a function or class type";
|
|
4624
|
-
const text = nodeBelongsToArgumentList(this
|
|
4625
|
-
? ExpectDiagnosticText.argumentMustBe(
|
|
4632
|
+
const text = nodeBelongsToArgumentList(this.compiler, sourceNode)
|
|
4633
|
+
? ExpectDiagnosticText.argumentMustBe(expectedText)
|
|
4626
4634
|
: ExpectDiagnosticText.typeArgumentMustBe(expectedText);
|
|
4627
4635
|
const origin = DiagnosticOrigin.fromNode(sourceNode);
|
|
4628
4636
|
diagnostics.push(Diagnostic.error(text, origin));
|
|
4629
4637
|
}
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
const
|
|
4633
|
-
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);
|
|
4634
4641
|
const origin = DiagnosticOrigin.fromNode(targetNode);
|
|
4635
4642
|
diagnostics.push(Diagnostic.error(text, origin));
|
|
4636
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
|
+
}
|
|
4637
4660
|
if (diagnostics.length > 0) {
|
|
4638
4661
|
onDiagnostics(diagnostics);
|
|
4639
4662
|
return;
|
|
4640
4663
|
}
|
|
4641
|
-
const isMatch = signatures.some((signature) => {
|
|
4642
|
-
const sourceType = matchWorker.getParameterType(signature, 0);
|
|
4643
|
-
return this.#checkProperties(sourceType, targetType);
|
|
4644
|
-
});
|
|
4645
4664
|
return {
|
|
4646
|
-
explain: () => this
|
|
4647
|
-
isMatch,
|
|
4665
|
+
explain: () => this.explain(matchWorker, sourceNode, targetNode),
|
|
4666
|
+
isMatch: matchWorker.assertionNode.abilityDiagnostics.size === 0,
|
|
4648
4667
|
};
|
|
4649
4668
|
}
|
|
4650
4669
|
}
|
|
@@ -5245,7 +5264,7 @@ class ToBeApplicable {
|
|
|
5245
5264
|
if (type.getCallSignatures().length === 0) {
|
|
5246
5265
|
const expectedText = "of a function type";
|
|
5247
5266
|
const text = nodeBelongsToArgumentList(this.#compiler, sourceNode)
|
|
5248
|
-
? ExpectDiagnosticText.argumentMustBe(
|
|
5267
|
+
? ExpectDiagnosticText.argumentMustBe(expectedText)
|
|
5249
5268
|
: ExpectDiagnosticText.typeArgumentMustBe(expectedText);
|
|
5250
5269
|
const origin = DiagnosticOrigin.fromNode(sourceNode);
|
|
5251
5270
|
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
@@ -5280,55 +5299,6 @@ class ToBeAssignableTo extends RelationMatcherBase {
|
|
|
5280
5299
|
}
|
|
5281
5300
|
}
|
|
5282
5301
|
|
|
5283
|
-
class AbilityMatcherBase {
|
|
5284
|
-
compiler;
|
|
5285
|
-
constructor(compiler) {
|
|
5286
|
-
this.compiler = compiler;
|
|
5287
|
-
}
|
|
5288
|
-
getArgumentCountText(nodes) {
|
|
5289
|
-
if (nodes.length === 0) {
|
|
5290
|
-
return "without arguments";
|
|
5291
|
-
}
|
|
5292
|
-
if (nodes.length === 1 && nodes[0]?.kind === this.compiler.SyntaxKind.SpreadElement) {
|
|
5293
|
-
return "with the given arguments";
|
|
5294
|
-
}
|
|
5295
|
-
return `with the given argument${nodes.length === 1 ? "" : "s"}`;
|
|
5296
|
-
}
|
|
5297
|
-
getTypeArgumentCountText(targetNode) {
|
|
5298
|
-
if (targetNode.elements.length === 0) {
|
|
5299
|
-
return "without type arguments";
|
|
5300
|
-
}
|
|
5301
|
-
return `with the given type argument${targetNode.elements.length === 1 ? "" : "s"}`;
|
|
5302
|
-
}
|
|
5303
|
-
explain(matchWorker, sourceNode, targetNode, getArgumentCountText) {
|
|
5304
|
-
const isExpression = nodeBelongsToArgumentList(this.compiler, sourceNode);
|
|
5305
|
-
const argumentCountText = getArgumentCountText();
|
|
5306
|
-
const diagnostics = [];
|
|
5307
|
-
if (matchWorker.assertionNode.abilityDiagnostics.size > 0) {
|
|
5308
|
-
for (const diagnostic of matchWorker.assertionNode.abilityDiagnostics) {
|
|
5309
|
-
const text = [this.explainNotText(isExpression, argumentCountText), getDiagnosticMessageText(diagnostic)];
|
|
5310
|
-
let origin;
|
|
5311
|
-
if (isDiagnosticWithLocation(diagnostic) && diagnosticBelongsToNode(diagnostic, targetNode)) {
|
|
5312
|
-
origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), sourceNode.getSourceFile(), matchWorker.assertionNode);
|
|
5313
|
-
}
|
|
5314
|
-
else {
|
|
5315
|
-
origin = DiagnosticOrigin.fromAssertion(matchWorker.assertionNode);
|
|
5316
|
-
}
|
|
5317
|
-
let related;
|
|
5318
|
-
if (diagnostic.relatedInformation != null) {
|
|
5319
|
-
related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
|
|
5320
|
-
}
|
|
5321
|
-
diagnostics.push(Diagnostic.error(text.flat(), origin).add({ related }));
|
|
5322
|
-
}
|
|
5323
|
-
}
|
|
5324
|
-
else {
|
|
5325
|
-
const origin = DiagnosticOrigin.fromAssertion(matchWorker.assertionNode);
|
|
5326
|
-
diagnostics.push(Diagnostic.error(this.explainText(isExpression, argumentCountText), origin));
|
|
5327
|
-
}
|
|
5328
|
-
return diagnostics;
|
|
5329
|
-
}
|
|
5330
|
-
}
|
|
5331
|
-
|
|
5332
5302
|
class ToBeCallableWith extends AbilityMatcherBase {
|
|
5333
5303
|
explainText = ExpectDiagnosticText.isCallable;
|
|
5334
5304
|
explainNotText = ExpectDiagnosticText.isNotCallable;
|
|
@@ -5337,7 +5307,7 @@ class ToBeCallableWith extends AbilityMatcherBase {
|
|
|
5337
5307
|
if (sourceType.getCallSignatures().length === 0) {
|
|
5338
5308
|
const text = [];
|
|
5339
5309
|
if (nodeBelongsToArgumentList(this.compiler, sourceNode)) {
|
|
5340
|
-
text.push(ExpectDiagnosticText.argumentMustBe("
|
|
5310
|
+
text.push(ExpectDiagnosticText.argumentMustBe("a callable expression"));
|
|
5341
5311
|
}
|
|
5342
5312
|
else {
|
|
5343
5313
|
text.push(ExpectDiagnosticText.typeArgumentMustBe("a callable type"));
|
|
@@ -5364,7 +5334,7 @@ class ToBeConstructableWith extends AbilityMatcherBase {
|
|
|
5364
5334
|
if (sourceType.getConstructSignatures().length === 0) {
|
|
5365
5335
|
const text = [];
|
|
5366
5336
|
if (nodeBelongsToArgumentList(this.compiler, sourceNode)) {
|
|
5367
|
-
text.push(ExpectDiagnosticText.argumentMustBe("
|
|
5337
|
+
text.push(ExpectDiagnosticText.argumentMustBe("a constructable expression"));
|
|
5368
5338
|
}
|
|
5369
5339
|
else {
|
|
5370
5340
|
text.push(ExpectDiagnosticText.typeArgumentMustBe("a constructable type"));
|
|
@@ -5393,7 +5363,7 @@ class ToBeInstantiableWith extends AbilityMatcherBase {
|
|
|
5393
5363
|
this.compiler.isExpressionWithTypeArguments(sourceNode))) {
|
|
5394
5364
|
let text;
|
|
5395
5365
|
if (nodeBelongsToArgumentList(this.compiler, sourceNode)) {
|
|
5396
|
-
text = ExpectDiagnosticText.argumentMustBe("
|
|
5366
|
+
text = ExpectDiagnosticText.argumentMustBe("an instantiable expression");
|
|
5397
5367
|
}
|
|
5398
5368
|
else {
|
|
5399
5369
|
text = ExpectDiagnosticText.typeArgumentMustBe("an instantiable type");
|
|
@@ -5424,7 +5394,7 @@ class ToHaveProperty {
|
|
|
5424
5394
|
const sourceTypeText = matchWorker.getTypeText(sourceNode);
|
|
5425
5395
|
const targetType = matchWorker.getType(targetNode);
|
|
5426
5396
|
let propertyNameText;
|
|
5427
|
-
if (
|
|
5397
|
+
if (targetType.flags & (this.#compiler.TypeFlags.StringLiteral | this.#compiler.TypeFlags.NumberLiteral)) {
|
|
5428
5398
|
propertyNameText = targetType.value.toString();
|
|
5429
5399
|
}
|
|
5430
5400
|
else {
|
|
@@ -5442,15 +5412,18 @@ class ToHaveProperty {
|
|
|
5442
5412
|
!matchWorker.extendsObjectType(sourceType)) {
|
|
5443
5413
|
const expectedText = "of an object type";
|
|
5444
5414
|
const text = nodeBelongsToArgumentList(this.#compiler, sourceNode)
|
|
5445
|
-
? ExpectDiagnosticText.argumentMustBe(
|
|
5415
|
+
? ExpectDiagnosticText.argumentMustBe(expectedText)
|
|
5446
5416
|
: ExpectDiagnosticText.typeArgumentMustBe(expectedText);
|
|
5447
5417
|
const origin = DiagnosticOrigin.fromNode(sourceNode);
|
|
5448
5418
|
diagnostics.push(Diagnostic.error(text, origin));
|
|
5449
5419
|
}
|
|
5450
5420
|
const targetType = matchWorker.getType(targetNode);
|
|
5451
|
-
if (!(
|
|
5452
|
-
|
|
5453
|
-
|
|
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);
|
|
5454
5427
|
const origin = DiagnosticOrigin.fromNode(targetNode);
|
|
5455
5428
|
diagnostics.push(Diagnostic.error(text, origin));
|
|
5456
5429
|
}
|
|
@@ -5509,8 +5482,8 @@ class ToRaiseError {
|
|
|
5509
5482
|
if (!(this.#compiler.isStringLiteralLike(targetNode) ||
|
|
5510
5483
|
this.#compiler.isNumericLiteral(targetNode) ||
|
|
5511
5484
|
this.#compiler.isRegularExpressionLiteral(targetNode))) {
|
|
5512
|
-
const expectedText = "a string, number or regular expression
|
|
5513
|
-
const text = ExpectDiagnosticText.argumentMustBe(
|
|
5485
|
+
const expectedText = "a string, number or regular expression";
|
|
5486
|
+
const text = ExpectDiagnosticText.argumentMustBe(expectedText);
|
|
5514
5487
|
const origin = DiagnosticOrigin.fromNode(targetNode);
|
|
5515
5488
|
diagnostics.push(Diagnostic.error(text, origin));
|
|
5516
5489
|
}
|
|
@@ -5551,6 +5524,7 @@ class ToRaiseError {
|
|
|
5551
5524
|
|
|
5552
5525
|
class ExpectService {
|
|
5553
5526
|
#compiler;
|
|
5527
|
+
#ensure;
|
|
5554
5528
|
#program;
|
|
5555
5529
|
#reject;
|
|
5556
5530
|
toAcceptProps;
|
|
@@ -5563,11 +5537,12 @@ class ExpectService {
|
|
|
5563
5537
|
toBeInstantiableWith;
|
|
5564
5538
|
toHaveProperty;
|
|
5565
5539
|
toRaiseError;
|
|
5566
|
-
constructor(compiler, program,
|
|
5540
|
+
constructor(compiler, program, resolvedConfig) {
|
|
5567
5541
|
this.#compiler = compiler;
|
|
5568
5542
|
this.#program = program;
|
|
5569
|
-
this.#
|
|
5570
|
-
this
|
|
5543
|
+
this.#ensure = new Ensure(compiler);
|
|
5544
|
+
this.#reject = new Reject(compiler, program, resolvedConfig);
|
|
5545
|
+
this.toAcceptProps = new ToAcceptProps(compiler);
|
|
5571
5546
|
this.toBe = new ToBe(compiler, program);
|
|
5572
5547
|
this.toBeApplicable = new ToBeApplicable(compiler);
|
|
5573
5548
|
this.toBeAssignableFrom = new ToBeAssignableFrom();
|
|
@@ -5580,15 +5555,12 @@ class ExpectService {
|
|
|
5580
5555
|
}
|
|
5581
5556
|
match(assertionNode, onDiagnostics) {
|
|
5582
5557
|
const matcherNameText = assertionNode.matcherNameNode.name.text;
|
|
5583
|
-
if (!
|
|
5558
|
+
if (!this.#ensure.argumentOrTypeArgument(assertionNode.source[0], assertionNode.node.expression, onDiagnostics)) {
|
|
5584
5559
|
return;
|
|
5585
5560
|
}
|
|
5586
5561
|
const matchWorker = new MatchWorker(this.#compiler, this.#program, assertionNode);
|
|
5587
5562
|
if (!(matcherNameText === "toBeInstantiableWith" || (matcherNameText === "toRaiseError" && !assertionNode.isNot)) &&
|
|
5588
|
-
this.#reject.argumentType([
|
|
5589
|
-
["source", assertionNode.source[0]],
|
|
5590
|
-
["target", assertionNode.target?.[0]],
|
|
5591
|
-
], onDiagnostics)) {
|
|
5563
|
+
this.#reject.argumentType([assertionNode.source[0], assertionNode.target?.[0]], onDiagnostics)) {
|
|
5592
5564
|
return;
|
|
5593
5565
|
}
|
|
5594
5566
|
switch (matcherNameText) {
|
|
@@ -5596,7 +5568,7 @@ class ExpectService {
|
|
|
5596
5568
|
case "toBe":
|
|
5597
5569
|
case "toBeAssignableFrom":
|
|
5598
5570
|
case "toBeAssignableTo":
|
|
5599
|
-
if (!
|
|
5571
|
+
if (!this.#ensure.argumentOrTypeArgument(assertionNode.target?.[0], assertionNode.matcherNameNode.name, onDiagnostics)) {
|
|
5600
5572
|
return;
|
|
5601
5573
|
}
|
|
5602
5574
|
return this[matcherNameText].match(matchWorker, assertionNode.source[0], assertionNode.target[0], onDiagnostics);
|
|
@@ -5607,13 +5579,13 @@ class ExpectService {
|
|
|
5607
5579
|
case "toRaiseError":
|
|
5608
5580
|
return this[matcherNameText].match(matchWorker, assertionNode.source[0], assertionNode.target, onDiagnostics);
|
|
5609
5581
|
case "toBeInstantiableWith": {
|
|
5610
|
-
if (!
|
|
5582
|
+
if (!this.#ensure.typeArgument(assertionNode.target?.[0], assertionNode.matcherNameNode.name, onDiagnostics)) {
|
|
5611
5583
|
return;
|
|
5612
5584
|
}
|
|
5613
5585
|
return this.toBeInstantiableWith.match(matchWorker, assertionNode.source[0], assertionNode.target[0], onDiagnostics);
|
|
5614
5586
|
}
|
|
5615
5587
|
case "toHaveProperty":
|
|
5616
|
-
if (!
|
|
5588
|
+
if (!this.#ensure.argument(assertionNode.target?.[0], assertionNode.matcherNameNode.name, onDiagnostics)) {
|
|
5617
5589
|
return;
|
|
5618
5590
|
}
|
|
5619
5591
|
return this.toHaveProperty.match(matchWorker, assertionNode.source[0], assertionNode.target[0], onDiagnostics);
|
|
@@ -5629,67 +5601,6 @@ class ExpectService {
|
|
|
5629
5601
|
}
|
|
5630
5602
|
}
|
|
5631
5603
|
|
|
5632
|
-
function capitalize(text) {
|
|
5633
|
-
return text.replace(/^./, text.charAt(0).toUpperCase());
|
|
5634
|
-
}
|
|
5635
|
-
|
|
5636
|
-
class RejectDiagnosticText {
|
|
5637
|
-
static argumentCannotBeOfType(argumentNameText, typeText) {
|
|
5638
|
-
return `An argument for '${argumentNameText}' cannot be of the '${typeText}' type.`;
|
|
5639
|
-
}
|
|
5640
|
-
static typeArgumentCannotBeOfType(argumentNameText, typeText) {
|
|
5641
|
-
return `A type argument for '${argumentNameText}' cannot be of the '${typeText}' type.`;
|
|
5642
|
-
}
|
|
5643
|
-
static typeWasRejected(typeText) {
|
|
5644
|
-
const optionNameText = `reject${capitalize(typeText)}Type`;
|
|
5645
|
-
return [
|
|
5646
|
-
`The '${typeText}' type was rejected because the '${optionNameText}' option is enabled.`,
|
|
5647
|
-
`If this check is necessary, pass '${typeText}' as the type argument explicitly.`,
|
|
5648
|
-
];
|
|
5649
|
-
}
|
|
5650
|
-
}
|
|
5651
|
-
|
|
5652
|
-
class Reject {
|
|
5653
|
-
#compiler;
|
|
5654
|
-
#rejectedArgumentTypes = new Set();
|
|
5655
|
-
#typeChecker;
|
|
5656
|
-
constructor(compiler, program, resolvedConfig) {
|
|
5657
|
-
this.#compiler = compiler;
|
|
5658
|
-
this.#typeChecker = program.getTypeChecker();
|
|
5659
|
-
if (resolvedConfig.rejectAnyType) {
|
|
5660
|
-
this.#rejectedArgumentTypes.add("any");
|
|
5661
|
-
}
|
|
5662
|
-
if (resolvedConfig.rejectNeverType) {
|
|
5663
|
-
this.#rejectedArgumentTypes.add("never");
|
|
5664
|
-
}
|
|
5665
|
-
}
|
|
5666
|
-
argumentType(target, onDiagnostics) {
|
|
5667
|
-
for (const rejectedType of this.#rejectedArgumentTypes) {
|
|
5668
|
-
const allowedKeyword = this.#compiler.SyntaxKind[`${capitalize(rejectedType)}Keyword`];
|
|
5669
|
-
if (target.some(([, node]) => node?.kind === allowedKeyword)) {
|
|
5670
|
-
continue;
|
|
5671
|
-
}
|
|
5672
|
-
for (const [name, node] of target) {
|
|
5673
|
-
if (!node) {
|
|
5674
|
-
continue;
|
|
5675
|
-
}
|
|
5676
|
-
if (this.#typeChecker.getTypeAtLocation(node).flags & this.#compiler.TypeFlags[capitalize(rejectedType)]) {
|
|
5677
|
-
const text = [
|
|
5678
|
-
nodeBelongsToArgumentList(this.#compiler, node)
|
|
5679
|
-
? RejectDiagnosticText.argumentCannotBeOfType(name, rejectedType)
|
|
5680
|
-
: RejectDiagnosticText.typeArgumentCannotBeOfType(capitalize(name), rejectedType),
|
|
5681
|
-
...RejectDiagnosticText.typeWasRejected(rejectedType),
|
|
5682
|
-
];
|
|
5683
|
-
const origin = DiagnosticOrigin.fromNode(node);
|
|
5684
|
-
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
5685
|
-
return true;
|
|
5686
|
-
}
|
|
5687
|
-
}
|
|
5688
|
-
}
|
|
5689
|
-
return false;
|
|
5690
|
-
}
|
|
5691
|
-
}
|
|
5692
|
-
|
|
5693
5604
|
class FixmeDiagnosticText {
|
|
5694
5605
|
static considerRemoving() {
|
|
5695
5606
|
return "Consider removing the '// @tstyche fixme' directive.";
|
|
@@ -5763,8 +5674,7 @@ class TestTreeWalker {
|
|
|
5763
5674
|
this.#cancellationToken = options.cancellationToken;
|
|
5764
5675
|
this.#hasOnly = options.hasOnly || resolvedConfig.only != null || options.position != null;
|
|
5765
5676
|
this.#position = options.position;
|
|
5766
|
-
|
|
5767
|
-
this.#expectService = new ExpectService(compiler, program, reject);
|
|
5677
|
+
this.#expectService = new ExpectService(compiler, program, resolvedConfig);
|
|
5768
5678
|
}
|
|
5769
5679
|
async #resolveRunMode(flags, node) {
|
|
5770
5680
|
const ifDirective = Directive.getDirectiveRange(this.#compiler, node, "if");
|
|
@@ -5998,7 +5908,7 @@ class FileRunner {
|
|
|
5998
5908
|
class Runner {
|
|
5999
5909
|
#eventEmitter = new EventEmitter();
|
|
6000
5910
|
#resolvedConfig;
|
|
6001
|
-
static version = "7.
|
|
5911
|
+
static version = "7.2.0";
|
|
6002
5912
|
constructor(resolvedConfig) {
|
|
6003
5913
|
this.#resolvedConfig = resolvedConfig;
|
|
6004
5914
|
}
|
|
@@ -6223,4 +6133,4 @@ class Cli {
|
|
|
6223
6133
|
}
|
|
6224
6134
|
}
|
|
6225
6135
|
|
|
6226
|
-
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 };
|