vitest 3.2.0-beta.1 → 3.2.0-beta.3
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 +0 -232
- package/dist/browser.d.ts +5 -3
- package/dist/browser.js +3 -4
- package/dist/chunks/{base.SfTiRNZf.js → base.D4119yLM.js} +4 -3
- package/dist/chunks/{benchmark.BoF7jW0Q.js → benchmark.Cf_PACH1.js} +1 -1
- package/dist/chunks/{cac.TfX2-DVH.js → cac.DWaWHIIE.js} +21 -16
- package/dist/chunks/{cli-api.2970Nj9J.js → cli-api.CnmEXkxs.js} +292 -59
- package/dist/chunks/{config.d.UqE-KR0o.d.ts → config.d.D2ROskhv.d.ts} +2 -0
- package/dist/chunks/{console.K1NMVOSc.js → console.Cwr-MFPV.js} +3 -2
- package/dist/chunks/{constants.BZZyIeIE.js → constants.DnKduX2e.js} +1 -0
- package/dist/chunks/{coverage.z0LVMxgb.js → coverage.C73DaDgS.js} +241 -4226
- package/dist/chunks/{creator.CuL7xDWI.js → creator.C8WKy2eW.js} +26 -44
- package/dist/chunks/{date.CDOsz-HY.js → date.ByMsSlOr.js} +25 -0
- package/dist/chunks/{defaults.DSxsTG0h.js → defaults.DpVH7vbg.js} +1 -0
- package/dist/chunks/{environment.d.D8YDy2v5.d.ts → environment.d.cL3nLXbE.d.ts} +1 -0
- package/dist/chunks/{execute.BpmIjFTD.js → execute.B3q-2LPV.js} +28 -5
- package/dist/chunks/{global.d.BCOHQEpR.d.ts → global.d.BNLIi6yo.d.ts} +13 -11
- package/dist/chunks/{globals.Cg4NtV4P.js → globals.CI21aWXF.js} +7 -7
- package/dist/chunks/{index.DFXFpH3w.js → index.2jgTs_Q5.js} +19 -1
- package/dist/chunks/{index.CUacZlWG.js → index.Bter3jj9.js} +954 -954
- package/dist/chunks/{index.DbWBPwtH.js → index.CbT4iuwc.js} +7 -4
- package/dist/chunks/index.D3XRDfWc.js +213 -0
- package/dist/chunks/{index.BPc7M5ni.js → index.DNgLEKsQ.js} +5 -15
- package/dist/chunks/index.JOzufsrU.js +276 -0
- package/dist/chunks/{index.DBIGubLC.js → index.X0nbfr6-.js} +7 -7
- package/dist/chunks/{inspector.DbDkSkFn.js → inspector.BFsh5KO0.js} +3 -0
- package/dist/chunks/{node.3xsWotC9.js → node.Be-ntJnD.js} +1 -1
- package/dist/chunks/{reporters.d.DGm4k1Wx.d.ts → reporters.d.Bt4IGtsa.d.ts} +41 -6
- package/dist/chunks/{rpc.D9_013TY.js → rpc.BKExFSRG.js} +2 -1
- package/dist/chunks/{runBaseTests.CguliJB5.js → runBaseTests.B_M1TTsK.js} +19 -11
- package/dist/chunks/{setup-common.BP6KrF_Z.js → setup-common.CF-O-dZX.js} +2 -3
- package/dist/chunks/typechecker.BgzF-6iO.js +954 -0
- package/dist/chunks/{utils.CgTj3MsC.js → utils.BlI4TC7Y.js} +1 -0
- package/dist/chunks/{utils.BfxieIyZ.js → utils.DPCq3gzW.js} +3 -0
- package/dist/chunks/{vi.BFR5YIgu.js → vi.pkoYCV6A.js} +25 -2
- package/dist/chunks/{vite.d.DjP_ALCZ.d.ts → vite.d.B-Kx3KCF.d.ts} +3 -1
- package/dist/chunks/{vm.CuLHT1BG.js → vm.DPYem2so.js} +72 -4
- package/dist/chunks/{worker.d.CoCI7hzP.d.ts → worker.d.BKbBp2ga.d.ts} +2 -2
- package/dist/chunks/{worker.d.D5Xdi-Zr.d.ts → worker.d.Bl1O4kuf.d.ts} +1 -1
- package/dist/cli.js +21 -2
- package/dist/config.cjs +2 -0
- package/dist/config.d.ts +7 -6
- package/dist/config.js +2 -2
- package/dist/coverage.d.ts +4 -4
- package/dist/coverage.js +7 -10
- package/dist/environments.d.ts +6 -2
- package/dist/environments.js +1 -1
- package/dist/execute.d.ts +9 -3
- package/dist/execute.js +1 -1
- package/dist/index.d.ts +25 -35
- package/dist/index.js +5 -6
- package/dist/node.d.ts +18 -10
- package/dist/node.js +22 -22
- package/dist/reporters.d.ts +4 -4
- package/dist/reporters.js +14 -14
- package/dist/runners.d.ts +1 -1
- package/dist/runners.js +13 -5
- package/dist/snapshot.js +2 -2
- package/dist/suite.js +2 -2
- package/dist/worker.js +9 -5
- package/dist/workers/forks.js +6 -4
- package/dist/workers/runVmTests.js +14 -10
- package/dist/workers/threads.js +4 -4
- package/dist/workers/vmForks.js +6 -6
- package/dist/workers/vmThreads.js +6 -6
- package/dist/workers.d.ts +4 -4
- package/dist/workers.js +10 -10
- package/package.json +22 -26
- package/dist/chunks/index.Bw6JxgX8.js +0 -143
- package/dist/chunks/run-once.Dimr7O9f.js +0 -47
- package/dist/chunks/typechecker.DYQbn8uK.js +0 -956
- package/dist/chunks/utils.8gfOgtry.js +0 -207
- package/dist/utils.d.ts +0 -3
- package/dist/utils.js +0 -2
|
@@ -0,0 +1,954 @@
|
|
|
1
|
+
import nodeos__default from 'node:os';
|
|
2
|
+
import { performance } from 'node:perf_hooks';
|
|
3
|
+
import { TraceMap, generatedPositionFor, eachMapping } from '@vitest/utils/source-map';
|
|
4
|
+
import { relative, basename, resolve, join } from 'pathe';
|
|
5
|
+
import { x } from 'tinyexec';
|
|
6
|
+
import { distDir } from '../path.js';
|
|
7
|
+
import { getTests, generateHash, calculateSuiteHash, someTasksAreOnly, interpretTaskModes } from '@vitest/runner/utils';
|
|
8
|
+
import '@vitest/utils';
|
|
9
|
+
import { parseAstAsync } from 'vite';
|
|
10
|
+
|
|
11
|
+
function hasFailedSnapshot(suite) {
|
|
12
|
+
return getTests(suite).some((s) => {
|
|
13
|
+
return s.result?.errors?.some((e) => typeof e?.message === "string" && e.message.match(/Snapshot .* mismatched/));
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function convertTasksToEvents(file, onTask) {
|
|
17
|
+
const packs = [];
|
|
18
|
+
const events = [];
|
|
19
|
+
function visit(suite) {
|
|
20
|
+
onTask?.(suite);
|
|
21
|
+
packs.push([
|
|
22
|
+
suite.id,
|
|
23
|
+
suite.result,
|
|
24
|
+
suite.meta
|
|
25
|
+
]);
|
|
26
|
+
events.push([suite.id, "suite-prepare"]);
|
|
27
|
+
suite.tasks.forEach((task) => {
|
|
28
|
+
if (task.type === "suite") {
|
|
29
|
+
visit(task);
|
|
30
|
+
} else {
|
|
31
|
+
onTask?.(task);
|
|
32
|
+
if (suite.mode !== "skip" && suite.mode !== "todo") {
|
|
33
|
+
packs.push([
|
|
34
|
+
task.id,
|
|
35
|
+
task.result,
|
|
36
|
+
task.meta
|
|
37
|
+
]);
|
|
38
|
+
events.push([task.id, "test-prepare"], [task.id, "test-finished"]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
events.push([suite.id, "suite-finished"]);
|
|
43
|
+
}
|
|
44
|
+
visit(file);
|
|
45
|
+
return {
|
|
46
|
+
packs,
|
|
47
|
+
events
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const REGEXP_WRAP_PREFIX = "$$vitest:";
|
|
52
|
+
function getOutputFile(config, reporter) {
|
|
53
|
+
if (!config?.outputFile) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (typeof config.outputFile === "string") {
|
|
57
|
+
return config.outputFile;
|
|
58
|
+
}
|
|
59
|
+
return config.outputFile[reporter];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Prepares `SerializedConfig` for serialization, e.g. `node:v8.serialize`
|
|
63
|
+
*/
|
|
64
|
+
function wrapSerializableConfig(config) {
|
|
65
|
+
let testNamePattern = config.testNamePattern;
|
|
66
|
+
let defines = config.defines;
|
|
67
|
+
// v8 serialize does not support regex
|
|
68
|
+
if (testNamePattern && typeof testNamePattern !== "string") {
|
|
69
|
+
testNamePattern = `${REGEXP_WRAP_PREFIX}${testNamePattern.toString()}`;
|
|
70
|
+
}
|
|
71
|
+
// v8 serialize drops properties with undefined value
|
|
72
|
+
if (defines) {
|
|
73
|
+
defines = {
|
|
74
|
+
keys: Object.keys(defines),
|
|
75
|
+
original: defines
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
...config,
|
|
80
|
+
testNamePattern,
|
|
81
|
+
defines
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// AST walker module for ESTree compatible trees
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
// An ancestor walk keeps an array of ancestor nodes (including the
|
|
89
|
+
// current node) and passes them to the callback as third parameter
|
|
90
|
+
// (and also as state parameter when no other state is present).
|
|
91
|
+
function ancestor(node, visitors, baseVisitor, state, override) {
|
|
92
|
+
var ancestors = [];
|
|
93
|
+
if (!baseVisitor) { baseVisitor = base
|
|
94
|
+
; }(function c(node, st, override) {
|
|
95
|
+
var type = override || node.type;
|
|
96
|
+
var isNew = node !== ancestors[ancestors.length - 1];
|
|
97
|
+
if (isNew) { ancestors.push(node); }
|
|
98
|
+
baseVisitor[type](node, st, c);
|
|
99
|
+
if (visitors[type]) { visitors[type](node, st || ancestors, ancestors); }
|
|
100
|
+
if (isNew) { ancestors.pop(); }
|
|
101
|
+
})(node, state, override);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function skipThrough(node, st, c) { c(node, st); }
|
|
105
|
+
function ignore(_node, _st, _c) {}
|
|
106
|
+
|
|
107
|
+
// Node walkers.
|
|
108
|
+
|
|
109
|
+
var base = {};
|
|
110
|
+
|
|
111
|
+
base.Program = base.BlockStatement = base.StaticBlock = function (node, st, c) {
|
|
112
|
+
for (var i = 0, list = node.body; i < list.length; i += 1)
|
|
113
|
+
{
|
|
114
|
+
var stmt = list[i];
|
|
115
|
+
|
|
116
|
+
c(stmt, st, "Statement");
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
base.Statement = skipThrough;
|
|
120
|
+
base.EmptyStatement = ignore;
|
|
121
|
+
base.ExpressionStatement = base.ParenthesizedExpression = base.ChainExpression =
|
|
122
|
+
function (node, st, c) { return c(node.expression, st, "Expression"); };
|
|
123
|
+
base.IfStatement = function (node, st, c) {
|
|
124
|
+
c(node.test, st, "Expression");
|
|
125
|
+
c(node.consequent, st, "Statement");
|
|
126
|
+
if (node.alternate) { c(node.alternate, st, "Statement"); }
|
|
127
|
+
};
|
|
128
|
+
base.LabeledStatement = function (node, st, c) { return c(node.body, st, "Statement"); };
|
|
129
|
+
base.BreakStatement = base.ContinueStatement = ignore;
|
|
130
|
+
base.WithStatement = function (node, st, c) {
|
|
131
|
+
c(node.object, st, "Expression");
|
|
132
|
+
c(node.body, st, "Statement");
|
|
133
|
+
};
|
|
134
|
+
base.SwitchStatement = function (node, st, c) {
|
|
135
|
+
c(node.discriminant, st, "Expression");
|
|
136
|
+
for (var i = 0, list = node.cases; i < list.length; i += 1) {
|
|
137
|
+
var cs = list[i];
|
|
138
|
+
|
|
139
|
+
c(cs, st);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
base.SwitchCase = function (node, st, c) {
|
|
143
|
+
if (node.test) { c(node.test, st, "Expression"); }
|
|
144
|
+
for (var i = 0, list = node.consequent; i < list.length; i += 1)
|
|
145
|
+
{
|
|
146
|
+
var cons = list[i];
|
|
147
|
+
|
|
148
|
+
c(cons, st, "Statement");
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
base.ReturnStatement = base.YieldExpression = base.AwaitExpression = function (node, st, c) {
|
|
152
|
+
if (node.argument) { c(node.argument, st, "Expression"); }
|
|
153
|
+
};
|
|
154
|
+
base.ThrowStatement = base.SpreadElement =
|
|
155
|
+
function (node, st, c) { return c(node.argument, st, "Expression"); };
|
|
156
|
+
base.TryStatement = function (node, st, c) {
|
|
157
|
+
c(node.block, st, "Statement");
|
|
158
|
+
if (node.handler) { c(node.handler, st); }
|
|
159
|
+
if (node.finalizer) { c(node.finalizer, st, "Statement"); }
|
|
160
|
+
};
|
|
161
|
+
base.CatchClause = function (node, st, c) {
|
|
162
|
+
if (node.param) { c(node.param, st, "Pattern"); }
|
|
163
|
+
c(node.body, st, "Statement");
|
|
164
|
+
};
|
|
165
|
+
base.WhileStatement = base.DoWhileStatement = function (node, st, c) {
|
|
166
|
+
c(node.test, st, "Expression");
|
|
167
|
+
c(node.body, st, "Statement");
|
|
168
|
+
};
|
|
169
|
+
base.ForStatement = function (node, st, c) {
|
|
170
|
+
if (node.init) { c(node.init, st, "ForInit"); }
|
|
171
|
+
if (node.test) { c(node.test, st, "Expression"); }
|
|
172
|
+
if (node.update) { c(node.update, st, "Expression"); }
|
|
173
|
+
c(node.body, st, "Statement");
|
|
174
|
+
};
|
|
175
|
+
base.ForInStatement = base.ForOfStatement = function (node, st, c) {
|
|
176
|
+
c(node.left, st, "ForInit");
|
|
177
|
+
c(node.right, st, "Expression");
|
|
178
|
+
c(node.body, st, "Statement");
|
|
179
|
+
};
|
|
180
|
+
base.ForInit = function (node, st, c) {
|
|
181
|
+
if (node.type === "VariableDeclaration") { c(node, st); }
|
|
182
|
+
else { c(node, st, "Expression"); }
|
|
183
|
+
};
|
|
184
|
+
base.DebuggerStatement = ignore;
|
|
185
|
+
|
|
186
|
+
base.FunctionDeclaration = function (node, st, c) { return c(node, st, "Function"); };
|
|
187
|
+
base.VariableDeclaration = function (node, st, c) {
|
|
188
|
+
for (var i = 0, list = node.declarations; i < list.length; i += 1)
|
|
189
|
+
{
|
|
190
|
+
var decl = list[i];
|
|
191
|
+
|
|
192
|
+
c(decl, st);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
base.VariableDeclarator = function (node, st, c) {
|
|
196
|
+
c(node.id, st, "Pattern");
|
|
197
|
+
if (node.init) { c(node.init, st, "Expression"); }
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
base.Function = function (node, st, c) {
|
|
201
|
+
if (node.id) { c(node.id, st, "Pattern"); }
|
|
202
|
+
for (var i = 0, list = node.params; i < list.length; i += 1)
|
|
203
|
+
{
|
|
204
|
+
var param = list[i];
|
|
205
|
+
|
|
206
|
+
c(param, st, "Pattern");
|
|
207
|
+
}
|
|
208
|
+
c(node.body, st, node.expression ? "Expression" : "Statement");
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
base.Pattern = function (node, st, c) {
|
|
212
|
+
if (node.type === "Identifier")
|
|
213
|
+
{ c(node, st, "VariablePattern"); }
|
|
214
|
+
else if (node.type === "MemberExpression")
|
|
215
|
+
{ c(node, st, "MemberPattern"); }
|
|
216
|
+
else
|
|
217
|
+
{ c(node, st); }
|
|
218
|
+
};
|
|
219
|
+
base.VariablePattern = ignore;
|
|
220
|
+
base.MemberPattern = skipThrough;
|
|
221
|
+
base.RestElement = function (node, st, c) { return c(node.argument, st, "Pattern"); };
|
|
222
|
+
base.ArrayPattern = function (node, st, c) {
|
|
223
|
+
for (var i = 0, list = node.elements; i < list.length; i += 1) {
|
|
224
|
+
var elt = list[i];
|
|
225
|
+
|
|
226
|
+
if (elt) { c(elt, st, "Pattern"); }
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
base.ObjectPattern = function (node, st, c) {
|
|
230
|
+
for (var i = 0, list = node.properties; i < list.length; i += 1) {
|
|
231
|
+
var prop = list[i];
|
|
232
|
+
|
|
233
|
+
if (prop.type === "Property") {
|
|
234
|
+
if (prop.computed) { c(prop.key, st, "Expression"); }
|
|
235
|
+
c(prop.value, st, "Pattern");
|
|
236
|
+
} else if (prop.type === "RestElement") {
|
|
237
|
+
c(prop.argument, st, "Pattern");
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
base.Expression = skipThrough;
|
|
243
|
+
base.ThisExpression = base.Super = base.MetaProperty = ignore;
|
|
244
|
+
base.ArrayExpression = function (node, st, c) {
|
|
245
|
+
for (var i = 0, list = node.elements; i < list.length; i += 1) {
|
|
246
|
+
var elt = list[i];
|
|
247
|
+
|
|
248
|
+
if (elt) { c(elt, st, "Expression"); }
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
base.ObjectExpression = function (node, st, c) {
|
|
252
|
+
for (var i = 0, list = node.properties; i < list.length; i += 1)
|
|
253
|
+
{
|
|
254
|
+
var prop = list[i];
|
|
255
|
+
|
|
256
|
+
c(prop, st);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
base.FunctionExpression = base.ArrowFunctionExpression = base.FunctionDeclaration;
|
|
260
|
+
base.SequenceExpression = function (node, st, c) {
|
|
261
|
+
for (var i = 0, list = node.expressions; i < list.length; i += 1)
|
|
262
|
+
{
|
|
263
|
+
var expr = list[i];
|
|
264
|
+
|
|
265
|
+
c(expr, st, "Expression");
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
base.TemplateLiteral = function (node, st, c) {
|
|
269
|
+
for (var i = 0, list = node.quasis; i < list.length; i += 1)
|
|
270
|
+
{
|
|
271
|
+
var quasi = list[i];
|
|
272
|
+
|
|
273
|
+
c(quasi, st);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
for (var i$1 = 0, list$1 = node.expressions; i$1 < list$1.length; i$1 += 1)
|
|
277
|
+
{
|
|
278
|
+
var expr = list$1[i$1];
|
|
279
|
+
|
|
280
|
+
c(expr, st, "Expression");
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
base.TemplateElement = ignore;
|
|
284
|
+
base.UnaryExpression = base.UpdateExpression = function (node, st, c) {
|
|
285
|
+
c(node.argument, st, "Expression");
|
|
286
|
+
};
|
|
287
|
+
base.BinaryExpression = base.LogicalExpression = function (node, st, c) {
|
|
288
|
+
c(node.left, st, "Expression");
|
|
289
|
+
c(node.right, st, "Expression");
|
|
290
|
+
};
|
|
291
|
+
base.AssignmentExpression = base.AssignmentPattern = function (node, st, c) {
|
|
292
|
+
c(node.left, st, "Pattern");
|
|
293
|
+
c(node.right, st, "Expression");
|
|
294
|
+
};
|
|
295
|
+
base.ConditionalExpression = function (node, st, c) {
|
|
296
|
+
c(node.test, st, "Expression");
|
|
297
|
+
c(node.consequent, st, "Expression");
|
|
298
|
+
c(node.alternate, st, "Expression");
|
|
299
|
+
};
|
|
300
|
+
base.NewExpression = base.CallExpression = function (node, st, c) {
|
|
301
|
+
c(node.callee, st, "Expression");
|
|
302
|
+
if (node.arguments)
|
|
303
|
+
{ for (var i = 0, list = node.arguments; i < list.length; i += 1)
|
|
304
|
+
{
|
|
305
|
+
var arg = list[i];
|
|
306
|
+
|
|
307
|
+
c(arg, st, "Expression");
|
|
308
|
+
} }
|
|
309
|
+
};
|
|
310
|
+
base.MemberExpression = function (node, st, c) {
|
|
311
|
+
c(node.object, st, "Expression");
|
|
312
|
+
if (node.computed) { c(node.property, st, "Expression"); }
|
|
313
|
+
};
|
|
314
|
+
base.ExportNamedDeclaration = base.ExportDefaultDeclaration = function (node, st, c) {
|
|
315
|
+
if (node.declaration)
|
|
316
|
+
{ c(node.declaration, st, node.type === "ExportNamedDeclaration" || node.declaration.id ? "Statement" : "Expression"); }
|
|
317
|
+
if (node.source) { c(node.source, st, "Expression"); }
|
|
318
|
+
};
|
|
319
|
+
base.ExportAllDeclaration = function (node, st, c) {
|
|
320
|
+
if (node.exported)
|
|
321
|
+
{ c(node.exported, st); }
|
|
322
|
+
c(node.source, st, "Expression");
|
|
323
|
+
};
|
|
324
|
+
base.ImportDeclaration = function (node, st, c) {
|
|
325
|
+
for (var i = 0, list = node.specifiers; i < list.length; i += 1)
|
|
326
|
+
{
|
|
327
|
+
var spec = list[i];
|
|
328
|
+
|
|
329
|
+
c(spec, st);
|
|
330
|
+
}
|
|
331
|
+
c(node.source, st, "Expression");
|
|
332
|
+
};
|
|
333
|
+
base.ImportExpression = function (node, st, c) {
|
|
334
|
+
c(node.source, st, "Expression");
|
|
335
|
+
};
|
|
336
|
+
base.ImportSpecifier = base.ImportDefaultSpecifier = base.ImportNamespaceSpecifier = base.Identifier = base.PrivateIdentifier = base.Literal = ignore;
|
|
337
|
+
|
|
338
|
+
base.TaggedTemplateExpression = function (node, st, c) {
|
|
339
|
+
c(node.tag, st, "Expression");
|
|
340
|
+
c(node.quasi, st, "Expression");
|
|
341
|
+
};
|
|
342
|
+
base.ClassDeclaration = base.ClassExpression = function (node, st, c) { return c(node, st, "Class"); };
|
|
343
|
+
base.Class = function (node, st, c) {
|
|
344
|
+
if (node.id) { c(node.id, st, "Pattern"); }
|
|
345
|
+
if (node.superClass) { c(node.superClass, st, "Expression"); }
|
|
346
|
+
c(node.body, st);
|
|
347
|
+
};
|
|
348
|
+
base.ClassBody = function (node, st, c) {
|
|
349
|
+
for (var i = 0, list = node.body; i < list.length; i += 1)
|
|
350
|
+
{
|
|
351
|
+
var elt = list[i];
|
|
352
|
+
|
|
353
|
+
c(elt, st);
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
base.MethodDefinition = base.PropertyDefinition = base.Property = function (node, st, c) {
|
|
357
|
+
if (node.computed) { c(node.key, st, "Expression"); }
|
|
358
|
+
if (node.value) { c(node.value, st, "Expression"); }
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
async function collectTests(ctx, filepath) {
|
|
362
|
+
const request = await ctx.vitenode.transformRequest(filepath, filepath);
|
|
363
|
+
if (!request) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
const ast = await parseAstAsync(request.code);
|
|
367
|
+
const testFilepath = relative(ctx.config.root, filepath);
|
|
368
|
+
const projectName = ctx.name;
|
|
369
|
+
const typecheckSubprojectName = projectName ? `${projectName}:__typecheck__` : "__typecheck__";
|
|
370
|
+
const file = {
|
|
371
|
+
filepath,
|
|
372
|
+
type: "suite",
|
|
373
|
+
id: generateHash(`${testFilepath}${typecheckSubprojectName}`),
|
|
374
|
+
name: testFilepath,
|
|
375
|
+
mode: "run",
|
|
376
|
+
tasks: [],
|
|
377
|
+
start: ast.start,
|
|
378
|
+
end: ast.end,
|
|
379
|
+
projectName,
|
|
380
|
+
meta: { typecheck: true },
|
|
381
|
+
file: null
|
|
382
|
+
};
|
|
383
|
+
file.file = file;
|
|
384
|
+
const definitions = [];
|
|
385
|
+
const getName = (callee) => {
|
|
386
|
+
if (!callee) {
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
if (callee.type === "Identifier") {
|
|
390
|
+
return callee.name;
|
|
391
|
+
}
|
|
392
|
+
if (callee.type === "CallExpression") {
|
|
393
|
+
return getName(callee.callee);
|
|
394
|
+
}
|
|
395
|
+
if (callee.type === "TaggedTemplateExpression") {
|
|
396
|
+
return getName(callee.tag);
|
|
397
|
+
}
|
|
398
|
+
if (callee.type === "MemberExpression") {
|
|
399
|
+
if (callee.object?.type === "Identifier" && [
|
|
400
|
+
"it",
|
|
401
|
+
"test",
|
|
402
|
+
"describe",
|
|
403
|
+
"suite"
|
|
404
|
+
].includes(callee.object.name)) {
|
|
405
|
+
return callee.object?.name;
|
|
406
|
+
}
|
|
407
|
+
// direct call as `__vite_ssr_exports_0__.test()`
|
|
408
|
+
if (callee.object?.name?.startsWith("__vite_ssr_")) {
|
|
409
|
+
return getName(callee.property);
|
|
410
|
+
}
|
|
411
|
+
// call as `__vite_ssr__.test.skip()`
|
|
412
|
+
return getName(callee.object?.property);
|
|
413
|
+
}
|
|
414
|
+
// unwrap (0, ...)
|
|
415
|
+
if (callee.type === "SequenceExpression" && callee.expressions.length === 2) {
|
|
416
|
+
const [e0, e1] = callee.expressions;
|
|
417
|
+
if (e0.type === "Literal" && e0.value === 0) {
|
|
418
|
+
return getName(e1);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return null;
|
|
422
|
+
};
|
|
423
|
+
ancestor(ast, { CallExpression(node) {
|
|
424
|
+
const { callee } = node;
|
|
425
|
+
const name = getName(callee);
|
|
426
|
+
if (!name) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
if (![
|
|
430
|
+
"it",
|
|
431
|
+
"test",
|
|
432
|
+
"describe",
|
|
433
|
+
"suite"
|
|
434
|
+
].includes(name)) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
const property = callee?.property?.name;
|
|
438
|
+
let mode = !property || property === name ? "run" : property;
|
|
439
|
+
// they will be picked up in the next iteration
|
|
440
|
+
if ([
|
|
441
|
+
"each",
|
|
442
|
+
"for",
|
|
443
|
+
"skipIf",
|
|
444
|
+
"runIf"
|
|
445
|
+
].includes(mode)) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
let start;
|
|
449
|
+
const end = node.end;
|
|
450
|
+
// .each
|
|
451
|
+
if (callee.type === "CallExpression") {
|
|
452
|
+
start = callee.end;
|
|
453
|
+
} else if (callee.type === "TaggedTemplateExpression") {
|
|
454
|
+
start = callee.end + 1;
|
|
455
|
+
} else {
|
|
456
|
+
start = node.start;
|
|
457
|
+
}
|
|
458
|
+
const { arguments: [messageNode] } = node;
|
|
459
|
+
const isQuoted = messageNode?.type === "Literal" || messageNode?.type === "TemplateLiteral";
|
|
460
|
+
const message = isQuoted ? request.code.slice(messageNode.start + 1, messageNode.end - 1) : request.code.slice(messageNode.start, messageNode.end);
|
|
461
|
+
// cannot statically analyze, so we always skip it
|
|
462
|
+
if (mode === "skipIf" || mode === "runIf") {
|
|
463
|
+
mode = "skip";
|
|
464
|
+
}
|
|
465
|
+
definitions.push({
|
|
466
|
+
start,
|
|
467
|
+
end,
|
|
468
|
+
name: message,
|
|
469
|
+
type: name === "it" || name === "test" ? "test" : "suite",
|
|
470
|
+
mode,
|
|
471
|
+
task: null
|
|
472
|
+
});
|
|
473
|
+
} });
|
|
474
|
+
let lastSuite = file;
|
|
475
|
+
const updateLatestSuite = (index) => {
|
|
476
|
+
while (lastSuite.suite && lastSuite.end < index) {
|
|
477
|
+
lastSuite = lastSuite.suite;
|
|
478
|
+
}
|
|
479
|
+
return lastSuite;
|
|
480
|
+
};
|
|
481
|
+
definitions.sort((a, b) => a.start - b.start).forEach((definition) => {
|
|
482
|
+
const latestSuite = updateLatestSuite(definition.start);
|
|
483
|
+
let mode = definition.mode;
|
|
484
|
+
if (latestSuite.mode !== "run") {
|
|
485
|
+
// inherit suite mode, if it's set
|
|
486
|
+
mode = latestSuite.mode;
|
|
487
|
+
}
|
|
488
|
+
if (definition.type === "suite") {
|
|
489
|
+
const task = {
|
|
490
|
+
type: definition.type,
|
|
491
|
+
id: "",
|
|
492
|
+
suite: latestSuite,
|
|
493
|
+
file,
|
|
494
|
+
tasks: [],
|
|
495
|
+
mode,
|
|
496
|
+
name: definition.name,
|
|
497
|
+
end: definition.end,
|
|
498
|
+
start: definition.start,
|
|
499
|
+
meta: { typecheck: true }
|
|
500
|
+
};
|
|
501
|
+
definition.task = task;
|
|
502
|
+
latestSuite.tasks.push(task);
|
|
503
|
+
lastSuite = task;
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
const task = {
|
|
507
|
+
type: definition.type,
|
|
508
|
+
id: "",
|
|
509
|
+
suite: latestSuite,
|
|
510
|
+
file,
|
|
511
|
+
mode,
|
|
512
|
+
timeout: 0,
|
|
513
|
+
context: {},
|
|
514
|
+
name: definition.name,
|
|
515
|
+
end: definition.end,
|
|
516
|
+
start: definition.start,
|
|
517
|
+
meta: { typecheck: true }
|
|
518
|
+
};
|
|
519
|
+
definition.task = task;
|
|
520
|
+
latestSuite.tasks.push(task);
|
|
521
|
+
});
|
|
522
|
+
calculateSuiteHash(file);
|
|
523
|
+
const hasOnly = someTasksAreOnly(file);
|
|
524
|
+
interpretTaskModes(file, ctx.config.testNamePattern, undefined, hasOnly, false, ctx.config.allowOnly);
|
|
525
|
+
return {
|
|
526
|
+
file,
|
|
527
|
+
parsed: request.code,
|
|
528
|
+
filepath,
|
|
529
|
+
map: request.map,
|
|
530
|
+
definitions
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const newLineRegExp = /\r?\n/;
|
|
535
|
+
const errCodeRegExp = /error TS(?<errCode>\d+)/;
|
|
536
|
+
async function makeTscErrorInfo(errInfo) {
|
|
537
|
+
const [errFilePathPos = "", ...errMsgRawArr] = errInfo.split(":");
|
|
538
|
+
if (!errFilePathPos || errMsgRawArr.length === 0 || errMsgRawArr.join("").length === 0) {
|
|
539
|
+
return ["unknown filepath", null];
|
|
540
|
+
}
|
|
541
|
+
const errMsgRaw = errMsgRawArr.join("").trim();
|
|
542
|
+
// get filePath, line, col
|
|
543
|
+
const [errFilePath, errPos] = errFilePathPos.slice(0, -1).split("(");
|
|
544
|
+
if (!errFilePath || !errPos) {
|
|
545
|
+
return ["unknown filepath", null];
|
|
546
|
+
}
|
|
547
|
+
const [errLine, errCol] = errPos.split(",");
|
|
548
|
+
if (!errLine || !errCol) {
|
|
549
|
+
return [errFilePath, null];
|
|
550
|
+
}
|
|
551
|
+
// get errCode, errMsg
|
|
552
|
+
const execArr = errCodeRegExp.exec(errMsgRaw);
|
|
553
|
+
if (!execArr) {
|
|
554
|
+
return [errFilePath, null];
|
|
555
|
+
}
|
|
556
|
+
const errCodeStr = execArr.groups?.errCode ?? "";
|
|
557
|
+
if (!errCodeStr) {
|
|
558
|
+
return [errFilePath, null];
|
|
559
|
+
}
|
|
560
|
+
const line = Number(errLine);
|
|
561
|
+
const col = Number(errCol);
|
|
562
|
+
const errCode = Number(errCodeStr);
|
|
563
|
+
return [errFilePath, {
|
|
564
|
+
filePath: errFilePath,
|
|
565
|
+
errCode,
|
|
566
|
+
line,
|
|
567
|
+
column: col,
|
|
568
|
+
errMsg: errMsgRaw.slice(`error TS${errCode} `.length)
|
|
569
|
+
}];
|
|
570
|
+
}
|
|
571
|
+
async function getRawErrsMapFromTsCompile(tscErrorStdout) {
|
|
572
|
+
const rawErrsMap = new Map();
|
|
573
|
+
// Merge details line with main line (i.e. which contains file path)
|
|
574
|
+
const infos = await Promise.all(tscErrorStdout.split(newLineRegExp).reduce((prev, next) => {
|
|
575
|
+
if (!next) {
|
|
576
|
+
return prev;
|
|
577
|
+
} else if (!next.startsWith(" ")) {
|
|
578
|
+
prev.push(next);
|
|
579
|
+
} else {
|
|
580
|
+
prev[prev.length - 1] += `\n${next}`;
|
|
581
|
+
}
|
|
582
|
+
return prev;
|
|
583
|
+
}, []).map((errInfoLine) => makeTscErrorInfo(errInfoLine)));
|
|
584
|
+
infos.forEach(([errFilePath, errInfo]) => {
|
|
585
|
+
if (!errInfo) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
if (!rawErrsMap.has(errFilePath)) {
|
|
589
|
+
rawErrsMap.set(errFilePath, [errInfo]);
|
|
590
|
+
} else {
|
|
591
|
+
rawErrsMap.get(errFilePath)?.push(errInfo);
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
return rawErrsMap;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
function createIndexMap(source) {
|
|
598
|
+
const map = new Map();
|
|
599
|
+
let index = 0;
|
|
600
|
+
let line = 1;
|
|
601
|
+
let column = 1;
|
|
602
|
+
for (const char of source) {
|
|
603
|
+
map.set(`${line}:${column}`, index++);
|
|
604
|
+
if (char === "\n" || char === "\r\n") {
|
|
605
|
+
line++;
|
|
606
|
+
column = 0;
|
|
607
|
+
} else {
|
|
608
|
+
column++;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
return map;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
class TypeCheckError extends Error {
|
|
615
|
+
name = "TypeCheckError";
|
|
616
|
+
constructor(message, stacks) {
|
|
617
|
+
super(message);
|
|
618
|
+
this.message = message;
|
|
619
|
+
this.stacks = stacks;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
class Typechecker {
|
|
623
|
+
_onParseStart;
|
|
624
|
+
_onParseEnd;
|
|
625
|
+
_onWatcherRerun;
|
|
626
|
+
_result = {
|
|
627
|
+
files: [],
|
|
628
|
+
sourceErrors: [],
|
|
629
|
+
time: 0
|
|
630
|
+
};
|
|
631
|
+
_startTime = 0;
|
|
632
|
+
_output = "";
|
|
633
|
+
_tests = {};
|
|
634
|
+
process;
|
|
635
|
+
files = [];
|
|
636
|
+
constructor(project) {
|
|
637
|
+
this.project = project;
|
|
638
|
+
}
|
|
639
|
+
setFiles(files) {
|
|
640
|
+
this.files = files;
|
|
641
|
+
}
|
|
642
|
+
onParseStart(fn) {
|
|
643
|
+
this._onParseStart = fn;
|
|
644
|
+
}
|
|
645
|
+
onParseEnd(fn) {
|
|
646
|
+
this._onParseEnd = fn;
|
|
647
|
+
}
|
|
648
|
+
onWatcherRerun(fn) {
|
|
649
|
+
this._onWatcherRerun = fn;
|
|
650
|
+
}
|
|
651
|
+
async collectFileTests(filepath) {
|
|
652
|
+
return collectTests(this.project, filepath);
|
|
653
|
+
}
|
|
654
|
+
getFiles() {
|
|
655
|
+
return this.files;
|
|
656
|
+
}
|
|
657
|
+
async collectTests() {
|
|
658
|
+
const tests = (await Promise.all(this.getFiles().map((filepath) => this.collectFileTests(filepath)))).reduce((acc, data) => {
|
|
659
|
+
if (!data) {
|
|
660
|
+
return acc;
|
|
661
|
+
}
|
|
662
|
+
acc[data.filepath] = data;
|
|
663
|
+
return acc;
|
|
664
|
+
}, {});
|
|
665
|
+
this._tests = tests;
|
|
666
|
+
return tests;
|
|
667
|
+
}
|
|
668
|
+
markPassed(file) {
|
|
669
|
+
if (!file.result?.state) {
|
|
670
|
+
file.result = { state: "pass" };
|
|
671
|
+
}
|
|
672
|
+
const markTasks = (tasks) => {
|
|
673
|
+
for (const task of tasks) {
|
|
674
|
+
if ("tasks" in task) {
|
|
675
|
+
markTasks(task.tasks);
|
|
676
|
+
}
|
|
677
|
+
if (!task.result?.state && (task.mode === "run" || task.mode === "queued")) {
|
|
678
|
+
task.result = { state: "pass" };
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
markTasks(file.tasks);
|
|
683
|
+
}
|
|
684
|
+
async prepareResults(output) {
|
|
685
|
+
const typeErrors = await this.parseTscLikeOutput(output);
|
|
686
|
+
const testFiles = new Set(this.getFiles());
|
|
687
|
+
if (!this._tests) {
|
|
688
|
+
this._tests = await this.collectTests();
|
|
689
|
+
}
|
|
690
|
+
const sourceErrors = [];
|
|
691
|
+
const files = [];
|
|
692
|
+
testFiles.forEach((path) => {
|
|
693
|
+
const { file, definitions, map, parsed } = this._tests[path];
|
|
694
|
+
const errors = typeErrors.get(path);
|
|
695
|
+
files.push(file);
|
|
696
|
+
if (!errors) {
|
|
697
|
+
this.markPassed(file);
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
const sortedDefinitions = [...definitions.sort((a, b) => b.start - a.start)];
|
|
701
|
+
// has no map for ".js" files that use // @ts-check
|
|
702
|
+
const traceMap = map && new TraceMap(map);
|
|
703
|
+
const indexMap = createIndexMap(parsed);
|
|
704
|
+
const markState = (task, state) => {
|
|
705
|
+
task.result = { state: task.mode === "run" || task.mode === "only" ? state : task.mode };
|
|
706
|
+
if (task.suite) {
|
|
707
|
+
markState(task.suite, state);
|
|
708
|
+
} else if (task.file && task !== task.file) {
|
|
709
|
+
markState(task.file, state);
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
errors.forEach(({ error, originalError }) => {
|
|
713
|
+
const processedPos = traceMap ? findGeneratedPosition(traceMap, {
|
|
714
|
+
line: originalError.line,
|
|
715
|
+
column: originalError.column,
|
|
716
|
+
source: basename(path)
|
|
717
|
+
}) : originalError;
|
|
718
|
+
const line = processedPos.line ?? originalError.line;
|
|
719
|
+
const column = processedPos.column ?? originalError.column;
|
|
720
|
+
const index = indexMap.get(`${line}:${column}`);
|
|
721
|
+
const definition = index != null && sortedDefinitions.find((def) => def.start <= index && def.end >= index);
|
|
722
|
+
const suite = definition ? definition.task : file;
|
|
723
|
+
const state = suite.mode === "run" || suite.mode === "only" ? "fail" : suite.mode;
|
|
724
|
+
const errors = suite.result?.errors || [];
|
|
725
|
+
suite.result = {
|
|
726
|
+
state,
|
|
727
|
+
errors
|
|
728
|
+
};
|
|
729
|
+
errors.push(error);
|
|
730
|
+
if (state === "fail") {
|
|
731
|
+
if (suite.suite) {
|
|
732
|
+
markState(suite.suite, "fail");
|
|
733
|
+
} else if (suite.file && suite !== suite.file) {
|
|
734
|
+
markState(suite.file, "fail");
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
this.markPassed(file);
|
|
739
|
+
});
|
|
740
|
+
typeErrors.forEach((errors, path) => {
|
|
741
|
+
if (!testFiles.has(path)) {
|
|
742
|
+
sourceErrors.push(...errors.map(({ error }) => error));
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
return {
|
|
746
|
+
files,
|
|
747
|
+
sourceErrors,
|
|
748
|
+
time: performance.now() - this._startTime
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
async parseTscLikeOutput(output) {
|
|
752
|
+
const errorsMap = await getRawErrsMapFromTsCompile(output);
|
|
753
|
+
const typesErrors = new Map();
|
|
754
|
+
errorsMap.forEach((errors, path) => {
|
|
755
|
+
const filepath = resolve(this.project.config.root, path);
|
|
756
|
+
const suiteErrors = errors.map((info) => {
|
|
757
|
+
const limit = Error.stackTraceLimit;
|
|
758
|
+
Error.stackTraceLimit = 0;
|
|
759
|
+
// 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.`
|
|
760
|
+
const errMsg = info.errMsg.replace(/\r?\n\s*(Type .* has no call signatures)/g, " $1");
|
|
761
|
+
const error = new TypeCheckError(errMsg, [{
|
|
762
|
+
file: filepath,
|
|
763
|
+
line: info.line,
|
|
764
|
+
column: info.column,
|
|
765
|
+
method: ""
|
|
766
|
+
}]);
|
|
767
|
+
Error.stackTraceLimit = limit;
|
|
768
|
+
return {
|
|
769
|
+
originalError: info,
|
|
770
|
+
error: {
|
|
771
|
+
name: error.name,
|
|
772
|
+
nameStr: String(error.name),
|
|
773
|
+
message: errMsg,
|
|
774
|
+
stacks: error.stacks,
|
|
775
|
+
stack: "",
|
|
776
|
+
stackStr: ""
|
|
777
|
+
}
|
|
778
|
+
};
|
|
779
|
+
});
|
|
780
|
+
typesErrors.set(filepath, suiteErrors);
|
|
781
|
+
});
|
|
782
|
+
return typesErrors;
|
|
783
|
+
}
|
|
784
|
+
async stop() {
|
|
785
|
+
this.process?.kill();
|
|
786
|
+
this.process = undefined;
|
|
787
|
+
}
|
|
788
|
+
async ensurePackageInstalled(ctx, checker) {
|
|
789
|
+
if (checker !== "tsc" && checker !== "vue-tsc") {
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
const packageName = checker === "tsc" ? "typescript" : "vue-tsc";
|
|
793
|
+
await ctx.packageInstaller.ensureInstalled(packageName, ctx.config.root);
|
|
794
|
+
}
|
|
795
|
+
getExitCode() {
|
|
796
|
+
return this.process?.exitCode != null && this.process.exitCode;
|
|
797
|
+
}
|
|
798
|
+
getOutput() {
|
|
799
|
+
return this._output;
|
|
800
|
+
}
|
|
801
|
+
async spawn() {
|
|
802
|
+
const { root, watch, typecheck } = this.project.config;
|
|
803
|
+
const args = [
|
|
804
|
+
"--noEmit",
|
|
805
|
+
"--pretty",
|
|
806
|
+
"false",
|
|
807
|
+
"--incremental",
|
|
808
|
+
"--tsBuildInfoFile",
|
|
809
|
+
join(process.versions.pnp ? join(nodeos__default.tmpdir(), this.project.hash) : distDir, "tsconfig.tmp.tsbuildinfo")
|
|
810
|
+
];
|
|
811
|
+
// use builtin watcher because it's faster
|
|
812
|
+
if (watch) {
|
|
813
|
+
args.push("--watch");
|
|
814
|
+
}
|
|
815
|
+
if (typecheck.allowJs) {
|
|
816
|
+
args.push("--allowJs", "--checkJs");
|
|
817
|
+
}
|
|
818
|
+
if (typecheck.tsconfig) {
|
|
819
|
+
args.push("-p", resolve(root, typecheck.tsconfig));
|
|
820
|
+
}
|
|
821
|
+
this._output = "";
|
|
822
|
+
this._startTime = performance.now();
|
|
823
|
+
const child = x(typecheck.checker, args, {
|
|
824
|
+
nodeOptions: {
|
|
825
|
+
cwd: root,
|
|
826
|
+
stdio: "pipe"
|
|
827
|
+
},
|
|
828
|
+
throwOnError: false
|
|
829
|
+
});
|
|
830
|
+
this.process = child.process;
|
|
831
|
+
let rerunTriggered = false;
|
|
832
|
+
let dataReceived = false;
|
|
833
|
+
return new Promise((resolve, reject) => {
|
|
834
|
+
if (!child.process || !child.process.stdout) {
|
|
835
|
+
reject(new Error(`Failed to initialize ${typecheck.checker}. This is a bug in Vitest - please, open an issue with reproduction.`));
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
child.process.stdout.on("data", (chunk) => {
|
|
839
|
+
dataReceived = true;
|
|
840
|
+
this._output += chunk;
|
|
841
|
+
if (!watch) {
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
if (this._output.includes("File change detected") && !rerunTriggered) {
|
|
845
|
+
this._onWatcherRerun?.();
|
|
846
|
+
this._startTime = performance.now();
|
|
847
|
+
this._result.sourceErrors = [];
|
|
848
|
+
this._result.files = [];
|
|
849
|
+
this._tests = null;
|
|
850
|
+
rerunTriggered = true;
|
|
851
|
+
}
|
|
852
|
+
if (/Found \w+ errors*. Watching for/.test(this._output)) {
|
|
853
|
+
rerunTriggered = false;
|
|
854
|
+
this.prepareResults(this._output).then((result) => {
|
|
855
|
+
this._result = result;
|
|
856
|
+
this._onParseEnd?.(result);
|
|
857
|
+
});
|
|
858
|
+
this._output = "";
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
const timeout = setTimeout(() => reject(new Error(`${typecheck.checker} spawn timed out`)), this.project.config.typecheck.spawnTimeout);
|
|
862
|
+
function onError(cause) {
|
|
863
|
+
clearTimeout(timeout);
|
|
864
|
+
reject(new Error("Spawning typechecker failed - is typescript installed?", { cause }));
|
|
865
|
+
}
|
|
866
|
+
child.process.once("spawn", () => {
|
|
867
|
+
this._onParseStart?.();
|
|
868
|
+
child.process?.off("error", onError);
|
|
869
|
+
clearTimeout(timeout);
|
|
870
|
+
if (process.platform === "win32") {
|
|
871
|
+
// on Windows, the process might be spawned but fail to start
|
|
872
|
+
// we wait for a potential error here. if "close" event didn't trigger,
|
|
873
|
+
// we resolve the promise
|
|
874
|
+
setTimeout(() => {
|
|
875
|
+
resolve({ result: child });
|
|
876
|
+
}, 200);
|
|
877
|
+
} else {
|
|
878
|
+
resolve({ result: child });
|
|
879
|
+
}
|
|
880
|
+
});
|
|
881
|
+
if (process.platform === "win32") {
|
|
882
|
+
child.process.once("close", (code) => {
|
|
883
|
+
if (code != null && code !== 0 && !dataReceived) {
|
|
884
|
+
onError(new Error(`The ${typecheck.checker} command exited with code ${code}.`));
|
|
885
|
+
}
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
child.process.once("error", onError);
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
async start() {
|
|
892
|
+
if (this.process) {
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
const { watch } = this.project.config;
|
|
896
|
+
const { result: child } = await this.spawn();
|
|
897
|
+
if (!watch) {
|
|
898
|
+
await child;
|
|
899
|
+
this._result = await this.prepareResults(this._output);
|
|
900
|
+
await this._onParseEnd?.(this._result);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
getResult() {
|
|
904
|
+
return this._result;
|
|
905
|
+
}
|
|
906
|
+
getTestFiles() {
|
|
907
|
+
return Object.values(this._tests || {}).map((i) => i.file);
|
|
908
|
+
}
|
|
909
|
+
getTestPacksAndEvents() {
|
|
910
|
+
const packs = [];
|
|
911
|
+
const events = [];
|
|
912
|
+
for (const { file } of Object.values(this._tests || {})) {
|
|
913
|
+
const result = convertTasksToEvents(file);
|
|
914
|
+
packs.push(...result.packs);
|
|
915
|
+
events.push(...result.events);
|
|
916
|
+
}
|
|
917
|
+
return {
|
|
918
|
+
packs,
|
|
919
|
+
events
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
function findGeneratedPosition(traceMap, { line, column, source }) {
|
|
924
|
+
const found = generatedPositionFor(traceMap, {
|
|
925
|
+
line,
|
|
926
|
+
column,
|
|
927
|
+
source
|
|
928
|
+
});
|
|
929
|
+
if (found.line !== null) {
|
|
930
|
+
return found;
|
|
931
|
+
}
|
|
932
|
+
// find the next source token position when the exact error position doesn't exist in source map.
|
|
933
|
+
// this can happen, for example, when the type error is in the comment "// @ts-expect-error"
|
|
934
|
+
// and comments are stripped away in the generated code.
|
|
935
|
+
const mappings = [];
|
|
936
|
+
eachMapping(traceMap, (m) => {
|
|
937
|
+
if (m.source === source && m.originalLine !== null && m.originalColumn !== null && (line === m.originalLine ? column < m.originalColumn : line < m.originalLine)) {
|
|
938
|
+
mappings.push(m);
|
|
939
|
+
}
|
|
940
|
+
});
|
|
941
|
+
const next = mappings.sort((a, b) => a.originalLine === b.originalLine ? a.originalColumn - b.originalColumn : a.originalLine - b.originalLine).at(0);
|
|
942
|
+
if (next) {
|
|
943
|
+
return {
|
|
944
|
+
line: next.generatedLine,
|
|
945
|
+
column: next.generatedColumn
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
return {
|
|
949
|
+
line: null,
|
|
950
|
+
column: null
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
export { TypeCheckError as T, Typechecker as a, convertTasksToEvents as c, getOutputFile as g, hasFailedSnapshot as h, wrapSerializableConfig as w };
|