@jsenv/core 28.0.2 → 28.1.2

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 (55) hide show
  1. package/dist/controllable_child_process.mjs +1 -2
  2. package/dist/controllable_worker_thread.mjs +1 -2
  3. package/dist/js/autoreload.js +25 -9
  4. package/dist/js/execute_using_dynamic_import.js +804 -1
  5. package/dist/js/script_type_module_supervisor.js +122 -0
  6. package/dist/js/supervisor.js +915 -0
  7. package/dist/main.js +432 -492
  8. package/package.json +13 -13
  9. package/readme.md +1 -1
  10. package/src/build/inject_global_version_mappings.js +3 -3
  11. package/src/dev/start_dev_server.js +2 -2
  12. package/src/execute/execute.js +1 -1
  13. package/src/execute/run.js +26 -38
  14. package/src/execute/runtimes/browsers/from_playwright.js +51 -77
  15. package/src/execute/runtimes/node/node_child_process.js +36 -36
  16. package/src/execute/runtimes/node/node_worker_thread.js +36 -36
  17. package/src/omega/kitchen.js +12 -9
  18. package/src/omega/omega_server.js +2 -2
  19. package/src/omega/server/file_service.js +2 -2
  20. package/src/omega/url_graph/url_info_transformations.js +8 -1
  21. package/src/plugins/autoreload/client/reload.js +20 -7
  22. package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +4 -4
  23. package/src/plugins/import_meta_hot/html_hot_dependencies.js +2 -2
  24. package/src/plugins/importmap/jsenv_plugin_importmap.js +5 -3
  25. package/src/plugins/inject_globals/inject_globals.js +3 -3
  26. package/src/plugins/inline/jsenv_plugin_data_urls.js +1 -1
  27. package/src/plugins/inline/jsenv_plugin_html_inline_content.js +10 -5
  28. package/src/plugins/plugins.js +5 -5
  29. package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +4 -4
  30. package/src/plugins/supervisor/client/script_type_module_supervisor.js +99 -0
  31. package/src/plugins/supervisor/client/supervisor.js +915 -0
  32. package/src/plugins/{html_supervisor/jsenv_plugin_html_supervisor.js → supervisor/jsenv_plugin_supervisor.js} +128 -102
  33. package/src/plugins/toolbar/client/execution/toolbar_execution.js +1 -1
  34. package/src/plugins/toolbar/jsenv_plugin_toolbar.js +4 -4
  35. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +7 -5
  36. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +5 -4
  37. package/src/plugins/transpilation/babel/jsenv_plugin_babel.js +13 -7
  38. package/src/plugins/transpilation/babel/new_stylesheet/babel_plugin_new_stylesheet_as_jsenv_import.js +6 -4
  39. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +4 -2
  40. package/src/plugins/url_analysis/html/html_urls.js +11 -10
  41. package/src/test/coverage/babel_plugin_instrument.js +1 -35
  42. package/src/test/coverage/empty_coverage_factory.js +1 -1
  43. package/src/test/execute_plan.js +7 -3
  44. package/src/test/execute_test_plan.js +2 -1
  45. package/src/test/logs_file_execution.js +49 -8
  46. package/dist/js/html_supervisor_installer.js +0 -1091
  47. package/dist/js/html_supervisor_setup.js +0 -89
  48. package/dist/js/uneval.js +0 -804
  49. package/src/plugins/html_supervisor/client/error_formatter.js +0 -426
  50. package/src/plugins/html_supervisor/client/error_in_notification.js +0 -21
  51. package/src/plugins/html_supervisor/client/error_overlay.js +0 -191
  52. package/src/plugins/html_supervisor/client/html_supervisor_installer.js +0 -315
  53. package/src/plugins/html_supervisor/client/html_supervisor_setup.js +0 -89
  54. package/src/plugins/html_supervisor/client/perf_browser.js +0 -17
  55. package/src/plugins/html_supervisor/client/uneval_exception.js +0 -8
@@ -1,1091 +0,0 @@
1
- import { u as uneval } from "./uneval.js";
2
-
3
- const unevalException = value => {
4
- if (value && value.hasOwnProperty("toString")) {
5
- delete value.toString;
6
- }
7
-
8
- return uneval(value, {
9
- ignoreSymbols: true
10
- });
11
- };
12
-
13
- const formatError = (error, {
14
- rootDirectoryUrl,
15
- errorBaseUrl,
16
- openInEditor,
17
- url,
18
- line,
19
- column
20
- }) => {
21
- let {
22
- message,
23
- stack
24
- } = normalizeErrorParts(error);
25
- let errorDetailsPromiseReference = {
26
- current: null
27
- };
28
- let tip = `Reported by the browser while executing <code>${window.location.pathname}${window.location.search}</code>.`;
29
- let errorUrlSite;
30
- const errorMeta = extractErrorMeta(error, {
31
- url,
32
- line,
33
- column
34
- });
35
-
36
- const resolveUrlSite = ({
37
- url,
38
- line,
39
- column
40
- }) => {
41
- if (typeof line === "string") line = parseInt(line);
42
- if (typeof column === "string") column = parseInt(column);
43
- const inlineUrlMatch = url.match(/@L([0-9]+)C([0-9]+)\-L([0-9]+)C([0-9]+)(\.[\w]+)$/);
44
-
45
- if (inlineUrlMatch) {
46
- const htmlUrl = url.slice(0, inlineUrlMatch.index);
47
- const tagLineStart = parseInt(inlineUrlMatch[1]);
48
- const tagColumnStart = parseInt(inlineUrlMatch[2]);
49
- const tagLineEnd = parseInt(inlineUrlMatch[3]);
50
- const tagColumnEnd = parseInt(inlineUrlMatch[4]);
51
- const extension = inlineUrlMatch[5];
52
- url = htmlUrl;
53
- line = tagLineStart + (typeof line === "number" ? line : 0); // stackTrace formatted by V8 (chrome)
54
-
55
- if (Error.captureStackTrace) {
56
- line--;
57
- }
58
-
59
- if (errorMeta.type === "dynamic_import_syntax_error") {
60
- // syntax error on inline script need line-1 for some reason
61
- if (Error.captureStackTrace) {
62
- line--;
63
- } else {
64
- // firefox and safari need line-2
65
- line -= 2;
66
- }
67
- }
68
-
69
- column = tagColumnStart + (typeof column === "number" ? column : 0);
70
- const fileUrl = resolveFileUrl(url);
71
- return {
72
- isInline: true,
73
- originalUrl: `${fileUrl}@L${tagLineStart}C${tagColumnStart}-L${tagLineEnd}C${tagColumnEnd}${extension}`,
74
- url: fileUrl,
75
- line,
76
- column
77
- };
78
- }
79
-
80
- return {
81
- isInline: false,
82
- url: resolveFileUrl(url),
83
- line,
84
- column
85
- };
86
- };
87
-
88
- const resolveFileUrl = url => {
89
- let urlObject = new URL(url);
90
-
91
- if (urlObject.origin === window.origin) {
92
- urlObject = new URL(`${urlObject.pathname.slice(1)}${urlObject.search}`, rootDirectoryUrl);
93
- }
94
-
95
- if (urlObject.href.startsWith("file:")) {
96
- const atFsIndex = urlObject.pathname.indexOf("/@fs/");
97
-
98
- if (atFsIndex > -1) {
99
- const afterAtFs = urlObject.pathname.slice(atFsIndex + "/@fs/".length);
100
- return new URL(afterAtFs, "file:///").href;
101
- }
102
- }
103
-
104
- return urlObject.href;
105
- };
106
-
107
- const generateClickableText = text => {
108
- const textWithHtmlLinks = makeLinksClickable(text, {
109
- createLink: (url, {
110
- line,
111
- column
112
- }) => {
113
- const urlSite = resolveUrlSite({
114
- url,
115
- line,
116
- column
117
- });
118
-
119
- if (!errorUrlSite && text === stack) {
120
- onErrorLocated(urlSite);
121
- }
122
-
123
- if (errorBaseUrl) {
124
- if (urlSite.url.startsWith(rootDirectoryUrl)) {
125
- urlSite.url = `${errorBaseUrl}${urlSite.url.slice(rootDirectoryUrl.length)}`;
126
- } else {
127
- urlSite.url = "file:///mocked_for_snapshots";
128
- }
129
- }
130
-
131
- const urlWithLineAndColumn = formatUrlWithLineAndColumn(urlSite);
132
- return {
133
- href: url.startsWith("file:") && openInEditor ? `javascript:window.fetch('/__open_in_editor__/${urlWithLineAndColumn}')` : urlSite.url,
134
- text: urlWithLineAndColumn
135
- };
136
- }
137
- });
138
- return textWithHtmlLinks;
139
- };
140
-
141
- const formatErrorText = ({
142
- message,
143
- stack,
144
- codeFrame
145
- }) => {
146
- let text;
147
-
148
- if (message && stack) {
149
- text = `${generateClickableText(message)}\n${generateClickableText(stack)}`;
150
- } else if (stack) {
151
- text = generateClickableText(stack);
152
- } else {
153
- text = generateClickableText(message);
154
- }
155
-
156
- if (codeFrame) {
157
- text += `\n\n${generateClickableText(codeFrame)}`;
158
- }
159
-
160
- return text;
161
- };
162
-
163
- const onErrorLocated = urlSite => {
164
- errorUrlSite = urlSite;
165
-
166
- errorDetailsPromiseReference.current = (async () => {
167
- try {
168
- if (errorMeta.type === "dynamic_import_fetch_error") {
169
- const response = await window.fetch(`/__get_error_cause__/${urlSite.isInline ? urlSite.originalUrl : urlSite.url}`);
170
-
171
- if (response.status !== 200) {
172
- return null;
173
- }
174
-
175
- const causeInfo = await response.json();
176
-
177
- if (!causeInfo) {
178
- return null;
179
- }
180
-
181
- const causeText = causeInfo.code === "NOT_FOUND" ? formatErrorText({
182
- message: causeInfo.reason,
183
- stack: causeInfo.codeFrame
184
- }) : formatErrorText({
185
- message: causeInfo.stack,
186
- stack: causeInfo.codeFrame
187
- });
188
- return {
189
- cause: causeText
190
- };
191
- }
192
-
193
- if (urlSite.line !== undefined) {
194
- let resourceToFetch = `/__get_code_frame__/${formatUrlWithLineAndColumn(urlSite)}`;
195
-
196
- if (!Error.captureStackTrace) {
197
- resourceToFetch += `?remap`;
198
- }
199
-
200
- const response = await window.fetch(resourceToFetch);
201
- const codeFrame = await response.text();
202
- return {
203
- codeFrame: formatErrorText({
204
- message: codeFrame
205
- })
206
- };
207
- }
208
- } catch (e) {
209
- // happens if server is closed for instance
210
- return null;
211
- }
212
-
213
- return null;
214
- })();
215
- }; // error.stack is more reliable than url/line/column reported on window error events
216
- // so use it only when error.stack is not available
217
-
218
-
219
- if (url && !stack && // ignore window.reportError() it gives no valuable info
220
- !url.endsWith("html_supervisor_installer.js")) {
221
- onErrorLocated(resolveUrlSite({
222
- url,
223
- line,
224
- column
225
- }));
226
- } else if (errorMeta.url) {
227
- onErrorLocated(resolveUrlSite(errorMeta));
228
- }
229
-
230
- return {
231
- theme: error && error.cause && error.cause.code === "PARSE_ERROR" ? "light" : "dark",
232
- title: "An error occured",
233
- text: formatErrorText({
234
- message,
235
- stack
236
- }),
237
- tip: `${tip}
238
- <br />
239
- Click outside to close.`,
240
- errorDetailsPromise: errorDetailsPromiseReference.current
241
- };
242
- };
243
-
244
- const extractErrorMeta = (error, {
245
- line
246
- }) => {
247
- if (!error) {
248
- return {};
249
- }
250
-
251
- const {
252
- message
253
- } = error;
254
-
255
- if (!message) {
256
- return {};
257
- }
258
-
259
- {
260
- // chrome
261
- if (message.includes("does not provide an export named")) {
262
- return {
263
- type: "dynamic_import_export_missing"
264
- };
265
- } // firefox
266
-
267
-
268
- if (message.startsWith("import not found:")) {
269
- return {
270
- type: "dynamic_import_export_missing",
271
- browser: "firefox"
272
- };
273
- } // safari
274
-
275
-
276
- if (message.startsWith("import binding name")) {
277
- return {
278
- type: "dynamic_import_export_missing"
279
- };
280
- }
281
- }
282
-
283
- {
284
- if (error.name === "SyntaxError" && typeof line === "number") {
285
- return {
286
- type: "dynamic_import_syntax_error"
287
- };
288
- }
289
- }
290
-
291
- {
292
- // chrome
293
- if (message.startsWith("Failed to fetch dynamically imported module: ")) {
294
- const url = error.message.slice("Failed to fetch dynamically imported module: ".length);
295
- return {
296
- type: "dynamic_import_fetch_error",
297
- url
298
- };
299
- } // firefox
300
-
301
-
302
- if (message === "error loading dynamically imported module") {
303
- return {
304
- type: "dynamic_import_fetch_error"
305
- };
306
- } // safari
307
-
308
-
309
- if (message === "Importing a module script failed.") {
310
- return {
311
- type: "dynamic_import_fetch_error"
312
- };
313
- }
314
- }
315
-
316
- return {};
317
- };
318
-
319
- const formatUrlWithLineAndColumn = ({
320
- url,
321
- line,
322
- column
323
- }) => {
324
- return line === undefined && column === undefined ? url : column === undefined ? `${url}:${line}` : `${url}:${line}:${column}`;
325
- };
326
-
327
- const normalizeErrorParts = error => {
328
- if (error === undefined) {
329
- return {
330
- message: "undefined"
331
- };
332
- }
333
-
334
- if (error === null) {
335
- return {
336
- message: "null"
337
- };
338
- }
339
-
340
- if (typeof error === "string") {
341
- return {
342
- message: error
343
- };
344
- }
345
-
346
- if (error instanceof Error) {
347
- if (error.name === "SyntaxError") {
348
- return {
349
- message: error.message
350
- };
351
- }
352
-
353
- if (error.cause && error.cause.code === "PARSE_ERROR") {
354
- if (error.messageHTML) {
355
- return {
356
- message: error.messageHTML
357
- };
358
- }
359
-
360
- return {
361
- message: error.message
362
- };
363
- } // stackTrace formatted by V8
364
-
365
-
366
- if (Error.captureStackTrace) {
367
- return {
368
- message: error.message,
369
- stack: getErrorStackWithoutErrorMessage(error)
370
- };
371
- }
372
-
373
- return {
374
- message: error.message,
375
- stack: error.stack ? ` ${error.stack}` : null
376
- };
377
- }
378
-
379
- if (typeof error === "object") {
380
- return error;
381
- }
382
-
383
- return {
384
- message: JSON.stringify(error)
385
- };
386
- };
387
-
388
- const getErrorStackWithoutErrorMessage = error => {
389
- let stack = error.stack;
390
- const messageInStack = `${error.name}: ${error.message}`;
391
-
392
- if (stack.startsWith(messageInStack)) {
393
- stack = stack.slice(messageInStack.length);
394
- }
395
-
396
- const nextLineIndex = stack.indexOf("\n");
397
-
398
- if (nextLineIndex > -1) {
399
- stack = stack.slice(nextLineIndex + 1);
400
- }
401
-
402
- return stack;
403
- };
404
-
405
- const makeLinksClickable = (string, {
406
- createLink = url => url
407
- }) => {
408
- // normalize line breaks
409
- string = string.replace(/\n/g, "\n");
410
- string = escapeHtml(string); // render links
411
-
412
- string = stringToStringWithLink(string, {
413
- transform: (url, {
414
- line,
415
- column
416
- }) => {
417
- const {
418
- href,
419
- text
420
- } = createLink(url, {
421
- line,
422
- column
423
- });
424
- return link({
425
- href,
426
- text
427
- });
428
- }
429
- });
430
- return string;
431
- };
432
-
433
- const escapeHtml = string => {
434
- return string.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
435
- }; // `Error: yo
436
- // at Object.execute (http://127.0.0.1:57300/build/src/__test__/file-throw.js:9:13)
437
- // at doExec (http://127.0.0.1:3000/src/__test__/file-throw.js:452:38)
438
- // at postOrderExec (http://127.0.0.1:3000/src/__test__/file-throw.js:448:16)
439
- // at http://127.0.0.1:3000/src/__test__/file-throw.js:399:18`.replace(/(?:https?|ftp|file):\/\/(.*+)$/gm, (...args) => {
440
- // debugger
441
- // })
442
-
443
-
444
- const stringToStringWithLink = (source, {
445
- transform = url => {
446
- return {
447
- href: url,
448
- text: url
449
- };
450
- }
451
- } = {}) => {
452
- return source.replace(/(?:https?|ftp|file):\/\/\S+/gm, match => {
453
- let linkHTML = "";
454
- const lastChar = match[match.length - 1]; // hotfix because our url regex sucks a bit
455
-
456
- const endsWithSeparationChar = lastChar === ")" || lastChar === ":";
457
-
458
- if (endsWithSeparationChar) {
459
- match = match.slice(0, -1);
460
- }
461
-
462
- const lineAndColumnPattern = /:([0-9]+):([0-9]+)$/;
463
- const lineAndColumMatch = match.match(lineAndColumnPattern);
464
-
465
- if (lineAndColumMatch) {
466
- const lineAndColumnString = lineAndColumMatch[0];
467
- const lineNumber = lineAndColumMatch[1];
468
- const columnNumber = lineAndColumMatch[2];
469
- linkHTML = transform(match.slice(0, -lineAndColumnString.length), {
470
- line: lineNumber,
471
- column: columnNumber
472
- });
473
- } else {
474
- const linePattern = /:([0-9]+)$/;
475
- const lineMatch = match.match(linePattern);
476
-
477
- if (lineMatch) {
478
- const lineString = lineMatch[0];
479
- const lineNumber = lineMatch[1];
480
- linkHTML = transform(match.slice(0, -lineString.length), {
481
- line: lineNumber
482
- });
483
- } else {
484
- linkHTML = transform(match, {});
485
- }
486
- }
487
-
488
- if (endsWithSeparationChar) {
489
- return `${linkHTML}${lastChar}`;
490
- }
491
-
492
- return linkHTML;
493
- });
494
- };
495
-
496
- const link = ({
497
- href,
498
- text = href
499
- }) => `<a href="${href}">${text}</a>`;
500
-
501
- const JSENV_ERROR_OVERLAY_TAGNAME = "jsenv-error-overlay";
502
- const displayErrorInDocument = (error, {
503
- rootDirectoryUrl,
504
- errorBaseUrl,
505
- openInEditor,
506
- url,
507
- line,
508
- column,
509
- codeFrame
510
- }) => {
511
- const {
512
- theme,
513
- title,
514
- text,
515
- tip,
516
- errorDetailsPromise
517
- } = formatError(error, {
518
- rootDirectoryUrl,
519
- errorBaseUrl,
520
- openInEditor,
521
- url,
522
- line,
523
- column,
524
- codeFrame
525
- });
526
- let jsenvErrorOverlay = new JsenvErrorOverlay({
527
- theme,
528
- title,
529
- text,
530
- tip,
531
- errorDetailsPromise
532
- });
533
- document.querySelectorAll(JSENV_ERROR_OVERLAY_TAGNAME).forEach(node => {
534
- node.parentNode.removeChild(node);
535
- });
536
- document.body.appendChild(jsenvErrorOverlay);
537
-
538
- const removeErrorOverlay = () => {
539
- if (jsenvErrorOverlay && jsenvErrorOverlay.parentNode) {
540
- document.body.removeChild(jsenvErrorOverlay);
541
- jsenvErrorOverlay = null;
542
- }
543
- };
544
-
545
- if (window.__reloader__) {
546
- window.__reloader__.onstatuschange = () => {
547
- if (window.__reloader__.status === "reloading") {
548
- removeErrorOverlay();
549
- }
550
- };
551
- }
552
-
553
- return removeErrorOverlay;
554
- };
555
-
556
- class JsenvErrorOverlay extends HTMLElement {
557
- constructor({
558
- theme,
559
- title,
560
- text,
561
- tip,
562
- errorDetailsPromise
563
- }) {
564
- super();
565
- this.root = this.attachShadow({
566
- mode: "open"
567
- });
568
- this.root.innerHTML = `
569
- <style>
570
- ${overlayCSS}
571
- </style>
572
- <div class="backdrop"></div>
573
- <div class="overlay" data-theme=${theme}>
574
- <h1 class="title">
575
- ${title}
576
- </h1>
577
- <pre class="text">${text}</pre>
578
- <div class="tip">
579
- ${tip}
580
- </div>
581
- </div>`;
582
-
583
- this.root.querySelector(".backdrop").onclick = () => {
584
- if (!this.parentNode) {
585
- // not in document anymore
586
- return;
587
- }
588
-
589
- this.root.querySelector(".backdrop").onclick = null;
590
- this.parentNode.removeChild(this);
591
- };
592
-
593
- if (errorDetailsPromise) {
594
- errorDetailsPromise.then(errorDetails => {
595
- if (!errorDetails || !this.parentNode) {
596
- return;
597
- }
598
-
599
- const {
600
- codeFrame,
601
- cause
602
- } = errorDetails;
603
-
604
- if (codeFrame) {
605
- this.root.querySelector(".text").innerHTML += `\n\n${codeFrame}`;
606
- }
607
-
608
- if (cause) {
609
- const causeIndented = prefixRemainingLines(cause, " ");
610
- this.root.querySelector(".text").innerHTML += `\n [cause]: ${causeIndented}`;
611
- }
612
- });
613
- }
614
- }
615
-
616
- }
617
-
618
- const prefixRemainingLines = (text, prefix) => {
619
- const lines = text.split(/\r?\n/);
620
- const firstLine = lines.shift();
621
- let result = firstLine;
622
- let i = 0;
623
-
624
- while (i < lines.length) {
625
- const line = lines[i];
626
- i++;
627
- result += line.length ? `\n${prefix}${line}` : `\n`;
628
- }
629
-
630
- return result;
631
- };
632
-
633
- if (customElements && !customElements.get(JSENV_ERROR_OVERLAY_TAGNAME)) {
634
- customElements.define(JSENV_ERROR_OVERLAY_TAGNAME, JsenvErrorOverlay);
635
- }
636
-
637
- const overlayCSS = `
638
- :host {
639
- position: fixed;
640
- z-index: 99999;
641
- top: 0;
642
- left: 0;
643
- width: 100%;
644
- height: 100%;
645
- overflow-y: scroll;
646
- margin: 0;
647
- background: rgba(0, 0, 0, 0.66);
648
- }
649
-
650
- .backdrop {
651
- position: absolute;
652
- left: 0;
653
- right: 0;
654
- top: 0;
655
- bottom: 0;
656
- }
657
-
658
- .overlay {
659
- position: relative;
660
- background: rgba(0, 0, 0, 0.95);
661
- width: 800px;
662
- margin: 30px auto;
663
- padding: 25px 40px;
664
- padding-top: 0;
665
- overflow: hidden; /* for h1 margins */
666
- border-radius: 4px 8px;
667
- box-shadow: 0 20px 40px rgb(0 0 0 / 30%), 0 15px 12px rgb(0 0 0 / 20%);
668
- box-sizing: border-box;
669
- font-family: monospace;
670
- direction: ltr;
671
- }
672
-
673
- h1 {
674
- color: red;
675
- text-align: center;
676
- }
677
-
678
- pre {
679
- overflow: auto;
680
- max-width: 100%;
681
- /* padding is nice + prevents scrollbar from hiding the text behind it */
682
- /* does not work nicely on firefox though https://bugzilla.mozilla.org/show_bug.cgi?id=748518 */
683
- padding: 20px;
684
- }
685
-
686
- .tip {
687
- border-top: 1px solid #999;
688
- padding-top: 12px;
689
- }
690
-
691
- [data-theme="dark"] {
692
- color: #999;
693
- }
694
- [data-theme="dark"] pre {
695
- background: #111;
696
- border: 1px solid #333;
697
- color: #eee;
698
- }
699
-
700
- [data-theme="light"] {
701
- color: #EEEEEE;
702
- }
703
- [data-theme="light"] pre {
704
- background: #1E1E1E;
705
- border: 1px solid white;
706
- color: #EEEEEE;
707
- }
708
-
709
- pre a {
710
- color: inherit;
711
- }`;
712
-
713
- const {
714
- Notification
715
- } = window;
716
-
717
- const displayErrorNotificationNotAvailable = () => {};
718
-
719
- const displayErrorNotificationImplementation = (error, {
720
- icon
721
- } = {}) => {
722
- if (Notification.permission === "granted") {
723
- const notification = new Notification("An error occured", {
724
- lang: "en",
725
- body: error ? error.stack : "undefined",
726
- icon
727
- });
728
-
729
- notification.onclick = () => {
730
- window.focus();
731
- };
732
- }
733
- };
734
-
735
- const displayErrorNotification = typeof Notification === "function" ? displayErrorNotificationImplementation : displayErrorNotificationNotAvailable;
736
-
737
- const {
738
- __html_supervisor__
739
- } = window;
740
- const supervisedScripts = [];
741
- const installHtmlSupervisor = ({
742
- rootDirectoryUrl,
743
- logs,
744
- measurePerf,
745
- errorOverlay,
746
- errorBaseUrl,
747
- openInEditor
748
- }) => {
749
-
750
- const scriptExecutionResults = {};
751
- let collectCalled = false;
752
- let pendingExecutionCount = 0;
753
- let resolveScriptExecutionsPromise;
754
- const scriptExecutionsPromise = new Promise(resolve => {
755
- resolveScriptExecutionsPromise = resolve;
756
- });
757
-
758
- const onExecutionStart = name => {
759
- scriptExecutionResults[name] = null; // ensure execution order is reflected into the object
760
-
761
- pendingExecutionCount++;
762
-
763
- if (measurePerf) {
764
- performance.mark(`execution_start`);
765
- }
766
- };
767
-
768
- const onExecutionSettled = (name, executionResult) => {
769
- if (measurePerf) {
770
- performance.measure(`execution`, `execution_start`);
771
- }
772
-
773
- scriptExecutionResults[name] = executionResult;
774
- pendingExecutionCount--;
775
-
776
- if (pendingExecutionCount === 0 && collectCalled) {
777
- resolveScriptExecutionsPromise();
778
- }
779
- };
780
-
781
- const onExecutionError = (executionResult, {
782
- currentScript,
783
- errorExposureInNotification = false
784
- }) => {
785
- const error = executionResult.error;
786
-
787
- if (error && error.code === "NETWORK_FAILURE") {
788
- if (currentScript) {
789
- const currentScriptErrorEvent = new Event("error");
790
- currentScript.dispatchEvent(currentScriptErrorEvent);
791
- }
792
- } else if (typeof error === "object") {
793
- const globalErrorEvent = new Event("error");
794
- globalErrorEvent.filename = error.filename;
795
- globalErrorEvent.lineno = error.line || error.lineno;
796
- globalErrorEvent.colno = error.column || error.columnno;
797
- globalErrorEvent.message = error.message;
798
- window.dispatchEvent(globalErrorEvent);
799
- }
800
-
801
- if (errorExposureInNotification) {
802
- displayErrorNotification(error);
803
- }
804
-
805
- executionResult.exceptionSource = unevalException(error);
806
- delete executionResult.error;
807
- };
808
-
809
- const getNavigationStartTime = () => {
810
- try {
811
- return window.performance.timing.navigationStart;
812
- } catch (e) {
813
- return Date.now();
814
- }
815
- };
816
-
817
- const performExecution = async ({
818
- src,
819
- type,
820
- currentScript,
821
- execute // https://developer.mozilla.org/en-US/docs/web/html/element/script
822
-
823
- }, {
824
- reload = false
825
- } = {}) => {
826
- if (logs) {
827
- console.group(`[jsenv] loading ${type} ${src}`);
828
- }
829
-
830
- onExecutionStart(src);
831
- let completed;
832
- let result;
833
- let error;
834
- const urlObject = new URL(src, window.location);
835
-
836
- if (reload) {
837
- urlObject.searchParams.set("hmr", Date.now());
838
- }
839
-
840
- __html_supervisor__.currentExecution = {
841
- type: type === "module" ? "dynamic_import" : "script_injection",
842
- url: urlObject.href
843
- };
844
-
845
- try {
846
- result = await execute(urlObject.href);
847
- completed = true;
848
- } catch (e) {
849
- completed = false;
850
- error = e;
851
- }
852
-
853
- if (completed) {
854
- const executionResult = {
855
- status: "completed",
856
- namespace: result,
857
- coverage: window.__coverage__
858
- };
859
- onExecutionSettled(src, executionResult);
860
-
861
- if (logs) {
862
- console.log(`${type} load ended`);
863
- console.groupEnd();
864
- }
865
-
866
- __html_supervisor__.currentExecution = null;
867
- return;
868
- }
869
-
870
- const executionResult = {
871
- status: "errored",
872
- coverage: window.__coverage__
873
- };
874
-
875
- if (error.name === "SyntaxError") ;
876
-
877
- executionResult.error = error;
878
- onExecutionSettled(src, executionResult);
879
- onExecutionError(executionResult, {
880
- currentScript
881
- });
882
-
883
- {
884
- if (typeof window.reportError === "function") {
885
- window.reportError(error);
886
- } else {
887
- console.error(error);
888
- }
889
- }
890
-
891
- if (logs) {
892
- console.groupEnd();
893
- }
894
-
895
- __html_supervisor__.currentExecution = null;
896
- };
897
-
898
- const classicExecutionQueue = createExecutionQueue(performExecution);
899
- const deferedExecutionQueue = createExecutionQueue(performExecution);
900
- deferedExecutionQueue.waitFor(new Promise(resolve => {
901
- if (document.readyState === "interactive" || document.readyState === "complete") {
902
- resolve();
903
- } else {
904
- document.addEventListener("readystatechange", () => {
905
- if (document.readyState === "interactive") {
906
- resolve();
907
- }
908
- });
909
- }
910
- }));
911
-
912
- __html_supervisor__.addScriptToExecute = async scriptToExecute => {
913
- if (!supervisedScripts.includes(scriptToExecute)) {
914
- supervisedScripts.push(scriptToExecute);
915
-
916
- scriptToExecute.reload = () => {
917
- return performExecution(scriptToExecute, {
918
- reload: true
919
- });
920
- };
921
- }
922
-
923
- if (scriptToExecute.async) {
924
- performExecution(scriptToExecute);
925
- return;
926
- }
927
-
928
- const useDeferQueue = scriptToExecute.defer || scriptToExecute.type === "module";
929
-
930
- if (useDeferQueue) {
931
- const classicExecutionPromise = classicExecutionQueue.getPromise();
932
-
933
- if (classicExecutionPromise) {
934
- deferedExecutionQueue.waitFor(classicExecutionPromise);
935
- }
936
-
937
- deferedExecutionQueue.executeAsap(scriptToExecute);
938
- } else {
939
- classicExecutionQueue.executeAsap(scriptToExecute);
940
- }
941
- };
942
-
943
- __html_supervisor__.collectScriptResults = async () => {
944
- collectCalled = true;
945
-
946
- if (pendingExecutionCount === 0) {
947
- resolveScriptExecutionsPromise();
948
- } else {
949
- await scriptExecutionsPromise;
950
- }
951
-
952
- let status = "completed";
953
- let exceptionSource = "";
954
- Object.keys(scriptExecutionResults).forEach(key => {
955
- const scriptExecutionResult = scriptExecutionResults[key];
956
-
957
- if (scriptExecutionResult.status === "errored") {
958
- status = "errored";
959
- exceptionSource = scriptExecutionResult.exceptionSource;
960
- }
961
- });
962
- return {
963
- status,
964
- ...(status === "errored" ? {
965
- exceptionSource
966
- } : {}),
967
- startTime: getNavigationStartTime(),
968
- endTime: Date.now(),
969
- scriptExecutionResults
970
- };
971
- };
972
-
973
- const {
974
- scriptsToExecute
975
- } = __html_supervisor__;
976
- const copy = scriptsToExecute.slice();
977
- scriptsToExecute.length = 0;
978
- copy.forEach(scriptToExecute => {
979
- __html_supervisor__.addScriptToExecute(scriptToExecute);
980
- });
981
-
982
- if (errorOverlay) {
983
- const onErrorReportedByBrowser = (error, {
984
- url,
985
- line,
986
- column
987
- }) => {
988
- displayErrorInDocument(error, {
989
- rootDirectoryUrl,
990
- errorBaseUrl,
991
- openInEditor,
992
- url,
993
- line,
994
- column
995
- });
996
- };
997
-
998
- window.addEventListener("error", errorEvent => {
999
- if (!errorEvent.isTrusted) {
1000
- // ignore custom error event (not sent by browser)
1001
- return;
1002
- }
1003
-
1004
- const {
1005
- error,
1006
- filename,
1007
- lineno,
1008
- colno
1009
- } = errorEvent;
1010
- onErrorReportedByBrowser(error, {
1011
- url: filename,
1012
- line: lineno,
1013
- column: colno
1014
- });
1015
- });
1016
- }
1017
- };
1018
-
1019
- __html_supervisor__.reloadSupervisedScript = ({
1020
- type,
1021
- src
1022
- }) => {
1023
- const supervisedScript = supervisedScripts.find(supervisedScriptCandidate => {
1024
- if (type && supervisedScriptCandidate.type !== type) {
1025
- return false;
1026
- }
1027
-
1028
- if (supervisedScriptCandidate.src !== src) {
1029
- return false;
1030
- }
1031
-
1032
- return true;
1033
- });
1034
-
1035
- if (supervisedScript) {
1036
- supervisedScript.reload();
1037
- }
1038
- };
1039
-
1040
- const superviseScriptTypeModule = ({
1041
- src,
1042
- isInline
1043
- }) => {
1044
- __html_supervisor__.addScriptToExecute({
1045
- src,
1046
- type: "module",
1047
- isInline,
1048
- execute: url => import(url)
1049
- });
1050
- };
1051
-
1052
- const createExecutionQueue = execute => {
1053
- const scripts = [];
1054
- let promiseToWait = null;
1055
-
1056
- const waitFor = async promise => {
1057
- promiseToWait = promise;
1058
- promiseToWait.then(() => {
1059
- promiseToWait = null;
1060
- dequeue();
1061
- }, () => {
1062
- promiseToWait = null;
1063
- dequeue();
1064
- });
1065
- };
1066
-
1067
- const executeAsap = async script => {
1068
- if (promiseToWait) {
1069
- scripts.push(script);
1070
- return;
1071
- }
1072
-
1073
- waitFor(execute(script));
1074
- };
1075
-
1076
- const dequeue = () => {
1077
- const scriptWaiting = scripts.shift();
1078
-
1079
- if (scriptWaiting) {
1080
- __html_supervisor__.addScriptToExecute(scriptWaiting);
1081
- }
1082
- };
1083
-
1084
- return {
1085
- waitFor,
1086
- executeAsap,
1087
- getPromise: () => promiseToWait
1088
- };
1089
- };
1090
-
1091
- export { installHtmlSupervisor, superviseScriptTypeModule };