Line data Source code
1 : // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 : // for details. All rights reserved. Use of this source code is governed by a
3 : // BSD-style license that can be found in the LICENSE file.
4 :
5 : import 'dart:async';
6 :
7 : import 'package:http/http.dart' as http;
8 :
9 : import 'no_package_resolver.dart';
10 : import 'package_config_resolver.dart';
11 : import 'package_resolver.dart';
12 : import 'package_root_resolver.dart';
13 : import 'utils.dart';
14 :
15 : /// A class that defines how to resolve `package:` URIs.
16 : ///
17 : /// This includes the information necessary to resolve `package:` URIs using
18 : /// either a package config or a package root. It can be used both as a standard
19 : /// cross-package representation of the user's configuration, and as a means of
20 : /// concretely locating packages and the assets they contain.
21 : ///
22 : /// Unlike [PackageResolver], all members on this are synchronous, which may
23 : /// require that more data be loaded up front. This is useful when primarily
24 : /// dealing with user-created package resolution strategies, whereas
25 : /// [PackageInfo] is usually preferable when the current Isolate's package
26 : /// resolution logic may be used.
27 : ///
28 : /// This class should not be implemented by user code.
29 : abstract class SyncPackageResolver {
30 : /// The map contained in the parsed package config.
31 : ///
32 : /// This maps package names to the base URIs for those packages. These are
33 : /// already resolved relative to [packageConfigUri], so if they're relative
34 : /// they should be considered relative to [Uri.base]. They're normalized to
35 : /// ensure that all URLs end with a trailing slash.
36 : ///
37 : /// [urlFor] should generally be used rather than looking up package URLs in
38 : /// this map, to ensure that code works with a package root as well as a
39 : /// package config.
40 : ///
41 : /// Returns `null` when using a [packageRoot] for resolution, or when no
42 : /// package resolution is being used.
43 : Map<String, Uri> get packageConfigMap;
44 :
45 : /// The URI for the package config.
46 : ///
47 : /// This is the URI from which [packageConfigMap] was parsed, if that's
48 : /// available. Otherwise, it's a `data:` URI containing a serialized
49 : /// representation of [packageConfigMap]. This `data:` URI should be accepted
50 : /// by all Dart tools.
51 : ///
52 : /// Note that if this is a `data:` URI, it's likely not safe to pass as a
53 : /// parameter to a Dart process due to length limits.
54 : ///
55 : /// Returns `null` when using a [packageRoot] for resolution, or when no
56 : /// package resolution is being used.
57 : Uri get packageConfigUri;
58 :
59 : /// The base URL for resolving `package:` URLs.
60 : ///
61 : /// This is normalized so that it always ends with a trailing slash.
62 : ///
63 : /// Returns `null` when using a [packageConfigMap] for resolution, or when no
64 : /// package resolution is being used.
65 : Uri get packageRoot;
66 :
67 : /// Returns a wrapper for [this] that implements [PackageResolver].
68 : PackageResolver get asAsync;
69 :
70 : /// Returns the argument to pass to a subprocess to get it to use this package
71 : /// resolution strategy when resolving `package:` URIs.
72 : ///
73 : /// This uses the `--package-root` or `--package` flags, which are the
74 : /// convention supported by the Dart VM and dart2js.
75 : ///
76 : /// Note that if [packageConfigUri] is a `data:` URI, it may be too large to
77 : /// pass on the command line.
78 : ///
79 : /// Returns `null` if no package resolution is in use.
80 : String get processArgument;
81 :
82 : /// Returns a package resolution strategy describing how the current isolate
83 : /// resolves `package:` URIs.
84 : ///
85 : /// This may throw exceptions if loading or parsing the isolate's package map
86 : /// fails.
87 : static final Future<SyncPackageResolver> current =
88 : PackageResolver.current.asSync;
89 :
90 : /// Returns a package resolution strategy that is unable to resolve any
91 : /// `package:` URIs.
92 : static final SyncPackageResolver none = new NoPackageResolver();
93 :
94 : /// Loads a package config file from [uri] and returns its package resolution
95 : /// strategy.
96 : ///
97 : /// This supports `file:`, `http:`, `data:` and `package:` URIs. It throws an
98 : /// [UnsupportedError] for any other schemes. If [client] is passed and an
99 : /// HTTP request is needed, it's used to make that request; otherwise, a
100 : /// default client is used.
101 : ///
102 : /// [uri] may be a [String] or a [Uri].
103 : static Future<SyncPackageResolver> loadConfig(uri, {http.Client client})
104 : async {
105 0 : uri = asUri(uri, "uri");
106 0 : return new SyncPackageResolver.config(
107 0 : await loadConfigMap(uri, client: client),
108 : uri: uri);
109 0 : }
110 :
111 : /// Returns the package resolution strategy for the given [packageConfigMap].
112 : ///
113 : /// If passed, [uri] specifies the URI from which [packageConfigMap] was
114 : /// loaded. It may be a [String] or a [Uri].
115 : ///
116 : /// Whether or not [uri] is passed, [packageConfigMap] is expected to be
117 : /// fully-resolved. That is, any relative URIs in the original package config
118 : /// source should be resolved relative to its location.
119 : factory SyncPackageResolver.config(Map<String, Uri> packageConfigMap, {uri}) =
120 : PackageConfigResolver;
121 :
122 : /// Returns the package resolution strategy for the given [packageRoot], which
123 : /// may be a [String] or a [Uri].
124 : factory SyncPackageResolver.root(packageRoot) = PackageRootResolver;
125 :
126 : /// Resolves [packageUri] according to this package resolution strategy.
127 : ///
128 : /// [packageUri] may be a [String] or a [Uri]. This throws a [FormatException]
129 : /// if [packageUri] isn't a `package:` URI or doesn't have at least one path
130 : /// segment.
131 : ///
132 : /// If [packageUri] refers to a package that's not in the package spec, this
133 : /// returns `null`.
134 : Uri resolveUri(packageUri);
135 :
136 : /// Returns the resolved URL for [package] and [path].
137 : ///
138 : /// This is equivalent to `resolveUri("package:$package/")` or
139 : /// `resolveUri("package:$package/$path")`, depending on whether [path] was
140 : /// passed.
141 : ///
142 : /// If [package] refers to a package that's not in the package spec, this
143 : /// returns `null`.
144 : Uri urlFor(String package, [String path]);
145 :
146 : /// Returns the `package:` URI for [url].
147 : ///
148 : /// If [url] can't be referred to using a `package:` URI, returns `null`.
149 : ///
150 : /// [url] may be a [String] or a [Uri].
151 : Uri packageUriFor(url);
152 :
153 : /// Returns the path on the local filesystem to the root of [package], or
154 : /// `null` if the root cannot be found.
155 : ///
156 : /// **Note**: this assumes a pub-style package layout. In particular:
157 : ///
158 : /// * If a package root is being used, this assumes that it contains symlinks
159 : /// to packages' lib/ directories.
160 : ///
161 : /// * If a package config is being used, this assumes that each entry points
162 : /// to a package's lib/ directory.
163 : ///
164 : /// If these assumptions are broken, this may return `null` or it may return
165 : /// an invalid result.
166 : ///
167 : /// Returns `null` if the package root is not a `file:` URI, or if the package
168 : /// config entry for [package] is not a `file:` URI.
169 : String packagePath(String package);
170 : }
|