UNPKG

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