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/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 (this.#supportedVersionRegex.test(tag)) {
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
- if (compiler.isCallExpression(node.parent)) {
2971
- return node.parent.arguments.some((argument) => argument === node);
2972
- }
2973
- return false;
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
- replacement: nodeBelongsToArgumentList(this.#compiler, whenNode.actionNode) ? "" : ";",
3011
+ end: whenExpressionEnd,
3012
+ replacement: nodeIsChildOfExpressionStatement(this.#compiler, whenNode.actionNode) ? ";" : "",
3048
3013
  },
3049
- { end: actionNameEnd, start: whenEnd },
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
- { end: expectExpressionEnd, start: expectStart },
3063
- { end: matcherNameEnd, start: expectEnd },
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
- replacement: nodeBelongsToArgumentList(this.#compiler, assertionNode.matcherNode) ? "" : ";",
3036
+ end: expectExpressionEnd,
3037
+ replacement: nodeIsChildOfExpressionStatement(this.#compiler, assertionNode.matcherNode) ? ";" : "",
3072
3038
  },
3073
- { end: matcherNameEnd, start: expectEnd },
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
- replacement: nodeBelongsToArgumentList(this.#compiler, assertionNode.matcherNode) ? "new" : "; new",
3047
+ end: expectExpressionEnd,
3048
+ replacement: nodeIsChildOfExpressionStatement(this.#compiler, assertionNode.matcherNode) ? "; new" : "new",
3082
3049
  },
3083
- { end: matcherNameEnd, start: expectEnd },
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, identifiers) {
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
- resolveTestMemberMeta(node) {
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.#projectService = projectService;
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.resolveTestMemberMeta(node);
3249
- if (meta != null && (meta.brand === TestTreeNodeBrand.Describe || meta.brand === TestTreeNodeBrand.Test)) {
3250
- const testTreeNode = new TestTreeNode(this.#compiler, meta.brand, node, parent, meta.flags);
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
- const matcherNode = this.#getMatcherNode(matcherNameNode);
3268
- if (!matcherNode) {
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
- const assertionNode = new AssertionNode(this.#compiler, meta.brand, node, parent, meta.flags, matcherNode, matcherNameNode, modifierNode, notNode);
3272
- this.#abilityLayer.handleAssertion(assertionNode);
3273
- this.#compiler.forEachChild(node, (node) => {
3274
- this.#collectTestTreeNodes(node, assertionNode);
3275
- });
3276
- this.#onNode(assertionNode, parent);
3277
- return;
3278
- }
3279
- if (meta != null && meta.brand === TestTreeNodeBrand.When) {
3280
- const actionNameNode = this.#getChainedNode(node);
3281
- if (!actionNameNode) {
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
- const actionNode = this.#getActionNode(actionNameNode);
3285
- if (!actionNode) {
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.#collectTestTreeNodes(sourceFile, testTree);
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
- this.#testTree.hasOnly = true;
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
- function capitalize(text) {
3508
- return text.replace(/^./, text.charAt(0).toUpperCase());
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 argumentMustBeProvided(argumentNameText) {
3522
- return `An argument for '${argumentNameText}' must be provided.`;
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 isIdenticalTo(sourceTypeText, targetTypeText) {
3601
- return `Type '${sourceTypeText}' is identical to type '${targetTypeText}'.`;
3617
+ static isTheSame(sourceTypeText, targetTypeText) {
3618
+ return `Type '${sourceTypeText}' is the same as type '${targetTypeText}'.`;
3602
3619
  }
3603
- static isNotIdenticalTo(sourceTypeText, targetTypeText) {
3604
- return `Type '${sourceTypeText}' is not identical to type '${targetTypeText}'.`;
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
- const relation = this.typeChecker.relation.assignable;
3649
- return this.#checkIsRelatedTo(sourceNode, targetNode, relation);
3664
+ return this.#checkIsRelatedTo(sourceNode, targetNode, Relation.Assignable);
3650
3665
  }
3651
3666
  checkIsAssignableWith(sourceNode, targetNode) {
3652
- const relation = this.typeChecker.relation.assignable;
3653
- return this.#checkIsRelatedTo(targetNode, sourceNode, relation);
3667
+ return this.#checkIsRelatedTo(targetNode, sourceNode, Relation.Assignable);
3654
3668
  }
3655
3669
  checkIsIdenticalTo(sourceNode, targetNode) {
3656
- const relation = this.typeChecker.relation.identity;
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.typeChecker.relation.identity
3663
- ? this.#simplifyType(this.getType(sourceNode))
3664
- : this.getType(sourceNode);
3665
- const targetType = relation === this.typeChecker.relation.identity
3666
- ? this.#simplifyType(this.getType(targetNode))
3667
- : this.getType(targetNode);
3668
- return this.typeChecker.isTypeRelatedTo(sourceType, targetType, relation);
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.isTypeRelatedTo(this.#simplifyType(type), candidateType, this.typeChecker.relation.identity))) {
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.isIdenticalTo;
3928
- explainNotText = ExpectDiagnosticText.isNotIdenticalTo;
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
- #rejectTypes = new Set();
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, resolvedConfig) {
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.#rejectsTypeArguments(matchWorker, onDiagnostics)) {
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
- #onSourceArgumentOrTypeArgumentMustBeProvided(assertion, onDiagnostics) {
4404
- const text = ExpectDiagnosticText.argumentOrTypeArgumentMustBeProvided("source", "Source");
4405
- const origin = DiagnosticOrigin.fromNode(assertion.node.expression);
4406
- onDiagnostics(Diagnostic.error(text, origin));
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
- #onTargetArgumentMustBeProvided(argumentNameText, assertion, onDiagnostics) {
4409
- const text = ExpectDiagnosticText.argumentMustBeProvided(argumentNameText);
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
- #onTargetArgumentOrTypeArgumentMustBeProvided(assertion, onDiagnostics) {
4414
- const text = ExpectDiagnosticText.argumentOrTypeArgumentMustBeProvided("target", "Target");
4415
- const origin = DiagnosticOrigin.fromNode(assertion.matcherNameNode.name);
4416
- onDiagnostics(Diagnostic.error(text, origin));
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
- #rejectsTypeArguments(matchWorker, onDiagnostics) {
4419
- for (const rejectedType of this.#rejectTypes) {
4448
+ argumentType(target, onDiagnostics) {
4449
+ for (const rejectedType of this.#rejectedArgumentTypes) {
4420
4450
  const allowedKeyword = this.#compiler.SyntaxKind[`${capitalize(rejectedType)}Keyword`];
4421
- if (matchWorker.assertion.source[0]?.kind === allowedKeyword ||
4422
- matchWorker.assertion.target?.[0]?.kind === allowedKeyword) {
4451
+ if (target.some(([, node]) => node?.kind === allowedKeyword)) {
4423
4452
  continue;
4424
4453
  }
4425
- for (const argumentName of ["source", "target"]) {
4426
- const argumentNode = matchWorker.assertion[argumentName]?.[0];
4427
- if (!argumentNode) {
4454
+ for (const [name, node] of target) {
4455
+ if (!node) {
4428
4456
  continue;
4429
4457
  }
4430
- if (matchWorker.getType(argumentNode).flags & this.#compiler.TypeFlags[capitalize(rejectedType)]) {
4458
+ if (this.#typeChecker.getTypeAtLocation(node).flags & this.#compiler.TypeFlags[capitalize(rejectedType)]) {
4431
4459
  const text = [
4432
- nodeBelongsToArgumentList(this.#compiler, argumentNode)
4433
- ? ExpectDiagnosticText.argumentCannotBeOfType(argumentName, rejectedType)
4434
- : ExpectDiagnosticText.typeArgumentCannotBeOfType(capitalize(argumentName), rejectedType),
4435
- ...ExpectDiagnosticText.typeWasRejected(rejectedType),
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(argumentNode);
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
- #taskResult;
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
- this.#taskResult = options.taskResult;
4460
- this.#expectService = new ExpectService(compiler, typeChecker, this.#resolvedConfig);
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(testNodes, runMode, parentResult) {
4486
- for (const testNode of testNodes) {
4571
+ visit(nodes, runMode, parentResult) {
4572
+ for (const node of nodes) {
4487
4573
  if (this.#cancellationToken?.isCancellationRequested) {
4488
4574
  break;
4489
4575
  }
4490
- const validationError = testNode.validate();
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(testNode, runMode, parentResult);
4578
+ this.#visitDescribe(node, runMode, parentResult);
4498
4579
  break;
4499
4580
  case TestTreeNodeBrand.Test:
4500
- this.#visitTest(testNode, runMode, parentResult);
4581
+ this.#visitTest(node, runMode, parentResult);
4501
4582
  break;
4502
4583
  case TestTreeNodeBrand.Expect:
4503
- this.#visitAssertion(testNode, runMode, parentResult);
4584
+ this.#visitAssertion(node, runMode, parentResult);
4504
4585
  break;
4505
4586
  case TestTreeNodeBrand.When:
4506
- this.#visitWhen(testNode, runMode, parentResult);
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
- EventEmitter.dispatch([
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, runMode, parentResult) {
4601
- if (when.abilityDiagnostics != null && when.abilityDiagnostics.size > 0) {
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 testTreeWalker = new TestTreeWalker(this.#compiler, typeChecker, this.#resolvedConfig, {
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-beta.8";
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 };