@jsenv/core 27.5.2 → 27.6.1

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.
@@ -88,11 +88,15 @@ export const installHtmlSupervisor = ({
88
88
  let completed
89
89
  let result
90
90
  let error
91
+ const urlObject = new URL(src, window.location)
92
+ if (reload) {
93
+ urlObject.searchParams.set("hmr", Date.now())
94
+ }
95
+ __html_supervisor__.currentExecution = {
96
+ type: type === "module" ? "dynamic_import" : "script_injection",
97
+ url: urlObject.href,
98
+ }
91
99
  try {
92
- const urlObject = new URL(src, window.location)
93
- if (reload) {
94
- urlObject.searchParams.set("hmr", Date.now())
95
- }
96
100
  result = await execute(urlObject.href)
97
101
  completed = true
98
102
  } catch (e) {
@@ -110,6 +114,7 @@ export const installHtmlSupervisor = ({
110
114
  console.log(`${type} load ended`)
111
115
  console.groupEnd()
112
116
  }
117
+ __html_supervisor__.currentExecution = null
113
118
  return
114
119
  }
115
120
  const executionResult = {
@@ -140,6 +145,7 @@ export const installHtmlSupervisor = ({
140
145
  if (logs) {
141
146
  console.groupEnd()
142
147
  }
148
+ __html_supervisor__.currentExecution = null
143
149
  }
144
150
 
145
151
  const classicExecutionQueue = createExecutionQueue(performExecution)
@@ -220,82 +226,28 @@ export const installHtmlSupervisor = ({
220
226
  })
221
227
 
222
228
  if (errorOverlay) {
223
- window.addEventListener("error", (errorEvent) => {
224
- if (!errorEvent.isTrusted) {
225
- // ignore custom error event (not sent by browser)
226
- return
227
- }
228
- const { error } = errorEvent
229
+ const onErrorReportedByBrowser = (error, { url, line, column }) => {
229
230
  displayErrorInDocument(error, {
230
231
  rootDirectoryUrl,
231
232
  errorBaseUrl,
232
233
  openInEditor,
233
- url: errorEvent.filename,
234
- line: errorEvent.lineno,
235
- column: errorEvent.colno,
236
- reportedBy: "browser",
234
+ url,
235
+ line,
236
+ column,
237
237
  })
238
- })
239
- if (window.__server_events__) {
240
- const isExecuting = () => {
241
- if (pendingExecutionCount > 0) {
242
- return true
243
- }
244
- if (
245
- document.readyState === "loading" ||
246
- document.readyState === "interactive"
247
- ) {
248
- return true
249
- }
250
- if (window.__reloader__ && window.__reloader__.status === "reloading") {
251
- return true
252
- }
253
- return false
238
+ }
239
+ window.addEventListener("error", (errorEvent) => {
240
+ if (!errorEvent.isTrusted) {
241
+ // ignore custom error event (not sent by browser)
242
+ return
254
243
  }
255
-
256
- window.__server_events__.addEventCallbacks({
257
- error_while_serving_file: (serverErrorEvent) => {
258
- if (!isExecuting()) {
259
- return
260
- }
261
- const {
262
- message,
263
- stack,
264
- traceUrl,
265
- traceLine,
266
- traceColumn,
267
- traceMessage,
268
- requestedRessource,
269
- isFaviconAutoRequest,
270
- } = JSON.parse(serverErrorEvent.data)
271
- if (isFaviconAutoRequest) {
272
- return
273
- }
274
- // setTimeout is to ensure the error
275
- // dispatched on window by browser is displayed first,
276
- // then the server error replaces it (because it contains more information)
277
- setTimeout(() => {
278
- displayErrorInDocument(
279
- {
280
- message,
281
- stack,
282
- },
283
- {
284
- rootDirectoryUrl,
285
- errorBaseUrl,
286
- openInEditor,
287
- url: traceUrl,
288
- line: traceLine,
289
- column: traceColumn,
290
- codeFrame: traceMessage,
291
- reportedBy: "server",
292
- requestedRessource,
293
- },
294
- )
295
- }, 10)
296
- },
244
+ const { error, filename, lineno, colno } = errorEvent
245
+ onErrorReportedByBrowser(error, {
246
+ url: filename,
247
+ line: lineno,
248
+ column: colno,
297
249
  })
298
- }
250
+ })
299
251
  }
300
252
  }
301
253
 
@@ -20,6 +20,7 @@ import {
20
20
  setHtmlNodeText,
21
21
  } from "@jsenv/ast"
22
22
  import { generateInlineContentUrl, stringifyUrlSite } from "@jsenv/urls"
23
+ import { getOriginalPosition } from "@jsenv/sourcemap"
23
24
 
24
25
  import { requireFromJsenv } from "@jsenv/core/src/require_from_jsenv.js"
25
26
 
@@ -46,44 +47,42 @@ export const jsenvPluginHtmlSupervisor = ({
46
47
  dev: true,
47
48
  test: true,
48
49
  },
49
- serve: (request, context) => {
50
- if (request.ressource.startsWith("/__open_in_editor__/")) {
51
- const file = request.ressource.slice("/__open_in_editor__/".length)
52
- if (!file) {
53
- return {
54
- status: 400,
55
- body: "Missing file in url",
56
- }
57
- }
58
- const launch = requireFromJsenv("launch-editor")
59
- launch(fileURLToPath(file), () => {
60
- // ignore error for now
61
- })
62
- return {
63
- status: 200,
64
- headers: {
65
- "cache-control": "no-store",
66
- },
67
- }
68
- }
50
+ serve: async (request, context) => {
69
51
  if (request.ressource.startsWith("/__get_code_frame__/")) {
70
- const url = request.ressource.slice("/__get_code_frame__/".length)
71
- const match = url.match(/:([0-9]+):([0-9]+)$/)
52
+ const { pathname, searchParams } = new URL(request.url)
53
+ const urlWithLineAndColumn = pathname.slice(
54
+ "/__get_code_frame__/".length,
55
+ )
56
+ const match = urlWithLineAndColumn.match(/:([0-9]+):([0-9]+)$/)
72
57
  if (!match) {
73
58
  return {
74
59
  status: 400,
75
60
  body: "Missing line and column in url",
76
61
  }
77
62
  }
78
- const file = url.slice(0, match.index)
79
- const line = parseInt(match[1])
80
- const column = parseInt(match[2])
63
+ const file = urlWithLineAndColumn.slice(0, match.index)
64
+ let line = parseInt(match[1])
65
+ let column = parseInt(match[2])
81
66
  const urlInfo = context.urlGraph.getUrlInfo(file)
82
67
  if (!urlInfo) {
83
68
  return {
84
69
  status: 404,
85
70
  }
86
71
  }
72
+ const remap = searchParams.has("remap")
73
+ if (remap) {
74
+ const sourcemap = urlInfo.sourcemap
75
+ if (sourcemap) {
76
+ const original = await getOriginalPosition({
77
+ sourcemap,
78
+ url: file,
79
+ line,
80
+ column,
81
+ })
82
+ line = original.line
83
+ column = original.column
84
+ }
85
+ }
87
86
  const codeFrame = stringifyUrlSite({
88
87
  url: file,
89
88
  line,
@@ -99,6 +98,76 @@ export const jsenvPluginHtmlSupervisor = ({
99
98
  body: codeFrame,
100
99
  }
101
100
  }
101
+ if (request.ressource.startsWith("/__get_error_cause__/")) {
102
+ const file = request.ressource.slice("/__get_error_cause__/".length)
103
+ if (!file) {
104
+ return {
105
+ status: 400,
106
+ body: "Missing file in url",
107
+ }
108
+ }
109
+ const getErrorCauseInfo = () => {
110
+ const urlInfo = context.urlGraph.getUrlInfo(file)
111
+ if (!urlInfo) {
112
+ return null
113
+ }
114
+ const { error } = urlInfo
115
+ if (error) {
116
+ return error
117
+ }
118
+ // search in direct dependencies (404 or 500)
119
+ const { dependencies } = urlInfo
120
+ for (const dependencyUrl of dependencies) {
121
+ const dependencyUrlInfo = context.urlGraph.getUrlInfo(dependencyUrl)
122
+ if (dependencyUrlInfo.error) {
123
+ return dependencyUrlInfo.error
124
+ }
125
+ }
126
+ return null
127
+ }
128
+ const causeInfo = getErrorCauseInfo()
129
+ const body = JSON.stringify(
130
+ causeInfo
131
+ ? {
132
+ code: causeInfo.code,
133
+ message: causeInfo.message,
134
+ reason: causeInfo.reason,
135
+ stack: causeInfo.stack,
136
+ codeFrame: causeInfo.traceMessage,
137
+ }
138
+ : null,
139
+ null,
140
+ " ",
141
+ )
142
+ return {
143
+ status: 200,
144
+ headers: {
145
+ "cache-control": "no-cache",
146
+ "content-type": "application/json",
147
+ "content-length": Buffer.byteLength(body),
148
+ },
149
+ body,
150
+ }
151
+ }
152
+ if (request.ressource.startsWith("/__open_in_editor__/")) {
153
+ const file = request.ressource.slice("/__open_in_editor__/".length)
154
+ if (!file) {
155
+ return {
156
+ status: 400,
157
+ body: "Missing file in url",
158
+ }
159
+ }
160
+ const launch = requireFromJsenv("launch-editor")
161
+ launch(fileURLToPath(file), () => {
162
+ // ignore error for now
163
+ })
164
+ return {
165
+ status: 200,
166
+ headers: {
167
+ "cache-control": "no-store",
168
+ },
169
+ }
170
+ }
102
171
  return null
103
172
  },
104
173
  transformUrlContent: {
@@ -60,8 +60,7 @@ export const executeTestPlan = async ({
60
60
  cooldownBetweenExecutions = 0,
61
61
  gcBetweenExecutions = logMemoryHeapUsage,
62
62
 
63
- coverageEnabled = process.argv.includes("--cover") ||
64
- process.argv.includes("--coverage"),
63
+ coverageEnabled = process.argv.includes("--coverage"),
65
64
  coverageConfig = {
66
65
  "./src/": true,
67
66
  },