"use strict"; // Dependencies var protocols = require("protocols"), isSsh = require("is-ssh"), qs = require("query-string"); /** * parsePath * Parses the input url. * * @name parsePath * @function * @param {String} url The input url. * @return {Object} An object containing the following fields: * * - `protocols` (Array): An array with the url protocols (usually it has one element). * - `protocol` (String): The first protocol, `"ssh"` (if the url is a ssh url) or `"file"`. * - `port` (null|Number): The domain port. * - `resource` (String): The url domain (including subdomains). * - `user` (String): The authentication user (usually for ssh urls). * - `pathname` (String): The url pathname. * - `hash` (String): The url hash. * - `search` (String): The url querystring value. * - `href` (String): The input url. * - `query` (Object): The url querystring, parsed as object. */ function parsePath(url) { url = (url || "").trim(); var output = { protocols: protocols(url), protocol: null, port: null, resource: "", user: "", pathname: "", hash: "", search: "", href: url, query: Object.create(null) }, protocolIndex = url.indexOf("://"), resourceIndex = -1, splits = null, parts = null; if (url.startsWith(".")) { if (url.startsWith("./")) { url = url.substring(2); } output.pathname = url; output.protocol = "file"; } var firstChar = url.charAt(1); if (!output.protocol) { output.protocol = output.protocols[0]; if (!output.protocol) { if (isSsh(url)) { output.protocol = "ssh"; } else if (firstChar === "/" || firstChar === "~") { url = url.substring(2); output.protocol = "file"; } else { output.protocol = "file"; } } } if (protocolIndex !== -1) { url = url.substring(protocolIndex + 3); } parts = url.split(/\/|\\/); if (output.protocol !== "file") { output.resource = parts.shift(); } else { output.resource = ""; } // user@domain splits = output.resource.split("@"); if (splits.length === 2) { output.user = splits[0]; output.resource = splits[1]; } // domain.com:port splits = output.resource.split(":"); if (splits.length === 2) { output.resource = splits[0]; if (splits[1]) { output.port = Number(splits[1]); if (isNaN(output.port)) { output.port = null; parts.unshift(splits[1]); } } else { output.port = null; } } // Remove empty elements parts = parts.filter(Boolean); // Stringify the pathname if (output.protocol === "file") { output.pathname = output.href; } else { output.pathname = output.pathname || (output.protocol !== "file" || output.href[0] === "/" ? "/" : "") + parts.join("/"); } // #some-hash splits = output.pathname.split("#"); if (splits.length === 2) { output.pathname = splits[0]; output.hash = splits[1]; } // ?foo=bar splits = output.pathname.split("?"); if (splits.length === 2) { output.pathname = splits[0]; output.search = splits[1]; } output.query = qs.parse(output.search); output.href = output.href.replace(/\/$/, ""); output.pathname = output.pathname.replace(/\/$/, ""); return output; } module.exports = parsePath;