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 /// | 6 /// |
7 /// ## Installing ## | 7 /// ## Installing ## |
8 /// | 8 /// |
9 /// Use [pub][] to install this package. Add the following to your | 9 /// Use [pub][] to install this package. Add the following to your |
10 /// `pubspec.yaml` file. | 10 /// `pubspec.yaml` file. |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 _builder.basenameWithoutExtension(path); | 99 _builder.basenameWithoutExtension(path); |
100 | 100 |
101 /// Gets the part of [path] before the last separator. | 101 /// Gets the part of [path] before the last separator. |
102 /// | 102 /// |
103 /// path.dirname('path/to/foo.dart'); // -> 'path/to' | 103 /// path.dirname('path/to/foo.dart'); // -> 'path/to' |
104 /// path.dirname('path/to'); // -> 'path' | 104 /// path.dirname('path/to'); // -> 'path' |
105 /// | 105 /// |
106 /// Trailing separators are ignored. | 106 /// Trailing separators are ignored. |
107 /// | 107 /// |
108 /// builder.dirname('path/to/'); // -> 'path' | 108 /// builder.dirname('path/to/'); // -> 'path' |
| 109 /// |
| 110 /// If an absolute path contains no directories, only a root, then the root |
| 111 /// is returned. |
| 112 /// |
| 113 /// path.dirname('/'); // -> '/' (posix) |
| 114 /// path.dirname('c:\'); // -> 'c:\' (windows) |
| 115 /// |
| 116 /// If a relative path has no directories, then '.' is returned. |
| 117 /// |
| 118 /// path.dirname('foo'); // -> '.' |
| 119 /// path.dirname(''); // -> '.' |
109 String dirname(String path) => _builder.dirname(path); | 120 String dirname(String path) => _builder.dirname(path); |
110 | 121 |
111 /// Gets the file extension of [path]: the portion of [basename] from the last | 122 /// Gets the file extension of [path]: the portion of [basename] from the last |
112 /// `.` to the end (including the `.` itself). | 123 /// `.` to the end (including the `.` itself). |
113 /// | 124 /// |
114 /// path.extension('path/to/foo.dart'); // -> '.dart' | 125 /// path.extension('path/to/foo.dart'); // -> '.dart' |
115 /// path.extension('path/to/foo'); // -> '' | 126 /// path.extension('path/to/foo'); // -> '' |
116 /// path.extension('path.to/foo'); // -> '' | 127 /// path.extension('path.to/foo'); // -> '' |
117 /// path.extension('path/to/foo.dart.js'); // -> '.js' | 128 /// path.extension('path/to/foo.dart.js'); // -> '.js' |
118 /// | 129 /// |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 /// path.relative('/root/path/a/b.dart'); // -> 'a/b.dart' | 252 /// path.relative('/root/path/a/b.dart'); // -> 'a/b.dart' |
242 /// path.relative('/root/other.dart'); // -> '../other.dart' | 253 /// path.relative('/root/other.dart'); // -> '../other.dart' |
243 /// | 254 /// |
244 /// If the [from] argument is passed, [path] is made relative to that instead. | 255 /// If the [from] argument is passed, [path] is made relative to that instead. |
245 /// | 256 /// |
246 /// path.relative('/root/path/a/b.dart', | 257 /// path.relative('/root/path/a/b.dart', |
247 /// from: '/root/path'); // -> 'a/b.dart' | 258 /// from: '/root/path'); // -> 'a/b.dart' |
248 /// path.relative('/root/other.dart', | 259 /// path.relative('/root/other.dart', |
249 /// from: '/root/path'); // -> '../other.dart' | 260 /// from: '/root/path'); // -> '../other.dart' |
250 /// | 261 /// |
| 262 /// If [path] and/or [from] are relative paths, they are assumed to be relative |
| 263 /// to the current directory. |
| 264 /// |
251 /// Since there is no relative path from one drive letter to another on Windows, | 265 /// Since there is no relative path from one drive letter to another on Windows, |
252 /// or from one hostname to another for URLs, this will return an absolute path | 266 /// or from one hostname to another for URLs, this will return an absolute path |
253 /// in those cases. | 267 /// in those cases. |
254 /// | 268 /// |
255 /// // Windows | 269 /// // Windows |
256 /// path.relative(r'D:\other', from: r'C:\home'); // -> 'D:\other' | 270 /// path.relative(r'D:\other', from: r'C:\home'); // -> 'D:\other' |
257 /// | 271 /// |
258 /// // URL | 272 /// // URL |
259 /// path.relative('http://dartlang.org', from: 'http://pub.dartlang.org'); | 273 /// path.relative('http://dartlang.org', from: 'http://pub.dartlang.org'); |
260 /// // -> 'http://dartlang.org' | 274 /// // -> 'http://dartlang.org' |
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 .toList(); | 589 .toList(); |
576 if (parsed.root != null) parsed.parts.insert(0, parsed.root); | 590 if (parsed.root != null) parsed.parts.insert(0, parsed.root); |
577 return parsed.parts; | 591 return parsed.parts; |
578 } | 592 } |
579 | 593 |
580 /// Normalizes [path], simplifying it by handling `..`, and `.`, and | 594 /// Normalizes [path], simplifying it by handling `..`, and `.`, and |
581 /// removing redundant path separators whenever possible. | 595 /// removing redundant path separators whenever possible. |
582 /// | 596 /// |
583 /// builder.normalize('path/./to/..//file.text'); // -> 'path/file.txt' | 597 /// builder.normalize('path/./to/..//file.text'); // -> 'path/file.txt' |
584 String normalize(String path) { | 598 String normalize(String path) { |
585 if (path == '') return path; | |
586 | |
587 var parsed = _parse(path); | 599 var parsed = _parse(path); |
588 parsed.normalize(); | 600 parsed.normalize(); |
589 return parsed.toString(); | 601 return parsed.toString(); |
590 } | 602 } |
591 | 603 |
592 /// Creates a new path by appending the given path parts to the [root]. | 604 /// Creates a new path by appending the given path parts to the [root]. |
593 /// Equivalent to [join()] with [root] as the first argument. Example: | 605 /// Equivalent to [join()] with [root] as the first argument. Example: |
594 /// | 606 /// |
595 /// var builder = new Builder(root: 'root'); | 607 /// var builder = new Builder(root: 'root'); |
596 /// builder.resolve('path', 'to', 'foo'); // -> 'root/path/to/foo' | 608 /// builder.resolve('path', 'to', 'foo'); // -> 'root/path/to/foo' |
597 String resolve(String part1, [String part2, String part3, String part4, | 609 String resolve(String part1, [String part2, String part3, String part4, |
598 String part5, String part6, String part7]) { | 610 String part5, String part6, String part7]) { |
599 return join(root, part1, part2, part3, part4, part5, part6, part7); | 611 return join(root, part1, part2, part3, part4, part5, part6, part7); |
600 } | 612 } |
601 | 613 |
602 /// Attempts to convert [path] to an equivalent relative path relative to | 614 /// Attempts to convert [path] to an equivalent relative path relative to |
603 /// [root]. | 615 /// [root]. |
604 /// | 616 /// |
605 /// var builder = new Builder(root: '/root/path'); | 617 /// var builder = new Builder(root: '/root/path'); |
606 /// builder.relative('/root/path/a/b.dart'); // -> 'a/b.dart' | 618 /// builder.relative('/root/path/a/b.dart'); // -> 'a/b.dart' |
607 /// builder.relative('/root/other.dart'); // -> '../other.dart' | 619 /// builder.relative('/root/other.dart'); // -> '../other.dart' |
608 /// | 620 /// |
609 /// If the [from] argument is passed, [path] is made relative to that instead. | 621 /// If the [from] argument is passed, [path] is made relative to that instead. |
610 /// | 622 /// |
611 /// builder.relative('/root/path/a/b.dart', | 623 /// builder.relative('/root/path/a/b.dart', |
612 /// from: '/root/path'); // -> 'a/b.dart' | 624 /// from: '/root/path'); // -> 'a/b.dart' |
613 /// builder.relative('/root/other.dart', | 625 /// builder.relative('/root/other.dart', |
614 /// from: '/root/path'); // -> '../other.dart' | 626 /// from: '/root/path'); // -> '../other.dart' |
615 /// | 627 /// |
| 628 /// If [path] and/or [from] are relative paths, they are assumed to be |
| 629 /// relative to [root]. |
| 630 /// |
616 /// Since there is no relative path from one drive letter to another on | 631 /// Since there is no relative path from one drive letter to another on |
617 /// Windows, this will return an absolute path in that case. | 632 /// Windows, this will return an absolute path in that case. |
618 /// | 633 /// |
619 /// builder.relative(r'D:\other', from: r'C:\other'); // -> 'D:\other' | 634 /// builder.relative(r'D:\other', from: r'C:\other'); // -> 'D:\other' |
620 /// | 635 /// |
621 /// This will also return an absolute path if an absolute [path] is passed to | 636 /// This will also return an absolute path if an absolute [path] is passed to |
622 /// a builder with a relative [root]. | 637 /// a builder with a relative [root]. |
623 /// | 638 /// |
624 /// var builder = new Builder(r'some/relative/path'); | 639 /// var builder = new Builder(r'some/relative/path'); |
625 /// builder.relative(r'/absolute/path'); // -> '/absolute/path' | 640 /// builder.relative(r'/absolute/path'); // -> '/absolute/path' |
626 String relative(String path, {String from}) { | 641 String relative(String path, {String from}) { |
627 if (path == '') return '.'; | |
628 | |
629 from = from == null ? root : this.join(root, from); | 642 from = from == null ? root : this.join(root, from); |
630 | 643 |
631 // We can't determine the path from a relative path to an absolute path. | 644 // We can't determine the path from a relative path to an absolute path. |
632 if (this.isRelative(from) && this.isAbsolute(path)) { | 645 if (this.isRelative(from) && this.isAbsolute(path)) { |
633 return this.normalize(path); | 646 return this.normalize(path); |
634 } | 647 } |
635 | 648 |
636 // If the given path is relative, resolve it relative to the root of the | 649 // If the given path is relative, resolve it relative to the root of the |
637 // builder. | 650 // builder. |
638 if (this.isRelative(path) || this.isRootRelative(path)) { | 651 if (this.isRelative(path) || this.isRootRelative(path)) { |
(...skipping 26 matching lines...) Expand all Loading... |
665 | 678 |
666 // Strip off their common prefix. | 679 // Strip off their common prefix. |
667 while (fromParsed.parts.length > 0 && pathParsed.parts.length > 0 && | 680 while (fromParsed.parts.length > 0 && pathParsed.parts.length > 0 && |
668 fromParsed.parts[0] == pathParsed.parts[0]) { | 681 fromParsed.parts[0] == pathParsed.parts[0]) { |
669 fromParsed.parts.removeAt(0); | 682 fromParsed.parts.removeAt(0); |
670 fromParsed.separators.removeAt(1); | 683 fromParsed.separators.removeAt(1); |
671 pathParsed.parts.removeAt(0); | 684 pathParsed.parts.removeAt(0); |
672 pathParsed.separators.removeAt(1); | 685 pathParsed.separators.removeAt(1); |
673 } | 686 } |
674 | 687 |
675 // If there are any directories left in the root path, we need to walk up | 688 // If there are any directories left in the from path, we need to walk up |
676 // out of them. | 689 // out of them. If a directory left in the from path is '..', it cannot |
| 690 // be cancelled by adding a '..'. |
| 691 if (fromParsed.parts.length > 0 && fromParsed.parts[0] == '..') { |
| 692 throw new ArgumentError('Unable to find a path to "$path" from "$from".'); |
| 693 } |
677 _growListFront(pathParsed.parts, fromParsed.parts.length, '..'); | 694 _growListFront(pathParsed.parts, fromParsed.parts.length, '..'); |
678 pathParsed.separators[0] = ''; | 695 pathParsed.separators[0] = ''; |
679 pathParsed.separators.insertAll(1, | 696 pathParsed.separators.insertAll(1, |
680 new List.filled(fromParsed.parts.length, style.separator)); | 697 new List.filled(fromParsed.parts.length, style.separator)); |
681 | 698 |
682 // Corner case: the paths completely collapsed. | 699 // Corner case: the paths completely collapsed. |
683 if (pathParsed.parts.length == 0) return '.'; | 700 if (pathParsed.parts.length == 0) return '.'; |
684 | 701 |
| 702 // Corner case: path was '.' and some '..' directories were added in front. |
| 703 // Don't add a final '/.' in that case. |
| 704 if (pathParsed.parts.length > 1 && pathParsed.parts.last == '.') { |
| 705 pathParsed.parts.removeLast(); |
| 706 pathParsed.separators..removeLast()..removeLast()..add(''); |
| 707 } |
| 708 |
685 // Make it relative. | 709 // Make it relative. |
686 pathParsed.root = ''; | 710 pathParsed.root = ''; |
687 pathParsed.removeTrailingSeparators(); | 711 pathParsed.removeTrailingSeparators(); |
688 | 712 |
689 return pathParsed.toString(); | 713 return pathParsed.toString(); |
690 } | 714 } |
691 | 715 |
692 /// Removes a trailing extension from the last part of [path]. | 716 /// Removes a trailing extension from the last part of [path]. |
693 /// | 717 /// |
694 /// builder.withoutExtension('path/to/foo.dart'); // -> 'path/to/foo' | 718 /// builder.withoutExtension('path/to/foo.dart'); // -> 'path/to/foo' |
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1035 return copy.parts.last; | 1059 return copy.parts.last; |
1036 } | 1060 } |
1037 | 1061 |
1038 String get basenameWithoutExtension { | 1062 String get basenameWithoutExtension { |
1039 var copy = this.clone(); | 1063 var copy = this.clone(); |
1040 copy.removeTrailingSeparators(); | 1064 copy.removeTrailingSeparators(); |
1041 if (copy.parts.isEmpty) return root == null ? '' : root; | 1065 if (copy.parts.isEmpty) return root == null ? '' : root; |
1042 return copy._splitExtension()[0]; | 1066 return copy._splitExtension()[0]; |
1043 } | 1067 } |
1044 | 1068 |
1045 bool get hasTrailingSeparator => !parts.isEmpty && (parts.last == '' || separa
tors.last != ''); | 1069 bool get hasTrailingSeparator => |
| 1070 !parts.isEmpty && (parts.last == '' || separators.last != ''); |
1046 | 1071 |
1047 void removeTrailingSeparators() { | 1072 void removeTrailingSeparators() { |
1048 while (!parts.isEmpty && parts.last == '') { | 1073 while (!parts.isEmpty && parts.last == '') { |
1049 parts.removeLast(); | 1074 parts.removeLast(); |
1050 separators.removeLast(); | 1075 separators.removeLast(); |
1051 } | 1076 } |
1052 if (separators.length > 0) separators[separators.length - 1] = ''; | 1077 if (separators.length > 0) separators[separators.length - 1] = ''; |
1053 } | 1078 } |
1054 | 1079 |
1055 void normalize() { | 1080 void normalize() { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1127 // doesn't count. | 1152 // doesn't count. |
1128 if (lastDot <= 0) return [file, '']; | 1153 if (lastDot <= 0) return [file, '']; |
1129 | 1154 |
1130 return [file.substring(0, lastDot), file.substring(lastDot)]; | 1155 return [file.substring(0, lastDot), file.substring(lastDot)]; |
1131 } | 1156 } |
1132 | 1157 |
1133 _ParsedPath clone() => new _ParsedPath( | 1158 _ParsedPath clone() => new _ParsedPath( |
1134 style, root, isRootRelative, | 1159 style, root, isRootRelative, |
1135 new List.from(parts), new List.from(separators)); | 1160 new List.from(parts), new List.from(separators)); |
1136 } | 1161 } |
OLD | NEW |