@jsenv/core 39.2.19 → 39.3.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.
@@ -11068,6 +11068,8 @@ const watchSourceFiles = (
11068
11068
  return stopWatchingSourceFiles;
11069
11069
  };
11070
11070
 
11071
+ const jsenvCoreDirectoryUrl = new URL("./jsenv-core/", import.meta.url);
11072
+
11071
11073
  const jsenvPluginHtmlSyntaxErrorFallback = () => {
11072
11074
  const htmlSyntaxErrorFileUrl = new URL(
11073
11075
  "./html/html_syntax_error.html",
@@ -11337,13 +11339,13 @@ const createPluginController = (
11337
11339
  currentPlugin = hook.plugin;
11338
11340
  currentHookName = hook.name;
11339
11341
  let valueReturned = hookFn(info);
11340
- currentPlugin = null;
11341
- currentHookName = null;
11342
11342
  if (info.timing) {
11343
11343
  info.timing[`${hook.name}-${hook.plugin.name.replace("jsenv:", "")}`] =
11344
11344
  performance$1.now() - startTimestamp;
11345
11345
  }
11346
11346
  valueReturned = assertAndNormalizeReturnValue(hook, valueReturned, info);
11347
+ currentPlugin = null;
11348
+ currentHookName = null;
11347
11349
  return valueReturned;
11348
11350
  };
11349
11351
  const callAsyncHook = async (hook, info) => {
@@ -11360,13 +11362,13 @@ const createPluginController = (
11360
11362
  currentPlugin = hook.plugin;
11361
11363
  currentHookName = hook.name;
11362
11364
  let valueReturned = await hookFn(info);
11363
- currentPlugin = null;
11364
- currentHookName = null;
11365
11365
  if (info.timing) {
11366
11366
  info.timing[`${hook.name}-${hook.plugin.name.replace("jsenv:", "")}`] =
11367
11367
  performance$1.now() - startTimestamp;
11368
11368
  }
11369
11369
  valueReturned = assertAndNormalizeReturnValue(hook, valueReturned, info);
11370
+ currentPlugin = null;
11371
+ currentHookName = null;
11370
11372
  return valueReturned;
11371
11373
  };
11372
11374
 
@@ -12873,6 +12875,9 @@ const applyReferenceEffectsOnUrlInfo = (reference) => {
12873
12875
  if (reference.filenameHint && !referencedUrlInfo.filenameHint) {
12874
12876
  referencedUrlInfo.filenameHint = reference.filenameHint;
12875
12877
  }
12878
+ if (reference.dirnameHint && !referencedUrlInfo.dirnameHint) {
12879
+ referencedUrlInfo.dirnameHint = reference.dirnameHint;
12880
+ }
12876
12881
  if (reference.debug) {
12877
12882
  referencedUrlInfo.debug = true;
12878
12883
  }
@@ -12992,18 +12997,28 @@ GRAPH_VISITOR.findDependency = (urlInfo, visitor) => {
12992
12997
  // because we start from root and ignore weak ref
12993
12998
  // The alternative would be to iterate on urlInfoMap
12994
12999
  // and call urlInfo.isUsed() but that would be more expensive
12995
- GRAPH_VISITOR.forEachUrlInfoStronglyReferenced = (initialUrlInfo, callback) => {
13000
+ GRAPH_VISITOR.forEachUrlInfoStronglyReferenced = (
13001
+ initialUrlInfo,
13002
+ callback,
13003
+ { directoryUrlInfoSet } = {},
13004
+ ) => {
12996
13005
  const seen = new Set();
12997
13006
  seen.add(initialUrlInfo);
12998
13007
  const iterateOnReferences = (urlInfo) => {
12999
13008
  for (const referenceToOther of urlInfo.referenceToOthersSet) {
13000
- if (referenceToOther.isWeak) {
13001
- continue;
13002
- }
13003
13009
  if (referenceToOther.gotInlined()) {
13004
13010
  continue;
13005
13011
  }
13006
13012
  const referencedUrlInfo = referenceToOther.urlInfo;
13013
+ if (
13014
+ directoryUrlInfoSet &&
13015
+ referenceToOther.expectedType === "directory"
13016
+ ) {
13017
+ directoryUrlInfoSet.add(referencedUrlInfo);
13018
+ }
13019
+ if (referenceToOther.isWeak) {
13020
+ continue;
13021
+ }
13007
13022
  if (seen.has(referencedUrlInfo)) {
13008
13023
  continue;
13009
13024
  }
@@ -14966,6 +14981,68 @@ const createRepartitionMessage = ({ html, css, js, json, other, total }) => {
14966
14981
  - `)}`;
14967
14982
  };
14968
14983
 
14984
+ const jsenvPluginDirectoryReferenceEffect = (
14985
+ directoryReferenceEffect = "error",
14986
+ ) => {
14987
+ return {
14988
+ name: "jsenv:directory_reference_effect",
14989
+ appliesDuring: "*",
14990
+ redirectReference: (reference) => {
14991
+ // http, https, data, about, ...
14992
+ if (!reference.url.startsWith("file:")) {
14993
+ return null;
14994
+ }
14995
+ if (reference.isInline) {
14996
+ return null;
14997
+ }
14998
+ if (reference.ownerUrlInfo.type === "directory") {
14999
+ reference.dirnameHint = reference.ownerUrlInfo.filenameHint;
15000
+ }
15001
+ const { pathname } = new URL(reference.url);
15002
+ if (pathname[pathname.length - 1] !== "/") {
15003
+ return null;
15004
+ }
15005
+ reference.leadsToADirectory = true;
15006
+ reference.expectedType = "directory";
15007
+ if (reference.ownerUrlInfo.type === "directory") {
15008
+ reference.dirnameHint = reference.ownerUrlInfo.filenameHint;
15009
+ }
15010
+ if (reference.type === "filesystem") {
15011
+ reference.filenameHint = `${
15012
+ reference.ownerUrlInfo.filenameHint
15013
+ }${urlToFilename$1(reference.url)}/`;
15014
+ } else {
15015
+ reference.filenameHint = `${urlToFilename$1(reference.url)}/`;
15016
+ }
15017
+ let actionForDirectory;
15018
+ if (reference.type === "a_href") {
15019
+ actionForDirectory = "copy";
15020
+ } else if (reference.type === "filesystem") {
15021
+ actionForDirectory = "copy";
15022
+ } else if (typeof directoryReferenceEffect === "string") {
15023
+ actionForDirectory = directoryReferenceEffect;
15024
+ } else if (typeof directoryReferenceEffect === "function") {
15025
+ actionForDirectory = directoryReferenceEffect(reference);
15026
+ } else {
15027
+ actionForDirectory = "error";
15028
+ }
15029
+ reference.actionForDirectory = actionForDirectory;
15030
+ if (actionForDirectory !== "copy") {
15031
+ reference.isWeak = true;
15032
+ }
15033
+ if (actionForDirectory === "error") {
15034
+ const error = new Error("Reference leads to a directory");
15035
+ error.code = "DIRECTORY_REFERENCE_NOT_ALLOWED";
15036
+ throw error;
15037
+ }
15038
+ if (actionForDirectory === "preserve") {
15039
+ return `ignore:${reference.specifier}`;
15040
+ }
15041
+ return null;
15042
+ },
15043
+ };
15044
+ };
15045
+
14969
15046
  const jsenvPluginInliningAsDataUrl = () => {
14970
15047
  return {
14971
15048
  name: "jsenv:inlining_as_data_url",
@@ -15341,15 +15418,17 @@ const jsenvPluginDirectoryReferenceAnalysis = () => {
15341
15418
  name: "jsenv:directory_reference_analysis",
15342
15419
  transformUrlContent: {
15343
15420
  directory: async (urlInfo) => {
15344
- const originalDirectoryReference =
15345
- findOriginalDirectoryReference(urlInfo);
15421
+ if (urlInfo.contentType !== "application/json") {
15422
+ return null;
15423
+ }
15424
+ // const isShapeBuildStep = urlInfo.kitchen.context.buildStep === "shape";
15425
+ const originalDirectoryReference = findOriginalDirectoryReference(
15426
+ urlInfo.firstReference,
15427
+ );
15346
15428
  const directoryRelativeUrl = urlToRelativeUrl(
15347
15429
  urlInfo.url,
15348
15430
  urlInfo.context.rootDirectoryUrl,
15349
15431
  );
15350
- if (urlInfo.contentType !== "application/json") {
15351
- return null;
15352
- }
15353
15432
  const entryNames = JSON.parse(urlInfo.content);
15354
15433
  const newEntryNames = [];
15355
15434
  for (const entryName of entryNames) {
@@ -15371,21 +15450,20 @@ const jsenvPluginDirectoryReferenceAnalysis = () => {
15371
15450
  };
15372
15451
  };
15373
15452
 
15374
- const findOriginalDirectoryReference = (urlInfo) => {
15453
+ const findOriginalDirectoryReference = (firstReference) => {
15375
15454
  const findNonFileSystemAncestor = (urlInfo) => {
15376
15455
  for (const referenceFromOther of urlInfo.referenceFromOthersSet) {
15377
- const urlInfoReferencingThisOne = referenceFromOther.ownerUrlInfo;
15378
- if (urlInfoReferencingThisOne.type !== "directory") {
15456
+ if (referenceFromOther.type !== "filesystem") {
15379
15457
  return referenceFromOther;
15380
15458
  }
15381
- const found = findNonFileSystemAncestor(urlInfoReferencingThisOne);
15382
- if (found) {
15383
- return found;
15384
- }
15459
+ return findNonFileSystemAncestor(referenceFromOther.ownerUrlInfo);
15385
15460
  }
15386
15461
  return null;
15387
15462
  };
15388
- return findNonFileSystemAncestor(urlInfo);
15463
+ if (firstReference.type !== "filesystem") {
15464
+ return firstReference;
15465
+ }
15466
+ return findNonFileSystemAncestor(firstReference.ownerUrlInfo);
15389
15467
  };
15390
15468
 
15391
15469
  // duplicated from @jsenv/log to avoid the dependency
@@ -16976,6 +17054,7 @@ const jsenvPluginReferenceAnalysis = ({
16976
17054
  inlineContent = true,
16977
17055
  inlineConvertedScript = false,
16978
17056
  fetchInlineUrls = true,
17057
+ directoryReferenceEffect,
16979
17058
  }) => {
16980
17059
  return [
16981
17060
  jsenvPluginDirectoryReferenceAnalysis(),
@@ -18406,130 +18485,129 @@ const jsenvPluginVersionSearchParam = () => {
18406
18485
  };
18407
18486
  };
18408
18487
 
18409
- const html404AndParentDirIsEmptyFileUrl = new URL(
18410
- "./html/html_404_and_parent_dir_is_empty.html",
18411
- import.meta.url,
18412
- );
18413
- const html404AndParentDirFileUrl = new URL(
18414
- "./html/html_404_and_parent_dir.html",
18415
- import.meta.url,
18416
- );
18417
- const htmlFileUrlForDirectory = new URL("./html/directory.html", import.meta.url);
18418
-
18419
- const jsenvPluginProtocolFile = ({
18488
+ const jsenvPluginFsRedirection = ({
18420
18489
  magicExtensions = ["inherit", ".js"],
18421
18490
  magicDirectoryIndex = true,
18422
18491
  preserveSymlinks = false,
18423
- directoryReferenceEffect = "error",
18424
18492
  }) => {
18425
- return [
18426
- {
18427
- name: "jsenv:fs_redirection",
18428
- appliesDuring: "*",
18429
- redirectReference: (reference) => {
18430
- // http, https, data, about, ...
18431
- if (!reference.url.startsWith("file:")) {
18432
- return null;
18433
- }
18434
- if (reference.isInline) {
18435
- return null;
18436
- }
18437
- // ignore root file url
18438
- if (reference.url === "file:///" || reference.url === "file://") {
18439
- reference.leadsToADirectory = true;
18440
- return `ignore:file:///`;
18441
- }
18442
- // ignore "./" on new URL("./")
18443
- if (
18444
- reference.subtype === "new_url_first_arg" &&
18445
- reference.specifier === "./"
18446
- ) {
18447
- return `ignore:${reference.url}`;
18448
- }
18449
- // ignore all new URL second arg
18450
- if (reference.subtype === "new_url_second_arg") {
18451
- return `ignore:${reference.url}`;
18452
- }
18453
-
18454
- const urlObject = new URL(reference.url);
18455
- let stat;
18456
- try {
18457
- stat = statSync(urlObject);
18458
- } catch (e) {
18459
- if (e.code === "ENOENT") {
18460
- stat = null;
18461
- } else {
18462
- throw e;
18463
- }
18464
- }
18465
-
18466
- const { search, hash } = urlObject;
18467
- let { pathname } = urlObject;
18468
- const pathnameUsesTrailingSlash = pathname.endsWith("/");
18469
- urlObject.search = "";
18470
- urlObject.hash = "";
18471
-
18472
- // force trailing slash on directories
18473
- if (stat && stat.isDirectory() && !pathnameUsesTrailingSlash) {
18474
- urlObject.pathname = `${pathname}/`;
18475
- }
18476
- // otherwise remove trailing slash if any
18477
- if (stat && !stat.isDirectory() && pathnameUsesTrailingSlash) {
18478
- // a warning here? (because it's strange to reference a file with a trailing slash)
18479
- urlObject.pathname = pathname.slice(0, -1);
18493
+ return {
18494
+ name: "jsenv:fs_redirection",
18495
+ appliesDuring: "*",
18496
+ redirectReference: (reference) => {
18497
+ // http, https, data, about, ...
18498
+ if (!reference.url.startsWith("file:")) {
18499
+ return null;
18500
+ }
18501
+ if (reference.isInline) {
18502
+ return null;
18503
+ }
18504
+ if (reference.url === "file:///" || reference.url === "file://") {
18505
+ reference.leadsToADirectory = true;
18506
+ return `ignore:file:///`;
18507
+ }
18508
+ // ignore all new URL second arg
18509
+ if (reference.subtype === "new_url_second_arg") {
18510
+ return `ignore:${reference.url}`;
18511
+ }
18512
+ // ignore "./" on new URL("./")
18513
+ // if (
18514
+ // reference.subtype === "new_url_first_arg" &&
18515
+ // reference.specifier === "./"
18516
+ // ) {
18517
+ // return `ignore:${reference.url}`;
18518
+ // }
18519
+ const urlObject = new URL(reference.url);
18520
+ let stat;
18521
+ try {
18522
+ stat = statSync(urlObject);
18523
+ } catch (e) {
18524
+ if (e.code === "ENOENT") {
18525
+ stat = null;
18526
+ } else {
18527
+ throw e;
18480
18528
  }
18481
-
18482
- let url = urlObject.href;
18483
- const shouldApplyDilesystemMagicResolution =
18484
- reference.type === "js_import";
18485
- if (shouldApplyDilesystemMagicResolution) {
18486
- const filesystemResolution = applyFileSystemMagicResolution(url, {
18529
+ }
18530
+ const { search, hash } = urlObject;
18531
+ urlObject.search = "";
18532
+ urlObject.hash = "";
18533
+ applyStatEffectsOnUrlObject(urlObject, stat);
18534
+ const shouldApplyFilesystemMagicResolution =
18535
+ reference.type === "js_import";
18536
+ if (shouldApplyFilesystemMagicResolution) {
18537
+ const filesystemResolution = applyFileSystemMagicResolution(
18538
+ urlObject.href,
18539
+ {
18487
18540
  fileStat: stat,
18488
18541
  magicDirectoryIndex,
18489
18542
  magicExtensions: getExtensionsToTry(
18490
18543
  magicExtensions,
18491
18544
  reference.ownerUrlInfo.url,
18492
18545
  ),
18493
- });
18494
- if (filesystemResolution.stat) {
18495
- stat = filesystemResolution.stat;
18496
- url = filesystemResolution.url;
18497
- }
18498
- }
18499
- if (!stat) {
18500
- return null;
18501
- }
18502
- reference.leadsToADirectory = stat && stat.isDirectory();
18503
- if (reference.leadsToADirectory) {
18504
- let actionForDirectory;
18505
- if (reference.type === "a_href") {
18506
- actionForDirectory = "ignore";
18507
- } else if (
18508
- reference.type === "http_request" ||
18509
- reference.type === "filesystem"
18510
- ) {
18511
- actionForDirectory = "copy";
18512
- } else if (typeof directoryReferenceEffect === "string") {
18513
- actionForDirectory = directoryReferenceEffect;
18514
- } else if (typeof directoryReferenceEffect === "function") {
18515
- actionForDirectory = directoryReferenceEffect(reference);
18516
- } else {
18517
- actionForDirectory = "error";
18518
- }
18519
- if (actionForDirectory === "error") {
18520
- const error = new Error("Reference leads to a directory");
18521
- error.code = "DIRECTORY_REFERENCE_NOT_ALLOWED";
18522
- throw error;
18523
- }
18524
- if (actionForDirectory === "preserve") {
18525
- return `ignore:${url}${search}${hash}`;
18526
- }
18546
+ },
18547
+ );
18548
+ if (filesystemResolution.stat) {
18549
+ stat = filesystemResolution.stat;
18550
+ urlObject.href = filesystemResolution.url;
18551
+ applyStatEffectsOnUrlObject(urlObject, stat);
18527
18552
  }
18528
- const urlRaw = preserveSymlinks ? url : resolveSymlink(url);
18529
- const resolvedUrl = `${urlRaw}${search}${hash}`;
18530
- return resolvedUrl;
18531
- },
18553
+ }
18554
+ if (!stat) {
18555
+ return null;
18556
+ }
18557
+ const urlRaw = preserveSymlinks
18558
+ ? urlObject.href
18559
+ : resolveSymlink(urlObject.href);
18560
+ const resolvedUrl = `${urlRaw}${search}${hash}`;
18561
+ return resolvedUrl;
18532
18562
  },
18563
+ };
18564
+ };
18565
+
18566
+ const applyStatEffectsOnUrlObject = (urlObject, stat) => {
18567
+ const { pathname } = urlObject;
18568
+ const pathnameUsesTrailingSlash = pathname.endsWith("/");
18569
+ // force trailing slash on directories
18570
+ if (stat && stat.isDirectory() && !pathnameUsesTrailingSlash) {
18571
+ urlObject.pathname = `${pathname}/`;
18572
+ }
18573
+ // otherwise remove trailing slash if any
18574
+ if (stat && !stat.isDirectory() && pathnameUsesTrailingSlash) {
18575
+ // a warning here? (because it's strange to reference a file with a trailing slash)
18576
+ urlObject.pathname = pathname.slice(0, -1);
18577
+ }
18578
+ };
18579
+
18580
+ const resolveSymlink = (fileUrl) => {
18581
+ const urlObject = new URL(fileUrl);
18582
+ const realpath = realpathSync(urlObject);
18583
+ const realUrlObject = pathToFileURL(realpath);
18584
+ if (urlObject.pathname.endsWith("/")) {
18585
+ realUrlObject.pathname += `/`;
18586
+ }
18587
+ return realUrlObject.href;
18588
+ };
18589
+
18590
+ const html404AndParentDirIsEmptyFileUrl = new URL(
18591
+ "./html/html_404_and_parent_dir_is_empty.html",
18592
+ import.meta.url,
18593
+ );
18594
+ const html404AndParentDirFileUrl = new URL(
18595
+ "./html/html_404_and_parent_dir.html",
18596
+ import.meta.url,
18597
+ );
18598
+ const htmlFileUrlForDirectory = new URL("./html/directory.html", import.meta.url);
18599
+
18600
+ const jsenvPluginProtocolFile = ({
18601
+ magicExtensions,
18602
+ magicDirectoryIndex,
18603
+ preserveSymlinks,
18604
+ }) => {
18605
+ return [
18606
+ jsenvPluginFsRedirection({
18607
+ magicExtensions,
18608
+ magicDirectoryIndex,
18609
+ preserveSymlinks,
18610
+ }),
18533
18611
  {
18534
18612
  name: "jsenv:fs_resolution",
18535
18613
  appliesDuring: "*",
@@ -18579,18 +18657,10 @@ const jsenvPluginProtocolFile = ({
18579
18657
  return null;
18580
18658
  }
18581
18659
  const urlObject = new URL(urlInfo.url);
18582
- if (urlInfo.firstReference.leadsToADirectory) {
18583
- if (!urlInfo.filenameHint) {
18584
- if (urlInfo.firstReference.type === "filesystem") {
18585
- urlInfo.filenameHint = `${
18586
- urlInfo.firstReference.ownerUrlInfo.filenameHint
18587
- }${urlToFilename$1(urlInfo.url)}/`;
18588
- } else {
18589
- urlInfo.filenameHint = `${urlToFilename$1(urlInfo.url)}/`;
18590
- }
18591
- }
18660
+ const { firstReference } = urlInfo;
18661
+ if (firstReference.leadsToADirectory) {
18592
18662
  const directoryContentArray = readdirSync(urlObject);
18593
- if (urlInfo.firstReference.type === "filesystem") {
18663
+ if (firstReference.type === "filesystem") {
18594
18664
  const content = JSON.stringify(directoryContentArray, null, " ");
18595
18665
  return {
18596
18666
  type: "directory",
@@ -18618,13 +18688,6 @@ const jsenvPluginProtocolFile = ({
18618
18688
  content: JSON.stringify(directoryContentArray, null, " "),
18619
18689
  };
18620
18690
  }
18621
- if (
18622
- !urlInfo.dirnameHint &&
18623
- urlInfo.firstReference.ownerUrlInfo.type === "directory"
18624
- ) {
18625
- urlInfo.dirnameHint =
18626
- urlInfo.firstReference.ownerUrlInfo.filenameHint;
18627
- }
18628
18691
  const contentType = CONTENT_TYPE.fromUrlExtension(urlInfo.url);
18629
18692
  if (contentType === "text/html") {
18630
18693
  try {
@@ -18770,16 +18833,6 @@ const replacePlaceholders$1 = (html, replacers) => {
18770
18833
  });
18771
18834
  };
18772
18835
 
18773
- const resolveSymlink = (fileUrl) => {
18774
- const urlObject = new URL(fileUrl);
18775
- const realpath = realpathSync(urlObject);
18776
- const realUrlObject = pathToFileURL(realpath);
18777
- if (urlObject.pathname.endsWith("/")) {
18778
- realUrlObject.pathname += `/`;
18779
- }
18780
- return realUrlObject.href;
18781
- };
18782
-
18783
18836
  const jsenvPluginProtocolHttp = () => {
18784
18837
  return {
18785
18838
  name: "jsenv:protocol_http",
@@ -20213,7 +20266,6 @@ const getCorePlugins = ({
20213
20266
  - All the rest uses web standard url resolution
20214
20267
  */
20215
20268
  jsenvPluginProtocolFile({
20216
- directoryReferenceEffect,
20217
20269
  magicExtensions,
20218
20270
  magicDirectoryIndex,
20219
20271
  }),
@@ -20222,6 +20274,7 @@ const getCorePlugins = ({
20222
20274
  ? [jsenvPluginNodeEsmResolution(nodeEsmResolution)]
20223
20275
  : []),
20224
20276
  jsenvPluginWebResolution(),
20277
+ jsenvPluginDirectoryReferenceEffect(directoryReferenceEffect),
20225
20278
 
20226
20279
  jsenvPluginVersionSearchParam(),
20227
20280
  jsenvPluginCommonJsGlobals(),
@@ -20240,46 +20293,6 @@ const getCorePlugins = ({
20240
20293
  ];
20241
20294
  };
20242
20295
 
20243
- const ensureUnixLineBreaks = (stringOrBuffer) => {
20244
- if (typeof stringOrBuffer === "string") {
20245
- const stringWithLinuxBreaks = stringOrBuffer.replace(/\r\n/g, "\n");
20246
- return stringWithLinuxBreaks;
20247
- }
20248
- return ensureUnixLineBreaksOnBuffer(stringOrBuffer);
20249
- };
20250
-
20251
- // https://github.com/nodejs/help/issues/1738#issuecomment-458460503
20252
- const ensureUnixLineBreaksOnBuffer = (buffer) => {
20253
- const int32Array = new Int32Array(buffer, 0, buffer.length);
20254
- const int32ArrayWithLineBreaksNormalized = int32Array.filter(
20255
- (element, index, typedArray) => {
20256
- if (element === 0x0d) {
20257
- if (typedArray[index + 1] === 0x0a) {
20258
- // Windows -> Unix
20259
- return false;
20260
- }
20261
- // Mac OS -> Unix
20262
- typedArray[index] = 0x0a;
20263
- }
20264
- return true;
20265
- },
20266
- );
20267
- return Buffer.from(int32ArrayWithLineBreaksNormalized);
20268
- };
20269
-
20270
- const jsenvPluginLineBreakNormalization = () => {
20271
- return {
20272
- name: "jsenv:line_break_normalizer",
20273
- appliesDuring: "build",
20274
- transformUrlContent: (urlInfo) => {
20275
- if (CONTENT_TYPE.isTextual(urlInfo.contentType)) {
20276
- return ensureUnixLineBreaks(urlInfo.content);
20277
- }
20278
- return null;
20279
- },
20280
- };
20281
- };
20282
-
20283
20296
  const escapeChars = (string, replacements) => {
20284
20297
  const charsToEscape = Object.keys(replacements);
20285
20298
  let result = "";
@@ -20357,9 +20370,14 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
20357
20370
  if (buildUrlFromCache) {
20358
20371
  return buildUrlFromCache;
20359
20372
  }
20360
- if (urlInfo.type === "directory") {
20373
+ if (
20374
+ urlInfo.type === "directory" ||
20375
+ (urlInfo.type === undefined && urlInfo.typeHint === "directory")
20376
+ ) {
20361
20377
  let directoryPath;
20362
- if (urlInfo.filenameHint) {
20378
+ if (url === sourceDirectoryUrl) {
20379
+ directoryPath = "";
20380
+ } else if (urlInfo.filenameHint) {
20363
20381
  directoryPath = urlInfo.filenameHint;
20364
20382
  } else {
20365
20383
  directoryPath = urlToRelativeUrl(url, sourceDirectoryUrl);
@@ -20732,7 +20750,7 @@ const createBuildSpecifierManager = ({
20732
20750
  if (!generatedUrl.startsWith("file:")) {
20733
20751
  return null;
20734
20752
  }
20735
- if (reference.isWeak) {
20753
+ if (reference.isWeak && reference.expectedType !== "directory") {
20736
20754
  return null;
20737
20755
  }
20738
20756
  if (reference.type === "sourcemap_comment") {
@@ -20997,6 +21015,9 @@ const createBuildSpecifierManager = ({
20997
21015
  if (reference.type === "sourcemap_comment") {
20998
21016
  return false;
20999
21017
  }
21018
+ if (reference.expectedType === "directory") {
21019
+ return true;
21020
+ }
21000
21021
  // specifier comes from "normalize" hook done a bit earlier in this file
21001
21022
  // we want to get back their build url to access their infos
21002
21023
  const referencedUrlInfo = reference.urlInfo;
@@ -21009,6 +21030,7 @@ const createBuildSpecifierManager = ({
21009
21030
  const prepareVersioning = () => {
21010
21031
  const contentOnlyVersionMap = new Map();
21011
21032
  const urlInfoToContainedPlaceholderSetMap = new Map();
21033
+ const directoryUrlInfoSet = new Set();
21012
21034
  {
21013
21035
  GRAPH_VISITOR.forEachUrlInfoStronglyReferenced(
21014
21036
  finalKitchen.graph.rootUrlInfo,
@@ -21065,6 +21087,9 @@ const createBuildSpecifierManager = ({
21065
21087
  const contentVersion = generateVersion([content], versionLength);
21066
21088
  contentOnlyVersionMap.set(urlInfo, contentVersion);
21067
21089
  },
21090
+ {
21091
+ directoryUrlInfoSet,
21092
+ },
21068
21093
  );
21069
21094
  }
21070
21095
 
@@ -21111,9 +21136,13 @@ const createBuildSpecifierManager = ({
21111
21136
  }
21112
21137
  return setOfUrlInfluencingVersion;
21113
21138
  };
21114
- for (const [urlInfo, contentOnlyVersion] of contentOnlyVersionMap) {
21139
+
21140
+ for (const [
21141
+ contentOnlyUrlInfo,
21142
+ contentOnlyVersion,
21143
+ ] of contentOnlyVersionMap) {
21115
21144
  const setOfUrlInfoInfluencingVersion =
21116
- getSetOfUrlInfoInfluencingVersion(urlInfo);
21145
+ getSetOfUrlInfoInfluencingVersion(contentOnlyUrlInfo);
21117
21146
  const versionPartSet = new Set();
21118
21147
  versionPartSet.add(contentOnlyVersion);
21119
21148
  for (const urlInfoInfluencingVersion of setOfUrlInfoInfluencingVersion) {
@@ -21122,13 +21151,42 @@ const createBuildSpecifierManager = ({
21122
21151
  );
21123
21152
  if (!otherUrlInfoContentVersion) {
21124
21153
  throw new Error(
21125
- `cannot find content version for ${urlInfoInfluencingVersion.url} (used by ${urlInfo.url})`,
21154
+ `cannot find content version for ${urlInfoInfluencingVersion.url} (used by ${contentOnlyUrlInfo.url})`,
21126
21155
  );
21127
21156
  }
21128
21157
  versionPartSet.add(otherUrlInfoContentVersion);
21129
21158
  }
21130
21159
  const version = generateVersion(versionPartSet, versionLength);
21131
- versionMap.set(urlInfo, version);
21160
+ versionMap.set(contentOnlyUrlInfo, version);
21161
+ }
21162
+ }
21163
+
21164
+ {
21165
+ // we should grab all the files inside this directory
21166
+ // they will influence his versioning
21167
+ for (const directoryUrlInfo of directoryUrlInfoSet) {
21168
+ const directoryUrl = directoryUrlInfo.url;
21169
+ // const urlInfoInsideThisDirectorySet = new Set();
21170
+ const versionsInfluencingThisDirectorySet = new Set();
21171
+ for (const [url, urlInfo] of finalKitchen.graph.urlInfoMap) {
21172
+ if (!urlIsInsideOf(url, directoryUrl)) {
21173
+ continue;
21174
+ }
21175
+ // ideally we should exclude eventual directories as the are redundant
21176
+ // with the file they contains
21177
+ const version = versionMap.get(urlInfo);
21178
+ if (version !== undefined) {
21179
+ versionsInfluencingThisDirectorySet.add(version);
21180
+ }
21181
+ }
21182
+ const contentVersion =
21183
+ versionsInfluencingThisDirectorySet.size === 0
21184
+ ? "empty"
21185
+ : generateVersion(
21186
+ versionsInfluencingThisDirectorySet,
21187
+ versionLength,
21188
+ );
21189
+ versionMap.set(directoryUrlInfo, contentVersion);
21132
21190
  }
21133
21191
  }
21134
21192
  };
@@ -21142,6 +21200,9 @@ const createBuildSpecifierManager = ({
21142
21200
  return buildSpecifier;
21143
21201
  }
21144
21202
  const version = versionMap.get(reference.urlInfo);
21203
+ if (version === undefined) {
21204
+ return buildSpecifier;
21205
+ }
21145
21206
  const buildSpecifierVersioned = injectVersionIntoBuildSpecifier({
21146
21207
  buildSpecifier,
21147
21208
  versioningMethod,
@@ -21251,9 +21312,9 @@ const createBuildSpecifierManager = ({
21251
21312
  generateReplacement(urlInfo.firstReference);
21252
21313
  }
21253
21314
  if (urlInfo.firstReference.type === "side_effect_file") {
21315
+ // side effect stuff must be generated too
21254
21316
  generateReplacement(urlInfo.firstReference);
21255
21317
  }
21256
- // side effect stuff must be generated too
21257
21318
  if (mayUsePlaceholder(urlInfo)) {
21258
21319
  const contentBeforeReplace = urlInfo.content;
21259
21320
  const { content, sourcemap } = placeholderAPI.replaceAll(
@@ -21729,6 +21790,46 @@ const asBuildUrlVersioned = ({
21729
21790
  return `${buildDirectoryUrl}${pathname}${search}${hash}`;
21730
21791
  };
21731
21792
 
21793
+ const ensureUnixLineBreaks = (stringOrBuffer) => {
21794
+ if (typeof stringOrBuffer === "string") {
21795
+ const stringWithLinuxBreaks = stringOrBuffer.replace(/\r\n/g, "\n");
21796
+ return stringWithLinuxBreaks;
21797
+ }
21798
+ return ensureUnixLineBreaksOnBuffer(stringOrBuffer);
21799
+ };
21800
+
21801
+ // https://github.com/nodejs/help/issues/1738#issuecomment-458460503
21802
+ const ensureUnixLineBreaksOnBuffer = (buffer) => {
21803
+ const int32Array = new Int32Array(buffer, 0, buffer.length);
21804
+ const int32ArrayWithLineBreaksNormalized = int32Array.filter(
21805
+ (element, index, typedArray) => {
21806
+ if (element === 0x0d) {
21807
+ if (typedArray[index + 1] === 0x0a) {
21808
+ // Windows -> Unix
21809
+ return false;
21810
+ }
21811
+ // Mac OS -> Unix
21812
+ typedArray[index] = 0x0a;
21813
+ }
21814
+ return true;
21815
+ },
21816
+ );
21817
+ return Buffer.from(int32ArrayWithLineBreaksNormalized);
21818
+ };
21819
+
21820
+ const jsenvPluginLineBreakNormalization = () => {
21821
+ return {
21822
+ name: "jsenv:line_break_normalizer",
21823
+ appliesDuring: "build",
21824
+ transformUrlContent: (urlInfo) => {
21825
+ if (CONTENT_TYPE.isTextual(urlInfo.contentType)) {
21826
+ return ensureUnixLineBreaks(urlInfo.content);
21827
+ }
21828
+ return null;
21829
+ },
21830
+ };
21831
+ };
21832
+
21732
21833
  /*
21733
21834
  * Build is split in 3 steps:
21734
21835
  * 1. craft
@@ -21857,7 +21958,10 @@ const build = async ({
21857
21958
  "buildDirectoryUrl",
21858
21959
  );
21859
21960
  if (outDirectoryUrl === undefined) {
21860
- if (process.env.CAPTURING_SIDE_EFFECTS) {
21961
+ if (
21962
+ process.env.CAPTURING_SIDE_EFFECTS ||
21963
+ urlIsInsideOf(sourceDirectoryUrl, jsenvCoreDirectoryUrl)
21964
+ ) {
21861
21965
  outDirectoryUrl = new URL("../.jsenv/", sourceDirectoryUrl);
21862
21966
  } else {
21863
21967
  const packageDirectoryUrl = lookupPackageDirectory(sourceDirectoryUrl);
@@ -22071,6 +22175,7 @@ build ${entryPointKeys.length} entry points`);
22071
22175
  fetchInlineUrls: false,
22072
22176
  // inlineContent: false,
22073
22177
  }),
22178
+ jsenvPluginDirectoryReferenceEffect(directoryReferenceEffect),
22074
22179
  ...(lineBreakNormalization
22075
22180
  ? [jsenvPluginLineBreakNormalization()]
22076
22181
  : []),
@@ -22723,7 +22828,10 @@ const startDevServer = async ({
22723
22828
  sourceDirectoryUrl,
22724
22829
  );
22725
22830
  if (outDirectoryUrl === undefined) {
22726
- if (process.env.CAPTURING_SIDE_EFFECTS) {
22831
+ if (
22832
+ process.env.CAPTURING_SIDE_EFFECTS ||
22833
+ urlIsInsideOf(sourceDirectoryUrl, jsenvCoreDirectoryUrl)
22834
+ ) {
22727
22835
  outDirectoryUrl = new URL("../.jsenv/", sourceDirectoryUrl);
22728
22836
  } else {
22729
22837
  const packageDirectoryUrl = lookupPackageDirectory(sourceDirectoryUrl);