extpath.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. import { posix, sep } from './path.js';
  6. import { isWindows } from './platform.js';
  7. import { startsWithIgnoreCase } from './strings.js';
  8. export function isPathSeparator(code) {
  9. return code === 47 /* CharCode.Slash */ || code === 92 /* CharCode.Backslash */;
  10. }
  11. /**
  12. * Takes a Windows OS path and changes backward slashes to forward slashes.
  13. * This should only be done for OS paths from Windows (or user provided paths potentially from Windows).
  14. * Using it on a Linux or MaxOS path might change it.
  15. */
  16. export function toSlashes(osPath) {
  17. return osPath.replace(/[\\/]/g, posix.sep);
  18. }
  19. /**
  20. * Takes a Windows OS path (using backward or forward slashes) and turns it into a posix path:
  21. * - turns backward slashes into forward slashes
  22. * - makes it absolute if it starts with a drive letter
  23. * This should only be done for OS paths from Windows (or user provided paths potentially from Windows).
  24. * Using it on a Linux or MaxOS path might change it.
  25. */
  26. export function toPosixPath(osPath) {
  27. if (osPath.indexOf('/') === -1) {
  28. osPath = toSlashes(osPath);
  29. }
  30. if (/^[a-zA-Z]:(\/|$)/.test(osPath)) { // starts with a drive letter
  31. osPath = '/' + osPath;
  32. }
  33. return osPath;
  34. }
  35. /**
  36. * Computes the _root_ this path, like `getRoot('c:\files') === c:\`,
  37. * `getRoot('files:///files/path') === files:///`,
  38. * or `getRoot('\\server\shares\path') === \\server\shares\`
  39. */
  40. export function getRoot(path, sep = posix.sep) {
  41. if (!path) {
  42. return '';
  43. }
  44. const len = path.length;
  45. const firstLetter = path.charCodeAt(0);
  46. if (isPathSeparator(firstLetter)) {
  47. if (isPathSeparator(path.charCodeAt(1))) {
  48. // UNC candidate \\localhost\shares\ddd
  49. // ^^^^^^^^^^^^^^^^^^^
  50. if (!isPathSeparator(path.charCodeAt(2))) {
  51. let pos = 3;
  52. const start = pos;
  53. for (; pos < len; pos++) {
  54. if (isPathSeparator(path.charCodeAt(pos))) {
  55. break;
  56. }
  57. }
  58. if (start !== pos && !isPathSeparator(path.charCodeAt(pos + 1))) {
  59. pos += 1;
  60. for (; pos < len; pos++) {
  61. if (isPathSeparator(path.charCodeAt(pos))) {
  62. return path.slice(0, pos + 1) // consume this separator
  63. .replace(/[\\/]/g, sep);
  64. }
  65. }
  66. }
  67. }
  68. }
  69. // /user/far
  70. // ^
  71. return sep;
  72. }
  73. else if (isWindowsDriveLetter(firstLetter)) {
  74. // check for windows drive letter c:\ or c:
  75. if (path.charCodeAt(1) === 58 /* CharCode.Colon */) {
  76. if (isPathSeparator(path.charCodeAt(2))) {
  77. // C:\fff
  78. // ^^^
  79. return path.slice(0, 2) + sep;
  80. }
  81. else {
  82. // C:
  83. // ^^
  84. return path.slice(0, 2);
  85. }
  86. }
  87. }
  88. // check for URI
  89. // scheme://authority/path
  90. // ^^^^^^^^^^^^^^^^^^^
  91. let pos = path.indexOf('://');
  92. if (pos !== -1) {
  93. pos += 3; // 3 -> "://".length
  94. for (; pos < len; pos++) {
  95. if (isPathSeparator(path.charCodeAt(pos))) {
  96. return path.slice(0, pos + 1); // consume this separator
  97. }
  98. }
  99. }
  100. return '';
  101. }
  102. /**
  103. * @deprecated please use `IUriIdentityService.extUri.isEqualOrParent` instead. If
  104. * you are in a context without services, consider to pass down the `extUri` from the
  105. * outside, or use `extUriBiasedIgnorePathCase` if you know what you are doing.
  106. */
  107. export function isEqualOrParent(base, parentCandidate, ignoreCase, separator = sep) {
  108. if (base === parentCandidate) {
  109. return true;
  110. }
  111. if (!base || !parentCandidate) {
  112. return false;
  113. }
  114. if (parentCandidate.length > base.length) {
  115. return false;
  116. }
  117. if (ignoreCase) {
  118. const beginsWith = startsWithIgnoreCase(base, parentCandidate);
  119. if (!beginsWith) {
  120. return false;
  121. }
  122. if (parentCandidate.length === base.length) {
  123. return true; // same path, different casing
  124. }
  125. let sepOffset = parentCandidate.length;
  126. if (parentCandidate.charAt(parentCandidate.length - 1) === separator) {
  127. sepOffset--; // adjust the expected sep offset in case our candidate already ends in separator character
  128. }
  129. return base.charAt(sepOffset) === separator;
  130. }
  131. if (parentCandidate.charAt(parentCandidate.length - 1) !== separator) {
  132. parentCandidate += separator;
  133. }
  134. return base.indexOf(parentCandidate) === 0;
  135. }
  136. export function isWindowsDriveLetter(char0) {
  137. return char0 >= 65 /* CharCode.A */ && char0 <= 90 /* CharCode.Z */ || char0 >= 97 /* CharCode.a */ && char0 <= 122 /* CharCode.z */;
  138. }
  139. export function hasDriveLetter(path, isWindowsOS = isWindows) {
  140. if (isWindowsOS) {
  141. return isWindowsDriveLetter(path.charCodeAt(0)) && path.charCodeAt(1) === 58 /* CharCode.Colon */;
  142. }
  143. return false;
  144. }