tstyche 3.0.0-rc.1 → 3.0.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.
@@ -558,6 +558,7 @@ interface MatchResult {
558
558
  }
559
559
  type Relation = Map<string, unknown>;
560
560
  interface TypeChecker extends ts.TypeChecker {
561
+ isApplicableIndexType: (source: ts.Type, target: ts.Type) => boolean;
561
562
  isTypeRelatedTo: (source: ts.Type, target: ts.Type, relation: Relation) => boolean;
562
563
  relation: {
563
564
  assignable: Relation;
package/build/tstyche.js CHANGED
@@ -701,22 +701,23 @@ class Store {
701
701
  static async #loadModule(modulePath) {
702
702
  const exports = {};
703
703
  const module = { exports };
704
- const candidatePaths = [Path.join(Path.dirname(modulePath), "tsserverlibrary.js"), modulePath];
705
- for (const candidatePath of candidatePaths) {
706
- const sourceText = await fs.readFile(candidatePath, { encoding: "utf8" });
707
- if (!sourceText.includes("isTypeRelatedTo")) {
708
- continue;
709
- }
710
- const toExpose = [
711
- "getTypeOfSymbol",
712
- "isTypeRelatedTo",
713
- "relation: { assignable: assignableRelation, identity: identityRelation, subtype: strictSubtypeRelation }",
714
- ];
715
- const modifiedSourceText = sourceText.replace("return checker;", `return { ...checker, ${toExpose.join(", ")} };`);
716
- const compiledWrapper = vm.compileFunction(modifiedSourceText, ["exports", "require", "module", "__filename", "__dirname"], { filename: candidatePath });
717
- compiledWrapper(exports, createRequire(candidatePath), module, candidatePath, Path.dirname(candidatePath));
718
- break;
719
- }
704
+ const packageConfigText = await fs.readFile(Path.resolve(modulePath, "../../package.json"), { encoding: "utf8" });
705
+ const { version: packageVersion } = JSON.parse(packageConfigText);
706
+ if (!Version.isSatisfiedWith(packageVersion, "5.3")) {
707
+ modulePath = Path.resolve(modulePath, "../tsserverlibrary.js");
708
+ }
709
+ const sourceText = await fs.readFile(modulePath, { encoding: "utf8" });
710
+ const toExpose = [];
711
+ if (Version.isSatisfiedWith(packageVersion, "4.4")) {
712
+ toExpose.push("isApplicableIndexType");
713
+ }
714
+ if (!Version.isSatisfiedWith(packageVersion, "4.6")) {
715
+ toExpose.push("getTypeOfSymbol");
716
+ }
717
+ toExpose.push("isTypeRelatedTo", "relation: { assignable: assignableRelation, identity: identityRelation, subtype: strictSubtypeRelation }");
718
+ const modifiedSourceText = sourceText.replace("return checker;", `return { ...checker, ${toExpose.join(", ")} };`);
719
+ const compiledWrapper = vm.compileFunction(modifiedSourceText, ["exports", "require", "module", "__filename", "__dirname"], { filename: modulePath });
720
+ compiledWrapper(exports, createRequire(modulePath), module, modulePath, Path.dirname(modulePath));
720
721
  return module.exports;
721
722
  }
722
723
  static #onDiagnostics(diagnostic) {
@@ -3282,6 +3283,28 @@ class MatchWorker {
3282
3283
  this.#typeChecker = typeChecker;
3283
3284
  this.assertion = assertion;
3284
3285
  }
3286
+ checkHasApplicableIndexType(sourceNode, targetNode) {
3287
+ const sourceType = this.getType(sourceNode);
3288
+ const targetType = this.getType(targetNode);
3289
+ if (Version.isSatisfiedWith(this.#compiler.version, "4.4")) {
3290
+ return this.#typeChecker
3291
+ .getIndexInfosOfType(sourceType)
3292
+ .some(({ keyType }) => this.#typeChecker.isApplicableIndexType(targetType, keyType));
3293
+ }
3294
+ if (targetType.flags & this.#compiler.TypeFlags.StringLiteral) {
3295
+ return sourceType.getStringIndexType() != null;
3296
+ }
3297
+ if (targetType.flags & this.#compiler.TypeFlags.NumberLiteral) {
3298
+ return (sourceType.getStringIndexType() ?? sourceType.getNumberIndexType()) != null;
3299
+ }
3300
+ return false;
3301
+ }
3302
+ checkHasProperty(sourceNode, propertyNameText) {
3303
+ const sourceType = this.getType(sourceNode);
3304
+ return sourceType
3305
+ .getProperties()
3306
+ .some((property) => this.#compiler.unescapeLeadingUnderscores(property.escapedName) === propertyNameText);
3307
+ }
3285
3308
  checkIsAssignableTo(sourceNode, targetNode) {
3286
3309
  const relation = this.#typeChecker.relation.assignable;
3287
3310
  return this.#checkIsRelatedTo(sourceNode, targetNode, relation);
@@ -3656,7 +3679,7 @@ class ToHaveProperty {
3656
3679
  diagnostics.push(Diagnostic.error(text, origin));
3657
3680
  }
3658
3681
  const targetType = matchWorker.getType(targetNode);
3659
- let propertyNameText;
3682
+ let propertyNameText = "";
3660
3683
  if (matchWorker.isStringOrNumberLiteralType(targetType)) {
3661
3684
  propertyNameText = targetType.value.toString();
3662
3685
  }
@@ -3673,9 +3696,8 @@ class ToHaveProperty {
3673
3696
  onDiagnostics(diagnostics);
3674
3697
  return;
3675
3698
  }
3676
- const isMatch = sourceType.getProperties().some((property) => {
3677
- return this.#compiler.unescapeLeadingUnderscores(property.escapedName) === propertyNameText;
3678
- });
3699
+ const isMatch = matchWorker.checkHasProperty(sourceNode, propertyNameText) ||
3700
+ matchWorker.checkHasApplicableIndexType(sourceNode, targetNode);
3679
3701
  return {
3680
3702
  explain: () => this.#explain(matchWorker, sourceNode, targetNode),
3681
3703
  isMatch,
@@ -4115,7 +4137,7 @@ class TaskRunner {
4115
4137
  class Runner {
4116
4138
  #eventEmitter = new EventEmitter();
4117
4139
  #resolvedConfig;
4118
- static version = "3.0.0-rc.1";
4140
+ static version = "3.0.0";
4119
4141
  constructor(resolvedConfig) {
4120
4142
  this.#resolvedConfig = resolvedConfig;
4121
4143
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tstyche",
3
- "version": "3.0.0-rc.1",
3
+ "version": "3.0.0",
4
4
  "description": "The Essential Type Testing Tool.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -63,16 +63,16 @@
63
63
  "devDependencies": {
64
64
  "@biomejs/biome": "1.9.4",
65
65
  "@rollup/plugin-typescript": "12.1.1",
66
- "@types/node": "22.8.5",
66
+ "@types/node": "22.9.0",
67
67
  "@types/react": "18.3.12",
68
68
  "ajv": "8.17.1",
69
- "cspell": "8.15.5",
69
+ "cspell": "8.15.7",
70
70
  "magic-string": "0.30.12",
71
71
  "monocart-coverage-reports": "2.11.1",
72
72
  "pretty-ansi": "2.0.0",
73
- "rollup": "4.24.3",
73
+ "rollup": "4.24.4",
74
74
  "rollup-plugin-dts": "6.1.1",
75
- "tslib": "2.8.0",
75
+ "tslib": "2.8.1",
76
76
  "typescript": "5.6.3"
77
77
  },
78
78
  "peerDependencies": {