Comparing version
@@ -1,6 +0,8 @@ | ||
var normalize = require("./normalize"); | ||
"use strict"; | ||
var absoluteWinRegExp = /^[A-Z]:([\\\/]|$)/i; | ||
var absoluteNixRegExp = /^\//i; | ||
const normalize = require("./normalize"); | ||
const absoluteWinRegExp = /^[A-Z]:([\\\/]|$)/i; | ||
const absoluteNixRegExp = /^\//i; | ||
module.exports = function join(path, request) { | ||
@@ -7,0 +9,0 @@ if(!request) return normalize(path); |
@@ -6,25 +6,13 @@ /* | ||
var normalize = require("./normalize"); | ||
var errors = require("errno"); | ||
var stream = require("readable-stream"); | ||
"use strict"; | ||
var ReadableStream = stream.Readable; | ||
var WritableStream = stream.Writable; | ||
const normalize = require("./normalize"); | ||
const join = require("./join"); | ||
const MemoryFileSystemError = require("./MemoryFileSystemError"); | ||
const errors = require("errno"); | ||
const stream = require("readable-stream"); | ||
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(); | ||
const ReadableStream = stream.Readable; | ||
const WritableStream = stream.Writable; | ||
function MemoryFileSystem(data) { | ||
this.data = data || {}; | ||
} | ||
module.exports = MemoryFileSystem; | ||
function isDir(item) { | ||
@@ -42,3 +30,3 @@ if(typeof item !== "object") return false; | ||
path = normalize(path); | ||
var nix = /^\//.test(path); | ||
const nix = /^\//.test(path); | ||
if(!nix) { | ||
@@ -62,171 +50,196 @@ if(!/^[A-Za-z]:/.test(path)) { | ||
MemoryFileSystem.prototype.meta = function(_path) { | ||
var path = pathToArray(_path); | ||
var current = this.data; | ||
for(var i = 0; i < path.length - 1; i++) { | ||
if(!isDir(current[path[i]])) | ||
return; | ||
current = current[path[i]]; | ||
class MemoryFileSystem { | ||
constructor(data) { | ||
this.data = data || {}; | ||
this.join = join; | ||
this.pathToArray = pathToArray; | ||
this.normalize = normalize; | ||
} | ||
return current[path[i]]; | ||
} | ||
MemoryFileSystem.prototype.existsSync = function(_path) { | ||
return !!this.meta(_path); | ||
} | ||
meta(_path) { | ||
const path = pathToArray(_path); | ||
let current = this.data; | ||
let i = 0; | ||
for(; i < path.length - 1; i++) { | ||
if(!isDir(current[path[i]])) | ||
return; | ||
current = current[path[i]]; | ||
} | ||
return current[path[i]]; | ||
} | ||
MemoryFileSystem.prototype.statSync = function(_path) { | ||
var current = this.meta(_path); | ||
if(_path === "/" || isDir(current)) { | ||
return { | ||
isFile: falseFn, | ||
isDirectory: trueFn, | ||
isBlockDevice: falseFn, | ||
isCharacterDevice: falseFn, | ||
isSymbolicLink: falseFn, | ||
isFIFO: falseFn, | ||
isSocket: falseFn | ||
}; | ||
} else if(isFile(current)) { | ||
return { | ||
isFile: trueFn, | ||
isDirectory: falseFn, | ||
isBlockDevice: falseFn, | ||
isCharacterDevice: falseFn, | ||
isSymbolicLink: falseFn, | ||
isFIFO: falseFn, | ||
isSocket: falseFn | ||
}; | ||
} else { | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
existsSync(_path) { | ||
return !!this.meta(_path); | ||
} | ||
}; | ||
MemoryFileSystem.prototype.readFileSync = function(_path, encoding) { | ||
var path = pathToArray(_path); | ||
var current = this.data; | ||
for(var i = 0; i < path.length - 1; i++) { | ||
if(!isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
current = current[path[i]]; | ||
statSync(_path) { | ||
let current = this.meta(_path); | ||
if(_path === "/" || isDir(current)) { | ||
return { | ||
isFile: falseFn, | ||
isDirectory: trueFn, | ||
isBlockDevice: falseFn, | ||
isCharacterDevice: falseFn, | ||
isSymbolicLink: falseFn, | ||
isFIFO: falseFn, | ||
isSocket: falseFn | ||
}; | ||
} else if(isFile(current)) { | ||
return { | ||
isFile: trueFn, | ||
isDirectory: falseFn, | ||
isBlockDevice: falseFn, | ||
isCharacterDevice: falseFn, | ||
isSymbolicLink: falseFn, | ||
isFIFO: falseFn, | ||
isSocket: falseFn | ||
}; | ||
} else { | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path, "stat"); | ||
} | ||
} | ||
if(!isFile(current[path[i]])) { | ||
if(isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.EISDIR, _path); | ||
else | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
} | ||
current = current[path[i]]; | ||
return encoding ? current.toString(encoding) : current; | ||
}; | ||
MemoryFileSystem.prototype.readdirSync = function(_path) { | ||
if(_path === "/") return Object.keys(this.data).filter(Boolean); | ||
var path = pathToArray(_path); | ||
var current = this.data; | ||
for(var i = 0; i < path.length - 1; i++) { | ||
if(!isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
readFileSync(_path, optionsOrEncoding) { | ||
const path = pathToArray(_path); | ||
let current = this.data; | ||
let i = 0 | ||
for(; i < path.length - 1; i++) { | ||
if(!isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path, "readFile"); | ||
current = current[path[i]]; | ||
} | ||
if(!isFile(current[path[i]])) { | ||
if(isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.EISDIR, _path, "readFile"); | ||
else | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path, "readFile"); | ||
} | ||
current = current[path[i]]; | ||
const encoding = typeof optionsOrEncoding === "object" ? optionsOrEncoding.encoding : optionsOrEncoding; | ||
return encoding ? current.toString(encoding) : current; | ||
} | ||
if(!isDir(current[path[i]])) { | ||
if(isFile(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOTDIR, _path); | ||
else | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
readdirSync(_path) { | ||
if(_path === "/") return Object.keys(this.data).filter(Boolean); | ||
const path = pathToArray(_path); | ||
let current = this.data; | ||
let i = 0; | ||
for(; i < path.length - 1; i++) { | ||
if(!isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path, "readdir"); | ||
current = current[path[i]]; | ||
} | ||
if(!isDir(current[path[i]])) { | ||
if(isFile(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOTDIR, _path, "readdir"); | ||
else | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path, "readdir"); | ||
} | ||
return Object.keys(current[path[i]]).filter(Boolean); | ||
} | ||
return Object.keys(current[path[i]]).filter(Boolean); | ||
}; | ||
MemoryFileSystem.prototype.mkdirpSync = function(_path) { | ||
var path = pathToArray(_path); | ||
if(path.length === 0) return; | ||
var current = this.data; | ||
for(var i = 0; i < path.length; i++) { | ||
if(isFile(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOTDIR, _path); | ||
else if(!isDir(current[path[i]])) | ||
current[path[i]] = {"":true}; | ||
current = current[path[i]]; | ||
mkdirpSync(_path) { | ||
const path = pathToArray(_path); | ||
if(path.length === 0) return; | ||
let current = this.data; | ||
for(let i = 0; i < path.length; i++) { | ||
if(isFile(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOTDIR, _path, "mkdirp"); | ||
else if(!isDir(current[path[i]])) | ||
current[path[i]] = {"":true}; | ||
current = current[path[i]]; | ||
} | ||
return; | ||
} | ||
return; | ||
}; | ||
MemoryFileSystem.prototype.mkdirSync = function(_path) { | ||
var path = pathToArray(_path); | ||
if(path.length === 0) return; | ||
var current = this.data; | ||
for(var i = 0; i < path.length - 1; i++) { | ||
if(!isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
current = current[path[i]]; | ||
mkdirSync(_path) { | ||
const path = pathToArray(_path); | ||
if(path.length === 0) return; | ||
let current = this.data; | ||
let i = 0; | ||
for(; i < path.length - 1; i++) { | ||
if(!isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path, "mkdir"); | ||
current = current[path[i]]; | ||
} | ||
if(isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.EEXIST, _path, "mkdir"); | ||
else if(isFile(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOTDIR, _path, "mkdir"); | ||
current[path[i]] = {"":true}; | ||
return; | ||
} | ||
if(isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.EEXIST, _path); | ||
else if(isFile(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOTDIR, _path); | ||
current[path[i]] = {"":true}; | ||
return; | ||
}; | ||
MemoryFileSystem.prototype._remove = function(_path, name, testFn) { | ||
var path = pathToArray(_path); | ||
if(path.length === 0) { | ||
throw new MemoryFileSystemError(errors.code.EPERM, _path); | ||
_remove(_path, name, testFn) { | ||
const path = pathToArray(_path); | ||
const operation = name === "File" ? "unlink" : "rmdir"; | ||
if(path.length === 0) { | ||
throw new MemoryFileSystemError(errors.code.EPERM, _path, operation); | ||
} | ||
let current = this.data; | ||
let i = 0; | ||
for(; i < path.length - 1; i++) { | ||
if(!isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path, operation); | ||
current = current[path[i]]; | ||
} | ||
if(!testFn(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path, operation); | ||
delete current[path[i]]; | ||
return; | ||
} | ||
var current = this.data; | ||
for(var i = 0; i < path.length - 1; i++) { | ||
if(!isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
current = current[path[i]]; | ||
rmdirSync(_path) { | ||
return this._remove(_path, "Directory", isDir); | ||
} | ||
if(!testFn(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
delete current[path[i]]; | ||
return; | ||
}; | ||
MemoryFileSystem.prototype.rmdirSync = function(_path) { | ||
return this._remove(_path, "Directory", isDir); | ||
}; | ||
unlinkSync(_path) { | ||
return this._remove(_path, "File", isFile); | ||
} | ||
MemoryFileSystem.prototype.unlinkSync = function(_path) { | ||
return this._remove(_path, "File", isFile); | ||
}; | ||
readlinkSync(_path) { | ||
throw new MemoryFileSystemError(errors.code.ENOSYS, _path, "readlink"); | ||
} | ||
MemoryFileSystem.prototype.readlinkSync = function(_path) { | ||
throw new MemoryFileSystemError(errors.code.ENOSYS, _path); | ||
}; | ||
MemoryFileSystem.prototype.writeFileSync = function(_path, content, encoding) { | ||
if(!content && !encoding) throw new Error("No content"); | ||
var path = pathToArray(_path); | ||
if(path.length === 0) { | ||
throw new MemoryFileSystemError(errors.code.EISDIR, _path); | ||
writeFileSync(_path, content, optionsOrEncoding) { | ||
if(!content && !optionsOrEncoding) throw new Error("No content"); | ||
const path = pathToArray(_path); | ||
if(path.length === 0) { | ||
throw new MemoryFileSystemError(errors.code.EISDIR, _path, "writeFile"); | ||
} | ||
let current = this.data; | ||
let i = 0 | ||
for(; i < path.length - 1; i++) { | ||
if(!isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path, "writeFile"); | ||
current = current[path[i]]; | ||
} | ||
if(isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.EISDIR, _path, "writeFile"); | ||
const encoding = typeof optionsOrEncoding === "object" ? optionsOrEncoding.encoding : optionsOrEncoding; | ||
current[path[i]] = optionsOrEncoding || typeof content === "string" ? new Buffer(content, encoding) : content; | ||
return; | ||
} | ||
var current = this.data; | ||
for(var i = 0; i < path.length - 1; i++) { | ||
if(!isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.ENOENT, _path); | ||
current = current[path[i]]; | ||
} | ||
if(isDir(current[path[i]])) | ||
throw new MemoryFileSystemError(errors.code.EISDIR, _path); | ||
current[path[i]] = encoding || typeof content === "string" ? new Buffer(content, encoding) : content; | ||
return; | ||
}; | ||
MemoryFileSystem.prototype.join = require("./join"); | ||
MemoryFileSystem.prototype.pathToArray = pathToArray; | ||
MemoryFileSystem.prototype.normalize = normalize; | ||
// 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 methods | ||
createReadStream(path, options) { | ||
let stream = new ReadableStream(); | ||
let done = false; | ||
let 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() { | ||
@@ -237,3 +250,3 @@ if (done) { | ||
done = true; | ||
this.emit('error', e); | ||
this.push(data.slice(options.start, options.end)); | ||
this.push(null); | ||
@@ -243,37 +256,43 @@ }; | ||
} | ||
options = options || { }; | ||
options.start = options.start || 0; | ||
options.end = options.end || data.length; | ||
stream._read = function() { | ||
if (done) { | ||
return; | ||
createWriteStream(path) { | ||
let stream = new WritableStream(); | ||
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; | ||
} | ||
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); | ||
}); | ||
let bl = [ ], len = 0; | ||
stream._write = (chunk, encoding, callback) => { | ||
bl.push(chunk); | ||
len += chunk.length; | ||
this.writeFile(path, Buffer.concat(bl, len), callback); | ||
} | ||
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); | ||
// async functions | ||
exists(path, callback) { | ||
return callback(this.existsSync(path)); | ||
} | ||
return stream; | ||
}; | ||
writeFile(path, content, encoding, callback) { | ||
if(!callback) { | ||
callback = encoding; | ||
encoding = undefined; | ||
} | ||
try { | ||
this.writeFileSync(path, content, encoding); | ||
} catch(e) { | ||
return callback(e); | ||
} | ||
return callback(); | ||
} | ||
} | ||
// async functions | ||
@@ -283,4 +302,5 @@ | ||
MemoryFileSystem.prototype[fn] = function(path, callback) { | ||
let result; | ||
try { | ||
var result = this[fn + "Sync"](path); | ||
result = this[fn + "Sync"](path); | ||
} catch(e) { | ||
@@ -305,4 +325,5 @@ setImmediate(function() { | ||
} | ||
let result; | ||
try { | ||
var result = this[fn + "Sync"](path, optArg); | ||
result = this[fn + "Sync"](path, optArg); | ||
} catch(e) { | ||
@@ -321,17 +342,2 @@ setImmediate(function() { | ||
MemoryFileSystem.prototype.exists = function(path, callback) { | ||
return callback(this.existsSync(path)); | ||
} | ||
MemoryFileSystem.prototype.writeFile = function (path, content, encoding, callback) { | ||
if(!callback) { | ||
callback = encoding; | ||
encoding = undefined; | ||
} | ||
try { | ||
this.writeFileSync(path, content, encoding); | ||
} catch(e) { | ||
return callback(e); | ||
} | ||
return callback(); | ||
}; | ||
module.exports = MemoryFileSystem; |
@@ -0,1 +1,4 @@ | ||
"use strict"; | ||
// eslint-disable-next-line complexity | ||
module.exports = function normalize(path) { | ||
@@ -7,3 +10,3 @@ var parts = path.split(/(\\+|\/+)/); | ||
var absolutePathStart = 0; | ||
for(var i = 0, sep = false; i < parts.length; i++, sep = !sep) { | ||
for(var i = 0, sep = false; i < parts.length; i += 1, sep = !sep) { | ||
var part = parts[i]; | ||
@@ -14,3 +17,8 @@ if(i === 0 && /^([A-Z]:)?$/i.test(part)) { | ||
} else if(sep) { | ||
result.push(part[0]); | ||
// UNC paths on Windows begin with a double backslash. | ||
if (i === 1 && parts[0].length === 0 && part === "\\\\") { | ||
result.push(part); | ||
} else { | ||
result.push(part[0]); | ||
} | ||
} else if(part === "..") { | ||
@@ -30,5 +38,10 @@ switch(result.length) { | ||
// i. e. "C:\..\a\b\c" => "C:\a\b\c" | ||
i++; | ||
sep = !sep; | ||
result.length = absolutePathStart; | ||
if (result[0] !== ".") { | ||
i += 1; | ||
sep = !sep; | ||
result.length = absolutePathStart; | ||
} else { | ||
result.length = 0; | ||
result.push(part); | ||
} | ||
break; | ||
@@ -43,3 +56,3 @@ case 4: | ||
} else { | ||
i++; | ||
i += 1; | ||
sep = !sep; | ||
@@ -68,5 +81,5 @@ result.length = 2; | ||
if(absolutePathStart === 0) { | ||
result.length--; | ||
result.length -= 1; | ||
} else { | ||
i++; | ||
i += 1; | ||
sep = !sep; | ||
@@ -81,3 +94,3 @@ } | ||
// i. e. "/a/./b/c" => "/a/b/c" | ||
result.length--; | ||
result.length -= 1; | ||
break; | ||
@@ -89,5 +102,5 @@ } | ||
} | ||
if(result.length === 1 && /^[A-Za-z]:$/.test(result)) | ||
if(result.length === 1 && /^[A-Za-z]:$/.test(result[0])) | ||
return result[0] + "\\"; | ||
return result.join(""); | ||
}; |
{ | ||
"name": "memory-fs", | ||
"version": "0.4.1", | ||
"version": "0.5.0", | ||
"description": "A simple in-memory filesystem. Holds data in a javascript object.", | ||
@@ -14,5 +14,9 @@ "main": "lib/MemoryFileSystem.js", | ||
"test": "mocha", | ||
"lint": "eslint lib/*", | ||
"cover": "istanbul cover node_modules/mocha/bin/_mocha", | ||
"travis": "npm run cover -- --report lcovonly" | ||
"travis": "npm run cover -- --report lcovonly && npm run lint" | ||
}, | ||
"engines": { | ||
"node": ">=4.3.0 <5.0.0 || >=5.10" | ||
}, | ||
"repository": { | ||
@@ -36,4 +40,5 @@ "type": "git", | ||
"coveralls": "^2.11.2", | ||
"istanbul": "^0.2.13", | ||
"mocha": "^1.20.1", | ||
"eslint": "^4.0.0", | ||
"istanbul": "0.4.5", | ||
"mocha": "3.2.0", | ||
"should": "^4.0.4" | ||
@@ -40,0 +45,0 @@ }, |
@@ -0,0 +0,0 @@ # memory-fs |
15236
13.5%7
40%441
11.36%7
16.67%