tstyche 3.0.0-beta.6 → 3.0.0-rc.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/build/index.d.cts CHANGED
@@ -149,7 +149,7 @@ interface Matchers {
149
149
  /**
150
150
  * Checks if the source type raises an error.
151
151
  */
152
- toRaiseError: (...target: Array<string | number>) => void;
152
+ toRaiseError: (...target: Array<string | number | RegExp>) => void;
153
153
  }
154
154
  interface Matchers {
155
155
  /**
package/build/index.d.ts CHANGED
@@ -149,7 +149,7 @@ interface Matchers {
149
149
  /**
150
150
  * Checks if the source type raises an error.
151
151
  */
152
- toRaiseError: (...target: Array<string | number>) => void;
152
+ toRaiseError: (...target: Array<string | number | RegExp>) => void;
153
153
  }
154
154
  interface Matchers {
155
155
  /**
@@ -65,7 +65,7 @@ declare class Diagnostic {
65
65
  static warning(text: string | Array<string>, origin?: DiagnosticOrigin): Diagnostic;
66
66
  }
67
67
 
68
- type DiagnosticsHandler$1 = (this: void, diagnostic: Diagnostic) => void;
68
+ type DiagnosticsHandler<T extends Diagnostic | Array<Diagnostic> = Diagnostic> = (this: void, diagnostics: T) => void;
69
69
 
70
70
  declare enum TestMemberBrand {
71
71
  Describe = "describe",
@@ -130,24 +130,17 @@ declare enum OptionBrand {
130
130
  List = "list"
131
131
  }
132
132
 
133
- declare enum OptionGroup {
134
- CommandLine = 2,
135
- ConfigFile = 4,
136
- ResolvedConfig = 6
137
- }
138
-
139
133
  declare class ConfigDiagnosticText {
140
- #private;
141
134
  static expected(element: string): string;
142
135
  static expectsListItemType(optionName: string, optionBrand: OptionBrand): string;
143
- static expectsValue(optionName: string, optionGroup: OptionGroup): string;
136
+ static expectsValue(optionName: string): string;
144
137
  static fileDoesNotExist(filePath: string): string;
145
138
  static moduleWasNotFound(specifier: string): string;
146
139
  static seen(element: string): string;
147
140
  static testFileMatchCannotStartWith(segment: string): Array<string>;
148
- static requiresValueType(optionName: string, optionBrand: OptionBrand, optionGroup: OptionGroup): string;
141
+ static requiresValueType(optionName: string, optionBrand: OptionBrand): string;
149
142
  static unknownOption(optionName: string): string;
150
- static usage(optionName: string, optionBrand: OptionBrand, optionGroup: OptionGroup): Promise<Array<string>>;
143
+ static usage(optionName: string, optionBrand: OptionBrand): Promise<Array<string>>;
151
144
  static versionIsNotSupported(value: string): string;
152
145
  static watchCannotBeEnabled(): string;
153
146
  }
@@ -285,12 +278,12 @@ declare class Config {
285
278
  static resolveConfigFilePath(filePath?: string): string;
286
279
  }
287
280
 
288
- interface ItemDefinition {
289
- brand: OptionBrand.String;
290
- name: string;
291
- pattern?: string;
281
+ declare enum OptionGroup {
282
+ CommandLine = 2,
283
+ ConfigFile = 4,
284
+ ResolvedConfig = 6
292
285
  }
293
- type OptionDefinition = PrimitiveTypeOptionDefinition | ListTypeOptionDefinition;
286
+
294
287
  interface BaseOptionDefinition {
295
288
  brand: OptionBrand;
296
289
  description: string;
@@ -300,15 +293,21 @@ interface BaseOptionDefinition {
300
293
  interface PrimitiveTypeOptionDefinition extends BaseOptionDefinition {
301
294
  brand: OptionBrand.String | OptionBrand.Number | OptionBrand.Boolean | OptionBrand.BareTrue;
302
295
  }
296
+ interface ItemDefinition {
297
+ brand: OptionBrand.String;
298
+ name: string;
299
+ pattern?: string;
300
+ }
303
301
  interface ListTypeOptionDefinition extends BaseOptionDefinition {
304
302
  brand: OptionBrand.List;
305
303
  items: ItemDefinition;
306
304
  }
305
+ type OptionDefinition = PrimitiveTypeOptionDefinition | ListTypeOptionDefinition;
307
306
  declare class Options {
308
307
  #private;
309
308
  static for(optionGroup: OptionGroup): Map<string, OptionDefinition>;
310
309
  static resolve(optionName: string, optionValue: string, rootPath?: string): string;
311
- static validate(optionDefinition: OptionDefinition | ItemDefinition, optionValue: string, optionGroup: OptionGroup, onDiagnostics: DiagnosticsHandler$1, origin?: DiagnosticOrigin): Promise<void>;
310
+ static validate(optionName: string, optionValue: string, optionBrand: OptionBrand, onDiagnostics: DiagnosticsHandler, origin?: DiagnosticOrigin): Promise<void>;
312
311
  }
313
312
 
314
313
  declare const defaultOptions: Required<ConfigFileOptions>;
@@ -339,9 +338,9 @@ interface EnvironmentOptions {
339
338
  */
340
339
  timeout: number;
341
340
  /**
342
- * The path to the currently installed TypeScript module.
341
+ * The specifier of the TypeScript module.
343
342
  */
344
- typescriptPath: string | undefined;
343
+ typescriptModule: string | undefined;
345
344
  }
346
345
 
347
346
  declare const environmentOptions: EnvironmentOptions;
@@ -553,8 +552,6 @@ declare class EventEmitter {
553
552
  removeReporters(): void;
554
553
  }
555
554
 
556
- type ArgumentNode = ts.Expression | ts.TypeNode;
557
- type DiagnosticsHandler = (diagnostics: Diagnostic | Array<Diagnostic>) => void;
558
555
  interface MatchResult {
559
556
  explain: () => Array<Diagnostic>;
560
557
  isMatch: boolean;
@@ -569,136 +566,29 @@ interface TypeChecker extends ts.TypeChecker {
569
566
  };
570
567
  }
571
568
 
572
- declare class MatchWorker {
573
- #private;
574
- assertion: Assertion;
575
- constructor(compiler: typeof ts, typeChecker: TypeChecker, assertion: Assertion);
576
- checkIsAssignableTo(sourceNode: ArgumentNode, targetNode: ArgumentNode): boolean;
577
- checkIsAssignableWith(sourceNode: ArgumentNode, targetNode: ArgumentNode): boolean;
578
- checkIsIdenticalTo(sourceNode: ArgumentNode, targetNode: ArgumentNode): boolean;
579
- checkIsSubtype(sourceNode: ArgumentNode, targetNode: ArgumentNode): boolean;
580
- extendsObjectType(type: ts.Type): boolean;
581
- getParameterType(signature: ts.Signature, index: number): ts.Type | undefined;
582
- getSignatures(node: ArgumentNode): Array<ts.Signature>;
583
- getTypeText(node: ArgumentNode): string;
584
- getType(node: ArgumentNode): ts.Type;
585
- isAnyOrNeverType(type: ts.Type): type is ts.StringLiteralType | ts.NumberLiteralType;
586
- isStringOrNumberLiteralType(type: ts.Type): type is ts.StringLiteralType | ts.NumberLiteralType;
587
- isObjectType(type: ts.Type): type is ts.ObjectType;
588
- isUnionType(type: ts.Type): type is ts.UnionType;
589
- isUniqueSymbolType(type: ts.Type): type is ts.UniqueESSymbolType;
590
- resolveDiagnosticOrigin(symbol: ts.Symbol, enclosingNode: ts.Node): DiagnosticOrigin;
591
- }
592
-
593
- declare class PrimitiveTypeMatcher {
594
- #private;
595
- constructor(targetTypeFlag: ts.TypeFlags);
596
- match(matchWorker: MatchWorker, sourceNode: ArgumentNode): MatchResult;
597
- }
598
-
599
- declare class ToAcceptProps {
600
- #private;
601
- constructor(compiler: typeof ts, typeChecker: TypeChecker);
602
- match(matchWorker: MatchWorker, sourceNode: ArgumentNode, targetNode: ArgumentNode, onDiagnostics: DiagnosticsHandler): MatchResult | undefined;
603
- }
604
-
605
- declare class ExpectDiagnosticText {
606
- static argumentOrTypeArgumentMustBeProvided(argumentNameText: string, typeArgumentNameText: string): string;
607
- static argumentMustBe(argumentNameText: string, expectedText: string): string;
608
- static argumentMustBeProvided(argumentNameText: string): string;
609
- static componentAcceptsProps(isTypeNode: boolean): string;
610
- static componentDoesNotAcceptProps(isTypeNode: boolean): string;
611
- static matcherIsDeprecated(matcherNameText: string): Array<string>;
612
- static matcherIsNotSupported(matcherNameText: string): string;
613
- static overloadGaveTheFollowingError(index: number, count: number, signatureText: string): string;
614
- static raisedTypeError(count?: number): string;
615
- static typeArgumentMustBe(argumentNameText: string, expectedText: string): string;
616
- static typeDidNotRaiseError(isTypeNode: boolean): string;
617
- static typeDidNotRaiseMatchingError(isTypeNode: boolean): string;
618
- static typeDoesNotHaveProperty(typeText: string, propertyNameText: string): string;
619
- static typeDoesMatch(sourceTypeText: string, targetTypeText: string): string;
620
- static typeDoesNotMatch(sourceTypeText: string, targetTypeText: string): string;
621
- static typeHasProperty(typeText: string, propertyNameText: string): string;
622
- static typeIs(typeText: string): string;
623
- static typeIsAssignableTo(sourceTypeText: string, targetTypeText: string): string;
624
- static typeIsAssignableWith(sourceTypeText: string, targetTypeText: string): string;
625
- static typeIsIdenticalTo(sourceTypeText: string, targetTypeText: string): string;
626
- static typeIsNotAssignableTo(sourceTypeText: string, targetTypeText: string): string;
627
- static typeIsNotAssignableWith(sourceTypeText: string, targetTypeText: string): string;
628
- static typeIsNotCompatibleWith(sourceTypeText: string, targetTypeText: string): string;
629
- static typeIsNotIdenticalTo(sourceTypeText: string, targetTypeText: string): string;
630
- static typeRaisedError(isTypeNode: boolean, count: number, targetCount: number): string;
631
- static typeRaisedMatchingError(isTypeNode: boolean): string;
632
- static typeRequiresProperty(typeText: string, propertyNameText: string): string;
633
- static typesOfPropertyAreNotCompatible(propertyNameText: string): string;
634
- }
635
-
636
- declare abstract class RelationMatcherBase {
637
- abstract explainText(sourceTypeText: string, targetTypeText: string): string;
638
- abstract explainNotText(sourceTypeText: string, targetTypeText: string): string;
639
- protected explain(matchWorker: MatchWorker, sourceNode: ArgumentNode, targetNode: ArgumentNode): Diagnostic[];
640
- abstract match(matchWorker: MatchWorker, sourceNode: ArgumentNode, targetNode: ArgumentNode): MatchResult;
641
- }
642
-
643
- declare class ToBe extends RelationMatcherBase {
644
- explainText: typeof ExpectDiagnosticText.typeIsIdenticalTo;
645
- explainNotText: typeof ExpectDiagnosticText.typeIsNotIdenticalTo;
646
- match(matchWorker: MatchWorker, sourceNode: ArgumentNode, targetNode: ArgumentNode): MatchResult;
647
- }
648
-
649
- declare class ToBeAssignableTo extends RelationMatcherBase {
650
- explainText: typeof ExpectDiagnosticText.typeIsAssignableTo;
651
- explainNotText: typeof ExpectDiagnosticText.typeIsNotAssignableTo;
652
- match(matchWorker: MatchWorker, sourceNode: ArgumentNode, targetNode: ArgumentNode): MatchResult;
653
- }
654
-
655
- declare class ToBeAssignableWith extends RelationMatcherBase {
656
- explainText: typeof ExpectDiagnosticText.typeIsAssignableWith;
657
- explainNotText: typeof ExpectDiagnosticText.typeIsNotAssignableWith;
658
- match(matchWorker: MatchWorker, sourceNode: ArgumentNode, targetNode: ArgumentNode): MatchResult;
659
- }
660
-
661
- declare class ToHaveProperty {
662
- #private;
663
- constructor(compiler: typeof ts);
664
- match(matchWorker: MatchWorker, sourceNode: ArgumentNode, targetNode: ArgumentNode, onDiagnostics: DiagnosticsHandler): MatchResult | undefined;
665
- }
666
-
667
- declare class ToMatch extends RelationMatcherBase {
668
- explainText: typeof ExpectDiagnosticText.typeDoesMatch;
669
- explainNotText: typeof ExpectDiagnosticText.typeDoesNotMatch;
670
- match(matchWorker: MatchWorker, sourceNode: ArgumentNode, targetNode: ArgumentNode): MatchResult;
671
- }
672
-
673
- declare class ToRaiseError {
674
- #private;
675
- constructor(compiler: typeof ts);
676
- match(matchWorker: MatchWorker, sourceNode: ArgumentNode, targetNodes: Array<ArgumentNode>, onDiagnostics: DiagnosticsHandler): MatchResult | undefined;
677
- }
678
-
679
569
  declare class ExpectService {
680
570
  #private;
681
- toAcceptProps: ToAcceptProps;
682
- toBe: ToBe;
683
- toBeAny: PrimitiveTypeMatcher;
684
- toBeAssignableTo: ToBeAssignableTo;
685
- toBeAssignableWith: ToBeAssignableWith;
686
- toBeBigInt: PrimitiveTypeMatcher;
687
- toBeBoolean: PrimitiveTypeMatcher;
688
- toBeNever: PrimitiveTypeMatcher;
689
- toBeNull: PrimitiveTypeMatcher;
690
- toBeNumber: PrimitiveTypeMatcher;
691
- toBeString: PrimitiveTypeMatcher;
692
- toBeSymbol: PrimitiveTypeMatcher;
693
- toBeUndefined: PrimitiveTypeMatcher;
694
- toBeUniqueSymbol: PrimitiveTypeMatcher;
695
- toBeUnknown: PrimitiveTypeMatcher;
696
- toBeVoid: PrimitiveTypeMatcher;
697
- toHaveProperty: ToHaveProperty;
698
- toMatch: ToMatch;
699
- toRaiseError: ToRaiseError;
571
+ private toAcceptProps;
572
+ private toBe;
573
+ private toBeAny;
574
+ private toBeAssignableTo;
575
+ private toBeAssignableWith;
576
+ private toBeBigInt;
577
+ private toBeBoolean;
578
+ private toBeNever;
579
+ private toBeNull;
580
+ private toBeNumber;
581
+ private toBeString;
582
+ private toBeSymbol;
583
+ private toBeUndefined;
584
+ private toBeUniqueSymbol;
585
+ private toBeUnknown;
586
+ private toBeVoid;
587
+ private toHaveProperty;
588
+ private toMatch;
589
+ private toRaiseError;
700
590
  constructor(compiler: typeof ts, typeChecker: TypeChecker);
701
- match(assertion: Assertion, onDiagnostics: DiagnosticsHandler): MatchResult | undefined;
591
+ match(assertion: Assertion, onDiagnostics: DiagnosticsHandler<Diagnostic | Array<Diagnostic>>): MatchResult | undefined;
702
592
  }
703
593
 
704
594
  declare class CancellationHandler implements EventHandler {
@@ -928,4 +818,4 @@ declare class WatchService {
928
818
  watch(cancellationToken: CancellationToken): AsyncIterable<Array<Task>>;
929
819
  }
930
820
 
931
- export { Assertion, BaseReporter, CancellationHandler, CancellationReason, CancellationToken, Cli, CollectService, Color, type CommandLineOptions, Config, ConfigDiagnosticText, type ConfigFileOptions, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, type DiagnosticsHandler$1 as DiagnosticsHandler, type EnvironmentOptions, type Event, EventEmitter, type EventHandler, ExitCodeHandler, ExpectResult, ExpectService, type FileWatchHandler, FileWatcher, type InputHandler, InputService, type ItemDefinition, Line, ListReporter, type MatchResult, OptionBrand, type OptionDefinition, OptionGroup, Options, OutputService, Path, type Plugin, PluginService, ProjectResult, ProjectService, type Reporter, type ReporterEvent, type ResolvedConfig, Result, ResultCount, ResultHandler, ResultStatus, ResultTiming, Runner, Scribbler, ScribblerJsx, type ScribblerOptions, Select, SelectDiagnosticText, SetupReporter, SourceFile, Store, SummaryReporter, TargetResult, type TargetResultStatus, Task, TaskResult, type TaskResultStatus, TestMember, TestMemberBrand, TestMemberFlags, TestResult, TestTree, Text, type TypeChecker, Version, type WatchHandler, WatchReporter, WatchService, Watcher, type WatcherOptions, addsPackageText, defaultOptions, describeNameText, diagnosticText, environmentOptions, fileViewText, formattedText, helpText, summaryText, taskStatusText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
821
+ export { Assertion, BaseReporter, CancellationHandler, CancellationReason, CancellationToken, Cli, CollectService, Color, type CommandLineOptions, Config, ConfigDiagnosticText, type ConfigFileOptions, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, type DiagnosticsHandler, type EnvironmentOptions, type Event, EventEmitter, type EventHandler, ExitCodeHandler, ExpectResult, ExpectService, type FileWatchHandler, FileWatcher, type InputHandler, InputService, type ItemDefinition, Line, ListReporter, type MatchResult, OptionBrand, type OptionDefinition, OptionGroup, Options, OutputService, Path, type Plugin, PluginService, ProjectResult, ProjectService, type Reporter, type ReporterEvent, type ResolvedConfig, Result, ResultCount, ResultHandler, ResultStatus, ResultTiming, Runner, Scribbler, ScribblerJsx, type ScribblerOptions, Select, SelectDiagnosticText, SetupReporter, SourceFile, Store, SummaryReporter, TargetResult, type TargetResultStatus, Task, TaskResult, type TaskResultStatus, TestMember, TestMemberBrand, TestMemberFlags, TestResult, TestTree, Text, type TypeChecker, Version, type WatchHandler, WatchReporter, WatchService, Watcher, type WatcherOptions, addsPackageText, defaultOptions, describeNameText, diagnosticText, environmentOptions, fileViewText, formattedText, helpText, summaryText, taskStatusText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
package/build/tstyche.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import { createRequire } from 'node:module';
3
+ import { fileURLToPath, pathToFileURL } from 'node:url';
3
4
  import vm from 'node:vm';
4
5
  import os from 'node:os';
5
6
  import process from 'node:process';
6
7
  import path from 'node:path';
7
8
  import { writeFileSync, rmSync, existsSync, watch } from 'node:fs';
8
9
  import streamConsumers from 'node:stream/consumers';
9
- import { pathToFileURL, fileURLToPath } from 'node:url';
10
10
 
11
11
  class DiagnosticOrigin {
12
12
  assertion;
@@ -154,7 +154,7 @@ class Environment {
154
154
  npmRegistry: Environment.#resolveNpmRegistry(),
155
155
  storePath: Environment.#resolveStorePath(),
156
156
  timeout: Environment.#resolveTimeout(),
157
- typescriptPath: Environment.#resolveTypeScriptPath(),
157
+ typescriptModule: Environment.#resolveTypeScriptModule(),
158
158
  };
159
159
  }
160
160
  static #resolveIsCi() {
@@ -205,18 +205,18 @@ class Environment {
205
205
  }
206
206
  return 30;
207
207
  }
208
- static #resolveTypeScriptPath() {
208
+ static #resolveTypeScriptModule() {
209
209
  let specifier = "typescript";
210
- if (process.env["TSTYCHE_TYPESCRIPT_PATH"] != null) {
211
- specifier = process.env["TSTYCHE_TYPESCRIPT_PATH"];
210
+ if (process.env["TSTYCHE_TYPESCRIPT_MODULE"] != null) {
211
+ specifier = process.env["TSTYCHE_TYPESCRIPT_MODULE"];
212
212
  }
213
- let resolvedPath;
213
+ let resolvedModule;
214
214
  try {
215
- resolvedPath = Path.normalizeSlashes(createRequire(import.meta.url).resolve(specifier));
215
+ resolvedModule = import.meta.resolve(specifier);
216
216
  }
217
217
  catch {
218
218
  }
219
- return resolvedPath;
219
+ return resolvedModule;
220
220
  }
221
221
  }
222
222
 
@@ -672,8 +672,8 @@ class Store {
672
672
  return compilerInstance;
673
673
  }
674
674
  let modulePath;
675
- if (tag === "current" && environmentOptions.typescriptPath != null) {
676
- modulePath = environmentOptions.typescriptPath;
675
+ if (tag === "current" && environmentOptions.typescriptModule != null) {
676
+ modulePath = fileURLToPath(environmentOptions.typescriptModule);
677
677
  }
678
678
  else {
679
679
  await Store.open();
@@ -741,7 +741,7 @@ class Store {
741
741
  }
742
742
  static async validateTag(tag) {
743
743
  if (tag === "current") {
744
- return environmentOptions.typescriptPath != null;
744
+ return environmentOptions.typescriptModule != null;
745
745
  }
746
746
  await Store.open();
747
747
  if (Store.#manifest?.isOutdated({ ageTolerance: 60 }) &&
@@ -764,8 +764,7 @@ class ConfigDiagnosticText {
764
764
  static expectsListItemType(optionName, optionBrand) {
765
765
  return `Item of the '${optionName}' list must be of type ${optionBrand}.`;
766
766
  }
767
- static expectsValue(optionName, optionGroup) {
768
- optionName = ConfigDiagnosticText.#optionName(optionName, optionGroup);
767
+ static expectsValue(optionName) {
769
768
  return `Option '${optionName}' expects a value.`;
770
769
  }
771
770
  static fileDoesNotExist(filePath) {
@@ -774,9 +773,6 @@ class ConfigDiagnosticText {
774
773
  static moduleWasNotFound(specifier) {
775
774
  return `The specified module '${specifier}' was not found.`;
776
775
  }
777
- static #optionName(optionName, optionGroup) {
778
- return optionGroup === 2 ? `--${optionName}` : optionName;
779
- }
780
776
  static seen(element) {
781
777
  return `The ${element} was seen here.`;
782
778
  }
@@ -786,39 +782,34 @@ class ConfigDiagnosticText {
786
782
  "The test files are only collected within the 'rootPath' directory.",
787
783
  ];
788
784
  }
789
- static requiresValueType(optionName, optionBrand, optionGroup) {
790
- const optionNameText = ConfigDiagnosticText.#optionName(optionName, optionGroup);
791
- return `Option '${optionNameText}' requires a value of type ${optionBrand}.`;
785
+ static requiresValueType(optionName, optionBrand) {
786
+ return `Option '${optionName}' requires a value of type ${optionBrand}.`;
792
787
  }
793
788
  static unknownOption(optionName) {
794
789
  return `Unknown option '${optionName}'.`;
795
790
  }
796
- static async usage(optionName, optionBrand, optionGroup) {
797
- const text = [];
798
- switch (optionName) {
791
+ static async usage(optionName, optionBrand) {
792
+ switch (optionName.startsWith("--") ? optionName.slice(2) : optionName) {
799
793
  case "target": {
800
- switch (optionGroup) {
801
- case 2:
802
- text.push("Value for the '--target' option must be a single tag or a comma separated list.", "Usage examples: '--target 4.9', '--target latest', '--target 4.9,5.3.2,current'.");
803
- break;
804
- case 4:
805
- text.push("Item of the 'target' list must be a supported version tag.");
806
- break;
794
+ const text = [];
795
+ if (optionName.startsWith("--")) {
796
+ text.push("Value for the '--target' option must be a single tag or a comma separated list.", "Usage examples: '--target 4.9', '--target latest', '--target 4.9,5.3.2,current'.");
797
+ }
798
+ else {
799
+ text.push("Item of the 'target' list must be a supported version tag.");
807
800
  }
808
801
  const supportedTags = await Store.getSupportedTags();
809
802
  if (supportedTags != null) {
810
803
  text.push(`Supported tags: ${["'", supportedTags.join("', '"), "'"].join("")}.`);
811
804
  }
812
- break;
805
+ return text;
813
806
  }
814
- default:
815
- text.push(ConfigDiagnosticText.requiresValueType(optionName, optionBrand, optionGroup));
816
807
  }
817
- return text;
808
+ return [ConfigDiagnosticText.requiresValueType(optionName, optionBrand)];
818
809
  }
819
810
  static versionIsNotSupported(value) {
820
811
  if (value === "current") {
821
- return "Cannot use 'current' as a target. Failed to resolve the path to the currently installed TypeScript module.";
812
+ return "Cannot use 'current' as a target. Failed to resolve the installed TypeScript module.";
822
813
  }
823
814
  return `TypeScript version '${value}' is not supported.`;
824
815
  }
@@ -970,54 +961,74 @@ class Options {
970
961
  }
971
962
  return definitionMap;
972
963
  }
964
+ static #getCanonicalOptionName(optionName) {
965
+ return optionName.startsWith("--") ? optionName.slice(2) : optionName;
966
+ }
967
+ static #isBuiltinReporter(optionValue) {
968
+ return ["list", "summary"].includes(optionValue);
969
+ }
970
+ static #isLookupStrategy(optionValue) {
971
+ return ["findup", "ignore"].includes(optionValue);
972
+ }
973
973
  static resolve(optionName, optionValue, rootPath = ".") {
974
- switch (optionName) {
974
+ const canonicalOptionName = Options.#getCanonicalOptionName(optionName);
975
+ switch (canonicalOptionName) {
976
+ case "config":
977
+ case "rootPath":
975
978
  case "tsconfig":
976
- if (["findup", "ignore"].includes(optionValue)) {
979
+ if (canonicalOptionName === "tsconfig" && Options.#isLookupStrategy(optionValue)) {
977
980
  break;
978
981
  }
979
- case "config":
980
- case "rootPath":
981
982
  optionValue = Path.resolve(rootPath, optionValue);
982
983
  break;
983
984
  case "plugins":
984
985
  case "reporters":
985
- if (optionValue.startsWith(".")) {
986
- optionValue = pathToFileURL(Path.join(Path.relative(".", rootPath), optionValue)).toString();
986
+ if (canonicalOptionName === "reporters" && Options.#isBuiltinReporter(optionValue)) {
987
+ break;
988
+ }
989
+ try {
990
+ if (optionValue.startsWith(".")) {
991
+ optionValue = pathToFileURL(Path.relative(".", Path.resolve(rootPath, optionValue))).toString();
992
+ }
993
+ else {
994
+ optionValue = import.meta.resolve(optionValue);
995
+ }
996
+ }
997
+ catch {
987
998
  }
988
999
  break;
989
1000
  }
990
1001
  return optionValue;
991
1002
  }
992
- static async validate(optionDefinition, optionValue, optionGroup, onDiagnostics, origin) {
993
- switch (optionDefinition.name) {
1003
+ static async validate(optionName, optionValue, optionBrand, onDiagnostics, origin) {
1004
+ const canonicalOptionName = Options.#getCanonicalOptionName(optionName);
1005
+ switch (canonicalOptionName) {
1006
+ case "config":
1007
+ case "rootPath":
994
1008
  case "tsconfig":
995
- if (["findup", "ignore"].includes(optionValue)) {
1009
+ if (canonicalOptionName === "tsconfig" && Options.#isLookupStrategy(optionValue)) {
996
1010
  break;
997
1011
  }
998
- case "config":
999
- case "rootPath":
1000
- if (!existsSync(optionValue)) {
1001
- onDiagnostics(Diagnostic.error(ConfigDiagnosticText.fileDoesNotExist(optionValue), origin));
1012
+ if (existsSync(optionValue)) {
1013
+ break;
1002
1014
  }
1015
+ onDiagnostics(Diagnostic.error(ConfigDiagnosticText.fileDoesNotExist(optionValue), origin));
1003
1016
  break;
1017
+ case "plugins":
1004
1018
  case "reporters":
1005
- if (["list", "summary"].includes(optionValue)) {
1019
+ if (canonicalOptionName === "reporters" && Options.#isBuiltinReporter(optionValue)) {
1006
1020
  break;
1007
1021
  }
1008
- case "plugins":
1009
- try {
1010
- await import(optionValue);
1011
- }
1012
- catch {
1013
- onDiagnostics(Diagnostic.error(ConfigDiagnosticText.moduleWasNotFound(optionValue), origin));
1022
+ if (optionValue.startsWith("file:") && existsSync(new URL(optionValue))) {
1023
+ break;
1014
1024
  }
1025
+ onDiagnostics(Diagnostic.error(ConfigDiagnosticText.moduleWasNotFound(optionValue), origin));
1015
1026
  break;
1016
1027
  case "target":
1017
1028
  if ((await Store.validateTag(optionValue)) === false) {
1018
1029
  onDiagnostics(Diagnostic.error([
1019
1030
  ConfigDiagnosticText.versionIsNotSupported(optionValue),
1020
- await ConfigDiagnosticText.usage(optionDefinition.name, optionDefinition.brand, optionGroup),
1031
+ await ConfigDiagnosticText.usage(optionName, optionBrand),
1021
1032
  ].flat(), origin));
1022
1033
  }
1023
1034
  break;
@@ -1048,10 +1059,10 @@ class CommandLineParser {
1048
1059
  this.#onDiagnostics = onDiagnostics;
1049
1060
  this.#options = Options.for(2);
1050
1061
  }
1051
- async #onExpectsValue(optionDefinition) {
1062
+ async #onExpectsValue(optionName, optionBrand) {
1052
1063
  const text = [
1053
- ConfigDiagnosticText.expectsValue(optionDefinition.name, 2),
1054
- await ConfigDiagnosticText.usage(optionDefinition.name, optionDefinition.brand, 2),
1064
+ ConfigDiagnosticText.expectsValue(optionName),
1065
+ await ConfigDiagnosticText.usage(optionName, optionBrand),
1055
1066
  ].flat();
1056
1067
  this.#onDiagnostics(Diagnostic.error(text));
1057
1068
  }
@@ -1061,10 +1072,9 @@ class CommandLineParser {
1061
1072
  while (arg != null) {
1062
1073
  index++;
1063
1074
  if (arg.startsWith("--")) {
1064
- const optionName = arg.slice(2);
1065
- const optionDefinition = this.#options.get(optionName);
1075
+ const optionDefinition = this.#options.get(arg.slice(2));
1066
1076
  if (optionDefinition) {
1067
- index = await this.#parseOptionValue(commandLineArgs, index, optionDefinition);
1077
+ index = await this.#parseOptionValue(commandLineArgs, index, arg, optionDefinition);
1068
1078
  }
1069
1079
  else {
1070
1080
  this.#onDiagnostics(Diagnostic.error(ConfigDiagnosticText.unknownOption(arg)));
@@ -1079,15 +1089,15 @@ class CommandLineParser {
1079
1089
  arg = commandLineArgs[index];
1080
1090
  }
1081
1091
  }
1082
- async #parseOptionValue(commandLineArgs, index, optionDefinition) {
1092
+ async #parseOptionValue(commandLineArgs, index, optionName, optionDefinition) {
1083
1093
  let optionValue = this.#resolveOptionValue(commandLineArgs[index]);
1084
1094
  switch (optionDefinition.brand) {
1085
1095
  case "bareTrue":
1086
- await Options.validate(optionDefinition, optionValue, 2, this.#onDiagnostics);
1096
+ await Options.validate(optionName, optionValue, optionDefinition.brand, this.#onDiagnostics);
1087
1097
  this.#commandLineOptions[optionDefinition.name] = true;
1088
1098
  break;
1089
1099
  case "boolean":
1090
- await Options.validate(optionDefinition, optionValue, 2, this.#onDiagnostics);
1100
+ await Options.validate(optionName, optionValue, optionDefinition.brand, this.#onDiagnostics);
1091
1101
  this.#commandLineOptions[optionDefinition.name] = optionValue !== "false";
1092
1102
  if (optionValue === "false" || optionValue === "true") {
1093
1103
  index++;
@@ -1099,25 +1109,25 @@ class CommandLineParser {
1099
1109
  .split(",")
1100
1110
  .map((value) => value.trim())
1101
1111
  .filter((value) => value !== "")
1102
- .map((value) => Options.resolve(optionDefinition.name, value));
1112
+ .map((value) => Options.resolve(optionName, value));
1103
1113
  for (const optionValue of optionValues) {
1104
- await Options.validate(optionDefinition, optionValue, 2, this.#onDiagnostics);
1114
+ await Options.validate(optionName, optionValue, optionDefinition.brand, this.#onDiagnostics);
1105
1115
  }
1106
1116
  this.#commandLineOptions[optionDefinition.name] = optionValues;
1107
1117
  index++;
1108
1118
  break;
1109
1119
  }
1110
- await this.#onExpectsValue(optionDefinition);
1120
+ await this.#onExpectsValue(optionName, optionDefinition.brand);
1111
1121
  break;
1112
1122
  case "string":
1113
1123
  if (optionValue !== "") {
1114
- optionValue = Options.resolve(optionDefinition.name, optionValue);
1115
- await Options.validate(optionDefinition, optionValue, 2, this.#onDiagnostics);
1124
+ optionValue = Options.resolve(optionName, optionValue);
1125
+ await Options.validate(optionName, optionValue, optionDefinition.brand, this.#onDiagnostics);
1116
1126
  this.#commandLineOptions[optionDefinition.name] = optionValue;
1117
1127
  index++;
1118
1128
  break;
1119
1129
  }
1120
- await this.#onExpectsValue(optionDefinition);
1130
+ await this.#onExpectsValue(optionName, optionDefinition.brand);
1121
1131
  break;
1122
1132
  }
1123
1133
  return index;
@@ -1271,7 +1281,7 @@ class ConfigFileParser {
1271
1281
  #onRequiresValue(optionDefinition, jsonNode, isListItem) {
1272
1282
  const text = isListItem
1273
1283
  ? ConfigDiagnosticText.expectsListItemType(optionDefinition.name, optionDefinition.brand)
1274
- : ConfigDiagnosticText.requiresValueType(optionDefinition.name, optionDefinition.brand, 4);
1284
+ : ConfigDiagnosticText.requiresValueType(optionDefinition.name, optionDefinition.brand);
1275
1285
  this.#onDiagnostics(Diagnostic.error(text, jsonNode.origin));
1276
1286
  }
1277
1287
  async #parseValue(optionDefinition, isListItem = false) {
@@ -1296,7 +1306,7 @@ class ConfigFileParser {
1296
1306
  }
1297
1307
  const rootPath = Path.dirname(this.#sourceFile.fileName);
1298
1308
  optionValue = Options.resolve(optionDefinition.name, optionValue, rootPath);
1299
- await Options.validate(optionDefinition, optionValue, 4, this.#onDiagnostics, jsonNode.origin);
1309
+ await Options.validate(optionDefinition.name, optionValue, optionDefinition.brand, this.#onDiagnostics, jsonNode.origin);
1300
1310
  break;
1301
1311
  }
1302
1312
  case "list": {
@@ -1400,14 +1410,14 @@ const defaultOptions = {
1400
1410
  plugins: [],
1401
1411
  reporters: ["list", "summary"],
1402
1412
  rootPath: Path.resolve("./"),
1403
- target: environmentOptions.typescriptPath != null ? ["current"] : ["latest"],
1413
+ target: environmentOptions.typescriptModule != null ? ["current"] : ["latest"],
1404
1414
  testFileMatch: ["**/*.tst.*", "**/__typetests__/*.test.*", "**/typetests/*.test.*"],
1405
1415
  tsconfig: "findup",
1406
1416
  };
1407
1417
 
1408
1418
  class Config {
1409
- static #onDiagnostics(diagnostics) {
1410
- EventEmitter.dispatch(["config:error", { diagnostics: [diagnostics] }]);
1419
+ static #onDiagnostics(diagnostic) {
1420
+ EventEmitter.dispatch(["config:error", { diagnostics: [diagnostic] }]);
1411
1421
  }
1412
1422
  static async parseCommandLine(commandLine) {
1413
1423
  const commandLineOptions = {};
@@ -3282,7 +3292,9 @@ class MatchWorker {
3282
3292
  }
3283
3293
  checkIsIdenticalTo(sourceNode, targetNode) {
3284
3294
  const relation = this.#typeChecker.relation.identity;
3285
- return this.#checkIsRelatedTo(sourceNode, targetNode, relation);
3295
+ return (this.#checkIsRelatedTo(sourceNode, targetNode, relation) &&
3296
+ this.checkIsAssignableTo(sourceNode, targetNode) &&
3297
+ this.checkIsAssignableWith(sourceNode, targetNode));
3286
3298
  }
3287
3299
  checkIsSubtype(sourceNode, targetNode) {
3288
3300
  const relation = this.#typeChecker.relation.subtype;
@@ -3723,8 +3735,10 @@ class ToRaiseError {
3723
3735
  match(matchWorker, sourceNode, targetNodes, onDiagnostics) {
3724
3736
  const diagnostics = [];
3725
3737
  for (const targetNode of targetNodes) {
3726
- if (!(this.#compiler.isStringLiteralLike(targetNode) || this.#compiler.isNumericLiteral(targetNode))) {
3727
- const expectedText = "a string or number literal";
3738
+ if (!(this.#compiler.isStringLiteralLike(targetNode) ||
3739
+ this.#compiler.isNumericLiteral(targetNode) ||
3740
+ this.#compiler.isRegularExpressionLiteral(targetNode))) {
3741
+ const expectedText = "a string, number or regular expression literal";
3728
3742
  const text = ExpectDiagnosticText.argumentMustBe("target", expectedText);
3729
3743
  const origin = DiagnosticOrigin.fromNode(targetNode);
3730
3744
  diagnostics.push(Diagnostic.error(text, origin));
@@ -3749,6 +3763,10 @@ class ToRaiseError {
3749
3763
  };
3750
3764
  }
3751
3765
  #matchExpectedError(diagnostic, targetNode) {
3766
+ if (this.#compiler.isRegularExpressionLiteral(targetNode)) {
3767
+ const targetRegex = new RegExp(...targetNode.text.slice(1).split("/"));
3768
+ return targetRegex.test(this.#compiler.flattenDiagnosticMessageText(diagnostic.messageText, " ", 0));
3769
+ }
3752
3770
  if (this.#compiler.isStringLiteralLike(targetNode)) {
3753
3771
  return this.#compiler.flattenDiagnosticMessageText(diagnostic.messageText, " ", 0).includes(targetNode.text);
3754
3772
  }
@@ -4097,7 +4115,7 @@ class TaskRunner {
4097
4115
  class Runner {
4098
4116
  #eventEmitter = new EventEmitter();
4099
4117
  #resolvedConfig;
4100
- static version = "3.0.0-beta.6";
4118
+ static version = "3.0.0-rc.1";
4101
4119
  constructor(resolvedConfig) {
4102
4120
  this.#resolvedConfig = resolvedConfig;
4103
4121
  }
@@ -4221,8 +4239,8 @@ class Cli {
4221
4239
  }
4222
4240
  continue;
4223
4241
  }
4224
- for (const pluginIdentifier of resolvedConfig.plugins) {
4225
- const plugin = (await import(pluginIdentifier)).default;
4242
+ for (const pluginSpecifier of resolvedConfig.plugins) {
4243
+ const plugin = (await import(pluginSpecifier)).default;
4226
4244
  PluginService.addHandler(plugin);
4227
4245
  }
4228
4246
  resolvedConfig = await PluginService.call("config", resolvedConfig, {});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tstyche",
3
- "version": "3.0.0-beta.6",
3
+ "version": "3.0.0-rc.1",
4
4
  "description": "The Essential Type Testing Tool.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -63,14 +63,14 @@
63
63
  "devDependencies": {
64
64
  "@biomejs/biome": "1.9.4",
65
65
  "@rollup/plugin-typescript": "12.1.1",
66
- "@types/node": "20.17.1",
66
+ "@types/node": "22.8.5",
67
67
  "@types/react": "18.3.12",
68
68
  "ajv": "8.17.1",
69
- "cspell": "8.15.4",
69
+ "cspell": "8.15.5",
70
70
  "magic-string": "0.30.12",
71
71
  "monocart-coverage-reports": "2.11.1",
72
72
  "pretty-ansi": "2.0.0",
73
- "rollup": "4.24.2",
73
+ "rollup": "4.24.3",
74
74
  "rollup-plugin-dts": "6.1.1",
75
75
  "tslib": "2.8.0",
76
76
  "typescript": "5.6.3"
@@ -85,6 +85,6 @@
85
85
  },
86
86
  "packageManager": "yarn@4.5.1",
87
87
  "engines": {
88
- "node": ">=18.17"
88
+ "node": ">=18.19"
89
89
  }
90
90
  }