Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 part of dart.core; | 5 part of dart.core; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A parsed URI, as specified by RFC-3986, http://tools.ietf.org/html/rfc3986. | 8 * A parsed URI, as specified by RFC-3986, http://tools.ietf.org/html/rfc3986. |
| 9 */ | 9 */ |
| 10 class Uri { | 10 class Uri { |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 256 | 256 |
| 257 return new Uri(scheme: scheme, | 257 return new Uri(scheme: scheme, |
| 258 userInfo: userInfo, | 258 userInfo: userInfo, |
| 259 host: host, | 259 host: host, |
| 260 port: port, | 260 port: port, |
| 261 pathSegments: unencodedPath.split("/"), | 261 pathSegments: unencodedPath.split("/"), |
| 262 queryParameters: queryParameters); | 262 queryParameters: queryParameters); |
| 263 } | 263 } |
| 264 | 264 |
| 265 /** | 265 /** |
| 266 * Creates a new `file` URI from an absolute or relative file path. | |
|
ahe
2013/08/06 14:14:30
I think backquotes are for code snippets, I'm not
Søren Gjesse
2013/08/07 12:08:00
Done.
| |
| 267 * | |
| 268 * The file path is passed in [path]. | |
| 269 * | |
| 270 * This path is interpreted using either Windows or non-Windows | |
| 271 * semantics. For Windows semantics the backslash or slash separator | |
| 272 * is used to separate path segments. | |
|
ahe
2013/08/06 14:14:30
Remove the rest of this paragraph from "For Window
Søren Gjesse
2013/08/07 12:08:00
Done.
| |
| 273 * | |
| 274 * With non-Windows semantics the slash `/` is used to separate path | |
|
ahe
2013/08/06 14:14:30
I'm not sure about this use of backquotes either.
Søren Gjesse
2013/08/07 12:08:00
Ended up using ("/") and ("\").
| |
| 275 * segments. | |
| 276 * | |
| 277 * With Windows semantics both the backslash `\` and the slash `/` | |
| 278 * are is used to separate path segments. An exception is when the | |
| 279 * path is prefixed with `\\?\` in which case only the backslash `\` | |
|
ahe
2013/08/06 14:14:30
You could replace "is prefixed with" by "starts wi
Søren Gjesse
2013/08/07 12:08:00
Thanks for rephrasing.
| |
| 280 * is treated as a path separator. | |
|
ahe
2013/08/06 14:14:30
Ditto for the backquotes in above paragraph.
Søren Gjesse
2013/08/07 12:08:00
Done.
| |
| 281 * | |
| 282 * If the path starts with a path separator an absolute URI is | |
| 283 * created. Otherwise a relative URI is created. One exception from | |
| 284 * this rule is that with Windows semantics and a path which starts | |
| 285 * with a drive letter then an absolute URI is created. | |
|
ahe
2013/08/06 14:14:30
This specification does not match the example belo
Søren Gjesse
2013/08/07 12:08:00
Extended the comment to say that the drive letter
| |
| 286 * | |
| 287 * The default for whether to use Windows or non-Windows semantics | |
| 288 * determined from the platform Dart is running on. When running in | |
| 289 * the standalone VM this is detected by the VM based on the | |
| 290 * operating system. When running in the browser non-Windows | |
|
ahe
2013/08/06 14:14:30
"the browser" -> "a browser".
Søren Gjesse
2013/08/07 12:08:00
Done.
| |
| 291 * semantics is always used. | |
| 292 * | |
| 293 * To override the automatic detection of which semantics to use pass | |
| 294 * a value for [windowsPath]. Passing `true` will use Windows | |
| 295 * semantics and passing `false` will use non-Windows semantics. | |
| 296 * | |
| 297 * Examples using non-Windows semantics (resulting URI in comment): | |
| 298 * | |
| 299 * new Uri.file("xxx/yyy"); // xxx/yyy | |
| 300 * new Uri.file("xxx/yyy/"); // xxx/yyy/ | |
| 301 * new Uri.file("/xxx/yyy"); // file:///xxx/yyy | |
| 302 * new Uri.file("/xxx/yyy/"); // file:///xxx/yyy/ | |
| 303 * new Uri.file("C:"); // C: | |
| 304 * | |
| 305 * Examples using Windows semantics (resulting URI in comment): | |
| 306 * | |
| 307 * new Uri.file(r"xxx\yyy"); // xxx/yyy | |
| 308 * new Uri.file(r"xxx\yyy\"); // xxx/yyy/ | |
| 309 * new Uri.file(r"\xxx\yyy"); // file:///xxx/yyy | |
| 310 * new Uri.file(r"\xxx\yyy/"); // file:///xxx/yyy/ | |
| 311 * new Uri.file(r"C:\xxx\yyy"); // file:///C:/xxx/yyy | |
| 312 * new Uri.file(r"C:xxx\yyy"); // file:///C:/xxx/yyy | |
| 313 * new Uri.file(r"\\server\share\file"); // file://server/share/file | |
| 314 * new Uri.file(r"C:"); // Throws as path with drive letter is not absolu te. | |
|
ahe
2013/08/06 14:14:30
Long line.
Søren Gjesse
2013/08/07 12:08:00
Done.
| |
| 315 * | |
| 316 * If the path passed is not a legal file path [ArgumentError] is thrown. | |
| 317 */ | |
| 318 factory Uri.file(String path, {bool windowsPath}) { | |
| 319 windowsPath = windowsPath == null ? Uri._isWindows : windowsPath; | |
|
ahe
2013/08/06 14:14:30
Remove Uri. prefix.
Søren Gjesse
2013/08/07 12:08:00
Done.
| |
| 320 return windowsPath ? _makeWindowsFileUrl(path) : _makeFileUri(path); | |
| 321 } | |
| 322 | |
| 323 external static bool get _isWindowsPlatform; | |
| 324 | |
| 325 static final bool _isWindows = _isWindowsPlatform; | |
|
ahe
2013/08/06 14:14:30
For dart2js, this code is suboptimal. I think it w
Søren Gjesse
2013/08/07 12:08:00
Done.
| |
| 326 | |
| 327 // Characters which are not allowed in file names on Windows. | |
| 328 static final _windowsPathReservedCharacters = [ | |
| 329 _DOUBLE_QUOTE, | |
| 330 _ASTERISK, | |
| 331 _SLASH, | |
| 332 _COLON, // Colon is only allowed after drive letter. | |
| 333 _LESS, | |
| 334 _GREATER, | |
| 335 _QUESTION, | |
| 336 _BACKSLASH, // Backslash can only be separator. | |
| 337 _BAR, | |
| 338 ]; | |
| 339 | |
| 340 static _checkNonWindowsPathReservedCharacters(List<String> segments, | |
| 341 bool argumentError) { | |
|
ahe
2013/08/06 14:14:30
Indentation.
Søren Gjesse
2013/08/07 12:08:00
Done.
| |
| 342 for (var segment in segments) { | |
| 343 if (segment.contains("/")) { | |
| 344 if (argumentError) { | |
| 345 throw new ArgumentError("Illegal path character $segment"); | |
| 346 } else { | |
| 347 throw new UnsupportedError("Illegal path character $segment"); | |
| 348 } | |
| 349 } | |
| 350 } | |
| 351 } | |
| 352 | |
| 353 static _checkWindowsPathReservedCharacters(List<String> segments, | |
| 354 bool argumentError, | |
| 355 [int firstSegment = 0]) { | |
| 356 for (int i = firstSegment; i < segments.length; i++) { | |
| 357 var segment = segments[i]; | |
| 358 for (int j = 0; j < segment.length; j++) { | |
| 359 if (_windowsPathReservedCharacters.contains(segment.codeUnitAt(j))) { | |
|
ahe
2013/08/06 14:14:30
I suspect that regular expressions would be faster
Søren Gjesse
2013/08/07 12:08:00
Done.
| |
| 360 if (argumentError) { | |
| 361 throw new ArgumentError("Illegal path character ${segment[j]}"); | |
| 362 } else { | |
| 363 throw new UnsupportedError("Illegal path character ${segment[j]}"); | |
| 364 } | |
| 365 } | |
| 366 } | |
| 367 } | |
| 368 } | |
| 369 | |
| 370 static _checkWindowsDriveLetter(int charCode, bool argumentError) { | |
| 371 if ((_UPPER_CASE_A <= charCode && charCode <= _UPPER_CASE_Z) || | |
| 372 (_LOWER_CASE_A <= charCode && charCode <= _LOWER_CASE_Z)) { | |
| 373 return; | |
| 374 } | |
| 375 if (argumentError) { | |
| 376 throw new ArgumentError("Illegal drive letter " + | |
| 377 new String.fromCharCode(charCode)); | |
| 378 } else { | |
| 379 throw new UnsupportedError("Illegal drive letter " + | |
| 380 new String.fromCharCode(charCode)); | |
| 381 } | |
| 382 } | |
| 383 | |
| 384 static _makeFileUri(String path) { | |
| 385 String sep = "/"; | |
| 386 if (path.length > 0 && path[0] == sep) { | |
| 387 // Absolute file:// URI. | |
| 388 return new Uri(scheme: "file", pathSegments: path.split(sep)); | |
| 389 } else { | |
| 390 // Relative URI. | |
| 391 return new Uri(pathSegments: path.split(sep)); | |
| 392 } | |
| 393 } | |
| 394 | |
| 395 static _makeWindowsFileUrl(String path) { | |
| 396 if (path.startsWith("\\\\?\\")) { | |
| 397 if (path.startsWith("\\\\?\\UNC\\")) { | |
| 398 path = "\\${path.substring(7)}"; | |
| 399 } else { | |
| 400 path = path.substring(4); | |
| 401 if (path.length < 3 || | |
| 402 path.codeUnitAt(1) != _COLON || | |
| 403 path.codeUnitAt(2) != _BACKSLASH) { | |
| 404 throw new ArgumentError( | |
| 405 "Windows paths with \\\\?\\ prefix must be absolute"); | |
| 406 } | |
| 407 } | |
| 408 } else { | |
| 409 path = path.replaceAll("/", "\\"); | |
| 410 } | |
| 411 String sep = "\\"; | |
| 412 if (path.length > 1 && path[1] == ":") { | |
| 413 _checkWindowsDriveLetter(path.codeUnitAt(0), true); | |
| 414 if (path.length == 2 || path.codeUnitAt(2) != _BACKSLASH) { | |
| 415 throw new ArgumentError( | |
| 416 "Windows paths with drive letter must be absolute"); | |
| 417 } | |
| 418 // Absolute file://C:/ URI. | |
| 419 var pathSegments = path.split(sep); | |
| 420 _checkWindowsPathReservedCharacters(pathSegments, true, 1); | |
| 421 return new Uri(scheme: "file", pathSegments: pathSegments); | |
| 422 } | |
| 423 | |
| 424 if (path.length > 0 && path[0] == sep) { | |
| 425 if (path.length > 1 && path[1] == sep) { | |
| 426 // Absolute file:// URI with host. | |
| 427 int pathStart = path.indexOf("\\", 2); | |
| 428 String hostPart = | |
| 429 pathStart == -1 ? path.substring(2) : path.substring(2, pathStart); | |
| 430 String pathPart = | |
| 431 pathStart == -1 ? "" : path.substring(pathStart + 1); | |
| 432 var pathSegments = pathPart.split(sep); | |
| 433 _checkWindowsPathReservedCharacters(pathSegments, true); | |
| 434 return new Uri( | |
| 435 scheme: "file", host: hostPart, pathSegments: pathSegments); | |
| 436 } else { | |
| 437 // Absolute file:// URI. | |
| 438 var pathSegments = path.split(sep); | |
| 439 _checkWindowsPathReservedCharacters(pathSegments, true); | |
| 440 return new Uri(scheme: "file", pathSegments: pathSegments); | |
| 441 } | |
| 442 } else { | |
| 443 // Relative URI. | |
| 444 var pathSegments = path.split(sep); | |
| 445 _checkWindowsPathReservedCharacters(pathSegments, true); | |
| 446 return new Uri(pathSegments: pathSegments); | |
| 447 } | |
| 448 } | |
| 449 | |
| 450 /** | |
| 266 * Returns the URI path split into its segments. Each of the | 451 * Returns the URI path split into its segments. Each of the |
| 267 * segments in the returned list have been decoded. If the path is | 452 * segments in the returned list have been decoded. If the path is |
| 268 * empty the empty list will be returned. A leading slash `/` does | 453 * empty the empty list will be returned. A leading slash `/` does |
| 269 * not affect the segments returned. | 454 * not affect the segments returned. |
| 270 * | 455 * |
| 271 * The returned list is unmodifiable and will throw [UnsupportedError] on any | 456 * The returned list is unmodifiable and will throw [UnsupportedError] on any |
| 272 * calls that would mutate it. | 457 * calls that would mutate it. |
| 273 */ | 458 */ |
| 274 List<String> get pathSegments { | 459 List<String> get pathSegments { |
| 275 if (_pathSegments == null) { | 460 if (_pathSegments == null) { |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 644 throw new StateError("Cannot use origin without a scheme: $this"); | 829 throw new StateError("Cannot use origin without a scheme: $this"); |
| 645 } | 830 } |
| 646 if (scheme != "http" && scheme != "https") { | 831 if (scheme != "http" && scheme != "https") { |
| 647 throw new StateError( | 832 throw new StateError( |
| 648 "Origin is only applicable schemes http and https: $this"); | 833 "Origin is only applicable schemes http and https: $this"); |
| 649 } | 834 } |
| 650 if (port == 0) return "$scheme://$host"; | 835 if (port == 0) return "$scheme://$host"; |
| 651 return "$scheme://$host:$port"; | 836 return "$scheme://$host:$port"; |
| 652 } | 837 } |
| 653 | 838 |
| 839 /** | |
| 840 * Returns the file path from a file URI. | |
| 841 * | |
| 842 * The returned path has either Windows or non-Windows | |
| 843 * semantics. | |
| 844 * | |
| 845 * For Windows semantics the backslash separator is used to separate | |
| 846 * path segments. | |
| 847 * | |
| 848 * For non-Windows semantics the slash is used to separate path | |
| 849 * segments. | |
| 850 * | |
| 851 * If the URI is absolute the path starts with a path separator | |
| 852 * unless Windows semantics is used and the first path segment is a | |
| 853 * drive letter. When Windows semantics is used a host component in | |
| 854 * the uri in interpreted as a file server and a UNC path is | |
| 855 * returned. | |
| 856 * | |
| 857 * The default for whether to use Windows or non-Windows semantics | |
| 858 * determined from the platform Dart is running on. When running in | |
| 859 * the standalone VM this is detected by the VM based on the | |
| 860 * operating system. When running in the browser non-Windows | |
|
ahe
2013/08/06 14:14:30
the browser -> a browser.
Søren Gjesse
2013/08/07 12:08:00
Done.
| |
| 861 * semantics is always used. | |
| 862 * | |
| 863 * To override the automatic detection of which semantics to use pass | |
| 864 * a value for [windowsPath]. Passing `true` will use Windows | |
| 865 * semantics and passing `false` will use non-Windows semantics. | |
| 866 * | |
| 867 * If the URI ends with a slash (i.e. the last path component is | |
| 868 * empty) the returned file path will also end with a slash. | |
| 869 * | |
| 870 * With Windows semantics URIs starting with a drive letter cannot | |
| 871 * be relative to the current drive on the designated drive. That is | |
| 872 * for the URI `file:///c:abc` calling `toFilePath` will return | |
| 873 * `c:\abc` and *not* `c:abc`. | |
|
ahe
2013/08/06 14:14:30
I thought this would throw.
Søren Gjesse
2013/08/07 12:08:00
It now throws.
As discussed before I was not sure
| |
| 874 * | |
| 875 * Examples using non-Windows semantics (resulting of calling toFilePath in co mment): | |
|
ahe
2013/08/06 14:14:30
Long line.
Søren Gjesse
2013/08/07 12:08:00
Done.
| |
| 876 * | |
| 877 * Uri.parse("xxx/yyy"); // xxx/yyy | |
| 878 * Uri.parse("xxx/yyy/"); // xxx/yyy/ | |
| 879 * Uri.parse("file:///xxx/yyy"); // /xxx/yyy | |
| 880 * Uri.parse("file:///xxx/yyy/"); // /xxx/yyy/ | |
| 881 * Uri.parse("file:///C:"); // /C: | |
| 882 * Uri.parse("file:///C:a"); // /C:a | |
| 883 * | |
| 884 * Examples using Windows semantics (resulting URI in comment): | |
| 885 * | |
| 886 * Uri.parse("xxx/yyy"); // xxx\yyy | |
| 887 * Uri.parse("xxx/yyy/"); // xxx\yyy\ | |
| 888 * Uri.parse("file:///xxx/yyy"); // \xxx\yyy | |
| 889 * Uri.parse("file:///xxx/yyy/"); // \xxx\yyy/ | |
| 890 * Uri.parse("file:///C:/xxx/yyy"); // C:\xxx\yyy | |
| 891 * Uri.parse("file:C:xxx/yyy"); // C:\xxx\yyy | |
| 892 * Uri.parse("file://server/share/file"); // \\server\share\file | |
| 893 * | |
| 894 * If the URI is not a file URI calling this throws | |
| 895 * [UnsupportedError]. | |
| 896 * | |
| 897 * If the URI cannot be converted to a file path calling this throws | |
| 898 * [UnsupportedError]. | |
| 899 */ | |
| 900 String toFilePath({bool windowsPath}) { | |
| 901 if (scheme != "" && scheme != "file") { | |
| 902 throw new UnsupportedError( | |
| 903 "Cannot extract a file path from a $scheme URI"); | |
| 904 } | |
| 905 if (windowsPath == null) windowsPath = _isWindows; | |
| 906 return windowsPath ? _toWindowsFilePath() : _toFilePath(); | |
|
ahe
2013/08/06 14:14:30
You should probably check that all other fields bu
Søren Gjesse
2013/08/07 12:08:00
Done and added tests.
| |
| 907 } | |
| 908 | |
| 909 String _toFilePath() { | |
| 910 if (host != "") { | |
| 911 throw new UnsupportedError( | |
| 912 "Cannot extract a non-Windows file path from a file URI " | |
| 913 "with an authority"); | |
| 914 } | |
| 915 _checkNonWindowsPathReservedCharacters(pathSegments, false); | |
| 916 var result = new StringBuffer(); | |
| 917 if (isAbsolute) result.write("/"); | |
| 918 result.writeAll(pathSegments, "/"); | |
| 919 return result.toString(); | |
| 920 } | |
| 921 | |
| 922 String _toWindowsFilePath() { | |
| 923 bool hasDriveLetter = false; | |
| 924 var segments = pathSegments; | |
| 925 if (segments.length > 0 && | |
| 926 segments[0].length >= 2 && | |
| 927 segments[0].codeUnitAt(1) == _COLON) { | |
| 928 _checkWindowsDriveLetter(segments[0].codeUnitAt(0), false); | |
| 929 if (segments[0].length > 2) { | |
| 930 var originalSegments = segments; | |
| 931 segments = new List<String>(originalSegments.length + 1); | |
| 932 segments[0] = originalSegments[0].substring(0, 2); | |
| 933 segments[1] = originalSegments[0].substring(2); | |
| 934 segments.setRange(2, segments.length, originalSegments, 1); | |
| 935 } | |
| 936 _checkWindowsPathReservedCharacters(segments, false, 1); | |
| 937 hasDriveLetter = true; | |
| 938 } else { | |
| 939 _checkWindowsPathReservedCharacters(segments, false); | |
| 940 } | |
| 941 var result = new StringBuffer(); | |
| 942 if (isAbsolute && !hasDriveLetter) result.write("\\"); | |
| 943 if (host != "") { | |
| 944 result.write("\\"); | |
| 945 result.write(host); | |
| 946 result.write("\\"); | |
| 947 } | |
| 948 result.writeAll(segments, "\\"); | |
| 949 if (hasDriveLetter && segments.length == 1) result.write("\\"); | |
| 950 return result.toString(); | |
| 951 } | |
| 952 | |
| 654 void _writeAuthority(StringSink ss) { | 953 void _writeAuthority(StringSink ss) { |
| 655 _addIfNonEmpty(ss, userInfo, userInfo, "@"); | 954 _addIfNonEmpty(ss, userInfo, userInfo, "@"); |
| 656 ss.write(host == null ? "null" : | 955 ss.write(host == null ? "null" : |
| 657 host.contains(':') ? '[$host]' : host); | 956 host.contains(':') ? '[$host]' : host); |
| 658 if (port != 0) { | 957 if (port != 0) { |
| 659 ss.write(":"); | 958 ss.write(":"); |
| 660 ss.write(port.toString()); | 959 ss.write(port.toString()); |
| 661 } | 960 } |
| 662 } | 961 } |
| 663 | 962 |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 833 var key = element.substring(0, index); | 1132 var key = element.substring(0, index); |
| 834 var value = element.substring(index + 1); | 1133 var value = element.substring(index + 1); |
| 835 map[Uri.decodeQueryComponent(key, decode: decode)] = | 1134 map[Uri.decodeQueryComponent(key, decode: decode)] = |
| 836 decodeQueryComponent(value, decode: decode); | 1135 decodeQueryComponent(value, decode: decode); |
| 837 } | 1136 } |
| 838 return map; | 1137 return map; |
| 839 }); | 1138 }); |
| 840 } | 1139 } |
| 841 | 1140 |
| 842 // Frequently used character codes. | 1141 // Frequently used character codes. |
| 1142 static const int _DOUBLE_QUOTE = 0x22; | |
| 843 static const int _PERCENT = 0x25; | 1143 static const int _PERCENT = 0x25; |
| 1144 static const int _ASTERISK = 0x2A; | |
| 844 static const int _PLUS = 0x2B; | 1145 static const int _PLUS = 0x2B; |
| 845 static const int _SLASH = 0x2F; | 1146 static const int _SLASH = 0x2F; |
| 846 static const int _ZERO = 0x30; | 1147 static const int _ZERO = 0x30; |
| 847 static const int _NINE = 0x39; | 1148 static const int _NINE = 0x39; |
| 848 static const int _COLON = 0x3A; | 1149 static const int _COLON = 0x3A; |
| 1150 static const int _LESS = 0x3C; | |
| 1151 static const int _GREATER = 0x3E; | |
| 1152 static const int _QUESTION = 0x3F; | |
| 849 static const int _AT_SIGN = 0x40; | 1153 static const int _AT_SIGN = 0x40; |
| 850 static const int _UPPER_CASE_A = 0x41; | 1154 static const int _UPPER_CASE_A = 0x41; |
| 851 static const int _UPPER_CASE_F = 0x46; | 1155 static const int _UPPER_CASE_F = 0x46; |
| 1156 static const int _UPPER_CASE_Z = 0x5A; | |
| 1157 static const int _BACKSLASH = 0x5C; | |
| 852 static const int _LOWER_CASE_A = 0x61; | 1158 static const int _LOWER_CASE_A = 0x61; |
| 853 static const int _LOWER_CASE_F = 0x66; | 1159 static const int _LOWER_CASE_F = 0x66; |
| 1160 static const int _LOWER_CASE_Z = 0x7A; | |
| 1161 static const int _BAR = 0x7C; | |
| 854 | 1162 |
| 855 /** | 1163 /** |
| 856 * This is the internal implementation of JavaScript's encodeURI function. | 1164 * This is the internal implementation of JavaScript's encodeURI function. |
| 857 * It encodes all characters in the string [text] except for those | 1165 * It encodes all characters in the string [text] except for those |
| 858 * that appear in [canonicalTable], and returns the escaped string. | 1166 * that appear in [canonicalTable], and returns the escaped string. |
| 859 */ | 1167 */ |
| 860 static String _uriEncode(List<int> canonicalTable, | 1168 static String _uriEncode(List<int> canonicalTable, |
| 861 String text, | 1169 String text, |
| 862 {bool spaceToPlus: false}) { | 1170 {bool spaceToPlus: false}) { |
| 863 byteToHex(int v) { | 1171 byteToHex(int v) { |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1145 void clear() { | 1453 void clear() { |
| 1146 throw new UnsupportedError("Cannot modify an unmodifiable map"); | 1454 throw new UnsupportedError("Cannot modify an unmodifiable map"); |
| 1147 } | 1455 } |
| 1148 void forEach(void f(K key, V value)) => _map.forEach(f); | 1456 void forEach(void f(K key, V value)) => _map.forEach(f); |
| 1149 Iterable<K> get keys => _map.keys; | 1457 Iterable<K> get keys => _map.keys; |
| 1150 Iterable<V> get values => _map.values; | 1458 Iterable<V> get values => _map.values; |
| 1151 int get length => _map.length; | 1459 int get length => _map.length; |
| 1152 bool get isEmpty => _map.isEmpty; | 1460 bool get isEmpty => _map.isEmpty; |
| 1153 bool get isNotEmpty => _map.isNotEmpty; | 1461 bool get isNotEmpty => _map.isNotEmpty; |
| 1154 } | 1462 } |
| OLD | NEW |