diff options
Diffstat (limited to 'lib/fs')
-rw-r--r-- | lib/fs/__tests__/mock.js | 83 | ||||
-rw-r--r-- | lib/fs/index.js | 106 | ||||
-rw-r--r-- | lib/fs/mock.js | 95 | ||||
-rw-r--r-- | lib/fs/node.js | 68 |
4 files changed, 199 insertions, 153 deletions
diff --git a/lib/fs/__tests__/mock.js b/lib/fs/__tests__/mock.js new file mode 100644 index 0000000..7842011 --- /dev/null +++ b/lib/fs/__tests__/mock.js @@ -0,0 +1,83 @@ +jest.autoMockOff(); + +describe('MockFS', function() { + var createMockFS = require('../mock'); + var fs = createMockFS({ + 'README.md': 'Hello World', + 'SUMMARY.md': '# Summary', + 'folder': { + 'test.md': 'Cool', + 'folder2': { + 'hello.md': 'Hello', + 'world.md': 'World' + } + } + }); + + describe('exists', function() { + pit('must return true for a file', function() { + return fs.exists('README.md') + .then(function(result) { + expect(result).toBeTruthy(); + }); + }); + + pit('must return false for a non existing file', function() { + return fs.exists('README_NOTEXISTS.md') + .then(function(result) { + expect(result).toBeFalsy(); + }); + }); + + pit('must return true for a directory', function() { + return fs.exists('folder') + .then(function(result) { + expect(result).toBeTruthy(); + }); + }); + + pit('must return true for a deep file', function() { + return fs.exists('folder/test.md') + .then(function(result) { + expect(result).toBeTruthy(); + }); + }); + + pit('must return true for a deep file (2)', function() { + return fs.exists('folder/folder2/hello.md') + .then(function(result) { + expect(result).toBeTruthy(); + }); + }); + }); + + describe('readAsString', function() { + pit('must return content for a file', function() { + return fs.readAsString('README.md') + .then(function(result) { + expect(result).toBe('Hello World'); + }); + }); + + pit('must return content for a deep file', function() { + return fs.readAsString('folder/test.md') + .then(function(result) { + expect(result).toBe('Cool'); + }); + }); + }); + + describe('readDir', function() { + pit('must return content for a directory', function() { + return fs.readDir('./') + .then(function(files) { + expect(files.size).toBe(3); + expect(files.includes('README.md')).toBeTruthy(); + expect(files.includes('SUMMARY.md')).toBeTruthy(); + expect(files.includes('folder/')).toBeTruthy(); + }); + }); + }); +}); + + diff --git a/lib/fs/index.js b/lib/fs/index.js deleted file mode 100644 index 8a3ca1e..0000000 --- a/lib/fs/index.js +++ /dev/null @@ -1,106 +0,0 @@ -var _ = require('lodash'); -var path = require('path'); - -var Promise = require('../utils/promise'); - -/* -A filesystem is an interface to read 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 -}; - -// Read stat infos about a file -FS.prototype.stat = function(filename) { - // 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); - })); - }); - } - }); - }, Promise([])); - }); -}; - -// 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'); - }); -}; - -// 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/mock.js b/lib/fs/mock.js new file mode 100644 index 0000000..2149e1d --- /dev/null +++ b/lib/fs/mock.js @@ -0,0 +1,95 @@ +var path = require('path'); +var is = require('is'); +var Buffer = require('buffer').Buffer; +var Immutable = require('immutable'); + +var FS = require('../models/fs'); +var error = require('../utils/error'); + +/** + Create a fake filesystem for unit testing GitBook. + + @param {Map<String:String|Map>} +*/ +function createMockFS(files) { + files = Immutable.fromJS(files); + var mtime = new Date(); + + function getFile(filePath) { + var parts = path.normalize(filePath).split('/'); + return parts.reduce(function(list, part, i) { + if (!list) return null; + + var file; + + if (!part || part === '.') file = list; + else file = list.get(part); + + if (!file) return null; + + if (is.string(file)) { + if (i === (parts.length - 1)) return file; + else return null; + } + + return file; + }, files); + } + + function fsExists(filePath) { + return Boolean(getFile(filePath) !== null); + } + + function fsReadFile(filePath) { + var file = getFile(filePath); + if (!is.string(file)) { + throw error.FileNotFoundError({ + filename: filePath + }); + } + + return new Buffer(file, 'utf8'); + } + + function fsStatFile(filePath) { + var file = getFile(filePath); + if (!file) { + throw error.FileNotFoundError({ + filename: filePath + }); + } + + return { + mtime: mtime + }; + } + + function fsReadDir(filePath) { + var dir = getFile(filePath); + if (!dir || is.string(dir)) { + throw error.FileNotFoundError({ + filename: filePath + }); + } + + return dir + .map(function(content, name) { + if (!is.string(content)) { + name = name + '/'; + } + + return name; + }) + .valueSeq(); + } + + return FS.create({ + root: '', + fsExists: fsExists, + fsReadFile: fsReadFile, + fsStatFile: fsStatFile, + fsReadDir: fsReadDir + }); +} + +module.exports = createMockFS; diff --git a/lib/fs/node.js b/lib/fs/node.js index fc2517e..e05cb65 100644 --- a/lib/fs/node.js +++ b/lib/fs/node.js @@ -1,36 +1,15 @@ -var _ = require('lodash'); -var util = require('util'); var path = require('path'); +var Immutable = require('immutable'); var fs = require('../utils/fs'); -var Promise = require('../utils/promise'); -var BaseFS = require('./'); +var FS = require('../models/fs'); -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) { - return fs.exists(filename); -}; - -// Read a file and returns a promise with the content as a buffer -NodeFS.prototype.read = function(filename) { - return fs.readFile(filename); -}; - -// Read stat infos about a file -NodeFS.prototype.stat = function(filename) { - return fs.stat(filename); -}; - -// List files in a directory -NodeFS.prototype.readdir = function(folder) { +function fsReadDir(folder) { return fs.readdir(folder) .then(function(files) { - return _.chain(files) + files = Immutable.List(files); + + return files .map(function(file) { if (file == '.' || file == '..') return; @@ -38,29 +17,24 @@ NodeFS.prototype.readdir = function(folder) { if (stat.isDirectory()) file = file + path.sep; return file; }) - .compact() - .value(); + .filter(function(file) { + return Boolean(file); + }); }); -}; - -// Load a JSON/JS file -NodeFS.prototype.loadAsObject = function(filename) { - return Promise() - .then(function() { - var jsFile; +} - try { - jsFile = require.resolve(filename); +function fsLoadObject(filename) { + return require(filename); +} - // Invalidate node.js cache for livreloading - delete require.cache[jsFile]; +module.exports = function createNodeFS(root) { + return FS.create({ + root: root, - return require(jsFile); - } - catch(err) { - return Promise.reject(err); - } + fsExists: fs.exists, + fsReadFile: fs.readFile, + fsStatFile: fs.stat, + fsReadDir: fsReadDir, + fsLoadObject: fsLoadObject }); }; - -module.exports = NodeFS; |