Skip to content

Commit

Permalink
feat: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Zekfad committed Jan 22, 2023
0 parents commit 55d89d2
Show file tree
Hide file tree
Showing 31 changed files with 852 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/

# Avoid committing pubspec.lock for library packages; see
# https://dart.dev/guides/libraries/private-files#pubspeclock.
pubspec.lock

web/
5 changes: 5 additions & 0 deletions .pubignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.vscode/
*.code-workspace

doc/
web/
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 1.0.0-dev.1

- Initial version.
13 changes: 13 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2023 Yaroslav Vorobev and contributors. All rights reserved.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Fetch API.

This package provides JavaScript bindings to [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).

## Features

* Full request parameters coverage
* Abort requests
* Read response
* As text
* As Blob
* As Stream of Uint8List
* Support streaming of data
* Get access to redirect status
* Support non-200 responses
1 change: 1 addition & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include: package:zekfad_lints/untyped/dart.yaml
10 changes: 10 additions & 0 deletions example/fetch_api_example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'package:fetch_api/fetch_api.dart';


void main() async {
final response = await fetch('https://proxy.cors.sh/https://example.com', RequestInit(
mode: RequestMode.cors,
),);

print(await response.text());
}
10 changes: 10 additions & 0 deletions lib/fetch_api.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export 'src/abort_controller.dart';
export 'src/abort_signal.dart';
export 'src/fetch.dart';
export 'src/headers.dart';
export 'src/iterator_wrapper.dart';
export 'src/readable_stream.dart';
export 'src/readable_stream_default_reader.dart';
export 'src/readable_stream_default_reader_chunk.dart';
export 'src/request_init.dart';
export 'src/response.dart';
17 changes: 17 additions & 0 deletions lib/src/_js.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'dart:js';
import 'dart:js_util';

export 'dart:js';
export 'dart:js_util';
export 'package:js/js.dart';


typedef Promise<T> = Object;

extension JsObjectMapExtension<K, V> on Map<K, V> {
dynamic toJsObject() => jsify(this);
}

extension JsArrayListExtension<E> on List<E> {
JsArray<dynamic> toJsArray() => JsArray.from(this);
}
20 changes: 20 additions & 0 deletions lib/src/abort_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import '_js.dart';
import 'abort_signal.dart';


@JS()
@staticInterop
class AbortController {
/// Creates a new [AbortController] object instance.
external factory AbortController();
}

extension AbortControllerExtension on AbortController {
/// Returns an `AbortSignal` object instance, which can be used to
/// communicate with, or to abort, a DOM request.
external final AbortSignal signal;

/// Aborts a DOM request before it has completed. This is able to abort
/// fetch requests, consumption of any response bodies, and streams.
external void abort([dynamic reason]);
}
8 changes: 8 additions & 0 deletions lib/src/abort_signal.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import '_js.dart';


@JS()
@staticInterop
class AbortSignal {
external factory AbortSignal();
}
10 changes: 10 additions & 0 deletions lib/src/fetch.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import '_js.dart';
import 'request_init.dart';
import 'response.dart';


@JS('fetch')
external Promise<Response> _fetch(dynamic resource, RequestInit? options);

Future<Response> fetch(dynamic resource, [RequestInit? options]) =>
promiseToFuture(_fetch(resource, options));
85 changes: 85 additions & 0 deletions lib/src/headers.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import '_js.dart';
import 'iterator.dart' as js;
import 'iterator_wrapper.dart';


@JS()
@staticInterop
class Headers {
/// Creates empty [Headers].
factory Headers() => Headers._();

/// Creates [Headers] from [Map].
factory Headers.fromMap(Map<String, String> init) =>
Headers._init(init.toJsObject());

/// Creates [Headers] from array of 2 items arrays.
factory Headers.fromArray(List<List<String>> init) {
final _init = JsArray<JsArray<dynamic>>();
for (final header in init) {
if (header.length != 2)
throw Exception('Bad argument');

_init.add(header.toJsArray());
}
return Headers._init(_init);
}

/// Creates a new [Headers] object.
@JS('Headers')
external factory Headers._();

/// Creates a new [Headers] object.
@JS('Headers')
external factory Headers._init(dynamic init);
}

extension HeadersExtension 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 `iterator` allowing to go through all key/value pairs contained
/// in this object.
@JS('entries')
external js.Iterator<List<String>> _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 `iterator` allowing you to go through all keys of the key/value
/// pairs contained in this object.
@JS('keys')
external js.Iterator<String> _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 `iterator` allowing you to go through all values of
/// the key/value pairs contained in this object.
@JS('values')
external js.Iterator<String> _values();

/// Returns an [IteratorWrapper] allowing to go through all key/value pairs
/// contained in this object.
IteratorWrapper<List<String>> entries() => IteratorWrapper(_entries());

/// Returns an [IteratorWrapper] allowing you to go through all keys of the
/// key/value pairs contained in this object.
IteratorWrapper<String> keys() => IteratorWrapper(_keys());

/// Returns an [IteratorWrapper] allowing you to go through all values of
/// the key/value pairs contained in this object.
IteratorWrapper<String> values() => IteratorWrapper(_values());
}
15 changes: 15 additions & 0 deletions lib/src/iterator.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import '_js.dart';
import 'iterator_result.dart';


@JS()
@anonymous
class Iterator<T> {
/// A function that accepts zero or one argument and returns an object
/// conforming to the [IteratorResult] interface.
///
/// If a non-object value gets returned (such as false or undefined)
/// when a built-in language feature (such as for...of) is using the iterator,
/// a TypeError ("iterator.next() returned a non-object value") will be thrown.
external IteratorResult<T> next();
}
31 changes: 31 additions & 0 deletions lib/src/iterator_result.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import '_js.dart';


@JS()
@anonymous
class IteratorResult<T> {
factory IteratorResult({
bool done = false,
T? value,
}) => IteratorResult._(
done: done,
value: value,
);

external factory IteratorResult._({
bool? done,
T? value,
});

/// A boolean that's `false` if the iterator was able to produce
/// the next value in the sequence. (This is equivalent to not specifying
/// the done property altogether.)
///
/// Has the value `true` if the iterator has completed its sequence.
/// In this case, value optionally specifies the return value of the iterator.
external bool? done;

/// Any JavaScript value returned by the iterator.
/// Can be omitted when [done] is `true`.
external T? value;
}
27 changes: 27 additions & 0 deletions lib/src/iterator_wrapper.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'dart:collection';
import 'dart:core';
import 'dart:core' as core;
import 'iterator.dart' as js;


/// Wrapper on top of JS iterator, providing [Iterable] and [Iterator] APIs.
class IteratorWrapper<T> extends IterableBase<T> implements core.Iterator<T> {
IteratorWrapper(this._iterator);

final js.Iterator<T> _iterator;

T? _current;

@override
T get current => _current!;

@override
bool moveNext() {
final next = _iterator.next();
_current = next.value;
return !(next.done ?? false);
}

@override
Iterator<T> get iterator => this;
}
54 changes: 54 additions & 0 deletions lib/src/readable_stream.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import '_js.dart';
import 'readable_stream_default_reader.dart';


@JS()
@staticInterop
class ReadableStream {
/// Creates and returns a readable stream object from the given handlers.
external factory ReadableStream([
dynamic underlyingSource,
dynamic queuingStrategy,
]);
}

extension ReadableStreamExtension on ReadableStream {
/// Returns a [bool] indicating whether or not the readable stream
/// is locked to a reader.
external final bool locked;

/// Returns a `Promise` that resolves when the stream is canceled.
/// Calling this method signals a loss of interest in the stream by a consumer.
/// The supplied [reason] argument will be given to the underlying source,
/// which may or may not use it.
@JS('cancel')
external Promise<dynamic> _cancel([dynamic reason]);

// pipeThrough()
// pipeTo()

/// Creates a reader and locks the stream to it.
/// While the stream is locked, no other reader can be acquired until this one
/// is released.
///
/// Implementation note: BYOP reader is unsupported, and therefore
/// no optional arguments provided.
external ReadableStreamDefaultReader getReader();

/// The [_tee] method tees this readable stream, returning a two-element
/// array containing the two resulting branches as new [ReadableStream]
/// instances. Each of those streams receives the same incoming data.
@JS('tee')
external List<dynamic> _tee();

/// Returns a [Future] that resolves when the stream is canceled.
/// Calling this method signals a loss of interest in the stream by a consumer.
/// The supplied [reason] argument will be given to the underlying source,
/// which may or may not use it.
Future<T?> cancel<T>([T? reason]) => promiseToFuture(_cancel(reason));

/// The [tee] method tees this readable stream, returning a two-element
/// array containing the two resulting branches as new [ReadableStream]
/// instances. Each of those streams receives the same incoming data.
List<ReadableStream> tee() => _tee().cast();
}
Loading

0 comments on commit 55d89d2

Please sign in to comment.