From c411aa13945e6a444a2dee1157b680ba5591b866 Mon Sep 17 00:00:00 2001 From: "David Humphrey (:humph) david.humphrey@senecacollege.ca" Date: Fri, 29 Nov 2013 10:56:55 -0500 Subject: [PATCH 1/4] Include the rest of node.js' path functions --- src/path.js | 136 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 108 insertions(+), 28 deletions(-) diff --git a/src/path.js b/src/path.js index ad71c61..38eeffa 100644 --- a/src/path.js +++ b/src/path.js @@ -19,18 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -// https://github.com/joyent/node/blob/41e53e557992a7d552a8e23de035f9463da25c99/lib/path.js - -define(function(require) { - - // Split a filename into [root, dir, basename, ext], unix version - // 'root' is just a slash, or nothing. - var splitPathRe = - /^(\/?)([\s\S]+\/(?!$)|\/)?((?:\.{1,2}$|[\s\S]+?)?(\.[^.\/]*)?)$/; - var splitPath = function(filename) { - var result = splitPathRe.exec(filename); - return [result[1] || '', result[2] || '', result[3] || '', result[4] || '']; - }; +// Based on https://github.com/joyent/node/blob/41e53e557992a7d552a8e23de035f9463da25c99/lib/path.js +define(function() { // resolves . and .. elements in a path array with directory names there // must be no slashes, empty elements, or device names (c:\) in the array @@ -62,11 +52,47 @@ define(function(require) { return parts; } + // Split a filename into [root, dir, basename, ext], unix version + // 'root' is just a slash, or nothing. + var splitPathRe = + /^(\/?)([\s\S]+\/(?!$)|\/)?((?:\.{1,2}$|[\s\S]+?)?(\.[^.\/]*)?)$/; + var splitPath = function(filename) { + var result = splitPathRe.exec(filename); + return [result[1] || '', result[2] || '', result[3] || '', result[4] || '']; + }; + + // path.resolve([from ...], to) + function resolve() { + var resolvedPath = '', + resolvedAbsolute = false; + + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = arguments[i]; + + // Skip empty and invalid entries + if (typeof path !== 'string' || !path) { + continue; + } + + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charAt(0) === '/'; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeArray(resolvedPath.split('/').filter(function(p) { + return !!p; + }), !resolvedAbsolute).join('/'); + + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; + } + // path.normalize(path) - // posix version function normalize(path) { - var isAbsolute = path.charAt(0) === '/'; - // var trailingSlash = path.substr(-1) === '/'; + var isAbsolute = path.charAt(0) === '/', + trailingSlash = path.substr(-1) === '/'; // Normalize the path path = normalizeArray(path.split('/').filter(function(p) { @@ -76,14 +102,61 @@ define(function(require) { if (!path && !isAbsolute) { path = '.'; } - /* if (path && trailingSlash) { path += '/'; } - */ return (isAbsolute ? '/' : '') + path; - }; + } + + function join() { + var paths = Array.prototype.slice.call(arguments, 0); + return normalize(paths.filter(function(p, index) { + return p && typeof p === 'string'; + }).join('/')); + } + + // path.relative(from, to) + function relative(from, to) { + from = exports.resolve(from).substr(1); + to = exports.resolve(to).substr(1); + + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + + return outputParts.join('/'); + } function dirname(path) { var result = splitPath(path), @@ -101,8 +174,7 @@ define(function(require) { } return root + dir; - }; - + } function basename(path, ext) { var f = splitPath(path)[2]; @@ -110,18 +182,26 @@ define(function(require) { if (ext && f.substr(-1 * ext.length) === ext) { f = f.substr(0, f.length - ext.length); } - return f === "" ? "/" : f; - }; - - function isAbsolute(path) { - return path.charAt(0) === '/'; + return f; } + function extname(path) { + return splitPath(path)[3]; + } + + // NOTE: we don't support path.exists() or path.existsSync(), which are deprecated, + // and need a FileSystem instance to work. Use fs.stat(). + return { normalize: normalize, + resolve: resolve, + join: join, + relative: relative, + sep: '/', + delimiter: ':', dirname: dirname, basename: basename, - isAbsolute: isAbsolute - } + extname: extname + }; -}); \ No newline at end of file +}); From 00b7866874a5290223e709c79e7c2f96726486d2 Mon Sep 17 00:00:00 2001 From: "David Humphrey (:humph) david.humphrey@senecacollege.ca" Date: Fri, 29 Nov 2013 11:08:58 -0500 Subject: [PATCH 2/4] Fix up issue in node.js' impl of basename --- src/fs.js | 3 ++- src/path.js | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/fs.js b/src/fs.js index e594a1a..fd342bd 100644 --- a/src/fs.js +++ b/src/fs.js @@ -1721,7 +1721,8 @@ define(function(require) { }; return { - FileSystem: FileSystem + FileSystem: FileSystem, + Path: require('src/path') }; }); diff --git a/src/path.js b/src/path.js index 38eeffa..7c0fbfb 100644 --- a/src/path.js +++ b/src/path.js @@ -67,7 +67,7 @@ define(function() { resolvedAbsolute = false; for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = arguments[i]; + var path = (i >= 0) ? arguments[i] : '/'; // Skip empty and invalid entries if (typeof path !== 'string' || !path) { @@ -182,7 +182,8 @@ define(function() { if (ext && f.substr(-1 * ext.length) === ext) { f = f.substr(0, f.length - ext.length); } - return f; + // NOTE: node.js just does `return f` + return f === "" ? "/" : f; } function extname(path) { From 6608a368f561d0aa0941c016003b6e9352658164 Mon Sep 17 00:00:00 2001 From: "David Humphrey (:humph) david.humphrey@senecacollege.ca" Date: Fri, 29 Nov 2013 11:27:29 -0500 Subject: [PATCH 3/4] Mark off changes to path.js with XXXidbfs comment prefix. --- src/path.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/path.js b/src/path.js index 7c0fbfb..ec21da3 100644 --- a/src/path.js +++ b/src/path.js @@ -67,6 +67,7 @@ define(function() { resolvedAbsolute = false; for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + // XXXidbfs: we don't have process.cwd() so we use '/' as a fallback var path = (i >= 0) ? arguments[i] : '/'; // Skip empty and invalid entries @@ -182,7 +183,7 @@ define(function() { if (ext && f.substr(-1 * ext.length) === ext) { f = f.substr(0, f.length - ext.length); } - // NOTE: node.js just does `return f` + // XXXidbfs: node.js just does `return f` return f === "" ? "/" : f; } @@ -190,8 +191,8 @@ define(function() { return splitPath(path)[3]; } - // NOTE: we don't support path.exists() or path.existsSync(), which are deprecated, - // and need a FileSystem instance to work. Use fs.stat(). + // XXXidbfs: we don't support path.exists() or path.existsSync(), which + // are deprecated, and need a FileSystem instance to work. Use fs.stat(). return { normalize: normalize, From cce22ea599a9eb4a7ea4e35a47c2e989a55ece72 Mon Sep 17 00:00:00 2001 From: "David Humphrey (:humph) david.humphrey@senecacollege.ca" Date: Fri, 29 Nov 2013 11:37:58 -0500 Subject: [PATCH 4/4] Fix indent level on API headers in README --- README.md | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c631fb7..689a668 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ fs = new IDBFS.FileSystem({ }, fsReady); ``` -###IDBFS.FileSystem.providers - Storage Providers +####IDBFS.FileSystem.providers - Storage Providers IDBFS can be configured to use a number of different storage providers. The provider object encapsulates all aspects of data access, making it possible to swap in different backend storage options. There are currently 4 different @@ -131,6 +131,39 @@ if( IDBFS.FileSystem.providers.WebSQL.isSupported() ) { You can also write your own provider if you need a different backend. See the code in `src/providers` for details. +####IDBFS.Path + +The node.js [path module](http://nodejs.org/api/path.html) is available via the `IDBFS.Path` object. It is +identical to the node.js version with the following differences: +* No support for `exits()` or `existsSync()`. Use `fs.stat()` instead. +* No notion of a current working directory in `resolve` (the root dir is used instead) + +```javascript +var path = IDBFS.Path; +var dir = path.dirname('/foo/bar/baz/asdf/quux'); +// dir is now '/foo/bar/baz/asdf' + +var base = path.basename('/foo/bar/baz/asdf/quux.html'); +// base is now 'quux.html' + +var ext = path.extname('index.html'); +// ext is now '.html' + +var newpath = path.join('/foo', 'bar', 'baz/asdf', 'quux', '..'); +// new path is now '/foo/bar/baz/asdf' +``` + +For more info see the docs in the [path module](http://nodejs.org/api/path.html) for a particular method: +* `path.normalize(p)` +* `path.join([path1], [path2], [...])` +* `path.resolve([from ...], to)` +* `path.relative(from, to)` +* `path.dirname(p)` +* `path.basename(p, [ext])` +* `path.extname(p)` +* `path.sep` +* `path.delimiter` + #### fs.stat(path, callback) Asynchronous stat(2). Callback gets `(error, stats)`, where `stats` is an object like