vitest 4.0.0-beta.1 → 4.0.0-beta.10
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/LICENSE.md +2 -2
- package/dist/browser.d.ts +13 -14
- package/dist/browser.js +6 -5
- package/dist/chunks/base.Cjha6usc.js +129 -0
- package/dist/chunks/{benchmark.CYdenmiT.js → benchmark.CJUa-Hsa.js} +6 -8
- package/dist/chunks/{benchmark.d.BwvBVTda.d.ts → benchmark.d.DAaHLpsq.d.ts} +4 -4
- package/dist/chunks/{browser.d.q8Z0P0q1.d.ts → browser.d.yFAklsD1.d.ts} +5 -5
- package/dist/chunks/{cac.D3EzDDZd.js → cac.DCxo_nSu.js} +70 -152
- package/dist/chunks/{cli-api.Dn5gKePv.js → cli-api.BJJXh9BV.js} +1330 -1677
- package/dist/chunks/{config.d.HJdfX-8k.d.ts → config.d.B_LthbQq.d.ts} +58 -63
- package/dist/chunks/{console.CtFJOzRO.js → console.7h5kHUIf.js} +34 -70
- package/dist/chunks/{constants.DnKduX2e.js → constants.D_Q9UYh-.js} +1 -9
- package/dist/chunks/{coverage.Cwa-XhJt.js → coverage.BCU-r2QL.js} +515 -781
- package/dist/chunks/{coverage.DVF1vEu8.js → coverage.D_JHT54q.js} +2 -2
- package/dist/chunks/{coverage.d.S9RMNXIe.d.ts → coverage.d.BZtK59WP.d.ts} +10 -8
- package/dist/chunks/{creator.GK6I-cL4.js → creator.08Gi-vCA.js} +93 -77
- package/dist/chunks/{date.Bq6ZW5rf.js → date.-jtEtIeV.js} +6 -17
- package/dist/chunks/{environment.d.CUq4cUgQ.d.ts → environment.d.BsToaxti.d.ts} +27 -6
- package/dist/chunks/{git.BVQ8w_Sw.js → git.BFNcloKD.js} +1 -2
- package/dist/chunks/{global.d.CVbXEflG.d.ts → global.d.BK3X7FW1.d.ts} +2 -5
- package/dist/chunks/{globals.Cxal6MLI.js → globals.DG-S3xFe.js} +8 -8
- package/dist/chunks/{index.CZI_8rVt.js → index.BIP7prJq.js} +289 -608
- package/dist/chunks/{index.B521nVV-.js → index.Bgo3tNWt.js} +23 -4
- package/dist/chunks/{index.TfbsX-3I.js → index.BjKEiSn0.js} +14 -24
- package/dist/chunks/{index.BWf_gE5n.js → index.CMfqw92x.js} +7 -6
- package/dist/chunks/{index.CmSc2RE5.js → index.DIWhzsUh.js} +72 -118
- package/dist/chunks/{inspector.C914Efll.js → inspector.CvQD-Nie.js} +10 -25
- package/dist/chunks/moduleRunner.d.D9nBoC4p.d.ts +201 -0
- package/dist/chunks/moduleTransport.I-bgQy0S.js +19 -0
- package/dist/chunks/{node.fjCdwEIl.js → node.CyipiPvJ.js} +1 -1
- package/dist/chunks/{plugin.d.C2EcJUjo.d.ts → plugin.d.BMVSnsGV.d.ts} +1 -1
- package/dist/chunks/{reporters.d.DxZg19fy.d.ts → reporters.d.BUWjmRYq.d.ts} +1226 -1291
- package/dist/chunks/resolveSnapshotEnvironment.Bkht6Yor.js +81 -0
- package/dist/chunks/resolver.Bx6lE0iq.js +119 -0
- package/dist/chunks/rpc.BKr6mtxz.js +65 -0
- package/dist/chunks/{setup-common.D7ZqXFx-.js → setup-common.uiMcU3cv.js} +17 -29
- package/dist/chunks/startModuleRunner.p67gbNo9.js +665 -0
- package/dist/chunks/{suite.d.FvehnV49.d.ts → suite.d.BJWk38HB.d.ts} +1 -1
- package/dist/chunks/test.BiqSKISg.js +214 -0
- package/dist/chunks/{typechecker.CVytUJuF.js → typechecker.DB-fIMaH.js} +144 -213
- package/dist/chunks/{utils.CAioKnHs.js → utils.C2YI6McM.js} +5 -14
- package/dist/chunks/{utils.XdZDrNZV.js → utils.D2R2NiOH.js} +8 -27
- package/dist/chunks/{vi.bdSIJ99Y.js → vi.ZPgvtBao.js} +156 -305
- package/dist/chunks/{vm.BThCzidc.js → vm.Ca0Y0W5f.js} +116 -226
- package/dist/chunks/{worker.d.DoNjFAiv.d.ts → worker.d.BDsXGkwh.d.ts} +28 -22
- package/dist/chunks/{worker.d.CmvJfRGs.d.ts → worker.d.BNcX_2mH.d.ts} +1 -1
- package/dist/cli.js +4 -4
- package/dist/config.cjs +3 -9
- package/dist/config.d.ts +49 -54
- package/dist/config.js +1 -1
- package/dist/coverage.d.ts +27 -26
- package/dist/coverage.js +6 -7
- package/dist/environments.d.ts +9 -13
- package/dist/environments.js +1 -1
- package/dist/index.d.ts +38 -45
- package/dist/index.js +7 -9
- package/dist/module-evaluator.d.ts +13 -0
- package/dist/module-evaluator.js +276 -0
- package/dist/module-runner.js +15 -0
- package/dist/node.d.ts +40 -41
- package/dist/node.js +23 -33
- package/dist/reporters.d.ts +12 -13
- package/dist/reporters.js +3 -3
- package/dist/runners.d.ts +3 -3
- package/dist/runners.js +13 -232
- package/dist/snapshot.js +2 -2
- package/dist/suite.d.ts +2 -2
- package/dist/suite.js +2 -2
- package/dist/worker.js +90 -47
- package/dist/workers/forks.js +34 -10
- package/dist/workers/runVmTests.js +36 -56
- package/dist/workers/threads.js +34 -10
- package/dist/workers/vmForks.js +11 -10
- package/dist/workers/vmThreads.js +11 -10
- package/dist/workers.d.ts +5 -4
- package/dist/workers.js +35 -17
- package/globals.d.ts +17 -17
- package/package.json +32 -31
- package/dist/chunks/base.Bj3pWTr1.js +0 -38
- package/dist/chunks/execute.B7h3T_Hc.js +0 -708
- package/dist/chunks/index.D-VkfKhf.js +0 -105
- package/dist/chunks/rpc.CsFtxqeq.js +0 -83
- package/dist/chunks/runBaseTests.BC7ZIH5L.js +0 -129
- package/dist/execute.d.ts +0 -148
- package/dist/execute.js +0 -13
|
@@ -10,16 +10,13 @@ import { parseAstAsync } from 'vite';
|
|
|
10
10
|
|
|
11
11
|
const REGEXP_WRAP_PREFIX = "$$vitest:";
|
|
12
12
|
function getOutputFile(config, reporter) {
|
|
13
|
-
if (
|
|
14
|
-
if (typeof config.outputFile === "string") return config.outputFile;
|
|
15
|
-
return config.outputFile[reporter];
|
|
13
|
+
if (config?.outputFile) return typeof config.outputFile === "string" ? config.outputFile : config.outputFile[reporter];
|
|
16
14
|
}
|
|
17
15
|
/**
|
|
18
16
|
* Prepares `SerializedConfig` for serialization, e.g. `node:v8.serialize`
|
|
19
17
|
*/
|
|
20
18
|
function wrapSerializableConfig(config) {
|
|
21
|
-
let testNamePattern = config.testNamePattern;
|
|
22
|
-
let defines = config.defines;
|
|
19
|
+
let testNamePattern = config.testNamePattern, defines = config.defines;
|
|
23
20
|
// v8 serialize does not support regex
|
|
24
21
|
if (testNamePattern && typeof testNamePattern !== "string") testNamePattern = `${REGEXP_WRAP_PREFIX}${testNamePattern.toString()}`;
|
|
25
22
|
// v8 serialize drops properties with undefined value
|
|
@@ -33,6 +30,49 @@ function wrapSerializableConfig(config) {
|
|
|
33
30
|
defines
|
|
34
31
|
};
|
|
35
32
|
}
|
|
33
|
+
function createDefinesScript(define) {
|
|
34
|
+
if (!define) return "";
|
|
35
|
+
const serializedDefine = serializeDefine(define);
|
|
36
|
+
return serializedDefine === "{}" ? "" : `
|
|
37
|
+
const defines = ${serializeDefine(define)}
|
|
38
|
+
Object.keys(defines).forEach((key) => {
|
|
39
|
+
const segments = key.split('.')
|
|
40
|
+
let target = globalThis
|
|
41
|
+
for (let i = 0; i < segments.length; i++) {
|
|
42
|
+
const segment = segments[i]
|
|
43
|
+
if (i === segments.length - 1) {
|
|
44
|
+
target[segment] = defines[key]
|
|
45
|
+
} else {
|
|
46
|
+
target = target[segment] || (target[segment] = {})
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
`;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Like `JSON.stringify` but keeps raw string values as a literal
|
|
54
|
+
* in the generated code. For example: `"window"` would refer to
|
|
55
|
+
* the global `window` object directly.
|
|
56
|
+
*/
|
|
57
|
+
function serializeDefine(define) {
|
|
58
|
+
const userDefine = {};
|
|
59
|
+
for (const key in define) {
|
|
60
|
+
// vitest sets this to avoid vite:client-inject plugin
|
|
61
|
+
if (key === "process.env.NODE_ENV" && define[key] === "process.env.NODE_ENV") continue;
|
|
62
|
+
// import.meta.env.* is handled in `importAnalysis` plugin
|
|
63
|
+
if (!key.startsWith("import.meta.env.")) userDefine[key] = define[key];
|
|
64
|
+
}
|
|
65
|
+
let res = `{`;
|
|
66
|
+
const keys = Object.keys(userDefine).sort();
|
|
67
|
+
for (let i = 0; i < keys.length; i++) {
|
|
68
|
+
const key = keys[i], val = userDefine[key];
|
|
69
|
+
if (res += `${JSON.stringify(key)}: ${handleDefineValue(val)}`, i !== keys.length - 1) res += `, `;
|
|
70
|
+
}
|
|
71
|
+
return `${res}}`;
|
|
72
|
+
}
|
|
73
|
+
function handleDefineValue(value) {
|
|
74
|
+
return typeof value === "undefined" ? "undefined" : typeof value === "string" ? value : JSON.stringify(value);
|
|
75
|
+
}
|
|
36
76
|
|
|
37
77
|
function hasFailedSnapshot(suite) {
|
|
38
78
|
return getTests(suite).some((s) => {
|
|
@@ -40,58 +80,44 @@ function hasFailedSnapshot(suite) {
|
|
|
40
80
|
});
|
|
41
81
|
}
|
|
42
82
|
function convertTasksToEvents(file, onTask) {
|
|
43
|
-
const packs = [];
|
|
44
|
-
const events = [];
|
|
83
|
+
const packs = [], events = [];
|
|
45
84
|
function visit(suite) {
|
|
46
|
-
onTask?.(suite)
|
|
47
|
-
packs.push([
|
|
85
|
+
onTask?.(suite), packs.push([
|
|
48
86
|
suite.id,
|
|
49
87
|
suite.result,
|
|
50
88
|
suite.meta
|
|
51
|
-
])
|
|
52
|
-
events.push([
|
|
89
|
+
]), events.push([
|
|
53
90
|
suite.id,
|
|
54
91
|
"suite-prepare",
|
|
55
92
|
void 0
|
|
56
|
-
])
|
|
57
|
-
suite.tasks.forEach((task) => {
|
|
93
|
+
]), suite.tasks.forEach((task) => {
|
|
58
94
|
if (task.type === "suite") visit(task);
|
|
59
|
-
else
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
events.push([
|
|
80
|
-
task.id,
|
|
81
|
-
"test-finished",
|
|
82
|
-
void 0
|
|
83
|
-
]);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
events.push([
|
|
95
|
+
else if (onTask?.(task), suite.mode !== "skip" && suite.mode !== "todo") packs.push([
|
|
96
|
+
task.id,
|
|
97
|
+
task.result,
|
|
98
|
+
task.meta
|
|
99
|
+
]), events.push([
|
|
100
|
+
task.id,
|
|
101
|
+
"test-prepare",
|
|
102
|
+
void 0
|
|
103
|
+
]), task.annotations.forEach((annotation) => {
|
|
104
|
+
events.push([
|
|
105
|
+
task.id,
|
|
106
|
+
"test-annotation",
|
|
107
|
+
{ annotation }
|
|
108
|
+
]);
|
|
109
|
+
}), events.push([
|
|
110
|
+
task.id,
|
|
111
|
+
"test-finished",
|
|
112
|
+
void 0
|
|
113
|
+
]);
|
|
114
|
+
}), events.push([
|
|
88
115
|
suite.id,
|
|
89
116
|
"suite-finished",
|
|
90
117
|
void 0
|
|
91
118
|
]);
|
|
92
119
|
}
|
|
93
|
-
visit(file)
|
|
94
|
-
return {
|
|
120
|
+
return visit(file), {
|
|
95
121
|
packs,
|
|
96
122
|
events
|
|
97
123
|
};
|
|
@@ -374,13 +400,9 @@ base.MethodDefinition = base.PropertyDefinition = base.Property = function (node
|
|
|
374
400
|
};
|
|
375
401
|
|
|
376
402
|
async function collectTests(ctx, filepath) {
|
|
377
|
-
const request = await ctx.
|
|
403
|
+
const request = await ctx.vite.environments.ssr.transformRequest(filepath);
|
|
378
404
|
if (!request) return null;
|
|
379
|
-
const ast = await parseAstAsync(request.code)
|
|
380
|
-
const testFilepath = relative(ctx.config.root, filepath);
|
|
381
|
-
const projectName = ctx.name;
|
|
382
|
-
const typecheckSubprojectName = projectName ? `${projectName}:__typecheck__` : "__typecheck__";
|
|
383
|
-
const file = {
|
|
405
|
+
const ast = await parseAstAsync(request.code), testFilepath = relative(ctx.config.root, filepath), projectName = ctx.name, typecheckSubprojectName = projectName ? `${projectName}:__typecheck__` : "__typecheck__", file = {
|
|
384
406
|
filepath,
|
|
385
407
|
type: "suite",
|
|
386
408
|
id: generateHash(`${testFilepath}${typecheckSubprojectName}`),
|
|
@@ -394,24 +416,19 @@ async function collectTests(ctx, filepath) {
|
|
|
394
416
|
file: null
|
|
395
417
|
};
|
|
396
418
|
file.file = file;
|
|
397
|
-
const definitions = []
|
|
398
|
-
const getName = (callee) => {
|
|
419
|
+
const definitions = [], getName = (callee) => {
|
|
399
420
|
if (!callee) return null;
|
|
400
421
|
if (callee.type === "Identifier") return callee.name;
|
|
401
422
|
if (callee.type === "CallExpression") return getName(callee.callee);
|
|
402
423
|
if (callee.type === "TaggedTemplateExpression") return getName(callee.tag);
|
|
403
|
-
if (callee.type === "MemberExpression")
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
if (callee.object?.name?.startsWith("__vite_ssr_")) return getName(callee.property);
|
|
412
|
-
// call as `__vite_ssr__.test.skip()`
|
|
413
|
-
return getName(callee.object?.property);
|
|
414
|
-
}
|
|
424
|
+
if (callee.type === "MemberExpression")
|
|
425
|
+
// call as `__vite_ssr__.test.skip()`
|
|
426
|
+
return callee.object?.type === "Identifier" && [
|
|
427
|
+
"it",
|
|
428
|
+
"test",
|
|
429
|
+
"describe",
|
|
430
|
+
"suite"
|
|
431
|
+
].includes(callee.object.name) ? callee.object?.name : callee.object?.name?.startsWith("__vite_ssr_") ? getName(callee.property) : getName(callee.object?.property);
|
|
415
432
|
// unwrap (0, ...)
|
|
416
433
|
if (callee.type === "SequenceExpression" && callee.expressions.length === 2) {
|
|
417
434
|
const [e0, e1] = callee.expressions;
|
|
@@ -420,10 +437,8 @@ async function collectTests(ctx, filepath) {
|
|
|
420
437
|
return null;
|
|
421
438
|
};
|
|
422
439
|
ancestor(ast, { CallExpression(node) {
|
|
423
|
-
const { callee } = node;
|
|
424
|
-
|
|
425
|
-
if (!name) return;
|
|
426
|
-
if (![
|
|
440
|
+
const { callee } = node, name = getName(callee);
|
|
441
|
+
if (!name || ![
|
|
427
442
|
"it",
|
|
428
443
|
"test",
|
|
429
444
|
"describe",
|
|
@@ -444,9 +459,7 @@ async function collectTests(ctx, filepath) {
|
|
|
444
459
|
if (callee.type === "CallExpression") start = callee.end;
|
|
445
460
|
else if (callee.type === "TaggedTemplateExpression") start = callee.end + 1;
|
|
446
461
|
else start = node.start;
|
|
447
|
-
const { arguments: [messageNode] } = node;
|
|
448
|
-
const isQuoted = messageNode?.type === "Literal" || messageNode?.type === "TemplateLiteral";
|
|
449
|
-
const message = isQuoted ? request.code.slice(messageNode.start + 1, messageNode.end - 1) : request.code.slice(messageNode.start, messageNode.end);
|
|
462
|
+
const { arguments: [messageNode] } = node, isQuoted = messageNode?.type === "Literal" || messageNode?.type === "TemplateLiteral", message = isQuoted ? request.code.slice(messageNode.start + 1, messageNode.end - 1) : request.code.slice(messageNode.start, messageNode.end);
|
|
450
463
|
// cannot statically analyze, so we always skip it
|
|
451
464
|
if (mode === "skipIf" || mode === "runIf") mode = "skip";
|
|
452
465
|
definitions.push({
|
|
@@ -482,9 +495,7 @@ async function collectTests(ctx, filepath) {
|
|
|
482
495
|
start: definition.start,
|
|
483
496
|
meta: { typecheck: true }
|
|
484
497
|
};
|
|
485
|
-
definition.task = task;
|
|
486
|
-
latestSuite.tasks.push(task);
|
|
487
|
-
lastSuite = task;
|
|
498
|
+
definition.task = task, latestSuite.tasks.push(task), lastSuite = task;
|
|
488
499
|
return;
|
|
489
500
|
}
|
|
490
501
|
const task = {
|
|
@@ -501,13 +512,10 @@ async function collectTests(ctx, filepath) {
|
|
|
501
512
|
annotations: [],
|
|
502
513
|
meta: { typecheck: true }
|
|
503
514
|
};
|
|
504
|
-
definition.task = task;
|
|
505
|
-
|
|
506
|
-
});
|
|
507
|
-
calculateSuiteHash(file);
|
|
515
|
+
definition.task = task, latestSuite.tasks.push(task);
|
|
516
|
+
}), calculateSuiteHash(file);
|
|
508
517
|
const hasOnly = someTasksAreOnly(file);
|
|
509
|
-
interpretTaskModes(file, ctx.config.testNamePattern, void 0, hasOnly, false, ctx.config.allowOnly)
|
|
510
|
-
return {
|
|
518
|
+
return interpretTaskModes(file, ctx.config.testNamePattern, void 0, hasOnly, false, ctx.config.allowOnly), {
|
|
511
519
|
file,
|
|
512
520
|
parsed: request.code,
|
|
513
521
|
filepath,
|
|
@@ -516,14 +524,11 @@ async function collectTests(ctx, filepath) {
|
|
|
516
524
|
};
|
|
517
525
|
}
|
|
518
526
|
|
|
519
|
-
const newLineRegExp = /\r?\n/;
|
|
520
|
-
const errCodeRegExp = /error TS(?<errCode>\d+)/;
|
|
527
|
+
const newLineRegExp = /\r?\n/, errCodeRegExp = /error TS(?<errCode>\d+)/;
|
|
521
528
|
async function makeTscErrorInfo(errInfo) {
|
|
522
529
|
const [errFilePathPos = "", ...errMsgRawArr] = errInfo.split(":");
|
|
523
530
|
if (!errFilePathPos || errMsgRawArr.length === 0 || errMsgRawArr.join("").length === 0) return ["unknown filepath", null];
|
|
524
|
-
const errMsgRaw = errMsgRawArr.join("").trim();
|
|
525
|
-
// get filePath, line, col
|
|
526
|
-
const [errFilePath, errPos] = errFilePathPos.slice(0, -1).split("(");
|
|
531
|
+
const errMsgRaw = errMsgRawArr.join("").trim(), [errFilePath, errPos] = errFilePathPos.slice(0, -1).split("(");
|
|
527
532
|
if (!errFilePath || !errPos) return ["unknown filepath", null];
|
|
528
533
|
const [errLine, errCol] = errPos.split(",");
|
|
529
534
|
if (!errLine || !errCol) return [errFilePath, null];
|
|
@@ -532,9 +537,7 @@ async function makeTscErrorInfo(errInfo) {
|
|
|
532
537
|
if (!execArr) return [errFilePath, null];
|
|
533
538
|
const errCodeStr = execArr.groups?.errCode ?? "";
|
|
534
539
|
if (!errCodeStr) return [errFilePath, null];
|
|
535
|
-
const line = Number(errLine);
|
|
536
|
-
const col = Number(errCol);
|
|
537
|
-
const errCode = Number(errCodeStr);
|
|
540
|
+
const line = Number(errLine), col = Number(errCol), errCode = Number(errCodeStr);
|
|
538
541
|
return [errFilePath, {
|
|
539
542
|
filePath: errFilePath,
|
|
540
543
|
errCode,
|
|
@@ -544,43 +547,30 @@ async function makeTscErrorInfo(errInfo) {
|
|
|
544
547
|
}];
|
|
545
548
|
}
|
|
546
549
|
async function getRawErrsMapFromTsCompile(tscErrorStdout) {
|
|
547
|
-
const rawErrsMap = /* @__PURE__ */ new Map()
|
|
548
|
-
// Merge details line with main line (i.e. which contains file path)
|
|
549
|
-
const infos = await Promise.all(tscErrorStdout.split(newLineRegExp).reduce((prev, next) => {
|
|
550
|
+
const rawErrsMap = /* @__PURE__ */ new Map(), infos = await Promise.all(tscErrorStdout.split(newLineRegExp).reduce((prev, next) => {
|
|
550
551
|
if (!next) return prev;
|
|
551
|
-
|
|
552
|
+
if (!next.startsWith(" ")) prev.push(next);
|
|
552
553
|
else prev[prev.length - 1] += `\n${next}`;
|
|
553
554
|
return prev;
|
|
554
555
|
}, []).map((errInfoLine) => makeTscErrorInfo(errInfoLine)));
|
|
555
|
-
infos.forEach(([errFilePath, errInfo]) => {
|
|
556
|
-
if (!errInfo)
|
|
557
|
-
if (!rawErrsMap.has(errFilePath)) rawErrsMap.set(errFilePath, [errInfo]);
|
|
556
|
+
return infos.forEach(([errFilePath, errInfo]) => {
|
|
557
|
+
if (errInfo) if (!rawErrsMap.has(errFilePath)) rawErrsMap.set(errFilePath, [errInfo]);
|
|
558
558
|
else rawErrsMap.get(errFilePath)?.push(errInfo);
|
|
559
|
-
});
|
|
560
|
-
return rawErrsMap;
|
|
559
|
+
}), rawErrsMap;
|
|
561
560
|
}
|
|
562
561
|
|
|
563
562
|
function createIndexMap(source) {
|
|
564
563
|
const map = /* @__PURE__ */ new Map();
|
|
565
|
-
let index = 0;
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
for (const char of source) {
|
|
569
|
-
map.set(`${line}:${column}`, index++);
|
|
570
|
-
if (char === "\n" || char === "\r\n") {
|
|
571
|
-
line++;
|
|
572
|
-
column = 0;
|
|
573
|
-
} else column++;
|
|
574
|
-
}
|
|
564
|
+
let index = 0, line = 1, column = 1;
|
|
565
|
+
for (const char of source) if (map.set(`${line}:${column}`, index++), char === "\n" || char === "\r\n") line++, column = 0;
|
|
566
|
+
else column++;
|
|
575
567
|
return map;
|
|
576
568
|
}
|
|
577
569
|
|
|
578
570
|
class TypeCheckError extends Error {
|
|
579
571
|
name = "TypeCheckError";
|
|
580
572
|
constructor(message, stacks) {
|
|
581
|
-
super(message);
|
|
582
|
-
this.message = message;
|
|
583
|
-
this.stacks = stacks;
|
|
573
|
+
super(message), this.message = message, this.stacks = stacks;
|
|
584
574
|
}
|
|
585
575
|
}
|
|
586
576
|
class Typechecker {
|
|
@@ -620,12 +610,9 @@ class Typechecker {
|
|
|
620
610
|
}
|
|
621
611
|
async collectTests() {
|
|
622
612
|
const tests = (await Promise.all(this.getFiles().map((filepath) => this.collectFileTests(filepath)))).reduce((acc, data) => {
|
|
623
|
-
|
|
624
|
-
acc[data.filepath] = data;
|
|
625
|
-
return acc;
|
|
613
|
+
return data && (acc[data.filepath] = data), acc;
|
|
626
614
|
}, {});
|
|
627
|
-
this._tests = tests;
|
|
628
|
-
return tests;
|
|
615
|
+
return this._tests = tests, tests;
|
|
629
616
|
}
|
|
630
617
|
markPassed(file) {
|
|
631
618
|
if (!file.result?.state) file.result = { state: "pass" };
|
|
@@ -638,26 +625,17 @@ class Typechecker {
|
|
|
638
625
|
markTasks(file.tasks);
|
|
639
626
|
}
|
|
640
627
|
async prepareResults(output) {
|
|
641
|
-
const typeErrors = await this.parseTscLikeOutput(output);
|
|
642
|
-
const testFiles = new Set(this.getFiles());
|
|
628
|
+
const typeErrors = await this.parseTscLikeOutput(output), testFiles = new Set(this.getFiles());
|
|
643
629
|
if (!this._tests) this._tests = await this.collectTests();
|
|
644
|
-
const sourceErrors = [];
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
const errors = typeErrors.get(path);
|
|
649
|
-
files.push(file);
|
|
650
|
-
if (!errors) {
|
|
630
|
+
const sourceErrors = [], files = [];
|
|
631
|
+
return testFiles.forEach((path) => {
|
|
632
|
+
const { file, definitions, map, parsed } = this._tests[path], errors = typeErrors.get(path);
|
|
633
|
+
if (files.push(file), !errors) {
|
|
651
634
|
this.markPassed(file);
|
|
652
635
|
return;
|
|
653
636
|
}
|
|
654
|
-
const sortedDefinitions = [...definitions.sort((a, b) => b.start - a.start)]
|
|
655
|
-
|
|
656
|
-
const traceMap = map && new TraceMap(map);
|
|
657
|
-
const indexMap = createIndexMap(parsed);
|
|
658
|
-
const markState = (task, state) => {
|
|
659
|
-
task.result = { state: task.mode === "run" || task.mode === "only" ? state : task.mode };
|
|
660
|
-
if (task.suite) markState(task.suite, state);
|
|
637
|
+
const sortedDefinitions = [...definitions.sort((a, b) => b.start - a.start)], traceMap = map && new TraceMap(map), indexMap = createIndexMap(parsed), markState = (task, state) => {
|
|
638
|
+
if (task.result = { state: task.mode === "run" || task.mode === "only" ? state : task.mode }, task.suite) markState(task.suite, state);
|
|
661
639
|
else if (task.file && task !== task.file) markState(task.file, state);
|
|
662
640
|
};
|
|
663
641
|
errors.forEach(({ error, originalError }) => {
|
|
@@ -665,53 +643,37 @@ class Typechecker {
|
|
|
665
643
|
line: originalError.line,
|
|
666
644
|
column: originalError.column,
|
|
667
645
|
source: basename(path)
|
|
668
|
-
}) : originalError;
|
|
669
|
-
|
|
670
|
-
const column = processedPos.column ?? originalError.column;
|
|
671
|
-
const index = indexMap.get(`${line}:${column}`);
|
|
672
|
-
const definition = index != null && sortedDefinitions.find((def) => def.start <= index && def.end >= index);
|
|
673
|
-
const suite = definition ? definition.task : file;
|
|
674
|
-
const state = suite.mode === "run" || suite.mode === "only" ? "fail" : suite.mode;
|
|
675
|
-
const errors = suite.result?.errors || [];
|
|
676
|
-
suite.result = {
|
|
646
|
+
}) : originalError, line = processedPos.line ?? originalError.line, column = processedPos.column ?? originalError.column, index = indexMap.get(`${line}:${column}`), definition = index != null && sortedDefinitions.find((def) => def.start <= index && def.end >= index), suite = definition ? definition.task : file, state = suite.mode === "run" || suite.mode === "only" ? "fail" : suite.mode, errors = suite.result?.errors || [];
|
|
647
|
+
if (suite.result = {
|
|
677
648
|
state,
|
|
678
649
|
errors
|
|
679
|
-
}
|
|
680
|
-
errors.push(error);
|
|
681
|
-
if (state === "fail") {
|
|
650
|
+
}, errors.push(error), state === "fail") {
|
|
682
651
|
if (suite.suite) markState(suite.suite, "fail");
|
|
683
652
|
else if (suite.file && suite !== suite.file) markState(suite.file, "fail");
|
|
684
653
|
}
|
|
685
|
-
});
|
|
686
|
-
|
|
687
|
-
});
|
|
688
|
-
typeErrors.forEach((errors, path) => {
|
|
654
|
+
}), this.markPassed(file);
|
|
655
|
+
}), typeErrors.forEach((errors, path) => {
|
|
689
656
|
if (!testFiles.has(path)) sourceErrors.push(...errors.map(({ error }) => error));
|
|
690
|
-
})
|
|
691
|
-
return {
|
|
657
|
+
}), {
|
|
692
658
|
files,
|
|
693
659
|
sourceErrors,
|
|
694
660
|
time: performance.now() - this._startTime
|
|
695
661
|
};
|
|
696
662
|
}
|
|
697
663
|
async parseTscLikeOutput(output) {
|
|
698
|
-
const errorsMap = await getRawErrsMapFromTsCompile(output);
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
const filepath = resolve(this.project.config.root, path);
|
|
702
|
-
const suiteErrors = errors.map((info) => {
|
|
664
|
+
const errorsMap = await getRawErrsMapFromTsCompile(output), typesErrors = /* @__PURE__ */ new Map();
|
|
665
|
+
return errorsMap.forEach((errors, path) => {
|
|
666
|
+
const filepath = resolve(this.project.config.root, path), suiteErrors = errors.map((info) => {
|
|
703
667
|
const limit = Error.stackTraceLimit;
|
|
704
668
|
Error.stackTraceLimit = 0;
|
|
705
669
|
// Some expect-type errors have the most useful information on the second line e.g. `This expression is not callable.\n Type 'ExpectString<number>' has no call signatures.`
|
|
706
|
-
const errMsg = info.errMsg.replace(/\r?\n\s*(Type .* has no call signatures)/g, " $1")
|
|
707
|
-
const error = new TypeCheckError(errMsg, [{
|
|
670
|
+
const errMsg = info.errMsg.replace(/\r?\n\s*(Type .* has no call signatures)/g, " $1"), error = new TypeCheckError(errMsg, [{
|
|
708
671
|
file: filepath,
|
|
709
672
|
line: info.line,
|
|
710
673
|
column: info.column,
|
|
711
674
|
method: ""
|
|
712
675
|
}]);
|
|
713
|
-
Error.stackTraceLimit = limit
|
|
714
|
-
return {
|
|
676
|
+
return Error.stackTraceLimit = limit, {
|
|
715
677
|
originalError: info,
|
|
716
678
|
error: {
|
|
717
679
|
name: error.name,
|
|
@@ -722,12 +684,10 @@ class Typechecker {
|
|
|
722
684
|
};
|
|
723
685
|
});
|
|
724
686
|
typesErrors.set(filepath, suiteErrors);
|
|
725
|
-
});
|
|
726
|
-
return typesErrors;
|
|
687
|
+
}), typesErrors;
|
|
727
688
|
}
|
|
728
689
|
async stop() {
|
|
729
|
-
this.process?.kill();
|
|
730
|
-
this.process = void 0;
|
|
690
|
+
this.process?.kill(), this.process = void 0;
|
|
731
691
|
}
|
|
732
692
|
async ensurePackageInstalled(ctx, checker) {
|
|
733
693
|
if (checker !== "tsc" && checker !== "vue-tsc") return;
|
|
@@ -741,8 +701,7 @@ class Typechecker {
|
|
|
741
701
|
return this._output;
|
|
742
702
|
}
|
|
743
703
|
async spawn() {
|
|
744
|
-
const { root, watch, typecheck } = this.project.config
|
|
745
|
-
const args = [
|
|
704
|
+
const { root, watch, typecheck } = this.project.config, args = [
|
|
746
705
|
"--noEmit",
|
|
747
706
|
"--pretty",
|
|
748
707
|
"false",
|
|
@@ -754,8 +713,7 @@ class Typechecker {
|
|
|
754
713
|
if (watch) args.push("--watch");
|
|
755
714
|
if (typecheck.allowJs) args.push("--allowJs", "--checkJs");
|
|
756
715
|
if (typecheck.tsconfig) args.push("-p", resolve(root, typecheck.tsconfig));
|
|
757
|
-
this._output = "";
|
|
758
|
-
this._startTime = performance.now();
|
|
716
|
+
this._output = "", this._startTime = performance.now();
|
|
759
717
|
const child = x(typecheck.checker, args, {
|
|
760
718
|
nodeOptions: {
|
|
761
719
|
cwd: root,
|
|
@@ -764,44 +722,26 @@ class Typechecker {
|
|
|
764
722
|
throwOnError: false
|
|
765
723
|
});
|
|
766
724
|
this.process = child.process;
|
|
767
|
-
let rerunTriggered = false;
|
|
768
|
-
let dataReceived = false;
|
|
725
|
+
let rerunTriggered = false, dataReceived = false;
|
|
769
726
|
return new Promise((resolve, reject) => {
|
|
770
727
|
if (!child.process || !child.process.stdout) {
|
|
771
|
-
reject(new Error(`Failed to initialize ${typecheck.checker}. This is a bug in Vitest - please, open an issue with reproduction.`));
|
|
728
|
+
reject(/* @__PURE__ */ new Error(`Failed to initialize ${typecheck.checker}. This is a bug in Vitest - please, open an issue with reproduction.`));
|
|
772
729
|
return;
|
|
773
730
|
}
|
|
774
731
|
child.process.stdout.on("data", (chunk) => {
|
|
775
|
-
dataReceived = true
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
this.
|
|
780
|
-
this._startTime = performance.now();
|
|
781
|
-
this._result.sourceErrors = [];
|
|
782
|
-
this._result.files = [];
|
|
783
|
-
this._tests = null;
|
|
784
|
-
rerunTriggered = true;
|
|
785
|
-
}
|
|
786
|
-
if (/Found \w+ errors*. Watching for/.test(this._output)) {
|
|
787
|
-
rerunTriggered = false;
|
|
788
|
-
this.prepareResults(this._output).then((result) => {
|
|
789
|
-
this._result = result;
|
|
790
|
-
this._onParseEnd?.(result);
|
|
791
|
-
});
|
|
792
|
-
this._output = "";
|
|
732
|
+
if (dataReceived = true, this._output += chunk, watch) {
|
|
733
|
+
if (this._output.includes("File change detected") && !rerunTriggered) this._onWatcherRerun?.(), this._startTime = performance.now(), this._result.sourceErrors = [], this._result.files = [], this._tests = null, rerunTriggered = true;
|
|
734
|
+
if (/Found \w+ errors*. Watching for/.test(this._output)) rerunTriggered = false, this.prepareResults(this._output).then((result) => {
|
|
735
|
+
this._result = result, this._onParseEnd?.(result);
|
|
736
|
+
}), this._output = "";
|
|
793
737
|
}
|
|
794
738
|
});
|
|
795
|
-
const timeout = setTimeout(() => reject(new Error(`${typecheck.checker} spawn timed out`)), this.project.config.typecheck.spawnTimeout);
|
|
739
|
+
const timeout = setTimeout(() => reject(/* @__PURE__ */ new Error(`${typecheck.checker} spawn timed out`)), this.project.config.typecheck.spawnTimeout);
|
|
796
740
|
function onError(cause) {
|
|
797
|
-
clearTimeout(timeout);
|
|
798
|
-
reject(new Error("Spawning typechecker failed - is typescript installed?", { cause }));
|
|
741
|
+
clearTimeout(timeout), reject(new Error("Spawning typechecker failed - is typescript installed?", { cause }));
|
|
799
742
|
}
|
|
800
|
-
child.process.once("spawn", () => {
|
|
801
|
-
this._onParseStart?.()
|
|
802
|
-
child.process?.off("error", onError);
|
|
803
|
-
clearTimeout(timeout);
|
|
804
|
-
if (process.platform === "win32")
|
|
743
|
+
if (child.process.once("spawn", () => {
|
|
744
|
+
if (this._onParseStart?.(), child.process?.off("error", onError), clearTimeout(timeout), process.platform === "win32")
|
|
805
745
|
// on Windows, the process might be spawned but fail to start
|
|
806
746
|
// we wait for a potential error here. if "close" event didn't trigger,
|
|
807
747
|
// we resolve the promise
|
|
@@ -809,22 +749,16 @@ class Typechecker {
|
|
|
809
749
|
resolve({ result: child });
|
|
810
750
|
}, 200);
|
|
811
751
|
else resolve({ result: child });
|
|
812
|
-
})
|
|
813
|
-
|
|
814
|
-
if (code != null && code !== 0 && !dataReceived) onError(new Error(`The ${typecheck.checker} command exited with code ${code}.`));
|
|
752
|
+
}), process.platform === "win32") child.process.once("close", (code) => {
|
|
753
|
+
if (code != null && code !== 0 && !dataReceived) onError(/* @__PURE__ */ new Error(`The ${typecheck.checker} command exited with code ${code}.`));
|
|
815
754
|
});
|
|
816
755
|
child.process.once("error", onError);
|
|
817
756
|
});
|
|
818
757
|
}
|
|
819
758
|
async start() {
|
|
820
759
|
if (this.process) return;
|
|
821
|
-
const { watch } = this.project.config;
|
|
822
|
-
|
|
823
|
-
if (!watch) {
|
|
824
|
-
await child;
|
|
825
|
-
this._result = await this.prepareResults(this._output);
|
|
826
|
-
await this._onParseEnd?.(this._result);
|
|
827
|
-
}
|
|
760
|
+
const { watch } = this.project.config, { result: child } = await this.spawn();
|
|
761
|
+
if (!watch) await child, this._result = await this.prepareResults(this._output), await this._onParseEnd?.(this._result);
|
|
828
762
|
}
|
|
829
763
|
getResult() {
|
|
830
764
|
return this._result;
|
|
@@ -833,12 +767,10 @@ class Typechecker {
|
|
|
833
767
|
return Object.values(this._tests || {}).map((i) => i.file);
|
|
834
768
|
}
|
|
835
769
|
getTestPacksAndEvents() {
|
|
836
|
-
const packs = [];
|
|
837
|
-
const events = [];
|
|
770
|
+
const packs = [], events = [];
|
|
838
771
|
for (const { file } of Object.values(this._tests || {})) {
|
|
839
772
|
const result = convertTasksToEvents(file);
|
|
840
|
-
packs.push(...result.packs);
|
|
841
|
-
events.push(...result.events);
|
|
773
|
+
packs.push(...result.packs), events.push(...result.events);
|
|
842
774
|
}
|
|
843
775
|
return {
|
|
844
776
|
packs,
|
|
@@ -861,14 +793,13 @@ function findGeneratedPosition(traceMap, { line, column, source }) {
|
|
|
861
793
|
if (m.source === source && m.originalLine !== null && m.originalColumn !== null && (line === m.originalLine ? column < m.originalColumn : line < m.originalLine)) mappings.push(m);
|
|
862
794
|
});
|
|
863
795
|
const next = mappings.sort((a, b) => a.originalLine === b.originalLine ? a.originalColumn - b.originalColumn : a.originalLine - b.originalLine).at(0);
|
|
864
|
-
|
|
796
|
+
return next ? {
|
|
865
797
|
line: next.generatedLine,
|
|
866
798
|
column: next.generatedColumn
|
|
867
|
-
}
|
|
868
|
-
return {
|
|
799
|
+
} : {
|
|
869
800
|
line: null,
|
|
870
801
|
column: null
|
|
871
802
|
};
|
|
872
803
|
}
|
|
873
804
|
|
|
874
|
-
export { TypeCheckError as T, Typechecker as a,
|
|
805
|
+
export { TypeCheckError as T, Typechecker as a, ancestor as b, createDefinesScript as c, convertTasksToEvents as d, getOutputFile as g, hasFailedSnapshot as h, wrapSerializableConfig as w };
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { parseRegexp } from '@vitest/utils';
|
|
2
2
|
|
|
3
|
-
const REGEXP_WRAP_PREFIX = "$$vitest:";
|
|
4
|
-
// Store global APIs in case process is overwritten by tests
|
|
5
|
-
const processSend = process.send?.bind(process);
|
|
6
|
-
const processOn = process.on?.bind(process);
|
|
7
|
-
const processOff = process.off?.bind(process);
|
|
8
|
-
const dispose = [];
|
|
3
|
+
const REGEXP_WRAP_PREFIX = "$$vitest:", processSend = process.send?.bind(process), processOn = process.on?.bind(process), processOff = process.off?.bind(process), dispose = [];
|
|
9
4
|
function createThreadsRpcOptions({ port }) {
|
|
10
5
|
return {
|
|
11
6
|
post: (v) => {
|
|
@@ -31,12 +26,9 @@ function createForksRpcOptions(nodeV8) {
|
|
|
31
26
|
},
|
|
32
27
|
on(fn) {
|
|
33
28
|
const handler = (message, ...extras) => {
|
|
34
|
-
|
|
35
|
-
if (message?.__tinypool_worker_message__) return;
|
|
36
|
-
return fn(message, ...extras);
|
|
29
|
+
if (!message?.__tinypool_worker_message__) return fn(message, ...extras);
|
|
37
30
|
};
|
|
38
|
-
processOn("message", handler);
|
|
39
|
-
dispose.push(() => processOff("message", handler));
|
|
31
|
+
processOn("message", handler), dispose.push(() => processOff("message", handler));
|
|
40
32
|
}
|
|
41
33
|
};
|
|
42
34
|
}
|
|
@@ -46,11 +38,10 @@ function createForksRpcOptions(nodeV8) {
|
|
|
46
38
|
function unwrapSerializableConfig(config) {
|
|
47
39
|
if (config.testNamePattern && typeof config.testNamePattern === "string") {
|
|
48
40
|
const testNamePattern = config.testNamePattern;
|
|
49
|
-
if (testNamePattern.startsWith(REGEXP_WRAP_PREFIX)) config.testNamePattern = parseRegexp(testNamePattern.slice(
|
|
41
|
+
if (testNamePattern.startsWith(REGEXP_WRAP_PREFIX)) config.testNamePattern = parseRegexp(testNamePattern.slice(9));
|
|
50
42
|
}
|
|
51
43
|
if (config.defines && Array.isArray(config.defines.keys) && config.defines.original) {
|
|
52
|
-
const { keys, original } = config.defines;
|
|
53
|
-
const defines = {};
|
|
44
|
+
const { keys, original } = config.defines, defines = {};
|
|
54
45
|
// Apply all keys from the original. Entries which had undefined value are missing from original now
|
|
55
46
|
for (const key of keys) defines[key] = original[key];
|
|
56
47
|
config.defines = defines;
|