Chromium Code Reviews| Index: pkg/analyzer/lib/src/util/absolute_path.dart |
| diff --git a/pkg/analyzer/lib/src/util/absolute_path.dart b/pkg/analyzer/lib/src/util/absolute_path.dart |
| index f31935d330a1841703d35bd6916b0818c771a3e3..2a90ad767570ae4964ea2981562215cd1269e645 100644 |
| --- a/pkg/analyzer/lib/src/util/absolute_path.dart |
| +++ b/pkg/analyzer/lib/src/util/absolute_path.dart |
| @@ -4,17 +4,21 @@ |
| library analyzer.src.util.absolute_path; |
| -/// The class for manipulating absolute paths. |
| +/// The class for manipulating absolute, normalized paths. |
| class AbsolutePathContext { |
| - final String separator; |
| + static const int _COLON = 0x3A; |
| + static const int _PERIOD = 0x2e; |
| + static const int _LOWER_A = 0x61; |
| + static const int _LOWER_Z = 0x7A; |
| + static const int _UPPER_A = 0x41; |
| + static const int _UPPER_Z = 0x5A; |
| + final bool _isWindows; |
| + String separator; |
| int _separatorChar; |
| - AbsolutePathContext(this.separator) { |
| - if (separator.length != 1) { |
| - throw new ArgumentError.value( |
| - separator, 'separator', 'must be exactly one character long'); |
| - } |
| + AbsolutePathContext(this._isWindows) { |
| + separator = _isWindows ? r'\' : '/'; |
| _separatorChar = separator.codeUnitAt(0); |
| } |
| @@ -55,6 +59,14 @@ class AbsolutePathContext { |
| : path.substring(0, lastIndex); |
| } |
| + /// Return `true` if the given [path] is valid. |
| + /// |
| + /// context.isNormalized('/foo/bar'); // -> true |
| + /// context.isNormalized('/foo/bar/../baz'); // -> false |
| + bool isValid(String path) { |
| + return _isAbsolute(path) && _isNormalized(path); |
| + } |
| + |
| /// Return `true` if [child] is a path beneath [parent], and `false` |
| /// otherwise. Both the [child] and [parent] paths must be absolute paths. |
| /// |
| @@ -94,6 +106,57 @@ class AbsolutePathContext { |
| return null; |
| } |
| + /// Return `true` if the given [path] is absolute. |
| + /// |
| + /// _isAbsolute('/foo/bar'); // -> true |
| + /// _isAbsolute('/'); // -> true |
| + /// _isAbsolute('foo/bar'); // -> false |
| + /// _isAbsolute('C:\foo\bar'); // -> true |
| + /// _isAbsolute('C:\'); // -> true |
| + /// _isAbsolute('foo\bar'); // -> false |
| + bool _isAbsolute(String path) { |
| + if (_isWindows) { |
| + return path.length >= 3 && |
| + _isAlphabetic(path.codeUnitAt(0)) && |
| + path.codeUnitAt(1) == _COLON && |
| + path.codeUnitAt(2) == _separatorChar; |
| + } else { |
| + return path.isNotEmpty && path.codeUnitAt(0) == _separatorChar; |
| + } |
| + } |
| + |
| + |
| + /// Return `true` if the given absolute [path] is normalized. |
| + /// |
| + /// _isAbsolute('/foo/bar'); // -> true |
| + /// _isAbsolute('/foo/..bar'); // -> true |
| + /// _isAbsolute('/'); // -> true |
| + /// _isAbsolute('/foo/bar/../baz'); // -> false |
| + /// _isAbsolute('/foo/bar/..'); // -> false |
|
Brian Wilkerson
2015/12/09 22:58:20
Wrong method name in examples.
|
| + bool _isNormalized(String path) { |
| + int periodCount = 0; |
| + for (int c in path.codeUnits) { |
| + if (c == _PERIOD) { |
| + periodCount++; |
| + continue; |
| + } |
| + if (c == _separatorChar) { |
| + if (periodCount == 1 || periodCount == 2) { |
| + return false; |
| + } |
| + } |
| + periodCount = 0; |
| + } |
| + return periodCount != 1 && periodCount != 2; |
| + } |
| + |
| + /// Returns whether [char] is the code for an ASCII letter (uppercase or |
| + /// lowercase). |
| + static bool _isAlphabetic(int char) { |
| + return char >= _UPPER_A && char <= _UPPER_Z || |
| + char >= _LOWER_A && char <= _LOWER_Z; |
| + } |
| + |
| /// Return `true` if [str] starts with the given [prefix]. |
| /// |
| /// The check is done from the end of [prefix], because absolute paths |