@rspack/core 2.0.1 → 2.0.3

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 (47) hide show
  1. package/compiled/http-proxy-middleware/index.d.ts +5 -30
  2. package/compiled/http-proxy-middleware/package.json +1 -1
  3. package/compiled/watchpack/index.d.ts +2 -218
  4. package/compiled/watchpack/index.js +1387 -939
  5. package/compiled/watchpack/package.json +8 -1
  6. package/compiled/watchpack/types/DirectoryWatcher.d.ts +333 -0
  7. package/compiled/watchpack/types/LinkResolver.d.ts +10 -0
  8. package/compiled/watchpack/types/getWatcherManager.d.ts +62 -0
  9. package/compiled/watchpack/types/index.d.ts +261 -0
  10. package/compiled/watchpack/types/reducePlan.d.ts +34 -0
  11. package/compiled/watchpack/types/watchEventSource.d.ts +53 -0
  12. package/compiled/watchpack/types/watchpack.d.ts +2 -0
  13. package/dist/Compilation.d.ts +3 -3
  14. package/dist/MultiCompiler.d.ts +1 -1
  15. package/dist/RuntimeGlobals.d.ts +1 -1
  16. package/dist/builtin-plugin/DeterministicChunkIdsPlugin.d.ts +1 -1
  17. package/dist/builtin-plugin/DeterministicModuleIdsPlugin.d.ts +1 -1
  18. package/dist/builtin-plugin/DynamicEntryPlugin.d.ts +1 -1
  19. package/dist/builtin-plugin/FlagDependencyUsagePlugin.d.ts +1 -1
  20. package/dist/builtin-plugin/HttpUriPlugin.d.ts +1 -1
  21. package/dist/builtin-plugin/JavascriptModulesPlugin.d.ts +1 -1
  22. package/dist/builtin-plugin/MangleExportsPlugin.d.ts +1 -1
  23. package/dist/builtin-plugin/ModuleConcatenationPlugin.d.ts +1 -1
  24. package/dist/builtin-plugin/NaturalChunkIdsPlugin.d.ts +1 -1
  25. package/dist/builtin-plugin/NaturalModuleIdsPlugin.d.ts +1 -1
  26. package/dist/builtin-plugin/SideEffectsFlagPlugin.d.ts +1 -1
  27. package/dist/builtin-plugin/SizeLimitsPlugin.d.ts +2 -2
  28. package/dist/builtin-plugin/SplitChunksPlugin.d.ts +1 -1
  29. package/dist/builtin-plugin/WorkerPlugin.d.ts +1 -1
  30. package/dist/builtin-plugin/rsc/RscServerPlugin.d.ts +8 -1
  31. package/dist/builtin-plugin/rsc/index.d.ts +6 -6
  32. package/dist/config/target.d.ts +1 -1
  33. package/dist/config/types.d.ts +4 -4
  34. package/dist/exports.d.ts +1 -1
  35. package/dist/index.js +35 -25
  36. package/dist/lib/CacheFacade.d.ts +1 -1
  37. package/dist/runtime/cssExtractHmr.d.ts +2 -2
  38. package/dist/runtime/moduleFederationDefaultRuntime.d.ts +1 -1
  39. package/dist/sharing/ConsumeSharedPlugin.d.ts +2 -2
  40. package/dist/sharing/ProvideSharedPlugin.d.ts +4 -4
  41. package/dist/sharing/SharePlugin.d.ts +4 -4
  42. package/dist/stats/statsFactoryUtils.d.ts +3 -3
  43. package/dist/util/comparators.d.ts +1 -1
  44. package/dist/util/createHash.d.ts +1 -1
  45. package/dist/util/identifier.d.ts +35 -8
  46. package/module.d.ts +6 -0
  47. package/package.json +8 -9
@@ -1111,7 +1111,7 @@ function patch (fs) {
1111
1111
 
1112
1112
  /***/ }),
1113
1113
 
1114
- /***/ 40:
1114
+ /***/ 600:
1115
1115
  /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
1116
1116
 
1117
1117
  "use strict";
@@ -1121,12 +1121,23 @@ function patch (fs) {
1121
1121
  */
1122
1122
 
1123
1123
 
1124
- const EventEmitter = (__nccwpck_require__(434).EventEmitter);
1125
- const fs = __nccwpck_require__(692);
1124
+ const { EventEmitter } = __nccwpck_require__(434);
1126
1125
  const path = __nccwpck_require__(928);
1126
+ const fs = __nccwpck_require__(692);
1127
+
1128
+ const watchEventSource = __nccwpck_require__(313);
1127
1129
 
1128
- const watchEventSource = __nccwpck_require__(729);
1130
+ /** @typedef {import("./index").IgnoredFunction} IgnoredFunction */
1131
+ /** @typedef {import("./index").EventType} EventType */
1132
+ /** @typedef {import("./index").TimeInfoEntries} TimeInfoEntries */
1133
+ /** @typedef {import("./index").Entry} Entry */
1134
+ /** @typedef {import("./index").ExistenceOnlyTimeEntry} ExistenceOnlyTimeEntry */
1135
+ /** @typedef {import("./index").OnlySafeTimeEntry} OnlySafeTimeEntry */
1136
+ /** @typedef {import("./index").EventMap} EventMap */
1137
+ /** @typedef {import("./getWatcherManager").WatcherManager} WatcherManager */
1138
+ /** @typedef {import("./watchEventSource").Watcher} EventSourceWatcher */
1129
1139
 
1140
+ /** @type {ExistenceOnlyTimeEntry} */
1130
1141
  const EXISTANCE_ONLY_TIME_ENTRY = Object.freeze({});
1131
1142
 
1132
1143
  let FS_ACCURACY = 2000;
@@ -1134,45 +1145,130 @@ let FS_ACCURACY = 2000;
1134
1145
  const IS_OSX = (__nccwpck_require__(857).platform)() === "darwin";
1135
1146
  const IS_WIN = (__nccwpck_require__(857).platform)() === "win32";
1136
1147
 
1137
- const WATCHPACK_POLLING = process.env.WATCHPACK_POLLING;
1148
+ const { WATCHPACK_POLLING } = process.env;
1138
1149
  const FORCE_POLLING =
1150
+ // @ts-expect-error avoid additional checks
1139
1151
  `${+WATCHPACK_POLLING}` === WATCHPACK_POLLING
1140
1152
  ? +WATCHPACK_POLLING
1141
- : !!WATCHPACK_POLLING && WATCHPACK_POLLING !== "false";
1153
+ : Boolean(WATCHPACK_POLLING) && WATCHPACK_POLLING !== "false";
1142
1154
 
1155
+ /**
1156
+ * @param {string} str string
1157
+ * @returns {string} lower cased string
1158
+ */
1143
1159
  function withoutCase(str) {
1144
1160
  return str.toLowerCase();
1145
1161
  }
1146
1162
 
1163
+ /**
1164
+ * @param {number} times times
1165
+ * @param {() => void} callback callback
1166
+ * @returns {() => void} result
1167
+ */
1147
1168
  function needCalls(times, callback) {
1148
- return function() {
1169
+ return function needCallsCallback() {
1149
1170
  if (--times === 0) {
1150
1171
  return callback();
1151
1172
  }
1152
1173
  };
1153
1174
  }
1154
1175
 
1176
+ /**
1177
+ * @param {Entry} entry entry
1178
+ */
1179
+ function fixupEntryAccuracy(entry) {
1180
+ if (entry.accuracy > FS_ACCURACY) {
1181
+ entry.safeTime = entry.safeTime - entry.accuracy + FS_ACCURACY;
1182
+ entry.accuracy = FS_ACCURACY;
1183
+ }
1184
+ }
1185
+
1186
+ /**
1187
+ * @param {number=} mtime mtime
1188
+ */
1189
+ function ensureFsAccuracy(mtime) {
1190
+ if (!mtime) return;
1191
+ if (FS_ACCURACY > 1 && mtime % 1 !== 0) FS_ACCURACY = 1;
1192
+ else if (FS_ACCURACY > 10 && mtime % 10 !== 0) FS_ACCURACY = 10;
1193
+ else if (FS_ACCURACY > 100 && mtime % 100 !== 0) FS_ACCURACY = 100;
1194
+ else if (FS_ACCURACY > 1000 && mtime % 1000 !== 0) FS_ACCURACY = 1000;
1195
+ }
1196
+
1197
+ /**
1198
+ * @typedef {object} FileWatcherEvents
1199
+ * @property {(type: EventType) => void} initial-missing initial missing event
1200
+ * @property {(mtime: number, type: EventType, initial: boolean) => void} change change event
1201
+ * @property {(type: EventType) => void} remove remove event
1202
+ * @property {() => void} closed closed event
1203
+ */
1204
+
1205
+ /**
1206
+ * @typedef {object} DirectoryWatcherEvents
1207
+ * @property {(type: EventType) => void} initial-missing initial missing event
1208
+ * @property {((file: string, mtime: number, type: EventType, initial: boolean) => void)} change change event
1209
+ * @property {(type: EventType) => void} remove remove event
1210
+ * @property {() => void} closed closed event
1211
+ */
1212
+
1213
+ /**
1214
+ * @template {EventMap} T
1215
+ * @extends {EventEmitter<{ [K in keyof T]: Parameters<T[K]> }>}
1216
+ */
1155
1217
  class Watcher extends EventEmitter {
1156
- constructor(directoryWatcher, filePath, startTime) {
1218
+ /**
1219
+ * @param {DirectoryWatcher} directoryWatcher a directory watcher
1220
+ * @param {string} target a target to watch
1221
+ * @param {number=} startTime start time
1222
+ */
1223
+ constructor(directoryWatcher, target, startTime) {
1157
1224
  super();
1158
1225
  this.directoryWatcher = directoryWatcher;
1159
- this.path = filePath;
1226
+ this.path = target;
1160
1227
  this.startTime = startTime && +startTime;
1161
1228
  }
1162
1229
 
1230
+ /**
1231
+ * @param {number} mtime mtime
1232
+ * @param {boolean} initial true when initial, otherwise false
1233
+ * @returns {boolean} true of start time less than mtile, otherwise false
1234
+ */
1163
1235
  checkStartTime(mtime, initial) {
1164
- const startTime = this.startTime;
1236
+ const { startTime } = this;
1165
1237
  if (typeof startTime !== "number") return !initial;
1166
1238
  return startTime <= mtime;
1167
1239
  }
1168
1240
 
1169
1241
  close() {
1242
+ // @ts-expect-error bad typing in EventEmitter
1170
1243
  this.emit("closed");
1171
1244
  }
1172
1245
  }
1173
1246
 
1247
+ /** @typedef {Set<string>} InitialScanRemoved */
1248
+
1249
+ /**
1250
+ * @typedef {object} WatchpackEvents
1251
+ * @property {(target: string, mtime: string, type: EventType, initial: boolean) => void} change change event
1252
+ * @property {() => void} closed closed event
1253
+ */
1254
+
1255
+ /**
1256
+ * @typedef {object} DirectoryWatcherOptions
1257
+ * @property {boolean=} followSymlinks true when need to resolve symlinks and watch symlink and real file, otherwise false
1258
+ * @property {IgnoredFunction=} ignored ignore some files from watching (glob pattern or regexp)
1259
+ * @property {number | boolean=} poll true when need to enable polling mode for watching, otherwise false
1260
+ */
1261
+
1262
+ /**
1263
+ * @extends {EventEmitter<{ [K in keyof WatchpackEvents]: Parameters<WatchpackEvents[K]> }>}
1264
+ */
1174
1265
  class DirectoryWatcher extends EventEmitter {
1175
- constructor(watcherManager, directoryPath, options) {
1266
+ /**
1267
+ * @param {WatcherManager} watcherManager a watcher manager
1268
+ * @param {string} directoryPath directory path
1269
+ * @param {DirectoryWatcherOptions=} options options
1270
+ */
1271
+ constructor(watcherManager, directoryPath, options = {}) {
1176
1272
  super();
1177
1273
  if (FORCE_POLLING) {
1178
1274
  options.poll = FORCE_POLLING;
@@ -1182,28 +1278,35 @@ class DirectoryWatcher extends EventEmitter {
1182
1278
  this.path = directoryPath;
1183
1279
  // safeTime is the point in time after which reading is safe to be unchanged
1184
1280
  // timestamp is a value that should be compared with another timestamp (mtime)
1185
- /** @type {Map<string, { safeTime: number, timestamp: number }} */
1281
+ /** @type {Map<string, Entry>} */
1186
1282
  this.files = new Map();
1187
1283
  /** @type {Map<string, number>} */
1188
1284
  this.filesWithoutCase = new Map();
1285
+ /** @type {Map<string, Watcher<DirectoryWatcherEvents> | boolean>} */
1189
1286
  this.directories = new Map();
1190
1287
  this.lastWatchEvent = 0;
1191
1288
  this.initialScan = true;
1192
1289
  this.ignored = options.ignored || (() => false);
1193
1290
  this.nestedWatching = false;
1291
+ /** @type {number | false} */
1194
1292
  this.polledWatching =
1195
1293
  typeof options.poll === "number"
1196
1294
  ? options.poll
1197
1295
  : options.poll
1198
- ? 5007
1199
- : false;
1296
+ ? 5007
1297
+ : false;
1298
+ /** @type {undefined | NodeJS.Timeout} */
1200
1299
  this.timeout = undefined;
1300
+ /** @type {null | InitialScanRemoved} */
1201
1301
  this.initialScanRemoved = new Set();
1302
+ /** @type {undefined | number} */
1202
1303
  this.initialScanFinished = undefined;
1203
- /** @type {Map<string, Set<Watcher>>} */
1304
+ /** @type {Map<string, Set<Watcher<DirectoryWatcherEvents> | Watcher<FileWatcherEvents>>>} */
1204
1305
  this.watchers = new Map();
1306
+ /** @type {Watcher<FileWatcherEvents> | null} */
1205
1307
  this.parentWatcher = null;
1206
1308
  this.refs = 0;
1309
+ /** @type {Map<string, boolean>} */
1207
1310
  this._activeEvents = new Map();
1208
1311
  this.closed = false;
1209
1312
  this.scanning = false;
@@ -1217,19 +1320,22 @@ class DirectoryWatcher extends EventEmitter {
1217
1320
  createWatcher() {
1218
1321
  try {
1219
1322
  if (this.polledWatching) {
1220
- this.watcher = {
1323
+ /** @type {EventSourceWatcher} */
1324
+ (this.watcher) = /** @type {EventSourceWatcher} */ ({
1221
1325
  close: () => {
1222
1326
  if (this.timeout) {
1223
1327
  clearTimeout(this.timeout);
1224
1328
  this.timeout = undefined;
1225
1329
  }
1226
- }
1227
- };
1330
+ },
1331
+ });
1228
1332
  } else {
1229
1333
  if (IS_OSX) {
1230
1334
  this.watchInParentDirectory();
1231
1335
  }
1232
- this.watcher = watchEventSource.watch(this.path);
1336
+ this.watcher =
1337
+ /** @type {EventSourceWatcher} */
1338
+ (watchEventSource.watch(this.path));
1233
1339
  this.watcher.on("change", this.onWatchEvent.bind(this));
1234
1340
  this.watcher.on("error", this.onWatcherError.bind(this));
1235
1341
  }
@@ -1238,6 +1344,11 @@ class DirectoryWatcher extends EventEmitter {
1238
1344
  }
1239
1345
  }
1240
1346
 
1347
+ /**
1348
+ * @template {(watcher: Watcher<EventMap>) => void} T
1349
+ * @param {string} path path
1350
+ * @param {T} fn function
1351
+ */
1241
1352
  forEachWatcher(path, fn) {
1242
1353
  const watchers = this.watchers.get(withoutCase(path));
1243
1354
  if (watchers !== undefined) {
@@ -1247,20 +1358,28 @@ class DirectoryWatcher extends EventEmitter {
1247
1358
  }
1248
1359
  }
1249
1360
 
1361
+ /**
1362
+ * @param {string} itemPath an item path
1363
+ * @param {boolean} initial true when initial, otherwise false
1364
+ * @param {EventType} type even type
1365
+ */
1250
1366
  setMissing(itemPath, initial, type) {
1251
1367
  if (this.initialScan) {
1252
- this.initialScanRemoved.add(itemPath);
1368
+ /** @type {InitialScanRemoved} */
1369
+ (this.initialScanRemoved).add(itemPath);
1253
1370
  }
1254
1371
 
1255
1372
  const oldDirectory = this.directories.get(itemPath);
1256
1373
  if (oldDirectory) {
1257
- if (this.nestedWatching) oldDirectory.close();
1374
+ if (this.nestedWatching) {
1375
+ /** @type {Watcher<DirectoryWatcherEvents>} */
1376
+ (oldDirectory).close();
1377
+ }
1258
1378
  this.directories.delete(itemPath);
1259
-
1260
- this.forEachWatcher(itemPath, w => w.emit("remove", type));
1379
+ this.forEachWatcher(itemPath, (w) => w.emit("remove", type));
1261
1380
  if (!initial) {
1262
- this.forEachWatcher(this.path, w =>
1263
- w.emit("change", itemPath, null, type, initial)
1381
+ this.forEachWatcher(this.path, (w) =>
1382
+ w.emit("change", itemPath, null, type, initial),
1264
1383
  );
1265
1384
  }
1266
1385
  }
@@ -1269,30 +1388,38 @@ class DirectoryWatcher extends EventEmitter {
1269
1388
  if (oldFile) {
1270
1389
  this.files.delete(itemPath);
1271
1390
  const key = withoutCase(itemPath);
1272
- const count = this.filesWithoutCase.get(key) - 1;
1391
+ const count = /** @type {number} */ (this.filesWithoutCase.get(key)) - 1;
1273
1392
  if (count <= 0) {
1274
1393
  this.filesWithoutCase.delete(key);
1275
- this.forEachWatcher(itemPath, w => w.emit("remove", type));
1394
+ this.forEachWatcher(itemPath, (w) => w.emit("remove", type));
1276
1395
  } else {
1277
1396
  this.filesWithoutCase.set(key, count);
1278
1397
  }
1279
1398
 
1280
1399
  if (!initial) {
1281
- this.forEachWatcher(this.path, w =>
1282
- w.emit("change", itemPath, null, type, initial)
1400
+ this.forEachWatcher(this.path, (w) =>
1401
+ w.emit("change", itemPath, null, type, initial),
1283
1402
  );
1284
1403
  }
1285
1404
  }
1286
1405
  }
1287
1406
 
1288
- setFileTime(filePath, mtime, initial, ignoreWhenEqual, type) {
1407
+ /**
1408
+ * @param {string} target a target to set file time
1409
+ * @param {number} mtime mtime
1410
+ * @param {boolean} initial true when initial, otherwise false
1411
+ * @param {boolean} ignoreWhenEqual true to ignore when equal, otherwise false
1412
+ * @param {EventType} type type
1413
+ */
1414
+ setFileTime(target, mtime, initial, ignoreWhenEqual, type) {
1289
1415
  const now = Date.now();
1290
1416
 
1291
- if (this.ignored(filePath)) return;
1417
+ if (this.ignored(target)) return;
1292
1418
 
1293
- const old = this.files.get(filePath);
1419
+ const old = this.files.get(target);
1294
1420
 
1295
- let safeTime, accuracy;
1421
+ let safeTime;
1422
+ let accuracy;
1296
1423
  if (initial) {
1297
1424
  safeTime = Math.min(now, mtime) + FS_ACCURACY;
1298
1425
  accuracy = FS_ACCURACY;
@@ -1311,14 +1438,14 @@ class DirectoryWatcher extends EventEmitter {
1311
1438
 
1312
1439
  if (ignoreWhenEqual && old && old.timestamp === mtime) return;
1313
1440
 
1314
- this.files.set(filePath, {
1441
+ this.files.set(target, {
1315
1442
  safeTime,
1316
1443
  accuracy,
1317
- timestamp: mtime
1444
+ timestamp: mtime,
1318
1445
  });
1319
1446
 
1320
1447
  if (!old) {
1321
- const key = withoutCase(filePath);
1448
+ const key = withoutCase(target);
1322
1449
  const count = this.filesWithoutCase.get(key);
1323
1450
  this.filesWithoutCase.set(key, (count || 0) + 1);
1324
1451
  if (count !== undefined) {
@@ -1330,27 +1457,33 @@ class DirectoryWatcher extends EventEmitter {
1330
1457
  this.doScan(false);
1331
1458
  }
1332
1459
 
1333
- this.forEachWatcher(filePath, w => {
1460
+ this.forEachWatcher(target, (w) => {
1334
1461
  if (!initial || w.checkStartTime(safeTime, initial)) {
1335
1462
  w.emit("change", mtime, type);
1336
1463
  }
1337
1464
  });
1338
1465
  } else if (!initial) {
1339
- this.forEachWatcher(filePath, w => w.emit("change", mtime, type));
1466
+ this.forEachWatcher(target, (w) => w.emit("change", mtime, type));
1340
1467
  }
1341
- this.forEachWatcher(this.path, w => {
1468
+ this.forEachWatcher(this.path, (w) => {
1342
1469
  if (!initial || w.checkStartTime(safeTime, initial)) {
1343
- w.emit("change", filePath, safeTime, type, initial);
1470
+ w.emit("change", target, safeTime, type, initial);
1344
1471
  }
1345
1472
  });
1346
1473
  }
1347
1474
 
1475
+ /**
1476
+ * @param {string} directoryPath directory path
1477
+ * @param {number} birthtime birthtime
1478
+ * @param {boolean} initial true when initial, otherwise false
1479
+ * @param {EventType} type even type
1480
+ */
1348
1481
  setDirectory(directoryPath, birthtime, initial, type) {
1349
1482
  if (this.ignored(directoryPath)) return;
1350
1483
  if (directoryPath === this.path) {
1351
1484
  if (!initial) {
1352
- this.forEachWatcher(this.path, w =>
1353
- w.emit("change", directoryPath, birthtime, type, initial)
1485
+ this.forEachWatcher(this.path, (w) =>
1486
+ w.emit("change", directoryPath, birthtime, type, initial),
1354
1487
  );
1355
1488
  }
1356
1489
  } else {
@@ -1364,19 +1497,14 @@ class DirectoryWatcher extends EventEmitter {
1364
1497
  this.directories.set(directoryPath, true);
1365
1498
  }
1366
1499
 
1367
- let safeTime;
1368
- if (initial) {
1369
- safeTime = Math.min(now, birthtime) + FS_ACCURACY;
1370
- } else {
1371
- safeTime = now;
1372
- }
1500
+ const safeTime = initial ? Math.min(now, birthtime) + FS_ACCURACY : now;
1373
1501
 
1374
- this.forEachWatcher(directoryPath, w => {
1502
+ this.forEachWatcher(directoryPath, (w) => {
1375
1503
  if (!initial || w.checkStartTime(safeTime, false)) {
1376
1504
  w.emit("change", birthtime, type);
1377
1505
  }
1378
1506
  });
1379
- this.forEachWatcher(this.path, w => {
1507
+ this.forEachWatcher(this.path, (w) => {
1380
1508
  if (!initial || w.checkStartTime(safeTime, initial)) {
1381
1509
  w.emit("change", directoryPath, safeTime, type, initial);
1382
1510
  }
@@ -1385,43 +1513,57 @@ class DirectoryWatcher extends EventEmitter {
1385
1513
  }
1386
1514
  }
1387
1515
 
1516
+ /**
1517
+ * @param {string} directoryPath directory path
1518
+ */
1388
1519
  createNestedWatcher(directoryPath) {
1389
1520
  const watcher = this.watcherManager.watchDirectory(directoryPath, 1);
1390
- watcher.on("change", (filePath, mtime, type, initial) => {
1391
- this.forEachWatcher(this.path, w => {
1521
+ watcher.on("change", (target, mtime, type, initial) => {
1522
+ this.forEachWatcher(this.path, (w) => {
1392
1523
  if (!initial || w.checkStartTime(mtime, initial)) {
1393
- w.emit("change", filePath, mtime, type, initial);
1524
+ w.emit("change", target, mtime, type, initial);
1394
1525
  }
1395
1526
  });
1396
1527
  });
1397
1528
  this.directories.set(directoryPath, watcher);
1398
1529
  }
1399
1530
 
1531
+ /**
1532
+ * @param {boolean} flag true when nested, otherwise false
1533
+ */
1400
1534
  setNestedWatching(flag) {
1401
- if (this.nestedWatching !== !!flag) {
1402
- this.nestedWatching = !!flag;
1535
+ if (this.nestedWatching !== Boolean(flag)) {
1536
+ this.nestedWatching = Boolean(flag);
1403
1537
  if (this.nestedWatching) {
1404
1538
  for (const directory of this.directories.keys()) {
1405
1539
  this.createNestedWatcher(directory);
1406
1540
  }
1407
1541
  } else {
1408
1542
  for (const [directory, watcher] of this.directories) {
1409
- watcher.close();
1543
+ /** @type {Watcher<DirectoryWatcherEvents>} */
1544
+ (watcher).close();
1410
1545
  this.directories.set(directory, true);
1411
1546
  }
1412
1547
  }
1413
1548
  }
1414
1549
  }
1415
1550
 
1416
- watch(filePath, startTime) {
1417
- const key = withoutCase(filePath);
1551
+ /**
1552
+ * @param {string} target a target to watch
1553
+ * @param {number=} startTime start time
1554
+ * @returns {Watcher<DirectoryWatcherEvents> | Watcher<FileWatcherEvents>} watcher
1555
+ */
1556
+ watch(target, startTime) {
1557
+ const key = withoutCase(target);
1418
1558
  let watchers = this.watchers.get(key);
1419
1559
  if (watchers === undefined) {
1420
1560
  watchers = new Set();
1421
1561
  this.watchers.set(key, watchers);
1422
1562
  }
1423
1563
  this.refs++;
1424
- const watcher = new Watcher(this, filePath, startTime);
1564
+ const watcher =
1565
+ /** @type {Watcher<DirectoryWatcherEvents> | Watcher<FileWatcherEvents>} */
1566
+ (new Watcher(this, target, startTime));
1425
1567
  watcher.on("closed", () => {
1426
1568
  if (--this.refs <= 0) {
1427
1569
  this.close();
@@ -1430,12 +1572,12 @@ class DirectoryWatcher extends EventEmitter {
1430
1572
  watchers.delete(watcher);
1431
1573
  if (watchers.size === 0) {
1432
1574
  this.watchers.delete(key);
1433
- if (this.path === filePath) this.setNestedWatching(false);
1575
+ if (this.path === target) this.setNestedWatching(false);
1434
1576
  }
1435
1577
  });
1436
1578
  watchers.add(watcher);
1437
1579
  let safeTime;
1438
- if (filePath === this.path) {
1580
+ if (target === this.path) {
1439
1581
  this.setNestedWatching(true);
1440
1582
  safeTime = this.lastWatchEvent;
1441
1583
  for (const entry of this.files.values()) {
@@ -1443,7 +1585,7 @@ class DirectoryWatcher extends EventEmitter {
1443
1585
  safeTime = Math.max(safeTime, entry.safeTime);
1444
1586
  }
1445
1587
  } else {
1446
- const entry = this.files.get(filePath);
1588
+ const entry = this.files.get(target);
1447
1589
  if (entry) {
1448
1590
  fixupEntryAccuracy(entry);
1449
1591
  safeTime = entry.safeTime;
@@ -1452,38 +1594,47 @@ class DirectoryWatcher extends EventEmitter {
1452
1594
  }
1453
1595
  }
1454
1596
  if (safeTime) {
1455
- if (safeTime >= startTime) {
1597
+ if (startTime && safeTime >= startTime) {
1456
1598
  process.nextTick(() => {
1457
1599
  if (this.closed) return;
1458
- if (filePath === this.path) {
1459
- watcher.emit(
1600
+ if (target === this.path) {
1601
+ /** @type {Watcher<DirectoryWatcherEvents>} */
1602
+ (watcher).emit(
1460
1603
  "change",
1461
- filePath,
1604
+ target,
1462
1605
  safeTime,
1463
1606
  "watch (outdated on attach)",
1464
- true
1607
+ true,
1465
1608
  );
1466
1609
  } else {
1467
- watcher.emit(
1610
+ /** @type {Watcher<FileWatcherEvents>} */
1611
+ (watcher).emit(
1468
1612
  "change",
1469
1613
  safeTime,
1470
1614
  "watch (outdated on attach)",
1471
- true
1615
+ true,
1472
1616
  );
1473
1617
  }
1474
1618
  });
1475
1619
  }
1476
1620
  } else if (this.initialScan) {
1477
- if (this.initialScanRemoved.has(filePath)) {
1621
+ if (
1622
+ /** @type {InitialScanRemoved} */
1623
+ (this.initialScanRemoved).has(target)
1624
+ ) {
1478
1625
  process.nextTick(() => {
1479
1626
  if (this.closed) return;
1480
1627
  watcher.emit("remove");
1481
1628
  });
1482
1629
  }
1483
1630
  } else if (
1484
- filePath !== this.path &&
1485
- !this.directories.has(filePath) &&
1486
- watcher.checkStartTime(this.initialScanFinished, false)
1631
+ target !== this.path &&
1632
+ !this.directories.has(target) &&
1633
+ watcher.checkStartTime(
1634
+ /** @type {number} */
1635
+ (this.initialScanFinished),
1636
+ false,
1637
+ )
1487
1638
  ) {
1488
1639
  process.nextTick(() => {
1489
1640
  if (this.closed) return;
@@ -1493,6 +1644,10 @@ class DirectoryWatcher extends EventEmitter {
1493
1644
  return watcher;
1494
1645
  }
1495
1646
 
1647
+ /**
1648
+ * @param {EventType} eventType event type
1649
+ * @param {string=} filename filename
1650
+ */
1496
1651
  onWatchEvent(eventType, filename) {
1497
1652
  if (this.closed) return;
1498
1653
  if (!filename) {
@@ -1504,15 +1659,15 @@ class DirectoryWatcher extends EventEmitter {
1504
1659
  return;
1505
1660
  }
1506
1661
 
1507
- const filePath = path.join(this.path, filename);
1508
- if (this.ignored(filePath)) return;
1662
+ const target = path.join(this.path, filename);
1663
+ if (this.ignored(target)) return;
1509
1664
 
1510
1665
  if (this._activeEvents.get(filename) === undefined) {
1511
1666
  this._activeEvents.set(filename, false);
1512
1667
  const checkStats = () => {
1513
1668
  if (this.closed) return;
1514
1669
  this._activeEvents.set(filename, false);
1515
- fs.lstat(filePath, (err, stats) => {
1670
+ fs.lstat(target, (err, stats) => {
1516
1671
  if (this.closed) return;
1517
1672
  if (this._activeEvents.get(filename) === true) {
1518
1673
  process.nextTick(checkStats);
@@ -1528,35 +1683,28 @@ class DirectoryWatcher extends EventEmitter {
1528
1683
  err.code !== "EBUSY"
1529
1684
  ) {
1530
1685
  this.onStatsError(err);
1531
- } else {
1532
- if (filename === path.basename(this.path)) {
1533
- // This may indicate that the directory itself was removed
1534
- if (!fs.existsSync(this.path)) {
1535
- this.onDirectoryRemoved("stat failed");
1536
- }
1537
- }
1686
+ } else if (
1687
+ filename === path.basename(this.path) && // This may indicate that the directory itself was removed
1688
+ !fs.existsSync(this.path)
1689
+ ) {
1690
+ this.onDirectoryRemoved("stat failed");
1538
1691
  }
1539
1692
  }
1540
1693
  this.lastWatchEvent = Date.now();
1541
1694
  if (!stats) {
1542
- this.setMissing(filePath, false, eventType);
1695
+ this.setMissing(target, false, eventType);
1543
1696
  } else if (stats.isDirectory()) {
1544
- this.setDirectory(
1545
- filePath,
1546
- +stats.birthtime || 1,
1547
- false,
1548
- eventType
1549
- );
1697
+ this.setDirectory(target, +stats.birthtime || 1, false, eventType);
1550
1698
  } else if (stats.isFile() || stats.isSymbolicLink()) {
1551
1699
  if (stats.mtime) {
1552
- ensureFsAccuracy(stats.mtime);
1700
+ ensureFsAccuracy(+stats.mtime);
1553
1701
  }
1554
1702
  this.setFileTime(
1555
- filePath,
1703
+ target,
1556
1704
  +stats.mtime || +stats.ctime || 1,
1557
1705
  false,
1558
1706
  false,
1559
- eventType
1707
+ eventType,
1560
1708
  );
1561
1709
  }
1562
1710
  });
@@ -1567,25 +1715,42 @@ class DirectoryWatcher extends EventEmitter {
1567
1715
  }
1568
1716
  }
1569
1717
 
1718
+ /**
1719
+ * @param {unknown=} err error
1720
+ */
1570
1721
  onWatcherError(err) {
1571
1722
  if (this.closed) return;
1572
1723
  if (err) {
1573
- if (err.code !== "EPERM" && err.code !== "ENOENT") {
1574
- console.error("Watchpack Error (watcher): " + err);
1724
+ if (
1725
+ /** @type {NodeJS.ErrnoException} */
1726
+ (err).code !== "EPERM" &&
1727
+ /** @type {NodeJS.ErrnoException} */
1728
+ (err).code !== "ENOENT"
1729
+ ) {
1730
+ // eslint-disable-next-line no-console
1731
+ console.error(`Watchpack Error (watcher): ${err}`);
1575
1732
  }
1576
1733
  this.onDirectoryRemoved("watch error");
1577
1734
  }
1578
1735
  }
1579
1736
 
1737
+ /**
1738
+ * @param {Error | NodeJS.ErrnoException=} err error
1739
+ */
1580
1740
  onStatsError(err) {
1581
1741
  if (err) {
1582
- console.error("Watchpack Error (stats): " + err);
1742
+ // eslint-disable-next-line no-console
1743
+ console.error(`Watchpack Error (stats): ${err}`);
1583
1744
  }
1584
1745
  }
1585
1746
 
1747
+ /**
1748
+ * @param {Error | NodeJS.ErrnoException=} err error
1749
+ */
1586
1750
  onScanError(err) {
1587
1751
  if (err) {
1588
- console.error("Watchpack Error (initial scan): " + err);
1752
+ // eslint-disable-next-line no-console
1753
+ console.error(`Watchpack Error (initial scan): ${err}`);
1589
1754
  }
1590
1755
  this.onScanFinished();
1591
1756
  }
@@ -1599,18 +1764,21 @@ class DirectoryWatcher extends EventEmitter {
1599
1764
  }
1600
1765
  }
1601
1766
 
1767
+ /**
1768
+ * @param {string} reason a reason
1769
+ */
1602
1770
  onDirectoryRemoved(reason) {
1603
1771
  if (this.watcher) {
1604
1772
  this.watcher.close();
1605
1773
  this.watcher = null;
1606
1774
  }
1607
1775
  this.watchInParentDirectory();
1608
- const type = `directory-removed (${reason})`;
1776
+ const type = /** @type {EventType} */ (`directory-removed (${reason})`);
1609
1777
  for (const directory of this.directories.keys()) {
1610
- this.setMissing(directory, null, type);
1778
+ this.setMissing(directory, false, type);
1611
1779
  }
1612
1780
  for (const file of this.files.keys()) {
1613
- this.setMissing(file, null, type);
1781
+ this.setMissing(file, false, type);
1614
1782
  }
1615
1783
  }
1616
1784
 
@@ -1622,7 +1790,8 @@ class DirectoryWatcher extends EventEmitter {
1622
1790
  if (path.dirname(parentDir) === parentDir) return;
1623
1791
 
1624
1792
  this.parentWatcher = this.watcherManager.watchFile(this.path, 1);
1625
- this.parentWatcher.on("change", (mtime, type) => {
1793
+ /** @type {Watcher<FileWatcherEvents>} */
1794
+ (this.parentWatcher).on("change", (mtime, type) => {
1626
1795
  if (this.closed) return;
1627
1796
 
1628
1797
  // On non-osx platforms we don't need this watcher to detect
@@ -1637,17 +1806,21 @@ class DirectoryWatcher extends EventEmitter {
1637
1806
  this.doScan(false);
1638
1807
 
1639
1808
  // directory was created so we emit an event
1640
- this.forEachWatcher(this.path, w =>
1641
- w.emit("change", this.path, mtime, type, false)
1809
+ this.forEachWatcher(this.path, (w) =>
1810
+ w.emit("change", this.path, mtime, type, false),
1642
1811
  );
1643
1812
  }
1644
1813
  });
1645
- this.parentWatcher.on("remove", () => {
1814
+ /** @type {Watcher<FileWatcherEvents>} */
1815
+ (this.parentWatcher).on("remove", () => {
1646
1816
  this.onDirectoryRemoved("parent directory removed");
1647
1817
  });
1648
1818
  }
1649
1819
  }
1650
1820
 
1821
+ /**
1822
+ * @param {boolean} initial true when initial, otherwise false
1823
+ */
1651
1824
  doScan(initial) {
1652
1825
  if (this.scanning) {
1653
1826
  if (this.scanAgain) {
@@ -1681,7 +1854,7 @@ class DirectoryWatcher extends EventEmitter {
1681
1854
  if (watcher.checkStartTime(this.initialScanFinished, false)) {
1682
1855
  watcher.emit(
1683
1856
  "initial-missing",
1684
- "scan (parent directory missing in initial scan)"
1857
+ "scan (parent directory missing in initial scan)",
1685
1858
  );
1686
1859
  }
1687
1860
  }
@@ -1696,7 +1869,7 @@ class DirectoryWatcher extends EventEmitter {
1696
1869
  return;
1697
1870
  }
1698
1871
  const itemPaths = new Set(
1699
- items.map(item => path.join(this.path, item.normalize("NFC")))
1872
+ items.map((item) => path.join(this.path, item.normalize("NFC"))),
1700
1873
  );
1701
1874
  for (const file of this.files.keys()) {
1702
1875
  if (!itemPaths.has(file)) {
@@ -1730,7 +1903,7 @@ class DirectoryWatcher extends EventEmitter {
1730
1903
  if (watcher.checkStartTime(this.initialScanFinished, false)) {
1731
1904
  watcher.emit(
1732
1905
  "initial-missing",
1733
- "scan (missing in initial scan)"
1906
+ "scan (missing in initial scan)",
1734
1907
  );
1735
1908
  }
1736
1909
  }
@@ -1756,7 +1929,7 @@ class DirectoryWatcher extends EventEmitter {
1756
1929
  // TODO https://github.com/libuv/libuv/pull/4566
1757
1930
  (err2.code === "EINVAL" && IS_WIN)
1758
1931
  ) {
1759
- this.setMissing(itemPath, initial, "scan (" + err2.code + ")");
1932
+ this.setMissing(itemPath, initial, `scan (${err2.code})`);
1760
1933
  } else {
1761
1934
  this.onScanError(err2);
1762
1935
  }
@@ -1765,23 +1938,25 @@ class DirectoryWatcher extends EventEmitter {
1765
1938
  }
1766
1939
  if (stats.isFile() || stats.isSymbolicLink()) {
1767
1940
  if (stats.mtime) {
1768
- ensureFsAccuracy(stats.mtime);
1941
+ ensureFsAccuracy(+stats.mtime);
1769
1942
  }
1770
1943
  this.setFileTime(
1771
1944
  itemPath,
1772
1945
  +stats.mtime || +stats.ctime || 1,
1773
1946
  initial,
1774
1947
  true,
1775
- "scan (file)"
1948
+ "scan (file)",
1949
+ );
1950
+ } else if (
1951
+ stats.isDirectory() &&
1952
+ (!initial || !this.directories.has(itemPath))
1953
+ ) {
1954
+ this.setDirectory(
1955
+ itemPath,
1956
+ +stats.birthtime || 1,
1957
+ initial,
1958
+ "scan (dir)",
1776
1959
  );
1777
- } else if (stats.isDirectory()) {
1778
- if (!initial || !this.directories.has(itemPath))
1779
- this.setDirectory(
1780
- itemPath,
1781
- +stats.birthtime || 1,
1782
- initial,
1783
- "scan (dir)"
1784
- );
1785
1960
  }
1786
1961
  itemFinished();
1787
1962
  });
@@ -1791,6 +1966,9 @@ class DirectoryWatcher extends EventEmitter {
1791
1966
  });
1792
1967
  }
1793
1968
 
1969
+ /**
1970
+ * @returns {Record<string, number>} times
1971
+ */
1794
1972
  getTimes() {
1795
1973
  const obj = Object.create(null);
1796
1974
  let safeTime = this.lastWatchEvent;
@@ -1801,7 +1979,9 @@ class DirectoryWatcher extends EventEmitter {
1801
1979
  }
1802
1980
  if (this.nestedWatching) {
1803
1981
  for (const w of this.directories.values()) {
1804
- const times = w.directoryWatcher.getTimes();
1982
+ const times =
1983
+ /** @type {Watcher<DirectoryWatcherEvents>} */
1984
+ (w).directoryWatcher.getTimes();
1805
1985
  for (const file of Object.keys(times)) {
1806
1986
  const time = times[file];
1807
1987
  safeTime = Math.max(safeTime, time);
@@ -1813,7 +1993,7 @@ class DirectoryWatcher extends EventEmitter {
1813
1993
  if (!this.initialScan) {
1814
1994
  for (const watchers of this.watchers.values()) {
1815
1995
  for (const watcher of watchers) {
1816
- const path = watcher.path;
1996
+ const { path } = watcher;
1817
1997
  if (!Object.prototype.hasOwnProperty.call(obj, path)) {
1818
1998
  obj[path] = null;
1819
1999
  }
@@ -1823,6 +2003,11 @@ class DirectoryWatcher extends EventEmitter {
1823
2003
  return obj;
1824
2004
  }
1825
2005
 
2006
+ /**
2007
+ * @param {TimeInfoEntries} fileTimestamps file timestamps
2008
+ * @param {TimeInfoEntries} directoryTimestamps directory timestamps
2009
+ * @returns {number} safe time
2010
+ */
1826
2011
  collectTimeInfoEntries(fileTimestamps, directoryTimestamps) {
1827
2012
  let safeTime = this.lastWatchEvent;
1828
2013
  for (const [file, entry] of this.files) {
@@ -1834,23 +2019,25 @@ class DirectoryWatcher extends EventEmitter {
1834
2019
  for (const w of this.directories.values()) {
1835
2020
  safeTime = Math.max(
1836
2021
  safeTime,
1837
- w.directoryWatcher.collectTimeInfoEntries(
2022
+ /** @type {Watcher<DirectoryWatcherEvents>} */
2023
+ (w).directoryWatcher.collectTimeInfoEntries(
1838
2024
  fileTimestamps,
1839
- directoryTimestamps
1840
- )
2025
+ directoryTimestamps,
2026
+ ),
1841
2027
  );
1842
2028
  }
1843
2029
  fileTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY);
1844
2030
  directoryTimestamps.set(this.path, {
1845
- safeTime
2031
+ safeTime,
1846
2032
  });
1847
2033
  } else {
1848
2034
  for (const dir of this.directories.keys()) {
1849
2035
  // No additional info about this directory
1850
2036
  // but maybe another DirectoryWatcher has info
1851
2037
  fileTimestamps.set(dir, EXISTANCE_ONLY_TIME_ENTRY);
1852
- if (!directoryTimestamps.has(dir))
2038
+ if (!directoryTimestamps.has(dir)) {
1853
2039
  directoryTimestamps.set(dir, EXISTANCE_ONLY_TIME_ENTRY);
2040
+ }
1854
2041
  }
1855
2042
  fileTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY);
1856
2043
  directoryTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY);
@@ -1858,7 +2045,7 @@ class DirectoryWatcher extends EventEmitter {
1858
2045
  if (!this.initialScan) {
1859
2046
  for (const watchers of this.watchers.values()) {
1860
2047
  for (const watcher of watchers) {
1861
- const path = watcher.path;
2048
+ const { path } = watcher;
1862
2049
  if (!fileTimestamps.has(path)) {
1863
2050
  fileTimestamps.set(path, null);
1864
2051
  }
@@ -1877,7 +2064,8 @@ class DirectoryWatcher extends EventEmitter {
1877
2064
  }
1878
2065
  if (this.nestedWatching) {
1879
2066
  for (const w of this.directories.values()) {
1880
- w.close();
2067
+ /** @type {Watcher<DirectoryWatcherEvents>} */
2068
+ (w).close();
1881
2069
  }
1882
2070
  this.directories.clear();
1883
2071
  }
@@ -1891,26 +2079,12 @@ class DirectoryWatcher extends EventEmitter {
1891
2079
 
1892
2080
  module.exports = DirectoryWatcher;
1893
2081
  module.exports.EXISTANCE_ONLY_TIME_ENTRY = EXISTANCE_ONLY_TIME_ENTRY;
1894
-
1895
- function fixupEntryAccuracy(entry) {
1896
- if (entry.accuracy > FS_ACCURACY) {
1897
- entry.safeTime = entry.safeTime - entry.accuracy + FS_ACCURACY;
1898
- entry.accuracy = FS_ACCURACY;
1899
- }
1900
- }
1901
-
1902
- function ensureFsAccuracy(mtime) {
1903
- if (!mtime) return;
1904
- if (FS_ACCURACY > 1 && mtime % 1 !== 0) FS_ACCURACY = 1;
1905
- else if (FS_ACCURACY > 10 && mtime % 10 !== 0) FS_ACCURACY = 10;
1906
- else if (FS_ACCURACY > 100 && mtime % 100 !== 0) FS_ACCURACY = 100;
1907
- else if (FS_ACCURACY > 1000 && mtime % 1000 !== 0) FS_ACCURACY = 1000;
1908
- }
2082
+ module.exports.Watcher = Watcher;
1909
2083
 
1910
2084
 
1911
2085
  /***/ }),
1912
2086
 
1913
- /***/ 751:
2087
+ /***/ 703:
1914
2088
  /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
1915
2089
 
1916
2090
  "use strict";
@@ -1931,12 +2105,13 @@ if (process.platform === "win32") EXPECTED_ERRORS.add("UNKNOWN");
1931
2105
 
1932
2106
  class LinkResolver {
1933
2107
  constructor() {
2108
+ /** @type {Map<string, readonly string[]>} */
1934
2109
  this.cache = new Map();
1935
2110
  }
1936
2111
 
1937
2112
  /**
1938
2113
  * @param {string} file path to file or directory
1939
- * @returns {string[]} array of file and all symlinks contributed in the resolving process (first item is the resolved file)
2114
+ * @returns {readonly string[]} array of file and all symlinks contributed in the resolving process (first item is the resolved file)
1940
2115
  */
1941
2116
  resolve(file) {
1942
2117
  const cacheEntry = this.cache.get(file);
@@ -1981,17 +2156,18 @@ class LinkResolver {
1981
2156
  for (let i = 1; i < parentResolved.length; i++) {
1982
2157
  resultSet.add(parentResolved[i]);
1983
2158
  }
1984
- result = Object.freeze(Array.from(resultSet));
2159
+ result = Object.freeze([...resultSet]);
1985
2160
  } else if (parentResolved.length > 1) {
1986
2161
  // we have links in the parent but not for the link content location
1987
- result = parentResolved.slice();
2162
+ result = [...parentResolved];
2163
+ // eslint-disable-next-line prefer-destructuring
1988
2164
  result[0] = linkResolved[0];
1989
2165
  // add the link
1990
2166
  result.push(realFile);
1991
2167
  Object.freeze(result);
1992
2168
  } else if (linkResolved.length > 1) {
1993
2169
  // we can return the link content location result
1994
- result = linkResolved.slice();
2170
+ result = [...linkResolved];
1995
2171
  // add the link
1996
2172
  result.push(realFile);
1997
2173
  Object.freeze(result);
@@ -2002,17 +2178,21 @@ class LinkResolver {
2002
2178
  // the resolve real location
2003
2179
  linkResolved[0],
2004
2180
  // add the link
2005
- realFile
2181
+ realFile,
2006
2182
  ]);
2007
2183
  }
2008
2184
  this.cache.set(file, result);
2009
2185
  return result;
2010
- } catch (e) {
2011
- if (!EXPECTED_ERRORS.has(e.code)) {
2012
- throw e;
2186
+ } catch (err) {
2187
+ if (
2188
+ /** @type {NodeJS.ErrnoException} */
2189
+ (err).code &&
2190
+ !EXPECTED_ERRORS.has(/** @type {NodeJS.ErrnoException} */ (err).code)
2191
+ ) {
2192
+ throw err;
2013
2193
  }
2014
2194
  // no link
2015
- const result = parentResolved.slice();
2195
+ const result = [...parentResolved];
2016
2196
  result[0] = realFile;
2017
2197
  Object.freeze(result);
2018
2198
  this.cache.set(file, result);
@@ -2020,12 +2200,13 @@ class LinkResolver {
2020
2200
  }
2021
2201
  }
2022
2202
  }
2203
+
2023
2204
  module.exports = LinkResolver;
2024
2205
 
2025
2206
 
2026
2207
  /***/ }),
2027
2208
 
2028
- /***/ 510:
2209
+ /***/ 254:
2029
2210
  /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
2030
2211
 
2031
2212
  "use strict";
@@ -2036,14 +2217,31 @@ module.exports = LinkResolver;
2036
2217
 
2037
2218
 
2038
2219
  const path = __nccwpck_require__(928);
2039
- const DirectoryWatcher = __nccwpck_require__(40);
2220
+ const DirectoryWatcher = __nccwpck_require__(600);
2221
+
2222
+ /** @typedef {import("./index").EventMap} EventMap */
2223
+ /** @typedef {import("./DirectoryWatcher").DirectoryWatcherOptions} DirectoryWatcherOptions */
2224
+ /** @typedef {import("./DirectoryWatcher").DirectoryWatcherEvents} DirectoryWatcherEvents */
2225
+ /** @typedef {import("./DirectoryWatcher").FileWatcherEvents} FileWatcherEvents */
2226
+ /**
2227
+ * @template {EventMap} T
2228
+ * @typedef {import("./DirectoryWatcher").Watcher<T>} Watcher
2229
+ */
2040
2230
 
2041
2231
  class WatcherManager {
2042
- constructor(options) {
2232
+ /**
2233
+ * @param {DirectoryWatcherOptions=} options options
2234
+ */
2235
+ constructor(options = {}) {
2043
2236
  this.options = options;
2237
+ /** @type {Map<string, DirectoryWatcher>} */
2044
2238
  this.directoryWatchers = new Map();
2045
2239
  }
2046
2240
 
2241
+ /**
2242
+ * @param {string} directory a directory
2243
+ * @returns {DirectoryWatcher} a directory watcher
2244
+ */
2047
2245
  getDirectoryWatcher(directory) {
2048
2246
  const watcher = this.directoryWatchers.get(directory);
2049
2247
  if (watcher === undefined) {
@@ -2057,23 +2255,34 @@ class WatcherManager {
2057
2255
  return watcher;
2058
2256
  }
2059
2257
 
2060
- watchFile(p, startTime) {
2061
- const directory = path.dirname(p);
2062
- if (directory === p) return null;
2063
- return this.getDirectoryWatcher(directory).watch(p, startTime);
2258
+ /**
2259
+ * @param {string} file file
2260
+ * @param {number=} startTime start time
2261
+ * @returns {Watcher<FileWatcherEvents> | null} watcher or null if file has no directory
2262
+ */
2263
+ watchFile(file, startTime) {
2264
+ const directory = path.dirname(file);
2265
+ if (directory === file) return null;
2266
+ return this.getDirectoryWatcher(directory).watch(file, startTime);
2064
2267
  }
2065
2268
 
2269
+ /**
2270
+ * @param {string} directory directory
2271
+ * @param {number=} startTime start time
2272
+ * @returns {Watcher<DirectoryWatcherEvents>} watcher
2273
+ */
2066
2274
  watchDirectory(directory, startTime) {
2067
2275
  return this.getDirectoryWatcher(directory).watch(directory, startTime);
2068
2276
  }
2069
2277
  }
2070
2278
 
2071
2279
  const watcherManagers = new WeakMap();
2280
+
2072
2281
  /**
2073
- * @param {object} options options
2282
+ * @param {DirectoryWatcherOptions} options options
2074
2283
  * @returns {WatcherManager} the watcher manager
2075
2284
  */
2076
- module.exports = options => {
2285
+ module.exports = (options) => {
2077
2286
  const watcherManager = watcherManagers.get(options);
2078
2287
  if (watcherManager !== undefined) return watcherManager;
2079
2288
  const newWatcherManager = new WatcherManager(options);
@@ -2085,7 +2294,7 @@ module.exports.WatcherManager = WatcherManager;
2085
2294
 
2086
2295
  /***/ }),
2087
2296
 
2088
- /***/ 864:
2297
+ /***/ 17:
2089
2298
  /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
2090
2299
 
2091
2300
  "use strict";
@@ -2095,522 +2304,705 @@ module.exports.WatcherManager = WatcherManager;
2095
2304
  */
2096
2305
 
2097
2306
 
2098
- const path = __nccwpck_require__(928);
2307
+ const { EventEmitter } = __nccwpck_require__(434);
2308
+ const globToRegExp = __nccwpck_require__(428);
2309
+ const LinkResolver = __nccwpck_require__(703);
2310
+ const getWatcherManager = __nccwpck_require__(254);
2311
+ const watchEventSource = __nccwpck_require__(313);
2312
+
2313
+ /** @typedef {import("./getWatcherManager").WatcherManager} WatcherManager */
2314
+ /** @typedef {import("./DirectoryWatcher")} DirectoryWatcher */
2315
+ /** @typedef {import("./DirectoryWatcher").DirectoryWatcherEvents} DirectoryWatcherEvents */
2316
+ /** @typedef {import("./DirectoryWatcher").FileWatcherEvents} FileWatcherEvents */
2317
+
2318
+ // eslint-disable-next-line jsdoc/reject-any-type
2319
+ /** @typedef {Record<string, (...args: any[]) => any>} EventMap */
2099
2320
 
2100
2321
  /**
2101
- * @template T
2102
- * @typedef {Object} TreeNode
2103
- * @property {string} filePath
2104
- * @property {TreeNode} parent
2105
- * @property {TreeNode[]} children
2106
- * @property {number} entries
2107
- * @property {boolean} active
2108
- * @property {T[] | T | undefined} value
2322
+ * @template {EventMap} T
2323
+ * @typedef {import("./DirectoryWatcher").Watcher<T>} Watcher
2109
2324
  */
2110
2325
 
2326
+ /** @typedef {(item: string) => boolean} IgnoredFunction */
2327
+ /** @typedef {string[] | RegExp | string | IgnoredFunction} Ignored */
2328
+
2111
2329
  /**
2112
- * @template T
2113
- * @param {Map<string, T[] | T} plan
2114
- * @param {number} limit
2115
- * @returns {Map<string, Map<T, string>>} the new plan
2330
+ * @typedef {object} WatcherOptions
2331
+ * @property {boolean=} followSymlinks true when need to resolve symlinks and watch symlink and real file, otherwise false
2332
+ * @property {Ignored=} ignored ignore some files from watching (glob pattern or regexp)
2333
+ * @property {number | boolean=} poll true when need to enable polling mode for watching, otherwise false
2116
2334
  */
2117
- module.exports = (plan, limit) => {
2118
- const treeMap = new Map();
2119
- // Convert to tree
2120
- for (const [filePath, value] of plan) {
2121
- treeMap.set(filePath, {
2122
- filePath,
2123
- parent: undefined,
2124
- children: undefined,
2125
- entries: 1,
2126
- active: true,
2127
- value
2128
- });
2129
- }
2130
- let currentCount = treeMap.size;
2131
- // Create parents and calculate sum of entries
2132
- for (const node of treeMap.values()) {
2133
- const parentPath = path.dirname(node.filePath);
2134
- if (parentPath !== node.filePath) {
2135
- let parent = treeMap.get(parentPath);
2136
- if (parent === undefined) {
2137
- parent = {
2138
- filePath: parentPath,
2139
- parent: undefined,
2140
- children: [node],
2141
- entries: node.entries,
2142
- active: false,
2143
- value: undefined
2144
- };
2145
- treeMap.set(parentPath, parent);
2146
- node.parent = parent;
2147
- } else {
2148
- node.parent = parent;
2149
- if (parent.children === undefined) {
2150
- parent.children = [node];
2151
- } else {
2152
- parent.children.push(node);
2153
- }
2154
- do {
2155
- parent.entries += node.entries;
2156
- parent = parent.parent;
2157
- } while (parent);
2158
- }
2159
- }
2160
- }
2161
- // Reduce until limit reached
2162
- while (currentCount > limit) {
2163
- // Select node that helps reaching the limit most effectively without overmerging
2164
- const overLimit = currentCount - limit;
2165
- let bestNode = undefined;
2166
- let bestCost = Infinity;
2167
- for (const node of treeMap.values()) {
2168
- if (node.entries <= 1 || !node.children || !node.parent) continue;
2169
- if (node.children.length === 0) continue;
2170
- if (node.children.length === 1 && !node.value) continue;
2171
- // Try to select the node with has just a bit more entries than we need to reduce
2172
- // When just a bit more is over 30% over the limit,
2173
- // also consider just a bit less entries then we need to reduce
2174
- const cost =
2175
- node.entries - 1 >= overLimit
2176
- ? node.entries - 1 - overLimit
2177
- : overLimit - node.entries + 1 + limit * 0.3;
2178
- if (cost < bestCost) {
2179
- bestNode = node;
2180
- bestCost = cost;
2181
- }
2182
- }
2183
- if (!bestNode) break;
2184
- // Merge all children
2185
- const reduction = bestNode.entries - 1;
2186
- bestNode.active = true;
2187
- bestNode.entries = 1;
2188
- currentCount -= reduction;
2189
- let parent = bestNode.parent;
2190
- while (parent) {
2191
- parent.entries -= reduction;
2192
- parent = parent.parent;
2193
- }
2194
- const queue = new Set(bestNode.children);
2195
- for (const node of queue) {
2196
- node.active = false;
2197
- node.entries = 0;
2198
- if (node.children) {
2199
- for (const child of node.children) queue.add(child);
2200
- }
2201
- }
2202
- }
2203
- // Write down new plan
2204
- const newPlan = new Map();
2205
- for (const rootNode of treeMap.values()) {
2206
- if (!rootNode.active) continue;
2207
- const map = new Map();
2208
- const queue = new Set([rootNode]);
2209
- for (const node of queue) {
2210
- if (node.active && node !== rootNode) continue;
2211
- if (node.value) {
2212
- if (Array.isArray(node.value)) {
2213
- for (const item of node.value) {
2214
- map.set(item, node.filePath);
2215
- }
2216
- } else {
2217
- map.set(node.value, node.filePath);
2218
- }
2219
- }
2220
- if (node.children) {
2221
- for (const child of node.children) {
2222
- queue.add(child);
2223
- }
2224
- }
2225
- }
2226
- newPlan.set(rootNode.filePath, map);
2227
- }
2228
- return newPlan;
2229
- };
2230
2335
 
2336
+ /** @typedef {WatcherOptions & { aggregateTimeout?: number }} WatchOptions */
2231
2337
 
2232
- /***/ }),
2338
+ /**
2339
+ * @typedef {object} NormalizedWatchOptions
2340
+ * @property {boolean} followSymlinks true when need to resolve symlinks and watch symlink and real file, otherwise false
2341
+ * @property {IgnoredFunction} ignored ignore some files from watching (glob pattern or regexp)
2342
+ * @property {number | boolean=} poll true when need to enable polling mode for watching, otherwise false
2343
+ */
2233
2344
 
2234
- /***/ 729:
2235
- /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
2345
+ /** @typedef {`scan (${string})` | "change" | "rename" | `watch ${string}` | `directory-removed ${string}`} EventType */
2346
+ /** @typedef {{ safeTime: number, timestamp: number, accuracy: number }} Entry */
2347
+ /** @typedef {{ safeTime: number }} OnlySafeTimeEntry */
2348
+ // eslint-disable-next-line jsdoc/ts-no-empty-object-type
2349
+ /** @typedef {{}} ExistenceOnlyTimeEntry */
2350
+ /** @typedef {Map<string, Entry | OnlySafeTimeEntry | ExistenceOnlyTimeEntry | null>} TimeInfoEntries */
2351
+ /** @typedef {Set<string>} Changes */
2352
+ /** @typedef {Set<string>} Removals */
2353
+ /** @typedef {{ changes: Changes, removals: Removals }} Aggregated */
2354
+ /** @typedef {{ files?: Iterable<string>, directories?: Iterable<string>, missing?: Iterable<string>, startTime?: number }} WatchMethodOptions */
2355
+ /** @typedef {Record<string, number>} Times */
2236
2356
 
2237
- "use strict";
2238
- /*
2239
- MIT License http://www.opensource.org/licenses/mit-license.php
2240
- Author Tobias Koppers @sokra
2241
- */
2357
+ /**
2358
+ * @param {MapIterator<WatchpackFileWatcher> | MapIterator<WatchpackDirectoryWatcher>} watchers watchers
2359
+ * @param {Set<DirectoryWatcher>} set set
2360
+ */
2361
+ function addWatchersToSet(watchers, set) {
2362
+ for (const ww of watchers) {
2363
+ const w = ww.watcher;
2364
+ if (!set.has(w.directoryWatcher)) {
2365
+ set.add(w.directoryWatcher);
2366
+ }
2367
+ }
2368
+ }
2242
2369
 
2370
+ /**
2371
+ * @param {string} ignored ignored
2372
+ * @returns {string | undefined} resolved global to regexp
2373
+ */
2374
+ const stringToRegexp = (ignored) => {
2375
+ if (ignored.length === 0) {
2376
+ return;
2377
+ }
2378
+ const { source } = globToRegExp(ignored, { globstar: true, extended: true });
2379
+ return `${source.slice(0, -1)}(?:$|\\/)`;
2380
+ };
2243
2381
 
2244
- const fs = __nccwpck_require__(896);
2245
- const path = __nccwpck_require__(928);
2246
- const { EventEmitter } = __nccwpck_require__(434);
2247
- const reducePlan = __nccwpck_require__(864);
2248
-
2249
- const IS_OSX = (__nccwpck_require__(857).platform)() === "darwin";
2250
- const IS_WIN = (__nccwpck_require__(857).platform)() === "win32";
2251
- const SUPPORTS_RECURSIVE_WATCHING = IS_OSX || IS_WIN;
2252
-
2253
- // Use 20 for OSX to make `FSWatcher.close` faster
2254
- // https://github.com/nodejs/node/issues/29949
2255
- const watcherLimit =
2256
- +process.env.WATCHPACK_WATCHER_LIMIT || (IS_OSX ? 20 : 10000);
2257
-
2258
- const recursiveWatcherLogging = !!process.env
2259
- .WATCHPACK_RECURSIVE_WATCHER_LOGGING;
2260
-
2261
- let isBatch = false;
2262
- let watcherCount = 0;
2382
+ /**
2383
+ * @param {Ignored=} ignored ignored
2384
+ * @returns {(item: string) => boolean} ignored to function
2385
+ */
2386
+ const ignoredToFunction = (ignored) => {
2387
+ if (Array.isArray(ignored)) {
2388
+ const stringRegexps = ignored.map((i) => stringToRegexp(i)).filter(Boolean);
2389
+ if (stringRegexps.length === 0) {
2390
+ return () => false;
2391
+ }
2392
+ const regexp = new RegExp(stringRegexps.join("|"));
2393
+ return (item) => regexp.test(item.replace(/\\/g, "/"));
2394
+ } else if (typeof ignored === "string") {
2395
+ const stringRegexp = stringToRegexp(ignored);
2396
+ if (!stringRegexp) {
2397
+ return () => false;
2398
+ }
2399
+ const regexp = new RegExp(stringRegexp);
2400
+ return (item) => regexp.test(item.replace(/\\/g, "/"));
2401
+ } else if (ignored instanceof RegExp) {
2402
+ return (item) => ignored.test(item.replace(/\\/g, "/"));
2403
+ } else if (typeof ignored === "function") {
2404
+ return ignored;
2405
+ } else if (ignored) {
2406
+ throw new Error(`Invalid option for 'ignored': ${ignored}`);
2407
+ } else {
2408
+ return () => false;
2409
+ }
2410
+ };
2263
2411
 
2264
- /** @type {Map<Watcher, string>} */
2265
- const pendingWatchers = new Map();
2412
+ /**
2413
+ * @param {WatchOptions} options options
2414
+ * @returns {NormalizedWatchOptions} normalized options
2415
+ */
2416
+ const normalizeOptions = (options) => ({
2417
+ followSymlinks: Boolean(options.followSymlinks),
2418
+ ignored: ignoredToFunction(options.ignored),
2419
+ poll: options.poll,
2420
+ });
2266
2421
 
2267
- /** @type {Map<string, RecursiveWatcher>} */
2268
- const recursiveWatchers = new Map();
2422
+ const normalizeCache = new WeakMap();
2423
+ /**
2424
+ * @param {WatchOptions} options options
2425
+ * @returns {NormalizedWatchOptions} normalized options
2426
+ */
2427
+ const cachedNormalizeOptions = (options) => {
2428
+ const cacheEntry = normalizeCache.get(options);
2429
+ if (cacheEntry !== undefined) return cacheEntry;
2430
+ const normalized = normalizeOptions(options);
2431
+ normalizeCache.set(options, normalized);
2432
+ return normalized;
2433
+ };
2269
2434
 
2270
- /** @type {Map<string, DirectWatcher>} */
2271
- const directWatchers = new Map();
2435
+ class WatchpackFileWatcher {
2436
+ /**
2437
+ * @param {Watchpack} watchpack watchpack
2438
+ * @param {Watcher<FileWatcherEvents>} watcher watcher
2439
+ * @param {string | string[]} files files
2440
+ */
2441
+ constructor(watchpack, watcher, files) {
2442
+ /** @type {string[]} */
2443
+ this.files = Array.isArray(files) ? files : [files];
2444
+ this.watcher = watcher;
2445
+ watcher.on("initial-missing", (type) => {
2446
+ for (const file of this.files) {
2447
+ if (!watchpack._missing.has(file)) {
2448
+ watchpack._onRemove(file, file, type);
2449
+ }
2450
+ }
2451
+ });
2452
+ watcher.on("change", (mtime, type, _initial) => {
2453
+ for (const file of this.files) {
2454
+ watchpack._onChange(file, mtime, file, type);
2455
+ }
2456
+ });
2457
+ watcher.on("remove", (type) => {
2458
+ for (const file of this.files) {
2459
+ watchpack._onRemove(file, file, type);
2460
+ }
2461
+ });
2462
+ }
2272
2463
 
2273
- /** @type {Map<Watcher, RecursiveWatcher | DirectWatcher>} */
2274
- const underlyingWatcher = new Map();
2464
+ /**
2465
+ * @param {string | string[]} files files
2466
+ */
2467
+ update(files) {
2468
+ if (!Array.isArray(files)) {
2469
+ if (this.files.length !== 1) {
2470
+ this.files = [files];
2471
+ } else if (this.files[0] !== files) {
2472
+ this.files[0] = files;
2473
+ }
2474
+ } else {
2475
+ this.files = files;
2476
+ }
2477
+ }
2275
2478
 
2276
- function createEPERMError(filePath) {
2277
- const error = new Error(`Operation not permitted: ${filePath}`);
2278
- error.code = "EPERM";
2279
- return error;
2479
+ close() {
2480
+ this.watcher.close();
2481
+ }
2280
2482
  }
2281
2483
 
2282
- function createHandleChangeEvent(watcher, filePath, handleChangeEvent) {
2283
- return (type, filename) => {
2284
- // TODO: After Node.js v22, fs.watch(dir) and deleting a dir will trigger the rename change event.
2285
- // Here we just ignore it and keep the same behavior as before v22
2286
- // https://github.com/libuv/libuv/pull/4376
2287
- if (
2288
- type === "rename" &&
2289
- path.isAbsolute(filename) &&
2290
- path.basename(filename) === path.basename(filePath)
2291
- ) {
2292
- if (!IS_OSX) {
2293
- // Before v22, windows will throw EPERM error
2294
- watcher.emit("error", createEPERMError(filename));
2484
+ class WatchpackDirectoryWatcher {
2485
+ /**
2486
+ * @param {Watchpack} watchpack watchpack
2487
+ * @param {Watcher<DirectoryWatcherEvents>} watcher watcher
2488
+ * @param {string} directories directories
2489
+ */
2490
+ constructor(watchpack, watcher, directories) {
2491
+ /** @type {string[]} */
2492
+ this.directories = Array.isArray(directories) ? directories : [directories];
2493
+ this.watcher = watcher;
2494
+ watcher.on("initial-missing", (type) => {
2495
+ for (const item of this.directories) {
2496
+ watchpack._onRemove(item, item, type);
2295
2497
  }
2296
- // Before v22, macos nothing to do
2297
- return;
2498
+ });
2499
+ watcher.on("change", (file, mtime, type, _initial) => {
2500
+ for (const item of this.directories) {
2501
+ watchpack._onChange(item, mtime, file, type);
2502
+ }
2503
+ });
2504
+ watcher.on("remove", (type) => {
2505
+ for (const item of this.directories) {
2506
+ watchpack._onRemove(item, item, type);
2507
+ }
2508
+ });
2509
+ }
2510
+
2511
+ /**
2512
+ * @param {string | string[]} directories directories
2513
+ */
2514
+ update(directories) {
2515
+ if (!Array.isArray(directories)) {
2516
+ if (this.directories.length !== 1) {
2517
+ this.directories = [directories];
2518
+ } else if (this.directories[0] !== directories) {
2519
+ this.directories[0] = directories;
2520
+ }
2521
+ } else {
2522
+ this.directories = directories;
2298
2523
  }
2299
- handleChangeEvent(type, filename);
2300
- };
2524
+ }
2525
+
2526
+ close() {
2527
+ this.watcher.close();
2528
+ }
2301
2529
  }
2302
2530
 
2303
- class DirectWatcher {
2304
- constructor(filePath) {
2305
- this.filePath = filePath;
2306
- this.watchers = new Set();
2307
- this.watcher = undefined;
2308
- try {
2309
- const watcher = fs.watch(filePath);
2531
+ /**
2532
+ * @typedef {object} WatchpackEvents
2533
+ * @property {(file: string, mtime: number, type: EventType) => void} change change event
2534
+ * @property {(file: string, type: EventType) => void} remove remove event
2535
+ * @property {(changes: Changes, removals: Removals) => void} aggregated aggregated event
2536
+ */
2310
2537
 
2311
- this.watcher = watcher;
2312
- const handleChangeEvent = createHandleChangeEvent(
2313
- watcher,
2314
- filePath,
2315
- (type, filename) => {
2316
- for (const w of this.watchers) {
2317
- w.emit("change", type, filename);
2538
+ /**
2539
+ * @extends {EventEmitter<{ [K in keyof WatchpackEvents]: Parameters<WatchpackEvents[K]> }>}
2540
+ */
2541
+ class Watchpack extends EventEmitter {
2542
+ /**
2543
+ * @param {WatchOptions=} options options
2544
+ */
2545
+ constructor(options = {}) {
2546
+ super();
2547
+ if (!options) options = {};
2548
+ /** @type {WatchOptions} */
2549
+ this.options = options;
2550
+ this.aggregateTimeout =
2551
+ typeof options.aggregateTimeout === "number"
2552
+ ? options.aggregateTimeout
2553
+ : 200;
2554
+ /** @type {NormalizedWatchOptions} */
2555
+ this.watcherOptions = cachedNormalizeOptions(options);
2556
+ /** @type {WatcherManager} */
2557
+ this.watcherManager = getWatcherManager(this.watcherOptions);
2558
+ /** @type {Map<string, WatchpackFileWatcher>} */
2559
+ this.fileWatchers = new Map();
2560
+ /** @type {Map<string, WatchpackDirectoryWatcher>} */
2561
+ this.directoryWatchers = new Map();
2562
+ /** @type {Set<string>} */
2563
+ this._missing = new Set();
2564
+ this.startTime = undefined;
2565
+ this.paused = false;
2566
+ /** @type {Changes} */
2567
+ this.aggregatedChanges = new Set();
2568
+ /** @type {Removals} */
2569
+ this.aggregatedRemovals = new Set();
2570
+ /** @type {undefined | NodeJS.Timeout} */
2571
+ this.aggregateTimer = undefined;
2572
+ this._onTimeout = this._onTimeout.bind(this);
2573
+ }
2574
+
2575
+ /**
2576
+ * @overload
2577
+ * @param {Iterable<string>} arg1 files
2578
+ * @param {Iterable<string>} arg2 directories
2579
+ * @param {number=} arg3 startTime
2580
+ * @returns {void}
2581
+ */
2582
+ /**
2583
+ * @overload
2584
+ * @param {WatchMethodOptions} arg1 watch options
2585
+ * @returns {void}
2586
+ */
2587
+ /**
2588
+ * @param {Iterable<string> | WatchMethodOptions} arg1 files
2589
+ * @param {Iterable<string>=} arg2 directories
2590
+ * @param {number=} arg3 startTime
2591
+ * @returns {void}
2592
+ */
2593
+ watch(arg1, arg2, arg3) {
2594
+ /** @type {Iterable<string> | undefined} */
2595
+ let files;
2596
+ /** @type {Iterable<string> | undefined} */
2597
+ let directories;
2598
+ /** @type {Iterable<string> | undefined} */
2599
+ let missing;
2600
+ /** @type {number | undefined} */
2601
+ let startTime;
2602
+ if (!arg2) {
2603
+ ({
2604
+ files = [],
2605
+ directories = [],
2606
+ missing = [],
2607
+ startTime,
2608
+ } = /** @type {WatchMethodOptions} */ (arg1));
2609
+ } else {
2610
+ files = /** @type {Iterable<string>} */ (arg1);
2611
+ directories = /** @type {Iterable<string>} */ (arg2);
2612
+ missing = [];
2613
+ startTime = /** @type {number} */ (arg3);
2614
+ }
2615
+ this.paused = false;
2616
+ const { fileWatchers, directoryWatchers } = this;
2617
+ const { ignored } = this.watcherOptions;
2618
+ /**
2619
+ * @param {string} path path
2620
+ * @returns {boolean} true when need to filter, otherwise false
2621
+ */
2622
+ const filter = (path) => !ignored(path);
2623
+ /**
2624
+ * @template K, V
2625
+ * @param {Map<K, V | V[]>} map map
2626
+ * @param {K} key key
2627
+ * @param {V} item item
2628
+ */
2629
+ const addToMap = (map, key, item) => {
2630
+ const list = map.get(key);
2631
+ if (list === undefined) {
2632
+ map.set(key, item);
2633
+ } else if (Array.isArray(list)) {
2634
+ list.push(item);
2635
+ } else {
2636
+ map.set(key, [list, item]);
2637
+ }
2638
+ };
2639
+ const fileWatchersNeeded = new Map();
2640
+ const directoryWatchersNeeded = new Map();
2641
+ /** @type {Set<string>} */
2642
+ const missingFiles = new Set();
2643
+ if (this.watcherOptions.followSymlinks) {
2644
+ const resolver = new LinkResolver();
2645
+ for (const file of files) {
2646
+ if (filter(file)) {
2647
+ for (const innerFile of resolver.resolve(file)) {
2648
+ if (file === innerFile || filter(innerFile)) {
2649
+ addToMap(fileWatchersNeeded, innerFile, file);
2650
+ }
2318
2651
  }
2319
2652
  }
2320
- );
2321
- watcher.on("change", handleChangeEvent);
2322
- watcher.on("error", error => {
2323
- for (const w of this.watchers) {
2324
- w.emit("error", error);
2653
+ }
2654
+ for (const file of missing) {
2655
+ if (filter(file)) {
2656
+ for (const innerFile of resolver.resolve(file)) {
2657
+ if (file === innerFile || filter(innerFile)) {
2658
+ missingFiles.add(file);
2659
+ addToMap(fileWatchersNeeded, innerFile, file);
2660
+ }
2661
+ }
2662
+ }
2663
+ }
2664
+ for (const dir of directories) {
2665
+ if (filter(dir)) {
2666
+ let first = true;
2667
+ for (const innerItem of resolver.resolve(dir)) {
2668
+ if (filter(innerItem)) {
2669
+ addToMap(
2670
+ first ? directoryWatchersNeeded : fileWatchersNeeded,
2671
+ innerItem,
2672
+ dir,
2673
+ );
2674
+ }
2675
+ first = false;
2676
+ }
2677
+ }
2678
+ }
2679
+ } else {
2680
+ for (const file of files) {
2681
+ if (filter(file)) {
2682
+ addToMap(fileWatchersNeeded, file, file);
2683
+ }
2684
+ }
2685
+ for (const file of missing) {
2686
+ if (filter(file)) {
2687
+ missingFiles.add(file);
2688
+ addToMap(fileWatchersNeeded, file, file);
2689
+ }
2690
+ }
2691
+ for (const dir of directories) {
2692
+ if (filter(dir)) {
2693
+ addToMap(directoryWatchersNeeded, dir, dir);
2694
+ }
2695
+ }
2696
+ }
2697
+ // Close unneeded old watchers
2698
+ // and update existing watchers
2699
+ for (const [key, w] of fileWatchers) {
2700
+ const needed = fileWatchersNeeded.get(key);
2701
+ if (needed === undefined) {
2702
+ w.close();
2703
+ fileWatchers.delete(key);
2704
+ } else {
2705
+ w.update(needed);
2706
+ fileWatchersNeeded.delete(key);
2707
+ }
2708
+ }
2709
+ for (const [key, w] of directoryWatchers) {
2710
+ const needed = directoryWatchersNeeded.get(key);
2711
+ if (needed === undefined) {
2712
+ w.close();
2713
+ directoryWatchers.delete(key);
2714
+ } else {
2715
+ w.update(needed);
2716
+ directoryWatchersNeeded.delete(key);
2717
+ }
2718
+ }
2719
+ // Create new watchers and install handlers on these watchers
2720
+ watchEventSource.batch(() => {
2721
+ for (const [key, files] of fileWatchersNeeded) {
2722
+ const watcher = this.watcherManager.watchFile(key, startTime);
2723
+ if (watcher) {
2724
+ fileWatchers.set(key, new WatchpackFileWatcher(this, watcher, files));
2325
2725
  }
2326
- });
2327
- } catch (err) {
2328
- process.nextTick(() => {
2329
- for (const w of this.watchers) {
2330
- w.emit("error", err);
2726
+ }
2727
+ for (const [key, directories] of directoryWatchersNeeded) {
2728
+ const watcher = this.watcherManager.watchDirectory(key, startTime);
2729
+ if (watcher) {
2730
+ directoryWatchers.set(
2731
+ key,
2732
+ new WatchpackDirectoryWatcher(this, watcher, directories),
2733
+ );
2331
2734
  }
2332
- });
2333
- }
2334
- watcherCount++;
2735
+ }
2736
+ });
2737
+ this._missing = missingFiles;
2738
+ this.startTime = startTime;
2335
2739
  }
2336
2740
 
2337
- add(watcher) {
2338
- underlyingWatcher.set(watcher, this);
2339
- this.watchers.add(watcher);
2741
+ close() {
2742
+ this.paused = true;
2743
+ if (this.aggregateTimer) clearTimeout(this.aggregateTimer);
2744
+ for (const w of this.fileWatchers.values()) w.close();
2745
+ for (const w of this.directoryWatchers.values()) w.close();
2746
+ this.fileWatchers.clear();
2747
+ this.directoryWatchers.clear();
2340
2748
  }
2341
2749
 
2342
- remove(watcher) {
2343
- this.watchers.delete(watcher);
2344
- if (this.watchers.size === 0) {
2345
- directWatchers.delete(this.filePath);
2346
- watcherCount--;
2347
- if (this.watcher) this.watcher.close();
2750
+ pause() {
2751
+ this.paused = true;
2752
+ if (this.aggregateTimer) clearTimeout(this.aggregateTimer);
2753
+ }
2754
+
2755
+ /**
2756
+ * @returns {Record<string, number>} times
2757
+ */
2758
+ getTimes() {
2759
+ /** @type {Set<DirectoryWatcher>} */
2760
+ const directoryWatchers = new Set();
2761
+ addWatchersToSet(this.fileWatchers.values(), directoryWatchers);
2762
+ addWatchersToSet(this.directoryWatchers.values(), directoryWatchers);
2763
+ /** @type {Record<string, number>} */
2764
+ const obj = Object.create(null);
2765
+ for (const w of directoryWatchers) {
2766
+ const times = w.getTimes();
2767
+ for (const file of Object.keys(times)) obj[file] = times[file];
2348
2768
  }
2769
+ return obj;
2349
2770
  }
2350
2771
 
2351
- getWatchers() {
2352
- return this.watchers;
2772
+ /**
2773
+ * @returns {TimeInfoEntries} time info entries
2774
+ */
2775
+ getTimeInfoEntries() {
2776
+ /** @type {TimeInfoEntries} */
2777
+ const map = new Map();
2778
+ this.collectTimeInfoEntries(map, map);
2779
+ return map;
2353
2780
  }
2354
- }
2355
2781
 
2356
- class RecursiveWatcher {
2357
- constructor(rootPath) {
2358
- this.rootPath = rootPath;
2359
- /** @type {Map<Watcher, string>} */
2360
- this.mapWatcherToPath = new Map();
2361
- /** @type {Map<string, Set<Watcher>>} */
2362
- this.mapPathToWatchers = new Map();
2363
- this.watcher = undefined;
2364
- try {
2365
- const watcher = fs.watch(rootPath, {
2366
- recursive: true
2367
- });
2368
- this.watcher = watcher;
2369
- watcher.on("change", (type, filename) => {
2370
- if (!filename) {
2371
- if (recursiveWatcherLogging) {
2372
- process.stderr.write(
2373
- `[watchpack] dispatch ${type} event in recursive watcher (${this.rootPath}) to all watchers\n`
2374
- );
2375
- }
2376
- for (const w of this.mapWatcherToPath.keys()) {
2377
- w.emit("change", type);
2378
- }
2379
- } else {
2380
- const dir = path.dirname(filename);
2381
- const watchers = this.mapPathToWatchers.get(dir);
2382
- if (recursiveWatcherLogging) {
2383
- process.stderr.write(
2384
- `[watchpack] dispatch ${type} event in recursive watcher (${
2385
- this.rootPath
2386
- }) for '${filename}' to ${
2387
- watchers ? watchers.size : 0
2388
- } watchers\n`
2389
- );
2390
- }
2391
- if (watchers === undefined) return;
2392
- for (const w of watchers) {
2393
- w.emit("change", type, path.basename(filename));
2394
- }
2395
- }
2396
- });
2397
- watcher.on("error", error => {
2398
- for (const w of this.mapWatcherToPath.keys()) {
2399
- w.emit("error", error);
2400
- }
2401
- });
2402
- } catch (err) {
2403
- process.nextTick(() => {
2404
- for (const w of this.mapWatcherToPath.keys()) {
2405
- w.emit("error", err);
2406
- }
2407
- });
2408
- }
2409
- watcherCount++;
2410
- if (recursiveWatcherLogging) {
2411
- process.stderr.write(
2412
- `[watchpack] created recursive watcher at ${rootPath}\n`
2413
- );
2782
+ /**
2783
+ * @param {TimeInfoEntries} fileTimestamps file timestamps
2784
+ * @param {TimeInfoEntries} directoryTimestamps directory timestamps
2785
+ */
2786
+ collectTimeInfoEntries(fileTimestamps, directoryTimestamps) {
2787
+ /** @type {Set<DirectoryWatcher>} */
2788
+ const allWatchers = new Set();
2789
+ addWatchersToSet(this.fileWatchers.values(), allWatchers);
2790
+ addWatchersToSet(this.directoryWatchers.values(), allWatchers);
2791
+ for (const w of allWatchers) {
2792
+ w.collectTimeInfoEntries(fileTimestamps, directoryTimestamps);
2414
2793
  }
2415
2794
  }
2416
2795
 
2417
- add(filePath, watcher) {
2418
- underlyingWatcher.set(watcher, this);
2419
- const subpath = filePath.slice(this.rootPath.length + 1) || ".";
2420
- this.mapWatcherToPath.set(watcher, subpath);
2421
- const set = this.mapPathToWatchers.get(subpath);
2422
- if (set === undefined) {
2423
- const newSet = new Set();
2424
- newSet.add(watcher);
2425
- this.mapPathToWatchers.set(subpath, newSet);
2426
- } else {
2427
- set.add(watcher);
2796
+ /**
2797
+ * @returns {Aggregated} aggregated info
2798
+ */
2799
+ getAggregated() {
2800
+ if (this.aggregateTimer) {
2801
+ clearTimeout(this.aggregateTimer);
2802
+ this.aggregateTimer = undefined;
2428
2803
  }
2804
+ const changes = this.aggregatedChanges;
2805
+ const removals = this.aggregatedRemovals;
2806
+ this.aggregatedChanges = new Set();
2807
+ this.aggregatedRemovals = new Set();
2808
+ return { changes, removals };
2429
2809
  }
2430
2810
 
2431
- remove(watcher) {
2432
- const subpath = this.mapWatcherToPath.get(watcher);
2433
- if (!subpath) return;
2434
- this.mapWatcherToPath.delete(watcher);
2435
- const set = this.mapPathToWatchers.get(subpath);
2436
- set.delete(watcher);
2437
- if (set.size === 0) {
2438
- this.mapPathToWatchers.delete(subpath);
2439
- }
2440
- if (this.mapWatcherToPath.size === 0) {
2441
- recursiveWatchers.delete(this.rootPath);
2442
- watcherCount--;
2443
- if (this.watcher) this.watcher.close();
2444
- if (recursiveWatcherLogging) {
2445
- process.stderr.write(
2446
- `[watchpack] closed recursive watcher at ${this.rootPath}\n`
2447
- );
2448
- }
2811
+ /**
2812
+ * @param {string} item item
2813
+ * @param {number} mtime mtime
2814
+ * @param {string} file file
2815
+ * @param {EventType} type type
2816
+ */
2817
+ _onChange(item, mtime, file, type) {
2818
+ file = file || item;
2819
+ if (!this.paused) {
2820
+ this.emit("change", file, mtime, type);
2821
+ if (this.aggregateTimer) clearTimeout(this.aggregateTimer);
2822
+ this.aggregateTimer = setTimeout(this._onTimeout, this.aggregateTimeout);
2449
2823
  }
2824
+ this.aggregatedRemovals.delete(item);
2825
+ this.aggregatedChanges.add(item);
2450
2826
  }
2451
2827
 
2452
- getWatchers() {
2453
- return this.mapWatcherToPath;
2828
+ /**
2829
+ * @param {string} item item
2830
+ * @param {string} file file
2831
+ * @param {EventType} type type
2832
+ */
2833
+ _onRemove(item, file, type) {
2834
+ file = file || item;
2835
+ if (!this.paused) {
2836
+ this.emit("remove", file, type);
2837
+ if (this.aggregateTimer) clearTimeout(this.aggregateTimer);
2838
+ this.aggregateTimer = setTimeout(this._onTimeout, this.aggregateTimeout);
2839
+ }
2840
+ this.aggregatedChanges.delete(item);
2841
+ this.aggregatedRemovals.add(item);
2454
2842
  }
2455
- }
2456
2843
 
2457
- class Watcher extends EventEmitter {
2458
- close() {
2459
- if (pendingWatchers.has(this)) {
2460
- pendingWatchers.delete(this);
2461
- return;
2462
- }
2463
- const watcher = underlyingWatcher.get(this);
2464
- watcher.remove(this);
2465
- underlyingWatcher.delete(this);
2844
+ _onTimeout() {
2845
+ this.aggregateTimer = undefined;
2846
+ const changes = this.aggregatedChanges;
2847
+ const removals = this.aggregatedRemovals;
2848
+ this.aggregatedChanges = new Set();
2849
+ this.aggregatedRemovals = new Set();
2850
+ this.emit("aggregated", changes, removals);
2466
2851
  }
2467
2852
  }
2468
2853
 
2469
- const createDirectWatcher = filePath => {
2470
- const existing = directWatchers.get(filePath);
2471
- if (existing !== undefined) return existing;
2472
- const w = new DirectWatcher(filePath);
2473
- directWatchers.set(filePath, w);
2474
- return w;
2475
- };
2854
+ module.exports = Watchpack;
2476
2855
 
2477
- const createRecursiveWatcher = rootPath => {
2478
- const existing = recursiveWatchers.get(rootPath);
2479
- if (existing !== undefined) return existing;
2480
- const w = new RecursiveWatcher(rootPath);
2481
- recursiveWatchers.set(rootPath, w);
2482
- return w;
2483
- };
2484
2856
 
2485
- const execute = () => {
2486
- /** @type {Map<string, Watcher[] | Watcher>} */
2487
- const map = new Map();
2488
- const addWatcher = (watcher, filePath) => {
2489
- const entry = map.get(filePath);
2490
- if (entry === undefined) {
2491
- map.set(filePath, watcher);
2492
- } else if (Array.isArray(entry)) {
2493
- entry.push(watcher);
2494
- } else {
2495
- map.set(filePath, [entry, watcher]);
2496
- }
2497
- };
2498
- for (const [watcher, filePath] of pendingWatchers) {
2499
- addWatcher(watcher, filePath);
2500
- }
2501
- pendingWatchers.clear();
2857
+ /***/ }),
2502
2858
 
2503
- // Fast case when we are not reaching the limit
2504
- if (!SUPPORTS_RECURSIVE_WATCHING || watcherLimit - watcherCount >= map.size) {
2505
- // Create watchers for all entries in the map
2506
- for (const [filePath, entry] of map) {
2507
- const w = createDirectWatcher(filePath);
2508
- if (Array.isArray(entry)) {
2509
- for (const item of entry) w.add(item);
2859
+ /***/ 240:
2860
+ /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
2861
+
2862
+ "use strict";
2863
+ /*
2864
+ MIT License http://www.opensource.org/licenses/mit-license.php
2865
+ Author Tobias Koppers @sokra
2866
+ */
2867
+
2868
+
2869
+ const path = __nccwpck_require__(928);
2870
+
2871
+ /**
2872
+ * @template T
2873
+ * @typedef {object} TreeNode
2874
+ * @property {string} target target
2875
+ * @property {TreeNode<T>} parent parent
2876
+ * @property {TreeNode<T>[]} children children
2877
+ * @property {number} entries number of entries
2878
+ * @property {boolean} active true when active, otherwise false
2879
+ * @property {T[] | T | undefined} value value
2880
+ */
2881
+
2882
+ /**
2883
+ * @template T
2884
+ * @param {Map<string, T[] | T>} plan plan
2885
+ * @param {number} limit limit
2886
+ * @returns {Map<string, Map<T, string>>} the new plan
2887
+ */
2888
+ module.exports = (plan, limit) => {
2889
+ const treeMap = new Map();
2890
+ // Convert to tree
2891
+ for (const [target, value] of plan) {
2892
+ treeMap.set(target, {
2893
+ target,
2894
+ parent: undefined,
2895
+ children: undefined,
2896
+ entries: 1,
2897
+ active: true,
2898
+ value,
2899
+ });
2900
+ }
2901
+ let currentCount = treeMap.size;
2902
+ // Create parents and calculate sum of entries
2903
+ for (const node of treeMap.values()) {
2904
+ const parentPath = path.dirname(node.target);
2905
+ if (parentPath !== node.target) {
2906
+ let parent = treeMap.get(parentPath);
2907
+ if (parent === undefined) {
2908
+ parent = {
2909
+ target: parentPath,
2910
+ parent: undefined,
2911
+ children: [node],
2912
+ entries: node.entries,
2913
+ active: false,
2914
+ value: undefined,
2915
+ };
2916
+ treeMap.set(parentPath, parent);
2917
+ node.parent = parent;
2510
2918
  } else {
2511
- w.add(entry);
2919
+ node.parent = parent;
2920
+ if (parent.children === undefined) {
2921
+ parent.children = [node];
2922
+ } else {
2923
+ parent.children.push(node);
2924
+ }
2925
+ do {
2926
+ parent.entries += node.entries;
2927
+ parent = parent.parent;
2928
+ } while (parent);
2512
2929
  }
2513
2930
  }
2514
- return;
2515
2931
  }
2516
-
2517
- // Reconsider existing watchers to improving watch plan
2518
- for (const watcher of recursiveWatchers.values()) {
2519
- for (const [w, subpath] of watcher.getWatchers()) {
2520
- addWatcher(w, path.join(watcher.rootPath, subpath));
2932
+ // Reduce until limit reached
2933
+ while (currentCount > limit) {
2934
+ // Select node that helps reaching the limit most effectively without overmerging
2935
+ const overLimit = currentCount - limit;
2936
+ let bestNode;
2937
+ let bestCost = Infinity;
2938
+ for (const node of treeMap.values()) {
2939
+ if (node.entries <= 1 || !node.children || !node.parent) continue;
2940
+ if (node.children.length === 0) continue;
2941
+ if (node.children.length === 1 && !node.value) continue;
2942
+ // Try to select the node with has just a bit more entries than we need to reduce
2943
+ // When just a bit more is over 30% over the limit,
2944
+ // also consider just a bit less entries then we need to reduce
2945
+ const cost =
2946
+ node.entries - 1 >= overLimit
2947
+ ? node.entries - 1 - overLimit
2948
+ : overLimit - node.entries + 1 + limit * 0.3;
2949
+ if (cost < bestCost) {
2950
+ bestNode = node;
2951
+ bestCost = cost;
2952
+ }
2521
2953
  }
2522
- }
2523
- for (const watcher of directWatchers.values()) {
2524
- for (const w of watcher.getWatchers()) {
2525
- addWatcher(w, watcher.filePath);
2954
+ if (!bestNode) break;
2955
+ // Merge all children
2956
+ const reduction = bestNode.entries - 1;
2957
+ bestNode.active = true;
2958
+ bestNode.entries = 1;
2959
+ currentCount -= reduction;
2960
+ let { parent } = bestNode;
2961
+ while (parent) {
2962
+ parent.entries -= reduction;
2963
+ parent = parent.parent;
2526
2964
  }
2527
- }
2528
-
2529
- // Merge map entries to keep watcher limit
2530
- // Create a 10% buffer to be able to enter fast case more often
2531
- const plan = reducePlan(map, watcherLimit * 0.9);
2532
-
2533
- // Update watchers for all entries in the map
2534
- for (const [filePath, entry] of plan) {
2535
- if (entry.size === 1) {
2536
- for (const [watcher, filePath] of entry) {
2537
- const w = createDirectWatcher(filePath);
2538
- const old = underlyingWatcher.get(watcher);
2539
- if (old === w) continue;
2540
- w.add(watcher);
2541
- if (old !== undefined) old.remove(watcher);
2965
+ const queue = new Set(bestNode.children);
2966
+ for (const node of queue) {
2967
+ node.active = false;
2968
+ node.entries = 0;
2969
+ if (node.children) {
2970
+ for (const child of node.children) queue.add(child);
2542
2971
  }
2543
- } else {
2544
- const filePaths = new Set(entry.values());
2545
- if (filePaths.size > 1) {
2546
- const w = createRecursiveWatcher(filePath);
2547
- for (const [watcher, watcherPath] of entry) {
2548
- const old = underlyingWatcher.get(watcher);
2549
- if (old === w) continue;
2550
- w.add(watcherPath, watcher);
2551
- if (old !== undefined) old.remove(watcher);
2552
- }
2553
- } else {
2554
- for (const filePath of filePaths) {
2555
- const w = createDirectWatcher(filePath);
2556
- for (const watcher of entry.keys()) {
2557
- const old = underlyingWatcher.get(watcher);
2558
- if (old === w) continue;
2559
- w.add(watcher);
2560
- if (old !== undefined) old.remove(watcher);
2972
+ }
2973
+ }
2974
+ // Write down new plan
2975
+ const newPlan = new Map();
2976
+ for (const rootNode of treeMap.values()) {
2977
+ if (!rootNode.active) continue;
2978
+ const map = new Map();
2979
+ const queue = new Set([rootNode]);
2980
+ for (const node of queue) {
2981
+ if (node.active && node !== rootNode) continue;
2982
+ if (node.value) {
2983
+ if (Array.isArray(node.value)) {
2984
+ for (const item of node.value) {
2985
+ map.set(item, node.target);
2561
2986
  }
2987
+ } else {
2988
+ map.set(node.value, node.target);
2989
+ }
2990
+ }
2991
+ if (node.children) {
2992
+ for (const child of node.children) {
2993
+ queue.add(child);
2562
2994
  }
2563
2995
  }
2564
2996
  }
2997
+ newPlan.set(rootNode.target, map);
2565
2998
  }
2999
+ return newPlan;
2566
3000
  };
2567
3001
 
2568
- exports.watch = filePath => {
2569
- const watcher = new Watcher();
2570
- // Find an existing watcher
2571
- const directWatcher = directWatchers.get(filePath);
2572
- if (directWatcher !== undefined) {
2573
- directWatcher.add(watcher);
2574
- return watcher;
2575
- }
2576
- let current = filePath;
2577
- for (;;) {
2578
- const recursiveWatcher = recursiveWatchers.get(current);
2579
- if (recursiveWatcher !== undefined) {
2580
- recursiveWatcher.add(filePath, watcher);
2581
- return watcher;
2582
- }
2583
- const parent = path.dirname(current);
2584
- if (parent === current) break;
2585
- current = parent;
2586
- }
2587
- // Queue up watcher for creation
2588
- pendingWatchers.set(watcher, filePath);
2589
- if (!isBatch) execute();
2590
- return watcher;
2591
- };
2592
-
2593
- exports.batch = fn => {
2594
- isBatch = true;
2595
- try {
2596
- fn();
2597
- } finally {
2598
- isBatch = false;
2599
- execute();
2600
- }
2601
- };
2602
-
2603
- exports.getNumberOfWatchers = () => {
2604
- return watcherCount;
2605
- };
2606
-
2607
- exports.createHandleChangeEvent = createHandleChangeEvent;
2608
- exports.watcherLimit = watcherLimit;
2609
-
2610
3002
 
2611
3003
  /***/ }),
2612
3004
 
2613
- /***/ 851:
3005
+ /***/ 313:
2614
3006
  /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
2615
3007
 
2616
3008
  "use strict";
@@ -2620,393 +3012,449 @@ exports.watcherLimit = watcherLimit;
2620
3012
  */
2621
3013
 
2622
3014
 
2623
- const getWatcherManager = __nccwpck_require__(510);
2624
- const LinkResolver = __nccwpck_require__(751);
2625
- const EventEmitter = (__nccwpck_require__(434).EventEmitter);
2626
- const globToRegExp = __nccwpck_require__(428);
2627
- const watchEventSource = __nccwpck_require__(729);
3015
+ const { EventEmitter } = __nccwpck_require__(434);
3016
+ const fs = __nccwpck_require__(896);
3017
+ const path = __nccwpck_require__(928);
3018
+ const reducePlan = __nccwpck_require__(240);
2628
3019
 
2629
- const EMPTY_ARRAY = [];
2630
- const EMPTY_OPTIONS = {};
3020
+ /** @typedef {import("fs").FSWatcher} FSWatcher */
3021
+ /** @typedef {import("./index").EventType} EventType */
2631
3022
 
2632
- function addWatchersToSet(watchers, set) {
2633
- for (const ww of watchers) {
2634
- const w = ww.watcher;
2635
- if (!set.has(w.directoryWatcher)) {
2636
- set.add(w.directoryWatcher);
2637
- }
2638
- }
2639
- }
3023
+ const IS_OSX = (__nccwpck_require__(857).platform)() === "darwin";
3024
+ const IS_WIN = (__nccwpck_require__(857).platform)() === "win32";
2640
3025
 
2641
- const stringToRegexp = ignored => {
2642
- if (ignored.length === 0) {
2643
- return;
2644
- }
2645
- const source = globToRegExp(ignored, { globstar: true, extended: true })
2646
- .source;
2647
- return source.slice(0, source.length - 1) + "(?:$|\\/)";
2648
- };
3026
+ const SUPPORTS_RECURSIVE_WATCHING = IS_OSX || IS_WIN;
2649
3027
 
2650
- const ignoredToFunction = ignored => {
2651
- if (Array.isArray(ignored)) {
2652
- const stringRegexps = ignored.map(i => stringToRegexp(i)).filter(Boolean);
2653
- if (stringRegexps.length === 0) {
2654
- return () => false;
2655
- }
2656
- const regexp = new RegExp(stringRegexps.join("|"));
2657
- return x => regexp.test(x.replace(/\\/g, "/"));
2658
- } else if (typeof ignored === "string") {
2659
- const stringRegexp = stringToRegexp(ignored);
2660
- if (!stringRegexp) {
2661
- return () => false;
2662
- }
2663
- const regexp = new RegExp(stringRegexp);
2664
- return x => regexp.test(x.replace(/\\/g, "/"));
2665
- } else if (ignored instanceof RegExp) {
2666
- return x => ignored.test(x.replace(/\\/g, "/"));
2667
- } else if (ignored instanceof Function) {
2668
- return ignored;
2669
- } else if (ignored) {
2670
- throw new Error(`Invalid option for 'ignored': ${ignored}`);
2671
- } else {
2672
- return () => false;
2673
- }
2674
- };
3028
+ // Use 20 for OSX to make `FSWatcher.close` faster
3029
+ // https://github.com/nodejs/node/issues/29949
3030
+ const watcherLimit =
3031
+ // @ts-expect-error avoid additional checks
3032
+ +process.env.WATCHPACK_WATCHER_LIMIT || (IS_OSX ? 20 : 10000);
2675
3033
 
2676
- const normalizeOptions = options => {
2677
- return {
2678
- followSymlinks: !!options.followSymlinks,
2679
- ignored: ignoredToFunction(options.ignored),
2680
- poll: options.poll
2681
- };
2682
- };
3034
+ const recursiveWatcherLogging = Boolean(
3035
+ process.env.WATCHPACK_RECURSIVE_WATCHER_LOGGING,
3036
+ );
2683
3037
 
2684
- const normalizeCache = new WeakMap();
2685
- const cachedNormalizeOptions = options => {
2686
- const cacheEntry = normalizeCache.get(options);
2687
- if (cacheEntry !== undefined) return cacheEntry;
2688
- const normalized = normalizeOptions(options);
2689
- normalizeCache.set(options, normalized);
2690
- return normalized;
2691
- };
3038
+ let isBatch = false;
3039
+ let watcherCount = 0;
2692
3040
 
2693
- class WatchpackFileWatcher {
2694
- constructor(watchpack, watcher, files) {
2695
- this.files = Array.isArray(files) ? files : [files];
2696
- this.watcher = watcher;
2697
- watcher.on("initial-missing", type => {
2698
- for (const file of this.files) {
2699
- if (!watchpack._missing.has(file))
2700
- watchpack._onRemove(file, file, type);
2701
- }
2702
- });
2703
- watcher.on("change", (mtime, type) => {
2704
- for (const file of this.files) {
2705
- watchpack._onChange(file, mtime, file, type);
2706
- }
2707
- });
2708
- watcher.on("remove", type => {
2709
- for (const file of this.files) {
2710
- watchpack._onRemove(file, file, type);
2711
- }
2712
- });
2713
- }
3041
+ /** @type {Map<Watcher, string>} */
3042
+ const pendingWatchers = new Map();
2714
3043
 
2715
- update(files) {
2716
- if (!Array.isArray(files)) {
2717
- if (this.files.length !== 1) {
2718
- this.files = [files];
2719
- } else if (this.files[0] !== files) {
2720
- this.files[0] = files;
3044
+ /** @type {Map<string, RecursiveWatcher>} */
3045
+ const recursiveWatchers = new Map();
3046
+
3047
+ /** @type {Map<string, DirectWatcher>} */
3048
+ const directWatchers = new Map();
3049
+
3050
+ /** @type {Map<Watcher, RecursiveWatcher | DirectWatcher>} */
3051
+ const underlyingWatcher = new Map();
3052
+
3053
+ /**
3054
+ * @param {string} filePath file path
3055
+ * @returns {NodeJS.ErrnoException} new error with file path in the message
3056
+ */
3057
+ function createEPERMError(filePath) {
3058
+ const error =
3059
+ /** @type {NodeJS.ErrnoException} */
3060
+ (new Error(`Operation not permitted: ${filePath}`));
3061
+ error.code = "EPERM";
3062
+ return error;
3063
+ }
3064
+
3065
+ /**
3066
+ * @param {FSWatcher} watcher watcher
3067
+ * @param {string} filePath a file path
3068
+ * @param {(type: "rename" | "change", filename: string) => void} handleChangeEvent function to handle change
3069
+ * @returns {(type: "rename" | "change", filename: string) => void} handler of change event
3070
+ */
3071
+ function createHandleChangeEvent(watcher, filePath, handleChangeEvent) {
3072
+ return (type, filename) => {
3073
+ // TODO: After Node.js v22, fs.watch(dir) and deleting a dir will trigger the rename change event.
3074
+ // Here we just ignore it and keep the same behavior as before v22
3075
+ // https://github.com/libuv/libuv/pull/4376
3076
+ if (
3077
+ type === "rename" &&
3078
+ path.isAbsolute(filename) &&
3079
+ path.basename(filename) === path.basename(filePath)
3080
+ ) {
3081
+ if (!IS_OSX) {
3082
+ // Before v22, windows will throw EPERM error
3083
+ watcher.emit("error", createEPERMError(filename));
2721
3084
  }
2722
- } else {
2723
- this.files = files;
3085
+ // Before v22, macos nothing to do
3086
+ return;
2724
3087
  }
2725
- }
3088
+ handleChangeEvent(type, filename);
3089
+ };
3090
+ }
2726
3091
 
2727
- close() {
2728
- this.watcher.close();
3092
+ class DirectWatcher {
3093
+ /**
3094
+ * @param {string} filePath file path
3095
+ */
3096
+ constructor(filePath) {
3097
+ this.filePath = filePath;
3098
+ this.watchers = new Set();
3099
+ /** @type {FSWatcher | undefined} */
3100
+ this.watcher = undefined;
3101
+ try {
3102
+ const watcher = fs.watch(filePath);
3103
+
3104
+ this.watcher = watcher;
3105
+ const handleChangeEvent = createHandleChangeEvent(
3106
+ watcher,
3107
+ filePath,
3108
+ (type, filename) => {
3109
+ for (const w of this.watchers) {
3110
+ w.emit("change", type, filename);
3111
+ }
3112
+ },
3113
+ );
3114
+ watcher.on("change", handleChangeEvent);
3115
+ watcher.on("error", (error) => {
3116
+ for (const w of this.watchers) {
3117
+ w.emit("error", error);
3118
+ }
3119
+ });
3120
+ } catch (err) {
3121
+ process.nextTick(() => {
3122
+ for (const w of this.watchers) {
3123
+ w.emit("error", err);
3124
+ }
3125
+ });
3126
+ }
3127
+ watcherCount++;
2729
3128
  }
2730
- }
2731
3129
 
2732
- class WatchpackDirectoryWatcher {
2733
- constructor(watchpack, watcher, directories) {
2734
- this.directories = Array.isArray(directories) ? directories : [directories];
2735
- this.watcher = watcher;
2736
- watcher.on("initial-missing", type => {
2737
- for (const item of this.directories) {
2738
- watchpack._onRemove(item, item, type);
2739
- }
2740
- });
2741
- watcher.on("change", (file, mtime, type) => {
2742
- for (const item of this.directories) {
2743
- watchpack._onChange(item, mtime, file, type);
2744
- }
2745
- });
2746
- watcher.on("remove", type => {
2747
- for (const item of this.directories) {
2748
- watchpack._onRemove(item, item, type);
2749
- }
2750
- });
3130
+ /**
3131
+ * @param {Watcher} watcher a watcher
3132
+ */
3133
+ add(watcher) {
3134
+ underlyingWatcher.set(watcher, this);
3135
+ this.watchers.add(watcher);
2751
3136
  }
2752
3137
 
2753
- update(directories) {
2754
- if (!Array.isArray(directories)) {
2755
- if (this.directories.length !== 1) {
2756
- this.directories = [directories];
2757
- } else if (this.directories[0] !== directories) {
2758
- this.directories[0] = directories;
2759
- }
2760
- } else {
2761
- this.directories = directories;
3138
+ /**
3139
+ * @param {Watcher} watcher a watcher
3140
+ */
3141
+ remove(watcher) {
3142
+ this.watchers.delete(watcher);
3143
+ if (this.watchers.size === 0) {
3144
+ directWatchers.delete(this.filePath);
3145
+ watcherCount--;
3146
+ if (this.watcher) this.watcher.close();
2762
3147
  }
2763
3148
  }
2764
3149
 
2765
- close() {
2766
- this.watcher.close();
3150
+ getWatchers() {
3151
+ return this.watchers;
2767
3152
  }
2768
3153
  }
2769
3154
 
2770
- class Watchpack extends EventEmitter {
2771
- constructor(options) {
2772
- super();
2773
- if (!options) options = EMPTY_OPTIONS;
2774
- this.options = options;
2775
- this.aggregateTimeout =
2776
- typeof options.aggregateTimeout === "number"
2777
- ? options.aggregateTimeout
2778
- : 200;
2779
- this.watcherOptions = cachedNormalizeOptions(options);
2780
- this.watcherManager = getWatcherManager(this.watcherOptions);
2781
- this.fileWatchers = new Map();
2782
- this.directoryWatchers = new Map();
2783
- this._missing = new Set();
2784
- this.startTime = undefined;
2785
- this.paused = false;
2786
- this.aggregatedChanges = new Set();
2787
- this.aggregatedRemovals = new Set();
2788
- this.aggregateTimer = undefined;
2789
- this._onTimeout = this._onTimeout.bind(this);
2790
- }
3155
+ /** @typedef {Set<Watcher>} WatcherSet */
2791
3156
 
2792
- watch(arg1, arg2, arg3) {
2793
- let files, directories, missing, startTime;
2794
- if (!arg2) {
2795
- ({
2796
- files = EMPTY_ARRAY,
2797
- directories = EMPTY_ARRAY,
2798
- missing = EMPTY_ARRAY,
2799
- startTime
2800
- } = arg1);
2801
- } else {
2802
- files = arg1;
2803
- directories = arg2;
2804
- missing = EMPTY_ARRAY;
2805
- startTime = arg3;
2806
- }
2807
- this.paused = false;
2808
- const fileWatchers = this.fileWatchers;
2809
- const directoryWatchers = this.directoryWatchers;
2810
- const ignored = this.watcherOptions.ignored;
2811
- const filter = path => !ignored(path);
2812
- const addToMap = (map, key, item) => {
2813
- const list = map.get(key);
2814
- if (list === undefined) {
2815
- map.set(key, item);
2816
- } else if (Array.isArray(list)) {
2817
- list.push(item);
2818
- } else {
2819
- map.set(key, [list, item]);
2820
- }
2821
- };
2822
- const fileWatchersNeeded = new Map();
2823
- const directoryWatchersNeeded = new Map();
2824
- const missingFiles = new Set();
2825
- if (this.watcherOptions.followSymlinks) {
2826
- const resolver = new LinkResolver();
2827
- for (const file of files) {
2828
- if (filter(file)) {
2829
- for (const innerFile of resolver.resolve(file)) {
2830
- if (file === innerFile || filter(innerFile)) {
2831
- addToMap(fileWatchersNeeded, innerFile, file);
2832
- }
3157
+ class RecursiveWatcher {
3158
+ /**
3159
+ * @param {string} rootPath a root path
3160
+ */
3161
+ constructor(rootPath) {
3162
+ this.rootPath = rootPath;
3163
+ /** @type {Map<Watcher, string>} */
3164
+ this.mapWatcherToPath = new Map();
3165
+ /** @type {Map<string, WatcherSet>} */
3166
+ this.mapPathToWatchers = new Map();
3167
+ this.watcher = undefined;
3168
+ try {
3169
+ const watcher = fs.watch(rootPath, {
3170
+ recursive: true,
3171
+ });
3172
+ this.watcher = watcher;
3173
+ watcher.on("change", (type, filename) => {
3174
+ if (!filename) {
3175
+ if (recursiveWatcherLogging) {
3176
+ process.stderr.write(
3177
+ `[watchpack] dispatch ${type} event in recursive watcher (${this.rootPath}) to all watchers\n`,
3178
+ );
2833
3179
  }
2834
- }
2835
- }
2836
- for (const file of missing) {
2837
- if (filter(file)) {
2838
- for (const innerFile of resolver.resolve(file)) {
2839
- if (file === innerFile || filter(innerFile)) {
2840
- missingFiles.add(file);
2841
- addToMap(fileWatchersNeeded, innerFile, file);
2842
- }
3180
+ for (const w of this.mapWatcherToPath.keys()) {
3181
+ w.emit("change", /** @type {EventType} */ (type));
2843
3182
  }
2844
- }
2845
- }
2846
- for (const dir of directories) {
2847
- if (filter(dir)) {
2848
- let first = true;
2849
- for (const innerItem of resolver.resolve(dir)) {
2850
- if (filter(innerItem)) {
2851
- addToMap(
2852
- first ? directoryWatchersNeeded : fileWatchersNeeded,
2853
- innerItem,
2854
- dir
2855
- );
2856
- }
2857
- first = false;
3183
+ } else {
3184
+ const dir = path.dirname(/** @type {string} */ (filename));
3185
+ const watchers = this.mapPathToWatchers.get(dir);
3186
+ if (recursiveWatcherLogging) {
3187
+ process.stderr.write(
3188
+ `[watchpack] dispatch ${type} event in recursive watcher (${
3189
+ this.rootPath
3190
+ }) for '${filename}' to ${
3191
+ watchers ? watchers.size : 0
3192
+ } watchers\n`,
3193
+ );
3194
+ }
3195
+ if (watchers === undefined) return;
3196
+ for (const w of watchers) {
3197
+ w.emit(
3198
+ "change",
3199
+ /** @type {EventType} */ (type),
3200
+ path.basename(/** @type {string} */ (filename)),
3201
+ );
2858
3202
  }
2859
3203
  }
2860
- }
2861
- } else {
2862
- for (const file of files) {
2863
- if (filter(file)) {
2864
- addToMap(fileWatchersNeeded, file, file);
2865
- }
2866
- }
2867
- for (const file of missing) {
2868
- if (filter(file)) {
2869
- missingFiles.add(file);
2870
- addToMap(fileWatchersNeeded, file, file);
3204
+ });
3205
+ watcher.on("error", (error) => {
3206
+ for (const w of this.mapWatcherToPath.keys()) {
3207
+ w.emit("error", error);
2871
3208
  }
2872
- }
2873
- for (const dir of directories) {
2874
- if (filter(dir)) {
2875
- addToMap(directoryWatchersNeeded, dir, dir);
3209
+ });
3210
+ } catch (err) {
3211
+ process.nextTick(() => {
3212
+ for (const w of this.mapWatcherToPath.keys()) {
3213
+ w.emit("error", err);
2876
3214
  }
2877
- }
3215
+ });
2878
3216
  }
2879
- // Close unneeded old watchers
2880
- // and update existing watchers
2881
- for (const [key, w] of fileWatchers) {
2882
- const needed = fileWatchersNeeded.get(key);
2883
- if (needed === undefined) {
2884
- w.close();
2885
- fileWatchers.delete(key);
2886
- } else {
2887
- w.update(needed);
2888
- fileWatchersNeeded.delete(key);
2889
- }
3217
+ watcherCount++;
3218
+ if (recursiveWatcherLogging) {
3219
+ process.stderr.write(
3220
+ `[watchpack] created recursive watcher at ${rootPath}\n`,
3221
+ );
3222
+ }
3223
+ }
3224
+
3225
+ /**
3226
+ * @param {string} filePath a file path
3227
+ * @param {Watcher} watcher a watcher
3228
+ */
3229
+ add(filePath, watcher) {
3230
+ underlyingWatcher.set(watcher, this);
3231
+ const subpath = filePath.slice(this.rootPath.length + 1) || ".";
3232
+ this.mapWatcherToPath.set(watcher, subpath);
3233
+ const set = this.mapPathToWatchers.get(subpath);
3234
+ if (set === undefined) {
3235
+ const newSet = new Set();
3236
+ newSet.add(watcher);
3237
+ this.mapPathToWatchers.set(subpath, newSet);
3238
+ } else {
3239
+ set.add(watcher);
2890
3240
  }
2891
- for (const [key, w] of directoryWatchers) {
2892
- const needed = directoryWatchersNeeded.get(key);
2893
- if (needed === undefined) {
2894
- w.close();
2895
- directoryWatchers.delete(key);
2896
- } else {
2897
- w.update(needed);
2898
- directoryWatchersNeeded.delete(key);
2899
- }
3241
+ }
3242
+
3243
+ /**
3244
+ * @param {Watcher} watcher a watcher
3245
+ */
3246
+ remove(watcher) {
3247
+ const subpath = this.mapWatcherToPath.get(watcher);
3248
+ if (!subpath) return;
3249
+ this.mapWatcherToPath.delete(watcher);
3250
+ const set = /** @type {WatcherSet} */ (this.mapPathToWatchers.get(subpath));
3251
+ set.delete(watcher);
3252
+ if (set.size === 0) {
3253
+ this.mapPathToWatchers.delete(subpath);
2900
3254
  }
2901
- // Create new watchers and install handlers on these watchers
2902
- watchEventSource.batch(() => {
2903
- for (const [key, files] of fileWatchersNeeded) {
2904
- const watcher = this.watcherManager.watchFile(key, startTime);
2905
- if (watcher) {
2906
- fileWatchers.set(key, new WatchpackFileWatcher(this, watcher, files));
2907
- }
2908
- }
2909
- for (const [key, directories] of directoryWatchersNeeded) {
2910
- const watcher = this.watcherManager.watchDirectory(key, startTime);
2911
- if (watcher) {
2912
- directoryWatchers.set(
2913
- key,
2914
- new WatchpackDirectoryWatcher(this, watcher, directories)
2915
- );
2916
- }
3255
+ if (this.mapWatcherToPath.size === 0) {
3256
+ recursiveWatchers.delete(this.rootPath);
3257
+ watcherCount--;
3258
+ if (this.watcher) this.watcher.close();
3259
+ if (recursiveWatcherLogging) {
3260
+ process.stderr.write(
3261
+ `[watchpack] closed recursive watcher at ${this.rootPath}\n`,
3262
+ );
2917
3263
  }
2918
- });
2919
- this._missing = missingFiles;
2920
- this.startTime = startTime;
3264
+ }
2921
3265
  }
2922
3266
 
2923
- close() {
2924
- this.paused = true;
2925
- if (this.aggregateTimer) clearTimeout(this.aggregateTimer);
2926
- for (const w of this.fileWatchers.values()) w.close();
2927
- for (const w of this.directoryWatchers.values()) w.close();
2928
- this.fileWatchers.clear();
2929
- this.directoryWatchers.clear();
3267
+ getWatchers() {
3268
+ return this.mapWatcherToPath;
2930
3269
  }
3270
+ }
2931
3271
 
2932
- pause() {
2933
- this.paused = true;
2934
- if (this.aggregateTimer) clearTimeout(this.aggregateTimer);
3272
+ /**
3273
+ * @typedef {object} WatcherEvents
3274
+ * @property {(eventType: EventType, filename?: string) => void} change change event
3275
+ * @property {(err: unknown) => void} error error event
3276
+ */
3277
+
3278
+ /**
3279
+ * @extends {EventEmitter<{ [K in keyof WatcherEvents]: Parameters<WatcherEvents[K]> }>}
3280
+ */
3281
+ class Watcher extends EventEmitter {
3282
+ constructor() {
3283
+ super();
2935
3284
  }
2936
3285
 
2937
- getTimes() {
2938
- const directoryWatchers = new Set();
2939
- addWatchersToSet(this.fileWatchers.values(), directoryWatchers);
2940
- addWatchersToSet(this.directoryWatchers.values(), directoryWatchers);
2941
- const obj = Object.create(null);
2942
- for (const w of directoryWatchers) {
2943
- const times = w.getTimes();
2944
- for (const file of Object.keys(times)) obj[file] = times[file];
3286
+ close() {
3287
+ if (pendingWatchers.has(this)) {
3288
+ pendingWatchers.delete(this);
3289
+ return;
2945
3290
  }
2946
- return obj;
3291
+ const watcher = underlyingWatcher.get(this);
3292
+ /** @type {RecursiveWatcher | DirectWatcher} */
3293
+ (watcher).remove(this);
3294
+ underlyingWatcher.delete(this);
2947
3295
  }
3296
+ }
2948
3297
 
2949
- getTimeInfoEntries() {
2950
- const map = new Map();
2951
- this.collectTimeInfoEntries(map, map);
2952
- return map;
2953
- }
3298
+ /**
3299
+ * @param {string} filePath a file path
3300
+ * @returns {DirectWatcher} a directory watcher
3301
+ */
3302
+ const createDirectWatcher = (filePath) => {
3303
+ const existing = directWatchers.get(filePath);
3304
+ if (existing !== undefined) return existing;
3305
+ const w = new DirectWatcher(filePath);
3306
+ directWatchers.set(filePath, w);
3307
+ return w;
3308
+ };
2954
3309
 
2955
- collectTimeInfoEntries(fileTimestamps, directoryTimestamps) {
2956
- const allWatchers = new Set();
2957
- addWatchersToSet(this.fileWatchers.values(), allWatchers);
2958
- addWatchersToSet(this.directoryWatchers.values(), allWatchers);
2959
- const safeTime = { value: 0 };
2960
- for (const w of allWatchers) {
2961
- w.collectTimeInfoEntries(fileTimestamps, directoryTimestamps, safeTime);
3310
+ /**
3311
+ * @param {string} rootPath a root path
3312
+ * @returns {RecursiveWatcher} a recursive watcher
3313
+ */
3314
+ const createRecursiveWatcher = (rootPath) => {
3315
+ const existing = recursiveWatchers.get(rootPath);
3316
+ if (existing !== undefined) return existing;
3317
+ const w = new RecursiveWatcher(rootPath);
3318
+ recursiveWatchers.set(rootPath, w);
3319
+ return w;
3320
+ };
3321
+
3322
+ const execute = () => {
3323
+ /** @type {Map<string, Watcher[] | Watcher>} */
3324
+ const map = new Map();
3325
+ /**
3326
+ * @param {Watcher} watcher a watcher
3327
+ * @param {string} filePath a file path
3328
+ */
3329
+ const addWatcher = (watcher, filePath) => {
3330
+ const entry = map.get(filePath);
3331
+ if (entry === undefined) {
3332
+ map.set(filePath, watcher);
3333
+ } else if (Array.isArray(entry)) {
3334
+ entry.push(watcher);
3335
+ } else {
3336
+ map.set(filePath, [entry, watcher]);
2962
3337
  }
3338
+ };
3339
+ for (const [watcher, filePath] of pendingWatchers) {
3340
+ addWatcher(watcher, filePath);
2963
3341
  }
3342
+ pendingWatchers.clear();
2964
3343
 
2965
- getAggregated() {
2966
- if (this.aggregateTimer) {
2967
- clearTimeout(this.aggregateTimer);
2968
- this.aggregateTimer = undefined;
3344
+ // Fast case when we are not reaching the limit
3345
+ if (!SUPPORTS_RECURSIVE_WATCHING || watcherLimit - watcherCount >= map.size) {
3346
+ // Create watchers for all entries in the map
3347
+ for (const [filePath, entry] of map) {
3348
+ const w = createDirectWatcher(filePath);
3349
+ if (Array.isArray(entry)) {
3350
+ for (const item of entry) w.add(item);
3351
+ } else {
3352
+ w.add(entry);
3353
+ }
2969
3354
  }
2970
- const changes = this.aggregatedChanges;
2971
- const removals = this.aggregatedRemovals;
2972
- this.aggregatedChanges = new Set();
2973
- this.aggregatedRemovals = new Set();
2974
- return { changes, removals };
3355
+ return;
2975
3356
  }
2976
3357
 
2977
- _onChange(item, mtime, file, type) {
2978
- file = file || item;
2979
- if (!this.paused) {
2980
- this.emit("change", file, mtime, type);
2981
- if (this.aggregateTimer) clearTimeout(this.aggregateTimer);
2982
- this.aggregateTimer = setTimeout(this._onTimeout, this.aggregateTimeout);
3358
+ // Reconsider existing watchers to improving watch plan
3359
+ for (const watcher of recursiveWatchers.values()) {
3360
+ for (const [w, subpath] of watcher.getWatchers()) {
3361
+ addWatcher(w, path.join(watcher.rootPath, subpath));
3362
+ }
3363
+ }
3364
+ for (const watcher of directWatchers.values()) {
3365
+ for (const w of watcher.getWatchers()) {
3366
+ addWatcher(w, watcher.filePath);
2983
3367
  }
2984
- this.aggregatedRemovals.delete(item);
2985
- this.aggregatedChanges.add(item);
2986
3368
  }
2987
3369
 
2988
- _onRemove(item, file, type) {
2989
- file = file || item;
2990
- if (!this.paused) {
2991
- this.emit("remove", file, type);
2992
- if (this.aggregateTimer) clearTimeout(this.aggregateTimer);
2993
- this.aggregateTimer = setTimeout(this._onTimeout, this.aggregateTimeout);
3370
+ // Merge map entries to keep watcher limit
3371
+ // Create a 10% buffer to be able to enter fast case more often
3372
+ const plan = reducePlan(map, watcherLimit * 0.9);
3373
+
3374
+ // Update watchers for all entries in the map
3375
+ for (const [filePath, entry] of plan) {
3376
+ if (entry.size === 1) {
3377
+ for (const [watcher, filePath] of entry) {
3378
+ const w = createDirectWatcher(filePath);
3379
+ const old = underlyingWatcher.get(watcher);
3380
+ if (old === w) continue;
3381
+ w.add(watcher);
3382
+ if (old !== undefined) old.remove(watcher);
3383
+ }
3384
+ } else {
3385
+ const filePaths = new Set(entry.values());
3386
+ if (filePaths.size > 1) {
3387
+ const w = createRecursiveWatcher(filePath);
3388
+ for (const [watcher, watcherPath] of entry) {
3389
+ const old = underlyingWatcher.get(watcher);
3390
+ if (old === w) continue;
3391
+ w.add(watcherPath, watcher);
3392
+ if (old !== undefined) old.remove(watcher);
3393
+ }
3394
+ } else {
3395
+ for (const filePath of filePaths) {
3396
+ const w = createDirectWatcher(filePath);
3397
+ for (const watcher of entry.keys()) {
3398
+ const old = underlyingWatcher.get(watcher);
3399
+ if (old === w) continue;
3400
+ w.add(watcher);
3401
+ if (old !== undefined) old.remove(watcher);
3402
+ }
3403
+ }
3404
+ }
2994
3405
  }
2995
- this.aggregatedChanges.delete(item);
2996
- this.aggregatedRemovals.add(item);
2997
3406
  }
3407
+ };
2998
3408
 
2999
- _onTimeout() {
3000
- this.aggregateTimer = undefined;
3001
- const changes = this.aggregatedChanges;
3002
- const removals = this.aggregatedRemovals;
3003
- this.aggregatedChanges = new Set();
3004
- this.aggregatedRemovals = new Set();
3005
- this.emit("aggregated", changes, removals);
3409
+ module.exports.Watcher = Watcher;
3410
+
3411
+ /**
3412
+ * @param {() => void} fn a function
3413
+ */
3414
+ module.exports.batch = (fn) => {
3415
+ isBatch = true;
3416
+ try {
3417
+ fn();
3418
+ } finally {
3419
+ isBatch = false;
3420
+ execute();
3006
3421
  }
3007
- }
3422
+ };
3008
3423
 
3009
- module.exports = Watchpack;
3424
+ module.exports.createHandleChangeEvent = createHandleChangeEvent;
3425
+
3426
+ module.exports.getNumberOfWatchers = () => watcherCount;
3427
+
3428
+ /**
3429
+ * @param {string} filePath a file path
3430
+ * @returns {Watcher} watcher
3431
+ */
3432
+ module.exports.watch = (filePath) => {
3433
+ const watcher = new Watcher();
3434
+ // Find an existing watcher
3435
+ const directWatcher = directWatchers.get(filePath);
3436
+ if (directWatcher !== undefined) {
3437
+ directWatcher.add(watcher);
3438
+ return watcher;
3439
+ }
3440
+ let current = filePath;
3441
+ for (;;) {
3442
+ const recursiveWatcher = recursiveWatchers.get(current);
3443
+ if (recursiveWatcher !== undefined) {
3444
+ recursiveWatcher.add(filePath, watcher);
3445
+ return watcher;
3446
+ }
3447
+ const parent = path.dirname(current);
3448
+ if (parent === current) break;
3449
+ current = parent;
3450
+ }
3451
+ // Queue up watcher for creation
3452
+ pendingWatchers.set(watcher, filePath);
3453
+ if (!isBatch) execute();
3454
+ return watcher;
3455
+ };
3456
+
3457
+ module.exports.watcherLimit = watcherLimit;
3010
3458
 
3011
3459
 
3012
3460
  /***/ }),
@@ -3117,7 +3565,7 @@ module.exports = require("util");
3117
3565
  /******/ // startup
3118
3566
  /******/ // Load entry module and return exports
3119
3567
  /******/ // This entry module is referenced by other modules so it can't be inlined
3120
- /******/ var __webpack_exports__ = __nccwpck_require__(851);
3568
+ /******/ var __webpack_exports__ = __nccwpck_require__(17);
3121
3569
  /******/ module.exports = __webpack_exports__;
3122
3570
  /******/
3123
3571
  /******/ })()