|  | // 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 'common.dart'; | 
|  | import 'elements/elements.dart' show LibraryElement; | 
|  | import 'util/emptyset.dart'; | 
|  |  | 
|  | /// API used by the library loader to translate internal SDK URIs into file | 
|  | /// system readable URIs. | 
|  | abstract class ResolvedUriTranslator { | 
|  | factory ResolvedUriTranslator( | 
|  | Map<String, Uri> sdkLibraries, | 
|  | DiagnosticReporter reporter, | 
|  | Uri platformConfigUri) = _ResolvedUriTranslator; | 
|  |  | 
|  | /// The set of platform libraries reported as unsupported. | 
|  | /// | 
|  | /// For instance when importing 'dart:io' without '--categories=Server'. | 
|  | Set<Uri> get disallowedLibraryUris; | 
|  |  | 
|  | /// Whether or not a mockable library has been translated. | 
|  | bool get mockableLibraryUsed; | 
|  |  | 
|  | /// A mapping from dart: library names to their location. | 
|  | Map<String, Uri> get sdkLibraries; | 
|  |  | 
|  | /// Translates the resolved [uri] into a readable URI. | 
|  | /// | 
|  | /// The [importingLibrary] holds the library importing [uri] or `null` if | 
|  | /// [uri] is loaded as the main library. The [importingLibrary] is used to | 
|  | /// grant access to internal libraries from platform libraries and patch | 
|  | /// libraries. | 
|  | /// | 
|  | /// If the [uri] is not accessible from [importingLibrary], this method is | 
|  | /// responsible for reporting errors. | 
|  | /// | 
|  | /// See [LibraryLoader] for terminology on URIs. | 
|  | Uri translate(LibraryElement importingLibrary, Uri uri, Spannable spannable); | 
|  | } | 
|  |  | 
|  | /// A translator that forwards all methods to an internal | 
|  | /// [ResolvedUriTranslator]. | 
|  | /// | 
|  | /// The translator to forward to may be set after the instance is constructed. | 
|  | /// This is useful for the compiler because some tasks that are instantiated at | 
|  | /// compiler construction time need a [ResolvedUriTranslator], but the data | 
|  | /// required to instantiate it cannot be obtained at construction time. So a | 
|  | /// [ForwardingResolvedUriTranslator] may be passed instead, and the translator | 
|  | /// to forward to can be set once the required data has been retrieved. | 
|  | class ForwardingResolvedUriTranslator implements ResolvedUriTranslator { | 
|  | ResolvedUriTranslator resolvedUriTranslator; | 
|  |  | 
|  | /// Returns `true` if [resolvedUriTranslator] is not `null`. | 
|  | bool get isSet => resolvedUriTranslator != null; | 
|  |  | 
|  | /// The opposite of [isSet]. | 
|  | bool get isNotSet => resolvedUriTranslator == null; | 
|  |  | 
|  | @override | 
|  | Uri translate(LibraryElement importingLibrary, Uri resolvedUri, | 
|  | Spannable spannable) => | 
|  | resolvedUriTranslator.translate(importingLibrary, resolvedUri, spannable); | 
|  |  | 
|  | @override | 
|  | Set<Uri> get disallowedLibraryUris => | 
|  | resolvedUriTranslator?.disallowedLibraryUris ?? | 
|  | const ImmutableEmptySet<Uri>(); | 
|  |  | 
|  | @override | 
|  | bool get mockableLibraryUsed => resolvedUriTranslator.mockableLibraryUsed; | 
|  |  | 
|  | @override | 
|  | Map<String, Uri> get sdkLibraries => resolvedUriTranslator.sdkLibraries; | 
|  | } | 
|  |  | 
|  | class _ResolvedUriTranslator implements ResolvedUriTranslator { | 
|  | final Map<String, Uri> _sdkLibraries; | 
|  | final DiagnosticReporter _reporter; | 
|  | final Uri _platformConfigUri; | 
|  |  | 
|  | Set<Uri> disallowedLibraryUris = new Set<Uri>(); | 
|  | bool mockableLibraryUsed = false; | 
|  |  | 
|  | _ResolvedUriTranslator( | 
|  | this._sdkLibraries, this._reporter, this._platformConfigUri); | 
|  |  | 
|  | Map<String, Uri> get sdkLibraries => _sdkLibraries; | 
|  |  | 
|  | @override | 
|  | Uri translate(LibraryElement importingLibrary, Uri uri, Spannable spannable) { | 
|  | if (uri.scheme == 'dart') { | 
|  | return translateDartUri(importingLibrary, uri, spannable); | 
|  | } | 
|  | return uri; | 
|  | } | 
|  |  | 
|  | /// Translates "resolvedUri" with scheme "dart" to a [uri] resolved relative | 
|  | /// to `options.platformConfigUri` according to the information in the file at | 
|  | /// `options.platformConfigUri`. | 
|  | /// | 
|  | /// Returns `null` and emits an error if the library could not be found or | 
|  | /// imported into [importingLibrary]. | 
|  | /// | 
|  | /// Internal libraries (whose name starts with '_') can be only resolved if | 
|  | /// [importingLibrary] is a platform or patch library. | 
|  | Uri translateDartUri( | 
|  | LibraryElement importingLibrary, Uri resolvedUri, Spannable spannable) { | 
|  | Uri location = lookupLibraryUri(resolvedUri.path); | 
|  |  | 
|  | if (location == null) { | 
|  | _reporter.reportErrorMessage(spannable, MessageKind.LIBRARY_NOT_FOUND, | 
|  | {'resolvedUri': resolvedUri}); | 
|  | return null; | 
|  | } | 
|  |  | 
|  | if (resolvedUri.path.startsWith('_')) { | 
|  | bool allowInternalLibraryAccess = importingLibrary != null && | 
|  | (importingLibrary.isPlatformLibrary || | 
|  | importingLibrary.isPatch || | 
|  | importingLibrary.canonicalUri.scheme == 'memory' || | 
|  | importingLibrary.canonicalUri.path | 
|  | .contains('tests/compiler/dart2js_native') || | 
|  | importingLibrary.canonicalUri.path | 
|  | .contains('tests/compiler/dart2js_extra') || | 
|  | (importingLibrary.canonicalUri.scheme == 'package' && | 
|  | importingLibrary.canonicalUri.path | 
|  | .startsWith('dart_internal/'))); | 
|  |  | 
|  | if (!allowInternalLibraryAccess) { | 
|  | if (importingLibrary != null) { | 
|  | _reporter.reportErrorMessage( | 
|  | spannable, MessageKind.INTERNAL_LIBRARY_FROM, { | 
|  | 'resolvedUri': resolvedUri, | 
|  | 'importingUri': importingLibrary.canonicalUri | 
|  | }); | 
|  | } else { | 
|  | _reporter.reportErrorMessage(spannable, MessageKind.INTERNAL_LIBRARY, | 
|  | {'resolvedUri': resolvedUri}); | 
|  | registerDisallowedLibraryUse(resolvedUri); | 
|  | } | 
|  | return null; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (location.scheme == "unsupported") { | 
|  | if (location.path == "") { | 
|  | _reporter.reportErrorMessage(spannable, | 
|  | MessageKind.LIBRARY_NOT_SUPPORTED, {'resolvedUri': resolvedUri}); | 
|  | registerDisallowedLibraryUse(resolvedUri); | 
|  | } else { | 
|  | // If the specification includes a path, we treat it as "partially" | 
|  | // unsupported: it is allowed to be imported unconditionally, but we | 
|  | // will not expose it as being supported in the const variable | 
|  | // `dart.library.name`. | 
|  | // | 
|  | // This is a stopgap measure to support packages like `http` that need | 
|  | // to import `dart:io` conditionally. Once config-imports are supported | 
|  | // in the language, we can make it an error again to import it | 
|  | // unconditionally. | 
|  | // | 
|  | // The plaform configuration files contain a URI of the form | 
|  | // `unsupported:path/to/library.dart` to indicate this partially | 
|  | // supported mode. We resolve the path with respect to the configuration | 
|  | // file. | 
|  | return _platformConfigUri.resolve(location.path); | 
|  | } | 
|  | return null; | 
|  | } | 
|  |  | 
|  | if (resolvedUri.path == 'html' || resolvedUri.path == 'io') { | 
|  | // TODO(ahe): Get rid of mockableLibraryUsed when test.dart | 
|  | // supports this use case better. | 
|  | mockableLibraryUsed = true; | 
|  | } | 
|  | return location; | 
|  | } | 
|  |  | 
|  | void registerDisallowedLibraryUse(Uri uri) { | 
|  | disallowedLibraryUris.add(uri); | 
|  | } | 
|  |  | 
|  | Uri lookupLibraryUri(String libraryName) { | 
|  | return _sdkLibraries[libraryName]; | 
|  | } | 
|  | } |