tstyche 6.2.0 → 7.0.0-beta.1

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
@@ -1,5 +1,4 @@
1
1
  import type ts from 'typescript';
2
- import type { WriteStream } from 'node:tty';
3
2
 
4
3
  declare enum CancellationReason {
5
4
  ConfigChange = "configChange",
@@ -169,7 +168,6 @@ interface ConfigFileOptions {
169
168
  rejectAnyType?: boolean;
170
169
  rejectNeverType?: boolean;
171
170
  reporters?: Array<string>;
172
- rootPath?: string;
173
171
  target?: Array<string>;
174
172
  testFileMatch?: Array<string>;
175
173
  tsconfig?: string;
@@ -183,9 +181,10 @@ interface InlineConfig {
183
181
  };
184
182
  template?: boolean;
185
183
  }
186
- interface ResolvedConfig extends Omit<CommandLineOptions, "config" | keyof ConfigFileOptions>, Required<ConfigFileOptions> {
184
+ interface ResolvedConfig extends Omit<CommandLineOptions, "config" | "root" | keyof ConfigFileOptions>, Required<ConfigFileOptions> {
187
185
  configFilePath: string;
188
186
  pathMatch: Array<string>;
187
+ rootPath: string;
189
188
  }
190
189
  interface TextRange {
191
190
  start: number;
@@ -205,17 +204,16 @@ declare class Config {
205
204
  commandLineOptions: CommandLineOptions;
206
205
  pathMatch: Array<string>;
207
206
  }>;
208
- static parseConfigFile(configPath?: string, rootPath?: string): Promise<{
207
+ static parseConfigFile(configPath?: string | undefined, rootPath?: string | undefined): Promise<{
209
208
  configFileOptions: ConfigFileOptions;
210
- configFilePath: string;
211
209
  }>;
212
210
  static resolve(options?: {
213
211
  configFileOptions?: ConfigFileOptions;
214
- configFilePath?: string;
215
- commandLineOptions?: Omit<CommandLineOptions, "config">;
212
+ commandLineOptions?: CommandLineOptions;
216
213
  pathMatch?: Array<string>;
217
214
  }): ResolvedConfig;
218
- static resolveConfigFilePath(configPath?: string, rootPath?: string): string;
215
+ static resolveConfigFilePath(configPath?: string | undefined, rootPath?: string | undefined): string;
216
+ static resolveRootPath(rootPath?: string | undefined): string;
219
217
  }
220
218
 
221
219
  declare enum OptionBrand {
@@ -258,8 +256,7 @@ declare const defaultOptions: Required<ConfigFileOptions>;
258
256
  declare enum OptionGroup {
259
257
  CommandLine = 2,
260
258
  ConfigFile = 4,
261
- InlineConditions = 8,
262
- ResolvedConfig = 6
259
+ InlineConditions = 8
263
260
  }
264
261
 
265
262
  interface BaseOptionDefinition {
@@ -283,7 +280,8 @@ type OptionDefinition = PrimitiveTypeOptionDefinition | ListTypeOptionDefinition
283
280
  declare class Options {
284
281
  #private;
285
282
  static for(optionGroup: OptionGroup): Map<string, OptionDefinition>;
286
- static resolve(optionName: string, optionValue: string, rootPath?: string): string;
283
+ static isJsonString(text: string): boolean;
284
+ static resolve(optionName: string, optionValue: string, basePath?: string): string;
287
285
  static validate(optionName: string, optionValue: string, onDiagnostics: DiagnosticsHandler, origin?: DiagnosticOrigin): Promise<void>;
288
286
  }
289
287
 
@@ -332,6 +330,13 @@ declare class WatchReporter extends BaseReporter {
332
330
  on([event, payload]: ReporterEvent): void;
333
331
  }
334
332
 
333
+ declare enum ProjectConfigKind {
334
+ Discovered = 0,
335
+ Default = 1,
336
+ Provided = 2,
337
+ Synthetic = 3
338
+ }
339
+
335
340
  declare enum ResultStatus {
336
341
  Runs = "runs",
337
342
  Passed = "passed",
@@ -343,6 +348,10 @@ declare enum ResultStatus {
343
348
  Todo = "todo"
344
349
  }
345
350
 
351
+ type ProjectConfig = {
352
+ kind: ProjectConfigKind;
353
+ specifier: string;
354
+ };
346
355
  type TargetResultStatus = ResultStatus.Runs | ResultStatus.Passed | ResultStatus.Failed;
347
356
  type TargetCounts = {
348
357
  [K in Exclude<TargetResultStatus, ResultStatus.Runs>]: number;
@@ -415,9 +424,9 @@ declare class FileResult {
415
424
 
416
425
  declare class ProjectResult {
417
426
  compilerVersion: string;
418
- projectConfigFilePath: string | undefined;
427
+ projectConfig: ProjectConfig;
419
428
  results: Array<FileResult>;
420
- constructor(compilerVersion: string, projectConfigFilePath: string | undefined);
429
+ constructor(compilerVersion: string, projectConfig: ProjectConfig);
421
430
  }
422
431
 
423
432
  declare class TargetResult {
@@ -468,7 +477,7 @@ type Event = ["config:error", {
468
477
  result: TargetResult;
469
478
  }] | ["project:uses", {
470
479
  compilerVersion: string;
471
- projectConfigFilePath: string | undefined;
480
+ projectConfig: ProjectConfig;
472
481
  }] | ["project:error", {
473
482
  diagnostics: Array<Diagnostic>;
474
483
  }] | ["file:start", {
@@ -599,7 +608,7 @@ interface TextProps {
599
608
  }
600
609
  declare function Text({ children, color, indent }: TextProps): ScribblerJsx.Element;
601
610
 
602
- declare function addsPackageText(packageVersion: string, packagePath: string, options?: {
611
+ declare function addsText(packageVersion: string, packagePath: string, options?: {
603
612
  short?: boolean;
604
613
  }): ScribblerJsx.Element;
605
614
 
@@ -621,6 +630,9 @@ declare function formattedText(input: string | Array<string> | Record<string, un
621
630
 
622
631
  declare function helpText(options: Map<string, OptionDefinition>, version: string): ScribblerJsx.Element;
623
632
 
633
+ interface WriteStream {
634
+ write(text: string): void;
635
+ }
624
636
  declare class StreamController {
625
637
  #private;
626
638
  constructor(stream: WriteStream);
@@ -655,8 +667,7 @@ declare function summaryText({ targetCounts, fileCounts, testCounts, assertionCo
655
667
 
656
668
  declare function testNameText(status: Exclude<TestResultStatus, ResultStatus.Runs>, name: string, indent?: number): ScribblerJsx.Element;
657
669
 
658
- declare function usesCompilerText(compilerVersion: string, projectConfigFilePath: string | undefined, options?: {
659
- prependEmptyLine?: boolean;
670
+ declare function usesText(compilerVersion: string, projectConfig: ProjectConfig, options?: {
660
671
  short?: boolean;
661
672
  }): ScribblerJsx.Element;
662
673
 
@@ -743,5 +754,5 @@ declare class Version {
743
754
  static isSatisfiedWith(source: string, target: string): boolean;
744
755
  }
745
756
 
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 };
757
+ 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 };
758
+ export type { AssertionCounts, AssertionResultStatus, CliOptions, 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, WriteStream };
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,30 +1209,33 @@ 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);
1218
1213
  }
1219
- static resolve(optionName, optionValue, rootPath = ".") {
1214
+ static isJsonString(text) {
1215
+ return text.startsWith("{");
1216
+ }
1217
+ static resolve(optionName, optionValue, basePath = ".") {
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:")) {
1230
1228
  optionValue = fileURLToPath(optionValue);
1231
1229
  }
1232
- optionValue = Path.resolve(rootPath, optionValue);
1230
+ optionValue = Path.resolve(basePath, 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 {
1239
1237
  if (optionValue.startsWith(".")) {
1240
- optionValue = pathToFileURL(Path.relative(".", Path.resolve(rootPath, optionValue))).toString();
1238
+ optionValue = pathToFileURL(Path.relative(".", Path.resolve(basePath, optionValue))).toString();
1241
1239
  }
1242
1240
  else {
1243
1241
  optionValue = import.meta.resolve(optionValue);
@@ -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))) {
@@ -1449,8 +1447,8 @@ class ConfigParser {
1449
1447
  this.#onRequiresValue(optionDefinition.name, optionDefinition.brand, jsonNode, isListItem);
1450
1448
  break;
1451
1449
  }
1452
- const rootPath = Path.dirname(this.#sourceFile.fileName);
1453
- optionValue = Options.resolve(optionDefinition.name, optionValue, rootPath);
1450
+ const basePath = Path.dirname(this.#sourceFile.fileName);
1451
+ optionValue = Options.resolve(optionDefinition.name, optionValue, basePath);
1454
1452
  await Options.validate(optionDefinition.name, optionValue, this.#onDiagnostics, jsonNode.origin);
1455
1453
  break;
1456
1454
  }
@@ -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));
@@ -1778,7 +1776,6 @@ var OptionGroup;
1778
1776
  OptionGroup[OptionGroup["CommandLine"] = 2] = "CommandLine";
1779
1777
  OptionGroup[OptionGroup["ConfigFile"] = 4] = "ConfigFile";
1780
1778
  OptionGroup[OptionGroup["InlineConditions"] = 8] = "InlineConditions";
1781
- OptionGroup[OptionGroup["ResolvedConfig"] = 6] = "ResolvedConfig";
1782
1779
  })(OptionGroup || (OptionGroup = {}));
1783
1780
 
1784
1781
  class CancellationHandler {
@@ -1874,13 +1871,21 @@ class FileResult {
1874
1871
  }
1875
1872
  }
1876
1873
 
1874
+ var ProjectConfigKind;
1875
+ (function (ProjectConfigKind) {
1876
+ ProjectConfigKind[ProjectConfigKind["Discovered"] = 0] = "Discovered";
1877
+ ProjectConfigKind[ProjectConfigKind["Default"] = 1] = "Default";
1878
+ ProjectConfigKind[ProjectConfigKind["Provided"] = 2] = "Provided";
1879
+ ProjectConfigKind[ProjectConfigKind["Synthetic"] = 3] = "Synthetic";
1880
+ })(ProjectConfigKind || (ProjectConfigKind = {}));
1881
+
1877
1882
  class ProjectResult {
1878
1883
  compilerVersion;
1879
- projectConfigFilePath;
1884
+ projectConfig;
1880
1885
  results = [];
1881
- constructor(compilerVersion, projectConfigFilePath) {
1886
+ constructor(compilerVersion, projectConfig) {
1882
1887
  this.compilerVersion = compilerVersion;
1883
- this.projectConfigFilePath = projectConfigFilePath;
1888
+ this.projectConfig = projectConfig;
1884
1889
  }
1885
1890
  }
1886
1891
 
@@ -1982,10 +1987,10 @@ class ResultHandler {
1982
1987
  }
1983
1988
  break;
1984
1989
  case "project:uses": {
1985
- let projectResult = this.#targetResult.results.get(payload.projectConfigFilePath);
1990
+ let projectResult = this.#targetResult.results.get(payload.projectConfig.specifier);
1986
1991
  if (!projectResult) {
1987
- projectResult = new ProjectResult(payload.compilerVersion, payload.projectConfigFilePath);
1988
- this.#targetResult.results.set(payload.projectConfigFilePath, projectResult);
1992
+ projectResult = new ProjectResult(payload.compilerVersion, payload.projectConfig);
1993
+ this.#targetResult.results.set(payload.projectConfig.specifier, projectResult);
1989
1994
  }
1990
1995
  this.#projectResult = projectResult;
1991
1996
  break;
@@ -2229,7 +2234,7 @@ class Scribbler {
2229
2234
  }
2230
2235
  }
2231
2236
 
2232
- function addsPackageText(packageVersion, packagePath, options) {
2237
+ function addsText(packageVersion, packagePath, options) {
2233
2238
  if (options?.short) {
2234
2239
  return (jsx(Line, { children: jsx(Text, { color: "90", children: packageVersion }) }));
2235
2240
  }
@@ -2563,15 +2568,24 @@ function testNameText(status, name, indent = 0) {
2563
2568
  return (jsx(Line, { indent: indent + 1, children: [jsx(Text, { color: getStatusColor(status), children: statusText }), " ", jsx(Text, { color: "90", children: name })] }));
2564
2569
  }
2565
2570
 
2566
- function usesCompilerText(compilerVersion, projectConfigFilePath, options) {
2571
+ function usesText(compilerVersion, projectConfig, options) {
2567
2572
  if (options?.short) {
2568
2573
  return jsx(Text, { color: "34", children: compilerVersion });
2569
2574
  }
2570
- let projectConfigPathText;
2571
- if (projectConfigFilePath != null) {
2572
- projectConfigPathText = (jsx(Text, { color: "90", children: [" with ", Path.relative("", projectConfigFilePath)] }));
2575
+ let projectConfigText;
2576
+ switch (projectConfig.kind) {
2577
+ case 0:
2578
+ case 2:
2579
+ projectConfigText = (jsx(Text, { color: "90", children: [" with ", Path.relative("", projectConfig.specifier)] }));
2580
+ break;
2581
+ case 1:
2582
+ projectConfigText = (jsx(Text, { color: "90", children: [" with ", projectConfig.specifier, " TSConfig"] }));
2583
+ break;
2584
+ case 3:
2585
+ projectConfigText = jsx(Text, { color: "90", children: " with inline TSConfig" });
2586
+ break;
2573
2587
  }
2574
- return (jsx(Text, { children: [options?.prependEmptyLine ? jsx(Line, {}) : undefined, jsx(Line, { children: [jsx(Text, { color: "34", children: "uses" }), " TypeScript ", compilerVersion, projectConfigPathText] }), jsx(Line, {})] }));
2588
+ return (jsx(Text, { children: [jsx(Line, { children: [jsx(Text, { color: "34", children: "uses" }), " TypeScript ", compilerVersion, projectConfigText] }), jsx(Line, {})] }));
2575
2589
  }
2576
2590
 
2577
2591
  function waitingForFileChangesText() {
@@ -2602,7 +2616,7 @@ class DotReporter extends BaseReporter {
2602
2616
  on([event, payload]) {
2603
2617
  switch (event) {
2604
2618
  case "store:adds":
2605
- OutputService.writeMessage(addsPackageText(payload.packageVersion, payload.packagePath, { short: true }));
2619
+ OutputService.writeMessage(addsText(payload.packageVersion, payload.packagePath, { short: true }));
2606
2620
  this.#hasReportedAdds = true;
2607
2621
  break;
2608
2622
  case "store:error":
@@ -2618,7 +2632,7 @@ class DotReporter extends BaseReporter {
2618
2632
  this.#hasReportedAdds = false;
2619
2633
  }
2620
2634
  if (this.resolvedConfig.target.length > 1) {
2621
- OutputService.writeMessage(usesCompilerText(payload.compilerVersion, payload.projectConfigFilePath, { short: true }));
2635
+ OutputService.writeMessage(usesText(payload.compilerVersion, payload.projectConfig, { short: true }));
2622
2636
  }
2623
2637
  break;
2624
2638
  case "target:end":
@@ -2692,7 +2706,7 @@ class ListReporter extends BaseReporter {
2692
2706
  this.resolvedConfig.verbose || (payload.result.files.length === 1 && this.resolvedConfig.watch !== true);
2693
2707
  break;
2694
2708
  case "store:adds":
2695
- OutputService.writeMessage(addsPackageText(payload.packageVersion, payload.packagePath));
2709
+ OutputService.writeMessage(addsText(payload.packageVersion, payload.packagePath));
2696
2710
  this.#hasReportedAdds = true;
2697
2711
  break;
2698
2712
  case "store:error":
@@ -2705,9 +2719,10 @@ class ListReporter extends BaseReporter {
2705
2719
  this.#hasReportedUses = false;
2706
2720
  break;
2707
2721
  case "project:uses":
2708
- OutputService.writeMessage(usesCompilerText(payload.compilerVersion, payload.projectConfigFilePath, {
2709
- prependEmptyLine: this.#hasReportedUses && !this.#hasReportedAdds && !this.#hasReportedError,
2710
- }));
2722
+ if (this.#hasReportedUses && !(this.#hasReportedAdds || this.#hasReportedError)) {
2723
+ OutputService.writeBlankLine();
2724
+ }
2725
+ OutputService.writeMessage(usesText(payload.compilerVersion, payload.projectConfig));
2711
2726
  this.#hasReportedAdds = false;
2712
2727
  this.#hasReportedUses = true;
2713
2728
  break;
@@ -2802,7 +2817,7 @@ class ListReporter extends BaseReporter {
2802
2817
  class SetupReporter {
2803
2818
  on([event, payload]) {
2804
2819
  if (event === "store:adds") {
2805
- OutputService.writeMessage(addsPackageText(payload.packageVersion, payload.packagePath));
2820
+ OutputService.writeMessage(addsText(payload.packageVersion, payload.packagePath));
2806
2821
  return;
2807
2822
  }
2808
2823
  if ("diagnostics" in payload) {
@@ -3562,11 +3577,11 @@ class SuppressedLayer {
3562
3577
  #collectSuppressedErrors(text) {
3563
3578
  const ranges = [];
3564
3579
  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();
3580
+ const offsetText = match[1];
3581
+ const directiveText = match[2];
3582
+ const ignoreText = match[3];
3583
+ const argumentSeparatorText = match[4];
3584
+ const argumentText = match[5]?.split(/--+/)[0]?.trimEnd();
3570
3585
  if (typeof offsetText !== "string" || !directiveText) {
3571
3586
  continue;
3572
3587
  }
@@ -4051,14 +4066,17 @@ var TestTreeNodeFlags;
4051
4066
 
4052
4067
  class ProjectService {
4053
4068
  #compiler;
4069
+ #host;
4054
4070
  #lastSeenProject = "";
4071
+ #projectConfig;
4055
4072
  #resolvedConfig;
4056
- #seenPrograms = new WeakSet();
4073
+ #seenProjects = new Set();
4057
4074
  #seenTestFiles = new Set();
4058
4075
  #service;
4059
4076
  constructor(compiler, resolvedConfig) {
4060
4077
  this.#compiler = compiler;
4061
4078
  this.#resolvedConfig = resolvedConfig;
4079
+ this.#projectConfig = this.#resolveProjectConfig(resolvedConfig.tsconfig);
4062
4080
  const noop = () => undefined;
4063
4081
  const noopLogger = {
4064
4082
  close: noop,
@@ -4074,8 +4092,8 @@ class ProjectService {
4074
4092
  const noopWatcher = {
4075
4093
  close: noop,
4076
4094
  };
4077
- const host = {
4078
- ...this.#compiler.sys,
4095
+ this.#host = {
4096
+ ...compiler.sys,
4079
4097
  clearImmediate,
4080
4098
  clearTimeout,
4081
4099
  setImmediate,
@@ -4083,10 +4101,13 @@ class ProjectService {
4083
4101
  watchDirectory: () => noopWatcher,
4084
4102
  watchFile: () => noopWatcher,
4085
4103
  };
4104
+ if (this.#projectConfig.kind === 3) {
4105
+ this.#host.readFile = (path) => path === this.#projectConfig.specifier ? resolvedConfig.tsconfig : compiler.sys.readFile(path);
4106
+ }
4086
4107
  this.#service = new this.#compiler.server.ProjectService({
4087
4108
  allowLocalPluginLoads: true,
4088
4109
  cancellationToken: this.#compiler.server.nullCancellationToken,
4089
- host,
4110
+ host: this.#host,
4090
4111
  logger: noopLogger,
4091
4112
  session: undefined,
4092
4113
  useInferredProjectPerProjectRoot: true,
@@ -4107,6 +4128,7 @@ class ProjectService {
4107
4128
  jsx: this.#compiler.JsxEmit.Preserve,
4108
4129
  module: this.#compiler.ModuleKind.NodeNext,
4109
4130
  moduleResolution: this.#compiler.ModuleResolutionKind.NodeNext,
4131
+ noEmit: true,
4110
4132
  noUncheckedIndexedAccess: true,
4111
4133
  resolveJsonModule: true,
4112
4134
  strict: 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",
@@ -4174,10 +4211,10 @@ class ProjectService {
4174
4211
  this.#seenTestFiles.add(filePath);
4175
4212
  const languageService = this.getLanguageService(filePath);
4176
4213
  const program = languageService?.getProgram();
4177
- if (!program || this.#seenPrograms.has(program)) {
4214
+ if (!program || this.#seenProjects.has(configFileName)) {
4178
4215
  return;
4179
4216
  }
4180
- this.#seenPrograms.add(program);
4217
+ this.#seenProjects.add(configFileName);
4181
4218
  const sourceFilesToCheck = program.getSourceFiles().filter((sourceFile) => {
4182
4219
  if (program.isSourceFileFromExternalLibrary(sourceFile) || program.isSourceFileDefaultLibrary(sourceFile)) {
4183
4220
  return false;
@@ -4193,9 +4230,9 @@ class ProjectService {
4193
4230
  }
4194
4231
  return false;
4195
4232
  });
4196
- const diagnostics = [];
4233
+ const diagnostics = [...program.getOptionsDiagnostics()];
4197
4234
  for (const sourceFile of sourceFilesToCheck) {
4198
- diagnostics.push(...program.getSyntacticDiagnostics(sourceFile), ...program.getSemanticDiagnostics(sourceFile));
4235
+ diagnostics.push(...program.getSyntacticDiagnostics(sourceFile), ...program.getSemanticDiagnostics(sourceFile), ...program.getDeclarationDiagnostics(sourceFile));
4199
4236
  }
4200
4237
  if (diagnostics.length > 0) {
4201
4238
  EventEmitter.dispatch(["project:error", { diagnostics: Diagnostic.fromDiagnostics(diagnostics) }]);
@@ -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.1";
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.1",
4
4
  "description": "Everything You Need for Type Testing.",
5
5
  "keywords": [
6
6
  "typescript",