tstyche 4.0.0-beta.8 → 4.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/build/index.d.cts +3 -3
- package/build/index.d.ts +3 -3
- package/build/tstyche.d.ts +80 -72
- package/build/tstyche.js +327 -279
- package/package.json +2 -47
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)) {
|
|
@@ -808,11 +810,7 @@ class Store {
|
|
|
808
810
|
modulePath = Path.resolve(modulePath, "../tsserverlibrary.js");
|
|
809
811
|
}
|
|
810
812
|
const sourceText = await fs.readFile(modulePath, { encoding: "utf8" });
|
|
811
|
-
const toExpose = [
|
|
812
|
-
"isApplicableIndexType",
|
|
813
|
-
"isTypeRelatedTo",
|
|
814
|
-
"relation: { assignable: assignableRelation, identity: identityRelation }",
|
|
815
|
-
];
|
|
813
|
+
const toExpose = ["isApplicableIndexType", "isTypeIdenticalTo"];
|
|
816
814
|
const modifiedSourceText = sourceText.replace("return checker;", `return { ...checker, ${toExpose.join(", ")} };`);
|
|
817
815
|
const compiledWrapper = vm.compileFunction(modifiedSourceText, ["exports", "require", "module", "__filename", "__dirname"], { filename: modulePath });
|
|
818
816
|
compiledWrapper(exports, createRequire(modulePath), module, modulePath, Path.dirname(modulePath));
|
|
@@ -2547,7 +2545,6 @@ var CancellationReason;
|
|
|
2547
2545
|
(function (CancellationReason) {
|
|
2548
2546
|
CancellationReason["ConfigChange"] = "configChange";
|
|
2549
2547
|
CancellationReason["ConfigError"] = "configError";
|
|
2550
|
-
CancellationReason["CollectError"] = "collectError";
|
|
2551
2548
|
CancellationReason["FailFast"] = "failFast";
|
|
2552
2549
|
CancellationReason["WatchClose"] = "watchClose";
|
|
2553
2550
|
})(CancellationReason || (CancellationReason = {}));
|
|
@@ -2873,18 +2870,9 @@ class WatchService {
|
|
|
2873
2870
|
}
|
|
2874
2871
|
}
|
|
2875
2872
|
|
|
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
2873
|
class TestTreeNode {
|
|
2885
2874
|
brand;
|
|
2886
2875
|
children = [];
|
|
2887
|
-
#compiler;
|
|
2888
2876
|
diagnostics = new Set();
|
|
2889
2877
|
flags;
|
|
2890
2878
|
name = "";
|
|
@@ -2892,7 +2880,6 @@ class TestTreeNode {
|
|
|
2892
2880
|
parent;
|
|
2893
2881
|
constructor(compiler, brand, node, parent, flags) {
|
|
2894
2882
|
this.brand = brand;
|
|
2895
|
-
this.#compiler = compiler;
|
|
2896
2883
|
this.node = node;
|
|
2897
2884
|
this.parent = parent;
|
|
2898
2885
|
this.flags = flags;
|
|
@@ -2908,34 +2895,6 @@ class TestTreeNode {
|
|
|
2908
2895
|
}
|
|
2909
2896
|
}
|
|
2910
2897
|
}
|
|
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
2898
|
}
|
|
2940
2899
|
|
|
2941
2900
|
class AssertionNode extends TestTreeNode {
|
|
@@ -2967,10 +2926,10 @@ class AssertionNode extends TestTreeNode {
|
|
|
2967
2926
|
}
|
|
2968
2927
|
|
|
2969
2928
|
function nodeBelongsToArgumentList(compiler, node) {
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
return
|
|
2929
|
+
return compiler.isCallExpression(node.parent) && node.parent.arguments.some((argument) => argument === node);
|
|
2930
|
+
}
|
|
2931
|
+
function nodeIsChildOfExpressionStatement(compiler, node) {
|
|
2932
|
+
return compiler.isExpressionStatement(node.parent);
|
|
2974
2933
|
}
|
|
2975
2934
|
|
|
2976
2935
|
class AbilityLayer {
|
|
@@ -3033,6 +2992,11 @@ class AbilityLayer {
|
|
|
3033
2992
|
this.#nodes = [];
|
|
3034
2993
|
this.#text = "";
|
|
3035
2994
|
}
|
|
2995
|
+
#eraseTrailingComma(node, parent) {
|
|
2996
|
+
if (node.hasTrailingComma) {
|
|
2997
|
+
this.#addRanges(parent, [{ start: node.end - 1, end: node.end }]);
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3036
3000
|
handleWhen(whenNode) {
|
|
3037
3001
|
const whenStart = whenNode.node.getStart();
|
|
3038
3002
|
const whenExpressionEnd = whenNode.node.expression.getEnd();
|
|
@@ -3040,13 +3004,14 @@ class AbilityLayer {
|
|
|
3040
3004
|
const actionNameEnd = whenNode.actionNameNode.getEnd();
|
|
3041
3005
|
switch (whenNode.actionNameNode.name.text) {
|
|
3042
3006
|
case "isCalledWith":
|
|
3007
|
+
this.#eraseTrailingComma(whenNode.target, whenNode);
|
|
3043
3008
|
this.#addRanges(whenNode, [
|
|
3044
3009
|
{
|
|
3045
|
-
end: whenExpressionEnd,
|
|
3046
3010
|
start: whenStart,
|
|
3047
|
-
|
|
3011
|
+
end: whenExpressionEnd,
|
|
3012
|
+
replacement: nodeIsChildOfExpressionStatement(this.#compiler, whenNode.actionNode) ? ";" : "",
|
|
3048
3013
|
},
|
|
3049
|
-
{
|
|
3014
|
+
{ start: whenEnd, end: actionNameEnd },
|
|
3050
3015
|
]);
|
|
3051
3016
|
break;
|
|
3052
3017
|
}
|
|
@@ -3059,28 +3024,30 @@ class AbilityLayer {
|
|
|
3059
3024
|
switch (assertionNode.matcherNameNode.name.text) {
|
|
3060
3025
|
case "toBeApplicable":
|
|
3061
3026
|
this.#addRanges(assertionNode, [
|
|
3062
|
-
{
|
|
3063
|
-
{
|
|
3027
|
+
{ start: expectStart, end: expectExpressionEnd },
|
|
3028
|
+
{ start: expectEnd, end: matcherNameEnd },
|
|
3064
3029
|
]);
|
|
3065
3030
|
break;
|
|
3066
3031
|
case "toBeCallableWith":
|
|
3032
|
+
this.#eraseTrailingComma(assertionNode.source, assertionNode);
|
|
3067
3033
|
this.#addRanges(assertionNode, [
|
|
3068
3034
|
{
|
|
3069
|
-
end: expectExpressionEnd,
|
|
3070
3035
|
start: expectStart,
|
|
3071
|
-
|
|
3036
|
+
end: expectExpressionEnd,
|
|
3037
|
+
replacement: nodeIsChildOfExpressionStatement(this.#compiler, assertionNode.matcherNode) ? ";" : "",
|
|
3072
3038
|
},
|
|
3073
|
-
{
|
|
3039
|
+
{ start: expectEnd, end: matcherNameEnd },
|
|
3074
3040
|
]);
|
|
3075
3041
|
break;
|
|
3076
3042
|
case "toBeConstructableWith":
|
|
3043
|
+
this.#eraseTrailingComma(assertionNode.source, assertionNode);
|
|
3077
3044
|
this.#addRanges(assertionNode, [
|
|
3078
3045
|
{
|
|
3079
|
-
end: expectExpressionEnd,
|
|
3080
3046
|
start: expectStart,
|
|
3081
|
-
|
|
3047
|
+
end: expectExpressionEnd,
|
|
3048
|
+
replacement: nodeIsChildOfExpressionStatement(this.#compiler, assertionNode.matcherNode) ? "; new" : "new",
|
|
3082
3049
|
},
|
|
3083
|
-
{
|
|
3050
|
+
{ start: expectEnd, end: matcherNameEnd },
|
|
3084
3051
|
]);
|
|
3085
3052
|
break;
|
|
3086
3053
|
}
|
|
@@ -3097,6 +3064,14 @@ class CollectDiagnosticText {
|
|
|
3097
3064
|
}
|
|
3098
3065
|
}
|
|
3099
3066
|
|
|
3067
|
+
var TestTreeNodeBrand;
|
|
3068
|
+
(function (TestTreeNodeBrand) {
|
|
3069
|
+
TestTreeNodeBrand["Describe"] = "describe";
|
|
3070
|
+
TestTreeNodeBrand["Test"] = "test";
|
|
3071
|
+
TestTreeNodeBrand["Expect"] = "expect";
|
|
3072
|
+
TestTreeNodeBrand["When"] = "when";
|
|
3073
|
+
})(TestTreeNodeBrand || (TestTreeNodeBrand = {}));
|
|
3074
|
+
|
|
3100
3075
|
var TestTreeNodeFlags;
|
|
3101
3076
|
(function (TestTreeNodeFlags) {
|
|
3102
3077
|
TestTreeNodeFlags[TestTreeNodeFlags["None"] = 0] = "None";
|
|
@@ -3110,19 +3085,8 @@ class IdentifierLookup {
|
|
|
3110
3085
|
#compiler;
|
|
3111
3086
|
#identifiers;
|
|
3112
3087
|
#moduleSpecifiers = ['"tstyche"', "'tstyche'"];
|
|
3113
|
-
constructor(compiler
|
|
3088
|
+
constructor(compiler) {
|
|
3114
3089
|
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
3090
|
}
|
|
3127
3091
|
handleImportDeclaration(node) {
|
|
3128
3092
|
if (this.#moduleSpecifiers.includes(node.moduleSpecifier.getText()) &&
|
|
@@ -3150,7 +3114,20 @@ class IdentifierLookup {
|
|
|
3150
3114
|
}
|
|
3151
3115
|
}
|
|
3152
3116
|
}
|
|
3153
|
-
|
|
3117
|
+
open() {
|
|
3118
|
+
this.#identifiers = {
|
|
3119
|
+
namedImports: {
|
|
3120
|
+
describe: undefined,
|
|
3121
|
+
expect: undefined,
|
|
3122
|
+
it: undefined,
|
|
3123
|
+
namespace: undefined,
|
|
3124
|
+
test: undefined,
|
|
3125
|
+
when: undefined,
|
|
3126
|
+
},
|
|
3127
|
+
namespace: undefined,
|
|
3128
|
+
};
|
|
3129
|
+
}
|
|
3130
|
+
resolveTestTreeNodeMeta(node) {
|
|
3154
3131
|
let flags = TestTreeNodeFlags.None;
|
|
3155
3132
|
let expression = node.expression;
|
|
3156
3133
|
while (this.#compiler.isPropertyAccessExpression(expression)) {
|
|
@@ -3233,72 +3210,72 @@ class CollectService {
|
|
|
3233
3210
|
#abilityLayer;
|
|
3234
3211
|
#compiler;
|
|
3235
3212
|
#identifierLookup;
|
|
3236
|
-
#projectService;
|
|
3237
|
-
#resolvedConfig;
|
|
3238
|
-
#testTree;
|
|
3239
3213
|
constructor(compiler, projectService, resolvedConfig) {
|
|
3240
3214
|
this.#compiler = compiler;
|
|
3241
|
-
this.#
|
|
3242
|
-
this.#resolvedConfig = resolvedConfig;
|
|
3243
|
-
this.#abilityLayer = new AbilityLayer(compiler, this.#projectService, this.#resolvedConfig);
|
|
3215
|
+
this.#abilityLayer = new AbilityLayer(compiler, projectService, resolvedConfig);
|
|
3244
3216
|
this.#identifierLookup = new IdentifierLookup(compiler);
|
|
3245
3217
|
}
|
|
3246
|
-
#collectTestTreeNodes(node, parent) {
|
|
3218
|
+
#collectTestTreeNodes(node, parent, testTree) {
|
|
3247
3219
|
if (this.#compiler.isCallExpression(node)) {
|
|
3248
|
-
const meta = this.#identifierLookup.
|
|
3249
|
-
if (meta != null
|
|
3250
|
-
|
|
3251
|
-
this.#compiler.forEachChild(node, (node) => {
|
|
3252
|
-
this.#collectTestTreeNodes(node, testTreeNode);
|
|
3253
|
-
});
|
|
3254
|
-
this.#onNode(testTreeNode, parent);
|
|
3255
|
-
return;
|
|
3256
|
-
}
|
|
3257
|
-
if (meta != null && meta.brand === TestTreeNodeBrand.Expect) {
|
|
3258
|
-
const modifierNode = this.#getChainedNode(node, "type");
|
|
3259
|
-
if (!modifierNode) {
|
|
3260
|
-
return;
|
|
3261
|
-
}
|
|
3262
|
-
const notNode = this.#getChainedNode(modifierNode, "not");
|
|
3263
|
-
const matcherNameNode = this.#getChainedNode(notNode ?? modifierNode);
|
|
3264
|
-
if (!matcherNameNode) {
|
|
3220
|
+
const meta = this.#identifierLookup.resolveTestTreeNodeMeta(node);
|
|
3221
|
+
if (meta != null) {
|
|
3222
|
+
if (!this.#checkNode(node, meta, parent)) {
|
|
3265
3223
|
return;
|
|
3266
3224
|
}
|
|
3267
|
-
|
|
3268
|
-
|
|
3225
|
+
if (meta.brand === TestTreeNodeBrand.Describe || meta.brand === TestTreeNodeBrand.Test) {
|
|
3226
|
+
const testTreeNode = new TestTreeNode(this.#compiler, meta.brand, node, parent, meta.flags);
|
|
3227
|
+
this.#compiler.forEachChild(node, (node) => {
|
|
3228
|
+
this.#collectTestTreeNodes(node, testTreeNode, testTree);
|
|
3229
|
+
});
|
|
3230
|
+
this.#onNode(testTreeNode, parent, testTree);
|
|
3269
3231
|
return;
|
|
3270
3232
|
}
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3233
|
+
if (meta.brand === TestTreeNodeBrand.Expect) {
|
|
3234
|
+
const modifierNode = this.#getChainedNode(node, "type");
|
|
3235
|
+
if (!modifierNode) {
|
|
3236
|
+
return;
|
|
3237
|
+
}
|
|
3238
|
+
const notNode = this.#getChainedNode(modifierNode, "not");
|
|
3239
|
+
const matcherNameNode = this.#getChainedNode(notNode ?? modifierNode);
|
|
3240
|
+
if (!matcherNameNode) {
|
|
3241
|
+
return;
|
|
3242
|
+
}
|
|
3243
|
+
const matcherNode = this.#getMatcherNode(matcherNameNode);
|
|
3244
|
+
if (!matcherNode) {
|
|
3245
|
+
return;
|
|
3246
|
+
}
|
|
3247
|
+
const assertionNode = new AssertionNode(this.#compiler, meta.brand, node, parent, meta.flags, matcherNode, matcherNameNode, modifierNode, notNode);
|
|
3248
|
+
this.#abilityLayer.handleAssertion(assertionNode);
|
|
3249
|
+
this.#compiler.forEachChild(node, (node) => {
|
|
3250
|
+
this.#collectTestTreeNodes(node, assertionNode, testTree);
|
|
3251
|
+
});
|
|
3252
|
+
this.#onNode(assertionNode, parent, testTree);
|
|
3282
3253
|
return;
|
|
3283
3254
|
}
|
|
3284
|
-
|
|
3285
|
-
|
|
3255
|
+
if (meta.brand === TestTreeNodeBrand.When) {
|
|
3256
|
+
const actionNameNode = this.#getChainedNode(node);
|
|
3257
|
+
if (!actionNameNode) {
|
|
3258
|
+
return;
|
|
3259
|
+
}
|
|
3260
|
+
const actionNode = this.#getActionNode(actionNameNode);
|
|
3261
|
+
if (!actionNode) {
|
|
3262
|
+
return;
|
|
3263
|
+
}
|
|
3264
|
+
this.#compiler.forEachChild(actionNode, (node) => {
|
|
3265
|
+
if (this.#compiler.isCallExpression(node)) {
|
|
3266
|
+
const meta = this.#identifierLookup.resolveTestTreeNodeMeta(node);
|
|
3267
|
+
if (meta?.brand === TestTreeNodeBrand.Describe || meta?.brand === TestTreeNodeBrand.Test) {
|
|
3268
|
+
const text = CollectDiagnosticText.cannotBeNestedWithin(meta.identifier, "when");
|
|
3269
|
+
const origin = DiagnosticOrigin.fromNode(node);
|
|
3270
|
+
this.#onDiagnostics(Diagnostic.error(text, origin));
|
|
3271
|
+
}
|
|
3272
|
+
}
|
|
3273
|
+
});
|
|
3274
|
+
const whenNode = new WhenNode(this.#compiler, meta.brand, node, parent, meta.flags, actionNode, actionNameNode);
|
|
3275
|
+
this.#abilityLayer.handleWhen(whenNode);
|
|
3276
|
+
this.#onNode(whenNode, parent, testTree);
|
|
3286
3277
|
return;
|
|
3287
3278
|
}
|
|
3288
|
-
this.#compiler.forEachChild(actionNode, (node) => {
|
|
3289
|
-
if (this.#compiler.isCallExpression(node)) {
|
|
3290
|
-
const meta = this.#identifierLookup.resolveTestMemberMeta(node);
|
|
3291
|
-
if (meta != null && (meta.brand === TestTreeNodeBrand.Describe || meta.brand === TestTreeNodeBrand.Test)) {
|
|
3292
|
-
const text = CollectDiagnosticText.cannotBeNestedWithin(meta.identifier, "when");
|
|
3293
|
-
const origin = DiagnosticOrigin.fromNode(node);
|
|
3294
|
-
this.#onDiagnostics(Diagnostic.error(text, origin));
|
|
3295
|
-
}
|
|
3296
|
-
}
|
|
3297
|
-
});
|
|
3298
|
-
const whenNode = new WhenNode(this.#compiler, meta.brand, node, parent, meta.flags, actionNode, actionNameNode);
|
|
3299
|
-
this.#abilityLayer.handleWhen(whenNode);
|
|
3300
|
-
this.#onNode(whenNode, parent);
|
|
3301
|
-
return;
|
|
3302
3279
|
}
|
|
3303
3280
|
}
|
|
3304
3281
|
if (this.#compiler.isImportDeclaration(node)) {
|
|
@@ -3306,20 +3283,45 @@ class CollectService {
|
|
|
3306
3283
|
return;
|
|
3307
3284
|
}
|
|
3308
3285
|
this.#compiler.forEachChild(node, (node) => {
|
|
3309
|
-
this.#collectTestTreeNodes(node, parent);
|
|
3286
|
+
this.#collectTestTreeNodes(node, parent, testTree);
|
|
3310
3287
|
});
|
|
3311
3288
|
}
|
|
3312
3289
|
createTestTree(sourceFile, semanticDiagnostics = []) {
|
|
3313
3290
|
const testTree = new TestTree(new Set(semanticDiagnostics), sourceFile);
|
|
3314
3291
|
EventEmitter.dispatch(["collect:start", { tree: testTree }]);
|
|
3315
|
-
this.#testTree = testTree;
|
|
3316
3292
|
this.#abilityLayer.open(sourceFile);
|
|
3317
|
-
this.#
|
|
3293
|
+
this.#identifierLookup.open();
|
|
3294
|
+
this.#collectTestTreeNodes(sourceFile, testTree, testTree);
|
|
3318
3295
|
this.#abilityLayer.close();
|
|
3319
|
-
this.#testTree = undefined;
|
|
3320
3296
|
EventEmitter.dispatch(["collect:end", { tree: testTree }]);
|
|
3321
3297
|
return testTree;
|
|
3322
3298
|
}
|
|
3299
|
+
#checkNode(node, meta, parent) {
|
|
3300
|
+
if ("brand" in parent && !this.#isNodeAllowed(meta, parent)) {
|
|
3301
|
+
const text = CollectDiagnosticText.cannotBeNestedWithin(meta.identifier, parent.node.expression.getText());
|
|
3302
|
+
const origin = DiagnosticOrigin.fromNode(node);
|
|
3303
|
+
this.#onDiagnostics(Diagnostic.error(text, origin));
|
|
3304
|
+
return false;
|
|
3305
|
+
}
|
|
3306
|
+
return true;
|
|
3307
|
+
}
|
|
3308
|
+
#isNodeAllowed(meta, parent) {
|
|
3309
|
+
switch (meta.brand) {
|
|
3310
|
+
case TestTreeNodeBrand.Describe:
|
|
3311
|
+
case TestTreeNodeBrand.Test:
|
|
3312
|
+
if (parent.brand === TestTreeNodeBrand.Test || parent.brand === TestTreeNodeBrand.Expect) {
|
|
3313
|
+
return false;
|
|
3314
|
+
}
|
|
3315
|
+
break;
|
|
3316
|
+
case TestTreeNodeBrand.Expect:
|
|
3317
|
+
case TestTreeNodeBrand.When:
|
|
3318
|
+
if (parent.brand === TestTreeNodeBrand.Describe) {
|
|
3319
|
+
return false;
|
|
3320
|
+
}
|
|
3321
|
+
break;
|
|
3322
|
+
}
|
|
3323
|
+
return true;
|
|
3324
|
+
}
|
|
3323
3325
|
#getChainedNode({ parent }, name) {
|
|
3324
3326
|
if (!this.#compiler.isPropertyAccessExpression(parent)) {
|
|
3325
3327
|
return;
|
|
@@ -3350,10 +3352,10 @@ class CollectService {
|
|
|
3350
3352
|
#onDiagnostics(diagnostic) {
|
|
3351
3353
|
EventEmitter.dispatch(["collect:error", { diagnostics: [diagnostic] }]);
|
|
3352
3354
|
}
|
|
3353
|
-
#onNode(node, parent) {
|
|
3355
|
+
#onNode(node, parent, testTree) {
|
|
3354
3356
|
parent.children.push(node);
|
|
3355
3357
|
if (node.flags & TestTreeNodeFlags.Only) {
|
|
3356
|
-
|
|
3358
|
+
testTree.hasOnly = true;
|
|
3357
3359
|
}
|
|
3358
3360
|
EventEmitter.dispatch(["collect:node", { node }]);
|
|
3359
3361
|
}
|
|
@@ -3409,7 +3411,6 @@ class ProjectService {
|
|
|
3409
3411
|
}
|
|
3410
3412
|
#getDefaultCompilerOptions() {
|
|
3411
3413
|
const defaultCompilerOptions = {
|
|
3412
|
-
allowImportingTsExtensions: true,
|
|
3413
3414
|
allowJs: true,
|
|
3414
3415
|
checkJs: true,
|
|
3415
3416
|
exactOptionalPropertyTypes: true,
|
|
@@ -3420,8 +3421,11 @@ class ProjectService {
|
|
|
3420
3421
|
resolveJsonModule: true,
|
|
3421
3422
|
strict: true,
|
|
3422
3423
|
target: this.#compiler.ScriptTarget.ESNext,
|
|
3423
|
-
verbatimModuleSyntax: true,
|
|
3424
3424
|
};
|
|
3425
|
+
if (Version.isSatisfiedWith(this.#compiler.version, "5.0")) {
|
|
3426
|
+
defaultCompilerOptions.allowImportingTsExtensions = true;
|
|
3427
|
+
defaultCompilerOptions.verbatimModuleSyntax = true;
|
|
3428
|
+
}
|
|
3425
3429
|
return defaultCompilerOptions;
|
|
3426
3430
|
}
|
|
3427
3431
|
getDefaultProject(filePath) {
|
|
@@ -3504,22 +3508,41 @@ var RunMode;
|
|
|
3504
3508
|
RunMode[RunMode["Todo"] = 8] = "Todo";
|
|
3505
3509
|
})(RunMode || (RunMode = {}));
|
|
3506
3510
|
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
}
|
|
3510
|
-
|
|
3511
|
-
class ExpectDiagnosticText {
|
|
3512
|
-
static argumentCannotBeOfType(argumentNameText, typeText) {
|
|
3513
|
-
return `An argument for '${argumentNameText}' cannot be of the '${typeText}' type.`;
|
|
3511
|
+
class EnsureDiagnosticText {
|
|
3512
|
+
static argumentMustBeProvided(argumentNameText) {
|
|
3513
|
+
return `An argument for '${argumentNameText}' must be provided.`;
|
|
3514
3514
|
}
|
|
3515
3515
|
static argumentOrTypeArgumentMustBeProvided(argumentNameText, typeArgumentNameText) {
|
|
3516
3516
|
return `An argument for '${argumentNameText}' or type argument for '${typeArgumentNameText}' must be provided.`;
|
|
3517
3517
|
}
|
|
3518
|
+
}
|
|
3519
|
+
|
|
3520
|
+
function argumentIsProvided(argumentNameText, node, enclosingNode, onDiagnostics) {
|
|
3521
|
+
if (!node) {
|
|
3522
|
+
const text = EnsureDiagnosticText.argumentMustBeProvided(argumentNameText);
|
|
3523
|
+
const origin = DiagnosticOrigin.fromNode(enclosingNode);
|
|
3524
|
+
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
3525
|
+
return false;
|
|
3526
|
+
}
|
|
3527
|
+
return true;
|
|
3528
|
+
}
|
|
3529
|
+
|
|
3530
|
+
function argumentOrTypeArgumentIsProvided(argumentNameText, typeArgumentNameText, node, enclosingNode, onDiagnostics) {
|
|
3531
|
+
if (!node) {
|
|
3532
|
+
const text = EnsureDiagnosticText.argumentOrTypeArgumentMustBeProvided(argumentNameText, typeArgumentNameText);
|
|
3533
|
+
const origin = DiagnosticOrigin.fromNode(enclosingNode);
|
|
3534
|
+
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
3535
|
+
return false;
|
|
3536
|
+
}
|
|
3537
|
+
return true;
|
|
3538
|
+
}
|
|
3539
|
+
|
|
3540
|
+
class ExpectDiagnosticText {
|
|
3518
3541
|
static argumentMustBe(argumentNameText, expectedText) {
|
|
3519
3542
|
return `An argument for '${argumentNameText}' must be ${expectedText}.`;
|
|
3520
3543
|
}
|
|
3521
|
-
static
|
|
3522
|
-
return `
|
|
3544
|
+
static typeArgumentMustBe(argumentNameText, expectedText) {
|
|
3545
|
+
return `A type argument for '${argumentNameText}' must be ${expectedText}.`;
|
|
3523
3546
|
}
|
|
3524
3547
|
static isCallable(isExpression, targetText) {
|
|
3525
3548
|
return `${isExpression ? "Expression" : "Type"} is callable ${targetText}.`;
|
|
@@ -3545,12 +3568,12 @@ class ExpectDiagnosticText {
|
|
|
3545
3568
|
static cannotBeApplied(targetText) {
|
|
3546
3569
|
return `The decorator function cannot be applied${targetText}.`;
|
|
3547
3570
|
}
|
|
3548
|
-
static doesNotHaveProperty(typeText, propertyNameText) {
|
|
3549
|
-
return `Type '${typeText}' does not have property '${propertyNameText}'.`;
|
|
3550
|
-
}
|
|
3551
3571
|
static hasProperty(typeText, propertyNameText) {
|
|
3552
3572
|
return `Type '${typeText}' has property '${propertyNameText}'.`;
|
|
3553
3573
|
}
|
|
3574
|
+
static doesNotHaveProperty(typeText, propertyNameText) {
|
|
3575
|
+
return `Type '${typeText}' does not have property '${propertyNameText}'.`;
|
|
3576
|
+
}
|
|
3554
3577
|
static didYouMeanToUse(suggestionText) {
|
|
3555
3578
|
return `Did you mean to use ${suggestionText}?`;
|
|
3556
3579
|
}
|
|
@@ -3563,12 +3586,6 @@ class ExpectDiagnosticText {
|
|
|
3563
3586
|
static raisedTypeError(count = 1) {
|
|
3564
3587
|
return `The raised type error${count === 1 ? "" : "s"}:`;
|
|
3565
3588
|
}
|
|
3566
|
-
static typeArgumentCannotBeOfType(argumentNameText, typeText) {
|
|
3567
|
-
return `A type argument for '${argumentNameText}' cannot be of the '${typeText}' type.`;
|
|
3568
|
-
}
|
|
3569
|
-
static typeArgumentMustBe(argumentNameText, expectedText) {
|
|
3570
|
-
return `A type argument for '${argumentNameText}' must be ${expectedText}.`;
|
|
3571
|
-
}
|
|
3572
3589
|
static raisedError(isExpression, count, targetCount) {
|
|
3573
3590
|
let countText = "a";
|
|
3574
3591
|
if (count > 1 || targetCount > 1) {
|
|
@@ -3597,11 +3614,11 @@ class ExpectDiagnosticText {
|
|
|
3597
3614
|
static isNotAssignableWith(sourceTypeText, targetTypeText) {
|
|
3598
3615
|
return `Type '${sourceTypeText}' is not assignable with type '${targetTypeText}'.`;
|
|
3599
3616
|
}
|
|
3600
|
-
static
|
|
3601
|
-
return `Type '${sourceTypeText}' is
|
|
3617
|
+
static isTheSame(sourceTypeText, targetTypeText) {
|
|
3618
|
+
return `Type '${sourceTypeText}' is the same as type '${targetTypeText}'.`;
|
|
3602
3619
|
}
|
|
3603
|
-
static
|
|
3604
|
-
return `Type '${sourceTypeText}' is not
|
|
3620
|
+
static isNotTheSame(sourceTypeText, targetTypeText) {
|
|
3621
|
+
return `Type '${sourceTypeText}' is not the same as type '${targetTypeText}'.`;
|
|
3605
3622
|
}
|
|
3606
3623
|
static isNotCompatibleWith(sourceTypeText, targetTypeText) {
|
|
3607
3624
|
return `Type '${sourceTypeText}' is not compatible with type '${targetTypeText}'.`;
|
|
@@ -3612,15 +3629,14 @@ class ExpectDiagnosticText {
|
|
|
3612
3629
|
static typesOfPropertyAreNotCompatible(propertyNameText) {
|
|
3613
3630
|
return `Types of property '${propertyNameText}' are not compatible.`;
|
|
3614
3631
|
}
|
|
3615
|
-
static typeWasRejected(typeText) {
|
|
3616
|
-
const optionNameText = `reject${capitalize(typeText)}Type`;
|
|
3617
|
-
return [
|
|
3618
|
-
`The '${typeText}' type was rejected because the '${optionNameText}' option is enabled.`,
|
|
3619
|
-
`If this check is necessary, pass '${typeText}' as the type argument explicitly.`,
|
|
3620
|
-
];
|
|
3621
|
-
}
|
|
3622
3632
|
}
|
|
3623
3633
|
|
|
3634
|
+
var Relation;
|
|
3635
|
+
(function (Relation) {
|
|
3636
|
+
Relation["Assignable"] = "assignable";
|
|
3637
|
+
Relation["Identical"] = "identical";
|
|
3638
|
+
})(Relation || (Relation = {}));
|
|
3639
|
+
|
|
3624
3640
|
class MatchWorker {
|
|
3625
3641
|
assertion;
|
|
3626
3642
|
#compiler;
|
|
@@ -3645,27 +3661,25 @@ class MatchWorker {
|
|
|
3645
3661
|
.some((property) => this.#compiler.unescapeLeadingUnderscores(property.escapedName) === propertyNameText);
|
|
3646
3662
|
}
|
|
3647
3663
|
checkIsAssignableTo(sourceNode, targetNode) {
|
|
3648
|
-
|
|
3649
|
-
return this.#checkIsRelatedTo(sourceNode, targetNode, relation);
|
|
3664
|
+
return this.#checkIsRelatedTo(sourceNode, targetNode, Relation.Assignable);
|
|
3650
3665
|
}
|
|
3651
3666
|
checkIsAssignableWith(sourceNode, targetNode) {
|
|
3652
|
-
|
|
3653
|
-
return this.#checkIsRelatedTo(targetNode, sourceNode, relation);
|
|
3667
|
+
return this.#checkIsRelatedTo(targetNode, sourceNode, Relation.Assignable);
|
|
3654
3668
|
}
|
|
3655
3669
|
checkIsIdenticalTo(sourceNode, targetNode) {
|
|
3656
|
-
|
|
3657
|
-
return (this.#checkIsRelatedTo(sourceNode, targetNode, relation) &&
|
|
3670
|
+
return (this.#checkIsRelatedTo(sourceNode, targetNode, Relation.Identical) &&
|
|
3658
3671
|
this.checkIsAssignableTo(sourceNode, targetNode) &&
|
|
3659
3672
|
this.checkIsAssignableWith(sourceNode, targetNode));
|
|
3660
3673
|
}
|
|
3661
3674
|
#checkIsRelatedTo(sourceNode, targetNode, relation) {
|
|
3662
|
-
const sourceType = relation === this.
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3675
|
+
const sourceType = relation === "identical" ? this.#simplifyType(this.getType(sourceNode)) : this.getType(sourceNode);
|
|
3676
|
+
const targetType = relation === "identical" ? this.#simplifyType(this.getType(targetNode)) : this.getType(targetNode);
|
|
3677
|
+
switch (relation) {
|
|
3678
|
+
case Relation.Assignable:
|
|
3679
|
+
return this.typeChecker.isTypeAssignableTo(sourceType, targetType);
|
|
3680
|
+
case Relation.Identical:
|
|
3681
|
+
return this.typeChecker.isTypeIdenticalTo(sourceType, targetType);
|
|
3682
|
+
}
|
|
3669
3683
|
}
|
|
3670
3684
|
extendsObjectType(type) {
|
|
3671
3685
|
const nonPrimitiveType = { flags: this.#compiler.TypeFlags.NonPrimitive };
|
|
@@ -3709,7 +3723,7 @@ class MatchWorker {
|
|
|
3709
3723
|
#simplifyType(type) {
|
|
3710
3724
|
if (type.isUnionOrIntersection()) {
|
|
3711
3725
|
const candidateType = this.#simplifyType(type.types[0]);
|
|
3712
|
-
if (type.types.every((type) => this.typeChecker.
|
|
3726
|
+
if (type.types.every((type) => this.typeChecker.isTypeIdenticalTo(this.#simplifyType(type), candidateType))) {
|
|
3713
3727
|
return candidateType;
|
|
3714
3728
|
}
|
|
3715
3729
|
}
|
|
@@ -3924,8 +3938,8 @@ class RelationMatcherBase {
|
|
|
3924
3938
|
}
|
|
3925
3939
|
|
|
3926
3940
|
class ToBe extends RelationMatcherBase {
|
|
3927
|
-
explainText = ExpectDiagnosticText.
|
|
3928
|
-
explainNotText = ExpectDiagnosticText.
|
|
3941
|
+
explainText = ExpectDiagnosticText.isTheSame;
|
|
3942
|
+
explainNotText = ExpectDiagnosticText.isNotTheSame;
|
|
3929
3943
|
match(matchWorker, sourceNode, targetNode) {
|
|
3930
3944
|
return {
|
|
3931
3945
|
explain: () => this.explain(matchWorker, sourceNode, targetNode),
|
|
@@ -4327,7 +4341,7 @@ class ToRaiseError {
|
|
|
4327
4341
|
|
|
4328
4342
|
class ExpectService {
|
|
4329
4343
|
#compiler;
|
|
4330
|
-
#
|
|
4344
|
+
#reject;
|
|
4331
4345
|
#typeChecker;
|
|
4332
4346
|
toAcceptProps;
|
|
4333
4347
|
toBe;
|
|
@@ -4338,15 +4352,10 @@ class ExpectService {
|
|
|
4338
4352
|
toBeConstructableWith;
|
|
4339
4353
|
toHaveProperty;
|
|
4340
4354
|
toRaiseError;
|
|
4341
|
-
constructor(compiler, typeChecker,
|
|
4355
|
+
constructor(compiler, typeChecker, reject) {
|
|
4342
4356
|
this.#compiler = compiler;
|
|
4357
|
+
this.#reject = reject;
|
|
4343
4358
|
this.#typeChecker = typeChecker;
|
|
4344
|
-
if (resolvedConfig?.rejectAnyType) {
|
|
4345
|
-
this.#rejectTypes.add("any");
|
|
4346
|
-
}
|
|
4347
|
-
if (resolvedConfig?.rejectNeverType) {
|
|
4348
|
-
this.#rejectTypes.add("never");
|
|
4349
|
-
}
|
|
4350
4359
|
this.toAcceptProps = new ToAcceptProps(compiler, typeChecker);
|
|
4351
4360
|
this.toBe = new ToBe();
|
|
4352
4361
|
this.toBeApplicable = new ToBeApplicable(compiler);
|
|
@@ -4359,13 +4368,15 @@ class ExpectService {
|
|
|
4359
4368
|
}
|
|
4360
4369
|
match(assertion, onDiagnostics) {
|
|
4361
4370
|
const matcherNameText = assertion.matcherNameNode.name.text;
|
|
4362
|
-
if (!assertion.source[0]) {
|
|
4363
|
-
this.#onSourceArgumentOrTypeArgumentMustBeProvided(assertion, onDiagnostics);
|
|
4371
|
+
if (!argumentOrTypeArgumentIsProvided("source", "Source", assertion.source[0], assertion.node.expression, onDiagnostics)) {
|
|
4364
4372
|
return;
|
|
4365
4373
|
}
|
|
4366
4374
|
const matchWorker = new MatchWorker(this.#compiler, this.#typeChecker, assertion);
|
|
4367
4375
|
if (!(matcherNameText === "toRaiseError" && assertion.isNot === false) &&
|
|
4368
|
-
this.#
|
|
4376
|
+
this.#reject.argumentType([
|
|
4377
|
+
["source", assertion.source[0]],
|
|
4378
|
+
["target", assertion.target?.[0]],
|
|
4379
|
+
], onDiagnostics)) {
|
|
4369
4380
|
return;
|
|
4370
4381
|
}
|
|
4371
4382
|
switch (matcherNameText) {
|
|
@@ -4373,8 +4384,7 @@ class ExpectService {
|
|
|
4373
4384
|
case "toBe":
|
|
4374
4385
|
case "toBeAssignableTo":
|
|
4375
4386
|
case "toBeAssignableWith":
|
|
4376
|
-
if (!assertion.target?.[0]) {
|
|
4377
|
-
this.#onTargetArgumentOrTypeArgumentMustBeProvided(assertion, onDiagnostics);
|
|
4387
|
+
if (!argumentOrTypeArgumentIsProvided("target", "Target", assertion.target?.[0], assertion.matcherNameNode.name, onDiagnostics)) {
|
|
4378
4388
|
return;
|
|
4379
4389
|
}
|
|
4380
4390
|
return this[matcherNameText].match(matchWorker, assertion.source[0], assertion.target[0], onDiagnostics);
|
|
@@ -4385,8 +4395,7 @@ class ExpectService {
|
|
|
4385
4395
|
case "toRaiseError":
|
|
4386
4396
|
return this[matcherNameText].match(matchWorker, assertion.source[0], assertion.target, onDiagnostics);
|
|
4387
4397
|
case "toHaveProperty":
|
|
4388
|
-
if (!assertion.target?.[0]) {
|
|
4389
|
-
this.#onTargetArgumentMustBeProvided("key", assertion, onDiagnostics);
|
|
4398
|
+
if (!argumentIsProvided("key", assertion.target?.[0], assertion.matcherNameNode.name, onDiagnostics)) {
|
|
4390
4399
|
return;
|
|
4391
4400
|
}
|
|
4392
4401
|
return this.toHaveProperty.match(matchWorker, assertion.source[0], assertion.target[0], onDiagnostics);
|
|
@@ -4400,42 +4409,61 @@ class ExpectService {
|
|
|
4400
4409
|
const origin = DiagnosticOrigin.fromNode(assertion.matcherNameNode.name);
|
|
4401
4410
|
onDiagnostics(Diagnostic.error(text, origin));
|
|
4402
4411
|
}
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
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.`;
|
|
4407
4421
|
}
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
const origin = DiagnosticOrigin.fromNode(assertion.matcherNameNode.name);
|
|
4411
|
-
onDiagnostics(Diagnostic.error(text, origin));
|
|
4422
|
+
static typeArgumentCannotBeOfType(argumentNameText, typeText) {
|
|
4423
|
+
return `A type argument for '${argumentNameText}' cannot be of the '${typeText}' type.`;
|
|
4412
4424
|
}
|
|
4413
|
-
|
|
4414
|
-
const
|
|
4415
|
-
|
|
4416
|
-
|
|
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
|
+
}
|
|
4417
4447
|
}
|
|
4418
|
-
|
|
4419
|
-
for (const rejectedType of this.#
|
|
4448
|
+
argumentType(target, onDiagnostics) {
|
|
4449
|
+
for (const rejectedType of this.#rejectedArgumentTypes) {
|
|
4420
4450
|
const allowedKeyword = this.#compiler.SyntaxKind[`${capitalize(rejectedType)}Keyword`];
|
|
4421
|
-
if (
|
|
4422
|
-
matchWorker.assertion.target?.[0]?.kind === allowedKeyword) {
|
|
4451
|
+
if (target.some(([, node]) => node?.kind === allowedKeyword)) {
|
|
4423
4452
|
continue;
|
|
4424
4453
|
}
|
|
4425
|
-
for (const
|
|
4426
|
-
|
|
4427
|
-
if (!argumentNode) {
|
|
4454
|
+
for (const [name, node] of target) {
|
|
4455
|
+
if (!node) {
|
|
4428
4456
|
continue;
|
|
4429
4457
|
}
|
|
4430
|
-
if (
|
|
4458
|
+
if (this.#typeChecker.getTypeAtLocation(node).flags & this.#compiler.TypeFlags[capitalize(rejectedType)]) {
|
|
4431
4459
|
const text = [
|
|
4432
|
-
nodeBelongsToArgumentList(this.#compiler,
|
|
4433
|
-
?
|
|
4434
|
-
:
|
|
4435
|
-
...
|
|
4460
|
+
nodeBelongsToArgumentList(this.#compiler, node)
|
|
4461
|
+
? RejectDiagnosticText.argumentCannotBeOfType(name, rejectedType)
|
|
4462
|
+
: RejectDiagnosticText.typeArgumentCannotBeOfType(capitalize(name), rejectedType),
|
|
4463
|
+
...RejectDiagnosticText.typeWasRejected(rejectedType),
|
|
4436
4464
|
];
|
|
4437
|
-
const origin = DiagnosticOrigin.fromNode(
|
|
4438
|
-
onDiagnostics(Diagnostic.error(text, origin));
|
|
4465
|
+
const origin = DiagnosticOrigin.fromNode(node);
|
|
4466
|
+
onDiagnostics([Diagnostic.error(text, origin)]);
|
|
4439
4467
|
return true;
|
|
4440
4468
|
}
|
|
4441
4469
|
}
|
|
@@ -4444,20 +4472,78 @@ class ExpectService {
|
|
|
4444
4472
|
}
|
|
4445
4473
|
}
|
|
4446
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
|
+
|
|
4447
4530
|
class TestTreeWalker {
|
|
4448
4531
|
#cancellationToken;
|
|
4449
4532
|
#expectService;
|
|
4450
4533
|
#hasOnly;
|
|
4534
|
+
#onTaskDiagnostics;
|
|
4451
4535
|
#position;
|
|
4452
4536
|
#resolvedConfig;
|
|
4453
|
-
#
|
|
4454
|
-
constructor(compiler, typeChecker, resolvedConfig, options) {
|
|
4537
|
+
#whenService;
|
|
4538
|
+
constructor(compiler, typeChecker, resolvedConfig, onTaskDiagnostics, options) {
|
|
4455
4539
|
this.#resolvedConfig = resolvedConfig;
|
|
4540
|
+
this.#onTaskDiagnostics = onTaskDiagnostics;
|
|
4456
4541
|
this.#cancellationToken = options.cancellationToken;
|
|
4457
4542
|
this.#hasOnly = options.hasOnly || resolvedConfig.only != null || options.position != null;
|
|
4458
4543
|
this.#position = options.position;
|
|
4459
|
-
|
|
4460
|
-
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);
|
|
4461
4547
|
}
|
|
4462
4548
|
#resolveRunMode(mode, testNode) {
|
|
4463
4549
|
if (testNode.flags & TestTreeNodeFlags.Fail) {
|
|
@@ -4482,28 +4568,23 @@ class TestTreeWalker {
|
|
|
4482
4568
|
}
|
|
4483
4569
|
return mode;
|
|
4484
4570
|
}
|
|
4485
|
-
visit(
|
|
4486
|
-
for (const
|
|
4571
|
+
visit(nodes, runMode, parentResult) {
|
|
4572
|
+
for (const node of nodes) {
|
|
4487
4573
|
if (this.#cancellationToken?.isCancellationRequested) {
|
|
4488
4574
|
break;
|
|
4489
4575
|
}
|
|
4490
|
-
|
|
4491
|
-
if (validationError.length > 0) {
|
|
4492
|
-
EventEmitter.dispatch(["task:error", { diagnostics: validationError, result: this.#taskResult }]);
|
|
4493
|
-
break;
|
|
4494
|
-
}
|
|
4495
|
-
switch (testNode.brand) {
|
|
4576
|
+
switch (node.brand) {
|
|
4496
4577
|
case TestTreeNodeBrand.Describe:
|
|
4497
|
-
this.#visitDescribe(
|
|
4578
|
+
this.#visitDescribe(node, runMode, parentResult);
|
|
4498
4579
|
break;
|
|
4499
4580
|
case TestTreeNodeBrand.Test:
|
|
4500
|
-
this.#visitTest(
|
|
4581
|
+
this.#visitTest(node, runMode, parentResult);
|
|
4501
4582
|
break;
|
|
4502
4583
|
case TestTreeNodeBrand.Expect:
|
|
4503
|
-
this.#visitAssertion(
|
|
4584
|
+
this.#visitAssertion(node, runMode, parentResult);
|
|
4504
4585
|
break;
|
|
4505
4586
|
case TestTreeNodeBrand.When:
|
|
4506
|
-
this.#visitWhen(
|
|
4587
|
+
this.#visitWhen(node);
|
|
4507
4588
|
break;
|
|
4508
4589
|
}
|
|
4509
4590
|
}
|
|
@@ -4554,13 +4635,7 @@ class TestTreeWalker {
|
|
|
4554
4635
|
runMode = this.#resolveRunMode(runMode, describe);
|
|
4555
4636
|
if (!(runMode & RunMode.Skip || (this.#hasOnly && !(runMode & RunMode.Only)) || runMode & RunMode.Todo) &&
|
|
4556
4637
|
describe.diagnostics.size > 0) {
|
|
4557
|
-
|
|
4558
|
-
"task:error",
|
|
4559
|
-
{
|
|
4560
|
-
diagnostics: Diagnostic.fromDiagnostics([...describe.diagnostics]),
|
|
4561
|
-
result: this.#taskResult,
|
|
4562
|
-
},
|
|
4563
|
-
]);
|
|
4638
|
+
this.#onTaskDiagnostics(Diagnostic.fromDiagnostics([...describe.diagnostics]));
|
|
4564
4639
|
}
|
|
4565
4640
|
else {
|
|
4566
4641
|
this.visit(describe.children, runMode, describeResult);
|
|
@@ -4597,37 +4672,14 @@ class TestTreeWalker {
|
|
|
4597
4672
|
EventEmitter.dispatch(["test:pass", { result: testResult }]);
|
|
4598
4673
|
}
|
|
4599
4674
|
}
|
|
4600
|
-
#visitWhen(when
|
|
4601
|
-
|
|
4602
|
-
const diagnostics = [];
|
|
4603
|
-
for (const diagnostic of when.abilityDiagnostics) {
|
|
4604
|
-
if (isDiagnosticWithLocation(diagnostic)) {
|
|
4605
|
-
const text = getDiagnosticMessageText(diagnostic);
|
|
4606
|
-
let origin;
|
|
4607
|
-
if (isDiagnosticWithLocation(diagnostic) && diagnosticBelongsToNode(diagnostic, when.node)) {
|
|
4608
|
-
origin = DiagnosticOrigin.fromNodes(when.target);
|
|
4609
|
-
}
|
|
4610
|
-
else {
|
|
4611
|
-
origin = new DiagnosticOrigin(diagnostic.start, getTextSpanEnd(diagnostic), when.node.getSourceFile());
|
|
4612
|
-
}
|
|
4613
|
-
let related;
|
|
4614
|
-
if (diagnostic.relatedInformation != null) {
|
|
4615
|
-
related = Diagnostic.fromDiagnostics(diagnostic.relatedInformation);
|
|
4616
|
-
}
|
|
4617
|
-
diagnostics.push(Diagnostic.error(text, origin).add({ related }));
|
|
4618
|
-
}
|
|
4619
|
-
}
|
|
4620
|
-
EventEmitter.dispatch(["task:error", { diagnostics, result: this.#taskResult }]);
|
|
4621
|
-
return;
|
|
4622
|
-
}
|
|
4623
|
-
this.visit(when.children, runMode, parentResult);
|
|
4675
|
+
#visitWhen(when) {
|
|
4676
|
+
this.#whenService.action(when);
|
|
4624
4677
|
}
|
|
4625
4678
|
}
|
|
4626
4679
|
|
|
4627
4680
|
class TaskRunner {
|
|
4628
4681
|
#collectService;
|
|
4629
4682
|
#compiler;
|
|
4630
|
-
#eventEmitter = new EventEmitter();
|
|
4631
4683
|
#resolvedConfig;
|
|
4632
4684
|
#projectService;
|
|
4633
4685
|
constructor(compiler, resolvedConfig) {
|
|
@@ -4689,21 +4741,17 @@ class TaskRunner {
|
|
|
4689
4741
|
if (!sourceFile) {
|
|
4690
4742
|
return;
|
|
4691
4743
|
}
|
|
4692
|
-
const cancellationHandler = new CancellationHandler(cancellationToken, CancellationReason.CollectError);
|
|
4693
|
-
this.#eventEmitter.addHandler(cancellationHandler);
|
|
4694
4744
|
const testTree = this.#collectService.createTestTree(sourceFile, semanticDiagnostics);
|
|
4695
|
-
this.#eventEmitter.removeHandler(cancellationHandler);
|
|
4696
|
-
if (cancellationToken.isCancellationRequested) {
|
|
4697
|
-
return;
|
|
4698
|
-
}
|
|
4699
4745
|
if (testTree.diagnostics.size > 0) {
|
|
4700
4746
|
this.#onDiagnostics(Diagnostic.fromDiagnostics([...testTree.diagnostics]), taskResult);
|
|
4701
4747
|
return;
|
|
4702
4748
|
}
|
|
4703
4749
|
const typeChecker = program?.getTypeChecker();
|
|
4704
|
-
const
|
|
4750
|
+
const onTaskDiagnostics = (diagnostics) => {
|
|
4751
|
+
this.#onDiagnostics(diagnostics, taskResult);
|
|
4752
|
+
};
|
|
4753
|
+
const testTreeWalker = new TestTreeWalker(this.#compiler, typeChecker, this.#resolvedConfig, onTaskDiagnostics, {
|
|
4705
4754
|
cancellationToken,
|
|
4706
|
-
taskResult,
|
|
4707
4755
|
hasOnly: testTree.hasOnly,
|
|
4708
4756
|
position: task.position,
|
|
4709
4757
|
});
|
|
@@ -4714,7 +4762,7 @@ class TaskRunner {
|
|
|
4714
4762
|
class Runner {
|
|
4715
4763
|
#eventEmitter = new EventEmitter();
|
|
4716
4764
|
#resolvedConfig;
|
|
4717
|
-
static version = "4.0.0-
|
|
4765
|
+
static version = "4.0.0-rc.0";
|
|
4718
4766
|
constructor(resolvedConfig) {
|
|
4719
4767
|
this.#resolvedConfig = resolvedConfig;
|
|
4720
4768
|
}
|
|
@@ -4914,4 +4962,4 @@ class Cli {
|
|
|
4914
4962
|
}
|
|
4915
4963
|
}
|
|
4916
4964
|
|
|
4917
|
-
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 };
|