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" + } } ];