resolve-pathname.js 1.7 KB

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