tstyche 4.3.0 → 5.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/build/index.d.cts +0 -42
- package/build/index.d.ts +0 -42
- package/build/tstyche.d.ts +100 -92
- package/build/tstyche.js +1030 -861
- package/package.json +2 -2
package/build/tstyche.js
CHANGED
|
@@ -6,34 +6,146 @@ import os from 'node:os';
|
|
|
6
6
|
import process from 'node:process';
|
|
7
7
|
import { createRequire } from 'node:module';
|
|
8
8
|
import vm from 'node:vm';
|
|
9
|
-
import streamConsumers from 'node:stream/consumers';
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
class EventEmitter {
|
|
11
|
+
static instanceCount = 0;
|
|
12
|
+
static #handlers = new Map();
|
|
13
|
+
static #reporters = new Map();
|
|
14
|
+
#scope;
|
|
15
|
+
constructor() {
|
|
16
|
+
this.#scope = EventEmitter.instanceCount++;
|
|
17
|
+
EventEmitter.#handlers.set(this.#scope, new Set());
|
|
18
|
+
EventEmitter.#reporters.set(this.#scope, new Set());
|
|
19
|
+
}
|
|
20
|
+
addHandler(handler) {
|
|
21
|
+
EventEmitter.#handlers.get(this.#scope)?.add(handler);
|
|
22
|
+
}
|
|
23
|
+
addReporter(reporter) {
|
|
24
|
+
EventEmitter.#reporters.get(this.#scope)?.add(reporter);
|
|
25
|
+
}
|
|
26
|
+
static dispatch(event) {
|
|
27
|
+
function forEachHandler(handlers, event) {
|
|
28
|
+
for (const handler of handlers) {
|
|
29
|
+
handler.on(event);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
for (const handlers of EventEmitter.#handlers.values()) {
|
|
33
|
+
forEachHandler(handlers, event);
|
|
34
|
+
}
|
|
35
|
+
for (const handlers of EventEmitter.#reporters.values()) {
|
|
36
|
+
forEachHandler(handlers, event);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
removeHandler(handler) {
|
|
40
|
+
EventEmitter.#handlers.get(this.#scope)?.delete(handler);
|
|
41
|
+
}
|
|
42
|
+
removeReporter(reporter) {
|
|
43
|
+
EventEmitter.#reporters.get(this.#scope)?.delete(reporter);
|
|
44
|
+
}
|
|
45
|
+
removeHandlers() {
|
|
46
|
+
EventEmitter.#handlers.get(this.#scope)?.clear();
|
|
47
|
+
}
|
|
48
|
+
removeReporters() {
|
|
49
|
+
EventEmitter.#reporters.get(this.#scope)?.clear();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
class Path {
|
|
54
|
+
static normalizeSlashes;
|
|
55
|
+
static {
|
|
56
|
+
if (path.sep === "/") {
|
|
57
|
+
Path.normalizeSlashes = (filePath) => filePath;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
Path.normalizeSlashes = (filePath) => filePath.replace(/\\/g, "/");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
static dirname(filePath) {
|
|
64
|
+
return Path.normalizeSlashes(path.dirname(filePath));
|
|
65
|
+
}
|
|
66
|
+
static join(...filePaths) {
|
|
67
|
+
return Path.normalizeSlashes(path.join(...filePaths));
|
|
68
|
+
}
|
|
69
|
+
static relative(from, to) {
|
|
70
|
+
const relativePath = Path.normalizeSlashes(path.relative(from, to));
|
|
71
|
+
if (/^\.\.?\//.test(relativePath)) {
|
|
72
|
+
return relativePath;
|
|
73
|
+
}
|
|
74
|
+
return `./${relativePath}`;
|
|
75
|
+
}
|
|
76
|
+
static resolve(...filePaths) {
|
|
77
|
+
return Path.normalizeSlashes(path.resolve(...filePaths));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
class SourceFile {
|
|
82
|
+
fileName;
|
|
83
|
+
#lineMap;
|
|
84
|
+
text;
|
|
85
|
+
constructor(fileName, text) {
|
|
86
|
+
this.fileName = fileName;
|
|
87
|
+
this.text = text;
|
|
88
|
+
this.#lineMap = this.#createLineMap();
|
|
89
|
+
}
|
|
90
|
+
#createLineMap() {
|
|
91
|
+
const result = [0];
|
|
92
|
+
let position = 0;
|
|
93
|
+
while (position < this.text.length) {
|
|
94
|
+
if (this.text.charAt(position - 1) === "\r") {
|
|
95
|
+
position++;
|
|
96
|
+
}
|
|
97
|
+
if (this.text.charAt(position - 1) === "\n") {
|
|
98
|
+
result.push(position);
|
|
99
|
+
}
|
|
100
|
+
position++;
|
|
101
|
+
}
|
|
102
|
+
result.push(position);
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
getLineStarts() {
|
|
106
|
+
return this.#lineMap;
|
|
107
|
+
}
|
|
108
|
+
getLineAndCharacterOfPosition(position) {
|
|
109
|
+
const line = this.#lineMap.findLastIndex((line) => line <= position);
|
|
110
|
+
const character = position - this.#lineMap[line];
|
|
111
|
+
return { line, character };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
class SourceService {
|
|
116
|
+
static #files = new Map();
|
|
117
|
+
static get(source) {
|
|
118
|
+
const file = SourceService.#files.get(source.fileName);
|
|
119
|
+
if (file != null) {
|
|
120
|
+
return file;
|
|
121
|
+
}
|
|
122
|
+
return source;
|
|
123
|
+
}
|
|
124
|
+
static set(source) {
|
|
125
|
+
SourceService.#files.set(source.fileName, source);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
16
128
|
|
|
17
129
|
class DiagnosticOrigin {
|
|
18
|
-
|
|
130
|
+
assertionNode;
|
|
19
131
|
end;
|
|
20
132
|
sourceFile;
|
|
21
133
|
start;
|
|
22
|
-
constructor(start, end, sourceFile,
|
|
134
|
+
constructor(start, end, sourceFile, assertionNode) {
|
|
23
135
|
this.start = start;
|
|
24
136
|
this.end = end;
|
|
25
|
-
this.sourceFile = sourceFile;
|
|
26
|
-
this.
|
|
137
|
+
this.sourceFile = SourceService.get(sourceFile);
|
|
138
|
+
this.assertionNode = assertionNode;
|
|
27
139
|
}
|
|
28
|
-
static fromAssertion(
|
|
29
|
-
const node =
|
|
30
|
-
return new DiagnosticOrigin(node.getStart(), node.getEnd(), node.getSourceFile(),
|
|
140
|
+
static fromAssertion(assertionNode) {
|
|
141
|
+
const node = assertionNode.matcherNameNode.name;
|
|
142
|
+
return new DiagnosticOrigin(node.getStart(), node.getEnd(), node.getSourceFile(), assertionNode);
|
|
31
143
|
}
|
|
32
|
-
static fromNode(node,
|
|
33
|
-
return new DiagnosticOrigin(node.getStart(), node.getEnd(), node.getSourceFile(),
|
|
144
|
+
static fromNode(node, assertionNode) {
|
|
145
|
+
return new DiagnosticOrigin(node.getStart(), node.getEnd(), node.getSourceFile(), assertionNode);
|
|
34
146
|
}
|
|
35
|
-
static fromNodes(nodes,
|
|
36
|
-
return new DiagnosticOrigin(nodes.pos, nodes.end, nodes[0].getSourceFile(),
|
|
147
|
+
static fromNodes(nodes, assertionNode) {
|
|
148
|
+
return new DiagnosticOrigin(nodes.pos, nodes.end, nodes[0].getSourceFile(), assertionNode);
|
|
37
149
|
}
|
|
38
150
|
}
|
|
39
151
|
|
|
@@ -82,135 +194,36 @@ class Diagnostic {
|
|
|
82
194
|
return this;
|
|
83
195
|
}
|
|
84
196
|
static error(text, origin) {
|
|
85
|
-
return new Diagnostic(text,
|
|
197
|
+
return new Diagnostic(text, "error", origin);
|
|
86
198
|
}
|
|
87
199
|
extendWith(text, origin) {
|
|
88
200
|
return new Diagnostic([this.text, text].flat(), this.category, origin ?? this.origin);
|
|
89
201
|
}
|
|
90
|
-
static fromDiagnostics(diagnostics
|
|
202
|
+
static fromDiagnostics(diagnostics) {
|
|
91
203
|
return diagnostics.map((diagnostic) => {
|
|
92
204
|
const code = `ts(${diagnostic.code})`;
|
|
93
205
|
let origin;
|
|
94
206
|
if (isDiagnosticWithLocation(diagnostic)) {
|
|
95
|
-
origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic),
|
|
207
|
+
origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), diagnostic.file);
|
|
96
208
|
}
|
|
97
209
|
let related;
|
|
98
210
|
if (diagnostic.relatedInformation != null) {
|
|
99
211
|
related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
|
|
100
212
|
}
|
|
101
213
|
const text = getDiagnosticMessageText(diagnostic);
|
|
102
|
-
return new Diagnostic(text,
|
|
214
|
+
return new Diagnostic(text, "error", origin).add({ code, related });
|
|
103
215
|
});
|
|
104
216
|
}
|
|
105
217
|
static warning(text, origin) {
|
|
106
|
-
return new Diagnostic(text,
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
class SourceFile {
|
|
111
|
-
fileName;
|
|
112
|
-
#lineMap;
|
|
113
|
-
text;
|
|
114
|
-
constructor(fileName, text) {
|
|
115
|
-
this.fileName = fileName;
|
|
116
|
-
this.text = text;
|
|
117
|
-
this.#lineMap = this.#createLineMap();
|
|
118
|
-
}
|
|
119
|
-
#createLineMap() {
|
|
120
|
-
const result = [0];
|
|
121
|
-
let position = 0;
|
|
122
|
-
while (position < this.text.length) {
|
|
123
|
-
if (this.text.charAt(position - 1) === "\r") {
|
|
124
|
-
position++;
|
|
125
|
-
}
|
|
126
|
-
if (this.text.charAt(position - 1) === "\n") {
|
|
127
|
-
result.push(position);
|
|
128
|
-
}
|
|
129
|
-
position++;
|
|
130
|
-
}
|
|
131
|
-
result.push(position);
|
|
132
|
-
return result;
|
|
133
|
-
}
|
|
134
|
-
getLineStarts() {
|
|
135
|
-
return this.#lineMap;
|
|
136
|
-
}
|
|
137
|
-
getLineAndCharacterOfPosition(position) {
|
|
138
|
-
const line = this.#lineMap.findLastIndex((line) => line <= position);
|
|
139
|
-
const character = position - this.#lineMap[line];
|
|
140
|
-
return { line, character };
|
|
218
|
+
return new Diagnostic(text, "warning", origin);
|
|
141
219
|
}
|
|
142
220
|
}
|
|
143
221
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
constructor() {
|
|
150
|
-
this.#scope = EventEmitter.instanceCount++;
|
|
151
|
-
EventEmitter.#handlers.set(this.#scope, new Set());
|
|
152
|
-
EventEmitter.#reporters.set(this.#scope, new Set());
|
|
153
|
-
}
|
|
154
|
-
addHandler(handler) {
|
|
155
|
-
EventEmitter.#handlers.get(this.#scope)?.add(handler);
|
|
156
|
-
}
|
|
157
|
-
addReporter(reporter) {
|
|
158
|
-
EventEmitter.#reporters.get(this.#scope)?.add(reporter);
|
|
159
|
-
}
|
|
160
|
-
static dispatch(event) {
|
|
161
|
-
function forEachHandler(handlers, event) {
|
|
162
|
-
for (const handler of handlers) {
|
|
163
|
-
handler.on(event);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
for (const handlers of EventEmitter.#handlers.values()) {
|
|
167
|
-
forEachHandler(handlers, event);
|
|
168
|
-
}
|
|
169
|
-
for (const handlers of EventEmitter.#reporters.values()) {
|
|
170
|
-
forEachHandler(handlers, event);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
removeHandler(handler) {
|
|
174
|
-
EventEmitter.#handlers.get(this.#scope)?.delete(handler);
|
|
175
|
-
}
|
|
176
|
-
removeReporter(reporter) {
|
|
177
|
-
EventEmitter.#reporters.get(this.#scope)?.delete(reporter);
|
|
178
|
-
}
|
|
179
|
-
removeHandlers() {
|
|
180
|
-
EventEmitter.#handlers.get(this.#scope)?.clear();
|
|
181
|
-
}
|
|
182
|
-
removeReporters() {
|
|
183
|
-
EventEmitter.#reporters.get(this.#scope)?.clear();
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
class Path {
|
|
188
|
-
static normalizeSlashes;
|
|
189
|
-
static {
|
|
190
|
-
if (path.sep === "/") {
|
|
191
|
-
Path.normalizeSlashes = (filePath) => filePath;
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
Path.normalizeSlashes = (filePath) => filePath.replace(/\\/g, "/");
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
static dirname(filePath) {
|
|
198
|
-
return Path.normalizeSlashes(path.dirname(filePath));
|
|
199
|
-
}
|
|
200
|
-
static join(...filePaths) {
|
|
201
|
-
return Path.normalizeSlashes(path.join(...filePaths));
|
|
202
|
-
}
|
|
203
|
-
static relative(from, to) {
|
|
204
|
-
const relativePath = Path.normalizeSlashes(path.relative(from, to));
|
|
205
|
-
if (/^\.\.?\//.test(relativePath)) {
|
|
206
|
-
return relativePath;
|
|
207
|
-
}
|
|
208
|
-
return `./${relativePath}`;
|
|
209
|
-
}
|
|
210
|
-
static resolve(...filePaths) {
|
|
211
|
-
return Path.normalizeSlashes(path.resolve(...filePaths));
|
|
212
|
-
}
|
|
213
|
-
}
|
|
222
|
+
var DiagnosticCategory;
|
|
223
|
+
(function (DiagnosticCategory) {
|
|
224
|
+
DiagnosticCategory["Error"] = "error";
|
|
225
|
+
DiagnosticCategory["Warning"] = "warning";
|
|
226
|
+
})(DiagnosticCategory || (DiagnosticCategory = {}));
|
|
214
227
|
|
|
215
228
|
class ConfigDiagnosticText {
|
|
216
229
|
static expected(element) {
|
|
@@ -237,19 +250,22 @@ class ConfigDiagnosticText {
|
|
|
237
250
|
static moduleWasNotFound(specifier) {
|
|
238
251
|
return `The specified module '${specifier}' was not found.`;
|
|
239
252
|
}
|
|
253
|
+
static optionValueMustBe(optionName, optionBrand) {
|
|
254
|
+
return `Value for the '${optionName}' option must be a ${optionBrand}.`;
|
|
255
|
+
}
|
|
240
256
|
static rangeIsNotValid(value) {
|
|
241
257
|
return `The specified range '${value}' is not valid.`;
|
|
242
258
|
}
|
|
259
|
+
static rangeDoesNotMatchSupported(value) {
|
|
260
|
+
return `The specified range '${value}' does not match any supported TypeScript versions.`;
|
|
261
|
+
}
|
|
243
262
|
static rangeUsage() {
|
|
244
263
|
return [
|
|
245
|
-
"A range must be specified using an operator and a minor version.",
|
|
246
|
-
"To set an upper bound, the intersection of two ranges
|
|
247
|
-
"
|
|
264
|
+
"A range must be specified using an operator and a minor version: '>=5.5'.",
|
|
265
|
+
"To set an upper bound, use the intersection of two ranges: '>=5.0 <5.3'.",
|
|
266
|
+
"Use the '||' operator to join ranges into a union: '>=5.2 <=5.3 || 5.4.2 || >5.5'.",
|
|
248
267
|
];
|
|
249
268
|
}
|
|
250
|
-
static requiresValueType(optionName, optionBrand) {
|
|
251
|
-
return `Option '${optionName}' requires a value of type ${optionBrand}.`;
|
|
252
|
-
}
|
|
253
269
|
static seen(element) {
|
|
254
270
|
return `The ${element} was seen here.`;
|
|
255
271
|
}
|
|
@@ -259,46 +275,14 @@ class ConfigDiagnosticText {
|
|
|
259
275
|
static unknownOption(optionName) {
|
|
260
276
|
return `Unknown option '${optionName}'.`;
|
|
261
277
|
}
|
|
262
|
-
static usage(optionName, optionBrand) {
|
|
263
|
-
switch (optionName.startsWith("--") ? optionName.slice(2) : optionName) {
|
|
264
|
-
case "target": {
|
|
265
|
-
const text = [];
|
|
266
|
-
if (optionName.startsWith("--")) {
|
|
267
|
-
text.push("Value for the '--target' option must be a string or a comma separated list.", "Examples: '--target 5.2', '--target next', '--target '>=5.0 <5.3, 5.4.2, >=5.5''.");
|
|
268
|
-
}
|
|
269
|
-
return text;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
return [ConfigDiagnosticText.requiresValueType(optionName, optionBrand)];
|
|
273
|
-
}
|
|
274
278
|
static versionIsNotSupported(value) {
|
|
275
|
-
|
|
276
|
-
return "Cannot use 'current' as a target. Failed to resolve the installed TypeScript module.";
|
|
277
|
-
}
|
|
278
|
-
return `TypeScript version '${value}' is not supported.`;
|
|
279
|
+
return `The TypeScript version '${value}' is not supported.`;
|
|
279
280
|
}
|
|
280
281
|
static watchCannotBeEnabled() {
|
|
281
282
|
return "Watch mode cannot be enabled in continuous integration environment.";
|
|
282
283
|
}
|
|
283
284
|
}
|
|
284
285
|
|
|
285
|
-
var OptionBrand;
|
|
286
|
-
(function (OptionBrand) {
|
|
287
|
-
OptionBrand["String"] = "string";
|
|
288
|
-
OptionBrand["Number"] = "number";
|
|
289
|
-
OptionBrand["Boolean"] = "boolean";
|
|
290
|
-
OptionBrand["BareTrue"] = "bareTrue";
|
|
291
|
-
OptionBrand["List"] = "list";
|
|
292
|
-
})(OptionBrand || (OptionBrand = {}));
|
|
293
|
-
|
|
294
|
-
var OptionGroup;
|
|
295
|
-
(function (OptionGroup) {
|
|
296
|
-
OptionGroup[OptionGroup["CommandLine"] = 2] = "CommandLine";
|
|
297
|
-
OptionGroup[OptionGroup["ConfigFile"] = 4] = "ConfigFile";
|
|
298
|
-
OptionGroup[OptionGroup["InlineConditions"] = 8] = "InlineConditions";
|
|
299
|
-
OptionGroup[OptionGroup["ResolvedConfig"] = 6] = "ResolvedConfig";
|
|
300
|
-
})(OptionGroup || (OptionGroup = {}));
|
|
301
|
-
|
|
302
286
|
class Environment {
|
|
303
287
|
static resolve() {
|
|
304
288
|
return {
|
|
@@ -555,6 +539,9 @@ class Manifest {
|
|
|
555
539
|
return;
|
|
556
540
|
}
|
|
557
541
|
resolve(tag) {
|
|
542
|
+
if (tag === "*") {
|
|
543
|
+
return this.resolutions["latest"];
|
|
544
|
+
}
|
|
558
545
|
if (this.versions.includes(tag)) {
|
|
559
546
|
return tag;
|
|
560
547
|
}
|
|
@@ -663,32 +650,58 @@ class ManifestService {
|
|
|
663
650
|
}
|
|
664
651
|
|
|
665
652
|
class TarReader {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
653
|
+
#leftover = new Uint8Array(0);
|
|
654
|
+
#reader;
|
|
655
|
+
#textDecoder = new TextDecoder();
|
|
656
|
+
constructor(stream) {
|
|
657
|
+
this.#reader = stream.getReader();
|
|
658
|
+
}
|
|
659
|
+
async *extract() {
|
|
660
|
+
while (true) {
|
|
661
|
+
const header = await this.#read(512);
|
|
662
|
+
if (this.#isEndOfArchive(header)) {
|
|
674
663
|
break;
|
|
675
664
|
}
|
|
676
|
-
const
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
665
|
+
const name = this.#textDecoder.decode(header.subarray(0, 100)).replace(/\0.*$/, "");
|
|
666
|
+
const sizeOctal = this.#textDecoder.decode(header.subarray(124, 136)).replace(/\0.*$/, "").trim();
|
|
667
|
+
const size = Number.parseInt(sizeOctal, 8);
|
|
668
|
+
const content = await this.#read(size);
|
|
669
|
+
yield { name, content };
|
|
670
|
+
if (size % 512 !== 0) {
|
|
671
|
+
const toSkip = 512 - (size % 512);
|
|
672
|
+
await this.#read(toSkip);
|
|
682
673
|
}
|
|
683
674
|
}
|
|
684
675
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
676
|
+
#isEndOfArchive(entry) {
|
|
677
|
+
return entry.every((byte) => byte === 0);
|
|
678
|
+
}
|
|
679
|
+
async #read(n) {
|
|
680
|
+
const result = new Uint8Array(n);
|
|
681
|
+
let filled = 0;
|
|
682
|
+
if (this.#leftover.length > 0) {
|
|
683
|
+
const toCopy = Math.min(this.#leftover.length, n);
|
|
684
|
+
result.set(this.#leftover.subarray(0, toCopy), filled);
|
|
685
|
+
filled += toCopy;
|
|
686
|
+
this.#leftover = this.#leftover.subarray(toCopy);
|
|
687
|
+
if (filled === n) {
|
|
688
|
+
return result;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
while (filled < n) {
|
|
692
|
+
const { value, done } = await this.#reader.read();
|
|
693
|
+
if (done) {
|
|
694
|
+
break;
|
|
695
|
+
}
|
|
696
|
+
const toCopy = Math.min(value.length, n - filled);
|
|
697
|
+
result.set(value.subarray(0, toCopy), filled);
|
|
698
|
+
filled += toCopy;
|
|
699
|
+
if (toCopy < value.length) {
|
|
700
|
+
this.#leftover = value.subarray(toCopy);
|
|
701
|
+
break;
|
|
702
|
+
}
|
|
690
703
|
}
|
|
691
|
-
return
|
|
704
|
+
return result.subarray(0, filled);
|
|
692
705
|
}
|
|
693
706
|
}
|
|
694
707
|
|
|
@@ -706,16 +719,18 @@ class PackageService {
|
|
|
706
719
|
const response = await this.#fetcher.get(request, diagnostic);
|
|
707
720
|
if (response?.body != null) {
|
|
708
721
|
const targetPath = `${packagePath}-${Math.random().toString(32).slice(2)}`;
|
|
709
|
-
|
|
722
|
+
const stream = response.body.pipeThrough(new DecompressionStream("gzip"));
|
|
723
|
+
const tarReader = new TarReader(stream);
|
|
724
|
+
for await (const file of tarReader.extract()) {
|
|
710
725
|
if (!file.name.startsWith("package/")) {
|
|
711
726
|
continue;
|
|
712
727
|
}
|
|
713
|
-
const filePath = Path.join(targetPath, file.name.replace(
|
|
728
|
+
const filePath = Path.join(targetPath, file.name.replace(/^package\//, ""));
|
|
714
729
|
const directoryPath = Path.dirname(filePath);
|
|
715
730
|
if (!existsSync(directoryPath)) {
|
|
716
731
|
await fs.mkdir(directoryPath, { recursive: true });
|
|
717
732
|
}
|
|
718
|
-
await fs.writeFile(filePath, file.
|
|
733
|
+
await fs.writeFile(filePath, file.content);
|
|
719
734
|
}
|
|
720
735
|
await fs.rename(targetPath, packagePath);
|
|
721
736
|
return packagePath;
|
|
@@ -765,7 +780,7 @@ class Store {
|
|
|
765
780
|
Store.#manifestService = new ManifestService(Store.#storePath, Store.#npmRegistry, Store.#fetcher);
|
|
766
781
|
}
|
|
767
782
|
static async fetch(tag) {
|
|
768
|
-
if (tag === "
|
|
783
|
+
if (tag === "*" && environmentOptions.typescriptModule != null) {
|
|
769
784
|
return;
|
|
770
785
|
}
|
|
771
786
|
await Store.open();
|
|
@@ -782,7 +797,7 @@ class Store {
|
|
|
782
797
|
return compilerInstance;
|
|
783
798
|
}
|
|
784
799
|
let modulePath;
|
|
785
|
-
if (tag === "
|
|
800
|
+
if (tag === "*" && environmentOptions.typescriptModule != null) {
|
|
786
801
|
modulePath = fileURLToPath(environmentOptions.typescriptModule);
|
|
787
802
|
}
|
|
788
803
|
else {
|
|
@@ -830,7 +845,7 @@ class Store {
|
|
|
830
845
|
Store.open = () => Promise.resolve();
|
|
831
846
|
Store.manifest = await Store.#manifestService.open();
|
|
832
847
|
if (Store.manifest != null) {
|
|
833
|
-
Store.#supportedTags = [...Object.keys(Store.manifest.resolutions), ...Store.manifest.versions
|
|
848
|
+
Store.#supportedTags = [...Object.keys(Store.manifest.resolutions), ...Store.manifest.versions];
|
|
834
849
|
}
|
|
835
850
|
}
|
|
836
851
|
static async prune() {
|
|
@@ -840,8 +855,8 @@ class Store {
|
|
|
840
855
|
await Store.#manifestService.open({ refresh: true });
|
|
841
856
|
}
|
|
842
857
|
static async validateTag(tag) {
|
|
843
|
-
if (tag === "
|
|
844
|
-
return
|
|
858
|
+
if (tag === "*") {
|
|
859
|
+
return true;
|
|
845
860
|
}
|
|
846
861
|
await Store.open();
|
|
847
862
|
if (Store.manifest?.isOutdated({ ageTolerance: 60 }) &&
|
|
@@ -859,23 +874,25 @@ class Store {
|
|
|
859
874
|
|
|
860
875
|
class Target {
|
|
861
876
|
static #rangeRegex = /^[<>]=?\d\.\d( [<>]=?\d\.\d)?$/;
|
|
862
|
-
static async expand(
|
|
863
|
-
|
|
864
|
-
for (const query of queries) {
|
|
865
|
-
if (!Target.isRange(query)) {
|
|
866
|
-
include.push(query);
|
|
867
|
-
continue;
|
|
868
|
-
}
|
|
877
|
+
static async expand(range, onDiagnostics, origin) {
|
|
878
|
+
if (Target.isRange(range)) {
|
|
869
879
|
await Store.open();
|
|
870
880
|
if (Store.manifest != null) {
|
|
871
881
|
let versions = [...Store.manifest.minorVersions];
|
|
872
|
-
for (const comparator of
|
|
873
|
-
versions = Target.#filter(comparator, versions);
|
|
882
|
+
for (const comparator of range.split(" ")) {
|
|
883
|
+
versions = Target.#filter(comparator.trim(), versions);
|
|
884
|
+
if (versions.length === 0) {
|
|
885
|
+
const text = [
|
|
886
|
+
ConfigDiagnosticText.rangeDoesNotMatchSupported(range),
|
|
887
|
+
ConfigDiagnosticText.inspectSupportedVersions(),
|
|
888
|
+
];
|
|
889
|
+
onDiagnostics(Diagnostic.error(text, origin));
|
|
890
|
+
}
|
|
874
891
|
}
|
|
875
|
-
|
|
892
|
+
return versions;
|
|
876
893
|
}
|
|
877
894
|
}
|
|
878
|
-
return
|
|
895
|
+
return [range];
|
|
879
896
|
}
|
|
880
897
|
static #filter(comparator, versions) {
|
|
881
898
|
const targetVersion = comparator.replace(/^[<>]=?/, "");
|
|
@@ -894,178 +911,177 @@ class Target {
|
|
|
894
911
|
static isRange(query) {
|
|
895
912
|
return Target.#rangeRegex.test(query);
|
|
896
913
|
}
|
|
914
|
+
static split(range) {
|
|
915
|
+
return range.split(/ *\|\| */);
|
|
916
|
+
}
|
|
897
917
|
}
|
|
898
918
|
|
|
899
919
|
class Options {
|
|
900
920
|
static #definitions = [
|
|
901
921
|
{
|
|
902
|
-
brand:
|
|
922
|
+
brand: "string",
|
|
903
923
|
description: "The Url to the config file validation schema.",
|
|
904
|
-
group:
|
|
924
|
+
group: 4,
|
|
905
925
|
name: "$schema",
|
|
906
926
|
},
|
|
907
927
|
{
|
|
908
|
-
brand:
|
|
909
|
-
description: "
|
|
910
|
-
group:
|
|
911
|
-
name: "
|
|
928
|
+
brand: "boolean",
|
|
929
|
+
description: "Check declaration files for type errors.",
|
|
930
|
+
group: 4,
|
|
931
|
+
name: "checkDeclarationFiles",
|
|
912
932
|
},
|
|
913
933
|
{
|
|
914
|
-
brand:
|
|
934
|
+
brand: "boolean",
|
|
915
935
|
description: "Check errors silenced by '// @ts-expect-error' directives.",
|
|
916
|
-
group:
|
|
936
|
+
group: 4,
|
|
917
937
|
name: "checkSuppressedErrors",
|
|
918
938
|
},
|
|
919
939
|
{
|
|
920
|
-
brand:
|
|
940
|
+
brand: "string",
|
|
921
941
|
description: "The path to a TSTyche configuration file.",
|
|
922
|
-
group:
|
|
942
|
+
group: 2,
|
|
923
943
|
name: "config",
|
|
924
944
|
},
|
|
925
945
|
{
|
|
926
|
-
brand:
|
|
946
|
+
brand: "boolean",
|
|
927
947
|
description: "Stop running tests after the first failed assertion.",
|
|
928
|
-
group:
|
|
948
|
+
group: 4 | 2,
|
|
929
949
|
name: "failFast",
|
|
930
950
|
},
|
|
931
951
|
{
|
|
932
|
-
brand:
|
|
952
|
+
brand: "true",
|
|
933
953
|
description: "Fetch the specified versions of the 'typescript' package and exit.",
|
|
934
|
-
group:
|
|
954
|
+
group: 2,
|
|
935
955
|
name: "fetch",
|
|
936
956
|
},
|
|
937
957
|
{
|
|
938
|
-
brand:
|
|
958
|
+
brand: "list",
|
|
939
959
|
description: "The list of glob patterns matching the fixture files.",
|
|
940
|
-
group:
|
|
960
|
+
group: 4,
|
|
941
961
|
items: {
|
|
942
|
-
brand:
|
|
962
|
+
brand: "string",
|
|
943
963
|
name: "fixtureFileMatch",
|
|
944
964
|
},
|
|
945
965
|
name: "fixtureFileMatch",
|
|
946
966
|
},
|
|
947
967
|
{
|
|
948
|
-
brand:
|
|
968
|
+
brand: "true",
|
|
949
969
|
description: "Print the list of command line options with brief descriptions and exit.",
|
|
950
|
-
group:
|
|
970
|
+
group: 2,
|
|
951
971
|
name: "help",
|
|
952
972
|
},
|
|
953
973
|
{
|
|
954
|
-
brand:
|
|
974
|
+
brand: "true",
|
|
955
975
|
description: "Print the list of supported versions of the 'typescript' package and exit.",
|
|
956
|
-
group:
|
|
976
|
+
group: 2,
|
|
957
977
|
name: "list",
|
|
958
978
|
},
|
|
959
979
|
{
|
|
960
|
-
brand:
|
|
980
|
+
brand: "true",
|
|
961
981
|
description: "Print the list of the selected test files and exit.",
|
|
962
|
-
group:
|
|
982
|
+
group: 2,
|
|
963
983
|
name: "listFiles",
|
|
964
984
|
},
|
|
965
985
|
{
|
|
966
|
-
brand:
|
|
986
|
+
brand: "string",
|
|
967
987
|
description: "Only run tests with matching name.",
|
|
968
|
-
group:
|
|
988
|
+
group: 2,
|
|
969
989
|
name: "only",
|
|
970
990
|
},
|
|
971
991
|
{
|
|
972
|
-
brand:
|
|
992
|
+
brand: "list",
|
|
973
993
|
description: "The list of plugins to use.",
|
|
974
|
-
group:
|
|
994
|
+
group: 2 | 4,
|
|
975
995
|
items: {
|
|
976
|
-
brand:
|
|
996
|
+
brand: "string",
|
|
977
997
|
name: "plugins",
|
|
978
998
|
},
|
|
979
999
|
name: "plugins",
|
|
980
1000
|
},
|
|
981
1001
|
{
|
|
982
|
-
brand:
|
|
1002
|
+
brand: "true",
|
|
983
1003
|
description: "Remove all installed versions of the 'typescript' package and exit.",
|
|
984
|
-
group:
|
|
1004
|
+
group: 2,
|
|
985
1005
|
name: "prune",
|
|
986
1006
|
},
|
|
987
1007
|
{
|
|
988
|
-
brand:
|
|
1008
|
+
brand: "boolean",
|
|
989
1009
|
description: "Reject the 'any' type passed as an argument to the 'expect()' function or a matcher.",
|
|
990
|
-
group:
|
|
1010
|
+
group: 4,
|
|
991
1011
|
name: "rejectAnyType",
|
|
992
1012
|
},
|
|
993
1013
|
{
|
|
994
|
-
brand:
|
|
1014
|
+
brand: "boolean",
|
|
995
1015
|
description: "Reject the 'never' type passed as an argument to the 'expect()' function or a matcher.",
|
|
996
|
-
group:
|
|
1016
|
+
group: 4,
|
|
997
1017
|
name: "rejectNeverType",
|
|
998
1018
|
},
|
|
999
1019
|
{
|
|
1000
|
-
brand:
|
|
1020
|
+
brand: "list",
|
|
1001
1021
|
description: "The list of reporters to use.",
|
|
1002
|
-
group:
|
|
1022
|
+
group: 2 | 4,
|
|
1003
1023
|
items: {
|
|
1004
|
-
brand:
|
|
1024
|
+
brand: "string",
|
|
1005
1025
|
name: "reporters",
|
|
1006
1026
|
},
|
|
1007
1027
|
name: "reporters",
|
|
1008
1028
|
},
|
|
1009
1029
|
{
|
|
1010
|
-
brand:
|
|
1030
|
+
brand: "string",
|
|
1011
1031
|
description: "The path to a directory containing files of a test project.",
|
|
1012
|
-
group:
|
|
1032
|
+
group: 4,
|
|
1013
1033
|
name: "rootPath",
|
|
1014
1034
|
},
|
|
1015
1035
|
{
|
|
1016
|
-
brand:
|
|
1036
|
+
brand: "true",
|
|
1017
1037
|
description: "Print the resolved configuration and exit.",
|
|
1018
|
-
group:
|
|
1038
|
+
group: 2,
|
|
1019
1039
|
name: "showConfig",
|
|
1020
1040
|
},
|
|
1021
1041
|
{
|
|
1022
|
-
brand:
|
|
1042
|
+
brand: "string",
|
|
1023
1043
|
description: "Skip tests with matching name.",
|
|
1024
|
-
group:
|
|
1044
|
+
group: 2,
|
|
1025
1045
|
name: "skip",
|
|
1026
1046
|
},
|
|
1027
1047
|
{
|
|
1028
|
-
brand:
|
|
1029
|
-
description: "The
|
|
1030
|
-
group:
|
|
1031
|
-
items: {
|
|
1032
|
-
brand: OptionBrand.String,
|
|
1033
|
-
name: "target",
|
|
1034
|
-
},
|
|
1048
|
+
brand: "range",
|
|
1049
|
+
description: "The range of TypeScript versions to be tested against.",
|
|
1050
|
+
group: 2 | 4 | 8,
|
|
1035
1051
|
name: "target",
|
|
1036
1052
|
},
|
|
1037
1053
|
{
|
|
1038
|
-
brand:
|
|
1054
|
+
brand: "list",
|
|
1039
1055
|
description: "The list of glob patterns matching the test files.",
|
|
1040
|
-
group:
|
|
1056
|
+
group: 4,
|
|
1041
1057
|
items: {
|
|
1042
|
-
brand:
|
|
1058
|
+
brand: "string",
|
|
1043
1059
|
name: "testFileMatch",
|
|
1044
1060
|
},
|
|
1045
1061
|
name: "testFileMatch",
|
|
1046
1062
|
},
|
|
1047
1063
|
{
|
|
1048
|
-
brand:
|
|
1064
|
+
brand: "string",
|
|
1049
1065
|
description: "The look up strategy to be used to find the TSConfig file.",
|
|
1050
|
-
group:
|
|
1066
|
+
group: 2 | 4,
|
|
1051
1067
|
name: "tsconfig",
|
|
1052
1068
|
},
|
|
1053
1069
|
{
|
|
1054
|
-
brand:
|
|
1070
|
+
brand: "true",
|
|
1055
1071
|
description: "Fetch the 'typescript' package metadata from the registry and exit.",
|
|
1056
|
-
group:
|
|
1072
|
+
group: 2,
|
|
1057
1073
|
name: "update",
|
|
1058
1074
|
},
|
|
1059
1075
|
{
|
|
1060
|
-
brand:
|
|
1076
|
+
brand: "true",
|
|
1061
1077
|
description: "Print the version number and exit.",
|
|
1062
|
-
group:
|
|
1078
|
+
group: 2,
|
|
1063
1079
|
name: "version",
|
|
1064
1080
|
},
|
|
1065
1081
|
{
|
|
1066
|
-
brand:
|
|
1082
|
+
brand: "true",
|
|
1067
1083
|
description: "Watch for changes and rerun related test files.",
|
|
1068
|
-
group:
|
|
1084
|
+
group: 2,
|
|
1069
1085
|
name: "watch",
|
|
1070
1086
|
},
|
|
1071
1087
|
];
|
|
@@ -1117,7 +1133,7 @@ class Options {
|
|
|
1117
1133
|
}
|
|
1118
1134
|
return optionValue;
|
|
1119
1135
|
}
|
|
1120
|
-
static async validate(optionName, optionValue,
|
|
1136
|
+
static async validate(optionName, optionValue, onDiagnostics, origin) {
|
|
1121
1137
|
const canonicalOptionName = Options.#getCanonicalOptionName(optionName);
|
|
1122
1138
|
switch (canonicalOptionName) {
|
|
1123
1139
|
case "config":
|
|
@@ -1144,16 +1160,17 @@ class Options {
|
|
|
1144
1160
|
case "target": {
|
|
1145
1161
|
if (/[<>=]/.test(optionValue)) {
|
|
1146
1162
|
if (!Target.isRange(optionValue)) {
|
|
1147
|
-
|
|
1163
|
+
const text = [ConfigDiagnosticText.rangeIsNotValid(optionValue), ...ConfigDiagnosticText.rangeUsage()];
|
|
1164
|
+
onDiagnostics(Diagnostic.error(text, origin));
|
|
1148
1165
|
}
|
|
1149
1166
|
break;
|
|
1150
1167
|
}
|
|
1151
1168
|
if ((await Store.validateTag(optionValue)) === false) {
|
|
1152
|
-
|
|
1169
|
+
const text = [
|
|
1153
1170
|
ConfigDiagnosticText.versionIsNotSupported(optionValue),
|
|
1154
|
-
...ConfigDiagnosticText.usage(optionName, optionBrand),
|
|
1155
1171
|
ConfigDiagnosticText.inspectSupportedVersions(),
|
|
1156
|
-
]
|
|
1172
|
+
];
|
|
1173
|
+
onDiagnostics(Diagnostic.error(text, origin));
|
|
1157
1174
|
}
|
|
1158
1175
|
break;
|
|
1159
1176
|
}
|
|
@@ -1174,7 +1191,7 @@ class Options {
|
|
|
1174
1191
|
}
|
|
1175
1192
|
}
|
|
1176
1193
|
|
|
1177
|
-
class
|
|
1194
|
+
class CommandParser {
|
|
1178
1195
|
#commandLineOptions;
|
|
1179
1196
|
#onDiagnostics;
|
|
1180
1197
|
#options;
|
|
@@ -1183,12 +1200,12 @@ class CommandLineParser {
|
|
|
1183
1200
|
this.#commandLineOptions = commandLine;
|
|
1184
1201
|
this.#pathMatch = pathMatch;
|
|
1185
1202
|
this.#onDiagnostics = onDiagnostics;
|
|
1186
|
-
this.#options = Options.for(
|
|
1203
|
+
this.#options = Options.for(2);
|
|
1187
1204
|
}
|
|
1188
1205
|
#onExpectsValue(optionName, optionBrand) {
|
|
1189
1206
|
const text = [
|
|
1190
1207
|
ConfigDiagnosticText.expectsValue(optionName),
|
|
1191
|
-
|
|
1208
|
+
ConfigDiagnosticText.optionValueMustBe(optionName, optionBrand),
|
|
1192
1209
|
];
|
|
1193
1210
|
this.#onDiagnostics(Diagnostic.error(text));
|
|
1194
1211
|
}
|
|
@@ -1218,18 +1235,18 @@ class CommandLineParser {
|
|
|
1218
1235
|
async #parseOptionValue(commandLineArgs, index, optionName, optionDefinition) {
|
|
1219
1236
|
let optionValue = this.#resolveOptionValue(commandLineArgs[index]);
|
|
1220
1237
|
switch (optionDefinition.brand) {
|
|
1221
|
-
case
|
|
1222
|
-
await Options.validate(optionName, optionValue,
|
|
1238
|
+
case "true":
|
|
1239
|
+
await Options.validate(optionName, optionValue, this.#onDiagnostics);
|
|
1223
1240
|
this.#commandLineOptions[optionDefinition.name] = true;
|
|
1224
1241
|
break;
|
|
1225
|
-
case
|
|
1226
|
-
await Options.validate(optionName, optionValue,
|
|
1242
|
+
case "boolean":
|
|
1243
|
+
await Options.validate(optionName, optionValue, this.#onDiagnostics);
|
|
1227
1244
|
this.#commandLineOptions[optionDefinition.name] = optionValue !== "false";
|
|
1228
1245
|
if (optionValue === "false" || optionValue === "true") {
|
|
1229
1246
|
index++;
|
|
1230
1247
|
}
|
|
1231
1248
|
break;
|
|
1232
|
-
case
|
|
1249
|
+
case "list":
|
|
1233
1250
|
if (optionValue !== "") {
|
|
1234
1251
|
const optionValues = optionValue
|
|
1235
1252
|
.split(",")
|
|
@@ -1237,7 +1254,7 @@ class CommandLineParser {
|
|
|
1237
1254
|
.filter((value) => value !== "")
|
|
1238
1255
|
.map((value) => Options.resolve(optionName, value));
|
|
1239
1256
|
for (const optionValue of optionValues) {
|
|
1240
|
-
await Options.validate(optionName, optionValue,
|
|
1257
|
+
await Options.validate(optionName, optionValue, this.#onDiagnostics);
|
|
1241
1258
|
}
|
|
1242
1259
|
this.#commandLineOptions[optionDefinition.name] = optionValues;
|
|
1243
1260
|
index++;
|
|
@@ -1245,16 +1262,30 @@ class CommandLineParser {
|
|
|
1245
1262
|
}
|
|
1246
1263
|
this.#onExpectsValue(optionName, optionDefinition.brand);
|
|
1247
1264
|
break;
|
|
1248
|
-
case
|
|
1265
|
+
case "string":
|
|
1249
1266
|
if (optionValue !== "") {
|
|
1250
1267
|
optionValue = Options.resolve(optionName, optionValue);
|
|
1251
|
-
await Options.validate(optionName, optionValue,
|
|
1268
|
+
await Options.validate(optionName, optionValue, this.#onDiagnostics);
|
|
1252
1269
|
this.#commandLineOptions[optionDefinition.name] = optionValue;
|
|
1253
1270
|
index++;
|
|
1254
1271
|
break;
|
|
1255
1272
|
}
|
|
1256
1273
|
this.#onExpectsValue(optionName, optionDefinition.brand);
|
|
1257
1274
|
break;
|
|
1275
|
+
case "range":
|
|
1276
|
+
if (optionValue !== "") {
|
|
1277
|
+
const optionValues = [];
|
|
1278
|
+
for (const range of Target.split(optionValue)) {
|
|
1279
|
+
await Options.validate(optionName, range, this.#onDiagnostics);
|
|
1280
|
+
const versions = await Target.expand(range, this.#onDiagnostics);
|
|
1281
|
+
optionValues.push(...versions);
|
|
1282
|
+
}
|
|
1283
|
+
this.#commandLineOptions[optionDefinition.name] = optionValues;
|
|
1284
|
+
index++;
|
|
1285
|
+
break;
|
|
1286
|
+
}
|
|
1287
|
+
this.#onExpectsValue(optionName, "string");
|
|
1288
|
+
break;
|
|
1258
1289
|
}
|
|
1259
1290
|
return index;
|
|
1260
1291
|
}
|
|
@@ -1276,43 +1307,58 @@ class ConfigParser {
|
|
|
1276
1307
|
this.#sourceFile = sourceFile;
|
|
1277
1308
|
this.#options = Options.for(optionGroup);
|
|
1278
1309
|
}
|
|
1279
|
-
#onRequiresValue(
|
|
1310
|
+
#onRequiresValue(optionName, optionBrand, jsonNode, isListItem) {
|
|
1280
1311
|
const text = isListItem
|
|
1281
|
-
? ConfigDiagnosticText.expectsListItemType(
|
|
1282
|
-
: ConfigDiagnosticText.
|
|
1312
|
+
? ConfigDiagnosticText.expectsListItemType(optionName, optionBrand)
|
|
1313
|
+
: ConfigDiagnosticText.optionValueMustBe(optionName, optionBrand);
|
|
1283
1314
|
this.#onDiagnostics(Diagnostic.error(text, jsonNode.origin));
|
|
1284
1315
|
}
|
|
1285
1316
|
async #parseValue(optionDefinition, isListItem = false) {
|
|
1286
1317
|
let jsonNode;
|
|
1287
1318
|
let optionValue;
|
|
1288
1319
|
switch (optionDefinition.brand) {
|
|
1289
|
-
case
|
|
1320
|
+
case "boolean": {
|
|
1290
1321
|
jsonNode = this.#jsonScanner.read();
|
|
1291
1322
|
optionValue = jsonNode.getValue();
|
|
1292
1323
|
if (typeof optionValue !== "boolean") {
|
|
1293
|
-
this.#onRequiresValue(optionDefinition, jsonNode, isListItem);
|
|
1324
|
+
this.#onRequiresValue(optionDefinition.name, optionDefinition.brand, jsonNode, isListItem);
|
|
1294
1325
|
break;
|
|
1295
1326
|
}
|
|
1296
1327
|
break;
|
|
1297
1328
|
}
|
|
1298
|
-
case
|
|
1329
|
+
case "string": {
|
|
1299
1330
|
jsonNode = this.#jsonScanner.read();
|
|
1300
1331
|
optionValue = jsonNode.getValue();
|
|
1301
1332
|
if (typeof optionValue !== "string") {
|
|
1302
|
-
this.#onRequiresValue(optionDefinition, jsonNode, isListItem);
|
|
1333
|
+
this.#onRequiresValue(optionDefinition.name, optionDefinition.brand, jsonNode, isListItem);
|
|
1303
1334
|
break;
|
|
1304
1335
|
}
|
|
1305
1336
|
const rootPath = Path.dirname(this.#sourceFile.fileName);
|
|
1306
1337
|
optionValue = Options.resolve(optionDefinition.name, optionValue, rootPath);
|
|
1307
|
-
await Options.validate(optionDefinition.name, optionValue,
|
|
1338
|
+
await Options.validate(optionDefinition.name, optionValue, this.#onDiagnostics, jsonNode.origin);
|
|
1308
1339
|
break;
|
|
1309
1340
|
}
|
|
1310
|
-
case
|
|
1341
|
+
case "range": {
|
|
1342
|
+
optionValue = [];
|
|
1343
|
+
jsonNode = this.#jsonScanner.read();
|
|
1344
|
+
const ranges = jsonNode.getValue();
|
|
1345
|
+
if (typeof ranges !== "string") {
|
|
1346
|
+
this.#onRequiresValue(optionDefinition.name, "string", jsonNode, isListItem);
|
|
1347
|
+
break;
|
|
1348
|
+
}
|
|
1349
|
+
for (const range of Target.split(ranges)) {
|
|
1350
|
+
await Options.validate(optionDefinition.name, range, this.#onDiagnostics, jsonNode.origin);
|
|
1351
|
+
const versions = await Target.expand(range, this.#onDiagnostics, jsonNode.origin);
|
|
1352
|
+
optionValue.push(...versions);
|
|
1353
|
+
}
|
|
1354
|
+
break;
|
|
1355
|
+
}
|
|
1356
|
+
case "list": {
|
|
1311
1357
|
optionValue = [];
|
|
1312
1358
|
const leftBracketToken = this.#jsonScanner.readToken("[");
|
|
1313
1359
|
if (!leftBracketToken.text) {
|
|
1314
1360
|
jsonNode = this.#jsonScanner.read();
|
|
1315
|
-
this.#onRequiresValue(optionDefinition, jsonNode, isListItem);
|
|
1361
|
+
this.#onRequiresValue(optionDefinition.name, optionDefinition.brand, jsonNode, isListItem);
|
|
1316
1362
|
break;
|
|
1317
1363
|
}
|
|
1318
1364
|
while (!this.#jsonScanner.isRead()) {
|
|
@@ -1410,8 +1456,8 @@ class ConfigParser {
|
|
|
1410
1456
|
}
|
|
1411
1457
|
|
|
1412
1458
|
const defaultOptions = {
|
|
1413
|
-
|
|
1414
|
-
checkSuppressedErrors:
|
|
1459
|
+
checkDeclarationFiles: true,
|
|
1460
|
+
checkSuppressedErrors: true,
|
|
1415
1461
|
failFast: false,
|
|
1416
1462
|
fixtureFileMatch: ["**/__fixtures__/*.{ts,tsx}", "**/fixtures/*.{ts,tsx}"],
|
|
1417
1463
|
plugins: [],
|
|
@@ -1419,7 +1465,7 @@ const defaultOptions = {
|
|
|
1419
1465
|
rejectNeverType: true,
|
|
1420
1466
|
reporters: ["list", "summary"],
|
|
1421
1467
|
rootPath: Path.resolve("./"),
|
|
1422
|
-
target:
|
|
1468
|
+
target: ["*"],
|
|
1423
1469
|
testFileMatch: ["**/*.tst.*", "**/__typetests__/*.test.*", "**/typetests/*.test.*"],
|
|
1424
1470
|
tsconfig: "findup",
|
|
1425
1471
|
};
|
|
@@ -1564,11 +1610,8 @@ class Config {
|
|
|
1564
1610
|
static async parseCommandLine(commandLine) {
|
|
1565
1611
|
const commandLineOptions = {};
|
|
1566
1612
|
const pathMatch = [];
|
|
1567
|
-
const commandLineParser = new
|
|
1613
|
+
const commandLineParser = new CommandParser(commandLineOptions, pathMatch, Config.#onDiagnostics);
|
|
1568
1614
|
await commandLineParser.parse(commandLine);
|
|
1569
|
-
if (commandLineOptions.target != null) {
|
|
1570
|
-
commandLineOptions.target = await Target.expand(commandLineOptions.target);
|
|
1571
|
-
}
|
|
1572
1615
|
return { commandLineOptions, pathMatch };
|
|
1573
1616
|
}
|
|
1574
1617
|
static async parseConfigFile(filePath) {
|
|
@@ -1581,11 +1624,8 @@ class Config {
|
|
|
1581
1624
|
encoding: "utf8",
|
|
1582
1625
|
});
|
|
1583
1626
|
const sourceFile = new SourceFile(configFilePath, configFileText);
|
|
1584
|
-
const configFileParser = new ConfigParser(configFileOptions,
|
|
1627
|
+
const configFileParser = new ConfigParser(configFileOptions, 4, sourceFile, new JsonScanner(sourceFile), Config.#onDiagnostics);
|
|
1585
1628
|
await configFileParser.parse();
|
|
1586
|
-
if (configFileOptions.target != null) {
|
|
1587
|
-
configFileOptions.target = await Target.expand(configFileOptions.target);
|
|
1588
|
-
}
|
|
1589
1629
|
}
|
|
1590
1630
|
return { configFileOptions, configFilePath };
|
|
1591
1631
|
}
|
|
@@ -1621,12 +1661,30 @@ class DirectiveDiagnosticText {
|
|
|
1621
1661
|
|
|
1622
1662
|
class Directive {
|
|
1623
1663
|
static #directiveRegex = /^(\/\/ *@tstyche)( *|-)?(\S*)?( *)?(.*)?/i;
|
|
1624
|
-
static
|
|
1664
|
+
static #rangeCache = new WeakMap();
|
|
1665
|
+
static getDirectiveRange(compiler, owner, directiveText) {
|
|
1666
|
+
const directiveRanges = Directive.getDirectiveRanges(compiler, owner.node);
|
|
1667
|
+
return directiveRanges?.find((range) => range.directive?.text === directiveText);
|
|
1668
|
+
}
|
|
1669
|
+
static getDirectiveRanges(compiler, node) {
|
|
1670
|
+
let ranges = Directive.#rangeCache.get(node);
|
|
1671
|
+
if (ranges != null) {
|
|
1672
|
+
return ranges;
|
|
1673
|
+
}
|
|
1674
|
+
let sourceFile;
|
|
1675
|
+
let position = 0;
|
|
1676
|
+
if (compiler.isSourceFile(node)) {
|
|
1677
|
+
sourceFile = node;
|
|
1678
|
+
}
|
|
1679
|
+
else {
|
|
1680
|
+
sourceFile = node.getSourceFile();
|
|
1681
|
+
position = node.getFullStart();
|
|
1682
|
+
}
|
|
1625
1683
|
const comments = compiler.getLeadingCommentRanges(sourceFile.text, position);
|
|
1626
1684
|
if (!comments || comments.length === 0) {
|
|
1627
1685
|
return;
|
|
1628
1686
|
}
|
|
1629
|
-
|
|
1687
|
+
ranges = [];
|
|
1630
1688
|
for (const comment of comments) {
|
|
1631
1689
|
if (comment.kind !== compiler.SyntaxKind.SingleLineCommentTrivia) {
|
|
1632
1690
|
continue;
|
|
@@ -1636,15 +1694,17 @@ class Directive {
|
|
|
1636
1694
|
ranges.push(range);
|
|
1637
1695
|
}
|
|
1638
1696
|
}
|
|
1697
|
+
Directive.#rangeCache.set(node, ranges);
|
|
1639
1698
|
return ranges;
|
|
1640
1699
|
}
|
|
1641
1700
|
static async getInlineConfig(ranges) {
|
|
1642
1701
|
if (!ranges) {
|
|
1643
1702
|
return;
|
|
1644
1703
|
}
|
|
1704
|
+
ranges = Array.isArray(ranges) ? ranges : [ranges];
|
|
1645
1705
|
const inlineConfig = {};
|
|
1646
1706
|
for (const range of ranges) {
|
|
1647
|
-
await Directive.#parse(inlineConfig,
|
|
1707
|
+
await Directive.#parse(inlineConfig, range);
|
|
1648
1708
|
}
|
|
1649
1709
|
return inlineConfig;
|
|
1650
1710
|
}
|
|
@@ -1656,6 +1716,7 @@ class Directive {
|
|
|
1656
1716
|
return;
|
|
1657
1717
|
}
|
|
1658
1718
|
const range = {
|
|
1719
|
+
sourceFile,
|
|
1659
1720
|
namespace: { start: comment.pos, end: comment.pos + namespaceText.length, text: namespaceText },
|
|
1660
1721
|
};
|
|
1661
1722
|
const directiveSeparatorText = match?.[2];
|
|
@@ -1675,45 +1736,61 @@ class Directive {
|
|
|
1675
1736
|
static #onDiagnostics(diagnostic) {
|
|
1676
1737
|
EventEmitter.dispatch(["directive:error", { diagnostics: [diagnostic] }]);
|
|
1677
1738
|
}
|
|
1678
|
-
static async #parse(inlineConfig,
|
|
1679
|
-
switch (
|
|
1739
|
+
static async #parse(inlineConfig, range) {
|
|
1740
|
+
switch (range.directive?.text) {
|
|
1680
1741
|
case "if":
|
|
1681
1742
|
{
|
|
1682
|
-
if (!
|
|
1743
|
+
if (!range.argument?.text) {
|
|
1683
1744
|
const text = DirectiveDiagnosticText.requiresArgument();
|
|
1684
|
-
const origin = new DiagnosticOrigin(
|
|
1745
|
+
const origin = new DiagnosticOrigin(range.namespace.start, range.directive.end, range.sourceFile);
|
|
1685
1746
|
Directive.#onDiagnostics(Diagnostic.error(text, origin));
|
|
1686
1747
|
return;
|
|
1687
1748
|
}
|
|
1688
|
-
const value = await Directive.#parseJson(sourceFile,
|
|
1749
|
+
const value = await Directive.#parseJson(range.sourceFile, range.argument.start, range.argument.end);
|
|
1689
1750
|
inlineConfig.if = value;
|
|
1690
1751
|
}
|
|
1691
1752
|
return;
|
|
1753
|
+
case "fixme":
|
|
1692
1754
|
case "template":
|
|
1693
|
-
if (
|
|
1755
|
+
if (range.argument?.text != null) {
|
|
1694
1756
|
const text = DirectiveDiagnosticText.doesNotTakeArgument();
|
|
1695
|
-
const origin = new DiagnosticOrigin(
|
|
1757
|
+
const origin = new DiagnosticOrigin(range.argument.start, range.argument.end, range.sourceFile);
|
|
1696
1758
|
Directive.#onDiagnostics(Diagnostic.error(text, origin));
|
|
1697
1759
|
}
|
|
1698
|
-
inlineConfig.
|
|
1760
|
+
inlineConfig[range.directive?.text] = true;
|
|
1699
1761
|
return;
|
|
1700
1762
|
}
|
|
1701
|
-
const target =
|
|
1763
|
+
const target = range?.directive ?? range.namespace;
|
|
1702
1764
|
const text = DirectiveDiagnosticText.isNotSupported(target.text);
|
|
1703
|
-
const origin = new DiagnosticOrigin(target.start, target.end, sourceFile);
|
|
1765
|
+
const origin = new DiagnosticOrigin(target.start, target.end, range.sourceFile);
|
|
1704
1766
|
Directive.#onDiagnostics(Diagnostic.error(text, origin));
|
|
1705
1767
|
}
|
|
1706
1768
|
static async #parseJson(sourceFile, start, end) {
|
|
1707
1769
|
const inlineOptions = {};
|
|
1708
|
-
const configParser = new ConfigParser(inlineOptions,
|
|
1770
|
+
const configParser = new ConfigParser(inlineOptions, 8, sourceFile, new JsonScanner(sourceFile, { start, end }), Directive.#onDiagnostics);
|
|
1709
1771
|
await configParser.parse();
|
|
1710
|
-
if ("target" in inlineOptions) {
|
|
1711
|
-
inlineOptions["target"] = await Target.expand(inlineOptions["target"]);
|
|
1712
|
-
}
|
|
1713
1772
|
return inlineOptions;
|
|
1714
1773
|
}
|
|
1715
1774
|
}
|
|
1716
1775
|
|
|
1776
|
+
var OptionBrand;
|
|
1777
|
+
(function (OptionBrand) {
|
|
1778
|
+
OptionBrand["String"] = "string";
|
|
1779
|
+
OptionBrand["SemverRange"] = "range";
|
|
1780
|
+
OptionBrand["Number"] = "number";
|
|
1781
|
+
OptionBrand["Boolean"] = "boolean";
|
|
1782
|
+
OptionBrand["True"] = "true";
|
|
1783
|
+
OptionBrand["List"] = "list";
|
|
1784
|
+
})(OptionBrand || (OptionBrand = {}));
|
|
1785
|
+
|
|
1786
|
+
var OptionGroup;
|
|
1787
|
+
(function (OptionGroup) {
|
|
1788
|
+
OptionGroup[OptionGroup["CommandLine"] = 2] = "CommandLine";
|
|
1789
|
+
OptionGroup[OptionGroup["ConfigFile"] = 4] = "ConfigFile";
|
|
1790
|
+
OptionGroup[OptionGroup["InlineConditions"] = 8] = "InlineConditions";
|
|
1791
|
+
OptionGroup[OptionGroup["ResolvedConfig"] = 6] = "ResolvedConfig";
|
|
1792
|
+
})(OptionGroup || (OptionGroup = {}));
|
|
1793
|
+
|
|
1717
1794
|
class CancellationHandler {
|
|
1718
1795
|
#cancellationToken;
|
|
1719
1796
|
#cancellationReason;
|
|
@@ -1723,7 +1800,7 @@ class CancellationHandler {
|
|
|
1723
1800
|
}
|
|
1724
1801
|
on([, payload]) {
|
|
1725
1802
|
if ("diagnostics" in payload) {
|
|
1726
|
-
if (payload.diagnostics.some((diagnostic) => diagnostic.category ===
|
|
1803
|
+
if (payload.diagnostics.some((diagnostic) => diagnostic.category === "error")) {
|
|
1727
1804
|
this.#cancellationToken.cancel(this.#cancellationReason);
|
|
1728
1805
|
}
|
|
1729
1806
|
}
|
|
@@ -1737,7 +1814,7 @@ class ExitCodeHandler {
|
|
|
1737
1814
|
return;
|
|
1738
1815
|
}
|
|
1739
1816
|
if ("diagnostics" in payload) {
|
|
1740
|
-
if (payload.diagnostics.some((diagnostic) => diagnostic.category ===
|
|
1817
|
+
if (payload.diagnostics.some((diagnostic) => diagnostic.category === "error")) {
|
|
1741
1818
|
this.#setCode(1);
|
|
1742
1819
|
}
|
|
1743
1820
|
}
|
|
@@ -1769,27 +1846,42 @@ class DescribeResult {
|
|
|
1769
1846
|
}
|
|
1770
1847
|
}
|
|
1771
1848
|
|
|
1772
|
-
var ResultStatus;
|
|
1773
|
-
(function (ResultStatus) {
|
|
1774
|
-
ResultStatus["Runs"] = "runs";
|
|
1775
|
-
ResultStatus["Passed"] = "passed";
|
|
1776
|
-
ResultStatus["Failed"] = "failed";
|
|
1777
|
-
ResultStatus["Skipped"] = "skipped";
|
|
1778
|
-
ResultStatus["Todo"] = "todo";
|
|
1779
|
-
})(ResultStatus || (ResultStatus = {}));
|
|
1780
|
-
|
|
1781
1849
|
class ExpectResult {
|
|
1782
|
-
|
|
1850
|
+
expect;
|
|
1783
1851
|
diagnostics = [];
|
|
1784
1852
|
parent;
|
|
1785
|
-
status =
|
|
1853
|
+
status = "runs";
|
|
1786
1854
|
timing = new ResultTiming();
|
|
1787
|
-
constructor(
|
|
1788
|
-
this.
|
|
1855
|
+
constructor(expect, parent) {
|
|
1856
|
+
this.expect = expect;
|
|
1789
1857
|
this.parent = parent;
|
|
1790
1858
|
}
|
|
1791
1859
|
}
|
|
1792
1860
|
|
|
1861
|
+
class ResultCount {
|
|
1862
|
+
failed = 0;
|
|
1863
|
+
passed = 0;
|
|
1864
|
+
skipped = 0;
|
|
1865
|
+
fixme = 0;
|
|
1866
|
+
todo = 0;
|
|
1867
|
+
get total() {
|
|
1868
|
+
return this.failed + this.passed + this.skipped + this.fixme + this.todo;
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
class FileResult {
|
|
1873
|
+
diagnostics = [];
|
|
1874
|
+
expectCount = new ResultCount();
|
|
1875
|
+
file;
|
|
1876
|
+
results = [];
|
|
1877
|
+
status = "runs";
|
|
1878
|
+
testCount = new ResultCount();
|
|
1879
|
+
timing = new ResultTiming();
|
|
1880
|
+
constructor(file) {
|
|
1881
|
+
this.file = file;
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1793
1885
|
class ProjectResult {
|
|
1794
1886
|
compilerVersion;
|
|
1795
1887
|
diagnostics = [];
|
|
@@ -1801,51 +1893,38 @@ class ProjectResult {
|
|
|
1801
1893
|
}
|
|
1802
1894
|
}
|
|
1803
1895
|
|
|
1804
|
-
class ResultCount {
|
|
1805
|
-
failed = 0;
|
|
1806
|
-
passed = 0;
|
|
1807
|
-
skipped = 0;
|
|
1808
|
-
todo = 0;
|
|
1809
|
-
get total() {
|
|
1810
|
-
return this.failed + this.passed + this.skipped + this.todo;
|
|
1811
|
-
}
|
|
1812
|
-
}
|
|
1813
|
-
|
|
1814
1896
|
class Result {
|
|
1815
1897
|
expectCount = new ResultCount();
|
|
1816
1898
|
fileCount = new ResultCount();
|
|
1899
|
+
files;
|
|
1817
1900
|
results = [];
|
|
1818
1901
|
targetCount = new ResultCount();
|
|
1819
|
-
tasks;
|
|
1820
1902
|
testCount = new ResultCount();
|
|
1821
1903
|
timing = new ResultTiming();
|
|
1822
|
-
constructor(
|
|
1823
|
-
this.
|
|
1904
|
+
constructor(files) {
|
|
1905
|
+
this.files = files;
|
|
1824
1906
|
}
|
|
1825
1907
|
}
|
|
1826
1908
|
|
|
1909
|
+
var ResultStatus;
|
|
1910
|
+
(function (ResultStatus) {
|
|
1911
|
+
ResultStatus["Runs"] = "runs";
|
|
1912
|
+
ResultStatus["Passed"] = "passed";
|
|
1913
|
+
ResultStatus["Failed"] = "failed";
|
|
1914
|
+
ResultStatus["Skipped"] = "skipped";
|
|
1915
|
+
ResultStatus["Fixme"] = "fixme";
|
|
1916
|
+
ResultStatus["Todo"] = "todo";
|
|
1917
|
+
})(ResultStatus || (ResultStatus = {}));
|
|
1918
|
+
|
|
1827
1919
|
class TargetResult {
|
|
1920
|
+
files;
|
|
1828
1921
|
results = new Map();
|
|
1829
|
-
status =
|
|
1922
|
+
status = "runs";
|
|
1830
1923
|
target;
|
|
1831
|
-
tasks;
|
|
1832
1924
|
timing = new ResultTiming();
|
|
1833
|
-
constructor(target,
|
|
1925
|
+
constructor(target, files) {
|
|
1834
1926
|
this.target = target;
|
|
1835
|
-
this.
|
|
1836
|
-
}
|
|
1837
|
-
}
|
|
1838
|
-
|
|
1839
|
-
class TaskResult {
|
|
1840
|
-
diagnostics = [];
|
|
1841
|
-
expectCount = new ResultCount();
|
|
1842
|
-
results = [];
|
|
1843
|
-
status = ResultStatus.Runs;
|
|
1844
|
-
task;
|
|
1845
|
-
testCount = new ResultCount();
|
|
1846
|
-
timing = new ResultTiming();
|
|
1847
|
-
constructor(task) {
|
|
1848
|
-
this.task = task;
|
|
1927
|
+
this.files = files;
|
|
1849
1928
|
}
|
|
1850
1929
|
}
|
|
1851
1930
|
|
|
@@ -1854,7 +1933,7 @@ class TestResult {
|
|
|
1854
1933
|
expectCount = new ResultCount();
|
|
1855
1934
|
parent;
|
|
1856
1935
|
results = [];
|
|
1857
|
-
status =
|
|
1936
|
+
status = "runs";
|
|
1858
1937
|
test;
|
|
1859
1938
|
timing = new ResultTiming();
|
|
1860
1939
|
constructor(test, parent) {
|
|
@@ -1866,10 +1945,10 @@ class TestResult {
|
|
|
1866
1945
|
class ResultHandler {
|
|
1867
1946
|
#describeResult;
|
|
1868
1947
|
#expectResult;
|
|
1948
|
+
#fileResult;
|
|
1869
1949
|
#projectResult;
|
|
1870
1950
|
#result;
|
|
1871
1951
|
#targetResult;
|
|
1872
|
-
#taskResult;
|
|
1873
1952
|
#testResult;
|
|
1874
1953
|
on([event, payload]) {
|
|
1875
1954
|
switch (event) {
|
|
@@ -1887,19 +1966,19 @@ class ResultHandler {
|
|
|
1887
1966
|
this.#targetResult.timing.start = Date.now();
|
|
1888
1967
|
break;
|
|
1889
1968
|
case "target:end":
|
|
1890
|
-
if (this.#targetResult.status ===
|
|
1969
|
+
if (this.#targetResult.status === "failed") {
|
|
1891
1970
|
this.#result.targetCount.failed++;
|
|
1892
1971
|
}
|
|
1893
1972
|
else {
|
|
1894
1973
|
this.#result.targetCount.passed++;
|
|
1895
|
-
this.#targetResult.status =
|
|
1974
|
+
this.#targetResult.status = "passed";
|
|
1896
1975
|
}
|
|
1897
1976
|
this.#targetResult.timing.end = Date.now();
|
|
1898
1977
|
this.#targetResult = undefined;
|
|
1899
1978
|
break;
|
|
1900
1979
|
case "store:error":
|
|
1901
|
-
if (payload.diagnostics.some(({ category }) => category ===
|
|
1902
|
-
this.#targetResult.status =
|
|
1980
|
+
if (payload.diagnostics.some(({ category }) => category === "error")) {
|
|
1981
|
+
this.#targetResult.status = "failed";
|
|
1903
1982
|
}
|
|
1904
1983
|
break;
|
|
1905
1984
|
case "project:uses": {
|
|
@@ -1912,42 +1991,42 @@ class ResultHandler {
|
|
|
1912
1991
|
break;
|
|
1913
1992
|
}
|
|
1914
1993
|
case "project:error":
|
|
1915
|
-
this.#targetResult.status =
|
|
1994
|
+
this.#targetResult.status = "failed";
|
|
1916
1995
|
this.#projectResult.diagnostics.push(...payload.diagnostics);
|
|
1917
1996
|
break;
|
|
1918
|
-
case "
|
|
1997
|
+
case "file:start":
|
|
1919
1998
|
this.#projectResult.results.push(payload.result);
|
|
1920
|
-
this.#
|
|
1921
|
-
this.#
|
|
1999
|
+
this.#fileResult = payload.result;
|
|
2000
|
+
this.#fileResult.timing.start = Date.now();
|
|
1922
2001
|
break;
|
|
1923
|
-
case "
|
|
2002
|
+
case "file:error":
|
|
1924
2003
|
case "directive:error":
|
|
1925
2004
|
case "collect:error":
|
|
1926
|
-
this.#targetResult.status =
|
|
1927
|
-
this.#
|
|
1928
|
-
this.#
|
|
2005
|
+
this.#targetResult.status = "failed";
|
|
2006
|
+
this.#fileResult.status = "failed";
|
|
2007
|
+
this.#fileResult.diagnostics.push(...payload.diagnostics);
|
|
1929
2008
|
break;
|
|
1930
|
-
case "
|
|
1931
|
-
if (this.#
|
|
1932
|
-
this.#
|
|
1933
|
-
this.#
|
|
2009
|
+
case "file:end":
|
|
2010
|
+
if (this.#fileResult.status === "failed" ||
|
|
2011
|
+
this.#fileResult.expectCount.failed > 0 ||
|
|
2012
|
+
this.#fileResult.testCount.failed > 0) {
|
|
1934
2013
|
this.#result.fileCount.failed++;
|
|
1935
|
-
this.#targetResult.status =
|
|
1936
|
-
this.#
|
|
2014
|
+
this.#targetResult.status = "failed";
|
|
2015
|
+
this.#fileResult.status = "failed";
|
|
1937
2016
|
}
|
|
1938
2017
|
else {
|
|
1939
2018
|
this.#result.fileCount.passed++;
|
|
1940
|
-
this.#
|
|
2019
|
+
this.#fileResult.status = "passed";
|
|
1941
2020
|
}
|
|
1942
|
-
this.#
|
|
1943
|
-
this.#
|
|
2021
|
+
this.#fileResult.timing.end = Date.now();
|
|
2022
|
+
this.#fileResult = undefined;
|
|
1944
2023
|
break;
|
|
1945
2024
|
case "describe:start":
|
|
1946
2025
|
if (this.#describeResult) {
|
|
1947
2026
|
this.#describeResult.results.push(payload.result);
|
|
1948
2027
|
}
|
|
1949
2028
|
else {
|
|
1950
|
-
this.#
|
|
2029
|
+
this.#fileResult.results.push(payload.result);
|
|
1951
2030
|
}
|
|
1952
2031
|
this.#describeResult = payload.result;
|
|
1953
2032
|
this.#describeResult.timing.start = Date.now();
|
|
@@ -1961,44 +2040,51 @@ class ResultHandler {
|
|
|
1961
2040
|
this.#describeResult.results.push(payload.result);
|
|
1962
2041
|
}
|
|
1963
2042
|
else {
|
|
1964
|
-
this.#
|
|
2043
|
+
this.#fileResult.results.push(payload.result);
|
|
1965
2044
|
}
|
|
1966
2045
|
this.#testResult = payload.result;
|
|
1967
2046
|
this.#testResult.timing.start = Date.now();
|
|
1968
2047
|
break;
|
|
1969
2048
|
case "test:error":
|
|
1970
2049
|
this.#result.testCount.failed++;
|
|
1971
|
-
this.#
|
|
1972
|
-
this.#testResult.status =
|
|
2050
|
+
this.#fileResult.testCount.failed++;
|
|
2051
|
+
this.#testResult.status = "failed";
|
|
1973
2052
|
this.#testResult.diagnostics.push(...payload.diagnostics);
|
|
1974
2053
|
this.#testResult.timing.end = Date.now();
|
|
1975
2054
|
this.#testResult = undefined;
|
|
1976
2055
|
break;
|
|
1977
2056
|
case "test:fail":
|
|
1978
2057
|
this.#result.testCount.failed++;
|
|
1979
|
-
this.#
|
|
1980
|
-
this.#testResult.status =
|
|
2058
|
+
this.#fileResult.testCount.failed++;
|
|
2059
|
+
this.#testResult.status = "failed";
|
|
1981
2060
|
this.#testResult.timing.end = Date.now();
|
|
1982
2061
|
this.#testResult = undefined;
|
|
1983
2062
|
break;
|
|
1984
2063
|
case "test:pass":
|
|
1985
2064
|
this.#result.testCount.passed++;
|
|
1986
|
-
this.#
|
|
1987
|
-
this.#testResult.status =
|
|
2065
|
+
this.#fileResult.testCount.passed++;
|
|
2066
|
+
this.#testResult.status = "passed";
|
|
1988
2067
|
this.#testResult.timing.end = Date.now();
|
|
1989
2068
|
this.#testResult = undefined;
|
|
1990
2069
|
break;
|
|
1991
2070
|
case "test:skip":
|
|
1992
2071
|
this.#result.testCount.skipped++;
|
|
1993
|
-
this.#
|
|
1994
|
-
this.#testResult.status =
|
|
2072
|
+
this.#fileResult.testCount.skipped++;
|
|
2073
|
+
this.#testResult.status = "skipped";
|
|
2074
|
+
this.#testResult.timing.end = Date.now();
|
|
2075
|
+
this.#testResult = undefined;
|
|
2076
|
+
break;
|
|
2077
|
+
case "test:fixme":
|
|
2078
|
+
this.#result.testCount.fixme++;
|
|
2079
|
+
this.#fileResult.testCount.fixme++;
|
|
2080
|
+
this.#testResult.status = "fixme";
|
|
1995
2081
|
this.#testResult.timing.end = Date.now();
|
|
1996
2082
|
this.#testResult = undefined;
|
|
1997
2083
|
break;
|
|
1998
2084
|
case "test:todo":
|
|
1999
2085
|
this.#result.testCount.todo++;
|
|
2000
|
-
this.#
|
|
2001
|
-
this.#testResult.status =
|
|
2086
|
+
this.#fileResult.testCount.todo++;
|
|
2087
|
+
this.#testResult.status = "todo";
|
|
2002
2088
|
this.#testResult.timing.end = Date.now();
|
|
2003
2089
|
this.#testResult = undefined;
|
|
2004
2090
|
break;
|
|
@@ -2007,49 +2093,59 @@ class ResultHandler {
|
|
|
2007
2093
|
this.#testResult.results.push(payload.result);
|
|
2008
2094
|
}
|
|
2009
2095
|
else {
|
|
2010
|
-
this.#
|
|
2096
|
+
this.#fileResult.results.push(payload.result);
|
|
2011
2097
|
}
|
|
2012
2098
|
this.#expectResult = payload.result;
|
|
2013
2099
|
this.#expectResult.timing.start = Date.now();
|
|
2014
2100
|
break;
|
|
2015
2101
|
case "expect:error":
|
|
2016
2102
|
this.#result.expectCount.failed++;
|
|
2017
|
-
this.#
|
|
2103
|
+
this.#fileResult.expectCount.failed++;
|
|
2018
2104
|
if (this.#testResult) {
|
|
2019
2105
|
this.#testResult.expectCount.failed++;
|
|
2020
2106
|
}
|
|
2021
|
-
this.#expectResult.status =
|
|
2107
|
+
this.#expectResult.status = "failed";
|
|
2022
2108
|
this.#expectResult.diagnostics.push(...payload.diagnostics);
|
|
2023
2109
|
this.#expectResult.timing.end = Date.now();
|
|
2024
2110
|
this.#expectResult = undefined;
|
|
2025
2111
|
break;
|
|
2026
2112
|
case "expect:fail":
|
|
2027
2113
|
this.#result.expectCount.failed++;
|
|
2028
|
-
this.#
|
|
2114
|
+
this.#fileResult.expectCount.failed++;
|
|
2029
2115
|
if (this.#testResult) {
|
|
2030
2116
|
this.#testResult.expectCount.failed++;
|
|
2031
2117
|
}
|
|
2032
|
-
this.#expectResult.status =
|
|
2118
|
+
this.#expectResult.status = "failed";
|
|
2033
2119
|
this.#expectResult.timing.end = Date.now();
|
|
2034
2120
|
this.#expectResult = undefined;
|
|
2035
2121
|
break;
|
|
2036
2122
|
case "expect:pass":
|
|
2037
2123
|
this.#result.expectCount.passed++;
|
|
2038
|
-
this.#
|
|
2124
|
+
this.#fileResult.expectCount.passed++;
|
|
2039
2125
|
if (this.#testResult) {
|
|
2040
2126
|
this.#testResult.expectCount.passed++;
|
|
2041
2127
|
}
|
|
2042
|
-
this.#expectResult.status =
|
|
2128
|
+
this.#expectResult.status = "passed";
|
|
2043
2129
|
this.#expectResult.timing.end = Date.now();
|
|
2044
2130
|
this.#expectResult = undefined;
|
|
2045
2131
|
break;
|
|
2046
2132
|
case "expect:skip":
|
|
2047
2133
|
this.#result.expectCount.skipped++;
|
|
2048
|
-
this.#
|
|
2134
|
+
this.#fileResult.expectCount.skipped++;
|
|
2049
2135
|
if (this.#testResult) {
|
|
2050
2136
|
this.#testResult.expectCount.skipped++;
|
|
2051
2137
|
}
|
|
2052
|
-
this.#expectResult.status =
|
|
2138
|
+
this.#expectResult.status = "skipped";
|
|
2139
|
+
this.#expectResult.timing.end = Date.now();
|
|
2140
|
+
this.#expectResult = undefined;
|
|
2141
|
+
break;
|
|
2142
|
+
case "expect:fixme":
|
|
2143
|
+
this.#result.expectCount.fixme++;
|
|
2144
|
+
this.#fileResult.expectCount.fixme++;
|
|
2145
|
+
if (this.#testResult) {
|
|
2146
|
+
this.#testResult.expectCount.fixme++;
|
|
2147
|
+
}
|
|
2148
|
+
this.#expectResult.status = "fixme";
|
|
2053
2149
|
this.#expectResult.timing.end = Date.now();
|
|
2054
2150
|
this.#expectResult = undefined;
|
|
2055
2151
|
break;
|
|
@@ -2078,7 +2174,7 @@ function Text({ children, color, indent }) {
|
|
|
2078
2174
|
if (color != null) {
|
|
2079
2175
|
ansiEscapes.push(color);
|
|
2080
2176
|
}
|
|
2081
|
-
return (jsx("text", { indent: indent ?? 0, children: [ansiEscapes.length > 0 ? jsx("ansi", { escapes: ansiEscapes }) : undefined, children, ansiEscapes.length > 0 ? jsx("ansi", { escapes:
|
|
2177
|
+
return (jsx("text", { indent: indent ?? 0, children: [ansiEscapes.length > 0 ? jsx("ansi", { escapes: ansiEscapes }) : undefined, children, ansiEscapes.length > 0 ? jsx("ansi", { escapes: "0" }) : undefined] }));
|
|
2082
2178
|
}
|
|
2083
2179
|
|
|
2084
2180
|
function Line({ children, color, indent }) {
|
|
@@ -2139,7 +2235,7 @@ class Scribbler {
|
|
|
2139
2235
|
}
|
|
2140
2236
|
|
|
2141
2237
|
function addsPackageText(packageVersion, packagePath) {
|
|
2142
|
-
return (jsx(Line, { children: [jsx(Text, { color:
|
|
2238
|
+
return (jsx(Line, { children: [jsx(Text, { color: "90", children: "adds" }), " TypeScript ", packageVersion, jsx(Text, { color: "90", children: [" to ", packagePath] })] }));
|
|
2143
2239
|
}
|
|
2144
2240
|
|
|
2145
2241
|
function describeNameText(name, indent = 0) {
|
|
@@ -2155,13 +2251,13 @@ function BreadcrumbsText({ ancestor }) {
|
|
|
2155
2251
|
ancestor = ancestor.parent;
|
|
2156
2252
|
}
|
|
2157
2253
|
text.push("");
|
|
2158
|
-
return jsx(Text, { color:
|
|
2254
|
+
return jsx(Text, { color: "90", children: text.reverse().join(" ❭ ") });
|
|
2159
2255
|
}
|
|
2160
|
-
function CodeLineText({ gutterWidth, lineNumber, lineNumberColor =
|
|
2161
|
-
return (jsx(Line, { children: [jsx(Text, { color: lineNumberColor, children: lineNumber.toString().padStart(gutterWidth) }), jsx(Text, { color:
|
|
2256
|
+
function CodeLineText({ gutterWidth, lineNumber, lineNumberColor = "90", lineText }) {
|
|
2257
|
+
return (jsx(Line, { children: [jsx(Text, { color: lineNumberColor, children: lineNumber.toString().padStart(gutterWidth) }), jsx(Text, { color: "90", children: " | " }), lineText] }));
|
|
2162
2258
|
}
|
|
2163
2259
|
function SquiggleLineText({ gutterWidth, indentWidth = 0, squiggleColor, squiggleWidth }) {
|
|
2164
|
-
return (jsx(Line, { children: [" ".repeat(gutterWidth), jsx(Text, { color:
|
|
2260
|
+
return (jsx(Line, { children: [" ".repeat(gutterWidth), jsx(Text, { color: "90", children: " | " }), " ".repeat(indentWidth), jsx(Text, { color: squiggleColor, children: "~".repeat(squiggleWidth === 0 ? 1 : squiggleWidth) })] }));
|
|
2165
2261
|
}
|
|
2166
2262
|
function CodeFrameText({ diagnosticCategory, diagnosticOrigin, options }) {
|
|
2167
2263
|
const linesAbove = options?.linesAbove ?? 2;
|
|
@@ -2175,11 +2271,11 @@ function CodeFrameText({ diagnosticCategory, diagnosticOrigin, options }) {
|
|
|
2175
2271
|
const gutterWidth = (lastLine + 1).toString().length + 2;
|
|
2176
2272
|
let highlightColor;
|
|
2177
2273
|
switch (diagnosticCategory) {
|
|
2178
|
-
case
|
|
2179
|
-
highlightColor =
|
|
2274
|
+
case "error":
|
|
2275
|
+
highlightColor = "31";
|
|
2180
2276
|
break;
|
|
2181
|
-
case
|
|
2182
|
-
highlightColor =
|
|
2277
|
+
case "warning":
|
|
2278
|
+
highlightColor = "33";
|
|
2183
2279
|
break;
|
|
2184
2280
|
}
|
|
2185
2281
|
const codeFrame = [];
|
|
@@ -2207,32 +2303,59 @@ function CodeFrameText({ diagnosticCategory, diagnosticOrigin, options }) {
|
|
|
2207
2303
|
}
|
|
2208
2304
|
}
|
|
2209
2305
|
let breadcrumbs;
|
|
2210
|
-
if (showBreadcrumbs && diagnosticOrigin.
|
|
2211
|
-
breadcrumbs = jsx(BreadcrumbsText, { ancestor: diagnosticOrigin.
|
|
2306
|
+
if (showBreadcrumbs && diagnosticOrigin.assertionNode != null) {
|
|
2307
|
+
breadcrumbs = jsx(BreadcrumbsText, { ancestor: diagnosticOrigin.assertionNode.parent });
|
|
2212
2308
|
}
|
|
2213
|
-
const location = (jsx(Line, { children: [" ".repeat(gutterWidth + 2), jsx(Text, { color:
|
|
2309
|
+
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}:${firstMarkedLineCharacter + 1}` }), breadcrumbs] }));
|
|
2214
2310
|
return (jsx(Text, { children: [codeFrame, jsx(Line, {}), location] }));
|
|
2215
2311
|
}
|
|
2216
2312
|
|
|
2217
2313
|
function DiagnosticText({ codeFrameOptions, diagnostic }) {
|
|
2218
|
-
const code = diagnostic.code ? jsx(Text, { color:
|
|
2314
|
+
const code = diagnostic.code ? jsx(Text, { color: "90", children: [" ", diagnostic.code] }) : undefined;
|
|
2219
2315
|
const text = Array.isArray(diagnostic.text) ? diagnostic.text : [diagnostic.text];
|
|
2220
2316
|
const message = text.map((text, index) => (jsx(Text, { children: [index === 1 ? jsx(Line, {}) : undefined, jsx(Line, { children: [text, index === 0 ? code : undefined] })] })));
|
|
2221
2317
|
const related = diagnostic.related?.map((relatedDiagnostic) => jsx(DiagnosticText, { diagnostic: relatedDiagnostic }));
|
|
2222
2318
|
const codeFrame = diagnostic.origin ? (jsx(Text, { children: [jsx(Line, {}), jsx(CodeFrameText, { diagnosticCategory: diagnostic.category, diagnosticOrigin: diagnostic.origin, options: codeFrameOptions })] })) : undefined;
|
|
2223
2319
|
return (jsx(Text, { children: [message, codeFrame, jsx(Line, {}), jsx(Text, { indent: 2, children: related })] }));
|
|
2224
2320
|
}
|
|
2225
|
-
function diagnosticText(diagnostic, codeFrameOptions = {}) {
|
|
2226
|
-
let prefix;
|
|
2227
|
-
switch (diagnostic.category) {
|
|
2228
|
-
case
|
|
2229
|
-
prefix = jsx(Text, { color:
|
|
2321
|
+
function diagnosticText(diagnostic, codeFrameOptions = {}) {
|
|
2322
|
+
let prefix;
|
|
2323
|
+
switch (diagnostic.category) {
|
|
2324
|
+
case "error":
|
|
2325
|
+
prefix = jsx(Text, { color: "31", children: "Error: " });
|
|
2326
|
+
break;
|
|
2327
|
+
case "warning":
|
|
2328
|
+
prefix = jsx(Text, { color: "33", children: "Warning: " });
|
|
2329
|
+
break;
|
|
2330
|
+
}
|
|
2331
|
+
return (jsx(Text, { children: [prefix, jsx(DiagnosticText, { codeFrameOptions: codeFrameOptions, diagnostic: diagnostic })] }));
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
function FileNameText({ filePath }) {
|
|
2335
|
+
const relativePath = Path.relative("", filePath);
|
|
2336
|
+
const lastPathSeparator = relativePath.lastIndexOf("/");
|
|
2337
|
+
const directoryNameText = relativePath.slice(0, lastPathSeparator + 1);
|
|
2338
|
+
const fileNameText = relativePath.slice(lastPathSeparator + 1);
|
|
2339
|
+
return (jsx(Text, { children: [jsx(Text, { color: "90", children: directoryNameText }), fileNameText] }));
|
|
2340
|
+
}
|
|
2341
|
+
function fileStatusText(status, file) {
|
|
2342
|
+
let statusColor;
|
|
2343
|
+
let statusText;
|
|
2344
|
+
switch (status) {
|
|
2345
|
+
case "runs":
|
|
2346
|
+
statusColor = "33";
|
|
2347
|
+
statusText = "runs";
|
|
2230
2348
|
break;
|
|
2231
|
-
case
|
|
2232
|
-
|
|
2349
|
+
case "passed":
|
|
2350
|
+
statusColor = "32";
|
|
2351
|
+
statusText = "pass";
|
|
2352
|
+
break;
|
|
2353
|
+
case "failed":
|
|
2354
|
+
statusColor = "31";
|
|
2355
|
+
statusText = "fail";
|
|
2233
2356
|
break;
|
|
2234
2357
|
}
|
|
2235
|
-
return (jsx(
|
|
2358
|
+
return (jsx(Line, { children: [jsx(Text, { color: statusColor, children: statusText }), " ", jsx(FileNameText, { filePath: file.path })] }));
|
|
2236
2359
|
}
|
|
2237
2360
|
|
|
2238
2361
|
function fileViewText(lines, addEmptyFinalLine) {
|
|
@@ -2258,13 +2381,13 @@ function formattedText(input) {
|
|
|
2258
2381
|
}
|
|
2259
2382
|
|
|
2260
2383
|
function HintText({ children }) {
|
|
2261
|
-
return (jsx(Text, { indent: 1, color:
|
|
2384
|
+
return (jsx(Text, { indent: 1, color: "90", children: children }));
|
|
2262
2385
|
}
|
|
2263
2386
|
function HelpHeaderText({ tstycheVersion }) {
|
|
2264
2387
|
return (jsx(Line, { children: ["The TSTyche Type Test Runner", jsx(HintText, { children: tstycheVersion })] }));
|
|
2265
2388
|
}
|
|
2266
2389
|
function CommandText({ hint, text }) {
|
|
2267
|
-
return (jsx(Line, { indent: 1, children: [jsx(Text, { color:
|
|
2390
|
+
return (jsx(Line, { indent: 1, children: [jsx(Text, { color: "34", children: text }), hint && jsx(HintText, { children: hint })] }));
|
|
2268
2391
|
}
|
|
2269
2392
|
function OptionDescriptionText({ text }) {
|
|
2270
2393
|
return jsx(Line, { indent: 1, children: text });
|
|
@@ -2272,8 +2395,8 @@ function OptionDescriptionText({ text }) {
|
|
|
2272
2395
|
function CommandLineUsageText() {
|
|
2273
2396
|
const usage = [
|
|
2274
2397
|
["tstyche", "Run all tests."],
|
|
2275
|
-
["tstyche
|
|
2276
|
-
["tstyche --target 5.3
|
|
2398
|
+
["tstyche query-params", "Only run the matching test file."],
|
|
2399
|
+
["tstyche --target '5.3 || 5.5.2 || >=5.7'", "Test against specific versions of TypeScript."],
|
|
2277
2400
|
];
|
|
2278
2401
|
const usageText = usage.map(([commandText, descriptionText]) => (jsx(Line, { children: [jsx(CommandText, { text: commandText }), jsx(OptionDescriptionText, { text: descriptionText })] })));
|
|
2279
2402
|
return jsx(Text, { children: usageText });
|
|
@@ -2282,16 +2405,19 @@ function CommandLineOptionNameText({ text }) {
|
|
|
2282
2405
|
return jsx(Text, { children: `--${text}` });
|
|
2283
2406
|
}
|
|
2284
2407
|
function CommandLineOptionHintText({ definition }) {
|
|
2285
|
-
if (definition.brand ===
|
|
2408
|
+
if (definition.brand === "list") {
|
|
2286
2409
|
return jsx(Text, { children: `${definition.brand} of ${definition.items.brand}s` });
|
|
2287
2410
|
}
|
|
2411
|
+
if (definition.brand === "range") {
|
|
2412
|
+
return jsx(Text, { children: "string" });
|
|
2413
|
+
}
|
|
2288
2414
|
return jsx(Text, { children: definition.brand });
|
|
2289
2415
|
}
|
|
2290
2416
|
function CommandLineOptionsText({ optionDefinitions }) {
|
|
2291
2417
|
const definitions = [...optionDefinitions.values()];
|
|
2292
2418
|
const optionsText = definitions.map((definition) => {
|
|
2293
2419
|
let hint;
|
|
2294
|
-
if (definition.brand !==
|
|
2420
|
+
if (definition.brand !== "true") {
|
|
2295
2421
|
hint = jsx(CommandLineOptionHintText, { definition: definition });
|
|
2296
2422
|
}
|
|
2297
2423
|
return (jsx(Text, { children: [jsx(CommandText, { text: jsx(CommandLineOptionNameText, { text: definition.name }), hint: hint }), jsx(OptionDescriptionText, { text: definition.description }), jsx(Line, {})] }));
|
|
@@ -2340,69 +2466,44 @@ class OutputService {
|
|
|
2340
2466
|
function RowText({ label, text }) {
|
|
2341
2467
|
return (jsx(Line, { children: [`${label}:`.padEnd(12), text] }));
|
|
2342
2468
|
}
|
|
2343
|
-
function CountText({ failed, passed, skipped, todo, total }) {
|
|
2344
|
-
return (jsx(Text, { children: [failed > 0 ? (jsx(Text, { children: [jsx(Text, { color:
|
|
2469
|
+
function CountText({ failed, fixme, passed, skipped, todo, total }) {
|
|
2470
|
+
return (jsx(Text, { children: [failed > 0 ? (jsx(Text, { children: [jsx(Text, { color: "31", children: [failed, " failed"] }), jsx(Text, { children: ", " })] })) : undefined, fixme > 0 ? (jsx(Text, { children: [jsx(Text, { color: "33", children: [fixme, " fixme"] }), jsx(Text, { children: ", " })] })) : undefined, skipped > 0 ? (jsx(Text, { children: [jsx(Text, { color: "33", children: [skipped, " skipped"] }), jsx(Text, { children: ", " })] })) : undefined, todo > 0 ? (jsx(Text, { children: [jsx(Text, { color: "35", children: [todo, " todo"] }), jsx(Text, { children: ", " })] })) : undefined, passed > 0 ? (jsx(Text, { children: [jsx(Text, { color: "32", children: [passed, " passed"] }), jsx(Text, { children: ", " })] })) : undefined, jsx(Text, { children: [total, " total"] })] }));
|
|
2345
2471
|
}
|
|
2346
2472
|
function DurationText({ seconds }) {
|
|
2347
2473
|
return jsx(Text, { children: `${Math.round(seconds * 10) / 10}s` });
|
|
2348
2474
|
}
|
|
2349
2475
|
function summaryText({ duration, expectCount, fileCount, targetCount, testCount, }) {
|
|
2350
|
-
const targetCountText = (jsx(RowText, { label: "Targets", text: jsx(CountText, { failed: targetCount.failed, passed: targetCount.passed, skipped: targetCount.skipped, todo: targetCount.todo, total: targetCount.total }) }));
|
|
2351
|
-
const fileCountText = (jsx(RowText, { label: "Test files", text: jsx(CountText, { failed: fileCount.failed, passed: fileCount.passed, skipped: fileCount.skipped, todo: fileCount.todo, total: fileCount.total }) }));
|
|
2352
|
-
const testCountText = (jsx(RowText, { label: "Tests", text: jsx(CountText, { failed: testCount.failed, passed: testCount.passed, skipped: testCount.skipped, todo: testCount.todo, total: testCount.total }) }));
|
|
2353
|
-
const assertionCountText = (jsx(RowText, { label: "Assertions", text: jsx(CountText, { failed: expectCount.failed, passed: expectCount.passed, skipped: expectCount.skipped, todo: expectCount.todo, total: expectCount.total }) }));
|
|
2476
|
+
const targetCountText = (jsx(RowText, { label: "Targets", text: jsx(CountText, { failed: targetCount.failed, fixme: targetCount.fixme, passed: targetCount.passed, skipped: targetCount.skipped, todo: targetCount.todo, total: targetCount.total }) }));
|
|
2477
|
+
const fileCountText = (jsx(RowText, { label: "Test files", text: jsx(CountText, { failed: fileCount.failed, fixme: fileCount.fixme, passed: fileCount.passed, skipped: fileCount.skipped, todo: fileCount.todo, total: fileCount.total }) }));
|
|
2478
|
+
const testCountText = (jsx(RowText, { label: "Tests", text: jsx(CountText, { failed: testCount.failed, fixme: testCount.fixme, passed: testCount.passed, skipped: testCount.skipped, todo: testCount.todo, total: testCount.total }) }));
|
|
2479
|
+
const assertionCountText = (jsx(RowText, { label: "Assertions", text: jsx(CountText, { failed: expectCount.failed, fixme: expectCount.fixme, passed: expectCount.passed, skipped: expectCount.skipped, todo: expectCount.todo, total: expectCount.total }) }));
|
|
2354
2480
|
return (jsx(Text, { children: [targetCountText, fileCountText, testCount.total > 0 ? testCountText : undefined, expectCount.total > 0 ? assertionCountText : undefined, jsx(RowText, { label: "Duration", text: jsx(DurationText, { seconds: duration / 1000 }) })] }));
|
|
2355
2481
|
}
|
|
2356
2482
|
|
|
2357
|
-
function FileNameText({ filePath }) {
|
|
2358
|
-
const relativePath = Path.relative("", filePath);
|
|
2359
|
-
const lastPathSeparator = relativePath.lastIndexOf("/");
|
|
2360
|
-
const directoryNameText = relativePath.slice(0, lastPathSeparator + 1);
|
|
2361
|
-
const fileNameText = relativePath.slice(lastPathSeparator + 1);
|
|
2362
|
-
return (jsx(Text, { children: [jsx(Text, { color: Color.Gray, children: directoryNameText }), fileNameText] }));
|
|
2363
|
-
}
|
|
2364
|
-
function taskStatusText(status, task) {
|
|
2365
|
-
let statusColor;
|
|
2366
|
-
let statusText;
|
|
2367
|
-
switch (status) {
|
|
2368
|
-
case ResultStatus.Runs:
|
|
2369
|
-
statusColor = Color.Yellow;
|
|
2370
|
-
statusText = "runs";
|
|
2371
|
-
break;
|
|
2372
|
-
case ResultStatus.Passed:
|
|
2373
|
-
statusColor = Color.Green;
|
|
2374
|
-
statusText = "pass";
|
|
2375
|
-
break;
|
|
2376
|
-
case ResultStatus.Failed:
|
|
2377
|
-
statusColor = Color.Red;
|
|
2378
|
-
statusText = "fail";
|
|
2379
|
-
break;
|
|
2380
|
-
}
|
|
2381
|
-
return (jsx(Line, { children: [jsx(Text, { color: statusColor, children: statusText }), " ", jsx(FileNameText, { filePath: task.filePath })] }));
|
|
2382
|
-
}
|
|
2383
|
-
|
|
2384
2483
|
function StatusText({ status }) {
|
|
2385
2484
|
switch (status) {
|
|
2386
2485
|
case "fail":
|
|
2387
|
-
return jsx(Text, { color:
|
|
2486
|
+
return jsx(Text, { color: "31", children: "\u00D7" });
|
|
2388
2487
|
case "pass":
|
|
2389
|
-
return jsx(Text, { color:
|
|
2488
|
+
return jsx(Text, { color: "32", children: "+" });
|
|
2390
2489
|
case "skip":
|
|
2391
|
-
return jsx(Text, { color:
|
|
2490
|
+
return jsx(Text, { color: "33", children: "- skip" });
|
|
2491
|
+
case "fixme":
|
|
2492
|
+
return jsx(Text, { color: "33", children: "- fixme" });
|
|
2392
2493
|
case "todo":
|
|
2393
|
-
return jsx(Text, { color:
|
|
2494
|
+
return jsx(Text, { color: "35", children: "- todo" });
|
|
2394
2495
|
}
|
|
2395
2496
|
}
|
|
2396
2497
|
function testNameText(status, name, indent = 0) {
|
|
2397
|
-
return (jsx(Line, { indent: indent + 1, children: [jsx(StatusText, { status: status }), " ", jsx(Text, { color:
|
|
2498
|
+
return (jsx(Line, { indent: indent + 1, children: [jsx(StatusText, { status: status }), " ", jsx(Text, { color: "90", children: name })] }));
|
|
2398
2499
|
}
|
|
2399
2500
|
|
|
2400
2501
|
function usesCompilerText(compilerVersion, projectConfigFilePath, options) {
|
|
2401
2502
|
let projectConfigPathText;
|
|
2402
2503
|
if (projectConfigFilePath != null) {
|
|
2403
|
-
projectConfigPathText = (jsx(Text, { color:
|
|
2504
|
+
projectConfigPathText = (jsx(Text, { color: "90", children: [" with ", Path.relative("", projectConfigFilePath)] }));
|
|
2404
2505
|
}
|
|
2405
|
-
return (jsx(Text, { children: [options?.prependEmptyLine ? jsx(Line, {}) : undefined, jsx(Line, { children: [jsx(Text, { color:
|
|
2506
|
+
return (jsx(Text, { children: [options?.prependEmptyLine ? jsx(Line, {}) : undefined, jsx(Line, { children: [jsx(Text, { color: "34", children: "uses" }), " TypeScript ", compilerVersion, projectConfigPathText] }), jsx(Line, {})] }));
|
|
2406
2507
|
}
|
|
2407
2508
|
|
|
2408
2509
|
function waitingForFileChangesText() {
|
|
@@ -2415,7 +2516,7 @@ function watchUsageText() {
|
|
|
2415
2516
|
["x", "to exit."],
|
|
2416
2517
|
];
|
|
2417
2518
|
const usageText = usage.map(([keyText, actionText]) => {
|
|
2418
|
-
return (jsx(Line, { children: [jsx(Text, { color:
|
|
2519
|
+
return (jsx(Line, { children: [jsx(Text, { color: "90", children: "Press" }), jsx(Text, { children: ` ${keyText} ` }), jsx(Text, { color: "90", children: actionText })] }));
|
|
2419
2520
|
});
|
|
2420
2521
|
return jsx(Text, { children: usageText });
|
|
2421
2522
|
}
|
|
@@ -2492,7 +2593,7 @@ class ListReporter extends BaseReporter {
|
|
|
2492
2593
|
on([event, payload]) {
|
|
2493
2594
|
switch (event) {
|
|
2494
2595
|
case "run:start":
|
|
2495
|
-
this.#isFileViewExpanded = payload.result.
|
|
2596
|
+
this.#isFileViewExpanded = payload.result.files.length === 1 && this.resolvedConfig.watch !== true;
|
|
2496
2597
|
break;
|
|
2497
2598
|
case "store:adds":
|
|
2498
2599
|
OutputService.writeMessage(addsPackageText(payload.packageVersion, payload.packagePath));
|
|
@@ -2504,7 +2605,7 @@ class ListReporter extends BaseReporter {
|
|
|
2504
2605
|
}
|
|
2505
2606
|
break;
|
|
2506
2607
|
case "target:start":
|
|
2507
|
-
this.#fileCount = payload.result.
|
|
2608
|
+
this.#fileCount = payload.result.files.length;
|
|
2508
2609
|
this.#hasReportedUses = false;
|
|
2509
2610
|
break;
|
|
2510
2611
|
case "project:uses":
|
|
@@ -2519,25 +2620,25 @@ class ListReporter extends BaseReporter {
|
|
|
2519
2620
|
OutputService.writeError(diagnosticText(diagnostic));
|
|
2520
2621
|
}
|
|
2521
2622
|
break;
|
|
2522
|
-
case "
|
|
2623
|
+
case "file:start":
|
|
2523
2624
|
if (!environmentOptions.noInteractive) {
|
|
2524
|
-
OutputService.writeMessage(
|
|
2625
|
+
OutputService.writeMessage(fileStatusText(payload.result.status, payload.result.file));
|
|
2525
2626
|
}
|
|
2526
2627
|
this.#fileCount--;
|
|
2527
2628
|
this.#hasReportedError = false;
|
|
2528
2629
|
break;
|
|
2529
|
-
case "
|
|
2630
|
+
case "file:error":
|
|
2530
2631
|
case "directive:error":
|
|
2531
2632
|
case "collect:error":
|
|
2532
2633
|
for (const diagnostic of payload.diagnostics) {
|
|
2533
2634
|
this.#fileView.addMessage(diagnosticText(diagnostic));
|
|
2534
2635
|
}
|
|
2535
2636
|
break;
|
|
2536
|
-
case "
|
|
2637
|
+
case "file:end":
|
|
2537
2638
|
if (!environmentOptions.noInteractive) {
|
|
2538
2639
|
OutputService.eraseLastLine();
|
|
2539
2640
|
}
|
|
2540
|
-
OutputService.writeMessage(
|
|
2641
|
+
OutputService.writeMessage(fileStatusText(payload.result.status, payload.result.file));
|
|
2541
2642
|
OutputService.writeMessage(this.#fileView.getViewText({ appendEmptyLine: this.#isLastFile }));
|
|
2542
2643
|
if (this.#fileView.hasErrors) {
|
|
2543
2644
|
OutputService.writeError(this.#fileView.getMessages());
|
|
@@ -2560,6 +2661,11 @@ class ListReporter extends BaseReporter {
|
|
|
2560
2661
|
this.#fileView.addTest("skip", payload.result.test.name);
|
|
2561
2662
|
}
|
|
2562
2663
|
break;
|
|
2664
|
+
case "test:fixme":
|
|
2665
|
+
if (this.#isFileViewExpanded) {
|
|
2666
|
+
this.#fileView.addTest("fixme", payload.result.test.name);
|
|
2667
|
+
}
|
|
2668
|
+
break;
|
|
2563
2669
|
case "test:todo":
|
|
2564
2670
|
if (this.#isFileViewExpanded) {
|
|
2565
2671
|
this.#fileView.addTest("todo", payload.result.test.name);
|
|
@@ -2602,10 +2708,10 @@ class SetupReporter {
|
|
|
2602
2708
|
if ("diagnostics" in payload) {
|
|
2603
2709
|
for (const diagnostic of payload.diagnostics) {
|
|
2604
2710
|
switch (diagnostic.category) {
|
|
2605
|
-
case
|
|
2711
|
+
case "error":
|
|
2606
2712
|
OutputService.writeError(diagnosticText(diagnostic));
|
|
2607
2713
|
break;
|
|
2608
|
-
case
|
|
2714
|
+
case "warning":
|
|
2609
2715
|
OutputService.writeWarning(diagnosticText(diagnostic));
|
|
2610
2716
|
break;
|
|
2611
2717
|
}
|
|
@@ -2651,18 +2757,18 @@ class WatchReporter extends BaseReporter {
|
|
|
2651
2757
|
}
|
|
2652
2758
|
}
|
|
2653
2759
|
|
|
2654
|
-
class
|
|
2655
|
-
|
|
2760
|
+
class FileLocation {
|
|
2761
|
+
path;
|
|
2656
2762
|
position;
|
|
2657
|
-
constructor(
|
|
2658
|
-
this.
|
|
2763
|
+
constructor(file, position) {
|
|
2764
|
+
this.path = Path.resolve(this.#toPath(file));
|
|
2659
2765
|
this.position = position;
|
|
2660
2766
|
}
|
|
2661
|
-
#toPath(
|
|
2662
|
-
if (typeof
|
|
2663
|
-
return
|
|
2767
|
+
#toPath(file) {
|
|
2768
|
+
if (typeof file === "string" && !file.startsWith("file:")) {
|
|
2769
|
+
return file;
|
|
2664
2770
|
}
|
|
2665
|
-
return fileURLToPath(
|
|
2771
|
+
return fileURLToPath(file);
|
|
2666
2772
|
}
|
|
2667
2773
|
}
|
|
2668
2774
|
|
|
@@ -3000,9 +3106,9 @@ class WatchService {
|
|
|
3000
3106
|
#resolvedConfig;
|
|
3001
3107
|
#watchedTestFiles;
|
|
3002
3108
|
#watchers = [];
|
|
3003
|
-
constructor(resolvedConfig,
|
|
3109
|
+
constructor(resolvedConfig, files) {
|
|
3004
3110
|
this.#resolvedConfig = resolvedConfig;
|
|
3005
|
-
this.#watchedTestFiles = new Map(
|
|
3111
|
+
this.#watchedTestFiles = new Map(files.map((file) => [file.path, file]));
|
|
3006
3112
|
}
|
|
3007
3113
|
#onDiagnostics(diagnostic) {
|
|
3008
3114
|
EventEmitter.dispatch(["watch:error", { diagnostics: [diagnostic] }]);
|
|
@@ -3031,7 +3137,7 @@ class WatchService {
|
|
|
3031
3137
|
case "\u001B":
|
|
3032
3138
|
case "q":
|
|
3033
3139
|
case "x":
|
|
3034
|
-
onClose(
|
|
3140
|
+
onClose("watchClose");
|
|
3035
3141
|
break;
|
|
3036
3142
|
case "\u000D":
|
|
3037
3143
|
case "\u0020":
|
|
@@ -3047,14 +3153,14 @@ class WatchService {
|
|
|
3047
3153
|
}
|
|
3048
3154
|
const onChangedFile = (filePath) => {
|
|
3049
3155
|
debounce.refresh();
|
|
3050
|
-
let
|
|
3051
|
-
if (
|
|
3052
|
-
this.#changedTestFiles.set(filePath,
|
|
3156
|
+
let file = this.#watchedTestFiles.get(filePath);
|
|
3157
|
+
if (file != null) {
|
|
3158
|
+
this.#changedTestFiles.set(filePath, file);
|
|
3053
3159
|
}
|
|
3054
3160
|
else if (Select.isTestFile(filePath, this.#resolvedConfig)) {
|
|
3055
|
-
|
|
3056
|
-
this.#changedTestFiles.set(filePath,
|
|
3057
|
-
this.#watchedTestFiles.set(filePath,
|
|
3161
|
+
file = new FileLocation(filePath);
|
|
3162
|
+
this.#changedTestFiles.set(filePath, file);
|
|
3163
|
+
this.#watchedTestFiles.set(filePath, file);
|
|
3058
3164
|
}
|
|
3059
3165
|
};
|
|
3060
3166
|
const onRemovedFile = (filePath) => {
|
|
@@ -3067,7 +3173,7 @@ class WatchService {
|
|
|
3067
3173
|
};
|
|
3068
3174
|
this.#watchers.push(new Watcher(this.#resolvedConfig.rootPath, onChangedFile, onRemovedFile, { recursive: true }));
|
|
3069
3175
|
const onChangedConfigFile = () => {
|
|
3070
|
-
onClose(
|
|
3176
|
+
onClose("configChange");
|
|
3071
3177
|
};
|
|
3072
3178
|
this.#watchers.push(new FileWatcher(this.#resolvedConfig.configFilePath, onChangedConfigFile));
|
|
3073
3179
|
for (const watcher of this.#watchers) {
|
|
@@ -3082,65 +3188,6 @@ class WatchService {
|
|
|
3082
3188
|
}
|
|
3083
3189
|
}
|
|
3084
3190
|
|
|
3085
|
-
class TestTreeNode {
|
|
3086
|
-
brand;
|
|
3087
|
-
children = [];
|
|
3088
|
-
diagnostics = new Set();
|
|
3089
|
-
flags;
|
|
3090
|
-
name = "";
|
|
3091
|
-
node;
|
|
3092
|
-
parent;
|
|
3093
|
-
constructor(compiler, brand, node, parent, flags) {
|
|
3094
|
-
this.brand = brand;
|
|
3095
|
-
this.node = node;
|
|
3096
|
-
this.parent = parent;
|
|
3097
|
-
this.flags = flags;
|
|
3098
|
-
if (node.arguments[0] != null && compiler.isStringLiteralLike(node.arguments[0])) {
|
|
3099
|
-
this.name = node.arguments[0].text;
|
|
3100
|
-
}
|
|
3101
|
-
if (node.arguments[1] != null && compiler.isFunctionLike(node.arguments[1])) {
|
|
3102
|
-
for (const diagnostic of parent.diagnostics) {
|
|
3103
|
-
if (diagnosticBelongsToNode(diagnostic, node.arguments[1].body)) {
|
|
3104
|
-
this.diagnostics.add(diagnostic);
|
|
3105
|
-
parent.diagnostics.delete(diagnostic);
|
|
3106
|
-
}
|
|
3107
|
-
}
|
|
3108
|
-
}
|
|
3109
|
-
}
|
|
3110
|
-
getDirectiveRanges(compiler) {
|
|
3111
|
-
return Directive.getDirectiveRanges(compiler, this.node.getSourceFile(), this.node.getFullStart());
|
|
3112
|
-
}
|
|
3113
|
-
}
|
|
3114
|
-
|
|
3115
|
-
class AssertionNode extends TestTreeNode {
|
|
3116
|
-
abilityDiagnostics = new Set();
|
|
3117
|
-
isNot;
|
|
3118
|
-
matcherNode;
|
|
3119
|
-
matcherNameNode;
|
|
3120
|
-
modifierNode;
|
|
3121
|
-
notNode;
|
|
3122
|
-
source;
|
|
3123
|
-
target;
|
|
3124
|
-
constructor(compiler, brand, node, parent, flags, matcherNode, matcherNameNode, modifierNode, notNode) {
|
|
3125
|
-
super(compiler, brand, node, parent, flags);
|
|
3126
|
-
this.isNot = notNode != null;
|
|
3127
|
-
this.matcherNode = matcherNode;
|
|
3128
|
-
this.matcherNameNode = matcherNameNode;
|
|
3129
|
-
this.modifierNode = modifierNode;
|
|
3130
|
-
this.source = this.node.typeArguments ?? this.node.arguments;
|
|
3131
|
-
if (compiler.isCallExpression(this.matcherNode)) {
|
|
3132
|
-
this.target = this.matcherNode.typeArguments ?? this.matcherNode.arguments;
|
|
3133
|
-
}
|
|
3134
|
-
for (const diagnostic of parent.diagnostics) {
|
|
3135
|
-
if (diagnosticBelongsToNode(diagnostic, this.source) ||
|
|
3136
|
-
(this.target != null && diagnosticBelongsToNode(diagnostic, this.target))) {
|
|
3137
|
-
this.diagnostics.add(diagnostic);
|
|
3138
|
-
parent.diagnostics.delete(diagnostic);
|
|
3139
|
-
}
|
|
3140
|
-
}
|
|
3141
|
-
}
|
|
3142
|
-
}
|
|
3143
|
-
|
|
3144
3191
|
function nodeBelongsToArgumentList(compiler, node) {
|
|
3145
3192
|
return compiler.isCallExpression(node.parent) && node.parent.arguments.some((argument) => argument === node);
|
|
3146
3193
|
}
|
|
@@ -3150,7 +3197,7 @@ function nodeIsChildOfExpressionStatement(compiler, node) {
|
|
|
3150
3197
|
|
|
3151
3198
|
class AbilityLayer {
|
|
3152
3199
|
#compiler;
|
|
3153
|
-
#expectErrorRegex = /^(
|
|
3200
|
+
#expectErrorRegex = /^(\s*)(\/\/ *@ts-expect-error)(!?)(:? *)(.*)?$/gim;
|
|
3154
3201
|
#filePath = "";
|
|
3155
3202
|
#nodes = [];
|
|
3156
3203
|
#projectService;
|
|
@@ -3171,16 +3218,27 @@ class AbilityLayer {
|
|
|
3171
3218
|
this.#text = `${this.#text.slice(0, range.start)}${rangeText}${this.#text.slice(range.end)}`;
|
|
3172
3219
|
}
|
|
3173
3220
|
}
|
|
3174
|
-
#belongsToNode(diagnostic) {
|
|
3221
|
+
#belongsToNode(node, diagnostic) {
|
|
3222
|
+
switch (node.brand) {
|
|
3223
|
+
case "expect":
|
|
3224
|
+
return (diagnosticBelongsToNode(diagnostic, node.matcherNode) &&
|
|
3225
|
+
!diagnosticBelongsToNode(diagnostic, node.source));
|
|
3226
|
+
case "when":
|
|
3227
|
+
return (diagnosticBelongsToNode(diagnostic, node.actionNode) &&
|
|
3228
|
+
!diagnosticBelongsToNode(diagnostic, node.target));
|
|
3229
|
+
}
|
|
3230
|
+
return false;
|
|
3231
|
+
}
|
|
3232
|
+
#mapToNodes(diagnostic) {
|
|
3175
3233
|
for (const node of this.#nodes) {
|
|
3176
|
-
if (
|
|
3234
|
+
if (this.#belongsToNode(node, diagnostic)) {
|
|
3177
3235
|
node.abilityDiagnostics.add(diagnostic);
|
|
3178
3236
|
return true;
|
|
3179
3237
|
}
|
|
3180
3238
|
}
|
|
3181
3239
|
return false;
|
|
3182
3240
|
}
|
|
3183
|
-
#
|
|
3241
|
+
#mapToDirectives(diagnostic) {
|
|
3184
3242
|
if (!isDiagnosticWithLocation(diagnostic)) {
|
|
3185
3243
|
return;
|
|
3186
3244
|
}
|
|
@@ -3225,18 +3283,19 @@ class AbilityLayer {
|
|
|
3225
3283
|
}
|
|
3226
3284
|
return ranges;
|
|
3227
3285
|
}
|
|
3228
|
-
close() {
|
|
3286
|
+
close(testTree) {
|
|
3229
3287
|
if (this.#nodes.length > 0 || this.#suppressedErrorsMap != null) {
|
|
3288
|
+
SourceService.set(testTree.sourceFile);
|
|
3230
3289
|
this.#projectService.openFile(this.#filePath, this.#text, this.#resolvedConfig.rootPath);
|
|
3231
3290
|
const languageService = this.#projectService.getLanguageService(this.#filePath);
|
|
3232
3291
|
const diagnostics = languageService?.getSemanticDiagnostics(this.#filePath);
|
|
3233
3292
|
if (diagnostics != null) {
|
|
3234
3293
|
this.#nodes.reverse();
|
|
3235
3294
|
for (const diagnostic of diagnostics) {
|
|
3236
|
-
if (this.#
|
|
3295
|
+
if (this.#mapToNodes(diagnostic)) {
|
|
3237
3296
|
continue;
|
|
3238
3297
|
}
|
|
3239
|
-
this.#
|
|
3298
|
+
this.#mapToDirectives(diagnostic);
|
|
3240
3299
|
}
|
|
3241
3300
|
}
|
|
3242
3301
|
}
|
|
@@ -3268,36 +3327,36 @@ class AbilityLayer {
|
|
|
3268
3327
|
}
|
|
3269
3328
|
return text.join("");
|
|
3270
3329
|
}
|
|
3271
|
-
|
|
3272
|
-
const expectStart =
|
|
3273
|
-
const expectExpressionEnd =
|
|
3274
|
-
const expectEnd =
|
|
3275
|
-
const matcherNameEnd =
|
|
3276
|
-
switch (
|
|
3330
|
+
handleExpect(expect) {
|
|
3331
|
+
const expectStart = expect.node.getStart();
|
|
3332
|
+
const expectExpressionEnd = expect.node.expression.getEnd();
|
|
3333
|
+
const expectEnd = expect.node.getEnd();
|
|
3334
|
+
const matcherNameEnd = expect.matcherNameNode.getEnd();
|
|
3335
|
+
switch (expect.matcherNameNode.name.text) {
|
|
3277
3336
|
case "toBeApplicable":
|
|
3278
|
-
this.#addRanges(
|
|
3337
|
+
this.#addRanges(expect, [
|
|
3279
3338
|
{ start: expectStart, end: expectExpressionEnd },
|
|
3280
3339
|
{ start: expectEnd, end: matcherNameEnd },
|
|
3281
3340
|
]);
|
|
3282
3341
|
break;
|
|
3283
3342
|
case "toBeCallableWith":
|
|
3284
|
-
this.#eraseTrailingComma(
|
|
3285
|
-
this.#addRanges(
|
|
3343
|
+
this.#eraseTrailingComma(expect.source, expect);
|
|
3344
|
+
this.#addRanges(expect, [
|
|
3286
3345
|
{
|
|
3287
3346
|
start: expectStart,
|
|
3288
3347
|
end: expectExpressionEnd,
|
|
3289
|
-
replacement: nodeIsChildOfExpressionStatement(this.#compiler,
|
|
3348
|
+
replacement: nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? ";" : "",
|
|
3290
3349
|
},
|
|
3291
3350
|
{ start: expectEnd, end: matcherNameEnd },
|
|
3292
3351
|
]);
|
|
3293
3352
|
break;
|
|
3294
3353
|
case "toBeConstructableWith":
|
|
3295
|
-
this.#eraseTrailingComma(
|
|
3296
|
-
this.#addRanges(
|
|
3354
|
+
this.#eraseTrailingComma(expect.source, expect);
|
|
3355
|
+
this.#addRanges(expect, [
|
|
3297
3356
|
{
|
|
3298
3357
|
start: expectStart,
|
|
3299
3358
|
end: expectExpressionEnd,
|
|
3300
|
-
replacement: nodeIsChildOfExpressionStatement(this.#compiler,
|
|
3359
|
+
replacement: nodeIsChildOfExpressionStatement(this.#compiler, expect.matcherNode) ? "; new" : "new",
|
|
3301
3360
|
},
|
|
3302
3361
|
{ start: expectEnd, end: matcherNameEnd },
|
|
3303
3362
|
]);
|
|
@@ -3307,7 +3366,7 @@ class AbilityLayer {
|
|
|
3307
3366
|
#handleSuppressedErrors(testTree) {
|
|
3308
3367
|
const suppressedErrors = this.#collectSuppressedErrors();
|
|
3309
3368
|
if (this.#resolvedConfig.checkSuppressedErrors) {
|
|
3310
|
-
testTree.suppressedErrors =
|
|
3369
|
+
testTree.suppressedErrors = suppressedErrors;
|
|
3311
3370
|
this.#suppressedErrorsMap = new Map();
|
|
3312
3371
|
}
|
|
3313
3372
|
for (const suppressedError of suppressedErrors) {
|
|
@@ -3352,22 +3411,61 @@ class CollectDiagnosticText {
|
|
|
3352
3411
|
}
|
|
3353
3412
|
}
|
|
3354
3413
|
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3414
|
+
class TestTreeNode {
|
|
3415
|
+
brand;
|
|
3416
|
+
children = [];
|
|
3417
|
+
diagnostics = new Set();
|
|
3418
|
+
flags;
|
|
3419
|
+
name = "";
|
|
3420
|
+
node;
|
|
3421
|
+
parent;
|
|
3422
|
+
constructor(compiler, brand, node, parent, flags) {
|
|
3423
|
+
this.brand = brand;
|
|
3424
|
+
this.node = node;
|
|
3425
|
+
this.parent = parent;
|
|
3426
|
+
this.flags = flags;
|
|
3427
|
+
if (node.arguments[0] != null && compiler.isStringLiteralLike(node.arguments[0])) {
|
|
3428
|
+
this.name = node.arguments[0].text;
|
|
3429
|
+
}
|
|
3430
|
+
if (node.arguments[1] != null && compiler.isFunctionLike(node.arguments[1])) {
|
|
3431
|
+
for (const diagnostic of parent.diagnostics) {
|
|
3432
|
+
if (diagnosticBelongsToNode(diagnostic, node.arguments[1].body)) {
|
|
3433
|
+
this.diagnostics.add(diagnostic);
|
|
3434
|
+
parent.diagnostics.delete(diagnostic);
|
|
3435
|
+
}
|
|
3436
|
+
}
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3362
3440
|
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3441
|
+
class ExpectNode extends TestTreeNode {
|
|
3442
|
+
abilityDiagnostics = new Set();
|
|
3443
|
+
isNot;
|
|
3444
|
+
matcherNode;
|
|
3445
|
+
matcherNameNode;
|
|
3446
|
+
modifierNode;
|
|
3447
|
+
notNode;
|
|
3448
|
+
source;
|
|
3449
|
+
target;
|
|
3450
|
+
constructor(compiler, brand, node, parent, flags, matcherNode, matcherNameNode, modifierNode, notNode) {
|
|
3451
|
+
super(compiler, brand, node, parent, flags);
|
|
3452
|
+
this.isNot = notNode != null;
|
|
3453
|
+
this.matcherNode = matcherNode;
|
|
3454
|
+
this.matcherNameNode = matcherNameNode;
|
|
3455
|
+
this.modifierNode = modifierNode;
|
|
3456
|
+
this.source = this.node.typeArguments ?? this.node.arguments;
|
|
3457
|
+
if (compiler.isCallExpression(this.matcherNode)) {
|
|
3458
|
+
this.target = this.matcherNode.typeArguments ?? this.matcherNode.arguments;
|
|
3459
|
+
}
|
|
3460
|
+
for (const diagnostic of parent.diagnostics) {
|
|
3461
|
+
if (diagnosticBelongsToNode(diagnostic, this.source) ||
|
|
3462
|
+
(this.target != null && diagnosticBelongsToNode(diagnostic, this.target))) {
|
|
3463
|
+
this.diagnostics.add(diagnostic);
|
|
3464
|
+
parent.diagnostics.delete(diagnostic);
|
|
3465
|
+
}
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
}
|
|
3371
3469
|
|
|
3372
3470
|
class IdentifierLookup {
|
|
3373
3471
|
#compiler;
|
|
@@ -3416,24 +3514,21 @@ class IdentifierLookup {
|
|
|
3416
3514
|
};
|
|
3417
3515
|
}
|
|
3418
3516
|
resolveTestTreeNodeMeta(node) {
|
|
3419
|
-
let flags =
|
|
3517
|
+
let flags = 0;
|
|
3420
3518
|
let expression = node.expression;
|
|
3421
3519
|
while (this.#compiler.isPropertyAccessExpression(expression)) {
|
|
3422
3520
|
if (expression.expression.getText() === this.#identifiers.namespace) {
|
|
3423
3521
|
break;
|
|
3424
3522
|
}
|
|
3425
3523
|
switch (expression.name.getText()) {
|
|
3426
|
-
case "fail":
|
|
3427
|
-
flags |= TestTreeNodeFlags.Fail;
|
|
3428
|
-
break;
|
|
3429
3524
|
case "only":
|
|
3430
|
-
flags |=
|
|
3525
|
+
flags |= 1;
|
|
3431
3526
|
break;
|
|
3432
3527
|
case "skip":
|
|
3433
|
-
flags |=
|
|
3528
|
+
flags |= 2;
|
|
3434
3529
|
break;
|
|
3435
3530
|
case "todo":
|
|
3436
|
-
flags |=
|
|
3531
|
+
flags |= 4;
|
|
3437
3532
|
break;
|
|
3438
3533
|
}
|
|
3439
3534
|
expression = expression.expression;
|
|
@@ -3451,14 +3546,14 @@ class IdentifierLookup {
|
|
|
3451
3546
|
}
|
|
3452
3547
|
switch (identifier) {
|
|
3453
3548
|
case "describe":
|
|
3454
|
-
return { brand:
|
|
3549
|
+
return { brand: "describe", flags, identifier };
|
|
3455
3550
|
case "it":
|
|
3456
3551
|
case "test":
|
|
3457
|
-
return { brand:
|
|
3552
|
+
return { brand: "test", flags, identifier };
|
|
3458
3553
|
case "expect":
|
|
3459
|
-
return { brand:
|
|
3554
|
+
return { brand: "expect", flags, identifier };
|
|
3460
3555
|
case "when":
|
|
3461
|
-
return { brand:
|
|
3556
|
+
return { brand: "when", flags, identifier };
|
|
3462
3557
|
}
|
|
3463
3558
|
return;
|
|
3464
3559
|
}
|
|
@@ -3474,9 +3569,6 @@ class TestTree {
|
|
|
3474
3569
|
this.diagnostics = diagnostics;
|
|
3475
3570
|
this.sourceFile = sourceFile;
|
|
3476
3571
|
}
|
|
3477
|
-
getDirectiveRanges(compiler) {
|
|
3478
|
-
return Directive.getDirectiveRanges(compiler, this.sourceFile);
|
|
3479
|
-
}
|
|
3480
3572
|
}
|
|
3481
3573
|
|
|
3482
3574
|
class WhenNode extends TestTreeNode {
|
|
@@ -3514,7 +3606,7 @@ class CollectService {
|
|
|
3514
3606
|
if (!this.#checkNode(node, meta, parent)) {
|
|
3515
3607
|
return;
|
|
3516
3608
|
}
|
|
3517
|
-
if (meta.brand ===
|
|
3609
|
+
if (meta.brand === "describe" || meta.brand === "test") {
|
|
3518
3610
|
const testTreeNode = new TestTreeNode(this.#compiler, meta.brand, node, parent, meta.flags);
|
|
3519
3611
|
this.#compiler.forEachChild(node, (node) => {
|
|
3520
3612
|
this.#collectTestTreeNodes(node, testTreeNode, testTree);
|
|
@@ -3522,7 +3614,7 @@ class CollectService {
|
|
|
3522
3614
|
this.#onNode(testTreeNode, parent, testTree);
|
|
3523
3615
|
return;
|
|
3524
3616
|
}
|
|
3525
|
-
if (meta.brand ===
|
|
3617
|
+
if (meta.brand === "expect") {
|
|
3526
3618
|
const modifierNode = this.#getChainedNode(node, "type");
|
|
3527
3619
|
if (!modifierNode) {
|
|
3528
3620
|
return;
|
|
@@ -3536,15 +3628,15 @@ class CollectService {
|
|
|
3536
3628
|
if (!matcherNode) {
|
|
3537
3629
|
return;
|
|
3538
3630
|
}
|
|
3539
|
-
const
|
|
3540
|
-
this.#abilityLayer.
|
|
3631
|
+
const expectNode = new ExpectNode(this.#compiler, meta.brand, node, parent, meta.flags, matcherNode, matcherNameNode, modifierNode, notNode);
|
|
3632
|
+
this.#abilityLayer.handleExpect(expectNode);
|
|
3541
3633
|
this.#compiler.forEachChild(node, (node) => {
|
|
3542
|
-
this.#collectTestTreeNodes(node,
|
|
3634
|
+
this.#collectTestTreeNodes(node, expectNode, testTree);
|
|
3543
3635
|
});
|
|
3544
|
-
this.#onNode(
|
|
3636
|
+
this.#onNode(expectNode, parent, testTree);
|
|
3545
3637
|
return;
|
|
3546
3638
|
}
|
|
3547
|
-
if (meta.brand ===
|
|
3639
|
+
if (meta.brand === "when") {
|
|
3548
3640
|
const actionNameNode = this.#getChainedNode(node);
|
|
3549
3641
|
if (!actionNameNode) {
|
|
3550
3642
|
return;
|
|
@@ -3556,7 +3648,7 @@ class CollectService {
|
|
|
3556
3648
|
this.#compiler.forEachChild(actionNode, (node) => {
|
|
3557
3649
|
if (this.#compiler.isCallExpression(node)) {
|
|
3558
3650
|
const meta = this.#identifierLookup.resolveTestTreeNodeMeta(node);
|
|
3559
|
-
if (meta?.brand ===
|
|
3651
|
+
if (meta?.brand === "describe" || meta?.brand === "test") {
|
|
3560
3652
|
const text = CollectDiagnosticText.cannotBeNestedWithin(meta.identifier, "when");
|
|
3561
3653
|
const origin = DiagnosticOrigin.fromNode(node);
|
|
3562
3654
|
this.#onDiagnostics(Diagnostic.error(text, origin));
|
|
@@ -3584,7 +3676,7 @@ class CollectService {
|
|
|
3584
3676
|
this.#abilityLayer.open(testTree);
|
|
3585
3677
|
this.#identifierLookup.open();
|
|
3586
3678
|
this.#collectTestTreeNodes(sourceFile, testTree, testTree);
|
|
3587
|
-
this.#abilityLayer.close();
|
|
3679
|
+
this.#abilityLayer.close(testTree);
|
|
3588
3680
|
EventEmitter.dispatch(["collect:end", { tree: testTree }]);
|
|
3589
3681
|
return testTree;
|
|
3590
3682
|
}
|
|
@@ -3599,15 +3691,15 @@ class CollectService {
|
|
|
3599
3691
|
}
|
|
3600
3692
|
#isNodeAllowed(meta, parent) {
|
|
3601
3693
|
switch (meta.brand) {
|
|
3602
|
-
case
|
|
3603
|
-
case
|
|
3604
|
-
if (parent.brand ===
|
|
3694
|
+
case "describe":
|
|
3695
|
+
case "test":
|
|
3696
|
+
if (parent.brand === "test" || parent.brand === "expect") {
|
|
3605
3697
|
return false;
|
|
3606
3698
|
}
|
|
3607
3699
|
break;
|
|
3608
|
-
case
|
|
3609
|
-
case
|
|
3610
|
-
if (parent.brand ===
|
|
3700
|
+
case "expect":
|
|
3701
|
+
case "when":
|
|
3702
|
+
if (parent.brand === "describe") {
|
|
3611
3703
|
return false;
|
|
3612
3704
|
}
|
|
3613
3705
|
break;
|
|
@@ -3646,13 +3738,29 @@ class CollectService {
|
|
|
3646
3738
|
}
|
|
3647
3739
|
#onNode(node, parent, testTree) {
|
|
3648
3740
|
parent.children.push(node);
|
|
3649
|
-
if (node.flags &
|
|
3741
|
+
if (node.flags & 1) {
|
|
3650
3742
|
testTree.hasOnly = true;
|
|
3651
3743
|
}
|
|
3652
3744
|
EventEmitter.dispatch(["collect:node", { node }]);
|
|
3653
3745
|
}
|
|
3654
3746
|
}
|
|
3655
3747
|
|
|
3748
|
+
var TestTreeNodeBrand;
|
|
3749
|
+
(function (TestTreeNodeBrand) {
|
|
3750
|
+
TestTreeNodeBrand["Describe"] = "describe";
|
|
3751
|
+
TestTreeNodeBrand["Test"] = "test";
|
|
3752
|
+
TestTreeNodeBrand["Expect"] = "expect";
|
|
3753
|
+
TestTreeNodeBrand["When"] = "when";
|
|
3754
|
+
})(TestTreeNodeBrand || (TestTreeNodeBrand = {}));
|
|
3755
|
+
|
|
3756
|
+
var TestTreeNodeFlags;
|
|
3757
|
+
(function (TestTreeNodeFlags) {
|
|
3758
|
+
TestTreeNodeFlags[TestTreeNodeFlags["None"] = 0] = "None";
|
|
3759
|
+
TestTreeNodeFlags[TestTreeNodeFlags["Only"] = 1] = "Only";
|
|
3760
|
+
TestTreeNodeFlags[TestTreeNodeFlags["Skip"] = 2] = "Skip";
|
|
3761
|
+
TestTreeNodeFlags[TestTreeNodeFlags["Todo"] = 4] = "Todo";
|
|
3762
|
+
})(TestTreeNodeFlags || (TestTreeNodeFlags = {}));
|
|
3763
|
+
|
|
3656
3764
|
class ProjectService {
|
|
3657
3765
|
#compiler;
|
|
3658
3766
|
#lastSeenProject = "";
|
|
@@ -3703,8 +3811,6 @@ class ProjectService {
|
|
|
3703
3811
|
}
|
|
3704
3812
|
#getDefaultCompilerOptions() {
|
|
3705
3813
|
const defaultCompilerOptions = {
|
|
3706
|
-
allowJs: true,
|
|
3707
|
-
checkJs: true,
|
|
3708
3814
|
exactOptionalPropertyTypes: true,
|
|
3709
3815
|
jsx: this.#compiler.JsxEmit.Preserve,
|
|
3710
3816
|
module: this.#compiler.ModuleKind.NodeNext,
|
|
@@ -3726,7 +3832,7 @@ class ProjectService {
|
|
|
3726
3832
|
getDefaultProject(filePath) {
|
|
3727
3833
|
const project = this.#service.getDefaultProjectForFile(this.#compiler.server.toNormalizedPath(filePath), true);
|
|
3728
3834
|
const compilerOptions = project?.getCompilerOptions();
|
|
3729
|
-
if (this.#resolvedConfig.
|
|
3835
|
+
if (this.#resolvedConfig.checkDeclarationFiles && compilerOptions?.skipLibCheck) {
|
|
3730
3836
|
project?.setCompilerOptions({ ...compilerOptions, skipLibCheck: false });
|
|
3731
3837
|
}
|
|
3732
3838
|
return project;
|
|
@@ -3759,12 +3865,12 @@ class ProjectService {
|
|
|
3759
3865
|
"project:uses",
|
|
3760
3866
|
{ compilerVersion: this.#compiler.version, projectConfigFilePath: configFileName },
|
|
3761
3867
|
]);
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3868
|
+
if (configFileErrors && configFileErrors.length > 0) {
|
|
3869
|
+
EventEmitter.dispatch([
|
|
3870
|
+
"project:error",
|
|
3871
|
+
{ diagnostics: Diagnostic.fromDiagnostics(configFileErrors) },
|
|
3872
|
+
]);
|
|
3873
|
+
}
|
|
3768
3874
|
}
|
|
3769
3875
|
if (!this.#seenTestFiles.has(filePath)) {
|
|
3770
3876
|
this.#seenTestFiles.add(filePath);
|
|
@@ -3778,13 +3884,16 @@ class ProjectService {
|
|
|
3778
3884
|
if (program.isSourceFileFromExternalLibrary(sourceFile) || program.isSourceFileDefaultLibrary(sourceFile)) {
|
|
3779
3885
|
return false;
|
|
3780
3886
|
}
|
|
3887
|
+
if (this.#resolvedConfig.checkDeclarationFiles && sourceFile.isDeclarationFile) {
|
|
3888
|
+
return true;
|
|
3889
|
+
}
|
|
3781
3890
|
if (Select.isFixtureFile(sourceFile.fileName, { ...this.#resolvedConfig, pathMatch: [] })) {
|
|
3782
3891
|
return true;
|
|
3783
3892
|
}
|
|
3784
3893
|
if (Select.isTestFile(sourceFile.fileName, { ...this.#resolvedConfig, pathMatch: [] })) {
|
|
3785
3894
|
return false;
|
|
3786
3895
|
}
|
|
3787
|
-
return
|
|
3896
|
+
return false;
|
|
3788
3897
|
});
|
|
3789
3898
|
const diagnostics = [];
|
|
3790
3899
|
for (const sourceFile of sourceFilesToCheck) {
|
|
@@ -3817,24 +3926,26 @@ class SuppressedDiagnosticText {
|
|
|
3817
3926
|
}
|
|
3818
3927
|
|
|
3819
3928
|
class SuppressedService {
|
|
3820
|
-
match(
|
|
3821
|
-
|
|
3929
|
+
match(testTree, onDiagnostics) {
|
|
3930
|
+
if (!testTree.suppressedErrors) {
|
|
3931
|
+
return;
|
|
3932
|
+
}
|
|
3933
|
+
for (const suppressedError of testTree.suppressedErrors) {
|
|
3822
3934
|
if (suppressedError.diagnostics.length === 0 || suppressedError.ignore) {
|
|
3823
3935
|
continue;
|
|
3824
3936
|
}
|
|
3937
|
+
const related = [
|
|
3938
|
+
Diagnostic.error(SuppressedDiagnosticText.suppressedError(suppressedError.diagnostics.length)),
|
|
3939
|
+
...Diagnostic.fromDiagnostics(suppressedError.diagnostics),
|
|
3940
|
+
];
|
|
3941
|
+
const origin = new DiagnosticOrigin(suppressedError.directive.start, suppressedError.directive.end, testTree.sourceFile);
|
|
3825
3942
|
if (!suppressedError.argument?.text) {
|
|
3826
3943
|
const text = SuppressedDiagnosticText.directiveRequires();
|
|
3827
|
-
|
|
3828
|
-
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
3944
|
+
onDiagnostics([Diagnostic.error(text, origin).add({ related })]);
|
|
3829
3945
|
continue;
|
|
3830
3946
|
}
|
|
3831
|
-
const related = [
|
|
3832
|
-
Diagnostic.error(SuppressedDiagnosticText.suppressedError(suppressedError.diagnostics.length)),
|
|
3833
|
-
...Diagnostic.fromDiagnostics(suppressedError.diagnostics, suppressedErrors.sourceFile),
|
|
3834
|
-
];
|
|
3835
3947
|
if (suppressedError.diagnostics.length > 1) {
|
|
3836
3948
|
const text = [SuppressedDiagnosticText.onlySingleError()];
|
|
3837
|
-
const origin = new DiagnosticOrigin(suppressedError.directive.start, suppressedError.directive.end, suppressedErrors.sourceFile);
|
|
3838
3949
|
onDiagnostics([Diagnostic.error(text, origin).add({ related })]);
|
|
3839
3950
|
continue;
|
|
3840
3951
|
}
|
|
@@ -3842,25 +3953,28 @@ class SuppressedService {
|
|
|
3842
3953
|
if (Array.isArray(messageText)) {
|
|
3843
3954
|
messageText = messageText.join("\n");
|
|
3844
3955
|
}
|
|
3845
|
-
if (!messageText
|
|
3956
|
+
if (!this.#matchMessage(messageText, suppressedError.argument.text)) {
|
|
3846
3957
|
const text = [SuppressedDiagnosticText.messageDidNotMatch()];
|
|
3847
|
-
const origin = new DiagnosticOrigin(suppressedError.argument.start, suppressedError.argument.end,
|
|
3958
|
+
const origin = new DiagnosticOrigin(suppressedError.argument.start, suppressedError.argument.end, testTree.sourceFile);
|
|
3848
3959
|
onDiagnostics([Diagnostic.error(text, origin).add({ related })]);
|
|
3849
3960
|
}
|
|
3850
3961
|
}
|
|
3851
3962
|
}
|
|
3963
|
+
#matchMessage(source, target) {
|
|
3964
|
+
if (target.includes("...")) {
|
|
3965
|
+
let position = 0;
|
|
3966
|
+
for (const segment of target.split("...")) {
|
|
3967
|
+
position = source.indexOf(segment, position);
|
|
3968
|
+
if (position === -1) {
|
|
3969
|
+
break;
|
|
3970
|
+
}
|
|
3971
|
+
}
|
|
3972
|
+
return position > 0;
|
|
3973
|
+
}
|
|
3974
|
+
return source.includes(target);
|
|
3975
|
+
}
|
|
3852
3976
|
}
|
|
3853
3977
|
|
|
3854
|
-
var RunMode;
|
|
3855
|
-
(function (RunMode) {
|
|
3856
|
-
RunMode[RunMode["Normal"] = 0] = "Normal";
|
|
3857
|
-
RunMode[RunMode["Fail"] = 1] = "Fail";
|
|
3858
|
-
RunMode[RunMode["Only"] = 2] = "Only";
|
|
3859
|
-
RunMode[RunMode["Skip"] = 4] = "Skip";
|
|
3860
|
-
RunMode[RunMode["Todo"] = 8] = "Todo";
|
|
3861
|
-
RunMode[RunMode["Void"] = 16] = "Void";
|
|
3862
|
-
})(RunMode || (RunMode = {}));
|
|
3863
|
-
|
|
3864
3978
|
class EnsureDiagnosticText {
|
|
3865
3979
|
static argumentMustBeProvided(argumentNameText) {
|
|
3866
3980
|
return `An argument for '${argumentNameText}' must be provided.`;
|
|
@@ -3984,21 +4098,15 @@ class ExpectDiagnosticText {
|
|
|
3984
4098
|
}
|
|
3985
4099
|
}
|
|
3986
4100
|
|
|
3987
|
-
var Relation;
|
|
3988
|
-
(function (Relation) {
|
|
3989
|
-
Relation["Assignable"] = "assignable";
|
|
3990
|
-
Relation["Identical"] = "identical";
|
|
3991
|
-
})(Relation || (Relation = {}));
|
|
3992
|
-
|
|
3993
4101
|
class MatchWorker {
|
|
3994
|
-
|
|
4102
|
+
assertionNode;
|
|
3995
4103
|
#compiler;
|
|
3996
4104
|
#signatureCache = new Map();
|
|
3997
4105
|
typeChecker;
|
|
3998
|
-
constructor(compiler, typeChecker,
|
|
4106
|
+
constructor(compiler, typeChecker, assertionNode) {
|
|
3999
4107
|
this.#compiler = compiler;
|
|
4000
4108
|
this.typeChecker = typeChecker;
|
|
4001
|
-
this.
|
|
4109
|
+
this.assertionNode = assertionNode;
|
|
4002
4110
|
}
|
|
4003
4111
|
checkHasApplicableIndexType(sourceNode, targetNode) {
|
|
4004
4112
|
const sourceType = this.getType(sourceNode);
|
|
@@ -4014,13 +4122,13 @@ class MatchWorker {
|
|
|
4014
4122
|
.some((property) => this.#compiler.unescapeLeadingUnderscores(property.escapedName) === propertyNameText);
|
|
4015
4123
|
}
|
|
4016
4124
|
checkIsAssignableTo(sourceNode, targetNode) {
|
|
4017
|
-
return this.#checkIsRelatedTo(sourceNode, targetNode,
|
|
4125
|
+
return this.#checkIsRelatedTo(sourceNode, targetNode, "assignable");
|
|
4018
4126
|
}
|
|
4019
4127
|
checkIsAssignableWith(sourceNode, targetNode) {
|
|
4020
|
-
return this.#checkIsRelatedTo(targetNode, sourceNode,
|
|
4128
|
+
return this.#checkIsRelatedTo(targetNode, sourceNode, "assignable");
|
|
4021
4129
|
}
|
|
4022
4130
|
checkIsIdenticalTo(sourceNode, targetNode) {
|
|
4023
|
-
return (this.#checkIsRelatedTo(sourceNode, targetNode,
|
|
4131
|
+
return (this.#checkIsRelatedTo(sourceNode, targetNode, "identical") &&
|
|
4024
4132
|
this.checkIsAssignableTo(sourceNode, targetNode) &&
|
|
4025
4133
|
this.checkIsAssignableWith(sourceNode, targetNode));
|
|
4026
4134
|
}
|
|
@@ -4028,9 +4136,9 @@ class MatchWorker {
|
|
|
4028
4136
|
const sourceType = relation === "identical" ? this.#simplifyType(this.getType(sourceNode)) : this.getType(sourceNode);
|
|
4029
4137
|
const targetType = relation === "identical" ? this.#simplifyType(this.getType(targetNode)) : this.getType(targetNode);
|
|
4030
4138
|
switch (relation) {
|
|
4031
|
-
case
|
|
4139
|
+
case "assignable":
|
|
4032
4140
|
return this.typeChecker.isTypeAssignableTo(sourceType, targetType);
|
|
4033
|
-
case
|
|
4141
|
+
case "identical":
|
|
4034
4142
|
return this.typeChecker.isTypeIdenticalTo(sourceType, targetType);
|
|
4035
4143
|
}
|
|
4036
4144
|
}
|
|
@@ -4071,9 +4179,9 @@ class MatchWorker {
|
|
|
4071
4179
|
this.#compiler.isShorthandPropertyAssignment(symbol.valueDeclaration)) &&
|
|
4072
4180
|
symbol.valueDeclaration.getStart() >= enclosingNode.getStart() &&
|
|
4073
4181
|
symbol.valueDeclaration.getEnd() <= enclosingNode.getEnd()) {
|
|
4074
|
-
return DiagnosticOrigin.fromNode(symbol.valueDeclaration.name, this.
|
|
4182
|
+
return DiagnosticOrigin.fromNode(symbol.valueDeclaration.name, this.assertionNode);
|
|
4075
4183
|
}
|
|
4076
|
-
return DiagnosticOrigin.fromNode(enclosingNode, this.
|
|
4184
|
+
return DiagnosticOrigin.fromNode(enclosingNode, this.assertionNode);
|
|
4077
4185
|
}
|
|
4078
4186
|
#simplifyType(type) {
|
|
4079
4187
|
if (type.isUnionOrIntersection()) {
|
|
@@ -4108,10 +4216,10 @@ class ToAcceptProps {
|
|
|
4108
4216
|
const signatures = matchWorker.getSignatures(sourceNode);
|
|
4109
4217
|
return signatures.reduce((accumulator, signature, index) => {
|
|
4110
4218
|
let diagnostic;
|
|
4111
|
-
const introText = matchWorker.
|
|
4219
|
+
const introText = matchWorker.assertionNode.isNot
|
|
4112
4220
|
? ExpectDiagnosticText.acceptsProps(isExpression)
|
|
4113
4221
|
: ExpectDiagnosticText.doesNotAcceptProps(isExpression);
|
|
4114
|
-
const origin = DiagnosticOrigin.fromNode(targetNode, matchWorker.
|
|
4222
|
+
const origin = DiagnosticOrigin.fromNode(targetNode, matchWorker.assertionNode);
|
|
4115
4223
|
if (signatures.length > 1) {
|
|
4116
4224
|
const signatureText = this.#typeChecker.signatureToString(signature, sourceNode);
|
|
4117
4225
|
const overloadText = ExpectDiagnosticText.overloadGaveTheFollowingError(index + 1, signatures.length, signatureText);
|
|
@@ -4121,7 +4229,7 @@ class ToAcceptProps {
|
|
|
4121
4229
|
diagnostic = Diagnostic.error([introText], origin);
|
|
4122
4230
|
}
|
|
4123
4231
|
const { diagnostics, isMatch } = this.#explainProperties(matchWorker, signature, targetNode, diagnostic);
|
|
4124
|
-
if (matchWorker.
|
|
4232
|
+
if (matchWorker.assertionNode.isNot ? isMatch : !isMatch) {
|
|
4125
4233
|
accumulator.push(...diagnostics);
|
|
4126
4234
|
}
|
|
4127
4235
|
return accumulator;
|
|
@@ -4229,7 +4337,7 @@ class ToAcceptProps {
|
|
|
4229
4337
|
if (sourceType != null && isUnionType(this.#compiler, sourceType)) {
|
|
4230
4338
|
let accumulator = [];
|
|
4231
4339
|
const isMatch = sourceType.types.some((sourceType) => {
|
|
4232
|
-
const text = matchWorker.
|
|
4340
|
+
const text = matchWorker.assertionNode.isNot
|
|
4233
4341
|
? ExpectDiagnosticText.isAssignableWith(sourceTypeText, targetTypeText)
|
|
4234
4342
|
: ExpectDiagnosticText.isNotAssignableWith(sourceTypeText, targetTypeText);
|
|
4235
4343
|
const { diagnostics, isMatch } = explain(sourceType, targetType, diagnostic.extendWith(text));
|
|
@@ -4284,10 +4392,10 @@ class RelationMatcherBase {
|
|
|
4284
4392
|
explain(matchWorker, sourceNode, targetNode) {
|
|
4285
4393
|
const sourceTypeText = matchWorker.getTypeText(sourceNode);
|
|
4286
4394
|
const targetTypeText = matchWorker.getTypeText(targetNode);
|
|
4287
|
-
const text = matchWorker.
|
|
4395
|
+
const text = matchWorker.assertionNode.isNot
|
|
4288
4396
|
? this.explainText(sourceTypeText, targetTypeText)
|
|
4289
4397
|
: this.explainNotText(sourceTypeText, targetTypeText);
|
|
4290
|
-
const origin = DiagnosticOrigin.fromNode(targetNode, matchWorker.
|
|
4398
|
+
const origin = DiagnosticOrigin.fromNode(targetNode, matchWorker.assertionNode);
|
|
4291
4399
|
return [Diagnostic.error(text, origin)];
|
|
4292
4400
|
}
|
|
4293
4401
|
}
|
|
@@ -4334,18 +4442,22 @@ class ToBeApplicable {
|
|
|
4334
4442
|
}
|
|
4335
4443
|
return text;
|
|
4336
4444
|
}
|
|
4337
|
-
#explain(matchWorker
|
|
4338
|
-
const targetText = this.#resolveTargetText(matchWorker.
|
|
4445
|
+
#explain(matchWorker) {
|
|
4446
|
+
const targetText = this.#resolveTargetText(matchWorker.assertionNode.matcherNode.parent);
|
|
4339
4447
|
const diagnostics = [];
|
|
4340
|
-
if (matchWorker.
|
|
4341
|
-
|
|
4448
|
+
if (matchWorker.assertionNode.abilityDiagnostics.size > 0) {
|
|
4449
|
+
const origin = DiagnosticOrigin.fromAssertion(matchWorker.assertionNode);
|
|
4450
|
+
for (const diagnostic of matchWorker.assertionNode.abilityDiagnostics) {
|
|
4342
4451
|
const text = [ExpectDiagnosticText.cannotBeApplied(targetText), getDiagnosticMessageText(diagnostic)];
|
|
4343
|
-
|
|
4344
|
-
|
|
4452
|
+
let related;
|
|
4453
|
+
if (diagnostic.relatedInformation != null) {
|
|
4454
|
+
related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
|
|
4455
|
+
}
|
|
4456
|
+
diagnostics.push(Diagnostic.error(text.flat(), origin).add({ related }));
|
|
4345
4457
|
}
|
|
4346
4458
|
}
|
|
4347
4459
|
else {
|
|
4348
|
-
const origin = DiagnosticOrigin.fromAssertion(matchWorker.
|
|
4460
|
+
const origin = DiagnosticOrigin.fromAssertion(matchWorker.assertionNode);
|
|
4349
4461
|
diagnostics.push(Diagnostic.error(ExpectDiagnosticText.canBeApplied(targetText), origin));
|
|
4350
4462
|
}
|
|
4351
4463
|
return diagnostics;
|
|
@@ -4362,8 +4474,8 @@ class ToBeApplicable {
|
|
|
4362
4474
|
return;
|
|
4363
4475
|
}
|
|
4364
4476
|
return {
|
|
4365
|
-
explain: () => this.#explain(matchWorker
|
|
4366
|
-
isMatch: matchWorker.
|
|
4477
|
+
explain: () => this.#explain(matchWorker),
|
|
4478
|
+
isMatch: matchWorker.assertionNode.abilityDiagnostics.size === 0,
|
|
4367
4479
|
};
|
|
4368
4480
|
}
|
|
4369
4481
|
}
|
|
@@ -4408,32 +4520,25 @@ class AbilityMatcherBase {
|
|
|
4408
4520
|
const isExpression = nodeBelongsToArgumentList(this.compiler, sourceNode);
|
|
4409
4521
|
const targetText = this.#resolveTargetText(targetNodes);
|
|
4410
4522
|
const diagnostics = [];
|
|
4411
|
-
if (matchWorker.
|
|
4412
|
-
for (const diagnostic of matchWorker.
|
|
4523
|
+
if (matchWorker.assertionNode.abilityDiagnostics.size > 0) {
|
|
4524
|
+
for (const diagnostic of matchWorker.assertionNode.abilityDiagnostics) {
|
|
4525
|
+
const text = [this.explainNotText(isExpression, targetText), getDiagnosticMessageText(diagnostic)];
|
|
4413
4526
|
let origin;
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), sourceNode.getSourceFile(), matchWorker.assertion);
|
|
4417
|
-
text.push(getDiagnosticMessageText(diagnostic));
|
|
4527
|
+
if (isDiagnosticWithLocation(diagnostic) && diagnosticBelongsToNode(diagnostic, targetNodes)) {
|
|
4528
|
+
origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), sourceNode.getSourceFile(), matchWorker.assertionNode);
|
|
4418
4529
|
}
|
|
4419
4530
|
else {
|
|
4420
|
-
|
|
4421
|
-
origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), sourceNode.getSourceFile(), matchWorker.assertion);
|
|
4422
|
-
}
|
|
4423
|
-
else {
|
|
4424
|
-
origin = DiagnosticOrigin.fromAssertion(matchWorker.assertion);
|
|
4425
|
-
}
|
|
4426
|
-
text.push(this.explainNotText(isExpression, targetText), getDiagnosticMessageText(diagnostic));
|
|
4531
|
+
origin = DiagnosticOrigin.fromAssertion(matchWorker.assertionNode);
|
|
4427
4532
|
}
|
|
4428
4533
|
let related;
|
|
4429
4534
|
if (diagnostic.relatedInformation != null) {
|
|
4430
|
-
related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation
|
|
4535
|
+
related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
|
|
4431
4536
|
}
|
|
4432
4537
|
diagnostics.push(Diagnostic.error(text.flat(), origin).add({ related }));
|
|
4433
4538
|
}
|
|
4434
4539
|
}
|
|
4435
4540
|
else {
|
|
4436
|
-
const origin = DiagnosticOrigin.fromAssertion(matchWorker.
|
|
4541
|
+
const origin = DiagnosticOrigin.fromAssertion(matchWorker.assertionNode);
|
|
4437
4542
|
diagnostics.push(Diagnostic.error(this.explainText(isExpression, targetText), origin));
|
|
4438
4543
|
}
|
|
4439
4544
|
return diagnostics;
|
|
@@ -4473,7 +4578,7 @@ class ToBeCallableWith extends AbilityMatcherBase {
|
|
|
4473
4578
|
}
|
|
4474
4579
|
return {
|
|
4475
4580
|
explain: () => this.explain(matchWorker, sourceNode, targetNodes),
|
|
4476
|
-
isMatch: matchWorker.
|
|
4581
|
+
isMatch: matchWorker.assertionNode.abilityDiagnostics.size === 0,
|
|
4477
4582
|
};
|
|
4478
4583
|
}
|
|
4479
4584
|
}
|
|
@@ -4508,7 +4613,7 @@ class ToBeConstructableWith extends AbilityMatcherBase {
|
|
|
4508
4613
|
}
|
|
4509
4614
|
return {
|
|
4510
4615
|
explain: () => this.explain(matchWorker, sourceNode, targetNodes),
|
|
4511
|
-
isMatch: matchWorker.
|
|
4616
|
+
isMatch: matchWorker.assertionNode.abilityDiagnostics.size === 0,
|
|
4512
4617
|
};
|
|
4513
4618
|
}
|
|
4514
4619
|
}
|
|
@@ -4528,8 +4633,8 @@ class ToHaveProperty {
|
|
|
4528
4633
|
else {
|
|
4529
4634
|
propertyNameText = `[${this.#compiler.unescapeLeadingUnderscores(targetType.symbol.escapedName)}]`;
|
|
4530
4635
|
}
|
|
4531
|
-
const origin = DiagnosticOrigin.fromNode(targetNode, matchWorker.
|
|
4532
|
-
return matchWorker.
|
|
4636
|
+
const origin = DiagnosticOrigin.fromNode(targetNode, matchWorker.assertionNode);
|
|
4637
|
+
return matchWorker.assertionNode.isNot
|
|
4533
4638
|
? [Diagnostic.error(ExpectDiagnosticText.hasProperty(sourceTypeText, propertyNameText), origin)]
|
|
4534
4639
|
: [Diagnostic.error(ExpectDiagnosticText.doesNotHaveProperty(sourceTypeText, propertyNameText), origin)];
|
|
4535
4640
|
}
|
|
@@ -4579,28 +4684,28 @@ class ToRaiseError {
|
|
|
4579
4684
|
}
|
|
4580
4685
|
#explain(matchWorker, sourceNode, targetNodes) {
|
|
4581
4686
|
const isExpression = nodeBelongsToArgumentList(this.#compiler, sourceNode);
|
|
4582
|
-
const origin = DiagnosticOrigin.fromAssertion(matchWorker.
|
|
4583
|
-
if (matchWorker.
|
|
4687
|
+
const origin = DiagnosticOrigin.fromAssertion(matchWorker.assertionNode);
|
|
4688
|
+
if (matchWorker.assertionNode.diagnostics.size === 0) {
|
|
4584
4689
|
const text = ExpectDiagnosticText.didNotRaiseError(isExpression);
|
|
4585
4690
|
return [Diagnostic.error(text, origin)];
|
|
4586
4691
|
}
|
|
4587
|
-
if (matchWorker.
|
|
4588
|
-
const count = matchWorker.
|
|
4692
|
+
if (matchWorker.assertionNode.diagnostics.size !== targetNodes.length) {
|
|
4693
|
+
const count = matchWorker.assertionNode.diagnostics.size;
|
|
4589
4694
|
const text = ExpectDiagnosticText.raisedError(isExpression, count, targetNodes.length);
|
|
4590
4695
|
const related = [
|
|
4591
4696
|
Diagnostic.error(ExpectDiagnosticText.raisedTypeError(count)),
|
|
4592
|
-
...Diagnostic.fromDiagnostics([...matchWorker.
|
|
4697
|
+
...Diagnostic.fromDiagnostics([...matchWorker.assertionNode.diagnostics]),
|
|
4593
4698
|
];
|
|
4594
4699
|
return [Diagnostic.error(text, origin).add({ related })];
|
|
4595
4700
|
}
|
|
4596
|
-
return [...matchWorker.
|
|
4701
|
+
return [...matchWorker.assertionNode.diagnostics].reduce((accumulator, diagnostic, index) => {
|
|
4597
4702
|
const targetNode = targetNodes[index];
|
|
4598
4703
|
const isMatch = this.#matchExpectedError(diagnostic, targetNode);
|
|
4599
|
-
if (matchWorker.
|
|
4600
|
-
const text = matchWorker.
|
|
4704
|
+
if (matchWorker.assertionNode.isNot ? isMatch : !isMatch) {
|
|
4705
|
+
const text = matchWorker.assertionNode.isNot
|
|
4601
4706
|
? ExpectDiagnosticText.raisedMatchingError(isExpression)
|
|
4602
4707
|
: ExpectDiagnosticText.didNotRaiseMatchingError(isExpression);
|
|
4603
|
-
const origin = DiagnosticOrigin.fromNode(targetNode, matchWorker.
|
|
4708
|
+
const origin = DiagnosticOrigin.fromNode(targetNode, matchWorker.assertionNode);
|
|
4604
4709
|
const related = [
|
|
4605
4710
|
Diagnostic.error(ExpectDiagnosticText.raisedTypeError()),
|
|
4606
4711
|
...Diagnostic.fromDiagnostics([diagnostic]),
|
|
@@ -4628,12 +4733,12 @@ class ToRaiseError {
|
|
|
4628
4733
|
}
|
|
4629
4734
|
let isMatch;
|
|
4630
4735
|
if (targetNodes.length === 0) {
|
|
4631
|
-
isMatch = matchWorker.
|
|
4736
|
+
isMatch = matchWorker.assertionNode.diagnostics.size > 0;
|
|
4632
4737
|
}
|
|
4633
4738
|
else {
|
|
4634
4739
|
isMatch =
|
|
4635
|
-
matchWorker.
|
|
4636
|
-
[...matchWorker.
|
|
4740
|
+
matchWorker.assertionNode.diagnostics.size === targetNodes.length &&
|
|
4741
|
+
[...matchWorker.assertionNode.diagnostics].every((diagnostic, index) => this.#matchExpectedError(diagnostic, targetNodes[index]));
|
|
4637
4742
|
}
|
|
4638
4743
|
return {
|
|
4639
4744
|
explain: () => this.#explain(matchWorker, sourceNode, targetNodes),
|
|
@@ -4683,16 +4788,16 @@ class ExpectService {
|
|
|
4683
4788
|
this.toHaveProperty = new ToHaveProperty(compiler);
|
|
4684
4789
|
this.toRaiseError = new ToRaiseError(compiler);
|
|
4685
4790
|
}
|
|
4686
|
-
match(
|
|
4687
|
-
const matcherNameText =
|
|
4688
|
-
if (!argumentOrTypeArgumentIsProvided("source", "Source",
|
|
4791
|
+
match(assertionNode, onDiagnostics) {
|
|
4792
|
+
const matcherNameText = assertionNode.matcherNameNode.name.text;
|
|
4793
|
+
if (!argumentOrTypeArgumentIsProvided("source", "Source", assertionNode.source[0], assertionNode.node.expression, onDiagnostics)) {
|
|
4689
4794
|
return;
|
|
4690
4795
|
}
|
|
4691
|
-
const matchWorker = new MatchWorker(this.#compiler, this.#typeChecker,
|
|
4692
|
-
if (!(matcherNameText === "toRaiseError" &&
|
|
4796
|
+
const matchWorker = new MatchWorker(this.#compiler, this.#typeChecker, assertionNode);
|
|
4797
|
+
if (!(matcherNameText === "toRaiseError" && assertionNode.isNot === false) &&
|
|
4693
4798
|
this.#reject.argumentType([
|
|
4694
|
-
["source",
|
|
4695
|
-
["target",
|
|
4799
|
+
["source", assertionNode.source[0]],
|
|
4800
|
+
["target", assertionNode.target?.[0]],
|
|
4696
4801
|
], onDiagnostics)) {
|
|
4697
4802
|
return;
|
|
4698
4803
|
}
|
|
@@ -4701,29 +4806,29 @@ class ExpectService {
|
|
|
4701
4806
|
case "toBe":
|
|
4702
4807
|
case "toBeAssignableTo":
|
|
4703
4808
|
case "toBeAssignableWith":
|
|
4704
|
-
if (!argumentOrTypeArgumentIsProvided("target", "Target",
|
|
4809
|
+
if (!argumentOrTypeArgumentIsProvided("target", "Target", assertionNode.target?.[0], assertionNode.matcherNameNode.name, onDiagnostics)) {
|
|
4705
4810
|
return;
|
|
4706
4811
|
}
|
|
4707
|
-
return this[matcherNameText].match(matchWorker,
|
|
4812
|
+
return this[matcherNameText].match(matchWorker, assertionNode.source[0], assertionNode.target[0], onDiagnostics);
|
|
4708
4813
|
case "toBeApplicable":
|
|
4709
|
-
return this.toBeApplicable.match(matchWorker,
|
|
4814
|
+
return this.toBeApplicable.match(matchWorker, assertionNode.source[0], onDiagnostics);
|
|
4710
4815
|
case "toBeCallableWith":
|
|
4711
4816
|
case "toBeConstructableWith":
|
|
4712
4817
|
case "toRaiseError":
|
|
4713
|
-
return this[matcherNameText].match(matchWorker,
|
|
4818
|
+
return this[matcherNameText].match(matchWorker, assertionNode.source[0], assertionNode.target, onDiagnostics);
|
|
4714
4819
|
case "toHaveProperty":
|
|
4715
|
-
if (!argumentIsProvided("key",
|
|
4820
|
+
if (!argumentIsProvided("key", assertionNode.target?.[0], assertionNode.matcherNameNode.name, onDiagnostics)) {
|
|
4716
4821
|
return;
|
|
4717
4822
|
}
|
|
4718
|
-
return this.toHaveProperty.match(matchWorker,
|
|
4823
|
+
return this.toHaveProperty.match(matchWorker, assertionNode.source[0], assertionNode.target[0], onDiagnostics);
|
|
4719
4824
|
default:
|
|
4720
|
-
this.#onMatcherIsNotSupported(matcherNameText,
|
|
4825
|
+
this.#onMatcherIsNotSupported(matcherNameText, assertionNode, onDiagnostics);
|
|
4721
4826
|
}
|
|
4722
4827
|
return;
|
|
4723
4828
|
}
|
|
4724
|
-
#onMatcherIsNotSupported(matcherNameText,
|
|
4829
|
+
#onMatcherIsNotSupported(matcherNameText, assertionNode, onDiagnostics) {
|
|
4725
4830
|
const text = ExpectDiagnosticText.matcherIsNotSupported(matcherNameText);
|
|
4726
|
-
const origin = DiagnosticOrigin.fromNode(
|
|
4831
|
+
const origin = DiagnosticOrigin.fromNode(assertionNode.matcherNameNode.name);
|
|
4727
4832
|
onDiagnostics(Diagnostic.error(text, origin));
|
|
4728
4833
|
}
|
|
4729
4834
|
}
|
|
@@ -4844,82 +4949,145 @@ class WhenService {
|
|
|
4844
4949
|
}
|
|
4845
4950
|
}
|
|
4846
4951
|
|
|
4952
|
+
class FixmeDiagnosticText {
|
|
4953
|
+
static considerRemoving() {
|
|
4954
|
+
return "Consider removing the '// @tstyche fixme' directive.";
|
|
4955
|
+
}
|
|
4956
|
+
static wasSupposedToFail(target) {
|
|
4957
|
+
return `The '${target}()' was supposed to fail, but it passed.`;
|
|
4958
|
+
}
|
|
4959
|
+
}
|
|
4960
|
+
|
|
4961
|
+
class FixmeService {
|
|
4962
|
+
static #expectRange;
|
|
4963
|
+
static #range;
|
|
4964
|
+
static async start(directive, owner) {
|
|
4965
|
+
const inlineConfig = await Directive.getInlineConfig(directive);
|
|
4966
|
+
if (inlineConfig?.fixme === true) {
|
|
4967
|
+
if (owner.brand === "expect") {
|
|
4968
|
+
FixmeService.#expectRange = { directive, owner, previous: FixmeService.#expectRange };
|
|
4969
|
+
}
|
|
4970
|
+
else {
|
|
4971
|
+
FixmeService.#range = { directive, owner, previous: FixmeService.#range };
|
|
4972
|
+
}
|
|
4973
|
+
}
|
|
4974
|
+
}
|
|
4975
|
+
static isFixme(owner, isPass) {
|
|
4976
|
+
if (owner.brand !== "expect") {
|
|
4977
|
+
return owner === FixmeService.#range?.owner && FixmeService.#range.isFail === true;
|
|
4978
|
+
}
|
|
4979
|
+
if (owner === FixmeService.#expectRange?.owner) {
|
|
4980
|
+
FixmeService.#expectRange.isFail = !isPass;
|
|
4981
|
+
return !isPass;
|
|
4982
|
+
}
|
|
4983
|
+
if (FixmeService.#range != null) {
|
|
4984
|
+
if (!isPass) {
|
|
4985
|
+
FixmeService.#range.isFail = true;
|
|
4986
|
+
return true;
|
|
4987
|
+
}
|
|
4988
|
+
FixmeService.#range.isFail ??= false;
|
|
4989
|
+
}
|
|
4990
|
+
return false;
|
|
4991
|
+
}
|
|
4992
|
+
static end(directive, owner, onFileDiagnostics) {
|
|
4993
|
+
let isFail;
|
|
4994
|
+
if (owner === FixmeService.#expectRange?.owner) {
|
|
4995
|
+
isFail = FixmeService.#expectRange.isFail;
|
|
4996
|
+
FixmeService.#expectRange = FixmeService.#expectRange?.previous;
|
|
4997
|
+
}
|
|
4998
|
+
if (owner === FixmeService.#range?.owner) {
|
|
4999
|
+
isFail = FixmeService.#range?.isFail;
|
|
5000
|
+
FixmeService.#range = FixmeService.#range?.previous;
|
|
5001
|
+
}
|
|
5002
|
+
if (isFail === false) {
|
|
5003
|
+
const targetText = owner.node.expression.getText();
|
|
5004
|
+
const text = [FixmeDiagnosticText.wasSupposedToFail(targetText), FixmeDiagnosticText.considerRemoving()];
|
|
5005
|
+
const origin = new DiagnosticOrigin(directive.namespace.start, directive.directive.end, directive.sourceFile);
|
|
5006
|
+
onFileDiagnostics([Diagnostic.error(text, origin)]);
|
|
5007
|
+
}
|
|
5008
|
+
}
|
|
5009
|
+
}
|
|
5010
|
+
|
|
4847
5011
|
class TestTreeWalker {
|
|
4848
5012
|
#cancellationToken;
|
|
4849
5013
|
#compiler;
|
|
4850
5014
|
#expectService;
|
|
4851
5015
|
#hasOnly;
|
|
4852
|
-
#
|
|
5016
|
+
#onFileDiagnostics;
|
|
4853
5017
|
#position;
|
|
4854
5018
|
#resolvedConfig;
|
|
4855
5019
|
#whenService;
|
|
4856
|
-
constructor(compiler, typeChecker, resolvedConfig,
|
|
5020
|
+
constructor(compiler, typeChecker, resolvedConfig, onFileDiagnostics, options) {
|
|
4857
5021
|
this.#compiler = compiler;
|
|
4858
5022
|
this.#resolvedConfig = resolvedConfig;
|
|
4859
|
-
this.#
|
|
5023
|
+
this.#onFileDiagnostics = onFileDiagnostics;
|
|
4860
5024
|
this.#cancellationToken = options.cancellationToken;
|
|
4861
5025
|
this.#hasOnly = options.hasOnly || resolvedConfig.only != null || options.position != null;
|
|
4862
5026
|
this.#position = options.position;
|
|
4863
5027
|
const reject = new Reject(compiler, typeChecker, resolvedConfig);
|
|
4864
5028
|
this.#expectService = new ExpectService(compiler, typeChecker, reject);
|
|
4865
|
-
this.#whenService = new WhenService(reject,
|
|
5029
|
+
this.#whenService = new WhenService(reject, onFileDiagnostics);
|
|
4866
5030
|
}
|
|
4867
|
-
async #resolveRunMode(
|
|
4868
|
-
const
|
|
4869
|
-
const inlineConfig = await Directive.getInlineConfig(
|
|
5031
|
+
async #resolveRunMode(flags, node) {
|
|
5032
|
+
const ifDirective = Directive.getDirectiveRange(this.#compiler, node, "if");
|
|
5033
|
+
const inlineConfig = await Directive.getInlineConfig(ifDirective);
|
|
4870
5034
|
if (inlineConfig?.if?.target != null && !Version.isIncluded(this.#compiler.version, inlineConfig.if.target)) {
|
|
4871
|
-
|
|
5035
|
+
flags |= 8;
|
|
4872
5036
|
}
|
|
4873
|
-
if (node.flags &
|
|
4874
|
-
mode |= RunMode.Fail;
|
|
4875
|
-
}
|
|
4876
|
-
if (node.flags & TestTreeNodeFlags.Only ||
|
|
5037
|
+
if (node.flags & 1 ||
|
|
4877
5038
|
(this.#resolvedConfig.only != null && node.name.toLowerCase().includes(this.#resolvedConfig.only.toLowerCase()))) {
|
|
4878
|
-
|
|
5039
|
+
flags |= 1;
|
|
4879
5040
|
}
|
|
4880
|
-
if (node.flags &
|
|
5041
|
+
if (node.flags & 2 ||
|
|
4881
5042
|
(this.#resolvedConfig.skip != null && node.name.toLowerCase().includes(this.#resolvedConfig.skip.toLowerCase()))) {
|
|
4882
|
-
|
|
5043
|
+
flags |= 2;
|
|
4883
5044
|
}
|
|
4884
|
-
if (node.flags &
|
|
4885
|
-
|
|
5045
|
+
if (node.flags & 4) {
|
|
5046
|
+
flags |= 4;
|
|
4886
5047
|
}
|
|
4887
5048
|
if (this.#position != null && node.node.getStart() === this.#position) {
|
|
4888
|
-
|
|
4889
|
-
|
|
5049
|
+
flags |= 1;
|
|
5050
|
+
flags &= -3;
|
|
4890
5051
|
}
|
|
4891
|
-
return
|
|
5052
|
+
return flags;
|
|
4892
5053
|
}
|
|
4893
|
-
async visit(nodes,
|
|
5054
|
+
async visit(nodes, runModeFlags, parentResult) {
|
|
4894
5055
|
for (const node of nodes) {
|
|
4895
5056
|
if (this.#cancellationToken?.isCancellationRequested) {
|
|
4896
5057
|
break;
|
|
4897
5058
|
}
|
|
5059
|
+
const fixmeDirective = Directive.getDirectiveRange(this.#compiler, node, "fixme");
|
|
5060
|
+
if (fixmeDirective) {
|
|
5061
|
+
FixmeService.start(fixmeDirective, node);
|
|
5062
|
+
}
|
|
4898
5063
|
switch (node.brand) {
|
|
4899
|
-
case
|
|
4900
|
-
await this.#visitDescribe(node,
|
|
5064
|
+
case "describe":
|
|
5065
|
+
await this.#visitDescribe(node, runModeFlags, parentResult);
|
|
4901
5066
|
break;
|
|
4902
|
-
case
|
|
4903
|
-
await this.#visitTest(node,
|
|
5067
|
+
case "test":
|
|
5068
|
+
await this.#visitTest(node, runModeFlags, parentResult);
|
|
4904
5069
|
break;
|
|
4905
|
-
case
|
|
4906
|
-
await this.#
|
|
5070
|
+
case "expect":
|
|
5071
|
+
await this.#visitExpect(node, runModeFlags, parentResult);
|
|
4907
5072
|
break;
|
|
4908
|
-
case
|
|
5073
|
+
case "when":
|
|
4909
5074
|
this.#visitWhen(node);
|
|
4910
5075
|
break;
|
|
4911
5076
|
}
|
|
5077
|
+
if (fixmeDirective) {
|
|
5078
|
+
FixmeService.end(fixmeDirective, node, this.#onFileDiagnostics);
|
|
5079
|
+
}
|
|
4912
5080
|
}
|
|
4913
5081
|
}
|
|
4914
|
-
async #
|
|
4915
|
-
await this.visit(
|
|
4916
|
-
|
|
4917
|
-
if (
|
|
5082
|
+
async #visitExpect(expect, runModeFlags, parentResult) {
|
|
5083
|
+
await this.visit(expect.children, runModeFlags, parentResult);
|
|
5084
|
+
runModeFlags = await this.#resolveRunMode(runModeFlags, expect);
|
|
5085
|
+
if (runModeFlags & 8) {
|
|
4918
5086
|
return;
|
|
4919
5087
|
}
|
|
4920
|
-
const expectResult = new ExpectResult(
|
|
5088
|
+
const expectResult = new ExpectResult(expect, parentResult);
|
|
4921
5089
|
EventEmitter.dispatch(["expect:start", { result: expectResult }]);
|
|
4922
|
-
if (
|
|
5090
|
+
if (runModeFlags & 2 || (this.#hasOnly && !(runModeFlags & 1))) {
|
|
4923
5091
|
EventEmitter.dispatch(["expect:skip", { result: expectResult }]);
|
|
4924
5092
|
return;
|
|
4925
5093
|
}
|
|
@@ -4929,59 +5097,57 @@ class TestTreeWalker {
|
|
|
4929
5097
|
{ diagnostics: Array.isArray(diagnostics) ? diagnostics : [diagnostics], result: expectResult },
|
|
4930
5098
|
]);
|
|
4931
5099
|
};
|
|
4932
|
-
if (
|
|
4933
|
-
onExpectDiagnostics(Diagnostic.fromDiagnostics([...
|
|
5100
|
+
if (expect.diagnostics.size > 0 && expect.matcherNameNode.name.text !== "toRaiseError") {
|
|
5101
|
+
onExpectDiagnostics(Diagnostic.fromDiagnostics([...expect.diagnostics]));
|
|
4934
5102
|
return;
|
|
4935
5103
|
}
|
|
4936
|
-
const matchResult = this.#expectService.match(
|
|
5104
|
+
const matchResult = this.#expectService.match(expect, onExpectDiagnostics);
|
|
4937
5105
|
if (!matchResult) {
|
|
4938
5106
|
return;
|
|
4939
5107
|
}
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
onExpectDiagnostics(Diagnostic.error(text, origin));
|
|
4945
|
-
}
|
|
4946
|
-
else {
|
|
4947
|
-
EventEmitter.dispatch(["expect:pass", { result: expectResult }]);
|
|
4948
|
-
}
|
|
5108
|
+
const isPass = expect.isNot ? !matchResult.isMatch : matchResult.isMatch;
|
|
5109
|
+
if (FixmeService.isFixme(expect, isPass)) {
|
|
5110
|
+
EventEmitter.dispatch(["expect:fixme", { result: expectResult }]);
|
|
5111
|
+
return;
|
|
4949
5112
|
}
|
|
4950
|
-
|
|
5113
|
+
if (isPass) {
|
|
4951
5114
|
EventEmitter.dispatch(["expect:pass", { result: expectResult }]);
|
|
4952
5115
|
}
|
|
4953
5116
|
else {
|
|
4954
5117
|
EventEmitter.dispatch(["expect:fail", { diagnostics: matchResult.explain(), result: expectResult }]);
|
|
4955
5118
|
}
|
|
4956
5119
|
}
|
|
4957
|
-
async #visitDescribe(describe,
|
|
4958
|
-
|
|
4959
|
-
if (
|
|
5120
|
+
async #visitDescribe(describe, runModeFlags, parentResult) {
|
|
5121
|
+
runModeFlags = await this.#resolveRunMode(runModeFlags, describe);
|
|
5122
|
+
if (runModeFlags & 8) {
|
|
4960
5123
|
return;
|
|
4961
5124
|
}
|
|
4962
5125
|
const describeResult = new DescribeResult(describe, parentResult);
|
|
4963
5126
|
EventEmitter.dispatch(["describe:start", { result: describeResult }]);
|
|
4964
|
-
if (!(
|
|
5127
|
+
if (!(runModeFlags & 2 ||
|
|
5128
|
+
(this.#hasOnly && !(runModeFlags & 1)) ||
|
|
5129
|
+
runModeFlags & 4) &&
|
|
4965
5130
|
describe.diagnostics.size > 0) {
|
|
4966
|
-
this.#
|
|
5131
|
+
this.#onFileDiagnostics(Diagnostic.fromDiagnostics([...describe.diagnostics]));
|
|
4967
5132
|
}
|
|
4968
5133
|
else {
|
|
4969
|
-
await this.visit(describe.children,
|
|
5134
|
+
await this.visit(describe.children, runModeFlags, describeResult);
|
|
4970
5135
|
}
|
|
4971
5136
|
EventEmitter.dispatch(["describe:end", { result: describeResult }]);
|
|
4972
5137
|
}
|
|
4973
|
-
async #visitTest(test,
|
|
4974
|
-
|
|
4975
|
-
if (
|
|
5138
|
+
async #visitTest(test, runModeFlags, parentResult) {
|
|
5139
|
+
runModeFlags = await this.#resolveRunMode(runModeFlags, test);
|
|
5140
|
+
if (runModeFlags & 8) {
|
|
4976
5141
|
return;
|
|
4977
5142
|
}
|
|
4978
5143
|
const testResult = new TestResult(test, parentResult);
|
|
4979
5144
|
EventEmitter.dispatch(["test:start", { result: testResult }]);
|
|
4980
|
-
if (
|
|
5145
|
+
if (runModeFlags & 4) {
|
|
4981
5146
|
EventEmitter.dispatch(["test:todo", { result: testResult }]);
|
|
4982
5147
|
return;
|
|
4983
5148
|
}
|
|
4984
|
-
if (!(
|
|
5149
|
+
if (!(runModeFlags & 2 || (this.#hasOnly && !(runModeFlags & 1))) &&
|
|
5150
|
+
test.diagnostics.size > 0) {
|
|
4985
5151
|
EventEmitter.dispatch([
|
|
4986
5152
|
"test:error",
|
|
4987
5153
|
{
|
|
@@ -4991,24 +5157,29 @@ class TestTreeWalker {
|
|
|
4991
5157
|
]);
|
|
4992
5158
|
return;
|
|
4993
5159
|
}
|
|
4994
|
-
await this.visit(test.children,
|
|
4995
|
-
if (
|
|
5160
|
+
await this.visit(test.children, runModeFlags, testResult);
|
|
5161
|
+
if (runModeFlags & 2 || (this.#hasOnly && !(runModeFlags & 1))) {
|
|
4996
5162
|
EventEmitter.dispatch(["test:skip", { result: testResult }]);
|
|
4997
5163
|
return;
|
|
4998
5164
|
}
|
|
4999
|
-
|
|
5000
|
-
|
|
5165
|
+
const isPass = testResult.expectCount.failed === 0;
|
|
5166
|
+
if (FixmeService.isFixme(test, isPass)) {
|
|
5167
|
+
EventEmitter.dispatch(["test:fixme", { result: testResult }]);
|
|
5168
|
+
return;
|
|
5001
5169
|
}
|
|
5002
|
-
|
|
5170
|
+
if (isPass) {
|
|
5003
5171
|
EventEmitter.dispatch(["test:pass", { result: testResult }]);
|
|
5004
5172
|
}
|
|
5173
|
+
else {
|
|
5174
|
+
EventEmitter.dispatch(["test:fail", { result: testResult }]);
|
|
5175
|
+
}
|
|
5005
5176
|
}
|
|
5006
5177
|
#visitWhen(when) {
|
|
5007
5178
|
this.#whenService.action(when);
|
|
5008
5179
|
}
|
|
5009
5180
|
}
|
|
5010
5181
|
|
|
5011
|
-
class
|
|
5182
|
+
class FileRunner {
|
|
5012
5183
|
#collectService;
|
|
5013
5184
|
#compiler;
|
|
5014
5185
|
#projectService;
|
|
@@ -5021,89 +5192,87 @@ class TaskRunner {
|
|
|
5021
5192
|
this.#collectService = new CollectService(compiler, this.#projectService, this.#resolvedConfig);
|
|
5022
5193
|
}
|
|
5023
5194
|
#onDiagnostics(diagnostics, result) {
|
|
5024
|
-
EventEmitter.dispatch(["
|
|
5195
|
+
EventEmitter.dispatch(["file:error", { diagnostics, result }]);
|
|
5025
5196
|
}
|
|
5026
|
-
async run(
|
|
5197
|
+
async run(file, cancellationToken) {
|
|
5027
5198
|
if (cancellationToken.isCancellationRequested) {
|
|
5028
5199
|
return;
|
|
5029
5200
|
}
|
|
5030
|
-
this.#projectService.openFile(
|
|
5031
|
-
const
|
|
5032
|
-
EventEmitter.dispatch(["
|
|
5033
|
-
await this.#run(
|
|
5034
|
-
EventEmitter.dispatch(["
|
|
5035
|
-
this.#projectService.closeFile(
|
|
5201
|
+
this.#projectService.openFile(file.path, undefined, this.#resolvedConfig.rootPath);
|
|
5202
|
+
const fileResult = new FileResult(file);
|
|
5203
|
+
EventEmitter.dispatch(["file:start", { result: fileResult }]);
|
|
5204
|
+
await this.#run(file, fileResult, cancellationToken);
|
|
5205
|
+
EventEmitter.dispatch(["file:end", { result: fileResult }]);
|
|
5206
|
+
this.#projectService.closeFile(file.path);
|
|
5036
5207
|
}
|
|
5037
|
-
async #
|
|
5038
|
-
const languageService = this.#projectService.getLanguageService(
|
|
5039
|
-
const syntacticDiagnostics = languageService?.getSyntacticDiagnostics(
|
|
5208
|
+
async #resolveFileFacts(file, fileResult, runModeFlags) {
|
|
5209
|
+
const languageService = this.#projectService.getLanguageService(file.path);
|
|
5210
|
+
const syntacticDiagnostics = languageService?.getSyntacticDiagnostics(file.path);
|
|
5040
5211
|
if (syntacticDiagnostics != null && syntacticDiagnostics.length > 0) {
|
|
5041
|
-
this.#onDiagnostics(Diagnostic.fromDiagnostics(syntacticDiagnostics),
|
|
5212
|
+
this.#onDiagnostics(Diagnostic.fromDiagnostics(syntacticDiagnostics), fileResult);
|
|
5042
5213
|
return;
|
|
5043
5214
|
}
|
|
5044
|
-
const semanticDiagnostics = languageService?.getSemanticDiagnostics(
|
|
5215
|
+
const semanticDiagnostics = languageService?.getSemanticDiagnostics(file.path);
|
|
5045
5216
|
const program = languageService?.getProgram();
|
|
5046
5217
|
const typeChecker = program?.getTypeChecker();
|
|
5047
|
-
const sourceFile = program?.getSourceFile(
|
|
5218
|
+
const sourceFile = program?.getSourceFile(file.path);
|
|
5048
5219
|
if (!sourceFile) {
|
|
5049
5220
|
return;
|
|
5050
5221
|
}
|
|
5051
|
-
const
|
|
5052
|
-
const directiveRanges = testTree.getDirectiveRanges(this.#compiler);
|
|
5222
|
+
const directiveRanges = Directive.getDirectiveRanges(this.#compiler, sourceFile);
|
|
5053
5223
|
const inlineConfig = await Directive.getInlineConfig(directiveRanges);
|
|
5054
5224
|
if (inlineConfig?.if?.target != null && !Version.isIncluded(this.#compiler.version, inlineConfig.if.target)) {
|
|
5055
|
-
|
|
5056
|
-
}
|
|
5057
|
-
if (testTree.suppressedErrors != null) {
|
|
5058
|
-
this.#suppressedService.match(testTree.suppressedErrors, (diagnostics) => {
|
|
5059
|
-
this.#onDiagnostics(diagnostics, taskResult);
|
|
5060
|
-
});
|
|
5225
|
+
runModeFlags |= 2;
|
|
5061
5226
|
}
|
|
5062
5227
|
if (inlineConfig?.template) {
|
|
5063
5228
|
if (semanticDiagnostics != null && semanticDiagnostics.length > 0) {
|
|
5064
|
-
this.#onDiagnostics(Diagnostic.fromDiagnostics(semanticDiagnostics),
|
|
5229
|
+
this.#onDiagnostics(Diagnostic.fromDiagnostics(semanticDiagnostics), fileResult);
|
|
5065
5230
|
return;
|
|
5066
5231
|
}
|
|
5067
|
-
const moduleSpecifier = pathToFileURL(
|
|
5232
|
+
const moduleSpecifier = pathToFileURL(file.path).toString();
|
|
5068
5233
|
const testText = (await import(moduleSpecifier))?.default;
|
|
5069
5234
|
if (typeof testText !== "string") {
|
|
5070
|
-
this.#onDiagnostics([Diagnostic.error("A template test file must export a string.")],
|
|
5235
|
+
this.#onDiagnostics([Diagnostic.error("A template test file must export a string.")], fileResult);
|
|
5071
5236
|
return;
|
|
5072
5237
|
}
|
|
5073
|
-
this.#projectService.openFile(
|
|
5074
|
-
return this.#
|
|
5238
|
+
this.#projectService.openFile(file.path, testText, this.#resolvedConfig.rootPath);
|
|
5239
|
+
return this.#resolveFileFacts(file, fileResult, runModeFlags);
|
|
5075
5240
|
}
|
|
5076
|
-
|
|
5241
|
+
const testTree = this.#collectService.createTestTree(sourceFile, semanticDiagnostics);
|
|
5242
|
+
this.#suppressedService.match(testTree, (diagnostics) => {
|
|
5243
|
+
this.#onDiagnostics(diagnostics, fileResult);
|
|
5244
|
+
});
|
|
5245
|
+
return { runModeFlags, testTree, typeChecker };
|
|
5077
5246
|
}
|
|
5078
|
-
async #run(
|
|
5079
|
-
if (!existsSync(
|
|
5080
|
-
this.#onDiagnostics([Diagnostic.error(`Test file '${
|
|
5247
|
+
async #run(file, fileResult, cancellationToken) {
|
|
5248
|
+
if (!existsSync(file.path)) {
|
|
5249
|
+
this.#onDiagnostics([Diagnostic.error(`Test file '${file.path}' does not exist.`)], fileResult);
|
|
5081
5250
|
return;
|
|
5082
5251
|
}
|
|
5083
|
-
const facts = await this.#
|
|
5252
|
+
const facts = await this.#resolveFileFacts(file, fileResult, 0);
|
|
5084
5253
|
if (!facts) {
|
|
5085
5254
|
return;
|
|
5086
5255
|
}
|
|
5087
5256
|
if (facts.testTree.diagnostics.size > 0) {
|
|
5088
|
-
this.#onDiagnostics(Diagnostic.fromDiagnostics([...facts.testTree.diagnostics]),
|
|
5257
|
+
this.#onDiagnostics(Diagnostic.fromDiagnostics([...facts.testTree.diagnostics]), fileResult);
|
|
5089
5258
|
return;
|
|
5090
5259
|
}
|
|
5091
|
-
const
|
|
5092
|
-
this.#onDiagnostics(diagnostics,
|
|
5260
|
+
const onFileDiagnostics = (diagnostics) => {
|
|
5261
|
+
this.#onDiagnostics(diagnostics, fileResult);
|
|
5093
5262
|
};
|
|
5094
|
-
const testTreeWalker = new TestTreeWalker(this.#compiler, facts.typeChecker, this.#resolvedConfig,
|
|
5263
|
+
const testTreeWalker = new TestTreeWalker(this.#compiler, facts.typeChecker, this.#resolvedConfig, onFileDiagnostics, {
|
|
5095
5264
|
cancellationToken,
|
|
5096
5265
|
hasOnly: facts.testTree.hasOnly,
|
|
5097
|
-
position:
|
|
5266
|
+
position: file.position,
|
|
5098
5267
|
});
|
|
5099
|
-
await testTreeWalker.visit(facts.testTree.children, facts.
|
|
5268
|
+
await testTreeWalker.visit(facts.testTree.children, facts.runModeFlags, undefined);
|
|
5100
5269
|
}
|
|
5101
5270
|
}
|
|
5102
5271
|
|
|
5103
5272
|
class Runner {
|
|
5104
5273
|
#eventEmitter = new EventEmitter();
|
|
5105
5274
|
#resolvedConfig;
|
|
5106
|
-
static version = "
|
|
5275
|
+
static version = "5.0.0-beta.0";
|
|
5107
5276
|
constructor(resolvedConfig) {
|
|
5108
5277
|
this.#resolvedConfig = resolvedConfig;
|
|
5109
5278
|
}
|
|
@@ -5111,7 +5280,7 @@ class Runner {
|
|
|
5111
5280
|
const resultHandler = new ResultHandler();
|
|
5112
5281
|
this.#eventEmitter.addHandler(resultHandler);
|
|
5113
5282
|
if (this.#resolvedConfig.failFast) {
|
|
5114
|
-
const cancellationHandler = new CancellationHandler(cancellationToken,
|
|
5283
|
+
const cancellationHandler = new CancellationHandler(cancellationToken, "failFast");
|
|
5115
5284
|
this.#eventEmitter.addHandler(cancellationHandler);
|
|
5116
5285
|
}
|
|
5117
5286
|
}
|
|
@@ -5140,39 +5309,39 @@ class Runner {
|
|
|
5140
5309
|
}
|
|
5141
5310
|
}
|
|
5142
5311
|
}
|
|
5143
|
-
async run(
|
|
5144
|
-
const
|
|
5312
|
+
async run(files, cancellationToken = new CancellationToken()) {
|
|
5313
|
+
const fileLocations = files.map((file) => (file instanceof FileLocation ? file : new FileLocation(file)));
|
|
5145
5314
|
this.#addHandlers(cancellationToken);
|
|
5146
5315
|
await this.#addReporters();
|
|
5147
|
-
await this.#run(
|
|
5316
|
+
await this.#run(fileLocations, cancellationToken);
|
|
5148
5317
|
if (this.#resolvedConfig.watch) {
|
|
5149
|
-
await this.#watch(
|
|
5318
|
+
await this.#watch(fileLocations, cancellationToken);
|
|
5150
5319
|
}
|
|
5151
5320
|
this.#eventEmitter.removeReporters();
|
|
5152
5321
|
this.#eventEmitter.removeHandlers();
|
|
5153
5322
|
}
|
|
5154
|
-
async #run(
|
|
5155
|
-
const result = new Result(
|
|
5323
|
+
async #run(files, cancellationToken) {
|
|
5324
|
+
const result = new Result(files);
|
|
5156
5325
|
EventEmitter.dispatch(["run:start", { result }]);
|
|
5157
5326
|
for (const target of this.#resolvedConfig.target) {
|
|
5158
|
-
const targetResult = new TargetResult(target,
|
|
5327
|
+
const targetResult = new TargetResult(target, files);
|
|
5159
5328
|
EventEmitter.dispatch(["target:start", { result: targetResult }]);
|
|
5160
5329
|
const compiler = await Store.load(target);
|
|
5161
5330
|
if (compiler) {
|
|
5162
|
-
const
|
|
5163
|
-
for (const
|
|
5164
|
-
await
|
|
5331
|
+
const fileRunner = new FileRunner(compiler, this.#resolvedConfig);
|
|
5332
|
+
for (const file of files) {
|
|
5333
|
+
await fileRunner.run(file, cancellationToken);
|
|
5165
5334
|
}
|
|
5166
5335
|
}
|
|
5167
5336
|
EventEmitter.dispatch(["target:end", { result: targetResult }]);
|
|
5168
5337
|
}
|
|
5169
5338
|
EventEmitter.dispatch(["run:end", { result }]);
|
|
5170
|
-
if (cancellationToken.reason ===
|
|
5339
|
+
if (cancellationToken.reason === "failFast") {
|
|
5171
5340
|
cancellationToken.reset();
|
|
5172
5341
|
}
|
|
5173
5342
|
}
|
|
5174
|
-
async #watch(
|
|
5175
|
-
const watchService = new WatchService(this.#resolvedConfig,
|
|
5343
|
+
async #watch(files, cancellationToken) {
|
|
5344
|
+
const watchService = new WatchService(this.#resolvedConfig, files);
|
|
5176
5345
|
for await (const testFiles of watchService.watch(cancellationToken)) {
|
|
5177
5346
|
await this.#run(testFiles, cancellationToken);
|
|
5178
5347
|
}
|
|
@@ -5182,14 +5351,14 @@ class Runner {
|
|
|
5182
5351
|
class Cli {
|
|
5183
5352
|
#eventEmitter = new EventEmitter();
|
|
5184
5353
|
async run(commandLine, cancellationToken = new CancellationToken()) {
|
|
5185
|
-
const cancellationHandler = new CancellationHandler(cancellationToken,
|
|
5354
|
+
const cancellationHandler = new CancellationHandler(cancellationToken, "configError");
|
|
5186
5355
|
this.#eventEmitter.addHandler(cancellationHandler);
|
|
5187
5356
|
const exitCodeHandler = new ExitCodeHandler();
|
|
5188
5357
|
this.#eventEmitter.addHandler(exitCodeHandler);
|
|
5189
5358
|
const setupReporter = new SetupReporter();
|
|
5190
5359
|
this.#eventEmitter.addReporter(setupReporter);
|
|
5191
5360
|
if (commandLine.includes("--help")) {
|
|
5192
|
-
const options = Options.for(
|
|
5361
|
+
const options = Options.for(2);
|
|
5193
5362
|
OutputService.writeMessage(helpText(options, Runner.version));
|
|
5194
5363
|
return;
|
|
5195
5364
|
}
|
|
@@ -5217,7 +5386,7 @@ class Cli {
|
|
|
5217
5386
|
return;
|
|
5218
5387
|
}
|
|
5219
5388
|
do {
|
|
5220
|
-
if (cancellationToken.reason ===
|
|
5389
|
+
if (cancellationToken.reason === "configChange") {
|
|
5221
5390
|
cancellationToken.reset();
|
|
5222
5391
|
exitCodeHandler.resetCode();
|
|
5223
5392
|
OutputService.clearTerminal();
|
|
@@ -5272,7 +5441,7 @@ class Cli {
|
|
|
5272
5441
|
const runner = new Runner(resolvedConfig);
|
|
5273
5442
|
await runner.run(testFiles, cancellationToken);
|
|
5274
5443
|
PluginService.removeHandlers();
|
|
5275
|
-
} while (cancellationToken.reason ===
|
|
5444
|
+
} while (cancellationToken.reason === "configChange");
|
|
5276
5445
|
this.#eventEmitter.removeHandlers();
|
|
5277
5446
|
}
|
|
5278
5447
|
#waitForChangedFiles(resolvedConfig, cancellationToken) {
|
|
@@ -5281,7 +5450,7 @@ class Cli {
|
|
|
5281
5450
|
cancellationToken.reset();
|
|
5282
5451
|
OutputService.writeMessage(waitingForFileChangesText());
|
|
5283
5452
|
const onChanged = () => {
|
|
5284
|
-
cancellationToken.cancel(
|
|
5453
|
+
cancellationToken.cancel("configChange");
|
|
5285
5454
|
for (const watcher of watchers) {
|
|
5286
5455
|
watcher.close();
|
|
5287
5456
|
}
|
|
@@ -5303,4 +5472,4 @@ class Cli {
|
|
|
5303
5472
|
}
|
|
5304
5473
|
}
|
|
5305
5474
|
|
|
5306
|
-
export {
|
|
5475
|
+
export { BaseReporter, CancellationHandler, CancellationReason, CancellationToken, Cli, CollectService, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, Directive, EventEmitter, ExitCodeHandler, ExpectNode, ExpectResult, ExpectService, FileLocation, FileResult, FileWatcher, Glob, InputService, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, PluginService, ProjectResult, ProjectService, Reject, Result, ResultCount, ResultHandler, ResultStatus, ResultTiming, Runner, Scribbler, Select, SelectDiagnosticText, SetupReporter, SourceFile, SourceService, Store, SummaryReporter, SuppressedService, TargetResult, TestResult, TestTree, TestTreeNode, TestTreeNodeBrand, TestTreeNodeFlags, Text, Version, WatchReporter, WatchService, Watcher, WhenNode, WhenService, addsPackageText, argumentIsProvided, argumentOrTypeArgumentIsProvided, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, environmentOptions, fileStatusText, fileViewText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, nodeBelongsToArgumentList, summaryText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
|