resolve-pathname.js 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global.resolvePathname = factory());
  5. }(this, (function () { 'use strict';
  6. function isAbsolute(pathname) {
  7. return pathname.charAt(0) === '/';
  8. }
  9. // About 1.5x faster than the two-arg version of Array#splice()
  10. function spliceOne(list, index) {
  11. for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) {
  12. list[i] = list[k];
  13. }
  14. list.pop();
  15. }
  16. // This implementation is based heavily on node's url.parse
  17. function resolvePathname(to, from) {
  18. if (from === undefined) from = '';
  19. var toParts = (to && to.split('/')) || [];
  20. var fromParts = (from && from.split('/')) || [];
  21. var isToAbs = to && isAbsolute(to);
  22. var isFromAbs = from && isAbsolute(from);
  23. var mustEndAbs = isToAbs || isFromAbs;
  24. if (to && isAbsolute(to)) {
  25. // to is absolute
  26. fromParts = toParts;
  27. } else if (toParts.length) {
  28. // to is relative, drop the filename
  29. fromParts.pop();
  30. fromParts = fromParts.concat(toParts);
  31. }
  32. if (!fromParts.length) return '/';
  33. var hasTrailingSlash;
  34. if (fromParts.length) {
  35. var last = fromParts[fromParts.length - 1];
  36. hasTrailingSlash = last === '.' || last === '..' || last === '';
  37. } else {
  38. hasTrailingSlash = false;
  39. }
  40. var up = 0;
  41. for (var i = fromParts.length; i >= 0; i--) {
  42. var part = fromParts[i];
  43. if (part === '.') {
  44. spliceOne(fromParts, i);
  45. } else if (part === '..') {
  46. spliceOne(fromParts, i);
  47. up++;
  48. } else if (up) {
  49. spliceOne(fromParts, i);
  50. up--;
  51. }
  52. }
  53. if (!mustEndAbs) for (; up--; up) fromParts.unshift('..');
  54. if (
  55. mustEndAbs &&
  56. fromParts[0] !== '' &&
  57. (!fromParts[0] || !isAbsolute(fromParts[0]))
  58. )
  59. fromParts.unshift('');
  60. var result = fromParts.join('/');
  61. if (hasTrailingSlash && result.substr(-1) !== '/') result += '/';
  62. return result;
  63. }
  64. return resolvePathname;
  65. })));