src/vs/platform/files/node/watcher/nodejs/nodejsWatcherLib.ts/NodeJSFileWatcherLibrary/doWatch
class NodeJSFileWatcherLibrary:	private async doWatch(path: string, isDirectory: boolean): Promise<IDisposable> {

		// macOS: watching samba shares can crash VSCode so we do
		// a simple check for the file path pointing to /Volumes
		// (https://github.com/microsoft/vscode/issues/106879)
		// TODO@electron this needs a revisit when the crash is
		// fixed or mitigated upstream.
		if (isMacintosh && isEqualOrParent(path, '/Volumes/', true)) {
			this.error(`Refusing to watch ${path} for changes using fs.watch() for possibly being a network share where watching is unreliable and unstable.`);

			return Disposable.None;
		}

		const cts = new CancellationTokenSource(this.cts.token);

		let disposables = new DisposableStore();

		try {
			const pathBasename = basename(path);

			// Creating watcher can fail with an exception
			const watcher = watch(path);
			disposables.add(toDisposable(() => {
				watcher.removeAllListeners();
				watcher.close();
			}));

			this.trace(`Started watching: '${path}'`);

			// Folder: resolve children to emit proper events
			const folderChildren = new Set<string>();
			if (isDirectory) {
				try {
					for (const child of await Promises.readdir(path)) {
						folderChildren.add(child);
					}
				} catch (error) {
					this.error(error);
				}
			}

			const mapPathToStatDisposable = new Map<string, IDisposable>();
			disposables.add(toDisposable(() => {
				for (const [, disposable] of mapPathToStatDisposable) {
					disposable.dispose();
				}
				mapPathToStatDisposable.clear();
			}));

			watcher.on('error', (code: number, signal: string) => {
				this.error(`Failed to watch ${path} for changes using fs.watch() (${code}, ${signal})`);

				// The watcher is no longer functional reliably
				// so we go ahead and dispose it
				this.dispose();
			});

			watcher.on('change', (type, raw) => {
				if (cts.token.isCancellationRequested) {
					return; // ignore if already disposed
				}

				this.trace(`[raw] ["${type}"] ${raw}`);

				// Normalize file name
				let changedFileName = '';
				if (raw) { // https://github.com/microsoft/vscode/issues/38191
					changedFileName = raw.toString();
					if (isMacintosh) {
						// Mac: uses NFD unicode form on disk, but we want NFC
						// See also https://github.com/nodejs/node/issues/2165
						changedFileName = normalizeNFC(changedFileName);
					}
				}

				if (!changedFileName || (type !== 'change' && type !== 'rename')) {
					return; // ignore unexpected events
				}

				// Folder
				if (isDirectory) {

					// Folder child added/deleted
					if (type === 'rename') {

						// Cancel any previous stats for this file if existing
						mapPathToStatDisposable.get(changedFileName)?.dispose();

						// Wait a bit and try see if the file still exists on disk
						// to decide on the resulting event
						const timeoutHandle = setTimeout(async () => {
							mapPathToStatDisposable.delete(changedFileName);

							// Depending on the OS the watcher runs on, there
							// is different behaviour for when the watched
							// folder path is being deleted:
							//
							// -   macOS: not reported but events continue to
							//            work even when the folder is brought
							//            back, though it seems every change
							//            to a file is reported as "rename"
							// -   Linux: "rename" event is reported with the
							//            name of the folder and events stop
							//            working
							// - Windows: an EPERM error is thrown that we
							//            handle from the `on('error')` event
							//
							// We do not re-attach the watcher after timeout
							// though as we do for file watches because for
							// file watching specifically we want to handle
							// the atomic-write cases where the file is being
							// deleted and recreated with different contents.
							//
							// Same as with recursive watching, we do not
							// emit a delete event in this case.
							if (changedFileName === pathBasename && !await Promises.exists(path)) {
								this.warn('Watcher shutdown because watched path got deleted');

								// The watcher is no longer functional reliably
								// so we go ahead and dispose it
								this.dispose();

								return;
							}

							// In order to properly detect renames on a case-insensitive
							// file system, we need to use `existsChildStrictCase` helper
							// because otherwise we would wrongly assume a file exists
							// when it was renamed to same name but different case.
							const fileExists = await this.existsChildStrictCase(join(path, changedFileName));

							if (cts.token.isCancellationRequested) {
								return; // ignore if disposed by now
							}

							// Figure out the correct event type:
							// File Exists: either 'added' or 'updated' if known before
							// File Does not Exist: always 'deleted'
							let type: FileChangeType;
							if (fileExists) {
								if (folderChildren.has(changedFileName)) {
									type = FileChangeType.UPDATED;
								} else {
									type = FileChangeType.ADDED;
									folderChildren.add(changedFileName);
								}
							} else {
								folderChildren.delete(changedFileName);
								type = FileChangeType.DELETED;
							}

							this.onFileChange({ path: join(this.request.path, changedFileName), type });
						}, NodeJSFileWatcherLibrary.FILE_DELETE_HANDLER_DELAY);

						mapPathToStatDisposable.set(changedFileName, toDisposable(() => clearTimeout(timeoutHandle)));
					}

					// Folder child changed
					else {

						// Figure out the correct event type: if this is the
						// first time we see this child, it can only be added
						let type: FileChangeType;
						if (folderChildren.has(changedFileName)) {
							type = FileChangeType.UPDATED;
						} else {
							type = FileChangeType.ADDED;
							folderChildren.add(changedFileName);
						}

						this.onFileChange({ path: join(this.request.path, changedFileName), type });
					}
				}

				// File
				else {

					// File added/deleted
					if (type === 'rename' || changedFileName !== pathBasename) {

						// Depending on the OS the watcher runs on, there
						// is different behaviour for when the watched
						// file path is being deleted:
						//
						// -   macOS: "rename" event is reported and events
						//            stop working
						// -   Linux: "rename" event is reported and events
						//            stop working
						// - Windows: "rename" event is reported and events
						//            continue to work when file is restored
						//
						// As opposed to folder watching, we re-attach the
						// watcher after brief timeout to support "atomic save"
						// operations where a tool may decide to delete a file
						// and then create it with the updated contents.
						//
						// Different to folder watching, we emit a delete event
						// though we never detect when the file is brought back
						// because the watcher is disposed then.

						const timeoutHandle = setTimeout(async () => {
							const fileExists = await Promises.exists(path);

							if (cts.token.isCancellationRequested) {
								return; // ignore if disposed by now
							}

							// File still exists, so emit as change event and reapply the watcher
							if (fileExists) {
								this.onFileChange({ path: this.request.path, type: FileChangeType.UPDATED }, true /* skip excludes/includes (file is explicitly watched) */);

								disposables.add(await this.doWatch(path, false));
							}

							// File seems to be really gone, so emit a deleted event and dispose
							else {
								const eventPromise = this.onFileChange({ path: this.request.path, type: FileChangeType.DELETED }, true /* skip excludes/includes (file is explicitly watched) */);

								// Important to await the event delivery
								// before disposing the watcher, otherwise
								// we will loose this event.
								await eventPromise;
								this.dispose();
							}
						}, NodeJSFileWatcherLibrary.FILE_DELETE_HANDLER_DELAY);

						// Very important to dispose the watcher which now points to a stale inode
						// and wire in a new disposable that tracks our timeout that is installed
						disposables.clear();
						disposables.add(toDisposable(() => clearTimeout(timeoutHandle)));
					}

					// File changed
					else {
						this.onFileChange({ path: this.request.path, type: FileChangeType.UPDATED }, true /* skip excludes/includes (file is explicitly watched) */);
					}
				}
			});
		} catch (error) {
			if (await Promises.exists(path) && !cts.token.isCancellationRequested) {
				this.error(`Failed to watch ${path} for changes using fs.watch() (${error.toString()})`);
			}
		}

		return toDisposable(() => {
			cts.dispose(true);
			disposables.dispose();
		});
	}