tstyche 4.0.0 → 4.0.2

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,153 +20,37 @@ declare class Cli {
20
20
  run(commandLine: Array<string>, cancellationToken?: CancellationToken): Promise<void>;
21
21
  }
22
22
 
23
- declare enum OptionBrand {
24
- String = "string",
25
- Number = "number",
26
- Boolean = "boolean",
27
- BareTrue = "bareTrue",// a boolean option that does not take a value and when specified is interpreted as 'true'
28
- List = "list"
29
- }
30
-
31
- declare class ConfigDiagnosticText {
32
- static expected(element: string): string;
33
- static expectsListItemType(optionName: string, optionBrand: OptionBrand): string;
34
- static expectsValue(optionName: string): string;
35
- static fileDoesNotExist(filePath: string): string;
36
- static inspectSupportedVersions(): string;
37
- static moduleWasNotFound(specifier: string): string;
38
- static rangeIsNotValid(value: string): string;
39
- static rangeUsage(): Array<string>;
40
- static requiresValueType(optionName: string, optionBrand: OptionBrand): string;
41
- static seen(element: string): string;
42
- static testFileMatchCannotStartWith(segment: string): Array<string>;
43
- static unexpected(element: string): string;
44
- static unknownOption(optionName: string): string;
45
- static usage(optionName: string, optionBrand: OptionBrand): Array<string>;
46
- static versionIsNotSupported(value: string): string;
47
- static watchCannotBeEnabled(): string;
48
- }
49
-
50
- /**
51
- * Options passed through the command line.
52
- */
53
23
  interface CommandLineOptions {
54
- /**
55
- * The path to a TSTyche configuration file.
56
- */
57
24
  config?: string;
58
- /**
59
- * Stop running tests after the first failed assertion.
60
- */
61
25
  failFast?: boolean;
62
- /**
63
- * Fetch the specified versions of the 'typescript' package and exit.
64
- */
65
26
  fetch?: boolean;
66
- /**
67
- * Print the list of command line options with brief descriptions and exit.
68
- */
69
27
  help?: boolean;
70
- /**
71
- * Print the list of supported versions of the 'typescript' package and exit.
72
- */
73
28
  list?: boolean;
74
- /**
75
- * Print the list of the selected test files and exit.
76
- */
77
29
  listFiles?: boolean;
78
- /**
79
- * Only run tests with matching name.
80
- */
81
30
  only?: string;
82
- /**
83
- * The list of plugins to use.
84
- */
85
31
  plugins?: Array<string>;
86
- /**
87
- * Remove all installed versions of the 'typescript' package and exit.
88
- */
89
32
  prune?: boolean;
90
- /**
91
- * The list of reporters to use.
92
- */
93
33
  reporters?: Array<string>;
94
- /**
95
- * Print the resolved configuration and exit.
96
- */
97
34
  showConfig?: boolean;
98
- /**
99
- * Skip tests with matching name.
100
- */
101
35
  skip?: string;
102
- /**
103
- * The list of TypeScript versions to be tested on.
104
- */
105
36
  target?: Array<string>;
106
- /**
107
- * The look up strategy to be used to find the TSConfig file.
108
- */
109
37
  tsconfig?: string;
110
- /**
111
- * Fetch the 'typescript' package metadata from the registry and exit.
112
- */
113
38
  update?: boolean;
114
- /**
115
- * Print the version number and exit.
116
- */
117
39
  version?: boolean;
118
- /**
119
- * Watch for changes and rerun related test files.
120
- */
121
40
  watch?: boolean;
122
41
  }
123
-
124
- /**
125
- * Options loaded from the configuration file.
126
- */
127
42
  interface ConfigFileOptions {
128
- /**
129
- * Enable type error reporting for source files.
130
- */
131
43
  checkSourceFiles?: boolean;
132
- /**
133
- * Stop running tests after the first failed assertion.
134
- */
135
44
  failFast?: boolean;
136
- /**
137
- * The list of plugins to use.
138
- */
139
45
  plugins?: Array<string>;
140
- /**
141
- * Reject the 'any' type passed as an argument to the 'expect()' function or a matcher.
142
- */
143
46
  rejectAnyType?: boolean;
144
- /**
145
- * Reject the 'never' type passed as an argument to the 'expect()' function or a matcher.
146
- */
147
47
  rejectNeverType?: boolean;
148
- /**
149
- * The list of reporters to use.
150
- */
151
48
  reporters?: Array<string>;
152
- /**
153
- * The path to a directory containing files of a test project.
154
- */
155
49
  rootPath?: string;
156
- /**
157
- * The list of TypeScript versions to be tested on.
158
- */
159
50
  target?: Array<string>;
160
- /**
161
- * The list of glob patterns matching the test files.
162
- */
163
51
  testFileMatch?: Array<string>;
164
- /**
165
- * The look up strategy to be used to find the TSConfig file.
166
- */
167
52
  tsconfig?: string;
168
53
  }
169
-
170
54
  interface InlineConfig {
171
55
  if?: {
172
56
  target?: Array<string>;
@@ -174,13 +58,7 @@ interface InlineConfig {
174
58
  template?: boolean;
175
59
  }
176
60
  interface ResolvedConfig extends Omit<CommandLineOptions, "config" | keyof ConfigFileOptions>, Required<ConfigFileOptions> {
177
- /**
178
- * The path to a TSTyche configuration file.
179
- */
180
61
  configFilePath: string;
181
- /**
182
- * Only run test files with matching path.
183
- */
184
62
  pathMatch: Array<string>;
185
63
  }
186
64
 
@@ -203,6 +81,33 @@ declare class Config {
203
81
  static resolveConfigFilePath(filePath?: string): string;
204
82
  }
205
83
 
84
+ declare enum OptionBrand {
85
+ String = "string",
86
+ Number = "number",
87
+ Boolean = "boolean",
88
+ BareTrue = "bareTrue",
89
+ List = "list"
90
+ }
91
+
92
+ declare class ConfigDiagnosticText {
93
+ static expected(element: string): string;
94
+ static expectsListItemType(optionName: string, optionBrand: OptionBrand): string;
95
+ static expectsValue(optionName: string): string;
96
+ static fileDoesNotExist(filePath: string): string;
97
+ static inspectSupportedVersions(): string;
98
+ static moduleWasNotFound(specifier: string): string;
99
+ static rangeIsNotValid(value: string): string;
100
+ static rangeUsage(): Array<string>;
101
+ static requiresValueType(optionName: string, optionBrand: OptionBrand): string;
102
+ static seen(element: string): string;
103
+ static testFileMatchCannotStartWith(segment: string): Array<string>;
104
+ static unexpected(element: string): string;
105
+ static unknownOption(optionName: string): string;
106
+ static usage(optionName: string, optionBrand: OptionBrand): Array<string>;
107
+ static versionIsNotSupported(value: string): string;
108
+ static watchCannotBeEnabled(): string;
109
+ }
110
+
206
111
  interface TextRange {
207
112
  start: number;
208
113
  end: number;
@@ -222,6 +127,15 @@ declare class Directive {
222
127
  static getInlineConfig(ranges: DirectiveRanges | undefined): Promise<InlineConfig | undefined>;
223
128
  }
224
129
 
130
+ declare const defaultOptions: Required<ConfigFileOptions>;
131
+
132
+ declare enum OptionGroup {
133
+ CommandLine = 2,
134
+ ConfigFile = 4,
135
+ InlineConditions = 8,
136
+ ResolvedConfig = 6
137
+ }
138
+
225
139
  declare enum DiagnosticCategory {
226
140
  Error = "error",
227
141
  Warning = "warning"
@@ -263,7 +177,7 @@ declare class Diagnostic {
263
177
  }): this;
264
178
  static error(text: string | Array<string>, origin?: DiagnosticOrigin): Diagnostic;
265
179
  extendWith(text: string | Array<string>, origin?: DiagnosticOrigin): Diagnostic;
266
- static fromDiagnostics(diagnostics: Array<ts.Diagnostic>): Array<Diagnostic>;
180
+ static fromDiagnostics(diagnostics: Array<ts.Diagnostic>, sourceFile?: ts.SourceFile): Array<Diagnostic>;
267
181
  static warning(text: string | Array<string>, origin?: DiagnosticOrigin): Diagnostic;
268
182
  }
269
183
 
@@ -274,13 +188,6 @@ declare function isDiagnosticWithLocation(diagnostic: ts.Diagnostic): diagnostic
274
188
 
275
189
  type DiagnosticsHandler<T extends Diagnostic | Array<Diagnostic> = Diagnostic> = (this: void, diagnostics: T) => void;
276
190
 
277
- declare enum OptionGroup {
278
- CommandLine = 2,
279
- ConfigFile = 4,
280
- InlineConditions = 8,
281
- ResolvedConfig = 6
282
- }
283
-
284
191
  interface BaseOptionDefinition {
285
192
  brand: OptionBrand;
286
193
  description: string;
@@ -306,8 +213,6 @@ declare class Options {
306
213
  static validate(optionName: string, optionValue: string, optionBrand: OptionBrand, onDiagnostics: DiagnosticsHandler, origin?: DiagnosticOrigin): Promise<void>;
307
214
  }
308
215
 
309
- declare const defaultOptions: Required<ConfigFileOptions>;
310
-
311
216
  declare enum TestTreeNodeBrand {
312
217
  Describe = "describe",
313
218
  Test = "test",
@@ -386,33 +291,12 @@ declare function argumentIsProvided<T>(argumentNameText: string, node: T, enclos
386
291
  declare function argumentOrTypeArgumentIsProvided<T>(argumentNameText: string, typeArgumentNameText: string, node: T, enclosingNode: ts.Node, onDiagnostics: DiagnosticsHandler<Array<Diagnostic>>): node is NonNullable<T>;
387
292
 
388
293
  interface EnvironmentOptions {
389
- /**
390
- * Is `true` if the process is running in continuous integration environment.
391
- */
392
294
  isCi: boolean;
393
- /**
394
- * Specifies whether color should be disabled in the output.
395
- */
396
295
  noColor: boolean;
397
- /**
398
- * Specifies whether interactive elements should be disabled in the output.
399
- */
400
296
  noInteractive: boolean;
401
- /**
402
- * The base URL of the 'npm' registry to use.
403
- */
404
297
  npmRegistry: string;
405
- /**
406
- * The directory where to store the 'typescript' packages.
407
- */
408
298
  storePath: string;
409
- /**
410
- * The number of seconds to wait before giving up stale operations.
411
- */
412
299
  timeout: number;
413
- /**
414
- * The specifier of the TypeScript module.
415
- */
416
300
  typescriptModule: string | undefined;
417
301
  }
418
302
 
@@ -752,8 +636,6 @@ interface CodeFrameOptions {
752
636
 
753
637
  declare function diagnosticText(diagnostic: Diagnostic, codeFrameOptions?: CodeFrameOptions): ScribblerJsx.Element;
754
638
 
755
- declare function taskStatusText(status: TaskResultStatus, task: Task): ScribblerJsx.Element;
756
-
757
639
  declare function fileViewText(lines: Array<ScribblerJsx.Element>, addEmptyFinalLine: boolean): ScribblerJsx.Element;
758
640
 
759
641
  declare function formattedText(input: string | Array<string> | Record<string, unknown>): ScribblerJsx.Element;
@@ -777,6 +659,8 @@ declare function summaryText({ duration, expectCount, fileCount, targetCount, te
777
659
  testCount: ResultCount;
778
660
  }): ScribblerJsx.Element;
779
661
 
662
+ declare function taskStatusText(status: TaskResultStatus, task: Task): ScribblerJsx.Element;
663
+
780
664
  declare function testNameText(status: "fail" | "pass" | "skip" | "todo", name: string, indent?: number): ScribblerJsx.Element;
781
665
 
782
666
  declare function usesCompilerText(compilerVersion: string, projectConfigFilePath: string | undefined, options?: {
@@ -799,17 +683,8 @@ interface SelectHookContext {
799
683
  resolvedConfig: ResolvedConfig;
800
684
  }
801
685
  interface Plugin {
802
- /**
803
- * The name of this plugin.
804
- */
805
686
  name: string;
806
- /**
807
- * Is called after configuration is resolved and allows to modify it.
808
- */
809
687
  config?: (resolvedConfig: ResolvedConfig) => ResolvedConfig | Promise<ResolvedConfig>;
810
- /**
811
- * Is called after test files are selected and allows to modify the list.
812
- */
813
688
  select?: (this: SelectHookContext, testFiles: Array<string>) => Array<string | URL> | Promise<Array<string | URL>>;
814
689
  }
815
690
 
@@ -920,4 +795,4 @@ declare class WhenService {
920
795
  }
921
796
 
922
797
  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 };
923
- 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 };
798
+ 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, TextRange, TypeChecker, WatchHandler, WatcherOptions };
package/build/tstyche.js CHANGED
@@ -8,76 +8,6 @@ import { createRequire } from 'node:module';
8
8
  import vm from 'node:vm';
9
9
  import streamConsumers from 'node:stream/consumers';
10
10
 
11
- class ConfigDiagnosticText {
12
- static expected(element) {
13
- return `Expected ${element}.`;
14
- }
15
- static expectsListItemType(optionName, optionBrand) {
16
- return `Item of the '${optionName}' list must be of type ${optionBrand}.`;
17
- }
18
- static expectsValue(optionName) {
19
- return `Option '${optionName}' expects a value.`;
20
- }
21
- static fileDoesNotExist(filePath) {
22
- return `The specified path '${filePath}' does not exist.`;
23
- }
24
- static inspectSupportedVersions() {
25
- return "Use the '--list' command line option to inspect the list of supported versions.";
26
- }
27
- static moduleWasNotFound(specifier) {
28
- return `The specified module '${specifier}' was not found.`;
29
- }
30
- static rangeIsNotValid(value) {
31
- return `The specified range '${value}' is not valid.`;
32
- }
33
- static rangeUsage() {
34
- return [
35
- "A range must be specified using an operator and a minor version.",
36
- "To set an upper bound, the intersection of two ranges can be used.",
37
- "Examples: '>=5.5', '>=5.0 <5.3'.",
38
- ];
39
- }
40
- static requiresValueType(optionName, optionBrand) {
41
- return `Option '${optionName}' requires a value of type ${optionBrand}.`;
42
- }
43
- static seen(element) {
44
- return `The ${element} was seen here.`;
45
- }
46
- static testFileMatchCannotStartWith(segment) {
47
- return [
48
- `A test file match pattern cannot start with '${segment}'.`,
49
- "The test files are only collected within the 'rootPath' directory.",
50
- ];
51
- }
52
- static unexpected(element) {
53
- return `Unexpected ${element}.`;
54
- }
55
- static unknownOption(optionName) {
56
- return `Unknown option '${optionName}'.`;
57
- }
58
- static usage(optionName, optionBrand) {
59
- switch (optionName.startsWith("--") ? optionName.slice(2) : optionName) {
60
- case "target": {
61
- const text = [];
62
- if (optionName.startsWith("--")) {
63
- 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''.");
64
- }
65
- return text;
66
- }
67
- }
68
- return [ConfigDiagnosticText.requiresValueType(optionName, optionBrand)];
69
- }
70
- static versionIsNotSupported(value) {
71
- if (value === "current") {
72
- return "Cannot use 'current' as a target. Failed to resolve the installed TypeScript module.";
73
- }
74
- return `TypeScript version '${value}' is not supported.`;
75
- }
76
- static watchCannotBeEnabled() {
77
- return "Watch mode cannot be enabled in continuous integration environment.";
78
- }
79
- }
80
-
81
11
  var DiagnosticCategory;
82
12
  (function (DiagnosticCategory) {
83
13
  DiagnosticCategory["Error"] = "error";
@@ -157,16 +87,16 @@ class Diagnostic {
157
87
  extendWith(text, origin) {
158
88
  return new Diagnostic([this.text, text].flat(), this.category, origin ?? this.origin);
159
89
  }
160
- static fromDiagnostics(diagnostics) {
90
+ static fromDiagnostics(diagnostics, sourceFile) {
161
91
  return diagnostics.map((diagnostic) => {
162
92
  const code = `ts(${diagnostic.code})`;
163
93
  let origin;
164
- if (diagnostic.file != null && diagnostic.start != null && diagnostic.length != null) {
165
- origin = new DiagnosticOrigin(diagnostic.start, diagnostic.start + diagnostic.length, diagnostic.file);
94
+ if (isDiagnosticWithLocation(diagnostic)) {
95
+ origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), sourceFile ?? diagnostic.file);
166
96
  }
167
97
  let related;
168
98
  if (diagnostic.relatedInformation != null) {
169
- related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
99
+ related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation, sourceFile);
170
100
  }
171
101
  const text = getDiagnosticMessageText(diagnostic);
172
102
  return new Diagnostic(text, DiagnosticCategory.Error, origin).add({ code, related });
@@ -282,6 +212,76 @@ class Path {
282
212
  }
283
213
  }
284
214
 
215
+ class ConfigDiagnosticText {
216
+ static expected(element) {
217
+ return `Expected ${element}.`;
218
+ }
219
+ static expectsListItemType(optionName, optionBrand) {
220
+ return `Item of the '${optionName}' list must be of type ${optionBrand}.`;
221
+ }
222
+ static expectsValue(optionName) {
223
+ return `Option '${optionName}' expects a value.`;
224
+ }
225
+ static fileDoesNotExist(filePath) {
226
+ return `The specified path '${filePath}' does not exist.`;
227
+ }
228
+ static inspectSupportedVersions() {
229
+ return "Use the '--list' command line option to inspect the list of supported versions.";
230
+ }
231
+ static moduleWasNotFound(specifier) {
232
+ return `The specified module '${specifier}' was not found.`;
233
+ }
234
+ static rangeIsNotValid(value) {
235
+ return `The specified range '${value}' is not valid.`;
236
+ }
237
+ static rangeUsage() {
238
+ return [
239
+ "A range must be specified using an operator and a minor version.",
240
+ "To set an upper bound, the intersection of two ranges can be used.",
241
+ "Examples: '>=5.5', '>=5.0 <5.3'.",
242
+ ];
243
+ }
244
+ static requiresValueType(optionName, optionBrand) {
245
+ return `Option '${optionName}' requires a value of type ${optionBrand}.`;
246
+ }
247
+ static seen(element) {
248
+ return `The ${element} was seen here.`;
249
+ }
250
+ static testFileMatchCannotStartWith(segment) {
251
+ return [
252
+ `A test file match pattern cannot start with '${segment}'.`,
253
+ "The test files are only collected within the 'rootPath' directory.",
254
+ ];
255
+ }
256
+ static unexpected(element) {
257
+ return `Unexpected ${element}.`;
258
+ }
259
+ static unknownOption(optionName) {
260
+ return `Unknown option '${optionName}'.`;
261
+ }
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
+ static versionIsNotSupported(value) {
275
+ if (value === "current") {
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
+ }
280
+ static watchCannotBeEnabled() {
281
+ return "Watch mode cannot be enabled in continuous integration environment.";
282
+ }
283
+ }
284
+
285
285
  var OptionBrand;
286
286
  (function (OptionBrand) {
287
287
  OptionBrand["String"] = "string";
@@ -513,7 +513,7 @@ class LockService {
513
513
  }
514
514
  return isLocked;
515
515
  }
516
- async #sleep(delay) {
516
+ #sleep(delay) {
517
517
  return new Promise((resolve) => setTimeout(resolve, delay));
518
518
  }
519
519
  }
@@ -1392,6 +1392,19 @@ class ConfigParser {
1392
1392
  }
1393
1393
  }
1394
1394
 
1395
+ const defaultOptions = {
1396
+ checkSourceFiles: true,
1397
+ failFast: false,
1398
+ plugins: [],
1399
+ rejectAnyType: true,
1400
+ rejectNeverType: true,
1401
+ reporters: ["list", "summary"],
1402
+ rootPath: Path.resolve("./"),
1403
+ target: environmentOptions.typescriptModule != null ? ["current"] : ["latest"],
1404
+ testFileMatch: ["**/*.tst.*", "**/__typetests__/*.test.*", "**/typetests/*.test.*"],
1405
+ tsconfig: "findup",
1406
+ };
1407
+
1395
1408
  class JsonNode {
1396
1409
  origin;
1397
1410
  text;
@@ -1525,19 +1538,6 @@ class JsonScanner {
1525
1538
  }
1526
1539
  }
1527
1540
 
1528
- const defaultOptions = {
1529
- checkSourceFiles: true,
1530
- failFast: false,
1531
- plugins: [],
1532
- rejectAnyType: true,
1533
- rejectNeverType: true,
1534
- reporters: ["list", "summary"],
1535
- rootPath: Path.resolve("./"),
1536
- target: environmentOptions.typescriptModule != null ? ["current"] : ["latest"],
1537
- testFileMatch: ["**/*.tst.*", "**/__typetests__/*.test.*", "**/typetests/*.test.*"],
1538
- tsconfig: "findup",
1539
- };
1540
-
1541
1541
  class Config {
1542
1542
  static #onDiagnostics(diagnostic) {
1543
1543
  EventEmitter.dispatch(["config:error", { diagnostics: [diagnostic] }]);
@@ -1589,20 +1589,19 @@ class Config {
1589
1589
  }
1590
1590
 
1591
1591
  class DirectiveDiagnosticText {
1592
- static doesNotTakeArgument(directiveName) {
1593
- return `Directive '${directiveName}' does not take an argument.`;
1592
+ static doesNotTakeArgument() {
1593
+ return "Directive does not take an argument.";
1594
1594
  }
1595
1595
  static isNotSupported(directive) {
1596
1596
  return `The '${directive}' directive is not supported.`;
1597
1597
  }
1598
- static requiresArgument(directiveName) {
1599
- return `Directive '${directiveName}' requires an argument.`;
1598
+ static requiresArgument() {
1599
+ return "Directive requires an argument.";
1600
1600
  }
1601
1601
  }
1602
1602
 
1603
1603
  class Directive {
1604
- static #commentSeparatorRegex = /--+/;
1605
- static #directiveRegex = /^(\/\/\s*@tstyche)(\s*|-)?(\S*)?(\s*)?(.*)?/i;
1604
+ static #directiveRegex = /^(\/\/ *@tstyche)( *|-)?(\S*)?( *)?(.*)?/i;
1606
1605
  static getDirectiveRanges(compiler, sourceFile, position = 0) {
1607
1606
  const comments = compiler.getLeadingCommentRanges(sourceFile.text, position);
1608
1607
  if (!comments || comments.length === 0) {
@@ -1631,28 +1630,28 @@ class Directive {
1631
1630
  return inlineConfig;
1632
1631
  }
1633
1632
  static #getRange(sourceFile, comment) {
1634
- const [text] = sourceFile.text.substring(comment.pos, comment.end).split(Directive.#commentSeparatorRegex);
1635
- const found = text?.match(Directive.#directiveRegex);
1636
- const namespaceText = found?.[1];
1633
+ const [text] = sourceFile.text.substring(comment.pos, comment.end).split(/--+/);
1634
+ const match = text?.match(Directive.#directiveRegex);
1635
+ const namespaceText = match?.[1];
1637
1636
  if (!namespaceText) {
1638
1637
  return;
1639
1638
  }
1640
- const ranges = {
1639
+ const range = {
1641
1640
  namespace: { start: comment.pos, end: comment.pos + namespaceText.length, text: namespaceText },
1642
1641
  };
1643
- const directiveSeparatorText = found?.[2];
1644
- const directiveText = found?.[3];
1645
- if (directiveText != null && directiveText.length > 0) {
1646
- const start = ranges.namespace.end + (directiveSeparatorText?.length ?? 0);
1647
- ranges.directive = { start, end: start + directiveText.length, text: directiveText };
1648
- }
1649
- const argumentSeparatorText = found?.[4];
1650
- const argumentText = found?.[5]?.trimEnd();
1651
- if (ranges.directive != null && argumentText != null && argumentText.length > 0) {
1652
- const start = ranges.directive.end + (argumentSeparatorText?.length ?? 0);
1653
- ranges.argument = { start, end: start + argumentText.length, text: argumentText };
1642
+ const directiveSeparatorText = match?.[2];
1643
+ const directiveText = match?.[3];
1644
+ if (typeof directiveText === "string" && typeof directiveSeparatorText === "string") {
1645
+ const start = range.namespace.end + directiveSeparatorText.length;
1646
+ range.directive = { start, end: start + directiveText.length, text: directiveText };
1647
+ const argumentSeparatorText = match?.[4];
1648
+ const argumentText = match?.[5]?.trimEnd();
1649
+ if (typeof argumentSeparatorText === "string" && typeof argumentText === "string") {
1650
+ const start = range.directive.end + argumentSeparatorText.length;
1651
+ range.argument = { start, end: start + argumentText.length, text: argumentText };
1652
+ }
1654
1653
  }
1655
- return ranges;
1654
+ return range;
1656
1655
  }
1657
1656
  static #onDiagnostics(diagnostic) {
1658
1657
  EventEmitter.dispatch(["directive:error", { diagnostics: [diagnostic] }]);
@@ -1662,8 +1661,8 @@ class Directive {
1662
1661
  case "if":
1663
1662
  {
1664
1663
  if (!ranges.argument?.text) {
1665
- const text = DirectiveDiagnosticText.requiresArgument(ranges.directive.text);
1666
- const origin = new DiagnosticOrigin(ranges.directive.start, ranges.directive.end, sourceFile);
1664
+ const text = DirectiveDiagnosticText.requiresArgument();
1665
+ const origin = new DiagnosticOrigin(ranges.namespace.start, ranges.directive.end, sourceFile);
1667
1666
  Directive.#onDiagnostics(Diagnostic.error(text, origin));
1668
1667
  return;
1669
1668
  }
@@ -1673,8 +1672,8 @@ class Directive {
1673
1672
  return;
1674
1673
  case "template":
1675
1674
  if (ranges.argument?.text != null) {
1676
- const text = DirectiveDiagnosticText.doesNotTakeArgument(ranges.directive.text);
1677
- const origin = new DiagnosticOrigin(ranges.directive.start, ranges.directive.end, sourceFile);
1675
+ const text = DirectiveDiagnosticText.doesNotTakeArgument();
1676
+ const origin = new DiagnosticOrigin(ranges.argument.start, ranges.argument.end, sourceFile);
1678
1677
  Directive.#onDiagnostics(Diagnostic.error(text, origin));
1679
1678
  }
1680
1679
  inlineConfig.template = true;
@@ -2131,7 +2130,9 @@ function describeNameText(name, indent = 0) {
2131
2130
  function BreadcrumbsText({ ancestor }) {
2132
2131
  const text = [];
2133
2132
  while ("name" in ancestor) {
2134
- text.push(ancestor.name);
2133
+ if (ancestor.name !== "") {
2134
+ text.push(ancestor.name);
2135
+ }
2135
2136
  ancestor = ancestor.parent;
2136
2137
  }
2137
2138
  text.push("");
@@ -2215,33 +2216,6 @@ function diagnosticText(diagnostic, codeFrameOptions = {}) {
2215
2216
  return (jsx(Text, { children: [prefix, jsx(DiagnosticText, { codeFrameOptions: codeFrameOptions, diagnostic: diagnostic })] }));
2216
2217
  }
2217
2218
 
2218
- function FileNameText({ filePath }) {
2219
- const relativePath = Path.relative("", filePath);
2220
- const lastPathSeparator = relativePath.lastIndexOf("/");
2221
- const directoryNameText = relativePath.slice(0, lastPathSeparator + 1);
2222
- const fileNameText = relativePath.slice(lastPathSeparator + 1);
2223
- return (jsx(Text, { children: [jsx(Text, { color: Color.Gray, children: directoryNameText }), fileNameText] }));
2224
- }
2225
- function taskStatusText(status, task) {
2226
- let statusColor;
2227
- let statusText;
2228
- switch (status) {
2229
- case ResultStatus.Runs:
2230
- statusColor = Color.Yellow;
2231
- statusText = "runs";
2232
- break;
2233
- case ResultStatus.Passed:
2234
- statusColor = Color.Green;
2235
- statusText = "pass";
2236
- break;
2237
- case ResultStatus.Failed:
2238
- statusColor = Color.Red;
2239
- statusText = "fail";
2240
- break;
2241
- }
2242
- return (jsx(Line, { children: [jsx(Text, { color: statusColor, children: statusText }), " ", jsx(FileNameText, { filePath: task.filePath })] }));
2243
- }
2244
-
2245
2219
  function fileViewText(lines, addEmptyFinalLine) {
2246
2220
  return (jsx(Text, { children: [[...lines], addEmptyFinalLine ? jsx(Line, {}) : undefined] }));
2247
2221
  }
@@ -2361,6 +2335,33 @@ function summaryText({ duration, expectCount, fileCount, targetCount, testCount,
2361
2335
  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 }) })] }));
2362
2336
  }
2363
2337
 
2338
+ function FileNameText({ filePath }) {
2339
+ const relativePath = Path.relative("", filePath);
2340
+ const lastPathSeparator = relativePath.lastIndexOf("/");
2341
+ const directoryNameText = relativePath.slice(0, lastPathSeparator + 1);
2342
+ const fileNameText = relativePath.slice(lastPathSeparator + 1);
2343
+ return (jsx(Text, { children: [jsx(Text, { color: Color.Gray, children: directoryNameText }), fileNameText] }));
2344
+ }
2345
+ function taskStatusText(status, task) {
2346
+ let statusColor;
2347
+ let statusText;
2348
+ switch (status) {
2349
+ case ResultStatus.Runs:
2350
+ statusColor = Color.Yellow;
2351
+ statusText = "runs";
2352
+ break;
2353
+ case ResultStatus.Passed:
2354
+ statusColor = Color.Green;
2355
+ statusText = "pass";
2356
+ break;
2357
+ case ResultStatus.Failed:
2358
+ statusColor = Color.Red;
2359
+ statusText = "fail";
2360
+ break;
2361
+ }
2362
+ return (jsx(Line, { children: [jsx(Text, { color: statusColor, children: statusText }), " ", jsx(FileNameText, { filePath: task.filePath })] }));
2363
+ }
2364
+
2364
2365
  function StatusText({ status }) {
2365
2366
  switch (status) {
2366
2367
  case "fail":
@@ -2646,6 +2647,14 @@ class Task {
2646
2647
  }
2647
2648
  }
2648
2649
 
2650
+ var CancellationReason;
2651
+ (function (CancellationReason) {
2652
+ CancellationReason["ConfigChange"] = "configChange";
2653
+ CancellationReason["ConfigError"] = "configError";
2654
+ CancellationReason["FailFast"] = "failFast";
2655
+ CancellationReason["WatchClose"] = "watchClose";
2656
+ })(CancellationReason || (CancellationReason = {}));
2657
+
2649
2658
  class CancellationToken {
2650
2659
  #isCancelled = false;
2651
2660
  #reason;
@@ -2669,14 +2678,6 @@ class CancellationToken {
2669
2678
  }
2670
2679
  }
2671
2680
 
2672
- var CancellationReason;
2673
- (function (CancellationReason) {
2674
- CancellationReason["ConfigChange"] = "configChange";
2675
- CancellationReason["ConfigError"] = "configError";
2676
- CancellationReason["FailFast"] = "failFast";
2677
- CancellationReason["WatchClose"] = "watchClose";
2678
- })(CancellationReason || (CancellationReason = {}));
2679
-
2680
2681
  class Watcher {
2681
2682
  #onChanged;
2682
2683
  #onRemoved;
@@ -3066,6 +3067,7 @@ function nodeIsChildOfExpressionStatement(compiler, node) {
3066
3067
 
3067
3068
  class AbilityLayer {
3068
3069
  #compiler;
3070
+ #expectErrorRegex = /^( *)(\/\/ *@ts-expect-error)(!?)(:? *)(.*)?$/gim;
3069
3071
  #filePath = "";
3070
3072
  #nodes = [];
3071
3073
  #projectService;
@@ -3076,6 +3078,30 @@ class AbilityLayer {
3076
3078
  this.#projectService = projectService;
3077
3079
  this.#resolvedConfig = resolvedConfig;
3078
3080
  }
3081
+ #collectSuppressedErrors() {
3082
+ const ranges = [];
3083
+ for (const match of this.#text.matchAll(this.#expectErrorRegex)) {
3084
+ const offsetText = match?.[1];
3085
+ const directiveText = match?.[2];
3086
+ const ignoreText = match?.[3];
3087
+ const argumentSeparatorText = match?.[4];
3088
+ const argumentText = match?.[5]?.split(/--+/)[0]?.trimEnd();
3089
+ if (typeof offsetText !== "string" || !directiveText || ignoreText === "!") {
3090
+ continue;
3091
+ }
3092
+ const start = match.index + offsetText.length;
3093
+ const range = {
3094
+ directive: { start, end: start + directiveText.length, text: directiveText },
3095
+ diagnostics: [],
3096
+ };
3097
+ if (typeof argumentSeparatorText === "string" && typeof argumentText === "string") {
3098
+ const start = range.directive.end + argumentSeparatorText.length;
3099
+ range.argument = { start, end: start + argumentText.length, text: argumentText };
3100
+ }
3101
+ ranges.push(range);
3102
+ }
3103
+ return ranges;
3104
+ }
3079
3105
  #getErasedRangeText(range) {
3080
3106
  if (this.#text.indexOf("\n", range.start) >= range.end) {
3081
3107
  return " ".repeat(range.end - range.start);
@@ -3184,9 +3210,18 @@ class AbilityLayer {
3184
3210
  break;
3185
3211
  }
3186
3212
  }
3213
+ #handleSuppressedErrors() {
3214
+ const suppressedErrors = this.#collectSuppressedErrors();
3215
+ for (const suppressedError of suppressedErrors) {
3216
+ const { start, end } = suppressedError.directive;
3217
+ const rangeText = this.#getErasedRangeText({ start: start + 2, end });
3218
+ this.#text = `${this.#text.slice(0, start + 2)}${rangeText}${this.#text.slice(end)}`;
3219
+ }
3220
+ }
3187
3221
  open(sourceFile) {
3188
3222
  this.#filePath = sourceFile.fileName;
3189
3223
  this.#text = sourceFile.text;
3224
+ this.#handleSuppressedErrors();
3190
3225
  }
3191
3226
  }
3192
3227
 
@@ -3641,6 +3676,7 @@ var RunMode;
3641
3676
  RunMode[RunMode["Only"] = 2] = "Only";
3642
3677
  RunMode[RunMode["Skip"] = 4] = "Skip";
3643
3678
  RunMode[RunMode["Todo"] = 8] = "Todo";
3679
+ RunMode[RunMode["Void"] = 16] = "Void";
3644
3680
  })(RunMode || (RunMode = {}));
3645
3681
 
3646
3682
  class EnsureDiagnosticText {
@@ -4170,69 +4206,75 @@ class ToBeAssignableWith extends RelationMatcherBase {
4170
4206
  }
4171
4207
  }
4172
4208
 
4173
- class ToBeCallableWith {
4174
- #compiler;
4209
+ class AbilityMatcherBase {
4210
+ compiler;
4175
4211
  constructor(compiler) {
4176
- this.#compiler = compiler;
4212
+ this.compiler = compiler;
4177
4213
  }
4178
4214
  #resolveTargetText(nodes) {
4179
4215
  if (nodes.length === 0) {
4180
4216
  return "without arguments";
4181
4217
  }
4182
- if (nodes.length === 1 && nodes[0]?.kind === this.#compiler.SyntaxKind.SpreadElement) {
4218
+ if (nodes.length === 1 && nodes[0]?.kind === this.compiler.SyntaxKind.SpreadElement) {
4183
4219
  return "with the given arguments";
4184
4220
  }
4185
4221
  return `with the given argument${nodes.length === 1 ? "" : "s"}`;
4186
4222
  }
4187
- #explain(matchWorker, sourceNode, targetNodes) {
4188
- const isExpression = nodeBelongsToArgumentList(this.#compiler, sourceNode);
4223
+ explain(matchWorker, sourceNode, targetNodes) {
4224
+ const isExpression = nodeBelongsToArgumentList(this.compiler, sourceNode);
4189
4225
  const targetText = this.#resolveTargetText(targetNodes);
4190
4226
  const diagnostics = [];
4191
4227
  if (matchWorker.assertion.abilityDiagnostics) {
4192
4228
  for (const diagnostic of matchWorker.assertion.abilityDiagnostics) {
4193
- const text = [
4194
- ExpectDiagnosticText.isNotCallable(isExpression, targetText),
4195
- getDiagnosticMessageText(diagnostic),
4196
- ];
4197
4229
  let origin;
4198
- if (isDiagnosticWithLocation(diagnostic) && diagnosticBelongsToNode(diagnostic, targetNodes)) {
4199
- origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), sourceNode.getSourceFile());
4230
+ const text = [];
4231
+ if (isDiagnosticWithLocation(diagnostic) && diagnosticBelongsToNode(diagnostic, sourceNode)) {
4232
+ origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), sourceNode.getSourceFile(), matchWorker.assertion);
4233
+ text.push(getDiagnosticMessageText(diagnostic));
4200
4234
  }
4201
4235
  else {
4202
- origin =
4203
- targetNodes.length > 0
4204
- ? DiagnosticOrigin.fromNodes(targetNodes)
4205
- : DiagnosticOrigin.fromAssertion(matchWorker.assertion);
4236
+ if (isDiagnosticWithLocation(diagnostic) && diagnosticBelongsToNode(diagnostic, targetNodes)) {
4237
+ origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), sourceNode.getSourceFile(), matchWorker.assertion);
4238
+ }
4239
+ else {
4240
+ origin = DiagnosticOrigin.fromAssertion(matchWorker.assertion);
4241
+ }
4242
+ text.push(this.explainNotText(isExpression, targetText), getDiagnosticMessageText(diagnostic));
4206
4243
  }
4207
4244
  let related;
4208
4245
  if (diagnostic.relatedInformation != null) {
4209
- related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
4246
+ related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation, sourceNode.getSourceFile());
4210
4247
  }
4211
4248
  diagnostics.push(Diagnostic.error(text.flat(), origin).add({ related }));
4212
4249
  }
4213
4250
  }
4214
4251
  else {
4215
4252
  const origin = DiagnosticOrigin.fromAssertion(matchWorker.assertion);
4216
- diagnostics.push(Diagnostic.error(ExpectDiagnosticText.isCallable(isExpression, targetText), origin));
4253
+ diagnostics.push(Diagnostic.error(this.explainText(isExpression, targetText), origin));
4217
4254
  }
4218
4255
  return diagnostics;
4219
4256
  }
4257
+ }
4258
+
4259
+ class ToBeCallableWith extends AbilityMatcherBase {
4260
+ explainText = ExpectDiagnosticText.isCallable;
4261
+ explainNotText = ExpectDiagnosticText.isNotCallable;
4220
4262
  match(matchWorker, sourceNode, targetNodes, onDiagnostics) {
4221
4263
  let type;
4222
- if (this.#compiler.isCallExpression(sourceNode)) {
4264
+ if (this.compiler.isCallExpression(sourceNode)) {
4223
4265
  type = matchWorker.typeChecker.getResolvedSignature(sourceNode)?.getReturnType();
4224
4266
  }
4225
- if (this.#compiler.isArrowFunction(sourceNode) ||
4226
- this.#compiler.isFunctionDeclaration(sourceNode) ||
4227
- this.#compiler.isFunctionExpression(sourceNode) ||
4228
- this.#compiler.isExpressionWithTypeArguments(sourceNode) ||
4229
- this.#compiler.isIdentifier(sourceNode) ||
4230
- this.#compiler.isPropertyAccessExpression(sourceNode)) {
4267
+ if (this.compiler.isArrowFunction(sourceNode) ||
4268
+ this.compiler.isFunctionDeclaration(sourceNode) ||
4269
+ this.compiler.isFunctionExpression(sourceNode) ||
4270
+ this.compiler.isExpressionWithTypeArguments(sourceNode) ||
4271
+ this.compiler.isIdentifier(sourceNode) ||
4272
+ this.compiler.isPropertyAccessExpression(sourceNode)) {
4231
4273
  type = matchWorker.getType(sourceNode);
4232
4274
  }
4233
4275
  if (!type || type.getCallSignatures().length === 0) {
4234
4276
  const text = [];
4235
- if (nodeBelongsToArgumentList(this.#compiler, sourceNode)) {
4277
+ if (nodeBelongsToArgumentList(this.compiler, sourceNode)) {
4236
4278
  text.push(ExpectDiagnosticText.argumentMustBe("source", "a callable expression"));
4237
4279
  }
4238
4280
  else {
@@ -4246,72 +4288,28 @@ class ToBeCallableWith {
4246
4288
  return;
4247
4289
  }
4248
4290
  return {
4249
- explain: () => this.#explain(matchWorker, sourceNode, targetNodes),
4291
+ explain: () => this.explain(matchWorker, sourceNode, targetNodes),
4250
4292
  isMatch: !matchWorker.assertion.abilityDiagnostics,
4251
4293
  };
4252
4294
  }
4253
4295
  }
4254
4296
 
4255
- class ToBeConstructableWith {
4256
- #compiler;
4257
- constructor(compiler) {
4258
- this.#compiler = compiler;
4259
- }
4260
- #resolveTargetText(nodes) {
4261
- if (nodes.length === 0) {
4262
- return "without arguments";
4263
- }
4264
- if (nodes.length === 1 && nodes[0]?.kind === this.#compiler.SyntaxKind.SpreadElement) {
4265
- return "with the given arguments";
4266
- }
4267
- return `with the given argument${nodes.length === 1 ? "" : "s"}`;
4268
- }
4269
- #explain(matchWorker, sourceNode, targetNodes) {
4270
- const isExpression = nodeBelongsToArgumentList(this.#compiler, sourceNode);
4271
- const targetText = this.#resolveTargetText(targetNodes);
4272
- const diagnostics = [];
4273
- if (matchWorker.assertion.abilityDiagnostics) {
4274
- for (const diagnostic of matchWorker.assertion.abilityDiagnostics) {
4275
- const text = [
4276
- ExpectDiagnosticText.isNotConstructable(isExpression, targetText),
4277
- getDiagnosticMessageText(diagnostic),
4278
- ];
4279
- let origin;
4280
- if (isDiagnosticWithLocation(diagnostic) && diagnosticBelongsToNode(diagnostic, targetNodes)) {
4281
- origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), sourceNode.getSourceFile());
4282
- }
4283
- else {
4284
- origin =
4285
- targetNodes.length > 0
4286
- ? DiagnosticOrigin.fromNodes(targetNodes)
4287
- : DiagnosticOrigin.fromAssertion(matchWorker.assertion);
4288
- }
4289
- let related;
4290
- if (diagnostic.relatedInformation != null) {
4291
- related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
4292
- }
4293
- diagnostics.push(Diagnostic.error(text.flat(), origin).add({ related }));
4294
- }
4295
- }
4296
- else {
4297
- const origin = DiagnosticOrigin.fromAssertion(matchWorker.assertion);
4298
- diagnostics.push(Diagnostic.error(ExpectDiagnosticText.isConstructable(isExpression, targetText), origin));
4299
- }
4300
- return diagnostics;
4301
- }
4297
+ class ToBeConstructableWith extends AbilityMatcherBase {
4298
+ explainText = ExpectDiagnosticText.isConstructable;
4299
+ explainNotText = ExpectDiagnosticText.isNotConstructable;
4302
4300
  match(matchWorker, sourceNode, targetNodes, onDiagnostics) {
4303
4301
  let type;
4304
- if (this.#compiler.isCallExpression(sourceNode)) {
4302
+ if (this.compiler.isCallExpression(sourceNode)) {
4305
4303
  type = matchWorker.typeChecker.getResolvedSignature(sourceNode)?.getReturnType();
4306
4304
  }
4307
- if (this.#compiler.isExpressionWithTypeArguments(sourceNode) ||
4308
- this.#compiler.isIdentifier(sourceNode) ||
4309
- this.#compiler.isPropertyAccessExpression(sourceNode)) {
4305
+ if (this.compiler.isExpressionWithTypeArguments(sourceNode) ||
4306
+ this.compiler.isIdentifier(sourceNode) ||
4307
+ this.compiler.isPropertyAccessExpression(sourceNode)) {
4310
4308
  type = matchWorker.getType(sourceNode);
4311
4309
  }
4312
4310
  if (!type || type.getConstructSignatures().length === 0) {
4313
4311
  const text = [];
4314
- if (nodeBelongsToArgumentList(this.#compiler, sourceNode)) {
4312
+ if (nodeBelongsToArgumentList(this.compiler, sourceNode)) {
4315
4313
  text.push(ExpectDiagnosticText.argumentMustBe("source", "a constructable expression"));
4316
4314
  }
4317
4315
  else {
@@ -4325,7 +4323,7 @@ class ToBeConstructableWith {
4325
4323
  return;
4326
4324
  }
4327
4325
  return {
4328
- explain: () => this.#explain(matchWorker, sourceNode, targetNodes),
4326
+ explain: () => this.explain(matchWorker, sourceNode, targetNodes),
4329
4327
  isMatch: !matchWorker.assertion.abilityDiagnostics,
4330
4328
  };
4331
4329
  }
@@ -4686,7 +4684,7 @@ class TestTreeWalker {
4686
4684
  const directiveRanges = node.getDirectiveRanges(this.#compiler);
4687
4685
  const inlineConfig = await Directive.getInlineConfig(directiveRanges);
4688
4686
  if (inlineConfig?.if?.target != null && !Version.isIncluded(this.#compiler.version, inlineConfig.if.target)) {
4689
- mode |= RunMode.Skip;
4687
+ mode |= RunMode.Void;
4690
4688
  }
4691
4689
  if (node.flags & TestTreeNodeFlags.Fail) {
4692
4690
  mode |= RunMode.Fail;
@@ -4731,9 +4729,12 @@ class TestTreeWalker {
4731
4729
  }
4732
4730
  async #visitAssertion(assertion, runMode, parentResult) {
4733
4731
  await this.visit(assertion.children, runMode, parentResult);
4732
+ runMode = await this.#resolveRunMode(runMode, assertion);
4733
+ if (runMode & RunMode.Void) {
4734
+ return;
4735
+ }
4734
4736
  const expectResult = new ExpectResult(assertion, parentResult);
4735
4737
  EventEmitter.dispatch(["expect:start", { result: expectResult }]);
4736
- runMode = await this.#resolveRunMode(runMode, assertion);
4737
4738
  if (runMode & RunMode.Skip || (this.#hasOnly && !(runMode & RunMode.Only))) {
4738
4739
  EventEmitter.dispatch(["expect:skip", { result: expectResult }]);
4739
4740
  return;
@@ -4770,9 +4771,12 @@ class TestTreeWalker {
4770
4771
  }
4771
4772
  }
4772
4773
  async #visitDescribe(describe, runMode, parentResult) {
4774
+ runMode = await this.#resolveRunMode(runMode, describe);
4775
+ if (runMode & RunMode.Void) {
4776
+ return;
4777
+ }
4773
4778
  const describeResult = new DescribeResult(describe, parentResult);
4774
4779
  EventEmitter.dispatch(["describe:start", { result: describeResult }]);
4775
- runMode = await this.#resolveRunMode(runMode, describe);
4776
4780
  if (!(runMode & RunMode.Skip || (this.#hasOnly && !(runMode & RunMode.Only)) || runMode & RunMode.Todo) &&
4777
4781
  describe.diagnostics.size > 0) {
4778
4782
  this.#onTaskDiagnostics(Diagnostic.fromDiagnostics([...describe.diagnostics]));
@@ -4783,9 +4787,12 @@ class TestTreeWalker {
4783
4787
  EventEmitter.dispatch(["describe:end", { result: describeResult }]);
4784
4788
  }
4785
4789
  async #visitTest(test, runMode, parentResult) {
4790
+ runMode = await this.#resolveRunMode(runMode, test);
4791
+ if (runMode & RunMode.Void) {
4792
+ return;
4793
+ }
4786
4794
  const testResult = new TestResult(test, parentResult);
4787
4795
  EventEmitter.dispatch(["test:start", { result: testResult }]);
4788
- runMode = await this.#resolveRunMode(runMode, test);
4789
4796
  if (runMode & RunMode.Todo) {
4790
4797
  EventEmitter.dispatch(["test:todo", { result: testResult }]);
4791
4798
  return;
@@ -4906,7 +4913,7 @@ class TaskRunner {
4906
4913
  class Runner {
4907
4914
  #eventEmitter = new EventEmitter();
4908
4915
  #resolvedConfig;
4909
- static version = "4.0.0";
4916
+ static version = "4.0.2";
4910
4917
  constructor(resolvedConfig) {
4911
4918
  this.#resolvedConfig = resolvedConfig;
4912
4919
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tstyche",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "Everything You Need for Type Testing.",
5
5
  "keywords": [
6
6
  "typescript",