aboutsummaryrefslogtreecommitdiff
path: root/src/js/node/fs.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/node/fs.js')
-rw-r--r--src/js/node/fs.js90
1 files changed, 89 insertions, 1 deletions
diff --git a/src/js/node/fs.js b/src/js/node/fs.js
index ab6816904..2c6b8cfbe 100644
--- a/src/js/node/fs.js
+++ b/src/js/node/fs.js
@@ -7,7 +7,6 @@ const Stream = require("node:stream");
const { isArrayBufferView } = require("node:util/types");
const constants = $processBindingConstants.fs;
-const { COPYFILE_EXCL } = constants;
var fs = Bun.fs();
class FSWatcher extends EventEmitter {
@@ -65,6 +64,45 @@ class FSWatcher extends EventEmitter {
unref() {
this.#watcher?.unref();
}
+
+ // https://github.com/nodejs/node/blob/9f51c55a47702dc6a0ca3569853dd7ba022bf7bb/lib/internal/fs/watchers.js#L259-L263
+ start() {}
+}
+
+/** Implemented in `node_fs_stat_watcher.zig` */
+// interface StatWatcherHandle {
+// ref();
+// unref();
+// close();
+// }
+
+class StatWatcher extends EventEmitter {
+ // _handle: StatWatcherHandle;
+
+ constructor(path, options) {
+ super();
+ this._handle = fs.watchFile(path, options, this.#onChange.bind(this));
+ }
+
+ #onChange(curr, prev) {
+ this.emit("change", curr, prev);
+ }
+
+ // https://github.com/nodejs/node/blob/9f51c55a47702dc6a0ca3569853dd7ba022bf7bb/lib/internal/fs/watchers.js#L259-L263
+ start() {}
+
+ stop() {
+ this._handle?.close();
+ this._handle = null;
+ }
+
+ ref() {
+ this._handle?.ref();
+ }
+
+ unref() {
+ this._handle?.unref();
+ }
}
var access = function access(...args) {
@@ -316,6 +354,54 @@ var access = function access(...args) {
return new FSWatcher(path, options, listener);
};
+// TODO: move this entire thing into native code.
+// the reason it's not done right now is because there isnt a great way to have multiple
+// listeners per StatWatcher with the current implementation in native code. the downside
+// of this means we need to do path validation in the js side of things
+const statWatchers = new Map();
+let _pathModule;
+function getValidatedPath(p) {
+ if (p instanceof URL) return Bun.fileURLToPath(p);
+ if (typeof p !== "string") throw new TypeError("Path must be a string or URL.");
+ return (_pathModule ??= require("node:path")).resolve(p);
+}
+function watchFile(filename, options, listener) {
+ filename = getValidatedPath(filename);
+
+ if (typeof options === "function") {
+ listener = options;
+ options = {};
+ }
+
+ if (typeof listener !== "function") {
+ throw new TypeError("listener must be a function");
+ }
+
+ var stat = statWatchers.get(filename);
+ if (!stat) {
+ stat = new StatWatcher(filename, options);
+ statWatchers.set(filename, stat);
+ }
+ stat.addListener("change", listener);
+ return stat;
+}
+function unwatchFile(filename, listener) {
+ filename = getValidatedPath(filename);
+
+ var stat = statWatchers.get(filename);
+ if (!stat) return;
+ if (listener) {
+ stat.removeListener("change", listener);
+ if (stat.listenerCount("change") !== 0) {
+ return;
+ }
+ } else {
+ stat.removeAllListeners("change");
+ }
+ stat.stop();
+ statWatchers.delete(filename);
+}
+
function callbackify(fsFunction, args) {
try {
const result = fsFunction.apply(fs, args.slice(0, args.length - 1));
@@ -1200,9 +1286,11 @@ export default {
truncateSync,
unlink,
unlinkSync,
+ unwatchFile,
utimes,
utimesSync,
watch,
+ watchFile,
write,
writeFile,
writeFileSync,