tstyche 2.0.0-beta.1 → 2.0.0-rc.1
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/build/tstyche.d.ts +48 -59
- package/build/tstyche.js +309 -369
- package/package.json +6 -7
package/build/tstyche.js
CHANGED
|
@@ -3,10 +3,9 @@ import path from 'node:path';
|
|
|
3
3
|
import process from 'node:process';
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
5
|
import os from 'node:os';
|
|
6
|
-
import { existsSync,
|
|
6
|
+
import { existsSync, writeFileSync, rmSync } from 'node:fs';
|
|
7
7
|
import fs from 'node:fs/promises';
|
|
8
8
|
import vm from 'node:vm';
|
|
9
|
-
import https from 'node:https';
|
|
10
9
|
import { spawn } from 'node:child_process';
|
|
11
10
|
|
|
12
11
|
class EventEmitter {
|
|
@@ -34,18 +33,21 @@ class EventEmitter {
|
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
class Path {
|
|
36
|
+
static normalizeSlashes;
|
|
37
|
+
static {
|
|
38
|
+
if (path.sep === "/") {
|
|
39
|
+
Path.normalizeSlashes = (filePath) => filePath;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
Path.normalizeSlashes = (filePath) => filePath.replace(/\\/g, "/");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
37
45
|
static dirname(filePath) {
|
|
38
46
|
return Path.normalizeSlashes(path.dirname(filePath));
|
|
39
47
|
}
|
|
40
48
|
static join(...filePaths) {
|
|
41
49
|
return Path.normalizeSlashes(path.join(...filePaths));
|
|
42
50
|
}
|
|
43
|
-
static normalizeSlashes(filePath) {
|
|
44
|
-
if (path.sep === "/") {
|
|
45
|
-
return filePath;
|
|
46
|
-
}
|
|
47
|
-
return filePath.replace(/\\/g, "/");
|
|
48
|
-
}
|
|
49
51
|
static relative(from, to) {
|
|
50
52
|
let relativePath = path.relative(from, to);
|
|
51
53
|
if (!relativePath.startsWith("./")) {
|
|
@@ -61,16 +63,11 @@ class Path {
|
|
|
61
63
|
class TestFile {
|
|
62
64
|
path;
|
|
63
65
|
position;
|
|
64
|
-
constructor(identifier) {
|
|
65
|
-
this.path = Path.normalizeSlashes(this.#
|
|
66
|
-
|
|
67
|
-
add(options) {
|
|
68
|
-
if (options.position != null) {
|
|
69
|
-
this.position = options.position;
|
|
70
|
-
}
|
|
71
|
-
return this;
|
|
66
|
+
constructor(identifier, position) {
|
|
67
|
+
this.path = Path.normalizeSlashes(this.#toPath(identifier));
|
|
68
|
+
this.position = position;
|
|
72
69
|
}
|
|
73
|
-
#
|
|
70
|
+
#toPath(identifier) {
|
|
74
71
|
if (typeof identifier === "string" && !identifier.startsWith("file:")) {
|
|
75
72
|
return identifier;
|
|
76
73
|
}
|
|
@@ -304,21 +301,21 @@ class CodeSpanText {
|
|
|
304
301
|
this.props = props;
|
|
305
302
|
}
|
|
306
303
|
render() {
|
|
307
|
-
const lastLineInFile = this.props.
|
|
308
|
-
const { character: markedCharacter, line: markedLine } = this.props.
|
|
304
|
+
const lastLineInFile = this.props.sourceFile.getLineAndCharacterOfPosition(this.props.sourceFile.text.length).line;
|
|
305
|
+
const { character: markedCharacter, line: markedLine } = this.props.sourceFile.getLineAndCharacterOfPosition(this.props.start);
|
|
309
306
|
const firstLine = Math.max(markedLine - 2, 0);
|
|
310
307
|
const lastLine = Math.min(firstLine + 5, lastLineInFile);
|
|
311
308
|
const lineNumberMaxWidth = String(lastLine + 1).length;
|
|
312
309
|
const codeSpan = [];
|
|
313
310
|
for (let index = firstLine; index <= lastLine; index++) {
|
|
314
|
-
const lineStart = this.props.
|
|
311
|
+
const lineStart = this.props.sourceFile.getPositionOfLineAndCharacter(index, 0);
|
|
315
312
|
const lineEnd = index === lastLineInFile
|
|
316
|
-
? this.props.
|
|
317
|
-
: this.props.
|
|
313
|
+
? this.props.sourceFile.text.length
|
|
314
|
+
: this.props.sourceFile.getPositionOfLineAndCharacter(index + 1, 0);
|
|
318
315
|
const lineNumberText = String(index + 1);
|
|
319
|
-
const lineText = this.props.
|
|
316
|
+
const lineText = this.props.sourceFile.text.slice(lineStart, lineEnd).trimEnd().replace(/\t/g, " ");
|
|
320
317
|
if (index === markedLine) {
|
|
321
|
-
codeSpan.push(jsx(Line, { children: [jsx(Text, { color: "31", children: ">" }), " ", lineNumberText.padStart(lineNumberMaxWidth), " ", jsx(Text, { color: "90", children: "|" }), " ", lineText] }), jsx(Line, { children: [" ".repeat(lineNumberMaxWidth + 3), jsx(Text, { color: "90", children: "|" }), " ".repeat(markedCharacter + 1), jsx(Text, { color: "31", children: "^" })] }));
|
|
318
|
+
codeSpan.push(jsx(Line, { children: [jsx(Text, { color: "31", children: ">" }), jsx(Text, { children: " " }), lineNumberText.padStart(lineNumberMaxWidth), jsx(Text, { children: " " }), jsx(Text, { color: "90", children: "|" }), " ", lineText] }), jsx(Line, { children: [" ".repeat(lineNumberMaxWidth + 3), jsx(Text, { color: "90", children: "|" }), " ".repeat(markedCharacter + 1), jsx(Text, { color: "31", children: "^" })] }));
|
|
322
319
|
}
|
|
323
320
|
else {
|
|
324
321
|
codeSpan.push(jsx(Line, { children: [" ".repeat(2), jsx(Text, { color: "90", children: [lineNumberText.padStart(lineNumberMaxWidth), " | ", lineText || ""] })] }));
|
|
@@ -328,7 +325,7 @@ class CodeSpanText {
|
|
|
328
325
|
jsx(Text, { color: "90", children: " ❭ " }),
|
|
329
326
|
jsx(Text, { children: ancestor }),
|
|
330
327
|
]);
|
|
331
|
-
const location = (jsx(Line, { children: [" ".repeat(lineNumberMaxWidth + 5), jsx(Text, { color: "90", children: "at" }), " ", jsx(Text, { color: "36", children: Path.relative("", this.props.
|
|
328
|
+
const location = (jsx(Line, { children: [" ".repeat(lineNumberMaxWidth + 5), jsx(Text, { color: "90", children: "at" }), jsx(Text, { children: " " }), jsx(Text, { color: "36", children: Path.relative("", this.props.sourceFile.fileName) }), jsx(Text, { color: "90", children: [":", String(markedLine + 1), ":", String(markedCharacter + 1)] }), breadcrumbs] }));
|
|
332
329
|
return (jsx(Text, { children: [codeSpan, jsx(Line, {}), location] }));
|
|
333
330
|
}
|
|
334
331
|
}
|
|
@@ -619,21 +616,21 @@ class RanFilesText {
|
|
|
619
616
|
this.props = props;
|
|
620
617
|
}
|
|
621
618
|
render() {
|
|
622
|
-
const
|
|
619
|
+
const testNameMatchText = [];
|
|
623
620
|
if (this.props.onlyMatch != null) {
|
|
624
|
-
|
|
621
|
+
testNameMatchText.push(jsx(Text, { children: [jsx(Text, { color: "90", children: "matching " }), jsx(MatchText, { text: this.props.onlyMatch })] }));
|
|
625
622
|
}
|
|
626
623
|
if (this.props.skipMatch != null) {
|
|
627
|
-
|
|
624
|
+
testNameMatchText.push(jsx(Text, { children: [this.props.onlyMatch == null ? undefined : jsx(Text, { color: "90", children: " and " }), jsx(Text, { color: "90", children: "not matching " }), jsx(MatchText, { text: this.props.skipMatch })] }));
|
|
628
625
|
}
|
|
629
|
-
let
|
|
626
|
+
let pathMatchText;
|
|
630
627
|
if (this.props.pathMatch.length > 0) {
|
|
631
|
-
|
|
628
|
+
pathMatchText = (jsx(Text, { children: [jsx(Text, { color: "90", children: "test files matching " }), jsx(MatchText, { text: this.props.pathMatch }), jsx(Text, { color: "90", children: "." })] }));
|
|
632
629
|
}
|
|
633
630
|
else {
|
|
634
|
-
|
|
631
|
+
pathMatchText = jsx(Text, { color: "90", children: "all test files." });
|
|
635
632
|
}
|
|
636
|
-
return (jsx(Line, { children: [jsx(Text, { color: "90", children: "Ran " }),
|
|
633
|
+
return (jsx(Line, { children: [jsx(Text, { color: "90", children: "Ran " }), testNameMatchText.length > 0 ? jsx(Text, { color: "90", children: "tests " }) : undefined, testNameMatchText, testNameMatchText.length > 0 ? jsx(Text, { color: "90", children: " in " }) : undefined, pathMatchText] }));
|
|
637
634
|
}
|
|
638
635
|
}
|
|
639
636
|
function summaryText({ duration, expectCount, fileCount, onlyMatch, pathMatch, skipMatch, targetCount, testCount, }) {
|
|
@@ -711,6 +708,11 @@ class FileViewService {
|
|
|
711
708
|
this.#lines.push(describeNameText(name, this.#indent));
|
|
712
709
|
this.#indent++;
|
|
713
710
|
}
|
|
711
|
+
clear() {
|
|
712
|
+
this.#indent = 0;
|
|
713
|
+
this.#lines = [];
|
|
714
|
+
this.#messages = [];
|
|
715
|
+
}
|
|
714
716
|
endDescribe() {
|
|
715
717
|
this.#indent--;
|
|
716
718
|
}
|
|
@@ -720,15 +722,9 @@ class FileViewService {
|
|
|
720
722
|
getViewText(options) {
|
|
721
723
|
return fileViewText(this.#lines, options?.appendEmptyLine === true || this.hasErrors);
|
|
722
724
|
}
|
|
723
|
-
reset() {
|
|
724
|
-
this.#indent = 0;
|
|
725
|
-
this.#lines = [];
|
|
726
|
-
this.#messages = [];
|
|
727
|
-
}
|
|
728
725
|
}
|
|
729
726
|
|
|
730
727
|
class RuntimeReporter {
|
|
731
|
-
resolvedConfig;
|
|
732
728
|
#currentCompilerVersion;
|
|
733
729
|
#currentProjectConfigFilePath;
|
|
734
730
|
#fileCount = 0;
|
|
@@ -736,10 +732,11 @@ class RuntimeReporter {
|
|
|
736
732
|
#hasReportedAdds = false;
|
|
737
733
|
#hasReportedError = false;
|
|
738
734
|
#isFileViewExpanded = false;
|
|
735
|
+
#resolvedConfig;
|
|
739
736
|
#outputService;
|
|
740
737
|
#seenDeprecations = new Set();
|
|
741
738
|
constructor(resolvedConfig, outputService) {
|
|
742
|
-
this
|
|
739
|
+
this.#resolvedConfig = resolvedConfig;
|
|
743
740
|
this.#outputService = outputService;
|
|
744
741
|
}
|
|
745
742
|
get #isLastFile() {
|
|
@@ -757,7 +754,7 @@ class RuntimeReporter {
|
|
|
757
754
|
break;
|
|
758
755
|
}
|
|
759
756
|
case "run:start": {
|
|
760
|
-
this.#isFileViewExpanded = payload.result.testFiles.length === 1 && this
|
|
757
|
+
this.#isFileViewExpanded = payload.result.testFiles.length === 1 && this.#resolvedConfig.watch !== true;
|
|
761
758
|
break;
|
|
762
759
|
}
|
|
763
760
|
case "store:info": {
|
|
@@ -822,7 +819,8 @@ class RuntimeReporter {
|
|
|
822
819
|
this.#outputService.writeError(this.#fileView.getMessages());
|
|
823
820
|
this.#hasReportedError = true;
|
|
824
821
|
}
|
|
825
|
-
this.#fileView.
|
|
822
|
+
this.#fileView.clear();
|
|
823
|
+
this.#seenDeprecations.clear();
|
|
826
824
|
break;
|
|
827
825
|
}
|
|
828
826
|
case "describe:start": {
|
|
@@ -960,8 +958,8 @@ class WatchReporter {
|
|
|
960
958
|
}
|
|
961
959
|
|
|
962
960
|
class ResultTiming {
|
|
963
|
-
end =
|
|
964
|
-
start =
|
|
961
|
+
end = Number.NaN;
|
|
962
|
+
start = Number.NaN;
|
|
965
963
|
get duration() {
|
|
966
964
|
return this.end - this.start;
|
|
967
965
|
}
|
|
@@ -989,8 +987,8 @@ var ResultStatus;
|
|
|
989
987
|
|
|
990
988
|
class ExpectResult {
|
|
991
989
|
assertion;
|
|
992
|
-
parent;
|
|
993
990
|
diagnostics = [];
|
|
991
|
+
parent;
|
|
994
992
|
status = "runs";
|
|
995
993
|
timing = new ResultTiming();
|
|
996
994
|
constructor(assertion, parent) {
|
|
@@ -1010,12 +1008,12 @@ class ResultCount {
|
|
|
1010
1008
|
}
|
|
1011
1009
|
|
|
1012
1010
|
class FileResult {
|
|
1013
|
-
testFile;
|
|
1014
1011
|
diagnostics = [];
|
|
1015
1012
|
expectCount = new ResultCount();
|
|
1016
1013
|
results = [];
|
|
1017
1014
|
status = "runs";
|
|
1018
1015
|
testCount = new ResultCount();
|
|
1016
|
+
testFile;
|
|
1019
1017
|
timing = new ResultTiming();
|
|
1020
1018
|
constructor(testFile) {
|
|
1021
1019
|
this.testFile = testFile;
|
|
@@ -1024,8 +1022,8 @@ class FileResult {
|
|
|
1024
1022
|
|
|
1025
1023
|
class ProjectResult {
|
|
1026
1024
|
compilerVersion;
|
|
1027
|
-
projectConfigFilePath;
|
|
1028
1025
|
diagnostics = [];
|
|
1026
|
+
projectConfigFilePath;
|
|
1029
1027
|
results = [];
|
|
1030
1028
|
constructor(compilerVersion, projectConfigFilePath) {
|
|
1031
1029
|
this.compilerVersion = compilerVersion;
|
|
@@ -1034,13 +1032,13 @@ class ProjectResult {
|
|
|
1034
1032
|
}
|
|
1035
1033
|
|
|
1036
1034
|
class Result {
|
|
1037
|
-
resolvedConfig;
|
|
1038
|
-
testFiles;
|
|
1039
1035
|
expectCount = new ResultCount();
|
|
1040
1036
|
fileCount = new ResultCount();
|
|
1037
|
+
resolvedConfig;
|
|
1041
1038
|
results = [];
|
|
1042
1039
|
targetCount = new ResultCount();
|
|
1043
1040
|
testCount = new ResultCount();
|
|
1041
|
+
testFiles;
|
|
1044
1042
|
timing = new ResultTiming();
|
|
1045
1043
|
constructor(resolvedConfig, testFiles) {
|
|
1046
1044
|
this.resolvedConfig = resolvedConfig;
|
|
@@ -1265,11 +1263,11 @@ class ResultHandler {
|
|
|
1265
1263
|
}
|
|
1266
1264
|
|
|
1267
1265
|
class TargetResult {
|
|
1268
|
-
versionTag;
|
|
1269
|
-
testFiles;
|
|
1270
1266
|
results = new Map();
|
|
1271
1267
|
status = "runs";
|
|
1268
|
+
testFiles;
|
|
1272
1269
|
timing = new ResultTiming();
|
|
1270
|
+
versionTag;
|
|
1273
1271
|
constructor(versionTag, testFiles) {
|
|
1274
1272
|
this.versionTag = versionTag;
|
|
1275
1273
|
this.testFiles = testFiles;
|
|
@@ -1277,12 +1275,12 @@ class TargetResult {
|
|
|
1277
1275
|
}
|
|
1278
1276
|
|
|
1279
1277
|
class TestResult {
|
|
1280
|
-
test;
|
|
1281
|
-
parent;
|
|
1282
1278
|
diagnostics = [];
|
|
1283
1279
|
expectCount = new ResultCount();
|
|
1280
|
+
parent;
|
|
1284
1281
|
results = [];
|
|
1285
1282
|
status = "runs";
|
|
1283
|
+
test;
|
|
1286
1284
|
timing = new ResultTiming();
|
|
1287
1285
|
constructor(test, parent) {
|
|
1288
1286
|
this.test = test;
|
|
@@ -1328,27 +1326,27 @@ var CancellationReason;
|
|
|
1328
1326
|
})(CancellationReason || (CancellationReason = {}));
|
|
1329
1327
|
|
|
1330
1328
|
class Watcher {
|
|
1331
|
-
targetPath;
|
|
1332
1329
|
#abortController = new AbortController();
|
|
1333
1330
|
#onChanged;
|
|
1334
1331
|
#onRemoved;
|
|
1335
1332
|
#recursive;
|
|
1333
|
+
#targetPath;
|
|
1336
1334
|
#watcher;
|
|
1337
|
-
constructor(targetPath, onChanged, onRemoved,
|
|
1338
|
-
this
|
|
1335
|
+
constructor(targetPath, onChanged, onRemoved, options) {
|
|
1336
|
+
this.#targetPath = targetPath;
|
|
1339
1337
|
this.#onChanged = onChanged;
|
|
1340
1338
|
this.#onRemoved = onRemoved ?? onChanged;
|
|
1341
|
-
this.#recursive = recursive;
|
|
1339
|
+
this.#recursive = options?.recursive;
|
|
1342
1340
|
}
|
|
1343
1341
|
close() {
|
|
1344
1342
|
this.#abortController.abort();
|
|
1345
1343
|
}
|
|
1346
1344
|
async watch() {
|
|
1347
|
-
this.#watcher = fs.watch(this
|
|
1345
|
+
this.#watcher = fs.watch(this.#targetPath, { recursive: this.#recursive, signal: this.#abortController.signal });
|
|
1348
1346
|
try {
|
|
1349
1347
|
for await (const event of this.#watcher) {
|
|
1350
1348
|
if (event.filename != null) {
|
|
1351
|
-
const filePath = Path.resolve(this
|
|
1349
|
+
const filePath = Path.resolve(this.#targetPath, event.filename);
|
|
1352
1350
|
if (existsSync(filePath)) {
|
|
1353
1351
|
await this.#onChanged(filePath);
|
|
1354
1352
|
}
|
|
@@ -1375,12 +1373,31 @@ class FileWatcher extends Watcher {
|
|
|
1375
1373
|
}
|
|
1376
1374
|
}
|
|
1377
1375
|
|
|
1376
|
+
class DiagnosticOrigin {
|
|
1377
|
+
breadcrumbs;
|
|
1378
|
+
end;
|
|
1379
|
+
sourceFile;
|
|
1380
|
+
start;
|
|
1381
|
+
constructor(start, end, sourceFile, breadcrumbs) {
|
|
1382
|
+
this.start = start;
|
|
1383
|
+
this.end = end;
|
|
1384
|
+
this.sourceFile = sourceFile;
|
|
1385
|
+
this.breadcrumbs = breadcrumbs;
|
|
1386
|
+
}
|
|
1387
|
+
static fromJsonNode(node, sourceFile, skipTrivia) {
|
|
1388
|
+
return new DiagnosticOrigin(skipTrivia(node.pos, sourceFile), node.end, sourceFile);
|
|
1389
|
+
}
|
|
1390
|
+
static fromNode(node, breadcrumbs) {
|
|
1391
|
+
return new DiagnosticOrigin(node.getStart(), node.getEnd(), node.getSourceFile(), breadcrumbs);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1378
1395
|
class Diagnostic {
|
|
1379
|
-
text;
|
|
1380
1396
|
category;
|
|
1381
|
-
origin;
|
|
1382
1397
|
code;
|
|
1383
1398
|
related;
|
|
1399
|
+
origin;
|
|
1400
|
+
text;
|
|
1384
1401
|
constructor(text, category, origin) {
|
|
1385
1402
|
this.text = text;
|
|
1386
1403
|
this.category = category;
|
|
@@ -1408,11 +1425,7 @@ class Diagnostic {
|
|
|
1408
1425
|
let origin;
|
|
1409
1426
|
const text = compiler.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
|
1410
1427
|
if (Diagnostic.isTsDiagnosticWithLocation(diagnostic)) {
|
|
1411
|
-
origin =
|
|
1412
|
-
end: diagnostic.start + diagnostic.length,
|
|
1413
|
-
file: diagnostic.file,
|
|
1414
|
-
start: diagnostic.start,
|
|
1415
|
-
};
|
|
1428
|
+
origin = new DiagnosticOrigin(diagnostic.start, diagnostic.start + diagnostic.length, diagnostic.file);
|
|
1416
1429
|
}
|
|
1417
1430
|
return new Diagnostic(text, category, origin).add({ code });
|
|
1418
1431
|
});
|
|
@@ -1599,6 +1612,12 @@ class OptionDiagnosticText {
|
|
|
1599
1612
|
return optionName;
|
|
1600
1613
|
}
|
|
1601
1614
|
}
|
|
1615
|
+
static testFileMatchCannotStartWith(segment) {
|
|
1616
|
+
return [
|
|
1617
|
+
`A test file match pattern cannot start with '${segment}'.`,
|
|
1618
|
+
"The test files are only collected within the 'rootPath' directory.",
|
|
1619
|
+
];
|
|
1620
|
+
}
|
|
1602
1621
|
static requiresValueType(optionName, optionBrand, optionGroup) {
|
|
1603
1622
|
optionName = OptionDiagnosticText.#optionName(optionName, optionGroup);
|
|
1604
1623
|
return `Option '${optionName}' requires a value of type ${optionBrand}.`;
|
|
@@ -1681,30 +1700,22 @@ class OptionValidator {
|
|
|
1681
1700
|
}
|
|
1682
1701
|
break;
|
|
1683
1702
|
}
|
|
1703
|
+
case "testFileMatch": {
|
|
1704
|
+
for (const segment of ["/", "../"]) {
|
|
1705
|
+
if (optionValue.startsWith(segment)) {
|
|
1706
|
+
this.#onDiagnostic(Diagnostic.error(OptionDiagnosticText.testFileMatchCannotStartWith(segment), origin));
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
break;
|
|
1710
|
+
}
|
|
1684
1711
|
case "watch": {
|
|
1685
1712
|
if (Environment.isCi) {
|
|
1686
1713
|
this.#onDiagnostic(Diagnostic.error(OptionDiagnosticText.watchCannotBeEnabledInCiEnvironment(), origin));
|
|
1687
|
-
break;
|
|
1688
|
-
}
|
|
1689
|
-
if (!this.#isWatchSupported()) {
|
|
1690
|
-
this.#onDiagnostic(Diagnostic.error(OptionDiagnosticText.watchIsNotAvailable(), origin));
|
|
1691
1714
|
}
|
|
1692
1715
|
break;
|
|
1693
1716
|
}
|
|
1694
1717
|
}
|
|
1695
1718
|
}
|
|
1696
|
-
#isWatchSupported() {
|
|
1697
|
-
let isRecursiveWatchAvailable;
|
|
1698
|
-
try {
|
|
1699
|
-
const watcher = watch(Path.resolve("./"), { persistent: false, recursive: true });
|
|
1700
|
-
watcher.close();
|
|
1701
|
-
isRecursiveWatchAvailable = true;
|
|
1702
|
-
}
|
|
1703
|
-
catch {
|
|
1704
|
-
isRecursiveWatchAvailable = false;
|
|
1705
|
-
}
|
|
1706
|
-
return isRecursiveWatchAvailable;
|
|
1707
|
-
}
|
|
1708
1719
|
}
|
|
1709
1720
|
|
|
1710
1721
|
class CommandLineOptionsWorker {
|
|
@@ -1810,7 +1821,7 @@ class CommandLineOptionsWorker {
|
|
|
1810
1821
|
}
|
|
1811
1822
|
|
|
1812
1823
|
class ConfigFileOptionsWorker {
|
|
1813
|
-
compiler;
|
|
1824
|
+
#compiler;
|
|
1814
1825
|
#configFileOptionDefinitions;
|
|
1815
1826
|
#configFileOptions;
|
|
1816
1827
|
#configFilePath;
|
|
@@ -1819,7 +1830,7 @@ class ConfigFileOptionsWorker {
|
|
|
1819
1830
|
#optionValidator;
|
|
1820
1831
|
#storeService;
|
|
1821
1832
|
constructor(compiler, configFileOptions, configFilePath, storeService, onDiagnostic) {
|
|
1822
|
-
this
|
|
1833
|
+
this.#compiler = compiler;
|
|
1823
1834
|
this.#configFileOptions = configFileOptions;
|
|
1824
1835
|
this.#configFilePath = configFilePath;
|
|
1825
1836
|
this.#storeService = storeService;
|
|
@@ -1828,31 +1839,27 @@ class ConfigFileOptionsWorker {
|
|
|
1828
1839
|
this.#optionValidator = new OptionValidator(this.#optionGroup, this.#storeService, this.#onDiagnostic);
|
|
1829
1840
|
}
|
|
1830
1841
|
#isDoubleQuotedString(node, sourceFile) {
|
|
1831
|
-
return (node.kind === this
|
|
1842
|
+
return (node.kind === this.#compiler.SyntaxKind.StringLiteral &&
|
|
1832
1843
|
sourceFile.text.slice(this.#skipTrivia(node.pos, sourceFile), node.end).startsWith('"'));
|
|
1833
1844
|
}
|
|
1834
1845
|
async parse(sourceText) {
|
|
1835
|
-
const
|
|
1836
|
-
if (
|
|
1837
|
-
for (const diagnostic of Diagnostic.fromDiagnostics(
|
|
1846
|
+
const sourceFile = this.#compiler.parseJsonText(this.#configFilePath, sourceText);
|
|
1847
|
+
if (sourceFile.parseDiagnostics.length > 0) {
|
|
1848
|
+
for (const diagnostic of Diagnostic.fromDiagnostics(sourceFile.parseDiagnostics, this.#compiler)) {
|
|
1838
1849
|
this.#onDiagnostic(diagnostic);
|
|
1839
1850
|
}
|
|
1840
1851
|
return;
|
|
1841
1852
|
}
|
|
1842
|
-
const rootExpression =
|
|
1843
|
-
if (rootExpression == null || !this
|
|
1844
|
-
const origin =
|
|
1853
|
+
const rootExpression = sourceFile.statements[0]?.expression;
|
|
1854
|
+
if (rootExpression == null || !this.#compiler.isObjectLiteralExpression(rootExpression)) {
|
|
1855
|
+
const origin = new DiagnosticOrigin(0, 0, sourceFile);
|
|
1845
1856
|
this.#onDiagnostic(Diagnostic.error("The root value of a configuration file must be an object literal.", origin));
|
|
1846
1857
|
return;
|
|
1847
1858
|
}
|
|
1848
1859
|
for (const property of rootExpression.properties) {
|
|
1849
|
-
if (this
|
|
1850
|
-
if (!this.#isDoubleQuotedString(property.name,
|
|
1851
|
-
const origin =
|
|
1852
|
-
end: property.end,
|
|
1853
|
-
file: configSourceFile,
|
|
1854
|
-
start: this.#skipTrivia(property.pos, configSourceFile),
|
|
1855
|
-
};
|
|
1860
|
+
if (this.#compiler.isPropertyAssignment(property)) {
|
|
1861
|
+
if (!this.#isDoubleQuotedString(property.name, sourceFile)) {
|
|
1862
|
+
const origin = DiagnosticOrigin.fromJsonNode(property, sourceFile, this.#skipTrivia);
|
|
1856
1863
|
this.#onDiagnostic(Diagnostic.error(OptionDiagnosticText.doubleQuotesExpected(), origin));
|
|
1857
1864
|
continue;
|
|
1858
1865
|
}
|
|
@@ -1862,14 +1869,10 @@ class ConfigFileOptionsWorker {
|
|
|
1862
1869
|
}
|
|
1863
1870
|
const optionDefinition = this.#configFileOptionDefinitions.get(optionName);
|
|
1864
1871
|
if (optionDefinition) {
|
|
1865
|
-
this.#configFileOptions[optionDefinition.name] = await this.#parseOptionValue(
|
|
1872
|
+
this.#configFileOptions[optionDefinition.name] = await this.#parseOptionValue(sourceFile, property.initializer, optionDefinition);
|
|
1866
1873
|
}
|
|
1867
1874
|
else {
|
|
1868
|
-
const origin =
|
|
1869
|
-
end: property.end,
|
|
1870
|
-
file: configSourceFile,
|
|
1871
|
-
start: this.#skipTrivia(property.pos, configSourceFile),
|
|
1872
|
-
};
|
|
1875
|
+
const origin = DiagnosticOrigin.fromJsonNode(property, sourceFile, this.#skipTrivia);
|
|
1873
1876
|
this.#onDiagnostic(Diagnostic.error(OptionDiagnosticText.unknownOption(optionName), origin));
|
|
1874
1877
|
}
|
|
1875
1878
|
}
|
|
@@ -1878,25 +1881,21 @@ class ConfigFileOptionsWorker {
|
|
|
1878
1881
|
}
|
|
1879
1882
|
async #parseOptionValue(sourceFile, valueExpression, optionDefinition, isListItem = false) {
|
|
1880
1883
|
switch (valueExpression.kind) {
|
|
1881
|
-
case this
|
|
1884
|
+
case this.#compiler.SyntaxKind.TrueKeyword: {
|
|
1882
1885
|
if (optionDefinition.brand === "boolean") {
|
|
1883
1886
|
return true;
|
|
1884
1887
|
}
|
|
1885
1888
|
break;
|
|
1886
1889
|
}
|
|
1887
|
-
case this
|
|
1890
|
+
case this.#compiler.SyntaxKind.FalseKeyword: {
|
|
1888
1891
|
if (optionDefinition.brand === "boolean") {
|
|
1889
1892
|
return false;
|
|
1890
1893
|
}
|
|
1891
1894
|
break;
|
|
1892
1895
|
}
|
|
1893
|
-
case this
|
|
1896
|
+
case this.#compiler.SyntaxKind.StringLiteral: {
|
|
1894
1897
|
if (!this.#isDoubleQuotedString(valueExpression, sourceFile)) {
|
|
1895
|
-
const origin =
|
|
1896
|
-
end: valueExpression.end,
|
|
1897
|
-
file: sourceFile,
|
|
1898
|
-
start: this.#skipTrivia(valueExpression.pos, sourceFile),
|
|
1899
|
-
};
|
|
1898
|
+
const origin = DiagnosticOrigin.fromJsonNode(valueExpression, sourceFile, this.#skipTrivia);
|
|
1900
1899
|
this.#onDiagnostic(Diagnostic.error(OptionDiagnosticText.doubleQuotesExpected(), origin));
|
|
1901
1900
|
return;
|
|
1902
1901
|
}
|
|
@@ -1905,17 +1904,13 @@ class ConfigFileOptionsWorker {
|
|
|
1905
1904
|
if (optionDefinition.name === "rootPath") {
|
|
1906
1905
|
value = Path.resolve(Path.dirname(this.#configFilePath), value);
|
|
1907
1906
|
}
|
|
1908
|
-
const origin =
|
|
1909
|
-
end: valueExpression.end,
|
|
1910
|
-
file: sourceFile,
|
|
1911
|
-
start: this.#skipTrivia(valueExpression.pos, sourceFile),
|
|
1912
|
-
};
|
|
1907
|
+
const origin = DiagnosticOrigin.fromJsonNode(valueExpression, sourceFile, this.#skipTrivia);
|
|
1913
1908
|
await this.#optionValidator.check(optionDefinition.name, value, optionDefinition.brand, origin);
|
|
1914
1909
|
return value;
|
|
1915
1910
|
}
|
|
1916
1911
|
break;
|
|
1917
1912
|
}
|
|
1918
|
-
case this
|
|
1913
|
+
case this.#compiler.SyntaxKind.ArrayLiteralExpression: {
|
|
1919
1914
|
if (optionDefinition.brand === "list") {
|
|
1920
1915
|
const value = [];
|
|
1921
1916
|
for (const element of valueExpression.elements) {
|
|
@@ -1926,14 +1921,10 @@ class ConfigFileOptionsWorker {
|
|
|
1926
1921
|
break;
|
|
1927
1922
|
}
|
|
1928
1923
|
}
|
|
1929
|
-
const origin = {
|
|
1930
|
-
end: valueExpression.end,
|
|
1931
|
-
file: sourceFile,
|
|
1932
|
-
start: this.#skipTrivia(valueExpression.pos, sourceFile),
|
|
1933
|
-
};
|
|
1934
1924
|
const text = isListItem
|
|
1935
1925
|
? OptionDiagnosticText.expectsListItemType(optionDefinition.name, optionDefinition.brand)
|
|
1936
1926
|
: OptionDiagnosticText.requiresValueType(optionDefinition.name, optionDefinition.brand, this.#optionGroup);
|
|
1927
|
+
const origin = DiagnosticOrigin.fromJsonNode(valueExpression, sourceFile, this.#skipTrivia);
|
|
1937
1928
|
this.#onDiagnostic(Diagnostic.error(text, origin));
|
|
1938
1929
|
return;
|
|
1939
1930
|
}
|
|
@@ -1988,14 +1979,14 @@ const defaultOptions = {
|
|
|
1988
1979
|
testFileMatch: ["**/*.tst.*", "**/__typetests__/*.test.*", "**/typetests/*.test.*"],
|
|
1989
1980
|
};
|
|
1990
1981
|
class ConfigService {
|
|
1991
|
-
compiler;
|
|
1992
1982
|
#commandLineOptions = {};
|
|
1983
|
+
#compiler;
|
|
1993
1984
|
#configFileOptions = {};
|
|
1994
1985
|
#configFilePath = Path.resolve(defaultOptions.rootPath, "./tstyche.config.json");
|
|
1995
1986
|
#pathMatch = [];
|
|
1996
1987
|
#storeService;
|
|
1997
1988
|
constructor(compiler, storeService) {
|
|
1998
|
-
this
|
|
1989
|
+
this.#compiler = compiler;
|
|
1999
1990
|
this.#storeService = storeService;
|
|
2000
1991
|
}
|
|
2001
1992
|
#onDiagnostic(diagnostic) {
|
|
@@ -2021,7 +2012,7 @@ class ConfigService {
|
|
|
2021
2012
|
const configFileText = await fs.readFile(this.#configFilePath, {
|
|
2022
2013
|
encoding: "utf8",
|
|
2023
2014
|
});
|
|
2024
|
-
const configFileWorker = new ConfigFileOptionsWorker(this
|
|
2015
|
+
const configFileWorker = new ConfigFileOptionsWorker(this.#compiler, this.#configFileOptions, this.#configFilePath, this.#storeService, this.#onDiagnostic);
|
|
2025
2016
|
await configFileWorker.parse(configFileText);
|
|
2026
2017
|
}
|
|
2027
2018
|
resolveConfig() {
|
|
@@ -2080,16 +2071,16 @@ class Timer {
|
|
|
2080
2071
|
}
|
|
2081
2072
|
|
|
2082
2073
|
class WatchService {
|
|
2083
|
-
resolvedConfig;
|
|
2084
2074
|
#changedTestFiles = new Map();
|
|
2085
2075
|
#inputService;
|
|
2076
|
+
#resolvedConfig;
|
|
2086
2077
|
#runCallback;
|
|
2087
2078
|
#selectService;
|
|
2088
2079
|
#timer = new Timer();
|
|
2089
2080
|
#watchers = [];
|
|
2090
2081
|
#watchedTestFiles;
|
|
2091
2082
|
constructor(resolvedConfig, runCallback, selectService, testFiles) {
|
|
2092
|
-
this
|
|
2083
|
+
this.#resolvedConfig = resolvedConfig;
|
|
2093
2084
|
this.#runCallback = runCallback;
|
|
2094
2085
|
this.#selectService = selectService;
|
|
2095
2086
|
this.#watchedTestFiles = new Map(testFiles.map((testFile) => [testFile.path, testFile]));
|
|
@@ -2157,39 +2148,37 @@ class WatchService {
|
|
|
2157
2148
|
this.#changedTestFiles.delete(filePath);
|
|
2158
2149
|
this.#watchedTestFiles.delete(filePath);
|
|
2159
2150
|
if (this.#watchedTestFiles.size === 0) {
|
|
2160
|
-
this.#onDiagnostic(Diagnostic.error(OptionDiagnosticText.noTestFilesWereLeft(this
|
|
2151
|
+
this.#onDiagnostic(Diagnostic.error(OptionDiagnosticText.noTestFilesWereLeft(this.#resolvedConfig)));
|
|
2161
2152
|
}
|
|
2162
2153
|
};
|
|
2163
|
-
this.#watchers.push(new Watcher(this
|
|
2154
|
+
this.#watchers.push(new Watcher(this.#resolvedConfig.rootPath, onChangedFile, onRemovedFile, { recursive: true }));
|
|
2164
2155
|
const onChangedConfigFile = () => {
|
|
2165
2156
|
cancellationToken?.cancel("configChange");
|
|
2166
2157
|
};
|
|
2167
|
-
this.#watchers.push(new FileWatcher(this
|
|
2158
|
+
this.#watchers.push(new FileWatcher(this.#resolvedConfig.configFilePath, onChangedConfigFile));
|
|
2168
2159
|
return Promise.all(this.#watchers.map((watcher) => watcher.watch()));
|
|
2169
2160
|
}
|
|
2170
2161
|
}
|
|
2171
2162
|
|
|
2172
2163
|
class TestMember {
|
|
2173
2164
|
brand;
|
|
2174
|
-
node;
|
|
2175
|
-
parent;
|
|
2176
|
-
flags;
|
|
2177
|
-
compiler;
|
|
2178
2165
|
diagnostics = new Set();
|
|
2166
|
+
flags;
|
|
2179
2167
|
members = [];
|
|
2180
2168
|
name = "";
|
|
2181
|
-
|
|
2169
|
+
node;
|
|
2170
|
+
parent;
|
|
2171
|
+
constructor(compiler, brand, node, parent, flags) {
|
|
2182
2172
|
this.brand = brand;
|
|
2183
2173
|
this.node = node;
|
|
2184
2174
|
this.parent = parent;
|
|
2185
2175
|
this.flags = flags;
|
|
2186
|
-
|
|
2187
|
-
if (node.arguments[0] != null && this.compiler.isStringLiteralLike(node.arguments[0])) {
|
|
2176
|
+
if (node.arguments[0] != null && compiler.isStringLiteralLike(node.arguments[0])) {
|
|
2188
2177
|
this.name = node.arguments[0].text;
|
|
2189
2178
|
}
|
|
2190
2179
|
if (node.arguments[1] != null &&
|
|
2191
|
-
|
|
2192
|
-
|
|
2180
|
+
compiler.isFunctionLike(node.arguments[1]) &&
|
|
2181
|
+
compiler.isBlock(node.arguments[1].body)) {
|
|
2193
2182
|
const blockStart = node.arguments[1].body.getStart();
|
|
2194
2183
|
const blockEnd = node.arguments[1].body.getEnd();
|
|
2195
2184
|
for (const diagnostic of parent.diagnostics) {
|
|
@@ -2216,11 +2205,7 @@ class TestMember {
|
|
|
2216
2205
|
case "describe": {
|
|
2217
2206
|
for (const member of this.members) {
|
|
2218
2207
|
if (member.brand === "expect") {
|
|
2219
|
-
diagnostics.push(Diagnostic.error(getText(member.node),
|
|
2220
|
-
end: member.node.getEnd(),
|
|
2221
|
-
file: member.node.getSourceFile(),
|
|
2222
|
-
start: member.node.getStart(),
|
|
2223
|
-
}));
|
|
2208
|
+
diagnostics.push(Diagnostic.error(getText(member.node), DiagnosticOrigin.fromNode(member.node)));
|
|
2224
2209
|
}
|
|
2225
2210
|
}
|
|
2226
2211
|
break;
|
|
@@ -2229,11 +2214,7 @@ class TestMember {
|
|
|
2229
2214
|
case "expect": {
|
|
2230
2215
|
for (const member of this.members) {
|
|
2231
2216
|
if (member.brand !== "expect") {
|
|
2232
|
-
diagnostics.push(Diagnostic.error(getText(member.node),
|
|
2233
|
-
end: member.node.getEnd(),
|
|
2234
|
-
file: member.node.getSourceFile(),
|
|
2235
|
-
start: member.node.getStart(),
|
|
2236
|
-
}));
|
|
2217
|
+
diagnostics.push(Diagnostic.error(getText(member.node), DiagnosticOrigin.fromNode(member.node)));
|
|
2237
2218
|
}
|
|
2238
2219
|
}
|
|
2239
2220
|
break;
|
|
@@ -2244,16 +2225,15 @@ class TestMember {
|
|
|
2244
2225
|
}
|
|
2245
2226
|
|
|
2246
2227
|
class Assertion extends TestMember {
|
|
2228
|
+
isNot;
|
|
2247
2229
|
matcherNode;
|
|
2248
2230
|
modifierNode;
|
|
2249
2231
|
notNode;
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2232
|
+
constructor(compiler, brand, node, parent, flags, matcherNode, modifierNode, notNode) {
|
|
2233
|
+
super(compiler, brand, node, parent, flags);
|
|
2234
|
+
this.isNot = notNode != null;
|
|
2253
2235
|
this.matcherNode = matcherNode;
|
|
2254
2236
|
this.modifierNode = modifierNode;
|
|
2255
|
-
this.notNode = notNode;
|
|
2256
|
-
this.isNot = notNode != null;
|
|
2257
2237
|
const argStart = this.source[0]?.getStart();
|
|
2258
2238
|
const argEnd = this.source[0]?.getEnd();
|
|
2259
2239
|
for (const diagnostic of parent.diagnostics) {
|
|
@@ -2295,11 +2275,11 @@ class Assertion extends TestMember {
|
|
|
2295
2275
|
}
|
|
2296
2276
|
|
|
2297
2277
|
class IdentifierLookup {
|
|
2298
|
-
compiler;
|
|
2278
|
+
#compiler;
|
|
2299
2279
|
#identifiers;
|
|
2300
2280
|
#moduleSpecifiers = ['"tstyche"', "'tstyche'"];
|
|
2301
2281
|
constructor(compiler, identifiers) {
|
|
2302
|
-
this
|
|
2282
|
+
this.#compiler = compiler;
|
|
2303
2283
|
this.#identifiers = identifiers ?? {
|
|
2304
2284
|
namedImports: {
|
|
2305
2285
|
describe: undefined,
|
|
@@ -2321,7 +2301,7 @@ class IdentifierLookup {
|
|
|
2321
2301
|
if (this.#moduleSpecifiers.includes(node.moduleSpecifier.getText()) &&
|
|
2322
2302
|
node.importClause?.isTypeOnly !== true &&
|
|
2323
2303
|
node.importClause?.namedBindings != null) {
|
|
2324
|
-
if (this
|
|
2304
|
+
if (this.#compiler.isNamedImports(node.importClause.namedBindings)) {
|
|
2325
2305
|
for (const element of node.importClause.namedBindings.elements) {
|
|
2326
2306
|
if (element.isTypeOnly) {
|
|
2327
2307
|
continue;
|
|
@@ -2338,7 +2318,7 @@ class IdentifierLookup {
|
|
|
2338
2318
|
}
|
|
2339
2319
|
}
|
|
2340
2320
|
}
|
|
2341
|
-
if (this
|
|
2321
|
+
if (this.#compiler.isNamespaceImport(node.importClause.namedBindings)) {
|
|
2342
2322
|
this.#identifiers.namespace = node.importClause.namedBindings.name.getText();
|
|
2343
2323
|
}
|
|
2344
2324
|
}
|
|
@@ -2346,7 +2326,7 @@ class IdentifierLookup {
|
|
|
2346
2326
|
resolveTestMemberMeta(node) {
|
|
2347
2327
|
let flags = 0;
|
|
2348
2328
|
let expression = node.expression;
|
|
2349
|
-
while (this
|
|
2329
|
+
while (this.#compiler.isPropertyAccessExpression(expression)) {
|
|
2350
2330
|
if (expression.expression.getText() === this.#identifiers.namespace) {
|
|
2351
2331
|
break;
|
|
2352
2332
|
}
|
|
@@ -2371,7 +2351,7 @@ class IdentifierLookup {
|
|
|
2371
2351
|
expression = expression.expression;
|
|
2372
2352
|
}
|
|
2373
2353
|
let identifierName;
|
|
2374
|
-
if (this
|
|
2354
|
+
if (this.#compiler.isPropertyAccessExpression(expression) &&
|
|
2375
2355
|
expression.expression.getText() === this.#identifiers.namespace) {
|
|
2376
2356
|
identifierName = expression.name.getText();
|
|
2377
2357
|
}
|
|
@@ -2395,12 +2375,10 @@ class IdentifierLookup {
|
|
|
2395
2375
|
}
|
|
2396
2376
|
|
|
2397
2377
|
class TestTree {
|
|
2398
|
-
compiler;
|
|
2399
2378
|
diagnostics;
|
|
2400
|
-
sourceFile;
|
|
2401
2379
|
members = [];
|
|
2402
|
-
|
|
2403
|
-
|
|
2380
|
+
sourceFile;
|
|
2381
|
+
constructor(diagnostics, sourceFile) {
|
|
2404
2382
|
this.diagnostics = diagnostics;
|
|
2405
2383
|
this.sourceFile = sourceFile;
|
|
2406
2384
|
}
|
|
@@ -2413,8 +2391,8 @@ class TestTree {
|
|
|
2413
2391
|
}
|
|
2414
2392
|
|
|
2415
2393
|
class CollectService {
|
|
2416
|
-
compiler;
|
|
2417
|
-
matcherIdentifiers = [
|
|
2394
|
+
#compiler;
|
|
2395
|
+
#matcherIdentifiers = [
|
|
2418
2396
|
"toBe",
|
|
2419
2397
|
"toBeAny",
|
|
2420
2398
|
"toBeAssignable",
|
|
@@ -2436,69 +2414,69 @@ class CollectService {
|
|
|
2436
2414
|
"toMatch",
|
|
2437
2415
|
"toRaiseError",
|
|
2438
2416
|
];
|
|
2439
|
-
modifierIdentifiers = ["type"];
|
|
2440
|
-
notIdentifier = "not";
|
|
2417
|
+
#modifierIdentifiers = ["type"];
|
|
2418
|
+
#notIdentifier = "not";
|
|
2441
2419
|
constructor(compiler) {
|
|
2442
|
-
this
|
|
2420
|
+
this.#compiler = compiler;
|
|
2443
2421
|
}
|
|
2444
2422
|
#collectTestMembers(node, identifiers, parent) {
|
|
2445
|
-
if (this
|
|
2446
|
-
this
|
|
2447
|
-
this.#collectTestMembers(node, new IdentifierLookup(this
|
|
2423
|
+
if (this.#compiler.isBlock(node)) {
|
|
2424
|
+
this.#compiler.forEachChild(node, (node) => {
|
|
2425
|
+
this.#collectTestMembers(node, new IdentifierLookup(this.#compiler, identifiers.clone()), parent);
|
|
2448
2426
|
});
|
|
2449
2427
|
return;
|
|
2450
2428
|
}
|
|
2451
|
-
if (this
|
|
2429
|
+
if (this.#compiler.isCallExpression(node)) {
|
|
2452
2430
|
const meta = identifiers.resolveTestMemberMeta(node);
|
|
2453
2431
|
if (meta != null && (meta.brand === "describe" || meta.brand === "test")) {
|
|
2454
|
-
const testMember = new TestMember(meta.brand, node, parent, meta.flags);
|
|
2432
|
+
const testMember = new TestMember(this.#compiler, meta.brand, node, parent, meta.flags);
|
|
2455
2433
|
parent.members.push(testMember);
|
|
2456
|
-
this
|
|
2434
|
+
this.#compiler.forEachChild(node, (node) => {
|
|
2457
2435
|
this.#collectTestMembers(node, identifiers, testMember);
|
|
2458
2436
|
});
|
|
2459
2437
|
return;
|
|
2460
2438
|
}
|
|
2461
2439
|
if (meta != null && meta.brand === "expect") {
|
|
2462
|
-
const modifierNode = this.#getMatchingChainNode(node, this
|
|
2440
|
+
const modifierNode = this.#getMatchingChainNode(node, this.#modifierIdentifiers);
|
|
2463
2441
|
if (!modifierNode) {
|
|
2464
2442
|
return;
|
|
2465
2443
|
}
|
|
2466
|
-
const notNode = this.#getMatchingChainNode(modifierNode, [this
|
|
2467
|
-
const matcherNode = this.#getMatchingChainNode(notNode ?? modifierNode, this
|
|
2444
|
+
const notNode = this.#getMatchingChainNode(modifierNode, [this.#notIdentifier]);
|
|
2445
|
+
const matcherNode = this.#getMatchingChainNode(notNode ?? modifierNode, this.#matcherIdentifiers)?.parent;
|
|
2468
2446
|
if (matcherNode == null || !this.#isMatcherNode(matcherNode)) {
|
|
2469
2447
|
return;
|
|
2470
2448
|
}
|
|
2471
|
-
const assertion = new Assertion(meta.brand, node, parent, meta.flags, matcherNode, modifierNode, notNode);
|
|
2449
|
+
const assertion = new Assertion(this.#compiler, meta.brand, node, parent, meta.flags, matcherNode, modifierNode, notNode);
|
|
2472
2450
|
parent.members.push(assertion);
|
|
2473
|
-
this
|
|
2451
|
+
this.#compiler.forEachChild(node, (node) => {
|
|
2474
2452
|
this.#collectTestMembers(node, identifiers, assertion);
|
|
2475
2453
|
});
|
|
2476
2454
|
return;
|
|
2477
2455
|
}
|
|
2478
2456
|
}
|
|
2479
|
-
if (this
|
|
2457
|
+
if (this.#compiler.isImportDeclaration(node)) {
|
|
2480
2458
|
identifiers.handleImportDeclaration(node);
|
|
2481
2459
|
return;
|
|
2482
2460
|
}
|
|
2483
|
-
if (this
|
|
2484
|
-
if (this
|
|
2485
|
-
this
|
|
2461
|
+
if (this.#compiler.isVariableDeclaration(node)) ;
|
|
2462
|
+
if (this.#compiler.isBinaryExpression(node)) ;
|
|
2463
|
+
this.#compiler.forEachChild(node, (node) => {
|
|
2486
2464
|
this.#collectTestMembers(node, identifiers, parent);
|
|
2487
2465
|
});
|
|
2488
2466
|
}
|
|
2489
2467
|
createTestTree(sourceFile, semanticDiagnostics = []) {
|
|
2490
|
-
const testTree = new TestTree(
|
|
2491
|
-
this.#collectTestMembers(sourceFile, new IdentifierLookup(this
|
|
2468
|
+
const testTree = new TestTree(new Set(semanticDiagnostics), sourceFile);
|
|
2469
|
+
this.#collectTestMembers(sourceFile, new IdentifierLookup(this.#compiler), testTree);
|
|
2492
2470
|
return testTree;
|
|
2493
2471
|
}
|
|
2494
2472
|
#getMatchingChainNode({ parent }, name) {
|
|
2495
|
-
if (this
|
|
2473
|
+
if (this.#compiler.isPropertyAccessExpression(parent) && name.includes(parent.name.getText())) {
|
|
2496
2474
|
return parent;
|
|
2497
2475
|
}
|
|
2498
2476
|
return;
|
|
2499
2477
|
}
|
|
2500
2478
|
#isMatcherNode(node) {
|
|
2501
|
-
return this
|
|
2479
|
+
return this.#compiler.isCallExpression(node) && this.#compiler.isPropertyAccessExpression(node.expression);
|
|
2502
2480
|
}
|
|
2503
2481
|
}
|
|
2504
2482
|
|
|
@@ -2518,8 +2496,8 @@ var TestMemberFlags;
|
|
|
2518
2496
|
})(TestMemberFlags || (TestMemberFlags = {}));
|
|
2519
2497
|
|
|
2520
2498
|
class PrimitiveTypeMatcher {
|
|
2521
|
-
typeChecker;
|
|
2522
2499
|
#targetTypeFlag;
|
|
2500
|
+
typeChecker;
|
|
2523
2501
|
constructor(typeChecker, targetTypeFlag) {
|
|
2524
2502
|
this.typeChecker = typeChecker;
|
|
2525
2503
|
this.#targetTypeFlag = targetTypeFlag;
|
|
@@ -2538,8 +2516,8 @@ class PrimitiveTypeMatcher {
|
|
|
2538
2516
|
}
|
|
2539
2517
|
|
|
2540
2518
|
class RelationMatcherBase {
|
|
2541
|
-
typeChecker;
|
|
2542
2519
|
relationExplanationVerb = "is";
|
|
2520
|
+
typeChecker;
|
|
2543
2521
|
constructor(typeChecker) {
|
|
2544
2522
|
this.typeChecker = typeChecker;
|
|
2545
2523
|
}
|
|
@@ -2729,8 +2707,8 @@ class ToRaiseError {
|
|
|
2729
2707
|
}
|
|
2730
2708
|
|
|
2731
2709
|
class Expect {
|
|
2732
|
-
compiler;
|
|
2733
|
-
typeChecker;
|
|
2710
|
+
#compiler;
|
|
2711
|
+
#typeChecker;
|
|
2734
2712
|
toBe;
|
|
2735
2713
|
toBeAny;
|
|
2736
2714
|
toBeAssignable;
|
|
@@ -2752,36 +2730,36 @@ class Expect {
|
|
|
2752
2730
|
toMatch;
|
|
2753
2731
|
toRaiseError;
|
|
2754
2732
|
constructor(compiler, typeChecker) {
|
|
2755
|
-
this
|
|
2756
|
-
this
|
|
2757
|
-
this.toBe = new ToBe(
|
|
2758
|
-
this.toBeAny = new PrimitiveTypeMatcher(
|
|
2759
|
-
this.toBeAssignable = new ToBeAssignableWith(
|
|
2760
|
-
this.toBeAssignableTo = new ToBeAssignableTo(
|
|
2761
|
-
this.toBeAssignableWith = new ToBeAssignableWith(
|
|
2762
|
-
this.toBeBigInt = new PrimitiveTypeMatcher(
|
|
2763
|
-
this.toBeBoolean = new PrimitiveTypeMatcher(
|
|
2764
|
-
this.toBeNever = new PrimitiveTypeMatcher(
|
|
2765
|
-
this.toBeNull = new PrimitiveTypeMatcher(
|
|
2766
|
-
this.toBeNumber = new PrimitiveTypeMatcher(
|
|
2767
|
-
this.toBeString = new PrimitiveTypeMatcher(
|
|
2768
|
-
this.toBeSymbol = new PrimitiveTypeMatcher(
|
|
2769
|
-
this.toBeUndefined = new PrimitiveTypeMatcher(
|
|
2770
|
-
this.toBeUniqueSymbol = new PrimitiveTypeMatcher(
|
|
2771
|
-
this.toBeUnknown = new PrimitiveTypeMatcher(
|
|
2772
|
-
this.toBeVoid = new PrimitiveTypeMatcher(
|
|
2773
|
-
this.toEqual = new ToBe(
|
|
2774
|
-
this.toHaveProperty = new ToHaveProperty(
|
|
2775
|
-
this.toMatch = new ToMatch(
|
|
2776
|
-
this.toRaiseError = new ToRaiseError(
|
|
2733
|
+
this.#compiler = compiler;
|
|
2734
|
+
this.#typeChecker = typeChecker;
|
|
2735
|
+
this.toBe = new ToBe(typeChecker);
|
|
2736
|
+
this.toBeAny = new PrimitiveTypeMatcher(typeChecker, compiler.TypeFlags.Any);
|
|
2737
|
+
this.toBeAssignable = new ToBeAssignableWith(typeChecker);
|
|
2738
|
+
this.toBeAssignableTo = new ToBeAssignableTo(typeChecker);
|
|
2739
|
+
this.toBeAssignableWith = new ToBeAssignableWith(typeChecker);
|
|
2740
|
+
this.toBeBigInt = new PrimitiveTypeMatcher(typeChecker, compiler.TypeFlags.BigInt);
|
|
2741
|
+
this.toBeBoolean = new PrimitiveTypeMatcher(typeChecker, compiler.TypeFlags.Boolean);
|
|
2742
|
+
this.toBeNever = new PrimitiveTypeMatcher(typeChecker, compiler.TypeFlags.Never);
|
|
2743
|
+
this.toBeNull = new PrimitiveTypeMatcher(typeChecker, compiler.TypeFlags.Null);
|
|
2744
|
+
this.toBeNumber = new PrimitiveTypeMatcher(typeChecker, compiler.TypeFlags.Number);
|
|
2745
|
+
this.toBeString = new PrimitiveTypeMatcher(typeChecker, compiler.TypeFlags.String);
|
|
2746
|
+
this.toBeSymbol = new PrimitiveTypeMatcher(typeChecker, compiler.TypeFlags.ESSymbol);
|
|
2747
|
+
this.toBeUndefined = new PrimitiveTypeMatcher(typeChecker, compiler.TypeFlags.Undefined);
|
|
2748
|
+
this.toBeUniqueSymbol = new PrimitiveTypeMatcher(typeChecker, compiler.TypeFlags.UniqueESSymbol);
|
|
2749
|
+
this.toBeUnknown = new PrimitiveTypeMatcher(typeChecker, compiler.TypeFlags.Unknown);
|
|
2750
|
+
this.toBeVoid = new PrimitiveTypeMatcher(typeChecker, compiler.TypeFlags.Void);
|
|
2751
|
+
this.toEqual = new ToBe(typeChecker);
|
|
2752
|
+
this.toHaveProperty = new ToHaveProperty(compiler, typeChecker);
|
|
2753
|
+
this.toMatch = new ToMatch(typeChecker);
|
|
2754
|
+
this.toRaiseError = new ToRaiseError(compiler, typeChecker);
|
|
2777
2755
|
}
|
|
2778
2756
|
static assertTypeChecker(typeChecker) {
|
|
2779
2757
|
return "isTypeRelatedTo" in typeChecker && "relation" in typeChecker;
|
|
2780
2758
|
}
|
|
2781
2759
|
#getType(node) {
|
|
2782
|
-
return this
|
|
2783
|
-
? this
|
|
2784
|
-
: this
|
|
2760
|
+
return this.#compiler.isExpression(node)
|
|
2761
|
+
? this.#typeChecker.getTypeAtLocation(node)
|
|
2762
|
+
: this.#typeChecker.getTypeFromTypeNode(node);
|
|
2785
2763
|
}
|
|
2786
2764
|
#getTypes(nodes) {
|
|
2787
2765
|
return nodes.map((node) => this.#getType(node));
|
|
@@ -2790,10 +2768,10 @@ class Expect {
|
|
|
2790
2768
|
return types.every((type) => this.#isStringOrNumberLiteralType(type));
|
|
2791
2769
|
}
|
|
2792
2770
|
#isStringOrNumberLiteralType(type) {
|
|
2793
|
-
return Boolean(type.flags & this
|
|
2771
|
+
return Boolean(type.flags & this.#compiler.TypeFlags.StringOrNumberLiteral);
|
|
2794
2772
|
}
|
|
2795
2773
|
#isUniqueSymbolType(type) {
|
|
2796
|
-
return Boolean(type.flags & this
|
|
2774
|
+
return Boolean(type.flags & this.#compiler.TypeFlags.UniqueESSymbol);
|
|
2797
2775
|
}
|
|
2798
2776
|
match(assertion, expectResult) {
|
|
2799
2777
|
const matcherNameText = assertion.matcherName.getText();
|
|
@@ -2839,9 +2817,9 @@ class Expect {
|
|
|
2839
2817
|
return;
|
|
2840
2818
|
}
|
|
2841
2819
|
const sourceType = this.#getType(assertion.source[0]);
|
|
2842
|
-
const nonPrimitiveType = { flags: this
|
|
2843
|
-
if (sourceType.flags & (this
|
|
2844
|
-
!this
|
|
2820
|
+
const nonPrimitiveType = { flags: this.#compiler.TypeFlags.NonPrimitive };
|
|
2821
|
+
if (sourceType.flags & (this.#compiler.TypeFlags.Any | this.#compiler.TypeFlags.Never) ||
|
|
2822
|
+
!this.#typeChecker.isTypeRelatedTo(sourceType, nonPrimitiveType, this.#typeChecker.relation.assignable)) {
|
|
2845
2823
|
this.#onSourceArgumentMustBeObjectType(assertion.source[0], expectResult);
|
|
2846
2824
|
return;
|
|
2847
2825
|
}
|
|
@@ -2880,29 +2858,17 @@ class Expect {
|
|
|
2880
2858
|
`'.${matcherNameText}()' is deprecated and will be removed in TSTyche 3.`,
|
|
2881
2859
|
"To learn more, visit https://tstyche.org/release-notes/tstyche-2",
|
|
2882
2860
|
];
|
|
2883
|
-
const origin =
|
|
2884
|
-
end: assertion.matcherName.getEnd(),
|
|
2885
|
-
file: assertion.matcherName.getSourceFile(),
|
|
2886
|
-
start: assertion.matcherName.getStart(),
|
|
2887
|
-
};
|
|
2861
|
+
const origin = DiagnosticOrigin.fromNode(assertion.matcherName);
|
|
2888
2862
|
EventEmitter.dispatch(["deprecation:info", { diagnostics: [Diagnostic.warning(text, origin)] }]);
|
|
2889
2863
|
}
|
|
2890
2864
|
#onKeyArgumentMustBeOfType(node, expectResult) {
|
|
2891
|
-
const receivedTypeText = this
|
|
2865
|
+
const receivedTypeText = this.#typeChecker.typeToString(this.#getType(node));
|
|
2892
2866
|
const text = `An argument for 'key' must be of type 'string | number | symbol', received: '${receivedTypeText}'.`;
|
|
2893
|
-
const origin =
|
|
2894
|
-
end: node.getEnd(),
|
|
2895
|
-
file: node.getSourceFile(),
|
|
2896
|
-
start: node.getStart(),
|
|
2897
|
-
};
|
|
2867
|
+
const origin = DiagnosticOrigin.fromNode(node);
|
|
2898
2868
|
EventEmitter.dispatch(["expect:error", { diagnostics: [Diagnostic.error(text, origin)], result: expectResult }]);
|
|
2899
2869
|
}
|
|
2900
2870
|
#onKeyArgumentMustBeProvided(assertion, expectResult) {
|
|
2901
|
-
const origin =
|
|
2902
|
-
end: assertion.matcherName.getEnd(),
|
|
2903
|
-
file: assertion.matcherName.getSourceFile(),
|
|
2904
|
-
start: assertion.matcherName.getStart(),
|
|
2905
|
-
};
|
|
2871
|
+
const origin = DiagnosticOrigin.fromNode(assertion.matcherName);
|
|
2906
2872
|
EventEmitter.dispatch([
|
|
2907
2873
|
"expect:error",
|
|
2908
2874
|
{
|
|
@@ -2913,11 +2879,7 @@ class Expect {
|
|
|
2913
2879
|
}
|
|
2914
2880
|
#onNotSupportedMatcherName(assertion, expectResult) {
|
|
2915
2881
|
const matcherNameText = assertion.matcherName.getText();
|
|
2916
|
-
const origin =
|
|
2917
|
-
end: assertion.matcherName.getEnd(),
|
|
2918
|
-
file: assertion.matcherName.getSourceFile(),
|
|
2919
|
-
start: assertion.matcherName.getStart(),
|
|
2920
|
-
};
|
|
2882
|
+
const origin = DiagnosticOrigin.fromNode(assertion.matcherName);
|
|
2921
2883
|
EventEmitter.dispatch([
|
|
2922
2884
|
"expect:error",
|
|
2923
2885
|
{
|
|
@@ -2927,22 +2889,14 @@ class Expect {
|
|
|
2927
2889
|
]);
|
|
2928
2890
|
}
|
|
2929
2891
|
#onSourceArgumentMustBeObjectType(node, expectResult) {
|
|
2930
|
-
const sourceText = this
|
|
2931
|
-
const receivedTypeText = this
|
|
2892
|
+
const sourceText = this.#compiler.isTypeNode(node) ? "A type argument for 'Source'" : "An argument for 'source'";
|
|
2893
|
+
const receivedTypeText = this.#typeChecker.typeToString(this.#getType(node));
|
|
2932
2894
|
const text = `${sourceText} must be of an object type, received: '${receivedTypeText}'.`;
|
|
2933
|
-
const origin =
|
|
2934
|
-
end: node.getEnd(),
|
|
2935
|
-
file: node.getSourceFile(),
|
|
2936
|
-
start: node.getStart(),
|
|
2937
|
-
};
|
|
2895
|
+
const origin = DiagnosticOrigin.fromNode(node);
|
|
2938
2896
|
EventEmitter.dispatch(["expect:error", { diagnostics: [Diagnostic.error(text, origin)], result: expectResult }]);
|
|
2939
2897
|
}
|
|
2940
2898
|
#onSourceArgumentMustBeProvided(assertion, expectResult) {
|
|
2941
|
-
const origin =
|
|
2942
|
-
end: assertion.node.getEnd(),
|
|
2943
|
-
file: assertion.node.getSourceFile(),
|
|
2944
|
-
start: assertion.node.getStart(),
|
|
2945
|
-
};
|
|
2899
|
+
const origin = DiagnosticOrigin.fromNode(assertion.node);
|
|
2946
2900
|
EventEmitter.dispatch([
|
|
2947
2901
|
"expect:error",
|
|
2948
2902
|
{
|
|
@@ -2954,11 +2908,7 @@ class Expect {
|
|
|
2954
2908
|
]);
|
|
2955
2909
|
}
|
|
2956
2910
|
#onTargetArgumentMustBeProvided(assertion, expectResult) {
|
|
2957
|
-
const origin =
|
|
2958
|
-
end: assertion.matcherName.getEnd(),
|
|
2959
|
-
file: assertion.matcherName.getSourceFile(),
|
|
2960
|
-
start: assertion.matcherName.getStart(),
|
|
2961
|
-
};
|
|
2911
|
+
const origin = DiagnosticOrigin.fromNode(assertion.matcherName);
|
|
2962
2912
|
EventEmitter.dispatch([
|
|
2963
2913
|
"expect:error",
|
|
2964
2914
|
{
|
|
@@ -2974,12 +2924,8 @@ class Expect {
|
|
|
2974
2924
|
for (const node of nodes) {
|
|
2975
2925
|
const receivedType = this.#getType(node);
|
|
2976
2926
|
if (!this.#isStringOrNumberLiteralType(receivedType)) {
|
|
2977
|
-
const receivedTypeText = this
|
|
2978
|
-
const origin =
|
|
2979
|
-
end: node.getEnd(),
|
|
2980
|
-
file: node.getSourceFile(),
|
|
2981
|
-
start: node.getStart(),
|
|
2982
|
-
};
|
|
2927
|
+
const receivedTypeText = this.#typeChecker.typeToString(this.#getType(node));
|
|
2928
|
+
const origin = DiagnosticOrigin.fromNode(node);
|
|
2983
2929
|
diagnostics.push(Diagnostic.error(`An argument for 'target' must be of type 'string | number', received: '${receivedTypeText}'.`, origin));
|
|
2984
2930
|
}
|
|
2985
2931
|
}
|
|
@@ -3019,10 +2965,10 @@ class Version {
|
|
|
3019
2965
|
}
|
|
3020
2966
|
|
|
3021
2967
|
class ProjectService {
|
|
3022
|
-
compiler;
|
|
2968
|
+
#compiler;
|
|
3023
2969
|
#service;
|
|
3024
2970
|
constructor(compiler) {
|
|
3025
|
-
this
|
|
2971
|
+
this.#compiler = compiler;
|
|
3026
2972
|
function doNothing() {
|
|
3027
2973
|
}
|
|
3028
2974
|
function returnFalse() {
|
|
@@ -3044,7 +2990,7 @@ class ProjectService {
|
|
|
3044
2990
|
startGroup: doNothing,
|
|
3045
2991
|
};
|
|
3046
2992
|
const host = {
|
|
3047
|
-
...this
|
|
2993
|
+
...this.#compiler.sys,
|
|
3048
2994
|
clearImmediate,
|
|
3049
2995
|
clearTimeout,
|
|
3050
2996
|
setImmediate,
|
|
@@ -3052,9 +2998,9 @@ class ProjectService {
|
|
|
3052
2998
|
watchDirectory: () => noopWatcher,
|
|
3053
2999
|
watchFile: () => noopWatcher,
|
|
3054
3000
|
};
|
|
3055
|
-
this.#service = new this
|
|
3001
|
+
this.#service = new this.#compiler.server.ProjectService({
|
|
3056
3002
|
allowLocalPluginLoads: true,
|
|
3057
|
-
cancellationToken: this
|
|
3003
|
+
cancellationToken: this.#compiler.server.nullCancellationToken,
|
|
3058
3004
|
host,
|
|
3059
3005
|
logger: noopLogger,
|
|
3060
3006
|
session: undefined,
|
|
@@ -3079,17 +3025,17 @@ class ProjectService {
|
|
|
3079
3025
|
strictNullChecks: true,
|
|
3080
3026
|
target: "esnext",
|
|
3081
3027
|
};
|
|
3082
|
-
if (Version.isSatisfiedWith(this
|
|
3028
|
+
if (Version.isSatisfiedWith(this.#compiler.version, "5.4")) {
|
|
3083
3029
|
defaultCompilerOptions.module = "preserve";
|
|
3084
3030
|
}
|
|
3085
|
-
if (Version.isSatisfiedWith(this
|
|
3031
|
+
if (Version.isSatisfiedWith(this.#compiler.version, "5.0")) {
|
|
3086
3032
|
defaultCompilerOptions["allowImportingTsExtensions"] = true;
|
|
3087
3033
|
defaultCompilerOptions.moduleResolution = "bundler";
|
|
3088
3034
|
}
|
|
3089
3035
|
return defaultCompilerOptions;
|
|
3090
3036
|
}
|
|
3091
3037
|
getDefaultProject(filePath) {
|
|
3092
|
-
return this.#service.getDefaultProjectForFile(this
|
|
3038
|
+
return this.#service.getDefaultProjectForFile(this.#compiler.server.toNormalizedPath(filePath), true);
|
|
3093
3039
|
}
|
|
3094
3040
|
getLanguageService(filePath) {
|
|
3095
3041
|
const project = this.getDefaultProject(filePath);
|
|
@@ -3102,30 +3048,30 @@ class ProjectService {
|
|
|
3102
3048
|
const { configFileErrors, configFileName } = this.#service.openClientFile(filePath, sourceText, undefined, projectRootPath);
|
|
3103
3049
|
EventEmitter.dispatch([
|
|
3104
3050
|
"project:info",
|
|
3105
|
-
{ compilerVersion: this
|
|
3051
|
+
{ compilerVersion: this.#compiler.version, projectConfigFilePath: configFileName },
|
|
3106
3052
|
]);
|
|
3107
3053
|
if (configFileErrors && configFileErrors.length > 0) {
|
|
3108
3054
|
EventEmitter.dispatch([
|
|
3109
3055
|
"project:error",
|
|
3110
|
-
{ diagnostics: Diagnostic.fromDiagnostics(configFileErrors, this
|
|
3056
|
+
{ diagnostics: Diagnostic.fromDiagnostics(configFileErrors, this.#compiler) },
|
|
3111
3057
|
]);
|
|
3112
3058
|
}
|
|
3113
3059
|
}
|
|
3114
3060
|
}
|
|
3115
3061
|
|
|
3116
3062
|
class TestTreeWorker {
|
|
3117
|
-
|
|
3118
|
-
compiler;
|
|
3063
|
+
#compiler;
|
|
3119
3064
|
#cancellationToken;
|
|
3120
3065
|
#expect;
|
|
3121
3066
|
#fileResult;
|
|
3122
3067
|
#hasOnly;
|
|
3123
3068
|
#position;
|
|
3069
|
+
#resolvedConfig;
|
|
3124
3070
|
constructor(resolvedConfig, compiler, expect, options) {
|
|
3125
|
-
this
|
|
3126
|
-
this
|
|
3127
|
-
this.#cancellationToken = options.cancellationToken;
|
|
3071
|
+
this.#resolvedConfig = resolvedConfig;
|
|
3072
|
+
this.#compiler = compiler;
|
|
3128
3073
|
this.#expect = expect;
|
|
3074
|
+
this.#cancellationToken = options.cancellationToken;
|
|
3129
3075
|
this.#fileResult = options.fileResult;
|
|
3130
3076
|
this.#hasOnly = options.hasOnly || resolvedConfig.only != null || options.position != null;
|
|
3131
3077
|
this.#position = options.position;
|
|
@@ -3135,11 +3081,11 @@ class TestTreeWorker {
|
|
|
3135
3081
|
mode |= 1;
|
|
3136
3082
|
}
|
|
3137
3083
|
if (member.flags & 2 ||
|
|
3138
|
-
(this
|
|
3084
|
+
(this.#resolvedConfig.only != null && member.name.toLowerCase().includes(this.#resolvedConfig.only.toLowerCase()))) {
|
|
3139
3085
|
mode |= 2;
|
|
3140
3086
|
}
|
|
3141
3087
|
if (member.flags & 4 ||
|
|
3142
|
-
(this
|
|
3088
|
+
(this.#resolvedConfig.skip != null && member.name.toLowerCase().includes(this.#resolvedConfig.skip.toLowerCase()))) {
|
|
3143
3089
|
mode |= 4;
|
|
3144
3090
|
}
|
|
3145
3091
|
if (member.flags & 8) {
|
|
@@ -3196,7 +3142,7 @@ class TestTreeWorker {
|
|
|
3196
3142
|
EventEmitter.dispatch([
|
|
3197
3143
|
"expect:error",
|
|
3198
3144
|
{
|
|
3199
|
-
diagnostics: Diagnostic.fromDiagnostics([...assertion.diagnostics], this
|
|
3145
|
+
diagnostics: Diagnostic.fromDiagnostics([...assertion.diagnostics], this.#compiler),
|
|
3200
3146
|
result: expectResult,
|
|
3201
3147
|
},
|
|
3202
3148
|
]);
|
|
@@ -3209,11 +3155,7 @@ class TestTreeWorker {
|
|
|
3209
3155
|
if (assertion.isNot ? !matchResult.isMatch : matchResult.isMatch) {
|
|
3210
3156
|
if (runMode & 1) {
|
|
3211
3157
|
const text = ["The assertion was supposed to fail, but it passed.", "Consider removing the '.fail' flag."];
|
|
3212
|
-
const origin =
|
|
3213
|
-
end: assertion.node.getEnd(),
|
|
3214
|
-
file: assertion.node.getSourceFile(),
|
|
3215
|
-
start: assertion.node.getStart(),
|
|
3216
|
-
};
|
|
3158
|
+
const origin = DiagnosticOrigin.fromNode(assertion.node);
|
|
3217
3159
|
EventEmitter.dispatch([
|
|
3218
3160
|
"expect:error",
|
|
3219
3161
|
{ diagnostics: [Diagnostic.error(text, origin)], result: expectResult },
|
|
@@ -3227,19 +3169,13 @@ class TestTreeWorker {
|
|
|
3227
3169
|
EventEmitter.dispatch(["expect:pass", { result: expectResult }]);
|
|
3228
3170
|
}
|
|
3229
3171
|
else {
|
|
3230
|
-
const origin =
|
|
3231
|
-
|
|
3232
|
-
end: assertion.matcherName.getEnd(),
|
|
3233
|
-
file: assertion.matcherName.getSourceFile(),
|
|
3234
|
-
start: assertion.matcherName.getStart(),
|
|
3235
|
-
};
|
|
3236
|
-
const diagnostics = [];
|
|
3237
|
-
for (const diagnostic of matchResult.explain()) {
|
|
3172
|
+
const origin = DiagnosticOrigin.fromNode(assertion.matcherName, assertion.ancestorNames);
|
|
3173
|
+
const diagnostics = matchResult.explain().map((diagnostic) => {
|
|
3238
3174
|
if (diagnostic.origin == null) {
|
|
3239
|
-
diagnostic.add({ origin });
|
|
3175
|
+
return diagnostic.add({ origin });
|
|
3240
3176
|
}
|
|
3241
|
-
|
|
3242
|
-
}
|
|
3177
|
+
return diagnostic;
|
|
3178
|
+
});
|
|
3243
3179
|
EventEmitter.dispatch(["expect:fail", { diagnostics, result: expectResult }]);
|
|
3244
3180
|
}
|
|
3245
3181
|
}
|
|
@@ -3252,7 +3188,7 @@ class TestTreeWorker {
|
|
|
3252
3188
|
EventEmitter.dispatch([
|
|
3253
3189
|
"file:error",
|
|
3254
3190
|
{
|
|
3255
|
-
diagnostics: Diagnostic.fromDiagnostics([...describe.diagnostics], this
|
|
3191
|
+
diagnostics: Diagnostic.fromDiagnostics([...describe.diagnostics], this.#compiler),
|
|
3256
3192
|
result: this.#fileResult,
|
|
3257
3193
|
},
|
|
3258
3194
|
]);
|
|
@@ -3274,7 +3210,7 @@ class TestTreeWorker {
|
|
|
3274
3210
|
EventEmitter.dispatch([
|
|
3275
3211
|
"test:error",
|
|
3276
3212
|
{
|
|
3277
|
-
diagnostics: Diagnostic.fromDiagnostics([...test.diagnostics], this
|
|
3213
|
+
diagnostics: Diagnostic.fromDiagnostics([...test.diagnostics], this.#compiler),
|
|
3278
3214
|
result: testResult,
|
|
3279
3215
|
},
|
|
3280
3216
|
]);
|
|
@@ -3295,13 +3231,13 @@ class TestTreeWorker {
|
|
|
3295
3231
|
}
|
|
3296
3232
|
|
|
3297
3233
|
class TestFileRunner {
|
|
3298
|
-
|
|
3299
|
-
compiler;
|
|
3234
|
+
#compiler;
|
|
3300
3235
|
#collectService;
|
|
3236
|
+
#resolvedConfig;
|
|
3301
3237
|
#projectService;
|
|
3302
3238
|
constructor(resolvedConfig, compiler) {
|
|
3303
|
-
this
|
|
3304
|
-
this
|
|
3239
|
+
this.#resolvedConfig = resolvedConfig;
|
|
3240
|
+
this.#compiler = compiler;
|
|
3305
3241
|
this.#collectService = new CollectService(compiler);
|
|
3306
3242
|
this.#projectService = new ProjectService(compiler);
|
|
3307
3243
|
}
|
|
@@ -3309,7 +3245,7 @@ class TestFileRunner {
|
|
|
3309
3245
|
if (cancellationToken?.isCancellationRequested === true) {
|
|
3310
3246
|
return;
|
|
3311
3247
|
}
|
|
3312
|
-
this.#projectService.openFile(testFile.path, undefined, this
|
|
3248
|
+
this.#projectService.openFile(testFile.path, undefined, this.#resolvedConfig.rootPath);
|
|
3313
3249
|
const fileResult = new FileResult(testFile);
|
|
3314
3250
|
EventEmitter.dispatch(["file:start", { result: fileResult }]);
|
|
3315
3251
|
this.#runFile(testFile, fileResult, cancellationToken);
|
|
@@ -3326,7 +3262,7 @@ class TestFileRunner {
|
|
|
3326
3262
|
EventEmitter.dispatch([
|
|
3327
3263
|
"file:error",
|
|
3328
3264
|
{
|
|
3329
|
-
diagnostics: Diagnostic.fromDiagnostics(syntacticDiagnostics, this
|
|
3265
|
+
diagnostics: Diagnostic.fromDiagnostics(syntacticDiagnostics, this.#compiler),
|
|
3330
3266
|
result: fileResult,
|
|
3331
3267
|
},
|
|
3332
3268
|
]);
|
|
@@ -3346,7 +3282,7 @@ class TestFileRunner {
|
|
|
3346
3282
|
EventEmitter.dispatch([
|
|
3347
3283
|
"file:error",
|
|
3348
3284
|
{
|
|
3349
|
-
diagnostics: Diagnostic.fromDiagnostics([...testTree.diagnostics], this
|
|
3285
|
+
diagnostics: Diagnostic.fromDiagnostics([...testTree.diagnostics], this.#compiler),
|
|
3350
3286
|
result: fileResult,
|
|
3351
3287
|
},
|
|
3352
3288
|
]);
|
|
@@ -3358,8 +3294,8 @@ class TestFileRunner {
|
|
|
3358
3294
|
EventEmitter.dispatch(["file:error", { diagnostics: [Diagnostic.error(text)], result: fileResult }]);
|
|
3359
3295
|
return;
|
|
3360
3296
|
}
|
|
3361
|
-
const expect = new Expect(this
|
|
3362
|
-
const testTreeWorker = new TestTreeWorker(this
|
|
3297
|
+
const expect = new Expect(this.#compiler, typeChecker);
|
|
3298
|
+
const testTreeWorker = new TestTreeWorker(this.#resolvedConfig, this.#compiler, expect, {
|
|
3363
3299
|
cancellationToken,
|
|
3364
3300
|
fileResult,
|
|
3365
3301
|
hasOnly: testTree.hasOnly,
|
|
@@ -3370,12 +3306,12 @@ class TestFileRunner {
|
|
|
3370
3306
|
}
|
|
3371
3307
|
|
|
3372
3308
|
class TaskRunner {
|
|
3373
|
-
resolvedConfig;
|
|
3374
3309
|
#eventEmitter = new EventEmitter();
|
|
3310
|
+
#resolvedConfig;
|
|
3375
3311
|
#selectService;
|
|
3376
3312
|
#storeService;
|
|
3377
3313
|
constructor(resolvedConfig, selectService, storeService) {
|
|
3378
|
-
this
|
|
3314
|
+
this.#resolvedConfig = resolvedConfig;
|
|
3379
3315
|
this.#selectService = selectService;
|
|
3380
3316
|
this.#storeService = storeService;
|
|
3381
3317
|
this.#eventEmitter.addHandler(new ResultHandler());
|
|
@@ -3385,11 +3321,11 @@ class TaskRunner {
|
|
|
3385
3321
|
}
|
|
3386
3322
|
async run(testFiles, cancellationToken = new CancellationToken()) {
|
|
3387
3323
|
let cancellationHandler;
|
|
3388
|
-
if (this
|
|
3324
|
+
if (this.#resolvedConfig.failFast) {
|
|
3389
3325
|
cancellationHandler = new CancellationHandler(cancellationToken, "failFast");
|
|
3390
3326
|
this.#eventEmitter.addHandler(cancellationHandler);
|
|
3391
3327
|
}
|
|
3392
|
-
if (this
|
|
3328
|
+
if (this.#resolvedConfig.watch === true) {
|
|
3393
3329
|
await this.#watch(testFiles, cancellationToken);
|
|
3394
3330
|
}
|
|
3395
3331
|
else {
|
|
@@ -3400,14 +3336,14 @@ class TaskRunner {
|
|
|
3400
3336
|
}
|
|
3401
3337
|
}
|
|
3402
3338
|
async #run(testFiles, cancellationToken) {
|
|
3403
|
-
const result = new Result(this
|
|
3339
|
+
const result = new Result(this.#resolvedConfig, testFiles);
|
|
3404
3340
|
EventEmitter.dispatch(["run:start", { result }]);
|
|
3405
|
-
for (const versionTag of this
|
|
3341
|
+
for (const versionTag of this.#resolvedConfig.target) {
|
|
3406
3342
|
const targetResult = new TargetResult(versionTag, testFiles);
|
|
3407
3343
|
EventEmitter.dispatch(["target:start", { result: targetResult }]);
|
|
3408
3344
|
const compiler = await this.#storeService.load(versionTag, cancellationToken);
|
|
3409
3345
|
if (compiler) {
|
|
3410
|
-
const testFileRunner = new TestFileRunner(this
|
|
3346
|
+
const testFileRunner = new TestFileRunner(this.#resolvedConfig, compiler);
|
|
3411
3347
|
for (const testFile of testFiles) {
|
|
3412
3348
|
testFileRunner.run(testFile, cancellationToken);
|
|
3413
3349
|
}
|
|
@@ -3424,7 +3360,7 @@ class TaskRunner {
|
|
|
3424
3360
|
const runCallback = async (testFiles) => {
|
|
3425
3361
|
await this.#run(testFiles, cancellationToken);
|
|
3426
3362
|
};
|
|
3427
|
-
const watchModeManager = new WatchService(this
|
|
3363
|
+
const watchModeManager = new WatchService(this.#resolvedConfig, runCallback, this.#selectService, testFiles);
|
|
3428
3364
|
cancellationToken?.onCancellationRequested((reason) => {
|
|
3429
3365
|
if (reason !== "failFast") {
|
|
3430
3366
|
watchModeManager.close();
|
|
@@ -3435,26 +3371,26 @@ class TaskRunner {
|
|
|
3435
3371
|
}
|
|
3436
3372
|
|
|
3437
3373
|
class TSTyche {
|
|
3438
|
-
resolvedConfig;
|
|
3439
3374
|
#eventEmitter = new EventEmitter();
|
|
3440
3375
|
#outputService;
|
|
3376
|
+
#resolvedConfig;
|
|
3441
3377
|
#selectService;
|
|
3442
3378
|
#storeService;
|
|
3443
3379
|
#taskRunner;
|
|
3444
|
-
static version = "2.0.0-
|
|
3380
|
+
static version = "2.0.0-rc.1";
|
|
3445
3381
|
constructor(resolvedConfig, outputService, selectService, storeService) {
|
|
3446
|
-
this
|
|
3382
|
+
this.#resolvedConfig = resolvedConfig;
|
|
3447
3383
|
this.#outputService = outputService;
|
|
3448
3384
|
this.#selectService = selectService;
|
|
3449
3385
|
this.#storeService = storeService;
|
|
3450
|
-
this.#taskRunner = new TaskRunner(this
|
|
3386
|
+
this.#taskRunner = new TaskRunner(this.#resolvedConfig, this.#selectService, this.#storeService);
|
|
3451
3387
|
}
|
|
3452
3388
|
close() {
|
|
3453
3389
|
this.#taskRunner.close();
|
|
3454
3390
|
}
|
|
3455
3391
|
async run(testFiles, cancellationToken = new CancellationToken()) {
|
|
3456
|
-
this.#eventEmitter.addHandler(new RuntimeReporter(this
|
|
3457
|
-
if (this
|
|
3392
|
+
this.#eventEmitter.addHandler(new RuntimeReporter(this.#resolvedConfig, this.#outputService));
|
|
3393
|
+
if (this.#resolvedConfig.watch === true) {
|
|
3458
3394
|
this.#eventEmitter.addHandler(new WatchReporter(this.#outputService));
|
|
3459
3395
|
}
|
|
3460
3396
|
else {
|
|
@@ -3472,6 +3408,9 @@ class GlobPattern {
|
|
|
3472
3408
|
let resultPattern = "\\.";
|
|
3473
3409
|
let optionalSegmentCount = 0;
|
|
3474
3410
|
for (const segment of segments) {
|
|
3411
|
+
if (segment === ".") {
|
|
3412
|
+
continue;
|
|
3413
|
+
}
|
|
3475
3414
|
if (segment === "**") {
|
|
3476
3415
|
resultPattern += "(\\/(?!(node_modules)(\\/|$))[^./][^/]*)*?";
|
|
3477
3416
|
continue;
|
|
@@ -3507,11 +3446,11 @@ class GlobPattern {
|
|
|
3507
3446
|
}
|
|
3508
3447
|
|
|
3509
3448
|
class SelectService {
|
|
3510
|
-
resolvedConfig;
|
|
3511
3449
|
#includeDirectoryRegex;
|
|
3512
3450
|
#includeFileRegex;
|
|
3451
|
+
#resolvedConfig;
|
|
3513
3452
|
constructor(resolvedConfig) {
|
|
3514
|
-
this
|
|
3453
|
+
this.#resolvedConfig = resolvedConfig;
|
|
3515
3454
|
this.#includeDirectoryRegex = GlobPattern.toRegex(resolvedConfig.testFileMatch, "directories");
|
|
3516
3455
|
this.#includeFileRegex = GlobPattern.toRegex(resolvedConfig.testFileMatch, "files");
|
|
3517
3456
|
}
|
|
@@ -3519,14 +3458,14 @@ class SelectService {
|
|
|
3519
3458
|
return this.#includeDirectoryRegex.test(directoryPath);
|
|
3520
3459
|
}
|
|
3521
3460
|
#isFileIncluded(filePath) {
|
|
3522
|
-
if (this
|
|
3523
|
-
!this
|
|
3461
|
+
if (this.#resolvedConfig.pathMatch.length > 0 &&
|
|
3462
|
+
!this.#resolvedConfig.pathMatch.some((match) => filePath.toLowerCase().includes(match.toLowerCase()))) {
|
|
3524
3463
|
return false;
|
|
3525
3464
|
}
|
|
3526
3465
|
return this.#includeFileRegex.test(filePath);
|
|
3527
3466
|
}
|
|
3528
3467
|
isTestFile(filePath) {
|
|
3529
|
-
return this.#isFileIncluded(Path.relative(this
|
|
3468
|
+
return this.#isFileIncluded(Path.relative(this.#resolvedConfig.rootPath, filePath));
|
|
3530
3469
|
}
|
|
3531
3470
|
#onDiagnostic(diagnostic) {
|
|
3532
3471
|
EventEmitter.dispatch(["select:error", { diagnostics: [diagnostic] }]);
|
|
@@ -3536,12 +3475,12 @@ class SelectService {
|
|
|
3536
3475
|
const testFilePaths = [];
|
|
3537
3476
|
await this.#visitDirectory(currentPath, testFilePaths);
|
|
3538
3477
|
if (testFilePaths.length === 0) {
|
|
3539
|
-
this.#onDiagnostic(Diagnostic.error(OptionDiagnosticText.noTestFilesWereSelected(this
|
|
3478
|
+
this.#onDiagnostic(Diagnostic.error(OptionDiagnosticText.noTestFilesWereSelected(this.#resolvedConfig)));
|
|
3540
3479
|
}
|
|
3541
3480
|
return testFilePaths.sort();
|
|
3542
3481
|
}
|
|
3543
3482
|
async #visitDirectory(currentPath, testFilePaths) {
|
|
3544
|
-
const targetPath = Path.join(this
|
|
3483
|
+
const targetPath = Path.join(this.#resolvedConfig.rootPath, currentPath);
|
|
3545
3484
|
let entries = [];
|
|
3546
3485
|
try {
|
|
3547
3486
|
entries = await fs.readdir(targetPath, { withFileTypes: true });
|
|
@@ -3573,6 +3512,21 @@ class SelectService {
|
|
|
3573
3512
|
}
|
|
3574
3513
|
}
|
|
3575
3514
|
|
|
3515
|
+
class StoreDiagnosticText {
|
|
3516
|
+
static failedToFetchMetadata(registryUrl) {
|
|
3517
|
+
return `Failed to fetch metadata of the 'typescript' package from '${registryUrl.toString()}'.`;
|
|
3518
|
+
}
|
|
3519
|
+
static failedWithStatusCode(code) {
|
|
3520
|
+
return `Request failed with status code ${String(code)}.`;
|
|
3521
|
+
}
|
|
3522
|
+
static maybeNetworkConnectionIssue() {
|
|
3523
|
+
return "Might be there is an issue with the registry or the network connection.";
|
|
3524
|
+
}
|
|
3525
|
+
static setupTimeoutExceeded(timeout) {
|
|
3526
|
+
return `Setup timeout of ${String(timeout / 1000)}s was exceeded.`;
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
|
|
3576
3530
|
class ManifestWorker {
|
|
3577
3531
|
#manifestFileName = "store-manifest.json";
|
|
3578
3532
|
#manifestFilePath;
|
|
@@ -3593,35 +3547,6 @@ class ManifestWorker {
|
|
|
3593
3547
|
}
|
|
3594
3548
|
return manifest;
|
|
3595
3549
|
}
|
|
3596
|
-
async #fetch() {
|
|
3597
|
-
return new Promise((resolve, reject) => {
|
|
3598
|
-
const request = https.get(new URL("typescript", this.#registryUrl), {
|
|
3599
|
-
headers: { accept: "application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*" },
|
|
3600
|
-
timeout: this.#timeout,
|
|
3601
|
-
}, (response) => {
|
|
3602
|
-
if (response.statusCode !== 200) {
|
|
3603
|
-
reject(new Error(`Request failed with status code ${String(response.statusCode)}.`));
|
|
3604
|
-
response.resume();
|
|
3605
|
-
return;
|
|
3606
|
-
}
|
|
3607
|
-
response.setEncoding("utf8");
|
|
3608
|
-
let rawData = "";
|
|
3609
|
-
response.on("data", (chunk) => {
|
|
3610
|
-
rawData += chunk;
|
|
3611
|
-
});
|
|
3612
|
-
response.on("end", () => {
|
|
3613
|
-
const packageMetadata = JSON.parse(rawData);
|
|
3614
|
-
resolve(packageMetadata);
|
|
3615
|
-
});
|
|
3616
|
-
});
|
|
3617
|
-
request.on("error", (error) => {
|
|
3618
|
-
reject(error);
|
|
3619
|
-
});
|
|
3620
|
-
request.on("timeout", () => {
|
|
3621
|
-
request.destroy();
|
|
3622
|
-
});
|
|
3623
|
-
});
|
|
3624
|
-
}
|
|
3625
3550
|
isOutdated(manifest, ageTolerance = 0) {
|
|
3626
3551
|
if (Date.now() - manifest.lastUpdated > 2 * 60 * 60 * 1000 + ageTolerance * 1000) {
|
|
3627
3552
|
return true;
|
|
@@ -3637,20 +3562,35 @@ class ManifestWorker {
|
|
|
3637
3562
|
};
|
|
3638
3563
|
let packageMetadata;
|
|
3639
3564
|
try {
|
|
3640
|
-
|
|
3565
|
+
const response = await fetch(new URL("typescript", this.#registryUrl), {
|
|
3566
|
+
headers: { accept: "application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*" },
|
|
3567
|
+
signal: AbortSignal.timeout(this.#timeout),
|
|
3568
|
+
});
|
|
3569
|
+
if (!response.ok) {
|
|
3570
|
+
this.#onDiagnostic(Diagnostic.error([
|
|
3571
|
+
StoreDiagnosticText.failedToFetchMetadata(this.#registryUrl),
|
|
3572
|
+
StoreDiagnosticText.failedWithStatusCode(response.status),
|
|
3573
|
+
]));
|
|
3574
|
+
return;
|
|
3575
|
+
}
|
|
3576
|
+
packageMetadata = (await response.json());
|
|
3641
3577
|
}
|
|
3642
3578
|
catch (error) {
|
|
3643
3579
|
if (options?.quite === true) {
|
|
3644
3580
|
return;
|
|
3645
3581
|
}
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3582
|
+
if (error instanceof Error && error.name === "TimeoutError") {
|
|
3583
|
+
this.#onDiagnostic(Diagnostic.error([
|
|
3584
|
+
StoreDiagnosticText.failedToFetchMetadata(this.#registryUrl),
|
|
3585
|
+
StoreDiagnosticText.setupTimeoutExceeded(this.#timeout),
|
|
3586
|
+
]));
|
|
3649
3587
|
}
|
|
3650
3588
|
else {
|
|
3651
|
-
|
|
3589
|
+
this.#onDiagnostic(Diagnostic.error([
|
|
3590
|
+
StoreDiagnosticText.failedToFetchMetadata(this.#registryUrl),
|
|
3591
|
+
StoreDiagnosticText.maybeNetworkConnectionIssue(),
|
|
3592
|
+
]));
|
|
3652
3593
|
}
|
|
3653
|
-
this.#onDiagnostic(Diagnostic.fromError(text, error));
|
|
3654
3594
|
return;
|
|
3655
3595
|
}
|
|
3656
3596
|
manifest.versions = Object.keys(packageMetadata.versions)
|
|
@@ -4068,10 +4008,10 @@ class Cli {
|
|
|
4068
4008
|
};
|
|
4069
4009
|
const onRemoved = () => {
|
|
4070
4010
|
};
|
|
4071
|
-
watchers.push(new Watcher(resolvedConfig.rootPath, onChangedTestFile, onRemoved, true));
|
|
4011
|
+
watchers.push(new Watcher(resolvedConfig.rootPath, onChangedTestFile, onRemoved, { recursive: true }));
|
|
4072
4012
|
}
|
|
4073
4013
|
return Promise.all(watchers.map((watcher) => watcher.watch()));
|
|
4074
4014
|
}
|
|
4075
4015
|
}
|
|
4076
4016
|
|
|
4077
|
-
export { Assertion, CancellationHandler, CancellationReason, CancellationToken, Cli, CollectService, Color, ConfigService, DescribeResult, Diagnostic, DiagnosticCategory, Environment, EventEmitter, ExitCodeHandler, Expect, ExpectResult, FileResult, FileWatcher, InputService, Line, OptionBrand, OptionDefinitionsMap, OptionDiagnosticText, OptionGroup, OutputService, Path, ProjectResult, ProjectService, Result, ResultCount, ResultHandler, ResultStatus, ResultTiming, RuntimeReporter, Scribbler, SelectService, SetupReporter, StoreService, SummaryReporter, TSTyche, TargetResult, TaskRunner, TestFile, TestMember, TestMemberBrand, TestMemberFlags, TestResult, TestTree, Text, Version, WatchReporter, WatchService, Watcher, addsPackageStepText, defaultOptions, describeNameText, diagnosticText, fileStatusText, fileViewText, formattedText, helpText, summaryText, testNameText, usesCompilerStepText, waitingForFileChangesText, watchUsageText };
|
|
4017
|
+
export { Assertion, CancellationHandler, CancellationReason, CancellationToken, Cli, CollectService, Color, ConfigService, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, Environment, EventEmitter, ExitCodeHandler, Expect, ExpectResult, FileResult, FileWatcher, InputService, Line, OptionBrand, OptionDefinitionsMap, OptionDiagnosticText, OptionGroup, OutputService, Path, ProjectResult, ProjectService, Result, ResultCount, ResultHandler, ResultStatus, ResultTiming, RuntimeReporter, Scribbler, SelectService, SetupReporter, StoreService, SummaryReporter, TSTyche, TargetResult, TaskRunner, TestFile, TestMember, TestMemberBrand, TestMemberFlags, TestResult, TestTree, Text, Version, WatchReporter, WatchService, Watcher, addsPackageStepText, defaultOptions, describeNameText, diagnosticText, fileStatusText, fileViewText, formattedText, helpText, summaryText, testNameText, usesCompilerStepText, waitingForFileChangesText, watchUsageText };
|