diff --git a/CHANGELOG.md b/CHANGELOG.md index 63980e0..2e1269e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ ## 1.0.0-dev.3 - **BREAKING**: Renamed extensions from `Extension` to `InstanceMembers`. +- Added `fetch_api.compatibility_layer` library to support Dart 2.19. + - Added `createHeadersFromMap` + - Added `createHeadersFromArray` + - Added `createRequestInit` + - Added `createAbortSignalTimeout` + - `AbortSignal` - Added `timeout` constructor-like method. - Added `abort` constructor-like method. @@ -14,7 +20,6 @@ - Added docs. - `Headers` - Added docs. - - Add methods `headersFromMap` and `headersFromArray` to support Dart 2.19. - `Iterator` and `IteratorResult` - Added docs. - `ReadableStreamDefaultReader` and `ReadableStreamDefaultReaderChunk` diff --git a/lib/compatibility_layer.dart b/lib/compatibility_layer.dart new file mode 100644 index 0000000..275b097 --- /dev/null +++ b/lib/compatibility_layer.dart @@ -0,0 +1,15 @@ +/// Dart 1.19 compatibility layer. +/// +/// Provides [createHeadersFromArray], [createHeadersFromMap], +/// [createAbortSignalTimeout] and [createRequestInit] functions, in replacement +/// of unsupported [Headers.fromArray], [Headers.fromMap], [AbortSignal.timeout] +/// and [RequestInit] respectively. +library fetch_api.compatibility_layer; + +import 'src/abort_signal/abort_signal.dart'; +import 'src/headers/headers.dart'; +import 'src/request_init/request_init.dart'; + +export 'src/abort_signal/abort_signal.dart' show createAbortSignalTimeout; +export 'src/headers/headers.dart' show createHeadersFromArray, createHeadersFromMap; +export 'src/request_init/request_init.dart' show createRequestInit; diff --git a/lib/fetch_api.dart b/lib/fetch_api.dart index 87c4e8e..86f2bd5 100644 --- a/lib/fetch_api.dart +++ b/lib/fetch_api.dart @@ -1,3 +1,9 @@ +/// The Fetch API provides an interface for fetching resources +/// (including across the network). It will seem familiar to anyone who has used +/// `XMLHttpRequest`, but the new API provides a more powerful and flexible +/// feature set. +library fetch_api; + export 'src/abort_controller.dart'; export 'src/abort_signal.dart'; export 'src/fetch.dart'; diff --git a/lib/src/abort_signal.dart b/lib/src/abort_signal.dart index d726f7c..a80ac2a 100644 --- a/lib/src/abort_signal.dart +++ b/lib/src/abort_signal.dart @@ -1,37 +1 @@ -import '_js.dart'; -import 'abort_controller.dart'; - - -/// The [AbortSignal] interface represents a signal object that allows you -/// to communicate with a DOM request (such as a fetch request) and abort it -/// if required via an [AbortController] object. -@JS() -@staticInterop -class AbortSignal { - /// Returns an [AbortSignal] instance that will automatically abort - /// after a specified [time]. - factory AbortSignal.timeout(Duration time) - => AbortSignal._timeout(time.inMilliseconds); - - /// Returns an [AbortSignal] instance that is already set as aborted. - external static AbortSignal abort([dynamic reason]); - - /// Returns an [AbortSignal] instance that will automatically abort - /// after a specified [time] in milliseconds. - @JS('timeout') - external static AbortSignal _timeout(int time); -} - - -extension AbortSignalInstanceMembers on AbortSignal { - /// A [bool] that indicates whether the request(s) the signal is - /// communicating with is/are aborted (`true`) or not (`false`). - external final bool aborted; - - /// A JavaScript value providing the abort reason, once the signal has aborted. - external final dynamic reason; - - /// Throws the signal's abort [reason] if the signal has been aborted; - /// otherwise it does nothing. - external void throwIfAborted(); -} +export 'abort_signal/abort_signal.dart' hide createAbortSignalTimeout; diff --git a/lib/src/abort_signal/abort_signal.compatibility_layer.dart b/lib/src/abort_signal/abort_signal.compatibility_layer.dart new file mode 100644 index 0000000..a52fde2 --- /dev/null +++ b/lib/src/abort_signal/abort_signal.compatibility_layer.dart @@ -0,0 +1,7 @@ +part of 'abort_signal.dart'; + + +/// Returns an [AbortSignal] instance that will automatically abort +/// after a specified [time]. +AbortSignal createAbortSignalTimeout(Duration time) + => AbortSignal._timeout(time.inMilliseconds); diff --git a/lib/src/abort_signal/abort_signal.dart b/lib/src/abort_signal/abort_signal.dart new file mode 100644 index 0000000..8efa6ef --- /dev/null +++ b/lib/src/abort_signal/abort_signal.dart @@ -0,0 +1,39 @@ +import '../_js.dart'; +import '../abort_controller.dart'; + +part 'abort_signal.compatibility_layer.dart'; + + +/// The [AbortSignal] interface represents a signal object that allows you +/// to communicate with a DOM request (such as a fetch request) and abort it +/// if required via an [AbortController] object. +@JS() +@staticInterop +class AbortSignal { + /// Returns an [AbortSignal] instance that will automatically abort + /// after a specified [time]. + factory AbortSignal.timeout(Duration time) + => AbortSignal._timeout(time.inMilliseconds); + + /// Returns an [AbortSignal] instance that is already set as aborted. + external static AbortSignal abort([dynamic reason]); + + /// Returns an [AbortSignal] instance that will automatically abort + /// after a specified [time] in milliseconds. + @JS('timeout') + external static AbortSignal _timeout(int time); +} + + +extension AbortSignalInstanceMembers on AbortSignal { + /// A [bool] that indicates whether the request(s) the signal is + /// communicating with is/are aborted (`true`) or not (`false`). + external final bool aborted; + + /// A JavaScript value providing the abort reason, once the signal has aborted. + external final dynamic reason; + + /// Throws the signal's abort [reason] if the signal has been aborted; + /// otherwise it does nothing. + external void throwIfAborted(); +} diff --git a/lib/src/headers.dart b/lib/src/headers.dart index d8a076e..4c828cf 100644 --- a/lib/src/headers.dart +++ b/lib/src/headers.dart @@ -1,115 +1 @@ -import '_js.dart'; -import 'iterator.dart' as js; -import 'iterator_wrapper.dart'; -import 'response.dart'; - - -/// The [Headers] interface of the Fetch API allows you to perform various -/// actions on HTTP request and response headers. These actions include -/// retrieving, setting, adding to, and removing headers from the list of -/// the request's headers. -/// -/// A [Headers] object has an associated header list, which is initially empty -/// and consists of zero or more name and value pairs. You can add to this using -/// methods like `append()`. In all methods of this interface, header names are -/// matched by case-insensitive byte sequence. -/// -/// For security reasons, some headers can only be controlled by the user agent. -/// These headers include the forbidden header names and forbidden response -/// header names. -/// -/// A [Headers] object also has an associated guard, which takes -/// a value of `immutable`, `request`, `request-no-cors`, `response`, or `none`. -/// This affects whether the `set()`, `delete()`, and `append()` methods will -/// mutate the header. -/// -/// You can retrieve a [Headers] object via the `Request.headers` and -/// [ResponseInstanceMembers.headers] properties, and create -/// a new [Headers] object using the `Headers()` constructor. -@JS() -@staticInterop -class Headers { - /// Creates a new [Headers] object. - @JS('Headers') - external factory Headers(); - - /// Creates a new [Headers] object. - @JS('Headers') - external factory Headers._init(dynamic init); - - /// Warning: available only with Dart 3.0 or higher. - /// Creates [Headers] from [Map]. - factory Headers.fromMap(Map init) => - headersFromMap(init); - - /// Warning: available only with Dart 3.0 or higher. - /// Creates [Headers] from array of 2 items arrays. - factory Headers.fromArray(List> init) => - headersFromArray(init); -} - -extension HeadersInstanceMembers on Headers { - /// Appends a new value onto an existing header inside a [Headers] object, - /// or adds the header if it does not already exist. - external void append(String name, String value); - - /// Deletes a header from a [Headers] object. - external void delete(String name); - - /// Returns an [js.Iterator] allowing to go through all key/value pairs - /// contained in this object. - @JS('entries') - external js.Iterator> _entries(); - - // forEach() - - /// Returns a [String] sequence of all the values of a header within - /// a [Headers] object with a given name. - external String? get(String name); - - /// Returns a [bool] stating whether a [Headers] object contains - /// a certain header. - external bool has(String name); - - /// Returns an [js.Iterator] allowing you to go through all keys of - /// the key/value pairs contained in this object. - @JS('keys') - external js.Iterator _keys(); - - /// Sets a new value for an existing header inside a [Headers] object, - /// or adds the header if it does not already exist. - external void set(String name, String value); - - /// Returns an [js.Iterator] allowing you to go through all values of - /// the key/value pairs contained in this object. - @JS('values') - external js.Iterator _values(); - - /// Returns an [IteratorWrapper] allowing to go through all key/value pairs - /// contained in this object. - IteratorWrapper> entries() => IteratorWrapper(_entries()); - - /// Returns an [IteratorWrapper] allowing you to go through all keys of the - /// key/value pairs contained in this object. - IteratorWrapper keys() => IteratorWrapper(_keys()); - - /// Returns an [IteratorWrapper] allowing you to go through all values of - /// the key/value pairs contained in this object. - IteratorWrapper values() => IteratorWrapper(_values()); -} - -/// Creates [Headers] from [Map]. -Headers headersFromMap(Map init) => - Headers._init(init.toJsObject()); - -/// Creates [Headers] from array of 2 items arrays. -Headers headersFromArray(List> init) { - final _init = JsArray>(); - for (final header in init) { - if (header.length != 2) - throw Exception('Bad argument'); - - _init.add(header.toJsArray()); - } - return Headers._init(_init); -} +export 'headers/headers.dart' hide createHeadersFromArray, createHeadersFromMap; diff --git a/lib/src/headers/headers.compatibility_layer.dart b/lib/src/headers/headers.compatibility_layer.dart new file mode 100644 index 0000000..57132c1 --- /dev/null +++ b/lib/src/headers/headers.compatibility_layer.dart @@ -0,0 +1,18 @@ +part of 'headers.dart'; + + +/// Creates [Headers] from [Map]. +Headers createHeadersFromMap(Map init) => + Headers._init(init.toJsObject()); + +/// Creates [Headers] from array of 2 items arrays. +Headers createHeadersFromArray(List> init) { + final _init = JsArray>(); + for (final header in init) { + if (header.length != 2) + throw Exception('Bad argument'); + + _init.add(header.toJsArray()); + } + return Headers._init(_init); +} diff --git a/lib/src/headers/headers.dart b/lib/src/headers/headers.dart new file mode 100644 index 0000000..b2684e6 --- /dev/null +++ b/lib/src/headers/headers.dart @@ -0,0 +1,109 @@ +import '../_js.dart'; +import '../iterator.dart' as js; +import '../iterator_wrapper.dart'; +import '../response.dart'; + +part 'headers.compatibility_layer.dart'; + + +/// The [Headers] interface of the Fetch API allows you to perform various +/// actions on HTTP request and response headers. These actions include +/// retrieving, setting, adding to, and removing headers from the list of +/// the request's headers. +/// +/// A [Headers] object has an associated header list, which is initially empty +/// and consists of zero or more name and value pairs. You can add to this using +/// methods like `append()`. In all methods of this interface, header names are +/// matched by case-insensitive byte sequence. +/// +/// For security reasons, some headers can only be controlled by the user agent. +/// These headers include the forbidden header names and forbidden response +/// header names. +/// +/// A [Headers] object also has an associated guard, which takes +/// a value of `immutable`, `request`, `request-no-cors`, `response`, or `none`. +/// This affects whether the `set()`, `delete()`, and `append()` methods will +/// mutate the header. +/// +/// You can retrieve a [Headers] object via the `Request.headers` and +/// [ResponseInstanceMembers.headers] properties, and create +/// a new [Headers] object using the `Headers()` constructor. +@JS() +@staticInterop +class Headers { + /// Creates a new [Headers] object. + @JS('Headers') + external factory Headers(); + + /// Creates a new [Headers] object. + @JS('Headers') + external factory Headers._init(dynamic init); + + /// Warning: available only with Dart 3.0 or higher. + /// Creates [Headers] from [Map]. + factory Headers.fromMap(Map init) => + Headers._init(init.toJsObject()); + + /// Warning: available only with Dart 3.0 or higher. + /// Creates [Headers] from array of 2 items arrays. + factory Headers.fromArray(List> init) { + final _init = JsArray>(); + for (final header in init) { + if (header.length != 2) + throw Exception('Bad argument'); + + _init.add(header.toJsArray()); + } + return Headers._init(_init); + } +} + +extension HeadersInstanceMembers on Headers { + /// Appends a new value onto an existing header inside a [Headers] object, + /// or adds the header if it does not already exist. + external void append(String name, String value); + + /// Deletes a header from a [Headers] object. + external void delete(String name); + + /// Returns an [js.Iterator] allowing to go through all key/value pairs + /// contained in this object. + @JS('entries') + external js.Iterator> _entries(); + + // forEach() + + /// Returns a [String] sequence of all the values of a header within + /// a [Headers] object with a given name. + external String? get(String name); + + /// Returns a [bool] stating whether a [Headers] object contains + /// a certain header. + external bool has(String name); + + /// Returns an [js.Iterator] allowing you to go through all keys of + /// the key/value pairs contained in this object. + @JS('keys') + external js.Iterator _keys(); + + /// Sets a new value for an existing header inside a [Headers] object, + /// or adds the header if it does not already exist. + external void set(String name, String value); + + /// Returns an [js.Iterator] allowing you to go through all values of + /// the key/value pairs contained in this object. + @JS('values') + external js.Iterator _values(); + + /// Returns an [IteratorWrapper] allowing to go through all key/value pairs + /// contained in this object. + IteratorWrapper> entries() => IteratorWrapper(_entries()); + + /// Returns an [IteratorWrapper] allowing you to go through all keys of the + /// key/value pairs contained in this object. + IteratorWrapper keys() => IteratorWrapper(_keys()); + + /// Returns an [IteratorWrapper] allowing you to go through all values of + /// the key/value pairs contained in this object. + IteratorWrapper values() => IteratorWrapper(_values()); +} diff --git a/lib/src/request_init.dart b/lib/src/request_init.dart index c95062e..cca9b5e 100644 --- a/lib/src/request_init.dart +++ b/lib/src/request_init.dart @@ -1,6 +1,6 @@ export 'request_init/request_cache.dart'; export 'request_init/request_credentials.dart'; -export 'request_init/request_init.dart'; +export 'request_init/request_init.dart' hide createRequestInit; export 'request_init/request_mode.dart'; export 'request_init/request_redirect.dart'; export 'request_init/request_referrer_policy.dart'; diff --git a/lib/src/request_init/request_init.compatibility_layer.dart b/lib/src/request_init/request_init.compatibility_layer.dart new file mode 100644 index 0000000..9073e5d --- /dev/null +++ b/lib/src/request_init/request_init.compatibility_layer.dart @@ -0,0 +1,30 @@ +part of 'request_init.dart'; + + +RequestInit createRequestInit({ + String method = 'GET', + Headers? headers, + dynamic body, + RequestMode mode = RequestMode.noCors, + RequestCredentials credentials = RequestCredentials.sameOrigin, + RequestCache cache = RequestCache.byDefault, + RequestRedirect redirect = RequestRedirect.follow, + String referrer = '', + RequestReferrerPolicy referrerPolicy = RequestReferrerPolicy.strictOriginWhenCrossOrigin, + String integrity = '', + bool keepalive = false, + AbortSignal? signal, +}) => RequestInit._( + method: method, + headers: headers ?? Headers(), + body: body, + mode: mode.toString(), + credentials: credentials.toString(), + cache: cache.toString(), + redirect: redirect.toString(), + referrer: referrer, + referrerPolicy: referrerPolicy.toString(), + integrity: integrity, + keepalive: keepalive, + signal: signal, +); diff --git a/lib/src/request_init/request_init.dart b/lib/src/request_init/request_init.dart index 466447e..cd53d5d 100644 --- a/lib/src/request_init/request_init.dart +++ b/lib/src/request_init/request_init.dart @@ -8,6 +8,8 @@ import 'request_mode.dart'; import 'request_redirect.dart'; import 'request_referrer_policy.dart'; +part 'request_init.compatibility_layer.dart'; + /// An object containing any custom settings that you want to apply to the /// request.