@lvce-editor/file-watcher-process 4.13.0 → 4.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +97 -46
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
2
2
|
import * as fs from 'node:fs/promises';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
3
4
|
import { FSWatcher } from 'chokidar';
|
|
4
|
-
import
|
|
5
|
+
import ignore from 'ignore';
|
|
6
|
+
import { join, relative } from 'node:path';
|
|
5
7
|
|
|
6
8
|
const handleUncaughtExceptionMonitor = error => {
|
|
7
9
|
console.error(`[file-watcher-process] Uncaught Exception: ${error}`);
|
|
@@ -1253,7 +1255,7 @@ const normalizeEvent = (eventName, path) => {
|
|
|
1253
1255
|
};
|
|
1254
1256
|
};
|
|
1255
1257
|
|
|
1256
|
-
const waitForWatcherToBeReady = async watcher => {
|
|
1258
|
+
const waitForWatcherToBeReady = async (watcher, signal) => {
|
|
1257
1259
|
const {
|
|
1258
1260
|
promise,
|
|
1259
1261
|
reject,
|
|
@@ -1262,6 +1264,7 @@ const waitForWatcherToBeReady = async watcher => {
|
|
|
1262
1264
|
const cleanup = () => {
|
|
1263
1265
|
watcher.off('ready', handleReady);
|
|
1264
1266
|
watcher.off('error', handleError);
|
|
1267
|
+
signal?.removeEventListener('abort', handleAbort);
|
|
1265
1268
|
};
|
|
1266
1269
|
const handleReady = () => {
|
|
1267
1270
|
cleanup();
|
|
@@ -1271,6 +1274,13 @@ const waitForWatcherToBeReady = async watcher => {
|
|
|
1271
1274
|
cleanup();
|
|
1272
1275
|
reject(error);
|
|
1273
1276
|
};
|
|
1277
|
+
const handleAbort = () => {
|
|
1278
|
+
handleError(signal?.reason);
|
|
1279
|
+
};
|
|
1280
|
+
signal?.throwIfAborted();
|
|
1281
|
+
signal?.addEventListener('abort', handleAbort, {
|
|
1282
|
+
once: true
|
|
1283
|
+
});
|
|
1274
1284
|
watcher.on('ready', handleReady);
|
|
1275
1285
|
watcher.on('error', handleError);
|
|
1276
1286
|
await promise;
|
|
@@ -1324,7 +1334,7 @@ const callBackInternal = async (eventName, path, stats) => {
|
|
|
1324
1334
|
const callback = (eventName, path, stats) => {
|
|
1325
1335
|
void callBackInternal(eventName, path);
|
|
1326
1336
|
};
|
|
1327
|
-
const errorCallback
|
|
1337
|
+
const errorCallback = error => {
|
|
1328
1338
|
console.error(`[file-watcher-process] ${error}`);
|
|
1329
1339
|
};
|
|
1330
1340
|
const watchFolder = async uri => {
|
|
@@ -1333,7 +1343,7 @@ const watchFolder = async uri => {
|
|
|
1333
1343
|
const path = fileURLToPath(uri);
|
|
1334
1344
|
watcher = new FSWatcher();
|
|
1335
1345
|
watcher.on('all', callback);
|
|
1336
|
-
watcher.on('error', errorCallback
|
|
1346
|
+
watcher.on('error', errorCallback);
|
|
1337
1347
|
const readyPromise = waitForWatcherToBeReady(watcher);
|
|
1338
1348
|
watcher.add(path);
|
|
1339
1349
|
await readyPromise;
|
|
@@ -1388,43 +1398,99 @@ const normalizeEvent2 = (id, eventName, path) => {
|
|
|
1388
1398
|
};
|
|
1389
1399
|
};
|
|
1390
1400
|
|
|
1391
|
-
const
|
|
1392
|
-
|
|
1401
|
+
const createIgnore = ignore;
|
|
1402
|
+
const loadGitIgnore = async (root, enabled) => {
|
|
1403
|
+
try {
|
|
1404
|
+
const content = await readFile(`${root}/.gitignore`, 'utf8');
|
|
1405
|
+
return createIgnore().add(content);
|
|
1406
|
+
} catch {
|
|
1407
|
+
return undefined;
|
|
1408
|
+
}
|
|
1393
1409
|
};
|
|
1394
|
-
const
|
|
1410
|
+
const createExcludedNamesFilter = exclude => {
|
|
1395
1411
|
const excludedNames = new Set(exclude);
|
|
1396
|
-
return path =>
|
|
1397
|
-
|
|
1412
|
+
return path => path.split(/[\\/]/).some(part => excludedNames.has(part));
|
|
1413
|
+
};
|
|
1414
|
+
const createIgnored = async (root, exclude, useGitIgnore) => {
|
|
1415
|
+
const isExcludedName = createExcludedNamesFilter(exclude);
|
|
1416
|
+
const gitIgnore = await loadGitIgnore(root);
|
|
1417
|
+
return (path, stats) => {
|
|
1418
|
+
if (isExcludedName(path)) {
|
|
1419
|
+
return true;
|
|
1420
|
+
}
|
|
1421
|
+
if (!gitIgnore) {
|
|
1422
|
+
return false;
|
|
1423
|
+
}
|
|
1424
|
+
const relativePath = relative(root, path).replaceAll('\\', '/');
|
|
1425
|
+
if (!relativePath || relativePath.startsWith('../')) {
|
|
1426
|
+
return false;
|
|
1427
|
+
}
|
|
1428
|
+
const candidate = stats?.isDirectory() ? `${relativePath}/` : relativePath;
|
|
1429
|
+
return gitIgnore.ignores(candidate);
|
|
1398
1430
|
};
|
|
1399
1431
|
};
|
|
1432
|
+
const send = event => {
|
|
1433
|
+
void invoke('FileWatcher.handleChange', event).catch(error => {
|
|
1434
|
+
console.error(`[file-watcher-process] ${error}`);
|
|
1435
|
+
});
|
|
1436
|
+
};
|
|
1400
1437
|
const watchFolders = async ({
|
|
1401
1438
|
exclude,
|
|
1402
1439
|
id,
|
|
1403
|
-
roots
|
|
1440
|
+
roots,
|
|
1441
|
+
useGitIgnore = false
|
|
1404
1442
|
}) => {
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1443
|
+
if (has(id)) {
|
|
1444
|
+
return fromError(new Error(`watcher ${id} is already registered`));
|
|
1445
|
+
}
|
|
1446
|
+
const controller = new AbortController();
|
|
1447
|
+
const watcherEntries = [];
|
|
1448
|
+
let ready = false;
|
|
1449
|
+
let closing;
|
|
1450
|
+
const callback = (eventName, path) => {
|
|
1451
|
+
if (!controller.signal.aborted) {
|
|
1452
|
+
send(normalizeEvent2(id, eventName, path));
|
|
1453
|
+
}
|
|
1413
1454
|
};
|
|
1414
|
-
const
|
|
1415
|
-
|
|
1455
|
+
const errorCallback = error => {
|
|
1456
|
+
console.error(`[file-watcher-process] ${error}`);
|
|
1457
|
+
if (controller.signal.aborted) return;
|
|
1458
|
+
if (ready) {
|
|
1459
|
+
send({
|
|
1460
|
+
...fromError(error),
|
|
1461
|
+
eventName: 'error',
|
|
1462
|
+
id,
|
|
1463
|
+
uri: ''
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1466
|
+
controller.abort(error);
|
|
1416
1467
|
};
|
|
1417
|
-
|
|
1468
|
+
controller.signal.addEventListener('abort', () => {
|
|
1469
|
+
remove(id);
|
|
1470
|
+
closing = Promise.allSettled(watcherEntries.map(({
|
|
1471
|
+
watcher
|
|
1472
|
+
}) => watcher.close()));
|
|
1473
|
+
}, {
|
|
1474
|
+
once: true
|
|
1475
|
+
});
|
|
1476
|
+
// Register before asynchronous setup so disposal also cancels a pending watch.
|
|
1477
|
+
add(id, controller);
|
|
1418
1478
|
try {
|
|
1419
1479
|
for (const root of roots) {
|
|
1480
|
+
controller.signal.throwIfAborted();
|
|
1420
1481
|
const path = fileURLToPath(root);
|
|
1482
|
+
const ignored = useGitIgnore ? await createIgnored(path, exclude, true) : createExcludedNamesFilter(exclude);
|
|
1483
|
+
controller.signal.throwIfAborted();
|
|
1421
1484
|
const watcher = new FSWatcher({
|
|
1422
|
-
ignored
|
|
1485
|
+
ignored,
|
|
1423
1486
|
ignoreInitial: true,
|
|
1424
|
-
ignorePermissionErrors:
|
|
1487
|
+
ignorePermissionErrors: false
|
|
1425
1488
|
});
|
|
1426
1489
|
watcher.on('error', errorCallback);
|
|
1427
|
-
|
|
1490
|
+
watcher.on('all', callback);
|
|
1491
|
+
const readyPromise = waitForWatcherToBeReady(watcher, controller.signal);
|
|
1492
|
+
// Later roots can fail before Promise.all is reached.
|
|
1493
|
+
void readyPromise.catch(() => {});
|
|
1428
1494
|
watcherEntries.push({
|
|
1429
1495
|
readyPromise,
|
|
1430
1496
|
watcher
|
|
@@ -1434,31 +1500,16 @@ const watchFolders = async ({
|
|
|
1434
1500
|
await Promise.all(watcherEntries.map(({
|
|
1435
1501
|
readyPromise
|
|
1436
1502
|
}) => readyPromise));
|
|
1503
|
+
controller.signal.throwIfAborted();
|
|
1504
|
+
ready = true;
|
|
1505
|
+
const inotifyWatchCount = await getInotifyWatchCount();
|
|
1506
|
+
controller.signal.throwIfAborted();
|
|
1507
|
+
return inotifyWatchCount === undefined ? success : successWithInotifyWatchCount(inotifyWatchCount);
|
|
1437
1508
|
} catch (error) {
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
}) => watcher.close()));
|
|
1509
|
+
controller.abort(error);
|
|
1510
|
+
await closing;
|
|
1441
1511
|
return fromError(error);
|
|
1442
1512
|
}
|
|
1443
|
-
for (const {
|
|
1444
|
-
watcher
|
|
1445
|
-
} of watcherEntries) {
|
|
1446
|
-
watcher.on('all', callback);
|
|
1447
|
-
}
|
|
1448
|
-
const controller = new AbortController();
|
|
1449
|
-
controller.signal.addEventListener('abort', () => {
|
|
1450
|
-
void Promise.allSettled(watcherEntries.map(({
|
|
1451
|
-
watcher
|
|
1452
|
-
}) => watcher.close()));
|
|
1453
|
-
}, {
|
|
1454
|
-
once: true
|
|
1455
|
-
});
|
|
1456
|
-
add(id, controller);
|
|
1457
|
-
const inotifyWatchCount = await getInotifyWatchCount();
|
|
1458
|
-
if (inotifyWatchCount === undefined) {
|
|
1459
|
-
return success;
|
|
1460
|
-
}
|
|
1461
|
-
return successWithInotifyWatchCount(inotifyWatchCount);
|
|
1462
1513
|
};
|
|
1463
1514
|
|
|
1464
1515
|
const commandMap = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvce-editor/file-watcher-process",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.14.1",
|
|
4
4
|
"description": "File Watcher Process",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Lvce Editor",
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@lvce-editor/assert": "^1.5.1",
|
|
22
|
-
"chokidar": "^5.0.0"
|
|
22
|
+
"chokidar": "^5.0.0",
|
|
23
|
+
"ignore": "^5.3.2"
|
|
23
24
|
},
|
|
24
25
|
"engines": {
|
|
25
26
|
"node": ">=22"
|