diff --git a/index.d.ts b/index.d.ts
index 81ca086ae..c168da9b5 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -2423,6 +2423,13 @@ export namespace util {
/** A minimal path module to resolve Unix, Windows and URL paths alike. */
namespace path {
+ /**
+ * Gets the prefix of an absolute UNC path, Unix path, or URL that makes it absolute, if present.
+ * @param path Path to test
+ * @returns the prefix, or null if path is relative
+ */
+ function absolutePrefix(path: string): (string|null);
+
/**
* Tests if the specified path is absolute.
* @param path Path to test
diff --git a/lib/path/README.md b/lib/path/README.md
index 1c1a2ba2f..e02de1ae1 100644
--- a/lib/path/README.md
+++ b/lib/path/README.md
@@ -16,4 +16,7 @@ API
* **path.resolve(originPath: `string`, includePath: `string`, [alreadyNormalized=false: `boolean`]): `string`**
Resolves the specified include path against the specified origin path.
+* **path.absolutePrefix(path: `string`): `string|null`**
+ Gets the prefix of an absolute Windows, UNC, or Unix path or a URL that indicates it's absolute.
+
**License:** [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/lib/path/index.d.ts b/lib/path/index.d.ts
index b664d81f6..d16a4a66b 100644
--- a/lib/path/index.d.ts
+++ b/lib/path/index.d.ts
@@ -1,3 +1,10 @@
+/**
+ * Gets the prefix of an absolute Windows, UNC, or Unix path or a URL that indicates it's absolute.
+ * @param {string} path Path to test
+ * @returns {string|null} the prefix, or null if path is relative
+ */
+export function absolutePrefix(path: string): (string|null);
+
/**
* Tests if the specified path is absolute.
* @param {string} path Path to test
diff --git a/lib/path/index.js b/lib/path/index.js
index 8c7ee12fb..e957a5d8c 100644
--- a/lib/path/index.js
+++ b/lib/path/index.js
@@ -7,6 +7,31 @@
*/
var path = exports;
+var absolutePrefix =
+/**
+ * Gets the prefix of an absolute Windows, UNC, or Unix path or a URL that indicates it's absolute.
+ * @param {string} path Path to test
+ * @returns {string|null} the prefix, or null if path is relative
+ */
+path.absolutePrefix = function absolutePrefix(path) {
+ var match;
+ if (path.startsWith("\\\\")) {
+ // UNC path
+ return "\\\\";
+ } else if ((match = /^\w*:\/\//.exec(path)) !== null) {
+ // URL
+ return match[0];
+ } else if ((match = /^\w:/.exec(path)) !== null) {
+ // Windows path
+ return match[0];
+ } else if (path.startsWith("/")) {
+ // Unix path
+ return "/";
+ } else {
+ return null;
+ }
+}
+
var isAbsolute =
/**
* Tests if the specified path is absolute.
@@ -14,7 +39,7 @@ var isAbsolute =
* @returns {boolean} `true` if path is absolute
*/
path.isAbsolute = function isAbsolute(path) {
- return /^(?:\/|\w+:|\\\\\w+)/.test(path);
+ return absolutePrefix(path) !== null;
};
var normalize =
@@ -24,20 +49,18 @@ var normalize =
* @returns {string} Normalized path
*/
path.normalize = function normalize(path) {
- var firstTwoCharacters = path.substring(0,2);
- var uncPrefix = "";
- if (firstTwoCharacters === "\\\\") {
- uncPrefix = firstTwoCharacters;
- path = path.substring(2);
+ var absolute = false;
+ var prefix = absolutePrefix(path);
+ if (prefix !== null) {
+ absolute = true;
+ path = path.substring(prefix.length);
+ } else {
+ prefix = "";
}
path = path.replace(/\\/g, "/")
.replace(/\/{2,}/g, "/");
- var parts = path.split("/"),
- absolute = isAbsolute(path),
- prefix = "";
- if (absolute)
- prefix = parts.shift() + "/";
+ var parts = path.split("/");
for (var i = 0; i < parts.length;) {
if (parts[i] === "..") {
if (i > 0 && parts[i - 1] !== "..")
@@ -51,7 +74,7 @@ path.normalize = function normalize(path) {
else
++i;
}
- return uncPrefix + prefix + parts.join("/");
+ return prefix + parts.join("/");
};
/**
diff --git a/lib/path/tests/index.js b/lib/path/tests/index.js
index 6b6155667..96a9811cc 100644
--- a/lib/path/tests/index.js
+++ b/lib/path/tests/index.js
@@ -12,6 +12,9 @@ tape.test("path", function(test) {
test.ok(path.isAbsolute("\\\\some-unc\\path\\file.js"), "should identify windows unc paths");
+ test.ok(path.isAbsolute("https://example.com/path/file.js"), "should identify absolute URLs");
+ test.ok(path.isAbsolute("://example.com/path/file.js"), "should identify protocol-relative URLs");
+
var paths = [
{
actual: "X:\\some\\..\\.\\path\\\\file.js",
@@ -61,6 +64,20 @@ tape.test("path", function(test) {
origin: "\\\\some-unc\\path\\..\\origin.js",
expected: "\\\\some-unc/file.js"
}
+ }, {
+ actual: "https://example.com/path/../file.js",
+ normal: "https://example.com/file.js",
+ resolve: {
+ origin: "/some/local/path",
+ expected: "https://example.com/file.js"
+ }
+ }, {
+ actual: "path/file2.js",
+ normal: "path/file2.js",
+ resolve: {
+ origin: "https://example.com/file1.js",
+ expected: "https://example.com/path/file2.js"
+ }
}
];