@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.
- package/dist/js/supervisor.js +326 -268
- package/dist/jsenv_plugin_supervisor.js +118 -139
- package/package.json +4 -4
- package/src/client/supervisor.js +349 -274
- package/src/jsenv_plugin_supervisor.js +16 -10
package/dist/js/supervisor.js
CHANGED
|
@@ -11,13 +11,17 @@ window.__supervisor__ = (() => {
|
|
|
11
11
|
};
|
|
12
12
|
const isWebkitOrSafari = typeof window.webkitConvertPointFromNodeToPage === "function";
|
|
13
13
|
const executionResults = {};
|
|
14
|
-
let
|
|
14
|
+
let documentTimingsOrigin;
|
|
15
15
|
try {
|
|
16
|
-
|
|
16
|
+
documentTimingsOrigin = window.performance.timing.navigationStart;
|
|
17
17
|
} catch (e) {
|
|
18
|
-
|
|
18
|
+
documentTimingsOrigin = Date.now();
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
const documentTimings = {
|
|
21
|
+
origin: documentTimingsOrigin,
|
|
22
|
+
start: Date.now() - documentTimingsOrigin,
|
|
23
|
+
end: null
|
|
24
|
+
};
|
|
21
25
|
supervisor.setup = ({
|
|
22
26
|
rootDirectoryUrl,
|
|
23
27
|
scriptInfos,
|
|
@@ -76,10 +80,13 @@ window.__supervisor__ = (() => {
|
|
|
76
80
|
const createExecutionController = (src, type) => {
|
|
77
81
|
const result = {
|
|
78
82
|
status: "pending",
|
|
79
|
-
duration: null,
|
|
80
83
|
coverage: null,
|
|
81
84
|
exception: null,
|
|
82
|
-
value: null
|
|
85
|
+
value: null,
|
|
86
|
+
timings: {
|
|
87
|
+
start: null,
|
|
88
|
+
end: null
|
|
89
|
+
}
|
|
83
90
|
};
|
|
84
91
|
let resolve;
|
|
85
92
|
const promise = new Promise(_resolve => {
|
|
@@ -88,7 +95,7 @@ window.__supervisor__ = (() => {
|
|
|
88
95
|
promises.push(promise);
|
|
89
96
|
executionResults[src] = result;
|
|
90
97
|
const start = () => {
|
|
91
|
-
result.
|
|
98
|
+
result.timings.start = Date.now() - documentTimingsOrigin;
|
|
92
99
|
result.coverage = null;
|
|
93
100
|
result.status = "started";
|
|
94
101
|
result.exception = null;
|
|
@@ -97,16 +104,15 @@ window.__supervisor__ = (() => {
|
|
|
97
104
|
}
|
|
98
105
|
};
|
|
99
106
|
const end = () => {
|
|
100
|
-
const now = Date.now();
|
|
101
107
|
remainingScriptCount--;
|
|
102
|
-
result.
|
|
108
|
+
result.timings.end = Date.now() - documentTimingsOrigin;
|
|
103
109
|
result.coverage = window.__coverage__;
|
|
104
110
|
if (logs) {
|
|
105
111
|
console.log("execution ".concat(result.status));
|
|
106
112
|
console.groupEnd();
|
|
107
113
|
}
|
|
108
114
|
if (remainingScriptCount === 0) {
|
|
109
|
-
|
|
115
|
+
documentTimings.end = Date.now() - documentTimingsOrigin;
|
|
110
116
|
}
|
|
111
117
|
resolve();
|
|
112
118
|
};
|
|
@@ -163,17 +169,27 @@ window.__supervisor__ = (() => {
|
|
|
163
169
|
const {
|
|
164
170
|
detectedBy,
|
|
165
171
|
failed,
|
|
166
|
-
|
|
172
|
+
errorEvent
|
|
167
173
|
} = await scriptLoadPromise;
|
|
168
174
|
if (failed) {
|
|
175
|
+
const messageDefault = "Error while loading script";
|
|
176
|
+
const {
|
|
177
|
+
error,
|
|
178
|
+
message,
|
|
179
|
+
filename,
|
|
180
|
+
lineno,
|
|
181
|
+
colno
|
|
182
|
+
} = errorEvent;
|
|
169
183
|
if (detectedBy === "script_error_event") {
|
|
170
184
|
// window.error won't be dispatched for this error
|
|
171
|
-
reportErrorBackToBrowser(error);
|
|
185
|
+
reportErrorBackToBrowser(error || errorEvent);
|
|
172
186
|
}
|
|
173
|
-
fail(error, {
|
|
174
|
-
message:
|
|
187
|
+
fail(error || message || messageDefault, {
|
|
188
|
+
message: messageDefault,
|
|
175
189
|
reportedBy: "script_error_event",
|
|
176
|
-
url: urlObject.href
|
|
190
|
+
url: filename || urlObject.href,
|
|
191
|
+
line: lineno,
|
|
192
|
+
column: colno
|
|
177
193
|
});
|
|
178
194
|
if (detectedBy === "script_error_event") {
|
|
179
195
|
supervisor.reportException(result.exception);
|
|
@@ -236,7 +252,7 @@ window.__supervisor__ = (() => {
|
|
|
236
252
|
return result;
|
|
237
253
|
} catch (e) {
|
|
238
254
|
fail(e, {
|
|
239
|
-
message: "Error while importing module
|
|
255
|
+
message: "Error while importing module",
|
|
240
256
|
reportedBy: "dynamic_import",
|
|
241
257
|
url: urlObject.href
|
|
242
258
|
});
|
|
@@ -289,16 +305,26 @@ window.__supervisor__ = (() => {
|
|
|
289
305
|
const {
|
|
290
306
|
detectedBy,
|
|
291
307
|
failed,
|
|
292
|
-
|
|
308
|
+
errorEvent
|
|
293
309
|
} = await scriptLoadResultPromise;
|
|
294
310
|
if (failed) {
|
|
311
|
+
const messageDefault = "Error while loading module";
|
|
312
|
+
const {
|
|
313
|
+
error,
|
|
314
|
+
message,
|
|
315
|
+
filename,
|
|
316
|
+
lineno,
|
|
317
|
+
colno
|
|
318
|
+
} = errorEvent;
|
|
295
319
|
// if (detectedBy === "script_error_event") {
|
|
296
320
|
// reportErrorBackToBrowser(error)
|
|
297
321
|
// }
|
|
298
|
-
fail(error, {
|
|
299
|
-
message:
|
|
322
|
+
fail(error || message || messageDefault, {
|
|
323
|
+
message: messageDefault,
|
|
300
324
|
reportedBy: "script_error_event",
|
|
301
|
-
url: urlObject.href
|
|
325
|
+
url: filename || urlObject.href,
|
|
326
|
+
line: lineno,
|
|
327
|
+
column: colno
|
|
302
328
|
});
|
|
303
329
|
if (detectedBy === "script_error_event") {
|
|
304
330
|
supervisor.reportException(result.exception);
|
|
@@ -420,8 +446,7 @@ window.__supervisor__ = (() => {
|
|
|
420
446
|
supervisor.getDocumentExecutionResult = async () => {
|
|
421
447
|
await Promise.all(promises);
|
|
422
448
|
return {
|
|
423
|
-
|
|
424
|
-
endTime: documentExecutionEndTime,
|
|
449
|
+
timings: documentTimings,
|
|
425
450
|
status: "completed",
|
|
426
451
|
executionResults
|
|
427
452
|
};
|
|
@@ -471,10 +496,11 @@ window.__supervisor__ = (() => {
|
|
|
471
496
|
// the stack from runtime, not normalized to v8
|
|
472
497
|
stackTrace: "",
|
|
473
498
|
// the stack trace (without error name and message)
|
|
499
|
+
stackFrames: undefined,
|
|
474
500
|
withServerUrls: {
|
|
475
501
|
message: "",
|
|
476
|
-
|
|
477
|
-
|
|
502
|
+
stack: "",
|
|
503
|
+
stackTrace: ""
|
|
478
504
|
},
|
|
479
505
|
meta: null,
|
|
480
506
|
site: {
|
|
@@ -498,76 +524,140 @@ window.__supervisor__ = (() => {
|
|
|
498
524
|
exception.message = reason;
|
|
499
525
|
return;
|
|
500
526
|
}
|
|
501
|
-
if (reason
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
527
|
+
if (typeof reason !== "object") {
|
|
528
|
+
exception.message = JSON.stringify(reason);
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
// isError can be false when reason is an ErrorEvent for instance
|
|
532
|
+
exception.isError = reason instanceof Error;
|
|
533
|
+
exception.name = reason.name || "Error";
|
|
534
|
+
exception.message = reason.message || message || "";
|
|
535
|
+
let stackFrames;
|
|
536
|
+
if (exception.isError && Error.captureStackTrace &&
|
|
537
|
+
// captureStackTrace exists on webkit but error.stack is not v8
|
|
538
|
+
!isWebkitOrSafari) {
|
|
539
|
+
// stackTrace formatted by V8
|
|
540
|
+
const {
|
|
541
|
+
prepareStackTrace
|
|
542
|
+
} = Error;
|
|
543
|
+
Error.prepareStackTrace = (e, callSites) => {
|
|
544
|
+
Error.prepareStackTrace = prepareStackTrace;
|
|
545
|
+
const getPropertiesFromEvalOrigin = origin => {
|
|
546
|
+
// Most eval() calls are in this format
|
|
547
|
+
const topLevelEvalMatch = /^eval at ([^(]+) \((.+):(\d+):(\d+)\)$/.exec(origin);
|
|
548
|
+
if (topLevelEvalMatch) {
|
|
549
|
+
const source = topLevelEvalMatch[2];
|
|
550
|
+
const line = Number(topLevelEvalMatch[3]);
|
|
551
|
+
const column = topLevelEvalMatch[4] - 1;
|
|
552
|
+
return {
|
|
553
|
+
url: source,
|
|
554
|
+
line,
|
|
555
|
+
column
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
// Parse nested eval() calls using recursion
|
|
559
|
+
const nestedEvalMatch = /^eval at ([^(]+) \((.+)\)$/.exec(origin);
|
|
560
|
+
if (nestedEvalMatch) {
|
|
561
|
+
return getPropertiesFromEvalOrigin(nestedEvalMatch[2]);
|
|
562
|
+
}
|
|
563
|
+
return null;
|
|
564
|
+
};
|
|
565
|
+
stackFrames = [];
|
|
566
|
+
for (const callSite of callSites) {
|
|
567
|
+
const url = callSite.getFileName() || callSite.getScriptNameOrSourceURL();
|
|
568
|
+
const line = callSite.getLineNumber();
|
|
569
|
+
const column = callSite.getColumnNumber();
|
|
570
|
+
const site = resolveUrlSite({
|
|
571
|
+
url,
|
|
572
|
+
line,
|
|
573
|
+
column
|
|
574
|
+
});
|
|
575
|
+
const stackFrame = {
|
|
576
|
+
raw: " at ".concat(String(callSite)),
|
|
577
|
+
url: site.url,
|
|
578
|
+
line: site.line,
|
|
579
|
+
column: site.column,
|
|
580
|
+
functionName: callSite.getFunctionName(),
|
|
581
|
+
isNative: callSite.isNative(),
|
|
582
|
+
isEval: callSite.isEval(),
|
|
583
|
+
isConstructor: callSite.isConstructor(),
|
|
584
|
+
isAsync: callSite.isAsync(),
|
|
585
|
+
evalSite: null
|
|
586
|
+
};
|
|
587
|
+
if (stackFrame.isEval) {
|
|
588
|
+
const evalOrigin = stackFrame.getEvalOrigin();
|
|
589
|
+
if (evalOrigin) {
|
|
590
|
+
stackFrame.evalSite = getPropertiesFromEvalOrigin(evalOrigin);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
stackFrames.push(stackFrame);
|
|
536
594
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
595
|
+
let stackTrace = "";
|
|
596
|
+
for (const stackFrame of stackFrames) {
|
|
597
|
+
if (stackTrace) stackTrace += "\n";
|
|
598
|
+
stackTrace += stackFrame.raw;
|
|
541
599
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
600
|
+
exception.stackTrace = stackTrace;
|
|
601
|
+
let stack = "";
|
|
602
|
+
const name = reason.name || "Error";
|
|
603
|
+
const message = reason.message || "";
|
|
604
|
+
stack += "".concat(name, ": ").concat(message);
|
|
605
|
+
if (stackTrace) {
|
|
606
|
+
stack += "\n".concat(stackTrace);
|
|
545
607
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
608
|
+
return stack;
|
|
609
|
+
};
|
|
610
|
+
exception.stackSourcemapped = true;
|
|
611
|
+
exception.stack = reason.stack;
|
|
612
|
+
if (stackFrames === undefined) {
|
|
613
|
+
// Error.prepareStackTrace not trigerred
|
|
614
|
+
// - reason is not an error
|
|
615
|
+
// - reason.stack already get
|
|
616
|
+
Error.prepareStackTrace = prepareStackTrace;
|
|
617
|
+
exception.stackTrace = getErrorStackTrace(reason);
|
|
618
|
+
} else {
|
|
619
|
+
exception.stackFrames = stackFrames;
|
|
620
|
+
const [firstCallFrame] = stackFrames;
|
|
621
|
+
if (exception.site.url === null && firstCallFrame && firstCallFrame.url) {
|
|
622
|
+
Object.assign(exception.site, {
|
|
623
|
+
url: firstCallFrame.url,
|
|
624
|
+
line: firstCallFrame.line,
|
|
625
|
+
column: firstCallFrame.column
|
|
626
|
+
});
|
|
551
627
|
}
|
|
552
628
|
}
|
|
553
|
-
|
|
629
|
+
} else {
|
|
630
|
+
exception.stackSourcemapped = false;
|
|
631
|
+
exception.stackTrace = reason.stack;
|
|
632
|
+
exception.stack = stringifyStack(exception);
|
|
554
633
|
}
|
|
555
|
-
if (
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
634
|
+
if (exception.site.url === null && reason.url) {
|
|
635
|
+
Object.assign(exception.site, resolveUrlSite({
|
|
636
|
+
url: reason.url
|
|
637
|
+
}));
|
|
638
|
+
}
|
|
639
|
+
{
|
|
640
|
+
// chrome
|
|
641
|
+
if (exception.message.includes("does not provide an export named")) {
|
|
642
|
+
exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
|
|
562
643
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
644
|
+
// firefox
|
|
645
|
+
if (exception.message.startsWith("import not found:") || exception.message.startsWith("ambiguous indirect export:")) {
|
|
646
|
+
exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
|
|
647
|
+
}
|
|
648
|
+
// safari
|
|
649
|
+
if (exception.message.startsWith("import binding name")) {
|
|
650
|
+
exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
|
|
651
|
+
}
|
|
652
|
+
if (exception.message.includes("Importing a module script failed")) {
|
|
653
|
+
exception.code = DYNAMIC_IMPORT_FETCH_ERROR;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
{
|
|
657
|
+
if (!exception.code && exception.name === "SyntaxError" && typeof line === "number") {
|
|
658
|
+
exception.code = DYNAMIC_IMPORT_SYNTAX_ERROR;
|
|
567
659
|
}
|
|
568
|
-
return;
|
|
569
660
|
}
|
|
570
|
-
exception.message = JSON.stringify(reason);
|
|
571
661
|
};
|
|
572
662
|
writeBasicProperties();
|
|
573
663
|
|
|
@@ -584,7 +674,7 @@ window.__supervisor__ = (() => {
|
|
|
584
674
|
line,
|
|
585
675
|
column
|
|
586
676
|
});
|
|
587
|
-
if (fileUrlSite.isInline && exception.
|
|
677
|
+
if (fileUrlSite.isInline && exception.name === "SyntaxError" && exception.code !== DYNAMIC_IMPORT_EXPORT_MISSING) {
|
|
588
678
|
// syntax error on inline script need line-1 for some reason
|
|
589
679
|
fileUrlSite.line = fileUrlSite.line - 1;
|
|
590
680
|
}
|
|
@@ -617,17 +707,19 @@ window.__supervisor__ = (() => {
|
|
|
617
707
|
return exception;
|
|
618
708
|
};
|
|
619
709
|
const stringifyStack = ({
|
|
710
|
+
codeFrame,
|
|
620
711
|
name,
|
|
621
712
|
message,
|
|
622
713
|
stackTrace
|
|
623
714
|
}) => {
|
|
624
|
-
let stack;
|
|
715
|
+
let stack = "";
|
|
716
|
+
if (codeFrame) {
|
|
717
|
+
stack += "".concat(codeFrame, "\n");
|
|
718
|
+
}
|
|
625
719
|
if (name && message) {
|
|
626
|
-
stack
|
|
720
|
+
stack += "".concat(name, ": ").concat(message);
|
|
627
721
|
} else if (message) {
|
|
628
|
-
stack
|
|
629
|
-
} else {
|
|
630
|
-
stack = "";
|
|
722
|
+
stack += message;
|
|
631
723
|
}
|
|
632
724
|
if (stackTrace) {
|
|
633
725
|
stack += "\n".concat(stackTrace);
|
|
@@ -764,140 +856,6 @@ window.__supervisor__ = (() => {
|
|
|
764
856
|
return replacement;
|
|
765
857
|
});
|
|
766
858
|
};
|
|
767
|
-
let formatError;
|
|
768
|
-
{
|
|
769
|
-
formatError = exceptionInfo => {
|
|
770
|
-
const errorParts = {
|
|
771
|
-
theme: "dark",
|
|
772
|
-
title: "An error occured",
|
|
773
|
-
text: "",
|
|
774
|
-
tip: "",
|
|
775
|
-
errorDetailsPromise: null
|
|
776
|
-
};
|
|
777
|
-
const tips = [];
|
|
778
|
-
tips.push("Click outside to close.");
|
|
779
|
-
errorParts.tip = tips.join("\n <br />\n ");
|
|
780
|
-
const generateClickableText = text => {
|
|
781
|
-
const textWithHtmlLinks = makeLinksClickable(text, {
|
|
782
|
-
createLink: ({
|
|
783
|
-
url,
|
|
784
|
-
line,
|
|
785
|
-
column
|
|
786
|
-
}) => {
|
|
787
|
-
const urlSite = resolveUrlSite({
|
|
788
|
-
url,
|
|
789
|
-
line,
|
|
790
|
-
column
|
|
791
|
-
});
|
|
792
|
-
if (errorBaseUrl) {
|
|
793
|
-
if (urlSite.url.startsWith(rootDirectoryUrl)) {
|
|
794
|
-
urlSite.url = "".concat(errorBaseUrl).concat(urlSite.url.slice(rootDirectoryUrl.length));
|
|
795
|
-
} else {
|
|
796
|
-
urlSite.url = "file:///mocked_for_snapshots";
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
const urlWithLineAndColumn = stringifyUrlSite(urlSite);
|
|
800
|
-
return {
|
|
801
|
-
href: urlSite.url.startsWith("file:") && openInEditor ? "javascript:window.fetch('/__open_in_editor__/".concat(encodeURIComponent(urlWithLineAndColumn), "')") : urlSite.url,
|
|
802
|
-
text: urlWithLineAndColumn
|
|
803
|
-
};
|
|
804
|
-
}
|
|
805
|
-
});
|
|
806
|
-
return textWithHtmlLinks;
|
|
807
|
-
};
|
|
808
|
-
errorParts.text = stringifyStack({
|
|
809
|
-
name: exceptionInfo.name,
|
|
810
|
-
message: exceptionInfo.message ? generateClickableText(exceptionInfo.message) : "",
|
|
811
|
-
stackTrace: exceptionInfo.stackTrace ? generateClickableText(exceptionInfo.stackTrace) : ""
|
|
812
|
-
});
|
|
813
|
-
if (exceptionInfo.site.url) {
|
|
814
|
-
errorParts.errorDetailsPromise = (async () => {
|
|
815
|
-
if (!serverIsJsenvDevServer) {
|
|
816
|
-
return null;
|
|
817
|
-
}
|
|
818
|
-
try {
|
|
819
|
-
if (exceptionInfo.code === DYNAMIC_IMPORT_FETCH_ERROR || exceptionInfo.reportedBy === "script_error_event") {
|
|
820
|
-
const response = await window.fetch("/__get_error_cause__/".concat(encodeURIComponent(exceptionInfo.site.isInline ? exceptionInfo.site.originalUrl : exceptionInfo.site.url)));
|
|
821
|
-
if (response.status !== 200) {
|
|
822
|
-
return null;
|
|
823
|
-
}
|
|
824
|
-
const causeInfo = await response.json();
|
|
825
|
-
if (!causeInfo) {
|
|
826
|
-
return null;
|
|
827
|
-
}
|
|
828
|
-
const causeText = causeInfo.code === "NOT_FOUND" ? stringifyStack({
|
|
829
|
-
name: causeInfo.name,
|
|
830
|
-
message: generateClickableText(causeInfo.reason),
|
|
831
|
-
stackTrace: generateClickableText(causeInfo.codeFrame)
|
|
832
|
-
}) : stringifyStack({
|
|
833
|
-
name: causeInfo.name,
|
|
834
|
-
message: generateClickableText(causeInfo.stack),
|
|
835
|
-
stackTrace: generateClickableText(causeInfo.codeFrame)
|
|
836
|
-
});
|
|
837
|
-
return {
|
|
838
|
-
cause: causeText
|
|
839
|
-
};
|
|
840
|
-
}
|
|
841
|
-
if (exceptionInfo.site.line !== undefined) {
|
|
842
|
-
const urlToFetch = new URL("/__get_code_frame__/".concat(encodeURIComponent(stringifyUrlSite(exceptionInfo.site))), window.origin);
|
|
843
|
-
if (!exceptionInfo.stackSourcemapped) {
|
|
844
|
-
urlToFetch.searchParams.set("remap", "");
|
|
845
|
-
}
|
|
846
|
-
const response = await window.fetch(urlToFetch);
|
|
847
|
-
if (response.status !== 200) {
|
|
848
|
-
return null;
|
|
849
|
-
}
|
|
850
|
-
const codeFrame = await response.text();
|
|
851
|
-
return {
|
|
852
|
-
codeFrame: generateClickableText(codeFrame)
|
|
853
|
-
};
|
|
854
|
-
}
|
|
855
|
-
} catch (e) {
|
|
856
|
-
// happens if server is closed for instance
|
|
857
|
-
return null;
|
|
858
|
-
}
|
|
859
|
-
return null;
|
|
860
|
-
})();
|
|
861
|
-
}
|
|
862
|
-
return errorParts;
|
|
863
|
-
};
|
|
864
|
-
const makeLinksClickable = (string, {
|
|
865
|
-
createLink = ({
|
|
866
|
-
url
|
|
867
|
-
}) => url
|
|
868
|
-
}) => {
|
|
869
|
-
// normalize line breaks
|
|
870
|
-
string = string.replace(/\n/g, "\n");
|
|
871
|
-
string = escapeHtml(string);
|
|
872
|
-
// render links
|
|
873
|
-
string = replaceUrls(string, ({
|
|
874
|
-
url,
|
|
875
|
-
line,
|
|
876
|
-
column
|
|
877
|
-
}) => {
|
|
878
|
-
const {
|
|
879
|
-
href,
|
|
880
|
-
text
|
|
881
|
-
} = createLink({
|
|
882
|
-
url,
|
|
883
|
-
line,
|
|
884
|
-
column
|
|
885
|
-
});
|
|
886
|
-
return link({
|
|
887
|
-
href,
|
|
888
|
-
text
|
|
889
|
-
});
|
|
890
|
-
});
|
|
891
|
-
return string;
|
|
892
|
-
};
|
|
893
|
-
const escapeHtml = string => {
|
|
894
|
-
return string.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
895
|
-
};
|
|
896
|
-
const link = ({
|
|
897
|
-
href,
|
|
898
|
-
text = href
|
|
899
|
-
}) => "<a href=\"".concat(href, "\">").concat(text, "</a>");
|
|
900
|
-
}
|
|
901
859
|
let displayErrorNotification;
|
|
902
860
|
{
|
|
903
861
|
const {
|
|
@@ -941,46 +899,151 @@ window.__supervisor__ = (() => {
|
|
|
941
899
|
return removeErrorOverlay;
|
|
942
900
|
};
|
|
943
901
|
class JsenvErrorOverlay extends HTMLElement {
|
|
944
|
-
constructor({
|
|
945
|
-
theme,
|
|
946
|
-
title,
|
|
947
|
-
text,
|
|
948
|
-
tip,
|
|
949
|
-
errorDetailsPromise
|
|
950
|
-
}) {
|
|
902
|
+
constructor(exception) {
|
|
951
903
|
super();
|
|
952
|
-
|
|
904
|
+
const root = this.attachShadow({
|
|
953
905
|
mode: "open"
|
|
954
906
|
});
|
|
955
|
-
|
|
956
|
-
|
|
907
|
+
const tips = [];
|
|
908
|
+
tips.push("Click outside to close.");
|
|
909
|
+
const tip = tips.join("\n <br />\n ");
|
|
910
|
+
root.innerHTML = "\n<style>\n ".concat(overlayCSS, "\n</style>\n<div class=\"backdrop\"></div>\n<div class=\"overlay\" data-theme=\"dark\">\n <h1 class=\"title\">\n An error occured\n </h1>\n <pre class=\"text\"></pre>\n <div class=\"tip\">\n ").concat(tip, "\n </div>\n</div>");
|
|
911
|
+
root.querySelector(".backdrop").onclick = () => {
|
|
957
912
|
if (!this.parentNode) {
|
|
958
913
|
// not in document anymore
|
|
959
914
|
return;
|
|
960
915
|
}
|
|
961
|
-
|
|
916
|
+
root.querySelector(".backdrop").onclick = null;
|
|
962
917
|
this.parentNode.removeChild(this);
|
|
963
918
|
};
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
919
|
+
const renderException = () => {
|
|
920
|
+
const {
|
|
921
|
+
cause = {}
|
|
922
|
+
} = exception;
|
|
923
|
+
const {
|
|
924
|
+
trace = {}
|
|
925
|
+
} = cause;
|
|
926
|
+
root.querySelector(".text").innerHTML = stringifyStack({
|
|
927
|
+
codeFrame: trace.codeFrame ? generateClickableText(trace.codeFrame) : "",
|
|
928
|
+
name: exception.name,
|
|
929
|
+
message: exception.message ? generateClickableText(exception.message) : "",
|
|
930
|
+
stackTrace: exception.stackTrace ? generateClickableText(exception.stackTrace) : ""
|
|
931
|
+
});
|
|
932
|
+
if (cause) {
|
|
933
|
+
const causeText = stringifyStack({
|
|
934
|
+
name: cause.name,
|
|
935
|
+
message: cause.reason ? generateClickableText(cause.reason) : cause.stack ? generateClickableText(cause.stack) : ""
|
|
936
|
+
});
|
|
937
|
+
if (causeText) {
|
|
938
|
+
const causeTextIndented = prefixRemainingLines(causeText, " ");
|
|
939
|
+
root.querySelector(".text").innerHTML += "\n [cause]: ".concat(causeTextIndented);
|
|
968
940
|
}
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
this.root.querySelector(".text").innerHTML += "\n\n".concat(codeFrame);
|
|
941
|
+
}
|
|
942
|
+
if (!exception.stackTrace && (exception.reportedBy === "script_error_event" || exception.reportedBy === "window_error_event" || exception.name === "SyntaxError" || exception.code === DYNAMIC_IMPORT_FETCH_ERROR || exception.code === DYNAMIC_IMPORT_EXPORT_MISSING || exception.code === DYNAMIC_IMPORT_SYNTAX_ERROR)) {
|
|
943
|
+
let traceSite = stringifyUrlSite(trace);
|
|
944
|
+
if (traceSite) {
|
|
945
|
+
root.querySelector(".text").innerHTML += "\n at ".concat(generateClickableText(traceSite));
|
|
975
946
|
}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
947
|
+
}
|
|
948
|
+
};
|
|
949
|
+
renderException();
|
|
950
|
+
if (exception.site.url && serverIsJsenvDevServer) {
|
|
951
|
+
(async () => {
|
|
952
|
+
try {
|
|
953
|
+
if (exception.code === DYNAMIC_IMPORT_FETCH_ERROR || exception.reportedBy === "script_error_event") {
|
|
954
|
+
const response = await window.fetch("/__get_error_cause__/".concat(encodeURIComponent(exception.site.isInline ? exception.site.originalUrl : exception.site.url)));
|
|
955
|
+
if (response.status !== 200) {
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
const causeInfo = await response.json();
|
|
959
|
+
if (!causeInfo) {
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
exception.cause = causeInfo;
|
|
963
|
+
renderException();
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
if (exception.site.line !== undefined) {
|
|
967
|
+
const urlToFetch = new URL("/__get_cause_trace__/".concat(encodeURIComponent(stringifyUrlSite(exception.site))), window.origin);
|
|
968
|
+
if (!exception.stackSourcemapped) {
|
|
969
|
+
urlToFetch.searchParams.set("remap", "");
|
|
970
|
+
}
|
|
971
|
+
const response = await window.fetch(urlToFetch);
|
|
972
|
+
if (response.status !== 200) {
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
const causeTrace = await response.json();
|
|
976
|
+
exception.cause = {
|
|
977
|
+
trace: causeTrace
|
|
978
|
+
};
|
|
979
|
+
renderException();
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
} catch (e) {
|
|
983
|
+
// happens if server is closed for instance
|
|
984
|
+
return;
|
|
979
985
|
}
|
|
980
|
-
});
|
|
986
|
+
})();
|
|
981
987
|
}
|
|
982
988
|
}
|
|
983
989
|
}
|
|
990
|
+
const generateClickableText = text => {
|
|
991
|
+
const textWithHtmlLinks = makeLinksClickable(text, {
|
|
992
|
+
createLink: ({
|
|
993
|
+
url,
|
|
994
|
+
line,
|
|
995
|
+
column
|
|
996
|
+
}) => {
|
|
997
|
+
const urlSite = resolveUrlSite({
|
|
998
|
+
url,
|
|
999
|
+
line,
|
|
1000
|
+
column
|
|
1001
|
+
});
|
|
1002
|
+
if (errorBaseUrl) {
|
|
1003
|
+
if (urlSite.url.startsWith(rootDirectoryUrl)) {
|
|
1004
|
+
urlSite.url = "".concat(errorBaseUrl).concat(urlSite.url.slice(rootDirectoryUrl.length));
|
|
1005
|
+
} else {
|
|
1006
|
+
urlSite.url = "file:///mocked_for_snapshots";
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
const urlWithLineAndColumn = stringifyUrlSite(urlSite);
|
|
1010
|
+
return {
|
|
1011
|
+
href: urlSite.url.startsWith("file:") && openInEditor ? "javascript:window.fetch('/__open_in_editor__/".concat(encodeURIComponent(urlWithLineAndColumn), "')") : urlSite.url,
|
|
1012
|
+
text: urlWithLineAndColumn
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
});
|
|
1016
|
+
return textWithHtmlLinks;
|
|
1017
|
+
};
|
|
1018
|
+
const makeLinksClickable = (string, {
|
|
1019
|
+
createLink = ({
|
|
1020
|
+
url
|
|
1021
|
+
}) => url
|
|
1022
|
+
}) => {
|
|
1023
|
+
// normalize line breaks
|
|
1024
|
+
string = string.replace(/\r\n/g, "\n");
|
|
1025
|
+
string = escapeHtml(string);
|
|
1026
|
+
// render links
|
|
1027
|
+
string = replaceUrls(string, ({
|
|
1028
|
+
url,
|
|
1029
|
+
line,
|
|
1030
|
+
column
|
|
1031
|
+
}) => {
|
|
1032
|
+
const {
|
|
1033
|
+
href,
|
|
1034
|
+
text
|
|
1035
|
+
} = createLink({
|
|
1036
|
+
url,
|
|
1037
|
+
line,
|
|
1038
|
+
column
|
|
1039
|
+
});
|
|
1040
|
+
return link({
|
|
1041
|
+
href,
|
|
1042
|
+
text
|
|
1043
|
+
});
|
|
1044
|
+
});
|
|
1045
|
+
return string;
|
|
1046
|
+
};
|
|
984
1047
|
const prefixRemainingLines = (text, prefix) => {
|
|
985
1048
|
const lines = text.split(/\r?\n/);
|
|
986
1049
|
const firstLine = lines.shift();
|
|
@@ -993,6 +1056,13 @@ window.__supervisor__ = (() => {
|
|
|
993
1056
|
}
|
|
994
1057
|
return result;
|
|
995
1058
|
};
|
|
1059
|
+
const escapeHtml = string => {
|
|
1060
|
+
return string.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1061
|
+
};
|
|
1062
|
+
const link = ({
|
|
1063
|
+
href,
|
|
1064
|
+
text = href
|
|
1065
|
+
}) => "<a href=\"".concat(href, "\">").concat(text, "</a>");
|
|
996
1066
|
if (customElements && !customElements.get(JSENV_ERROR_OVERLAY_TAGNAME)) {
|
|
997
1067
|
customElements.define(JSENV_ERROR_OVERLAY_TAGNAME, JsenvErrorOverlay);
|
|
998
1068
|
}
|
|
@@ -1000,21 +1070,8 @@ window.__supervisor__ = (() => {
|
|
|
1000
1070
|
}
|
|
1001
1071
|
supervisor.createException = createException;
|
|
1002
1072
|
supervisor.reportException = exception => {
|
|
1003
|
-
const {
|
|
1004
|
-
theme,
|
|
1005
|
-
title,
|
|
1006
|
-
text,
|
|
1007
|
-
tip,
|
|
1008
|
-
errorDetailsPromise
|
|
1009
|
-
} = formatError(exception);
|
|
1010
1073
|
if (errorOverlay) {
|
|
1011
|
-
const removeErrorOverlay = displayJsenvErrorOverlay(
|
|
1012
|
-
theme,
|
|
1013
|
-
title,
|
|
1014
|
-
text,
|
|
1015
|
-
tip,
|
|
1016
|
-
errorDetailsPromise
|
|
1017
|
-
});
|
|
1074
|
+
const removeErrorOverlay = displayJsenvErrorOverlay(exception);
|
|
1018
1075
|
if (window.__reloader__) {
|
|
1019
1076
|
const onchange = window.__reloader__.status.onchange;
|
|
1020
1077
|
window.__reloader__.status.onchange = () => {
|
|
@@ -1027,8 +1084,8 @@ window.__supervisor__ = (() => {
|
|
|
1027
1084
|
}
|
|
1028
1085
|
if (errorNotification) {
|
|
1029
1086
|
displayErrorNotification({
|
|
1030
|
-
title,
|
|
1031
|
-
text
|
|
1087
|
+
title: "An error occured",
|
|
1088
|
+
text: "todo"
|
|
1032
1089
|
});
|
|
1033
1090
|
}
|
|
1034
1091
|
return exception;
|
|
@@ -1055,6 +1112,7 @@ window.__supervisor__ = (() => {
|
|
|
1055
1112
|
// when error is reported within a worker error is null
|
|
1056
1113
|
// but there is a message property on errorEvent
|
|
1057
1114
|
reportedBy: "window_error_event",
|
|
1115
|
+
message,
|
|
1058
1116
|
url: filename,
|
|
1059
1117
|
line: lineno,
|
|
1060
1118
|
column: colno
|
|
@@ -1097,7 +1155,7 @@ window.__supervisor__ = (() => {
|
|
|
1097
1155
|
resolve({
|
|
1098
1156
|
detectedBy: "window_error_event",
|
|
1099
1157
|
failed: true,
|
|
1100
|
-
|
|
1158
|
+
errorEvent
|
|
1101
1159
|
});
|
|
1102
1160
|
}
|
|
1103
1161
|
};
|
|
@@ -1110,7 +1168,7 @@ window.__supervisor__ = (() => {
|
|
|
1110
1168
|
resolve({
|
|
1111
1169
|
detectedBy: "script_error_event",
|
|
1112
1170
|
failed: true,
|
|
1113
|
-
|
|
1171
|
+
errorEvent
|
|
1114
1172
|
});
|
|
1115
1173
|
});
|
|
1116
1174
|
script.addEventListener("load", () => {
|