index.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. // 'path' module extracted from Node.js v8.11.1 (only the posix part)
  2. // transplited with Babel
  3. // Copyright Joyent, Inc. and other Node contributors.
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a
  6. // copy of this software and associated documentation files (the
  7. // "Software"), to deal in the Software without restriction, including
  8. // without limitation the rights to use, copy, modify, merge, publish,
  9. // distribute, sublicense, and/or sell copies of the Software, and to permit
  10. // persons to whom the Software is furnished to do so, subject to the
  11. // following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included
  14. // in all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  19. // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  20. // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  21. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  22. // USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. 'use strict';
  24. function assertPath(path) {
  25. if (typeof path !== 'string') {
  26. throw new TypeError('Path must be a string. Received ' + JSON.stringify(path));
  27. }
  28. }
  29. // Resolves . and .. elements in a path with directory names
  30. function normalizeStringPosix(path, allowAboveRoot) {
  31. var res = '';
  32. var lastSegmentLength = 0;
  33. var lastSlash = -1;
  34. var dots = 0;
  35. var code;
  36. for (var i = 0; i <= path.length; ++i) {
  37. if (i < path.length)
  38. code = path.charCodeAt(i);
  39. else if (code === 47 /*/*/)
  40. break;
  41. else
  42. code = 47 /*/*/;
  43. if (code === 47 /*/*/) {
  44. if (lastSlash === i - 1 || dots === 1) {
  45. // NOOP
  46. } else if (lastSlash !== i - 1 && dots === 2) {
  47. if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== 46 /*.*/ || res.charCodeAt(res.length - 2) !== 46 /*.*/) {
  48. if (res.length > 2) {
  49. var lastSlashIndex = res.lastIndexOf('/');
  50. if (lastSlashIndex !== res.length - 1) {
  51. if (lastSlashIndex === -1) {
  52. res = '';
  53. lastSegmentLength = 0;
  54. } else {
  55. res = res.slice(0, lastSlashIndex);
  56. lastSegmentLength = res.length - 1 - res.lastIndexOf('/');
  57. }
  58. lastSlash = i;
  59. dots = 0;
  60. continue;
  61. }
  62. } else if (res.length === 2 || res.length === 1) {
  63. res = '';
  64. lastSegmentLength = 0;
  65. lastSlash = i;
  66. dots = 0;
  67. continue;
  68. }
  69. }
  70. if (allowAboveRoot) {
  71. if (res.length > 0)
  72. res += '/..';
  73. else
  74. res = '..';
  75. lastSegmentLength = 2;
  76. }
  77. } else {
  78. if (res.length > 0)
  79. res += '/' + path.slice(lastSlash + 1, i);
  80. else
  81. res = path.slice(lastSlash + 1, i);
  82. lastSegmentLength = i - lastSlash - 1;
  83. }
  84. lastSlash = i;
  85. dots = 0;
  86. } else if (code === 46 /*.*/ && dots !== -1) {
  87. ++dots;
  88. } else {
  89. dots = -1;
  90. }
  91. }
  92. return res;
  93. }
  94. function _format(sep, pathObject) {
  95. var dir = pathObject.dir || pathObject.root;
  96. var base = pathObject.base || (pathObject.name || '') + (pathObject.ext || '');
  97. if (!dir) {
  98. return base;
  99. }
  100. if (dir === pathObject.root) {
  101. return dir + base;
  102. }
  103. return dir + sep + base;
  104. }
  105. var posix = {
  106. // path.resolve([from ...], to)
  107. resolve: function resolve() {
  108. var resolvedPath = '';
  109. var resolvedAbsolute = false;
  110. var cwd;
  111. for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
  112. var path;
  113. if (i >= 0)
  114. path = arguments[i];
  115. else {
  116. if (cwd === undefined)
  117. cwd = process.cwd();
  118. path = cwd;
  119. }
  120. assertPath(path);
  121. // Skip empty entries
  122. if (path.length === 0) {
  123. continue;
  124. }
  125. resolvedPath = path + '/' + resolvedPath;
  126. resolvedAbsolute = path.charCodeAt(0) === 47 /*/*/;
  127. }
  128. // At this point the path should be resolved to a full absolute path, but
  129. // handle relative paths to be safe (might happen when process.cwd() fails)
  130. // Normalize the path
  131. resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute);
  132. if (resolvedAbsolute) {
  133. if (resolvedPath.length > 0)
  134. return '/' + resolvedPath;
  135. else
  136. return '/';
  137. } else if (resolvedPath.length > 0) {
  138. return resolvedPath;
  139. } else {
  140. return '.';
  141. }
  142. },
  143. normalize: function normalize(path) {
  144. assertPath(path);
  145. if (path.length === 0) return '.';
  146. var isAbsolute = path.charCodeAt(0) === 47 /*/*/;
  147. var trailingSeparator = path.charCodeAt(path.length - 1) === 47 /*/*/;
  148. // Normalize the path
  149. path = normalizeStringPosix(path, !isAbsolute);
  150. if (path.length === 0 && !isAbsolute) path = '.';
  151. if (path.length > 0 && trailingSeparator) path += '/';
  152. if (isAbsolute) return '/' + path;
  153. return path;
  154. },
  155. isAbsolute: function isAbsolute(path) {
  156. assertPath(path);
  157. return path.length > 0 && path.charCodeAt(0) === 47 /*/*/;
  158. },
  159. join: function join() {
  160. if (arguments.length === 0)
  161. return '.';
  162. var joined;
  163. for (var i = 0; i < arguments.length; ++i) {
  164. var arg = arguments[i];
  165. assertPath(arg);
  166. if (arg.length > 0) {
  167. if (joined === undefined)
  168. joined = arg;
  169. else
  170. joined += '/' + arg;
  171. }
  172. }
  173. if (joined === undefined)
  174. return '.';
  175. return posix.normalize(joined);
  176. },
  177. relative: function relative(from, to) {
  178. assertPath(from);
  179. assertPath(to);
  180. if (from === to) return '';
  181. from = posix.resolve(from);
  182. to = posix.resolve(to);
  183. if (from === to) return '';
  184. // Trim any leading backslashes
  185. var fromStart = 1;
  186. for (; fromStart < from.length; ++fromStart) {
  187. if (from.charCodeAt(fromStart) !== 47 /*/*/)
  188. break;
  189. }
  190. var fromEnd = from.length;
  191. var fromLen = fromEnd - fromStart;
  192. // Trim any leading backslashes
  193. var toStart = 1;
  194. for (; toStart < to.length; ++toStart) {
  195. if (to.charCodeAt(toStart) !== 47 /*/*/)
  196. break;
  197. }
  198. var toEnd = to.length;
  199. var toLen = toEnd - toStart;
  200. // Compare paths to find the longest common path from root
  201. var length = fromLen < toLen ? fromLen : toLen;
  202. var lastCommonSep = -1;
  203. var i = 0;
  204. for (; i <= length; ++i) {
  205. if (i === length) {
  206. if (toLen > length) {
  207. if (to.charCodeAt(toStart + i) === 47 /*/*/) {
  208. // We get here if `from` is the exact base path for `to`.
  209. // For example: from='/foo/bar'; to='/foo/bar/baz'
  210. return to.slice(toStart + i + 1);
  211. } else if (i === 0) {
  212. // We get here if `from` is the root
  213. // For example: from='/'; to='/foo'
  214. return to.slice(toStart + i);
  215. }
  216. } else if (fromLen > length) {
  217. if (from.charCodeAt(fromStart + i) === 47 /*/*/) {
  218. // We get here if `to` is the exact base path for `from`.
  219. // For example: from='/foo/bar/baz'; to='/foo/bar'
  220. lastCommonSep = i;
  221. } else if (i === 0) {
  222. // We get here if `to` is the root.
  223. // For example: from='/foo'; to='/'
  224. lastCommonSep = 0;
  225. }
  226. }
  227. break;
  228. }
  229. var fromCode = from.charCodeAt(fromStart + i);
  230. var toCode = to.charCodeAt(toStart + i);
  231. if (fromCode !== toCode)
  232. break;
  233. else if (fromCode === 47 /*/*/)
  234. lastCommonSep = i;
  235. }
  236. var out = '';
  237. // Generate the relative path based on the path difference between `to`
  238. // and `from`
  239. for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
  240. if (i === fromEnd || from.charCodeAt(i) === 47 /*/*/) {
  241. if (out.length === 0)
  242. out += '..';
  243. else
  244. out += '/..';
  245. }
  246. }
  247. // Lastly, append the rest of the destination (`to`) path that comes after
  248. // the common path parts
  249. if (out.length > 0)
  250. return out + to.slice(toStart + lastCommonSep);
  251. else {
  252. toStart += lastCommonSep;
  253. if (to.charCodeAt(toStart) === 47 /*/*/)
  254. ++toStart;
  255. return to.slice(toStart);
  256. }
  257. },
  258. _makeLong: function _makeLong(path) {
  259. return path;
  260. },
  261. dirname: function dirname(path) {
  262. assertPath(path);
  263. if (path.length === 0) return '.';
  264. var code = path.charCodeAt(0);
  265. var hasRoot = code === 47 /*/*/;
  266. var end = -1;
  267. var matchedSlash = true;
  268. for (var i = path.length - 1; i >= 1; --i) {
  269. code = path.charCodeAt(i);
  270. if (code === 47 /*/*/) {
  271. if (!matchedSlash) {
  272. end = i;
  273. break;
  274. }
  275. } else {
  276. // We saw the first non-path separator
  277. matchedSlash = false;
  278. }
  279. }
  280. if (end === -1) return hasRoot ? '/' : '.';
  281. if (hasRoot && end === 1) return '//';
  282. return path.slice(0, end);
  283. },
  284. basename: function basename(path, ext) {
  285. if (ext !== undefined && typeof ext !== 'string') throw new TypeError('"ext" argument must be a string');
  286. assertPath(path);
  287. var start = 0;
  288. var end = -1;
  289. var matchedSlash = true;
  290. var i;
  291. if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {
  292. if (ext.length === path.length && ext === path) return '';
  293. var extIdx = ext.length - 1;
  294. var firstNonSlashEnd = -1;
  295. for (i = path.length - 1; i >= 0; --i) {
  296. var code = path.charCodeAt(i);
  297. if (code === 47 /*/*/) {
  298. // If we reached a path separator that was not part of a set of path
  299. // separators at the end of the string, stop now
  300. if (!matchedSlash) {
  301. start = i + 1;
  302. break;
  303. }
  304. } else {
  305. if (firstNonSlashEnd === -1) {
  306. // We saw the first non-path separator, remember this index in case
  307. // we need it if the extension ends up not matching
  308. matchedSlash = false;
  309. firstNonSlashEnd = i + 1;
  310. }
  311. if (extIdx >= 0) {
  312. // Try to match the explicit extension
  313. if (code === ext.charCodeAt(extIdx)) {
  314. if (--extIdx === -1) {
  315. // We matched the extension, so mark this as the end of our path
  316. // component
  317. end = i;
  318. }
  319. } else {
  320. // Extension does not match, so our result is the entire path
  321. // component
  322. extIdx = -1;
  323. end = firstNonSlashEnd;
  324. }
  325. }
  326. }
  327. }
  328. if (start === end) end = firstNonSlashEnd;else if (end === -1) end = path.length;
  329. return path.slice(start, end);
  330. } else {
  331. for (i = path.length - 1; i >= 0; --i) {
  332. if (path.charCodeAt(i) === 47 /*/*/) {
  333. // If we reached a path separator that was not part of a set of path
  334. // separators at the end of the string, stop now
  335. if (!matchedSlash) {
  336. start = i + 1;
  337. break;
  338. }
  339. } else if (end === -1) {
  340. // We saw the first non-path separator, mark this as the end of our
  341. // path component
  342. matchedSlash = false;
  343. end = i + 1;
  344. }
  345. }
  346. if (end === -1) return '';
  347. return path.slice(start, end);
  348. }
  349. },
  350. extname: function extname(path) {
  351. assertPath(path);
  352. var startDot = -1;
  353. var startPart = 0;
  354. var end = -1;
  355. var matchedSlash = true;
  356. // Track the state of characters (if any) we see before our first dot and
  357. // after any path separator we find
  358. var preDotState = 0;
  359. for (var i = path.length - 1; i >= 0; --i) {
  360. var code = path.charCodeAt(i);
  361. if (code === 47 /*/*/) {
  362. // If we reached a path separator that was not part of a set of path
  363. // separators at the end of the string, stop now
  364. if (!matchedSlash) {
  365. startPart = i + 1;
  366. break;
  367. }
  368. continue;
  369. }
  370. if (end === -1) {
  371. // We saw the first non-path separator, mark this as the end of our
  372. // extension
  373. matchedSlash = false;
  374. end = i + 1;
  375. }
  376. if (code === 46 /*.*/) {
  377. // If this is our first dot, mark it as the start of our extension
  378. if (startDot === -1)
  379. startDot = i;
  380. else if (preDotState !== 1)
  381. preDotState = 1;
  382. } else if (startDot !== -1) {
  383. // We saw a non-dot and non-path separator before our dot, so we should
  384. // have a good chance at having a non-empty extension
  385. preDotState = -1;
  386. }
  387. }
  388. if (startDot === -1 || end === -1 ||
  389. // We saw a non-dot character immediately before the dot
  390. preDotState === 0 ||
  391. // The (right-most) trimmed path component is exactly '..'
  392. preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
  393. return '';
  394. }
  395. return path.slice(startDot, end);
  396. },
  397. format: function format(pathObject) {
  398. if (pathObject === null || typeof pathObject !== 'object') {
  399. throw new TypeError('The "pathObject" argument must be of type Object. Received type ' + typeof pathObject);
  400. }
  401. return _format('/', pathObject);
  402. },
  403. parse: function parse(path) {
  404. assertPath(path);
  405. var ret = { root: '', dir: '', base: '', ext: '', name: '' };
  406. if (path.length === 0) return ret;
  407. var code = path.charCodeAt(0);
  408. var isAbsolute = code === 47 /*/*/;
  409. var start;
  410. if (isAbsolute) {
  411. ret.root = '/';
  412. start = 1;
  413. } else {
  414. start = 0;
  415. }
  416. var startDot = -1;
  417. var startPart = 0;
  418. var end = -1;
  419. var matchedSlash = true;
  420. var i = path.length - 1;
  421. // Track the state of characters (if any) we see before our first dot and
  422. // after any path separator we find
  423. var preDotState = 0;
  424. // Get non-dir info
  425. for (; i >= start; --i) {
  426. code = path.charCodeAt(i);
  427. if (code === 47 /*/*/) {
  428. // If we reached a path separator that was not part of a set of path
  429. // separators at the end of the string, stop now
  430. if (!matchedSlash) {
  431. startPart = i + 1;
  432. break;
  433. }
  434. continue;
  435. }
  436. if (end === -1) {
  437. // We saw the first non-path separator, mark this as the end of our
  438. // extension
  439. matchedSlash = false;
  440. end = i + 1;
  441. }
  442. if (code === 46 /*.*/) {
  443. // If this is our first dot, mark it as the start of our extension
  444. if (startDot === -1) startDot = i;else if (preDotState !== 1) preDotState = 1;
  445. } else if (startDot !== -1) {
  446. // We saw a non-dot and non-path separator before our dot, so we should
  447. // have a good chance at having a non-empty extension
  448. preDotState = -1;
  449. }
  450. }
  451. if (startDot === -1 || end === -1 ||
  452. // We saw a non-dot character immediately before the dot
  453. preDotState === 0 ||
  454. // The (right-most) trimmed path component is exactly '..'
  455. preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
  456. if (end !== -1) {
  457. if (startPart === 0 && isAbsolute) ret.base = ret.name = path.slice(1, end);else ret.base = ret.name = path.slice(startPart, end);
  458. }
  459. } else {
  460. if (startPart === 0 && isAbsolute) {
  461. ret.name = path.slice(1, startDot);
  462. ret.base = path.slice(1, end);
  463. } else {
  464. ret.name = path.slice(startPart, startDot);
  465. ret.base = path.slice(startPart, end);
  466. }
  467. ret.ext = path.slice(startDot, end);
  468. }
  469. if (startPart > 0) ret.dir = path.slice(0, startPart - 1);else if (isAbsolute) ret.dir = '/';
  470. return ret;
  471. },
  472. sep: '/',
  473. delimiter: ':',
  474. win32: null,
  475. posix: null
  476. };
  477. posix.posix = posix;
  478. module.exports = posix;