OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library analyzer.src.util.absolute_path; | 5 library analyzer.src.util.absolute_path; |
6 | 6 |
7 /// The class for manipulating absolute paths. | 7 /// The class for manipulating absolute, normalized paths. |
8 class AbsolutePathContext { | 8 class AbsolutePathContext { |
9 final String separator; | 9 static const int _COLON = 0x3A; |
10 static const int _PERIOD = 0x2e; | |
11 static const int _LOWER_A = 0x61; | |
12 static const int _LOWER_Z = 0x7A; | |
13 static const int _UPPER_A = 0x41; | |
14 static const int _UPPER_Z = 0x5A; | |
10 | 15 |
16 final bool _isWindows; | |
17 String separator; | |
11 int _separatorChar; | 18 int _separatorChar; |
12 | 19 |
13 AbsolutePathContext(this.separator) { | 20 AbsolutePathContext(this._isWindows) { |
14 if (separator.length != 1) { | 21 separator = _isWindows ? r'\' : '/'; |
15 throw new ArgumentError.value( | |
16 separator, 'separator', 'must be exactly one character long'); | |
17 } | |
18 _separatorChar = separator.codeUnitAt(0); | 22 _separatorChar = separator.codeUnitAt(0); |
19 } | 23 } |
20 | 24 |
21 /// Append the given relative [suffix] to the given absolute [parent]. | 25 /// Append the given relative [suffix] to the given absolute [parent]. |
22 /// | 26 /// |
23 /// context.append('/path/to', 'foo'); // -> '/path/to/foo' | 27 /// context.append('/path/to', 'foo'); // -> '/path/to/foo' |
24 /// | 28 /// |
25 /// The given [suffix] cannot be an absolute path or use `..`. | 29 /// The given [suffix] cannot be an absolute path or use `..`. |
26 String append(String parent, String suffix) { | 30 String append(String parent, String suffix) { |
27 return '$parent$separator$suffix'; | 31 return '$parent$separator$suffix'; |
(...skipping 20 matching lines...) Expand all Loading... | |
48 /// context.dirname(r'C:\path'); // -> 'C:\' | 52 /// context.dirname(r'C:\path'); // -> 'C:\' |
49 /// context.dirname(r'C:\'); // -> 'C:\' | 53 /// context.dirname(r'C:\'); // -> 'C:\' |
50 String dirname(String path) { | 54 String dirname(String path) { |
51 int firstIndex = path.indexOf(separator); | 55 int firstIndex = path.indexOf(separator); |
52 int lastIndex = path.lastIndexOf(separator); | 56 int lastIndex = path.lastIndexOf(separator); |
53 return lastIndex == firstIndex | 57 return lastIndex == firstIndex |
54 ? path.substring(0, firstIndex + 1) | 58 ? path.substring(0, firstIndex + 1) |
55 : path.substring(0, lastIndex); | 59 : path.substring(0, lastIndex); |
56 } | 60 } |
57 | 61 |
62 /// Return `true` if the given [path] is valid. | |
63 /// | |
64 /// context.isNormalized('/foo/bar'); // -> true | |
65 /// context.isNormalized('/foo/bar/../baz'); // -> false | |
66 bool isValid(String path) { | |
67 return _isAbsolute(path) && _isNormalized(path); | |
68 } | |
69 | |
58 /// Return `true` if [child] is a path beneath [parent], and `false` | 70 /// Return `true` if [child] is a path beneath [parent], and `false` |
59 /// otherwise. Both the [child] and [parent] paths must be absolute paths. | 71 /// otherwise. Both the [child] and [parent] paths must be absolute paths. |
60 /// | 72 /// |
61 /// context.isWithin('/root/path', '/root/path/a'); // -> true | 73 /// context.isWithin('/root/path', '/root/path/a'); // -> true |
62 /// context.isWithin('/root/path', '/root/other'); // -> false | 74 /// context.isWithin('/root/path', '/root/other'); // -> false |
63 /// context.isWithin('/root/path', '/root/path'); // -> false | 75 /// context.isWithin('/root/path', '/root/path'); // -> false |
64 bool isWithin(String parent, String child) { | 76 bool isWithin(String parent, String child) { |
65 int parentLength = parent.length; | 77 int parentLength = parent.length; |
66 int childLength = child.length; | 78 int childLength = child.length; |
67 if (parentLength >= childLength) { | 79 if (parentLength >= childLength) { |
(...skipping 19 matching lines...) Expand all Loading... | |
87 /// context.relative('/root/path', '/root/path/a/b.dart'); // -> 'a/b.dart ' | 99 /// context.relative('/root/path', '/root/path/a/b.dart'); // -> 'a/b.dart ' |
88 /// context.relative('/root/path', '/root/other.dart'); // -> null | 100 /// context.relative('/root/path', '/root/other.dart'); // -> null |
89 String suffix(String parent, String child) { | 101 String suffix(String parent, String child) { |
90 String parentPrefix = parent + separator; | 102 String parentPrefix = parent + separator; |
91 if (child.startsWith(parentPrefix)) { | 103 if (child.startsWith(parentPrefix)) { |
92 return child.substring(parentPrefix.length); | 104 return child.substring(parentPrefix.length); |
93 } | 105 } |
94 return null; | 106 return null; |
95 } | 107 } |
96 | 108 |
109 /// Return `true` if the given [path] is absolute. | |
110 /// | |
111 /// _isAbsolute('/foo/bar'); // -> true | |
112 /// _isAbsolute('/'); // -> true | |
113 /// _isAbsolute('foo/bar'); // -> false | |
114 /// _isAbsolute('C:\foo\bar'); // -> true | |
115 /// _isAbsolute('C:\'); // -> true | |
116 /// _isAbsolute('foo\bar'); // -> false | |
117 bool _isAbsolute(String path) { | |
118 if (_isWindows) { | |
119 return path.length >= 3 && | |
120 _isAlphabetic(path.codeUnitAt(0)) && | |
121 path.codeUnitAt(1) == _COLON && | |
122 path.codeUnitAt(2) == _separatorChar; | |
123 } else { | |
124 return path.isNotEmpty && path.codeUnitAt(0) == _separatorChar; | |
125 } | |
126 } | |
127 | |
128 | |
129 /// Return `true` if the given absolute [path] is normalized. | |
130 /// | |
131 /// _isAbsolute('/foo/bar'); // -> true | |
132 /// _isAbsolute('/foo/..bar'); // -> true | |
133 /// _isAbsolute('/'); // -> true | |
134 /// _isAbsolute('/foo/bar/../baz'); // -> false | |
135 /// _isAbsolute('/foo/bar/..'); // -> false | |
Brian Wilkerson
2015/12/09 22:58:20
Wrong method name in examples.
| |
136 bool _isNormalized(String path) { | |
137 int periodCount = 0; | |
138 for (int c in path.codeUnits) { | |
139 if (c == _PERIOD) { | |
140 periodCount++; | |
141 continue; | |
142 } | |
143 if (c == _separatorChar) { | |
144 if (periodCount == 1 || periodCount == 2) { | |
145 return false; | |
146 } | |
147 } | |
148 periodCount = 0; | |
149 } | |
150 return periodCount != 1 && periodCount != 2; | |
151 } | |
152 | |
153 /// Returns whether [char] is the code for an ASCII letter (uppercase or | |
154 /// lowercase). | |
155 static bool _isAlphabetic(int char) { | |
156 return char >= _UPPER_A && char <= _UPPER_Z || | |
157 char >= _LOWER_A && char <= _LOWER_Z; | |
158 } | |
159 | |
97 /// Return `true` if [str] starts with the given [prefix]. | 160 /// Return `true` if [str] starts with the given [prefix]. |
98 /// | 161 /// |
99 /// The check is done from the end of [prefix], because absolute paths | 162 /// The check is done from the end of [prefix], because absolute paths |
100 /// usually have the same prefix, e.g. the user's home directory. | 163 /// usually have the same prefix, e.g. the user's home directory. |
101 static bool _startsWithUnsafe(String str, String prefix) { | 164 static bool _startsWithUnsafe(String str, String prefix) { |
102 int len = prefix.length; | 165 int len = prefix.length; |
103 for (int i = len - 1; i >= 0; i--) { | 166 for (int i = len - 1; i >= 0; i--) { |
104 if (str.codeUnitAt(i) != prefix.codeUnitAt(i)) { | 167 if (str.codeUnitAt(i) != prefix.codeUnitAt(i)) { |
105 return false; | 168 return false; |
106 } | 169 } |
107 } | 170 } |
108 return true; | 171 return true; |
109 } | 172 } |
110 } | 173 } |
OLD | NEW |