@jsenv/test 3.3.16 → 3.3.18

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.
@@ -1,231 +0,0 @@
1
- /*
2
- * Exception are objects used to wrap a value that is thrown
3
- * Usually they wrap error but the value can be anything as
4
- * throw "toto" can be used in JS
5
- *
6
- * - provide a common API to interact with value that can be thrown
7
- * - enrich usual errors with a bit more information (line, column)
8
- * - normalize error properties
9
- * - exception.stackTrace: only the stack trace as string (no error.name or error.message)
10
- * - error.stack: error.name + error.message + error.stackTrace
11
- *
12
- * It is used mostly internally by jsenv but can also be found
13
- * value returned by "executeTestPlan" public export (for failed executions)
14
- * and value returned by "execute" public export (when execution fails)
15
- *
16
- * This file is responsible to wrap error hapenning in Node.js runtime
17
- * The browser part can be found in "supervisor.js"
18
- */
19
-
20
- // https://github.com/marvinhagemeister/errorstacks/tree/main
21
- // https://cdn.jsdelivr.net/npm/errorstacks@latest/dist/esm/index.mjs
22
- import { URL_META } from "@jsenv/url-meta";
23
- import { parseStackTrace } from "errorstacks";
24
-
25
- const isDev = process.execArgv.includes("--conditions=development");
26
- const jsenvCoreDirectoryUrl = new URL("../../../../../", import.meta.url);
27
-
28
- export const createException = (reason, { rootDirectoryUrl } = {}) => {
29
- const exception = {
30
- isException: true,
31
- isError: false,
32
- name: "",
33
- message: "",
34
- stack: "",
35
- stackTrace: "",
36
- stackFrames: undefined,
37
- site: null,
38
- };
39
-
40
- if (reason === undefined) {
41
- exception.message = "undefined";
42
- return exception;
43
- }
44
- if (reason === null) {
45
- exception.message = "null";
46
- return exception;
47
- }
48
- if (typeof reason === "string") {
49
- exception.message = reason;
50
- return exception;
51
- }
52
- if (typeof reason !== "object") {
53
- exception.message = JSON.stringify(reason);
54
- return exception;
55
- }
56
- if (reason.stackFrames === undefined && "stack" in reason) {
57
- let stackFrames;
58
-
59
- const { prepareStackTrace } = Error;
60
- Error.prepareStackTrace = (e, callSites) => {
61
- Error.prepareStackTrace = prepareStackTrace;
62
-
63
- stackFrames = [];
64
- for (const callSite of callSites) {
65
- const stackFrame = {
66
- raw: ` at ${String(callSite)}`,
67
- url: callSite.getFileName() || callSite.getScriptNameOrSourceURL(),
68
- line: callSite.getLineNumber(),
69
- column: callSite.getColumnNumber(),
70
- functionName: callSite.getFunctionName(),
71
- isNative: callSite.isNative(),
72
- isEval: callSite.isEval(),
73
- isConstructor: callSite.isConstructor(),
74
- isAsync: callSite.isAsync(),
75
- evalSite: null,
76
- };
77
- if (stackFrame.isEval) {
78
- const evalOrigin = stackFrame.getEvalOrigin();
79
- if (evalOrigin) {
80
- stackFrame.evalSite = getPropertiesFromEvalOrigin(evalOrigin);
81
- }
82
- }
83
- stackFrames.push(stackFrame);
84
- }
85
- return "";
86
- };
87
- exception.stack = reason.stack;
88
- if (stackFrames === undefined) {
89
- // Error.prepareStackTrace not trigerred
90
- // - reason is not an error
91
- // - reason.stack already get
92
- Error.prepareStackTrace = prepareStackTrace;
93
-
94
- const calls = parseStackTrace(reason.stack);
95
- stackFrames = [];
96
- for (const call of calls) {
97
- if (call.fileName === "") {
98
- continue;
99
- }
100
- stackFrames.push({
101
- raw: call.raw,
102
- functionName: call.name,
103
- url: call.fileName,
104
- line: call.line,
105
- column: call.column,
106
- native: call.type === "native",
107
- });
108
- }
109
- }
110
-
111
- const stackFramesNonNative = [];
112
- for (const stackFrame of stackFrames) {
113
- if (!stackFrame.url) {
114
- continue;
115
- }
116
- if (stackFrame.url.startsWith("node:")) {
117
- stackFrame.native = "node";
118
- continue;
119
- }
120
- if (stackFrame.url.startsWith("file:")) {
121
- if (rootDirectoryUrl && stackFrame.url.startsWith(rootDirectoryUrl)) {
122
- stackFramesNonNative.push(stackFrame);
123
- continue;
124
- }
125
-
126
- if (isDev) {
127
- // while developing jsenv itself we want to exclude any
128
- // - src/*
129
- // - packages/**/src/
130
- // for the users of jsenv it's easier, we want to exclude
131
- // - **/node_modules/@jsenv/**
132
- if (
133
- URL_META.matches(stackFrame.url, {
134
- [`${jsenvCoreDirectoryUrl}src/`]: true,
135
- [`${jsenvCoreDirectoryUrl}packages/**/src/`]: true,
136
- })
137
- ) {
138
- stackFrame.native = "jsenv";
139
- continue;
140
- }
141
- } else if (
142
- URL_META.matches(stackFrame.url, {
143
- "file:///**/node_modules/@jsenv/core/": true,
144
- })
145
- ) {
146
- stackFrame.native = "jsenv";
147
- continue;
148
- }
149
- }
150
- stackFramesNonNative.push(stackFrame);
151
- }
152
- if (stackFramesNonNative.length) {
153
- stackFrames = stackFramesNonNative;
154
- }
155
-
156
- reason.stackFrames = stackFrames;
157
-
158
- let stackTrace = "";
159
- for (const stackFrame of stackFrames) {
160
- if (stackTrace) stackTrace += "\n";
161
- stackTrace += stackFrame.raw;
162
- }
163
- reason.stackTrace = stackTrace;
164
- let stack = "";
165
- const name = getErrorName(reason);
166
- const message = reason.message || "";
167
- stack += `${name}: ${message}`;
168
- if (stackTrace) {
169
- stack += `\n${stackTrace}`;
170
- }
171
- reason.stack = stack;
172
-
173
- const [firstCallFrame] = stackFrames;
174
- if (firstCallFrame && (!reason.site || !reason.site.isInline)) {
175
- reason.site = firstCallFrame.url
176
- ? {
177
- url: firstCallFrame.url,
178
- line: firstCallFrame.line,
179
- column: firstCallFrame.column,
180
- }
181
- : firstCallFrame.evalSite;
182
- }
183
- }
184
- // getOwnPropertyNames to catch non enumerable properties on reason
185
- // (happens mostly when reason is instanceof Error)
186
- // like .stack, .message
187
- // some properties are even on the prototype like .name
188
- for (const ownPropertyName of Object.getOwnPropertyNames(reason)) {
189
- exception[ownPropertyName] = reason[ownPropertyName];
190
- }
191
- const isError = reason instanceof Error;
192
- exception.isError = isError;
193
- if (isError) {
194
- // getOwnPropertyNames is not enough to copy .name and .message
195
- // on error instances
196
- exception.name = getErrorName(reason);
197
- exception.message = reason.message;
198
- }
199
- return exception;
200
- };
201
-
202
- const getErrorName = (value) => {
203
- const { constructor } = value;
204
- if (constructor) {
205
- if (constructor.name !== "Object") {
206
- return constructor.name;
207
- }
208
- }
209
- return value.name || "Error";
210
- };
211
-
212
- const getPropertiesFromEvalOrigin = (origin) => {
213
- // Most eval() calls are in this format
214
- const topLevelEvalMatch = /^eval at [^(]+ \(.+:\d+:\d+\)$/.exec(origin);
215
- if (topLevelEvalMatch) {
216
- const source = topLevelEvalMatch[2];
217
- const line = Number(topLevelEvalMatch[3]);
218
- const column = topLevelEvalMatch[4] - 1;
219
- return {
220
- url: source,
221
- line,
222
- column,
223
- };
224
- }
225
- // Parse nested eval() calls using recursion
226
- const nestedEvalMatch = /^eval at [^(]+ \(.+\)$/.exec(origin);
227
- if (nestedEvalMatch) {
228
- return getPropertiesFromEvalOrigin(nestedEvalMatch[2]);
229
- }
230
- return null;
231
- };