@jsenv/core 40.6.0 → 40.6.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.
@@ -5,6 +5,79 @@ import { extname } from "node:path";
5
5
  import crypto, { createHash } from "node:crypto";
6
6
  import { pathToFileURL, fileURLToPath } from "node:url";
7
7
 
8
+ const isFileSystemPath = (value) => {
9
+ if (typeof value !== "string") {
10
+ throw new TypeError(
11
+ `isFileSystemPath first arg must be a string, got ${value}`,
12
+ );
13
+ }
14
+ if (value[0] === "/") {
15
+ return true;
16
+ }
17
+ return startsWithWindowsDriveLetter(value);
18
+ };
19
+
20
+ const startsWithWindowsDriveLetter = (string) => {
21
+ const firstChar = string[0];
22
+ if (!/[a-zA-Z]/.test(firstChar)) return false;
23
+
24
+ const secondChar = string[1];
25
+ if (secondChar !== ":") return false;
26
+
27
+ return true;
28
+ };
29
+
30
+ const fileSystemPathToUrl = (value) => {
31
+ if (!isFileSystemPath(value)) {
32
+ throw new Error(`value must be a filesystem path, got ${value}`);
33
+ }
34
+ return String(pathToFileURL(value));
35
+ };
36
+
37
+ const getCallerPosition = () => {
38
+ const { prepareStackTrace } = Error;
39
+ Error.prepareStackTrace = (error, stack) => {
40
+ Error.prepareStackTrace = prepareStackTrace;
41
+ return stack;
42
+ };
43
+ const { stack } = new Error();
44
+ const callerCallsite = stack[2];
45
+ const fileName = callerCallsite.getFileName();
46
+ return {
47
+ url:
48
+ fileName && isFileSystemPath(fileName)
49
+ ? fileSystemPathToUrl(fileName)
50
+ : fileName,
51
+ line: callerCallsite.getLineNumber(),
52
+ column: callerCallsite.getColumnNumber(),
53
+ };
54
+ };
55
+
56
+ const urlToFileSystemPath = (url) => {
57
+ const urlObject = new URL(url);
58
+ let { origin, pathname, hash } = urlObject;
59
+ if (urlObject.protocol === "file:") {
60
+ origin = "file://";
61
+ }
62
+ pathname = pathname
63
+ .split("/")
64
+ .map((part) => {
65
+ return part.replace(/%(?![0-9A-F][0-9A-F])/g, "%25");
66
+ })
67
+ .join("/");
68
+ if (hash) {
69
+ pathname += `%23${encodeURIComponent(hash.slice(1))}`;
70
+ }
71
+ const urlString = `${origin}${pathname}`;
72
+ const fileSystemPath = fileURLToPath(urlString);
73
+ if (fileSystemPath[fileSystemPath.length - 1] === "/") {
74
+ // remove trailing / so that nodejs path becomes predictable otherwise it logs
75
+ // the trailing slash on linux but does not on windows
76
+ return fileSystemPath.slice(0, -1);
77
+ }
78
+ return fileSystemPath;
79
+ };
80
+
8
81
  /*
9
82
  * data:[<mediatype>][;base64],<data>
10
83
  * https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs#syntax
@@ -637,6 +710,58 @@ const escapeHtml = (string) => {
637
710
  .replace(/'/g, "&#039;");
638
711
  };
639
712
 
713
+ const formatError = (error) => {
714
+ let text = "";
715
+ text += error.stack;
716
+ const { cause } = error;
717
+ if (cause) {
718
+ const formatCause = (cause, depth) => {
719
+ let causeText = prefixFirstAndIndentRemainingLines({
720
+ prefix: " [cause]:",
721
+ indentation: " ".repeat(depth + 1),
722
+ text: cause.stack,
723
+ });
724
+ const nestedCause = cause.cause;
725
+ if (nestedCause) {
726
+ const nestedCauseText = formatCause(nestedCause, depth + 1);
727
+ causeText += `\n${nestedCauseText}`;
728
+ }
729
+ return causeText;
730
+ };
731
+ const causeText = formatCause(cause, 0);
732
+ text += `\n${causeText}`;
733
+ }
734
+ return text;
735
+ };
736
+
737
+ const prefixFirstAndIndentRemainingLines = ({
738
+ prefix,
739
+ indentation,
740
+ text,
741
+ trimLines,
742
+ trimLastLine,
743
+ }) => {
744
+ const lines = text.split(/\r?\n/);
745
+ const firstLine = lines.shift();
746
+ if (indentation === undefined) {
747
+ {
748
+ indentation = " "; // prefix + space
749
+ }
750
+ }
751
+ let result = `${prefix} ${firstLine}` ;
752
+ let i = 0;
753
+ while (i < lines.length) {
754
+ const line = trimLines ? lines[i].trim() : lines[i];
755
+ i++;
756
+ result += line.length
757
+ ? `\n${indentation}${line}`
758
+ : trimLastLine && i === lines.length
759
+ ? ""
760
+ : `\n`;
761
+ }
762
+ return result;
763
+ };
764
+
640
765
  const LOG_LEVEL_OFF = "off";
641
766
 
642
767
  const LOG_LEVEL_DEBUG = "debug";
@@ -1262,6 +1387,75 @@ const urlToOrigin$1 = (url) => {
1262
1387
  return new URL(urlString).origin;
1263
1388
  };
1264
1389
 
1390
+ const setUrlExtension = (url, extension) => {
1391
+ const origin = urlToOrigin$1(url);
1392
+ const currentExtension = urlToExtension$1(url);
1393
+ if (typeof extension === "function") {
1394
+ extension = extension(currentExtension);
1395
+ }
1396
+ const resource = urlToResource(url);
1397
+ const [pathname, search] = resource.split("?");
1398
+ const pathnameWithoutExtension = currentExtension
1399
+ ? pathname.slice(0, -currentExtension.length)
1400
+ : pathname;
1401
+ let newPathname;
1402
+ if (pathnameWithoutExtension.endsWith("/")) {
1403
+ newPathname = pathnameWithoutExtension.slice(0, -1);
1404
+ newPathname += extension;
1405
+ newPathname += "/";
1406
+ } else {
1407
+ newPathname = pathnameWithoutExtension;
1408
+ newPathname += extension;
1409
+ }
1410
+ return `${origin}${newPathname}${search ? `?${search}` : ""}`;
1411
+ };
1412
+
1413
+ const setUrlFilename = (url, filename) => {
1414
+ const parentPathname = new URL("./", url).pathname;
1415
+ return transformUrlPathname(url, (pathname) => {
1416
+ if (typeof filename === "function") {
1417
+ filename = filename(pathnameToFilename(pathname));
1418
+ }
1419
+ return `${parentPathname}${filename}`;
1420
+ });
1421
+ };
1422
+
1423
+ const setUrlBasename = (url, basename) => {
1424
+ return setUrlFilename(url, (filename) => {
1425
+ if (typeof basename === "function") {
1426
+ basename = basename(filenameToBasename(filename));
1427
+ }
1428
+ return `${basename}${urlToExtension$1(url)}`;
1429
+ });
1430
+ };
1431
+
1432
+ const transformUrlPathname = (url, transformer) => {
1433
+ if (typeof url === "string") {
1434
+ const urlObject = new URL(url);
1435
+ const { pathname } = urlObject;
1436
+ const pathnameTransformed = transformer(pathname);
1437
+ if (pathnameTransformed === pathname) {
1438
+ return url;
1439
+ }
1440
+ let { origin } = urlObject;
1441
+ // origin is "null" for "file://" urls with Node.js
1442
+ if (origin === "null" && urlObject.href.startsWith("file:")) {
1443
+ origin = "file://";
1444
+ }
1445
+ const { search, hash } = urlObject;
1446
+ const urlWithPathnameTransformed = `${origin}${pathnameTransformed}${search}${hash}`;
1447
+ return urlWithPathnameTransformed;
1448
+ }
1449
+ const pathnameTransformed = transformer(url.pathname);
1450
+ url.pathname = pathnameTransformed;
1451
+ return url;
1452
+ };
1453
+ const ensurePathnameTrailingSlash = (url) => {
1454
+ return transformUrlPathname(url, (pathname) => {
1455
+ return pathname.endsWith("/") ? pathname : `${pathname}/`;
1456
+ });
1457
+ };
1458
+
1265
1459
  const asUrlWithoutSearch = (url) => {
1266
1460
  url = String(url);
1267
1461
  if (url.includes("?")) {
@@ -1352,130 +1546,6 @@ const injectQueryParams = (url, params) => {
1352
1546
  return normalizeUrl(calledWithString ? urlObject.href : urlObject);
1353
1547
  };
1354
1548
 
1355
- const setUrlExtension = (url, extension) => {
1356
- const origin = urlToOrigin$1(url);
1357
- const currentExtension = urlToExtension$1(url);
1358
- if (typeof extension === "function") {
1359
- extension = extension(currentExtension);
1360
- }
1361
- const resource = urlToResource(url);
1362
- const [pathname, search] = resource.split("?");
1363
- const pathnameWithoutExtension = currentExtension
1364
- ? pathname.slice(0, -currentExtension.length)
1365
- : pathname;
1366
- let newPathname;
1367
- if (pathnameWithoutExtension.endsWith("/")) {
1368
- newPathname = pathnameWithoutExtension.slice(0, -1);
1369
- newPathname += extension;
1370
- newPathname += "/";
1371
- } else {
1372
- newPathname = pathnameWithoutExtension;
1373
- newPathname += extension;
1374
- }
1375
- return `${origin}${newPathname}${search ? `?${search}` : ""}`;
1376
- };
1377
-
1378
- const setUrlFilename = (url, filename) => {
1379
- const parentPathname = new URL("./", url).pathname;
1380
- return transformUrlPathname(url, (pathname) => {
1381
- if (typeof filename === "function") {
1382
- filename = filename(pathnameToFilename(pathname));
1383
- }
1384
- return `${parentPathname}${filename}`;
1385
- });
1386
- };
1387
-
1388
- const setUrlBasename = (url, basename) => {
1389
- return setUrlFilename(url, (filename) => {
1390
- if (typeof basename === "function") {
1391
- basename = basename(filenameToBasename(filename));
1392
- }
1393
- return `${basename}${urlToExtension$1(url)}`;
1394
- });
1395
- };
1396
-
1397
- const transformUrlPathname = (url, transformer) => {
1398
- if (typeof url === "string") {
1399
- const urlObject = new URL(url);
1400
- const { pathname } = urlObject;
1401
- const pathnameTransformed = transformer(pathname);
1402
- if (pathnameTransformed === pathname) {
1403
- return url;
1404
- }
1405
- let { origin } = urlObject;
1406
- // origin is "null" for "file://" urls with Node.js
1407
- if (origin === "null" && urlObject.href.startsWith("file:")) {
1408
- origin = "file://";
1409
- }
1410
- const { search, hash } = urlObject;
1411
- const urlWithPathnameTransformed = `${origin}${pathnameTransformed}${search}${hash}`;
1412
- return urlWithPathnameTransformed;
1413
- }
1414
- const pathnameTransformed = transformer(url.pathname);
1415
- url.pathname = pathnameTransformed;
1416
- return url;
1417
- };
1418
- const ensurePathnameTrailingSlash = (url) => {
1419
- return transformUrlPathname(url, (pathname) => {
1420
- return pathname.endsWith("/") ? pathname : `${pathname}/`;
1421
- });
1422
- };
1423
-
1424
- const isFileSystemPath = (value) => {
1425
- if (typeof value !== "string") {
1426
- throw new TypeError(
1427
- `isFileSystemPath first arg must be a string, got ${value}`,
1428
- );
1429
- }
1430
- if (value[0] === "/") {
1431
- return true;
1432
- }
1433
- return startsWithWindowsDriveLetter(value);
1434
- };
1435
-
1436
- const startsWithWindowsDriveLetter = (string) => {
1437
- const firstChar = string[0];
1438
- if (!/[a-zA-Z]/.test(firstChar)) return false;
1439
-
1440
- const secondChar = string[1];
1441
- if (secondChar !== ":") return false;
1442
-
1443
- return true;
1444
- };
1445
-
1446
- const fileSystemPathToUrl = (value) => {
1447
- if (!isFileSystemPath(value)) {
1448
- throw new Error(`value must be a filesystem path, got ${value}`);
1449
- }
1450
- return String(pathToFileURL(value));
1451
- };
1452
-
1453
- const getCallerPosition = () => {
1454
- const { prepareStackTrace } = Error;
1455
- Error.prepareStackTrace = (error, stack) => {
1456
- Error.prepareStackTrace = prepareStackTrace;
1457
- return stack;
1458
- };
1459
- const { stack } = new Error();
1460
- const callerCallsite = stack[2];
1461
- const fileName = callerCallsite.getFileName();
1462
- return {
1463
- url:
1464
- fileName && isFileSystemPath(fileName)
1465
- ? fileSystemPathToUrl(fileName)
1466
- : fileName,
1467
- line: callerCallsite.getLineNumber(),
1468
- column: callerCallsite.getColumnNumber(),
1469
- };
1470
- };
1471
-
1472
- const resolveUrl$1 = (specifier, baseUrl) => {
1473
- if (typeof baseUrl === "undefined") {
1474
- throw new TypeError(`baseUrl missing to resolve ${specifier}`);
1475
- }
1476
- return String(new URL(specifier, baseUrl));
1477
- };
1478
-
1479
1549
  const getCommonPathname = (pathname, otherPathname) => {
1480
1550
  if (pathname === otherPathname) {
1481
1551
  return pathname;
@@ -1585,6 +1655,13 @@ const moveUrl = ({ url, from, to, preferRelative }) => {
1585
1655
  return absoluteUrl;
1586
1656
  };
1587
1657
 
1658
+ const resolveUrl$1 = (specifier, baseUrl) => {
1659
+ if (typeof baseUrl === "undefined") {
1660
+ throw new TypeError(`baseUrl missing to resolve ${specifier}`);
1661
+ }
1662
+ return String(new URL(specifier, baseUrl));
1663
+ };
1664
+
1588
1665
  const urlIsInsideOf = (url, otherUrl) => {
1589
1666
  const urlObject = new URL(url);
1590
1667
  const otherUrlObject = new URL(otherUrl);
@@ -1603,31 +1680,6 @@ const urlIsInsideOf = (url, otherUrl) => {
1603
1680
  return isInside;
1604
1681
  };
1605
1682
 
1606
- const urlToFileSystemPath = (url) => {
1607
- const urlObject = new URL(url);
1608
- let { origin, pathname, hash } = urlObject;
1609
- if (urlObject.protocol === "file:") {
1610
- origin = "file://";
1611
- }
1612
- pathname = pathname
1613
- .split("/")
1614
- .map((part) => {
1615
- return part.replace(/%(?![0-9A-F][0-9A-F])/g, "%25");
1616
- })
1617
- .join("/");
1618
- if (hash) {
1619
- pathname += `%23${encodeURIComponent(hash.slice(1))}`;
1620
- }
1621
- const urlString = `${origin}${pathname}`;
1622
- const fileSystemPath = fileURLToPath(urlString);
1623
- if (fileSystemPath[fileSystemPath.length - 1] === "/") {
1624
- // remove trailing / so that nodejs path becomes predictable otherwise it logs
1625
- // the trailing slash on linux but does not on windows
1626
- return fileSystemPath.slice(0, -1);
1627
- }
1628
- return fileSystemPath;
1629
- };
1630
-
1631
1683
  const validateDirectoryUrl = (value) => {
1632
1684
  let urlString;
1633
1685
 
@@ -6205,4 +6257,4 @@ const memoizeByFirstArgument = (compute) => {
6205
6257
  return fnWithMemoization;
6206
6258
  };
6207
6259
 
6208
- export { ANSI, CONTENT_TYPE, DATA_URL, JS_QUOTES, RUNTIME_COMPAT, URL_META, applyFileSystemMagicResolution, applyNodeEsmResolution, asSpecifierWithoutSearch, asUrlWithoutSearch, assertAndNormalizeDirectoryUrl, bufferToEtag, compareFileUrls, composeTwoImportMaps, createDetailedMessage$1 as createDetailedMessage, createLogger, createTaskLog, defaultLookupPackageScope, defaultReadPackageJson, ensurePathnameTrailingSlash, ensureWindowsDriveLetter, errorToHTML, generateContentFrame, getCallerPosition, getExtensionsToTry, injectQueryParamsIntoSpecifier, isFileSystemPath, isSpecifierForNodeBuiltin, lookupPackageDirectory, memoizeByFirstArgument, moveUrl, normalizeImportMap, normalizeUrl, readCustomConditionsFromProcessArgs, readEntryStatSync, readPackageAtOrNull, registerDirectoryLifecycle, resolveImport, setUrlBasename, setUrlExtension, setUrlFilename, stringifyUrlSite, urlIsInsideOf, urlToBasename, urlToExtension$1 as urlToExtension, urlToFileSystemPath, urlToFilename$1 as urlToFilename, urlToPathname$1 as urlToPathname, urlToRelativeUrl, validateResponseIntegrity, writeFileSync };
6260
+ export { ANSI, CONTENT_TYPE, DATA_URL, JS_QUOTES, RUNTIME_COMPAT, URL_META, applyFileSystemMagicResolution, applyNodeEsmResolution, asSpecifierWithoutSearch, asUrlWithoutSearch, assertAndNormalizeDirectoryUrl, bufferToEtag, compareFileUrls, composeTwoImportMaps, createDetailedMessage$1 as createDetailedMessage, createLogger, createTaskLog, defaultLookupPackageScope, defaultReadPackageJson, ensurePathnameTrailingSlash, ensureWindowsDriveLetter, errorToHTML, formatError, generateContentFrame, getCallerPosition, getExtensionsToTry, injectQueryParamsIntoSpecifier, isFileSystemPath, isSpecifierForNodeBuiltin, lookupPackageDirectory, memoizeByFirstArgument, moveUrl, normalizeImportMap, normalizeUrl, readCustomConditionsFromProcessArgs, readEntryStatSync, readPackageAtOrNull, registerDirectoryLifecycle, resolveImport, setUrlBasename, setUrlExtension, setUrlFilename, stringifyUrlSite, urlIsInsideOf, urlToBasename, urlToExtension$1 as urlToExtension, urlToFileSystemPath, urlToFilename$1 as urlToFilename, urlToPathname$1 as urlToPathname, urlToRelativeUrl, validateResponseIntegrity, writeFileSync };
@@ -1,6 +1,6 @@
1
1
  import { WebSocketResponse, pickContentType, ServerEvents, jsenvServiceCORS, jsenvAccessControlAllowedHeaders, composeTwoResponses, serveDirectory, jsenvServiceErrorHandler, startServer } from "@jsenv/server";
2
2
  import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/internal/convertFileSystemErrorToResponseProperties.js";
3
- import { lookupPackageDirectory, registerDirectoryLifecycle, urlToRelativeUrl, moveUrl, urlIsInsideOf, ensureWindowsDriveLetter, createDetailedMessage, stringifyUrlSite, generateContentFrame, validateResponseIntegrity, setUrlFilename, getCallerPosition, urlToBasename, urlToExtension, asSpecifierWithoutSearch, asUrlWithoutSearch, injectQueryParamsIntoSpecifier, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, urlToFileSystemPath, writeFileSync, createLogger, URL_META, applyNodeEsmResolution, RUNTIME_COMPAT, normalizeUrl, ANSI, CONTENT_TYPE, errorToHTML, DATA_URL, normalizeImportMap, composeTwoImportMaps, resolveImport, JS_QUOTES, defaultLookupPackageScope, defaultReadPackageJson, readCustomConditionsFromProcessArgs, readEntryStatSync, urlToFilename, ensurePathnameTrailingSlash, compareFileUrls, applyFileSystemMagicResolution, getExtensionsToTry, setUrlExtension, isSpecifierForNodeBuiltin, memoizeByFirstArgument, assertAndNormalizeDirectoryUrl, createTaskLog, readPackageAtOrNull } from "./jsenv_core_packages.js";
3
+ import { lookupPackageDirectory, registerDirectoryLifecycle, urlToRelativeUrl, moveUrl, urlIsInsideOf, ensureWindowsDriveLetter, createDetailedMessage, stringifyUrlSite, generateContentFrame, validateResponseIntegrity, setUrlFilename, getCallerPosition, urlToBasename, urlToExtension, asSpecifierWithoutSearch, asUrlWithoutSearch, injectQueryParamsIntoSpecifier, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, urlToFileSystemPath, writeFileSync, createLogger, URL_META, applyNodeEsmResolution, RUNTIME_COMPAT, normalizeUrl, ANSI, CONTENT_TYPE, errorToHTML, DATA_URL, normalizeImportMap, composeTwoImportMaps, resolveImport, JS_QUOTES, defaultLookupPackageScope, defaultReadPackageJson, readCustomConditionsFromProcessArgs, readEntryStatSync, urlToFilename, ensurePathnameTrailingSlash, compareFileUrls, applyFileSystemMagicResolution, getExtensionsToTry, setUrlExtension, isSpecifierForNodeBuiltin, memoizeByFirstArgument, assertAndNormalizeDirectoryUrl, createTaskLog, formatError, readPackageAtOrNull } from "./jsenv_core_packages.js";
4
4
  import { readFileSync, existsSync, readdirSync, lstatSync, realpathSync } from "node:fs";
5
5
  import { pathToFileURL } from "node:url";
6
6
  import { generateSourcemapFileUrl, createMagicSource, composeTwoSourcemaps, generateSourcemapDataUrl, SOURCEMAP } from "@jsenv/sourcemap";
@@ -242,6 +242,12 @@ ${reason}`,
242
242
  });
243
243
  return error;
244
244
  }
245
+ if (error.code === "PROTOCOL_NOT_SUPPORTED") {
246
+ const notSupportedError = createFailedToResolveUrlError({
247
+ reason: error.message,
248
+ });
249
+ return notSupportedError;
250
+ }
245
251
  return createFailedToResolveUrlError({
246
252
  reason: `An error occured during specifier resolution`,
247
253
  ...detailsFromValueThrown(error),
@@ -282,7 +288,6 @@ ${reason}`,
282
288
  });
283
289
  return fetchError;
284
290
  };
285
-
286
291
  if (error.code === "EPERM") {
287
292
  return createFailedToFetchUrlContentError({
288
293
  code: "NOT_ALLOWED",
@@ -329,6 +334,9 @@ const createTransformUrlContentError = ({
329
334
  if (error.code === "MODULE_NOT_FOUND") {
330
335
  return error;
331
336
  }
337
+ if (error.code === "PROTOCOL_NOT_SUPPORTED") {
338
+ return error;
339
+ }
332
340
  if (error.code === "DIRECTORY_REFERENCE_NOT_ALLOWED") {
333
341
  return error;
334
342
  }
@@ -336,47 +344,8 @@ const createTransformUrlContentError = ({
336
344
  if (error.isJsenvCookingError) {
337
345
  return error;
338
346
  }
347
+ const trace = getErrorTrace(error, urlInfo.firstReference);
339
348
  const reference = urlInfo.firstReference;
340
- let trace = reference.trace;
341
- let line = error.line;
342
- let column = error.column;
343
- if (urlInfo.isInline) {
344
- line = trace.line + line;
345
- line = line - 1;
346
- trace = {
347
- ...trace,
348
- line,
349
- column,
350
- codeFrame: generateContentFrame({
351
- line,
352
- column,
353
- content: urlInfo.inlineUrlSite.content,
354
- }),
355
- message: stringifyUrlSite({
356
- url: urlInfo.inlineUrlSite.url,
357
- line,
358
- column,
359
- content: urlInfo.inlineUrlSite.content,
360
- }),
361
- };
362
- } else {
363
- trace = {
364
- url: urlInfo.url,
365
- line,
366
- column: error.column,
367
- codeFrame: generateContentFrame({
368
- line,
369
- column: error.column,
370
- content: urlInfo.content,
371
- }),
372
- message: stringifyUrlSite({
373
- url: urlInfo.url,
374
- line,
375
- column: error.column,
376
- content: urlInfo.content,
377
- }),
378
- };
379
- }
380
349
  const transformError = new Error(
381
350
  createDetailedMessage(
382
351
  `parse error on "${urlInfo.type}"
@@ -467,9 +436,55 @@ ${reference.trace.message}`,
467
436
  return finalizeError;
468
437
  };
469
438
 
439
+ const getErrorTrace = (error, reference) => {
440
+ const urlInfo = reference.urlInfo;
441
+ let trace = reference.trace;
442
+ let line = error.line;
443
+ let column = error.column;
444
+ if (urlInfo.isInline) {
445
+ line = trace.line + line;
446
+ line = line - 1;
447
+ return {
448
+ ...trace,
449
+ line,
450
+ column,
451
+ codeFrame: generateContentFrame({
452
+ line,
453
+ column,
454
+ content: urlInfo.inlineUrlSite.content,
455
+ }),
456
+ message: stringifyUrlSite({
457
+ url: urlInfo.inlineUrlSite.url,
458
+ line,
459
+ column,
460
+ content: urlInfo.inlineUrlSite.content,
461
+ }),
462
+ };
463
+ }
464
+ return {
465
+ url: urlInfo.url,
466
+ line,
467
+ column: error.column,
468
+ codeFrame: generateContentFrame({
469
+ line,
470
+ column: error.column,
471
+ content: urlInfo.content,
472
+ }),
473
+ message: stringifyUrlSite({
474
+ url: urlInfo.url,
475
+ line,
476
+ column: error.column,
477
+ content: urlInfo.content,
478
+ }),
479
+ };
480
+ };
481
+
470
482
  const detailsFromFirstReference = (reference) => {
471
483
  const referenceInProject = getFirstReferenceInProject(reference);
472
- if (referenceInProject === reference) {
484
+ if (
485
+ referenceInProject === reference ||
486
+ referenceInProject.type === "http_request"
487
+ ) {
473
488
  return {};
474
489
  }
475
490
  return {
@@ -478,6 +493,9 @@ const detailsFromFirstReference = (reference) => {
478
493
  };
479
494
  const getFirstReferenceInProject = (reference) => {
480
495
  const ownerUrlInfo = reference.ownerUrlInfo;
496
+ if (ownerUrlInfo.isRoot) {
497
+ return reference;
498
+ }
481
499
  if (
482
500
  !ownerUrlInfo.url.includes("/node_modules/") &&
483
501
  ownerUrlInfo.packageDirectoryUrl ===
@@ -485,7 +503,8 @@ const getFirstReferenceInProject = (reference) => {
485
503
  ) {
486
504
  return reference;
487
505
  }
488
- return getFirstReferenceInProject(ownerUrlInfo.firstReference);
506
+ const { firstReference } = ownerUrlInfo;
507
+ return getFirstReferenceInProject(firstReference);
489
508
  };
490
509
 
491
510
  const detailsFromPluginController = (pluginController) => {
@@ -2708,7 +2727,28 @@ const createKitchen = ({
2708
2727
 
2709
2728
  ignore,
2710
2729
  ignoreProtocol = "remove",
2711
- supportedProtocols = ["file:", "data:", "virtual:", "http:", "https:"],
2730
+ supportedProtocols = [
2731
+ "file:",
2732
+ "data:",
2733
+ // eslint-disable-next-line no-script-url
2734
+ "javascript:",
2735
+ "virtual:",
2736
+ "ignore:",
2737
+ "http:",
2738
+ "https:",
2739
+ "chrome:",
2740
+ "chrome-extension:",
2741
+ "chrome-untrusted:",
2742
+ "isolated-app:",
2743
+ ],
2744
+ includedProtocols = [
2745
+ "file:",
2746
+ "data:",
2747
+ "virtual:",
2748
+ "ignore:",
2749
+ "http:",
2750
+ "https:",
2751
+ ],
2712
2752
 
2713
2753
  // during dev/test clientRuntimeCompat is a single runtime
2714
2754
  // during build clientRuntimeCompat is runtimeCompat
@@ -2728,6 +2768,9 @@ const createKitchen = ({
2728
2768
 
2729
2769
  const nodeRuntimeEnabled = Object.keys(runtimeCompat).includes("node");
2730
2770
  const packageConditions = [nodeRuntimeEnabled ? "node" : "browser", "import"];
2771
+ if (nodeRuntimeEnabled) {
2772
+ supportedProtocols.push("node:");
2773
+ }
2731
2774
 
2732
2775
  if (packageDependencies === "auto") {
2733
2776
  packageDependencies = build && nodeRuntimeEnabled ? "ignore" : "include";
@@ -2799,8 +2842,11 @@ const createKitchen = ({
2799
2842
 
2800
2843
  const isIgnoredByProtocol = (url) => {
2801
2844
  const { protocol } = new URL(url);
2802
- const protocolIsSupported = supportedProtocols.includes(protocol);
2803
- return !protocolIsSupported;
2845
+ const protocolIsIncluded = includedProtocols.includes(protocol);
2846
+ if (protocolIsIncluded) {
2847
+ return false;
2848
+ }
2849
+ return true;
2804
2850
  };
2805
2851
  const isIgnoredBecauseInPackageDependencies = (() => {
2806
2852
  if (packageDependencies === undefined) {
@@ -3007,6 +3053,21 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
3007
3053
  }
3008
3054
  reference.generatedUrl = reference.url;
3009
3055
  reference.generatedSearchParams = reference.searchParams;
3056
+ if (dev) {
3057
+ let url = reference.url;
3058
+ let { protocol } = new URL(url);
3059
+ if (protocol === "ignore:") {
3060
+ url = url.slice("ignore:".length);
3061
+ protocol = new URL(url, "http://example.com").protocol;
3062
+ }
3063
+ if (!supportedProtocols.includes(protocol)) {
3064
+ const protocolNotSupportedError = new Error(
3065
+ `Unsupported protocol "${protocol}" for url "${url}"`,
3066
+ );
3067
+ protocolNotSupportedError.code = "PROTOCOL_NOT_SUPPORTED";
3068
+ throw protocolNotSupportedError;
3069
+ }
3070
+ }
3010
3071
  return reference;
3011
3072
  } catch (error) {
3012
3073
  throw createResolveUrlError({
@@ -6548,6 +6609,9 @@ const jsenvPluginProtocolFile = ({
6548
6609
  name: "jsenv:directory_as_json",
6549
6610
  appliesDuring: "*",
6550
6611
  fetchUrlContent: (urlInfo) => {
6612
+ if (!urlInfo.url.startsWith("file:")) {
6613
+ return null;
6614
+ }
6551
6615
  const { firstReference } = urlInfo;
6552
6616
  let { fsStat } = firstReference;
6553
6617
  if (!fsStat) {
@@ -9399,7 +9463,7 @@ const startDevServer = async ({
9399
9463
  url: reference.url,
9400
9464
  status: 500,
9401
9465
  statusText: error.reason,
9402
- statusMessage: error.stack,
9466
+ statusMessage: formatError(error),
9403
9467
  headers: {
9404
9468
  "cache-control": "no-store",
9405
9469
  },