Permalink
Browse files

path, feat: add `path.relative` which compats with nodejs. (#449)

  • Loading branch information...
richardo2016 authored and xicilion committed Aug 1, 2018
1 parent 66f5f8d commit 6405bf7f5948139c9b8481bbbfa501c512e0cfbf
View
@@ -29,6 +29,7 @@ class path_base : public object_base {
static result_t isAbsolute(exlib::string path, bool& retVal);
static result_t join(OptArgs ps, exlib::string& retVal);
static result_t resolve(OptArgs ps, exlib::string& retVal);
static result_t relative(exlib::string _from, exlib::string to, exlib::string& retVal);
static result_t toNamespacedPath(v8::Local<v8::Value> path, v8::Local<v8::Value>& retVal);
static result_t get_sep(exlib::string& retVal);
static result_t get_delimiter(exlib::string& retVal);
@@ -55,6 +56,7 @@ class path_base : public object_base {
static void s_isAbsolute(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_join(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_resolve(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_relative(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_toNamespacedPath(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_get_sep(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Value>& args);
static void s_get_delimiter(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Value>& args);
@@ -75,6 +77,7 @@ inline ClassInfo& path_base::class_info()
{ "isAbsolute", s_isAbsolute, true },
{ "join", s_join, true },
{ "resolve", s_resolve, true },
{ "relative", s_relative, true },
{ "toNamespacedPath", s_toNamespacedPath, true }
};
@@ -224,6 +227,23 @@ inline void path_base::s_resolve(const v8::FunctionCallbackInfo<v8::Value>& args
METHOD_RETURN();
}
inline void path_base::s_relative(const v8::FunctionCallbackInfo<v8::Value>& args)
{
exlib::string vr;
METHOD_NAME("path.relative");
METHOD_ENTER();
METHOD_OVER(2, 2);
ARG(exlib::string, 0);
ARG(exlib::string, 1);
hr = relative(v0, v1, vr);
METHOD_RETURN();
}
inline void path_base::s_toNamespacedPath(const v8::FunctionCallbackInfo<v8::Value>& args)
{
v8::Local<v8::Value> vr;
@@ -29,6 +29,7 @@ class path_posix_base : public object_base {
static result_t isAbsolute(exlib::string path, bool& retVal);
static result_t join(OptArgs ps, exlib::string& retVal);
static result_t resolve(OptArgs ps, exlib::string& retVal);
static result_t relative(exlib::string _from, exlib::string to, exlib::string& retVal);
static result_t toNamespacedPath(v8::Local<v8::Value> path, v8::Local<v8::Value>& retVal);
static result_t get_sep(exlib::string& retVal);
static result_t get_delimiter(exlib::string& retVal);
@@ -55,6 +56,7 @@ class path_posix_base : public object_base {
static void s_isAbsolute(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_join(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_resolve(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_relative(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_toNamespacedPath(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_get_sep(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Value>& args);
static void s_get_delimiter(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Value>& args);
@@ -75,6 +77,7 @@ inline ClassInfo& path_posix_base::class_info()
{ "isAbsolute", s_isAbsolute, true },
{ "join", s_join, true },
{ "resolve", s_resolve, true },
{ "relative", s_relative, true },
{ "toNamespacedPath", s_toNamespacedPath, true }
};
@@ -224,6 +227,23 @@ inline void path_posix_base::s_resolve(const v8::FunctionCallbackInfo<v8::Value>
METHOD_RETURN();
}
inline void path_posix_base::s_relative(const v8::FunctionCallbackInfo<v8::Value>& args)
{
exlib::string vr;
METHOD_NAME("path_posix.relative");
METHOD_ENTER();
METHOD_OVER(2, 2);
ARG(exlib::string, 0);
ARG(exlib::string, 1);
hr = relative(v0, v1, vr);
METHOD_RETURN();
}
inline void path_posix_base::s_toNamespacedPath(const v8::FunctionCallbackInfo<v8::Value>& args)
{
v8::Local<v8::Value> vr;
@@ -29,6 +29,7 @@ class path_win32_base : public object_base {
static result_t isAbsolute(exlib::string path, bool& retVal);
static result_t join(OptArgs ps, exlib::string& retVal);
static result_t resolve(OptArgs ps, exlib::string& retVal);
static result_t relative(exlib::string _from, exlib::string to, exlib::string& retVal);
static result_t toNamespacedPath(v8::Local<v8::Value> path, v8::Local<v8::Value>& retVal);
static result_t get_sep(exlib::string& retVal);
static result_t get_delimiter(exlib::string& retVal);
@@ -55,6 +56,7 @@ class path_win32_base : public object_base {
static void s_isAbsolute(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_join(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_resolve(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_relative(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_toNamespacedPath(const v8::FunctionCallbackInfo<v8::Value>& args);
static void s_get_sep(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Value>& args);
static void s_get_delimiter(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Value>& args);
@@ -75,6 +77,7 @@ inline ClassInfo& path_win32_base::class_info()
{ "isAbsolute", s_isAbsolute, true },
{ "join", s_join, true },
{ "resolve", s_resolve, true },
{ "relative", s_relative, true },
{ "toNamespacedPath", s_toNamespacedPath, true }
};
@@ -224,6 +227,23 @@ inline void path_win32_base::s_resolve(const v8::FunctionCallbackInfo<v8::Value>
METHOD_RETURN();
}
inline void path_win32_base::s_relative(const v8::FunctionCallbackInfo<v8::Value>& args)
{
exlib::string vr;
METHOD_NAME("path_win32.relative");
METHOD_ENTER();
METHOD_OVER(2, 2);
ARG(exlib::string, 0);
ARG(exlib::string, 1);
hr = relative(v0, v1, vr);
METHOD_RETURN();
}
inline void path_win32_base::s_toNamespacedPath(const v8::FunctionCallbackInfo<v8::Value>& args)
{
v8::Local<v8::Value> vr;
View
@@ -568,6 +568,18 @@ inline result_t _resolve(OptArgs ps, exlib::string& retVal)
return _normalize(p.str(), retVal, true);
}
inline result_t _resolve(exlib::string& path)
{
exlib::string str;
process_base::cwd(str);
Path p;
p.resolvePosix(str);
p.resolvePosix(path);
return _normalize(p.str(), path, true);
}
inline result_t _resolve_win32(OptArgs ps, exlib::string& retVal)
{
exlib::string str;
@@ -600,6 +612,234 @@ inline result_t _resolve_win32(exlib::string& path)
return _normalize_win32(p.str(), path, true);
}
inline result_t _relative(exlib::string from, exlib::string to, exlib::string& retVal)
{
if (from == to)
return 0;
result_t hr;
hr = _resolve(from);
if (hr < 0)
return hr;
hr = _resolve(to);
if (hr < 0)
return hr;
if (from == to)
return 0;
// Trim any leading backslashes
int32_t fromStart = 1;
for (; fromStart < from.length(); ++fromStart) {
if (!isPosixPathSlash(from[fromStart]))
break;
}
int32_t fromEnd = (int32_t)from.length();
int32_t fromLen = (fromEnd - fromStart);
// Trim any leading backslashes
int32_t toStart = 1;
for (; toStart < to.length(); ++toStart) {
if (!isPosixPathSlash(to[toStart]))
break;
}
int32_t toEnd = (int32_t)to.length();
int32_t toLen = (toEnd - toStart);
// Compare paths to find the longest common path from root
int32_t length = (fromLen < toLen ? fromLen : toLen);
int32_t lastCommonSep = -1;
int32_t i = 0;
for (; i <= length; ++i) {
if (i == length) {
if (toLen > length) {
if (isPosixPathSlash(to[toStart + i])) {
// We get here if `from` is the exact base path for `to`.
// For example: from='/foo/bar'; to='/foo/bar/baz'
return _normalize(to.substr(toStart + i + 1), retVal, false);
} else if (i == 0) {
// We get here if `from` is the root
// For example: from='/'; to='/foo'
return _normalize(to.substr(toStart + i), retVal, false);
}
} else if (fromLen > length) {
if (isPosixPathSlash(from[fromStart + i])) {
// We get here if `to` is the exact base path for `from`.
// For example: from='/foo/bar/baz'; to='/foo/bar'
lastCommonSep = i;
} else if (i == 0) {
// We get here if `to` is the root.
// For example: from='/foo'; to='/'
lastCommonSep = 0;
}
}
break;
}
char fromChar = from[fromStart + i];
char toChar = to[toStart + i];
if (fromChar != toChar)
break;
else if (isPosixPathSlash(fromChar))
lastCommonSep = i;
}
exlib::string out = "";
// Generate the relative path based on the path difference between `to`
// and `from`
for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
if (i == fromEnd || isPosixPathSlash(from[i])) {
if (out.length() == 0)
out += "..";
else
out += "/..";
}
}
// Lastly, append the rest of the destination (`to`) path that comes after
// the common path parts
if (out.length() > 0) {
return _normalize(out + to.substr(toStart + lastCommonSep), retVal, false);
} else {
toStart += lastCommonSep;
if (isPosixPathSlash(to[toStart]))
++toStart;
return _normalize(to.substr(toStart), retVal, false);
}
return 0;
}
inline result_t _relative_win32(exlib::string from, exlib::string to, exlib::string& retVal)
{
if (from == to)
return 0;
exlib::string fromOrig = "" + from;
exlib::string toOrig = "" + to;
exlib::string str;
int32_t hr;
hr = _resolve_win32(from);
if (hr < 0)
return hr;
hr = _resolve_win32(to);
if (hr < 0)
return hr;
if (fromOrig == toOrig)
return 0;
from = "" + fromOrig;
from.tolower();
to = "" + toOrig;
to.tolower();
if (from == to)
return 0;
// Trim any leading backslashes
int32_t fromStart = 0;
for (; fromStart < from.length(); ++fromStart) {
if (!isWin32PathSlash(from[fromStart]))
break;
}
// Trim trailing backslashes (applicable to UNC paths only)
int32_t fromEnd = (int32_t)from.length();
for (; fromEnd - 1 > fromStart; --fromEnd) {
if (!isWin32PathSlash(from[fromEnd - 1]))
break;
}
int32_t fromLen = (fromEnd - fromStart);
// Trim any leading backslashes
int32_t toStart = 0;
for (; toStart < to.length(); ++toStart) {
if (!isWin32PathSlash(to[toStart]))
break;
}
// Trim trailing backslashes (applicable to UNC paths only)
int32_t toEnd = (int32_t)to.length();
for (; toEnd - 1 > toStart; --toEnd) {
if (!isWin32PathSlash(to[toEnd - 1]))
break;
}
int32_t toLen = (toEnd - toStart);
// Compare paths to find the longest common path from root
int32_t length = (fromLen < toLen ? fromLen : toLen);
int32_t lastCommonSep = -1;
int32_t i = 0;
for (; i <= length; ++i) {
if (i == length) {
if (toLen > length) {
if (isWin32PathSlash(to[toStart + i])) {
// We get here if `from` is the exact base path for `to`.
// For example: from='C:\\foo\\bar'; to='C:\\foo\\bar\\baz'
return _normalize_win32(toOrig.substr(toStart + i + 1), retVal, true);
} else if (i == 2) {
// We get here if `from` is the device root.
// For example: from='C:\\'; to='C:\\foo'
return _normalize_win32(toOrig.substr(toStart + i), retVal, true);
}
}
if (fromLen > length) {
if (isWin32PathSlash(from[fromStart + i])) {
// We get here if `to` is the exact base path for `from`.
// For example: from='C:\\foo\\bar'; to='C:\\foo'
lastCommonSep = i;
} else if (i == 2) {
// We get here if `to` is the device root.
// For example: from='C:\\foo\\bar'; to='C:\\'
lastCommonSep = 3;
}
}
break;
}
char fromChar = from[fromStart + i];
char toChar = to[toStart + i];
if (fromChar != toChar)
break;
else if (isWin32PathSlash(fromChar))
lastCommonSep = i;
}
// We found a mismatch before the first common path separator was seen, so
// return the original `to`.
if (i != length && lastCommonSep == -1) {
return _normalize_win32(toOrig, retVal, true);
}
exlib::string out = "";
if (lastCommonSep == -1)
lastCommonSep = 0;
// Generate the relative path based on the path difference between `to` and
// `from`
for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
if (i == fromEnd || isWin32PathSlash(from[i])) {
if (out.length() == 0)
out += "..";
else
out += "\\..";
}
}
// Lastly, append the rest of the destination (`to`) path that comes after
// the common path parts
if (out.length() > 0) {
return _normalize_win32(out + toOrig.substr(toStart + lastCommonSep), retVal, true);
} else {
toStart += lastCommonSep;
if (isWin32PathSlash(toOrig[toStart]))
++toStart;
return _normalize_win32(toOrig.substr(toStart), retVal, true);
}
}
inline result_t _sep(exlib::string& retVal)
{
retVal.assign(1, PATH_SLASH);
Oops, something went wrong.

0 comments on commit 6405bf7

Please sign in to comment.