@jsenv/core 40.2.1 → 40.3.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.
@@ -22,6 +22,7 @@ import {
22
22
  assertAndNormalizeDirectoryUrl,
23
23
  clearDirectorySync,
24
24
  compareFileUrls,
25
+ createLookupPackageDirectory,
25
26
  ensureEmptyDirectory,
26
27
  lookupPackageDirectory,
27
28
  readPackageAtOrNull,
@@ -490,7 +491,21 @@ export const build = async ({
490
491
  return compareFileUrls(a.sourceUrl, b.sourceUrl);
491
492
  });
492
493
 
493
- const packageDirectoryUrl = lookupPackageDirectory(sourceDirectoryUrl);
494
+ const lookupPackageDirectoryUrl = createLookupPackageDirectory();
495
+ const packageDirectoryCache = new Map();
496
+ const readPackageDirectory = (url) => {
497
+ const fromCache = packageDirectoryCache.get(url);
498
+ if (fromCache !== undefined) {
499
+ return fromCache;
500
+ }
501
+ return readPackageAtOrNull(url);
502
+ };
503
+ const packageDirectory = {
504
+ url: lookupPackageDirectory(sourceDirectoryUrl),
505
+ find: lookupPackageDirectoryUrl,
506
+ read: readPackageDirectory,
507
+ };
508
+
494
509
  if (outDirectoryUrl === undefined) {
495
510
  if (
496
511
  process.env.CAPTURING_SIDE_EFFECTS ||
@@ -498,101 +513,24 @@ export const build = async ({
498
513
  urlIsInsideOf(sourceDirectoryUrl, jsenvCoreDirectoryUrl))
499
514
  ) {
500
515
  outDirectoryUrl = new URL("../.jsenv_b/", sourceDirectoryUrl).href;
501
- } else if (packageDirectoryUrl) {
502
- outDirectoryUrl = `${packageDirectoryUrl}.jsenv/`;
516
+ } else if (packageDirectory.url) {
517
+ outDirectoryUrl = `${packageDirectory.url}.jsenv/`;
503
518
  }
504
519
  }
505
- let rootPackageDirectoryUrl = packageDirectoryUrl;
506
- if (packageDirectoryUrl) {
507
- const parentPackageDirectoryUrl = lookupPackageDirectory(
508
- new URL("../", packageDirectoryUrl),
520
+ let rootPackageDirectoryUrl;
521
+ if (packageDirectory.url) {
522
+ const parentPackageDirectoryUrl = packageDirectory.find(
523
+ new URL("../", packageDirectory.url),
509
524
  );
510
- if (parentPackageDirectoryUrl) {
511
- rootPackageDirectoryUrl = parentPackageDirectoryUrl;
512
- }
525
+ rootPackageDirectoryUrl = parentPackageDirectoryUrl || packageDirectory.url;
526
+ } else {
527
+ rootPackageDirectoryUrl = packageDirectory.url;
513
528
  }
514
529
 
515
530
  const runBuild = async ({ signal }) => {
516
531
  const startDate = Date.now();
517
532
  const { onBuildEnd, onEntryPointBuildStart } = startBuildLogs();
518
533
 
519
- const sourceFileBuildCallbackMap = new Map();
520
- const registerSourceFileBuildEffect = (url, callback) => {
521
- const buildCallbackSet = sourceFileBuildCallbackMap.get(url);
522
- if (buildCallbackSet) {
523
- buildCallbackSet.add(callback);
524
- } else {
525
- const set = new Set();
526
- set.add(callback);
527
- sourceFileBuildCallbackMap.set(url, set);
528
- }
529
- };
530
- const onSourceFileBuild = ({
531
- sourceUrlInfo,
532
- sourceFileUrl,
533
- buildFileUrl,
534
- }) => {
535
- const buildCallbackSet = sourceFileBuildCallbackMap.get(sourceFileUrl);
536
- if (buildCallbackSet) {
537
- for (const buildCallback of buildCallbackSet) {
538
- buildCallback({ sourceUrlInfo, buildFileUrl });
539
- }
540
- }
541
- };
542
- sync_package_side_effects: {
543
- if (!packageDirectoryUrl) {
544
- break sync_package_side_effects;
545
- }
546
- if (
547
- urlIsInsideOf(packageDirectoryUrl, jsenvCoreDirectoryUrl) ||
548
- packageDirectoryUrl === String(jsenvCoreDirectoryUrl)
549
- ) {
550
- break sync_package_side_effects;
551
- }
552
- const packageJson = readPackageAtOrNull(packageDirectoryUrl);
553
- if (!packageJson) {
554
- break sync_package_side_effects;
555
- }
556
- const { sideEffects } = packageJson;
557
- if (!sideEffects || !Array.isArray(sideEffects)) {
558
- break sync_package_side_effects;
559
- }
560
- const sideEffectFileUrlSet = new Set();
561
- const packageJsonFileUrl = new URL("./package.json", packageDirectoryUrl)
562
- .href;
563
- for (const sideEffectFileRelativeUrl of sideEffects) {
564
- const sideEffectFileUrl = new URL(
565
- sideEffectFileRelativeUrl,
566
- packageDirectoryUrl,
567
- ).href;
568
- sideEffectFileUrlSet.add(sideEffectFileUrl);
569
- registerSourceFileBuildEffect(
570
- sideEffectFileUrl,
571
- ({ sourceUrlInfo, buildFileUrl }) => {
572
- if (sourceUrlInfo.isInline) {
573
- return;
574
- }
575
- const urlRelativeToPackage = urlToRelativeUrl(
576
- buildFileUrl,
577
- packageDirectoryUrl,
578
- );
579
- if (sideEffectFileUrlSet.has(buildFileUrl)) {
580
- return;
581
- }
582
- sideEffects.push(
583
- urlRelativeToPackage[0] === "."
584
- ? urlRelativeToPackage
585
- : `./${urlRelativeToPackage}`,
586
- );
587
- writeFileSync(
588
- packageJsonFileUrl,
589
- JSON.stringify(packageJson, null, " "),
590
- );
591
- },
592
- );
593
- }
594
- }
595
-
596
534
  const buildUrlsGenerator = createBuildUrlsGenerator({
597
535
  sourceDirectoryUrl,
598
536
  buildDirectoryUrl,
@@ -643,9 +581,9 @@ export const build = async ({
643
581
  buildDirectoryUrl,
644
582
  outDirectoryUrl: entryOutDirectoryUrl,
645
583
  sourceRelativeUrl: entryPoint.sourceRelativeUrl,
584
+ packageDirectory,
646
585
  buildUrlsGenerator,
647
586
  someEntryPointUseNode,
648
- onSourceFileBuild,
649
587
  },
650
588
  entryPoint.params,
651
589
  );
@@ -857,6 +795,7 @@ const entryPointDefaultParams = {
857
795
  sourcemapsSourcesContent: undefined,
858
796
  assetManifest: false,
859
797
  assetManifestFileRelativeUrl: "asset-manifest.json",
798
+ packageSideEffects: true,
860
799
  };
861
800
 
862
801
  const prepareEntryPointBuild = async (
@@ -864,11 +803,11 @@ const prepareEntryPointBuild = async (
864
803
  signal,
865
804
  sourceDirectoryUrl,
866
805
  buildDirectoryUrl,
867
- sourceRelativeUrl,
868
806
  outDirectoryUrl,
807
+ sourceRelativeUrl,
808
+ packageDirectory,
869
809
  buildUrlsGenerator,
870
810
  someEntryPointUseNode,
871
- onSourceFileBuild,
872
811
  },
873
812
  entryPointParams,
874
813
  ) => {
@@ -906,6 +845,7 @@ const prepareEntryPointBuild = async (
906
845
  sourcemapsSourcesContent,
907
846
  assetManifest,
908
847
  assetManifestFileRelativeUrl,
848
+ packageSideEffects,
909
849
  } = {
910
850
  ...entryPointDefaultParams,
911
851
  ...entryPointParams,
@@ -998,6 +938,7 @@ const prepareEntryPointBuild = async (
998
938
  outDirectoryUrl: outDirectoryUrl
999
939
  ? new URL("craft/", outDirectoryUrl)
1000
940
  : undefined,
941
+ packageDirectory,
1001
942
  });
1002
943
 
1003
944
  let _getOtherEntryBuildInfo;
@@ -1025,6 +966,7 @@ const prepareEntryPointBuild = async (
1025
966
  ...(bundling ? [jsenvPluginBundling(bundling)] : []),
1026
967
  ...(minification ? [jsenvPluginMinification(minification)] : []),
1027
968
  ...getCorePlugins({
969
+ packageDirectory,
1028
970
  rootDirectoryUrl: sourceDirectoryUrl,
1029
971
  runtimeCompat,
1030
972
  referenceAnalysis,
@@ -1042,6 +984,7 @@ const prepareEntryPointBuild = async (
1042
984
  inlining: false,
1043
985
  http,
1044
986
  scenarioPlaceholders,
987
+ packageSideEffects,
1045
988
  }),
1046
989
  ]);
1047
990
  const rawPluginController = createPluginController(
@@ -1094,6 +1037,7 @@ const prepareEntryPointBuild = async (
1094
1037
  outDirectoryUrl: outDirectoryUrl
1095
1038
  ? new URL("shape/", outDirectoryUrl)
1096
1039
  : undefined,
1040
+ packageDirectory,
1097
1041
  });
1098
1042
  const buildSpecifierManager = createBuildSpecifierManager({
1099
1043
  rawKitchen,
@@ -1112,7 +1056,6 @@ const prepareEntryPointBuild = async (
1112
1056
  versioningViaImportmap &&
1113
1057
  rawKitchen.graph.getUrlInfo(entryReference.url).type === "html" &&
1114
1058
  rawKitchen.context.isSupportedOnCurrentClients("importmap"),
1115
- onSourceFileBuild,
1116
1059
  });
1117
1060
  const finalPluginStore = createPluginStore([
1118
1061
  jsenvPluginReferenceAnalysis({
@@ -1137,7 +1080,7 @@ const prepareEntryPointBuild = async (
1137
1080
  appliesDuring: "build",
1138
1081
  transformUrlContent: async (urlInfo) => {
1139
1082
  await rawKitchen.pluginController.callAsyncHooks(
1140
- "optimizeUrlContent",
1083
+ "optimizeBuildUrlContent",
1141
1084
  urlInfo,
1142
1085
  (optimizeReturnValue) => {
1143
1086
  urlInfo.mutateContent(optimizeReturnValue);
@@ -1365,6 +1308,41 @@ const prepareEntryPointBuild = async (
1365
1308
  buildOperation.throwIfAborted();
1366
1309
  }
1367
1310
  }
1311
+
1312
+ refine_hook: {
1313
+ const refineBuildUrlContentCallbackSet = new Set();
1314
+ const refineBuildCallbackSet = new Set();
1315
+ for (const plugin of rawKitchen.pluginController.activePlugins) {
1316
+ const refineBuildUrlContent = plugin.refineBuildUrlContent;
1317
+ if (refineBuildUrlContent) {
1318
+ refineBuildUrlContentCallbackSet.add(refineBuildUrlContent);
1319
+ }
1320
+ const refineBuild = plugin.refineBuild;
1321
+ if (refineBuild) {
1322
+ refineBuildCallbackSet.add(refineBuild);
1323
+ }
1324
+ }
1325
+ if (refineBuildUrlContentCallbackSet.size) {
1326
+ GRAPH_VISITOR.forEachUrlInfoStronglyReferenced(
1327
+ finalKitchen.graph.rootUrlInfo,
1328
+ (buildUrlInfo) => {
1329
+ if (!buildUrlInfo.url.startsWith("file:")) {
1330
+ return;
1331
+ }
1332
+ for (const refineBuildUrlContentCallback of refineBuildUrlContentCallbackSet) {
1333
+ refineBuildUrlContentCallback(buildUrlInfo, {
1334
+ buildUrl: buildSpecifierManager.getBuildUrl(buildUrlInfo),
1335
+ });
1336
+ }
1337
+ },
1338
+ );
1339
+ }
1340
+ if (refineBuildCallbackSet.size) {
1341
+ for (const refineBuildCallback of refineBuildCallbackSet) {
1342
+ refineBuildCallback(finalKitchen);
1343
+ }
1344
+ }
1345
+ }
1368
1346
  }
1369
1347
  const {
1370
1348
  buildFileContents,
@@ -45,7 +45,6 @@ export const createBuildSpecifierManager = ({
45
45
  versioningMethod,
46
46
  versionLength,
47
47
  canUseImportmap,
48
- onSourceFileBuild,
49
48
  }) => {
50
49
  const placeholderAPI = createPlaceholderAPI({
51
50
  length,
@@ -112,31 +111,6 @@ export const createBuildSpecifierManager = ({
112
111
  buildSpecifier,
113
112
  reference,
114
113
  );
115
-
116
- if (buildUrlInfo.sourceUrls) {
117
- for (const sourceUrl of buildUrlInfo.sourceUrls) {
118
- const rawUrlInfo = rawKitchen.graph.getUrlInfo(sourceUrl);
119
- if (rawUrlInfo) {
120
- onSourceFileBuild({
121
- sourceUrlInfo: rawUrlInfo,
122
- buildUrlInfo,
123
- sourceFileUrl: rawUrlInfo.url,
124
- buildFileUrl: buildUrl,
125
- });
126
- }
127
- }
128
- } else if (buildUrlInfo.originalUrl) {
129
- const rawUrlInfo = rawKitchen.graph.getUrlInfo(buildUrlInfo.originalUrl);
130
- if (rawUrlInfo) {
131
- onSourceFileBuild({
132
- sourceUrlInfo: rawUrlInfo,
133
- buildUrlInfo,
134
- sourceFileUrl: rawUrlInfo.url,
135
- buildFileUrl: buildUrl,
136
- });
137
- }
138
- }
139
-
140
114
  return buildGeneratedSpecifier;
141
115
  };
142
116
  const internalRedirections = new Map();
@@ -153,14 +127,17 @@ export const createBuildSpecifierManager = ({
153
127
  );
154
128
  for (const url of Object.keys(urlInfosBundled)) {
155
129
  const urlInfoBundled = urlInfosBundled[url];
130
+ const contentSideEffects = [];
156
131
  if (urlInfoBundled.sourceUrls) {
157
132
  for (const sourceUrl of urlInfoBundled.sourceUrls) {
158
- const sourceRawUrlInfo = rawKitchen.graph.getUrlInfo(sourceUrl);
159
- if (sourceRawUrlInfo) {
160
- sourceRawUrlInfo.data.bundled = true;
133
+ const rawUrlInfo = rawKitchen.graph.getUrlInfo(sourceUrl);
134
+ if (rawUrlInfo) {
135
+ rawUrlInfo.data.bundled = true;
136
+ contentSideEffects.push(...rawUrlInfo.contentSideEffects);
161
137
  }
162
138
  }
163
139
  }
140
+ urlInfoBundled.contentSideEffects = contentSideEffects;
164
141
  bundleInfoMap.set(url, urlInfoBundled);
165
142
  }
166
143
  };
@@ -322,6 +299,7 @@ export const createBuildSpecifierManager = ({
322
299
  contentType: bundleInfo.contentType,
323
300
  sourcemap: bundleInfo.sourcemap,
324
301
  data: bundleInfo.data,
302
+ contentSideEffects: bundleInfo.contentSideEffects,
325
303
  };
326
304
  }
327
305
  const rawUrlInfo = rawKitchen.graph.getUrlInfo(rawUrl);
@@ -370,6 +348,7 @@ export const createBuildSpecifierManager = ({
370
348
  originalContent: rawUrlInfo.originalContent,
371
349
  originalUrl: rawUrlInfo.originalUrl,
372
350
  sourcemap: rawUrlInfo.sourcemap,
351
+ contentSideEffects: rawUrlInfo.contentSideEffects,
373
352
  };
374
353
  }
375
354
  if (firstReference.isInline) {
@@ -1080,6 +1059,8 @@ export const createBuildSpecifierManager = ({
1080
1059
  };
1081
1060
  },
1082
1061
 
1062
+ getBuildUrl: (urlInfo) => urlInfoToBuildUrlMap.get(urlInfo),
1063
+
1083
1064
  getBuildInfo: () => {
1084
1065
  const buildManifest = {};
1085
1066
  const buildContents = {};
@@ -2,6 +2,7 @@ import {
2
2
  assertAndNormalizeDirectoryUrl,
3
3
  bufferToEtag,
4
4
  lookupPackageDirectory,
5
+ readPackageAtOrNull,
5
6
  } from "@jsenv/filesystem";
6
7
  import { createLogger, createTaskLog } from "@jsenv/humanize";
7
8
  import {
@@ -240,10 +241,17 @@ export const startDevServer = async ({
240
241
  );
241
242
  serverStopCallbackSet.add(stopWatchingSourceFiles);
242
243
 
244
+ const packageDirectory = {
245
+ url: lookupPackageDirectory(sourceDirectoryUrl),
246
+ find: lookupPackageDirectory,
247
+ read: readPackageAtOrNull,
248
+ };
249
+
243
250
  const devServerPluginStore = createPluginStore([
244
251
  jsenvPluginServerEvents({ clientAutoreload }),
245
252
  ...plugins,
246
253
  ...getCorePlugins({
254
+ packageDirectory,
247
255
  rootDirectoryUrl: sourceDirectoryUrl,
248
256
  mainFilePath: sourceMainFilePath,
249
257
  runtimeCompat,
@@ -307,6 +315,7 @@ export const startDevServer = async ({
307
315
  outDirectoryUrl: outDirectoryUrl
308
316
  ? new URL(`${runtimeName}@${runtimeVersion}/`, outDirectoryUrl)
309
317
  : undefined,
318
+ packageDirectory,
310
319
  });
311
320
  kitchen.graph.urlInfoCreatedEventEmitter.on((urlInfoCreated) => {
312
321
  const { watch } = URL_META.applyAssociations({
@@ -49,6 +49,7 @@ export const createKitchen = ({
49
49
  sourcemapsSourcesContent,
50
50
  outDirectoryUrl,
51
51
  initialContext = {},
52
+ packageDirectory,
52
53
  }) => {
53
54
  const logger = createLogger({ logLevel });
54
55
 
@@ -63,6 +64,7 @@ export const createKitchen = ({
63
64
  logger,
64
65
  rootDirectoryUrl,
65
66
  mainFilePath,
67
+ packageDirectory,
66
68
  dev,
67
69
  build,
68
70
  runtimeCompat,
@@ -79,6 +81,8 @@ export const createKitchen = ({
79
81
  conditions: packageConditions,
80
82
  parentUrl: importer,
81
83
  specifier,
84
+ lookupPackageScope: packageDirectory.find,
85
+ readPackageJson: packageDirectory.read,
82
86
  });
83
87
  return { url, packageDirectoryUrl, packageJson };
84
88
  },
@@ -99,6 +103,9 @@ export const createKitchen = ({
99
103
  rootDirectoryUrl,
100
104
  kitchen,
101
105
  });
106
+ graph.urlInfoCreatedEventEmitter.on((urlInfoCreated) => {
107
+ pluginController.callHooks("urlInfoCreated", urlInfoCreated, () => {});
108
+ });
102
109
  kitchen.graph = graph;
103
110
 
104
111
  const urlInfoTransformer = createUrlInfoTransformer({
@@ -351,6 +358,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
351
358
  isEntryPoint,
352
359
  isDynamicEntryPoint,
353
360
  filenameHint,
361
+ contentSideEffects,
354
362
  } = fetchUrlContentReturnValue;
355
363
  if (content === undefined) {
356
364
  content = body;
@@ -383,6 +391,9 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
383
391
  if (typeof isDynamicEntryPoint === "boolean") {
384
392
  urlInfo.isDynamicEntryPoint = isDynamicEntryPoint;
385
393
  }
394
+ if (contentSideEffects) {
395
+ urlInfo.contentSideEffects = contentSideEffects;
396
+ }
386
397
  assertFetchedContentCompliance({
387
398
  urlInfo,
388
399
  content,
@@ -7,7 +7,6 @@ import {
7
7
  urlToBasename,
8
8
  urlToExtension,
9
9
  } from "@jsenv/urls";
10
-
11
10
  import { prependContent } from "../prepend_content.js";
12
11
 
13
12
  let referenceId = 0;
@@ -40,7 +39,14 @@ export const createDependencies = (ownerUrlInfo) => {
40
39
  ...props,
41
40
  });
42
41
  const reference = originalReference.resolve();
43
- reference.finalize();
42
+ if (reference.urlInfo) {
43
+ return reference;
44
+ }
45
+ const kitchen = ownerUrlInfo.kitchen;
46
+ const urlInfo = kitchen.graph.reuseOrCreateUrlInfo(reference);
47
+ reference.urlInfo = urlInfo;
48
+ addDependency(reference);
49
+ ownerUrlInfo.context.finalizeReference(reference);
44
50
  return reference;
45
51
  };
46
52
 
@@ -356,6 +362,7 @@ const createReference = ({
356
362
  implicitReferenceSet: new Set(),
357
363
  isWeak,
358
364
  hasVersioningEffect,
365
+ urlInfoEffectSet: new Set(),
359
366
  version,
360
367
  injected,
361
368
  timing: {},
@@ -389,17 +396,6 @@ const createReference = ({
389
396
  return referenceRedirected;
390
397
  };
391
398
 
392
- reference.finalize = () => {
393
- if (reference.urlInfo) {
394
- return;
395
- }
396
- const kitchen = ownerUrlInfo.kitchen;
397
- const urlInfo = kitchen.graph.reuseOrCreateUrlInfo(reference);
398
- reference.urlInfo = urlInfo;
399
- addDependency(reference);
400
- ownerUrlInfo.context.finalizeReference(reference);
401
- };
402
-
403
399
  // "formatReference" can be async BUT this is an exception
404
400
  // for most cases it will be sync. We want to favor the sync signature to keep things simpler
405
401
  // The only case where it needs to be async is when
@@ -762,4 +758,8 @@ const applyReferenceEffectsOnUrlInfo = (reference) => {
762
758
  referencedUrlInfo.entryUrlInfo = reference.isEntryPoint
763
759
  ? referencedUrlInfo
764
760
  : reference.ownerUrlInfo.entryUrlInfo;
761
+
762
+ for (const urlInfoEffect of reference.urlInfoEffectSet) {
763
+ urlInfoEffect(referencedUrlInfo);
764
+ }
765
765
  };
@@ -3,7 +3,6 @@ import {
3
3
  injectQueryParamsIntoSpecifier,
4
4
  urlToRelativeUrl,
5
5
  } from "@jsenv/urls";
6
-
7
6
  import { createEventEmitter } from "../../helpers/event_emitter.js";
8
7
  import { createDependencies } from "./references.js";
9
8
  import { GRAPH_VISITOR } from "./url_graph_visitor.js";
@@ -213,6 +212,7 @@ const createUrlInfo = (url, context) => {
213
212
  contentAst: undefined,
214
213
  contentLength: undefined,
215
214
  contentFinalized: false,
215
+ contentSideEffects: [],
216
216
 
217
217
  sourcemap: null,
218
218
  sourcemapIsWrong: false,
@@ -242,6 +242,26 @@ const createUrlInfo = (url, context) => {
242
242
  urlInfo.pathname = new URL(url).pathname;
243
243
  urlInfo.searchParams = new URL(url).searchParams;
244
244
 
245
+ Object.defineProperty(urlInfo, "packageDirectoryUrl", {
246
+ enumerable: true,
247
+ configurable: true,
248
+ get: () => context.packageDirectory.find(url),
249
+ });
250
+ Object.defineProperty(urlInfo, "packageJSON", {
251
+ enumerable: true,
252
+ configurable: true,
253
+ get: () => {
254
+ const packageDirectoryUrl = context.packageDirectory.find(url);
255
+ return packageDirectoryUrl
256
+ ? context.packageDirectory.read(packageDirectoryUrl)
257
+ : null;
258
+ },
259
+ });
260
+ Object.defineProperty(urlInfo, "packageName", {
261
+ enumerable: true,
262
+ configurable: true,
263
+ get: () => urlInfo.packageJSON?.name,
264
+ });
245
265
  urlInfo.dependencies = createDependencies(urlInfo);
246
266
  urlInfo.isUsed = () => {
247
267
  if (urlInfo.isRoot) {
@@ -9,6 +9,6 @@
9
9
  <body>
10
10
  <p>Syntax error: <strong>${reasonCode}</strong></p>
11
11
  <a jsenv-ignore href="${errorLinkHref}">${errorLinkText}</a>
12
- <pre>${syntaxError}</pre>
12
+ ${syntaxErrorHTML}
13
13
  </body>
14
14
  </html>
@@ -1,5 +1,5 @@
1
1
  import { parseHtml } from "@jsenv/ast";
2
- import { generateContentFrame } from "@jsenv/humanize";
2
+ import { errorToHTML, generateContentFrame } from "@jsenv/humanize";
3
3
  import { urlToRelativeUrl } from "@jsenv/urls";
4
4
  import { readFileSync } from "node:fs";
5
5
  import { jsenvCoreDirectoryUrl } from "../../jsenv_core_directory_url.js";
@@ -71,19 +71,11 @@ const generateHtmlForSyntaxError = (
71
71
  urlWithLineAndColumn,
72
72
  )}')`,
73
73
  errorLinkText: `${htmlRelativeUrl}:${line}:${column}`,
74
- syntaxError: escapeHtml(htmlErrorContentFrame),
74
+ syntaxErrorHTML: errorToHTML(htmlErrorContentFrame),
75
75
  };
76
76
  const html = replacePlaceholders(htmlForSyntaxError, replacers);
77
77
  return html;
78
78
  };
79
- const escapeHtml = (string) => {
80
- return string
81
- .replace(/&/g, "&amp;")
82
- .replace(/</g, "&lt;")
83
- .replace(/>/g, "&gt;")
84
- .replace(/"/g, "&quot;")
85
- .replace(/'/g, "&#039;");
86
- };
87
79
  const replacePlaceholders = (html, replacers) => {
88
80
  return html.replace(/\$\{(\w+)\}/g, (match, name) => {
89
81
  const replacer = replacers[name];