Version 2.16.0-98.0.dev
Merge commit '1c1f518bff015e6518b86fc3196b8796d45c3d08' into 'dev'
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 024368c..169abef 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -160,7 +160,7 @@
if (!_isRedirectingConstructor(c)) c
];
- assert(constructors.isNotEmpty);
+ assert(constructors.isNotEmpty || cls.isMixinDeclaration);
// Move field initializers to constructors.
// Clone AST for all constructors except the first.
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/mixin_with_field_test.dart b/pkg/vm/testcases/transformations/type_flow/transformer/mixin_with_field_test.dart
new file mode 100644
index 0000000..bca77d0
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/mixin_with_field_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for dartbug.com/47822
+
+mixin M {
+ int x = (() => 7)();
+}
+
+class C with M {}
+
+main() {
+ print(C().x);
+}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/mixin_with_field_test.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/mixin_with_field_test.dart.expect
new file mode 100644
index 0000000..14d7ff0
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/mixin_with_field_test.dart.expect
@@ -0,0 +1,20 @@
+library #lib /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+abstract class M extends core::Object /*isMixinDeclaration*/ {
+}
+abstract class _C&Object&M extends core::Object implements self::M /*isAnonymousMixin,isEliminatedMixin*/ {
+[@vm.inferred-type.metadata=int?] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2] field core::int x;
+ synthetic constructor •() → self::_C&Object&M
+ : self::_C&Object&M::x = (() → core::int => 7)(){() → core::int}, super core::Object::•()
+ ;
+}
+class C extends self::_C&Object&M {
+ synthetic constructor •() → self::C
+ : super self::_C&Object&M::•()
+ ;
+}
+static method main() → dynamic {
+ core::print([@vm.direct-call.metadata=#lib::_C&Object&M.x] [@vm.inferred-type.metadata=int?] new self::C::•().{self::_C&Object&M::x}{core::int});
+}
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index 0b42ab7..41d7e23 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -162,6 +162,13 @@
/// The returned iterable will provide the same elements as this iterable,
/// and, after that, the elements of [other], in the same order as in the
/// original iterables.
+ ///
+ /// Example:
+ /// ```dart
+ /// var planets = <String>['Earth', 'Jupiter'];
+ /// var updated = planets.followedBy(['Mars', 'Venus']);
+ /// print(updated); // (Earth, Jupiter, Mars, Venus)
+ /// ```
Iterable<E> followedBy(Iterable<E> other) {
var self = this; // TODO(lrn): Remove when we can promote `this`.
if (self is EfficientLengthIterable<E>) {
@@ -189,13 +196,24 @@
/// For example, [elementAt] may call `toElement` only once.
///
/// Equivalent to:
- /// ```dart
+ /// ```
/// Iterable<T> map<T>(T toElement(E e)) sync* {
/// for (var value in this) {
/// yield toElement(value);
/// }
/// }
/// ```
+ /// Example:
+ /// ```dart import:convert
+ /// var products = jsonDecode('''
+ /// [
+ /// {"name": "Screwdriver", "price": 42.00},
+ /// {"name": "Wingnut", "price": 0.50}
+ /// ]
+ /// ''');
+ /// var values = products.map((product) => product['price'] as double);
+ /// var totalPrice = values.fold(0.0, (a, b) => a + b); // 42.5.
+ /// ```
Iterable<T> map<T>(T toElement(E e)) => MappedIterable<E, T>(this, toElement);
/// Returns a new lazy [Iterable] with all elements that satisfy the
@@ -210,6 +228,14 @@
/// Iterating will not cache results, and thus iterating multiple times over
/// the returned [Iterable] may invoke the supplied
/// function [test] multiple times on the same element.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// var result = numbers.where((x) => x < 5); // (1, 2, 3)
+ /// result = numbers.where((x) => x > 5); // (6, 7)
+ /// result = numbers.where((x) => x.isEven); // (2, 6)
+ /// ```
Iterable<E> where(bool test(E element)) => WhereIterable<E>(this, test);
/// Returns a new lazy [Iterable] with all elements that have type [T].
@@ -233,17 +259,18 @@
///
/// Example:
/// ```dart
- /// var pairs = [[1, 2], [3, 4]];
- /// var flattened = pairs.expand((pair) => pair).toList();
- /// print(flattened); // => [1, 2, 3, 4];
+ /// Iterable<int> count(int n) sync* {
+ /// for (var i = 1; i <= n; i++) {
+ /// yield i;
+ /// }
+ /// }
///
- /// var input = [1, 2, 3];
- /// var duplicated = input.expand((i) => [i, i]).toList();
- /// print(duplicated); // => [1, 1, 2, 2, 3, 3]
+ /// var numbers = [1, 3, 0, 2];
+ /// print(numbers.expand(count)); // (1, 1, 2, 3, 1, 2)
/// ```
///
/// Equivalent to:
- /// ```dart
+ /// ```
/// Iterable<T> expand<T>(Iterable<T> toElements(E e)) sync* {
/// for (var value in this) {
/// yield* toElements(value);
@@ -267,6 +294,15 @@
/// (see [Set.identity]) that its `contains` uses.
/// Likewise the `Iterable` returned by a [Map.keys] call
/// should use the same equality that the `Map` uses for keys.
+ ///
+ /// Example:
+ /// ```dart
+ /// final gasPlanets = <int, String>{1: 'Jupiter', 2: 'Saturn'};
+ /// final containsOne = gasPlanets.keys.contains(1); // true
+ /// final containsFive = gasPlanets.keys.contains(5); // false
+ /// final containsJupiter = gasPlanets.values.contains('Jupiter'); // true
+ /// final containsMercury = gasPlanets.values.contains('Mercury'); // false
+ /// ```
bool contains(Object? element) {
for (E e in this) {
if (e == element) return true;
@@ -275,6 +311,16 @@
}
/// Invokes [action] on each element of this iterable in iteration order.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 6, 7];
+ /// numbers.forEach(print);
+ /// // 1
+ /// // 2
+ /// // 6
+ /// // 7
+ /// ```
void forEach(void action(E element)) {
for (E element in this) action(element);
}
@@ -288,7 +334,7 @@
/// Otherwise this method starts with the first element from the iterator,
/// and then combines it with the remaining elements in iteration order,
/// as if by:
- /// ```dart
+ /// ```
/// E value = iterable.first;
/// iterable.skip(1).forEach((element) {
/// value = combine(value, element);
@@ -297,7 +343,9 @@
/// ```
/// Example of calculating the sum of an iterable:
/// ```dart
- /// iterable.reduce((value, element) => value + element);
+ /// final numbers = <double>[10, 2, 5, 0.5];
+ /// final result = numbers.reduce((value, element) => value + element);
+ /// print(result); // 17.5
/// ```
E reduce(E combine(E value, E element)) {
Iterator<E> iterator = this.iterator;
@@ -317,7 +365,7 @@
/// Uses [initialValue] as the initial value,
/// then iterates through the elements and updates the value with
/// each element using the [combine] function, as if by:
- /// ```dart
+ /// ```
/// var value = initialValue;
/// for (E element in this) {
/// value = combine(value, element);
@@ -326,7 +374,11 @@
/// ```
/// Example of calculating the sum of an iterable:
/// ```dart
- /// iterable.fold(0, (prev, element) => prev + element);
+ /// final numbers = <double>[10, 2, 5, 0.5];
+ /// const initialValue = 100.0;
+ /// final result = numbers.fold<double>(
+ /// initialValue, (previousValue, element) => previousValue + element);
+ /// print(result); // 117.5
/// ```
T fold<T>(T initialValue, T combine(T previousValue, E element)) {
var value = initialValue;
@@ -338,6 +390,14 @@
///
/// Checks every element in iteration order, and returns `false` if
/// any of them make [test] return `false`, otherwise returns `true`.
+ ///
+ /// Example:
+ /// ```dart
+ /// final planetsByMass = <double, String>{0.06: 'Mercury', 0.81: 'Venus',
+ /// 0.11: 'Mars'};
+ /// // Checks whether all keys are smaller than 1.
+ /// final every = planetsByMass.keys.every((key) => key < 1.0); // true
+ /// ```
bool every(bool test(E element)) {
for (E element in this) {
if (!test(element)) return false;
@@ -351,6 +411,13 @@
/// converts each one to a [String] by calling [Object.toString],
/// and then concatenates the strings, with the
/// [separator] string interleaved between the elements.
+ ///
+ /// Example:
+ /// ```dart
+ /// final planetsByMass = <double, String>{0.06: 'Mercury', 0.81: 'Venus',
+ /// 0.11: 'Mars'};
+ /// final joinedNames = planetsByMass.values.join('-'); // Mercury-Venus-Mars
+ /// ```
String join([String separator = ""]) {
Iterator<E> iterator = this.iterator;
if (!iterator.moveNext()) return "";
@@ -373,6 +440,13 @@
///
/// Checks every element in iteration order, and returns `true` if
/// any of them make [test] return `true`, otherwise returns false.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// var result = numbers.any((element) => element >= 5); // true;
+ /// result = numbers.any((element) => element >= 10); // false;
+ /// ```
bool any(bool test(E element)) {
for (E element in this) {
if (test(element)) return true;
@@ -384,6 +458,14 @@
///
/// The elements are in iteration order.
/// The list is fixed-length if [growable] is false.
+ ///
+ /// Example:
+ /// ```dart
+ /// final planets = <int, String>{1: 'Mercury', 2: 'Venus', 3: 'Mars'};
+ /// final keysList = planets.keys.toList(growable: false); // [1, 2, 3]
+ /// final valuesList =
+ /// planets.values.toList(growable: false); // [Mercury, Venus, Mars]
+ /// ```
List<E> toList({bool growable = true}) {
return List<E>.of(this, growable: growable);
}
@@ -395,6 +477,12 @@
/// or it contains one or more elements that are equal.
/// The order of the elements in the set is not guaranteed to be the same
/// as for the iterable.
+ ///
+ /// Example:
+ /// ```dart
+ /// final planets = <int, String>{1: 'Mercury', 2: 'Venus', 3: 'Mars'};
+ /// final valueSet = planets.values.toSet(); // {Mercury, Venus, Mars}
+ /// ```
Set<E> toSet() => Set<E>.of(this);
/// Returns the number of elements in [this].
@@ -415,11 +503,25 @@
/// Whether this collection has no elements.
///
/// May be computed by checking if `iterator.moveNext()` returns `false`.
+ ///
+ /// Example:
+ /// ```dart
+ /// final emptyList = <int>[];
+ /// print(emptyList.isEmpty); // true;
+ /// print(emptyList.iterator.moveNext()); // false
+ /// ```
bool get isEmpty => !iterator.moveNext();
/// Whether this collection has at least one element.
///
/// May be computed by checking if `iterator.moveNext()` returns `true`.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>{1, 2, 3};
+ /// print(numbers.isNotEmpty); // true;
+ /// print(numbers.iterator.moveNext()); // true
+ /// ```
bool get isNotEmpty => !isEmpty;
/// Returns a lazy iterable of the [count] first elements of this iterable.
@@ -431,6 +533,13 @@
/// elements have been seen.
///
/// The `count` must not be negative.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// final result = numbers.take(4); // (1, 2, 3, 5)
+ /// final takeAll = numbers.take(100); // (1, 2, 3, 5, 6, 7)
+ /// ```
Iterable<E> take(int count) {
return TakeIterable<E>(this, count);
}
@@ -443,6 +552,15 @@
/// The elements can be computed by stepping through [iterator] until an
/// element is found where `test(element)` is false. At that point,
/// the returned iterable stops (its `moveNext()` returns false).
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// var result = numbers.takeWhile((x) => x < 5); // (1, 2, 3)
+ /// result = numbers.takeWhile((x) => x != 3); // (1, 2)
+ /// result = numbers.takeWhile((x) => x != 4); // (1, 2, 3, 5, 6, 7)
+ /// result = numbers.takeWhile((x) => x.isOdd); // (1)
+ /// ```
Iterable<E> takeWhile(bool test(E value)) {
return TakeWhileIterable<E>(this, test);
}
@@ -460,6 +578,13 @@
/// through earlier elements, for example when iterating a [List].
/// Such iterables are allowed to ignore the initial skipped elements.
///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// final result = numbers.skip(4); // (6, 7)
+ /// final skipAll = numbers.skip(100); // () - no elements.
+ /// ```
+ ///
/// The [count] must not be negative.
Iterable<E> skip(int count) {
return SkipIterable<E>(this, count);
@@ -475,6 +600,15 @@
/// true. If all elements satisfy `test` the resulting iterable is empty,
/// otherwise it iterates the remaining elements in their original order,
/// starting with the first element for which `test(element)` returns `false`.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// var result = numbers.skipWhile((x) => x < 5); // (5, 6, 7)
+ /// result = numbers.skipWhile((x) => x != 3); // (3, 5, 6, 7)
+ /// result = numbers.skipWhile((x) => x != 4); // ()
+ /// result = numbers.skipWhile((x) => x.isOdd); // (2, 3, 5, 6, 7)
+ /// ```
Iterable<E> skipWhile(bool test(E value)) {
return SkipWhileIterable<E>(this, test);
}
@@ -527,6 +661,15 @@
///
/// Iterates through elements and returns the first to satisfy [test].
///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// var result = numbers.firstWhere((element) => element < 5); // 1
+ /// result = numbers.firstWhere((element) => element > 5); // 6
+ /// result =
+ /// numbers.firstWhere((element) => element > 10, orElse: () => -1); // -1
+ /// ```
+ ///
/// If no element satisfies [test], the result of invoking the [orElse]
/// function is returned.
/// If [orElse] is omitted, it defaults to throwing a [StateError].
@@ -547,6 +690,15 @@
/// checks `test(element)` for each,
/// and finally returns that last one that matched.
///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// var result = numbers.lastWhere((element) => element < 5); // 3
+ /// result = numbers.lastWhere((element) => element > 5); // 7
+ /// result = numbers.lastWhere((element) => element > 10,
+ /// orElse: () => -1); // -1
+ /// ```
+ ///
/// If no element satisfies [test], the result of invoking the [orElse]
/// function is returned.
/// If [orElse] is omitted, it defaults to throwing a [StateError].
@@ -571,6 +723,22 @@
/// If more than one matching element is found, throws [StateError].
/// If no matching element is found, returns the result of [orElse].
/// If [orElse] is omitted, it defaults to throwing a [StateError].
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[2, 2, 10];
+ /// var result = numbers.singleWhere((element) => element > 5); // 10
+ /// ```
+ /// When no matching element is found, the result of calling [orElse] is
+ /// returned instead.
+ /// ```dart continued
+ /// result = numbers.singleWhere((element) => element == 1,
+ /// orElse: () => -1); // -1
+ /// ```
+ /// There must not be more than one matching element.
+ /// ```dart continued
+ /// result = numbers.singleWhere((element) => element == 2); // Throws Error.
+ /// ```
E singleWhere(bool test(E element), {E orElse()?}) {
late E result;
bool foundMatching = false;
@@ -597,6 +765,12 @@
/// May iterate through the elements in iteration order, ignoring the
/// first [index] elements and then returning the next.
/// Some iterables may have a more efficient way to find the element.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// final elementAt = numbers.elementAt(4); // 6
+ /// ```
E elementAt(int index) {
RangeError.checkNotNegative(index, "index");
int elementIndex = 0;
diff --git a/sdk/lib/core/string_buffer.dart b/sdk/lib/core/string_buffer.dart
index 9f5a615..675dcd3 100644
--- a/sdk/lib/core/string_buffer.dart
+++ b/sdk/lib/core/string_buffer.dart
@@ -9,8 +9,71 @@
/// Allows for the incremental building of a string using `write*()` methods.
/// The strings are concatenated to a single string only when [toString] is
/// called.
+///
+/// Example:
+/// ```dart
+/// final buffer = StringBuffer('DART');
+/// print(buffer.length); // 4
+/// ```
+/// To add the string representation of an object, as returned by
+/// [Object.toString], to the buffer, use [write].
+/// Is also used for adding a string directly.
+/// ```
+/// buffer.write(' is open source');
+/// print(buffer.length); // 19
+/// print(buffer); // DART is open source
+///
+/// const int dartYear = 2011;
+/// buffer
+/// ..write(' since ') // Writes a string.
+/// ..write(dartYear); // Writes an int.
+/// print(buffer); // DART is open source since 2011
+/// print(buffer.length); // 30
+/// ```
+/// To add a newline after the object's string representation, use [writeln].
+/// Calling [writeln] with no argument adds a single newline to the buffer.
+/// ```
+/// buffer.writeln(); // Contains "DART is open source since 2011\n".
+/// buffer.writeln('-' * (buffer.length - 1)); // 30 '-'s and a newline.
+/// print(buffer.length); // 62
+/// ```
+/// To write multiple objects to the buffer, use [writeAll].
+/// ```
+/// const separator = '-';
+/// buffer.writeAll(['Dart', 'is', 'fun!'], separator);
+/// print(buffer.length); // 74
+/// print(buffer);
+/// // DART is open source since 2011
+/// // ------------------------------
+/// // Dart-is-fun!
+/// ```
+/// To add the string representation of a Unicode code point, `charCode`,
+/// to the buffer, use [writeCharCode].
+/// ```
+/// buffer.writeCharCode(0x0A); // LF (line feed)
+/// buffer.writeCharCode(0x44); // 'D'
+/// buffer.writeCharCode(0x61); // 'a'
+/// buffer.writeCharCode(0x72); // 'r'
+/// buffer.writeCharCode(0x74); // 't'
+/// print(buffer.length); // 79
+/// ```
+/// To convert the content to a single string, use [toString].
+/// ```
+/// final text = buffer.toString();
+/// print(text);
+/// // DART is open source since 2011
+/// // ------------------------------
+/// // Dart-is-fun!
+/// // Dart
+/// ```
+/// To clear the buffer, so that it can be reused, use [clear].
+/// ```
+/// buffer.clear();
+/// print(buffer.isEmpty); // true
+/// print(buffer.length); // 0
+/// ```
class StringBuffer implements StringSink {
- /// Creates the string buffer with an initial content.
+ /// Creates a string buffer containing the provided [content].
external StringBuffer([Object content = ""]);
/// Returns the length of the content that has been accumulated so far.
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index 543cb5f..cd38662 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -26,20 +26,92 @@
/// A parsed URI, such as a URL.
///
-/// **See also:**
+/// To create a URI with specific components, use [new Uri]:
+/// ```dart
+/// var httpsUri = Uri(
+/// scheme: 'https',
+/// host: 'dart.dev',
+/// path: '/guides/libraries/library-tour',
+/// fragment: 'numbers');
+/// print(httpsUri); // https://dart.dev/guides/libraries/library-tour#numbers
///
+/// httpsUri = Uri(
+/// scheme: 'https',
+/// host: 'example.com',
+/// path: '/page/',
+/// queryParameters: {'search': 'blue', 'limit': '10'});
+/// print(httpsUri); // https://example.com/page/?search=blue&limit=10
+///
+/// final mailtoUri = Uri(
+/// scheme: 'mailto',
+/// path: 'John.Doe@example.com',
+/// queryParameters: {'subject': 'Example'});
+/// print(mailtoUri); // mailto:John.Doe@example.com?subject=Example
+/// ```
+///
+/// ## HTTP and HTTPS URI
+/// To create a URI with https scheme, use [Uri.https] or [Uri.http]:
+/// ```dart
+/// final httpsUri = Uri.https('example.com', 'api/fetch', {'limit': '10'});
+/// print(httpsUri); // https://example.com/api/fetch?limit=10
+/// ```
+/// ## File URI
+/// To create a URI from file path, use [Uri.file]:
+/// ```dart
+/// final fileUriUnix =
+/// Uri.file(r'/home/myself/images/image.png', windows: false);
+/// print(fileUriUnix); // file:///home/myself/images/image.png
+///
+/// final fileUriWindows =
+/// Uri.file(r'C:\Users\myself\Documents\image.png', windows: true);
+/// print(fileUriWindows); // file:///C:/Users/myself/Documents/image.png
+/// ```
+/// If the URI is not a file URI, calling this throws [UnsupportedError].
+///
+/// ## Directory URI
+/// Like [Uri.file] except that a non-empty URI path ends in a slash.
+/// ```dart
+/// final fileDirectory =
+/// Uri.directory('/home/myself/data/image', windows: false);
+/// print(fileDirectory); // file:///home/myself/data/image/
+///
+/// final fileDirectoryWindows = Uri.directory('/data/images', windows: true);
+/// print(fileDirectoryWindows); // file:///data/images/
+/// ```
+///
+/// ## URI from string
+/// To create a URI from string, use [Uri.parse] or [Uri.tryParse]:
+/// ```dart
+/// final uri = Uri.parse(
+/// 'https://dart.dev/guides/libraries/library-tour#utility-classes');
+/// print(uri); // https://dart.dev
+/// print(uri.isScheme('https')); // true
+/// print(uri.origin); // https://dart.dev
+/// print(uri.host); // dart.dev
+/// print(uri.authority); // dart.dev
+/// print(uri.port); // 443
+/// print(uri.path); // guides/libraries/library-tour
+/// print(uri.pathSegments); // [guides, libraries, library-tour]
+/// print(uri.fragment); // utility-classes
+/// print(uri.hasQuery); // false
+/// print(uri.data); // null
+/// ```
+///
+/// **See also:**
/// * [URIs][uris] in the [library tour][libtour]
-/// * [RFC-3986](http://tools.ietf.org/html/rfc3986)
+/// * [RFC-3986](https://tools.ietf.org/html/rfc3986)
+/// * [RFC-2396](https://tools.ietf.org/html/rfc2396)
+/// * [RFC-2045](https://tools.ietf.org/html/rfc2045)
///
/// [uris]: https://dart.dev/guides/libraries/library-tour#uris
/// [libtour]: https://dart.dev/guides/libraries/library-tour
abstract class Uri {
/// The natural base URI for the current platform.
///
- /// When running in a browser this is the current URL of the current page
+ /// When running in a browser, this is the current URL of the current page
/// (from `window.location.href`).
///
- /// When not running in a browser this is the file URI referencing
+ /// When not running in a browser, this is the file URI referencing
/// the current working directory.
external static Uri get base;
@@ -93,7 +165,7 @@
/// When [query] is used, the provided string should be a valid URI query,
/// but invalid characters, other than general delimiters,
/// will be escaped if necessary.
- /// When [queryParameters] is used the query is built from the
+ /// When [queryParameters] is used, the query is built from the
/// provided map. Each key and value in the map is percent-encoded
/// and joined using equal and ampersand characters.
/// A value in the map must be either a string, or an [Iterable] of strings,
@@ -110,8 +182,24 @@
///
/// The fragment component is set through [fragment].
/// It should be a valid URI fragment, but invalid characters other than
- /// general delimiters, are escaped if necessary.
+ /// general delimiters are escaped if necessary.
/// If [fragment] is omitted or `null`, the URI has no fragment part.
+ ///
+ /// Example:
+ /// ```dart
+ /// final httpsUri = Uri(
+ /// scheme: 'https',
+ /// host: 'dart.dev',
+ /// path: 'guides/libraries/library-tour',
+ /// fragment: 'numbers');
+ /// print(httpsUri); // https://dart.dev/guides/libraries/library-tour#numbers
+ ///
+ /// final mailtoUri = Uri(
+ /// scheme: 'mailto',
+ /// path: 'John.Doe@example.com',
+ /// queryParameters: {'subject': 'Example'});
+ /// print(mailtoUri); // mailto:John.Doe@example.com?subject=Example
+ /// ```
factory Uri(
{String? scheme,
String? userInfo,
@@ -125,20 +213,19 @@
/// Creates a new `http` URI from authority, path and query.
///
- /// Examples:
- ///
+ /// Example:
/// ```dart
- /// // http://example.org/path?q=dart.
- /// Uri.http("example.org", "/path", { "q" : "dart" });
+ /// var uri = Uri.http('example.org', '/path', { 'q' : 'dart' });
+ /// print(uri); // http://example.org/path?q=dart
///
- /// // http://user:pass@localhost:8080
- /// Uri.http("user:pass@localhost:8080", "");
+ /// uri = Uri.http('user:password@localhost:8080', '');
+ /// print(uri); // http://user:password@localhost:8080
///
- /// // http://example.org/a%20b
- /// Uri.http("example.org", "a b");
+ /// uri = Uri.http('example.org', 'a b');
+ /// print(uri); // http://example.org/a%20b
///
- /// // http://example.org/a%252F
- /// Uri.http("example.org", "/a%2F");
+ /// uri = Uri.http('example.org', '/a%2F');
+ /// print(uri); // http://example.org/a%252F
/// ```
///
/// The `scheme` is always set to `http`.
@@ -161,6 +248,21 @@
///
/// This constructor is the same as [Uri.http] except for the scheme
/// which is set to `https`.
+ ///
+ /// Example:
+ /// ```dart
+ /// var uri = Uri.https('example.org', '/path', {'q': 'dart'});
+ /// print(uri); // https://example.org/path?q=dart
+ ///
+ /// uri = Uri.https('user:password@localhost:8080', '');
+ /// print(uri); // https://user:password@localhost:8080
+ ///
+ /// uri = Uri.https('example.org', 'a b');
+ /// print(uri); // https://example.org/a%20b
+ ///
+ /// uri = Uri.https('example.org', '/a%2F');
+ /// print(uri); // https://example.org/a%252F
+ /// ```
factory Uri.https(String authority, String unencodedPath,
[Map<String, dynamic>? queryParameters]) = _Uri.https;
@@ -171,7 +273,7 @@
/// This path is interpreted using either Windows or non-Windows
/// semantics.
///
- /// With non-Windows semantics the slash (`/`) is used to separate
+ /// With non-Windows semantics, the slash (`/`) is used to separate
/// path segments in the input [path].
///
/// With Windows semantics, backslash (`\`) and forward-slash (`/`)
@@ -182,14 +284,14 @@
/// If the path starts with a path separator, an absolute URI (with the
/// `file` scheme and an empty authority) is created.
/// Otherwise a relative URI reference with no scheme or authority is created.
- /// One exception from this rule is that when Windows semantics is used
+ /// One exception to this rule is that when Windows semantics is used
/// and the path starts with a drive letter followed by a colon (":") and a
/// path separator, then an absolute URI is created.
///
/// The default for whether to use Windows or non-Windows semantics
- /// determined from the platform Dart is running on. When running in
+ /// is determined from the platform Dart is running on. When running in
/// the standalone VM, this is detected by the VM based on the
- /// operating system. When running in a browser non-Windows semantics
+ /// operating system. When running in a browser, non-Windows semantics
/// is always used.
///
/// To override the automatic detection of which semantics to use pass
@@ -197,51 +299,49 @@
/// semantics and passing `false` will use non-Windows semantics.
///
/// Examples using non-Windows semantics:
- ///
/// ```dart
/// // xxx/yyy
- /// Uri.file("xxx/yyy", windows: false);
+ /// Uri.file('xxx/yyy', windows: false);
///
/// // xxx/yyy/
- /// Uri.file("xxx/yyy/", windows: false);
+ /// Uri.file('xxx/yyy/', windows: false);
///
/// // file:///xxx/yyy
- /// Uri.file("/xxx/yyy", windows: false);
+ /// Uri.file('/xxx/yyy', windows: false);
///
/// // file:///xxx/yyy/
- /// Uri.file("/xxx/yyy/", windows: false);
+ /// Uri.file('/xxx/yyy/', windows: false);
///
/// // C%3A
- /// Uri.file("C:", windows: false);
+ /// Uri.file('C:', windows: false);
/// ```
///
/// Examples using Windows semantics:
- ///
/// ```dart
/// // xxx/yyy
- /// Uri.file(r"xxx\yyy", windows: true);
+ /// Uri.file(r'xxx\yyy', windows: true);
///
/// // xxx/yyy/
- /// Uri.file(r"xxx\yyy\", windows: true);
+ /// Uri.file(r'xxx\yyy\', windows: true);
///
/// file:///xxx/yyy
- /// Uri.file(r"\xxx\yyy", windows: true);
+ /// Uri.file(r'\xxx\yyy', windows: true);
///
/// file:///xxx/yyy/
- /// Uri.file(r"\xxx\yyy/", windows: true);
+ /// Uri.file(r'\xxx\yyy/', windows: true);
///
/// // file:///C:/xxx/yyy
- /// Uri.file(r"C:\xxx\yyy", windows: true);
+ /// Uri.file(r'C:\xxx\yyy', windows: true);
///
/// // This throws an error. A path with a drive letter, but no following
/// // path, is not allowed.
- /// Uri.file(r"C:", windows: true);
+ /// Uri.file(r'C:', windows: true);
///
/// // This throws an error. A path with a drive letter is not absolute.
- /// Uri.file(r"C:xxx\yyy", windows: true);
+ /// Uri.file(r'C:xxx\yyy', windows: true);
///
/// // file://server/share/file
- /// Uri.file(r"\\server\share\file", windows: true);
+ /// Uri.file(r'\\server\share\file', windows: true);
/// ```
///
/// If the path passed is not a valid file path, an error is thrown.
@@ -252,17 +352,27 @@
/// If [path] is not empty, and it doesn't end in a directory separator,
/// then a slash is added to the returned URI's path.
/// In all other cases, the result is the same as returned by `Uri.file`.
+ ///
+ /// Example:
+ /// ```dart
+ /// final fileDirectory = Uri.directory('data/images', windows: false);
+ /// print(fileDirectory); // data/images/
+ ///
+ /// final fileDirectoryWindows =
+ /// Uri.directory(r'C:\data\images', windows: true);
+ /// print(fileDirectoryWindows); // file:///C:/data/images/
+ /// ```
factory Uri.directory(String path, {bool? windows}) = _Uri.directory;
/// Creates a `data:` URI containing the [content] string.
///
- /// Converts the content to a bytes using [encoding] or the charset specified
+ /// Converts the content to bytes using [encoding] or the charset specified
/// in [parameters] (defaulting to US-ASCII if not specified or unrecognized),
/// then encodes the bytes into the resulting data URI.
///
- /// Defaults to encoding using percent-encoding (any non-ASCII or non-URI-valid
- /// bytes is replaced by a percent encoding). If [base64] is true, the bytes
- /// are instead encoded using [base64].
+ /// Defaults to encoding using percent-encoding (any non-ASCII or
+ /// non-URI-valid bytes is replaced by a percent encoding). If [base64] is
+ /// true, the bytes are instead encoded using [base64].
///
/// If [encoding] is not provided and [parameters] has a `charset` entry,
/// that name is looked up using [Encoding.getByName],
@@ -280,6 +390,16 @@
/// as an omitted `charset` parameter defaults to meaning `US-ASCII`.
///
/// To read the content back, use [UriData.contentAsString].
+ ///
+ /// Example:
+ /// ```dart
+ /// final uri = Uri.dataFromString(
+ /// 'example content',
+ /// mimeType: 'text/plain',
+ /// parameters: <String, String>{'search': 'file', 'max': '10'},
+ /// );
+ /// print(uri); // data:;search=name;max=10,example%20content
+ /// ```
factory Uri.dataFromString(String content,
{String? mimeType,
Encoding? encoding,
@@ -307,6 +427,12 @@
/// in the data URI, the character is percent-escaped. If the character is
/// non-ASCII, it is first UTF-8 encoded and then the bytes are percent
/// encoded.
+ ///
+ /// Example:
+ /// ```dart
+ /// final uri = Uri.dataFromBytes([68, 97, 114, 116]);
+ /// print(uri); // data:application/octet-stream;base64,RGFydA==
+ /// ```
factory Uri.dataFromBytes(List<int> bytes,
{String mimeType = "application/octet-stream",
Map<String, String>? parameters,
@@ -336,7 +462,7 @@
/// The user info part of the authority component.
///
- /// Th value is the empty string if there is no user info in the
+ /// The value is the empty string if there is no user info in the
/// authority component.
String get userInfo;
@@ -363,7 +489,7 @@
///
/// The path is the actual substring of the URI representing the path,
/// and it is encoded where necessary. To get direct access to the decoded
- /// path use [pathSegments].
+ /// path, use [pathSegments].
///
/// The path value is the empty string if there is no path component.
String get path;
@@ -372,7 +498,7 @@
///
/// The value is the actual substring of the URI representing the query part,
/// and it is encoded where necessary.
- /// To get direct access to the decoded query use [queryParameters].
+ /// To get direct access to the decoded query, use [queryParameters].
///
/// The value is the empty string if there is no query component.
String get query;
@@ -385,8 +511,8 @@
/// The URI path split into its segments.
///
- /// Each of the segments in the list have been decoded.
- /// If the path is empty the empty list will
+ /// Each of the segments in the list has been decoded.
+ /// If the path is empty, the empty list will
/// be returned. A leading slash `/` does not affect the segments returned.
///
/// The list is unmodifiable and will throw [UnsupportedError] on any
@@ -395,10 +521,11 @@
/// The URI query split into a map according to the rules
/// specified for FORM post in the [HTML 4.01 specification section
- /// 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
+ /// 17.13.4](https://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4
+ /// "HTML 4.01 section 17.13.4").
///
/// Each key and value in the resulting map has been decoded.
- /// If there is no query the empty map is returned.
+ /// If there is no query, the empty map is returned.
///
/// Keys in the query string that have no value are mapped to the
/// empty string.
@@ -407,20 +534,36 @@
/// The [queryParametersAll] getter can provide a map
/// that maps keys to all of their values.
///
+ /// Example:
+ /// ```dart import:convert
+ /// final uri =
+ /// Uri.parse('https://example.com/api/fetch?limit=10,20,30&max=100');
+ /// print(jsonEncode(uri.queryParameters));
+ /// // {"limit":"10,20,30","max":"100"}
+ /// ```
+ ///
/// The map is unmodifiable.
Map<String, String> get queryParameters;
/// Returns the URI query split into a map according to the rules
/// specified for FORM post in the [HTML 4.01 specification section
- /// 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
+ /// 17.13.4](https://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4
+ /// "HTML 4.01 section 17.13.4").
///
/// Each key and value in the resulting map has been decoded. If there is no
- /// query the map is empty.
+ /// query, the map is empty.
///
/// Keys are mapped to lists of their values. If a key occurs only once,
/// its value is a singleton list. If a key occurs with no value, the
/// empty string is used as the value for that occurrence.
///
+ /// Example:
+ /// ```dart import:convert
+ /// final uri =
+ /// Uri.parse('https://example.com/api/fetch?limit=10,20,30&max=100');
+ /// print(jsonEncode(uri.queryParameters)); // {"limit":"10,20,30","max":"100"}
+ /// ```
+ ///
/// The map and the lists it contains are unmodifiable.
Map<String, List<String>> get queryParametersAll;
@@ -462,7 +605,7 @@
/// It is an error if the scheme is not "http" or "https", or if the host name
/// is missing or empty.
///
- /// See: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin
+ /// See: https://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin
String get origin;
/// Whether the scheme of this [Uri] is [scheme].
@@ -472,8 +615,11 @@
///
/// Example:
/// ```dart
- /// var uri = Uri.parse("http://example.com/");
- /// print(uri.isScheme("HTTP")); // Prints true.
+ /// var uri = Uri.parse('http://example.com');
+ /// print(uri.isScheme('HTTP')); // true
+ ///
+ /// final uriNoScheme = Uri(host: 'example.com');
+ /// print(uriNoScheme.isScheme('HTTP')); // false
/// ```
///
/// An empty [scheme] string matches a URI with no scheme
@@ -485,22 +631,22 @@
/// The returned path has either Windows or non-Windows
/// semantics.
///
- /// For non-Windows semantics the slash ("/") is used to separate
+ /// For non-Windows semantics, the slash ("/") is used to separate
/// path segments.
///
- /// For Windows semantics the backslash ("\\") separator is used to
+ /// For Windows semantics, the backslash ("\\") separator is used to
/// separate path segments.
///
- /// If the URI is absolute the path starts with a path separator
+ /// If the URI is absolute, the path starts with a path separator
/// unless Windows semantics is used and the first path segment is a
- /// drive letter. When Windows semantics is used a host component in
+ /// drive letter. When Windows semantics is used, a host component in
/// the uri in interpreted as a file server and a UNC path is
/// returned.
///
/// The default for whether to use Windows or non-Windows semantics
- /// determined from the platform Dart is running on. When running in
- /// the standalone VM this is detected by the VM based on the
- /// operating system. When running in a browser non-Windows semantics
+ /// is determined from the platform Dart is running on. When running in
+ /// the standalone VM, this is detected by the VM based on the
+ /// operating system. When running in a browser, non-Windows semantics
/// is always used.
///
/// To override the automatic detection of which semantics to use pass
@@ -508,10 +654,10 @@
/// semantics and passing `false` will use non-Windows semantics.
///
/// If the URI ends with a slash (i.e. the last path component is
- /// empty) the returned file path will also end with a slash.
+ /// empty), the returned file path will also end with a slash.
///
- /// With Windows semantics URIs starting with a drive letter cannot
- /// be relative to the current drive on the designated drive. That is
+ /// With Windows semantics, URIs starting with a drive letter cannot
+ /// be relative to the current drive on the designated drive. That is,
/// for the URI `file:///c:abc` calling `toFilePath` will throw as a
/// path segment cannot contain colon on Windows.
///
@@ -536,10 +682,10 @@
/// // cannot contain colon on Windows.
/// Uri.parse("file://server/share/file"); // \\server\share\file
/// ```
- /// If the URI is not a file URI calling this throws
+ /// If the URI is not a file URI, calling this throws
/// [UnsupportedError].
///
- /// If the URI cannot be converted to a file path calling this throws
+ /// If the URI cannot be converted to a file path, calling this throws
/// [UnsupportedError].
// TODO(lrn): Deprecate and move functionality to File class or similar.
// The core libraries should not worry about the platform.
@@ -576,31 +722,35 @@
/// Each part that is not provided will default to the corresponding
/// value from this `Uri` instead.
///
- /// This method is different from [Uri.resolve] which overrides in a
+ /// This method is different from [Uri.resolve], which overrides in a
/// hierarchical manner,
/// and can instead replace each part of a `Uri` individually.
///
/// Example:
/// ```dart
- /// Uri uri1 = Uri.parse("a://b@c:4/d/e?f#g");
- /// Uri uri2 = uri1.replace(scheme: "A", path: "D/E/E", fragment: "G");
- /// print(uri2); // prints "a://b@c:4/D/E/E?f#G"
+ /// final uri1 = Uri.parse(
+ /// 'http://dart.dev/guides/libraries/library-tour#utility-classes');
+ ///
+ /// final uri2 = uri1.replace(
+ /// scheme: 'https',
+ /// path: 'guides/libraries/library-tour',
+ /// fragment: 'uris');
+ /// print(uri2); // https://dart.dev/guides/libraries/library-tour#uris
/// ```
/// This method acts similarly to using the `Uri` constructor with
/// some of the arguments taken from this `Uri`. Example:
- /// ```dart
- /// Uri uri3 = Uri(
- /// scheme: "A",
+ /// ``` dart continued
+ /// final Uri uri3 = Uri(
+ /// scheme: 'https',
/// userInfo: uri1.userInfo,
/// host: uri1.host,
- /// port: uri1.port,
- /// path: "D/E/E",
+ /// port: uri2.port,
+ /// path: '/guides/language/language-tour',
/// query: uri1.query,
- /// fragment: "G");
- /// print(uri3); // prints "a://b@c:4/D/E/E?f#G"
- /// print(uri2 == uri3); // prints true.
+ /// fragment: null);
+ /// print(uri3); // https://dart.dev/guides/language/language-tour
/// ```
- /// Using this method can be seen as a shorthand for the `Uri` constructor
+ /// Using this method can be seen as shorthand for the `Uri` constructor
/// call above, but may also be slightly faster because the parts taken
/// from this `Uri` need not be checked for validity again.
Uri replace(
@@ -617,6 +767,13 @@
/// Creates a `Uri` that differs from this only in not having a fragment.
///
/// If this `Uri` does not have a fragment, it is itself returned.
+ ///
+ /// Example:
+ /// ```dart
+ /// final uri =
+ /// Uri.parse('https://example.org:8080/foo/bar#frag').removeFragment();
+ /// print(uri); // https://example.org:8080/foo/bar
+ /// ```
Uri removeFragment();
/// Resolve [reference] as an URI relative to `this`.
@@ -629,16 +786,17 @@
/// See [resolveUri] for details.
Uri resolve(String reference);
- /// Resolve [reference] as an URI relative to `this`.
+ /// Resolve [reference] as a URI relative to `this`.
///
/// Returns the resolved URI.
///
/// The algorithm "Transform Reference" for resolving a reference is described
- /// in [RFC-3986 Section 5](http://tools.ietf.org/html/rfc3986#section-5 "RFC-1123").
+ /// in [RFC-3986 Section 5](https://tools.ietf.org/html/rfc3986#section-5
+ /// "RFC-1123").
///
/// Updated to handle the case where the base URI is just a relative path -
- /// that is: when it has no scheme and no authority and the path does not start
- /// with a slash.
+ /// that is: when it has no scheme and no authority and the path does not
+ /// start with a slash.
/// In that case, the paths are combined without removing leading "..", and
/// an empty path is not converted to "/".
Uri resolveUri(Uri reference);
@@ -648,7 +806,7 @@
/// A normalized path does not contain `.` segments or non-leading `..`
/// segments.
/// Only a relative path with no scheme or authority may contain
- /// leading `..` segments,
+ /// leading `..` segments;
/// a path that starts with `/` will also drop any leading `..` segments.
///
/// This uses the same normalization strategy as `Uri().resolve(this)`.
@@ -666,6 +824,15 @@
///
/// If the [uri] string is not valid as a URI or URI reference,
/// a [FormatException] is thrown.
+ ///
+ /// Example:
+ /// ```dart
+ /// final uri =
+ /// Uri.parse('https://example.com/api/fetch?limit=10,20,30&max=100');
+ /// print(uri); // https://example.com/api/fetch?limit=10,20,30&max=100
+ ///
+ /// Uri.parse('::Not valid URI::'); // Throws FormatException.
+ /// ```
static Uri parse(String uri, [int start = 0, int? end]) {
// This parsing will not validate percent-encoding, IPv6, etc.
// When done splitting into parts, it will call, e.g., [_makeFragment]
@@ -963,6 +1130,17 @@
/// of [uri], and only the substring from `start` to `end` is parsed as a URI.
///
/// Returns `null` if the [uri] string is not valid as a URI or URI reference.
+ ///
+ /// Example:
+ /// ```dart
+ /// final uri = Uri.tryParse(
+ /// 'https://dart.dev/guides/libraries/library-tour#utility-classes', 0,
+ /// 16);
+ /// print(uri); // https://dart.dev
+ ///
+ /// var notUri = Uri.tryParse('::Not valid URI::');
+ /// print(notUri); // null
+ /// ```
static Uri? tryParse(String uri, [int start = 0, int? end]) {
// TODO: Optimize to avoid throwing-and-recatching.
try {
@@ -977,19 +1155,26 @@
///
/// All characters except uppercase and lowercase letters, digits and
/// the characters `-_.!~*'()` are percent-encoded. This is the
- /// set of characters specified in RFC 2396 and the which is
+ /// set of characters specified in RFC 2396 and which is
/// specified for the encodeUriComponent in ECMA-262 version 5.1.
///
- /// When manually encoding path segments or query components remember
+ /// When manually encoding path segments or query components, remember
/// to encode each part separately before building the path or query
/// string.
///
/// For encoding the query part consider using
/// [encodeQueryComponent].
///
- /// To avoid the need for explicitly encoding use the [pathSegments]
+ /// To avoid the need for explicitly encoding, use the [pathSegments]
/// and [queryParameters] optional named arguments when constructing
/// a [Uri].
+ ///
+ /// Example:
+ /// ```dart
+ /// const request = 'http://example.com/search=Dart';
+ /// final encoded = Uri.encodeComponent(request);
+ /// print(encoded); // http%3A%2F%2Fexample.com%2Fsearch%3DDart
+ /// ```
static String encodeComponent(String component) {
return _Uri._uriEncode(_Uri._unreserved2396Table, component, utf8, false);
}
@@ -1024,7 +1209,7 @@
* [queryParameters] optional named arguments when constructing a
* [Uri].
*
- * See http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 for more
+ * See https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 for more
* details.
*/
static String encodeQueryComponent(String component,
@@ -1035,14 +1220,21 @@
/// Decodes the percent-encoding in [encodedComponent].
///
/// Note that decoding a URI component might change its meaning as
- /// some of the decoded characters could be characters with are
+ /// some of the decoded characters could be characters which are
/// delimiters for a given URI component type. Always split a URI
/// component using the delimiters for the component before decoding
/// the individual parts.
///
- /// For handling the [path] and [query] components consider using
+ /// For handling the [path] and [query] components, consider using
/// [pathSegments] and [queryParameters] to get the separated and
/// decoded component.
+ ///
+ /// Example:
+ /// ```dart
+ /// final decoded =
+ /// Uri.decodeComponent('http%3A%2F%2Fexample.com%2Fsearch%3DDart');
+ /// print(decoded); // http://example.com/search=Dart
+ /// ```
static String decodeComponent(String encodedComponent) {
return _Uri._uriDecode(
encodedComponent, 0, encodedComponent.length, utf8, false);
@@ -1066,7 +1258,14 @@
/// All characters except uppercase and lowercase letters, digits and
/// the characters `!#$&'()*+,-./:;=?@_~` are percent-encoded. This
/// is the set of characters specified in in ECMA-262 version 5.1 for
- /// the encodeURI function .
+ /// the encodeURI function.
+ ///
+ /// Example:
+ /// ```dart
+ /// final encoded =
+ /// Uri.encodeFull('https://example.com/api/query?search= dart is');
+ /// print(encoded); // https://example.com/api/query?search=%20dart%20is
+ /// ```
static String encodeFull(String uri) {
return _Uri._uriEncode(_Uri._encodeFullTable, uri, utf8, false);
}
@@ -1075,24 +1274,41 @@
///
/// Note that decoding a full URI might change its meaning as some of
/// the decoded characters could be reserved characters. In most
- /// cases an encoded URI should be parsed into components using
+ /// cases, an encoded URI should be parsed into components using
/// [Uri.parse] before decoding the separate components.
+ ///
+ /// Example:
+ /// ```dart
+ /// final decoded =
+ /// Uri.decodeFull('https://example.com/api/query?search=%20dart%20is');
+ /// print(decoded); // https://example.com/api/query?search= dart is
+ /// ```
static String decodeFull(String uri) {
return _Uri._uriDecode(uri, 0, uri.length, utf8, false);
}
/// Splits the [query] into a map according to the rules
/// specified for FORM post in the [HTML 4.01 specification section
- /// 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
+ /// 17.13.4](https://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4
+ /// "HTML 4.01 section 17.13.4").
///
/// Each key and value in the returned map has been decoded. If the [query]
- /// is the empty string an empty map is returned.
+ /// is the empty string, an empty map is returned.
///
/// Keys in the query string that have no value are mapped to the
/// empty string.
///
- /// Each query component will be decoded using [encoding]. The default encoding
- /// is UTF-8.
+ /// Each query component will be decoded using [encoding]. The default
+ /// encoding is UTF-8.
+ ///
+ /// Example:
+ /// ```dart import:convert
+ /// final queryStringMap =
+ /// Uri.splitQueryString('limit=10&max=100&search=Dart%20is%20fun');
+ /// print(jsonEncode(queryStringMap));
+ /// // {"limit":"10","max":"100","search":"Dart is fun"}
+ ///
+ /// ```
static Map<String, String> splitQueryString(String query,
{Encoding encoding = utf8}) {
return query.split("&").fold({}, (map, element) {
@@ -1170,7 +1386,7 @@
/// representation.
///
/// Acts on the substring from [start] to [end]. If [end] is omitted, it
- /// defaults ot the end of the string.
+ /// defaults to the end of the string.
///
/// Some examples of IPv6 addresses:
/// * `::1`
@@ -2181,7 +2397,7 @@
/// Performs RFC 3986 Percent-Encoding Normalization.
///
- /// Returns a replacement string that should be replace the original escape.
+ /// Returns a replacement string that should replace the original escape.
/// Returns null if no replacement is necessary because the escape is
/// not for an unreserved character and is already non-lower-case.
///
@@ -2266,12 +2482,12 @@
}
/// Runs through component checking that each character is valid and
- /// normalize percent escapes.
+ /// normalizes percent escapes.
///
/// Uses [charTable] to check if a non-`%` character is allowed.
/// Each `%` character must be followed by two hex digits.
- /// If the hex-digits are lower case letters, they are converted to
- /// upper case.
+ /// If the hex-digits are lowercase letters, they are converted to
+ /// uppercase.
///
/// Returns `null` if the original content was already normalized.
static String? _normalize(
@@ -2430,7 +2646,7 @@
/// Removing the ".." from a "bar/foo/.." sequence results in "bar/"
/// (trailing "/"). If the entire path is removed (because it contains as
/// many ".." segments as real segments), the result is "./".
- /// This is different from an empty string, which represents "no path",
+ /// This is different from an empty string, which represents "no path"
/// when you resolve it against a base URI with a path with a non-empty
/// final segment.
static String _normalizeRelativePath(String path, bool allowScheme) {
@@ -2811,7 +3027,7 @@
/// If [plusToSpace] is `true`, plus characters will be converted to spaces.
///
/// The decoder will create a byte-list of the percent-encoded parts, and then
- /// decode the byte-list using [encoding]. The default encodings UTF-8.
+ /// decode the byte-list using [encoding]. The default encoding is UTF-8.
static String _uriDecode(
String text, int start, int end, Encoding encoding, bool plusToSpace) {
assert(0 <= start);
@@ -3115,7 +3331,7 @@
/// Data URIs are non-hierarchical URIs that can contain any binary data.
/// They are defined by [RFC 2397](https://tools.ietf.org/html/rfc2397).
///
-/// This class allows parsing the URI text and extracting individual parts of the
+/// This class allows parsing the URI text, extracting individual parts of the
/// URI, as well as building the URI text from structured parts.
class UriData {
static const int _noScheme = -1;
@@ -3137,7 +3353,7 @@
/// The first separator ends the mime type. We don't bother with finding
/// the '/' inside the mime type.
///
- /// Each two separators after that marks a parameter key and value.
+ /// Each two separators after that mark a parameter key and value.
///
/// If there is a single separator left, it ends the "base64" marker.
///
@@ -3244,7 +3460,7 @@
/// until just before the ',' before the data, or before a `;base64,`
/// marker.
///
- /// Of an [indices] list is passed, separator indices are stored in that
+ /// If an [indices] list is passed, separator indices are stored in that
/// list.
static void _writeUri(
String? mimeType,
@@ -3335,7 +3551,7 @@
/// it valid, and existing escapes are case normalized.
///
/// Accessing the individual parts may fail later if they turn out to have
- /// content that can't be decoded successfully as a string, for example if
+ /// content that cannot be decoded successfully as a string, for example if
/// existing percent escapes represent bytes that cannot be decoded
/// by the chosen [Encoding] (see [contentAsString]).
///
@@ -3410,7 +3626,7 @@
/// If the parameters of the media type contains a `charset` parameter
/// then this returns its value, otherwise it returns `US-ASCII`,
/// which is the default charset for data URIs.
- /// If the value contain non-ASCII percent escapes, they are decoded as UTF-8.
+ /// If the values contain non-ASCII percent escapes, they are decoded as UTF-8.
///
/// If the MIME type representation in the URI text contains URI escapes,
/// they are unescaped in the returned string.
@@ -3497,7 +3713,7 @@
/// If the content is Base64 encoded, it will be decoded to bytes and then
/// decoded to a string using [encoding].
/// If encoding is omitted, the value of a `charset` parameter is used
- /// if it is recognized by [Encoding.getByName], otherwise it defaults to
+ /// if it is recognized by [Encoding.getByName]; otherwise it defaults to
/// the [ascii] encoding, which is the default encoding for data URIs
/// that do not specify an encoding.
///
@@ -3725,7 +3941,7 @@
// Initial state for scheme validation.
const int _schemeStart = 20;
-/// Transition tables used to scan a URI to determine its structure.
+/// Transition tables are used to scan a URI to determine its structure.
///
/// The tables represent a state machine with output.
///
@@ -3740,13 +3956,13 @@
/// and a 3-bit index into the output table.
///
/// For URI scanning, only characters in the range U+0020 through U+007E are
-/// interesting, all characters outside that range are treated the same.
-/// The tables only contain 96 entries, representing that characters in the
+/// interesting; all characters outside that range are treated the same.
+/// The tables only contain 96 entries, representing the characters in the
/// interesting range, plus one more to represent all values outside the range.
/// The character entries are stored in one `Uint8List` per state, with the
/// transition for a character at position `character ^ 0x60`,
/// which maps the range U+0020 .. U+007F into positions 0 .. 95.
-/// All remaining characters are mapped to position 31 (`0x7f ^ 0x60`) which
+/// All remaining characters are mapped to position 31 (`0x7f ^ 0x60`), which
/// represents the transition for all remaining characters.
final List<Uint8List> _scannerTables = _createTables();
diff --git a/tools/VERSION b/tools/VERSION
index 63f943c..5f05953 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 16
PATCH 0
-PRERELEASE 97
+PRERELEASE 98
PRERELEASE_PATCH 0
\ No newline at end of file