UNPKG

6.36 kBJavaScriptView Raw
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22// resolves . and .. elements in a path array with directory names there
23// must be no slashes, empty elements, or device names (c:\) in the array
24// (so also no leading and trailing slashes - it does not distinguish
25// relative and absolute paths)
26function normalizeArray(parts, allowAboveRoot) {
27 // if the path tries to go above the root, `up` ends up > 0
28 var up = 0;
29 for (var i = parts.length - 1; i >= 0; i--) {
30 var last = parts[i];
31 if (last === '.') {
32 parts.splice(i, 1);
33 } else if (last === '..') {
34 parts.splice(i, 1);
35 up++;
36 } else if (up) {
37 parts.splice(i, 1);
38 up--;
39 }
40 }
41
42 // if the path is allowed to go above the root, restore leading ..s
43 if (allowAboveRoot) {
44 for (; up--; up) {
45 parts.unshift('..');
46 }
47 }
48
49 return parts;
50}
51
52// Split a filename into [root, dir, basename, ext], unix version
53// 'root' is just a slash, or nothing.
54var splitPathRe =
55 /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
56var splitPath = function(filename) {
57 return splitPathRe.exec(filename).slice(1);
58};
59
60// path.resolve([from ...], to)
61// posix version
62export function resolve() {
63 var resolvedPath = '',
64 resolvedAbsolute = false;
65
66 for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
67 var path = (i >= 0) ? arguments[i] : '/';
68
69 // Skip empty and invalid entries
70 if (typeof path !== 'string') {
71 throw new TypeError('Arguments to path.resolve must be strings');
72 } else if (!path) {
73 continue;
74 }
75
76 resolvedPath = path + '/' + resolvedPath;
77 resolvedAbsolute = path.charAt(0) === '/';
78 }
79
80 // At this point the path should be resolved to a full absolute path, but
81 // handle relative paths to be safe (might happen when process.cwd() fails)
82
83 // Normalize the path
84 resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
85 return !!p;
86 }), !resolvedAbsolute).join('/');
87
88 return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
89};
90
91// path.normalize(path)
92// posix version
93export function normalize(path) {
94 var isPathAbsolute = isAbsolute(path),
95 trailingSlash = substr(path, -1) === '/';
96
97 // Normalize the path
98 path = normalizeArray(filter(path.split('/'), function(p) {
99 return !!p;
100 }), !isPathAbsolute).join('/');
101
102 if (!path && !isPathAbsolute) {
103 path = '.';
104 }
105 if (path && trailingSlash) {
106 path += '/';
107 }
108
109 return (isPathAbsolute ? '/' : '') + path;
110};
111
112// posix version
113export function isAbsolute(path) {
114 return path.charAt(0) === '/';
115}
116
117// posix version
118export function join() {
119 var paths = Array.prototype.slice.call(arguments, 0);
120 return normalize(filter(paths, function(p, index) {
121 if (typeof p !== 'string') {
122 throw new TypeError('Arguments to path.join must be strings');
123 }
124 return p;
125 }).join('/'));
126}
127
128
129// path.relative(from, to)
130// posix version
131export function relative(from, to) {
132 from = resolve(from).substr(1);
133 to = resolve(to).substr(1);
134
135 function trim(arr) {
136 var start = 0;
137 for (; start < arr.length; start++) {
138 if (arr[start] !== '') break;
139 }
140
141 var end = arr.length - 1;
142 for (; end >= 0; end--) {
143 if (arr[end] !== '') break;
144 }
145
146 if (start > end) return [];
147 return arr.slice(start, end - start + 1);
148 }
149
150 var fromParts = trim(from.split('/'));
151 var toParts = trim(to.split('/'));
152
153 var length = Math.min(fromParts.length, toParts.length);
154 var samePartsLength = length;
155 for (var i = 0; i < length; i++) {
156 if (fromParts[i] !== toParts[i]) {
157 samePartsLength = i;
158 break;
159 }
160 }
161
162 var outputParts = [];
163 for (var i = samePartsLength; i < fromParts.length; i++) {
164 outputParts.push('..');
165 }
166
167 outputParts = outputParts.concat(toParts.slice(samePartsLength));
168
169 return outputParts.join('/');
170}
171
172export var sep = '/';
173export var delimiter = ':';
174
175export function dirname(path) {
176 var result = splitPath(path),
177 root = result[0],
178 dir = result[1];
179
180 if (!root && !dir) {
181 // No dirname whatsoever
182 return '.';
183 }
184
185 if (dir) {
186 // It has a dirname, strip trailing slash
187 dir = dir.substr(0, dir.length - 1);
188 }
189
190 return root + dir;
191}
192
193export function basename(path, ext) {
194 var f = splitPath(path)[2];
195 // TODO: make this comparison case-insensitive on windows?
196 if (ext && f.substr(-1 * ext.length) === ext) {
197 f = f.substr(0, f.length - ext.length);
198 }
199 return f;
200}
201
202
203export function extname(path) {
204 return splitPath(path)[3];
205}
206export default {
207 extname: extname,
208 basename: basename,
209 dirname: dirname,
210 sep: sep,
211 delimiter: delimiter,
212 relative: relative,
213 join: join,
214 isAbsolute: isAbsolute,
215 normalize: normalize,
216 resolve: resolve
217};
218function filter (xs, f) {
219 if (xs.filter) return xs.filter(f);
220 var res = [];
221 for (var i = 0; i < xs.length; i++) {
222 if (f(xs[i], i, xs)) res.push(xs[i]);
223 }
224 return res;
225}
226
227// String.prototype.substr - negative index don't work in IE8
228var substr = 'ab'.substr(-1) === 'b' ?
229 function (str, start, len) { return str.substr(start, len) } :
230 function (str, start, len) {
231 if (start < 0) start = str.length + start;
232 return str.substr(start, len);
233 }
234;