tstyche 1.0.0-rc → 1.0.0-rc.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.0.0-rc.2] - 2024-02-14
4
+
5
+ ### Fixed
6
+
7
+ - Use the `isTypeRelatedTo()` method directly, to make strict subtype checks possible ([#127](https://github.com/tstyche/tstyche/pull/127), [#126](https://github.com/tstyche/tstyche/pull/126))
8
+
9
+ ## [1.0.0-rc.1] - 2024-02-10
10
+
11
+ ### Changed
12
+
13
+ - **Breaking!** Remove the `disableTestFileLookup` option in favor of `testFileMatch: []` ([#121](https://github.com/tstyche/tstyche/pull/121))
14
+
15
+ ### Added
16
+
17
+ - **New!** Set `module: "preserve"` in the default compiler options for inferred project that are using TypeScript 5.4 and up ([#111](https://github.com/tstyche/tstyche/pull/111))
18
+
19
+ ### Fixed
20
+
21
+ - Do not select test files, if `testFileMatch` is an empty list ([#120](https://github.com/tstyche/tstyche/pull/120))
22
+
3
23
  ## [1.0.0-rc] - 2024-01-28
4
24
 
5
25
  ### Changed
@@ -116,6 +136,8 @@
116
136
 
117
137
  _First pre-release._
118
138
 
139
+ [1.0.0-rc.2]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-rc.2
140
+ [1.0.0-rc.1]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-rc.1
119
141
  [1.0.0-rc]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-rc
120
142
  [1.0.0-beta.9]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.9
121
143
  [1.0.0-beta.8]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.8
package/README.md CHANGED
@@ -4,6 +4,7 @@
4
4
  [![license][license-badge]][license-url]
5
5
  [![packagephobia][packagephobia-badge]][packagephobia-url]
6
6
  [![coverage][coverage-badge]][coverage-url]
7
+ [![discord][discord-badge]][discord-url]
7
8
 
8
9
  The Essential Type Testing Tool.
9
10
 
@@ -75,6 +76,10 @@ This simple!
75
76
 
76
77
  Visit [https://tstyche.org](https://tstyche.org) to view the full documentation.
77
78
 
79
+ ## Feedback
80
+
81
+ If you have any questions or suggestions, [start a discussion](https://github.com/tstyche/tstyche/discussions/new/choose) or [open an issue](https://github.com/tstyche/tstyche/issues/new/choose) on GitHub. Preferring a chat? Join our [Discord server][discord-url].
82
+
78
83
  ## License
79
84
 
80
85
  [MIT][license-url] © TSTyche
@@ -85,5 +90,7 @@ Visit [https://tstyche.org](https://tstyche.org) to view the full documentation.
85
90
  [license-url]: https://github.com/tstyche/tstyche/blob/main/LICENSE.md
86
91
  [packagephobia-badge]: https://badgen.net/packagephobia/install/tstyche
87
92
  [packagephobia-url]: https://packagephobia.com/result?p=tstyche
88
- [coverage-badge]: https://badgen.net/codecov/c/github/tstyche/tstyche
89
- [coverage-url]: https://app.codecov.io/gh/tstyche/tstyche
93
+ [coverage-badge]: https://badgen.net/codacy/coverage/a581ca5c323a455886b7bdd9623c4ec8
94
+ [coverage-url]: https://app.codacy.com/gh/tstyche/tstyche/coverage/dashboard
95
+ [discord-badge]: https://badgen.net/static/chat/on%20Discord
96
+ [discord-url]: https://discord.gg/gCSasd3QJq
@@ -139,10 +139,6 @@ interface CommandLineOptions {
139
139
  * Options loaded from the configuration file.
140
140
  */
141
141
  interface ConfigFileOptions {
142
- /**
143
- * Do not search for the test files.
144
- */
145
- disableTestFileLookup?: boolean;
146
142
  /**
147
143
  * Stop running tests after the first failed assertion.
148
144
  */
@@ -183,7 +179,7 @@ declare class ConfigService {
183
179
  declare class TSTyche {
184
180
  #private;
185
181
  readonly resolvedConfig: ResolvedConfig;
186
- static readonly version = "__version__";
182
+ static readonly version = "1.0.0-rc.2";
187
183
  constructor(resolvedConfig: ResolvedConfig, storeService: StoreService);
188
184
  run(testFiles: Array<string | URL>): Promise<void>;
189
185
  }
@@ -445,10 +441,14 @@ interface MatchResult {
445
441
  explain: () => Array<Diagnostic>;
446
442
  isMatch: boolean;
447
443
  }
444
+ type Relation = Map<string, unknown>;
448
445
  interface TypeChecker extends ts.TypeChecker {
449
- isTypeAssignableTo: (source: ts.Type, target: ts.Type) => boolean;
450
- isTypeIdenticalTo: (source: ts.Type, target: ts.Type) => boolean;
451
- isTypeSubtypeOf: (source: ts.Type, target: ts.Type) => boolean;
446
+ isTypeRelatedTo: (source: ts.Type, target: ts.Type, relation: Relation) => boolean;
447
+ relation: {
448
+ assignable: Relation;
449
+ identity: Relation;
450
+ subtype: Relation;
451
+ };
452
452
  }
453
453
 
454
454
  declare class PrimitiveTypeMatcher {
package/build/tstyche.js CHANGED
@@ -1742,7 +1742,7 @@ class ToBeAssignable {
1742
1742
  : [Diagnostic.error(`Type '${targetTypeText}' is not assignable to type '${sourceTypeText}'.`)];
1743
1743
  }
1744
1744
  match(sourceType, targetType, isNot) {
1745
- const isMatch = this.typeChecker.isTypeAssignableTo(targetType, sourceType);
1745
+ const isMatch = this.typeChecker.isTypeRelatedTo(targetType, sourceType, this.typeChecker.relation.assignable);
1746
1746
  return {
1747
1747
  explain: () => this.#explain(sourceType, targetType, isNot),
1748
1748
  isMatch,
@@ -1763,7 +1763,7 @@ class ToEqual {
1763
1763
  : [Diagnostic.error(`Type '${targetTypeText}' is not identical to type '${sourceTypeText}'.`)];
1764
1764
  }
1765
1765
  match(sourceType, targetType, isNot) {
1766
- const isMatch = this.typeChecker.isTypeIdenticalTo(sourceType, targetType);
1766
+ const isMatch = this.typeChecker.isTypeRelatedTo(sourceType, targetType, this.typeChecker.relation.identity);
1767
1767
  return {
1768
1768
  explain: () => this.#explain(sourceType, targetType, isNot),
1769
1769
  isMatch,
@@ -1825,7 +1825,7 @@ class ToMatch {
1825
1825
  : [Diagnostic.error(`Type '${targetTypeText}' is not a subtype of type '${sourceTypeText}'.`)];
1826
1826
  }
1827
1827
  match(sourceType, targetType, isNot) {
1828
- const isMatch = this.typeChecker.isTypeSubtypeOf(sourceType, targetType);
1828
+ const isMatch = this.typeChecker.isTypeRelatedTo(sourceType, targetType, this.typeChecker.relation.subtype);
1829
1829
  return {
1830
1830
  explain: () => this.#explain(sourceType, targetType, isNot),
1831
1831
  isMatch,
@@ -1971,7 +1971,7 @@ class Expect {
1971
1971
  this.toRaiseError = new ToRaiseError(this.compiler, this.typeChecker);
1972
1972
  }
1973
1973
  static assertTypeChecker(typeChecker) {
1974
- return ("isTypeAssignableTo" in typeChecker && "isTypeIdenticalTo" in typeChecker && "isTypeSubtypeOf" in typeChecker);
1974
+ return ("isTypeRelatedTo" in typeChecker && "relation" in typeChecker);
1975
1975
  }
1976
1976
  #getType(node) {
1977
1977
  return this.compiler.isExpression(node)
@@ -2030,7 +2030,7 @@ class Expect {
2030
2030
  const sourceType = this.#getType(assertion.source[0]);
2031
2031
  const nonPrimitiveType = { flags: this.compiler.TypeFlags.NonPrimitive };
2032
2032
  if (sourceType.flags & (this.compiler.TypeFlags.Any | this.compiler.TypeFlags.Never)
2033
- || !this.typeChecker.isTypeAssignableTo(sourceType, nonPrimitiveType)) {
2033
+ || !this.typeChecker.isTypeRelatedTo(sourceType, nonPrimitiveType, this.typeChecker.relation.assignable)) {
2034
2034
  this.#onSourceArgumentMustBeObjectType(assertion.source[0], expectResult);
2035
2035
  return;
2036
2036
  }
@@ -2254,7 +2254,10 @@ class ProjectService {
2254
2254
  strictNullChecks: true,
2255
2255
  target: "esnext",
2256
2256
  };
2257
- if (Version.isSatisfiedWith(this.compiler.version, "5")) {
2257
+ if (Version.isSatisfiedWith(this.compiler.version, "5.4")) {
2258
+ defaultCompilerOptions.module = "preserve";
2259
+ }
2260
+ if (Version.isSatisfiedWith(this.compiler.version, "5.0")) {
2258
2261
  defaultCompilerOptions["allowImportingTsExtensions"] = true;
2259
2262
  defaultCompilerOptions.moduleResolution = "bundler";
2260
2263
  }
@@ -2525,7 +2528,7 @@ class TestFileRunner {
2525
2528
  }
2526
2529
  const typeChecker = program.getTypeChecker();
2527
2530
  if (!Expect.assertTypeChecker(typeChecker)) {
2528
- const text = "The required 'isTypeAssignableTo()', 'isTypeIdenticalTo()' and 'isTypeSubtypeOf()' methods are missing in the provided type checker.";
2531
+ const text = "The required 'isTypeRelatedTo()' method is missing in the provided type checker.";
2529
2532
  EventEmitter.dispatch(["file:error", { diagnostics: [Diagnostic.error(text)], result: fileResult }]);
2530
2533
  return;
2531
2534
  }
@@ -2577,7 +2580,7 @@ class TSTyche {
2577
2580
  #abortController = new AbortController();
2578
2581
  #storeService;
2579
2582
  #taskRunner;
2580
- static version = "1.0.0-rc";
2583
+ static version = "1.0.0-rc.2";
2581
2584
  constructor(resolvedConfig, storeService) {
2582
2585
  this.resolvedConfig = resolvedConfig;
2583
2586
  this.#storeService = storeService;
@@ -2588,12 +2591,11 @@ class TSTyche {
2588
2591
  EventEmitter.addHandler(([eventName, payload]) => {
2589
2592
  if (eventName.includes("error") || eventName.includes("fail")) {
2590
2593
  if ("diagnostics" in payload
2591
- && !payload.diagnostics.some(({ category }) => category === "error")) {
2592
- return;
2593
- }
2594
- process.exitCode = 1;
2595
- if (this.resolvedConfig.failFast) {
2596
- this.#abortController.abort();
2594
+ && payload.diagnostics.some((diagnostic) => diagnostic.category === "error")) {
2595
+ process.exitCode = 1;
2596
+ if (this.resolvedConfig.failFast) {
2597
+ this.#abortController.abort();
2598
+ }
2597
2599
  }
2598
2600
  }
2599
2601
  });
@@ -2628,12 +2630,6 @@ class OptionDefinitionsMap {
2628
2630
  group: 2,
2629
2631
  name: "config",
2630
2632
  },
2631
- {
2632
- brand: "boolean",
2633
- description: "Do not search for the test files.",
2634
- group: 4,
2635
- name: "disableTestFileLookup",
2636
- },
2637
2633
  {
2638
2634
  brand: "boolean",
2639
2635
  description: "Stop running tests after the first failed assertion.",
@@ -3114,7 +3110,6 @@ class ConfigService {
3114
3110
  #commandLineOptions = {};
3115
3111
  #configFileOptions = {};
3116
3112
  static #defaultOptions = {
3117
- disableTestFileLookup: false,
3118
3113
  failFast: false,
3119
3114
  rootPath: Path.resolve("./"),
3120
3115
  target: [Environment.typescriptPath == null ? "latest" : "current"],
@@ -3535,10 +3530,14 @@ class StoreService {
3535
3530
  const candidatePaths = [Path.join(Path.dirname(modulePath), "tsserverlibrary.js"), modulePath];
3536
3531
  for (const candidatePath of candidatePaths) {
3537
3532
  const sourceText = await fs.readFile(candidatePath, { encoding: "utf8" });
3538
- const modifiedSourceText = sourceText.replace("return checker;", "return { ...checker, isTypeIdenticalTo, isTypeSubtypeOf };");
3539
- if (modifiedSourceText.length === sourceText.length) {
3533
+ if (!sourceText.includes("isTypeRelatedTo")) {
3540
3534
  continue;
3541
3535
  }
3536
+ const toExpose = [
3537
+ "isTypeRelatedTo",
3538
+ "relation: { assignable: assignableRelation, identity: identityRelation, subtype: strictSubtypeRelation }",
3539
+ ];
3540
+ const modifiedSourceText = sourceText.replace("return checker;", `return { ...checker, ${toExpose.join(", ")} };`);
3542
3541
  const compiledWrapper = vm.compileFunction(modifiedSourceText, ["exports", "require", "module", "__filename", "__dirname"], { filename: candidatePath });
3543
3542
  compiledWrapper(exports, createRequire(candidatePath), module, candidatePath, Path.dirname(candidatePath));
3544
3543
  break;
@@ -3595,7 +3594,6 @@ class StoreService {
3595
3594
  }
3596
3595
 
3597
3596
  class Cli {
3598
- #abortController = new AbortController();
3599
3597
  #logger;
3600
3598
  #storeService;
3601
3599
  constructor() {
@@ -3612,7 +3610,6 @@ class Cli {
3612
3610
  for (const diagnostic of payload.diagnostics) {
3613
3611
  switch (diagnostic.category) {
3614
3612
  case "error":
3615
- this.#abortController.abort();
3616
3613
  process.exitCode = 1;
3617
3614
  this.#logger.writeError(diagnosticText(diagnostic));
3618
3615
  break;
@@ -3640,10 +3637,10 @@ class Cli {
3640
3637
  return;
3641
3638
  }
3642
3639
  if (commandLineArguments.includes("--update")) {
3643
- await this.#storeService.update(this.#abortController.signal);
3640
+ await this.#storeService.update();
3644
3641
  return;
3645
3642
  }
3646
- const compiler = await this.#storeService.load(Environment.typescriptPath == null ? "latest" : "current", this.#abortController.signal);
3643
+ const compiler = await this.#storeService.load(Environment.typescriptPath == null ? "latest" : "current");
3647
3644
  if (!compiler) {
3648
3645
  return;
3649
3646
  }
@@ -3670,12 +3667,12 @@ class Cli {
3670
3667
  }
3671
3668
  if (configService.commandLineOptions.install === true) {
3672
3669
  for (const tag of resolvedConfig.target) {
3673
- await this.#storeService.install(tag, this.#abortController.signal);
3670
+ await this.#storeService.install(tag);
3674
3671
  }
3675
3672
  return;
3676
3673
  }
3677
3674
  let testFiles = [];
3678
- if (!resolvedConfig.disableTestFileLookup) {
3675
+ if (resolvedConfig.testFileMatch.length !== 0) {
3679
3676
  testFiles = configService.selectTestFiles();
3680
3677
  if (testFiles.length === 0) {
3681
3678
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tstyche",
3
- "version": "1.0.0-rc",
3
+ "version": "1.0.0-rc.2",
4
4
  "description": "The Essential Type Testing Tool.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -17,6 +17,7 @@
17
17
  "type": "git",
18
18
  "url": "git+https://github.com/tstyche/tstyche.git"
19
19
  },
20
+ "funding": "https://github.com/tstyche/tstyche?sponsor=1",
20
21
  "license": "MIT",
21
22
  "type": "module",
22
23
  "exports": {
@@ -37,15 +38,15 @@
37
38
  "bench": "./benchmarks/tstyche.bench.sh",
38
39
  "build": "rollup --config rollup.config.js",
39
40
  "build:watch": "yarn build --sourcemap --watch",
40
- "clean": "rm -rf build",
41
- "generate": "yarn generate:schema && yarn generate:types",
42
- "generate:schema": "node ./models/__scripts__/generate-schema.js",
43
- "generate:types": "node ./models/__scripts__/generate-types.js",
44
41
  "check": "yarn check:spelling && yarn check:formatting",
45
- "check:spelling": "cspell --config cspell.config.json --quiet",
46
42
  "check:formatting": "dprint check",
43
+ "check:spelling": "cspell --config cspell.config.json --quiet",
47
44
  "check:types": "tsc --noEmit --project tsconfig.json",
45
+ "clean": "rm -rf build",
48
46
  "format": "dprint fmt",
47
+ "generate": "yarn generate:schema && yarn generate:types",
48
+ "generate:schema": "node ./models/__scripts__/generate-schema.js",
49
+ "generate:types": "node ./models/__scripts__/generate-types.js",
49
50
  "lint": "eslint ./ --config eslint.config.json --ext .js,.cts,.ts,.tsx",
50
51
  "prepack": "yarn clean && yarn build",
51
52
  "prepublish": "yarn test",
@@ -59,9 +60,9 @@
59
60
  "devDependencies": {
60
61
  "@jest/globals": "29.7.0",
61
62
  "@rollup/plugin-typescript": "11.1.6",
62
- "@types/node": "20.11.8",
63
- "@typescript-eslint/eslint-plugin": "6.19.1",
64
- "@typescript-eslint/parser": "6.19.1",
63
+ "@types/node": "20.11.17",
64
+ "@typescript-eslint/eslint-plugin": "7.0.1",
65
+ "@typescript-eslint/parser": "7.0.1",
65
66
  "ajv": "8.12.0",
66
67
  "c8": "9.1.0",
67
68
  "cspell": "8.3.2",
@@ -69,13 +70,13 @@
69
70
  "eslint": "8.56.0",
70
71
  "eslint-import-resolver-typescript": "3.6.1",
71
72
  "eslint-plugin-import": "2.29.1",
72
- "eslint-plugin-jest": "27.6.3",
73
+ "eslint-plugin-jest": "27.8.0",
73
74
  "eslint-plugin-jest-formatting": "3.1.0",
74
- "eslint-plugin-simple-import-sort": "10.0.0",
75
+ "eslint-plugin-simple-import-sort": "12.0.0",
75
76
  "jest": "29.7.0",
76
77
  "jest-serializer-ansi-escapes": "2.0.1",
77
- "magic-string": "0.30.5",
78
- "rollup": "4.9.6",
78
+ "magic-string": "0.30.7",
79
+ "rollup": "4.10.0",
79
80
  "rollup-plugin-dts": "6.1.0",
80
81
  "ts-node": "10.9.2",
81
82
  "tslib": "2.6.2",
@@ -89,7 +90,7 @@
89
90
  "optional": true
90
91
  }
91
92
  },
92
- "packageManager": "yarn@3.7.0",
93
+ "packageManager": "yarn@3.8.0",
93
94
  "engines": {
94
95
  "node": "^16.14 || 18.x || >=20.x"
95
96
  }