tstyche 4.0.0-rc.0 → 4.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,60 +20,6 @@ declare class Cli {
20
20
  run(commandLine: Array<string>, cancellationToken?: CancellationToken): Promise<void>;
21
21
  }
22
22
 
23
- declare enum TestTreeNodeBrand {
24
- Describe = "describe",
25
- Test = "test",
26
- Expect = "expect",
27
- When = "when"
28
- }
29
-
30
- declare enum TestTreeNodeFlags {
31
- None = 0,
32
- Fail = 1,
33
- Only = 2,
34
- Skip = 4,
35
- Todo = 8
36
- }
37
-
38
- declare class WhenNode extends TestTreeNode {
39
- actionNode: ts.CallExpression;
40
- actionNameNode: ts.PropertyAccessExpression;
41
- abilityDiagnostics: Set<ts.Diagnostic> | undefined;
42
- target: ts.NodeArray<ts.Expression> | ts.NodeArray<ts.TypeNode>;
43
- constructor(compiler: typeof ts, brand: TestTreeNodeBrand, node: ts.CallExpression, parent: TestTree | TestTreeNode, flags: TestTreeNodeFlags, actionNode: ts.CallExpression, actionNameNode: ts.PropertyAccessExpression);
44
- }
45
-
46
- declare class TestTreeNode {
47
- brand: TestTreeNodeBrand;
48
- children: Array<TestTreeNode | AssertionNode | WhenNode>;
49
- diagnostics: Set<ts.Diagnostic>;
50
- flags: TestTreeNodeFlags;
51
- name: string;
52
- node: ts.CallExpression;
53
- parent: TestTree | TestTreeNode;
54
- constructor(compiler: typeof ts, brand: TestTreeNodeBrand, node: ts.CallExpression, parent: TestTree | TestTreeNode, flags: TestTreeNodeFlags);
55
- }
56
-
57
- declare class TestTree {
58
- children: Array<TestTreeNode | AssertionNode | WhenNode>;
59
- diagnostics: Set<ts.Diagnostic>;
60
- hasOnly: boolean;
61
- sourceFile: ts.SourceFile;
62
- constructor(diagnostics: Set<ts.Diagnostic>, sourceFile: ts.SourceFile);
63
- }
64
-
65
- declare class AssertionNode extends TestTreeNode {
66
- abilityDiagnostics: Set<ts.Diagnostic> | undefined;
67
- isNot: boolean;
68
- matcherNode: ts.CallExpression | ts.Decorator;
69
- matcherNameNode: ts.PropertyAccessExpression;
70
- modifierNode: ts.PropertyAccessExpression;
71
- notNode: ts.PropertyAccessExpression | undefined;
72
- source: ts.NodeArray<ts.Expression> | ts.NodeArray<ts.TypeNode>;
73
- target: ts.NodeArray<ts.Expression> | ts.NodeArray<ts.TypeNode> | undefined;
74
- constructor(compiler: typeof ts, brand: TestTreeNodeBrand, node: ts.CallExpression, parent: TestTree | TestTreeNode, flags: TestTreeNodeFlags, matcherNode: ts.CallExpression | ts.Decorator, matcherNameNode: ts.PropertyAccessExpression, modifierNode: ts.PropertyAccessExpression, notNode?: ts.PropertyAccessExpression);
75
- }
76
-
77
23
  declare enum OptionBrand {
78
24
  String = "string",
79
25
  Number = "number",
@@ -100,52 +46,6 @@ declare class ConfigDiagnosticText {
100
46
  static watchCannotBeEnabled(): string;
101
47
  }
102
48
 
103
- /**
104
- * Options loaded from the configuration file.
105
- */
106
- interface ConfigFileOptions {
107
- /**
108
- * Enable type error reporting for source files.
109
- */
110
- checkSourceFiles?: boolean;
111
- /**
112
- * Stop running tests after the first failed assertion.
113
- */
114
- failFast?: boolean;
115
- /**
116
- * The list of plugins to use.
117
- */
118
- plugins?: Array<string>;
119
- /**
120
- * Reject the 'any' type passed as an argument to the 'expect()' function or a matcher.
121
- */
122
- rejectAnyType?: boolean;
123
- /**
124
- * Reject the 'never' type passed as an argument to the 'expect()' function or a matcher.
125
- */
126
- rejectNeverType?: boolean;
127
- /**
128
- * The list of reporters to use.
129
- */
130
- reporters?: Array<string>;
131
- /**
132
- * The path to a directory containing files of a test project.
133
- */
134
- rootPath?: string;
135
- /**
136
- * The list of TypeScript versions to be tested on.
137
- */
138
- target?: Array<string>;
139
- /**
140
- * The list of glob patterns matching the test files.
141
- */
142
- testFileMatch?: Array<string>;
143
- /**
144
- * The look up strategy to be used to find the TSConfig file.
145
- */
146
- tsconfig?: string;
147
- }
148
-
149
49
  /**
150
50
  * Options passed through the command line.
151
51
  */
@@ -220,6 +120,58 @@ interface CommandLineOptions {
220
120
  watch?: boolean;
221
121
  }
222
122
 
123
+ /**
124
+ * Options loaded from the configuration file.
125
+ */
126
+ interface ConfigFileOptions {
127
+ /**
128
+ * Enable type error reporting for source files.
129
+ */
130
+ checkSourceFiles?: boolean;
131
+ /**
132
+ * Stop running tests after the first failed assertion.
133
+ */
134
+ failFast?: boolean;
135
+ /**
136
+ * The list of plugins to use.
137
+ */
138
+ plugins?: Array<string>;
139
+ /**
140
+ * Reject the 'any' type passed as an argument to the 'expect()' function or a matcher.
141
+ */
142
+ rejectAnyType?: boolean;
143
+ /**
144
+ * Reject the 'never' type passed as an argument to the 'expect()' function or a matcher.
145
+ */
146
+ rejectNeverType?: boolean;
147
+ /**
148
+ * The list of reporters to use.
149
+ */
150
+ reporters?: Array<string>;
151
+ /**
152
+ * The path to a directory containing files of a test project.
153
+ */
154
+ rootPath?: string;
155
+ /**
156
+ * The list of TypeScript versions to be tested on.
157
+ */
158
+ target?: Array<string>;
159
+ /**
160
+ * The list of glob patterns matching the test files.
161
+ */
162
+ testFileMatch?: Array<string>;
163
+ /**
164
+ * The look up strategy to be used to find the TSConfig file.
165
+ */
166
+ tsconfig?: string;
167
+ }
168
+
169
+ interface InlineConfig {
170
+ if?: {
171
+ target?: Array<string>;
172
+ };
173
+ template?: boolean;
174
+ }
223
175
  interface ResolvedConfig extends Omit<CommandLineOptions, "config" | keyof ConfigFileOptions>, Required<ConfigFileOptions> {
224
176
  /**
225
177
  * The path to a TSTyche configuration file.
@@ -230,6 +182,7 @@ interface ResolvedConfig extends Omit<CommandLineOptions, "config" | keyof Confi
230
182
  */
231
183
  pathMatch: Array<string>;
232
184
  }
185
+
233
186
  declare class Config {
234
187
  #private;
235
188
  static parseCommandLine(commandLine: Array<string>): Promise<{
@@ -249,6 +202,25 @@ declare class Config {
249
202
  static resolveConfigFilePath(filePath?: string): string;
250
203
  }
251
204
 
205
+ interface TextRange {
206
+ start: number;
207
+ end: number;
208
+ text: string;
209
+ }
210
+ interface DirectiveRange {
211
+ namespace: TextRange;
212
+ directive?: TextRange;
213
+ argument?: TextRange;
214
+ }
215
+ type DirectiveRanges = Array<DirectiveRange> & {
216
+ sourceFile: ts.SourceFile;
217
+ };
218
+ declare class Directive {
219
+ #private;
220
+ static getDirectiveRanges(compiler: typeof ts, sourceFile: ts.SourceFile, position?: number): DirectiveRanges | undefined;
221
+ static getInlineConfig(ranges: DirectiveRanges | undefined): Promise<InlineConfig | undefined>;
222
+ }
223
+
252
224
  declare enum DiagnosticCategory {
253
225
  Error = "error",
254
226
  Warning = "warning"
@@ -304,6 +276,7 @@ type DiagnosticsHandler<T extends Diagnostic | Array<Diagnostic> = Diagnostic> =
304
276
  declare enum OptionGroup {
305
277
  CommandLine = 2,
306
278
  ConfigFile = 4,
279
+ InlineConditions = 8,
307
280
  ResolvedConfig = 6
308
281
  }
309
282
 
@@ -334,6 +307,62 @@ declare class Options {
334
307
 
335
308
  declare const defaultOptions: Required<ConfigFileOptions>;
336
309
 
310
+ declare enum TestTreeNodeBrand {
311
+ Describe = "describe",
312
+ Test = "test",
313
+ Expect = "expect",
314
+ When = "when"
315
+ }
316
+
317
+ declare enum TestTreeNodeFlags {
318
+ None = 0,
319
+ Fail = 1,
320
+ Only = 2,
321
+ Skip = 4,
322
+ Todo = 8
323
+ }
324
+
325
+ declare class WhenNode extends TestTreeNode {
326
+ actionNode: ts.CallExpression;
327
+ actionNameNode: ts.PropertyAccessExpression;
328
+ abilityDiagnostics: Set<ts.Diagnostic> | undefined;
329
+ target: ts.NodeArray<ts.Expression> | ts.NodeArray<ts.TypeNode>;
330
+ constructor(compiler: typeof ts, brand: TestTreeNodeBrand, node: ts.CallExpression, parent: TestTree | TestTreeNode, flags: TestTreeNodeFlags, actionNode: ts.CallExpression, actionNameNode: ts.PropertyAccessExpression);
331
+ }
332
+
333
+ declare class TestTreeNode {
334
+ brand: TestTreeNodeBrand;
335
+ children: Array<TestTreeNode | AssertionNode | WhenNode>;
336
+ diagnostics: Set<ts.Diagnostic>;
337
+ flags: TestTreeNodeFlags;
338
+ name: string;
339
+ node: ts.CallExpression;
340
+ parent: TestTree | TestTreeNode;
341
+ constructor(compiler: typeof ts, brand: TestTreeNodeBrand, node: ts.CallExpression, parent: TestTree | TestTreeNode, flags: TestTreeNodeFlags);
342
+ getDirectiveRanges(compiler: typeof ts): DirectiveRanges | undefined;
343
+ }
344
+
345
+ declare class TestTree {
346
+ children: Array<TestTreeNode | AssertionNode | WhenNode>;
347
+ diagnostics: Set<ts.Diagnostic>;
348
+ hasOnly: boolean;
349
+ sourceFile: ts.SourceFile;
350
+ constructor(diagnostics: Set<ts.Diagnostic>, sourceFile: ts.SourceFile);
351
+ getDirectiveRanges(compiler: typeof ts): DirectiveRanges | undefined;
352
+ }
353
+
354
+ declare class AssertionNode extends TestTreeNode {
355
+ abilityDiagnostics: Set<ts.Diagnostic> | undefined;
356
+ isNot: boolean;
357
+ matcherNode: ts.CallExpression | ts.Decorator;
358
+ matcherNameNode: ts.PropertyAccessExpression;
359
+ modifierNode: ts.PropertyAccessExpression;
360
+ notNode: ts.PropertyAccessExpression | undefined;
361
+ source: ts.NodeArray<ts.Expression> | ts.NodeArray<ts.TypeNode>;
362
+ target: ts.NodeArray<ts.Expression> | ts.NodeArray<ts.TypeNode> | undefined;
363
+ constructor(compiler: typeof ts, brand: TestTreeNodeBrand, node: ts.CallExpression, parent: TestTree | TestTreeNode, flags: TestTreeNodeFlags, matcherNode: ts.CallExpression | ts.Decorator, matcherNameNode: ts.PropertyAccessExpression, modifierNode: ts.PropertyAccessExpression, notNode: ts.PropertyAccessExpression | undefined);
364
+ }
365
+
337
366
  declare class ProjectService {
338
367
  #private;
339
368
  constructor(compiler: typeof ts, resolvedConfig: ResolvedConfig);
@@ -546,6 +575,8 @@ type Event = ["config:error", {
546
575
  result: TaskResult;
547
576
  }] | ["task:end", {
548
577
  result: TaskResult;
578
+ }] | ["directive:error", {
579
+ diagnostics: Array<Diagnostic>;
549
580
  }] | ["collect:start", {
550
581
  tree: TestTree;
551
582
  }] | ["collect:error", {
@@ -855,6 +886,7 @@ declare class Store {
855
886
  declare class Version {
856
887
  #private;
857
888
  static isGreaterThan(source: string, target: string): boolean;
889
+ static isIncluded(source: string, range: Array<string>): boolean;
858
890
  static isSatisfiedWith(source: string, target: string): boolean;
859
891
  }
860
892
 
@@ -886,5 +918,5 @@ declare class WhenService {
886
918
  action(when: WhenNode): void;
887
919
  }
888
920
 
889
- export { AssertionNode, BaseReporter, CancellationHandler, CancellationReason, CancellationToken, Cli, CollectService, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, EventEmitter, ExitCodeHandler, ExpectResult, ExpectService, FileWatcher, InputService, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, PluginService, ProjectResult, ProjectService, Reject, Result, ResultCount, ResultHandler, ResultStatus, ResultTiming, Runner, Scribbler, ScribblerJsx, Select, SelectDiagnosticText, SetupReporter, SourceFile, Store, SummaryReporter, TargetResult, Task, TaskResult, TestResult, TestTree, TestTreeNode, TestTreeNodeBrand, TestTreeNodeFlags, Text, Version, WatchReporter, WatchService, Watcher, WhenNode, WhenService, addsPackageText, argumentIsProvided, argumentOrTypeArgumentIsProvided, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, environmentOptions, fileViewText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, nodeBelongsToArgumentList, summaryText, taskStatusText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
890
- export type { CodeFrameOptions, CommandLineOptions, ConfigFileOptions, DiagnosticsHandler, EnvironmentOptions, Event, EventHandler, FileWatchHandler, InputHandler, ItemDefinition, MatchResult, OptionDefinition, Plugin, Reporter, ReporterEvent, ResolvedConfig, ScribblerOptions, SelectHookContext, TargetResultStatus, TaskResultStatus, TypeChecker, WatchHandler, WatcherOptions };
921
+ export { AssertionNode, BaseReporter, CancellationHandler, CancellationReason, CancellationToken, Cli, CollectService, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, Directive, EventEmitter, ExitCodeHandler, ExpectResult, ExpectService, FileWatcher, InputService, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, PluginService, ProjectResult, ProjectService, Reject, Result, ResultCount, ResultHandler, ResultStatus, ResultTiming, Runner, Scribbler, ScribblerJsx, Select, SelectDiagnosticText, SetupReporter, SourceFile, Store, SummaryReporter, TargetResult, Task, TaskResult, TestResult, TestTree, TestTreeNode, TestTreeNodeBrand, TestTreeNodeFlags, Text, Version, WatchReporter, WatchService, Watcher, WhenNode, WhenService, addsPackageText, argumentIsProvided, argumentOrTypeArgumentIsProvided, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, environmentOptions, fileViewText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, nodeBelongsToArgumentList, summaryText, taskStatusText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
922
+ export type { CodeFrameOptions, CommandLineOptions, ConfigFileOptions, DiagnosticsHandler, DirectiveRange, DirectiveRanges, EnvironmentOptions, Event, EventHandler, FileWatchHandler, InlineConfig, InputHandler, ItemDefinition, MatchResult, OptionDefinition, Plugin, Reporter, ReporterEvent, ResolvedConfig, ScribblerOptions, SelectHookContext, TargetResultStatus, TaskResultStatus, TypeChecker, WatchHandler, WatcherOptions };
package/build/tstyche.js CHANGED
@@ -292,6 +292,7 @@ var OptionGroup;
292
292
  (function (OptionGroup) {
293
293
  OptionGroup[OptionGroup["CommandLine"] = 2] = "CommandLine";
294
294
  OptionGroup[OptionGroup["ConfigFile"] = 4] = "ConfigFile";
295
+ OptionGroup[OptionGroup["InlineConditions"] = 8] = "InlineConditions";
295
296
  OptionGroup[OptionGroup["ResolvedConfig"] = 6] = "ResolvedConfig";
296
297
  })(OptionGroup || (OptionGroup = {}));
297
298
 
@@ -376,6 +377,9 @@ class Version {
376
377
  static isGreaterThan(source, target) {
377
378
  return !(source === target) && Version.#satisfies(source, target);
378
379
  }
380
+ static isIncluded(source, range) {
381
+ return range.some((target) => source.startsWith(target));
382
+ }
379
383
  static isSatisfiedWith(source, target) {
380
384
  return source === target || Version.#satisfies(source, target);
381
385
  }
@@ -1004,7 +1008,7 @@ class Options {
1004
1008
  {
1005
1009
  brand: OptionBrand.List,
1006
1010
  description: "The list of TypeScript versions to be tested on.",
1007
- group: OptionGroup.CommandLine | OptionGroup.ConfigFile,
1011
+ group: OptionGroup.CommandLine | OptionGroup.ConfigFile | OptionGroup.InlineConditions,
1008
1012
  items: {
1009
1013
  brand: OptionBrand.String,
1010
1014
  name: "target",
@@ -1239,146 +1243,18 @@ class CommandLineParser {
1239
1243
  }
1240
1244
  }
1241
1245
 
1242
- class JsonNode {
1243
- origin;
1244
- text;
1245
- constructor(text, origin) {
1246
- this.origin = origin;
1247
- this.text = text;
1248
- }
1249
- getValue(options) {
1250
- if (this.text == null) {
1251
- return undefined;
1252
- }
1253
- if (/^['"]/.test(this.text)) {
1254
- return this.text.slice(1, -1);
1255
- }
1256
- if (options?.expectsIdentifier) {
1257
- return this.text;
1258
- }
1259
- if (this.text === "true") {
1260
- return true;
1261
- }
1262
- if (this.text === "false") {
1263
- return false;
1264
- }
1265
- if (/^\d/.test(this.text)) {
1266
- return Number.parseFloat(this.text);
1267
- }
1268
- return undefined;
1269
- }
1270
- }
1271
-
1272
- class JsonScanner {
1273
- #currentPosition = 0;
1274
- #previousPosition = 0;
1275
- #sourceFile;
1276
- constructor(sourceFile) {
1277
- this.#sourceFile = sourceFile;
1278
- }
1279
- #getOrigin() {
1280
- return new DiagnosticOrigin(this.#previousPosition, this.#currentPosition, this.#sourceFile);
1281
- }
1282
- isRead() {
1283
- return !(this.#currentPosition < this.#sourceFile.text.length);
1284
- }
1285
- #peekCharacter() {
1286
- return this.#sourceFile.text.charAt(this.#currentPosition);
1287
- }
1288
- #peekNextCharacter() {
1289
- return this.#sourceFile.text.charAt(this.#currentPosition + 1);
1290
- }
1291
- peekToken(token) {
1292
- this.#skipTrivia();
1293
- return this.#peekCharacter() === token;
1294
- }
1295
- read() {
1296
- this.#skipTrivia();
1297
- this.#previousPosition = this.#currentPosition;
1298
- if (/[\s,:\]}]/.test(this.#peekCharacter())) {
1299
- return new JsonNode(undefined, this.#getOrigin());
1300
- }
1301
- let text = "";
1302
- let closingTokenText = "";
1303
- if (/[[{'"]/.test(this.#peekCharacter())) {
1304
- text += this.#readCharacter();
1305
- switch (text) {
1306
- case "[":
1307
- closingTokenText = "]";
1308
- break;
1309
- case "{":
1310
- closingTokenText = "}";
1311
- break;
1312
- default:
1313
- closingTokenText = text;
1314
- }
1315
- }
1316
- while (!this.isRead()) {
1317
- text += this.#readCharacter();
1318
- if (text.slice(-1) === closingTokenText || (!closingTokenText && /[\s,:\]}]/.test(this.#peekCharacter()))) {
1319
- break;
1320
- }
1321
- }
1322
- return new JsonNode(text, this.#getOrigin());
1323
- }
1324
- #readCharacter() {
1325
- return this.#sourceFile.text.charAt(this.#currentPosition++);
1326
- }
1327
- readToken(token) {
1328
- this.#skipTrivia();
1329
- this.#previousPosition = this.#currentPosition;
1330
- if (this.#peekCharacter() === token) {
1331
- this.#currentPosition++;
1332
- return new JsonNode(token, this.#getOrigin());
1333
- }
1334
- return new JsonNode(undefined, this.#getOrigin());
1335
- }
1336
- #skipTrivia() {
1337
- while (!this.isRead()) {
1338
- if (/\s/.test(this.#peekCharacter())) {
1339
- this.#currentPosition++;
1340
- continue;
1341
- }
1342
- if (this.#peekCharacter() === "/") {
1343
- if (this.#peekNextCharacter() === "/") {
1344
- this.#currentPosition += 2;
1345
- while (!this.isRead()) {
1346
- if (this.#readCharacter() === "\n") {
1347
- break;
1348
- }
1349
- }
1350
- continue;
1351
- }
1352
- if (this.#peekNextCharacter() === "*") {
1353
- this.#currentPosition += 2;
1354
- while (!this.isRead()) {
1355
- if (this.#peekCharacter() === "*" && this.#peekNextCharacter() === "/") {
1356
- this.#currentPosition += 2;
1357
- break;
1358
- }
1359
- this.#currentPosition++;
1360
- }
1361
- continue;
1362
- }
1363
- }
1364
- break;
1365
- }
1366
- this.#previousPosition = this.#currentPosition;
1367
- }
1368
- }
1369
-
1370
- class ConfigFileParser {
1246
+ class ConfigParser {
1371
1247
  #configFileOptions;
1372
1248
  #jsonScanner;
1373
1249
  #onDiagnostics;
1374
1250
  #options;
1375
1251
  #sourceFile;
1376
- constructor(configFileOptions, sourceFile, onDiagnostics) {
1377
- this.#configFileOptions = configFileOptions;
1378
- this.#sourceFile = sourceFile;
1252
+ constructor(configOptions, optionGroup, sourceFile, jsonScanner, onDiagnostics) {
1253
+ this.#configFileOptions = configOptions;
1254
+ this.#jsonScanner = jsonScanner;
1379
1255
  this.#onDiagnostics = onDiagnostics;
1380
- this.#options = Options.for(OptionGroup.ConfigFile);
1381
- this.#jsonScanner = new JsonScanner(this.#sourceFile);
1256
+ this.#sourceFile = sourceFile;
1257
+ this.#options = Options.for(optionGroup);
1382
1258
  }
1383
1259
  #onRequiresValue(optionDefinition, jsonNode, isListItem) {
1384
1260
  const text = isListItem
@@ -1471,9 +1347,8 @@ class ConfigFileParser {
1471
1347
  if (!optionDefinition) {
1472
1348
  const text = ConfigDiagnosticText.unknownOption(optionName);
1473
1349
  this.#onDiagnostics(Diagnostic.error(text, optionNameNode.origin));
1474
- if (this.#jsonScanner.readToken(":")) {
1475
- this.#jsonScanner.read();
1476
- }
1350
+ this.#jsonScanner.readToken(":");
1351
+ this.#jsonScanner.read();
1477
1352
  const commaToken = this.#jsonScanner.readToken(",");
1478
1353
  if (!commaToken.text) {
1479
1354
  break;
@@ -1507,6 +1382,138 @@ class ConfigFileParser {
1507
1382
  }
1508
1383
  }
1509
1384
 
1385
+ class JsonNode {
1386
+ origin;
1387
+ text;
1388
+ constructor(text, origin) {
1389
+ this.origin = origin;
1390
+ this.text = text;
1391
+ }
1392
+ getValue(options) {
1393
+ if (this.text == null) {
1394
+ return undefined;
1395
+ }
1396
+ if (/^['"]/.test(this.text)) {
1397
+ return this.text.slice(1, -1);
1398
+ }
1399
+ if (options?.expectsIdentifier) {
1400
+ return this.text;
1401
+ }
1402
+ if (this.text === "true") {
1403
+ return true;
1404
+ }
1405
+ if (this.text === "false") {
1406
+ return false;
1407
+ }
1408
+ if (/^\d/.test(this.text)) {
1409
+ return Number.parseFloat(this.text);
1410
+ }
1411
+ return undefined;
1412
+ }
1413
+ }
1414
+
1415
+ class JsonScanner {
1416
+ #end;
1417
+ #position;
1418
+ #previousPosition;
1419
+ #sourceFile;
1420
+ constructor(sourceFile, options) {
1421
+ this.#end = options?.end ?? sourceFile.text.length;
1422
+ this.#position = options?.start ?? 0;
1423
+ this.#previousPosition = options?.start ?? 0;
1424
+ this.#sourceFile = sourceFile;
1425
+ }
1426
+ #getOrigin() {
1427
+ return new DiagnosticOrigin(this.#previousPosition, this.#position, this.#sourceFile);
1428
+ }
1429
+ isRead() {
1430
+ return !(this.#position < this.#end);
1431
+ }
1432
+ #peekCharacter() {
1433
+ return this.#sourceFile.text.charAt(this.#position);
1434
+ }
1435
+ #peekNextCharacter() {
1436
+ return this.#sourceFile.text.charAt(this.#position + 1);
1437
+ }
1438
+ peekToken(token) {
1439
+ this.#skipTrivia();
1440
+ return this.#peekCharacter() === token;
1441
+ }
1442
+ read() {
1443
+ this.#skipTrivia();
1444
+ this.#previousPosition = this.#position;
1445
+ if (/[\s,:\]}]/.test(this.#peekCharacter())) {
1446
+ return new JsonNode(undefined, this.#getOrigin());
1447
+ }
1448
+ let text = "";
1449
+ let closingTokenText = "";
1450
+ if (/[[{'"]/.test(this.#peekCharacter())) {
1451
+ text += this.#readCharacter();
1452
+ switch (text) {
1453
+ case "[":
1454
+ closingTokenText = "]";
1455
+ break;
1456
+ case "{":
1457
+ closingTokenText = "}";
1458
+ break;
1459
+ default:
1460
+ closingTokenText = text;
1461
+ }
1462
+ }
1463
+ while (!this.isRead()) {
1464
+ text += this.#readCharacter();
1465
+ if (text.slice(-1) === closingTokenText || (!closingTokenText && /[\s,:\]}]/.test(this.#peekCharacter()))) {
1466
+ break;
1467
+ }
1468
+ }
1469
+ return new JsonNode(text, this.#getOrigin());
1470
+ }
1471
+ #readCharacter() {
1472
+ return this.#sourceFile.text.charAt(this.#position++);
1473
+ }
1474
+ readToken(token) {
1475
+ this.#skipTrivia();
1476
+ this.#previousPosition = this.#position;
1477
+ if (this.#peekCharacter() === token) {
1478
+ this.#position++;
1479
+ return new JsonNode(token, this.#getOrigin());
1480
+ }
1481
+ return new JsonNode(undefined, this.#getOrigin());
1482
+ }
1483
+ #skipTrivia() {
1484
+ while (!this.isRead()) {
1485
+ if (/\s/.test(this.#peekCharacter())) {
1486
+ this.#position++;
1487
+ continue;
1488
+ }
1489
+ if (this.#peekCharacter() === "/") {
1490
+ if (this.#peekNextCharacter() === "/") {
1491
+ this.#position += 2;
1492
+ while (!this.isRead()) {
1493
+ if (this.#readCharacter() === "\n") {
1494
+ break;
1495
+ }
1496
+ }
1497
+ continue;
1498
+ }
1499
+ if (this.#peekNextCharacter() === "*") {
1500
+ this.#position += 2;
1501
+ while (!this.isRead()) {
1502
+ if (this.#peekCharacter() === "*" && this.#peekNextCharacter() === "/") {
1503
+ this.#position += 2;
1504
+ break;
1505
+ }
1506
+ this.#position++;
1507
+ }
1508
+ continue;
1509
+ }
1510
+ }
1511
+ break;
1512
+ }
1513
+ this.#previousPosition = this.#position;
1514
+ }
1515
+ }
1516
+
1510
1517
  const defaultOptions = {
1511
1518
  checkSourceFiles: true,
1512
1519
  failFast: false,
@@ -1544,7 +1551,7 @@ class Config {
1544
1551
  encoding: "utf8",
1545
1552
  });
1546
1553
  const sourceFile = new SourceFile(configFilePath, configFileText);
1547
- const configFileParser = new ConfigFileParser(configFileOptions, sourceFile, Config.#onDiagnostics);
1554
+ const configFileParser = new ConfigParser(configFileOptions, OptionGroup.ConfigFile, sourceFile, new JsonScanner(sourceFile), Config.#onDiagnostics);
1548
1555
  await configFileParser.parse();
1549
1556
  if (configFileOptions.target != null) {
1550
1557
  configFileOptions.target = await Target.expand(configFileOptions.target);
@@ -1570,6 +1577,114 @@ class Config {
1570
1577
  }
1571
1578
  }
1572
1579
 
1580
+ class DirectiveDiagnosticText {
1581
+ static doesNotTakeArgument(directiveName) {
1582
+ return `Directive '${directiveName}' does not take an argument.`;
1583
+ }
1584
+ static isNotSupported(directive) {
1585
+ return `The '${directive}' directive is not supported.`;
1586
+ }
1587
+ static requiresArgument(directiveName) {
1588
+ return `Directive '${directiveName}' requires an argument.`;
1589
+ }
1590
+ }
1591
+
1592
+ class Directive {
1593
+ static #commentSeparatorRegex = /--+/;
1594
+ static #directiveRegex = /^(\/\/\s*@tstyche)(\s*|-)?(\S*)?(\s*)?(.*)?/i;
1595
+ static getDirectiveRanges(compiler, sourceFile, position = 0) {
1596
+ const comments = compiler.getLeadingCommentRanges(sourceFile.text, position);
1597
+ if (!comments || comments.length === 0) {
1598
+ return;
1599
+ }
1600
+ const ranges = Object.assign([], { sourceFile });
1601
+ for (const comment of comments) {
1602
+ if (comment.kind !== compiler.SyntaxKind.SingleLineCommentTrivia) {
1603
+ continue;
1604
+ }
1605
+ const range = Directive.#getRange(sourceFile, comment);
1606
+ if (range != null) {
1607
+ ranges.push(range);
1608
+ }
1609
+ }
1610
+ return ranges;
1611
+ }
1612
+ static async getInlineConfig(ranges) {
1613
+ if (!ranges) {
1614
+ return;
1615
+ }
1616
+ const inlineConfig = {};
1617
+ for (const range of ranges) {
1618
+ await Directive.#parse(inlineConfig, ranges.sourceFile, range);
1619
+ }
1620
+ return inlineConfig;
1621
+ }
1622
+ static #getRange(sourceFile, comment) {
1623
+ const [text] = sourceFile.text.substring(comment.pos, comment.end).split(Directive.#commentSeparatorRegex);
1624
+ const found = text?.match(Directive.#directiveRegex);
1625
+ const namespaceText = found?.[1];
1626
+ if (!namespaceText) {
1627
+ return;
1628
+ }
1629
+ const ranges = {
1630
+ namespace: { start: comment.pos, end: comment.pos + namespaceText.length, text: namespaceText },
1631
+ };
1632
+ const directiveSeparatorText = found?.[2];
1633
+ const directiveText = found?.[3];
1634
+ if (directiveText != null && directiveText.length > 0) {
1635
+ const start = ranges.namespace.end + (directiveSeparatorText?.length ?? 0);
1636
+ ranges.directive = { start, end: start + directiveText.length, text: directiveText };
1637
+ }
1638
+ const argumentSeparatorText = found?.[4];
1639
+ const argumentText = found?.[5]?.trimEnd();
1640
+ if (ranges.directive != null && argumentText != null && argumentText.length > 0) {
1641
+ const start = ranges.directive.end + (argumentSeparatorText?.length ?? 0);
1642
+ ranges.argument = { start, end: start + argumentText.length, text: argumentText };
1643
+ }
1644
+ return ranges;
1645
+ }
1646
+ static #onDiagnostics(diagnostic) {
1647
+ EventEmitter.dispatch(["directive:error", { diagnostics: [diagnostic] }]);
1648
+ }
1649
+ static async #parse(inlineConfig, sourceFile, ranges) {
1650
+ switch (ranges.directive?.text) {
1651
+ case "if":
1652
+ {
1653
+ if (!ranges.argument?.text) {
1654
+ const text = DirectiveDiagnosticText.requiresArgument(ranges.directive.text);
1655
+ const origin = new DiagnosticOrigin(ranges.directive.start, ranges.directive.end, sourceFile);
1656
+ Directive.#onDiagnostics(Diagnostic.error(text, origin));
1657
+ return;
1658
+ }
1659
+ const value = await Directive.#parseJson(sourceFile, ranges.argument.start, ranges.argument.end);
1660
+ inlineConfig.if = value;
1661
+ }
1662
+ return;
1663
+ case "template":
1664
+ if (ranges.argument?.text != null) {
1665
+ const text = DirectiveDiagnosticText.doesNotTakeArgument(ranges.directive.text);
1666
+ const origin = new DiagnosticOrigin(ranges.directive.start, ranges.directive.end, sourceFile);
1667
+ Directive.#onDiagnostics(Diagnostic.error(text, origin));
1668
+ }
1669
+ inlineConfig.template = true;
1670
+ return;
1671
+ }
1672
+ const target = ranges?.directive ?? ranges.namespace;
1673
+ const text = DirectiveDiagnosticText.isNotSupported(target.text);
1674
+ const origin = new DiagnosticOrigin(target.start, target.end, sourceFile);
1675
+ Directive.#onDiagnostics(Diagnostic.error(text, origin));
1676
+ }
1677
+ static async #parseJson(sourceFile, start, end) {
1678
+ const inlineOptions = {};
1679
+ const configParser = new ConfigParser(inlineOptions, OptionGroup.InlineConditions, sourceFile, new JsonScanner(sourceFile, { start, end }), Directive.#onDiagnostics);
1680
+ await configParser.parse();
1681
+ if ("target" in inlineOptions) {
1682
+ inlineOptions["target"] = await Target.expand(inlineOptions["target"]);
1683
+ }
1684
+ return inlineOptions;
1685
+ }
1686
+ }
1687
+
1573
1688
  class CancellationHandler {
1574
1689
  #cancellationToken;
1575
1690
  #cancellationReason;
@@ -1777,6 +1892,7 @@ class ResultHandler {
1777
1892
  this.#taskResult.timing.start = Date.now();
1778
1893
  break;
1779
1894
  case "task:error":
1895
+ case "directive:error":
1780
1896
  case "collect:error":
1781
1897
  this.#targetResult.status = ResultStatus.Failed;
1782
1898
  this.#taskResult.status = ResultStatus.Failed;
@@ -2380,6 +2496,7 @@ class ListReporter extends BaseReporter {
2380
2496
  this.#hasReportedError = false;
2381
2497
  break;
2382
2498
  case "task:error":
2499
+ case "directive:error":
2383
2500
  case "collect:error":
2384
2501
  for (const diagnostic of payload.diagnostics) {
2385
2502
  this.#fileView.addMessage(diagnosticText(diagnostic));
@@ -2895,6 +3012,9 @@ class TestTreeNode {
2895
3012
  }
2896
3013
  }
2897
3014
  }
3015
+ getDirectiveRanges(compiler) {
3016
+ return Directive.getDirectiveRanges(compiler, this.node.getSourceFile(), this.node.getFullStart());
3017
+ }
2898
3018
  }
2899
3019
 
2900
3020
  class AssertionNode extends TestTreeNode {
@@ -3185,6 +3305,9 @@ class TestTree {
3185
3305
  this.diagnostics = diagnostics;
3186
3306
  this.sourceFile = sourceFile;
3187
3307
  }
3308
+ getDirectiveRanges(compiler) {
3309
+ return Directive.getDirectiveRanges(compiler, this.sourceFile);
3310
+ }
3188
3311
  }
3189
3312
 
3190
3313
  class WhenNode extends TestTreeNode {
@@ -4529,6 +4652,7 @@ class WhenService {
4529
4652
 
4530
4653
  class TestTreeWalker {
4531
4654
  #cancellationToken;
4655
+ #compiler;
4532
4656
  #expectService;
4533
4657
  #hasOnly;
4534
4658
  #onTaskDiagnostics;
@@ -4536,6 +4660,7 @@ class TestTreeWalker {
4536
4660
  #resolvedConfig;
4537
4661
  #whenService;
4538
4662
  constructor(compiler, typeChecker, resolvedConfig, onTaskDiagnostics, options) {
4663
+ this.#compiler = compiler;
4539
4664
  this.#resolvedConfig = resolvedConfig;
4540
4665
  this.#onTaskDiagnostics = onTaskDiagnostics;
4541
4666
  this.#cancellationToken = options.cancellationToken;
@@ -4545,43 +4670,46 @@ class TestTreeWalker {
4545
4670
  this.#expectService = new ExpectService(compiler, typeChecker, reject);
4546
4671
  this.#whenService = new WhenService(reject, onTaskDiagnostics);
4547
4672
  }
4548
- #resolveRunMode(mode, testNode) {
4549
- if (testNode.flags & TestTreeNodeFlags.Fail) {
4673
+ async #resolveRunMode(mode, node) {
4674
+ const directiveRanges = node.getDirectiveRanges(this.#compiler);
4675
+ const inlineConfig = await Directive.getInlineConfig(directiveRanges);
4676
+ if (inlineConfig?.if?.target != null && !Version.isIncluded(this.#compiler.version, inlineConfig.if.target)) {
4677
+ mode |= RunMode.Skip;
4678
+ }
4679
+ if (node.flags & TestTreeNodeFlags.Fail) {
4550
4680
  mode |= RunMode.Fail;
4551
4681
  }
4552
- if (testNode.flags & TestTreeNodeFlags.Only ||
4553
- (this.#resolvedConfig.only != null &&
4554
- testNode.name.toLowerCase().includes(this.#resolvedConfig.only.toLowerCase()))) {
4682
+ if (node.flags & TestTreeNodeFlags.Only ||
4683
+ (this.#resolvedConfig.only != null && node.name.toLowerCase().includes(this.#resolvedConfig.only.toLowerCase()))) {
4555
4684
  mode |= RunMode.Only;
4556
4685
  }
4557
- if (testNode.flags & TestTreeNodeFlags.Skip ||
4558
- (this.#resolvedConfig.skip != null &&
4559
- testNode.name.toLowerCase().includes(this.#resolvedConfig.skip.toLowerCase()))) {
4686
+ if (node.flags & TestTreeNodeFlags.Skip ||
4687
+ (this.#resolvedConfig.skip != null && node.name.toLowerCase().includes(this.#resolvedConfig.skip.toLowerCase()))) {
4560
4688
  mode |= RunMode.Skip;
4561
4689
  }
4562
- if (testNode.flags & TestTreeNodeFlags.Todo) {
4690
+ if (node.flags & TestTreeNodeFlags.Todo) {
4563
4691
  mode |= RunMode.Todo;
4564
4692
  }
4565
- if (this.#position != null && testNode.node.getStart() === this.#position) {
4693
+ if (this.#position != null && node.node.getStart() === this.#position) {
4566
4694
  mode |= RunMode.Only;
4567
4695
  mode &= ~RunMode.Skip;
4568
4696
  }
4569
4697
  return mode;
4570
4698
  }
4571
- visit(nodes, runMode, parentResult) {
4699
+ async visit(nodes, runMode, parentResult) {
4572
4700
  for (const node of nodes) {
4573
4701
  if (this.#cancellationToken?.isCancellationRequested) {
4574
4702
  break;
4575
4703
  }
4576
4704
  switch (node.brand) {
4577
4705
  case TestTreeNodeBrand.Describe:
4578
- this.#visitDescribe(node, runMode, parentResult);
4706
+ await this.#visitDescribe(node, runMode, parentResult);
4579
4707
  break;
4580
4708
  case TestTreeNodeBrand.Test:
4581
- this.#visitTest(node, runMode, parentResult);
4709
+ await this.#visitTest(node, runMode, parentResult);
4582
4710
  break;
4583
4711
  case TestTreeNodeBrand.Expect:
4584
- this.#visitAssertion(node, runMode, parentResult);
4712
+ await this.#visitAssertion(node, runMode, parentResult);
4585
4713
  break;
4586
4714
  case TestTreeNodeBrand.When:
4587
4715
  this.#visitWhen(node);
@@ -4589,11 +4717,11 @@ class TestTreeWalker {
4589
4717
  }
4590
4718
  }
4591
4719
  }
4592
- #visitAssertion(assertion, runMode, parentResult) {
4593
- this.visit(assertion.children, runMode, parentResult);
4720
+ async #visitAssertion(assertion, runMode, parentResult) {
4721
+ await this.visit(assertion.children, runMode, parentResult);
4594
4722
  const expectResult = new ExpectResult(assertion, parentResult);
4595
4723
  EventEmitter.dispatch(["expect:start", { result: expectResult }]);
4596
- runMode = this.#resolveRunMode(runMode, assertion);
4724
+ runMode = await this.#resolveRunMode(runMode, assertion);
4597
4725
  if (runMode & RunMode.Skip || (this.#hasOnly && !(runMode & RunMode.Only))) {
4598
4726
  EventEmitter.dispatch(["expect:skip", { result: expectResult }]);
4599
4727
  return;
@@ -4629,23 +4757,23 @@ class TestTreeWalker {
4629
4757
  EventEmitter.dispatch(["expect:fail", { diagnostics: matchResult.explain(), result: expectResult }]);
4630
4758
  }
4631
4759
  }
4632
- #visitDescribe(describe, runMode, parentResult) {
4760
+ async #visitDescribe(describe, runMode, parentResult) {
4633
4761
  const describeResult = new DescribeResult(describe, parentResult);
4634
4762
  EventEmitter.dispatch(["describe:start", { result: describeResult }]);
4635
- runMode = this.#resolveRunMode(runMode, describe);
4763
+ runMode = await this.#resolveRunMode(runMode, describe);
4636
4764
  if (!(runMode & RunMode.Skip || (this.#hasOnly && !(runMode & RunMode.Only)) || runMode & RunMode.Todo) &&
4637
4765
  describe.diagnostics.size > 0) {
4638
4766
  this.#onTaskDiagnostics(Diagnostic.fromDiagnostics([...describe.diagnostics]));
4639
4767
  }
4640
4768
  else {
4641
- this.visit(describe.children, runMode, describeResult);
4769
+ await this.visit(describe.children, runMode, describeResult);
4642
4770
  }
4643
4771
  EventEmitter.dispatch(["describe:end", { result: describeResult }]);
4644
4772
  }
4645
- #visitTest(test, runMode, parentResult) {
4773
+ async #visitTest(test, runMode, parentResult) {
4646
4774
  const testResult = new TestResult(test, parentResult);
4647
4775
  EventEmitter.dispatch(["test:start", { result: testResult }]);
4648
- runMode = this.#resolveRunMode(runMode, test);
4776
+ runMode = await this.#resolveRunMode(runMode, test);
4649
4777
  if (runMode & RunMode.Todo) {
4650
4778
  EventEmitter.dispatch(["test:todo", { result: testResult }]);
4651
4779
  return;
@@ -4660,7 +4788,7 @@ class TestTreeWalker {
4660
4788
  ]);
4661
4789
  return;
4662
4790
  }
4663
- this.visit(test.children, runMode, testResult);
4791
+ await this.visit(test.children, runMode, testResult);
4664
4792
  if (runMode & RunMode.Skip || (this.#hasOnly && !(runMode & RunMode.Only))) {
4665
4793
  EventEmitter.dispatch(["test:skip", { result: testResult }]);
4666
4794
  return;
@@ -4702,21 +4830,27 @@ class TaskRunner {
4702
4830
  EventEmitter.dispatch(["task:end", { result: taskResult }]);
4703
4831
  this.#projectService.closeFile(task.filePath);
4704
4832
  }
4705
- async #run(task, taskResult, cancellationToken) {
4706
- if (!existsSync(task.filePath)) {
4707
- this.#onDiagnostics([Diagnostic.error(`Test file '${task.filePath}' does not exist.`)], taskResult);
4708
- return;
4709
- }
4710
- let languageService = this.#projectService.getLanguageService(task.filePath);
4833
+ async #resolveTaskFacts(task, taskResult, runMode = RunMode.Normal) {
4834
+ const languageService = this.#projectService.getLanguageService(task.filePath);
4711
4835
  const syntacticDiagnostics = languageService?.getSyntacticDiagnostics(task.filePath);
4712
4836
  if (syntacticDiagnostics != null && syntacticDiagnostics.length > 0) {
4713
4837
  this.#onDiagnostics(Diagnostic.fromDiagnostics(syntacticDiagnostics), taskResult);
4714
4838
  return;
4715
4839
  }
4716
- let semanticDiagnostics = languageService?.getSemanticDiagnostics(task.filePath);
4717
- let program = languageService?.getProgram();
4718
- let sourceFile = program?.getSourceFile(task.filePath);
4719
- if (sourceFile?.text.startsWith("// @tstyche-template")) {
4840
+ const semanticDiagnostics = languageService?.getSemanticDiagnostics(task.filePath);
4841
+ const program = languageService?.getProgram();
4842
+ const typeChecker = program?.getTypeChecker();
4843
+ const sourceFile = program?.getSourceFile(task.filePath);
4844
+ if (!sourceFile) {
4845
+ return;
4846
+ }
4847
+ const testTree = this.#collectService.createTestTree(sourceFile, semanticDiagnostics);
4848
+ const directiveRanges = testTree.getDirectiveRanges(this.#compiler);
4849
+ const inlineConfig = await Directive.getInlineConfig(directiveRanges);
4850
+ if (inlineConfig?.if?.target != null && !Version.isIncluded(this.#compiler.version, inlineConfig.if.target)) {
4851
+ runMode |= RunMode.Skip;
4852
+ }
4853
+ if (inlineConfig?.template) {
4720
4854
  if (semanticDiagnostics != null && semanticDiagnostics.length > 0) {
4721
4855
  this.#onDiagnostics(Diagnostic.fromDiagnostics(semanticDiagnostics), taskResult);
4722
4856
  return;
@@ -4728,41 +4862,39 @@ class TaskRunner {
4728
4862
  return;
4729
4863
  }
4730
4864
  this.#projectService.openFile(task.filePath, testText, this.#resolvedConfig.rootPath);
4731
- languageService = this.#projectService.getLanguageService(task.filePath);
4732
- const syntacticDiagnostics = languageService?.getSyntacticDiagnostics(task.filePath);
4733
- if (syntacticDiagnostics != null && syntacticDiagnostics.length > 0) {
4734
- this.#onDiagnostics(Diagnostic.fromDiagnostics(syntacticDiagnostics), taskResult);
4735
- return;
4736
- }
4737
- semanticDiagnostics = languageService?.getSemanticDiagnostics(task.filePath);
4738
- program = languageService?.getProgram();
4739
- sourceFile = program?.getSourceFile(task.filePath);
4865
+ return this.#resolveTaskFacts(task, taskResult, runMode);
4740
4866
  }
4741
- if (!sourceFile) {
4867
+ return { runMode, testTree, typeChecker };
4868
+ }
4869
+ async #run(task, taskResult, cancellationToken) {
4870
+ if (!existsSync(task.filePath)) {
4871
+ this.#onDiagnostics([Diagnostic.error(`Test file '${task.filePath}' does not exist.`)], taskResult);
4742
4872
  return;
4743
4873
  }
4744
- const testTree = this.#collectService.createTestTree(sourceFile, semanticDiagnostics);
4745
- if (testTree.diagnostics.size > 0) {
4746
- this.#onDiagnostics(Diagnostic.fromDiagnostics([...testTree.diagnostics]), taskResult);
4874
+ const facts = await this.#resolveTaskFacts(task, taskResult);
4875
+ if (!facts) {
4876
+ return;
4877
+ }
4878
+ if (facts.testTree.diagnostics.size > 0) {
4879
+ this.#onDiagnostics(Diagnostic.fromDiagnostics([...facts.testTree.diagnostics]), taskResult);
4747
4880
  return;
4748
4881
  }
4749
- const typeChecker = program?.getTypeChecker();
4750
4882
  const onTaskDiagnostics = (diagnostics) => {
4751
4883
  this.#onDiagnostics(diagnostics, taskResult);
4752
4884
  };
4753
- const testTreeWalker = new TestTreeWalker(this.#compiler, typeChecker, this.#resolvedConfig, onTaskDiagnostics, {
4885
+ const testTreeWalker = new TestTreeWalker(this.#compiler, facts.typeChecker, this.#resolvedConfig, onTaskDiagnostics, {
4754
4886
  cancellationToken,
4755
- hasOnly: testTree.hasOnly,
4887
+ hasOnly: facts.testTree.hasOnly,
4756
4888
  position: task.position,
4757
4889
  });
4758
- testTreeWalker.visit(testTree.children, RunMode.Normal, undefined);
4890
+ await testTreeWalker.visit(facts.testTree.children, facts.runMode, undefined);
4759
4891
  }
4760
4892
  }
4761
4893
 
4762
4894
  class Runner {
4763
4895
  #eventEmitter = new EventEmitter();
4764
4896
  #resolvedConfig;
4765
- static version = "4.0.0-rc.0";
4897
+ static version = "4.0.0-rc.1";
4766
4898
  constructor(resolvedConfig) {
4767
4899
  this.#resolvedConfig = resolvedConfig;
4768
4900
  }
@@ -4962,4 +5094,4 @@ class Cli {
4962
5094
  }
4963
5095
  }
4964
5096
 
4965
- export { AssertionNode, BaseReporter, CancellationHandler, CancellationReason, CancellationToken, Cli, CollectService, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, EventEmitter, ExitCodeHandler, ExpectResult, ExpectService, FileWatcher, InputService, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, PluginService, ProjectResult, ProjectService, Reject, Result, ResultCount, ResultHandler, ResultStatus, ResultTiming, Runner, Scribbler, Select, SelectDiagnosticText, SetupReporter, SourceFile, Store, SummaryReporter, TargetResult, Task, TaskResult, TestResult, TestTree, TestTreeNode, TestTreeNodeBrand, TestTreeNodeFlags, Text, Version, WatchReporter, WatchService, Watcher, WhenNode, WhenService, addsPackageText, argumentIsProvided, argumentOrTypeArgumentIsProvided, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, environmentOptions, fileViewText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, nodeBelongsToArgumentList, summaryText, taskStatusText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
5097
+ export { AssertionNode, BaseReporter, CancellationHandler, CancellationReason, CancellationToken, Cli, CollectService, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, Directive, EventEmitter, ExitCodeHandler, ExpectResult, ExpectService, FileWatcher, InputService, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, PluginService, ProjectResult, ProjectService, Reject, Result, ResultCount, ResultHandler, ResultStatus, ResultTiming, Runner, Scribbler, Select, SelectDiagnosticText, SetupReporter, SourceFile, Store, SummaryReporter, TargetResult, Task, TaskResult, TestResult, TestTree, TestTreeNode, TestTreeNodeBrand, TestTreeNodeFlags, Text, Version, WatchReporter, WatchService, Watcher, WhenNode, WhenService, addsPackageText, argumentIsProvided, argumentOrTypeArgumentIsProvided, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, environmentOptions, fileViewText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, nodeBelongsToArgumentList, summaryText, taskStatusText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tstyche",
3
- "version": "4.0.0-rc.0",
3
+ "version": "4.0.0-rc.1",
4
4
  "description": "The Essential Type Testing Tool.",
5
5
  "keywords": [
6
6
  "typescript",