@jsenv/core 27.3.4 → 27.4.0
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/README.md +16 -4
- package/dist/js/event_source_client.js +45 -24
- package/dist/js/html_supervisor_installer.js +368 -139
- package/dist/main.js +515 -334
- package/package.json +5 -6
- package/src/build/build.js +4 -2
- package/src/helpers/event_source/event_source.js +38 -17
- package/src/omega/errors.js +41 -9
- package/src/omega/kitchen.js +35 -19
- package/src/omega/omega_server.js +54 -1
- package/src/omega/server/file_service.js +30 -3
- package/src/plugins/autoreload/dev_sse/client/event_source_client.js +8 -8
- package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +160 -171
- package/src/plugins/autoreload/jsenv_plugin_autoreload.js +0 -4
- package/src/plugins/html_supervisor/client/error_in_document.js +268 -121
- package/src/plugins/html_supervisor/client/html_supervisor_installer.js +47 -5
- package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +37 -12
- package/src/plugins/plugins.js +0 -2
- package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +3 -1
- package/src/test/logs_file_execution.js +60 -27
- package/src/test/logs_file_execution.test.mjs +41 -0
|
@@ -1,73 +1,269 @@
|
|
|
1
|
-
|
|
2
|
-
const title = "An error occured"
|
|
3
|
-
let theme =
|
|
4
|
-
error && error.cause && error.cause.code === "PARSE_ERROR"
|
|
5
|
-
? "light"
|
|
6
|
-
: "dark"
|
|
7
|
-
let message = errorToHTML(error)
|
|
8
|
-
const css = `
|
|
9
|
-
.jsenv-console {
|
|
10
|
-
background: rgba(0, 0, 0, 0.95);
|
|
11
|
-
position: absolute;
|
|
12
|
-
top: 0;
|
|
13
|
-
left: 0;
|
|
14
|
-
width: 100%;
|
|
15
|
-
height: 100%;
|
|
16
|
-
display: flex;
|
|
17
|
-
flex-direction: column;
|
|
18
|
-
align-items: center;
|
|
19
|
-
z-index: 1000;
|
|
20
|
-
box-sizing: border-box;
|
|
21
|
-
padding: 1em;
|
|
22
|
-
}
|
|
1
|
+
const JSENV_ERROR_OVERLAY_TAGNAME = "jsenv-error-overlay"
|
|
23
2
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
3
|
+
export const displayErrorInDocument = (
|
|
4
|
+
error,
|
|
5
|
+
{ rootDirectoryUrl, url, line, column },
|
|
6
|
+
) => {
|
|
7
|
+
document.querySelectorAll(JSENV_ERROR_OVERLAY_TAGNAME).forEach((node) => {
|
|
8
|
+
node.parentNode.removeChild(node)
|
|
9
|
+
})
|
|
10
|
+
const { theme, title, message, stack } = errorToHTML(error, {
|
|
11
|
+
url,
|
|
12
|
+
line,
|
|
13
|
+
column,
|
|
14
|
+
})
|
|
15
|
+
const jsenvErrorOverlay = new JsenvErrorOverlay({
|
|
16
|
+
theme,
|
|
17
|
+
title,
|
|
18
|
+
stack: stack
|
|
19
|
+
? `${replaceLinks(message, { rootDirectoryUrl })}\n${replaceLinks(stack, {
|
|
20
|
+
rootDirectoryUrl,
|
|
21
|
+
})}`
|
|
22
|
+
: replaceLinks(message, { rootDirectoryUrl }),
|
|
23
|
+
})
|
|
24
|
+
document.body.appendChild(jsenvErrorOverlay)
|
|
25
|
+
}
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
class JsenvErrorOverlay extends HTMLElement {
|
|
28
|
+
constructor({ title, stack, theme = "dark" }) {
|
|
29
|
+
super()
|
|
30
|
+
this.root = this.attachShadow({ mode: "open" })
|
|
31
|
+
this.root.innerHTML = overlayHtml
|
|
32
|
+
this.root.querySelector(".overlay").setAttribute("data-theme", theme)
|
|
33
|
+
this.root.querySelector(".title").innerHTML = title
|
|
34
|
+
this.root.querySelector(".stack").innerHTML = stack
|
|
35
|
+
this.root.querySelector(".backdrop").onclick = () => {
|
|
36
|
+
if (!this.parentNode) {
|
|
37
|
+
// not in document anymore
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
this.root.querySelector(".backdrop").onclick = null
|
|
41
|
+
this.parentNode.removeChild(this)
|
|
32
42
|
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
33
45
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
/* avoid scrollbar to hide the text behind it */
|
|
38
|
-
padding: 20px;
|
|
39
|
-
}
|
|
46
|
+
if (customElements && !customElements.get(JSENV_ERROR_OVERLAY_TAGNAME)) {
|
|
47
|
+
customElements.define(JSENV_ERROR_OVERLAY_TAGNAME, JsenvErrorOverlay)
|
|
48
|
+
}
|
|
40
49
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
const overlayHtml = `
|
|
51
|
+
<style>
|
|
52
|
+
:host {
|
|
53
|
+
position: fixed;
|
|
54
|
+
z-index: 99999;
|
|
55
|
+
top: 0;
|
|
56
|
+
left: 0;
|
|
57
|
+
width: 100%;
|
|
58
|
+
height: 100%;
|
|
59
|
+
overflow-y: scroll;
|
|
60
|
+
margin: 0;
|
|
61
|
+
background: rgba(0, 0, 0, 0.66);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.backdrop {
|
|
65
|
+
position: absolute;
|
|
66
|
+
left: 0;
|
|
67
|
+
right: 0;
|
|
68
|
+
top: 0;
|
|
69
|
+
bottom: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.overlay {
|
|
73
|
+
position: relative;
|
|
74
|
+
background: rgba(0, 0, 0, 0.95);
|
|
75
|
+
width: 800px;
|
|
76
|
+
margin: 30px auto;
|
|
77
|
+
padding: 25px 40px;
|
|
78
|
+
padding-top: 0;
|
|
79
|
+
overflow: hidden; /* for h1 margins */
|
|
80
|
+
border-radius: 4px 8px;
|
|
81
|
+
box-shadow: 0 20px 40px rgb(0 0 0 / 30%), 0 15px 12px rgb(0 0 0 / 20%);
|
|
82
|
+
box-sizing: border-box;
|
|
83
|
+
font-family: monospace;
|
|
84
|
+
direction: ltr;
|
|
85
|
+
}
|
|
46
86
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
87
|
+
h1 {
|
|
88
|
+
color: red;
|
|
89
|
+
text-align: center;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
pre {
|
|
93
|
+
overflow: auto;
|
|
94
|
+
max-width: 100%;
|
|
95
|
+
/* padding is nice + prevents scrollbar from hiding the text behind it */
|
|
96
|
+
/* does not work nicely on firefox though https://bugzilla.mozilla.org/show_bug.cgi?id=748518 */
|
|
97
|
+
padding: 20px;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.tip {
|
|
101
|
+
border-top: 1px solid #999;
|
|
102
|
+
padding-top: 12px;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
[data-theme="dark"] {
|
|
106
|
+
color: #999;
|
|
107
|
+
}
|
|
108
|
+
[data-theme="dark"] pre {
|
|
109
|
+
background: #111;
|
|
110
|
+
border: 1px solid #333;
|
|
111
|
+
color: #eee;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
[data-theme="light"] {
|
|
115
|
+
color: #EEEEEE;
|
|
116
|
+
}
|
|
117
|
+
[data-theme="light"] pre {
|
|
118
|
+
background: #1E1E1E;
|
|
119
|
+
border: 1px solid white;
|
|
120
|
+
color: #EEEEEE;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
pre a {
|
|
124
|
+
color: inherit;
|
|
125
|
+
}
|
|
126
|
+
</style>
|
|
127
|
+
<div class="backdrop"></div>
|
|
128
|
+
<div class="overlay">
|
|
129
|
+
<h1 class="title"></h1>
|
|
130
|
+
<pre class="stack"></pre>
|
|
131
|
+
<div class="tip">Click outside to close.</div>
|
|
132
|
+
</div>
|
|
133
|
+
`
|
|
134
|
+
|
|
135
|
+
const parseErrorInfo = (error) => {
|
|
136
|
+
if (error === undefined) {
|
|
137
|
+
return {
|
|
138
|
+
message: "undefined",
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (error === null) {
|
|
142
|
+
return {
|
|
143
|
+
message: "null",
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (typeof error === "string") {
|
|
147
|
+
return {
|
|
148
|
+
message: error,
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (error instanceof Error) {
|
|
152
|
+
if (error.name === "SyntaxError") {
|
|
153
|
+
return {
|
|
154
|
+
message: error.message,
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (error.cause && error.cause.code === "PARSE_ERROR") {
|
|
158
|
+
if (error.messageHTML) {
|
|
159
|
+
return {
|
|
160
|
+
message: error.messageHTML,
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
message: error.message,
|
|
165
|
+
}
|
|
51
166
|
}
|
|
167
|
+
// stackTrace formatted by V8
|
|
168
|
+
if (Error.captureStackTrace) {
|
|
169
|
+
return {
|
|
170
|
+
message: error.message,
|
|
171
|
+
stack: getErrorStackWithoutErrorMessage(error),
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
message: error.message,
|
|
176
|
+
stack: error.stack ? ` ${error.stack}` : null,
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (typeof error === "object") {
|
|
180
|
+
return error
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
message: JSON.stringify(error),
|
|
184
|
+
}
|
|
185
|
+
}
|
|
52
186
|
|
|
53
|
-
|
|
54
|
-
|
|
187
|
+
const getErrorStackWithoutErrorMessage = (error) => {
|
|
188
|
+
let stack = error.stack
|
|
189
|
+
const messageInStack = `${error.name}: ${error.message}`
|
|
190
|
+
if (stack.startsWith(messageInStack)) {
|
|
191
|
+
stack = stack.slice(messageInStack.length)
|
|
192
|
+
}
|
|
193
|
+
const nextLineIndex = stack.indexOf("\n")
|
|
194
|
+
if (nextLineIndex > -1) {
|
|
195
|
+
stack = stack.slice(nextLineIndex + 1)
|
|
196
|
+
}
|
|
197
|
+
return stack
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const errorToHTML = (error, { url, line, column }) => {
|
|
201
|
+
let { message, stack } = parseErrorInfo(error)
|
|
202
|
+
if (url) {
|
|
203
|
+
if (!stack || (error && error.name === "SyntaxError")) {
|
|
204
|
+
stack = ` at ${appendLineAndColumn(url, { line, column })}`
|
|
55
205
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
document.querySelector("#button-close-jsenv-console").onclick = () => {
|
|
67
|
-
removeJsenvConsole()
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
theme:
|
|
209
|
+
error && error.cause && error.cause.code === "PARSE_ERROR"
|
|
210
|
+
? "light"
|
|
211
|
+
: "dark",
|
|
212
|
+
title: "An error occured",
|
|
213
|
+
message,
|
|
214
|
+
stack,
|
|
68
215
|
}
|
|
69
216
|
}
|
|
70
217
|
|
|
218
|
+
const replaceLinks = (string, { rootDirectoryUrl }) => {
|
|
219
|
+
// normalize line breaks
|
|
220
|
+
string = string.replace(/\n/g, "\n")
|
|
221
|
+
string = escapeHtml(string)
|
|
222
|
+
// render links
|
|
223
|
+
string = stringToStringWithLink(string, {
|
|
224
|
+
transform: (url, { line, column }) => {
|
|
225
|
+
const urlObject = new URL(url)
|
|
226
|
+
|
|
227
|
+
const onFileUrl = (fileUrlObject) => {
|
|
228
|
+
const atFsIndex = fileUrlObject.pathname.indexOf("/@fs/")
|
|
229
|
+
let fileUrl
|
|
230
|
+
if (atFsIndex > -1) {
|
|
231
|
+
const afterAtFs = fileUrlObject.pathname.slice(
|
|
232
|
+
atFsIndex + "/@fs/".length,
|
|
233
|
+
)
|
|
234
|
+
fileUrl = new URL(afterAtFs, "file:///").href
|
|
235
|
+
} else {
|
|
236
|
+
fileUrl = fileUrlObject.href
|
|
237
|
+
}
|
|
238
|
+
fileUrl = appendLineAndColumn(fileUrl, {
|
|
239
|
+
line,
|
|
240
|
+
column,
|
|
241
|
+
})
|
|
242
|
+
return link({
|
|
243
|
+
href: `javascript:window.fetch('/__open_in_editor__/${fileUrl}')`,
|
|
244
|
+
text: fileUrl,
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (urlObject.origin === window.origin) {
|
|
249
|
+
const fileUrlObject = new URL(
|
|
250
|
+
`${urlObject.pathname.slice(1)}${urlObject.search}`,
|
|
251
|
+
rootDirectoryUrl,
|
|
252
|
+
)
|
|
253
|
+
return onFileUrl(fileUrlObject)
|
|
254
|
+
}
|
|
255
|
+
if (urlObject.href.startsWith("file:")) {
|
|
256
|
+
return onFileUrl(urlObject)
|
|
257
|
+
}
|
|
258
|
+
return link({
|
|
259
|
+
href: url,
|
|
260
|
+
text: appendLineAndColumn(url, { line, column }),
|
|
261
|
+
})
|
|
262
|
+
},
|
|
263
|
+
})
|
|
264
|
+
return string
|
|
265
|
+
}
|
|
266
|
+
|
|
71
267
|
const escapeHtml = (string) => {
|
|
72
268
|
return string
|
|
73
269
|
.replace(/&/g, "&")
|
|
@@ -77,36 +273,14 @@ const escapeHtml = (string) => {
|
|
|
77
273
|
.replace(/'/g, "'")
|
|
78
274
|
}
|
|
79
275
|
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (error && error instanceof Error) {
|
|
84
|
-
if (error.cause && error.cause.code === "PARSE_ERROR") {
|
|
85
|
-
html = error.messageHTML || escapeHtml(error.message)
|
|
86
|
-
}
|
|
87
|
-
// stackTrace formatted by V8
|
|
88
|
-
else if (Error.captureStackTrace) {
|
|
89
|
-
html = escapeHtml(error.stack)
|
|
90
|
-
} else {
|
|
91
|
-
// other stack trace such as firefox do not contain error.message
|
|
92
|
-
html = escapeHtml(`${error.message}
|
|
93
|
-
${error.stack}`)
|
|
94
|
-
}
|
|
95
|
-
} else if (typeof error === "string") {
|
|
96
|
-
html = error
|
|
97
|
-
} else if (error === undefined) {
|
|
98
|
-
html = "undefined"
|
|
99
|
-
} else {
|
|
100
|
-
html = JSON.stringify(error)
|
|
276
|
+
const appendLineAndColumn = (url, { line, column }) => {
|
|
277
|
+
if (line !== undefined && column !== undefined) {
|
|
278
|
+
return `${url}:${line}:${column}`
|
|
101
279
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return { href: url, text: url }
|
|
107
|
-
},
|
|
108
|
-
})
|
|
109
|
-
return htmlWithLinks
|
|
280
|
+
if (line !== undefined) {
|
|
281
|
+
return `${url}:${line}`
|
|
282
|
+
}
|
|
283
|
+
return url
|
|
110
284
|
}
|
|
111
285
|
|
|
112
286
|
// `Error: yo
|
|
@@ -144,28 +318,23 @@ const stringToStringWithLink = (
|
|
|
144
318
|
const lineAndColumnString = lineAndColumMatch[0]
|
|
145
319
|
const lineNumber = lineAndColumMatch[1]
|
|
146
320
|
const columnNumber = lineAndColumMatch[2]
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
321
|
+
linkHTML = transform(match.slice(0, -lineAndColumnString.length), {
|
|
322
|
+
line: lineNumber,
|
|
323
|
+
column: columnNumber,
|
|
324
|
+
})
|
|
150
325
|
} else {
|
|
151
326
|
const linePattern = /:([0-9]+)$/
|
|
152
327
|
const lineMatch = match.match(linePattern)
|
|
153
328
|
if (lineMatch) {
|
|
154
329
|
const lineString = lineMatch[0]
|
|
155
330
|
const lineNumber = lineMatch[1]
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
linkHTML = link({
|
|
159
|
-
href,
|
|
160
|
-
text: `${text}:${lineNumber}`,
|
|
331
|
+
linkHTML = transform(match.slice(0, -lineString.length), {
|
|
332
|
+
line: lineNumber,
|
|
161
333
|
})
|
|
162
334
|
} else {
|
|
163
|
-
|
|
164
|
-
const { href, text } = transform(url)
|
|
165
|
-
linkHTML = link({ href, text })
|
|
335
|
+
linkHTML = transform(match, {})
|
|
166
336
|
}
|
|
167
337
|
}
|
|
168
|
-
|
|
169
338
|
if (endsWithSeparationChar) {
|
|
170
339
|
return `${linkHTML}${lastChar}`
|
|
171
340
|
}
|
|
@@ -174,25 +343,3 @@ const stringToStringWithLink = (
|
|
|
174
343
|
}
|
|
175
344
|
|
|
176
345
|
const link = ({ href, text = href }) => `<a href="${href}">${text}</a>`
|
|
177
|
-
|
|
178
|
-
const appendHMTLInside = (html, parentNode) => {
|
|
179
|
-
const temoraryParent = document.createElement("div")
|
|
180
|
-
temoraryParent.innerHTML = html
|
|
181
|
-
return transferChildren(temoraryParent, parentNode)
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const transferChildren = (fromNode, toNode) => {
|
|
185
|
-
const childNodes = [].slice.call(fromNode.childNodes, 0)
|
|
186
|
-
let i = 0
|
|
187
|
-
while (i < childNodes.length) {
|
|
188
|
-
toNode.appendChild(childNodes[i])
|
|
189
|
-
i++
|
|
190
|
-
}
|
|
191
|
-
return () => {
|
|
192
|
-
let c = 0
|
|
193
|
-
while (c < childNodes.length) {
|
|
194
|
-
fromNode.appendChild(childNodes[c])
|
|
195
|
-
c++
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
@@ -4,7 +4,11 @@ import { displayErrorNotification } from "./error_in_notification.js"
|
|
|
4
4
|
|
|
5
5
|
const { __html_supervisor__ } = window
|
|
6
6
|
|
|
7
|
-
export const installHtmlSupervisor = ({
|
|
7
|
+
export const installHtmlSupervisor = ({
|
|
8
|
+
logs,
|
|
9
|
+
measurePerf,
|
|
10
|
+
rootDirectoryUrl,
|
|
11
|
+
}) => {
|
|
8
12
|
const errorTransformer = null // could implement error stack remapping if needed
|
|
9
13
|
const scriptExecutionResults = {}
|
|
10
14
|
let collectCalled = false
|
|
@@ -35,14 +39,14 @@ export const installHtmlSupervisor = ({ logs, measurePerf }) => {
|
|
|
35
39
|
{
|
|
36
40
|
currentScript,
|
|
37
41
|
errorExposureInNotification = false,
|
|
38
|
-
errorExposureInDocument =
|
|
42
|
+
errorExposureInDocument = false,
|
|
39
43
|
},
|
|
40
44
|
) => {
|
|
41
45
|
const error = executionResult.error
|
|
42
46
|
if (error && error.code === "NETWORK_FAILURE") {
|
|
43
47
|
if (currentScript) {
|
|
44
|
-
const
|
|
45
|
-
currentScript.dispatchEvent(
|
|
48
|
+
const currentScriptErrorEvent = new Event("error")
|
|
49
|
+
currentScript.dispatchEvent(currentScriptErrorEvent)
|
|
46
50
|
}
|
|
47
51
|
} else if (typeof error === "object") {
|
|
48
52
|
const globalErrorEvent = new Event("error")
|
|
@@ -56,7 +60,7 @@ export const installHtmlSupervisor = ({ logs, measurePerf }) => {
|
|
|
56
60
|
displayErrorNotification(error)
|
|
57
61
|
}
|
|
58
62
|
if (errorExposureInDocument) {
|
|
59
|
-
displayErrorInDocument(error)
|
|
63
|
+
displayErrorInDocument(error, { rootDirectoryUrl })
|
|
60
64
|
}
|
|
61
65
|
executionResult.exceptionSource = unevalException(error)
|
|
62
66
|
delete executionResult.error
|
|
@@ -202,6 +206,44 @@ export const installHtmlSupervisor = ({ logs, measurePerf }) => {
|
|
|
202
206
|
copy.forEach((scriptToExecute) => {
|
|
203
207
|
__html_supervisor__.addScriptToExecute(scriptToExecute)
|
|
204
208
|
})
|
|
209
|
+
|
|
210
|
+
window.addEventListener("error", (errorEvent) => {
|
|
211
|
+
if (!errorEvent.isTrusted) {
|
|
212
|
+
// ignore custom error event (not sent by browser)
|
|
213
|
+
return
|
|
214
|
+
}
|
|
215
|
+
const { error } = errorEvent
|
|
216
|
+
displayErrorInDocument(error, {
|
|
217
|
+
rootDirectoryUrl,
|
|
218
|
+
url: errorEvent.filename,
|
|
219
|
+
line: errorEvent.lineno,
|
|
220
|
+
column: errorEvent.colno,
|
|
221
|
+
})
|
|
222
|
+
})
|
|
223
|
+
if (window.__jsenv_event_source_client__) {
|
|
224
|
+
const onServerErrorEvent = (serverErrorEvent) => {
|
|
225
|
+
const { reason, stack, url, line, column, contentFrame } = JSON.parse(
|
|
226
|
+
serverErrorEvent.data,
|
|
227
|
+
)
|
|
228
|
+
displayErrorInDocument(
|
|
229
|
+
{
|
|
230
|
+
message: reason,
|
|
231
|
+
stack: stack ? `${stack}\n\n${contentFrame}` : contentFrame,
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
rootDirectoryUrl,
|
|
235
|
+
url,
|
|
236
|
+
line,
|
|
237
|
+
column,
|
|
238
|
+
},
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
window.__jsenv_event_source_client__.addEventCallbacks({
|
|
242
|
+
file_not_found: onServerErrorEvent,
|
|
243
|
+
parse_error: onServerErrorEvent,
|
|
244
|
+
unexpected_error: onServerErrorEvent,
|
|
245
|
+
})
|
|
246
|
+
}
|
|
205
247
|
}
|
|
206
248
|
|
|
207
249
|
export const superviseScriptTypeModule = ({ src, isInline }) => {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* - scripts are wrapped to be supervised
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { fileURLToPath } from "node:url"
|
|
7
8
|
import {
|
|
8
9
|
parseHtmlString,
|
|
9
10
|
stringifyHtmlAst,
|
|
@@ -20,6 +21,8 @@ import {
|
|
|
20
21
|
} from "@jsenv/ast"
|
|
21
22
|
import { generateInlineContentUrl } from "@jsenv/urls"
|
|
22
23
|
|
|
24
|
+
import { requireFromJsenv } from "@jsenv/core/src/require_from_jsenv.js"
|
|
25
|
+
|
|
23
26
|
export const jsenvPluginHtmlSupervisor = ({
|
|
24
27
|
logs = false,
|
|
25
28
|
measurePerf = false,
|
|
@@ -40,8 +43,27 @@ export const jsenvPluginHtmlSupervisor = ({
|
|
|
40
43
|
dev: true,
|
|
41
44
|
test: true,
|
|
42
45
|
},
|
|
46
|
+
serve: (request) => {
|
|
47
|
+
if (!request.ressource.startsWith("/__open_in_editor__/")) {
|
|
48
|
+
return null
|
|
49
|
+
}
|
|
50
|
+
const file = request.ressource.slice("/__open_in_editor__/".length)
|
|
51
|
+
if (!file) {
|
|
52
|
+
return {
|
|
53
|
+
status: 400,
|
|
54
|
+
body: 'Missing "file" in url search params',
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const launch = requireFromJsenv("launch-editor")
|
|
58
|
+
launch(fileURLToPath(file), () => {
|
|
59
|
+
// ignore error for now
|
|
60
|
+
})
|
|
61
|
+
return {
|
|
62
|
+
status: 200,
|
|
63
|
+
}
|
|
64
|
+
},
|
|
43
65
|
transformUrlContent: {
|
|
44
|
-
html: ({ url, content },
|
|
66
|
+
html: ({ url, content }, context) => {
|
|
45
67
|
const htmlAst = parseHtmlString(content)
|
|
46
68
|
const scriptsToSupervise = []
|
|
47
69
|
|
|
@@ -59,7 +81,7 @@ export const jsenvPluginHtmlSupervisor = ({
|
|
|
59
81
|
lineEnd,
|
|
60
82
|
columnEnd,
|
|
61
83
|
})
|
|
62
|
-
const [inlineScriptReference] = referenceUtils.foundInline({
|
|
84
|
+
const [inlineScriptReference] = context.referenceUtils.foundInline({
|
|
63
85
|
type: "script_src",
|
|
64
86
|
expectedType: { classic: "js_classic", module: "js_module" }[
|
|
65
87
|
scriptCategory
|
|
@@ -128,11 +150,12 @@ export const jsenvPluginHtmlSupervisor = ({
|
|
|
128
150
|
}
|
|
129
151
|
},
|
|
130
152
|
})
|
|
131
|
-
const [htmlSupervisorInstallerFileReference] =
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
153
|
+
const [htmlSupervisorInstallerFileReference] =
|
|
154
|
+
context.referenceUtils.inject({
|
|
155
|
+
type: "js_import_export",
|
|
156
|
+
expectedType: "js_module",
|
|
157
|
+
specifier: htmlSupervisorInstallerFileUrl,
|
|
158
|
+
})
|
|
136
159
|
injectScriptNodeAsEarlyAsPossible(
|
|
137
160
|
htmlAst,
|
|
138
161
|
createHtmlNode({
|
|
@@ -146,6 +169,7 @@ export const jsenvPluginHtmlSupervisor = ({
|
|
|
146
169
|
{
|
|
147
170
|
logs,
|
|
148
171
|
measurePerf,
|
|
172
|
+
rootDirectoryUrl: context.rootDirectoryUrl,
|
|
149
173
|
},
|
|
150
174
|
null,
|
|
151
175
|
" ",
|
|
@@ -153,11 +177,12 @@ export const jsenvPluginHtmlSupervisor = ({
|
|
|
153
177
|
"injected-by": "jsenv:html_supervisor",
|
|
154
178
|
}),
|
|
155
179
|
)
|
|
156
|
-
const [htmlSupervisorSetupFileReference] =
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
180
|
+
const [htmlSupervisorSetupFileReference] =
|
|
181
|
+
context.referenceUtils.inject({
|
|
182
|
+
type: "script_src",
|
|
183
|
+
expectedType: "js_classic",
|
|
184
|
+
specifier: htmlSupervisorSetupFileUrl,
|
|
185
|
+
})
|
|
161
186
|
injectScriptNodeAsEarlyAsPossible(
|
|
162
187
|
htmlAst,
|
|
163
188
|
createHtmlNode({
|
package/src/plugins/plugins.js
CHANGED
|
@@ -79,7 +79,9 @@ export const jsenvPluginUrlAnalysis = ({
|
|
|
79
79
|
type: "filesystem",
|
|
80
80
|
subtype: "directory_entry",
|
|
81
81
|
specifier: directoryEntryName,
|
|
82
|
-
trace:
|
|
82
|
+
trace: {
|
|
83
|
+
message: `"${directoryRelativeUrl}${directoryEntryName}" entry in directory referenced by ${originalDirectoryReference.trace.message}`,
|
|
84
|
+
},
|
|
83
85
|
})
|
|
84
86
|
})
|
|
85
87
|
},
|