index.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. "use strict";
  2. // Dependencies
  3. var protocols = require("protocols"),
  4. isSsh = require("is-ssh"),
  5. qs = require("query-string");
  6. /**
  7. * parsePath
  8. * Parses the input url.
  9. *
  10. * @name parsePath
  11. * @function
  12. * @param {String} url The input url.
  13. * @return {Object} An object containing the following fields:
  14. *
  15. * - `protocols` (Array): An array with the url protocols (usually it has one element).
  16. * - `protocol` (String): The first protocol, `"ssh"` (if the url is a ssh url) or `"file"`.
  17. * - `port` (null|Number): The domain port.
  18. * - `resource` (String): The url domain (including subdomains).
  19. * - `user` (String): The authentication user (usually for ssh urls).
  20. * - `pathname` (String): The url pathname.
  21. * - `hash` (String): The url hash.
  22. * - `search` (String): The url querystring value.
  23. * - `href` (String): The input url.
  24. * - `query` (Object): The url querystring, parsed as object.
  25. */
  26. function parsePath(url) {
  27. url = (url || "").trim();
  28. var output = {
  29. protocols: protocols(url),
  30. protocol: null,
  31. port: null,
  32. resource: "",
  33. user: "",
  34. pathname: "",
  35. hash: "",
  36. search: "",
  37. href: url,
  38. query: Object.create(null)
  39. },
  40. protocolIndex = url.indexOf("://"),
  41. resourceIndex = -1,
  42. splits = null,
  43. parts = null;
  44. if (url.startsWith(".")) {
  45. if (url.startsWith("./")) {
  46. url = url.substring(2);
  47. }
  48. output.pathname = url;
  49. output.protocol = "file";
  50. }
  51. var firstChar = url.charAt(1);
  52. if (!output.protocol) {
  53. output.protocol = output.protocols[0];
  54. if (!output.protocol) {
  55. if (isSsh(url)) {
  56. output.protocol = "ssh";
  57. } else if (firstChar === "/" || firstChar === "~") {
  58. url = url.substring(2);
  59. output.protocol = "file";
  60. } else {
  61. output.protocol = "file";
  62. }
  63. }
  64. }
  65. if (protocolIndex !== -1) {
  66. url = url.substring(protocolIndex + 3);
  67. }
  68. parts = url.split(/\/|\\/);
  69. if (output.protocol !== "file") {
  70. output.resource = parts.shift();
  71. } else {
  72. output.resource = "";
  73. }
  74. // user@domain
  75. splits = output.resource.split("@");
  76. if (splits.length === 2) {
  77. output.user = splits[0];
  78. output.resource = splits[1];
  79. }
  80. // domain.com:port
  81. splits = output.resource.split(":");
  82. if (splits.length === 2) {
  83. output.resource = splits[0];
  84. if (splits[1]) {
  85. output.port = Number(splits[1]);
  86. if (isNaN(output.port)) {
  87. output.port = null;
  88. parts.unshift(splits[1]);
  89. }
  90. } else {
  91. output.port = null;
  92. }
  93. }
  94. // Remove empty elements
  95. parts = parts.filter(Boolean);
  96. // Stringify the pathname
  97. if (output.protocol === "file") {
  98. output.pathname = output.href;
  99. } else {
  100. output.pathname = output.pathname || (output.protocol !== "file" || output.href[0] === "/" ? "/" : "") + parts.join("/");
  101. }
  102. // #some-hash
  103. splits = output.pathname.split("#");
  104. if (splits.length === 2) {
  105. output.pathname = splits[0];
  106. output.hash = splits[1];
  107. }
  108. // ?foo=bar
  109. splits = output.pathname.split("?");
  110. if (splits.length === 2) {
  111. output.pathname = splits[0];
  112. output.search = splits[1];
  113. }
  114. output.query = qs.parse(output.search);
  115. output.href = output.href.replace(/\/$/, "");
  116. output.pathname = output.pathname.replace(/\/$/, "");
  117. return output;
  118. }
  119. module.exports = parsePath;