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

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

Issue 16580005: Support a URL style for pathos. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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 | « no previous file | pkg/pathos/test/pathos_url_test.dart » ('j') | pkg/pathos/test/pathos_url_test.dart » ('J')
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 80ffe72a57da05881db73e521e0753a0788d560b..796e06f8250fb9086367d679647a6b707e9b5527 100644
--- a/pkg/pathos/lib/path.dart
+++ b/pkg/pathos/lib/path.dart
@@ -31,13 +31,8 @@ final _builder = new Builder();
* Inserts [length] elements in front of the [list] and fills them with the
* [fillValue].
*/
-void _growListFront(List list, int length, fillValue) {
- list.length += length;
- list.setRange(length, list.length, list);
- for (var i = 0; i < length; i++) {
- list[i] = fillValue;
- }
-}
+void _growListFront(List list, int length, fillValue) =>
+ list.insertAll(0, new List.filled(length, fillValue));
/// Gets the path to the current working directory.
String get current => io.Directory.current.path;
@@ -112,9 +107,17 @@ String extension(String path) => _builder.extension(path);
String rootPrefix(String path) => _builder.rootPrefix(path);
/// Returns `true` if [path] is an absolute path and `false` if it is a
-/// relative path. On POSIX systems, absolute paths start with a `/` (forward
-/// slash). On Windows, an absolute path starts with `\\`, or a drive letter
-/// followed by `:/` or `:\`.
+/// relative path.
+///
+/// On POSIX systems, absolute paths start with a `/` (forward slash). On
+/// Windows, an absolute path starts with `\\`, or a drive letter followed by
+/// `:/` or `:\`. For URLs, absolute paths either start with a protocol and
+/// optional hostname (e.g. `http://dartlang.org`, `file://`) or with a `/`.
+///
+/// URLs that start with `/` are known as "root-relative", since they're
+/// relative to the root of the current URL. Since root-relative paths are still
+/// absolute in every other sense, [isAbsolute] will return true for them. They
+/// can be detected using [isRootRelative].
bool isAbsolute(String path) => _builder.isAbsolute(path);
/// Returns `true` if [path] is a relative path and `false` if it is absolute.
@@ -123,6 +126,16 @@ bool isAbsolute(String path) => _builder.isAbsolute(path);
/// `:/` or `:\`.
bool isRelative(String path) => _builder.isRelative(path);
+/// Returns `true` if [path] is a root-relative path and `false` if it's not.
+///
+/// URLs that start with `/` are known as "root-relative", since they're
+/// relative to the root of the current URL. Since root-relative paths are still
+/// absolute in every other sense, [isAbsolute] will return true for them. They
+/// can be detected using [isRootRelative].
+///
+/// No POSIX and Windows paths are root-relative.
+bool isRootRelative(String path) => _builder.isRootRelative(path);
+
/// Joins the given path parts into a single path using the current platform's
/// [separator]. Example:
///
@@ -340,9 +353,17 @@ class Builder {
}
/// Returns `true` if [path] is an absolute path and `false` if it is a
- /// relative path. On POSIX systems, absolute paths start with a `/` (forward
- /// slash). On Windows, an absolute path starts with `\\`, or a drive letter
- /// followed by `:/` or `:\`.
+ /// relative path.
+ ///
+ /// On POSIX systems, absolute paths start with a `/` (forward slash). On
+ /// Windows, an absolute path starts with `\\`, or a drive letter followed by
+ /// `:/` or `:\`. For URLs, absolute paths either start with a protocol and
+ /// optional hostname (e.g. `http://dartlang.org`, `file://`) or with a `/`.
+ ///
+ /// URLs that start with `/` are known as "root-relative", since they're
+ /// relative to the root of the current URL. Since root-relative paths are still
Bob Nystrom 2013/06/06 22:50:40 Long lines.
nweiz 2013/06/07 01:04:30 Done.
+ /// absolute in every other sense, [isAbsolute] will return true for them. They
+ /// can be detected using [isRootRelative].
bool isAbsolute(String path) => _parse(path).isAbsolute;
/// Returns `true` if [path] is a relative path and `false` if it is absolute.
@@ -351,6 +372,16 @@ class Builder {
/// `:/` or `:\`.
bool isRelative(String path) => !isAbsolute(path);
+ /// Returns `true` if [path] is a root-relative path and `false` if it's not.
+ ///
+ /// URLs that start with `/` are known as "root-relative", since they're
+ /// relative to the root of the current URL. Since root-relative paths are still
Bob Nystrom 2013/06/06 22:50:40 Ditto.
nweiz 2013/06/07 01:04:30 Done.
+ /// absolute in every other sense, [isAbsolute] will return true for them. They
+ /// can be detected using [isRootRelative].
+ ///
+ /// No POSIX and Windows paths are root-relative.
+ bool isRootRelative(String path) => _parse(path).isRootRelative;
+
/// Joins the given path parts into a single path. Example:
///
/// builder.join('path', 'to', 'foo'); // -> 'path/to/foo'
@@ -390,7 +421,14 @@ class Builder {
var needsSeparator = false;
for (var part in parts) {
- if (this.isAbsolute(part)) {
+ if (this.isRootRelative(part) &&
+ this.isAbsolute(buffer.toString()) &&
+ !this.isRootRelative(buffer.toString())) {
+ var oldRoot = this.rootPrefix(buffer.toString());
Bob Nystrom 2013/06/06 22:50:40 A couple of things here: 1. Calling toString() on
nweiz 2013/06/07 01:04:30 Done.
+ buffer = new StringBuffer();
Bob Nystrom 2013/06/06 22:50:40 buffer.clear() seems cleaner to me. Below too?
nweiz 2013/06/07 01:04:30 Done.
+ buffer.write(oldRoot);
+ buffer.write(part);
+ } else if (this.isAbsolute(part)) {
// An absolute path discards everything before it.
buffer = new StringBuffer();
buffer.write(part);
@@ -406,8 +444,7 @@ class Builder {
// Unless this part ends with a separator, we'll need to add one before
// the next part.
- needsSeparator = part.length > 0 &&
- !part[part.length - 1].contains(style.separatorPattern);
+ needsSeparator = part.contains(style.needsSeparatorPattern);
}
return buffer.toString();
@@ -498,7 +535,9 @@ class Builder {
// If the given path is relative, resolve it relative to the root of the
// builder.
- if (this.isRelative(path)) path = this.resolve(path);
+ if (this.isRelative(path) || this.isRootRelative(path)) {
+ path = this.resolve(path);
+ }
// If the path is still relative and `from` is absolute, we're unable to
// find a path from `from` to `path`.
@@ -524,16 +563,17 @@ class Builder {
while (fromParsed.parts.length > 0 && pathParsed.parts.length > 0 &&
fromParsed.parts[0] == pathParsed.parts[0]) {
fromParsed.parts.removeAt(0);
- fromParsed.separators.removeAt(0);
+ fromParsed.separators.removeAt(1);
pathParsed.parts.removeAt(0);
- pathParsed.separators.removeAt(0);
+ pathParsed.separators.removeAt(1);
}
// If there are any directories left in the root path, we need to walk up
// out of them.
_growListFront(pathParsed.parts, fromParsed.parts.length, '..');
- _growListFront(
- pathParsed.separators, fromParsed.parts.length, style.separator);
+ pathParsed.separators[0] = '';
+ pathParsed.separators.insertAll(1,
+ new List.filled(fromParsed.parts.length, style.separator));
// Corner case: the paths completely collapsed.
if (pathParsed.parts.length == 0) return '.';
@@ -566,11 +606,21 @@ class Builder {
// Remove the root prefix, if any.
var root = style.getRoot(path);
+ var isRootRelative = style.getRelativeRoot(path) != null;
if (root != null) path = path.substring(root.length);
// Split the parts on path separators.
var parts = [];
var separators = [];
+
+ var firstSeparator = style.separatorPattern.firstMatch(path);
+ if (firstSeparator != null && firstSeparator.start == 0) {
+ separators.add(firstSeparator[0]);
+ path = path.substring(firstSeparator[0].length);
+ } else {
+ separators.add('');
+ }
+
var start = 0;
for (var match in style.separatorPattern.allMatches(path)) {
parts.add(path.substring(start, match.start));
@@ -584,7 +634,7 @@ class Builder {
separators.add('');
}
- return new _ParsedPath(style, root, parts, separators);
+ return new _ParsedPath(style, root, isRootRelative, parts, separators);
}
}
@@ -592,20 +642,34 @@ class Builder {
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', '/', '/', '/');
+ static final posix = new Style._('posix', '/', '/', r'[^/]$', '/');
/// 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'[/\\]',
+ static final windows = new Style._('windows', '\\', r'[/\\]', r'[^/\\]$',
r'\\\\|[a-zA-Z]:[/\\]');
+ /// URLs aren't filesystem paths, but they're supported by Pathos to make it
+ /// easier to manipulate URL paths in the browser.
+ ///
+ /// 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 rootPattern)
+ String needsSeparatorPattern, String rootPattern,
+ [String relativeRootPattern])
: separatorPattern = new RegExp(separatorPattern),
- _rootPattern = new RegExp('^$rootPattern');
+ needsSeparatorPattern = new RegExp(needsSeparatorPattern),
+ _rootPattern = new RegExp('^$rootPattern'),
+ _relativeRootPattern = relativeRootPattern == null ? null :
+ new RegExp('^$relativeRootPattern');
/// The name of this path style. Will be "posix" or "windows".
final String name;
@@ -619,15 +683,39 @@ class Style {
/// "\" is the canonical one.
final Pattern separatorPattern;
+ /// The [Pattern] that matches path components that need a separator after
+ /// them.
+ ///
+ /// Some styles ([url] in particlar) have moderately complex rules about when
+ /// a separator is needed, especially for root path components.
Bob Nystrom 2013/06/06 22:50:40 Can you explain what these rules are somewhere?
nweiz 2013/06/07 01:04:30 Done.
+ final Pattern 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
/// path in this style.
final RegExp _rootPattern;
+ /// The [RegExp] 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;
+
/// 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);
+ if (match == null) return getRelativeRoot(path);
+ return match[0];
Bob Nystrom 2013/06/06 22:50:40 Seems weird to refer back to match here after dele
nweiz 2013/06/07 01:04:30 Done.
+ }
+
+ /// Gets the root prefix of [path] if it's root-relative.
+ ///
+ /// 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 (match == null) return null;
return match[0];
}
@@ -646,12 +734,20 @@ class _ParsedPath {
/// letters.
String root;
+ /// Whether this path is root-relative.
+ ///
+ /// See [Builder.isRootRelative].
+ bool isRootRelative;
+
/// The path-separated parts of the path. All but the last will be
/// directories.
List<String> parts;
- /// The path separators following each part. The last one will be an empty
- /// string unless the path ends with a trailing separator.
+ /// The path separators preceeding each part.
Bob Nystrom 2013/06/06 22:50:40 "preceeding" -> "preceding".
nweiz 2013/06/07 01:04:30 Done.
+ ///
+ /// The first one will be an empty string unless the root requires a separator
+ /// between it and the path. The last one will be an empty string unless the
+ /// path ends with a trailing separator.
List<String> separators;
/// The file extension of the last part, or "" if it doesn't have one.
@@ -660,7 +756,8 @@ class _ParsedPath {
/// `true` if this is an absolute path.
bool get isAbsolute => root != null;
- _ParsedPath(this.style, this.root, this.parts, this.separators);
+ _ParsedPath(this.style, this.root, this.isRootRelative, this.parts,
+ this.separators);
String get basename {
var copy = this.clone();
@@ -715,8 +812,12 @@ class _ParsedPath {
}
// Canonicalize separators.
- var newSeparators = [];
- _growListFront(newSeparators, newParts.length, style.separator);
+ var newSeparators = new List.generate(
+ newParts.length, (_) => style.separator, growable: true);
+ newSeparators.insert(0,
+ isAbsolute && newParts.length > 0 &&
+ root.contains(style.needsSeparatorPattern) ?
+ style.separator : '');
parts = newParts;
separators = newSeparators;
@@ -732,9 +833,10 @@ class _ParsedPath {
var builder = new StringBuffer();
if (root != null) builder.write(root);
for (var i = 0; i < parts.length; i++) {
- builder.write(parts[i]);
builder.write(separators[i]);
+ builder.write(parts[i]);
}
+ builder.write(separators.last);
return builder.toString();
}
@@ -758,5 +860,6 @@ class _ParsedPath {
}
_ParsedPath clone() => new _ParsedPath(
- style, root, new List.from(parts), new List.from(separators));
+ style, root, isRootRelative,
+ new List.from(parts), new List.from(separators));
}
« no previous file with comments | « no previous file | pkg/pathos/test/pathos_url_test.dart » ('j') | pkg/pathos/test/pathos_url_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698