@jsenv/core 27.6.0 → 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.
@@ -38,6 +38,8 @@ const formatError = (error, {
38
38
  line,
39
39
  column
40
40
  }) => {
41
+ if (typeof line === "string") line = parseInt(line);
42
+ if (typeof column === "string") column = parseInt(column);
41
43
  const inlineUrlMatch = url.match(/@L([0-9]+)C([0-9]+)\-L([0-9]+)C([0-9]+)(\.[\w]+)$/);
42
44
 
43
45
  if (inlineUrlMatch) {
@@ -48,7 +50,7 @@ const formatError = (error, {
48
50
  const tagColumnEnd = parseInt(inlineUrlMatch[4]);
49
51
  const extension = inlineUrlMatch[5];
50
52
  url = htmlUrl;
51
- line = tagLineStart + (line === undefined ? 0 : parseInt(line)); // stackTrace formatted by V8 (chrome)
53
+ line = tagLineStart + (typeof line === "number" ? line : 0); // stackTrace formatted by V8 (chrome)
52
54
 
53
55
  if (Error.captureStackTrace) {
54
56
  line--;
@@ -64,7 +66,7 @@ const formatError = (error, {
64
66
  }
65
67
  }
66
68
 
67
- column = tagColumnStart + (column === undefined ? 0 : parseInt(column));
69
+ column = tagColumnStart + (typeof column === "number" ? column : 0);
68
70
  const fileUrl = resolveFileUrl(url);
69
71
  return {
70
72
  isInline: true,
@@ -188,7 +190,13 @@ const formatError = (error, {
188
190
  }
189
191
 
190
192
  if (urlSite.line !== undefined) {
191
- const response = await window.fetch(`/__get_code_frame__/${formatUrlWithLineAndColumn(urlSite)}`);
193
+ let ressourceToFetch = `/__get_code_frame__/${formatUrlWithLineAndColumn(urlSite)}`;
194
+
195
+ if (!Error.captureStackTrace) {
196
+ ressourceToFetch += `?remap`;
197
+ }
198
+
199
+ const response = await window.fetch(ressourceToFetch);
192
200
  const codeFrame = await response.text();
193
201
  return {
194
202
  codeFrame: formatErrorText({
package/dist/main.js CHANGED
@@ -16,7 +16,7 @@ import { Readable, Stream, Writable } from "node:stream";
16
16
  import { Http2ServerResponse } from "node:http2";
17
17
  import { lookup } from "node:dns";
18
18
  import { parseHtmlString, stringifyHtmlAst, visitHtmlNodes, getHtmlNodeAttribute, analyzeScriptNode, setHtmlNodeAttributes, parseSrcSet, getHtmlNodePosition, getHtmlNodeAttributePosition, applyPostCss, postCssPluginUrlVisitor, parseJsUrls, findHtmlNode, getHtmlNodeText, removeHtmlNode, setHtmlNodeText, applyBabelPlugins, injectScriptNodeAsEarlyAsPossible, createHtmlNode, removeHtmlNodeText, transpileWithParcel, injectJsImport, minifyWithParcel, analyzeLinkNode } from "@jsenv/ast";
19
- import { createMagicSource, composeTwoSourcemaps, sourcemapConverter, SOURCEMAP, generateSourcemapFileUrl, generateSourcemapDataUrl } from "@jsenv/sourcemap";
19
+ import { createMagicSource, getOriginalPosition, composeTwoSourcemaps, sourcemapConverter, SOURCEMAP, generateSourcemapFileUrl, generateSourcemapDataUrl } from "@jsenv/sourcemap";
20
20
  import { createRequire } from "node:module";
21
21
  import babelParser from "@babel/parser";
22
22
  import v8, { takeCoverage } from "node:v8";
@@ -12046,10 +12046,14 @@ const jsenvPluginHtmlSupervisor = ({
12046
12046
  dev: true,
12047
12047
  test: true
12048
12048
  },
12049
- serve: (request, context) => {
12049
+ serve: async (request, context) => {
12050
12050
  if (request.ressource.startsWith("/__get_code_frame__/")) {
12051
- const url = request.ressource.slice("/__get_code_frame__/".length);
12052
- const match = url.match(/:([0-9]+):([0-9]+)$/);
12051
+ const {
12052
+ pathname,
12053
+ searchParams
12054
+ } = new URL(request.url);
12055
+ const urlWithLineAndColumn = pathname.slice("/__get_code_frame__/".length);
12056
+ const match = urlWithLineAndColumn.match(/:([0-9]+):([0-9]+)$/);
12053
12057
 
12054
12058
  if (!match) {
12055
12059
  return {
@@ -12058,9 +12062,9 @@ const jsenvPluginHtmlSupervisor = ({
12058
12062
  };
12059
12063
  }
12060
12064
 
12061
- const file = url.slice(0, match.index);
12062
- const line = parseInt(match[1]);
12063
- const column = parseInt(match[2]);
12065
+ const file = urlWithLineAndColumn.slice(0, match.index);
12066
+ let line = parseInt(match[1]);
12067
+ let column = parseInt(match[2]);
12064
12068
  const urlInfo = context.urlGraph.getUrlInfo(file);
12065
12069
 
12066
12070
  if (!urlInfo) {
@@ -12069,6 +12073,23 @@ const jsenvPluginHtmlSupervisor = ({
12069
12073
  };
12070
12074
  }
12071
12075
 
12076
+ const remap = searchParams.has("remap");
12077
+
12078
+ if (remap) {
12079
+ const sourcemap = urlInfo.sourcemap;
12080
+
12081
+ if (sourcemap) {
12082
+ const original = await getOriginalPosition({
12083
+ sourcemap,
12084
+ url: file,
12085
+ line,
12086
+ column
12087
+ });
12088
+ line = original.line;
12089
+ column = original.column;
12090
+ }
12091
+ }
12092
+
12072
12093
  const codeFrame = stringifyUrlSite({
12073
12094
  url: file,
12074
12095
  line,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "27.6.0",
3
+ "version": "27.6.1",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -74,7 +74,7 @@
74
74
  "@jsenv/log": "3.1.0",
75
75
  "@jsenv/node-esm-resolution": "0.1.0",
76
76
  "@jsenv/server": "13.0.0",
77
- "@jsenv/sourcemap": "1.0.3",
77
+ "@jsenv/sourcemap": "1.0.4",
78
78
  "@jsenv/uneval": "1.6.0",
79
79
  "@jsenv/url-meta": "7.0.0",
80
80
  "@jsenv/urls": "1.2.7",
@@ -10,6 +10,9 @@ export const formatError = (
10
10
  const errorMeta = extractErrorMeta(error, { url, line, column })
11
11
 
12
12
  const resolveUrlSite = ({ url, line, column }) => {
13
+ if (typeof line === "string") line = parseInt(line)
14
+ if (typeof column === "string") column = parseInt(column)
15
+
13
16
  const inlineUrlMatch = url.match(
14
17
  /@L([0-9]+)C([0-9]+)\-L([0-9]+)C([0-9]+)(\.[\w]+)$/,
15
18
  )
@@ -21,7 +24,7 @@ export const formatError = (
21
24
  const tagColumnEnd = parseInt(inlineUrlMatch[4])
22
25
  const extension = inlineUrlMatch[5]
23
26
  url = htmlUrl
24
- line = tagLineStart + (line === undefined ? 0 : parseInt(line))
27
+ line = tagLineStart + (typeof line === "number" ? line : 0)
25
28
  // stackTrace formatted by V8 (chrome)
26
29
  if (Error.captureStackTrace) {
27
30
  line--
@@ -35,7 +38,7 @@ export const formatError = (
35
38
  line -= 2
36
39
  }
37
40
  }
38
- column = tagColumnStart + (column === undefined ? 0 : parseInt(column))
41
+ column = tagColumnStart + (typeof column === "number" ? column : 0)
39
42
  const fileUrl = resolveFileUrl(url)
40
43
  return {
41
44
  isInline: true,
@@ -149,9 +152,13 @@ export const formatError = (
149
152
  }
150
153
  }
151
154
  if (urlSite.line !== undefined) {
152
- const response = await window.fetch(
153
- `/__get_code_frame__/${formatUrlWithLineAndColumn(urlSite)}`,
154
- )
155
+ let ressourceToFetch = `/__get_code_frame__/${formatUrlWithLineAndColumn(
156
+ urlSite,
157
+ )}`
158
+ if (!Error.captureStackTrace) {
159
+ ressourceToFetch += `?remap`
160
+ }
161
+ const response = await window.fetch(ressourceToFetch)
155
162
  const codeFrame = await response.text()
156
163
  return {
157
164
  codeFrame: formatErrorText({ message: codeFrame }),
@@ -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,25 +47,42 @@ export const jsenvPluginHtmlSupervisor = ({
46
47
  dev: true,
47
48
  test: true,
48
49
  },
49
- serve: (request, context) => {
50
+ serve: async (request, context) => {
50
51
  if (request.ressource.startsWith("/__get_code_frame__/")) {
51
- const url = request.ressource.slice("/__get_code_frame__/".length)
52
- 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]+)$/)
53
57
  if (!match) {
54
58
  return {
55
59
  status: 400,
56
60
  body: "Missing line and column in url",
57
61
  }
58
62
  }
59
- const file = url.slice(0, match.index)
60
- const line = parseInt(match[1])
61
- 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])
62
66
  const urlInfo = context.urlGraph.getUrlInfo(file)
63
67
  if (!urlInfo) {
64
68
  return {
65
69
  status: 404,
66
70
  }
67
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
+ }
68
86
  const codeFrame = stringifyUrlSite({
69
87
  url: file,
70
88
  line,
@@ -1,85 +0,0 @@
1
- import { memoize } from "@jsenv/utils/src/memoize/memoize.js"
2
- import { remapSourcePosition } from "@jsenv/sourcemap/src/error_stack_remap/remap_source_position.js"
3
- import { SOURCEMAP } from "@jsenv/sourcemap/src/sourcemap_comment.js"
4
- import { DATA_URL } from "@jsenv/urls/src/data_url.js"
5
-
6
- const loadSourceMapConsumer = memoize(async () => {
7
- const script = document.createElement("script")
8
- script.src = "https://unpkg.com/source-map@0.7.3/dist/source-map.js"
9
-
10
- const scriptLoadedPromise = new Promise((resolve) => {
11
- script.onload = resolve
12
- })
13
- document.head.appendChild(script)
14
- await scriptLoadedPromise
15
- const { SourceMapConsumer } = window.sourceMap
16
- await SourceMapConsumer.initialize({
17
- "lib/mappings.wasm": "https://unpkg.com/source-map@0.7.3/lib/mappings.wasm",
18
- })
19
- return SourceMapConsumer
20
- })
21
-
22
- export const remapErrorSite = async ({ url, line, column }) => {
23
- const asServerUrl = (url) => {
24
- if (url.startsWith("file:///")) {
25
- url = `${window.origin}/@fs/${url.slice("file:///".length)}`
26
- }
27
- return url
28
- }
29
-
30
- const SourceMapConsumer = await loadSourceMapConsumer()
31
- const original = await remapSourcePosition({
32
- source: url,
33
- line,
34
- column,
35
- resolveFile: (specifier) => new URL(specifier, `${window.origin}/`).href,
36
- urlToSourcemapConsumer: async (url) => {
37
- const serverUrl = asServerUrl(url)
38
- const fileResponse = await window.fetch(serverUrl)
39
- const text = await fileResponse.text()
40
- const jsSourcemapComment = SOURCEMAP.readComment({
41
- contentType: "text/javascript",
42
- content: text,
43
- })
44
-
45
- const jsSourcemapUrl = jsSourcemapComment.specifier
46
- let sourcemapUrl
47
- let sourcemapUrlContent
48
- if (jsSourcemapUrl.startsWith("data:")) {
49
- sourcemapUrl = url
50
- sourcemapUrlContent = window.atob(DATA_URL.parse(jsSourcemapUrl).data)
51
- } else {
52
- sourcemapUrl = new URL(jsSourcemapUrl, url).href
53
- const sourcemapResponse = await window.fetch(sourcemapUrl)
54
- sourcemapUrlContent = await sourcemapResponse.text()
55
- }
56
-
57
- const sourceMap = JSON.parse(sourcemapUrlContent)
58
- let { sourcesContent } = sourceMap
59
- if (!sourcesContent) {
60
- sourcesContent = []
61
- sourceMap.sourcesContent = sourcesContent
62
- }
63
- let firstSourceMapSourceFailure = null
64
- await Promise.all(
65
- sourceMap.sources.map(async (source, index) => {
66
- if (index in sourcesContent) return
67
- let sourceUrl = new URL(source, sourcemapUrl).href
68
- sourceUrl = asServerUrl(sourceUrl)
69
- try {
70
- const sourceResponse = await window.fetch(sourceUrl)
71
- const sourceContent = await sourceResponse.text()
72
- sourcesContent[index] = sourceContent
73
- } catch (e) {
74
- firstSourceMapSourceFailure = e
75
- }
76
- }),
77
- )
78
- if (firstSourceMapSourceFailure) {
79
- return null
80
- }
81
- return new SourceMapConsumer(sourceMap)
82
- },
83
- })
84
- return original
85
- }