tstyche 4.0.0-beta.7 → 4.0.0-beta.8
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 +64 -60
- package/package.json +2 -2
package/build/tstyche.js
CHANGED
|
@@ -3173,27 +3173,27 @@ class IdentifierLookup {
|
|
|
3173
3173
|
}
|
|
3174
3174
|
expression = expression.expression;
|
|
3175
3175
|
}
|
|
3176
|
-
let
|
|
3176
|
+
let identifier;
|
|
3177
3177
|
if (this.#compiler.isPropertyAccessExpression(expression) &&
|
|
3178
3178
|
expression.expression.getText() === this.#identifiers.namespace) {
|
|
3179
|
-
|
|
3179
|
+
identifier = expression.name.getText();
|
|
3180
3180
|
}
|
|
3181
3181
|
else {
|
|
3182
|
-
|
|
3182
|
+
identifier = Object.keys(this.#identifiers.namedImports).find((key) => this.#identifiers.namedImports[key] === expression.getText());
|
|
3183
3183
|
}
|
|
3184
|
-
if (!
|
|
3184
|
+
if (!identifier) {
|
|
3185
3185
|
return;
|
|
3186
3186
|
}
|
|
3187
|
-
switch (
|
|
3187
|
+
switch (identifier) {
|
|
3188
3188
|
case "describe":
|
|
3189
|
-
return { brand: TestTreeNodeBrand.Describe, flags };
|
|
3189
|
+
return { brand: TestTreeNodeBrand.Describe, flags, identifier };
|
|
3190
3190
|
case "it":
|
|
3191
3191
|
case "test":
|
|
3192
|
-
return { brand: TestTreeNodeBrand.Test, flags };
|
|
3192
|
+
return { brand: TestTreeNodeBrand.Test, flags, identifier };
|
|
3193
3193
|
case "expect":
|
|
3194
|
-
return { brand: TestTreeNodeBrand.Expect, flags };
|
|
3194
|
+
return { brand: TestTreeNodeBrand.Expect, flags, identifier };
|
|
3195
3195
|
case "when":
|
|
3196
|
-
return { brand: TestTreeNodeBrand.When, flags };
|
|
3196
|
+
return { brand: TestTreeNodeBrand.When, flags, identifier };
|
|
3197
3197
|
}
|
|
3198
3198
|
return;
|
|
3199
3199
|
}
|
|
@@ -3232,6 +3232,7 @@ class WhenNode extends TestTreeNode {
|
|
|
3232
3232
|
class CollectService {
|
|
3233
3233
|
#abilityLayer;
|
|
3234
3234
|
#compiler;
|
|
3235
|
+
#identifierLookup;
|
|
3235
3236
|
#projectService;
|
|
3236
3237
|
#resolvedConfig;
|
|
3237
3238
|
#testTree;
|
|
@@ -3240,14 +3241,15 @@ class CollectService {
|
|
|
3240
3241
|
this.#projectService = projectService;
|
|
3241
3242
|
this.#resolvedConfig = resolvedConfig;
|
|
3242
3243
|
this.#abilityLayer = new AbilityLayer(compiler, this.#projectService, this.#resolvedConfig);
|
|
3244
|
+
this.#identifierLookup = new IdentifierLookup(compiler);
|
|
3243
3245
|
}
|
|
3244
|
-
#collectTestTreeNodes(node,
|
|
3246
|
+
#collectTestTreeNodes(node, parent) {
|
|
3245
3247
|
if (this.#compiler.isCallExpression(node)) {
|
|
3246
|
-
const meta =
|
|
3248
|
+
const meta = this.#identifierLookup.resolveTestMemberMeta(node);
|
|
3247
3249
|
if (meta != null && (meta.brand === TestTreeNodeBrand.Describe || meta.brand === TestTreeNodeBrand.Test)) {
|
|
3248
3250
|
const testTreeNode = new TestTreeNode(this.#compiler, meta.brand, node, parent, meta.flags);
|
|
3249
3251
|
this.#compiler.forEachChild(node, (node) => {
|
|
3250
|
-
this.#collectTestTreeNodes(node,
|
|
3252
|
+
this.#collectTestTreeNodes(node, testTreeNode);
|
|
3251
3253
|
});
|
|
3252
3254
|
this.#onNode(testTreeNode, parent);
|
|
3253
3255
|
return;
|
|
@@ -3269,7 +3271,7 @@ class CollectService {
|
|
|
3269
3271
|
const assertionNode = new AssertionNode(this.#compiler, meta.brand, node, parent, meta.flags, matcherNode, matcherNameNode, modifierNode, notNode);
|
|
3270
3272
|
this.#abilityLayer.handleAssertion(assertionNode);
|
|
3271
3273
|
this.#compiler.forEachChild(node, (node) => {
|
|
3272
|
-
this.#collectTestTreeNodes(node,
|
|
3274
|
+
this.#collectTestTreeNodes(node, assertionNode);
|
|
3273
3275
|
});
|
|
3274
3276
|
this.#onNode(assertionNode, parent);
|
|
3275
3277
|
return;
|
|
@@ -3285,9 +3287,9 @@ class CollectService {
|
|
|
3285
3287
|
}
|
|
3286
3288
|
this.#compiler.forEachChild(actionNode, (node) => {
|
|
3287
3289
|
if (this.#compiler.isCallExpression(node)) {
|
|
3288
|
-
const meta =
|
|
3290
|
+
const meta = this.#identifierLookup.resolveTestMemberMeta(node);
|
|
3289
3291
|
if (meta != null && (meta.brand === TestTreeNodeBrand.Describe || meta.brand === TestTreeNodeBrand.Test)) {
|
|
3290
|
-
const text = CollectDiagnosticText.cannotBeNestedWithin(
|
|
3292
|
+
const text = CollectDiagnosticText.cannotBeNestedWithin(meta.identifier, "when");
|
|
3291
3293
|
const origin = DiagnosticOrigin.fromNode(node);
|
|
3292
3294
|
this.#onDiagnostics(Diagnostic.error(text, origin));
|
|
3293
3295
|
}
|
|
@@ -3300,11 +3302,11 @@ class CollectService {
|
|
|
3300
3302
|
}
|
|
3301
3303
|
}
|
|
3302
3304
|
if (this.#compiler.isImportDeclaration(node)) {
|
|
3303
|
-
|
|
3305
|
+
this.#identifierLookup.handleImportDeclaration(node);
|
|
3304
3306
|
return;
|
|
3305
3307
|
}
|
|
3306
3308
|
this.#compiler.forEachChild(node, (node) => {
|
|
3307
|
-
this.#collectTestTreeNodes(node,
|
|
3309
|
+
this.#collectTestTreeNodes(node, parent);
|
|
3308
3310
|
});
|
|
3309
3311
|
}
|
|
3310
3312
|
createTestTree(sourceFile, semanticDiagnostics = []) {
|
|
@@ -3312,7 +3314,7 @@ class CollectService {
|
|
|
3312
3314
|
EventEmitter.dispatch(["collect:start", { tree: testTree }]);
|
|
3313
3315
|
this.#testTree = testTree;
|
|
3314
3316
|
this.#abilityLayer.open(sourceFile);
|
|
3315
|
-
this.#collectTestTreeNodes(sourceFile,
|
|
3317
|
+
this.#collectTestTreeNodes(sourceFile, testTree);
|
|
3316
3318
|
this.#abilityLayer.close();
|
|
3317
3319
|
this.#testTree = undefined;
|
|
3318
3320
|
EventEmitter.dispatch(["collect:end", { tree: testTree }]);
|
|
@@ -3362,6 +3364,7 @@ class ProjectService {
|
|
|
3362
3364
|
#lastSeenProject = "";
|
|
3363
3365
|
#resolvedConfig;
|
|
3364
3366
|
#seenPrograms = new WeakSet();
|
|
3367
|
+
#seenTestFiles = new Set();
|
|
3365
3368
|
#service;
|
|
3366
3369
|
constructor(compiler, resolvedConfig) {
|
|
3367
3370
|
this.#compiler = compiler;
|
|
@@ -3399,15 +3402,6 @@ class ProjectService {
|
|
|
3399
3402
|
useInferredProjectPerProjectRoot: true,
|
|
3400
3403
|
useSingleInferredProject: false,
|
|
3401
3404
|
});
|
|
3402
|
-
switch (this.#resolvedConfig.tsconfig) {
|
|
3403
|
-
case "findup":
|
|
3404
|
-
break;
|
|
3405
|
-
case "ignore":
|
|
3406
|
-
this.#service.getConfigFileNameForFile = () => undefined;
|
|
3407
|
-
break;
|
|
3408
|
-
default:
|
|
3409
|
-
this.#service.getConfigFileNameForFile = () => this.#resolvedConfig.tsconfig;
|
|
3410
|
-
}
|
|
3411
3405
|
this.#service.setCompilerOptionsForInferredProjects(this.#getDefaultCompilerOptions());
|
|
3412
3406
|
}
|
|
3413
3407
|
closeFile(filePath) {
|
|
@@ -3442,7 +3436,23 @@ class ProjectService {
|
|
|
3442
3436
|
const project = this.getDefaultProject(filePath);
|
|
3443
3437
|
return project?.getLanguageService(true);
|
|
3444
3438
|
}
|
|
3439
|
+
#isFileIncluded(filePath) {
|
|
3440
|
+
const configSourceFile = this.#compiler.readJsonConfigFile(this.#resolvedConfig.tsconfig, this.#compiler.sys.readFile);
|
|
3441
|
+
const { fileNames } = this.#compiler.parseJsonSourceFileConfigFileContent(configSourceFile, this.#compiler.sys, Path.dirname(this.#resolvedConfig.tsconfig), undefined, this.#resolvedConfig.tsconfig);
|
|
3442
|
+
return fileNames.includes(filePath);
|
|
3443
|
+
}
|
|
3445
3444
|
openFile(filePath, sourceText, projectRootPath) {
|
|
3445
|
+
switch (this.#resolvedConfig.tsconfig) {
|
|
3446
|
+
case "findup":
|
|
3447
|
+
break;
|
|
3448
|
+
case "ignore":
|
|
3449
|
+
this.#service.getConfigFileNameForFile = () => undefined;
|
|
3450
|
+
break;
|
|
3451
|
+
default:
|
|
3452
|
+
this.#service.getConfigFileNameForFile = this.#isFileIncluded(filePath)
|
|
3453
|
+
? () => this.#resolvedConfig.tsconfig
|
|
3454
|
+
: () => undefined;
|
|
3455
|
+
}
|
|
3446
3456
|
const { configFileErrors, configFileName } = this.#service.openClientFile(filePath, sourceText, undefined, projectRootPath);
|
|
3447
3457
|
if (configFileName !== this.#lastSeenProject) {
|
|
3448
3458
|
this.#lastSeenProject = configFileName;
|
|
@@ -3457,29 +3467,29 @@ class ProjectService {
|
|
|
3457
3467
|
{ diagnostics: Diagnostic.fromDiagnostics(configFileErrors) },
|
|
3458
3468
|
]);
|
|
3459
3469
|
}
|
|
3460
|
-
if (this.#resolvedConfig.checkSourceFiles && !
|
|
3470
|
+
if (this.#resolvedConfig.checkSourceFiles && !this.#seenTestFiles.has(filePath)) {
|
|
3471
|
+
this.#seenTestFiles.add(filePath);
|
|
3461
3472
|
const languageService = this.getLanguageService(filePath);
|
|
3462
3473
|
const program = languageService?.getProgram();
|
|
3463
3474
|
if (!program || this.#seenPrograms.has(program)) {
|
|
3464
3475
|
return;
|
|
3465
3476
|
}
|
|
3466
3477
|
this.#seenPrograms.add(program);
|
|
3467
|
-
const
|
|
3468
|
-
for (const sourceFile of program.getSourceFiles()) {
|
|
3478
|
+
const sourceFilesToCheck = program.getSourceFiles().filter((sourceFile) => {
|
|
3469
3479
|
if (program.isSourceFileFromExternalLibrary(sourceFile) || program.isSourceFileDefaultLibrary(sourceFile)) {
|
|
3470
|
-
|
|
3480
|
+
return false;
|
|
3471
3481
|
}
|
|
3472
|
-
if (
|
|
3473
|
-
|
|
3482
|
+
if (Select.isTestFile(sourceFile.fileName, { ...this.#resolvedConfig, pathMatch: [] })) {
|
|
3483
|
+
return false;
|
|
3474
3484
|
}
|
|
3475
|
-
|
|
3485
|
+
return true;
|
|
3486
|
+
});
|
|
3476
3487
|
const diagnostics = [];
|
|
3477
|
-
for (const sourceFile of
|
|
3488
|
+
for (const sourceFile of sourceFilesToCheck) {
|
|
3478
3489
|
diagnostics.push(...program.getSyntacticDiagnostics(sourceFile), ...program.getSemanticDiagnostics(sourceFile));
|
|
3479
3490
|
}
|
|
3480
3491
|
if (diagnostics.length > 0) {
|
|
3481
3492
|
EventEmitter.dispatch(["project:error", { diagnostics: Diagnostic.fromDiagnostics(diagnostics) }]);
|
|
3482
|
-
return;
|
|
3483
3493
|
}
|
|
3484
3494
|
}
|
|
3485
3495
|
}
|
|
@@ -4587,7 +4597,7 @@ class TestTreeWalker {
|
|
|
4587
4597
|
EventEmitter.dispatch(["test:pass", { result: testResult }]);
|
|
4588
4598
|
}
|
|
4589
4599
|
}
|
|
4590
|
-
#visitWhen(when,
|
|
4600
|
+
#visitWhen(when, runMode, parentResult) {
|
|
4591
4601
|
if (when.abilityDiagnostics != null && when.abilityDiagnostics.size > 0) {
|
|
4592
4602
|
const diagnostics = [];
|
|
4593
4603
|
for (const diagnostic of when.abilityDiagnostics) {
|
|
@@ -4610,6 +4620,7 @@ class TestTreeWalker {
|
|
|
4610
4620
|
EventEmitter.dispatch(["task:error", { diagnostics, result: this.#taskResult }]);
|
|
4611
4621
|
return;
|
|
4612
4622
|
}
|
|
4623
|
+
this.visit(when.children, runMode, parentResult);
|
|
4613
4624
|
}
|
|
4614
4625
|
}
|
|
4615
4626
|
|
|
@@ -4625,6 +4636,9 @@ class TaskRunner {
|
|
|
4625
4636
|
this.#projectService = new ProjectService(compiler, this.#resolvedConfig);
|
|
4626
4637
|
this.#collectService = new CollectService(compiler, this.#projectService, this.#resolvedConfig);
|
|
4627
4638
|
}
|
|
4639
|
+
#onDiagnostics(diagnostics, result) {
|
|
4640
|
+
EventEmitter.dispatch(["task:error", { diagnostics, result }]);
|
|
4641
|
+
}
|
|
4628
4642
|
async run(task, cancellationToken) {
|
|
4629
4643
|
if (cancellationToken.isCancellationRequested) {
|
|
4630
4644
|
return;
|
|
@@ -4638,19 +4652,13 @@ class TaskRunner {
|
|
|
4638
4652
|
}
|
|
4639
4653
|
async #run(task, taskResult, cancellationToken) {
|
|
4640
4654
|
if (!existsSync(task.filePath)) {
|
|
4641
|
-
|
|
4642
|
-
"task:error",
|
|
4643
|
-
{ diagnostics: [Diagnostic.error(`Test file '${task.filePath}' does not exist.`)], result: taskResult },
|
|
4644
|
-
]);
|
|
4655
|
+
this.#onDiagnostics([Diagnostic.error(`Test file '${task.filePath}' does not exist.`)], taskResult);
|
|
4645
4656
|
return;
|
|
4646
4657
|
}
|
|
4647
4658
|
let languageService = this.#projectService.getLanguageService(task.filePath);
|
|
4648
4659
|
const syntacticDiagnostics = languageService?.getSyntacticDiagnostics(task.filePath);
|
|
4649
4660
|
if (syntacticDiagnostics != null && syntacticDiagnostics.length > 0) {
|
|
4650
|
-
|
|
4651
|
-
"task:error",
|
|
4652
|
-
{ diagnostics: Diagnostic.fromDiagnostics(syntacticDiagnostics), result: taskResult },
|
|
4653
|
-
]);
|
|
4661
|
+
this.#onDiagnostics(Diagnostic.fromDiagnostics(syntacticDiagnostics), taskResult);
|
|
4654
4662
|
return;
|
|
4655
4663
|
}
|
|
4656
4664
|
let semanticDiagnostics = languageService?.getSemanticDiagnostics(task.filePath);
|
|
@@ -4658,21 +4666,20 @@ class TaskRunner {
|
|
|
4658
4666
|
let sourceFile = program?.getSourceFile(task.filePath);
|
|
4659
4667
|
if (sourceFile?.text.startsWith("// @tstyche-template")) {
|
|
4660
4668
|
if (semanticDiagnostics != null && semanticDiagnostics.length > 0) {
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4669
|
+
this.#onDiagnostics(Diagnostic.fromDiagnostics(semanticDiagnostics), taskResult);
|
|
4670
|
+
return;
|
|
4671
|
+
}
|
|
4672
|
+
const moduleSpecifier = pathToFileURL(task.filePath).toString();
|
|
4673
|
+
const testText = (await import(moduleSpecifier))?.default;
|
|
4674
|
+
if (typeof testText !== "string") {
|
|
4675
|
+
this.#onDiagnostics([Diagnostic.error("A template test file must export a string.")], taskResult);
|
|
4665
4676
|
return;
|
|
4666
4677
|
}
|
|
4667
|
-
|
|
4668
|
-
this.#projectService.openFile(task.filePath, text, this.#resolvedConfig.rootPath);
|
|
4678
|
+
this.#projectService.openFile(task.filePath, testText, this.#resolvedConfig.rootPath);
|
|
4669
4679
|
languageService = this.#projectService.getLanguageService(task.filePath);
|
|
4670
4680
|
const syntacticDiagnostics = languageService?.getSyntacticDiagnostics(task.filePath);
|
|
4671
4681
|
if (syntacticDiagnostics != null && syntacticDiagnostics.length > 0) {
|
|
4672
|
-
|
|
4673
|
-
"task:error",
|
|
4674
|
-
{ diagnostics: Diagnostic.fromDiagnostics(syntacticDiagnostics), result: taskResult },
|
|
4675
|
-
]);
|
|
4682
|
+
this.#onDiagnostics(Diagnostic.fromDiagnostics(syntacticDiagnostics), taskResult);
|
|
4676
4683
|
return;
|
|
4677
4684
|
}
|
|
4678
4685
|
semanticDiagnostics = languageService?.getSemanticDiagnostics(task.filePath);
|
|
@@ -4690,10 +4697,7 @@ class TaskRunner {
|
|
|
4690
4697
|
return;
|
|
4691
4698
|
}
|
|
4692
4699
|
if (testTree.diagnostics.size > 0) {
|
|
4693
|
-
|
|
4694
|
-
"task:error",
|
|
4695
|
-
{ diagnostics: Diagnostic.fromDiagnostics([...testTree.diagnostics]), result: taskResult },
|
|
4696
|
-
]);
|
|
4700
|
+
this.#onDiagnostics(Diagnostic.fromDiagnostics([...testTree.diagnostics]), taskResult);
|
|
4697
4701
|
return;
|
|
4698
4702
|
}
|
|
4699
4703
|
const typeChecker = program?.getTypeChecker();
|
|
@@ -4710,7 +4714,7 @@ class TaskRunner {
|
|
|
4710
4714
|
class Runner {
|
|
4711
4715
|
#eventEmitter = new EventEmitter();
|
|
4712
4716
|
#resolvedConfig;
|
|
4713
|
-
static version = "4.0.0-beta.
|
|
4717
|
+
static version = "4.0.0-beta.8";
|
|
4714
4718
|
constructor(resolvedConfig) {
|
|
4715
4719
|
this.#resolvedConfig = resolvedConfig;
|
|
4716
4720
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tstyche",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.8",
|
|
4
4
|
"description": "The Essential Type Testing Tool.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"@types/node": "22.15.3",
|
|
66
66
|
"@types/react": "19.1.2",
|
|
67
67
|
"ajv": "8.17.1",
|
|
68
|
-
"cspell": "
|
|
68
|
+
"cspell": "9.0.0",
|
|
69
69
|
"magic-string": "0.30.17",
|
|
70
70
|
"monocart-coverage-reports": "2.12.4",
|
|
71
71
|
"pretty-ansi": "3.0.0",
|