@ms-cloudpack/file-watcher 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/lib/BaseWatcher.d.ts +22 -0
- package/lib/BaseWatcher.d.ts.map +1 -0
- package/lib/BaseWatcher.js +59 -0
- package/lib/BaseWatcher.js.map +1 -0
- package/lib/DefaultWatcher.d.ts +9 -0
- package/lib/DefaultWatcher.d.ts.map +1 -0
- package/lib/DefaultWatcher.js +46 -0
- package/lib/DefaultWatcher.js.map +1 -0
- package/lib/ForkWatcher.d.ts +15 -0
- package/lib/ForkWatcher.d.ts.map +1 -0
- package/lib/ForkWatcher.js +54 -0
- package/lib/ForkWatcher.js.map +1 -0
- package/lib/createWatcher.d.ts +11 -10
- package/lib/createWatcher.d.ts.map +1 -1
- package/lib/createWatcher.js +9 -43
- package/lib/createWatcher.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/types/WatchMessages.d.ts +25 -0
- package/lib/types/WatchMessages.d.ts.map +1 -0
- package/lib/types/WatchMessages.js +2 -0
- package/lib/types/WatchMessages.js.map +1 -0
- package/lib/types/Watcher.d.ts +36 -0
- package/lib/types/Watcher.d.ts.map +1 -0
- package/lib/types/Watcher.js +2 -0
- package/lib/types/Watcher.js.map +1 -0
- package/lib/watcherForkWrapper.d.ts +2 -0
- package/lib/watcherForkWrapper.d.ts.map +1 -0
- package/lib/watcherForkWrapper.js +38 -0
- package/lib/watcherForkWrapper.js.map +1 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -16,19 +16,22 @@ const watcher = createWatcher();
|
|
|
16
16
|
const unwatch = watcher.watch({ path: 'path/to/package' }, () => console.log(`package changed`));
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
3. To dispose, call the returned `unwatch`, or call `watcher.
|
|
19
|
+
3. To dispose, call the returned `unwatch`, or call `watcher.dispose` to unsubscribe from all watchers.
|
|
20
20
|
|
|
21
21
|
```ts
|
|
22
22
|
// Dispose an individual watcher.
|
|
23
23
|
await unwatch();
|
|
24
24
|
|
|
25
25
|
// Dispose all watchers.
|
|
26
|
-
await watcher.
|
|
26
|
+
await watcher.dispose();
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
### `createWatcher` options
|
|
30
|
+
|
|
31
|
+
- `type` (`'default' | 'fork'`, optional): By default, this will create a watcher in the same thread. Use `type: 'fork'` to create the watcher in a forked process.
|
|
32
|
+
|
|
29
33
|
### `watcher.watch` options
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
| `watchedPaths` | string[] | Relative paths from the base path to watch. Defaults to `package.json` and `src/` folder. |
|
|
35
|
+
- `path` (`string`): The absolute root path to be watched.
|
|
36
|
+
- `id` (`string`, optional): ID for the watch job (defaults to `path`). If you call `watch` twice using the same `id`, subsequent calls will be ignored.
|
|
37
|
+
- `watchedPaths` (`string[]`, optional): Relative paths/globs from the root path to watch. Defaults to `*.json` and `src/**/*`, excluding `node_modules`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { UnwatchCallback, WatchChangeCallback, Watcher, WatchOptions, WatchOptionsWithId } from './types/Watcher.js';
|
|
2
|
+
/**
|
|
3
|
+
* Base class for watcher implementations.
|
|
4
|
+
*/
|
|
5
|
+
export declare abstract class BaseWatcher implements Watcher {
|
|
6
|
+
/** Watcher is disposed or disposing */
|
|
7
|
+
private _disposeCalled;
|
|
8
|
+
/** Mapping from ID to change callback */
|
|
9
|
+
protected _onChangeCallbacks: Record<string, WatchChangeCallback>;
|
|
10
|
+
/** Mapping from ID to unwatch callback */
|
|
11
|
+
private _unwatchCallbacks;
|
|
12
|
+
/** Number of IDs currently being watched (just used for testing) */
|
|
13
|
+
get activeWatchCount(): number;
|
|
14
|
+
watch(baseOptions: WatchOptions, onChange: WatchChangeCallback): UnwatchCallback;
|
|
15
|
+
unwatch(id: string): Promise<void>;
|
|
16
|
+
dispose(): Promise<void>;
|
|
17
|
+
protected abstract _watch(options: WatchOptionsWithId, onChange: WatchChangeCallback): UnwatchCallback;
|
|
18
|
+
/** By default, calls all the unwatch callbacks. Override for custom dispose logic. */
|
|
19
|
+
protected _dispose(): Promise<void>;
|
|
20
|
+
protected _isDisposed(): boolean;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=BaseWatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseWatcher.d.ts","sourceRoot":"","sources":["../src/BaseWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACnB,OAAO,EACP,YAAY,EACZ,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAE5B;;GAEG;AACH,8BAAsB,WAAY,YAAW,OAAO;IAClD,uCAAuC;IACvC,OAAO,CAAC,cAAc,CAAS;IAC/B,yCAAyC;IACzC,SAAS,CAAC,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAM;IACvE,0CAA0C;IAC1C,OAAO,CAAC,iBAAiB,CAAuC;IAEhE,oEAAoE;IACpE,IAAW,gBAAgB,IAAI,MAAM,CAEpC;IAEM,KAAK,CAAC,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,mBAAmB,GAAG,eAAe;IA8B1E,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAOrC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,mBAAmB,GAAG,eAAe;IAEtG,sFAAsF;cACtE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAIzC,SAAS,CAAC,WAAW,IAAI,OAAO;CAGjC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base class for watcher implementations.
|
|
3
|
+
*/
|
|
4
|
+
export class BaseWatcher {
|
|
5
|
+
constructor() {
|
|
6
|
+
/** Watcher is disposed or disposing */
|
|
7
|
+
this._disposeCalled = false;
|
|
8
|
+
/** Mapping from ID to change callback */
|
|
9
|
+
this._onChangeCallbacks = {};
|
|
10
|
+
/** Mapping from ID to unwatch callback */
|
|
11
|
+
this._unwatchCallbacks = {};
|
|
12
|
+
}
|
|
13
|
+
/** Number of IDs currently being watched (just used for testing) */
|
|
14
|
+
get activeWatchCount() {
|
|
15
|
+
return Object.keys(this._unwatchCallbacks).length;
|
|
16
|
+
}
|
|
17
|
+
watch(baseOptions, onChange) {
|
|
18
|
+
if (this._isDisposed()) {
|
|
19
|
+
throw new Error('Watcher has been disposed.');
|
|
20
|
+
}
|
|
21
|
+
const { id = baseOptions.path } = baseOptions;
|
|
22
|
+
if (!this._unwatchCallbacks[id]) {
|
|
23
|
+
this._onChangeCallbacks[id] = onChange;
|
|
24
|
+
// Watch the path using the child class's implementation
|
|
25
|
+
const unwatch = this._watch({ ...baseOptions, id }, onChange);
|
|
26
|
+
// Make an unwatch wrapper to clean up parent class state
|
|
27
|
+
let calledUnwatch = false;
|
|
28
|
+
this._unwatchCallbacks[id] = async () => {
|
|
29
|
+
// The same unwatch callback might be returned multiple times in case of duplicate calls
|
|
30
|
+
// for the same ID. Only do the cleanup once.
|
|
31
|
+
if (!calledUnwatch) {
|
|
32
|
+
calledUnwatch = true;
|
|
33
|
+
await unwatch();
|
|
34
|
+
delete this._unwatchCallbacks[id];
|
|
35
|
+
delete this._onChangeCallbacks[id];
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return this._unwatchCallbacks[id];
|
|
40
|
+
}
|
|
41
|
+
async unwatch(id) {
|
|
42
|
+
// The wrapper code at the callback definition in watch() handles cleanup of callback records.
|
|
43
|
+
await this._unwatchCallbacks[id]?.();
|
|
44
|
+
}
|
|
45
|
+
async dispose() {
|
|
46
|
+
this._disposeCalled = true;
|
|
47
|
+
await this._dispose();
|
|
48
|
+
this._unwatchCallbacks = {};
|
|
49
|
+
this._onChangeCallbacks = {};
|
|
50
|
+
}
|
|
51
|
+
/** By default, calls all the unwatch callbacks. Override for custom dispose logic. */
|
|
52
|
+
async _dispose() {
|
|
53
|
+
await Promise.all(Object.values(this._unwatchCallbacks).map((unwatch) => unwatch()));
|
|
54
|
+
}
|
|
55
|
+
_isDisposed() {
|
|
56
|
+
return this._disposeCalled;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=BaseWatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseWatcher.js","sourceRoot":"","sources":["../src/BaseWatcher.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,OAAgB,WAAW;IAAjC;QACE,uCAAuC;QAC/B,mBAAc,GAAG,KAAK,CAAC;QAC/B,yCAAyC;QAC/B,uBAAkB,GAAwC,EAAE,CAAC;QACvE,0CAA0C;QAClC,sBAAiB,GAAoC,EAAE,CAAC;IA2DlE,CAAC;IAzDC,oEAAoE;IACpE,IAAW,gBAAgB;QACzB,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC;IACpD,CAAC;IAEM,KAAK,CAAC,WAAyB,EAAE,QAA6B;QACnE,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QAED,MAAM,EAAE,EAAE,GAAG,WAAW,CAAC,IAAI,EAAE,GAAG,WAAW,CAAC;QAE9C,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,EAAE,CAAC;YAChC,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC;YAEvC,wDAAwD;YACxD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,WAAW,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;YAE9D,yDAAyD;YACzD,IAAI,aAAa,GAAG,KAAK,CAAC;YAC1B,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,GAAG,KAAK,IAAI,EAAE;gBACtC,wFAAwF;gBACxF,6CAA6C;gBAC7C,IAAI,CAAC,aAAa,EAAE,CAAC;oBACnB,aAAa,GAAG,IAAI,CAAC;oBACrB,MAAM,OAAO,EAAE,CAAC;oBAChB,OAAO,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;oBAClC,OAAO,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;gBACrC,CAAC;YACH,CAAC,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,EAAU;QAC7B,8FAA8F;QAC9F,MAAM,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACvC,CAAC;IAEM,KAAK,CAAC,OAAO;QAClB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACtB,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAC;QAC5B,IAAI,CAAC,kBAAkB,GAAG,EAAE,CAAC;IAC/B,CAAC;IAID,sFAAsF;IAC5E,KAAK,CAAC,QAAQ;QACtB,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACvF,CAAC;IAES,WAAW;QACnB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;CACF","sourcesContent":["import type {\n UnwatchCallback,\n WatchChangeCallback,\n Watcher,\n WatchOptions,\n WatchOptionsWithId,\n} from './types/Watcher.js';\n\n/**\n * Base class for watcher implementations.\n */\nexport abstract class BaseWatcher implements Watcher {\n /** Watcher is disposed or disposing */\n private _disposeCalled = false;\n /** Mapping from ID to change callback */\n protected _onChangeCallbacks: Record<string, WatchChangeCallback> = {};\n /** Mapping from ID to unwatch callback */\n private _unwatchCallbacks: Record<string, UnwatchCallback> = {};\n\n /** Number of IDs currently being watched (just used for testing) */\n public get activeWatchCount(): number {\n return Object.keys(this._unwatchCallbacks).length;\n }\n\n public watch(baseOptions: WatchOptions, onChange: WatchChangeCallback): UnwatchCallback {\n if (this._isDisposed()) {\n throw new Error('Watcher has been disposed.');\n }\n\n const { id = baseOptions.path } = baseOptions;\n\n if (!this._unwatchCallbacks[id]) {\n this._onChangeCallbacks[id] = onChange;\n\n // Watch the path using the child class's implementation\n const unwatch = this._watch({ ...baseOptions, id }, onChange);\n\n // Make an unwatch wrapper to clean up parent class state\n let calledUnwatch = false;\n this._unwatchCallbacks[id] = async () => {\n // The same unwatch callback might be returned multiple times in case of duplicate calls\n // for the same ID. Only do the cleanup once.\n if (!calledUnwatch) {\n calledUnwatch = true;\n await unwatch();\n delete this._unwatchCallbacks[id];\n delete this._onChangeCallbacks[id];\n }\n };\n }\n\n return this._unwatchCallbacks[id];\n }\n\n public async unwatch(id: string): Promise<void> {\n // The wrapper code at the callback definition in watch() handles cleanup of callback records.\n await this._unwatchCallbacks[id]?.();\n }\n\n public async dispose(): Promise<void> {\n this._disposeCalled = true;\n await this._dispose();\n this._unwatchCallbacks = {};\n this._onChangeCallbacks = {};\n }\n\n protected abstract _watch(options: WatchOptionsWithId, onChange: WatchChangeCallback): UnwatchCallback;\n\n /** By default, calls all the unwatch callbacks. Override for custom dispose logic. */\n protected async _dispose(): Promise<void> {\n await Promise.all(Object.values(this._unwatchCallbacks).map((unwatch) => unwatch()));\n }\n\n protected _isDisposed(): boolean {\n return this._disposeCalled;\n }\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { UnwatchCallback, WatchChangeCallback, WatchOptionsWithId } from './types/Watcher.js';
|
|
2
|
+
import { BaseWatcher } from './BaseWatcher.js';
|
|
3
|
+
/**
|
|
4
|
+
* Watch for changes using chokidar in the current process.
|
|
5
|
+
*/
|
|
6
|
+
export declare class DefaultWatcher extends BaseWatcher {
|
|
7
|
+
protected _watch(options: WatchOptionsWithId, onChange: WatchChangeCallback): UnwatchCallback;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=DefaultWatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultWatcher.d.ts","sourceRoot":"","sources":["../src/DefaultWatcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACnG,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAI/C;;GAEG;AACH,qBAAa,cAAe,SAAQ,WAAW;IAI7C,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,mBAAmB,GAAG,eAAe;CAkB9F"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import chokidar from 'chokidar';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { BaseWatcher } from './BaseWatcher.js';
|
|
4
|
+
const defaultWatchPaths = ['src/**/*', '*.json', '!**/node_modules/**/*'];
|
|
5
|
+
/**
|
|
6
|
+
* Watch for changes using chokidar in the current process.
|
|
7
|
+
*/
|
|
8
|
+
export class DefaultWatcher extends BaseWatcher {
|
|
9
|
+
// TODO: Ideally if this is called multiple times with a different ID but the same root path and
|
|
10
|
+
// same watch paths, a single chokidar watcher should be created and shared. But this involves a
|
|
11
|
+
// lot of extra tracking logic and isn't essential until SSR is actually being used in an app.
|
|
12
|
+
_watch(options, onChange) {
|
|
13
|
+
const { path: rootPath, watchPaths = defaultWatchPaths } = options;
|
|
14
|
+
const { positiveGlobs, negativeGlobs } = separateGlobs(watchPaths);
|
|
15
|
+
const paths = positiveGlobs.map((relPath) => path.resolve(rootPath, relPath));
|
|
16
|
+
const ignored = negativeGlobs.map((relPath) => path.resolve(rootPath, relPath));
|
|
17
|
+
// For efficiency, don't follow symlinks, and don't send 'add' events after the initial scan.
|
|
18
|
+
let watcher = chokidar
|
|
19
|
+
.watch(paths, { ignored, followSymlinks: false, ignoreInitial: true })
|
|
20
|
+
.on('change', (filePath) => {
|
|
21
|
+
onChange(filePath);
|
|
22
|
+
});
|
|
23
|
+
return async () => {
|
|
24
|
+
await watcher?.close();
|
|
25
|
+
watcher = undefined;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* This function separates positive and negative globs to later on ignore the negative ones.
|
|
31
|
+
* This is necessary because chokidar does not support negative globs well.
|
|
32
|
+
*/
|
|
33
|
+
function separateGlobs(globs) {
|
|
34
|
+
const positiveGlobs = [];
|
|
35
|
+
const negativeGlobs = [];
|
|
36
|
+
for (const glob of globs) {
|
|
37
|
+
if (glob.startsWith('!')) {
|
|
38
|
+
negativeGlobs.push(glob.slice(1));
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
positiveGlobs.push(glob);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return { positiveGlobs, negativeGlobs };
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=DefaultWatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultWatcher.js","sourceRoot":"","sources":["../src/DefaultWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,QAA4B,MAAM,UAAU,CAAC;AACpD,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,MAAM,iBAAiB,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,uBAAuB,CAAC,CAAC;AAE1E;;GAEG;AACH,MAAM,OAAO,cAAe,SAAQ,WAAW;IAC7C,gGAAgG;IAChG,gGAAgG;IAChG,8FAA8F;IACpF,MAAM,CAAC,OAA2B,EAAE,QAA6B;QACzE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,GAAG,iBAAiB,EAAE,GAAG,OAAO,CAAC;QACnE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;QACnE,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;QAC9E,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;QAEhF,6FAA6F;QAC7F,IAAI,OAAO,GAA0B,QAAQ;aAC1C,KAAK,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;aACrE,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE;YACzB,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QAEL,OAAO,KAAK,IAAI,EAAE;YAChB,MAAM,OAAO,EAAE,KAAK,EAAE,CAAC;YACvB,OAAO,GAAG,SAAS,CAAC;QACtB,CAAC,CAAC;IACJ,CAAC;CACF;AAED;;;GAGG;AACH,SAAS,aAAa,CAAC,KAAe;IACpC,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,MAAM,aAAa,GAAa,EAAE,CAAC;IAEnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC;AAC1C,CAAC","sourcesContent":["import chokidar, { type FSWatcher } from 'chokidar';\nimport path from 'path';\nimport type { UnwatchCallback, WatchChangeCallback, WatchOptionsWithId } from './types/Watcher.js';\nimport { BaseWatcher } from './BaseWatcher.js';\n\nconst defaultWatchPaths = ['src/**/*', '*.json', '!**/node_modules/**/*'];\n\n/**\n * Watch for changes using chokidar in the current process.\n */\nexport class DefaultWatcher extends BaseWatcher {\n // TODO: Ideally if this is called multiple times with a different ID but the same root path and\n // same watch paths, a single chokidar watcher should be created and shared. But this involves a\n // lot of extra tracking logic and isn't essential until SSR is actually being used in an app.\n protected _watch(options: WatchOptionsWithId, onChange: WatchChangeCallback): UnwatchCallback {\n const { path: rootPath, watchPaths = defaultWatchPaths } = options;\n const { positiveGlobs, negativeGlobs } = separateGlobs(watchPaths);\n const paths = positiveGlobs.map((relPath) => path.resolve(rootPath, relPath));\n const ignored = negativeGlobs.map((relPath) => path.resolve(rootPath, relPath));\n\n // For efficiency, don't follow symlinks, and don't send 'add' events after the initial scan.\n let watcher: FSWatcher | undefined = chokidar\n .watch(paths, { ignored, followSymlinks: false, ignoreInitial: true })\n .on('change', (filePath) => {\n onChange(filePath);\n });\n\n return async () => {\n await watcher?.close();\n watcher = undefined;\n };\n }\n}\n\n/**\n * This function separates positive and negative globs to later on ignore the negative ones.\n * This is necessary because chokidar does not support negative globs well.\n */\nfunction separateGlobs(globs: string[]): { positiveGlobs: string[]; negativeGlobs: string[] } {\n const positiveGlobs: string[] = [];\n const negativeGlobs: string[] = [];\n\n for (const glob of globs) {\n if (glob.startsWith('!')) {\n negativeGlobs.push(glob.slice(1));\n } else {\n positiveGlobs.push(glob);\n }\n }\n\n return { positiveGlobs, negativeGlobs };\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { UnwatchCallback, WatchOptions } from './types/Watcher.js';
|
|
2
|
+
import { BaseWatcher } from './BaseWatcher.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a watcher in a fork which can watch a package and notify the client when it changes.
|
|
5
|
+
*/
|
|
6
|
+
export declare class ForkWatcher extends BaseWatcher {
|
|
7
|
+
private _child;
|
|
8
|
+
constructor();
|
|
9
|
+
protected _watch(options: Required<WatchOptions>): UnwatchCallback;
|
|
10
|
+
protected _dispose(): Promise<void>;
|
|
11
|
+
protected _isDisposed(): boolean;
|
|
12
|
+
/** Typed wrapper for `this._child.send()`. No-op if `_child` is disposed. */
|
|
13
|
+
private _sendMessage;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=ForkWatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForkWatcher.d.ts","sourceRoot":"","sources":["../src/ForkWatcher.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAK/C;;GAEG;AACH,qBAAa,WAAY,SAAQ,WAAW;IAC1C,OAAO,CAAC,MAAM,CAA2B;;IAyBzC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,eAAe;cAQlD,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAYzC,SAAS,CAAC,WAAW,IAAI,OAAO;IAIhC,6EAA6E;IAC7E,OAAO,CAAC,YAAY;CAGrB"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { fork } from 'child_process';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { BaseWatcher } from './BaseWatcher.js';
|
|
5
|
+
const currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const watcherForkWrapper = path.resolve(currentDir, 'watcherForkWrapper.js');
|
|
7
|
+
/**
|
|
8
|
+
* Creates a watcher in a fork which can watch a package and notify the client when it changes.
|
|
9
|
+
*/
|
|
10
|
+
export class ForkWatcher extends BaseWatcher {
|
|
11
|
+
constructor() {
|
|
12
|
+
super();
|
|
13
|
+
this._child = fork(watcherForkWrapper);
|
|
14
|
+
this._child.on('message', (message) => {
|
|
15
|
+
switch (message.type) {
|
|
16
|
+
case 'change':
|
|
17
|
+
if (this._isDisposed()) {
|
|
18
|
+
throw new Error('Watcher has been disposed.');
|
|
19
|
+
}
|
|
20
|
+
this._onChangeCallbacks[message.id]?.(message.changedPath);
|
|
21
|
+
break;
|
|
22
|
+
case 'error':
|
|
23
|
+
console.error(`An error occurred while watching files: ${message.error}`);
|
|
24
|
+
break;
|
|
25
|
+
default:
|
|
26
|
+
console.warn(`Unknown message type: ${JSON.stringify(message)}`);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
_watch(options) {
|
|
31
|
+
this._sendMessage({ type: 'watch', options });
|
|
32
|
+
return () => {
|
|
33
|
+
this._sendMessage({ type: 'unwatch', id: options.id });
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async _dispose() {
|
|
37
|
+
await new Promise((r) => {
|
|
38
|
+
if (!this._child) {
|
|
39
|
+
return r();
|
|
40
|
+
}
|
|
41
|
+
this._child.on('close', r);
|
|
42
|
+
this._sendMessage({ type: 'shutdown' });
|
|
43
|
+
this._child = undefined;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
_isDisposed() {
|
|
47
|
+
return !this._child || super._isDisposed();
|
|
48
|
+
}
|
|
49
|
+
/** Typed wrapper for `this._child.send()`. No-op if `_child` is disposed. */
|
|
50
|
+
_sendMessage(message) {
|
|
51
|
+
this._child?.send(message);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=ForkWatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForkWatcher.js","sourceRoot":"","sources":["../src/ForkWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,IAAI,EAAqB,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAGpC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChE,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,uBAAuB,CAAC,CAAC;AAE7E;;GAEG;AACH,MAAM,OAAO,WAAY,SAAQ,WAAW;IAG1C;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAEvC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAqB,EAAE,EAAE;YAClD,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;gBACrB,KAAK,QAAQ;oBACX,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;wBACvB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;oBAChD,CAAC;oBACD,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;oBAC3D,MAAM;gBAER,KAAK,OAAO;oBACV,OAAO,CAAC,KAAK,CAAC,2CAA2C,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;oBAC1E,MAAM;gBAER;oBACE,OAAO,CAAC,IAAI,CAAC,yBAAyB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACrE,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAES,MAAM,CAAC,OAA+B;QAC9C,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAE9C,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACzD,CAAC,CAAC;IACJ,CAAC;IAES,KAAK,CAAC,QAAQ;QACtB,MAAM,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE;YAC5B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,OAAO,CAAC,EAAE,CAAC;YACb,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAC3B,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;YACxC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC;IAES,WAAW;QACnB,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;IAC7C,CAAC;IAED,6EAA6E;IACrE,YAAY,CAAC,OAAsB;QACzC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;CACF","sourcesContent":["import path from 'path';\nimport { fork, type ChildProcess } from 'child_process';\nimport { fileURLToPath } from 'url';\nimport type { ChildMessage, ParentMessage } from './types/WatchMessages.js';\nimport type { UnwatchCallback, WatchOptions } from './types/Watcher.js';\nimport { BaseWatcher } from './BaseWatcher.js';\n\nconst currentDir = path.dirname(fileURLToPath(import.meta.url));\nconst watcherForkWrapper = path.resolve(currentDir, 'watcherForkWrapper.js');\n\n/**\n * Creates a watcher in a fork which can watch a package and notify the client when it changes.\n */\nexport class ForkWatcher extends BaseWatcher {\n private _child: ChildProcess | undefined;\n\n constructor() {\n super();\n this._child = fork(watcherForkWrapper);\n\n this._child.on('message', (message: ChildMessage) => {\n switch (message.type) {\n case 'change':\n if (this._isDisposed()) {\n throw new Error('Watcher has been disposed.');\n }\n this._onChangeCallbacks[message.id]?.(message.changedPath);\n break;\n\n case 'error':\n console.error(`An error occurred while watching files: ${message.error}`);\n break;\n\n default:\n console.warn(`Unknown message type: ${JSON.stringify(message)}`);\n }\n });\n }\n\n protected _watch(options: Required<WatchOptions>): UnwatchCallback {\n this._sendMessage({ type: 'watch', options });\n\n return () => {\n this._sendMessage({ type: 'unwatch', id: options.id });\n };\n }\n\n protected async _dispose(): Promise<void> {\n await new Promise<void>((r) => {\n if (!this._child) {\n return r();\n }\n\n this._child.on('close', r);\n this._sendMessage({ type: 'shutdown' });\n this._child = undefined;\n });\n }\n\n protected _isDisposed(): boolean {\n return !this._child || super._isDisposed();\n }\n\n /** Typed wrapper for `this._child.send()`. No-op if `_child` is disposed. */\n private _sendMessage(message: ParentMessage): void {\n this._child?.send(message);\n }\n}\n"]}
|
package/lib/createWatcher.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
path: string;
|
|
3
|
-
watchPaths?: string[];
|
|
4
|
-
}
|
|
5
|
-
export interface Watcher {
|
|
6
|
-
watch(options: WatchOptions, onPackageChanged: () => void): () => Promise<void>;
|
|
7
|
-
unwatchAll(): Promise<void>;
|
|
8
|
-
}
|
|
1
|
+
import type { Watcher } from './types/Watcher.js';
|
|
9
2
|
/**
|
|
10
|
-
*
|
|
3
|
+
* Create a file watcher. By default, the watcher will run in the main thread.
|
|
4
|
+
* Use `{ type: 'fork' }` to run the watcher in a forked process.
|
|
11
5
|
*/
|
|
12
|
-
export declare function createWatcher(
|
|
6
|
+
export declare function createWatcher(options?: {
|
|
7
|
+
/**
|
|
8
|
+
* By default, the watcher will run in the main thread.
|
|
9
|
+
* Specify `'fork'` to run the watcher in a forked process.
|
|
10
|
+
* @default 'default'
|
|
11
|
+
*/
|
|
12
|
+
type?: 'default' | 'fork';
|
|
13
|
+
}): Watcher;
|
|
13
14
|
//# sourceMappingURL=createWatcher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createWatcher.d.ts","sourceRoot":"","sources":["../src/createWatcher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"createWatcher.d.ts","sourceRoot":"","sources":["../src/createWatcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE;IACtC;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC3B,GAAG,OAAO,CAKV"}
|
package/lib/createWatcher.js
CHANGED
|
@@ -1,47 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
// TODO: This list of watched paths is hardcoded, but really it shouldn't be. In fact, this whole file
|
|
4
|
-
// probably shouldn't be here. I think lage should be responsible for understanding what "bundle" means
|
|
5
|
-
// (we can provide a definition) and what its inputs are and what it depends on. Then when we call
|
|
6
|
-
// ensurePackageBundled, lage can ensure watching is happening for the full graph of tasks.
|
|
7
|
-
const defaultWatchPaths = ['src/**', '*.json', '!**/node_modules/**'];
|
|
1
|
+
import { DefaultWatcher } from './DefaultWatcher.js';
|
|
2
|
+
import { ForkWatcher } from './ForkWatcher.js';
|
|
8
3
|
/**
|
|
9
|
-
*
|
|
4
|
+
* Create a file watcher. By default, the watcher will run in the main thread.
|
|
5
|
+
* Use `{ type: 'fork' }` to run the watcher in a forked process.
|
|
10
6
|
*/
|
|
11
|
-
export function createWatcher() {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const { path, watchPaths = defaultWatchPaths } = options;
|
|
17
|
-
const paths = watchPaths.map((relPath) => resolve(path, relPath)).filter((p) => !watchedPaths.has(p));
|
|
18
|
-
let watcher;
|
|
19
|
-
if (paths.length) {
|
|
20
|
-
// Add paths to watchedPaths to avoid watching them again.
|
|
21
|
-
paths.forEach((p) => watchedPaths.add(p));
|
|
22
|
-
// Watch source and register a handler which will rebundle the changed package and notify the client on
|
|
23
|
-
// success. Note that if failures happen, the client will receive the error notification automatically.
|
|
24
|
-
watcher = chokidar.watch(paths).on('change', onPackageChanged);
|
|
25
|
-
watchers.add(watcher);
|
|
26
|
-
}
|
|
27
|
-
// Return a dispose function to individually clean up.
|
|
28
|
-
return async () => {
|
|
29
|
-
if (watcher) {
|
|
30
|
-
const w = watcher;
|
|
31
|
-
watcher = undefined;
|
|
32
|
-
watchers.delete(w);
|
|
33
|
-
for (const watchedPath of paths) {
|
|
34
|
-
watchedPaths.delete(watchedPath);
|
|
35
|
-
}
|
|
36
|
-
await w.close();
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
},
|
|
40
|
-
async unwatchAll() {
|
|
41
|
-
await Promise.all(Array.from(watchers).map((w) => w.close()));
|
|
42
|
-
watchers.clear();
|
|
43
|
-
watchedPaths.clear();
|
|
44
|
-
},
|
|
45
|
-
};
|
|
7
|
+
export function createWatcher(options) {
|
|
8
|
+
if (options?.type === 'fork') {
|
|
9
|
+
return new ForkWatcher();
|
|
10
|
+
}
|
|
11
|
+
return new DefaultWatcher();
|
|
46
12
|
}
|
|
47
13
|
//# sourceMappingURL=createWatcher.js.map
|
package/lib/createWatcher.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createWatcher.js","sourceRoot":"","sources":["../src/createWatcher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"createWatcher.js","sourceRoot":"","sources":["../src/createWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,OAO7B;IACC,IAAI,OAAO,EAAE,IAAI,KAAK,MAAM,EAAE,CAAC;QAC7B,OAAO,IAAI,WAAW,EAAE,CAAC;IAC3B,CAAC;IACD,OAAO,IAAI,cAAc,EAAE,CAAC;AAC9B,CAAC","sourcesContent":["import { DefaultWatcher } from './DefaultWatcher.js';\nimport { ForkWatcher } from './ForkWatcher.js';\nimport type { Watcher } from './types/Watcher.js';\n\n/**\n * Create a file watcher. By default, the watcher will run in the main thread.\n * Use `{ type: 'fork' }` to run the watcher in a forked process.\n */\nexport function createWatcher(options?: {\n /**\n * By default, the watcher will run in the main thread.\n * Specify `'fork'` to run the watcher in a forked process.\n * @default 'default'\n */\n type?: 'default' | 'fork';\n}): Watcher {\n if (options?.type === 'fork') {\n return new ForkWatcher();\n }\n return new DefaultWatcher();\n}\n"]}
|
package/lib/index.d.ts
CHANGED
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC","sourcesContent":["export type { Watcher, WatchOptions } from './types/Watcher.js';\nexport { createWatcher } from './createWatcher.js';\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { WatchOptions, WatchOptionsWithId } from './Watcher.js';
|
|
2
|
+
type WatchMessage = {
|
|
3
|
+
type: 'watch';
|
|
4
|
+
options: Required<WatchOptions>;
|
|
5
|
+
};
|
|
6
|
+
type UnwatchMessage = Pick<WatchOptionsWithId, 'id'> & {
|
|
7
|
+
type: 'unwatch';
|
|
8
|
+
};
|
|
9
|
+
type ShutdownMessage = {
|
|
10
|
+
type: 'shutdown';
|
|
11
|
+
};
|
|
12
|
+
/** Message from the parent to the child in `ForkWatcher` */
|
|
13
|
+
export type ParentMessage = WatchMessage | UnwatchMessage | ShutdownMessage;
|
|
14
|
+
type ChangeMessage = Pick<WatchOptionsWithId, 'id'> & {
|
|
15
|
+
type: 'change';
|
|
16
|
+
changedPath: string;
|
|
17
|
+
};
|
|
18
|
+
type ErrorMessage = {
|
|
19
|
+
type: 'error';
|
|
20
|
+
error: Error;
|
|
21
|
+
};
|
|
22
|
+
/** Message from the child to the parent in `ForkWatcher` */
|
|
23
|
+
export type ChildMessage = ChangeMessage | ErrorMessage;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=WatchMessages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WatchMessages.d.ts","sourceRoot":"","sources":["../../src/types/WatchMessages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAErE,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;CACjC,CAAC;AAEF,KAAK,cAAc,GAAG,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,GAAG;IACrD,IAAI,EAAE,SAAS,CAAC;CACjB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,UAAU,CAAC;CAClB,CAAC;AAEF,4DAA4D;AAC5D,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,cAAc,GAAG,eAAe,CAAC;AAE5E,KAAK,aAAa,GAAG,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,GAAG;IACpD,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF,4DAA4D;AAC5D,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WatchMessages.js","sourceRoot":"","sources":["../../src/types/WatchMessages.ts"],"names":[],"mappings":"","sourcesContent":["import type { WatchOptions, WatchOptionsWithId } from './Watcher.js';\n\ntype WatchMessage = {\n type: 'watch';\n options: Required<WatchOptions>;\n};\n\ntype UnwatchMessage = Pick<WatchOptionsWithId, 'id'> & {\n type: 'unwatch';\n};\n\ntype ShutdownMessage = {\n type: 'shutdown';\n};\n\n/** Message from the parent to the child in `ForkWatcher` */\nexport type ParentMessage = WatchMessage | UnwatchMessage | ShutdownMessage;\n\ntype ChangeMessage = Pick<WatchOptionsWithId, 'id'> & {\n type: 'change';\n changedPath: string;\n};\n\ntype ErrorMessage = {\n type: 'error';\n error: Error;\n};\n\n/** Message from the child to the parent in `ForkWatcher` */\nexport type ChildMessage = ChangeMessage | ErrorMessage;\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface WatchOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Absolute path to the root directory where watching should happen.
|
|
4
|
+
*/
|
|
5
|
+
path: string;
|
|
6
|
+
/**
|
|
7
|
+
* ID for the watch job (defaults to `path`).
|
|
8
|
+
* If you call `watch` twice using the same `id`, subsequent calls will be ignored.
|
|
9
|
+
*/
|
|
10
|
+
id?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Path globs to watch, relative to `path`.
|
|
13
|
+
* Defaults to `['src/**', '*.json', '!**\/node_modules/**']`
|
|
14
|
+
*/
|
|
15
|
+
watchPaths?: string[];
|
|
16
|
+
}
|
|
17
|
+
export type WatchOptionsWithId = WatchOptions & Required<Pick<WatchOptions, 'id'>>;
|
|
18
|
+
/**
|
|
19
|
+
* Callback when a watched path changes.
|
|
20
|
+
* @param changedPath Absolute path to the file that changed.
|
|
21
|
+
*/
|
|
22
|
+
export type WatchChangeCallback = (changedPath: string) => void;
|
|
23
|
+
/** Callback to unwatch a path */
|
|
24
|
+
export type UnwatchCallback = () => void | Promise<void>;
|
|
25
|
+
export interface Watcher {
|
|
26
|
+
/**
|
|
27
|
+
* Watch a path for changes.
|
|
28
|
+
* @returns Callback to unwatch the path.
|
|
29
|
+
*/
|
|
30
|
+
watch(options: WatchOptions, onChange: WatchChangeCallback): UnwatchCallback;
|
|
31
|
+
/** Remove watchers for a specific ID (path) */
|
|
32
|
+
unwatch(id: string): Promise<void>;
|
|
33
|
+
/** Dispose all watchers. The Watcher object can't be reused afer this. */
|
|
34
|
+
dispose(): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=Watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Watcher.d.ts","sourceRoot":"","sources":["../../src/types/Watcher.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC;AAEnF;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;AAEhE,iCAAiC;AACjC,MAAM,MAAM,eAAe,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEzD,MAAM,WAAW,OAAO;IACtB;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,mBAAmB,GAAG,eAAe,CAAC;IAE7E,+CAA+C;IAC/C,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC,0EAA0E;IAC1E,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Watcher.js","sourceRoot":"","sources":["../../src/types/Watcher.ts"],"names":[],"mappings":"","sourcesContent":["export interface WatchOptions {\n /**\n * Absolute path to the root directory where watching should happen.\n */\n path: string;\n\n /**\n * ID for the watch job (defaults to `path`).\n * If you call `watch` twice using the same `id`, subsequent calls will be ignored.\n */\n id?: string;\n\n /**\n * Path globs to watch, relative to `path`.\n * Defaults to `['src/**', '*.json', '!**\\/node_modules/**']`\n */\n watchPaths?: string[];\n}\n\nexport type WatchOptionsWithId = WatchOptions & Required<Pick<WatchOptions, 'id'>>;\n\n/**\n * Callback when a watched path changes.\n * @param changedPath Absolute path to the file that changed.\n */\nexport type WatchChangeCallback = (changedPath: string) => void;\n\n/** Callback to unwatch a path */\nexport type UnwatchCallback = () => void | Promise<void>;\n\nexport interface Watcher {\n /**\n * Watch a path for changes.\n * @returns Callback to unwatch the path.\n */\n watch(options: WatchOptions, onChange: WatchChangeCallback): UnwatchCallback;\n\n /** Remove watchers for a specific ID (path) */\n unwatch(id: string): Promise<void>;\n\n /** Dispose all watchers. The Watcher object can't be reused afer this. */\n dispose(): Promise<void>;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcherForkWrapper.d.ts","sourceRoot":"","sources":["../src/watcherForkWrapper.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { DefaultWatcher } from './DefaultWatcher.js';
|
|
2
|
+
/**
|
|
3
|
+
* `ForkWatcher` runs this file to initialize the watcher in a child process.
|
|
4
|
+
*/
|
|
5
|
+
function initializeWatcher() {
|
|
6
|
+
const watcher = new DefaultWatcher();
|
|
7
|
+
process.on('message', (message) => {
|
|
8
|
+
(async () => {
|
|
9
|
+
switch (message.type) {
|
|
10
|
+
case 'watch':
|
|
11
|
+
{
|
|
12
|
+
watcher.watch(message.options, (changedPath) => {
|
|
13
|
+
sendMessage({ type: 'change', id: message.options.id, changedPath });
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
break;
|
|
17
|
+
case 'unwatch':
|
|
18
|
+
await watcher.unwatch(message.id);
|
|
19
|
+
break;
|
|
20
|
+
case 'shutdown':
|
|
21
|
+
await watcher.dispose();
|
|
22
|
+
// eslint-disable-next-line no-restricted-properties -- rule isn't relevant for exiting a child process
|
|
23
|
+
process.exit(0);
|
|
24
|
+
}
|
|
25
|
+
})().catch((error) => {
|
|
26
|
+
sendMessage({ type: 'error', error: error });
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/** Typed wrapper for `process.send()` */
|
|
31
|
+
function sendMessage(message) {
|
|
32
|
+
process.send?.(message);
|
|
33
|
+
}
|
|
34
|
+
// Prevent the process from exiting immediately.
|
|
35
|
+
// This is handled by the parent process instead with the shutdown message.
|
|
36
|
+
process.on('SIGINT', () => { });
|
|
37
|
+
initializeWatcher();
|
|
38
|
+
//# sourceMappingURL=watcherForkWrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcherForkWrapper.js","sourceRoot":"","sources":["../src/watcherForkWrapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD;;GAEG;AACH,SAAS,iBAAiB;IACxB,MAAM,OAAO,GAAG,IAAI,cAAc,EAAE,CAAC;IAErC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAsB,EAAE,EAAE;QAC/C,CAAC,KAAK,IAAI,EAAE;YACV,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;gBACrB,KAAK,OAAO;oBACV,CAAC;wBACC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,WAAW,EAAE,EAAE;4BAC7C,WAAW,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;wBACvE,CAAC,CAAC,CAAC;oBACL,CAAC;oBACD,MAAM;gBAER,KAAK,SAAS;oBACZ,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;oBAClC,MAAM;gBAER,KAAK,UAAU;oBACb,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;oBACxB,uGAAuG;oBACvG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;QACH,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACnB,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAc,EAAE,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,yCAAyC;AACzC,SAAS,WAAW,CAAC,OAAqB;IACxC,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC;AAC1B,CAAC;AAED,gDAAgD;AAChD,2EAA2E;AAC3E,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AAE/B,iBAAiB,EAAE,CAAC","sourcesContent":["import { DefaultWatcher } from './DefaultWatcher.js';\nimport type { ChildMessage, ParentMessage } from './types/WatchMessages.js';\n\n/**\n * `ForkWatcher` runs this file to initialize the watcher in a child process.\n */\nfunction initializeWatcher() {\n const watcher = new DefaultWatcher();\n\n process.on('message', (message: ParentMessage) => {\n (async () => {\n switch (message.type) {\n case 'watch':\n {\n watcher.watch(message.options, (changedPath) => {\n sendMessage({ type: 'change', id: message.options.id, changedPath });\n });\n }\n break;\n\n case 'unwatch':\n await watcher.unwatch(message.id);\n break;\n\n case 'shutdown':\n await watcher.dispose();\n // eslint-disable-next-line no-restricted-properties -- rule isn't relevant for exiting a child process\n process.exit(0);\n }\n })().catch((error) => {\n sendMessage({ type: 'error', error: error as Error });\n });\n });\n}\n\n/** Typed wrapper for `process.send()` */\nfunction sendMessage(message: ChildMessage) {\n process.send?.(message);\n}\n\n// Prevent the process from exiting immediately.\n// This is handled by the parent process instead with the shutdown message.\nprocess.on('SIGINT', () => {});\n\ninitializeWatcher();\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ms-cloudpack/file-watcher",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A file watcher abstraction for use with Cloudpack.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"chokidar": "^3.5.3"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
+
"@ms-cloudpack/environment": "*",
|
|
21
22
|
"@ms-cloudpack/eslint-plugin-internal": "^0.0.1",
|
|
22
23
|
"@ms-cloudpack/scripts": "^0.0.1",
|
|
23
24
|
"@ms-cloudpack/test-utilities": "^0.5.0"
|