@jsenv/core 41.4.5 → 41.4.7

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.
@@ -628,9 +628,10 @@ const getFirstReferenceInProject = (reference) => {
628
628
  return getFirstReferenceInProject(firstReference);
629
629
  };
630
630
 
631
- // An url written by an injection cannot be resolved: the placeholder is still there
632
- // when references are analyzed. Rather than guessing what a placeholder looks like
633
- // (the key is free-form), tell the file it comes from: injections are configured for it.
631
+ // Injections write urls in html attributes before references are analyzed, so an url
632
+ // that still cannot be resolved may be a placeholder no injection replaced. Rather than
633
+ // guessing what a placeholder looks like (the key is free-form), tell the file it comes
634
+ // from: injections are configured for it.
634
635
  const detailsFromInjectionsOnOwner = (reference) => {
635
636
  if (!reference) {
636
637
  return {};
@@ -649,7 +650,7 @@ const detailsFromInjectionsOnOwner = (reference) => {
649
650
  return {};
650
651
  }
651
652
  return {
652
- suggestion: `injections are configured for this file; when "${reference.specifier}" is meant to be written by one of them, add "jsenv-ignore" so jsenv leaves that url alone:
653
+ suggestion: `injections are configured for this file; when "${reference.specifier}" is meant to be written by one of them, check the placeholder spelling, or add "jsenv-ignore" so jsenv leaves that url alone:
653
654
  <${node.nodeName} jsenv-ignore ${attributeName}="${reference.specifier}" />`,
654
655
  };
655
656
  };
@@ -2101,6 +2102,9 @@ const createUrlInfo = (url, context) => {
2101
2102
  contentFinalized: false,
2102
2103
  contentSideEffects: [],
2103
2104
  contentInjections: {},
2105
+ // placeholders already consumed somewhere else than the content (in a specifier),
2106
+ // so that not finding them in the content is not worth a warning
2107
+ contentInjectionUsedKeySet: new Set(),
2104
2108
 
2105
2109
  sourcemap: null,
2106
2110
  sourcemapIsWrong: false,
@@ -2413,6 +2417,13 @@ const INJECTIONS = {
2413
2417
  },
2414
2418
  };
2415
2419
 
2420
+ const readInjectionValue = (injection) => {
2421
+ if (injection && injection[injectionSymbol]) {
2422
+ return injection.value;
2423
+ }
2424
+ return injection;
2425
+ };
2426
+
2416
2427
  const isPlaceholderInjection = (value) => {
2417
2428
  return (
2418
2429
  !value || !value[injectionSymbol] || value[injectionSymbol] !== "global"
@@ -2486,7 +2497,7 @@ const injectPlaceholderReplacements = (
2486
2497
  for (const { key, isOptional, value } of placeholderReplacements) {
2487
2498
  let index = content.indexOf(key);
2488
2499
  if (index === -1) {
2489
- if (!isOptional) {
2500
+ if (!isOptional && !urlInfo.contentInjectionUsedKeySet.has(key)) {
2490
2501
  urlInfo.context.logger.warn(
2491
2502
  `placeholder "${key}" not found in ${urlInfo.url}.
2492
2503
  --- suggestion a ---
@@ -2511,7 +2522,7 @@ return {
2511
2522
  magicSource.replace({
2512
2523
  start,
2513
2524
  end,
2514
- replacement: asReplacement(value, urlInfo),
2525
+ replacement: asReplacement(value, urlInfo.type),
2515
2526
  });
2516
2527
  index = content.indexOf(key, end);
2517
2528
  }
@@ -2522,8 +2533,8 @@ return {
2522
2533
  // In JS the placeholder stands for a value, so it must be substituted by a literal.
2523
2534
  // Everywhere else (html attributes and text, css, ...) it stands for a piece of text
2524
2535
  // and is substituted as-is, so it can be concatenated: href="__BACKEND_URL__/users/me"
2525
- const asReplacement = (value, urlInfo) => {
2526
- if (urlInfo.type === "js_classic" || urlInfo.type === "js_module") {
2536
+ const asReplacement = (value, type) => {
2537
+ if (type === "js_classic" || type === "js_module") {
2527
2538
  return JSON.stringify(value, null, " ");
2528
2539
  }
2529
2540
  if (typeof value === "string") {
@@ -4675,6 +4686,25 @@ const testAppliesDuring = (plugin, kitchen) => {
4675
4686
  );
4676
4687
  };
4677
4688
 
4689
+ // A bare specifier ("preact", "@jsenv/core/x.js") is resolved by node esm resolution,
4690
+ // everything else ("/a.js", "./a.js", "http://example.com/a.js") by url resolution
4691
+ const isBareSpecifier = (specifier) => {
4692
+ if (
4693
+ specifier[0] === "/" ||
4694
+ specifier.startsWith("./") ||
4695
+ specifier.startsWith("../")
4696
+ ) {
4697
+ return false;
4698
+ }
4699
+ try {
4700
+ // eslint-disable-next-line no-new
4701
+ new URL(specifier);
4702
+ return false;
4703
+ } catch {
4704
+ return true;
4705
+ }
4706
+ };
4707
+
4678
4708
  /*
4679
4709
  * https://github.com/parcel-bundler/parcel/blob/v2/packages/transformers/css/src/CSSTransformer.js
4680
4710
  */
@@ -5616,7 +5646,7 @@ const parseAndTransformJsReferences = async (
5616
5646
  let filenameHint;
5617
5647
  if (
5618
5648
  externalReferenceInfo.subtype === "import_dynamic" &&
5619
- isBareSpecifier$2(externalReferenceInfo.specifier)
5649
+ isBareSpecifier(externalReferenceInfo.specifier)
5620
5650
  ) {
5621
5651
  filenameHint = `${externalReferenceInfo.specifier}.js`;
5622
5652
  }
@@ -5706,23 +5736,6 @@ const parseAndTransformJsReferences = async (
5706
5736
  return { content, sourcemap };
5707
5737
  };
5708
5738
 
5709
- const isBareSpecifier$2 = (specifier) => {
5710
- if (
5711
- specifier[0] === "/" ||
5712
- specifier.startsWith("./") ||
5713
- specifier.startsWith("../")
5714
- ) {
5715
- return false;
5716
- }
5717
- try {
5718
- // eslint-disable-next-line no-new
5719
- new URL(specifier);
5720
- return false;
5721
- } catch {
5722
- return true;
5723
- }
5724
- };
5725
-
5726
5739
  const jsenvPluginReferenceExpectedTypes = () => {
5727
5740
  const redirectJsReference = (reference) => {
5728
5741
  const urlObject = new URL(reference.url);
@@ -6113,7 +6126,7 @@ const createBuildPackageConditions = (
6113
6126
  for (const key of keys) {
6114
6127
  const associatedValue = packageConditionsConfig[key];
6115
6128
 
6116
- if (!isBareSpecifier$1(key)) {
6129
+ if (!isBareSpecifier(key)) {
6117
6130
  const url = new URL(key, rootDirectoryUrl);
6118
6131
  associationsRaw[url] = associatedValue;
6119
6132
  continue;
@@ -6148,7 +6161,7 @@ const createBuildPackageConditions = (
6148
6161
  );
6149
6162
  resolveConditionsFromSpecifier = (specifier, importer, { resolver }) => {
6150
6163
  let associatedValue;
6151
- if (isBareSpecifier$1(specifier)) {
6164
+ if (isBareSpecifier(specifier)) {
6152
6165
  const { url } = resolver({
6153
6166
  specifier,
6154
6167
  parentUrl: importer,
@@ -6173,7 +6186,7 @@ const createBuildPackageConditions = (
6173
6186
  const nodeRuntimeEnabled = Object.keys(runtimeCompat).includes("node");
6174
6187
  // https://nodejs.org/api/esm.html#resolver-algorithm-specification
6175
6188
  const devResolver = (specifier, importer, { resolver }) => {
6176
- if (isBareSpecifier$1(specifier)) {
6189
+ if (isBareSpecifier(specifier)) {
6177
6190
  const { url } = resolver({
6178
6191
  specifier,
6179
6192
  parentUrl: importer,
@@ -6237,7 +6250,7 @@ const createBuildPackageConditions = (
6237
6250
  const associations = URL_META.resolveAssociations(
6238
6251
  { applies: value },
6239
6252
  (pattern) => {
6240
- if (isBareSpecifier$1(pattern)) {
6253
+ if (isBareSpecifier(pattern)) {
6241
6254
  try {
6242
6255
  if (pattern.endsWith("/")) {
6243
6256
  // avoid package path not exported
@@ -6260,7 +6273,7 @@ const createBuildPackageConditions = (
6260
6273
  },
6261
6274
  );
6262
6275
  customResolver = (specifier, importer, { resolver }) => {
6263
- if (isBareSpecifier$1(specifier)) {
6276
+ if (isBareSpecifier(specifier)) {
6264
6277
  const { url } = resolver({
6265
6278
  specifier,
6266
6279
  parentUrl: importer,
@@ -6392,23 +6405,6 @@ const createResolverWithFallbackOnError = (mainResolver, fallbackResolver) => {
6392
6405
  };
6393
6406
  };
6394
6407
 
6395
- const isBareSpecifier$1 = (specifier) => {
6396
- if (
6397
- specifier[0] === "/" ||
6398
- specifier.startsWith("./") ||
6399
- specifier.startsWith("../")
6400
- ) {
6401
- return false;
6402
- }
6403
- try {
6404
- // eslint-disable-next-line no-new
6405
- new URL(specifier);
6406
- return false;
6407
- } catch {
6408
- return true;
6409
- }
6410
- };
6411
-
6412
6408
  const jsenvPluginNodeEsmResolution = ({
6413
6409
  packageDirectory,
6414
6410
  resolutionConfig = {},
@@ -6555,7 +6551,13 @@ const jsenvPluginWebResolution = () => {
6555
6551
  if (ownerUrlInfo.originalUrl?.startsWith("http")) {
6556
6552
  return new URL(resource, ownerUrlInfo.originalUrl);
6557
6553
  }
6558
- const url = new URL(resource.slice(1), ownerUrlInfo.entryUrlInfo.url);
6554
+ // "/x" is the web meaning of a root-relative url: the root of what is
6555
+ // served, which is the source directory — not the directory the entry
6556
+ // point happens to sit in.
6557
+ const url = new URL(
6558
+ resource.slice(1),
6559
+ ownerUrlInfo.context.rootDirectoryUrl,
6560
+ );
6559
6561
  return url;
6560
6562
  }
6561
6563
  // baseUrl happens second argument to new URL() is different from
@@ -7676,6 +7678,7 @@ const jsenvPluginInjections = (rawAssociations) => {
7676
7678
  }
7677
7679
  return null;
7678
7680
  };
7681
+ const injectionsForUrlInfoMap = new WeakMap();
7679
7682
  let getInjections = null;
7680
7683
 
7681
7684
  return {
@@ -7694,8 +7697,8 @@ const jsenvPluginInjections = (rawAssociations) => {
7694
7697
  });
7695
7698
  return injectionsGetter;
7696
7699
  };
7697
- // an url written by an injection cannot be resolved during reference analysis;
7698
- // errors use this to tell the file holds injections and suggest "jsenv-ignore"
7700
+ // errors and the build read this to know an unresolved url may come from
7701
+ // an injection, and word what they report accordingly
7699
7702
  context.hasInjections = (url) => {
7700
7703
  return Boolean(findInjectionsGetterForUrl(url));
7701
7704
  };
@@ -7749,16 +7752,61 @@ const jsenvPluginInjections = (rawAssociations) => {
7749
7752
  contentInjections: defaultInjections,
7750
7753
  };
7751
7754
  }
7755
+ injectionsForUrlInfoMap.set(urlInfo, injections);
7752
7756
  return {
7753
- contentInjections: {
7754
- ...defaultInjections,
7755
- ...injections,
7756
- },
7757
+ contentInjections: { ...defaultInjections, ...injections },
7757
7758
  };
7758
7759
  },
7760
+ // The content still holds the placeholders when references are analyzed: they are
7761
+ // replaced at the very end, once the type of every inline content is known.
7762
+ // A specifier must not wait for that, it would resolve "__BACKEND_URL__/users/me"
7763
+ // as a file sitting next to the document. Only the placeholder is resolved here,
7764
+ // then the specifier goes to whoever resolves this kind of url (node esm, web, ...)
7765
+ resolveReference: (reference) => {
7766
+ const { ownerUrlInfo } = reference;
7767
+ const injections = injectionsForUrlInfoMap.get(ownerUrlInfo);
7768
+ if (!injections) {
7769
+ return null;
7770
+ }
7771
+ const { specifier, keySet } = injectIntoSpecifier(
7772
+ reference.specifier,
7773
+ injections,
7774
+ );
7775
+ if (keySet.size === 0) {
7776
+ return null;
7777
+ }
7778
+ reference.specifier = specifier;
7779
+ for (const key of keySet) {
7780
+ // rewriting the specifier takes the placeholder out of the content,
7781
+ // so the injection step must not expect to find it there
7782
+ ownerUrlInfo.contentInjectionUsedKeySet.add(key);
7783
+ }
7784
+ return null;
7785
+ },
7759
7786
  };
7760
7787
  };
7761
7788
 
7789
+ const injectIntoSpecifier = (specifier, injections) => {
7790
+ let specifierInjected = specifier;
7791
+ const keySet = new Set();
7792
+ for (const key of Object.keys(injections)) {
7793
+ if (!specifierInjected.includes(key)) {
7794
+ continue;
7795
+ }
7796
+ const injection = injections[key];
7797
+ if (!isPlaceholderInjection(injection)) {
7798
+ continue;
7799
+ }
7800
+ const value = readInjectionValue(injection);
7801
+ if (typeof value !== "string") {
7802
+ continue;
7803
+ }
7804
+ specifierInjected = specifierInjected.replaceAll(key, value);
7805
+ keySet.add(key);
7806
+ }
7807
+ return { specifier: specifierInjected, keySet };
7808
+ };
7809
+
7762
7810
  // What a file inlines (a <script> or a <style> inside html) is authored in that file
7763
7811
  // and inherits its injections, with two adjustments:
7764
7812
  // - a global belongs to the file itself, injecting it into each inline content would
@@ -9833,8 +9881,10 @@ const getCorePlugins = ({
9833
9881
  ...(packageBundle
9834
9882
  ? [jsenvPluginWorkspaceBundle({ packageDirectory })]
9835
9883
  : []),
9836
- jsenvPluginReferenceAnalysis(referenceAnalysis),
9884
+ // before reference analysis: an url written by an injection must hold its
9885
+ // final value when references are analyzed
9837
9886
  jsenvPluginInjections(injections),
9887
+ jsenvPluginReferenceAnalysis(referenceAnalysis),
9838
9888
  jsenvPluginTranspilation(transpilation),
9839
9889
  // "jsenvPluginInlining" must be very soon because all other plugins will react differently once they see the file is inlined
9840
9890
  ...(inlining ? [jsenvPluginInlining()] : []),
@@ -10320,6 +10370,7 @@ const createBuildSpecifierManager = ({
10320
10370
  buildDirectoryUrl,
10321
10371
  assetsDirectory,
10322
10372
  buildUrlsGenerator,
10373
+ entryKey,
10323
10374
  base,
10324
10375
  length = 8,
10325
10376
 
@@ -10358,6 +10409,7 @@ const createBuildSpecifierManager = ({
10358
10409
  urlInfo,
10359
10410
  ownerUrlInfo: reference.ownerUrlInfo,
10360
10411
  assetsDirectory,
10412
+ entryKey,
10361
10413
  });
10362
10414
  }
10363
10415
 
@@ -11177,7 +11229,7 @@ const createBuildSpecifierManager = ({
11177
11229
 
11178
11230
  prepareResyncResourceHints: ({ registerHtmlRefine }) => {
11179
11231
  const hintToInjectMap = new Map();
11180
- registerHtmlRefine((htmlAst, { registerHtmlMutation }) => {
11232
+ registerHtmlRefine((htmlAst, { registerHtmlMutation, htmlUrlInfo }) => {
11181
11233
  visitHtmlNodes(htmlAst, {
11182
11234
  link: (node) => {
11183
11235
  if (getHtmlNodeAttribute(node, "jsenv-ignore") !== undefined) {
@@ -11201,12 +11253,39 @@ const createBuildSpecifierManager = ({
11201
11253
  return;
11202
11254
  }
11203
11255
  const rawUrl = href;
11256
+ if (targetsAFileThatDoesNotExist(rawUrl)) {
11257
+ // this hint never designated anything, so nothing can explain its
11258
+ // removal; taking away markup written by hand on a guess is worse
11259
+ // than leaving it there
11260
+ logger.warn(
11261
+ createDetailedMessage(
11262
+ `${UNICODE.WARNING} resource hint kept as is: "${href}" cannot be resolved`,
11263
+ {
11264
+ "html file": htmlUrlInfo.url,
11265
+ ...(rawKitchen.context.hasInjections
11266
+ ? {
11267
+ suggestion: `when that url is written by an injection, jsenv resolves it in html attributes before analyzing references; check the placeholder spelling`,
11268
+ }
11269
+ : {}),
11270
+ },
11271
+ ),
11272
+ );
11273
+ // the build url means nothing for something jsenv could not resolve,
11274
+ // and it would leak a local path into the build
11275
+ registerHtmlMutation(() => {
11276
+ setHtmlNodeAttributes(node, {
11277
+ href: urlToRelativeUrl(rawUrl, htmlUrlInfo.url),
11278
+ });
11279
+ });
11280
+ return;
11281
+ }
11204
11282
  const finalUrl = internalRedirections.get(rawUrl) || rawUrl;
11205
11283
  const urlInfo = finalKitchen.graph.getUrlInfo(finalUrl);
11206
11284
  if (!urlInfo) {
11207
- if (rel === "preconnect" || rel === "dns-prefetch") {
11208
- // preconnect/dns-prefetch hints refer to origins, not specific resources in the graph.
11209
- // Keep them as-is the author knows what external domains will be used at runtime.
11285
+ if (!href.startsWith("file:")) {
11286
+ // the hint designates a resource jsenv does not own: an origin for
11287
+ // preconnect/dns-prefetch, a remote file for the others. The author
11288
+ // knows what the page will request at runtime, keep it as-is.
11210
11289
  return;
11211
11290
  }
11212
11291
  logger.warn(
@@ -11388,9 +11467,14 @@ const createBuildSpecifierManager = ({
11388
11467
  let contentKey;
11389
11468
  // if to guard for html where versioned build specifier is not generated
11390
11469
  if (buildSpecifierVersioned) {
11391
- const buildUrlVersioned = asBuildUrlVersioned({
11392
- buildSpecifierVersioned,
11393
- buildDirectoryUrl,
11470
+ // The version goes on the build url, not on the specifier: a
11471
+ // specifier is written for one importer to read (base: "./" makes
11472
+ // it relative to that importer, base: "https://cdn…" makes it
11473
+ // absolute elsewhere) and says nothing about where the file lands.
11474
+ const buildUrlVersioned = injectVersionIntoBuildSpecifier({
11475
+ buildSpecifier: buildUrl,
11476
+ version: versionMap.get(urlInfo),
11477
+ versioningMethod,
11394
11478
  });
11395
11479
  const buildRelativeUrlVersioned = urlToRelativeUrl(
11396
11480
  buildUrlVersioned,
@@ -11634,21 +11718,14 @@ const injectVersionIntoBuildSpecifier = ({
11634
11718
  );
11635
11719
  };
11636
11720
 
11637
- const asBuildUrlVersioned = ({
11638
- buildSpecifierVersioned,
11639
- buildDirectoryUrl,
11640
- }) => {
11641
- if (buildSpecifierVersioned[0] === "/") {
11642
- return new URL(buildSpecifierVersioned.slice(1), buildDirectoryUrl).href;
11643
- }
11644
- const buildUrl = new URL(buildSpecifierVersioned, buildDirectoryUrl).href;
11645
- if (buildUrl.startsWith(buildDirectoryUrl)) {
11646
- return buildUrl;
11721
+ const targetsAFileThatDoesNotExist = (url) => {
11722
+ if (!url.startsWith("file:")) {
11723
+ return false;
11647
11724
  }
11648
- // it's likely "base" parameter was set to an url origin like "https://cdn.example.com"
11649
- // let's move url to build directory
11650
- const { pathname, search, hash } = new URL(buildSpecifierVersioned);
11651
- return `${buildDirectoryUrl}${pathname}${search}${hash}`;
11725
+ const urlObject = new URL(url);
11726
+ urlObject.search = "";
11727
+ urlObject.hash = "";
11728
+ return !existsSync(urlObject);
11652
11729
  };
11653
11730
 
11654
11731
  // import { ANSI } from "@jsenv/humanize";
@@ -11678,12 +11755,41 @@ const createBuildUrlsGenerator = ({
11678
11755
  };
11679
11756
 
11680
11757
  const nameSetPerDirectoryMap = new Map();
11681
- const generate = (url, { urlInfo, ownerUrlInfo, assetsDirectory }) => {
11682
- const buildUrlFromMap = buildUrlMap.get(url);
11758
+ const reserveName = (directoryPath, urlName) => {
11759
+ let nameSet = nameSetPerDirectoryMap.get(directoryPath);
11760
+ if (!nameSet) {
11761
+ nameSet = new Set();
11762
+ nameSetPerDirectoryMap.set(directoryPath, nameSet);
11763
+ }
11764
+ let [basename, extension] = splitFileExtension(urlName);
11765
+ extension = extensionMappings[extension] || extension;
11766
+ let nameCandidate = `${basename}${extension}`; // reconstruct name in case extension was normalized
11767
+ let integer = 1;
11768
+ while (nameSet.has(nameCandidate)) {
11769
+ integer++;
11770
+ nameCandidate = `${basename}${integer}${extension}`;
11771
+ }
11772
+ nameSet.add(nameCandidate);
11773
+ return nameCandidate;
11774
+ };
11775
+ const generate = (
11776
+ url,
11777
+ { urlInfo, ownerUrlInfo, assetsDirectory, entryKey },
11778
+ ) => {
11779
+ // A url already inside the build directory names a chunk a bundler just
11780
+ // produced, and each entry point is bundled on its own: two of them
11781
+ // routinely produce a chunk of the same name holding different code (the
11782
+ // shared dependencies of THAT entry point, exported under names decided by
11783
+ // THAT bundle). They are told apart by the entry point they come from —
11784
+ // sharing the file would leave one entry importing exports the file on disk
11785
+ // does not have.
11786
+ const insideBuildDirectory = urlIsOrIsInsideOf(url, buildDirectoryUrl);
11787
+ const key = insideBuildDirectory ? `${entryKey} ${url}` : url;
11788
+ const buildUrlFromMap = buildUrlMap.get(key);
11683
11789
  if (buildUrlFromMap) {
11684
11790
  return buildUrlFromMap;
11685
11791
  }
11686
- if (urlIsOrIsInsideOf(url, buildDirectoryUrl)) {
11792
+ if (insideBuildDirectory) {
11687
11793
  if (ownerUrlInfo.searchParams.has("dynamic_import_id")) {
11688
11794
  const ownerDirectoryPath = determineDirectoryPath({
11689
11795
  sourceDirectoryUrl,
@@ -11695,11 +11801,18 @@ const createBuildUrlsGenerator = ({
11695
11801
  buildUrl = injectQueryParams(buildUrl, {
11696
11802
  dynamic_import_id: undefined,
11697
11803
  });
11698
- associateBuildUrl(url, buildUrl);
11804
+ associateBuildUrl(key, buildUrl);
11699
11805
  return buildUrl;
11700
11806
  }
11701
- associateBuildUrl(url, url);
11702
- return url;
11807
+ const urlObject = new URL(url);
11808
+ const chunkDirectoryPath = urlToRelativeUrl(
11809
+ new URL("./", urlObject),
11810
+ buildDirectoryUrl,
11811
+ );
11812
+ const chunkName = reserveName(chunkDirectoryPath, urlToFilename(url));
11813
+ const buildUrl = `${buildDirectoryUrl}${chunkDirectoryPath}${chunkName}${urlObject.search}${urlObject.hash}`;
11814
+ associateBuildUrl(key, buildUrl);
11815
+ return buildUrl;
11703
11816
  }
11704
11817
  if (urlInfo.type === "entry_build") {
11705
11818
  const buildUrl = new URL(urlInfo.filenameHint, buildDirectoryUrl).href;
@@ -11731,25 +11844,10 @@ const createBuildUrlsGenerator = ({
11731
11844
  urlInfo,
11732
11845
  ownerUrlInfo,
11733
11846
  });
11734
- let nameSet = nameSetPerDirectoryMap.get(directoryPath);
11735
- if (!nameSet) {
11736
- nameSet = new Set();
11737
- nameSetPerDirectoryMap.set(directoryPath, nameSet);
11738
- }
11739
11847
  const urlObject = new URL(url);
11740
11848
  injectQueryParams(urlObject, { dynamic_import_id: undefined });
11741
11849
  let { search, hash } = urlObject;
11742
- let urlName = getUrlName(url, urlInfo);
11743
- let [basename, extension] = splitFileExtension(urlName);
11744
- extension = extensionMappings[extension] || extension;
11745
- let nameCandidate = `${basename}${extension}`; // reconstruct name in case extension was normalized
11746
- let integer = 1;
11747
- while (nameSet.has(nameCandidate)) {
11748
- integer++;
11749
- nameCandidate = `${basename}${integer}${extension}`;
11750
- }
11751
- const name = nameCandidate;
11752
- nameSet.add(name);
11850
+ const name = reserveName(directoryPath, getUrlName(url, urlInfo));
11753
11851
  const buildUrl = `${buildDirectoryUrl}${directoryPath}${name}${search}${hash}`;
11754
11852
  associateBuildUrl(url, buildUrl);
11755
11853
  return buildUrl;
@@ -13136,6 +13234,7 @@ const prepareEntryPointBuild = async (
13136
13234
  base,
13137
13235
  assetsDirectory,
13138
13236
  buildUrlsGenerator,
13237
+ entryKey: sourceRelativeUrl,
13139
13238
 
13140
13239
  versioning,
13141
13240
  versioningMethod,
@@ -13374,7 +13473,10 @@ const prepareEntryPointBuild = async (
13374
13473
  const registerHtmlMutation = (callback) => {
13375
13474
  htmlMutationCallbackSet.add(callback);
13376
13475
  };
13377
- htmlRefine(htmlAst, { registerHtmlMutation });
13476
+ htmlRefine(htmlAst, {
13477
+ registerHtmlMutation,
13478
+ htmlUrlInfo: urlInfo,
13479
+ });
13378
13480
  for (const htmlMutationCallback of htmlMutationCallbackSet) {
13379
13481
  htmlMutationCallback();
13380
13482
  }
@@ -13459,21 +13561,4 @@ const prepareEntryPointBuild = async (
13459
13561
  };
13460
13562
  };
13461
13563
 
13462
- const isBareSpecifier = (specifier) => {
13463
- if (
13464
- specifier[0] === "/" ||
13465
- specifier.startsWith("./") ||
13466
- specifier.startsWith("../")
13467
- ) {
13468
- return false;
13469
- }
13470
- try {
13471
- // eslint-disable-next-line no-new
13472
- new URL(specifier);
13473
- return false;
13474
- } catch {
13475
- return true;
13476
- }
13477
- };
13478
-
13479
13564
  export { build };