@jsenv/core 28.0.2 → 28.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/controllable_child_process.mjs +1 -2
  2. package/dist/controllable_worker_thread.mjs +1 -2
  3. package/dist/js/autoreload.js +25 -9
  4. package/dist/js/execute_using_dynamic_import.js +804 -1
  5. package/dist/js/script_type_module_supervisor.js +129 -0
  6. package/dist/js/supervisor.js +921 -0
  7. package/dist/main.js +432 -492
  8. package/package.json +13 -13
  9. package/readme.md +1 -1
  10. package/src/build/inject_global_version_mappings.js +3 -3
  11. package/src/dev/start_dev_server.js +2 -2
  12. package/src/execute/execute.js +1 -1
  13. package/src/execute/run.js +26 -38
  14. package/src/execute/runtimes/browsers/from_playwright.js +51 -77
  15. package/src/execute/runtimes/node/node_child_process.js +36 -36
  16. package/src/execute/runtimes/node/node_worker_thread.js +36 -36
  17. package/src/omega/kitchen.js +12 -9
  18. package/src/omega/omega_server.js +2 -2
  19. package/src/omega/server/file_service.js +2 -2
  20. package/src/omega/url_graph/url_info_transformations.js +8 -1
  21. package/src/plugins/autoreload/client/reload.js +20 -7
  22. package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +4 -4
  23. package/src/plugins/import_meta_hot/html_hot_dependencies.js +2 -2
  24. package/src/plugins/importmap/jsenv_plugin_importmap.js +5 -3
  25. package/src/plugins/inject_globals/inject_globals.js +3 -3
  26. package/src/plugins/inline/jsenv_plugin_data_urls.js +1 -1
  27. package/src/plugins/inline/jsenv_plugin_html_inline_content.js +10 -5
  28. package/src/plugins/plugins.js +5 -5
  29. package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +4 -4
  30. package/src/plugins/supervisor/client/script_type_module_supervisor.js +108 -0
  31. package/src/plugins/supervisor/client/supervisor.js +921 -0
  32. package/src/plugins/{html_supervisor/jsenv_plugin_html_supervisor.js → supervisor/jsenv_plugin_supervisor.js} +128 -102
  33. package/src/plugins/toolbar/client/execution/toolbar_execution.js +1 -1
  34. package/src/plugins/toolbar/jsenv_plugin_toolbar.js +4 -4
  35. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +7 -5
  36. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +5 -4
  37. package/src/plugins/transpilation/babel/jsenv_plugin_babel.js +13 -7
  38. package/src/plugins/transpilation/babel/new_stylesheet/babel_plugin_new_stylesheet_as_jsenv_import.js +6 -4
  39. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +4 -2
  40. package/src/plugins/url_analysis/html/html_urls.js +11 -10
  41. package/src/test/coverage/babel_plugin_instrument.js +1 -35
  42. package/src/test/coverage/empty_coverage_factory.js +1 -1
  43. package/src/test/execute_plan.js +7 -3
  44. package/src/test/execute_test_plan.js +2 -1
  45. package/src/test/logs_file_execution.js +49 -8
  46. package/dist/js/html_supervisor_installer.js +0 -1091
  47. package/dist/js/html_supervisor_setup.js +0 -89
  48. package/dist/js/uneval.js +0 -804
  49. package/src/plugins/html_supervisor/client/error_formatter.js +0 -426
  50. package/src/plugins/html_supervisor/client/error_in_notification.js +0 -21
  51. package/src/plugins/html_supervisor/client/error_overlay.js +0 -191
  52. package/src/plugins/html_supervisor/client/html_supervisor_installer.js +0 -315
  53. package/src/plugins/html_supervisor/client/html_supervisor_setup.js +0 -89
  54. package/src/plugins/html_supervisor/client/perf_browser.js +0 -17
  55. package/src/plugins/html_supervisor/client/uneval_exception.js +0 -8
@@ -1,426 +0,0 @@
1
- export const formatError = (
2
- error,
3
- { rootDirectoryUrl, errorBaseUrl, openInEditor, url, line, column },
4
- ) => {
5
- let { message, stack } = normalizeErrorParts(error)
6
- let errorDetailsPromiseReference = { current: null }
7
- let tip = `Reported by the browser while executing <code>${window.location.pathname}${window.location.search}</code>.`
8
- let errorUrlSite
9
-
10
- const errorMeta = extractErrorMeta(error, { url, line, column })
11
-
12
- const resolveUrlSite = ({ url, line, column }) => {
13
- if (typeof line === "string") line = parseInt(line)
14
- if (typeof column === "string") column = parseInt(column)
15
-
16
- const inlineUrlMatch = url.match(
17
- /@L([0-9]+)C([0-9]+)\-L([0-9]+)C([0-9]+)(\.[\w]+)$/,
18
- )
19
- if (inlineUrlMatch) {
20
- const htmlUrl = url.slice(0, inlineUrlMatch.index)
21
- const tagLineStart = parseInt(inlineUrlMatch[1])
22
- const tagColumnStart = parseInt(inlineUrlMatch[2])
23
- const tagLineEnd = parseInt(inlineUrlMatch[3])
24
- const tagColumnEnd = parseInt(inlineUrlMatch[4])
25
- const extension = inlineUrlMatch[5]
26
- url = htmlUrl
27
- line = tagLineStart + (typeof line === "number" ? line : 0)
28
- // stackTrace formatted by V8 (chrome)
29
- if (Error.captureStackTrace) {
30
- line--
31
- }
32
- if (errorMeta.type === "dynamic_import_syntax_error") {
33
- // syntax error on inline script need line-1 for some reason
34
- if (Error.captureStackTrace) {
35
- line--
36
- } else {
37
- // firefox and safari need line-2
38
- line -= 2
39
- }
40
- }
41
- column = tagColumnStart + (typeof column === "number" ? column : 0)
42
- const fileUrl = resolveFileUrl(url)
43
- return {
44
- isInline: true,
45
- originalUrl: `${fileUrl}@L${tagLineStart}C${tagColumnStart}-L${tagLineEnd}C${tagColumnEnd}${extension}`,
46
- url: fileUrl,
47
- line,
48
- column,
49
- }
50
- }
51
- return {
52
- isInline: false,
53
- url: resolveFileUrl(url),
54
- line,
55
- column,
56
- }
57
- }
58
-
59
- const resolveFileUrl = (url) => {
60
- let urlObject = new URL(url)
61
- if (urlObject.origin === window.origin) {
62
- urlObject = new URL(
63
- `${urlObject.pathname.slice(1)}${urlObject.search}`,
64
- rootDirectoryUrl,
65
- )
66
- }
67
- if (urlObject.href.startsWith("file:")) {
68
- const atFsIndex = urlObject.pathname.indexOf("/@fs/")
69
- if (atFsIndex > -1) {
70
- const afterAtFs = urlObject.pathname.slice(atFsIndex + "/@fs/".length)
71
- return new URL(afterAtFs, "file:///").href
72
- }
73
- }
74
- return urlObject.href
75
- }
76
-
77
- const generateClickableText = (text) => {
78
- const textWithHtmlLinks = makeLinksClickable(text, {
79
- createLink: (url, { line, column }) => {
80
- const urlSite = resolveUrlSite({ url, line, column })
81
- if (!errorUrlSite && text === stack) {
82
- onErrorLocated(urlSite, "error.stack")
83
- }
84
- if (errorBaseUrl) {
85
- if (urlSite.url.startsWith(rootDirectoryUrl)) {
86
- urlSite.url = `${errorBaseUrl}${urlSite.url.slice(
87
- rootDirectoryUrl.length,
88
- )}`
89
- } else {
90
- urlSite.url = "file:///mocked_for_snapshots"
91
- }
92
- }
93
- const urlWithLineAndColumn = formatUrlWithLineAndColumn(urlSite)
94
- return {
95
- href:
96
- url.startsWith("file:") && openInEditor
97
- ? `javascript:window.fetch('/__open_in_editor__/${urlWithLineAndColumn}')`
98
- : urlSite.url,
99
- text: urlWithLineAndColumn,
100
- }
101
- },
102
- })
103
- return textWithHtmlLinks
104
- }
105
-
106
- const formatErrorText = ({ message, stack, codeFrame }) => {
107
- let text
108
- if (message && stack) {
109
- text = `${generateClickableText(message)}\n${generateClickableText(
110
- stack,
111
- )}`
112
- } else if (stack) {
113
- text = generateClickableText(stack)
114
- } else {
115
- text = generateClickableText(message)
116
- }
117
- if (codeFrame) {
118
- text += `\n\n${generateClickableText(codeFrame)}`
119
- }
120
- return text
121
- }
122
-
123
- const onErrorLocated = (urlSite) => {
124
- errorUrlSite = urlSite
125
- errorDetailsPromiseReference.current = (async () => {
126
- try {
127
- if (errorMeta.type === "dynamic_import_fetch_error") {
128
- const response = await window.fetch(
129
- `/__get_error_cause__/${
130
- urlSite.isInline ? urlSite.originalUrl : urlSite.url
131
- }`,
132
- )
133
-
134
- if (response.status !== 200) {
135
- return null
136
- }
137
- const causeInfo = await response.json()
138
- if (!causeInfo) {
139
- return null
140
- }
141
-
142
- const causeText =
143
- causeInfo.code === "NOT_FOUND"
144
- ? formatErrorText({
145
- message: causeInfo.reason,
146
- stack: causeInfo.codeFrame,
147
- })
148
- : formatErrorText({
149
- message: causeInfo.stack,
150
- stack: causeInfo.codeFrame,
151
- })
152
- return {
153
- cause: causeText,
154
- }
155
- }
156
- if (urlSite.line !== undefined) {
157
- let resourceToFetch = `/__get_code_frame__/${formatUrlWithLineAndColumn(
158
- urlSite,
159
- )}`
160
- if (!Error.captureStackTrace) {
161
- resourceToFetch += `?remap`
162
- }
163
- const response = await window.fetch(resourceToFetch)
164
- const codeFrame = await response.text()
165
- return {
166
- codeFrame: formatErrorText({ message: codeFrame }),
167
- }
168
- }
169
- } catch (e) {
170
- // happens if server is closed for instance
171
- return null
172
- }
173
- return null
174
- })()
175
- }
176
-
177
- // error.stack is more reliable than url/line/column reported on window error events
178
- // so use it only when error.stack is not available
179
- if (
180
- url &&
181
- !stack &&
182
- // ignore window.reportError() it gives no valuable info
183
- !url.endsWith("html_supervisor_installer.js")
184
- ) {
185
- onErrorLocated(resolveUrlSite({ url, line, column }))
186
- } else if (errorMeta.url) {
187
- onErrorLocated(resolveUrlSite(errorMeta))
188
- }
189
-
190
- return {
191
- theme:
192
- error && error.cause && error.cause.code === "PARSE_ERROR"
193
- ? "light"
194
- : "dark",
195
- title: "An error occured",
196
- text: formatErrorText({ message, stack }),
197
- tip: `${tip}
198
- <br />
199
- Click outside to close.`,
200
- errorDetailsPromise: errorDetailsPromiseReference.current,
201
- }
202
- }
203
-
204
- const extractErrorMeta = (error, { line }) => {
205
- if (!error) {
206
- return {}
207
- }
208
- const { message } = error
209
- if (!message) {
210
- return {}
211
- }
212
-
213
- export_missing: {
214
- // chrome
215
- if (message.includes("does not provide an export named")) {
216
- return {
217
- type: "dynamic_import_export_missing",
218
- }
219
- }
220
- // firefox
221
- if (message.startsWith("import not found:")) {
222
- return {
223
- type: "dynamic_import_export_missing",
224
- browser: "firefox",
225
- }
226
- }
227
- // safari
228
- if (message.startsWith("import binding name")) {
229
- return {
230
- type: "dynamic_import_export_missing",
231
- }
232
- }
233
- }
234
-
235
- js_syntax_error: {
236
- if (error.name === "SyntaxError" && typeof line === "number") {
237
- return {
238
- type: "dynamic_import_syntax_error",
239
- }
240
- }
241
- }
242
-
243
- fetch_error: {
244
- // chrome
245
- if (message.startsWith("Failed to fetch dynamically imported module: ")) {
246
- const url = error.message.slice(
247
- "Failed to fetch dynamically imported module: ".length,
248
- )
249
- return {
250
- type: "dynamic_import_fetch_error",
251
- url,
252
- }
253
- }
254
- // firefox
255
- if (message === "error loading dynamically imported module") {
256
- return {
257
- type: "dynamic_import_fetch_error",
258
- }
259
- }
260
- // safari
261
- if (message === "Importing a module script failed.") {
262
- return {
263
- type: "dynamic_import_fetch_error",
264
- }
265
- }
266
- }
267
-
268
- return {}
269
- }
270
-
271
- const formatUrlWithLineAndColumn = ({ url, line, column }) => {
272
- return line === undefined && column === undefined
273
- ? url
274
- : column === undefined
275
- ? `${url}:${line}`
276
- : `${url}:${line}:${column}`
277
- }
278
-
279
- const normalizeErrorParts = (error) => {
280
- if (error === undefined) {
281
- return {
282
- message: "undefined",
283
- }
284
- }
285
- if (error === null) {
286
- return {
287
- message: "null",
288
- }
289
- }
290
- if (typeof error === "string") {
291
- return {
292
- message: error,
293
- }
294
- }
295
- if (error instanceof Error) {
296
- if (error.name === "SyntaxError") {
297
- return {
298
- message: error.message,
299
- }
300
- }
301
- if (error.cause && error.cause.code === "PARSE_ERROR") {
302
- if (error.messageHTML) {
303
- return {
304
- message: error.messageHTML,
305
- }
306
- }
307
- return {
308
- message: error.message,
309
- }
310
- }
311
- // stackTrace formatted by V8
312
- if (Error.captureStackTrace) {
313
- return {
314
- message: error.message,
315
- stack: getErrorStackWithoutErrorMessage(error),
316
- }
317
- }
318
- return {
319
- message: error.message,
320
- stack: error.stack ? ` ${error.stack}` : null,
321
- }
322
- }
323
- if (typeof error === "object") {
324
- return error
325
- }
326
- return {
327
- message: JSON.stringify(error),
328
- }
329
- }
330
-
331
- const getErrorStackWithoutErrorMessage = (error) => {
332
- let stack = error.stack
333
- const messageInStack = `${error.name}: ${error.message}`
334
- if (stack.startsWith(messageInStack)) {
335
- stack = stack.slice(messageInStack.length)
336
- }
337
- const nextLineIndex = stack.indexOf("\n")
338
- if (nextLineIndex > -1) {
339
- stack = stack.slice(nextLineIndex + 1)
340
- }
341
- return stack
342
- }
343
-
344
- const makeLinksClickable = (string, { createLink = (url) => url }) => {
345
- // normalize line breaks
346
- string = string.replace(/\n/g, "\n")
347
- string = escapeHtml(string)
348
- // render links
349
- string = stringToStringWithLink(string, {
350
- transform: (url, { line, column }) => {
351
- const { href, text } = createLink(url, { line, column })
352
- return link({ href, text })
353
- },
354
- })
355
- return string
356
- }
357
-
358
- const escapeHtml = (string) => {
359
- return string
360
- .replace(/&/g, "&amp;")
361
- .replace(/</g, "&lt;")
362
- .replace(/>/g, "&gt;")
363
- .replace(/"/g, "&quot;")
364
- .replace(/'/g, "&#039;")
365
- }
366
-
367
- // `Error: yo
368
- // at Object.execute (http://127.0.0.1:57300/build/src/__test__/file-throw.js:9:13)
369
- // at doExec (http://127.0.0.1:3000/src/__test__/file-throw.js:452:38)
370
- // at postOrderExec (http://127.0.0.1:3000/src/__test__/file-throw.js:448:16)
371
- // at http://127.0.0.1:3000/src/__test__/file-throw.js:399:18`.replace(/(?:https?|ftp|file):\/\/(.*+)$/gm, (...args) => {
372
- // debugger
373
- // })
374
- const stringToStringWithLink = (
375
- source,
376
- {
377
- transform = (url) => {
378
- return {
379
- href: url,
380
- text: url,
381
- }
382
- },
383
- } = {},
384
- ) => {
385
- return source.replace(/(?:https?|ftp|file):\/\/\S+/gm, (match) => {
386
- let linkHTML = ""
387
-
388
- const lastChar = match[match.length - 1]
389
-
390
- // hotfix because our url regex sucks a bit
391
- const endsWithSeparationChar = lastChar === ")" || lastChar === ":"
392
- if (endsWithSeparationChar) {
393
- match = match.slice(0, -1)
394
- }
395
-
396
- const lineAndColumnPattern = /:([0-9]+):([0-9]+)$/
397
- const lineAndColumMatch = match.match(lineAndColumnPattern)
398
- if (lineAndColumMatch) {
399
- const lineAndColumnString = lineAndColumMatch[0]
400
- const lineNumber = lineAndColumMatch[1]
401
- const columnNumber = lineAndColumMatch[2]
402
- linkHTML = transform(match.slice(0, -lineAndColumnString.length), {
403
- line: lineNumber,
404
- column: columnNumber,
405
- })
406
- } else {
407
- const linePattern = /:([0-9]+)$/
408
- const lineMatch = match.match(linePattern)
409
- if (lineMatch) {
410
- const lineString = lineMatch[0]
411
- const lineNumber = lineMatch[1]
412
- linkHTML = transform(match.slice(0, -lineString.length), {
413
- line: lineNumber,
414
- })
415
- } else {
416
- linkHTML = transform(match, {})
417
- }
418
- }
419
- if (endsWithSeparationChar) {
420
- return `${linkHTML}${lastChar}`
421
- }
422
- return linkHTML
423
- })
424
- }
425
-
426
- const link = ({ href, text = href }) => `<a href="${href}">${text}</a>`
@@ -1,21 +0,0 @@
1
- const { Notification } = window
2
-
3
- const displayErrorNotificationNotAvailable = () => {}
4
-
5
- const displayErrorNotificationImplementation = (error, { icon } = {}) => {
6
- if (Notification.permission === "granted") {
7
- const notification = new Notification("An error occured", {
8
- lang: "en",
9
- body: error ? error.stack : "undefined",
10
- icon,
11
- })
12
- notification.onclick = () => {
13
- window.focus()
14
- }
15
- }
16
- }
17
-
18
- export const displayErrorNotification =
19
- typeof Notification === "function"
20
- ? displayErrorNotificationImplementation
21
- : displayErrorNotificationNotAvailable
@@ -1,191 +0,0 @@
1
- import { formatError } from "./error_formatter.js"
2
-
3
- const JSENV_ERROR_OVERLAY_TAGNAME = "jsenv-error-overlay"
4
-
5
- export const displayErrorInDocument = (
6
- error,
7
- {
8
- rootDirectoryUrl,
9
- errorBaseUrl,
10
- openInEditor,
11
- url,
12
- line,
13
- column,
14
- codeFrame,
15
- },
16
- ) => {
17
- const { theme, title, text, tip, errorDetailsPromise } = formatError(error, {
18
- rootDirectoryUrl,
19
- errorBaseUrl,
20
- openInEditor,
21
- url,
22
- line,
23
- column,
24
- codeFrame,
25
- })
26
-
27
- let jsenvErrorOverlay = new JsenvErrorOverlay({
28
- theme,
29
- title,
30
- text,
31
- tip,
32
- errorDetailsPromise,
33
- })
34
- document.querySelectorAll(JSENV_ERROR_OVERLAY_TAGNAME).forEach((node) => {
35
- node.parentNode.removeChild(node)
36
- })
37
- document.body.appendChild(jsenvErrorOverlay)
38
- const removeErrorOverlay = () => {
39
- if (jsenvErrorOverlay && jsenvErrorOverlay.parentNode) {
40
- document.body.removeChild(jsenvErrorOverlay)
41
- jsenvErrorOverlay = null
42
- }
43
- }
44
- if (window.__reloader__) {
45
- window.__reloader__.onstatuschange = () => {
46
- if (window.__reloader__.status === "reloading") {
47
- removeErrorOverlay()
48
- }
49
- }
50
- }
51
- return removeErrorOverlay
52
- }
53
-
54
- class JsenvErrorOverlay extends HTMLElement {
55
- constructor({ theme, title, text, tip, errorDetailsPromise }) {
56
- super()
57
- this.root = this.attachShadow({ mode: "open" })
58
- this.root.innerHTML = `
59
- <style>
60
- ${overlayCSS}
61
- </style>
62
- <div class="backdrop"></div>
63
- <div class="overlay" data-theme=${theme}>
64
- <h1 class="title">
65
- ${title}
66
- </h1>
67
- <pre class="text">${text}</pre>
68
- <div class="tip">
69
- ${tip}
70
- </div>
71
- </div>`
72
- this.root.querySelector(".backdrop").onclick = () => {
73
- if (!this.parentNode) {
74
- // not in document anymore
75
- return
76
- }
77
- this.root.querySelector(".backdrop").onclick = null
78
- this.parentNode.removeChild(this)
79
- }
80
- if (errorDetailsPromise) {
81
- errorDetailsPromise.then((errorDetails) => {
82
- if (!errorDetails || !this.parentNode) {
83
- return
84
- }
85
- const { codeFrame, cause } = errorDetails
86
- if (codeFrame) {
87
- this.root.querySelector(".text").innerHTML += `\n\n${codeFrame}`
88
- }
89
- if (cause) {
90
- const causeIndented = prefixRemainingLines(cause, " ")
91
- this.root.querySelector(
92
- ".text",
93
- ).innerHTML += `\n [cause]: ${causeIndented}`
94
- }
95
- })
96
- }
97
- }
98
- }
99
-
100
- const prefixRemainingLines = (text, prefix) => {
101
- const lines = text.split(/\r?\n/)
102
- const firstLine = lines.shift()
103
- let result = firstLine
104
- let i = 0
105
- while (i < lines.length) {
106
- const line = lines[i]
107
- i++
108
- result += line.length ? `\n${prefix}${line}` : `\n`
109
- }
110
- return result
111
- }
112
-
113
- if (customElements && !customElements.get(JSENV_ERROR_OVERLAY_TAGNAME)) {
114
- customElements.define(JSENV_ERROR_OVERLAY_TAGNAME, JsenvErrorOverlay)
115
- }
116
-
117
- const overlayCSS = `
118
- :host {
119
- position: fixed;
120
- z-index: 99999;
121
- top: 0;
122
- left: 0;
123
- width: 100%;
124
- height: 100%;
125
- overflow-y: scroll;
126
- margin: 0;
127
- background: rgba(0, 0, 0, 0.66);
128
- }
129
-
130
- .backdrop {
131
- position: absolute;
132
- left: 0;
133
- right: 0;
134
- top: 0;
135
- bottom: 0;
136
- }
137
-
138
- .overlay {
139
- position: relative;
140
- background: rgba(0, 0, 0, 0.95);
141
- width: 800px;
142
- margin: 30px auto;
143
- padding: 25px 40px;
144
- padding-top: 0;
145
- overflow: hidden; /* for h1 margins */
146
- border-radius: 4px 8px;
147
- box-shadow: 0 20px 40px rgb(0 0 0 / 30%), 0 15px 12px rgb(0 0 0 / 20%);
148
- box-sizing: border-box;
149
- font-family: monospace;
150
- direction: ltr;
151
- }
152
-
153
- h1 {
154
- color: red;
155
- text-align: center;
156
- }
157
-
158
- pre {
159
- overflow: auto;
160
- max-width: 100%;
161
- /* padding is nice + prevents scrollbar from hiding the text behind it */
162
- /* does not work nicely on firefox though https://bugzilla.mozilla.org/show_bug.cgi?id=748518 */
163
- padding: 20px;
164
- }
165
-
166
- .tip {
167
- border-top: 1px solid #999;
168
- padding-top: 12px;
169
- }
170
-
171
- [data-theme="dark"] {
172
- color: #999;
173
- }
174
- [data-theme="dark"] pre {
175
- background: #111;
176
- border: 1px solid #333;
177
- color: #eee;
178
- }
179
-
180
- [data-theme="light"] {
181
- color: #EEEEEE;
182
- }
183
- [data-theme="light"] pre {
184
- background: #1E1E1E;
185
- border: 1px solid white;
186
- color: #EEEEEE;
187
- }
188
-
189
- pre a {
190
- color: inherit;
191
- }`