@jsenv/core 40.6.2 → 40.7.1

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/build/browserslist_index/browserslist_index.js +62 -48
  2. package/dist/build/build.js +412 -185
  3. package/dist/build/jsenv_core_packages.js +103 -105
  4. package/dist/client/directory_listing/js/directory_listing.js +41 -26
  5. package/dist/client/ribbon/ribbon.js +40 -37
  6. package/dist/jsenv_core.js +4 -0
  7. package/dist/start_build_server/jsenv_core_packages.js +29 -29
  8. package/dist/start_dev_server/jsenv_core_packages.js +103 -105
  9. package/dist/start_dev_server/start_dev_server.js +412 -182
  10. package/package.json +21 -12
  11. package/src/build/build.js +9 -9
  12. package/src/build/build_specifier_manager.js +3 -3
  13. package/src/build/build_urls_generator.js +2 -2
  14. package/src/dev/start_dev_server.js +11 -8
  15. package/src/helpers/web_url_converter.js +2 -2
  16. package/src/kitchen/errors.js +1 -1
  17. package/src/kitchen/kitchen.js +2 -0
  18. package/src/kitchen/out_directory_url.js +2 -2
  19. package/src/kitchen/url_graph/url_graph.js +1 -0
  20. package/src/kitchen/url_graph/url_info_injections.js +172 -0
  21. package/src/kitchen/url_graph/url_info_transformations.js +28 -7
  22. package/src/main.js +1 -1
  23. package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +2 -2
  24. package/src/plugins/chrome_devtools_json/jsenv_plugin_chrome_devtools_json.js +1 -0
  25. package/src/plugins/global_scenarios/jsenv_plugin_global_scenarios.js +4 -9
  26. package/src/plugins/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +2 -0
  27. package/src/plugins/injections/jsenv_plugin_injections.js +51 -85
  28. package/src/plugins/plugin_controller.js +28 -7
  29. package/src/plugins/plugins.js +3 -1
  30. package/src/plugins/protocol_file/client/directory_listing.jsx +42 -23
  31. package/src/plugins/protocol_file/file_and_server_urls_converter.js +2 -5
  32. package/src/plugins/protocol_file/jsenv_plugin_directory_listing.js +65 -49
  33. package/src/plugins/protocol_file/jsenv_plugin_fs_redirection.js +36 -3
  34. package/src/plugins/protocol_file/jsenv_plugin_protocol_file.js +3 -0
  35. package/src/plugins/ribbon/client/ribbon.js +40 -37
  36. package/src/plugins/injections/internal/inject_globals.js +0 -52
@@ -1,10 +1,10 @@
1
- import { parseHtml, injectHtmlNodeAsEarlyAsPossible, createHtmlNode, stringifyHtmlAst, applyBabelPlugins, generateUrlForInlineContent, parseJsWithAcorn, visitHtmlNodes, analyzeScriptNode, getHtmlNodeText, getHtmlNodeAttribute, getHtmlNodePosition, getUrlForContentInsideHtml, setHtmlNodeAttributes, setHtmlNodeText, parseCssUrls, getHtmlNodeAttributePosition, parseSrcSet, removeHtmlNodeText, parseJsUrls, getUrlForContentInsideJs, analyzeLinkNode, injectJsenvScript, findHtmlNode, removeHtmlNode, insertHtmlNodeAfter } from "@jsenv/ast";
1
+ import { parseHtml, injectHtmlNodeAsEarlyAsPossible, createHtmlNode, stringifyHtmlAst, applyBabelPlugins, generateUrlForInlineContent, injectJsenvScript, parseJsWithAcorn, visitHtmlNodes, analyzeScriptNode, getHtmlNodeText, getHtmlNodeAttribute, getHtmlNodePosition, getUrlForContentInsideHtml, setHtmlNodeAttributes, setHtmlNodeText, parseCssUrls, getHtmlNodeAttributePosition, parseSrcSet, removeHtmlNodeText, parseJsUrls, getUrlForContentInsideJs, analyzeLinkNode, findHtmlNode, removeHtmlNode, insertHtmlNodeAfter } from "@jsenv/ast";
2
2
  import { jsenvPluginBundling } from "@jsenv/plugin-bundling";
3
3
  import { jsenvPluginMinification } from "@jsenv/plugin-minification";
4
4
  import { jsenvPluginTranspilation, jsenvPluginJsModuleFallback } from "@jsenv/plugin-transpilation";
5
5
  import { memoryUsage } from "node:process";
6
6
  import { readFileSync, existsSync, readdirSync, lstatSync, realpathSync } from "node:fs";
7
- import { lookupPackageDirectory, registerDirectoryLifecycle, urlToRelativeUrl, createDetailedMessage, stringifyUrlSite, generateContentFrame, validateResponseIntegrity, urlIsInsideOf, ensureWindowsDriveLetter, setUrlFilename, moveUrl, getCallerPosition, urlToBasename, urlToExtension, asSpecifierWithoutSearch, asUrlWithoutSearch, injectQueryParamsIntoSpecifier, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, urlToFileSystemPath, writeFileSync, createLogger, URL_META, applyNodeEsmResolution, RUNTIME_COMPAT, normalizeUrl, ANSI, CONTENT_TYPE, urlToFilename, DATA_URL, errorToHTML, normalizeImportMap, composeTwoImportMaps, resolveImport, JS_QUOTES, defaultLookupPackageScope, defaultReadPackageJson, readCustomConditionsFromProcessArgs, readEntryStatSync, ensurePathnameTrailingSlash, compareFileUrls, applyFileSystemMagicResolution, getExtensionsToTry, setUrlExtension, isSpecifierForNodeBuiltin, renderDetails, humanizeDuration, humanizeFileSize, renderTable, renderBigSection, distributePercentages, humanizeMemory, comparePathnames, UNICODE, escapeRegexpSpecialChars, injectQueryParamIntoSpecifierWithoutEncoding, renderUrlOrRelativeUrlFilename, injectQueryParams, assertAndNormalizeDirectoryUrl, Abort, raceProcessTeardownEvents, startMonitoringCpuUsage, startMonitoringMemoryUsage, createLookupPackageDirectory, readPackageAtOrNull, inferRuntimeCompatFromClosestPackage, browserDefaultRuntimeCompat, nodeDefaultRuntimeCompat, clearDirectorySync, createTaskLog, ensureEmptyDirectory, updateJsonFileSync, createDynamicLog } from "./jsenv_core_packages.js";
7
+ import { lookupPackageDirectory, registerDirectoryLifecycle, urlToRelativeUrl, createDetailedMessage, stringifyUrlSite, generateContentFrame, validateResponseIntegrity, urlIsOrIsInsideOf, ensureWindowsDriveLetter, setUrlFilename, moveUrl, getCallerPosition, urlToBasename, urlToExtension, asSpecifierWithoutSearch, asUrlWithoutSearch, injectQueryParamsIntoSpecifier, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, urlToFileSystemPath, writeFileSync, createLogger, URL_META, applyNodeEsmResolution, RUNTIME_COMPAT, normalizeUrl, ANSI, CONTENT_TYPE, urlToFilename, DATA_URL, errorToHTML, normalizeImportMap, composeTwoImportMaps, resolveImport, JS_QUOTES, defaultLookupPackageScope, defaultReadPackageJson, readCustomConditionsFromProcessArgs, readEntryStatSync, ensurePathnameTrailingSlash, compareFileUrls, applyFileSystemMagicResolution, getExtensionsToTry, setUrlExtension, isSpecifierForNodeBuiltin, renderDetails, humanizeDuration, humanizeFileSize, renderTable, renderBigSection, distributePercentages, humanizeMemory, comparePathnames, UNICODE, escapeRegexpSpecialChars, injectQueryParamIntoSpecifierWithoutEncoding, renderUrlOrRelativeUrlFilename, injectQueryParams, assertAndNormalizeDirectoryUrl, Abort, raceProcessTeardownEvents, startMonitoringCpuUsage, startMonitoringMemoryUsage, createLookupPackageDirectory, readPackageAtOrNull, inferRuntimeCompatFromClosestPackage, browserDefaultRuntimeCompat, nodeDefaultRuntimeCompat, clearDirectorySync, createTaskLog, ensureEmptyDirectory, updateJsonFileSync, createDynamicLog } from "./jsenv_core_packages.js";
8
8
  import { pathToFileURL } from "node:url";
9
9
  import { generateSourcemapFileUrl, createMagicSource, composeTwoSourcemaps, generateSourcemapDataUrl, SOURCEMAP } from "@jsenv/sourcemap";
10
10
  import { performance } from "node:perf_hooks";
@@ -306,7 +306,7 @@ ${error.message}`,
306
306
  name: "TRANSFORM_URL_CONTENT_ERROR",
307
307
  code: "PARSE_ERROR",
308
308
  reason: error.message,
309
- stack: error.stack,
309
+ stack: transformError.stack,
310
310
  trace,
311
311
  asResponse: error.asResponse,
312
312
  });
@@ -531,7 +531,7 @@ const determineFileUrlForOutDirectory = (urlInfo) => {
531
531
  if (!url.startsWith("file:")) {
532
532
  return url;
533
533
  }
534
- if (!urlIsInsideOf(url, rootDirectoryUrl)) {
534
+ if (!urlIsOrIsInsideOf(url, rootDirectoryUrl)) {
535
535
  const fsRootUrl = ensureWindowsDriveLetter("file:///", url);
536
536
  url = `${rootDirectoryUrl}@fs/${url.slice(fsRootUrl.length)}`;
537
537
  }
@@ -1858,6 +1858,7 @@ const createUrlInfo = (url, context) => {
1858
1858
  contentLength: undefined,
1859
1859
  contentFinalized: false,
1860
1860
  contentSideEffects: [],
1861
+ contentInjections: {},
1861
1862
 
1862
1863
  sourcemap: null,
1863
1864
  sourcemapIsWrong: false,
@@ -2122,6 +2123,176 @@ ${urlInfo.url}`,
2122
2123
  return urlInfo;
2123
2124
  };
2124
2125
 
2126
+ const injectionSymbol = Symbol.for("jsenv_injection");
2127
+ const INJECTIONS = {
2128
+ global: (value) => {
2129
+ return { [injectionSymbol]: "global", value };
2130
+ },
2131
+ optional: (value) => {
2132
+ return { [injectionSymbol]: "optional", value };
2133
+ },
2134
+ };
2135
+
2136
+ const isPlaceholderInjection = (value) => {
2137
+ return (
2138
+ !value || !value[injectionSymbol] || value[injectionSymbol] !== "global"
2139
+ );
2140
+ };
2141
+
2142
+ const applyContentInjections = (content, contentInjections, urlInfo) => {
2143
+ const keys = Object.keys(contentInjections);
2144
+ const globals = {};
2145
+ const placeholderReplacements = [];
2146
+ for (const key of keys) {
2147
+ const contentInjection = contentInjections[key];
2148
+ if (contentInjection && contentInjection[injectionSymbol]) {
2149
+ const valueBehindSymbol = contentInjection[injectionSymbol];
2150
+ if (valueBehindSymbol === "global") {
2151
+ globals[key] = contentInjection.value;
2152
+ } else if (valueBehindSymbol === "optional") {
2153
+ placeholderReplacements.push({
2154
+ key,
2155
+ isOptional: true,
2156
+ value: contentInjection.value,
2157
+ });
2158
+ } else {
2159
+ throw new Error(`unknown injection type "${valueBehindSymbol}"`);
2160
+ }
2161
+ } else {
2162
+ placeholderReplacements.push({
2163
+ key,
2164
+ value: contentInjection,
2165
+ });
2166
+ }
2167
+ }
2168
+
2169
+ const needGlobalsInjection = Object.keys(globals).length > 0;
2170
+ const needPlaceholderReplacements = placeholderReplacements.length > 0;
2171
+
2172
+ if (needGlobalsInjection && needPlaceholderReplacements) {
2173
+ const globalInjectionResult = injectGlobals(content, globals, urlInfo);
2174
+ const replaceInjectionResult = injectPlaceholderReplacements(
2175
+ globalInjectionResult.content,
2176
+ placeholderReplacements,
2177
+ urlInfo,
2178
+ );
2179
+ return {
2180
+ content: replaceInjectionResult.content,
2181
+ sourcemap: composeTwoSourcemaps(
2182
+ globalInjectionResult.sourcemap,
2183
+ replaceInjectionResult.sourcemap,
2184
+ ),
2185
+ };
2186
+ }
2187
+ if (needGlobalsInjection) {
2188
+ return injectGlobals(content, globals, urlInfo);
2189
+ }
2190
+ if (needPlaceholderReplacements) {
2191
+ return injectPlaceholderReplacements(
2192
+ content,
2193
+ placeholderReplacements,
2194
+ urlInfo,
2195
+ );
2196
+ }
2197
+ return null;
2198
+ };
2199
+
2200
+ const injectPlaceholderReplacements = (
2201
+ content,
2202
+ placeholderReplacements,
2203
+ urlInfo,
2204
+ ) => {
2205
+ const magicSource = createMagicSource(content);
2206
+ for (const { key, isOptional, value } of placeholderReplacements) {
2207
+ let index = content.indexOf(key);
2208
+ if (index === -1) {
2209
+ if (!isOptional) {
2210
+ urlInfo.context.logger.warn(
2211
+ `placeholder "${key}" not found in ${urlInfo.url}.
2212
+ --- suggestion a ---
2213
+ Add "${key}" in that file.
2214
+ --- suggestion b ---
2215
+ Fix eventual typo in "${key}"?
2216
+ --- suggestion c ---
2217
+ Mark injection as optional using INJECTIONS.optional():
2218
+ import { INJECTIONS } from "@jsenv/core";
2219
+
2220
+ return {
2221
+ "${key}": INJECTIONS.optional(${JSON.stringify(value)}),
2222
+ };`,
2223
+ );
2224
+ }
2225
+ continue;
2226
+ }
2227
+
2228
+ while (index !== -1) {
2229
+ const start = index;
2230
+ const end = index + key.length;
2231
+ magicSource.replace({
2232
+ start,
2233
+ end,
2234
+ replacement:
2235
+ urlInfo.type === "js_classic" ||
2236
+ urlInfo.type === "js_module" ||
2237
+ urlInfo.type === "html"
2238
+ ? JSON.stringify(value, null, " ")
2239
+ : value,
2240
+ });
2241
+ index = content.indexOf(key, end);
2242
+ }
2243
+ }
2244
+ return magicSource.toContentAndSourcemap();
2245
+ };
2246
+
2247
+ const injectGlobals = (content, globals, urlInfo) => {
2248
+ if (urlInfo.type === "html") {
2249
+ return globalInjectorOnHtml(content, globals, urlInfo);
2250
+ }
2251
+ if (urlInfo.type === "js_classic" || urlInfo.type === "js_module") {
2252
+ return globalsInjectorOnJs(content, globals, urlInfo);
2253
+ }
2254
+ throw new Error(`cannot inject globals into "${urlInfo.type}"`);
2255
+ };
2256
+ const globalInjectorOnHtml = (content, globals, urlInfo) => {
2257
+ // ideally we would inject an importmap but browser support is too low
2258
+ // (even worse for worker/service worker)
2259
+ // so for now we inject code into entry points
2260
+ const htmlAst = parseHtml({
2261
+ html: content,
2262
+ url: urlInfo.url,
2263
+ storeOriginalPositions: false,
2264
+ });
2265
+ const clientCode = generateClientCodeForGlobals(globals, {
2266
+ isWebWorker: false,
2267
+ });
2268
+ injectJsenvScript(htmlAst, {
2269
+ content: clientCode,
2270
+ pluginName: "jsenv:inject_globals",
2271
+ });
2272
+ return {
2273
+ content: stringifyHtmlAst(htmlAst),
2274
+ };
2275
+ };
2276
+ const globalsInjectorOnJs = (content, globals, urlInfo) => {
2277
+ const clientCode = generateClientCodeForGlobals(globals, {
2278
+ isWebWorker:
2279
+ urlInfo.subtype === "worker" ||
2280
+ urlInfo.subtype === "service_worker" ||
2281
+ urlInfo.subtype === "shared_worker",
2282
+ });
2283
+ const magicSource = createMagicSource(content);
2284
+ magicSource.prepend(clientCode);
2285
+ return magicSource.toContentAndSourcemap();
2286
+ };
2287
+ const generateClientCodeForGlobals = (globals, { isWebWorker = false }) => {
2288
+ const globalName = isWebWorker ? "self" : "window";
2289
+ return `Object.assign(${globalName}, ${JSON.stringify(
2290
+ globals,
2291
+ null,
2292
+ " ",
2293
+ )});`;
2294
+ };
2295
+
2125
2296
  const defineGettersOnPropertiesDerivedFromOriginalContent = (
2126
2297
  urlInfo,
2127
2298
  ) => {
@@ -2402,6 +2573,7 @@ const createUrlInfoTransformer = ({
2402
2573
  contentLength,
2403
2574
  sourcemap,
2404
2575
  sourcemapIsWrong,
2576
+ contentInjections,
2405
2577
  } = transformations;
2406
2578
  if (type) {
2407
2579
  urlInfo.type = type;
@@ -2409,13 +2581,23 @@ const createUrlInfoTransformer = ({
2409
2581
  if (contentType) {
2410
2582
  urlInfo.contentType = contentType;
2411
2583
  }
2412
- const contentModified = setContentProperties(urlInfo, {
2413
- content,
2414
- contentAst,
2415
- contentEtag,
2416
- contentLength,
2417
- });
2418
-
2584
+ if (Object.hasOwn(transformations, "contentInjections")) {
2585
+ if (contentInjections) {
2586
+ Object.assign(urlInfo.contentInjections, contentInjections);
2587
+ }
2588
+ if (content === undefined) {
2589
+ return;
2590
+ }
2591
+ }
2592
+ let contentModified;
2593
+ if (Object.hasOwn(transformations, "content")) {
2594
+ contentModified = setContentProperties(urlInfo, {
2595
+ content,
2596
+ contentAst,
2597
+ contentEtag,
2598
+ contentLength,
2599
+ });
2600
+ }
2419
2601
  if (
2420
2602
  sourcemap &&
2421
2603
  mayHaveSourcemap(urlInfo) &&
@@ -2607,6 +2789,15 @@ const createUrlInfoTransformer = ({
2607
2789
  if (transformations) {
2608
2790
  applyTransformations(urlInfo, transformations);
2609
2791
  }
2792
+ const { contentInjections } = urlInfo;
2793
+ if (contentInjections && Object.keys(contentInjections).length > 0) {
2794
+ const injectionTransformations = applyContentInjections(
2795
+ urlInfo.content,
2796
+ contentInjections,
2797
+ urlInfo,
2798
+ );
2799
+ applyTransformations(urlInfo, injectionTransformations);
2800
+ }
2610
2801
  applyContentEffects(urlInfo);
2611
2802
  urlInfo.contentFinalized = true;
2612
2803
  };
@@ -2752,6 +2943,7 @@ const createKitchen = ({
2752
2943
  inlineContentClientFileUrl,
2753
2944
  isSupportedOnCurrentClients: memoizeIsSupported(clientRuntimeCompat),
2754
2945
  isSupportedOnFutureClients: memoizeIsSupported(runtimeCompat),
2946
+ isPlaceholderInjection,
2755
2947
  getPluginMeta: null,
2756
2948
  sourcemaps,
2757
2949
  outDirectoryUrl,
@@ -3927,10 +4119,10 @@ const generateHtmlForSyntaxError = (
3927
4119
  errorLinkText: `${htmlRelativeUrl}:${line}:${column}`,
3928
4120
  syntaxErrorHTML: errorToHTML(htmlErrorContentFrame),
3929
4121
  };
3930
- const html = replacePlaceholders$1(htmlForSyntaxError, replacers);
4122
+ const html = replacePlaceholders(htmlForSyntaxError, replacers);
3931
4123
  return html;
3932
4124
  };
3933
- const replacePlaceholders$1 = (html, replacers) => {
4125
+ const replacePlaceholders = (html, replacers) => {
3934
4126
  return html.replace(/\$\{(\w+)\}/g, (match, name) => {
3935
4127
  const replacer = replacers[name];
3936
4128
  if (replacer === undefined) {
@@ -3943,10 +4135,19 @@ const replacePlaceholders$1 = (html, replacers) => {
3943
4135
  });
3944
4136
  };
3945
4137
 
3946
- const createPluginStore = (plugins) => {
4138
+ const createPluginStore = async (plugins) => {
3947
4139
  const allDevServerRoutes = [];
4140
+ const allDevServerServices = [];
3948
4141
  const pluginArray = [];
3949
- const addPlugin = (plugin) => {
4142
+
4143
+ const pluginPromises = [];
4144
+ const addPlugin = async (plugin) => {
4145
+ if (plugin && typeof plugin.then === "function") {
4146
+ pluginPromises.push(plugin);
4147
+ const value = await plugin;
4148
+ addPlugin(value);
4149
+ return;
4150
+ }
3950
4151
  if (Array.isArray(plugin)) {
3951
4152
  for (const subplugin of plugin) {
3952
4153
  addPlugin(subplugin);
@@ -3965,21 +4166,28 @@ const createPluginStore = (plugins) => {
3965
4166
  allDevServerRoutes.push(devServerRoute);
3966
4167
  }
3967
4168
  }
4169
+ if (plugin.devServerServices) {
4170
+ const devServerServices = plugin.devServerServices;
4171
+ for (const devServerService of devServerServices) {
4172
+ allDevServerServices.push(devServerService);
4173
+ }
4174
+ }
3968
4175
  pluginArray.push(plugin);
3969
4176
  };
3970
4177
  addPlugin(jsenvPluginHtmlSyntaxErrorFallback());
3971
4178
  for (const plugin of plugins) {
3972
4179
  addPlugin(plugin);
3973
4180
  }
4181
+ await Promise.all(pluginPromises);
3974
4182
 
3975
4183
  return {
3976
4184
  pluginArray,
3977
-
3978
4185
  allDevServerRoutes,
4186
+ allDevServerServices,
3979
4187
  };
3980
4188
  };
3981
4189
 
3982
- const createPluginController = (
4190
+ const createPluginController = async (
3983
4191
  pluginStore,
3984
4192
  kitchen,
3985
4193
  { initialPuginsMeta = {} } = {},
@@ -4002,7 +4210,7 @@ const createPluginController = (
4002
4210
  pluginCandidate.destroy?.();
4003
4211
  continue;
4004
4212
  }
4005
- const initPluginResult = initPlugin(pluginCandidate, kitchen);
4213
+ const initPluginResult = await initPlugin(pluginCandidate, kitchen);
4006
4214
  if (!initPluginResult) {
4007
4215
  pluginCandidate.destroy?.();
4008
4216
  continue;
@@ -4054,6 +4262,7 @@ const createPluginController = (
4054
4262
  key === "serverEvents" ||
4055
4263
  key === "mustStayFirst" ||
4056
4264
  key === "devServerRoutes" ||
4265
+ key === "devServerServices" ||
4057
4266
  key === "effect"
4058
4267
  ) {
4059
4268
  continue;
@@ -4227,6 +4436,7 @@ const createPluginController = (
4227
4436
  const HOOK_NAMES = [
4228
4437
  "init",
4229
4438
  "devServerRoutes", // is called only during dev/tests
4439
+ "devServerServices", // is called only during dev/tests
4230
4440
  "resolveReference",
4231
4441
  "redirectReference",
4232
4442
  "transformReferenceSearchParams",
@@ -4281,12 +4491,12 @@ const testAppliesDuring = (plugin, kitchen) => {
4281
4491
  `"appliesDuring" must be an object or a string, got ${appliesDuring}`,
4282
4492
  );
4283
4493
  };
4284
- const initPlugin = (plugin, kitchen) => {
4494
+ const initPlugin = async (plugin, kitchen) => {
4285
4495
  const { init } = plugin;
4286
4496
  if (!init) {
4287
4497
  return true;
4288
4498
  }
4289
- const initReturnValue = init(kitchen.context, { plugin });
4499
+ const initReturnValue = await init(kitchen.context, { plugin });
4290
4500
  if (initReturnValue === false) {
4291
4501
  return false;
4292
4502
  }
@@ -4365,6 +4575,9 @@ const returnValueAssertions = [
4365
4575
  return undefined;
4366
4576
  }
4367
4577
  if (typeof content !== "string" && !Buffer.isBuffer(content) && !body) {
4578
+ if (Object.hasOwn(valueReturned, "contentInjections")) {
4579
+ return undefined;
4580
+ }
4368
4581
  throw new Error(
4369
4582
  `Unexpected "content" returned by "${hook.plugin.name}" ${hook.name} hook: it must be a string or a buffer; got ${content}`,
4370
4583
  );
@@ -6143,10 +6356,7 @@ const jsenvPluginVersionSearchParam = () => {
6143
6356
 
6144
6357
  const FILE_AND_SERVER_URLS_CONVERTER = {
6145
6358
  asServerUrl: (fileUrl, serverRootDirectoryUrl) => {
6146
- if (fileUrl === serverRootDirectoryUrl) {
6147
- return "/";
6148
- }
6149
- if (urlIsInsideOf(fileUrl, serverRootDirectoryUrl)) {
6359
+ if (urlIsOrIsInsideOf(fileUrl, serverRootDirectoryUrl)) {
6150
6360
  const urlRelativeToServer = urlToRelativeUrl(
6151
6361
  fileUrl,
6152
6362
  serverRootDirectoryUrl,
@@ -6172,103 +6382,6 @@ const FILE_AND_SERVER_URLS_CONVERTER = {
6172
6382
  },
6173
6383
  };
6174
6384
 
6175
- const jsenvPluginInjections = (rawAssociations) => {
6176
- let resolvedAssociations;
6177
-
6178
- return {
6179
- name: "jsenv:injections",
6180
- appliesDuring: "*",
6181
- init: (context) => {
6182
- resolvedAssociations = URL_META.resolveAssociations(
6183
- { injectionsGetter: rawAssociations },
6184
- context.rootDirectoryUrl,
6185
- );
6186
- },
6187
- transformUrlContent: async (urlInfo) => {
6188
- const { injectionsGetter } = URL_META.applyAssociations({
6189
- url: asUrlWithoutSearch(urlInfo.url),
6190
- associations: resolvedAssociations,
6191
- });
6192
- if (!injectionsGetter) {
6193
- return null;
6194
- }
6195
- if (typeof injectionsGetter !== "function") {
6196
- throw new TypeError("injectionsGetter must be a function");
6197
- }
6198
- const injections = await injectionsGetter(urlInfo);
6199
- if (!injections) {
6200
- return null;
6201
- }
6202
- const keys = Object.keys(injections);
6203
- if (keys.length === 0) {
6204
- return null;
6205
- }
6206
- return replacePlaceholders(urlInfo.content, injections, urlInfo);
6207
- },
6208
- };
6209
- };
6210
-
6211
- const injectionSymbol = Symbol.for("jsenv_injection");
6212
- const INJECTIONS = {
6213
- optional: (value) => {
6214
- return { [injectionSymbol]: "optional", value };
6215
- },
6216
- };
6217
-
6218
- // we export this because it is imported by jsenv_plugin_placeholder.js and unit test
6219
- const replacePlaceholders = (content, replacements, urlInfo) => {
6220
- const magicSource = createMagicSource(content);
6221
- for (const key of Object.keys(replacements)) {
6222
- let index = content.indexOf(key);
6223
- const replacement = replacements[key];
6224
- let isOptional;
6225
- let value;
6226
- if (replacement && replacement[injectionSymbol]) {
6227
- const valueBehindSymbol = replacement[injectionSymbol];
6228
- isOptional = valueBehindSymbol === "optional";
6229
- value = replacement.value;
6230
- } else {
6231
- value = replacement;
6232
- }
6233
- if (index === -1) {
6234
- if (!isOptional) {
6235
- urlInfo.context.logger.warn(
6236
- `placeholder "${key}" not found in ${urlInfo.url}.
6237
- --- suggestion a ---
6238
- Add "${key}" in that file.
6239
- --- suggestion b ---
6240
- Fix eventual typo in "${key}"?
6241
- --- suggestion c ---
6242
- Mark injection as optional using INJECTIONS.optional():
6243
- import { INJECTIONS } from "@jsenv/core";
6244
-
6245
- return {
6246
- "${key}": INJECTIONS.optional(${JSON.stringify(value)}),
6247
- };`,
6248
- );
6249
- }
6250
- continue;
6251
- }
6252
-
6253
- while (index !== -1) {
6254
- const start = index;
6255
- const end = index + key.length;
6256
- magicSource.replace({
6257
- start,
6258
- end,
6259
- replacement:
6260
- urlInfo.type === "js_classic" ||
6261
- urlInfo.type === "js_module" ||
6262
- urlInfo.type === "html"
6263
- ? JSON.stringify(value, null, " ")
6264
- : value,
6265
- });
6266
- index = content.indexOf(key, end);
6267
- }
6268
- }
6269
- return magicSource.toContentAndSourcemap();
6270
- };
6271
-
6272
6385
  /*
6273
6386
  * NICE TO HAVE:
6274
6387
  *
@@ -6299,6 +6412,7 @@ const htmlFileUrlForDirectory = import.meta.resolve(
6299
6412
  );
6300
6413
 
6301
6414
  const jsenvPluginDirectoryListing = ({
6415
+ spa,
6302
6416
  urlMocks = false,
6303
6417
  autoreload = true,
6304
6418
  directoryContentMagicName,
@@ -6340,7 +6454,7 @@ const jsenvPluginDirectoryListing = ({
6340
6454
  return null;
6341
6455
  }
6342
6456
  }
6343
- return `${htmlFileUrlForDirectory}?url=${encodeURIComponent(url)}&enoent`;
6457
+ return `${htmlFileUrlForDirectory}?url=${encodeURIComponent(requestedUrl)}&enoent`;
6344
6458
  }
6345
6459
  const isDirectory = fsStat?.isDirectory();
6346
6460
  if (!isDirectory) {
@@ -6366,34 +6480,35 @@ const jsenvPluginDirectoryListing = ({
6366
6480
  if (urlWithoutSearch !== String(htmlFileUrlForDirectory)) {
6367
6481
  return null;
6368
6482
  }
6369
- const requestedUrl = urlInfo.searchParams.get("url");
6370
- if (!requestedUrl) {
6483
+ const urlNotFound = urlInfo.searchParams.get("url");
6484
+ if (!urlNotFound) {
6371
6485
  return null;
6372
6486
  }
6487
+
6373
6488
  urlInfo.headers["cache-control"] = "no-cache";
6374
6489
  const enoent = urlInfo.searchParams.has("enoent");
6375
6490
  if (enoent) {
6376
6491
  urlInfo.status = 404;
6377
- urlInfo.headers["cache-control"] = "no-cache";
6378
6492
  }
6379
6493
  const request = urlInfo.context.request;
6380
6494
  const { rootDirectoryUrl, mainFilePath } = urlInfo.context;
6381
- return replacePlaceholders(
6382
- urlInfo.content,
6495
+ const directoryListingInjections = generateDirectoryListingInjection(
6496
+ urlNotFound,
6383
6497
  {
6384
- ...generateDirectoryListingInjection(requestedUrl, {
6385
- autoreload,
6386
- request,
6387
- urlMocks,
6388
- directoryContentMagicName,
6389
- rootDirectoryUrl,
6390
- mainFilePath,
6391
- packageDirectory,
6392
- enoent,
6393
- }),
6498
+ spa,
6499
+ autoreload,
6500
+ request,
6501
+ urlMocks,
6502
+ directoryContentMagicName,
6503
+ rootDirectoryUrl,
6504
+ mainFilePath,
6505
+ packageDirectory,
6506
+ enoent,
6394
6507
  },
6395
- urlInfo,
6396
6508
  );
6509
+ return {
6510
+ contentInjections: directoryListingInjections,
6511
+ };
6397
6512
  },
6398
6513
  },
6399
6514
  devServerRoutes: [
@@ -6412,8 +6527,10 @@ const jsenvPluginDirectoryListing = ({
6412
6527
  directoryRelativeUrl,
6413
6528
  rootDirectoryUrl,
6414
6529
  );
6415
- const closestDirectoryUrl =
6416
- getFirstExistingDirectoryUrl(requestedUrl);
6530
+ const closestDirectoryUrl = getFirstExistingDirectoryUrl(
6531
+ requestedUrl,
6532
+ rootDirectoryUrl,
6533
+ );
6417
6534
  const sendMessage = (message) => {
6418
6535
  websocket.send(JSON.stringify(message));
6419
6536
  };
@@ -6471,8 +6588,9 @@ const jsenvPluginDirectoryListing = ({
6471
6588
  };
6472
6589
 
6473
6590
  const generateDirectoryListingInjection = (
6474
- requestedUrl,
6591
+ urlNotFound,
6475
6592
  {
6593
+ spa,
6476
6594
  rootDirectoryUrl,
6477
6595
  mainFilePath,
6478
6596
  packageDirectory,
@@ -6485,7 +6603,7 @@ const generateDirectoryListingInjection = (
6485
6603
  ) => {
6486
6604
  let serverRootDirectoryUrl = rootDirectoryUrl;
6487
6605
  const firstExistingDirectoryUrl = getFirstExistingDirectoryUrl(
6488
- requestedUrl,
6606
+ urlNotFound,
6489
6607
  serverRootDirectoryUrl,
6490
6608
  );
6491
6609
  const directoryContentItems = getDirectoryContentItems({
@@ -6536,8 +6654,8 @@ const generateDirectoryListingInjection = (
6536
6654
  const { host } = new URL(request.url);
6537
6655
  const websocketUrl = `${websocketScheme}://${host}/.internal/directory_content.websocket?directory=${encodeURIComponent(directoryUrlRelativeToServer)}`;
6538
6656
 
6539
- const navItems = [];
6540
- {
6657
+ const generateBreadcrumb = () => {
6658
+ const breadcrumb = [];
6541
6659
  const lastItemUrl = firstExistingDirectoryUrl;
6542
6660
  const lastItemRelativeUrl = urlToRelativeUrl(lastItemUrl, rootDirectoryUrl);
6543
6661
  const rootDirectoryUrlName = urlToFilename(rootDirectoryUrl);
@@ -6547,7 +6665,6 @@ const generateDirectoryListingInjection = (
6547
6665
  } else {
6548
6666
  parts = [rootDirectoryUrlName];
6549
6667
  }
6550
-
6551
6668
  let i = 0;
6552
6669
  while (i < parts.length) {
6553
6670
  const part = parts[i];
@@ -6568,7 +6685,7 @@ const generateDirectoryListingInjection = (
6568
6685
  navItemUrl,
6569
6686
  serverRootDirectoryUrl,
6570
6687
  );
6571
- let urlRelativeToDocument = urlToRelativeUrl(navItemUrl, requestedUrl);
6688
+ let urlRelativeToDocument = urlToRelativeUrl(navItemUrl, urlNotFound);
6572
6689
  const isServerRootDirectory = navItemUrl === serverRootDirectoryUrl;
6573
6690
  if (isServerRootDirectory) {
6574
6691
  urlRelativeToServer = `/${directoryContentMagicName}`;
@@ -6576,7 +6693,7 @@ const generateDirectoryListingInjection = (
6576
6693
  }
6577
6694
  const name = part;
6578
6695
  const isCurrent = navItemUrl === String(firstExistingDirectoryUrl);
6579
- navItems.push({
6696
+ breadcrumb.push({
6580
6697
  url: navItemUrl,
6581
6698
  urlRelativeToServer,
6582
6699
  urlRelativeToDocument,
@@ -6586,34 +6703,47 @@ const generateDirectoryListingInjection = (
6586
6703
  });
6587
6704
  i++;
6588
6705
  }
6589
- }
6706
+ return breadcrumb;
6707
+ };
6708
+ const breadcrumb = generateBreadcrumb();
6590
6709
 
6591
6710
  let enoentDetails = null;
6592
6711
  if (enoent) {
6712
+ const buildEnoentPathInfo = (urlBase, closestExistingUrl) => {
6713
+ let filePathExisting;
6714
+ let filePathNotFound;
6715
+ const existingIndex = String(closestExistingUrl).length;
6716
+ filePathExisting = urlToRelativeUrl(
6717
+ closestExistingUrl,
6718
+ serverRootDirectoryUrl,
6719
+ );
6720
+ filePathNotFound = urlBase.slice(existingIndex);
6721
+ return [filePathExisting, filePathNotFound];
6722
+ };
6593
6723
  const fileRelativeUrl = urlToRelativeUrl(
6594
- requestedUrl,
6724
+ urlNotFound,
6595
6725
  serverRootDirectoryUrl,
6596
6726
  );
6597
- let filePathExisting;
6598
- let filePathNotFound;
6599
- const existingIndex = String(firstExistingDirectoryUrl).length;
6600
- filePathExisting = urlToRelativeUrl(
6601
- firstExistingDirectoryUrl,
6602
- serverRootDirectoryUrl,
6603
- );
6604
- filePathNotFound = requestedUrl.slice(existingIndex);
6605
6727
  enoentDetails = {
6606
- fileUrl: requestedUrl,
6728
+ fileUrl: urlNotFound,
6607
6729
  fileRelativeUrl,
6730
+ };
6731
+
6732
+ const [filePathExisting, filePathNotFound] = buildEnoentPathInfo(
6733
+ urlNotFound,
6734
+ firstExistingDirectoryUrl,
6735
+ );
6736
+ Object.assign(enoentDetails, {
6608
6737
  filePathExisting: `/${filePathExisting}`,
6609
6738
  filePathNotFound,
6610
- };
6739
+ });
6611
6740
  }
6612
6741
 
6613
6742
  return {
6614
6743
  __DIRECTORY_LISTING__: {
6744
+ spa,
6615
6745
  enoentDetails,
6616
- navItems,
6746
+ breadcrumb,
6617
6747
  urlMocks,
6618
6748
  directoryContentMagicName,
6619
6749
  directoryUrl: firstExistingDirectoryUrl,
@@ -6626,16 +6756,16 @@ const generateDirectoryListingInjection = (
6626
6756
  },
6627
6757
  };
6628
6758
  };
6629
- const getFirstExistingDirectoryUrl = (requestedUrl, serverRootDirectoryUrl) => {
6630
- let firstExistingDirectoryUrl = new URL("./", requestedUrl);
6631
- while (!existsSync(firstExistingDirectoryUrl)) {
6632
- firstExistingDirectoryUrl = new URL("../", firstExistingDirectoryUrl);
6633
- if (!urlIsInsideOf(firstExistingDirectoryUrl, serverRootDirectoryUrl)) {
6634
- firstExistingDirectoryUrl = new URL(serverRootDirectoryUrl);
6759
+ const getFirstExistingDirectoryUrl = (urlBase, serverRootDirectoryUrl) => {
6760
+ let directoryUrlCandidate = new URL("./", urlBase);
6761
+ while (!existsSync(directoryUrlCandidate)) {
6762
+ directoryUrlCandidate = new URL("../", directoryUrlCandidate);
6763
+ if (!urlIsOrIsInsideOf(directoryUrlCandidate, serverRootDirectoryUrl)) {
6764
+ directoryUrlCandidate = new URL(serverRootDirectoryUrl);
6635
6765
  break;
6636
6766
  }
6637
6767
  }
6638
- return firstExistingDirectoryUrl;
6768
+ return directoryUrlCandidate;
6639
6769
  };
6640
6770
  const getDirectoryContentItems = ({
6641
6771
  serverRootDirectoryUrl,
@@ -6679,6 +6809,7 @@ const getDirectoryContentItems = ({
6679
6809
  };
6680
6810
 
6681
6811
  const jsenvPluginFsRedirection = ({
6812
+ spa,
6682
6813
  directoryContentMagicName,
6683
6814
  magicExtensions = ["inherit", ".js"],
6684
6815
  magicDirectoryIndex = true,
@@ -6768,11 +6899,19 @@ const jsenvPluginFsRedirection = ({
6768
6899
  // 3. The url pathname does not ends with "/"
6769
6900
  // In that case we assume client explicitely asks to load a directory
6770
6901
  if (
6902
+ spa &&
6771
6903
  !urlToExtension(urlObject) &&
6772
6904
  !urlToPathname(urlObject).endsWith("/")
6773
6905
  ) {
6774
- const { mainFilePath, rootDirectoryUrl } =
6906
+ const { requestedUrl, rootDirectoryUrl, mainFilePath } =
6775
6907
  reference.ownerUrlInfo.context;
6908
+ const closestHtmlRootFile = getClosestHtmlRootFile(
6909
+ requestedUrl,
6910
+ rootDirectoryUrl,
6911
+ );
6912
+ if (closestHtmlRootFile) {
6913
+ return closestHtmlRootFile;
6914
+ }
6776
6915
  return new URL(mainFilePath, rootDirectoryUrl);
6777
6916
  }
6778
6917
  return null;
@@ -6822,9 +6961,29 @@ const resolveSymlink = (fileUrl) => {
6822
6961
  return realUrlObject.href;
6823
6962
  };
6824
6963
 
6964
+ const getClosestHtmlRootFile = (requestedUrl, serverRootDirectoryUrl) => {
6965
+ let directoryUrl = new URL("./", requestedUrl);
6966
+ while (true) {
6967
+ const indexHtmlFileUrl = new URL(`index.html`, directoryUrl);
6968
+ if (existsSync(indexHtmlFileUrl)) {
6969
+ return indexHtmlFileUrl.href;
6970
+ }
6971
+ const filename = urlToFilename(directoryUrl);
6972
+ const htmlFileUrlCandidate = new URL(`${filename}.html`, directoryUrl);
6973
+ if (existsSync(htmlFileUrlCandidate)) {
6974
+ return htmlFileUrlCandidate.href;
6975
+ }
6976
+ if (!urlIsOrIsInsideOf(directoryUrl, serverRootDirectoryUrl)) {
6977
+ return null;
6978
+ }
6979
+ directoryUrl = new URL("../", directoryUrl);
6980
+ }
6981
+ };
6982
+
6825
6983
  const directoryContentMagicName = "...";
6826
6984
 
6827
6985
  const jsenvPluginProtocolFile = ({
6986
+ spa = true,
6828
6987
  magicExtensions,
6829
6988
  magicDirectoryIndex,
6830
6989
  preserveSymlinks,
@@ -6836,6 +6995,7 @@ const jsenvPluginProtocolFile = ({
6836
6995
  }) => {
6837
6996
  return [
6838
6997
  jsenvPluginFsRedirection({
6998
+ spa,
6839
6999
  directoryContentMagicName,
6840
7000
  magicExtensions,
6841
7001
  magicDirectoryIndex,
@@ -6891,6 +7051,7 @@ const jsenvPluginProtocolFile = ({
6891
7051
  ...(directoryListing
6892
7052
  ? [
6893
7053
  jsenvPluginDirectoryListing({
7054
+ spa,
6894
7055
  ...directoryListing,
6895
7056
  directoryContentMagicName,
6896
7057
  rootDirectoryUrl,
@@ -7085,6 +7246,69 @@ const asValidFilename = (string) => {
7085
7246
  return string;
7086
7247
  };
7087
7248
 
7249
+ const jsenvPluginInjections = (rawAssociations) => {
7250
+ const getDefaultInjections = (urlInfo) => {
7251
+ if (urlInfo.context.dev && urlInfo.type === "html") {
7252
+ const relativeUrl = urlToRelativeUrl(
7253
+ urlInfo.url,
7254
+ urlInfo.context.rootDirectoryUrl,
7255
+ );
7256
+ return {
7257
+ HTML_ROOT_PATHNAME: INJECTIONS.global(`/${relativeUrl}`),
7258
+ };
7259
+ }
7260
+ return null;
7261
+ };
7262
+ let getInjections = null;
7263
+
7264
+ return {
7265
+ name: "jsenv:injections",
7266
+ appliesDuring: "*",
7267
+ init: (context) => {
7268
+ if (rawAssociations && Object.keys(rawAssociations).length > 0) {
7269
+ const resolvedAssociations = URL_META.resolveAssociations(
7270
+ { injectionsGetter: rawAssociations },
7271
+ context.rootDirectoryUrl,
7272
+ );
7273
+ getInjections = (urlInfo) => {
7274
+ const { injectionsGetter } = URL_META.applyAssociations({
7275
+ url: asUrlWithoutSearch(urlInfo.url),
7276
+ associations: resolvedAssociations,
7277
+ });
7278
+ if (!injectionsGetter) {
7279
+ return null;
7280
+ }
7281
+ if (typeof injectionsGetter !== "function") {
7282
+ throw new TypeError("injectionsGetter must be a function");
7283
+ }
7284
+ return injectionsGetter(urlInfo);
7285
+ };
7286
+ }
7287
+ },
7288
+ transformUrlContent: async (urlInfo) => {
7289
+ const defaultInjections = getDefaultInjections(urlInfo);
7290
+ if (!getInjections) {
7291
+ return {
7292
+ contentInjections: defaultInjections,
7293
+ };
7294
+ }
7295
+ const injectionsResult = getInjections(urlInfo);
7296
+ if (!injectionsResult) {
7297
+ return {
7298
+ contentInjections: defaultInjections,
7299
+ };
7300
+ }
7301
+ const injections = await injectionsResult;
7302
+ return {
7303
+ contentInjections: {
7304
+ ...defaultInjections,
7305
+ ...injections,
7306
+ },
7307
+ };
7308
+ },
7309
+ };
7310
+ };
7311
+
7088
7312
  /*
7089
7313
  * Some code uses globals specific to Node.js in code meant to run in browsers...
7090
7314
  * This plugin will replace some node globals to things compatible with web:
@@ -7277,6 +7501,8 @@ const babelPluginMetadataExpressionPaths = (
7277
7501
  * - replaced by true: When scenario matches (import.meta.dev and it's the dev server)
7278
7502
  * - left as is to be evaluated to undefined (import.meta.build but it's the dev server)
7279
7503
  * - replaced by undefined (import.meta.dev but it's build; the goal is to ensure it's tree-shaked)
7504
+ *
7505
+ * TODO: ideally during dev we would keep import.meta.dev and ensure we set it to true rather than replacing it with true?
7280
7506
  */
7281
7507
 
7282
7508
 
@@ -7382,14 +7608,12 @@ const babelPluginMetadataImportMetaScenarios = () => {
7382
7608
 
7383
7609
  const jsenvPluginGlobalScenarios = () => {
7384
7610
  const transformIfNeeded = (urlInfo) => {
7385
- return replacePlaceholders(
7386
- urlInfo.content,
7387
- {
7611
+ return {
7612
+ contentInjections: {
7388
7613
  __DEV__: INJECTIONS.optional(urlInfo.context.dev),
7389
7614
  __BUILD__: INJECTIONS.optional(urlInfo.context.build),
7390
7615
  },
7391
- urlInfo,
7392
- );
7616
+ };
7393
7617
  };
7394
7618
 
7395
7619
  return {
@@ -7822,7 +8046,7 @@ const jsenvPluginAutoreloadServer = ({
7822
8046
  serverEvents: {
7823
8047
  reload: (serverEventInfo) => {
7824
8048
  const formatUrlForClient = (url) => {
7825
- if (urlIsInsideOf(url, serverEventInfo.rootDirectoryUrl)) {
8049
+ if (urlIsOrIsInsideOf(url, serverEventInfo.rootDirectoryUrl)) {
7826
8050
  return urlToRelativeUrl(url, serverEventInfo.rootDirectoryUrl);
7827
8051
  }
7828
8052
  if (url.startsWith("file:")) {
@@ -8397,6 +8621,7 @@ const jsenvPluginChromeDevtoolsJson = () => {
8397
8621
  devServerRoutes: [
8398
8622
  {
8399
8623
  endpoint: "GET /.well-known/appspecific/com.chrome.devtools.json",
8624
+ declarationSource: import.meta.url,
8400
8625
  fetch: (request, { kitchen }) => {
8401
8626
  const { rootDirectoryUrl } = kitchen.context;
8402
8627
  return Response.json({
@@ -8632,6 +8857,7 @@ const getCorePlugins = ({
8632
8857
  transpilation = true,
8633
8858
  inlining = true,
8634
8859
  http = false,
8860
+ spa,
8635
8861
 
8636
8862
  clientAutoreload,
8637
8863
  clientAutoreloadOnServerRestart,
@@ -8661,7 +8887,7 @@ const getCorePlugins = ({
8661
8887
 
8662
8888
  return [
8663
8889
  jsenvPluginReferenceAnalysis(referenceAnalysis),
8664
- ...(injections ? [jsenvPluginInjections(injections)] : []),
8890
+ jsenvPluginInjections(injections),
8665
8891
  jsenvPluginTranspilation(transpilation),
8666
8892
  // "jsenvPluginInlining" must be very soon because all other plugins will react differently once they see the file is inlined
8667
8893
  ...(inlining ? [jsenvPluginInlining()] : []),
@@ -8674,6 +8900,7 @@ const getCorePlugins = ({
8674
8900
  */
8675
8901
  jsenvPluginProtocolHttp(http),
8676
8902
  jsenvPluginProtocolFile({
8903
+ spa,
8677
8904
  magicExtensions,
8678
8905
  magicDirectoryIndex,
8679
8906
  directoryListing,
@@ -9783,7 +10010,7 @@ const createBuildSpecifierManager = ({
9783
10010
  // const urlInfoInsideThisDirectorySet = new Set();
9784
10011
  const versionsInfluencingThisDirectorySet = new Set();
9785
10012
  for (const [url, urlInfo] of finalKitchen.graph.urlInfoMap) {
9786
- if (!urlIsInsideOf(url, directoryUrl)) {
10013
+ if (!urlIsOrIsInsideOf(url, directoryUrl)) {
9787
10014
  continue;
9788
10015
  }
9789
10016
  // ideally we should exclude eventual directories as the are redundant
@@ -10182,7 +10409,7 @@ const createBuildSpecifierManager = ({
10182
10409
  }
10183
10410
  if (
10184
10411
  urlInfo.type === "asset" &&
10185
- urlIsInsideOf(urlInfo.url, buildDirectoryUrl)
10412
+ urlIsOrIsInsideOf(urlInfo.url, buildDirectoryUrl)
10186
10413
  ) {
10187
10414
  return;
10188
10415
  }
@@ -10497,7 +10724,7 @@ const createBuildUrlsGenerator = ({
10497
10724
  if (buildUrlFromMap) {
10498
10725
  return buildUrlFromMap;
10499
10726
  }
10500
- if (urlIsInsideOf(url, buildDirectoryUrl)) {
10727
+ if (urlIsOrIsInsideOf(url, buildDirectoryUrl)) {
10501
10728
  if (ownerUrlInfo.searchParams.has("dynamic_import_id")) {
10502
10729
  const ownerDirectoryPath = determineDirectoryPath({
10503
10730
  sourceDirectoryUrl,
@@ -10912,7 +11139,7 @@ const build = async ({
10912
11139
  );
10913
11140
  }
10914
11141
  }
10915
- if (!urlIsInsideOf(sourceUrl, sourceDirectoryUrl)) {
11142
+ if (!urlIsOrIsInsideOf(sourceUrl, sourceDirectoryUrl)) {
10916
11143
  throw new Error(
10917
11144
  `The key "${key}" in "entryPoints" is invalid: it must be inside the source directory at ${sourceDirectoryUrl}.`,
10918
11145
  );
@@ -10963,7 +11190,7 @@ const build = async ({
10963
11190
  `The buildRelativeUrl "${buildRelativeUrl}"${forEntryPointOrEmpty} is invalid: it must be a relative url.`,
10964
11191
  );
10965
11192
  }
10966
- if (!urlIsInsideOf(buildUrl, buildDirectoryUrl)) {
11193
+ if (!urlIsOrIsInsideOf(buildUrl, buildDirectoryUrl)) {
10967
11194
  throw new Error(
10968
11195
  `The buildRelativeUrl "${buildRelativeUrl}"${forEntryPointOrEmpty} is invalid: it must be inside the build directory at ${buildDirectoryUrl}.`,
10969
11196
  );
@@ -11463,7 +11690,7 @@ const build = async ({
11463
11690
  let hasSomeOutdatedSideEffectUrl = false;
11464
11691
  for (const packageSideEffectUrl of packageSideEffectUrlSet) {
11465
11692
  if (
11466
- urlIsInsideOf(packageSideEffectUrl, buildDirectoryUrl) &&
11693
+ urlIsOrIsInsideOf(packageSideEffectUrl, buildDirectoryUrl) &&
11467
11694
  !buildSideEffectUrlSet.has(packageSideEffectUrl)
11468
11695
  ) {
11469
11696
  hasSomeOutdatedSideEffectUrl = true;
@@ -11763,7 +11990,7 @@ const prepareEntryPointBuild = async (
11763
11990
  });
11764
11991
 
11765
11992
  let _getOtherEntryBuildInfo;
11766
- const rawPluginStore = createPluginStore([
11993
+ const rawPluginStore = await createPluginStore([
11767
11994
  ...(mappings ? [jsenvPluginMappings(mappings)] : []),
11768
11995
  {
11769
11996
  name: "jsenv:other_entry_point_build_during_craft",
@@ -11808,7 +12035,7 @@ const prepareEntryPointBuild = async (
11808
12035
  packageSideEffects,
11809
12036
  }),
11810
12037
  ]);
11811
- const rawPluginController = createPluginController(
12038
+ const rawPluginController = await createPluginController(
11812
12039
  rawPluginStore,
11813
12040
  rawKitchen,
11814
12041
  );
@@ -11879,7 +12106,7 @@ const prepareEntryPointBuild = async (
11879
12106
  rawKitchen.graph.getUrlInfo(entryReference.url).type === "html" &&
11880
12107
  rawKitchen.context.isSupportedOnCurrentClients("importmap"),
11881
12108
  });
11882
- const finalPluginStore = createPluginStore([
12109
+ const finalPluginStore = await createPluginStore([
11883
12110
  jsenvPluginReferenceAnalysis({
11884
12111
  ...referenceAnalysis,
11885
12112
  fetchInlineUrls: false,
@@ -11912,7 +12139,7 @@ const prepareEntryPointBuild = async (
11912
12139
  },
11913
12140
  buildSpecifierManager.jsenvPluginMoveToBuildDirectory,
11914
12141
  ]);
11915
- const finalPluginController = createPluginController(
12142
+ const finalPluginController = await createPluginController(
11916
12143
  finalPluginStore,
11917
12144
  finalKitchen,
11918
12145
  {