refactor(fs)!: return Watcher from watch and watchImmediate (#3610)

* refactor(fs)!: return Watcher from watch and watchImmediate

Both resolve to a `Watcher` resource instead of an `UnwatchFn` callback;
call `await watcher.close()` to stop watching. `UnwatchFn` is removed and
`Watcher` is now exported.

* fix change file

* fmt
This commit is contained in:
Lucas Fernandes Nogueira
2026-09-22 06:06:50 -03:00
committed by GitHub
parent 8083107a0a
commit fdfb35e531
4 changed files with 42 additions and 27 deletions
+6
View File
@@ -0,0 +1,6 @@
---
"fs": major
"fs-js": major
---
**Breaking:** `watch` and `watchImmediate` now resolve to a `Watcher` resource instead of an `UnwatchFn` callback. Call `await watcher.close()` to stop watching. The `UnwatchFn` type has been removed and `Watcher` is now exported.
+10 -10
View File
@@ -17,7 +17,7 @@
let watchRecursive = $state(false)
/** @type {fs.BaseDirectory | undefined} */
let baseDir = $state()
let unwatchFn
let watcher
let unwatchPath = ''
let isMobile = $state(false)
@@ -161,15 +161,15 @@
}
if (options.delayMs === 0) {
fs.watchImmediate(watchPath, onMessage, options)
.then((fn) => {
unwatchFn = fn
.then((w) => {
watcher = w
unwatchPath = watchPath
})
.catch(onMessage)
} else {
fs.watch(watchPath, onMessage, options)
.then((fn) => {
unwatchFn = fn
.then((w) => {
watcher = w
unwatchPath = watchPath
})
.catch(onMessage)
@@ -178,11 +178,11 @@
}
function unwatch() {
if (unwatchFn) {
if (watcher) {
onMessage(`Stopped watching ${unwatchPath} for changes`)
unwatchFn()
watcher.close()
}
unwatchFn = undefined
watcher = undefined
unwatchPath = undefined
}
@@ -190,8 +190,8 @@
if (file) {
file.close()
}
if (unwatchFn) {
unwatchFn()
if (watcher) {
watcher.close()
}
})
</script>
File diff suppressed because one or more lines are too long
+25 -16
View File
@@ -1283,19 +1283,18 @@ type WatchEventKindRemove =
| { kind: 'folder' }
| { kind: 'other' }
// TODO: Remove this in v3, return `Watcher` instead
/**
* @since 2.0.0
* A file system watcher. Call {@linkcode Watcher.close} to stop watching.
*
* @since 3.0.0
*/
type UnwatchFn = () => void
class Watcher extends Resource {}
async function watchInternal(
paths: string | string[] | URL | URL[],
cb: (event: WatchEvent) => void,
options: DebouncedWatchOptions
): Promise<UnwatchFn> {
): Promise<Watcher> {
const watchPaths = Array.isArray(paths) ? paths : [paths]
for (const path of watchPaths) {
@@ -1313,41 +1312,51 @@ async function watchInternal(
onEvent
})
const watcher = new Watcher(rid)
return () => {
void watcher.close()
}
return new Watcher(rid)
}
// TODO: Return `Watcher` instead in v3
/**
* Watch changes (after a delay) on files or directories.
*
* @example
* ```typescript
* import { watch, BaseDirectory } from '@tauri-apps/plugin-fs';
* const watcher = await watch('app.conf', (event) => console.log(event), { baseDir: BaseDirectory.AppConfig });
* // when you're done watching:
* await watcher.close();
* ```
*
* @since 2.0.0
*/
async function watch(
paths: string | string[] | URL | URL[],
cb: (event: WatchEvent) => void,
options?: DebouncedWatchOptions
): Promise<UnwatchFn> {
): Promise<Watcher> {
return await watchInternal(paths, cb, {
delayMs: 2000,
...options
})
}
// TODO: Return `Watcher` instead in v3
/**
* Watch changes on files or directories.
*
* @example
* ```typescript
* import { watchImmediate, BaseDirectory } from '@tauri-apps/plugin-fs';
* const watcher = await watchImmediate('app.conf', (event) => console.log(event), { baseDir: BaseDirectory.AppConfig });
* // when you're done watching:
* await watcher.close();
* ```
*
* @since 2.0.0
*/
async function watchImmediate(
paths: string | string[] | URL | URL[],
cb: (event: WatchEvent) => void,
options?: WatchOptions
): Promise<UnwatchFn> {
): Promise<Watcher> {
return await watchInternal(paths, cb, {
...options,
delayMs: undefined
@@ -1475,13 +1484,13 @@ export type {
WatchEventKindAccess,
WatchEventKindCreate,
WatchEventKindModify,
WatchEventKindRemove,
UnwatchFn
WatchEventKindRemove
}
export {
BaseDirectory,
FileHandle,
Watcher,
create,
open,
copyFile,