@jsenv/core 27.3.4 → 27.5.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.
Files changed (88) hide show
  1. package/dist/js/autoreload.js +359 -0
  2. package/dist/js/execute_using_dynamic_import.js +1 -1
  3. package/dist/js/html_supervisor_installer.js +524 -147
  4. package/dist/js/html_supervisor_setup.js +3 -4
  5. package/dist/js/new_stylesheet.js +26 -58
  6. package/dist/js/server_events_client.js +307 -0
  7. package/dist/main.js +7709 -7324
  8. package/package.json +15 -15
  9. package/{README.md → readme.md} +18 -7
  10. package/src/build/build.js +16 -18
  11. package/src/build/start_build_server.js +24 -28
  12. package/src/dev/start_dev_server.js +34 -96
  13. package/src/execute/execute.js +17 -35
  14. package/src/omega/errors.js +43 -9
  15. package/src/omega/kitchen.js +42 -25
  16. package/src/omega/omega_server.js +96 -74
  17. package/src/omega/server/file_service.js +256 -28
  18. package/src/omega/url_graph.js +33 -20
  19. package/src/plugins/autoreload/client/autoreload.js +201 -0
  20. package/src/plugins/autoreload/{dev_sse/client → client}/autoreload_preference.js +0 -0
  21. package/src/plugins/autoreload/{dev_sse/client → client}/reload.js +29 -10
  22. package/src/plugins/autoreload/{dev_sse/client → client}/url_helpers.js +0 -0
  23. package/src/plugins/autoreload/jsenv_plugin_autoreload.js +4 -8
  24. package/src/plugins/autoreload/{dev_sse/jsenv_plugin_dev_sse_client.js → jsenv_plugin_autoreload_client.js} +8 -8
  25. package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +196 -0
  26. package/src/{dev/plugins → plugins}/explorer/client/explorer.html +0 -0
  27. package/src/{dev/plugins → plugins}/explorer/client/jsenv.png +0 -0
  28. package/src/{dev/plugins → plugins}/explorer/jsenv_plugin_explorer.js +1 -3
  29. package/src/plugins/html_supervisor/client/error_overlay.js +401 -0
  30. package/src/plugins/html_supervisor/client/html_supervisor_installer.js +138 -23
  31. package/src/plugins/html_supervisor/client/html_supervisor_setup.js +3 -4
  32. package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +55 -23
  33. package/src/plugins/inline/jsenv_plugin_html_inline_content.js +97 -117
  34. package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +66 -58
  35. package/src/plugins/plugin_controller.js +102 -67
  36. package/src/plugins/plugins.js +10 -10
  37. package/src/{helpers/event_source/event_source.js → plugins/server_events/client/event_source_connection.js} +125 -33
  38. package/src/plugins/server_events/client/server_events_client.js +17 -0
  39. package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +48 -0
  40. package/src/plugins/server_events/server_events_dispatcher.js +69 -0
  41. package/src/{dev/plugins → plugins}/toolbar/client/animation/toolbar_animation.js +0 -0
  42. package/src/{dev/plugins → plugins}/toolbar/client/eventsource/eventsource.css +0 -0
  43. package/src/{dev/plugins → plugins}/toolbar/client/eventsource/toolbar_eventsource.js +0 -0
  44. package/src/{dev/plugins → plugins}/toolbar/client/execution/execution.css +0 -0
  45. package/src/{dev/plugins → plugins}/toolbar/client/execution/toolbar_execution.js +0 -0
  46. package/src/{dev/plugins → plugins}/toolbar/client/focus/focus.css +0 -0
  47. package/src/{dev/plugins → plugins}/toolbar/client/focus/toolbar_focus.js +0 -0
  48. package/src/{dev/plugins → plugins}/toolbar/client/jsenv_logo.svg +0 -0
  49. package/src/{dev/plugins → plugins}/toolbar/client/notification/toolbar_notification.js +0 -0
  50. package/src/{dev/plugins → plugins}/toolbar/client/responsive/overflow_menu.css +0 -0
  51. package/src/{dev/plugins → plugins}/toolbar/client/responsive/toolbar_responsive.js +0 -0
  52. package/src/{dev/plugins → plugins}/toolbar/client/settings/settings.css +0 -0
  53. package/src/{dev/plugins → plugins}/toolbar/client/settings/toolbar_settings.js +0 -0
  54. package/src/{dev/plugins → plugins}/toolbar/client/theme/jsenv_theme.css +0 -0
  55. package/src/{dev/plugins → plugins}/toolbar/client/theme/light_theme.css +0 -0
  56. package/src/{dev/plugins → plugins}/toolbar/client/theme/toolbar_theme.js +0 -0
  57. package/src/{dev/plugins → plugins}/toolbar/client/toolbar.html +0 -0
  58. package/src/{dev/plugins → plugins}/toolbar/client/toolbar_injector.js +0 -0
  59. package/src/{dev/plugins → plugins}/toolbar/client/toolbar_main.css +0 -0
  60. package/src/{dev/plugins → plugins}/toolbar/client/toolbar_main.js +0 -0
  61. package/src/{dev/plugins → plugins}/toolbar/client/tooltip/tooltip.css +0 -0
  62. package/src/{dev/plugins → plugins}/toolbar/client/tooltip/tooltip.js +0 -0
  63. package/src/{dev/plugins → plugins}/toolbar/client/util/animation.js +0 -0
  64. package/src/{dev/plugins → plugins}/toolbar/client/util/dom.js +0 -0
  65. package/src/{dev/plugins → plugins}/toolbar/client/util/fetch_using_xhr.js +0 -0
  66. package/src/{dev/plugins → plugins}/toolbar/client/util/fetching.js +0 -0
  67. package/src/{dev/plugins → plugins}/toolbar/client/util/iframe_to_parent_href.js +0 -0
  68. package/src/{dev/plugins → plugins}/toolbar/client/util/jsenv_logger.js +0 -0
  69. package/src/{dev/plugins → plugins}/toolbar/client/util/preferences.js +0 -0
  70. package/src/{dev/plugins → plugins}/toolbar/client/util/responsive.js +0 -0
  71. package/src/{dev/plugins → plugins}/toolbar/client/util/util.js +0 -0
  72. package/src/{dev/plugins → plugins}/toolbar/client/variant/variant.js +0 -0
  73. package/src/{dev/plugins → plugins}/toolbar/jsenv_plugin_toolbar.js +0 -0
  74. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +4 -3
  75. package/src/plugins/transpilation/babel/new_stylesheet/client/new_stylesheet.js +25 -55
  76. package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +44 -24
  77. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +6 -1
  78. package/src/plugins/url_analysis/html/html_urls.js +8 -8
  79. package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +3 -1
  80. package/src/test/execute_plan.js +36 -54
  81. package/src/test/execute_test_plan.js +2 -2
  82. package/src/test/logs_file_execution.js +60 -27
  83. package/src/test/logs_file_execution.test.mjs +41 -0
  84. package/dist/js/event_source_client.js +0 -528
  85. package/src/helpers/event_source/sse_service.js +0 -53
  86. package/src/plugins/autoreload/dev_sse/client/event_source_client.js +0 -193
  87. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +0 -203
  88. package/src/plugins/html_supervisor/client/error_in_document.js +0 -198
@@ -10,109 +10,411 @@ const unevalException = value => {
10
10
  });
11
11
  };
12
12
 
13
- const displayErrorInDocument = error => {
14
- const title = "An error occured";
15
- let theme = error && error.cause && error.cause.code === "PARSE_ERROR" ? "light" : "dark";
16
- let message = errorToHTML(error);
17
- const css = `
18
- .jsenv-console {
19
- background: rgba(0, 0, 0, 0.95);
20
- position: absolute;
21
- top: 0;
22
- left: 0;
23
- width: 100%;
24
- height: 100%;
25
- display: flex;
26
- flex-direction: column;
27
- align-items: center;
28
- z-index: 1000;
29
- box-sizing: border-box;
30
- padding: 1em;
31
- }
13
+ const JSENV_ERROR_OVERLAY_TAGNAME = "jsenv-error-overlay";
14
+ const displayErrorInDocument = (error, {
15
+ rootDirectoryUrl,
16
+ openInEditor,
17
+ url,
18
+ line,
19
+ column,
20
+ reportedBy,
21
+ requestedRessource
22
+ }) => {
23
+ document.querySelectorAll(JSENV_ERROR_OVERLAY_TAGNAME).forEach(node => {
24
+ node.parentNode.removeChild(node);
25
+ });
26
+ const {
27
+ theme,
28
+ title,
29
+ message,
30
+ stack,
31
+ tip
32
+ } = errorToHTML(error, {
33
+ url,
34
+ line,
35
+ column,
36
+ reportedBy,
37
+ requestedRessource
38
+ });
39
+ let jsenvErrorOverlay = new JsenvErrorOverlay({
40
+ theme,
41
+ title,
42
+ text: createErrorText({
43
+ rootDirectoryUrl,
44
+ openInEditor,
45
+ message,
46
+ stack
47
+ }),
48
+ tip
49
+ });
50
+ document.body.appendChild(jsenvErrorOverlay);
32
51
 
33
- .jsenv-console h1 {
34
- color: red;
35
- display: flex;
36
- align-items: center;
52
+ const removeErrorOverlay = () => {
53
+ if (jsenvErrorOverlay && jsenvErrorOverlay.parentNode) {
54
+ document.body.removeChild(jsenvErrorOverlay);
55
+ jsenvErrorOverlay = null;
37
56
  }
57
+ };
38
58
 
39
- #button-close-jsenv-console {
40
- margin-left: 10px;
41
- }
59
+ if (window.__reloader__) {
60
+ window.__reloader__.onstatuschange = () => {
61
+ if (window.__reloader__.status === "reloading") {
62
+ removeErrorOverlay();
63
+ }
64
+ };
65
+ }
42
66
 
43
- .jsenv-console pre {
44
- overflow: auto;
45
- max-width: 70em;
46
- /* avoid scrollbar to hide the text behind it */
47
- padding: 20px;
48
- }
67
+ return removeErrorOverlay;
68
+ };
49
69
 
50
- .jsenv-console pre[data-theme="dark"] {
51
- background: #111;
52
- border: 1px solid #333;
53
- color: #eee;
54
- }
70
+ const createErrorText = ({
71
+ rootDirectoryUrl,
72
+ openInEditor,
73
+ message,
74
+ stack
75
+ }) => {
76
+ if (message && stack) {
77
+ return `${replaceLinks(message, {
78
+ rootDirectoryUrl,
79
+ openInEditor
80
+ })}\n${replaceLinks(stack, {
81
+ rootDirectoryUrl,
82
+ openInEditor
83
+ })}`;
84
+ }
85
+
86
+ if (stack) {
87
+ return replaceLinks(stack, {
88
+ rootDirectoryUrl,
89
+ openInEditor
90
+ });
91
+ }
92
+
93
+ return replaceLinks(message, {
94
+ rootDirectoryUrl,
95
+ openInEditor
96
+ });
97
+ };
98
+
99
+ class JsenvErrorOverlay extends HTMLElement {
100
+ constructor({
101
+ theme,
102
+ title,
103
+ text,
104
+ tip
105
+ }) {
106
+ super();
107
+ this.root = this.attachShadow({
108
+ mode: "open"
109
+ });
110
+ this.root.innerHTML = overlayHtml;
111
+
112
+ this.root.querySelector(".backdrop").onclick = () => {
113
+ if (!this.parentNode) {
114
+ // not in document anymore
115
+ return;
116
+ }
117
+
118
+ this.root.querySelector(".backdrop").onclick = null;
119
+ this.parentNode.removeChild(this);
120
+ };
121
+
122
+ this.root.querySelector(".overlay").setAttribute("data-theme", theme);
123
+ this.root.querySelector(".title").innerHTML = title;
124
+ this.root.querySelector(".text").innerHTML = text;
125
+ this.root.querySelector(".tip").innerHTML = tip;
126
+ }
127
+
128
+ }
129
+
130
+ if (customElements && !customElements.get(JSENV_ERROR_OVERLAY_TAGNAME)) {
131
+ customElements.define(JSENV_ERROR_OVERLAY_TAGNAME, JsenvErrorOverlay);
132
+ }
133
+
134
+ const overlayHtml = `
135
+ <style>
136
+ :host {
137
+ position: fixed;
138
+ z-index: 99999;
139
+ top: 0;
140
+ left: 0;
141
+ width: 100%;
142
+ height: 100%;
143
+ overflow-y: scroll;
144
+ margin: 0;
145
+ background: rgba(0, 0, 0, 0.66);
146
+ }
147
+
148
+ .backdrop {
149
+ position: absolute;
150
+ left: 0;
151
+ right: 0;
152
+ top: 0;
153
+ bottom: 0;
154
+ }
155
+
156
+ .overlay {
157
+ position: relative;
158
+ background: rgba(0, 0, 0, 0.95);
159
+ width: 800px;
160
+ margin: 30px auto;
161
+ padding: 25px 40px;
162
+ padding-top: 0;
163
+ overflow: hidden; /* for h1 margins */
164
+ border-radius: 4px 8px;
165
+ box-shadow: 0 20px 40px rgb(0 0 0 / 30%), 0 15px 12px rgb(0 0 0 / 20%);
166
+ box-sizing: border-box;
167
+ font-family: monospace;
168
+ direction: ltr;
169
+ }
170
+
171
+ h1 {
172
+ color: red;
173
+ text-align: center;
174
+ }
175
+
176
+ pre {
177
+ overflow: auto;
178
+ max-width: 100%;
179
+ /* padding is nice + prevents scrollbar from hiding the text behind it */
180
+ /* does not work nicely on firefox though https://bugzilla.mozilla.org/show_bug.cgi?id=748518 */
181
+ padding: 20px;
182
+ }
183
+
184
+ .tip {
185
+ border-top: 1px solid #999;
186
+ padding-top: 12px;
187
+ }
188
+
189
+ [data-theme="dark"] {
190
+ color: #999;
191
+ }
192
+ [data-theme="dark"] pre {
193
+ background: #111;
194
+ border: 1px solid #333;
195
+ color: #eee;
196
+ }
197
+
198
+ [data-theme="light"] {
199
+ color: #EEEEEE;
200
+ }
201
+ [data-theme="light"] pre {
202
+ background: #1E1E1E;
203
+ border: 1px solid white;
204
+ color: #EEEEEE;
205
+ }
206
+
207
+ pre a {
208
+ color: inherit;
209
+ }
210
+ </style>
211
+ <div class="backdrop"></div>
212
+ <div class="overlay">
213
+ <h1 class="title"></h1>
214
+ <pre class="text"></pre>
215
+ <div class="tip"></div>
216
+ </div>
217
+ `;
218
+
219
+ const parseErrorInfo = error => {
220
+ if (error === undefined) {
221
+ return {
222
+ message: "undefined"
223
+ };
224
+ }
225
+
226
+ if (error === null) {
227
+ return {
228
+ message: "null"
229
+ };
230
+ }
231
+
232
+ if (typeof error === "string") {
233
+ return {
234
+ message: error
235
+ };
236
+ }
55
237
 
56
- .jsenv-console pre[data-theme="light"] {
57
- background: #1E1E1E;
58
- border: 1px solid white;
59
- color: #EEEEEE;
238
+ if (error instanceof Error) {
239
+ if (error.name === "SyntaxError") {
240
+ return {
241
+ message: error.message
242
+ };
60
243
  }
61
244
 
62
- .jsenv-console pre a {
63
- color: inherit;
245
+ if (error.cause && error.cause.code === "PARSE_ERROR") {
246
+ if (error.messageHTML) {
247
+ return {
248
+ message: error.messageHTML
249
+ };
250
+ }
251
+
252
+ return {
253
+ message: error.message
254
+ };
255
+ } // stackTrace formatted by V8
256
+
257
+
258
+ if (Error.captureStackTrace) {
259
+ return {
260
+ message: error.message,
261
+ stack: getErrorStackWithoutErrorMessage(error)
262
+ };
64
263
  }
65
- `;
66
- const html = `
67
- <style type="text/css">${css}></style>
68
- <div class="jsenv-console">
69
- <h1>${title} <button id="button-close-jsenv-console">X</button></h1>
70
- <pre data-theme="${theme}">${message}</pre>
71
- </div>
72
- `;
73
- const removeJsenvConsole = appendHMTLInside(html, document.body);
74
-
75
- document.querySelector("#button-close-jsenv-console").onclick = () => {
76
- removeJsenvConsole();
264
+
265
+ return {
266
+ message: error.message,
267
+ stack: error.stack ? ` ${error.stack}` : null
268
+ };
269
+ }
270
+
271
+ if (typeof error === "object") {
272
+ return error;
273
+ }
274
+
275
+ return {
276
+ message: JSON.stringify(error)
77
277
  };
78
278
  };
79
279
 
80
- const escapeHtml = string => {
81
- return string.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
82
- };
280
+ const getErrorStackWithoutErrorMessage = error => {
281
+ let stack = error.stack;
282
+ const messageInStack = `${error.name}: ${error.message}`;
83
283
 
84
- const errorToHTML = error => {
85
- let html;
284
+ if (stack.startsWith(messageInStack)) {
285
+ stack = stack.slice(messageInStack.length);
286
+ }
86
287
 
87
- if (error && error instanceof Error) {
88
- if (error.cause && error.cause.code === "PARSE_ERROR") {
89
- html = error.messageHTML || escapeHtml(error.message);
90
- } // stackTrace formatted by V8
91
- else if (Error.captureStackTrace) {
92
- html = escapeHtml(error.stack);
93
- } else {
94
- // other stack trace such as firefox do not contain error.message
95
- html = escapeHtml(`${error.message}
96
- ${error.stack}`);
288
+ const nextLineIndex = stack.indexOf("\n");
289
+
290
+ if (nextLineIndex > -1) {
291
+ stack = stack.slice(nextLineIndex + 1);
292
+ }
293
+
294
+ return stack;
295
+ };
296
+
297
+ const errorToHTML = (error, {
298
+ url,
299
+ line,
300
+ column,
301
+ reportedBy,
302
+ requestedRessource
303
+ }) => {
304
+ let {
305
+ message,
306
+ stack
307
+ } = parseErrorInfo(error);
308
+
309
+ if (url) {
310
+ if (!stack || error && error.name === "SyntaxError") {
311
+ stack = ` at ${appendLineAndColumn(url, {
312
+ line,
313
+ column
314
+ })}`;
97
315
  }
98
- } else if (typeof error === "string") {
99
- html = error;
100
- } else if (error === undefined) {
101
- html = "undefined";
102
- } else {
103
- html = JSON.stringify(error);
104
316
  }
105
317
 
106
- const htmlWithCorrectLineBreaks = html.replace(/\n/g, "\n");
107
- const htmlWithLinks = stringToStringWithLink(htmlWithCorrectLineBreaks, {
108
- transform: url => {
109
- return {
110
- href: url,
111
- text: url
318
+ let tip = formatTip({
319
+ reportedBy,
320
+ requestedRessource
321
+ });
322
+ return {
323
+ theme: error && error.cause && error.cause.code === "PARSE_ERROR" ? "light" : "dark",
324
+ title: "An error occured",
325
+ message,
326
+ stack,
327
+ tip: `${tip}
328
+ <br />
329
+ Click outside to close.`
330
+ };
331
+ };
332
+
333
+ const formatTip = ({
334
+ reportedBy,
335
+ requestedRessource
336
+ }) => {
337
+ if (reportedBy === "browser") {
338
+ return `Reported by the browser while executing <code>${window.location.pathname}${window.location.search}</code>.`;
339
+ }
340
+
341
+ return `Reported by the server while serving <code>${requestedRessource}</code>`;
342
+ };
343
+
344
+ const replaceLinks = (string, {
345
+ rootDirectoryUrl,
346
+ openInEditor
347
+ }) => {
348
+ // normalize line breaks
349
+ string = string.replace(/\n/g, "\n");
350
+ string = escapeHtml(string); // render links
351
+
352
+ string = stringToStringWithLink(string, {
353
+ transform: (url, {
354
+ line,
355
+ column
356
+ }) => {
357
+ const urlObject = new URL(url);
358
+
359
+ const onFileUrl = fileUrlObject => {
360
+ const atFsIndex = fileUrlObject.pathname.indexOf("/@fs/");
361
+ let fileUrl;
362
+
363
+ if (atFsIndex > -1) {
364
+ const afterAtFs = fileUrlObject.pathname.slice(atFsIndex + "/@fs/".length);
365
+ fileUrl = new URL(afterAtFs, "file:///").href;
366
+ } else {
367
+ fileUrl = fileUrlObject.href;
368
+ }
369
+
370
+ fileUrl = appendLineAndColumn(fileUrl, {
371
+ line,
372
+ column
373
+ });
374
+ return link({
375
+ href: openInEditor ? `javascript:window.fetch('/__open_in_editor__/${fileUrl}')` : fileUrl,
376
+ text: fileUrl
377
+ });
112
378
  };
379
+
380
+ if (urlObject.origin === window.origin) {
381
+ const fileUrlObject = new URL(`${urlObject.pathname.slice(1)}${urlObject.search}`, rootDirectoryUrl);
382
+ return onFileUrl(fileUrlObject);
383
+ }
384
+
385
+ if (urlObject.href.startsWith("file:")) {
386
+ return onFileUrl(urlObject);
387
+ }
388
+
389
+ return link({
390
+ href: url,
391
+ text: appendLineAndColumn(url, {
392
+ line,
393
+ column
394
+ })
395
+ });
113
396
  }
114
397
  });
115
- return htmlWithLinks;
398
+ return string;
399
+ };
400
+
401
+ const escapeHtml = string => {
402
+ return string.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
403
+ };
404
+
405
+ const appendLineAndColumn = (url, {
406
+ line,
407
+ column
408
+ }) => {
409
+ if (line !== undefined && column !== undefined) {
410
+ return `${url}:${line}:${column}`;
411
+ }
412
+
413
+ if (line !== undefined) {
414
+ return `${url}:${line}`;
415
+ }
416
+
417
+ return url;
116
418
  }; // `Error: yo
117
419
  // at Object.execute (http://127.0.0.1:57300/build/src/__test__/file-throw.js:9:13)
118
420
  // at doExec (http://127.0.0.1:3000/src/__test__/file-throw.js:452:38)
@@ -147,14 +449,9 @@ const stringToStringWithLink = (source, {
147
449
  const lineAndColumnString = lineAndColumMatch[0];
148
450
  const lineNumber = lineAndColumMatch[1];
149
451
  const columnNumber = lineAndColumMatch[2];
150
- const url = match.slice(0, -lineAndColumnString.length);
151
- const {
152
- href,
153
- text
154
- } = transform(url);
155
- linkHTML = link({
156
- href,
157
- text: `${text}:${lineNumber}:${columnNumber}`
452
+ linkHTML = transform(match.slice(0, -lineAndColumnString.length), {
453
+ line: lineNumber,
454
+ column: columnNumber
158
455
  });
159
456
  } else {
160
457
  const linePattern = /:([0-9]+)$/;
@@ -163,25 +460,11 @@ const stringToStringWithLink = (source, {
163
460
  if (lineMatch) {
164
461
  const lineString = lineMatch[0];
165
462
  const lineNumber = lineMatch[1];
166
- const url = match.slice(0, -lineString.length);
167
- const {
168
- href,
169
- text
170
- } = transform(url);
171
- linkHTML = link({
172
- href,
173
- text: `${text}:${lineNumber}`
463
+ linkHTML = transform(match.slice(0, -lineString.length), {
464
+ line: lineNumber
174
465
  });
175
466
  } else {
176
- const url = match;
177
- const {
178
- href,
179
- text
180
- } = transform(url);
181
- linkHTML = link({
182
- href,
183
- text
184
- });
467
+ linkHTML = transform(match, {});
185
468
  }
186
469
  }
187
470
 
@@ -198,31 +481,6 @@ const link = ({
198
481
  text = href
199
482
  }) => `<a href="${href}">${text}</a>`;
200
483
 
201
- const appendHMTLInside = (html, parentNode) => {
202
- const temoraryParent = document.createElement("div");
203
- temoraryParent.innerHTML = html;
204
- return transferChildren(temoraryParent, parentNode);
205
- };
206
-
207
- const transferChildren = (fromNode, toNode) => {
208
- const childNodes = [].slice.call(fromNode.childNodes, 0);
209
- let i = 0;
210
-
211
- while (i < childNodes.length) {
212
- toNode.appendChild(childNodes[i]);
213
- i++;
214
- }
215
-
216
- return () => {
217
- let c = 0;
218
-
219
- while (c < childNodes.length) {
220
- fromNode.appendChild(childNodes[c]);
221
- c++;
222
- }
223
- };
224
- };
225
-
226
484
  const {
227
485
  Notification
228
486
  } = window;
@@ -250,9 +508,13 @@ const displayErrorNotification = typeof Notification === "function" ? displayErr
250
508
  const {
251
509
  __html_supervisor__
252
510
  } = window;
511
+ const supervisedScripts = [];
253
512
  const installHtmlSupervisor = ({
513
+ rootDirectoryUrl,
254
514
  logs,
255
- measurePerf
515
+ measurePerf,
516
+ errorOverlay,
517
+ openInEditor
256
518
  }) => {
257
519
 
258
520
  const scriptExecutionResults = {};
@@ -288,15 +550,14 @@ const installHtmlSupervisor = ({
288
550
 
289
551
  const onExecutionError = (executionResult, {
290
552
  currentScript,
291
- errorExposureInNotification = false,
292
- errorExposureInDocument = true
553
+ errorExposureInNotification = false
293
554
  }) => {
294
555
  const error = executionResult.error;
295
556
 
296
557
  if (error && error.code === "NETWORK_FAILURE") {
297
558
  if (currentScript) {
298
- const errorEvent = new Event("error");
299
- currentScript.dispatchEvent(errorEvent);
559
+ const currentScriptErrorEvent = new Event("error");
560
+ currentScript.dispatchEvent(currentScriptErrorEvent);
300
561
  }
301
562
  } else if (typeof error === "object") {
302
563
  const globalErrorEvent = new Event("error");
@@ -311,10 +572,6 @@ const installHtmlSupervisor = ({
311
572
  displayErrorNotification(error);
312
573
  }
313
574
 
314
- if (errorExposureInDocument) {
315
- displayErrorInDocument(error);
316
- }
317
-
318
575
  executionResult.exceptionSource = unevalException(error);
319
576
  delete executionResult.error;
320
577
  };
@@ -333,7 +590,9 @@ const installHtmlSupervisor = ({
333
590
  currentScript,
334
591
  execute // https://developer.mozilla.org/en-US/docs/web/html/element/script
335
592
 
336
- }) => {
593
+ }, {
594
+ reload = false
595
+ } = {}) => {
337
596
  if (logs) {
338
597
  console.group(`[jsenv] loading ${type} ${src}`);
339
598
  }
@@ -344,7 +603,13 @@ const installHtmlSupervisor = ({
344
603
  let error;
345
604
 
346
605
  try {
347
- result = await execute();
606
+ const urlObject = new URL(src, window.location);
607
+
608
+ if (reload) {
609
+ urlObject.searchParams.set("hmr", Date.now());
610
+ }
611
+
612
+ result = await execute(urlObject.href);
348
613
  completed = true;
349
614
  } catch (e) {
350
615
  completed = false;
@@ -408,12 +673,22 @@ const installHtmlSupervisor = ({
408
673
  }));
409
674
 
410
675
  __html_supervisor__.addScriptToExecute = async scriptToExecute => {
676
+ if (!supervisedScripts.includes(scriptToExecute)) {
677
+ supervisedScripts.push(scriptToExecute);
678
+
679
+ scriptToExecute.reload = () => {
680
+ return performExecution(scriptToExecute, {
681
+ reload: true
682
+ });
683
+ };
684
+ }
685
+
411
686
  if (scriptToExecute.async) {
412
687
  performExecution(scriptToExecute);
413
688
  return;
414
689
  }
415
690
 
416
- const useDeferQueue = scriptToExecute.defer || scriptToExecute.type === "js_module";
691
+ const useDeferQueue = scriptToExecute.defer || scriptToExecute.type === "module";
417
692
 
418
693
  if (useDeferQueue) {
419
694
  // defer must wait for classic script to be done
@@ -467,16 +742,118 @@ const installHtmlSupervisor = ({
467
742
  copy.forEach(scriptToExecute => {
468
743
  __html_supervisor__.addScriptToExecute(scriptToExecute);
469
744
  });
745
+
746
+ if (errorOverlay) {
747
+ window.addEventListener("error", errorEvent => {
748
+ if (!errorEvent.isTrusted) {
749
+ // ignore custom error event (not sent by browser)
750
+ return;
751
+ }
752
+
753
+ const {
754
+ error
755
+ } = errorEvent;
756
+ displayErrorInDocument(error, {
757
+ rootDirectoryUrl,
758
+ openInEditor,
759
+ url: errorEvent.filename,
760
+ line: errorEvent.lineno,
761
+ column: errorEvent.colno,
762
+ reportedBy: "browser"
763
+ });
764
+ });
765
+
766
+ if (window.__server_events__) {
767
+ const isExecuting = () => {
768
+ if (pendingExecutionCount > 0) {
769
+ return true;
770
+ }
771
+
772
+ if (document.readyState === "loading" || document.readyState === "interactive") {
773
+ return true;
774
+ }
775
+
776
+ if (window.__reloader__ && window.__reloader__.status === "reloading") {
777
+ return true;
778
+ }
779
+
780
+ return false;
781
+ };
782
+
783
+ window.__server_events__.addEventCallbacks({
784
+ error_while_serving_file: serverErrorEvent => {
785
+ if (!isExecuting()) {
786
+ return;
787
+ }
788
+
789
+ const {
790
+ message,
791
+ stack,
792
+ traceUrl,
793
+ traceLine,
794
+ traceColumn,
795
+ traceMessage,
796
+ requestedRessource,
797
+ isFaviconAutoRequest
798
+ } = JSON.parse(serverErrorEvent.data);
799
+
800
+ if (isFaviconAutoRequest) {
801
+ return;
802
+ } // setTimeout is to ensure the error
803
+ // dispatched on window by browser is displayed first,
804
+ // then the server error replaces it (because it contains more information)
805
+
806
+
807
+ setTimeout(() => {
808
+ displayErrorInDocument({
809
+ message,
810
+ stack: stack && traceMessage ? `${stack}\n\n${traceMessage}` : stack ? stack : traceMessage ? `\n${traceMessage}` : ""
811
+ }, {
812
+ rootDirectoryUrl,
813
+ openInEditor,
814
+ url: traceUrl,
815
+ line: traceLine,
816
+ column: traceColumn,
817
+ reportedBy: "server",
818
+ requestedRessource
819
+ });
820
+ }, 10);
821
+ }
822
+ });
823
+ }
824
+ }
825
+ };
826
+
827
+ __html_supervisor__.reloadSupervisedScript = ({
828
+ type,
829
+ src
830
+ }) => {
831
+ const supervisedScript = supervisedScripts.find(supervisedScriptCandidate => {
832
+ if (type && supervisedScriptCandidate.type !== type) {
833
+ return false;
834
+ }
835
+
836
+ if (supervisedScriptCandidate.src !== src) {
837
+ return false;
838
+ }
839
+
840
+ return true;
841
+ });
842
+
843
+ if (supervisedScript) {
844
+ supervisedScript.reload();
845
+ }
470
846
  };
847
+
471
848
  const superviseScriptTypeModule = ({
472
849
  src,
473
850
  isInline
474
851
  }) => {
475
852
  __html_supervisor__.addScriptToExecute({
476
853
  src,
477
- type: "js_module",
854
+ type: "module",
478
855
  isInline,
479
- execute: () => import(new URL(src, document.location.href).href)
856
+ execute: url => import(url)
480
857
  });
481
858
  };
482
859