@jsenv/plugin-supervisor 1.4.0 → 1.4.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.
@@ -13,13 +13,18 @@ window.__supervisor__ = (() => {
13
13
  typeof window.webkitConvertPointFromNodeToPage === "function";
14
14
 
15
15
  const executionResults = {};
16
- let documentExecutionStartTime;
16
+ let documentTimingsOrigin;
17
17
  try {
18
- documentExecutionStartTime = window.performance.timing.navigationStart;
18
+ documentTimingsOrigin = window.performance.timing.navigationStart;
19
19
  } catch (e) {
20
- documentExecutionStartTime = Date.now();
20
+ documentTimingsOrigin = Date.now();
21
21
  }
22
- let documentExecutionEndTime;
22
+ const documentTimings = {
23
+ origin: documentTimingsOrigin,
24
+ start: Date.now() - documentTimingsOrigin,
25
+ end: null,
26
+ };
27
+
23
28
  supervisor.setup = ({
24
29
  rootDirectoryUrl,
25
30
  scriptInfos,
@@ -80,10 +85,13 @@ window.__supervisor__ = (() => {
80
85
  const createExecutionController = (src, type) => {
81
86
  const result = {
82
87
  status: "pending",
83
- duration: null,
84
88
  coverage: null,
85
89
  exception: null,
86
90
  value: null,
91
+ timings: {
92
+ start: null,
93
+ end: null,
94
+ },
87
95
  };
88
96
 
89
97
  let resolve;
@@ -94,7 +102,7 @@ window.__supervisor__ = (() => {
94
102
  executionResults[src] = result;
95
103
 
96
104
  const start = () => {
97
- result.duration = null;
105
+ result.timings.start = Date.now() - documentTimingsOrigin;
98
106
  result.coverage = null;
99
107
  result.status = "started";
100
108
  result.exception = null;
@@ -103,16 +111,15 @@ window.__supervisor__ = (() => {
103
111
  }
104
112
  };
105
113
  const end = () => {
106
- const now = Date.now();
107
114
  remainingScriptCount--;
108
- result.duration = now - documentExecutionStartTime;
115
+ result.timings.end = Date.now() - documentTimingsOrigin;
109
116
  result.coverage = window.__coverage__;
110
117
  if (logs) {
111
118
  console.log(`execution ${result.status}`);
112
119
  console.groupEnd();
113
120
  }
114
121
  if (remainingScriptCount === 0) {
115
- documentExecutionEndTime = now;
122
+ documentTimings.end = Date.now() - documentTimingsOrigin;
116
123
  }
117
124
  resolve();
118
125
  };
@@ -160,16 +167,20 @@ window.__supervisor__ = (() => {
160
167
  }
161
168
  const scriptLoadPromise = getScriptLoadPromise(currentScriptClone);
162
169
  parentNode.replaceChild(currentScriptClone, nodeToReplace);
163
- const { detectedBy, failed, error } = await scriptLoadPromise;
170
+ const { detectedBy, failed, errorEvent } = await scriptLoadPromise;
164
171
  if (failed) {
172
+ const messageDefault = `Error while loading script`;
173
+ const { error, message, filename, lineno, colno } = errorEvent;
165
174
  if (detectedBy === "script_error_event") {
166
175
  // window.error won't be dispatched for this error
167
- reportErrorBackToBrowser(error);
176
+ reportErrorBackToBrowser(error || errorEvent);
168
177
  }
169
- fail(error, {
170
- message: `Error while loading script: ${urlObject.href}`,
178
+ fail(error || message || messageDefault, {
179
+ message: messageDefault,
171
180
  reportedBy: "script_error_event",
172
- url: urlObject.href,
181
+ url: filename || urlObject.href,
182
+ line: lineno,
183
+ column: colno,
173
184
  });
174
185
  if (detectedBy === "script_error_event") {
175
186
  supervisor.reportException(result.exception);
@@ -222,7 +233,7 @@ window.__supervisor__ = (() => {
222
233
  return result;
223
234
  } catch (e) {
224
235
  fail(e, {
225
- message: `Error while importing module: ${urlObject.href}`,
236
+ message: `Error while importing module`,
226
237
  reportedBy: "dynamic_import",
227
238
  url: urlObject.href,
228
239
  });
@@ -268,16 +279,21 @@ window.__supervisor__ = (() => {
268
279
  const scriptLoadResultPromise =
269
280
  getScriptLoadPromise(currentScriptClone);
270
281
  parentNode.replaceChild(currentScriptClone, nodeToReplace);
271
- const { detectedBy, failed, error } = await scriptLoadResultPromise;
282
+ const { detectedBy, failed, errorEvent } =
283
+ await scriptLoadResultPromise;
272
284
 
273
285
  if (failed) {
286
+ const messageDefault = `Error while loading module`;
287
+ const { error, message, filename, lineno, colno } = errorEvent;
274
288
  // if (detectedBy === "script_error_event") {
275
289
  // reportErrorBackToBrowser(error)
276
290
  // }
277
- fail(error, {
278
- message: `Error while loading module: ${urlObject.href}`,
291
+ fail(error || message || messageDefault, {
292
+ message: messageDefault,
279
293
  reportedBy: "script_error_event",
280
- url: urlObject.href,
294
+ url: filename || urlObject.href,
295
+ line: lineno,
296
+ column: colno,
281
297
  });
282
298
  if (detectedBy === "script_error_event") {
283
299
  supervisor.reportException(result.exception);
@@ -391,8 +407,7 @@ window.__supervisor__ = (() => {
391
407
  supervisor.getDocumentExecutionResult = async () => {
392
408
  await Promise.all(promises);
393
409
  return {
394
- startTime: documentExecutionStartTime,
395
- endTime: documentExecutionEndTime,
410
+ timings: documentTimings,
396
411
  status: "completed",
397
412
  executionResults,
398
413
  };
@@ -435,10 +450,11 @@ window.__supervisor__ = (() => {
435
450
  stackSourcemapped: null,
436
451
  stackOriginal: "", // the stack from runtime, not normalized to v8
437
452
  stackTrace: "", // the stack trace (without error name and message)
453
+ stackFrames: undefined,
438
454
  withServerUrls: {
439
455
  message: "",
440
- stackTrace: "",
441
456
  stack: "",
457
+ stackTrace: "",
442
458
  },
443
459
  meta: null,
444
460
  site: {
@@ -463,78 +479,154 @@ window.__supervisor__ = (() => {
463
479
  exception.message = reason;
464
480
  return;
465
481
  }
466
- if (reason instanceof Error) {
467
- const error = reason;
468
- exception.isError = true;
469
- exception.name = error.name || "Error";
470
- exception.message = error.message || "";
471
- if (
472
- Error.captureStackTrace &&
473
- // captureStackTrace exists on webkit but error.stack is not v8
474
- !isWebkitOrSafari
475
- ) {
476
- // stackTrace formatted by V8
477
- exception.stackSourcemapped = true;
478
- exception.stack = error.stack;
479
- exception.stackTrace = getErrorStackTrace(error);
480
- } else if (error.stack) {
481
- exception.stackSourcemapped = false;
482
- exception.stackTrace = error.stack;
483
- exception.stack = stringifyStack(exception);
484
- }
482
+ if (typeof reason !== "object") {
483
+ exception.message = JSON.stringify(reason);
484
+ return;
485
+ }
486
+ // isError can be false when reason is an ErrorEvent for instance
487
+ exception.isError = reason instanceof Error;
488
+ exception.name = reason.name || "Error";
489
+ exception.message = reason.message || message || "";
485
490
 
486
- if (error.reportedBy) {
487
- exception.reportedBy = error.reportedBy;
488
- }
489
- if (error.url) {
490
- Object.assign(exception.site, resolveUrlSite({ url: error.url }));
491
- }
492
- export_missing: {
493
- // chrome
494
- if (error.message.includes("does not provide an export named")) {
495
- exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
496
- return;
497
- }
498
- // firefox
499
- if (
500
- error.message.startsWith("import not found:") ||
501
- error.message.startsWith("ambiguous indirect export:")
502
- ) {
503
- exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
504
- return;
491
+ let stackFrames;
492
+ if (
493
+ exception.isError &&
494
+ Error.captureStackTrace &&
495
+ // captureStackTrace exists on webkit but error.stack is not v8
496
+ !isWebkitOrSafari
497
+ ) {
498
+ // stackTrace formatted by V8
499
+ const { prepareStackTrace } = Error;
500
+ Error.prepareStackTrace = (e, callSites) => {
501
+ Error.prepareStackTrace = prepareStackTrace;
502
+
503
+ const getPropertiesFromEvalOrigin = (origin) => {
504
+ // Most eval() calls are in this format
505
+ const topLevelEvalMatch =
506
+ /^eval at ([^(]+) \((.+):(\d+):(\d+)\)$/.exec(origin);
507
+ if (topLevelEvalMatch) {
508
+ const source = topLevelEvalMatch[2];
509
+ const line = Number(topLevelEvalMatch[3]);
510
+ const column = topLevelEvalMatch[4] - 1;
511
+ return {
512
+ url: source,
513
+ line,
514
+ column,
515
+ };
516
+ }
517
+ // Parse nested eval() calls using recursion
518
+ const nestedEvalMatch = /^eval at ([^(]+) \((.+)\)$/.exec(origin);
519
+ if (nestedEvalMatch) {
520
+ return getPropertiesFromEvalOrigin(nestedEvalMatch[2]);
521
+ }
522
+ return null;
523
+ };
524
+
525
+ stackFrames = [];
526
+ for (const callSite of callSites) {
527
+ const url =
528
+ callSite.getFileName() || callSite.getScriptNameOrSourceURL();
529
+ const line = callSite.getLineNumber();
530
+ const column = callSite.getColumnNumber();
531
+ const site = resolveUrlSite({ url, line, column });
532
+ const stackFrame = {
533
+ raw: ` at ${String(callSite)}`,
534
+ url: site.url,
535
+ line: site.line,
536
+ column: site.column,
537
+ functionName: callSite.getFunctionName(),
538
+ isNative: callSite.isNative(),
539
+ isEval: callSite.isEval(),
540
+ isConstructor: callSite.isConstructor(),
541
+ isAsync: callSite.isAsync(),
542
+ evalSite: null,
543
+ };
544
+ if (stackFrame.isEval) {
545
+ const evalOrigin = stackFrame.getEvalOrigin();
546
+ if (evalOrigin) {
547
+ stackFrame.evalSite = getPropertiesFromEvalOrigin(evalOrigin);
548
+ }
549
+ }
550
+ stackFrames.push(stackFrame);
505
551
  }
506
- // safari
507
- if (error.message.startsWith("import binding name")) {
508
- exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
509
- return;
552
+ let stackTrace = "";
553
+ for (const stackFrame of stackFrames) {
554
+ if (stackTrace) stackTrace += "\n";
555
+ stackTrace += stackFrame.raw;
510
556
  }
511
- if (error.message.includes("Importing a module script failed")) {
512
- exception.code = DYNAMIC_IMPORT_FETCH_ERROR;
513
- return;
557
+ exception.stackTrace = stackTrace;
558
+
559
+ let stack = "";
560
+ const name = reason.name || "Error";
561
+ const message = reason.message || "";
562
+ stack += `${name}: ${message}`;
563
+ if (stackTrace) {
564
+ stack += `\n${stackTrace}`;
514
565
  }
515
- }
516
- js_syntax_error: {
517
- if (error.name === "SyntaxError" && typeof line === "number") {
518
- exception.code = DYNAMIC_IMPORT_SYNTAX_ERROR;
519
- return;
566
+ return stack;
567
+ };
568
+
569
+ exception.stackSourcemapped = true;
570
+ exception.stack = reason.stack;
571
+ if (stackFrames === undefined) {
572
+ // Error.prepareStackTrace not trigerred
573
+ // - reason is not an error
574
+ // - reason.stack already get
575
+ Error.prepareStackTrace = prepareStackTrace;
576
+ exception.stackTrace = getErrorStackTrace(reason);
577
+ } else {
578
+ exception.stackFrames = stackFrames;
579
+ const [firstCallFrame] = stackFrames;
580
+ if (
581
+ exception.site.url === null &&
582
+ firstCallFrame &&
583
+ firstCallFrame.url
584
+ ) {
585
+ Object.assign(exception.site, {
586
+ url: firstCallFrame.url,
587
+ line: firstCallFrame.line,
588
+ column: firstCallFrame.column,
589
+ });
520
590
  }
521
591
  }
522
- return;
592
+ } else {
593
+ exception.stackSourcemapped = false;
594
+ exception.stackTrace = reason.stack;
595
+ exception.stack = stringifyStack(exception);
523
596
  }
524
- if (typeof reason === "object") {
525
- // happens when reason is an Event for instance
526
- exception.code = reason.code;
527
- exception.message = reason.message || message;
528
- exception.stack = reason.stack;
529
- if (reason.reportedBy) {
530
- exception.reportedBy = reason.reportedBy;
597
+
598
+ if (exception.site.url === null && reason.url) {
599
+ Object.assign(exception.site, resolveUrlSite({ url: reason.url }));
600
+ }
601
+ export_missing: {
602
+ // chrome
603
+ if (exception.message.includes("does not provide an export named")) {
604
+ exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
605
+ }
606
+ // firefox
607
+ if (
608
+ exception.message.startsWith("import not found:") ||
609
+ exception.message.startsWith("ambiguous indirect export:")
610
+ ) {
611
+ exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
531
612
  }
532
- if (reason.url) {
533
- Object.assign(exception.site, resolveUrlSite({ url: reason.url }));
613
+ // safari
614
+ if (exception.message.startsWith("import binding name")) {
615
+ exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
616
+ }
617
+ if (exception.message.includes("Importing a module script failed")) {
618
+ exception.code = DYNAMIC_IMPORT_FETCH_ERROR;
619
+ }
620
+ }
621
+ js_syntax_error: {
622
+ if (
623
+ !exception.code &&
624
+ exception.name === "SyntaxError" &&
625
+ typeof line === "number"
626
+ ) {
627
+ exception.code = DYNAMIC_IMPORT_SYNTAX_ERROR;
534
628
  }
535
- return;
536
629
  }
537
- exception.message = JSON.stringify(reason);
538
630
  };
539
631
  writeBasicProperties();
540
632
 
@@ -549,7 +641,8 @@ window.__supervisor__ = (() => {
549
641
  const fileUrlSite = resolveUrlSite({ url, line, column });
550
642
  if (
551
643
  fileUrlSite.isInline &&
552
- exception.code === DYNAMIC_IMPORT_SYNTAX_ERROR
644
+ exception.name === "SyntaxError" &&
645
+ exception.code !== DYNAMIC_IMPORT_EXPORT_MISSING
553
646
  ) {
554
647
  // syntax error on inline script need line-1 for some reason
555
648
  fileUrlSite.line = fileUrlSite.line - 1;
@@ -588,14 +681,15 @@ window.__supervisor__ = (() => {
588
681
  return exception;
589
682
  };
590
683
 
591
- const stringifyStack = ({ name, message, stackTrace }) => {
592
- let stack;
684
+ const stringifyStack = ({ codeFrame, name, message, stackTrace }) => {
685
+ let stack = "";
686
+ if (codeFrame) {
687
+ stack += `${codeFrame}\n`;
688
+ }
593
689
  if (name && message) {
594
- stack = `${name}: ${message}`;
690
+ stack += `${name}: ${message}`;
595
691
  } else if (message) {
596
- stack = message;
597
- } else {
598
- stack = "";
692
+ stack += message;
599
693
  }
600
694
  if (stackTrace) {
601
695
  stack += `\n${stackTrace}`;
@@ -737,153 +831,6 @@ window.__supervisor__ = (() => {
737
831
  });
738
832
  };
739
833
 
740
- let formatError;
741
- error_formatter: {
742
- formatError = (exceptionInfo) => {
743
- const errorParts = {
744
- theme: "dark",
745
- title: "An error occured",
746
- text: "",
747
- tip: "",
748
- errorDetailsPromise: null,
749
- };
750
- const tips = [];
751
- tips.push("Click outside to close.");
752
- errorParts.tip = tips.join(`\n <br />\n `);
753
-
754
- const generateClickableText = (text) => {
755
- const textWithHtmlLinks = makeLinksClickable(text, {
756
- createLink: ({ url, line, column }) => {
757
- const urlSite = resolveUrlSite({ url, line, column });
758
- if (errorBaseUrl) {
759
- if (urlSite.url.startsWith(rootDirectoryUrl)) {
760
- urlSite.url = `${errorBaseUrl}${urlSite.url.slice(
761
- rootDirectoryUrl.length,
762
- )}`;
763
- } else {
764
- urlSite.url = "file:///mocked_for_snapshots";
765
- }
766
- }
767
- const urlWithLineAndColumn = stringifyUrlSite(urlSite);
768
- return {
769
- href:
770
- urlSite.url.startsWith("file:") && openInEditor
771
- ? `javascript:window.fetch('/__open_in_editor__/${encodeURIComponent(
772
- urlWithLineAndColumn,
773
- )}')`
774
- : urlSite.url,
775
- text: urlWithLineAndColumn,
776
- };
777
- },
778
- });
779
- return textWithHtmlLinks;
780
- };
781
-
782
- errorParts.text = stringifyStack({
783
- name: exceptionInfo.name,
784
- message: exceptionInfo.message
785
- ? generateClickableText(exceptionInfo.message)
786
- : "",
787
- stackTrace: exceptionInfo.stackTrace
788
- ? generateClickableText(exceptionInfo.stackTrace)
789
- : "",
790
- });
791
- if (exceptionInfo.site.url) {
792
- errorParts.errorDetailsPromise = (async () => {
793
- if (!serverIsJsenvDevServer) {
794
- return null;
795
- }
796
- try {
797
- if (
798
- exceptionInfo.code === DYNAMIC_IMPORT_FETCH_ERROR ||
799
- exceptionInfo.reportedBy === "script_error_event"
800
- ) {
801
- const response = await window.fetch(
802
- `/__get_error_cause__/${encodeURIComponent(
803
- exceptionInfo.site.isInline
804
- ? exceptionInfo.site.originalUrl
805
- : exceptionInfo.site.url,
806
- )}`,
807
- );
808
- if (response.status !== 200) {
809
- return null;
810
- }
811
- const causeInfo = await response.json();
812
- if (!causeInfo) {
813
- return null;
814
- }
815
- const causeText =
816
- causeInfo.code === "NOT_FOUND"
817
- ? stringifyStack({
818
- name: causeInfo.name,
819
- message: generateClickableText(causeInfo.reason),
820
- stackTrace: generateClickableText(causeInfo.codeFrame),
821
- })
822
- : stringifyStack({
823
- name: causeInfo.name,
824
- message: generateClickableText(causeInfo.stack),
825
- stackTrace: generateClickableText(causeInfo.codeFrame),
826
- });
827
- return {
828
- cause: causeText,
829
- };
830
- }
831
- if (exceptionInfo.site.line !== undefined) {
832
- const urlToFetch = new URL(
833
- `/__get_code_frame__/${encodeURIComponent(
834
- stringifyUrlSite(exceptionInfo.site),
835
- )}`,
836
- window.origin,
837
- );
838
- if (!exceptionInfo.stackSourcemapped) {
839
- urlToFetch.searchParams.set("remap", "");
840
- }
841
- const response = await window.fetch(urlToFetch);
842
- if (response.status !== 200) {
843
- return null;
844
- }
845
- const codeFrame = await response.text();
846
- return {
847
- codeFrame: generateClickableText(codeFrame),
848
- };
849
- }
850
- } catch (e) {
851
- // happens if server is closed for instance
852
- return null;
853
- }
854
- return null;
855
- })();
856
- }
857
- return errorParts;
858
- };
859
-
860
- const makeLinksClickable = (
861
- string,
862
- { createLink = ({ url }) => url },
863
- ) => {
864
- // normalize line breaks
865
- string = string.replace(/\n/g, "\n");
866
- string = escapeHtml(string);
867
- // render links
868
- string = replaceUrls(string, ({ url, line, column }) => {
869
- const { href, text } = createLink({ url, line, column });
870
- return link({ href, text });
871
- });
872
- return string;
873
- };
874
-
875
- const escapeHtml = (string) => {
876
- return string
877
- .replace(/&/g, "&amp;")
878
- .replace(/</g, "&lt;")
879
- .replace(/>/g, "&gt;")
880
- .replace(/"/g, "&quot;")
881
- .replace(/'/g, "&#039;");
882
- };
883
-
884
- const link = ({ href, text = href }) => `<a href="${href}">${text}</a>`;
885
- }
886
-
887
834
  let displayErrorNotification;
888
835
  error_notification: {
889
836
  const { Notification } = window;
@@ -928,51 +875,178 @@ window.__supervisor__ = (() => {
928
875
  };
929
876
 
930
877
  class JsenvErrorOverlay extends HTMLElement {
931
- constructor({ theme, title, text, tip, errorDetailsPromise }) {
878
+ constructor(exception) {
932
879
  super();
933
- this.root = this.attachShadow({ mode: "open" });
934
- this.root.innerHTML = `
880
+ const root = this.attachShadow({ mode: "open" });
881
+ const tips = [];
882
+ tips.push("Click outside to close.");
883
+ const tip = tips.join(`\n <br />\n `);
884
+ root.innerHTML = `
935
885
  <style>
936
886
  ${overlayCSS}
937
887
  </style>
938
888
  <div class="backdrop"></div>
939
- <div class="overlay" data-theme=${theme}>
889
+ <div class="overlay" data-theme="dark">
940
890
  <h1 class="title">
941
- ${title}
891
+ An error occured
942
892
  </h1>
943
- <pre class="text">${text}</pre>
893
+ <pre class="text"></pre>
944
894
  <div class="tip">
945
895
  ${tip}
946
896
  </div>
947
897
  </div>`;
948
- this.root.querySelector(".backdrop").onclick = () => {
898
+ root.querySelector(".backdrop").onclick = () => {
949
899
  if (!this.parentNode) {
950
900
  // not in document anymore
951
901
  return;
952
902
  }
953
- this.root.querySelector(".backdrop").onclick = null;
903
+ root.querySelector(".backdrop").onclick = null;
954
904
  this.parentNode.removeChild(this);
955
905
  };
956
- if (errorDetailsPromise) {
957
- errorDetailsPromise.then((errorDetails) => {
958
- if (!errorDetails || !this.parentNode) {
959
- return;
906
+
907
+ const renderException = () => {
908
+ const { cause = {} } = exception;
909
+ const { trace = {} } = cause;
910
+
911
+ root.querySelector(".text").innerHTML = stringifyStack({
912
+ codeFrame: trace.codeFrame
913
+ ? generateClickableText(trace.codeFrame)
914
+ : "",
915
+ name: exception.name,
916
+ message: exception.message
917
+ ? generateClickableText(exception.message)
918
+ : "",
919
+ stackTrace: exception.stackTrace
920
+ ? generateClickableText(exception.stackTrace)
921
+ : "",
922
+ });
923
+ if (cause) {
924
+ const causeText = stringifyStack({
925
+ name: cause.name,
926
+ message: cause.reason
927
+ ? generateClickableText(cause.reason)
928
+ : cause.stack
929
+ ? generateClickableText(cause.stack)
930
+ : "",
931
+ });
932
+ if (causeText) {
933
+ const causeTextIndented = prefixRemainingLines(causeText, " ");
934
+ root.querySelector(".text").innerHTML +=
935
+ `\n [cause]: ${causeTextIndented}`;
960
936
  }
961
- const { codeFrame, cause } = errorDetails;
962
- if (codeFrame) {
963
- this.root.querySelector(".text").innerHTML +=
964
- `\n\n${codeFrame}`;
937
+ }
938
+ if (
939
+ !exception.stackTrace &&
940
+ (exception.reportedBy === "script_error_event" ||
941
+ exception.reportedBy === "window_error_event" ||
942
+ exception.name === "SyntaxError" ||
943
+ exception.code === DYNAMIC_IMPORT_FETCH_ERROR ||
944
+ exception.code === DYNAMIC_IMPORT_EXPORT_MISSING ||
945
+ exception.code === DYNAMIC_IMPORT_SYNTAX_ERROR)
946
+ ) {
947
+ let traceSite = stringifyUrlSite(trace);
948
+ if (traceSite) {
949
+ root.querySelector(".text").innerHTML +=
950
+ `\n at ${generateClickableText(traceSite)}`;
965
951
  }
966
- if (cause) {
967
- const causeIndented = prefixRemainingLines(cause, " ");
968
- this.root.querySelector(".text").innerHTML +=
969
- `\n [cause]: ${causeIndented}`;
952
+ }
953
+ };
954
+ renderException();
955
+ if (exception.site.url && serverIsJsenvDevServer) {
956
+ (async () => {
957
+ try {
958
+ if (
959
+ exception.code === DYNAMIC_IMPORT_FETCH_ERROR ||
960
+ exception.reportedBy === "script_error_event"
961
+ ) {
962
+ const response = await window.fetch(
963
+ `/__get_error_cause__/${encodeURIComponent(
964
+ exception.site.isInline
965
+ ? exception.site.originalUrl
966
+ : exception.site.url,
967
+ )}`,
968
+ );
969
+ if (response.status !== 200) {
970
+ return;
971
+ }
972
+ const causeInfo = await response.json();
973
+ if (!causeInfo) {
974
+ return;
975
+ }
976
+ exception.cause = causeInfo;
977
+ renderException();
978
+ return;
979
+ }
980
+ if (exception.site.line !== undefined) {
981
+ const urlToFetch = new URL(
982
+ `/__get_cause_trace__/${encodeURIComponent(
983
+ stringifyUrlSite(exception.site),
984
+ )}`,
985
+ window.origin,
986
+ );
987
+ if (!exception.stackSourcemapped) {
988
+ urlToFetch.searchParams.set("remap", "");
989
+ }
990
+ const response = await window.fetch(urlToFetch);
991
+ if (response.status !== 200) {
992
+ return;
993
+ }
994
+ const causeTrace = await response.json();
995
+ exception.cause = {
996
+ trace: causeTrace,
997
+ };
998
+ renderException();
999
+ return;
1000
+ }
1001
+ } catch (e) {
1002
+ // happens if server is closed for instance
1003
+ return;
970
1004
  }
971
- });
1005
+ })();
972
1006
  }
973
1007
  }
974
1008
  }
975
-
1009
+ const generateClickableText = (text) => {
1010
+ const textWithHtmlLinks = makeLinksClickable(text, {
1011
+ createLink: ({ url, line, column }) => {
1012
+ const urlSite = resolveUrlSite({ url, line, column });
1013
+ if (errorBaseUrl) {
1014
+ if (urlSite.url.startsWith(rootDirectoryUrl)) {
1015
+ urlSite.url = `${errorBaseUrl}${urlSite.url.slice(
1016
+ rootDirectoryUrl.length,
1017
+ )}`;
1018
+ } else {
1019
+ urlSite.url = "file:///mocked_for_snapshots";
1020
+ }
1021
+ }
1022
+ const urlWithLineAndColumn = stringifyUrlSite(urlSite);
1023
+ return {
1024
+ href:
1025
+ urlSite.url.startsWith("file:") && openInEditor
1026
+ ? `javascript:window.fetch('/__open_in_editor__/${encodeURIComponent(
1027
+ urlWithLineAndColumn,
1028
+ )}')`
1029
+ : urlSite.url,
1030
+ text: urlWithLineAndColumn,
1031
+ };
1032
+ },
1033
+ });
1034
+ return textWithHtmlLinks;
1035
+ };
1036
+ const makeLinksClickable = (
1037
+ string,
1038
+ { createLink = ({ url }) => url },
1039
+ ) => {
1040
+ // normalize line breaks
1041
+ string = string.replace(/\r\n/g, "\n");
1042
+ string = escapeHtml(string);
1043
+ // render links
1044
+ string = replaceUrls(string, ({ url, line, column }) => {
1045
+ const { href, text } = createLink({ url, line, column });
1046
+ return link({ href, text });
1047
+ });
1048
+ return string;
1049
+ };
976
1050
  const prefixRemainingLines = (text, prefix) => {
977
1051
  const lines = text.split(/\r?\n/);
978
1052
  const firstLine = lines.shift();
@@ -985,6 +1059,15 @@ window.__supervisor__ = (() => {
985
1059
  }
986
1060
  return result;
987
1061
  };
1062
+ const escapeHtml = (string) => {
1063
+ return string
1064
+ .replace(/&/g, "&amp;")
1065
+ .replace(/</g, "&lt;")
1066
+ .replace(/>/g, "&gt;")
1067
+ .replace(/"/g, "&quot;")
1068
+ .replace(/'/g, "&#039;");
1069
+ };
1070
+ const link = ({ href, text = href }) => `<a href="${href}">${text}</a>`;
988
1071
 
989
1072
  if (customElements && !customElements.get(JSENV_ERROR_OVERLAY_TAGNAME)) {
990
1073
  customElements.define(JSENV_ERROR_OVERLAY_TAGNAME, JsenvErrorOverlay);
@@ -1069,17 +1152,8 @@ window.__supervisor__ = (() => {
1069
1152
 
1070
1153
  supervisor.createException = createException;
1071
1154
  supervisor.reportException = (exception) => {
1072
- const { theme, title, text, tip, errorDetailsPromise } =
1073
- formatError(exception);
1074
-
1075
1155
  if (errorOverlay) {
1076
- const removeErrorOverlay = displayJsenvErrorOverlay({
1077
- theme,
1078
- title,
1079
- text,
1080
- tip,
1081
- errorDetailsPromise,
1082
- });
1156
+ const removeErrorOverlay = displayJsenvErrorOverlay(exception);
1083
1157
  if (window.__reloader__) {
1084
1158
  const onchange = window.__reloader__.status.onchange;
1085
1159
  window.__reloader__.status.onchange = () => {
@@ -1092,8 +1166,8 @@ window.__supervisor__ = (() => {
1092
1166
  }
1093
1167
  if (errorNotification) {
1094
1168
  displayErrorNotification({
1095
- title,
1096
- text,
1169
+ title: "An error occured",
1170
+ text: "todo",
1097
1171
  });
1098
1172
  }
1099
1173
  return exception;
@@ -1114,6 +1188,7 @@ window.__supervisor__ = (() => {
1114
1188
  // when error is reported within a worker error is null
1115
1189
  // but there is a message property on errorEvent
1116
1190
  reportedBy: "window_error_event",
1191
+ message,
1117
1192
  url: filename,
1118
1193
  line: lineno,
1119
1194
  column: colno,
@@ -1159,7 +1234,7 @@ window.__supervisor__ = (() => {
1159
1234
  resolve({
1160
1235
  detectedBy: "window_error_event",
1161
1236
  failed: true,
1162
- error: errorEvent,
1237
+ errorEvent,
1163
1238
  });
1164
1239
  }
1165
1240
  };
@@ -1172,7 +1247,7 @@ window.__supervisor__ = (() => {
1172
1247
  resolve({
1173
1248
  detectedBy: "script_error_event",
1174
1249
  failed: true,
1175
- error: errorEvent,
1250
+ errorEvent,
1176
1251
  });
1177
1252
  });
1178
1253
  script.addEventListener("load", () => {