@jsenv/core 41.3.0 → 41.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import { createSupportsColor, isUnicodeSupported, eastAsianWidth, clearTerminal, eraseLines } from "./jsenv_core_node_modules.js";
2
2
  import { stripVTControlCharacters } from "node:util";
3
3
  import { readFileSync, existsSync, chmodSync, statSync, lstatSync, readdirSync, openSync, closeSync, unlinkSync, rmdirSync, mkdirSync, writeFileSync as writeFileSync$1, watch, realpathSync } from "node:fs";
4
- import { extname } from "node:path";
4
+ import { extname, basename, dirname } from "node:path";
5
5
  import crypto, { createHash } from "node:crypto";
6
6
  import { pathToFileURL, fileURLToPath } from "node:url";
7
7
 
@@ -3382,6 +3382,21 @@ const writeFileSync = (destination, content = "", { force } = {}) => {
3382
3382
  }
3383
3383
  };
3384
3384
 
3385
+ const callOnceIdle = (callback, idleMs) => {
3386
+ let timeoutId;
3387
+ return (...args) => {
3388
+ if (timeoutId) {
3389
+ clearTimeout(timeoutId);
3390
+ }
3391
+ timeoutId = setTimeout(() => {
3392
+ callback(...args);
3393
+ }, idleMs);
3394
+ if (timeoutId.unref) {
3395
+ timeoutId.unref();
3396
+ }
3397
+ };
3398
+ };
3399
+
3385
3400
  const callOnceIdlePerFile = (callback, idleMs) => {
3386
3401
  const timeoutIdMap = new Map();
3387
3402
  return (fileEvent) => {
@@ -3433,6 +3448,25 @@ const createWatcher = (sourcePath, options) => {
3433
3448
  return watcher;
3434
3449
  };
3435
3450
 
3451
+ const guardTooFastSecondCall = (
3452
+ callback,
3453
+ cooldownBetweenFileEvents = 40,
3454
+ ) => {
3455
+ let previousCallMs;
3456
+ return (...args) => {
3457
+ const nowMs = Date.now();
3458
+ if (previousCallMs) {
3459
+ const msEllapsed = nowMs - previousCallMs;
3460
+ if (msEllapsed < cooldownBetweenFileEvents) {
3461
+ previousCallMs = null;
3462
+ return;
3463
+ }
3464
+ }
3465
+ previousCallMs = nowMs;
3466
+ callback(...args);
3467
+ };
3468
+ };
3469
+
3436
3470
  const guardTooFastSecondCallPerFile = (
3437
3471
  callback,
3438
3472
  cooldownBetweenFileEvents = 40,
@@ -3476,8 +3510,8 @@ callback: ${callback}`);
3476
3510
  return { registerCleanupCallback, cleanup };
3477
3511
  };
3478
3512
 
3479
- const isLinux = process.platform === "linux";
3480
- const fsWatchSupportsRecursive = !isLinux;
3513
+ const isLinux$1 = process.platform === "linux";
3514
+ const fsWatchSupportsRecursive = !isLinux$1;
3481
3515
 
3482
3516
  const registerDirectoryLifecycle = (
3483
3517
  source,
@@ -3502,15 +3536,15 @@ const registerDirectoryLifecycle = (
3502
3536
  },
3503
3537
  ) => {
3504
3538
  const sourceUrl = assertAndNormalizeDirectoryUrl(source);
3505
- if (!undefinedOrFunction(added)) {
3539
+ if (!undefinedOrFunction$1(added)) {
3506
3540
  throw new TypeError(`added must be a function or undefined, got ${added}`);
3507
3541
  }
3508
- if (!undefinedOrFunction(updated)) {
3542
+ if (!undefinedOrFunction$1(updated)) {
3509
3543
  throw new TypeError(
3510
3544
  `updated must be a function or undefined, got ${updated}`,
3511
3545
  );
3512
3546
  }
3513
- if (!undefinedOrFunction(removed)) {
3547
+ if (!undefinedOrFunction$1(removed)) {
3514
3548
  throw new TypeError(
3515
3549
  `removed must be a function or undefined, got ${removed}`,
3516
3550
  );
@@ -3805,7 +3839,7 @@ const registerDirectoryLifecycle = (
3805
3839
  }
3806
3840
  };
3807
3841
  const handleEntryUpdated = (entryInfo) => {
3808
- if (updated && entryInfo.patternValue && shouldCallUpdated(entryInfo)) {
3842
+ if (updated && entryInfo.patternValue && shouldCallUpdated$1(entryInfo)) {
3809
3843
  infoMap.set(entryInfo.relativeUrl, entryInfo);
3810
3844
  updated({
3811
3845
  relativeUrl: entryInfo.relativeUrl,
@@ -3848,7 +3882,7 @@ ${relativeUrls.join("\n")}`,
3848
3882
  return tracker.cleanup;
3849
3883
  };
3850
3884
 
3851
- const shouldCallUpdated = (entryInfo) => {
3885
+ const shouldCallUpdated$1 = (entryInfo) => {
3852
3886
  const { stat, previousInfo } = entryInfo;
3853
3887
  if (!stat.atimeMs) {
3854
3888
  return true;
@@ -3862,7 +3896,7 @@ const shouldCallUpdated = (entryInfo) => {
3862
3896
  return true;
3863
3897
  };
3864
3898
 
3865
- const undefinedOrFunction = (value) => {
3899
+ const undefinedOrFunction$1 = (value) => {
3866
3900
  return typeof value === "undefined" || typeof value === "function";
3867
3901
  };
3868
3902
 
@@ -3891,6 +3925,224 @@ const fileSystemPathToDirectoryRelativeUrlAndFilename = (path) => {
3891
3925
  };
3892
3926
  };
3893
3927
 
3928
+ const isMacos = process.platform === "darwin";
3929
+ const isLinux = process.platform === "linux";
3930
+ const isFreeBSD = process.platform === "freebsd";
3931
+
3932
+ const registerFileLifecycle = (
3933
+ source,
3934
+ {
3935
+ added,
3936
+ updated,
3937
+ removed,
3938
+ notifyExistent = false,
3939
+ keepProcessAlive = true,
3940
+ cooldownBetweenFileEvents = 0,
3941
+ idleMs = 50,
3942
+ },
3943
+ ) => {
3944
+ const sourceUrl = assertAndNormalizeFileUrl(source);
3945
+ if (!undefinedOrFunction(added)) {
3946
+ throw new TypeError(`added must be a function or undefined, got ${added}`);
3947
+ }
3948
+ if (!undefinedOrFunction(updated)) {
3949
+ throw new TypeError(
3950
+ `updated must be a function or undefined, got ${updated}`,
3951
+ );
3952
+ }
3953
+ if (!undefinedOrFunction(removed)) {
3954
+ throw new TypeError(
3955
+ `removed must be a function or undefined, got ${removed}`,
3956
+ );
3957
+ }
3958
+ if (idleMs) {
3959
+ if (updated) {
3960
+ updated = callOnceIdle(updated, idleMs);
3961
+ }
3962
+ }
3963
+ if (cooldownBetweenFileEvents) {
3964
+ if (added) {
3965
+ added = guardTooFastSecondCall(added, cooldownBetweenFileEvents);
3966
+ }
3967
+ if (updated) {
3968
+ updated = guardTooFastSecondCall(updated, cooldownBetweenFileEvents);
3969
+ }
3970
+ if (removed) {
3971
+ removed = guardTooFastSecondCall(removed, cooldownBetweenFileEvents);
3972
+ }
3973
+ }
3974
+
3975
+ const tracker = trackResources();
3976
+
3977
+ const handleFileFound = ({ stat, existent }) => {
3978
+ const fileMutationStopWatching = watchFileMutation(sourceUrl, {
3979
+ updated,
3980
+ removed: () => {
3981
+ fileMutationStopTracking();
3982
+ watchFileAdded();
3983
+ if (removed) {
3984
+ removed();
3985
+ }
3986
+ },
3987
+ keepProcessAlive,
3988
+ stat,
3989
+ });
3990
+ const fileMutationStopTracking = tracker.registerCleanupCallback(
3991
+ fileMutationStopWatching,
3992
+ );
3993
+
3994
+ if (added) {
3995
+ if (existent) {
3996
+ if (notifyExistent) {
3997
+ added({ existent: true });
3998
+ }
3999
+ } else {
4000
+ added({});
4001
+ }
4002
+ }
4003
+ };
4004
+
4005
+ const watchFileAdded = () => {
4006
+ const fileCreationStopWatching = watchFileCreation(
4007
+ sourceUrl,
4008
+ (stat) => {
4009
+ fileCreationgStopTracking();
4010
+ handleFileFound({ stat, existent: false });
4011
+ },
4012
+ keepProcessAlive,
4013
+ );
4014
+ const fileCreationgStopTracking = tracker.registerCleanupCallback(
4015
+ fileCreationStopWatching,
4016
+ );
4017
+ };
4018
+
4019
+ const { type, stat } = readFileInfo(sourceUrl);
4020
+ if (type === null) {
4021
+ if (added) {
4022
+ watchFileAdded();
4023
+ } else {
4024
+ throw new Error(
4025
+ `${urlToFileSystemPath(sourceUrl)} must lead to a file, found nothing`,
4026
+ );
4027
+ }
4028
+ } else if (type === "file") {
4029
+ handleFileFound({ stat, existent: true });
4030
+ } else {
4031
+ throw new Error(
4032
+ `${urlToFileSystemPath(
4033
+ sourceUrl,
4034
+ )} must lead to a file, type found instead`,
4035
+ );
4036
+ }
4037
+
4038
+ return tracker.cleanup;
4039
+ };
4040
+
4041
+ const readFileInfo = (url) => {
4042
+ try {
4043
+ const stat = readEntryStatSync(new URL(url));
4044
+ return {
4045
+ type: statsToType(stat),
4046
+ stat,
4047
+ };
4048
+ } catch (e) {
4049
+ if (e.code === "ENOENT") {
4050
+ return {
4051
+ type: null,
4052
+ stat: null,
4053
+ };
4054
+ }
4055
+ throw e;
4056
+ }
4057
+ };
4058
+
4059
+ const undefinedOrFunction = (value) =>
4060
+ typeof value === "undefined" || typeof value === "function";
4061
+
4062
+ const watchFileCreation = (source, callback, keepProcessAlive) => {
4063
+ const sourcePath = urlToFileSystemPath(source);
4064
+ const sourceFilename = basename(sourcePath);
4065
+ const directoryPath = dirname(sourcePath);
4066
+ let directoryWatcher = createWatcher(directoryPath, {
4067
+ persistent: keepProcessAlive,
4068
+ });
4069
+ directoryWatcher.on("change", (eventType, filename) => {
4070
+ if (filename && filename !== sourceFilename) return;
4071
+
4072
+ const { type, stat } = readFileInfo(source);
4073
+ // ignore if something else with that name gets created
4074
+ // we are only interested into files
4075
+ if (type !== "file") {
4076
+ return;
4077
+ }
4078
+ directoryWatcher.close();
4079
+ directoryWatcher = undefined;
4080
+ callback(stat);
4081
+ });
4082
+
4083
+ return () => {
4084
+ if (directoryWatcher) {
4085
+ directoryWatcher.close();
4086
+ }
4087
+ };
4088
+ };
4089
+
4090
+ const watchFileMutation = (
4091
+ sourceUrl,
4092
+ { updated, removed, keepProcessAlive, stat },
4093
+ ) => {
4094
+ let prevStat = stat;
4095
+ let watcher;
4096
+
4097
+ const onChange = () => {
4098
+ const { type, stat } = readFileInfo(sourceUrl);
4099
+
4100
+ if (type === null) {
4101
+ stopWatching();
4102
+ if (removed) {
4103
+ removed();
4104
+ }
4105
+ } else if (type === "file") {
4106
+ if (updated && shouldCallUpdated(stat, prevStat)) {
4107
+ updated();
4108
+ }
4109
+ if ((isMacos || isLinux || isFreeBSD) && prevStat.ino !== stat.ino) {
4110
+ stopWatching();
4111
+ watch();
4112
+ }
4113
+ }
4114
+ prevStat = stat;
4115
+ };
4116
+
4117
+ const watch = () => {
4118
+ watcher = createWatcher(urlToFileSystemPath(sourceUrl), {
4119
+ persistent: keepProcessAlive,
4120
+ });
4121
+ watcher.on("change", onChange);
4122
+ };
4123
+ const stopWatching = () => {
4124
+ if (watcher) {
4125
+ watcher.close();
4126
+ watcher = undefined;
4127
+ }
4128
+ };
4129
+ watch();
4130
+ return stopWatching;
4131
+ };
4132
+
4133
+ const shouldCallUpdated = (stat, prevStat) => {
4134
+ if (!stat.atimeMs) {
4135
+ return true;
4136
+ }
4137
+ if (stat.atimeMs <= stat.mtimeMs) {
4138
+ return true;
4139
+ }
4140
+ if (stat.mtimeMs !== prevStat.mtimeMs) {
4141
+ return true;
4142
+ }
4143
+ return false;
4144
+ };
4145
+
3894
4146
  /*
3895
4147
  * - Buffer documentation on Node.js
3896
4148
  * https://nodejs.org/docs/latest-v13.x/api/buffer.html
@@ -6419,4 +6671,4 @@ const isResponseEligibleForIntegrityValidation = (response) => {
6419
6671
  return ["basic", "cors", "default"].includes(response.type);
6420
6672
  };
6421
6673
 
6422
- export { ANSI, CONTENT_TYPE, DATA_URL, JS_QUOTES, RUNTIME_COMPAT, URL_META, applyFileSystemMagicResolution, applyNodeEsmResolution, asSpecifierWithoutSearch, asUrlWithoutSearch, assertAndNormalizeDirectoryUrl, bufferToEtag, compareFileUrls, composeTwoImportMaps, createDetailedMessage$1 as createDetailedMessage, createLogger, createTaskLog, ensurePathnameTrailingSlash, ensureWindowsDriveLetter, errorToHTML, formatError, generateContentFrame, getCallerPosition, getExtensionsToTry, injectQueryParams, injectQueryParamsIntoSpecifier, isFileSystemPath, isSpecifierForNodeBuiltin, lookupPackageDirectory, moveUrl, normalizeImportMap, normalizeUrl, readCustomConditionsFromProcessArgs, readEntryStatSync, readPackageAtOrNull, registerDirectoryLifecycle, resolveImport, setUrlBasename, setUrlExtension, setUrlFilename, stringifyUrlSite, urlIsOrIsInsideOf, urlToBasename, urlToExtension$1 as urlToExtension, urlToFileSystemPath, urlToFilename$1 as urlToFilename, urlToPathname$1 as urlToPathname, urlToRelativeUrl, validateResponseIntegrity, writeFileSync };
6674
+ export { ANSI, CONTENT_TYPE, DATA_URL, JS_QUOTES, RUNTIME_COMPAT, URL_META, applyFileSystemMagicResolution, applyNodeEsmResolution, asSpecifierWithoutSearch, asUrlWithoutSearch, assertAndNormalizeDirectoryUrl, bufferToEtag, compareFileUrls, composeTwoImportMaps, createDetailedMessage$1 as createDetailedMessage, createLogger, createTaskLog, ensurePathnameTrailingSlash, ensureWindowsDriveLetter, errorToHTML, formatError, generateContentFrame, getCallerPosition, getExtensionsToTry, injectQueryParams, injectQueryParamsIntoSpecifier, isFileSystemPath, isSpecifierForNodeBuiltin, lookupPackageDirectory, moveUrl, normalizeImportMap, normalizeUrl, readCustomConditionsFromProcessArgs, readEntryStatSync, readPackageAtOrNull, registerDirectoryLifecycle, registerFileLifecycle, resolveImport, setUrlBasename, setUrlExtension, setUrlFilename, stringifyUrlSite, urlIsOrIsInsideOf, urlToBasename, urlToExtension$1 as urlToExtension, urlToFileSystemPath, urlToFilename$1 as urlToFilename, urlToPathname$1 as urlToPathname, urlToRelativeUrl, validateResponseIntegrity, writeFileSync };