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 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
268 /// path.relative('http://dartlang.org', from: 'http://pub.dartlang.org'); | 268 /// path.relative('http://dartlang.org', from: 'http://pub.dartlang.org'); |
269 /// // -> 'http://dartlang.org' | 269 /// // -> 'http://dartlang.org' |
270 String relative(String path, {String from}) => | 270 String relative(String path, {String from}) => |
271 _builder.relative(path, from: from); | 271 _builder.relative(path, from: from); |
272 | 272 |
273 /// Removes a trailing extension from the last part of [path]. | 273 /// Removes a trailing extension from the last part of [path]. |
274 /// | 274 /// |
275 /// withoutExtension('path/to/foo.dart'); // -> 'path/to/foo' | 275 /// withoutExtension('path/to/foo.dart'); // -> 'path/to/foo' |
276 String withoutExtension(String path) => _builder.withoutExtension(path); | 276 String withoutExtension(String path) => _builder.withoutExtension(path); |
277 | 277 |
278 /// Returns the path represented by [uri]. | |
279 /// | |
280 /// For POSIX and Windows styles, [uri] must be a `file:` URI. For the URL | |
281 /// style, this will just convert [uri] to a string. | |
282 /// | |
283 /// // POSIX | |
284 /// path.fromUri(Uri.parse('file:///path/to/foo')) | |
285 /// // -> '/path/to/foo' | |
286 /// | |
287 /// // Windows | |
288 /// path.fromUri(Uri.parse('file:///C:/path/to/foo')) | |
289 /// // -> r'C:\path\to\foo' | |
290 /// | |
291 /// // URL | |
292 /// path.fromUri(Uri.parse('http://dartlang.org/path/to/foo')) | |
293 /// // -> 'http://dartlang.org/path/to/foo' | |
294 String fromUri(Uri uri) => _builder.fromUri(uri); | |
295 | |
296 /// Returns the URI that represents [path]. | |
297 /// | |
298 /// For POSIX and Windows styles, this will return a `file:` URI. For the URL | |
299 /// style, this will just convert [path] to a [Uri]. | |
300 /// | |
301 /// This will always convert relative paths to absolute ones before converting | |
302 /// to a URI. | |
303 /// | |
304 /// // POSIX | |
305 /// path.toUri('/path/to/foo') | |
306 /// // -> Uri.parse('file:///path/to/foo') | |
307 /// | |
308 /// // Windows | |
309 /// path.toUri(r'C:\path\to\foo') | |
310 /// // -> Uri.parse('file:///C:/path/to/foo') | |
311 /// | |
312 /// // URL | |
313 /// path.toUri('http://dartlang.org/path/to/foo') | |
314 /// // -> Uri.parse('http://dartlang.org/path/to/foo') | |
315 Uri toUri(String path) => _builder.toUri(path); | |
316 | |
278 /// Validates that there are no non-null arguments following a null one and | 317 /// Validates that there are no non-null arguments following a null one and |
279 /// throws an appropriate [ArgumentError] on failure. | 318 /// throws an appropriate [ArgumentError] on failure. |
280 _validateArgList(String method, List<String> args) { | 319 _validateArgList(String method, List<String> args) { |
281 for (var i = 1; i < args.length; i++) { | 320 for (var i = 1; i < args.length; i++) { |
282 // Ignore nulls hanging off the end. | 321 // Ignore nulls hanging off the end. |
283 if (args[i] == null || args[i - 1] != null) continue; | 322 if (args[i] == null || args[i - 1] != null) continue; |
284 | 323 |
285 var numArgs; | 324 var numArgs; |
286 for (numArgs = args.length; numArgs >= 1; numArgs--) { | 325 for (numArgs = args.length; numArgs >= 1; numArgs--) { |
287 if (args[numArgs - 1] != null) break; | 326 if (args[numArgs - 1] != null) break; |
(...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
666 for (var i = parsed.parts.length - 1; i >= 0; i--) { | 705 for (var i = parsed.parts.length - 1; i >= 0; i--) { |
667 if (!parsed.parts[i].isEmpty) { | 706 if (!parsed.parts[i].isEmpty) { |
668 parsed.parts[i] = parsed.basenameWithoutExtension; | 707 parsed.parts[i] = parsed.basenameWithoutExtension; |
669 break; | 708 break; |
670 } | 709 } |
671 } | 710 } |
672 | 711 |
673 return parsed.toString(); | 712 return parsed.toString(); |
674 } | 713 } |
675 | 714 |
715 /// Returns the path represented by [uri]. | |
716 /// | |
717 /// For POSIX and Windows styles, [uri] must be a `file:` URI. For the URL | |
718 /// style, this will just convert [uri] to a string. | |
719 /// | |
720 /// // POSIX | |
721 /// builder.fromUri(Uri.parse('file:///path/to/foo')) | |
722 /// // -> '/path/to/foo' | |
723 /// | |
724 /// // Windows | |
725 /// builder.fromUri(Uri.parse('file:///C:/path/to/foo')) | |
726 /// // -> r'C:\path\to\foo' | |
727 /// | |
728 /// // URL | |
729 /// builder.fromUri(Uri.parse('http://dartlang.org/path/to/foo')) | |
730 /// // -> 'http://dartlang.org/path/to/foo' | |
731 String fromUri(Uri uri) => style.pathFromUri(uri); | |
732 | |
733 /// Returns the URI that represents [path]. | |
734 /// | |
735 /// For POSIX and Windows styles, this will return a `file:` URI. For the URL | |
736 /// style, this will just convert [path] to a [Uri]. | |
737 /// | |
738 /// // POSIX | |
739 /// builder.toUri('/path/to/foo') | |
740 /// // -> Uri.parse('file:///path/to/foo') | |
741 /// | |
742 /// // Windows | |
743 /// builder.toUri(r'C:\path\to\foo') | |
744 /// // -> Uri.parse('file:///C:/path/to/foo') | |
745 /// | |
746 /// // URL | |
747 /// builder.toUri('http://dartlang.org/path/to/foo') | |
748 /// // -> Uri.parse('http://dartlang.org/path/to/foo') | |
749 Uri toUri(String path) { | |
750 if (isRelative(path)) { | |
751 return Uri.parse(path.replaceAll(style.separatorPattern, '/')); | |
752 } else { | |
753 return style.pathToUri(join(root, path)); | |
754 } | |
755 } | |
756 | |
676 _ParsedPath _parse(String path) { | 757 _ParsedPath _parse(String path) { |
677 var before = path; | 758 var before = path; |
678 | 759 |
679 // Remove the root prefix, if any. | 760 // Remove the root prefix, if any. |
680 var root = style.getRoot(path); | 761 var root = style.getRoot(path); |
681 var isRootRelative = style.getRelativeRoot(path) != null; | 762 var isRootRelative = style.getRelativeRoot(path) != null; |
682 if (root != null) path = path.substring(root.length); | 763 if (root != null) path = path.substring(root.length); |
683 | 764 |
684 // Split the parts on path separators. | 765 // Split the parts on path separators. |
685 var parts = []; | 766 var parts = []; |
(...skipping 21 matching lines...) Expand all Loading... | |
707 } | 788 } |
708 | 789 |
709 return new _ParsedPath(style, root, isRootRelative, parts, separators); | 790 return new _ParsedPath(style, root, isRootRelative, parts, separators); |
710 } | 791 } |
711 } | 792 } |
712 | 793 |
713 /// An enum type describing a "flavor" of path. | 794 /// An enum type describing a "flavor" of path. |
714 class Style { | 795 class Style { |
715 /// POSIX-style paths use "/" (forward slash) as separators. Absolute paths | 796 /// POSIX-style paths use "/" (forward slash) as separators. Absolute paths |
716 /// start with "/". Used by UNIX, Linux, Mac OS X, and others. | 797 /// start with "/". Used by UNIX, Linux, Mac OS X, and others. |
717 static final posix = new Style._('posix', '/', '/', r'[^/]$', '/'); | 798 static final posix = new _PosixStyle(); |
718 | 799 |
719 /// Windows paths use "\" (backslash) as separators. Absolute paths start with | 800 /// Windows paths use "\" (backslash) as separators. Absolute paths start with |
720 /// a drive letter followed by a colon (example, "C:") or two backslashes | 801 /// a drive letter followed by a colon (example, "C:") or two backslashes |
721 /// ("\\") for UNC paths. | 802 /// ("\\") for UNC paths. |
722 // TODO(rnystrom): The UNC root prefix should include the drive name too, not | 803 // TODO(rnystrom): The UNC root prefix should include the drive name too, not |
723 // just the "\\". | 804 // just the "\\". |
724 static final windows = new Style._('windows', '\\', r'[/\\]', r'[^/\\]$', | 805 static final windows = new _WindowsStyle(); |
725 r'\\\\|[a-zA-Z]:[/\\]'); | |
726 | 806 |
727 /// URLs aren't filesystem paths, but they're supported by Pathos to make it | 807 /// URLs aren't filesystem paths, but they're supported by Pathos to make it |
728 /// easier to manipulate URL paths in the browser. | 808 /// easier to manipulate URL paths in the browser. |
729 /// | 809 /// |
730 /// URLs use "/" (forward slash) as separators. Absolute paths either start | 810 /// URLs use "/" (forward slash) as separators. Absolute paths either start |
731 /// with a protocol and optional hostname (e.g. `http://dartlang.org`, | 811 /// with a protocol and optional hostname (e.g. `http://dartlang.org`, |
732 /// `file://`) or with "/". | 812 /// `file://`) or with "/". |
733 static final url = new Style._('url', '/', '/', | 813 static final url = new _UrlStyle(); |
734 r"(^[a-zA-Z][-+.a-zA-Z\d]*://|[^/])$", | |
735 r"[a-zA-Z][-+.a-zA-Z\d]*://[^/]*", r"/"); | |
736 | 814 |
737 Style._(this.name, this.separator, String separatorPattern, | 815 Style._(this.name, this.separator, String separatorPattern, |
738 String needsSeparatorPattern, String rootPattern, | 816 String needsSeparatorPattern, String rootPattern, |
739 [String relativeRootPattern]) | 817 [String relativeRootPattern]) |
740 : separatorPattern = new RegExp(separatorPattern), | 818 : separatorPattern = new RegExp(separatorPattern), |
741 needsSeparatorPattern = new RegExp(needsSeparatorPattern), | 819 needsSeparatorPattern = new RegExp(needsSeparatorPattern), |
742 _rootPattern = new RegExp('^$rootPattern'), | 820 _rootPattern = new RegExp('^$rootPattern'), |
743 _relativeRootPattern = relativeRootPattern == null ? null : | 821 _relativeRootPattern = relativeRootPattern == null ? null : |
744 new RegExp('^$relativeRootPattern'); | 822 new RegExp('^$relativeRootPattern'); |
745 | 823 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
788 /// Gets the root prefix of [path] if it's root-relative. | 866 /// Gets the root prefix of [path] if it's root-relative. |
789 /// | 867 /// |
790 /// If [path] is relative or absolute and not root-relative, returns `null`. | 868 /// If [path] is relative or absolute and not root-relative, returns `null`. |
791 String getRelativeRoot(String path) { | 869 String getRelativeRoot(String path) { |
792 if (_relativeRootPattern == null) return null; | 870 if (_relativeRootPattern == null) return null; |
793 var match = _relativeRootPattern.firstMatch(path); | 871 var match = _relativeRootPattern.firstMatch(path); |
794 if (match == null) return null; | 872 if (match == null) return null; |
795 return match[0]; | 873 return match[0]; |
796 } | 874 } |
797 | 875 |
876 /// Returns the path represented by [uri] in this style. | |
877 String pathFromUri(Uri uri); | |
878 | |
879 /// Returns the URI that represents [path]. | |
880 /// | |
881 /// [path] is guaranteed to be absolute. Relative paths are handled | |
Bob Nystrom
2013/06/13 00:21:18
"guaranteed" is confusing here. Is it required to
nweiz
2013/06/19 00:50:27
This documentation is intended for implementors of
Bob Nystrom
2013/06/19 18:02:18
Ah, that makes sense. It isn't strictly true that
| |
882 /// automatically by [Builder]. | |
883 Uri pathToUri(String path); | |
884 | |
798 String toString() => name; | 885 String toString() => name; |
799 } | 886 } |
800 | 887 |
888 /// The style for POSIX paths. | |
889 class _PosixStyle extends Style { | |
890 _PosixStyle() | |
891 : super._('posix', '/', '/', r'[^/]$', '/'); | |
Bob Nystrom
2013/06/13 00:21:18
Since you are subclassing the styles now, let's ma
nweiz
2013/06/19 00:50:27
Done.
| |
892 | |
893 String pathFromUri(Uri uri) { | |
894 if (uri.scheme == '' || uri.scheme == 'file') return uri.path; | |
Bob Nystrom
2013/06/13 00:21:18
What about URL decoding?
nweiz
2013/06/19 00:50:27
Done.
| |
895 throw new ArgumentError("Uri $uri must have scheme 'file:'."); | |
896 } | |
897 | |
898 Uri pathToUri(String path) => Uri.parse('file://$path'); | |
Bob Nystrom
2013/06/13 00:21:18
new Uri(scheme: "file", path: path);
Søren Gjesse
2013/06/13 07:13:32
The path should also be encoded
new Uri(scheme: "
nweiz
2013/06/19 00:50:27
Done.
| |
899 } | |
900 | |
901 /// The style for Windows paths. | |
902 class _WindowsStyle extends Style { | |
903 _WindowsStyle() | |
904 : super._('windows', '\\', r'[/\\]', r'[^/\\]$', r'\\\\|[a-zA-Z]:[/\\]'); | |
905 | |
906 String pathFromUri(Uri uri) { | |
907 if (uri.scheme != '' && uri.scheme != 'file') { | |
908 throw new ArgumentError("Uri $uri must have scheme 'file:'."); | |
909 } | |
910 | |
911 if (uri.host == '') { | |
912 if (uri.path.startsWith('/')) { | |
913 // Drive-letter paths look like "file:///C:/path/to/file". The | |
914 // replaceFirst removes the extra initial slash. | |
915 return uri.path.replaceFirst("/", "").replaceAll("/", "\\"); | |
916 } else { | |
917 return uri.path.replaceAll("/", "\\"); | |
Bob Nystrom
2013/06/13 00:21:18
Doing this replaceAll for both arms seems redundan
nweiz
2013/06/19 00:50:27
Done.
| |
918 } | |
919 } else { | |
920 // Network paths look like "file://hostname/path/to/file". | |
921 return "\\\\${uri.host}${uri.path.replaceAll("/", "\\")}"; | |
922 } | |
923 } | |
924 | |
925 Uri pathToUri(String path) { | |
926 if (path.startsWith('\\\\')) { | |
927 // Network paths become "file://hostname/path/to/file". | |
928 return Uri.parse('file:${path.replaceAll("\\", "/")}'); | |
Bob Nystrom
2013/06/13 00:21:18
Use the regular Uri constructor here instead of ma
nweiz
2013/06/19 00:50:27
Done.
| |
929 } else { | |
930 // Drive-letter paths become "file:///C:/path/to/file". | |
931 return Uri.parse('file:///${path.replaceAll("\\", "/")}'); | |
932 } | |
933 } | |
934 } | |
935 | |
936 /// The style for URL paths. | |
937 class _UrlStyle extends Style { | |
938 _UrlStyle() | |
939 : super._('url', '/', '/', | |
940 r"(^[a-zA-Z][-+.a-zA-Z\d]*://|[^/])$", | |
941 r"[a-zA-Z][-+.a-zA-Z\d]*://[^/]*", r"/"); | |
942 | |
943 String pathFromUri(Uri uri) => uri.toString(); | |
944 | |
945 Uri pathToUri(String path) => Uri.parse(path); | |
946 } | |
947 | |
801 // TODO(rnystrom): Make this public? | 948 // TODO(rnystrom): Make this public? |
802 class _ParsedPath { | 949 class _ParsedPath { |
803 /// The [Style] that was used to parse this path. | 950 /// The [Style] that was used to parse this path. |
804 Style style; | 951 Style style; |
805 | 952 |
806 /// The absolute root portion of the path, or `null` if the path is relative. | 953 /// The absolute root portion of the path, or `null` if the path is relative. |
807 /// On POSIX systems, this will be `null` or "/". On Windows, it can be | 954 /// On POSIX systems, this will be `null` or "/". On Windows, it can be |
808 /// `null`, "//" for a UNC path, or something like "C:\" for paths with drive | 955 /// `null`, "//" for a UNC path, or something like "C:\" for paths with drive |
809 /// letters. | 956 /// letters. |
810 String root; | 957 String root; |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
931 // doesn't count. | 1078 // doesn't count. |
932 if (lastDot <= 0) return [file, '']; | 1079 if (lastDot <= 0) return [file, '']; |
933 | 1080 |
934 return [file.substring(0, lastDot), file.substring(lastDot)]; | 1081 return [file.substring(0, lastDot), file.substring(lastDot)]; |
935 } | 1082 } |
936 | 1083 |
937 _ParsedPath clone() => new _ParsedPath( | 1084 _ParsedPath clone() => new _ParsedPath( |
938 style, root, isRootRelative, | 1085 style, root, isRootRelative, |
939 new List.from(parts), new List.from(separators)); | 1086 new List.from(parts), new List.from(separators)); |
940 } | 1087 } |
OLD | NEW |