Comparing version 0.2.0 to 0.3.0
@@ -7,3 +7,19 @@ /* | ||
var normalize = require("./normalize"); | ||
var errors = require("errno"); | ||
var stream = require("readable-stream"); | ||
var ReadableStream = stream.Readable; | ||
var WritableStream = stream.Writable; | ||
function MemoryFileSystemError(err, path) { | ||
Error.call(this) | ||
if (Error.captureStackTrace) | ||
Error.captureStackTrace(this, arguments.callee) | ||
this.code = err.code; | ||
this.errno = err.errno; | ||
this.message = err.description; | ||
this.path = path; | ||
} | ||
MemoryFileSystemError.prototype = new Error(); | ||
function MemoryFileSystem(data) { | ||
@@ -28,3 +44,5 @@ this.data = data || {}; | ||
if(!nix) { | ||
if(!/^[A-Za-z]:/.test(path)) throw new Error("Invalid path '" + path + "'"); | ||
if(!/^[A-Za-z]:/.test(path)) { | ||
throw new MemoryFileSystemError(errors.code.EINVAL, path); | ||
} | ||
path = path.replace(/[\\\/]+/g, "\\"); // multi slashs | ||
@@ -44,3 +62,3 @@ path = path.split(/[\\\/]/); | ||
MemoryFileSystem.prototype.statSync = function(_path) { | ||
MemoryFileSystem.prototype.meta = function(_path) { | ||
var path = pathToArray(_path); | ||
@@ -50,6 +68,15 @@ var current = this.data; | ||
if(!isDir(current[path[i]])) | ||
throw new Error("Path doesn't exist '" + _path + "'"); | ||
return null; | ||
current = current[path[i]]; | ||
} | ||
if(_path === "/" || isDir(current[path[i]])) { | ||
return current[path[i]]; | ||
} | ||
MemoryFileSystem.prototype.existsSync = function(_path) { | ||
return !!this.meta(_path); | ||
} | ||
MemoryFileSystem.prototype.statSync = function(_path) { | ||
var current = this.meta(_path); | ||
if(_path === "/" || isDir(current)) { | ||
return { | ||
@@ -64,3 +91,3 @@ isFile: falseFn, | ||
}; | ||
} else if(isFile(current[path[i]])) { | ||
} else if(isFile(current)) { | ||
return { | ||
@@ -75,4 +102,5 @@ isFile: trueFn, | ||
}; | ||
} else | ||
throw new Error("Path doesn't exist '" + _path + "'"); | ||
} else { | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
} | ||
}; | ||
@@ -85,3 +113,3 @@ | ||
if(!isDir(current[path[i]])) | ||
throw new Error("Path doesn't exist '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
current = current[path[i]]; | ||
@@ -91,5 +119,5 @@ } | ||
if(isDir(current[path[i]])) | ||
throw new Error("Cannot readFile on directory '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.EISDIR, _path); | ||
else | ||
throw new Error("Path doesn't exist '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
} | ||
@@ -106,3 +134,3 @@ current = current[path[i]]; | ||
if(!isDir(current[path[i]])) | ||
throw new Error("Path doesn't exist '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
current = current[path[i]]; | ||
@@ -112,5 +140,5 @@ } | ||
if(isFile(current[path[i]])) | ||
throw new Error("Cannot readdir on file '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.ENOTDIR, _path); | ||
else | ||
throw new Error("Path doesn't exist '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
} | ||
@@ -126,3 +154,3 @@ return Object.keys(current[path[i]]).filter(Boolean); | ||
if(isFile(current[path[i]])) | ||
throw new Error("Path is a file '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.ENOTDIR, _path); | ||
else if(!isDir(current[path[i]])) | ||
@@ -141,9 +169,9 @@ current[path[i]] = {"":true}; | ||
if(!isDir(current[path[i]])) | ||
throw new Error("Path doesn't exist '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
current = current[path[i]]; | ||
} | ||
if(isDir(current[path[i]])) | ||
throw new new Error("Directory already exist '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.EEXIST, _path); | ||
else if(isFile(current[path[i]])) | ||
throw new Error("Cannot mkdir on file '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.ENOTDIR, _path); | ||
current[path[i]] = {"":true}; | ||
@@ -155,11 +183,13 @@ return; | ||
var path = pathToArray(_path); | ||
if(path.length === 0) throw new Error("Path cannot be removed '" + _path + "'"); | ||
if(path.length === 0) { | ||
throw new MemoryFileSystemError(errors.code.EPERM, _path); | ||
} | ||
var current = this.data; | ||
for(var i = 0; i < path.length - 1; i++) { | ||
if(!isDir(current[path[i]])) | ||
throw new Error("Path doesn't exist '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
current = current[path[i]]; | ||
} | ||
if(!testFn(current[path[i]])) | ||
throw new Error("'" + name + "' doesn't exist '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
delete current[path[i]]; | ||
@@ -178,3 +208,3 @@ return; | ||
MemoryFileSystem.prototype.readlinkSync = function(_path) { | ||
throw new Error("Path is not a link '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.ENOSYS, _path); | ||
}; | ||
@@ -185,11 +215,13 @@ | ||
var path = pathToArray(_path); | ||
if(path.length === 0) throw new Error("Path is not a file '" + _path + "'"); | ||
if(path.length === 0) { | ||
throw new MemoryFileSystemError(errors.code.EISDIR, _path); | ||
} | ||
var current = this.data; | ||
for(var i = 0; i < path.length - 1; i++) { | ||
if(!isDir(current[path[i]])) | ||
throw new Error("Path doesn't exist '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
current = current[path[i]]; | ||
} | ||
if(isDir(current[path[i]])) | ||
throw new Error("Cannot writeFile on directory '" + _path + "'"); | ||
throw new MemoryFileSystemError(errors.code.EISDIR, _path); | ||
current[path[i]] = encoding || typeof content === "string" ? new Buffer(content, encoding) : content; | ||
@@ -203,2 +235,56 @@ return; | ||
// stream functions | ||
MemoryFileSystem.prototype.createReadStream = function(path, options) { | ||
var stream = new ReadableStream(); | ||
var done = false; | ||
var data; | ||
try { | ||
data = this.readFileSync(path); | ||
} catch (e) { | ||
stream._read = function() { | ||
if (done) { | ||
return; | ||
} | ||
done = true; | ||
this.emit('error', e); | ||
this.push(null); | ||
}; | ||
return stream; | ||
} | ||
options = options || { }; | ||
options.start = options.start || 0; | ||
options.end = options.end || data.length; | ||
stream._read = function() { | ||
if (done) { | ||
return; | ||
} | ||
done = true; | ||
this.push(data.slice(options.start, options.end)); | ||
this.push(null); | ||
}; | ||
return stream; | ||
}; | ||
MemoryFileSystem.prototype.createWriteStream = function(path, options) { | ||
var stream = new WritableStream(), self = this; | ||
try { | ||
// Zero the file and make sure it is writable | ||
this.writeFileSync(path, new Buffer(0)); | ||
} catch(e) { | ||
// This or setImmediate? | ||
stream.once('prefinish', function() { | ||
stream.emit('error', e); | ||
}); | ||
return stream; | ||
} | ||
var bl = [ ], len = 0; | ||
stream._write = function(chunk, encoding, callback) { | ||
bl.push(chunk); | ||
len += chunk.length; | ||
self.writeFile(path, Buffer.concat(bl, len), callback); | ||
} | ||
return stream; | ||
}; | ||
// async functions | ||
@@ -217,2 +303,6 @@ | ||
MemoryFileSystem.prototype.exists = function(path, callback) { | ||
return callback(this.existsSync(path)); | ||
} | ||
MemoryFileSystem.prototype.readFile = function(path, optArg, callback) { | ||
@@ -219,0 +309,0 @@ if(!callback) { |
{ | ||
"name": "memory-fs", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "A simple in-memory filesystem. Holds data in a javascript object.", | ||
@@ -10,4 +10,5 @@ "main": "lib/MemoryFileSystem.js", | ||
"scripts": { | ||
"test": "mocha -R spec", | ||
"cover": "istanbul cover node_modules/mocha/bin/_mocha -- -R spec" | ||
"test": "mocha", | ||
"cover": "istanbul cover node_modules/mocha/bin/_mocha", | ||
"travis": "npm run cover -- --report lcovonly" | ||
}, | ||
@@ -29,6 +30,13 @@ "repository": { | ||
"devDependencies": { | ||
"bl": "^1.0.0", | ||
"codecov.io": "^0.1.4", | ||
"coveralls": "^2.11.2", | ||
"istanbul": "^0.2.13", | ||
"mocha": "^1.20.1", | ||
"should": "^4.0.4" | ||
}, | ||
"dependencies": { | ||
"errno": "^0.1.3", | ||
"readable-stream": "^2.0.1" | ||
} | ||
} |
@@ -0,1 +1,2 @@ | ||
var bl = require("bl"); | ||
var should = require("should"); | ||
@@ -31,2 +32,3 @@ var MemoryFileSystem = require("../lib/MemoryFileSystem"); | ||
fs.rmdirSync("/test"); | ||
fs.existsSync("/test").should.be.eql(false); | ||
(function() { | ||
@@ -37,2 +39,3 @@ fs.readdirSync("/test"); | ||
fs.mkdirpSync("/a/depth/sub/dir"); | ||
fs.existsSync("/a/depth/sub").should.be.eql(true); | ||
var stat = fs.statSync("/a/depth/sub"); | ||
@@ -55,2 +58,3 @@ stat.isFile().should.be.eql(false); | ||
fs.rmdirSync("C:\\test"); | ||
fs.existsSync("C:\\test").should.be.eql(false); | ||
(function() { | ||
@@ -61,2 +65,3 @@ fs.readdirSync("C:\\test"); | ||
fs.mkdirpSync("D:\\a\\depth\\sub\\dir"); | ||
fs.existsSync("D:\\a\\depth\\sub").should.be.eql(true); | ||
var stat = fs.statSync("D:\\a\\depth\\sub"); | ||
@@ -213,3 +218,6 @@ stat.isFile().should.be.eql(false); | ||
content.should.be.eql(new Buffer("World")); | ||
done(); | ||
fs.exists("/test/dir/b", function(exists) { | ||
exists.should.be.eql(true); | ||
done(); | ||
}); | ||
}); | ||
@@ -232,2 +240,74 @@ }); | ||
}); | ||
describe("streams", function() { | ||
describe("writable streams", function() { | ||
it("should write files", function() { | ||
var fs = new MemoryFileSystem(); | ||
fs.createWriteStream("/file").end("Hello"); | ||
fs.readFileSync("/file", "utf8").should.be.eql("Hello"); | ||
}); | ||
it("should zero files", function() { | ||
var fs = new MemoryFileSystem(); | ||
fs.createWriteStream("/file").end(); | ||
fs.readFileSync("/file", "utf8").should.be.eql(""); | ||
}); | ||
it("should accept pipes", function(done) { | ||
// TODO: Any way to avoid the asyncness of this? | ||
var fs = new MemoryFileSystem(); | ||
bl(new Buffer("Hello")) | ||
.pipe(fs.createWriteStream("/file")) | ||
.once('finish', function() { | ||
fs.readFileSync("/file", "utf8").should.be.eql("Hello"); | ||
done(); | ||
}); | ||
}); | ||
it("should propagate errors", function(done) { | ||
var fs = new MemoryFileSystem(); | ||
var stream = fs.createWriteStream("file"); | ||
var err = false; | ||
stream.once('error', function() { | ||
err = true; | ||
}).once('finish', function() { | ||
err.should.eql(true); | ||
done(); | ||
}); | ||
stream.end(); | ||
}); | ||
}); | ||
describe("readable streams", function() { | ||
it("should read files", function(done) { | ||
var fs = new MemoryFileSystem(); | ||
fs.writeFileSync("/file", "Hello"); | ||
fs.createReadStream("/file").pipe(bl(function(err, data) { | ||
data.toString('utf8').should.be.eql("Hello"); | ||
done(); | ||
})); | ||
}); | ||
it("should respect start/end", function(done) { | ||
var fs = new MemoryFileSystem(); | ||
fs.writeFileSync("/file", "Hello"); | ||
fs.createReadStream("/file", { | ||
start: 1, | ||
end: 3 | ||
}).pipe(bl(function(err, data) { | ||
data.toString('utf8').should.be.eql("el"); | ||
done(); | ||
})); | ||
}); | ||
it("should propagate errors", function(done) { | ||
var fs = new MemoryFileSystem(); | ||
var stream = fs.createReadStream("file"); | ||
var err = false; | ||
// Why does this dummy event need to be here? It looks like it | ||
// either has to be this or data before the stream will actually | ||
// do anything. | ||
stream.on('readable', function() { }).on('error', function() { | ||
err = true; | ||
}).on('end', function() { | ||
err.should.eql(true); | ||
done(); | ||
}); | ||
stream.read(0); | ||
}); | ||
}); | ||
}); | ||
describe("normalize", function() { | ||
@@ -368,2 +448,2 @@ it("should normalize paths", function() { | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
29900
767
2
6
+ Addederrno@^0.1.3
+ Addedreadable-stream@^2.0.1
+ Addedcore-util-is@1.0.3(transitive)
+ Addederrno@0.1.8(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedisarray@1.0.0(transitive)
+ Addedprocess-nextick-args@2.0.1(transitive)
+ Addedprr@1.0.1(transitive)
+ Addedreadable-stream@2.3.8(transitive)
+ Addedsafe-buffer@5.1.2(transitive)
+ Addedstring_decoder@1.1.1(transitive)
+ Addedutil-deprecate@1.0.2(transitive)