tstyche 4.0.0-beta.7 → 4.0.0-beta.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/tstyche.d.ts +79 -66
- package/build/tstyche.js +348 -296
- package/package.json +6 -6
package/build/tstyche.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ import type ts from 'typescript';
|
|
|
3
3
|
declare enum CancellationReason {
|
|
4
4
|
ConfigChange = "configChange",
|
|
5
5
|
ConfigError = "configError",
|
|
6
|
-
CollectError = "collectError",
|
|
7
6
|
FailFast = "failFast",
|
|
8
7
|
WatchClose = "watchClose"
|
|
9
8
|
}
|
|
@@ -21,58 +20,6 @@ declare class Cli {
|
|
|
21
20
|
run(commandLine: Array<string>, cancellationToken?: CancellationToken): Promise<void>;
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
declare enum DiagnosticCategory {
|
|
25
|
-
Error = "error",
|
|
26
|
-
Warning = "warning"
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
declare class SourceFile {
|
|
30
|
-
#private;
|
|
31
|
-
fileName: string;
|
|
32
|
-
text: string;
|
|
33
|
-
constructor(fileName: string, text: string);
|
|
34
|
-
getLineStarts(): Array<number>;
|
|
35
|
-
getLineAndCharacterOfPosition(position: number): {
|
|
36
|
-
line: number;
|
|
37
|
-
character: number;
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
declare class DiagnosticOrigin {
|
|
42
|
-
assertion: AssertionNode | undefined;
|
|
43
|
-
end: number;
|
|
44
|
-
sourceFile: SourceFile | ts.SourceFile;
|
|
45
|
-
start: number;
|
|
46
|
-
constructor(start: number, end: number, sourceFile: SourceFile | ts.SourceFile, assertion?: AssertionNode);
|
|
47
|
-
static fromAssertion(assertion: AssertionNode): DiagnosticOrigin;
|
|
48
|
-
static fromNode(node: ts.Node, assertion?: AssertionNode): DiagnosticOrigin;
|
|
49
|
-
static fromNodes(nodes: ts.NodeArray<ts.Node>, assertion?: AssertionNode): DiagnosticOrigin;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
declare class Diagnostic {
|
|
53
|
-
category: DiagnosticCategory;
|
|
54
|
-
code: string | undefined;
|
|
55
|
-
origin: DiagnosticOrigin | undefined;
|
|
56
|
-
related: Array<Diagnostic> | undefined;
|
|
57
|
-
text: string | Array<string>;
|
|
58
|
-
constructor(text: string | Array<string>, category: DiagnosticCategory, origin?: DiagnosticOrigin);
|
|
59
|
-
add(options: {
|
|
60
|
-
code?: string | undefined;
|
|
61
|
-
related?: Array<Diagnostic> | undefined;
|
|
62
|
-
}): this;
|
|
63
|
-
static error(text: string | Array<string>, origin?: DiagnosticOrigin): Diagnostic;
|
|
64
|
-
extendWith(text: string | Array<string>, origin?: DiagnosticOrigin): Diagnostic;
|
|
65
|
-
static fromDiagnostics(diagnostics: Array<ts.Diagnostic>): Array<Diagnostic>;
|
|
66
|
-
static warning(text: string | Array<string>, origin?: DiagnosticOrigin): Diagnostic;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
declare function diagnosticBelongsToNode(diagnostic: ts.Diagnostic, node: ts.NodeArray<ts.Node> | ts.Node): boolean;
|
|
70
|
-
declare function getDiagnosticMessageText(diagnostic: ts.Diagnostic): string | Array<string>;
|
|
71
|
-
declare function getTextSpanEnd(span: ts.TextSpan): number;
|
|
72
|
-
declare function isDiagnosticWithLocation(diagnostic: ts.Diagnostic): diagnostic is ts.DiagnosticWithLocation;
|
|
73
|
-
|
|
74
|
-
type DiagnosticsHandler<T extends Diagnostic | Array<Diagnostic> = Diagnostic> = (this: void, diagnostics: T) => void;
|
|
75
|
-
|
|
76
23
|
declare enum TestTreeNodeBrand {
|
|
77
24
|
Describe = "describe",
|
|
78
25
|
Test = "test",
|
|
@@ -88,21 +35,27 @@ declare enum TestTreeNodeFlags {
|
|
|
88
35
|
Todo = 8
|
|
89
36
|
}
|
|
90
37
|
|
|
38
|
+
declare class WhenNode extends TestTreeNode {
|
|
39
|
+
actionNode: ts.CallExpression;
|
|
40
|
+
actionNameNode: ts.PropertyAccessExpression;
|
|
41
|
+
abilityDiagnostics: Set<ts.Diagnostic> | undefined;
|
|
42
|
+
target: ts.NodeArray<ts.Expression> | ts.NodeArray<ts.TypeNode>;
|
|
43
|
+
constructor(compiler: typeof ts, brand: TestTreeNodeBrand, node: ts.CallExpression, parent: TestTree | TestTreeNode, flags: TestTreeNodeFlags, actionNode: ts.CallExpression, actionNameNode: ts.PropertyAccessExpression);
|
|
44
|
+
}
|
|
45
|
+
|
|
91
46
|
declare class TestTreeNode {
|
|
92
|
-
#private;
|
|
93
47
|
brand: TestTreeNodeBrand;
|
|
94
|
-
children: Array<TestTreeNode | AssertionNode>;
|
|
48
|
+
children: Array<TestTreeNode | AssertionNode | WhenNode>;
|
|
95
49
|
diagnostics: Set<ts.Diagnostic>;
|
|
96
50
|
flags: TestTreeNodeFlags;
|
|
97
51
|
name: string;
|
|
98
52
|
node: ts.CallExpression;
|
|
99
53
|
parent: TestTree | TestTreeNode;
|
|
100
54
|
constructor(compiler: typeof ts, brand: TestTreeNodeBrand, node: ts.CallExpression, parent: TestTree | TestTreeNode, flags: TestTreeNodeFlags);
|
|
101
|
-
validate(): Array<Diagnostic>;
|
|
102
55
|
}
|
|
103
56
|
|
|
104
57
|
declare class TestTree {
|
|
105
|
-
children: Array<TestTreeNode | AssertionNode>;
|
|
58
|
+
children: Array<TestTreeNode | AssertionNode | WhenNode>;
|
|
106
59
|
diagnostics: Set<ts.Diagnostic>;
|
|
107
60
|
hasOnly: boolean;
|
|
108
61
|
sourceFile: ts.SourceFile;
|
|
@@ -296,6 +249,58 @@ declare class Config {
|
|
|
296
249
|
static resolveConfigFilePath(filePath?: string): string;
|
|
297
250
|
}
|
|
298
251
|
|
|
252
|
+
declare enum DiagnosticCategory {
|
|
253
|
+
Error = "error",
|
|
254
|
+
Warning = "warning"
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
declare class SourceFile {
|
|
258
|
+
#private;
|
|
259
|
+
fileName: string;
|
|
260
|
+
text: string;
|
|
261
|
+
constructor(fileName: string, text: string);
|
|
262
|
+
getLineStarts(): Array<number>;
|
|
263
|
+
getLineAndCharacterOfPosition(position: number): {
|
|
264
|
+
line: number;
|
|
265
|
+
character: number;
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
declare class DiagnosticOrigin {
|
|
270
|
+
assertion: AssertionNode | undefined;
|
|
271
|
+
end: number;
|
|
272
|
+
sourceFile: SourceFile | ts.SourceFile;
|
|
273
|
+
start: number;
|
|
274
|
+
constructor(start: number, end: number, sourceFile: SourceFile | ts.SourceFile, assertion?: AssertionNode);
|
|
275
|
+
static fromAssertion(assertion: AssertionNode): DiagnosticOrigin;
|
|
276
|
+
static fromNode(node: ts.Node, assertion?: AssertionNode): DiagnosticOrigin;
|
|
277
|
+
static fromNodes(nodes: ts.NodeArray<ts.Node>, assertion?: AssertionNode): DiagnosticOrigin;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
declare class Diagnostic {
|
|
281
|
+
category: DiagnosticCategory;
|
|
282
|
+
code: string | undefined;
|
|
283
|
+
origin: DiagnosticOrigin | undefined;
|
|
284
|
+
related: Array<Diagnostic> | undefined;
|
|
285
|
+
text: string | Array<string>;
|
|
286
|
+
constructor(text: string | Array<string>, category: DiagnosticCategory, origin?: DiagnosticOrigin);
|
|
287
|
+
add(options: {
|
|
288
|
+
code?: string | undefined;
|
|
289
|
+
related?: Array<Diagnostic> | undefined;
|
|
290
|
+
}): this;
|
|
291
|
+
static error(text: string | Array<string>, origin?: DiagnosticOrigin): Diagnostic;
|
|
292
|
+
extendWith(text: string | Array<string>, origin?: DiagnosticOrigin): Diagnostic;
|
|
293
|
+
static fromDiagnostics(diagnostics: Array<ts.Diagnostic>): Array<Diagnostic>;
|
|
294
|
+
static warning(text: string | Array<string>, origin?: DiagnosticOrigin): Diagnostic;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
declare function diagnosticBelongsToNode(diagnostic: ts.Diagnostic, node: ts.NodeArray<ts.Node> | ts.Node): boolean;
|
|
298
|
+
declare function getDiagnosticMessageText(diagnostic: ts.Diagnostic): string | Array<string>;
|
|
299
|
+
declare function getTextSpanEnd(span: ts.TextSpan): number;
|
|
300
|
+
declare function isDiagnosticWithLocation(diagnostic: ts.Diagnostic): diagnostic is ts.DiagnosticWithLocation;
|
|
301
|
+
|
|
302
|
+
type DiagnosticsHandler<T extends Diagnostic | Array<Diagnostic> = Diagnostic> = (this: void, diagnostics: T) => void;
|
|
303
|
+
|
|
299
304
|
declare enum OptionGroup {
|
|
300
305
|
CommandLine = 2,
|
|
301
306
|
ConfigFile = 4,
|
|
@@ -346,13 +351,9 @@ declare class CollectService {
|
|
|
346
351
|
|
|
347
352
|
declare function nodeBelongsToArgumentList(compiler: typeof ts, node: ts.Node): boolean;
|
|
348
353
|
|
|
349
|
-
declare
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
abilityDiagnostics: Set<ts.Diagnostic> | undefined;
|
|
353
|
-
target: ts.NodeArray<ts.Expression> | ts.NodeArray<ts.TypeNode>;
|
|
354
|
-
constructor(compiler: typeof ts, brand: TestTreeNodeBrand, node: ts.CallExpression, parent: TestTree | TestTreeNode, flags: TestTreeNodeFlags, actionNode: ts.CallExpression, actionNameNode: ts.PropertyAccessExpression);
|
|
355
|
-
}
|
|
354
|
+
declare function argumentIsProvided<T>(argumentNameText: string, node: T, enclosingNode: ts.Node, onDiagnostics: DiagnosticsHandler<Array<Diagnostic>>): node is NonNullable<T>;
|
|
355
|
+
|
|
356
|
+
declare function argumentOrTypeArgumentIsProvided<T>(argumentNameText: string, typeArgumentNameText: string, node: T, enclosingNode: ts.Node, onDiagnostics: DiagnosticsHandler<Array<Diagnostic>>): node is NonNullable<T>;
|
|
356
357
|
|
|
357
358
|
interface EnvironmentOptions {
|
|
358
359
|
/**
|
|
@@ -599,6 +600,12 @@ declare class EventEmitter {
|
|
|
599
600
|
removeReporters(): void;
|
|
600
601
|
}
|
|
601
602
|
|
|
603
|
+
declare class Reject {
|
|
604
|
+
#private;
|
|
605
|
+
constructor(compiler: typeof ts, typeChecker: ts.TypeChecker, resolvedConfig: ResolvedConfig);
|
|
606
|
+
argumentType(target: Array<[name: string, node: ts.Expression | ts.TypeNode | undefined]>, onDiagnostics: DiagnosticsHandler<Array<Diagnostic>>): boolean;
|
|
607
|
+
}
|
|
608
|
+
|
|
602
609
|
interface MatchResult {
|
|
603
610
|
explain: () => Array<Diagnostic>;
|
|
604
611
|
isMatch: boolean;
|
|
@@ -624,7 +631,7 @@ declare class ExpectService {
|
|
|
624
631
|
private toBeConstructableWith;
|
|
625
632
|
private toHaveProperty;
|
|
626
633
|
private toRaiseError;
|
|
627
|
-
constructor(compiler: typeof ts, typeChecker: TypeChecker,
|
|
634
|
+
constructor(compiler: typeof ts, typeChecker: TypeChecker, reject: Reject);
|
|
628
635
|
match(assertion: AssertionNode, onDiagnostics: DiagnosticsHandler<Diagnostic | Array<Diagnostic>>): MatchResult | undefined;
|
|
629
636
|
}
|
|
630
637
|
|
|
@@ -878,5 +885,11 @@ declare class WatchService {
|
|
|
878
885
|
watch(cancellationToken: CancellationToken): AsyncIterable<Array<Task>>;
|
|
879
886
|
}
|
|
880
887
|
|
|
881
|
-
|
|
888
|
+
declare class WhenService {
|
|
889
|
+
#private;
|
|
890
|
+
constructor(reject: Reject, onDiagnostics: DiagnosticsHandler<Array<Diagnostic>>);
|
|
891
|
+
action(when: WhenNode): void;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
export { AssertionNode, BaseReporter, CancellationHandler, CancellationReason, CancellationToken, Cli, CollectService, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, EventEmitter, ExitCodeHandler, ExpectResult, ExpectService, FileWatcher, InputService, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, PluginService, ProjectResult, ProjectService, Reject, Result, ResultCount, ResultHandler, ResultStatus, ResultTiming, Runner, Scribbler, ScribblerJsx, Select, SelectDiagnosticText, SetupReporter, SourceFile, Store, SummaryReporter, TargetResult, Task, TaskResult, TestResult, TestTree, TestTreeNode, TestTreeNodeBrand, TestTreeNodeFlags, Text, Version, WatchReporter, WatchService, Watcher, WhenNode, WhenService, addsPackageText, argumentIsProvided, argumentOrTypeArgumentIsProvided, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, environmentOptions, fileViewText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, nodeBelongsToArgumentList, summaryText, taskStatusText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
|
|
882
895
|
export type { CodeFrameOptions, CommandLineOptions, ConfigFileOptions, DiagnosticsHandler, EnvironmentOptions, Event, EventHandler, FileWatchHandler, InputHandler, ItemDefinition, MatchResult, OptionDefinition, Plugin, Reporter, ReporterEvent, ResolvedConfig, ScribblerOptions, SelectHookContext, TargetResultStatus, TaskResultStatus, TypeChecker, WatchHandler, WatcherOptions };
|
package/build/tstyche.js
CHANGED
|
@@ -572,7 +572,6 @@ class ManifestService {
|
|
|
572
572
|
#manifestFilePath;
|
|
573
573
|
#npmRegistry;
|
|
574
574
|
#storePath;
|
|
575
|
-
#supportedVersionRegex = /^(5)\.\d\.\d$/;
|
|
576
575
|
constructor(storePath, npmRegistry, fetcher) {
|
|
577
576
|
this.#storePath = storePath;
|
|
578
577
|
this.#npmRegistry = npmRegistry;
|
|
@@ -602,7 +601,7 @@ class ManifestService {
|
|
|
602
601
|
const versions = [];
|
|
603
602
|
const packageMetadata = (await response.json());
|
|
604
603
|
for (const [tag, meta] of Object.entries(packageMetadata.versions)) {
|
|
605
|
-
if (
|
|
604
|
+
if (!tag.includes("-") && Version.isSatisfiedWith(tag, "4.7.2")) {
|
|
606
605
|
versions.push(tag);
|
|
607
606
|
packages[tag] = { integrity: meta.dist.integrity, tarball: meta.dist.tarball };
|
|
608
607
|
}
|
|
@@ -701,6 +700,9 @@ class PackageService {
|
|
|
701
700
|
if (response?.body != null) {
|
|
702
701
|
const targetPath = `${packagePath}-${Math.random().toString(32).slice(2)}`;
|
|
703
702
|
for await (const file of TarReader.extract(response.body)) {
|
|
703
|
+
if (!file.name.startsWith("package/")) {
|
|
704
|
+
continue;
|
|
705
|
+
}
|
|
704
706
|
const filePath = Path.join(targetPath, file.name.replace("package/", ""));
|
|
705
707
|
const directoryPath = Path.dirname(filePath);
|
|
706
708
|
if (!existsSync(directoryPath)) {
|
|
@@ -2547,7 +2549,6 @@ var CancellationReason;
|
|
|
2547
2549
|
(function (CancellationReason) {
|
|
2548
2550
|
CancellationReason["ConfigChange"] = "configChange";
|
|
2549
2551
|
CancellationReason["ConfigError"] = "configError";
|
|
2550
|
-
CancellationReason["CollectError"] = "collectError";
|
|
2551
2552
|
CancellationReason["FailFast"] = "failFast";
|
|
2552
2553
|
CancellationReason["WatchClose"] = "watchClose";
|
|
2553
2554
|
})(CancellationReason || (CancellationReason = {}));
|
|
@@ -2873,18 +2874,9 @@ class WatchService {
|
|
|
2873
2874
|
}
|
|
2874
2875
|
}
|
|
2875
2876
|
|
|
2876
|
-
var TestTreeNodeBrand;
|
|
2877
|
-
(function (TestTreeNodeBrand) {
|
|
2878
|
-
TestTreeNodeBrand["Describe"] = "describe";
|
|
2879
|
-
TestTreeNodeBrand["Test"] = "test";
|
|
2880
|
-
TestTreeNodeBrand["Expect"] = "expect";
|
|
2881
|
-
TestTreeNodeBrand["When"] = "when";
|
|
2882
|
-
})(TestTreeNodeBrand || (TestTreeNodeBrand = {}));
|
|
2883
|
-
|
|
2884
2877
|
class TestTreeNode {
|
|
2885
2878
|
brand;
|
|
2886
2879
|
children = [];
|
|
2887
|
-
#compiler;
|
|
2888
2880
|
diagnostics = new Set();
|
|
2889
2881
|
flags;
|
|
2890
2882
|
name = "";
|
|
@@ -2892,7 +2884,6 @@ class TestTreeNode {
|
|
|
2892
2884
|
parent;
|
|
2893
2885
|
constructor(compiler, brand, node, parent, flags) {
|
|
2894
2886
|
this.brand = brand;
|
|
2895
|
-
this.#compiler = compiler;
|
|
2896
2887
|
this.node = node;
|
|
2897
2888
|
this.parent = parent;
|
|
2898
2889
|
this.flags = flags;
|
|
@@ -2908,34 +2899,6 @@ class TestTreeNode {
|
|
|
2908
2899
|
}
|
|
2909
2900
|
}
|
|
2910
2901
|
}
|
|
2911
|
-
validate() {
|
|
2912
|
-
const diagnostics = [];
|
|
2913
|
-
const getText = (node) => `'${node.expression.getText()}()' cannot be nested within '${this.node.expression.getText()}()'.`;
|
|
2914
|
-
const getParentCallExpression = (node) => {
|
|
2915
|
-
while (!this.#compiler.isCallExpression(node.parent)) {
|
|
2916
|
-
node = node.parent;
|
|
2917
|
-
}
|
|
2918
|
-
return node.parent;
|
|
2919
|
-
};
|
|
2920
|
-
switch (this.brand) {
|
|
2921
|
-
case TestTreeNodeBrand.Describe:
|
|
2922
|
-
for (const child of this.children) {
|
|
2923
|
-
if (child.brand === TestTreeNodeBrand.Expect || child.brand === TestTreeNodeBrand.When) {
|
|
2924
|
-
diagnostics.push(Diagnostic.error(getText(child.node), DiagnosticOrigin.fromNode(getParentCallExpression(child.node))));
|
|
2925
|
-
}
|
|
2926
|
-
}
|
|
2927
|
-
break;
|
|
2928
|
-
case TestTreeNodeBrand.Test:
|
|
2929
|
-
case TestTreeNodeBrand.Expect:
|
|
2930
|
-
for (const child of this.children) {
|
|
2931
|
-
if (child.brand === TestTreeNodeBrand.Describe || child.brand === TestTreeNodeBrand.Test) {
|
|
2932
|
-
diagnostics.push(Diagnostic.error(getText(child.node), DiagnosticOrigin.fromNode(child.node)));
|
|
2933
|
-
}
|
|
2934
|
-
}
|
|
2935
|
-
break;
|
|
2936
|
-
}
|
|
2937
|
-
return diagnostics;
|
|
2938
|
-
}
|
|
2939
2902
|
}
|
|
2940
2903
|
|
|
2941
2904
|
class AssertionNode extends TestTreeNode {
|
|
@@ -3033,6 +2996,11 @@ class AbilityLayer {
|
|
|
3033
2996
|
this.#nodes = [];
|
|
3034
2997
|
this.#text = "";
|
|
3035
2998
|
}
|
|
2999
|
+
#eraseTrailingComma(node, parent) {
|
|
3000
|
+
if (node.hasTrailingComma) {
|
|
3001
|
+
this.#addRanges(parent, [{ start: node.end - 1, end: node.end }]);
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3036
3004
|
handleWhen(whenNode) {
|
|
3037
3005
|
const whenStart = whenNode.node.getStart();
|
|
3038
3006
|
const whenExpressionEnd = whenNode.node.expression.getEnd();
|
|
@@ -3040,13 +3008,14 @@ class AbilityLayer {
|
|
|
3040
3008
|
const actionNameEnd = whenNode.actionNameNode.getEnd();
|
|
3041
3009
|
switch (whenNode.actionNameNode.name.text) {
|
|
3042
3010
|
case "isCalledWith":
|
|
3011
|
+
this.#eraseTrailingComma(whenNode.target, whenNode);
|
|
3043
3012
|
this.#addRanges(whenNode, [
|
|
3044
3013
|
{
|
|
3045
|
-
end: whenExpressionEnd,
|
|
3046
3014
|
start: whenStart,
|
|
3015
|
+
end: whenExpressionEnd,
|
|
3047
3016
|
replacement: nodeBelongsToArgumentList(this.#compiler, whenNode.actionNode) ? "" : ";",
|
|
3048
3017
|
},
|
|
3049
|
-
{
|
|
3018
|
+
{ start: whenEnd, end: actionNameEnd },
|
|
3050
3019
|
]);
|
|
3051
3020
|
break;
|
|
3052
3021
|
}
|
|
@@ -3059,28 +3028,30 @@ class AbilityLayer {
|
|
|
3059
3028
|
switch (assertionNode.matcherNameNode.name.text) {
|
|
3060
3029
|
case "toBeApplicable":
|
|
3061
3030
|
this.#addRanges(assertionNode, [
|
|
3062
|
-
{
|
|
3063
|
-
{
|
|
3031
|
+
{ start: expectStart, end: expectExpressionEnd },
|
|
3032
|
+
{ start: expectEnd, end: matcherNameEnd },
|
|
3064
3033
|
]);
|
|
3065
3034
|
break;
|
|
3066
3035
|
case "toBeCallableWith":
|
|
3036
|
+
this.#eraseTrailingComma(assertionNode.source, assertionNode);
|
|
3067
3037
|
this.#addRanges(assertionNode, [
|
|
3068
3038
|
{
|
|
3069
|
-
end: expectExpressionEnd,
|
|
3070
3039
|
start: expectStart,
|
|
3040
|
+
end: expectExpressionEnd,
|
|
3071
3041
|
replacement: nodeBelongsToArgumentList(this.#compiler, assertionNode.matcherNode) ? "" : ";",
|
|
3072
3042
|
},
|
|
3073
|
-
{
|
|
3043
|
+
{ start: expectEnd, end: matcherNameEnd },
|
|
3074
3044
|
]);
|
|
3075
3045
|
break;
|
|
3076
3046
|
case "toBeConstructableWith":
|
|
3047
|
+
this.#eraseTrailingComma(assertionNode.source, assertionNode);
|
|
3077
3048
|
this.#addRanges(assertionNode, [
|
|
3078
3049
|
{
|
|
3079
|
-
end: expectExpressionEnd,
|
|
3080
3050
|
start: expectStart,
|
|
3051
|
+
end: expectExpressionEnd,
|
|
3081
3052
|
replacement: nodeBelongsToArgumentList(this.#compiler, assertionNode.matcherNode) ? "new" : "; new",
|
|
3082
3053
|
},
|
|
3083
|
-
{
|
|
3054
|
+
{ start: expectEnd, end: matcherNameEnd },
|
|
3084
3055
|
]);
|
|
3085
3056
|
break;
|
|
3086
3057
|
}
|
|
@@ -3097,6 +3068,14 @@ class CollectDiagnosticText {
|
|
|
3097
3068
|
}
|
|
3098
3069
|
}
|
|
3099
3070
|
|
|
3071
|
+
var TestTreeNodeBrand;
|
|
3072
|
+
(function (TestTreeNodeBrand) {
|
|
3073
|
+
TestTreeNodeBrand["Describe"] = "describe";
|
|
3074
|
+
TestTreeNodeBrand["Test"] = "test";
|
|
3075
|
+
TestTreeNodeBrand["Expect"] = "expect";
|
|
3076
|
+
TestTreeNodeBrand["When"] = "when";
|
|
3077
|
+
})(TestTreeNodeBrand || (TestTreeNodeBrand = {}));
|
|
3078
|
+
|
|
3100
3079
|
var TestTreeNodeFlags;
|
|
3101
3080
|
(function (TestTreeNodeFlags) {
|
|
3102
3081
|
TestTreeNodeFlags[TestTreeNodeFlags["None"] = 0] = "None";
|
|
@@ -3110,19 +3089,8 @@ class IdentifierLookup {
|
|
|
3110
3089
|
#compiler;
|
|
3111
3090
|
#identifiers;
|
|
3112
3091
|
#moduleSpecifiers = ['"tstyche"', "'tstyche'"];
|
|
3113
|
-
constructor(compiler
|
|
3092
|
+
constructor(compiler) {
|
|
3114
3093
|
this.#compiler = compiler;
|
|
3115
|
-
this.#identifiers = identifiers ?? {
|
|
3116
|
-
namedImports: {
|
|
3117
|
-
describe: undefined,
|
|
3118
|
-
expect: undefined,
|
|
3119
|
-
it: undefined,
|
|
3120
|
-
namespace: undefined,
|
|
3121
|
-
test: undefined,
|
|
3122
|
-
when: undefined,
|
|
3123
|
-
},
|
|
3124
|
-
namespace: undefined,
|
|
3125
|
-
};
|
|
3126
3094
|
}
|
|
3127
3095
|
handleImportDeclaration(node) {
|
|
3128
3096
|
if (this.#moduleSpecifiers.includes(node.moduleSpecifier.getText()) &&
|
|
@@ -3150,7 +3118,20 @@ class IdentifierLookup {
|
|
|
3150
3118
|
}
|
|
3151
3119
|
}
|
|
3152
3120
|
}
|
|
3153
|
-
|
|
3121
|
+
open() {
|
|
3122
|
+
this.#identifiers = {
|
|
3123
|
+
namedImports: {
|
|
3124
|
+
describe: undefined,
|
|
3125
|
+
expect: undefined,
|
|
3126
|
+
it: undefined,
|
|
3127
|
+
namespace: undefined,
|
|
3128
|
+
test: undefined,
|
|
3129
|
+
when: undefined,
|
|
3130
|
+
},
|
|
3131
|
+
namespace: undefined,
|
|
3132
|
+
};
|
|
3133
|
+
}
|
|
3134
|
+
resolveTestTreeNodeMeta(node) {
|
|
3154
3135
|
let flags = TestTreeNodeFlags.None;
|
|
3155
3136
|
let expression = node.expression;
|
|
3156
3137
|
while (this.#compiler.isPropertyAccessExpression(expression)) {
|
|
@@ -3173,27 +3154,27 @@ class IdentifierLookup {
|
|
|
3173
3154
|
}
|
|
3174
3155
|
expression = expression.expression;
|
|
3175
3156
|
}
|
|
3176
|
-
let
|
|
3157
|
+
let identifier;
|
|
3177
3158
|
if (this.#compiler.isPropertyAccessExpression(expression) &&
|
|
3178
3159
|
expression.expression.getText() === this.#identifiers.namespace) {
|
|
3179
|
-
|
|
3160
|
+
identifier = expression.name.getText();
|
|
3180
3161
|
}
|
|
3181
3162
|
else {
|
|
3182
|
-
|
|
3163
|
+
identifier = Object.keys(this.#identifiers.namedImports).find((key) => this.#identifiers.namedImports[key] === expression.getText());
|
|
3183
3164
|
}
|
|
3184
|
-
if (!
|
|
3165
|
+
if (!identifier) {
|
|
3185
3166
|
return;
|
|
3186
3167
|
}
|
|
3187
|
-
switch (
|
|
3168
|
+
switch (identifier) {
|
|
3188
3169
|
case "describe":
|
|
3189
|
-
return { brand: TestTreeNodeBrand.Describe, flags };
|
|
3170
|
+
return { brand: TestTreeNodeBrand.Describe, flags, identifier };
|
|
3190
3171
|
case "it":
|
|
3191
3172
|
case "test":
|
|
3192
|
-
return { brand: TestTreeNodeBrand.Test, flags };
|
|
3173
|
+
return { brand: TestTreeNodeBrand.Test, flags, identifier };
|
|
3193
3174
|
case "expect":
|
|
3194
|
-
return { brand: TestTreeNodeBrand.Expect, flags };
|
|
3175
|
+
return { brand: TestTreeNodeBrand.Expect, flags, identifier };
|
|
3195
3176
|
case "when":
|
|
3196
|
-
return { brand: TestTreeNodeBrand.When, flags };
|
|
3177
|
+
return { brand: TestTreeNodeBrand.When, flags, identifier };
|
|
3197
3178
|
}
|
|
3198
3179
|
return;
|
|
3199
3180
|
}
|
|
@@ -3232,92 +3213,119 @@ class WhenNode extends TestTreeNode {
|
|
|
3232
3213
|
class CollectService {
|
|
3233
3214
|
#abilityLayer;
|
|
3234
3215
|
#compiler;
|
|
3235
|
-
#
|
|
3236
|
-
#resolvedConfig;
|
|
3237
|
-
#testTree;
|
|
3216
|
+
#identifierLookup;
|
|
3238
3217
|
constructor(compiler, projectService, resolvedConfig) {
|
|
3239
3218
|
this.#compiler = compiler;
|
|
3240
|
-
this.#
|
|
3241
|
-
this.#
|
|
3242
|
-
this.#abilityLayer = new AbilityLayer(compiler, this.#projectService, this.#resolvedConfig);
|
|
3219
|
+
this.#abilityLayer = new AbilityLayer(compiler, projectService, resolvedConfig);
|
|
3220
|
+
this.#identifierLookup = new IdentifierLookup(compiler);
|
|
3243
3221
|
}
|
|
3244
|
-
#collectTestTreeNodes(node,
|
|
3222
|
+
#collectTestTreeNodes(node, parent, testTree) {
|
|
3245
3223
|
if (this.#compiler.isCallExpression(node)) {
|
|
3246
|
-
const meta =
|
|
3247
|
-
if (meta != null
|
|
3248
|
-
|
|
3249
|
-
this.#compiler.forEachChild(node, (node) => {
|
|
3250
|
-
this.#collectTestTreeNodes(node, identifiers, testTreeNode);
|
|
3251
|
-
});
|
|
3252
|
-
this.#onNode(testTreeNode, parent);
|
|
3253
|
-
return;
|
|
3254
|
-
}
|
|
3255
|
-
if (meta != null && meta.brand === TestTreeNodeBrand.Expect) {
|
|
3256
|
-
const modifierNode = this.#getChainedNode(node, "type");
|
|
3257
|
-
if (!modifierNode) {
|
|
3224
|
+
const meta = this.#identifierLookup.resolveTestTreeNodeMeta(node);
|
|
3225
|
+
if (meta != null) {
|
|
3226
|
+
if (!this.#checkNode(node, meta, parent)) {
|
|
3258
3227
|
return;
|
|
3259
3228
|
}
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
if (!matcherNode) {
|
|
3229
|
+
if (meta.brand === TestTreeNodeBrand.Describe || meta.brand === TestTreeNodeBrand.Test) {
|
|
3230
|
+
const testTreeNode = new TestTreeNode(this.#compiler, meta.brand, node, parent, meta.flags);
|
|
3231
|
+
this.#compiler.forEachChild(node, (node) => {
|
|
3232
|
+
this.#collectTestTreeNodes(node, testTreeNode, testTree);
|
|
3233
|
+
});
|
|
3234
|
+
this.#onNode(testTreeNode, parent, testTree);
|
|
3267
3235
|
return;
|
|
3268
3236
|
}
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3237
|
+
if (meta.brand === TestTreeNodeBrand.Expect) {
|
|
3238
|
+
const modifierNode = this.#getChainedNode(node, "type");
|
|
3239
|
+
if (!modifierNode) {
|
|
3240
|
+
return;
|
|
3241
|
+
}
|
|
3242
|
+
const notNode = this.#getChainedNode(modifierNode, "not");
|
|
3243
|
+
const matcherNameNode = this.#getChainedNode(notNode ?? modifierNode);
|
|
3244
|
+
if (!matcherNameNode) {
|
|
3245
|
+
return;
|
|
3246
|
+
}
|
|
3247
|
+
const matcherNode = this.#getMatcherNode(matcherNameNode);
|
|
3248
|
+
if (!matcherNode) {
|
|
3249
|
+
return;
|
|
3250
|
+
}
|
|
3251
|
+
const assertionNode = new AssertionNode(this.#compiler, meta.brand, node, parent, meta.flags, matcherNode, matcherNameNode, modifierNode, notNode);
|
|
3252
|
+
this.#abilityLayer.handleAssertion(assertionNode);
|
|
3253
|
+
this.#compiler.forEachChild(node, (node) => {
|
|
3254
|
+
this.#collectTestTreeNodes(node, assertionNode, testTree);
|
|
3255
|
+
});
|
|
3256
|
+
this.#onNode(assertionNode, parent, testTree);
|
|
3280
3257
|
return;
|
|
3281
3258
|
}
|
|
3282
|
-
|
|
3283
|
-
|
|
3259
|
+
if (meta.brand === TestTreeNodeBrand.When) {
|
|
3260
|
+
const actionNameNode = this.#getChainedNode(node);
|
|
3261
|
+
if (!actionNameNode) {
|
|
3262
|
+
return;
|
|
3263
|
+
}
|
|
3264
|
+
const actionNode = this.#getActionNode(actionNameNode);
|
|
3265
|
+
if (!actionNode) {
|
|
3266
|
+
return;
|
|
3267
|
+
}
|
|
3268
|
+
this.#compiler.forEachChild(actionNode, (node) => {
|
|
3269
|
+
if (this.#compiler.isCallExpression(node)) {
|
|
3270
|
+
const meta = this.#identifierLookup.resolveTestTreeNodeMeta(node);
|
|
3271
|
+
if (meta?.brand === TestTreeNodeBrand.Describe || meta?.brand === TestTreeNodeBrand.Test) {
|
|
3272
|
+
const text = CollectDiagnosticText.cannotBeNestedWithin(meta.identifier, "when");
|
|
3273
|
+
const origin = DiagnosticOrigin.fromNode(node);
|
|
3274
|
+
this.#onDiagnostics(Diagnostic.error(text, origin));
|
|
3275
|
+
}
|
|
3276
|
+
}
|
|
3277
|
+
});
|
|
3278
|
+
const whenNode = new WhenNode(this.#compiler, meta.brand, node, parent, meta.flags, actionNode, actionNameNode);
|
|
3279
|
+
this.#abilityLayer.handleWhen(whenNode);
|
|
3280
|
+
this.#onNode(whenNode, parent, testTree);
|
|
3284
3281
|
return;
|
|
3285
3282
|
}
|
|
3286
|
-
this.#compiler.forEachChild(actionNode, (node) => {
|
|
3287
|
-
if (this.#compiler.isCallExpression(node)) {
|
|
3288
|
-
const meta = identifiers.resolveTestMemberMeta(node);
|
|
3289
|
-
if (meta != null && (meta.brand === TestTreeNodeBrand.Describe || meta.brand === TestTreeNodeBrand.Test)) {
|
|
3290
|
-
const text = CollectDiagnosticText.cannotBeNestedWithin(node.expression.getText(), "when");
|
|
3291
|
-
const origin = DiagnosticOrigin.fromNode(node);
|
|
3292
|
-
this.#onDiagnostics(Diagnostic.error(text, origin));
|
|
3293
|
-
}
|
|
3294
|
-
}
|
|
3295
|
-
});
|
|
3296
|
-
const whenNode = new WhenNode(this.#compiler, meta.brand, node, parent, meta.flags, actionNode, actionNameNode);
|
|
3297
|
-
this.#abilityLayer.handleWhen(whenNode);
|
|
3298
|
-
this.#onNode(whenNode, parent);
|
|
3299
|
-
return;
|
|
3300
3283
|
}
|
|
3301
3284
|
}
|
|
3302
3285
|
if (this.#compiler.isImportDeclaration(node)) {
|
|
3303
|
-
|
|
3286
|
+
this.#identifierLookup.handleImportDeclaration(node);
|
|
3304
3287
|
return;
|
|
3305
3288
|
}
|
|
3306
3289
|
this.#compiler.forEachChild(node, (node) => {
|
|
3307
|
-
this.#collectTestTreeNodes(node,
|
|
3290
|
+
this.#collectTestTreeNodes(node, parent, testTree);
|
|
3308
3291
|
});
|
|
3309
3292
|
}
|
|
3310
3293
|
createTestTree(sourceFile, semanticDiagnostics = []) {
|
|
3311
3294
|
const testTree = new TestTree(new Set(semanticDiagnostics), sourceFile);
|
|
3312
3295
|
EventEmitter.dispatch(["collect:start", { tree: testTree }]);
|
|
3313
|
-
this.#testTree = testTree;
|
|
3314
3296
|
this.#abilityLayer.open(sourceFile);
|
|
3315
|
-
this.#
|
|
3297
|
+
this.#identifierLookup.open();
|
|
3298
|
+
this.#collectTestTreeNodes(sourceFile, testTree, testTree);
|
|
3316
3299
|
this.#abilityLayer.close();
|
|
3317
|
-
this.#testTree = undefined;
|
|
3318
3300
|
EventEmitter.dispatch(["collect:end", { tree: testTree }]);
|
|
3319
3301
|
return testTree;
|
|
3320
3302
|
}
|
|
3303
|
+
#checkNode(node, meta, parent) {
|
|
3304
|
+
if ("brand" in parent && !this.#isNodeAllowed(meta, parent)) {
|
|
3305
|
+
const text = CollectDiagnosticText.cannotBeNestedWithin(meta.identifier, parent.node.expression.getText());
|
|
3306
|
+
const origin = DiagnosticOrigin.fromNode(node);
|
|
3307
|
+
this.#onDiagnostics(Diagnostic.error(text, origin));
|
|
3308
|
+
return false;
|
|
3309
|
+
}
|
|
3310
|
+
return true;
|
|
3311
|
+
}
|
|
3312
|
+
#isNodeAllowed(meta, parent) {
|
|
3313
|
+
switch (meta.brand) {
|
|
3314
|
+
case TestTreeNodeBrand.Describe:
|
|
3315
|
+
case TestTreeNodeBrand.Test:
|
|
3316
|
+
if (parent.brand === TestTreeNodeBrand.Test || parent.brand === TestTreeNodeBrand.Expect) {
|
|
3317
|
+
return false;
|
|
3318
|
+
}
|
|
3319
|
+
break;
|
|
3320
|
+
case TestTreeNodeBrand.Expect:
|
|
3321
|
+
case TestTreeNodeBrand.When:
|
|
3322
|
+
if (parent.brand === TestTreeNodeBrand.Describe) {
|
|
3323
|
+
return false;
|
|
3324
|
+
}
|
|
3325
|
+
break;
|
|
3326
|
+
}
|
|
3327
|
+
return true;
|
|
3328
|
+
}
|
|
3321
3329
|
#getChainedNode({ parent }, name) {
|
|
3322
3330
|
if (!this.#compiler.isPropertyAccessExpression(parent)) {
|
|
3323
3331
|
return;
|
|
@@ -3348,10 +3356,10 @@ class CollectService {
|
|
|
3348
3356
|
#onDiagnostics(diagnostic) {
|
|
3349
3357
|
EventEmitter.dispatch(["collect:error", { diagnostics: [diagnostic] }]);
|
|
3350
3358
|
}
|
|
3351
|
-
#onNode(node, parent) {
|
|
3359
|
+
#onNode(node, parent, testTree) {
|
|
3352
3360
|
parent.children.push(node);
|
|
3353
3361
|
if (node.flags & TestTreeNodeFlags.Only) {
|
|
3354
|
-
|
|
3362
|
+
testTree.hasOnly = true;
|
|
3355
3363
|
}
|
|
3356
3364
|
EventEmitter.dispatch(["collect:node", { node }]);
|
|
3357
3365
|
}
|
|
@@ -3362,6 +3370,7 @@ class ProjectService {
|
|
|
3362
3370
|
#lastSeenProject = "";
|
|
3363
3371
|
#resolvedConfig;
|
|
3364
3372
|
#seenPrograms = new WeakSet();
|
|
3373
|
+
#seenTestFiles = new Set();
|
|
3365
3374
|
#service;
|
|
3366
3375
|
constructor(compiler, resolvedConfig) {
|
|
3367
3376
|
this.#compiler = compiler;
|
|
@@ -3399,15 +3408,6 @@ class ProjectService {
|
|
|
3399
3408
|
useInferredProjectPerProjectRoot: true,
|
|
3400
3409
|
useSingleInferredProject: false,
|
|
3401
3410
|
});
|
|
3402
|
-
switch (this.#resolvedConfig.tsconfig) {
|
|
3403
|
-
case "findup":
|
|
3404
|
-
break;
|
|
3405
|
-
case "ignore":
|
|
3406
|
-
this.#service.getConfigFileNameForFile = () => undefined;
|
|
3407
|
-
break;
|
|
3408
|
-
default:
|
|
3409
|
-
this.#service.getConfigFileNameForFile = () => this.#resolvedConfig.tsconfig;
|
|
3410
|
-
}
|
|
3411
3411
|
this.#service.setCompilerOptionsForInferredProjects(this.#getDefaultCompilerOptions());
|
|
3412
3412
|
}
|
|
3413
3413
|
closeFile(filePath) {
|
|
@@ -3415,7 +3415,6 @@ class ProjectService {
|
|
|
3415
3415
|
}
|
|
3416
3416
|
#getDefaultCompilerOptions() {
|
|
3417
3417
|
const defaultCompilerOptions = {
|
|
3418
|
-
allowImportingTsExtensions: true,
|
|
3419
3418
|
allowJs: true,
|
|
3420
3419
|
checkJs: true,
|
|
3421
3420
|
exactOptionalPropertyTypes: true,
|
|
@@ -3426,8 +3425,11 @@ class ProjectService {
|
|
|
3426
3425
|
resolveJsonModule: true,
|
|
3427
3426
|
strict: true,
|
|
3428
3427
|
target: this.#compiler.ScriptTarget.ESNext,
|
|
3429
|
-
verbatimModuleSyntax: true,
|
|
3430
3428
|
};
|
|
3429
|
+
if (Version.isSatisfiedWith(this.#compiler.version, "5.0")) {
|
|
3430
|
+
defaultCompilerOptions.allowImportingTsExtensions = true;
|
|
3431
|
+
defaultCompilerOptions.verbatimModuleSyntax = true;
|
|
3432
|
+
}
|
|
3431
3433
|
return defaultCompilerOptions;
|
|
3432
3434
|
}
|
|
3433
3435
|
getDefaultProject(filePath) {
|
|
@@ -3442,7 +3444,23 @@ class ProjectService {
|
|
|
3442
3444
|
const project = this.getDefaultProject(filePath);
|
|
3443
3445
|
return project?.getLanguageService(true);
|
|
3444
3446
|
}
|
|
3447
|
+
#isFileIncluded(filePath) {
|
|
3448
|
+
const configSourceFile = this.#compiler.readJsonConfigFile(this.#resolvedConfig.tsconfig, this.#compiler.sys.readFile);
|
|
3449
|
+
const { fileNames } = this.#compiler.parseJsonSourceFileConfigFileContent(configSourceFile, this.#compiler.sys, Path.dirname(this.#resolvedConfig.tsconfig), undefined, this.#resolvedConfig.tsconfig);
|
|
3450
|
+
return fileNames.includes(filePath);
|
|
3451
|
+
}
|
|
3445
3452
|
openFile(filePath, sourceText, projectRootPath) {
|
|
3453
|
+
switch (this.#resolvedConfig.tsconfig) {
|
|
3454
|
+
case "findup":
|
|
3455
|
+
break;
|
|
3456
|
+
case "ignore":
|
|
3457
|
+
this.#service.getConfigFileNameForFile = () => undefined;
|
|
3458
|
+
break;
|
|
3459
|
+
default:
|
|
3460
|
+
this.#service.getConfigFileNameForFile = this.#isFileIncluded(filePath)
|
|
3461
|
+
? () => this.#resolvedConfig.tsconfig
|
|
3462
|
+
: () => undefined;
|
|
3463
|
+
}
|
|
3446
3464
|
const { configFileErrors, configFileName } = this.#service.openClientFile(filePath, sourceText, undefined, projectRootPath);
|
|
3447
3465
|
if (configFileName !== this.#lastSeenProject) {
|
|
3448
3466
|
this.#lastSeenProject = configFileName;
|
|
@@ -3457,29 +3475,29 @@ class ProjectService {
|
|
|
3457
3475
|
{ diagnostics: Diagnostic.fromDiagnostics(configFileErrors) },
|
|
3458
3476
|
]);
|
|
3459
3477
|
}
|
|
3460
|
-
if (this.#resolvedConfig.checkSourceFiles && !
|
|
3478
|
+
if (this.#resolvedConfig.checkSourceFiles && !this.#seenTestFiles.has(filePath)) {
|
|
3479
|
+
this.#seenTestFiles.add(filePath);
|
|
3461
3480
|
const languageService = this.getLanguageService(filePath);
|
|
3462
3481
|
const program = languageService?.getProgram();
|
|
3463
3482
|
if (!program || this.#seenPrograms.has(program)) {
|
|
3464
3483
|
return;
|
|
3465
3484
|
}
|
|
3466
3485
|
this.#seenPrograms.add(program);
|
|
3467
|
-
const
|
|
3468
|
-
for (const sourceFile of program.getSourceFiles()) {
|
|
3486
|
+
const sourceFilesToCheck = program.getSourceFiles().filter((sourceFile) => {
|
|
3469
3487
|
if (program.isSourceFileFromExternalLibrary(sourceFile) || program.isSourceFileDefaultLibrary(sourceFile)) {
|
|
3470
|
-
|
|
3488
|
+
return false;
|
|
3471
3489
|
}
|
|
3472
|
-
if (
|
|
3473
|
-
|
|
3490
|
+
if (Select.isTestFile(sourceFile.fileName, { ...this.#resolvedConfig, pathMatch: [] })) {
|
|
3491
|
+
return false;
|
|
3474
3492
|
}
|
|
3475
|
-
|
|
3493
|
+
return true;
|
|
3494
|
+
});
|
|
3476
3495
|
const diagnostics = [];
|
|
3477
|
-
for (const sourceFile of
|
|
3496
|
+
for (const sourceFile of sourceFilesToCheck) {
|
|
3478
3497
|
diagnostics.push(...program.getSyntacticDiagnostics(sourceFile), ...program.getSemanticDiagnostics(sourceFile));
|
|
3479
3498
|
}
|
|
3480
3499
|
if (diagnostics.length > 0) {
|
|
3481
3500
|
EventEmitter.dispatch(["project:error", { diagnostics: Diagnostic.fromDiagnostics(diagnostics) }]);
|
|
3482
|
-
return;
|
|
3483
3501
|
}
|
|
3484
3502
|
}
|
|
3485
3503
|
}
|
|
@@ -3494,22 +3512,41 @@ var RunMode;
|
|
|
3494
3512
|
RunMode[RunMode["Todo"] = 8] = "Todo";
|
|
3495
3513
|
})(RunMode || (RunMode = {}));
|
|
3496
3514
|
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
}
|
|
3500
|
-
|
|
3501
|
-
class ExpectDiagnosticText {
|
|
3502
|
-
static argumentCannotBeOfType(argumentNameText, typeText) {
|
|
3503
|
-
return `An argument for '${argumentNameText}' cannot be of the '${typeText}' type.`;
|
|
3515
|
+
class EnsureDiagnosticText {
|
|
3516
|
+
static argumentMustBeProvided(argumentNameText) {
|
|
3517
|
+
return `An argument for '${argumentNameText}' must be provided.`;
|
|
3504
3518
|
}
|
|
3505
3519
|
static argumentOrTypeArgumentMustBeProvided(argumentNameText, typeArgumentNameText) {
|
|
3506
3520
|
return `An argument for '${argumentNameText}' or type argument for '${typeArgumentNameText}' must be provided.`;
|
|
3507
3521
|
}
|
|
3522
|
+
}
|
|
3523
|
+
|
|
3524
|
+
function argumentIsProvided(argumentNameText, node, enclosingNode, onDiagnostics) {
|
|
3525
|
+
if (!node) {
|
|
3526
|
+
const text = EnsureDiagnosticText.argumentMustBeProvided(argumentNameText);
|
|
3527
|
+
const origin = DiagnosticOrigin.fromNode(enclosingNode);
|
|
3528
|
+
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
3529
|
+
return false;
|
|
3530
|
+
}
|
|
3531
|
+
return true;
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
function argumentOrTypeArgumentIsProvided(argumentNameText, typeArgumentNameText, node, enclosingNode, onDiagnostics) {
|
|
3535
|
+
if (!node) {
|
|
3536
|
+
const text = EnsureDiagnosticText.argumentOrTypeArgumentMustBeProvided(argumentNameText, typeArgumentNameText);
|
|
3537
|
+
const origin = DiagnosticOrigin.fromNode(enclosingNode);
|
|
3538
|
+
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
3539
|
+
return false;
|
|
3540
|
+
}
|
|
3541
|
+
return true;
|
|
3542
|
+
}
|
|
3543
|
+
|
|
3544
|
+
class ExpectDiagnosticText {
|
|
3508
3545
|
static argumentMustBe(argumentNameText, expectedText) {
|
|
3509
3546
|
return `An argument for '${argumentNameText}' must be ${expectedText}.`;
|
|
3510
3547
|
}
|
|
3511
|
-
static
|
|
3512
|
-
return `
|
|
3548
|
+
static typeArgumentMustBe(argumentNameText, expectedText) {
|
|
3549
|
+
return `A type argument for '${argumentNameText}' must be ${expectedText}.`;
|
|
3513
3550
|
}
|
|
3514
3551
|
static isCallable(isExpression, targetText) {
|
|
3515
3552
|
return `${isExpression ? "Expression" : "Type"} is callable ${targetText}.`;
|
|
@@ -3535,12 +3572,12 @@ class ExpectDiagnosticText {
|
|
|
3535
3572
|
static cannotBeApplied(targetText) {
|
|
3536
3573
|
return `The decorator function cannot be applied${targetText}.`;
|
|
3537
3574
|
}
|
|
3538
|
-
static doesNotHaveProperty(typeText, propertyNameText) {
|
|
3539
|
-
return `Type '${typeText}' does not have property '${propertyNameText}'.`;
|
|
3540
|
-
}
|
|
3541
3575
|
static hasProperty(typeText, propertyNameText) {
|
|
3542
3576
|
return `Type '${typeText}' has property '${propertyNameText}'.`;
|
|
3543
3577
|
}
|
|
3578
|
+
static doesNotHaveProperty(typeText, propertyNameText) {
|
|
3579
|
+
return `Type '${typeText}' does not have property '${propertyNameText}'.`;
|
|
3580
|
+
}
|
|
3544
3581
|
static didYouMeanToUse(suggestionText) {
|
|
3545
3582
|
return `Did you mean to use ${suggestionText}?`;
|
|
3546
3583
|
}
|
|
@@ -3553,12 +3590,6 @@ class ExpectDiagnosticText {
|
|
|
3553
3590
|
static raisedTypeError(count = 1) {
|
|
3554
3591
|
return `The raised type error${count === 1 ? "" : "s"}:`;
|
|
3555
3592
|
}
|
|
3556
|
-
static typeArgumentCannotBeOfType(argumentNameText, typeText) {
|
|
3557
|
-
return `A type argument for '${argumentNameText}' cannot be of the '${typeText}' type.`;
|
|
3558
|
-
}
|
|
3559
|
-
static typeArgumentMustBe(argumentNameText, expectedText) {
|
|
3560
|
-
return `A type argument for '${argumentNameText}' must be ${expectedText}.`;
|
|
3561
|
-
}
|
|
3562
3593
|
static raisedError(isExpression, count, targetCount) {
|
|
3563
3594
|
let countText = "a";
|
|
3564
3595
|
if (count > 1 || targetCount > 1) {
|
|
@@ -3602,13 +3633,6 @@ class ExpectDiagnosticText {
|
|
|
3602
3633
|
static typesOfPropertyAreNotCompatible(propertyNameText) {
|
|
3603
3634
|
return `Types of property '${propertyNameText}' are not compatible.`;
|
|
3604
3635
|
}
|
|
3605
|
-
static typeWasRejected(typeText) {
|
|
3606
|
-
const optionNameText = `reject${capitalize(typeText)}Type`;
|
|
3607
|
-
return [
|
|
3608
|
-
`The '${typeText}' type was rejected because the '${optionNameText}' option is enabled.`,
|
|
3609
|
-
`If this check is necessary, pass '${typeText}' as the type argument explicitly.`,
|
|
3610
|
-
];
|
|
3611
|
-
}
|
|
3612
3636
|
}
|
|
3613
3637
|
|
|
3614
3638
|
class MatchWorker {
|
|
@@ -4317,7 +4341,7 @@ class ToRaiseError {
|
|
|
4317
4341
|
|
|
4318
4342
|
class ExpectService {
|
|
4319
4343
|
#compiler;
|
|
4320
|
-
#
|
|
4344
|
+
#reject;
|
|
4321
4345
|
#typeChecker;
|
|
4322
4346
|
toAcceptProps;
|
|
4323
4347
|
toBe;
|
|
@@ -4328,15 +4352,10 @@ class ExpectService {
|
|
|
4328
4352
|
toBeConstructableWith;
|
|
4329
4353
|
toHaveProperty;
|
|
4330
4354
|
toRaiseError;
|
|
4331
|
-
constructor(compiler, typeChecker,
|
|
4355
|
+
constructor(compiler, typeChecker, reject) {
|
|
4332
4356
|
this.#compiler = compiler;
|
|
4357
|
+
this.#reject = reject;
|
|
4333
4358
|
this.#typeChecker = typeChecker;
|
|
4334
|
-
if (resolvedConfig?.rejectAnyType) {
|
|
4335
|
-
this.#rejectTypes.add("any");
|
|
4336
|
-
}
|
|
4337
|
-
if (resolvedConfig?.rejectNeverType) {
|
|
4338
|
-
this.#rejectTypes.add("never");
|
|
4339
|
-
}
|
|
4340
4359
|
this.toAcceptProps = new ToAcceptProps(compiler, typeChecker);
|
|
4341
4360
|
this.toBe = new ToBe();
|
|
4342
4361
|
this.toBeApplicable = new ToBeApplicable(compiler);
|
|
@@ -4349,13 +4368,15 @@ class ExpectService {
|
|
|
4349
4368
|
}
|
|
4350
4369
|
match(assertion, onDiagnostics) {
|
|
4351
4370
|
const matcherNameText = assertion.matcherNameNode.name.text;
|
|
4352
|
-
if (!assertion.source[0]) {
|
|
4353
|
-
this.#onSourceArgumentOrTypeArgumentMustBeProvided(assertion, onDiagnostics);
|
|
4371
|
+
if (!argumentOrTypeArgumentIsProvided("source", "Source", assertion.source[0], assertion.node.expression, onDiagnostics)) {
|
|
4354
4372
|
return;
|
|
4355
4373
|
}
|
|
4356
4374
|
const matchWorker = new MatchWorker(this.#compiler, this.#typeChecker, assertion);
|
|
4357
4375
|
if (!(matcherNameText === "toRaiseError" && assertion.isNot === false) &&
|
|
4358
|
-
this.#
|
|
4376
|
+
this.#reject.argumentType([
|
|
4377
|
+
["source", assertion.source[0]],
|
|
4378
|
+
["target", assertion.target?.[0]],
|
|
4379
|
+
], onDiagnostics)) {
|
|
4359
4380
|
return;
|
|
4360
4381
|
}
|
|
4361
4382
|
switch (matcherNameText) {
|
|
@@ -4363,8 +4384,7 @@ class ExpectService {
|
|
|
4363
4384
|
case "toBe":
|
|
4364
4385
|
case "toBeAssignableTo":
|
|
4365
4386
|
case "toBeAssignableWith":
|
|
4366
|
-
if (!assertion.target?.[0]) {
|
|
4367
|
-
this.#onTargetArgumentOrTypeArgumentMustBeProvided(assertion, onDiagnostics);
|
|
4387
|
+
if (!argumentOrTypeArgumentIsProvided("target", "Target", assertion.target?.[0], assertion.matcherNameNode.name, onDiagnostics)) {
|
|
4368
4388
|
return;
|
|
4369
4389
|
}
|
|
4370
4390
|
return this[matcherNameText].match(matchWorker, assertion.source[0], assertion.target[0], onDiagnostics);
|
|
@@ -4375,8 +4395,7 @@ class ExpectService {
|
|
|
4375
4395
|
case "toRaiseError":
|
|
4376
4396
|
return this[matcherNameText].match(matchWorker, assertion.source[0], assertion.target, onDiagnostics);
|
|
4377
4397
|
case "toHaveProperty":
|
|
4378
|
-
if (!assertion.target?.[0]) {
|
|
4379
|
-
this.#onTargetArgumentMustBeProvided("key", assertion, onDiagnostics);
|
|
4398
|
+
if (!argumentIsProvided("key", assertion.target?.[0], assertion.matcherNameNode.name, onDiagnostics)) {
|
|
4380
4399
|
return;
|
|
4381
4400
|
}
|
|
4382
4401
|
return this.toHaveProperty.match(matchWorker, assertion.source[0], assertion.target[0], onDiagnostics);
|
|
@@ -4390,42 +4409,61 @@ class ExpectService {
|
|
|
4390
4409
|
const origin = DiagnosticOrigin.fromNode(assertion.matcherNameNode.name);
|
|
4391
4410
|
onDiagnostics(Diagnostic.error(text, origin));
|
|
4392
4411
|
}
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4412
|
+
}
|
|
4413
|
+
|
|
4414
|
+
function capitalize(text) {
|
|
4415
|
+
return text.replace(/^./, text.charAt(0).toUpperCase());
|
|
4416
|
+
}
|
|
4417
|
+
|
|
4418
|
+
class RejectDiagnosticText {
|
|
4419
|
+
static argumentCannotBeOfType(argumentNameText, typeText) {
|
|
4420
|
+
return `An argument for '${argumentNameText}' cannot be of the '${typeText}' type.`;
|
|
4397
4421
|
}
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
const origin = DiagnosticOrigin.fromNode(assertion.matcherNameNode.name);
|
|
4401
|
-
onDiagnostics(Diagnostic.error(text, origin));
|
|
4422
|
+
static typeArgumentCannotBeOfType(argumentNameText, typeText) {
|
|
4423
|
+
return `A type argument for '${argumentNameText}' cannot be of the '${typeText}' type.`;
|
|
4402
4424
|
}
|
|
4403
|
-
|
|
4404
|
-
const
|
|
4405
|
-
|
|
4406
|
-
|
|
4425
|
+
static typeWasRejected(typeText) {
|
|
4426
|
+
const optionNameText = `reject${capitalize(typeText)}Type`;
|
|
4427
|
+
return [
|
|
4428
|
+
`The '${typeText}' type was rejected because the '${optionNameText}' option is enabled.`,
|
|
4429
|
+
`If this check is necessary, pass '${typeText}' as the type argument explicitly.`,
|
|
4430
|
+
];
|
|
4431
|
+
}
|
|
4432
|
+
}
|
|
4433
|
+
|
|
4434
|
+
class Reject {
|
|
4435
|
+
#compiler;
|
|
4436
|
+
#rejectedArgumentTypes = new Set();
|
|
4437
|
+
#typeChecker;
|
|
4438
|
+
constructor(compiler, typeChecker, resolvedConfig) {
|
|
4439
|
+
this.#compiler = compiler;
|
|
4440
|
+
this.#typeChecker = typeChecker;
|
|
4441
|
+
if (resolvedConfig?.rejectAnyType) {
|
|
4442
|
+
this.#rejectedArgumentTypes.add("any");
|
|
4443
|
+
}
|
|
4444
|
+
if (resolvedConfig?.rejectNeverType) {
|
|
4445
|
+
this.#rejectedArgumentTypes.add("never");
|
|
4446
|
+
}
|
|
4407
4447
|
}
|
|
4408
|
-
|
|
4409
|
-
for (const rejectedType of this.#
|
|
4448
|
+
argumentType(target, onDiagnostics) {
|
|
4449
|
+
for (const rejectedType of this.#rejectedArgumentTypes) {
|
|
4410
4450
|
const allowedKeyword = this.#compiler.SyntaxKind[`${capitalize(rejectedType)}Keyword`];
|
|
4411
|
-
if (
|
|
4412
|
-
matchWorker.assertion.target?.[0]?.kind === allowedKeyword) {
|
|
4451
|
+
if (target.some(([, node]) => node?.kind === allowedKeyword)) {
|
|
4413
4452
|
continue;
|
|
4414
4453
|
}
|
|
4415
|
-
for (const
|
|
4416
|
-
|
|
4417
|
-
if (!argumentNode) {
|
|
4454
|
+
for (const [name, node] of target) {
|
|
4455
|
+
if (!node) {
|
|
4418
4456
|
continue;
|
|
4419
4457
|
}
|
|
4420
|
-
if (
|
|
4458
|
+
if (this.#typeChecker.getTypeAtLocation(node).flags & this.#compiler.TypeFlags[capitalize(rejectedType)]) {
|
|
4421
4459
|
const text = [
|
|
4422
|
-
nodeBelongsToArgumentList(this.#compiler,
|
|
4423
|
-
?
|
|
4424
|
-
:
|
|
4425
|
-
...
|
|
4460
|
+
nodeBelongsToArgumentList(this.#compiler, node)
|
|
4461
|
+
? RejectDiagnosticText.argumentCannotBeOfType(name, rejectedType)
|
|
4462
|
+
: RejectDiagnosticText.typeArgumentCannotBeOfType(capitalize(name), rejectedType),
|
|
4463
|
+
...RejectDiagnosticText.typeWasRejected(rejectedType),
|
|
4426
4464
|
];
|
|
4427
|
-
const origin = DiagnosticOrigin.fromNode(
|
|
4428
|
-
onDiagnostics(Diagnostic.error(text, origin));
|
|
4465
|
+
const origin = DiagnosticOrigin.fromNode(node);
|
|
4466
|
+
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
4429
4467
|
return true;
|
|
4430
4468
|
}
|
|
4431
4469
|
}
|
|
@@ -4434,20 +4472,78 @@ class ExpectService {
|
|
|
4434
4472
|
}
|
|
4435
4473
|
}
|
|
4436
4474
|
|
|
4475
|
+
class WhenDiagnosticText {
|
|
4476
|
+
static actionIsNotSupported(actionNameText) {
|
|
4477
|
+
return `The '.${actionNameText}()' action is not supported.`;
|
|
4478
|
+
}
|
|
4479
|
+
}
|
|
4480
|
+
|
|
4481
|
+
class WhenService {
|
|
4482
|
+
#onDiagnostics;
|
|
4483
|
+
#reject;
|
|
4484
|
+
constructor(reject, onDiagnostics) {
|
|
4485
|
+
this.#reject = reject;
|
|
4486
|
+
this.#onDiagnostics = onDiagnostics;
|
|
4487
|
+
}
|
|
4488
|
+
action(when) {
|
|
4489
|
+
if (!argumentIsProvided("target", when.target[0], when.node.expression, this.#onDiagnostics) ||
|
|
4490
|
+
this.#reject.argumentType([["target", when.target[0]]], this.#onDiagnostics)) {
|
|
4491
|
+
return;
|
|
4492
|
+
}
|
|
4493
|
+
const actionNameText = when.actionNameNode.name.getText();
|
|
4494
|
+
switch (actionNameText) {
|
|
4495
|
+
case "isCalledWith":
|
|
4496
|
+
break;
|
|
4497
|
+
default:
|
|
4498
|
+
this.#onActionIsNotSupported(actionNameText, when, this.#onDiagnostics);
|
|
4499
|
+
return;
|
|
4500
|
+
}
|
|
4501
|
+
if (when.abilityDiagnostics != null && when.abilityDiagnostics.size > 0) {
|
|
4502
|
+
const diagnostics = [];
|
|
4503
|
+
for (const diagnostic of when.abilityDiagnostics) {
|
|
4504
|
+
if (isDiagnosticWithLocation(diagnostic)) {
|
|
4505
|
+
const text = getDiagnosticMessageText(diagnostic);
|
|
4506
|
+
let origin;
|
|
4507
|
+
if (isDiagnosticWithLocation(diagnostic) && diagnosticBelongsToNode(diagnostic, when.node)) {
|
|
4508
|
+
origin = DiagnosticOrigin.fromNodes(when.target);
|
|
4509
|
+
}
|
|
4510
|
+
else {
|
|
4511
|
+
origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), when.node.getSourceFile());
|
|
4512
|
+
}
|
|
4513
|
+
let related;
|
|
4514
|
+
if (diagnostic.relatedInformation != null) {
|
|
4515
|
+
related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
|
|
4516
|
+
}
|
|
4517
|
+
diagnostics.push(Diagnostic.error(text, origin).add({ related }));
|
|
4518
|
+
}
|
|
4519
|
+
}
|
|
4520
|
+
this.#onDiagnostics(diagnostics);
|
|
4521
|
+
}
|
|
4522
|
+
}
|
|
4523
|
+
#onActionIsNotSupported(actionNameText, when, onDiagnostics) {
|
|
4524
|
+
const text = WhenDiagnosticText.actionIsNotSupported(actionNameText);
|
|
4525
|
+
const origin = DiagnosticOrigin.fromNode(when.actionNameNode.name);
|
|
4526
|
+
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
4527
|
+
}
|
|
4528
|
+
}
|
|
4529
|
+
|
|
4437
4530
|
class TestTreeWalker {
|
|
4438
4531
|
#cancellationToken;
|
|
4439
4532
|
#expectService;
|
|
4440
4533
|
#hasOnly;
|
|
4534
|
+
#onTaskDiagnostics;
|
|
4441
4535
|
#position;
|
|
4442
4536
|
#resolvedConfig;
|
|
4443
|
-
#
|
|
4444
|
-
constructor(compiler, typeChecker, resolvedConfig, options) {
|
|
4537
|
+
#whenService;
|
|
4538
|
+
constructor(compiler, typeChecker, resolvedConfig, onTaskDiagnostics, options) {
|
|
4445
4539
|
this.#resolvedConfig = resolvedConfig;
|
|
4540
|
+
this.#onTaskDiagnostics = onTaskDiagnostics;
|
|
4446
4541
|
this.#cancellationToken = options.cancellationToken;
|
|
4447
4542
|
this.#hasOnly = options.hasOnly || resolvedConfig.only != null || options.position != null;
|
|
4448
4543
|
this.#position = options.position;
|
|
4449
|
-
|
|
4450
|
-
this.#expectService = new ExpectService(compiler, typeChecker,
|
|
4544
|
+
const reject = new Reject(compiler, typeChecker, resolvedConfig);
|
|
4545
|
+
this.#expectService = new ExpectService(compiler, typeChecker, reject);
|
|
4546
|
+
this.#whenService = new WhenService(reject, onTaskDiagnostics);
|
|
4451
4547
|
}
|
|
4452
4548
|
#resolveRunMode(mode, testNode) {
|
|
4453
4549
|
if (testNode.flags & TestTreeNodeFlags.Fail) {
|
|
@@ -4472,28 +4568,23 @@ class TestTreeWalker {
|
|
|
4472
4568
|
}
|
|
4473
4569
|
return mode;
|
|
4474
4570
|
}
|
|
4475
|
-
visit(
|
|
4476
|
-
for (const
|
|
4571
|
+
visit(nodes, runMode, parentResult) {
|
|
4572
|
+
for (const node of nodes) {
|
|
4477
4573
|
if (this.#cancellationToken?.isCancellationRequested) {
|
|
4478
4574
|
break;
|
|
4479
4575
|
}
|
|
4480
|
-
|
|
4481
|
-
if (validationError.length > 0) {
|
|
4482
|
-
EventEmitter.dispatch(["task:error", { diagnostics: validationError, result: this.#taskResult }]);
|
|
4483
|
-
break;
|
|
4484
|
-
}
|
|
4485
|
-
switch (testNode.brand) {
|
|
4576
|
+
switch (node.brand) {
|
|
4486
4577
|
case TestTreeNodeBrand.Describe:
|
|
4487
|
-
this.#visitDescribe(
|
|
4578
|
+
this.#visitDescribe(node, runMode, parentResult);
|
|
4488
4579
|
break;
|
|
4489
4580
|
case TestTreeNodeBrand.Test:
|
|
4490
|
-
this.#visitTest(
|
|
4581
|
+
this.#visitTest(node, runMode, parentResult);
|
|
4491
4582
|
break;
|
|
4492
4583
|
case TestTreeNodeBrand.Expect:
|
|
4493
|
-
this.#visitAssertion(
|
|
4584
|
+
this.#visitAssertion(node, runMode, parentResult);
|
|
4494
4585
|
break;
|
|
4495
4586
|
case TestTreeNodeBrand.When:
|
|
4496
|
-
this.#visitWhen(
|
|
4587
|
+
this.#visitWhen(node);
|
|
4497
4588
|
break;
|
|
4498
4589
|
}
|
|
4499
4590
|
}
|
|
@@ -4544,13 +4635,7 @@ class TestTreeWalker {
|
|
|
4544
4635
|
runMode = this.#resolveRunMode(runMode, describe);
|
|
4545
4636
|
if (!(runMode & RunMode.Skip || (this.#hasOnly && !(runMode & RunMode.Only)) || runMode & RunMode.Todo) &&
|
|
4546
4637
|
describe.diagnostics.size > 0) {
|
|
4547
|
-
|
|
4548
|
-
"task:error",
|
|
4549
|
-
{
|
|
4550
|
-
diagnostics: Diagnostic.fromDiagnostics([...describe.diagnostics]),
|
|
4551
|
-
result: this.#taskResult,
|
|
4552
|
-
},
|
|
4553
|
-
]);
|
|
4638
|
+
this.#onTaskDiagnostics(Diagnostic.fromDiagnostics([...describe.diagnostics]));
|
|
4554
4639
|
}
|
|
4555
4640
|
else {
|
|
4556
4641
|
this.visit(describe.children, runMode, describeResult);
|
|
@@ -4587,36 +4672,14 @@ class TestTreeWalker {
|
|
|
4587
4672
|
EventEmitter.dispatch(["test:pass", { result: testResult }]);
|
|
4588
4673
|
}
|
|
4589
4674
|
}
|
|
4590
|
-
#visitWhen(when
|
|
4591
|
-
|
|
4592
|
-
const diagnostics = [];
|
|
4593
|
-
for (const diagnostic of when.abilityDiagnostics) {
|
|
4594
|
-
if (isDiagnosticWithLocation(diagnostic)) {
|
|
4595
|
-
const text = getDiagnosticMessageText(diagnostic);
|
|
4596
|
-
let origin;
|
|
4597
|
-
if (isDiagnosticWithLocation(diagnostic) && diagnosticBelongsToNode(diagnostic, when.node)) {
|
|
4598
|
-
origin = DiagnosticOrigin.fromNodes(when.target);
|
|
4599
|
-
}
|
|
4600
|
-
else {
|
|
4601
|
-
origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), when.node.getSourceFile());
|
|
4602
|
-
}
|
|
4603
|
-
let related;
|
|
4604
|
-
if (diagnostic.relatedInformation != null) {
|
|
4605
|
-
related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
|
|
4606
|
-
}
|
|
4607
|
-
diagnostics.push(Diagnostic.error(text, origin).add({ related }));
|
|
4608
|
-
}
|
|
4609
|
-
}
|
|
4610
|
-
EventEmitter.dispatch(["task:error", { diagnostics, result: this.#taskResult }]);
|
|
4611
|
-
return;
|
|
4612
|
-
}
|
|
4675
|
+
#visitWhen(when) {
|
|
4676
|
+
this.#whenService.action(when);
|
|
4613
4677
|
}
|
|
4614
4678
|
}
|
|
4615
4679
|
|
|
4616
4680
|
class TaskRunner {
|
|
4617
4681
|
#collectService;
|
|
4618
4682
|
#compiler;
|
|
4619
|
-
#eventEmitter = new EventEmitter();
|
|
4620
4683
|
#resolvedConfig;
|
|
4621
4684
|
#projectService;
|
|
4622
4685
|
constructor(compiler, resolvedConfig) {
|
|
@@ -4625,6 +4688,9 @@ class TaskRunner {
|
|
|
4625
4688
|
this.#projectService = new ProjectService(compiler, this.#resolvedConfig);
|
|
4626
4689
|
this.#collectService = new CollectService(compiler, this.#projectService, this.#resolvedConfig);
|
|
4627
4690
|
}
|
|
4691
|
+
#onDiagnostics(diagnostics, result) {
|
|
4692
|
+
EventEmitter.dispatch(["task:error", { diagnostics, result }]);
|
|
4693
|
+
}
|
|
4628
4694
|
async run(task, cancellationToken) {
|
|
4629
4695
|
if (cancellationToken.isCancellationRequested) {
|
|
4630
4696
|
return;
|
|
@@ -4638,19 +4704,13 @@ class TaskRunner {
|
|
|
4638
4704
|
}
|
|
4639
4705
|
async #run(task, taskResult, cancellationToken) {
|
|
4640
4706
|
if (!existsSync(task.filePath)) {
|
|
4641
|
-
|
|
4642
|
-
"task:error",
|
|
4643
|
-
{ diagnostics: [Diagnostic.error(`Test file '${task.filePath}' does not exist.`)], result: taskResult },
|
|
4644
|
-
]);
|
|
4707
|
+
this.#onDiagnostics([Diagnostic.error(`Test file '${task.filePath}' does not exist.`)], taskResult);
|
|
4645
4708
|
return;
|
|
4646
4709
|
}
|
|
4647
4710
|
let languageService = this.#projectService.getLanguageService(task.filePath);
|
|
4648
4711
|
const syntacticDiagnostics = languageService?.getSyntacticDiagnostics(task.filePath);
|
|
4649
4712
|
if (syntacticDiagnostics != null && syntacticDiagnostics.length > 0) {
|
|
4650
|
-
|
|
4651
|
-
"task:error",
|
|
4652
|
-
{ diagnostics: Diagnostic.fromDiagnostics(syntacticDiagnostics), result: taskResult },
|
|
4653
|
-
]);
|
|
4713
|
+
this.#onDiagnostics(Diagnostic.fromDiagnostics(syntacticDiagnostics), taskResult);
|
|
4654
4714
|
return;
|
|
4655
4715
|
}
|
|
4656
4716
|
let semanticDiagnostics = languageService?.getSemanticDiagnostics(task.filePath);
|
|
@@ -4658,21 +4718,20 @@ class TaskRunner {
|
|
|
4658
4718
|
let sourceFile = program?.getSourceFile(task.filePath);
|
|
4659
4719
|
if (sourceFile?.text.startsWith("// @tstyche-template")) {
|
|
4660
4720
|
if (semanticDiagnostics != null && semanticDiagnostics.length > 0) {
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4721
|
+
this.#onDiagnostics(Diagnostic.fromDiagnostics(semanticDiagnostics), taskResult);
|
|
4722
|
+
return;
|
|
4723
|
+
}
|
|
4724
|
+
const moduleSpecifier = pathToFileURL(task.filePath).toString();
|
|
4725
|
+
const testText = (await import(moduleSpecifier))?.default;
|
|
4726
|
+
if (typeof testText !== "string") {
|
|
4727
|
+
this.#onDiagnostics([Diagnostic.error("A template test file must export a string.")], taskResult);
|
|
4665
4728
|
return;
|
|
4666
4729
|
}
|
|
4667
|
-
|
|
4668
|
-
this.#projectService.openFile(task.filePath, text, this.#resolvedConfig.rootPath);
|
|
4730
|
+
this.#projectService.openFile(task.filePath, testText, this.#resolvedConfig.rootPath);
|
|
4669
4731
|
languageService = this.#projectService.getLanguageService(task.filePath);
|
|
4670
4732
|
const syntacticDiagnostics = languageService?.getSyntacticDiagnostics(task.filePath);
|
|
4671
4733
|
if (syntacticDiagnostics != null && syntacticDiagnostics.length > 0) {
|
|
4672
|
-
|
|
4673
|
-
"task:error",
|
|
4674
|
-
{ diagnostics: Diagnostic.fromDiagnostics(syntacticDiagnostics), result: taskResult },
|
|
4675
|
-
]);
|
|
4734
|
+
this.#onDiagnostics(Diagnostic.fromDiagnostics(syntacticDiagnostics), taskResult);
|
|
4676
4735
|
return;
|
|
4677
4736
|
}
|
|
4678
4737
|
semanticDiagnostics = languageService?.getSemanticDiagnostics(task.filePath);
|
|
@@ -4682,24 +4741,17 @@ class TaskRunner {
|
|
|
4682
4741
|
if (!sourceFile) {
|
|
4683
4742
|
return;
|
|
4684
4743
|
}
|
|
4685
|
-
const cancellationHandler = new CancellationHandler(cancellationToken, CancellationReason.CollectError);
|
|
4686
|
-
this.#eventEmitter.addHandler(cancellationHandler);
|
|
4687
4744
|
const testTree = this.#collectService.createTestTree(sourceFile, semanticDiagnostics);
|
|
4688
|
-
this.#eventEmitter.removeHandler(cancellationHandler);
|
|
4689
|
-
if (cancellationToken.isCancellationRequested) {
|
|
4690
|
-
return;
|
|
4691
|
-
}
|
|
4692
4745
|
if (testTree.diagnostics.size > 0) {
|
|
4693
|
-
|
|
4694
|
-
"task:error",
|
|
4695
|
-
{ diagnostics: Diagnostic.fromDiagnostics([...testTree.diagnostics]), result: taskResult },
|
|
4696
|
-
]);
|
|
4746
|
+
this.#onDiagnostics(Diagnostic.fromDiagnostics([...testTree.diagnostics]), taskResult);
|
|
4697
4747
|
return;
|
|
4698
4748
|
}
|
|
4699
4749
|
const typeChecker = program?.getTypeChecker();
|
|
4700
|
-
const
|
|
4750
|
+
const onTaskDiagnostics = (diagnostics) => {
|
|
4751
|
+
this.#onDiagnostics(diagnostics, taskResult);
|
|
4752
|
+
};
|
|
4753
|
+
const testTreeWalker = new TestTreeWalker(this.#compiler, typeChecker, this.#resolvedConfig, onTaskDiagnostics, {
|
|
4701
4754
|
cancellationToken,
|
|
4702
|
-
taskResult,
|
|
4703
4755
|
hasOnly: testTree.hasOnly,
|
|
4704
4756
|
position: task.position,
|
|
4705
4757
|
});
|
|
@@ -4710,7 +4762,7 @@ class TaskRunner {
|
|
|
4710
4762
|
class Runner {
|
|
4711
4763
|
#eventEmitter = new EventEmitter();
|
|
4712
4764
|
#resolvedConfig;
|
|
4713
|
-
static version = "4.0.0-beta.
|
|
4765
|
+
static version = "4.0.0-beta.9";
|
|
4714
4766
|
constructor(resolvedConfig) {
|
|
4715
4767
|
this.#resolvedConfig = resolvedConfig;
|
|
4716
4768
|
}
|
|
@@ -4910,4 +4962,4 @@ class Cli {
|
|
|
4910
4962
|
}
|
|
4911
4963
|
}
|
|
4912
4964
|
|
|
4913
|
-
export { AssertionNode, BaseReporter, CancellationHandler, CancellationReason, CancellationToken, Cli, CollectService, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, EventEmitter, ExitCodeHandler, ExpectResult, ExpectService, FileWatcher, InputService, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, PluginService, ProjectResult, ProjectService, Result, ResultCount, ResultHandler, ResultStatus, ResultTiming, Runner, Scribbler, Select, SelectDiagnosticText, SetupReporter, SourceFile, Store, SummaryReporter, TargetResult, Task, TaskResult, TestResult, TestTree, TestTreeNode, TestTreeNodeBrand, TestTreeNodeFlags, Text, Version, WatchReporter, WatchService, Watcher, WhenNode, addsPackageText, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, environmentOptions, fileViewText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, nodeBelongsToArgumentList, summaryText, taskStatusText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
|
|
4965
|
+
export { AssertionNode, BaseReporter, CancellationHandler, CancellationReason, CancellationToken, Cli, CollectService, Color, Config, ConfigDiagnosticText, DescribeResult, Diagnostic, DiagnosticCategory, DiagnosticOrigin, EventEmitter, ExitCodeHandler, ExpectResult, ExpectService, FileWatcher, InputService, Line, ListReporter, OptionBrand, OptionGroup, Options, OutputService, Path, PluginService, ProjectResult, ProjectService, Reject, Result, ResultCount, ResultHandler, ResultStatus, ResultTiming, Runner, Scribbler, Select, SelectDiagnosticText, SetupReporter, SourceFile, Store, SummaryReporter, TargetResult, Task, TaskResult, TestResult, TestTree, TestTreeNode, TestTreeNodeBrand, TestTreeNodeFlags, Text, Version, WatchReporter, WatchService, Watcher, WhenNode, WhenService, addsPackageText, argumentIsProvided, argumentOrTypeArgumentIsProvided, defaultOptions, describeNameText, diagnosticBelongsToNode, diagnosticText, environmentOptions, fileViewText, formattedText, getDiagnosticMessageText, getTextSpanEnd, helpText, isDiagnosticWithLocation, nodeBelongsToArgumentList, summaryText, taskStatusText, testNameText, usesCompilerText, waitingForFileChangesText, watchUsageText };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tstyche",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.9",
|
|
4
4
|
"description": "The Essential Type Testing Tool.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -62,21 +62,21 @@
|
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@biomejs/biome": "1.9.4",
|
|
64
64
|
"@rollup/plugin-typescript": "12.1.2",
|
|
65
|
-
"@types/node": "22.15.
|
|
66
|
-
"@types/react": "19.1.
|
|
65
|
+
"@types/node": "22.15.15",
|
|
66
|
+
"@types/react": "19.1.3",
|
|
67
67
|
"ajv": "8.17.1",
|
|
68
|
-
"cspell": "
|
|
68
|
+
"cspell": "9.0.0",
|
|
69
69
|
"magic-string": "0.30.17",
|
|
70
70
|
"monocart-coverage-reports": "2.12.4",
|
|
71
71
|
"pretty-ansi": "3.0.0",
|
|
72
|
-
"rollup": "4.40.
|
|
72
|
+
"rollup": "4.40.2",
|
|
73
73
|
"rollup-plugin-dts": "6.2.1",
|
|
74
74
|
"ts-blank-space": "0.6.1",
|
|
75
75
|
"tslib": "2.8.1",
|
|
76
76
|
"typescript": "5.8.3"
|
|
77
77
|
},
|
|
78
78
|
"peerDependencies": {
|
|
79
|
-
"typescript": "
|
|
79
|
+
"typescript": ">=4.7"
|
|
80
80
|
},
|
|
81
81
|
"peerDependenciesMeta": {
|
|
82
82
|
"typescript": {
|