tstyche 1.0.0-rc.2 → 1.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
@@ -2,7 +2,8 @@
2
2
 
3
3
  [![version][version-badge]][version-url]
4
4
  [![license][license-badge]][license-url]
5
- [![packagephobia][packagephobia-badge]][packagephobia-url]
5
+ [![requirements][requirements-badge]][requirements-url]
6
+ [![install-size][install-size-badge]][install-size-url]
6
7
  [![coverage][coverage-badge]][coverage-url]
7
8
  [![discord][discord-badge]][discord-url]
8
9
 
@@ -88,8 +89,10 @@ If you have any questions or suggestions, [start a discussion](https://github.co
88
89
  [version-url]: https://npmjs.com/package/tstyche
89
90
  [license-badge]: https://badgen.net/github/license/tstyche/tstyche
90
91
  [license-url]: https://github.com/tstyche/tstyche/blob/main/LICENSE.md
91
- [packagephobia-badge]: https://badgen.net/packagephobia/install/tstyche
92
- [packagephobia-url]: https://packagephobia.com/result?p=tstyche
92
+ [requirements-badge]: https://badgen.net/npm/node/tstyche
93
+ [requirements-url]: https://tstyche.org/reference/requirements
94
+ [install-size-badge]: https://badgen.net/install-size/install/tstyche
95
+ [install-size-url]: https://install-size.com/result?p=tstyche
93
96
  [coverage-badge]: https://badgen.net/codacy/coverage/a581ca5c323a455886b7bdd9623c4ec8
94
97
  [coverage-url]: https://app.codacy.com/gh/tstyche/tstyche/coverage/dashboard
95
98
  [discord-badge]: https://badgen.net/static/chat/on%20Discord
package/build/index.d.cts CHANGED
@@ -77,47 +77,47 @@ interface Matchers {
77
77
  (target: unknown): void;
78
78
  };
79
79
  /**
80
- * Checks if the `bigint` type is identical to the source type.
80
+ * Checks if the source type is `bigint`.
81
81
  */
82
82
  toBeBigInt: () => void;
83
83
  /**
84
- * Checks if the `boolean` type is identical to the source type.
84
+ * Checks if the source type is `boolean`.
85
85
  */
86
86
  toBeBoolean: () => void;
87
87
  /**
88
- * Checks if the `never` type is identical to the source type.
88
+ * Checks if the source type is `never`.
89
89
  */
90
90
  toBeNever: () => void;
91
91
  /**
92
- * Checks if the `null` type is identical to the source type.
92
+ * Checks if the source type is `null`.
93
93
  */
94
94
  toBeNull: () => void;
95
95
  /**
96
- * Checks if the `number` type is identical to the source type.
96
+ * Checks if the source type is `number`.
97
97
  */
98
98
  toBeNumber: () => void;
99
99
  /**
100
- * Checks if the `string` type is identical to the source type.
100
+ * Checks if the source type is `string`.
101
101
  */
102
102
  toBeString: () => void;
103
103
  /**
104
- * Checks if the `symbol` type is identical to the source type.
104
+ * Checks if the source type is `symbol`.
105
105
  */
106
106
  toBeSymbol: () => void;
107
107
  /**
108
- * Checks if the `undefined` type is identical to the source type.
108
+ * Checks if the source type is `undefined`.
109
109
  */
110
110
  toBeUndefined: () => void;
111
111
  /**
112
- * Checks if the `unique symbol` type is identical to the source type.
112
+ * Checks if the source type is `unique symbol`.
113
113
  */
114
114
  toBeUniqueSymbol: () => void;
115
115
  /**
116
- * Checks if the `unknown` type is identical to the source type.
116
+ * Checks if the source type is `unknown`.
117
117
  */
118
118
  toBeUnknown: () => void;
119
119
  /**
120
- * Checks if the `void` type is identical to the source type.
120
+ * Checks if the source type is `void`.
121
121
  */
122
122
  toBeVoid: () => void;
123
123
  /**
package/build/index.d.ts CHANGED
@@ -77,47 +77,47 @@ interface Matchers {
77
77
  (target: unknown): void;
78
78
  };
79
79
  /**
80
- * Checks if the `bigint` type is identical to the source type.
80
+ * Checks if the source type is `bigint`.
81
81
  */
82
82
  toBeBigInt: () => void;
83
83
  /**
84
- * Checks if the `boolean` type is identical to the source type.
84
+ * Checks if the source type is `boolean`.
85
85
  */
86
86
  toBeBoolean: () => void;
87
87
  /**
88
- * Checks if the `never` type is identical to the source type.
88
+ * Checks if the source type is `never`.
89
89
  */
90
90
  toBeNever: () => void;
91
91
  /**
92
- * Checks if the `null` type is identical to the source type.
92
+ * Checks if the source type is `null`.
93
93
  */
94
94
  toBeNull: () => void;
95
95
  /**
96
- * Checks if the `number` type is identical to the source type.
96
+ * Checks if the source type is `number`.
97
97
  */
98
98
  toBeNumber: () => void;
99
99
  /**
100
- * Checks if the `string` type is identical to the source type.
100
+ * Checks if the source type is `string`.
101
101
  */
102
102
  toBeString: () => void;
103
103
  /**
104
- * Checks if the `symbol` type is identical to the source type.
104
+ * Checks if the source type is `symbol`.
105
105
  */
106
106
  toBeSymbol: () => void;
107
107
  /**
108
- * Checks if the `undefined` type is identical to the source type.
108
+ * Checks if the source type is `undefined`.
109
109
  */
110
110
  toBeUndefined: () => void;
111
111
  /**
112
- * Checks if the `unique symbol` type is identical to the source type.
112
+ * Checks if the source type is `unique symbol`.
113
113
  */
114
114
  toBeUniqueSymbol: () => void;
115
115
  /**
116
- * Checks if the `unknown` type is identical to the source type.
116
+ * Checks if the source type is `unknown`.
117
117
  */
118
118
  toBeUnknown: () => void;
119
119
  /**
120
- * Checks if the `void` type is identical to the source type.
120
+ * Checks if the source type is `void`.
121
121
  */
122
122
  toBeVoid: () => void;
123
123
  /**
@@ -12,7 +12,6 @@ interface DiagnosticOrigin {
12
12
  start: number;
13
13
  }
14
14
  declare class Diagnostic {
15
- #private;
16
15
  text: string | Array<string>;
17
16
  category: DiagnosticCategory;
18
17
  origin?: DiagnosticOrigin | undefined;
@@ -31,17 +30,23 @@ declare class Diagnostic {
31
30
  static warning(text: string | Array<string>, origin?: DiagnosticOrigin): Diagnostic;
32
31
  }
33
32
 
33
+ declare class CancellationToken {
34
+ #private;
35
+ get isCancellationRequested(): boolean;
36
+ cancel(): void;
37
+ }
38
+
34
39
  declare class StoreService {
35
40
  #private;
36
41
  constructor();
37
- getSupportedTags(signal?: AbortSignal): Promise<Array<string>>;
38
- install(tag: string, signal?: AbortSignal): Promise<string | undefined>;
39
- load(tag: string, signal?: AbortSignal): Promise<typeof ts | undefined>;
40
- open(signal?: AbortSignal): Promise<void>;
42
+ getSupportedTags(): Promise<Array<string>>;
43
+ install(tag: string, cancellationToken?: CancellationToken): Promise<string | undefined>;
44
+ load(tag: string, cancellationToken?: CancellationToken): Promise<typeof ts | undefined>;
45
+ open(): Promise<void>;
41
46
  prune: () => Promise<void>;
42
- resolveTag(tag: string, signal?: AbortSignal): Promise<string | undefined>;
43
- update(signal?: AbortSignal): Promise<void>;
44
- validateTag(tag: string, signal?: AbortSignal): Promise<boolean>;
47
+ resolveTag(tag: string): Promise<string | undefined>;
48
+ update(): Promise<void>;
49
+ validateTag(tag: string): Promise<boolean | undefined>;
45
50
  }
46
51
 
47
52
  declare enum OptionBrand {
@@ -51,7 +56,6 @@ declare enum OptionBrand {
51
56
  True = "true",// an option which does not take a value
52
57
  List = "list"
53
58
  }
54
-
55
59
  declare enum OptionGroup {
56
60
  CommandLine = 2,
57
61
  ConfigFile = 4
@@ -179,7 +183,7 @@ declare class ConfigService {
179
183
  declare class TSTyche {
180
184
  #private;
181
185
  readonly resolvedConfig: ResolvedConfig;
182
- static readonly version = "1.0.0-rc.2";
186
+ static readonly version = "1.1.0";
183
187
  constructor(resolvedConfig: ResolvedConfig, storeService: StoreService);
184
188
  run(testFiles: Array<string | URL>): Promise<void>;
185
189
  }
@@ -195,7 +199,6 @@ declare enum TestMemberBrand {
195
199
  Test = "test",
196
200
  Expect = "expect"
197
201
  }
198
-
199
202
  declare enum TestMemberFlags {
200
203
  None = 0,
201
204
  Fail = 1,
@@ -282,7 +285,6 @@ declare class ResultTiming {
282
285
  get duration(): number;
283
286
  }
284
287
 
285
- type FileResultStatus = ResultStatus.Runs | ResultStatus.Passed | ResultStatus.Failed;
286
288
  declare enum ResultStatus {
287
289
  Runs = "runs",
288
290
  Passed = "passed",
@@ -327,6 +329,7 @@ declare class DescribeResult {
327
329
  constructor(describe: TestMember, parent: DescribeResult | undefined);
328
330
  }
329
331
 
332
+ type FileResultStatus = ResultStatus.Runs | ResultStatus.Passed | ResultStatus.Failed;
330
333
  declare class FileResult {
331
334
  testFile: URL;
332
335
  diagnostics: Array<Diagnostic>;
@@ -346,11 +349,12 @@ declare class ProjectResult {
346
349
  constructor(compilerVersion: string, projectConfigFilePath: string | undefined);
347
350
  }
348
351
 
352
+ type TargetResultStatus = ResultStatus.Runs | ResultStatus.Passed | ResultStatus.Failed;
349
353
  declare class TargetResult {
350
354
  versionTag: string;
351
355
  testFiles: Array<URL>;
352
356
  results: Map<string | undefined, ProjectResult>;
353
- status: ResultStatus.Runs | ResultStatus.Passed | ResultStatus.Failed;
357
+ status: TargetResultStatus;
354
358
  timing: ResultTiming;
355
359
  constructor(versionTag: string, testFiles: Array<URL>);
356
360
  }
@@ -454,24 +458,30 @@ interface TypeChecker extends ts.TypeChecker {
454
458
  declare class PrimitiveTypeMatcher {
455
459
  #private;
456
460
  typeChecker: TypeChecker;
457
- constructor(typeChecker: TypeChecker, targetTypeFlag: ts.TypeFlags, targetTypeText: string);
458
- match(sourceType: ts.Type, isNot: boolean): MatchResult;
461
+ constructor(typeChecker: TypeChecker, targetTypeFlag: ts.TypeFlags);
462
+ match(sourceType: ts.Type): MatchResult;
459
463
  }
460
464
 
461
- declare class ToBeAssignable {
462
- #private;
465
+ declare abstract class RelationMatcherBase {
463
466
  typeChecker: TypeChecker;
467
+ abstract relation: Relation;
468
+ abstract relationExplanationText: string;
464
469
  constructor(typeChecker: TypeChecker);
470
+ protected explain(sourceType: ts.Type, targetType: ts.Type, isNot: boolean): Array<Diagnostic>;
465
471
  match(sourceType: ts.Type, targetType: ts.Type, isNot: boolean): MatchResult;
466
472
  }
467
473
 
468
- declare class ToEqual {
469
- #private;
470
- typeChecker: TypeChecker;
471
- constructor(typeChecker: TypeChecker);
474
+ declare class ToBeAssignable extends RelationMatcherBase {
475
+ relation: Relation;
476
+ relationExplanationText: string;
472
477
  match(sourceType: ts.Type, targetType: ts.Type, isNot: boolean): MatchResult;
473
478
  }
474
479
 
480
+ declare class ToEqual extends RelationMatcherBase {
481
+ relation: Relation;
482
+ relationExplanationText: string;
483
+ }
484
+
475
485
  declare class ToHaveProperty {
476
486
  #private;
477
487
  compiler: typeof ts;
@@ -480,11 +490,9 @@ declare class ToHaveProperty {
480
490
  match(sourceType: ts.Type, targetType: ts.StringLiteralType | ts.NumberLiteralType | ts.UniqueESSymbolType, isNot: boolean): MatchResult;
481
491
  }
482
492
 
483
- declare class ToMatch {
484
- #private;
485
- typeChecker: TypeChecker;
486
- constructor(typeChecker: TypeChecker);
487
- match(sourceType: ts.Type, targetType: ts.Type, isNot: boolean): MatchResult;
493
+ declare class ToMatch extends RelationMatcherBase {
494
+ relation: Relation;
495
+ relationExplanationText: string;
488
496
  }
489
497
 
490
498
  declare class ToRaiseError {
@@ -637,7 +645,7 @@ declare class TaskRunner {
637
645
  #private;
638
646
  readonly resolvedConfig: ResolvedConfig;
639
647
  constructor(resolvedConfig: ResolvedConfig, storeService: StoreService);
640
- run(testFiles: Array<URL>, target: Array<string>, signal?: AbortSignal): Promise<Result>;
648
+ run(testFiles: Array<URL>, target: Array<string>, cancellationToken?: CancellationToken): Promise<Result>;
641
649
  }
642
650
 
643
651
  declare enum Color {
@@ -746,4 +754,4 @@ declare class Version {
746
754
  static isVersionTag(target: string): boolean;
747
755
  }
748
756
 
749
- export { Assertion, Cli, CollectService, Color, type CommandLineOptions, type ConfigFileOptions, ConfigService, DescribeResult, Diagnostic, DiagnosticCategory, type DiagnosticOrigin, Environment, type Event, EventEmitter, type EventHandler, Expect, ExpectResult, FileResult, type FileResultStatus, type ItemDefinition, Line, Logger, type LoggerOptions, type MatchResult, OptionBrand, type OptionDefinition, OptionDefinitionsMap, OptionGroup, Path, ProjectResult, ProjectService, Reporter, type ResolvedConfig, Result, ResultCount, ResultManager, ResultStatus, ResultTiming, Scribbler, type ScribblerOptions, StoreService, SummaryReporter, TSTyche, TargetResult, TaskRunner, TestMember, TestMemberBrand, TestMemberFlags, TestResult, TestTree, Text, ThoroughReporter, type TypeChecker, Version, type WriteStream, addsPackageStepText, describeNameText, diagnosticText, fileStatusText, fileViewText, formattedText, helpText, summaryText, testNameText, usesCompilerStepText };
757
+ export { Assertion, CancellationToken, Cli, CollectService, Color, type CommandLineOptions, type ConfigFileOptions, ConfigService, DescribeResult, Diagnostic, DiagnosticCategory, type DiagnosticOrigin, Environment, type Event, EventEmitter, type EventHandler, Expect, ExpectResult, FileResult, type FileResultStatus, type ItemDefinition, Line, Logger, type LoggerOptions, type MatchResult, OptionBrand, type OptionDefinition, OptionDefinitionsMap, OptionGroup, Path, ProjectResult, ProjectService, Reporter, type ResolvedConfig, Result, ResultCount, ResultManager, ResultStatus, ResultTiming, Scribbler, type ScribblerOptions, StoreService, SummaryReporter, TSTyche, TargetResult, type TargetResultStatus, TaskRunner, TestMember, TestMemberBrand, TestMemberFlags, TestResult, TestTree, Text, ThoroughReporter, type TypeChecker, Version, type WriteStream, addsPackageStepText, describeNameText, diagnosticText, fileStatusText, fileViewText, formattedText, helpText, summaryText, testNameText, usesCompilerStepText };
package/build/tstyche.js CHANGED
@@ -35,7 +35,7 @@ class Path {
35
35
  if (path.sep === "/") {
36
36
  return filePath;
37
37
  }
38
- return filePath.replaceAll("\\", "/");
38
+ return filePath.replace(/\\/g, "/");
39
39
  }
40
40
  static relative(from, to) {
41
41
  let relativePath = path.relative(from, to);
@@ -113,7 +113,7 @@ class Environment {
113
113
  }
114
114
  let resolvedPath;
115
115
  try {
116
- resolvedPath = createRequire(import.meta.url).resolve(moduleId);
116
+ resolvedPath = Path.normalizeSlashes(createRequire(import.meta.url).resolve(moduleId));
117
117
  }
118
118
  catch {
119
119
  }
@@ -154,7 +154,7 @@ class Scribbler {
154
154
  #indentEachLine(lines, level) {
155
155
  const indentStep = " ";
156
156
  const notEmptyLineRegExp = /^(?!$)/gm;
157
- return lines.replaceAll(notEmptyLineRegExp, indentStep.repeat(level));
157
+ return lines.replace(notEmptyLineRegExp, indentStep.repeat(level));
158
158
  }
159
159
  render(element) {
160
160
  if (element != null) {
@@ -320,7 +320,7 @@ class CodeSpanText {
320
320
  ? this.props.file.text.length
321
321
  : this.props.file.getPositionOfLineAndCharacter(index + 1, 0);
322
322
  const lineNumberText = String(index + 1);
323
- const lineText = this.props.file.text.slice(lineStart, lineEnd).trimEnd().replaceAll("\t", " ");
323
+ const lineText = this.props.file.text.slice(lineStart, lineEnd).trimEnd().replace(/\t/g, " ");
324
324
  if (index === markedLine) {
325
325
  codeSpan.push(Scribbler.createElement(Line, null,
326
326
  Scribbler.createElement(Text, { color: "31" }, ">"),
@@ -999,6 +999,15 @@ class DescribeResult {
999
999
  }
1000
1000
  }
1001
1001
 
1002
+ var ResultStatus;
1003
+ (function (ResultStatus) {
1004
+ ResultStatus["Runs"] = "runs";
1005
+ ResultStatus["Passed"] = "passed";
1006
+ ResultStatus["Failed"] = "failed";
1007
+ ResultStatus["Skipped"] = "skipped";
1008
+ ResultStatus["Todo"] = "todo";
1009
+ })(ResultStatus || (ResultStatus = {}));
1010
+
1002
1011
  class ExpectResult {
1003
1012
  assertion;
1004
1013
  parent;
@@ -1254,15 +1263,6 @@ class ResultManager {
1254
1263
  }
1255
1264
  }
1256
1265
 
1257
- var ResultStatus;
1258
- (function (ResultStatus) {
1259
- ResultStatus["Runs"] = "runs";
1260
- ResultStatus["Passed"] = "passed";
1261
- ResultStatus["Failed"] = "failed";
1262
- ResultStatus["Skipped"] = "skipped";
1263
- ResultStatus["Todo"] = "todo";
1264
- })(ResultStatus || (ResultStatus = {}));
1265
-
1266
1266
  class TargetResult {
1267
1267
  versionTag;
1268
1268
  testFiles;
@@ -1333,30 +1333,20 @@ class Diagnostic {
1333
1333
  }
1334
1334
  static fromError(text, error) {
1335
1335
  const messageText = Array.isArray(text) ? text : [text];
1336
- if (error instanceof Error) {
1337
- if (error.cause != null) {
1338
- messageText.push(this.#normalizeMessage(String(error.cause)));
1339
- }
1340
- messageText.push(this.#normalizeMessage(String(error.message)));
1341
- if (error.stack != null) {
1342
- const stackLines = error.stack
1343
- .split("\n")
1344
- .slice(1)
1345
- .map((line) => line.trimStart());
1346
- messageText.push(...stackLines);
1336
+ if (error instanceof Error && error.stack != null) {
1337
+ if (messageText.length > 1) {
1338
+ messageText.push("");
1347
1339
  }
1340
+ const stackLines = error.stack
1341
+ .split("\n")
1342
+ .map((line) => line.trimStart());
1343
+ messageText.push(...stackLines);
1348
1344
  }
1349
1345
  return Diagnostic.error(messageText);
1350
1346
  }
1351
1347
  static isTsDiagnosticWithLocation(diagnostic) {
1352
1348
  return diagnostic.file != null && diagnostic.start != null && diagnostic.length != null;
1353
1349
  }
1354
- static #normalizeMessage(text) {
1355
- if (text.endsWith(".")) {
1356
- return text;
1357
- }
1358
- return `${text}.`;
1359
- }
1360
1350
  static warning(text, origin) {
1361
1351
  return new Diagnostic(text, "warning", origin);
1362
1352
  }
@@ -1695,7 +1685,6 @@ var TestMemberBrand;
1695
1685
  TestMemberBrand["Test"] = "test";
1696
1686
  TestMemberBrand["Expect"] = "expect";
1697
1687
  })(TestMemberBrand || (TestMemberBrand = {}));
1698
-
1699
1688
  var TestMemberFlags;
1700
1689
  (function (TestMemberFlags) {
1701
1690
  TestMemberFlags[TestMemberFlags["None"] = 0] = "None";
@@ -1708,69 +1697,61 @@ var TestMemberFlags;
1708
1697
  class PrimitiveTypeMatcher {
1709
1698
  typeChecker;
1710
1699
  #targetTypeFlag;
1711
- #targetTypeText;
1712
- constructor(typeChecker, targetTypeFlag, targetTypeText) {
1700
+ constructor(typeChecker, targetTypeFlag) {
1713
1701
  this.typeChecker = typeChecker;
1714
1702
  this.#targetTypeFlag = targetTypeFlag;
1715
- this.#targetTypeText = targetTypeText;
1716
1703
  }
1717
- #explain(sourceType, isNot) {
1704
+ #explain(sourceType) {
1718
1705
  const sourceTypeText = this.typeChecker.typeToString(sourceType);
1719
- return isNot
1720
- ? [Diagnostic.error(`Type '${this.#targetTypeText}' is identical to type '${sourceTypeText}'.`)]
1721
- : [Diagnostic.error(`Type '${this.#targetTypeText}' is not identical to type '${sourceTypeText}'.`)];
1706
+ return [Diagnostic.error(`The source type is '${sourceTypeText}'.`)];
1722
1707
  }
1723
- match(sourceType, isNot) {
1708
+ match(sourceType) {
1724
1709
  const isMatch = Boolean(sourceType.flags & this.#targetTypeFlag);
1725
1710
  return {
1726
- explain: () => this.#explain(sourceType, isNot),
1711
+ explain: () => this.#explain(sourceType),
1727
1712
  isMatch,
1728
1713
  };
1729
1714
  }
1730
1715
  }
1731
1716
 
1732
- class ToBeAssignable {
1717
+ class RelationMatcherBase {
1733
1718
  typeChecker;
1734
1719
  constructor(typeChecker) {
1735
1720
  this.typeChecker = typeChecker;
1736
1721
  }
1737
- #explain(sourceType, targetType, isNot) {
1722
+ explain(sourceType, targetType, isNot) {
1738
1723
  const sourceTypeText = this.typeChecker.typeToString(sourceType);
1739
1724
  const targetTypeText = this.typeChecker.typeToString(targetType);
1740
1725
  return isNot
1741
- ? [Diagnostic.error(`Type '${targetTypeText}' is assignable to type '${sourceTypeText}'.`)]
1742
- : [Diagnostic.error(`Type '${targetTypeText}' is not assignable to type '${sourceTypeText}'.`)];
1726
+ ? [Diagnostic.error(`Type '${targetTypeText}' is ${this.relationExplanationText} type '${sourceTypeText}'.`)]
1727
+ : [Diagnostic.error(`Type '${targetTypeText}' is not ${this.relationExplanationText} type '${sourceTypeText}'.`)];
1743
1728
  }
1744
1729
  match(sourceType, targetType, isNot) {
1745
- const isMatch = this.typeChecker.isTypeRelatedTo(targetType, sourceType, this.typeChecker.relation.assignable);
1730
+ const isMatch = this.typeChecker.isTypeRelatedTo(sourceType, targetType, this.relation);
1746
1731
  return {
1747
- explain: () => this.#explain(sourceType, targetType, isNot),
1732
+ explain: () => this.explain(sourceType, targetType, isNot),
1748
1733
  isMatch,
1749
1734
  };
1750
1735
  }
1751
1736
  }
1752
1737
 
1753
- class ToEqual {
1754
- typeChecker;
1755
- constructor(typeChecker) {
1756
- this.typeChecker = typeChecker;
1757
- }
1758
- #explain(sourceType, targetType, isNot) {
1759
- const sourceTypeText = this.typeChecker.typeToString(sourceType);
1760
- const targetTypeText = this.typeChecker.typeToString(targetType);
1761
- return isNot
1762
- ? [Diagnostic.error(`Type '${targetTypeText}' is identical to type '${sourceTypeText}'.`)]
1763
- : [Diagnostic.error(`Type '${targetTypeText}' is not identical to type '${sourceTypeText}'.`)];
1764
- }
1738
+ class ToBeAssignable extends RelationMatcherBase {
1739
+ relation = this.typeChecker.relation.assignable;
1740
+ relationExplanationText = "assignable to";
1765
1741
  match(sourceType, targetType, isNot) {
1766
- const isMatch = this.typeChecker.isTypeRelatedTo(sourceType, targetType, this.typeChecker.relation.identity);
1742
+ const isMatch = this.typeChecker.isTypeRelatedTo(targetType, sourceType, this.relation);
1767
1743
  return {
1768
- explain: () => this.#explain(sourceType, targetType, isNot),
1744
+ explain: () => this.explain(sourceType, targetType, isNot),
1769
1745
  isMatch,
1770
1746
  };
1771
1747
  }
1772
1748
  }
1773
1749
 
1750
+ class ToEqual extends RelationMatcherBase {
1751
+ relation = this.typeChecker.relation.identity;
1752
+ relationExplanationText = "identical to";
1753
+ }
1754
+
1774
1755
  class ToHaveProperty {
1775
1756
  compiler;
1776
1757
  typeChecker;
@@ -1812,25 +1793,9 @@ class ToHaveProperty {
1812
1793
  }
1813
1794
  }
1814
1795
 
1815
- class ToMatch {
1816
- typeChecker;
1817
- constructor(typeChecker) {
1818
- this.typeChecker = typeChecker;
1819
- }
1820
- #explain(sourceType, targetType, isNot) {
1821
- const sourceTypeText = this.typeChecker.typeToString(sourceType);
1822
- const targetTypeText = this.typeChecker.typeToString(targetType);
1823
- return isNot
1824
- ? [Diagnostic.error(`Type '${targetTypeText}' is a subtype of type '${sourceTypeText}'.`)]
1825
- : [Diagnostic.error(`Type '${targetTypeText}' is not a subtype of type '${sourceTypeText}'.`)];
1826
- }
1827
- match(sourceType, targetType, isNot) {
1828
- const isMatch = this.typeChecker.isTypeRelatedTo(sourceType, targetType, this.typeChecker.relation.subtype);
1829
- return {
1830
- explain: () => this.#explain(sourceType, targetType, isNot),
1831
- isMatch,
1832
- };
1833
- }
1796
+ class ToMatch extends RelationMatcherBase {
1797
+ relation = this.typeChecker.relation.subtype;
1798
+ relationExplanationText = "a subtype of";
1834
1799
  }
1835
1800
 
1836
1801
  class ToRaiseError {
@@ -1952,19 +1917,19 @@ class Expect {
1952
1917
  constructor(compiler, typeChecker) {
1953
1918
  this.compiler = compiler;
1954
1919
  this.typeChecker = typeChecker;
1955
- this.toBeAny = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Any, "any");
1920
+ this.toBeAny = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Any);
1956
1921
  this.toBeAssignable = new ToBeAssignable(this.typeChecker);
1957
- this.toBeBigInt = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.BigInt, "bigint");
1958
- this.toBeBoolean = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Boolean, "boolean");
1959
- this.toBeNever = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Never, "never");
1960
- this.toBeNull = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Null, "null");
1961
- this.toBeNumber = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Number, "number");
1962
- this.toBeString = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.String, "string");
1963
- this.toBeSymbol = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.ESSymbol, "symbol");
1964
- this.toBeUndefined = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Undefined, "undefined");
1965
- this.toBeUniqueSymbol = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.UniqueESSymbol, "unique symbol");
1966
- this.toBeUnknown = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Unknown, "unknown");
1967
- this.toBeVoid = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Void, "void");
1922
+ this.toBeBigInt = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.BigInt);
1923
+ this.toBeBoolean = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Boolean);
1924
+ this.toBeNever = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Never);
1925
+ this.toBeNull = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Null);
1926
+ this.toBeNumber = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Number);
1927
+ this.toBeString = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.String);
1928
+ this.toBeSymbol = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.ESSymbol);
1929
+ this.toBeUndefined = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Undefined);
1930
+ this.toBeUniqueSymbol = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.UniqueESSymbol);
1931
+ this.toBeUnknown = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Unknown);
1932
+ this.toBeVoid = new PrimitiveTypeMatcher(this.typeChecker, this.compiler.TypeFlags.Void);
1968
1933
  this.toEqual = new ToEqual(this.typeChecker);
1969
1934
  this.toHaveProperty = new ToHaveProperty(this.compiler, this.typeChecker);
1970
1935
  this.toMatch = new ToMatch(this.typeChecker);
@@ -2021,7 +1986,7 @@ class Expect {
2021
1986
  this.#onSourceArgumentMustBeProvided(assertion, expectResult);
2022
1987
  return;
2023
1988
  }
2024
- return this[matcherNameText].match(this.#getType(assertion.source[0]), assertion.isNot);
1989
+ return this[matcherNameText].match(this.#getType(assertion.source[0]));
2025
1990
  case "toHaveProperty": {
2026
1991
  if (assertion.source[0] == null) {
2027
1992
  this.#onSourceArgumentMustBeProvided(assertion, expectResult);
@@ -2291,19 +2256,19 @@ class ProjectService {
2291
2256
  class TestTreeWorker {
2292
2257
  resolvedConfig;
2293
2258
  compiler;
2259
+ #cancellationToken;
2294
2260
  #expect;
2295
2261
  #fileResult;
2296
2262
  #hasOnly;
2297
2263
  #position;
2298
- #signal;
2299
2264
  constructor(resolvedConfig, compiler, expect, options) {
2300
2265
  this.resolvedConfig = resolvedConfig;
2301
2266
  this.compiler = compiler;
2267
+ this.#cancellationToken = options.cancellationToken;
2302
2268
  this.#expect = expect;
2303
2269
  this.#fileResult = options.fileResult;
2304
2270
  this.#hasOnly = options.hasOnly || resolvedConfig.only != null || options.position != null;
2305
2271
  this.#position = options.position;
2306
- this.#signal = options.signal;
2307
2272
  }
2308
2273
  #resolveRunMode(mode, member) {
2309
2274
  if (member.flags & 1) {
@@ -2327,7 +2292,7 @@ class TestTreeWorker {
2327
2292
  }
2328
2293
  visit(members, runMode, parentResult) {
2329
2294
  for (const member of members) {
2330
- if (this.#signal?.aborted === true) {
2295
+ if (this.#cancellationToken?.isCancellationRequested === true) {
2331
2296
  break;
2332
2297
  }
2333
2298
  const validationError = member.validate();
@@ -2477,8 +2442,8 @@ class TestFileRunner {
2477
2442
  this.#collectService = new CollectService(compiler);
2478
2443
  this.#projectService = new ProjectService(compiler);
2479
2444
  }
2480
- run(testFile, signal) {
2481
- if (signal?.aborted === true) {
2445
+ run(testFile, cancellationToken) {
2446
+ if (cancellationToken?.isCancellationRequested === true) {
2482
2447
  return;
2483
2448
  }
2484
2449
  const testFilePath = fileURLToPath(testFile);
@@ -2486,11 +2451,11 @@ class TestFileRunner {
2486
2451
  this.#projectService.openFile(testFilePath, undefined, this.resolvedConfig.rootPath);
2487
2452
  const fileResult = new FileResult(testFile);
2488
2453
  EventEmitter.dispatch(["file:start", { result: fileResult }]);
2489
- this.#runFile(testFilePath, fileResult, position, signal);
2454
+ this.#runFile(testFilePath, fileResult, position, cancellationToken);
2490
2455
  EventEmitter.dispatch(["file:end", { result: fileResult }]);
2491
2456
  this.#projectService.closeFile(testFilePath);
2492
2457
  }
2493
- #runFile(testFilePath, fileResult, position, signal) {
2458
+ #runFile(testFilePath, fileResult, position, cancellationToken) {
2494
2459
  const languageService = this.#projectService.getLanguageService(testFilePath);
2495
2460
  if (!languageService) {
2496
2461
  return;
@@ -2534,10 +2499,10 @@ class TestFileRunner {
2534
2499
  }
2535
2500
  const expect = new Expect(this.compiler, typeChecker);
2536
2501
  const testTreeWorker = new TestTreeWorker(this.resolvedConfig, this.compiler, expect, {
2502
+ cancellationToken,
2537
2503
  fileResult,
2538
2504
  hasOnly: testTree.hasOnly,
2539
2505
  position,
2540
- signal,
2541
2506
  });
2542
2507
  testTreeWorker.visit(testTree.members, 0, undefined);
2543
2508
  }
@@ -2555,17 +2520,17 @@ class TaskRunner {
2555
2520
  this.#resultManager.handleEvent(event);
2556
2521
  });
2557
2522
  }
2558
- async run(testFiles, target, signal) {
2523
+ async run(testFiles, target, cancellationToken) {
2559
2524
  const result = new Result(this.resolvedConfig, testFiles);
2560
2525
  EventEmitter.dispatch(["start", { result }]);
2561
2526
  for (const versionTag of target) {
2562
2527
  const targetResult = new TargetResult(versionTag, testFiles);
2563
2528
  EventEmitter.dispatch(["target:start", { result: targetResult }]);
2564
- const compiler = await this.#storeService.load(versionTag, signal);
2529
+ const compiler = await this.#storeService.load(versionTag, cancellationToken);
2565
2530
  if (compiler) {
2566
2531
  const testFileRunner = new TestFileRunner(this.resolvedConfig, compiler);
2567
2532
  for (const testFile of testFiles) {
2568
- testFileRunner.run(testFile, signal);
2533
+ testFileRunner.run(testFile, cancellationToken);
2569
2534
  }
2570
2535
  }
2571
2536
  EventEmitter.dispatch(["target:end", { result: targetResult }]);
@@ -2575,12 +2540,24 @@ class TaskRunner {
2575
2540
  }
2576
2541
  }
2577
2542
 
2543
+ class CancellationToken {
2544
+ #isCancelled = false;
2545
+ get isCancellationRequested() {
2546
+ return this.#isCancelled;
2547
+ }
2548
+ cancel() {
2549
+ if (!this.#isCancelled) {
2550
+ this.#isCancelled = true;
2551
+ }
2552
+ }
2553
+ }
2554
+
2578
2555
  class TSTyche {
2579
2556
  resolvedConfig;
2580
- #abortController = new AbortController();
2557
+ #cancellationToken = new CancellationToken();
2581
2558
  #storeService;
2582
2559
  #taskRunner;
2583
- static version = "1.0.0-rc.2";
2560
+ static version = "1.1.0";
2584
2561
  constructor(resolvedConfig, storeService) {
2585
2562
  this.resolvedConfig = resolvedConfig;
2586
2563
  this.#storeService = storeService;
@@ -2594,7 +2571,7 @@ class TSTyche {
2594
2571
  && payload.diagnostics.some((diagnostic) => diagnostic.category === "error")) {
2595
2572
  process.exitCode = 1;
2596
2573
  if (this.resolvedConfig.failFast) {
2597
- this.#abortController.abort();
2574
+ this.#cancellationToken.cancel();
2598
2575
  }
2599
2576
  }
2600
2577
  }
@@ -2618,7 +2595,7 @@ class TSTyche {
2618
2595
  });
2619
2596
  }
2620
2597
  async run(testFiles) {
2621
- await this.#taskRunner.run(this.#normalizePaths(testFiles), this.resolvedConfig.target, this.#abortController.signal);
2598
+ await this.#taskRunner.run(this.#normalizePaths(testFiles), this.resolvedConfig.target, this.#cancellationToken);
2622
2599
  }
2623
2600
  }
2624
2601
 
@@ -2825,7 +2802,7 @@ class OptionValidator {
2825
2802
  }
2826
2803
  break;
2827
2804
  case "target":
2828
- if (!(await this.#storeService.validateTag(optionValue))) {
2805
+ if (await this.#storeService.validateTag(optionValue) === false) {
2829
2806
  this.#onDiagnostic(Diagnostic.error([
2830
2807
  this.#optionDiagnosticText.versionIsNotSupported(optionValue),
2831
2808
  ...(await this.#optionUsageText.get(optionName, optionBrand)),
@@ -3194,7 +3171,6 @@ var OptionBrand;
3194
3171
  OptionBrand["True"] = "true";
3195
3172
  OptionBrand["List"] = "list";
3196
3173
  })(OptionBrand || (OptionBrand = {}));
3197
-
3198
3174
  var OptionGroup;
3199
3175
  (function (OptionGroup) {
3200
3176
  OptionGroup[OptionGroup["CommandLine"] = 2] = "CommandLine";
@@ -3216,42 +3192,40 @@ class ManifestWorker {
3216
3192
  this.#manifestFilePath = Path.join(storePath, this.#manifestFileName);
3217
3193
  this.#prune = prune;
3218
3194
  }
3219
- async #create(signal) {
3220
- const manifest = await this.#load(signal);
3195
+ async #create() {
3196
+ const manifest = await this.#load();
3221
3197
  if (manifest != null) {
3222
3198
  await this.persist(manifest);
3223
3199
  }
3224
3200
  return manifest;
3225
3201
  }
3226
- async #fetch(signal) {
3202
+ async #fetch() {
3227
3203
  return new Promise((resolve, reject) => {
3228
3204
  const request = https.get(new URL("typescript", this.#registryUrl), {
3229
3205
  headers: { accept: "application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*" },
3230
- signal,
3231
- }, (result) => {
3232
- if (result.statusCode !== 200) {
3233
- reject(new Error(`Request failed with status code ${String(result.statusCode)}.`));
3234
- result.resume();
3206
+ timeout: this.#timeout,
3207
+ }, (response) => {
3208
+ if (response.statusCode !== 200) {
3209
+ reject(new Error(`Request failed with status code ${String(response.statusCode)}.`));
3210
+ response.resume();
3235
3211
  return;
3236
3212
  }
3237
- result.setEncoding("utf8");
3213
+ response.setEncoding("utf8");
3238
3214
  let rawData = "";
3239
- result.on("data", (chunk) => {
3215
+ response.on("data", (chunk) => {
3240
3216
  rawData += chunk;
3241
3217
  });
3242
- result.on("end", () => {
3243
- try {
3244
- const packageMetadata = JSON.parse(rawData);
3245
- resolve(packageMetadata);
3246
- }
3247
- catch (error) {
3248
- reject(error);
3249
- }
3218
+ response.on("end", () => {
3219
+ const packageMetadata = JSON.parse(rawData);
3220
+ resolve(packageMetadata);
3250
3221
  });
3251
3222
  });
3252
3223
  request.on("error", (error) => {
3253
3224
  reject(error);
3254
3225
  });
3226
+ request.on("timeout", () => {
3227
+ request.destroy();
3228
+ });
3255
3229
  });
3256
3230
  }
3257
3231
  isOutdated(manifest, ageTolerance = 0) {
@@ -3260,7 +3234,7 @@ class ManifestWorker {
3260
3234
  }
3261
3235
  return false;
3262
3236
  }
3263
- async #load(signal, options = { quite: false }) {
3237
+ async #load(options) {
3264
3238
  const manifest = {
3265
3239
  $version: this.#version,
3266
3240
  lastUpdated: Date.now(),
@@ -3268,27 +3242,21 @@ class ManifestWorker {
3268
3242
  versions: [],
3269
3243
  };
3270
3244
  let packageMetadata;
3271
- const abortController = new AbortController();
3272
- const timeoutSignal = AbortSignal.timeout(this.#timeout);
3273
- timeoutSignal.addEventListener("abort", () => {
3274
- abortController.abort(`Setup timeout of ${this.#timeout / 1000}s was exceeded.`);
3275
- }, { once: true });
3276
- signal?.addEventListener("abort", () => {
3277
- abortController.abort("Fetch got canceled by request.");
3278
- }, { once: true });
3279
3245
  try {
3280
- packageMetadata = await this.#fetch(abortController.signal);
3246
+ packageMetadata = await this.#fetch();
3281
3247
  }
3282
3248
  catch (error) {
3283
- if (!options.quite) {
3284
- const text = [`Failed to fetch metadata of the 'typescript' package from '${this.#registryUrl.toString()}'.`];
3285
- if (error instanceof Error && error.name !== "AbortError") {
3286
- text.push("Might be there is an issue with the registry or the network connection.");
3287
- }
3288
- this.#onDiagnostic(Diagnostic.fromError(text, error));
3249
+ if (options?.quite === true) {
3250
+ return;
3289
3251
  }
3290
- }
3291
- if (!packageMetadata) {
3252
+ const text = [`Failed to fetch metadata of the 'typescript' package from '${this.#registryUrl.toString()}'.`];
3253
+ if (error instanceof Error && "code" in error && error.code === "ECONNRESET") {
3254
+ text.push(`Setup timeout of ${this.#timeout / 1000}s was exceeded.`);
3255
+ }
3256
+ else {
3257
+ text.push("Might be there is an issue with the registry or the network connection.");
3258
+ }
3259
+ this.#onDiagnostic(Diagnostic.fromError(text, error));
3292
3260
  return;
3293
3261
  }
3294
3262
  manifest.versions = Object.keys(packageMetadata.versions)
@@ -3309,10 +3277,10 @@ class ManifestWorker {
3309
3277
  }
3310
3278
  return manifest;
3311
3279
  }
3312
- async open(signal, options) {
3280
+ async open(options) {
3313
3281
  let manifest;
3314
3282
  if (!existsSync(this.#manifestFilePath)) {
3315
- return this.#create(signal);
3283
+ return this.#create();
3316
3284
  }
3317
3285
  let manifestText;
3318
3286
  try {
@@ -3331,11 +3299,11 @@ class ManifestWorker {
3331
3299
  }
3332
3300
  if (manifest == null || manifest.$version !== this.#version) {
3333
3301
  await this.#prune();
3334
- return this.#create(signal);
3302
+ return this.#create();
3335
3303
  }
3336
3304
  if (this.isOutdated(manifest) || options?.refresh === true) {
3337
3305
  const quite = options?.refresh !== true;
3338
- const freshManifest = await this.#load(signal, { quite });
3306
+ const freshManifest = await this.#load({ quite });
3339
3307
  if (freshManifest != null) {
3340
3308
  await this.persist(freshManifest);
3341
3309
  return freshManifest;
@@ -3374,7 +3342,7 @@ class Lock {
3374
3342
  }
3375
3343
  const waitStartTime = Date.now();
3376
3344
  while (isLocked) {
3377
- if (options.signal?.aborted === true) {
3345
+ if (options.cancellationToken?.isCancellationRequested === true) {
3378
3346
  break;
3379
3347
  }
3380
3348
  if (Date.now() - waitStartTime > options.timeout) {
@@ -3403,51 +3371,55 @@ class PackageInstaller {
3403
3371
  this.#storePath = storePath;
3404
3372
  this.#onDiagnostic = onDiagnostic;
3405
3373
  }
3406
- async ensure(compilerVersion, signal) {
3374
+ async ensure(compilerVersion, cancellationToken) {
3407
3375
  const installationPath = Path.join(this.#storePath, compilerVersion);
3408
3376
  const readyFilePath = Path.join(installationPath, this.#readyFileName);
3377
+ const modulePath = Path.join(installationPath, "node_modules", "typescript", "lib", "typescript.js");
3378
+ if (existsSync(readyFilePath)) {
3379
+ return modulePath;
3380
+ }
3409
3381
  if (await Lock.isLocked(installationPath, {
3382
+ cancellationToken,
3410
3383
  onDiagnostic: (text) => {
3411
3384
  this.#onDiagnostic(Diagnostic.error([`Failed to install 'typescript@${compilerVersion}'.`, text]));
3412
3385
  },
3413
- signal,
3414
3386
  timeout: this.#timeout,
3415
3387
  })) {
3416
3388
  return;
3417
3389
  }
3418
- if (!existsSync(readyFilePath)) {
3419
- EventEmitter.dispatch(["store:info", { compilerVersion, installationPath }]);
3420
- try {
3421
- await fs.mkdir(installationPath, { recursive: true });
3422
- const lock = new Lock(installationPath);
3423
- const packageJson = {
3424
- name: "tstyche-typescript",
3425
- version: compilerVersion,
3426
- description: "Do not change. This package was generated by TSTyche",
3427
- private: true,
3428
- license: "MIT",
3429
- dependencies: {
3430
- typescript: compilerVersion,
3431
- },
3432
- };
3433
- await fs.writeFile(Path.join(installationPath, "package.json"), JSON.stringify(packageJson, null, 2));
3434
- await this.#install(installationPath, signal);
3435
- await fs.writeFile(readyFilePath, "");
3436
- lock.release();
3437
- }
3438
- catch (error) {
3439
- this.#onDiagnostic(Diagnostic.fromError(`Failed to install 'typescript@${compilerVersion}'.`, error));
3440
- }
3390
+ const lock = new Lock(installationPath);
3391
+ EventEmitter.dispatch(["store:info", { compilerVersion, installationPath }]);
3392
+ try {
3393
+ await fs.mkdir(installationPath, { recursive: true });
3394
+ const packageJson = {
3395
+ name: "tstyche-typescript",
3396
+ version: compilerVersion,
3397
+ description: "Do not change. This package was generated by TSTyche",
3398
+ private: true,
3399
+ license: "MIT",
3400
+ dependencies: {
3401
+ typescript: compilerVersion,
3402
+ },
3403
+ };
3404
+ await fs.writeFile(Path.join(installationPath, "package.json"), JSON.stringify(packageJson, null, 2));
3405
+ await this.#install(installationPath);
3406
+ await fs.writeFile(readyFilePath, "");
3407
+ return modulePath;
3408
+ }
3409
+ catch (error) {
3410
+ this.#onDiagnostic(Diagnostic.fromError(`Failed to install 'typescript@${compilerVersion}'.`, error));
3411
+ }
3412
+ finally {
3413
+ lock.release();
3441
3414
  }
3442
- return Path.join(installationPath, "node_modules", "typescript", "lib", "typescript.js");
3415
+ return;
3443
3416
  }
3444
- async #install(cwd, signal) {
3417
+ async #install(cwd) {
3445
3418
  const args = ["install", "--ignore-scripts", "--no-bin-links", "--no-package-lock"];
3446
3419
  return new Promise((resolve, reject) => {
3447
3420
  const spawnedNpm = spawn("npm", args, {
3448
3421
  cwd,
3449
3422
  shell: true,
3450
- signal,
3451
3423
  stdio: "ignore",
3452
3424
  timeout: this.#timeout,
3453
3425
  });
@@ -3459,9 +3431,9 @@ class PackageInstaller {
3459
3431
  resolve();
3460
3432
  }
3461
3433
  if (signal != null) {
3462
- reject(new Error(`Setup timeout of ${this.#timeout / 1000}s was exceeded.`));
3434
+ reject(new Error(`setup timeout of ${this.#timeout / 1000}s was exceeded`));
3463
3435
  }
3464
- reject(new Error(`Process exited with code ${String(code)}.`));
3436
+ reject(new Error(`process exited with code ${String(code)}`));
3465
3437
  });
3466
3438
  });
3467
3439
  }
@@ -3478,25 +3450,25 @@ class StoreService {
3478
3450
  this.#packageInstaller = new PackageInstaller(this.#storePath, this.#onDiagnostic);
3479
3451
  this.#manifestWorker = new ManifestWorker(this.#storePath, this.#onDiagnostic, this.prune);
3480
3452
  }
3481
- async getSupportedTags(signal) {
3482
- await this.open(signal);
3453
+ async getSupportedTags() {
3454
+ await this.open();
3483
3455
  if (!this.#manifest) {
3484
3456
  return [];
3485
3457
  }
3486
3458
  return [...Object.keys(this.#manifest.resolutions), ...this.#manifest.versions, "current"].sort();
3487
3459
  }
3488
- async install(tag, signal) {
3460
+ async install(tag, cancellationToken) {
3489
3461
  if (tag === "current") {
3490
3462
  return;
3491
3463
  }
3492
- const version = await this.resolveTag(tag, signal);
3464
+ const version = await this.resolveTag(tag);
3493
3465
  if (version == null) {
3494
3466
  this.#onDiagnostic(Diagnostic.error(`Cannot add the 'typescript' package for the '${tag}' tag.`));
3495
3467
  return;
3496
3468
  }
3497
- return this.#packageInstaller.ensure(version, signal);
3469
+ return this.#packageInstaller.ensure(version, cancellationToken);
3498
3470
  }
3499
- async load(tag, signal) {
3471
+ async load(tag, cancellationToken) {
3500
3472
  let compilerInstance = this.#compilerInstanceCache.get(tag);
3501
3473
  if (compilerInstance != null) {
3502
3474
  return compilerInstance;
@@ -3506,7 +3478,7 @@ class StoreService {
3506
3478
  modulePath = Environment.typescriptPath;
3507
3479
  }
3508
3480
  else {
3509
- const version = await this.resolveTag(tag, signal);
3481
+ const version = await this.resolveTag(tag);
3510
3482
  if (version == null) {
3511
3483
  this.#onDiagnostic(Diagnostic.error(`Cannot add the 'typescript' package for the '${tag}' tag.`));
3512
3484
  return;
@@ -3515,7 +3487,7 @@ class StoreService {
3515
3487
  if (compilerInstance != null) {
3516
3488
  return compilerInstance;
3517
3489
  }
3518
- modulePath = await this.#packageInstaller.ensure(version, signal);
3490
+ modulePath = await this.#packageInstaller.ensure(version, cancellationToken);
3519
3491
  }
3520
3492
  if (modulePath != null) {
3521
3493
  compilerInstance = await this.#loadModule(modulePath);
@@ -3547,20 +3519,20 @@ class StoreService {
3547
3519
  #onDiagnostic = (diagnostic) => {
3548
3520
  EventEmitter.dispatch(["store:error", { diagnostics: [diagnostic] }]);
3549
3521
  };
3550
- async open(signal) {
3522
+ async open() {
3551
3523
  if (this.#manifest) {
3552
3524
  return;
3553
3525
  }
3554
- this.#manifest = await this.#manifestWorker.open(signal);
3526
+ this.#manifest = await this.#manifestWorker.open();
3555
3527
  }
3556
3528
  prune = async () => {
3557
3529
  await fs.rm(this.#storePath, { force: true, recursive: true });
3558
3530
  };
3559
- async resolveTag(tag, signal) {
3531
+ async resolveTag(tag) {
3560
3532
  if (tag === "current") {
3561
3533
  return tag;
3562
3534
  }
3563
- await this.open(signal);
3535
+ await this.open();
3564
3536
  if (!this.#manifest) {
3565
3537
  return;
3566
3538
  }
@@ -3569,16 +3541,16 @@ class StoreService {
3569
3541
  }
3570
3542
  return this.#manifest.resolutions[tag];
3571
3543
  }
3572
- async update(signal) {
3573
- await this.#manifestWorker.open(signal, { refresh: true });
3544
+ async update() {
3545
+ await this.#manifestWorker.open({ refresh: true });
3574
3546
  }
3575
- async validateTag(tag, signal) {
3547
+ async validateTag(tag) {
3576
3548
  if (tag === "current") {
3577
3549
  return Environment.typescriptPath != null;
3578
3550
  }
3579
- await this.open(signal);
3551
+ await this.open();
3580
3552
  if (!this.#manifest) {
3581
- return false;
3553
+ return undefined;
3582
3554
  }
3583
3555
  if (this.#manifestWorker.isOutdated(this.#manifest, 60)
3584
3556
  && (!Version.isVersionTag(tag)
@@ -3589,11 +3561,12 @@ class StoreService {
3589
3561
  `The resolution of the '${tag}' tag may be outdated.`,
3590
3562
  ]));
3591
3563
  }
3592
- return this.#manifest.versions.includes(tag) || tag in this.#manifest.resolutions || tag === "current";
3564
+ return tag in this.#manifest.resolutions || this.#manifest.versions.includes(tag);
3593
3565
  }
3594
3566
  }
3595
3567
 
3596
3568
  class Cli {
3569
+ #cancellationToken = new CancellationToken();
3597
3570
  #logger;
3598
3571
  #storeService;
3599
3572
  constructor() {
@@ -3610,8 +3583,9 @@ class Cli {
3610
3583
  for (const diagnostic of payload.diagnostics) {
3611
3584
  switch (diagnostic.category) {
3612
3585
  case "error":
3613
- process.exitCode = 1;
3586
+ this.#cancellationToken.cancel();
3614
3587
  this.#logger.writeError(diagnosticText(diagnostic));
3588
+ process.exitCode = 1;
3615
3589
  break;
3616
3590
  case "warning":
3617
3591
  this.#logger.writeWarning(diagnosticText(diagnostic));
@@ -3646,11 +3620,11 @@ class Cli {
3646
3620
  }
3647
3621
  const configService = new ConfigService(compiler, this.#storeService);
3648
3622
  await configService.parseCommandLine(commandLineArguments);
3649
- if (process.exitCode === 1) {
3623
+ if (this.#cancellationToken.isCancellationRequested) {
3650
3624
  return;
3651
3625
  }
3652
3626
  await configService.readConfigFile();
3653
- if (process.exitCode === 1) {
3627
+ if (this.#cancellationToken.isCancellationRequested) {
3654
3628
  return;
3655
3629
  }
3656
3630
  const resolvedConfig = configService.resolveConfig();
@@ -3688,4 +3662,4 @@ class Cli {
3688
3662
  }
3689
3663
  }
3690
3664
 
3691
- export { Assertion, Cli, CollectService, Color, ConfigService, DescribeResult, Diagnostic, DiagnosticCategory, Environment, EventEmitter, Expect, ExpectResult, FileResult, Line, Logger, OptionBrand, OptionDefinitionsMap, OptionGroup, Path, ProjectResult, ProjectService, Reporter, Result, ResultCount, ResultManager, ResultStatus, ResultTiming, Scribbler, StoreService, SummaryReporter, TSTyche, TargetResult, TaskRunner, TestMember, TestMemberBrand, TestMemberFlags, TestResult, TestTree, Text, ThoroughReporter, Version, addsPackageStepText, describeNameText, diagnosticText, fileStatusText, fileViewText, formattedText, helpText, summaryText, testNameText, usesCompilerStepText };
3665
+ export { Assertion, CancellationToken, Cli, CollectService, Color, ConfigService, DescribeResult, Diagnostic, DiagnosticCategory, Environment, EventEmitter, Expect, ExpectResult, FileResult, Line, Logger, OptionBrand, OptionDefinitionsMap, OptionGroup, Path, ProjectResult, ProjectService, Reporter, Result, ResultCount, ResultManager, ResultStatus, ResultTiming, Scribbler, StoreService, SummaryReporter, TSTyche, TargetResult, TaskRunner, TestMember, TestMemberBrand, TestMemberFlags, TestResult, TestTree, Text, ThoroughReporter, Version, addsPackageStepText, describeNameText, diagnosticText, fileStatusText, fileViewText, formattedText, helpText, summaryText, testNameText, usesCompilerStepText };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tstyche",
3
- "version": "1.0.0-rc.2",
3
+ "version": "1.1.0",
4
4
  "description": "The Essential Type Testing Tool.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -50,35 +50,34 @@
50
50
  "lint": "eslint ./ --config eslint.config.json --ext .js,.cts,.ts,.tsx",
51
51
  "prepack": "yarn clean && yarn build",
52
52
  "prepublish": "yarn test",
53
- "test": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest --config jest.config.js",
53
+ "test": "yarn test:unit && yarn test:schema && yarn test:e2e",
54
54
  "test:coverage": "yarn build --sourcemap && c8 --config c8.config.json yarn test:e2e",
55
- "test:e2e": "yarn test --testMatch '**/tests/*.test.js'",
55
+ "test:e2e": "mocha tests/*.js --config mocha.config.json",
56
56
  "test:examples": "tstyche examples",
57
+ "test:schema": "mocha models/__tests__/*.js --config mocha.config.json",
57
58
  "test:types": "tstyche tests",
58
- "test:unit": "yarn test --testMatch '**/source/**/__tests__/*.test.ts?(x)'"
59
+ "test:unit": "mocha source/*/__tests__/*.js --config mocha.config.json"
59
60
  },
60
61
  "devDependencies": {
61
- "@jest/globals": "29.7.0",
62
62
  "@rollup/plugin-typescript": "11.1.6",
63
- "@types/node": "20.11.17",
64
- "@typescript-eslint/eslint-plugin": "7.0.1",
65
- "@typescript-eslint/parser": "7.0.1",
63
+ "@types/mocha": "10.0.6",
64
+ "@types/node": "20.11.20",
65
+ "@typescript-eslint/eslint-plugin": "7.1.0",
66
+ "@typescript-eslint/parser": "7.1.0",
66
67
  "ajv": "8.12.0",
67
68
  "c8": "9.1.0",
68
- "cspell": "8.3.2",
69
+ "cspell": "8.4.1",
69
70
  "dprint": "0.45.0",
70
- "eslint": "8.56.0",
71
+ "eslint": "8.57.0",
71
72
  "eslint-import-resolver-typescript": "3.6.1",
72
73
  "eslint-plugin-import": "2.29.1",
73
- "eslint-plugin-jest": "27.8.0",
74
- "eslint-plugin-jest-formatting": "3.1.0",
74
+ "eslint-plugin-mocha": "10.3.0",
75
75
  "eslint-plugin-simple-import-sort": "12.0.0",
76
- "jest": "29.7.0",
77
- "jest-serializer-ansi-escapes": "2.0.1",
78
76
  "magic-string": "0.30.7",
79
- "rollup": "4.10.0",
77
+ "mocha": "10.3.0",
78
+ "pretty-ansi": "2.0.0",
79
+ "rollup": "4.12.0",
80
80
  "rollup-plugin-dts": "6.1.0",
81
- "ts-node": "10.9.2",
82
81
  "tslib": "2.6.2",
83
82
  "typescript": "5.3.3"
84
83
  },
@@ -92,6 +91,6 @@
92
91
  },
93
92
  "packageManager": "yarn@3.8.0",
94
93
  "engines": {
95
- "node": "^16.14 || 18.x || >=20.x"
94
+ "node": ">=14.17"
96
95
  }
97
- }
96
+ }
package/CHANGELOG.md DELETED
@@ -1,151 +0,0 @@
1
- # Changelog
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
-
23
- ## [1.0.0-rc] - 2024-01-28
24
-
25
- ### Changed
26
-
27
- - **Breaking!** Replace the `allowNoTestFiles` option with `disableTestFileLookup` ([#104](https://github.com/tstyche/tstyche/pull/104))
28
-
29
- ### Added
30
-
31
- - **New!** Set default compiler options for inferred (e.g. JavaScript) projects ([#93](https://github.com/tstyche/tstyche/pull/93))
32
- - Add the `TSTYCHE_NO_INTERACTIVE` environment variable ([#88](https://github.com/tstyche/tstyche/pull/88))
33
- - Add the `TSTYCHE_TYPESCRIPT_PATH` environment variable ([#84](https://github.com/tstyche/tstyche/pull/84))
34
-
35
- ### Fixed
36
-
37
- - Only select TypeScript and JavaScript files for test run ([#105](https://github.com/tstyche/tstyche/pull/105))
38
-
39
- ## [1.0.0-beta.9] - 2024-01-05
40
-
41
- ### Fixed
42
-
43
- - Fix `"target": ["current"]` support for TypeScript 5.2 and below ([#83](https://github.com/tstyche/tstyche/pull/83))
44
-
45
- ## [1.0.0-beta.8] - 2024-01-05
46
-
47
- ### Changed
48
-
49
- - **Breaking!** Make `"target": ["current"]` the default instead of `"target": ["latest"]` ([#81](https://github.com/tstyche/tstyche/pull/81), [#80](https://github.com/tstyche/tstyche/pull/80), [#66](https://github.com/tstyche/tstyche/pull/66))
50
- - **New!** Load the installed TypeScript package for type testing instead of installing another copy to the store ([#71](https://github.com/tstyche/tstyche/pull/71), [#64](https://github.com/tstyche/tstyche/pull/64))
51
-
52
- ### Added
53
-
54
- - Add the `Path` class ([#59](https://github.com/tstyche/tstyche/pull/59))
55
-
56
- ### Fixed
57
-
58
- - Correctly handle command line options that do not take a value ([#58](https://github.com/tstyche/tstyche/pull/58))
59
-
60
- ## [1.0.0-beta.7] - 2023-12-29
61
-
62
- ### Changed
63
-
64
- - **Breaking!** Add new `Expect` class to validate provided values and orchestrate matchers logic ([#39](https://github.com/tstyche/tstyche/pull/39))
65
-
66
- ### Added
67
-
68
- - **New!** Load local language service plugins to support files like `.svelte` or `.vue` ([#56](https://github.com/tstyche/tstyche/pull/56))
69
-
70
- ### Fixed
71
-
72
- - Make the source argument checks stricter for the `.toHaveProperty()` matcher ([#46](https://github.com/tstyche/tstyche/pull/46))
73
-
74
- ## [1.0.0-beta.6] - 2023-12-03
75
-
76
- ### Added
77
-
78
- - **New!** Add `.toHaveProperty()` matcher ([#36](https://github.com/tstyche/tstyche/pull/36))
79
-
80
- ### Fixed
81
-
82
- - Accept template literals as arguments of the `.toRaiseError()` matcher ([#38](https://github.com/tstyche/tstyche/pull/38))
83
-
84
- ## [1.0.0-beta.5] - 2023-11-27
85
-
86
- ### Changed
87
-
88
- - **Breaking!** Move retry logic to the `Lock` class ([#31](https://github.com/tstyche/tstyche/pull/31))
89
- - Bring back support for Node.js 16 ([#28](https://github.com/tstyche/tstyche/pull/28), [#27](https://github.com/tstyche/tstyche/pull/27))
90
-
91
- ### Added
92
-
93
- - **New!** Add support for the `current` target tag ([#33](https://github.com/tstyche/tstyche/pull/33))
94
-
95
- ### Fixed
96
-
97
- - Allow `.raiseError()` to take template literals as arguments ([#35](https://github.com/tstyche/tstyche/pull/35))
98
-
99
- ## [1.0.0-beta.4] - 2023-11-24
100
-
101
- ### Added
102
-
103
- - Use Node.js Fetch API ([#23](https://github.com/tstyche/tstyche/pull/23))
104
-
105
- ### Removed
106
-
107
- - **Breaking!** Remove the `context()` helper ([#24](https://github.com/tstyche/tstyche/pull/24))
108
- - **Breaking!** Drop support for Node.js 16 ([#22](https://github.com/tstyche/tstyche/pull/22))
109
- - **Breaking!** Rename methods of the `StoreService` class ([`5d74201`](https://github.com/tstyche/tstyche/commit/5d74201))
110
-
111
- ### Fixed
112
-
113
- - Tune up behavior of `.skip` and `.only` run mode flags ([#25](https://github.com/tstyche/tstyche/pull/25))
114
- - Clean up error messages of primitive type matchers ([#21](https://github.com/tstyche/tstyche/pull/21))
115
- - Normalize `installationPath` path output ([#19](https://github.com/tstyche/tstyche/pull/19))
116
-
117
- ## [1.0.0-beta.3] - 2023-11-13
118
-
119
- ### Fixed
120
-
121
- - Support TypeScript's 'node10' and 'node16' resolutions ([`7dd805a`](https://github.com/tstyche/tstyche/commit/7dd805a), [`9c83e79`](https://github.com/tstyche/tstyche/commit/9c83e79))
122
-
123
- ## [1.0.0-beta.2] - 2023-11-12
124
-
125
- ### Fixed
126
-
127
- - Support TypeScript's 'node10' resolution ([#7](https://github.com/tstyche/tstyche/pull/7))
128
-
129
- ## [1.0.0-beta.1] - 2023-11-09
130
-
131
- ### Fixed
132
-
133
- - Include 'cjs' files in the published package ([`90b6473`](https://github.com/tstyche/tstyche/commit/90b6473))
134
-
135
- ## [1.0.0-beta.0] - 2023-11-09
136
-
137
- _First pre-release._
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
141
- [1.0.0-rc]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-rc
142
- [1.0.0-beta.9]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.9
143
- [1.0.0-beta.8]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.8
144
- [1.0.0-beta.7]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.7
145
- [1.0.0-beta.6]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.6
146
- [1.0.0-beta.5]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.5
147
- [1.0.0-beta.4]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.4
148
- [1.0.0-beta.3]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.3
149
- [1.0.0-beta.2]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.2
150
- [1.0.0-beta.1]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.1
151
- [1.0.0-beta.0]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.0