vitest-pool-assemblyscript 0.9.1 → 0.10.1
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/assembly/compare.ts +11 -12
- package/assembly/describe.ts +4 -4
- package/assembly/expect.ts +44 -26
- package/assembly/test.ts +9 -9
- package/assembly/utils.ts +218 -62
- package/dist/{addon-interface-CYFXMbK7.mjs → addon-interface-BaUmn7uC.mjs} +12 -12
- package/dist/addon-interface-BaUmn7uC.mjs.map +1 -0
- package/dist/{ast-visitor-CWEOd3UH.mjs → ast-visitor-w1HMbuJR.mjs} +2 -2
- package/dist/{ast-visitor-CWEOd3UH.mjs.map → ast-visitor-w1HMbuJR.mjs.map} +1 -1
- package/dist/compile-runner-BGHM_85g.mjs +82 -0
- package/dist/compile-runner-BGHM_85g.mjs.map +1 -0
- package/dist/compiler/transforms/deep-equals.d.mts.map +1 -1
- package/dist/compiler/transforms/deep-equals.mjs +61 -22
- package/dist/compiler/transforms/deep-equals.mjs.map +1 -1
- package/dist/compiler/transforms/strip-inline.mjs +2 -2
- package/dist/{compiler-Dqs-qd3I.mjs → compiler-CXR5UJId.mjs} +55 -27
- package/dist/compiler-CXR5UJId.mjs.map +1 -0
- package/dist/config/index-v3.d.mts +1 -1
- package/dist/config/index-v3.d.mts.map +1 -1
- package/dist/config/index-v3.mjs.map +1 -1
- package/dist/config/index.d.mts +2 -2
- package/dist/config/index.mjs +5 -7
- package/dist/{constants-DbxJ3hzg.mjs → constants-Bq5KNxXJ.mjs} +4 -2
- package/dist/constants-Bq5KNxXJ.mjs.map +1 -0
- package/dist/{coverage-merge-CBXkpM1O.mjs → coverage-merge-0WqdC-dq.mjs} +1 -1
- package/dist/{coverage-merge-CBXkpM1O.mjs.map → coverage-merge-0WqdC-dq.mjs.map} +1 -1
- package/dist/coverage-provider/index.mjs +36 -36
- package/dist/coverage-provider/index.mjs.map +1 -1
- package/dist/{feature-check-Bje3ntpV.mjs → feature-check-BJpc4LoO.mjs} +4 -4
- package/dist/{feature-check-Bje3ntpV.mjs.map → feature-check-BJpc4LoO.mjs.map} +1 -1
- package/dist/index-internal.d.mts +3 -3
- package/dist/index-internal.d.mts.map +1 -1
- package/dist/index-internal.mjs +5 -4
- package/dist/index-v3.d.mts.map +1 -1
- package/dist/index-v3.mjs +19 -33
- package/dist/index-v3.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +5 -7
- package/dist/{load-user-imports-Bx5ZlhSm.mjs → load-user-imports-Bcx9NOt9.mjs} +119 -232
- package/dist/load-user-imports-Bcx9NOt9.mjs.map +1 -0
- package/dist/pool-errors-Bn6YaguR.mjs +630 -0
- package/dist/pool-errors-Bn6YaguR.mjs.map +1 -0
- package/dist/{pool-runner-init-CNpRdA5u.d.mts → pool-runner-init-CCvnKt5o.d.mts} +2 -2
- package/dist/pool-runner-init-CCvnKt5o.d.mts.map +1 -0
- package/dist/{pool-runner-init-BqkwQ2tk.mjs → pool-runner-init-DjRCbiX-.mjs} +15 -30
- package/dist/pool-runner-init-DjRCbiX-.mjs.map +1 -0
- package/dist/pool-thread/compile-worker-thread.d.mts +1 -1
- package/dist/pool-thread/compile-worker-thread.d.mts.map +1 -1
- package/dist/pool-thread/compile-worker-thread.mjs +29 -19
- package/dist/pool-thread/compile-worker-thread.mjs.map +1 -1
- package/dist/pool-thread/test-worker-thread.d.mts +1 -1
- package/dist/pool-thread/test-worker-thread.d.mts.map +1 -1
- package/dist/pool-thread/test-worker-thread.mjs +25 -18
- package/dist/pool-thread/test-worker-thread.mjs.map +1 -1
- package/dist/pool-thread/v3-tinypool-thread.d.mts +1 -1
- package/dist/pool-thread/v3-tinypool-thread.d.mts.map +1 -1
- package/dist/pool-thread/v3-tinypool-thread.mjs +43 -33
- package/dist/pool-thread/v3-tinypool-thread.mjs.map +1 -1
- package/dist/test-runner-BeP8ClnE.mjs +147 -0
- package/dist/test-runner-BeP8ClnE.mjs.map +1 -0
- package/dist/{types-DHVk5iAx.d.mts → types-CoroKYxB.d.mts} +39 -16
- package/dist/types-CoroKYxB.d.mts.map +1 -0
- package/dist/vitest-file-tasks-vvZzigcF.mjs +473 -0
- package/dist/vitest-file-tasks-vvZzigcF.mjs.map +1 -0
- package/dist/wasm-memory-C8Nkl2Sz.mjs +134 -0
- package/dist/wasm-memory-C8Nkl2Sz.mjs.map +1 -0
- package/dist/{worker-rpc-channel-CZZIxtv5.mjs → worker-rpc-channel-CvCrc8aa.mjs} +1 -1
- package/dist/{worker-rpc-channel-CZZIxtv5.mjs.map → worker-rpc-channel-CvCrc8aa.mjs.map} +1 -1
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/prebuilds/darwin-x64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/prebuilds/linux-arm64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/prebuilds/linux-x64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/prebuilds/linux-x64/vitest-pool-assemblyscript.musl.node +0 -0
- package/prebuilds/win32-arm64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/prebuilds/win32-x64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/src/instrumentation/native/addon.cpp +71 -32
- package/dist/addon-interface-CYFXMbK7.mjs.map +0 -1
- package/dist/compile-runner-BNFHRGZO.mjs +0 -85
- package/dist/compile-runner-BNFHRGZO.mjs.map +0 -1
- package/dist/compiler-Dqs-qd3I.mjs.map +0 -1
- package/dist/constants-DbxJ3hzg.mjs.map +0 -1
- package/dist/debug-DtRAL4rM.mjs +0 -232
- package/dist/debug-DtRAL4rM.mjs.map +0 -1
- package/dist/load-user-imports-Bx5ZlhSm.mjs.map +0 -1
- package/dist/path-utils-t9OzjXYF.mjs +0 -24
- package/dist/path-utils-t9OzjXYF.mjs.map +0 -1
- package/dist/pool-runner-init-BqkwQ2tk.mjs.map +0 -1
- package/dist/pool-runner-init-CNpRdA5u.d.mts.map +0 -1
- package/dist/resolve-config-s9gSJSMc.mjs +0 -85
- package/dist/resolve-config-s9gSJSMc.mjs.map +0 -1
- package/dist/test-runner-BGqc9uCK.mjs +0 -138
- package/dist/test-runner-BGqc9uCK.mjs.map +0 -1
- package/dist/types-DHVk5iAx.d.mts.map +0 -1
- package/dist/vitest-file-tasks-D8sOClGX.mjs +0 -149
- package/dist/vitest-file-tasks-D8sOClGX.mjs.map +0 -1
- package/dist/vitest-tasks-BZ24sghI.mjs +0 -321
- package/dist/vitest-tasks-BZ24sghI.mjs.map +0 -1
- package/dist/wasm-names-BFtzQCH4.mjs +0 -124
- package/dist/wasm-names-BFtzQCH4.mjs.map +0 -1
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
import { POOL_ERROR_NAMES, POOL_INTERNAL_PATHS, TEST_ERROR_NAMES } from "./constants-Bq5KNxXJ.mjs";
|
|
2
|
+
import { relative } from "node:path";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { stripVTControlCharacters } from "node:util";
|
|
5
|
+
import c from "tinyrainbow";
|
|
6
|
+
import { highlight } from "tinyhighlight";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { diff } from "@vitest/utils/diff";
|
|
9
|
+
import { SourceMapConsumer } from "source-map";
|
|
10
|
+
|
|
11
|
+
//#region src/util/path-utils.ts
|
|
12
|
+
/**
|
|
13
|
+
* Path Utilities
|
|
14
|
+
*
|
|
15
|
+
* Cross-platform path normalization for consistent path comparisons.
|
|
16
|
+
* All internal paths use forward slashes.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Convert path to forward slashes for consistent cross-platform comparison.
|
|
20
|
+
*
|
|
21
|
+
* Source maps always use forward slashes regardless of OS. By normalizing
|
|
22
|
+
* all paths to forward slashes, we ensure consistent matching between:
|
|
23
|
+
* - Source map paths (already forward slashes)
|
|
24
|
+
* - Glob results (OS-native, need conversion on Windows)
|
|
25
|
+
* - Relative paths from Node's path.relative() (OS-native)
|
|
26
|
+
* - Resolved paths from Node's path.resolve() (OS-native)
|
|
27
|
+
*/
|
|
28
|
+
function toForwardSlash(path) {
|
|
29
|
+
return path.replace(/\\/g, "/");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/util/debug.ts
|
|
34
|
+
globalThis.AS_POOL_DEBUG = false;
|
|
35
|
+
const DEBUG_ENV_ENABLED_VALUE = "vitest_as_pool";
|
|
36
|
+
function isEnabled() {
|
|
37
|
+
return globalThis.AS_POOL_DEBUG === true || process.env.DEBUG === DEBUG_ENV_ENABLED_VALUE;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Initialize debug mode for current async context (called by worker at task start)
|
|
41
|
+
* @param {boolean} debugEnabled - Enable verbose debug logging
|
|
42
|
+
*/
|
|
43
|
+
function setGlobalDebugMode(debugEnabled) {
|
|
44
|
+
globalThis.AS_POOL_DEBUG = debugEnabled;
|
|
45
|
+
}
|
|
46
|
+
function debugLog(...args) {
|
|
47
|
+
if (args?.length > 0 && typeof args[0] === "function") {
|
|
48
|
+
const result = args[0]();
|
|
49
|
+
const rest = args.length > 1 ? args.slice(1) : [];
|
|
50
|
+
console.log(Date.now(), String(result), ...rest);
|
|
51
|
+
} else console.log(Date.now(), ...args);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Log debug message (only when debug enabled in current global context)
|
|
55
|
+
* or when environment has a given DEBUG variable set.
|
|
56
|
+
*/
|
|
57
|
+
function debug(...args) {
|
|
58
|
+
if (isEnabled()) debugLog(...args);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Log debug message (caller expected to determine if enabled)
|
|
62
|
+
*/
|
|
63
|
+
function debugOverride(...args) {
|
|
64
|
+
debugLog(...args);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/util/highlight-code.ts
|
|
69
|
+
/**
|
|
70
|
+
* Adapted from vitest. The internal function was changed between vitest 3.2.x and 4.0.x,
|
|
71
|
+
* and then removed from public exposure in 4.1.x, so now instead we recreate the same
|
|
72
|
+
* highlighting color rules.
|
|
73
|
+
*
|
|
74
|
+
* @see https://github.com/vitest-dev/vitest/blob/v4.1.0/packages/vitest/src/utils/colors.ts#L18
|
|
75
|
+
*
|
|
76
|
+
* Vitest is released under the MIT license, included in this project's root.
|
|
77
|
+
* Copyright (c) 2021-Present Vitest Team
|
|
78
|
+
*/
|
|
79
|
+
const colors = {
|
|
80
|
+
Keyword: c.magenta,
|
|
81
|
+
IdentifierCapitalized: c.yellow,
|
|
82
|
+
Punctuator: c.yellow,
|
|
83
|
+
StringLiteral: c.green,
|
|
84
|
+
NoSubstitutionTemplate: c.green,
|
|
85
|
+
MultiLineComment: c.gray,
|
|
86
|
+
SingleLineComment: c.gray,
|
|
87
|
+
RegularExpressionLiteral: c.cyan,
|
|
88
|
+
NumericLiteral: c.blue,
|
|
89
|
+
TemplateHead: (text) => c.green(text.slice(0, text.length - 2)) + c.cyan(text.slice(-2)),
|
|
90
|
+
TemplateTail: (text) => c.cyan(text.slice(0, 1)) + c.green(text.slice(1)),
|
|
91
|
+
TemplateMiddle: (text) => c.cyan(text.slice(0, 1)) + c.green(text.slice(1, text.length - 2)) + c.cyan(text.slice(-2)),
|
|
92
|
+
IdentifierCallable: c.blue,
|
|
93
|
+
PrivateIdentifierCallable: (text) => `#${c.blue(text.slice(1))}`,
|
|
94
|
+
Invalid: (text) => c.white(c.bgRed(c.bold(text)))
|
|
95
|
+
};
|
|
96
|
+
function highlightCode(source) {
|
|
97
|
+
return highlight(source, { colors });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/util/test-error-formatting.ts
|
|
102
|
+
const FRAME_POINTER = "❯";
|
|
103
|
+
const CODE_FRAME_INDENT_SPACES = 4;
|
|
104
|
+
const MAX_CODE_HIGHLIGHT_LENGTH = 1e5;
|
|
105
|
+
function getYellowString(str) {
|
|
106
|
+
return c.yellow(str);
|
|
107
|
+
}
|
|
108
|
+
function toPlaintextStackFrameString(frame) {
|
|
109
|
+
return ` at ${frame.method} ${frame.file}:${frame.line}:${frame.column}`;
|
|
110
|
+
}
|
|
111
|
+
function toVitestLikeStackFrameString(frame) {
|
|
112
|
+
return c.cyan(` ${c.dim(FRAME_POINTER)} ${frame.method} ${frame.file}:${c.dim(`${frame.line}:${frame.column}`)}`);
|
|
113
|
+
}
|
|
114
|
+
async function getSourceCodeFrameString(sourceMap, frame) {
|
|
115
|
+
let source;
|
|
116
|
+
const fileIndex = sourceMap?.sources.indexOf(frame.file) ?? -1;
|
|
117
|
+
if (fileIndex < 0 || !sourceMap?.sourcesContent) source = await readFile(frame.file, "utf-8");
|
|
118
|
+
else source = sourceMap.sourcesContent[fileIndex];
|
|
119
|
+
if (!source) return;
|
|
120
|
+
return generateCodeFrame(source.length < MAX_CODE_HIGHLIGHT_LENGTH ? highlightCode(source) : source, CODE_FRAME_INDENT_SPACES, frame);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Vitest doesn't expose generateCodeFrame as a util, so we have
|
|
124
|
+
* recreated it here with minimal changes.
|
|
125
|
+
*
|
|
126
|
+
* @see https://github.com/vitest-dev/vitest/blob/v3.2.4/packages/vitest/src/node/printError.ts#L424
|
|
127
|
+
*
|
|
128
|
+
* Vitest is released under the MIT license, included in this project's root.
|
|
129
|
+
* Copyright (c) 2021-Present Vitest Team
|
|
130
|
+
*/
|
|
131
|
+
const lineSplitRE = /\r?\n/;
|
|
132
|
+
function generateCodeFrame(source, indent = 0, loc, range = 2) {
|
|
133
|
+
const start = typeof loc === "object" ? positionToOffset(source, loc.line, loc.column) : loc;
|
|
134
|
+
const end = start;
|
|
135
|
+
const lines = source.split(lineSplitRE);
|
|
136
|
+
const nl = /\r\n/.test(source) ? 2 : 1;
|
|
137
|
+
let count = 0;
|
|
138
|
+
let res = [];
|
|
139
|
+
const columns = process.stdout?.columns || 80;
|
|
140
|
+
for (let i = 0; i < lines.length; i++) {
|
|
141
|
+
count += lines[i].length + nl;
|
|
142
|
+
if (count >= start) {
|
|
143
|
+
for (let j = i - range; j <= i + range || end > count; j++) {
|
|
144
|
+
if (j < 0 || j >= lines.length) continue;
|
|
145
|
+
const lineLength = lines[j].length;
|
|
146
|
+
if (stripVTControlCharacters(lines[j]).length > 200) return "";
|
|
147
|
+
res.push(lineNo(j + 1) + truncateString(lines[j].replace(/\t/g, " "), columns - 5 - indent));
|
|
148
|
+
if (j === i) {
|
|
149
|
+
const pad = start - (count - lineLength) + (nl - 1);
|
|
150
|
+
const length = Math.max(1, end > count ? lineLength - pad : end - start);
|
|
151
|
+
res.push(lineNo() + " ".repeat(pad) + c.red("^".repeat(length)));
|
|
152
|
+
} else if (j > i) {
|
|
153
|
+
if (end > count) {
|
|
154
|
+
const length = Math.max(1, Math.min(end - count, lineLength));
|
|
155
|
+
res.push(lineNo() + c.red("^".repeat(length)));
|
|
156
|
+
}
|
|
157
|
+
count += lineLength + 1;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (indent) res = res.map((line) => " ".repeat(indent) + line);
|
|
164
|
+
return res.join("\n");
|
|
165
|
+
}
|
|
166
|
+
function positionToOffset(source, lineNumber, columnNumber) {
|
|
167
|
+
const lines = source.split(lineSplitRE);
|
|
168
|
+
const nl = /\r\n/.test(source) ? 2 : 1;
|
|
169
|
+
let start = 0;
|
|
170
|
+
if (lineNumber > lines.length) return source.length;
|
|
171
|
+
for (let i = 0; i < lineNumber - 1; i++) start += lines[i].length + nl;
|
|
172
|
+
return start + columnNumber;
|
|
173
|
+
}
|
|
174
|
+
function lineNo(no = "") {
|
|
175
|
+
return c.gray(`${String(no).padStart(3, " ")}| `);
|
|
176
|
+
}
|
|
177
|
+
function truncateString(text, maxLength) {
|
|
178
|
+
const plainText = stripVTControlCharacters(text);
|
|
179
|
+
if (plainText.length <= maxLength) return text;
|
|
180
|
+
return `${plainText.slice(0, maxLength - 1)}…`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region src/wasm-executor/source-maps.ts
|
|
185
|
+
function parseSourceMap(sourceMap) {
|
|
186
|
+
const sourceMapObj = JSON.parse(sourceMap);
|
|
187
|
+
delete sourceMapObj.sourceRoot;
|
|
188
|
+
return sourceMapObj;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Extract structured call stack from V8 using Error.prepareStackTrace
|
|
192
|
+
*
|
|
193
|
+
* V8 provides a special API to access structured stack traces with line:column info.
|
|
194
|
+
* This gives us WAT text positions which can be mapped to AS source via source maps.
|
|
195
|
+
*
|
|
196
|
+
* @param capturedError - Error object to extract stack from
|
|
197
|
+
* @returns Array of V8 CallSite objects
|
|
198
|
+
*/
|
|
199
|
+
function extractCallStack(capturedError) {
|
|
200
|
+
let stackTrace = [];
|
|
201
|
+
const originalPrepareStackTrace = Error.prepareStackTrace;
|
|
202
|
+
Error.prepareStackTrace = (_err, structuredStackTrace) => {
|
|
203
|
+
stackTrace = structuredStackTrace;
|
|
204
|
+
return "";
|
|
205
|
+
};
|
|
206
|
+
capturedError.stack;
|
|
207
|
+
Error.prepareStackTrace = originalPrepareStackTrace;
|
|
208
|
+
return stackTrace;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Create WebAssembly call site with source mapping
|
|
212
|
+
*
|
|
213
|
+
* Takes a V8 CallSite and maps it to AS source location if possible.
|
|
214
|
+
*
|
|
215
|
+
* @param callSite - V8 CallSite object from Error.prepareStackTrace
|
|
216
|
+
* @param sourceMapJson - Source map consumer initialized with WASM source map
|
|
217
|
+
* @returns Mapped call site or null if not a WASM call site
|
|
218
|
+
*/
|
|
219
|
+
function createWebAssemblyCallSite(callSite, sourceMapConsumer, loggingPrefix, allowJS) {
|
|
220
|
+
const fileName = callSite.getFileName();
|
|
221
|
+
const watLine = callSite.getLineNumber();
|
|
222
|
+
const watColumn = callSite.getColumnNumber();
|
|
223
|
+
const functionName = callSite.getFunctionName() ?? "function[unknown]";
|
|
224
|
+
const debugString = `function: "${functionName}" | file: ${fileName}:${watLine}:${watColumn}`;
|
|
225
|
+
if (!fileName) {
|
|
226
|
+
debug(`${loggingPrefix} - Skipping source-mapping of invalid frame (no file): ${debugString}`);
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
if (!fileName.startsWith("wasm://")) if (allowJS) {
|
|
230
|
+
if (!watLine || !watColumn) {
|
|
231
|
+
debug(`${loggingPrefix} - Failed to pass through invalid JS stack location: ${debugString}`);
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
debug(`${loggingPrefix} - Passing through JS stack location: ${debugString}`);
|
|
235
|
+
return {
|
|
236
|
+
functionName,
|
|
237
|
+
location: {
|
|
238
|
+
filePath: fileName,
|
|
239
|
+
line: watLine,
|
|
240
|
+
column: watColumn
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
} else {
|
|
244
|
+
debug(`${loggingPrefix} - Skipping source-mapping of non-WASM stack location: ${debugString}`);
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
if (watLine && watColumn) {
|
|
248
|
+
const original = sourceMapConsumer.originalPositionFor({
|
|
249
|
+
line: watLine,
|
|
250
|
+
column: watColumn
|
|
251
|
+
});
|
|
252
|
+
if (!original.source || original.line === null || original.column === null) {
|
|
253
|
+
debug(`${loggingPrefix} - Failed to source-map stack location: ${debugString}`);
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
debug(`${loggingPrefix} - Source-mapped stack location: ${debugString} → ${original.source}:${original.line}:${original.column}`);
|
|
257
|
+
return {
|
|
258
|
+
functionName,
|
|
259
|
+
location: {
|
|
260
|
+
filePath: original.source,
|
|
261
|
+
line: original.line,
|
|
262
|
+
column: original.column
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
debug(`${loggingPrefix} - Cannot source-map stack-location: ${debugString}`);
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
//#endregion
|
|
271
|
+
//#region src/wasm-executor/wasm-names.ts
|
|
272
|
+
/**
|
|
273
|
+
* Extracts the short name from a WASM function table name identifier.
|
|
274
|
+
*/
|
|
275
|
+
function getShortFunctionName(fullName) {
|
|
276
|
+
if (!fullName) return "";
|
|
277
|
+
let decoded;
|
|
278
|
+
try {
|
|
279
|
+
decoded = decodeURIComponent(fullName);
|
|
280
|
+
decoded = decoded.replace("\\2c", ",");
|
|
281
|
+
} catch {
|
|
282
|
+
decoded = fullName;
|
|
283
|
+
}
|
|
284
|
+
let angleBracketDepth = 0;
|
|
285
|
+
let parenDepth = 0;
|
|
286
|
+
let lastSlashOutsideBrackets = -1;
|
|
287
|
+
for (let i = 0; i < decoded.length; i++) {
|
|
288
|
+
const char = decoded[i];
|
|
289
|
+
if (char === "<") angleBracketDepth++;
|
|
290
|
+
else if (char === ">" && decoded[i - 1] !== "=") angleBracketDepth--;
|
|
291
|
+
else if (char === "(") parenDepth++;
|
|
292
|
+
else if (char === ")") parenDepth--;
|
|
293
|
+
else if (char === "/" && angleBracketDepth === 0 && parenDepth === 0) lastSlashOutsideBrackets = i;
|
|
294
|
+
}
|
|
295
|
+
const functionPart = lastSlashOutsideBrackets >= 0 ? decoded.substring(lastSlashOutsideBrackets + 1) : decoded;
|
|
296
|
+
const anonymousMatch = functionPart.match(/^.+~(anonymous\|\d+)$/);
|
|
297
|
+
if (anonymousMatch) return anonymousMatch[1];
|
|
298
|
+
return shortenTypePart(functionPart);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Finds the index of the closing '>' that matches the opening '<' at openIndex.
|
|
302
|
+
*/
|
|
303
|
+
function findMatchingCloseBracket(str, openIndex) {
|
|
304
|
+
let angleBracketDepth = 1;
|
|
305
|
+
for (let i = openIndex + 1; i < str.length; i++) {
|
|
306
|
+
const char = str[i];
|
|
307
|
+
if (char === "<") angleBracketDepth++;
|
|
308
|
+
else if (char === ">" && str[i - 1] !== "=") {
|
|
309
|
+
angleBracketDepth--;
|
|
310
|
+
if (angleBracketDepth === 0) return i;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return str.length - 1;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Finds the index of the closing ')' that matches the opening '(' at openIndex.
|
|
317
|
+
*/
|
|
318
|
+
function findMatchingCloseParen(str, openIndex) {
|
|
319
|
+
let parenDepth = 1;
|
|
320
|
+
let angleBracketDepth = 0;
|
|
321
|
+
for (let i = openIndex + 1; i < str.length; i++) {
|
|
322
|
+
const char = str[i];
|
|
323
|
+
if (char === "(") parenDepth++;
|
|
324
|
+
else if (char === ")") {
|
|
325
|
+
parenDepth--;
|
|
326
|
+
if (parenDepth === 0) return i;
|
|
327
|
+
} else if (char === "<") angleBracketDepth++;
|
|
328
|
+
else if (char === ">" && str[i - 1] !== "=") angleBracketDepth--;
|
|
329
|
+
}
|
|
330
|
+
return str.length - 1;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Splits a string by commas at the top level (not inside <> or ()).
|
|
334
|
+
*/
|
|
335
|
+
function splitByTopLevelComma(str) {
|
|
336
|
+
const parts = [];
|
|
337
|
+
let current = "";
|
|
338
|
+
let angleBracketDepth = 0;
|
|
339
|
+
let parenDepth = 0;
|
|
340
|
+
for (let i = 0; i < str.length; i++) {
|
|
341
|
+
const char = str[i];
|
|
342
|
+
if (char === "<") angleBracketDepth++;
|
|
343
|
+
else if (char === ">" && str[i - 1] !== "=") angleBracketDepth--;
|
|
344
|
+
else if (char === "(") parenDepth++;
|
|
345
|
+
else if (char === ")") parenDepth--;
|
|
346
|
+
else if (char === "," && angleBracketDepth === 0 && parenDepth === 0) {
|
|
347
|
+
parts.push(current);
|
|
348
|
+
current = "";
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
current += char;
|
|
352
|
+
}
|
|
353
|
+
parts.push(current);
|
|
354
|
+
return parts;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Processes the content inside generic brackets or function args.
|
|
358
|
+
*/
|
|
359
|
+
function shortenGenericContent(content) {
|
|
360
|
+
return splitByTopLevelComma(content).map((part) => shortenTypePart(part.trim())).join(",");
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Shortens a function type like (args)=>returnType.
|
|
364
|
+
*/
|
|
365
|
+
function shortenFunctionType(part) {
|
|
366
|
+
const closeParenIndex = findMatchingCloseParen(part, 0);
|
|
367
|
+
const argsContent = part.substring(1, closeParenIndex);
|
|
368
|
+
const afterParen = part.substring(closeParenIndex + 1);
|
|
369
|
+
const shortenedArgs = argsContent ? shortenGenericContent(argsContent) : "";
|
|
370
|
+
let returnPart = afterParen;
|
|
371
|
+
if (afterParen.startsWith("=>") && afterParen.length > 2) returnPart = "=>" + shortenTypePart(afterParen.substring(2));
|
|
372
|
+
return "(" + shortenedArgs + ")" + returnPart;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Shortens a type/function part, processing paths and generics recursively.
|
|
376
|
+
*/
|
|
377
|
+
function shortenTypePart(part) {
|
|
378
|
+
if (part.startsWith("(")) return shortenFunctionType(part);
|
|
379
|
+
const openBracket = part.indexOf("<");
|
|
380
|
+
if (openBracket === -1) {
|
|
381
|
+
if (!part.includes("/")) return part;
|
|
382
|
+
return part.substring(part.lastIndexOf("/") + 1);
|
|
383
|
+
}
|
|
384
|
+
const namePart = part.substring(0, openBracket);
|
|
385
|
+
const closeBracket = findMatchingCloseBracket(part, openBracket);
|
|
386
|
+
const genericContent = part.substring(openBracket + 1, closeBracket);
|
|
387
|
+
const name = namePart.includes("/") ? namePart.substring(namePart.lastIndexOf("/") + 1) : namePart;
|
|
388
|
+
const shortenedContent = shortenGenericContent(genericContent);
|
|
389
|
+
return name + "<" + shortenedContent + ">";
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
//#endregion
|
|
393
|
+
//#region src/wasm-executor/wasm-errors.ts
|
|
394
|
+
/**
|
|
395
|
+
* Error Enhancement and Source Mapping
|
|
396
|
+
*
|
|
397
|
+
* This module handles mapping WASM errors to AssemblyScript source locations
|
|
398
|
+
* using source maps. It enhances error messages and stack traces with accurate
|
|
399
|
+
* file:line:column information for better developer experience.
|
|
400
|
+
*/
|
|
401
|
+
const POOL_INTERNAL_PATHS_SET = new Set(POOL_INTERNAL_PATHS);
|
|
402
|
+
function passthroughCallSite(callSite) {
|
|
403
|
+
const fileName = callSite.getFileName();
|
|
404
|
+
const watLine = callSite.getLineNumber();
|
|
405
|
+
const watColumn = callSite.getColumnNumber();
|
|
406
|
+
return {
|
|
407
|
+
method: callSite.getFunctionName() || "wasm-function[unknown]",
|
|
408
|
+
file: fileName ?? "unknown-file",
|
|
409
|
+
line: watLine || -1,
|
|
410
|
+
column: watColumn || -1
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
async function sourceMapRawCallStack(rawCallStack, sourceMap, loggingPrefix, allowJS) {
|
|
414
|
+
const mappedStack = [];
|
|
415
|
+
if (!rawCallStack || rawCallStack.length === 0) return mappedStack;
|
|
416
|
+
if (sourceMap) {
|
|
417
|
+
const sourceMapConsumer = await new SourceMapConsumer(sourceMap);
|
|
418
|
+
rawCallStack.forEach((callSite) => {
|
|
419
|
+
const mappedCallSite = createWebAssemblyCallSite(callSite, sourceMapConsumer, loggingPrefix, allowJS);
|
|
420
|
+
if (mappedCallSite) mappedStack.push(mappedCallSite);
|
|
421
|
+
});
|
|
422
|
+
sourceMapConsumer.destroy();
|
|
423
|
+
}
|
|
424
|
+
return mappedStack;
|
|
425
|
+
}
|
|
426
|
+
function parseMappedStack(mappedStack) {
|
|
427
|
+
return mappedStack.filter((frame) => !POOL_INTERNAL_PATHS_SET.has(frame.location.filePath)).map((frame) => ({
|
|
428
|
+
method: getShortFunctionName(frame.functionName),
|
|
429
|
+
file: frame.location.filePath,
|
|
430
|
+
line: frame.location.line,
|
|
431
|
+
column: frame.location.filePath.startsWith("file") ? frame.location.column : frame.location.column + 1
|
|
432
|
+
}));
|
|
433
|
+
}
|
|
434
|
+
async function processWASMErrorStack(rawCallStack, sourceMap, loggingPrefix, allowJS) {
|
|
435
|
+
const sourceMappedStack = await sourceMapRawCallStack(rawCallStack, sourceMap, loggingPrefix, allowJS);
|
|
436
|
+
debug(`${loggingPrefix} - Mapped ${rawCallStack.length} call sites to ${sourceMappedStack.length} source locations`);
|
|
437
|
+
const parsedStack = parseMappedStack(sourceMappedStack);
|
|
438
|
+
if (parsedStack.length === 0) rawCallStack.forEach((callSite) => {
|
|
439
|
+
parsedStack.push(passthroughCallSite(callSite));
|
|
440
|
+
});
|
|
441
|
+
return parsedStack;
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Enhance reportable test error on the provided test result with source mapped stack locations
|
|
445
|
+
* and a formatted diff based on the error type
|
|
446
|
+
*/
|
|
447
|
+
async function enhanceTestError(testError, task, sourceMap, logPrefix, allowJS, projectRoot, applyStackToTestErrorCause, rawCallStack, diffOptions) {
|
|
448
|
+
let expectedVsActualDiffString;
|
|
449
|
+
const isAssertionFailure = testError.name === TEST_ERROR_NAMES.AssertionError;
|
|
450
|
+
const valuesProvided = testError.expected !== void 0 && testError.actual !== void 0;
|
|
451
|
+
if (isAssertionFailure && valuesProvided) expectedVsActualDiffString = diff(testError.expected, testError.actual, diffOptions) ?? "";
|
|
452
|
+
if (!rawCallStack || rawCallStack.length === 0) {
|
|
453
|
+
testError.diff = expectedVsActualDiffString;
|
|
454
|
+
testError.stack = `${task.name} - ${testError.message}`;
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
const testErrorToUpdate = applyStackToTestErrorCause && testError.cause ? testError.cause : testError;
|
|
458
|
+
const parsedStack = await processWASMErrorStack(rawCallStack, sourceMap, logPrefix, allowJS);
|
|
459
|
+
let primaryStackFrameString;
|
|
460
|
+
let highlightedSourceCodeFrameString;
|
|
461
|
+
if (parsedStack.length > 0) {
|
|
462
|
+
parsedStack.forEach((frame) => {
|
|
463
|
+
if (frame.file.startsWith("file://")) {
|
|
464
|
+
frame.file = toForwardSlash(relative(projectRoot, fileURLToPath(frame.file)));
|
|
465
|
+
testErrorToUpdate.stack += toPlaintextStackFrameString(frame) + "\n";
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
const primaryStackFrame = parsedStack[0];
|
|
469
|
+
testErrorToUpdate.stacks = parsedStack.slice(1);
|
|
470
|
+
testErrorToUpdate.stack = parsedStack.map(toPlaintextStackFrameString).join("\n");
|
|
471
|
+
try {
|
|
472
|
+
highlightedSourceCodeFrameString = await getSourceCodeFrameString(sourceMap, primaryStackFrame);
|
|
473
|
+
} catch (err) {
|
|
474
|
+
debug(`${logPrefix} - Error reading source for primary stack frame file "${primaryStackFrame.file}":`, err);
|
|
475
|
+
}
|
|
476
|
+
primaryStackFrameString = toVitestLikeStackFrameString(primaryStackFrame);
|
|
477
|
+
debug(`${logPrefix} - Enhanced ${testError.name} error with parsed source stack`);
|
|
478
|
+
} else testErrorToUpdate.stack = `${task.name} - ${testError.message}`;
|
|
479
|
+
testErrorToUpdate.diff = [
|
|
480
|
+
expectedVsActualDiffString,
|
|
481
|
+
expectedVsActualDiffString ? "\n\n" : "",
|
|
482
|
+
primaryStackFrameString ?? "",
|
|
483
|
+
highlightedSourceCodeFrameString ? "\n" : "",
|
|
484
|
+
highlightedSourceCodeFrameString ?? ""
|
|
485
|
+
].join("");
|
|
486
|
+
debug(`[${logPrefix} - Enhanced error with diffs`);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
//#endregion
|
|
490
|
+
//#region src/util/pool-errors.ts
|
|
491
|
+
function abortWASMExecutionOnSuccess() {
|
|
492
|
+
return {
|
|
493
|
+
["__as_pool_error__"]: true,
|
|
494
|
+
name: POOL_ERROR_NAMES.WASMExecutionAbortSuccess,
|
|
495
|
+
testError: {},
|
|
496
|
+
originalErrorMayContainJS: false,
|
|
497
|
+
originalErrorRawStack: [],
|
|
498
|
+
applyStackToTestErrorCause: false
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
function abortWASMExecution(testError, errorForStack) {
|
|
502
|
+
return {
|
|
503
|
+
["__as_pool_error__"]: true,
|
|
504
|
+
name: POOL_ERROR_NAMES.WASMExecutionAbortError,
|
|
505
|
+
testError,
|
|
506
|
+
originalErrorMayContainJS: false,
|
|
507
|
+
originalErrorRawStack: errorForStack ? extractCallStack(errorForStack) : [],
|
|
508
|
+
applyStackToTestErrorCause: false
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
function wrapPoolError(name, originalError, originalErrorMayContainJS = false) {
|
|
512
|
+
let originalErrorName;
|
|
513
|
+
let originalErrorMessage;
|
|
514
|
+
let originalErrorRawStack;
|
|
515
|
+
if (originalError && originalError instanceof Error) {
|
|
516
|
+
originalErrorName = originalError.name;
|
|
517
|
+
originalErrorMessage = originalError.message;
|
|
518
|
+
originalErrorRawStack = extractCallStack(originalError);
|
|
519
|
+
} else if (originalError) {
|
|
520
|
+
originalErrorMessage = String(originalError);
|
|
521
|
+
originalErrorRawStack = [];
|
|
522
|
+
} else {
|
|
523
|
+
originalErrorMessage = "Unknown Error";
|
|
524
|
+
originalErrorRawStack = [];
|
|
525
|
+
}
|
|
526
|
+
const testError = {
|
|
527
|
+
name,
|
|
528
|
+
message: `${originalErrorName ? `${originalErrorName}: ` : ""}${originalErrorMessage}`
|
|
529
|
+
};
|
|
530
|
+
return {
|
|
531
|
+
["__as_pool_error__"]: true,
|
|
532
|
+
name,
|
|
533
|
+
message: "Wrapped error",
|
|
534
|
+
originalErrorRawStack,
|
|
535
|
+
originalErrorMayContainJS,
|
|
536
|
+
testError,
|
|
537
|
+
applyStackToTestErrorCause: false
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function createPoolError(name, message, originalError, originalErrorMayContainJS = true) {
|
|
541
|
+
if (originalError && originalError["__as_pool_error__"]) return originalError;
|
|
542
|
+
let originalErrorRawStack = [];
|
|
543
|
+
let applyStackToTestErrorCause = false;
|
|
544
|
+
const testError = {
|
|
545
|
+
name,
|
|
546
|
+
message
|
|
547
|
+
};
|
|
548
|
+
if (originalError && originalError instanceof Error) {
|
|
549
|
+
testError.cause = {
|
|
550
|
+
name: originalError.name,
|
|
551
|
+
message: `${originalError.message}`
|
|
552
|
+
};
|
|
553
|
+
originalErrorRawStack = extractCallStack(originalError);
|
|
554
|
+
applyStackToTestErrorCause = true;
|
|
555
|
+
} else if (originalError) testError.cause = {
|
|
556
|
+
name: POOL_ERROR_NAMES.PoolError,
|
|
557
|
+
message: String(originalError)
|
|
558
|
+
};
|
|
559
|
+
return {
|
|
560
|
+
["__as_pool_error__"]: true,
|
|
561
|
+
name,
|
|
562
|
+
message,
|
|
563
|
+
originalErrorRawStack,
|
|
564
|
+
originalErrorMayContainJS,
|
|
565
|
+
testError,
|
|
566
|
+
applyStackToTestErrorCause
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
function createTestTimeoutError(test) {
|
|
570
|
+
const message = `Test timed out after ${test.timeout}ms`;
|
|
571
|
+
return {
|
|
572
|
+
name: POOL_ERROR_NAMES.WASMExecutionTimeoutError,
|
|
573
|
+
message,
|
|
574
|
+
stack: `${test.id}_${message}`,
|
|
575
|
+
diff: getYellowString(` Test Timeout Exceeded (${test.timeout}ms)`)
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
function createTestExpectedToFailError(test) {
|
|
579
|
+
const message = `Test is expected to fail, but all assertion(s) passed`;
|
|
580
|
+
return {
|
|
581
|
+
name: TEST_ERROR_NAMES.AssertionError,
|
|
582
|
+
message,
|
|
583
|
+
stack: `${test.id}_${message}`,
|
|
584
|
+
diff: getYellowString(` Expected to fail, but all assertion(s) passed`)
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
function isAbortErrorString(item) {
|
|
588
|
+
return item === POOL_ERROR_NAMES.PoolRunAbortedError || item === "AbortError";
|
|
589
|
+
}
|
|
590
|
+
function isAbortError(error) {
|
|
591
|
+
return isAbortErrorString(error) || isAbortErrorString(error?.name) || error?.message === "Terminating worker thread";
|
|
592
|
+
}
|
|
593
|
+
function getExpectedMessageOrAny(expectedMsgStr) {
|
|
594
|
+
return expectedMsgStr ? `"${expectedMsgStr}"` : "<any>";
|
|
595
|
+
}
|
|
596
|
+
async function buildEnhancedFileError(error, task, sourceMap, logPrefix, projectRoot, unexpectedContext, diffOptions) {
|
|
597
|
+
let testError;
|
|
598
|
+
let stack;
|
|
599
|
+
let applyStackToTestErrorCause;
|
|
600
|
+
let allowStackJS;
|
|
601
|
+
if (error && error["__as_pool_error__"]) {
|
|
602
|
+
const wrapper = error;
|
|
603
|
+
testError = wrapper.testError;
|
|
604
|
+
stack = wrapper.originalErrorRawStack;
|
|
605
|
+
applyStackToTestErrorCause = wrapper.applyStackToTestErrorCause;
|
|
606
|
+
allowStackJS = wrapper.originalErrorMayContainJS;
|
|
607
|
+
} else if (error instanceof Error) {
|
|
608
|
+
testError = {
|
|
609
|
+
name: POOL_ERROR_NAMES.PoolError,
|
|
610
|
+
message: `${error.name}: ${error.message}`
|
|
611
|
+
};
|
|
612
|
+
stack = extractCallStack(error);
|
|
613
|
+
allowStackJS = true;
|
|
614
|
+
applyStackToTestErrorCause = false;
|
|
615
|
+
} else {
|
|
616
|
+
testError = {
|
|
617
|
+
name: POOL_ERROR_NAMES.PoolError,
|
|
618
|
+
message: `Unexpected error (${unexpectedContext}): ${String(error)}`
|
|
619
|
+
};
|
|
620
|
+
stack = extractCallStack(/* @__PURE__ */ new Error());
|
|
621
|
+
allowStackJS = true;
|
|
622
|
+
applyStackToTestErrorCause = false;
|
|
623
|
+
}
|
|
624
|
+
await enhanceTestError(testError, task, sourceMap, logPrefix, allowStackJS, projectRoot, applyStackToTestErrorCause, stack, diffOptions);
|
|
625
|
+
return testError;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
//#endregion
|
|
629
|
+
export { abortWASMExecution, abortWASMExecutionOnSuccess, buildEnhancedFileError, createPoolError, createTestExpectedToFailError, createTestTimeoutError, debug, debugOverride, enhanceTestError, extractCallStack, getExpectedMessageOrAny, getShortFunctionName, isAbortError, parseSourceMap, setGlobalDebugMode, toForwardSlash, wrapPoolError };
|
|
630
|
+
//# sourceMappingURL=pool-errors-Bn6YaguR.mjs.map
|