/* global Bare */ const EventEmitter = require('bare-events') const path = require('bare-path') const { Readable, Writable } = require('bare-stream') const binding = require('./binding') const isWindows = Bare.platform === 'win32' const constants = exports.constants = { O_RDWR: binding.O_RDWR, O_RDONLY: binding.O_RDONLY, O_WRONLY: binding.O_WRONLY, O_CREAT: binding.O_CREAT, O_TRUNC: binding.O_TRUNC, O_APPEND: binding.O_APPEND, F_OK: binding.F_OK || 0, R_OK: binding.R_OK || 0, W_OK: binding.W_OK || 0, X_OK: binding.X_OK || 0, S_IFMT: binding.S_IFMT, S_IFREG: binding.S_IFREG, S_IFDIR: binding.S_IFDIR, S_IFCHR: binding.S_IFCHR, S_IFLNK: binding.S_IFLNK, S_IFBLK: binding.S_IFBLK || 0, S_IFIFO: binding.S_IFIFO || 0, S_IFSOCK: binding.S_IFSOCK || 0, S_IRUSR: binding.S_IRUSR || 0, S_IWUSR: binding.S_IWUSR || 0, S_IXUSR: binding.S_IXUSR || 0, S_IRGRP: binding.S_IRGRP || 0, S_IWGRP: binding.S_IWGRP || 0, S_IXGRP: binding.S_IXGRP || 0, S_IROTH: binding.S_IROTH || 0, S_IWOTH: binding.S_IWOTH || 0, S_IXOTH: binding.S_IXOTH || 0, UV_DIRENT_UNKNOWN: binding.UV_DIRENT_UNKNOWN, UV_DIRENT_FILE: binding.UV_DIRENT_FILE, UV_DIRENT_DIR: binding.UV_DIRENT_DIR, UV_DIRENT_LINK: binding.UV_DIRENT_LINK, UV_DIRENT_FIFO: binding.UV_DIRENT_FIFO, UV_DIRENT_SOCKET: binding.UV_DIRENT_SOCKET, UV_DIRENT_CHAR: binding.UV_DIRENT_CHAR, UV_DIRENT_BLOCK: binding.UV_DIRENT_BLOCK, UV_FS_SYMLINK_DIR: binding.UV_FS_SYMLINK_DIR, UV_FS_SYMLINK_JUNCTION: binding.UV_FS_SYMLINK_JUNCTION } const reqs = [] let used = 0 const fs = { handle: Buffer.allocUnsafe(binding.sizeofFS) } binding.init(fs.handle, fs, onresponse) Bare.on('exit', () => binding.destroy(fs.handle)) // Lightly-modified from the Node FS internal utils. function flagsToNumber (flags) { switch (flags) { case 'r' : return constants.O_RDONLY case 'rs' : // Fall through. case 'sr' : return constants.O_RDONLY | constants.O_SYNC case 'r+' : return constants.O_RDWR case 'rs+' : // Fall through. case 'sr+' : return constants.O_RDWR | constants.O_SYNC case 'w' : return constants.O_TRUNC | constants.O_CREAT | constants.O_WRONLY case 'wx' : // Fall through. case 'xw' : return constants.O_TRUNC | constants.O_CREAT | constants.O_WRONLY | constants.O_EXCL case 'w+' : return constants.O_TRUNC | constants.O_CREAT | constants.O_RDWR case 'wx+': // Fall through. case 'xw+': return constants.O_TRUNC | constants.O_CREAT | constants.O_RDWR | constants.O_EXCL case 'a' : return constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY case 'ax' : // Fall through. case 'xa' : return constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY | constants.O_EXCL case 'as' : // Fall through. case 'sa' : return constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY | constants.O_SYNC case 'a+' : return constants.O_APPEND | constants.O_CREAT | constants.O_RDWR case 'ax+': // Fall through. case 'xa+': return constants.O_APPEND | constants.O_CREAT | constants.O_RDWR | constants.O_EXCL case 'as+': // Fall through. case 'sa+': return constants.O_APPEND | constants.O_CREAT | constants.O_RDWR | constants.O_SYNC } throw typeError('ERR_INVALID_ARG_VALUE', `Invalid value in flags: ${flags}`) } function modeToNumber (mode) { mode = parseInt(mode, 8) if (isNaN(mode)) throw typeError('ERR_INVALID_ARG_VALUE', 'Mode must be a number or octal string') return mode } function alloc () { const handle = Buffer.alloc(binding.sizeofFSReq) binding.initReq(fs.handle, handle) const view = new Uint32Array(handle.buffer, handle.byteOffset + binding.offsetofFSReqID, 1) view[0] = reqs.length const req = { handle, view, type: 0, callback: null } used++ reqs.push(req) return req } function getReq () { return used === reqs.length ? alloc() : reqs[used++] } function onresponse (id, err, result) { const req = reqs[id] used-- if (used !== id) { const u = reqs[used] reqs[u.view[0] = id] = u reqs[req.view[0] = used] = req } const callback = req.callback req.callback = null callback(err, result) } function open (filepath, flags, mode, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof cb !== 'function') { if (typeof flags === 'function') { cb = flags flags = 'r' mode = 0o666 } else if (typeof mode === 'function') { cb = mode mode = 0o666 } else { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } } if (typeof flags === 'string') flags = flagsToNumber(flags) if (typeof mode === 'string') mode = modeToNumber(mode) const req = getReq() req.callback = cb binding.open(req.handle, filepath, flags, mode) } function openSync (filepath, flags = 'r', mode = 0o666) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof flags === 'string') flags = flagsToNumber(flags) if (typeof mode === 'string') mode = modeToNumber(mode) return binding.openSync(filepath, flags, mode) } function close (fd, cb = noop) { if (typeof fd !== 'number') { throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')') } if (fd < 0 || fd > 0x7fffffff) { throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd) } if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } const req = getReq() req.callback = cb binding.close(req.handle, fd) } function closeSync (fd) { if (typeof fd !== 'number') { throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')') } if (fd < 0 || fd > 0x7fffffff) { throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd) } return binding.closeSync(fd) } function access (filepath, mode, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof cb !== 'function') { if (typeof mode === 'function') { cb = mode mode = constants.F_OK } else { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } } const req = getReq() req.callback = cb binding.access(req.handle, filepath, mode) } function accessSync (filepath, mode = constants.F_OK) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } binding.accessSync(filepath, mode) } function exists (filepath, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } return access(filepath, (err) => cb(!!err)) // eslint-disable-line n/no-callback-literal } function existsSync (filepath) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } try { accessSync(filepath) return true } catch { return false } } function read (fd, buffer, offset, len, pos, cb) { if (typeof fd !== 'number') { throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')') } if (fd < 0 || fd > 0x7fffffff) { throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd) } if (!Buffer.isBuffer(buffer) && !ArrayBuffer.isView(buffer)) { throw typeError('ERR_INVALID_ARG_TYPE', 'Buffer must be a buffer. Received type ' + (typeof buffer) + ' (' + buffer + ')') } if (typeof cb !== 'function') { if (typeof offset === 'function') { cb = offset offset = 0 len = buffer.byteLength pos = -1 } else if (typeof len === 'function') { cb = len len = buffer.byteLength - offset pos = -1 } else if (typeof pos === 'function') { cb = pos pos = -1 } else { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } } if (typeof pos !== 'number') pos = -1 const req = getReq() req.callback = cb binding.read(req.handle, fd, buffer, offset, len, pos) } function readSync (fd, buffer, offset = 0, len = buffer.byteLength - offset, pos = -1) { if (typeof fd !== 'number') { throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')') } if (fd < 0 || fd > 0x7fffffff) { throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd) } if (!Buffer.isBuffer(buffer) && !ArrayBuffer.isView(buffer)) { throw typeError('ERR_INVALID_ARG_TYPE', 'Buffer must be a buffer. Received type ' + (typeof buffer) + ' (' + buffer + ')') } return binding.readSync(fd, buffer, offset, len, pos) } function readv (fd, buffers, pos, cb) { if (typeof fd !== 'number') { throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')') } if (fd < 0 || fd > 0x7fffffff) { throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd) } if (typeof pos === 'function') { cb = pos pos = -1 } else if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } if (typeof pos !== 'number') pos = -1 const req = getReq() req.callback = cb binding.readv(req.handle, fd, buffers, pos) } function write (fd, data, offset, len, pos, cb) { if (typeof fd !== 'number') { throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')') } if (fd < 0 || fd > 0x7fffffff) { throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd) } if (typeof data !== 'string' && !Buffer.isBuffer(data) && !ArrayBuffer.isView(data)) { throw typeError('ERR_INVALID_ARG_TYPE', 'Data must be a string or buffer. Received type ' + (typeof data)) } if (typeof data === 'string') { let encoding = len cb = pos pos = offset if (typeof cb !== 'function') { if (typeof pos === 'function') { cb = pos pos = -1 encoding = 'utf8' } else if (typeof encoding === 'function') { cb = encoding encoding = 'utf8' } else { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } } if (typeof pos === 'string') { encoding = pos pos = -1 } data = Buffer.from(data, encoding) offset = 0 len = data.byteLength } else if (typeof cb !== 'function') { if (typeof offset === 'function') { cb = offset offset = 0 len = data.byteLength pos = -1 } else if (typeof len === 'function') { cb = len len = data.byteLength - offset pos = -1 } else if (typeof pos === 'function') { cb = pos pos = -1 } else { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } } if (typeof pos !== 'number') pos = -1 const req = getReq() req.callback = cb binding.write(req.handle, fd, data, offset, len, pos) } function writeSync (fd, data, offset = 0, len, pos) { if (typeof fd !== 'number') { throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')') } if (fd < 0 || fd > 0x7fffffff) { throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd) } if (typeof data !== 'string' && !Buffer.isBuffer(data) && !ArrayBuffer.isView(data)) { throw typeError('ERR_INVALID_ARG_TYPE', 'Data must be a string or buffer. Received type ' + (typeof data)) } if (typeof data === 'string') data = Buffer.from(data) if (typeof len !== 'number') len = data.byteLength - offset if (typeof pos !== 'number') pos = -1 return binding.writeSync(fd, data, offset, len, pos) } function writev (fd, buffers, pos, cb) { if (typeof fd !== 'number') { throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')') } if (fd < 0 || fd > 0x7fffffff) { throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd) } if (typeof pos === 'function') { cb = pos pos = -1 } else if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } if (typeof pos !== 'number') pos = -1 const req = getReq() req.callback = cb binding.writev(req.handle, fd, buffers, pos) } function stat (filepath, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } const data = new Array(Stats.length) const req = getReq() req.callback = function (err, _) { if (err) cb(err, null) else cb(null, new Stats(...data)) } binding.stat(req.handle, filepath, data) } function statSync (filepath) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } return new Stats(...binding.statSync(filepath)) } function lstat (filepath, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } const data = new Array(Stats.length) const req = getReq() req.callback = function (err, _) { if (err) cb(err, null) else cb(null, new Stats(...data)) } binding.lstat(req.handle, filepath, data) } function lstatSync (filepath) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } return new Stats(...binding.lstatSync(filepath)) } function fstat (fd, cb) { if (typeof fd !== 'number') { throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')') } if (fd < 0 || fd > 0x7fffffff) { throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd) } if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } const data = new Array(Stats.length) const req = getReq() req.callback = function (err, _) { if (err) cb(err, null) else cb(null, new Stats(...data)) } binding.fstat(req.handle, fd, data) } function fstatSync (fd) { if (typeof fd !== 'number') { throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')') } if (fd < 0 || fd > 0x7fffffff) { throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd) } return new Stats(...binding.fstatSync(fd)) } function ftruncate (fd, len, cb) { if (typeof fd !== 'number') { throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')') } if (fd < 0 || fd > 0x7fffffff) { throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd) } if (typeof len === 'function') { cb = len len = 0 } else if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } const req = getReq() req.callback = cb binding.ftruncate(req.handle, fd, len) } function chmod (filepath, mode, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof mode === 'string') mode = modeToNumber(mode) const req = getReq() req.callback = cb binding.chmod(req.handle, filepath, mode) } function chmodSync (filepath, mode) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof mode === 'string') mode = modeToNumber(mode) binding.chmodSync(filepath, mode) } function fchmod (fd, mode, cb) { if (typeof fd !== 'number') { throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')') } if (fd < 0 || fd > 0x7fffffff) { throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd) } if (typeof mode === 'string') mode = modeToNumber(mode) const req = getReq() req.callback = cb binding.fchmod(req.handle, fd, mode) } function fchmodSync (fd, mode) { if (typeof fd !== 'number') { throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')') } if (fd < 0 || fd > 0x7fffffff) { throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd) } if (typeof mode === 'string') mode = modeToNumber(mode) binding.fchmodSync(fd, mode) } function mkdirRecursive (filepath, mode, cb) { mkdir(filepath, { mode }, function (err) { if (err === null) return cb(null, 0, null) if (err.code !== 'ENOENT') { stat(filepath, function (e, st) { if (e) return cb(e, e.errno, null) if (st.isDirectory()) return cb(null, 0, null) cb(err, err.errno, null) }) return } while (filepath.endsWith(path.sep)) filepath = filepath.slice(0, -1) const i = filepath.lastIndexOf(path.sep) if (i <= 0) return cb(err, err.errno, null) mkdirRecursive(filepath.slice(0, i), mode, function (err) { if (err) return cb(err, err.errno, null) mkdir(filepath, { mode }, function (err) { if (err === null) return cb(null, 0, null) stat(filepath, function (e, st) { if (e) return cb(e, e.errno, null) if (st.isDirectory()) return cb(null, 0, null) cb(err, err.errno, null) }) }) }) }) } function mkdir (filepath, opts, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof opts === 'function') { cb = opts opts = { mode: 0o777 } } else if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } if (typeof opts === 'number') opts = { mode: opts } else if (!opts) opts = {} const mode = typeof opts.mode === 'number' ? opts.mode : 0o777 if (opts.recursive) return mkdirRecursive(filepath.replace(/\//g, path.sep), mode, cb) const req = getReq() req.callback = cb binding.mkdir(req.handle, filepath, mode) } function mkdirRecursiveSync (filepath, mode) { try { mkdirSync(filepath, { mode }) } catch (err) { if (err.code !== 'ENOENT' && statSync(filepath).isDirectory()) { return } while (filepath.endsWith(path.sep)) filepath = filepath.slice(0, -1) const i = filepath.lastIndexOf(path.sep) if (i <= 0) throw err mkdirRecursiveSync(filepath.slice(0, i), { mode }) try { mkdirSync(filepath, { mode }) } catch (err) { if (statSync(filepath).isDirectory()) { return } throw err } } } function mkdirSync (filepath, opts) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof opts === 'number') opts = { mode: opts } else if (!opts) opts = {} const mode = typeof opts.mode === 'number' ? opts.mode : 0o777 if (opts.recursive) return mkdirRecursiveSync(filepath.replace(/\//g, path.sep), mode) binding.mkdirSync(filepath, mode) } function rmdir (filepath, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } const req = getReq() req.callback = cb binding.rmdir(req.handle, filepath) } function rmdirSync (filepath) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } binding.rmdirSync(filepath) } function rmRecursive (filepath, opts, cb) { rmdir(filepath, function (err) { if (err === null) return cb(null) if (err.code !== 'ENOTEMPTY') return cb(err) readdir(filepath, function (err, files) { if (err) return cb(err) if (files.length === 0) return rmdir(filepath, cb) let missing = files.length let done = false for (const file of files) { rm(filepath + path.sep + file, opts, function (err) { if (done) return if (err) { done = true return cb(err) } if (--missing === 0) rmdir(filepath, cb) }) } }) }) } function rm (filepath, opts, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof opts === 'function') { cb = opts opts = {} } else if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } if (!opts) opts = {} lstat(filepath, function (err, st) { if (err) { return cb(err.code === 'ENOENT' && opts.force ? null : err) } if (st.isDirectory()) { if (opts.recursive) return rmRecursive(filepath, opts, cb) const err = new Error('is a directory') err.code = 'EISDIR' return cb(err) } unlink(filepath, cb) }) } function rmRecursiveSync (filepath, opts) { try { rmdirSync(filepath) } catch (err) { if (err.code !== 'ENOTEMPTY') throw err const files = readdirSync(filepath) for (const file of files) { rmSync(filepath + path.sep + file, opts) } rmdirSync(filepath) } } function rmSync (filepath, opts) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (!opts) opts = {} try { const st = lstatSync(filepath) if (st.isDirectory()) { if (opts.recursive) return rmRecursiveSync(filepath, opts) const err = new Error('is a directory') err.code = 'EISDIR' throw err } unlinkSync(filepath) } catch (err) { if (err.code !== 'ENOENT' || !opts.force) throw err } } function unlink (filepath, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } const req = getReq() req.callback = cb binding.unlink(req.handle, filepath) } function unlinkSync (filepath) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } binding.unlinkSync(filepath) } function rename (src, dst, cb) { if (typeof src !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof src) + ' (' + src + ')') } if (typeof dst !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof dst) + ' (' + dst + ')') } if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } const req = getReq() req.callback = cb binding.rename(req.handle, src, dst) } function renameSync (src, dst) { if (typeof src !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof src) + ' (' + src + ')') } if (typeof dst !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof dst) + ' (' + dst + ')') } binding.renameSync(src, dst) } function realpath (filepath, opts, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof opts === 'function') { cb = opts opts = {} } else if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} const { encoding = 'utf8' } = opts const data = Buffer.allocUnsafe(binding.sizeofFSPath) const req = getReq() req.callback = function (err, _) { if (err) return cb(err, null) let path = data.subarray(0, data.indexOf(0)) if (encoding !== 'buffer') path = path.toString(encoding) cb(null, path) } binding.realpath(req.handle, filepath, data) } function realpathSync (filepath, opts) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} const { encoding = 'utf8' } = opts const data = Buffer.allocUnsafe(binding.sizeofFSPath) binding.realpathSync(filepath, data) filepath = data.subarray(0, data.indexOf(0)) if (encoding !== 'buffer') filepath = filepath.toString(encoding) return filepath } function readlink (filepath, opts, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof opts === 'function') { cb = opts opts = {} } else if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} const { encoding = 'utf8' } = opts const data = Buffer.allocUnsafe(binding.sizeofFSPath) const req = getReq() req.callback = function (err, _) { if (err) return cb(err, null) let path = data.subarray(0, data.indexOf(0)) if (encoding !== 'buffer') path = path.toString(encoding) cb(null, path) } binding.readlink(req.handle, filepath, data) } function readlinkSync (filepath, opts) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} const { encoding = 'utf8' } = opts const data = Buffer.allocUnsafe(binding.sizeofFSPath) binding.readlinkSync(filepath, data) filepath = data.subarray(0, data.indexOf(0)) if (encoding !== 'buffer') filepath = filepath.toString(encoding) return filepath } function normalizeSymlinkTarget (target, type, filepath) { if (isWindows) { if (type === 'junction') target = path.resolve(filepath, '..', target) if (path.isAbsolute(target)) return path.toNamespacedPath(target) return target.replace(/\//g, path.sep) } return target } function symlink (target, filepath, type, cb) { if (typeof target !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Target must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof type === 'function') { cb = type type = null } else if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } if (typeof type === 'string') { switch (type) { case 'file': type = 0 break case 'dir': type = constants.UV_FS_SYMLINK_DIR break case 'junction': type = constants.UV_FS_SYMLINK_JUNCTION break default: throw typeError('ERR_FS_INVALID_SYMLINK_TYPE', 'Symlink type must be one of "dir", "file", or "junction". Received "' + type + '"') } } else if (typeof type !== 'number') { if (isWindows) { target = path.resolve(filepath, '..', target) stat(target, (err, st) => { type = err === null && st.isDirectory() ? constants.UV_FS_SYMLINK_DIR : constants.UV_FS_SYMLINK_JUNCTION symlink(target, filepath, type, cb) }) return } type = 0 } const req = getReq() req.callback = cb binding.symlink(req.handle, normalizeSymlinkTarget(target), path.toNamespacedPath(filepath), type) } function symlinkSync (target, filepath, type) { if (typeof target !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Target must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof type === 'string') { switch (type) { case 'file': type = 0 break case 'dir': type = constants.UV_FS_SYMLINK_DIR break case 'junction': type = constants.UV_FS_SYMLINK_JUNCTION break default: throw typeError('ERR_FS_INVALID_SYMLINK_TYPE', 'Symlink type must be one of "dir", "file", or "junction". Received "' + type + '"') } } else if (typeof type !== 'number') { if (isWindows) { target = path.resolve(filepath, '..', target) type = statSync(target).isDirectory() ? constants.UV_FS_SYMLINK_DIR : constants.UV_FS_SYMLINK_JUNCTION } else { type = 0 } } binding.symlinkSync(normalizeSymlinkTarget(target), path.toNamespacedPath(filepath), type) } function opendir (filepath, opts, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof opts === 'function') { cb = opts opts = {} } else if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} const data = Buffer.allocUnsafe(binding.sizeofFSDir) const req = getReq() req.callback = function (err, _) { if (err) return cb(err, null) cb(null, new Dir(filepath, data, opts)) } binding.opendir(req.handle, filepath, data) } function opendirSync (filepath, opts) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} const data = Buffer.allocUnsafe(binding.sizeofFSDir) binding.opendirSync(filepath, data) return new Dir(filepath, data, opts) } function readdir (filepath, opts, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof opts === 'function') { cb = opts opts = {} } else if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} const { withFileTypes = false } = opts opendir(filepath, opts, async (err, dir) => { if (err) return cb(err, null) const result = [] for await (const entry of dir) { result.push(withFileTypes ? entry : entry.name) } cb(null, result) }) } function readdirSync (filepath, opts) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} const { withFileTypes = false } = opts const dir = opendirSync(filepath, opts) const result = [] while (true) { const entry = dir.readSync() if (entry === null) break result.push(withFileTypes ? entry : entry.name) } return result } function readFile (filepath, opts, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof opts === 'function') { cb = opts opts = {} } else if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} const { encoding = 'buffer' } = opts open(filepath, opts.flag || 'r', function (err, fd) { if (err) return cb(err) fstat(fd, function (err, st) { if (err) return closeAndError(err) let buffer = Buffer.allocUnsafe(st.size) let len = 0 read(fd, buffer, loop) function loop (err, r) { if (err) return closeAndError(err) len += r if (r === 0 || len === buffer.byteLength) return done() read(fd, buffer.subarray(len), loop) } function done () { if (len !== buffer.byteLength) buffer = buffer.subarray(0, len) close(fd, function (err) { if (err) return cb(err) if (encoding !== 'buffer') buffer = buffer.toString(encoding) cb(null, buffer) }) } }) function closeAndError (err) { close(fd, function () { cb(err) }) } }) } function readFileSync (filepath, opts) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} const { encoding = 'buffer' } = opts const fd = openSync(filepath, opts.flag || 'r') try { const st = fstatSync(fd) let buffer = Buffer.allocUnsafe(st.size) let len = 0 while (true) { const r = readSync(fd, len ? buffer.subarray(len) : buffer) len += r if (r === 0 || len === buffer.byteLength) break } if (len !== buffer.byteLength) buffer = buffer.subarray(0, len) if (encoding !== 'buffer') buffer = buffer.toString(encoding) return buffer } finally { try { closeSync(fd) } catch {} } } function writeFile (filepath, data, opts, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof data !== 'string' && !Buffer.isBuffer(data) && !ArrayBuffer.isView(data)) { throw typeError('ERR_INVALID_ARG_TYPE', 'Data must be a string or buffer. Received type ' + (typeof data)) } if (typeof opts === 'function') { cb = opts opts = {} } else if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} if (typeof data === 'string') data = Buffer.from(data, opts.encoding) open(filepath, opts.flag || 'w', opts.mode || 0o666, function (err, fd) { if (err) return cb(err) write(fd, data, loop) function loop (err, w) { if (err) return closeAndError(err) if (w === data.byteLength) return done() write(fd, data.subarray(w), loop) } function done () { close(fd, function (err) { if (err) return cb(err) return cb(null) }) } function closeAndError (err) { close(fd, function () { cb(err) }) } }) } function writeFileSync (filepath, data, opts) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof data !== 'string' && !Buffer.isBuffer(data) && !ArrayBuffer.isView(data)) { throw typeError('ERR_INVALID_ARG_TYPE', 'Data must be a string or buffer. Received type ' + (typeof data)) } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} if (typeof data === 'string') data = Buffer.from(data, opts.encoding) const fd = openSync(filepath, opts.flag || 'w', opts.mode) try { let len = 0 while (true) { len += writeSync(fd, len ? data.subarray(len) : data) if (len === data.byteLength) break } } finally { try { closeSync(fd) } catch {} } } function appendFile (filepath, data, opts, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof data !== 'string' && !Buffer.isBuffer(data) && !ArrayBuffer.isView(data)) { throw typeError('ERR_INVALID_ARG_TYPE', 'Data must be a string or buffer. Received type ' + (typeof data)) } if (typeof opts === 'function') { cb = opts opts = {} } else if (typeof cb !== 'function') { throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')') } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} opts = { ...opts } if (!opts.flags) opts.flag = 'a' return writeFile(filepath, data, opts, cb) } function appendFileSync (filepath, data, opts) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof data !== 'string' && !Buffer.isBuffer(data) && !ArrayBuffer.isView(data)) { throw typeError('ERR_INVALID_ARG_TYPE', 'Data must be a string or buffer. Received type ' + (typeof data)) } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} opts = { ...opts } if (!opts.flags) opts.flag = 'a' return writeFileSync(filepath, data, opts) } function watch (filepath, opts, cb) { if (typeof filepath !== 'string') { throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')') } if (typeof opts === 'function') { cb = opts opts = {} } if (typeof opts === 'string') opts = { encoding: opts } else if (!opts) opts = {} const watcher = new Watcher(filepath, opts) if (cb) watcher.on('change', cb) return watcher } class Stats { constructor (dev, mode, nlink, uid, gid, rdev, blksize, ino, size, blocks, atimeMs, mtimeMs, ctimeMs, birthtimeMs) { this.dev = dev this.mode = mode this.nlink = nlink this.uid = uid this.gid = gid this.rdev = rdev this.blksize = blksize this.ino = ino this.size = size this.blocks = blocks this.atimeMs = atimeMs this.mtimeMs = mtimeMs this.ctimeMs = ctimeMs this.birthtimeMs = birthtimeMs this.atime = new Date(atimeMs) this.mtime = new Date(mtimeMs) this.ctime = new Date(ctimeMs) this.birthtime = new Date(birthtimeMs) } isDirectory () { return (this.mode & constants.S_IFMT) === constants.S_IFDIR } isFile () { return (this.mode & constants.S_IFMT) === constants.S_IFREG } isBlockDevice () { return (this.mode & constants.S_IFMT) === constants.S_IFBLK } isCharacterDevice () { return (this.mode & constants.S_IFCHR) === constants.S_IFCHR } isFIFO () { return (this.mode & constants.S_IFMT) === constants.S_IFIFO } isSymbolicLink () { return (this.mode & constants.S_IFMT) === constants.S_IFLNK } isSocket () { return (this.mode & constants.S_IFMT) === constants.S_IFSOCK } } class Dir { constructor (path, handle, opts = {}) { const { encoding = 'utf8', bufferSize = 32 } = opts this._handle = handle this._dirents = Buffer.allocUnsafe(binding.sizeofFSDirent * bufferSize) this._encoding = encoding this._buffer = [] this._ended = false this.path = path } read (cb) { if (!cb) return promisify(this.read.bind(this)) if (this._buffer.length) return queueMicrotask(() => cb(null, this._buffer.shift())) if (this._ended) return queueMicrotask(() => cb(null, null)) const data = [] const req = getReq() req.callback = (err, _) => { if (err) return cb(err, null) if (data.length === 0) this._ended = true else { for (const entry of data) { let name = Buffer.from(entry.name) if (this._encoding !== 'buffer') name = name.toString(this._encoding) this._buffer.push(new Dirent(this.path, name, entry.type)) } } if (this._ended) return cb(null, null) cb(null, this._buffer.shift()) } binding.readdir(req.handle, this._handle, this._dirents, data) } readSync () { if (this._buffer.length) return this._buffer.shift() if (this._ended) return null const data = [] binding.readdirSync(this._handle, this._dirents, data) if (data.length === 0) this._ended = true else { for (const entry of data) { let name = Buffer.from(entry.name) if (this._encoding !== 'buffer') name = name.toString(this._encoding) this._buffer.push(new Dirent(this.path, name, entry.type)) } } if (this._ended) return null return this._buffer.shift() } close (cb) { if (!cb) return promisify(this.close.bind(this)) const req = getReq() req.callback = (err, _) => { this._handle = null cb(err) } binding.closedir(req.handle, this._handle) } closeSync () { binding.closedirSync(this._handle) this._handle = null } [Symbol.iterator] () { return { next: () => { if (this._buffer.length) { return { done: false, value: this._buffer.shift() } } if (this._ended) { return { done: true } } const entry = this.readSync() if (entry) { return { done: false, value: entry } } this.closeSync() return { done: true } } } } [Symbol.asyncIterator] () { return { next: () => new Promise((resolve, reject) => { if (this._buffer.length) { return resolve({ done: false, value: this._buffer.shift() }) } if (this._ended) { return resolve({ done: true }) } this.read((err, entry) => { if (err) return reject(err) if (entry) { return resolve({ done: false, value: entry }) } this.close((err) => err ? reject(err) : resolve({ done: true })) }) }) } } } class Dirent { constructor (path, name, type) { this.type = type this.path = path this.name = name } isFile () { return this.type === constants.UV_DIRENT_FILE } isDirectory () { return this.type === constants.UV_DIRENT_DIR } isSymbolicLink () { return this.type === constants.UV_DIRENT_LINK } isFIFO () { return this.type === constants.UV_DIRENT_FIFO } isSocket () { return this.type === constants.UV_DIRENT_SOCKET } isCharacterDevice () { return this.type === constants.UV_DIRENT_CHAR } isBlockDevice () { return this.type === constants.UV_DIRENT_BLOCK } } class FileWriteStream extends Writable { constructor (path, opts = {}) { super({ map }) this.path = path this.fd = 0 this.flags = opts.flags || 'w' this.mode = opts.mode || 0o666 } _open (cb) { open(this.path, this.flags, this.mode, (err, fd) => { if (err) return cb(err) this.fd = fd cb(null) }) } _writev (batch, cb) { writev(this.fd, batch.map(({ chunk }) => chunk), cb) } _destroy (err, cb) { if (!this.fd) return cb(err) close(this.fd, () => cb(err)) } } class FileReadStream extends Readable { constructor (path, opts = {}) { super() this.path = path this.fd = 0 this._offset = opts.start || 0 this._missing = 0 if (opts.length) this._missing = opts.length else if (typeof opts.end === 'number') this._missing = opts.end - this._offset + 1 else this._missing = -1 } _open (cb) { open(this.path, constants.O_RDONLY, (err, fd) => { if (err) return cb(err) const onerror = (err) => close(fd, () => cb(err)) fstat(fd, (err, st) => { if (err) return onerror(err) if (!st.isFile()) return onerror(new Error(this.path + ' is not a file')) this.fd = fd if (this._missing === -1) this._missing = st.size if (st.size < this._offset) { this._offset = st.size this._missing = 0 return cb(null) } if (st.size < this._offset + this._missing) { this._missing = st.size - this._offset return cb(null) } cb(null) }) }) } _read (size) { if (!this._missing) { this.push(null) return } const data = Buffer.allocUnsafe(Math.min(this._missing, size)) read(this.fd, data, 0, data.byteLength, this._offset, (err, read) => { if (err) return this.destroy(err) if (!read) { this.push(null) return } if (this._missing < read) read = this._missing this.push(data.subarray(0, read)) this._missing -= read this._offset += read if (!this._missing) this.push(null) }) } _destroy (err, cb) { if (!this.fd) return cb(err) close(this.fd, () => cb(err)) } } class Watcher extends EventEmitter { constructor (path, opts) { const { persistent = true, recursive = false, encoding = 'utf8' } = opts super() this._closed = false this._encoding = encoding this._handle = binding.watcherInit(path, recursive, this, this._onevent, this._onclose) if (!persistent) this.unref() } _onevent (err, events, filename) { if (err) { this.close() this.emit('error', err) } else { const path = this._encoding === 'buffer' ? Buffer.from(filename) : Buffer.from(filename).toString(this._encoding) if (events & binding.UV_RENAME) { this.emit('change', 'rename', path) } if (events & binding.UV_CHANGE) { this.emit('change', 'change', path) } } } _onclose () { this._handle = null this.emit('close') } close () { if (this._closed) return this._closed = true binding.watcherClose(this._handle) } ref () { if (this._handle) binding.watcherRef(this._handle) return this } unref () { if (this._handle) binding.watcherUnref(this._handle) return this } [Symbol.asyncIterator] () { const buffer = [] let done = false let error = null let next = null this .on('change', (eventType, filename) => { if (next) { next.resolve({ done: false, value: { eventType, filename } }) next = null } else { buffer.push({ eventType, filename }) } }) .on('error', (err) => { done = true error = err if (next) { next.reject(error) next = null } }) .on('close', () => { done = true if (next) { next.resolve({ done }) next = null } }) return { next: () => new Promise((resolve, reject) => { if (error) return reject(error) if (buffer.length) return resolve({ done: false, value: buffer.shift() }) if (done) return resolve({ done }) next = { resolve, reject } }) } } } exports.promises = {} function typeError (code, message) { const error = new TypeError(message) error.code = code return error } function noop () {} exports.access = access exports.appendFile = appendFile exports.chmod = chmod exports.close = close exports.exists = exists exports.fchmod = fchmod exports.fstat = fstat exports.ftruncate = ftruncate exports.lstat = lstat exports.mkdir = mkdir exports.open = open exports.opendir = opendir exports.read = read exports.readFile = readFile exports.readdir = readdir exports.readlink = readlink exports.readv = readv exports.realpath = realpath exports.rename = rename exports.rm = rm exports.rmdir = rmdir exports.stat = stat exports.symlink = symlink exports.unlink = unlink exports.watch = watch exports.write = write exports.writeFile = writeFile exports.writev = writev exports.accessSync = accessSync exports.appendFileSync = appendFileSync exports.chmodSync = chmodSync exports.closeSync = closeSync exports.existsSync = existsSync exports.fchmodSync = fchmodSync exports.fstatSync = fstatSync exports.lstatSync = lstatSync exports.mkdirSync = mkdirSync exports.openSync = openSync exports.opendirSync = opendirSync exports.readFileSync = readFileSync exports.readSync = readSync exports.readdirSync = readdirSync exports.readlinkSync = readlinkSync exports.realpathSync = realpathSync exports.renameSync = renameSync exports.rmSync = rmSync exports.rmdirSync = rmdirSync exports.statSync = statSync exports.symlinkSync = symlinkSync exports.unlinkSync = unlinkSync exports.writeFileSync = writeFileSync exports.writeSync = writeSync exports.promises.access = promisify(access) exports.promises.appendFile = promisify(appendFile) exports.promises.chmod = promisify(chmod) exports.promises.lstat = promisify(lstat) exports.promises.mkdir = promisify(mkdir) exports.promises.opendir = promisify(opendir) exports.promises.readFile = promisify(readFile) exports.promises.readdir = promisify(readdir) exports.promises.readlink = promisify(readlink) exports.promises.realpath = promisify(realpath) exports.promises.rename = promisify(rename) exports.promises.rm = promisify(rm) exports.promises.rmdir = promisify(rmdir) exports.promises.stat = promisify(stat) exports.promises.symlink = promisify(symlink) exports.promises.unlink = promisify(unlink) exports.promises.writeFile = promisify(writeFile) exports.promises.watch = watch // Already async iterable exports.Stats = Stats exports.Dir = Dir exports.Dirent = Dirent exports.Watcher = Watcher exports.ReadStream = FileReadStream exports.createReadStream = function createReadStream (path, opts) { return new FileReadStream(path, opts) } exports.WriteStream = FileWriteStream exports.createWriteStream = function createWriteStream (path, opts) { return new FileWriteStream(path, opts) } function promisify (fn) { return function (...args) { return new Promise((resolve, reject) => { fn(...args, function (err, res) { if (err) return reject(err) resolve(res) }) }) } } function map (data) { return typeof data === 'string' ? Buffer.from(data) : data }