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

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

Issue 59483008: Add isWithin to pkg/path. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: code review Created 7 years, 1 month 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/path/test/posix_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/path/lib/path.dart
diff --git a/pkg/path/lib/path.dart b/pkg/path/lib/path.dart
index 3c5f51eb3ea967285dfa8aee4586088c21e8a588..5f469edd6a6e5b9e67cc4abd2d892a8e8405e89e 100644
--- a/pkg/path/lib/path.dart
+++ b/pkg/path/lib/path.dart
@@ -301,6 +301,13 @@ String normalize(String path) => _builder.normalize(path);
String relative(String path, {String from}) =>
_builder.relative(path, from: from);
+/// Returns `true` if [child] is a path beneath `parent`, and `false` otherwise.
+///
+/// path.isWithin('/root/path', '/root/path/a'); // -> true
+/// path.isWithin('/root/path', '/root/other'); // -> false
+/// path.isWithin('/root/path', '/root/path') // -> false
+bool isWithin(String parent, String child) => _builder.isWithin(parent, child);
+
/// Removes a trailing extension from the last part of [path].
///
/// withoutExtension('path/to/foo.dart'); // -> 'path/to/foo'
@@ -560,10 +567,13 @@ class Builder {
if (this.isRootRelative(part) && isAbsoluteAndNotRootRelative) {
// If the new part is root-relative, it preserves the previous root but
// replaces the path after it.
- var oldRoot = this.rootPrefix(buffer.toString());
+ var parsed = _parse(part);
+ parsed.root = this.rootPrefix(buffer.toString());
+ if (parsed.root.contains(style.needsSeparatorPattern)) {
+ parsed.separators[0] = style.separator;
+ }
buffer.clear();
- buffer.write(oldRoot);
- buffer.write(part);
+ buffer.write(parsed);
} else if (this.isAbsolute(part)) {
isAbsoluteAndNotRootRelative = !this.isRootRelative(part);
// An absolute path discards everything before it.
@@ -661,6 +671,11 @@ class Builder {
///
/// var builder = new Builder(r'some/relative/path');
/// builder.relative(r'/absolute/path'); // -> '/absolute/path'
+ ///
+ /// If [root] is relative, it may be impossible to determine a path from
+ /// [from] to [path]. For example, if [root] and [path] are "." and [from] is
+ /// "/", no path can be determined. In this case, a [PathException] will be
+ /// thrown.
String relative(String path, {String from}) {
from = from == null ? root : this.join(root, from);
@@ -678,7 +693,7 @@ class Builder {
// If the path is still relative and `from` is absolute, we're unable to
// find a path from `from` to `path`.
if (this.isRelative(path) && this.isAbsolute(from)) {
- throw new ArgumentError('Unable to find a path to "$path" from "$from".');
+ throw new PathException('Unable to find a path to "$path" from "$from".');
}
var fromParsed = _parse(from)..normalize();
@@ -712,7 +727,7 @@ class Builder {
// out of them. If a directory left in the from path is '..', it cannot
// be cancelled by adding a '..'.
if (fromParsed.parts.length > 0 && fromParsed.parts[0] == '..') {
- throw new ArgumentError('Unable to find a path to "$path" from "$from".');
+ throw new PathException('Unable to find a path to "$path" from "$from".');
}
_growListFront(pathParsed.parts, fromParsed.parts.length, '..');
pathParsed.separators[0] = '';
@@ -736,6 +751,27 @@ class Builder {
return pathParsed.toString();
}
+ /// Returns `true` if [child] is a path beneath `parent`, and `false`
+ /// otherwise.
+ ///
+ /// path.isWithin('/root/path', '/root/path/a'); // -> true
+ /// path.isWithin('/root/path', '/root/other'); // -> false
+ /// path.isWithin('/root/path', '/root/path') // -> false
+ bool isWithin(String parent, String child) {
+ var relative;
+ try {
+ relative = this.relative(child, from: parent);
+ } on PathException catch (_) {
+ // If no relative path from [parent] to [child] is found, [child]
+ // definitely isn't a child of [parent].
+ return false;
+ }
+
+ var parts = this.split(relative);
+ return this.isRelative(relative) && parts.first != '..' &&
+ parts.first != '.';
+ }
+
/// Removes a trailing extension from the last part of [path].
///
/// builder.withoutExtension('path/to/foo.dart'); // -> 'path/to/foo'
@@ -983,6 +1019,10 @@ class _WindowsStyle extends Style {
final needsSeparatorPattern = new RegExp(r'[^/\\]$');
final rootPattern = new RegExp(r'^(\\\\[^\\]+\\[^\\/]+|[a-zA-Z]:[/\\])');
+ // Matches a back or forward slash that's not followed by another back or
+ // forward slash.
+ final relativeRootPattern = new RegExp(r"^[/\\](?![/\\])");
+
String pathFromUri(Uri uri) {
if (uri.scheme != '' && uri.scheme != 'file') {
throw new ArgumentError("Uri $uri must have scheme 'file:'.");
@@ -1197,3 +1237,13 @@ class _ParsedPath {
style, root, isRootRelative,
new List.from(parts), new List.from(separators));
}
+
+/// An exception class that's thrown when a path operation is unable to be
+/// computed accurately.
+class PathException implements Exception {
+ String message;
+
+ PathException(this.message);
+
+ String toString() => "PathException: $message";
+}
« no previous file with comments | « no previous file | pkg/path/test/posix_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698