or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Watch

1

2

Watch provides utilities for watching file trees in Node.js applications. It offers two primary interfaces: `watchTree` for simple callback-based file monitoring, and `createMonitor` for event-driven monitoring with EventEmitter patterns. The library supports comprehensive filtering options and includes a command-line interface for automated command execution on file changes.

3

4

## Package Information

5

6

- **Package Name**: watch

7

- **Package Type**: npm

8

- **Language**: JavaScript

9

- **Installation**: `npm install watch`

10

11

## Core Imports

12

13

```javascript

14

const watch = require("watch");

15

```

16

17

For individual imports:

18

19

```javascript

20

const { watchTree, unwatchTree, createMonitor, walk } = require("watch");

21

```

22

23

## Basic Usage

24

25

```javascript

26

const watch = require("watch");

27

28

// Simple file watching with callback

29

watch.watchTree("/path/to/watch", function (f, curr, prev) {

30

if (typeof f == "object" && prev === null && curr === null) {

31

// Finished walking the tree

32

console.log("Watching", Object.keys(f).length, "files");

33

} else if (prev === null) {

34

// New file

35

console.log("New file:", f);

36

} else if (curr.nlink === 0) {

37

// File removed

38

console.log("Removed:", f);

39

} else {

40

// File changed

41

console.log("Changed:", f);

42

}

43

});

44

45

// Event-driven monitoring

46

watch.createMonitor("/path/to/watch", function (monitor) {

47

monitor.on("created", function (f, stat) {

48

console.log("Created:", f);

49

});

50

monitor.on("changed", function (f, curr, prev) {

51

console.log("Changed:", f);

52

});

53

monitor.on("removed", function (f, stat) {

54

console.log("Removed:", f);

55

});

56

57

// Stop monitoring

58

// monitor.stop();

59

});

60

```

61

62

## Capabilities

63

64

### Directory Tree Watching

65

66

Monitor file and directory changes with customizable filtering and polling options.

67

68

```javascript { .api }

69

/**

70

* Watch a directory tree for file changes

71

* @param {string} root - Directory path to watch

72

* @param {WatchOptions|WatchCallback} [options] - Watch configuration options (optional)

73

* @param {WatchCallback} callback - Called on file changes and setup completion

74

* Note: If options is not provided, the second parameter becomes the callback

75

*/

76

function watchTree(root, options, callback);

77

78

/**

79

* Stop watching a directory tree

80

* @param {string} root - Directory path to stop watching

81

*/

82

function unwatchTree(root);

83

84

interface WatchOptions {

85

/** Skip files starting with "." */

86

ignoreDotFiles?: boolean;

87

/** Function to filter files/directories (return true to include) */

88

filter?: (filepath: string, stat: Stats) => boolean;

89

/** Polling interval in seconds */

90

interval?: number;

91

/** Skip unreadable directories silently (handles EACCES errors) */

92

ignoreUnreadableDir?: boolean;

93

/** Skip files with permission issues silently (handles EPERM errors) */

94

ignoreNotPermitted?: boolean;

95

/** Skip directories matching this pattern */

96

ignoreDirectoryPattern?: RegExp;

97

}

98

99

/**

100

* Callback for watchTree file changes

101

* @param {string|object} f - File path or file hash object (on completion)

102

* @param {Stats|null} curr - Current file stats

103

* @param {Stats|null} prev - Previous file stats (null for new files)

104

*/

105

type WatchCallback = (f: string | object, curr: Stats | null, prev: Stats | null) => void;

106

```

107

108

**Callback Behavior:**

109

- **Setup completion**: `f` is an object (file hash), `curr` and `prev` are `null`

110

- **New file**: `prev` is `null`, `curr` contains file stats

111

- **Removed file**: `curr.nlink` is `0` (file's link count is zero)

112

- **Changed file**: Both `curr` and `prev` contain stats, and modification times differ

113

114

**Important:** The function uses `fs.watchFile` internally and only triggers callbacks for actual content changes (based on mtime comparison), not just access times.

115

116

### Event-Driven Monitoring

117

118

Create an EventEmitter-based monitor for advanced file system event handling.

119

120

```javascript { .api }

121

/**

122

* Create an EventEmitter-based file monitor

123

* @param {string} root - Directory path to monitor

124

* @param {WatchOptions|MonitorCallback} [options] - Monitor configuration options (optional)

125

* @param {MonitorCallback} callback - Called with monitor object when ready

126

* Note: If options is not provided, the second parameter becomes the callback

127

*/

128

function createMonitor(root, options, callback);

129

130

/**

131

* Callback for createMonitor setup completion

132

* @param {Monitor} monitor - The configured monitor instance

133

*/

134

type MonitorCallback = (monitor: Monitor) => void;

135

136

interface Monitor extends EventEmitter {

137

/** Hash of file paths to current stat objects */

138

files: { [filepath: string]: Stats };

139

/** Stop monitoring (calls unwatchTree) */

140

stop(): void;

141

}

142

```

143

144

**Monitor Events:**

145

- `'created'` - New file created: `(filename: string, stat: Stats)`

146

- `'removed'` - File removed: `(filename: string, stat: Stats)`

147

- `'changed'` - File modified: `(filename: string, curr: Stats, prev: Stats)`

148

149

**Note:** The monitor includes deduplication logic to prevent duplicate events for the same file and action type within rapid succession.

150

151

### Directory Walking

152

153

Recursively walk a directory tree and build a file hash without watching.

154

155

```javascript { .api }

156

/**

157

* Recursively walk a directory tree

158

* @param {string} dir - Directory to walk

159

* @param {WalkOptions|WalkCallback} [options] - Walk configuration options (optional)

160

* @param {WalkCallback} callback - Called with results when complete

161

* Note: If options is not provided, the second parameter becomes the callback

162

*/

163

function walk(dir, options, callback);

164

165

interface WalkOptions {

166

/** Skip files starting with "." */

167

ignoreDotFiles?: boolean;

168

/** Function to filter files/directories (return true to include) */

169

filter?: (filepath: string, stat: Stats) => boolean;

170

/** Skip unreadable directories silently (handles EACCES errors) */

171

ignoreUnreadableDir?: boolean;

172

/** Skip files with permission issues silently (handles EPERM errors) */

173

ignoreNotPermitted?: boolean;

174

/** Skip directories matching this pattern */

175

ignoreDirectoryPattern?: RegExp;

176

}

177

178

/**

179

* Callback for walk completion

180

* @param {Error|null} err - Error if walk failed

181

* @param {object} files - Hash of file paths to stat objects

182

*/

183

type WalkCallback = (err: Error | null, files: { [filepath: string]: Stats }) => void;

184

```

185

186

### Command Line Interface

187

188

Execute commands automatically when files change, with throttling and filtering support. Install globally with `npm install watch -g` to use the `watch` command anywhere.

189

190

```bash { .api }

191

# Basic usage

192

watch <command> [...directory]

193

194

# With options

195

watch "npm test" ./src --wait=2 --ignoreDotFiles

196

197

# Available options:

198

--wait=<seconds>, -w # Throttle command execution (seconds)

199

--filter=<file>, -f # Path to filter function module (exports filter function)

200

--interval=<seconds>, -i # Polling interval (default: 0.2)

201

--ignoreDotFiles, -d # Ignore dot files

202

--ignoreUnreadable, -u # Ignore unreadable directories

203

--ignoreDirectoryPattern=<regexp>, -p # Ignore matching directories

204

```

205

206

The CLI tool watches specified directories (defaults to current working directory) and executes the given command whenever files change. The `--wait` option prevents rapid repeated executions.

207

208

**Filter Module Example:**

209

The `--filter` option accepts a path to a JavaScript file that exports a filter function:

210

211

```javascript

212

// myfilter.js

213

module.exports = function (filepath, stat) {

214

// Return true to include file in watching, false to exclude

215

return stat.isDirectory() || filepath.match(/\.(js|ts|json)$/);

216

};

217

```

218

219

Then use: `watch "npm test" ./src --filter=./myfilter.js`

220

221

## Types

222

223

```javascript { .api }

224

/**

225

* Node.js fs.Stats object containing file metadata

226

*/

227

interface Stats {

228

isFile(): boolean;

229

isDirectory(): boolean;

230

isSymbolicLink(): boolean;

231

size: number;

232

mtime: Date;

233

nlink: number;

234

// ... other fs.Stats properties

235

}

236

237

/**

238

* Filter function type for determining which files to include

239

* @param {string} filepath - Full path to file or directory

240

* @param {Stats} stat - File system stats object

241

* @returns {boolean} True to include file in watching/walking

242

*/

243

type FilterFunction = (filepath: string, stat: Stats) => boolean;

244

```

245

246

## Usage Examples

247

248

### Advanced Filtering

249

250

```javascript

251

const watch = require("watch");

252

253

// Custom filter function

254

function sourceFilter(f, stat) {

255

return stat.isDirectory() || f.match(/\.(js|ts|json)$/);

256

}

257

258

watch.watchTree("./src", {

259

filter: sourceFilter,

260

ignoreDotFiles: true,

261

ignoreDirectoryPattern: /node_modules/

262

}, function (f, curr, prev) {

263

if (typeof f !== "object") {

264

console.log("Source file changed:", f);

265

}

266

});

267

```

268

269

### Monitor with Cleanup

270

271

```javascript

272

const watch = require("watch");

273

274

let monitor;

275

276

watch.createMonitor("./project", {

277

interval: 1,

278

ignoreDotFiles: true

279

}, function (m) {

280

monitor = m;

281

282

monitor.on("created", (f) => console.log("+ " + f));

283

monitor.on("removed", (f) => console.log("- " + f));

284

monitor.on("changed", (f) => console.log("~ " + f));

285

});

286

287

// Cleanup on exit

288

process.on("SIGINT", function() {

289

if (monitor) {

290

monitor.stop();

291

}

292

process.exit();

293

});

294

```

295

296

### One-time Directory Scan

297

298

```javascript

299

const watch = require("watch");

300

301

watch.walk("./docs", {

302

ignoreDotFiles: true,

303

filter: (f, stat) => stat.isDirectory() || f.endsWith('.md')

304

}, function (err, files) {

305

if (err) throw err;

306

307

console.log("Found", Object.keys(files).length, "markdown files:");

308

Object.keys(files).forEach(file => {

309

if (files[file].isFile()) {

310

console.log("-", file);

311

}

312

});

313

});

314

```