tstyche 7.2.0 → 7.2.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.
Files changed (2) hide show
  1. package/dist/api.js +59 -27
  2. package/package.json +1 -1
package/dist/api.js CHANGED
@@ -609,7 +609,7 @@ class Fetcher {
609
609
  }
610
610
  async get(request, diagnostic, options) {
611
611
  let delay = 3000;
612
- request.headers.set("User-Agent", `tstyche/${"7.2.0"} ${process.platform} ${process.arch}`);
612
+ request.headers.set("User-Agent", `tstyche/${"7.2.1"} ${process.platform} ${process.arch}`);
613
613
  for (let attempt = 0; attempt <= this.#retries; attempt++) {
614
614
  const isLastAttempt = attempt === this.#retries;
615
615
  const suppressErrors = options?.suppressErrors || !isLastAttempt;
@@ -3430,6 +3430,11 @@ class AbilityLayer {
3430
3430
  const targetNode = expect.target?.[0];
3431
3431
  if (!sourceNode ||
3432
3432
  !targetNode ||
3433
+ !(this.#compiler.isIdentifier(sourceNode) ||
3434
+ this.#compiler.isPropertyAccessExpression(sourceNode) ||
3435
+ this.#compiler.isTypeReferenceNode(sourceNode) ||
3436
+ this.#compiler.isExpressionWithTypeArguments(sourceNode)) ||
3437
+ !/^[A-Z_$]/.test(sourceNode.getText()[0]) ||
3433
3438
  !this.#compiler.isObjectLiteralExpression(targetNode) ||
3434
3439
  !targetNode.properties.every((property) => (this.#compiler.isPropertyAssignment(property) &&
3435
3440
  (this.#compiler.isIdentifier(property.name) || this.#compiler.isStringLiteral(property.name))) ||
@@ -3455,20 +3460,22 @@ class AbilityLayer {
3455
3460
  for (const property of targetNode.properties) {
3456
3461
  if (this.#compiler.isPropertyAssignment(property)) {
3457
3462
  this.#editor
3458
- .update(property.name.getStart(), property.name.getEnd() + 1, this.#compiler.isStringLiteral(property.name)
3459
- ? ` ${property.name.getText().slice(1, -1)} =`
3460
- : property.name.getText() + "=")
3461
- .update(property.initializer.getStart(), property.initializer.getStart(), "{")
3462
- .update(property.initializer.getStart(), property.initializer.getEnd(), property.initializer.getText() + "}");
3463
+ .update(property.name.getStart(), property.name.getEnd(), this.#compiler.isStringLiteral(property.name)
3464
+ ? ` ${property.name.getText().slice(1, -1)} `
3465
+ : property.name.getText())
3466
+ .insert(property.initializer.getStart(), "={")
3467
+ .update(property.initializer.getStart(), property.initializer.getEnd(), property.initializer.getText())
3468
+ .insert(property.initializer.getEnd(), "}");
3463
3469
  continue;
3464
3470
  }
3465
3471
  if (this.#compiler.isSpreadAssignment(property)) {
3466
3472
  this.#editor
3467
- .update(property.getStart(), property.getStart(), "{")
3468
- .update(property.getStart(), property.getEnd(), property.getText() + "}");
3473
+ .insert(property.getStart(), "{")
3474
+ .update(property.getStart(), property.getEnd(), property.getText())
3475
+ .insert(property.getEnd(), "}");
3469
3476
  }
3470
3477
  }
3471
- this.#editor.update(matcherNodeEnd, matcherNodeEnd, "/>");
3478
+ this.#editor.insert(matcherNodeEnd, "/>");
3472
3479
  break;
3473
3480
  }
3474
3481
  case "toBeApplicable":
@@ -3687,6 +3694,10 @@ class TextEditor {
3687
3694
  }
3688
3695
  return this;
3689
3696
  }
3697
+ insert(position, text) {
3698
+ this.update(position, position, text);
3699
+ return this;
3700
+ }
3690
3701
  #getErased(start, end) {
3691
3702
  if (this.#text.indexOf("\n", start) >= end) {
3692
3703
  return " ".repeat(end - start);
@@ -4425,6 +4436,20 @@ class Ensure {
4425
4436
  }
4426
4437
  return true;
4427
4438
  }
4439
+ jsxSetup(program, node, onDiagnostics) {
4440
+ const diagnosticText = [];
4441
+ if (!program.getCompilerOptions().jsx) {
4442
+ diagnosticText.push("The matcher requires the 'jsx' compiler option to be configured.");
4443
+ }
4444
+ if (node.getSourceFile().languageVariant !== this.#compiler.LanguageVariant.JSX) {
4445
+ diagnosticText.push("The matcher requires a '.tsx' file extension.");
4446
+ }
4447
+ if (diagnosticText.length > 0) {
4448
+ this.#emitDiagnostic(diagnosticText, node, onDiagnostics);
4449
+ return false;
4450
+ }
4451
+ return true;
4452
+ }
4428
4453
  typeArgument(node, enclosingNode, onDiagnostics) {
4429
4454
  if (!node || nodeBelongsToArgumentList(this.#compiler, node)) {
4430
4455
  this.#emitDiagnostic("A type argument must be provided.", enclosingNode, onDiagnostics);
@@ -4433,8 +4458,11 @@ class Ensure {
4433
4458
  return true;
4434
4459
  }
4435
4460
  #emitDiagnostic(text, enclosingNode, onDiagnostics) {
4461
+ if (!Array.isArray(text)) {
4462
+ text = [text];
4463
+ }
4436
4464
  const origin = DiagnosticOrigin.fromNode(enclosingNode);
4437
- onDiagnostics([Diagnostic.error(text, origin)]);
4465
+ onDiagnostics(text.map((text) => Diagnostic.error(text, origin)));
4438
4466
  }
4439
4467
  }
4440
4468
 
@@ -4529,7 +4557,6 @@ class ExpectDiagnosticText {
4529
4557
  class MatchWorker {
4530
4558
  assertionNode;
4531
4559
  #compiler;
4532
- #signatureCache = new Map();
4533
4560
  typeChecker;
4534
4561
  constructor(compiler, program, assertionNode) {
4535
4562
  this.#compiler = compiler;
@@ -4553,17 +4580,6 @@ class MatchWorker {
4553
4580
  : { flags: this.#compiler.TypeFlags.NonPrimitive };
4554
4581
  return this.typeChecker.isTypeAssignableTo(type, nonPrimitiveType);
4555
4582
  }
4556
- getSignatures(node) {
4557
- let signatures = this.#signatureCache.get(node);
4558
- if (!signatures) {
4559
- const type = this.getType(node);
4560
- signatures = type.getCallSignatures();
4561
- if (signatures.length === 0) {
4562
- signatures = type.getConstructSignatures();
4563
- }
4564
- }
4565
- return signatures;
4566
- }
4567
4583
  getTypeText(node) {
4568
4584
  return this.typeChecker.typeToString(this.getType(node));
4569
4585
  }
@@ -4626,9 +4642,21 @@ class ToAcceptProps extends AbilityMatcherBase {
4626
4642
  explainNotText = ExpectDiagnosticText.doesNotAcceptProps;
4627
4643
  match(matchWorker, sourceNode, targetNode, onDiagnostics) {
4628
4644
  const diagnostics = [];
4629
- const signatures = matchWorker.getSignatures(sourceNode);
4630
- if (signatures.length === 0) {
4631
- const expectedText = "of a function or class type";
4645
+ const sourceType = matchWorker.getType(sourceNode);
4646
+ if (!(this.compiler.isIdentifier(sourceNode) ||
4647
+ this.compiler.isPropertyAccessExpression(sourceNode) ||
4648
+ this.compiler.isTypeReferenceNode(sourceNode) ||
4649
+ this.compiler.isExpressionWithTypeArguments(sourceNode)) ||
4650
+ !(sourceType.getCallSignatures().length > 0 || sourceType.getConstructSignatures().length > 0)) {
4651
+ const expectedText = "an identifier of a JSX component";
4652
+ const text = nodeBelongsToArgumentList(this.compiler, sourceNode)
4653
+ ? ExpectDiagnosticText.argumentMustBe(expectedText)
4654
+ : ExpectDiagnosticText.typeArgumentMustBe(expectedText);
4655
+ const origin = DiagnosticOrigin.fromNode(sourceNode);
4656
+ diagnostics.push(Diagnostic.error(text, origin));
4657
+ }
4658
+ else if (!/^[A-Z_$]/.test(sourceNode.getText()[0])) {
4659
+ const expectedText = "an identifier that begins with an uppercase letter";
4632
4660
  const text = nodeBelongsToArgumentList(this.compiler, sourceNode)
4633
4661
  ? ExpectDiagnosticText.argumentMustBe(expectedText)
4634
4662
  : ExpectDiagnosticText.typeArgumentMustBe(expectedText);
@@ -5555,14 +5583,18 @@ class ExpectService {
5555
5583
  }
5556
5584
  match(assertionNode, onDiagnostics) {
5557
5585
  const matcherNameText = assertionNode.matcherNameNode.name.text;
5586
+ if (matcherNameText === "toAcceptProps" &&
5587
+ !this.#ensure.jsxSetup(this.#program, assertionNode.matcherNameNode.name, onDiagnostics)) {
5588
+ return;
5589
+ }
5558
5590
  if (!this.#ensure.argumentOrTypeArgument(assertionNode.source[0], assertionNode.node.expression, onDiagnostics)) {
5559
5591
  return;
5560
5592
  }
5561
- const matchWorker = new MatchWorker(this.#compiler, this.#program, assertionNode);
5562
5593
  if (!(matcherNameText === "toBeInstantiableWith" || (matcherNameText === "toRaiseError" && !assertionNode.isNot)) &&
5563
5594
  this.#reject.argumentType([assertionNode.source[0], assertionNode.target?.[0]], onDiagnostics)) {
5564
5595
  return;
5565
5596
  }
5597
+ const matchWorker = new MatchWorker(this.#compiler, this.#program, assertionNode);
5566
5598
  switch (matcherNameText) {
5567
5599
  case "toAcceptProps":
5568
5600
  case "toBe":
@@ -5908,7 +5940,7 @@ class FileRunner {
5908
5940
  class Runner {
5909
5941
  #eventEmitter = new EventEmitter();
5910
5942
  #resolvedConfig;
5911
- static version = "7.2.0";
5943
+ static version = "7.2.1";
5912
5944
  constructor(resolvedConfig) {
5913
5945
  this.#resolvedConfig = resolvedConfig;
5914
5946
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tstyche",
3
- "version": "7.2.0",
3
+ "version": "7.2.1",
4
4
  "description": "Everything You Need for Type Testing.",
5
5
  "keywords": [
6
6
  "typescript",