| Index: lib/src/resource.dart
|
| diff --git a/lib/src/resource.dart b/lib/src/resource.dart
|
| index 2fef5f6325910a8cb9e4a06c720cbcabe5bc9000..924ec051b364e38c6fa90bd3867704bb2100f69f 100644
|
| --- a/lib/src/resource.dart
|
| +++ b/lib/src/resource.dart
|
| @@ -1,218 +1,87 @@
|
| -// Copyright (c) 2015, 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.
|
| -
|
| -library resoure.resource;
|
| -
|
| -import "dart:async" show Future, Stream;
|
| -import "dart:convert" show Encoding;
|
| -import "dart:isolate" show Isolate;
|
| -import "package_resolver.dart";
|
| -import "io.dart" as io; // Loading strategy. TODO: Be configuration dependent.
|
| -
|
| -/// A strategy for resolving package URIs
|
| -abstract class PackageResolver {
|
| - /// Cache of the current resolver, accessible directly after it has first
|
| - /// been found asynchronously.
|
| - static PackageResolver _current;
|
| -
|
| - /// The package resolution strategy used by the current isolate.
|
| - static final Future<PackageResolver> current = _findIsolateResolution();
|
| -
|
| - PackageResolver();
|
| -
|
| - /// Creates a resolver using a map from package name to package location.
|
| - factory PackageResolver.fromMap(Map<String, Uri> packages) = MapResolver;
|
| -
|
| - /// Creates a resolver using a package root.
|
| - factory PackageResolver.fromRoot(Uri packageRoot) = RootResolver;
|
| -
|
| - /// Resolves a package URI to its location.
|
| - ///
|
| - /// If [uri] does not have `package` as scheme, it is returned again.
|
| - /// Otherwise the package name is looked up, and if found, a location
|
| - /// for the package file is returned.
|
| - Future<Uri> resolve(Uri uri);
|
| -
|
| - /// Returns a [Resource] for the [uri] as resolved by this resolver.
|
| - Resource resource(Uri uri) {
|
| - return new _UriResource(this, uri);
|
| - }
|
| -
|
| - /// Finds the way the current isolate resolves package URIs.
|
| - ///
|
| - /// Is only called once, and when it has been called, the [_current]
|
| - /// resolver is initialized, so [UriResource] will be initialized
|
| - /// with the resolver directly.
|
| - static Future<PackageResolver> _findIsolateResolution() async {
|
| - var pair = await Future.wait([Isolate.packageRoot, Isolate.packageMap]);
|
| - Uri root = pair[0];
|
| - if (root != null) {
|
| - _current = new RootResolver(root);
|
| - } else {
|
| - Map<String, Uri> map = pair[1];
|
| - _current = new MapResolver(map);
|
| - }
|
| - return _current;
|
| - }
|
| -}
|
| -
|
| -/// A resource that can be read into the program.
|
| -///
|
| -/// A resource is data that can be located using a URI and read into
|
| -/// the program at runtime.
|
| -/// The URI may use the `package` scheme to read resources provided
|
| -/// along with package sources.
|
| -abstract class Resource {
|
| - /// Creates a resource object with the given [uri] as location.
|
| - ///
|
| - /// The `uri` is a string containing a valid URI.
|
| - /// If the string is not a valid URI, using any of the functions on
|
| - /// the resource object will fail.
|
| - ///
|
| - /// The URI may be relative, in which case it will be resolved
|
| - /// against [Uri.base] before being used.
|
| - ///
|
| - /// The URI may use the `package` scheme, which is always supported.
|
| - /// Other schemes may also be supported where possible.
|
| - const factory Resource(String uri) = _StringResource;
|
| -
|
| - /// Creates a resource object with the given [uri] as location.
|
| - ///
|
| - /// The URI may be relative, in which case it will be resolved
|
| - /// against [Uri.base] before being used.
|
| - ///
|
| - /// The URI may use the `package` scheme, which is always supported.
|
| - /// Other schemes may also be supported where possible.
|
| - factory Resource.forUri(Uri uri) =>
|
| - new _UriResource(PackageResolver._current, uri);
|
| -
|
| - /// The location `uri` of this resource.
|
| - ///
|
| - /// This is a [Uri] of the `uri` parameter given to the constructor.
|
| - /// If the parameter was not a valid URI, reading `uri` may fail.
|
| - Uri get uri;
|
| -
|
| - Stream<List<int>> openRead();
|
| -
|
| - Future<List<int>> readAsBytes();
|
| -
|
| - /// Read the resource content as a string.
|
| - ///
|
| - /// The content is decoded into a string using an [Encoding].
|
| - /// If no other encoding is provided, it defaults to UTF-8.
|
| - Future<String> readAsString({Encoding encoding});
|
| -}
|
| -
|
| -class _StringResource implements Resource {
|
| - final String _uri;
|
| -
|
| - const _StringResource(String uri) : _uri = uri;
|
| -
|
| - Uri get uri => Uri.parse(_uri);
|
| -
|
| - Stream<List<int>> openRead() {
|
| - return new _UriResource(PackageResolver._current, uri).openRead();
|
| - }
|
| - Future<List<int>> readAsBytes() {
|
| - return new _UriResource(PackageResolver._current, uri).readAsBytes();
|
| - }
|
| - Future<String> readAsString({Encoding encoding}) {
|
| - return new _UriResource(PackageResolver._current, uri)
|
| - .readAsString(encoding: encoding);
|
| - }
|
| -}
|
| -
|
| -class _UriResource implements Resource {
|
| - /// The strategy for resolving package: URIs.
|
| - ///
|
| - /// May be null intially. If so, the [PackageResolver.current] resolver is
|
| - /// used (and cached for later use).
|
| - PackageResolver _resolver;
|
| -
|
| - /// The URI of the resource.
|
| - final Uri uri;
|
| -
|
| - _UriResource(this.resolver, Uri uri);
|
| -
|
| - Stream<List<int>> openRead() async* {
|
| - Uri uri = await _resolve(this.uri);
|
| - return io.readAsStream(uri);
|
| - }
|
| -
|
| - Future<List<int>> readAsBytes() async {
|
| - Uri uri = await _resolve(this.uri);
|
| - return io.readAsBytes(uri);
|
| - }
|
| -
|
| - Future<String> readAsString({Encoding encoding}) async {
|
| - Uri uri = await _resolve(this.uri);
|
| - return io.readAsString(uri, encoding);
|
| - }
|
| -
|
| - static void _checkPackageUri(Uri uri) {
|
| - if (uri.scheme != "package") {
|
| - throw new ArgumentError.value(uri, "Not a package: URI");
|
| - }
|
| - if (uri.hasAuthority) {
|
| - throw new ArgumentError.value(uri,
|
| - "A package: URI must not have an authority part");
|
| - }
|
| - if (uri.path.isEmpty || uri.path.startsWith('/')) {
|
| - throw new ArgumentError.value(uri,
|
| - "A package: URI must have the form "
|
| - "'package:packageName/packagePath'");
|
| - }
|
| - if (uri.hasQuery) {
|
| - throw new ArgumentError.value(uri,
|
| - "A package: URI must not have a query part");
|
| - }
|
| - if (uri.hasFragment) {
|
| - throw new ArgumentError.value(uri,
|
| - "A package: URI must not have a fragment part");
|
| - }
|
| - }
|
| -
|
| - Future<Uri> _resolve(Uri uri) async {
|
| - if (uri.scheme != "package") {
|
| - return Uri.base.resolveUri(uri);
|
| - }
|
| - _checkPackageUri(uri);
|
| - _resolver ??= await PackageResolver._current;
|
| - return _resolver.resolve(uri);
|
| - }
|
| -}
|
| -
|
| -/// A [PackageResolver] based on a packags map.
|
| -class MapResolver extends PackageResolver {
|
| - Map<String, Uri> _mapping;
|
| -
|
| - MapResolver(this._mapping);
|
| -
|
| - Uri resolve(Uri uri) {
|
| - if (uri.scheme != "package") return uri;
|
| - var path = uri.path;
|
| - int slashIndex = path.indexOf('/');
|
| - if (slashIndex <= 0) {
|
| - throw new ArgumentError.value(uri, "Invalid package URI");
|
| - }
|
| - int packageName = path.substring(0, slashIndex);
|
| - var base = _mapping[packageName];
|
| - if (base != null) {
|
| - int packagePath = path.substring(slashIndex + 1);
|
| - return base.resolveUri(new Uri(path: packagePath));
|
| - }
|
| - throw new UnsupportedError("No package named '$packageName' found");
|
| - }
|
| -}
|
| -
|
| -/// A [PackageResolver] based on a package root.
|
| -class RootResolver extends PackageResolver {
|
| - Uri _root;
|
| - RootResolver(this._root);
|
| -
|
| - Uri resolve(Uri uri) {
|
| - if (uri.scheme != "package") return uri;
|
| - return _root.resolve(uri.path);
|
| - }
|
| -}
|
| +// Copyright (c) 2015, 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.
|
| +
|
| +import "dart:async" show Future, Stream;
|
| +import "dart:convert" show Encoding;
|
| +import "dart:isolate" show Isolate;
|
| +import "loader.dart";
|
| +
|
| +/// A resource that can be read into the program.
|
| +///
|
| +/// A resource is data that can be located using a URI and read into
|
| +/// the program at runtime.
|
| +/// The URI may use the `package` scheme to read resources provided
|
| +/// along with package sources.
|
| +abstract class Resource {
|
| + /// Creates a resource object with the given [uri] as location.
|
| + ///
|
| + /// The [uri] must be either a [Uri] or a string containing a valid URI.
|
| + /// If the string is not a valid URI, using any of the functions on
|
| + /// the resource object will fail.
|
| + ///
|
| + /// The URI may be relative, in which case it will be resolved
|
| + /// against [Uri.base] before being used.
|
| + ///
|
| + /// The URI may use the `package` scheme, which is always supported.
|
| + /// Other schemes may also be supported where possible.
|
| + ///
|
| + /// If [loader] is provided, it is used to load absolute non-package URIs.
|
| + /// Package: URIs are resolved to a non-package URI before being loaded, so
|
| + /// the loader doesn't have to support package: URIs, nor does it need to
|
| + /// support relative URI references.
|
| + /// If [loader] is omitted, a default implementation is used which supports
|
| + /// as many of `http`, `https`, `file` and `data` as are available on the
|
| + /// current platform.
|
| + const factory Resource(uri, {ResourceLoader loader}) = _Resource;
|
| +
|
| + /// The location URI of this resource.
|
| + ///
|
| + /// This is a [Uri] of the `uri` parameter given to the constructor.
|
| + /// If the parameter was a string that did not contain a valid URI,
|
| + /// reading `uri` will fail.
|
| + Uri get uri;
|
| +
|
| + /// Reads the resource content as a stream of bytes.
|
| + Stream<List<int>> openRead();
|
| +
|
| + /// Reads the resource content as a single list of bytes.
|
| + Future<List<int>> readAsBytes();
|
| +
|
| + /// Reads the resource content as a string.
|
| + ///
|
| + /// The content is decoded into a string using an [Encoding].
|
| + /// If no other encoding is provided, it defaults to UTF-8.
|
| + Future<String> readAsString({Encoding encoding});
|
| +}
|
| +
|
| +class _Resource implements Resource {
|
| + /// Loading strategy for the resource.
|
| + final ResourceLoader _loader;
|
| +
|
| + /// The URI of the resource.
|
| + final _uri;
|
| +
|
| + const _Resource(uri, {ResourceLoader loader})
|
| + : _uri = uri, _loader = (loader != null) ? loader : const DefaultLoader();
|
| + // TODO: Make this `loader ?? const DefaultLoader()` when ?? is const.
|
| +
|
| + Uri get uri => (_uri is String) ? Uri.parse(_uri) : (_uri as Uri);
|
| +
|
| + Stream<List<int>> openRead() async* {
|
| + Uri uri = await _resolvedUri;
|
| + yield* _loader.openRead(uri);
|
| + }
|
| +
|
| + Future<List<int>> readAsBytes() async {
|
| + Uri uri = await _resolvedUri;
|
| + return _loader.readAsBytes(uri);
|
| + }
|
| +
|
| + Future<String> readAsString({Encoding encoding}) async {
|
| + Uri uri = await _resolvedUri;
|
| + return _loader.readAsString(uri, encoding: encoding);
|
| + }
|
| +
|
| + Future<Uri> get _resolvedUri => resolveUri(uri);
|
| +}
|
|
|