@jsenv/core 34.2.2 → 34.3.0

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.
Files changed (36) hide show
  1. package/dist/html/explorer.html +5 -4
  2. package/dist/importmap_node_loader.mjs +49 -0
  3. package/dist/js/resolveImport.js +504 -0
  4. package/dist/jsenv.js +392 -670
  5. package/dist/no_experimental_warnings.cjs +8 -0
  6. package/package.json +2 -1
  7. package/src/build/build.js +32 -14
  8. package/src/build/version_mappings_injection.js +20 -27
  9. package/src/dev/file_service.js +1 -1
  10. package/src/execute/execute.js +2 -0
  11. package/src/execute/runtimes/node/exec_options.js +15 -2
  12. package/src/execute/runtimes/node/importmap_node_loader.mjs +51 -0
  13. package/src/execute/runtimes/node/importmap_node_loader_file_url.js +4 -0
  14. package/src/execute/runtimes/node/no_experimental_warnings.cjs +12 -0
  15. package/src/execute/runtimes/node/no_experimental_warnings_file_url.js +4 -0
  16. package/src/execute/runtimes/node/node_child_process.js +15 -0
  17. package/src/execute/runtimes/node/node_worker_thread.js +13 -0
  18. package/src/kitchen/kitchen.js +5 -3
  19. package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +2 -2
  20. package/src/plugins/importmap/jsenv_plugin_importmap.js +6 -2
  21. package/src/plugins/{inline/jsenv_plugin_html_inline_content.js → inline_content_analysis/jsenv_plugin_html_inline_content_analysis.js} +12 -6
  22. package/src/plugins/{inline/jsenv_plugin_inline.js → inline_content_analysis/jsenv_plugin_inline_content_analysis.js} +8 -10
  23. package/src/plugins/{inline/jsenv_plugin_js_inline_content.js → inline_content_analysis/jsenv_plugin_js_inline_content_analysis.js} +4 -2
  24. package/src/plugins/inlining/jsenv_plugin_inlining.js +22 -0
  25. package/src/plugins/{inline/jsenv_plugin_inline_query_param.js → inlining/jsenv_plugin_inlining_as_data_url.js} +16 -9
  26. package/src/plugins/inlining/jsenv_plugin_inlining_into_html.js +149 -0
  27. package/src/plugins/plugins.js +5 -2
  28. package/src/plugins/ribbon/jsenv_plugin_ribbon.js +11 -10
  29. package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +2 -2
  30. package/src/plugins/supervisor/html_supervisor_injection.js +23 -25
  31. package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +20 -5
  32. package/src/plugins/transpilation/js_module_fallback/jsenv_plugin_js_module_fallback_inside_html.js +2 -2
  33. package/src/plugins/transpilation/js_module_fallback/jsenv_plugin_js_module_fallback_on_workers.js +3 -3
  34. package/src/plugins/url_analysis/html/html_urls.js +1 -1
  35. /package/src/plugins/{inline → inline_content_analysis}/client/inline_content.js +0 -0
  36. /package/src/plugins/{inline → inline_content_analysis}/jsenv_plugin_data_urls.js +0 -0
package/dist/jsenv.js CHANGED
@@ -15,9 +15,10 @@ import { Readable, Stream, Writable } from "node:stream";
15
15
  import { Http2ServerResponse } from "node:http2";
16
16
  import { lookup } from "node:dns";
17
17
  import { SOURCEMAP, generateSourcemapFileUrl, composeTwoSourcemaps, generateSourcemapDataUrl, createMagicSource, getOriginalPosition } from "@jsenv/sourcemap";
18
- import { parseHtmlString, stringifyHtmlAst, getHtmlNodeAttribute, visitHtmlNodes, analyzeScriptNode, setHtmlNodeAttributes, parseSrcSet, getHtmlNodePosition, getHtmlNodeAttributePosition, parseCssUrls, parseJsUrls, getHtmlNodeText, setHtmlNodeText, removeHtmlNodeText, applyBabelPlugins, injectScriptNodeAsEarlyAsPossible, createHtmlNode, findHtmlNode, removeHtmlNode, injectJsImport, analyzeLinkNode, injectHtmlNode, insertHtmlNodeAfter } from "@jsenv/ast";
18
+ import { parseHtmlString, stringifyHtmlAst, getHtmlNodeAttribute, visitHtmlNodes, analyzeScriptNode, setHtmlNodeAttributes, parseSrcSet, getHtmlNodePosition, getHtmlNodeAttributePosition, parseCssUrls, parseJsUrls, getHtmlNodeText, setHtmlNodeText, removeHtmlNodeText, applyBabelPlugins, injectHtmlNodeAsEarlyAsPossible, createHtmlNode, findHtmlNode, removeHtmlNode, injectJsImport, analyzeLinkNode, injectHtmlNode, insertHtmlNodeAfter } from "@jsenv/ast";
19
19
  import { createRequire } from "node:module";
20
20
  import babelParser from "@babel/parser";
21
+ import { assertImportMap, resolveUrl as resolveUrl$1, normalizeImportMap, resolveImport } from "./js/resolveImport.js";
21
22
  import v8, { takeCoverage } from "node:v8";
22
23
  import stripAnsi from "strip-ansi";
23
24
  import { createId } from "@paralleldrive/cuid2";
@@ -77,7 +78,7 @@ const DATA_URL = {
77
78
  }
78
79
  };
79
80
 
80
- const urlToScheme$1 = url => {
81
+ const urlToScheme = url => {
81
82
  const urlString = String(url);
82
83
  const colonIndex = urlString.indexOf(":");
83
84
  if (colonIndex === -1) {
@@ -88,7 +89,7 @@ const urlToScheme$1 = url => {
88
89
  };
89
90
 
90
91
  const urlToResource = url => {
91
- const scheme = urlToScheme$1(url);
92
+ const scheme = urlToScheme(url);
92
93
  if (scheme === "file") {
93
94
  const urlAsStringWithoutFileProtocol = String(url).slice("file://".length);
94
95
  return urlAsStringWithoutFileProtocol;
@@ -104,7 +105,7 @@ const urlToResource = url => {
104
105
  return urlAsStringWithoutProtocol;
105
106
  };
106
107
 
107
- const urlToPathname$1 = url => {
108
+ const urlToPathname = url => {
108
109
  const resource = urlToResource(url);
109
110
  const pathname = resourceToPathname(resource);
110
111
  return pathname;
@@ -122,7 +123,7 @@ const resourceToPathname = resource => {
122
123
  };
123
124
 
124
125
  const urlToFilename$1 = url => {
125
- const pathname = urlToPathname$1(url);
126
+ const pathname = urlToPathname(url);
126
127
  const pathnameBeforeLastSlash = pathname.endsWith("/") ? pathname.slice(0, -1) : pathname;
127
128
  const slashLastIndex = pathnameBeforeLastSlash.lastIndexOf("/");
128
129
  const filename = slashLastIndex === -1 ? pathnameBeforeLastSlash : pathnameBeforeLastSlash.slice(slashLastIndex + 1);
@@ -319,10 +320,10 @@ const lineRangeWithinLines = ({
319
320
  };
320
321
 
321
322
  const urlToExtension$1 = url => {
322
- const pathname = urlToPathname$1(url);
323
- return pathnameToExtension$1(pathname);
323
+ const pathname = urlToPathname(url);
324
+ return pathnameToExtension(pathname);
324
325
  };
325
- const pathnameToExtension$1 = pathname => {
326
+ const pathnameToExtension = pathname => {
326
327
  const slashLastIndex = pathname.lastIndexOf("/");
327
328
  if (slashLastIndex !== -1) {
328
329
  pathname = pathname.slice(slashLastIndex + 1);
@@ -446,7 +447,7 @@ const getCallerPosition = () => {
446
447
  };
447
448
  };
448
449
 
449
- const resolveUrl$1 = (specifier, baseUrl) => {
450
+ const resolveUrl = (specifier, baseUrl) => {
450
451
  if (typeof baseUrl === "undefined") {
451
452
  throw new TypeError(`baseUrl missing to resolve ${specifier}`);
452
453
  }
@@ -519,7 +520,7 @@ const urlToRelativeUrl = (url, baseUrl) => {
519
520
  const specificPathname = pathname.slice(commonPathname.length);
520
521
  const baseSpecificPathname = basePathname.slice(commonPathname.length);
521
522
  if (baseSpecificPathname.includes("/")) {
522
- const baseSpecificParentPathname = pathnameToParentPathname$1(baseSpecificPathname);
523
+ const baseSpecificParentPathname = pathnameToParentPathname(baseSpecificPathname);
523
524
  const relativeDirectoriesNotation = baseSpecificParentPathname.replace(/.*?\//g, "../");
524
525
  const relativeUrl = `${relativeDirectoriesNotation}${specificPathname}${search}${hash}`;
525
526
  return relativeUrl;
@@ -527,7 +528,7 @@ const urlToRelativeUrl = (url, baseUrl) => {
527
528
  const relativeUrl = `${specificPathname}${search}${hash}`;
528
529
  return relativeUrl;
529
530
  };
530
- const pathnameToParentPathname$1 = pathname => {
531
+ const pathnameToParentPathname = pathname => {
531
532
  const slashLastIndex = pathname.lastIndexOf("/");
532
533
  if (slashLastIndex === -1) {
533
534
  return "/";
@@ -1674,7 +1675,7 @@ const removeDirectory = async (rootDirectoryUrl, {
1674
1675
  removeDirectoryOperation.throwIfAborted();
1675
1676
  const names = await readDirectory(directoryUrl);
1676
1677
  await Promise.all(names.map(async name => {
1677
- const url = resolveUrl$1(name, directoryUrl);
1678
+ const url = resolveUrl(name, directoryUrl);
1678
1679
  await visit(url);
1679
1680
  }));
1680
1681
  };
@@ -2634,7 +2635,7 @@ const UNICODE = {
2634
2635
  supported: canUseUnicode
2635
2636
  };
2636
2637
 
2637
- const createDetailedMessage$1 = (message, details = {}) => {
2638
+ const createDetailedMessage = (message, details = {}) => {
2638
2639
  let string = `${message}`;
2639
2640
  Object.keys(details).forEach(key => {
2640
2641
  const value = details[key];
@@ -4967,7 +4968,7 @@ const startServer = async ({
4967
4968
  warn,
4968
4969
  requestWaitingMs
4969
4970
  }) => {
4970
- warn(createDetailedMessage$1(`still no response found for request after ${requestWaitingMs} ms`, {
4971
+ warn(createDetailedMessage(`still no response found for request after ${requestWaitingMs} ms`, {
4971
4972
  "request url": request.url,
4972
4973
  "request headers": JSON.stringify(request.headers, null, " ")
4973
4974
  }));
@@ -5352,7 +5353,7 @@ const startServer = async ({
5352
5353
  if (error.message === "aborted") {
5353
5354
  addRequestLog(rootRequestNode, {
5354
5355
  type: "debug",
5355
- value: createDetailedMessage$1(`request aborted by client`, {
5356
+ value: createDetailedMessage(`request aborted by client`, {
5356
5357
  "error message": error.message
5357
5358
  })
5358
5359
  });
@@ -5360,7 +5361,7 @@ const startServer = async ({
5360
5361
  // I'm not sure this can happen but it's here in case
5361
5362
  addRequestLog(rootRequestNode, {
5362
5363
  type: "error",
5363
- value: createDetailedMessage$1(`"error" event emitted on request`, {
5364
+ value: createDetailedMessage(`"error" event emitted on request`, {
5364
5365
  "error stack": error.stack
5365
5366
  })
5366
5367
  });
@@ -5379,7 +5380,7 @@ const startServer = async ({
5379
5380
  const onPushStreamError = e => {
5380
5381
  addRequestLog(requestNode, {
5381
5382
  type: "error",
5382
- value: createDetailedMessage$1(`An error occured while pushing a stream to the response for ${request.resource}`, {
5383
+ value: createDetailedMessage(`An error occured while pushing a stream to the response for ${request.resource}`, {
5383
5384
  "error stack": e.stack
5384
5385
  })
5385
5386
  });
@@ -5610,7 +5611,7 @@ const startServer = async ({
5610
5611
  }
5611
5612
  addRequestLog(requestNode, {
5612
5613
  type: "error",
5613
- value: createDetailedMessage$1(`internal error while handling request`, {
5614
+ value: createDetailedMessage(`internal error while handling request`, {
5614
5615
  "error stack": errorWhileHandlingRequest.stack
5615
5616
  })
5616
5617
  });
@@ -5704,7 +5705,7 @@ const startServer = async ({
5704
5705
  onError: error => {
5705
5706
  addRequestLog(requestNode, {
5706
5707
  type: "error",
5707
- value: createDetailedMessage$1(`An error occured while sending response`, {
5708
+ value: createDetailedMessage(`An error occured while sending response`, {
5708
5709
  "error stack": error.stack
5709
5710
  })
5710
5711
  });
@@ -8373,7 +8374,7 @@ const createResolveUrlError = ({
8373
8374
  reason,
8374
8375
  ...details
8375
8376
  }) => {
8376
- const resolveError = new Error(createDetailedMessage$1(`Failed to resolve url reference`, {
8377
+ const resolveError = new Error(createDetailedMessage(`Failed to resolve url reference`, {
8377
8378
  reason,
8378
8379
  ...details,
8379
8380
  "specifier": `"${reference.specifier}"`,
@@ -8392,7 +8393,7 @@ const createResolveUrlError = ({
8392
8393
  });
8393
8394
  }
8394
8395
  if (error.code === "DIRECTORY_REFERENCE_NOT_ALLOWED") {
8395
- error.message = createDetailedMessage$1(error.message, {
8396
+ error.message = createDetailedMessage(error.message, {
8396
8397
  "reference trace": reference.trace.message
8397
8398
  });
8398
8399
  return error;
@@ -8413,7 +8414,7 @@ const createFetchUrlContentError = ({
8413
8414
  reason,
8414
8415
  ...details
8415
8416
  }) => {
8416
- const fetchError = new Error(createDetailedMessage$1(`Failed to fetch url content`, {
8417
+ const fetchError = new Error(createDetailedMessage(`Failed to fetch url content`, {
8417
8418
  reason,
8418
8419
  ...details,
8419
8420
  "url": urlInfo.url,
@@ -8483,7 +8484,7 @@ const createTransformUrlContentError = ({
8483
8484
  reason,
8484
8485
  ...details
8485
8486
  }) => {
8486
- const transformError = new Error(createDetailedMessage$1(`"transformUrlContent" error on "${urlInfo.type}"`, {
8487
+ const transformError = new Error(createDetailedMessage(`"transformUrlContent" error on "${urlInfo.type}"`, {
8487
8488
  reason,
8488
8489
  ...details,
8489
8490
  "url": urlInfo.url,
@@ -8536,7 +8537,7 @@ const createFinalizeUrlContentError = ({
8536
8537
  urlInfo,
8537
8538
  error
8538
8539
  }) => {
8539
- const finalizeError = new Error(createDetailedMessage$1(`"finalizeUrlContent" error on "${urlInfo.type}"`, {
8540
+ const finalizeError = new Error(createDetailedMessage(`"finalizeUrlContent" error on "${urlInfo.type}"`, {
8540
8541
  ...detailsFromValueThrown(error),
8541
8542
  "url": urlInfo.url,
8542
8543
  "url reference trace": reference.trace.message,
@@ -9048,7 +9049,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
9048
9049
  try {
9049
9050
  const fetchUrlContentReturnValue = await pluginController.callAsyncHooksUntil("fetchUrlContent", urlInfo, contextDuringFetch);
9050
9051
  if (!fetchUrlContentReturnValue) {
9051
- logger.warn(createDetailedMessage$1(`no plugin has handled url during "fetchUrlContent" hook -> url will be ignored`, {
9052
+ logger.warn(createDetailedMessage(`no plugin has handled url during "fetchUrlContent" hook -> url will be ignored`, {
9052
9053
  "url": urlInfo.url,
9053
9054
  "url reference trace": reference.trace.message
9054
9055
  }));
@@ -9372,6 +9373,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
9372
9373
  kitchenContext.injectReference = injectReference;
9373
9374
  const getWithoutSearchParam = ({
9374
9375
  urlInfo,
9376
+ reference,
9375
9377
  context,
9376
9378
  searchParam,
9377
9379
  expectedType
@@ -9384,7 +9386,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
9384
9386
  return [null, null];
9385
9387
  }
9386
9388
  searchParams.delete(searchParam);
9387
- const originalRef = context.reference.original || context.reference;
9389
+ const originalRef = reference || context.reference.original || context.reference;
9388
9390
  const referenceWithoutSearchParam = {
9389
9391
  ...originalRef,
9390
9392
  original: originalRef,
@@ -9393,8 +9395,8 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
9393
9395
  ...originalRef.data
9394
9396
  },
9395
9397
  expectedType,
9396
- specifier: context.reference.specifier.replace(`?${searchParam}`, "").replace(`&${searchParam}`, ""),
9397
- url: urlObject.href,
9398
+ specifier: originalRef.specifier.replace(`?${searchParam}`, "").replace(`&${searchParam}`, ""),
9399
+ url: normalizeUrl(urlObject.href),
9398
9400
  generatedSpecifier: null,
9399
9401
  generatedUrl: null,
9400
9402
  filename: null
@@ -10109,7 +10111,7 @@ const visitHtmlUrls = ({
10109
10111
  if (type === "text") {
10110
10112
  // ignore <script type="whatever" src="./file.js">
10111
10113
  // per HTML spec https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type
10112
- // this will be handled by jsenv_plugin_html_inline_content
10114
+ // this will be handled by jsenv_plugin_html_inline_content_analysis
10113
10115
  return;
10114
10116
  }
10115
10117
  visitAttributeAsUrlSpecifier({
@@ -10426,12 +10428,211 @@ const findOriginalDirectoryReference = (urlInfo, context) => {
10426
10428
  return ref;
10427
10429
  };
10428
10430
 
10431
+ const jsenvPluginInliningAsDataUrl = () => {
10432
+ return {
10433
+ name: "jsenv:inlining_as_data_url",
10434
+ appliesDuring: "*",
10435
+ formatUrl: {
10436
+ // if the referenced url is a worker we could use
10437
+ // https://www.oreilly.com/library/view/web-workers/9781449322120/ch04.html
10438
+ // but maybe we should rather use ?object_url
10439
+ // or people could do this:
10440
+ // import workerText from './worker.js?text'
10441
+ // const blob = new Blob(workerText, { type: 'text/javascript' })
10442
+ // window.URL.createObjectURL(blob)
10443
+ // in any case the recommended way is to use an url
10444
+ // to benefit from shared worker and reuse worker between tabs
10445
+ "*": (reference, context) => {
10446
+ if (!reference.original || !reference.original.searchParams.has("inline")) {
10447
+ return null;
10448
+ }
10449
+ // <link rel="stylesheet"> and <script> can be inlined in the html
10450
+ if (reference.type === "link_href" && reference.subtype === "stylesheet") {
10451
+ return null;
10452
+ }
10453
+ if (reference.type === "script") {
10454
+ return null;
10455
+ }
10456
+ return (async () => {
10457
+ const urlInfo = context.urlGraph.getUrlInfo(reference.url);
10458
+ await context.cook(urlInfo, {
10459
+ reference
10460
+ });
10461
+ const specifier = DATA_URL.stringify({
10462
+ mediaType: urlInfo.contentType,
10463
+ base64Flag: true,
10464
+ data: Buffer.from(urlInfo.content).toString("base64")
10465
+ });
10466
+ return specifier;
10467
+ })();
10468
+ }
10469
+ }
10470
+ };
10471
+ };
10472
+
10473
+ const jsenvPluginInliningIntoHtml = () => {
10474
+ return {
10475
+ name: "jsenv:inlining_into_html",
10476
+ appliesDuring: "*",
10477
+ transformUrlContent: {
10478
+ html: async (urlInfo, context) => {
10479
+ const htmlAst = parseHtmlString(urlInfo.content);
10480
+ const mutations = [];
10481
+ const actions = [];
10482
+ const onStyleSheet = (linkNode, {
10483
+ href
10484
+ }) => {
10485
+ const linkReference = context.referenceUtils.find(ref => ref.generatedSpecifier === href && ref.type === "link_href" && ref.subtype === "stylesheet");
10486
+ if (!linkReference.original || !linkReference.original.searchParams.has("inline")) {
10487
+ return;
10488
+ }
10489
+ const linkUrlInfo = context.urlGraph.getUrlInfo(linkReference.url);
10490
+ actions.push(async () => {
10491
+ await context.cook(linkUrlInfo, {
10492
+ reference: linkReference
10493
+ });
10494
+ const {
10495
+ line,
10496
+ column,
10497
+ isOriginal
10498
+ } = getHtmlNodePosition(linkNode, {
10499
+ preferOriginal: true
10500
+ });
10501
+ context.referenceUtils.becomesInline(linkReference, {
10502
+ line: line - 1,
10503
+ column,
10504
+ isOriginal,
10505
+ specifier: linkReference.generatedSpecifier,
10506
+ content: linkUrlInfo.content,
10507
+ contentType: linkUrlInfo.contentType
10508
+ });
10509
+ mutations.push(() => {
10510
+ setHtmlNodeAttributes(linkNode, {
10511
+ "inlined-from-href": href,
10512
+ "href": undefined,
10513
+ "rel": undefined,
10514
+ "type": undefined,
10515
+ "as": undefined,
10516
+ "crossorigin": undefined,
10517
+ "integrity": undefined,
10518
+ "jsenv-inlined-by": "jsenv:inlining_into_html"
10519
+ });
10520
+ linkNode.nodeName = "style";
10521
+ linkNode.tagName = "style";
10522
+ setHtmlNodeText(linkNode, linkUrlInfo.content, {
10523
+ indentation: "auto"
10524
+ });
10525
+ });
10526
+ });
10527
+ };
10528
+ const onScriptWithSrc = (scriptNode, {
10529
+ src
10530
+ }) => {
10531
+ const scriptReference = context.referenceUtils.find(ref => ref.generatedSpecifier === src && ref.type === "script");
10532
+ if (!scriptReference.original || !scriptReference.original.searchParams.has("inline")) {
10533
+ return;
10534
+ }
10535
+ const scriptUrlInfo = context.urlGraph.getUrlInfo(scriptReference.url);
10536
+ actions.push(async () => {
10537
+ await context.cook(scriptUrlInfo, {
10538
+ reference: scriptReference
10539
+ });
10540
+ const {
10541
+ line,
10542
+ column,
10543
+ isOriginal
10544
+ } = getHtmlNodePosition(scriptNode, {
10545
+ preferOriginal: true
10546
+ });
10547
+ context.referenceUtils.becomesInline(scriptReference, {
10548
+ line: line - 1,
10549
+ column,
10550
+ isOriginal,
10551
+ specifier: scriptReference.generatedSpecifier,
10552
+ content: scriptUrlInfo.content,
10553
+ contentType: scriptUrlInfo.contentType
10554
+ });
10555
+ mutations.push(() => {
10556
+ setHtmlNodeAttributes(scriptNode, {
10557
+ "inlined-from-src": src,
10558
+ "src": undefined,
10559
+ "crossorigin": undefined,
10560
+ "integrity": undefined,
10561
+ "jsenv-inlined-by": "jsenv:inlining_into_html"
10562
+ });
10563
+ setHtmlNodeText(scriptNode, scriptUrlInfo.content, {
10564
+ indentation: "auto"
10565
+ });
10566
+ });
10567
+ });
10568
+ };
10569
+ visitHtmlNodes(htmlAst, {
10570
+ link: linkNode => {
10571
+ const rel = getHtmlNodeAttribute(linkNode, "rel");
10572
+ if (rel !== "stylesheet") {
10573
+ return;
10574
+ }
10575
+ const href = getHtmlNodeAttribute(linkNode, "href");
10576
+ if (!href) {
10577
+ return;
10578
+ }
10579
+ onStyleSheet(linkNode, {
10580
+ href
10581
+ });
10582
+ },
10583
+ script: scriptNode => {
10584
+ const {
10585
+ type
10586
+ } = analyzeScriptNode(scriptNode);
10587
+ const scriptNodeText = getHtmlNodeText(scriptNode);
10588
+ if (scriptNodeText) {
10589
+ return;
10590
+ }
10591
+ const src = getHtmlNodeAttribute(scriptNode, "src");
10592
+ if (!src) {
10593
+ return;
10594
+ }
10595
+ onScriptWithSrc(scriptNode, {
10596
+ type,
10597
+ src
10598
+ });
10599
+ }
10600
+ });
10601
+ if (actions.length > 0) {
10602
+ await Promise.all(actions.map(action => action()));
10603
+ }
10604
+ mutations.forEach(mutation => mutation());
10605
+ const htmlModified = stringifyHtmlAst(htmlAst);
10606
+ return htmlModified;
10607
+ }
10608
+ }
10609
+ };
10610
+ };
10611
+
10612
+ const jsenvPluginInlining = () => {
10613
+ return [{
10614
+ name: "jsenv:inlining",
10615
+ appliesDuring: "*",
10616
+ redirectUrl: reference => {
10617
+ const {
10618
+ searchParams
10619
+ } = reference;
10620
+ if (searchParams.has("inline")) {
10621
+ const urlObject = new URL(reference.url);
10622
+ urlObject.searchParams.delete("inline");
10623
+ return urlObject.href;
10624
+ }
10625
+ return null;
10626
+ }
10627
+ }, jsenvPluginInliningAsDataUrl(), jsenvPluginInliningIntoHtml()];
10628
+ };
10629
+
10429
10630
  /*
10430
10631
  * This plugin ensure content inlined inside HTML is cooked (inline <script> for instance)
10431
10632
  * For <script hot-accept> the script content will be moved to a virtual file
10432
10633
  * to enable hot reloading
10433
10634
  */
10434
- const jsenvPluginHtmlInlineContent = ({
10635
+ const jsenvPluginHtmlInlineContentAnalysis = ({
10435
10636
  analyzeConvertedScripts
10436
10637
  }) => {
10437
10638
  const cookInlineContent = async ({
@@ -10457,7 +10658,7 @@ ${e.traceMessage}`);
10457
10658
  }
10458
10659
  };
10459
10660
  return {
10460
- name: "jsenv:html_inline_content",
10661
+ name: "jsenv:html_inline_content_analysis",
10461
10662
  appliesDuring: "*",
10462
10663
  transformUrlContent: {
10463
10664
  html: async (urlInfo, context) => {
@@ -10511,9 +10712,12 @@ ${e.traceMessage}`);
10511
10712
  });
10512
10713
  });
10513
10714
  mutations.push(() => {
10514
- setHtmlNodeText(styleNode, inlineStyleUrlInfo.content);
10715
+ setHtmlNodeText(styleNode, inlineStyleUrlInfo.content, {
10716
+ indentation: false // indentation would decrease strack trace precision
10717
+ });
10718
+
10515
10719
  setHtmlNodeAttributes(styleNode, {
10516
- "jsenv-cooked-by": "jsenv:html_inline_content"
10720
+ "jsenv-cooked-by": "jsenv:html_inline_content_analysis"
10517
10721
  });
10518
10722
  });
10519
10723
  },
@@ -10575,7 +10779,7 @@ ${e.traceMessage}`);
10575
10779
  });
10576
10780
  mutations.push(() => {
10577
10781
  const attributes = {
10578
- "jsenv-cooked-by": "jsenv:html_inline_content",
10782
+ "jsenv-cooked-by": "jsenv:html_inline_content_analysis",
10579
10783
  // 1. <script type="jsx"> becomes <script>
10580
10784
  // 2. <script type="module/jsx"> becomes <script type="module">
10581
10785
  ...(extension ? {
@@ -10588,7 +10792,10 @@ ${e.traceMessage}`);
10588
10792
  ...attributes
10589
10793
  });
10590
10794
  } else {
10591
- setHtmlNodeText(scriptNode, inlineScriptUrlInfo.content);
10795
+ setHtmlNodeText(scriptNode, inlineScriptUrlInfo.content, {
10796
+ indentation: false // indentation would decrease stack trace precision
10797
+ });
10798
+
10592
10799
  setHtmlNodeAttributes(scriptNode, {
10593
10800
  ...attributes
10594
10801
  });
@@ -10721,7 +10928,7 @@ const JS_QUOTE_REPLACEMENTS = {
10721
10928
  }
10722
10929
  };
10723
10930
 
10724
- const jsenvPluginJsInlineContent = ({
10931
+ const jsenvPluginJsInlineContentAnalysis = ({
10725
10932
  allowEscapeForVersioning
10726
10933
  }) => {
10727
10934
  const parseAndTransformInlineContentCalls = async (urlInfo, context) => {
@@ -10783,7 +10990,7 @@ const jsenvPluginJsInlineContent = ({
10783
10990
  return magicSource.toContentAndSourcemap();
10784
10991
  };
10785
10992
  return {
10786
- name: "jsenv:js_inline_content",
10993
+ name: "jsenv:js_inline_content_analysis",
10787
10994
  appliesDuring: "*",
10788
10995
  transformUrlContent: {
10789
10996
  js_classic: parseAndTransformInlineContentCalls,
@@ -11099,61 +11306,20 @@ const base64ToBuffer = base64String => Buffer.from(base64String, "base64");
11099
11306
  const base64ToString = base64String => Buffer.from(base64String, "base64").toString("utf8");
11100
11307
  const dataToBase64 = data => Buffer.from(data).toString("base64");
11101
11308
 
11102
- const jsenvPluginInlineQueryParam = () => {
11103
- return {
11104
- name: "jsenv:inline_query_param",
11105
- appliesDuring: "*",
11106
- formatUrl: {
11107
- // <link> and <script> can be inlined in the html
11108
- // this should be done during dev and postbuild but not build
11109
- // so that the bundled file gets inlined and not the entry point
11110
- "link_href": () => null,
11111
- "style": () => null,
11112
- "script": () => null,
11113
- // if the referenced url is a worker we could use
11114
- // https://www.oreilly.com/library/view/web-workers/9781449322120/ch04.html
11115
- // but maybe we should rather use ?object_url
11116
- // or people could do this:
11117
- // import workerText from './worker.js?text'
11118
- // const blob = new Blob(workerText, { type: 'text/javascript' })
11119
- // window.URL.createObjectURL(blob)
11120
- // in any case the recommended way is to use an url
11121
- // to benefit from shared worker and reuse worker between tabs
11122
- "*": (reference, context) => {
11123
- if (!reference.searchParams.has("inline")) {
11124
- return null;
11125
- }
11126
- return (async () => {
11127
- const urlInfo = context.urlGraph.getUrlInfo(reference.url);
11128
- await context.cook(urlInfo, {
11129
- reference
11130
- });
11131
- const specifier = DATA_URL.stringify({
11132
- mediaType: urlInfo.contentType,
11133
- base64Flag: true,
11134
- data: Buffer.from(urlInfo.content).toString("base64")
11135
- });
11136
- return specifier;
11137
- })();
11138
- }
11139
- }
11140
- };
11141
- };
11142
-
11143
- const jsenvPluginInline = ({
11309
+ const jsenvPluginInlineContentAnalysis = ({
11144
11310
  fetchInlineUrls = true,
11145
11311
  analyzeConvertedScripts = false,
11146
11312
  allowEscapeForVersioning = false
11147
11313
  } = {}) => {
11148
- return [...(fetchInlineUrls ? [jsenvPluginInlineUrls()] : []), jsenvPluginHtmlInlineContent({
11314
+ return [...(fetchInlineUrls ? [jsenvPluginInlineContentFetcher()] : []), jsenvPluginHtmlInlineContentAnalysis({
11149
11315
  analyzeConvertedScripts
11150
- }), jsenvPluginJsInlineContent({
11316
+ }), jsenvPluginJsInlineContentAnalysis({
11151
11317
  allowEscapeForVersioning
11152
- }), jsenvPluginDataUrls(), jsenvPluginInlineQueryParam()];
11318
+ }), jsenvPluginDataUrls()];
11153
11319
  };
11154
- const jsenvPluginInlineUrls = () => {
11320
+ const jsenvPluginInlineContentFetcher = () => {
11155
11321
  return {
11156
- name: "jsenv:inline_urls",
11322
+ name: "jsenv:inline_content_fetcher",
11157
11323
  appliesDuring: "*",
11158
11324
  fetchUrlContent: urlInfo => {
11159
11325
  if (!urlInfo.isInline) {
@@ -15176,7 +15342,7 @@ const jsenvPluginJsModuleFallbackInsideHtml = ({
15176
15342
  await context.cook(systemJsUrlInfo, {
15177
15343
  reference: systemJsReference
15178
15344
  });
15179
- injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
15345
+ injectHtmlNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
15180
15346
  tagName: "script",
15181
15347
  textContent: systemJsUrlInfo.content
15182
15348
  }), "jsenv:js_module_fallback");
@@ -15209,13 +15375,13 @@ const isExpectingJsModule = reference => {
15209
15375
  * when {type: "module"} cannot be used on web workers:
15210
15376
  * - new Worker("worker.js", { type: "module" })
15211
15377
  * transformed into
15212
- * new Worker("worker.js?as_js_classic", { type: " lassic" })
15378
+ * new Worker("worker.js?js_module_fallback", { type: " lassic" })
15213
15379
  * - navigator.serviceWorker.register("service_worker.js", { type: "module" })
15214
15380
  * transformed into
15215
- * navigator.serviceWorker.register("service_worker.js?as_js_classic", { type: "classic" })
15381
+ * navigator.serviceWorker.register("service_worker.js?js_module_fallback", { type: "classic" })
15216
15382
  * - new SharedWorker("shared_worker.js", { type: "module" })
15217
15383
  * transformed into
15218
- * new SharedWorker("shared_worker.js?as_js_classic", { type: "classic" })
15384
+ * new SharedWorker("shared_worker.js?js_module_fallback", { type: "classic" })
15219
15385
  */
15220
15386
  const jsenvPluginJsModuleFallbackOnWorkers = () => {
15221
15387
  const turnIntoJsClassicProxy = reference => {
@@ -15294,306 +15460,6 @@ const splitFileExtension$2 = filename => {
15294
15460
  return [filename.slice(0, dotLastIndex), filename.slice(dotLastIndex)];
15295
15461
  };
15296
15462
 
15297
- // duplicated from @jsenv/log to avoid the dependency
15298
- const createDetailedMessage = (message, details = {}) => {
15299
- let string = `${message}`;
15300
- Object.keys(details).forEach(key => {
15301
- const value = details[key];
15302
- string += `
15303
- --- ${key} ---
15304
- ${Array.isArray(value) ? value.join(`
15305
- `) : value}`;
15306
- });
15307
- return string;
15308
- };
15309
-
15310
- const assertImportMap = value => {
15311
- if (value === null) {
15312
- throw new TypeError(`an importMap must be an object, got null`);
15313
- }
15314
- const type = typeof value;
15315
- if (type !== "object") {
15316
- throw new TypeError(`an importMap must be an object, received ${value}`);
15317
- }
15318
- if (Array.isArray(value)) {
15319
- throw new TypeError(`an importMap must be an object, received array ${value}`);
15320
- }
15321
- };
15322
-
15323
- const hasScheme = string => {
15324
- return /^[a-zA-Z]{2,}:/.test(string);
15325
- };
15326
-
15327
- const urlToScheme = urlString => {
15328
- const colonIndex = urlString.indexOf(":");
15329
- if (colonIndex === -1) return "";
15330
- return urlString.slice(0, colonIndex);
15331
- };
15332
-
15333
- const urlToPathname = urlString => {
15334
- return ressourceToPathname(urlToRessource(urlString));
15335
- };
15336
- const urlToRessource = urlString => {
15337
- const scheme = urlToScheme(urlString);
15338
- if (scheme === "file") {
15339
- return urlString.slice("file://".length);
15340
- }
15341
- if (scheme === "https" || scheme === "http") {
15342
- // remove origin
15343
- const afterProtocol = urlString.slice(scheme.length + "://".length);
15344
- const pathnameSlashIndex = afterProtocol.indexOf("/", "://".length);
15345
- return afterProtocol.slice(pathnameSlashIndex);
15346
- }
15347
- return urlString.slice(scheme.length + 1);
15348
- };
15349
- const ressourceToPathname = ressource => {
15350
- const searchSeparatorIndex = ressource.indexOf("?");
15351
- return searchSeparatorIndex === -1 ? ressource : ressource.slice(0, searchSeparatorIndex);
15352
- };
15353
-
15354
- const urlToOrigin = urlString => {
15355
- const scheme = urlToScheme(urlString);
15356
- if (scheme === "file") {
15357
- return "file://";
15358
- }
15359
- if (scheme === "http" || scheme === "https") {
15360
- const secondProtocolSlashIndex = scheme.length + "://".length;
15361
- const pathnameSlashIndex = urlString.indexOf("/", secondProtocolSlashIndex);
15362
- if (pathnameSlashIndex === -1) return urlString;
15363
- return urlString.slice(0, pathnameSlashIndex);
15364
- }
15365
- return urlString.slice(0, scheme.length + 1);
15366
- };
15367
-
15368
- const pathnameToParentPathname = pathname => {
15369
- const slashLastIndex = pathname.lastIndexOf("/");
15370
- if (slashLastIndex === -1) {
15371
- return "/";
15372
- }
15373
- return pathname.slice(0, slashLastIndex + 1);
15374
- };
15375
-
15376
- // could be useful: https://url.spec.whatwg.org/#url-miscellaneous
15377
- const resolveUrl = (specifier, baseUrl) => {
15378
- if (baseUrl) {
15379
- if (typeof baseUrl !== "string") {
15380
- throw new TypeError(writeBaseUrlMustBeAString({
15381
- baseUrl,
15382
- specifier
15383
- }));
15384
- }
15385
- if (!hasScheme(baseUrl)) {
15386
- throw new Error(writeBaseUrlMustBeAbsolute({
15387
- baseUrl,
15388
- specifier
15389
- }));
15390
- }
15391
- }
15392
- if (hasScheme(specifier)) {
15393
- return specifier;
15394
- }
15395
- if (!baseUrl) {
15396
- throw new Error(writeBaseUrlRequired({
15397
- baseUrl,
15398
- specifier
15399
- }));
15400
- }
15401
-
15402
- // scheme relative
15403
- if (specifier.slice(0, 2) === "//") {
15404
- return `${urlToScheme(baseUrl)}:${specifier}`;
15405
- }
15406
-
15407
- // origin relative
15408
- if (specifier[0] === "/") {
15409
- return `${urlToOrigin(baseUrl)}${specifier}`;
15410
- }
15411
- const baseOrigin = urlToOrigin(baseUrl);
15412
- const basePathname = urlToPathname(baseUrl);
15413
- if (specifier === ".") {
15414
- const baseDirectoryPathname = pathnameToParentPathname(basePathname);
15415
- return `${baseOrigin}${baseDirectoryPathname}`;
15416
- }
15417
-
15418
- // pathname relative inside
15419
- if (specifier.slice(0, 2) === "./") {
15420
- const baseDirectoryPathname = pathnameToParentPathname(basePathname);
15421
- return `${baseOrigin}${baseDirectoryPathname}${specifier.slice(2)}`;
15422
- }
15423
-
15424
- // pathname relative outside
15425
- if (specifier.slice(0, 3) === "../") {
15426
- let unresolvedPathname = specifier;
15427
- const importerFolders = basePathname.split("/");
15428
- importerFolders.pop();
15429
- while (unresolvedPathname.slice(0, 3) === "../") {
15430
- unresolvedPathname = unresolvedPathname.slice(3);
15431
- // when there is no folder left to resolved
15432
- // we just ignore '../'
15433
- if (importerFolders.length) {
15434
- importerFolders.pop();
15435
- }
15436
- }
15437
- const resolvedPathname = `${importerFolders.join("/")}/${unresolvedPathname}`;
15438
- return `${baseOrigin}${resolvedPathname}`;
15439
- }
15440
-
15441
- // bare
15442
- if (basePathname === "") {
15443
- return `${baseOrigin}/${specifier}`;
15444
- }
15445
- if (basePathname[basePathname.length] === "/") {
15446
- return `${baseOrigin}${basePathname}${specifier}`;
15447
- }
15448
- return `${baseOrigin}${pathnameToParentPathname(basePathname)}${specifier}`;
15449
- };
15450
- const writeBaseUrlMustBeAString = ({
15451
- baseUrl,
15452
- specifier
15453
- }) => `baseUrl must be a string.
15454
- --- base url ---
15455
- ${baseUrl}
15456
- --- specifier ---
15457
- ${specifier}`;
15458
- const writeBaseUrlMustBeAbsolute = ({
15459
- baseUrl,
15460
- specifier
15461
- }) => `baseUrl must be absolute.
15462
- --- base url ---
15463
- ${baseUrl}
15464
- --- specifier ---
15465
- ${specifier}`;
15466
- const writeBaseUrlRequired = ({
15467
- baseUrl,
15468
- specifier
15469
- }) => `baseUrl required to resolve relative specifier.
15470
- --- base url ---
15471
- ${baseUrl}
15472
- --- specifier ---
15473
- ${specifier}`;
15474
-
15475
- const tryUrlResolution = (string, url) => {
15476
- const result = resolveUrl(string, url);
15477
- return hasScheme(result) ? result : null;
15478
- };
15479
-
15480
- const resolveSpecifier = (specifier, importer) => {
15481
- if (specifier === "." || specifier[0] === "/" || specifier.startsWith("./") || specifier.startsWith("../")) {
15482
- return resolveUrl(specifier, importer);
15483
- }
15484
- if (hasScheme(specifier)) {
15485
- return specifier;
15486
- }
15487
- return null;
15488
- };
15489
-
15490
- const applyImportMap = ({
15491
- importMap,
15492
- specifier,
15493
- importer,
15494
- createBareSpecifierError = ({
15495
- specifier,
15496
- importer
15497
- }) => {
15498
- return new Error(createDetailedMessage(`Unmapped bare specifier.`, {
15499
- specifier,
15500
- importer
15501
- }));
15502
- },
15503
- onImportMapping = () => {}
15504
- }) => {
15505
- assertImportMap(importMap);
15506
- if (typeof specifier !== "string") {
15507
- throw new TypeError(createDetailedMessage("specifier must be a string.", {
15508
- specifier,
15509
- importer
15510
- }));
15511
- }
15512
- if (importer) {
15513
- if (typeof importer !== "string") {
15514
- throw new TypeError(createDetailedMessage("importer must be a string.", {
15515
- importer,
15516
- specifier
15517
- }));
15518
- }
15519
- if (!hasScheme(importer)) {
15520
- throw new Error(createDetailedMessage(`importer must be an absolute url.`, {
15521
- importer,
15522
- specifier
15523
- }));
15524
- }
15525
- }
15526
- const specifierUrl = resolveSpecifier(specifier, importer);
15527
- const specifierNormalized = specifierUrl || specifier;
15528
- const {
15529
- scopes
15530
- } = importMap;
15531
- if (scopes && importer) {
15532
- const scopeSpecifierMatching = Object.keys(scopes).find(scopeSpecifier => {
15533
- return scopeSpecifier === importer || specifierIsPrefixOf(scopeSpecifier, importer);
15534
- });
15535
- if (scopeSpecifierMatching) {
15536
- const scopeMappings = scopes[scopeSpecifierMatching];
15537
- const mappingFromScopes = applyMappings(scopeMappings, specifierNormalized, scopeSpecifierMatching, onImportMapping);
15538
- if (mappingFromScopes !== null) {
15539
- return mappingFromScopes;
15540
- }
15541
- }
15542
- }
15543
- const {
15544
- imports
15545
- } = importMap;
15546
- if (imports) {
15547
- const mappingFromImports = applyMappings(imports, specifierNormalized, undefined, onImportMapping);
15548
- if (mappingFromImports !== null) {
15549
- return mappingFromImports;
15550
- }
15551
- }
15552
- if (specifierUrl) {
15553
- return specifierUrl;
15554
- }
15555
- throw createBareSpecifierError({
15556
- specifier,
15557
- importer
15558
- });
15559
- };
15560
- const applyMappings = (mappings, specifierNormalized, scope, onImportMapping) => {
15561
- const specifierCandidates = Object.keys(mappings);
15562
- let i = 0;
15563
- while (i < specifierCandidates.length) {
15564
- const specifierCandidate = specifierCandidates[i];
15565
- i++;
15566
- if (specifierCandidate === specifierNormalized) {
15567
- const address = mappings[specifierCandidate];
15568
- onImportMapping({
15569
- scope,
15570
- from: specifierCandidate,
15571
- to: address,
15572
- before: specifierNormalized,
15573
- after: address
15574
- });
15575
- return address;
15576
- }
15577
- if (specifierIsPrefixOf(specifierCandidate, specifierNormalized)) {
15578
- const address = mappings[specifierCandidate];
15579
- const afterSpecifier = specifierNormalized.slice(specifierCandidate.length);
15580
- const addressFinal = tryUrlResolution(afterSpecifier, address);
15581
- onImportMapping({
15582
- scope,
15583
- from: specifierCandidate,
15584
- to: address,
15585
- before: specifierNormalized,
15586
- after: addressFinal
15587
- });
15588
- return addressFinal;
15589
- }
15590
- }
15591
- return null;
15592
- };
15593
- const specifierIsPrefixOf = (specifierHref, href) => {
15594
- return specifierHref[specifierHref.length - 1] === "/" && href.startsWith(specifierHref);
15595
- };
15596
-
15597
15463
  // https://github.com/systemjs/systemjs/blob/89391f92dfeac33919b0223bbf834a1f4eea5750/src/common.js#L136
15598
15464
  const composeTwoImportMaps = (leftImportMap, rightImportMap) => {
15599
15465
  assertImportMap(leftImportMap);
@@ -15651,8 +15517,8 @@ const composeTwoMappings = (leftMappings, rightMappings) => {
15651
15517
  };
15652
15518
  const objectHasKey = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
15653
15519
  const compareAddressAndSpecifier = (address, specifier) => {
15654
- const addressUrl = resolveUrl(address, "file:///");
15655
- const specifierUrl = resolveUrl(specifier, "file:///");
15520
+ const addressUrl = resolveUrl$1(address, "file:///");
15521
+ const specifierUrl = resolveUrl$1(specifier, "file:///");
15656
15522
  return addressUrl === specifierUrl;
15657
15523
  };
15658
15524
  const composeTwoScopes = (leftScopes, rightScopes, imports) => {
@@ -15684,209 +15550,6 @@ const composeTwoScopes = (leftScopes, rightScopes, imports) => {
15684
15550
  return scopes;
15685
15551
  };
15686
15552
 
15687
- const sortImports = imports => {
15688
- const mappingsSorted = {};
15689
- Object.keys(imports).sort(compareLengthOrLocaleCompare).forEach(name => {
15690
- mappingsSorted[name] = imports[name];
15691
- });
15692
- return mappingsSorted;
15693
- };
15694
- const sortScopes = scopes => {
15695
- const scopesSorted = {};
15696
- Object.keys(scopes).sort(compareLengthOrLocaleCompare).forEach(scopeSpecifier => {
15697
- scopesSorted[scopeSpecifier] = sortImports(scopes[scopeSpecifier]);
15698
- });
15699
- return scopesSorted;
15700
- };
15701
- const compareLengthOrLocaleCompare = (a, b) => {
15702
- return b.length - a.length || a.localeCompare(b);
15703
- };
15704
-
15705
- const normalizeImportMap = (importMap, baseUrl) => {
15706
- assertImportMap(importMap);
15707
- if (!isStringOrUrl(baseUrl)) {
15708
- throw new TypeError(formulateBaseUrlMustBeStringOrUrl({
15709
- baseUrl
15710
- }));
15711
- }
15712
- const {
15713
- imports,
15714
- scopes
15715
- } = importMap;
15716
- return {
15717
- imports: imports ? normalizeMappings(imports, baseUrl) : undefined,
15718
- scopes: scopes ? normalizeScopes(scopes, baseUrl) : undefined
15719
- };
15720
- };
15721
- const isStringOrUrl = value => {
15722
- if (typeof value === "string") {
15723
- return true;
15724
- }
15725
- if (typeof URL === "function" && value instanceof URL) {
15726
- return true;
15727
- }
15728
- return false;
15729
- };
15730
- const normalizeMappings = (mappings, baseUrl) => {
15731
- const mappingsNormalized = {};
15732
- Object.keys(mappings).forEach(specifier => {
15733
- const address = mappings[specifier];
15734
- if (typeof address !== "string") {
15735
- console.warn(formulateAddressMustBeAString({
15736
- address,
15737
- specifier
15738
- }));
15739
- return;
15740
- }
15741
- const specifierResolved = resolveSpecifier(specifier, baseUrl) || specifier;
15742
- const addressUrl = tryUrlResolution(address, baseUrl);
15743
- if (addressUrl === null) {
15744
- console.warn(formulateAdressResolutionFailed({
15745
- address,
15746
- baseUrl,
15747
- specifier
15748
- }));
15749
- return;
15750
- }
15751
- if (specifier.endsWith("/") && !addressUrl.endsWith("/")) {
15752
- console.warn(formulateAddressUrlRequiresTrailingSlash({
15753
- addressUrl,
15754
- address,
15755
- specifier
15756
- }));
15757
- return;
15758
- }
15759
- mappingsNormalized[specifierResolved] = addressUrl;
15760
- });
15761
- return sortImports(mappingsNormalized);
15762
- };
15763
- const normalizeScopes = (scopes, baseUrl) => {
15764
- const scopesNormalized = {};
15765
- Object.keys(scopes).forEach(scopeSpecifier => {
15766
- const scopeMappings = scopes[scopeSpecifier];
15767
- const scopeUrl = tryUrlResolution(scopeSpecifier, baseUrl);
15768
- if (scopeUrl === null) {
15769
- console.warn(formulateScopeResolutionFailed({
15770
- scope: scopeSpecifier,
15771
- baseUrl
15772
- }));
15773
- return;
15774
- }
15775
- const scopeValueNormalized = normalizeMappings(scopeMappings, baseUrl);
15776
- scopesNormalized[scopeUrl] = scopeValueNormalized;
15777
- });
15778
- return sortScopes(scopesNormalized);
15779
- };
15780
- const formulateBaseUrlMustBeStringOrUrl = ({
15781
- baseUrl
15782
- }) => `baseUrl must be a string or an url.
15783
- --- base url ---
15784
- ${baseUrl}`;
15785
- const formulateAddressMustBeAString = ({
15786
- specifier,
15787
- address
15788
- }) => `Address must be a string.
15789
- --- address ---
15790
- ${address}
15791
- --- specifier ---
15792
- ${specifier}`;
15793
- const formulateAdressResolutionFailed = ({
15794
- address,
15795
- baseUrl,
15796
- specifier
15797
- }) => `Address url resolution failed.
15798
- --- address ---
15799
- ${address}
15800
- --- base url ---
15801
- ${baseUrl}
15802
- --- specifier ---
15803
- ${specifier}`;
15804
- const formulateAddressUrlRequiresTrailingSlash = ({
15805
- addressURL,
15806
- address,
15807
- specifier
15808
- }) => `Address must end with /.
15809
- --- address url ---
15810
- ${addressURL}
15811
- --- address ---
15812
- ${address}
15813
- --- specifier ---
15814
- ${specifier}`;
15815
- const formulateScopeResolutionFailed = ({
15816
- scope,
15817
- baseUrl
15818
- }) => `Scope url resolution failed.
15819
- --- scope ---
15820
- ${scope}
15821
- --- base url ---
15822
- ${baseUrl}`;
15823
-
15824
- const pathnameToExtension = pathname => {
15825
- const slashLastIndex = pathname.lastIndexOf("/");
15826
- if (slashLastIndex !== -1) {
15827
- pathname = pathname.slice(slashLastIndex + 1);
15828
- }
15829
- const dotLastIndex = pathname.lastIndexOf(".");
15830
- if (dotLastIndex === -1) return "";
15831
- // if (dotLastIndex === pathname.length - 1) return ""
15832
- return pathname.slice(dotLastIndex);
15833
- };
15834
-
15835
- const resolveImport = ({
15836
- specifier,
15837
- importer,
15838
- importMap,
15839
- defaultExtension = false,
15840
- createBareSpecifierError,
15841
- onImportMapping = () => {}
15842
- }) => {
15843
- let url;
15844
- if (importMap) {
15845
- url = applyImportMap({
15846
- importMap,
15847
- specifier,
15848
- importer,
15849
- createBareSpecifierError,
15850
- onImportMapping
15851
- });
15852
- } else {
15853
- url = resolveUrl(specifier, importer);
15854
- }
15855
- if (defaultExtension) {
15856
- url = applyDefaultExtension({
15857
- url,
15858
- importer,
15859
- defaultExtension
15860
- });
15861
- }
15862
- return url;
15863
- };
15864
- const applyDefaultExtension = ({
15865
- url,
15866
- importer,
15867
- defaultExtension
15868
- }) => {
15869
- if (urlToPathname(url).endsWith("/")) {
15870
- return url;
15871
- }
15872
- if (typeof defaultExtension === "string") {
15873
- const extension = pathnameToExtension(url);
15874
- if (extension === "") {
15875
- return `${url}${defaultExtension}`;
15876
- }
15877
- return url;
15878
- }
15879
- if (defaultExtension === true) {
15880
- const extension = pathnameToExtension(url);
15881
- if (extension === "" && importer) {
15882
- const importerPathname = urlToPathname(importer);
15883
- const importerExtension = pathnameToExtension(importerPathname);
15884
- return `${url}${importerExtension}`;
15885
- }
15886
- }
15887
- return url;
15888
- };
15889
-
15890
15553
  /*
15891
15554
  * Plugin to read and apply importmap files found in html files.
15892
15555
  * - feeds importmap files to jsenv kitchen
@@ -16003,7 +15666,9 @@ const jsenvPluginImportmap = () => {
16003
15666
  await context.cook(inlineImportmapUrlInfo, {
16004
15667
  reference: inlineImportmapReference
16005
15668
  });
16006
- setHtmlNodeText(importmap, inlineImportmapUrlInfo.content);
15669
+ setHtmlNodeText(importmap, inlineImportmapUrlInfo.content, {
15670
+ indentation: "auto"
15671
+ });
16007
15672
  setHtmlNodeAttributes(importmap, {
16008
15673
  "jsenv-cooked-by": "jsenv:importmap"
16009
15674
  });
@@ -16021,7 +15686,9 @@ const jsenvPluginImportmap = () => {
16021
15686
  reference: importmapReference
16022
15687
  });
16023
15688
  onHtmlImportmapParsed(JSON.parse(importmapUrlInfo.content), htmlUrlInfo.url);
16024
- setHtmlNodeText(importmap, importmapUrlInfo.content);
15689
+ setHtmlNodeText(importmap, importmapUrlInfo.content, {
15690
+ indentation: "auto"
15691
+ });
16025
15692
  setHtmlNodeAttributes(importmap, {
16026
15693
  "src": undefined,
16027
15694
  "jsenv-inlined-by": "jsenv:importmap",
@@ -17796,7 +17463,9 @@ const injectSupervisorIntoHTML = async ({
17796
17463
  src: inlineScriptSrc
17797
17464
  });
17798
17465
  mutations.push(() => {
17799
- setHtmlNodeText(scriptNode, remoteJsSupervised);
17466
+ setHtmlNodeText(scriptNode, remoteJsSupervised, {
17467
+ indentation: "auto"
17468
+ });
17800
17469
  setHtmlNodeAttributes(scriptNode, {
17801
17470
  "jsenv-cooked-by": "jsenv:supervisor",
17802
17471
  "src": undefined,
@@ -17819,7 +17488,9 @@ const injectSupervisorIntoHTML = async ({
17819
17488
  inlineSrc: inlineScriptSrc
17820
17489
  });
17821
17490
  mutations.push(() => {
17822
- setHtmlNodeText(scriptNode, inlineJsSupervised);
17491
+ setHtmlNodeText(scriptNode, inlineJsSupervised, {
17492
+ indentation: "auto"
17493
+ });
17823
17494
  setHtmlNodeAttributes(scriptNode, {
17824
17495
  "jsenv-cooked-by": "jsenv:supervisor"
17825
17496
  });
@@ -17852,7 +17523,9 @@ const injectSupervisorIntoHTML = async ({
17852
17523
  src
17853
17524
  });
17854
17525
  mutations.push(() => {
17855
- setHtmlNodeText(scriptNode, remoteJsSupervised);
17526
+ setHtmlNodeText(scriptNode, remoteJsSupervised, {
17527
+ indentation: "auto"
17528
+ });
17856
17529
  setHtmlNodeAttributes(scriptNode, {
17857
17530
  "jsenv-cooked-by": "jsenv:supervisor",
17858
17531
  "src": undefined,
@@ -17887,6 +17560,10 @@ const injectSupervisorIntoHTML = async ({
17887
17560
  }
17888
17561
  const src = getHtmlNodeAttribute(scriptNode, "src");
17889
17562
  if (src) {
17563
+ const urlObject = new URL(src, "http://example.com");
17564
+ if (urlObject.searchParams.has("inline")) {
17565
+ return;
17566
+ }
17890
17567
  handleScriptWithSrc(scriptNode, {
17891
17568
  type,
17892
17569
  src
@@ -17903,20 +17580,15 @@ const injectSupervisorIntoHTML = async ({
17903
17580
  serverIsJsenvDevServer: webServer.isJsenvDevServer,
17904
17581
  rootDirectoryUrl: webServer.rootDirectoryUrl,
17905
17582
  scriptInfos
17906
- }, " ");
17907
- injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
17583
+ }, " ");
17584
+ injectHtmlNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
17908
17585
  tagName: "script",
17909
- textContent: `
17910
- window.__supervisor__.setup({
17911
- ${setupParamsSource}
17912
- })
17913
- `
17586
+ textContent: `window.__supervisor__.setup({${setupParamsSource}})`
17914
17587
  }), "jsenv:supervisor");
17915
- const supervisorScript = createHtmlNode({
17588
+ injectHtmlNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
17916
17589
  tagName: "script",
17917
17590
  src: supervisorScriptSrc
17918
- });
17919
- injectScriptNodeAsEarlyAsPossible(htmlAst, supervisorScript, "jsenv:supervisor");
17591
+ }), "jsenv:supervisor");
17920
17592
  }
17921
17593
  // 3. Perform actions (transforming inline script content) and html mutations
17922
17594
  if (actions.length > 0) {
@@ -17944,14 +17616,11 @@ const generateCodeToSuperviseScriptWithSrc = ({
17944
17616
  type,
17945
17617
  src
17946
17618
  }) => {
17619
+ const srcEncoded = JSON.stringify(src);
17947
17620
  if (type === "js_module") {
17948
- return `
17949
- window.__supervisor__.superviseScriptTypeModule(${JSON.stringify(src)}, (url) => import(url));
17950
- `;
17621
+ return `window.__supervisor__.superviseScriptTypeModule(${srcEncoded}, (url) => import(url));`;
17951
17622
  }
17952
- return `
17953
- window.__supervisor__.superviseScript(${JSON.stringify(src)});
17954
- `;
17623
+ return `window.__supervisor__.superviseScript(${srcEncoded});`;
17955
17624
  };
17956
17625
 
17957
17626
  /*
@@ -18556,10 +18225,23 @@ const jsenvPluginImportAssertions = ({
18556
18225
  };
18557
18226
  const turnIntoJsModuleProxy = (reference, type) => {
18558
18227
  reference.mutation = magicSource => {
18559
- magicSource.remove({
18560
- start: reference.assertNode.start,
18561
- end: reference.assertNode.end
18562
- });
18228
+ const {
18229
+ assertNode
18230
+ } = reference;
18231
+ if (reference.subtype === "import_dynamic") {
18232
+ const assertPropertyNode = assertNode.properties.find(prop => prop.key.name === "assert");
18233
+ const assertPropertyValue = assertPropertyNode.value;
18234
+ const typePropertyNode = assertPropertyValue.properties.find(prop => prop.key.name === "type");
18235
+ magicSource.remove({
18236
+ start: typePropertyNode.start,
18237
+ end: typePropertyNode.end
18238
+ });
18239
+ } else {
18240
+ magicSource.remove({
18241
+ start: assertNode.start,
18242
+ end: assertNode.end
18243
+ });
18244
+ }
18563
18245
  };
18564
18246
  const newUrl = injectQueryParams(reference.url, {
18565
18247
  [`as_${type}_module`]: ""
@@ -20300,7 +19982,7 @@ const jsenvPluginAutoreloadClient = () => {
20300
19982
  expectedType: "js_module",
20301
19983
  specifier: autoreloadClientFileUrl
20302
19984
  });
20303
- injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
19985
+ injectHtmlNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
20304
19986
  tagName: "script",
20305
19987
  type: "module",
20306
19988
  src: autoreloadClientReference.generatedSpecifier
@@ -20668,16 +20350,13 @@ const jsenvPluginRibbon = ({
20668
20350
  const paramsJson = JSON.stringify({
20669
20351
  text: context.dev ? "DEV" : "BUILD"
20670
20352
  }, null, " ");
20671
- const scriptNode = createHtmlNode({
20353
+ injectHtmlNode(htmlAst, createHtmlNode({
20672
20354
  tagName: "script",
20673
20355
  type: "module",
20674
- textContent: `
20675
- import { injectRibbon } from "${ribbonClientFileReference.generatedSpecifier}"
20676
-
20677
- injectRibbon(${paramsJson})
20678
- `
20679
- });
20680
- injectHtmlNode(htmlAst, scriptNode, "jsenv:ribbon");
20356
+ textContent: `import { injectRibbon } from "${ribbonClientFileReference.generatedSpecifier}"
20357
+
20358
+ injectRibbon(${paramsJson});`
20359
+ }), "jsenv:ribbon");
20681
20360
  return stringifyHtmlAst(htmlAst);
20682
20361
  }
20683
20362
  }
@@ -20694,6 +20373,7 @@ const getCorePlugins = ({
20694
20373
  directoryReferenceAllowed,
20695
20374
  supervisor,
20696
20375
  transpilation = true,
20376
+ inlining = true,
20697
20377
  clientAutoreload = false,
20698
20378
  clientFileChangeCallbackList,
20699
20379
  clientFilesPruneCallbackList,
@@ -20726,9 +20406,9 @@ const getCorePlugins = ({
20726
20406
  }), jsenvPluginTranspilation(transpilation), jsenvPluginImportmap(),
20727
20407
  // before node esm to handle bare specifiers
20728
20408
  // + before node esm to handle importmap before inline content
20729
- jsenvPluginInline(),
20409
+ jsenvPluginInlineContentAnalysis(),
20730
20410
  // before "file urls" to resolve and load inline urls
20731
- ...(supervisor ? [jsenvPluginSupervisor(supervisor)] : []),
20411
+ ...(inlining ? [jsenvPluginInlining()] : []), ...(supervisor ? [jsenvPluginSupervisor(supervisor)] : []),
20732
20412
  // after inline as it needs inline script to be cooked
20733
20413
  jsenvPluginFileUrls({
20734
20414
  directoryReferenceAllowed,
@@ -20983,7 +20663,7 @@ const injectors = {
20983
20663
  const htmlAst = parseHtmlString(urlInfo.content, {
20984
20664
  storeOriginalPositions: false
20985
20665
  });
20986
- injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
20666
+ injectHtmlNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
20987
20667
  tagName: "script",
20988
20668
  textContent: generateClientCodeForVersionMappings(versionMappings, {
20989
20669
  globalName: "window",
@@ -21002,10 +20682,11 @@ const jsInjector = (urlInfo, {
21002
20682
  minification
21003
20683
  }) => {
21004
20684
  const magicSource = createMagicSource(urlInfo.content);
21005
- magicSource.prepend(generateClientCodeForVersionMappings(versionMappings, {
20685
+ const code = generateClientCodeForVersionMappings(versionMappings, {
21006
20686
  globalName: isWebWorkerUrlInfo(urlInfo) ? "self" : "window",
21007
20687
  minification
21008
- }));
20688
+ });
20689
+ magicSource.prepend(`${code}\n\n`);
21009
20690
  return magicSource.toContentAndSourcemap();
21010
20691
  };
21011
20692
  const generateClientCodeForVersionMappings = (versionMappings, {
@@ -21015,14 +20696,12 @@ const generateClientCodeForVersionMappings = (versionMappings, {
21015
20696
  if (minification) {
21016
20697
  return `;(function(){var m = ${JSON.stringify(versionMappings)}; ${globalName}.__v__ = function (s) { return m[s] || s }; })();`;
21017
20698
  }
21018
- return `
21019
- ;(function() {
20699
+ return `;(function() {
21020
20700
  var __versionMappings__ = ${JSON.stringify(versionMappings, null, " ")};
21021
20701
  ${globalName}.__v__ = function (specifier) {
21022
20702
  return __versionMappings__[specifier] || specifier
21023
20703
  };
21024
- })();
21025
- `;
20704
+ })();`;
21026
20705
  };
21027
20706
  const injectVersionMappingsAsImportmap = async ({
21028
20707
  urlInfo,
@@ -21035,18 +20714,15 @@ const injectVersionMappingsAsImportmap = async ({
21035
20714
  // jsenv_plugin_importmap.js is removing importmap during build
21036
20715
  // it means at this point we know HTML has no importmap in it
21037
20716
  // we can safely inject one
21038
- const importmapNode = createHtmlNode({
20717
+ injectHtmlNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
21039
20718
  tagName: "script",
21040
20719
  type: "importmap",
21041
20720
  textContent: kitchen.kitchenContext.minification ? JSON.stringify({
21042
20721
  imports: versionMappings
21043
- }) : `
21044
- {
21045
- "imports": {${JSON.stringify(versionMappings, null, " ").slice(1, -1)} }
21046
- }
21047
- `
21048
- });
21049
- injectScriptNodeAsEarlyAsPossible(htmlAst, importmapNode, "jsenv:versioning");
20722
+ }) : JSON.stringify({
20723
+ imports: versionMappings
20724
+ }, null, " ")
20725
+ }), "jsenv:versioning");
21050
20726
  kitchen.urlInfoTransformer.applyFinalTransformations(urlInfo, {
21051
20727
  content: stringifyHtmlAst(htmlAst)
21052
20728
  });
@@ -21121,7 +20797,7 @@ const defaultRuntimeCompat = {
21121
20797
  * Controls if url in build file contents are versioned
21122
20798
  * @param {('search_param'|'filename')} [buildParameters.versioningMethod="search_param"]
21123
20799
  * Controls how url are versioned
21124
- * @param {boolean|string} [buildParameters.sourcemaps=false]
20800
+ * @param {('none'|'inline'|'file'|'programmatic'} [buildParameters.sourcemaps="none"]
21125
20801
  * Generate sourcemaps in the build directory
21126
20802
  * @return {Object} buildReturnValue
21127
20803
  * @return {Object} buildReturnValue.buildFileContents
@@ -21142,7 +20818,7 @@ const build = async ({
21142
20818
  runtimeCompat = defaultRuntimeCompat,
21143
20819
  base = runtimeCompat.node ? "./" : "/",
21144
20820
  plugins = [],
21145
- sourcemaps = false,
20821
+ sourcemaps = "none",
21146
20822
  sourcemapsSourcesContent,
21147
20823
  urlAnalysis = {},
21148
20824
  urlResolution,
@@ -21305,6 +20981,7 @@ build ${entryPointKeys.length} entry points`);
21305
20981
  babelHelpersAsImport: !explicitJsModuleFallback,
21306
20982
  jsModuleFallbackOnJsClassic: false
21307
20983
  },
20984
+ inlining: false,
21308
20985
  scenarioPlaceholders
21309
20986
  })],
21310
20987
  sourcemaps,
@@ -21343,9 +21020,9 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
21343
21020
  ...contextSharedDuringBuild,
21344
21021
  plugins: [urlAnalysisPlugin, ...(lineBreakNormalization ? [jsenvPluginLineBreakNormalization()] : []), jsenvPluginJsModuleFallback({
21345
21022
  systemJsInjection: true
21346
- }), jsenvPluginInline({
21023
+ }), jsenvPluginInlineContentAnalysis({
21347
21024
  fetchInlineUrls: false
21348
- }), {
21025
+ }), jsenvPluginInlining(), {
21349
21026
  name: "jsenv:build",
21350
21027
  appliesDuring: "build",
21351
21028
  resolveUrl: reference => {
@@ -21382,16 +21059,25 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
21382
21059
  return reference.url;
21383
21060
  }
21384
21061
  if (reference.isInline) {
21062
+ const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl);
21063
+ const parentRawUrl = parentUrlInfo.originalUrl;
21385
21064
  const rawUrlInfo = GRAPH.find(rawGraph, rawUrlInfo => {
21386
- if (!rawUrlInfo.isInline) {
21387
- return false;
21065
+ const {
21066
+ inlineUrlSite
21067
+ } = rawUrlInfo;
21068
+ // not inline
21069
+ if (!inlineUrlSite) return false;
21070
+ if (inlineUrlSite.url === parentRawUrl && inlineUrlSite.line === reference.specifierLine && inlineUrlSite.column === reference.specifierColumn) {
21071
+ return true;
21388
21072
  }
21389
21073
  if (rawUrlInfo.content === reference.content) {
21390
21074
  return true;
21391
21075
  }
21392
- return rawUrlInfo.originalContent === reference.content;
21076
+ if (rawUrlInfo.originalContent === reference.content) {
21077
+ return true;
21078
+ }
21079
+ return false;
21393
21080
  });
21394
- const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl);
21395
21081
  if (!rawUrlInfo) {
21396
21082
  // generated during final graph
21397
21083
  // (happens for JSON.parse injected for import assertions for instance)
@@ -21521,7 +21207,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
21521
21207
  const rawUrl = buildDirectoryRedirections.get(url) || url;
21522
21208
  const rawUrlInfo = rawGraph.getUrlInfo(rawUrl);
21523
21209
  if (!rawUrlInfo) {
21524
- throw new Error(createDetailedMessage$1(`Cannot find url`, {
21210
+ throw new Error(createDetailedMessage(`Cannot find url`, {
21525
21211
  url,
21526
21212
  "raw urls": Array.from(buildDirectoryRedirections.values()),
21527
21213
  "build urls": Array.from(buildDirectoryRedirections.keys())
@@ -21559,6 +21245,10 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
21559
21245
  return rawUrlInfo;
21560
21246
  }
21561
21247
  if (reference.isInline) {
21248
+ if (reference.prev && !reference.prev.isInline) {
21249
+ const urlBeforeRedirect = findKey(finalRedirections, reference.prev.url);
21250
+ return fromBundleOrRawGraph(urlBeforeRedirect);
21251
+ }
21562
21252
  return fromBundleOrRawGraph(reference.url);
21563
21253
  }
21564
21254
  // reference updated during "postbuild":
@@ -22007,7 +21697,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
22007
21697
  build: true,
22008
21698
  runtimeCompat,
22009
21699
  ...contextSharedDuringBuild,
22010
- plugins: [urlAnalysisPlugin, jsenvPluginInline({
21700
+ plugins: [urlAnalysisPlugin, jsenvPluginInlineContentAnalysis({
22011
21701
  fetchInlineUrls: false,
22012
21702
  analyzeConvertedScripts: true,
22013
21703
  // to be able to version their urls
@@ -22280,7 +21970,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
22280
21970
  type: getHtmlNodeAttribute(hintNode, "type"),
22281
21971
  crossorigin: getHtmlNodeAttribute(hintNode, "crossorigin")
22282
21972
  });
22283
- insertHtmlNodeAfter(nodeToInsert, hintNode.parentNode, hintNode);
21973
+ insertHtmlNodeAfter(nodeToInsert, hintNode);
22284
21974
  });
22285
21975
  }
22286
21976
  });
@@ -22591,7 +22281,7 @@ const jsenvPluginServerEventsClientInjection = () => {
22591
22281
  expectedType: "js_module",
22592
22282
  specifier: serverEventsClientFileUrl
22593
22283
  });
22594
- injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
22284
+ injectHtmlNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
22595
22285
  tagName: "script",
22596
22286
  type: "module",
22597
22287
  src: serverEventsClientFileReference.generatedSpecifier
@@ -22953,7 +22643,7 @@ const createFileService = ({
22953
22643
  if (code === "PARSE_ERROR") {
22954
22644
  // when possible let browser re-throw the syntax error
22955
22645
  // it's not possible to do that when url info content is not available
22956
- // (happens for as_js_classic for instance)
22646
+ // (happens for js_module_fallback for instance)
22957
22647
  if (urlInfo.content !== undefined) {
22958
22648
  return {
22959
22649
  url: reference.url,
@@ -23523,7 +23213,7 @@ const generateFileExecutionSteps = ({
23523
23213
  return;
23524
23214
  }
23525
23215
  if (typeof stepConfig !== "object") {
23526
- throw new TypeError(createDetailedMessage$1(`found unexpected value in plan, they must be object`, {
23216
+ throw new TypeError(createDetailedMessage(`found unexpected value in plan, they must be object`, {
23527
23217
  ["file relative path"]: fileRelativeUrl,
23528
23218
  ["execution name"]: executionName,
23529
23219
  ["value"]: stepConfig
@@ -23590,7 +23280,7 @@ const readNodeV8CoverageDirectory = async ({
23590
23280
  timeSpentTrying += 200;
23591
23281
  return tryReadJsonFile();
23592
23282
  }
23593
- console.warn(createDetailedMessage$1(`Error while reading coverage file`, {
23283
+ console.warn(createDetailedMessage(`Error while reading coverage file`, {
23594
23284
  "error stack": e.stack,
23595
23285
  "file": dirEntryUrl
23596
23286
  }));
@@ -23751,7 +23441,7 @@ const composeV8AndIstanbul = (v8FileByFileCoverage, istanbulFileByFileCoverage,
23751
23441
  const v8Coverage = v8FileByFileCoverage[key];
23752
23442
  if (v8Coverage) {
23753
23443
  if (coverageV8ConflictWarning) {
23754
- console.warn(createDetailedMessage$1(`Coverage conflict on "${key}", found two coverage that cannot be merged together: v8 and istanbul. The istanbul coverage will be ignored.`, {
23444
+ console.warn(createDetailedMessage(`Coverage conflict on "${key}", found two coverage that cannot be merged together: v8 and istanbul. The istanbul coverage will be ignored.`, {
23755
23445
  details: `This happens when a file is executed on a runtime using v8 coverage (node or chromium) and on runtime using istanbul coverage (firefox or webkit)`,
23756
23446
  suggestion: "You can disable this warning with coverageV8ConflictWarning: false"
23757
23447
  }));
@@ -23856,7 +23546,7 @@ const relativeUrlToEmptyCoverage = async (relativeUrl, {
23856
23546
  const operation = Abort.startOperation();
23857
23547
  operation.addAbortSignal(signal);
23858
23548
  try {
23859
- const fileUrl = resolveUrl$1(relativeUrl, rootDirectoryUrl);
23549
+ const fileUrl = resolveUrl(relativeUrl, rootDirectoryUrl);
23860
23550
  const content = await readFile(fileUrl, {
23861
23551
  as: "string"
23862
23552
  });
@@ -25137,7 +24827,7 @@ const executeTestPlan = async ({
25137
24827
  });
25138
24828
  if (patternsMatchingCoverAndExecute.length) {
25139
24829
  // It would be strange, for a given file to be both covered and executed
25140
- throw new Error(createDetailedMessage$1(`some file will be both covered and executed`, {
24830
+ throw new Error(createDetailedMessage(`some file will be both covered and executed`, {
25141
24831
  patterns: patternsMatchingCoverAndExecute
25142
24832
  }));
25143
24833
  }
@@ -25166,7 +24856,7 @@ const executeTestPlan = async ({
25166
24856
  const logger = createLogger({
25167
24857
  logLevel
25168
24858
  });
25169
- logger.debug(createDetailedMessage$1(`Prepare executing plan`, {
24859
+ logger.debug(createDetailedMessage(`Prepare executing plan`, {
25170
24860
  runtimes: JSON.stringify(runtimes, null, " ")
25171
24861
  }));
25172
24862
 
@@ -25182,7 +24872,7 @@ const executeTestPlan = async ({
25182
24872
  await ensureEmptyDirectory(process.env.NODE_V8_COVERAGE);
25183
24873
  } else {
25184
24874
  coverageMethodForNodeJs = "Profiler";
25185
- logger.warn(createDetailedMessage$1(`process.env.NODE_V8_COVERAGE is required to generate coverage for Node.js subprocesses`, {
24875
+ logger.warn(createDetailedMessage(`process.env.NODE_V8_COVERAGE is required to generate coverage for Node.js subprocesses`, {
25186
24876
  "suggestion": `set process.env.NODE_V8_COVERAGE`,
25187
24877
  "suggestion 2": `use coverageMethodForNodeJs: "Profiler". But it means coverage for child_process and worker_thread cannot be collected`
25188
24878
  }));
@@ -25899,7 +25589,7 @@ const importPlaywright = async ({
25899
25589
  return namespace;
25900
25590
  } catch (e) {
25901
25591
  if (e.code === "ERR_MODULE_NOT_FOUND") {
25902
- throw new Error(createDetailedMessage$1(`"playwright" not found. You need playwright in your dependencies to use "${browserName}"`, {
25592
+ throw new Error(createDetailedMessage(`"playwright" not found. You need playwright in your dependencies to use "${browserName}"`, {
25903
25593
  suggestion: `npm install --save-dev playwright`
25904
25594
  }), {
25905
25595
  cause: e
@@ -26010,7 +25700,12 @@ const ExecOptions = {
26010
25700
  while (i < execArgv.length) {
26011
25701
  const execArg = execArgv[i];
26012
25702
  const option = execOptionFromExecArg(execArg);
26013
- execOptions[option.name] = option.value;
25703
+ const existing = execOptions[option.name];
25704
+ if (existing) {
25705
+ execOptions[option.name] = Array.isArray(existing) ? [...existing, option.value] : [existing, option.value];
25706
+ } else {
25707
+ execOptions[option.name] = option.value;
25708
+ }
26014
25709
  i++;
26015
25710
  }
26016
25711
  return execOptions;
@@ -26026,7 +25721,13 @@ const ExecOptions = {
26026
25721
  execArgv.push(optionName);
26027
25722
  return;
26028
25723
  }
26029
- execArgv.push(`${optionName}=${optionValue}`);
25724
+ if (Array.isArray(optionValue)) {
25725
+ optionValue.forEach(subValue => {
25726
+ execArgv.push(`${optionName}=${subValue}`);
25727
+ });
25728
+ } else {
25729
+ execArgv.push(`${optionName}=${optionValue}`);
25730
+ }
26030
25731
  });
26031
25732
  return execArgv;
26032
25733
  }
@@ -26057,7 +25758,7 @@ const createChildExecOptions = async ({
26057
25758
  debugModeInheritBreak = true
26058
25759
  } = {}) => {
26059
25760
  if (typeof debugMode === "string" && AVAILABLE_DEBUG_MODE.indexOf(debugMode) === -1) {
26060
- throw new TypeError(createDetailedMessage$1(`unexpected debug mode.`, {
25761
+ throw new TypeError(createDetailedMessage(`unexpected debug mode.`, {
26061
25762
  ["debug mode"]: debugMode,
26062
25763
  ["allowed debug mode"]: AVAILABLE_DEBUG_MODE
26063
25764
  }));
@@ -26254,6 +25955,10 @@ const EXIT_CODES = {
26254
25955
  SIGTERM: 128 + SIGTERM_SIGNAL_NUMBER
26255
25956
  };
26256
25957
 
25958
+ const IMPORTMAP_NODE_LOADER_FILE_URL = new URL("./importmap_node_loader.mjs?entry_point=", import.meta.url).href;
25959
+
25960
+ const NO_EXPERIMENTAL_WARNING_FILE_URL = new URL("./no_experimental_warnings.cjs?entry_point=", import.meta.url).href;
25961
+
26257
25962
  const CONTROLLABLE_CHILD_PROCESS_URL = new URL("./controllable_child_process.mjs?entry_point=", import.meta.url).href;
26258
25963
  const nodeChildProcess = {
26259
25964
  type: "node",
@@ -26266,6 +25971,7 @@ nodeChildProcess.run = async ({
26266
25971
  logProcessCommand = false,
26267
25972
  rootDirectoryUrl,
26268
25973
  fileRelativeUrl,
25974
+ importMap,
26269
25975
  keepRunning,
26270
25976
  gracefulStopAllocatedMs = 4000,
26271
25977
  stopSignal,
@@ -26296,6 +26002,12 @@ nodeChildProcess.run = async ({
26296
26002
  env.NODE_V8_COVERAGE = "";
26297
26003
  }
26298
26004
  commandLineOptions = ["--experimental-import-meta-resolve", ...commandLineOptions];
26005
+ if (importMap) {
26006
+ env.IMPORT_MAP = JSON.stringify(importMap);
26007
+ env.IMPORT_MAP_BASE_URL = rootDirectoryUrl;
26008
+ commandLineOptions.push(`--experimental-loader=${fileURLToPath(IMPORTMAP_NODE_LOADER_FILE_URL)}`);
26009
+ commandLineOptions.push(`--require=${fileURLToPath(NO_EXPERIMENTAL_WARNING_FILE_URL)}`);
26010
+ }
26299
26011
  const cleanupCallbackList = createCallbackListNotifiedOnce();
26300
26012
  const cleanup = async reason => {
26301
26013
  await cleanupCallbackList.notify({
@@ -26321,9 +26033,10 @@ nodeChildProcess.run = async ({
26321
26033
  execArgv,
26322
26034
  // silent: true
26323
26035
  stdio: ["pipe", "pipe", "pipe", "ipc"],
26324
- env: envForChildProcess
26036
+ env: envForChildProcess,
26037
+ cwd: new URL(rootDirectoryUrl)
26325
26038
  });
26326
- logger.debug(createDetailedMessage$1(`child process forked (pid ${childProcess.pid})`, {
26039
+ logger.debug(createDetailedMessage(`child process forked (pid ${childProcess.pid})`, {
26327
26040
  "custom env": JSON.stringify(env, null, " ")
26328
26041
  }));
26329
26042
  // if we pass stream, pipe them https://github.com/sindresorhus/execa/issues/81
@@ -26584,6 +26297,7 @@ nodeWorkerThread.run = async ({
26584
26297
  // logger,
26585
26298
  rootDirectoryUrl,
26586
26299
  fileRelativeUrl,
26300
+ importMap,
26587
26301
  keepRunning,
26588
26302
  stopSignal,
26589
26303
  onConsole,
@@ -26610,6 +26324,12 @@ nodeWorkerThread.run = async ({
26610
26324
  if (coverageMethodForNodeJs !== "NODE_V8_COVERAGE") {
26611
26325
  env.NODE_V8_COVERAGE = "";
26612
26326
  }
26327
+ if (importMap) {
26328
+ env.IMPORT_MAP = JSON.stringify(importMap);
26329
+ env.IMPORT_MAP_BASE_URL = rootDirectoryUrl;
26330
+ commandLineOptions.push(`--experimental-loader=${fileURLToPath(IMPORTMAP_NODE_LOADER_FILE_URL)}`);
26331
+ commandLineOptions.push(`--require=${fileURLToPath(NO_EXPERIMENTAL_WARNING_FILE_URL)}`);
26332
+ }
26613
26333
  const workerThreadExecOptions = await createChildExecOptions({
26614
26334
  signal,
26615
26335
  debugPort,
@@ -26995,6 +26715,7 @@ const execute = async ({
26995
26715
  logLevel,
26996
26716
  rootDirectoryUrl,
26997
26717
  webServer,
26718
+ importMap,
26998
26719
  fileRelativeUrl,
26999
26720
  allocatedMs,
27000
26721
  mirrorConsole = true,
@@ -27028,6 +26749,7 @@ const execute = async ({
27028
26749
  rootDirectoryUrl,
27029
26750
  webServer,
27030
26751
  fileRelativeUrl,
26752
+ importMap,
27031
26753
  ...runtimeParams
27032
26754
  };
27033
26755
  let result = await run({