tstyche 6.0.3 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tag.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Runs TSTyche in the same process, streaming error messages and test results to the `stderr` and `stdout` in real-time.
3
+ *
4
+ * @returns A promise that resolves if the test run is successful and rejects if it fails.
5
+ */
6
+ declare function tstyche(template: TemplateStringsArray, ...substitutions: Array<string>): Promise<void>;
7
+
8
+ export { tstyche as default };
package/dist/tag.js ADDED
@@ -0,0 +1,36 @@
1
+ import { Cli, EventEmitter, CancellationToken } from './tstyche.js';
2
+
3
+ class StatusHandler {
4
+ #hasError = false;
5
+ hasError() {
6
+ return this.#hasError;
7
+ }
8
+ on([event, payload]) {
9
+ if (event === "run:start") {
10
+ this.#hasError = false;
11
+ return;
12
+ }
13
+ if ("diagnostics" in payload) {
14
+ if (payload.diagnostics.some((diagnostic) => diagnostic.category === "error")) {
15
+ this.#hasError = true;
16
+ }
17
+ }
18
+ }
19
+ }
20
+ async function tstyche(template, ...substitutions) {
21
+ const cli = new Cli({ noErrorExitCode: true });
22
+ const commandLine = String.raw(template, ...substitutions).split(/\s+/);
23
+ const eventEmitter = new EventEmitter();
24
+ const statusHandler = new StatusHandler();
25
+ eventEmitter.addHandler(statusHandler);
26
+ await cli.run(commandLine, new CancellationToken());
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
+ });
34
+ }
35
+
36
+ export { tstyche as default };
package/dist/tstyche.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type ts from 'typescript';
2
+ import type { WriteStream } from 'node:tty';
2
3
 
3
4
  declare enum CancellationReason {
4
5
  ConfigChange = "configChange",
@@ -15,9 +16,13 @@ declare class CancellationToken {
15
16
  reset(): void;
16
17
  }
17
18
 
19
+ interface CliOptions {
20
+ noErrorExitCode?: boolean;
21
+ }
18
22
  declare class Cli {
19
23
  #private;
20
- run(commandLine: Array<string>, cancellationToken?: CancellationToken): Promise<void>;
24
+ constructor(options?: CliOptions);
25
+ run(commandLine: ReadonlyArray<string>, cancellationToken?: CancellationToken): Promise<void>;
21
26
  }
22
27
 
23
28
  declare enum DiagnosticCategory {
@@ -143,7 +148,9 @@ interface CommandLineOptions {
143
148
  listFiles?: boolean;
144
149
  only?: string;
145
150
  prune?: boolean;
151
+ quiet?: boolean;
146
152
  reporters?: Array<string>;
153
+ root?: string;
147
154
  showConfig?: boolean;
148
155
  skip?: string;
149
156
  target?: Array<string>;
@@ -157,6 +164,7 @@ interface ConfigFileOptions {
157
164
  checkSuppressedErrors?: boolean;
158
165
  failFast?: boolean;
159
166
  fixtureFileMatch?: Array<string>;
167
+ quiet?: boolean;
160
168
  rejectAnyType?: boolean;
161
169
  rejectNeverType?: boolean;
162
170
  reporters?: Array<string>;
@@ -191,11 +199,11 @@ interface DirectiveRange {
191
199
 
192
200
  declare class Config {
193
201
  #private;
194
- static parseCommandLine(commandLine: Array<string>): Promise<{
202
+ static parseCommandLine(commandLine: ReadonlyArray<string>): Promise<{
195
203
  commandLineOptions: CommandLineOptions;
196
204
  pathMatch: Array<string>;
197
205
  }>;
198
- static parseConfigFile(filePath?: string): Promise<{
206
+ static parseConfigFile(configPath?: string, rootPath?: string): Promise<{
199
207
  configFileOptions: ConfigFileOptions;
200
208
  configFilePath: string;
201
209
  }>;
@@ -205,7 +213,7 @@ declare class Config {
205
213
  commandLineOptions?: Omit<CommandLineOptions, "config">;
206
214
  pathMatch?: Array<string>;
207
215
  }): ResolvedConfig;
208
- static resolveConfigFilePath(filePath?: string): string;
216
+ static resolveConfigFilePath(configPath?: string, rootPath?: string): string;
209
217
  }
210
218
 
211
219
  declare enum OptionBrand {
@@ -604,8 +612,18 @@ declare function formattedText(input: string | Array<string> | Record<string, un
604
612
 
605
613
  declare function helpText(options: Map<string, OptionDefinition>, version: string): ScribblerJsx.Element;
606
614
 
615
+ declare class StreamController {
616
+ #private;
617
+ constructor(stream: WriteStream);
618
+ disable(): void;
619
+ enable(): void;
620
+ write(text: string): void;
621
+ }
622
+
607
623
  declare class OutputService {
608
624
  #private;
625
+ static errorStream: StreamController;
626
+ static outputStream: StreamController;
609
627
  static clearTerminal(): void;
610
628
  static eraseLastLine(): void;
611
629
  static writeError(element: ScribblerJsx.Element | Array<ScribblerJsx.Element>): void;
@@ -714,5 +732,5 @@ declare class Version {
714
732
  static isSatisfiedWith(source: string, target: string): boolean;
715
733
  }
716
734
 
717
- export { BaseReporter, CancellationReason, CancellationToken, Cli, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, Directive, EventEmitter, ExpectResult, FileLocation, FileResult, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, ProjectResult, Result, ResultStatus, Runner, Scribbler, ScribblerJsx, Select, SelectDiagnosticText, SetupReporter, Store, SummaryReporter, SuppressedResult, TargetResult, TestResult, Text, Version, WatchReporter, addsPackageText, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, environmentOptions, fileStatusText, fileViewText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, prologueText, summaryText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
735
+ export { BaseReporter, CancellationReason, CancellationToken, Cli, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, Directive, 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, environmentOptions, fileStatusText, fileViewText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, prologueText, summaryText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
718
736
  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 };
package/dist/tstyche.js CHANGED
@@ -1099,6 +1099,12 @@ class Options {
1099
1099
  group: 2,
1100
1100
  name: "prune",
1101
1101
  },
1102
+ {
1103
+ brand: "boolean",
1104
+ description: "Silence all test runner output except errors and warnings.",
1105
+ group: 2 | 4,
1106
+ name: "quiet",
1107
+ },
1102
1108
  {
1103
1109
  brand: "boolean",
1104
1110
  description: "Reject the 'any' type passed as an argument to the 'expect()' function or a matcher.",
@@ -1121,6 +1127,12 @@ class Options {
1121
1127
  },
1122
1128
  name: "reporters",
1123
1129
  },
1130
+ {
1131
+ brand: "string",
1132
+ description: "The path to a directory containing files of a test project.",
1133
+ group: 2,
1134
+ name: "root",
1135
+ },
1124
1136
  {
1125
1137
  brand: "string",
1126
1138
  description: "The path to a directory containing files of a test project.",
@@ -1202,11 +1214,15 @@ class Options {
1202
1214
  const canonicalOptionName = Options.#getCanonicalOptionName(optionName);
1203
1215
  switch (canonicalOptionName) {
1204
1216
  case "config":
1217
+ case "root":
1205
1218
  case "rootPath":
1206
1219
  case "tsconfig":
1207
1220
  if (canonicalOptionName === "tsconfig" && Options.#isLookupStrategy(optionValue)) {
1208
1221
  break;
1209
1222
  }
1223
+ if (optionValue.startsWith("file:")) {
1224
+ optionValue = fileURLToPath(optionValue);
1225
+ }
1210
1226
  optionValue = Path.resolve(rootPath, optionValue);
1211
1227
  break;
1212
1228
  case "reporters":
@@ -1231,6 +1247,7 @@ class Options {
1231
1247
  const canonicalOptionName = Options.#getCanonicalOptionName(optionName);
1232
1248
  switch (canonicalOptionName) {
1233
1249
  case "config":
1250
+ case "root":
1234
1251
  case "rootPath":
1235
1252
  case "tsconfig":
1236
1253
  if (canonicalOptionName === "tsconfig" && Options.#isLookupStrategy(optionValue)) {
@@ -1553,6 +1570,7 @@ const defaultOptions = {
1553
1570
  checkSuppressedErrors: true,
1554
1571
  failFast: false,
1555
1572
  fixtureFileMatch: ["**/__fixtures__/*.{ts,tsx}", "**/fixtures/*.{ts,tsx}"],
1573
+ quiet: false,
1556
1574
  rejectAnyType: true,
1557
1575
  rejectNeverType: true,
1558
1576
  reporters: ["list", "summary"],
@@ -1573,10 +1591,10 @@ class Config {
1573
1591
  await commandLineParser.parse(commandLine);
1574
1592
  return { commandLineOptions, pathMatch };
1575
1593
  }
1576
- static async parseConfigFile(filePath) {
1577
- const configFilePath = Config.resolveConfigFilePath(filePath);
1594
+ static async parseConfigFile(configPath, rootPath) {
1595
+ const configFilePath = Config.resolveConfigFilePath(configPath, rootPath);
1578
1596
  const configFileOptions = {
1579
- rootPath: Path.dirname(configFilePath),
1597
+ rootPath: rootPath ?? Path.dirname(configFilePath),
1580
1598
  };
1581
1599
  if (existsSync(configFilePath)) {
1582
1600
  const configFileText = await fs.readFile(configFilePath, {
@@ -1599,10 +1617,16 @@ class Config {
1599
1617
  if ("config" in resolvedConfig) {
1600
1618
  delete resolvedConfig.config;
1601
1619
  }
1620
+ if ("root" in resolvedConfig) {
1621
+ delete resolvedConfig.root;
1622
+ }
1602
1623
  return resolvedConfig;
1603
1624
  }
1604
- static resolveConfigFilePath(filePath) {
1605
- return filePath != null ? Path.resolve(filePath) : Path.resolve("./tstyche.config.json");
1625
+ static resolveConfigFilePath(configPath, rootPath = ".") {
1626
+ if (configPath != null) {
1627
+ return Path.resolve(configPath);
1628
+ }
1629
+ return Path.resolve(rootPath, "./tstyche.config.json");
1606
1630
  }
1607
1631
  }
1608
1632
 
@@ -2415,19 +2439,36 @@ function helpText(options, version) {
2415
2439
  return (jsx(Text, { children: [jsx(HelpHeaderText, { tstycheVersion: version }), jsx(Line, {}), jsx(CommandLineUsageText, {}), jsx(Line, {}), jsx(CommandLineOptionsText, { optionDefinitions: options }), jsx(Line, {}), jsx(HelpFooterText, {}), jsx(Line, {})] }));
2416
2440
  }
2417
2441
 
2442
+ class StreamController {
2443
+ #isEnabled = true;
2444
+ #stream;
2445
+ constructor(stream) {
2446
+ this.#stream = stream;
2447
+ }
2448
+ disable() {
2449
+ this.#isEnabled = false;
2450
+ }
2451
+ enable() {
2452
+ this.#isEnabled = true;
2453
+ }
2454
+ write(text) {
2455
+ this.#isEnabled && this.#stream.write(text);
2456
+ }
2457
+ }
2458
+
2418
2459
  class OutputService {
2460
+ static errorStream = new StreamController(process.stderr);
2461
+ static outputStream = new StreamController(process.stdout);
2419
2462
  static #isClear = false;
2420
2463
  static #scribbler = new Scribbler();
2421
- static #stderr = process.stderr;
2422
- static #stdout = process.stdout;
2423
2464
  static clearTerminal() {
2424
2465
  if (!OutputService.#isClear) {
2425
- OutputService.#stdout.write("\u001B[2J\u001B[3J\u001B[H");
2466
+ OutputService.outputStream.write("\u001B[2J\u001B[3J\u001B[H");
2426
2467
  OutputService.#isClear = true;
2427
2468
  }
2428
2469
  }
2429
2470
  static eraseLastLine() {
2430
- OutputService.#stdout.write("\u001B[1A\u001B[0K");
2471
+ OutputService.outputStream.write("\u001B[1A\u001B[0K");
2431
2472
  }
2432
2473
  static #writeTo(stream, element) {
2433
2474
  const elements = Array.isArray(element) ? element : [element];
@@ -2437,13 +2478,13 @@ class OutputService {
2437
2478
  OutputService.#isClear = false;
2438
2479
  }
2439
2480
  static writeError(element) {
2440
- OutputService.#writeTo(OutputService.#stderr, element);
2481
+ OutputService.#writeTo(OutputService.errorStream, element);
2441
2482
  }
2442
2483
  static writeMessage(element) {
2443
- OutputService.#writeTo(OutputService.#stdout, element);
2484
+ OutputService.#writeTo(OutputService.outputStream, element);
2444
2485
  }
2445
2486
  static writeWarning(element) {
2446
- OutputService.#writeTo(OutputService.#stderr, element);
2487
+ OutputService.#writeTo(OutputService.errorStream, element);
2447
2488
  }
2448
2489
  }
2449
2490
 
@@ -5914,7 +5955,7 @@ class FileRunner {
5914
5955
  class Runner {
5915
5956
  #eventEmitter = new EventEmitter();
5916
5957
  #resolvedConfig;
5917
- static version = "6.0.3";
5958
+ static version = "6.1.0";
5918
5959
  constructor(resolvedConfig) {
5919
5960
  this.#resolvedConfig = resolvedConfig;
5920
5961
  }
@@ -5952,6 +5993,9 @@ class Runner {
5952
5993
  }
5953
5994
  }
5954
5995
  async run(files, cancellationToken = new CancellationToken()) {
5996
+ if (this.#resolvedConfig.quiet) {
5997
+ OutputService.outputStream.disable();
5998
+ }
5955
5999
  if (!this.#resolvedConfig.watch) {
5956
6000
  OutputService.writeMessage(prologueText(Runner.version, this.#resolvedConfig.rootPath));
5957
6001
  }
@@ -5964,6 +6008,9 @@ class Runner {
5964
6008
  }
5965
6009
  this.#eventEmitter.removeReporters();
5966
6010
  this.#eventEmitter.removeHandlers();
6011
+ if (this.#resolvedConfig.quiet) {
6012
+ OutputService.outputStream.enable();
6013
+ }
5967
6014
  }
5968
6015
  async #run(files, cancellationToken) {
5969
6016
  const result = new Result(files);
@@ -5995,11 +6042,15 @@ class Runner {
5995
6042
 
5996
6043
  class Cli {
5997
6044
  #eventEmitter = new EventEmitter();
6045
+ #noErrorExitCode;
6046
+ constructor(options) {
6047
+ this.#noErrorExitCode = options?.noErrorExitCode ?? false;
6048
+ }
5998
6049
  async run(commandLine, cancellationToken = new CancellationToken()) {
5999
6050
  const cancellationHandler = new CancellationHandler(cancellationToken, "configError");
6000
6051
  this.#eventEmitter.addHandler(cancellationHandler);
6001
6052
  const exitCodeHandler = new ExitCodeHandler();
6002
- this.#eventEmitter.addHandler(exitCodeHandler);
6053
+ !this.#noErrorExitCode && this.#eventEmitter.addHandler(exitCodeHandler);
6003
6054
  const setupReporter = new SetupReporter();
6004
6055
  this.#eventEmitter.addReporter(setupReporter);
6005
6056
  if (commandLine.includes("--help")) {
@@ -6038,7 +6089,7 @@ class Cli {
6038
6089
  this.#eventEmitter.addHandler(cancellationHandler);
6039
6090
  this.#eventEmitter.addReporter(setupReporter);
6040
6091
  }
6041
- const { configFileOptions, configFilePath } = await Config.parseConfigFile(commandLineOptions.config);
6092
+ const { configFileOptions, configFilePath } = await Config.parseConfigFile(commandLineOptions.config, commandLineOptions.root);
6042
6093
  const resolvedConfig = Config.resolve({
6043
6094
  configFileOptions,
6044
6095
  configFilePath,
@@ -6110,4 +6161,4 @@ class Cli {
6110
6161
  }
6111
6162
  }
6112
6163
 
6113
- export { BaseReporter, CancellationReason, CancellationToken, Cli, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, Directive, EventEmitter, ExpectResult, FileLocation, FileResult, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, ProjectResult, Result, ResultStatus, Runner, Scribbler, Select, SelectDiagnosticText, SetupReporter, Store, SummaryReporter, SuppressedResult, TargetResult, TestResult, Text, Version, WatchReporter, addsPackageText, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, environmentOptions, fileStatusText, fileViewText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, prologueText, summaryText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
6164
+ export { BaseReporter, CancellationReason, CancellationToken, Cli, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, Directive, 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, environmentOptions, fileStatusText, fileViewText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, prologueText, summaryText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tstyche",
3
- "version": "6.0.3",
3
+ "version": "6.1.0",
4
4
  "description": "Everything You Need for Type Testing.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -25,6 +25,7 @@
25
25
  "import": "./dist/index.js",
26
26
  "require": "./dist/index.cjs"
27
27
  },
28
+ "./tag": "./dist/tag.js",
28
29
  "./tstyche": "./dist/tstyche.js",
29
30
  "./package.json": "./package.json"
30
31
  },