Chromium Code Reviews| 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 |