tstyche 3.4.0 → 4.0.0-beta.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/build/tstyche.js CHANGED
@@ -140,15 +140,15 @@ class Diagnostic {
140
140
  }
141
141
  const text = typeof diagnostic.messageText === "string"
142
142
  ? diagnostic.messageText
143
- : Diagnostic.#toMessageText(diagnostic.messageText);
143
+ : Diagnostic.toMessageText(diagnostic.messageText);
144
144
  return new Diagnostic(text, DiagnosticCategory.Error, origin).add({ code, related });
145
145
  });
146
146
  }
147
- static #toMessageText(chain) {
147
+ static toMessageText(chain) {
148
148
  const result = [chain.messageText];
149
149
  if (chain.next != null) {
150
150
  for (const nextChain of chain.next) {
151
- result.push(...Diagnostic.#toMessageText(nextChain));
151
+ result.push(...Diagnostic.toMessageText(nextChain));
152
152
  }
153
153
  }
154
154
  return result;
@@ -363,9 +363,6 @@ class Version {
363
363
  static isSatisfiedWith(source, target) {
364
364
  return source === target || Version.#satisfies(source, target);
365
365
  }
366
- static isVersionTag(target) {
367
- return /^\d+/.test(target);
368
- }
369
366
  static #satisfies(source, target) {
370
367
  const sourceElements = source.split(/\.|-/);
371
368
  const targetElements = target.split(/\.|-/);
@@ -394,8 +391,8 @@ class StoreDiagnosticText {
394
391
  static failedToFetchMetadata(registry) {
395
392
  return `Failed to fetch metadata of the 'typescript' package from '${registry}'.`;
396
393
  }
397
- static failedToInstalTypeScript(version) {
398
- return `Failed to install 'typescript@${version}'.`;
394
+ static failedToFetchPackage(version) {
395
+ return `Failed to fetch the 'typescript@${version}' package.`;
399
396
  }
400
397
  static failedToUpdateMetadata(registry) {
401
398
  return `Failed to update metadata of the 'typescript' package from '${registry}'.`;
@@ -499,9 +496,10 @@ class LockService {
499
496
  }
500
497
 
501
498
  class Manifest {
502
- static #version = "2";
499
+ static #version = "3";
503
500
  $version;
504
501
  lastUpdated;
502
+ minorVersions;
505
503
  npmRegistry;
506
504
  packages;
507
505
  resolutions;
@@ -509,6 +507,7 @@ class Manifest {
509
507
  constructor(data) {
510
508
  this.$version = data.$version ?? Manifest.#version;
511
509
  this.lastUpdated = data.lastUpdated ?? Date.now();
510
+ this.minorVersions = data.minorVersions;
512
511
  this.npmRegistry = data.npmRegistry;
513
512
  this.packages = data.packages;
514
513
  this.resolutions = data.resolutions;
@@ -542,6 +541,7 @@ class Manifest {
542
541
  const manifestData = {
543
542
  $version: this.$version,
544
543
  lastUpdated: this.lastUpdated,
544
+ minorVersions: this.minorVersions,
545
545
  npmRegistry: this.npmRegistry,
546
546
  packages: this.packages,
547
547
  resolutions: this.resolutions,
@@ -556,7 +556,7 @@ class ManifestService {
556
556
  #manifestFilePath;
557
557
  #npmRegistry;
558
558
  #storePath;
559
- #supportedVersionRegex = /^(4|5)\.\d\.\d$/;
559
+ #supportedVersionRegex = /^(5)\.\d\.\d$/;
560
560
  constructor(storePath, npmRegistry, fetcher) {
561
561
  this.#storePath = storePath;
562
562
  this.#npmRegistry = npmRegistry;
@@ -591,7 +591,7 @@ class ManifestService {
591
591
  packages[tag] = { integrity: meta.dist.integrity, tarball: meta.dist.tarball };
592
592
  }
593
593
  }
594
- const minorVersions = new Set(versions.map((version) => version.slice(0, -2)));
594
+ const minorVersions = [...new Set(versions.map((version) => version.slice(0, -2)))];
595
595
  for (const tag of minorVersions) {
596
596
  const resolvedVersion = versions.findLast((version) => version.startsWith(tag));
597
597
  if (resolvedVersion != null) {
@@ -608,7 +608,7 @@ class ManifestService {
608
608
  }
609
609
  }
610
610
  }
611
- return new Manifest({ npmRegistry: this.#npmRegistry, packages, resolutions, versions });
611
+ return new Manifest({ minorVersions, npmRegistry: this.#npmRegistry, packages, resolutions, versions });
612
612
  }
613
613
  async open(options) {
614
614
  if (!existsSync(this.#manifestFilePath)) {
@@ -685,9 +685,6 @@ class PackageService {
685
685
  if (response?.body != null) {
686
686
  const targetPath = `${packagePath}-${Math.random().toString(32).slice(2)}`;
687
687
  for await (const file of TarReader.extract(response.body)) {
688
- if (!file.name.startsWith("package/")) {
689
- continue;
690
- }
691
688
  const filePath = Path.join(targetPath, file.name.replace("package/", ""));
692
689
  const directoryPath = Path.dirname(filePath);
693
690
  if (!existsSync(directoryPath)) {
@@ -702,7 +699,7 @@ class PackageService {
702
699
  }
703
700
  async ensure(packageVersion, manifest) {
704
701
  let packagePath = Path.join(this.#storePath, `typescript@${packageVersion}`);
705
- const diagnostic = Diagnostic.error(StoreDiagnosticText.failedToInstalTypeScript(packageVersion));
702
+ const diagnostic = Diagnostic.error(StoreDiagnosticText.failedToFetchPackage(packageVersion));
706
703
  if (await this.#lockService.isLocked(packagePath, diagnostic)) {
707
704
  return;
708
705
  }
@@ -742,11 +739,7 @@ class Store {
742
739
  Store.#packageService = new PackageService(Store.#storePath, Store.#fetcher, Store.#lockService);
743
740
  Store.#manifestService = new ManifestService(Store.#storePath, Store.#npmRegistry, Store.#fetcher);
744
741
  }
745
- static async getSupportedTags() {
746
- await Store.open();
747
- return Store.#supportedTags;
748
- }
749
- static async install(tag) {
742
+ static async fetch(tag) {
750
743
  if (tag === "current") {
751
744
  return;
752
745
  }
@@ -799,14 +792,11 @@ class Store {
799
792
  modulePath = Path.resolve(modulePath, "../tsserverlibrary.js");
800
793
  }
801
794
  const sourceText = await fs.readFile(modulePath, { encoding: "utf8" });
802
- const toExpose = [];
803
- if (Version.isSatisfiedWith(packageVersion, "4.4")) {
804
- toExpose.push("isApplicableIndexType");
805
- }
806
- if (!Version.isSatisfiedWith(packageVersion, "4.6")) {
807
- toExpose.push("getTypeOfSymbol");
808
- }
809
- toExpose.push("isTypeRelatedTo", "relation: { assignable: assignableRelation, identity: identityRelation, subtype: strictSubtypeRelation }");
795
+ const toExpose = [
796
+ "isApplicableIndexType",
797
+ "isTypeRelatedTo",
798
+ "relation: { assignable: assignableRelation, identity: identityRelation }",
799
+ ];
810
800
  const modifiedSourceText = sourceText.replace("return checker;", `return { ...checker, ${toExpose.join(", ")} };`);
811
801
  const compiledWrapper = vm.compileFunction(modifiedSourceText, ["exports", "require", "module", "__filename", "__dirname"], { filename: modulePath });
812
802
  compiledWrapper(exports, createRequire(modulePath), module, modulePath, Path.dirname(modulePath));
@@ -857,7 +847,7 @@ class Target {
857
847
  }
858
848
  await Store.open();
859
849
  if (Store.manifest != null) {
860
- let versions = Object.keys(Store.manifest.resolutions).slice(0, -4);
850
+ let versions = [...Store.manifest.minorVersions];
861
851
  for (const comparator of query.split(" ")) {
862
852
  versions = Target.#filter(comparator, versions);
863
853
  }
@@ -913,15 +903,15 @@ class Options {
913
903
  },
914
904
  {
915
905
  brand: OptionBrand.BareTrue,
916
- description: "Print the list of command line options with brief descriptions and exit.",
906
+ description: "Fetch specified versions of the 'typescript' package and exit.",
917
907
  group: OptionGroup.CommandLine,
918
- name: "help",
908
+ name: "fetch",
919
909
  },
920
910
  {
921
911
  brand: OptionBrand.BareTrue,
922
- description: "Install specified versions of the 'typescript' package and exit.",
912
+ description: "Print the list of command line options with brief descriptions and exit.",
923
913
  group: OptionGroup.CommandLine,
924
- name: "install",
914
+ name: "help",
925
915
  },
926
916
  {
927
917
  brand: OptionBrand.BareTrue,
@@ -1157,11 +1147,11 @@ class CommandLineParser {
1157
1147
  this.#onDiagnostics = onDiagnostics;
1158
1148
  this.#options = Options.for(OptionGroup.CommandLine);
1159
1149
  }
1160
- async #onExpectsValue(optionName, optionBrand) {
1150
+ #onExpectsValue(optionName, optionBrand) {
1161
1151
  const text = [
1162
1152
  ConfigDiagnosticText.expectsValue(optionName),
1163
- await ConfigDiagnosticText.usage(optionName, optionBrand),
1164
- ].flat();
1153
+ ...ConfigDiagnosticText.usage(optionName, optionBrand),
1154
+ ];
1165
1155
  this.#onDiagnostics(Diagnostic.error(text));
1166
1156
  }
1167
1157
  async parse(commandLineArgs) {
@@ -1215,7 +1205,7 @@ class CommandLineParser {
1215
1205
  index++;
1216
1206
  break;
1217
1207
  }
1218
- await this.#onExpectsValue(optionName, optionDefinition.brand);
1208
+ this.#onExpectsValue(optionName, optionDefinition.brand);
1219
1209
  break;
1220
1210
  case OptionBrand.String:
1221
1211
  if (optionValue !== "") {
@@ -1225,7 +1215,7 @@ class CommandLineParser {
1225
1215
  index++;
1226
1216
  break;
1227
1217
  }
1228
- await this.#onExpectsValue(optionName, optionDefinition.brand);
1218
+ this.#onExpectsValue(optionName, optionDefinition.brand);
1229
1219
  break;
1230
1220
  }
1231
1221
  return index;
@@ -1504,11 +1494,11 @@ class ConfigFileParser {
1504
1494
  }
1505
1495
 
1506
1496
  const defaultOptions = {
1507
- checkSourceFiles: false,
1497
+ checkSourceFiles: true,
1508
1498
  failFast: false,
1509
1499
  plugins: [],
1510
- rejectAnyType: false,
1511
- rejectNeverType: false,
1500
+ rejectAnyType: true,
1501
+ rejectNeverType: true,
1512
1502
  reporters: ["list", "summary"],
1513
1503
  rootPath: Path.resolve("./"),
1514
1504
  target: environmentOptions.typescriptModule != null ? ["current"] : ["latest"],
@@ -1909,6 +1899,293 @@ class ResultHandler {
1909
1899
  }
1910
1900
  }
1911
1901
 
1902
+ var TestTreeNodeBrand;
1903
+ (function (TestTreeNodeBrand) {
1904
+ TestTreeNodeBrand["Describe"] = "describe";
1905
+ TestTreeNodeBrand["Test"] = "test";
1906
+ TestTreeNodeBrand["Expect"] = "expect";
1907
+ })(TestTreeNodeBrand || (TestTreeNodeBrand = {}));
1908
+
1909
+ class TestTreeNode {
1910
+ brand;
1911
+ children = [];
1912
+ #compiler;
1913
+ diagnostics = new Set();
1914
+ flags;
1915
+ name = "";
1916
+ node;
1917
+ parent;
1918
+ constructor(compiler, brand, node, parent, flags) {
1919
+ this.brand = brand;
1920
+ this.#compiler = compiler;
1921
+ this.node = node;
1922
+ this.parent = parent;
1923
+ this.flags = flags;
1924
+ if (node.arguments[0] != null && compiler.isStringLiteralLike(node.arguments[0])) {
1925
+ this.name = node.arguments[0].text;
1926
+ }
1927
+ if (node.arguments[1] != null &&
1928
+ compiler.isFunctionLike(node.arguments[1]) &&
1929
+ compiler.isBlock(node.arguments[1].body)) {
1930
+ const blockStart = node.arguments[1].body.getStart();
1931
+ const blockEnd = node.arguments[1].body.getEnd();
1932
+ for (const diagnostic of parent.diagnostics) {
1933
+ if (diagnostic.start != null && diagnostic.start >= blockStart && diagnostic.start <= blockEnd) {
1934
+ this.diagnostics.add(diagnostic);
1935
+ parent.diagnostics.delete(diagnostic);
1936
+ }
1937
+ }
1938
+ }
1939
+ }
1940
+ validate() {
1941
+ const diagnostics = [];
1942
+ const getText = (node) => `'${node.expression.getText()}()' cannot be nested within '${this.node.expression.getText()}()'.`;
1943
+ const getParentCallExpression = (node) => {
1944
+ while (!this.#compiler.isCallExpression(node.parent)) {
1945
+ node = node.parent;
1946
+ }
1947
+ return node.parent;
1948
+ };
1949
+ switch (this.brand) {
1950
+ case TestTreeNodeBrand.Describe:
1951
+ for (const member of this.children) {
1952
+ if (member.brand === TestTreeNodeBrand.Expect) {
1953
+ diagnostics.push(Diagnostic.error(getText(member.node), DiagnosticOrigin.fromNode(getParentCallExpression(member.node))));
1954
+ }
1955
+ }
1956
+ break;
1957
+ case TestTreeNodeBrand.Test:
1958
+ case TestTreeNodeBrand.Expect:
1959
+ for (const member of this.children) {
1960
+ if (member.brand !== TestTreeNodeBrand.Expect) {
1961
+ diagnostics.push(Diagnostic.error(getText(member.node), DiagnosticOrigin.fromNode(member.node)));
1962
+ }
1963
+ }
1964
+ break;
1965
+ }
1966
+ return diagnostics;
1967
+ }
1968
+ }
1969
+
1970
+ class AssertionNode extends TestTreeNode {
1971
+ isNot;
1972
+ matcherName;
1973
+ matcherNode;
1974
+ modifierNode;
1975
+ notNode;
1976
+ source;
1977
+ target;
1978
+ constructor(compiler, brand, node, parent, flags, matcherNode, modifierNode, notNode) {
1979
+ super(compiler, brand, node, parent, flags);
1980
+ this.isNot = notNode != null;
1981
+ this.matcherName = matcherNode.expression.name;
1982
+ this.matcherNode = matcherNode;
1983
+ this.modifierNode = modifierNode;
1984
+ this.source = this.node.typeArguments ?? this.node.arguments;
1985
+ this.target = this.matcherNode.typeArguments ?? this.matcherNode.arguments;
1986
+ for (const diagnostic of parent.diagnostics) {
1987
+ if (diagnostic.start != null && diagnostic.start >= this.source.pos && diagnostic.start <= this.source.end) {
1988
+ this.diagnostics.add(diagnostic);
1989
+ parent.diagnostics.delete(diagnostic);
1990
+ }
1991
+ }
1992
+ }
1993
+ }
1994
+
1995
+ var TestTreeNodeFlags;
1996
+ (function (TestTreeNodeFlags) {
1997
+ TestTreeNodeFlags[TestTreeNodeFlags["None"] = 0] = "None";
1998
+ TestTreeNodeFlags[TestTreeNodeFlags["Fail"] = 1] = "Fail";
1999
+ TestTreeNodeFlags[TestTreeNodeFlags["Only"] = 2] = "Only";
2000
+ TestTreeNodeFlags[TestTreeNodeFlags["Skip"] = 4] = "Skip";
2001
+ TestTreeNodeFlags[TestTreeNodeFlags["Todo"] = 8] = "Todo";
2002
+ })(TestTreeNodeFlags || (TestTreeNodeFlags = {}));
2003
+
2004
+ class IdentifierLookup {
2005
+ #compiler;
2006
+ #identifiers;
2007
+ #moduleSpecifiers = ['"tstyche"', "'tstyche'"];
2008
+ constructor(compiler, identifiers) {
2009
+ this.#compiler = compiler;
2010
+ this.#identifiers = identifiers ?? {
2011
+ namedImports: {
2012
+ describe: undefined,
2013
+ expect: undefined,
2014
+ it: undefined,
2015
+ namespace: undefined,
2016
+ test: undefined,
2017
+ },
2018
+ namespace: undefined,
2019
+ };
2020
+ }
2021
+ handleImportDeclaration(node) {
2022
+ if (this.#moduleSpecifiers.includes(node.moduleSpecifier.getText()) &&
2023
+ node.importClause?.isTypeOnly !== true &&
2024
+ node.importClause?.namedBindings != null) {
2025
+ if (this.#compiler.isNamedImports(node.importClause.namedBindings)) {
2026
+ for (const element of node.importClause.namedBindings.elements) {
2027
+ if (element.isTypeOnly) {
2028
+ continue;
2029
+ }
2030
+ let identifierKey;
2031
+ if (element.propertyName) {
2032
+ identifierKey = element.propertyName.getText();
2033
+ }
2034
+ else {
2035
+ identifierKey = element.name.getText();
2036
+ }
2037
+ if (identifierKey in this.#identifiers.namedImports) {
2038
+ this.#identifiers.namedImports[identifierKey] = element.name.getText();
2039
+ }
2040
+ }
2041
+ }
2042
+ if (this.#compiler.isNamespaceImport(node.importClause.namedBindings)) {
2043
+ this.#identifiers.namespace = node.importClause.namedBindings.name.getText();
2044
+ }
2045
+ }
2046
+ }
2047
+ resolveTestMemberMeta(node) {
2048
+ let flags = TestTreeNodeFlags.None;
2049
+ let expression = node.expression;
2050
+ while (this.#compiler.isPropertyAccessExpression(expression)) {
2051
+ if (expression.expression.getText() === this.#identifiers.namespace) {
2052
+ break;
2053
+ }
2054
+ switch (expression.name.getText()) {
2055
+ case "fail":
2056
+ flags |= TestTreeNodeFlags.Fail;
2057
+ break;
2058
+ case "only":
2059
+ flags |= TestTreeNodeFlags.Only;
2060
+ break;
2061
+ case "skip":
2062
+ flags |= TestTreeNodeFlags.Skip;
2063
+ break;
2064
+ case "todo":
2065
+ flags |= TestTreeNodeFlags.Todo;
2066
+ break;
2067
+ }
2068
+ expression = expression.expression;
2069
+ }
2070
+ let identifierName;
2071
+ if (this.#compiler.isPropertyAccessExpression(expression) &&
2072
+ expression.expression.getText() === this.#identifiers.namespace) {
2073
+ identifierName = expression.name.getText();
2074
+ }
2075
+ else {
2076
+ identifierName = Object.keys(this.#identifiers.namedImports).find((key) => this.#identifiers.namedImports[key] === expression.getText());
2077
+ }
2078
+ if (!identifierName) {
2079
+ return;
2080
+ }
2081
+ switch (identifierName) {
2082
+ case "describe":
2083
+ return { brand: TestTreeNodeBrand.Describe, flags };
2084
+ case "it":
2085
+ case "test":
2086
+ return { brand: TestTreeNodeBrand.Test, flags };
2087
+ case "expect":
2088
+ return { brand: TestTreeNodeBrand.Expect, flags };
2089
+ }
2090
+ return;
2091
+ }
2092
+ }
2093
+
2094
+ class TestTree {
2095
+ children = [];
2096
+ diagnostics;
2097
+ hasOnly = false;
2098
+ sourceFile;
2099
+ constructor(diagnostics, sourceFile) {
2100
+ this.diagnostics = diagnostics;
2101
+ this.sourceFile = sourceFile;
2102
+ }
2103
+ }
2104
+
2105
+ class CollectService {
2106
+ #compiler;
2107
+ constructor(compiler) {
2108
+ this.#compiler = compiler;
2109
+ }
2110
+ #collectTestTreeNodes(node, identifiers, parent) {
2111
+ if (this.#compiler.isCallExpression(node)) {
2112
+ const meta = identifiers.resolveTestMemberMeta(node);
2113
+ if (meta != null && (meta.brand === TestTreeNodeBrand.Describe || meta.brand === TestTreeNodeBrand.Test)) {
2114
+ const testTreeNode = new TestTreeNode(this.#compiler, meta.brand, node, parent, meta.flags);
2115
+ parent.children.push(testTreeNode);
2116
+ EventEmitter.dispatch(["collect:node", { testNode: testTreeNode }]);
2117
+ this.#compiler.forEachChild(node, (node) => {
2118
+ this.#collectTestTreeNodes(node, identifiers, testTreeNode);
2119
+ });
2120
+ return;
2121
+ }
2122
+ if (meta != null && meta.brand === TestTreeNodeBrand.Expect) {
2123
+ const modifierNode = this.#getChainedNode(node, "type");
2124
+ if (!modifierNode) {
2125
+ return;
2126
+ }
2127
+ const notNode = this.#getChainedNode(modifierNode, "not");
2128
+ const matcherNode = this.#getChainedNode(notNode ?? modifierNode)?.parent;
2129
+ if (!matcherNode || !this.#isMatcherNode(matcherNode)) {
2130
+ return;
2131
+ }
2132
+ const assertionNode = new AssertionNode(this.#compiler, meta.brand, node, parent, meta.flags, matcherNode, modifierNode, notNode);
2133
+ parent.children.push(assertionNode);
2134
+ EventEmitter.dispatch(["collect:node", { testNode: assertionNode }]);
2135
+ this.#compiler.forEachChild(node, (node) => {
2136
+ this.#collectTestTreeNodes(node, identifiers, assertionNode);
2137
+ });
2138
+ return;
2139
+ }
2140
+ }
2141
+ if (this.#compiler.isImportDeclaration(node)) {
2142
+ identifiers.handleImportDeclaration(node);
2143
+ return;
2144
+ }
2145
+ this.#compiler.forEachChild(node, (node) => {
2146
+ this.#collectTestTreeNodes(node, identifiers, parent);
2147
+ });
2148
+ }
2149
+ createTestTree(sourceFile, semanticDiagnostics = []) {
2150
+ const testTree = new TestTree(new Set(semanticDiagnostics), sourceFile);
2151
+ EventEmitter.dispatch(["collect:start", { testTree }]);
2152
+ this.#collectTestTreeNodes(sourceFile, new IdentifierLookup(this.#compiler), testTree);
2153
+ EventEmitter.dispatch(["collect:end", { testTree }]);
2154
+ return testTree;
2155
+ }
2156
+ #getChainedNode({ parent }, name) {
2157
+ if (!this.#compiler.isPropertyAccessExpression(parent)) {
2158
+ return;
2159
+ }
2160
+ if (name != null && name !== parent.name.getText()) {
2161
+ return;
2162
+ }
2163
+ return parent;
2164
+ }
2165
+ #isMatcherNode(node) {
2166
+ return this.#compiler.isCallExpression(node) && this.#compiler.isPropertyAccessExpression(node.expression);
2167
+ }
2168
+ }
2169
+
2170
+ class TestTreeHandler {
2171
+ testTree;
2172
+ on([event, payload]) {
2173
+ switch (event) {
2174
+ case "collect:start":
2175
+ this.testTree = payload.testTree;
2176
+ break;
2177
+ case "collect:end":
2178
+ this.testTree = undefined;
2179
+ break;
2180
+ case "collect:node":
2181
+ if (payload.testNode.flags & TestTreeNodeFlags.Only) {
2182
+ this.testTree.hasOnly = true;
2183
+ }
2184
+ break;
2185
+ }
2186
+ }
2187
+ }
2188
+
1912
2189
  function jsx(type, props) {
1913
2190
  return { props, type };
1914
2191
  }
@@ -2013,12 +2290,15 @@ function CodeLineText({ gutterWidth, lineNumber, lineNumberColor = Color.Gray, l
2013
2290
  function SquiggleLineText({ gutterWidth, indentWidth = 0, squiggleColor, squiggleWidth }) {
2014
2291
  return (jsx(Line, { children: [" ".repeat(gutterWidth), jsx(Text, { color: Color.Gray, children: " | " }), " ".repeat(indentWidth), jsx(Text, { color: squiggleColor, children: "~".repeat(squiggleWidth === 0 ? 1 : squiggleWidth) })] }));
2015
2292
  }
2016
- function CodeSpanText({ diagnosticCategory, diagnosticOrigin }) {
2293
+ function CodeFrameText({ diagnosticCategory, diagnosticOrigin, options }) {
2294
+ const linesAbove = options?.linesAbove ?? 2;
2295
+ const linesBelow = options?.linesBelow ?? 3;
2296
+ const showBreadcrumbs = options?.showBreadcrumbs ?? true;
2017
2297
  const lineMap = diagnosticOrigin.sourceFile.getLineStarts();
2018
2298
  const { character: firstMarkedLineCharacter, line: firstMarkedLine } = diagnosticOrigin.sourceFile.getLineAndCharacterOfPosition(diagnosticOrigin.start);
2019
2299
  const { character: lastMarkedLineCharacter, line: lastMarkedLine } = diagnosticOrigin.sourceFile.getLineAndCharacterOfPosition(diagnosticOrigin.end);
2020
- const firstLine = Math.max(firstMarkedLine - 2, 0);
2021
- const lastLine = Math.min(firstLine + 5, lineMap.length - 1);
2300
+ const firstLine = Math.max(firstMarkedLine - linesAbove, 0);
2301
+ const lastLine = Math.min(lastMarkedLine + linesBelow, lineMap.length - 1);
2022
2302
  const gutterWidth = (lastLine + 1).toString().length + 2;
2023
2303
  let highlightColor;
2024
2304
  switch (diagnosticCategory) {
@@ -2029,43 +2309,47 @@ function CodeSpanText({ diagnosticCategory, diagnosticOrigin }) {
2029
2309
  highlightColor = Color.Yellow;
2030
2310
  break;
2031
2311
  }
2032
- const codeSpan = [];
2312
+ const codeFrame = [];
2033
2313
  for (let index = firstLine; index <= lastLine; index++) {
2034
2314
  const lineStart = lineMap[index];
2035
2315
  const lineEnd = index === lineMap.length - 1 ? diagnosticOrigin.sourceFile.text.length : lineMap[index + 1];
2036
2316
  const lineText = diagnosticOrigin.sourceFile.text.slice(lineStart, lineEnd).trimEnd().replace(/\t/g, " ");
2037
2317
  if (index >= firstMarkedLine && index <= lastMarkedLine) {
2038
- codeSpan.push(jsx(CodeLineText, { gutterWidth: gutterWidth, lineNumber: index + 1, lineNumberColor: highlightColor, lineText: lineText }));
2318
+ codeFrame.push(jsx(CodeLineText, { gutterWidth: gutterWidth, lineNumber: index + 1, lineNumberColor: highlightColor, lineText: lineText }));
2039
2319
  if (index === firstMarkedLine) {
2040
2320
  const squiggleLength = index === lastMarkedLine
2041
2321
  ? lastMarkedLineCharacter - firstMarkedLineCharacter
2042
2322
  : lineText.length - firstMarkedLineCharacter;
2043
- codeSpan.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, indentWidth: firstMarkedLineCharacter, squiggleColor: highlightColor, squiggleWidth: squiggleLength }));
2323
+ codeFrame.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, indentWidth: firstMarkedLineCharacter, squiggleColor: highlightColor, squiggleWidth: squiggleLength }));
2044
2324
  }
2045
2325
  else if (index === lastMarkedLine) {
2046
- codeSpan.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, squiggleColor: highlightColor, squiggleWidth: lastMarkedLineCharacter }));
2326
+ codeFrame.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, squiggleColor: highlightColor, squiggleWidth: lastMarkedLineCharacter }));
2047
2327
  }
2048
2328
  else {
2049
- codeSpan.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, squiggleColor: highlightColor, squiggleWidth: lineText.length }));
2329
+ codeFrame.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, squiggleColor: highlightColor, squiggleWidth: lineText.length }));
2050
2330
  }
2051
2331
  }
2052
2332
  else {
2053
- codeSpan.push(jsx(CodeLineText, { gutterWidth: gutterWidth, lineNumber: index + 1, lineText: lineText }));
2333
+ codeFrame.push(jsx(CodeLineText, { gutterWidth: gutterWidth, lineNumber: index + 1, lineText: lineText }));
2054
2334
  }
2055
2335
  }
2056
- const location = (jsx(Line, { children: [" ".repeat(gutterWidth + 2), jsx(Text, { color: Color.Gray, children: " at " }), jsx(Text, { color: Color.Cyan, children: Path.relative("", diagnosticOrigin.sourceFile.fileName) }), jsx(Text, { color: Color.Gray, children: `:${firstMarkedLine + 1}:${firstMarkedLineCharacter + 1}` }), diagnosticOrigin.assertion && jsx(BreadcrumbsText, { ancestor: diagnosticOrigin.assertion.parent })] }));
2057
- return (jsx(Text, { children: [codeSpan, jsx(Line, {}), location] }));
2336
+ let breadcrumbs;
2337
+ if (showBreadcrumbs && diagnosticOrigin.assertion != null) {
2338
+ breadcrumbs = jsx(BreadcrumbsText, { ancestor: diagnosticOrigin.assertion.parent });
2339
+ }
2340
+ const location = (jsx(Line, { children: [" ".repeat(gutterWidth + 2), jsx(Text, { color: Color.Gray, children: " at " }), jsx(Text, { color: Color.Cyan, children: Path.relative("", diagnosticOrigin.sourceFile.fileName) }), jsx(Text, { color: Color.Gray, children: `:${firstMarkedLine + 1}:${firstMarkedLineCharacter + 1}` }), breadcrumbs] }));
2341
+ return (jsx(Text, { children: [codeFrame, jsx(Line, {}), location] }));
2058
2342
  }
2059
2343
 
2060
- function DiagnosticText({ diagnostic }) {
2344
+ function DiagnosticText({ codeFrameOptions, diagnostic }) {
2061
2345
  const code = diagnostic.code ? jsx(Text, { color: Color.Gray, children: [" ", diagnostic.code] }) : undefined;
2062
2346
  const text = Array.isArray(diagnostic.text) ? diagnostic.text : [diagnostic.text];
2063
2347
  const message = text.map((text, index) => (jsx(Text, { children: [index === 1 ? jsx(Line, {}) : undefined, jsx(Line, { children: [text, index === 0 ? code : undefined] })] })));
2064
2348
  const related = diagnostic.related?.map((relatedDiagnostic) => jsx(DiagnosticText, { diagnostic: relatedDiagnostic }));
2065
- const codeSpan = diagnostic.origin ? (jsx(Text, { children: [jsx(Line, {}), jsx(CodeSpanText, { diagnosticCategory: diagnostic.category, diagnosticOrigin: diagnostic.origin })] })) : undefined;
2066
- return (jsx(Text, { children: [message, codeSpan, jsx(Line, {}), jsx(Text, { indent: 2, children: related })] }));
2349
+ const codeFrame = diagnostic.origin ? (jsx(Text, { children: [jsx(Line, {}), jsx(CodeFrameText, { diagnosticCategory: diagnostic.category, diagnosticOrigin: diagnostic.origin, options: codeFrameOptions })] })) : undefined;
2350
+ return (jsx(Text, { children: [message, codeFrame, jsx(Line, {}), jsx(Text, { indent: 2, children: related })] }));
2067
2351
  }
2068
- function diagnosticText(diagnostic) {
2352
+ function diagnosticText(diagnostic, codeFrameOptions = {}) {
2069
2353
  let prefix;
2070
2354
  switch (diagnostic.category) {
2071
2355
  case DiagnosticCategory.Error:
@@ -2075,7 +2359,7 @@ function diagnosticText(diagnostic) {
2075
2359
  prefix = jsx(Text, { color: Color.Yellow, children: "Warning: " });
2076
2360
  break;
2077
2361
  }
2078
- return (jsx(Text, { children: [prefix, jsx(DiagnosticText, { diagnostic: diagnostic })] }));
2362
+ return (jsx(Text, { children: [prefix, jsx(DiagnosticText, { codeFrameOptions: codeFrameOptions, diagnostic: diagnostic })] }));
2079
2363
  }
2080
2364
 
2081
2365
  function FileNameText({ filePath }) {
@@ -2143,7 +2427,7 @@ function CommandLineUsageText() {
2143
2427
  const usage = [
2144
2428
  ["tstyche", "Run all tests."],
2145
2429
  ["tstyche path/to/first.test.ts", "Only run the test files with matching path."],
2146
- ["tstyche --target 4.9,5.3.2,current", "Test on all specified versions of TypeScript."],
2430
+ ["tstyche --target 5.3,5.6.2,current", "Test on all specified versions of TypeScript."],
2147
2431
  ];
2148
2432
  const usageText = usage.map(([commandText, descriptionText]) => (jsx(Line, { children: [jsx(CommandText, { text: commandText }), jsx(OptionDescriptionText, { text: descriptionText })] })));
2149
2433
  return jsx(Text, { children: usageText });
@@ -2356,21 +2640,11 @@ class ListReporter extends BaseReporter {
2356
2640
  #hasReportedError = false;
2357
2641
  #hasReportedUses = false;
2358
2642
  #isFileViewExpanded = false;
2359
- #seenDeprecations = new Set();
2360
2643
  get #isLastFile() {
2361
2644
  return this.#fileCount === 0;
2362
2645
  }
2363
2646
  on([event, payload]) {
2364
2647
  switch (event) {
2365
- case "deprecation:info": {
2366
- for (const diagnostic of payload.diagnostics) {
2367
- if (!this.#seenDeprecations.has(diagnostic.text.toString())) {
2368
- this.#fileView.addMessage(diagnosticText(diagnostic));
2369
- this.#seenDeprecations.add(diagnostic.text.toString());
2370
- }
2371
- }
2372
- break;
2373
- }
2374
2648
  case "run:start":
2375
2649
  this.#isFileViewExpanded = payload.result.tasks.length === 1 && this.resolvedConfig.watch !== true;
2376
2650
  break;
@@ -2422,7 +2696,6 @@ class ListReporter extends BaseReporter {
2422
2696
  this.#hasReportedError = true;
2423
2697
  }
2424
2698
  this.#fileView.clear();
2425
- this.#seenDeprecations.clear();
2426
2699
  break;
2427
2700
  case "describe:start":
2428
2701
  if (this.#isFileViewExpanded) {
@@ -2793,19 +3066,19 @@ class Debounce {
2793
3066
  this.#delay = delay;
2794
3067
  this.#onResolve = onResolve;
2795
3068
  }
2796
- clearTimeout() {
3069
+ cancel() {
2797
3070
  clearTimeout(this.#timeout);
2798
3071
  }
2799
- refreshTimeout() {
2800
- this.clearTimeout();
3072
+ refresh() {
3073
+ this.cancel();
2801
3074
  this.#timeout = setTimeout(() => {
2802
3075
  this.#resolve?.(this.#onResolve());
2803
3076
  }, this.#delay);
2804
3077
  }
2805
- resolveWith(value) {
3078
+ resolve(value) {
2806
3079
  this.#resolve?.(value);
2807
3080
  }
2808
- setup() {
3081
+ schedule() {
2809
3082
  return new Promise((resolve) => {
2810
3083
  this.#resolve = resolve;
2811
3084
  });
@@ -2833,13 +3106,13 @@ class WatchService {
2833
3106
  };
2834
3107
  const debounce = new Debounce(100, onResolve);
2835
3108
  const onClose = (reason) => {
2836
- debounce.clearTimeout();
3109
+ debounce.cancel();
2837
3110
  this.#inputService?.close();
2838
3111
  for (const watcher of this.#watchers) {
2839
3112
  watcher.close();
2840
3113
  }
2841
3114
  cancellationToken.cancel(reason);
2842
- debounce.resolveWith([]);
3115
+ debounce.resolve([]);
2843
3116
  };
2844
3117
  if (!environmentOptions.noInteractive) {
2845
3118
  const onInput = (chunk) => {
@@ -2854,9 +3127,9 @@ class WatchService {
2854
3127
  case "\u000D":
2855
3128
  case "\u0020":
2856
3129
  case "a":
2857
- debounce.clearTimeout();
3130
+ debounce.cancel();
2858
3131
  if (this.#watchedTestFiles.size > 0) {
2859
- debounce.resolveWith([...this.#watchedTestFiles.values()]);
3132
+ debounce.resolve([...this.#watchedTestFiles.values()]);
2860
3133
  }
2861
3134
  break;
2862
3135
  }
@@ -2864,7 +3137,7 @@ class WatchService {
2864
3137
  this.#inputService = new InputService(onInput);
2865
3138
  }
2866
3139
  const onChangedFile = (filePath) => {
2867
- debounce.refreshTimeout();
3140
+ debounce.refresh();
2868
3141
  let task = this.#watchedTestFiles.get(filePath);
2869
3142
  if (task != null) {
2870
3143
  this.#changedTestFiles.set(filePath, task);
@@ -2879,7 +3152,7 @@ class WatchService {
2879
3152
  this.#changedTestFiles.delete(filePath);
2880
3153
  this.#watchedTestFiles.delete(filePath);
2881
3154
  if (this.#watchedTestFiles.size === 0) {
2882
- debounce.clearTimeout();
3155
+ debounce.cancel();
2883
3156
  this.#onDiagnostics(Diagnostic.error(SelectDiagnosticText.noTestFilesWereLeft(this.#resolvedConfig)));
2884
3157
  }
2885
3158
  };
@@ -2892,7 +3165,7 @@ class WatchService {
2892
3165
  watcher.watch();
2893
3166
  }
2894
3167
  while (!cancellationToken.isCancellationRequested) {
2895
- const testFiles = await debounce.setup();
3168
+ const testFiles = await debounce.schedule();
2896
3169
  if (testFiles.length > 0) {
2897
3170
  yield testFiles;
2898
3171
  }
@@ -2900,276 +3173,7 @@ class WatchService {
2900
3173
  }
2901
3174
  }
2902
3175
 
2903
- var TestMemberBrand;
2904
- (function (TestMemberBrand) {
2905
- TestMemberBrand["Describe"] = "describe";
2906
- TestMemberBrand["Test"] = "test";
2907
- TestMemberBrand["Expect"] = "expect";
2908
- })(TestMemberBrand || (TestMemberBrand = {}));
2909
-
2910
- class TestMember {
2911
- brand;
2912
- #compiler;
2913
- diagnostics = new Set();
2914
- flags;
2915
- members = [];
2916
- name = "";
2917
- node;
2918
- parent;
2919
- constructor(compiler, brand, node, parent, flags) {
2920
- this.brand = brand;
2921
- this.#compiler = compiler;
2922
- this.node = node;
2923
- this.parent = parent;
2924
- this.flags = flags;
2925
- if (node.arguments[0] != null && compiler.isStringLiteralLike(node.arguments[0])) {
2926
- this.name = node.arguments[0].text;
2927
- }
2928
- if (node.arguments[1] != null &&
2929
- compiler.isFunctionLike(node.arguments[1]) &&
2930
- compiler.isBlock(node.arguments[1].body)) {
2931
- const blockStart = node.arguments[1].body.getStart();
2932
- const blockEnd = node.arguments[1].body.getEnd();
2933
- for (const diagnostic of parent.diagnostics) {
2934
- if (diagnostic.start != null && diagnostic.start >= blockStart && diagnostic.start <= blockEnd) {
2935
- this.diagnostics.add(diagnostic);
2936
- parent.diagnostics.delete(diagnostic);
2937
- }
2938
- }
2939
- }
2940
- }
2941
- validate() {
2942
- const diagnostics = [];
2943
- const getText = (node) => `'${node.expression.getText()}()' cannot be nested within '${this.node.expression.getText()}()'.`;
2944
- const getParentCallExpression = (node) => {
2945
- while (!this.#compiler.isCallExpression(node.parent)) {
2946
- node = node.parent;
2947
- }
2948
- return node.parent;
2949
- };
2950
- switch (this.brand) {
2951
- case TestMemberBrand.Describe:
2952
- for (const member of this.members) {
2953
- if (member.brand === TestMemberBrand.Expect) {
2954
- diagnostics.push(Diagnostic.error(getText(member.node), DiagnosticOrigin.fromNode(getParentCallExpression(member.node))));
2955
- }
2956
- }
2957
- break;
2958
- case TestMemberBrand.Test:
2959
- case TestMemberBrand.Expect:
2960
- for (const member of this.members) {
2961
- if (member.brand !== TestMemberBrand.Expect) {
2962
- diagnostics.push(Diagnostic.error(getText(member.node), DiagnosticOrigin.fromNode(member.node)));
2963
- }
2964
- }
2965
- break;
2966
- }
2967
- return diagnostics;
2968
- }
2969
- }
2970
-
2971
- class Assertion extends TestMember {
2972
- isNot;
2973
- matcherName;
2974
- matcherNode;
2975
- modifierNode;
2976
- notNode;
2977
- source;
2978
- target;
2979
- constructor(compiler, brand, node, parent, flags, matcherNode, modifierNode, notNode) {
2980
- super(compiler, brand, node, parent, flags);
2981
- this.isNot = notNode != null;
2982
- this.matcherName = matcherNode.expression.name;
2983
- this.matcherNode = matcherNode;
2984
- this.modifierNode = modifierNode;
2985
- this.source = this.node.typeArguments ?? this.node.arguments;
2986
- this.target = this.matcherNode.typeArguments ?? this.matcherNode.arguments;
2987
- for (const diagnostic of parent.diagnostics) {
2988
- if (diagnostic.start != null && diagnostic.start >= this.source.pos && diagnostic.start <= this.source.end) {
2989
- this.diagnostics.add(diagnostic);
2990
- parent.diagnostics.delete(diagnostic);
2991
- }
2992
- }
2993
- }
2994
- }
2995
-
2996
- var TestMemberFlags;
2997
- (function (TestMemberFlags) {
2998
- TestMemberFlags[TestMemberFlags["None"] = 0] = "None";
2999
- TestMemberFlags[TestMemberFlags["Fail"] = 1] = "Fail";
3000
- TestMemberFlags[TestMemberFlags["Only"] = 2] = "Only";
3001
- TestMemberFlags[TestMemberFlags["Skip"] = 4] = "Skip";
3002
- TestMemberFlags[TestMemberFlags["Todo"] = 8] = "Todo";
3003
- })(TestMemberFlags || (TestMemberFlags = {}));
3004
-
3005
- class IdentifierLookup {
3006
- #compiler;
3007
- #identifiers;
3008
- #moduleSpecifiers = ['"tstyche"', "'tstyche'"];
3009
- constructor(compiler, identifiers) {
3010
- this.#compiler = compiler;
3011
- this.#identifiers = identifiers ?? {
3012
- namedImports: {
3013
- describe: undefined,
3014
- expect: undefined,
3015
- it: undefined,
3016
- namespace: undefined,
3017
- test: undefined,
3018
- },
3019
- namespace: undefined,
3020
- };
3021
- }
3022
- handleImportDeclaration(node) {
3023
- if (this.#moduleSpecifiers.includes(node.moduleSpecifier.getText()) &&
3024
- node.importClause?.isTypeOnly !== true &&
3025
- node.importClause?.namedBindings != null) {
3026
- if (this.#compiler.isNamedImports(node.importClause.namedBindings)) {
3027
- for (const element of node.importClause.namedBindings.elements) {
3028
- if (element.isTypeOnly) {
3029
- continue;
3030
- }
3031
- let identifierKey;
3032
- if (element.propertyName) {
3033
- identifierKey = element.propertyName.getText();
3034
- }
3035
- else {
3036
- identifierKey = element.name.getText();
3037
- }
3038
- if (identifierKey in this.#identifiers.namedImports) {
3039
- this.#identifiers.namedImports[identifierKey] = element.name.getText();
3040
- }
3041
- }
3042
- }
3043
- if (this.#compiler.isNamespaceImport(node.importClause.namedBindings)) {
3044
- this.#identifiers.namespace = node.importClause.namedBindings.name.getText();
3045
- }
3046
- }
3047
- }
3048
- resolveTestMemberMeta(node) {
3049
- let flags = TestMemberFlags.None;
3050
- let expression = node.expression;
3051
- while (this.#compiler.isPropertyAccessExpression(expression)) {
3052
- if (expression.expression.getText() === this.#identifiers.namespace) {
3053
- break;
3054
- }
3055
- switch (expression.name.getText()) {
3056
- case "fail":
3057
- flags |= TestMemberFlags.Fail;
3058
- break;
3059
- case "only":
3060
- flags |= TestMemberFlags.Only;
3061
- break;
3062
- case "skip":
3063
- flags |= TestMemberFlags.Skip;
3064
- break;
3065
- case "todo":
3066
- flags |= TestMemberFlags.Todo;
3067
- break;
3068
- }
3069
- expression = expression.expression;
3070
- }
3071
- let identifierName;
3072
- if (this.#compiler.isPropertyAccessExpression(expression) &&
3073
- expression.expression.getText() === this.#identifiers.namespace) {
3074
- identifierName = expression.name.getText();
3075
- }
3076
- else {
3077
- identifierName = Object.keys(this.#identifiers.namedImports).find((key) => this.#identifiers.namedImports[key] === expression.getText());
3078
- }
3079
- if (!identifierName) {
3080
- return;
3081
- }
3082
- switch (identifierName) {
3083
- case "describe":
3084
- return { brand: TestMemberBrand.Describe, flags };
3085
- case "it":
3086
- case "test":
3087
- return { brand: TestMemberBrand.Test, flags };
3088
- case "expect":
3089
- return { brand: TestMemberBrand.Expect, flags };
3090
- }
3091
- return;
3092
- }
3093
- }
3094
-
3095
- class TestTree {
3096
- diagnostics;
3097
- members = [];
3098
- sourceFile;
3099
- constructor(diagnostics, sourceFile) {
3100
- this.diagnostics = diagnostics;
3101
- this.sourceFile = sourceFile;
3102
- }
3103
- get hasOnly() {
3104
- function hasOnly(root) {
3105
- return root.members.some((branch) => branch.flags & TestMemberFlags.Only || ("members" in branch && hasOnly(branch)));
3106
- }
3107
- return hasOnly(this);
3108
- }
3109
- }
3110
-
3111
- class CollectService {
3112
- #compiler;
3113
- constructor(compiler) {
3114
- this.#compiler = compiler;
3115
- }
3116
- #collectTestMembers(node, identifiers, parent) {
3117
- if (this.#compiler.isCallExpression(node)) {
3118
- const meta = identifiers.resolveTestMemberMeta(node);
3119
- if (meta != null && (meta.brand === TestMemberBrand.Describe || meta.brand === TestMemberBrand.Test)) {
3120
- const testMember = new TestMember(this.#compiler, meta.brand, node, parent, meta.flags);
3121
- parent.members.push(testMember);
3122
- this.#compiler.forEachChild(node, (node) => {
3123
- this.#collectTestMembers(node, identifiers, testMember);
3124
- });
3125
- return;
3126
- }
3127
- if (meta != null && meta.brand === TestMemberBrand.Expect) {
3128
- const modifierNode = this.#getChainedNode(node, "type");
3129
- if (!modifierNode) {
3130
- return;
3131
- }
3132
- const notNode = this.#getChainedNode(modifierNode, "not");
3133
- const matcherNode = this.#getChainedNode(notNode ?? modifierNode)?.parent;
3134
- if (!matcherNode || !this.#isMatcherNode(matcherNode)) {
3135
- return;
3136
- }
3137
- const assertion = new Assertion(this.#compiler, meta.brand, node, parent, meta.flags, matcherNode, modifierNode, notNode);
3138
- parent.members.push(assertion);
3139
- this.#compiler.forEachChild(node, (node) => {
3140
- this.#collectTestMembers(node, identifiers, assertion);
3141
- });
3142
- return;
3143
- }
3144
- }
3145
- if (this.#compiler.isImportDeclaration(node)) {
3146
- identifiers.handleImportDeclaration(node);
3147
- return;
3148
- }
3149
- this.#compiler.forEachChild(node, (node) => {
3150
- this.#collectTestMembers(node, identifiers, parent);
3151
- });
3152
- }
3153
- createTestTree(sourceFile, semanticDiagnostics = []) {
3154
- const testTree = new TestTree(new Set(semanticDiagnostics), sourceFile);
3155
- this.#collectTestMembers(sourceFile, new IdentifierLookup(this.#compiler), testTree);
3156
- return testTree;
3157
- }
3158
- #getChainedNode({ parent }, name) {
3159
- if (!this.#compiler.isPropertyAccessExpression(parent)) {
3160
- return;
3161
- }
3162
- if (name != null && name !== parent.name.getText()) {
3163
- return;
3164
- }
3165
- return parent;
3166
- }
3167
- #isMatcherNode(node) {
3168
- return this.#compiler.isCallExpression(node) && this.#compiler.isPropertyAccessExpression(node.expression);
3169
- }
3170
- }
3171
-
3172
- class ProjectService {
3176
+ class ProjectService {
3173
3177
  #compiler;
3174
3178
  #lastSeenProject = "";
3175
3179
  #resolvedConfig;
@@ -3227,24 +3231,19 @@ class ProjectService {
3227
3231
  }
3228
3232
  #getDefaultCompilerOptions() {
3229
3233
  const defaultCompilerOptions = {
3234
+ allowImportingTsExtensions: true,
3230
3235
  allowJs: true,
3231
3236
  checkJs: true,
3232
- esModuleInterop: true,
3233
- jsx: "preserve",
3234
- module: "esnext",
3235
- moduleResolution: "node",
3237
+ exactOptionalPropertyTypes: true,
3238
+ jsx: this.#compiler.JsxEmit.Preserve,
3239
+ module: this.#compiler.ModuleKind.NodeNext,
3240
+ moduleResolution: this.#compiler.ModuleResolutionKind.NodeNext,
3241
+ noUncheckedIndexedAccess: true,
3236
3242
  resolveJsonModule: true,
3237
- strictFunctionTypes: true,
3238
- strictNullChecks: true,
3239
- target: "esnext",
3243
+ strict: true,
3244
+ target: this.#compiler.ScriptTarget.ESNext,
3245
+ verbatimModuleSyntax: true,
3240
3246
  };
3241
- if (Version.isSatisfiedWith(this.#compiler.version, "5.4")) {
3242
- defaultCompilerOptions.module = "preserve";
3243
- }
3244
- if (Version.isSatisfiedWith(this.#compiler.version, "5.0")) {
3245
- defaultCompilerOptions.allowImportingTsExtensions = true;
3246
- defaultCompilerOptions.moduleResolution = "bundler";
3247
- }
3248
3247
  return defaultCompilerOptions;
3249
3248
  }
3250
3249
  getDefaultProject(filePath) {
@@ -3336,12 +3335,6 @@ class ExpectDiagnosticText {
3336
3335
  static componentDoesNotAcceptProps(isTypeNode) {
3337
3336
  return `${isTypeNode ? "Component type" : "Component"} does not accept props of the given type.`;
3338
3337
  }
3339
- static matcherIsDeprecated(matcherNameText) {
3340
- return [
3341
- `The '.${matcherNameText}()' matcher is deprecated and will be removed in TSTyche 4.`,
3342
- "To learn more, visit https://tstyche.org/releases/tstyche-3",
3343
- ];
3344
- }
3345
3338
  static matcherIsNotSupported(matcherNameText) {
3346
3339
  return `The '.${matcherNameText}()' matcher is not supported.`;
3347
3340
  }
@@ -3366,18 +3359,9 @@ class ExpectDiagnosticText {
3366
3359
  static typeDoesNotHaveProperty(typeText, propertyNameText) {
3367
3360
  return `Type '${typeText}' does not have property '${propertyNameText}'.`;
3368
3361
  }
3369
- static typeDoesMatch(sourceTypeText, targetTypeText) {
3370
- return `Type '${sourceTypeText}' does match type '${targetTypeText}'.`;
3371
- }
3372
- static typeDoesNotMatch(sourceTypeText, targetTypeText) {
3373
- return `Type '${sourceTypeText}' does not match type '${targetTypeText}'.`;
3374
- }
3375
3362
  static typeHasProperty(typeText, propertyNameText) {
3376
3363
  return `Type '${typeText}' has property '${propertyNameText}'.`;
3377
3364
  }
3378
- static typeIs(typeText) {
3379
- return `Type is '${typeText}'.`;
3380
- }
3381
3365
  static typeIsAssignableTo(sourceTypeText, targetTypeText) {
3382
3366
  return `Type '${sourceTypeText}' is assignable to type '${targetTypeText}'.`;
3383
3367
  }
@@ -3438,18 +3422,9 @@ class MatchWorker {
3438
3422
  checkHasApplicableIndexType(sourceNode, targetNode) {
3439
3423
  const sourceType = this.getType(sourceNode);
3440
3424
  const targetType = this.getType(targetNode);
3441
- if (Version.isSatisfiedWith(this.#compiler.version, "4.4")) {
3442
- return this.#typeChecker
3443
- .getIndexInfosOfType(sourceType)
3444
- .some(({ keyType }) => this.#typeChecker.isApplicableIndexType(targetType, keyType));
3445
- }
3446
- if (targetType.flags & this.#compiler.TypeFlags.StringLiteral) {
3447
- return sourceType.getStringIndexType() != null;
3448
- }
3449
- if (targetType.flags & this.#compiler.TypeFlags.NumberLiteral) {
3450
- return (sourceType.getStringIndexType() ?? sourceType.getNumberIndexType()) != null;
3451
- }
3452
- return false;
3425
+ return this.#typeChecker
3426
+ .getIndexInfosOfType(sourceType)
3427
+ .some(({ keyType }) => this.#typeChecker.isApplicableIndexType(targetType, keyType));
3453
3428
  }
3454
3429
  checkHasProperty(sourceNode, propertyNameText) {
3455
3430
  const sourceType = this.getType(sourceNode);
@@ -3471,10 +3446,6 @@ class MatchWorker {
3471
3446
  this.checkIsAssignableTo(sourceNode, targetNode) &&
3472
3447
  this.checkIsAssignableWith(sourceNode, targetNode));
3473
3448
  }
3474
- checkIsSubtype(sourceNode, targetNode) {
3475
- const relation = this.#typeChecker.relation.subtype;
3476
- return this.#checkIsRelatedTo(sourceNode, targetNode, relation);
3477
- }
3478
3449
  #checkIsRelatedTo(sourceNode, targetNode, relation) {
3479
3450
  const sourceType = relation === this.#typeChecker.relation.identity
3480
3451
  ? this.#simplifyType(this.getType(sourceNode))
@@ -3561,26 +3532,6 @@ class MatchWorker {
3561
3532
  }
3562
3533
  }
3563
3534
 
3564
- class PrimitiveTypeMatcher {
3565
- #targetTypeFlag;
3566
- constructor(targetTypeFlag) {
3567
- this.#targetTypeFlag = targetTypeFlag;
3568
- }
3569
- #explain(matchWorker, sourceNode) {
3570
- const sourceTypeText = matchWorker.getTypeText(sourceNode);
3571
- const origin = DiagnosticOrigin.fromAssertion(matchWorker.assertion);
3572
- return [Diagnostic.error(ExpectDiagnosticText.typeIs(sourceTypeText), origin)];
3573
- }
3574
- match(matchWorker, sourceNode) {
3575
- const sourceType = matchWorker.getType(sourceNode);
3576
- const isMatch = !!(sourceType.flags & this.#targetTypeFlag);
3577
- return {
3578
- explain: () => this.#explain(matchWorker, sourceNode),
3579
- isMatch,
3580
- };
3581
- }
3582
- }
3583
-
3584
3535
  class ToAcceptProps {
3585
3536
  #compiler;
3586
3537
  #typeChecker;
@@ -3868,17 +3819,6 @@ class ToHaveProperty {
3868
3819
  }
3869
3820
  }
3870
3821
 
3871
- class ToMatch extends RelationMatcherBase {
3872
- explainText = ExpectDiagnosticText.typeDoesMatch;
3873
- explainNotText = ExpectDiagnosticText.typeDoesNotMatch;
3874
- match(matchWorker, sourceNode, targetNode) {
3875
- return {
3876
- explain: () => this.explain(matchWorker, sourceNode, targetNode),
3877
- isMatch: matchWorker.checkIsSubtype(sourceNode, targetNode),
3878
- };
3879
- }
3880
- }
3881
-
3882
3822
  class ToRaiseError {
3883
3823
  #compiler;
3884
3824
  constructor(compiler) {
@@ -3948,14 +3888,17 @@ class ToRaiseError {
3948
3888
  };
3949
3889
  }
3950
3890
  #matchExpectedError(diagnostic, targetNode) {
3891
+ if (this.#compiler.isNumericLiteral(targetNode)) {
3892
+ return Number.parseInt(targetNode.text, 10) === diagnostic.code;
3893
+ }
3894
+ const messageText = typeof diagnostic.messageText === "string"
3895
+ ? diagnostic.messageText
3896
+ : Diagnostic.toMessageText(diagnostic.messageText).join("\n");
3951
3897
  if (this.#compiler.isRegularExpressionLiteral(targetNode)) {
3952
3898
  const targetRegex = new RegExp(...targetNode.text.slice(1).split("/"));
3953
- return targetRegex.test(this.#compiler.flattenDiagnosticMessageText(diagnostic.messageText, " ", 0));
3954
- }
3955
- if (this.#compiler.isStringLiteralLike(targetNode)) {
3956
- return this.#compiler.flattenDiagnosticMessageText(diagnostic.messageText, " ", 0).includes(targetNode.text);
3899
+ return targetRegex.test(messageText);
3957
3900
  }
3958
- return Number.parseInt(targetNode.text, 10) === diagnostic.code;
3901
+ return messageText.includes(targetNode.text);
3959
3902
  }
3960
3903
  }
3961
3904
 
@@ -3965,22 +3908,9 @@ class ExpectService {
3965
3908
  #typeChecker;
3966
3909
  toAcceptProps;
3967
3910
  toBe;
3968
- toBeAny;
3969
3911
  toBeAssignableTo;
3970
3912
  toBeAssignableWith;
3971
- toBeBigInt;
3972
- toBeBoolean;
3973
- toBeNever;
3974
- toBeNull;
3975
- toBeNumber;
3976
- toBeString;
3977
- toBeSymbol;
3978
- toBeUndefined;
3979
- toBeUniqueSymbol;
3980
- toBeUnknown;
3981
- toBeVoid;
3982
3913
  toHaveProperty;
3983
- toMatch;
3984
3914
  toRaiseError;
3985
3915
  constructor(compiler, typeChecker, resolvedConfig) {
3986
3916
  this.#compiler = compiler;
@@ -3993,31 +3923,13 @@ class ExpectService {
3993
3923
  }
3994
3924
  this.toAcceptProps = new ToAcceptProps(compiler, typeChecker);
3995
3925
  this.toBe = new ToBe();
3996
- this.toBeAny = new PrimitiveTypeMatcher(compiler.TypeFlags.Any);
3997
3926
  this.toBeAssignableTo = new ToBeAssignableTo();
3998
3927
  this.toBeAssignableWith = new ToBeAssignableWith();
3999
- this.toBeBigInt = new PrimitiveTypeMatcher(compiler.TypeFlags.BigInt);
4000
- this.toBeBoolean = new PrimitiveTypeMatcher(compiler.TypeFlags.Boolean);
4001
- this.toBeNever = new PrimitiveTypeMatcher(compiler.TypeFlags.Never);
4002
- this.toBeNull = new PrimitiveTypeMatcher(compiler.TypeFlags.Null);
4003
- this.toBeNumber = new PrimitiveTypeMatcher(compiler.TypeFlags.Number);
4004
- this.toBeString = new PrimitiveTypeMatcher(compiler.TypeFlags.String);
4005
- this.toBeSymbol = new PrimitiveTypeMatcher(compiler.TypeFlags.ESSymbol);
4006
- this.toBeUndefined = new PrimitiveTypeMatcher(compiler.TypeFlags.Undefined);
4007
- this.toBeUniqueSymbol = new PrimitiveTypeMatcher(compiler.TypeFlags.UniqueESSymbol);
4008
- this.toBeUnknown = new PrimitiveTypeMatcher(compiler.TypeFlags.Unknown);
4009
- this.toBeVoid = new PrimitiveTypeMatcher(compiler.TypeFlags.Void);
4010
3928
  this.toHaveProperty = new ToHaveProperty(compiler);
4011
- this.toMatch = new ToMatch();
4012
3929
  this.toRaiseError = new ToRaiseError(compiler);
4013
3930
  }
4014
3931
  match(assertion, onDiagnostics) {
4015
3932
  const matcherNameText = assertion.matcherName.getText();
4016
- if (matcherNameText === "toMatch") {
4017
- const text = ExpectDiagnosticText.matcherIsDeprecated(matcherNameText);
4018
- const origin = DiagnosticOrigin.fromNode(assertion.matcherName);
4019
- EventEmitter.dispatch(["deprecation:info", { diagnostics: [Diagnostic.warning(text, origin)] }]);
4020
- }
4021
3933
  if (!assertion.source[0]) {
4022
3934
  this.#onSourceArgumentOrTypeArgumentMustBeProvided(assertion, onDiagnostics);
4023
3935
  return;
@@ -4028,7 +3940,6 @@ class ExpectService {
4028
3940
  case "toBe":
4029
3941
  case "toBeAssignableTo":
4030
3942
  case "toBeAssignableWith":
4031
- case "toMatch":
4032
3943
  if (!assertion.target[0]) {
4033
3944
  this.#onTargetArgumentOrTypeArgumentMustBeProvided(assertion, onDiagnostics);
4034
3945
  return;
@@ -4037,19 +3948,6 @@ class ExpectService {
4037
3948
  return;
4038
3949
  }
4039
3950
  return this[matcherNameText].match(matchWorker, assertion.source[0], assertion.target[0], onDiagnostics);
4040
- case "toBeAny":
4041
- case "toBeBigInt":
4042
- case "toBeBoolean":
4043
- case "toBeNever":
4044
- case "toBeNull":
4045
- case "toBeNumber":
4046
- case "toBeString":
4047
- case "toBeSymbol":
4048
- case "toBeUndefined":
4049
- case "toBeUniqueSymbol":
4050
- case "toBeUnknown":
4051
- case "toBeVoid":
4052
- return this[matcherNameText].match(matchWorker, assertion.source[0]);
4053
3951
  case "toHaveProperty":
4054
3952
  if (!assertion.target[0]) {
4055
3953
  this.#onTargetArgumentMustBeProvided("key", assertion, onDiagnostics);
@@ -4088,10 +3986,14 @@ class ExpectService {
4088
3986
  }
4089
3987
  #rejectsTypeArguments(matchWorker, onDiagnostics) {
4090
3988
  for (const rejectedType of this.#rejectTypes) {
3989
+ const allowedKeyword = this.#compiler.SyntaxKind[`${Format.capitalize(rejectedType)}Keyword`];
3990
+ if (matchWorker.assertion.source[0]?.kind === allowedKeyword ||
3991
+ matchWorker.assertion.target[0]?.kind === allowedKeyword) {
3992
+ continue;
3993
+ }
4091
3994
  for (const argumentName of ["source", "target"]) {
4092
3995
  const argumentNode = matchWorker.assertion[argumentName][0];
4093
- if (!argumentNode ||
4094
- argumentNode.kind === this.#compiler.SyntaxKind[`${Format.capitalize(rejectedType)}Keyword`]) {
3996
+ if (!argumentNode) {
4095
3997
  continue;
4096
3998
  }
4097
3999
  if (matchWorker.getType(argumentNode).flags & this.#compiler.TypeFlags[Format.capitalize(rejectedType)]) {
@@ -4112,7 +4014,6 @@ class ExpectService {
4112
4014
  }
4113
4015
 
4114
4016
  class TestTreeWalker {
4115
- #compiler;
4116
4017
  #cancellationToken;
4117
4018
  #expectService;
4118
4019
  #hasOnly;
@@ -4121,59 +4022,60 @@ class TestTreeWalker {
4121
4022
  #taskResult;
4122
4023
  constructor(resolvedConfig, compiler, typeChecker, options) {
4123
4024
  this.#resolvedConfig = resolvedConfig;
4124
- this.#compiler = compiler;
4125
4025
  this.#cancellationToken = options.cancellationToken;
4126
4026
  this.#hasOnly = options.hasOnly || resolvedConfig.only != null || options.position != null;
4127
4027
  this.#position = options.position;
4128
4028
  this.#taskResult = options.taskResult;
4129
4029
  this.#expectService = new ExpectService(compiler, typeChecker, this.#resolvedConfig);
4130
4030
  }
4131
- #resolveRunMode(mode, member) {
4132
- if (member.flags & TestMemberFlags.Fail) {
4031
+ #resolveRunMode(mode, testNode) {
4032
+ if (testNode.flags & TestTreeNodeFlags.Fail) {
4133
4033
  mode |= RunMode.Fail;
4134
4034
  }
4135
- if (member.flags & TestMemberFlags.Only ||
4136
- (this.#resolvedConfig.only != null && member.name.toLowerCase().includes(this.#resolvedConfig.only.toLowerCase()))) {
4035
+ if (testNode.flags & TestTreeNodeFlags.Only ||
4036
+ (this.#resolvedConfig.only != null &&
4037
+ testNode.name.toLowerCase().includes(this.#resolvedConfig.only.toLowerCase()))) {
4137
4038
  mode |= RunMode.Only;
4138
4039
  }
4139
- if (member.flags & TestMemberFlags.Skip ||
4140
- (this.#resolvedConfig.skip != null && member.name.toLowerCase().includes(this.#resolvedConfig.skip.toLowerCase()))) {
4040
+ if (testNode.flags & TestTreeNodeFlags.Skip ||
4041
+ (this.#resolvedConfig.skip != null &&
4042
+ testNode.name.toLowerCase().includes(this.#resolvedConfig.skip.toLowerCase()))) {
4141
4043
  mode |= RunMode.Skip;
4142
4044
  }
4143
- if (member.flags & TestMemberFlags.Todo) {
4045
+ if (testNode.flags & TestTreeNodeFlags.Todo) {
4144
4046
  mode |= RunMode.Todo;
4145
4047
  }
4146
- if (this.#position != null && member.node.getStart() === this.#position) {
4048
+ if (this.#position != null && testNode.node.getStart() === this.#position) {
4147
4049
  mode |= RunMode.Only;
4148
4050
  mode &= ~RunMode.Skip;
4149
4051
  }
4150
4052
  return mode;
4151
4053
  }
4152
- visit(members, runMode, parentResult) {
4153
- for (const member of members) {
4054
+ visit(testNodes, runMode, parentResult) {
4055
+ for (const testNode of testNodes) {
4154
4056
  if (this.#cancellationToken?.isCancellationRequested) {
4155
4057
  break;
4156
4058
  }
4157
- const validationError = member.validate();
4059
+ const validationError = testNode.validate();
4158
4060
  if (validationError.length > 0) {
4159
4061
  EventEmitter.dispatch(["task:error", { diagnostics: validationError, result: this.#taskResult }]);
4160
4062
  break;
4161
4063
  }
4162
- switch (member.brand) {
4163
- case TestMemberBrand.Describe:
4164
- this.#visitDescribe(member, runMode, parentResult);
4064
+ switch (testNode.brand) {
4065
+ case TestTreeNodeBrand.Describe:
4066
+ this.#visitDescribe(testNode, runMode, parentResult);
4165
4067
  break;
4166
- case TestMemberBrand.Test:
4167
- this.#visitTest(member, runMode, parentResult);
4068
+ case TestTreeNodeBrand.Test:
4069
+ this.#visitTest(testNode, runMode, parentResult);
4168
4070
  break;
4169
- case TestMemberBrand.Expect:
4170
- this.#visitAssertion(member, runMode, parentResult);
4071
+ case TestTreeNodeBrand.Expect:
4072
+ this.#visitAssertion(testNode, runMode, parentResult);
4171
4073
  break;
4172
4074
  }
4173
4075
  }
4174
4076
  }
4175
4077
  #visitAssertion(assertion, runMode, parentResult) {
4176
- this.visit(assertion.members, runMode, parentResult);
4078
+ this.visit(assertion.children, runMode, parentResult);
4177
4079
  const expectResult = new ExpectResult(assertion, parentResult);
4178
4080
  EventEmitter.dispatch(["expect:start", { result: expectResult }]);
4179
4081
  runMode = this.#resolveRunMode(runMode, assertion);
@@ -4227,7 +4129,7 @@ class TestTreeWalker {
4227
4129
  ]);
4228
4130
  }
4229
4131
  else {
4230
- this.visit(describe.members, runMode, describeResult);
4132
+ this.visit(describe.children, runMode, describeResult);
4231
4133
  }
4232
4134
  EventEmitter.dispatch(["describe:end", { result: describeResult }]);
4233
4135
  }
@@ -4249,7 +4151,7 @@ class TestTreeWalker {
4249
4151
  ]);
4250
4152
  return;
4251
4153
  }
4252
- this.visit(test.members, runMode, testResult);
4154
+ this.visit(test.children, runMode, testResult);
4253
4155
  if (runMode & RunMode.Skip || (this.#hasOnly && !(runMode & RunMode.Only))) {
4254
4156
  EventEmitter.dispatch(["test:skip", { result: testResult }]);
4255
4157
  return;
@@ -4329,17 +4231,27 @@ class TaskRunner {
4329
4231
  hasOnly: testTree.hasOnly,
4330
4232
  position: task.position,
4331
4233
  });
4332
- testTreeWalker.visit(testTree.members, RunMode.Normal, undefined);
4234
+ testTreeWalker.visit(testTree.children, RunMode.Normal, undefined);
4333
4235
  }
4334
4236
  }
4335
4237
 
4336
4238
  class Runner {
4337
4239
  #eventEmitter = new EventEmitter();
4338
4240
  #resolvedConfig;
4339
- static version = "3.4.0";
4241
+ static version = "4.0.0-beta.0";
4340
4242
  constructor(resolvedConfig) {
4341
4243
  this.#resolvedConfig = resolvedConfig;
4342
4244
  }
4245
+ #addHandlers(cancellationToken) {
4246
+ const resultHandler = new ResultHandler();
4247
+ this.#eventEmitter.addHandler(resultHandler);
4248
+ const testTreeHandler = new TestTreeHandler();
4249
+ this.#eventEmitter.addHandler(testTreeHandler);
4250
+ if (this.#resolvedConfig.failFast) {
4251
+ const cancellationHandler = new CancellationHandler(cancellationToken, CancellationReason.FailFast);
4252
+ this.#eventEmitter.addHandler(cancellationHandler);
4253
+ }
4254
+ }
4343
4255
  async #addReporters() {
4344
4256
  if (this.#resolvedConfig.watch && !environmentOptions.noInteractive) {
4345
4257
  const watchReporter = new WatchReporter(this.#resolvedConfig);
@@ -4367,13 +4279,8 @@ class Runner {
4367
4279
  }
4368
4280
  async run(testFiles, cancellationToken = new CancellationToken()) {
4369
4281
  const tasks = testFiles.map((testFile) => (testFile instanceof Task ? testFile : new Task(testFile)));
4370
- const resultHandler = new ResultHandler();
4371
- this.#eventEmitter.addHandler(resultHandler);
4282
+ this.#addHandlers(cancellationToken);
4372
4283
  await this.#addReporters();
4373
- if (this.#resolvedConfig.failFast) {
4374
- const cancellationHandler = new CancellationHandler(cancellationToken, CancellationReason.FailFast);
4375
- this.#eventEmitter.addHandler(cancellationHandler);
4376
- }
4377
4284
  await this.#run(tasks, cancellationToken);
4378
4285
  if (this.#resolvedConfig.watch) {
4379
4286
  await this.#watch(tasks, cancellationToken);
@@ -4476,9 +4383,9 @@ class Cli {
4476
4383
  OutputService.writeMessage(formattedText({ ...resolvedConfig, ...environmentOptions }));
4477
4384
  continue;
4478
4385
  }
4479
- if (commandLine.includes("--install")) {
4386
+ if (commandLine.includes("--fetch")) {
4480
4387
  for (const tag of resolvedConfig.target) {
4481
- await Store.install(tag);
4388
+ await Store.fetch(tag);
4482
4389
  }
4483
4390
  continue;
4484
4391
  }
@@ -4533,4 +4440,4 @@ class Cli {
4533
4440
  }
4534
4441
  }
4535
4442
 
4536
- export { Assertion, BaseReporter, CancellationHandler, CancellationReason, CancellationToken, Cli, CollectService, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, EventEmitter, ExitCodeHandler, ExpectResult, ExpectService, FileWatcher, InputService, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, PluginService, ProjectResult, ProjectService, Result, ResultCount, ResultHandler, ResultStatus, ResultTiming, Runner, Scribbler, Select, SelectDiagnosticText, SetupReporter, SourceFile, Store, SummaryReporter, TargetResult, Task, TaskResult, TestMember, TestMemberBrand, TestMemberFlags, TestResult, TestTree, Text, Version, WatchReporter, WatchService, Watcher, addsPackageText, defaultOptions, describeNameText, diagnosticText, environmentOptions, fileViewText, formattedText, helpText, summaryText, taskStatusText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
4443
+ export { AssertionNode, BaseReporter, CancellationHandler, CancellationReason, CancellationToken, Cli, CollectService, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, EventEmitter, ExitCodeHandler, ExpectResult, ExpectService, FileWatcher, InputService, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, PluginService, ProjectResult, ProjectService, Result, ResultCount, ResultHandler, ResultStatus, ResultTiming, Runner, Scribbler, Select, SelectDiagnosticText, SetupReporter, SourceFile, Store, SummaryReporter, TargetResult, Task, TaskResult, TestResult, TestTree, TestTreeHandler, TestTreeNode, TestTreeNodeBrand, TestTreeNodeFlags, Text, Version, WatchReporter, WatchService, Watcher, addsPackageText, defaultOptions, describeNameText, diagnosticText, environmentOptions, fileViewText, formattedText, helpText, summaryText, taskStatusText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };