tstyche 6.2.0 → 7.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/dist/tag.js CHANGED
@@ -25,12 +25,9 @@ async function tstyche(template, ...substitutions) {
25
25
  eventEmitter.addHandler(statusHandler);
26
26
  await cli.run(commandLine, new CancellationToken());
27
27
  eventEmitter.removeHandler(statusHandler);
28
- return new Promise((resolve, reject) => {
29
- if (statusHandler.hasError()) {
30
- reject(new Error("TSTyche test run failed. Check the output above for details."));
31
- }
32
- resolve();
33
- });
28
+ if (statusHandler.hasError()) {
29
+ throw new Error("TSTyche test run failed. Check the output above for details.");
30
+ }
34
31
  }
35
32
 
36
33
  export { tstyche as default };
package/dist/tstyche.d.ts CHANGED
@@ -169,7 +169,6 @@ interface ConfigFileOptions {
169
169
  rejectAnyType?: boolean;
170
170
  rejectNeverType?: boolean;
171
171
  reporters?: Array<string>;
172
- rootPath?: string;
173
172
  target?: Array<string>;
174
173
  testFileMatch?: Array<string>;
175
174
  tsconfig?: string;
@@ -183,9 +182,10 @@ interface InlineConfig {
183
182
  };
184
183
  template?: boolean;
185
184
  }
186
- interface ResolvedConfig extends Omit<CommandLineOptions, "config" | keyof ConfigFileOptions>, Required<ConfigFileOptions> {
185
+ interface ResolvedConfig extends Omit<CommandLineOptions, "config" | "root" | keyof ConfigFileOptions>, Required<ConfigFileOptions> {
187
186
  configFilePath: string;
188
187
  pathMatch: Array<string>;
188
+ rootPath: string;
189
189
  }
190
190
  interface TextRange {
191
191
  start: number;
@@ -205,17 +205,16 @@ declare class Config {
205
205
  commandLineOptions: CommandLineOptions;
206
206
  pathMatch: Array<string>;
207
207
  }>;
208
- static parseConfigFile(configPath?: string, rootPath?: string): Promise<{
208
+ static parseConfigFile(configPath?: string | undefined, rootPath?: string | undefined): Promise<{
209
209
  configFileOptions: ConfigFileOptions;
210
- configFilePath: string;
211
210
  }>;
212
211
  static resolve(options?: {
213
212
  configFileOptions?: ConfigFileOptions;
214
- configFilePath?: string;
215
- commandLineOptions?: Omit<CommandLineOptions, "config">;
213
+ commandLineOptions?: CommandLineOptions;
216
214
  pathMatch?: Array<string>;
217
215
  }): ResolvedConfig;
218
- static resolveConfigFilePath(configPath?: string, rootPath?: string): string;
216
+ static resolveConfigFilePath(configPath?: string | undefined, rootPath?: string | undefined): string;
217
+ static resolveRootPath(rootPath?: string | undefined): string;
219
218
  }
220
219
 
221
220
  declare enum OptionBrand {
@@ -283,6 +282,7 @@ type OptionDefinition = PrimitiveTypeOptionDefinition | ListTypeOptionDefinition
283
282
  declare class Options {
284
283
  #private;
285
284
  static for(optionGroup: OptionGroup): Map<string, OptionDefinition>;
285
+ static isJsonString(text: string): boolean;
286
286
  static resolve(optionName: string, optionValue: string, rootPath?: string): string;
287
287
  static validate(optionName: string, optionValue: string, onDiagnostics: DiagnosticsHandler, origin?: DiagnosticOrigin): Promise<void>;
288
288
  }
@@ -332,6 +332,13 @@ declare class WatchReporter extends BaseReporter {
332
332
  on([event, payload]: ReporterEvent): void;
333
333
  }
334
334
 
335
+ declare enum ProjectConfigKind {
336
+ Discovered = 0,
337
+ Default = 1,
338
+ Provided = 2,
339
+ Synthetic = 3
340
+ }
341
+
335
342
  declare enum ResultStatus {
336
343
  Runs = "runs",
337
344
  Passed = "passed",
@@ -343,6 +350,10 @@ declare enum ResultStatus {
343
350
  Todo = "todo"
344
351
  }
345
352
 
353
+ type ProjectConfig = {
354
+ kind: ProjectConfigKind;
355
+ specifier: string;
356
+ };
346
357
  type TargetResultStatus = ResultStatus.Runs | ResultStatus.Passed | ResultStatus.Failed;
347
358
  type TargetCounts = {
348
359
  [K in Exclude<TargetResultStatus, ResultStatus.Runs>]: number;
@@ -415,9 +426,9 @@ declare class FileResult {
415
426
 
416
427
  declare class ProjectResult {
417
428
  compilerVersion: string;
418
- projectConfigFilePath: string | undefined;
429
+ projectConfig: ProjectConfig;
419
430
  results: Array<FileResult>;
420
- constructor(compilerVersion: string, projectConfigFilePath: string | undefined);
431
+ constructor(compilerVersion: string, projectConfig: ProjectConfig);
421
432
  }
422
433
 
423
434
  declare class TargetResult {
@@ -468,7 +479,7 @@ type Event = ["config:error", {
468
479
  result: TargetResult;
469
480
  }] | ["project:uses", {
470
481
  compilerVersion: string;
471
- projectConfigFilePath: string | undefined;
482
+ projectConfig: ProjectConfig;
472
483
  }] | ["project:error", {
473
484
  diagnostics: Array<Diagnostic>;
474
485
  }] | ["file:start", {
@@ -599,7 +610,7 @@ interface TextProps {
599
610
  }
600
611
  declare function Text({ children, color, indent }: TextProps): ScribblerJsx.Element;
601
612
 
602
- declare function addsPackageText(packageVersion: string, packagePath: string, options?: {
613
+ declare function addsText(packageVersion: string, packagePath: string, options?: {
603
614
  short?: boolean;
604
615
  }): ScribblerJsx.Element;
605
616
 
@@ -655,8 +666,7 @@ declare function summaryText({ targetCounts, fileCounts, testCounts, assertionCo
655
666
 
656
667
  declare function testNameText(status: Exclude<TestResultStatus, ResultStatus.Runs>, name: string, indent?: number): ScribblerJsx.Element;
657
668
 
658
- declare function usesCompilerText(compilerVersion: string, projectConfigFilePath: string | undefined, options?: {
659
- prependEmptyLine?: boolean;
669
+ declare function usesText(compilerVersion: string, projectConfig: ProjectConfig, options?: {
660
670
  short?: boolean;
661
671
  }): ScribblerJsx.Element;
662
672
 
@@ -743,5 +753,5 @@ declare class Version {
743
753
  static isSatisfiedWith(source: string, target: string): boolean;
744
754
  }
745
755
 
746
- export { BaseReporter, CancellationReason, CancellationToken, Cli, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, Directive, DotReporter, EventEmitter, ExpectResult, FileLocation, FileResult, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, ProjectResult, Result, ResultStatus, Runner, Scribbler, ScribblerJsx, Select, SelectDiagnosticText, SetupReporter, Store, StreamController, SummaryReporter, SuppressedResult, TargetResult, TestResult, Text, Version, WatchReporter, addsPackageText, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, dotText, environmentOptions, fileStatusText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, prologueText, summaryText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
747
- export type { AssertionCounts, AssertionResultStatus, CodeFrameOptions, CommandLineOptions, ConfigFileOptions, DiagnosticsHandler, DirectiveRange, EnvironmentOptions, Event, EventHandler, FileCounts, FileResultStatus, InlineConfig, ItemDefinition, OptionDefinition, Reporter, ReporterEvent, ResolvedConfig, ResultCounts, ResultTiming, ScribblerOptions, SuppressedCounts, SuppressedResultStatus, TargetCounts, TargetResultStatus, TestCounts, TestResultStatus, TextRange };
756
+ export { BaseReporter, CancellationReason, CancellationToken, Cli, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, Directive, DotReporter, EventEmitter, ExpectResult, FileLocation, FileResult, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, ProjectConfigKind, ProjectResult, Result, ResultStatus, Runner, Scribbler, ScribblerJsx, Select, SelectDiagnosticText, SetupReporter, Store, StreamController, SummaryReporter, SuppressedResult, TargetResult, TestResult, Text, Version, WatchReporter, addsText, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, dotText, environmentOptions, fileStatusText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, prologueText, summaryText, testNameText, usesText, waitingForFileChangesText, watchUsageText };
757
+ export type { AssertionCounts, AssertionResultStatus, CodeFrameOptions, CommandLineOptions, ConfigFileOptions, DiagnosticsHandler, DirectiveRange, EnvironmentOptions, Event, EventHandler, FileCounts, FileResultStatus, InlineConfig, ItemDefinition, OptionDefinition, ProjectConfig, Reporter, ReporterEvent, ResolvedConfig, ResultCounts, ResultTiming, ScribblerOptions, SuppressedCounts, SuppressedResultStatus, TargetCounts, TargetResultStatus, TestCounts, TestResultStatus, TextRange };
package/dist/tstyche.js CHANGED
@@ -60,7 +60,7 @@ class JsonNode {
60
60
  return undefined;
61
61
  }
62
62
  if (/^['"]/.test(this.text)) {
63
- return this.text.slice(1, -1);
63
+ return this.text.slice(1, -1).replaceAll("\\", "");
64
64
  }
65
65
  if (options?.expectsIdentifier) {
66
66
  return this.text;
@@ -244,7 +244,8 @@ class JsonScanner {
244
244
  }
245
245
  while (!this.isRead()) {
246
246
  text += this.#readCharacter();
247
- if (text.slice(-1) === closingTokenText || (!closingTokenText && /[\s,:\]}]/.test(this.#peekCharacter()))) {
247
+ if ((text.at(-2) !== "\\" && text.at(-1) === closingTokenText) ||
248
+ (!closingTokenText && /[\s,:\]}]/.test(this.#peekCharacter()))) {
248
249
  break;
249
250
  }
250
251
  }
@@ -1083,7 +1084,7 @@ class Options {
1083
1084
  },
1084
1085
  {
1085
1086
  brand: "true",
1086
- description: "Print the list of the selected test files and exit.",
1087
+ description: "Print the list of selected test files and exit.",
1087
1088
  group: 2,
1088
1089
  name: "listFiles",
1089
1090
  },
@@ -1133,12 +1134,6 @@ class Options {
1133
1134
  group: 2,
1134
1135
  name: "root",
1135
1136
  },
1136
- {
1137
- brand: "string",
1138
- description: "The path to a directory containing files of a test project.",
1139
- group: 4,
1140
- name: "rootPath",
1141
- },
1142
1137
  {
1143
1138
  brand: "true",
1144
1139
  description: "Print the resolved configuration and exit.",
@@ -1153,7 +1148,7 @@ class Options {
1153
1148
  },
1154
1149
  {
1155
1150
  brand: "range",
1156
- description: "The range of TypeScript versions to be tested against.",
1151
+ description: "The range of TypeScript versions to test against.",
1157
1152
  group: 2 | 4 | 8,
1158
1153
  name: "target",
1159
1154
  },
@@ -1169,7 +1164,7 @@ class Options {
1169
1164
  },
1170
1165
  {
1171
1166
  brand: "string",
1172
- description: "The look up strategy to be used to find the TSConfig file.",
1167
+ description: "The TSConfig to load.",
1173
1168
  group: 2 | 4,
1174
1169
  name: "tsconfig",
1175
1170
  },
@@ -1214,16 +1209,19 @@ class Options {
1214
1209
  return ["dot", "list", "summary"].includes(optionValue);
1215
1210
  }
1216
1211
  static #isLookupStrategy(optionValue) {
1217
- return ["findup", "ignore"].includes(optionValue);
1212
+ return ["findup", "baseline"].includes(optionValue);
1213
+ }
1214
+ static isJsonString(text) {
1215
+ return text.startsWith("{");
1218
1216
  }
1219
1217
  static resolve(optionName, optionValue, rootPath = ".") {
1220
1218
  const canonicalOptionName = Options.#getCanonicalOptionName(optionName);
1221
1219
  switch (canonicalOptionName) {
1222
1220
  case "config":
1223
1221
  case "root":
1224
- case "rootPath":
1225
1222
  case "tsconfig":
1226
- if (canonicalOptionName === "tsconfig" && Options.#isLookupStrategy(optionValue)) {
1223
+ if (canonicalOptionName === "tsconfig" &&
1224
+ (Options.#isLookupStrategy(optionValue) || Options.isJsonString(optionValue))) {
1227
1225
  break;
1228
1226
  }
1229
1227
  if (optionValue.startsWith("file:")) {
@@ -1232,7 +1230,7 @@ class Options {
1232
1230
  optionValue = Path.resolve(rootPath, optionValue);
1233
1231
  break;
1234
1232
  case "reporters":
1235
- if (canonicalOptionName === "reporters" && Options.#isBuiltinReporter(optionValue)) {
1233
+ if (Options.#isBuiltinReporter(optionValue)) {
1236
1234
  break;
1237
1235
  }
1238
1236
  try {
@@ -1254,9 +1252,9 @@ class Options {
1254
1252
  switch (canonicalOptionName) {
1255
1253
  case "config":
1256
1254
  case "root":
1257
- case "rootPath":
1258
1255
  case "tsconfig":
1259
- if (canonicalOptionName === "tsconfig" && Options.#isLookupStrategy(optionValue)) {
1256
+ if (canonicalOptionName === "tsconfig" &&
1257
+ (Options.#isLookupStrategy(optionValue) || Options.isJsonString(optionValue))) {
1260
1258
  break;
1261
1259
  }
1262
1260
  if (existsSync(optionValue)) {
@@ -1265,7 +1263,7 @@ class Options {
1265
1263
  onDiagnostics(Diagnostic.error(ConfigDiagnosticText.fileDoesNotExist(optionValue), origin));
1266
1264
  break;
1267
1265
  case "reporters":
1268
- if (canonicalOptionName === "reporters" && Options.#isBuiltinReporter(optionValue)) {
1266
+ if (Options.#isBuiltinReporter(optionValue)) {
1269
1267
  break;
1270
1268
  }
1271
1269
  if (optionValue.startsWith("file:") && existsSync(new URL(optionValue))) {
@@ -1580,7 +1578,6 @@ const defaultOptions = {
1580
1578
  rejectAnyType: true,
1581
1579
  rejectNeverType: true,
1582
1580
  reporters: ["list", "summary"],
1583
- rootPath: Path.resolve("./"),
1584
1581
  target: ["*"],
1585
1582
  testFileMatch: ["**/*.tst.*", "**/__typetests__/*.test.*", "**/typetests/*.test.*"],
1586
1583
  tsconfig: "findup",
@@ -1599,10 +1596,8 @@ class Config {
1599
1596
  return { commandLineOptions, pathMatch };
1600
1597
  }
1601
1598
  static async parseConfigFile(configPath, rootPath) {
1599
+ const configFileOptions = {};
1602
1600
  const configFilePath = Config.resolveConfigFilePath(configPath, rootPath);
1603
- const configFileOptions = {
1604
- rootPath: rootPath ?? Path.dirname(configFilePath),
1605
- };
1606
1601
  if (existsSync(configFilePath)) {
1607
1602
  const configFileText = await fs.readFile(configFilePath, {
1608
1603
  encoding: "utf8",
@@ -1611,12 +1606,13 @@ class Config {
1611
1606
  const configFileParser = new ConfigParser(configFileOptions, 4, sourceFile, new JsonScanner(sourceFile), Config.#onDiagnostics);
1612
1607
  await configFileParser.parse();
1613
1608
  }
1614
- return { configFileOptions, configFilePath };
1609
+ return { configFileOptions };
1615
1610
  }
1616
1611
  static resolve(options) {
1617
1612
  const resolvedConfig = {
1618
- configFilePath: Config.resolveConfigFilePath(options?.configFilePath),
1613
+ configFilePath: Config.resolveConfigFilePath(options?.commandLineOptions?.config, options?.commandLineOptions?.root),
1619
1614
  pathMatch: options?.pathMatch ?? [],
1615
+ rootPath: Config.resolveRootPath(options?.commandLineOptions?.root),
1620
1616
  ...defaultOptions,
1621
1617
  ...options?.configFileOptions,
1622
1618
  ...options?.commandLineOptions,
@@ -1629,11 +1625,13 @@ class Config {
1629
1625
  }
1630
1626
  return resolvedConfig;
1631
1627
  }
1632
- static resolveConfigFilePath(configPath, rootPath = ".") {
1633
- if (configPath != null) {
1634
- return Path.resolve(configPath);
1635
- }
1636
- return Path.resolve(rootPath, "./tstyche.config.json");
1628
+ static resolveConfigFilePath(configPath, rootPath) {
1629
+ return configPath != null
1630
+ ? Path.resolve(configPath)
1631
+ : Path.resolve(Config.resolveRootPath(rootPath), "./tstyche.json");
1632
+ }
1633
+ static resolveRootPath(rootPath) {
1634
+ return Path.resolve(rootPath ?? ".");
1637
1635
  }
1638
1636
  }
1639
1637
 
@@ -1709,13 +1707,13 @@ class Directive {
1709
1707
  sourceFile,
1710
1708
  namespace: { start: comment.pos, end: comment.pos + namespaceText.length, text: namespaceText },
1711
1709
  };
1712
- const directiveSeparatorText = match?.[2];
1713
- const directiveText = match?.[3];
1710
+ const directiveSeparatorText = match[2];
1711
+ const directiveText = match[3];
1714
1712
  if (typeof directiveText === "string" && typeof directiveSeparatorText === "string") {
1715
1713
  const start = range.namespace.end + directiveSeparatorText.length;
1716
1714
  range.directive = { start, end: start + directiveText.length, text: directiveText };
1717
- const argumentSeparatorText = match?.[4];
1718
- const argumentText = match?.[5]?.trimEnd();
1715
+ const argumentSeparatorText = match[4];
1716
+ const argumentText = match[5]?.trimEnd();
1719
1717
  if (typeof argumentSeparatorText === "string" && typeof argumentText === "string") {
1720
1718
  const start = range.directive.end + argumentSeparatorText.length;
1721
1719
  range.argument = { start, end: start + argumentText.length, text: argumentText };
@@ -1747,10 +1745,10 @@ class Directive {
1747
1745
  const origin = new DiagnosticOrigin(range.argument.start, range.argument.end, range.sourceFile);
1748
1746
  Directive.#onDiagnostics(Diagnostic.error(text, origin));
1749
1747
  }
1750
- inlineConfig[range.directive?.text] = true;
1748
+ inlineConfig[range.directive.text] = true;
1751
1749
  return;
1752
1750
  }
1753
- const target = range?.directive ?? range.namespace;
1751
+ const target = range.directive ?? range.namespace;
1754
1752
  const text = DirectiveDiagnosticText.isNotSupported(target.text);
1755
1753
  const origin = new DiagnosticOrigin(target.start, target.end, range.sourceFile);
1756
1754
  Directive.#onDiagnostics(Diagnostic.error(text, origin));
@@ -1874,13 +1872,21 @@ class FileResult {
1874
1872
  }
1875
1873
  }
1876
1874
 
1875
+ var ProjectConfigKind;
1876
+ (function (ProjectConfigKind) {
1877
+ ProjectConfigKind[ProjectConfigKind["Discovered"] = 0] = "Discovered";
1878
+ ProjectConfigKind[ProjectConfigKind["Default"] = 1] = "Default";
1879
+ ProjectConfigKind[ProjectConfigKind["Provided"] = 2] = "Provided";
1880
+ ProjectConfigKind[ProjectConfigKind["Synthetic"] = 3] = "Synthetic";
1881
+ })(ProjectConfigKind || (ProjectConfigKind = {}));
1882
+
1877
1883
  class ProjectResult {
1878
1884
  compilerVersion;
1879
- projectConfigFilePath;
1885
+ projectConfig;
1880
1886
  results = [];
1881
- constructor(compilerVersion, projectConfigFilePath) {
1887
+ constructor(compilerVersion, projectConfig) {
1882
1888
  this.compilerVersion = compilerVersion;
1883
- this.projectConfigFilePath = projectConfigFilePath;
1889
+ this.projectConfig = projectConfig;
1884
1890
  }
1885
1891
  }
1886
1892
 
@@ -1982,10 +1988,10 @@ class ResultHandler {
1982
1988
  }
1983
1989
  break;
1984
1990
  case "project:uses": {
1985
- let projectResult = this.#targetResult.results.get(payload.projectConfigFilePath);
1991
+ let projectResult = this.#targetResult.results.get(payload.projectConfig.specifier);
1986
1992
  if (!projectResult) {
1987
- projectResult = new ProjectResult(payload.compilerVersion, payload.projectConfigFilePath);
1988
- this.#targetResult.results.set(payload.projectConfigFilePath, projectResult);
1993
+ projectResult = new ProjectResult(payload.compilerVersion, payload.projectConfig);
1994
+ this.#targetResult.results.set(payload.projectConfig.specifier, projectResult);
1989
1995
  }
1990
1996
  this.#projectResult = projectResult;
1991
1997
  break;
@@ -2229,7 +2235,7 @@ class Scribbler {
2229
2235
  }
2230
2236
  }
2231
2237
 
2232
- function addsPackageText(packageVersion, packagePath, options) {
2238
+ function addsText(packageVersion, packagePath, options) {
2233
2239
  if (options?.short) {
2234
2240
  return (jsx(Line, { children: jsx(Text, { color: "90", children: packageVersion }) }));
2235
2241
  }
@@ -2563,15 +2569,24 @@ function testNameText(status, name, indent = 0) {
2563
2569
  return (jsx(Line, { indent: indent + 1, children: [jsx(Text, { color: getStatusColor(status), children: statusText }), " ", jsx(Text, { color: "90", children: name })] }));
2564
2570
  }
2565
2571
 
2566
- function usesCompilerText(compilerVersion, projectConfigFilePath, options) {
2572
+ function usesText(compilerVersion, projectConfig, options) {
2567
2573
  if (options?.short) {
2568
2574
  return jsx(Text, { color: "34", children: compilerVersion });
2569
2575
  }
2570
- let projectConfigPathText;
2571
- if (projectConfigFilePath != null) {
2572
- projectConfigPathText = (jsx(Text, { color: "90", children: [" with ", Path.relative("", projectConfigFilePath)] }));
2576
+ let projectConfigText;
2577
+ switch (projectConfig.kind) {
2578
+ case 0:
2579
+ case 2:
2580
+ projectConfigText = (jsx(Text, { color: "90", children: [" with ", Path.relative("", projectConfig.specifier)] }));
2581
+ break;
2582
+ case 1:
2583
+ projectConfigText = (jsx(Text, { color: "90", children: [" with ", projectConfig.specifier, " TSConfig"] }));
2584
+ break;
2585
+ case 3:
2586
+ projectConfigText = jsx(Text, { color: "90", children: " with inline TSConfig" });
2587
+ break;
2573
2588
  }
2574
- return (jsx(Text, { children: [options?.prependEmptyLine ? jsx(Line, {}) : undefined, jsx(Line, { children: [jsx(Text, { color: "34", children: "uses" }), " TypeScript ", compilerVersion, projectConfigPathText] }), jsx(Line, {})] }));
2589
+ return (jsx(Text, { children: [jsx(Line, { children: [jsx(Text, { color: "34", children: "uses" }), " TypeScript ", compilerVersion, projectConfigText] }), jsx(Line, {})] }));
2575
2590
  }
2576
2591
 
2577
2592
  function waitingForFileChangesText() {
@@ -2602,7 +2617,7 @@ class DotReporter extends BaseReporter {
2602
2617
  on([event, payload]) {
2603
2618
  switch (event) {
2604
2619
  case "store:adds":
2605
- OutputService.writeMessage(addsPackageText(payload.packageVersion, payload.packagePath, { short: true }));
2620
+ OutputService.writeMessage(addsText(payload.packageVersion, payload.packagePath, { short: true }));
2606
2621
  this.#hasReportedAdds = true;
2607
2622
  break;
2608
2623
  case "store:error":
@@ -2618,7 +2633,7 @@ class DotReporter extends BaseReporter {
2618
2633
  this.#hasReportedAdds = false;
2619
2634
  }
2620
2635
  if (this.resolvedConfig.target.length > 1) {
2621
- OutputService.writeMessage(usesCompilerText(payload.compilerVersion, payload.projectConfigFilePath, { short: true }));
2636
+ OutputService.writeMessage(usesText(payload.compilerVersion, payload.projectConfig, { short: true }));
2622
2637
  }
2623
2638
  break;
2624
2639
  case "target:end":
@@ -2692,7 +2707,7 @@ class ListReporter extends BaseReporter {
2692
2707
  this.resolvedConfig.verbose || (payload.result.files.length === 1 && this.resolvedConfig.watch !== true);
2693
2708
  break;
2694
2709
  case "store:adds":
2695
- OutputService.writeMessage(addsPackageText(payload.packageVersion, payload.packagePath));
2710
+ OutputService.writeMessage(addsText(payload.packageVersion, payload.packagePath));
2696
2711
  this.#hasReportedAdds = true;
2697
2712
  break;
2698
2713
  case "store:error":
@@ -2705,9 +2720,10 @@ class ListReporter extends BaseReporter {
2705
2720
  this.#hasReportedUses = false;
2706
2721
  break;
2707
2722
  case "project:uses":
2708
- OutputService.writeMessage(usesCompilerText(payload.compilerVersion, payload.projectConfigFilePath, {
2709
- prependEmptyLine: this.#hasReportedUses && !this.#hasReportedAdds && !this.#hasReportedError,
2710
- }));
2723
+ if (this.#hasReportedUses && !(this.#hasReportedAdds || this.#hasReportedError)) {
2724
+ OutputService.writeBlankLine();
2725
+ }
2726
+ OutputService.writeMessage(usesText(payload.compilerVersion, payload.projectConfig));
2711
2727
  this.#hasReportedAdds = false;
2712
2728
  this.#hasReportedUses = true;
2713
2729
  break;
@@ -2802,7 +2818,7 @@ class ListReporter extends BaseReporter {
2802
2818
  class SetupReporter {
2803
2819
  on([event, payload]) {
2804
2820
  if (event === "store:adds") {
2805
- OutputService.writeMessage(addsPackageText(payload.packageVersion, payload.packagePath));
2821
+ OutputService.writeMessage(addsText(payload.packageVersion, payload.packagePath));
2806
2822
  return;
2807
2823
  }
2808
2824
  if ("diagnostics" in payload) {
@@ -3562,11 +3578,11 @@ class SuppressedLayer {
3562
3578
  #collectSuppressedErrors(text) {
3563
3579
  const ranges = [];
3564
3580
  for (const match of text.matchAll(this.#expectErrorRegex)) {
3565
- const offsetText = match?.[1];
3566
- const directiveText = match?.[2];
3567
- const ignoreText = match?.[3];
3568
- const argumentSeparatorText = match?.[4];
3569
- const argumentText = match?.[5]?.split(/--+/)[0]?.trimEnd();
3581
+ const offsetText = match[1];
3582
+ const directiveText = match[2];
3583
+ const ignoreText = match[3];
3584
+ const argumentSeparatorText = match[4];
3585
+ const argumentText = match[5]?.split(/--+/)[0]?.trimEnd();
3570
3586
  if (typeof offsetText !== "string" || !directiveText) {
3571
3587
  continue;
3572
3588
  }
@@ -4051,7 +4067,9 @@ var TestTreeNodeFlags;
4051
4067
 
4052
4068
  class ProjectService {
4053
4069
  #compiler;
4070
+ #host;
4054
4071
  #lastSeenProject = "";
4072
+ #projectConfig;
4055
4073
  #resolvedConfig;
4056
4074
  #seenPrograms = new WeakSet();
4057
4075
  #seenTestFiles = new Set();
@@ -4059,6 +4077,7 @@ class ProjectService {
4059
4077
  constructor(compiler, resolvedConfig) {
4060
4078
  this.#compiler = compiler;
4061
4079
  this.#resolvedConfig = resolvedConfig;
4080
+ this.#projectConfig = this.#resolveProjectConfig(resolvedConfig.tsconfig);
4062
4081
  const noop = () => undefined;
4063
4082
  const noopLogger = {
4064
4083
  close: noop,
@@ -4074,8 +4093,8 @@ class ProjectService {
4074
4093
  const noopWatcher = {
4075
4094
  close: noop,
4076
4095
  };
4077
- const host = {
4078
- ...this.#compiler.sys,
4096
+ this.#host = {
4097
+ ...compiler.sys,
4079
4098
  clearImmediate,
4080
4099
  clearTimeout,
4081
4100
  setImmediate,
@@ -4083,10 +4102,13 @@ class ProjectService {
4083
4102
  watchDirectory: () => noopWatcher,
4084
4103
  watchFile: () => noopWatcher,
4085
4104
  };
4105
+ if (this.#projectConfig.kind === 3) {
4106
+ this.#host.readFile = (path) => path === this.#projectConfig.specifier ? resolvedConfig.tsconfig : compiler.sys.readFile(path);
4107
+ }
4086
4108
  this.#service = new this.#compiler.server.ProjectService({
4087
4109
  allowLocalPluginLoads: true,
4088
4110
  cancellationToken: this.#compiler.server.nullCancellationToken,
4089
- host,
4111
+ host: this.#host,
4090
4112
  logger: noopLogger,
4091
4113
  session: undefined,
4092
4114
  useInferredProjectPerProjectRoot: true,
@@ -4140,29 +4162,44 @@ class ProjectService {
4140
4162
  return project?.getLanguageService(true);
4141
4163
  }
4142
4164
  #isFileIncluded(filePath) {
4143
- const configSourceFile = this.#compiler.readJsonConfigFile(this.#resolvedConfig.tsconfig, this.#compiler.sys.readFile);
4144
- const { fileNames } = this.#compiler.parseJsonSourceFileConfigFileContent(configSourceFile, this.#compiler.sys, Path.dirname(this.#resolvedConfig.tsconfig), undefined, this.#resolvedConfig.tsconfig);
4165
+ const configSourceFile = this.#compiler.readJsonConfigFile(this.#projectConfig.specifier, this.#host.readFile);
4166
+ const { fileNames } = this.#compiler.parseJsonSourceFileConfigFileContent(configSourceFile, this.#host, Path.dirname(this.#projectConfig.specifier), undefined, this.#projectConfig.specifier);
4145
4167
  return fileNames.includes(filePath);
4146
4168
  }
4169
+ #resolveProjectConfig(specifier) {
4170
+ if (specifier === "baseline") {
4171
+ return { kind: 1, specifier: "baseline" };
4172
+ }
4173
+ if (specifier === "findup") {
4174
+ return { kind: 0, specifier: "" };
4175
+ }
4176
+ if (Options.isJsonString(specifier)) {
4177
+ return {
4178
+ kind: 3,
4179
+ specifier: Path.resolve(this.#resolvedConfig.rootPath, `${Math.random().toString(32).slice(2)}.tsconfig.json`),
4180
+ };
4181
+ }
4182
+ return { kind: 2, specifier };
4183
+ }
4147
4184
  openFile(filePath, sourceText) {
4148
- switch (this.#resolvedConfig.tsconfig) {
4149
- case "findup":
4185
+ switch (this.#projectConfig.kind) {
4186
+ case 0:
4150
4187
  break;
4151
- case "ignore":
4188
+ case 1:
4152
4189
  this.#service.getConfigFileNameForFile = () => undefined;
4153
4190
  break;
4154
4191
  default:
4155
4192
  this.#service.getConfigFileNameForFile = this.#isFileIncluded(filePath)
4156
- ? () => this.#resolvedConfig.tsconfig
4193
+ ? () => this.#projectConfig.specifier
4157
4194
  : () => undefined;
4158
4195
  }
4159
4196
  const { configFileErrors, configFileName } = this.#service.openClientFile(filePath, sourceText, undefined, this.#resolvedConfig.rootPath);
4160
4197
  if (configFileName !== this.#lastSeenProject) {
4161
4198
  this.#lastSeenProject = configFileName;
4162
- EventEmitter.dispatch([
4163
- "project:uses",
4164
- { compilerVersion: this.#compiler.version, projectConfigFilePath: configFileName },
4165
- ]);
4199
+ const projectConfig = configFileName != null
4200
+ ? { ...this.#projectConfig, specifier: configFileName }
4201
+ : { kind: 1, specifier: "baseline" };
4202
+ EventEmitter.dispatch(["project:uses", { compilerVersion: this.#compiler.version, projectConfig }]);
4166
4203
  if (configFileErrors && configFileErrors.length > 0) {
4167
4204
  EventEmitter.dispatch([
4168
4205
  "project:error",
@@ -5557,7 +5594,7 @@ class ExpectService {
5557
5594
  return;
5558
5595
  }
5559
5596
  const matchWorker = new MatchWorker(this.#compiler, this.#program, assertionNode);
5560
- if (!(matcherNameText === "toRaiseError" && assertionNode.isNot === false) &&
5597
+ if (!(matcherNameText === "toRaiseError" && !assertionNode.isNot) &&
5561
5598
  this.#reject.argumentType([
5562
5599
  ["source", assertionNode.source[0]],
5563
5600
  ["target", assertionNode.target?.[0]],
@@ -5623,10 +5660,10 @@ class Reject {
5623
5660
  constructor(compiler, program, resolvedConfig) {
5624
5661
  this.#compiler = compiler;
5625
5662
  this.#typeChecker = program.getTypeChecker();
5626
- if (resolvedConfig?.rejectAnyType) {
5663
+ if (resolvedConfig.rejectAnyType) {
5627
5664
  this.#rejectedArgumentTypes.add("any");
5628
5665
  }
5629
- if (resolvedConfig?.rejectNeverType) {
5666
+ if (resolvedConfig.rejectNeverType) {
5630
5667
  this.#rejectedArgumentTypes.add("never");
5631
5668
  }
5632
5669
  }
@@ -5756,11 +5793,11 @@ class FixmeService {
5756
5793
  let isFail;
5757
5794
  if (owner === FixmeService.#expectRange?.owner) {
5758
5795
  isFail = FixmeService.#expectRange.isFail;
5759
- FixmeService.#expectRange = FixmeService.#expectRange?.previous;
5796
+ FixmeService.#expectRange = FixmeService.#expectRange.previous;
5760
5797
  }
5761
5798
  if (owner === FixmeService.#range?.owner) {
5762
- isFail = FixmeService.#range?.isFail;
5763
- FixmeService.#range = FixmeService.#range?.previous;
5799
+ isFail = FixmeService.#range.isFail;
5800
+ FixmeService.#range = FixmeService.#range.previous;
5764
5801
  }
5765
5802
  if (isFail === false) {
5766
5803
  const text = [FixmeDiagnosticText.wasSupposedToFail(owner.brand), FixmeDiagnosticText.considerRemoving()];
@@ -6028,7 +6065,7 @@ class FileRunner {
6028
6065
  class Runner {
6029
6066
  #eventEmitter = new EventEmitter();
6030
6067
  #resolvedConfig;
6031
- static version = "6.2.0";
6068
+ static version = "7.0.0-beta.0";
6032
6069
  constructor(resolvedConfig) {
6033
6070
  this.#resolvedConfig = resolvedConfig;
6034
6071
  }
@@ -6115,7 +6152,17 @@ class Runner {
6115
6152
  }
6116
6153
  }
6117
6154
 
6155
+ class CliDiagnosticText {
6156
+ static configLocationChanged(oldConfigFilePath, newConfigFilePath) {
6157
+ return [
6158
+ "The default configuration file location has changed.",
6159
+ `The discovered file has been automatically renamed from '${Path.relative(".", oldConfigFilePath)}' to '${Path.relative(".", newConfigFilePath)}'.`,
6160
+ ];
6161
+ }
6162
+ }
6163
+
6118
6164
  class Cli {
6165
+ #deferredDiagnostics;
6119
6166
  #eventEmitter = new EventEmitter();
6120
6167
  #noErrorExitCode;
6121
6168
  constructor(options) {
@@ -6156,6 +6203,14 @@ class Cli {
6156
6203
  if (cancellationToken.isCancellationRequested()) {
6157
6204
  return;
6158
6205
  }
6206
+ if (!commandLineOptions.config) {
6207
+ const oldConfigFilePath = Path.resolve(Config.resolveRootPath(commandLineOptions.root), "./tstyche.config.json");
6208
+ if (existsSync(oldConfigFilePath) && !environmentOptions.isCi) {
6209
+ const newConfigFilePath = Path.resolve(Config.resolveConfigFilePath(undefined, commandLineOptions.root));
6210
+ await fs.rename(oldConfigFilePath, newConfigFilePath);
6211
+ this.#deferredDiagnostics = Diagnostic.warning(CliDiagnosticText.configLocationChanged(oldConfigFilePath, newConfigFilePath));
6212
+ }
6213
+ }
6159
6214
  do {
6160
6215
  if (cancellationToken.getReason() === "configChange") {
6161
6216
  cancellationToken.reset();
@@ -6164,13 +6219,8 @@ class Cli {
6164
6219
  this.#eventEmitter.addHandler(cancellationHandler);
6165
6220
  this.#eventEmitter.addReporter(setupReporter);
6166
6221
  }
6167
- const { configFileOptions, configFilePath } = await Config.parseConfigFile(commandLineOptions.config, commandLineOptions.root);
6168
- const resolvedConfig = Config.resolve({
6169
- configFileOptions,
6170
- configFilePath,
6171
- commandLineOptions,
6172
- pathMatch,
6173
- });
6222
+ const { configFileOptions } = await Config.parseConfigFile(commandLineOptions.config, commandLineOptions.root);
6223
+ const resolvedConfig = Config.resolve({ configFileOptions, commandLineOptions, pathMatch });
6174
6224
  if (cancellationToken.isCancellationRequested()) {
6175
6225
  if (commandLine.includes("--watch")) {
6176
6226
  await this.#waitForChangedFiles(resolvedConfig, cancellationToken);
@@ -6198,7 +6248,7 @@ class Cli {
6198
6248
  }
6199
6249
  }
6200
6250
  if (commandLine.includes("--listFiles")) {
6201
- OutputService.writeMessage(formattedText(testFiles.map((testFile) => testFile.toString())));
6251
+ OutputService.writeMessage(formattedText(testFiles));
6202
6252
  continue;
6203
6253
  }
6204
6254
  this.#eventEmitter.removeHandler(cancellationHandler);
@@ -6206,6 +6256,10 @@ class Cli {
6206
6256
  const runner = new Runner(resolvedConfig);
6207
6257
  await runner.run(testFiles, cancellationToken);
6208
6258
  } while (cancellationToken.getReason() === "configChange");
6259
+ if (this.#deferredDiagnostics != null) {
6260
+ OutputService.writeBlankLine();
6261
+ OutputService.writeWarning(diagnosticText(this.#deferredDiagnostics));
6262
+ }
6209
6263
  this.#eventEmitter.removeHandlers();
6210
6264
  }
6211
6265
  #waitForChangedFiles(resolvedConfig, cancellationToken) {
@@ -6236,4 +6290,4 @@ class Cli {
6236
6290
  }
6237
6291
  }
6238
6292
 
6239
- export { BaseReporter, CancellationReason, CancellationToken, Cli, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, Directive, DotReporter, EventEmitter, ExpectResult, FileLocation, FileResult, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, ProjectResult, Result, ResultStatus, Runner, Scribbler, Select, SelectDiagnosticText, SetupReporter, Store, StreamController, SummaryReporter, SuppressedResult, TargetResult, TestResult, Text, Version, WatchReporter, addsPackageText, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, dotText, environmentOptions, fileStatusText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, prologueText, summaryText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
6293
+ export { BaseReporter, CancellationReason, CancellationToken, Cli, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, Directive, DotReporter, EventEmitter, ExpectResult, FileLocation, FileResult, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, ProjectConfigKind, ProjectResult, Result, ResultStatus, Runner, Scribbler, Select, SelectDiagnosticText, SetupReporter, Store, StreamController, SummaryReporter, SuppressedResult, TargetResult, TestResult, Text, Version, WatchReporter, addsText, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, dotText, environmentOptions, fileStatusText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, prologueText, summaryText, testNameText, usesText, waitingForFileChangesText, watchUsageText };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tstyche",
3
- "version": "6.2.0",
3
+ "version": "7.0.0-beta.0",
4
4
  "description": "Everything You Need for Type Testing.",
5
5
  "keywords": [
6
6
  "typescript",