diff options
Diffstat (limited to 'lib/fs')
-rw-r--r-- | lib/fs/index.js | 148 | ||||
-rw-r--r-- | lib/fs/node.js | 72 |
2 files changed, 220 insertions, 0 deletions
diff --git a/lib/fs/index.js b/lib/fs/index.js new file mode 100644 index 0000000..1961b07 --- /dev/null +++ b/lib/fs/index.js @@ -0,0 +1,148 @@ +var Q = require('q'); +var _ = require('lodash'); +var path = require('path'); +var Buffer = require('buffer').Buffer; +var destroy = require('destroy'); + +/* +A filesystem is an interface to read/write files +GitBook can works with a virtual filesystem, for example in the browser. +*/ + +// .readdir return files/folder as a list of string, folder ending with '/' +function pathIsFolder(filename) { + return _.last(filename) == '/' || _.last(filename) == '\\'; +} + + +function FS() { + +} + +// Check if a file exists, run a Promise(true) if that's the case, Promise(false) otherwise +FS.prototype.exists = function(filename) { + // To implement for each fs +}; + +// Read a file and returns a promise with the content as a buffer +FS.prototype.read = function(filename) { + // To implement for each fs +}; + +// Write a file and returns a promise +FS.prototype.write = function(filename, buffer) { + // To implement for each fs +}; + +// List files/directories in a directory +FS.prototype.readdir = function(folder) { + // To implement for each fs +}; + + +// These methods don't require to be redefined, by default it uses .exists, .read, .write, .list +// For optmization, it can be redefined: + +// List files in a directory +FS.prototype.listFiles = function(folder) { + return this.readdir(folder) + .then(function(files) { + return _.reject(files, pathIsFolder); + }); +}; + +// List all files in the fs +FS.prototype.listAllFiles = function(folder) { + var that = this; + + return this.readdir(folder) + .then(function(files) { + return _.reduce(files, function(prev, file) { + return prev.then(function(output) { + var isDirectory = pathIsFolder(file); + + if (!isDirectory) { + output.push(file); + return output; + } else { + return that.listAllFiles(path.join(folder, file)) + .then(function(files) { + return output.concat(_.map(files, function(_file) { + return path.join(file, _file); + })); + }); + } + }); + }, Q([])); + }); +}; + +// Read a file as a string (utf-8) +FS.prototype.readAsString = function(filename) { + return this.read(filename) + .then(function(buf) { + return buf.toString('utf-8'); + }); +}; + +// Write a stream to a file and returns a promise +FS.prototype.writeStream = function(filename, stream) { + var bufs = []; + var d = Q.defer(); + + var cleanup = function() { + destroy(stream); + stream.removeAllListeners(); + }; + + stream.on('data', function(d) { + bufs.push(d); + }); + + stream.on('error', function(err) { + cleanup(); + + d.reject(err); + }); + + stream.on('end', function(){ + cleanup(); + + var buf = Buffer.concat(bufs); + d.resolve(buf); + }); + + return d.promise; +}; + +// Copy a file +FS.prototype.copy = function(from, to) { + var that = this; + + return this.read(from) + .then(function(buf) { + return that.write(to, buf); + }); +}; + +// Find a file in a folder (case incensitive) +// Return the real filename +FS.prototype.findFile = function findFile(root, filename) { + return this.listFiles(root) + .then(function(files) { + return _.find(files, function(file) { + return (file.toLowerCase() == filename.toLowerCase()); + }); + }); +}; + +// Load a JSON file +// By default, fs only supports JSON +FS.prototype.loadAsObject = function(filename) { + return this.readAsString(filename) + .then(function(str) { + return JSON.parse(str); + }); +}; + +module.exports = FS; diff --git a/lib/fs/node.js b/lib/fs/node.js new file mode 100644 index 0000000..0c470d7 --- /dev/null +++ b/lib/fs/node.js @@ -0,0 +1,72 @@ +var Q = require('q'); +var _ = require('lodash'); +var util = require('util'); +var path = require('path'); +var fs = require('fs'); + +var BaseFS = require('./'); + +function NodeFS() { + BaseFS.call(this); +} +util.inherits(NodeFS, BaseFS); + +// Check if a file exists, run a Promise(true) if that's the case, Promise(false) otherwise +NodeFS.prototype.exists = function(filename) { + var d = Q.defer(); + + fs.exists(filename, function(exists) { + d.resolve(exists); + }); + + return d.promise; +}; + +// Read a file and returns a promise with the content as a buffer +NodeFS.prototype.read = function(filename) { + return Q.nfcall(fs.readFile, filename); +}; + +// Write a file and returns a promise +NodeFS.prototype.write = function(filename, buffer) { + return Q.nfcall(fs.writeFile, filename, buffer); +}; + +// List files in a directory +NodeFS.prototype.readdir = function(folder) { + return Q.nfcall(fs.readdir, folder) + .then(function(files) { + return _.chain(files) + .map(function(file) { + if (file == '.' || file == '..') return; + + var stat = fs.statSync(path.join(folder, file)); + if (stat.isDirectory()) file = file + path.sep; + return file; + }) + .compact() + .value(); + }); +}; + +// Load a JSON/JS file +NodeFS.prototype.loadAsObject = function(filename) { + return Q() + .then(function() { + var jsFile; + + try { + jsFile = require.resolve(filename); + + // Invalidate node.js cache for livreloading + delete require.cache[jsFile]; + + return require(jsFile); + } + catch(err) { + return Q.reject(err); + } + }); +}; + +module.exports = NodeFS; |