blob: b57e5d0b01a906cdd36467f361fc8af85552ac59 [file] [log] [blame]
// Copyright (c) 2016, 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:collection';
import 'package:collection/collection.dart';
import 'package:package_config/packages_file.dart' as packages_file;
import 'package:path/path.dart' as p;
import 'async_package_resolver.dart';
import 'package_resolver.dart';
import 'sync_package_resolver.dart';
import 'utils.dart';
/// A package resolution strategy based on a package config map.
class PackageConfigResolver implements SyncPackageResolver {
@override
final packageRoot = null;
@override
final Map<String, Uri> packageConfigMap;
@override
Uri get packageConfigUri {
if (_uri != null) return _uri;
var buffer = StringBuffer();
packages_file.write(buffer, packageConfigMap, comment: '');
_uri =
UriData.fromString(buffer.toString(), parameters: {'charset': 'utf-8'})
.uri;
return _uri;
}
Uri _uri;
@override
PackageResolver get asAsync => AsyncPackageResolver(this);
@override
String get processArgument => '--packages=$packageConfigUri';
PackageConfigResolver(Map<String, Uri> packageConfigMap, {uri})
: packageConfigMap = _normalizeMap(packageConfigMap),
_uri = uri == null ? null : asUri(uri, 'uri');
/// Normalizes the URIs in [map] to ensure that they all end in a trailing
/// slash.
static Map<String, Uri> _normalizeMap(Map<String, Uri> map) =>
UnmodifiableMapView(
mapMap(map, value: (_, uri) => ensureTrailingSlash(uri)));
@override
Uri resolveUri(packageUri) {
var uri = asPackageUri(packageUri, 'packageUri');
var baseUri = packageConfigMap[uri.pathSegments.first];
if (baseUri == null) return null;
var segments = baseUri.pathSegments.toList()
..removeLast(); // Remove the trailing slash.
// Following [Isolate.resolvePackageUri], "package:foo" resolves to null.
if (uri.pathSegments.length == 1) return null;
segments.addAll(uri.pathSegments.skip(1));
return baseUri.replace(pathSegments: segments);
}
@override
Uri urlFor(String package, [String path]) {
var baseUri = packageConfigMap[package];
if (baseUri == null) return null;
if (path == null) return baseUri;
return baseUri.resolve(path);
}
@override
Uri packageUriFor(url) {
url = asUri(url, 'url').toString();
// Make sure isWithin works if [url] is exactly the base.
var nested = p.url.join(url, '_');
for (var package in packageConfigMap.keys) {
var base = packageConfigMap[package].toString();
if (!p.url.isWithin(base, nested)) continue;
var relative = p.url.relative(url, from: base);
if (relative == '.') relative = '';
return Uri.parse('package:$package/$relative');
}
return null;
}
@override
String packagePath(String package) {
var lib = packageConfigMap[package];
if (lib == null) return null;
if (lib.scheme != 'file') return null;
return p.dirname(p.fromUri(lib));
}
}