tstyche 4.0.1 → 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.
@@ -177,7 +177,7 @@ declare class Diagnostic {
177
177
  }): this;
178
178
  static error(text: string | Array<string>, origin?: DiagnosticOrigin): Diagnostic;
179
179
  extendWith(text: string | Array<string>, origin?: DiagnosticOrigin): Diagnostic;
180
- static fromDiagnostics(diagnostics: Array<ts.Diagnostic>): Array<Diagnostic>;
180
+ static fromDiagnostics(diagnostics: Array<ts.Diagnostic>, sourceFile?: ts.SourceFile): Array<Diagnostic>;
181
181
  static warning(text: string | Array<string>, origin?: DiagnosticOrigin): Diagnostic;
182
182
  }
183
183
 
@@ -795,4 +795,4 @@ declare class WhenService {
795
795
  }
796
796
 
797
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, 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
@@ -87,16 +87,16 @@ class Diagnostic {
87
87
  extendWith(text, origin) {
88
88
  return new Diagnostic([this.text, text].flat(), this.category, origin ?? this.origin);
89
89
  }
90
- static fromDiagnostics(diagnostics) {
90
+ static fromDiagnostics(diagnostics, sourceFile) {
91
91
  return diagnostics.map((diagnostic) => {
92
92
  const code = `ts(${diagnostic.code})`;
93
93
  let origin;
94
- if (diagnostic.file != null && diagnostic.start != null && diagnostic.length != null) {
95
- 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);
96
96
  }
97
97
  let related;
98
98
  if (diagnostic.relatedInformation != null) {
99
- related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
99
+ related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation, sourceFile);
100
100
  }
101
101
  const text = getDiagnosticMessageText(diagnostic);
102
102
  return new Diagnostic(text, DiagnosticCategory.Error, origin).add({ code, related });
@@ -2130,7 +2130,9 @@ function describeNameText(name, indent = 0) {
2130
2130
  function BreadcrumbsText({ ancestor }) {
2131
2131
  const text = [];
2132
2132
  while ("name" in ancestor) {
2133
- text.push(ancestor.name);
2133
+ if (ancestor.name !== "") {
2134
+ text.push(ancestor.name);
2135
+ }
2134
2136
  ancestor = ancestor.parent;
2135
2137
  }
2136
2138
  text.push("");
@@ -3065,6 +3067,7 @@ function nodeIsChildOfExpressionStatement(compiler, node) {
3065
3067
 
3066
3068
  class AbilityLayer {
3067
3069
  #compiler;
3070
+ #expectErrorRegex = /^( *)(\/\/ *@ts-expect-error)(!?)(:? *)(.*)?$/gim;
3068
3071
  #filePath = "";
3069
3072
  #nodes = [];
3070
3073
  #projectService;
@@ -3075,6 +3078,30 @@ class AbilityLayer {
3075
3078
  this.#projectService = projectService;
3076
3079
  this.#resolvedConfig = resolvedConfig;
3077
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
+ }
3078
3105
  #getErasedRangeText(range) {
3079
3106
  if (this.#text.indexOf("\n", range.start) >= range.end) {
3080
3107
  return " ".repeat(range.end - range.start);
@@ -3183,9 +3210,18 @@ class AbilityLayer {
3183
3210
  break;
3184
3211
  }
3185
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
+ }
3186
3221
  open(sourceFile) {
3187
3222
  this.#filePath = sourceFile.fileName;
3188
3223
  this.#text = sourceFile.text;
3224
+ this.#handleSuppressedErrors();
3189
3225
  }
3190
3226
  }
3191
3227
 
@@ -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
  }
@@ -4915,7 +4913,7 @@ class TaskRunner {
4915
4913
  class Runner {
4916
4914
  #eventEmitter = new EventEmitter();
4917
4915
  #resolvedConfig;
4918
- static version = "4.0.1";
4916
+ static version = "4.0.2";
4919
4917
  constructor(resolvedConfig) {
4920
4918
  this.#resolvedConfig = resolvedConfig;
4921
4919
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tstyche",
3
- "version": "4.0.1",
3
+ "version": "4.0.2",
4
4
  "description": "Everything You Need for Type Testing.",
5
5
  "keywords": [
6
6
  "typescript",