@jsenv/core 28.1.3 → 28.2.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/script_type_module_supervisor.js +8 -13
- package/dist/js/supervisor.js +690 -504
- package/dist/main.js +13332 -13179
- package/package.json +5 -5
- package/readme.md +3 -3
- package/src/build/build.js +980 -713
- package/src/build/inject_global_version_mappings.js +5 -20
- package/src/build/start_build_server.js +2 -2
- package/src/dev/start_dev_server.js +6 -3
- package/src/omega/compat/runtime_compat.js +9 -6
- package/src/omega/errors.js +3 -0
- package/src/omega/fetched_content_compliance.js +2 -2
- package/src/omega/kitchen.js +191 -146
- package/src/omega/server/file_service.js +104 -71
- package/src/omega/url_graph/url_graph_loader.js +77 -0
- package/src/omega/url_graph/url_info_transformations.js +12 -15
- package/src/omega/url_graph.js +118 -101
- package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +1 -0
- package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +34 -36
- package/src/plugins/autoreload/jsenv_plugin_hmr.js +3 -2
- package/src/plugins/bundling/js_module/{bundle_js_module.js → bundle_js_modules.js} +51 -14
- package/src/plugins/bundling/jsenv_plugin_bundling.js +2 -2
- package/src/plugins/import_meta_hot/jsenv_plugin_import_meta_hot.js +11 -0
- package/src/plugins/inline/jsenv_plugin_html_inline_content.js +73 -62
- package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +77 -89
- package/src/plugins/plugin_controller.js +26 -22
- package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +1 -0
- package/src/plugins/supervisor/client/script_type_module_supervisor.js +7 -9
- package/src/plugins/supervisor/client/supervisor.js +99 -52
- package/src/plugins/supervisor/jsenv_plugin_supervisor.js +2 -4
- package/src/plugins/transpilation/as_js_classic/async-to-promises.js +16 -0
- package/src/plugins/transpilation/as_js_classic/convert_js_module_to_js_classic.js +85 -0
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +48 -190
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_conversion.js +104 -0
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +161 -240
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_library.js +92 -0
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_workers.js +19 -12
- package/src/plugins/transpilation/babel/jsenv_plugin_babel.js +1 -24
- package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +82 -52
- package/src/plugins/transpilation/jsenv_plugin_transpilation.js +12 -13
- package/src/plugins/url_analysis/html/html_urls.js +91 -34
- package/src/plugins/url_analysis/js/js_urls.js +5 -4
- package/src/plugins/url_resolution/jsenv_plugin_url_resolution.js +1 -0
- package/src/test/execute_plan.js +3 -8
- package/src/build/inject_service_worker_urls.js +0 -78
- package/src/build/resync_resource_hints.js +0 -112
- package/src/omega/url_graph/url_graph_load.js +0 -74
package/dist/js/supervisor.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
window.__supervisor__ = (() => {
|
|
2
2
|
const notImplemented = () => {
|
|
3
|
-
throw new Error(`window.__supervisor__.setup() not called`)
|
|
4
|
-
}
|
|
5
|
-
|
|
3
|
+
throw new Error(`window.__supervisor__.setup() not called`);
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
const executionResults = {};
|
|
6
7
|
const supervisor = {
|
|
7
8
|
reportError: notImplemented,
|
|
8
9
|
superviseScript: notImplemented,
|
|
9
10
|
reloadSupervisedScript: notImplemented,
|
|
10
11
|
getDocumentExecutionResult: notImplemented,
|
|
11
|
-
executionResults
|
|
12
|
-
}
|
|
12
|
+
executionResults
|
|
13
|
+
};
|
|
14
|
+
let navigationStartTime;
|
|
13
15
|
|
|
14
|
-
let navigationStartTime
|
|
15
16
|
try {
|
|
16
|
-
navigationStartTime = window.performance.timing.navigationStart
|
|
17
|
+
navigationStartTime = window.performance.timing.navigationStart;
|
|
17
18
|
} catch (e) {
|
|
18
|
-
navigationStartTime = Date.now()
|
|
19
|
+
navigationStartTime = Date.now();
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
supervisor.setupReportException = ({
|
|
@@ -23,23 +24,24 @@ window.__supervisor__ = (() => {
|
|
|
23
24
|
errorNotification,
|
|
24
25
|
errorOverlay,
|
|
25
26
|
errorBaseUrl,
|
|
26
|
-
openInEditor
|
|
27
|
+
openInEditor
|
|
27
28
|
}) => {
|
|
28
|
-
const DYNAMIC_IMPORT_FETCH_ERROR = "dynamic_import_fetch_error"
|
|
29
|
-
const DYNAMIC_IMPORT_EXPORT_MISSING = "dynamic_import_export_missing"
|
|
30
|
-
const DYNAMIC_IMPORT_SYNTAX_ERROR = "dynamic_import_syntax_error"
|
|
29
|
+
const DYNAMIC_IMPORT_FETCH_ERROR = "dynamic_import_fetch_error";
|
|
30
|
+
const DYNAMIC_IMPORT_EXPORT_MISSING = "dynamic_import_export_missing";
|
|
31
|
+
const DYNAMIC_IMPORT_SYNTAX_ERROR = "dynamic_import_syntax_error";
|
|
31
32
|
|
|
32
33
|
const createException = ({
|
|
33
34
|
reason,
|
|
34
35
|
reportedBy,
|
|
35
36
|
url,
|
|
36
37
|
line,
|
|
37
|
-
column
|
|
38
|
+
column
|
|
38
39
|
} = {}) => {
|
|
39
40
|
const exception = {
|
|
40
41
|
reason,
|
|
41
42
|
reportedBy,
|
|
42
|
-
isError: false,
|
|
43
|
+
isError: false,
|
|
44
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw
|
|
43
45
|
code: null,
|
|
44
46
|
message: null,
|
|
45
47
|
stack: null,
|
|
@@ -52,462 +54,526 @@ window.__supervisor__ = (() => {
|
|
|
52
54
|
url: null,
|
|
53
55
|
line: null,
|
|
54
56
|
column: null,
|
|
55
|
-
originalUrl: null
|
|
56
|
-
}
|
|
57
|
-
}
|
|
57
|
+
originalUrl: null
|
|
58
|
+
}
|
|
59
|
+
};
|
|
58
60
|
|
|
59
61
|
const writeBasicProperties = () => {
|
|
60
62
|
if (reason === undefined) {
|
|
61
|
-
exception.message = "undefined"
|
|
62
|
-
return
|
|
63
|
+
exception.message = "undefined";
|
|
64
|
+
return;
|
|
63
65
|
}
|
|
66
|
+
|
|
64
67
|
if (reason === null) {
|
|
65
|
-
exception.message = "null"
|
|
66
|
-
return
|
|
68
|
+
exception.message = "null";
|
|
69
|
+
return;
|
|
67
70
|
}
|
|
71
|
+
|
|
68
72
|
if (typeof reason === "string") {
|
|
69
|
-
exception.message = reason
|
|
70
|
-
return
|
|
73
|
+
exception.message = reason;
|
|
74
|
+
return;
|
|
71
75
|
}
|
|
76
|
+
|
|
72
77
|
if (reason instanceof Error) {
|
|
73
|
-
const error = reason
|
|
74
|
-
let message = error.message
|
|
75
|
-
exception.isError = true
|
|
78
|
+
const error = reason;
|
|
79
|
+
let message = error.message;
|
|
80
|
+
exception.isError = true;
|
|
81
|
+
|
|
76
82
|
if (Error.captureStackTrace) {
|
|
77
83
|
// stackTrace formatted by V8
|
|
78
|
-
exception.message = message
|
|
79
|
-
exception.stack = getErrorStackWithoutErrorMessage(error)
|
|
80
|
-
exception.stackFormatIsV8 = true
|
|
81
|
-
exception.stackSourcemapped = true
|
|
84
|
+
exception.message = message;
|
|
85
|
+
exception.stack = getErrorStackWithoutErrorMessage(error);
|
|
86
|
+
exception.stackFormatIsV8 = true;
|
|
87
|
+
exception.stackSourcemapped = true;
|
|
82
88
|
} else {
|
|
83
|
-
exception.message = message
|
|
84
|
-
exception.stack = error.stack ? ` ${error.stack}` : null
|
|
85
|
-
exception.stackFormatIsV8 = false
|
|
86
|
-
exception.stackSourcemapped = false
|
|
89
|
+
exception.message = message;
|
|
90
|
+
exception.stack = error.stack ? ` ${error.stack}` : null;
|
|
91
|
+
exception.stackFormatIsV8 = false;
|
|
92
|
+
exception.stackSourcemapped = false;
|
|
87
93
|
}
|
|
94
|
+
|
|
88
95
|
if (error.reportedBy) {
|
|
89
|
-
exception.reportedBy = error.reportedBy
|
|
96
|
+
exception.reportedBy = error.reportedBy;
|
|
90
97
|
}
|
|
98
|
+
|
|
91
99
|
if (error.url) {
|
|
92
|
-
Object.assign(exception.site, resolveUrlSite({
|
|
100
|
+
Object.assign(exception.site, resolveUrlSite({
|
|
101
|
+
url: error.url
|
|
102
|
+
}));
|
|
93
103
|
}
|
|
104
|
+
|
|
94
105
|
if (error.needsReport) {
|
|
95
|
-
exception.needsReport = true
|
|
106
|
+
exception.needsReport = true;
|
|
96
107
|
}
|
|
97
|
-
|
|
108
|
+
|
|
109
|
+
{
|
|
98
110
|
// chrome
|
|
99
111
|
if (message.includes("does not provide an export named")) {
|
|
100
|
-
exception.code = DYNAMIC_IMPORT_EXPORT_MISSING
|
|
101
|
-
return
|
|
102
|
-
}
|
|
103
|
-
|
|
112
|
+
exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
|
|
113
|
+
return;
|
|
114
|
+
} // firefox
|
|
115
|
+
|
|
116
|
+
|
|
104
117
|
if (message.startsWith("import not found:")) {
|
|
105
|
-
exception.code = DYNAMIC_IMPORT_EXPORT_MISSING
|
|
106
|
-
return
|
|
107
|
-
}
|
|
108
|
-
|
|
118
|
+
exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
|
|
119
|
+
return;
|
|
120
|
+
} // safari
|
|
121
|
+
|
|
122
|
+
|
|
109
123
|
if (message.startsWith("import binding name")) {
|
|
110
|
-
exception.code = DYNAMIC_IMPORT_EXPORT_MISSING
|
|
111
|
-
return
|
|
124
|
+
exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
|
|
125
|
+
return;
|
|
112
126
|
}
|
|
113
127
|
}
|
|
114
|
-
|
|
128
|
+
|
|
129
|
+
{
|
|
115
130
|
if (error.name === "SyntaxError" && typeof line === "number") {
|
|
116
|
-
exception.code = DYNAMIC_IMPORT_SYNTAX_ERROR
|
|
117
|
-
return
|
|
131
|
+
exception.code = DYNAMIC_IMPORT_SYNTAX_ERROR;
|
|
132
|
+
return;
|
|
118
133
|
}
|
|
119
134
|
}
|
|
120
|
-
|
|
135
|
+
|
|
136
|
+
return;
|
|
121
137
|
}
|
|
138
|
+
|
|
122
139
|
if (typeof reason === "object") {
|
|
123
|
-
exception.code = reason.code
|
|
124
|
-
exception.message = reason.message
|
|
125
|
-
exception.stack = reason.stack
|
|
140
|
+
exception.code = reason.code;
|
|
141
|
+
exception.message = reason.message;
|
|
142
|
+
exception.stack = reason.stack;
|
|
143
|
+
|
|
126
144
|
if (reason.reportedBy) {
|
|
127
|
-
exception.reportedBy = reason.reportedBy
|
|
145
|
+
exception.reportedBy = reason.reportedBy;
|
|
128
146
|
}
|
|
147
|
+
|
|
129
148
|
if (reason.url) {
|
|
130
|
-
Object.assign(exception.site, resolveUrlSite({
|
|
149
|
+
Object.assign(exception.site, resolveUrlSite({
|
|
150
|
+
url: reason.url
|
|
151
|
+
}));
|
|
131
152
|
}
|
|
153
|
+
|
|
132
154
|
if (reason.needsReport) {
|
|
133
|
-
exception.needsReport = true
|
|
155
|
+
exception.needsReport = true;
|
|
134
156
|
}
|
|
135
|
-
|
|
157
|
+
|
|
158
|
+
return;
|
|
136
159
|
}
|
|
137
|
-
exception.message = JSON.stringify(reason)
|
|
138
|
-
}
|
|
139
|
-
writeBasicProperties()
|
|
140
160
|
|
|
141
|
-
|
|
161
|
+
exception.message = JSON.stringify(reason);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
writeBasicProperties(); // first create a version of the stack with file://
|
|
142
165
|
// (and use it to locate exception url+line+column)
|
|
166
|
+
|
|
143
167
|
if (exception.stack) {
|
|
144
|
-
exception.originalStack = exception.stack
|
|
145
|
-
exception.stack = replaceUrls(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
168
|
+
exception.originalStack = exception.stack;
|
|
169
|
+
exception.stack = replaceUrls(exception.originalStack, serverUrlSite => {
|
|
170
|
+
const fileUrlSite = resolveUrlSite(serverUrlSite);
|
|
171
|
+
|
|
172
|
+
if (exception.site.url === null) {
|
|
173
|
+
Object.assign(exception.site, fileUrlSite);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return stringifyUrlSite(fileUrlSite);
|
|
177
|
+
});
|
|
178
|
+
} // then if it fails, use url+line+column passed
|
|
179
|
+
|
|
180
|
+
|
|
157
181
|
if (exception.site.url === null && url) {
|
|
158
182
|
if (typeof line === "string") {
|
|
159
|
-
line = parseInt(line)
|
|
183
|
+
line = parseInt(line);
|
|
160
184
|
}
|
|
185
|
+
|
|
161
186
|
if (typeof column === "string") {
|
|
162
|
-
column = parseInt(column)
|
|
187
|
+
column = parseInt(column);
|
|
163
188
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
189
|
+
|
|
190
|
+
const fileUrlSite = resolveUrlSite({
|
|
191
|
+
url,
|
|
192
|
+
line,
|
|
193
|
+
column
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
if (fileUrlSite.isInline && exception.code === DYNAMIC_IMPORT_SYNTAX_ERROR) {
|
|
169
197
|
// syntax error on inline script need line-1 for some reason
|
|
170
198
|
if (Error.captureStackTrace) {
|
|
171
|
-
fileUrlSite.line
|
|
199
|
+
fileUrlSite.line--;
|
|
172
200
|
} else {
|
|
173
201
|
// firefox and safari need line-2
|
|
174
|
-
fileUrlSite.line -= 2
|
|
202
|
+
fileUrlSite.line -= 2;
|
|
175
203
|
}
|
|
176
204
|
}
|
|
177
|
-
|
|
205
|
+
|
|
206
|
+
Object.assign(exception.site, fileUrlSite);
|
|
178
207
|
}
|
|
179
|
-
exception.text = stringifyMessageAndStack(exception)
|
|
180
|
-
return exception
|
|
181
|
-
}
|
|
182
208
|
|
|
183
|
-
|
|
209
|
+
exception.text = stringifyMessageAndStack(exception);
|
|
210
|
+
return exception;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const stringifyMessageAndStack = ({
|
|
214
|
+
message,
|
|
215
|
+
stack
|
|
216
|
+
}) => {
|
|
184
217
|
if (message && stack) {
|
|
185
|
-
return `${message}\n${stack}
|
|
218
|
+
return `${message}\n${stack}`;
|
|
186
219
|
}
|
|
220
|
+
|
|
187
221
|
if (stack) {
|
|
188
|
-
return stack
|
|
222
|
+
return stack;
|
|
189
223
|
}
|
|
190
|
-
return message
|
|
191
|
-
}
|
|
192
224
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
225
|
+
return message;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const stringifyUrlSite = ({
|
|
229
|
+
url,
|
|
230
|
+
line,
|
|
231
|
+
column
|
|
232
|
+
}) => {
|
|
233
|
+
return typeof line === "number" && typeof column === "number" ? `${url}:${line}:${column}` : typeof line === "number" ? `${url}:${line}` : url;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const resolveUrlSite = ({
|
|
237
|
+
url,
|
|
238
|
+
line,
|
|
239
|
+
column
|
|
240
|
+
}) => {
|
|
241
|
+
const inlineUrlMatch = url.match(/@L([0-9]+)C([0-9]+)\-L([0-9]+)C([0-9]+)(\.[\w]+)$/);
|
|
200
242
|
|
|
201
|
-
const resolveUrlSite = ({ url, line, column }) => {
|
|
202
|
-
const inlineUrlMatch = url.match(
|
|
203
|
-
/@L([0-9]+)C([0-9]+)\-L([0-9]+)C([0-9]+)(\.[\w]+)$/,
|
|
204
|
-
)
|
|
205
243
|
if (inlineUrlMatch) {
|
|
206
|
-
const htmlUrl = url.slice(0, inlineUrlMatch.index)
|
|
207
|
-
const tagLineStart = parseInt(inlineUrlMatch[1])
|
|
208
|
-
const tagColumnStart = parseInt(inlineUrlMatch[2])
|
|
209
|
-
const tagLineEnd = parseInt(inlineUrlMatch[3])
|
|
210
|
-
const tagColumnEnd = parseInt(inlineUrlMatch[4])
|
|
211
|
-
const extension = inlineUrlMatch[5]
|
|
212
|
-
url = htmlUrl
|
|
213
|
-
line = tagLineStart + (typeof line === "number" ? line : 0)
|
|
214
|
-
|
|
244
|
+
const htmlUrl = url.slice(0, inlineUrlMatch.index);
|
|
245
|
+
const tagLineStart = parseInt(inlineUrlMatch[1]);
|
|
246
|
+
const tagColumnStart = parseInt(inlineUrlMatch[2]);
|
|
247
|
+
const tagLineEnd = parseInt(inlineUrlMatch[3]);
|
|
248
|
+
const tagColumnEnd = parseInt(inlineUrlMatch[4]);
|
|
249
|
+
const extension = inlineUrlMatch[5];
|
|
250
|
+
url = htmlUrl;
|
|
251
|
+
line = tagLineStart + (typeof line === "number" ? line : 0); // stackTrace formatted by V8 (chrome)
|
|
252
|
+
|
|
215
253
|
if (Error.captureStackTrace) {
|
|
216
|
-
line
|
|
254
|
+
line--;
|
|
217
255
|
}
|
|
218
|
-
|
|
219
|
-
|
|
256
|
+
|
|
257
|
+
column = tagColumnStart + (typeof column === "number" ? column : 0);
|
|
258
|
+
const fileUrl = resolveFileUrl(url);
|
|
220
259
|
return {
|
|
221
260
|
isInline: true,
|
|
222
261
|
serverUrl: url,
|
|
223
262
|
originalUrl: `${fileUrl}@L${tagLineStart}C${tagColumnStart}-L${tagLineEnd}C${tagColumnEnd}${extension}`,
|
|
224
263
|
url: fileUrl,
|
|
225
264
|
line,
|
|
226
|
-
column
|
|
227
|
-
}
|
|
265
|
+
column
|
|
266
|
+
};
|
|
228
267
|
}
|
|
268
|
+
|
|
229
269
|
return {
|
|
230
270
|
isInline: false,
|
|
231
271
|
serverUrl: url,
|
|
232
272
|
url: resolveFileUrl(url),
|
|
233
273
|
line,
|
|
234
|
-
column
|
|
235
|
-
}
|
|
236
|
-
}
|
|
274
|
+
column
|
|
275
|
+
};
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const getErrorStackWithoutErrorMessage = error => {
|
|
279
|
+
let stack = error.stack;
|
|
280
|
+
const messageInStack = `${error.name}: ${error.message}`;
|
|
237
281
|
|
|
238
|
-
const getErrorStackWithoutErrorMessage = (error) => {
|
|
239
|
-
let stack = error.stack
|
|
240
|
-
const messageInStack = `${error.name}: ${error.message}`
|
|
241
282
|
if (stack.startsWith(messageInStack)) {
|
|
242
|
-
stack = stack.slice(messageInStack.length)
|
|
283
|
+
stack = stack.slice(messageInStack.length);
|
|
243
284
|
}
|
|
244
|
-
|
|
285
|
+
|
|
286
|
+
const nextLineIndex = stack.indexOf("\n");
|
|
287
|
+
|
|
245
288
|
if (nextLineIndex > -1) {
|
|
246
|
-
stack = stack.slice(nextLineIndex + 1)
|
|
289
|
+
stack = stack.slice(nextLineIndex + 1);
|
|
247
290
|
}
|
|
248
|
-
return stack
|
|
249
|
-
}
|
|
250
291
|
|
|
251
|
-
|
|
252
|
-
|
|
292
|
+
return stack;
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const resolveFileUrl = url => {
|
|
296
|
+
let urlObject = new URL(url);
|
|
297
|
+
|
|
253
298
|
if (urlObject.origin === window.origin) {
|
|
254
|
-
urlObject = new URL(
|
|
255
|
-
`${urlObject.pathname.slice(1)}${urlObject.search}`,
|
|
256
|
-
rootDirectoryUrl,
|
|
257
|
-
)
|
|
299
|
+
urlObject = new URL(`${urlObject.pathname.slice(1)}${urlObject.search}`, rootDirectoryUrl);
|
|
258
300
|
}
|
|
301
|
+
|
|
259
302
|
if (urlObject.href.startsWith("file:")) {
|
|
260
|
-
const atFsIndex = urlObject.pathname.indexOf("/@fs/")
|
|
303
|
+
const atFsIndex = urlObject.pathname.indexOf("/@fs/");
|
|
304
|
+
|
|
261
305
|
if (atFsIndex > -1) {
|
|
262
|
-
const afterAtFs = urlObject.pathname.slice(atFsIndex + "/@fs/".length)
|
|
263
|
-
return new URL(afterAtFs, "file:///").href
|
|
306
|
+
const afterAtFs = urlObject.pathname.slice(atFsIndex + "/@fs/".length);
|
|
307
|
+
return new URL(afterAtFs, "file:///").href;
|
|
264
308
|
}
|
|
265
309
|
}
|
|
266
|
-
return urlObject.href
|
|
267
|
-
}
|
|
268
310
|
|
|
269
|
-
|
|
311
|
+
return urlObject.href;
|
|
312
|
+
}; // `Error: yo
|
|
270
313
|
// at Object.execute (http://127.0.0.1:57300/build/src/__test__/file-throw.js:9:13)
|
|
271
314
|
// at doExec (http://127.0.0.1:3000/src/__test__/file-throw.js:452:38)
|
|
272
315
|
// at postOrderExec (http://127.0.0.1:3000/src/__test__/file-throw.js:448:16)
|
|
273
316
|
// at http://127.0.0.1:3000/src/__test__/file-throw.js:399:18`.replace(/(?:https?|ftp|file):\/\/(.*+)$/gm, (...args) => {
|
|
274
317
|
// debugger
|
|
275
318
|
// })
|
|
319
|
+
|
|
320
|
+
|
|
276
321
|
const replaceUrls = (source, replace) => {
|
|
277
|
-
return source.replace(/(?:https?|ftp|file):\/\/\S+/gm,
|
|
278
|
-
let replacement = ""
|
|
279
|
-
const lastChar = match[match.length - 1]
|
|
322
|
+
return source.replace(/(?:https?|ftp|file):\/\/\S+/gm, match => {
|
|
323
|
+
let replacement = "";
|
|
324
|
+
const lastChar = match[match.length - 1]; // hotfix because our url regex sucks a bit
|
|
325
|
+
|
|
326
|
+
const endsWithSeparationChar = lastChar === ")" || lastChar === ":";
|
|
280
327
|
|
|
281
|
-
// hotfix because our url regex sucks a bit
|
|
282
|
-
const endsWithSeparationChar = lastChar === ")" || lastChar === ":"
|
|
283
328
|
if (endsWithSeparationChar) {
|
|
284
|
-
match = match.slice(0, -1)
|
|
329
|
+
match = match.slice(0, -1);
|
|
285
330
|
}
|
|
286
331
|
|
|
287
|
-
const lineAndColumnPattern = /:([0-9]+):([0-9]+)
|
|
288
|
-
const lineAndColumMatch = match.match(lineAndColumnPattern)
|
|
332
|
+
const lineAndColumnPattern = /:([0-9]+):([0-9]+)$/;
|
|
333
|
+
const lineAndColumMatch = match.match(lineAndColumnPattern);
|
|
334
|
+
|
|
289
335
|
if (lineAndColumMatch) {
|
|
290
|
-
const lineAndColumnString = lineAndColumMatch[0]
|
|
291
|
-
const lineString = lineAndColumMatch[1]
|
|
292
|
-
const columnString = lineAndColumMatch[2]
|
|
336
|
+
const lineAndColumnString = lineAndColumMatch[0];
|
|
337
|
+
const lineString = lineAndColumMatch[1];
|
|
338
|
+
const columnString = lineAndColumMatch[2];
|
|
293
339
|
replacement = replace({
|
|
294
340
|
url: match.slice(0, -lineAndColumnString.length),
|
|
295
341
|
line: lineString ? parseInt(lineString) : null,
|
|
296
|
-
column: columnString ? parseInt(columnString) : null
|
|
297
|
-
})
|
|
342
|
+
column: columnString ? parseInt(columnString) : null
|
|
343
|
+
});
|
|
298
344
|
} else {
|
|
299
|
-
const linePattern = /:([0-9]+)
|
|
300
|
-
const lineMatch = match.match(linePattern)
|
|
345
|
+
const linePattern = /:([0-9]+)$/;
|
|
346
|
+
const lineMatch = match.match(linePattern);
|
|
347
|
+
|
|
301
348
|
if (lineMatch) {
|
|
302
|
-
const lineString = lineMatch[0]
|
|
349
|
+
const lineString = lineMatch[0];
|
|
303
350
|
replacement = replace({
|
|
304
351
|
url: match.slice(0, -lineString.length),
|
|
305
|
-
line: lineString ? parseInt(lineString) : null
|
|
306
|
-
})
|
|
352
|
+
line: lineString ? parseInt(lineString) : null
|
|
353
|
+
});
|
|
307
354
|
} else {
|
|
308
355
|
replacement = replace({
|
|
309
|
-
url: match
|
|
310
|
-
})
|
|
356
|
+
url: match
|
|
357
|
+
});
|
|
311
358
|
}
|
|
312
359
|
}
|
|
360
|
+
|
|
313
361
|
if (endsWithSeparationChar) {
|
|
314
|
-
return `${replacement}${lastChar}
|
|
362
|
+
return `${replacement}${lastChar}`;
|
|
315
363
|
}
|
|
316
|
-
return replacement
|
|
317
|
-
})
|
|
318
|
-
}
|
|
319
364
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
365
|
+
return replacement;
|
|
366
|
+
});
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
let formatError;
|
|
370
|
+
|
|
371
|
+
{
|
|
372
|
+
formatError = exceptionInfo => {
|
|
323
373
|
const errorParts = {
|
|
324
374
|
theme: "dark",
|
|
325
375
|
title: "An error occured",
|
|
326
376
|
text: "",
|
|
327
377
|
tip: "",
|
|
328
|
-
errorDetailsPromise: null
|
|
329
|
-
}
|
|
330
|
-
const tips = []
|
|
331
|
-
tips.push("Click outside to close.")
|
|
332
|
-
errorParts.tip = tips.join(`\n <br />\n `)
|
|
378
|
+
errorDetailsPromise: null
|
|
379
|
+
};
|
|
380
|
+
const tips = [];
|
|
381
|
+
tips.push("Click outside to close.");
|
|
382
|
+
errorParts.tip = tips.join(`\n <br />\n `);
|
|
333
383
|
|
|
334
|
-
const generateClickableText =
|
|
384
|
+
const generateClickableText = text => {
|
|
335
385
|
const textWithHtmlLinks = makeLinksClickable(text, {
|
|
336
|
-
createLink: ({
|
|
337
|
-
|
|
386
|
+
createLink: ({
|
|
387
|
+
url,
|
|
388
|
+
line,
|
|
389
|
+
column
|
|
390
|
+
}) => {
|
|
391
|
+
const urlSite = resolveUrlSite({
|
|
392
|
+
url,
|
|
393
|
+
line,
|
|
394
|
+
column
|
|
395
|
+
});
|
|
396
|
+
|
|
338
397
|
if (errorBaseUrl) {
|
|
339
398
|
if (urlSite.url.startsWith(rootDirectoryUrl)) {
|
|
340
|
-
urlSite.url = `${errorBaseUrl}${urlSite.url.slice(
|
|
341
|
-
rootDirectoryUrl.length,
|
|
342
|
-
)}`
|
|
399
|
+
urlSite.url = `${errorBaseUrl}${urlSite.url.slice(rootDirectoryUrl.length)}`;
|
|
343
400
|
} else {
|
|
344
|
-
urlSite.url = "file:///mocked_for_snapshots"
|
|
401
|
+
urlSite.url = "file:///mocked_for_snapshots";
|
|
345
402
|
}
|
|
346
403
|
}
|
|
347
|
-
|
|
404
|
+
|
|
405
|
+
const urlWithLineAndColumn = stringifyUrlSite(urlSite);
|
|
348
406
|
return {
|
|
349
|
-
href:
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
}
|
|
357
|
-
},
|
|
358
|
-
})
|
|
359
|
-
return textWithHtmlLinks
|
|
360
|
-
}
|
|
407
|
+
href: urlSite.url.startsWith("file:") && openInEditor ? `javascript:window.fetch('/__open_in_editor__/${encodeURIComponent(urlWithLineAndColumn)}')` : urlSite.url,
|
|
408
|
+
text: urlWithLineAndColumn
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
return textWithHtmlLinks;
|
|
413
|
+
};
|
|
361
414
|
|
|
362
415
|
errorParts.text = stringifyMessageAndStack({
|
|
363
|
-
message: exceptionInfo.message
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
? generateClickableText(exceptionInfo.stack)
|
|
368
|
-
: "",
|
|
369
|
-
})
|
|
416
|
+
message: exceptionInfo.message ? generateClickableText(exceptionInfo.message) : "",
|
|
417
|
+
stack: exceptionInfo.stack ? generateClickableText(exceptionInfo.stack) : ""
|
|
418
|
+
});
|
|
419
|
+
|
|
370
420
|
if (exceptionInfo.site.url) {
|
|
371
421
|
errorParts.errorDetailsPromise = (async () => {
|
|
372
422
|
try {
|
|
373
|
-
if (
|
|
374
|
-
exceptionInfo.
|
|
375
|
-
|
|
376
|
-
) {
|
|
377
|
-
const response = await window.fetch(
|
|
378
|
-
`/__get_error_cause__/${encodeURIComponent(
|
|
379
|
-
exceptionInfo.site.isInline
|
|
380
|
-
? exceptionInfo.site.originalUrl
|
|
381
|
-
: exceptionInfo.site.url,
|
|
382
|
-
)}`,
|
|
383
|
-
)
|
|
423
|
+
if (exceptionInfo.code === DYNAMIC_IMPORT_FETCH_ERROR || exceptionInfo.reportedBy === "script_error_event") {
|
|
424
|
+
const response = await window.fetch(`/__get_error_cause__/${encodeURIComponent(exceptionInfo.site.isInline ? exceptionInfo.site.originalUrl : exceptionInfo.site.url)}`);
|
|
425
|
+
|
|
384
426
|
if (response.status !== 200) {
|
|
385
|
-
return null
|
|
427
|
+
return null;
|
|
386
428
|
}
|
|
387
|
-
|
|
429
|
+
|
|
430
|
+
const causeInfo = await response.json();
|
|
431
|
+
|
|
388
432
|
if (!causeInfo) {
|
|
389
|
-
return null
|
|
433
|
+
return null;
|
|
390
434
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
stack: generateClickableText(causeInfo.codeFrame),
|
|
400
|
-
})
|
|
435
|
+
|
|
436
|
+
const causeText = causeInfo.code === "NOT_FOUND" ? stringifyMessageAndStack({
|
|
437
|
+
message: generateClickableText(causeInfo.reason),
|
|
438
|
+
stack: generateClickableText(causeInfo.codeFrame)
|
|
439
|
+
}) : stringifyMessageAndStack({
|
|
440
|
+
message: generateClickableText(causeInfo.stack),
|
|
441
|
+
stack: generateClickableText(causeInfo.codeFrame)
|
|
442
|
+
});
|
|
401
443
|
return {
|
|
402
|
-
cause: causeText
|
|
403
|
-
}
|
|
444
|
+
cause: causeText
|
|
445
|
+
};
|
|
404
446
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
)
|
|
411
|
-
) {
|
|
412
|
-
const urlToFetch = new URL(
|
|
413
|
-
`/__get_code_frame__/${encodeURIComponent(
|
|
414
|
-
stringifyUrlSite(exceptionInfo.site),
|
|
415
|
-
)}`,
|
|
416
|
-
window.origin,
|
|
417
|
-
)
|
|
447
|
+
|
|
448
|
+
if (exceptionInfo.site.line !== undefined && // code frame showing internal window.reportError is pointless
|
|
449
|
+
!exceptionInfo.site.url.endsWith(`script_type_module_supervisor.js`)) {
|
|
450
|
+
const urlToFetch = new URL(`/__get_code_frame__/${encodeURIComponent(stringifyUrlSite(exceptionInfo.site))}`, window.origin);
|
|
451
|
+
|
|
418
452
|
if (!exceptionInfo.stackSourcemapped) {
|
|
419
|
-
urlToFetch.searchParams.set("remap", "")
|
|
453
|
+
urlToFetch.searchParams.set("remap", "");
|
|
420
454
|
}
|
|
421
|
-
|
|
455
|
+
|
|
456
|
+
const response = await window.fetch(urlToFetch);
|
|
457
|
+
|
|
422
458
|
if (response.status !== 200) {
|
|
423
|
-
return null
|
|
459
|
+
return null;
|
|
424
460
|
}
|
|
425
|
-
|
|
461
|
+
|
|
462
|
+
const codeFrame = await response.text();
|
|
426
463
|
return {
|
|
427
|
-
codeFrame: generateClickableText(codeFrame)
|
|
428
|
-
}
|
|
464
|
+
codeFrame: generateClickableText(codeFrame)
|
|
465
|
+
};
|
|
429
466
|
}
|
|
430
467
|
} catch (e) {
|
|
431
468
|
// happens if server is closed for instance
|
|
432
|
-
return null
|
|
469
|
+
return null;
|
|
433
470
|
}
|
|
434
|
-
|
|
435
|
-
|
|
471
|
+
|
|
472
|
+
return null;
|
|
473
|
+
})();
|
|
436
474
|
}
|
|
437
|
-
return errorParts
|
|
438
|
-
}
|
|
439
475
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
476
|
+
return errorParts;
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
const makeLinksClickable = (string, {
|
|
480
|
+
createLink = ({
|
|
481
|
+
url
|
|
482
|
+
}) => url
|
|
483
|
+
}) => {
|
|
444
484
|
// normalize line breaks
|
|
445
|
-
string = string.replace(/\n/g, "\n")
|
|
446
|
-
string = escapeHtml(string)
|
|
447
|
-
// render links
|
|
448
|
-
string = replaceUrls(string, ({ url, line, column }) => {
|
|
449
|
-
const { href, text } = createLink({ url, line, column })
|
|
450
|
-
return link({ href, text })
|
|
451
|
-
})
|
|
452
|
-
return string
|
|
453
|
-
}
|
|
485
|
+
string = string.replace(/\n/g, "\n");
|
|
486
|
+
string = escapeHtml(string); // render links
|
|
454
487
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
488
|
+
string = replaceUrls(string, ({
|
|
489
|
+
url,
|
|
490
|
+
line,
|
|
491
|
+
column
|
|
492
|
+
}) => {
|
|
493
|
+
const {
|
|
494
|
+
href,
|
|
495
|
+
text
|
|
496
|
+
} = createLink({
|
|
497
|
+
url,
|
|
498
|
+
line,
|
|
499
|
+
column
|
|
500
|
+
});
|
|
501
|
+
return link({
|
|
502
|
+
href,
|
|
503
|
+
text
|
|
504
|
+
});
|
|
505
|
+
});
|
|
506
|
+
return string;
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
const escapeHtml = string => {
|
|
510
|
+
return string.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
511
|
+
};
|
|
463
512
|
|
|
464
|
-
const link = ({
|
|
513
|
+
const link = ({
|
|
514
|
+
href,
|
|
515
|
+
text = href
|
|
516
|
+
}) => `<a href="${href}">${text}</a>`;
|
|
465
517
|
}
|
|
466
518
|
|
|
467
|
-
let displayErrorNotification
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
519
|
+
let displayErrorNotification;
|
|
520
|
+
|
|
521
|
+
{
|
|
522
|
+
const {
|
|
523
|
+
Notification
|
|
524
|
+
} = window;
|
|
525
|
+
displayErrorNotification = typeof Notification === "function" ? ({
|
|
526
|
+
title,
|
|
527
|
+
text,
|
|
528
|
+
icon
|
|
529
|
+
}) => {
|
|
530
|
+
if (Notification.permission === "granted") {
|
|
531
|
+
const notification = new Notification(title, {
|
|
532
|
+
lang: "en",
|
|
533
|
+
body: text,
|
|
534
|
+
icon
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
notification.onclick = () => {
|
|
538
|
+
window.focus();
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
} : () => {};
|
|
485
542
|
}
|
|
486
543
|
|
|
487
|
-
const JSENV_ERROR_OVERLAY_TAGNAME = "jsenv-error-overlay"
|
|
488
|
-
let displayJsenvErrorOverlay
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
.
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
544
|
+
const JSENV_ERROR_OVERLAY_TAGNAME = "jsenv-error-overlay";
|
|
545
|
+
let displayJsenvErrorOverlay;
|
|
546
|
+
|
|
547
|
+
{
|
|
548
|
+
displayJsenvErrorOverlay = params => {
|
|
549
|
+
let jsenvErrorOverlay = new JsenvErrorOverlay(params);
|
|
550
|
+
document.querySelectorAll(JSENV_ERROR_OVERLAY_TAGNAME).forEach(node => {
|
|
551
|
+
node.parentNode.removeChild(node);
|
|
552
|
+
});
|
|
553
|
+
document.body.appendChild(jsenvErrorOverlay);
|
|
554
|
+
|
|
498
555
|
const removeErrorOverlay = () => {
|
|
499
556
|
if (jsenvErrorOverlay && jsenvErrorOverlay.parentNode) {
|
|
500
|
-
document.body.removeChild(jsenvErrorOverlay)
|
|
501
|
-
jsenvErrorOverlay = null
|
|
557
|
+
document.body.removeChild(jsenvErrorOverlay);
|
|
558
|
+
jsenvErrorOverlay = null;
|
|
502
559
|
}
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
return removeErrorOverlay;
|
|
563
|
+
};
|
|
506
564
|
|
|
507
565
|
class JsenvErrorOverlay extends HTMLElement {
|
|
508
|
-
constructor({
|
|
509
|
-
|
|
510
|
-
|
|
566
|
+
constructor({
|
|
567
|
+
theme,
|
|
568
|
+
title,
|
|
569
|
+
text,
|
|
570
|
+
tip,
|
|
571
|
+
errorDetailsPromise
|
|
572
|
+
}) {
|
|
573
|
+
super();
|
|
574
|
+
this.root = this.attachShadow({
|
|
575
|
+
mode: "open"
|
|
576
|
+
});
|
|
511
577
|
this.root.innerHTML = `
|
|
512
578
|
<style>
|
|
513
579
|
${overlayCSS}
|
|
@@ -521,50 +587,60 @@ window.__supervisor__ = (() => {
|
|
|
521
587
|
<div class="tip">
|
|
522
588
|
${tip}
|
|
523
589
|
</div>
|
|
524
|
-
</div
|
|
590
|
+
</div>`;
|
|
591
|
+
|
|
525
592
|
this.root.querySelector(".backdrop").onclick = () => {
|
|
526
593
|
if (!this.parentNode) {
|
|
527
594
|
// not in document anymore
|
|
528
|
-
return
|
|
595
|
+
return;
|
|
529
596
|
}
|
|
530
|
-
|
|
531
|
-
this.
|
|
532
|
-
|
|
597
|
+
|
|
598
|
+
this.root.querySelector(".backdrop").onclick = null;
|
|
599
|
+
this.parentNode.removeChild(this);
|
|
600
|
+
};
|
|
601
|
+
|
|
533
602
|
if (errorDetailsPromise) {
|
|
534
|
-
errorDetailsPromise.then(
|
|
603
|
+
errorDetailsPromise.then(errorDetails => {
|
|
535
604
|
if (!errorDetails || !this.parentNode) {
|
|
536
|
-
return
|
|
605
|
+
return;
|
|
537
606
|
}
|
|
538
|
-
|
|
607
|
+
|
|
608
|
+
const {
|
|
609
|
+
codeFrame,
|
|
610
|
+
cause
|
|
611
|
+
} = errorDetails;
|
|
612
|
+
|
|
539
613
|
if (codeFrame) {
|
|
540
|
-
this.root.querySelector(".text").innerHTML += `\n\n${codeFrame}
|
|
614
|
+
this.root.querySelector(".text").innerHTML += `\n\n${codeFrame}`;
|
|
541
615
|
}
|
|
616
|
+
|
|
542
617
|
if (cause) {
|
|
543
|
-
const causeIndented = prefixRemainingLines(cause, " ")
|
|
544
|
-
this.root.querySelector(
|
|
545
|
-
".text",
|
|
546
|
-
).innerHTML += `\n [cause]: ${causeIndented}`
|
|
618
|
+
const causeIndented = prefixRemainingLines(cause, " ");
|
|
619
|
+
this.root.querySelector(".text").innerHTML += `\n [cause]: ${causeIndented}`;
|
|
547
620
|
}
|
|
548
|
-
})
|
|
621
|
+
});
|
|
549
622
|
}
|
|
550
623
|
}
|
|
624
|
+
|
|
551
625
|
}
|
|
552
626
|
|
|
553
627
|
const prefixRemainingLines = (text, prefix) => {
|
|
554
|
-
const lines = text.split(/\r?\n/)
|
|
555
|
-
const firstLine = lines.shift()
|
|
556
|
-
let result = firstLine
|
|
557
|
-
let i = 0
|
|
628
|
+
const lines = text.split(/\r?\n/);
|
|
629
|
+
const firstLine = lines.shift();
|
|
630
|
+
let result = firstLine;
|
|
631
|
+
let i = 0;
|
|
632
|
+
|
|
558
633
|
while (i < lines.length) {
|
|
559
|
-
const line = lines[i]
|
|
560
|
-
i
|
|
561
|
-
result += line.length ? `\n${prefix}${line}` : `\n
|
|
634
|
+
const line = lines[i];
|
|
635
|
+
i++;
|
|
636
|
+
result += line.length ? `\n${prefix}${line}` : `\n`;
|
|
562
637
|
}
|
|
563
|
-
|
|
564
|
-
|
|
638
|
+
|
|
639
|
+
return result;
|
|
640
|
+
};
|
|
565
641
|
|
|
566
642
|
if (customElements && !customElements.get(JSENV_ERROR_OVERLAY_TAGNAME)) {
|
|
567
|
-
customElements.define(JSENV_ERROR_OVERLAY_TAGNAME, JsenvErrorOverlay)
|
|
643
|
+
customElements.define(JSENV_ERROR_OVERLAY_TAGNAME, JsenvErrorOverlay);
|
|
568
644
|
}
|
|
569
645
|
|
|
570
646
|
const overlayCSS = `
|
|
@@ -641,13 +717,19 @@ window.__supervisor__ = (() => {
|
|
|
641
717
|
|
|
642
718
|
pre a {
|
|
643
719
|
color: inherit;
|
|
644
|
-
}
|
|
720
|
+
}`;
|
|
645
721
|
}
|
|
646
722
|
|
|
647
|
-
supervisor.createException = createException
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
723
|
+
supervisor.createException = createException;
|
|
724
|
+
|
|
725
|
+
supervisor.reportException = exception => {
|
|
726
|
+
const {
|
|
727
|
+
theme,
|
|
728
|
+
title,
|
|
729
|
+
text,
|
|
730
|
+
tip,
|
|
731
|
+
errorDetailsPromise
|
|
732
|
+
} = formatError(exception);
|
|
651
733
|
|
|
652
734
|
if (errorOverlay) {
|
|
653
735
|
const removeErrorOverlay = displayJsenvErrorOverlay({
|
|
@@ -655,30 +737,41 @@ window.__supervisor__ = (() => {
|
|
|
655
737
|
title,
|
|
656
738
|
text,
|
|
657
739
|
tip,
|
|
658
|
-
errorDetailsPromise
|
|
659
|
-
})
|
|
740
|
+
errorDetailsPromise
|
|
741
|
+
});
|
|
742
|
+
|
|
660
743
|
if (window.__reloader__) {
|
|
661
744
|
window.__reloader__.onstatuschange = () => {
|
|
662
745
|
if (window.__reloader__.status === "reloading") {
|
|
663
|
-
removeErrorOverlay()
|
|
746
|
+
removeErrorOverlay();
|
|
664
747
|
}
|
|
665
|
-
}
|
|
748
|
+
};
|
|
666
749
|
}
|
|
667
750
|
}
|
|
751
|
+
|
|
668
752
|
if (errorNotification) {
|
|
669
753
|
displayErrorNotification({
|
|
670
754
|
title,
|
|
671
|
-
text
|
|
672
|
-
})
|
|
755
|
+
text
|
|
756
|
+
});
|
|
673
757
|
}
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
758
|
+
|
|
759
|
+
return exception;
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
window.addEventListener("error", errorEvent => {
|
|
677
763
|
if (!errorEvent.isTrusted) {
|
|
678
764
|
// ignore custom error event (not sent by browser)
|
|
679
|
-
return
|
|
765
|
+
return;
|
|
680
766
|
}
|
|
681
|
-
|
|
767
|
+
|
|
768
|
+
const {
|
|
769
|
+
error,
|
|
770
|
+
message,
|
|
771
|
+
filename,
|
|
772
|
+
lineno,
|
|
773
|
+
colno
|
|
774
|
+
} = errorEvent;
|
|
682
775
|
const exception = supervisor.createException({
|
|
683
776
|
// when error is reported within a worker error is null
|
|
684
777
|
// but there is a message property on errorEvent
|
|
@@ -686,166 +779,249 @@ window.__supervisor__ = (() => {
|
|
|
686
779
|
reportedBy: "window_error_event",
|
|
687
780
|
url: filename,
|
|
688
781
|
line: lineno,
|
|
689
|
-
column: colno
|
|
690
|
-
})
|
|
691
|
-
supervisor.reportException(exception)
|
|
692
|
-
})
|
|
693
|
-
window.addEventListener("unhandledrejection",
|
|
782
|
+
column: colno
|
|
783
|
+
});
|
|
784
|
+
supervisor.reportException(exception);
|
|
785
|
+
});
|
|
786
|
+
window.addEventListener("unhandledrejection", event => {
|
|
694
787
|
if (event.defaultPrevented) {
|
|
695
|
-
return
|
|
788
|
+
return;
|
|
696
789
|
}
|
|
790
|
+
|
|
697
791
|
const exception = supervisor.createException({
|
|
698
792
|
reason: event.reason,
|
|
699
|
-
reportedBy: "window_unhandledrejection_event"
|
|
700
|
-
})
|
|
701
|
-
supervisor.reportException(exception)
|
|
702
|
-
})
|
|
703
|
-
}
|
|
793
|
+
reportedBy: "window_unhandledrejection_event"
|
|
794
|
+
});
|
|
795
|
+
supervisor.reportException(exception);
|
|
796
|
+
});
|
|
797
|
+
};
|
|
704
798
|
|
|
705
799
|
supervisor.setup = ({
|
|
706
800
|
rootDirectoryUrl,
|
|
707
801
|
logs,
|
|
708
|
-
measurePerf,
|
|
709
802
|
errorOverlay,
|
|
710
803
|
errorBaseUrl,
|
|
711
|
-
openInEditor
|
|
804
|
+
openInEditor
|
|
712
805
|
}) => {
|
|
713
806
|
supervisor.setupReportException({
|
|
714
807
|
rootDirectoryUrl,
|
|
715
808
|
errorOverlay,
|
|
716
809
|
errorBaseUrl,
|
|
717
|
-
openInEditor
|
|
718
|
-
})
|
|
810
|
+
openInEditor
|
|
811
|
+
});
|
|
812
|
+
const supervisedScripts = [];
|
|
813
|
+
const pendingPromises = []; // respect execution order
|
|
814
|
+
// - wait for classic scripts to be done (non async)
|
|
815
|
+
// - wait module script previous execution (non async)
|
|
816
|
+
// see https://gist.github.com/jakub-g/385ee6b41085303a53ad92c7c8afd7a6#typemodule-vs-non-module-typetextjavascript-vs-script-nomodule
|
|
817
|
+
|
|
818
|
+
const executionQueue = [];
|
|
819
|
+
let executing = false;
|
|
820
|
+
|
|
821
|
+
const addToExecutionQueue = async execution => {
|
|
822
|
+
if (execution.async) {
|
|
823
|
+
execution.start();
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if (executing) {
|
|
828
|
+
executionQueue.push(execution);
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
719
831
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
832
|
+
startThenDequeue(execution);
|
|
833
|
+
};
|
|
834
|
+
|
|
835
|
+
const startThenDequeue = async execution => {
|
|
836
|
+
executing = true;
|
|
837
|
+
const promise = execution.start();
|
|
838
|
+
await promise;
|
|
839
|
+
executing = false;
|
|
840
|
+
|
|
841
|
+
if (executionQueue.length) {
|
|
842
|
+
const nextExecution = executionQueue.shift();
|
|
843
|
+
startThenDequeue(nextExecution);
|
|
844
|
+
}
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
supervisor.addExecution = ({
|
|
848
|
+
type,
|
|
849
|
+
src,
|
|
850
|
+
async,
|
|
851
|
+
execute
|
|
852
|
+
}) => {
|
|
723
853
|
const execution = {
|
|
724
854
|
type,
|
|
725
855
|
src,
|
|
726
856
|
async,
|
|
727
|
-
execute
|
|
728
|
-
}
|
|
857
|
+
execute
|
|
858
|
+
};
|
|
859
|
+
|
|
729
860
|
execution.start = () => {
|
|
730
|
-
return superviseExecution(execution, {
|
|
731
|
-
|
|
861
|
+
return superviseExecution(execution, {
|
|
862
|
+
isReload: false
|
|
863
|
+
});
|
|
864
|
+
};
|
|
865
|
+
|
|
732
866
|
execution.reload = () => {
|
|
733
|
-
return superviseExecution(execution, {
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
867
|
+
return superviseExecution(execution, {
|
|
868
|
+
isReload: true
|
|
869
|
+
});
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
supervisedScripts.push(execution);
|
|
873
|
+
return addToExecutionQueue(execution);
|
|
874
|
+
};
|
|
875
|
+
|
|
876
|
+
const superviseExecution = async (execution, {
|
|
877
|
+
isReload
|
|
878
|
+
}) => {
|
|
739
879
|
if (logs) {
|
|
740
|
-
console.group(`[jsenv] loading ${execution.type} ${execution.src}`)
|
|
741
|
-
}
|
|
742
|
-
if (measurePerf) {
|
|
743
|
-
performance.mark(`execution_start`)
|
|
880
|
+
console.group(`[jsenv] loading ${execution.type} ${execution.src}`);
|
|
744
881
|
}
|
|
882
|
+
|
|
745
883
|
const executionResult = {
|
|
746
884
|
status: "pending",
|
|
747
|
-
|
|
748
|
-
|
|
885
|
+
loadDuration: null,
|
|
886
|
+
executionDuration: null,
|
|
887
|
+
duration: null,
|
|
749
888
|
exception: null,
|
|
750
889
|
namespace: null,
|
|
751
|
-
coverage: null
|
|
752
|
-
}
|
|
753
|
-
executionResults[execution.src] = executionResult
|
|
754
|
-
|
|
755
|
-
const
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
890
|
+
coverage: null
|
|
891
|
+
};
|
|
892
|
+
executionResults[execution.src] = executionResult;
|
|
893
|
+
|
|
894
|
+
const monitorScriptLoad = () => {
|
|
895
|
+
const loadStartTime = Date.now();
|
|
896
|
+
let resolveScriptLoadPromise;
|
|
897
|
+
const scriptLoadPromise = new Promise(resolve => {
|
|
898
|
+
resolveScriptLoadPromise = resolve;
|
|
899
|
+
});
|
|
900
|
+
pendingPromises.push(scriptLoadPromise);
|
|
901
|
+
return () => {
|
|
902
|
+
const loadEndTime = Date.now();
|
|
903
|
+
executionResult.loadDuration = loadEndTime - loadStartTime;
|
|
904
|
+
resolveScriptLoadPromise();
|
|
905
|
+
};
|
|
906
|
+
};
|
|
907
|
+
|
|
908
|
+
const monitorScriptExecution = () => {
|
|
909
|
+
const executionStartTime = Date.now();
|
|
910
|
+
let resolveExecutionPromise;
|
|
911
|
+
const executionPromise = new Promise(resolve => {
|
|
912
|
+
resolveExecutionPromise = resolve;
|
|
913
|
+
});
|
|
914
|
+
pendingPromises.push(executionPromise);
|
|
915
|
+
return () => {
|
|
916
|
+
executionResult.coverage = window.__coverage__;
|
|
917
|
+
executionResult.executionDuration = Date.now() - executionStartTime;
|
|
918
|
+
executionResult.duration = executionResult.loadDuration + executionResult.executionDuration;
|
|
919
|
+
resolveExecutionPromise();
|
|
920
|
+
};
|
|
921
|
+
};
|
|
922
|
+
|
|
923
|
+
const onError = e => {
|
|
924
|
+
executionResult.status = "errored";
|
|
925
|
+
const exception = supervisor.createException({
|
|
926
|
+
reason: e
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
if (exception.needsReport) {
|
|
930
|
+
supervisor.reportException(exception);
|
|
762
931
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
932
|
+
|
|
933
|
+
executionResult.exception = exception;
|
|
934
|
+
};
|
|
935
|
+
|
|
936
|
+
const scriptLoadDone = monitorScriptLoad();
|
|
937
|
+
|
|
766
938
|
try {
|
|
767
|
-
const result = await execution.execute({
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
939
|
+
const result = await execution.execute({
|
|
940
|
+
isReload
|
|
941
|
+
});
|
|
942
|
+
|
|
771
943
|
if (logs) {
|
|
772
|
-
console.log(`${execution.type} load ended`)
|
|
773
|
-
console.groupEnd()
|
|
944
|
+
console.log(`${execution.type} load ended`);
|
|
945
|
+
console.groupEnd();
|
|
774
946
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
const
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
947
|
+
|
|
948
|
+
executionResult.status = "loaded";
|
|
949
|
+
scriptLoadDone();
|
|
950
|
+
const scriptExecutionDone = monitorScriptExecution();
|
|
951
|
+
|
|
952
|
+
if (execution.type === "js_classic") {
|
|
953
|
+
executionResult.status = "completed";
|
|
954
|
+
scriptExecutionDone();
|
|
955
|
+
} else if (execution.type === "js_module") {
|
|
956
|
+
result.executionPromise.then(namespace => {
|
|
957
|
+
executionResult.status = "completed";
|
|
958
|
+
executionResult.namespace = namespace;
|
|
959
|
+
scriptExecutionDone();
|
|
960
|
+
}, e => {
|
|
961
|
+
onError(e);
|
|
962
|
+
scriptExecutionDone();
|
|
963
|
+
});
|
|
783
964
|
}
|
|
784
|
-
|
|
785
|
-
executionResult.coverage = window.__coverage__
|
|
965
|
+
} catch (e) {
|
|
786
966
|
if (logs) {
|
|
787
|
-
console.groupEnd()
|
|
967
|
+
console.groupEnd();
|
|
788
968
|
}
|
|
789
|
-
resolveScriptExecutionPromise()
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
969
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
// - wait module script previous execution (non async)
|
|
796
|
-
// see https://gist.github.com/jakub-g/385ee6b41085303a53ad92c7c8afd7a6#typemodule-vs-non-module-typetextjavascript-vs-script-nomodule
|
|
797
|
-
supervisor.getPreviousExecutionDonePromise = async () => {
|
|
798
|
-
const previousNonAsyncScriptExecutions = scriptExecutionPromises.filter(
|
|
799
|
-
(promise) => !promise.execution.async,
|
|
800
|
-
)
|
|
801
|
-
await Promise.all(previousNonAsyncScriptExecutions)
|
|
802
|
-
}
|
|
803
|
-
supervisor.superviseScript = async ({ src, async }) => {
|
|
804
|
-
const { currentScript } = document
|
|
805
|
-
const parentNode = currentScript.parentNode
|
|
806
|
-
if (!async) {
|
|
807
|
-
await supervisor.getPreviousExecutionDonePromise()
|
|
970
|
+
onError(e);
|
|
971
|
+
scriptLoadDone();
|
|
808
972
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
973
|
+
};
|
|
974
|
+
|
|
975
|
+
supervisor.superviseScript = async ({
|
|
976
|
+
src,
|
|
977
|
+
async
|
|
978
|
+
}) => {
|
|
979
|
+
const {
|
|
980
|
+
currentScript
|
|
981
|
+
} = document;
|
|
982
|
+
const parentNode = currentScript.parentNode;
|
|
983
|
+
let nodeToReplace;
|
|
984
|
+
let currentScriptClone;
|
|
985
|
+
return supervisor.addExecution({
|
|
812
986
|
src,
|
|
813
987
|
type: "js_classic",
|
|
814
988
|
async,
|
|
815
|
-
execute: async ({
|
|
816
|
-
|
|
989
|
+
execute: async ({
|
|
990
|
+
isReload
|
|
991
|
+
}) => {
|
|
992
|
+
const urlObject = new URL(src, window.location);
|
|
817
993
|
const loadPromise = new Promise((resolve, reject) => {
|
|
818
994
|
// do not use script.cloneNode()
|
|
819
995
|
// bcause https://stackoverflow.com/questions/28771542/why-dont-clonenode-script-tags-execute
|
|
820
|
-
currentScriptClone = document.createElement("script")
|
|
821
|
-
// browsers set async by default when creating script(s)
|
|
996
|
+
currentScriptClone = document.createElement("script"); // browsers set async by default when creating script(s)
|
|
822
997
|
// we want an exact copy to preserves how code is executed
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
})
|
|
998
|
+
|
|
999
|
+
currentScriptClone.async = false;
|
|
1000
|
+
Array.from(currentScript.attributes).forEach(attribute => {
|
|
1001
|
+
currentScriptClone.setAttribute(attribute.nodeName, attribute.nodeValue);
|
|
1002
|
+
});
|
|
1003
|
+
|
|
830
1004
|
if (isReload) {
|
|
831
|
-
urlObject.searchParams.set("hmr", Date.now())
|
|
832
|
-
nodeToReplace = currentScriptClone
|
|
833
|
-
currentScriptClone.src = urlObject.href
|
|
1005
|
+
urlObject.searchParams.set("hmr", Date.now());
|
|
1006
|
+
nodeToReplace = currentScriptClone;
|
|
1007
|
+
currentScriptClone.src = urlObject.href;
|
|
834
1008
|
} else {
|
|
835
|
-
currentScriptClone.removeAttribute("jsenv-plugin-owner")
|
|
836
|
-
currentScriptClone.removeAttribute("jsenv-plugin-action")
|
|
837
|
-
currentScriptClone.removeAttribute("inlined-from-src")
|
|
838
|
-
currentScriptClone.removeAttribute("original-position")
|
|
839
|
-
currentScriptClone.removeAttribute("original-src-position")
|
|
840
|
-
nodeToReplace = currentScript
|
|
841
|
-
currentScriptClone.src = src
|
|
1009
|
+
currentScriptClone.removeAttribute("jsenv-plugin-owner");
|
|
1010
|
+
currentScriptClone.removeAttribute("jsenv-plugin-action");
|
|
1011
|
+
currentScriptClone.removeAttribute("inlined-from-src");
|
|
1012
|
+
currentScriptClone.removeAttribute("original-position");
|
|
1013
|
+
currentScriptClone.removeAttribute("original-src-position");
|
|
1014
|
+
nodeToReplace = currentScript;
|
|
1015
|
+
currentScriptClone.src = src;
|
|
842
1016
|
}
|
|
843
|
-
|
|
844
|
-
currentScriptClone.addEventListener("
|
|
845
|
-
|
|
846
|
-
|
|
1017
|
+
|
|
1018
|
+
currentScriptClone.addEventListener("error", reject);
|
|
1019
|
+
currentScriptClone.addEventListener("load", resolve);
|
|
1020
|
+
parentNode.replaceChild(currentScriptClone, nodeToReplace);
|
|
1021
|
+
});
|
|
1022
|
+
|
|
847
1023
|
try {
|
|
848
|
-
await loadPromise
|
|
1024
|
+
await loadPromise;
|
|
849
1025
|
} catch (e) {
|
|
850
1026
|
// eslint-disable-next-line no-throw-literal
|
|
851
1027
|
throw {
|
|
@@ -853,63 +1029,73 @@ window.__supervisor__ = (() => {
|
|
|
853
1029
|
reportedBy: "script_error_event",
|
|
854
1030
|
url: urlObject.href,
|
|
855
1031
|
// window.error won't be dispatched for this error
|
|
856
|
-
needsReport: true
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
},
|
|
860
|
-
})
|
|
861
|
-
return execution.start()
|
|
862
|
-
}
|
|
863
|
-
supervisor.reloadSupervisedScript = ({ type, src }) => {
|
|
864
|
-
const supervisedScript = supervisedScripts.find(
|
|
865
|
-
(supervisedScriptCandidate) => {
|
|
866
|
-
if (type && supervisedScriptCandidate.type !== type) {
|
|
867
|
-
return false
|
|
868
|
-
}
|
|
869
|
-
if (supervisedScriptCandidate.src !== src) {
|
|
870
|
-
return false
|
|
1032
|
+
needsReport: true
|
|
1033
|
+
};
|
|
871
1034
|
}
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
1035
|
+
}
|
|
1036
|
+
});
|
|
1037
|
+
};
|
|
1038
|
+
|
|
1039
|
+
supervisor.reloadSupervisedScript = ({
|
|
1040
|
+
type,
|
|
1041
|
+
src
|
|
1042
|
+
}) => {
|
|
1043
|
+
const supervisedScript = supervisedScripts.find(supervisedScriptCandidate => {
|
|
1044
|
+
if (type && supervisedScriptCandidate.type !== type) {
|
|
1045
|
+
return false;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
if (supervisedScriptCandidate.src !== src) {
|
|
1049
|
+
return false;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
return true;
|
|
1053
|
+
});
|
|
1054
|
+
|
|
875
1055
|
if (supervisedScript) {
|
|
876
|
-
supervisedScript.reload()
|
|
1056
|
+
supervisedScript.reload();
|
|
877
1057
|
}
|
|
878
|
-
}
|
|
1058
|
+
};
|
|
1059
|
+
|
|
879
1060
|
supervisor.getDocumentExecutionResult = async () => {
|
|
880
1061
|
// just to be super safe and ensure any <script type="module"> got a chance to execute
|
|
881
|
-
const documentReadyPromise = new Promise(
|
|
1062
|
+
const documentReadyPromise = new Promise(resolve => {
|
|
882
1063
|
if (document.readyState === "complete") {
|
|
883
|
-
resolve()
|
|
884
|
-
return
|
|
1064
|
+
resolve();
|
|
1065
|
+
return;
|
|
885
1066
|
}
|
|
1067
|
+
|
|
886
1068
|
const loadCallback = () => {
|
|
887
|
-
window.removeEventListener("load", loadCallback)
|
|
888
|
-
resolve()
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
1069
|
+
window.removeEventListener("load", loadCallback);
|
|
1070
|
+
resolve();
|
|
1071
|
+
};
|
|
1072
|
+
|
|
1073
|
+
window.addEventListener("load", loadCallback);
|
|
1074
|
+
});
|
|
1075
|
+
await documentReadyPromise;
|
|
1076
|
+
|
|
893
1077
|
const waitScriptExecutions = async () => {
|
|
894
|
-
const
|
|
895
|
-
await Promise.all(
|
|
896
|
-
// new scripts added while the other where executing
|
|
1078
|
+
const numberOfPromises = pendingPromises.length;
|
|
1079
|
+
await Promise.all(pendingPromises); // new scripts added while the other where executing
|
|
897
1080
|
// (should happen only on webkit where
|
|
898
1081
|
// script might be added after window load event)
|
|
899
|
-
|
|
900
|
-
|
|
1082
|
+
|
|
1083
|
+
await new Promise(resolve => setTimeout(resolve));
|
|
1084
|
+
|
|
1085
|
+
if (pendingPromises.length > numberOfPromises) {
|
|
1086
|
+
await waitScriptExecutions();
|
|
901
1087
|
}
|
|
902
|
-
}
|
|
903
|
-
await waitScriptExecutions()
|
|
1088
|
+
};
|
|
904
1089
|
|
|
1090
|
+
await waitScriptExecutions();
|
|
905
1091
|
return {
|
|
906
1092
|
status: "completed",
|
|
907
1093
|
executionResults,
|
|
908
1094
|
startTime: navigationStartTime,
|
|
909
|
-
endTime: Date.now()
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
}
|
|
1095
|
+
endTime: Date.now()
|
|
1096
|
+
};
|
|
1097
|
+
};
|
|
1098
|
+
};
|
|
913
1099
|
|
|
914
|
-
return supervisor
|
|
915
|
-
})()
|
|
1100
|
+
return supervisor;
|
|
1101
|
+
})();
|