Comparing version 0.0.15 to 2.0.1
1048
index.js
@@ -1,1047 +0,1 @@ | ||
/// <reference path="typings/tsd.d.ts" /> | ||
"use strict"; | ||
var __extends = (this && this.__extends) || function (d, b) { | ||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
/** | ||
* path.resolve | ||
* path.sep | ||
* path.relative | ||
* path.dirname | ||
*/ | ||
var process = require('process'); | ||
if (typeof window === 'object') | ||
window.process = process; | ||
var path = require('path'); | ||
var time = new Date; | ||
var memfs; | ||
(function (memfs) { | ||
// Like `fs.Stats` | ||
var Stats = (function () { | ||
function Stats() { | ||
//this.uid = process.getuid(); | ||
this.uid = 0; | ||
//this.gid = process.getgid(); | ||
this.gid = 0; | ||
this.rdev = 0; | ||
this.blksize = 4096; | ||
this.ino = 0; | ||
this.size = 0; | ||
this.blocks = 1; | ||
this.atime = time; | ||
this.mtime = time; | ||
this.ctime = time; | ||
this.birthtime = time; | ||
this.dev = 0; | ||
this.mode = 0; | ||
this.nlink = 0; | ||
this._isFile = false; | ||
this._isDirectory = false; | ||
} | ||
Stats.build = function (node) { | ||
var stats = new Stats; | ||
stats.uid = node.uid; | ||
stats.gid = node.gid; | ||
stats.atime = node.atime; | ||
stats.mtime = node.mtime; | ||
stats.ctime = node.ctime; | ||
if (node instanceof Directory) { | ||
stats._isDirectory = true; | ||
} | ||
else if (node instanceof File) { | ||
var data = node.getData(); | ||
stats.size = data.length; | ||
stats._isFile = true; | ||
} | ||
return stats; | ||
}; | ||
Stats.prototype.isFile = function () { | ||
return this._isFile; | ||
}; | ||
Stats.prototype.isDirectory = function () { | ||
return this._isDirectory; | ||
}; | ||
Stats.prototype.isSymbolicLink = function () { | ||
return false; | ||
}; | ||
return Stats; | ||
}()); | ||
memfs.Stats = Stats; | ||
var Node = (function () { | ||
function Node(relative, layer) { | ||
// File descriptor, negative, because a real file descriptors cannot be negative. | ||
this.fd = Node.fd--; | ||
this.uid = 0; | ||
//uid: number = process.getuid(); | ||
this.gid = 0; | ||
//gid: number = process.getgid(); | ||
this.atime = new Date; | ||
this.mtime = new Date; | ||
this.ctime = new Date; | ||
this.relative = relative; | ||
this.path = path.resolve(layer.mountpoint, relative); | ||
this.layer = layer; | ||
} | ||
Node.prototype.getData = function () { | ||
return ''; | ||
}; | ||
Node.prototype.setData = function (data) { | ||
}; | ||
Node.prototype.getPath = function () { | ||
return this.path; | ||
}; | ||
Node.prototype.stats = function () { | ||
return Stats.build(this); | ||
}; | ||
Node.prototype.chown = function (uid, gid) { | ||
this.uid = uid; | ||
this.gid = gid; | ||
}; | ||
Node.fd = -1; | ||
return Node; | ||
}()); | ||
memfs.Node = Node; | ||
var File = (function (_super) { | ||
__extends(File, _super); | ||
function File() { | ||
_super.apply(this, arguments); | ||
// A "cursor" position in a file, where data will be written. | ||
this.position = 0; | ||
} | ||
File.prototype.getData = function () { | ||
return this.layer.files[this.relative]; | ||
}; | ||
File.prototype.setData = function (data) { | ||
this.layer.files[this.relative] = data.toString(); | ||
}; | ||
File.prototype.truncate = function (len) { | ||
if (len === void 0) { len = 0; } | ||
this.setData(this.getData().substr(0, len)); | ||
}; | ||
return File; | ||
}(Node)); | ||
memfs.File = File; | ||
var Directory = (function (_super) { | ||
__extends(Directory, _super); | ||
function Directory() { | ||
_super.apply(this, arguments); | ||
} | ||
return Directory; | ||
}(Node)); | ||
memfs.Directory = Directory; | ||
// A single `JSON` file of data mounted to a single mount point. | ||
// We have it so that we can store file contents in a single JS string dictionary. | ||
var Layer = (function () { | ||
function Layer(mountpoint, files) { | ||
/** | ||
* A map of relative file names to file contents 'string'. | ||
* { | ||
* "test.txt": "...." | ||
* "some/path/hello.txt": "world ..." | ||
* } | ||
*/ | ||
this.files = {}; | ||
this.mountpoint = path.resolve(mountpoint); | ||
this.files = files; | ||
} | ||
return Layer; | ||
}()); | ||
memfs.Layer = Layer; | ||
// A collection of layers, we have this, so that we override functions with `.attach()` only once. | ||
var Volume = (function () { | ||
function Volume() { | ||
this.memfs = memfs; | ||
// A flattened map of all nodes in this file system. | ||
this.flattened = {}; | ||
// Collection of file layers, where the top ones override the bottom ones. | ||
this.layers = []; | ||
// A map of pseudo 'file descriptors' to LNodes. | ||
this.fds = {}; | ||
} | ||
Volume.prototype.normalize = function (somepath) { | ||
somepath = path.normalize(somepath); | ||
// Remove trailing slash. | ||
if (somepath[somepath.length - 1] == path.sep) | ||
somepath = somepath.substr(0, somepath.length - 1); | ||
return somepath; | ||
}; | ||
Volume.prototype.addDir = function (fullpath, layer) { | ||
fullpath = this.normalize(fullpath); | ||
if (this.flattened[fullpath]) | ||
throw Error('Node already exists: ' + fullpath); | ||
var relative = path.relative(layer.mountpoint, fullpath); | ||
relative = relative.replace(/\\/g, '/'); // Always use forward slashed in our virtual relative paths. | ||
var directory = new Directory(relative, layer); | ||
this.flattened[fullpath] = directory; | ||
this.fds[directory.fd] = directory; | ||
return directory; | ||
}; | ||
Volume.prototype.addFile = function (fullpath, layer) { | ||
fullpath = this.normalize(fullpath); | ||
if (this.flattened[fullpath]) | ||
throw Error('Node already exists: ' + fullpath); | ||
var relative = path.relative(layer.mountpoint, fullpath); | ||
relative = relative.replace(/\\/g, '/'); // Always use forward slashed in our virtual relative paths. | ||
var node = new File(relative, layer); | ||
this.flattened[fullpath] = node; | ||
this.fds[node.fd] = node; | ||
var steps = relative.split('/'); | ||
var dirfullpath = layer.mountpoint; | ||
for (var i = 0; i < steps.length - 1; i++) { | ||
dirfullpath += path.sep + steps[i]; | ||
var exists = !!this.flattened[fullpath]; | ||
if (!exists) | ||
this.addDir(dirfullpath, layer); | ||
} | ||
return node; | ||
}; | ||
Volume.prototype.addLayer = function (layer) { | ||
this.layers.push(layer); | ||
var mountpoint = path.resolve(layer.mountpoint) + path.sep; | ||
// Add the root dir at the mount point. | ||
this.addDir(mountpoint, layer); | ||
for (var relative in layer.files) { | ||
var filepath = relative.replace(/\//g, path.sep); | ||
var fullpath = mountpoint + filepath; | ||
this.addFile(fullpath, layer); | ||
} | ||
}; | ||
Volume.prototype.getFilePath = function (p) { | ||
var filepath = path.resolve(p); | ||
var node = this.getNode(filepath); | ||
return node ? node : null; | ||
}; | ||
Volume.prototype.getNode = function (p) { | ||
var filepath = path.resolve(p); | ||
var node = this.flattened[filepath]; | ||
if (!node) | ||
throw this.err404(filepath); | ||
return node; | ||
}; | ||
Volume.prototype.getFile = function (p) { | ||
var node = this.getNode(p); | ||
if (node instanceof File) | ||
return node; | ||
else | ||
throw this.err404(node.path); | ||
}; | ||
Volume.prototype.getDirectory = function (p) { | ||
var node = this.getNode(p); | ||
if (node instanceof Directory) | ||
return node; | ||
else | ||
throw Error('Directory not found: ' + node.path); | ||
}; | ||
Volume.prototype.getByFd = function (fd) { | ||
var node = this.fds[fd]; | ||
if (node) | ||
return node; | ||
else | ||
throw Error('Node file descriptor not found: ' + fd); | ||
}; | ||
Volume.prototype.getLayerContainingPath = function (fullpath) { | ||
for (var i = 0; i < this.layers.length; i++) { | ||
var layer = this.layers[i]; | ||
if (fullpath.indexOf(layer.mountpoint) === 0) | ||
return layer; | ||
} | ||
return null; | ||
}; | ||
Volume.prototype.err404 = function (file) { | ||
return Error('File not found: ' + file); | ||
}; | ||
/** | ||
* Mount virtual in-memory files. | ||
* @param mountpoint Path to the root of the mounting point. | ||
* @param files A dictionary of relative file paths to their contents. | ||
*/ | ||
Volume.prototype.mountSync = function (mountpoint, files) { | ||
if (files === void 0) { files = {}; } | ||
var layer = new Layer(mountpoint, files); | ||
this.addLayer(layer); | ||
}; | ||
// TODO: Mount from URL? | ||
// TODO: `mount('/usr/lib', 'http://example.com/volumes/usr/lib.json', callback)` | ||
// TODO: ...also cache that it has been loaded... | ||
Volume.prototype.mount = function (mountpoint, files, callback) { | ||
}; | ||
// fs.readFile(filename[, options]) | ||
Volume.prototype.readFileSync = function (file, encoding) { | ||
var f = this.getFile(file); | ||
if (encoding) { | ||
return f.getData(); // String | ||
} | ||
else { | ||
// return f.getData(); // String | ||
var Buffer = require('buffer').Buffer; | ||
return new Buffer(f.getData()); // Buffer | ||
} | ||
}; | ||
// fs.readFile(filename[, options], callback) | ||
Volume.prototype.readFile = function (file, opts, cb) { | ||
if (typeof opts == "function") { | ||
cb = opts; | ||
opts = {}; | ||
} | ||
try { | ||
var f = this.getFile(file); // This throws, or succeeds. | ||
var self = this; | ||
process.nextTick(function () { | ||
var result = self.readFileSync(file, opts); | ||
cb(null, result); | ||
}); | ||
} | ||
catch (e) { | ||
cb(e); | ||
} | ||
}; | ||
// fs.realpathSync(path[, cache]) | ||
Volume.prototype.realpathSync = function (file, opts) { | ||
var node = this.getNode(file); // This throws, or succeeds. | ||
return node.path; | ||
}; | ||
// fs.realpath(path[, cache], callback) | ||
Volume.prototype.realpath = function (filepath, cache, callback) { | ||
if (typeof cache == "function") | ||
callback = cache; | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
callback(null, self.realpathSync(filepath, cache)); | ||
} | ||
catch (e) { | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.statSync(path) | ||
Volume.prototype.statSync = function (p) { | ||
var node = this.getNode(p); | ||
return node.stats(); | ||
}; | ||
// fs.lstatSync(path) | ||
Volume.prototype.lstatSync = function (p) { | ||
return this.statSync(p); | ||
}; | ||
// fs.stat(path, callback) | ||
Volume.prototype.stat = function (p, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
callback(null, self.statSync(p)); | ||
} | ||
catch (e) { | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.lstat(path, callback) | ||
Volume.prototype.lstat = function (p, callback) { | ||
this.stat(p, callback); | ||
}; | ||
//fs.renameSync(oldPath, newPath) | ||
Volume.prototype.renameSync = function (oldPath, newPath) { | ||
var node = this.getNode(oldPath); | ||
oldPath = node.path; | ||
newPath = path.resolve(newPath); | ||
delete this.flattened[oldPath]; | ||
this.flattened[newPath] = node; | ||
node.path = newPath; | ||
node.relative = path.relative(node.layer.mountpoint, newPath); | ||
}; | ||
//fs.renameSync(oldPath, newPath[, cb]) | ||
Volume.prototype.rename = function (oldPath, newPath, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.renameSync(oldPath, newPath); | ||
if (callback) | ||
callback(); // Docs: "Returns nothing or exception." | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
//fs.fstatSync(fd) | ||
Volume.prototype.fstatSync = function (fd) { | ||
var node = this.getByFd(fd); | ||
return node.stats(); | ||
}; | ||
// fs.fstat(fd, callback) | ||
Volume.prototype.fstat = function (fd, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
callback(null, self.fstatSync(fd)); | ||
} | ||
catch (e) { | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.writeFileSync(filename, data[, options]) | ||
Volume.prototype.writeFileSync = function (filename, data, options) { | ||
try { | ||
var file = this.getFile(filename); | ||
} | ||
catch (e) { | ||
var fullpath = path.resolve(filename); | ||
var layer = this.getLayerContainingPath(fullpath); | ||
if (!layer) | ||
throw Error('Cannot create new file at this path: ' + fullpath); | ||
var file = this.addFile(fullpath, layer); | ||
} | ||
file.setData(data.toString()); | ||
}; | ||
// fs.writeFile(filename, data[, options], callback) | ||
Volume.prototype.writeFile = function (filename, data, options, callback) { | ||
if (typeof options == "function") { | ||
callback = options; | ||
options = null; | ||
} | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.writeFileSync(filename, data, options); | ||
if (callback) | ||
callback(); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.existsSync(filename) | ||
Volume.prototype.existsSync = function (filename) { | ||
// This will make `unionfs` to forward ask next file system for `existsSync`. | ||
var fullpath = path.resolve(filename); | ||
if (!this.getLayerContainingPath(fullpath)) | ||
throw ('Path not in mount point.'); | ||
try { | ||
this.getNode(filename); | ||
return true; | ||
} | ||
catch (e) { | ||
return false; | ||
} | ||
}; | ||
// fs.exists(filename, callback) | ||
Volume.prototype.exists = function (filename, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
callback(self.existsSync(filename)); | ||
}); | ||
}; | ||
// fs.readdirSync(path) | ||
Volume.prototype.readdirSync = function (p) { | ||
var fullpath = path.resolve(p); | ||
// Check the path points into at least one of the directories our layers are mounted to. | ||
var layer = this.getLayerContainingPath(fullpath); | ||
if (!layer) { | ||
throw Error('Directory not found: ' + fullpath); | ||
} | ||
// Check directory exists. | ||
try { | ||
var dir = this.getDirectory(fullpath); | ||
} | ||
catch (e) { | ||
throw Error("ENOENT: no such file or directory, scandir '" + fullpath + "'"); | ||
} | ||
var len = fullpath.length; | ||
var index = {}; | ||
for (var nodepath in this.flattened) { | ||
if (nodepath.indexOf(fullpath) === 0) { | ||
try { | ||
var node = this.getNode(nodepath); | ||
} | ||
catch (e) { | ||
// This should never happen. | ||
throw e; | ||
} | ||
// console.log(node); | ||
var relative = nodepath.substr(len + 1); | ||
var sep_pos = relative.indexOf(path.sep); | ||
if (sep_pos > -1) | ||
relative = relative.substr(0, sep_pos); | ||
if (relative) | ||
index[relative] = 1; | ||
} | ||
} | ||
var files = []; | ||
for (var file in index) | ||
files.push(file); | ||
return files; | ||
}; | ||
// fs.readdir(path, callback) | ||
Volume.prototype.readdir = function (p, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
callback(null, self.readdirSync(p)); | ||
} | ||
catch (e) { | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.appendFileSync(filename, data[, options]) | ||
Volume.prototype.appendFileSync = function (filename, data, options) { | ||
try { | ||
var file = this.getFile(filename); | ||
file.setData(file.getData() + data.toString()); | ||
} | ||
catch (e) { | ||
var fullpath = path.resolve(filename); | ||
var layer = this.getLayerContainingPath(fullpath); | ||
if (!layer) | ||
throw Error('Cannot create new file at this path: ' + fullpath); | ||
var file = this.addFile(fullpath, layer); | ||
file.setData(data.toString()); | ||
} | ||
}; | ||
// fs.appendFile(filename, data[, options], callback) | ||
Volume.prototype.appendFile = function (filename, data, options, callback) { | ||
if (typeof options == 'function') { | ||
callback = options; | ||
options = null; | ||
} | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.appendFileSync(filename, data, options); | ||
if (callback) | ||
callback(); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.unlinkSync(path) | ||
Volume.prototype.unlinkSync = function (filename) { | ||
var node = this.getNode(filename); | ||
delete node.layer.files[node.relative]; | ||
delete this.flattened[node.path]; | ||
delete this.fds[node.fd]; | ||
}; | ||
// fs.unlink(path, callback) | ||
Volume.prototype.unlink = function (filename, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.unlinkSync(filename); | ||
if (callback) | ||
callback(); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.truncateSync(path, len) | ||
Volume.prototype.truncateSync = function (filename, len) { | ||
var file = this.getFile(filename); | ||
file.truncate(len); | ||
}; | ||
// fs.truncate(path, len, callback) | ||
Volume.prototype.truncate = function (filename, len, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.truncateSync(filename, len); | ||
if (callback) | ||
callback(); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.ftruncateSync(fd, len) | ||
Volume.prototype.ftruncateSync = function (fd, len) { | ||
var node = this.getByFd(fd); | ||
if (!(node instanceof File)) | ||
this.err404(node.path); | ||
node.truncate(len); | ||
}; | ||
// fs.ftruncate(fd, len, callback) | ||
Volume.prototype.ftruncate = function (fd, len, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.ftruncateSync(fd, len); | ||
if (callback) | ||
callback(); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.chownSync(path, uid, gid) | ||
Volume.prototype.chownSync = function (filename, uid, gid) { | ||
var node = this.getNode(filename); | ||
node.chown(uid, gid); | ||
}; | ||
// fs.chown(path, uid, gid, callback) | ||
Volume.prototype.chown = function (filename, uid, gid, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.chownSync(filename, uid, gid); | ||
if (callback) | ||
callback(); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.fchownSync(fd, uid, gid) | ||
Volume.prototype.fchownSync = function (fd, uid, gid) { | ||
var node = this.getByFd(fd); | ||
node.chown(uid, gid); | ||
}; | ||
// fs.fchown(fd, uid, gid, callback) | ||
Volume.prototype.fchown = function (fd, uid, gid, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.fchownSync(fd, uid, gid); | ||
if (callback) | ||
callback(); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.lchownSync(path, uid, gid) | ||
Volume.prototype.lchownSync = function (filename, uid, gid) { | ||
this.chownSync(filename, uid, gid); | ||
}; | ||
// fs.lchown(path, uid, gid, callback) | ||
Volume.prototype.lchown = function (filename, uid, gid, callback) { | ||
this.chown(filename, uid, gid, callback); | ||
}; | ||
// fs.chmodSync(path, mode) | ||
Volume.prototype.chmodSync = function (filename, mode) { | ||
this.getNode(filename); // Does nothing, but throws if `filename` does not resolve to a node. | ||
}; | ||
// fs.chmod(filename, mode, callback) | ||
Volume.prototype.chmod = function (filename, mode, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.chmodSync(filename, mode); | ||
if (callback) | ||
callback(); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.fchmodSync(fd, mode) | ||
Volume.prototype.fchmodSync = function (fd, mode) { | ||
this.getByFd(fd); | ||
}; | ||
// fs.fchmod(fd, mode, callback) | ||
Volume.prototype.fchmod = function (fd, mode, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.fchmodSync(fd, mode); | ||
if (callback) | ||
callback(); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.lchmodSync(path, mode) | ||
Volume.prototype.lchmodSync = function (filename, mode) { | ||
this.chmodSync(filename, mode); | ||
}; | ||
// fs.lchmod(path, mode, callback) | ||
Volume.prototype.lchmod = function (filename, mode, callback) { | ||
this.chmod(filename, mode, callback); | ||
}; | ||
// fs.rmdirSync(path) | ||
Volume.prototype.rmdirSync = function (p) { | ||
var dir = this.getDirectory(p); | ||
delete this.flattened[dir.path]; | ||
delete this.fds[dir.fd]; | ||
}; | ||
// fs.rmdir(path, callback) | ||
Volume.prototype.rmdir = function (p, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.rmdirSync(p); | ||
if (callback) | ||
callback(); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.openSync(path, flags[, mode]) | ||
Volume.prototype.openSync = function (p, flags, mode) { | ||
var file = this.getFile(p); | ||
return file.fd; | ||
}; | ||
// fs.open(path, flags[, mode], callback) | ||
Volume.prototype.open = function (p, flags, mode, callback) { | ||
if (typeof mode == 'function') { | ||
callback = mode; | ||
mode = 438; // 0666 | ||
} | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
callback(null, self.openSync(p, flags, mode)); | ||
} | ||
catch (e) { | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.utimesSync(path, atime, mtime) | ||
Volume.prototype.utimesSync = function (filename, atime, mtime) { | ||
var node = this.getNode(filename); | ||
node.atime = atime; | ||
node.mtime = mtime; | ||
}; | ||
// fs.utimes(path, atime, mtime, callback) | ||
Volume.prototype.utimes = function (filename, atime, mtime, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
callback(null, self.utimesSync(filename, atime, mtime)); | ||
} | ||
catch (e) { | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.futimesSync(fd, atime, mtime) | ||
Volume.prototype.futimesSync = function (fd, atime, mtime) { | ||
var node = this.getByFd(fd); | ||
node.atime = atime; | ||
node.mtime = mtime; | ||
}; | ||
// fs.futimes(fd, atime, mtime, callback) | ||
Volume.prototype.futimes = function (fd, atime, mtime, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
callback(null, self.futimesSync(fd, atime, mtime)); | ||
} | ||
catch (e) { | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.accessSync(path[, mode]) | ||
Volume.prototype.accessSync = function (filename, mode) { | ||
// fs.F_OK | fs.R_OK | fs.W_OK | fs.X_OK | ||
// Everything passes, as long as a node exists. | ||
this.getNode(filename); | ||
}; | ||
// fs.access(path[, mode], callback) | ||
Volume.prototype.access = function (filename, mode, callback) { | ||
if (typeof mode == 'function') { | ||
callback = mode; | ||
mode = 7; // fs.F_OK | fs.R_OK | fs.W_OK | fs.X_OK | ||
} | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.accessSync(filename, mode); | ||
callback(); | ||
} | ||
catch (e) { | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.closeSync(fd) | ||
Volume.prototype.closeSync = function (fd) { | ||
this.getNode(fd); | ||
}; | ||
// fs.close(fd, callback) | ||
Volume.prototype.close = function (fd, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.closeSync(fd); | ||
if (callback) | ||
callback(); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.mkdirSync(path[, mode]) | ||
Volume.prototype.mkdirSync = function (p, mode) { | ||
var fullpath = path.resolve(p); | ||
var layer = this.getLayerContainingPath(fullpath); | ||
if (!layer) | ||
throw Error('Cannot create directory at this path: ' + fullpath); | ||
// Check if parent directory exists. | ||
try { | ||
var parent = path.dirname(fullpath); | ||
var dir = this.getDirectory(parent); | ||
} | ||
catch (e) { | ||
throw Error("ENOENT: no such file or directory, mkdir '" + fullpath + "'"); | ||
} | ||
this.addDir(fullpath, layer); | ||
}; | ||
// fs.mkdir(path[, mode], callback) | ||
Volume.prototype.mkdir = function (p, mode, callback) { | ||
if (typeof mode == 'function') { | ||
callback = mode; | ||
mode = 511; // 0777 | ||
} | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.mkdirSync(p, mode); | ||
if (callback) | ||
callback(); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
Volume.prototype.writeSync = function (fd, data, position, encoding) { | ||
var file = this.getByFd(fd); | ||
if (!(file instanceof File)) | ||
throw Error('Is not a file: ' + file.path); | ||
var Buffer = require('buffer').Buffer; | ||
if (!(data instanceof Buffer)) { | ||
// Docs: "If data is not a Buffer instance then the value will be coerced to a string." | ||
data = data.toString(); | ||
} | ||
else { | ||
var buffer = data; | ||
var offset = position; | ||
var length = encoding; | ||
position = arguments[4]; | ||
data = buffer.slice(offset, length); | ||
data = data.toString(); | ||
} | ||
if (typeof position == 'undefined') | ||
position = file.position; | ||
var cont = file.getData(); | ||
cont = cont.substr(0, position) + data + cont.substr(position + data.length); | ||
file.setData(cont); | ||
file.position = position + data.length; | ||
//return data.length; | ||
return Buffer.byteLength(data, encoding); | ||
}; | ||
//fs.write(fd, data[, position[, encoding]], callback) | ||
//fs.write(fd, buffer, offset, length[, position], callback) | ||
Volume.prototype.write = function (fd, buffer, offset, length, position, callback) { | ||
if (typeof position == 'function') { | ||
callback = position; | ||
position = void 0; | ||
} | ||
if (typeof length == 'function') { | ||
callback = length; | ||
length = position = void 0; | ||
} | ||
if (typeof offset == 'function') { | ||
callback = offset; | ||
offset = length = position = void 0; | ||
} | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
var bytes = self.writeSync(fd, buffer, offset, length, position); | ||
if (callback) | ||
callback(null, bytes); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.readSync(fd, buffer, offset, length, position) | ||
Volume.prototype.readSync = function (fd, buffer, offset, length, position) { | ||
// TODO: Node.js will read the file forever in `.creatReadStream` mode. | ||
// TODO: We need to generate new file descriptor `fd` for every new `openSync` | ||
// TODO: and track position in file for every `readSync` and then when we are at the EOF | ||
// TODO: we should return 0 (zero bytes read) so the stream closes. | ||
var file = this.getByFd(fd); | ||
if (!(file instanceof File)) | ||
throw Error('Not a file: ' + file.path); | ||
var data = file.getData(); | ||
if (position === null) | ||
position = file.position; | ||
var chunk = data.substr(position, length); | ||
buffer.write(chunk, offset, length); | ||
return chunk.length; | ||
}; | ||
// fs.read(fd, buffer, offset, length, position, callback) | ||
Volume.prototype.read = function (fd, buffer, offset, length, position, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
var bytes = self.readSync(fd, buffer, offset, length, position); | ||
callback(null, bytes, buffer); | ||
} | ||
catch (e) { | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.linkSync(srcpath, dstpath) | ||
Volume.prototype.linkSync = function (srcpath, dstpath) { | ||
var node = this.getNode(srcpath); | ||
dstpath = path.resolve(dstpath); | ||
if (this.flattened[dstpath]) | ||
throw Error('Destination path already in use: ' + dstpath); | ||
this.flattened[dstpath] = node; | ||
}; | ||
// fs.link(srcpath, dstpath, callback) | ||
Volume.prototype.link = function (srcpath, dstpath, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.linkSync(srcpath, dstpath); | ||
if (callback) | ||
callback(); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.symlinkSync(srcpath, dstpath[, type]) | ||
Volume.prototype.symlinkSync = function (srcpath, dstpath, t) { | ||
this.linkSync(srcpath, dstpath); | ||
}; | ||
// fs.symlink(srcpath, dstpath[, type], callback) | ||
Volume.prototype.symlink = function (srcpath, dstpath, t, callback) { | ||
if (typeof t == 'function') { | ||
callback = t; | ||
t = void 0; | ||
} | ||
this.link(srcpath, dstpath, callback); | ||
}; | ||
// fs.readlinkSync(path) | ||
Volume.prototype.readlinkSync = function (p) { | ||
var node = this.getNode(p); | ||
return node.path; | ||
}; | ||
// fs.readlink(path, callback) | ||
Volume.prototype.readlink = function (p, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
callback(null, self.readlinkSync(p)); | ||
} | ||
catch (e) { | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.fsyncSync(fd) | ||
Volume.prototype.fsyncSync = function (fd) { | ||
this.getByFd(fd); | ||
}; | ||
// fs.fsync(fd, callback) | ||
Volume.prototype.fsync = function (fd, callback) { | ||
var self = this; | ||
process.nextTick(function () { | ||
try { | ||
self.fsyncSync(fd); | ||
if (callback) | ||
callback(); | ||
} | ||
catch (e) { | ||
if (callback) | ||
callback(e); | ||
} | ||
}); | ||
}; | ||
// fs.createReadStream(path[, options]) | ||
Volume.prototype.createReadStream = function (p, options) { | ||
options = options || {}; | ||
var file = options.fd ? this.getByFd(options.fd) : this.getFile(p); | ||
if (!(file instanceof File)) | ||
throw Error('Not a file: ' + file.path); | ||
var util = require('util'); | ||
var Readable = require('stream').Readable; | ||
var Buffer = require('buffer').Buffer; | ||
function MemFileReadStream(opt) { | ||
Readable.call(this, opt); | ||
this.done = false; | ||
} | ||
util.inherits(MemFileReadStream, Readable); | ||
MemFileReadStream.prototype._read = function () { | ||
if (!this.done) { | ||
this.push(new Buffer(file.getData())); | ||
// this.push(null); | ||
this.done = true; | ||
} | ||
else { | ||
this.push(null); | ||
} | ||
}; | ||
return new MemFileReadStream(); | ||
}; | ||
// fs.createWriteStream(path[, options]) | ||
Volume.prototype.createWriteStream = function (p, options) { | ||
options = options || {}; | ||
var file = (options.fd ? this.getByFd(options.fd) : this.getFile(p)); | ||
if (!(file instanceof File)) | ||
throw Error('Not a file: ' + file.path); | ||
if (options.start) | ||
file.position = options.start; | ||
var util = require('util'); | ||
var Writable = require('stream').Writable; | ||
var Buffer = require('buffer').Buffer; | ||
function MemFileWriteStream(opt) { | ||
Writable.call(this, opt); | ||
} | ||
util.inherits(MemFileWriteStream, Writable); | ||
MemFileWriteStream.prototype._write = function (chunk) { | ||
chunk = chunk.toString(); | ||
var cont = file.getData(); | ||
cont = cont.substr(0, file.position) + chunk + cont.substr(file.position + chunk.length); | ||
file.setData(cont); | ||
file.position += chunk.length; | ||
}; | ||
return new MemFileWriteStream(); | ||
}; | ||
return Volume; | ||
}()); | ||
memfs.Volume = Volume; | ||
})(memfs || (memfs = {})); | ||
module.exports = memfs; | ||
module.exports = require('lib/index'); |
{ | ||
"name": "memfs", | ||
"version": "0.0.15", | ||
"description": "In-memory file-system with node.js `fs` API", | ||
"main": "index.js", | ||
"keywords": ["fs", "file", "file system", "mount", "memory", "in-memory", "virtual"], | ||
"version": "2.0.1", | ||
"description": "In-memory file-system with Node's fs API.", | ||
"main": "lib/index.js", | ||
"keywords": [ | ||
"fs", "fs.js", "memory-fs", "memfs", | ||
"file", "file system", "mount", "memory", | ||
"in-memory", "virtual", "test", "testing", "mock"], | ||
"repository": { | ||
@@ -12,12 +15,56 @@ "type" : "git", | ||
"scripts": { | ||
"test": "mocha" | ||
"build": "npm run build-ts && npm run build-js", | ||
"build-ts": "./node_modules/.bin/gulp build-ts", | ||
"build-js": "./node_modules/.bin/babel src --out-dir lib", | ||
"test": "npm run test-coverage", | ||
"test-basic": "./node_modules/.bin/mocha --require ts-node/register src/**/*.test.ts src/**/*.test.tsx", | ||
"test-watch": "./node_modules/.bin/mocha --require ts-node/register src/**/*.test.ts src/**/*.test.tsx --watch", | ||
"test-coverage": "nyc --per-file mocha --require ts-node/register --require source-map-support/register --full-trace --bail src/**/*.test.ts" | ||
}, | ||
"dependencies": { | ||
"path": "0.12.7", | ||
"process": "0.11.9", | ||
"buffer": "5.0.2" | ||
"fast-extend": "0.0.2" | ||
}, | ||
"devDependencies": { | ||
"chai": "*" | ||
"mocha": "3.4.2", | ||
"chai": "4.1.0", | ||
"typescript": "2.4.2", | ||
"ts-node": "3.3.0", | ||
"babel-cli": "6.24.1", | ||
"babel-preset-es2015": "6.24.1", | ||
"gulp": "3.9.1", | ||
"gulp-typescript": "3.2.1", | ||
"source-map-support": "0.4.15", | ||
"nyc": "11.1.0", | ||
"@types/mocha": "2.2.41", | ||
"@types/chai": "4.0.1", | ||
"@types/node": "8.0.17" | ||
}, | ||
"nyc": { | ||
"per-file": true, | ||
"include": [ | ||
"src/**/*.ts", | ||
"src/**/*.tsx" | ||
], | ||
"exclude": [ | ||
"src/**/*.test.ts", | ||
"src/**/*.test.tsx" | ||
], | ||
"extension": [ | ||
".ts", | ||
".tsx" | ||
], | ||
"require": [ | ||
"ts-node/register" | ||
], | ||
"reporter": [ | ||
"text", | ||
"json", | ||
"lcov", | ||
"text-summary" | ||
], | ||
"sourceMap": true, | ||
"instrument": true, | ||
"cache": true | ||
} | ||
} |
299
README.md
@@ -1,42 +0,285 @@ | ||
# memfs | ||
# memfs 2.0 | ||
[See example in browser.](https://jsfiddle.net/6a96vLoj/2/) | ||
In-memory file-system with [Node's `fs` API](https://nodejs.org/api/fs.html). | ||
A [`fs`](https://nodejs.org/api/fs.html) API to work with *virtual in-memory* files. | ||
[![][npm-img]][npm-url] | ||
```javascript | ||
var memfs = require('memfs'); | ||
- 100% of Node's `fs` API implemented, see *API Status* | ||
- Stores files in memory, in `Buffer`s | ||
- Throws same* errors as Node.js | ||
- Has concept of *i-nodes* | ||
- Implements *hard links* | ||
- Implements *soft links* (aka symlinks, symbolic links) | ||
- More testing coming soon* | ||
- Permissions may* be implemented in the future | ||
var mem = new memfs.Volume; | ||
mem.mountSync('./', { | ||
"test.js": "console.log(123);", | ||
"dir/hello.js": "console.log('hello world');" | ||
}); | ||
Usage: | ||
console.log(mem.readFileSync('./dir/hello.js').toString()); | ||
```js | ||
import {fs} from 'memfs'; | ||
fs.writeFileSync('/hello.txt', 'World!'); | ||
fs.readFileSync('/hello.txt', 'utf8'); // World! | ||
``` | ||
Use it together with [`unionfs`](http://www.npmjs.com/package/unionfs): | ||
Create a file system from a plain JSON: | ||
```javascript | ||
var unionfs = require('unionfs'); | ||
var fs = require('fs'); | ||
```js | ||
import {fs, vol} from 'memfs'; | ||
// Create a union of two file systems: | ||
unionfs | ||
vol.importJSON({ | ||
'./README.md': '1', | ||
'./src/index.js': '2', | ||
'./node_modules/debug/index.js': '3', | ||
}, '/app'); | ||
fs.readFileSync('/app/README.md', 'utf8'); // 1 | ||
vol.readFileSync('/app/src/index.js', 'utf8'): // 2 | ||
``` | ||
Export to JSON: | ||
```js | ||
vol.writeFileSync('/script.sh', '#! /bin/bash'); | ||
vol.toJSON(); // {"/script.sh": "#! /bin/bash"} | ||
``` | ||
Use it for testing: | ||
```js | ||
vol.writeFileSync('/foo', 'bar'); | ||
expect(vol.toJSON()).to.eql({"/foo": "bar"}); | ||
``` | ||
#### See also | ||
Other filesystem goodies: | ||
- [`unionfs`][unionfs] - creates a union of multiple filesystem volumes | ||
- [`linkfs`][linkfs] - redirects filesystem paths | ||
- [`fs-monkey`][fs-monkey] - monkey-patches Node's `fs` module and `require` function | ||
- [`libfs`](https://github.com/streamich/full-js/blob/master/src/lib/fs.ts) - real filesystem (that executes UNIX system calls) implemented in JavaScript | ||
Create as many filesystem volumes as you need: | ||
```js | ||
import {Volume} from 'memfs'; | ||
const vol = Volume.fromJSON({'/foo': 'bar'}); | ||
vol.readFileSync('/foo'); // bar | ||
``` | ||
Use `memfs` together with [`unionfs`][unionfs] to create one filesystem | ||
from your in-memory volumes and the real disk filesystem: | ||
```js | ||
import * as fs from 'fs'; | ||
import {ufs} from 'unionfs'; | ||
ufs | ||
.use(fs) | ||
.use(mem); | ||
// Now `unionfs` has the `fs` API but on both file systems. | ||
console.log(unionfs.readFileSync('./test.js').toString()); // console.log(123); | ||
// Replace `fs` with the union of those file systems. | ||
unionfs.replace(fs); | ||
.use(vol); | ||
// Now you can do this. | ||
console.log(fs.readFileSync('./test.js').toString()); // console.log(123); | ||
ufs.readFileSync('/foo'); // bar | ||
``` | ||
// ... and this: | ||
require('./test.js'); // 123 | ||
Use [`fs-monkey`][fs-monkey] to monkey-patch Node's `require` function: | ||
```js | ||
import {patchRequire} from 'fs-monkey'; | ||
vol.writeFileSync('/index.js', 'console.log("hi world")'); | ||
patchRequire(vol); | ||
require('/index'); // hi world | ||
``` | ||
## Dependencies | ||
This package depends on the following Node modules: `buffer`, `events`, | ||
`streams`, `path`. | ||
It also uses `process` and `setImmediate` globals, but mocks them, if not | ||
available. | ||
## Reference | ||
#### `vol` vs `fs` | ||
This package exports `vol` and `fs` objects which both can be used for | ||
filesystem operations but are slightly different. | ||
```js | ||
import {vol, fs} from 'memfs'; | ||
``` | ||
`vol` is an instance of `Volume` constructor, it is a default volume created | ||
for your convenience. `fs` in and *fs-like* object created from `vol` using | ||
`createFsFromVolume(vol)`, see reference below. | ||
#### `Volume` | ||
`Volume` is a constructor function for creating new volumes: | ||
```js | ||
import {Volume} from 'memfs'; | ||
const vol = new Volume; | ||
``` | ||
`Volume` implements all [Node's filesystem methods](https://nodejs.org/api/fs.html): | ||
```js | ||
vol.writeFileSync('/foo', 'bar'); | ||
``` | ||
But it does not hold constants or constructor functions: | ||
```js | ||
vol.F_OK; // undefined | ||
vol.ReadStream; // undefined | ||
``` | ||
A new volume can be create using the `Volume.fromJSON` convenience method: | ||
```js | ||
const vol = Volume.fromJSON({ | ||
'/app/index.js': '...', | ||
'/app/package.json': '...', | ||
}); | ||
``` | ||
It is just a shorthand for `vol.fromJSON`, see below. | ||
#### `Volume` instance `vol` | ||
###### `vol.fromJSON(json[, cwd])` | ||
Adds files from a flat `json` object to the volume `vol`. The `cwd` argument | ||
is optional and is used to compute absolute file paths, if a file path is | ||
given in a relative form. | ||
```js | ||
vol.fromJSON({ | ||
'./index.js': '...', | ||
'./package.json': '...', | ||
}, '/app'); | ||
``` | ||
###### `vol.mountSync(cwd, json)` | ||
Legacy method, which is just an alias for `vol.fromJSON`. | ||
###### `vol.toJSON([paths[, json[, isRelative]]])` | ||
Exports the whole contents of the volume recursively to a flat JSON object. | ||
`paths` is an optional argument that specifies one or more paths to be exported. | ||
If this argument is omitted, the whole volume is exported. `paths` can be | ||
an array of paths. A path can be a string, `Buffer` or an `URL` object. | ||
`json` is an optional object parameter where the list of files will be added. | ||
`isRelative` is boolean that specifies if returned paths should be relative. | ||
###### `vol.mkdirp(path, callback)` | ||
Creates a directory tree recursively. `path` is specifies a directory to | ||
create and can be a string, `Buffer`, or an `URL` object. `callback` is | ||
called on completion and may receive only one argument - an `Error` object. | ||
###### `vol.mkdirpSync(path)` | ||
A synchronous version of `vol.mkdirp`. This method throws. | ||
#### FS API Status | ||
- [x] Constants | ||
- [x] `FSWatcher` | ||
- [x] `ReadStream` | ||
- [x] `WriteStream` | ||
- [x] `Stats` | ||
- [x] `access(path[, mode], callback)` | ||
- Does not check permissions | ||
- [x] `accessSync(path[, mode])` | ||
- Does not check permissions | ||
- [x] `appendFile(file, data[, options], callback)` | ||
- [x] `appendFileSync(file, data[, options])` | ||
- [x] `chmod(path, mode, callback)` | ||
- [x] `chmodSync(path, mode)` | ||
- [x] `chown(path, uid, gid, callback)` | ||
- [x] `chownSync(path, uid, gid)` | ||
- [x] `close(fd, callback)` | ||
- [x] `closeSync(fd)` | ||
- [x] `createReadStream(path[, options])` | ||
- [x] `createWriteStream(path[, options])` | ||
- [x] `exists(path, callback)` | ||
- [x] `existsSync(path)` | ||
- [x] `fchmod(fd, mode, callback)` | ||
- [x] `fchmodSync(fd, mode)` | ||
- [x] `fchown(fd, uid, gid, callback)` | ||
- [x] `fchownSync(fd, uid, gid)` | ||
- [x] `fdatasync(fd, callback)` | ||
- [x] `fdatasyncSync(fd)` | ||
- [x] `fstat(fd, callback)` | ||
- [x] `fstatSync(fd)` | ||
- [x] `fsync(fd, callback)` | ||
- [x] `fsyncSync(fd)` | ||
- [x] `ftruncate(fd[, len], callback)` | ||
- [x] `ftruncateSync(fd[, len])` | ||
- [x] `futimes(fd, atime, mtime, callback)` | ||
- [x] `futimesSync(fd, atime, mtime)` | ||
- [x] `lchmod(path, mode, callback)` | ||
- [x] `lchmodSync(path, mode)` | ||
- [x] `lchown(path, uid, gid, callback)` | ||
- [x] `lchownSync(path, uid, gid)` | ||
- [x] `link(existingPath, newPath, callback)` | ||
- [x] `linkSync(existingPath, newPath)` | ||
- [x] `lstat(path, callback)` | ||
- [x] `lstatSync(path)` | ||
- [x] `mkdir(path[, mode], callback)` | ||
- [x] `mkdirSync(path[, mode])` | ||
- [x] `mkdtemp(prefix[, options], callback)` | ||
- [x] `mkdtempSync(prefix[, options])` | ||
- [x] `open(path, flags[, mode], callback)` | ||
- [x] `openSync(path, flags[, mode])` | ||
- [x] `read(fd, buffer, offset, length, position, callback)` | ||
- [x] `readSync(fd, buffer, offset, length, position)` | ||
- [x] `readdir(path[, options], callback)` | ||
- [x] `readdirSync(path[, options])` | ||
- [x] `readFile(path[, options], callback)` | ||
- [x] `readFileSync(path[, options])` | ||
- [x] `readlink(path[, options], callback)` | ||
- [x] `readlinkSync(path[, options])` | ||
- [x] `realpath(path[, options], callback)` | ||
- [x] `realpathSync(path[, options])` | ||
- Caching not implemented | ||
- [x] `rename(oldPath, newPath, callback)` | ||
- [x] `renameSync(oldPath, newPath)` | ||
- [x] `rmdir(path, callback)` | ||
- [x] `rmdirSync(path)` | ||
- [x] `stat(path, callback)` | ||
- [x] `statSync(path)` | ||
- [x] `symlink(target, path[, type], callback)` | ||
- [x] `symlinkSync(target, path[, type])` | ||
- [x] `truncate(path[, len], callback)` | ||
- [x] `truncateSync(path[, len])` | ||
- [x] `unlink(path, callback)` | ||
- [x] `unlinkSync(path)` | ||
- [x] `utimes(path, atime, mtime, callback)` | ||
- [x] `utimesSync(path, atime, mtime)` | ||
- [x] `watch(filename[, options][, listener])` | ||
- [x] `watchFile(filename[, options], listener)` | ||
- [x] `unwatchFile(filename[, listener])` | ||
- [x] `write(fd, buffer[, offset[, length[, position]]], callback)` | ||
- [x] `write(fd, string[, position[, encoding]], callback)` | ||
- [x] `writeFile(file, data[, options], callback)` | ||
- [x] `writeFileSync(file, data[, options])` | ||
- [x] `writeSync(fd, buffer[, offset[, length[, position]]])` | ||
- [x] `writeSync(fd, string[, position[, encoding]])` | ||
[npm-url]: https://www.npmjs.com/package/memfs | ||
[npm-img]: https://img.shields.io/npm/v/memfs.svg | ||
[memfs]: https://github.com/streamich/memfs | ||
[unionfs]: https://github.com/streamich/unionfs | ||
[linkfs]: https://github.com/streamich/linkfs | ||
[fs-monkey]: https://github.com/streamich/fs-monkey |
{ | ||
"compilerOptions": { | ||
"target": "es3", | ||
"target": "es5", | ||
"module": "commonjs", | ||
"removeComments": false | ||
} | ||
"removeComments": false, | ||
"noImplicitAny": false, | ||
"sourceMap": false | ||
}, | ||
"exclude": [ | ||
"node_modules", | ||
"lib" | ||
] | ||
} |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
290011
1
25
3923
1
286
13
1
+ Addedfast-extend@0.0.2
+ Addedfast-extend@0.0.2(transitive)
- Removedbuffer@5.0.2
- Removedpath@0.12.7
- Removedprocess@0.11.9
- Removedbase64-js@1.5.1(transitive)
- Removedbuffer@5.0.2(transitive)
- Removedieee754@1.2.1(transitive)
- Removedinherits@2.0.3(transitive)
- Removedpath@0.12.7(transitive)
- Removedprocess@0.11.9(transitive)
- Removedutil@0.10.4(transitive)