OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// A comprehensive, cross-platform path manipulation library. | 5 /// A comprehensive, cross-platform path manipulation library. |
6 library path; | 6 library path; |
7 | 7 |
8 import 'dart:io' as io; | 8 import 'dart:io' as io; |
9 | 9 |
10 /// An internal builder for the current OS so we can provide a straight | 10 /// An internal builder for the current OS so we can provide a straight |
(...skipping 19 matching lines...) Expand all Loading... |
30 /// path.basename('path/to'); // -> 'to' | 30 /// path.basename('path/to'); // -> 'to' |
31 String basename(String path) => _builder.basename(path); | 31 String basename(String path) => _builder.basename(path); |
32 | 32 |
33 /// Gets the part of [path] after the last separator, and without any trailing | 33 /// Gets the part of [path] after the last separator, and without any trailing |
34 /// file extension. | 34 /// file extension. |
35 /// | 35 /// |
36 /// path.basenameWithoutExtension('path/to/foo.dart'); // -> 'foo' | 36 /// path.basenameWithoutExtension('path/to/foo.dart'); // -> 'foo' |
37 String basenameWithoutExtension(String path) => | 37 String basenameWithoutExtension(String path) => |
38 _builder.basenameWithoutExtension(path); | 38 _builder.basenameWithoutExtension(path); |
39 | 39 |
| 40 /// Gets the part of [path] before the last separator. |
| 41 /// |
| 42 /// path.dirname('path/to/foo.dart'); // -> 'path/to' |
| 43 /// path.dirname('path/to'); // -> 'to' |
| 44 String dirname(String path) => _builder.dirname(path); |
| 45 |
40 /// Gets the file extension of [path]: the portion of [basename] from the last | 46 /// Gets the file extension of [path]: the portion of [basename] from the last |
41 /// `.` to the end (including the `.` itself). | 47 /// `.` to the end (including the `.` itself). |
42 /// | 48 /// |
43 /// path.extension('path/to/foo.dart'); // -> '.dart' | 49 /// path.extension('path/to/foo.dart'); // -> '.dart' |
44 /// path.extension('path/to/foo'); // -> '' | 50 /// path.extension('path/to/foo'); // -> '' |
45 /// path.extension('path.to/foo'); // -> '' | 51 /// path.extension('path.to/foo'); // -> '' |
46 /// path.extension('path/to/foo.dart.js'); // -> '.js' | 52 /// path.extension('path/to/foo.dart.js'); // -> '.js' |
47 /// | 53 /// |
48 /// If the file name starts with a `.`, then that is not considered the | 54 /// If the file name starts with a `.`, then that is not considered the |
49 /// extension: | 55 /// extension: |
50 /// | 56 /// |
51 /// path.extension('~/.bashrc'); // -> '' | 57 /// path.extension('~/.bashrc'); // -> '' |
52 /// path.extension('~/.notes.txt'); // -> '.txt' | 58 /// path.extension('~/.notes.txt'); // -> '.txt' |
53 String extension(String path) => _builder.extension(path); | 59 String extension(String path) => _builder.extension(path); |
54 | 60 |
| 61 // TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed. |
| 62 /// Returns the root of [path], if it's absolute, or the empty string if it's |
| 63 /// relative. |
| 64 /// |
| 65 /// // Unix |
| 66 /// path.rootPrefix('path/to/foo'); // -> '' |
| 67 /// path.rootPrefix('/path/to/foo'); // -> '/' |
| 68 /// |
| 69 /// // Windows |
| 70 /// path.rootPrefix(r'path\to\foo'); // -> '' |
| 71 /// path.rootPrefix(r'C:\path\to\foo'); // -> r'C:\' |
| 72 String rootPrefix(String path) => _builder.rootPrefix(path); |
| 73 |
55 /// Returns `true` if [path] is an absolute path and `false` if it is a | 74 /// Returns `true` if [path] is an absolute path and `false` if it is a |
56 /// relative path. On POSIX systems, absolute paths start with a `/` (forward | 75 /// relative path. On POSIX systems, absolute paths start with a `/` (forward |
57 /// slash). On Windows, an absolute path starts with `\\`, or a drive letter | 76 /// slash). On Windows, an absolute path starts with `\\`, or a drive letter |
58 /// followed by `:/` or `:\`. | 77 /// followed by `:/` or `:\`. |
59 bool isAbsolute(String path) => _builder.isAbsolute(path); | 78 bool isAbsolute(String path) => _builder.isAbsolute(path); |
60 | 79 |
61 /// Returns `true` if [path] is a relative path and `false` if it is absolute. | 80 /// Returns `true` if [path] is a relative path and `false` if it is absolute. |
62 /// On POSIX systems, absolute paths start with a `/` (forward slash). On | 81 /// On POSIX systems, absolute paths start with a `/` (forward slash). On |
63 /// Windows, an absolute path starts with `\\`, or a drive letter followed by | 82 /// Windows, an absolute path starts with `\\`, or a drive letter followed by |
64 /// `:/` or `:\`. | 83 /// `:/` or `:\`. |
65 bool isRelative(String path) => _builder.isRelative(path); | 84 bool isRelative(String path) => _builder.isRelative(path); |
66 | 85 |
67 /// Joins the given path parts into a single path using the current platform's | 86 /// Joins the given path parts into a single path using the current platform's |
68 /// [separator]. Example: | 87 /// [separator]. Example: |
69 /// | 88 /// |
70 /// path.join('path', 'to', 'foo'); // -> 'path/to/foo' | 89 /// path.join('path', 'to', 'foo'); // -> 'path/to/foo' |
71 /// | 90 /// |
72 /// If any part ends in a path separator, then a redundant separator will not | 91 /// If any part ends in a path separator, then a redundant separator will not |
73 /// be added: | 92 /// be added: |
74 /// | 93 /// |
75 /// path.join('path/', 'to', 'foo'); // -> 'path/to/foo | 94 /// path.join('path/', 'to', 'foo'); // -> 'path/to/foo |
76 /// | 95 /// |
77 /// If a part is an absolute path, then anything before that will be ignored: | 96 /// If a part is an absolute path, then anything before that will be ignored: |
78 /// | 97 /// |
79 /// path.join('path', '/to', 'foo'); // -> '/to/foo' | 98 /// path.join('path', '/to', 'foo'); // -> '/to/foo' |
80 String join(String part1, [String part2, String part3, String part4, | 99 String join(String part1, [String part2, String part3, String part4, |
81 String part5, String part6, String part7, String part8]) { | 100 String part5, String part6, String part7, String part8]) => |
82 if (!?part2) return _builder.join(part1); | 101 _builder.join(part1, part2, part3, part4, part5, part6, part7, part8); |
83 if (!?part3) return _builder.join(part1, part2); | 102 |
84 if (!?part4) return _builder.join(part1, part2, part3); | 103 // TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed. |
85 if (!?part5) return _builder.join(part1, part2, part3, part4); | 104 /// Splits [path] into its components using the current platform's [separator]. |
86 if (!?part6) return _builder.join(part1, part2, part3, part4, part5); | 105 /// Example: |
87 if (!?part7) return _builder.join(part1, part2, part3, part4, part5, part6); | 106 /// |
88 if (!?part8) return _builder.join(part1, part2, part3, part4, part5, part6, | 107 /// path.split('path/to/foo'); // -> ['path', 'to', 'foo'] |
89 part7); | 108 /// |
90 return _builder.join(part1, part2, part3, part4, part5, part6, part7, part8); | 109 /// If [path] is absolute, the root directory will be the first element in the |
91 } | 110 /// array. Example: |
| 111 /// |
| 112 /// // Unix |
| 113 /// path.split('/path/to/foo'); // -> ['/', 'path', 'to', 'foo'] |
| 114 /// |
| 115 /// // Windows |
| 116 /// path.split(r'C:\path\to\foo'); // -> [r'C:\', 'path', 'to', 'foo'] |
| 117 List<String> split(String path) => _builder.split(path); |
92 | 118 |
93 /// Normalizes [path], simplifying it by handling `..`, and `.`, and | 119 /// Normalizes [path], simplifying it by handling `..`, and `.`, and |
94 /// removing redundant path separators whenever possible. | 120 /// removing redundant path separators whenever possible. |
95 /// | 121 /// |
96 /// path.normalize('path/./to/..//file.text'); // -> 'path/file.txt' | 122 /// path.normalize('path/./to/..//file.text'); // -> 'path/file.txt' |
97 String normalize(String path) => _builder.normalize(path); | 123 String normalize(String path) => _builder.normalize(path); |
98 | 124 |
99 /// Attempts to convert [path] to an equivalent relative path from the current | 125 /// Attempts to convert [path] to an equivalent relative path from the current |
100 /// directory. | 126 /// directory. |
101 /// | 127 /// |
102 /// // Given current directory is /root/path: | 128 /// // Given current directory is /root/path: |
103 /// path.relative('/root/path/a/b.dart'); // -> 'a/b.dart' | 129 /// path.relative('/root/path/a/b.dart'); // -> 'a/b.dart' |
104 /// path.relative('/root/other.dart'); // -> '../other.dart' | 130 /// path.relative('/root/other.dart'); // -> '../other.dart' |
105 /// | 131 /// |
| 132 /// If the [from] argument is passed, [path] is made relative to that instead. |
| 133 /// |
| 134 /// path.relative('/root/path/a/b.dart', |
| 135 /// from: '/root/path'); // -> 'a/b.dart' |
| 136 /// path.relative('/root/other.dart', |
| 137 /// from: '/root/path'); // -> '../other.dart' |
| 138 /// |
106 /// Since there is no relative path from one drive letter to another on Windows, | 139 /// Since there is no relative path from one drive letter to another on Windows, |
107 /// this will return an absolute path in that case. | 140 /// this will return an absolute path in that case. |
108 /// | 141 /// |
109 /// // Given current directory is C:\home: | 142 /// path.relative(r'D:\other', from: r'C:\home'); // -> 'D:\other' |
110 /// path.relative(r'D:\other'); // -> 'D:\other' | 143 String relative(String path, {String from}) => |
111 String relative(String path) => _builder.relative(path); | 144 _builder.relative(path, from: from); |
112 | 145 |
113 /// Removes a trailing extension from the last part of [path]. | 146 /// Removes a trailing extension from the last part of [path]. |
114 /// | 147 /// |
115 /// withoutExtension('path/to/foo.dart'); // -> 'path/to/foo' | 148 /// withoutExtension('path/to/foo.dart'); // -> 'path/to/foo' |
116 String withoutExtension(String path) => _builder.withoutExtension(path); | 149 String withoutExtension(String path) => _builder.withoutExtension(path); |
117 | 150 |
118 /// An instantiable class for manipulating paths. Unlike the top-level | 151 /// An instantiable class for manipulating paths. Unlike the top-level |
119 /// functions, this lets you explicitly select what platform the paths will use. | 152 /// functions, this lets you explicitly select what platform the paths will use. |
120 class Builder { | 153 class Builder { |
121 /// Creates a new path builder for the given style and root directory. | 154 /// Creates a new path builder for the given style and root directory. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 /// builder.basename('path/to'); // -> 'to' | 189 /// builder.basename('path/to'); // -> 'to' |
157 String basename(String path) => _parse(path).basename; | 190 String basename(String path) => _parse(path).basename; |
158 | 191 |
159 /// Gets the part of [path] after the last separator on the builder's | 192 /// Gets the part of [path] after the last separator on the builder's |
160 /// platform, and without any trailing file extension. | 193 /// platform, and without any trailing file extension. |
161 /// | 194 /// |
162 /// builder.basenameWithoutExtension('path/to/foo.dart'); // -> 'foo' | 195 /// builder.basenameWithoutExtension('path/to/foo.dart'); // -> 'foo' |
163 String basenameWithoutExtension(String path) => | 196 String basenameWithoutExtension(String path) => |
164 _parse(path).basenameWithoutExtension; | 197 _parse(path).basenameWithoutExtension; |
165 | 198 |
| 199 /// Gets the part of [path] before the last separator. |
| 200 /// |
| 201 /// builder.dirname('path/to/foo.dart'); // -> 'path/to' |
| 202 /// builder.dirname('path/to'); // -> 'to' |
| 203 String dirname(String path) { |
| 204 var parsed = _parse(path); |
| 205 if (parsed.parts.isEmpty) return parsed.root == null ? '.' : parsed.root; |
| 206 if (!parsed.hasTrailingSeparator) { |
| 207 if (parsed.parts.length == 1) { |
| 208 return parsed.root == null ? '.' : parsed.root; |
| 209 } |
| 210 parsed.parts.removeLast(); |
| 211 parsed.separators.removeLast(); |
| 212 } |
| 213 parsed.separators[parsed.separators.length - 1] = ''; |
| 214 return parsed.toString(); |
| 215 } |
| 216 |
166 /// Gets the file extension of [path]: the portion of [basename] from the last | 217 /// Gets the file extension of [path]: the portion of [basename] from the last |
167 /// `.` to the end (including the `.` itself). | 218 /// `.` to the end (including the `.` itself). |
168 /// | 219 /// |
169 /// builder.extension('path/to/foo.dart'); // -> '.dart' | 220 /// builder.extension('path/to/foo.dart'); // -> '.dart' |
170 /// builder.extension('path/to/foo'); // -> '' | 221 /// builder.extension('path/to/foo'); // -> '' |
171 /// builder.extension('path.to/foo'); // -> '' | 222 /// builder.extension('path.to/foo'); // -> '' |
172 /// builder.extension('path/to/foo.dart.js'); // -> '.js' | 223 /// builder.extension('path/to/foo.dart.js'); // -> '.js' |
173 /// | 224 /// |
174 /// If the file name starts with a `.`, then it is not considered an | 225 /// If the file name starts with a `.`, then it is not considered an |
175 /// extension: | 226 /// extension: |
176 /// | 227 /// |
177 /// builder.extension('~/.bashrc'); // -> '' | 228 /// builder.extension('~/.bashrc'); // -> '' |
178 /// builder.extension('~/.notes.txt'); // -> '.txt' | 229 /// builder.extension('~/.notes.txt'); // -> '.txt' |
179 String extension(String path) => _parse(path).extension; | 230 String extension(String path) => _parse(path).extension; |
180 | 231 |
| 232 // TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed. |
| 233 /// Returns the root of [path], if it's absolute, or an empty string if it's |
| 234 /// relative. |
| 235 /// |
| 236 /// // Unix |
| 237 /// builder.rootPrefix('path/to/foo'); // -> '' |
| 238 /// builder.rootPrefix('/path/to/foo'); // -> '/' |
| 239 /// |
| 240 /// // Windows |
| 241 /// builder.rootPrefix(r'path\to\foo'); // -> '' |
| 242 /// builder.rootPrefix(r'C:\path\to\foo'); // -> r'C:\' |
| 243 String rootPrefix(String path) { |
| 244 var root = _parse(path).root; |
| 245 return root == null ? '' : root; |
| 246 } |
| 247 |
181 /// Returns `true` if [path] is an absolute path and `false` if it is a | 248 /// Returns `true` if [path] is an absolute path and `false` if it is a |
182 /// relative path. On POSIX systems, absolute paths start with a `/` (forward | 249 /// relative path. On POSIX systems, absolute paths start with a `/` (forward |
183 /// slash). On Windows, an absolute path starts with `\\`, or a drive letter | 250 /// slash). On Windows, an absolute path starts with `\\`, or a drive letter |
184 /// followed by `:/` or `:\`. | 251 /// followed by `:/` or `:\`. |
185 bool isAbsolute(String path) => _parse(path).isAbsolute; | 252 bool isAbsolute(String path) => _parse(path).isAbsolute; |
186 | 253 |
187 /// Returns `true` if [path] is a relative path and `false` if it is absolute. | 254 /// Returns `true` if [path] is a relative path and `false` if it is absolute. |
188 /// On POSIX systems, absolute paths start with a `/` (forward slash). On | 255 /// On POSIX systems, absolute paths start with a `/` (forward slash). On |
189 /// Windows, an absolute path starts with `\\`, or a drive letter followed by | 256 /// Windows, an absolute path starts with `\\`, or a drive letter followed by |
190 /// `:/` or `:\`. | 257 /// `:/` or `:\`. |
(...skipping 10 matching lines...) Expand all Loading... |
201 /// | 268 /// |
202 /// If a part is an absolute path, then anything before that will be ignored: | 269 /// If a part is an absolute path, then anything before that will be ignored: |
203 /// | 270 /// |
204 /// builder.join('path', '/to', 'foo'); // -> '/to/foo' | 271 /// builder.join('path', '/to', 'foo'); // -> '/to/foo' |
205 /// | 272 /// |
206 String join(String part1, [String part2, String part3, String part4, | 273 String join(String part1, [String part2, String part3, String part4, |
207 String part5, String part6, String part7, String part8]) { | 274 String part5, String part6, String part7, String part8]) { |
208 var buffer = new StringBuffer(); | 275 var buffer = new StringBuffer(); |
209 var needsSeparator = false; | 276 var needsSeparator = false; |
210 | 277 |
211 addPart(condition, part) { | 278 var parts = [part1, part2, part3, part4, part5, part6, part7, part8]; |
212 if (!condition) return; | 279 for (var i = 1; i < parts.length; i++) { |
| 280 if (parts[i] != null && parts[i - 1] == null) { |
| 281 throw new ArgumentError("join(): part ${i - 1} was null, but part $i " |
| 282 "was not."); |
| 283 } |
| 284 } |
| 285 |
| 286 for (var part in parts) { |
| 287 if (part == null) continue; |
213 | 288 |
214 if (this.isAbsolute(part)) { | 289 if (this.isAbsolute(part)) { |
215 // An absolute path discards everything before it. | 290 // An absolute path discards everything before it. |
216 buffer.clear(); | 291 buffer.clear(); |
217 buffer.add(part); | 292 buffer.add(part); |
218 } else { | 293 } else { |
219 if (part.length > 0 && style.separatorPattern.hasMatch(part[0])) { | 294 if (part.length > 0 && style.separatorPattern.hasMatch(part[0])) { |
220 // The part starts with a separator, so we don't need to add one. | 295 // The part starts with a separator, so we don't need to add one. |
221 } else if (needsSeparator) { | 296 } else if (needsSeparator) { |
222 buffer.add(separator); | 297 buffer.add(separator); |
223 } | 298 } |
224 | 299 |
225 buffer.add(part); | 300 buffer.add(part); |
226 } | 301 } |
227 | 302 |
228 // Unless this part ends with a separator, we'll need to add one before | 303 // Unless this part ends with a separator, we'll need to add one before |
229 // the next part. | 304 // the next part. |
230 needsSeparator = part.length > 0 && | 305 needsSeparator = part.length > 0 && |
231 !style.separatorPattern.hasMatch(part[part.length - 1]); | 306 !style.separatorPattern.hasMatch(part[part.length - 1]); |
232 } | 307 } |
233 | 308 |
234 addPart(true, part1); | 309 return buffer.toString(); |
235 addPart(?part2, part2); | 310 } |
236 addPart(?part3, part3); | |
237 addPart(?part4, part4); | |
238 addPart(?part5, part5); | |
239 addPart(?part6, part6); | |
240 addPart(?part7, part7); | |
241 addPart(?part8, part8); | |
242 | 311 |
243 return buffer.toString(); | 312 // TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed. |
| 313 /// Splits [path] into its components using the current platform's |
| 314 /// [separator]. Example: |
| 315 /// |
| 316 /// builder.split('path/to/foo'); // -> ['path', 'to', 'foo'] |
| 317 /// |
| 318 /// If [path] is absolute, the root directory will be the first element in the |
| 319 /// array. Example: |
| 320 /// |
| 321 /// // Unix |
| 322 /// builder.split('/path/to/foo'); // -> ['/', 'path', 'to', 'foo'] |
| 323 /// |
| 324 /// // Windows |
| 325 /// builder.split(r'C:\path\to\foo'); // -> [r'C:\', 'path', 'to', 'foo'] |
| 326 List<String> split(String path) { |
| 327 var parsed = _parse(path); |
| 328 // Filter out empty parts that exist due to multiple separators in a row. |
| 329 parsed.parts = parsed.parts.filter((part) => part != ''); |
| 330 if (parsed.root != null) parsed.parts.insertRange(0, 1, parsed.root); |
| 331 return parsed.parts; |
244 } | 332 } |
245 | 333 |
246 /// Normalizes [path], simplifying it by handling `..`, and `.`, and | 334 /// Normalizes [path], simplifying it by handling `..`, and `.`, and |
247 /// removing redundant path separators whenever possible. | 335 /// removing redundant path separators whenever possible. |
248 /// | 336 /// |
249 /// builder.normalize('path/./to/..//file.text'); // -> 'path/file.txt' | 337 /// builder.normalize('path/./to/..//file.text'); // -> 'path/file.txt' |
250 String normalize(String path) { | 338 String normalize(String path) { |
251 if (path == '') return path; | 339 if (path == '') return path; |
252 | 340 |
253 var parsed = _parse(path); | 341 var parsed = _parse(path); |
(...skipping 17 matching lines...) Expand all Loading... |
271 return join(root, part1, part2, part3, part4, part5, part6, part7); | 359 return join(root, part1, part2, part3, part4, part5, part6, part7); |
272 } | 360 } |
273 | 361 |
274 /// Attempts to convert [path] to an equivalent relative path relative to | 362 /// Attempts to convert [path] to an equivalent relative path relative to |
275 /// [root]. | 363 /// [root]. |
276 /// | 364 /// |
277 /// var builder = new Builder(root: '/root/path'); | 365 /// var builder = new Builder(root: '/root/path'); |
278 /// builder.relative('/root/path/a/b.dart'); // -> 'a/b.dart' | 366 /// builder.relative('/root/path/a/b.dart'); // -> 'a/b.dart' |
279 /// builder.relative('/root/other.dart'); // -> '../other.dart' | 367 /// builder.relative('/root/other.dart'); // -> '../other.dart' |
280 /// | 368 /// |
| 369 /// If the [from] argument is passed, [path] is made relative to that instead. |
| 370 /// |
| 371 /// builder.relative('/root/path/a/b.dart', |
| 372 /// from: '/root/path'); // -> 'a/b.dart' |
| 373 /// builder.relative('/root/other.dart', |
| 374 /// from: '/root/path'); // -> '../other.dart' |
| 375 /// |
281 /// Since there is no relative path from one drive letter to another on | 376 /// Since there is no relative path from one drive letter to another on |
282 /// Windows, this will return an absolute path in that case. | 377 /// Windows, this will return an absolute path in that case. |
283 /// | 378 /// |
284 /// var builder = new Builder(root: r'C:\home'); | 379 /// builder.relative(r'D:\other', from: r'C:\other'); // -> 'D:\other' |
285 /// builder.relative(r'D:\other'); // -> 'D:\other' | 380 /// |
286 String relative(String path) { | 381 /// This will also return an absolute path if an absolute [path] is passed to |
| 382 /// a builder with a relative [root]. |
| 383 /// |
| 384 /// var builder = new Builder(r'some/relative/path'); |
| 385 /// builder.relative(r'/absolute/path'); // -> '/absolute/path' |
| 386 String relative(String path, {String from}) { |
287 if (path == '') return '.'; | 387 if (path == '') return '.'; |
288 | 388 |
289 // If the base path is relative, resolve it relative to the current | 389 from = from == null ? root : this.join(root, from); |
290 // directory. | |
291 var base = root; | |
292 if (this.isRelative(base)) base = absolute(base); | |
293 | 390 |
294 // If the given path is relative, resolve it relative to the base. | 391 // We can't determine the path from a relative path to an absolute path. |
295 if (this.isRelative(path)) return this.normalize(path); | 392 if (this.isRelative(from) && this.isAbsolute(path)) { |
| 393 return this.normalize(path); |
| 394 } |
296 | 395 |
297 var baseParsed = _parse(base)..normalize(); | 396 // If the given path is relative, resolve it relative to the root of the |
| 397 // builder. |
| 398 if (this.isRelative(path)) path = this.resolve(path); |
| 399 |
| 400 // If the path is still relative and `from` is absolute, we're unable to |
| 401 // find a path from `from` to `path`. |
| 402 if (this.isRelative(path) && this.isAbsolute(from)) { |
| 403 throw new ArgumentError('Unable to find a path to "$path" from "$from".'); |
| 404 } |
| 405 |
| 406 var fromParsed = _parse(from)..normalize(); |
298 var pathParsed = _parse(path)..normalize(); | 407 var pathParsed = _parse(path)..normalize(); |
299 | 408 |
300 // If the root prefixes don't match (for example, different drive letters | 409 // If the root prefixes don't match (for example, different drive letters |
301 // on Windows), then there is no relative path, so just return the absolute | 410 // on Windows), then there is no relative path, so just return the absolute |
302 // one. | 411 // one. |
303 // TODO(rnystrom): Drive letters are case-insentive on Windows. Should | 412 // TODO(rnystrom): Drive letters are case-insentive on Windows. Should |
304 // handle "C:\" and "c:\" being the same root. | 413 // handle "C:\" and "c:\" being the same root. |
305 if (baseParsed.root != pathParsed.root) return pathParsed.toString(); | 414 if (fromParsed.root != pathParsed.root) return pathParsed.toString(); |
306 | 415 |
307 // Strip off their common prefix. | 416 // Strip off their common prefix. |
308 while (baseParsed.parts.length > 0 && pathParsed.parts.length > 0 && | 417 while (fromParsed.parts.length > 0 && pathParsed.parts.length > 0 && |
309 baseParsed.parts[0] == pathParsed.parts[0]) { | 418 fromParsed.parts[0] == pathParsed.parts[0]) { |
310 baseParsed.parts.removeAt(0); | 419 fromParsed.parts.removeAt(0); |
311 baseParsed.separators.removeAt(0); | 420 fromParsed.separators.removeAt(0); |
312 pathParsed.parts.removeAt(0); | 421 pathParsed.parts.removeAt(0); |
313 pathParsed.separators.removeAt(0); | 422 pathParsed.separators.removeAt(0); |
314 } | 423 } |
315 | 424 |
316 // If there are any directories left in the root path, we need to walk up | 425 // If there are any directories left in the root path, we need to walk up |
317 // out of them. | 426 // out of them. |
318 pathParsed.parts.insertRange(0, baseParsed.parts.length, '..'); | 427 pathParsed.parts.insertRange(0, fromParsed.parts.length, '..'); |
319 pathParsed.separators.insertRange(0, baseParsed.parts.length, | 428 pathParsed.separators.insertRange(0, fromParsed.parts.length, |
320 style.separator); | 429 style.separator); |
321 | 430 |
322 // Corner case: the paths completely collapsed. | 431 // Corner case: the paths completely collapsed. |
323 if (pathParsed.parts.length == 0) return '.'; | 432 if (pathParsed.parts.length == 0) return '.'; |
324 | 433 |
325 // Make it relative. | 434 // Make it relative. |
326 pathParsed.root = ''; | 435 pathParsed.root = ''; |
327 pathParsed.removeTrailingSeparator(); | 436 pathParsed.removeTrailingSeparator(); |
328 | 437 |
329 return pathParsed.toString(); | 438 return pathParsed.toString(); |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
526 | 635 |
527 var lastDot = file.lastIndexOf('.'); | 636 var lastDot = file.lastIndexOf('.'); |
528 | 637 |
529 // If there is no dot, or it's the first character, like '.bashrc', it | 638 // If there is no dot, or it's the first character, like '.bashrc', it |
530 // doesn't count. | 639 // doesn't count. |
531 if (lastDot <= 0) return [file, '']; | 640 if (lastDot <= 0) return [file, '']; |
532 | 641 |
533 return [file.substring(0, lastDot), file.substring(lastDot)]; | 642 return [file.substring(0, lastDot), file.substring(lastDot)]; |
534 } | 643 } |
535 } | 644 } |
OLD | NEW |