Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(294)

Unified Diff: pkg/pathos/lib/path.dart

Issue 16848002: Add toUri and fromUri functions to pathos. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Preserve trailing separators. Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/pathos/README.md ('k') | pkg/pathos/test/pathos_posix_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/pathos/lib/path.dart
diff --git a/pkg/pathos/lib/path.dart b/pkg/pathos/lib/path.dart
index 145953f3c8aa619d13f4fbcbaec0c9df65a184dd..eeb426db62b5744701dc049b0ca4adbdf6e874fe 100644
--- a/pkg/pathos/lib/path.dart
+++ b/pkg/pathos/lib/path.dart
@@ -275,6 +275,45 @@ String relative(String path, {String from}) =>
/// withoutExtension('path/to/foo.dart'); // -> 'path/to/foo'
String withoutExtension(String path) => _builder.withoutExtension(path);
+/// Returns the path represented by [uri].
+///
+/// For POSIX and Windows styles, [uri] must be a `file:` URI. For the URL
+/// style, this will just convert [uri] to a string.
+///
+/// // POSIX
+/// path.fromUri(Uri.parse('file:///path/to/foo'))
+/// // -> '/path/to/foo'
+///
+/// // Windows
+/// path.fromUri(Uri.parse('file:///C:/path/to/foo'))
+/// // -> r'C:\path\to\foo'
+///
+/// // URL
+/// path.fromUri(Uri.parse('http://dartlang.org/path/to/foo'))
+/// // -> 'http://dartlang.org/path/to/foo'
+String fromUri(Uri uri) => _builder.fromUri(uri);
+
+/// Returns the URI that represents [path].
+///
+/// For POSIX and Windows styles, this will return a `file:` URI. For the URL
+/// style, this will just convert [path] to a [Uri].
+///
+/// This will always convert relative paths to absolute ones before converting
+/// to a URI.
+///
+/// // POSIX
+/// path.toUri('/path/to/foo')
+/// // -> Uri.parse('file:///path/to/foo')
+///
+/// // Windows
+/// path.toUri(r'C:\path\to\foo')
+/// // -> Uri.parse('file:///C:/path/to/foo')
+///
+/// // URL
+/// path.toUri('http://dartlang.org/path/to/foo')
+/// // -> Uri.parse('http://dartlang.org/path/to/foo')
+Uri toUri(String path) => _builder.toUri(path);
+
/// Validates that there are no non-null arguments following a null one and
/// throws an appropriate [ArgumentError] on failure.
_validateArgList(String method, List<String> args) {
@@ -673,6 +712,48 @@ class Builder {
return parsed.toString();
}
+ /// Returns the path represented by [uri].
+ ///
+ /// For POSIX and Windows styles, [uri] must be a `file:` URI. For the URL
+ /// style, this will just convert [uri] to a string.
+ ///
+ /// // POSIX
+ /// builder.fromUri(Uri.parse('file:///path/to/foo'))
+ /// // -> '/path/to/foo'
+ ///
+ /// // Windows
+ /// builder.fromUri(Uri.parse('file:///C:/path/to/foo'))
+ /// // -> r'C:\path\to\foo'
+ ///
+ /// // URL
+ /// builder.fromUri(Uri.parse('http://dartlang.org/path/to/foo'))
+ /// // -> 'http://dartlang.org/path/to/foo'
+ String fromUri(Uri uri) => style.pathFromUri(uri);
+
+ /// Returns the URI that represents [path].
+ ///
+ /// For POSIX and Windows styles, this will return a `file:` URI. For the URL
+ /// style, this will just convert [path] to a [Uri].
+ ///
+ /// // POSIX
+ /// builder.toUri('/path/to/foo')
+ /// // -> Uri.parse('file:///path/to/foo')
+ ///
+ /// // Windows
+ /// builder.toUri(r'C:\path\to\foo')
+ /// // -> Uri.parse('file:///C:/path/to/foo')
+ ///
+ /// // URL
+ /// builder.toUri('http://dartlang.org/path/to/foo')
+ /// // -> Uri.parse('http://dartlang.org/path/to/foo')
+ Uri toUri(String path) {
+ if (isRelative(path)) {
+ return Uri.parse(path.replaceAll(style.separatorPattern, '/'));
+ } else {
+ return style.pathToUri(join(root, path));
+ }
+ }
+
_ParsedPath _parse(String path) {
var before = path;
@@ -711,18 +792,17 @@ class Builder {
}
/// An enum type describing a "flavor" of path.
-class Style {
+abstract class Style {
/// POSIX-style paths use "/" (forward slash) as separators. Absolute paths
/// start with "/". Used by UNIX, Linux, Mac OS X, and others.
- static final posix = new Style._('posix', '/', '/', r'[^/]$', '/');
+ static final posix = new _PosixStyle();
/// Windows paths use "\" (backslash) as separators. Absolute paths start with
/// a drive letter followed by a colon (example, "C:") or two backslashes
/// ("\\") for UNC paths.
// TODO(rnystrom): The UNC root prefix should include the drive name too, not
// just the "\\".
- static final windows = new Style._('windows', '\\', r'[/\\]', r'[^/\\]$',
- r'\\\\|[a-zA-Z]:[/\\]');
+ static final windows = new _WindowsStyle();
/// URLs aren't filesystem paths, but they're supported by Pathos to make it
/// easier to manipulate URL paths in the browser.
@@ -730,30 +810,19 @@ class Style {
/// URLs use "/" (forward slash) as separators. Absolute paths either start
/// with a protocol and optional hostname (e.g. `http://dartlang.org`,
/// `file://`) or with "/".
- static final url = new Style._('url', '/', '/',
- r"(^[a-zA-Z][-+.a-zA-Z\d]*://|[^/])$",
- r"[a-zA-Z][-+.a-zA-Z\d]*://[^/]*", r"/");
-
- Style._(this.name, this.separator, String separatorPattern,
- String needsSeparatorPattern, String rootPattern,
- [String relativeRootPattern])
- : separatorPattern = new RegExp(separatorPattern),
- needsSeparatorPattern = new RegExp(needsSeparatorPattern),
- _rootPattern = new RegExp('^$rootPattern'),
- _relativeRootPattern = relativeRootPattern == null ? null :
- new RegExp('^$relativeRootPattern');
+ static final url = new _UrlStyle();
/// The name of this path style. Will be "posix" or "windows".
- final String name;
+ String get name;
/// The path separator for this style. On POSIX, this is `/`. On Windows,
/// it's `\`.
- final String separator;
+ String get separator;
/// The [Pattern] that can be used to match a separator for a path in this
- /// style. Windows allows both "/" and "\" as path separators even though
- /// "\" is the canonical one.
- final Pattern separatorPattern;
+ /// style. Windows allows both "/" and "\" as path separators even though "\"
+ /// is the canonical one.
+ Pattern get separatorPattern;
/// The [Pattern] that matches path components that need a separator after
/// them.
@@ -763,24 +832,23 @@ class Style {
/// separator between the root and the first component, even if the root
/// already ends in a separator character. For example, to join "file://" and
/// "usr", an additional "/" is needed (making "file:///usr").
- final Pattern needsSeparatorPattern;
+ Pattern get needsSeparatorPattern;
- // TODO(nweiz): make this a Pattern when issue 7080 is fixed.
- /// The [RegExp] that can be used to match the root prefix of an absolute
+ /// The [Pattern] that can be used to match the root prefix of an absolute
/// path in this style.
- final RegExp _rootPattern;
+ Pattern get rootPattern;
- /// The [RegExp] that can be used to match the root prefix of a root-relative
+ /// The [Pattern] that can be used to match the root prefix of a root-relative
/// path in this style.
///
/// This can be null to indicate that this style doesn't support root-relative
/// paths.
- final RegExp _relativeRootPattern;
+ final Pattern relativeRootPattern = null;
/// Gets the root prefix of [path] if path is absolute. If [path] is relative,
/// returns `null`.
String getRoot(String path) {
- var match = _rootPattern.firstMatch(path);
+ var match = rootPattern.firstMatch(path);
if (match != null) return match[0];
return getRelativeRoot(path);
}
@@ -789,15 +857,146 @@ class Style {
///
/// If [path] is relative or absolute and not root-relative, returns `null`.
String getRelativeRoot(String path) {
- if (_relativeRootPattern == null) return null;
- var match = _relativeRootPattern.firstMatch(path);
+ if (relativeRootPattern == null) return null;
+ var match = relativeRootPattern.firstMatch(path);
if (match == null) return null;
return match[0];
}
+ /// Returns the path represented by [uri] in this style.
+ String pathFromUri(Uri uri);
+
+ /// Returns the URI that represents [path].
+ ///
+ /// Pathos will always path an absolute path for [path]. Relative paths are
+ /// handled automatically by [Builder].
+ Uri pathToUri(String path);
+
String toString() => name;
}
+/// The style for POSIX paths.
+class _PosixStyle extends Style {
+ _PosixStyle();
+
+ static final _builder = new Builder(style: Style.posix);
+
+ final name = 'posix';
+ final separator = '/';
+ final separatorPattern = new RegExp(r'/');
+ final needsSeparatorPattern = new RegExp(r'[^/]$');
+ final rootPattern = new RegExp(r'^/');
+
+ String pathFromUri(Uri uri) {
+ if (uri.scheme == '' || uri.scheme == 'file') {
+ return Uri.decodeComponent(uri.path);
+ }
+ throw new ArgumentError("Uri $uri must have scheme 'file:'.");
+ }
+
+ Uri pathToUri(String path) {
+ var parsed = _builder._parse(path);
+
+ if (parsed.parts.isEmpty) {
+ // If the path is a bare root (e.g. "/"), [components] will
+ // currently be empty. We add two empty components so the URL constructor
+ // produces "file:///", with a trailing slash.
+ parsed.parts.addAll(["", ""]);
+ } else if (parsed.hasTrailingSeparator) {
+ // If the path has a trailing slash, add a single empty component so the
+ // URI has a trailing slash as well.
+ parsed.parts.add("");
+ }
+
+ return new Uri(scheme: 'file', pathSegments: parsed.parts);
+ }
+}
+
+/// The style for Windows paths.
+class _WindowsStyle extends Style {
+ _WindowsStyle();
+
+ static final _builder = new Builder(style: Style.windows);
+
+ final name = 'windows';
+ final separator = '\\';
+ final separatorPattern = new RegExp(r'[/\\]');
+ final needsSeparatorPattern = new RegExp(r'[^/\\]$');
+ final rootPattern = new RegExp(r'^(\\\\|[a-zA-Z]:[/\\])');
+
+ String pathFromUri(Uri uri) {
+ if (uri.scheme != '' && uri.scheme != 'file') {
+ throw new ArgumentError("Uri $uri must have scheme 'file:'.");
+ }
+
+ var path = uri.path;
+ if (uri.host == '') {
+ // Drive-letter paths look like "file:///C:/path/to/file". The
+ // replaceFirst removes the extra initial slash.
+ if (path.startsWith('/')) path = path.replaceFirst("/", "");
+ } else {
+ // Network paths look like "file://hostname/path/to/file".
+ path = '\\\\${uri.host}$path';
+ }
+ return Uri.decodeComponent(path.replaceAll("/", "\\"));
+ }
+
+ Uri pathToUri(String path) {
+ var parsed = _builder._parse(path);
+ if (parsed.root == r'\\') {
+ // Network paths become "file://hostname/path/to/file".
+
+ var host = parsed.parts.removeAt(0);
+
+ if (parsed.parts.isEmpty) {
+ // If the path is a bare root (e.g. "\\hostname"), [parsed.parts] will
+ // currently be empty. We add two empty components so the URL
+ // constructor produces "file://hostname/", with a trailing slash.
+ parsed.parts.addAll(["", ""]);
+ } else if (parsed.hasTrailingSeparator) {
+ // If the path has a trailing slash, add a single empty component so the
+ // URI has a trailing slash as well.
+ parsed.parts.add("");
+ }
+
+ return new Uri(scheme: 'file', host: host, pathSegments: parsed.parts);
+ } else {
+ // Drive-letter paths become "file:///C:/path/to/file".
+
+ // If the path is a bare root (e.g. "C:\"), [parsed.parts] will currently
+ // be empty. We add an empty component so the URL constructor produces
+ // "file:///C:/", with a trailing slash. We also add an empty component if
+ // the URL otherwise has a trailing slash.
+ if (parsed.parts.length == 0 || parsed.hasTrailingSeparator) {
+ parsed.parts.add("");
+ }
+
+ // Get rid of the trailing "\" in "C:\" because the URI constructor will
+ // add a separator on its own.
+ parsed.parts.insert(0, parsed.root.replaceAll(separatorPattern, ""));
+
+ return new Uri(scheme: 'file', pathSegments: parsed.parts);
+ }
+ }
+}
+
+/// The style for URL paths.
+class _UrlStyle extends Style {
+ _UrlStyle();
+
+ final name = 'url';
+ final separator = '/';
+ final separatorPattern = new RegExp(r'/');
+ final needsSeparatorPattern = new RegExp(
+ r"(^[a-zA-Z][-+.a-zA-Z\d]*://|[^/])$");
+ final rootPattern = new RegExp(r"[a-zA-Z][-+.a-zA-Z\d]*://[^/]*");
+ final relativeRootPattern = new RegExp(r"^/");
+
+ String pathFromUri(Uri uri) => uri.toString();
+
+ Uri pathToUri(String path) => Uri.parse(path);
+}
+
// TODO(rnystrom): Make this public?
class _ParsedPath {
/// The [Style] that was used to parse this path.
@@ -848,6 +1047,8 @@ class _ParsedPath {
return copy._splitExtension()[0];
}
+ bool get hasTrailingSeparator => !parts.isEmpty && (parts.last == '' || separators.last != '');
+
void removeTrailingSeparators() {
while (!parts.isEmpty && parts.last == '') {
parts.removeLast();
« no previous file with comments | « pkg/pathos/README.md ('k') | pkg/pathos/test/pathos_posix_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698