@jsenv/core 27.5.0 → 27.5.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/dist/js/html_supervisor_installer.js +372 -289
- package/dist/main.js +63 -18
- package/package.json +2 -1
- package/src/dev/start_dev_server.js +5 -3
- package/src/plugins/html_supervisor/client/error_formatter.js +305 -0
- package/src/plugins/html_supervisor/client/error_overlay.js +60 -268
- package/src/plugins/html_supervisor/client/html_supervisor_installer.js +23 -32
- package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +53 -15
- package/src/test/execute_test_plan.js +1 -2
|
@@ -1,33 +1,64 @@
|
|
|
1
|
+
import { formatError } from "./error_formatter.js"
|
|
2
|
+
|
|
1
3
|
const JSENV_ERROR_OVERLAY_TAGNAME = "jsenv-error-overlay"
|
|
2
4
|
|
|
5
|
+
let previousErrorInfo = null
|
|
6
|
+
|
|
3
7
|
export const displayErrorInDocument = (
|
|
4
8
|
error,
|
|
5
9
|
{
|
|
6
10
|
rootDirectoryUrl,
|
|
11
|
+
errorBaseUrl,
|
|
7
12
|
openInEditor,
|
|
8
13
|
url,
|
|
9
14
|
line,
|
|
10
15
|
column,
|
|
16
|
+
codeFrame,
|
|
11
17
|
reportedBy,
|
|
12
18
|
requestedRessource,
|
|
13
19
|
},
|
|
14
20
|
) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
const nowMs = Date.now()
|
|
22
|
+
// ensure error dispatched on window by browser is displayed first
|
|
23
|
+
// then the server error replaces it (because it contains more information)
|
|
24
|
+
if (previousErrorInfo) {
|
|
25
|
+
const previousErrorReportedBy = previousErrorInfo.reportedBy
|
|
26
|
+
const msEllapsedSincePreviousError = nowMs - previousErrorInfo.ms
|
|
27
|
+
if (
|
|
28
|
+
previousErrorReportedBy === "server" &&
|
|
29
|
+
reportedBy === "browser" &&
|
|
30
|
+
msEllapsedSincePreviousError < 50
|
|
31
|
+
) {
|
|
32
|
+
return () => {}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
previousErrorInfo = {
|
|
36
|
+
ms: nowMs,
|
|
37
|
+
reportedBy,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const { theme, title, text, codeFramePromise, tip } = formatError(error, {
|
|
41
|
+
rootDirectoryUrl,
|
|
42
|
+
errorBaseUrl,
|
|
43
|
+
openInEditor,
|
|
19
44
|
url,
|
|
20
45
|
line,
|
|
21
46
|
column,
|
|
47
|
+
codeFrame,
|
|
22
48
|
reportedBy,
|
|
23
49
|
requestedRessource,
|
|
24
50
|
})
|
|
51
|
+
|
|
25
52
|
let jsenvErrorOverlay = new JsenvErrorOverlay({
|
|
26
53
|
theme,
|
|
27
54
|
title,
|
|
28
|
-
text
|
|
55
|
+
text,
|
|
56
|
+
codeFramePromise,
|
|
29
57
|
tip,
|
|
30
58
|
})
|
|
59
|
+
document.querySelectorAll(JSENV_ERROR_OVERLAY_TAGNAME).forEach((node) => {
|
|
60
|
+
node.parentNode.removeChild(node)
|
|
61
|
+
})
|
|
31
62
|
document.body.appendChild(jsenvErrorOverlay)
|
|
32
63
|
const removeErrorOverlay = () => {
|
|
33
64
|
if (jsenvErrorOverlay && jsenvErrorOverlay.parentNode) {
|
|
@@ -45,29 +76,24 @@ export const displayErrorInDocument = (
|
|
|
45
76
|
return removeErrorOverlay
|
|
46
77
|
}
|
|
47
78
|
|
|
48
|
-
const createErrorText = ({
|
|
49
|
-
rootDirectoryUrl,
|
|
50
|
-
openInEditor,
|
|
51
|
-
message,
|
|
52
|
-
stack,
|
|
53
|
-
}) => {
|
|
54
|
-
if (message && stack) {
|
|
55
|
-
return `${replaceLinks(message, {
|
|
56
|
-
rootDirectoryUrl,
|
|
57
|
-
openInEditor,
|
|
58
|
-
})}\n${replaceLinks(stack, { rootDirectoryUrl, openInEditor })}`
|
|
59
|
-
}
|
|
60
|
-
if (stack) {
|
|
61
|
-
return replaceLinks(stack, { rootDirectoryUrl, openInEditor })
|
|
62
|
-
}
|
|
63
|
-
return replaceLinks(message, { rootDirectoryUrl, openInEditor })
|
|
64
|
-
}
|
|
65
|
-
|
|
66
79
|
class JsenvErrorOverlay extends HTMLElement {
|
|
67
|
-
constructor({ theme, title, text, tip }) {
|
|
80
|
+
constructor({ theme, title, text, codeFramePromise, tip }) {
|
|
68
81
|
super()
|
|
69
82
|
this.root = this.attachShadow({ mode: "open" })
|
|
70
|
-
this.root.innerHTML =
|
|
83
|
+
this.root.innerHTML = `
|
|
84
|
+
<style>
|
|
85
|
+
${overlayCSS}
|
|
86
|
+
</style>
|
|
87
|
+
<div class="backdrop"></div>
|
|
88
|
+
<div class="overlay" data-theme=${theme}>
|
|
89
|
+
<h1 class="title">
|
|
90
|
+
${title}
|
|
91
|
+
</h1>
|
|
92
|
+
<pre class="text">${text}</pre>
|
|
93
|
+
<div class="tip">
|
|
94
|
+
${tip}
|
|
95
|
+
</div>
|
|
96
|
+
</div>`
|
|
71
97
|
this.root.querySelector(".backdrop").onclick = () => {
|
|
72
98
|
if (!this.parentNode) {
|
|
73
99
|
// not in document anymore
|
|
@@ -76,10 +102,13 @@ class JsenvErrorOverlay extends HTMLElement {
|
|
|
76
102
|
this.root.querySelector(".backdrop").onclick = null
|
|
77
103
|
this.parentNode.removeChild(this)
|
|
78
104
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
105
|
+
if (codeFramePromise) {
|
|
106
|
+
codeFramePromise.then((codeFrame) => {
|
|
107
|
+
if (this.parentNode) {
|
|
108
|
+
this.root.querySelector(".text").innerHTML += `\n\n${codeFrame}`
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
}
|
|
83
112
|
}
|
|
84
113
|
}
|
|
85
114
|
|
|
@@ -87,8 +116,7 @@ if (customElements && !customElements.get(JSENV_ERROR_OVERLAY_TAGNAME)) {
|
|
|
87
116
|
customElements.define(JSENV_ERROR_OVERLAY_TAGNAME, JsenvErrorOverlay)
|
|
88
117
|
}
|
|
89
118
|
|
|
90
|
-
const
|
|
91
|
-
<style>
|
|
119
|
+
const overlayCSS = `
|
|
92
120
|
:host {
|
|
93
121
|
position: fixed;
|
|
94
122
|
z-index: 99999;
|
|
@@ -162,240 +190,4 @@ pre {
|
|
|
162
190
|
|
|
163
191
|
pre a {
|
|
164
192
|
color: inherit;
|
|
165
|
-
}
|
|
166
|
-
</style>
|
|
167
|
-
<div class="backdrop"></div>
|
|
168
|
-
<div class="overlay">
|
|
169
|
-
<h1 class="title"></h1>
|
|
170
|
-
<pre class="text"></pre>
|
|
171
|
-
<div class="tip"></div>
|
|
172
|
-
</div>
|
|
173
|
-
`
|
|
174
|
-
|
|
175
|
-
const parseErrorInfo = (error) => {
|
|
176
|
-
if (error === undefined) {
|
|
177
|
-
return {
|
|
178
|
-
message: "undefined",
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
if (error === null) {
|
|
182
|
-
return {
|
|
183
|
-
message: "null",
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
if (typeof error === "string") {
|
|
187
|
-
return {
|
|
188
|
-
message: error,
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
if (error instanceof Error) {
|
|
192
|
-
if (error.name === "SyntaxError") {
|
|
193
|
-
return {
|
|
194
|
-
message: error.message,
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
if (error.cause && error.cause.code === "PARSE_ERROR") {
|
|
198
|
-
if (error.messageHTML) {
|
|
199
|
-
return {
|
|
200
|
-
message: error.messageHTML,
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
return {
|
|
204
|
-
message: error.message,
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
// stackTrace formatted by V8
|
|
208
|
-
if (Error.captureStackTrace) {
|
|
209
|
-
return {
|
|
210
|
-
message: error.message,
|
|
211
|
-
stack: getErrorStackWithoutErrorMessage(error),
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
return {
|
|
215
|
-
message: error.message,
|
|
216
|
-
stack: error.stack ? ` ${error.stack}` : null,
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
if (typeof error === "object") {
|
|
220
|
-
return error
|
|
221
|
-
}
|
|
222
|
-
return {
|
|
223
|
-
message: JSON.stringify(error),
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const getErrorStackWithoutErrorMessage = (error) => {
|
|
228
|
-
let stack = error.stack
|
|
229
|
-
const messageInStack = `${error.name}: ${error.message}`
|
|
230
|
-
if (stack.startsWith(messageInStack)) {
|
|
231
|
-
stack = stack.slice(messageInStack.length)
|
|
232
|
-
}
|
|
233
|
-
const nextLineIndex = stack.indexOf("\n")
|
|
234
|
-
if (nextLineIndex > -1) {
|
|
235
|
-
stack = stack.slice(nextLineIndex + 1)
|
|
236
|
-
}
|
|
237
|
-
return stack
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const errorToHTML = (
|
|
241
|
-
error,
|
|
242
|
-
{ url, line, column, reportedBy, requestedRessource },
|
|
243
|
-
) => {
|
|
244
|
-
let { message, stack } = parseErrorInfo(error)
|
|
245
|
-
if (url) {
|
|
246
|
-
if (!stack || (error && error.name === "SyntaxError")) {
|
|
247
|
-
stack = ` at ${appendLineAndColumn(url, { line, column })}`
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
let tip = formatTip({ reportedBy, requestedRessource })
|
|
251
|
-
return {
|
|
252
|
-
theme:
|
|
253
|
-
error && error.cause && error.cause.code === "PARSE_ERROR"
|
|
254
|
-
? "light"
|
|
255
|
-
: "dark",
|
|
256
|
-
title: "An error occured",
|
|
257
|
-
message,
|
|
258
|
-
stack,
|
|
259
|
-
tip: `${tip}
|
|
260
|
-
<br />
|
|
261
|
-
Click outside to close.`,
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const formatTip = ({ reportedBy, requestedRessource }) => {
|
|
266
|
-
if (reportedBy === "browser") {
|
|
267
|
-
return `Reported by the browser while executing <code>${window.location.pathname}${window.location.search}</code>.`
|
|
268
|
-
}
|
|
269
|
-
return `Reported by the server while serving <code>${requestedRessource}</code>`
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const replaceLinks = (string, { rootDirectoryUrl, openInEditor }) => {
|
|
273
|
-
// normalize line breaks
|
|
274
|
-
string = string.replace(/\n/g, "\n")
|
|
275
|
-
string = escapeHtml(string)
|
|
276
|
-
// render links
|
|
277
|
-
string = stringToStringWithLink(string, {
|
|
278
|
-
transform: (url, { line, column }) => {
|
|
279
|
-
const urlObject = new URL(url)
|
|
280
|
-
|
|
281
|
-
const onFileUrl = (fileUrlObject) => {
|
|
282
|
-
const atFsIndex = fileUrlObject.pathname.indexOf("/@fs/")
|
|
283
|
-
let fileUrl
|
|
284
|
-
if (atFsIndex > -1) {
|
|
285
|
-
const afterAtFs = fileUrlObject.pathname.slice(
|
|
286
|
-
atFsIndex + "/@fs/".length,
|
|
287
|
-
)
|
|
288
|
-
fileUrl = new URL(afterAtFs, "file:///").href
|
|
289
|
-
} else {
|
|
290
|
-
fileUrl = fileUrlObject.href
|
|
291
|
-
}
|
|
292
|
-
fileUrl = appendLineAndColumn(fileUrl, {
|
|
293
|
-
line,
|
|
294
|
-
column,
|
|
295
|
-
})
|
|
296
|
-
return link({
|
|
297
|
-
href: openInEditor
|
|
298
|
-
? `javascript:window.fetch('/__open_in_editor__/${fileUrl}')`
|
|
299
|
-
: fileUrl,
|
|
300
|
-
text: fileUrl,
|
|
301
|
-
})
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
if (urlObject.origin === window.origin) {
|
|
305
|
-
const fileUrlObject = new URL(
|
|
306
|
-
`${urlObject.pathname.slice(1)}${urlObject.search}`,
|
|
307
|
-
rootDirectoryUrl,
|
|
308
|
-
)
|
|
309
|
-
return onFileUrl(fileUrlObject)
|
|
310
|
-
}
|
|
311
|
-
if (urlObject.href.startsWith("file:")) {
|
|
312
|
-
return onFileUrl(urlObject)
|
|
313
|
-
}
|
|
314
|
-
return link({
|
|
315
|
-
href: url,
|
|
316
|
-
text: appendLineAndColumn(url, { line, column }),
|
|
317
|
-
})
|
|
318
|
-
},
|
|
319
|
-
})
|
|
320
|
-
return string
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
const escapeHtml = (string) => {
|
|
324
|
-
return string
|
|
325
|
-
.replace(/&/g, "&")
|
|
326
|
-
.replace(/</g, "<")
|
|
327
|
-
.replace(/>/g, ">")
|
|
328
|
-
.replace(/"/g, """)
|
|
329
|
-
.replace(/'/g, "'")
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const appendLineAndColumn = (url, { line, column }) => {
|
|
333
|
-
if (line !== undefined && column !== undefined) {
|
|
334
|
-
return `${url}:${line}:${column}`
|
|
335
|
-
}
|
|
336
|
-
if (line !== undefined) {
|
|
337
|
-
return `${url}:${line}`
|
|
338
|
-
}
|
|
339
|
-
return url
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// `Error: yo
|
|
343
|
-
// at Object.execute (http://127.0.0.1:57300/build/src/__test__/file-throw.js:9:13)
|
|
344
|
-
// at doExec (http://127.0.0.1:3000/src/__test__/file-throw.js:452:38)
|
|
345
|
-
// at postOrderExec (http://127.0.0.1:3000/src/__test__/file-throw.js:448:16)
|
|
346
|
-
// at http://127.0.0.1:3000/src/__test__/file-throw.js:399:18`.replace(/(?:https?|ftp|file):\/\/(.*+)$/gm, (...args) => {
|
|
347
|
-
// debugger
|
|
348
|
-
// })
|
|
349
|
-
const stringToStringWithLink = (
|
|
350
|
-
source,
|
|
351
|
-
{
|
|
352
|
-
transform = (url) => {
|
|
353
|
-
return {
|
|
354
|
-
href: url,
|
|
355
|
-
text: url,
|
|
356
|
-
}
|
|
357
|
-
},
|
|
358
|
-
} = {},
|
|
359
|
-
) => {
|
|
360
|
-
return source.replace(/(?:https?|ftp|file):\/\/\S+/gm, (match) => {
|
|
361
|
-
let linkHTML = ""
|
|
362
|
-
|
|
363
|
-
const lastChar = match[match.length - 1]
|
|
364
|
-
|
|
365
|
-
// hotfix because our url regex sucks a bit
|
|
366
|
-
const endsWithSeparationChar = lastChar === ")" || lastChar === ":"
|
|
367
|
-
if (endsWithSeparationChar) {
|
|
368
|
-
match = match.slice(0, -1)
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const lineAndColumnPattern = /:([0-9]+):([0-9]+)$/
|
|
372
|
-
const lineAndColumMatch = match.match(lineAndColumnPattern)
|
|
373
|
-
if (lineAndColumMatch) {
|
|
374
|
-
const lineAndColumnString = lineAndColumMatch[0]
|
|
375
|
-
const lineNumber = lineAndColumMatch[1]
|
|
376
|
-
const columnNumber = lineAndColumMatch[2]
|
|
377
|
-
linkHTML = transform(match.slice(0, -lineAndColumnString.length), {
|
|
378
|
-
line: lineNumber,
|
|
379
|
-
column: columnNumber,
|
|
380
|
-
})
|
|
381
|
-
} else {
|
|
382
|
-
const linePattern = /:([0-9]+)$/
|
|
383
|
-
const lineMatch = match.match(linePattern)
|
|
384
|
-
if (lineMatch) {
|
|
385
|
-
const lineString = lineMatch[0]
|
|
386
|
-
const lineNumber = lineMatch[1]
|
|
387
|
-
linkHTML = transform(match.slice(0, -lineString.length), {
|
|
388
|
-
line: lineNumber,
|
|
389
|
-
})
|
|
390
|
-
} else {
|
|
391
|
-
linkHTML = transform(match, {})
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
if (endsWithSeparationChar) {
|
|
395
|
-
return `${linkHTML}${lastChar}`
|
|
396
|
-
}
|
|
397
|
-
return linkHTML
|
|
398
|
-
})
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const link = ({ href, text = href }) => `<a href="${href}">${text}</a>`
|
|
193
|
+
}`
|
|
@@ -11,6 +11,7 @@ export const installHtmlSupervisor = ({
|
|
|
11
11
|
logs,
|
|
12
12
|
measurePerf,
|
|
13
13
|
errorOverlay,
|
|
14
|
+
errorBaseUrl,
|
|
14
15
|
openInEditor,
|
|
15
16
|
}) => {
|
|
16
17
|
const errorTransformer = null // could implement error stack remapping if needed
|
|
@@ -224,13 +225,14 @@ export const installHtmlSupervisor = ({
|
|
|
224
225
|
// ignore custom error event (not sent by browser)
|
|
225
226
|
return
|
|
226
227
|
}
|
|
227
|
-
const { error } = errorEvent
|
|
228
|
+
const { error, filename, lineno, colno } = errorEvent
|
|
228
229
|
displayErrorInDocument(error, {
|
|
229
230
|
rootDirectoryUrl,
|
|
231
|
+
errorBaseUrl,
|
|
230
232
|
openInEditor,
|
|
231
|
-
url:
|
|
232
|
-
line:
|
|
233
|
-
column:
|
|
233
|
+
url: filename,
|
|
234
|
+
line: lineno,
|
|
235
|
+
column: colno,
|
|
234
236
|
reportedBy: "browser",
|
|
235
237
|
})
|
|
236
238
|
})
|
|
@@ -250,7 +252,6 @@ export const installHtmlSupervisor = ({
|
|
|
250
252
|
}
|
|
251
253
|
return false
|
|
252
254
|
}
|
|
253
|
-
|
|
254
255
|
window.__server_events__.addEventCallbacks({
|
|
255
256
|
error_while_serving_file: (serverErrorEvent) => {
|
|
256
257
|
if (!isExecuting()) {
|
|
@@ -269,33 +270,23 @@ export const installHtmlSupervisor = ({
|
|
|
269
270
|
if (isFaviconAutoRequest) {
|
|
270
271
|
return
|
|
271
272
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
rootDirectoryUrl,
|
|
290
|
-
openInEditor,
|
|
291
|
-
url: traceUrl,
|
|
292
|
-
line: traceLine,
|
|
293
|
-
column: traceColumn,
|
|
294
|
-
reportedBy: "server",
|
|
295
|
-
requestedRessource,
|
|
296
|
-
},
|
|
297
|
-
)
|
|
298
|
-
}, 10)
|
|
273
|
+
displayErrorInDocument(
|
|
274
|
+
{
|
|
275
|
+
message,
|
|
276
|
+
stack,
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
rootDirectoryUrl,
|
|
280
|
+
errorBaseUrl,
|
|
281
|
+
openInEditor,
|
|
282
|
+
url: traceUrl,
|
|
283
|
+
line: traceLine,
|
|
284
|
+
column: traceColumn,
|
|
285
|
+
codeFrame: traceMessage,
|
|
286
|
+
reportedBy: "server",
|
|
287
|
+
requestedRessource,
|
|
288
|
+
},
|
|
289
|
+
)
|
|
299
290
|
},
|
|
300
291
|
})
|
|
301
292
|
}
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
removeHtmlNodeText,
|
|
20
20
|
setHtmlNodeText,
|
|
21
21
|
} from "@jsenv/ast"
|
|
22
|
-
import { generateInlineContentUrl } from "@jsenv/urls"
|
|
22
|
+
import { generateInlineContentUrl, stringifyUrlSite } from "@jsenv/urls"
|
|
23
23
|
|
|
24
24
|
import { requireFromJsenv } from "@jsenv/core/src/require_from_jsenv.js"
|
|
25
25
|
|
|
@@ -28,6 +28,7 @@ export const jsenvPluginHtmlSupervisor = ({
|
|
|
28
28
|
measurePerf = false,
|
|
29
29
|
errorOverlay = true,
|
|
30
30
|
openInEditor = true,
|
|
31
|
+
errorBaseUrl,
|
|
31
32
|
}) => {
|
|
32
33
|
const htmlSupervisorSetupFileUrl = new URL(
|
|
33
34
|
"./client/html_supervisor_setup.js?js_classic",
|
|
@@ -45,24 +46,60 @@ export const jsenvPluginHtmlSupervisor = ({
|
|
|
45
46
|
dev: true,
|
|
46
47
|
test: true,
|
|
47
48
|
},
|
|
48
|
-
serve: (request) => {
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
serve: (request, context) => {
|
|
50
|
+
if (request.ressource.startsWith("/__open_in_editor__/")) {
|
|
51
|
+
const file = request.ressource.slice("/__open_in_editor__/".length)
|
|
52
|
+
if (!file) {
|
|
53
|
+
return {
|
|
54
|
+
status: 400,
|
|
55
|
+
body: "Missing file in url",
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const launch = requireFromJsenv("launch-editor")
|
|
59
|
+
launch(fileURLToPath(file), () => {
|
|
60
|
+
// ignore error for now
|
|
61
|
+
})
|
|
54
62
|
return {
|
|
55
|
-
status:
|
|
56
|
-
|
|
63
|
+
status: 200,
|
|
64
|
+
headers: {
|
|
65
|
+
"cache-control": "no-store",
|
|
66
|
+
},
|
|
57
67
|
}
|
|
58
68
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
69
|
+
if (request.ressource.startsWith("/__get_code_frame__/")) {
|
|
70
|
+
const url = request.ressource.slice("/__get_code_frame__/".length)
|
|
71
|
+
const match = url.match(/:([0-9]+):([0-9]+)$/)
|
|
72
|
+
if (!match) {
|
|
73
|
+
return {
|
|
74
|
+
status: 400,
|
|
75
|
+
body: "Missing line and column in url",
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const file = url.slice(0, match.index)
|
|
79
|
+
const line = parseInt(match[1])
|
|
80
|
+
const column = parseInt(match[2])
|
|
81
|
+
const urlInfo = context.urlGraph.getUrlInfo(file)
|
|
82
|
+
if (!urlInfo) {
|
|
83
|
+
return {
|
|
84
|
+
status: 404,
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const codeFrame = stringifyUrlSite({
|
|
88
|
+
url: file,
|
|
89
|
+
line,
|
|
90
|
+
column,
|
|
91
|
+
content: urlInfo.originalContent,
|
|
92
|
+
})
|
|
93
|
+
return {
|
|
94
|
+
status: 200,
|
|
95
|
+
headers: {
|
|
96
|
+
"content-type": "text/plain",
|
|
97
|
+
"content-length": Buffer.byteLength(codeFrame),
|
|
98
|
+
},
|
|
99
|
+
body: codeFrame,
|
|
100
|
+
}
|
|
65
101
|
}
|
|
102
|
+
return null
|
|
66
103
|
},
|
|
67
104
|
transformUrlContent: {
|
|
68
105
|
html: ({ url, content }, context) => {
|
|
@@ -173,6 +210,7 @@ export const jsenvPluginHtmlSupervisor = ({
|
|
|
173
210
|
installHtmlSupervisor(${JSON.stringify(
|
|
174
211
|
{
|
|
175
212
|
rootDirectoryUrl: context.rootDirectoryUrl,
|
|
213
|
+
errorBaseUrl,
|
|
176
214
|
logs,
|
|
177
215
|
measurePerf,
|
|
178
216
|
errorOverlay,
|
|
@@ -60,8 +60,7 @@ export const executeTestPlan = async ({
|
|
|
60
60
|
cooldownBetweenExecutions = 0,
|
|
61
61
|
gcBetweenExecutions = logMemoryHeapUsage,
|
|
62
62
|
|
|
63
|
-
coverageEnabled = process.argv.includes("--
|
|
64
|
-
process.argv.includes("--coverage"),
|
|
63
|
+
coverageEnabled = process.argv.includes("--coverage"),
|
|
65
64
|
coverageConfig = {
|
|
66
65
|
"./src/": true,
|
|
67
66
|
},
|