tstyche 4.0.2 → 4.1.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 CHANGED
@@ -70,8 +70,7 @@ Here is the list of all matchers:
70
70
  - `.toBeApplicable` ensures that the decorator function can be applied,
71
71
  - `.toBeCallableWith()` checks whether a function is callable with the given arguments,
72
72
  - `.toBeConstructableWith()` checks whether a class is constructable with the given arguments,
73
- - `.toHaveProperty()` looks up keys on an object type,
74
- - `.toRaiseError()` captures the message or code of a type error.
73
+ - `.toHaveProperty()` looks up keys on an object type.
75
74
 
76
75
  ## Runner
77
76
 
@@ -41,6 +41,7 @@ interface CommandLineOptions {
41
41
  }
42
42
  interface ConfigFileOptions {
43
43
  checkSourceFiles?: boolean;
44
+ checkSuppressedErrors?: boolean;
44
45
  failFast?: boolean;
45
46
  plugins?: Array<string>;
46
47
  rejectAnyType?: boolean;
@@ -231,7 +232,7 @@ declare enum TestTreeNodeFlags {
231
232
  declare class WhenNode extends TestTreeNode {
232
233
  actionNode: ts.CallExpression;
233
234
  actionNameNode: ts.PropertyAccessExpression;
234
- abilityDiagnostics: Set<ts.Diagnostic> | undefined;
235
+ abilityDiagnostics: Set<ts.Diagnostic>;
235
236
  target: ts.NodeArray<ts.Expression> | ts.NodeArray<ts.TypeNode>;
236
237
  constructor(compiler: typeof ts, brand: TestTreeNodeBrand, node: ts.CallExpression, parent: TestTree | TestTreeNode, flags: TestTreeNodeFlags, actionNode: ts.CallExpression, actionNameNode: ts.PropertyAccessExpression);
237
238
  }
@@ -248,17 +249,28 @@ declare class TestTreeNode {
248
249
  getDirectiveRanges(compiler: typeof ts): DirectiveRanges | undefined;
249
250
  }
250
251
 
252
+ interface SuppressedError {
253
+ directive: TextRange;
254
+ ignore: boolean;
255
+ argument?: TextRange;
256
+ diagnostics: Array<ts.Diagnostic>;
257
+ }
258
+ type SuppressedErrors = Array<SuppressedError> & {
259
+ sourceFile: ts.SourceFile;
260
+ };
261
+
251
262
  declare class TestTree {
252
263
  children: Array<TestTreeNode | AssertionNode | WhenNode>;
253
264
  diagnostics: Set<ts.Diagnostic>;
254
265
  hasOnly: boolean;
255
266
  sourceFile: ts.SourceFile;
267
+ suppressedErrors: SuppressedErrors | undefined;
256
268
  constructor(diagnostics: Set<ts.Diagnostic>, sourceFile: ts.SourceFile);
257
269
  getDirectiveRanges(compiler: typeof ts): DirectiveRanges | undefined;
258
270
  }
259
271
 
260
272
  declare class AssertionNode extends TestTreeNode {
261
- abilityDiagnostics: Set<ts.Diagnostic> | undefined;
273
+ abilityDiagnostics: Set<ts.Diagnostic>;
262
274
  isNot: boolean;
263
275
  matcherNode: ts.CallExpression | ts.Decorator;
264
276
  matcherNameNode: ts.PropertyAccessExpression;
@@ -759,6 +771,10 @@ declare class Store {
759
771
  static validateTag(tag: string): Promise<boolean | undefined>;
760
772
  }
761
773
 
774
+ declare class SuppressedService {
775
+ match(suppressedErrors: SuppressedErrors, onDiagnostics: DiagnosticsHandler<Array<Diagnostic>>): void;
776
+ }
777
+
762
778
  declare class Version {
763
779
  #private;
764
780
  static isGreaterThan(source: string, target: string): boolean;
@@ -794,5 +810,5 @@ declare class WhenService {
794
810
  action(when: WhenNode): void;
795
811
  }
796
812
 
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 };
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 };
813
+ 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, SuppressedService, 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 };
814
+ export type { CodeFrameOptions, CommandLineOptions, ConfigFileOptions, DiagnosticsHandler, DirectiveRange, DirectiveRanges, EnvironmentOptions, Event, EventHandler, FileWatchHandler, InlineConfig, InputHandler, ItemDefinition, MatchResult, OptionDefinition, Plugin, Reporter, ReporterEvent, ResolvedConfig, ScribblerOptions, SelectHookContext, SuppressedError, SuppressedErrors, TargetResultStatus, TaskResultStatus, TextRange, TypeChecker, WatchHandler, WatcherOptions };
package/build/tstyche.js CHANGED
@@ -96,7 +96,7 @@ class Diagnostic {
96
96
  }
97
97
  let related;
98
98
  if (diagnostic.relatedInformation != null) {
99
- related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation, sourceFile);
99
+ related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
100
100
  }
101
101
  const text = getDiagnosticMessageText(diagnostic);
102
102
  return new Diagnostic(text, DiagnosticCategory.Error, origin).add({ code, related });
@@ -910,6 +910,12 @@ class Options {
910
910
  group: OptionGroup.ConfigFile,
911
911
  name: "checkSourceFiles",
912
912
  },
913
+ {
914
+ brand: OptionBrand.Boolean,
915
+ description: "Check errors silenced by '// @ts-expect-error' directives.",
916
+ group: OptionGroup.ConfigFile,
917
+ name: "checkSuppressedErrors",
918
+ },
913
919
  {
914
920
  brand: OptionBrand.String,
915
921
  description: "The path to a TSTyche configuration file.",
@@ -1394,6 +1400,7 @@ class ConfigParser {
1394
1400
 
1395
1401
  const defaultOptions = {
1396
1402
  checkSourceFiles: true,
1403
+ checkSuppressedErrors: false,
1397
1404
  failFast: false,
1398
1405
  plugins: [],
1399
1406
  rejectAnyType: true,
@@ -3030,7 +3037,7 @@ class TestTreeNode {
3030
3037
  }
3031
3038
 
3032
3039
  class AssertionNode extends TestTreeNode {
3033
- abilityDiagnostics;
3040
+ abilityDiagnostics = new Set();
3034
3041
  isNot;
3035
3042
  matcherNode;
3036
3043
  matcherNameNode;
@@ -3072,12 +3079,51 @@ class AbilityLayer {
3072
3079
  #nodes = [];
3073
3080
  #projectService;
3074
3081
  #resolvedConfig;
3082
+ #suppressedErrorsMap;
3075
3083
  #text = "";
3076
3084
  constructor(compiler, projectService, resolvedConfig) {
3077
3085
  this.#compiler = compiler;
3078
3086
  this.#projectService = projectService;
3079
3087
  this.#resolvedConfig = resolvedConfig;
3080
3088
  }
3089
+ #addRanges(node, ranges) {
3090
+ this.#nodes.push(node);
3091
+ for (const range of ranges) {
3092
+ const rangeText = range.replacement != null
3093
+ ? `${range.replacement}${this.#getErasedRangeText(range).slice(range.replacement.length)}`
3094
+ : this.#getErasedRangeText(range);
3095
+ this.#text = `${this.#text.slice(0, range.start)}${rangeText}${this.#text.slice(range.end)}`;
3096
+ }
3097
+ }
3098
+ #belongsToNode(diagnostic) {
3099
+ for (const node of this.#nodes) {
3100
+ if (diagnosticBelongsToNode(diagnostic, "matcherNode" in node ? node.matcherNode : node.actionNode)) {
3101
+ node.abilityDiagnostics.add(diagnostic);
3102
+ return true;
3103
+ }
3104
+ }
3105
+ return false;
3106
+ }
3107
+ #belongsToDirective(diagnostic) {
3108
+ if (!isDiagnosticWithLocation(diagnostic)) {
3109
+ return;
3110
+ }
3111
+ const { file, start } = diagnostic;
3112
+ const lineMap = file.getLineStarts();
3113
+ let line = this.#compiler.getLineAndCharacterOfPosition(file, start).line - 1;
3114
+ while (line >= 0) {
3115
+ const suppressedError = this.#suppressedErrorsMap?.get(line);
3116
+ if (suppressedError != null) {
3117
+ suppressedError.diagnostics.push(diagnostic);
3118
+ break;
3119
+ }
3120
+ const lineText = file.text.slice(lineMap[line], lineMap[line + 1]).trim();
3121
+ if (lineText !== "" && !lineText.startsWith("//")) {
3122
+ break;
3123
+ }
3124
+ line--;
3125
+ }
3126
+ }
3081
3127
  #collectSuppressedErrors() {
3082
3128
  const ranges = [];
3083
3129
  for (const match of this.#text.matchAll(this.#expectErrorRegex)) {
@@ -3086,12 +3132,13 @@ class AbilityLayer {
3086
3132
  const ignoreText = match?.[3];
3087
3133
  const argumentSeparatorText = match?.[4];
3088
3134
  const argumentText = match?.[5]?.split(/--+/)[0]?.trimEnd();
3089
- if (typeof offsetText !== "string" || !directiveText || ignoreText === "!") {
3135
+ if (typeof offsetText !== "string" || !directiveText) {
3090
3136
  continue;
3091
3137
  }
3092
3138
  const start = match.index + offsetText.length;
3093
3139
  const range = {
3094
3140
  directive: { start, end: start + directiveText.length, text: directiveText },
3141
+ ignore: ignoreText === "!",
3095
3142
  diagnostics: [],
3096
3143
  };
3097
3144
  if (typeof argumentSeparatorText === "string" && typeof argumentText === "string") {
@@ -3102,52 +3149,24 @@ class AbilityLayer {
3102
3149
  }
3103
3150
  return ranges;
3104
3151
  }
3105
- #getErasedRangeText(range) {
3106
- if (this.#text.indexOf("\n", range.start) >= range.end) {
3107
- return " ".repeat(range.end - range.start);
3108
- }
3109
- const text = [];
3110
- for (let index = range.start; index < range.end; index++) {
3111
- const character = this.#text.charAt(index);
3112
- switch (character) {
3113
- case "\n":
3114
- case "\r":
3115
- text.push(character);
3116
- break;
3117
- default:
3118
- text.push(" ");
3119
- }
3120
- }
3121
- return text.join("");
3122
- }
3123
- #addRanges(node, ranges) {
3124
- this.#nodes.push(node);
3125
- for (const range of ranges) {
3126
- const rangeText = range.replacement != null
3127
- ? `${range.replacement}${this.#getErasedRangeText(range).slice(range.replacement.length)}`
3128
- : this.#getErasedRangeText(range);
3129
- this.#text = `${this.#text.slice(0, range.start)}${rangeText}${this.#text.slice(range.end)}`;
3130
- }
3131
- }
3132
3152
  close() {
3133
- if (this.#nodes.length > 0) {
3153
+ if (this.#nodes.length > 0 || this.#suppressedErrorsMap != null) {
3134
3154
  this.#projectService.openFile(this.#filePath, this.#text, this.#resolvedConfig.rootPath);
3135
3155
  const languageService = this.#projectService.getLanguageService(this.#filePath);
3136
- const diagnostics = new Set(languageService?.getSemanticDiagnostics(this.#filePath));
3137
- for (const node of this.#nodes.reverse()) {
3156
+ const diagnostics = languageService?.getSemanticDiagnostics(this.#filePath);
3157
+ if (diagnostics != null) {
3158
+ this.#nodes.reverse();
3138
3159
  for (const diagnostic of diagnostics) {
3139
- if (diagnosticBelongsToNode(diagnostic, "matcherNode" in node ? node.matcherNode : node.actionNode)) {
3140
- if (!node.abilityDiagnostics) {
3141
- node.abilityDiagnostics = new Set();
3142
- }
3143
- node.abilityDiagnostics.add(diagnostic);
3144
- diagnostics.delete(diagnostic);
3160
+ if (this.#belongsToNode(diagnostic)) {
3161
+ continue;
3145
3162
  }
3163
+ this.#belongsToDirective(diagnostic);
3146
3164
  }
3147
3165
  }
3148
3166
  }
3149
3167
  this.#filePath = "";
3150
3168
  this.#nodes = [];
3169
+ this.#suppressedErrorsMap = undefined;
3151
3170
  this.#text = "";
3152
3171
  }
3153
3172
  #eraseTrailingComma(node, parent) {
@@ -3155,24 +3174,23 @@ class AbilityLayer {
3155
3174
  this.#addRanges(parent, [{ start: node.end - 1, end: node.end }]);
3156
3175
  }
3157
3176
  }
3158
- handleWhen(whenNode) {
3159
- const whenStart = whenNode.node.getStart();
3160
- const whenExpressionEnd = whenNode.node.expression.getEnd();
3161
- const whenEnd = whenNode.node.getEnd();
3162
- const actionNameEnd = whenNode.actionNameNode.getEnd();
3163
- switch (whenNode.actionNameNode.name.text) {
3164
- case "isCalledWith":
3165
- this.#eraseTrailingComma(whenNode.target, whenNode);
3166
- this.#addRanges(whenNode, [
3167
- {
3168
- start: whenStart,
3169
- end: whenExpressionEnd,
3170
- replacement: nodeIsChildOfExpressionStatement(this.#compiler, whenNode.actionNode) ? ";" : "",
3171
- },
3172
- { start: whenEnd, end: actionNameEnd },
3173
- ]);
3174
- break;
3177
+ #getErasedRangeText(range) {
3178
+ if (this.#text.indexOf("\n", range.start) >= range.end) {
3179
+ return " ".repeat(range.end - range.start);
3180
+ }
3181
+ const text = [];
3182
+ for (let index = range.start; index < range.end; index++) {
3183
+ const character = this.#text.charAt(index);
3184
+ switch (character) {
3185
+ case "\n":
3186
+ case "\r":
3187
+ text.push(character);
3188
+ break;
3189
+ default:
3190
+ text.push(" ");
3191
+ }
3175
3192
  }
3193
+ return text.join("");
3176
3194
  }
3177
3195
  handleAssertion(assertionNode) {
3178
3196
  const expectStart = assertionNode.node.getStart();
@@ -3210,18 +3228,45 @@ class AbilityLayer {
3210
3228
  break;
3211
3229
  }
3212
3230
  }
3213
- #handleSuppressedErrors() {
3231
+ #handleSuppressedErrors(testTree) {
3214
3232
  const suppressedErrors = this.#collectSuppressedErrors();
3233
+ if (this.#resolvedConfig.checkSuppressedErrors) {
3234
+ testTree.suppressedErrors = Object.assign(suppressedErrors, { sourceFile: testTree.sourceFile });
3235
+ this.#suppressedErrorsMap = new Map();
3236
+ }
3215
3237
  for (const suppressedError of suppressedErrors) {
3216
3238
  const { start, end } = suppressedError.directive;
3217
3239
  const rangeText = this.#getErasedRangeText({ start: start + 2, end });
3218
3240
  this.#text = `${this.#text.slice(0, start + 2)}${rangeText}${this.#text.slice(end)}`;
3241
+ if (this.#suppressedErrorsMap != null) {
3242
+ const { line } = testTree.sourceFile.getLineAndCharacterOfPosition(start);
3243
+ this.#suppressedErrorsMap.set(line, suppressedError);
3244
+ }
3245
+ }
3246
+ }
3247
+ handleWhen(whenNode) {
3248
+ const whenStart = whenNode.node.getStart();
3249
+ const whenExpressionEnd = whenNode.node.expression.getEnd();
3250
+ const whenEnd = whenNode.node.getEnd();
3251
+ const actionNameEnd = whenNode.actionNameNode.getEnd();
3252
+ switch (whenNode.actionNameNode.name.text) {
3253
+ case "isCalledWith":
3254
+ this.#eraseTrailingComma(whenNode.target, whenNode);
3255
+ this.#addRanges(whenNode, [
3256
+ {
3257
+ start: whenStart,
3258
+ end: whenExpressionEnd,
3259
+ replacement: nodeIsChildOfExpressionStatement(this.#compiler, whenNode.actionNode) ? ";" : "",
3260
+ },
3261
+ { start: whenEnd, end: actionNameEnd },
3262
+ ]);
3263
+ break;
3219
3264
  }
3220
3265
  }
3221
- open(sourceFile) {
3222
- this.#filePath = sourceFile.fileName;
3223
- this.#text = sourceFile.text;
3224
- this.#handleSuppressedErrors();
3266
+ open(testTree) {
3267
+ this.#filePath = testTree.sourceFile.fileName;
3268
+ this.#text = testTree.sourceFile.text;
3269
+ this.#handleSuppressedErrors(testTree);
3225
3270
  }
3226
3271
  }
3227
3272
 
@@ -3348,6 +3393,7 @@ class TestTree {
3348
3393
  diagnostics;
3349
3394
  hasOnly = false;
3350
3395
  sourceFile;
3396
+ suppressedErrors;
3351
3397
  constructor(diagnostics, sourceFile) {
3352
3398
  this.diagnostics = diagnostics;
3353
3399
  this.sourceFile = sourceFile;
@@ -3360,7 +3406,7 @@ class TestTree {
3360
3406
  class WhenNode extends TestTreeNode {
3361
3407
  actionNode;
3362
3408
  actionNameNode;
3363
- abilityDiagnostics;
3409
+ abilityDiagnostics = new Set();
3364
3410
  target;
3365
3411
  constructor(compiler, brand, node, parent, flags, actionNode, actionNameNode) {
3366
3412
  super(compiler, brand, node, parent, flags);
@@ -3459,7 +3505,7 @@ class CollectService {
3459
3505
  createTestTree(sourceFile, semanticDiagnostics = []) {
3460
3506
  const testTree = new TestTree(new Set(semanticDiagnostics), sourceFile);
3461
3507
  EventEmitter.dispatch(["collect:start", { tree: testTree }]);
3462
- this.#abilityLayer.open(sourceFile);
3508
+ this.#abilityLayer.open(testTree);
3463
3509
  this.#identifierLookup.open();
3464
3510
  this.#collectTestTreeNodes(sourceFile, testTree, testTree);
3465
3511
  this.#abilityLayer.close();
@@ -3596,6 +3642,9 @@ class ProjectService {
3596
3642
  defaultCompilerOptions.allowImportingTsExtensions = true;
3597
3643
  defaultCompilerOptions.verbatimModuleSyntax = true;
3598
3644
  }
3645
+ if (Version.isSatisfiedWith(this.#compiler.version, "5.6")) {
3646
+ defaultCompilerOptions.noUncheckedSideEffectImports = true;
3647
+ }
3599
3648
  return defaultCompilerOptions;
3600
3649
  }
3601
3650
  getDefaultProject(filePath) {
@@ -3669,6 +3718,60 @@ class ProjectService {
3669
3718
  }
3670
3719
  }
3671
3720
 
3721
+ class SuppressedDiagnosticText {
3722
+ static directiveRequires() {
3723
+ return [
3724
+ "Directive requires an argument.",
3725
+ "Add a fragment of the expected error message after the directive.",
3726
+ "To ignore the directive, append a '!' character after it.",
3727
+ ];
3728
+ }
3729
+ static messageDidNotMatch() {
3730
+ return "The diagnostic message did not match.";
3731
+ }
3732
+ static onlySingleError() {
3733
+ return "Only a single error can be suppressed.";
3734
+ }
3735
+ static suppressedError(count = 1) {
3736
+ return `The suppressed error${count === 1 ? "" : "s"}:`;
3737
+ }
3738
+ }
3739
+
3740
+ class SuppressedService {
3741
+ match(suppressedErrors, onDiagnostics) {
3742
+ for (const suppressedError of suppressedErrors) {
3743
+ if (suppressedError.diagnostics.length === 0 || suppressedError.ignore) {
3744
+ continue;
3745
+ }
3746
+ if (!suppressedError.argument?.text) {
3747
+ const text = SuppressedDiagnosticText.directiveRequires();
3748
+ const origin = new DiagnosticOrigin(suppressedError.directive.start, suppressedError.directive.end, suppressedErrors.sourceFile);
3749
+ onDiagnostics([Diagnostic.error(text, origin)]);
3750
+ continue;
3751
+ }
3752
+ const related = [
3753
+ Diagnostic.error(SuppressedDiagnosticText.suppressedError(suppressedError.diagnostics.length)),
3754
+ ...Diagnostic.fromDiagnostics(suppressedError.diagnostics, suppressedErrors.sourceFile),
3755
+ ];
3756
+ if (suppressedError.diagnostics.length > 1) {
3757
+ const text = [SuppressedDiagnosticText.onlySingleError()];
3758
+ const origin = new DiagnosticOrigin(suppressedError.directive.start, suppressedError.directive.end, suppressedErrors.sourceFile);
3759
+ onDiagnostics([Diagnostic.error(text, origin).add({ related })]);
3760
+ continue;
3761
+ }
3762
+ let messageText = getDiagnosticMessageText(suppressedError.diagnostics[0]);
3763
+ if (Array.isArray(messageText)) {
3764
+ messageText = messageText.join("\n");
3765
+ }
3766
+ if (!messageText.includes(suppressedError.argument.text)) {
3767
+ const text = [SuppressedDiagnosticText.messageDidNotMatch()];
3768
+ const origin = new DiagnosticOrigin(suppressedError.argument.start, suppressedError.argument.end, suppressedErrors.sourceFile);
3769
+ onDiagnostics([Diagnostic.error(text, origin).add({ related })]);
3770
+ }
3771
+ }
3772
+ }
3773
+ }
3774
+
3672
3775
  var RunMode;
3673
3776
  (function (RunMode) {
3674
3777
  RunMode[RunMode["Normal"] = 0] = "Normal";
@@ -4153,7 +4256,7 @@ class ToBeApplicable {
4153
4256
  #explain(matchWorker, sourceNode) {
4154
4257
  const targetText = this.#resolveTargetText(matchWorker.assertion.matcherNode.parent);
4155
4258
  const diagnostics = [];
4156
- if (matchWorker.assertion.abilityDiagnostics) {
4259
+ if (matchWorker.assertion.abilityDiagnostics.size > 0) {
4157
4260
  for (const diagnostic of matchWorker.assertion.abilityDiagnostics) {
4158
4261
  const text = [ExpectDiagnosticText.cannotBeApplied(targetText), getDiagnosticMessageText(diagnostic)];
4159
4262
  const origin = DiagnosticOrigin.fromNode(sourceNode);
@@ -4179,7 +4282,7 @@ class ToBeApplicable {
4179
4282
  }
4180
4283
  return {
4181
4284
  explain: () => this.#explain(matchWorker, sourceNode),
4182
- isMatch: !matchWorker.assertion.abilityDiagnostics,
4285
+ isMatch: matchWorker.assertion.abilityDiagnostics.size === 0,
4183
4286
  };
4184
4287
  }
4185
4288
  }
@@ -4224,7 +4327,7 @@ class AbilityMatcherBase {
4224
4327
  const isExpression = nodeBelongsToArgumentList(this.compiler, sourceNode);
4225
4328
  const targetText = this.#resolveTargetText(targetNodes);
4226
4329
  const diagnostics = [];
4227
- if (matchWorker.assertion.abilityDiagnostics) {
4330
+ if (matchWorker.assertion.abilityDiagnostics.size > 0) {
4228
4331
  for (const diagnostic of matchWorker.assertion.abilityDiagnostics) {
4229
4332
  let origin;
4230
4333
  const text = [];
@@ -4289,7 +4392,7 @@ class ToBeCallableWith extends AbilityMatcherBase {
4289
4392
  }
4290
4393
  return {
4291
4394
  explain: () => this.explain(matchWorker, sourceNode, targetNodes),
4292
- isMatch: !matchWorker.assertion.abilityDiagnostics,
4395
+ isMatch: matchWorker.assertion.abilityDiagnostics.size === 0,
4293
4396
  };
4294
4397
  }
4295
4398
  }
@@ -4324,7 +4427,7 @@ class ToBeConstructableWith extends AbilityMatcherBase {
4324
4427
  }
4325
4428
  return {
4326
4429
  explain: () => this.explain(matchWorker, sourceNode, targetNodes),
4327
- isMatch: !matchWorker.assertion.abilityDiagnostics,
4430
+ isMatch: matchWorker.assertion.abilityDiagnostics.size === 0,
4328
4431
  };
4329
4432
  }
4330
4433
  }
@@ -4631,7 +4734,7 @@ class WhenService {
4631
4734
  this.#onActionIsNotSupported(actionNameText, when, this.#onDiagnostics);
4632
4735
  return;
4633
4736
  }
4634
- if (when.abilityDiagnostics != null && when.abilityDiagnostics.size > 0) {
4737
+ if (when.abilityDiagnostics.size > 0) {
4635
4738
  const diagnostics = [];
4636
4739
  for (const diagnostic of when.abilityDiagnostics) {
4637
4740
  if (isDiagnosticWithLocation(diagnostic)) {
@@ -4827,8 +4930,9 @@ class TestTreeWalker {
4827
4930
  class TaskRunner {
4828
4931
  #collectService;
4829
4932
  #compiler;
4830
- #resolvedConfig;
4831
4933
  #projectService;
4934
+ #resolvedConfig;
4935
+ #suppressedService = new SuppressedService();
4832
4936
  constructor(compiler, resolvedConfig) {
4833
4937
  this.#compiler = compiler;
4834
4938
  this.#resolvedConfig = resolvedConfig;
@@ -4869,6 +4973,11 @@ class TaskRunner {
4869
4973
  if (inlineConfig?.if?.target != null && !Version.isIncluded(this.#compiler.version, inlineConfig.if.target)) {
4870
4974
  runMode |= RunMode.Skip;
4871
4975
  }
4976
+ if (testTree.suppressedErrors != null) {
4977
+ this.#suppressedService.match(testTree.suppressedErrors, (diagnostics) => {
4978
+ this.#onDiagnostics(diagnostics, taskResult);
4979
+ });
4980
+ }
4872
4981
  if (inlineConfig?.template) {
4873
4982
  if (semanticDiagnostics != null && semanticDiagnostics.length > 0) {
4874
4983
  this.#onDiagnostics(Diagnostic.fromDiagnostics(semanticDiagnostics), taskResult);
@@ -4913,7 +5022,7 @@ class TaskRunner {
4913
5022
  class Runner {
4914
5023
  #eventEmitter = new EventEmitter();
4915
5024
  #resolvedConfig;
4916
- static version = "4.0.2";
5025
+ static version = "4.1.0";
4917
5026
  constructor(resolvedConfig) {
4918
5027
  this.#resolvedConfig = resolvedConfig;
4919
5028
  }
@@ -5113,4 +5222,4 @@ class Cli {
5113
5222
  }
5114
5223
  }
5115
5224
 
5116
- 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 };
5225
+ 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, SuppressedService, 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.2",
3
+ "version": "4.1.0",
4
4
  "description": "Everything You Need for Type Testing.",
5
5
  "keywords": [
6
6
  "typescript",