aboutsummaryrefslogtreecommitdiff
path: root/lib/path.js
diff options
context:
space:
mode:
authorisaacs <i@izs.me>2010-10-26 14:41:06 -0700
committerRyan Dahl <ry@tinyclouds.org>2010-11-14 22:49:26 -0800
commit9996b459e15581fcbff22de2f9a2b5173fc2ba5f (patch)
tree93c8050ab102666e133464128f5a5c3a708b24d3 /lib/path.js
parent25eecd179bb50b08a97eccd80edde1b9afa124d0 (diff)
downloadandroid-node-v8-9996b459e15581fcbff22de2f9a2b5173fc2ba5f.tar.gz
android-node-v8-9996b459e15581fcbff22de2f9a2b5173fc2ba5f.tar.bz2
android-node-v8-9996b459e15581fcbff22de2f9a2b5173fc2ba5f.zip
Implement new path.join behavior
1. Express desired path.join behavior in tests. 2. Update fs.realpath to reflect new path.join behavior 3. Update url.resolve() to use new path.join behavior.
Diffstat (limited to 'lib/path.js')
-rw-r--r--lib/path.js95
1 files changed, 79 insertions, 16 deletions
diff --git a/lib/path.js b/lib/path.js
index d3a2ea698f..5eea05f782 100644
--- a/lib/path.js
+++ b/lib/path.js
@@ -1,44 +1,107 @@
+function validPathPart (p, keepBlanks) {
+ return typeof p === "string" && (p || keepBlanks);
+}
+
exports.join = function () {
- return exports.normalize(Array.prototype.join.call(arguments, "/"));
+ var args = Array.prototype.slice.call(arguments);
+ // edge case flag to switch into url-resolve-mode
+ var keepBlanks = false;
+ if (args[ args.length - 1 ] === true) {
+ keepBlanks = args.pop();
+ }
+ // return exports.split(args.join("/"), keepBlanks).join("/");
+ var joined = exports.normalizeArray(args, keepBlanks).join("/");
+ return joined;
+};
+exports.split = function (path, keepBlanks) {
+ // split based on /, but only if that / is not at the start or end.
+ return exports.normalizeArray(path.split(/^|\/(?!$)/), keepBlanks);
};
+function cleanArray (parts, keepBlanks) {
+ var i = 0;
+ var l = parts.length - 1;
+ var stripped = false;
+ // strip leading empty args
+ while (i < l && !validPathPart(parts[i], keepBlanks)) {
+ stripped = true;
+ i ++;
+ }
+ // strip tailing empty args
+ while (l >= i && !validPathPart(parts[l], keepBlanks)) {
+ stripped = true;
+ l --;
+ }
+ if (stripped) {
+ // if l chopped all the way back to i, then this is empty
+ parts = Array.prototype.slice.call(parts, i, l + 1);
+ }
+ return parts.filter(function (p) { return validPathPart(p, keepBlanks) })
+ .join('/')
+ .split(/^|\/(?!$)/);
+}
+exports.normalizeArray = function (original, keepBlanks) {
+ var parts = cleanArray(original, keepBlanks);
+ if (!parts.length || (parts.length === 1 && !parts[0])) return ["."];
-exports.normalizeArray = function (parts, keepBlanks) {
- var directories = [], prev;
- for (var i = 0, l = parts.length - 1; i <= l; i++) {
+ // now we're fully ready to rock.
+ // leading/trailing invalids have been stripped off.
+ // if it comes in starting with a slash, or ending with a slash,
+ var leadingSlash = (parts[0].charAt(0) === "/");
+ if (leadingSlash) parts[0] = parts[0].substr(1);
+ var last = parts.slice(-1)[0];
+ var tailingSlash = (last.substr(-1) === "/");
+ if (tailingSlash) parts[parts.length - 1] = last.slice(0, -1);
+ var directories = [];
+ var prev;
+ for (var i = 0, l = parts.length - 1 ; i <= l ; i ++) {
var directory = parts[i];
- // if it's blank, but it's not the first thing, and not the last thing, skip it.
- if (directory === "" && i !== 0 && i !== l && !keepBlanks) continue;
+ // if it's blank, and we're not keeping blanks, then skip it.
+ if (directory === "" && !keepBlanks) continue;
- // if it's a dot, and there was some previous dir already, then skip it.
- if (directory === "." && prev !== undefined) continue;
-
- // if it starts with "", and is a . or .., then skip it.
- if (directories.length === 1 && directories[0] === "" && (
- directory === "." || directory === "..")) continue;
+ // if it's a dot, then skip it
+ if (directory === "." && (
+ directories.length
+ || (i === 0 && !(tailingSlash && i === l))
+ || (i === 0 && leadingSlash)
+ )) continue;
+ // if we're dealing with an absolute path, then discard ..s that go
+ // above that the base.
+ if (leadingSlash && directories.length === 0 && directory === "..") {
+ continue;
+ }
+ // trying to go up a dir
if (
directory === ".."
&& directories.length
&& prev !== ".."
- && prev !== "."
&& prev !== undefined
- && (prev !== "" || keepBlanks)
) {
directories.pop();
prev = directories.slice(-1)[0];
} else {
- if (prev === ".") directories.pop();
directories.push(directory);
prev = directory;
}
}
+ if (!directories.length) {
+ directories = [ leadingSlash || tailingSlash ? "" : "." ];
+ }
+ var last = directories.slice(-1)[0];
+ if (tailingSlash && last.substr(-1) !== "/") {
+ directories[directories.length-1] += "/";
+ }
+ if (leadingSlash && directories[0].charAt(0) !== "/") {
+ if (directories[0] === ".") directories[0] = "";
+ directories[0] = "/" + directories[0];
+ }
return directories;
};
exports.normalize = function (path, keepBlanks) {
- return exports.normalizeArray(path.split("/"), keepBlanks).join("/");
+ return exports.join(path, keepBlanks || false);
};
exports.dirname = function (path) {