| Index: packages/analyzer/lib/src/context/source.dart
|
| diff --git a/packages/analyzer/lib/src/context/source.dart b/packages/analyzer/lib/src/context/source.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1f7c3b572d0c583ed55738fa52f35c8e16c0f6f9
|
| --- /dev/null
|
| +++ b/packages/analyzer/lib/src/context/source.dart
|
| @@ -0,0 +1,268 @@
|
| +// 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 analyzer.src.context.source;
|
| +
|
| +import 'dart:collection';
|
| +
|
| +import 'package:analyzer/exception/exception.dart';
|
| +import 'package:analyzer/file_system/file_system.dart';
|
| +import 'package:analyzer/file_system/physical_file_system.dart';
|
| +import 'package:analyzer/source/package_map_resolver.dart';
|
| +import 'package:analyzer/src/generated/engine.dart';
|
| +import 'package:analyzer/src/generated/sdk.dart';
|
| +import 'package:analyzer/src/generated/source.dart';
|
| +import 'package:analyzer/src/generated/utilities_dart.dart' as utils;
|
| +import 'package:analyzer/src/util/fast_uri.dart';
|
| +import 'package:package_config/packages.dart';
|
| +
|
| +/**
|
| + * Instances of the class `SourceFactory` resolve possibly relative URI's
|
| + * against an existing [Source].
|
| + */
|
| +class SourceFactoryImpl implements SourceFactory {
|
| + @override
|
| + AnalysisContext context;
|
| +
|
| + /**
|
| + * URI processor used to find mappings for `package:` URIs found in a
|
| + * `.packages` config file.
|
| + */
|
| + final Packages _packages;
|
| +
|
| + /**
|
| + * Resource provider used in working with package maps.
|
| + */
|
| + final ResourceProvider _resourceProvider;
|
| +
|
| + /**
|
| + * The resolvers used to resolve absolute URI's.
|
| + */
|
| + final List<UriResolver> resolvers;
|
| +
|
| + /**
|
| + * The predicate to determine is [Source] is local.
|
| + */
|
| + LocalSourcePredicate _localSourcePredicate = LocalSourcePredicate.NOT_SDK;
|
| +
|
| + /**
|
| + * Cache of mapping of absolute [Uri]s to [Source]s.
|
| + */
|
| + final HashMap<Uri, Source> _absoluteUriToSourceCache =
|
| + new HashMap<Uri, Source>();
|
| +
|
| + /**
|
| + * Initialize a newly created source factory with the given absolute URI
|
| + * [resolvers] and optional [_packages] resolution helper.
|
| + */
|
| + SourceFactoryImpl(this.resolvers,
|
| + [this._packages, ResourceProvider resourceProvider])
|
| + : _resourceProvider =
|
| + resourceProvider ?? PhysicalResourceProvider.INSTANCE;
|
| +
|
| + @override
|
| + DartSdk get dartSdk {
|
| + List<UriResolver> resolvers = this.resolvers;
|
| + int length = resolvers.length;
|
| + for (int i = 0; i < length; i++) {
|
| + UriResolver resolver = resolvers[i];
|
| + if (resolver is DartUriResolver) {
|
| + DartUriResolver dartUriResolver = resolver;
|
| + return dartUriResolver.dartSdk;
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + void set localSourcePredicate(LocalSourcePredicate localSourcePredicate) {
|
| + this._localSourcePredicate = localSourcePredicate;
|
| + }
|
| +
|
| + @override
|
| + Map<String, List<Folder>> get packageMap {
|
| + // Start by looking in .packages.
|
| + if (_packages != null) {
|
| + Map<String, List<Folder>> packageMap = <String, List<Folder>>{};
|
| + _packages.asMap().forEach((String name, Uri uri) {
|
| + if (uri.scheme == 'file' || uri.scheme == '' /* unspecified */) {
|
| + packageMap[name] = <Folder>[
|
| + _resourceProvider.getFolder(uri.toFilePath())
|
| + ];
|
| + }
|
| + });
|
| + return packageMap;
|
| + }
|
| +
|
| + // Default to the PackageMapUriResolver.
|
| + PackageMapUriResolver resolver = resolvers
|
| + .firstWhere((r) => r is PackageMapUriResolver, orElse: () => null);
|
| + return resolver?.packageMap;
|
| + }
|
| +
|
| + @override
|
| + SourceFactory clone() {
|
| + SourceFactory factory =
|
| + new SourceFactory(resolvers, _packages, _resourceProvider);
|
| + factory.localSourcePredicate = _localSourcePredicate;
|
| + return factory;
|
| + }
|
| +
|
| + @override
|
| + Source forUri(String absoluteUri) {
|
| + try {
|
| + Uri uri = FastUri.parse(absoluteUri);
|
| + if (uri.isAbsolute) {
|
| + return _internalResolveUri(null, uri);
|
| + }
|
| + } catch (exception, stackTrace) {
|
| + AnalysisEngine.instance.logger.logError(
|
| + "Could not resolve URI: $absoluteUri",
|
| + new CaughtException(exception, stackTrace));
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Source forUri2(Uri absoluteUri) {
|
| + if (absoluteUri.isAbsolute) {
|
| + try {
|
| + return _internalResolveUri(null, absoluteUri);
|
| + } on AnalysisException catch (exception, stackTrace) {
|
| + AnalysisEngine.instance.logger.logError(
|
| + "Could not resolve URI: $absoluteUri",
|
| + new CaughtException(exception, stackTrace));
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Source fromEncoding(String encoding) {
|
| + Source source = forUri(encoding);
|
| + if (source == null) {
|
| + throw new ArgumentError("Invalid source encoding: '$encoding'");
|
| + }
|
| + return source;
|
| + }
|
| +
|
| + @override
|
| + bool isLocalSource(Source source) => _localSourcePredicate.isLocal(source);
|
| +
|
| + @override
|
| + Source resolveUri(Source containingSource, String containedUri) {
|
| + if (containedUri == null || containedUri.isEmpty) {
|
| + return null;
|
| + }
|
| + try {
|
| + // Force the creation of an escaped URI to deal with spaces, etc.
|
| + return _internalResolveUri(containingSource, FastUri.parse(containedUri));
|
| + } on FormatException {
|
| + return null;
|
| + } catch (exception, stackTrace) {
|
| + String containingFullName =
|
| + containingSource != null ? containingSource.fullName : '<null>';
|
| + AnalysisEngine.instance.logger.logInformation(
|
| + "Could not resolve URI ($containedUri) "
|
| + "relative to source ($containingFullName)",
|
| + new CaughtException(exception, stackTrace));
|
| + return null;
|
| + }
|
| + }
|
| +
|
| + @override
|
| + Uri restoreUri(Source source) {
|
| + // First see if a resolver can restore the URI.
|
| + for (UriResolver resolver in resolvers) {
|
| + Uri uri = resolver.restoreAbsolute(source);
|
| + if (uri != null) {
|
| + // Now see if there's a package mapping.
|
| + Uri packageMappedUri = _getPackageMapping(uri);
|
| + if (packageMappedUri != null) {
|
| + return packageMappedUri;
|
| + }
|
| + // Fall back to the resolver's computed URI.
|
| + return uri;
|
| + }
|
| + }
|
| +
|
| + return null;
|
| + }
|
| +
|
| + Uri _getPackageMapping(Uri sourceUri) {
|
| + if (_packages == null) {
|
| + return null;
|
| + }
|
| + if (sourceUri.scheme != 'file') {
|
| + //TODO(pquitslund): verify this works for non-file URIs.
|
| + return null;
|
| + }
|
| +
|
| + Uri packageUri;
|
| + _packages.asMap().forEach((String name, Uri uri) {
|
| + if (packageUri == null) {
|
| + if (utils.startsWith(sourceUri, uri)) {
|
| + packageUri = Uri.parse(
|
| + 'package:$name/${sourceUri.path.substring(uri.path.length)}');
|
| + }
|
| + }
|
| + });
|
| + return packageUri;
|
| + }
|
| +
|
| + /**
|
| + * Return a source object representing the URI that results from resolving
|
| + * the given (possibly relative) contained URI against the URI associated
|
| + * with an existing source object, or `null` if the URI could not be resolved.
|
| + *
|
| + * @param containingSource the source containing the given URI
|
| + * @param containedUri the (possibly relative) URI to be resolved against the
|
| + * containing source
|
| + * @return the source representing the contained URI
|
| + * @throws AnalysisException if either the contained URI is invalid or if it
|
| + * cannot be resolved against the source object's URI
|
| + */
|
| + Source _internalResolveUri(Source containingSource, Uri containedUri) {
|
| + if (!containedUri.isAbsolute) {
|
| + if (containingSource == null) {
|
| + throw new AnalysisException(
|
| + "Cannot resolve a relative URI without a containing source: "
|
| + "$containedUri");
|
| + }
|
| + containedUri =
|
| + utils.resolveRelativeUri(containingSource.uri, containedUri);
|
| + }
|
| +
|
| + Uri actualUri = containedUri;
|
| +
|
| + // Check .packages and update target and actual URIs as appropriate.
|
| + if (_packages != null && containedUri.scheme == 'package') {
|
| + Uri packageUri = null;
|
| + try {
|
| + packageUri =
|
| + _packages.resolve(containedUri, notFound: (Uri packageUri) => null);
|
| + } on ArgumentError {
|
| + // Fall through to try resolvers.
|
| + }
|
| +
|
| + if (packageUri != null) {
|
| + // Ensure scheme is set.
|
| + if (packageUri.scheme == '') {
|
| + packageUri = packageUri.replace(scheme: 'file');
|
| + }
|
| + containedUri = packageUri;
|
| + }
|
| + }
|
| +
|
| + return _absoluteUriToSourceCache.putIfAbsent(containedUri, () {
|
| + for (UriResolver resolver in resolvers) {
|
| + Source result = resolver.resolveAbsolute(containedUri, actualUri);
|
| + if (result != null) {
|
| + return result;
|
| + }
|
| + }
|
| + return null;
|
| + });
|
| + }
|
| +}
|
|
|