normalize.js 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. module.exports = function normalize(path) {
  2. var parts = path.split(/(\\+|\/+)/);
  3. if(parts.length === 1)
  4. return path;
  5. var result = [];
  6. var absolutePathStart = 0;
  7. for(var i = 0, sep = false; i < parts.length; i++, sep = !sep) {
  8. var part = parts[i];
  9. if(i === 0 && /^([A-Z]:)?$/i.test(part)) {
  10. result.push(part);
  11. absolutePathStart = 2;
  12. } else if(sep) {
  13. result.push(part[0]);
  14. } else if(part === "..") {
  15. switch(result.length) {
  16. case 0:
  17. // i. e. ".." => ".."
  18. // i. e. "../a/b/c" => "../a/b/c"
  19. result.push(part);
  20. break;
  21. case 2:
  22. // i. e. "a/.." => ""
  23. // i. e. "/.." => "/"
  24. // i. e. "C:\.." => "C:\"
  25. // i. e. "a/../b/c" => "b/c"
  26. // i. e. "/../b/c" => "/b/c"
  27. // i. e. "C:\..\a\b\c" => "C:\a\b\c"
  28. i++;
  29. sep = !sep;
  30. result.length = absolutePathStart;
  31. break;
  32. case 4:
  33. // i. e. "a/b/.." => "a"
  34. // i. e. "/a/.." => "/"
  35. // i. e. "C:\a\.." => "C:\"
  36. // i. e. "/a/../b/c" => "/b/c"
  37. if(absolutePathStart === 0) {
  38. result.length -= 3;
  39. } else {
  40. i++;
  41. sep = !sep;
  42. result.length = 2;
  43. }
  44. break;
  45. default:
  46. // i. e. "/a/b/.." => "/a"
  47. // i. e. "/a/b/../c" => "/a/c"
  48. result.length -= 3;
  49. break;
  50. }
  51. } else if(part === ".") {
  52. switch(result.length) {
  53. case 0:
  54. // i. e. "." => "."
  55. // i. e. "./a/b/c" => "./a/b/c"
  56. result.push(part);
  57. break;
  58. case 2:
  59. // i. e. "a/." => "a"
  60. // i. e. "/." => "/"
  61. // i. e. "C:\." => "C:\"
  62. // i. e. "C:\.\a\b\c" => "C:\a\b\c"
  63. if(absolutePathStart === 0) {
  64. result.length--;
  65. } else {
  66. i++;
  67. sep = !sep;
  68. }
  69. break;
  70. default:
  71. // i. e. "a/b/." => "a/b"
  72. // i. e. "/a/." => "/"
  73. // i. e. "C:\a\." => "C:\"
  74. // i. e. "a/./b/c" => "a/b/c"
  75. // i. e. "/a/./b/c" => "/a/b/c"
  76. result.length--;
  77. break;
  78. }
  79. } else if(part) {
  80. result.push(part);
  81. }
  82. }
  83. if(result.length === 1 && /^[A-Za-z]:$/.test(result))
  84. return result[0] + "\\";
  85. return result.join("");
  86. };