@jsenv/core 39.5.23 → 39.5.25

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.
@@ -3,7 +3,7 @@ import os, { networkInterfaces } from "node:os";
3
3
  import tty from "node:tty";
4
4
  import stringWidth from "string-width";
5
5
  import { pathToFileURL, fileURLToPath } from "node:url";
6
- import { readdir, chmod, stat, lstat, promises, readFileSync, writeFileSync as writeFileSync$1, mkdirSync, unlink, openSync, closeSync, rmdir, watch, readdirSync, statSync, createReadStream, lstatSync, readFile, existsSync, realpathSync } from "node:fs";
6
+ import { readdir, chmod, stat, lstat, chmodSync, statSync, lstatSync, promises, readFileSync, writeFileSync as writeFileSync$1, mkdirSync, unlink, openSync, closeSync, rmdir, watch, readdirSync, createReadStream, readFile, existsSync, realpathSync } from "node:fs";
7
7
  import { extname } from "node:path";
8
8
  import crypto, { createHash } from "node:crypto";
9
9
  import cluster from "node:cluster";
@@ -988,7 +988,7 @@ platform === 'Android'
988
988
  const ESC = '\u001B[';
989
989
 
990
990
  !isBrowser && process$1.env.TERM_PROGRAM === 'Apple_Terminal';
991
- const isWindows$3 = !isBrowser && process$1.platform === 'win32';
991
+ const isWindows$4 = !isBrowser && process$1.platform === 'win32';
992
992
 
993
993
  isBrowser ? () => {
994
994
  throw new Error('`process.cwd()` only works in Node.js, not the browser.');
@@ -1014,7 +1014,7 @@ const eraseLines = count => {
1014
1014
  const eraseLine = ESC + '2K';
1015
1015
  const eraseScreen = ESC + '2J';
1016
1016
 
1017
- const clearTerminal = isWindows$3
1017
+ const clearTerminal = isWindows$4
1018
1018
  ? `${eraseScreen}${ESC}0f`
1019
1019
  // 1. Erases the screen (Only done in case `2` is not supported)
1020
1020
  // 2. Erases the whole screen including scrollback buffer
@@ -1808,13 +1808,21 @@ const urlIsInsideOf = (url, otherUrl) => {
1808
1808
  };
1809
1809
 
1810
1810
  const urlToFileSystemPath = (url) => {
1811
- let urlString = String(url);
1812
- if (urlString[urlString.length - 1] === "/") {
1811
+ const urlObject = new URL(url);
1812
+ let urlString;
1813
+ if (urlObject.hash) {
1814
+ const origin =
1815
+ urlObject.protocol === "file:" ? "file://" : urlObject.origin;
1816
+ urlString = `${origin}${urlObject.pathname}${urlObject.search}%23${urlObject.hash.slice(1)}`;
1817
+ } else {
1818
+ urlString = urlObject.href;
1819
+ }
1820
+ const fileSystemPath = fileURLToPath(urlString);
1821
+ if (fileSystemPath[fileSystemPath.length - 1] === "/") {
1813
1822
  // remove trailing / so that nodejs path becomes predictable otherwise it logs
1814
1823
  // the trailing slash on linux but does not on windows
1815
- urlString = urlString.slice(0, -1);
1824
+ return fileSystemPath.slice(0, -1);
1816
1825
  }
1817
- const fileSystemPath = fileURLToPath(urlString);
1818
1826
  return fileSystemPath;
1819
1827
  };
1820
1828
 
@@ -1977,7 +1985,7 @@ const comparePathnames = (leftPathame, rightPathname) => {
1977
1985
  return 0;
1978
1986
  };
1979
1987
 
1980
- const isWindows$2 = process.platform === "win32";
1988
+ const isWindows$3 = process.platform === "win32";
1981
1989
  const baseUrlFallback = fileSystemPathToUrl$1(process.cwd());
1982
1990
 
1983
1991
  /**
@@ -2000,7 +2008,7 @@ const ensureWindowsDriveLetter = (url, baseUrl) => {
2000
2008
  throw new Error(`absolute url expect but got ${url}`);
2001
2009
  }
2002
2010
 
2003
- if (!isWindows$2) {
2011
+ if (!isWindows$3) {
2004
2012
  return url;
2005
2013
  }
2006
2014
 
@@ -3165,7 +3173,7 @@ const writeEntryPermissions = async (source, permissions) => {
3165
3173
  */
3166
3174
 
3167
3175
 
3168
- const isWindows$1 = process.platform === "win32";
3176
+ const isWindows$2 = process.platform === "win32";
3169
3177
 
3170
3178
  const readEntryStat = async (
3171
3179
  source,
@@ -3185,7 +3193,7 @@ const readEntryStat = async (
3185
3193
  return readStat(sourcePath, {
3186
3194
  followLink,
3187
3195
  ...handleNotFoundOption,
3188
- ...(isWindows$1
3196
+ ...(isWindows$2
3189
3197
  ? {
3190
3198
  // Windows can EPERM on stat
3191
3199
  handlePermissionDeniedError: async (error) => {
@@ -3250,13 +3258,104 @@ const readStat = (
3250
3258
  });
3251
3259
  };
3252
3260
 
3261
+ const writeEntryPermissionsSync = (source, permissions) => {
3262
+ const sourceUrl = assertAndNormalizeFileUrl(source);
3263
+
3264
+ let binaryFlags;
3265
+ {
3266
+ binaryFlags = permissions;
3267
+ }
3268
+
3269
+ chmodSync(new URL(sourceUrl), binaryFlags);
3270
+ };
3271
+
3253
3272
  /*
3254
3273
  * - stats object documentation on Node.js
3255
3274
  * https://nodejs.org/docs/latest-v13.x/api/fs.html#fs_class_fs_stats
3256
3275
  */
3257
3276
 
3258
3277
 
3259
- process.platform === "win32";
3278
+ const isWindows$1 = process.platform === "win32";
3279
+
3280
+ const readEntryStatSync = (
3281
+ source,
3282
+ { nullIfNotFound = false, followLink = true } = {},
3283
+ ) => {
3284
+ let sourceUrl = assertAndNormalizeFileUrl(source);
3285
+ if (sourceUrl.endsWith("/")) sourceUrl = sourceUrl.slice(0, -1);
3286
+
3287
+ const sourcePath = urlToFileSystemPath(sourceUrl);
3288
+
3289
+ const handleNotFoundOption = nullIfNotFound
3290
+ ? {
3291
+ handleNotFoundError: () => null,
3292
+ }
3293
+ : {};
3294
+
3295
+ return statSyncNaive(sourcePath, {
3296
+ followLink,
3297
+ ...handleNotFoundOption,
3298
+ ...(isWindows$1
3299
+ ? {
3300
+ // Windows can EPERM on stat
3301
+ handlePermissionDeniedError: (error) => {
3302
+ console.error(
3303
+ `trying to fix windows EPERM after stats on ${sourcePath}`,
3304
+ );
3305
+
3306
+ try {
3307
+ // unfortunately it means we mutate the permissions
3308
+ // without being able to restore them to the previous value
3309
+ // (because reading current permission would also throw)
3310
+ writeEntryPermissionsSync(sourceUrl, 0o666);
3311
+ const stats = statSyncNaive(sourcePath, {
3312
+ followLink,
3313
+ ...handleNotFoundOption,
3314
+ // could not fix the permission error, give up and throw original error
3315
+ handlePermissionDeniedError: () => {
3316
+ console.error(`still got EPERM after stats on ${sourcePath}`);
3317
+ throw error;
3318
+ },
3319
+ });
3320
+ return stats;
3321
+ } catch (e) {
3322
+ console.error(
3323
+ `error while trying to fix windows EPERM after stats on ${sourcePath}: ${e.stack}`,
3324
+ );
3325
+ throw error;
3326
+ }
3327
+ },
3328
+ }
3329
+ : {}),
3330
+ });
3331
+ };
3332
+
3333
+ const statSyncNaive = (
3334
+ sourcePath,
3335
+ {
3336
+ followLink,
3337
+ handleNotFoundError = null,
3338
+ handlePermissionDeniedError = null,
3339
+ } = {},
3340
+ ) => {
3341
+ const nodeMethod = followLink ? statSync : lstatSync;
3342
+
3343
+ try {
3344
+ const stats = nodeMethod(sourcePath);
3345
+ return stats;
3346
+ } catch (error) {
3347
+ if (handleNotFoundError && error.code === "ENOENT") {
3348
+ return handleNotFoundError(error);
3349
+ }
3350
+ if (
3351
+ handlePermissionDeniedError &&
3352
+ (error.code === "EPERM" || error.code === "EACCES")
3353
+ ) {
3354
+ return handlePermissionDeniedError(error);
3355
+ }
3356
+ throw error;
3357
+ }
3358
+ };
3260
3359
 
3261
3360
  const statsToType = (stats) => {
3262
3361
  if (stats.isFile()) return "file";
@@ -3958,7 +4057,7 @@ const registerDirectoryLifecycle = (
3958
4057
  try {
3959
4058
  const relativeUrl = urlToRelativeUrl(url, source);
3960
4059
  const previousInfo = infoMap.get(relativeUrl);
3961
- const stat = statSync(new URL(url));
4060
+ const stat = readEntryStatSync(new URL(url));
3962
4061
  const type = statsToType(stat);
3963
4062
  const patternValue = previousInfo
3964
4063
  ? previousInfo.patternValue
@@ -4035,7 +4134,7 @@ const registerDirectoryLifecycle = (
4035
4134
  const removedEntryRelativeUrl = relativeUrlCandidateArray.find(
4036
4135
  (relativeUrlCandidate) => {
4037
4136
  try {
4038
- statSync(new URL(relativeUrlCandidate, sourceUrl));
4137
+ readEntryStatSync(new URL(relativeUrlCandidate, sourceUrl));
4039
4138
  return false;
4040
4139
  } catch (e) {
4041
4140
  if (e.code === "ENOENT") {
@@ -4186,8 +4285,8 @@ const registerDirectoryLifecycle = (
4186
4285
  }
4187
4286
  };
4188
4287
  const handleEntryUpdated = (entryInfo) => {
4189
- infoMap.set(entryInfo.relativeUrl, entryInfo);
4190
4288
  if (updated && entryInfo.patternValue && shouldCallUpdated(entryInfo)) {
4289
+ infoMap.set(entryInfo.relativeUrl, entryInfo);
4191
4290
  updated({
4192
4291
  relativeUrl: entryInfo.relativeUrl,
4193
4292
  type: entryInfo.type,
@@ -8686,7 +8785,7 @@ const bundleCss = async (cssUrlInfos) => {
8686
8785
  },
8687
8786
  resolve(specifier, from) {
8688
8787
  const fileUrlObject = new URL(specifier, pathToFileURL(from));
8689
- const filePath = fileURLToPath(fileUrlObject);
8788
+ const filePath = urlToFileSystemPath(fileUrlObject);
8690
8789
  return filePath;
8691
8790
  },
8692
8791
  },
@@ -8755,7 +8854,7 @@ const minifyCss = async (cssUrlInfo) => {
8755
8854
 
8756
8855
  const targets = runtimeCompatToTargets$1(cssUrlInfo.context.runtimeCompat);
8757
8856
  const { code, map } = transform({
8758
- filename: fileURLToPath(cssUrlInfo.originalUrl),
8857
+ filename: urlToFileSystemPath(cssUrlInfo.originalUrl),
8759
8858
  code: Buffer.from(cssUrlInfo.content),
8760
8859
  targets,
8761
8860
  minify: true,
@@ -10601,7 +10700,7 @@ const applyCssTranspilation = async ({
10601
10700
  const { transform } = await import("lightningcss");
10602
10701
  const targets = runtimeCompatToTargets(runtimeCompat);
10603
10702
  const { code, map } = transform({
10604
- filename: fileURLToPath(inputUrl),
10703
+ filename: urlToFileSystemPath(inputUrl),
10605
10704
  code: Buffer.from(input),
10606
10705
  targets,
10607
10706
  minify: false,
@@ -10875,7 +10974,7 @@ const jsenvPluginImportAttributes = ({
10875
10974
  const originalUrlInfo = urlInfo.getWithoutSearchParam(
10876
10975
  `as_${type}_module`,
10877
10976
  {
10878
- expectedType: "json",
10977
+ expectedType: type,
10879
10978
  },
10880
10979
  );
10881
10980
  if (!originalUrlInfo) {
@@ -11172,6 +11271,10 @@ const generateHtmlForSyntaxError = (
11172
11271
  const htmlForSyntaxError = String(readFileSync(htmlSyntaxErrorFileUrl));
11173
11272
  const htmlRelativeUrl = urlToRelativeUrl(htmlUrl, rootDirectoryUrl);
11174
11273
  const { line, column } = htmlSyntaxError;
11274
+ if (htmlUrl.startsWith(jsenvCoreDirectoryUrl.href)) {
11275
+ htmlUrl = urlToRelativeUrl(htmlUrl, jsenvCoreDirectoryUrl);
11276
+ htmlUrl = `@jsenv/core/${htmlUrl}`;
11277
+ }
11175
11278
  const urlWithLineAndColumn = `${htmlUrl}:${line}:${column}`;
11176
11279
  const replacers = {
11177
11280
  fileRelativeUrl: htmlRelativeUrl,
@@ -12046,17 +12149,18 @@ const isResponseEligibleForIntegrityValidation = (response) => {
12046
12149
  };
12047
12150
 
12048
12151
  const assertFetchedContentCompliance = ({ urlInfo, content }) => {
12152
+ if (urlInfo.status === 404) {
12153
+ return;
12154
+ }
12049
12155
  const { expectedContentType } = urlInfo.firstReference;
12050
12156
  if (expectedContentType && urlInfo.contentType !== expectedContentType) {
12051
12157
  throw new Error(
12052
- `Unexpected content-type on url: "${expectedContentType}" was expect but got "${urlInfo.contentType}`,
12158
+ `content-type must be "${expectedContentType}", got "${urlInfo.contentType}`,
12053
12159
  );
12054
12160
  }
12055
12161
  const { expectedType } = urlInfo.firstReference;
12056
12162
  if (expectedType && urlInfo.type !== expectedType) {
12057
- throw new Error(
12058
- `Unexpected type on url: "${expectedType}" was expect but got "${urlInfo.type}"`,
12059
- );
12163
+ throw new Error(`type must be "${expectedType}", got "${urlInfo.type}"`);
12060
12164
  }
12061
12165
  const { integrity } = urlInfo.firstReference;
12062
12166
  if (integrity) {
@@ -13433,6 +13537,7 @@ const createUrlInfo = (url, context) => {
13433
13537
  jsQuote: null, // maybe move to inlineUrlSite?
13434
13538
 
13435
13539
  timing: {},
13540
+ status: 200,
13436
13541
  headers: {},
13437
13542
  debug: false,
13438
13543
  };
@@ -14500,21 +14605,16 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
14500
14605
  body,
14501
14606
  isEntryPoint,
14502
14607
  } = fetchUrlContentReturnValue;
14503
- if (status !== 200) {
14504
- throw new Error(`unexpected status, ${status}`);
14505
- }
14506
14608
  if (content === undefined) {
14507
14609
  content = body;
14508
14610
  }
14509
14611
  if (contentType === undefined) {
14510
14612
  contentType = headers["content-type"] || "application/octet-stream";
14511
14613
  }
14614
+ urlInfo.status = status;
14512
14615
  urlInfo.contentType = contentType;
14513
14616
  urlInfo.headers = headers;
14514
- urlInfo.type =
14515
- type ||
14516
- urlInfo.firstReference.expectedType ||
14517
- inferUrlInfoType(urlInfo);
14617
+ urlInfo.type = type || inferUrlInfoType(urlInfo);
14518
14618
  urlInfo.subtype =
14519
14619
  subtype ||
14520
14620
  urlInfo.firstReference.expectedSubtype ||
@@ -14838,10 +14938,11 @@ const memoizeIsSupported = (runtimeCompat) => {
14838
14938
 
14839
14939
  const inferUrlInfoType = (urlInfo) => {
14840
14940
  const { type, typeHint } = urlInfo;
14941
+ const { contentType } = urlInfo;
14942
+ const { expectedType } = urlInfo.firstReference;
14841
14943
  if (type === "sourcemap" || typeHint === "sourcemap") {
14842
14944
  return "sourcemap";
14843
14945
  }
14844
- const { contentType } = urlInfo;
14845
14946
  if (contentType === "text/html") {
14846
14947
  return "html";
14847
14948
  }
@@ -14849,7 +14950,12 @@ const inferUrlInfoType = (urlInfo) => {
14849
14950
  return "css";
14850
14951
  }
14851
14952
  if (contentType === "text/javascript") {
14852
- if (urlInfo.typeHint === "js_classic") return "js_classic";
14953
+ if (expectedType === "js_classic") {
14954
+ return "js_classic";
14955
+ }
14956
+ if (typeHint === "js_classic") {
14957
+ return "js_classic";
14958
+ }
14853
14959
  return "js_module";
14854
14960
  }
14855
14961
  if (contentType === "application/importmap+json") {
@@ -14867,7 +14973,7 @@ const inferUrlInfoType = (urlInfo) => {
14867
14973
  if (CONTENT_TYPE.isTextual(contentType)) {
14868
14974
  return "text";
14869
14975
  }
14870
- return "other";
14976
+ return expectedType || "other";
14871
14977
  };
14872
14978
 
14873
14979
  const createUrlGraphSummary = (
@@ -18269,7 +18375,7 @@ const applyFileSystemMagicResolution = (
18269
18375
 
18270
18376
  if (fileStat === undefined) {
18271
18377
  try {
18272
- fileStat = statSync(new URL(fileUrl));
18378
+ fileStat = readEntryStatSync(new URL(fileUrl));
18273
18379
  } catch (e) {
18274
18380
  if (e.code === "ENOENT") {
18275
18381
  result.lastENOENTError = e;
@@ -18311,7 +18417,7 @@ const applyFileSystemMagicResolution = (
18311
18417
  const urlCandidate = `${parentUrl}${urlFilename}${extensionToTry}`;
18312
18418
  let stat;
18313
18419
  try {
18314
- stat = statSync(new URL(urlCandidate));
18420
+ stat = readEntryStatSync(new URL(urlCandidate));
18315
18421
  } catch (e) {
18316
18422
  if (e.code === "ENOENT") {
18317
18423
  stat = null;
@@ -18672,7 +18778,7 @@ const jsenvPluginFsRedirection = ({
18672
18778
  const urlObject = new URL(reference.url);
18673
18779
  let stat;
18674
18780
  try {
18675
- stat = statSync(urlObject);
18781
+ stat = readEntryStatSync(urlObject);
18676
18782
  } catch (e) {
18677
18783
  if (e.code === "ENOENT") {
18678
18784
  stat = null;
@@ -18852,10 +18958,13 @@ const jsenvPluginProtocolFile = ({
18852
18958
  };
18853
18959
  }
18854
18960
  const contentType = CONTENT_TYPE.fromUrlExtension(urlInfo.url);
18855
- if (contentType === "text/html") {
18961
+ const request = urlInfo.context.request;
18962
+ if (request && request.headers["sec-fetch-dest"] === "document") {
18856
18963
  try {
18857
18964
  const fileBuffer = readFileSync(urlObject);
18858
- const content = String(fileBuffer);
18965
+ const content = CONTENT_TYPE.isTextual(contentType)
18966
+ ? String(fileBuffer)
18967
+ : fileBuffer;
18859
18968
  return {
18860
18969
  content,
18861
18970
  contentType,
@@ -18872,7 +18981,7 @@ const jsenvPluginProtocolFile = ({
18872
18981
  const parentDirectoryContentArray = readdirSync(
18873
18982
  new URL(parentDirectoryUrl),
18874
18983
  );
18875
- const html = generateHtmlForENOENTOnHtmlFile(
18984
+ const html = generateHtmlForENOENT(
18876
18985
  urlInfo.url,
18877
18986
  parentDirectoryContentArray,
18878
18987
  parentDirectoryUrl,
@@ -18880,6 +18989,7 @@ const jsenvPluginProtocolFile = ({
18880
18989
  directoryListingUrlMocks,
18881
18990
  );
18882
18991
  return {
18992
+ status: 404,
18883
18993
  contentType: "text/html",
18884
18994
  content: html,
18885
18995
  headers: {
@@ -18925,7 +19035,7 @@ const generateHtmlForDirectory = (
18925
19035
  const html = replacePlaceholders$1(htmlForDirectory, replacers);
18926
19036
  return html;
18927
19037
  };
18928
- const generateHtmlForENOENTOnHtmlFile = (
19038
+ const generateHtmlForENOENT = (
18929
19039
  url,
18930
19040
  parentDirectoryContentArray,
18931
19041
  parentDirectoryUrl,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "39.5.23",
3
+ "version": "39.5.25",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -69,22 +69,22 @@
69
69
  "dependencies": {
70
70
  "@financial-times/polyfill-useragent-normaliser": "1.10.2",
71
71
  "@jsenv/abort": "4.3.0",
72
- "@jsenv/ast": "6.3.5",
73
- "@jsenv/filesystem": "4.10.11",
72
+ "@jsenv/ast": "6.3.6",
73
+ "@jsenv/filesystem": "4.10.12",
74
74
  "@jsenv/humanize": "1.2.8",
75
75
  "@jsenv/importmap": "1.2.1",
76
76
  "@jsenv/integrity": "0.0.2",
77
- "@jsenv/js-module-fallback": "1.3.49",
77
+ "@jsenv/js-module-fallback": "1.3.50",
78
78
  "@jsenv/node-esm-resolution": "1.0.6",
79
- "@jsenv/plugin-bundling": "2.7.16",
79
+ "@jsenv/plugin-bundling": "2.7.17",
80
80
  "@jsenv/plugin-minification": "1.5.10",
81
- "@jsenv/plugin-supervisor": "1.5.27",
82
- "@jsenv/plugin-transpilation": "1.4.84",
81
+ "@jsenv/plugin-supervisor": "1.5.29",
82
+ "@jsenv/plugin-transpilation": "1.4.85",
83
83
  "@jsenv/runtime-compat": "1.3.1",
84
84
  "@jsenv/server": "15.3.3",
85
- "@jsenv/sourcemap": "1.2.25",
85
+ "@jsenv/sourcemap": "1.2.26",
86
86
  "@jsenv/url-meta": "8.5.2",
87
- "@jsenv/urls": "2.5.2",
87
+ "@jsenv/urls": "2.5.3",
88
88
  "@jsenv/utils": "2.1.2",
89
89
  "string-width": "7.2.0"
90
90
  },
@@ -1,17 +1,18 @@
1
1
  import { validateResponseIntegrity } from "@jsenv/integrity";
2
2
 
3
3
  export const assertFetchedContentCompliance = ({ urlInfo, content }) => {
4
+ if (urlInfo.status === 404) {
5
+ return;
6
+ }
4
7
  const { expectedContentType } = urlInfo.firstReference;
5
8
  if (expectedContentType && urlInfo.contentType !== expectedContentType) {
6
9
  throw new Error(
7
- `Unexpected content-type on url: "${expectedContentType}" was expect but got "${urlInfo.contentType}`,
10
+ `content-type must be "${expectedContentType}", got "${urlInfo.contentType}`,
8
11
  );
9
12
  }
10
13
  const { expectedType } = urlInfo.firstReference;
11
14
  if (expectedType && urlInfo.type !== expectedType) {
12
- throw new Error(
13
- `Unexpected type on url: "${expectedType}" was expect but got "${urlInfo.type}"`,
14
- );
15
+ throw new Error(`type must be "${expectedType}", got "${urlInfo.type}"`);
15
16
  }
16
17
  const { integrity } = urlInfo.firstReference;
17
18
  if (integrity) {
@@ -342,21 +342,16 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
342
342
  body,
343
343
  isEntryPoint,
344
344
  } = fetchUrlContentReturnValue;
345
- if (status !== 200) {
346
- throw new Error(`unexpected status, ${status}`);
347
- }
348
345
  if (content === undefined) {
349
346
  content = body;
350
347
  }
351
348
  if (contentType === undefined) {
352
349
  contentType = headers["content-type"] || "application/octet-stream";
353
350
  }
351
+ urlInfo.status = status;
354
352
  urlInfo.contentType = contentType;
355
353
  urlInfo.headers = headers;
356
- urlInfo.type =
357
- type ||
358
- urlInfo.firstReference.expectedType ||
359
- inferUrlInfoType(urlInfo);
354
+ urlInfo.type = type || inferUrlInfoType(urlInfo);
360
355
  urlInfo.subtype =
361
356
  subtype ||
362
357
  urlInfo.firstReference.expectedSubtype ||
@@ -680,10 +675,11 @@ const memoizeIsSupported = (runtimeCompat) => {
680
675
 
681
676
  const inferUrlInfoType = (urlInfo) => {
682
677
  const { type, typeHint } = urlInfo;
678
+ const { contentType } = urlInfo;
679
+ const { expectedType } = urlInfo.firstReference;
683
680
  if (type === "sourcemap" || typeHint === "sourcemap") {
684
681
  return "sourcemap";
685
682
  }
686
- const { contentType } = urlInfo;
687
683
  if (contentType === "text/html") {
688
684
  return "html";
689
685
  }
@@ -691,7 +687,12 @@ const inferUrlInfoType = (urlInfo) => {
691
687
  return "css";
692
688
  }
693
689
  if (contentType === "text/javascript") {
694
- if (urlInfo.typeHint === "js_classic") return "js_classic";
690
+ if (expectedType === "js_classic") {
691
+ return "js_classic";
692
+ }
693
+ if (typeHint === "js_classic") {
694
+ return "js_classic";
695
+ }
695
696
  return "js_module";
696
697
  }
697
698
  if (contentType === "application/importmap+json") {
@@ -709,5 +710,5 @@ const inferUrlInfoType = (urlInfo) => {
709
710
  if (CONTENT_TYPE.isTextual(contentType)) {
710
711
  return "text";
711
712
  }
712
- return "other";
713
+ return expectedType || "other";
713
714
  };
@@ -226,6 +226,7 @@ const createUrlInfo = (url, context) => {
226
226
  jsQuote: null, // maybe move to inlineUrlSite?
227
227
 
228
228
  timing: {},
229
+ status: 200,
229
230
  headers: {},
230
231
  debug: false,
231
232
  };
@@ -1,8 +1,8 @@
1
1
  import { parseHtml } from "@jsenv/ast";
2
+ import { generateContentFrame } from "@jsenv/humanize";
2
3
  import { urlToRelativeUrl } from "@jsenv/urls";
3
4
  import { readFileSync } from "node:fs";
4
-
5
- import { generateContentFrame } from "@jsenv/humanize";
5
+ import { jsenvCoreDirectoryUrl } from "../../jsenv_core_directory_url.js";
6
6
 
7
7
  export const jsenvPluginHtmlSyntaxErrorFallback = () => {
8
8
  const htmlSyntaxErrorFileUrl = new URL(
@@ -58,6 +58,10 @@ const generateHtmlForSyntaxError = (
58
58
  const htmlForSyntaxError = String(readFileSync(htmlSyntaxErrorFileUrl));
59
59
  const htmlRelativeUrl = urlToRelativeUrl(htmlUrl, rootDirectoryUrl);
60
60
  const { line, column } = htmlSyntaxError;
61
+ if (htmlUrl.startsWith(jsenvCoreDirectoryUrl.href)) {
62
+ htmlUrl = urlToRelativeUrl(htmlUrl, jsenvCoreDirectoryUrl);
63
+ htmlUrl = `@jsenv/core/${htmlUrl}`;
64
+ }
61
65
  const urlWithLineAndColumn = `${htmlUrl}:${line}:${column}`;
62
66
  const replacers = {
63
67
  fileRelativeUrl: htmlRelativeUrl,
@@ -1,8 +1,9 @@
1
+ import { readEntryStatSync } from "@jsenv/filesystem";
1
2
  import {
2
3
  applyFileSystemMagicResolution,
3
4
  getExtensionsToTry,
4
5
  } from "@jsenv/node-esm-resolution";
5
- import { realpathSync, statSync } from "node:fs";
6
+ import { realpathSync } from "node:fs";
6
7
  import { pathToFileURL } from "node:url";
7
8
 
8
9
  export const jsenvPluginFsRedirection = ({
@@ -39,7 +40,7 @@ export const jsenvPluginFsRedirection = ({
39
40
  const urlObject = new URL(reference.url);
40
41
  let stat;
41
42
  try {
42
- stat = statSync(urlObject);
43
+ stat = readEntryStatSync(urlObject);
43
44
  } catch (e) {
44
45
  if (e.code === "ENOENT") {
45
46
  stat = null;
@@ -118,10 +118,13 @@ export const jsenvPluginProtocolFile = ({
118
118
  };
119
119
  }
120
120
  const contentType = CONTENT_TYPE.fromUrlExtension(urlInfo.url);
121
- if (contentType === "text/html") {
121
+ const request = urlInfo.context.request;
122
+ if (request && request.headers["sec-fetch-dest"] === "document") {
122
123
  try {
123
124
  const fileBuffer = readFileSync(urlObject);
124
- const content = String(fileBuffer);
125
+ const content = CONTENT_TYPE.isTextual(contentType)
126
+ ? String(fileBuffer)
127
+ : fileBuffer;
125
128
  return {
126
129
  content,
127
130
  contentType,
@@ -138,7 +141,7 @@ export const jsenvPluginProtocolFile = ({
138
141
  const parentDirectoryContentArray = readdirSync(
139
142
  new URL(parentDirectoryUrl),
140
143
  );
141
- const html = generateHtmlForENOENTOnHtmlFile(
144
+ const html = generateHtmlForENOENT(
142
145
  urlInfo.url,
143
146
  parentDirectoryContentArray,
144
147
  parentDirectoryUrl,
@@ -146,6 +149,7 @@ export const jsenvPluginProtocolFile = ({
146
149
  directoryListingUrlMocks,
147
150
  );
148
151
  return {
152
+ status: 404,
149
153
  contentType: "text/html",
150
154
  content: html,
151
155
  headers: {
@@ -191,7 +195,7 @@ const generateHtmlForDirectory = (
191
195
  const html = replacePlaceholders(htmlForDirectory, replacers);
192
196
  return html;
193
197
  };
194
- const generateHtmlForENOENTOnHtmlFile = (
198
+ const generateHtmlForENOENT = (
195
199
  url,
196
200
  parentDirectoryContentArray,
197
201
  parentDirectoryUrl,